@kaleabdenbel/llmweb 1.0.4 → 1.0.6
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 +10 -3
- package/dist/adapters/express.d.mts +8 -0
- package/dist/adapters/express.d.ts +8 -0
- package/dist/adapters/express.js +200 -0
- package/dist/adapters/express.mjs +163 -0
- package/dist/adapters/next.d.mts +10 -0
- package/dist/adapters/next.d.ts +10 -0
- package/dist/adapters/next.js +299 -0
- package/dist/adapters/next.mjs +261 -0
- package/dist/adapters/react.d.mts +18 -0
- package/dist/adapters/react.d.ts +18 -0
- package/dist/adapters/react.js +336 -0
- package/dist/adapters/react.mjs +300 -0
- package/dist/adapters/vanilla.d.mts +8 -0
- package/dist/adapters/vanilla.d.ts +8 -0
- package/dist/adapters/vanilla.js +201 -0
- package/dist/adapters/vanilla.mjs +164 -0
- package/dist/cli.js +447 -102
- package/dist/index-C5RUlsf2.d.mts +56 -0
- package/dist/index-C5RUlsf2.d.ts +56 -0
- package/dist/index.browser.d.mts +10 -0
- package/dist/index.browser.d.ts +10 -0
- package/dist/index.browser.js +185 -0
- package/dist/index.browser.mjs +154 -0
- package/dist/index.d.mts +11 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +208 -0
- package/dist/index.mjs +167 -0
- package/dist/injector-DD7MSHW4.d.mts +26 -0
- package/dist/injector-Gh9wJgRZ.d.ts +26 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -11,13 +11,19 @@ The data compiler that transforms messy application state into LLM-readable trut
|
|
|
11
11
|
- **The Engine**: Compiles these into a single, structured JSON object for LLMs.
|
|
12
12
|
- **Framework Adapters**: Utilities for [Next.js](docs/next.md), [React](docs/react.md), [Express](docs/express.md), and [Vanilla JS](docs/vanilla.md).
|
|
13
13
|
|
|
14
|
-
##
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
The fastest way to get started is using the CLI:
|
|
15
17
|
|
|
16
18
|
```bash
|
|
17
|
-
|
|
19
|
+
npx llmweb init
|
|
18
20
|
```
|
|
19
21
|
|
|
20
|
-
|
|
22
|
+
For a deep dive into the **Bridge Pattern**, **Server Actions**, and **Advanced Mapping**, check out our [Definitive Guide](docs/guide.md).
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Integration (Next.js)
|
|
21
27
|
|
|
22
28
|
### 1. Define your Truth
|
|
23
29
|
|
|
@@ -80,6 +86,7 @@ export default function LlmTruthPage() {
|
|
|
80
86
|
- **Error Boundaries**: Configurable `failLoudly` mode for strict data integrity.
|
|
81
87
|
- **Timeouts**: Prevent slow APIs from hanging your truth route.
|
|
82
88
|
- **Deterministic Merging**: Static structure defines the slots; dynamic data fills them.
|
|
89
|
+
- **AI-Friendly JSON-LD**: Automatically generate Schema.org metadata for LLM context discovery.
|
|
83
90
|
|
|
84
91
|
## Advanced Mapping
|
|
85
92
|
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
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
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/adapters/express.ts
|
|
31
|
+
var express_exports = {};
|
|
32
|
+
__export(express_exports, {
|
|
33
|
+
llmMiddleware: () => llmMiddleware
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(express_exports);
|
|
36
|
+
|
|
37
|
+
// src/core/resolver.ts
|
|
38
|
+
async function resolveAll(dynamicSources, options = {}) {
|
|
39
|
+
const keys = Object.keys(dynamicSources);
|
|
40
|
+
const results = await Promise.allSettled(
|
|
41
|
+
keys.map((key) => resolveSource(dynamicSources[key], options.timeout))
|
|
42
|
+
);
|
|
43
|
+
const data = {};
|
|
44
|
+
results.forEach((result, index) => {
|
|
45
|
+
const key = keys[index];
|
|
46
|
+
if (result.status === "fulfilled") {
|
|
47
|
+
data[key] = result.value;
|
|
48
|
+
} else {
|
|
49
|
+
console.error(`[llmweb] Failed to resolve source "${key}":`, result.reason);
|
|
50
|
+
data[key] = null;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
return data;
|
|
54
|
+
}
|
|
55
|
+
async function resolveSource(source, timeoutMs) {
|
|
56
|
+
const { from } = source;
|
|
57
|
+
const controller = timeoutMs ? new AbortController() : null;
|
|
58
|
+
const signal = controller?.signal;
|
|
59
|
+
const timeoutPromise = timeoutMs ? new Promise(
|
|
60
|
+
(_, reject) => setTimeout(() => {
|
|
61
|
+
controller?.abort();
|
|
62
|
+
reject(new Error(`Timeout of ${timeoutMs}ms exceeded`));
|
|
63
|
+
}, timeoutMs)
|
|
64
|
+
) : null;
|
|
65
|
+
const resolvePromise = (async () => {
|
|
66
|
+
if (from.type === "fetch") {
|
|
67
|
+
if (!from.url) throw new Error("Fetch source requires a URL");
|
|
68
|
+
const response = await fetch(from.url, { signal });
|
|
69
|
+
if (!response.ok) throw new Error(`HTTP error ${response.status} for ${from.url}`);
|
|
70
|
+
return response.json();
|
|
71
|
+
}
|
|
72
|
+
if (from.type === "fn") {
|
|
73
|
+
if (!from.call) throw new Error('Function source requires a "call" property');
|
|
74
|
+
return from.call();
|
|
75
|
+
}
|
|
76
|
+
throw new Error(`Unsupported source type: ${from.type}`);
|
|
77
|
+
})();
|
|
78
|
+
if (timeoutPromise) {
|
|
79
|
+
return Promise.race([resolvePromise, timeoutPromise]);
|
|
80
|
+
}
|
|
81
|
+
return resolvePromise;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// src/core/transformer.ts
|
|
85
|
+
function transform(sourceData, schema) {
|
|
86
|
+
if (!sourceData) return sourceData;
|
|
87
|
+
if (Array.isArray(sourceData)) {
|
|
88
|
+
return sourceData.map((item) => transform(item, schema));
|
|
89
|
+
}
|
|
90
|
+
if (typeof sourceData !== "object") return sourceData;
|
|
91
|
+
const result = {};
|
|
92
|
+
for (const [targetKey, mapping] of Object.entries(schema)) {
|
|
93
|
+
if (typeof mapping === "string") {
|
|
94
|
+
result[targetKey] = getValueByPath(sourceData, mapping);
|
|
95
|
+
} else if (typeof mapping === "function") {
|
|
96
|
+
result[targetKey] = mapping(sourceData);
|
|
97
|
+
} else if (typeof mapping === "object" && mapping !== null) {
|
|
98
|
+
result[targetKey] = transform(sourceData, mapping);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
function getValueByPath(obj, path) {
|
|
104
|
+
return path.split(".").reduce((acc, part) => acc && acc[part], obj);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// src/core/merger.ts
|
|
108
|
+
function merge(staticData, dynamicResults) {
|
|
109
|
+
if (!staticData) return dynamicResults;
|
|
110
|
+
return {
|
|
111
|
+
...staticData,
|
|
112
|
+
...dynamicResults
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// src/core/compiler.ts
|
|
117
|
+
async function compileLLM(config, loader, options = {}) {
|
|
118
|
+
const { static: staticRef, dynamic, ...topLevelMetadata } = config;
|
|
119
|
+
let staticTruth = { ...topLevelMetadata };
|
|
120
|
+
if (staticRef) {
|
|
121
|
+
try {
|
|
122
|
+
if (typeof staticRef === "object") {
|
|
123
|
+
staticTruth = { ...staticTruth, ...staticRef };
|
|
124
|
+
} else {
|
|
125
|
+
const content = await loader(staticRef);
|
|
126
|
+
if (content) {
|
|
127
|
+
staticTruth = { ...staticTruth, ...JSON.parse(content) };
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
} catch (error) {
|
|
131
|
+
if (options.failLoudly) {
|
|
132
|
+
throw new Error(`[llmweb] Static Truth Error: Failed to load/parse JSON at ${staticRef}. ${error}`);
|
|
133
|
+
}
|
|
134
|
+
console.warn(`[llmweb] Warning: Could not load static JSON at ${staticRef}. Proceeding with dynamic data only.`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const dynamicTruth = {};
|
|
138
|
+
if (config.dynamic) {
|
|
139
|
+
const rawResults = await resolveAll(config.dynamic, { timeout: options.timeout });
|
|
140
|
+
for (const [key, source] of Object.entries(config.dynamic)) {
|
|
141
|
+
const rawData = rawResults[key];
|
|
142
|
+
if (rawData === null && options.failLoudly) {
|
|
143
|
+
throw new Error(`[llmweb] Dynamic Truth Error: Source "${key}" failed to resolve.`);
|
|
144
|
+
}
|
|
145
|
+
if (rawData && source.map) {
|
|
146
|
+
try {
|
|
147
|
+
dynamicTruth[key] = transform(rawData, source.map);
|
|
148
|
+
} catch (error) {
|
|
149
|
+
if (options.failLoudly) {
|
|
150
|
+
throw new Error(`[llmweb] Transformation Error: Failed to map source "${key}". ${error}`);
|
|
151
|
+
}
|
|
152
|
+
console.error(`[llmweb] Warning: Mapping failed for "${key}". Using raw data.`);
|
|
153
|
+
dynamicTruth[key] = rawData;
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
dynamicTruth[key] = rawData;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return merge(staticTruth, dynamicTruth);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// src/index.ts
|
|
164
|
+
async function createLLMSource(config, options = {}) {
|
|
165
|
+
const nodeLoader = async (path) => {
|
|
166
|
+
try {
|
|
167
|
+
const fs = await import(
|
|
168
|
+
/* webpackIgnore: true */
|
|
169
|
+
"fs"
|
|
170
|
+
);
|
|
171
|
+
const nodePath = await import(
|
|
172
|
+
/* webpackIgnore: true */
|
|
173
|
+
"path"
|
|
174
|
+
);
|
|
175
|
+
const fullPath = path.startsWith("/") ? path : nodePath.join(process.cwd(), path);
|
|
176
|
+
return fs.readFileSync(fullPath, "utf-8");
|
|
177
|
+
} catch (error) {
|
|
178
|
+
console.warn(`[llmweb] Warning: 'node:fs' not available. Skipping static file load: ${path}`);
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
return compileLLM(config, nodeLoader, options);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// src/adapters/express.ts
|
|
186
|
+
function llmMiddleware(config) {
|
|
187
|
+
return async (req, res, next) => {
|
|
188
|
+
try {
|
|
189
|
+
const truth = await createLLMSource(config);
|
|
190
|
+
res.status(200).json(truth);
|
|
191
|
+
} catch (error) {
|
|
192
|
+
console.error("[llmweb] Express middleware error:", error);
|
|
193
|
+
res.status(500).json({ error: "Internal Server Error" });
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
198
|
+
0 && (module.exports = {
|
|
199
|
+
llmMiddleware
|
|
200
|
+
});
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// src/core/resolver.ts
|
|
2
|
+
async function resolveAll(dynamicSources, options = {}) {
|
|
3
|
+
const keys = Object.keys(dynamicSources);
|
|
4
|
+
const results = await Promise.allSettled(
|
|
5
|
+
keys.map((key) => resolveSource(dynamicSources[key], options.timeout))
|
|
6
|
+
);
|
|
7
|
+
const data = {};
|
|
8
|
+
results.forEach((result, index) => {
|
|
9
|
+
const key = keys[index];
|
|
10
|
+
if (result.status === "fulfilled") {
|
|
11
|
+
data[key] = result.value;
|
|
12
|
+
} else {
|
|
13
|
+
console.error(`[llmweb] Failed to resolve source "${key}":`, result.reason);
|
|
14
|
+
data[key] = null;
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
return data;
|
|
18
|
+
}
|
|
19
|
+
async function resolveSource(source, timeoutMs) {
|
|
20
|
+
const { from } = source;
|
|
21
|
+
const controller = timeoutMs ? new AbortController() : null;
|
|
22
|
+
const signal = controller?.signal;
|
|
23
|
+
const timeoutPromise = timeoutMs ? new Promise(
|
|
24
|
+
(_, reject) => setTimeout(() => {
|
|
25
|
+
controller?.abort();
|
|
26
|
+
reject(new Error(`Timeout of ${timeoutMs}ms exceeded`));
|
|
27
|
+
}, timeoutMs)
|
|
28
|
+
) : null;
|
|
29
|
+
const resolvePromise = (async () => {
|
|
30
|
+
if (from.type === "fetch") {
|
|
31
|
+
if (!from.url) throw new Error("Fetch source requires a URL");
|
|
32
|
+
const response = await fetch(from.url, { signal });
|
|
33
|
+
if (!response.ok) throw new Error(`HTTP error ${response.status} for ${from.url}`);
|
|
34
|
+
return response.json();
|
|
35
|
+
}
|
|
36
|
+
if (from.type === "fn") {
|
|
37
|
+
if (!from.call) throw new Error('Function source requires a "call" property');
|
|
38
|
+
return from.call();
|
|
39
|
+
}
|
|
40
|
+
throw new Error(`Unsupported source type: ${from.type}`);
|
|
41
|
+
})();
|
|
42
|
+
if (timeoutPromise) {
|
|
43
|
+
return Promise.race([resolvePromise, timeoutPromise]);
|
|
44
|
+
}
|
|
45
|
+
return resolvePromise;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/core/transformer.ts
|
|
49
|
+
function transform(sourceData, schema) {
|
|
50
|
+
if (!sourceData) return sourceData;
|
|
51
|
+
if (Array.isArray(sourceData)) {
|
|
52
|
+
return sourceData.map((item) => transform(item, schema));
|
|
53
|
+
}
|
|
54
|
+
if (typeof sourceData !== "object") return sourceData;
|
|
55
|
+
const result = {};
|
|
56
|
+
for (const [targetKey, mapping] of Object.entries(schema)) {
|
|
57
|
+
if (typeof mapping === "string") {
|
|
58
|
+
result[targetKey] = getValueByPath(sourceData, mapping);
|
|
59
|
+
} else if (typeof mapping === "function") {
|
|
60
|
+
result[targetKey] = mapping(sourceData);
|
|
61
|
+
} else if (typeof mapping === "object" && mapping !== null) {
|
|
62
|
+
result[targetKey] = transform(sourceData, mapping);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
function getValueByPath(obj, path) {
|
|
68
|
+
return path.split(".").reduce((acc, part) => acc && acc[part], obj);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// src/core/merger.ts
|
|
72
|
+
function merge(staticData, dynamicResults) {
|
|
73
|
+
if (!staticData) return dynamicResults;
|
|
74
|
+
return {
|
|
75
|
+
...staticData,
|
|
76
|
+
...dynamicResults
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// src/core/compiler.ts
|
|
81
|
+
async function compileLLM(config, loader, options = {}) {
|
|
82
|
+
const { static: staticRef, dynamic, ...topLevelMetadata } = config;
|
|
83
|
+
let staticTruth = { ...topLevelMetadata };
|
|
84
|
+
if (staticRef) {
|
|
85
|
+
try {
|
|
86
|
+
if (typeof staticRef === "object") {
|
|
87
|
+
staticTruth = { ...staticTruth, ...staticRef };
|
|
88
|
+
} else {
|
|
89
|
+
const content = await loader(staticRef);
|
|
90
|
+
if (content) {
|
|
91
|
+
staticTruth = { ...staticTruth, ...JSON.parse(content) };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
} catch (error) {
|
|
95
|
+
if (options.failLoudly) {
|
|
96
|
+
throw new Error(`[llmweb] Static Truth Error: Failed to load/parse JSON at ${staticRef}. ${error}`);
|
|
97
|
+
}
|
|
98
|
+
console.warn(`[llmweb] Warning: Could not load static JSON at ${staticRef}. Proceeding with dynamic data only.`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const dynamicTruth = {};
|
|
102
|
+
if (config.dynamic) {
|
|
103
|
+
const rawResults = await resolveAll(config.dynamic, { timeout: options.timeout });
|
|
104
|
+
for (const [key, source] of Object.entries(config.dynamic)) {
|
|
105
|
+
const rawData = rawResults[key];
|
|
106
|
+
if (rawData === null && options.failLoudly) {
|
|
107
|
+
throw new Error(`[llmweb] Dynamic Truth Error: Source "${key}" failed to resolve.`);
|
|
108
|
+
}
|
|
109
|
+
if (rawData && source.map) {
|
|
110
|
+
try {
|
|
111
|
+
dynamicTruth[key] = transform(rawData, source.map);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
if (options.failLoudly) {
|
|
114
|
+
throw new Error(`[llmweb] Transformation Error: Failed to map source "${key}". ${error}`);
|
|
115
|
+
}
|
|
116
|
+
console.error(`[llmweb] Warning: Mapping failed for "${key}". Using raw data.`);
|
|
117
|
+
dynamicTruth[key] = rawData;
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
dynamicTruth[key] = rawData;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return merge(staticTruth, dynamicTruth);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// src/index.ts
|
|
128
|
+
async function createLLMSource(config, options = {}) {
|
|
129
|
+
const nodeLoader = async (path) => {
|
|
130
|
+
try {
|
|
131
|
+
const fs = await import(
|
|
132
|
+
/* webpackIgnore: true */
|
|
133
|
+
"fs"
|
|
134
|
+
);
|
|
135
|
+
const nodePath = await import(
|
|
136
|
+
/* webpackIgnore: true */
|
|
137
|
+
"path"
|
|
138
|
+
);
|
|
139
|
+
const fullPath = path.startsWith("/") ? path : nodePath.join(process.cwd(), path);
|
|
140
|
+
return fs.readFileSync(fullPath, "utf-8");
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.warn(`[llmweb] Warning: 'node:fs' not available. Skipping static file load: ${path}`);
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
return compileLLM(config, nodeLoader, options);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// src/adapters/express.ts
|
|
150
|
+
function llmMiddleware(config) {
|
|
151
|
+
return async (req, res, next) => {
|
|
152
|
+
try {
|
|
153
|
+
const truth = await createLLMSource(config);
|
|
154
|
+
res.status(200).json(truth);
|
|
155
|
+
} catch (error) {
|
|
156
|
+
console.error("[llmweb] Express middleware error:", error);
|
|
157
|
+
res.status(500).json({ error: "Internal Server Error" });
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
export {
|
|
162
|
+
llmMiddleware
|
|
163
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { L as LLMConfig } from '../index-C5RUlsf2.mjs';
|
|
2
|
+
export { LLMJson } from './react.mjs';
|
|
3
|
+
import 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A helper for Next.js App Router Route Handlers (route.ts).
|
|
7
|
+
*/
|
|
8
|
+
declare function createLLMHandler(config: LLMConfig): () => Promise<Response>;
|
|
9
|
+
|
|
10
|
+
export { createLLMHandler };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { L as LLMConfig } from '../index-C5RUlsf2.js';
|
|
2
|
+
export { LLMJson } from './react.js';
|
|
3
|
+
import 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A helper for Next.js App Router Route Handlers (route.ts).
|
|
7
|
+
*/
|
|
8
|
+
declare function createLLMHandler(config: LLMConfig): () => Promise<Response>;
|
|
9
|
+
|
|
10
|
+
export { createLLMHandler };
|