@junejs/server 1.0.0-dev.29 → 1.0.0-dev.42
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 +38 -20
- package/dist/agent-durable.js +159 -13
- package/dist/agent-native.d.ts +15 -12
- package/dist/agent-native.js +72 -8
- 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 +38 -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/core-version.js +1 -1
- 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 +8 -5
- package/dist/llms-links.js +31 -1
- 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 +260 -41
- 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 +203 -21
- package/src/agent-native.ts +94 -7
- package/src/build.ts +67 -5
- package/src/core-version.ts +1 -1
- package/src/llms-links.ts +46 -1
- package/src/negotiate.ts +39 -15
- package/src/pipeline.ts +433 -45
- package/src/web-manifest.ts +2 -6
- package/src/worker.ts +55 -17
package/dist/pipeline.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { iconLetter } from "./icon-letter.js";
|
|
2
|
-
import { collectLlmsLinks } from "./llms-links.js";
|
|
2
|
+
import { collectLlmsLinks, collectSitemapPages } from "./llms-links.js";
|
|
3
3
|
import { webManifest } from "./web-manifest.js";
|
|
4
4
|
import { SEGMENT_HEADER, TITLE_HEADER, encodeTitle, negotiate } from "./negotiate.js";
|
|
5
5
|
import { ensureScope, runInScope, setRequestLocale } from "@junejs/db";
|
|
6
6
|
import { LoaderDataContext } from "@junejs/core/route";
|
|
7
|
+
import { siteShortName } from "@junejs/core/config";
|
|
7
8
|
import React, { Suspense, use } from "react";
|
|
8
9
|
import { renderToReadableStream } from "react-dom/server";
|
|
9
|
-
import { Document } from "@junejs/core/document";
|
|
10
|
-
import { apiCatalog, buildLinkHeader, llmsTxt, mcpServerCard, robotsTxt, sitemapXml } from "@junejs/core/discovery";
|
|
11
|
-
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";
|
|
12
14
|
import { LOCALE_COOKIE, localeAlternates, localeDir, matchPinnedLocale, negotiateLocale } from "@junejs/core/i18n";
|
|
13
15
|
//#region src/pipeline.ts
|
|
14
16
|
function readCookie(request, name) {
|
|
@@ -21,6 +23,7 @@ function readCookie(request, name) {
|
|
|
21
23
|
}
|
|
22
24
|
}
|
|
23
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": "*" };
|
|
24
27
|
function text(body, contentType, init) {
|
|
25
28
|
const headers = new Headers(init?.headers);
|
|
26
29
|
headers.set("content-type", contentType);
|
|
@@ -39,13 +42,49 @@ function StreamedView({ loadPromise, def, ctx }) {
|
|
|
39
42
|
function letterFavicon(siteName) {
|
|
40
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" } });
|
|
41
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
|
+
}
|
|
42
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
|
+
}
|
|
43
78
|
function createPipeline(cfg) {
|
|
44
79
|
const { docConfig, agent } = cfg;
|
|
45
80
|
const NotFound = cfg.notFoundComponent ?? DefaultNotFound;
|
|
81
|
+
const publishesCatalogs = agent.discovery && !docConfig.basePath;
|
|
46
82
|
function htmlHeaders() {
|
|
47
|
-
const headers = new Headers({
|
|
48
|
-
|
|
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);
|
|
49
88
|
if (links.length) headers.set("link", links.join(", "));
|
|
50
89
|
if (cfg.htmlCacheControl) headers.set("cache-control", cfg.htmlCacheControl);
|
|
51
90
|
return headers;
|
|
@@ -66,18 +105,52 @@ function createPipeline(cfg) {
|
|
|
66
105
|
protocol: ctx.url.protocol.replace(":", "")
|
|
67
106
|
});
|
|
68
107
|
}
|
|
69
|
-
function pageProps(ctx) {
|
|
70
|
-
const
|
|
108
|
+
function pageProps(ctx, def) {
|
|
109
|
+
const isHome = routePathOf.get(ctx) === "/";
|
|
71
110
|
return {
|
|
72
111
|
pageUrl: ctx.url.href,
|
|
73
|
-
isHome
|
|
74
|
-
onLocaleDomain:
|
|
112
|
+
isHome,
|
|
113
|
+
onLocaleDomain: onLocaleDomain(ctx),
|
|
114
|
+
markdownHref: agent.discovery && def.md !== false ? markdownPath(ctx.url.pathname, isHome) : void 0
|
|
75
115
|
};
|
|
76
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
|
+
}
|
|
77
150
|
async function renderDocument(node, metadata, status, chain, locale, boundaryKey, alternates, page) {
|
|
78
151
|
const wrapped = chain.reduceRight((acc, L) => React.createElement(L, null, acc), node);
|
|
79
152
|
const stream = await renderToReadableStream(React.createElement(Document, {
|
|
80
|
-
config: docConfigForRender(),
|
|
153
|
+
config: docConfigForRender(page?.pageUrl),
|
|
81
154
|
metadata,
|
|
82
155
|
children: wrapped,
|
|
83
156
|
shellKey: boundaryKey,
|
|
@@ -93,7 +166,8 @@ function createPipeline(cfg) {
|
|
|
93
166
|
}
|
|
94
167
|
async function renderFragment(node, metadata, chain, boundaryIndex, boundaryKey) {
|
|
95
168
|
const segmented = typeof boundaryIndex === "number" && boundaryKey != null;
|
|
96
|
-
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);
|
|
97
171
|
await stream.allReady;
|
|
98
172
|
const html = await new Response(stream).text();
|
|
99
173
|
const headers = new Headers({ "content-type": "text/html; charset=utf-8" });
|
|
@@ -105,14 +179,16 @@ function createPipeline(cfg) {
|
|
|
105
179
|
headers
|
|
106
180
|
});
|
|
107
181
|
}
|
|
108
|
-
function docConfigForRender() {
|
|
182
|
+
function docConfigForRender(pageUrl) {
|
|
109
183
|
const webmcpTools = agent.webmcp && agent.mcp ? mcpTools() : null;
|
|
110
|
-
|
|
184
|
+
const servesCatalog = !!pageUrl && catalogOrigin(new URL(pageUrl)) !== null;
|
|
185
|
+
return {
|
|
111
186
|
...docConfig,
|
|
112
|
-
webmcpTools
|
|
113
|
-
|
|
187
|
+
...webmcpTools?.length ? { webmcpTools } : {},
|
|
188
|
+
...servesCatalog ? { aiCatalog: AI_CATALOG_PATH } : {}
|
|
189
|
+
};
|
|
114
190
|
}
|
|
115
|
-
async function renderStreamingDocument(resolved, loadPromise, ctx) {
|
|
191
|
+
async function renderStreamingDocument(resolved, loadPromise, ctx, breadcrumbs) {
|
|
116
192
|
const { def, chain, loading: Loading, boundaryKey } = resolved;
|
|
117
193
|
const leaf = React.createElement(StreamedView, {
|
|
118
194
|
loadPromise,
|
|
@@ -123,12 +199,13 @@ function createPipeline(cfg) {
|
|
|
123
199
|
const wrapped = chain.reduceRight((acc, L) => React.createElement(L, null, acc), boundary);
|
|
124
200
|
const metadata = typeof def.metadata === "object" ? def.metadata : void 0;
|
|
125
201
|
const stream = await renderToReadableStream(React.createElement(Document, {
|
|
126
|
-
config: docConfigForRender(),
|
|
202
|
+
config: docConfigForRender(ctx.url.href),
|
|
127
203
|
metadata,
|
|
128
204
|
children: wrapped,
|
|
129
205
|
shellKey: boundaryKey,
|
|
130
206
|
alternates: alternatesFor(ctx),
|
|
131
|
-
...pageProps(ctx),
|
|
207
|
+
...pageProps(ctx, def),
|
|
208
|
+
breadcrumbs,
|
|
132
209
|
...langDir(ctx.locale)
|
|
133
210
|
}), { onError: (e) => console.error("[june] streaming render error:", e) });
|
|
134
211
|
return new Response(stream, {
|
|
@@ -136,23 +213,74 @@ function createPipeline(cfg) {
|
|
|
136
213
|
headers: htmlHeaders()
|
|
137
214
|
});
|
|
138
215
|
}
|
|
139
|
-
function
|
|
140
|
-
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({
|
|
141
229
|
error: "Not Found",
|
|
142
|
-
|
|
143
|
-
|
|
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 }), {
|
|
144
238
|
title: "Not found",
|
|
145
239
|
robots: "noindex"
|
|
146
240
|
}, 404, [], locale);
|
|
147
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
|
+
}
|
|
148
265
|
function resolveMeta(def, data, ctx) {
|
|
149
266
|
return typeof def.metadata === "function" ? def.metadata(data, ctx) : def.metadata;
|
|
150
267
|
}
|
|
151
268
|
async function renderMarkdown(def, data, ctx) {
|
|
152
269
|
const jsonData = typeof def.json === "function" ? await def.json(data, ctx) : def.json === false ? null : data;
|
|
153
|
-
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);
|
|
154
271
|
return text(body, "text/markdown; charset=utf-8", { headers: { "x-markdown-tokens": String(Math.ceil(body.length / 4)) } });
|
|
155
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
|
+
}
|
|
156
284
|
async function renderProjection(resolved, target, data, ctx) {
|
|
157
285
|
const { def, chain, boundaryIndex, boundaryKey } = resolved;
|
|
158
286
|
if (target !== "fragment" && def[target] === false) return notFoundResponse(target, ctx.url.pathname, ctx.locale);
|
|
@@ -169,19 +297,74 @@ function createPipeline(cfg) {
|
|
|
169
297
|
const node = provideLoaderData(data, def.view ? def.view(data, ctx) : null);
|
|
170
298
|
const meta = resolveMeta(def, data, ctx);
|
|
171
299
|
if (target === "fragment") return renderFragment(node, meta, chain, boundaryIndex, boundaryKey);
|
|
172
|
-
|
|
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;
|
|
173
334
|
}
|
|
174
335
|
async function discovery(url) {
|
|
336
|
+
const catalog = await agentCatalog(url);
|
|
337
|
+
if (catalog) return catalog;
|
|
175
338
|
switch (url.pathname) {
|
|
176
339
|
case "/llms.txt": {
|
|
177
340
|
const routes = await cfg.routeList();
|
|
178
|
-
const
|
|
179
|
-
|
|
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");
|
|
180
357
|
}
|
|
181
|
-
case "/
|
|
182
|
-
case
|
|
183
|
-
|
|
184
|
-
|
|
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;
|
|
185
368
|
default: return null;
|
|
186
369
|
}
|
|
187
370
|
}
|
|
@@ -189,14 +372,45 @@ function createPipeline(cfg) {
|
|
|
189
372
|
const url = new URL(request.url);
|
|
190
373
|
if (url.pathname === "/mcp") {
|
|
191
374
|
if (!agent.mcp) return notFoundResponse("view", url.pathname);
|
|
375
|
+
const identity = cfg.identity ? await cfg.identity(request) : void 0;
|
|
192
376
|
return mcpHandler(request, {
|
|
193
377
|
request,
|
|
194
|
-
...
|
|
195
|
-
}
|
|
378
|
+
...identity
|
|
379
|
+
}, mcpServerIdentity(url.origin, {
|
|
380
|
+
site: docConfig.site,
|
|
381
|
+
agent
|
|
382
|
+
}));
|
|
383
|
+
}
|
|
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
|
+
}
|
|
196
403
|
}
|
|
197
|
-
if (request.method === "
|
|
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) {
|
|
198
409
|
const d = await discovery(url);
|
|
199
|
-
if (d) return
|
|
410
|
+
if (d) return request.method === "HEAD" ? new Response(null, {
|
|
411
|
+
status: d.status,
|
|
412
|
+
headers: d.headers
|
|
413
|
+
}) : d;
|
|
200
414
|
}
|
|
201
415
|
if (agent.runtime.enabled && cfg.agentSurface) {
|
|
202
416
|
const a = await cfg.agentSurface(request, url);
|
|
@@ -228,8 +442,8 @@ function createPipeline(cfg) {
|
|
|
228
442
|
if (locale) setRequestLocale(locale);
|
|
229
443
|
}
|
|
230
444
|
const { target, pathname, speculative } = negotiate(url, request, routeBase);
|
|
231
|
-
const resolved = await
|
|
232
|
-
if (!resolved) return notFoundResponse(target, pathname, locale);
|
|
445
|
+
const resolved = await resolveRoute(pathname);
|
|
446
|
+
if (!resolved) return notFoundResponse(target, pathname, locale, request);
|
|
233
447
|
const ctx = {
|
|
234
448
|
request,
|
|
235
449
|
url,
|
|
@@ -240,7 +454,10 @@ function createPipeline(cfg) {
|
|
|
240
454
|
};
|
|
241
455
|
routePathOf.set(ctx, pathname);
|
|
242
456
|
if ("handler" in resolved) return resolved.handler(request, ctx);
|
|
243
|
-
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
|
+
}
|
|
244
461
|
let data;
|
|
245
462
|
try {
|
|
246
463
|
data = resolved.def.load ? await resolved.def.load(ctx) : void 0;
|
|
@@ -251,11 +468,13 @@ function createPipeline(cfg) {
|
|
|
251
468
|
}
|
|
252
469
|
return { async fetch(request) {
|
|
253
470
|
await ensureScope();
|
|
471
|
+
const resources = cfg.resources ? await cfg.resources() : {};
|
|
472
|
+
const services = cfg.services ? await cfg.services() : void 0;
|
|
254
473
|
return runInScope({
|
|
255
|
-
resources
|
|
256
|
-
services
|
|
474
|
+
resources,
|
|
475
|
+
services
|
|
257
476
|
}, () => handleRequest(request));
|
|
258
477
|
} };
|
|
259
478
|
}
|
|
260
479
|
//#endregion
|
|
261
|
-
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
|