@tanstack/cli 0.0.2 → 0.0.3
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/bin.cjs +293 -2
- package/dist/bin.mjs +293 -2
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +17 -17
- package/dist/index.d.mts +17 -17
- package/dist/index.mjs +1 -1
- package/dist/{template-BYKvtZrT.cjs → template-B-i2qO8E.cjs} +83 -34
- package/dist/{template-2SxOxCJc.mjs → template-BgEATWaG.mjs} +83 -34
- package/package.json +1 -1
- package/src/api/fetch.test.ts +3 -3
- package/src/api/fetch.ts +65 -37
- package/src/cache/index.ts +89 -0
- package/src/commands/create.ts +1 -1
- package/src/commands/mcp.test.ts +3 -3
- package/src/commands/mcp.ts +5 -1
- package/src/engine/compile-with-addons.test.ts +7 -7
- package/src/engine/compile.test.ts +1 -1
- package/src/engine/compile.ts +6 -6
- package/src/engine/custom-addons/shared.ts +1 -1
- package/src/engine/template.test.ts +1 -1
- package/src/engine/template.ts +1 -1
- package/src/engine/types.ts +6 -4
- package/src/mcp/api.ts +42 -0
- package/src/mcp/tools.ts +323 -0
- package/src/mcp/types.ts +46 -0
- package/src/templates/base.ts +3 -0
package/src/engine/types.ts
CHANGED
|
@@ -156,9 +156,11 @@ export const IntegrationInfoSchema = z.object({
|
|
|
156
156
|
requiresTailwind: z.boolean().optional(),
|
|
157
157
|
demoRequiresTailwind: z.boolean().optional(),
|
|
158
158
|
|
|
159
|
-
// Dependencies
|
|
159
|
+
// Dependencies
|
|
160
160
|
dependsOn: z.array(z.string()).optional(),
|
|
161
|
-
|
|
161
|
+
// Exclusive types - only one integration per exclusive type can be selected
|
|
162
|
+
// e.g., exclusive: ['deploy'] means only one deploy integration at a time
|
|
163
|
+
exclusive: z.array(z.string()).optional(),
|
|
162
164
|
|
|
163
165
|
// Partner integration
|
|
164
166
|
partnerId: z.string().optional(),
|
|
@@ -250,7 +252,8 @@ export const ManifestIntegrationSchema = z.object({
|
|
|
250
252
|
category: CategorySchema.optional(),
|
|
251
253
|
modes: z.array(RouterModeSchema),
|
|
252
254
|
dependsOn: z.array(z.string()).optional(),
|
|
253
|
-
|
|
255
|
+
// Exclusive types - only one integration per exclusive type can be selected
|
|
256
|
+
exclusive: z.array(z.string()).optional(),
|
|
254
257
|
partnerId: z.string().optional(),
|
|
255
258
|
hasOptions: z.boolean().optional(),
|
|
256
259
|
link: z.string().optional(),
|
|
@@ -269,7 +272,6 @@ export const ManifestCustomTemplateSchema = z.object({
|
|
|
269
272
|
icon: z.string().optional(),
|
|
270
273
|
features: z.array(z.string()).optional(),
|
|
271
274
|
})
|
|
272
|
-
export type ManifestCustomTemplate = z.infer<typeof ManifestCustomTemplateSchema>
|
|
273
275
|
|
|
274
276
|
export const ManifestSchema = z.object({
|
|
275
277
|
version: z.string(),
|
package/src/mcp/api.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { LibrariesResponseSchema, PartnersResponseSchema } from './types.js'
|
|
2
|
+
import type { LibrariesResponse, PartnersResponse } from './types.js'
|
|
3
|
+
|
|
4
|
+
const TANSTACK_API_BASE = 'https://tanstack.com/api/data'
|
|
5
|
+
|
|
6
|
+
export async function fetchLibraries(): Promise<LibrariesResponse> {
|
|
7
|
+
const response = await fetch(`${TANSTACK_API_BASE}/libraries`)
|
|
8
|
+
if (!response.ok) {
|
|
9
|
+
throw new Error(`Failed to fetch libraries: ${response.statusText}`)
|
|
10
|
+
}
|
|
11
|
+
const data = await response.json()
|
|
12
|
+
return LibrariesResponseSchema.parse(data)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function fetchPartners(): Promise<PartnersResponse> {
|
|
16
|
+
const response = await fetch(`${TANSTACK_API_BASE}/partners`)
|
|
17
|
+
if (!response.ok) {
|
|
18
|
+
throw new Error(`Failed to fetch partners: ${response.statusText}`)
|
|
19
|
+
}
|
|
20
|
+
const data = await response.json()
|
|
21
|
+
return PartnersResponseSchema.parse(data)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function fetchDocContent(
|
|
25
|
+
repo: string,
|
|
26
|
+
branch: string,
|
|
27
|
+
filePath: string,
|
|
28
|
+
): Promise<string | null> {
|
|
29
|
+
const url = `https://raw.githubusercontent.com/${repo}/${branch}/${filePath}`
|
|
30
|
+
const response = await fetch(url, {
|
|
31
|
+
headers: { 'User-Agent': 'tanstack-cli' },
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
if (response.status === 404) {
|
|
36
|
+
return null
|
|
37
|
+
}
|
|
38
|
+
throw new Error(`Failed to fetch doc: ${response.statusText}`)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return response.text()
|
|
42
|
+
}
|
package/src/mcp/tools.ts
ADDED
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import { fetchDocContent, fetchLibraries, fetchPartners } from './api.js'
|
|
3
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
4
|
+
|
|
5
|
+
// Algolia config (public read-only keys)
|
|
6
|
+
const ALGOLIA_APP_ID = 'FQ0DQ6MA3C'
|
|
7
|
+
const ALGOLIA_API_KEY = '10c34d6a5c89f6048cf644d601e65172'
|
|
8
|
+
const ALGOLIA_INDEX = 'tanstack-test'
|
|
9
|
+
|
|
10
|
+
const GROUP_KEYS = ['state', 'headlessUI', 'performance', 'tooling'] as const
|
|
11
|
+
|
|
12
|
+
function jsonResult(data: unknown) {
|
|
13
|
+
return { content: [{ type: 'text' as const, text: JSON.stringify(data, null, 2) }] }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function errorResult(error: string) {
|
|
17
|
+
return { content: [{ type: 'text' as const, text: `Error: ${error}` }], isError: true }
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function registerDocTools(server: McpServer) {
|
|
21
|
+
// Tool: tanstack_list_libraries
|
|
22
|
+
server.tool(
|
|
23
|
+
'tanstack_list_libraries',
|
|
24
|
+
'List TanStack libraries with metadata, frameworks, and docs URLs.',
|
|
25
|
+
{
|
|
26
|
+
group: z
|
|
27
|
+
.enum(GROUP_KEYS)
|
|
28
|
+
.optional()
|
|
29
|
+
.describe('Filter libraries by group. Options: state, headlessUI, performance, tooling'),
|
|
30
|
+
},
|
|
31
|
+
async ({ group }) => {
|
|
32
|
+
try {
|
|
33
|
+
const data = await fetchLibraries()
|
|
34
|
+
let libraries = data.libraries
|
|
35
|
+
|
|
36
|
+
if (group && data.groups[group]) {
|
|
37
|
+
const groupIds = data.groups[group]
|
|
38
|
+
libraries = libraries.filter((lib) => groupIds.includes(lib.id))
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const groupName = group ? data.groupNames[group] || group : 'All Libraries'
|
|
42
|
+
|
|
43
|
+
return jsonResult({
|
|
44
|
+
group: groupName,
|
|
45
|
+
count: libraries.length,
|
|
46
|
+
libraries: libraries.map((lib) => ({
|
|
47
|
+
id: lib.id,
|
|
48
|
+
name: lib.name,
|
|
49
|
+
tagline: lib.tagline,
|
|
50
|
+
description: lib.description,
|
|
51
|
+
frameworks: lib.frameworks,
|
|
52
|
+
latestVersion: lib.latestVersion,
|
|
53
|
+
docsUrl: lib.docsUrl,
|
|
54
|
+
githubUrl: lib.githubUrl,
|
|
55
|
+
})),
|
|
56
|
+
})
|
|
57
|
+
} catch (error) {
|
|
58
|
+
return errorResult(String(error))
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
// Tool: tanstack_doc
|
|
64
|
+
server.tool(
|
|
65
|
+
'tanstack_doc',
|
|
66
|
+
'Fetch a TanStack documentation page by library and path.',
|
|
67
|
+
{
|
|
68
|
+
library: z.string().describe('Library ID (e.g., query, router, table, form)'),
|
|
69
|
+
path: z.string().describe('Documentation path (e.g., framework/react/overview)'),
|
|
70
|
+
version: z.string().optional().describe('Version (e.g., v5, v1). Defaults to latest'),
|
|
71
|
+
},
|
|
72
|
+
async ({ library: libraryId, path, version = 'latest' }) => {
|
|
73
|
+
try {
|
|
74
|
+
const data = await fetchLibraries()
|
|
75
|
+
const library = data.libraries.find((l) => l.id === libraryId)
|
|
76
|
+
|
|
77
|
+
if (!library) {
|
|
78
|
+
return errorResult(
|
|
79
|
+
`Library "${libraryId}" not found. Use tanstack_list_libraries to see available libraries.`,
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (version !== 'latest' && !library.availableVersions.includes(version)) {
|
|
84
|
+
return errorResult(
|
|
85
|
+
`Version "${version}" not found for ${library.name}. Available: ${library.availableVersions.join(', ')}`,
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Resolve branch
|
|
90
|
+
const branch =
|
|
91
|
+
version === 'latest' || version === library.latestVersion
|
|
92
|
+
? library.latestBranch || 'main'
|
|
93
|
+
: version
|
|
94
|
+
|
|
95
|
+
const docsRoot = library.docsRoot || 'docs'
|
|
96
|
+
const filePath = `${docsRoot}/${path}.md`
|
|
97
|
+
const content = await fetchDocContent(library.repo, branch, filePath)
|
|
98
|
+
|
|
99
|
+
if (!content) {
|
|
100
|
+
return errorResult(
|
|
101
|
+
`Document not found: ${library.name} / ${path} (version: ${version})`,
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Extract frontmatter title if present
|
|
106
|
+
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/)
|
|
107
|
+
let title = path.split('/').pop() || 'Untitled'
|
|
108
|
+
let docContent = content
|
|
109
|
+
|
|
110
|
+
if (frontmatterMatch && frontmatterMatch[1]) {
|
|
111
|
+
const frontmatter = frontmatterMatch[1]
|
|
112
|
+
const titleMatch = frontmatter.match(/title:\s*['"]?([^'"\n]+)['"]?/)
|
|
113
|
+
if (titleMatch && titleMatch[1]) {
|
|
114
|
+
title = titleMatch[1]
|
|
115
|
+
}
|
|
116
|
+
docContent = content.slice(frontmatterMatch[0].length).trim()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return jsonResult({
|
|
120
|
+
title,
|
|
121
|
+
content: docContent,
|
|
122
|
+
url: `https://tanstack.com/${libraryId}/${version}/docs/${path}`,
|
|
123
|
+
library: library.name,
|
|
124
|
+
version: version === 'latest' ? library.latestVersion : version,
|
|
125
|
+
})
|
|
126
|
+
} catch (error) {
|
|
127
|
+
return errorResult(String(error))
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
// Tool: tanstack_search_docs
|
|
133
|
+
server.tool(
|
|
134
|
+
'tanstack_search_docs',
|
|
135
|
+
'Search TanStack documentation. Returns matching pages with snippets.',
|
|
136
|
+
{
|
|
137
|
+
query: z.string().describe('Search query'),
|
|
138
|
+
library: z.string().optional().describe('Filter to specific library (e.g., query, router)'),
|
|
139
|
+
framework: z
|
|
140
|
+
.string()
|
|
141
|
+
.optional()
|
|
142
|
+
.describe('Filter to specific framework (e.g., react, vue, solid)'),
|
|
143
|
+
limit: z
|
|
144
|
+
.number()
|
|
145
|
+
.min(1)
|
|
146
|
+
.max(50)
|
|
147
|
+
.optional()
|
|
148
|
+
.describe('Maximum number of results (default: 10, max: 50)'),
|
|
149
|
+
},
|
|
150
|
+
async ({ query, library, framework, limit = 10 }) => {
|
|
151
|
+
try {
|
|
152
|
+
const ALL_LIBRARIES = [
|
|
153
|
+
'config', 'form', 'optimistic', 'pacer', 'query', 'ranger',
|
|
154
|
+
'react-charts', 'router', 'start', 'store', 'table', 'virtual', 'db', 'devtools',
|
|
155
|
+
]
|
|
156
|
+
const ALL_FRAMEWORKS = ['react', 'vue', 'solid', 'svelte', 'angular']
|
|
157
|
+
|
|
158
|
+
// Build filters
|
|
159
|
+
const filterParts: Array<string> = ['version:latest']
|
|
160
|
+
|
|
161
|
+
if (library) {
|
|
162
|
+
const otherLibraries = ALL_LIBRARIES.filter((l) => l !== library)
|
|
163
|
+
const exclusions = otherLibraries.map((l) => `NOT library:${l}`).join(' AND ')
|
|
164
|
+
if (exclusions) filterParts.push(`(${exclusions})`)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (framework) {
|
|
168
|
+
const otherFrameworks = ALL_FRAMEWORKS.filter((f) => f !== framework)
|
|
169
|
+
const exclusions = otherFrameworks.map((f) => `NOT framework:${f}`).join(' AND ')
|
|
170
|
+
if (exclusions) filterParts.push(`(${exclusions})`)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Call Algolia REST API directly
|
|
174
|
+
const searchParams = {
|
|
175
|
+
requests: [
|
|
176
|
+
{
|
|
177
|
+
indexName: ALGOLIA_INDEX,
|
|
178
|
+
query,
|
|
179
|
+
hitsPerPage: Math.min(limit, 50),
|
|
180
|
+
filters: filterParts.join(' AND '),
|
|
181
|
+
attributesToRetrieve: ['hierarchy', 'url', 'content', 'library'],
|
|
182
|
+
attributesToSnippet: ['content:80'],
|
|
183
|
+
},
|
|
184
|
+
],
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const response = await fetch(
|
|
188
|
+
`https://${ALGOLIA_APP_ID}-dsn.algolia.net/1/indexes/*/queries`,
|
|
189
|
+
{
|
|
190
|
+
method: 'POST',
|
|
191
|
+
headers: {
|
|
192
|
+
'Content-Type': 'application/json',
|
|
193
|
+
'X-Algolia-Application-Id': ALGOLIA_APP_ID,
|
|
194
|
+
'X-Algolia-API-Key': ALGOLIA_API_KEY,
|
|
195
|
+
},
|
|
196
|
+
body: JSON.stringify(searchParams),
|
|
197
|
+
},
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
if (!response.ok) {
|
|
201
|
+
return errorResult(`Algolia search failed: ${response.statusText}`)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const searchResponse = await response.json() as {
|
|
205
|
+
results: Array<{
|
|
206
|
+
hits: Array<{
|
|
207
|
+
objectID: string
|
|
208
|
+
url: string
|
|
209
|
+
library?: string
|
|
210
|
+
hierarchy: Record<string, string | undefined>
|
|
211
|
+
content?: string
|
|
212
|
+
_snippetResult?: { content?: { value?: string } }
|
|
213
|
+
}>
|
|
214
|
+
nbHits?: number
|
|
215
|
+
}>
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const searchResult = searchResponse.results[0]
|
|
219
|
+
if (!searchResult) {
|
|
220
|
+
return jsonResult({ query, totalHits: 0, results: [] })
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const results = searchResult.hits.map((hit) => {
|
|
224
|
+
const breadcrumb = Object.values(hit.hierarchy).filter((v): v is string => Boolean(v))
|
|
225
|
+
return {
|
|
226
|
+
title: hit.hierarchy.lvl1 || hit.hierarchy.lvl0 || 'Untitled',
|
|
227
|
+
url: hit.url,
|
|
228
|
+
snippet: hit._snippetResult?.content?.value || hit.content || '',
|
|
229
|
+
library: hit.library || 'unknown',
|
|
230
|
+
breadcrumb,
|
|
231
|
+
}
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
return jsonResult({
|
|
235
|
+
query,
|
|
236
|
+
totalHits: searchResult.nbHits || results.length,
|
|
237
|
+
results,
|
|
238
|
+
})
|
|
239
|
+
} catch (error) {
|
|
240
|
+
return errorResult(String(error))
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
// Tool: tanstack_ecosystem
|
|
246
|
+
server.tool(
|
|
247
|
+
'tanstack_ecosystem',
|
|
248
|
+
'Ecosystem partner recommendations. Filter by category (database, auth, deployment, monitoring, cms, api, data-grid) or library.',
|
|
249
|
+
{
|
|
250
|
+
category: z
|
|
251
|
+
.string()
|
|
252
|
+
.optional()
|
|
253
|
+
.describe(
|
|
254
|
+
'Filter by category: database, auth, deployment, monitoring, cms, api, data-grid, code-review, learning',
|
|
255
|
+
),
|
|
256
|
+
library: z
|
|
257
|
+
.string()
|
|
258
|
+
.optional()
|
|
259
|
+
.describe('Filter by TanStack library (e.g., start, router, query, table)'),
|
|
260
|
+
},
|
|
261
|
+
async ({ category, library }) => {
|
|
262
|
+
try {
|
|
263
|
+
const data = await fetchPartners()
|
|
264
|
+
|
|
265
|
+
// Category aliases
|
|
266
|
+
const categoryAliases: Record<string, string> = {
|
|
267
|
+
db: 'database',
|
|
268
|
+
postgres: 'database',
|
|
269
|
+
sql: 'database',
|
|
270
|
+
login: 'auth',
|
|
271
|
+
authentication: 'auth',
|
|
272
|
+
hosting: 'deployment',
|
|
273
|
+
deploy: 'deployment',
|
|
274
|
+
serverless: 'deployment',
|
|
275
|
+
errors: 'monitoring',
|
|
276
|
+
logging: 'monitoring',
|
|
277
|
+
content: 'cms',
|
|
278
|
+
'api-keys': 'api',
|
|
279
|
+
grid: 'data-grid',
|
|
280
|
+
review: 'code-review',
|
|
281
|
+
courses: 'learning',
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
let resolvedCategory: string | undefined
|
|
285
|
+
if (category) {
|
|
286
|
+
const normalized = category.toLowerCase().trim()
|
|
287
|
+
resolvedCategory = categoryAliases[normalized] || normalized
|
|
288
|
+
if (!data.categories.includes(resolvedCategory)) {
|
|
289
|
+
resolvedCategory = undefined
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const lib = library?.toLowerCase().trim()
|
|
294
|
+
|
|
295
|
+
const partners = data.partners
|
|
296
|
+
.filter((p) => !resolvedCategory || p.category === resolvedCategory)
|
|
297
|
+
.filter((p) => !lib || p.libraries.some((l) => l === lib))
|
|
298
|
+
.map((p) => ({
|
|
299
|
+
id: p.id,
|
|
300
|
+
name: p.name,
|
|
301
|
+
tagline: p.tagline,
|
|
302
|
+
description: p.description,
|
|
303
|
+
category: p.category,
|
|
304
|
+
categoryLabel: p.categoryLabel,
|
|
305
|
+
url: p.url,
|
|
306
|
+
libraries: p.libraries,
|
|
307
|
+
}))
|
|
308
|
+
|
|
309
|
+
return jsonResult({
|
|
310
|
+
query: {
|
|
311
|
+
category,
|
|
312
|
+
categoryResolved: resolvedCategory,
|
|
313
|
+
library,
|
|
314
|
+
},
|
|
315
|
+
count: partners.length,
|
|
316
|
+
partners,
|
|
317
|
+
})
|
|
318
|
+
} catch (error) {
|
|
319
|
+
return errorResult(String(error))
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
)
|
|
323
|
+
}
|
package/src/mcp/types.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
// API response types from tanstack.com
|
|
4
|
+
export const LibrarySchema = z.object({
|
|
5
|
+
id: z.string(),
|
|
6
|
+
name: z.string(),
|
|
7
|
+
tagline: z.string(),
|
|
8
|
+
description: z.string().optional(),
|
|
9
|
+
frameworks: z.array(z.string()),
|
|
10
|
+
latestVersion: z.string(),
|
|
11
|
+
latestBranch: z.string().optional(),
|
|
12
|
+
availableVersions: z.array(z.string()),
|
|
13
|
+
repo: z.string(),
|
|
14
|
+
docsRoot: z.string().optional(),
|
|
15
|
+
defaultDocs: z.string().optional(),
|
|
16
|
+
docsUrl: z.string().optional(),
|
|
17
|
+
githubUrl: z.string().optional(),
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
export const LibrariesResponseSchema = z.object({
|
|
21
|
+
libraries: z.array(LibrarySchema),
|
|
22
|
+
groups: z.record(z.array(z.string())),
|
|
23
|
+
groupNames: z.record(z.string()),
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
export const PartnerSchema = z.object({
|
|
27
|
+
id: z.string(),
|
|
28
|
+
name: z.string(),
|
|
29
|
+
tagline: z.string().optional(),
|
|
30
|
+
description: z.string(),
|
|
31
|
+
category: z.string(),
|
|
32
|
+
categoryLabel: z.string(),
|
|
33
|
+
libraries: z.array(z.string()),
|
|
34
|
+
url: z.string(),
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
export const PartnersResponseSchema = z.object({
|
|
38
|
+
partners: z.array(PartnerSchema),
|
|
39
|
+
categories: z.array(z.string()),
|
|
40
|
+
categoryLabels: z.record(z.string()),
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
export type Library = z.infer<typeof LibrarySchema>
|
|
44
|
+
export type LibrariesResponse = z.infer<typeof LibrariesResponseSchema>
|
|
45
|
+
export type Partner = z.infer<typeof PartnerSchema>
|
|
46
|
+
export type PartnersResponse = z.infer<typeof PartnersResponseSchema>
|
package/src/templates/base.ts
CHANGED
|
@@ -841,6 +841,9 @@ ${packageManager}${packageManager === 'npm' ? ' run' : ''} dev
|
|
|
841
841
|
- [TanStack Router Documentation](https://tanstack.com/router)
|
|
842
842
|
`
|
|
843
843
|
|
|
844
|
+
// .nvmrc - Node version (TanStack Start requires 22.12.0+)
|
|
845
|
+
files['.nvmrc'] = '23'
|
|
846
|
+
|
|
844
847
|
return files
|
|
845
848
|
}
|
|
846
849
|
|