create-githat-app 1.0.5 → 1.0.7

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 (3) hide show
  1. package/README.md +35 -0
  2. package/dist/cli.js +102 -22
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,5 +1,19 @@
1
+ <div align="center">
2
+
1
3
  # create-githat-app
2
4
 
5
+ **The CLI for [GitHat](https://githat.io) — Auth + Hosting that replaces Clerk + Vercel**
6
+
7
+ [![npm version](https://img.shields.io/npm/v/create-githat-app?style=flat-square&logo=npm&logoColor=white&color=cb3837)](https://www.npmjs.com/package/create-githat-app)
8
+ [![npm downloads](https://img.shields.io/npm/dm/create-githat-app?style=flat-square&logo=npm&logoColor=white&color=cb3837)](https://www.npmjs.com/package/create-githat-app)
9
+ [![SDK](https://img.shields.io/npm/v/@githat/nextjs?style=flat-square&logo=npm&logoColor=white&label=%40githat%2Fnextjs&color=cb3837)](https://www.npmjs.com/package/@githat/nextjs)
10
+ [![Website](https://img.shields.io/website?style=flat-square&url=https%3A%2F%2Fgithat.io&up_message=live&up_color=1f6feb&label=githat.io)](https://githat.io)
11
+ [![License](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](LICENSE)
12
+
13
+ </div>
14
+
15
+ ---
16
+
3
17
  Scaffold a production-ready app with a fully-managed backend — auth, teams, orgs, API keys, MCP verification, and AI agent identity. **No backend to deploy.**
4
18
 
5
19
  [GitHat](https://githat.io) is your backend. When you run `create-githat-app`, your generated project connects to GitHat's hosted platform at `api.githat.io`. User accounts, organizations, teams, API keys, MCP servers, and AI agents are all stored and managed by GitHat. You write frontend code only.
@@ -263,6 +277,19 @@ VITE_GITHAT_PUBLISHABLE_KEY=pk_live_...
263
277
  VITE_GITHAT_API_URL=https://api.githat.io
264
278
  ```
265
279
 
280
+ ## Documentation
281
+
282
+ - [GitHat Quick Start](https://githat.io/docs/quickstart) — Get running in 5 minutes
283
+ - [SDK Reference](https://githat.io/docs/sdk) — `@githat/nextjs` hooks, components, and server utils
284
+ - [API Reference](https://githat.io/docs/api) — All 86 REST endpoints
285
+ - [CLI Reference](https://githat.io/docs/cli) — Flags, prompts, and templates
286
+ - [Next.js Guide](https://githat.io/docs/nextjs) — Auth in Next.js 14-16+
287
+ - [React Guide](https://githat.io/docs/react) — Auth in any React app
288
+ - [Bring Your Own Database](https://githat.io/docs/byod) — Keep your PostgreSQL, MySQL, or MongoDB
289
+ - [MCP Servers](https://githat.io/docs/mcp) — Domain verification for AI tool servers
290
+ - [AI Agents](https://githat.io/docs/agents) — Wallet-based identity for autonomous agents
291
+ - [Skills Marketplace](https://githat.io/docs/skills) — Install templates, integrations, and workflows
292
+
266
293
  ## Contributing
267
294
 
268
295
  ```bash
@@ -273,6 +300,14 @@ npm run build
273
300
  node bin/index.js test-app
274
301
  ```
275
302
 
303
+ ## Related
304
+
305
+ - [@githat/nextjs](https://www.npmjs.com/package/@githat/nextjs) — React/Next.js SDK
306
+ - [GitHat Platform](https://githat.io) — Auth + Hosting replacing Clerk + Vercel
307
+ - [GitHat Pricing](https://githat.io/pricing) — Free, Pro, and Enterprise tiers
308
+ - [GitHat vs Clerk](https://githat.io/compare/githat-vs-clerk) — Feature comparison
309
+ - [GitHat vs Auth0](https://githat.io/compare/githat-vs-auth0) — Why developers switch
310
+
276
311
  ## License
277
312
 
278
313
  MIT
package/dist/cli.js CHANGED
@@ -11,7 +11,7 @@ import gradient from "gradient-string";
11
11
  import chalk from "chalk";
12
12
 
13
13
  // src/constants.ts
14
- var VERSION = "1.0.5";
14
+ var VERSION = "1.0.6";
15
15
  var DEFAULT_API_URL = "https://api.githat.io";
16
16
  var DASHBOARD_URL = "https://githat.io/dashboard/apps";
17
17
  var BRAND_COLORS = ["#7c3aed", "#6366f1", "#8b5cf6"];
@@ -281,12 +281,12 @@ async function promptProjectType() {
281
281
  {
282
282
  value: "frontend",
283
283
  label: "Frontend only",
284
- hint: "Next.js with API routes"
284
+ hint: "Next.js or React+Vite"
285
285
  },
286
286
  {
287
287
  value: "fullstack",
288
288
  label: "Fullstack",
289
- hint: "Next.js + separate API (Turborepo)"
289
+ hint: "Next.js + API (Turborepo)"
290
290
  }
291
291
  ]
292
292
  })
@@ -325,16 +325,17 @@ function getInstallCommand(pm) {
325
325
  }
326
326
 
327
327
  // src/prompts/framework.ts
328
- async function promptFramework(typescriptOverride) {
328
+ async function promptFramework(typescriptOverride, isFullstack) {
329
329
  const packageManager = detectPackageManager();
330
+ const frameworkOptions = isFullstack ? [{ value: "nextjs", label: "Next.js 16", hint: "App Router \xB7 SSR \xB7 middleware auth" }] : [
331
+ { value: "nextjs", label: "Next.js 16", hint: "App Router \xB7 SSR \xB7 middleware auth" },
332
+ { value: "react-vite", label: "React 19 + Vite 7", hint: "SPA \xB7 client-side routing" }
333
+ ];
330
334
  const answers = await p3.group(
331
335
  {
332
336
  framework: () => p3.select({
333
337
  message: "Framework",
334
- options: [
335
- { value: "nextjs", label: "Next.js 16", hint: "App Router \xB7 SSR \xB7 middleware auth" },
336
- { value: "react-vite", label: "React 19 + Vite 7", hint: "SPA \xB7 client-side routing" }
337
- ]
338
+ options: frameworkOptions
338
339
  }),
339
340
  typescript: () => typescriptOverride !== void 0 ? Promise.resolve(typescriptOverride) : p3.select({
340
341
  message: "Language",
@@ -397,7 +398,77 @@ async function promptBackend() {
397
398
  }
398
399
 
399
400
  // src/prompts/githat.ts
401
+ import { execSync } from "child_process";
400
402
  import * as p5 from "@clack/prompts";
403
+ function openBrowser(url) {
404
+ try {
405
+ const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
406
+ execSync(`${cmd} "${url}"`, { stdio: "ignore" });
407
+ } catch {
408
+ }
409
+ }
410
+ function sleep(ms) {
411
+ return new Promise((resolve4) => setTimeout(resolve4, ms));
412
+ }
413
+ async function deviceAuthFlow() {
414
+ const spinner2 = p5.spinner();
415
+ try {
416
+ spinner2.start("Requesting device code...");
417
+ const codeRes = await fetch(`${DEFAULT_API_URL}/auth/device/code`, {
418
+ method: "POST",
419
+ headers: { "Content-Type": "application/json" },
420
+ body: JSON.stringify({ client_name: "create-githat-app" })
421
+ });
422
+ if (!codeRes.ok) {
423
+ spinner2.stop("Failed to get device code");
424
+ return null;
425
+ }
426
+ const codeData = await codeRes.json();
427
+ spinner2.stop("Device code generated");
428
+ p5.note(
429
+ `Code: ${codeData.user_code}
430
+
431
+ Opening browser to complete sign-in...
432
+ If it doesn't open, visit: ${codeData.verification_uri_complete}`,
433
+ "Authorize Device"
434
+ );
435
+ openBrowser(codeData.verification_uri_complete);
436
+ spinner2.start("Waiting for browser authorization...");
437
+ const expiresAt = Date.now() + codeData.expires_in * 1e3;
438
+ const pollInterval = (codeData.interval || 5) * 1e3;
439
+ while (Date.now() < expiresAt) {
440
+ await sleep(pollInterval);
441
+ const tokenRes = await fetch(`${DEFAULT_API_URL}/auth/device/token`, {
442
+ method: "POST",
443
+ headers: { "Content-Type": "application/json" },
444
+ body: JSON.stringify({ device_code: codeData.device_code })
445
+ });
446
+ const tokenData = await tokenRes.json();
447
+ if (tokenData.error === "authorization_pending") {
448
+ continue;
449
+ }
450
+ if (tokenData.error === "expired_token") {
451
+ spinner2.stop("Device code expired");
452
+ p5.log.error("Authorization timed out. Please try again.");
453
+ return null;
454
+ }
455
+ if (tokenData.publishable_key) {
456
+ spinner2.stop("Authorized!");
457
+ p5.log.success(`Connected to ${tokenData.app_name || "your app"} (${tokenData.org_name || "your org"})`);
458
+ return tokenData.publishable_key;
459
+ }
460
+ spinner2.stop("Authorization failed");
461
+ return null;
462
+ }
463
+ spinner2.stop("Timed out");
464
+ p5.log.error("Authorization timed out. Please try again.");
465
+ return null;
466
+ } catch (err) {
467
+ spinner2.stop("Connection error");
468
+ p5.log.error("Failed to connect to GitHat API. Check your internet connection.");
469
+ return null;
470
+ }
471
+ }
401
472
  async function promptGitHat(existingKey) {
402
473
  let publishableKey = existingKey || "";
403
474
  if (!publishableKey) {
@@ -405,6 +476,7 @@ async function promptGitHat(existingKey) {
405
476
  message: "Connect to GitHat",
406
477
  options: [
407
478
  { value: "skip", label: "Skip for now", hint: "auth works on localhost \u2014 add key later" },
479
+ { value: "browser", label: "Sign in with browser", hint: "opens githat.io to authorize" },
408
480
  { value: "paste", label: "I have a key", hint: "paste your pk_live_... key" }
409
481
  ]
410
482
  });
@@ -412,7 +484,14 @@ async function promptGitHat(existingKey) {
412
484
  p5.cancel("Setup cancelled.");
413
485
  process.exit(0);
414
486
  }
415
- if (connectChoice === "paste") {
487
+ if (connectChoice === "browser") {
488
+ const key = await deviceAuthFlow();
489
+ if (key) {
490
+ publishableKey = key;
491
+ } else {
492
+ p5.log.warn("Authorization failed. Continuing without key...");
493
+ }
494
+ } else if (connectChoice === "paste") {
416
495
  const pastedKey = await p5.text({
417
496
  message: "Publishable key",
418
497
  placeholder: `pk_live_... (get one at ${DASHBOARD_URL})`,
@@ -535,9 +614,10 @@ async function runPrompts(args) {
535
614
  const project = await promptProject(args.initialName);
536
615
  const projectType = await promptProjectType();
537
616
  sectionHeader("Stack");
538
- const framework = await promptFramework(args.typescript);
617
+ const isFullstack = projectType.projectType === "fullstack";
618
+ const framework = await promptFramework(args.typescript, isFullstack);
539
619
  let backend = {};
540
- if (projectType.projectType === "fullstack") {
620
+ if (isFullstack) {
541
621
  backend = await promptBackend();
542
622
  }
543
623
  sectionHeader("Connect");
@@ -579,7 +659,7 @@ function answersToContext(answers) {
579
659
  // src/scaffold/index.ts
580
660
  import fs3 from "fs-extra";
581
661
  import path3 from "path";
582
- import { execSync as execSync2 } from "child_process";
662
+ import { execSync as execSync3 } from "child_process";
583
663
  import * as p9 from "@clack/prompts";
584
664
  import chalk2 from "chalk";
585
665
 
@@ -701,25 +781,25 @@ function createSpinner(text4) {
701
781
  return ora({ text: text4, color: "magenta" });
702
782
  }
703
783
  async function withSpinner(text4, fn, successText) {
704
- const spinner = createSpinner(text4);
705
- spinner.start();
784
+ const spinner2 = createSpinner(text4);
785
+ spinner2.start();
706
786
  try {
707
787
  const result = await fn();
708
- spinner.succeed(successText || text4);
788
+ spinner2.succeed(successText || text4);
709
789
  return result;
710
790
  } catch (err) {
711
- spinner.fail(text4);
791
+ spinner2.fail(text4);
712
792
  throw err;
713
793
  }
714
794
  }
715
795
 
716
796
  // src/utils/git.ts
717
- import { execSync } from "child_process";
797
+ import { execSync as execSync2 } from "child_process";
718
798
  function initGit(cwd) {
719
799
  try {
720
- execSync("git init", { cwd, stdio: "ignore" });
721
- execSync("git add -A", { cwd, stdio: "ignore" });
722
- execSync('git commit -m "Initial commit from create-githat-app"', {
800
+ execSync2("git init", { cwd, stdio: "ignore" });
801
+ execSync2("git add -A", { cwd, stdio: "ignore" });
802
+ execSync2('git commit -m "Initial commit from create-githat-app"', {
723
803
  cwd,
724
804
  stdio: "ignore"
725
805
  });
@@ -776,7 +856,7 @@ async function scaffold(context, options) {
776
856
  `Installing dependencies with ${context.packageManager}...`,
777
857
  async () => {
778
858
  try {
779
- execSync2(installCmd, { cwd: root, stdio: "ignore", timeout: 12e4 });
859
+ execSync3(installCmd, { cwd: root, stdio: "ignore", timeout: 12e4 });
780
860
  } catch (err) {
781
861
  const msg = err.message || "";
782
862
  if (msg.includes("TIMEOUT")) {
@@ -799,7 +879,7 @@ async function scaffold(context, options) {
799
879
  if (!p9.isCancel(starPrompt) && starPrompt) {
800
880
  try {
801
881
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
802
- execSync2(`${cmd} "https://github.com/GitHat-IO/githat"`, { stdio: "ignore" });
882
+ execSync3(`${cmd} "https://github.com/GitHat-IO/githat"`, { stdio: "ignore" });
803
883
  } catch {
804
884
  p9.log.info("Visit https://github.com/GitHat-IO/githat to star us!");
805
885
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-githat-app",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "GitHat CLI — scaffold apps and manage the skills marketplace",
5
5
  "type": "module",
6
6
  "bin": {