create-instant-app 1.0.40 → 1.0.41-branch-python-sdk-v1.26586025551.1

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 CHANGED
@@ -1,34 +1,53 @@
1
1
  #!/usr/bin/env node
2
- import{Command as Fe,Option as l}from"commander";import*as U from"@clack/prompts";import{spawn as Oe}from"child_process";import{execa as je}from"execa";async function $(){return new Promise(e=>{let t=process.env.SHELL||"/bin/bash",n=Oe(t,["-i","-c","which claude"],{stdio:["ignore","pipe","ignore"]}),r="";n.stdout.on("data",i=>{r+=i.toString()}),n.on("close",i=>{if(i===0){let o=r.trim();o.includes("aliased to ")?e(o.split("aliased to ")[1]||null):e(o)}else e(null)})})}var J=async(e,t)=>{let n=await $();if(!n)throw new Error("Claude not found in path");await je(n,[e],{stdio:"inherit",cwd:t})};import{version as Me}from"@instantdb/version";import K from"path";var H=e=>(e.length>1&&e.endsWith("/")&&(e=e.slice(0,-1)),e),Re=/^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/,Y=e=>{let n=H(e).split("/"),r=n[n.length-1];if(r==="."){let s=K.resolve(process.cwd());r=K.basename(s)}let i=n.findIndex(s=>s.startsWith("@"));n.findIndex(s=>s.startsWith("@"))!==-1&&(r=n.slice(i).join("/"));let o=n.filter(s=>!s.startsWith("@")).join("/");return[r,o]},E=e=>e.trim(),D=e=>{let t=H(e),n=t.split("/"),r=n.findIndex(o=>o.startsWith("@")),i=n[n.length-1];if(n.findIndex(o=>o.startsWith("@"))!==-1&&(i=n.slice(r).join("/")),!(t==="."||Re.test(i??"")))return"App name must consist of only lowercase alphanumeric characters, '-', and '_'"};import{renderUnwrap as P,UI as m}from"instant-cli/ui";var C={base:"next-js-app-dir",appName:"Awesome Todos",ruleFiles:null,createRepo:!0,prompt:null,app:null,token:null,yes:!1,temporary:!1},q=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"||null,X=e=>e.cursor&&"cursor"||e.claude&&"claude"||e.codex&&"codex"||e.gemini&&"gemini"||e.rules&&"codex"||null,Z=async()=>{let e=C,t=new Fe().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(["next-js-app-dir","vite-react","vite-vanilla","expo","bun-react","tanstack-start","tanstack-start-with-tanstack-query","solidjs-vite","sveltekit","vue-vite","vercel-ai-sdk","ai-chat"])).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("--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(Me).parse(process.argv),n=t.args[0]&&E(t.args[0]);if(n){let o=D(n);if(o)throw new Error("Invalid app name: "+o);e.appName=n}let r=t.opts();if(r.app&&r.temp)throw new Error("--app and --temp cannot be used together");if(r.yes){if(r.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{...C,appName:n,base:q(r)??C.base,ruleFiles:X(r)??"claude",createRepo:r.git??C.createRepo,app:r.app??null,token:r.token??null,yes:!0,temporary:r.temp??!1}}if(r.ai&&!await $())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 U.group({appName:async()=>{if(n)return n.trim();let o=await P(new m.TextInput({prompt:"What will your project/folder be called?",placeholder:"awesome-todos",defaultValue:"awesome-todos",validate:a=>D(E(a)),modifyOutput:m.ciaModifier()}));return E(o)},prompt:async()=>r.ai?await P(new m.TextInput({prompt:"What would you like to create?",placeholder:"Create an app that...",modifyOutput:m.modifiers.piped([m.ciaModifier()])})):null,base:async({results:o})=>{let s=q(r);return s||(o.prompt?P(new m.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:m.modifiers.piped([m.ciaModifier()])})):P(new m.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}],defaultValue:"next-js-app-dir",modifyOutput:m.modifiers.piped([m.ciaModifier()])})))},ruleFiles:async({results:o})=>{if(o.prompt)return"claude";let s=X(r);return s||P(new m.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:m.ciaModifier()}))},createRepo:async()=>r.git!==void 0?r.git:!0,temporary:async()=>r.temp??!1},{onCancel(){process.exit(1)}}),app:r.app??null,token:r.token??null,yes:!1}};import Se from"path";import Ne from"fs-extra";import{log as Ee,outro as Pt}from"@clack/prompts";import{intro as $e}from"@clack/prompts";import Q from"chalk";var De=` _ _ _
2
+ import{Command as Me,Option as l}from"commander";import*as L from"@clack/prompts";import{spawn as Re}from"child_process";import{execa as $e}from"execa";async function B(){return new Promise(e=>{let t=process.env.SHELL||"/bin/bash",n=Re(t,["-i","-c","which claude"],{stdio:["ignore","pipe","ignore"]}),r="";n.stdout.on("data",i=>{r+=i.toString()}),n.on("close",i=>{if(i===0){let a=r.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 B();if(!n)throw new Error("Claude not found in path");await $e(n,[e],{stdio:"inherit",cwd:t})};import{version as De}from"@instantdb/version";import X from"path";var Z=e=>(e.length>1&&e.endsWith("/")&&(e=e.slice(0,-1)),e),Fe=/^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/,Q=e=>{let n=Z(e).split("/"),r=n[n.length-1];if(r==="."){let o=X.resolve(process.cwd());r=X.basename(o)}let i=n.findIndex(o=>o.startsWith("@"));n.findIndex(o=>o.startsWith("@"))!==-1&&(r=n.slice(i).join("/"));let a=n.filter(o=>!o.startsWith("@")).join("/");return[r,a]},O=e=>e.trim(),G=e=>{let t=Z(e),n=t.split("/"),r=n.findIndex(a=>a.startsWith("@")),i=n[n.length-1];if(n.findIndex(a=>a.startsWith("@"))!==-1&&(i=n.slice(r).join("/")),!(t==="."||Fe.test(i??"")))return"App name must consist of only lowercase alphanumeric characters, '-', and '_'"};import{renderUnwrap as A,UI as f}from"instant-cli/ui";var j={base:"next-js-app-dir",appName:"Awesome Todos",ruleFiles:null,createRepo:!0,prompt:null,app:null,token:null,yes:!1,temporary:!1},ee=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,te=e=>e.cursor&&"cursor"||e.claude&&"claude"||e.codex&&"codex"||e.gemini&&"gemini"||e.rules&&"codex"||null,ne=async()=>{let e=j,t=new Me().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(["next-js-app-dir","vite-react","vite-vanilla","expo","bun-react","tanstack-start","tanstack-start-with-tanstack-query","solidjs-vite","sveltekit","vue-vite","vercel-ai-sdk","ai-chat","python-script"])).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(De).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 r=t.opts();if(r.app&&r.temp)throw new Error("--app and --temp cannot be used together");if(r.yes){if(r.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{...j,appName:n,base:ee(r)??j.base,ruleFiles:te(r)??"claude",createRepo:r.git??j.createRepo,app:r.app??null,token:r.token??null,yes:!0,temporary:r.temp??!1}}if(r.ai&&!await B())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 L.group({appName:async()=>{if(n)return n.trim();let a=await A(new f.TextInput({prompt:"What will your project/folder be called?",placeholder:"awesome-todos",defaultValue:"awesome-todos",validate:s=>G(O(s)),modifyOutput:f.ciaModifier()}));return O(a)},prompt:async()=>r.ai?await A(new f.TextInput({prompt:"What would you like to create?",placeholder:"Create an app that...",modifyOutput:f.modifiers.piped([f.ciaModifier()])})):null,base:async({results:a})=>{let o=ee(r);return o||(a.prompt?A(new f.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:f.modifiers.piped([f.ciaModifier()])})):A(new f.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:f.modifiers.piped([f.ciaModifier()])})))},ruleFiles:async({results:a})=>{if(a.prompt)return"claude";let o=te(r);return o||A(new f.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:f.ciaModifier()}))},createRepo:async()=>r.git!==void 0?r.git:!0,temporary:async()=>r.temp??!1},{onCancel(){process.exit(1)}}),app:r.app??null,token:r.token??null,yes:!1}};import Y from"path";import U from"fs-extra";import{log as V,outro as St}from"@clack/prompts";import{intro as Ue}from"@clack/prompts";import re from"chalk";var Ve=` _ _ _
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 |_|_| |_|___/\\__\\__,_|_| |_|\\__|`,ee=()=>{$e(`
9
- `+De.split(`
10
- `).map(e=>`${Q.gray("\u2502")}${Q.hex("#EA580D").bold(" "+e)}`).join(`
11
- `))};import u from"path";import Ge from"tiged";import c from"fs-extra";import te from"path";import{fileURLToPath as Ue}from"url";var Ve=Ue(import.meta.url),Be=te.dirname(Ve),O=te.join(Be,"../");import I from"chalk";var T=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 ne,UI as h}from"instant-cli/ui";import Le from"slugify";import We from"ignore";var re=async(e,t)=>{let n=u.resolve(process.cwd(),t);if(c.existsSync(n))if(c.readdirSync(n).length===0)h.log(`${I.cyan.bold(e.appName)} exists but is empty, continuing...`,h.ciaModifier(null));else{let o=await ne(new h.Select({promptText:I.redBright(`${I.bold("Warning:")} ${I.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:h.ciaModifier()}));o==="abort"&&(h.log("Aborting installation..."),process.exit(1)),o==="clear"&&c.emptyDirSync(n)}let r=Ke({projectDir:n,baseTemplateName:e.base}),i=e.appName==="."?"App":I.hex("#EA570B").bold(e.appName);if(await ne(new h.Spinner({promise:r,workingText:"Scaffolding project files...",doneText:`Successfully scaffolded ${i}!`,errorText:"Error scaffolding project files",modifyOutput:h.ciaModifier(null)})),c.pathExistsSync(u.join(n,"pnpm-lock.yaml"))&&c.removeSync(u.join(n,"pnpm-lock.yaml")),c.pathExistsSync(u.join(n,"bun.lock"))&&c.removeSync(u.join(n,"bun.lock")),T(e.base)==="pnpm"&&e.base==="expo"&&await c.appendFile(u.join(n,".npmrc"),`node-linker=hoisted
12
- enable-pre-post-scripts=true`),e.base==="expo"){let o=Le.default(t);V(u.join(n,"app.json"),'"name": "expo-template"',`"name": "${t}"`),V(u.join(n,"app.json"),'"slug": "expo-template"',`"slug": "${o}"`),V(u.join(n,"app/_layout.tsx"),'"My Instant App"',`"${t}"`)}return n},V=(e,t,n)=>{let i=c.readFileSync(e,"utf8").replaceAll(t,n);c.writeFileSync(e,i)},ze=async({projectDir:e,baseTemplateName:t})=>{let n=`instantdb/instant/examples/${t}`;await Ge(n,{mode:"tar",disableCache:!0}).clone(e)};async function Je(e,t){let n=We();n.add(".git");try{let r=u.join(e,".gitignore"),i=await c.readFile(r,"utf8");n.add(i)}catch{}await c.copy(e,t,{filter:r=>{let i=u.relative(e,r);return i===""?!0:!n.ignores(i)}})}var Ke=async({projectDir:e,baseTemplateName:t})=>{let n=u.join(O,`template/base/${t}`),r=!!process.env.INSTANT_CLI_DEV&&!!process.env.INSTANT_REPO_FOLDER,i=c.pathExistsSync(n),o=r?"dev":i?"bundled-template":"tiged";if(o==="bundled-template"){c.copySync(n,e);let s=u.join(e,"_gitignore"),a=u.join(e,".gitignore");c.pathExistsSync(s)&&c.renameSync(s,a);return}if(o==="dev"){let s=process.env.INSTANT_REPO_FOLDER;if(!s)throw new Error("INSTANT_REPO_FOLDER is required when using repo-examples scaffolding.");let a=u.join(s,"examples",t);await Je(a,e);return}process.env.INSTANT_CLI_DEV&&!process.env.INSTANT_REPO_FOLDER&&h.log(I.bold.yellowBright(`WARNING: INSTANT_CLI_DEV is TRUE but no INSTANT_REPO_FOLDER is set.
13
- Using git to clone from main...`),h.ciaModifier(null)),await ze({projectDir:e,baseTemplateName:t})};import{execa as He}from"execa";import{renderUnwrap as Ye,UI as j}from"instant-cli/ui";var oe=async(e,t)=>{let n=He(e,["install"],{cwd:t}),r=await Ye(new j.Spinner({promise:n,workingText:`Installing dependencies with ${e}...`,doneText:"Successfully installed dependencies!",modifyOutput:j.ciaModifier(null)}));r.exitCode!==0&&(j.log(r.stderr,j.ciaModifier(null)),process.exit(1))};import At from"chalk";import qe from"fs-extra";import ae from"path";var Xe={claude:"CLAUDE.md",gemini:"GEMINI.md",cursor:"AGENTS.md",codex:"AGENTS.md",zed:"AGENTS.md",windsurf:"AGENTS.md"},ie=({projectDir:e,ruleFilesToAdd:t})=>{t!==null&&qe.copyFileSync(ae.join(O,"template/rules/AGENTS.md"),ae.join(e,Xe[t]))};import{execSync as G}from"child_process";import B from"path";import*as pe from"@clack/prompts";import R from"chalk";import{execa as _}from"execa";import le from"fs-extra";import{renderUnwrap as se,UI as k}from"instant-cli/ui";var Ze=e=>{try{return G("git --version",{cwd:e}),!0}catch{return!1}},Qe=e=>le.existsSync(B.join(e,".git")),et=async e=>{try{return await _("git",["rev-parse","--is-inside-work-tree"],{cwd:e,stdout:"ignore"}),!0}catch{return!1}},tt=()=>{let t=G("git --version").toString().trim().split(" ")[2],n=t?.split(".")[0],r=t?.split(".")[1];return{major:Number(n),minor:Number(r)}},nt=()=>G("git config --global init.defaultBranch || echo main").toString().trim(),ce=async e=>{if(!Ze(e)){pe.log.warn("Git is not installed. Skipping Git initialization.");return}let t=Qe(e),n=await et(e),r=B.parse(e).name;if(n&&t){if(!await se(new k.Confirmation({promptText:`${R.redBright.bold("Warning:")} Git is already initialized in "${r}". Initializing a new git repository would delete the previous history. Would you like to continue anyways?`,defaultValue:!1,modifyOutput:k.ciaModifier()})))return;le.removeSync(B.join(e,".git"))}else if(n&&!t&&!await se(new k.Confirmation({promptText:`${R.redBright.bold("Warning:")} "${r}" is already in a git worktree.
8
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 |_|_| |_|___/\\__\\__,_|_| |_|\\__|`,oe=()=>{Ue(`
9
+ `+Ve.split(`
10
+ `).map(e=>`${re.gray("\u2502")}${re.hex("#EA580D").bold(" "+e)}`).join(`
11
+ `))};import m from"path";import We from"tiged";import d from"fs-extra";import ae from"path";import{fileURLToPath as Be}from"url";var Ge=Be(import.meta.url),Le=ae.dirname(Ge),R=ae.join(Le,"../");import I from"chalk";var $=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 ie,UI as w}from"instant-cli/ui";import ze from"slugify";import Ke from"ignore";var se=async(e,t)=>{let n=m.resolve(process.cwd(),t);if(d.existsSync(n))if(d.readdirSync(n).length===0)w.log(`${I.cyan.bold(e.appName)} exists but is empty, continuing...`,w.ciaModifier(null));else{let a=await ie(new w.Select({promptText:I.redBright(`${I.bold("Warning:")} ${I.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 r=Ye({projectDir:n,baseTemplateName:e.base}),i=e.appName==="."?"App":I.hex("#EA570B").bold(e.appName);if(await ie(new w.Spinner({promise:r,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")),$(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=ze.default(t);W(m.join(n,"app.json"),'"name": "expo-template"',`"name": "${t}"`),W(m.join(n,"app.json"),'"slug": "expo-template"',`"slug": "${a}"`),W(m.join(n,"app/_layout.tsx"),'"My Instant App"',`"${t}"`)}return n},W=(e,t,n)=>{let i=d.readFileSync(e,"utf8").replaceAll(t,n);d.writeFileSync(e,i)},Je=async({projectDir:e,baseTemplateName:t})=>{let n=`instantdb/instant/examples/${t}`;await We(n,{mode:"tar",disableCache:!0}).clone(e)};async function He(e,t){let n=Ke();n.add(".git");try{let r=m.join(e,".gitignore"),i=await d.readFile(r,"utf8");n.add(i)}catch{}await d.copy(e,t,{filter:r=>{let i=m.relative(e,r);return i===""?!0:!n.ignores(i)}})}var Ye=async({projectDir:e,baseTemplateName:t})=>{let n=m.join(R,`template/base/${t}`),r=!!process.env.INSTANT_CLI_DEV&&!!process.env.INSTANT_REPO_FOLDER,i=d.pathExistsSync(n),a=r?"dev":i?"bundled-template":"tiged";if(a==="bundled-template"){d.copySync(n,e);let o=m.join(e,"_gitignore"),s=m.join(e,".gitignore");d.pathExistsSync(o)&&d.renameSync(o,s);return}if(a==="dev"){let o=process.env.INSTANT_REPO_FOLDER;if(!o)throw new Error("INSTANT_REPO_FOLDER is required when using repo-examples scaffolding.");let s=m.join(o,"examples",t);await He(s,e);return}process.env.INSTANT_CLI_DEV&&!process.env.INSTANT_REPO_FOLDER&&w.log(I.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 Je({projectDir:e,baseTemplateName:t})};import{execa as qe}from"execa";import{renderUnwrap as Xe,UI as F}from"instant-cli/ui";var pe=async(e,t)=>{let n=qe(e,["install"],{cwd:t}),r=await Xe(new F.Spinner({promise:n,workingText:`Installing dependencies with ${e}...`,doneText:"Successfully installed dependencies!",modifyOutput:F.ciaModifier(null)}));r.exitCode!==0&&(F.log(r.stderr,F.ciaModifier(null)),process.exit(1))};import Oe from"chalk";import Ze from"fs-extra";import le from"path";var Qe={claude:"CLAUDE.md",gemini:"GEMINI.md",cursor:"AGENTS.md",codex:"AGENTS.md",zed:"AGENTS.md",windsurf:"AGENTS.md"},ce=({projectDir:e,ruleFilesToAdd:t})=>{t!==null&&Ze.copyFileSync(le.join(R,"template/rules/AGENTS.md"),le.join(e,Qe[t]))};import{execSync as K}from"child_process";import z from"path";import*as ue from"@clack/prompts";import M from"chalk";import{execa as _}from"execa";import me from"fs-extra";import{renderUnwrap as de,UI as v}from"instant-cli/ui";var et=e=>{try{return K("git --version",{cwd:e}),!0}catch{return!1}},tt=e=>me.existsSync(z.join(e,".git")),nt=async e=>{try{return await _("git",["rev-parse","--is-inside-work-tree"],{cwd:e,stdout:"ignore"}),!0}catch{return!1}},rt=()=>{let t=K("git --version").toString().trim().split(" ")[2],n=t?.split(".")[0],r=t?.split(".")[1];return{major:Number(n),minor:Number(r)}},ot=()=>K("git config --global init.defaultBranch || echo main").toString().trim(),fe=async e=>{if(!et(e)){ue.log.warn("Git is not installed. Skipping Git initialization.");return}let t=tt(e),n=await nt(e),r=z.parse(e).name;if(n&&t){if(!await de(new v.Confirmation({promptText:`${M.redBright.bold("Warning:")} Git is already initialized in "${r}". Initializing a new git repository would delete the previous history. Would you like to continue anyways?`,defaultValue:!1,modifyOutput:v.ciaModifier()})))return;me.removeSync(z.join(e,".git"))}else if(n&&!t&&!await de(new v.Confirmation({promptText:`${M.redBright.bold("Warning:")} "${r}" 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:k.ciaModifier()})))return;try{let i=nt(),{major:o,minor:s}=tt();o<2||o==2&&s<28?(await _("git",["init"],{cwd:e}),await _("git",["symbolic-ref","HEAD",`refs/heads/${i}`],{cwd:e})):await _("git",["init",`--initial-branch=${i}`],{cwd:e}),await _("git",["add","."],{cwd:e}),await _("git",["commit","-m","Initial commit (create-instant-app)"],{cwd:e}),k.log(R.dim(`${R.green("\u2713")} Git repository initialized successfully.`),k.ciaModifier(null))}catch{}};import ot from"env-paths";import{mkdir as at,readFile as it,writeFile as st}from"node:fs/promises";import pt from"open";import{join as lt}from"node:path";import{randomUUID as me}from"node:crypto";import{version as rt}from"@instantdb/version";var de=!!process.env.INSTANT_CLI_DEV,ue=de?"http://localhost:3000":"https://instantdb.com",L=process.env.INSTANT_CLI_API_URI||(de?"http://localhost:8888":"https://api.instantdb.com");async function w({path:e,body:t,method:n="GET",authToken:r,metadata:i}){let s={"Content-Type":"application/json","X-Instant-Source":"create-instant-app","X-Instant-Version":rt,"X-Instant-Command":"create"};r&&(s.Authorization=`Bearer ${r}`),i&&(s["X-Instant-Metadata"]=JSON.stringify(i));let a=await fetch(`${L}${e}`,{method:n??"GET",headers:s,body:t?JSON.stringify(t):void 0,signal:AbortSignal.timeout(3e5)}),p;try{p=await a.json()}catch{p=null}if(!a.ok){let f=p.message||p.hint?.errors?.[0]?.message||"There was an error";throw new Error(f)}return p}import{renderUnwrap as A,UI as d}from"instant-cli/ui";function y(e){return e.replace(/[-_]/g," ").replace(/\b\w/g,t=>t.toUpperCase())}var ct=!!process.env.INSTANT_CLI_DEV,dt=!!process.env.INSTANT_CLI_FORCE_EPHEMERAL;function ge(){let e=`instantdb-${ct?"dev":"prod"}`,{config:t}=ot(e);return{authConfigFilePath:lt(t,"a"),appConfigDirPath:t}}var fe=async(e,t,n,r)=>{let i=me(),o=me(),s={id:i,title:e,admin_token:o,org_id:n};return r?.rules&&(s.rules=r.rules),r?.schema&&(s.schema=r.schema),await w({method:"POST",authToken:t,path:"/dash/apps",body:s,metadata:r}),{appId:i,adminToken:o,source:"created"}},W=(e,t,n)=>{w({method:"POST",path:`/dash/apps/${e}/track-import`,authToken:t,metadata:n}).catch(()=>{})},he=async e=>await w({method:"GET",path:"/dash",authToken:e}),we=async(e,t)=>await w({method:"GET",path:`/dash/orgs/${t}`,authToken:e});var ut=async(e,t)=>{try{let n=await he(e),r=n.apps.find(i=>i.id===t);if(r)return{appId:r.id,adminToken:r.admin_token};for(let i of n.orgs){let{apps:o}=await we(e,i.id),s=o.find(a=>a.id===t);if(s)return{appId:s.id,adminToken:s.admin_token}}return null}catch{return null}},mt=async(e,t)=>{try{return await w({method:"GET",path:`/dash/apps/${e}/schema/pull`,authToken:t}),!0}catch{return!1}},ft=async()=>dt?null:process.env.INSTANT_CLI_AUTH_TOKEN?process.env.INSTANT_CLI_AUTH_TOKEN:await it(ge().authConfigFilePath,"utf-8").catch(()=>null),F=async(e,t)=>{let n=await w({authToken:null,method:"POST",path:"/dash/apps/ephemeral",body:{title:e,rules:{$users:{view:"true"},$files:{allow:{view:"true",create:"true",delete:"true"}}}},metadata:t});return{appId:n.app.id,adminToken:n.app["admin-token"]}},ye=async(e,t,n)=>{let r=await ft();if(t?.yes&&!t?.app)if(r&&!t.temporary){let{appId:a,adminToken:p}=await fe(y(e),r,void 0,n);return{appId:a,adminToken:p,approach:"create"}}else{let{appId:a,adminToken:p}=await F(y(e),n);return{appId:a,adminToken:p,approach:"ephemeral"}}if(t?.temporary){let a=await A(new d.TextInput({defaultValue:y(e),prompt:"Enter a name for your temporary app:",placeholder:y(e),modifyOutput:d.ciaModifier()}));return{...await F(a,n),approach:"ephemeral"}}if(t?.app){if(t.token){if(!await mt(t.app,t.token))throw new Error("Invalid app ID and token combination. Please verify both the app ID and token are correct.");return d.log(`Linking to app: ${t.app}`,d.ciaModifier(null)),W(t.app,t.token,n),{appId:t.app,adminToken:t.token,approach:"import"}}if(r){let a=await ut(r,t.app);if(!a)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 d.log(`Linking to app: ${t.app}`,d.ciaModifier(null)),W(a.appId,r,n),{appId:a.appId,adminToken:a.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(!r){let a=await A(new d.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:d.ciaModifier()}));if(a==="login"){let p=await w({authToken:null,method:"POST",path:"/dash/cli/auth/register"}).catch(Ce=>{throw new Error("Failed to register",{cause:Ce})}),{secret:f,ticket:g}=p;pt(`${ue}/dash?ticket=${g}`);let M=ht({secret:f}),z=await A(new d.Spinner({promise:M,workingText:"Waiting for login in browser",disappearWhenDone:!0,modifyOutput:d.ciaModifier(null)}));await wt(z.token),r=z.token}if(a==="skip")return d.log("Skipping app link step",d.ciaModifier(null)),null;if(a==="ephemeral"){let p=await A(new d.TextInput({defaultValue:y(e),prompt:"Enter a name for your temporary app:",placeholder:y(e),modifyOutput:d.ciaModifier()}));return{...await F(p,n),approach:"ephemeral"}}}if(!r)return null;let i=await he(r).catch(a=>{throw new Error("Failed to fetch dashboard",{cause:a})}),o=i.orgs.filter(a=>a.role!=="app-member");i.orgs=o;let s=await A(new d.AppSelector({startingMenuIndex:0,defaultAppName:y(e),allowCreate:!0,allowEphemeral:!0,api:{getDash(){return i},createEphemeralApp(a){return F(a,n)},getAppsForOrg:async a=>{let{apps:p}=await we(r,a);return{apps:p}},createApp:async(a,p)=>{let{appId:f,adminToken:g}=await fe(a,r,p,n);return{appId:f,adminToken:g}}},modifyOutput:d.ciaModifier()}));return s?.approach==="import"&&W(s.appId,r,n),s};function gt(e){return new Promise(t=>setTimeout(t,e))}async function ht({secret:e}){for(let t=1;t<=120;t++){await gt(1e3);let n=await fetch(`${L}/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 wt(e){let t=ge();return await at(t.appConfigDirPath,{recursive:!0}),st(t.authConfigFilePath,e,"utf-8")}import yt from"fs-extra";import Tt from"path";var bt={"next-js-app-dir":"NEXT_PUBLIC_INSTANT_APP_ID","vite-react":"VITE_INSTANT_APP_ID","vite-vanilla":"VITE_INSTANT_APP_ID",expo:"EXPO_PUBLIC_INSTANT_APP_ID","tanstack-start":"VITE_INSTANT_APP_ID","bun-react":"BUN_PUBLIC_INSTANT_APP_ID","solidjs-vite":"VITE_INSTANT_APP_ID",sveltekit:"VITE_INSTANT_APP_ID","vue-vite":"VITE_INSTANT_APP_ID","tanstack-start-with-tanstack-query":"VITE_INSTANT_APP_ID","vercel-ai-sdk":"NEXT_PUBLIC_INSTANT_APP_ID","ai-chat":"NEXT_PUBLIC_INSTANT_APP_ID"},Te=(e,t,n,r)=>{let i=Tt.join(t,".env"),s=`${bt[e.base]}=${n}
16
- INSTANT_APP_ADMIN_TOKEN=${r}`;yt.writeFileSync(i,s)};import{stdin as b,stdout as be}from"process";import{setRawModeWindowsFriendly as Ie}from"instant-cli/ui";async function It(){return new Promise(e=>{if(!be.isTTY||!b.isTTY){e(null);return}let t=b.isRaw;t||Ie(b,!0);let n=setTimeout(()=>{i(),e(null)},100),r="",i=()=>{clearTimeout(n),b.removeListener("data",o),!t&&b.isTTY&&Ie(b,!1)},o=s=>{let a=s.toString();r+=a;let p=r.match(/\x1b\]11;rgb:([0-9a-fA-F]+)\/([0-9a-fA-F]+)\/([0-9a-fA-F]+)(?:\x1b\\|\x07)/);if(p){i();let[,f,g,M]=p;e(`rgb:${f}/${g}/${M}`)}};b.on("data",o),be.write("\x1B]11;?\x1B\\")})}function kt(e){let t=e.match(/rgb:([0-9a-fA-F]+)\/([0-9a-fA-F]+)\/([0-9a-fA-F]+)/);if(!t)return null;let[,n,r,i]=t,o=Math.round(parseInt(n,16)/257),s=Math.round(parseInt(r,16)/257),a=Math.round(parseInt(i,16)/257);return{r:o,g:s,b:a}}function _t(e){return(.299*e.r+.587*e.g+.114*e.b)/255>.5}async function ke(){try{let e=await It();if(!e)return"unknown";let t=kt(e);return t?_t(t)?"light":"dark":"unknown"}catch(e){return console.error("Error detecting terminal theme:",e),"unknown"}}import S from"chalk";var x=(e,t)=>e==="light"?S.bgYellowBright(t):S.bgBlackBright(t),_e=(e,t=console.log,n=!1)=>{let r=(process.stdout.columns||80)-4,i=e.split(`
17
- `),o=!0;i.forEach(s=>{if(s.length===0){o?(t(""),o=!1):console.log(S.gray("\u2502"));return}for(let a=0;a<s.length;a+=r){let p=s.slice(a,a+r);a+r<s.length&&p.length===r&&(p=p+"-"),o?(t(p),o=!1):console.log(S.gray("\u2502 ")+p)}}),n&&console.log(S.gray("\u2502"))};var N="\x1B[?25h";import{execa as St}from"execa";import xe from"fs-extra";import{permsTypescriptFileToCode as xt,schemaTypescriptFileToInstantSchema as vt}from"@instantdb/platform";function ve(e){for(let t of["src/instant.perms.ts","instant.perms.ts"])try{let n=xe.readFileSync(`${e}/${t}`,"utf8");return{code:xt(n,t)}}catch{}return null}function Pe(e){for(let t of["src/instant.schema.ts","instant.schema.ts"])try{let n=xe.readFileSync(`${e}/${t}`,"utf8");return vt(n,t)}catch{}return null}import{UI as v}from"instant-cli/ui";var Ae=e=>{if(e){if(e.approach==="import"){v.log(`Imported app with App ID: ${e.appId}`,v.ciaModifier());return}e.approach==="create"&&v.log(`Created new app with App ID: ${e.appId}`,v.ciaModifier()),e.approach==="ephemeral"&&v.log(`Created temporary app with App ID: ${e.appId}`,v.ciaModifier())}};var Nt=async()=>{process.argv.some(g=>["-h","--help","--version","-V"].includes(g))||ee();let e=await ke(),t=await Z(),[n,r]=Y(t.appName),i=T(t.base),o=await re(t,r);ie({projectDir:o,ruleFilesToAdd:t.ruleFiles});let s={template:t.base,aiTool:t.ruleFiles??"none",usedAiPrompt:!!t.prompt,rules:ve(o),schema:Pe(o)},a=await ye(r==="."?n:r,t,s);Ae(a),a&&Te(t,o,a.appId,a.adminToken);let p=Ne.readJSONSync(Se.join(o,"package.json"));if(p.name=n,i!=="bun"){let{stdout:g}=await St(i,["-v"],{cwd:o});p.packageManager=`${i}@${g.trim()}`}Ne.writeJSONSync(Se.join(o,"package.json"),p,{spaces:2}),await oe(T(t.base),o),t.createRepo&&await ce(o),t.prompt&&(await J(t.prompt,o),process.stdout.write(N)),Pt("Done!");let f=t.base==="expo"?"start":"dev";a?(console.log(`
15
+ `,defaultValue:!1,modifyOutput:v.ciaModifier()})))return;try{let i=ot(),{major:a,minor:o}=rt();a<2||a==2&&o<28?(await _("git",["init"],{cwd:e}),await _("git",["symbolic-ref","HEAD",`refs/heads/${i}`],{cwd:e})):await _("git",["init",`--initial-branch=${i}`],{cwd:e}),await _("git",["add","."],{cwd:e}),await _("git",["commit","-m","Initial commit (create-instant-app)"],{cwd:e}),v.log(M.dim(`${M.green("\u2713")} Git repository initialized successfully.`),v.ciaModifier(null))}catch{}};import it from"env-paths";import{mkdir as st,readFile as pt,writeFile as lt}from"node:fs/promises";import ct from"open";import{join as dt}from"node:path";import{randomUUID as we}from"node:crypto";import{version as at}from"@instantdb/version";var ge=!!process.env.INSTANT_CLI_DEV,he=ge?"http://localhost:3000":"https://instantdb.com",J=process.env.INSTANT_CLI_API_URI||(ge?"http://localhost:8888":"https://api.instantdb.com");async function y({path:e,body:t,method:n="GET",authToken:r,metadata:i}){let o={"Content-Type":"application/json","X-Instant-Source":"create-instant-app","X-Instant-Version":at,"X-Instant-Command":"create"};r&&(o.Authorization=`Bearer ${r}`),i&&(o["X-Instant-Metadata"]=JSON.stringify(i));let s=await fetch(`${J}${e}`,{method:n??"GET",headers:o,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 S,UI as u}from"instant-cli/ui";function T(e){return e.replace(/[-_]/g," ").replace(/\b\w/g,t=>t.toUpperCase())}var ut=!!process.env.INSTANT_CLI_DEV,mt=!!process.env.INSTANT_CLI_FORCE_EPHEMERAL;function Te(){let e=`instantdb-${ut?"dev":"prod"}`,{config:t}=it(e);return{authConfigFilePath:dt(t,"a"),appConfigDirPath:t}}var ye=async(e,t,n,r)=>{let i=we(),a=we(),o={id:i,title:e,admin_token:a,org_id:n};return r?.rules&&(o.rules=r.rules),r?.schema&&(o.schema=r.schema),await y({method:"POST",authToken:t,path:"/dash/apps",body:o,metadata:r}),{appId:i,adminToken:a,source:"created"}},H=(e,t,n)=>{y({method:"POST",path:`/dash/apps/${e}/track-import`,authToken:t,metadata:n}).catch(()=>{})},be=async e=>await y({method:"GET",path:"/dash",authToken:e}),Ie=async(e,t)=>await y({method:"GET",path:`/dash/orgs/${t}`,authToken:e});var ft=async(e,t)=>{try{let n=await be(e),r=n.apps.find(i=>i.id===t);if(r)return{appId:r.id,adminToken:r.admin_token};for(let i of n.orgs){let{apps:a}=await Ie(e,i.id),o=a.find(s=>s.id===t);if(o)return{appId:o.id,adminToken:o.admin_token}}return null}catch{return null}},gt=async(e,t)=>{try{return await y({method:"GET",path:`/dash/apps/${e}/schema/pull`,authToken:t}),!0}catch{return!1}},ht=async()=>mt?null:process.env.INSTANT_CLI_AUTH_TOKEN?process.env.INSTANT_CLI_AUTH_TOKEN:await pt(Te().authConfigFilePath,"utf-8").catch(()=>null),D=async(e,t)=>{let n=await y({authToken:null,method:"POST",path:"/dash/apps/ephemeral",body:{title:e,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 r=await ht();if(t?.yes&&!t?.app)if(r&&!t.temporary){let{appId:s,adminToken:p}=await ye(T(e),r,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 S(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 gt(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)),H(t.app,t.token,n),{appId:t.app,adminToken:t.token,approach:"import"}}if(r){let s=await ft(r,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)),H(s.appId,r,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(!r){let s=await S(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 y({authToken:null,method:"POST",path:"/dash/cli/auth/register"}).catch(P=>{throw new Error("Failed to register",{cause:P})}),{secret:c,ticket:h}=p;ct(`${he}/dash?ticket=${h}`);let x=yt({secret:c}),C=await S(new u.Spinner({promise:x,workingText:"Waiting for login in browser",disappearWhenDone:!0,modifyOutput:u.ciaModifier(null)}));await Tt(C.token),r=C.token}if(s==="skip")return u.log("Skipping app link step",u.ciaModifier(null)),null;if(s==="ephemeral"){let p=await S(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(!r)return null;let i=await be(r).catch(s=>{throw new Error("Failed to fetch dashboard",{cause:s})}),a=i.orgs.filter(s=>s.role!=="app-member");i.orgs=a;let o=await S(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 Ie(r,s);return{apps:p}},createApp:async(s,p)=>{let{appId:c,adminToken:h}=await ye(s,r,p,n);return{appId:c,adminToken:h}}},modifyOutput:u.ciaModifier()}));return o?.approach==="import"&&H(o.appId,r,n),o};function wt(e){return new Promise(t=>setTimeout(t,e))}async function yt({secret:e}){for(let t=1;t<=120;t++){await wt(1e3);let n=await fetch(`${J}/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){let t=Te();return await st(t.appConfigDirPath,{recursive:!0}),lt(t.authConfigFilePath,e,"utf-8")}import bt from"fs-extra";import It from"path";var vt={"next-js-app-dir":"NEXT_PUBLIC_INSTANT_APP_ID","vite-react":"VITE_INSTANT_APP_ID","vite-vanilla":"VITE_INSTANT_APP_ID",expo:"EXPO_PUBLIC_INSTANT_APP_ID","tanstack-start":"VITE_INSTANT_APP_ID","bun-react":"BUN_PUBLIC_INSTANT_APP_ID","solidjs-vite":"VITE_INSTANT_APP_ID",sveltekit:"VITE_INSTANT_APP_ID","vue-vite":"VITE_INSTANT_APP_ID","tanstack-start-with-tanstack-query":"VITE_INSTANT_APP_ID","vercel-ai-sdk":"NEXT_PUBLIC_INSTANT_APP_ID","ai-chat":"NEXT_PUBLIC_INSTANT_APP_ID","python-script":"INSTANT_APP_ID"},_e=(e,t,n,r)=>{let i=It.join(t,".env"),a=vt[e.base],o=e.base==="python-script"?"INSTANT_ADMIN_TOKEN":"INSTANT_APP_ADMIN_TOKEN",s=`${a}=${n}
16
+ ${o}=${r}`;bt.writeFileSync(i,s)};import{stdin as b,stdout as ke}from"process";import{setRawModeWindowsFriendly as xe}from"instant-cli/ui";async function _t(){return new Promise(e=>{if(!ke.isTTY||!b.isTTY){e(null);return}let t=b.isRaw;t||xe(b,!0);let n=setTimeout(()=>{i(),e(null)},100),r="",i=()=>{clearTimeout(n),b.removeListener("data",a),!t&&b.isTTY&&xe(b,!1)},a=o=>{let s=o.toString();r+=s;let p=r.match(/\x1b\]11;rgb:([0-9a-fA-F]+)\/([0-9a-fA-F]+)\/([0-9a-fA-F]+)(?:\x1b\\|\x07)/);if(p){i();let[,c,h,x]=p;e(`rgb:${c}/${h}/${x}`)}};b.on("data",a),ke.write("\x1B]11;?\x1B\\")})}function kt(e){let t=e.match(/rgb:([0-9a-fA-F]+)\/([0-9a-fA-F]+)\/([0-9a-fA-F]+)/);if(!t)return null;let[,n,r,i]=t,a=Math.round(parseInt(n,16)/257),o=Math.round(parseInt(r,16)/257),s=Math.round(parseInt(i,16)/257);return{r:a,g:o,b:s}}function xt(e){return(.299*e.r+.587*e.g+.114*e.b)/255>.5}async function Pe(){try{let e=await _t();if(!e)return"unknown";let t=kt(e);return t?xt(t)?"light":"dark":"unknown"}catch(e){return console.error("Error detecting terminal theme:",e),"unknown"}}import N from"chalk";var g=(e,t)=>e==="light"?N.bgYellowBright(t):N.bgBlackBright(t),Ae=(e,t=console.log,n=!1)=>{let r=(process.stdout.columns||80)-4,i=e.split(`
17
+ `),a=!0;i.forEach(o=>{if(o.length===0){a?(t(""),a=!1):console.log(N.gray("\u2502"));return}for(let s=0;s<o.length;s+=r){let p=o.slice(s,s+r);s+r<o.length&&p.length===r&&(p=p+"-"),a?(t(p),a=!1):console.log(N.gray("\u2502 ")+p)}}),n&&console.log(N.gray("\u2502"))};var E="\x1B[?25h";import{execa as je}from"execa";import{createRequire as Nt}from"node:module";import Se from"fs-extra";import{permsTypescriptFileToCode as Pt,schemaTypescriptFileToInstantSchema as At}from"@instantdb/platform";function Ne(e){for(let t of["src/instant.perms.ts","instant.perms.ts"])try{let n=Se.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=Se.readFileSync(`${e}/${t}`,"utf8");return At(n,t)}catch{}return null}import{UI as k}from"instant-cli/ui";var Ce=e=>{if(e){if(e.approach==="import"){k.log(`Imported app with App ID: ${e.appId}`,k.ciaModifier());return}e.approach==="create"&&k.log(`Created new app with App ID: ${e.appId}`,k.ciaModifier()),e.approach==="ephemeral"&&k.log(`Created temporary app with App ID: ${e.appId}`,k.ciaModifier())}};var Et=async()=>{process.argv.some(c=>["-h","--help","--version","-V"].includes(c))||oe();let e=await Pe(),t=await ne(),[n,r]=Q(t.appName),i=t.base==="python-script",a=$(t.base),o=await se(t,r);ce({projectDir:o,ruleFilesToAdd:t.ruleFiles});let s={template:t.base,aiTool:t.ruleFiles??"none",usedAiPrompt:!!t.prompt,rules:Ne(o),schema:Ee(o)},p=await ve(r==="."?n:r,t,s);if(Ce(p),p&&_e(t,o,p.appId,p.adminToken),i){let c=n.replace(/^@/,"").replace(/\//g,"-"),h=Y.join(o,"pyproject.toml"),x=U.readFileSync(h,"utf-8");U.writeFileSync(h,x.replace(/^name = .*$/m,`name = "${c}"`));let C=Nt(import.meta.url).resolve("instant-cli/bin/index.js");try{await je("node",[C,"genpy"],{cwd:o,stdio:"inherit"})}catch(P){V.warn("instant-cli genpy failed; run `npx instant-cli genpy` in your project to refresh Python types."),V.warn(P instanceof Error?P.message:String(P))}}else{let c=U.readJSONSync(Y.join(o,"package.json"));if(c.name=n,a!=="bun"){let{stdout:h}=await je(a,["-v"],{cwd:o});c.packageManager=`${a}@${h.trim()}`}U.writeJSONSync(Y.join(o,"package.json"),c,{spaces:2}),await pe(a,o)}if(t.createRepo&&await fe(o),t.prompt&&(await q(t.prompt,o),process.stdout.write(E)),St("Done!"),i)p?(console.log(`
18
18
  \u{1F389} Success! Your project is ready to go!
19
19
 
20
20
  To get started:
21
- 1. ${x(e,"cd "+r)}
22
- 2. ${x(e,T(t.base)+" run "+f)}
23
- `),a.approach==="ephemeral"&&console.log(`
21
+ 1. ${g(e,"cd "+r)}
22
+ 2. ${g(e,"uv sync")}
23
+ 3. ${g(e,"uv run --env-file .env python main.py")}
24
+ `),p.approach==="ephemeral"&&console.log(`
24
25
  An ephemeral app has been created and added to your .env file.
25
- It will expire in two weeks. For a permanent app, sign in and use ${x(e,"npx instant-cli claim")}
26
+ It will expire in two weeks. For a permanent app, sign in and use ${g(e,"npx instant-cli claim")}
26
27
  `)):console.log(`
27
28
  \u{1F389} Success! Your project is ready to go!
28
29
 
29
30
  To get started:
30
- 1. ${x(e,"cd "+r)}
31
- 2. Create a new app on ${At.underline("www.instantdb.com")}
31
+ 1. ${g(e,"cd "+r)}
32
+ 2. Create a new app on ${Oe.underline("www.instantdb.com")}
32
33
  3. Add your APP_ID to the .env file
33
- 4. ${x(e,T(t.base)+" run "+f)}
34
- `),process.stdout.write(N),process.exit(0)};Nt().catch(e=>{Ee.error("Aborting installation..."),_e(e.message,Ee.error),process.stdout.write(N),process.exit(1)});process.on("SIGINT",()=>{process.stdout.write(N),process.exit(0)});
34
+ 4. ${g(e,"uv sync")}
35
+ 5. ${g(e,"uv run --env-file .env python main.py")}
36
+ `);else{let c=t.base==="expo"?"start":"dev";p?(console.log(`
37
+ \u{1F389} Success! Your project is ready to go!
38
+
39
+ To get started:
40
+ 1. ${g(e,"cd "+r)}
41
+ 2. ${g(e,a+" run "+c)}
42
+ `),p.approach==="ephemeral"&&console.log(`
43
+ An ephemeral app has been created and added to your .env file.
44
+ It will expire in two weeks. For a permanent app, sign in and use ${g(e,"npx instant-cli claim")}
45
+ `)):console.log(`
46
+ \u{1F389} Success! Your project is ready to go!
47
+
48
+ To get started:
49
+ 1. ${g(e,"cd "+r)}
50
+ 2. Create a new app on ${Oe.underline("www.instantdb.com")}
51
+ 3. Add your APP_ID to the .env file
52
+ 4. ${g(e,a+" run "+c)}
53
+ `)}process.stdout.write(E),process.exit(0)};Et().catch(e=>{V.error("Aborting installation..."),Ae(e.message,V.error),process.stdout.write(E),process.exit(1)});process.on("SIGINT",()=>{process.stdout.write(E),process.exit(0)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-instant-app",
3
- "version": "1.0.40",
3
+ "version": "1.0.41-branch-python-sdk-v1.26586025551.1",
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": {
@@ -35,9 +35,9 @@
35
35
  "slugify": "^1.6.6",
36
36
  "sort-package-json": "^2.10.0",
37
37
  "tiged": "^2.12.7",
38
- "@instantdb/version": "1.0.40",
39
- "@instantdb/platform": "1.0.40",
40
- "instant-cli": "1.0.40"
38
+ "@instantdb/platform": "1.0.41-branch-python-sdk-v1.26586025551.1",
39
+ "@instantdb/version": "1.0.41-branch-python-sdk-v1.26586025551.1",
40
+ "instant-cli": "1.0.41-branch-python-sdk-v1.26586025551.1"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@anthropic-ai/sdk": "^0.60.0",
@@ -0,0 +1,2 @@
1
+ INSTANT_APP_ID=
2
+ INSTANT_ADMIN_TOKEN=
@@ -0,0 +1,16 @@
1
+ # Welcome to your InstantDB Python script 👋
2
+
3
+ [InstantDB Docs](https://www.instantdb.com/docs/start-python)
4
+
5
+ This is a Python script scaffolded with create-instant-app.
6
+
7
+ To install dependencies:
8
+ `uv sync`
9
+
10
+ To run the script:
11
+ `uv run --env-file .env python main.py`
12
+
13
+ To push schema and permission changes (requires Node):
14
+ `npx instant-cli push`
15
+
16
+ Got any feedback or questions? Join our [Discord](https://discord.gg/hgVf9R6SBm)
@@ -0,0 +1,5 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ uv.lock
5
+ .env
@@ -0,0 +1,13 @@
1
+ // Docs: https://www.instantdb.com/docs/permissions
2
+
3
+ import type { InstantRules } from "@instantdb/core";
4
+
5
+ const rules = {
6
+ /**
7
+ * Welcome to Instant's permission system!
8
+ * Right now your rules are empty. To start filling them in, check out the docs:
9
+ * https://www.instantdb.com/docs/permissions
10
+ */
11
+ } satisfies InstantRules;
12
+
13
+ export default rules;
@@ -0,0 +1,29 @@
1
+ // Docs: https://www.instantdb.com/docs/modeling-data
2
+
3
+ import { i } from "@instantdb/core";
4
+
5
+ const _schema = i.schema({
6
+ entities: {
7
+ $files: i.entity({
8
+ path: i.string().unique().indexed(),
9
+ url: i.string(),
10
+ }),
11
+ $users: i.entity({
12
+ email: i.string().unique().indexed().optional(),
13
+ }),
14
+ todos: i.entity({
15
+ text: i.string(),
16
+ done: i.boolean(),
17
+ createdAt: i.number(),
18
+ }),
19
+ },
20
+ links: {},
21
+ rooms: {},
22
+ });
23
+
24
+ type _AppSchema = typeof _schema;
25
+ interface AppSchema extends _AppSchema {}
26
+ const schema: AppSchema = _schema;
27
+
28
+ export type { AppSchema };
29
+ export default schema;
@@ -0,0 +1,14 @@
1
+ """Fallback so `from instant_types import ...` works before codegen runs.
2
+
3
+ Run `npx instant-cli genpy` to replace this with a schema-bound module
4
+ that gives you typed `db.tx.<entity>` and validated query results.
5
+ """
6
+
7
+ from instantdb import (
8
+ AsyncInstant,
9
+ Instant,
10
+ InstantAPIError,
11
+ InstantError,
12
+ id,
13
+ lookup,
14
+ )
@@ -0,0 +1,36 @@
1
+ """Hello world InstantDB script.
2
+
3
+ Reads INSTANT_APP_ID and INSTANT_ADMIN_TOKEN from the environment. Run:
4
+
5
+ uv run --env-file .env python main.py
6
+ """
7
+
8
+ import time
9
+
10
+ from instant_types import Instant, id
11
+
12
+ db = Instant()
13
+
14
+
15
+ def main() -> None:
16
+ todo_id = id()
17
+ db.transact(
18
+ db.tx.todos[todo_id].update(
19
+ {
20
+ "text": "Hello from Python!",
21
+ "done": False,
22
+ "createdAt": int(time.time() * 1000),
23
+ }
24
+ )
25
+ )
26
+
27
+ result = db.query({"todos": {}})
28
+ print(f"Found {len(result['todos'])} todo(s):")
29
+ for todo in result["todos"]:
30
+ row = todo.model_dump() if hasattr(todo, "model_dump") else todo
31
+ status = "x" if row["done"] else " "
32
+ print(f" [{status}] {row['text']}")
33
+
34
+
35
+ if __name__ == "__main__":
36
+ main()
@@ -0,0 +1,6 @@
1
+ [project]
2
+ name = "python-script"
3
+ version = "0.0.0"
4
+ description = "InstantDB Python script starter"
5
+ requires-python = ">=3.10"
6
+ dependencies = ["instantdb"]