@yak-io/nextjs 0.7.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,245 +1,166 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * Yak Next.js Route Manifest Generator
4
- *
5
- * This CLI tool scans a Next.js app directory and generates a manifest
6
- * of all available page routes that can be injected into the chat context.
7
- *
8
- * Usage:
9
- * yak-nextjs generate-manifest [options]
10
- *
11
- * Options:
12
- * --app-dir <path> Path to Next.js app directory (default: ./src/app)
13
- * --pages-dir <path> Path to Next.js pages directory (optional, scanned in addition to app-dir)
14
- * --output <path> Output file path (default: ./src/yak-routes-manifest.json)
15
- */
2
+
3
+ // src/cli/generate-manifest.ts
16
4
  import * as fs from "node:fs";
17
5
  import * as path from "node:path";
18
- /**
19
- * Extract static metadata (title and description) from a Next.js page file.
20
- * Parses `export const metadata = { title: "...", description: "..." }` patterns.
21
- * Does not support dynamic generateMetadata functions.
22
- */
23
6
  function extractMetadata(filePath) {
24
- try {
25
- const content = fs.readFileSync(filePath, "utf-8");
26
- // Match `export const metadata` object
27
- const metadataMatch = content.match(/export\s+const\s+metadata\s*(?::\s*Metadata\s*)?=\s*\{([^}]*(?:\{[^}]*\}[^}]*)*)\}/s);
28
- if (!metadataMatch) {
29
- return {};
30
- }
31
- const metadataBlock = metadataMatch[1];
32
- const result = {};
33
- // Extract title - handle both single and double quotes
34
- const titleMatch = metadataBlock?.match(/title\s*:\s*["'`]([^"'`]+)["'`]/);
35
- if (titleMatch?.[1]) {
36
- result.title = titleMatch[1];
37
- }
38
- // Extract description - handle both single and double quotes
39
- const descMatch = metadataBlock?.match(/description\s*:\s*["'`]([^"'`]+)["'`]/);
40
- if (descMatch?.[1]) {
41
- result.description = descMatch[1];
42
- }
43
- return result;
7
+ try {
8
+ const content = fs.readFileSync(filePath, "utf-8");
9
+ const metadataMatch = content.match(
10
+ /export\s+const\s+metadata\s*(?::\s*Metadata\s*)?=\s*\{([^}]*(?:\{[^}]*\}[^}]*)*)\}/s
11
+ );
12
+ if (!metadataMatch) {
13
+ return {};
44
14
  }
45
- catch {
46
- return {};
15
+ const metadataBlock = metadataMatch[1];
16
+ const result = {};
17
+ const titleMatch = metadataBlock?.match(/title\s*:\s*["'`]([^"'`]+)["'`]/);
18
+ if (titleMatch?.[1]) {
19
+ result.title = titleMatch[1];
47
20
  }
21
+ const descMatch = metadataBlock?.match(/description\s*:\s*["'`]([^"'`]+)["'`]/);
22
+ if (descMatch?.[1]) {
23
+ result.description = descMatch[1];
24
+ }
25
+ return result;
26
+ } catch {
27
+ return {};
28
+ }
48
29
  }
49
- /**
50
- * Check if a path segment is a route group (organizational only, not part of URL)
51
- */
52
30
  function isRouteGroup(segment) {
53
- return segment.startsWith("(") && segment.endsWith(")");
31
+ return segment.startsWith("(") && segment.endsWith(")");
54
32
  }
55
- /**
56
- * Check if a path segment is an optional catch-all (e.g., [[...slug]])
57
- * These segments match the base path without any additional segments
58
- */
59
33
  function isOptionalCatchAll(segment) {
60
- return segment.startsWith("[[...") && segment.endsWith("]]");
34
+ return segment.startsWith("[[...") && segment.endsWith("]]");
61
35
  }
62
- /**
63
- * Check if a path segment is a required catch-all (e.g., [...slug])
64
- * These segments require at least one additional path segment
65
- */
66
36
  function isRequiredCatchAll(segment) {
67
- return segment.startsWith("[...") && segment.endsWith("]") && !segment.startsWith("[[");
37
+ return segment.startsWith("[...") && segment.endsWith("]") && !segment.startsWith("[[");
68
38
  }
69
- /**
70
- * Check if a path segment is a dynamic segment (e.g., [id])
71
- */
72
39
  function isDynamicSegment(segment) {
73
- return (segment.startsWith("[") &&
74
- segment.endsWith("]") &&
75
- !isOptionalCatchAll(segment) &&
76
- !isRequiredCatchAll(segment));
40
+ return segment.startsWith("[") && segment.endsWith("]") && !isOptionalCatchAll(segment) && !isRequiredCatchAll(segment);
77
41
  }
78
- /**
79
- * Normalize a dynamic segment for display
80
- * e.g., [id] → :id, [postId] → :postId
81
- */
82
42
  function normalizeDynamicSegment(segment) {
83
- // Extract the parameter name from [name] format
84
- const paramName = segment.slice(1, -1);
85
- return `:${paramName}`;
43
+ const paramName = segment.slice(1, -1);
44
+ return `:${paramName}`;
86
45
  }
87
- /**
88
- * Normalize a route path for display (excludes route groups and handles dynamic segments)
89
- */
90
46
  function normalizeRoutePath(segments) {
91
- // Filter out route groups - they don't appear in URLs
92
- // Filter out optional catch-all segments - they match the base path
93
- const urlSegments = segments
94
- .filter((seg) => !isRouteGroup(seg) && !isOptionalCatchAll(seg))
95
- .map((seg) => {
96
- if (isDynamicSegment(seg)) {
97
- return normalizeDynamicSegment(seg);
98
- }
99
- if (isRequiredCatchAll(seg)) {
100
- // For required catch-all, extract the name: [...slug] → :slug+
101
- const paramName = seg.slice(4, -1);
102
- return `:${paramName}+`;
103
- }
104
- return seg;
105
- });
106
- if (urlSegments.length === 0)
107
- return "/";
108
- return `/${urlSegments.join("/")}`;
47
+ const urlSegments = segments.filter((seg) => !isRouteGroup(seg) && !isOptionalCatchAll(seg)).map((seg) => {
48
+ if (isDynamicSegment(seg)) {
49
+ return normalizeDynamicSegment(seg);
50
+ }
51
+ if (isRequiredCatchAll(seg)) {
52
+ const paramName = seg.slice(4, -1);
53
+ return `:${paramName}+`;
54
+ }
55
+ return seg;
56
+ });
57
+ if (urlSegments.length === 0) return "/";
58
+ return `/${urlSegments.join("/")}`;
109
59
  }
110
- /**
111
- * Check if file is a page file
112
- */
113
60
  function isPageFile(filename) {
114
- return filename === "page.tsx" || filename === "page.js";
61
+ return filename === "page.tsx" || filename === "page.js";
115
62
  }
116
- /**
117
- * Recursively scan a directory for Next.js page routes
118
- */
119
63
  function scanDirectory(dirPath, segments = []) {
120
- const routes = [];
121
- try {
122
- const entries = fs.readdirSync(dirPath, { withFileTypes: true });
123
- for (const entry of entries) {
124
- const fullPath = path.join(dirPath, entry.name);
125
- if (entry.isDirectory()) {
126
- // Skip special Next.js directories and api routes
127
- if (entry.name.startsWith("_") || entry.name === "api") {
128
- continue;
129
- }
130
- // Recursively scan subdirectories
131
- routes.push(...scanDirectory(fullPath, [...segments, entry.name]));
132
- }
133
- else if (entry.isFile() && isPageFile(entry.name)) {
134
- const metadata = extractMetadata(fullPath);
135
- routes.push({
136
- path: normalizeRoutePath(segments),
137
- title: metadata.title,
138
- description: metadata.description,
139
- });
140
- }
64
+ const routes = [];
65
+ try {
66
+ const entries = fs.readdirSync(dirPath, { withFileTypes: true });
67
+ for (const entry of entries) {
68
+ const fullPath = path.join(dirPath, entry.name);
69
+ if (entry.isDirectory()) {
70
+ if (entry.name.startsWith("_") || entry.name === "api") {
71
+ continue;
141
72
  }
73
+ routes.push(...scanDirectory(fullPath, [...segments, entry.name]));
74
+ } else if (entry.isFile() && isPageFile(entry.name)) {
75
+ const metadata = extractMetadata(fullPath);
76
+ routes.push({
77
+ path: normalizeRoutePath(segments),
78
+ title: metadata.title,
79
+ description: metadata.description
80
+ });
81
+ }
142
82
  }
143
- catch (error) {
144
- console.error(`Error scanning directory ${dirPath}:`, error);
145
- }
146
- return routes;
83
+ } catch (error) {
84
+ console.error(`Error scanning directory ${dirPath}:`, error);
85
+ }
86
+ return routes;
147
87
  }
148
- /**
149
- * File discovery helpers for legacy `pages/` directories
150
- */
151
- const VALID_PAGE_EXTENSIONS = new Set([".js", ".jsx", ".ts", ".tsx", ".md", ".mdx"]);
152
- const SPECIAL_PAGE_FILENAMES = new Set([
153
- "_app",
154
- "_document",
155
- "_error",
156
- "404",
157
- "500",
158
- "middleware",
159
- "_middleware",
88
+ var VALID_PAGE_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".jsx", ".ts", ".tsx", ".md", ".mdx"]);
89
+ var SPECIAL_PAGE_FILENAMES = /* @__PURE__ */ new Set([
90
+ "_app",
91
+ "_document",
92
+ "_error",
93
+ "404",
94
+ "500",
95
+ "middleware",
96
+ "_middleware"
160
97
  ]);
161
- /**
162
- * Recursively scan a pages directory for Next.js page routes
163
- */
164
98
  function scanPagesDirectory(dirPath, segments = []) {
165
- const routes = [];
166
- try {
167
- const entries = fs.readdirSync(dirPath, { withFileTypes: true });
168
- for (const entry of entries) {
169
- const fullPath = path.join(dirPath, entry.name);
170
- if (entry.isDirectory()) {
171
- // Skip special directories and api routes
172
- if (entry.name.startsWith("_") || entry.name === "api") {
173
- continue;
174
- }
175
- routes.push(...scanPagesDirectory(fullPath, [...segments, entry.name]));
176
- }
177
- else if (entry.isFile()) {
178
- const extension = path.extname(entry.name);
179
- if (!VALID_PAGE_EXTENSIONS.has(extension)) {
180
- continue;
181
- }
182
- const baseName = entry.name.slice(0, -extension.length);
183
- if (!baseName || SPECIAL_PAGE_FILENAMES.has(baseName) || baseName.startsWith("_")) {
184
- continue;
185
- }
186
- const routeSegments = buildPagesSegments(segments, baseName);
187
- const metadata = extractMetadata(fullPath);
188
- routes.push({
189
- path: normalizeRoutePath(routeSegments),
190
- title: metadata.title,
191
- description: metadata.description,
192
- });
193
- }
99
+ const routes = [];
100
+ try {
101
+ const entries = fs.readdirSync(dirPath, { withFileTypes: true });
102
+ for (const entry of entries) {
103
+ const fullPath = path.join(dirPath, entry.name);
104
+ if (entry.isDirectory()) {
105
+ if (entry.name.startsWith("_") || entry.name === "api") {
106
+ continue;
194
107
  }
108
+ routes.push(...scanPagesDirectory(fullPath, [...segments, entry.name]));
109
+ } else if (entry.isFile()) {
110
+ const extension = path.extname(entry.name);
111
+ if (!VALID_PAGE_EXTENSIONS.has(extension)) {
112
+ continue;
113
+ }
114
+ const baseName = entry.name.slice(0, -extension.length);
115
+ if (!baseName || SPECIAL_PAGE_FILENAMES.has(baseName) || baseName.startsWith("_")) {
116
+ continue;
117
+ }
118
+ const routeSegments = buildPagesSegments(segments, baseName);
119
+ const metadata = extractMetadata(fullPath);
120
+ routes.push({
121
+ path: normalizeRoutePath(routeSegments),
122
+ title: metadata.title,
123
+ description: metadata.description
124
+ });
125
+ }
195
126
  }
196
- catch (error) {
197
- console.error(`Error scanning directory ${dirPath}:`, error);
198
- }
199
- return routes;
127
+ } catch (error) {
128
+ console.error(`Error scanning directory ${dirPath}:`, error);
129
+ }
130
+ return routes;
200
131
  }
201
132
  function buildPagesSegments(segments, baseName) {
202
- const routeSegments = [...segments];
203
- if (baseName !== "index") {
204
- routeSegments.push(baseName);
205
- }
206
- return routeSegments;
133
+ const routeSegments = [...segments];
134
+ if (baseName !== "index") {
135
+ routeSegments.push(baseName);
136
+ }
137
+ return routeSegments;
207
138
  }
208
- /**
209
- * Parse command-line arguments
210
- */
211
139
  function parseArgs() {
212
- const args = process.argv.slice(2);
213
- let appDir = "./src/app";
214
- let pagesDir;
215
- // Default to ./src/yak.routes.ts - TypeScript module that gets bundled
216
- let output = "./src/yak.routes.ts";
217
- let help = false;
218
- for (let i = 0; i < args.length; i++) {
219
- const arg = args[i];
220
- if (arg === "--help" || arg === "-h") {
221
- help = true;
222
- }
223
- else if (arg === "--app-dir" && args[i + 1]) {
224
- appDir = args[i + 1];
225
- i++;
226
- }
227
- else if (arg === "--pages-dir" && args[i + 1]) {
228
- pagesDir = args[i + 1];
229
- i++;
230
- }
231
- else if (arg === "--output" && args[i + 1]) {
232
- output = args[i + 1];
233
- i++;
234
- }
140
+ const args = process.argv.slice(2);
141
+ let appDir = "./src/app";
142
+ let pagesDir;
143
+ let output = "./src/yak.routes.ts";
144
+ let help = false;
145
+ for (let i = 0; i < args.length; i++) {
146
+ const arg = args[i];
147
+ if (arg === "--help" || arg === "-h") {
148
+ help = true;
149
+ } else if (arg === "--app-dir" && args[i + 1]) {
150
+ appDir = args[i + 1];
151
+ i++;
152
+ } else if (arg === "--pages-dir" && args[i + 1]) {
153
+ pagesDir = args[i + 1];
154
+ i++;
155
+ } else if (arg === "--output" && args[i + 1]) {
156
+ output = args[i + 1];
157
+ i++;
235
158
  }
236
- return { appDir, pagesDir, output, help };
159
+ }
160
+ return { appDir, pagesDir, output, help };
237
161
  }
238
- /**
239
- * Display help message
240
- */
241
162
  function showHelp() {
242
- console.log(`
163
+ console.log(`
243
164
  Yak Next.js Route Manifest Generator
244
165
 
245
166
  Scans a Next.js app directory and generates a TypeScript module with route definitions.
@@ -259,16 +180,13 @@ Examples:
259
180
  yak-nextjs generate-manifest --output ./src/generated/yak.routes.ts
260
181
  `);
261
182
  }
262
- /**
263
- * Generate TypeScript module content
264
- */
265
183
  function generateTypeScriptModule(routes) {
266
- const routesJson = JSON.stringify(routes, null, 2);
267
- return `/**
184
+ const routesJson = JSON.stringify(routes, null, 2);
185
+ return `/**
268
186
  * Auto-generated by yak-nextjs generate-manifest
269
187
  * DO NOT EDIT - This file is regenerated at build time
270
188
  *
271
- * Generated: ${new Date().toISOString()}
189
+ * Generated: ${(/* @__PURE__ */ new Date()).toISOString()}
272
190
  */
273
191
 
274
192
  import type { RouteInfo } from "@yak-io/nextjs/server";
@@ -280,54 +198,46 @@ import type { RouteInfo } from "@yak-io/nextjs/server";
280
198
  export const routes: RouteInfo[] = ${routesJson} as const;
281
199
  `;
282
200
  }
283
- /**
284
- * Main entry point
285
- */
286
201
  function main() {
287
- const { appDir, pagesDir, output, help } = parseArgs();
288
- if (help) {
289
- showHelp();
290
- process.exit(0);
291
- }
292
- console.log("🔍 Scanning Next.js page routes...");
293
- const routes = [];
294
- // Scan app directory
295
- const appDirPath = path.resolve(process.cwd(), appDir);
296
- if (fs.existsSync(appDirPath)) {
297
- console.log(` App directory: ${appDir}`);
298
- routes.push(...scanDirectory(appDirPath, []));
299
- }
300
- else {
301
- console.log(` App directory: ${appDir} (not found, skipping)`);
302
- }
303
- // Scan pages directory if provided
304
- if (pagesDir) {
305
- const pagesDirPath = path.resolve(process.cwd(), pagesDir);
306
- if (fs.existsSync(pagesDirPath)) {
307
- console.log(` Pages directory: ${pagesDir}`);
308
- routes.push(...scanPagesDirectory(pagesDirPath, []));
309
- }
310
- else {
311
- console.log(` Pages directory: ${pagesDir} (not found, skipping)`);
312
- }
313
- }
314
- if (routes.length === 0) {
315
- console.error("❌ Error: No routes found. Check your directory paths.");
316
- process.exit(1);
317
- }
318
- // Deduplicate routes by path (app router takes precedence)
319
- const uniqueRoutes = Array.from(new Map(routes.map((r) => [r.path, r])).values()).sort((a, b) => a.path.localeCompare(b.path));
320
- const outputPath = path.resolve(process.cwd(), output);
321
- // Ensure output directory exists
322
- const outputDir = path.dirname(outputPath);
323
- if (!fs.existsSync(outputDir)) {
324
- fs.mkdirSync(outputDir, { recursive: true });
202
+ const { appDir, pagesDir, output, help } = parseArgs();
203
+ if (help) {
204
+ showHelp();
205
+ process.exit(0);
206
+ }
207
+ console.log("\u{1F50D} Scanning Next.js page routes...");
208
+ const routes = [];
209
+ const appDirPath = path.resolve(process.cwd(), appDir);
210
+ if (fs.existsSync(appDirPath)) {
211
+ console.log(` App directory: ${appDir}`);
212
+ routes.push(...scanDirectory(appDirPath, []));
213
+ } else {
214
+ console.log(` App directory: ${appDir} (not found, skipping)`);
215
+ }
216
+ if (pagesDir) {
217
+ const pagesDirPath = path.resolve(process.cwd(), pagesDir);
218
+ if (fs.existsSync(pagesDirPath)) {
219
+ console.log(` Pages directory: ${pagesDir}`);
220
+ routes.push(...scanPagesDirectory(pagesDirPath, []));
221
+ } else {
222
+ console.log(` Pages directory: ${pagesDir} (not found, skipping)`);
325
223
  }
326
- // Write TypeScript module
327
- const content = generateTypeScriptModule(uniqueRoutes);
328
- fs.writeFileSync(outputPath, content, "utf-8");
329
- console.log(`✅ Generated route manifest with ${uniqueRoutes.length} routes`);
330
- console.log(` Output: ${outputPath}`);
224
+ }
225
+ if (routes.length === 0) {
226
+ console.error("\u274C Error: No routes found. Check your directory paths.");
227
+ process.exit(1);
228
+ }
229
+ const uniqueRoutes = Array.from(new Map(routes.map((r) => [r.path, r])).values()).sort(
230
+ (a, b) => a.path.localeCompare(b.path)
231
+ );
232
+ const outputPath = path.resolve(process.cwd(), output);
233
+ const outputDir = path.dirname(outputPath);
234
+ if (!fs.existsSync(outputDir)) {
235
+ fs.mkdirSync(outputDir, { recursive: true });
236
+ }
237
+ const content = generateTypeScriptModule(uniqueRoutes);
238
+ fs.writeFileSync(outputPath, content, "utf-8");
239
+ console.log(`\u2705 Generated route manifest with ${uniqueRoutes.length} routes`);
240
+ console.log(` Output: ${outputPath}`);
331
241
  }
332
- // Run the CLI
333
242
  main();
243
+ //# sourceMappingURL=generate-manifest.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/cli/generate-manifest.ts"],
4
+ "sourcesContent": ["#!/usr/bin/env node\n\n/**\n * Yak Next.js Route Manifest Generator\n *\n * This CLI tool scans a Next.js app directory and generates a manifest\n * of all available page routes that can be injected into the chat context.\n *\n * Usage:\n * yak-nextjs generate-manifest [options]\n *\n * Options:\n * --app-dir <path> Path to Next.js app directory (default: ./src/app)\n * --pages-dir <path> Path to Next.js pages directory (optional, scanned in addition to app-dir)\n * --output <path> Output file path (default: ./src/yak-routes-manifest.json)\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { RouteInfo } from \"@yak-io/javascript/server\";\n\n/**\n * Extract static metadata (title and description) from a Next.js page file.\n * Parses `export const metadata = { title: \"...\", description: \"...\" }` patterns.\n * Does not support dynamic generateMetadata functions.\n */\nfunction extractMetadata(filePath: string): { title?: string; description?: string } {\n try {\n const content = fs.readFileSync(filePath, \"utf-8\");\n\n // Match `export const metadata` object\n const metadataMatch = content.match(\n /export\\s+const\\s+metadata\\s*(?::\\s*Metadata\\s*)?=\\s*\\{([^}]*(?:\\{[^}]*\\}[^}]*)*)\\}/s\n );\n\n if (!metadataMatch) {\n return {};\n }\n\n const metadataBlock = metadataMatch[1];\n const result: { title?: string; description?: string } = {};\n\n // Extract title - handle both single and double quotes\n const titleMatch = metadataBlock?.match(/title\\s*:\\s*[\"'`]([^\"'`]+)[\"'`]/);\n if (titleMatch?.[1]) {\n result.title = titleMatch[1];\n }\n\n // Extract description - handle both single and double quotes\n const descMatch = metadataBlock?.match(/description\\s*:\\s*[\"'`]([^\"'`]+)[\"'`]/);\n if (descMatch?.[1]) {\n result.description = descMatch[1];\n }\n\n return result;\n } catch {\n return {};\n }\n}\n\n/**\n * Check if a path segment is a route group (organizational only, not part of URL)\n */\nfunction isRouteGroup(segment: string): boolean {\n return segment.startsWith(\"(\") && segment.endsWith(\")\");\n}\n\n/**\n * Check if a path segment is an optional catch-all (e.g., [[...slug]])\n * These segments match the base path without any additional segments\n */\nfunction isOptionalCatchAll(segment: string): boolean {\n return segment.startsWith(\"[[...\") && segment.endsWith(\"]]\");\n}\n\n/**\n * Check if a path segment is a required catch-all (e.g., [...slug])\n * These segments require at least one additional path segment\n */\nfunction isRequiredCatchAll(segment: string): boolean {\n return segment.startsWith(\"[...\") && segment.endsWith(\"]\") && !segment.startsWith(\"[[\");\n}\n\n/**\n * Check if a path segment is a dynamic segment (e.g., [id])\n */\nfunction isDynamicSegment(segment: string): boolean {\n return (\n segment.startsWith(\"[\") &&\n segment.endsWith(\"]\") &&\n !isOptionalCatchAll(segment) &&\n !isRequiredCatchAll(segment)\n );\n}\n\n/**\n * Normalize a dynamic segment for display\n * e.g., [id] \u2192 :id, [postId] \u2192 :postId\n */\nfunction normalizeDynamicSegment(segment: string): string {\n // Extract the parameter name from [name] format\n const paramName = segment.slice(1, -1);\n return `:${paramName}`;\n}\n\n/**\n * Normalize a route path for display (excludes route groups and handles dynamic segments)\n */\nfunction normalizeRoutePath(segments: string[]): string {\n // Filter out route groups - they don't appear in URLs\n // Filter out optional catch-all segments - they match the base path\n const urlSegments = segments\n .filter((seg) => !isRouteGroup(seg) && !isOptionalCatchAll(seg))\n .map((seg) => {\n if (isDynamicSegment(seg)) {\n return normalizeDynamicSegment(seg);\n }\n if (isRequiredCatchAll(seg)) {\n // For required catch-all, extract the name: [...slug] \u2192 :slug+\n const paramName = seg.slice(4, -1);\n return `:${paramName}+`;\n }\n return seg;\n });\n if (urlSegments.length === 0) return \"/\";\n return `/${urlSegments.join(\"/\")}`;\n}\n\n/**\n * Check if file is a page file\n */\nfunction isPageFile(filename: string): boolean {\n return filename === \"page.tsx\" || filename === \"page.js\";\n}\n\n/**\n * Recursively scan a directory for Next.js page routes\n */\nfunction scanDirectory(dirPath: string, segments: string[] = []): RouteInfo[] {\n const routes: RouteInfo[] = [];\n\n try {\n const entries = fs.readdirSync(dirPath, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dirPath, entry.name);\n\n if (entry.isDirectory()) {\n // Skip special Next.js directories and api routes\n if (entry.name.startsWith(\"_\") || entry.name === \"api\") {\n continue;\n }\n\n // Recursively scan subdirectories\n routes.push(...scanDirectory(fullPath, [...segments, entry.name]));\n } else if (entry.isFile() && isPageFile(entry.name)) {\n const metadata = extractMetadata(fullPath);\n\n routes.push({\n path: normalizeRoutePath(segments),\n title: metadata.title,\n description: metadata.description,\n });\n }\n }\n } catch (error) {\n console.error(`Error scanning directory ${dirPath}:`, error);\n }\n\n return routes;\n}\n\n/**\n * File discovery helpers for legacy `pages/` directories\n */\nconst VALID_PAGE_EXTENSIONS = new Set([\".js\", \".jsx\", \".ts\", \".tsx\", \".md\", \".mdx\"]);\nconst SPECIAL_PAGE_FILENAMES = new Set([\n \"_app\",\n \"_document\",\n \"_error\",\n \"404\",\n \"500\",\n \"middleware\",\n \"_middleware\",\n]);\n\n/**\n * Recursively scan a pages directory for Next.js page routes\n */\nfunction scanPagesDirectory(dirPath: string, segments: string[] = []): RouteInfo[] {\n const routes: RouteInfo[] = [];\n\n try {\n const entries = fs.readdirSync(dirPath, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dirPath, entry.name);\n\n if (entry.isDirectory()) {\n // Skip special directories and api routes\n if (entry.name.startsWith(\"_\") || entry.name === \"api\") {\n continue;\n }\n\n routes.push(...scanPagesDirectory(fullPath, [...segments, entry.name]));\n } else if (entry.isFile()) {\n const extension = path.extname(entry.name);\n if (!VALID_PAGE_EXTENSIONS.has(extension)) {\n continue;\n }\n\n const baseName = entry.name.slice(0, -extension.length);\n if (!baseName || SPECIAL_PAGE_FILENAMES.has(baseName) || baseName.startsWith(\"_\")) {\n continue;\n }\n\n const routeSegments = buildPagesSegments(segments, baseName);\n const metadata = extractMetadata(fullPath);\n\n routes.push({\n path: normalizeRoutePath(routeSegments),\n title: metadata.title,\n description: metadata.description,\n });\n }\n }\n } catch (error) {\n console.error(`Error scanning directory ${dirPath}:`, error);\n }\n\n return routes;\n}\n\nfunction buildPagesSegments(segments: string[], baseName: string): string[] {\n const routeSegments = [...segments];\n if (baseName !== \"index\") {\n routeSegments.push(baseName);\n }\n return routeSegments;\n}\n\n/**\n * Parse command-line arguments\n */\nfunction parseArgs(): {\n appDir: string;\n pagesDir: string | undefined;\n output: string;\n help: boolean;\n} {\n const args = process.argv.slice(2);\n let appDir = \"./src/app\";\n let pagesDir: string | undefined;\n // Default to ./src/yak.routes.ts - TypeScript module that gets bundled\n let output = \"./src/yak.routes.ts\";\n let help = false;\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === \"--help\" || arg === \"-h\") {\n help = true;\n } else if (arg === \"--app-dir\" && args[i + 1]) {\n appDir = args[i + 1] as string;\n i++;\n } else if (arg === \"--pages-dir\" && args[i + 1]) {\n pagesDir = args[i + 1] as string;\n i++;\n } else if (arg === \"--output\" && args[i + 1]) {\n output = args[i + 1] as string;\n i++;\n }\n }\n\n return { appDir, pagesDir, output, help };\n}\n\n/**\n * Display help message\n */\nfunction showHelp(): void {\n console.log(`\nYak Next.js Route Manifest Generator\n\nScans a Next.js app directory and generates a TypeScript module with route definitions.\n\nUsage:\n yak-nextjs generate-manifest [options]\n\nOptions:\n --app-dir <path> Path to Next.js app directory (default: ./src/app)\n --pages-dir <path> Path to Next.js pages directory (optional)\n --output <path> Output file path (default: ./src/yak.routes.ts)\n --help, -h Show this help message\n\nExamples:\n yak-nextjs generate-manifest\n yak-nextjs generate-manifest --app-dir ./app\n yak-nextjs generate-manifest --output ./src/generated/yak.routes.ts\n `);\n}\n\n/**\n * Generate TypeScript module content\n */\nfunction generateTypeScriptModule(routes: RouteInfo[]): string {\n const routesJson = JSON.stringify(routes, null, 2);\n\n return `/**\n * Auto-generated by yak-nextjs generate-manifest\n * DO NOT EDIT - This file is regenerated at build time\n * \n * Generated: ${new Date().toISOString()}\n */\n\nimport type { RouteInfo } from \"@yak-io/nextjs/server\";\n\n/**\n * All scanned routes from your Next.js application.\n * Use with createRouteManifestAdapter for filtering options.\n */\nexport const routes: RouteInfo[] = ${routesJson} as const;\n`;\n}\n\n/**\n * Main entry point\n */\nfunction main(): void {\n const { appDir, pagesDir, output, help } = parseArgs();\n\n if (help) {\n showHelp();\n process.exit(0);\n }\n\n console.log(\"\uD83D\uDD0D Scanning Next.js page routes...\");\n\n const routes: RouteInfo[] = [];\n\n // Scan app directory\n const appDirPath = path.resolve(process.cwd(), appDir);\n if (fs.existsSync(appDirPath)) {\n console.log(` App directory: ${appDir}`);\n routes.push(...scanDirectory(appDirPath, []));\n } else {\n console.log(` App directory: ${appDir} (not found, skipping)`);\n }\n\n // Scan pages directory if provided\n if (pagesDir) {\n const pagesDirPath = path.resolve(process.cwd(), pagesDir);\n if (fs.existsSync(pagesDirPath)) {\n console.log(` Pages directory: ${pagesDir}`);\n routes.push(...scanPagesDirectory(pagesDirPath, []));\n } else {\n console.log(` Pages directory: ${pagesDir} (not found, skipping)`);\n }\n }\n\n if (routes.length === 0) {\n console.error(\"\u274C Error: No routes found. Check your directory paths.\");\n process.exit(1);\n }\n\n // Deduplicate routes by path (app router takes precedence)\n const uniqueRoutes = Array.from(new Map(routes.map((r) => [r.path, r])).values()).sort((a, b) =>\n a.path.localeCompare(b.path)\n );\n\n const outputPath = path.resolve(process.cwd(), output);\n\n // Ensure output directory exists\n const outputDir = path.dirname(outputPath);\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true });\n }\n\n // Write TypeScript module\n const content = generateTypeScriptModule(uniqueRoutes);\n fs.writeFileSync(outputPath, content, \"utf-8\");\n\n console.log(`\u2705 Generated route manifest with ${uniqueRoutes.length} routes`);\n console.log(` Output: ${outputPath}`);\n}\n\n// Run the CLI\nmain();\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ "use client";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
20
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
+
22
+ // src/index.client.ts
23
+ var index_client_exports = {};
24
+ __export(index_client_exports, {
25
+ YakProvider: () => YakProvider,
26
+ useYak: () => import_react.useYak
27
+ });
28
+ module.exports = __toCommonJS(index_client_exports);
29
+ __reExport(index_client_exports, require("@yak-io/react"), module.exports);
30
+
31
+ // src/client/useYak.ts
32
+ var import_react = require("@yak-io/react");
33
+
34
+ // src/client/YakProvider.tsx
35
+ var import_react2 = require("@yak-io/react");
36
+ var import_navigation = require("next/navigation");
37
+ var import_react3 = require("react");
38
+ var import_jsx_runtime = require("react/jsx-runtime");
39
+ function isAbsoluteUrl(path) {
40
+ return /^https?:\/\//i.test(path);
41
+ }
42
+ async function defaultGetConfig() {
43
+ const res = await fetch("/api/yak", { credentials: "include" });
44
+ if (!res.ok) {
45
+ throw new Error(`Failed to fetch config: ${res.status}`);
46
+ }
47
+ return res.json();
48
+ }
49
+ async function defaultOnToolCall(name, args) {
50
+ const res = await fetch("/api/yak", {
51
+ method: "POST",
52
+ headers: { "Content-Type": "application/json" },
53
+ credentials: "include",
54
+ body: JSON.stringify({ name, args })
55
+ });
56
+ const data = await res.json();
57
+ if (!data.ok) {
58
+ throw new Error(data.error ?? "Tool execution failed");
59
+ }
60
+ return data.result;
61
+ }
62
+ function YakProvider(props) {
63
+ const router = (0, import_navigation.useRouter)();
64
+ const handleRedirect = (0, import_react3.useCallback)(
65
+ (path) => {
66
+ if (isAbsoluteUrl(path)) {
67
+ window.location.assign(path);
68
+ return;
69
+ }
70
+ router.push(path);
71
+ },
72
+ [router]
73
+ );
74
+ const getConfig = (0, import_react3.useMemo)(() => props.getConfig ?? defaultGetConfig, [props.getConfig]);
75
+ const onToolCall = (0, import_react3.useMemo)(() => props.onToolCall ?? defaultOnToolCall, [props.onToolCall]);
76
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
77
+ import_react2.YakProvider,
78
+ {
79
+ ...props,
80
+ getConfig,
81
+ onToolCall,
82
+ onRedirect: props.onRedirect ?? handleRedirect
83
+ }
84
+ );
85
+ }
86
+ //# sourceMappingURL=index.client.cjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.client.ts", "../src/client/useYak.ts", "../src/client/YakProvider.tsx"],
4
+ "sourcesContent": ["\"use client\";\n\nexport * from \"@yak-io/react\";\nexport type { YakChatAPI } from \"./client/useYak.js\";\nexport { useYak } from \"./client/useYak.js\";\nexport type { YakProviderProps } from \"./client/YakProvider.js\";\nexport { YakProvider } from \"./client/YakProvider.js\";\n", "\"use client\";\n\nimport { useYak } from \"@yak-io/react\";\n\n// Re-export useYak for convenience\nexport { useYak };\n\n/**\n * The object returned by {@link useYak} \u2014 the imperative handle for controlling\n * chat and voice (`open`, `close`, `openWithPrompt`, `voiceStart`, `voiceStop`,\n * `voiceToggle`) plus reactive state (`isOpen`, `isReady`, `chatLoading`,\n * `voiceState`, `voiceLoading`, \u2026).\n */\nexport type YakChatAPI = ReturnType<typeof useYak>;\n", "\"use client\";\n\nimport {\n YakProvider as CoreYakProvider,\n type YakProviderProps as CoreYakProviderProps,\n} from \"@yak-io/react\";\nimport { useRouter } from \"next/navigation\";\nimport type React from \"react\";\nimport { useCallback, useMemo } from \"react\";\n\nexport type YakProviderProps = CoreYakProviderProps;\n\nfunction isAbsoluteUrl(path: string): boolean {\n return /^https?:\\/\\//i.test(path);\n}\n\n/**\n * Default getConfig that fetches from /api/yak\n */\nasync function defaultGetConfig() {\n const res = await fetch(\"/api/yak\", { credentials: \"include\" });\n if (!res.ok) {\n throw new Error(`Failed to fetch config: ${res.status}`);\n }\n return res.json();\n}\n\n/**\n * Default onToolCall that POSTs to /api/yak\n */\nasync function defaultOnToolCall(name: string, args: unknown) {\n const res = await fetch(\"/api/yak\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n credentials: \"include\",\n body: JSON.stringify({ name, args }),\n });\n const data = await res.json();\n if (!data.ok) {\n throw new Error(data.error ?? \"Tool execution failed\");\n }\n return data.result;\n}\n\n/**\n * Next-aware YakProvider that falls back to client-side navigation\n * and provides sensible defaults for getConfig and onToolCall.\n *\n * By default:\n * - `getConfig` fetches from `/api/yak` (GET)\n * - `onToolCall` POSTs to `/api/yak`\n *\n * These defaults assume you've set up the API handler via `createNextYakHandler`.\n */\nexport function YakProvider(props: YakProviderProps): React.JSX.Element {\n const router = useRouter();\n\n const handleRedirect = useCallback(\n (path: string) => {\n if (isAbsoluteUrl(path)) {\n window.location.assign(path);\n return;\n }\n\n router.push(path);\n },\n [router]\n );\n\n const getConfig = useMemo(() => props.getConfig ?? defaultGetConfig, [props.getConfig]);\n\n const onToolCall = useMemo(() => props.onToolCall ?? defaultOnToolCall, [props.onToolCall]);\n\n return (\n <CoreYakProvider\n {...props}\n getConfig={getConfig}\n onToolCall={onToolCall}\n onRedirect={props.onRedirect ?? handleRedirect}\n />\n );\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,iCAAc,0BAFd;;;ACEA,mBAAuB;;;ACAvB,IAAAA,gBAGO;AACP,wBAA0B;AAE1B,IAAAA,gBAAqC;AAkEjC;AA9DJ,SAAS,cAAc,MAAuB;AAC5C,SAAO,gBAAgB,KAAK,IAAI;AAClC;AAKA,eAAe,mBAAmB;AAChC,QAAM,MAAM,MAAM,MAAM,YAAY,EAAE,aAAa,UAAU,CAAC;AAC9D,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,IAAI,MAAM,2BAA2B,IAAI,MAAM,EAAE;AAAA,EACzD;AACA,SAAO,IAAI,KAAK;AAClB;AAKA,eAAe,kBAAkB,MAAc,MAAe;AAC5D,QAAM,MAAM,MAAM,MAAM,YAAY;AAAA,IAClC,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,aAAa;AAAA,IACb,MAAM,KAAK,UAAU,EAAE,MAAM,KAAK,CAAC;AAAA,EACrC,CAAC;AACD,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,MAAI,CAAC,KAAK,IAAI;AACZ,UAAM,IAAI,MAAM,KAAK,SAAS,uBAAuB;AAAA,EACvD;AACA,SAAO,KAAK;AACd;AAYO,SAAS,YAAY,OAA4C;AACtE,QAAM,aAAS,6BAAU;AAEzB,QAAM,qBAAiB;AAAA,IACrB,CAAC,SAAiB;AAChB,UAAI,cAAc,IAAI,GAAG;AACvB,eAAO,SAAS,OAAO,IAAI;AAC3B;AAAA,MACF;AAEA,aAAO,KAAK,IAAI;AAAA,IAClB;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,gBAAY,uBAAQ,MAAM,MAAM,aAAa,kBAAkB,CAAC,MAAM,SAAS,CAAC;AAEtF,QAAM,iBAAa,uBAAQ,MAAM,MAAM,cAAc,mBAAmB,CAAC,MAAM,UAAU,CAAC;AAE1F,SACE;AAAA,IAAC,cAAAC;AAAA,IAAA;AAAA,MACE,GAAG;AAAA,MACJ;AAAA,MACA;AAAA,MACA,YAAY,MAAM,cAAc;AAAA;AAAA,EAClC;AAEJ;",
6
+ "names": ["import_react", "CoreYakProvider"]
7
+ }