create-tina-app 1.6.2 → 2.1.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.
package/dist/index.js CHANGED
@@ -1,95 +1,7 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __commonJS = (cb, mod) => function __require() {
8
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
19
- // If the importer is in node compatibility mode or this is not an ESM
20
- // file that has been converted to a CommonJS file using a Babel-
21
- // compatible transform (i.e. "__esModule" has not been set), then set
22
- // "default" to the CommonJS "module.exports" for node compatibility.
23
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
24
- mod
25
- ));
26
-
27
- // package.json
28
- var require_package = __commonJS({
29
- "package.json"(exports, module) {
30
- module.exports = {
31
- name: "create-tina-app",
32
- version: "1.6.2",
33
- main: "dist/index.js",
34
- files: [
35
- "dist",
36
- "examples",
37
- "bin/*"
38
- ],
39
- bin: "bin/create-tina-app",
40
- typings: "dist/index.d.ts",
41
- license: "Apache-2.0",
42
- buildConfig: {
43
- entryPoints: [
44
- {
45
- name: "src/index.ts",
46
- target: "node"
47
- }
48
- ]
49
- },
50
- engines: {
51
- node: ">=18.18.0"
52
- },
53
- scripts: {
54
- types: "pnpm tsc",
55
- build: "tinacms-scripts build",
56
- "test-run-bin": "pnpm create-tina-app"
57
- },
58
- publishConfig: {
59
- registry: "https://registry.npmjs.org"
60
- },
61
- repository: {
62
- url: "https://github.com/tinacms/tinacms.git",
63
- directory: "packages/create-tina-app"
64
- },
65
- devDependencies: {
66
- "@tinacms/scripts": "workspace:*",
67
- "@types/cross-spawn": "catalog:",
68
- "@types/fs-extra": "^11.0.4",
69
- "@types/node": "^22.13.1",
70
- "@types/prompts": "catalog:",
71
- "@types/tar": "catalog:",
72
- typescript: "^5.7.3"
73
- },
74
- dependencies: {
75
- "@tinacms/metrics": "workspace:*",
76
- chalk: "4.1.2",
77
- commander: "^12.1.0",
78
- "cross-spawn": "catalog:",
79
- "fs-extra": "catalog:",
80
- ora: "catalog:",
81
- prompts: "catalog:",
82
- tar: "catalog:",
83
- "validate-npm-package-name": "catalog:"
84
- }
85
- };
86
- }
87
- });
88
-
89
1
  // src/index.ts
90
- import { Telemetry } from "@tinacms/metrics";
91
2
  import prompts from "prompts";
92
- import path4 from "node:path";
3
+ import path3 from "node:path";
4
+ import { createRequire } from "node:module";
93
5
 
94
6
  // src/util/fileUtil.ts
95
7
  import fs from "fs-extra";
@@ -107,6 +19,16 @@ var TextStyles = {
107
19
  err: chalk.red,
108
20
  bold: chalk.bold
109
21
  };
22
+ var TextStylesBold = {
23
+ tinaOrange: chalk.hex("#EC4816").bold,
24
+ link: (url) => `\x1B]8;;${url}\x07${chalk.cyan.underline(url)}\x1B]8;;\x07`,
25
+ cmd: chalk.bgBlackBright.bold.white,
26
+ info: chalk.blue,
27
+ success: chalk.green,
28
+ warn: chalk.yellow,
29
+ err: chalk.red,
30
+ bold: chalk.bold
31
+ };
110
32
 
111
33
  // src/util/fileUtil.ts
112
34
  async function isWriteable(directory) {
@@ -212,7 +134,6 @@ function install(packageManager, verboseOutput) {
212
134
 
213
135
  // src/util/git.ts
214
136
  import { execSync } from "child_process";
215
- import path2 from "path";
216
137
  import fs2 from "fs-extra";
217
138
  function isInGitRepository() {
218
139
  try {
@@ -231,16 +152,11 @@ function isInMercurialRepository() {
231
152
  return false;
232
153
  }
233
154
  function makeFirstCommit(root) {
234
- try {
235
- execSync("git checkout -b main", { stdio: "ignore" });
236
- execSync("git add -A", { stdio: "ignore" });
237
- execSync('git commit -m "Initial commit from Create Tina App"', {
238
- stdio: "ignore"
239
- });
240
- } catch (err) {
241
- fs2.removeSync(path2.join(root, ".git"));
242
- throw err;
243
- }
155
+ execSync("git checkout -b main", { stdio: "ignore" });
156
+ execSync("git add -A", { stdio: "ignore" });
157
+ execSync('git commit -m "Initial commit from Create Tina App"', {
158
+ stdio: "ignore"
159
+ });
244
160
  }
245
161
  function initializeGit(spinner) {
246
162
  execSync("git --version", { stdio: "ignore" });
@@ -323,13 +239,27 @@ async function downloadAndExtractRepo(root, { username, name: name2, branch, fil
323
239
 
324
240
  // src/templates.ts
325
241
  import { copy } from "fs-extra";
326
- import path3 from "path";
242
+ import path2 from "path";
327
243
  var TEMPLATES = [
328
244
  {
329
245
  title: "\u2B50 NextJS starter",
330
246
  description: "Kickstart your project with Next.js \u2013 our top recommendation for a seamless, performant, and versatile web experience.",
331
247
  value: "tina-nextjs-starter",
332
248
  isInternal: false,
249
+ features: [
250
+ {
251
+ name: "Visual Editing",
252
+ description: "\u2705"
253
+ },
254
+ {
255
+ name: "ISR",
256
+ description: "\u2705"
257
+ },
258
+ {
259
+ name: "SSG",
260
+ description: "\u2705"
261
+ }
262
+ ],
333
263
  gitURL: "https://github.com/tinacms/tina-nextjs-starter",
334
264
  devUrl: "http://localhost:3000"
335
265
  },
@@ -338,6 +268,20 @@ var TEMPLATES = [
338
268
  description: "Get your documentation site up and running with TinaCMS and Next.js in minutes.",
339
269
  value: "tina-docs",
340
270
  isInternal: false,
271
+ features: [
272
+ {
273
+ name: "Visual Editing",
274
+ description: "\u2705"
275
+ },
276
+ {
277
+ name: "ISR",
278
+ description: "\u2705"
279
+ },
280
+ {
281
+ name: "SSG",
282
+ description: "\u2705"
283
+ }
284
+ ],
341
285
  gitURL: "https://github.com/tinacms/tina-docs",
342
286
  devUrl: "http://localhost:3000"
343
287
  },
@@ -346,6 +290,20 @@ var TEMPLATES = [
346
290
  description: "Get started with Astro - a modern static site generator designed for fast, lightweight, and flexible web projects.",
347
291
  value: "tina-astro-starter",
348
292
  isInternal: false,
293
+ features: [
294
+ {
295
+ name: "Visual Editing",
296
+ description: "\u274C"
297
+ },
298
+ {
299
+ name: "ISR",
300
+ description: "\u274C"
301
+ },
302
+ {
303
+ name: "SSG",
304
+ description: "\u2705"
305
+ }
306
+ ],
349
307
  gitURL: "https://github.com/tinacms/tina-astro-starter",
350
308
  devUrl: "http://localhost:4321"
351
309
  },
@@ -354,6 +312,20 @@ var TEMPLATES = [
354
312
  description: "With Hugo, you wield the power of lightning-fast site generation, crafting web experiences at the speed of thought.",
355
313
  value: "tina-hugo-starter",
356
314
  isInternal: false,
315
+ features: [
316
+ {
317
+ name: "Visual Editing",
318
+ description: "\u274C"
319
+ },
320
+ {
321
+ name: "ISR",
322
+ description: "\u274C"
323
+ },
324
+ {
325
+ name: "SSG",
326
+ description: "\u2705"
327
+ }
328
+ ],
357
329
  gitURL: "https://github.com/tinacms/tina-hugo-starter",
358
330
  devUrl: "http://localhost:1313"
359
331
  },
@@ -362,6 +334,20 @@ var TEMPLATES = [
362
334
  description: "Dive into Remix to orchestrate seamless, interactive user journeys like a maestro of the web.",
363
335
  value: "tina-remix-starter",
364
336
  isInternal: false,
337
+ features: [
338
+ {
339
+ name: "Visual Editing",
340
+ description: "\u274C"
341
+ },
342
+ {
343
+ name: "ISR",
344
+ description: "\u274C"
345
+ },
346
+ {
347
+ name: "SSG",
348
+ description: "\u26A0\uFE0F Requires adapter"
349
+ }
350
+ ],
365
351
  gitURL: "https://github.com/tinacms/tina-remix-starter",
366
352
  devUrl: "http://localhost:3000"
367
353
  },
@@ -370,14 +356,42 @@ var TEMPLATES = [
370
356
  description: "Docusaurus empowers you to build and evolve documentation like crafting a living, breathing knowledge repository.",
371
357
  value: "tinasaurus",
372
358
  isInternal: false,
359
+ features: [
360
+ {
361
+ name: "Visual Editing",
362
+ description: "\u274C"
363
+ },
364
+ {
365
+ name: "ISR",
366
+ description: "\u274C"
367
+ },
368
+ {
369
+ name: "SSR",
370
+ description: "\u2705"
371
+ }
372
+ ],
373
373
  gitURL: "https://github.com/tinacms/tinasaurus",
374
374
  devUrl: "http://localhost:3000"
375
375
  },
376
376
  {
377
377
  title: "Bare bones starter",
378
- description: "Stripped down to essentials, this starter is the canvas for pure, unadulterated code creativity.",
378
+ description: "Stripped down to essentials, this starter is the canvas for pure, unadulterated code creativity. Built with Next.js.",
379
379
  value: "basic",
380
380
  isInternal: false,
381
+ features: [
382
+ {
383
+ name: "Visual Editing",
384
+ description: "\u2705"
385
+ },
386
+ {
387
+ name: "ISR",
388
+ description: "\u2705"
389
+ },
390
+ {
391
+ name: "SSG",
392
+ description: "\u2705"
393
+ }
394
+ ],
381
395
  gitURL: "https://github.com/tinacms/tina-barebones-starter",
382
396
  devUrl: "http://localhost:3000"
383
397
  }
@@ -394,7 +408,7 @@ async function downloadTemplate(template, root, spinner) {
394
408
  )}`;
395
409
  await downloadAndExtractRepo(root, repoInfo);
396
410
  } else {
397
- const templateFile = path3.join(__dirname, "..", "examples", template.value);
411
+ const templateFile = path2.join(__dirname, "..", "examples", template.value);
398
412
  await copy(`${templateFile}/`, "./");
399
413
  }
400
414
  }
@@ -440,17 +454,20 @@ async function checkPackageExists(name2) {
440
454
  import { exit } from "node:process";
441
455
 
442
456
  // src/util/options.ts
443
- var import_package = __toESM(require_package());
444
457
  import { Command } from "commander";
445
458
 
459
+ // package.json
460
+ var name = "create-tina-app";
461
+ var version = "2.1.0";
462
+
446
463
  // src/util/packageManagers.ts
447
464
  var PKG_MANAGERS = ["npm", "yarn", "pnpm", "bun"];
448
465
 
449
466
  // src/util/options.ts
450
467
  function extractOptions(args) {
451
468
  let projectName = "";
452
- const program = new Command(import_package.name);
453
- program.version(import_package.version).option(
469
+ const program = new Command(name);
470
+ program.version(version).option(
454
471
  "-t, --template <template>",
455
472
  `Choose which template to start from. Valid templates are: ${TEMPLATES.map(
456
473
  (x2) => x2.value
@@ -475,11 +492,111 @@ function extractOptions(args) {
475
492
  return opts;
476
493
  }
477
494
 
478
- // src/index.ts
479
- import validate from "validate-npm-package-name";
495
+ // src/util/isNpm.js
496
+ import { builtinModules as builtins } from "node:module";
497
+ function validate(name2) {
498
+ if (name2 === null) {
499
+ return {
500
+ message: "name cannot be null",
501
+ isError: true
502
+ };
503
+ }
504
+ if (name2 === void 0) {
505
+ return {
506
+ message: "name cannot be undefined",
507
+ isError: true
508
+ };
509
+ }
510
+ if (typeof name2 !== "string") {
511
+ return {
512
+ message: "name must be a string",
513
+ isError: true
514
+ };
515
+ }
516
+ if (!name2.length) {
517
+ return {
518
+ message: "name length must be greater than zero",
519
+ isError: true
520
+ };
521
+ }
522
+ if (name2.startsWith(".")) {
523
+ return {
524
+ message: "name cannot start with a period",
525
+ isError: true
526
+ };
527
+ }
528
+ if (name2.match(/^_/)) {
529
+ return {
530
+ message: "name cannot start with an underscore",
531
+ isError: true
532
+ };
533
+ }
534
+ if (name2.trim() !== name2) {
535
+ return {
536
+ message: "name cannot contain leading or trailing spaces",
537
+ isError: true
538
+ };
539
+ }
540
+ const exclusionList = ["node_modules", "favicon.ico"];
541
+ exclusionList.forEach(function(excludedName) {
542
+ if (name2.toLowerCase() === excludedName) {
543
+ return {
544
+ message: excludedName + " is not a valid package name",
545
+ isError: true
546
+ };
547
+ }
548
+ });
549
+ if (builtins.includes(name2.toLowerCase())) {
550
+ return {
551
+ message: name2 + " is a core module name",
552
+ isError: true
553
+ };
554
+ }
555
+ if (name2.length > 214) {
556
+ return {
557
+ message: "name can no longer contain more than 214 characters",
558
+ isError: true
559
+ };
560
+ }
561
+ if (name2.toLowerCase() !== name2) {
562
+ return {
563
+ message: "name can no longer contain capital letters",
564
+ isError: true
565
+ };
566
+ }
567
+ if (/[~'!()*]/.test(name2.split("/").slice(-1)[0])) {
568
+ return {
569
+ message: `name can no longer contain special characters ("~'!()*")`,
570
+ isError: true
571
+ };
572
+ }
573
+ if (encodeURIComponent(name2) !== name2) {
574
+ const scopedPackagePattern = new RegExp("^(?:@([^/]+?)[/])?([^/]+?)$");
575
+ const nameMatch = name2.match(scopedPackagePattern);
576
+ if (nameMatch) {
577
+ const user = nameMatch[1];
578
+ const pkg = nameMatch[2];
579
+ if (pkg.startsWith(".")) {
580
+ return {
581
+ message: "name cannot start with a period",
582
+ isError: true
583
+ };
584
+ }
585
+ if (encodeURIComponent(user) === user && encodeURIComponent(pkg) === pkg) {
586
+ return { message: null, isError: false };
587
+ }
588
+ }
589
+ return {
590
+ message: "name can only contain URL-friendly characters",
591
+ isError: true
592
+ };
593
+ }
594
+ return { message: null, isError: false };
595
+ }
480
596
 
481
597
  // src/util/asciiArt.ts
482
598
  var llama = " :--=: \n :-===- \n -=====- \n -=======. \n .=========-. \n :===========--:\n -=============.\n .==========-:. \n :=========-. \n -=========- \n .==========- \n -==========- \n :===========- \n -=============. \n :==============: \n :===============- \n .:-================- \n ..::---==================== \n ....::::::::::-------============================. \n .---=================================================: \n .-=====================================================- \n:=======================================================. \n .-====================================================. \n .-=================================================. \n :=============================================- \n -============================================. \n .============-:. -==========- \n :=========-: .. -==========. \n -========: :-=- -=========- \n .========. .-==== :=========: \n -=======: :=====. -========: \n -======- -====- -=======: \n -=====: -====: :======. \n .=====. -====. .-====- \n :==== -===- -====: \n -==- :===- :====. ";
599
+ var errorArt = " ++++++++++++++\u2260 \n +++++++++\u2248 \u03C0+++++++++\u2260 \n ++++ ++++ \n +++ +++\u2248 \n +++ +++ \n \u03C0++ +++ \n ++ ++ \n +- +\u03C0 \n ++\xD7 +++++++++ \u2260+++++++++ \u221A+++++++++ ++ \n + ++ \u2248+++ ++ ++ ++++ +\u221E \n ++ ++ ++ ++ ++ ++ + \n ++ ++ ++ ++ ++ ++ ++ \n ++ ++-+++++++- ++ ++ +++++++- + \n \u221A+ ++\xF7+++++ ++ ++++++++ ++ \n ++ ++ \u221E++ ++ ++ ++ \n ++ ++ +++ ++ ++ ++ \n ++ ++ +++ \u2260+++++++++ ++ \u2260+ \n ++ ++ ++ +\u2260\u221E\u221A\u221A\u2260\xD7+\u03C0 ++ \u2260+ \n ++ \u2260+ \n ++ \u2260+ \n ++ +++ \u2260+ \n ++ ++++ \u2260+ \n ++ ++++++++ \u2260+ \n ++ ++++++++++ =+ \n ++ ++++++ =+ \n ++ \u2248++++++ =+ \n ++ +++++++ \u2260+ \n ++ +++++++ \u2260+ \n ++ +++++++ =+ \n ++ ++++++++ =+ \n ++ \u221E++++++++++++ \u2260+ \n ++ \u221E++++++++++++++++++++++++++++++- =+ \n ++ +++++++++++++++++++++++++++++++++ \u2260+ \n ++ +++++++++++++++++++++++++++++++++ \u2260+ \n ++ ++++++++++++++++++++++++++++++ \u2260+ \n ++ +++++++++++++++++++++++++++++ \u2260+ \n ++ ++++++++++++++++++++++++++++ \u2260+ \n ++ ++++++++\u2260\u2260++++++=\u221A ++++++++ \u2260+ \n ++ ++++++ + +++++++ \u2260+ \n ++ +++++ \u221E+++ \xF7++++++ \u2260+ \n ++ ++++ +++ +++++\u221A \u2260+ \n ++ +++= +++\u221A ++++ \u2260+ \n ++ ++\u221E =++ +++ \u2260+ \n ++ ++\u2248 +++ ++\xF7 =+ \n ++ +++ +++\u2260 +++ =+ \n ++ \u2260+ \n ++ + \n \u2248+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ \n ++ +\u2260 \n ++ +++++++++ ++++++++ +++++++ ++++++ ++++++++ +\u2260 \n ++ ++ ++ ++ + ++ ++ ++ ++ ++ +\u2260 \n ++ ++ ++ ++ + ++ ++ ++ ++ ++ +\u2260 \n ++ ++++++++ ++++++++ ++++++++ ++ ++ ++++++++ +\u2260 \n ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +\u2260 \n ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +\u2260 \n ++ +++++++++ ++ ++ ++ ++ +++++++ ++ ++ +\u2260 \n ++ +\u2260 \n ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ \n \n ";
483
600
  var tinaCms = "\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\n\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\n \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\n \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551\n \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\n \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D";
484
601
 
485
602
  // src/themes.ts
@@ -517,21 +634,325 @@ var THEMES = [
517
634
  ];
518
635
 
519
636
  // src/index.ts
637
+ import { PostHog } from "posthog-node";
638
+
639
+ // src/util/posthog.ts
640
+ import { createHash, randomUUID } from "node:crypto";
641
+ import { system as getSystemInfo } from "systeminformation";
642
+ var CreateTinaAppStartedEvent = "create-tina-app-started";
643
+ var CreateTinaAppFinishedEvent = "create-tina-app-finished";
644
+ var TRACKING_STEPS = {
645
+ INIT: "initializing",
646
+ PRE_RUN_CHECKS: "pre_run_checks",
647
+ TELEMETRY_SETUP: "telemetry_setup",
648
+ PKG_MANAGER_SELECT: "package_manager_selection",
649
+ PROJECT_NAME_INPUT: "project_name_input",
650
+ TEMPLATE_SELECT: "template_selection",
651
+ THEME_SELECT: "theme_selection",
652
+ DIRECTORY_SETUP: "directory_setup",
653
+ DOWNLOADING_TEMPLATE: "downloading_template",
654
+ UPDATING_METADATA: "updating_metadata",
655
+ INSTALLING_PACKAGES: "installing_packages",
656
+ GIT_INIT: "git_initialization",
657
+ COMPLETE: "complete"
658
+ };
659
+ function generateSessionId() {
660
+ return randomUUID();
661
+ }
662
+ async function getAnonymousUserId() {
663
+ try {
664
+ const sysInfo = await getSystemInfo();
665
+ const systemUuid = sysInfo.uuid || "unknown";
666
+ if (systemUuid === "unknown" || !systemUuid) {
667
+ return `fallback-${randomUUID()}`;
668
+ }
669
+ const hash = createHash("sha256");
670
+ hash.update(systemUuid);
671
+ return hash.digest("hex").substring(0, 32);
672
+ } catch (error) {
673
+ return `fallback-${randomUUID()}`;
674
+ }
675
+ }
676
+ var ERROR_CODES = {
677
+ // Validation Errors (VAL_*)
678
+ ERR_VAL_INVALID_TEMPLATE: "ERR_VAL_INVALID_TEMPLATE",
679
+ ERR_VAL_INVALID_PKG_MANAGER: "ERR_VAL_INVALID_PKG_MANAGER",
680
+ ERR_VAL_INVALID_PROJECT_NAME: "ERR_VAL_INVALID_PROJECT_NAME",
681
+ ERR_VAL_UNSUPPORTED_NODE: "ERR_VAL_UNSUPPORTED_NODE",
682
+ ERR_VAL_NO_PKG_MANAGERS: "ERR_VAL_NO_PKG_MANAGERS",
683
+ // File System Errors (FS_*)
684
+ ERR_FS_NOT_WRITABLE: "ERR_FS_NOT_WRITABLE",
685
+ ERR_FS_HAS_CONFLICTS: "ERR_FS_HAS_CONFLICTS",
686
+ ERR_FS_MKDIR_FAILED: "ERR_FS_MKDIR_FAILED",
687
+ ERR_FS_CHDIR_FAILED: "ERR_FS_CHDIR_FAILED",
688
+ ERR_FS_READ_PACKAGE_JSON: "ERR_FS_READ_PACKAGE_JSON",
689
+ ERR_FS_WRITE_PACKAGE_JSON: "ERR_FS_WRITE_PACKAGE_JSON",
690
+ ERR_FS_UPDATE_THEME_FAILED: "ERR_FS_UPDATE_THEME_FAILED",
691
+ ERR_FS_COPY_TEMPLATE_FAILED: "ERR_FS_COPY_TEMPLATE_FAILED",
692
+ // Network Errors (NET_*)
693
+ ERR_NET_POSTHOG_CONFIG_FETCH: "ERR_NET_POSTHOG_CONFIG_FETCH",
694
+ ERR_NET_TARBALL_DOWNLOAD: "ERR_NET_TARBALL_DOWNLOAD",
695
+ ERR_NET_GITHUB_API_FAILED: "ERR_NET_GITHUB_API_FAILED",
696
+ ERR_NET_REPO_INFO_NOT_FOUND: "ERR_NET_REPO_INFO_NOT_FOUND",
697
+ ERR_NET_REPO_INVALID_URL: "ERR_NET_REPO_INVALID_URL",
698
+ ERR_NET_TARBALL_EXTRACT: "ERR_NET_TARBALL_EXTRACT",
699
+ // Installation Errors (INSTALL_*)
700
+ ERR_INSTALL_PKG_MANAGER_FAILED: "ERR_INSTALL_PKG_MANAGER_FAILED",
701
+ ERR_INSTALL_PKG_MANAGER_NOT_FOUND: "ERR_INSTALL_PKG_MANAGER_NOT_FOUND",
702
+ ERR_INSTALL_SPAWN_ERROR: "ERR_INSTALL_SPAWN_ERROR",
703
+ ERR_INSTALL_TIMEOUT: "ERR_INSTALL_TIMEOUT",
704
+ // Git Errors (GIT_*)
705
+ ERR_GIT_NOT_INSTALLED: "ERR_GIT_NOT_INSTALLED",
706
+ ERR_GIT_INIT_FAILED: "ERR_GIT_INIT_FAILED",
707
+ ERR_GIT_ADD_FAILED: "ERR_GIT_ADD_FAILED",
708
+ ERR_GIT_COMMIT_FAILED: "ERR_GIT_COMMIT_FAILED",
709
+ ERR_GIT_CHECKOUT_FAILED: "ERR_GIT_CHECKOUT_FAILED",
710
+ ERR_GIT_ALREADY_INITIALIZED: "ERR_GIT_ALREADY_INITIALIZED",
711
+ // User Cancellation (CANCEL_*)
712
+ ERR_CANCEL_PKG_MANAGER_PROMPT: "ERR_CANCEL_PKG_MANAGER_PROMPT",
713
+ ERR_CANCEL_PROJECT_NAME_PROMPT: "ERR_CANCEL_PROJECT_NAME_PROMPT",
714
+ ERR_CANCEL_TEMPLATE_PROMPT: "ERR_CANCEL_TEMPLATE_PROMPT",
715
+ ERR_CANCEL_THEME_PROMPT: "ERR_CANCEL_THEME_PROMPT",
716
+ ERR_CANCEL_SIGINT: "ERR_CANCEL_SIGINT",
717
+ // Configuration Errors (CFG_*)
718
+ ERR_CFG_POSTHOG_INIT_FAILED: "ERR_CFG_POSTHOG_INIT_FAILED",
719
+ ERR_CFG_OSINFO_FETCH_FAILED: "ERR_CFG_OSINFO_FETCH_FAILED",
720
+ ERR_CFG_TELEMETRY_SETUP_FAILED: "ERR_CFG_TELEMETRY_SETUP_FAILED",
721
+ // Template Errors (TPL_*)
722
+ ERR_TPL_DOWNLOAD_FAILED: "ERR_TPL_DOWNLOAD_FAILED",
723
+ ERR_TPL_EXTRACT_FAILED: "ERR_TPL_EXTRACT_FAILED",
724
+ ERR_TPL_METADATA_UPDATE_FAILED: "ERR_TPL_METADATA_UPDATE_FAILED",
725
+ ERR_TPL_INTERNAL_COPY_FAILED: "ERR_TPL_INTERNAL_COPY_FAILED",
726
+ ERR_TPL_THEME_UPDATE_FAILED: "ERR_TPL_THEME_UPDATE_FAILED",
727
+ // Uncategorized
728
+ ERR_UNCAUGHT: "ERR_UNCAUGHT"
729
+ };
730
+ function sanitizeStackTrace(stack) {
731
+ if (!stack) return "";
732
+ let sanitized = stack;
733
+ sanitized = sanitized.replace(/\/Users\/[^\/]+/g, "<user-home>");
734
+ sanitized = sanitized.replace(/[A-Z]:\\Users\\[^\\]+/gi, "<user-home>");
735
+ sanitized = sanitized.replace(
736
+ /.*\/(packages\/create-tina-app)\//g,
737
+ "<workspace>/$1/"
738
+ );
739
+ sanitized = sanitized.replace(
740
+ /(\/|\\)node_modules(\/|\\)/g,
741
+ "<node_modules>/"
742
+ );
743
+ sanitized = sanitized.replace(/\.npm\/_cacache/g, "<pkg-cache>");
744
+ sanitized = sanitized.replace(/\.yarn\/cache/g, "<pkg-cache>");
745
+ sanitized = sanitized.replace(/\.pnpm-store/g, "<pkg-cache>");
746
+ sanitized = sanitized.replace(/[A-Z]:\\/gi, "<drive>/");
747
+ return sanitized;
748
+ }
749
+ function truncateStackTrace(stack, maxFrames = 5) {
750
+ const lines = stack.split("\n");
751
+ const filtered = lines.filter((line) => {
752
+ if (!line.trim().startsWith("at ")) return true;
753
+ return !line.includes("node:internal") && !line.includes("node_modules/prompts") && !line.includes("node_modules/ora");
754
+ }).slice(0, maxFrames + 1);
755
+ return filtered.join("\n");
756
+ }
757
+ function createSimpleHash(str) {
758
+ let hash = 0;
759
+ for (let i = 0; i < str.length; i++) {
760
+ const char = str.charCodeAt(i);
761
+ hash = (hash << 5) - hash + char;
762
+ hash = hash & hash;
763
+ }
764
+ return Math.abs(hash).toString(36);
765
+ }
766
+ function sanitizeError(error) {
767
+ const message = error.message || "Unknown error";
768
+ const rawStack = error.stack || "";
769
+ const truncated = truncateStackTrace(rawStack);
770
+ const sanitizedStack = sanitizeStackTrace(truncated);
771
+ const stackForHash = rawStack.replace(/:\d+:\d+/g, "").replace(/\/Users\/[^\/]+/g, "").replace(/[A-Z]:\\Users\\[^\\]+/gi, "");
772
+ const originalStackHash = createSimpleHash(stackForHash);
773
+ return {
774
+ message,
775
+ sanitizedStack,
776
+ originalStackHash
777
+ };
778
+ }
779
+ function postHogCapture(client, distinctId, sessionId, event, properties) {
780
+ if (process.env.TINA_DEV === "true") return;
781
+ if (!client) {
782
+ return;
783
+ }
784
+ try {
785
+ client.capture({
786
+ distinctId,
787
+ event,
788
+ properties: {
789
+ ...properties,
790
+ sessionId,
791
+ system: "tinacms/create-tina-app"
792
+ }
793
+ });
794
+ } catch (error) {
795
+ console.error("Error capturing event:", error);
796
+ }
797
+ }
798
+ function postHogCaptureError(client, distinctId, sessionId, error, context) {
799
+ if (process.env.TINA_DEV === "true") return;
800
+ if (!client) return;
801
+ const { message, sanitizedStack, originalStackHash } = sanitizeError(error);
802
+ const {
803
+ errorCode,
804
+ errorCategory,
805
+ step,
806
+ fatal = true,
807
+ additionalProperties = {}
808
+ } = context;
809
+ let eventName;
810
+ if (errorCategory === "user-cancellation") {
811
+ eventName = "create-tina-app-user-cancelled";
812
+ } else if (errorCategory === "validation") {
813
+ eventName = "create-tina-app-validation-error";
814
+ } else {
815
+ eventName = "create-tina-app-error";
816
+ }
817
+ const properties = {
818
+ error_code: errorCode,
819
+ error_category: errorCategory,
820
+ error_message: message.substring(0, 500),
821
+ // Limit message length
822
+ sanitized_stack: sanitizedStack,
823
+ stack_hash: originalStackHash,
824
+ step,
825
+ fatal,
826
+ user_cancelled: errorCategory === "user-cancellation",
827
+ sessionId,
828
+ ...additionalProperties
829
+ };
830
+ try {
831
+ client.capture({
832
+ distinctId,
833
+ event: eventName,
834
+ properties: {
835
+ ...properties,
836
+ system: "tinacms/create-tina-app"
837
+ }
838
+ });
839
+ } catch (captureError) {
840
+ console.error("Error capturing error event:", captureError);
841
+ }
842
+ }
843
+
844
+ // src/util/fetchPosthogConfig.tsx
845
+ async function fetchPostHogConfig(endpointUrl) {
846
+ try {
847
+ const response = await fetch(endpointUrl, {
848
+ method: "GET",
849
+ headers: {
850
+ "Content-Type": "application/json"
851
+ }
852
+ });
853
+ if (!response.ok) {
854
+ throw new Error(`Failed to fetch PostHog config: ${response.statusText}`);
855
+ }
856
+ const config = await response.json();
857
+ return {
858
+ POSTHOG_API_KEY: config.api_key,
859
+ POSTHOG_ENDPOINT: config.host
860
+ };
861
+ } catch (error) {
862
+ console.warn(
863
+ `Failed to fetch PostHog config from endpoint: ${error instanceof Error ? error.message : "Unknown error"}`
864
+ );
865
+ return {};
866
+ }
867
+ }
868
+
869
+ // src/index.ts
870
+ import { osInfo as getOsSystemInfo } from "systeminformation";
871
+ var posthogClient = null;
872
+ async function initializePostHog(configEndpoint) {
873
+ let apiKey;
874
+ let endpoint;
875
+ if (configEndpoint) {
876
+ const config = await fetchPostHogConfig(configEndpoint);
877
+ apiKey = config.POSTHOG_API_KEY;
878
+ endpoint = config.POSTHOG_ENDPOINT;
879
+ }
880
+ if (!apiKey) {
881
+ console.warn(
882
+ "PostHog API key not found. PostHog tracking will be disabled."
883
+ );
884
+ return null;
885
+ }
886
+ return new PostHog(apiKey, {
887
+ host: endpoint
888
+ });
889
+ }
890
+ function formatTemplateChoice(template) {
891
+ let description = template.description || "";
892
+ if (template.features && template.features.length > 0) {
893
+ const featuresText = template.features.map((feature) => ` \u2022 ${feature.name}: ${feature.description}`).join("\n");
894
+ description = `${description}
895
+
896
+ Features:
897
+ ${featuresText}`;
898
+ }
899
+ return {
900
+ title: template.title,
901
+ value: template.value,
902
+ description
903
+ };
904
+ }
520
905
  async function run() {
521
906
  const ora = (await import("ora")).default;
522
907
  let packageManagerInstallationHadError = false;
908
+ const sessionId = generateSessionId();
909
+ const userId = await getAnonymousUserId();
523
910
  if (process.stdout.columns >= 60) {
524
911
  console.log(TextStyles.tinaOrange(`${llama}`));
525
912
  console.log(TextStyles.tinaOrange(`${tinaCms}`));
526
913
  } else {
527
914
  console.log(TextStyles.tinaOrange(`\u{1F999} TinaCMS`));
528
915
  }
529
- const version2 = require_package().version;
916
+ const require2 = createRequire(import.meta.url);
917
+ const version2 = require2("../package.json").version;
530
918
  console.log(`Create Tina App v${version2}`);
919
+ const opts = extractOptions(process.argv);
920
+ const installedPkgManagers = [];
921
+ for (const pkg_manager of PKG_MANAGERS) {
922
+ if (await checkPackageExists(pkg_manager)) {
923
+ installedPkgManagers.push(pkg_manager);
924
+ }
925
+ }
926
+ const telemetryData = {};
927
+ if (!opts.noTelemetry) {
928
+ console.log(`
929
+ ${TextStylesBold.bold("Telemetry Notice")}`);
930
+ console.log(
931
+ `To help the TinaCMS team improve the developer experience, create-tina-app collects anonymous usage statistics. This data helps us understand which environments and features are most important to support. Usage analytics may include: Operating system and version, package manager name and version (local only), Node.js version (local only), and the selected TinaCMS starter template.
932
+ No personal or project-specific code is ever collected. You can opt out at any time by passing the --noTelemetry flag.
933
+ `
934
+ );
935
+ posthogClient = await initializePostHog(
936
+ "https://identity-v2.tinajs.io/v2/posthog-token"
937
+ );
938
+ const osInfo = await getOsSystemInfo();
939
+ telemetryData["os-platform"] = osInfo.platform;
940
+ telemetryData["os-distro"] = osInfo.distro;
941
+ telemetryData["os-release"] = osInfo.release;
942
+ telemetryData["node-version"] = process.version;
943
+ for (const pkgManager2 of PKG_MANAGERS) {
944
+ telemetryData[`${pkgManager2}-installed`] = installedPkgManagers.includes(pkgManager2);
945
+ }
946
+ }
531
947
  const spinner = ora();
532
948
  preRunChecks(spinner);
533
- const opts = extractOptions(process.argv);
534
- const telemetry = new Telemetry({ disabled: opts?.noTelemetry });
949
+ postHogCapture(
950
+ posthogClient,
951
+ userId,
952
+ sessionId,
953
+ CreateTinaAppStartedEvent,
954
+ telemetryData
955
+ );
535
956
  let template = null;
536
957
  if (opts.template) {
537
958
  template = TEMPLATES.find((_template) => _template.value === opts.template);
@@ -541,6 +962,23 @@ async function run() {
541
962
  (x2) => x2.value
542
963
  )}`
543
964
  );
965
+ postHogCaptureError(
966
+ posthogClient,
967
+ userId,
968
+ sessionId,
969
+ new Error(`Invalid template: ${opts.template}`),
970
+ {
971
+ errorCode: ERROR_CODES.ERR_VAL_INVALID_TEMPLATE,
972
+ errorCategory: "validation",
973
+ step: TRACKING_STEPS.TEMPLATE_SELECT,
974
+ fatal: true,
975
+ additionalProperties: {
976
+ ...telemetryData,
977
+ provided_template: opts.template
978
+ }
979
+ }
980
+ );
981
+ if (posthogClient) await posthogClient.shutdown();
544
982
  exit(1);
545
983
  }
546
984
  }
@@ -550,20 +988,45 @@ async function run() {
550
988
  spinner.fail(
551
989
  `The provided package manager '${opts.pkgManager}' is not supported. Please provide one of the following: ${PKG_MANAGERS}`
552
990
  );
991
+ postHogCaptureError(
992
+ posthogClient,
993
+ userId,
994
+ sessionId,
995
+ new Error(`Invalid package manager: ${opts.pkgManager}`),
996
+ {
997
+ errorCode: ERROR_CODES.ERR_VAL_INVALID_PKG_MANAGER,
998
+ errorCategory: "validation",
999
+ step: TRACKING_STEPS.PKG_MANAGER_SELECT,
1000
+ fatal: true,
1001
+ additionalProperties: {
1002
+ ...telemetryData,
1003
+ provided_pkg_manager: opts.pkgManager
1004
+ }
1005
+ }
1006
+ );
1007
+ if (posthogClient) await posthogClient.shutdown();
553
1008
  exit(1);
554
1009
  }
555
1010
  }
556
1011
  if (!pkgManager) {
557
- const installedPkgManagers = [];
558
- for (const pkg_manager of PKG_MANAGERS) {
559
- if (await checkPackageExists(pkg_manager)) {
560
- installedPkgManagers.push(pkg_manager);
561
- }
562
- }
563
1012
  if (installedPkgManagers.length === 0) {
564
1013
  spinner.fail(
565
1014
  `You have no supported package managers installed. Please install one of the following: ${PKG_MANAGERS}`
566
1015
  );
1016
+ postHogCaptureError(
1017
+ posthogClient,
1018
+ userId,
1019
+ sessionId,
1020
+ new Error("No supported package managers installed"),
1021
+ {
1022
+ errorCode: ERROR_CODES.ERR_VAL_NO_PKG_MANAGERS,
1023
+ errorCategory: "validation",
1024
+ step: TRACKING_STEPS.PRE_RUN_CHECKS,
1025
+ fatal: true,
1026
+ additionalProperties: telemetryData
1027
+ }
1028
+ );
1029
+ if (posthogClient) await posthogClient.shutdown();
567
1030
  exit(1);
568
1031
  }
569
1032
  const res = await prompts({
@@ -574,8 +1037,25 @@ async function run() {
574
1037
  return { title: manager, value: manager };
575
1038
  })
576
1039
  });
577
- if (!Object.hasOwn(res, "packageManager")) exit(1);
1040
+ if (!Object.hasOwn(res, "packageManager")) {
1041
+ postHogCaptureError(
1042
+ posthogClient,
1043
+ userId,
1044
+ sessionId,
1045
+ new Error("User cancelled package manager selection"),
1046
+ {
1047
+ errorCode: ERROR_CODES.ERR_CANCEL_PKG_MANAGER_PROMPT,
1048
+ errorCategory: "user-cancellation",
1049
+ step: TRACKING_STEPS.PKG_MANAGER_SELECT,
1050
+ fatal: true,
1051
+ additionalProperties: telemetryData
1052
+ }
1053
+ );
1054
+ if (posthogClient) await posthogClient.shutdown();
1055
+ exit(1);
1056
+ }
578
1057
  pkgManager = res.packageManager;
1058
+ telemetryData["package-manager"] = pkgManager;
579
1059
  }
580
1060
  let projectName = opts.projectName;
581
1061
  if (!projectName) {
@@ -585,14 +1065,30 @@ async function run() {
585
1065
  message: "What is your project named?",
586
1066
  initial: "my-tina-app",
587
1067
  validate: (name2) => {
588
- const { validForNewPackages, errors } = validate(
589
- path4.basename(path4.resolve(name2))
1068
+ const { message, isError } = validate(
1069
+ path3.basename(path3.resolve(name2))
590
1070
  );
591
- if (validForNewPackages) return true;
592
- return `Invalid project name: ${errors[0]}`;
1071
+ if (isError) return `Invalid project name: ${message}`;
1072
+ return true;
593
1073
  }
594
1074
  });
595
- if (!Object.hasOwn(res, "name")) exit(1);
1075
+ if (!Object.hasOwn(res, "name")) {
1076
+ postHogCaptureError(
1077
+ posthogClient,
1078
+ userId,
1079
+ sessionId,
1080
+ new Error("User cancelled project name input"),
1081
+ {
1082
+ errorCode: ERROR_CODES.ERR_CANCEL_PROJECT_NAME_PROMPT,
1083
+ errorCategory: "user-cancellation",
1084
+ step: TRACKING_STEPS.PROJECT_NAME_INPUT,
1085
+ fatal: true,
1086
+ additionalProperties: telemetryData
1087
+ }
1088
+ );
1089
+ if (posthogClient) await posthogClient.shutdown();
1090
+ exit(1);
1091
+ }
596
1092
  projectName = res.name;
597
1093
  }
598
1094
  if (!template) {
@@ -600,11 +1096,28 @@ async function run() {
600
1096
  name: "template",
601
1097
  type: "select",
602
1098
  message: "What starter code would you like to use?",
603
- choices: TEMPLATES
1099
+ choices: TEMPLATES.map(formatTemplateChoice)
604
1100
  });
605
- if (!Object.hasOwn(res, "template")) exit(1);
1101
+ if (!Object.hasOwn(res, "template")) {
1102
+ postHogCaptureError(
1103
+ posthogClient,
1104
+ userId,
1105
+ sessionId,
1106
+ new Error("User cancelled template selection"),
1107
+ {
1108
+ errorCode: ERROR_CODES.ERR_CANCEL_TEMPLATE_PROMPT,
1109
+ errorCategory: "user-cancellation",
1110
+ step: TRACKING_STEPS.TEMPLATE_SELECT,
1111
+ fatal: true,
1112
+ additionalProperties: telemetryData
1113
+ }
1114
+ );
1115
+ if (posthogClient) await posthogClient.shutdown();
1116
+ exit(1);
1117
+ }
606
1118
  template = TEMPLATES.find((_template) => _template.value === res.template);
607
1119
  }
1120
+ telemetryData["template"] = template.value;
608
1121
  let themeChoice;
609
1122
  if (template.value === "tina-docs") {
610
1123
  const res = await prompts({
@@ -613,32 +1126,73 @@ async function run() {
613
1126
  message: "What theme would you like to use?",
614
1127
  choices: THEMES
615
1128
  });
616
- if (!Object.hasOwn(res, "theme")) exit(1);
1129
+ if (!Object.hasOwn(res, "theme")) {
1130
+ postHogCaptureError(
1131
+ posthogClient,
1132
+ userId,
1133
+ sessionId,
1134
+ new Error("User cancelled theme selection"),
1135
+ {
1136
+ errorCode: ERROR_CODES.ERR_CANCEL_THEME_PROMPT,
1137
+ errorCategory: "user-cancellation",
1138
+ step: TRACKING_STEPS.THEME_SELECT,
1139
+ fatal: true,
1140
+ additionalProperties: {
1141
+ ...telemetryData,
1142
+ template: template.value
1143
+ }
1144
+ }
1145
+ );
1146
+ if (posthogClient) await posthogClient.shutdown();
1147
+ exit(1);
1148
+ }
617
1149
  themeChoice = res.theme;
618
1150
  }
619
- await telemetry.submitRecord({
620
- event: {
621
- name: "create-tina-app:invoke",
622
- template: template.value,
623
- pkgManager
624
- }
625
- });
626
- const rootDir = path4.join(process.cwd(), projectName);
627
- if (!await isWriteable(path4.dirname(rootDir))) {
1151
+ const rootDir = path3.join(process.cwd(), projectName);
1152
+ if (!await isWriteable(path3.dirname(rootDir))) {
628
1153
  spinner.fail(
629
1154
  "The application path is not writable, please check folder permissions and try again. It is likely you do not have write permissions for this folder."
630
1155
  );
1156
+ postHogCaptureError(
1157
+ posthogClient,
1158
+ userId,
1159
+ sessionId,
1160
+ new Error("Directory not writable"),
1161
+ {
1162
+ errorCode: ERROR_CODES.ERR_FS_NOT_WRITABLE,
1163
+ errorCategory: "filesystem",
1164
+ step: TRACKING_STEPS.DIRECTORY_SETUP,
1165
+ fatal: true,
1166
+ additionalProperties: {
1167
+ ...telemetryData,
1168
+ template: template.value
1169
+ }
1170
+ }
1171
+ );
1172
+ if (posthogClient) await posthogClient.shutdown();
631
1173
  process.exit(1);
632
1174
  }
633
1175
  let appName;
634
1176
  try {
635
1177
  appName = await setupProjectDirectory(rootDir);
1178
+ telemetryData["app-name"] = appName;
636
1179
  } catch (err) {
637
- spinner.fail(err.message);
1180
+ const error = err;
1181
+ spinner.fail(error.message);
1182
+ postHogCaptureError(posthogClient, userId, sessionId, error, {
1183
+ errorCode: ERROR_CODES.ERR_FS_MKDIR_FAILED,
1184
+ errorCategory: "filesystem",
1185
+ step: TRACKING_STEPS.DIRECTORY_SETUP,
1186
+ fatal: true,
1187
+ additionalProperties: {
1188
+ ...telemetryData,
1189
+ template: template.value
1190
+ }
1191
+ });
1192
+ if (posthogClient) await posthogClient.shutdown();
638
1193
  exit(1);
639
1194
  }
640
1195
  try {
641
- await downloadTemplate(template, rootDir, spinner);
642
1196
  if (themeChoice) {
643
1197
  await updateThemeSettings(rootDir, themeChoice);
644
1198
  }
@@ -650,7 +1204,20 @@ async function run() {
650
1204
  updateProjectPackageVersion(rootDir, "0.0.1");
651
1205
  spinner.succeed();
652
1206
  } catch (err) {
653
- spinner.fail(`Failed to download template: ${err.message}`);
1207
+ const error = err;
1208
+ spinner.fail(`Failed to download template: ${error.message}`);
1209
+ postHogCaptureError(posthogClient, userId, sessionId, error, {
1210
+ errorCode: ERROR_CODES.ERR_TPL_DOWNLOAD_FAILED,
1211
+ errorCategory: "template",
1212
+ step: TRACKING_STEPS.DOWNLOADING_TEMPLATE,
1213
+ fatal: true,
1214
+ additionalProperties: {
1215
+ ...telemetryData,
1216
+ template: template.value,
1217
+ theme: themeChoice
1218
+ }
1219
+ });
1220
+ if (posthogClient) await posthogClient.shutdown();
654
1221
  exit(1);
655
1222
  }
656
1223
  spinner.start("Installing packages.");
@@ -658,8 +1225,20 @@ async function run() {
658
1225
  await install(pkgManager, opts.verbose);
659
1226
  spinner.succeed();
660
1227
  } catch (err) {
661
- spinner.fail(`Failed to install packages: ${err.message}`);
1228
+ const error = err;
1229
+ spinner.fail(`Failed to install packages: ${error.message}`);
662
1230
  packageManagerInstallationHadError = true;
1231
+ postHogCaptureError(posthogClient, userId, sessionId, error, {
1232
+ errorCode: ERROR_CODES.ERR_INSTALL_PKG_MANAGER_FAILED,
1233
+ errorCategory: "installation",
1234
+ step: TRACKING_STEPS.INSTALLING_PACKAGES,
1235
+ fatal: false,
1236
+ additionalProperties: {
1237
+ ...telemetryData,
1238
+ template: template.value,
1239
+ package_manager: pkgManager
1240
+ }
1241
+ });
663
1242
  }
664
1243
  spinner.start("Initializing git repository.");
665
1244
  try {
@@ -668,13 +1247,33 @@ async function run() {
668
1247
  spinner.succeed();
669
1248
  }
670
1249
  } catch (err) {
1250
+ const error = err;
671
1251
  spinner.fail("Failed to initialize Git repository, skipping.");
1252
+ postHogCaptureError(posthogClient, userId, sessionId, error, {
1253
+ errorCode: ERROR_CODES.ERR_GIT_INIT_FAILED,
1254
+ errorCategory: "git",
1255
+ step: TRACKING_STEPS.GIT_INIT,
1256
+ fatal: false,
1257
+ additionalProperties: {
1258
+ ...telemetryData,
1259
+ template: template.value
1260
+ }
1261
+ });
672
1262
  }
1263
+ postHogCapture(
1264
+ posthogClient,
1265
+ userId,
1266
+ sessionId,
1267
+ CreateTinaAppFinishedEvent,
1268
+ telemetryData
1269
+ );
673
1270
  spinner.succeed(`Created ${TextStyles.tinaOrange(appName)}
674
1271
  `);
675
1272
  if (template.value === "tina-hugo-starter") {
676
1273
  spinner.warn(
677
- `Hugo is required for this starter. Install it via ${TextStyles.link("https://gohugo.io/installation/")}
1274
+ `Hugo is required for this starter. Install it via ${TextStyles.link(
1275
+ "https://gohugo.io/installation/"
1276
+ )}
678
1277
  `
679
1278
  );
680
1279
  }
@@ -683,26 +1282,55 @@ async function run() {
683
1282
 
684
1283
  ${padCommand(`cd ${appName}`)}# move into your project directory${packageManagerInstallationHadError ? `
685
1284
  ${padCommand(`${pkgManager} install`)}# install dependencies` : ""}
686
- ${padCommand(`${pkgManager} run dev`)}# start the dev server ${TextStyles.link(template.devUrl)}
1285
+ ${padCommand(
1286
+ `${pkgManager} run dev`
1287
+ )}# start the dev server ${TextStyles.link(template.devUrl)}
687
1288
  ${padCommand(`${pkgManager} run build`)}# build the app for production
688
1289
  `);
689
1290
  console.log("Next steps:");
690
1291
  console.log(
691
- ` \u2022 \u{1F4DD} Edit some content: ${TextStyles.link("https://tina.io/docs/using-tina-editor")}`
1292
+ ` \u2022 \u{1F4DD} Edit some content: ${TextStyles.link(
1293
+ "https://tina.io/docs/using-tina-editor"
1294
+ )}`
692
1295
  );
693
1296
  console.log(
694
- ` \u2022 \u{1F4D6} Learn the basics: ${TextStyles.link("https://tina.io/docs/schema/")}`
1297
+ ` \u2022 \u{1F4D6} Learn the basics: ${TextStyles.link(
1298
+ "https://tina.io/docs/schema/"
1299
+ )}`
695
1300
  );
696
1301
  console.log(
697
- ` \u2022 \u{1F58C}\uFE0F Extend Tina with custom field components: ${TextStyles.link("https://tina.io/docs/advanced/extending-tina/")}`
1302
+ ` \u2022 \u{1F58C}\uFE0F Extend Tina with custom field components: ${TextStyles.link(
1303
+ "https://tina.io/docs/advanced/extending-tina/"
1304
+ )}`
698
1305
  );
699
1306
  console.log(
700
- ` \u2022 \u{1F680} Deploy to Production: ${TextStyles.link("https://tina.io/docs/tinacloud/")}`
1307
+ ` \u2022 \u{1F680} Deploy to Production: ${TextStyles.link(
1308
+ "https://tina.io/docs/tinacloud/"
1309
+ )}`
701
1310
  );
702
1311
  }
703
- run().catch((error) => {
1312
+ run().catch(async (error) => {
1313
+ if (process.stdout.columns >= 60) {
1314
+ console.log(TextStyles.tinaOrange(`${errorArt}`));
1315
+ }
704
1316
  console.error("Error running create-tina-app:", error);
1317
+ const sessionId = generateSessionId();
1318
+ const userId = await getAnonymousUserId();
1319
+ postHogCaptureError(posthogClient, userId, sessionId, error, {
1320
+ errorCode: ERROR_CODES.ERR_UNCAUGHT,
1321
+ errorCategory: "uncategorized",
1322
+ step: "unknown",
1323
+ fatal: true,
1324
+ additionalProperties: {}
1325
+ });
1326
+ if (posthogClient) {
1327
+ await posthogClient.shutdown();
1328
+ }
705
1329
  process.exit(1);
1330
+ }).then(async () => {
1331
+ if (posthogClient) {
1332
+ await posthogClient.shutdown();
1333
+ }
706
1334
  });
707
1335
  export {
708
1336
  run