create-openfort 0.1.9 → 1.0.0

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 (67) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/index.js +20 -20
  3. package/package.json +1 -1
  4. package/template/backend/pnpm-lock.yaml +6 -6
  5. package/template/openfort-templates/firebase/AGENTS.md +1 -1
  6. package/template/openfort-templates/firebase/package.json +3 -3
  7. package/template/openfort-templates/firebase/src/App.tsx +2 -1
  8. package/template/openfort-templates/firebase/src/integrations/openfort/providers.tsx +36 -32
  9. package/template/openfort-templates/firebase/src/lib/contracts.ts +34 -0
  10. package/template/openfort-templates/firebase/src/ui/openfort/blockchain/ActionsCard.tsx +25 -13
  11. package/template/openfort-templates/firebase/src/ui/openfort/wallets/WalletCreation.tsx +108 -63
  12. package/template/openfort-templates/firebase/src/ui/openfort/wallets/WalletListCard.tsx +211 -41
  13. package/template/openfort-templates/firebase/src/ui/openfort/wallets/WalletPasswordSheets.tsx +45 -21
  14. package/template/openfort-templates/headless/AGENTS.md +1 -1
  15. package/template/openfort-templates/headless/package.json +2 -2
  16. package/template/openfort-templates/headless/src/components/cards/actions.tsx +30 -21
  17. package/template/openfort-templates/headless/src/components/cards/auth.tsx +2 -2
  18. package/template/openfort-templates/headless/src/components/cards/profile.tsx +0 -2
  19. package/template/openfort-templates/headless/src/components/cards/wallets.tsx +230 -67
  20. package/template/openfort-templates/headless/src/components/createWallet.tsx +115 -73
  21. package/template/openfort-templates/headless/src/components/passwordRecovery.tsx +48 -23
  22. package/template/openfort-templates/headless/src/components/providers.tsx +30 -22
  23. package/template/openfort-templates/headless/src/lib/contracts.ts +43 -0
  24. package/template/openfort-templates/openfort-ui/AGENTS.md +1 -1
  25. package/template/openfort-templates/openfort-ui/package.json +3 -3
  26. package/template/openfort-templates/openfort-ui/src/components/cards/actions.tsx +30 -15
  27. package/template/openfort-templates/openfort-ui/src/components/cards/auth.tsx +1 -1
  28. package/template/openfort-templates/openfort-ui/src/components/cards/wallets.tsx +232 -67
  29. package/template/openfort-templates/openfort-ui/src/components/createWallet.tsx +115 -73
  30. package/template/openfort-templates/openfort-ui/src/components/passwordRecovery.tsx +48 -23
  31. package/template/openfort-templates/openfort-ui/src/components/providers.tsx +34 -27
  32. package/template/openfort-templates/openfort-ui/src/lib/contracts.ts +35 -0
  33. package/template/openfort-templates/solana-headless/biome.json +70 -0
  34. package/template/openfort-templates/solana-headless/index.html +16 -0
  35. package/template/openfort-templates/solana-headless/package.json +34 -0
  36. package/template/openfort-templates/solana-headless/public/githubLogo.svg +5 -0
  37. package/template/openfort-templates/solana-headless/public/openfort.svg +13 -0
  38. package/template/openfort-templates/solana-headless/public/solanaLogo.svg +11 -0
  39. package/template/openfort-templates/solana-headless/src/App.tsx +7 -0
  40. package/template/openfort-templates/solana-headless/src/components/cards/auth.tsx +167 -0
  41. package/template/openfort-templates/solana-headless/src/components/cards/head.tsx +359 -0
  42. package/template/openfort-templates/solana-headless/src/components/cards/history.tsx +134 -0
  43. package/template/openfort-templates/solana-headless/src/components/cards/main.tsx +140 -0
  44. package/template/openfort-templates/solana-headless/src/components/cards/profile.tsx +80 -0
  45. package/template/openfort-templates/solana-headless/src/components/cards/send.tsx +242 -0
  46. package/template/openfort-templates/solana-headless/src/components/cards/sign.tsx +48 -0
  47. package/template/openfort-templates/solana-headless/src/components/cards/wallets.tsx +199 -0
  48. package/template/openfort-templates/solana-headless/src/components/createWallet.tsx +117 -0
  49. package/template/openfort-templates/solana-headless/src/components/passwordRecovery.tsx +167 -0
  50. package/template/openfort-templates/solana-headless/src/components/providers.tsx +23 -0
  51. package/template/openfort-templates/solana-headless/src/components/ui/Sheet.tsx +47 -0
  52. package/template/openfort-templates/solana-headless/src/components/ui/Tabs.tsx +111 -0
  53. package/template/openfort-templates/solana-headless/src/components/ui/TruncateData.tsx +31 -0
  54. package/template/openfort-templates/solana-headless/src/hooks/useSolanaMessageSigner.ts +37 -0
  55. package/template/openfort-templates/solana-headless/src/index.css +180 -0
  56. package/template/openfort-templates/solana-headless/src/lib/errors.ts +4 -0
  57. package/template/openfort-templates/solana-headless/src/lib/solana/balance.ts +17 -0
  58. package/template/openfort-templates/solana-headless/src/lib/solana/index.ts +4 -0
  59. package/template/openfort-templates/solana-headless/src/lib/solana/kora.ts +137 -0
  60. package/template/openfort-templates/solana-headless/src/lib/solana/transaction.ts +146 -0
  61. package/template/openfort-templates/solana-headless/src/lib/solana/transactionHistory.ts +39 -0
  62. package/template/openfort-templates/solana-headless/src/main.tsx +13 -0
  63. package/template/openfort-templates/solana-headless/src/vite-env.d.ts +1 -0
  64. package/template/openfort-templates/solana-headless/tsconfig.app.json +24 -0
  65. package/template/openfort-templates/solana-headless/tsconfig.json +7 -0
  66. package/template/openfort-templates/solana-headless/tsconfig.node.json +22 -0
  67. package/template/openfort-templates/solana-headless/vite.config.ts +8 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - [#201](https://github.com/openfort-xyz/openfort-react/pull/201) [`2c23537`](https://github.com/openfort-xyz/openfort-react/commit/2c235373b7879584c26e70951d3839b3157bd4b0) Thanks [@isardmart](https://github.com/isardmart)! - solana, wagmi subpath, tree shakeable
8
+
9
+ ### Minor Changes
10
+
11
+ - [#205](https://github.com/openfort-xyz/openfort-react/pull/205) [`9c442df`](https://github.com/openfort-xyz/openfort-react/commit/9c442df5080ea5f16ed1d2905da36d338105e722) Thanks [@isardmart](https://github.com/isardmart)! - added solana-headless template to the cli
12
+
13
+ ## 0.1.10
14
+
15
+ ### Patch Changes
16
+
17
+ - [#186](https://github.com/openfort-xyz/openfort-react/pull/186) [`fdb39df`](https://github.com/openfort-xyz/openfort-react/commit/fdb39dffbfc52fd015ddb17a43cff321461047d1) Thanks [@isardmart](https://github.com/isardmart)! - added retries on connector of useWallets, fixed error on headless social login
18
+
3
19
  ## 0.1.9
4
20
 
5
21
  ### Patch Changes
package/dist/index.js CHANGED
@@ -1,28 +1,28 @@
1
1
  #!/usr/bin/env node
2
- import Oe from"path";import G from"fs-extra";import*as p from"@clack/prompts";import De from"chalk";import{Command as Fe,Option as Ue}from"commander";import M from"path";import{fileURLToPath as Ie}from"url";var ve=Ie(import.meta.url),xe=M.dirname(ve),_=M.join(xe,"../"),z=` ___ ___ ___ _ _ ___ ___ ___ _____
2
+ import Te from"path";import F from"fs-extra";import*as c from"@clack/prompts";import He from"chalk";import{Command as je,Option as De}from"commander";import Y from"path";import{fileURLToPath as we}from"url";var Oe=we(import.meta.url),ve=Y.dirname(Oe),S=Y.join(ve,"../"),M=` ___ ___ ___ _ _ ___ ___ ___ _____
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"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"crypto";import Ce from"https";import{hostname as Re,userInfo as Ae}from"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
- Learn more about Openfort at ${De.hex("#5B87F5").bold("https://www.openfort.xyz")}
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 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"path";import N from"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"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
- `)};import me from"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
6
+ `,b="openfort-project",$="create-openfort";var z=["openfort-ui","headless","solana-headless","firebase"],W=["auto","midnight","minimal","soft","web95","rounded","retro","nouns"];import Ie from"path";import xe from"fs-extra";var h=()=>{let e=Ie.join(S,"package.json");return xe.readJSONSync(e).version??"unknown"};var w=class extends Error{};var a={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 Ne,{createHash as q}from"crypto";import ke from"https";import{hostname as Ce,userInfo as Re}from"os";var J="https://analytics.openfort.io",X="phc_HosujvcO5QzmU2MVvZo8AxWV0pplTZJLr3jEd8dRVPE",Be=()=>{let e=`${Ce()}-${Re().username}`;return q("sha256").update(e).digest("hex").slice(0,16)},A=class{constructor(){this.enabled=!0;this.send=async({properties:o={},status:r})=>{if(a.debug("Sending telemetry...",{status:r,properties:o}),!this.enabled)return;if(!X||!J){a.warn("Telemetry is not configured properly. Please contact openfort developers at support@openfort.xyz.");return}let t={session_id:this.sessionId,cli_version:h(),node_version:process.version,platform:process.platform,cli_status:r,projectId:this.projectId,projectName:this.projectName,template:this.template,...o},n=JSON.stringify({api_key:X,event:"cli_tool_used",distinct_id:this.anonymousId,properties:t}),i=new URL(`${J}/capture/`),s={hostname:i.hostname,port:i.port||443,path:i.pathname,method:"POST",headers:{"Content-Type":"application/json","Content-Length":n.length}};return new Promise(d=>{let l=ke.request(s,p=>{p.on("data",()=>{a.debug("Telemetry request response received",p.statusMessage)}),p.on("end",()=>{d()})});l.on("error",p=>{a.debug("Telemetry request error",p),d()}),l.write(n),l.end()})};this.anonymousId=Be(),this.sessionId=q("sha256").update(Ne.randomBytes(16)).digest("hex").slice(0,15)}},u=new A;var x=e=>(e.length>1&&e.endsWith("/")&&(e=e.slice(0,-1)),e);var Le=/^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/,Z=e=>{let o=x(e),r=o.split("/"),t=r.findIndex(i=>i.startsWith("@")),n=r[r.length-1];if(r.findIndex(i=>i.startsWith("@"))!==-1&&(n=r.slice(t).join("/")),!(o==="."||Le.test(n??"")))return"App name must consist of only lowercase alphanumeric characters, '-', and '_'"};var Q="[\\da-f]{8}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{12}",ee=`(test|live)_${Q}`,$e=new RegExp(`^sk_${ee}$`),Ae=new RegExp(`^pk_${ee}$`),Ke=new RegExp(`^${Q}$`),Ve=/^.{44}$/,P=({label:e,required:o=!0,regex:r,formatHint:t,customCheck:n})=>i=>{if(i!=="-"){if(o&&!i)return`${e} is required`;if(r&&i&&!r.test(i))return`${e} is invalid${t?` (${t})`:""}`;if(n)return n(i)}},te=P({label:"Openfort Publishable Key",regex:Ae,formatHint:"expected format: pk_test_... or pk_live_..."}),ne=P({label:"Openfort Secret Key",regex:$e,formatHint:"expected format: sk_test_... or sk_live_..."}),oe=P({label:"Shield Publishable Key",regex:Ke,formatHint:"expected UUID format"}),re=P({label:"Shield Secret",required:!0}),ie=P({label:"Shield Encryption Share",regex:Ve,formatHint:"expected 44 characters"}),ae=P({label:"API endpoint",customCheck:e=>{try{new URL(e);return}catch{return"API endpoint must be a valid URL"}}}),se=async e=>{try{return!!(await(await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"}})).json()).session}catch{return!1}};var Ue={appName:b,template:"openfort-ui",createBackend:!0},le=async()=>{let e=new je().name($).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 De("--debug").hideHelp(!0)).version(h(),"-v, --version","Display the version number").addHelpText("afterAll",`
7
+ Learn more about Openfort at ${He.hex("#5B87F5").bold("https://www.openfort.xyz")}
8
+ `).parse(process.argv),o=e.args[0],r=e.opts();r.debug||(a.debug=()=>{}),u.enabled=!r.noTelemetry,a.debug("Telemetry enabled:",u.enabled),u.send({status:"started"});let t={...Ue,appName:o||b,flags:{noGit:r.noGit||!1,noInstall:r.noInstall||!1,default:r.default||!1,CI:r.CI||!1,template:r.template,theme:r.theme}};if(t.flags.CI)return t.template=r.template||"openfort-ui",t.theme=r.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 a.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 w("Non-interactive environment");let n=await c.group({...!o&&{name:()=>c.text({message:"What will your project be called?",defaultValue:b,validate:Z})},template:()=>c.select({message:"Select an Openfort template:",options:z.filter(i=>i!=="solana-headless").map(i=>({value:i,label:i==="openfort-ui"?"Openfort UI (default)":i,hint:Fe(i)})),initialValue:"openfort-ui"}),chain:({results:i})=>{if(i.template==="headless")return c.select({message:"Select blockchain:",options:[{value:"ethereum",label:"Ethereum (EVM)",hint:"Polygon Amoy, Beam testnet, etc."},{value:"solana",label:"Solana (SVM)",hint:"Devnet / Mainnet-Beta"}],initialValue:"ethereum"})},createBackend:()=>c.confirm({message:"Do you want to create a backend for automatic account recovery?",initialValue:!0}),apiEndpoint:async({results:i})=>{if(!i.createBackend){let s=await c.confirm({message:"Do you have an existing API endpoint for account recovery?",initialValue:!1});if(c.isCancel(s)&&process.exit(1),s){let d=!1,l="";for(;!d;){let p=await c.text({message:"Enter your API endpoint for creating encryption sessions:",placeholder:"http://localhost:3110/api/protected-create-encryption-session",validate:ae});c.isCancel(p)&&process.exit(1),l=p;let f=c.spinner();if(f.start("Testing API endpoint..."),await se(l))f.stop("API endpoint validated!"),d=!0;else{f.stop("API endpoint validation failed"),a.error("The endpoint did not return a valid session response");let E=await c.confirm({message:"Would you like to try another endpoint?",initialValue:!0});(c.isCancel(E)||!E)&&process.exit(1)}}return l}}},theme:({results:i})=>{if(i.template==="openfort-ui")return c.select({message:"Select a theme:",options:W.map(s=>({value:s,label:s==="auto"?"Auto (default)":s})),initialValue:"auto"})},openfortPublishableKey:()=>c.text({message:"Enter your Project Publishable Key:",placeholder:"pk_test_...",validate:te}),openfortSecretKey:({results:i})=>{if(i.createBackend)return c.text({message:"Enter your Project Secret Key:",placeholder:"sk_test_...",validate:ne})},shieldEncryptionShare:({results:i})=>{if(i.createBackend)return c.text({message:"Enter your Shield Encryption Share:",placeholder:"Your 44-character encryption share",validate:ie})},shieldPublishableKey:()=>c.text({message:"Enter your Shield Publishable Key:",placeholder:"00000000-0000-0000-0000-000000000000",validate:oe}),shieldSecretKey:({results:i})=>{if(i.createBackend)return c.text({message:"Enter your Shield Secret Key:",placeholder:"Your Shield Secret",validate:re})},...!t.flags.noGit&&{git:()=>c.confirm({message:"Should we initialize a Git repository and stage the changes?",initialValue:!0})}},{onCancel(){process.exit(1)}});return u.template=n.template,u.projectId=n.openfortPublishableKey,{appName:n.name||t.appName,template:n.chain==="solana"&&n.template==="headless"?"solana-headless":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 w)return a.warn(`
10
+ ${$} needs an interactive terminal to provide options`),await c.confirm({message:"Continue scaffolding a default Openfort app?",initialValue:!0})||(a.info("Exiting..."),process.exit(0)),a.info(`Bootstrapping a default Openfort app in ./${t.appName}`),{...t,template:"openfort-ui",createBackend:!1,openfortPublishableKey:"",shieldPublishableKey:""};throw n}};function Fe(e){switch(e){case"openfort-ui":return"Pre-built UI components";case"headless":return"Custom, unstyled \u2014 Ethereum or Solana";case"firebase":return"With Firebase authentication";default:return""}}import me from"path";import N from"path";import k from"fs-extra";import Ge from"ora";var pe=async({projectDir:e,openfortSecretKey:o,shieldSecretKey:r,shieldPublishableKey:t,shieldEncryptionShare:n,port:i=3110})=>{let s=Ge("Creating backend...").start();try{let d=N.join(S,"template/backend"),l=N.join(e,"backend");k.copySync(d,l);let p=N.join(l,".env.example"),f=N.join(l,".env");if(k.existsSync(p)){let E=k.readFileSync(p,"utf-8").replace(/OPENFORT_SECRET_KEY=.*/g,`OPENFORT_SECRET_KEY=${o}`).replace(/SHIELD_SECRET_KEY=.*/g,`SHIELD_SECRET_KEY=${r}`).replace(/SHIELD_PUBLISHABLE_KEY=.*/g,`SHIELD_PUBLISHABLE_KEY=${t}`).replace(/SHIELD_ENCRYPTION_SHARE=.*/g,`SHIELD_ENCRYPTION_SHARE=${n}`).replace(/PORT=.*/g,`PORT=${i}`);k.writeFileSync(f,E)}await new Promise(g=>setTimeout(g,250)),s.succeed("Backend created successfully!")}catch(d){throw s.fail("Failed to create backend"),a.error(d instanceof Error?d.message:String(d)),d}};import K from"path";import*as _ from"@clack/prompts";import T from"chalk";import y from"fs-extra";import Ye from"ora";var ce=async({projectName:e,projectDir:o,template:r,createBackend:t})=>{a.info("");let n=Ye(`Scaffolding in: ${o}...
11
+ `).start();if(y.existsSync(o))if(y.readdirSync(o).length===0)e!=="."&&n.info(`${T.cyan.bold(e)} exists but is empty, continuing...
12
+ `);else{n.stopAndPersist();let p=await _.select({message:`${T.redBright.bold("Warning:")} ${T.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"});(_.isCancel(p)||p==="abort")&&(n.fail("Aborting installation..."),process.exit(1));let f=await _.confirm({message:`Are you sure you want to ${p==="clear"?"clear the directory":"overwrite conflicting files"}?`,initialValue:!1});(_.isCancel(f)||!f)&&(n.fail("Aborting installation..."),process.exit(1)),p==="clear"&&(n.info(`Emptying ${T.cyan.bold(e)} and creating Openfort app..
13
+ `),y.emptyDirSync(o))}n.start(),y.mkdirSync(o,{recursive:!0});let i=K.join(S,"template/openfort-templates",r),s=t?K.join(o,"frontend"):o;y.copySync(i,s);let d=K.join(s,"package.json");if(y.existsSync(d)){let p=y.readJsonSync(d),f=p.dependencies;f?.["@openfort/react"]&&f["@openfort/react"].startsWith("workspace:")&&(f["@openfort/react"]="latest",y.writeJsonSync(d,p,{spaces:2}))}let l=e==="."?"App":T.cyan.bold(e);await new Promise(p=>setTimeout(p,250)),n.succeed(`${l} ${T.green("scaffolded successfully!")}
14
+ `)};import de from"path";import C from"fs-extra";var fe=({projectDir:e,openfortPublishableKey:o,shieldPublishableKey:r,apiEndpoint:t,theme:n})=>{let i=de.join(e,".env.example"),s=de.join(e,".env");if(!C.existsSync(i)){let p=Me({openfortPublishableKey:o,shieldPublishableKey:r,apiEndpoint:t,theme:n});C.writeFileSync(s,p);return}let l=C.readFileSync(i,"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=${r}`).replace(/NEXT_PUBLIC_SHIELD_PUBLISHABLE_KEY=.*/g,`NEXT_PUBLIC_SHIELD_PUBLISHABLE_KEY=${r}`).replace(/SHIELD_PUBLISHABLE_KEY=.*/g,`SHIELD_PUBLISHABLE_KEY=${r}`),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}`)),C.writeFileSync(s,l)},Me=({openfortPublishableKey:e,shieldPublishableKey:o,apiEndpoint:r,theme:t})=>{let n=`# Openfort Configuration
15
15
  VITE_OPENFORT_PUBLISHABLE_KEY=${e}
16
16
  VITE_SHIELD_PUBLISHABLE_KEY=${o}
17
- `;return i&&(n+=`VITE_CREATE_ENCRYPTED_SESSION_ENDPOINT=${i}
17
+ `;return r&&(n+=`VITE_CREATE_ENCRYPTED_SESSION_ENDPOINT=${r}
18
18
  `),t&&(n+=`VITE_OPENFORT_THEME=${t}
19
- `),n};var he=async({projectName:e,template:o,openfortPublishableKey:i,shieldPublishableKey:t,apiEndpoint:n,theme:a,createBackendOption:s,openfortSecretKey:c,shieldSecretKey:l,shieldApiKey:d,shieldEncryptionShare:u})=>{let m=ge.resolve(process.cwd(),e);await fe({projectName:e,projectDir:m,template:o,createBackend:s});let h=s?ge.join(m,"frontend"):m;return ue({projectDir:h,openfortPublishableKey:i,shieldPublishableKey:t,apiEndpoint:n,theme:a}),s&&c&&l&&d&&u&&await ce({projectDir:m,openfortSecretKey:c,shieldSecretKey:l,shieldApiKey:d,shieldEncryptionShare:u}),r.info("All done!"),m};import{execSync as H}from"child_process";import K from"path";import*as V from"@clack/prompts";import O from"chalk";import{execa as I}from"execa";import ye from"fs-extra";import Je from"ora";var Xe=e=>{try{return H("git --version",{cwd:e}),!0}catch{return!1}},j=e=>ye.existsSync(K.join(e,".git")),D=async e=>{try{return await I("git",["rev-parse","--is-inside-work-tree"],{cwd:e,stdout:"ignore"}),!0}catch{return!1}},qe=()=>{let o=H("git --version").toString().trim().split(" ")[2],i=o?.split(".")[0],t=o?.split(".")[1];return{major:Number(i),minor:Number(t)}},Ze=()=>H("git config --global init.defaultBranch || echo main").toString().trim(),Ee=async e=>{if(r.info("Initializing Git..."),!Xe(e)){r.warn("Git is not installed. Skipping Git initialization.");return}let o=Je(`Creating a new git repo...
20
- `).start(),i=j(e),t=await D(e),n=K.parse(e).name;if(t&&i){if(o.stop(),!await V.confirm({message:`${O.redBright.bold("Warning:")} Git is already initialized in "${n}". Initializing a new git repository would delete the previous history. Would you like to continue anyways?`,initialValue:!1})){o.info("Skipping Git initialization.");return}ye.removeSync(K.join(e,".git"))}else if(t&&!i&&(o.stop(),!await V.confirm({message:`${O.redBright.bold("Warning:")} "${n}" is already in a git worktree. Would you still like to initialize a new git repository in this directory?`,initialValue:!1}))){o.info("Skipping Git initialization.");return}try{let a=Ze(),{major:s,minor:c}=qe();s<2||s===2&&c<28?(await I("git",["init"],{cwd:e}),await I("git",["symbolic-ref","HEAD",`refs/heads/${a}`],{cwd:e})):await I("git",["init",`--initial-branch=${a}`],{cwd:e}),await I("git",["add","."],{cwd:e}),o.succeed(`${O.green("Successfully initialized and staged")} ${O.green.bold("git")}
19
+ `),n};var ue=async({projectName:e,template:o,openfortPublishableKey:r,shieldPublishableKey:t,apiEndpoint:n,theme:i,createBackendOption:s,openfortSecretKey:d,shieldSecretKey:l,shieldEncryptionShare:p})=>{let f=me.resolve(process.cwd(),e);await ce({projectName:e,projectDir:f,template:o,createBackend:s});let g=s?me.join(f,"frontend"):f;return fe({projectDir:g,openfortPublishableKey:r,shieldPublishableKey:t,apiEndpoint:n,theme:i}),s&&d&&l&&t&&p&&await pe({projectDir:f,openfortSecretKey:d,shieldSecretKey:l,shieldPublishableKey:t,shieldEncryptionShare:p}),a.info("All done!"),f};import{execSync as j}from"child_process";import V from"path";import*as H from"@clack/prompts";import O from"chalk";import{execa as v}from"execa";import ge from"fs-extra";import ze from"ora";var We=e=>{try{return j("git --version",{cwd:e}),!0}catch{return!1}},D=e=>ge.existsSync(V.join(e,".git")),U=async e=>{try{return await v("git",["rev-parse","--is-inside-work-tree"],{cwd:e,stdout:"ignore"}),!0}catch{return!1}},Je=()=>{let o=j("git --version").toString().trim().split(" ")[2],r=o?.split(".")[0],t=o?.split(".")[1];return{major:Number(r),minor:Number(t)}},Xe=()=>j("git config --global init.defaultBranch || echo main").toString().trim(),he=async e=>{if(a.info("Initializing Git..."),!We(e)){a.warn("Git is not installed. Skipping Git initialization.");return}let o=ze(`Creating a new git repo...
20
+ `).start(),r=D(e),t=await U(e),n=V.parse(e).name;if(t&&r){if(o.stop(),!await H.confirm({message:`${O.redBright.bold("Warning:")} Git is already initialized in "${n}". Initializing a new git repository would delete the previous history. Would you like to continue anyways?`,initialValue:!1})){o.info("Skipping Git initialization.");return}ge.removeSync(V.join(e,".git"))}else if(t&&!r&&(o.stop(),!await H.confirm({message:`${O.redBright.bold("Warning:")} "${n}" is already in a git worktree. Would you still like to initialize a new git repository in this directory?`,initialValue:!1}))){o.info("Skipping Git initialization.");return}try{let i=Xe(),{major:s,minor:d}=Je();s<2||s===2&&d<28?(await v("git",["init"],{cwd:e}),await v("git",["symbolic-ref","HEAD",`refs/heads/${i}`],{cwd:e})):await v("git",["init",`--initial-branch=${i}`],{cwd:e}),await v("git",["add","."],{cwd:e}),o.succeed(`${O.green("Successfully initialized and staged")} ${O.green.bold("git")}
21
21
  `)}catch{o.fail(`${O.bold.red("Failed:")} could not initialize git. Update git to the latest version!
22
- `)}};import F from"path";import f from"chalk";import U from"fs-extra";var C=()=>{let e=process.env.npm_config_user_agent;return e?e.startsWith("yarn")?"yarn":e.startsWith("pnpm")?"pnpm":e.startsWith("bun")?"bun":"npm":"npm"};var _e=async({projectName:e=b,projectDir:o,createBackend:i})=>{let t=C();if(r.info(`
23
- ${f.green("Success! Your Openfort project is ready.")}`),r.info(`
24
- Next steps:`),e!=="."&&r.info(` ${f.cyan(`cd ${e}`)}`),i){let n=F.join(o,"backend","node_modules"),a=F.join(o,"frontend","node_modules"),s=!U.existsSync(n)||!U.existsSync(a);r.info(`
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
- ${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
- ${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"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"child_process";import nt from"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)});
22
+ `)}};import m from"chalk";var R=()=>{let e=process.env.npm_config_user_agent;return e?e.startsWith("yarn")?"yarn":e.startsWith("pnpm")?"pnpm":e.startsWith("bun")?"bun":"npm":"npm"};var ye=async({projectName:e=b,projectDir:o,createBackend:r})=>{let t=R();a.info(`
23
+ ${m.green("Success! Your Openfort project is ready.")}`),a.info(`
24
+ Next steps:`),e!=="."&&a.info(` ${m.cyan(`cd ${e}`)}`);let n=t==="yarn"?t:`${t} install`,i=["npm","bun"].includes(t)?`${t} run dev`:`${t} dev`;r?(a.info(`
25
+ ${m.yellow("For the backend:")}`),a.info(` ${m.cyan("cd backend")}`),a.info(` ${m.cyan(n)}`),a.info(` ${m.cyan(i)}`),a.info(`
26
+ ${m.yellow("For the frontend (in a new terminal):")}`),a.info(` ${m.cyan("cd frontend")}`),a.info(` ${m.cyan(n)}`),a.info(` ${m.cyan(i)}`)):(a.info(` ${m.cyan(n)}`),a.info(` ${m.cyan(i)}`)),!await U(o)&&!D(o)&&(a.info(`
27
+ ${m.cyan("git init")}`),a.info(` ${m.cyan('git commit -m "initial commit"')}`)),a.info(`
28
+ ${m.blue("Learn more at https://www.openfort.xyz/docs")}`)};import Ee from"path";var _e=e=>{let r=x(e).split("/"),t=r[r.length-1];if(t==="."){let s=Ee.resolve(process.cwd());t=Ee.basename(s)}let n=r.findIndex(s=>s.startsWith("@"));r.findIndex(s=>s.startsWith("@"))!==-1&&(t=r.slice(n).join("/"));let i=r.filter(s=>!s.startsWith("@")).join("/");return[t,i]};import qe from"gradient-string";var Ze=["#c3c3c3ff","#ff3b30"],Se=async()=>{let e=qe(Ze),o=R();(o==="yarn"||o==="pnpm")&&console.log(""),console.log(e.multiline(M))};import{execSync as Qe}from"child_process";import et from"https";var be=e=>{let o=h();o.includes("beta")?(a.warn(" You are using a beta version of create-openfort."),a.warn(" Please report any bugs you encounter.")):o.includes("next")?(a.warn(" You are running create-openfort with the @next tag which is no longer maintained."),a.warn(" Please run the CLI with @latest instead.")):o!==e&&(a.warn(" You are using an outdated version of create-openfort."),a.warn(" Your version:",`${o}.`,"Latest version in the npm registry:",e),a.warn(" Please run the CLI with @latest to get the latest updates."))};function tt(){return new Promise((e,o)=>{et.get("https://registry.npmjs.org/-/package/create-openfort/dist-tags",r=>{if(r.statusCode===200){let t="";r.on("data",n=>{t+=n}),r.on("end",()=>{e(JSON.parse(t).latest)})}else o()}).on("error",()=>{o()})})}var Pe=()=>tt().catch(()=>{try{return Qe("npm view create-openfort version").toString().trim()}catch{return null}});var nt=async()=>{let e=await Pe();await Se(),e&&be(e);let{appName:o,template:r,theme:t,createBackend:n,apiEndpoint:i,openfortPublishableKey:s,openfortSecretKey:d,shieldPublishableKey:l,shieldSecretKey:p,shieldEncryptionShare:f,flags:{noGit:g}}=await le(),[E,G]=_e(o);u.projectName=E;let I=await ue({projectName:G,template:r,openfortPublishableKey:s,apiEndpoint:i||(n?"http://localhost:3110/api/protected-create-encryption-session":void 0),theme:t,createBackendOption:n,openfortSecretKey:d,shieldSecretKey:p,shieldPublishableKey:l,shieldEncryptionShare:f}),B=n?Te.join(I,"frontend","package.json"):Te.join(I,"package.json");if(F.existsSync(B)){let L=F.readJSONSync(B);L.name=E,L.openfortMetadata={initVersion:h(),template:r},F.writeJSONSync(B,L,{spaces:2})}g||await he(I),await ye({projectName:G,projectDir:I,createBackend:n}),u.send({status:"completed"}),process.exit(0)};nt().catch(e=>{a.error("Aborting installation..."),e instanceof Error?a.error(e):a.error("An unknown error has occurred. Please open an issue on GitHub with the below:"),u.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.9",
3
+ "version": "1.0.0",
4
4
  "description": "Create Openfort applications with embedded wallets",
5
5
  "license": "MIT",
6
6
  "author": "Openfort (https://www.openfort.xyz)",
@@ -443,7 +443,7 @@ packages:
443
443
 
444
444
  glob@7.2.3:
445
445
  resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
446
- deprecated: Glob versions prior to v9 are no longer supported
446
+ deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
447
447
 
448
448
  gopd@1.2.0:
449
449
  resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
@@ -625,8 +625,8 @@ packages:
625
625
  proxy-from-env@1.1.0:
626
626
  resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
627
627
 
628
- qs@6.14.1:
629
- resolution: {integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==}
628
+ qs@6.14.2:
629
+ resolution: {integrity: sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==}
630
630
  engines: {node: '>=0.6'}
631
631
 
632
632
  range-parser@1.2.1:
@@ -1038,7 +1038,7 @@ snapshots:
1038
1038
  http-errors: 2.0.0
1039
1039
  iconv-lite: 0.4.24
1040
1040
  on-finished: 2.4.1
1041
- qs: 6.14.1
1041
+ qs: 6.14.2
1042
1042
  raw-body: 2.5.2
1043
1043
  type-is: 1.6.18
1044
1044
  unpipe: 1.0.0
@@ -1179,7 +1179,7 @@ snapshots:
1179
1179
  parseurl: 1.3.3
1180
1180
  path-to-regexp: 0.1.12
1181
1181
  proxy-addr: 2.0.7
1182
- qs: 6.14.1
1182
+ qs: 6.14.2
1183
1183
  range-parser: 1.2.1
1184
1184
  safe-buffer: 5.2.1
1185
1185
  send: 0.19.0
@@ -1399,7 +1399,7 @@ snapshots:
1399
1399
 
1400
1400
  proxy-from-env@1.1.0: {}
1401
1401
 
1402
- qs@6.14.1:
1402
+ qs@6.14.2:
1403
1403
  dependencies:
1404
1404
  side-channel: 1.1.0
1405
1405
 
@@ -104,7 +104,7 @@ Required environment variables for agent operation:
104
104
  ```env
105
105
  VITE_OPENFORT_PUBLISHABLE_KEY=pk_test_...
106
106
  VITE_SHIELD_PUBLISHABLE_KEY=sk_test_...
107
- VITE_POLICY_ID=pol_...
107
+ VITE_FEE_SPONSORSHIP_ID=pol_...
108
108
  VITE_CREATE_ENCRYPTED_SESSION_BASE_URL=http://localhost:5000
109
109
  VITE_CREATE_ENCRYPTED_SESSION_ENDPOINT=/api/shield-session
110
110
  VITE_apiKey=YOUR_FIREBASE_API_KEY
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "@heroicons/react": "^2.2.0",
15
- "@openfort/react": "latest",
15
+ "@openfort/react": "workspace:^",
16
16
  "@tanstack/react-query": ">=5.45.1",
17
17
  "firebase": "^11.4.0",
18
18
  "react": "^18.2.0",
@@ -22,11 +22,11 @@
22
22
  },
23
23
  "devDependencies": {
24
24
  "@biomejs/biome": "^2.3.8",
25
- "@types/react": "^19.1.10",
26
25
  "@tailwindcss/vite": "^4.1.15",
27
- "tailwindcss": "^4.1.15",
26
+ "@types/react": "^19.1.10",
28
27
  "@types/react-dom": "^19.1.7",
29
28
  "@vitejs/plugin-react": "^4.3.4",
29
+ "tailwindcss": "^4.1.15",
30
30
  "typescript": "~5.8.3",
31
31
  "vite": "^6.4.1"
32
32
  }
@@ -8,7 +8,7 @@ function App() {
8
8
  const { signOut } = useSignOut()
9
9
 
10
10
  useEffect(() => {
11
- auth.onAuthStateChanged((user) => {
11
+ const unsubscribe = auth.onAuthStateChanged((user) => {
12
12
  console.log('onAuthStateChanged')
13
13
  if (user) {
14
14
  console.log('onAuthStateChanged - User is signed in:', user)
@@ -18,6 +18,7 @@ function App() {
18
18
  signOut()
19
19
  }
20
20
  })
21
+ return unsubscribe
21
22
  }, [])
22
23
 
23
24
  return (
@@ -1,8 +1,5 @@
1
- import {
2
- getDefaultConfig,
3
- OpenfortProvider,
4
- ThirdPartyOAuthProvider,
5
- } from '@openfort/react'
1
+ import { OpenfortProvider, ThirdPartyOAuthProvider } from '@openfort/react'
2
+ import { getDefaultConfig, OpenfortWagmiBridge } from '@openfort/react/wagmi'
6
3
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
7
4
  import { beamTestnet, polygonAmoy, sepolia } from 'viem/chains'
8
5
  import { createConfig, WagmiProvider } from 'wagmi'
@@ -19,34 +16,41 @@ const wagmiConfig = createConfig(
19
16
 
20
17
  const queryClient = new QueryClient()
21
18
 
19
+ // Firebase's getIdToken(false) uses its own internal cache and only refreshes
20
+ // when the token is near expiry — no navigator lock, no starvation risk.
21
+ // Objects are defined outside the component for stable references so
22
+ // OpenfortProvider doesn't re-render from reference inequality.
23
+ const thirdPartyAuth = {
24
+ provider: ThirdPartyOAuthProvider.FIREBASE,
25
+ getAccessToken: async (): Promise<string | null> => {
26
+ return (await auth.currentUser?.getIdToken(/* forceRefresh */ false)) ?? null
27
+ },
28
+ }
29
+
30
+ const walletConfig = {
31
+ shieldPublishableKey: import.meta.env.VITE_SHIELD_PUBLISHABLE_KEY!,
32
+ ethereum: {
33
+ ethereumFeeSponsorshipId: import.meta.env.VITE_FEE_SPONSORSHIP_ID,
34
+ },
35
+ createEncryptedSessionEndpoint: import.meta.env.VITE_CREATE_ENCRYPTED_SESSION_ENDPOINT,
36
+ connectOnLogin: false, // Wallet creation handled manually after auth
37
+ }
38
+
22
39
  export function OpenfortProviders({ children }: { children: React.ReactNode }) {
23
40
  return (
24
- <WagmiProvider config={wagmiConfig}>
25
- <QueryClientProvider client={queryClient}>
26
- <OpenfortProvider
27
- debugMode
28
- publishableKey={import.meta.env.VITE_OPENFORT_PUBLISHABLE_KEY!}
29
- walletConfig={{
30
- shieldPublishableKey: import.meta.env.VITE_SHIELD_PUBLISHABLE_KEY!, // Get it from https://dashboard.openfort.io
31
- ethereumProviderPolicyId: import.meta.env.VITE_POLICY_ID, // Policy ID for sponsoring transactions
32
- createEncryptedSessionEndpoint: import.meta.env
33
- .VITE_CREATE_ENCRYPTED_SESSION_ENDPOINT, // Endpoint for encryption session
34
- recoverWalletAutomaticallyAfterAuth: false, // Wallet creation handled manually after auth
35
- }}
36
- thirdPartyAuth={{
37
- getAccessToken: async () => {
38
- return (
39
- (await auth.currentUser?.getIdToken(
40
- /* forceRefresh */ false,
41
- )) ?? null
42
- )
43
- },
44
- provider: ThirdPartyOAuthProvider.FIREBASE,
45
- }}
46
- >
47
- {children}
48
- </OpenfortProvider>
49
- </QueryClientProvider>
50
- </WagmiProvider>
41
+ <QueryClientProvider client={queryClient}>
42
+ <WagmiProvider config={wagmiConfig}>
43
+ <OpenfortWagmiBridge>
44
+ <OpenfortProvider
45
+ debugMode
46
+ publishableKey={import.meta.env.VITE_OPENFORT_PUBLISHABLE_KEY!}
47
+ walletConfig={walletConfig}
48
+ thirdPartyAuth={thirdPartyAuth}
49
+ >
50
+ {children}
51
+ </OpenfortProvider>
52
+ </OpenfortWagmiBridge>
53
+ </WagmiProvider>
54
+ </QueryClientProvider>
51
55
  )
52
56
  }
@@ -0,0 +1,34 @@
1
+ /** Chain IDs for mint contracts (viem/wagmi) */
2
+ const BEAM_CHAIN_ID = 13337
3
+ const POLYGON_CHAIN_ID = 80002
4
+ const BASE_SEPOLIA_CHAIN_ID = 84532
5
+
6
+ const DEFAULT_POLYGON_MINT = '0xef147ed8bb07a2a0e7df4c1ac09e96dec459ffac'
7
+ const DEFAULT_BEAM_MINT = '0x45238AB60ACA6862a70fe996D1A8baDb71Af5A8f'
8
+
9
+ type MintContractType = 'claim' | 'mint'
10
+
11
+ interface MintContractConfig {
12
+ address: string
13
+ type: MintContractType
14
+ }
15
+
16
+ function getMintContractAddress(chainId: number | undefined): string | undefined {
17
+ if (chainId == null) return undefined
18
+ if (chainId === BEAM_CHAIN_ID) {
19
+ return import.meta.env.VITE_BEAM_MINT_CONTRACT ?? DEFAULT_BEAM_MINT
20
+ }
21
+ if (chainId === POLYGON_CHAIN_ID || chainId === BASE_SEPOLIA_CHAIN_ID) {
22
+ return import.meta.env.VITE_POLYGON_MINT_CONTRACT ?? DEFAULT_POLYGON_MINT
23
+ }
24
+ return import.meta.env.VITE_POLYGON_MINT_CONTRACT ?? DEFAULT_POLYGON_MINT
25
+ }
26
+
27
+ export function getMintContractConfig(chainId: number | undefined): MintContractConfig | undefined {
28
+ const address = getMintContractAddress(chainId)
29
+ if (!address) return undefined
30
+ return {
31
+ address,
32
+ type: chainId === BEAM_CHAIN_ID ? 'claim' : 'mint',
33
+ }
34
+ }
@@ -1,19 +1,20 @@
1
1
  import { getAddress, parseAbi } from 'viem'
2
- import { useAccount, useReadContract, useWriteContract } from 'wagmi'
2
+ import { useAccount, useChainId, useReadContract, useWriteContract } from 'wagmi'
3
3
 
4
4
  import { TruncateData } from '../../../components/ui/TruncateData'
5
-
6
- const ERC20_ADDRESS = '0xef147ed8bb07a2a0e7df4c1ac09e96dec459ffac'
5
+ import { getMintContractConfig } from '../../../lib/contracts'
7
6
 
8
7
  function MintContract() {
9
8
  const { address } = useAccount()
9
+ const chainId = useChainId()
10
+ const config = getMintContractConfig(chainId)
10
11
 
11
12
  const {
12
13
  data: balance,
13
14
  refetch,
14
15
  error: balanceError,
15
16
  } = useReadContract({
16
- address: ERC20_ADDRESS,
17
+ address: (config?.address ?? undefined) as `0x${string}` | undefined,
17
18
  abi: [
18
19
  {
19
20
  type: 'function',
@@ -24,11 +25,11 @@ function MintContract() {
24
25
  },
25
26
  ],
26
27
  functionName: 'balanceOf',
27
- args: [address!],
28
+ args: config && address ? [address] : undefined,
28
29
  })
29
30
 
30
31
  const { data: tokenSymbol } = useReadContract({
31
- address: ERC20_ADDRESS,
32
+ address: (config?.address ?? undefined) as `0x${string}` | undefined,
32
33
  abi: [
33
34
  {
34
35
  type: 'function',
@@ -59,12 +60,23 @@ function MintContract() {
59
60
  })
60
61
 
61
62
  async function submit({ amount }: { amount: string }) {
62
- writeContract({
63
- address: getAddress(ERC20_ADDRESS),
64
- abi: parseAbi(['function mint(address to, uint256 amount)']),
65
- functionName: 'mint',
66
- args: [address!, BigInt(amount)],
67
- })
63
+ if (!config?.address) return
64
+ const amountWei = BigInt(amount) * BigInt(10 ** 18)
65
+ if (config.type === 'claim') {
66
+ writeContract({
67
+ address: getAddress(config.address),
68
+ abi: parseAbi(['function claim(uint256 amount)']),
69
+ functionName: 'claim',
70
+ args: [amountWei],
71
+ })
72
+ } else {
73
+ writeContract({
74
+ address: getAddress(config.address),
75
+ abi: parseAbi(['function mint(address to, uint256 amount)']),
76
+ functionName: 'mint',
77
+ args: [address!, amountWei],
78
+ })
79
+ }
68
80
  }
69
81
 
70
82
  return (
@@ -87,7 +99,7 @@ function MintContract() {
87
99
  className="grow peer"
88
100
  name="amount"
89
101
  />
90
- <button className="btn" disabled={isPending || !address}>
102
+ <button className="btn" disabled={isPending || !address || !config}>
91
103
  {isPending ? 'Minting...' : 'Mint Tokens'}
92
104
  </button>
93
105
  </form>