@farm.js/plugin 0.1.0-beta.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/LICENSE +22 -0
- package/README.md +11 -0
- package/dist/api/index.d.ts +42 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +567 -0
- package/dist/context/index.d.ts +61 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +75 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +49 -0
- package/dist/middleware/index.d.ts +97 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +469 -0
- package/dist/observability/index.d.ts +190 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +399 -0
- package/dist/rsc/build-paths.d.ts +3 -0
- package/dist/rsc/build-paths.d.ts.map +1 -0
- package/dist/rsc/build-paths.js +8 -0
- package/dist/rsc/entries/client.d.ts +14 -0
- package/dist/rsc/entries/client.d.ts.map +1 -0
- package/dist/rsc/entries/client.js +283 -0
- package/dist/rsc/entries/rsc.d.ts +13 -0
- package/dist/rsc/entries/rsc.d.ts.map +1 -0
- package/dist/rsc/entries/rsc.js +932 -0
- package/dist/rsc/entries/ssr.d.ts +13 -0
- package/dist/rsc/entries/ssr.d.ts.map +1 -0
- package/dist/rsc/entries/ssr.js +245 -0
- package/dist/rsc/index.d.ts +78 -0
- package/dist/rsc/index.d.ts.map +1 -0
- package/dist/rsc/index.js +1368 -0
- package/dist/rsc/nitro-build.d.ts +36 -0
- package/dist/rsc/nitro-build.d.ts.map +1 -0
- package/dist/rsc/nitro-build.js +396 -0
- package/dist/rsc/optimized-boundary.d.ts +20 -0
- package/dist/rsc/optimized-boundary.d.ts.map +1 -0
- package/dist/rsc/optimized-boundary.js +15 -0
- package/dist/rsc/server-fn-transform.d.ts +6 -0
- package/dist/rsc/server-fn-transform.d.ts.map +1 -0
- package/dist/rsc/server-fn-transform.js +152 -0
- package/dist/rsc/types.d.ts +123 -0
- package/dist/rsc/types.d.ts.map +1 -0
- package/dist/rsc/types.js +1 -0
- package/dist/rsc/vite-plugin-nitro.d.ts +33 -0
- package/dist/rsc/vite-plugin-nitro.d.ts.map +1 -0
- package/dist/rsc/vite-plugin-nitro.js +163 -0
- package/package.json +94 -0
- package/scripts/build.js +7 -0
- package/scripts/clean.js +6 -0
- package/scripts/run-nitro.mjs +18 -0
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Farm.js Middleware Plugin
|
|
3
|
+
*
|
|
4
|
+
* Standalone middleware support that works with or without RSC.
|
|
5
|
+
* Discovers and executes middleware.ts files in the source directory.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { farmMiddleware } from '@farm.js/plugin/middleware'
|
|
10
|
+
*
|
|
11
|
+
* export default defineConfig({
|
|
12
|
+
* plugins: [farmMiddleware({ srcDir: 'src' })],
|
|
13
|
+
* })
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
import { createRequire } from "node:module";
|
|
17
|
+
import { _withAfterNodeMiddleware } from "@farm.js/core/after";
|
|
18
|
+
// Create require for ESM compatibility
|
|
19
|
+
const require_ = createRequire(import.meta.url);
|
|
20
|
+
// Get picocolors with forced color support (to handle NO_COLOR env being set)
|
|
21
|
+
const getColors = () => {
|
|
22
|
+
try {
|
|
23
|
+
const pico = require_("picocolors");
|
|
24
|
+
if (typeof pico?.createColors === "function") {
|
|
25
|
+
return pico.createColors(true);
|
|
26
|
+
}
|
|
27
|
+
if (typeof pico?.green === "function")
|
|
28
|
+
return pico;
|
|
29
|
+
}
|
|
30
|
+
catch { }
|
|
31
|
+
const id = (s) => s;
|
|
32
|
+
return {
|
|
33
|
+
bold: id,
|
|
34
|
+
dim: id,
|
|
35
|
+
cyan: id,
|
|
36
|
+
red: id,
|
|
37
|
+
yellow: id,
|
|
38
|
+
blue: id,
|
|
39
|
+
white: id,
|
|
40
|
+
gray: id,
|
|
41
|
+
green: id,
|
|
42
|
+
magenta: id,
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Parse cookies from Cookie header
|
|
47
|
+
*/
|
|
48
|
+
function parseCookies(cookieHeader) {
|
|
49
|
+
if (!cookieHeader)
|
|
50
|
+
return {};
|
|
51
|
+
return cookieHeader.split(";").reduce((cookies, cookie) => {
|
|
52
|
+
const [name, ...rest] = cookie.split("=");
|
|
53
|
+
const value = rest.join("=").trim();
|
|
54
|
+
if (name && value) {
|
|
55
|
+
cookies[name.trim()] = decodeURIComponent(value);
|
|
56
|
+
}
|
|
57
|
+
return cookies;
|
|
58
|
+
}, {});
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Serialize a cookie
|
|
62
|
+
*/
|
|
63
|
+
function serializeCookie(name, value, options = {}) {
|
|
64
|
+
let cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
|
|
65
|
+
if (options.maxAge) {
|
|
66
|
+
cookie += `; Max-Age=${options.maxAge}`;
|
|
67
|
+
}
|
|
68
|
+
if (options.expires) {
|
|
69
|
+
cookie += `; Expires=${options.expires.toUTCString()}`;
|
|
70
|
+
}
|
|
71
|
+
if (options.path) {
|
|
72
|
+
cookie += `; Path=${options.path}`;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
cookie += "; Path=/";
|
|
76
|
+
}
|
|
77
|
+
if (options.domain) {
|
|
78
|
+
cookie += `; Domain=${options.domain}`;
|
|
79
|
+
}
|
|
80
|
+
if (options.secure) {
|
|
81
|
+
cookie += "; Secure";
|
|
82
|
+
}
|
|
83
|
+
if (options.httpOnly) {
|
|
84
|
+
cookie += "; HttpOnly";
|
|
85
|
+
}
|
|
86
|
+
if (options.sameSite) {
|
|
87
|
+
cookie += `; SameSite=${options.sameSite.charAt(0).toUpperCase() + options.sameSite.slice(1)}`;
|
|
88
|
+
}
|
|
89
|
+
return cookie;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Create a cookie jar for managing cookies
|
|
93
|
+
*/
|
|
94
|
+
function createCookieJar(req, res) {
|
|
95
|
+
const cookies = parseCookies(req.headers.cookie);
|
|
96
|
+
const setCookies = [];
|
|
97
|
+
return {
|
|
98
|
+
get(name) {
|
|
99
|
+
return cookies[name];
|
|
100
|
+
},
|
|
101
|
+
set(name, value, options = {}) {
|
|
102
|
+
cookies[name] = value;
|
|
103
|
+
const cookieString = serializeCookie(name, value, options);
|
|
104
|
+
setCookies.push(cookieString);
|
|
105
|
+
res.setHeader("Set-Cookie", setCookies);
|
|
106
|
+
},
|
|
107
|
+
delete(name) {
|
|
108
|
+
delete cookies[name];
|
|
109
|
+
const cookieString = serializeCookie(name, "", {
|
|
110
|
+
maxAge: 0,
|
|
111
|
+
expires: new Date(0),
|
|
112
|
+
});
|
|
113
|
+
setCookies.push(cookieString);
|
|
114
|
+
res.setHeader("Set-Cookie", setCookies);
|
|
115
|
+
},
|
|
116
|
+
getAll() {
|
|
117
|
+
return { ...cookies };
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Create a full middleware context
|
|
123
|
+
*/
|
|
124
|
+
function createContext(req, res, viteServer) {
|
|
125
|
+
const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
|
|
126
|
+
const headers = new Map();
|
|
127
|
+
const data = new Map();
|
|
128
|
+
const cookies = createCookieJar(req, res);
|
|
129
|
+
let handled = false;
|
|
130
|
+
const ctx = {
|
|
131
|
+
request: req,
|
|
132
|
+
response: res,
|
|
133
|
+
url,
|
|
134
|
+
pathname: url.pathname,
|
|
135
|
+
searchParams: url.searchParams,
|
|
136
|
+
method: req.method || "GET",
|
|
137
|
+
params: {},
|
|
138
|
+
route: url.pathname,
|
|
139
|
+
vite: {
|
|
140
|
+
isDev: process.env.NODE_ENV !== "production",
|
|
141
|
+
hmr: !!viteServer?.hot,
|
|
142
|
+
server: viteServer,
|
|
143
|
+
},
|
|
144
|
+
data,
|
|
145
|
+
headers,
|
|
146
|
+
cookies,
|
|
147
|
+
_handled: false,
|
|
148
|
+
redirect(redirectUrl, status = 307) {
|
|
149
|
+
if (handled) {
|
|
150
|
+
console.warn("Response already sent, cannot redirect");
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
ctx._redirectUrl = redirectUrl;
|
|
154
|
+
ctx._handled = true;
|
|
155
|
+
handled = true;
|
|
156
|
+
res.writeHead(status, {
|
|
157
|
+
Location: redirectUrl,
|
|
158
|
+
"Content-Type": "text/plain",
|
|
159
|
+
});
|
|
160
|
+
res.end(`Redirecting to ${redirectUrl}`);
|
|
161
|
+
},
|
|
162
|
+
rewrite(rewriteUrl) {
|
|
163
|
+
ctx._rewriteUrl = rewriteUrl;
|
|
164
|
+
// Update the URL for downstream middleware
|
|
165
|
+
const newUrl = new URL(rewriteUrl, `http://${req.headers.host || "localhost"}`);
|
|
166
|
+
ctx.url = newUrl;
|
|
167
|
+
ctx.pathname = newUrl.pathname;
|
|
168
|
+
ctx.searchParams = newUrl.searchParams;
|
|
169
|
+
// Update the original request URL
|
|
170
|
+
req.url = rewriteUrl;
|
|
171
|
+
},
|
|
172
|
+
json(jsonData, status = 200) {
|
|
173
|
+
if (handled) {
|
|
174
|
+
console.warn("Response already sent, cannot send JSON");
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
ctx._handled = true;
|
|
178
|
+
handled = true;
|
|
179
|
+
res.writeHead(status, {
|
|
180
|
+
"Content-Type": "application/json",
|
|
181
|
+
});
|
|
182
|
+
res.end(JSON.stringify(jsonData));
|
|
183
|
+
},
|
|
184
|
+
text(content, status = 200) {
|
|
185
|
+
if (handled) {
|
|
186
|
+
console.warn("Response already sent, cannot send text");
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
ctx._handled = true;
|
|
190
|
+
handled = true;
|
|
191
|
+
res.writeHead(status, {
|
|
192
|
+
"Content-Type": "text/plain",
|
|
193
|
+
});
|
|
194
|
+
res.end(content);
|
|
195
|
+
},
|
|
196
|
+
html(content, status = 200) {
|
|
197
|
+
if (handled) {
|
|
198
|
+
console.warn("Response already sent, cannot send HTML");
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
ctx._handled = true;
|
|
202
|
+
handled = true;
|
|
203
|
+
res.writeHead(status, {
|
|
204
|
+
"Content-Type": "text/html",
|
|
205
|
+
});
|
|
206
|
+
res.end(content);
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
return ctx;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Farm.js Middleware Plugin
|
|
213
|
+
*/
|
|
214
|
+
export default function farmMiddleware(options = {}) {
|
|
215
|
+
const srcDir = options.srcDir ?? "src";
|
|
216
|
+
const debug = options.debug ?? false;
|
|
217
|
+
// Middleware cache
|
|
218
|
+
let middlewareCache = new Map();
|
|
219
|
+
let discoveryComplete = false;
|
|
220
|
+
let discoveryPromise = null;
|
|
221
|
+
const log = (message) => {
|
|
222
|
+
if (!debug)
|
|
223
|
+
return;
|
|
224
|
+
try {
|
|
225
|
+
const pc = require("picocolors");
|
|
226
|
+
console.log(pc.dim("[") + pc.bold(pc.blue("FARM")) + pc.dim("]") + " " + pc.gray(message));
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
console.log(`[FARM] ${message}`);
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
return {
|
|
233
|
+
name: "@farm.js/plugin/middleware",
|
|
234
|
+
enforce: "pre",
|
|
235
|
+
configureServer(server) {
|
|
236
|
+
// Discover middleware
|
|
237
|
+
const discoverMiddleware = async (dir, routePath = "/") => {
|
|
238
|
+
const fs = await import("fs");
|
|
239
|
+
const path = await import("path");
|
|
240
|
+
if (!fs.existsSync(dir))
|
|
241
|
+
return;
|
|
242
|
+
// Check for middleware file
|
|
243
|
+
const extensions = [".ts", ".tsx", ".js", ".jsx"];
|
|
244
|
+
for (const ext of extensions) {
|
|
245
|
+
const middlewareFile = path.join(dir, `middleware${ext}`);
|
|
246
|
+
if (fs.existsSync(middlewareFile)) {
|
|
247
|
+
try {
|
|
248
|
+
const module = await server.ssrLoadModule(middlewareFile);
|
|
249
|
+
if (module.default) {
|
|
250
|
+
middlewareCache.set(routePath, {
|
|
251
|
+
path: routePath,
|
|
252
|
+
filePath: middlewareFile,
|
|
253
|
+
module: module.default,
|
|
254
|
+
config: module.config,
|
|
255
|
+
});
|
|
256
|
+
log(`Middleware discovered: ${routePath}`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
catch (e) {
|
|
260
|
+
log(`Middleware load failed at ${routePath}: ${e.message}`);
|
|
261
|
+
}
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
// Recursively check subdirectories
|
|
266
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
267
|
+
for (const entry of entries) {
|
|
268
|
+
if (entry.isDirectory() &&
|
|
269
|
+
!entry.name.startsWith(".") &&
|
|
270
|
+
!entry.name.startsWith("_") &&
|
|
271
|
+
entry.name !== "api") {
|
|
272
|
+
const subDir = path.join(dir, entry.name);
|
|
273
|
+
const subRoutePath = routePath === "/" ? `/${entry.name}` : `${routePath}/${entry.name}`;
|
|
274
|
+
await discoverMiddleware(subDir, subRoutePath);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
// Initialize discovery
|
|
279
|
+
const initializeDiscovery = async () => {
|
|
280
|
+
const path = await import("path");
|
|
281
|
+
const appDir = path.join(server.config.root, srcDir);
|
|
282
|
+
await discoverMiddleware(appDir);
|
|
283
|
+
discoveryComplete = true;
|
|
284
|
+
};
|
|
285
|
+
discoveryPromise = initializeDiscovery().catch((e) => {
|
|
286
|
+
console.error("[FARM] Middleware discovery error:", e);
|
|
287
|
+
});
|
|
288
|
+
// Execute middleware chain
|
|
289
|
+
const executeMiddleware = async (req, res, pathname, sharedData) => {
|
|
290
|
+
// Wait for discovery
|
|
291
|
+
if (discoveryPromise && !discoveryComplete) {
|
|
292
|
+
await discoveryPromise;
|
|
293
|
+
}
|
|
294
|
+
// Find applicable middleware (cascading from root to specific)
|
|
295
|
+
const applicable = Array.from(middlewareCache.values())
|
|
296
|
+
.filter((mw) => {
|
|
297
|
+
if (mw.path === "/")
|
|
298
|
+
return true;
|
|
299
|
+
return pathname.startsWith(mw.path) || pathname === mw.path;
|
|
300
|
+
})
|
|
301
|
+
.sort((a, b) => a.path.split("/").length - b.path.split("/").length);
|
|
302
|
+
if (applicable.length === 0)
|
|
303
|
+
return false;
|
|
304
|
+
const startTime = Date.now();
|
|
305
|
+
const method = req.method || "GET";
|
|
306
|
+
// Log middleware execution in the same format as @farm.js/core
|
|
307
|
+
const pc = getColors();
|
|
308
|
+
const logMsg = [
|
|
309
|
+
pc.dim("[") + pc.bold(pc.blue("FARM")) + pc.dim("]"),
|
|
310
|
+
pc.dim("[") + pc.bold(pc.magenta("MIDDLEWARE")) + pc.dim("]"),
|
|
311
|
+
pc.dim("[") + pc.bold(pc.white(method.padEnd(3))) + pc.dim("]"),
|
|
312
|
+
pc.gray("Executing middleware: "),
|
|
313
|
+
pc.gray(pathname),
|
|
314
|
+
pc.dim(` (${applicable.length} middleware)`),
|
|
315
|
+
].join(" ");
|
|
316
|
+
console.log(logMsg);
|
|
317
|
+
// Create full middleware context
|
|
318
|
+
const ctx = createContext(req, res, server);
|
|
319
|
+
// Use shared data if provided
|
|
320
|
+
if (sharedData) {
|
|
321
|
+
for (const [key, value] of sharedData) {
|
|
322
|
+
ctx.data.set(key, value);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
for (const mw of applicable) {
|
|
326
|
+
const middleware = mw.module;
|
|
327
|
+
// Handle middleware chain object (has .build method)
|
|
328
|
+
if (middleware && typeof middleware === "object" && "build" in middleware) {
|
|
329
|
+
if (typeof middleware.setBasePath === "function") {
|
|
330
|
+
middleware.setBasePath(mw.path);
|
|
331
|
+
}
|
|
332
|
+
const built = middleware.build();
|
|
333
|
+
const handlers = built.handlers || [];
|
|
334
|
+
let handlerIndex = 0;
|
|
335
|
+
const executeNext = async () => {
|
|
336
|
+
if (handlerIndex < handlers.length) {
|
|
337
|
+
const handler = handlers[handlerIndex++];
|
|
338
|
+
await handler(ctx, executeNext);
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
await executeNext();
|
|
342
|
+
}
|
|
343
|
+
else if (typeof middleware === "function") {
|
|
344
|
+
// Plain middleware function
|
|
345
|
+
await middleware(ctx, async () => { });
|
|
346
|
+
}
|
|
347
|
+
// Check if response was sent
|
|
348
|
+
if (ctx._handled || res.headersSent || res.writableEnded) {
|
|
349
|
+
return true;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
// Apply collected headers to response
|
|
353
|
+
for (const [key, value] of ctx.headers) {
|
|
354
|
+
try {
|
|
355
|
+
res.setHeader(key, value);
|
|
356
|
+
}
|
|
357
|
+
catch (e) { }
|
|
358
|
+
}
|
|
359
|
+
// Store middleware data on request for pages to access
|
|
360
|
+
req.__FARM_MIDDLEWARE_DATA__ = Object.fromEntries(ctx.data);
|
|
361
|
+
// Log middleware completion
|
|
362
|
+
const duration = Date.now() - startTime;
|
|
363
|
+
const pc2 = getColors();
|
|
364
|
+
const completeLogMsg = [
|
|
365
|
+
pc2.dim("[") + pc2.bold(pc2.blue("FARM")) + pc2.dim("]"),
|
|
366
|
+
pc2.dim("[") + pc2.bold(pc2.magenta("MIDDLEWARE")) + pc2.dim("]"),
|
|
367
|
+
pc2.dim("[") + pc2.bold(pc2.white(method.padEnd(3))) + pc2.dim("]"),
|
|
368
|
+
pc2.gray("Completed"),
|
|
369
|
+
pc2.gray(pathname),
|
|
370
|
+
pc2.dim(`(${duration}ms)`),
|
|
371
|
+
].join(" ");
|
|
372
|
+
console.log(completeLogMsg);
|
|
373
|
+
return false;
|
|
374
|
+
};
|
|
375
|
+
// Expose middleware execution for other plugins
|
|
376
|
+
server.__farmMiddleware__ = {
|
|
377
|
+
execute: executeMiddleware,
|
|
378
|
+
getCache: () => middlewareCache,
|
|
379
|
+
isReady: () => discoveryComplete,
|
|
380
|
+
waitForDiscovery: () => discoveryPromise,
|
|
381
|
+
};
|
|
382
|
+
// Add middleware to handle requests
|
|
383
|
+
return () => {
|
|
384
|
+
server.middlewares.use(_withAfterNodeMiddleware(async (req, res, next) => {
|
|
385
|
+
const url = req.url || "/";
|
|
386
|
+
const pathname = url.split("?")[0];
|
|
387
|
+
// Skip Vite internal requests
|
|
388
|
+
if (pathname.startsWith("/@") ||
|
|
389
|
+
pathname.startsWith("/__") ||
|
|
390
|
+
pathname.startsWith("/node_modules") ||
|
|
391
|
+
(pathname.includes(".") && !pathname.endsWith("/"))) {
|
|
392
|
+
return next();
|
|
393
|
+
}
|
|
394
|
+
try {
|
|
395
|
+
// Execute middleware
|
|
396
|
+
const middlewareData = new Map();
|
|
397
|
+
const handled = await executeMiddleware(req, res, pathname, middlewareData);
|
|
398
|
+
if (handled) {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
catch (e) {
|
|
403
|
+
console.error("[FARM] Middleware error:", e);
|
|
404
|
+
}
|
|
405
|
+
next();
|
|
406
|
+
}));
|
|
407
|
+
};
|
|
408
|
+
},
|
|
409
|
+
async handleHotUpdate({ file, server, modules }) {
|
|
410
|
+
const fileName = file.split("/").pop() || "";
|
|
411
|
+
if (fileName.startsWith("middleware.")) {
|
|
412
|
+
log(`Middleware updated: ${fileName}`);
|
|
413
|
+
// Invalidate the module in Vite's module graph
|
|
414
|
+
for (const mod of modules) {
|
|
415
|
+
server.moduleGraph.invalidateModule(mod);
|
|
416
|
+
}
|
|
417
|
+
// Find and update the cached middleware
|
|
418
|
+
for (const [routePath, mw] of middlewareCache.entries()) {
|
|
419
|
+
if (mw.filePath === file) {
|
|
420
|
+
try {
|
|
421
|
+
// Reload the module
|
|
422
|
+
const module = await server.ssrLoadModule(file);
|
|
423
|
+
if (module.default) {
|
|
424
|
+
middlewareCache.set(routePath, {
|
|
425
|
+
path: routePath,
|
|
426
|
+
filePath: file,
|
|
427
|
+
module: module.default,
|
|
428
|
+
config: module.config,
|
|
429
|
+
});
|
|
430
|
+
log(`Middleware reloaded: ${routePath}`);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
catch (e) {
|
|
434
|
+
log(`Middleware reload failed: ${e.message}`);
|
|
435
|
+
}
|
|
436
|
+
break;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
// Also check if this is a new middleware file not yet in cache
|
|
440
|
+
if (!Array.from(middlewareCache.values()).some((mw) => mw.filePath === file)) {
|
|
441
|
+
try {
|
|
442
|
+
const path = await import("path");
|
|
443
|
+
const srcPath = path.join(server.config.root, srcDir);
|
|
444
|
+
const relativePath = file
|
|
445
|
+
.replace(srcPath, "")
|
|
446
|
+
.replace(/\/middleware\.(ts|tsx|js|jsx)$/, "");
|
|
447
|
+
const routePath = relativePath === "" ? "/" : relativePath;
|
|
448
|
+
const module = await server.ssrLoadModule(file);
|
|
449
|
+
if (module.default) {
|
|
450
|
+
middlewareCache.set(routePath, {
|
|
451
|
+
path: routePath,
|
|
452
|
+
filePath: file,
|
|
453
|
+
module: module.default,
|
|
454
|
+
config: module.config,
|
|
455
|
+
});
|
|
456
|
+
log(`New middleware discovered: ${routePath}`);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
catch (e) {
|
|
460
|
+
log(`New middleware load failed: ${e.message}`);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
server.ws.send({ type: "full-reload", path: "*" });
|
|
464
|
+
return [];
|
|
465
|
+
}
|
|
466
|
+
},
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
export { farmMiddleware };
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from "http";
|
|
2
|
+
export type IncidentSeverity = "low" | "medium" | "high" | "critical";
|
|
3
|
+
export type ObservabilitySignalKind = "request.completed" | "api.response" | "render.completed" | "runtime.error" | "build.result" | "nitro.build";
|
|
4
|
+
export interface ObservabilitySignal {
|
|
5
|
+
id: string;
|
|
6
|
+
kind: ObservabilitySignalKind;
|
|
7
|
+
timestamp: number;
|
|
8
|
+
service: string;
|
|
9
|
+
environment: string;
|
|
10
|
+
tags: Record<string, string>;
|
|
11
|
+
request?: {
|
|
12
|
+
method: string;
|
|
13
|
+
pathname: string;
|
|
14
|
+
statusCode: number;
|
|
15
|
+
durationMs: number;
|
|
16
|
+
requestId: string;
|
|
17
|
+
};
|
|
18
|
+
api?: {
|
|
19
|
+
method: string;
|
|
20
|
+
pathname: string;
|
|
21
|
+
status: number;
|
|
22
|
+
};
|
|
23
|
+
render?: {
|
|
24
|
+
pathname: string;
|
|
25
|
+
routePattern: string | null;
|
|
26
|
+
};
|
|
27
|
+
error?: {
|
|
28
|
+
phase: string;
|
|
29
|
+
message: string;
|
|
30
|
+
name?: string;
|
|
31
|
+
};
|
|
32
|
+
build?: {
|
|
33
|
+
success: boolean;
|
|
34
|
+
preset: string;
|
|
35
|
+
root: string;
|
|
36
|
+
outputDir?: string;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export interface ObservabilityIncident {
|
|
40
|
+
id: string;
|
|
41
|
+
kind: string;
|
|
42
|
+
title: string;
|
|
43
|
+
severity: IncidentSeverity;
|
|
44
|
+
fingerprint: string;
|
|
45
|
+
detectedAt: number;
|
|
46
|
+
signalId: string;
|
|
47
|
+
summary?: string;
|
|
48
|
+
metadata?: Record<string, unknown>;
|
|
49
|
+
}
|
|
50
|
+
export interface ObservabilityDetectionContext {
|
|
51
|
+
now: () => number;
|
|
52
|
+
}
|
|
53
|
+
export interface ObservabilityRule {
|
|
54
|
+
id: string;
|
|
55
|
+
severity?: IncidentSeverity;
|
|
56
|
+
when: (signal: ObservabilitySignal, context: ObservabilityDetectionContext) => boolean | Promise<boolean>;
|
|
57
|
+
buildIncident?: (signal: ObservabilitySignal, context: ObservabilityDetectionContext) => Partial<Omit<ObservabilityIncident, "id" | "detectedAt" | "signalId">> | null | undefined | Promise<Partial<Omit<ObservabilityIncident, "id" | "detectedAt" | "signalId">> | null | undefined>;
|
|
58
|
+
}
|
|
59
|
+
export interface ObservabilityFixResult {
|
|
60
|
+
summary: string;
|
|
61
|
+
branch?: string;
|
|
62
|
+
commitSha?: string;
|
|
63
|
+
metadata?: Record<string, unknown>;
|
|
64
|
+
}
|
|
65
|
+
export interface ObservabilityPipelineContext {
|
|
66
|
+
signal: ObservabilitySignal;
|
|
67
|
+
incident: ObservabilityIncident;
|
|
68
|
+
/**
|
|
69
|
+
* @deprecated Use state["fix"] or step result values in `state`.
|
|
70
|
+
*/
|
|
71
|
+
fixResult?: ObservabilityFixResult | null;
|
|
72
|
+
state: Record<string, unknown>;
|
|
73
|
+
}
|
|
74
|
+
export type ObservabilityAction = (context: ObservabilityPipelineContext) => unknown | Promise<unknown>;
|
|
75
|
+
export type ObservabilityPipelineStepName = string;
|
|
76
|
+
export interface ObservabilityWorkflowStepEvent {
|
|
77
|
+
step: string;
|
|
78
|
+
context: ObservabilityPipelineContext;
|
|
79
|
+
}
|
|
80
|
+
export interface ObservabilityWorkflowStepCompleteEvent extends ObservabilityWorkflowStepEvent {
|
|
81
|
+
result: unknown;
|
|
82
|
+
}
|
|
83
|
+
export interface ObservabilityWorkflowStepErrorEvent extends ObservabilityWorkflowStepEvent {
|
|
84
|
+
error: unknown;
|
|
85
|
+
}
|
|
86
|
+
export interface ObservabilityWorkflowErrorEvent {
|
|
87
|
+
error: unknown;
|
|
88
|
+
context: ObservabilityPipelineContext;
|
|
89
|
+
}
|
|
90
|
+
export interface ObservabilityWorkflowCallbacks {
|
|
91
|
+
onIncident?: (context: ObservabilityPipelineContext) => void | Promise<void>;
|
|
92
|
+
onPipelineStart?: (context: ObservabilityPipelineContext) => void | Promise<void>;
|
|
93
|
+
onPipelineComplete?: (context: ObservabilityPipelineContext) => void | Promise<void>;
|
|
94
|
+
onPipelineError?: (event: ObservabilityWorkflowErrorEvent) => void | Promise<void>;
|
|
95
|
+
onStepStart?: (event: ObservabilityWorkflowStepEvent) => void | Promise<void>;
|
|
96
|
+
onStepComplete?: (event: ObservabilityWorkflowStepCompleteEvent) => void | Promise<void>;
|
|
97
|
+
onStepError?: (event: ObservabilityWorkflowStepErrorEvent) => void | Promise<void>;
|
|
98
|
+
}
|
|
99
|
+
export interface ObservabilityWorkflowOptions {
|
|
100
|
+
pipeline?: ObservabilityPipelineStepName[];
|
|
101
|
+
actions?: Record<string, ObservabilityAction>;
|
|
102
|
+
/**
|
|
103
|
+
* Callback lifecycle for side effects around pipeline execution.
|
|
104
|
+
*/
|
|
105
|
+
callbacks?: ObservabilityWorkflowCallbacks;
|
|
106
|
+
/**
|
|
107
|
+
* Continue pipeline execution when a step fails.
|
|
108
|
+
* Defaults to true to avoid affecting request handling.
|
|
109
|
+
*/
|
|
110
|
+
continueOnStepError?: boolean;
|
|
111
|
+
/**
|
|
112
|
+
* @deprecated Use `callbacks.onIncident`.
|
|
113
|
+
*/
|
|
114
|
+
onIncident?: (context: ObservabilityPipelineContext) => void | Promise<void>;
|
|
115
|
+
/**
|
|
116
|
+
* @deprecated Use `actions.fix` and include "fix" in `pipeline`.
|
|
117
|
+
*/
|
|
118
|
+
runFix?: (context: ObservabilityPipelineContext) => ObservabilityFixResult | null | undefined | Promise<ObservabilityFixResult | null | undefined>;
|
|
119
|
+
/**
|
|
120
|
+
* @deprecated Use `actions.pullRequest` and include "pullRequest" in `pipeline`.
|
|
121
|
+
*/
|
|
122
|
+
openPullRequest?: (context: ObservabilityPipelineContext) => void | Promise<void>;
|
|
123
|
+
}
|
|
124
|
+
export interface ObservabilityDetectionOptions {
|
|
125
|
+
enabled?: boolean;
|
|
126
|
+
dedupeWindowMs?: number;
|
|
127
|
+
rules?: ObservabilityRule[];
|
|
128
|
+
mapSignalToIncident?: (signal: ObservabilitySignal, context: ObservabilityDetectionContext) => ObservabilityIncident | null | undefined | Promise<ObservabilityIncident | null | undefined>;
|
|
129
|
+
}
|
|
130
|
+
export interface ObservabilityTelemetryOptions {
|
|
131
|
+
slowRequestMs?: number;
|
|
132
|
+
logLifecycle?: boolean;
|
|
133
|
+
annotateHtml?: boolean;
|
|
134
|
+
}
|
|
135
|
+
export interface ObservabilityPluginOptions {
|
|
136
|
+
service?: string;
|
|
137
|
+
environment?: string;
|
|
138
|
+
tags?: Record<string, string>;
|
|
139
|
+
telemetry?: ObservabilityTelemetryOptions;
|
|
140
|
+
detection?: ObservabilityDetectionOptions;
|
|
141
|
+
workflow?: ObservabilityWorkflowOptions;
|
|
142
|
+
/**
|
|
143
|
+
* @deprecated Use telemetry.slowRequestMs instead.
|
|
144
|
+
*/
|
|
145
|
+
slowRequestMs?: number;
|
|
146
|
+
/**
|
|
147
|
+
* @deprecated Use telemetry.logLifecycle instead.
|
|
148
|
+
*/
|
|
149
|
+
logLifecycle?: boolean;
|
|
150
|
+
}
|
|
151
|
+
interface ObservabilityPlugin {
|
|
152
|
+
name: string;
|
|
153
|
+
enforce?: "pre" | "post";
|
|
154
|
+
init?: () => void;
|
|
155
|
+
ready?: () => void;
|
|
156
|
+
beforeRequest?: (req: IncomingMessage, res: ServerResponse, context?: unknown) => void;
|
|
157
|
+
afterResponse?: (req: IncomingMessage, res: ServerResponse, context?: unknown) => void | Promise<void>;
|
|
158
|
+
afterApiHandler?: (response: Response, api: {
|
|
159
|
+
method: string;
|
|
160
|
+
pathname: string;
|
|
161
|
+
}, context?: unknown) => Response | Promise<Response>;
|
|
162
|
+
afterRender?: (html: string, render: {
|
|
163
|
+
pathname: string;
|
|
164
|
+
routePattern: string | null;
|
|
165
|
+
}, context?: unknown) => string;
|
|
166
|
+
onError?: (error: {
|
|
167
|
+
phase: string;
|
|
168
|
+
error: unknown;
|
|
169
|
+
}, context?: unknown) => void | Promise<void>;
|
|
170
|
+
hmrUpdate?: (update: {
|
|
171
|
+
file: string;
|
|
172
|
+
modules: string[];
|
|
173
|
+
}, context?: unknown) => void;
|
|
174
|
+
afterBundle?: (result: {
|
|
175
|
+
success: boolean;
|
|
176
|
+
preset: string;
|
|
177
|
+
root: string;
|
|
178
|
+
}, context?: unknown) => void | Promise<void>;
|
|
179
|
+
afterNitroBuild?: (payload: {
|
|
180
|
+
preset: string;
|
|
181
|
+
outputDir: string;
|
|
182
|
+
root?: string;
|
|
183
|
+
}, context?: unknown) => void | Promise<void>;
|
|
184
|
+
shutdown?: (payload: {
|
|
185
|
+
reason: string;
|
|
186
|
+
}, context?: unknown) => void;
|
|
187
|
+
}
|
|
188
|
+
export declare function observabilityPlugin(options?: ObservabilityPluginOptions): ObservabilityPlugin;
|
|
189
|
+
export {};
|
|
190
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/observability/index.ts"],"names":[],"mappings":"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"}
|