@tanstack/cli
Advanced tools
| const require_fetch = require('./fetch-DG5dLrsb.cjs'); | ||
| exports.BINARY_PREFIX = require_fetch.BINARY_PREFIX; |
| const require_template = require('./template-lWrIZhCQ.cjs'); | ||
| let node_fs = require("node:fs"); | ||
| let node_path = require("node:path"); | ||
| let zod = require("zod"); | ||
| let node_os = require("node:os"); | ||
| //#region src/engine/types.ts | ||
| const CategorySchema = zod.z.enum([ | ||
| "tanstack", | ||
| "database", | ||
| "orm", | ||
| "auth", | ||
| "deploy", | ||
| "tooling", | ||
| "monitoring", | ||
| "api", | ||
| "i18n", | ||
| "cms", | ||
| "other" | ||
| ]); | ||
| const IntegrationTypeSchema = zod.z.enum([ | ||
| "integration", | ||
| "example", | ||
| "toolchain", | ||
| "deployment" | ||
| ]); | ||
| const IntegrationPhaseSchema = zod.z.enum([ | ||
| "setup", | ||
| "integration", | ||
| "example" | ||
| ]); | ||
| const RouterModeSchema = zod.z.enum(["file-router", "code-router"]); | ||
| const SelectOptionSchema = zod.z.object({ | ||
| type: zod.z.literal("select"), | ||
| label: zod.z.string(), | ||
| description: zod.z.string().optional(), | ||
| default: zod.z.string(), | ||
| options: zod.z.array(zod.z.object({ | ||
| value: zod.z.string(), | ||
| label: zod.z.string() | ||
| })) | ||
| }); | ||
| const BooleanOptionSchema = zod.z.object({ | ||
| type: zod.z.literal("boolean"), | ||
| label: zod.z.string(), | ||
| description: zod.z.string().optional(), | ||
| default: zod.z.boolean() | ||
| }); | ||
| const StringOptionSchema = zod.z.object({ | ||
| type: zod.z.literal("string"), | ||
| label: zod.z.string(), | ||
| description: zod.z.string().optional(), | ||
| default: zod.z.string() | ||
| }); | ||
| const IntegrationOptionSchema = zod.z.discriminatedUnion("type", [ | ||
| SelectOptionSchema, | ||
| BooleanOptionSchema, | ||
| StringOptionSchema | ||
| ]); | ||
| const IntegrationOptionsSchema = zod.z.record(zod.z.string(), IntegrationOptionSchema); | ||
| const HookTypeSchema = zod.z.enum([ | ||
| "header-user", | ||
| "provider", | ||
| "root-provider", | ||
| "layout", | ||
| "vite-plugin", | ||
| "devtools", | ||
| "entry-client" | ||
| ]); | ||
| const HookSchema = zod.z.object({ | ||
| type: HookTypeSchema.optional(), | ||
| path: zod.z.string().optional(), | ||
| jsName: zod.z.string().optional(), | ||
| import: zod.z.string().optional(), | ||
| code: zod.z.string().optional() | ||
| }); | ||
| const RouteSchema = zod.z.object({ | ||
| url: zod.z.string().optional(), | ||
| name: zod.z.string().optional(), | ||
| icon: zod.z.string().optional(), | ||
| path: zod.z.string(), | ||
| jsName: zod.z.string(), | ||
| children: zod.z.array(zod.z.lazy(() => RouteSchema)).optional() | ||
| }); | ||
| const EnvVarSchema = zod.z.object({ | ||
| name: zod.z.string(), | ||
| description: zod.z.string(), | ||
| required: zod.z.boolean().optional(), | ||
| example: zod.z.string().optional() | ||
| }); | ||
| const CommandSchema = zod.z.object({ | ||
| command: zod.z.string(), | ||
| args: zod.z.array(zod.z.string()).optional() | ||
| }); | ||
| const IntegrationInfoSchema = zod.z.object({ | ||
| id: zod.z.string().optional(), | ||
| name: zod.z.string(), | ||
| description: zod.z.string(), | ||
| author: zod.z.string().optional(), | ||
| version: zod.z.string().optional(), | ||
| link: zod.z.string().optional(), | ||
| license: zod.z.string().optional(), | ||
| warning: zod.z.string().optional(), | ||
| type: IntegrationTypeSchema, | ||
| phase: IntegrationPhaseSchema, | ||
| category: CategorySchema.optional(), | ||
| modes: zod.z.array(RouterModeSchema), | ||
| priority: zod.z.number().optional(), | ||
| default: zod.z.boolean().optional(), | ||
| requiresTailwind: zod.z.boolean().optional(), | ||
| demoRequiresTailwind: zod.z.boolean().optional(), | ||
| dependsOn: zod.z.array(zod.z.string()).optional(), | ||
| exclusive: zod.z.array(zod.z.string()).optional(), | ||
| partnerId: zod.z.string().optional(), | ||
| options: IntegrationOptionsSchema.optional(), | ||
| hooks: zod.z.array(HookSchema).optional(), | ||
| routes: zod.z.array(RouteSchema).optional(), | ||
| packageAdditions: zod.z.object({ | ||
| dependencies: zod.z.record(zod.z.string(), zod.z.string()).optional(), | ||
| devDependencies: zod.z.record(zod.z.string(), zod.z.string()).optional(), | ||
| scripts: zod.z.record(zod.z.string(), zod.z.string()).optional() | ||
| }).optional(), | ||
| shadcnComponents: zod.z.array(zod.z.string()).optional(), | ||
| gitignorePatterns: zod.z.array(zod.z.string()).optional(), | ||
| envVars: zod.z.array(EnvVarSchema).optional(), | ||
| command: CommandSchema.optional(), | ||
| integrationSpecialSteps: zod.z.array(zod.z.string()).optional(), | ||
| createSpecialSteps: zod.z.array(zod.z.string()).optional(), | ||
| postInitSpecialSteps: zod.z.array(zod.z.string()).optional(), | ||
| smallLogo: zod.z.string().optional(), | ||
| logo: zod.z.string().optional(), | ||
| readme: zod.z.string().optional() | ||
| }); | ||
| const IntegrationCompiledSchema = IntegrationInfoSchema.extend({ | ||
| id: zod.z.string(), | ||
| files: zod.z.record(zod.z.string(), zod.z.string()), | ||
| deletedFiles: zod.z.array(zod.z.string()).optional() | ||
| }); | ||
| const CustomTemplateInfoSchema = zod.z.object({ | ||
| id: zod.z.string().optional(), | ||
| name: zod.z.string(), | ||
| description: zod.z.string(), | ||
| framework: zod.z.string(), | ||
| mode: RouterModeSchema, | ||
| typescript: zod.z.boolean(), | ||
| tailwind: zod.z.boolean(), | ||
| integrations: zod.z.array(zod.z.string()), | ||
| integrationOptions: zod.z.record(zod.z.string(), zod.z.record(zod.z.string(), zod.z.unknown())).optional(), | ||
| banner: zod.z.string().optional() | ||
| }); | ||
| const CustomTemplateCompiledSchema = CustomTemplateInfoSchema.extend({ id: zod.z.string() }); | ||
| const ManifestIntegrationSchema = zod.z.object({ | ||
| id: zod.z.string(), | ||
| name: zod.z.string(), | ||
| description: zod.z.string(), | ||
| type: IntegrationTypeSchema, | ||
| category: CategorySchema.optional(), | ||
| modes: zod.z.array(RouterModeSchema), | ||
| dependsOn: zod.z.array(zod.z.string()).optional(), | ||
| exclusive: zod.z.array(zod.z.string()).optional(), | ||
| partnerId: zod.z.string().optional(), | ||
| hasOptions: zod.z.boolean().optional(), | ||
| link: zod.z.string().optional(), | ||
| color: zod.z.string().optional(), | ||
| requiresTailwind: zod.z.boolean().optional(), | ||
| demoRequiresTailwind: zod.z.boolean().optional() | ||
| }); | ||
| const ManifestCustomTemplateSchema = zod.z.object({ | ||
| id: zod.z.string(), | ||
| name: zod.z.string(), | ||
| description: zod.z.string(), | ||
| banner: zod.z.string().optional(), | ||
| icon: zod.z.string().optional(), | ||
| features: zod.z.array(zod.z.string()).optional() | ||
| }); | ||
| const ManifestSchema = zod.z.object({ | ||
| version: zod.z.string(), | ||
| generated: zod.z.string(), | ||
| integrations: zod.z.array(ManifestIntegrationSchema), | ||
| customTemplates: zod.z.array(ManifestCustomTemplateSchema).optional() | ||
| }); | ||
| //#endregion | ||
| //#region src/cache/index.ts | ||
| const CACHE_DIR = (0, node_path.join)((0, node_os.homedir)(), ".tanstack", "cache"); | ||
| const DEFAULT_TTL_MS = 1440 * 60 * 1e3; | ||
| function ensureCacheDir() { | ||
| if (!(0, node_fs.existsSync)(CACHE_DIR)) (0, node_fs.mkdirSync)(CACHE_DIR, { recursive: true }); | ||
| } | ||
| function getCachePath(key) { | ||
| return (0, node_path.join)(CACHE_DIR, `${key.replace(/[^a-zA-Z0-9-_]/g, "_")}.json`); | ||
| } | ||
| function getCached(key) { | ||
| const cachePath = getCachePath(key); | ||
| if (!(0, node_fs.existsSync)(cachePath)) return null; | ||
| try { | ||
| const raw = (0, node_fs.readFileSync)(cachePath, "utf-8"); | ||
| const entry = JSON.parse(raw); | ||
| if (Date.now() - entry.timestamp > entry.ttl) return null; | ||
| return entry.data; | ||
| } catch { | ||
| return null; | ||
| } | ||
| } | ||
| function setCache(key, data, ttlMs = DEFAULT_TTL_MS) { | ||
| ensureCacheDir(); | ||
| const cachePath = getCachePath(key); | ||
| const entry = { | ||
| data, | ||
| timestamp: Date.now(), | ||
| ttl: ttlMs | ||
| }; | ||
| (0, node_fs.writeFileSync)(cachePath, JSON.stringify(entry, null, 2), "utf-8"); | ||
| } | ||
| async function fetchWithCache(key, fetcher, ttlMs = DEFAULT_TTL_MS) { | ||
| const cached = getCached(key); | ||
| if (cached !== null) return cached; | ||
| const data = await fetcher(); | ||
| setCache(key, data, ttlMs); | ||
| return data; | ||
| } | ||
| //#endregion | ||
| //#region src/api/fetch.ts | ||
| const GITHUB_RAW_BASE = "https://raw.githubusercontent.com/TanStack/cli/main/integrations"; | ||
| const CACHE_TTL_MS = 3600 * 1e3; | ||
| const BINARY_EXTENSIONS = new Set([ | ||
| ".png", | ||
| ".jpg", | ||
| ".jpeg", | ||
| ".gif", | ||
| ".webp", | ||
| ".ico", | ||
| ".svg", | ||
| ".woff", | ||
| ".woff2", | ||
| ".ttf", | ||
| ".eot", | ||
| ".otf", | ||
| ".pdf", | ||
| ".zip", | ||
| ".tar", | ||
| ".gz", | ||
| ".mp3", | ||
| ".mp4", | ||
| ".wav", | ||
| ".ogg", | ||
| ".webm" | ||
| ]); | ||
| const BINARY_PREFIX = "base64:"; | ||
| /** | ||
| * Check if a file should be treated as binary based on extension | ||
| */ | ||
| function isBinaryFile(filePath) { | ||
| return BINARY_EXTENSIONS.has((0, node_path.extname)(filePath).toLowerCase()); | ||
| } | ||
| /** | ||
| * Check if a path is a local directory | ||
| */ | ||
| function isLocalPath(path) { | ||
| return path.startsWith("/") || path.startsWith("./") || path.startsWith(".."); | ||
| } | ||
| /** | ||
| * Fetch the integration manifest from GitHub or local path (with caching for remote) | ||
| */ | ||
| async function fetchManifest(baseUrl = GITHUB_RAW_BASE) { | ||
| if (isLocalPath(baseUrl)) { | ||
| const manifestPath = (0, node_path.join)(baseUrl, "manifest.json"); | ||
| if (!(0, node_fs.existsSync)(manifestPath)) throw new Error(`Manifest not found at ${manifestPath}`); | ||
| const data = JSON.parse((0, node_fs.readFileSync)(manifestPath, "utf-8")); | ||
| return ManifestSchema.parse(data); | ||
| } | ||
| return fetchWithCache(`manifest_${baseUrl.replace(/[^a-zA-Z0-9]/g, "_")}`, async () => { | ||
| const url = `${baseUrl}/manifest.json`; | ||
| const response = await fetch(url); | ||
| if (!response.ok) throw new Error(`Failed to fetch manifest: ${response.statusText}`); | ||
| const data = await response.json(); | ||
| return ManifestSchema.parse(data); | ||
| }, CACHE_TTL_MS); | ||
| } | ||
| /** | ||
| * Fetch integration info.json from GitHub or local path (with caching for remote) | ||
| */ | ||
| async function fetchIntegrationInfo(integrationId, baseUrl = GITHUB_RAW_BASE) { | ||
| if (isLocalPath(baseUrl)) { | ||
| const infoPath = (0, node_path.join)(baseUrl, integrationId, "info.json"); | ||
| if (!(0, node_fs.existsSync)(infoPath)) throw new Error(`Integration info not found at ${infoPath}`); | ||
| const data = JSON.parse((0, node_fs.readFileSync)(infoPath, "utf-8")); | ||
| return IntegrationInfoSchema.parse(data); | ||
| } | ||
| return fetchWithCache(`integration_info_${integrationId}_${baseUrl.replace(/[^a-zA-Z0-9]/g, "_")}`, async () => { | ||
| const url = `${baseUrl}/${integrationId}/info.json`; | ||
| const response = await fetch(url); | ||
| if (!response.ok) throw new Error(`Failed to fetch integration ${integrationId}: ${response.statusText}`); | ||
| const data = await response.json(); | ||
| return IntegrationInfoSchema.parse(data); | ||
| }, CACHE_TTL_MS); | ||
| } | ||
| /** | ||
| * Recursively read all files from a directory | ||
| * Binary files are read as base64 with a prefix marker | ||
| */ | ||
| function readDirRecursive(dir, basePath = "") { | ||
| const files = {}; | ||
| if (!(0, node_fs.existsSync)(dir)) return files; | ||
| for (const entry of (0, node_fs.readdirSync)(dir)) { | ||
| const fullPath = (0, node_path.join)(dir, entry); | ||
| const relativePath = basePath ? `${basePath}/${entry}` : entry; | ||
| if ((0, node_fs.statSync)(fullPath).isDirectory()) Object.assign(files, readDirRecursive(fullPath, relativePath)); | ||
| else if (isBinaryFile(relativePath)) files[relativePath] = BINARY_PREFIX + (0, node_fs.readFileSync)(fullPath).toString("base64"); | ||
| else files[relativePath] = (0, node_fs.readFileSync)(fullPath, "utf-8"); | ||
| } | ||
| return files; | ||
| } | ||
| /** | ||
| * Fetch all files for an integration from GitHub or local path (with caching for remote) | ||
| */ | ||
| async function fetchIntegrationFiles(integrationId, baseUrl = GITHUB_RAW_BASE) { | ||
| if (isLocalPath(baseUrl)) return readDirRecursive((0, node_path.join)(baseUrl, integrationId, "assets")); | ||
| return fetchWithCache(`integration_files_${integrationId}_${baseUrl.replace(/[^a-zA-Z0-9]/g, "_")}`, async () => { | ||
| const filesUrl = `${baseUrl}/${integrationId}/files.json`; | ||
| const response = await fetch(filesUrl); | ||
| if (!response.ok) return {}; | ||
| const fileList = await response.json(); | ||
| const files = {}; | ||
| await Promise.all(fileList.map(async (filePath) => { | ||
| const fileUrl = `${baseUrl}/${integrationId}/assets/${filePath}`; | ||
| const fileResponse = await fetch(fileUrl); | ||
| if (fileResponse.ok) if (isBinaryFile(filePath)) { | ||
| const buffer = await fileResponse.arrayBuffer(); | ||
| files[filePath] = BINARY_PREFIX + Buffer.from(buffer).toString("base64"); | ||
| } else files[filePath] = await fileResponse.text(); | ||
| })); | ||
| return files; | ||
| }, CACHE_TTL_MS); | ||
| } | ||
| /** | ||
| * Fetch integration package.json if it exists | ||
| */ | ||
| async function fetchIntegrationPackageJson(integrationId, baseUrl) { | ||
| if (isLocalPath(baseUrl)) { | ||
| const pkgPath = (0, node_path.join)(baseUrl, integrationId, "package.json"); | ||
| if ((0, node_fs.existsSync)(pkgPath)) return JSON.parse((0, node_fs.readFileSync)(pkgPath, "utf-8")); | ||
| return null; | ||
| } | ||
| const url = `${baseUrl}/${integrationId}/package.json`; | ||
| const response = await fetch(url); | ||
| if (!response.ok) return null; | ||
| return response.json(); | ||
| } | ||
| /** | ||
| * Fetch a complete compiled integration from GitHub | ||
| */ | ||
| async function fetchIntegration(integrationId, baseUrl = GITHUB_RAW_BASE) { | ||
| const [info, files, pkgJson] = await Promise.all([ | ||
| fetchIntegrationInfo(integrationId, baseUrl), | ||
| fetchIntegrationFiles(integrationId, baseUrl), | ||
| fetchIntegrationPackageJson(integrationId, baseUrl) | ||
| ]); | ||
| const packageAdditions = info.packageAdditions ?? {}; | ||
| if (pkgJson) { | ||
| if (pkgJson.dependencies) packageAdditions.dependencies = { | ||
| ...packageAdditions.dependencies, | ||
| ...pkgJson.dependencies | ||
| }; | ||
| if (pkgJson.devDependencies) packageAdditions.devDependencies = { | ||
| ...packageAdditions.devDependencies, | ||
| ...pkgJson.devDependencies | ||
| }; | ||
| if (pkgJson.scripts) packageAdditions.scripts = { | ||
| ...packageAdditions.scripts, | ||
| ...pkgJson.scripts | ||
| }; | ||
| } | ||
| return IntegrationCompiledSchema.parse({ | ||
| ...info, | ||
| id: integrationId, | ||
| files, | ||
| packageAdditions: Object.keys(packageAdditions).length > 0 ? packageAdditions : void 0, | ||
| deletedFiles: [] | ||
| }); | ||
| } | ||
| /** | ||
| * Fetch multiple integrations in parallel | ||
| */ | ||
| async function fetchIntegrations(integrationIds, baseUrl = GITHUB_RAW_BASE) { | ||
| return Promise.all(integrationIds.map((id) => fetchIntegration(id, baseUrl))); | ||
| } | ||
| //#endregion | ||
| Object.defineProperty(exports, 'BINARY_PREFIX', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return BINARY_PREFIX; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'CategorySchema', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return CategorySchema; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'CommandSchema', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return CommandSchema; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'CustomTemplateCompiledSchema', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return CustomTemplateCompiledSchema; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'CustomTemplateInfoSchema', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return CustomTemplateInfoSchema; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'EnvVarSchema', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return EnvVarSchema; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'HookSchema', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return HookSchema; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'IntegrationCompiledSchema', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return IntegrationCompiledSchema; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'IntegrationInfoSchema', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return IntegrationInfoSchema; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'IntegrationOptionSchema', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return IntegrationOptionSchema; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'IntegrationOptionsSchema', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return IntegrationOptionsSchema; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'IntegrationPhaseSchema', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return IntegrationPhaseSchema; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'IntegrationTypeSchema', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return IntegrationTypeSchema; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'ManifestIntegrationSchema', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return ManifestIntegrationSchema; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'ManifestSchema', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return ManifestSchema; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'RouteSchema', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return RouteSchema; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'RouterModeSchema', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return RouterModeSchema; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'fetchIntegration', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return fetchIntegration; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'fetchIntegrationFiles', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return fetchIntegrationFiles; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'fetchIntegrationInfo', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return fetchIntegrationInfo; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'fetchIntegrations', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return fetchIntegrations; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'fetchManifest', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return fetchManifest; | ||
| } | ||
| }); |
| import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs"; | ||
| import { extname, join } from "node:path"; | ||
| import { z } from "zod"; | ||
| import { homedir } from "node:os"; | ||
| //#region src/engine/types.ts | ||
| const CategorySchema = z.enum([ | ||
| "tanstack", | ||
| "database", | ||
| "orm", | ||
| "auth", | ||
| "deploy", | ||
| "tooling", | ||
| "monitoring", | ||
| "api", | ||
| "i18n", | ||
| "cms", | ||
| "other" | ||
| ]); | ||
| const IntegrationTypeSchema = z.enum([ | ||
| "integration", | ||
| "example", | ||
| "toolchain", | ||
| "deployment" | ||
| ]); | ||
| const IntegrationPhaseSchema = z.enum([ | ||
| "setup", | ||
| "integration", | ||
| "example" | ||
| ]); | ||
| const RouterModeSchema = z.enum(["file-router", "code-router"]); | ||
| const SelectOptionSchema = z.object({ | ||
| type: z.literal("select"), | ||
| label: z.string(), | ||
| description: z.string().optional(), | ||
| default: z.string(), | ||
| options: z.array(z.object({ | ||
| value: z.string(), | ||
| label: z.string() | ||
| })) | ||
| }); | ||
| const BooleanOptionSchema = z.object({ | ||
| type: z.literal("boolean"), | ||
| label: z.string(), | ||
| description: z.string().optional(), | ||
| default: z.boolean() | ||
| }); | ||
| const StringOptionSchema = z.object({ | ||
| type: z.literal("string"), | ||
| label: z.string(), | ||
| description: z.string().optional(), | ||
| default: z.string() | ||
| }); | ||
| const IntegrationOptionSchema = z.discriminatedUnion("type", [ | ||
| SelectOptionSchema, | ||
| BooleanOptionSchema, | ||
| StringOptionSchema | ||
| ]); | ||
| const IntegrationOptionsSchema = z.record(z.string(), IntegrationOptionSchema); | ||
| const HookTypeSchema = z.enum([ | ||
| "header-user", | ||
| "provider", | ||
| "root-provider", | ||
| "layout", | ||
| "vite-plugin", | ||
| "devtools", | ||
| "entry-client" | ||
| ]); | ||
| const HookSchema = z.object({ | ||
| type: HookTypeSchema.optional(), | ||
| path: z.string().optional(), | ||
| jsName: z.string().optional(), | ||
| import: z.string().optional(), | ||
| code: z.string().optional() | ||
| }); | ||
| const RouteSchema = z.object({ | ||
| url: z.string().optional(), | ||
| name: z.string().optional(), | ||
| icon: z.string().optional(), | ||
| path: z.string(), | ||
| jsName: z.string(), | ||
| children: z.array(z.lazy(() => RouteSchema)).optional() | ||
| }); | ||
| const EnvVarSchema = z.object({ | ||
| name: z.string(), | ||
| description: z.string(), | ||
| required: z.boolean().optional(), | ||
| example: z.string().optional() | ||
| }); | ||
| const CommandSchema = z.object({ | ||
| command: z.string(), | ||
| args: z.array(z.string()).optional() | ||
| }); | ||
| const IntegrationInfoSchema = z.object({ | ||
| id: z.string().optional(), | ||
| name: z.string(), | ||
| description: z.string(), | ||
| author: z.string().optional(), | ||
| version: z.string().optional(), | ||
| link: z.string().optional(), | ||
| license: z.string().optional(), | ||
| warning: z.string().optional(), | ||
| type: IntegrationTypeSchema, | ||
| phase: IntegrationPhaseSchema, | ||
| category: CategorySchema.optional(), | ||
| modes: z.array(RouterModeSchema), | ||
| priority: z.number().optional(), | ||
| default: z.boolean().optional(), | ||
| requiresTailwind: z.boolean().optional(), | ||
| demoRequiresTailwind: z.boolean().optional(), | ||
| dependsOn: z.array(z.string()).optional(), | ||
| exclusive: z.array(z.string()).optional(), | ||
| partnerId: z.string().optional(), | ||
| options: IntegrationOptionsSchema.optional(), | ||
| hooks: z.array(HookSchema).optional(), | ||
| routes: z.array(RouteSchema).optional(), | ||
| packageAdditions: z.object({ | ||
| dependencies: z.record(z.string(), z.string()).optional(), | ||
| devDependencies: z.record(z.string(), z.string()).optional(), | ||
| scripts: z.record(z.string(), z.string()).optional() | ||
| }).optional(), | ||
| shadcnComponents: z.array(z.string()).optional(), | ||
| gitignorePatterns: z.array(z.string()).optional(), | ||
| envVars: z.array(EnvVarSchema).optional(), | ||
| command: CommandSchema.optional(), | ||
| integrationSpecialSteps: z.array(z.string()).optional(), | ||
| createSpecialSteps: z.array(z.string()).optional(), | ||
| postInitSpecialSteps: z.array(z.string()).optional(), | ||
| smallLogo: z.string().optional(), | ||
| logo: z.string().optional(), | ||
| readme: z.string().optional() | ||
| }); | ||
| const IntegrationCompiledSchema = IntegrationInfoSchema.extend({ | ||
| id: z.string(), | ||
| files: z.record(z.string(), z.string()), | ||
| deletedFiles: z.array(z.string()).optional() | ||
| }); | ||
| const CustomTemplateInfoSchema = z.object({ | ||
| id: z.string().optional(), | ||
| name: z.string(), | ||
| description: z.string(), | ||
| framework: z.string(), | ||
| mode: RouterModeSchema, | ||
| typescript: z.boolean(), | ||
| tailwind: z.boolean(), | ||
| integrations: z.array(z.string()), | ||
| integrationOptions: z.record(z.string(), z.record(z.string(), z.unknown())).optional(), | ||
| banner: z.string().optional() | ||
| }); | ||
| const CustomTemplateCompiledSchema = CustomTemplateInfoSchema.extend({ id: z.string() }); | ||
| const ManifestIntegrationSchema = z.object({ | ||
| id: z.string(), | ||
| name: z.string(), | ||
| description: z.string(), | ||
| type: IntegrationTypeSchema, | ||
| category: CategorySchema.optional(), | ||
| modes: z.array(RouterModeSchema), | ||
| dependsOn: z.array(z.string()).optional(), | ||
| exclusive: z.array(z.string()).optional(), | ||
| partnerId: z.string().optional(), | ||
| hasOptions: z.boolean().optional(), | ||
| link: z.string().optional(), | ||
| color: z.string().optional(), | ||
| requiresTailwind: z.boolean().optional(), | ||
| demoRequiresTailwind: z.boolean().optional() | ||
| }); | ||
| const ManifestCustomTemplateSchema = z.object({ | ||
| id: z.string(), | ||
| name: z.string(), | ||
| description: z.string(), | ||
| banner: z.string().optional(), | ||
| icon: z.string().optional(), | ||
| features: z.array(z.string()).optional() | ||
| }); | ||
| const ManifestSchema = z.object({ | ||
| version: z.string(), | ||
| generated: z.string(), | ||
| integrations: z.array(ManifestIntegrationSchema), | ||
| customTemplates: z.array(ManifestCustomTemplateSchema).optional() | ||
| }); | ||
| //#endregion | ||
| //#region src/cache/index.ts | ||
| const CACHE_DIR = join(homedir(), ".tanstack", "cache"); | ||
| const DEFAULT_TTL_MS = 1440 * 60 * 1e3; | ||
| function ensureCacheDir() { | ||
| if (!existsSync(CACHE_DIR)) mkdirSync(CACHE_DIR, { recursive: true }); | ||
| } | ||
| function getCachePath(key) { | ||
| return join(CACHE_DIR, `${key.replace(/[^a-zA-Z0-9-_]/g, "_")}.json`); | ||
| } | ||
| function getCached(key) { | ||
| const cachePath = getCachePath(key); | ||
| if (!existsSync(cachePath)) return null; | ||
| try { | ||
| const raw = readFileSync(cachePath, "utf-8"); | ||
| const entry = JSON.parse(raw); | ||
| if (Date.now() - entry.timestamp > entry.ttl) return null; | ||
| return entry.data; | ||
| } catch { | ||
| return null; | ||
| } | ||
| } | ||
| function setCache(key, data, ttlMs = DEFAULT_TTL_MS) { | ||
| ensureCacheDir(); | ||
| const cachePath = getCachePath(key); | ||
| const entry = { | ||
| data, | ||
| timestamp: Date.now(), | ||
| ttl: ttlMs | ||
| }; | ||
| writeFileSync(cachePath, JSON.stringify(entry, null, 2), "utf-8"); | ||
| } | ||
| async function fetchWithCache(key, fetcher, ttlMs = DEFAULT_TTL_MS) { | ||
| const cached = getCached(key); | ||
| if (cached !== null) return cached; | ||
| const data = await fetcher(); | ||
| setCache(key, data, ttlMs); | ||
| return data; | ||
| } | ||
| //#endregion | ||
| //#region src/api/fetch.ts | ||
| const GITHUB_RAW_BASE = "https://raw.githubusercontent.com/TanStack/cli/main/integrations"; | ||
| const CACHE_TTL_MS = 3600 * 1e3; | ||
| const BINARY_EXTENSIONS = new Set([ | ||
| ".png", | ||
| ".jpg", | ||
| ".jpeg", | ||
| ".gif", | ||
| ".webp", | ||
| ".ico", | ||
| ".svg", | ||
| ".woff", | ||
| ".woff2", | ||
| ".ttf", | ||
| ".eot", | ||
| ".otf", | ||
| ".pdf", | ||
| ".zip", | ||
| ".tar", | ||
| ".gz", | ||
| ".mp3", | ||
| ".mp4", | ||
| ".wav", | ||
| ".ogg", | ||
| ".webm" | ||
| ]); | ||
| const BINARY_PREFIX = "base64:"; | ||
| /** | ||
| * Check if a file should be treated as binary based on extension | ||
| */ | ||
| function isBinaryFile(filePath) { | ||
| return BINARY_EXTENSIONS.has(extname(filePath).toLowerCase()); | ||
| } | ||
| /** | ||
| * Check if a path is a local directory | ||
| */ | ||
| function isLocalPath(path) { | ||
| return path.startsWith("/") || path.startsWith("./") || path.startsWith(".."); | ||
| } | ||
| /** | ||
| * Fetch the integration manifest from GitHub or local path (with caching for remote) | ||
| */ | ||
| async function fetchManifest(baseUrl = GITHUB_RAW_BASE) { | ||
| if (isLocalPath(baseUrl)) { | ||
| const manifestPath = join(baseUrl, "manifest.json"); | ||
| if (!existsSync(manifestPath)) throw new Error(`Manifest not found at ${manifestPath}`); | ||
| const data = JSON.parse(readFileSync(manifestPath, "utf-8")); | ||
| return ManifestSchema.parse(data); | ||
| } | ||
| return fetchWithCache(`manifest_${baseUrl.replace(/[^a-zA-Z0-9]/g, "_")}`, async () => { | ||
| const url = `${baseUrl}/manifest.json`; | ||
| const response = await fetch(url); | ||
| if (!response.ok) throw new Error(`Failed to fetch manifest: ${response.statusText}`); | ||
| const data = await response.json(); | ||
| return ManifestSchema.parse(data); | ||
| }, CACHE_TTL_MS); | ||
| } | ||
| /** | ||
| * Fetch integration info.json from GitHub or local path (with caching for remote) | ||
| */ | ||
| async function fetchIntegrationInfo(integrationId, baseUrl = GITHUB_RAW_BASE) { | ||
| if (isLocalPath(baseUrl)) { | ||
| const infoPath = join(baseUrl, integrationId, "info.json"); | ||
| if (!existsSync(infoPath)) throw new Error(`Integration info not found at ${infoPath}`); | ||
| const data = JSON.parse(readFileSync(infoPath, "utf-8")); | ||
| return IntegrationInfoSchema.parse(data); | ||
| } | ||
| return fetchWithCache(`integration_info_${integrationId}_${baseUrl.replace(/[^a-zA-Z0-9]/g, "_")}`, async () => { | ||
| const url = `${baseUrl}/${integrationId}/info.json`; | ||
| const response = await fetch(url); | ||
| if (!response.ok) throw new Error(`Failed to fetch integration ${integrationId}: ${response.statusText}`); | ||
| const data = await response.json(); | ||
| return IntegrationInfoSchema.parse(data); | ||
| }, CACHE_TTL_MS); | ||
| } | ||
| /** | ||
| * Recursively read all files from a directory | ||
| * Binary files are read as base64 with a prefix marker | ||
| */ | ||
| function readDirRecursive(dir, basePath = "") { | ||
| const files = {}; | ||
| if (!existsSync(dir)) return files; | ||
| for (const entry of readdirSync(dir)) { | ||
| const fullPath = join(dir, entry); | ||
| const relativePath = basePath ? `${basePath}/${entry}` : entry; | ||
| if (statSync(fullPath).isDirectory()) Object.assign(files, readDirRecursive(fullPath, relativePath)); | ||
| else if (isBinaryFile(relativePath)) files[relativePath] = BINARY_PREFIX + readFileSync(fullPath).toString("base64"); | ||
| else files[relativePath] = readFileSync(fullPath, "utf-8"); | ||
| } | ||
| return files; | ||
| } | ||
| /** | ||
| * Fetch all files for an integration from GitHub or local path (with caching for remote) | ||
| */ | ||
| async function fetchIntegrationFiles(integrationId, baseUrl = GITHUB_RAW_BASE) { | ||
| if (isLocalPath(baseUrl)) return readDirRecursive(join(baseUrl, integrationId, "assets")); | ||
| return fetchWithCache(`integration_files_${integrationId}_${baseUrl.replace(/[^a-zA-Z0-9]/g, "_")}`, async () => { | ||
| const filesUrl = `${baseUrl}/${integrationId}/files.json`; | ||
| const response = await fetch(filesUrl); | ||
| if (!response.ok) return {}; | ||
| const fileList = await response.json(); | ||
| const files = {}; | ||
| await Promise.all(fileList.map(async (filePath) => { | ||
| const fileUrl = `${baseUrl}/${integrationId}/assets/${filePath}`; | ||
| const fileResponse = await fetch(fileUrl); | ||
| if (fileResponse.ok) if (isBinaryFile(filePath)) { | ||
| const buffer = await fileResponse.arrayBuffer(); | ||
| files[filePath] = BINARY_PREFIX + Buffer.from(buffer).toString("base64"); | ||
| } else files[filePath] = await fileResponse.text(); | ||
| })); | ||
| return files; | ||
| }, CACHE_TTL_MS); | ||
| } | ||
| /** | ||
| * Fetch integration package.json if it exists | ||
| */ | ||
| async function fetchIntegrationPackageJson(integrationId, baseUrl) { | ||
| if (isLocalPath(baseUrl)) { | ||
| const pkgPath = join(baseUrl, integrationId, "package.json"); | ||
| if (existsSync(pkgPath)) return JSON.parse(readFileSync(pkgPath, "utf-8")); | ||
| return null; | ||
| } | ||
| const url = `${baseUrl}/${integrationId}/package.json`; | ||
| const response = await fetch(url); | ||
| if (!response.ok) return null; | ||
| return response.json(); | ||
| } | ||
| /** | ||
| * Fetch a complete compiled integration from GitHub | ||
| */ | ||
| async function fetchIntegration(integrationId, baseUrl = GITHUB_RAW_BASE) { | ||
| const [info, files, pkgJson] = await Promise.all([ | ||
| fetchIntegrationInfo(integrationId, baseUrl), | ||
| fetchIntegrationFiles(integrationId, baseUrl), | ||
| fetchIntegrationPackageJson(integrationId, baseUrl) | ||
| ]); | ||
| const packageAdditions = info.packageAdditions ?? {}; | ||
| if (pkgJson) { | ||
| if (pkgJson.dependencies) packageAdditions.dependencies = { | ||
| ...packageAdditions.dependencies, | ||
| ...pkgJson.dependencies | ||
| }; | ||
| if (pkgJson.devDependencies) packageAdditions.devDependencies = { | ||
| ...packageAdditions.devDependencies, | ||
| ...pkgJson.devDependencies | ||
| }; | ||
| if (pkgJson.scripts) packageAdditions.scripts = { | ||
| ...packageAdditions.scripts, | ||
| ...pkgJson.scripts | ||
| }; | ||
| } | ||
| return IntegrationCompiledSchema.parse({ | ||
| ...info, | ||
| id: integrationId, | ||
| files, | ||
| packageAdditions: Object.keys(packageAdditions).length > 0 ? packageAdditions : void 0, | ||
| deletedFiles: [] | ||
| }); | ||
| } | ||
| /** | ||
| * Fetch multiple integrations in parallel | ||
| */ | ||
| async function fetchIntegrations(integrationIds, baseUrl = GITHUB_RAW_BASE) { | ||
| return Promise.all(integrationIds.map((id) => fetchIntegration(id, baseUrl))); | ||
| } | ||
| //#endregion | ||
| export { RouterModeSchema as S, IntegrationPhaseSchema as _, fetchIntegrations as a, ManifestSchema as b, CommandSchema as c, EnvVarSchema as d, HookSchema as f, IntegrationOptionsSchema as g, IntegrationOptionSchema as h, fetchIntegrationInfo as i, CustomTemplateCompiledSchema as l, IntegrationInfoSchema as m, fetchIntegration as n, fetchManifest as o, IntegrationCompiledSchema as p, fetchIntegrationFiles as r, CategorySchema as s, BINARY_PREFIX as t, CustomTemplateInfoSchema as u, IntegrationTypeSchema as v, RouteSchema as x, ManifestIntegrationSchema as y }; |
| import { a as fetchIntegrations, i as fetchIntegrationInfo, n as fetchIntegration, o as fetchManifest, r as fetchIntegrationFiles, t as BINARY_PREFIX } from "./fetch-DhlVXS6S.mjs"; | ||
| export { BINARY_PREFIX }; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
+15
-7
| #!/usr/bin/env node | ||
| const require_template = require('./template-Cup47s9h.cjs'); | ||
| const require_template = require('./template-lWrIZhCQ.cjs'); | ||
| const require_fetch = require('./fetch-DG5dLrsb.cjs'); | ||
| let node_fs = require("node:fs"); | ||
@@ -87,3 +88,3 @@ let node_path = require("node:path"); | ||
| try { | ||
| manifest = await require_template.fetchManifest(integrationsPath); | ||
| manifest = await require_fetch.fetchManifest(integrationsPath); | ||
| s.stop("Integrations loaded"); | ||
@@ -230,3 +231,3 @@ } catch (error$1) { | ||
| if (resolvedIds.size > 0) try { | ||
| chosenIntegrations = await require_template.fetchIntegrations(Array.from(resolvedIds), integrationsPath); | ||
| chosenIntegrations = await require_fetch.fetchIntegrations(Array.from(resolvedIds), integrationsPath); | ||
| } catch (error$1) { | ||
@@ -255,3 +256,6 @@ s.stop("Failed to fetch integration details"); | ||
| (0, node_fs.mkdirSync)((0, node_path.resolve)(fullPath, ".."), { recursive: true }); | ||
| (0, node_fs.writeFileSync)(fullPath, content, "utf-8"); | ||
| if (content.startsWith(require_fetch.BINARY_PREFIX)) { | ||
| const base64Data = content.slice(require_fetch.BINARY_PREFIX.length); | ||
| (0, node_fs.writeFileSync)(fullPath, Buffer.from(base64Data, "base64")); | ||
| } else (0, node_fs.writeFileSync)(fullPath, content, "utf-8"); | ||
| } | ||
@@ -614,3 +618,3 @@ await require_template.writeConfigFile(targetDir, compileOptions); | ||
| try { | ||
| const integrations = (await require_template.fetchManifest()).integrations.filter((a) => a.modes.includes("file-router")).map((integration) => ({ | ||
| const integrations = (await require_fetch.fetchManifest()).integrations.filter((a) => a.modes.includes("file-router")).map((integration) => ({ | ||
| id: integration.id, | ||
@@ -653,5 +657,6 @@ name: integration.name, | ||
| const { resolve: resolve$2 } = await import("node:path"); | ||
| const { BINARY_PREFIX: BINARY_PREFIX$1 } = await Promise.resolve().then(() => require("./fetch-CbFFGJEw.cjs")); | ||
| const { execSync } = await import("node:child_process"); | ||
| let chosenIntegrations = []; | ||
| if (integrations?.length) chosenIntegrations = await require_template.fetchIntegrations(integrations); | ||
| if (integrations?.length) chosenIntegrations = await require_fetch.fetchIntegrations(integrations); | ||
| const output = require_template.compile({ | ||
@@ -671,3 +676,6 @@ projectName, | ||
| mkdirSync$1(resolve$2(fullPath, ".."), { recursive: true }); | ||
| writeFileSync$1(fullPath, content, "utf-8"); | ||
| if (content.startsWith(BINARY_PREFIX$1)) { | ||
| const base64Data = content.slice(BINARY_PREFIX$1.length); | ||
| writeFileSync$1(fullPath, Buffer.from(base64Data, "base64")); | ||
| } else writeFileSync$1(fullPath, content, "utf-8"); | ||
| } | ||
@@ -674,0 +682,0 @@ try { |
+11
-3
| #!/usr/bin/env node | ||
| import { A as writeConfigFile, a as initIntegration, d as fetchManifest, i as compileIntegration, j as compile, n as initTemplate, r as loadTemplate, t as compileTemplate, u as fetchIntegrations } from "./template-CkAkdP8n.mjs"; | ||
| import { a as initIntegration, i as compileIntegration, l as writeConfigFile, n as initTemplate, r as loadTemplate, t as compileTemplate, u as compile } from "./template-Szi7-AZJ.mjs"; | ||
| import { a as fetchIntegrations, o as fetchManifest, t as BINARY_PREFIX } from "./fetch-DhlVXS6S.mjs"; | ||
| import { existsSync, mkdirSync, writeFileSync } from "node:fs"; | ||
@@ -251,3 +252,6 @@ import { resolve } from "node:path"; | ||
| mkdirSync(resolve(fullPath, ".."), { recursive: true }); | ||
| writeFileSync(fullPath, content, "utf-8"); | ||
| if (content.startsWith(BINARY_PREFIX)) { | ||
| const base64Data = content.slice(BINARY_PREFIX.length); | ||
| writeFileSync(fullPath, Buffer.from(base64Data, "base64")); | ||
| } else writeFileSync(fullPath, content, "utf-8"); | ||
| } | ||
@@ -648,2 +652,3 @@ await writeConfigFile(targetDir, compileOptions); | ||
| const { resolve: resolve$1 } = await import("node:path"); | ||
| const { BINARY_PREFIX: BINARY_PREFIX$1 } = await import("./fetch-I_OVg8JX.mjs"); | ||
| const { execSync } = await import("node:child_process"); | ||
@@ -666,3 +671,6 @@ let chosenIntegrations = []; | ||
| mkdirSync$1(resolve$1(fullPath, ".."), { recursive: true }); | ||
| writeFileSync$1(fullPath, content, "utf-8"); | ||
| if (content.startsWith(BINARY_PREFIX$1)) { | ||
| const base64Data = content.slice(BINARY_PREFIX$1.length); | ||
| writeFileSync$1(fullPath, Buffer.from(base64Data, "base64")); | ||
| } else writeFileSync$1(fullPath, content, "utf-8"); | ||
| } | ||
@@ -669,0 +677,0 @@ try { |
+23
-22
@@ -1,20 +0,21 @@ | ||
| const require_template = require('./template-Cup47s9h.cjs'); | ||
| const require_template = require('./template-lWrIZhCQ.cjs'); | ||
| const require_fetch = require('./fetch-DG5dLrsb.cjs'); | ||
| exports.CONFIG_FILE = require_template.CONFIG_FILE; | ||
| exports.CategorySchema = require_template.CategorySchema; | ||
| exports.CommandSchema = require_template.CommandSchema; | ||
| exports.CustomTemplateCompiledSchema = require_template.CustomTemplateCompiledSchema; | ||
| exports.CustomTemplateInfoSchema = require_template.CustomTemplateInfoSchema; | ||
| exports.EnvVarSchema = require_template.EnvVarSchema; | ||
| exports.HookSchema = require_template.HookSchema; | ||
| exports.IntegrationCompiledSchema = require_template.IntegrationCompiledSchema; | ||
| exports.IntegrationInfoSchema = require_template.IntegrationInfoSchema; | ||
| exports.IntegrationOptionSchema = require_template.IntegrationOptionSchema; | ||
| exports.IntegrationOptionsSchema = require_template.IntegrationOptionsSchema; | ||
| exports.IntegrationPhaseSchema = require_template.IntegrationPhaseSchema; | ||
| exports.IntegrationTypeSchema = require_template.IntegrationTypeSchema; | ||
| exports.ManifestIntegrationSchema = require_template.ManifestIntegrationSchema; | ||
| exports.ManifestSchema = require_template.ManifestSchema; | ||
| exports.RouteSchema = require_template.RouteSchema; | ||
| exports.RouterModeSchema = require_template.RouterModeSchema; | ||
| exports.CategorySchema = require_fetch.CategorySchema; | ||
| exports.CommandSchema = require_fetch.CommandSchema; | ||
| exports.CustomTemplateCompiledSchema = require_fetch.CustomTemplateCompiledSchema; | ||
| exports.CustomTemplateInfoSchema = require_fetch.CustomTemplateInfoSchema; | ||
| exports.EnvVarSchema = require_fetch.EnvVarSchema; | ||
| exports.HookSchema = require_fetch.HookSchema; | ||
| exports.IntegrationCompiledSchema = require_fetch.IntegrationCompiledSchema; | ||
| exports.IntegrationInfoSchema = require_fetch.IntegrationInfoSchema; | ||
| exports.IntegrationOptionSchema = require_fetch.IntegrationOptionSchema; | ||
| exports.IntegrationOptionsSchema = require_fetch.IntegrationOptionsSchema; | ||
| exports.IntegrationPhaseSchema = require_fetch.IntegrationPhaseSchema; | ||
| exports.IntegrationTypeSchema = require_fetch.IntegrationTypeSchema; | ||
| exports.ManifestIntegrationSchema = require_fetch.ManifestIntegrationSchema; | ||
| exports.ManifestSchema = require_fetch.ManifestSchema; | ||
| exports.RouteSchema = require_fetch.RouteSchema; | ||
| exports.RouterModeSchema = require_fetch.RouterModeSchema; | ||
| exports.compile = require_template.compile; | ||
@@ -24,7 +25,7 @@ exports.compileIntegration = require_template.compileIntegration; | ||
| exports.compileWithAttribution = require_template.compileWithAttribution; | ||
| exports.fetchIntegration = require_template.fetchIntegration; | ||
| exports.fetchIntegrationFiles = require_template.fetchIntegrationFiles; | ||
| exports.fetchIntegrationInfo = require_template.fetchIntegrationInfo; | ||
| exports.fetchIntegrations = require_template.fetchIntegrations; | ||
| exports.fetchManifest = require_template.fetchManifest; | ||
| exports.fetchIntegration = require_fetch.fetchIntegration; | ||
| exports.fetchIntegrationFiles = require_fetch.fetchIntegrationFiles; | ||
| exports.fetchIntegrationInfo = require_fetch.fetchIntegrationInfo; | ||
| exports.fetchIntegrations = require_fetch.fetchIntegrations; | ||
| exports.fetchManifest = require_fetch.fetchManifest; | ||
| exports.initIntegration = require_template.initIntegration; | ||
@@ -31,0 +32,0 @@ exports.initTemplate = require_template.initTemplate; |
+2
-1
@@ -1,3 +0,4 @@ | ||
| import { A as writeConfigFile, C as IntegrationTypeSchema, D as RouterModeSchema, E as RouteSchema, M as compileWithAttribution, N as processTemplateFile, O as CONFIG_FILE, P as relativePath, S as IntegrationPhaseSchema, T as ManifestSchema, _ as HookSchema, a as initIntegration, b as IntegrationOptionSchema, c as fetchIntegrationFiles, d as fetchManifest, f as CategorySchema, g as EnvVarSchema, h as CustomTemplateInfoSchema, i as compileIntegration, j as compile, k as readConfigFile, l as fetchIntegrationInfo, m as CustomTemplateCompiledSchema, n as initTemplate, o as loadRemoteIntegration, p as CommandSchema, r as loadTemplate, s as fetchIntegration, t as compileTemplate, u as fetchIntegrations, v as IntegrationCompiledSchema, w as ManifestIntegrationSchema, x as IntegrationOptionsSchema, y as IntegrationInfoSchema } from "./template-CkAkdP8n.mjs"; | ||
| import { a as initIntegration, c as readConfigFile, d as compileWithAttribution, f as processTemplateFile, i as compileIntegration, l as writeConfigFile, n as initTemplate, o as loadRemoteIntegration, p as relativePath, r as loadTemplate, s as CONFIG_FILE, t as compileTemplate, u as compile } from "./template-Szi7-AZJ.mjs"; | ||
| import { S as RouterModeSchema, _ as IntegrationPhaseSchema, a as fetchIntegrations, b as ManifestSchema, c as CommandSchema, d as EnvVarSchema, f as HookSchema, g as IntegrationOptionsSchema, h as IntegrationOptionSchema, i as fetchIntegrationInfo, l as CustomTemplateCompiledSchema, m as IntegrationInfoSchema, n as fetchIntegration, o as fetchManifest, p as IntegrationCompiledSchema, r as fetchIntegrationFiles, s as CategorySchema, u as CustomTemplateInfoSchema, v as IntegrationTypeSchema, x as RouteSchema, y as ManifestIntegrationSchema } from "./fetch-DhlVXS6S.mjs"; | ||
| export { CONFIG_FILE, CategorySchema, CommandSchema, CustomTemplateCompiledSchema, CustomTemplateInfoSchema, EnvVarSchema, HookSchema, IntegrationCompiledSchema, IntegrationInfoSchema, IntegrationOptionSchema, IntegrationOptionsSchema, IntegrationPhaseSchema, IntegrationTypeSchema, ManifestIntegrationSchema, ManifestSchema, RouteSchema, RouterModeSchema, compile, compileIntegration, compileTemplate, compileWithAttribution, fetchIntegration, fetchIntegrationFiles, fetchIntegrationInfo, fetchIntegrations, fetchManifest, initIntegration, initTemplate, loadRemoteIntegration, loadTemplate, processTemplateFile, readConfigFile, relativePath, writeConfigFile }; |
+1
-1
| { | ||
| "name": "@tanstack/cli", | ||
| "version": "0.0.7", | ||
| "version": "0.0.8", | ||
| "description": "TanStack CLI for scaffolding and tooling", | ||
@@ -5,0 +5,0 @@ "author": "Tanner Linsley", |
+31
-2
| import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs' | ||
| import { join } from 'node:path' | ||
| import { extname, join } from 'node:path' | ||
| import { | ||
@@ -17,3 +17,21 @@ IntegrationCompiledSchema, | ||
| // Binary file extensions that should be read as base64 | ||
| const BINARY_EXTENSIONS = new Set([ | ||
| '.png', '.jpg', '.jpeg', '.gif', '.webp', '.ico', '.svg', | ||
| '.woff', '.woff2', '.ttf', '.eot', '.otf', | ||
| '.pdf', '.zip', '.tar', '.gz', | ||
| '.mp3', '.mp4', '.wav', '.ogg', '.webm', | ||
| ]) | ||
| // Prefix for base64-encoded binary files | ||
| export const BINARY_PREFIX = 'base64:' | ||
| /** | ||
| * Check if a file should be treated as binary based on extension | ||
| */ | ||
| function isBinaryFile(filePath: string): boolean { | ||
| return BINARY_EXTENSIONS.has(extname(filePath).toLowerCase()) | ||
| } | ||
| /** | ||
| * Check if a path is a local directory | ||
@@ -96,2 +114,3 @@ */ | ||
| * Recursively read all files from a directory | ||
| * Binary files are read as base64 with a prefix marker | ||
| */ | ||
@@ -113,2 +132,6 @@ function readDirRecursive( | ||
| Object.assign(files, readDirRecursive(fullPath, relativePath)) | ||
| } else if (isBinaryFile(relativePath)) { | ||
| // Read binary files as base64 with prefix | ||
| const buffer = readFileSync(fullPath) | ||
| files[relativePath] = BINARY_PREFIX + buffer.toString('base64') | ||
| } else { | ||
@@ -158,3 +181,9 @@ files[relativePath] = readFileSync(fullPath, 'utf-8') | ||
| if (fileResponse.ok) { | ||
| files[filePath] = await fileResponse.text() | ||
| if (isBinaryFile(filePath)) { | ||
| // Fetch binary files as arrayBuffer and convert to base64 | ||
| const buffer = await fileResponse.arrayBuffer() | ||
| files[filePath] = BINARY_PREFIX + Buffer.from(buffer).toString('base64') | ||
| } else { | ||
| files[filePath] = await fileResponse.text() | ||
| } | ||
| } | ||
@@ -161,0 +190,0 @@ }), |
@@ -17,3 +17,3 @@ import { resolve } from 'node:path' | ||
| import chalk from 'chalk' | ||
| import { fetchIntegrations, fetchManifest } from '../api/fetch.js' | ||
| import { BINARY_PREFIX, fetchIntegrations, fetchManifest } from '../api/fetch.js' | ||
| import { compile } from '../engine/compile.js' | ||
@@ -387,3 +387,10 @@ import { writeConfigFile } from '../engine/config-file.js' | ||
| mkdirSync(dir, { recursive: true }) | ||
| writeFileSync(fullPath, content, 'utf-8') | ||
| // Handle binary files (base64 encoded with prefix) | ||
| if (content.startsWith(BINARY_PREFIX)) { | ||
| const base64Data = content.slice(BINARY_PREFIX.length) | ||
| writeFileSync(fullPath, Buffer.from(base64Data, 'base64')) | ||
| } else { | ||
| writeFileSync(fullPath, content, 'utf-8') | ||
| } | ||
| } | ||
@@ -390,0 +397,0 @@ |
@@ -97,2 +97,3 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js' | ||
| const { resolve } = await import('node:path') | ||
| const { BINARY_PREFIX } = await import('../api/fetch.js') | ||
| const { execSync } = await import('node:child_process') | ||
@@ -125,3 +126,10 @@ | ||
| mkdirSync(dir, { recursive: true }) | ||
| writeFileSync(fullPath, content, 'utf-8') | ||
| // Handle binary files (base64 encoded with prefix) | ||
| if (content.startsWith(BINARY_PREFIX)) { | ||
| const base64Data = content.slice(BINARY_PREFIX.length) | ||
| writeFileSync(fullPath, Buffer.from(base64Data, 'base64')) | ||
| } else { | ||
| writeFileSync(fullPath, content, 'utf-8') | ||
| } | ||
| } | ||
@@ -128,0 +136,0 @@ |
@@ -132,2 +132,3 @@ import { getBaseFiles, getBaseFilesWithAttribution } from '../templates/base.js' | ||
| '@tanstack/react-router-devtools': '^1.132.0', | ||
| '@tanstack/react-devtools': '^0.9.2', | ||
| '@tanstack/react-start': '^1.132.0', | ||
@@ -250,2 +251,19 @@ react: '^19.2.0', | ||
| // Generate .env.example with integration env vars | ||
| if (uniqueEnvVars.length > 0) { | ||
| const envLines: Array<string> = [ | ||
| '# Environment Variables', | ||
| '# Copy this file to .env.local and fill in your values', | ||
| '', | ||
| ] | ||
| for (const v of uniqueEnvVars) { | ||
| envLines.push(`# ${v.description}${v.required ? ' (required)' : ''}`) | ||
| envLines.push(`${v.name}=${v.example || ''}`) | ||
| envLines.push('') | ||
| } | ||
| outputFiles['.env.example'] = envLines.join('\n') | ||
| } | ||
| return { | ||
@@ -252,0 +270,0 @@ files: outputFiles, |
+11
-19
@@ -166,7 +166,5 @@ /** | ||
| if (devtoolsPlugins.length > 0) { | ||
| lines.push({ text: `import React from 'react'`, integrationId: 'base' }) | ||
| } | ||
| lines.push({ text: `import { HeadContent, Scripts, createRootRoute } from '@tanstack/react-router'`, integrationId: 'base' }) | ||
| lines.push({ text: `import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'`, integrationId: 'base' }) | ||
| lines.push({ text: `import { TanStackDevtools } from '@tanstack/react-devtools'`, integrationId: 'base' }) | ||
| lines.push({ text: `import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'`, integrationId: 'base' }) | ||
@@ -198,12 +196,2 @@ lines.push({ text: `import appCss from '../styles.css?url'`, integrationId: 'base' }) | ||
| // Devtools array | ||
| if (devtoolsPlugins.length > 0) { | ||
| lines.push({ text: '', integrationId: 'base' }) | ||
| lines.push({ text: `const devtoolsPlugins = [`, integrationId: 'base' }) | ||
| for (const devtools of devtoolsPlugins) { | ||
| lines.push({ text: ` ${devtools.jsName},`, integrationId: devtools.integrationId }) | ||
| } | ||
| lines.push({ text: `]`, integrationId: 'base' }) | ||
| } | ||
| lines.push({ text: '', integrationId: 'base' }) | ||
@@ -242,9 +230,13 @@ lines.push({ text: `export const Route = createRootRoute({`, integrationId: 'base' }) | ||
| lines.push({ text: `${currentIndent}{children}`, integrationId: 'base' }) | ||
| lines.push({ text: `${currentIndent}<TanStackRouterDevtools />`, integrationId: 'base' }) | ||
| if (devtoolsPlugins.length > 0) { | ||
| lines.push({ text: `${currentIndent}{devtoolsPlugins.map((plugin, i) => (`, integrationId: 'base' }) | ||
| lines.push({ text: `${currentIndent} <React.Fragment key={i}>{plugin.render}</React.Fragment>`, integrationId: 'base' }) | ||
| lines.push({ text: `${currentIndent}))}`, integrationId: 'base' }) | ||
| // TanStack unified devtools with plugins | ||
| lines.push({ text: `${currentIndent}<TanStackDevtools`, integrationId: 'base' }) | ||
| lines.push({ text: `${currentIndent} config={{ position: 'bottom-right' }}`, integrationId: 'base' }) | ||
| lines.push({ text: `${currentIndent} plugins={[`, integrationId: 'base' }) | ||
| lines.push({ text: `${currentIndent} { name: 'TanStack Router', render: <TanStackRouterDevtoolsPanel /> },`, integrationId: 'base' }) | ||
| for (const devtools of devtoolsPlugins) { | ||
| lines.push({ text: `${currentIndent} ${devtools.jsName},`, integrationId: devtools.integrationId }) | ||
| } | ||
| lines.push({ text: `${currentIndent} ]}`, integrationId: 'base' }) | ||
| lines.push({ text: `${currentIndent}/>`, integrationId: 'base' }) | ||
@@ -251,0 +243,0 @@ for (const provider of [...rootProviders].reverse()) { |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
563174
1.18%41
10.81%12533
1.32%43
-2.27%96
12.94%