create-instant-app 0.22.107 → 0.22.108-experimental.drewh-use-clone.21267978145.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.
Files changed (69) hide show
  1. package/dist/index.js +12 -11
  2. package/package.json +6 -3
  3. package/template/base/expo/README.md +0 -15
  4. package/template/base/expo/_env +0 -2
  5. package/template/base/expo/_gitignore +0 -41
  6. package/template/base/expo/app/+not-found.tsx +0 -16
  7. package/template/base/expo/app/_layout.tsx +0 -37
  8. package/template/base/expo/app/index.tsx +0 -64
  9. package/template/base/expo/app.json +0 -42
  10. package/template/base/expo/assets/fonts/SpaceMono-Regular.ttf +0 -0
  11. package/template/base/expo/assets/images/adaptive-icon.png +0 -0
  12. package/template/base/expo/assets/images/favicon.png +0 -0
  13. package/template/base/expo/assets/images/icon.png +0 -0
  14. package/template/base/expo/assets/images/partial-react-logo.png +0 -0
  15. package/template/base/expo/assets/images/react-logo.png +0 -0
  16. package/template/base/expo/assets/images/react-logo@2x.png +0 -0
  17. package/template/base/expo/assets/images/react-logo@3x.png +0 -0
  18. package/template/base/expo/assets/images/splash-icon.png +0 -0
  19. package/template/base/expo/babel.config.js +0 -12
  20. package/template/base/expo/constants/Colors.ts +0 -26
  21. package/template/base/expo/eslint.config.js +0 -10
  22. package/template/base/expo/expo-env.d.ts +0 -3
  23. package/template/base/expo/global.css +0 -3
  24. package/template/base/expo/hooks/useColorScheme.ts +0 -1
  25. package/template/base/expo/hooks/useColorScheme.web.ts +0 -21
  26. package/template/base/expo/hooks/useThemeColor.ts +0 -21
  27. package/template/base/expo/instant.perms.ts +0 -24
  28. package/template/base/expo/instant.schema.ts +0 -44
  29. package/template/base/expo/lib/db.ts +0 -7
  30. package/template/base/expo/metro.config.js +0 -6
  31. package/template/base/expo/nativewind-env.d.ts +0 -1
  32. package/template/base/expo/package.json +0 -56
  33. package/template/base/expo/scripts/reset-project.js +0 -112
  34. package/template/base/expo/tailwind.config.js +0 -9
  35. package/template/base/expo/tsconfig.json +0 -18
  36. package/template/base/next-js-app-dir/README.md +0 -15
  37. package/template/base/next-js-app-dir/_env +0 -2
  38. package/template/base/next-js-app-dir/_gitignore +0 -41
  39. package/template/base/next-js-app-dir/next-env.d.ts +0 -5
  40. package/template/base/next-js-app-dir/next.config.ts +0 -7
  41. package/template/base/next-js-app-dir/package.json +0 -26
  42. package/template/base/next-js-app-dir/postcss.config.mjs +0 -5
  43. package/template/base/next-js-app-dir/public/file.svg +0 -1
  44. package/template/base/next-js-app-dir/public/globe.svg +0 -1
  45. package/template/base/next-js-app-dir/public/next.svg +0 -1
  46. package/template/base/next-js-app-dir/public/vercel.svg +0 -1
  47. package/template/base/next-js-app-dir/public/window.svg +0 -1
  48. package/template/base/next-js-app-dir/src/app/favicon.ico +0 -0
  49. package/template/base/next-js-app-dir/src/app/globals.css +0 -26
  50. package/template/base/next-js-app-dir/src/app/layout.tsx +0 -34
  51. package/template/base/next-js-app-dir/src/app/page.tsx +0 -169
  52. package/template/base/next-js-app-dir/src/instant.perms.ts +0 -24
  53. package/template/base/next-js-app-dir/src/instant.schema.ts +0 -50
  54. package/template/base/next-js-app-dir/src/lib/db.ts +0 -8
  55. package/template/base/next-js-app-dir/tsconfig.json +0 -27
  56. package/template/base/vite-vanilla/README.md +0 -15
  57. package/template/base/vite-vanilla/_env +0 -2
  58. package/template/base/vite-vanilla/_gitignore +0 -25
  59. package/template/base/vite-vanilla/index.html +0 -13
  60. package/template/base/vite-vanilla/package.json +0 -19
  61. package/template/base/vite-vanilla/public/vite.svg +0 -1
  62. package/template/base/vite-vanilla/src/instant.perms.ts +0 -24
  63. package/template/base/vite-vanilla/src/instant.schema.ts +0 -50
  64. package/template/base/vite-vanilla/src/lib/db.ts +0 -11
  65. package/template/base/vite-vanilla/src/main.ts +0 -242
  66. package/template/base/vite-vanilla/src/style.css +0 -96
  67. package/template/base/vite-vanilla/src/typescript.svg +0 -1
  68. package/template/base/vite-vanilla/src/vite-env.d.ts +0 -1
  69. package/template/base/vite-vanilla/tsconfig.json +0 -24
package/dist/index.js CHANGED
@@ -1,23 +1,24 @@
1
1
  #!/usr/bin/env node
2
- import{Command as _e,Option as l}from"commander";import*as F from"@clack/prompts";import{spawn as ke}from"child_process";import{execa as be}from"execa";async function M(){return new Promise(e=>{let t=process.env.SHELL||"/bin/bash",n=ke(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 D=async(e,t)=>{let n=await M();if(!n)throw new Error("Claude not found in path");await be(n,[e],{stdio:"inherit",cwd:t})};import{version as Ae}from"@instantdb/version";import V from"path";var L=e=>(e.length>1&&e.endsWith("/")&&(e=e.slice(0,-1)),e),Te=/^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/,z=e=>{let n=L(e).split("/"),r=n[n.length-1];if(r==="."){let o=V.resolve(process.cwd());r=V.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]},C=e=>e.trim(),$=e=>{let t=L(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==="."||Te.test(i??"")))return"App name must consist of only lowercase alphanumeric characters, '-', and '_'"};import{renderUnwrap as S,UI as u}from"instant-cli/ui";var Ie={base:"next-js-app-dir",appName:"Awesome Todos",ruleFiles:null,createRepo:!0,prompt:null},H=async()=>{let e=Ie,t=new _e().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-vanilla","expo"])).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("--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)")).version(Ae).parse(process.argv),n=t.args[0]&&C(t.args[0]);if(n){let o=$(n);if(o)throw new Error("Invalid app name: "+o);e.appName=n}let r=t.opts();if(r.ai&&!await M())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");let i=await F.group({appName:async()=>{if(n)return n.trim();let o=await S(new u.TextInput({prompt:"What will your project/folder be called?",placeholder:"awesome-todos",defaultValue:"awesome-todos",validate:s=>$(C(s)),modifyOutput:u.ciaModifier()}));return C(o)},prompt:async()=>r.ai?await S(new u.TextInput({prompt:"What would you like to create?",placeholder:"Create an app that...",modifyOutput:u.modifiers.piped([u.ciaModifier()])})):null,base:async({results:o})=>r.base?r.base:r.vanilla?"vite-vanilla":r.next?"next-js-app-dir":r.expo?"expo":o.prompt?S(new u.Select({promptText:"What framework would you like to use?",options:[{value:"next-js-app-dir",label:"Next.js"},{value:"expo",label:"Expo: React Native"}],defaultValue:"next-js-app-dir",modifyOutput:u.modifiers.piped([u.ciaModifier()])})):S(new u.Select({promptText:"What framework would you like to use?",options:[{value:"next-js-app-dir",label:"Next.js"},{value:"vite-vanilla",label:"Vite: Vanilla TS"},{value:"expo",label:"Expo: React Native"}],defaultValue:"next-js-app-dir",modifyOutput:u.modifiers.piped([u.ciaModifier()])})),ruleFiles:async({results:o})=>o.prompt?"claude":r.cursor?"cursor":r.claude?"claude":r.codex?"codex":r.gemini?"gemini":r.rules?"codex":S(new u.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:u.ciaModifier()})),createRepo:async()=>r.git!==void 0?r.git:!0},{onCancel(){process.exit(1)}}),a={app:r.app??null,token:r.token??null};return{project:i,appFlags:a}};import we from"path";import ye from"fs-extra";import{log as xe,outro as lt}from"@clack/prompts";import{intro as Pe}from"@clack/prompts";import J from"chalk";var ve=` _ _ _
2
+ import{Command as Ie,Option as l}from"commander";import*as F from"@clack/prompts";import{spawn as xe}from"child_process";import{execa as ke}from"execa";async function M(){return new Promise(e=>{let t=process.env.SHELL||"/bin/bash",n=xe(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 W=async(e,t)=>{let n=await M();if(!n)throw new Error("Claude not found in path");await ke(n,[e],{stdio:"inherit",cwd:t})};import{version as _e}from"@instantdb/version";import L from"path";var V=e=>(e.length>1&&e.endsWith("/")&&(e=e.slice(0,-1)),e),be=/^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/,z=e=>{let n=V(e).split("/"),o=n[n.length-1];if(o==="."){let r=L.resolve(process.cwd());o=L.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]},C=e=>e.trim(),$=e=>{let t=V(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==="."||be.test(i??"")))return"App name must consist of only lowercase alphanumeric characters, '-', and '_'"};import{renderUnwrap as N,UI as m}from"instant-cli/ui";var Ae={base:"next-js-app-dir",appName:"Awesome Todos",ruleFiles:null,createRepo:!0,prompt:null},H=async()=>{let e=Ae,t=new Ie().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-vanilla","expo"])).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("--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)")).version(_e).parse(process.argv),n=t.args[0]&&C(t.args[0]);if(n){let r=$(n);if(r)throw new Error("Invalid app name: "+r);e.appName=n}let o=t.opts();if(o.ai&&!await M())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");let i=await F.group({appName:async()=>{if(n)return n.trim();let r=await N(new m.TextInput({prompt:"What will your project/folder be called?",placeholder:"awesome-todos",defaultValue:"awesome-todos",validate:s=>$(C(s)),modifyOutput:m.ciaModifier()}));return C(r)},prompt:async()=>o.ai?await N(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:r})=>o.base?o.base:o.vanilla?"vite-vanilla":o.next?"next-js-app-dir":o.expo?"expo":r.prompt?N(new m.Select({promptText:"What framework would you like to use?",options:[{value:"next-js-app-dir",label:"Next.js"},{value:"expo",label:"Expo: React Native"}],defaultValue:"next-js-app-dir",modifyOutput:m.modifiers.piped([m.ciaModifier()])})):N(new m.Select({promptText:"What framework would you like to use?",options:[{value:"next-js-app-dir",label:"Next.js"},{value:"vite-vanilla",label:"Vite: Vanilla TS"},{value:"expo",label:"Expo: React Native"}],defaultValue:"next-js-app-dir",modifyOutput:m.modifiers.piped([m.ciaModifier()])})),ruleFiles:async({results:r})=>r.prompt?"claude":o.cursor?"cursor":o.claude?"claude":o.codex?"codex":o.gemini?"gemini":o.rules?"codex":N(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()=>o.git!==void 0?o.git:!0},{onCancel(){process.exit(1)}}),a={app:o.app??null,token:o.token??null};return{project:i,appFlags:a}};import we from"path";import ye from"fs-extra";import{log as Te,outro as ft}from"@clack/prompts";import{intro as Pe}from"@clack/prompts";import J from"chalk";var ve=` _ _ _
3
3
  \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 (_) | | | |
4
4
  \u2588 \u2588\u2588\u2588\u2588 _ _ __ ___| |_ __ _ _ _ _| |_
5
5
  \u2588 \u2588\u2588\u2588\u2588 | | '_ \\/ __| __/ _\\\`| '_ \\| __|
6
6
  \u2588 \u2588\u2588\u2588\u2588 | | | | \\__ \\ || (_| | | | | |_
7
- \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 |_|_| |_|___/\\__\\__,_|_| |_|\\__|`,K=()=>{Pe(`
7
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 |_|_| |_|___/\\__\\__,_|_| |_|\\__|`,Y=()=>{Pe(`
8
8
  `+ve.split(`
9
9
  `).map(e=>`${J.gray("\u2502")}${J.hex("#EA580D").bold(" "+e)}`).join(`
10
- `))};import f from"path";import h from"fs-extra";import Y from"path";import{fileURLToPath as Se}from"url";var Ne=Se(import.meta.url),Ce=Y.dirname(Ne),g=Y.join(Ce,"../");import A from"chalk";var k=()=>{let e=process.env.npm_config_user_agent;return e?e.startsWith("yarn")?"yarn":e.startsWith("pnpm")?"pnpm":e.startsWith("bun")?"bun":"npm":"npm"};import{renderUnwrap as je,UI as b}from"instant-cli/ui";import Oe from"slugify";var X=async(e,t)=>{let n=f.resolve(process.cwd(),t),r=f.join(g,`template/base/${e.base}`);if(h.existsSync(n))if(h.readdirSync(n).length===0)b.log(`${A.cyan.bold(e.appName)} exists but is empty, continuing...`,b.ciaModifier(null));else{let a=await je(new b.Select({promptText:A.redBright(`${A.bold("Warning:")} ${A.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:b.ciaModifier()}));a==="abort"&&(b.log("Aborting installation..."),process.exit(1)),a==="clear"&&h.emptyDirSync(n)}if(h.copySync(r,n),h.renameSync(f.join(n,"_gitignore"),f.join(n,".gitignore")),h.renameSync(f.join(n,"_env"),f.join(n,".env")),k()==="pnpm"&&e.base==="expo"&&h.appendFile(f.join(n,".npmrc"),`node-linker=hoisted
11
- enable-pre-post-scripts=true`),e.base==="expo"){let a=Oe.default(t);G(f.join(n,"app.json"),'"name": "expo-template"',`"name": "${t}"`),G(f.join(n,"app.json"),'"slug": "expo-template"',`"slug": "${a}"`),G(f.join(n,"app/_layout.tsx"),'"My Instant App"',`"${t}"`)}let i=e.appName==="."?"App":A.hex("#EA570B").bold(e.appName);return b.log(A.dim(`${i} scaffolded successfully!`),b.ciaModifier(null)),n},G=(e,t,n)=>{let i=h.readFileSync(e,"utf8").replaceAll(t,n);h.writeFileSync(e,i)};import{execa as Ee}from"execa";import{renderUnwrap as Me,UI as j}from"instant-cli/ui";var q=async(e,t)=>{let n=Ee(e,["install"],{cwd:t}),r=await Me(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 ct from"chalk";import y from"fs-extra";import c from"path";var Z=({projectDir:e,ruleFilesToAdd:t})=>{if(t!==null)switch(t){case"cursor":y.ensureDirSync(c.join(e,".cursor/rules")),y.copyFileSync(c.join(g,"template/rules/cursor-rules.md"),c.join(e,".cursor/rules/instant.mdc"));break;case"claude":y.copyFileSync(c.join(g,"template/rules/AGENTS.md"),c.join(e,"CLAUDE.md"));break;case"codex":y.copyFileSync(c.join(g,"template/rules/AGENTS.md"),c.join(e,"AGENTS.md"));break;case"gemini":y.copyFileSync(c.join(g,"template/rules/AGENTS.md"),c.join(e,"GEMINI.md"));break;case"zed":y.copyFileSync(c.join(g,"template/rules/AGENTS.md"),c.join(e,"AGENTS.md"));break;case"windsurf":y.ensureDirSync(c.join(e,".windsurf/rules")),y.copyFileSync(c.join(g,"template/rules/windsurf-rules.md"),c.join(e,".windsurf/rules/instant.md"));break}};import{execSync as B}from"child_process";import R from"path";import*as te from"@clack/prompts";import Q from"chalk";import{execa as P}from"execa";import ne from"fs-extra";import{renderUnwrap as ee,UI as I}from"instant-cli/ui";var $e=e=>{try{return B("git --version",{cwd:e}),!0}catch{return!1}},Fe=e=>ne.existsSync(R.join(e,".git")),Ge=async e=>{try{return await P("git",["rev-parse","--is-inside-work-tree"],{cwd:e,stdout:"ignore"}),!0}catch{return!1}},Re=()=>{let t=B("git --version").toString().trim().split(" ")[2],n=t?.split(".")[0],r=t?.split(".")[1];return{major:Number(n),minor:Number(r)}},Be=()=>B("git config --global init.defaultBranch || echo main").toString().trim(),oe=async e=>{if(!$e(e)){te.log.warn("Git is not installed. Skipping Git initialization.");return}let t=Fe(e),n=await Ge(e),r=R.parse(e).name;if(n&&t){if(!await ee(new I.Confirmation({promptText:`${Q.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:I.ciaModifier()})))return;ne.removeSync(R.join(e,".git"))}else if(n&&!t&&!await ee(new I.Confirmation({promptText:`${Q.redBright.bold("Warning:")} "${r}" is already in a git worktree.
10
+ `))};import f from"path";import g from"fs-extra";import Ne from"degit";import k from"chalk";var x=()=>{let e=process.env.npm_config_user_agent;return e?e.startsWith("yarn")?"yarn":e.startsWith("pnpm")?"pnpm":e.startsWith("bun")?"bun":"npm":"npm"};import{renderUnwrap as Se,UI as h}from"instant-cli/ui";import Ce from"slugify";import Oe from"ignore";var K=async(e,t)=>{let n=f.resolve(process.cwd(),t);if(g.existsSync(n))if(g.readdirSync(n).length===0)h.log(`${k.cyan.bold(e.appName)} exists but is empty, continuing...`,h.ciaModifier(null));else{let i=await Se(new h.Select({promptText:k.redBright(`${k.bold("Warning:")} ${k.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()}));i==="abort"&&(h.log("Aborting installation..."),process.exit(1)),i==="clear"&&g.emptyDirSync(n)}if(await Me({projectDir:n,baseTemplateName:e.base}),g.pathExistsSync(f.join(n,"pnpm-lock.yaml"))&&g.removeSync(f.join(n,"pnpm-lock.yaml")),x()==="pnpm"&&e.base==="expo"&&g.appendFile(f.join(n,".npmrc"),`node-linker=hoisted
11
+ enable-pre-post-scripts=true`),e.base==="expo"){let i=Ce.default(t);R(f.join(n,"app.json"),'"name": "expo-template"',`"name": "${t}"`),R(f.join(n,"app.json"),'"slug": "expo-template"',`"slug": "${i}"`),R(f.join(n,"app/_layout.tsx"),'"My Instant App"',`"${t}"`)}let o=e.appName==="."?"App":k.hex("#EA570B").bold(e.appName);return h.log(k.dim(`${o} scaffolded successfully!`),h.ciaModifier(null)),n},R=(e,t,n)=>{let i=g.readFileSync(e,"utf8").replaceAll(t,n);g.writeFileSync(e,i)},je=async({projectDir:e,baseTemplateName:t})=>{let n=`instantdb/instant/examples/${t}`;await Ne(n).clone(e)};async function Ee(e,t){let n=f.join(e,".gitignore"),o=Oe();o.add(".git");try{let i=await g.readFile(n,"utf8");o.add(i)}catch{}await g.copy(e,t,{filter:i=>{let a=f.relative(e,i);return a===""?!0:!o.ignores(a)}})}var Me=async({projectDir:e,baseTemplateName:t})=>{if(process.env.INSTANT_CLI_DEV&&process.env.INSTANT_REPO_FOLDER){let n=f.join(process.env.INSTANT_REPO_FOLDER,"examples",t);await Ee(n,e);return}process.env.INSTANT_CLI_DEV&&h.log(k.bold.yellowBright(`WARNING: INSTANT_CLI_DEV is TRUE but no INSTANT_REPO_FOLDER is set.
12
+ Using git to clone from main...`),h.ciaModifier(null)),await je({projectDir:e,baseTemplateName:t})};import{execa as $e}from"execa";import{renderUnwrap as Fe,UI as O}from"instant-cli/ui";var X=async(e,t)=>{let n=$e(e,["install"],{cwd:t}),o=await Fe(new O.Spinner({promise:n,workingText:`Installing dependencies with ${e}...`,doneText:"Successfully installed dependencies!",modifyOutput:O.ciaModifier(null)}));o.exitCode!==0&&(O.log(o.stderr,O.ciaModifier(null)),process.exit(1))};import gt from"chalk";import y from"fs-extra";import c from"path";import q from"path";import{fileURLToPath as Re}from"url";var Ge=Re(import.meta.url),De=q.dirname(Ge),b=q.join(De,"../");var Z=({projectDir:e,ruleFilesToAdd:t})=>{if(t!==null)switch(t){case"cursor":y.ensureDirSync(c.join(e,".cursor/rules")),y.copyFileSync(c.join(b,"template/rules/cursor-rules.md"),c.join(e,".cursor/rules/instant.mdc"));break;case"claude":y.copyFileSync(c.join(b,"template/rules/AGENTS.md"),c.join(e,"CLAUDE.md"));break;case"codex":y.copyFileSync(c.join(b,"template/rules/AGENTS.md"),c.join(e,"AGENTS.md"));break;case"gemini":y.copyFileSync(c.join(b,"template/rules/AGENTS.md"),c.join(e,"GEMINI.md"));break;case"zed":y.copyFileSync(c.join(b,"template/rules/AGENTS.md"),c.join(e,"AGENTS.md"));break;case"windsurf":y.ensureDirSync(c.join(e,".windsurf/rules")),y.copyFileSync(c.join(b,"template/rules/windsurf-rules.md"),c.join(e,".windsurf/rules/instant.md"));break}};import{execSync as D}from"child_process";import G from"path";import*as te from"@clack/prompts";import Q from"chalk";import{execa as P}from"execa";import ne from"fs-extra";import{renderUnwrap as ee,UI as A}from"instant-cli/ui";var Be=e=>{try{return D("git --version",{cwd:e}),!0}catch{return!1}},Ue=e=>ne.existsSync(G.join(e,".git")),We=async e=>{try{return await P("git",["rev-parse","--is-inside-work-tree"],{cwd:e,stdout:"ignore"}),!0}catch{return!1}},Le=()=>{let t=D("git --version").toString().trim().split(" ")[2],n=t?.split(".")[0],o=t?.split(".")[1];return{major:Number(n),minor:Number(o)}},Ve=()=>D("git config --global init.defaultBranch || echo main").toString().trim(),oe=async e=>{if(!Be(e)){te.log.warn("Git is not installed. Skipping Git initialization.");return}let t=Ue(e),n=await We(e),o=G.parse(e).name;if(n&&t){if(!await ee(new A.Confirmation({promptText:`${Q.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:A.ciaModifier()})))return;ne.removeSync(G.join(e,".git"))}else if(n&&!t&&!await ee(new A.Confirmation({promptText:`${Q.redBright.bold("Warning:")} "${o}" is already in a git worktree.
12
13
  Would you still like to initialize a new git repository in this directory?
13
- `,defaultValue:!1,modifyOutput:I.ciaModifier()})))return;try{let i=Be(),{major:a,minor:o}=Re();a<2||a==2&&o<28?(await P("git",["init"],{cwd:e}),await P("git",["symbolic-ref","HEAD",`refs/heads/${i}`],{cwd:e})):await P("git",["init",`--initial-branch=${i}`],{cwd:e}),await P("git",["add","."],{cwd:e}),await P("git",["commit","-m","Initial commit (create-instant-app)"],{cwd:e}),I.log("Git repository initialized successfully.",I.ciaModifier(null))}catch{}};import We from"env-paths";import*as De from"@clack/prompts";import{mkdir as Ve,readFile as Le,writeFile as ze}from"node:fs/promises";import He from"open";import{join as Je}from"node:path";import{randomUUID as ae}from"node:crypto";import{version as Ue}from"@instantdb/version";var re=!!process.env.INSTANT_CLI_DEV,ie=re?"http://localhost:3000":"https://instantdb.com",U=process.env.INSTANT_CLI_API_URI||(re?"http://localhost:8888":"https://api.instantdb.com");async function x({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":Ue,"X-Instant-Command":"create"};r&&(o.Authorization=`Bearer ${r}`),i&&(o["X-Instant-Metadata"]=JSON.stringify(i));let p=await fetch(`${U}${e}`,{method:n??"GET",headers:o,body:t?JSON.stringify(t):void 0,signal:AbortSignal.timeout(3e5)}),s;try{s=await p.json()}catch{s=null}if(!p.ok){let m=s.message||s.hint?.errors?.[0]?.message||"There was an error";throw new Error(m)}return s}import{renderUnwrap as O,UI as d}from"instant-cli/ui";var Ke=!!process.env.INSTANT_CLI_DEV,Ye=!!process.env.INSTANT_CLI_FORCE_EPHEMERAL;function pe(){let e=`instantdb-${Ke?"dev":"prod"}`,{config:t}=We(e);return{authConfigFilePath:Je(t,"a"),appConfigDirPath:t}}var Xe=async(e,t,n,r)=>{let i=ae(),a=ae();return await x({method:"POST",authToken:t,path:"/dash/apps",body:{id:i,title:e,admin_token:a,org_id:n},metadata:r}),{appID:i,adminToken:a,source:"created"}},W=(e,t,n)=>{x({method:"POST",path:`/dash/apps/${e}/track-import`,authToken:t,metadata:n}).catch(()=>{})},le=async e=>await x({method:"GET",path:"/dash",authToken:e}),ce=async(e,t)=>await x({method:"GET",path:`/dash/orgs/${t}`,authToken:e});var qe=async(e,t)=>{try{let n=await le(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 ce(e,i.id),o=a.find(p=>p.id===t);if(o)return{appId:o.id,adminToken:o.admin_token}}return null}catch{return null}},Ze=async(e,t)=>{try{return await x({method:"GET",path:`/dash/apps/${e}/schema/pull`,authToken:t}),!0}catch{return!1}},Qe=async()=>Ye?null:process.env.INSTANT_CLI_AUTH_TOKEN?process.env.INSTANT_CLI_AUTH_TOKEN:await Le(pe().authConfigFilePath,"utf-8").catch(()=>null),se=async(e,t)=>{let n=await x({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"]}},de=async(e,t)=>{let n=await Qe();if(e?.app){if(e.token){if(!await Ze(e.app,e.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: ${e.app}`,d.ciaModifier(null)),W(e.app,e.token,t),{appId:e.app,adminToken:e.token,approach:"import"}}if(n){let o=await qe(n,e.app);if(!o)throw new Error(`You don't have access to app "${e.app}". Please check the app ID or use --token to provide a token.`);return d.log(`Linking to app: ${e.app}`,d.ciaModifier(null)),W(o.appId,n,t),{appId:o.appId,adminToken:o.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 ${e.app} --token <token>`)}if(!n){let o=await O(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(o==="login"){let p=await x({authToken:null,method:"POST",path:"/dash/cli/auth/register"}),{secret:s,ticket:m}=p;He(`${ie}/dash?ticket=${m}`);let _=tt({secret:s}),w=await O(new d.Spinner({promise:_,workingText:"Waiting for login in browser",disappearWhenDone:!0,modifyOutput:d.ciaModifier(null)}));await nt(w.token),n=w.token}if(o==="skip")return d.log("Skipping app link step",d.ciaModifier(null)),null;if(o==="ephemeral"){let p=await O(new d.TextInput({defaultValue:"my-cool-app",prompt:"Enter a name for your temporary app:",placeholder:"my-cool-app",modifyOutput:d.ciaModifier()}));return{...await se(p,t),approach:"ephemeral"}}}if(!n)return null;let r=await le(n),i=r.orgs.filter(o=>o.role!=="app-member");r.orgs=i;let a=await O(new d.AppSelector({startingMenuIndex:0,allowCreate:!0,allowEphemeral:!0,api:{getDash(){return r},createEphemeralApp(o){return se(o,t)},getAppsForOrg:async o=>{let{apps:p}=await ce(n,o);return{apps:p}},createApp:async(o,p)=>{let{appID:s,adminToken:m}=await Xe(o,n,p,t);return{appId:s,adminToken:m}}},modifyOutput:d.ciaModifier()}));return a?.approach==="import"&&W(a.appId,n,t),a};function et(e){return new Promise(t=>setTimeout(t,e))}async function tt({secret:e}){for(let t=1;t<=120;t++){await et(1e3);let n=await fetch(`${U}/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 nt(e){let t=pe();return await Ve(t.appConfigDirPath,{recursive:!0}),ze(t.authConfigFilePath,e,"utf-8")}import ot from"fs-extra";import rt from"path";var it={"next-js-app-dir":"NEXT_PUBLIC_INSTANT_APP_ID","vite-vanilla":"VITE_INSTANT_APP_ID",expo:"EXPO_PUBLIC_INSTANT_APP_ID"},ue=(e,t,n,r)=>{let i=rt.join(t,".env"),o=`${it[e.base]}=${n}
14
- INSTANT_APP_ADMIN_TOKEN=${r}`;ot.writeFileSync(i,o)};import{stdin as T,stdout as me}from"process";import{setRawModeWindowsFriendly as fe}from"instant-cli/ui";async function at(){return new Promise(e=>{if(!me.isTTY||!T.isTTY){e(null);return}let t=T.isRaw;t||fe(T,!0);let n=setTimeout(()=>{i(),e(null)},100),r="",i=()=>{clearTimeout(n),T.removeListener("data",a),!t&&T.isTTY&&fe(T,!1)},a=o=>{let p=o.toString();r+=p;let s=r.match(/\x1b\]11;rgb:([0-9a-fA-F]+)\/([0-9a-fA-F]+)\/([0-9a-fA-F]+)(?:\x1b\\|\x07)/);if(s){i();let[,m,_,w]=s;e(`rgb:${m}/${_}/${w}`)}};T.on("data",a),me.write("\x1B]11;?\x1B\\")})}function st(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),p=Math.round(parseInt(i,16)/257);return{r:a,g:o,b:p}}function pt(e){return(.299*e.r+.587*e.g+.114*e.b)/255>.5}async function ge(){try{let e=await at();if(!e)return"unknown";let t=st(e);return t?pt(t)?"light":"dark":"unknown"}catch(e){return console.error("Error detecting terminal theme:",e),"unknown"}}import N from"chalk";var v=(e,t)=>e==="light"?N.bgYellowBright(t):N.bgBlackBright(t),he=(e,t=console.log,n=!1)=>{let r=(process.stdout.columns||80)-4,i=e.split(`
15
- `),a=!0;i.forEach(o=>{if(o.length===0){a?(t(""),a=!1):console.log(N.gray("\u2502"));return}for(let p=0;p<o.length;p+=r){let s=o.slice(p,p+r);p+r<o.length&&s.length===r&&(s=s+"-"),a?(t(s),a=!1):console.log(N.gray("\u2502 ")+s)}}),n&&console.log(N.gray("\u2502"))};var E="\x1B[?25h";import{execa as dt}from"execa";var ut=async()=>{process.argv.some(w=>["-h","--help","--version","-V"].includes(w))||K();let e=await ge(),{project:t,appFlags:n}=await H(),[r,i]=z(t.appName),a=k(),o=await X(t,i);Z({projectDir:o,ruleFilesToAdd:t.ruleFiles});let p={template:t.base,aiTool:t.ruleFiles??"none",usedAiPrompt:!!t.prompt},s=await de(n,p);s&&ue(t,o,s.appId,s.adminToken),await q(k(),o);let m=ye.readJSONSync(we.join(o,"package.json"));if(m.name=r,a!=="bun"){let{stdout:w}=await dt(a,["-v"],{cwd:o});m.packageManager=`${a}@${w.trim()}`}ye.writeJSONSync(we.join(o,"package.json"),m,{spaces:2}),t.createRepo&&await oe(o),t.prompt&&(await D(t.prompt,o),process.stdout.write(E)),lt("Done!");let _=t.base==="expo"?"start":"dev";s?(console.log(`
14
+ `,defaultValue:!1,modifyOutput:A.ciaModifier()})))return;try{let i=Ve(),{major:a,minor:r}=Le();a<2||a==2&&r<28?(await P("git",["init"],{cwd:e}),await P("git",["symbolic-ref","HEAD",`refs/heads/${i}`],{cwd:e})):await P("git",["init",`--initial-branch=${i}`],{cwd:e}),await P("git",["add","."],{cwd:e}),await P("git",["commit","-m","Initial commit (create-instant-app)"],{cwd:e}),A.log("Git repository initialized successfully.",A.ciaModifier(null))}catch{}};import He from"env-paths";import*as Je from"@clack/prompts";import{mkdir as Ye,readFile as Ke,writeFile as Xe}from"node:fs/promises";import qe from"open";import{join as Ze}from"node:path";import{randomUUID as ae}from"node:crypto";import{version as ze}from"@instantdb/version";var re=!!process.env.INSTANT_CLI_DEV,ie=re?"http://localhost:3000":"https://instantdb.com",B=process.env.INSTANT_CLI_API_URI||(re?"http://localhost:8888":"https://api.instantdb.com");async function T({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":ze,"X-Instant-Command":"create"};o&&(r.Authorization=`Bearer ${o}`),i&&(r["X-Instant-Metadata"]=JSON.stringify(i));let p=await fetch(`${B}${e}`,{method:n??"GET",headers:r,body:t?JSON.stringify(t):void 0,signal:AbortSignal.timeout(3e5)}),s;try{s=await p.json()}catch{s=null}if(!p.ok){let u=s.message||s.hint?.errors?.[0]?.message||"There was an error";throw new Error(u)}return s}import{renderUnwrap as j,UI as d}from"instant-cli/ui";var Qe=!!process.env.INSTANT_CLI_DEV,et=!!process.env.INSTANT_CLI_FORCE_EPHEMERAL;function pe(){let e=`instantdb-${Qe?"dev":"prod"}`,{config:t}=He(e);return{authConfigFilePath:Ze(t,"a"),appConfigDirPath:t}}var tt=async(e,t,n,o)=>{let i=ae(),a=ae();return await T({method:"POST",authToken:t,path:"/dash/apps",body:{id:i,title:e,admin_token:a,org_id:n},metadata:o}),{appID:i,adminToken:a,source:"created"}},U=(e,t,n)=>{T({method:"POST",path:`/dash/apps/${e}/track-import`,authToken:t,metadata:n}).catch(()=>{})},le=async e=>await T({method:"GET",path:"/dash",authToken:e}),ce=async(e,t)=>await T({method:"GET",path:`/dash/orgs/${t}`,authToken:e});var nt=async(e,t)=>{try{let n=await le(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 ce(e,i.id),r=a.find(p=>p.id===t);if(r)return{appId:r.id,adminToken:r.admin_token}}return null}catch{return null}},ot=async(e,t)=>{try{return await T({method:"GET",path:`/dash/apps/${e}/schema/pull`,authToken:t}),!0}catch{return!1}},rt=async()=>et?null:process.env.INSTANT_CLI_AUTH_TOKEN?process.env.INSTANT_CLI_AUTH_TOKEN:await Ke(pe().authConfigFilePath,"utf-8").catch(()=>null),se=async(e,t)=>{let n=await T({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"]}},de=async(e,t)=>{let n=await rt();if(e?.app){if(e.token){if(!await ot(e.app,e.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: ${e.app}`,d.ciaModifier(null)),U(e.app,e.token,t),{appId:e.app,adminToken:e.token,approach:"import"}}if(n){let r=await nt(n,e.app);if(!r)throw new Error(`You don't have access to app "${e.app}". Please check the app ID or use --token to provide a token.`);return d.log(`Linking to app: ${e.app}`,d.ciaModifier(null)),U(r.appId,n,t),{appId:r.appId,adminToken:r.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 ${e.app} --token <token>`)}if(!n){let r=await j(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(r==="login"){let p=await T({authToken:null,method:"POST",path:"/dash/cli/auth/register"}),{secret:s,ticket:u}=p;qe(`${ie}/dash?ticket=${u}`);let _=at({secret:s}),w=await j(new d.Spinner({promise:_,workingText:"Waiting for login in browser",disappearWhenDone:!0,modifyOutput:d.ciaModifier(null)}));await st(w.token),n=w.token}if(r==="skip")return d.log("Skipping app link step",d.ciaModifier(null)),null;if(r==="ephemeral"){let p=await j(new d.TextInput({defaultValue:"my-cool-app",prompt:"Enter a name for your temporary app:",placeholder:"my-cool-app",modifyOutput:d.ciaModifier()}));return{...await se(p,t),approach:"ephemeral"}}}if(!n)return null;let o=await le(n),i=o.orgs.filter(r=>r.role!=="app-member");o.orgs=i;let a=await j(new d.AppSelector({startingMenuIndex:0,allowCreate:!0,allowEphemeral:!0,api:{getDash(){return o},createEphemeralApp(r){return se(r,t)},getAppsForOrg:async r=>{let{apps:p}=await ce(n,r);return{apps:p}},createApp:async(r,p)=>{let{appID:s,adminToken:u}=await tt(r,n,p,t);return{appId:s,adminToken:u}}},modifyOutput:d.ciaModifier()}));return a?.approach==="import"&&U(a.appId,n,t),a};function it(e){return new Promise(t=>setTimeout(t,e))}async function at({secret:e}){for(let t=1;t<=120;t++){await it(1e3);let n=await fetch(`${B}/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 st(e){let t=pe();return await Ye(t.appConfigDirPath,{recursive:!0}),Xe(t.authConfigFilePath,e,"utf-8")}import pt from"fs-extra";import lt from"path";var ct={"next-js-app-dir":"NEXT_PUBLIC_INSTANT_APP_ID","vite-vanilla":"VITE_INSTANT_APP_ID",expo:"EXPO_PUBLIC_INSTANT_APP_ID"},ue=(e,t,n,o)=>{let i=lt.join(t,".env"),r=`${ct[e.base]}=${n}
15
+ INSTANT_APP_ADMIN_TOKEN=${o}`;pt.writeFileSync(i,r)};import{stdin as I,stdout as me}from"process";import{setRawModeWindowsFriendly as fe}from"instant-cli/ui";async function dt(){return new Promise(e=>{if(!me.isTTY||!I.isTTY){e(null);return}let t=I.isRaw;t||fe(I,!0);let n=setTimeout(()=>{i(),e(null)},100),o="",i=()=>{clearTimeout(n),I.removeListener("data",a),!t&&I.isTTY&&fe(I,!1)},a=r=>{let p=r.toString();o+=p;let s=o.match(/\x1b\]11;rgb:([0-9a-fA-F]+)\/([0-9a-fA-F]+)\/([0-9a-fA-F]+)(?:\x1b\\|\x07)/);if(s){i();let[,u,_,w]=s;e(`rgb:${u}/${_}/${w}`)}};I.on("data",a),me.write("\x1B]11;?\x1B\\")})}function ut(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),p=Math.round(parseInt(i,16)/257);return{r:a,g:r,b:p}}function mt(e){return(.299*e.r+.587*e.g+.114*e.b)/255>.5}async function ge(){try{let e=await dt();if(!e)return"unknown";let t=ut(e);return t?mt(t)?"light":"dark":"unknown"}catch(e){return console.error("Error detecting terminal theme:",e),"unknown"}}import S from"chalk";var v=(e,t)=>e==="light"?S.bgYellowBright(t):S.bgBlackBright(t),he=(e,t=console.log,n=!1)=>{let o=(process.stdout.columns||80)-4,i=e.split(`
16
+ `),a=!0;i.forEach(r=>{if(r.length===0){a?(t(""),a=!1):console.log(S.gray("\u2502"));return}for(let p=0;p<r.length;p+=o){let s=r.slice(p,p+o);p+o<r.length&&s.length===o&&(s=s+"-"),a?(t(s),a=!1):console.log(S.gray("\u2502 ")+s)}}),n&&console.log(S.gray("\u2502"))};var E="\x1B[?25h";import{execa as ht}from"execa";var wt=async()=>{process.argv.some(w=>["-h","--help","--version","-V"].includes(w))||Y();let e=await ge(),{project:t,appFlags:n}=await H(),[o,i]=z(t.appName),a=x(),r=await K(t,i);Z({projectDir:r,ruleFilesToAdd:t.ruleFiles});let p={template:t.base,aiTool:t.ruleFiles??"none",usedAiPrompt:!!t.prompt},s=await de(n,p);s&&ue(t,r,s.appId,s.adminToken);let u=ye.readJSONSync(we.join(r,"package.json"));if(u.name=o,u.packageManager&&delete u.packageManager,a!=="bun"){let{stdout:w}=await ht(a,["-v"],{cwd:r});u.packageManager=`${a}@${w.trim()}`}ye.writeJSONSync(we.join(r,"package.json"),u,{spaces:2}),await X(x(),r),t.createRepo&&await oe(r),t.prompt&&(await W(t.prompt,r),process.stdout.write(E)),ft("Done!");let _=t.base==="expo"?"start":"dev";s?(console.log(`
16
17
  \u{1F389} Success! Your project is ready to go!
17
18
 
18
19
  To get started:
19
20
  1. ${v(e,"cd "+i)}
20
- 2. ${v(e,k()+" run "+_)}
21
+ 2. ${v(e,x()+" run "+_)}
21
22
  `),s.approach==="ephemeral"&&console.log(`
22
23
  An ephemeral app has been created and added to your .env file.
23
24
  It will expire in two weeks. For a permanent app, sign in and use ${v(e,"npx instant-cli claim")}
@@ -26,7 +27,7 @@ INSTANT_APP_ADMIN_TOKEN=${r}`;ot.writeFileSync(i,o)};import{stdin as T,stdout as
26
27
 
27
28
  To get started:
28
29
  1. ${v(e,"cd "+i)}
29
- 2. Create a new app on ${ct.underline("www.instantdb.com")}
30
+ 2. Create a new app on ${gt.underline("www.instantdb.com")}
30
31
  3. Add your APP_ID to the .env file
31
- 4. ${v(e,k()+" run "+_)}
32
- `)};ut().catch(e=>{xe.error("Aborting installation..."),he(e.message,xe.error),process.stdout.write(E),process.exit(1)});process.on("SIGINT",()=>{process.stdout.write(E),process.exit(0)});
32
+ 4. ${v(e,x()+" run "+_)}
33
+ `)};wt().catch(e=>{Te.error("Aborting installation..."),he(e.message,Te.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": "0.22.107",
3
+ "version": "0.22.108-experimental.drewh-use-clone.21267978145.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": {
@@ -25,19 +25,22 @@
25
25
  "@ianvs/prettier-plugin-sort-imports": "^4.2.1",
26
26
  "chalk": "5.2.0",
27
27
  "commander": "^10.0.1",
28
+ "degit": "^2.8.4",
28
29
  "env-paths": "^3.0.0",
29
30
  "execa": "^7.2.0",
30
31
  "fs-extra": "^11.3.1",
31
32
  "gradient-string": "^2.0.2",
33
+ "ignore": "^7.0.5",
32
34
  "open": "^10.1.0",
33
35
  "ora": "6.3.1",
34
36
  "slugify": "^1.6.6",
35
37
  "sort-package-json": "^2.10.0",
36
- "@instantdb/version": "0.22.107",
37
- "instant-cli": "0.22.107"
38
+ "@instantdb/version": "0.22.108-experimental.drewh-use-clone.21267978145.1",
39
+ "instant-cli": "0.22.108-experimental.drewh-use-clone.21267978145.1"
38
40
  },
39
41
  "devDependencies": {
40
42
  "@anthropic-ai/sdk": "^0.60.0",
43
+ "@types/degit": "^2.8.6",
41
44
  "@types/fs-extra": "^11.0.4",
42
45
  "@types/node": "^18.11.18",
43
46
  "tsup": "^6.7.0",
@@ -1,15 +0,0 @@
1
- # Welcome to your InstantDB Expo app 👋
2
-
3
- This is an Expo project scaffolded with create-instant-app.
4
-
5
- To run the development server:
6
- `npm run start`
7
-
8
- To push schema changes:
9
- `npx instant-cli push`
10
-
11
- To pull schema changes:
12
- `npx instant-cli pull`
13
-
14
-
15
- Got any feedback or questions? Join our [Discord](https://discord.gg/hgVf9R6SBm)
@@ -1,2 +0,0 @@
1
- EXPO_PUBLIC_INSTANT_APP_ID=
2
- INSTANT_APP_ADMIN_TOKEN=
@@ -1,41 +0,0 @@
1
- # Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
2
-
3
- # dependencies
4
- node_modules/
5
-
6
- # Expo
7
- .expo/
8
- dist/
9
- web-build/
10
- expo-env.d.ts
11
-
12
- # Native
13
- .kotlin/
14
- *.orig.*
15
- *.jks
16
- *.p8
17
- *.p12
18
- *.key
19
- *.mobileprovision
20
-
21
- # Metro
22
- .metro-health-check*
23
-
24
- # debug
25
- npm-debug.*
26
- yarn-debug.*
27
- yarn-error.*
28
-
29
- # macOS
30
- .DS_Store
31
- *.pem
32
-
33
- # local env files
34
- .env*.local
35
-
36
- # typescript
37
- *.tsbuildinfo
38
-
39
- app-example
40
-
41
- .env
@@ -1,16 +0,0 @@
1
- import { Link, Stack } from "expo-router";
2
- import { View, Text } from "react-native";
3
-
4
- export default function NotFoundScreen() {
5
- return (
6
- <>
7
- <Stack.Screen options={{ title: "Oops!" }} />
8
- <View className="flex flex-1 items-center justify-center p-5">
9
- <Text>This screen does not exist.</Text>
10
- <Link href="/" className="mt-[15px] py-[15px]">
11
- <Text>Go to home screen!</Text>
12
- </Link>
13
- </View>
14
- </>
15
- );
16
- }
@@ -1,37 +0,0 @@
1
- import {
2
- DarkTheme,
3
- DefaultTheme,
4
- ThemeProvider,
5
- } from "@react-navigation/native";
6
- import "../global.css";
7
- import { useFonts } from "expo-font";
8
- import { Stack } from "expo-router";
9
- import { StatusBar } from "expo-status-bar";
10
- import "react-native-reanimated";
11
-
12
- import { useColorScheme } from "@/hooks/useColorScheme";
13
-
14
- export default function RootLayout() {
15
- const colorScheme = useColorScheme();
16
- const [loaded] = useFonts({
17
- SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"),
18
- });
19
-
20
- if (!loaded) {
21
- // Async font loading only occurs in development.
22
- return null;
23
- }
24
-
25
- return (
26
- <ThemeProvider value={colorScheme === "dark" ? DarkTheme : DefaultTheme}>
27
- <Stack>
28
- <Stack.Screen
29
- name="index"
30
- options={{ headerShown: true, headerTitle: "My Instant App" }}
31
- />
32
- <Stack.Screen name="+not-found" />
33
- </Stack>
34
- <StatusBar style="auto" />
35
- </ThemeProvider>
36
- );
37
- }
@@ -1,64 +0,0 @@
1
- import { db } from "@/lib/db";
2
- import { AppSchema } from "@/instant.schema";
3
- import { InstaQLEntity } from "@instantdb/react-native";
4
- import { View, Text, Button } from "react-native";
5
-
6
- type Color = InstaQLEntity<AppSchema, "colors">;
7
-
8
- const selectId = "4d39508b-9ee2-48a3-b70d-8192d9c5a059";
9
-
10
- function App() {
11
- const { isLoading, error, data } = db.useQuery({
12
- colors: {
13
- $: { where: { id: selectId } },
14
- },
15
- });
16
- if (isLoading) {
17
- return (
18
- <View>
19
- <Text>Loading...</Text>
20
- </View>
21
- );
22
- }
23
- if (error) {
24
- return (
25
- <View>
26
- <Text>Error: {error.message}</Text>
27
- </View>
28
- );
29
- }
30
-
31
- return <Main color={data.colors[0]} />;
32
- }
33
-
34
- function Main(props: { color?: Color }) {
35
- const { value } = props.color || { value: "lightgray" };
36
-
37
- return (
38
- <View
39
- className="flex flex-1 items-center justify-center"
40
- style={[{ backgroundColor: value }]}
41
- >
42
- <View className="bg-white opacity-80 p-3 rounded-lg">
43
- <Text className="text-[24px] font-bold mb-4">
44
- Hi! pick your favorite color
45
- </Text>
46
- <View className="my-4">
47
- {["green", "blue", "purple"].map((c) => {
48
- return (
49
- <Button
50
- title={c}
51
- onPress={() => {
52
- db.transact(db.tx.colors[selectId].update({ value: c }));
53
- }}
54
- key={c}
55
- />
56
- );
57
- })}
58
- </View>
59
- </View>
60
- </View>
61
- );
62
- }
63
-
64
- export default App;
@@ -1,42 +0,0 @@
1
- {
2
- "expo": {
3
- "name": "expo-template",
4
- "slug": "expo-template",
5
- "version": "1.0.0",
6
- "orientation": "portrait",
7
- "icon": "./assets/images/icon.png",
8
- "scheme": "expotemplate",
9
- "userInterfaceStyle": "automatic",
10
- "newArchEnabled": true,
11
- "ios": {
12
- "supportsTablet": true
13
- },
14
- "android": {
15
- "adaptiveIcon": {
16
- "foregroundImage": "./assets/images/adaptive-icon.png",
17
- "backgroundColor": "#ffffff"
18
- },
19
- "edgeToEdgeEnabled": true
20
- },
21
- "web": {
22
- "bundler": "metro",
23
- "output": "static",
24
- "favicon": "./assets/images/favicon.png"
25
- },
26
- "plugins": [
27
- "expo-router",
28
- [
29
- "expo-splash-screen",
30
- {
31
- "image": "./assets/images/splash-icon.png",
32
- "imageWidth": 200,
33
- "resizeMode": "contain",
34
- "backgroundColor": "#ffffff"
35
- }
36
- ]
37
- ],
38
- "experiments": {
39
- "typedRoutes": true
40
- }
41
- }
42
- }
@@ -1,12 +0,0 @@
1
- module.exports = function (api) {
2
- api.cache(true);
3
- return {
4
- plugins: [
5
- "react-native-reanimated/plugin",
6
- ],
7
- presets: [
8
- ["babel-preset-expo", { jsxImportSource: "nativewind" }],
9
- "nativewind/babel",
10
- ],
11
- };
12
- };
@@ -1,26 +0,0 @@
1
- /**
2
- * Below are the colors that are used in the app. The colors are defined in the light and dark mode.
3
- * There are many other ways to style your app. For example, [Nativewind](https://www.nativewind.dev/), [Tamagui](https://tamagui.dev/), [unistyles](https://reactnativeunistyles.vercel.app), etc.
4
- */
5
-
6
- const tintColorLight = '#0a7ea4';
7
- const tintColorDark = '#fff';
8
-
9
- export const Colors = {
10
- light: {
11
- text: '#11181C',
12
- background: '#fff',
13
- tint: tintColorLight,
14
- icon: '#687076',
15
- tabIconDefault: '#687076',
16
- tabIconSelected: tintColorLight,
17
- },
18
- dark: {
19
- text: '#ECEDEE',
20
- background: '#151718',
21
- tint: tintColorDark,
22
- icon: '#9BA1A6',
23
- tabIconDefault: '#9BA1A6',
24
- tabIconSelected: tintColorDark,
25
- },
26
- };
@@ -1,10 +0,0 @@
1
- // https://docs.expo.dev/guides/using-eslint/
2
- const { defineConfig } = require('eslint/config');
3
- const expoConfig = require('eslint-config-expo/flat');
4
-
5
- module.exports = defineConfig([
6
- expoConfig,
7
- {
8
- ignores: ['dist/*'],
9
- },
10
- ]);
@@ -1,3 +0,0 @@
1
- /// <reference types="expo/types" />
2
-
3
- // NOTE: This file should not be edited and should be in your git ignore
@@ -1,3 +0,0 @@
1
- @tailwind base;
2
- @tailwind components;
3
- @tailwind utilities;
@@ -1 +0,0 @@
1
- export { useColorScheme } from 'react-native';
@@ -1,21 +0,0 @@
1
- import { useEffect, useState } from 'react';
2
- import { useColorScheme as useRNColorScheme } from 'react-native';
3
-
4
- /**
5
- * To support static rendering, this value needs to be re-calculated on the client side for web
6
- */
7
- export function useColorScheme() {
8
- const [hasHydrated, setHasHydrated] = useState(false);
9
-
10
- useEffect(() => {
11
- setHasHydrated(true);
12
- }, []);
13
-
14
- const colorScheme = useRNColorScheme();
15
-
16
- if (hasHydrated) {
17
- return colorScheme;
18
- }
19
-
20
- return 'light';
21
- }
@@ -1,21 +0,0 @@
1
- /**
2
- * Learn more about light and dark modes:
3
- * https://docs.expo.dev/guides/color-schemes/
4
- */
5
-
6
- import { Colors } from '@/constants/Colors';
7
- import { useColorScheme } from '@/hooks/useColorScheme';
8
-
9
- export function useThemeColor(
10
- props: { light?: string; dark?: string },
11
- colorName: keyof typeof Colors.light & keyof typeof Colors.dark
12
- ) {
13
- const theme = useColorScheme() ?? 'light';
14
- const colorFromProps = props[theme];
15
-
16
- if (colorFromProps) {
17
- return colorFromProps;
18
- } else {
19
- return Colors[theme][colorName];
20
- }
21
- }
@@ -1,24 +0,0 @@
1
- // Docs: https://www.instantdb.com/docs/permissions
2
-
3
- import type { InstantRules } from "@instantdb/react-native";
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
- * Here's an example to give you a feel:
12
- * posts: {
13
- * allow: {
14
- * view: "true",
15
- * create: "isOwner",
16
- * update: "isOwner",
17
- * delete: "isOwner",
18
- * },
19
- * bind: ["isOwner", "auth.id != null && auth.id == data.ownerId"],
20
- * },
21
- */
22
- } satisfies InstantRules;
23
-
24
- export default rules;
@@ -1,44 +0,0 @@
1
- // Docs: https://www.instantdb.com/docs/modeling-data
2
-
3
- import { i } from "@instantdb/react-native";
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
- imageURL: i.string().optional(),
14
- type: i.string().optional(),
15
- }),
16
- colors: i.entity({
17
- value: i.string(),
18
- }),
19
- },
20
- rooms: {},
21
- links: {
22
- $usersLinkedPrimaryUser: {
23
- forward: {
24
- on: "$users",
25
- has: "one",
26
- label: "linkedPrimaryUser",
27
- onDelete: "cascade",
28
- },
29
- reverse: {
30
- on: "$users",
31
- has: "many",
32
- label: "linkedGuestUsers",
33
- },
34
- },
35
- },
36
- });
37
-
38
- // This helps TypeScript display nicer intellisense
39
- type _AppSchema = typeof _schema;
40
- interface AppSchema extends _AppSchema {}
41
- const schema: AppSchema = _schema;
42
-
43
- export type { AppSchema };
44
- export default schema;
@@ -1,7 +0,0 @@
1
- import { init } from "@instantdb/react-native";
2
- import schema from "../instant.schema";
3
-
4
- export const db = init({
5
- appId: process.env.EXPO_PUBLIC_INSTANT_APP_ID!,
6
- schema,
7
- });
@@ -1,6 +0,0 @@
1
- const { getDefaultConfig } = require("expo/metro-config");
2
- const { withNativeWind } = require("nativewind/metro");
3
-
4
- const config = getDefaultConfig(__dirname);
5
-
6
- module.exports = withNativeWind(config, { input: "./global.css" });
@@ -1 +0,0 @@
1
- /// <reference types="nativewind/types" />