create-openfort 0.1.7 → 0.1.8

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 (24) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/index.js +7 -7
  3. package/package.json +2 -2
  4. package/template/openfort-templates/firebase/src/components/cards/head.tsx +0 -1
  5. package/template/openfort-templates/headless/src/App.tsx +1 -3
  6. package/template/openfort-templates/headless/src/components/cards/actions.tsx +51 -25
  7. package/template/openfort-templates/headless/src/components/cards/auth.tsx +48 -39
  8. package/template/openfort-templates/headless/src/components/cards/head.tsx +161 -150
  9. package/template/openfort-templates/headless/src/components/cards/main.tsx +58 -52
  10. package/template/openfort-templates/headless/src/components/cards/profile.tsx +28 -34
  11. package/template/openfort-templates/headless/src/components/cards/sign.tsx +35 -49
  12. package/template/openfort-templates/headless/src/components/cards/wallets.tsx +54 -40
  13. package/template/openfort-templates/headless/src/components/createWallet.tsx +63 -30
  14. package/template/openfort-templates/headless/src/components/passwordRecovery.tsx +61 -56
  15. package/template/openfort-templates/headless/src/components/providers.tsx +12 -16
  16. package/template/openfort-templates/headless/src/components/ui/Sheet.tsx +14 -16
  17. package/template/openfort-templates/headless/src/components/ui/Tabs.tsx +46 -36
  18. package/template/openfort-templates/headless/src/components/ui/TruncateData.tsx +14 -8
  19. package/template/openfort-templates/headless/src/index.css +1 -2
  20. package/template/openfort-templates/headless/tsconfig.app.json +3 -9
  21. package/template/openfort-templates/headless/tsconfig.node.json +3 -7
  22. package/template/openfort-templates/headless/vite.config.ts +2 -2
  23. package/template/openfort-templates/openfort-ui/src/components/cards/actions.tsx +52 -23
  24. package/template/openfort-templates/openfort-ui/src/components/cards/head.tsx +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.8
4
+
5
+ ### Patch Changes
6
+
7
+ - [#145](https://github.com/openfort-xyz/openfort-react/pull/145) [`fe5844b`](https://github.com/openfort-xyz/openfort-react/commit/fe5844b7fd877274d7e59634941c983679ff73ab) Thanks [@martimayoral](https://github.com/martimayoral)! - improve samples when no policy
8
+
9
+ - [#145](https://github.com/openfort-xyz/openfort-react/pull/145) [`fe5844b`](https://github.com/openfort-xyz/openfort-react/commit/fe5844b7fd877274d7e59634941c983679ff73ab) Thanks [@martimayoral](https://github.com/martimayoral)! - improve wording and promps order
10
+
3
11
  ## 0.1.7
4
12
 
5
13
  ### Patch Changes
package/dist/index.js CHANGED
@@ -3,14 +3,14 @@ import Oe from"node:path";import G from"fs-extra";import*as p from"@clack/prompt
3
3
  / _ \\| _ \\| __| \\| | __/ _ \\| _ \\_ _|
4
4
  | (_) | _/| _|| | _| (_) | / | |
5
5
  \\___/|_| |___|_|\\_|_| \\___/|_|_\\ |_|
6
- `,b="openfort-project",L="create-openfort";var W=["openfort-ui","headless","firebase"],J=["auto","midnight","minimal","soft","web95","rounded","retro","nouns"];import Ne from"node:path";import ke from"fs-extra";var y=()=>{let e=Ne.join(_,"package.json");return ke.readJSONSync(e).version??"unknown"};var T=class extends Error{};var r={error:(...e)=>console.error(...e),warn:(...e)=>console.warn(...e),info:(...e)=>console.log(...e),success:(...e)=>console.log(...e),debug:(...e)=>console.log(...e)};import $e,{createHash as Z}from"node:crypto";import Ce from"node:https";import{hostname as Re,userInfo as Ae}from"node:os";var X="https://analytics.openfort.io",q="phc_HosujvcO5QzmU2MVvZo8AxWV0pplTZJLr3jEd8dRVPE",Le=()=>{let e=`${Re()}-${Ae().username}`;return Z("sha256").update(e).digest("hex").slice(0,16)},B=class{constructor(){this.enabled=!0;this.send=async({properties:o={},status:i})=>{if(r.debug("Sending telemetry...",{status:i,properties:o}),!this.enabled)return;if(!q||!X){r.warn("Telemetry is not configured properly. Please contact openfort developers at support@openfort.xyz.");return}let t={session_id:this.sessionId,cli_version:y(),node_version:process.version,platform:process.platform,cli_status:i,projectId:this.projectId,projectName:this.projectName,template:this.template,...o},n=JSON.stringify({api_key:q,event:"cli_tool_used",distinct_id:this.anonymousId,properties:t}),a=new URL(`${X}/capture/`),s={hostname:a.hostname,port:a.port||443,path:a.pathname,method:"POST",headers:{"Content-Type":"application/json","Content-Length":n.length}};return new Promise(c=>{let l=Ce.request(s,d=>{d.on("data",()=>{r.debug("Telemetry request response received",d.statusMessage)}),d.on("end",()=>{c()})});l.on("error",d=>{r.debug("Telemetry request error",d),c()}),l.write(n),l.end()})};this.anonymousId=Le(),this.sessionId=Z("sha256").update($e.randomBytes(16)).digest("hex").slice(0,15)}},g=new B;var x=e=>(e.length>1&&e.endsWith("/")&&(e=e.slice(0,-1)),e);var Be=/^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/,Q=e=>{let o=x(e),i=o.split("/"),t=i.findIndex(a=>a.startsWith("@")),n=i[i.length-1];if(i.findIndex(a=>a.startsWith("@"))!==-1&&(n=i.slice(t).join("/")),!(o==="."||Be.test(n??"")))return"App name must consist of only lowercase alphanumeric characters, '-', and '_'"};var ee="[\\da-f]{8}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{12}",te=`(test|live)_${ee}`,Ke=new RegExp(`^sk_${te}$`),Ve=new RegExp(`^pk_${te}$`),He=new RegExp(`^${ee}$`),je=/^.{44}$/,S=({label:e,required:o=!0,regex:i,formatHint:t,customCheck:n})=>a=>{if(a!=="-"){if(o&&!a)return`${e} is required`;if(i&&a&&!i.test(a))return`${e} is invalid${t?` (${t})`:""}`;if(n)return n(a)}},ne=S({label:"Openfort Publishable Key",regex:Ve,formatHint:"expected format: pk_test_... or pk_live_..."}),oe=S({label:"Openfort Secret Key",regex:Ke,formatHint:"expected format: sk_test_... or sk_live_..."}),ie=S({label:"Shield Publishable Key",regex:He,formatHint:"expected UUID format"}),re=S({label:"Shield Secret",required:!0}),ae=S({label:"Shield Encryption Share",regex:je,formatHint:"expected 44 characters"}),se=S({label:"API endpoint",customCheck:e=>{try{new URL(e);return}catch{return"API endpoint must be a valid URL"}}}),le=async e=>{try{return!!(await(await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"}})).json()).session}catch{return!1}};var Ge={appName:b,template:"openfort-ui",createBackend:!0},pe=async()=>{let e=new Fe().name(L).description("A CLI for creating Openfort applications with embedded wallets").argument("[dir]","The name of the application, as well as the name of the directory to create").option("--noGit","Explicitly tell the CLI to not initialize a new git repo in the project",!1).option("--noInstall","Explicitly tell the CLI to not run the package manager's install command",!1).option("-y, --default","Bypass the CLI and use all default options to bootstrap a new Openfort app",!1).option("--CI","Boolean value if we're running in CI",!1).option("--template [string]","Specify the template to use").option("--theme [string]","Specify the theme to use (for openfort-ui template)").option("--noTelemetry","Disable sending anonymous usage data",!1).addOption(new Ue("--debug").hideHelp(!0)).version(y(),"-v, --version","Display the version number").addHelpText("afterAll",`
6
+ `,b="openfort-project",L="create-openfort";var W=["openfort-ui","headless","firebase"],J=["auto","midnight","minimal","soft","web95","rounded","retro","nouns"];import Ne from"node:path";import ke from"fs-extra";var y=()=>{let e=Ne.join(_,"package.json");return ke.readJSONSync(e).version??"unknown"};var T=class extends Error{};var r={error:(...e)=>console.error(...e),warn:(...e)=>console.warn(...e),info:(...e)=>console.log(...e),success:(...e)=>console.log(...e),debug:(...e)=>console.log(...e)};import $e,{createHash as Z}from"node:crypto";import Ce from"node:https";import{hostname as Re,userInfo as Ae}from"node:os";var X="https://analytics.openfort.io",q="phc_HosujvcO5QzmU2MVvZo8AxWV0pplTZJLr3jEd8dRVPE",Le=()=>{let e=`${Re()}-${Ae().username}`;return Z("sha256").update(e).digest("hex").slice(0,16)},B=class{constructor(){this.enabled=!0;this.send=async({properties:o={},status:i})=>{if(r.debug("Sending telemetry...",{status:i,properties:o}),!this.enabled)return;if(!q||!X){r.warn("Telemetry is not configured properly. Please contact openfort developers at support@openfort.xyz.");return}let t={session_id:this.sessionId,cli_version:y(),node_version:process.version,platform:process.platform,cli_status:i,projectId:this.projectId,projectName:this.projectName,template:this.template,...o},n=JSON.stringify({api_key:q,event:"cli_tool_used",distinct_id:this.anonymousId,properties:t}),a=new URL(`${X}/capture/`),s={hostname:a.hostname,port:a.port||443,path:a.pathname,method:"POST",headers:{"Content-Type":"application/json","Content-Length":n.length}};return new Promise(c=>{let l=Ce.request(s,d=>{d.on("data",()=>{r.debug("Telemetry request response received",d.statusMessage)}),d.on("end",()=>{c()})});l.on("error",d=>{r.debug("Telemetry request error",d),c()}),l.write(n),l.end()})};this.anonymousId=Le(),this.sessionId=Z("sha256").update($e.randomBytes(16)).digest("hex").slice(0,15)}},g=new B;var x=e=>(e.length>1&&e.endsWith("/")&&(e=e.slice(0,-1)),e);var Be=/^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/,Q=e=>{let o=x(e),i=o.split("/"),t=i.findIndex(a=>a.startsWith("@")),n=i[i.length-1];if(i.findIndex(a=>a.startsWith("@"))!==-1&&(n=i.slice(t).join("/")),!(o==="."||Be.test(n??"")))return"App name must consist of only lowercase alphanumeric characters, '-', and '_'"};var ee="[\\da-f]{8}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{12}",te=`(test|live)_${ee}`,Ke=new RegExp(`^sk_${te}$`),Ve=new RegExp(`^pk_${te}$`),He=new RegExp(`^${ee}$`),je=/^.{44}$/,P=({label:e,required:o=!0,regex:i,formatHint:t,customCheck:n})=>a=>{if(a!=="-"){if(o&&!a)return`${e} is required`;if(i&&a&&!i.test(a))return`${e} is invalid${t?` (${t})`:""}`;if(n)return n(a)}},ne=P({label:"Openfort Publishable Key",regex:Ve,formatHint:"expected format: pk_test_... or pk_live_..."}),oe=P({label:"Openfort Secret Key",regex:Ke,formatHint:"expected format: sk_test_... or sk_live_..."}),ie=P({label:"Shield Publishable Key",regex:He,formatHint:"expected UUID format"}),re=P({label:"Shield Secret",required:!0}),ae=P({label:"Shield Encryption Share",regex:je,formatHint:"expected 44 characters"}),se=P({label:"API endpoint",customCheck:e=>{try{new URL(e);return}catch{return"API endpoint must be a valid URL"}}}),le=async e=>{try{return!!(await(await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"}})).json()).session}catch{return!1}};var Ge={appName:b,template:"openfort-ui",createBackend:!0},pe=async()=>{let e=new Fe().name(L).description("A CLI for creating Openfort applications with embedded wallets").argument("[dir]","The name of the application, as well as the name of the directory to create").option("--noGit","Explicitly tell the CLI to not initialize a new git repo in the project",!1).option("--noInstall","Explicitly tell the CLI to not run the package manager's install command",!1).option("-y, --default","Bypass the CLI and use all default options to bootstrap a new Openfort app",!1).option("--CI","Boolean value if we're running in CI",!1).option("--template [string]","Specify the template to use").option("--theme [string]","Specify the theme to use (for openfort-ui template)").option("--noTelemetry","Disable sending anonymous usage data",!1).addOption(new Ue("--debug").hideHelp(!0)).version(y(),"-v, --version","Display the version number").addHelpText("afterAll",`
7
7
  Learn more about Openfort at ${De.hex("#5B87F5").bold("https://www.openfort.xyz")}
8
8
  `).parse(process.argv),o=e.args[0],i=e.opts();i.debug||(r.debug=()=>{}),g.enabled=!i.noTelemetry,r.debug("Telemetry enabled:",g.enabled),g.send({status:"started"});let t={...Ge,appName:o||b,flags:{noGit:i.noGit||!1,noInstall:i.noInstall||!1,default:i.default||!1,CI:i.CI||!1,template:i.template,theme:i.theme}};if(t.flags.CI)return t.template=i.template||"openfort-ui",t.theme=i.theme,t.createBackend=!1,t.openfortPublishableKey="pk_test_00000000-0000-0000-0000-000000000000",t.shieldPublishableKey="00000000-0000-0000-0000-000000000000",t;if(t.flags.default)return t.template="openfort-ui",t.createBackend=!1,t.openfortPublishableKey="",t.shieldPublishableKey="",t;try{if(process.env.TERM_PROGRAM?.toLowerCase().includes("mintty"))throw r.warn(` WARNING: It looks like you are using MinTTY, which is non-interactive. This is most likely because you are
9
- using Git Bash. If that's that case, please use Git Bash from another terminal, such as Windows Terminal.`),new T("Non-interactive environment");let n=await p.group({...!o&&{name:()=>p.text({message:"What will your project be called?",defaultValue:b,validate:Q})},template:()=>p.select({message:"Select an Openfort template:",options:W.map(a=>({value:a,label:a==="openfort-ui"?"Openfort UI (default)":a,hint:Ye(a)})),initialValue:"openfort-ui"}),createBackend:()=>p.confirm({message:"Do you want to create a backend for automatic account recovery?",initialValue:!0}),apiEndpoint:async({results:a})=>{if(!a.createBackend){let s=await p.confirm({message:"Do you have an existing API endpoint for account recovery?",initialValue:!1});if(p.isCancel(s)&&process.exit(1),s){let c=!1,l="";for(;!c;){let d=await p.text({message:"Enter your API endpoint for creating encryption sessions:",placeholder:"http://localhost:3110/api/protected-create-encryption-session",validate:se});p.isCancel(d)&&process.exit(1),l=d;let u=p.spinner();if(u.start("Testing API endpoint..."),await le(l))u.stop("API endpoint validated!"),c=!0;else{u.stop("API endpoint validation failed"),r.error("The endpoint did not return a valid session response");let h=await p.confirm({message:"Would you like to try another endpoint?",initialValue:!0});(p.isCancel(h)||!h)&&process.exit(1)}}return l}}},theme:({results:a})=>{if(a.template==="openfort-ui")return p.select({message:"Select a theme:",options:J.map(s=>({value:s,label:s==="auto"?"Auto (default)":s})),initialValue:"auto"})},openfortPublishableKey:()=>p.text({message:"Enter your Openfort Publishable Key:",placeholder:"pk_test_...",validate:ne}),openfortSecretKey:({results:a})=>{if(a.createBackend)return p.text({message:"Enter your Openfort Secret Key:",placeholder:"sk_test_...",validate:oe})},shieldPublishableKey:()=>p.text({message:"Enter your Shield Publishable Key:",placeholder:"00000000-0000-0000-0000-000000000000",validate:ie}),shieldEncryptionShare:({results:a})=>{if(a.createBackend)return p.text({message:"Enter your Shield Encryption Share:",placeholder:"Your 44-character encryption share",validate:ae})},shieldSecretKey:({results:a})=>{if(a.createBackend)return p.text({message:"Enter your Shield Secret Key:",placeholder:"Your Shield Secret",validate:re})},...!t.flags.noGit&&{git:()=>p.confirm({message:"Should we initialize a Git repository and stage the changes?",initialValue:!0})}},{onCancel(){process.exit(1)}});return g.template=n.template,g.projectId=n.openfortPublishableKey,{appName:n.name||t.appName,template:n.template,theme:n.theme,createBackend:n.createBackend,apiEndpoint:n.apiEndpoint,openfortPublishableKey:n.openfortPublishableKey,openfortSecretKey:n.openfortSecretKey,shieldPublishableKey:n.shieldPublishableKey,shieldSecretKey:n.shieldSecretKey,shieldEncryptionShare:n.shieldEncryptionShare,flags:{...t.flags,noGit:!n.git||t.flags.noGit}}}catch(n){if(n instanceof T)return r.warn(`
10
- ${L} needs an interactive terminal to provide options`),await p.confirm({message:"Continue scaffolding a default Openfort app?",initialValue:!0})||(r.info("Exiting..."),process.exit(0)),r.info(`Bootstrapping a default Openfort app in ./${t.appName}`),{...t,template:"openfort-ui",createBackend:!1,openfortPublishableKey:"",shieldPublishableKey:""};throw n}};function Ye(e){switch(e){case"openfort-ui":return"Pre-built UI components";case"headless":return"Custom, unstyled components";case"firebase":return"With Firebase authentication";default:return""}}import ge from"node:path";import N from"node:path";import k from"fs-extra";import Me from"ora";var ce=async({projectDir:e,openfortSecretKey:o,shieldSecretKey:i,shieldApiKey:t,shieldEncryptionShare:n,port:a=3110})=>{let s=Me("Creating backend...").start();try{let c=N.join(_,"template/backend"),l=N.join(e,"backend");k.copySync(c,l);let d=N.join(l,".env.example"),u=N.join(l,".env");if(k.existsSync(d)){let h=k.readFileSync(d,"utf-8").replace(/OPENFORT_SECRET_KEY=.*/g,`OPENFORT_SECRET_KEY=${o}`).replace(/SHIELD_SECRET_KEY=.*/g,`SHIELD_SECRET_KEY=${i}`).replace(/SHIELD_API_KEY=.*/g,`SHIELD_API_KEY=${t}`).replace(/SHIELD_ENCRYPTION_SHARE=.*/g,`SHIELD_ENCRYPTION_SHARE=${n}`).replace(/PORT=.*/g,`PORT=${a}`);k.writeFileSync(u,h)}await new Promise(m=>setTimeout(m,250)),s.succeed("Backend created successfully!")}catch(c){throw s.fail("Failed to create backend"),r.error(c instanceof Error?c.message:String(c)),c}};import de from"node:path";import*as E from"@clack/prompts";import P from"chalk";import w from"fs-extra";import ze from"ora";var fe=async({projectName:e,projectDir:o,template:i,createBackend:t})=>{r.info("");let n=ze(`Scaffolding in: ${o}...
11
- `).start();if(w.existsSync(o))if(w.readdirSync(o).length===0)e!=="."&&n.info(`${P.cyan.bold(e)} exists but is empty, continuing...
12
- `);else{n.stopAndPersist();let l=await E.select({message:`${P.redBright.bold("Warning:")} ${P.cyan.bold(e)} already exists and isn't empty. How would you like to proceed?`,options:[{label:"Abort installation (recommended)",value:"abort"},{label:"Clear the directory and continue installation",value:"clear"},{label:"Continue installation and overwrite conflicting files",value:"overwrite"}],initialValue:"abort"});(E.isCancel(l)||l==="abort")&&(n.fail("Aborting installation..."),process.exit(1));let d=await E.confirm({message:`Are you sure you want to ${l==="clear"?"clear the directory":"overwrite conflicting files"}?`,initialValue:!1});(E.isCancel(d)||!d)&&(n.fail("Aborting installation..."),process.exit(1)),l==="clear"&&(n.info(`Emptying ${P.cyan.bold(e)} and creating Openfort app..
13
- `),w.emptyDirSync(o))}n.start(),w.mkdirSync(o,{recursive:!0});let a=de.join(_,"template/openfort-templates",i),s=t?de.join(o,"frontend"):o;w.copySync(a,s);let c=e==="."?"App":P.cyan.bold(e);await new Promise(l=>setTimeout(l,250)),n.succeed(`${c} ${P.green("scaffolded successfully!")}
9
+ using Git Bash. If that's that case, please use Git Bash from another terminal, such as Windows Terminal.`),new T("Non-interactive environment");let n=await p.group({...!o&&{name:()=>p.text({message:"What will your project be called?",defaultValue:b,validate:Q})},template:()=>p.select({message:"Select an Openfort template:",options:W.map(a=>({value:a,label:a==="openfort-ui"?"Openfort UI (default)":a,hint:Ye(a)})),initialValue:"openfort-ui"}),createBackend:()=>p.confirm({message:"Do you want to create a backend for automatic account recovery?",initialValue:!0}),apiEndpoint:async({results:a})=>{if(!a.createBackend){let s=await p.confirm({message:"Do you have an existing API endpoint for account recovery?",initialValue:!1});if(p.isCancel(s)&&process.exit(1),s){let c=!1,l="";for(;!c;){let d=await p.text({message:"Enter your API endpoint for creating encryption sessions:",placeholder:"http://localhost:3110/api/protected-create-encryption-session",validate:se});p.isCancel(d)&&process.exit(1),l=d;let u=p.spinner();if(u.start("Testing API endpoint..."),await le(l))u.stop("API endpoint validated!"),c=!0;else{u.stop("API endpoint validation failed"),r.error("The endpoint did not return a valid session response");let h=await p.confirm({message:"Would you like to try another endpoint?",initialValue:!0});(p.isCancel(h)||!h)&&process.exit(1)}}return l}}},theme:({results:a})=>{if(a.template==="openfort-ui")return p.select({message:"Select a theme:",options:J.map(s=>({value:s,label:s==="auto"?"Auto (default)":s})),initialValue:"auto"})},openfortPublishableKey:()=>p.text({message:"Enter your Project Publishable Key:",placeholder:"pk_test_...",validate:ne}),openfortSecretKey:({results:a})=>{if(a.createBackend)return p.text({message:"Enter your Project Secret Key:",placeholder:"sk_test_...",validate:oe})},shieldEncryptionShare:({results:a})=>{if(a.createBackend)return p.text({message:"Enter your Shield Encryption Share:",placeholder:"Your 44-character encryption share",validate:ae})},shieldPublishableKey:()=>p.text({message:"Enter your Shield Publishable Key:",placeholder:"00000000-0000-0000-0000-000000000000",validate:ie}),shieldSecretKey:({results:a})=>{if(a.createBackend)return p.text({message:"Enter your Shield Secret Key:",placeholder:"Your Shield Secret",validate:re})},...!t.flags.noGit&&{git:()=>p.confirm({message:"Should we initialize a Git repository and stage the changes?",initialValue:!0})}},{onCancel(){process.exit(1)}});return g.template=n.template,g.projectId=n.openfortPublishableKey,{appName:n.name||t.appName,template:n.template,theme:n.theme,createBackend:n.createBackend,apiEndpoint:n.apiEndpoint,openfortPublishableKey:n.openfortPublishableKey,openfortSecretKey:n.openfortSecretKey,shieldPublishableKey:n.shieldPublishableKey,shieldSecretKey:n.shieldSecretKey,shieldEncryptionShare:n.shieldEncryptionShare,flags:{...t.flags,noGit:!n.git||t.flags.noGit}}}catch(n){if(n instanceof T)return r.warn(`
10
+ ${L} needs an interactive terminal to provide options`),await p.confirm({message:"Continue scaffolding a default Openfort app?",initialValue:!0})||(r.info("Exiting..."),process.exit(0)),r.info(`Bootstrapping a default Openfort app in ./${t.appName}`),{...t,template:"openfort-ui",createBackend:!1,openfortPublishableKey:"",shieldPublishableKey:""};throw n}};function Ye(e){switch(e){case"openfort-ui":return"Pre-built UI components";case"headless":return"Custom, unstyled components";case"firebase":return"With Firebase authentication";default:return""}}import ge from"node:path";import N from"node:path";import k from"fs-extra";import Me from"ora";var ce=async({projectDir:e,openfortSecretKey:o,shieldSecretKey:i,shieldApiKey:t,shieldEncryptionShare:n,port:a=3110})=>{let s=Me("Creating backend...").start();try{let c=N.join(_,"template/backend"),l=N.join(e,"backend");k.copySync(c,l);let d=N.join(l,".env.example"),u=N.join(l,".env");if(k.existsSync(d)){let h=k.readFileSync(d,"utf-8").replace(/OPENFORT_SECRET_KEY=.*/g,`OPENFORT_SECRET_KEY=${o}`).replace(/SHIELD_SECRET_KEY=.*/g,`SHIELD_SECRET_KEY=${i}`).replace(/SHIELD_API_KEY=.*/g,`SHIELD_API_KEY=${t}`).replace(/SHIELD_ENCRYPTION_SHARE=.*/g,`SHIELD_ENCRYPTION_SHARE=${n}`).replace(/PORT=.*/g,`PORT=${a}`);k.writeFileSync(u,h)}await new Promise(m=>setTimeout(m,250)),s.succeed("Backend created successfully!")}catch(c){throw s.fail("Failed to create backend"),r.error(c instanceof Error?c.message:String(c)),c}};import de from"node:path";import*as E from"@clack/prompts";import S from"chalk";import w from"fs-extra";import ze from"ora";var fe=async({projectName:e,projectDir:o,template:i,createBackend:t})=>{r.info("");let n=ze(`Scaffolding in: ${o}...
11
+ `).start();if(w.existsSync(o))if(w.readdirSync(o).length===0)e!=="."&&n.info(`${S.cyan.bold(e)} exists but is empty, continuing...
12
+ `);else{n.stopAndPersist();let l=await E.select({message:`${S.redBright.bold("Warning:")} ${S.cyan.bold(e)} already exists and isn't empty. How would you like to proceed?`,options:[{label:"Abort installation (recommended)",value:"abort"},{label:"Clear the directory and continue installation",value:"clear"},{label:"Continue installation and overwrite conflicting files",value:"overwrite"}],initialValue:"abort"});(E.isCancel(l)||l==="abort")&&(n.fail("Aborting installation..."),process.exit(1));let d=await E.confirm({message:`Are you sure you want to ${l==="clear"?"clear the directory":"overwrite conflicting files"}?`,initialValue:!1});(E.isCancel(d)||!d)&&(n.fail("Aborting installation..."),process.exit(1)),l==="clear"&&(n.info(`Emptying ${S.cyan.bold(e)} and creating Openfort app..
13
+ `),w.emptyDirSync(o))}n.start(),w.mkdirSync(o,{recursive:!0});let a=de.join(_,"template/openfort-templates",i),s=t?de.join(o,"frontend"):o;w.copySync(a,s);let c=e==="."?"App":S.cyan.bold(e);await new Promise(l=>setTimeout(l,250)),n.succeed(`${c} ${S.green("scaffolded successfully!")}
14
14
  `)};import me from"node:path";import $ from"fs-extra";var ue=({projectDir:e,openfortPublishableKey:o,shieldPublishableKey:i,apiEndpoint:t,theme:n})=>{let a=me.join(e,".env.example"),s=me.join(e,".env");if(!$.existsSync(a)){let d=We({openfortPublishableKey:o,shieldPublishableKey:i,apiEndpoint:t,theme:n});$.writeFileSync(s,d);return}let l=$.readFileSync(a,"utf-8");l=l.replace(/VITE_OPENFORT_PUBLISHABLE_KEY=.*/g,`VITE_OPENFORT_PUBLISHABLE_KEY=${o}`).replace(/NEXT_PUBLIC_OPENFORT_PUBLISHABLE_KEY=.*/g,`NEXT_PUBLIC_OPENFORT_PUBLISHABLE_KEY=${o}`).replace(/OPENFORT_PUBLISHABLE_KEY=.*/g,`OPENFORT_PUBLISHABLE_KEY=${o}`),l=l.replace(/VITE_SHIELD_PUBLISHABLE_KEY=.*/g,`VITE_SHIELD_PUBLISHABLE_KEY=${i}`).replace(/NEXT_PUBLIC_SHIELD_PUBLISHABLE_KEY=.*/g,`NEXT_PUBLIC_SHIELD_PUBLISHABLE_KEY=${i}`).replace(/SHIELD_PUBLISHABLE_KEY=.*/g,`SHIELD_PUBLISHABLE_KEY=${i}`),t&&(l=l.replace(/VITE_CREATE_ENCRYPTED_SESSION_ENDPOINT=.*/g,`VITE_CREATE_ENCRYPTED_SESSION_ENDPOINT=${t}`).replace(/NEXT_PUBLIC_CREATE_ENCRYPTED_SESSION_ENDPOINT=.*/g,`NEXT_PUBLIC_CREATE_ENCRYPTED_SESSION_ENDPOINT=${t}`).replace(/CREATE_ENCRYPTED_SESSION_ENDPOINT=.*/g,`CREATE_ENCRYPTED_SESSION_ENDPOINT=${t}`)),n&&(l=l.replace(/VITE_OPENFORT_THEME=.*/g,`VITE_OPENFORT_THEME=${n}`).replace(/NEXT_PUBLIC_OPENFORT_THEME=.*/g,`NEXT_PUBLIC_OPENFORT_THEME=${n}`).replace(/OPENFORT_THEME=.*/g,`OPENFORT_THEME=${n}`)),$.writeFileSync(s,l)},We=({openfortPublishableKey:e,shieldPublishableKey:o,apiEndpoint:i,theme:t})=>{let n=`# Openfort Configuration
15
15
  VITE_OPENFORT_PUBLISHABLE_KEY=${e}
16
16
  VITE_SHIELD_PUBLISHABLE_KEY=${o}
@@ -25,4 +25,4 @@ Next steps:`),e!=="."&&r.info(` ${f.cyan(`cd ${e}`)}`),i){let n=F.join(o,"backe
25
25
  ${f.yellow("For the backend:")}`),r.info(` ${f.cyan("cd backend")}`),s&&(t==="yarn"?r.info(` ${f.cyan(t)}`):r.info(` ${f.cyan(`${t} install`)}`)),["npm","bun"].includes(t)?r.info(` ${f.cyan(`${t} run dev`)}`):r.info(` ${f.cyan(`${t} dev`)}`),r.info(`
26
26
  ${f.yellow("For the frontend (in a new terminal):")}`),r.info(` ${f.cyan("cd frontend")}`),s&&(t==="yarn"?r.info(` ${f.cyan(t)}`):r.info(` ${f.cyan(`${t} install`)}`)),["npm","bun"].includes(t)?r.info(` ${f.cyan(`${t} run dev`)}`):r.info(` ${f.cyan(`${t} dev`)}`)}else{let n=F.join(o,"node_modules");!U.existsSync(n)&&(t==="yarn"?r.info(` ${f.cyan(t)}`):r.info(` ${f.cyan(`${t} install`)}`)),["npm","bun"].includes(t)?r.info(` ${f.cyan(`${t} run dev`)}`):r.info(` ${f.cyan(`${t} dev`)}`)}!await D(o)&&!j(o)&&(r.info(`
27
27
  ${f.cyan("git init")}`),r.info(` ${f.cyan('git commit -m "initial commit"')}`)),r.info(`
28
- ${f.blue("Learn more at https://www.openfort.xyz/docs")}`)};import be from"node:path";var Se=e=>{let i=x(e).split("/"),t=i[i.length-1];if(t==="."){let s=be.resolve(process.cwd());t=be.basename(s)}let n=i.findIndex(s=>s.startsWith("@"));i.findIndex(s=>s.startsWith("@"))!==-1&&(t=i.slice(n).join("/"));let a=i.filter(s=>!s.startsWith("@")).join("/");return[t,a]};import Qe from"gradient-string";var et=["#c3c3c3ff","#ff3b30"],Pe=async()=>{let e=Qe(et),o=C();(o==="yarn"||o==="pnpm")&&console.log(""),console.log(e.multiline(z))};import{execSync as tt}from"node:child_process";import nt from"node:https";var Te=e=>{let o=y();o.includes("beta")?(r.warn(" You are using a beta version of create-openfort."),r.warn(" Please report any bugs you encounter.")):o.includes("next")?(r.warn(" You are running create-openfort with the @next tag which is no longer maintained."),r.warn(" Please run the CLI with @latest instead.")):o!==e&&(r.warn(" You are using an outdated version of create-openfort."),r.warn(" Your version:",`${o}.`,"Latest version in the npm registry:",e),r.warn(" Please run the CLI with @latest to get the latest updates."))};function ot(){return new Promise((e,o)=>{nt.get("https://registry.npmjs.org/-/package/create-openfort/dist-tags",i=>{if(i.statusCode===200){let t="";i.on("data",n=>{t+=n}),i.on("end",()=>{e(JSON.parse(t).latest)})}else o()}).on("error",()=>{o()})})}var we=()=>ot().catch(()=>{try{return tt("npm view create-openfort version").toString().trim()}catch{return null}});var it=async()=>{let e=await we();await Pe(),e&&Te(e);let{appName:o,template:i,theme:t,createBackend:n,apiEndpoint:a,openfortPublishableKey:s,openfortSecretKey:c,shieldPublishableKey:l,shieldSecretKey:d,shieldEncryptionShare:u,flags:{noGit:m}}=await pe(),[h,Y]=Se(o);g.projectName=h;let v=await he({projectName:Y,template:i,openfortPublishableKey:s,shieldPublishableKey:l,apiEndpoint:a||(n?"http://localhost:3110/api/protected-create-encryption-session":void 0),theme:t,createBackendOption:n,openfortSecretKey:c,shieldSecretKey:d,shieldApiKey:l,shieldEncryptionShare:u}),R=n?Oe.join(v,"frontend","package.json"):Oe.join(v,"package.json");if(G.existsSync(R)){let A=G.readJSONSync(R);A.name=h,A.openfortMetadata={initVersion:y(),template:i},G.writeJSONSync(R,A,{spaces:2})}m||await Ee(v),await _e({projectName:Y,projectDir:v,createBackend:n}),g.send({status:"completed"}),process.exit(0)};it().catch(e=>{r.error("Aborting installation..."),e instanceof Error?r.error(e):r.error("An unknown error has occurred. Please open an issue on GitHub with the below:"),g.send({status:"error",properties:{error:e instanceof Error?e.message:String(e)}}),process.exit(1)});
28
+ ${f.blue("Learn more at https://www.openfort.xyz/docs")}`)};import be from"node:path";var Pe=e=>{let i=x(e).split("/"),t=i[i.length-1];if(t==="."){let s=be.resolve(process.cwd());t=be.basename(s)}let n=i.findIndex(s=>s.startsWith("@"));i.findIndex(s=>s.startsWith("@"))!==-1&&(t=i.slice(n).join("/"));let a=i.filter(s=>!s.startsWith("@")).join("/");return[t,a]};import Qe from"gradient-string";var et=["#c3c3c3ff","#ff3b30"],Se=async()=>{let e=Qe(et),o=C();(o==="yarn"||o==="pnpm")&&console.log(""),console.log(e.multiline(z))};import{execSync as tt}from"node:child_process";import nt from"node:https";var Te=e=>{let o=y();o.includes("beta")?(r.warn(" You are using a beta version of create-openfort."),r.warn(" Please report any bugs you encounter.")):o.includes("next")?(r.warn(" You are running create-openfort with the @next tag which is no longer maintained."),r.warn(" Please run the CLI with @latest instead.")):o!==e&&(r.warn(" You are using an outdated version of create-openfort."),r.warn(" Your version:",`${o}.`,"Latest version in the npm registry:",e),r.warn(" Please run the CLI with @latest to get the latest updates."))};function ot(){return new Promise((e,o)=>{nt.get("https://registry.npmjs.org/-/package/create-openfort/dist-tags",i=>{if(i.statusCode===200){let t="";i.on("data",n=>{t+=n}),i.on("end",()=>{e(JSON.parse(t).latest)})}else o()}).on("error",()=>{o()})})}var we=()=>ot().catch(()=>{try{return tt("npm view create-openfort version").toString().trim()}catch{return null}});var it=async()=>{let e=await we();await Se(),e&&Te(e);let{appName:o,template:i,theme:t,createBackend:n,apiEndpoint:a,openfortPublishableKey:s,openfortSecretKey:c,shieldPublishableKey:l,shieldSecretKey:d,shieldEncryptionShare:u,flags:{noGit:m}}=await pe(),[h,Y]=Pe(o);g.projectName=h;let v=await he({projectName:Y,template:i,openfortPublishableKey:s,shieldPublishableKey:l,apiEndpoint:a||(n?"http://localhost:3110/api/protected-create-encryption-session":void 0),theme:t,createBackendOption:n,openfortSecretKey:c,shieldSecretKey:d,shieldApiKey:l,shieldEncryptionShare:u}),R=n?Oe.join(v,"frontend","package.json"):Oe.join(v,"package.json");if(G.existsSync(R)){let A=G.readJSONSync(R);A.name=h,A.openfortMetadata={initVersion:y(),template:i},G.writeJSONSync(R,A,{spaces:2})}m||await Ee(v),await _e({projectName:Y,projectDir:v,createBackend:n}),g.send({status:"completed"}),process.exit(0)};it().catch(e=>{r.error("Aborting installation..."),e instanceof Error?r.error(e):r.error("An unknown error has occurred. Please open an issue on GitHub with the below:"),g.send({status:"error",properties:{error:e instanceof Error?e.message:String(e)}}),process.exit(1)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-openfort",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Create Openfort applications with embedded wallets",
5
5
  "license": "MIT",
6
6
  "author": "Openfort (https://www.openfort.xyz)",
@@ -49,7 +49,7 @@
49
49
  "@types/fs-extra": "^11.0.4",
50
50
  "@types/gradient-string": "^1.1.6",
51
51
  "@types/node": "^20.14.10",
52
- "tsup": "^6.7.0",
52
+ "tsup": "^8.3.5",
53
53
  "type-fest": "^3.13.1",
54
54
  "typescript": "^5.8.2"
55
55
  },
@@ -286,7 +286,6 @@ const GlowCanvas = ({ accentColor, backgroundColor }: { accentColor: string, bac
286
286
  document.removeEventListener("mousemove", handleMouseMove);
287
287
  if (animationRef.current) cancelAnimationFrame(animationRef.current);
288
288
  };
289
- // biome-ignore lint/correctness/useExhaustiveDependencies: animation effect depends on dimensions only
290
289
  }, [dimensions]);
291
290
 
292
291
  return (
@@ -1,9 +1,7 @@
1
1
  import { Main } from './components/cards/main'
2
2
 
3
3
  function App() {
4
- return (
5
- <Main />
6
- )
4
+ return <Main />
7
5
  }
8
6
 
9
7
  export default App
@@ -1,16 +1,21 @@
1
- import { getAddress, parseAbi } from "viem";
2
- import { useAccount, useReadContract, useWriteContract } from "wagmi";
3
- import { TruncateData } from "../ui/TruncateData";
4
- import { useWallets } from "@openfort/react";
1
+ import { useMemo } from 'react'
2
+ import { getAddress, parseAbi } from 'viem'
3
+ import {
4
+ useAccount,
5
+ useChains,
6
+ useReadContract,
7
+ useWriteContract
8
+ } from 'wagmi'
9
+ import { TruncateData } from '../ui/TruncateData'
5
10
 
6
11
  const MintContract = () => {
7
-
8
12
  const { address } = useAccount()
9
- const wallWallets = useWallets()
10
- console.log({ wallWallets })
11
-
12
13
 
13
- const { data: balance, refetch, error: balanceError } = useReadContract({
14
+ const {
15
+ data: balance,
16
+ refetch,
17
+ error: balanceError,
18
+ } = useReadContract({
14
19
  address: '0xef147ed8bb07a2a0e7df4c1ac09e96dec459ffac',
15
20
  abi: [
16
21
  {
@@ -38,17 +43,22 @@ const MintContract = () => {
38
43
  functionName: 'symbol',
39
44
  })
40
45
 
41
- const { data: hash, isPending, writeContract, error } = useWriteContract({
46
+ const {
47
+ data: hash,
48
+ isPending,
49
+ writeContract,
50
+ error,
51
+ } = useWriteContract({
42
52
  mutation: {
43
53
  onSuccess: () => {
44
54
  setTimeout(() => {
45
55
  refetch()
46
- }, 100);
56
+ }, 100)
47
57
  },
48
58
  onSettled: (data: unknown, error: Error | null) => {
49
- console.log('Settled', { data, error });
50
- }
51
- }
59
+ console.log('Settled', { data, error })
60
+ },
61
+ },
52
62
  })
53
63
 
54
64
  async function submit({ amount }: { amount: string }) {
@@ -63,7 +73,9 @@ const MintContract = () => {
63
73
  return (
64
74
  <div>
65
75
  <h2>Mint contract</h2>
66
- <p className="mb-2 text-zinc-400 text-sm">Current balance: {balance?.toString()} {tokenSymbol as string || ""}</p>
76
+ <p className="mb-2 text-zinc-400 text-sm">
77
+ Current balance: {balance?.toString()} {(tokenSymbol as string) || ''}
78
+ </p>
67
79
  <form
68
80
  className="space-y-4"
69
81
  onSubmit={(e) => {
@@ -78,13 +90,8 @@ const MintContract = () => {
78
90
  className="grow peer"
79
91
  name="amount"
80
92
  />
81
- <button
82
- className='btn'
83
- disabled={isPending || !address}
84
- >
85
- {
86
- isPending ? 'Minting...' : 'Mint Tokens'
87
- }
93
+ <button className="btn" disabled={isPending || !address}>
94
+ {isPending ? 'Minting...' : 'Mint Tokens'}
88
95
  </button>
89
96
  </form>
90
97
  <TruncateData data={hash} />
@@ -95,14 +102,33 @@ const MintContract = () => {
95
102
  }
96
103
 
97
104
  export const Actions = () => {
98
-
105
+ const hasSponsorPolicy = useMemo(() => !!import.meta.env.VITE_POLICY_ID, [])
106
+ const chains = useChains()
99
107
  return (
100
108
  <div className="flex flex-col w-full">
101
109
  <h1>Actions</h1>
102
110
  <span className="mb-4 text-zinc-400 text-sm">
103
111
  Interact with smart contracts on the blockchain.
104
112
  </span>
113
+ {!hasSponsorPolicy && (
114
+ <div className="mb-3 p-3 bg-red-800 text-white rounded text-sm">
115
+ <strong>Warning: Transactions are not sponsored.</strong> Minting may
116
+ fail because transactions are not being sponsored. To sponsor
117
+ transactions, go to the{' '}
118
+ <a
119
+ href="https://dashboard.openfort.xyz/policies"
120
+ target="_blank"
121
+ rel="noopener noreferrer"
122
+ className="underline"
123
+ >
124
+ Openfort Dashboard
125
+ </a>{' '}
126
+ and <b>create a policy</b> sponsoring transactions in{' '}
127
+ <b>{chains[0].name}</b>. Set the <code>VITE_POLICY_ID</code>{' '}
128
+ environment variable with the policy ID.
129
+ </div>
130
+ )}
105
131
  <MintContract />
106
132
  </div>
107
- );
108
- }
133
+ )
134
+ }
@@ -1,62 +1,73 @@
1
- import { OAuthProvider, useAuthCallback, useEmailAuth, useGuestAuth, useOAuth } from "@openfort/react";
2
- import React, { useState } from "react";
1
+ import {
2
+ OAuthProvider,
3
+ useAuthCallback,
4
+ useEmailAuth,
5
+ useGuestAuth,
6
+ useOAuth,
7
+ } from '@openfort/react'
8
+ import type React from 'react'
9
+ import { useState } from 'react'
3
10
 
4
11
  const GoogleSignInButton: React.FC = () => {
5
12
  // Sign in with Google
6
- const { initOAuth, isLoading } = useOAuth();
13
+ const { initOAuth, isLoading } = useOAuth()
7
14
 
8
15
  return (
9
16
  <button
10
17
  onClick={() => initOAuth({ provider: OAuthProvider.GOOGLE })}
11
18
  className="w-full py-2 px-4 border border-zinc-700 text-white rounded cursor-pointer transition-colors hover:bg-zinc-900/60"
12
19
  >
13
- {isLoading ? "Loading..." : "Continue with Google"}
20
+ {isLoading ? 'Loading...' : 'Continue with Google'}
14
21
  </button>
15
- );
16
- };
22
+ )
23
+ }
17
24
 
18
25
  const GuestSignInButton: React.FC = () => {
19
26
  // Sign in with Google
20
- const { signUpGuest, isLoading } = useGuestAuth();
27
+ const { signUpGuest, isLoading } = useGuestAuth()
21
28
 
22
29
  return (
23
30
  <button
24
31
  onClick={() => signUpGuest()}
25
32
  className="w-full py-2 px-4 border border-zinc-700 text-white rounded cursor-pointer transition-colors hover:bg-zinc-900/60"
26
33
  >
27
- {isLoading ? "Loading..." : "Continue as Guest"}
34
+ {isLoading ? 'Loading...' : 'Continue as Guest'}
28
35
  </button>
29
- );
30
- };
36
+ )
37
+ }
31
38
 
32
39
  const EmailForm = ({ isLogin }: { isLogin: boolean }) => {
33
- const { signInEmail, signUpEmail, error, isLoading } = useEmailAuth();
40
+ const { signInEmail, signUpEmail, error, isLoading } = useEmailAuth()
34
41
 
35
42
  const handleSubmit = async (event: React.FormEvent) => {
36
- event.preventDefault();
37
- const form = event.target as HTMLFormElement;
38
- const email = (form.elements[0] as HTMLInputElement).value;
39
- const password = (form.elements[1] as HTMLInputElement).value;
43
+ event.preventDefault()
44
+ const form = event.target as HTMLFormElement
45
+ const email = (form.elements[0] as HTMLInputElement).value
46
+ const password = (form.elements[1] as HTMLInputElement).value
40
47
  if (isLogin) {
41
48
  const { requiresEmailVerification } = await signInEmail({
42
49
  email,
43
- password
44
- });
50
+ password,
51
+ })
45
52
 
46
53
  if (requiresEmailVerification) {
47
- alert("User is not verified. Please check your email to verify your account.");
54
+ alert(
55
+ 'User is not verified. Please check your email to verify your account.',
56
+ )
48
57
  }
49
58
  } else {
50
59
  const { requiresEmailVerification } = await signUpEmail({
51
60
  email,
52
61
  password,
53
- });
62
+ })
54
63
 
55
64
  if (requiresEmailVerification) {
56
- alert("Registration successful! Please check your email to verify your account.");
65
+ alert(
66
+ 'Registration successful! Please check your email to verify your account.',
67
+ )
57
68
  }
58
69
  }
59
- };
70
+ }
60
71
 
61
72
  return (
62
73
  <form onSubmit={handleSubmit} className="space-y-4 mb-4">
@@ -88,32 +99,33 @@ const EmailForm = ({ isLogin }: { isLogin: boolean }) => {
88
99
  </div>
89
100
  {error && <p className="text-red-500 text-sm">{error.message}</p>}
90
101
 
91
- <button
92
- type="submit"
93
- className="btn mt-2"
94
- >
95
- {isLoading ? "Loading..." : isLogin ? "Sign In" : "Sign Up"}
102
+ <button type="submit" className="btn mt-2">
103
+ {isLoading ? 'Loading...' : isLogin ? 'Sign In' : 'Sign Up'}
96
104
  </button>
97
105
  </form>
98
106
  )
99
107
  }
100
108
 
101
109
  const AuthForm = () => {
102
- const [isLogin, setIsLogin] = useState(true);
110
+ const [isLogin, setIsLogin] = useState(true)
103
111
  const { isLoading } = useAuthCallback({
104
- onSuccess: () => { alert("Authentication verified!") },
105
- onError: (e) => { alert("Authentication verification failed!" + e.message) },
106
- });
112
+ onSuccess: () => {
113
+ alert('Authentication verified!')
114
+ },
115
+ onError: (e) => {
116
+ alert(`Authentication verification failed!${e.message}`)
117
+ },
118
+ })
107
119
 
108
120
  if (isLoading) {
109
- return <div>Verifying authentication...</div>;
121
+ return <div>Verifying authentication...</div>
110
122
  }
111
123
 
112
124
  return (
113
125
  <div className="space-y-6">
114
126
  <div className="relative">
115
127
  <h1 className="text-left text-2xl font-semibold tracking-tight">
116
- {isLogin ? "Sign in to account" : "Create an account"}
128
+ {isLogin ? 'Sign in to account' : 'Create an account'}
117
129
  </h1>
118
130
  </div>
119
131
 
@@ -124,9 +136,7 @@ const AuthForm = () => {
124
136
  <div className="w-full border-t border-gray-300" />
125
137
  </div>
126
138
  <div className="relative flex justify-center text-sm">
127
- <span className="bg-zinc-800 px-2">
128
- or
129
- </span>
139
+ <span className="bg-zinc-800 px-2">or</span>
130
140
  </div>
131
141
  </div>
132
142
 
@@ -136,20 +146,19 @@ const AuthForm = () => {
136
146
  </div>
137
147
 
138
148
  <div className="text-left text-sm">
139
- {isLogin ? "Already have an account? " : "Don't have an account? "}
149
+ {isLogin ? 'Already have an account? ' : "Don't have an account? "}
140
150
  <button
141
151
  onClick={() => setIsLogin(!isLogin)}
142
152
  className="text-primary hover:underline cursor-pointer font-medium"
143
153
  >
144
- {isLogin ? "Sign Up" : "Sign In"}
154
+ {isLogin ? 'Sign Up' : 'Sign In'}
145
155
  </button>
146
156
  </div>
147
157
  </div>
148
- );
158
+ )
149
159
  }
150
160
 
151
161
  export const Auth = () => {
152
-
153
162
  return (
154
163
  <div className="card relative">
155
164
  <AuthForm />