@tanstack/cli 0.63.1 → 0.64.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/cli.js +56 -13
- package/dist/options.js +29 -12
- package/dist/telemetry.js +60 -12
- package/dist/types/options.d.ts +3 -1
- package/dist/types/ui-prompts.d.ts +3 -1
- package/dist/ui-prompts.js +41 -4
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
|
-
import { Command, InvalidArgumentError } from 'commander';
|
|
3
|
+
import { Command, InvalidArgumentError, Option } from 'commander';
|
|
4
4
|
import { cancel, confirm, intro, isCancel, log } from '@clack/prompts';
|
|
5
5
|
import chalk from 'chalk';
|
|
6
6
|
import semver from 'semver';
|
|
@@ -37,6 +37,19 @@ function sanitizeIdList(values) {
|
|
|
37
37
|
.map((value) => sanitizeId(value))
|
|
38
38
|
.filter((value) => Boolean(value))));
|
|
39
39
|
}
|
|
40
|
+
const AGENT_FLAG = '--agent';
|
|
41
|
+
function addHiddenAgentFlag(cmd) {
|
|
42
|
+
if (cmd.options.some((option) => option.long === AGENT_FLAG)) {
|
|
43
|
+
return cmd;
|
|
44
|
+
}
|
|
45
|
+
cmd.addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp());
|
|
46
|
+
return cmd;
|
|
47
|
+
}
|
|
48
|
+
function getInvocationTelemetryProperties() {
|
|
49
|
+
return {
|
|
50
|
+
invoked_by_agent: process.argv.includes(AGENT_FLAG),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
40
53
|
function getStarterTelemetryProperties(value) {
|
|
41
54
|
if (!value) {
|
|
42
55
|
return {};
|
|
@@ -134,7 +147,7 @@ function getResolvedCreateTelemetryProperties(finalOptions, cliOptions) {
|
|
|
134
147
|
function formatErrorMessage(error) {
|
|
135
148
|
return error instanceof Error ? error.message : 'An unknown error occurred';
|
|
136
149
|
}
|
|
137
|
-
export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaultFramework, frameworkDefinitionInitializers, showDeploymentOptions =
|
|
150
|
+
export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaultFramework, frameworkDefinitionInitializers, showDeploymentOptions = true, legacyAutoCreate = false, defaultRouterOnly = false, }) {
|
|
138
151
|
let currentTelemetry;
|
|
139
152
|
const environment = createUIEnvironment(appName, false, () => currentTelemetry);
|
|
140
153
|
const program = new Command();
|
|
@@ -275,6 +288,7 @@ export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaul
|
|
|
275
288
|
const startedAt = Date.now();
|
|
276
289
|
currentTelemetry = telemetry;
|
|
277
290
|
telemetry.captureCommandStarted(command, {
|
|
291
|
+
...getInvocationTelemetryProperties(),
|
|
278
292
|
...opts.properties,
|
|
279
293
|
cli_version: VERSION,
|
|
280
294
|
});
|
|
@@ -295,6 +309,7 @@ export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaul
|
|
|
295
309
|
.name(name)
|
|
296
310
|
.description(`${appName} CLI`)
|
|
297
311
|
.version(VERSION, '-v, --version', 'output the current version');
|
|
312
|
+
addHiddenAgentFlag(program);
|
|
298
313
|
// Helper to create the create command action handler
|
|
299
314
|
async function handleCreate(projectName, options) {
|
|
300
315
|
try {
|
|
@@ -444,38 +459,49 @@ export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaul
|
|
|
444
459
|
cliOptions.template.toLowerCase() !== 'file-router') {
|
|
445
460
|
cliOptions.routerOnly = true;
|
|
446
461
|
}
|
|
447
|
-
|
|
462
|
+
if (options.framework) {
|
|
463
|
+
cliOptions.framework = getFrameworkByName(options.framework).id;
|
|
464
|
+
}
|
|
465
|
+
else if (defaultFramework) {
|
|
466
|
+
cliOptions.framework = getFrameworkByName(defaultFramework).id;
|
|
467
|
+
}
|
|
448
468
|
const nonInteractive = !!cliOptions.nonInteractive || !!cliOptions.yes;
|
|
449
469
|
if (cliOptions.interactive && nonInteractive) {
|
|
450
470
|
throw new Error('Cannot combine --interactive with --non-interactive/--yes.');
|
|
451
471
|
}
|
|
452
|
-
const
|
|
472
|
+
const hasInteractiveTerminal = !!process.stdin.isTTY && !!process.stdout.isTTY && !process.env.CI;
|
|
453
473
|
const wantsInteractiveMode = !nonInteractive &&
|
|
454
|
-
(cliOptions.interactive ||
|
|
455
|
-
(cliOptions.addOns === true && addOnsFlagPassed));
|
|
474
|
+
(cliOptions.interactive || hasInteractiveTerminal);
|
|
456
475
|
let finalOptions;
|
|
457
476
|
if (wantsInteractiveMode) {
|
|
458
|
-
cliOptions.addOns
|
|
477
|
+
if (cliOptions.addOns === undefined) {
|
|
478
|
+
cliOptions.addOns = true;
|
|
479
|
+
}
|
|
459
480
|
}
|
|
460
481
|
else {
|
|
482
|
+
if (!cliOptions.framework) {
|
|
483
|
+
cliOptions.framework = getFrameworkByName(defaultFramework || 'React').id;
|
|
484
|
+
}
|
|
461
485
|
finalOptions = await normalizeOptions(cliOptions, forcedAddOns, { forcedDeployment });
|
|
462
486
|
}
|
|
463
|
-
if (
|
|
464
|
-
|
|
465
|
-
throw new Error('When using --non-interactive/--yes, pass explicit add-ons via --add-ons <ids>.');
|
|
466
|
-
}
|
|
487
|
+
if (!wantsInteractiveMode && cliOptions.addOns === true) {
|
|
488
|
+
throw new Error('When running non-interactively, pass explicit add-ons via --add-ons <ids>.');
|
|
467
489
|
}
|
|
468
490
|
if (finalOptions) {
|
|
469
491
|
intro(`Creating a new ${appName} app in ${projectName}...`);
|
|
470
492
|
}
|
|
471
493
|
else {
|
|
472
|
-
if (
|
|
494
|
+
if (!wantsInteractiveMode) {
|
|
473
495
|
throw new Error('Project name is required in non-interactive mode. Pass [project-name] or --target-dir.');
|
|
474
496
|
}
|
|
475
497
|
intro(`Let's configure your ${appName} application`);
|
|
476
498
|
finalOptions = await promptForCreateOptions(cliOptions, {
|
|
477
499
|
forcedAddOns,
|
|
500
|
+
forcedDeployment,
|
|
478
501
|
showDeploymentOptions,
|
|
502
|
+
defaultFrameworkId: defaultFramework
|
|
503
|
+
? getFrameworkByName(defaultFramework)?.id
|
|
504
|
+
: undefined,
|
|
479
505
|
});
|
|
480
506
|
}
|
|
481
507
|
if (!finalOptions) {
|
|
@@ -507,6 +533,7 @@ export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaul
|
|
|
507
533
|
}
|
|
508
534
|
// Helper to configure create command options
|
|
509
535
|
function configureCreateCommand(cmd) {
|
|
536
|
+
addHiddenAgentFlag(cmd);
|
|
510
537
|
cmd.argument('[project-name]', 'name of the project');
|
|
511
538
|
if (!defaultFramework) {
|
|
512
539
|
cmd.option('--framework <type>', `project framework (${availableFrameworks.join(', ')})`, (value) => {
|
|
@@ -517,7 +544,7 @@ export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaul
|
|
|
517
544
|
throw new InvalidArgumentError(`Invalid framework: ${value}. Only the following are allowed: ${availableFrameworks.join(', ')}`);
|
|
518
545
|
}
|
|
519
546
|
return value;
|
|
520
|
-
}
|
|
547
|
+
});
|
|
521
548
|
}
|
|
522
549
|
cmd
|
|
523
550
|
.option('--starter [url-or-id]', 'DEPRECATED: use --template. Initializes from a template URL or built-in id', false)
|
|
@@ -624,6 +651,7 @@ export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaul
|
|
|
624
651
|
program
|
|
625
652
|
.command('libraries')
|
|
626
653
|
.description('List TanStack libraries')
|
|
654
|
+
.addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
|
|
627
655
|
.option('--group <group>', `filter by group (${LIBRARY_GROUPS.join(', ')})`)
|
|
628
656
|
.option('--json', 'output JSON for automation', false)
|
|
629
657
|
.action(async (options) => {
|
|
@@ -681,6 +709,7 @@ export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaul
|
|
|
681
709
|
program
|
|
682
710
|
.command('doc')
|
|
683
711
|
.description('Fetch a TanStack documentation page')
|
|
712
|
+
.addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
|
|
684
713
|
.argument('<library>', 'library ID (eg. query, router, table)')
|
|
685
714
|
.argument('<path>', 'documentation path (eg. framework/react/overview)')
|
|
686
715
|
.option('--docs-version <version>', 'docs version (default: latest)', 'latest')
|
|
@@ -757,6 +786,7 @@ export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaul
|
|
|
757
786
|
program
|
|
758
787
|
.command('search-docs')
|
|
759
788
|
.description('Search TanStack documentation')
|
|
789
|
+
.addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
|
|
760
790
|
.argument('<query>', 'search query')
|
|
761
791
|
.option('--library <id>', 'filter to specific library')
|
|
762
792
|
.option('--framework <name>', 'filter to specific framework')
|
|
@@ -804,6 +834,7 @@ export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaul
|
|
|
804
834
|
program
|
|
805
835
|
.command('ecosystem')
|
|
806
836
|
.description('List TanStack ecosystem partners')
|
|
837
|
+
.addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
|
|
807
838
|
.option('--category <category>', 'filter by category')
|
|
808
839
|
.option('--library <id>', 'filter by TanStack library')
|
|
809
840
|
.option('--json', 'output JSON for automation', false)
|
|
@@ -873,6 +904,7 @@ export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaul
|
|
|
873
904
|
program
|
|
874
905
|
.command('pin-versions')
|
|
875
906
|
.description('Pin versions of the TanStack libraries')
|
|
907
|
+
.addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
|
|
876
908
|
.action(async () => {
|
|
877
909
|
try {
|
|
878
910
|
await runWithTelemetry('pin-versions', {}, async (telemetry) => {
|
|
@@ -943,6 +975,7 @@ Remove your node_modules directory and package lock file and re-install.`);
|
|
|
943
975
|
telemetryCommand
|
|
944
976
|
.command('status')
|
|
945
977
|
.description('Show anonymous telemetry status')
|
|
978
|
+
.addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
|
|
946
979
|
.option('--json', 'output JSON for automation', false)
|
|
947
980
|
.action(async (options) => {
|
|
948
981
|
const status = await getTelemetryStatus({ createIfMissing: true });
|
|
@@ -966,6 +999,7 @@ Remove your node_modules directory and package lock file and re-install.`);
|
|
|
966
999
|
telemetryCommand
|
|
967
1000
|
.command('enable')
|
|
968
1001
|
.description('Enable anonymous telemetry')
|
|
1002
|
+
.addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
|
|
969
1003
|
.action(async () => {
|
|
970
1004
|
await setTelemetryEnabled(true);
|
|
971
1005
|
console.log('Anonymous telemetry enabled');
|
|
@@ -973,6 +1007,7 @@ Remove your node_modules directory and package lock file and re-install.`);
|
|
|
973
1007
|
telemetryCommand
|
|
974
1008
|
.command('disable')
|
|
975
1009
|
.description('Disable anonymous telemetry')
|
|
1010
|
+
.addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
|
|
976
1011
|
.action(async () => {
|
|
977
1012
|
await setTelemetryEnabled(false);
|
|
978
1013
|
console.log('Anonymous telemetry disabled');
|
|
@@ -980,6 +1015,7 @@ Remove your node_modules directory and package lock file and re-install.`);
|
|
|
980
1015
|
// === ADD SUBCOMMAND ===
|
|
981
1016
|
program
|
|
982
1017
|
.command('add')
|
|
1018
|
+
.addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
|
|
983
1019
|
.argument('[add-on...]', 'Name of the add-ons (or add-ons separated by spaces or commas)')
|
|
984
1020
|
.option('--forced', 'Force the add-on to be added', false)
|
|
985
1021
|
.action(async (addOns, options) => {
|
|
@@ -1032,6 +1068,7 @@ Remove your node_modules directory and package lock file and re-install.`);
|
|
|
1032
1068
|
addOnCommand
|
|
1033
1069
|
.command('init')
|
|
1034
1070
|
.description('Initialize an add-on from the current project')
|
|
1071
|
+
.addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
|
|
1035
1072
|
.action(async () => {
|
|
1036
1073
|
try {
|
|
1037
1074
|
await runWithTelemetry('add-on:init', {}, async () => {
|
|
@@ -1046,6 +1083,7 @@ Remove your node_modules directory and package lock file and re-install.`);
|
|
|
1046
1083
|
addOnCommand
|
|
1047
1084
|
.command('compile')
|
|
1048
1085
|
.description('Update add-on from the current project')
|
|
1086
|
+
.addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
|
|
1049
1087
|
.action(async () => {
|
|
1050
1088
|
try {
|
|
1051
1089
|
await runWithTelemetry('add-on:compile', {}, async () => {
|
|
@@ -1060,6 +1098,7 @@ Remove your node_modules directory and package lock file and re-install.`);
|
|
|
1060
1098
|
addOnCommand
|
|
1061
1099
|
.command('dev')
|
|
1062
1100
|
.description('Watch project files and continuously refresh .add-on and add-on.json')
|
|
1101
|
+
.addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
|
|
1063
1102
|
.action(async () => {
|
|
1064
1103
|
try {
|
|
1065
1104
|
await runWithTelemetry('add-on:dev', {}, async () => {
|
|
@@ -1076,6 +1115,7 @@ Remove your node_modules directory and package lock file and re-install.`);
|
|
|
1076
1115
|
templateCommand
|
|
1077
1116
|
.command('init')
|
|
1078
1117
|
.description('Initialize a project template from the current project')
|
|
1118
|
+
.addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
|
|
1079
1119
|
.action(async () => {
|
|
1080
1120
|
try {
|
|
1081
1121
|
await runWithTelemetry('template:init', {}, async () => {
|
|
@@ -1090,6 +1130,7 @@ Remove your node_modules directory and package lock file and re-install.`);
|
|
|
1090
1130
|
templateCommand
|
|
1091
1131
|
.command('compile')
|
|
1092
1132
|
.description('Compile the template JSON file for the current project')
|
|
1133
|
+
.addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
|
|
1093
1134
|
.action(async () => {
|
|
1094
1135
|
try {
|
|
1095
1136
|
await runWithTelemetry('template:compile', {}, async () => {
|
|
@@ -1106,6 +1147,7 @@ Remove your node_modules directory and package lock file and re-install.`);
|
|
|
1106
1147
|
starterCommand
|
|
1107
1148
|
.command('init')
|
|
1108
1149
|
.description('Deprecated alias: initialize a project template')
|
|
1150
|
+
.addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
|
|
1109
1151
|
.action(async () => {
|
|
1110
1152
|
try {
|
|
1111
1153
|
await runWithTelemetry('starter:init', {}, async () => {
|
|
@@ -1120,6 +1162,7 @@ Remove your node_modules directory and package lock file and re-install.`);
|
|
|
1120
1162
|
starterCommand
|
|
1121
1163
|
.command('compile')
|
|
1122
1164
|
.description('Deprecated alias: compile the template JSON file')
|
|
1165
|
+
.addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
|
|
1123
1166
|
.action(async () => {
|
|
1124
1167
|
try {
|
|
1125
1168
|
await runWithTelemetry('starter:compile', {}, async () => {
|
package/dist/options.js
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
import { intro } from '@clack/prompts';
|
|
2
|
-
import { finalizeAddOns, getFrameworkById, getPackageManager, loadStarter, populateAddOnOptionsDefaults, readConfigFile, } from '@tanstack/create';
|
|
3
|
-
import { getProjectName, promptForAddOnOptions, promptForEnvVars, selectAddOns, selectDeployment, selectExamples, selectGit, selectPackageManager, selectTemplate, selectToolchain, } from './ui-prompts.js';
|
|
2
|
+
import { finalizeAddOns, getFrameworkById, getFrameworks, getPackageManager, loadStarter, populateAddOnOptionsDefaults, readConfigFile, } from '@tanstack/create';
|
|
3
|
+
import { getProjectName, promptForAddOnOptions, promptForEnvVars, selectAddOns, selectDeployment, selectExamples, selectFramework, selectGit, selectInstall, selectPackageManager, selectTemplate, selectToolchain, } from './ui-prompts.js';
|
|
4
4
|
import { listTemplateChoices, resolveStarterSpecifier, } from './command-line.js';
|
|
5
5
|
import { getCurrentDirectoryName, sanitizePackageName, validateProjectName, } from './utils.js';
|
|
6
|
-
export async function promptForCreateOptions(cliOptions, { forcedAddOns = [], showDeploymentOptions =
|
|
6
|
+
export async function promptForCreateOptions(cliOptions, { forcedAddOns = [], forcedDeployment, showDeploymentOptions = true, defaultFrameworkId, }) {
|
|
7
7
|
const options = {};
|
|
8
|
-
|
|
8
|
+
if (cliOptions.framework) {
|
|
9
|
+
options.framework = getFrameworkById(cliOptions.framework);
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
const availableFrameworks = getFrameworks();
|
|
13
|
+
if (defaultFrameworkId || availableFrameworks.length <= 1) {
|
|
14
|
+
options.framework = getFrameworkById(defaultFrameworkId || 'react');
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
options.framework = await selectFramework(availableFrameworks, defaultFrameworkId);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
9
20
|
// Validate project name
|
|
10
21
|
if (cliOptions.projectName) {
|
|
11
22
|
// Handle "." as project name - use sanitized current directory name
|
|
@@ -71,11 +82,19 @@ export async function promptForCreateOptions(cliOptions, { forcedAddOns = [], sh
|
|
|
71
82
|
// Toolchain selection
|
|
72
83
|
const toolchain = await selectToolchain(options.framework, cliOptions.toolchain);
|
|
73
84
|
// Deployment selection
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
85
|
+
let deployment;
|
|
86
|
+
if (routerOnly) {
|
|
87
|
+
deployment = undefined;
|
|
88
|
+
}
|
|
89
|
+
else if (cliOptions.deployment) {
|
|
90
|
+
deployment = cliOptions.deployment;
|
|
91
|
+
}
|
|
92
|
+
else if (showDeploymentOptions) {
|
|
93
|
+
deployment = await selectDeployment(options.framework, cliOptions.deployment, forcedDeployment);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
deployment = forcedDeployment;
|
|
97
|
+
}
|
|
79
98
|
// Add-ons selection
|
|
80
99
|
const addOns = new Set();
|
|
81
100
|
// Examples/demo pages are enabled by default
|
|
@@ -139,9 +158,7 @@ export async function promptForCreateOptions(cliOptions, { forcedAddOns = [], sh
|
|
|
139
158
|
options.envVarValues =
|
|
140
159
|
envVarValues;
|
|
141
160
|
options.git = cliOptions.git ?? (await selectGit());
|
|
142
|
-
|
|
143
|
-
options.install = false;
|
|
144
|
-
}
|
|
161
|
+
options.install = cliOptions.install ?? (await selectInstall());
|
|
145
162
|
if (starter) {
|
|
146
163
|
options.starter = starter;
|
|
147
164
|
}
|
package/dist/telemetry.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { version as nodeVersion } from 'node:process';
|
|
2
2
|
import { getTelemetryStatus, markTelemetryNoticeSeen, TELEMETRY_NOTICE_VERSION, } from './telemetry-config.js';
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const POSTHOG_PROJECT_TOKEN = 'phc_xJ2VBahJBzy3BShLhuGpw7EyoSuQtgwXXvhE9BYtHuKQ';
|
|
3
|
+
const TELEMETRY_TRANSPORT_ENDPOINT = 'https://www.google-analytics.com/g/collect';
|
|
4
|
+
const TELEMETRY_PROPERTY_ID = 'G-JMT1Z50SPS';
|
|
6
5
|
const TELEMETRY_NOTICE = 'TanStack CLI sends anonymous usage telemetry by default. It never sends project names, paths, raw search text, template URLs, add-on config values, or raw error messages. Disable it with `tanstack telemetry disable` or `TANSTACK_CLI_TELEMETRY_DISABLED=1`.';
|
|
7
6
|
const TELEMETRY_TIMEOUT_MS = 1200;
|
|
7
|
+
const TELEMETRY_VALUE_MAX_LENGTH = 500;
|
|
8
|
+
const TELEMETRY_NUMERIC_PREFIX = 'epn.';
|
|
9
|
+
const TELEMETRY_STRING_PREFIX = 'ep.';
|
|
8
10
|
let telemetryStatusPromise;
|
|
9
11
|
function getNodeMajorVersion() {
|
|
10
12
|
return Number.parseInt(nodeVersion.replace(/^v/, '').split('.')[0] || '0', 10);
|
|
@@ -26,6 +28,57 @@ function cleanProperties(value) {
|
|
|
26
28
|
}
|
|
27
29
|
return value;
|
|
28
30
|
}
|
|
31
|
+
function truncateValue(value) {
|
|
32
|
+
return value.length > TELEMETRY_VALUE_MAX_LENGTH
|
|
33
|
+
? `${value.slice(0, TELEMETRY_VALUE_MAX_LENGTH - 1)}…`
|
|
34
|
+
: value;
|
|
35
|
+
}
|
|
36
|
+
function normalizeParamKey(key) {
|
|
37
|
+
const normalized = key.replace(/[^a-zA-Z0-9_]/g, '_').replace(/^_+/, '');
|
|
38
|
+
const prefixed = /^[a-zA-Z]/.test(normalized)
|
|
39
|
+
? normalized
|
|
40
|
+
: `p_${normalized || 'value'}`;
|
|
41
|
+
return prefixed.slice(0, 40);
|
|
42
|
+
}
|
|
43
|
+
function normalizeParamValue(value) {
|
|
44
|
+
if (value === undefined || value === null) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
if (typeof value === 'boolean') {
|
|
48
|
+
return value ? 1 : 0;
|
|
49
|
+
}
|
|
50
|
+
if (typeof value === 'number') {
|
|
51
|
+
return Number.isFinite(value) ? value : undefined;
|
|
52
|
+
}
|
|
53
|
+
if (typeof value === 'string') {
|
|
54
|
+
return truncateValue(value);
|
|
55
|
+
}
|
|
56
|
+
const cleaned = cleanProperties(value);
|
|
57
|
+
if (cleaned === undefined) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
return truncateValue(JSON.stringify(cleaned));
|
|
61
|
+
}
|
|
62
|
+
function createTelemetryRequestBody(event, distinctId, properties) {
|
|
63
|
+
const params = new URLSearchParams({
|
|
64
|
+
cid: distinctId,
|
|
65
|
+
en: event,
|
|
66
|
+
tid: TELEMETRY_PROPERTY_ID,
|
|
67
|
+
v: '2',
|
|
68
|
+
});
|
|
69
|
+
for (const [key, value] of Object.entries(properties)) {
|
|
70
|
+
const normalizedValue = normalizeParamValue(value);
|
|
71
|
+
if (normalizedValue === undefined) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const normalizedKey = normalizeParamKey(key);
|
|
75
|
+
const paramName = typeof normalizedValue === 'number'
|
|
76
|
+
? `${TELEMETRY_NUMERIC_PREFIX}${normalizedKey}`
|
|
77
|
+
: `${TELEMETRY_STRING_PREFIX}${normalizedKey}`;
|
|
78
|
+
params.append(paramName, String(normalizedValue));
|
|
79
|
+
}
|
|
80
|
+
return params.toString();
|
|
81
|
+
}
|
|
29
82
|
function getErrorCode(error) {
|
|
30
83
|
if (!error || typeof error !== 'object') {
|
|
31
84
|
return 'unknown_error';
|
|
@@ -63,17 +116,12 @@ async function postEvent(event, distinctId, properties) {
|
|
|
63
116
|
controller.abort();
|
|
64
117
|
}, TELEMETRY_TIMEOUT_MS);
|
|
65
118
|
try {
|
|
66
|
-
await fetch(
|
|
119
|
+
await fetch(TELEMETRY_TRANSPORT_ENDPOINT, {
|
|
67
120
|
method: 'POST',
|
|
68
121
|
headers: {
|
|
69
|
-
'Content-Type': 'application/
|
|
122
|
+
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
|
|
70
123
|
},
|
|
71
|
-
body:
|
|
72
|
-
api_key: POSTHOG_PROJECT_TOKEN,
|
|
73
|
-
distinct_id: distinctId,
|
|
74
|
-
event,
|
|
75
|
-
properties,
|
|
76
|
-
}),
|
|
124
|
+
body: createTelemetryRequestBody(event, distinctId, properties),
|
|
77
125
|
signal: controller.signal,
|
|
78
126
|
});
|
|
79
127
|
}
|
|
@@ -171,7 +219,7 @@ export class TelemetryClient {
|
|
|
171
219
|
}
|
|
172
220
|
baseProperties() {
|
|
173
221
|
return {
|
|
174
|
-
|
|
222
|
+
client_lib: 'tanstack-cli',
|
|
175
223
|
disabled_by: this.disabledBy,
|
|
176
224
|
node_major: getNodeMajorVersion(),
|
|
177
225
|
os_arch: process.arch,
|
package/dist/types/options.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { Options } from '@tanstack/create';
|
|
2
2
|
import type { CliOptions } from './types.js';
|
|
3
|
-
export declare function promptForCreateOptions(cliOptions: CliOptions, { forcedAddOns, showDeploymentOptions, }: {
|
|
3
|
+
export declare function promptForCreateOptions(cliOptions: CliOptions, { forcedAddOns, forcedDeployment, showDeploymentOptions, defaultFrameworkId, }: {
|
|
4
4
|
forcedAddOns?: Array<string>;
|
|
5
|
+
forcedDeployment?: string;
|
|
5
6
|
showDeploymentOptions?: boolean;
|
|
7
|
+
defaultFrameworkId?: string;
|
|
6
8
|
}): Promise<Required<Options> | undefined>;
|
|
7
9
|
export declare function promptForAddOns(): Promise<Array<string>>;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { AddOn, PackageManager } from '@tanstack/create';
|
|
2
2
|
import type { Framework } from '@tanstack/create/dist/types/types.js';
|
|
3
|
+
export declare function selectFramework(frameworks: Array<Framework>, defaultFrameworkId?: string): Promise<Framework>;
|
|
4
|
+
export declare function selectInstall(): Promise<boolean>;
|
|
3
5
|
export declare function getProjectName(): Promise<string>;
|
|
4
6
|
export declare function selectPackageManager(): Promise<PackageManager>;
|
|
5
7
|
export declare function selectTemplate(templates: Array<{
|
|
@@ -13,4 +15,4 @@ export declare function selectExamples(): Promise<boolean>;
|
|
|
13
15
|
export declare function selectToolchain(framework: Framework, toolchain?: string | false): Promise<string | undefined>;
|
|
14
16
|
export declare function promptForAddOnOptions(addOnIds: Array<string>, framework: Framework): Promise<Record<string, Record<string, any>>>;
|
|
15
17
|
export declare function promptForEnvVars(addOns: Array<AddOn>): Promise<Record<string, string>>;
|
|
16
|
-
export declare function selectDeployment(framework: Framework, deployment?: string): Promise<string | undefined>;
|
|
18
|
+
export declare function selectDeployment(framework: Framework, deployment?: string, forcedDeployment?: string): Promise<string | undefined>;
|
package/dist/ui-prompts.js
CHANGED
|
@@ -1,6 +1,36 @@
|
|
|
1
1
|
import { cancel, confirm, isCancel, multiselect, note, password, select, text, } from '@clack/prompts';
|
|
2
2
|
import { DEFAULT_PACKAGE_MANAGER, SUPPORTED_PACKAGE_MANAGERS, getAllAddOns, } from '@tanstack/create';
|
|
3
3
|
import { validateProjectName } from './utils.js';
|
|
4
|
+
export async function selectFramework(frameworks, defaultFrameworkId) {
|
|
5
|
+
const initialValue = (defaultFrameworkId &&
|
|
6
|
+
frameworks.find((f) => f.id.toLowerCase() === defaultFrameworkId.toLowerCase())?.id) ||
|
|
7
|
+
frameworks[0].id;
|
|
8
|
+
const selected = await select({
|
|
9
|
+
message: 'Select framework:',
|
|
10
|
+
options: frameworks.map((f) => ({ value: f.id, label: f.name })),
|
|
11
|
+
initialValue,
|
|
12
|
+
});
|
|
13
|
+
if (isCancel(selected)) {
|
|
14
|
+
cancel('Operation cancelled.');
|
|
15
|
+
process.exit(0);
|
|
16
|
+
}
|
|
17
|
+
const framework = frameworks.find((f) => f.id === selected);
|
|
18
|
+
if (!framework) {
|
|
19
|
+
throw new Error(`Unknown framework: ${selected}`);
|
|
20
|
+
}
|
|
21
|
+
return framework;
|
|
22
|
+
}
|
|
23
|
+
export async function selectInstall() {
|
|
24
|
+
const install = await confirm({
|
|
25
|
+
message: 'Would you like to install dependencies now?',
|
|
26
|
+
initialValue: true,
|
|
27
|
+
});
|
|
28
|
+
if (isCancel(install)) {
|
|
29
|
+
cancel('Operation cancelled.');
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
return install;
|
|
33
|
+
}
|
|
4
34
|
export async function getProjectName() {
|
|
5
35
|
const value = await text({
|
|
6
36
|
message: 'What would you like to name your project?',
|
|
@@ -249,7 +279,7 @@ export async function promptForEnvVars(addOns) {
|
|
|
249
279
|
}
|
|
250
280
|
return result;
|
|
251
281
|
}
|
|
252
|
-
export async function selectDeployment(framework, deployment) {
|
|
282
|
+
export async function selectDeployment(framework, deployment, forcedDeployment) {
|
|
253
283
|
const deployments = new Set();
|
|
254
284
|
let initialValue = undefined;
|
|
255
285
|
for (const addOn of framework
|
|
@@ -260,20 +290,27 @@ export async function selectDeployment(framework, deployment) {
|
|
|
260
290
|
if (deployment && addOn.id === deployment) {
|
|
261
291
|
return deployment;
|
|
262
292
|
}
|
|
263
|
-
if (addOn.
|
|
293
|
+
if (forcedDeployment && addOn.id === forcedDeployment) {
|
|
294
|
+
initialValue = addOn.id;
|
|
295
|
+
}
|
|
296
|
+
else if (!initialValue && addOn.default) {
|
|
264
297
|
initialValue = addOn.id;
|
|
265
298
|
}
|
|
266
299
|
}
|
|
267
300
|
}
|
|
301
|
+
if (deployments.size === 0) {
|
|
302
|
+
return undefined;
|
|
303
|
+
}
|
|
268
304
|
const dp = await select({
|
|
269
|
-
message: 'Select deployment adapter',
|
|
305
|
+
message: 'Select deployment adapter:',
|
|
270
306
|
options: [
|
|
307
|
+
{ value: undefined, label: 'None' },
|
|
271
308
|
...Array.from(deployments).map((d) => ({
|
|
272
309
|
value: d.id,
|
|
273
310
|
label: d.name,
|
|
274
311
|
})),
|
|
275
312
|
],
|
|
276
|
-
initialValue
|
|
313
|
+
initialValue,
|
|
277
314
|
});
|
|
278
315
|
if (isCancel(dp)) {
|
|
279
316
|
cancel('Operation cancelled.');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.64.1",
|
|
4
4
|
"description": "TanStack CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"tempy": "^3.1.0",
|
|
42
42
|
"validate-npm-package-name": "^7.0.0",
|
|
43
43
|
"zod": "^3.24.2",
|
|
44
|
-
"@tanstack/create": "0.63.
|
|
44
|
+
"@tanstack/create": "0.63.5"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@playwright/test": "^1.58.2",
|