geo-ai-next 0.1.1 → 0.2.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.
package/README.md CHANGED
@@ -2,9 +2,11 @@
2
2
 
3
3
  [![npm](https://img.shields.io/npm/v/geo-ai-next)](https://npmjs.com/package/geo-ai-next)
4
4
 
5
- Part of the [GEO AI ecosystem](https://github.com/madeburo/GEO-AI). Full documentation → [geo-ai-core](https://npmjs.com/package/geo-ai-core)
5
+ Part of the [GEO AI – AI Search Optimization](https://www.geoai.run) ecosystem. [GitHub](https://github.com/madeburo/GEO-AI)
6
6
 
7
- Thin Next.js wrapper for [geo-ai-core](../core) — middleware and App Router route handler for serving `llms.txt` / `llms-full.txt`.
7
+ Next.js integration for [geo-ai-core](https://npmjs.com/package/geo-ai-core) — static file generation, middleware, and App Router route handler for `llms.txt` / `llms-full.txt`.
8
+
9
+ Try the analyzer at [geoai.run/analyze](https://www.geoai.run/analyze)
8
10
 
9
11
  ## Installation
10
12
 
@@ -14,9 +16,237 @@ npm install geo-ai-next
14
16
 
15
17
  Peer dependency: `next >= 16`
16
18
 
19
+ ---
20
+
21
+ ## Recommended Production Setup
22
+
23
+ The shortest path to working GEO AI files in production:
24
+
25
+ **1.** Create `geo-ai.config.mjs` in your project root
26
+ **2.** Add the build script to `package.json`
27
+ **3.** Run `npm run build` — files appear in `public/`
28
+ **4.** Deploy — done
29
+
30
+ ```json
31
+ {
32
+ "scripts": {
33
+ "geo:generate": "geo-ai-generate",
34
+ "build": "npm run geo:generate && next build"
35
+ }
36
+ }
37
+ ```
38
+
39
+ ```js
40
+ // geo-ai.config.mjs
41
+ export default {
42
+ siteName: 'My Site',
43
+ siteUrl: 'https://example.com',
44
+ provider: { Pages: [{ title: 'Home', url: '/', description: 'Welcome' }] },
45
+ crawlers: 'all',
46
+ };
47
+ ```
48
+
49
+ After build, verify:
50
+ ```bash
51
+ ls public/llms.txt public/llms-full.txt # both files present
52
+ ```
53
+
54
+ Full details and options in the sections below.
55
+
56
+ ---
57
+
58
+ ## llms.txt vs llms-full.txt
59
+
60
+ Both files follow the [llms.txt standard](https://llmstxt.org) for making site content readable by AI search engines.
61
+
62
+ | File | Purpose | Content |
63
+ |------|---------|---------|
64
+ | `llms.txt` | Concise index for AI crawlers | Site name, description, crawler rules, resource list with titles, URLs, and short descriptions |
65
+ | `llms-full.txt` | Extended version for deep indexing | Everything in `llms.txt` plus full page content, product pricing, availability, and variants |
66
+
67
+ AI crawlers like GPTBot and ClaudeBot discover `llms.txt` first. If they need more detail — for example to answer a product question — they fetch `llms-full.txt`. Serving both maximizes your site's visibility in AI search results.
68
+
69
+ ---
70
+
71
+ ## Static File Generation (Recommended)
72
+
73
+ The most reliable approach for production. Generates `public/llms.txt` and `public/llms-full.txt` as static files before `next build` — Next.js serves them automatically, no middleware needed.
74
+
75
+ ```typescript
76
+ // scripts/generate-llms.ts
77
+ import { generateLlmsFiles } from 'geo-ai-next';
78
+
79
+ await generateLlmsFiles({
80
+ siteName: 'My Site',
81
+ siteUrl: 'https://example.com',
82
+ siteDescription: 'AI-optimized site description',
83
+ provider: {
84
+ Pages: [
85
+ { title: 'Home', url: '/', description: 'Welcome page' },
86
+ { title: 'About', url: '/about', description: 'About us' },
87
+ ],
88
+ Products: [
89
+ { title: 'Widget', url: '/products/widget', description: 'A great widget', price: '$29' },
90
+ ],
91
+ },
92
+ crawlers: 'all',
93
+ });
94
+ ```
95
+
96
+ Add to `package.json`:
97
+
98
+ ```json
99
+ {
100
+ "scripts": {
101
+ "geo:generate": "geo-ai-generate",
102
+ "build": "npm run geo:generate && next build"
103
+ }
104
+ }
105
+ ```
106
+
107
+ After `npm run build`, both files are written to `public/` and served at:
108
+ - `https://yoursite.com/llms.txt`
109
+ - `https://yoursite.com/llms-full.txt`
110
+
111
+ ### Options
112
+
113
+ | Option | Type | Default | Description |
114
+ |--------|------|---------|-------------|
115
+ | `outDir` | `string` | `'public'` | Output directory (relative to cwd) |
116
+ | `locale` | `string` | — | Locale for content generation |
117
+ | + all `GeoAIConfig` options | | | `siteName`, `siteUrl`, `provider`, `crawlers`, `cache`, etc. |
118
+
119
+ ### CLI
120
+
121
+ The `geo-ai-generate` binary is included in the package. It reads `geo-ai.config.mjs` from your project root by default.
122
+
123
+ ```bash
124
+ # Run directly (reads geo-ai.config.mjs)
125
+ npx geo-ai-generate
126
+
127
+ # Custom config path
128
+ npx geo-ai-generate --config ./config/geo-ai.mjs
129
+ ```
130
+
131
+ Example `geo-ai.config.mjs`:
132
+
133
+ ```js
134
+ // geo-ai.config.mjs
135
+ export default {
136
+ siteName: 'My Site',
137
+ siteUrl: 'https://example.com',
138
+ provider: {
139
+ Pages: [
140
+ { title: 'Home', url: '/', description: 'Welcome' },
141
+ { title: 'About', url: '/about', description: 'About us' },
142
+ ],
143
+ },
144
+ crawlers: 'all',
145
+ };
146
+ ```
147
+
148
+ With this config file in place, your `package.json` scripts become:
149
+
150
+ ```json
151
+ {
152
+ "scripts": {
153
+ "geo:generate": "geo-ai-generate",
154
+ "build": "npm run geo:generate && next build"
155
+ }
156
+ }
157
+ ```
158
+
159
+ ### Troubleshooting: 404 on `/llms.txt`
160
+
161
+ 1. Make sure `generateLlmsFiles()` runs before `next build`
162
+ 2. Check that `public/llms.txt` exists after generation
163
+ 3. Vercel and Netlify serve `public/` automatically — no extra config needed
164
+ 4. For custom servers, ensure static file serving is configured for the `public/` directory
165
+
166
+ ---
167
+
168
+ ## End-to-End Example
169
+
170
+ Minimal Next.js app that generates and serves both files:
171
+
172
+ **1. Install**
173
+ ```bash
174
+ npm install geo-ai-next
175
+ ```
176
+
177
+ **2. Create `geo-ai.config.mjs`**
178
+ ```js
179
+ export default {
180
+ siteName: 'Acme Store',
181
+ siteUrl: 'https://acme.example.com',
182
+ siteDescription: 'Quality widgets for every need',
183
+ provider: {
184
+ Pages: [
185
+ { title: 'Home', url: '/', description: 'Welcome to Acme Store' },
186
+ { title: 'About', url: '/about', description: 'Our story' },
187
+ ],
188
+ Products: [
189
+ {
190
+ title: 'Classic Widget',
191
+ url: '/products/classic',
192
+ description: 'Our best-selling widget',
193
+ price: '$29.99',
194
+ available: true,
195
+ },
196
+ ],
197
+ },
198
+ crawlers: 'all',
199
+ };
200
+ ```
201
+
202
+ **3. Add scripts to `package.json`**
203
+ ```json
204
+ {
205
+ "scripts": {
206
+ "geo:generate": "geo-ai-generate",
207
+ "build": "npm run geo:generate && next build"
208
+ }
209
+ }
210
+ ```
211
+
212
+ **4. Run build**
213
+ ```bash
214
+ npm run build
215
+ ```
216
+
217
+ Output:
218
+ ```
219
+ [geo-ai] Generating llms files → /your-project/public
220
+ [geo-ai] ✓ /your-project/public/llms.txt (843 bytes)
221
+ [geo-ai] ✓ /your-project/public/llms-full.txt (1204 bytes)
222
+ [geo-ai] Done.
223
+ ```
224
+
225
+ **5. Verify**
226
+ ```bash
227
+ curl https://acme.example.com/llms.txt
228
+ curl https://acme.example.com/llms-full.txt
229
+ ```
230
+
231
+ Both return `200 OK` with `text/plain` content — no middleware, no route handler needed.
232
+
233
+ ---
234
+
235
+ ## Runtime Serving (Alternative)
236
+
237
+ If you were already using middleware or a route handler, they continue to work. Static generation is the recommended production approach, but runtime serving is still valid for dynamic use cases like per-request locale or content that changes too frequently to regenerate at build time.
238
+
239
+ | Approach | When to use |
240
+ |----------|-------------|
241
+ | Static generation (`generateLlmsFiles`) | Production default — works on Vercel, Netlify, any static host |
242
+ | Middleware (`geoAIMiddleware`) | Dynamic content per-request, edge locale detection |
243
+ | Route handler (`createLlmsHandler`) | Custom route path, App Router, programmatic control |
244
+
245
+ ---
246
+
17
247
  ## Middleware
18
248
 
19
- Intercepts `/llms.txt` and `/llms-full.txt` requests, passes everything else through:
249
+ Intercepts `/llms.txt` and `/llms-full.txt` at the edge, passes everything else through. Use this when you need dynamic content per-request (e.g. locale from cookies, A/B testing).
20
250
 
21
251
  ```typescript
22
252
  // middleware.ts
@@ -27,7 +257,7 @@ export default geoAIMiddleware({
27
257
  siteUrl: 'https://example.com',
28
258
  provider: new MyProvider(),
29
259
  cache: '24h',
30
- cacheMaxAge: 3600, // Cache-Control max-age in seconds (default 3600)
260
+ cacheMaxAge: 3600, // Cache-Control max-age in seconds (default 3600)
31
261
  injectLinkHeader: true, // adds Link header to all responses
32
262
  });
33
263
 
@@ -36,9 +266,11 @@ export const config = {
36
266
  };
37
267
  ```
38
268
 
269
+ ---
270
+
39
271
  ## Route Handler
40
272
 
41
- For App Router — serves llms content at any route you choose:
273
+ For App Router — serves llms content at a custom route. File type is determined by URL path (`/llms-full.txt`) or query param `?type=full`.
42
274
 
43
275
  ```typescript
44
276
  // app/llms/route.ts
@@ -48,15 +280,15 @@ export const { GET } = createLlmsHandler({
48
280
  siteName: 'My Site',
49
281
  siteUrl: 'https://example.com',
50
282
  provider: new MyProvider(),
51
- cacheMaxAge: 7200, // optional, default 3600
283
+ cacheMaxAge: 3600, // optional, default 3600
52
284
  });
53
285
  ```
54
286
 
55
- Type is determined by URL path (`/llms-full.txt`) or query param `?type=full`.
287
+ ---
56
288
 
57
289
  ## Re-exports
58
290
 
59
- All public API from `geo-ai-core` is re-exported, so you don't need to install both:
291
+ All public API from `geo-ai-core` is re-exported no need to install both packages:
60
292
 
61
293
  ```typescript
62
294
  import {
@@ -67,9 +299,12 @@ import {
67
299
  AI_BOTS,
68
300
  type ContentProvider,
69
301
  type Resource,
302
+ type GeoAIConfig,
70
303
  } from 'geo-ai-next';
71
304
  ```
72
305
 
306
+ ---
307
+
73
308
  ## Requirements
74
309
 
75
310
  - Node.js >= 20
package/dist/cli.mjs ADDED
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __esm = (fn, res) => function __init() {
5
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
+ };
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+
12
+ // src/generate.ts
13
+ var generate_exports = {};
14
+ __export(generate_exports, {
15
+ generateLlmsFiles: () => generateLlmsFiles
16
+ });
17
+ import { createGeoAI } from "geo-ai-core";
18
+ import { writeFile, mkdir } from "fs/promises";
19
+ import { join, resolve } from "path";
20
+ async function generateLlmsFiles(config) {
21
+ const outDir = resolve(config.outDir ?? "public");
22
+ console.log(`[geo-ai] Generating llms files \u2192 ${outDir}`);
23
+ const core = createGeoAI(config);
24
+ await mkdir(outDir, { recursive: true });
25
+ const [llmsContent, llmsFullContent] = await Promise.all([
26
+ core.generateLlms(false, config.locale),
27
+ core.generateLlms(true, config.locale)
28
+ ]);
29
+ const llmsPath = join(outDir, "llms.txt");
30
+ const llmsFullPath = join(outDir, "llms-full.txt");
31
+ const tmpLlms = `${llmsPath}.tmp`;
32
+ const tmpFull = `${llmsFullPath}.tmp`;
33
+ try {
34
+ await Promise.all([
35
+ writeFile(tmpLlms, llmsContent, "utf-8"),
36
+ writeFile(tmpFull, llmsFullContent, "utf-8")
37
+ ]);
38
+ const { rename } = await import("fs/promises");
39
+ await Promise.all([
40
+ rename(tmpLlms, llmsPath),
41
+ rename(tmpFull, llmsFullPath)
42
+ ]);
43
+ } catch (err) {
44
+ const { unlink } = await import("fs/promises");
45
+ await unlink(tmpLlms).catch(() => {
46
+ });
47
+ await unlink(tmpFull).catch(() => {
48
+ });
49
+ throw err;
50
+ }
51
+ console.log(`[geo-ai] \u2713 ${llmsPath} (${llmsContent.length} bytes)`);
52
+ console.log(`[geo-ai] \u2713 ${llmsFullPath} (${llmsFullContent.length} bytes)`);
53
+ return { llmsPath, llmsFullPath };
54
+ }
55
+ var init_generate = __esm({
56
+ "src/generate.ts"() {
57
+ "use strict";
58
+ }
59
+ });
60
+
61
+ // src/cli.ts
62
+ import { resolve as resolve2 } from "path";
63
+ import { pathToFileURL } from "url";
64
+ async function main() {
65
+ const args = process.argv.slice(2);
66
+ let configPath = resolve2("geo-ai.config.ts");
67
+ const configIdx = args.indexOf("--config");
68
+ if (configIdx !== -1 && args[configIdx + 1]) {
69
+ configPath = resolve2(args[configIdx + 1]);
70
+ }
71
+ let config;
72
+ try {
73
+ const mod = await import(pathToFileURL(configPath).href);
74
+ config = mod.default ?? mod;
75
+ } catch {
76
+ const jsPath = configPath.replace(/\.ts$/, ".mjs");
77
+ try {
78
+ const mod = await import(pathToFileURL(jsPath).href);
79
+ config = mod.default ?? mod;
80
+ } catch {
81
+ console.error(`[geo-ai] Could not load config from ${configPath}`);
82
+ console.error(`[geo-ai] Create a geo-ai.config.ts (or .mjs) file in your project root.`);
83
+ console.error(`[geo-ai] Example:
84
+ `);
85
+ console.error(` import type { GenerateLlmsFilesConfig } from 'geo-ai-next';`);
86
+ console.error(` export default {`);
87
+ console.error(` siteName: 'My Site',`);
88
+ console.error(` siteUrl: 'https://example.com',`);
89
+ console.error(` provider: { Pages: [{ title: 'Home', url: '/' }] },`);
90
+ console.error(` } satisfies GenerateLlmsFilesConfig;
91
+ `);
92
+ process.exit(1);
93
+ }
94
+ }
95
+ const { generateLlmsFiles: generateLlmsFiles2 } = await Promise.resolve().then(() => (init_generate(), generate_exports));
96
+ await generateLlmsFiles2(config);
97
+ console.log("[geo-ai] Done.");
98
+ }
99
+ main().catch((err) => {
100
+ console.error("[geo-ai] Generation failed:", err);
101
+ process.exit(1);
102
+ });
package/dist/index.cjs CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,22 +17,31 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
21
31
  var src_exports = {};
22
32
  __export(src_exports, {
23
- AI_BOTS: () => import_geo_ai_core3.AI_BOTS,
24
- BotRulesEngine: () => import_geo_ai_core3.BotRulesEngine,
25
- CrawlTracker: () => import_geo_ai_core3.CrawlTracker,
26
- CryptoService: () => import_geo_ai_core3.CryptoService,
27
- FileCacheAdapter: () => import_geo_ai_core3.FileCacheAdapter,
28
- LlmsGenerator: () => import_geo_ai_core3.LlmsGenerator,
29
- MemoryCacheAdapter: () => import_geo_ai_core3.MemoryCacheAdapter,
30
- MemoryCrawlStore: () => import_geo_ai_core3.MemoryCrawlStore,
31
- SeoGenerator: () => import_geo_ai_core3.SeoGenerator,
32
- createGeoAI: () => import_geo_ai_core3.createGeoAI,
33
+ AI_BOTS: () => import_geo_ai_core4.AI_BOTS,
34
+ BotRulesEngine: () => import_geo_ai_core4.BotRulesEngine,
35
+ CrawlTracker: () => import_geo_ai_core4.CrawlTracker,
36
+ CryptoService: () => import_geo_ai_core4.CryptoService,
37
+ FileCacheAdapter: () => import_geo_ai_core4.FileCacheAdapter,
38
+ LlmsGenerator: () => import_geo_ai_core4.LlmsGenerator,
39
+ MemoryCacheAdapter: () => import_geo_ai_core4.MemoryCacheAdapter,
40
+ MemoryCrawlStore: () => import_geo_ai_core4.MemoryCrawlStore,
41
+ SeoGenerator: () => import_geo_ai_core4.SeoGenerator,
42
+ createGeoAI: () => import_geo_ai_core4.createGeoAI,
33
43
  createLlmsHandler: () => createLlmsHandler,
44
+ generateLlmsFiles: () => generateLlmsFiles,
34
45
  geoAIMiddleware: () => geoAIMiddleware
35
46
  });
36
47
  module.exports = __toCommonJS(src_exports);
@@ -102,8 +113,48 @@ function createLlmsHandler(config) {
102
113
  };
103
114
  }
104
115
 
105
- // src/index.ts
116
+ // src/generate.ts
106
117
  var import_geo_ai_core3 = require("geo-ai-core");
118
+ var import_promises = require("fs/promises");
119
+ var import_node_path = require("path");
120
+ async function generateLlmsFiles(config) {
121
+ const outDir = (0, import_node_path.resolve)(config.outDir ?? "public");
122
+ console.log(`[geo-ai] Generating llms files \u2192 ${outDir}`);
123
+ const core = (0, import_geo_ai_core3.createGeoAI)(config);
124
+ await (0, import_promises.mkdir)(outDir, { recursive: true });
125
+ const [llmsContent, llmsFullContent] = await Promise.all([
126
+ core.generateLlms(false, config.locale),
127
+ core.generateLlms(true, config.locale)
128
+ ]);
129
+ const llmsPath = (0, import_node_path.join)(outDir, "llms.txt");
130
+ const llmsFullPath = (0, import_node_path.join)(outDir, "llms-full.txt");
131
+ const tmpLlms = `${llmsPath}.tmp`;
132
+ const tmpFull = `${llmsFullPath}.tmp`;
133
+ try {
134
+ await Promise.all([
135
+ (0, import_promises.writeFile)(tmpLlms, llmsContent, "utf-8"),
136
+ (0, import_promises.writeFile)(tmpFull, llmsFullContent, "utf-8")
137
+ ]);
138
+ const { rename } = await import("fs/promises");
139
+ await Promise.all([
140
+ rename(tmpLlms, llmsPath),
141
+ rename(tmpFull, llmsFullPath)
142
+ ]);
143
+ } catch (err) {
144
+ const { unlink } = await import("fs/promises");
145
+ await unlink(tmpLlms).catch(() => {
146
+ });
147
+ await unlink(tmpFull).catch(() => {
148
+ });
149
+ throw err;
150
+ }
151
+ console.log(`[geo-ai] \u2713 ${llmsPath} (${llmsContent.length} bytes)`);
152
+ console.log(`[geo-ai] \u2713 ${llmsFullPath} (${llmsFullContent.length} bytes)`);
153
+ return { llmsPath, llmsFullPath };
154
+ }
155
+
156
+ // src/index.ts
157
+ var import_geo_ai_core4 = require("geo-ai-core");
107
158
  // Annotate the CommonJS export names for ESM import in node:
108
159
  0 && (module.exports = {
109
160
  AI_BOTS,
@@ -117,6 +168,7 @@ var import_geo_ai_core3 = require("geo-ai-core");
117
168
  SeoGenerator,
118
169
  createGeoAI,
119
170
  createLlmsHandler,
171
+ generateLlmsFiles,
120
172
  geoAIMiddleware
121
173
  });
122
174
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/middleware.ts","../src/handler.ts"],"sourcesContent":["// geo-ai-next main entry point\n\n// Next.js middleware\nexport { geoAIMiddleware } from './middleware';\nexport type { GeoAIMiddlewareConfig } from './middleware';\n\n// Next.js route handler\nexport { createLlmsHandler } from './handler';\nexport type { LlmsHandlerConfig } from './handler';\n\n// Re-export all public types, interfaces, and classes from geo-ai-core\nexport {\n createGeoAI,\n MemoryCacheAdapter,\n FileCacheAdapter,\n CrawlTracker,\n MemoryCrawlStore,\n CryptoService,\n BotRulesEngine,\n AI_BOTS,\n SeoGenerator,\n LlmsGenerator,\n} from 'geo-ai-core';\n\nexport type {\n GeoAIInstance,\n Resource,\n ProductResource,\n ResourceSection,\n ContentProvider,\n CacheAdapter,\n CrawlEntry,\n CrawlActivity,\n CrawlStore,\n CrawlTrackingConfig,\n CryptoConfig,\n GeoAIConfig,\n AiProvider,\n AiGeneratorConfig,\n AiError,\n AiBulkConfig,\n AiContext,\n} from 'geo-ai-core';\n","import { NextResponse } from 'next/server';\nimport type { NextRequest } from 'next/server';\nimport { createGeoAI } from 'geo-ai-core';\nimport type { GeoAIConfig, GeoAIInstance } from 'geo-ai-core';\n\n// ── Config ──────────────────────────────────────────────────────────\n\nexport interface GeoAIMiddlewareConfig extends GeoAIConfig {\n /** Inject Link header pointing to llms.txt on non-llms responses. Default: false */\n injectLinkHeader?: boolean;\n /** Cache-Control max-age in seconds for llms.txt responses. Default: 3600 */\n cacheMaxAge?: number;\n}\n\n// ── Middleware factory ───────────────────────────────────────────────\n\n/**\n * Creates a Next.js middleware function that intercepts `/llms.txt` and\n * `/llms-full.txt` requests, returning generated content as `text/plain`.\n * All other paths are passed through via `NextResponse.next()`.\n */\nexport function geoAIMiddleware(\n config: GeoAIMiddlewareConfig,\n): (request: NextRequest) => Promise<NextResponse> {\n const core: GeoAIInstance = createGeoAI(config);\n const injectLink = config.injectLinkHeader ?? false;\n const maxAge = config.cacheMaxAge ?? 3600;\n\n return async (request: NextRequest): Promise<NextResponse> => {\n const { pathname } = request.nextUrl;\n\n // ── Match llms paths ───────────────────────────────────────────\n if (pathname === '/llms.txt' || pathname === '/llms-full.txt') {\n const isFull = pathname === '/llms-full.txt';\n\n try {\n const content = await core.generateLlms(isFull);\n\n // Fire-and-forget: track visit without blocking the response\n core.trackVisit(request as unknown as Request).catch(() => {});\n\n return new NextResponse(content, {\n status: 200,\n headers: {\n 'Content-Type': 'text/plain; charset=utf-8',\n 'Cache-Control': `public, max-age=${maxAge}`,\n },\n });\n } catch {\n return new NextResponse('Internal Server Error', {\n status: 500,\n headers: { 'Content-Type': 'text/plain; charset=utf-8' },\n });\n }\n }\n\n // ── Passthrough ────────────────────────────────────────────────\n const response = NextResponse.next();\n\n if (injectLink) {\n response.headers.set('Link', core.generateLinkHeader());\n }\n\n return response;\n };\n}\n","import { createGeoAI } from 'geo-ai-core';\nimport type { GeoAIConfig, GeoAIInstance } from 'geo-ai-core';\n\n// ── Config ──────────────────────────────────────────────────────────\n\nexport interface LlmsHandlerConfig extends GeoAIConfig {\n /** Cache-Control max-age in seconds for llms.txt responses. Default: 3600 */\n cacheMaxAge?: number;\n}\n\n// ── Route Handler factory ───────────────────────────────────────────\n\n/**\n * Creates a Next.js App Router route handler that serves llms.txt content.\n * File type is determined by URL path (`/llms-full.txt`) or query `?type=full`.\n *\n * Usage in `app/llms/route.ts`:\n * ```ts\n * export const { GET } = createLlmsHandler({ ... });\n * ```\n */\nexport function createLlmsHandler(config: LlmsHandlerConfig): {\n GET: (request: Request) => Promise<Response>;\n} {\n const core: GeoAIInstance = createGeoAI(config);\n const maxAge = config.cacheMaxAge ?? 3600;\n\n return {\n async GET(request: Request): Promise<Response> {\n const url = new URL(request.url);\n const isFull =\n url.pathname.endsWith('/llms-full.txt') ||\n url.searchParams.get('type') === 'full';\n\n try {\n const content = await core.generateLlms(isFull);\n\n // Fire-and-forget: log bot visit without blocking the response\n core.trackVisit(request).catch(() => {});\n\n return new Response(content, {\n status: 200,\n headers: {\n 'Content-Type': 'text/plain; charset=utf-8',\n 'Cache-Control': `public, max-age=${maxAge}`,\n },\n });\n } catch {\n return new Response('Internal Server Error', {\n status: 500,\n headers: { 'Content-Type': 'text/plain; charset=utf-8' },\n });\n }\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,oBAA6B;AAE7B,yBAA4B;AAmBrB,SAAS,gBACd,QACiD;AACjD,QAAM,WAAsB,gCAAY,MAAM;AAC9C,QAAM,aAAa,OAAO,oBAAoB;AAC9C,QAAM,SAAS,OAAO,eAAe;AAErC,SAAO,OAAO,YAAgD;AAC5D,UAAM,EAAE,SAAS,IAAI,QAAQ;AAG7B,QAAI,aAAa,eAAe,aAAa,kBAAkB;AAC7D,YAAM,SAAS,aAAa;AAE5B,UAAI;AACF,cAAM,UAAU,MAAM,KAAK,aAAa,MAAM;AAG9C,aAAK,WAAW,OAA6B,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAE7D,eAAO,IAAI,2BAAa,SAAS;AAAA,UAC/B,QAAQ;AAAA,UACR,SAAS;AAAA,YACP,gBAAgB;AAAA,YAChB,iBAAiB,mBAAmB,MAAM;AAAA,UAC5C;AAAA,QACF,CAAC;AAAA,MACH,QAAQ;AACN,eAAO,IAAI,2BAAa,yBAAyB;AAAA,UAC/C,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,4BAA4B;AAAA,QACzD,CAAC;AAAA,MACH;AAAA,IACF;AAGA,UAAM,WAAW,2BAAa,KAAK;AAEnC,QAAI,YAAY;AACd,eAAS,QAAQ,IAAI,QAAQ,KAAK,mBAAmB,CAAC;AAAA,IACxD;AAEA,WAAO;AAAA,EACT;AACF;;;ACjEA,IAAAA,sBAA4B;AAqBrB,SAAS,kBAAkB,QAEhC;AACA,QAAM,WAAsB,iCAAY,MAAM;AAC9C,QAAM,SAAS,OAAO,eAAe;AAErC,SAAO;AAAA,IACL,MAAM,IAAI,SAAqC;AAC7C,YAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAC/B,YAAM,SACJ,IAAI,SAAS,SAAS,gBAAgB,KACtC,IAAI,aAAa,IAAI,MAAM,MAAM;AAEnC,UAAI;AACF,cAAM,UAAU,MAAM,KAAK,aAAa,MAAM;AAG9C,aAAK,WAAW,OAAO,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAEvC,eAAO,IAAI,SAAS,SAAS;AAAA,UAC3B,QAAQ;AAAA,UACR,SAAS;AAAA,YACP,gBAAgB;AAAA,YAChB,iBAAiB,mBAAmB,MAAM;AAAA,UAC5C;AAAA,QACF,CAAC;AAAA,MACH,QAAQ;AACN,eAAO,IAAI,SAAS,yBAAyB;AAAA,UAC3C,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,4BAA4B;AAAA,QACzD,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;;;AF5CA,IAAAC,sBAWO;","names":["import_geo_ai_core","import_geo_ai_core"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/middleware.ts","../src/handler.ts","../src/generate.ts"],"sourcesContent":["// geo-ai-next main entry point\n\n// Next.js middleware\nexport { geoAIMiddleware } from './middleware';\nexport type { GeoAIMiddlewareConfig } from './middleware';\n\n// Next.js route handler\nexport { createLlmsHandler } from './handler';\nexport type { LlmsHandlerConfig } from './handler';\n\n// Static file generation (build step)\nexport { generateLlmsFiles } from './generate';\nexport type { GenerateLlmsFilesConfig, GenerateLlmsFilesResult } from './generate';\n\n// Re-export all public types, interfaces, and classes from geo-ai-core\nexport {\n createGeoAI,\n MemoryCacheAdapter,\n FileCacheAdapter,\n CrawlTracker,\n MemoryCrawlStore,\n CryptoService,\n BotRulesEngine,\n AI_BOTS,\n SeoGenerator,\n LlmsGenerator,\n} from 'geo-ai-core';\n\nexport type {\n GeoAIInstance,\n Resource,\n ProductResource,\n ResourceSection,\n ContentProvider,\n CacheAdapter,\n CrawlEntry,\n CrawlActivity,\n CrawlStore,\n CrawlTrackingConfig,\n CryptoConfig,\n GeoAIConfig,\n AiProvider,\n AiGeneratorConfig,\n AiError,\n AiBulkConfig,\n AiContext,\n} from 'geo-ai-core';\n","import { NextResponse } from 'next/server';\nimport type { NextRequest } from 'next/server';\nimport { createGeoAI } from 'geo-ai-core';\nimport type { GeoAIConfig, GeoAIInstance } from 'geo-ai-core';\n\n// ── Config ──────────────────────────────────────────────────────────\n\nexport interface GeoAIMiddlewareConfig extends GeoAIConfig {\n /** Inject Link header pointing to llms.txt on non-llms responses. Default: false */\n injectLinkHeader?: boolean;\n /** Cache-Control max-age in seconds for llms.txt responses. Default: 3600 */\n cacheMaxAge?: number;\n}\n\n// ── Middleware factory ───────────────────────────────────────────────\n\n/**\n * Creates a Next.js middleware function that intercepts `/llms.txt` and\n * `/llms-full.txt` requests, returning generated content as `text/plain`.\n * All other paths are passed through via `NextResponse.next()`.\n */\nexport function geoAIMiddleware(\n config: GeoAIMiddlewareConfig,\n): (request: NextRequest) => Promise<NextResponse> {\n const core: GeoAIInstance = createGeoAI(config);\n const injectLink = config.injectLinkHeader ?? false;\n const maxAge = config.cacheMaxAge ?? 3600;\n\n return async (request: NextRequest): Promise<NextResponse> => {\n const { pathname } = request.nextUrl;\n\n // ── Match llms paths ───────────────────────────────────────────\n if (pathname === '/llms.txt' || pathname === '/llms-full.txt') {\n const isFull = pathname === '/llms-full.txt';\n\n try {\n const content = await core.generateLlms(isFull);\n\n // Fire-and-forget: track visit without blocking the response\n core.trackVisit(request as unknown as Request).catch(() => {});\n\n return new NextResponse(content, {\n status: 200,\n headers: {\n 'Content-Type': 'text/plain; charset=utf-8',\n 'Cache-Control': `public, max-age=${maxAge}`,\n },\n });\n } catch {\n return new NextResponse('Internal Server Error', {\n status: 500,\n headers: { 'Content-Type': 'text/plain; charset=utf-8' },\n });\n }\n }\n\n // ── Passthrough ────────────────────────────────────────────────\n const response = NextResponse.next();\n\n if (injectLink) {\n response.headers.set('Link', core.generateLinkHeader());\n }\n\n return response;\n };\n}\n","import { createGeoAI } from 'geo-ai-core';\nimport type { GeoAIConfig, GeoAIInstance } from 'geo-ai-core';\n\n// ── Config ──────────────────────────────────────────────────────────\n\nexport interface LlmsHandlerConfig extends GeoAIConfig {\n /** Cache-Control max-age in seconds for llms.txt responses. Default: 3600 */\n cacheMaxAge?: number;\n}\n\n// ── Route Handler factory ───────────────────────────────────────────\n\n/**\n * Creates a Next.js App Router route handler that serves llms.txt content.\n * File type is determined by URL path (`/llms-full.txt`) or query `?type=full`.\n *\n * Usage in `app/llms/route.ts`:\n * ```ts\n * export const { GET } = createLlmsHandler({ ... });\n * ```\n */\nexport function createLlmsHandler(config: LlmsHandlerConfig): {\n GET: (request: Request) => Promise<Response>;\n} {\n const core: GeoAIInstance = createGeoAI(config);\n const maxAge = config.cacheMaxAge ?? 3600;\n\n return {\n async GET(request: Request): Promise<Response> {\n const url = new URL(request.url);\n const isFull =\n url.pathname.endsWith('/llms-full.txt') ||\n url.searchParams.get('type') === 'full';\n\n try {\n const content = await core.generateLlms(isFull);\n\n // Fire-and-forget: log bot visit without blocking the response\n core.trackVisit(request).catch(() => {});\n\n return new Response(content, {\n status: 200,\n headers: {\n 'Content-Type': 'text/plain; charset=utf-8',\n 'Cache-Control': `public, max-age=${maxAge}`,\n },\n });\n } catch {\n return new Response('Internal Server Error', {\n status: 500,\n headers: { 'Content-Type': 'text/plain; charset=utf-8' },\n });\n }\n },\n };\n}\n","import { createGeoAI } from 'geo-ai-core';\nimport type { GeoAIConfig } from 'geo-ai-core';\nimport { writeFile, mkdir } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\n\n// ── Config ──────────────────────────────────────────────────────────\n\nexport interface GenerateLlmsFilesConfig extends GeoAIConfig {\n /** Output directory for generated files. Default: 'public' (relative to cwd) */\n outDir?: string;\n /** Locale for content generation */\n locale?: string;\n}\n\nexport interface GenerateLlmsFilesResult {\n llmsPath: string;\n llmsFullPath: string;\n}\n\n// ── Generator ───────────────────────────────────────────────────────\n\n/**\n * Generates `llms.txt` and `llms-full.txt` as static files in the output\n * directory (default: `public/`). Designed to be called from a build script\n * or `next.config.js` before `next build`.\n *\n * - Creates the output directory if it doesn't exist\n * - Overwrites existing files atomically (write to temp, then rename)\n * - Logs progress to stdout\n * - Throws on failure with a descriptive error\n *\n * @example\n * ```ts\n * // scripts/generate-llms.ts\n * import { generateLlmsFiles } from 'geo-ai-next';\n *\n * await generateLlmsFiles({\n * siteName: 'My Site',\n * siteUrl: 'https://example.com',\n * provider: { Pages: [{ title: 'Home', url: '/' }] },\n * });\n * ```\n */\nexport async function generateLlmsFiles(\n config: GenerateLlmsFilesConfig,\n): Promise<GenerateLlmsFilesResult> {\n const outDir = resolve(config.outDir ?? 'public');\n\n console.log(`[geo-ai] Generating llms files → ${outDir}`);\n\n const core = createGeoAI(config);\n\n // Ensure output directory exists\n await mkdir(outDir, { recursive: true });\n\n // Generate both variants\n const [llmsContent, llmsFullContent] = await Promise.all([\n core.generateLlms(false, config.locale),\n core.generateLlms(true, config.locale),\n ]);\n\n const llmsPath = join(outDir, 'llms.txt');\n const llmsFullPath = join(outDir, 'llms-full.txt');\n\n // Write files atomically: write temp then rename\n const tmpLlms = `${llmsPath}.tmp`;\n const tmpFull = `${llmsFullPath}.tmp`;\n\n try {\n await Promise.all([\n writeFile(tmpLlms, llmsContent, 'utf-8'),\n writeFile(tmpFull, llmsFullContent, 'utf-8'),\n ]);\n\n // Rename is atomic on most filesystems\n const { rename } = await import('node:fs/promises');\n await Promise.all([\n rename(tmpLlms, llmsPath),\n rename(tmpFull, llmsFullPath),\n ]);\n } catch (err) {\n // Clean up temp files on failure\n const { unlink } = await import('node:fs/promises');\n await unlink(tmpLlms).catch(() => {});\n await unlink(tmpFull).catch(() => {});\n throw err;\n }\n\n console.log(`[geo-ai] ✓ ${llmsPath} (${llmsContent.length} bytes)`);\n console.log(`[geo-ai] ✓ ${llmsFullPath} (${llmsFullContent.length} bytes)`);\n\n return { llmsPath, llmsFullPath };\n}\n"],"mappings":"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","names":["import_geo_ai_core","import_geo_ai_core","import_geo_ai_core"]}
package/dist/index.d.cts CHANGED
@@ -32,4 +32,38 @@ declare function createLlmsHandler(config: LlmsHandlerConfig): {
32
32
  GET: (request: Request) => Promise<Response>;
33
33
  };
34
34
 
35
- export { type GeoAIMiddlewareConfig, type LlmsHandlerConfig, createLlmsHandler, geoAIMiddleware };
35
+ interface GenerateLlmsFilesConfig extends GeoAIConfig {
36
+ /** Output directory for generated files. Default: 'public' (relative to cwd) */
37
+ outDir?: string;
38
+ /** Locale for content generation */
39
+ locale?: string;
40
+ }
41
+ interface GenerateLlmsFilesResult {
42
+ llmsPath: string;
43
+ llmsFullPath: string;
44
+ }
45
+ /**
46
+ * Generates `llms.txt` and `llms-full.txt` as static files in the output
47
+ * directory (default: `public/`). Designed to be called from a build script
48
+ * or `next.config.js` before `next build`.
49
+ *
50
+ * - Creates the output directory if it doesn't exist
51
+ * - Overwrites existing files atomically (write to temp, then rename)
52
+ * - Logs progress to stdout
53
+ * - Throws on failure with a descriptive error
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * // scripts/generate-llms.ts
58
+ * import { generateLlmsFiles } from 'geo-ai-next';
59
+ *
60
+ * await generateLlmsFiles({
61
+ * siteName: 'My Site',
62
+ * siteUrl: 'https://example.com',
63
+ * provider: { Pages: [{ title: 'Home', url: '/' }] },
64
+ * });
65
+ * ```
66
+ */
67
+ declare function generateLlmsFiles(config: GenerateLlmsFilesConfig): Promise<GenerateLlmsFilesResult>;
68
+
69
+ export { type GenerateLlmsFilesConfig, type GenerateLlmsFilesResult, type GeoAIMiddlewareConfig, type LlmsHandlerConfig, createLlmsHandler, generateLlmsFiles, geoAIMiddleware };
package/dist/index.d.ts CHANGED
@@ -32,4 +32,38 @@ declare function createLlmsHandler(config: LlmsHandlerConfig): {
32
32
  GET: (request: Request) => Promise<Response>;
33
33
  };
34
34
 
35
- export { type GeoAIMiddlewareConfig, type LlmsHandlerConfig, createLlmsHandler, geoAIMiddleware };
35
+ interface GenerateLlmsFilesConfig extends GeoAIConfig {
36
+ /** Output directory for generated files. Default: 'public' (relative to cwd) */
37
+ outDir?: string;
38
+ /** Locale for content generation */
39
+ locale?: string;
40
+ }
41
+ interface GenerateLlmsFilesResult {
42
+ llmsPath: string;
43
+ llmsFullPath: string;
44
+ }
45
+ /**
46
+ * Generates `llms.txt` and `llms-full.txt` as static files in the output
47
+ * directory (default: `public/`). Designed to be called from a build script
48
+ * or `next.config.js` before `next build`.
49
+ *
50
+ * - Creates the output directory if it doesn't exist
51
+ * - Overwrites existing files atomically (write to temp, then rename)
52
+ * - Logs progress to stdout
53
+ * - Throws on failure with a descriptive error
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * // scripts/generate-llms.ts
58
+ * import { generateLlmsFiles } from 'geo-ai-next';
59
+ *
60
+ * await generateLlmsFiles({
61
+ * siteName: 'My Site',
62
+ * siteUrl: 'https://example.com',
63
+ * provider: { Pages: [{ title: 'Home', url: '/' }] },
64
+ * });
65
+ * ```
66
+ */
67
+ declare function generateLlmsFiles(config: GenerateLlmsFilesConfig): Promise<GenerateLlmsFilesResult>;
68
+
69
+ export { type GenerateLlmsFilesConfig, type GenerateLlmsFilesResult, type GeoAIMiddlewareConfig, type LlmsHandlerConfig, createLlmsHandler, generateLlmsFiles, geoAIMiddleware };
package/dist/index.mjs CHANGED
@@ -65,9 +65,49 @@ function createLlmsHandler(config) {
65
65
  };
66
66
  }
67
67
 
68
+ // src/generate.ts
69
+ import { createGeoAI as createGeoAI3 } from "geo-ai-core";
70
+ import { writeFile, mkdir } from "fs/promises";
71
+ import { join, resolve } from "path";
72
+ async function generateLlmsFiles(config) {
73
+ const outDir = resolve(config.outDir ?? "public");
74
+ console.log(`[geo-ai] Generating llms files \u2192 ${outDir}`);
75
+ const core = createGeoAI3(config);
76
+ await mkdir(outDir, { recursive: true });
77
+ const [llmsContent, llmsFullContent] = await Promise.all([
78
+ core.generateLlms(false, config.locale),
79
+ core.generateLlms(true, config.locale)
80
+ ]);
81
+ const llmsPath = join(outDir, "llms.txt");
82
+ const llmsFullPath = join(outDir, "llms-full.txt");
83
+ const tmpLlms = `${llmsPath}.tmp`;
84
+ const tmpFull = `${llmsFullPath}.tmp`;
85
+ try {
86
+ await Promise.all([
87
+ writeFile(tmpLlms, llmsContent, "utf-8"),
88
+ writeFile(tmpFull, llmsFullContent, "utf-8")
89
+ ]);
90
+ const { rename } = await import("fs/promises");
91
+ await Promise.all([
92
+ rename(tmpLlms, llmsPath),
93
+ rename(tmpFull, llmsFullPath)
94
+ ]);
95
+ } catch (err) {
96
+ const { unlink } = await import("fs/promises");
97
+ await unlink(tmpLlms).catch(() => {
98
+ });
99
+ await unlink(tmpFull).catch(() => {
100
+ });
101
+ throw err;
102
+ }
103
+ console.log(`[geo-ai] \u2713 ${llmsPath} (${llmsContent.length} bytes)`);
104
+ console.log(`[geo-ai] \u2713 ${llmsFullPath} (${llmsFullContent.length} bytes)`);
105
+ return { llmsPath, llmsFullPath };
106
+ }
107
+
68
108
  // src/index.ts
69
109
  import {
70
- createGeoAI as createGeoAI3,
110
+ createGeoAI as createGeoAI4,
71
111
  MemoryCacheAdapter,
72
112
  FileCacheAdapter,
73
113
  CrawlTracker,
@@ -88,8 +128,9 @@ export {
88
128
  MemoryCacheAdapter,
89
129
  MemoryCrawlStore,
90
130
  SeoGenerator,
91
- createGeoAI3 as createGeoAI,
131
+ createGeoAI4 as createGeoAI,
92
132
  createLlmsHandler,
133
+ generateLlmsFiles,
93
134
  geoAIMiddleware
94
135
  };
95
136
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/middleware.ts","../src/handler.ts","../src/index.ts"],"sourcesContent":["import { NextResponse } from 'next/server';\nimport type { NextRequest } from 'next/server';\nimport { createGeoAI } from 'geo-ai-core';\nimport type { GeoAIConfig, GeoAIInstance } from 'geo-ai-core';\n\n// ── Config ──────────────────────────────────────────────────────────\n\nexport interface GeoAIMiddlewareConfig extends GeoAIConfig {\n /** Inject Link header pointing to llms.txt on non-llms responses. Default: false */\n injectLinkHeader?: boolean;\n /** Cache-Control max-age in seconds for llms.txt responses. Default: 3600 */\n cacheMaxAge?: number;\n}\n\n// ── Middleware factory ───────────────────────────────────────────────\n\n/**\n * Creates a Next.js middleware function that intercepts `/llms.txt` and\n * `/llms-full.txt` requests, returning generated content as `text/plain`.\n * All other paths are passed through via `NextResponse.next()`.\n */\nexport function geoAIMiddleware(\n config: GeoAIMiddlewareConfig,\n): (request: NextRequest) => Promise<NextResponse> {\n const core: GeoAIInstance = createGeoAI(config);\n const injectLink = config.injectLinkHeader ?? false;\n const maxAge = config.cacheMaxAge ?? 3600;\n\n return async (request: NextRequest): Promise<NextResponse> => {\n const { pathname } = request.nextUrl;\n\n // ── Match llms paths ───────────────────────────────────────────\n if (pathname === '/llms.txt' || pathname === '/llms-full.txt') {\n const isFull = pathname === '/llms-full.txt';\n\n try {\n const content = await core.generateLlms(isFull);\n\n // Fire-and-forget: track visit without blocking the response\n core.trackVisit(request as unknown as Request).catch(() => {});\n\n return new NextResponse(content, {\n status: 200,\n headers: {\n 'Content-Type': 'text/plain; charset=utf-8',\n 'Cache-Control': `public, max-age=${maxAge}`,\n },\n });\n } catch {\n return new NextResponse('Internal Server Error', {\n status: 500,\n headers: { 'Content-Type': 'text/plain; charset=utf-8' },\n });\n }\n }\n\n // ── Passthrough ────────────────────────────────────────────────\n const response = NextResponse.next();\n\n if (injectLink) {\n response.headers.set('Link', core.generateLinkHeader());\n }\n\n return response;\n };\n}\n","import { createGeoAI } from 'geo-ai-core';\nimport type { GeoAIConfig, GeoAIInstance } from 'geo-ai-core';\n\n// ── Config ──────────────────────────────────────────────────────────\n\nexport interface LlmsHandlerConfig extends GeoAIConfig {\n /** Cache-Control max-age in seconds for llms.txt responses. Default: 3600 */\n cacheMaxAge?: number;\n}\n\n// ── Route Handler factory ───────────────────────────────────────────\n\n/**\n * Creates a Next.js App Router route handler that serves llms.txt content.\n * File type is determined by URL path (`/llms-full.txt`) or query `?type=full`.\n *\n * Usage in `app/llms/route.ts`:\n * ```ts\n * export const { GET } = createLlmsHandler({ ... });\n * ```\n */\nexport function createLlmsHandler(config: LlmsHandlerConfig): {\n GET: (request: Request) => Promise<Response>;\n} {\n const core: GeoAIInstance = createGeoAI(config);\n const maxAge = config.cacheMaxAge ?? 3600;\n\n return {\n async GET(request: Request): Promise<Response> {\n const url = new URL(request.url);\n const isFull =\n url.pathname.endsWith('/llms-full.txt') ||\n url.searchParams.get('type') === 'full';\n\n try {\n const content = await core.generateLlms(isFull);\n\n // Fire-and-forget: log bot visit without blocking the response\n core.trackVisit(request).catch(() => {});\n\n return new Response(content, {\n status: 200,\n headers: {\n 'Content-Type': 'text/plain; charset=utf-8',\n 'Cache-Control': `public, max-age=${maxAge}`,\n },\n });\n } catch {\n return new Response('Internal Server Error', {\n status: 500,\n headers: { 'Content-Type': 'text/plain; charset=utf-8' },\n });\n }\n },\n };\n}\n","// geo-ai-next main entry point\n\n// Next.js middleware\nexport { geoAIMiddleware } from './middleware';\nexport type { GeoAIMiddlewareConfig } from './middleware';\n\n// Next.js route handler\nexport { createLlmsHandler } from './handler';\nexport type { LlmsHandlerConfig } from './handler';\n\n// Re-export all public types, interfaces, and classes from geo-ai-core\nexport {\n createGeoAI,\n MemoryCacheAdapter,\n FileCacheAdapter,\n CrawlTracker,\n MemoryCrawlStore,\n CryptoService,\n BotRulesEngine,\n AI_BOTS,\n SeoGenerator,\n LlmsGenerator,\n} from 'geo-ai-core';\n\nexport type {\n GeoAIInstance,\n Resource,\n ProductResource,\n ResourceSection,\n ContentProvider,\n CacheAdapter,\n CrawlEntry,\n CrawlActivity,\n CrawlStore,\n CrawlTrackingConfig,\n CryptoConfig,\n GeoAIConfig,\n AiProvider,\n AiGeneratorConfig,\n AiError,\n AiBulkConfig,\n AiContext,\n} from 'geo-ai-core';\n"],"mappings":";AAAA,SAAS,oBAAoB;AAE7B,SAAS,mBAAmB;AAmBrB,SAAS,gBACd,QACiD;AACjD,QAAM,OAAsB,YAAY,MAAM;AAC9C,QAAM,aAAa,OAAO,oBAAoB;AAC9C,QAAM,SAAS,OAAO,eAAe;AAErC,SAAO,OAAO,YAAgD;AAC5D,UAAM,EAAE,SAAS,IAAI,QAAQ;AAG7B,QAAI,aAAa,eAAe,aAAa,kBAAkB;AAC7D,YAAM,SAAS,aAAa;AAE5B,UAAI;AACF,cAAM,UAAU,MAAM,KAAK,aAAa,MAAM;AAG9C,aAAK,WAAW,OAA6B,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAE7D,eAAO,IAAI,aAAa,SAAS;AAAA,UAC/B,QAAQ;AAAA,UACR,SAAS;AAAA,YACP,gBAAgB;AAAA,YAChB,iBAAiB,mBAAmB,MAAM;AAAA,UAC5C;AAAA,QACF,CAAC;AAAA,MACH,QAAQ;AACN,eAAO,IAAI,aAAa,yBAAyB;AAAA,UAC/C,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,4BAA4B;AAAA,QACzD,CAAC;AAAA,MACH;AAAA,IACF;AAGA,UAAM,WAAW,aAAa,KAAK;AAEnC,QAAI,YAAY;AACd,eAAS,QAAQ,IAAI,QAAQ,KAAK,mBAAmB,CAAC;AAAA,IACxD;AAEA,WAAO;AAAA,EACT;AACF;;;ACjEA,SAAS,eAAAA,oBAAmB;AAqBrB,SAAS,kBAAkB,QAEhC;AACA,QAAM,OAAsBA,aAAY,MAAM;AAC9C,QAAM,SAAS,OAAO,eAAe;AAErC,SAAO;AAAA,IACL,MAAM,IAAI,SAAqC;AAC7C,YAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAC/B,YAAM,SACJ,IAAI,SAAS,SAAS,gBAAgB,KACtC,IAAI,aAAa,IAAI,MAAM,MAAM;AAEnC,UAAI;AACF,cAAM,UAAU,MAAM,KAAK,aAAa,MAAM;AAG9C,aAAK,WAAW,OAAO,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAEvC,eAAO,IAAI,SAAS,SAAS;AAAA,UAC3B,QAAQ;AAAA,UACR,SAAS;AAAA,YACP,gBAAgB;AAAA,YAChB,iBAAiB,mBAAmB,MAAM;AAAA,UAC5C;AAAA,QACF,CAAC;AAAA,MACH,QAAQ;AACN,eAAO,IAAI,SAAS,yBAAyB;AAAA,UAC3C,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,4BAA4B;AAAA,QACzD,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;;;AC5CA;AAAA,EACE,eAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;","names":["createGeoAI","createGeoAI"]}
1
+ {"version":3,"sources":["../src/middleware.ts","../src/handler.ts","../src/generate.ts","../src/index.ts"],"sourcesContent":["import { NextResponse } from 'next/server';\nimport type { NextRequest } from 'next/server';\nimport { createGeoAI } from 'geo-ai-core';\nimport type { GeoAIConfig, GeoAIInstance } from 'geo-ai-core';\n\n// ── Config ──────────────────────────────────────────────────────────\n\nexport interface GeoAIMiddlewareConfig extends GeoAIConfig {\n /** Inject Link header pointing to llms.txt on non-llms responses. Default: false */\n injectLinkHeader?: boolean;\n /** Cache-Control max-age in seconds for llms.txt responses. Default: 3600 */\n cacheMaxAge?: number;\n}\n\n// ── Middleware factory ───────────────────────────────────────────────\n\n/**\n * Creates a Next.js middleware function that intercepts `/llms.txt` and\n * `/llms-full.txt` requests, returning generated content as `text/plain`.\n * All other paths are passed through via `NextResponse.next()`.\n */\nexport function geoAIMiddleware(\n config: GeoAIMiddlewareConfig,\n): (request: NextRequest) => Promise<NextResponse> {\n const core: GeoAIInstance = createGeoAI(config);\n const injectLink = config.injectLinkHeader ?? false;\n const maxAge = config.cacheMaxAge ?? 3600;\n\n return async (request: NextRequest): Promise<NextResponse> => {\n const { pathname } = request.nextUrl;\n\n // ── Match llms paths ───────────────────────────────────────────\n if (pathname === '/llms.txt' || pathname === '/llms-full.txt') {\n const isFull = pathname === '/llms-full.txt';\n\n try {\n const content = await core.generateLlms(isFull);\n\n // Fire-and-forget: track visit without blocking the response\n core.trackVisit(request as unknown as Request).catch(() => {});\n\n return new NextResponse(content, {\n status: 200,\n headers: {\n 'Content-Type': 'text/plain; charset=utf-8',\n 'Cache-Control': `public, max-age=${maxAge}`,\n },\n });\n } catch {\n return new NextResponse('Internal Server Error', {\n status: 500,\n headers: { 'Content-Type': 'text/plain; charset=utf-8' },\n });\n }\n }\n\n // ── Passthrough ────────────────────────────────────────────────\n const response = NextResponse.next();\n\n if (injectLink) {\n response.headers.set('Link', core.generateLinkHeader());\n }\n\n return response;\n };\n}\n","import { createGeoAI } from 'geo-ai-core';\nimport type { GeoAIConfig, GeoAIInstance } from 'geo-ai-core';\n\n// ── Config ──────────────────────────────────────────────────────────\n\nexport interface LlmsHandlerConfig extends GeoAIConfig {\n /** Cache-Control max-age in seconds for llms.txt responses. Default: 3600 */\n cacheMaxAge?: number;\n}\n\n// ── Route Handler factory ───────────────────────────────────────────\n\n/**\n * Creates a Next.js App Router route handler that serves llms.txt content.\n * File type is determined by URL path (`/llms-full.txt`) or query `?type=full`.\n *\n * Usage in `app/llms/route.ts`:\n * ```ts\n * export const { GET } = createLlmsHandler({ ... });\n * ```\n */\nexport function createLlmsHandler(config: LlmsHandlerConfig): {\n GET: (request: Request) => Promise<Response>;\n} {\n const core: GeoAIInstance = createGeoAI(config);\n const maxAge = config.cacheMaxAge ?? 3600;\n\n return {\n async GET(request: Request): Promise<Response> {\n const url = new URL(request.url);\n const isFull =\n url.pathname.endsWith('/llms-full.txt') ||\n url.searchParams.get('type') === 'full';\n\n try {\n const content = await core.generateLlms(isFull);\n\n // Fire-and-forget: log bot visit without blocking the response\n core.trackVisit(request).catch(() => {});\n\n return new Response(content, {\n status: 200,\n headers: {\n 'Content-Type': 'text/plain; charset=utf-8',\n 'Cache-Control': `public, max-age=${maxAge}`,\n },\n });\n } catch {\n return new Response('Internal Server Error', {\n status: 500,\n headers: { 'Content-Type': 'text/plain; charset=utf-8' },\n });\n }\n },\n };\n}\n","import { createGeoAI } from 'geo-ai-core';\nimport type { GeoAIConfig } from 'geo-ai-core';\nimport { writeFile, mkdir } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\n\n// ── Config ──────────────────────────────────────────────────────────\n\nexport interface GenerateLlmsFilesConfig extends GeoAIConfig {\n /** Output directory for generated files. Default: 'public' (relative to cwd) */\n outDir?: string;\n /** Locale for content generation */\n locale?: string;\n}\n\nexport interface GenerateLlmsFilesResult {\n llmsPath: string;\n llmsFullPath: string;\n}\n\n// ── Generator ───────────────────────────────────────────────────────\n\n/**\n * Generates `llms.txt` and `llms-full.txt` as static files in the output\n * directory (default: `public/`). Designed to be called from a build script\n * or `next.config.js` before `next build`.\n *\n * - Creates the output directory if it doesn't exist\n * - Overwrites existing files atomically (write to temp, then rename)\n * - Logs progress to stdout\n * - Throws on failure with a descriptive error\n *\n * @example\n * ```ts\n * // scripts/generate-llms.ts\n * import { generateLlmsFiles } from 'geo-ai-next';\n *\n * await generateLlmsFiles({\n * siteName: 'My Site',\n * siteUrl: 'https://example.com',\n * provider: { Pages: [{ title: 'Home', url: '/' }] },\n * });\n * ```\n */\nexport async function generateLlmsFiles(\n config: GenerateLlmsFilesConfig,\n): Promise<GenerateLlmsFilesResult> {\n const outDir = resolve(config.outDir ?? 'public');\n\n console.log(`[geo-ai] Generating llms files → ${outDir}`);\n\n const core = createGeoAI(config);\n\n // Ensure output directory exists\n await mkdir(outDir, { recursive: true });\n\n // Generate both variants\n const [llmsContent, llmsFullContent] = await Promise.all([\n core.generateLlms(false, config.locale),\n core.generateLlms(true, config.locale),\n ]);\n\n const llmsPath = join(outDir, 'llms.txt');\n const llmsFullPath = join(outDir, 'llms-full.txt');\n\n // Write files atomically: write temp then rename\n const tmpLlms = `${llmsPath}.tmp`;\n const tmpFull = `${llmsFullPath}.tmp`;\n\n try {\n await Promise.all([\n writeFile(tmpLlms, llmsContent, 'utf-8'),\n writeFile(tmpFull, llmsFullContent, 'utf-8'),\n ]);\n\n // Rename is atomic on most filesystems\n const { rename } = await import('node:fs/promises');\n await Promise.all([\n rename(tmpLlms, llmsPath),\n rename(tmpFull, llmsFullPath),\n ]);\n } catch (err) {\n // Clean up temp files on failure\n const { unlink } = await import('node:fs/promises');\n await unlink(tmpLlms).catch(() => {});\n await unlink(tmpFull).catch(() => {});\n throw err;\n }\n\n console.log(`[geo-ai] ✓ ${llmsPath} (${llmsContent.length} bytes)`);\n console.log(`[geo-ai] ✓ ${llmsFullPath} (${llmsFullContent.length} bytes)`);\n\n return { llmsPath, llmsFullPath };\n}\n","// geo-ai-next main entry point\n\n// Next.js middleware\nexport { geoAIMiddleware } from './middleware';\nexport type { GeoAIMiddlewareConfig } from './middleware';\n\n// Next.js route handler\nexport { createLlmsHandler } from './handler';\nexport type { LlmsHandlerConfig } from './handler';\n\n// Static file generation (build step)\nexport { generateLlmsFiles } from './generate';\nexport type { GenerateLlmsFilesConfig, GenerateLlmsFilesResult } from './generate';\n\n// Re-export all public types, interfaces, and classes from geo-ai-core\nexport {\n createGeoAI,\n MemoryCacheAdapter,\n FileCacheAdapter,\n CrawlTracker,\n MemoryCrawlStore,\n CryptoService,\n BotRulesEngine,\n AI_BOTS,\n SeoGenerator,\n LlmsGenerator,\n} from 'geo-ai-core';\n\nexport type {\n GeoAIInstance,\n Resource,\n ProductResource,\n ResourceSection,\n ContentProvider,\n CacheAdapter,\n CrawlEntry,\n CrawlActivity,\n CrawlStore,\n CrawlTrackingConfig,\n CryptoConfig,\n GeoAIConfig,\n AiProvider,\n AiGeneratorConfig,\n AiError,\n AiBulkConfig,\n AiContext,\n} from 'geo-ai-core';\n"],"mappings":"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","names":["createGeoAI","createGeoAI","createGeoAI"]}
package/package.json CHANGED
@@ -1,7 +1,13 @@
1
1
  {
2
2
  "name": "geo-ai-next",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "license": "GPL-2.0",
5
+ "homepage": "https://www.geoai.run",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/madeburo/GEO-AI.git",
9
+ "directory": "packages/next"
10
+ },
5
11
  "type": "module",
6
12
  "exports": {
7
13
  ".": {
@@ -19,7 +25,8 @@
19
25
  "llms-txt",
20
26
  "llms.txt",
21
27
  "ai",
22
- "generative-engine-optimization",
28
+ "ai-search-optimization",
29
+ "geoai",
23
30
  "nextjs",
24
31
  "next",
25
32
  "middleware",
@@ -38,12 +45,15 @@
38
45
  "files": [
39
46
  "dist"
40
47
  ],
48
+ "bin": {
49
+ "geo-ai-generate": "dist/cli.mjs"
50
+ },
41
51
  "scripts": {
42
52
  "build": "tsup",
43
53
  "typecheck": "tsc --noEmit"
44
54
  },
45
55
  "dependencies": {
46
- "geo-ai-core": "*"
56
+ "geo-ai-core": "^0.2.0"
47
57
  },
48
58
  "engines": {
49
59
  "node": ">=20"