@yak-io/nextjs 0.1.2 → 0.1.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/README.md CHANGED
@@ -164,12 +164,12 @@ Behind the scenes `@yak-io/javascript` merges every `RouteSource` into a single
164
164
  yak-nextjs generate-manifest
165
165
  ```
166
166
 
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.
167
+ Use the CLI to pre-compute a manifest at build time. The JSON matches the runtime manifest structure exposed by the handlers.
168
168
 
169
169
  **Options:**
170
170
  - `--app-dir <path>` – Path to Next.js app directory (default: `./src/app`)
171
171
  - `--pages-dir <path>` – Path to Next.js pages directory (optional, scanned in addition to app-dir)
172
- - `--output <path>` – Output file path (default: `./yak-routes-manifest.json`)
172
+ - `--output <path>` – Output file path (default: `./public/yak-routes-manifest.json`)
173
173
 
174
174
  **Examples:**
175
175
  ```bash
@@ -197,22 +197,9 @@ Add a `prebuild` script to generate the manifest before Next.js builds:
197
197
  }
198
198
  ```
199
199
 
200
- This uses the defaults (`./src/app` `./yak-routes-manifest.json`). Customize if needed:
200
+ That's it! The manifest is generated to `./public/yak-routes-manifest.json` and the handler automatically fetches it at runtime on serverless platforms like Vercel. No code changes needed.
201
201
 
202
- ```json
203
- {
204
- "scripts": {
205
- "prebuild": "yak-nextjs generate-manifest --app-dir ./app --output ./routes.json"
206
- }
207
- }
208
- ```
209
-
210
- > **Important:** The manifest must be in the project root (not `public/`). On Vercel and other serverless platforms, files in `public/` are served via CDN and are not available on the function's filesystem.
211
-
212
- The handler checks these locations automatically:
213
- 1. `./yak-routes-manifest.json`
214
- 2. `./.next/yak-routes-manifest.json`
215
- 3. `./public/yak-routes-manifest.json` (only works in non-serverless environments)
202
+ The handler automatically detects the deployment environment (Vercel via `VERCEL_URL`, Netlify via `URL`, or custom `NEXT_PUBLIC_BASE_URL`) and fetches the manifest from the public folder.
216
203
 
217
204
  ### Alternative: explicit routes
218
205
 
@@ -227,24 +214,14 @@ export const { GET, POST } = createNextYakHandler({
227
214
  });
228
215
  ```
229
216
 
230
- ### Loading a custom manifest location
231
-
232
- ```ts
233
- import { createNextYakHandler, loadRoutes } from "@yak-io/nextjs/server";
234
-
235
- export const { GET, POST } = createNextYakHandler({
236
- routes: loadRoutes("./custom/manifest.json"),
237
- });
238
- ```
239
-
240
217
  ## API surface (server)
241
218
 
242
219
  `@yak-io/nextjs/server` exports:
243
220
 
244
221
  - `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.
245
- - `loadRouteManifest(path?: string)` – load a pre-built JSON manifest, returns `null` if not found. Checks `./yak-routes-manifest.json`, `./.next/yak-routes-manifest.json`, and `./public/yak-routes-manifest.json` by default.
222
+ - `loadRouteManifest(path?: string)` – load a pre-built JSON manifest via filesystem read, returns `null` if not found.
246
223
  - `loadRoutes(path?: string)` – load routes from a manifest, throws with helpful error if not found.
247
- - `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.
224
+ - `createNextYakHandler(config)` – unified GET + POST handler. When `routes`/`getRoutes` are omitted it auto-scans `./src/app` (override with `appDir`). In production, automatically fetches manifest from public folder.
248
225
  - `createNextYakConfigHandler(config)` – GET-only convenience wrapper.
249
226
  - `createNextYakToolsHandler(config)` – POST-only wrapper.
250
227
  - Re-exported types from `@yak-io/javascript/server` (RouteInfo, RouteManifest, ToolDefinition, ToolManifest, ToolExecutor, ChatConfig, RouteSourceInput, ToolSourceInput, etc.).
@@ -11,7 +11,7 @@
11
11
  * Options:
12
12
  * --app-dir <path> Path to Next.js app directory (default: ./src/app)
13
13
  * --pages-dir <path> Path to Next.js pages directory (optional, scanned in addition to app-dir)
14
- * --output <path> Output file path (default: ./yak-routes-manifest.json)
14
+ * --output <path> Output file path (default: ./public/yak-routes-manifest.json)
15
15
  */
16
16
  export {};
17
17
  //# sourceMappingURL=generate-manifest.d.ts.map
@@ -11,7 +11,7 @@
11
11
  * Options:
12
12
  * --app-dir <path> Path to Next.js app directory (default: ./src/app)
13
13
  * --pages-dir <path> Path to Next.js pages directory (optional, scanned in addition to app-dir)
14
- * --output <path> Output file path (default: ./yak-routes-manifest.json)
14
+ * --output <path> Output file path (default: ./public/yak-routes-manifest.json)
15
15
  */
16
16
  import * as fs from "node:fs";
17
17
  import * as path from "node:path";
@@ -201,7 +201,7 @@ function parseArgs() {
201
201
  const args = process.argv.slice(2);
202
202
  let appDir = "./src/app";
203
203
  let pagesDir = undefined;
204
- let output = "./yak-routes-manifest.json";
204
+ let output = "./public/yak-routes-manifest.json";
205
205
  let help = false;
206
206
  for (let i = 0; i < args.length; i++) {
207
207
  const arg = args[i];
@@ -238,7 +238,7 @@ Usage:
238
238
  Options:
239
239
  --app-dir <path> Path to Next.js app directory (default: ./src/app)
240
240
  --pages-dir <path> Path to Next.js pages directory (optional)
241
- --output <path> Output file path (default: ./yak-routes-manifest.json)
241
+ --output <path> Output file path (default: ./public/yak-routes-manifest.json)
242
242
  --help, -h Show this help message
243
243
 
244
244
  Examples:
@@ -290,6 +290,7 @@ function main() {
290
290
  generated_at: new Date().toISOString(),
291
291
  };
292
292
  const outputPath = path.resolve(process.cwd(), output);
293
+ // Write JSON manifest
293
294
  fs.writeFileSync(outputPath, JSON.stringify(manifest, null, 2), "utf-8");
294
295
  console.log(`✅ Generated manifest with ${uniqueRoutes.length} page routes`);
295
296
  console.log(` Output: ${outputPath}`);
@@ -1,9 +1,8 @@
1
1
  import type { RouteSourceInput, ToolSourceInput, RouteInfo, RouteManifest, ToolManifest, ToolExecutor } from "@yak-io/javascript/server";
2
2
  /**
3
- * Load a pre-built route manifest from disk.
3
+ * Load a pre-built route manifest from disk (JSON file).
4
4
  *
5
- * This should be used in production environments where filesystem scanning
6
- * is not available (e.g., Vercel serverless functions).
5
+ * This works in traditional Node.js deployments where the filesystem is available.
7
6
  *
8
7
  * Generate the manifest at build time using:
9
8
  * yak-nextjs generate-manifest
@@ -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,aAAa,EACb,YAAY,EACZ,YAAY,EACb,MAAM,2BAA2B,CAAC;AAgBnC;;;;;;;;;;;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
+ {"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;AAiBnC;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAgB7E;AAgED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,CAe7D;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;AAmGD,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"}
@@ -3,22 +3,21 @@ import * as fs from "node:fs";
3
3
  import * as path from "node:path";
4
4
  import { scanRoutes } from "./scan-routes.js";
5
5
  /**
6
- * Default paths to check for pre-built route manifests.
7
- *
8
- * On Vercel/serverless, files in `public/` are served via CDN and NOT available
9
- * on the function's filesystem. The manifest must be in the project root or
10
- * another location that gets bundled with the serverless function.
6
+ * Default paths to check for pre-built route manifests (JSON files).
7
+ * These are read via fs.readFileSync at runtime.
11
8
  */
12
9
  const DEFAULT_MANIFEST_PATHS = [
10
+ "./public/yak-routes-manifest.json",
13
11
  "./yak-routes-manifest.json",
14
- "./.next/yak-routes-manifest.json",
15
- "./public/yak-routes-manifest.json", // Only works in non-serverless environments
16
12
  ];
17
13
  /**
18
- * Load a pre-built route manifest from disk.
14
+ * Public URL path where the manifest is served from (when in public/).
15
+ */
16
+ const PUBLIC_MANIFEST_URL = "/yak-routes-manifest.json";
17
+ /**
18
+ * Load a pre-built route manifest from disk (JSON file).
19
19
  *
20
- * This should be used in production environments where filesystem scanning
21
- * is not available (e.g., Vercel serverless functions).
20
+ * This works in traditional Node.js deployments where the filesystem is available.
22
21
  *
23
22
  * Generate the manifest at build time using:
24
23
  * yak-nextjs generate-manifest
@@ -42,6 +41,59 @@ export function loadRouteManifest(manifestPath) {
42
41
  }
43
42
  return null;
44
43
  }
44
+ /**
45
+ * Fetch the route manifest from the public URL.
46
+ * Used in serverless environments where filesystem access is not available.
47
+ */
48
+ async function fetchRouteManifest() {
49
+ // Try to determine the base URL for fetching
50
+ const baseUrl = getBaseUrl();
51
+ if (!baseUrl) {
52
+ return null;
53
+ }
54
+ try {
55
+ const url = new URL(PUBLIC_MANIFEST_URL, baseUrl);
56
+ const response = await fetch(url.toString(), {
57
+ headers: { "Accept": "application/json" },
58
+ cache: "no-store",
59
+ });
60
+ if (!response.ok) {
61
+ return null;
62
+ }
63
+ const manifest = await response.json();
64
+ if (manifest?.routes) {
65
+ return manifest;
66
+ }
67
+ }
68
+ catch {
69
+ // Fetch failed
70
+ }
71
+ return null;
72
+ }
73
+ /**
74
+ * Get the base URL for the current deployment.
75
+ * Supports Vercel, Netlify, and custom configurations.
76
+ */
77
+ function getBaseUrl() {
78
+ // Vercel provides VERCEL_URL (without protocol)
79
+ if (process.env.VERCEL_URL) {
80
+ const protocol = process.env.VERCEL_ENV === "development" ? "http" : "https";
81
+ return `${protocol}://${process.env.VERCEL_URL}`;
82
+ }
83
+ // Netlify provides URL
84
+ if (process.env.URL) {
85
+ return process.env.URL;
86
+ }
87
+ // Custom base URL
88
+ if (process.env.NEXT_PUBLIC_BASE_URL) {
89
+ return process.env.NEXT_PUBLIC_BASE_URL;
90
+ }
91
+ // For local development
92
+ if (process.env.NODE_ENV === "development") {
93
+ return "http://localhost:3000";
94
+ }
95
+ return null;
96
+ }
45
97
  /**
46
98
  * Load routes from a pre-built manifest.
47
99
  * Throws if manifest is not found.
@@ -49,7 +101,9 @@ export function loadRouteManifest(manifestPath) {
49
101
  export function loadRoutes(manifestPath) {
50
102
  const manifest = loadRouteManifest(manifestPath);
51
103
  if (!manifest) {
52
- const pathsChecked = manifestPath ? manifestPath : DEFAULT_MANIFEST_PATHS.join(", ");
104
+ const pathsChecked = manifestPath
105
+ ? manifestPath
106
+ : [...DEFAULT_MANIFEST_PATHS].join(", ");
53
107
  throw new Error(`Route manifest not found. Checked: ${pathsChecked}\n\n` +
54
108
  `In production environments (like Vercel), route scanning requires a pre-built manifest.\n` +
55
109
  `Generate it at build time by adding to your build script:\n\n` +
@@ -68,30 +122,36 @@ export function createNextYakHandler(config) {
68
122
  });
69
123
  }
70
124
  /**
71
- * Attempt to scan routes from filesystem, with production-safe fallback.
125
+ * Attempt to load routes from filesystem or fetch from public URL.
72
126
  *
73
127
  * In development: scans the app directory directly
74
- * In production (Vercel, etc.): falls back to pre-built manifest if directory doesn't exist
128
+ * In production (Vercel, etc.): falls back to pre-built manifest via filesystem or HTTP fetch
75
129
  */
76
- function tryLoadRoutes(appDir) {
130
+ async function tryLoadRoutes(appDir) {
77
131
  const targetDir = path.resolve(process.cwd(), appDir);
78
132
  // If the app directory exists, scan it directly (development mode)
79
133
  if (fs.existsSync(targetDir)) {
80
134
  return scanRoutes(appDir);
81
135
  }
82
- // In production, the source directory doesn't exist - try loading from manifest
136
+ // In production, the source directory doesn't exist - try loading from manifest file
83
137
  const manifest = loadRouteManifest();
84
138
  if (manifest) {
85
139
  return manifest.routes;
86
140
  }
141
+ // Try fetching from public URL (works on Vercel/serverless)
142
+ const fetchedManifest = await fetchRouteManifest();
143
+ if (fetchedManifest) {
144
+ return fetchedManifest.routes;
145
+ }
87
146
  // Neither source nor manifest available - provide helpful error
88
147
  throw new Error(`App directory not found: ${targetDir}\n\n` +
89
148
  `This typically happens in production (Vercel, etc.) where source files aren't deployed.\n\n` +
90
149
  `Solutions:\n` +
91
- `1. Generate a route manifest at build time:\n` +
92
- ` Add to your build script: yak-nextjs generate-manifest\n\n` +
150
+ `1. Generate a route manifest at build time (recommended):\n` +
151
+ ` Add to package.json: "prebuild": "yak-nextjs generate-manifest"\n` +
152
+ ` The manifest will be placed in public/ and automatically loaded.\n\n` +
93
153
  `2. Provide routes explicitly:\n` +
94
- ` createNextYakHandler({ routes: [...] })\n\n` +
154
+ ` createNextYakHandler({ routes: [{ path: "/", title: "Home" }, ...] })\n\n` +
95
155
  `3. Use getRoutes callback:\n` +
96
156
  ` createNextYakHandler({ getRoutes: async () => [...] })`);
97
157
  }
@@ -102,7 +162,10 @@ function resolveRouteSources(config) {
102
162
  if (config.getRoutes) {
103
163
  return config.getRoutes;
104
164
  }
105
- return async () => applyRouteFilters(tryLoadRoutes(config.appDir ?? "./src/app"), config.routeFilter);
165
+ return async () => {
166
+ const routes = await tryLoadRoutes(config.appDir ?? "./src/app");
167
+ return applyRouteFilters(routes, config.routeFilter);
168
+ };
106
169
  }
107
170
  function applyRouteFilters(routes, filter) {
108
171
  if (!filter) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yak-io/nextjs",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
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",