create-tina-app 2.0.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +751 -50
- package/dist/templates.d.ts +6 -0
- package/dist/util/asciiArt.d.ts +1 -0
- package/dist/util/fetchPosthogConfig.d.ts +5 -0
- package/dist/util/isNpm.d.ts +16 -0
- package/dist/util/posthog.d.ts +147 -0
- package/dist/util/textstyles.d.ts +10 -0
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import { Telemetry } from "@tinacms/metrics";
|
|
3
2
|
import prompts from "prompts";
|
|
4
|
-
import
|
|
3
|
+
import path3 from "node:path";
|
|
5
4
|
import { createRequire } from "node:module";
|
|
6
5
|
|
|
7
6
|
// src/util/fileUtil.ts
|
|
@@ -20,6 +19,16 @@ var TextStyles = {
|
|
|
20
19
|
err: chalk.red,
|
|
21
20
|
bold: chalk.bold
|
|
22
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
|
+
};
|
|
23
32
|
|
|
24
33
|
// src/util/fileUtil.ts
|
|
25
34
|
async function isWriteable(directory) {
|
|
@@ -125,7 +134,6 @@ function install(packageManager, verboseOutput) {
|
|
|
125
134
|
|
|
126
135
|
// src/util/git.ts
|
|
127
136
|
import { execSync } from "child_process";
|
|
128
|
-
import path2 from "path";
|
|
129
137
|
import fs2 from "fs-extra";
|
|
130
138
|
function isInGitRepository() {
|
|
131
139
|
try {
|
|
@@ -144,16 +152,11 @@ function isInMercurialRepository() {
|
|
|
144
152
|
return false;
|
|
145
153
|
}
|
|
146
154
|
function makeFirstCommit(root) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
});
|
|
153
|
-
} catch (err) {
|
|
154
|
-
fs2.removeSync(path2.join(root, ".git"));
|
|
155
|
-
throw err;
|
|
156
|
-
}
|
|
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
|
+
});
|
|
157
160
|
}
|
|
158
161
|
function initializeGit(spinner) {
|
|
159
162
|
execSync("git --version", { stdio: "ignore" });
|
|
@@ -236,13 +239,27 @@ async function downloadAndExtractRepo(root, { username, name: name2, branch, fil
|
|
|
236
239
|
|
|
237
240
|
// src/templates.ts
|
|
238
241
|
import { copy } from "fs-extra";
|
|
239
|
-
import
|
|
242
|
+
import path2 from "path";
|
|
240
243
|
var TEMPLATES = [
|
|
241
244
|
{
|
|
242
245
|
title: "\u2B50 NextJS starter",
|
|
243
246
|
description: "Kickstart your project with Next.js \u2013 our top recommendation for a seamless, performant, and versatile web experience.",
|
|
244
247
|
value: "tina-nextjs-starter",
|
|
245
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
|
+
],
|
|
246
263
|
gitURL: "https://github.com/tinacms/tina-nextjs-starter",
|
|
247
264
|
devUrl: "http://localhost:3000"
|
|
248
265
|
},
|
|
@@ -251,6 +268,20 @@ var TEMPLATES = [
|
|
|
251
268
|
description: "Get your documentation site up and running with TinaCMS and Next.js in minutes.",
|
|
252
269
|
value: "tina-docs",
|
|
253
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
|
+
],
|
|
254
285
|
gitURL: "https://github.com/tinacms/tina-docs",
|
|
255
286
|
devUrl: "http://localhost:3000"
|
|
256
287
|
},
|
|
@@ -259,6 +290,20 @@ var TEMPLATES = [
|
|
|
259
290
|
description: "Get started with Astro - a modern static site generator designed for fast, lightweight, and flexible web projects.",
|
|
260
291
|
value: "tina-astro-starter",
|
|
261
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
|
+
],
|
|
262
307
|
gitURL: "https://github.com/tinacms/tina-astro-starter",
|
|
263
308
|
devUrl: "http://localhost:4321"
|
|
264
309
|
},
|
|
@@ -267,6 +312,20 @@ var TEMPLATES = [
|
|
|
267
312
|
description: "With Hugo, you wield the power of lightning-fast site generation, crafting web experiences at the speed of thought.",
|
|
268
313
|
value: "tina-hugo-starter",
|
|
269
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
|
+
],
|
|
270
329
|
gitURL: "https://github.com/tinacms/tina-hugo-starter",
|
|
271
330
|
devUrl: "http://localhost:1313"
|
|
272
331
|
},
|
|
@@ -275,6 +334,20 @@ var TEMPLATES = [
|
|
|
275
334
|
description: "Dive into Remix to orchestrate seamless, interactive user journeys like a maestro of the web.",
|
|
276
335
|
value: "tina-remix-starter",
|
|
277
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
|
+
],
|
|
278
351
|
gitURL: "https://github.com/tinacms/tina-remix-starter",
|
|
279
352
|
devUrl: "http://localhost:3000"
|
|
280
353
|
},
|
|
@@ -283,14 +356,42 @@ var TEMPLATES = [
|
|
|
283
356
|
description: "Docusaurus empowers you to build and evolve documentation like crafting a living, breathing knowledge repository.",
|
|
284
357
|
value: "tinasaurus",
|
|
285
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
|
+
],
|
|
286
373
|
gitURL: "https://github.com/tinacms/tinasaurus",
|
|
287
374
|
devUrl: "http://localhost:3000"
|
|
288
375
|
},
|
|
289
376
|
{
|
|
290
377
|
title: "Bare bones starter",
|
|
291
|
-
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.",
|
|
292
379
|
value: "basic",
|
|
293
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
|
+
],
|
|
294
395
|
gitURL: "https://github.com/tinacms/tina-barebones-starter",
|
|
295
396
|
devUrl: "http://localhost:3000"
|
|
296
397
|
}
|
|
@@ -307,7 +408,7 @@ async function downloadTemplate(template, root, spinner) {
|
|
|
307
408
|
)}`;
|
|
308
409
|
await downloadAndExtractRepo(root, repoInfo);
|
|
309
410
|
} else {
|
|
310
|
-
const templateFile =
|
|
411
|
+
const templateFile = path2.join(__dirname, "..", "examples", template.value);
|
|
311
412
|
await copy(`${templateFile}/`, "./");
|
|
312
413
|
}
|
|
313
414
|
}
|
|
@@ -357,7 +458,7 @@ import { Command } from "commander";
|
|
|
357
458
|
|
|
358
459
|
// package.json
|
|
359
460
|
var name = "create-tina-app";
|
|
360
|
-
var version = "2.
|
|
461
|
+
var version = "2.1.1";
|
|
361
462
|
|
|
362
463
|
// src/util/packageManagers.ts
|
|
363
464
|
var PKG_MANAGERS = ["npm", "yarn", "pnpm", "bun"];
|
|
@@ -391,11 +492,111 @@ function extractOptions(args) {
|
|
|
391
492
|
return opts;
|
|
392
493
|
}
|
|
393
494
|
|
|
394
|
-
// src/
|
|
395
|
-
import
|
|
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
|
+
}
|
|
396
596
|
|
|
397
597
|
// src/util/asciiArt.ts
|
|
398
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 ";
|
|
399
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";
|
|
400
601
|
|
|
401
602
|
// src/themes.ts
|
|
@@ -433,9 +634,280 @@ var THEMES = [
|
|
|
433
634
|
];
|
|
434
635
|
|
|
435
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, disableGeoip) {
|
|
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
|
+
disableGeoip: disableGeoip ?? true
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
function formatTemplateChoice(template) {
|
|
892
|
+
let description = template.description || "";
|
|
893
|
+
if (template.features && template.features.length > 0) {
|
|
894
|
+
const featuresText = template.features.map((feature) => ` \u2022 ${feature.name}: ${feature.description}`).join("\n");
|
|
895
|
+
description = `${description}
|
|
896
|
+
|
|
897
|
+
Features:
|
|
898
|
+
${featuresText}`;
|
|
899
|
+
}
|
|
900
|
+
return {
|
|
901
|
+
title: template.title,
|
|
902
|
+
value: template.value,
|
|
903
|
+
description
|
|
904
|
+
};
|
|
905
|
+
}
|
|
436
906
|
async function run() {
|
|
437
907
|
const ora = (await import("ora")).default;
|
|
438
908
|
let packageManagerInstallationHadError = false;
|
|
909
|
+
const sessionId = generateSessionId();
|
|
910
|
+
const userId = await getAnonymousUserId();
|
|
439
911
|
if (process.stdout.columns >= 60) {
|
|
440
912
|
console.log(TextStyles.tinaOrange(`${llama}`));
|
|
441
913
|
console.log(TextStyles.tinaOrange(`${tinaCms}`));
|
|
@@ -445,10 +917,44 @@ async function run() {
|
|
|
445
917
|
const require2 = createRequire(import.meta.url);
|
|
446
918
|
const version2 = require2("../package.json").version;
|
|
447
919
|
console.log(`Create Tina App v${version2}`);
|
|
920
|
+
const opts = extractOptions(process.argv);
|
|
921
|
+
const installedPkgManagers = [];
|
|
922
|
+
for (const pkg_manager of PKG_MANAGERS) {
|
|
923
|
+
if (await checkPackageExists(pkg_manager)) {
|
|
924
|
+
installedPkgManagers.push(pkg_manager);
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
const telemetryData = {};
|
|
928
|
+
if (!opts.noTelemetry) {
|
|
929
|
+
console.log(`
|
|
930
|
+
${TextStylesBold.bold("Telemetry Notice")}`);
|
|
931
|
+
console.log(
|
|
932
|
+
`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.
|
|
933
|
+
No personal or project-specific code is ever collected. You can opt out at any time by passing the --noTelemetry flag.
|
|
934
|
+
`
|
|
935
|
+
);
|
|
936
|
+
posthogClient = await initializePostHog(
|
|
937
|
+
"https://identity-v2.tinajs.io/v2/posthog-token",
|
|
938
|
+
false
|
|
939
|
+
);
|
|
940
|
+
const osInfo = await getOsSystemInfo();
|
|
941
|
+
telemetryData["os-platform"] = osInfo.platform;
|
|
942
|
+
telemetryData["os-distro"] = osInfo.distro;
|
|
943
|
+
telemetryData["os-release"] = osInfo.release;
|
|
944
|
+
telemetryData["node-version"] = process.version;
|
|
945
|
+
for (const pkgManager2 of PKG_MANAGERS) {
|
|
946
|
+
telemetryData[`${pkgManager2}-installed`] = installedPkgManagers.includes(pkgManager2);
|
|
947
|
+
}
|
|
948
|
+
}
|
|
448
949
|
const spinner = ora();
|
|
449
950
|
preRunChecks(spinner);
|
|
450
|
-
|
|
451
|
-
|
|
951
|
+
postHogCapture(
|
|
952
|
+
posthogClient,
|
|
953
|
+
userId,
|
|
954
|
+
sessionId,
|
|
955
|
+
CreateTinaAppStartedEvent,
|
|
956
|
+
telemetryData
|
|
957
|
+
);
|
|
452
958
|
let template = null;
|
|
453
959
|
if (opts.template) {
|
|
454
960
|
template = TEMPLATES.find((_template) => _template.value === opts.template);
|
|
@@ -458,6 +964,23 @@ async function run() {
|
|
|
458
964
|
(x2) => x2.value
|
|
459
965
|
)}`
|
|
460
966
|
);
|
|
967
|
+
postHogCaptureError(
|
|
968
|
+
posthogClient,
|
|
969
|
+
userId,
|
|
970
|
+
sessionId,
|
|
971
|
+
new Error(`Invalid template: ${opts.template}`),
|
|
972
|
+
{
|
|
973
|
+
errorCode: ERROR_CODES.ERR_VAL_INVALID_TEMPLATE,
|
|
974
|
+
errorCategory: "validation",
|
|
975
|
+
step: TRACKING_STEPS.TEMPLATE_SELECT,
|
|
976
|
+
fatal: true,
|
|
977
|
+
additionalProperties: {
|
|
978
|
+
...telemetryData,
|
|
979
|
+
provided_template: opts.template
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
);
|
|
983
|
+
if (posthogClient) await posthogClient.shutdown();
|
|
461
984
|
exit(1);
|
|
462
985
|
}
|
|
463
986
|
}
|
|
@@ -467,20 +990,45 @@ async function run() {
|
|
|
467
990
|
spinner.fail(
|
|
468
991
|
`The provided package manager '${opts.pkgManager}' is not supported. Please provide one of the following: ${PKG_MANAGERS}`
|
|
469
992
|
);
|
|
993
|
+
postHogCaptureError(
|
|
994
|
+
posthogClient,
|
|
995
|
+
userId,
|
|
996
|
+
sessionId,
|
|
997
|
+
new Error(`Invalid package manager: ${opts.pkgManager}`),
|
|
998
|
+
{
|
|
999
|
+
errorCode: ERROR_CODES.ERR_VAL_INVALID_PKG_MANAGER,
|
|
1000
|
+
errorCategory: "validation",
|
|
1001
|
+
step: TRACKING_STEPS.PKG_MANAGER_SELECT,
|
|
1002
|
+
fatal: true,
|
|
1003
|
+
additionalProperties: {
|
|
1004
|
+
...telemetryData,
|
|
1005
|
+
provided_pkg_manager: opts.pkgManager
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
);
|
|
1009
|
+
if (posthogClient) await posthogClient.shutdown();
|
|
470
1010
|
exit(1);
|
|
471
1011
|
}
|
|
472
1012
|
}
|
|
473
1013
|
if (!pkgManager) {
|
|
474
|
-
const installedPkgManagers = [];
|
|
475
|
-
for (const pkg_manager of PKG_MANAGERS) {
|
|
476
|
-
if (await checkPackageExists(pkg_manager)) {
|
|
477
|
-
installedPkgManagers.push(pkg_manager);
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
1014
|
if (installedPkgManagers.length === 0) {
|
|
481
1015
|
spinner.fail(
|
|
482
1016
|
`You have no supported package managers installed. Please install one of the following: ${PKG_MANAGERS}`
|
|
483
1017
|
);
|
|
1018
|
+
postHogCaptureError(
|
|
1019
|
+
posthogClient,
|
|
1020
|
+
userId,
|
|
1021
|
+
sessionId,
|
|
1022
|
+
new Error("No supported package managers installed"),
|
|
1023
|
+
{
|
|
1024
|
+
errorCode: ERROR_CODES.ERR_VAL_NO_PKG_MANAGERS,
|
|
1025
|
+
errorCategory: "validation",
|
|
1026
|
+
step: TRACKING_STEPS.PRE_RUN_CHECKS,
|
|
1027
|
+
fatal: true,
|
|
1028
|
+
additionalProperties: telemetryData
|
|
1029
|
+
}
|
|
1030
|
+
);
|
|
1031
|
+
if (posthogClient) await posthogClient.shutdown();
|
|
484
1032
|
exit(1);
|
|
485
1033
|
}
|
|
486
1034
|
const res = await prompts({
|
|
@@ -491,8 +1039,25 @@ async function run() {
|
|
|
491
1039
|
return { title: manager, value: manager };
|
|
492
1040
|
})
|
|
493
1041
|
});
|
|
494
|
-
if (!Object.hasOwn(res, "packageManager"))
|
|
1042
|
+
if (!Object.hasOwn(res, "packageManager")) {
|
|
1043
|
+
postHogCaptureError(
|
|
1044
|
+
posthogClient,
|
|
1045
|
+
userId,
|
|
1046
|
+
sessionId,
|
|
1047
|
+
new Error("User cancelled package manager selection"),
|
|
1048
|
+
{
|
|
1049
|
+
errorCode: ERROR_CODES.ERR_CANCEL_PKG_MANAGER_PROMPT,
|
|
1050
|
+
errorCategory: "user-cancellation",
|
|
1051
|
+
step: TRACKING_STEPS.PKG_MANAGER_SELECT,
|
|
1052
|
+
fatal: true,
|
|
1053
|
+
additionalProperties: telemetryData
|
|
1054
|
+
}
|
|
1055
|
+
);
|
|
1056
|
+
if (posthogClient) await posthogClient.shutdown();
|
|
1057
|
+
exit(1);
|
|
1058
|
+
}
|
|
495
1059
|
pkgManager = res.packageManager;
|
|
1060
|
+
telemetryData["package-manager"] = pkgManager;
|
|
496
1061
|
}
|
|
497
1062
|
let projectName = opts.projectName;
|
|
498
1063
|
if (!projectName) {
|
|
@@ -502,14 +1067,30 @@ async function run() {
|
|
|
502
1067
|
message: "What is your project named?",
|
|
503
1068
|
initial: "my-tina-app",
|
|
504
1069
|
validate: (name2) => {
|
|
505
|
-
const {
|
|
506
|
-
|
|
1070
|
+
const { message, isError } = validate(
|
|
1071
|
+
path3.basename(path3.resolve(name2))
|
|
507
1072
|
);
|
|
508
|
-
if (
|
|
509
|
-
return
|
|
1073
|
+
if (isError) return `Invalid project name: ${message}`;
|
|
1074
|
+
return true;
|
|
510
1075
|
}
|
|
511
1076
|
});
|
|
512
|
-
if (!Object.hasOwn(res, "name"))
|
|
1077
|
+
if (!Object.hasOwn(res, "name")) {
|
|
1078
|
+
postHogCaptureError(
|
|
1079
|
+
posthogClient,
|
|
1080
|
+
userId,
|
|
1081
|
+
sessionId,
|
|
1082
|
+
new Error("User cancelled project name input"),
|
|
1083
|
+
{
|
|
1084
|
+
errorCode: ERROR_CODES.ERR_CANCEL_PROJECT_NAME_PROMPT,
|
|
1085
|
+
errorCategory: "user-cancellation",
|
|
1086
|
+
step: TRACKING_STEPS.PROJECT_NAME_INPUT,
|
|
1087
|
+
fatal: true,
|
|
1088
|
+
additionalProperties: telemetryData
|
|
1089
|
+
}
|
|
1090
|
+
);
|
|
1091
|
+
if (posthogClient) await posthogClient.shutdown();
|
|
1092
|
+
exit(1);
|
|
1093
|
+
}
|
|
513
1094
|
projectName = res.name;
|
|
514
1095
|
}
|
|
515
1096
|
if (!template) {
|
|
@@ -517,11 +1098,28 @@ async function run() {
|
|
|
517
1098
|
name: "template",
|
|
518
1099
|
type: "select",
|
|
519
1100
|
message: "What starter code would you like to use?",
|
|
520
|
-
choices: TEMPLATES
|
|
1101
|
+
choices: TEMPLATES.map(formatTemplateChoice)
|
|
521
1102
|
});
|
|
522
|
-
if (!Object.hasOwn(res, "template"))
|
|
1103
|
+
if (!Object.hasOwn(res, "template")) {
|
|
1104
|
+
postHogCaptureError(
|
|
1105
|
+
posthogClient,
|
|
1106
|
+
userId,
|
|
1107
|
+
sessionId,
|
|
1108
|
+
new Error("User cancelled template selection"),
|
|
1109
|
+
{
|
|
1110
|
+
errorCode: ERROR_CODES.ERR_CANCEL_TEMPLATE_PROMPT,
|
|
1111
|
+
errorCategory: "user-cancellation",
|
|
1112
|
+
step: TRACKING_STEPS.TEMPLATE_SELECT,
|
|
1113
|
+
fatal: true,
|
|
1114
|
+
additionalProperties: telemetryData
|
|
1115
|
+
}
|
|
1116
|
+
);
|
|
1117
|
+
if (posthogClient) await posthogClient.shutdown();
|
|
1118
|
+
exit(1);
|
|
1119
|
+
}
|
|
523
1120
|
template = TEMPLATES.find((_template) => _template.value === res.template);
|
|
524
1121
|
}
|
|
1122
|
+
telemetryData["template"] = template.value;
|
|
525
1123
|
let themeChoice;
|
|
526
1124
|
if (template.value === "tina-docs") {
|
|
527
1125
|
const res = await prompts({
|
|
@@ -530,32 +1128,73 @@ async function run() {
|
|
|
530
1128
|
message: "What theme would you like to use?",
|
|
531
1129
|
choices: THEMES
|
|
532
1130
|
});
|
|
533
|
-
if (!Object.hasOwn(res, "theme"))
|
|
1131
|
+
if (!Object.hasOwn(res, "theme")) {
|
|
1132
|
+
postHogCaptureError(
|
|
1133
|
+
posthogClient,
|
|
1134
|
+
userId,
|
|
1135
|
+
sessionId,
|
|
1136
|
+
new Error("User cancelled theme selection"),
|
|
1137
|
+
{
|
|
1138
|
+
errorCode: ERROR_CODES.ERR_CANCEL_THEME_PROMPT,
|
|
1139
|
+
errorCategory: "user-cancellation",
|
|
1140
|
+
step: TRACKING_STEPS.THEME_SELECT,
|
|
1141
|
+
fatal: true,
|
|
1142
|
+
additionalProperties: {
|
|
1143
|
+
...telemetryData,
|
|
1144
|
+
template: template.value
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
);
|
|
1148
|
+
if (posthogClient) await posthogClient.shutdown();
|
|
1149
|
+
exit(1);
|
|
1150
|
+
}
|
|
534
1151
|
themeChoice = res.theme;
|
|
535
1152
|
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
name: "create-tina-app:invoke",
|
|
539
|
-
template: template.value,
|
|
540
|
-
pkgManager
|
|
541
|
-
}
|
|
542
|
-
});
|
|
543
|
-
const rootDir = path4.join(process.cwd(), projectName);
|
|
544
|
-
if (!await isWriteable(path4.dirname(rootDir))) {
|
|
1153
|
+
const rootDir = path3.join(process.cwd(), projectName);
|
|
1154
|
+
if (!await isWriteable(path3.dirname(rootDir))) {
|
|
545
1155
|
spinner.fail(
|
|
546
1156
|
"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."
|
|
547
1157
|
);
|
|
1158
|
+
postHogCaptureError(
|
|
1159
|
+
posthogClient,
|
|
1160
|
+
userId,
|
|
1161
|
+
sessionId,
|
|
1162
|
+
new Error("Directory not writable"),
|
|
1163
|
+
{
|
|
1164
|
+
errorCode: ERROR_CODES.ERR_FS_NOT_WRITABLE,
|
|
1165
|
+
errorCategory: "filesystem",
|
|
1166
|
+
step: TRACKING_STEPS.DIRECTORY_SETUP,
|
|
1167
|
+
fatal: true,
|
|
1168
|
+
additionalProperties: {
|
|
1169
|
+
...telemetryData,
|
|
1170
|
+
template: template.value
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
);
|
|
1174
|
+
if (posthogClient) await posthogClient.shutdown();
|
|
548
1175
|
process.exit(1);
|
|
549
1176
|
}
|
|
550
1177
|
let appName;
|
|
551
1178
|
try {
|
|
552
1179
|
appName = await setupProjectDirectory(rootDir);
|
|
1180
|
+
telemetryData["app-name"] = appName;
|
|
553
1181
|
} catch (err) {
|
|
554
|
-
|
|
1182
|
+
const error = err;
|
|
1183
|
+
spinner.fail(error.message);
|
|
1184
|
+
postHogCaptureError(posthogClient, userId, sessionId, error, {
|
|
1185
|
+
errorCode: ERROR_CODES.ERR_FS_MKDIR_FAILED,
|
|
1186
|
+
errorCategory: "filesystem",
|
|
1187
|
+
step: TRACKING_STEPS.DIRECTORY_SETUP,
|
|
1188
|
+
fatal: true,
|
|
1189
|
+
additionalProperties: {
|
|
1190
|
+
...telemetryData,
|
|
1191
|
+
template: template.value
|
|
1192
|
+
}
|
|
1193
|
+
});
|
|
1194
|
+
if (posthogClient) await posthogClient.shutdown();
|
|
555
1195
|
exit(1);
|
|
556
1196
|
}
|
|
557
1197
|
try {
|
|
558
|
-
await downloadTemplate(template, rootDir, spinner);
|
|
559
1198
|
if (themeChoice) {
|
|
560
1199
|
await updateThemeSettings(rootDir, themeChoice);
|
|
561
1200
|
}
|
|
@@ -567,7 +1206,20 @@ async function run() {
|
|
|
567
1206
|
updateProjectPackageVersion(rootDir, "0.0.1");
|
|
568
1207
|
spinner.succeed();
|
|
569
1208
|
} catch (err) {
|
|
570
|
-
|
|
1209
|
+
const error = err;
|
|
1210
|
+
spinner.fail(`Failed to download template: ${error.message}`);
|
|
1211
|
+
postHogCaptureError(posthogClient, userId, sessionId, error, {
|
|
1212
|
+
errorCode: ERROR_CODES.ERR_TPL_DOWNLOAD_FAILED,
|
|
1213
|
+
errorCategory: "template",
|
|
1214
|
+
step: TRACKING_STEPS.DOWNLOADING_TEMPLATE,
|
|
1215
|
+
fatal: true,
|
|
1216
|
+
additionalProperties: {
|
|
1217
|
+
...telemetryData,
|
|
1218
|
+
template: template.value,
|
|
1219
|
+
theme: themeChoice
|
|
1220
|
+
}
|
|
1221
|
+
});
|
|
1222
|
+
if (posthogClient) await posthogClient.shutdown();
|
|
571
1223
|
exit(1);
|
|
572
1224
|
}
|
|
573
1225
|
spinner.start("Installing packages.");
|
|
@@ -575,8 +1227,20 @@ async function run() {
|
|
|
575
1227
|
await install(pkgManager, opts.verbose);
|
|
576
1228
|
spinner.succeed();
|
|
577
1229
|
} catch (err) {
|
|
578
|
-
|
|
1230
|
+
const error = err;
|
|
1231
|
+
spinner.fail(`Failed to install packages: ${error.message}`);
|
|
579
1232
|
packageManagerInstallationHadError = true;
|
|
1233
|
+
postHogCaptureError(posthogClient, userId, sessionId, error, {
|
|
1234
|
+
errorCode: ERROR_CODES.ERR_INSTALL_PKG_MANAGER_FAILED,
|
|
1235
|
+
errorCategory: "installation",
|
|
1236
|
+
step: TRACKING_STEPS.INSTALLING_PACKAGES,
|
|
1237
|
+
fatal: false,
|
|
1238
|
+
additionalProperties: {
|
|
1239
|
+
...telemetryData,
|
|
1240
|
+
template: template.value,
|
|
1241
|
+
package_manager: pkgManager
|
|
1242
|
+
}
|
|
1243
|
+
});
|
|
580
1244
|
}
|
|
581
1245
|
spinner.start("Initializing git repository.");
|
|
582
1246
|
try {
|
|
@@ -585,8 +1249,26 @@ async function run() {
|
|
|
585
1249
|
spinner.succeed();
|
|
586
1250
|
}
|
|
587
1251
|
} catch (err) {
|
|
1252
|
+
const error = err;
|
|
588
1253
|
spinner.fail("Failed to initialize Git repository, skipping.");
|
|
1254
|
+
postHogCaptureError(posthogClient, userId, sessionId, error, {
|
|
1255
|
+
errorCode: ERROR_CODES.ERR_GIT_INIT_FAILED,
|
|
1256
|
+
errorCategory: "git",
|
|
1257
|
+
step: TRACKING_STEPS.GIT_INIT,
|
|
1258
|
+
fatal: false,
|
|
1259
|
+
additionalProperties: {
|
|
1260
|
+
...telemetryData,
|
|
1261
|
+
template: template.value
|
|
1262
|
+
}
|
|
1263
|
+
});
|
|
589
1264
|
}
|
|
1265
|
+
postHogCapture(
|
|
1266
|
+
posthogClient,
|
|
1267
|
+
userId,
|
|
1268
|
+
sessionId,
|
|
1269
|
+
CreateTinaAppFinishedEvent,
|
|
1270
|
+
telemetryData
|
|
1271
|
+
);
|
|
590
1272
|
spinner.succeed(`Created ${TextStyles.tinaOrange(appName)}
|
|
591
1273
|
`);
|
|
592
1274
|
if (template.value === "tina-hugo-starter") {
|
|
@@ -629,9 +1311,28 @@ async function run() {
|
|
|
629
1311
|
)}`
|
|
630
1312
|
);
|
|
631
1313
|
}
|
|
632
|
-
run().catch((error) => {
|
|
1314
|
+
run().catch(async (error) => {
|
|
1315
|
+
if (process.stdout.columns >= 60) {
|
|
1316
|
+
console.log(TextStyles.tinaOrange(`${errorArt}`));
|
|
1317
|
+
}
|
|
633
1318
|
console.error("Error running create-tina-app:", error);
|
|
1319
|
+
const sessionId = generateSessionId();
|
|
1320
|
+
const userId = await getAnonymousUserId();
|
|
1321
|
+
postHogCaptureError(posthogClient, userId, sessionId, error, {
|
|
1322
|
+
errorCode: ERROR_CODES.ERR_UNCAUGHT,
|
|
1323
|
+
errorCategory: "uncategorized",
|
|
1324
|
+
step: "unknown",
|
|
1325
|
+
fatal: true,
|
|
1326
|
+
additionalProperties: {}
|
|
1327
|
+
});
|
|
1328
|
+
if (posthogClient) {
|
|
1329
|
+
await posthogClient.shutdown();
|
|
1330
|
+
}
|
|
634
1331
|
process.exit(1);
|
|
1332
|
+
}).then(async () => {
|
|
1333
|
+
if (posthogClient) {
|
|
1334
|
+
await posthogClient.shutdown();
|
|
1335
|
+
}
|
|
635
1336
|
});
|
|
636
1337
|
export {
|
|
637
1338
|
run
|
package/dist/templates.d.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { Ora } from 'ora';
|
|
2
|
+
type Feature = {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
};
|
|
2
6
|
export type BaseExample = {
|
|
3
7
|
title: string;
|
|
4
8
|
description?: string;
|
|
9
|
+
features?: Feature[];
|
|
5
10
|
value: string;
|
|
6
11
|
devUrl: string;
|
|
7
12
|
};
|
|
@@ -15,3 +20,4 @@ export type ExternalTemplate = BaseExample & {
|
|
|
15
20
|
export type Template = InternalTemplate | ExternalTemplate;
|
|
16
21
|
export declare const TEMPLATES: Template[];
|
|
17
22
|
export declare function downloadTemplate(template: Template, root: string, spinner: Ora): Promise<void>;
|
|
23
|
+
export {};
|
package/dist/util/asciiArt.d.ts
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {Object} ValidationResult
|
|
3
|
+
* @property {string | null} message
|
|
4
|
+
* @property {boolean} isError
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Validates whether the provided name is valid on NPM.
|
|
8
|
+
*
|
|
9
|
+
* @param {string} name
|
|
10
|
+
* @returns {ValidationResult}
|
|
11
|
+
*/
|
|
12
|
+
export default function validate(name: string): ValidationResult;
|
|
13
|
+
export type ValidationResult = {
|
|
14
|
+
message: string | null;
|
|
15
|
+
isError: boolean;
|
|
16
|
+
};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { PostHog } from 'posthog-node';
|
|
2
|
+
export declare const CreateTinaAppStartedEvent: string;
|
|
3
|
+
export declare const CreateTinaAppFinishedEvent: string;
|
|
4
|
+
/**
|
|
5
|
+
* Step names for tracking progress through the create-tina-app process
|
|
6
|
+
*/
|
|
7
|
+
export declare const TRACKING_STEPS: {
|
|
8
|
+
readonly INIT: "initializing";
|
|
9
|
+
readonly PRE_RUN_CHECKS: "pre_run_checks";
|
|
10
|
+
readonly TELEMETRY_SETUP: "telemetry_setup";
|
|
11
|
+
readonly PKG_MANAGER_SELECT: "package_manager_selection";
|
|
12
|
+
readonly PROJECT_NAME_INPUT: "project_name_input";
|
|
13
|
+
readonly TEMPLATE_SELECT: "template_selection";
|
|
14
|
+
readonly THEME_SELECT: "theme_selection";
|
|
15
|
+
readonly DIRECTORY_SETUP: "directory_setup";
|
|
16
|
+
readonly DOWNLOADING_TEMPLATE: "downloading_template";
|
|
17
|
+
readonly UPDATING_METADATA: "updating_metadata";
|
|
18
|
+
readonly INSTALLING_PACKAGES: "installing_packages";
|
|
19
|
+
readonly GIT_INIT: "git_initialization";
|
|
20
|
+
readonly COMPLETE: "complete";
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Generate a unique session ID for this run
|
|
24
|
+
*/
|
|
25
|
+
export declare function generateSessionId(): string;
|
|
26
|
+
/**
|
|
27
|
+
* Get a hashed user ID based on system UUID
|
|
28
|
+
* Returns a consistent anonymous identifier for the machine
|
|
29
|
+
*/
|
|
30
|
+
export declare function getAnonymousUserId(): Promise<string>;
|
|
31
|
+
/**
|
|
32
|
+
* Structured error codes for categorizing failures
|
|
33
|
+
*/
|
|
34
|
+
export declare const ERROR_CODES: {
|
|
35
|
+
readonly ERR_VAL_INVALID_TEMPLATE: "ERR_VAL_INVALID_TEMPLATE";
|
|
36
|
+
readonly ERR_VAL_INVALID_PKG_MANAGER: "ERR_VAL_INVALID_PKG_MANAGER";
|
|
37
|
+
readonly ERR_VAL_INVALID_PROJECT_NAME: "ERR_VAL_INVALID_PROJECT_NAME";
|
|
38
|
+
readonly ERR_VAL_UNSUPPORTED_NODE: "ERR_VAL_UNSUPPORTED_NODE";
|
|
39
|
+
readonly ERR_VAL_NO_PKG_MANAGERS: "ERR_VAL_NO_PKG_MANAGERS";
|
|
40
|
+
readonly ERR_FS_NOT_WRITABLE: "ERR_FS_NOT_WRITABLE";
|
|
41
|
+
readonly ERR_FS_HAS_CONFLICTS: "ERR_FS_HAS_CONFLICTS";
|
|
42
|
+
readonly ERR_FS_MKDIR_FAILED: "ERR_FS_MKDIR_FAILED";
|
|
43
|
+
readonly ERR_FS_CHDIR_FAILED: "ERR_FS_CHDIR_FAILED";
|
|
44
|
+
readonly ERR_FS_READ_PACKAGE_JSON: "ERR_FS_READ_PACKAGE_JSON";
|
|
45
|
+
readonly ERR_FS_WRITE_PACKAGE_JSON: "ERR_FS_WRITE_PACKAGE_JSON";
|
|
46
|
+
readonly ERR_FS_UPDATE_THEME_FAILED: "ERR_FS_UPDATE_THEME_FAILED";
|
|
47
|
+
readonly ERR_FS_COPY_TEMPLATE_FAILED: "ERR_FS_COPY_TEMPLATE_FAILED";
|
|
48
|
+
readonly ERR_NET_POSTHOG_CONFIG_FETCH: "ERR_NET_POSTHOG_CONFIG_FETCH";
|
|
49
|
+
readonly ERR_NET_TARBALL_DOWNLOAD: "ERR_NET_TARBALL_DOWNLOAD";
|
|
50
|
+
readonly ERR_NET_GITHUB_API_FAILED: "ERR_NET_GITHUB_API_FAILED";
|
|
51
|
+
readonly ERR_NET_REPO_INFO_NOT_FOUND: "ERR_NET_REPO_INFO_NOT_FOUND";
|
|
52
|
+
readonly ERR_NET_REPO_INVALID_URL: "ERR_NET_REPO_INVALID_URL";
|
|
53
|
+
readonly ERR_NET_TARBALL_EXTRACT: "ERR_NET_TARBALL_EXTRACT";
|
|
54
|
+
readonly ERR_INSTALL_PKG_MANAGER_FAILED: "ERR_INSTALL_PKG_MANAGER_FAILED";
|
|
55
|
+
readonly ERR_INSTALL_PKG_MANAGER_NOT_FOUND: "ERR_INSTALL_PKG_MANAGER_NOT_FOUND";
|
|
56
|
+
readonly ERR_INSTALL_SPAWN_ERROR: "ERR_INSTALL_SPAWN_ERROR";
|
|
57
|
+
readonly ERR_INSTALL_TIMEOUT: "ERR_INSTALL_TIMEOUT";
|
|
58
|
+
readonly ERR_GIT_NOT_INSTALLED: "ERR_GIT_NOT_INSTALLED";
|
|
59
|
+
readonly ERR_GIT_INIT_FAILED: "ERR_GIT_INIT_FAILED";
|
|
60
|
+
readonly ERR_GIT_ADD_FAILED: "ERR_GIT_ADD_FAILED";
|
|
61
|
+
readonly ERR_GIT_COMMIT_FAILED: "ERR_GIT_COMMIT_FAILED";
|
|
62
|
+
readonly ERR_GIT_CHECKOUT_FAILED: "ERR_GIT_CHECKOUT_FAILED";
|
|
63
|
+
readonly ERR_GIT_ALREADY_INITIALIZED: "ERR_GIT_ALREADY_INITIALIZED";
|
|
64
|
+
readonly ERR_CANCEL_PKG_MANAGER_PROMPT: "ERR_CANCEL_PKG_MANAGER_PROMPT";
|
|
65
|
+
readonly ERR_CANCEL_PROJECT_NAME_PROMPT: "ERR_CANCEL_PROJECT_NAME_PROMPT";
|
|
66
|
+
readonly ERR_CANCEL_TEMPLATE_PROMPT: "ERR_CANCEL_TEMPLATE_PROMPT";
|
|
67
|
+
readonly ERR_CANCEL_THEME_PROMPT: "ERR_CANCEL_THEME_PROMPT";
|
|
68
|
+
readonly ERR_CANCEL_SIGINT: "ERR_CANCEL_SIGINT";
|
|
69
|
+
readonly ERR_CFG_POSTHOG_INIT_FAILED: "ERR_CFG_POSTHOG_INIT_FAILED";
|
|
70
|
+
readonly ERR_CFG_OSINFO_FETCH_FAILED: "ERR_CFG_OSINFO_FETCH_FAILED";
|
|
71
|
+
readonly ERR_CFG_TELEMETRY_SETUP_FAILED: "ERR_CFG_TELEMETRY_SETUP_FAILED";
|
|
72
|
+
readonly ERR_TPL_DOWNLOAD_FAILED: "ERR_TPL_DOWNLOAD_FAILED";
|
|
73
|
+
readonly ERR_TPL_EXTRACT_FAILED: "ERR_TPL_EXTRACT_FAILED";
|
|
74
|
+
readonly ERR_TPL_METADATA_UPDATE_FAILED: "ERR_TPL_METADATA_UPDATE_FAILED";
|
|
75
|
+
readonly ERR_TPL_INTERNAL_COPY_FAILED: "ERR_TPL_INTERNAL_COPY_FAILED";
|
|
76
|
+
readonly ERR_TPL_THEME_UPDATE_FAILED: "ERR_TPL_THEME_UPDATE_FAILED";
|
|
77
|
+
readonly ERR_UNCAUGHT: "ERR_UNCAUGHT";
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Sends an event to PostHog for analytics tracking.
|
|
81
|
+
*
|
|
82
|
+
* @param client - The PostHog client instance used to send the event
|
|
83
|
+
* @param distinctId - A unique identifier for the user (hashed system UUID)
|
|
84
|
+
* @param sessionId - A unique identifier for this run/session
|
|
85
|
+
* @param event - The name of the event to track (e.g., 'create-tina-app-started')
|
|
86
|
+
* @param properties - Additional properties to include with the event
|
|
87
|
+
*
|
|
88
|
+
* @remarks
|
|
89
|
+
* - Returns early if the PostHog client is not provided
|
|
90
|
+
* - Skips sending data when `TINA_DEV` environment variable is set to 'true'
|
|
91
|
+
* - Automatically adds a 'system' property with value 'tinacms/create-tina-app'
|
|
92
|
+
* - Includes sessionId in properties to track individual runs
|
|
93
|
+
* - Uses hashed system UUID as distinctId to track unique users anonymously
|
|
94
|
+
* - Logs errors to console if event capture fails
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```typescript
|
|
98
|
+
* const client = new PostHog('api-key');
|
|
99
|
+
* const userId = await getAnonymousUserId();
|
|
100
|
+
* const sessionId = generateSessionId();
|
|
101
|
+
* postHogCapture(client, userId, sessionId, 'create-tina-app-started', {
|
|
102
|
+
* template: 'basic',
|
|
103
|
+
* typescript: true
|
|
104
|
+
* });
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
export declare function postHogCapture(client: PostHog, distinctId: string, sessionId: string, event: string, properties: Record<string, any>): void;
|
|
108
|
+
/**
|
|
109
|
+
* Capture an error event in PostHog with categorized tracking and sanitized stack traces
|
|
110
|
+
*
|
|
111
|
+
* @param client - The PostHog client instance
|
|
112
|
+
* @param distinctId - A unique identifier for the user (hashed system UUID)
|
|
113
|
+
* @param sessionId - A unique identifier for this run/session
|
|
114
|
+
* @param error - The error object that was thrown
|
|
115
|
+
* @param context - Context about the error including code, category, step, and additional properties
|
|
116
|
+
*
|
|
117
|
+
* @remarks
|
|
118
|
+
* - Sanitizes stack traces to remove local file paths
|
|
119
|
+
* - Maps error categories to three event types:
|
|
120
|
+
* - 'create-tina-app-error' for technical failures (filesystem, network, installation, git, etc.)
|
|
121
|
+
* - 'create-tina-app-validation-error' for user input validation issues
|
|
122
|
+
* - 'create-tina-app-user-cancelled' for user cancellations (Ctrl+C)
|
|
123
|
+
* - Includes error code, sanitized stack, step name, and telemetry data in properties
|
|
124
|
+
* - Non-fatal errors are tracked but allow the process to continue
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* try {
|
|
129
|
+
* await downloadTemplate();
|
|
130
|
+
* } catch (err) {
|
|
131
|
+
* postHogCaptureError(client, userId, sessionId, err as Error, {
|
|
132
|
+
* errorCode: ERROR_CODES.ERR_TPL_DOWNLOAD_FAILED,
|
|
133
|
+
* errorCategory: 'template',
|
|
134
|
+
* step: TRACKING_STEPS.DOWNLOADING_TEMPLATE,
|
|
135
|
+
* fatal: true,
|
|
136
|
+
* additionalProperties: { template: 'basic' }
|
|
137
|
+
* });
|
|
138
|
+
* }
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
export declare function postHogCaptureError(client: PostHog | null, distinctId: string, sessionId: string, error: Error, context: {
|
|
142
|
+
errorCode: string;
|
|
143
|
+
errorCategory: string;
|
|
144
|
+
step: string;
|
|
145
|
+
fatal?: boolean;
|
|
146
|
+
additionalProperties?: Record<string, any>;
|
|
147
|
+
}): void;
|
|
@@ -8,3 +8,13 @@ export declare const TextStyles: {
|
|
|
8
8
|
err: import("chalk").ChalkInstance;
|
|
9
9
|
bold: import("chalk").ChalkInstance;
|
|
10
10
|
};
|
|
11
|
+
export declare const TextStylesBold: {
|
|
12
|
+
tinaOrange: import("chalk").ChalkInstance;
|
|
13
|
+
link: (url: string) => string;
|
|
14
|
+
cmd: import("chalk").ChalkInstance;
|
|
15
|
+
info: import("chalk").ChalkInstance;
|
|
16
|
+
success: import("chalk").ChalkInstance;
|
|
17
|
+
warn: import("chalk").ChalkInstance;
|
|
18
|
+
err: import("chalk").ChalkInstance;
|
|
19
|
+
bold: import("chalk").ChalkInstance;
|
|
20
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-tina-app",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"files": [
|
|
@@ -44,10 +44,10 @@
|
|
|
44
44
|
"cross-spawn": "^7.0.6",
|
|
45
45
|
"fs-extra": "^11.3.0",
|
|
46
46
|
"ora": "^8.2.0",
|
|
47
|
+
"posthog-node": "^5.17.2",
|
|
47
48
|
"prompts": "^2.4.2",
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"@tinacms/metrics": "2.0.1"
|
|
49
|
+
"systeminformation": "^5.27.13",
|
|
50
|
+
"tar": "7.4.0"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
53
|
"types": "pnpm tsc",
|