@junejs/server 1.0.0-dev.28 → 1.0.0-dev.36
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/dist/agent-compile.d.ts +8 -9
- package/dist/agent-discover.d.ts +3 -4
- package/dist/agent-durable.d.ts +20 -19
- package/dist/agent-durable.js +41 -6
- package/dist/agent-native.d.ts +10 -11
- package/dist/agent-native.js +6 -2
- package/dist/app.d.ts +4 -5
- package/dist/app.js +2 -1
- package/dist/blob.d.ts +4 -5
- package/dist/build.d.ts +6 -6
- package/dist/build.js +34 -7
- package/dist/client-bundle.d.ts +8 -9
- package/dist/{config-freeze-DwI-Rmvq.d.ts → config-freeze-ZWC_Qd4h.d.ts} +1 -1
- package/dist/config-freeze.d.ts +1 -1
- package/dist/config-loader.d.ts +3 -4
- package/dist/connection-auth.d.ts +8 -9
- package/dist/content.d.ts +9 -10
- package/dist/core-version.d.ts +3 -4
- package/dist/css-modules-ambient.d.ts +2 -1
- package/dist/css-modules.d.ts +10 -11
- package/dist/css.d.ts +9 -10
- package/dist/d1-migrate.d.ts +6 -7
- package/dist/d1-migrate.js +3 -2
- package/dist/db.d.ts +2 -2
- package/dist/deploy.d.ts +3 -4
- package/dist/deploy.js +3 -2
- package/dist/dev-reload.d.ts +3 -4
- package/dist/dev.d.ts +4 -5
- package/dist/favicon.d.ts +16 -17
- package/dist/host.d.ts +5 -5
- package/dist/icon-letter.d.ts +2 -3
- package/dist/index.d.ts +4 -4
- package/dist/instrumentation.d.ts +2 -3
- package/dist/instrumentation.js +2 -1
- package/dist/island-registry.d.ts +6 -7
- package/dist/isolate-local.d.ts +4 -5
- package/dist/kv.d.ts +3 -4
- package/dist/llms-links.d.ts +9 -0
- package/dist/llms-links.js +65 -0
- package/dist/{manifest-gcNWqWoI.d.ts → manifest-DSNX4I-G.d.ts} +2 -2
- package/dist/manifest.d.ts +1 -1
- package/dist/negotiate.d.ts +4 -3
- package/dist/negotiate.js +24 -14
- package/dist/{pipeline-cCR6MGNK.d.ts → pipeline-BHUjBO0G.d.ts} +5 -1
- package/dist/pipeline.d.ts +2 -2
- package/dist/pipeline.js +263 -39
- package/dist/resources.d.ts +5 -6
- package/dist/router.d.ts +12 -13
- package/dist/rsc-build.d.ts +6 -7
- package/dist/rsc-bundle.d.ts +6 -7
- package/dist/rsc-manifest.d.ts +5 -6
- package/dist/rsc-runtime/flight-render-routes.d.ts +3 -4
- package/dist/rsc-runtime/flight-render.d.ts +2 -3
- package/dist/rsc-runtime/flight-to-html.d.ts +2 -3
- package/dist/rsc-runtime/flight-to-html.js +3 -2
- package/dist/rsc-runtime/rsdw-shims.d.ts +2 -1
- package/dist/segment.d.ts +4 -5
- package/dist/sqlite-driver.d.ts +10 -11
- package/dist/static-files.d.ts +4 -5
- package/dist/tsconfig-jsx.d.ts +4 -5
- package/dist/turn-events.d.ts +2 -3
- package/dist/web-manifest.d.ts +3 -4
- package/dist/web-manifest.js +2 -6
- package/dist/{worker-BkFHGtxp.d.ts → worker-Dv4l6Ybs.d.ts} +4 -2
- package/dist/worker.d.ts +1 -1
- package/dist/worker.js +35 -18
- package/package.json +5 -5
- package/src/agent-durable.ts +39 -10
- package/src/agent-native.ts +5 -1
- package/src/build.ts +63 -5
- package/src/llms-links.ts +96 -0
- package/src/negotiate.ts +39 -15
- package/src/pipeline.ts +437 -47
- package/src/web-manifest.ts +2 -6
- package/src/worker.ts +55 -17
package/dist/pipeline.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { iconLetter } from "./icon-letter.js";
|
|
2
|
+
import { collectLlmsLinks, collectSitemapPages } from "./llms-links.js";
|
|
2
3
|
import { webManifest } from "./web-manifest.js";
|
|
3
4
|
import { SEGMENT_HEADER, TITLE_HEADER, encodeTitle, negotiate } from "./negotiate.js";
|
|
4
5
|
import { ensureScope, runInScope, setRequestLocale } from "@junejs/db";
|
|
5
6
|
import { LoaderDataContext } from "@junejs/core/route";
|
|
7
|
+
import { siteShortName } from "@junejs/core/config";
|
|
6
8
|
import React, { Suspense, use } from "react";
|
|
7
9
|
import { renderToReadableStream } from "react-dom/server";
|
|
8
|
-
import { Document } from "@junejs/core/document";
|
|
9
|
-
import { apiCatalog, buildLinkHeader, llmsTxt, mcpServerCard, robotsTxt, sitemapXml } from "@junejs/core/discovery";
|
|
10
|
-
import { mcpHandler, mcpTools } from "@junejs/core/mcp";
|
|
10
|
+
import { Document, PRERENDER_ORIGIN, documentTitle, pageCanonical } from "@junejs/core/document";
|
|
11
|
+
import { AGENT_SKILLS_INDEX_PATH, AI_CATALOG_PATH, API_CATALOG_CONTENT_TYPE, ARD_PATH, MCP_SERVER_CARD_TYPE, agentSkillsIndex, aiCatalog, apiCatalog, buildLinkHeader, llmsTxt, mcpServerCard, robotsTxt, siteSkill, sitemapXml } from "@junejs/core/discovery";
|
|
12
|
+
import { mcpHandler, mcpServerIdentity, mcpTools } from "@junejs/core/mcp";
|
|
13
|
+
import { OPENAPI_MEDIA_TYPE, apiActionId, apiHandler, apiNamespaceResponse, isApiNamespace, openApiDocument } from "@junejs/core/api";
|
|
11
14
|
import { LOCALE_COOKIE, localeAlternates, localeDir, matchPinnedLocale, negotiateLocale } from "@junejs/core/i18n";
|
|
12
15
|
//#region src/pipeline.ts
|
|
13
16
|
function readCookie(request, name) {
|
|
@@ -20,6 +23,7 @@ function readCookie(request, name) {
|
|
|
20
23
|
}
|
|
21
24
|
}
|
|
22
25
|
const DefaultNotFound = ({ pathname }) => React.createElement("main", null, React.createElement("h1", null, "404 — Not found"), React.createElement("p", null, pathname));
|
|
26
|
+
const CORS = { "access-control-allow-origin": "*" };
|
|
23
27
|
function text(body, contentType, init) {
|
|
24
28
|
const headers = new Headers(init?.headers);
|
|
25
29
|
headers.set("content-type", contentType);
|
|
@@ -38,13 +42,49 @@ function StreamedView({ loadPromise, def, ctx }) {
|
|
|
38
42
|
function letterFavicon(siteName) {
|
|
39
43
|
return text(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" rx="12" fill="#1d1d1f"/><text x="32" y="32" dy=".36em" text-anchor="middle" font-family="ui-sans-serif, system-ui, sans-serif" font-size="34" font-weight="600" fill="#fbfbf8">${(iconLetter(siteName) || "•").replace(/[<>&"']/g, "") || "•"}</text></svg>\n`, "image/svg+xml", { headers: { "cache-control": "public, max-age=86400" } });
|
|
40
44
|
}
|
|
45
|
+
function markdownPath(pathname, isHome) {
|
|
46
|
+
const path = pathname.replace(/\/+$/, "");
|
|
47
|
+
return isHome ? `${path.replace(/\/index$/, "")}/index.md` : `${path}.md`;
|
|
48
|
+
}
|
|
49
|
+
function htmlPath(pathname, isHome) {
|
|
50
|
+
const path = pathname.endsWith(".md") ? pathname.slice(0, -3) : pathname;
|
|
51
|
+
if (!isHome) return path;
|
|
52
|
+
return path.replace(/\/+$/, "").replace(/\/index$/, "") || "/";
|
|
53
|
+
}
|
|
54
|
+
const SERVER_CARD_PATH = "/.well-known/mcp/server-card.json";
|
|
55
|
+
const SERVER_CARD_CORS = {
|
|
56
|
+
"access-control-allow-origin": "*",
|
|
57
|
+
"access-control-allow-methods": "GET, HEAD",
|
|
58
|
+
"access-control-allow-headers": "Content-Type, If-None-Match",
|
|
59
|
+
"access-control-expose-headers": "ETag"
|
|
60
|
+
};
|
|
61
|
+
function humanizeSegment(segment) {
|
|
62
|
+
let s = segment;
|
|
63
|
+
try {
|
|
64
|
+
s = decodeURIComponent(segment);
|
|
65
|
+
} catch {}
|
|
66
|
+
s = s.replace(/[-_]+/g, " ").trim();
|
|
67
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
68
|
+
}
|
|
41
69
|
const routePathOf = /* @__PURE__ */ new WeakMap();
|
|
70
|
+
function isDecodablePath(pathname) {
|
|
71
|
+
try {
|
|
72
|
+
for (const segment of pathname.split("/"));
|
|
73
|
+
return true;
|
|
74
|
+
} catch {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
42
78
|
function createPipeline(cfg) {
|
|
43
79
|
const { docConfig, agent } = cfg;
|
|
44
80
|
const NotFound = cfg.notFoundComponent ?? DefaultNotFound;
|
|
81
|
+
const publishesCatalogs = agent.discovery && !docConfig.basePath;
|
|
45
82
|
function htmlHeaders() {
|
|
46
|
-
const headers = new Headers({
|
|
47
|
-
|
|
83
|
+
const headers = new Headers({
|
|
84
|
+
"content-type": "text/html; charset=utf-8",
|
|
85
|
+
vary: "accept"
|
|
86
|
+
});
|
|
87
|
+
const links = [buildLinkHeader(agent, { catalogs: publishesCatalogs }), ...cfg.earlyHints ?? []].filter(Boolean);
|
|
48
88
|
if (links.length) headers.set("link", links.join(", "));
|
|
49
89
|
if (cfg.htmlCacheControl) headers.set("cache-control", cfg.htmlCacheControl);
|
|
50
90
|
return headers;
|
|
@@ -65,18 +105,52 @@ function createPipeline(cfg) {
|
|
|
65
105
|
protocol: ctx.url.protocol.replace(":", "")
|
|
66
106
|
});
|
|
67
107
|
}
|
|
68
|
-
function pageProps(ctx) {
|
|
69
|
-
const
|
|
108
|
+
function pageProps(ctx, def) {
|
|
109
|
+
const isHome = routePathOf.get(ctx) === "/";
|
|
70
110
|
return {
|
|
71
111
|
pageUrl: ctx.url.href,
|
|
72
|
-
isHome
|
|
73
|
-
onLocaleDomain:
|
|
112
|
+
isHome,
|
|
113
|
+
onLocaleDomain: onLocaleDomain(ctx),
|
|
114
|
+
markdownHref: agent.discovery && def.md !== false ? markdownPath(ctx.url.pathname, isHome) : void 0
|
|
74
115
|
};
|
|
75
116
|
}
|
|
117
|
+
async function breadcrumbsFor(ctx, meta) {
|
|
118
|
+
const routePath = routePathOf.get(ctx);
|
|
119
|
+
if (!routePath || routePath === "/" || meta?.breadcrumb === false) return void 0;
|
|
120
|
+
const urlPath = ctx.url.pathname.replace(/\/+$/, "") || "/";
|
|
121
|
+
const route = routePath.replace(/\/+$/, "");
|
|
122
|
+
const prefix = urlPath.endsWith(route) ? urlPath.slice(0, urlPath.length - route.length) : "";
|
|
123
|
+
const home = {
|
|
124
|
+
name: siteShortName(docConfig.site) ?? documentTitle(void 0, docConfig.site),
|
|
125
|
+
path: prefix || "/"
|
|
126
|
+
};
|
|
127
|
+
if (Array.isArray(meta?.breadcrumb)) return [home, ...meta.breadcrumb];
|
|
128
|
+
const segments = route.split("/").filter(Boolean);
|
|
129
|
+
const trail = [home];
|
|
130
|
+
for (let i = 1; i < segments.length; i++) {
|
|
131
|
+
const ancestor = "/" + segments.slice(0, i).join("/");
|
|
132
|
+
const r = await resolveRoute(ancestor);
|
|
133
|
+
if (!r || "handler" in r || Object.keys(r.params).length > 0) continue;
|
|
134
|
+
const title = typeof r.def.metadata === "object" ? r.def.metadata?.title : void 0;
|
|
135
|
+
trail.push({
|
|
136
|
+
name: title || humanizeSegment(segments[i - 1]),
|
|
137
|
+
path: prefix + ancestor
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
trail.push({
|
|
141
|
+
name: meta?.title || humanizeSegment(segments[segments.length - 1]),
|
|
142
|
+
path: urlPath
|
|
143
|
+
});
|
|
144
|
+
return trail;
|
|
145
|
+
}
|
|
146
|
+
function onLocaleDomain(ctx) {
|
|
147
|
+
const host = ctx.url.hostname.toLowerCase();
|
|
148
|
+
return cfg.i18n ? Object.values(cfg.i18n.locales).some((l) => l.domain?.toLowerCase() === host) : false;
|
|
149
|
+
}
|
|
76
150
|
async function renderDocument(node, metadata, status, chain, locale, boundaryKey, alternates, page) {
|
|
77
151
|
const wrapped = chain.reduceRight((acc, L) => React.createElement(L, null, acc), node);
|
|
78
152
|
const stream = await renderToReadableStream(React.createElement(Document, {
|
|
79
|
-
config: docConfigForRender(),
|
|
153
|
+
config: docConfigForRender(page?.pageUrl),
|
|
80
154
|
metadata,
|
|
81
155
|
children: wrapped,
|
|
82
156
|
shellKey: boundaryKey,
|
|
@@ -92,7 +166,8 @@ function createPipeline(cfg) {
|
|
|
92
166
|
}
|
|
93
167
|
async function renderFragment(node, metadata, chain, boundaryIndex, boundaryKey) {
|
|
94
168
|
const segmented = typeof boundaryIndex === "number" && boundaryKey != null;
|
|
95
|
-
const
|
|
169
|
+
const wrapped = (segmented ? chain.slice(boundaryIndex + 1) : chain).reduceRight((acc, L) => React.createElement(L, null, acc), node);
|
|
170
|
+
const stream = await renderToReadableStream(wrapped);
|
|
96
171
|
await stream.allReady;
|
|
97
172
|
const html = await new Response(stream).text();
|
|
98
173
|
const headers = new Headers({ "content-type": "text/html; charset=utf-8" });
|
|
@@ -104,14 +179,16 @@ function createPipeline(cfg) {
|
|
|
104
179
|
headers
|
|
105
180
|
});
|
|
106
181
|
}
|
|
107
|
-
function docConfigForRender() {
|
|
182
|
+
function docConfigForRender(pageUrl) {
|
|
108
183
|
const webmcpTools = agent.webmcp && agent.mcp ? mcpTools() : null;
|
|
109
|
-
|
|
184
|
+
const servesCatalog = !!pageUrl && catalogOrigin(new URL(pageUrl)) !== null;
|
|
185
|
+
return {
|
|
110
186
|
...docConfig,
|
|
111
|
-
webmcpTools
|
|
112
|
-
|
|
187
|
+
...webmcpTools?.length ? { webmcpTools } : {},
|
|
188
|
+
...servesCatalog ? { aiCatalog: AI_CATALOG_PATH } : {}
|
|
189
|
+
};
|
|
113
190
|
}
|
|
114
|
-
async function renderStreamingDocument(resolved, loadPromise, ctx) {
|
|
191
|
+
async function renderStreamingDocument(resolved, loadPromise, ctx, breadcrumbs) {
|
|
115
192
|
const { def, chain, loading: Loading, boundaryKey } = resolved;
|
|
116
193
|
const leaf = React.createElement(StreamedView, {
|
|
117
194
|
loadPromise,
|
|
@@ -122,12 +199,13 @@ function createPipeline(cfg) {
|
|
|
122
199
|
const wrapped = chain.reduceRight((acc, L) => React.createElement(L, null, acc), boundary);
|
|
123
200
|
const metadata = typeof def.metadata === "object" ? def.metadata : void 0;
|
|
124
201
|
const stream = await renderToReadableStream(React.createElement(Document, {
|
|
125
|
-
config: docConfigForRender(),
|
|
202
|
+
config: docConfigForRender(ctx.url.href),
|
|
126
203
|
metadata,
|
|
127
204
|
children: wrapped,
|
|
128
205
|
shellKey: boundaryKey,
|
|
129
206
|
alternates: alternatesFor(ctx),
|
|
130
|
-
...pageProps(ctx),
|
|
207
|
+
...pageProps(ctx, def),
|
|
208
|
+
breadcrumbs,
|
|
131
209
|
...langDir(ctx.locale)
|
|
132
210
|
}), { onError: (e) => console.error("[june] streaming render error:", e) });
|
|
133
211
|
return new Response(stream, {
|
|
@@ -135,23 +213,74 @@ function createPipeline(cfg) {
|
|
|
135
213
|
headers: htmlHeaders()
|
|
136
214
|
});
|
|
137
215
|
}
|
|
138
|
-
function
|
|
139
|
-
return
|
|
216
|
+
async function resolveRoute(pathname) {
|
|
217
|
+
return isDecodablePath(pathname) ? cfg.resolve(pathname) : null;
|
|
218
|
+
}
|
|
219
|
+
function notFoundResponse(target, pathname, locale, unmatched) {
|
|
220
|
+
if (unmatched && agent.api) {
|
|
221
|
+
const url = new URL(unmatched.url);
|
|
222
|
+
if (isApiNamespace(url.pathname)) return apiNamespaceResponse(unmatched, url.origin);
|
|
223
|
+
}
|
|
224
|
+
if (target === "md") return discoveryLinks().then((links) => text(notFoundMarkdown(pathname, links), "text/markdown; charset=utf-8", {
|
|
225
|
+
status: 404,
|
|
226
|
+
headers: { vary: "accept" }
|
|
227
|
+
}));
|
|
228
|
+
if (target !== "view") return discoveryLinks().then((links) => Response.json({
|
|
140
229
|
error: "Not Found",
|
|
141
|
-
|
|
142
|
-
|
|
230
|
+
code: "not_found",
|
|
231
|
+
path: pathname,
|
|
232
|
+
hint: notFoundHint(links)
|
|
233
|
+
}, {
|
|
234
|
+
status: 404,
|
|
235
|
+
headers: { vary: "accept" }
|
|
236
|
+
}));
|
|
237
|
+
return renderDocument(React.createElement(NotFound, { pathname }), {
|
|
143
238
|
title: "Not found",
|
|
144
239
|
robots: "noindex"
|
|
145
240
|
}, 404, [], locale);
|
|
146
241
|
}
|
|
242
|
+
async function discoveryLinks() {
|
|
243
|
+
const links = [];
|
|
244
|
+
if (agent.discovery) links.push(["llms.txt — the site index for agents", "/llms.txt"], ["sitemap.xml — every page", "/sitemap.xml"]);
|
|
245
|
+
if (agent.mcp) links.push(["MCP server — this site's tools", "/mcp"]);
|
|
246
|
+
if (agent.api) links.push(["OpenAPI — the same tools over HTTP", "/openapi.json"]);
|
|
247
|
+
const home = await cfg.resolve("/");
|
|
248
|
+
if (home && "def" in home && home.def.md !== false) links.push(["Home page (Markdown)", "/index.md"]);
|
|
249
|
+
return links;
|
|
250
|
+
}
|
|
251
|
+
function notFoundHint(links) {
|
|
252
|
+
return links.length ? `No page at this path. Start from ${links.map(([, h]) => h).join(", ")}.` : "No page at this path.";
|
|
253
|
+
}
|
|
254
|
+
function notFoundMarkdown(pathname, links) {
|
|
255
|
+
const site = docConfig.site.name ? ` on ${docConfig.site.name}` : "";
|
|
256
|
+
return [
|
|
257
|
+
"# 404 — Not found",
|
|
258
|
+
"",
|
|
259
|
+
links.length ? `There is no page at \`${pathname}\`${site}. Try one of these instead:` : `There is no page at \`${pathname}\`${site}.`,
|
|
260
|
+
"",
|
|
261
|
+
...links.map(([label, href]) => `- [${label}](${href})`),
|
|
262
|
+
""
|
|
263
|
+
].join("\n");
|
|
264
|
+
}
|
|
147
265
|
function resolveMeta(def, data, ctx) {
|
|
148
266
|
return typeof def.metadata === "function" ? def.metadata(data, ctx) : def.metadata;
|
|
149
267
|
}
|
|
150
268
|
async function renderMarkdown(def, data, ctx) {
|
|
151
269
|
const jsonData = typeof def.json === "function" ? await def.json(data, ctx) : def.json === false ? null : data;
|
|
152
|
-
const body = typeof def.md === "function" ? await def.md(data, ctx) : "```json\n" + JSON.stringify(jsonData, null, 2) + "\n```\n";
|
|
270
|
+
const body = withFrontmatter(typeof def.md === "function" ? await def.md(data, ctx) : "```json\n" + JSON.stringify(jsonData, null, 2) + "\n```\n", resolveMeta(def, data, ctx), ctx);
|
|
153
271
|
return text(body, "text/markdown; charset=utf-8", { headers: { "x-markdown-tokens": String(Math.ceil(body.length / 4)) } });
|
|
154
272
|
}
|
|
273
|
+
function withFrontmatter(body, meta, ctx) {
|
|
274
|
+
if (/^---\r?\n/.test(body)) return body;
|
|
275
|
+
const title = meta?.title || documentTitle(meta, docConfig.site);
|
|
276
|
+
const description = meta?.description ?? docConfig.site.description;
|
|
277
|
+
const canonical = pageCanonical(docConfig, meta, ctx.url.href, htmlPath(ctx.url.pathname, routePathOf.get(ctx) === "/"), onLocaleDomain(ctx));
|
|
278
|
+
const lines = ["---", `title: ${JSON.stringify(title)}`];
|
|
279
|
+
if (description) lines.push(`description: ${JSON.stringify(description)}`);
|
|
280
|
+
if (canonical) lines.push(`canonical: ${JSON.stringify(canonical)}`);
|
|
281
|
+
lines.push("---", "");
|
|
282
|
+
return lines.join("\n") + body;
|
|
283
|
+
}
|
|
155
284
|
async function renderProjection(resolved, target, data, ctx) {
|
|
156
285
|
const { def, chain, boundaryIndex, boundaryKey } = resolved;
|
|
157
286
|
if (target !== "fragment" && def[target] === false) return notFoundResponse(target, ctx.url.pathname, ctx.locale);
|
|
@@ -168,15 +297,74 @@ function createPipeline(cfg) {
|
|
|
168
297
|
const node = provideLoaderData(data, def.view ? def.view(data, ctx) : null);
|
|
169
298
|
const meta = resolveMeta(def, data, ctx);
|
|
170
299
|
if (target === "fragment") return renderFragment(node, meta, chain, boundaryIndex, boundaryKey);
|
|
171
|
-
|
|
300
|
+
const page = {
|
|
301
|
+
...pageProps(ctx, def),
|
|
302
|
+
breadcrumbs: await breadcrumbsFor(ctx, meta)
|
|
303
|
+
};
|
|
304
|
+
return renderDocument(node, meta, 200, chain, ctx.locale, boundaryKey, alternatesFor(ctx), page);
|
|
305
|
+
}
|
|
306
|
+
function catalogOrigin(url) {
|
|
307
|
+
return publishesCatalogs ? publicOrigin(url) : null;
|
|
308
|
+
}
|
|
309
|
+
function publicOrigin(url) {
|
|
310
|
+
if (url.origin !== PRERENDER_ORIGIN) return url.origin;
|
|
311
|
+
return docConfig.site.url ? new URL(docConfig.site.url).origin : docConfig.deployOrigin ?? null;
|
|
312
|
+
}
|
|
313
|
+
function publicBase(url) {
|
|
314
|
+
const origin = publicOrigin(url);
|
|
315
|
+
return origin === null ? null : origin + (docConfig.basePath ?? "");
|
|
316
|
+
}
|
|
317
|
+
async function agentCatalog(url) {
|
|
318
|
+
const { pathname } = url;
|
|
319
|
+
if (!pathname.startsWith("/.well-known/")) return null;
|
|
320
|
+
const origin = catalogOrigin(url);
|
|
321
|
+
if (!origin) return null;
|
|
322
|
+
if (pathname === AGENT_SKILLS_INDEX_PATH) return Response.json(await agentSkillsIndex(origin, agent, docConfig.site), { headers: CORS });
|
|
323
|
+
if (pathname === AI_CATALOG_PATH || pathname === ARD_PATH) return Response.json(aiCatalog(origin, agent, docConfig.site), { headers: CORS });
|
|
324
|
+
const skill = siteSkill(origin, agent, docConfig.site);
|
|
325
|
+
if (pathname === new URL(skill.url).pathname) return text(skill.markdown, "text/markdown; charset=utf-8", { headers: CORS });
|
|
326
|
+
if (pathname.startsWith("/.well-known/agent-skills/")) return Response.json({
|
|
327
|
+
error: "Not Found",
|
|
328
|
+
path: pathname
|
|
329
|
+
}, {
|
|
330
|
+
status: 404,
|
|
331
|
+
headers: CORS
|
|
332
|
+
});
|
|
333
|
+
return null;
|
|
172
334
|
}
|
|
173
335
|
async function discovery(url) {
|
|
336
|
+
const catalog = await agentCatalog(url);
|
|
337
|
+
if (catalog) return catalog;
|
|
174
338
|
switch (url.pathname) {
|
|
175
|
-
case "/llms.txt":
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
339
|
+
case "/llms.txt": {
|
|
340
|
+
const routes = await cfg.routeList();
|
|
341
|
+
const base = publicBase(url) ?? docConfig.basePath ?? "";
|
|
342
|
+
const links = await collectLlmsLinks(base, routes, cfg.resolve);
|
|
343
|
+
return text(llmsTxt(base, routes, agent, docConfig.site, links), "text/markdown; charset=utf-8");
|
|
344
|
+
}
|
|
345
|
+
case "/robots.txt": {
|
|
346
|
+
const base = publicBase(url);
|
|
347
|
+
if (base === null) return text("Not Found\n", "text/plain; charset=utf-8", { status: 404 });
|
|
348
|
+
return text(robotsTxt(base, { catalogs: catalogOrigin(url) !== null }), "text/plain; charset=utf-8");
|
|
349
|
+
}
|
|
350
|
+
case "/sitemap.xml": {
|
|
351
|
+
const base = publicBase(url);
|
|
352
|
+
if (base === null) return text("Not Found\n", "text/plain; charset=utf-8", { status: 404 });
|
|
353
|
+
return text(sitemapXml(base, await collectSitemapPages(await cfg.routeList(), cfg.resolve, {
|
|
354
|
+
i18n: !!cfg.i18n,
|
|
355
|
+
staticPaths: cfg.staticBuild === true
|
|
356
|
+
}), cfg.i18n), "application/xml; charset=utf-8");
|
|
357
|
+
}
|
|
358
|
+
case "/.well-known/api-catalog": return text(JSON.stringify(apiCatalog(url.origin, agent)), API_CATALOG_CONTENT_TYPE, { headers: { link: `</.well-known/api-catalog>; rel="api-catalog"` } });
|
|
359
|
+
case SERVER_CARD_PATH: return agent.mcp ? text(JSON.stringify(mcpServerCard(url.origin, {
|
|
360
|
+
site: docConfig.site,
|
|
361
|
+
agent,
|
|
362
|
+
icons: docConfig.icons,
|
|
363
|
+
basePath: docConfig.basePath
|
|
364
|
+
})), MCP_SERVER_CARD_TYPE, { headers: {
|
|
365
|
+
...SERVER_CARD_CORS,
|
|
366
|
+
"cache-control": "public, max-age=3600"
|
|
367
|
+
} }) : null;
|
|
180
368
|
default: return null;
|
|
181
369
|
}
|
|
182
370
|
}
|
|
@@ -184,14 +372,45 @@ function createPipeline(cfg) {
|
|
|
184
372
|
const url = new URL(request.url);
|
|
185
373
|
if (url.pathname === "/mcp") {
|
|
186
374
|
if (!agent.mcp) return notFoundResponse("view", url.pathname);
|
|
375
|
+
const identity = cfg.identity ? await cfg.identity(request) : void 0;
|
|
187
376
|
return mcpHandler(request, {
|
|
188
377
|
request,
|
|
189
|
-
...
|
|
190
|
-
}
|
|
378
|
+
...identity
|
|
379
|
+
}, mcpServerIdentity(url.origin, {
|
|
380
|
+
site: docConfig.site,
|
|
381
|
+
agent
|
|
382
|
+
}));
|
|
191
383
|
}
|
|
192
|
-
if (
|
|
384
|
+
if (agent.api) {
|
|
385
|
+
if (url.pathname === "/openapi.json" && (request.method === "GET" || request.method === "HEAD")) {
|
|
386
|
+
const doc = Response.json(openApiDocument(url.origin, docConfig.site), { headers: {
|
|
387
|
+
"content-type": OPENAPI_MEDIA_TYPE,
|
|
388
|
+
"access-control-allow-origin": "*"
|
|
389
|
+
} });
|
|
390
|
+
return request.method === "HEAD" ? new Response(null, {
|
|
391
|
+
status: doc.status,
|
|
392
|
+
headers: doc.headers
|
|
393
|
+
}) : doc;
|
|
394
|
+
}
|
|
395
|
+
const actionId = apiActionId(url.pathname);
|
|
396
|
+
if (actionId) {
|
|
397
|
+
const identity = cfg.identity ? await cfg.identity(request) : void 0;
|
|
398
|
+
return apiHandler(request, actionId, {
|
|
399
|
+
request,
|
|
400
|
+
...identity
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
if (request.method === "OPTIONS" && agent.discovery && agent.mcp && url.pathname === SERVER_CARD_PATH) return new Response(null, {
|
|
405
|
+
status: 204,
|
|
406
|
+
headers: SERVER_CARD_CORS
|
|
407
|
+
});
|
|
408
|
+
if ((request.method === "GET" || request.method === "HEAD") && agent.discovery) {
|
|
193
409
|
const d = await discovery(url);
|
|
194
|
-
if (d) return
|
|
410
|
+
if (d) return request.method === "HEAD" ? new Response(null, {
|
|
411
|
+
status: d.status,
|
|
412
|
+
headers: d.headers
|
|
413
|
+
}) : d;
|
|
195
414
|
}
|
|
196
415
|
if (agent.runtime.enabled && cfg.agentSurface) {
|
|
197
416
|
const a = await cfg.agentSurface(request, url);
|
|
@@ -223,8 +442,8 @@ function createPipeline(cfg) {
|
|
|
223
442
|
if (locale) setRequestLocale(locale);
|
|
224
443
|
}
|
|
225
444
|
const { target, pathname, speculative } = negotiate(url, request, routeBase);
|
|
226
|
-
const resolved = await
|
|
227
|
-
if (!resolved) return notFoundResponse(target, pathname, locale);
|
|
445
|
+
const resolved = await resolveRoute(pathname);
|
|
446
|
+
if (!resolved) return notFoundResponse(target, pathname, locale, request);
|
|
228
447
|
const ctx = {
|
|
229
448
|
request,
|
|
230
449
|
url,
|
|
@@ -235,7 +454,10 @@ function createPipeline(cfg) {
|
|
|
235
454
|
};
|
|
236
455
|
routePathOf.set(ctx, pathname);
|
|
237
456
|
if ("handler" in resolved) return resolved.handler(request, ctx);
|
|
238
|
-
if (target === "view" && resolved.loading && typeof resolved.def.metadata !== "function")
|
|
457
|
+
if (target === "view" && resolved.loading && typeof resolved.def.metadata !== "function") {
|
|
458
|
+
const breadcrumbs = await breadcrumbsFor(ctx, resolved.def.metadata);
|
|
459
|
+
return renderStreamingDocument(resolved, Promise.resolve(resolved.def.load ? resolved.def.load(ctx) : void 0), ctx, breadcrumbs);
|
|
460
|
+
}
|
|
239
461
|
let data;
|
|
240
462
|
try {
|
|
241
463
|
data = resolved.def.load ? await resolved.def.load(ctx) : void 0;
|
|
@@ -246,11 +468,13 @@ function createPipeline(cfg) {
|
|
|
246
468
|
}
|
|
247
469
|
return { async fetch(request) {
|
|
248
470
|
await ensureScope();
|
|
471
|
+
const resources = cfg.resources ? await cfg.resources() : {};
|
|
472
|
+
const services = cfg.services ? await cfg.services() : void 0;
|
|
249
473
|
return runInScope({
|
|
250
|
-
resources
|
|
251
|
-
services
|
|
474
|
+
resources,
|
|
475
|
+
services
|
|
252
476
|
}, () => handleRequest(request));
|
|
253
477
|
} };
|
|
254
478
|
}
|
|
255
479
|
//#endregion
|
|
256
|
-
export { createPipeline };
|
|
480
|
+
export { createPipeline, htmlPath, isDecodablePath, markdownPath };
|
package/dist/resources.d.ts
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { t as D1Database } from "./d1-BkdUg9kg.js";
|
|
2
2
|
import { ResourceConfig, Resources } from "@junejs/core/resources";
|
|
3
3
|
//#region src/resources.d.ts
|
|
4
|
-
declare function memoizeResources(config?: ResourceConfig): () => Promise<Resources>;
|
|
5
|
-
type WorkerEnv = {
|
|
4
|
+
export declare function memoizeResources(config?: ResourceConfig): () => Promise<Resources>;
|
|
5
|
+
export type WorkerEnv = {
|
|
6
6
|
DB?: D1Database;
|
|
7
7
|
} & Record<string, unknown>;
|
|
8
|
-
type ResourceFlags = {
|
|
8
|
+
export type ResourceFlags = {
|
|
9
9
|
db?: boolean;
|
|
10
10
|
kv?: boolean;
|
|
11
11
|
blob?: boolean;
|
|
12
12
|
};
|
|
13
|
-
declare function bindWorkerResources(flags: ResourceFlags): (env?: unknown) => Promise<Resources>;
|
|
14
|
-
//#endregion
|
|
15
|
-
export { ResourceFlags, WorkerEnv, bindWorkerResources, memoizeResources };
|
|
13
|
+
export declare function bindWorkerResources(flags: ResourceFlags): (env?: unknown) => Promise<Resources>;
|
|
14
|
+
//#endregion
|
package/dist/router.d.ts
CHANGED
|
@@ -1,32 +1,31 @@
|
|
|
1
1
|
//#region src/router.d.ts
|
|
2
|
-
type RouteMatch = {
|
|
2
|
+
export type RouteMatch = {
|
|
3
3
|
file: string;
|
|
4
4
|
params: Record<string, string>;
|
|
5
5
|
};
|
|
6
|
-
type SegmentMatch = {
|
|
6
|
+
export type SegmentMatch = {
|
|
7
7
|
dir: string;
|
|
8
8
|
layout?: string;
|
|
9
9
|
loading?: string;
|
|
10
10
|
error?: string;
|
|
11
11
|
notFound?: string;
|
|
12
12
|
};
|
|
13
|
-
type RouteTreeMatch = {
|
|
13
|
+
export type RouteTreeMatch = {
|
|
14
14
|
file: string;
|
|
15
15
|
params: Record<string, string>;
|
|
16
16
|
segments: SegmentMatch[];
|
|
17
17
|
};
|
|
18
|
-
declare function findMiddlewareFile(appDir: string): string | null;
|
|
19
|
-
type MatchOptions = {
|
|
18
|
+
export declare function findMiddlewareFile(appDir: string): string | null;
|
|
19
|
+
export type MatchOptions = {
|
|
20
20
|
pageConvention?: boolean;
|
|
21
21
|
};
|
|
22
|
-
declare function isResourceFile(file: string): boolean;
|
|
23
|
-
declare function matchRouteTree(appDir: string, pathname: string, options?: MatchOptions): Promise<RouteTreeMatch | null>;
|
|
24
|
-
declare function resolveNotFound(appDir: string, pathname: string): Promise<{
|
|
22
|
+
export declare function isResourceFile(file: string): boolean;
|
|
23
|
+
export declare function matchRouteTree(appDir: string, pathname: string, options?: MatchOptions): Promise<RouteTreeMatch | null>;
|
|
24
|
+
export declare function resolveNotFound(appDir: string, pathname: string): Promise<{
|
|
25
25
|
segments: SegmentMatch[];
|
|
26
26
|
notFound?: string;
|
|
27
27
|
}>;
|
|
28
|
-
declare function routeFiles(appDir: string, options?: MatchOptions): Promise<string[]>;
|
|
29
|
-
declare function listRoutes(appDir: string, options?: MatchOptions): Promise<string[]>;
|
|
30
|
-
declare function matchRoute(appDir: string, pathname: string, options?: MatchOptions): Promise<RouteMatch | null>;
|
|
31
|
-
//#endregion
|
|
32
|
-
export { MatchOptions, RouteMatch, RouteTreeMatch, SegmentMatch, findMiddlewareFile, isResourceFile, listRoutes, matchRoute, matchRouteTree, resolveNotFound, routeFiles };
|
|
28
|
+
export declare function routeFiles(appDir: string, options?: MatchOptions): Promise<string[]>;
|
|
29
|
+
export declare function listRoutes(appDir: string, options?: MatchOptions): Promise<string[]>;
|
|
30
|
+
export declare function matchRoute(appDir: string, pathname: string, options?: MatchOptions): Promise<RouteMatch | null>;
|
|
31
|
+
//#endregion
|
package/dist/rsc-build.d.ts
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { DocumentConfig } from "@junejs/core/document";
|
|
2
2
|
//#region src/rsc-build.d.ts
|
|
3
|
-
type RscRoute = {
|
|
3
|
+
export type RscRoute = {
|
|
4
4
|
path: string;
|
|
5
5
|
file: string;
|
|
6
6
|
};
|
|
7
|
-
declare function findRscRoutes(appDir: string): RscRoute[];
|
|
8
|
-
type RscBuildResult = {
|
|
7
|
+
export declare function findRscRoutes(appDir: string): RscRoute[];
|
|
8
|
+
export type RscBuildResult = {
|
|
9
9
|
worker: string;
|
|
10
10
|
server: string;
|
|
11
11
|
paths: string[];
|
|
12
12
|
} | null;
|
|
13
|
-
declare function buildRsc(appRoot: string, outDir: string, docConfig: DocumentConfig): Promise<RscBuildResult>;
|
|
13
|
+
export declare function buildRsc(appRoot: string, outDir: string, docConfig: DocumentConfig): Promise<RscBuildResult>;
|
|
14
14
|
type Fetcher = (request: Request) => Promise<Response>;
|
|
15
|
-
declare function createRscDispatch(ssrFetch: Fetcher, rscFetch: Fetcher, rscPaths: Iterable<string>): Fetcher;
|
|
16
|
-
//#endregion
|
|
17
|
-
export { RscBuildResult, RscRoute, buildRsc, createRscDispatch, findRscRoutes };
|
|
15
|
+
export declare function createRscDispatch(ssrFetch: Fetcher, rscFetch: Fetcher, rscPaths: Iterable<string>): Fetcher;
|
|
16
|
+
//#endregion
|
package/dist/rsc-bundle.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
//#region src/rsc-bundle.d.ts
|
|
2
|
-
type RscGraph = "server" | "ssr";
|
|
3
|
-
type RscAliases = Record<string, string>;
|
|
4
|
-
declare function bundleServerGraph(entryFile: string, cwd: string, aliases?: RscAliases, appDir?: string): Promise<string>;
|
|
5
|
-
declare function bundleSsrGraph(entryFile: string, cwd: string, aliases?: RscAliases): Promise<string>;
|
|
6
|
-
declare function referencesNodeBuiltins(code: string): boolean;
|
|
7
|
-
//#endregion
|
|
8
|
-
export { RscAliases, RscGraph, bundleServerGraph, bundleSsrGraph, referencesNodeBuiltins };
|
|
2
|
+
export type RscGraph = "server" | "ssr";
|
|
3
|
+
export type RscAliases = Record<string, string>;
|
|
4
|
+
export declare function bundleServerGraph(entryFile: string, cwd: string, aliases?: RscAliases, appDir?: string): Promise<string>;
|
|
5
|
+
export declare function bundleSsrGraph(entryFile: string, cwd: string, aliases?: RscAliases): Promise<string>;
|
|
6
|
+
export declare function referencesNodeBuiltins(code: string): boolean;
|
|
7
|
+
//#endregion
|
package/dist/rsc-manifest.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Plugin } from "rolldown";
|
|
2
2
|
//#region src/rsc-manifest.d.ts
|
|
3
|
-
declare const RSC_SERVER_MANIFEST_FILE = "_rsc-server.gen.ts";
|
|
4
|
-
declare const RSC_CLIENT_MANIFEST_FILE = "_rsc-client.gen.ts";
|
|
5
|
-
declare function rscClientReferencesPlugin(appDir: string): Plugin;
|
|
6
|
-
declare function generateRscManifests(appDir: string): number;
|
|
7
|
-
//#endregion
|
|
8
|
-
export { RSC_CLIENT_MANIFEST_FILE, RSC_SERVER_MANIFEST_FILE, generateRscManifests, rscClientReferencesPlugin };
|
|
3
|
+
export declare const RSC_SERVER_MANIFEST_FILE = "_rsc-server.gen.ts";
|
|
4
|
+
export declare const RSC_CLIENT_MANIFEST_FILE = "_rsc-client.gen.ts";
|
|
5
|
+
export declare function rscClientReferencesPlugin(appDir: string): Plugin;
|
|
6
|
+
export declare function generateRscManifests(appDir: string): number;
|
|
7
|
+
//#endregion
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
//#region src/rsc-runtime/flight-render-routes.d.ts
|
|
2
|
-
declare function renderFlight(path: string): Promise<string | null>;
|
|
3
|
-
declare function rscPaths(): string[];
|
|
4
|
-
//#endregion
|
|
5
|
-
export { renderFlight, rscPaths };
|
|
2
|
+
export declare function renderFlight(path: string): Promise<string | null>;
|
|
3
|
+
export declare function rscPaths(): string[];
|
|
4
|
+
//#endregion
|
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
//#region src/rsc-runtime/flight-to-html.d.ts
|
|
2
|
-
declare function flightToHtml(flight: string, moduleMap?: Record<string, unknown>): Promise<string>;
|
|
3
|
-
//#endregion
|
|
4
|
-
export { flightToHtml };
|
|
2
|
+
export declare function flightToHtml(flight: string, moduleMap?: Record<string, unknown>): Promise<string>;
|
|
3
|
+
//#endregion
|
|
@@ -20,11 +20,12 @@ async function streamToString(stream) {
|
|
|
20
20
|
}
|
|
21
21
|
async function flightToHtml(flight, moduleMap = {}) {
|
|
22
22
|
const flightStream = new Response(flight).body;
|
|
23
|
-
const
|
|
23
|
+
const tree = createFromReadableStream(flightStream, { serverConsumerManifest: {
|
|
24
24
|
moduleMap,
|
|
25
25
|
serverModuleMap: null,
|
|
26
26
|
moduleLoading: null
|
|
27
|
-
} })
|
|
27
|
+
} });
|
|
28
|
+
const html = await renderToReadableStream(/* @__PURE__ */ jsx(Root, { tree }));
|
|
28
29
|
if (typeof html.allReady?.then === "function") await html.allReady;
|
|
29
30
|
return streamToString(html);
|
|
30
31
|
}
|
package/dist/segment.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//#region src/segment.d.ts
|
|
2
|
-
declare const boundaryWarning: (file: string) => string;
|
|
3
|
-
declare function boundaryKey(file: string): string;
|
|
4
|
-
declare function resolveBoundary<C>(items: Array<{
|
|
2
|
+
export declare const boundaryWarning: (file: string) => string;
|
|
3
|
+
export declare function boundaryKey(file: string): string;
|
|
4
|
+
export declare function resolveBoundary<C>(items: Array<{
|
|
5
5
|
file: string;
|
|
6
6
|
entry: C | null;
|
|
7
7
|
boundary: boolean;
|
|
@@ -10,5 +10,4 @@ declare function resolveBoundary<C>(items: Array<{
|
|
|
10
10
|
boundaryIndex: number | null;
|
|
11
11
|
key: string | null;
|
|
12
12
|
};
|
|
13
|
-
//#endregion
|
|
14
|
-
export { boundaryKey, boundaryWarning, resolveBoundary };
|
|
13
|
+
//#endregion
|