@yak-io/nextjs 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -2
- package/dist/cli/generate-manifest.d.ts +3 -2
- package/dist/cli/generate-manifest.d.ts.map +1 -1
- package/dist/cli/generate-manifest.js +98 -16
- package/dist/server/createNextYakHandler.d.ts +19 -1
- package/dist/server/createNextYakHandler.d.ts.map +1 -1
- package/dist/server/createNextYakHandler.js +82 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -161,17 +161,87 @@ Behind the scenes `@yak-io/javascript` merges every `RouteSource` into a single
|
|
|
161
161
|
## CLI: route manifest generator
|
|
162
162
|
|
|
163
163
|
```bash
|
|
164
|
-
yak-nextjs generate-manifest
|
|
164
|
+
yak-nextjs generate-manifest
|
|
165
165
|
```
|
|
166
166
|
|
|
167
167
|
Use the CLI when you prefer to pre-compute a manifest at build time. The JSON matches the runtime manifest structure exposed by the handlers.
|
|
168
168
|
|
|
169
|
+
**Options:**
|
|
170
|
+
- `--app-dir <path>` – Path to Next.js app directory (default: `./src/app`)
|
|
171
|
+
- `--pages-dir <path>` – Path to Next.js pages directory (optional, scanned in addition to app-dir)
|
|
172
|
+
- `--output <path>` – Output file path (default: `./public/yak-routes-manifest.json`)
|
|
173
|
+
|
|
174
|
+
**Examples:**
|
|
175
|
+
```bash
|
|
176
|
+
yak-nextjs generate-manifest
|
|
177
|
+
yak-nextjs generate-manifest --pages-dir ./src/pages
|
|
178
|
+
yak-nextjs generate-manifest --app-dir ./app --pages-dir ./pages
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Route Manifest for Production
|
|
182
|
+
|
|
183
|
+
During local development, routes are scanned directly from the filesystem—no setup needed. However, when you build your Next.js app for production, only the compiled `.next` output is included. Source files like `./src/app` are not present at runtime.
|
|
184
|
+
|
|
185
|
+
To enable route scanning in production builds, generate a manifest at build time.
|
|
186
|
+
|
|
187
|
+
### Recommended setup
|
|
188
|
+
|
|
189
|
+
Add a `prebuild` script to generate the manifest before Next.js builds:
|
|
190
|
+
|
|
191
|
+
```json
|
|
192
|
+
{
|
|
193
|
+
"scripts": {
|
|
194
|
+
"prebuild": "yak-nextjs generate-manifest",
|
|
195
|
+
"build": "next build"
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
This uses the defaults (`./src/app` → `./public/yak-routes-manifest.json`). Customize if needed:
|
|
201
|
+
|
|
202
|
+
```json
|
|
203
|
+
{
|
|
204
|
+
"scripts": {
|
|
205
|
+
"prebuild": "yak-nextjs generate-manifest --app-dir ./app --output ./public/routes.json"
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
The handler checks these locations automatically:
|
|
211
|
+
1. `./yak-routes-manifest.json`
|
|
212
|
+
2. `./public/yak-routes-manifest.json`
|
|
213
|
+
|
|
214
|
+
### Alternative: explicit routes
|
|
215
|
+
|
|
216
|
+
If you prefer not to use filesystem scanning, provide routes explicitly:
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
export const { GET, POST } = createNextYakHandler({
|
|
220
|
+
routes: [
|
|
221
|
+
{ path: "/", title: "Home" },
|
|
222
|
+
{ path: "/pricing", title: "Pricing" },
|
|
223
|
+
],
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Loading a custom manifest location
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
import { createNextYakHandler, loadRoutes } from "@yak-io/nextjs/server";
|
|
231
|
+
|
|
232
|
+
export const { GET, POST } = createNextYakHandler({
|
|
233
|
+
routes: loadRoutes("./custom/manifest.json"),
|
|
234
|
+
});
|
|
235
|
+
```
|
|
236
|
+
|
|
169
237
|
## API surface (server)
|
|
170
238
|
|
|
171
239
|
`@yak-io/nextjs/server` exports:
|
|
172
240
|
|
|
173
241
|
- `scanRoutes(directory: string, options?: { directoryType?: "app" | "pages" })` – low-level filesystem scanner (useful for precomputing manifests or composing custom sources). Only captures page routes, extracting `title` and `description` from static metadata exports.
|
|
174
|
-
- `
|
|
242
|
+
- `loadRouteManifest(path?: string)` – load a pre-built JSON manifest, returns `null` if not found. Checks `./yak-routes-manifest.json` and `./public/yak-routes-manifest.json` by default.
|
|
243
|
+
- `loadRoutes(path?: string)` – load routes from a manifest, throws with helpful error if not found.
|
|
244
|
+
- `createNextYakHandler(config)` – unified GET + POST handler (wrapping `createYakHandler`). When `routes`/`getRoutes` are omitted it auto-scans `./src/app` and `./src/pages` (override with `appDir`/`pagesDir`, and narrow results via `routeFilter?: { include?: RegExp[]; exclude?: RegExp[] }`). In production, automatically falls back to pre-built manifests.
|
|
175
245
|
- `createNextYakConfigHandler(config)` – GET-only convenience wrapper.
|
|
176
246
|
- `createNextYakToolsHandler(config)` – POST-only wrapper.
|
|
177
247
|
- Re-exported types from `@yak-io/javascript/server` (RouteInfo, RouteManifest, ToolDefinition, ToolManifest, ToolExecutor, ChatConfig, RouteSourceInput, ToolSourceInput, etc.).
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
* yak-nextjs generate-manifest [options]
|
|
10
10
|
*
|
|
11
11
|
* Options:
|
|
12
|
-
* --app-dir <path> Path to Next.js app directory (default: ./app)
|
|
13
|
-
* --
|
|
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: ./public/yak-routes-manifest.json)
|
|
14
15
|
*/
|
|
15
16
|
export {};
|
|
16
17
|
//# sourceMappingURL=generate-manifest.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-manifest.d.ts","sourceRoot":"","sources":["../../src/cli/generate-manifest.ts"],"names":[],"mappings":";AAEA
|
|
1
|
+
{"version":3,"file":"generate-manifest.d.ts","sourceRoot":"","sources":["../../src/cli/generate-manifest.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;GAaG"}
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
* yak-nextjs generate-manifest [options]
|
|
10
10
|
*
|
|
11
11
|
* Options:
|
|
12
|
-
* --app-dir <path> Path to Next.js app directory (default: ./app)
|
|
13
|
-
* --
|
|
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: ./public/yak-routes-manifest.json)
|
|
14
15
|
*/
|
|
15
16
|
import * as fs from "node:fs";
|
|
16
17
|
import * as path from "node:path";
|
|
@@ -141,13 +142,66 @@ function scanDirectory(dirPath, segments = []) {
|
|
|
141
142
|
}
|
|
142
143
|
return routes;
|
|
143
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* File discovery helpers for legacy `pages/` directories
|
|
147
|
+
*/
|
|
148
|
+
const VALID_PAGE_EXTENSIONS = new Set([".js", ".jsx", ".ts", ".tsx", ".md", ".mdx"]);
|
|
149
|
+
const SPECIAL_PAGE_FILENAMES = new Set(["_app", "_document", "_error", "404", "500", "middleware", "_middleware"]);
|
|
150
|
+
/**
|
|
151
|
+
* Recursively scan a pages directory for Next.js page routes
|
|
152
|
+
*/
|
|
153
|
+
function scanPagesDirectory(dirPath, segments = []) {
|
|
154
|
+
const routes = [];
|
|
155
|
+
try {
|
|
156
|
+
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
157
|
+
for (const entry of entries) {
|
|
158
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
159
|
+
if (entry.isDirectory()) {
|
|
160
|
+
// Skip special directories and api routes
|
|
161
|
+
if (entry.name.startsWith("_") || entry.name === "api") {
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
routes.push(...scanPagesDirectory(fullPath, [...segments, entry.name]));
|
|
165
|
+
}
|
|
166
|
+
else if (entry.isFile()) {
|
|
167
|
+
const extension = path.extname(entry.name);
|
|
168
|
+
if (!VALID_PAGE_EXTENSIONS.has(extension)) {
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
const baseName = entry.name.slice(0, -extension.length);
|
|
172
|
+
if (!baseName || SPECIAL_PAGE_FILENAMES.has(baseName) || baseName.startsWith("_")) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
const routeSegments = buildPagesSegments(segments, baseName);
|
|
176
|
+
const metadata = extractMetadata(fullPath);
|
|
177
|
+
routes.push({
|
|
178
|
+
path: normalizeRoutePath(routeSegments),
|
|
179
|
+
title: metadata.title,
|
|
180
|
+
description: metadata.description,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
console.error(`Error scanning directory ${dirPath}:`, error);
|
|
187
|
+
}
|
|
188
|
+
return routes;
|
|
189
|
+
}
|
|
190
|
+
function buildPagesSegments(segments, baseName) {
|
|
191
|
+
const routeSegments = [...segments];
|
|
192
|
+
if (baseName !== "index") {
|
|
193
|
+
routeSegments.push(baseName);
|
|
194
|
+
}
|
|
195
|
+
return routeSegments;
|
|
196
|
+
}
|
|
144
197
|
/**
|
|
145
198
|
* Parse command-line arguments
|
|
146
199
|
*/
|
|
147
200
|
function parseArgs() {
|
|
148
201
|
const args = process.argv.slice(2);
|
|
149
|
-
let appDir = "./app";
|
|
150
|
-
let
|
|
202
|
+
let appDir = "./src/app";
|
|
203
|
+
let pagesDir = undefined;
|
|
204
|
+
let output = "./public/yak-routes-manifest.json";
|
|
151
205
|
let help = false;
|
|
152
206
|
for (let i = 0; i < args.length; i++) {
|
|
153
207
|
const arg = args[i];
|
|
@@ -158,12 +212,16 @@ function parseArgs() {
|
|
|
158
212
|
appDir = args[i + 1];
|
|
159
213
|
i++;
|
|
160
214
|
}
|
|
215
|
+
else if (arg === "--pages-dir" && args[i + 1]) {
|
|
216
|
+
pagesDir = args[i + 1];
|
|
217
|
+
i++;
|
|
218
|
+
}
|
|
161
219
|
else if (arg === "--output" && args[i + 1]) {
|
|
162
220
|
output = args[i + 1];
|
|
163
221
|
i++;
|
|
164
222
|
}
|
|
165
223
|
}
|
|
166
|
-
return { appDir, output, help };
|
|
224
|
+
return { appDir, pagesDir, output, help };
|
|
167
225
|
}
|
|
168
226
|
/**
|
|
169
227
|
* Display help message
|
|
@@ -178,38 +236,62 @@ Usage:
|
|
|
178
236
|
yak-nextjs generate-manifest [options]
|
|
179
237
|
|
|
180
238
|
Options:
|
|
181
|
-
--app-dir <path> Path to Next.js app directory (default: ./app)
|
|
182
|
-
--
|
|
239
|
+
--app-dir <path> Path to Next.js app directory (default: ./src/app)
|
|
240
|
+
--pages-dir <path> Path to Next.js pages directory (optional)
|
|
241
|
+
--output <path> Output file path (default: ./public/yak-routes-manifest.json)
|
|
183
242
|
--help, -h Show this help message
|
|
184
243
|
|
|
185
|
-
|
|
186
|
-
yak-nextjs generate-manifest
|
|
244
|
+
Examples:
|
|
245
|
+
yak-nextjs generate-manifest
|
|
246
|
+
yak-nextjs generate-manifest --app-dir ./app
|
|
247
|
+
yak-nextjs generate-manifest --pages-dir ./src/pages
|
|
248
|
+
yak-nextjs generate-manifest --app-dir ./app --pages-dir ./pages
|
|
187
249
|
`);
|
|
188
250
|
}
|
|
189
251
|
/**
|
|
190
252
|
* Main entry point
|
|
191
253
|
*/
|
|
192
254
|
function main() {
|
|
193
|
-
const { appDir, output, help } = parseArgs();
|
|
255
|
+
const { appDir, pagesDir, output, help } = parseArgs();
|
|
194
256
|
if (help) {
|
|
195
257
|
showHelp();
|
|
196
258
|
process.exit(0);
|
|
197
259
|
}
|
|
198
260
|
console.log("🔍 Scanning Next.js page routes...");
|
|
199
|
-
|
|
261
|
+
const routes = [];
|
|
262
|
+
// Scan app directory
|
|
200
263
|
const appDirPath = path.resolve(process.cwd(), appDir);
|
|
201
|
-
if (
|
|
202
|
-
console.
|
|
264
|
+
if (fs.existsSync(appDirPath)) {
|
|
265
|
+
console.log(` App directory: ${appDir}`);
|
|
266
|
+
routes.push(...scanDirectory(appDirPath, []));
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
console.log(` App directory: ${appDir} (not found, skipping)`);
|
|
270
|
+
}
|
|
271
|
+
// Scan pages directory if provided
|
|
272
|
+
if (pagesDir) {
|
|
273
|
+
const pagesDirPath = path.resolve(process.cwd(), pagesDir);
|
|
274
|
+
if (fs.existsSync(pagesDirPath)) {
|
|
275
|
+
console.log(` Pages directory: ${pagesDir}`);
|
|
276
|
+
routes.push(...scanPagesDirectory(pagesDirPath, []));
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
console.log(` Pages directory: ${pagesDir} (not found, skipping)`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
if (routes.length === 0) {
|
|
283
|
+
console.error("❌ Error: No routes found. Check your directory paths.");
|
|
203
284
|
process.exit(1);
|
|
204
285
|
}
|
|
205
|
-
|
|
286
|
+
// Deduplicate routes by path (app router takes precedence)
|
|
287
|
+
const uniqueRoutes = Array.from(new Map(routes.map(r => [r.path, r])).values());
|
|
206
288
|
const manifest = {
|
|
207
|
-
routes:
|
|
289
|
+
routes: uniqueRoutes.sort((a, b) => a.path.localeCompare(b.path)),
|
|
208
290
|
generated_at: new Date().toISOString(),
|
|
209
291
|
};
|
|
210
292
|
const outputPath = path.resolve(process.cwd(), output);
|
|
211
293
|
fs.writeFileSync(outputPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
212
|
-
console.log(`✅ Generated manifest with ${
|
|
294
|
+
console.log(`✅ Generated manifest with ${uniqueRoutes.length} page routes`);
|
|
213
295
|
console.log(` Output: ${outputPath}`);
|
|
214
296
|
}
|
|
215
297
|
// Run the CLI
|
|
@@ -1,4 +1,22 @@
|
|
|
1
|
-
import type { RouteSourceInput, ToolSourceInput, RouteInfo, ToolManifest, ToolExecutor } from "@yak-io/javascript/server";
|
|
1
|
+
import type { RouteSourceInput, ToolSourceInput, RouteInfo, RouteManifest, ToolManifest, ToolExecutor } from "@yak-io/javascript/server";
|
|
2
|
+
/**
|
|
3
|
+
* Load a pre-built route manifest from disk.
|
|
4
|
+
*
|
|
5
|
+
* This should be used in production environments where filesystem scanning
|
|
6
|
+
* is not available (e.g., Vercel serverless functions).
|
|
7
|
+
*
|
|
8
|
+
* Generate the manifest at build time using:
|
|
9
|
+
* yak-nextjs generate-manifest --app-dir ./src/app --output ./public/yak-routes-manifest.json
|
|
10
|
+
*
|
|
11
|
+
* @param manifestPath - Path to the manifest JSON file (default: tries common locations)
|
|
12
|
+
* @returns Route manifest or null if not found
|
|
13
|
+
*/
|
|
14
|
+
export declare function loadRouteManifest(manifestPath?: string): RouteManifest | null;
|
|
15
|
+
/**
|
|
16
|
+
* Load routes from a pre-built manifest.
|
|
17
|
+
* Throws if manifest is not found.
|
|
18
|
+
*/
|
|
19
|
+
export declare function loadRoutes(manifestPath?: string): RouteInfo[];
|
|
2
20
|
export type NextYakRouteFilter = {
|
|
3
21
|
include?: RegExp[];
|
|
4
22
|
exclude?: RegExp[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createNextYakHandler.d.ts","sourceRoot":"","sources":["../../src/server/createNextYakHandler.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,YAAY,EACZ,YAAY,EACb,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"createNextYakHandler.d.ts","sourceRoot":"","sources":["../../src/server/createNextYakHandler.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,aAAa,EACb,YAAY,EACZ,YAAY,EACb,MAAM,2BAA2B,CAAC;AAWnC;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAgB7E;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,CAa7D;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IACvC,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC;IACvC,WAAW,CAAC,EAAE,YAAY,CAAC;CAC5B,CAAC;AAEF;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,oBAAoB;;;EAKhE;AA6FD,MAAM,MAAM,0BAA0B,GAAG;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IACvC,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC;CACxC,CAAC;AAEF,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,0BAA0B,wCAK5E;AAED,MAAM,MAAM,yBAAyB,GAAG;IACtC,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC;IACvC,WAAW,EAAE,YAAY,CAAC;CAC3B,CAAC;AAEF,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,yBAAyB,uCAW1E"}
|
|
@@ -1,5 +1,58 @@
|
|
|
1
1
|
import { createYakHandler, createYakConfigHandler, createYakToolsHandler, } from "@yak-io/javascript/server";
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import * as path from "node:path";
|
|
2
4
|
import { scanRoutes } from "./scan-routes.js";
|
|
5
|
+
/**
|
|
6
|
+
* Default paths to check for pre-built route manifests
|
|
7
|
+
*/
|
|
8
|
+
const DEFAULT_MANIFEST_PATHS = [
|
|
9
|
+
"./yak-routes-manifest.json",
|
|
10
|
+
"./public/yak-routes-manifest.json",
|
|
11
|
+
];
|
|
12
|
+
/**
|
|
13
|
+
* Load a pre-built route manifest from disk.
|
|
14
|
+
*
|
|
15
|
+
* This should be used in production environments where filesystem scanning
|
|
16
|
+
* is not available (e.g., Vercel serverless functions).
|
|
17
|
+
*
|
|
18
|
+
* Generate the manifest at build time using:
|
|
19
|
+
* yak-nextjs generate-manifest --app-dir ./src/app --output ./public/yak-routes-manifest.json
|
|
20
|
+
*
|
|
21
|
+
* @param manifestPath - Path to the manifest JSON file (default: tries common locations)
|
|
22
|
+
* @returns Route manifest or null if not found
|
|
23
|
+
*/
|
|
24
|
+
export function loadRouteManifest(manifestPath) {
|
|
25
|
+
const pathsToTry = manifestPath ? [manifestPath] : [...DEFAULT_MANIFEST_PATHS];
|
|
26
|
+
for (const relativePath of pathsToTry) {
|
|
27
|
+
try {
|
|
28
|
+
const fullPath = path.resolve(process.cwd(), relativePath);
|
|
29
|
+
if (fs.existsSync(fullPath)) {
|
|
30
|
+
const content = fs.readFileSync(fullPath, "utf-8");
|
|
31
|
+
return JSON.parse(content);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Continue to next path
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Load routes from a pre-built manifest.
|
|
42
|
+
* Throws if manifest is not found.
|
|
43
|
+
*/
|
|
44
|
+
export function loadRoutes(manifestPath) {
|
|
45
|
+
const manifest = loadRouteManifest(manifestPath);
|
|
46
|
+
if (!manifest) {
|
|
47
|
+
const pathsChecked = manifestPath ? manifestPath : DEFAULT_MANIFEST_PATHS.join(", ");
|
|
48
|
+
throw new Error(`Route manifest not found. Checked: ${pathsChecked}\n\n` +
|
|
49
|
+
`In production environments (like Vercel), route scanning requires a pre-built manifest.\n` +
|
|
50
|
+
`Generate it at build time by adding to your build script:\n\n` +
|
|
51
|
+
` yak-nextjs generate-manifest --app-dir ./src/app --output ./public/yak-routes-manifest.json\n\n` +
|
|
52
|
+
`Or provide routes explicitly in your handler configuration.`);
|
|
53
|
+
}
|
|
54
|
+
return manifest.routes;
|
|
55
|
+
}
|
|
3
56
|
/**
|
|
4
57
|
* Create a unified Next.js App Router handler backed by the core primitives
|
|
5
58
|
*/
|
|
@@ -9,6 +62,34 @@ export function createNextYakHandler(config) {
|
|
|
9
62
|
tools: resolveToolSources(config),
|
|
10
63
|
});
|
|
11
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Attempt to scan routes from filesystem, with production-safe fallback.
|
|
67
|
+
*
|
|
68
|
+
* In development: scans the app directory directly
|
|
69
|
+
* In production (Vercel, etc.): falls back to pre-built manifest if directory doesn't exist
|
|
70
|
+
*/
|
|
71
|
+
function tryLoadRoutes(appDir) {
|
|
72
|
+
const targetDir = path.resolve(process.cwd(), appDir);
|
|
73
|
+
// If the app directory exists, scan it directly (development mode)
|
|
74
|
+
if (fs.existsSync(targetDir)) {
|
|
75
|
+
return scanRoutes(appDir);
|
|
76
|
+
}
|
|
77
|
+
// In production, the source directory doesn't exist - try loading from manifest
|
|
78
|
+
const manifest = loadRouteManifest();
|
|
79
|
+
if (manifest) {
|
|
80
|
+
return manifest.routes;
|
|
81
|
+
}
|
|
82
|
+
// Neither source nor manifest available - provide helpful error
|
|
83
|
+
throw new Error(`App directory not found: ${targetDir}\n\n` +
|
|
84
|
+
`This typically happens in production (Vercel, etc.) where source files aren't deployed.\n\n` +
|
|
85
|
+
`Solutions:\n` +
|
|
86
|
+
`1. Generate a route manifest at build time:\n` +
|
|
87
|
+
` Add to your build script: yak-nextjs generate-manifest --app-dir ./src/app --output ./public/yak-routes-manifest.json\n\n` +
|
|
88
|
+
`2. Provide routes explicitly:\n` +
|
|
89
|
+
` createNextYakHandler({ routes: [...] })\n\n` +
|
|
90
|
+
`3. Use getRoutes callback:\n` +
|
|
91
|
+
` createNextYakHandler({ getRoutes: async () => [...] })`);
|
|
92
|
+
}
|
|
12
93
|
function resolveRouteSources(config) {
|
|
13
94
|
if (config.routes) {
|
|
14
95
|
return config.routes;
|
|
@@ -16,7 +97,7 @@ function resolveRouteSources(config) {
|
|
|
16
97
|
if (config.getRoutes) {
|
|
17
98
|
return config.getRoutes;
|
|
18
99
|
}
|
|
19
|
-
return async () => applyRouteFilters(
|
|
100
|
+
return async () => applyRouteFilters(tryLoadRoutes(config.appDir ?? "./src/app"), config.routeFilter);
|
|
20
101
|
}
|
|
21
102
|
function applyRouteFilters(routes, filter) {
|
|
22
103
|
if (!filter) {
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { scanRoutes } from "./scan-routes.js";
|
|
2
2
|
export type { ScanRoutesOptions } from "./scan-routes.js";
|
|
3
|
-
export { createNextYakHandler, createNextYakConfigHandler, createNextYakToolsHandler, } from "./createNextYakHandler.js";
|
|
3
|
+
export { createNextYakHandler, createNextYakConfigHandler, createNextYakToolsHandler, loadRouteManifest, loadRoutes, } from "./createNextYakHandler.js";
|
|
4
4
|
export type { NextYakHandlerConfig, NextYakConfigHandlerConfig, NextYakToolsHandlerConfig, NextYakRouteFilter, } from "./createNextYakHandler.js";
|
|
5
5
|
export type { ToolExecutor, ToolCallPayload, ToolCallResult, ToolDefinition, ToolManifest, RouteInfo, RouteManifest, ChatConfig, } from "@yak-io/javascript/server";
|
|
6
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,OAAO,EACN,oBAAoB,EACpB,0BAA0B,EAC1B,yBAAyB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,OAAO,EACN,oBAAoB,EACpB,0BAA0B,EAC1B,yBAAyB,EACzB,iBAAiB,EACjB,UAAU,GACV,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACX,oBAAoB,EACpB,0BAA0B,EAC1B,yBAAyB,EACzB,kBAAkB,GAClB,MAAM,2BAA2B,CAAC;AAEnC,YAAY,EACX,YAAY,EACZ,eAAe,EACf,cAAc,EACd,cAAc,EACd,YAAY,EACZ,SAAS,EACT,aAAa,EACb,UAAU,GACV,MAAM,2BAA2B,CAAC"}
|
package/dist/server/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { scanRoutes } from "./scan-routes.js";
|
|
2
|
-
export { createNextYakHandler, createNextYakConfigHandler, createNextYakToolsHandler, } from "./createNextYakHandler.js";
|
|
2
|
+
export { createNextYakHandler, createNextYakConfigHandler, createNextYakToolsHandler, loadRouteManifest, loadRoutes, } from "./createNextYakHandler.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yak-io/nextjs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Next.js SDK for embedding yak chatbot with route manifest generation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -11,8 +11,7 @@
|
|
|
11
11
|
"directory": "packages/nextjs"
|
|
12
12
|
},
|
|
13
13
|
"publishConfig": {
|
|
14
|
-
"access": "public"
|
|
15
|
-
"provenance": false
|
|
14
|
+
"access": "public"
|
|
16
15
|
},
|
|
17
16
|
"keywords": [
|
|
18
17
|
"yak",
|