@tanstack/cli 0.0.7 → 0.0.8

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.
@@ -1,11 +1,10 @@
1
+ import { a as fetchIntegrations, l as CustomTemplateCompiledSchema, p as IntegrationCompiledSchema } from "./fetch-DhlVXS6S.mjs";
1
2
  import { render } from "ejs";
2
3
  import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
3
- import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
4
- import { basename, dirname, extname, join, resolve } from "node:path";
5
- import { z } from "zod";
4
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
5
+ import { basename, dirname, extname, resolve } from "node:path";
6
6
  import ignore from "ignore";
7
7
  import parseGitignore from "parse-gitignore";
8
- import { homedir } from "node:os";
9
8
 
10
9
  //#region src/engine/template.ts
11
10
  /**
@@ -323,16 +322,16 @@ function generateEntryClient(_options, entryClientInits) {
323
322
  function generateRootRoute(options, rootProviders, devtoolsPlugins) {
324
323
  const lines = [];
325
324
  const hasHeader = options.chosenIntegrations.length > 0;
326
- if (devtoolsPlugins.length > 0) lines.push({
327
- text: `import React from 'react'`,
325
+ lines.push({
326
+ text: `import { HeadContent, Scripts, createRootRoute } from '@tanstack/react-router'`,
328
327
  integrationId: "base"
329
328
  });
330
329
  lines.push({
331
- text: `import { HeadContent, Scripts, createRootRoute } from '@tanstack/react-router'`,
330
+ text: `import { TanStackDevtools } from '@tanstack/react-devtools'`,
332
331
  integrationId: "base"
333
332
  });
334
333
  lines.push({
335
- text: `import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'`,
334
+ text: `import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'`,
336
335
  integrationId: "base"
337
336
  });
338
337
  lines.push({
@@ -357,24 +356,6 @@ function generateRootRoute(options, rootProviders, devtoolsPlugins) {
357
356
  integrationId: devtools.integrationId
358
357
  });
359
358
  }
360
- if (devtoolsPlugins.length > 0) {
361
- lines.push({
362
- text: "",
363
- integrationId: "base"
364
- });
365
- lines.push({
366
- text: `const devtoolsPlugins = [`,
367
- integrationId: "base"
368
- });
369
- for (const devtools of devtoolsPlugins) lines.push({
370
- text: ` ${devtools.jsName},`,
371
- integrationId: devtools.integrationId
372
- });
373
- lines.push({
374
- text: `]`,
375
- integrationId: "base"
376
- });
377
- }
378
359
  lines.push({
379
360
  text: "",
380
361
  integrationId: "base"
@@ -472,23 +453,33 @@ function generateRootRoute(options, rootProviders, devtoolsPlugins) {
472
453
  integrationId: "base"
473
454
  });
474
455
  lines.push({
475
- text: `${currentIndent}<TanStackRouterDevtools />`,
456
+ text: `${currentIndent}<TanStackDevtools`,
457
+ integrationId: "base"
458
+ });
459
+ lines.push({
460
+ text: `${currentIndent} config={{ position: 'bottom-right' }}`,
461
+ integrationId: "base"
462
+ });
463
+ lines.push({
464
+ text: `${currentIndent} plugins={[`,
465
+ integrationId: "base"
466
+ });
467
+ lines.push({
468
+ text: `${currentIndent} { name: 'TanStack Router', render: <TanStackRouterDevtoolsPanel /> },`,
469
+ integrationId: "base"
470
+ });
471
+ for (const devtools of devtoolsPlugins) lines.push({
472
+ text: `${currentIndent} ${devtools.jsName},`,
473
+ integrationId: devtools.integrationId
474
+ });
475
+ lines.push({
476
+ text: `${currentIndent} ]}`,
477
+ integrationId: "base"
478
+ });
479
+ lines.push({
480
+ text: `${currentIndent}/>`,
476
481
  integrationId: "base"
477
482
  });
478
- if (devtoolsPlugins.length > 0) {
479
- lines.push({
480
- text: `${currentIndent}{devtoolsPlugins.map((plugin, i) => (`,
481
- integrationId: "base"
482
- });
483
- lines.push({
484
- text: `${currentIndent} <React.Fragment key={i}>{plugin.render}</React.Fragment>`,
485
- integrationId: "base"
486
- });
487
- lines.push({
488
- text: `${currentIndent}))}`,
489
- integrationId: "base"
490
- });
491
- }
492
483
  for (const provider of [...rootProviders].reverse()) {
493
484
  currentIndent = currentIndent.slice(0, -2);
494
485
  lines.push({
@@ -1462,6 +1453,7 @@ function buildPackageJson(options, packages) {
1462
1453
  dependencies: {
1463
1454
  "@tanstack/react-router": "^1.132.0",
1464
1455
  "@tanstack/react-router-devtools": "^1.132.0",
1456
+ "@tanstack/react-devtools": "^0.9.2",
1465
1457
  "@tanstack/react-start": "^1.132.0",
1466
1458
  react: "^19.2.0",
1467
1459
  "react-dom": "^19.2.0",
@@ -1535,14 +1527,28 @@ function compile(options) {
1535
1527
  for (const [path, { content }] of files) outputFiles[path] = content;
1536
1528
  outputFiles["package.json"] = buildPackageJson(options, packages);
1537
1529
  const seenEnvVars = /* @__PURE__ */ new Set();
1530
+ const uniqueEnvVars = envVars.filter((v) => {
1531
+ if (seenEnvVars.has(v.name)) return false;
1532
+ seenEnvVars.add(v.name);
1533
+ return true;
1534
+ });
1535
+ if (uniqueEnvVars.length > 0) {
1536
+ const envLines = [
1537
+ "# Environment Variables",
1538
+ "# Copy this file to .env.local and fill in your values",
1539
+ ""
1540
+ ];
1541
+ for (const v of uniqueEnvVars) {
1542
+ envLines.push(`# ${v.description}${v.required ? " (required)" : ""}`);
1543
+ envLines.push(`${v.name}=${v.example || ""}`);
1544
+ envLines.push("");
1545
+ }
1546
+ outputFiles[".env.example"] = envLines.join("\n");
1547
+ }
1538
1548
  return {
1539
1549
  files: outputFiles,
1540
1550
  packages,
1541
- envVars: envVars.filter((v) => {
1542
- if (seenEnvVars.has(v.name)) return false;
1543
- seenEnvVars.add(v.name);
1544
- return true;
1545
- }),
1551
+ envVars: uniqueEnvVars,
1546
1552
  warnings
1547
1553
  };
1548
1554
  }
@@ -1791,355 +1797,6 @@ async function readConfigFile(targetDir) {
1791
1797
  }
1792
1798
  }
1793
1799
 
1794
- //#endregion
1795
- //#region src/engine/types.ts
1796
- const CategorySchema = z.enum([
1797
- "tanstack",
1798
- "database",
1799
- "orm",
1800
- "auth",
1801
- "deploy",
1802
- "tooling",
1803
- "monitoring",
1804
- "api",
1805
- "i18n",
1806
- "cms",
1807
- "other"
1808
- ]);
1809
- const IntegrationTypeSchema = z.enum([
1810
- "integration",
1811
- "example",
1812
- "toolchain",
1813
- "deployment"
1814
- ]);
1815
- const IntegrationPhaseSchema = z.enum([
1816
- "setup",
1817
- "integration",
1818
- "example"
1819
- ]);
1820
- const RouterModeSchema = z.enum(["file-router", "code-router"]);
1821
- const SelectOptionSchema = z.object({
1822
- type: z.literal("select"),
1823
- label: z.string(),
1824
- description: z.string().optional(),
1825
- default: z.string(),
1826
- options: z.array(z.object({
1827
- value: z.string(),
1828
- label: z.string()
1829
- }))
1830
- });
1831
- const BooleanOptionSchema = z.object({
1832
- type: z.literal("boolean"),
1833
- label: z.string(),
1834
- description: z.string().optional(),
1835
- default: z.boolean()
1836
- });
1837
- const StringOptionSchema = z.object({
1838
- type: z.literal("string"),
1839
- label: z.string(),
1840
- description: z.string().optional(),
1841
- default: z.string()
1842
- });
1843
- const IntegrationOptionSchema = z.discriminatedUnion("type", [
1844
- SelectOptionSchema,
1845
- BooleanOptionSchema,
1846
- StringOptionSchema
1847
- ]);
1848
- const IntegrationOptionsSchema = z.record(z.string(), IntegrationOptionSchema);
1849
- const HookTypeSchema = z.enum([
1850
- "header-user",
1851
- "provider",
1852
- "root-provider",
1853
- "layout",
1854
- "vite-plugin",
1855
- "devtools",
1856
- "entry-client"
1857
- ]);
1858
- const HookSchema = z.object({
1859
- type: HookTypeSchema.optional(),
1860
- path: z.string().optional(),
1861
- jsName: z.string().optional(),
1862
- import: z.string().optional(),
1863
- code: z.string().optional()
1864
- });
1865
- const RouteSchema = z.object({
1866
- url: z.string().optional(),
1867
- name: z.string().optional(),
1868
- icon: z.string().optional(),
1869
- path: z.string(),
1870
- jsName: z.string(),
1871
- children: z.array(z.lazy(() => RouteSchema)).optional()
1872
- });
1873
- const EnvVarSchema = z.object({
1874
- name: z.string(),
1875
- description: z.string(),
1876
- required: z.boolean().optional(),
1877
- example: z.string().optional()
1878
- });
1879
- const CommandSchema = z.object({
1880
- command: z.string(),
1881
- args: z.array(z.string()).optional()
1882
- });
1883
- const IntegrationInfoSchema = z.object({
1884
- id: z.string().optional(),
1885
- name: z.string(),
1886
- description: z.string(),
1887
- author: z.string().optional(),
1888
- version: z.string().optional(),
1889
- link: z.string().optional(),
1890
- license: z.string().optional(),
1891
- warning: z.string().optional(),
1892
- type: IntegrationTypeSchema,
1893
- phase: IntegrationPhaseSchema,
1894
- category: CategorySchema.optional(),
1895
- modes: z.array(RouterModeSchema),
1896
- priority: z.number().optional(),
1897
- default: z.boolean().optional(),
1898
- requiresTailwind: z.boolean().optional(),
1899
- demoRequiresTailwind: z.boolean().optional(),
1900
- dependsOn: z.array(z.string()).optional(),
1901
- exclusive: z.array(z.string()).optional(),
1902
- partnerId: z.string().optional(),
1903
- options: IntegrationOptionsSchema.optional(),
1904
- hooks: z.array(HookSchema).optional(),
1905
- routes: z.array(RouteSchema).optional(),
1906
- packageAdditions: z.object({
1907
- dependencies: z.record(z.string(), z.string()).optional(),
1908
- devDependencies: z.record(z.string(), z.string()).optional(),
1909
- scripts: z.record(z.string(), z.string()).optional()
1910
- }).optional(),
1911
- shadcnComponents: z.array(z.string()).optional(),
1912
- gitignorePatterns: z.array(z.string()).optional(),
1913
- envVars: z.array(EnvVarSchema).optional(),
1914
- command: CommandSchema.optional(),
1915
- integrationSpecialSteps: z.array(z.string()).optional(),
1916
- createSpecialSteps: z.array(z.string()).optional(),
1917
- postInitSpecialSteps: z.array(z.string()).optional(),
1918
- smallLogo: z.string().optional(),
1919
- logo: z.string().optional(),
1920
- readme: z.string().optional()
1921
- });
1922
- const IntegrationCompiledSchema = IntegrationInfoSchema.extend({
1923
- id: z.string(),
1924
- files: z.record(z.string(), z.string()),
1925
- deletedFiles: z.array(z.string()).optional()
1926
- });
1927
- const CustomTemplateInfoSchema = z.object({
1928
- id: z.string().optional(),
1929
- name: z.string(),
1930
- description: z.string(),
1931
- framework: z.string(),
1932
- mode: RouterModeSchema,
1933
- typescript: z.boolean(),
1934
- tailwind: z.boolean(),
1935
- integrations: z.array(z.string()),
1936
- integrationOptions: z.record(z.string(), z.record(z.string(), z.unknown())).optional(),
1937
- banner: z.string().optional()
1938
- });
1939
- const CustomTemplateCompiledSchema = CustomTemplateInfoSchema.extend({ id: z.string() });
1940
- const ManifestIntegrationSchema = z.object({
1941
- id: z.string(),
1942
- name: z.string(),
1943
- description: z.string(),
1944
- type: IntegrationTypeSchema,
1945
- category: CategorySchema.optional(),
1946
- modes: z.array(RouterModeSchema),
1947
- dependsOn: z.array(z.string()).optional(),
1948
- exclusive: z.array(z.string()).optional(),
1949
- partnerId: z.string().optional(),
1950
- hasOptions: z.boolean().optional(),
1951
- link: z.string().optional(),
1952
- color: z.string().optional(),
1953
- requiresTailwind: z.boolean().optional(),
1954
- demoRequiresTailwind: z.boolean().optional()
1955
- });
1956
- const ManifestCustomTemplateSchema = z.object({
1957
- id: z.string(),
1958
- name: z.string(),
1959
- description: z.string(),
1960
- banner: z.string().optional(),
1961
- icon: z.string().optional(),
1962
- features: z.array(z.string()).optional()
1963
- });
1964
- const ManifestSchema = z.object({
1965
- version: z.string(),
1966
- generated: z.string(),
1967
- integrations: z.array(ManifestIntegrationSchema),
1968
- customTemplates: z.array(ManifestCustomTemplateSchema).optional()
1969
- });
1970
-
1971
- //#endregion
1972
- //#region src/cache/index.ts
1973
- const CACHE_DIR = join(homedir(), ".tanstack", "cache");
1974
- const DEFAULT_TTL_MS = 1440 * 60 * 1e3;
1975
- function ensureCacheDir() {
1976
- if (!existsSync(CACHE_DIR)) mkdirSync(CACHE_DIR, { recursive: true });
1977
- }
1978
- function getCachePath(key) {
1979
- return join(CACHE_DIR, `${key.replace(/[^a-zA-Z0-9-_]/g, "_")}.json`);
1980
- }
1981
- function getCached(key) {
1982
- const cachePath = getCachePath(key);
1983
- if (!existsSync(cachePath)) return null;
1984
- try {
1985
- const raw = readFileSync(cachePath, "utf-8");
1986
- const entry = JSON.parse(raw);
1987
- if (Date.now() - entry.timestamp > entry.ttl) return null;
1988
- return entry.data;
1989
- } catch {
1990
- return null;
1991
- }
1992
- }
1993
- function setCache(key, data, ttlMs = DEFAULT_TTL_MS) {
1994
- ensureCacheDir();
1995
- const cachePath = getCachePath(key);
1996
- const entry = {
1997
- data,
1998
- timestamp: Date.now(),
1999
- ttl: ttlMs
2000
- };
2001
- writeFileSync(cachePath, JSON.stringify(entry, null, 2), "utf-8");
2002
- }
2003
- async function fetchWithCache(key, fetcher, ttlMs = DEFAULT_TTL_MS) {
2004
- const cached = getCached(key);
2005
- if (cached !== null) return cached;
2006
- const data = await fetcher();
2007
- setCache(key, data, ttlMs);
2008
- return data;
2009
- }
2010
-
2011
- //#endregion
2012
- //#region src/api/fetch.ts
2013
- const GITHUB_RAW_BASE = "https://raw.githubusercontent.com/TanStack/cli/main/integrations";
2014
- const CACHE_TTL_MS = 3600 * 1e3;
2015
- /**
2016
- * Check if a path is a local directory
2017
- */
2018
- function isLocalPath(path) {
2019
- return path.startsWith("/") || path.startsWith("./") || path.startsWith("..");
2020
- }
2021
- /**
2022
- * Fetch the integration manifest from GitHub or local path (with caching for remote)
2023
- */
2024
- async function fetchManifest(baseUrl = GITHUB_RAW_BASE) {
2025
- if (isLocalPath(baseUrl)) {
2026
- const manifestPath = join(baseUrl, "manifest.json");
2027
- if (!existsSync(manifestPath)) throw new Error(`Manifest not found at ${manifestPath}`);
2028
- const data = JSON.parse(readFileSync(manifestPath, "utf-8"));
2029
- return ManifestSchema.parse(data);
2030
- }
2031
- return fetchWithCache(`manifest_${baseUrl.replace(/[^a-zA-Z0-9]/g, "_")}`, async () => {
2032
- const url = `${baseUrl}/manifest.json`;
2033
- const response = await fetch(url);
2034
- if (!response.ok) throw new Error(`Failed to fetch manifest: ${response.statusText}`);
2035
- const data = await response.json();
2036
- return ManifestSchema.parse(data);
2037
- }, CACHE_TTL_MS);
2038
- }
2039
- /**
2040
- * Fetch integration info.json from GitHub or local path (with caching for remote)
2041
- */
2042
- async function fetchIntegrationInfo(integrationId, baseUrl = GITHUB_RAW_BASE) {
2043
- if (isLocalPath(baseUrl)) {
2044
- const infoPath = join(baseUrl, integrationId, "info.json");
2045
- if (!existsSync(infoPath)) throw new Error(`Integration info not found at ${infoPath}`);
2046
- const data = JSON.parse(readFileSync(infoPath, "utf-8"));
2047
- return IntegrationInfoSchema.parse(data);
2048
- }
2049
- return fetchWithCache(`integration_info_${integrationId}_${baseUrl.replace(/[^a-zA-Z0-9]/g, "_")}`, async () => {
2050
- const url = `${baseUrl}/${integrationId}/info.json`;
2051
- const response = await fetch(url);
2052
- if (!response.ok) throw new Error(`Failed to fetch integration ${integrationId}: ${response.statusText}`);
2053
- const data = await response.json();
2054
- return IntegrationInfoSchema.parse(data);
2055
- }, CACHE_TTL_MS);
2056
- }
2057
- /**
2058
- * Recursively read all files from a directory
2059
- */
2060
- function readDirRecursive(dir, basePath = "") {
2061
- const files = {};
2062
- if (!existsSync(dir)) return files;
2063
- for (const entry of readdirSync(dir)) {
2064
- const fullPath = join(dir, entry);
2065
- const relativePath$1 = basePath ? `${basePath}/${entry}` : entry;
2066
- if (statSync(fullPath).isDirectory()) Object.assign(files, readDirRecursive(fullPath, relativePath$1));
2067
- else files[relativePath$1] = readFileSync(fullPath, "utf-8");
2068
- }
2069
- return files;
2070
- }
2071
- /**
2072
- * Fetch all files for an integration from GitHub or local path (with caching for remote)
2073
- */
2074
- async function fetchIntegrationFiles(integrationId, baseUrl = GITHUB_RAW_BASE) {
2075
- if (isLocalPath(baseUrl)) return readDirRecursive(join(baseUrl, integrationId, "assets"));
2076
- return fetchWithCache(`integration_files_${integrationId}_${baseUrl.replace(/[^a-zA-Z0-9]/g, "_")}`, async () => {
2077
- const filesUrl = `${baseUrl}/${integrationId}/files.json`;
2078
- const response = await fetch(filesUrl);
2079
- if (!response.ok) return {};
2080
- const fileList = await response.json();
2081
- const files = {};
2082
- await Promise.all(fileList.map(async (filePath) => {
2083
- const fileUrl = `${baseUrl}/${integrationId}/assets/${filePath}`;
2084
- const fileResponse = await fetch(fileUrl);
2085
- if (fileResponse.ok) files[filePath] = await fileResponse.text();
2086
- }));
2087
- return files;
2088
- }, CACHE_TTL_MS);
2089
- }
2090
- /**
2091
- * Fetch integration package.json if it exists
2092
- */
2093
- async function fetchIntegrationPackageJson(integrationId, baseUrl) {
2094
- if (isLocalPath(baseUrl)) {
2095
- const pkgPath = join(baseUrl, integrationId, "package.json");
2096
- if (existsSync(pkgPath)) return JSON.parse(readFileSync(pkgPath, "utf-8"));
2097
- return null;
2098
- }
2099
- const url = `${baseUrl}/${integrationId}/package.json`;
2100
- const response = await fetch(url);
2101
- if (!response.ok) return null;
2102
- return response.json();
2103
- }
2104
- /**
2105
- * Fetch a complete compiled integration from GitHub
2106
- */
2107
- async function fetchIntegration(integrationId, baseUrl = GITHUB_RAW_BASE) {
2108
- const [info, files, pkgJson] = await Promise.all([
2109
- fetchIntegrationInfo(integrationId, baseUrl),
2110
- fetchIntegrationFiles(integrationId, baseUrl),
2111
- fetchIntegrationPackageJson(integrationId, baseUrl)
2112
- ]);
2113
- const packageAdditions = info.packageAdditions ?? {};
2114
- if (pkgJson) {
2115
- if (pkgJson.dependencies) packageAdditions.dependencies = {
2116
- ...packageAdditions.dependencies,
2117
- ...pkgJson.dependencies
2118
- };
2119
- if (pkgJson.devDependencies) packageAdditions.devDependencies = {
2120
- ...packageAdditions.devDependencies,
2121
- ...pkgJson.devDependencies
2122
- };
2123
- if (pkgJson.scripts) packageAdditions.scripts = {
2124
- ...packageAdditions.scripts,
2125
- ...pkgJson.scripts
2126
- };
2127
- }
2128
- return IntegrationCompiledSchema.parse({
2129
- ...info,
2130
- id: integrationId,
2131
- files,
2132
- packageAdditions: Object.keys(packageAdditions).length > 0 ? packageAdditions : void 0,
2133
- deletedFiles: []
2134
- });
2135
- }
2136
- /**
2137
- * Fetch multiple integrations in parallel
2138
- */
2139
- async function fetchIntegrations(integrationIds, baseUrl = GITHUB_RAW_BASE) {
2140
- return Promise.all(integrationIds.map((id) => fetchIntegration(id, baseUrl)));
2141
- }
2142
-
2143
1800
  //#endregion
2144
1801
  //#region src/engine/custom-addons/shared.ts
2145
1802
  /**
@@ -2542,4 +2199,4 @@ async function loadTemplate(url) {
2542
2199
  }
2543
2200
 
2544
2201
  //#endregion
2545
- export { writeConfigFile as A, IntegrationTypeSchema as C, RouterModeSchema as D, RouteSchema as E, compileWithAttribution as M, processTemplateFile as N, CONFIG_FILE as O, relativePath as P, IntegrationPhaseSchema as S, ManifestSchema as T, HookSchema as _, initIntegration as a, IntegrationOptionSchema as b, fetchIntegrationFiles as c, fetchManifest as d, CategorySchema as f, EnvVarSchema as g, CustomTemplateInfoSchema as h, compileIntegration as i, compile as j, readConfigFile as k, fetchIntegrationInfo as l, CustomTemplateCompiledSchema as m, initTemplate as n, loadRemoteIntegration as o, CommandSchema as p, loadTemplate as r, fetchIntegration as s, compileTemplate as t, fetchIntegrations as u, IntegrationCompiledSchema as v, ManifestIntegrationSchema as w, IntegrationOptionsSchema as x, IntegrationInfoSchema as y };
2202
+ export { initIntegration as a, readConfigFile as c, compileWithAttribution as d, processTemplateFile as f, compileIntegration as i, writeConfigFile as l, initTemplate as n, loadRemoteIntegration as o, relativePath as p, loadTemplate as r, CONFIG_FILE as s, compileTemplate as t, compile as u };