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/bin/create-tina-app +1 -1
- package/dist/index.js +775 -147
- 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 +17 -8
- package/package.json +7 -6
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
|
|
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
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
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
|
|
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 =
|
|
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(
|
|
453
|
-
program.version(
|
|
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/
|
|
479
|
-
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
|
+
}
|
|
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
|
|
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
|
-
|
|
534
|
-
|
|
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"))
|
|
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 {
|
|
589
|
-
|
|
1068
|
+
const { message, isError } = validate(
|
|
1069
|
+
path3.basename(path3.resolve(name2))
|
|
590
1070
|
);
|
|
591
|
-
if (
|
|
592
|
-
return
|
|
1071
|
+
if (isError) return `Invalid project name: ${message}`;
|
|
1072
|
+
return true;
|
|
593
1073
|
}
|
|
594
1074
|
});
|
|
595
|
-
if (!Object.hasOwn(res, "name"))
|
|
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"))
|
|
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"))
|
|
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
|
-
|
|
620
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|