reroute-js 0.45.11 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -2
- package/_/blog/src/client/routes/blog/[layout].tsx +45 -13
- package/_/blog/src/client/routes/blog/content/pt-BR/1-hello-world.tsx +27 -0
- package/_/blog/src/client/routes/index.tsx +4 -4
- package/_/search/src/client/routes/docs/content/content-collections.md +18 -0
- package/cli/bin.d.ts +2 -2
- package/cli/bin.js +1175 -431
- package/cli/bin.js.map +33 -24
- package/cli/index.d.ts +2 -2
- package/cli/index.js +5 -5
- package/cli/index.js.map +1 -1
- package/cli/src/cli.d.ts +2 -2
- package/cli/src/commands/analyze.d.ts +2 -2
- package/cli/src/commands/build.d.ts +2 -2
- package/cli/src/commands/dev.d.ts +2 -2
- package/cli/src/commands/gen.d.ts +2 -2
- package/cli/src/commands/gen.d.ts.map +1 -1
- package/cli/src/commands/index.d.ts +2 -2
- package/cli/src/commands/init.d.ts +2 -2
- package/cli/src/commands/lib/assets.d.ts +2 -2
- package/cli/src/commands/lib/bundler.d.ts +2 -2
- package/cli/src/commands/lib/command.d.ts +2 -2
- package/cli/src/commands/lib/env.d.ts +2 -2
- package/cli/src/commands/lib/index.d.ts +2 -2
- package/cli/src/commands/lib/log.d.ts +2 -2
- package/cli/src/commands/lib/markdown/availability.d.ts +2 -2
- package/cli/src/commands/lib/markdown/index.d.ts +2 -2
- package/cli/src/commands/lib/markdown/processor.d.ts +2 -2
- package/cli/src/commands/lib/production.d.ts +2 -2
- package/cli/src/commands/lib/server.d.ts +2 -2
- package/cli/src/commands/lib/streaming/analyzer.d.ts +2 -2
- package/cli/src/commands/lib/streaming/suspense.d.ts +2 -2
- package/cli/src/commands/lib/tailwind.d.ts +2 -2
- package/cli/src/commands/lib/terminal-ui.d.ts +2 -2
- package/cli/src/commands/lib/version.d.ts +2 -2
- package/cli/src/commands/og.d.ts +2 -2
- package/cli/src/commands/start.d.ts +2 -2
- package/cli/src/index.d.ts +2 -2
- package/core/index.d.ts +2 -2
- package/core/index.js +827 -192
- package/core/index.js.map +32 -23
- package/core/src/bundler/hash.d.ts +2 -2
- package/core/src/bundler/index.d.ts +2 -2
- package/core/src/config.d.ts +6 -3
- package/core/src/config.d.ts.map +1 -1
- package/core/src/content/discovery.d.ts +2 -2
- package/core/src/content/index.d.ts +2 -2
- package/core/src/content/metadata.d.ts +2 -2
- package/core/src/i18n/catalog.d.ts +17 -0
- package/core/src/i18n/catalog.d.ts.map +1 -0
- package/core/src/i18n/discover.d.ts +19 -0
- package/core/src/i18n/discover.d.ts.map +1 -0
- package/core/src/i18n/index.d.ts +17 -0
- package/core/src/i18n/index.d.ts.map +1 -0
- package/core/src/i18n/messages.d.ts +18 -0
- package/core/src/i18n/messages.d.ts.map +1 -0
- package/core/src/i18n/negotiate.d.ts +18 -0
- package/core/src/i18n/negotiate.d.ts.map +1 -0
- package/core/src/i18n/pathname.d.ts +34 -0
- package/core/src/i18n/pathname.d.ts.map +1 -0
- package/core/src/i18n/resolve.d.ts +22 -0
- package/core/src/i18n/resolve.d.ts.map +1 -0
- package/core/src/i18n/types.d.ts +68 -0
- package/core/src/i18n/types.d.ts.map +1 -0
- package/core/src/index.d.ts +3 -2
- package/core/src/index.d.ts.map +1 -1
- package/core/src/llms/extractor.d.ts +2 -2
- package/core/src/llms/formatter.d.ts +2 -2
- package/core/src/llms/full-generator.d.ts +2 -2
- package/core/src/llms/index-generator.d.ts +2 -2
- package/core/src/llms/index.d.ts +2 -2
- package/core/src/og/discovery.d.ts +2 -2
- package/core/src/og/discovery.d.ts.map +1 -1
- package/core/src/og/index.d.ts +2 -2
- package/core/src/og/meta.d.ts +2 -2
- package/core/src/og/render.d.ts +2 -2
- package/core/src/og/types.d.ts +2 -2
- package/core/src/robots/discovery.d.ts +2 -2
- package/core/src/robots/generator.d.ts +2 -2
- package/core/src/robots/index.d.ts +2 -2
- package/core/src/robots/policies.d.ts +2 -2
- package/core/src/rss/discovery.d.ts +4 -2
- package/core/src/rss/discovery.d.ts.map +1 -1
- package/core/src/rss/generator.d.ts +2 -2
- package/core/src/rss/index.d.ts +2 -2
- package/core/src/sitemap/discovery.d.ts +7 -2
- package/core/src/sitemap/discovery.d.ts.map +1 -1
- package/core/src/sitemap/generator.d.ts +2 -2
- package/core/src/sitemap/generator.d.ts.map +1 -1
- package/core/src/sitemap/index.d.ts +2 -2
- package/core/src/ssr/index.d.ts +2 -2
- package/core/src/ssr/lib/cache.d.ts +2 -2
- package/core/src/ssr/lib/cleanup.d.ts +2 -2
- package/core/src/ssr/lib/collections.d.ts +2 -2
- package/core/src/ssr/lib/compression.d.ts +2 -2
- package/core/src/ssr/lib/compute/content.d.ts +2 -9
- package/core/src/ssr/lib/compute/content.d.ts.map +1 -1
- package/core/src/ssr/lib/compute/index.d.ts +2 -2
- package/core/src/ssr/lib/compute/index.d.ts.map +1 -1
- package/core/src/ssr/lib/compute/layouts.d.ts +2 -2
- package/core/src/ssr/lib/compute/routes.d.ts +2 -2
- package/core/src/ssr/lib/compute/routes.d.ts.map +1 -1
- package/core/src/ssr/lib/content-path.d.ts +22 -0
- package/core/src/ssr/lib/content-path.d.ts.map +1 -0
- package/core/src/ssr/lib/data.d.ts +2 -2
- package/core/src/ssr/lib/data.d.ts.map +1 -1
- package/core/src/ssr/lib/html.d.ts +2 -2
- package/core/src/ssr/lib/imports.d.ts +2 -2
- package/core/src/ssr/lib/index.d.ts +3 -2
- package/core/src/ssr/lib/index.d.ts.map +1 -1
- package/core/src/ssr/lib/layouts.d.ts +2 -2
- package/core/src/ssr/lib/metadata.d.ts +2 -2
- package/core/src/ssr/lib/metadata.d.ts.map +1 -1
- package/core/src/ssr/lib/mime.d.ts +2 -2
- package/core/src/ssr/lib/modules.d.ts +4 -4
- package/core/src/ssr/lib/modules.d.ts.map +1 -1
- package/core/src/ssr/lib/path.d.ts +2 -2
- package/core/src/ssr/lib/preload.d.ts +2 -2
- package/core/src/ssr/lib/preload.d.ts.map +1 -1
- package/core/src/ssr/lib/route-match.d.ts +20 -0
- package/core/src/ssr/lib/route-match.d.ts.map +1 -0
- package/core/src/ssr/lib/scripts/collections.d.ts +2 -2
- package/core/src/ssr/lib/scripts/data.d.ts +3 -3
- package/core/src/ssr/lib/scripts/data.d.ts.map +1 -1
- package/core/src/ssr/lib/scripts/escape.d.ts +2 -2
- package/core/src/ssr/lib/scripts/feeds.d.ts +2 -2
- package/core/src/ssr/lib/scripts/index.d.ts +2 -2
- package/core/src/ssr/lib/seed.d.ts +2 -2
- package/core/src/ssr/lib/seed.d.ts.map +1 -1
- package/core/src/ssr/lib/serialize.d.ts +2 -2
- package/core/src/ssr/lib/setup.d.ts +3 -3
- package/core/src/ssr/lib/setup.d.ts.map +1 -1
- package/core/src/ssr/lib/styles.d.ts +2 -2
- package/core/src/ssr/lib/template.d.ts +2 -2
- package/core/src/ssr/lib/types.d.ts +2 -2
- package/core/src/ssr/render.d.ts +4 -2
- package/core/src/ssr/render.d.ts.map +1 -1
- package/core/src/ssr/stream.d.ts +4 -2
- package/core/src/ssr/stream.d.ts.map +1 -1
- package/elysia/index.d.ts +2 -2
- package/elysia/index.js +1072 -276
- package/elysia/index.js.map +37 -27
- package/elysia/src/index.d.ts +2 -2
- package/elysia/src/libs/assets.d.ts +2 -2
- package/elysia/src/libs/cache.d.ts +2 -2
- package/elysia/src/libs/caching.d.ts +2 -2
- package/elysia/src/libs/http.d.ts +2 -2
- package/elysia/src/libs/i18n.d.ts +26 -0
- package/elysia/src/libs/i18n.d.ts.map +1 -0
- package/elysia/src/libs/image.d.ts +2 -2
- package/elysia/src/libs/index.d.ts +2 -2
- package/elysia/src/libs/llms.d.ts +2 -2
- package/elysia/src/libs/response.d.ts +2 -2
- package/elysia/src/libs/serving.d.ts +2 -2
- package/elysia/src/plugin.d.ts +2 -2
- package/elysia/src/routes/artifacts.d.ts +2 -2
- package/elysia/src/routes/content.d.ts +2 -2
- package/elysia/src/routes/image.d.ts +2 -2
- package/elysia/src/routes/index.d.ts +2 -2
- package/elysia/src/routes/internal.d.ts +2 -2
- package/elysia/src/routes/llms.d.ts +2 -2
- package/elysia/src/routes/og.d.ts +2 -2
- package/elysia/src/routes/og.d.ts.map +1 -1
- package/elysia/src/routes/redirects.d.ts +2 -2
- package/elysia/src/routes/robots.d.ts +2 -2
- package/elysia/src/routes/rss.d.ts +2 -2
- package/elysia/src/routes/rss.d.ts.map +1 -1
- package/elysia/src/routes/search.d.ts +2 -2
- package/elysia/src/routes/search.d.ts.map +1 -1
- package/elysia/src/routes/sitemap.d.ts +2 -2
- package/elysia/src/routes/ssr.d.ts +2 -2
- package/elysia/src/routes/ssr.d.ts.map +1 -1
- package/elysia/src/routes/static.d.ts +2 -2
- package/elysia/src/types.d.ts +2 -2
- package/package.json +7 -6
- package/react/index.d.ts +2 -2
- package/react/index.js +565 -171
- package/react/index.js.map +12 -10
- package/react/src/components/ClientOnly.d.ts +2 -2
- package/react/src/components/ContentRoute.d.ts +3 -3
- package/react/src/components/ContentRoute.d.ts.map +1 -1
- package/react/src/components/Image.d.ts +2 -2
- package/react/src/components/LazyRoute.d.ts +2 -2
- package/react/src/components/Link.d.ts +2 -2
- package/react/src/components/Link.d.ts.map +1 -1
- package/react/src/components/Markdown.d.ts +2 -2
- package/react/src/components/Outlet.d.ts +2 -2
- package/react/src/components/index.d.ts +2 -2
- package/react/src/hooks/index.d.ts +2 -2
- package/react/src/hooks/useContent.d.ts +2 -2
- package/react/src/hooks/useContent.d.ts.map +1 -1
- package/react/src/hooks/useData.d.ts +2 -2
- package/react/src/hooks/useFeed.d.ts +2 -2
- package/react/src/hooks/useLayoutData.d.ts +2 -2
- package/react/src/hooks/useLlms.d.ts +2 -2
- package/react/src/hooks/useNavigate.d.ts +2 -2
- package/react/src/hooks/useParams.d.ts +2 -2
- package/react/src/hooks/useRouter.d.ts +2 -2
- package/react/src/hooks/useSearch.d.ts +2 -2
- package/react/src/hooks/useSearch.d.ts.map +1 -1
- package/react/src/hooks/useSearchParams.d.ts +2 -2
- package/react/src/hooks/useToc.d.ts +2 -2
- package/react/src/i18n/LocaleProvider.d.ts +49 -0
- package/react/src/i18n/LocaleProvider.d.ts.map +1 -0
- package/react/src/i18n/helpers.d.ts +24 -0
- package/react/src/i18n/helpers.d.ts.map +1 -0
- package/react/src/i18n/index.d.ts +13 -0
- package/react/src/i18n/index.d.ts.map +1 -0
- package/react/src/index.d.ts +3 -2
- package/react/src/index.d.ts.map +1 -1
- package/react/src/lib/collection.d.ts +2 -2
- package/react/src/lib/content.d.ts +4 -3
- package/react/src/lib/content.d.ts.map +1 -1
- package/react/src/lib/head.d.ts +2 -2
- package/react/src/lib/index.d.ts +2 -2
- package/react/src/lib/lazy-route.d.ts +2 -2
- package/react/src/lib/route-loader.d.ts +2 -2
- package/react/src/providers/ContentProvider.d.ts +3 -3
- package/react/src/providers/ContentProvider.d.ts.map +1 -1
- package/react/src/providers/RerouteProvider.d.ts +8 -6
- package/react/src/providers/RerouteProvider.d.ts.map +1 -1
- package/react/src/providers/RouterProvider.d.ts +2 -2
- package/react/src/providers/index.d.ts +2 -2
- package/react/src/types/any.d.ts +2 -2
- package/react/src/types/index.d.ts +2 -2
- package/react/src/types/router.d.ts +2 -2
- package/telemetry/react.d.ts +2 -2
- package/telemetry/react.js +8 -4
- package/telemetry/react.js.map +2 -2
- package/telemetry/server.d.ts +2 -2
- package/telemetry/server.js +60 -5
- package/telemetry/server.js.map +22 -17
- package/telemetry/src/react/api.d.ts +2 -2
- package/telemetry/src/react/context.d.ts +2 -2
- package/telemetry/src/react/index.d.ts +2 -2
- package/telemetry/src/react/telemetry.d.ts +2 -2
- package/telemetry/src/server/context.d.ts +2 -2
- package/telemetry/src/server/headers/extractor.d.ts +2 -2
- package/telemetry/src/server/headers/index.d.ts +2 -2
- package/telemetry/src/server/headers/presets.d.ts +2 -2
- package/telemetry/src/server/index.d.ts +2 -2
- package/telemetry/src/server/instrumentation.d.ts +2 -2
- package/telemetry/src/server/plugin.d.ts +2 -2
- package/telemetry/src/server/sourcemap.d.ts +2 -2
package/elysia/index.js
CHANGED
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* reroute-js v0.
|
|
2
|
+
* reroute-js v0.46.0
|
|
3
3
|
*
|
|
4
4
|
* @license MIT
|
|
5
5
|
* @copyright 2026 stewones <hi@stewan.io>
|
|
6
|
-
* @see https://github.com/
|
|
6
|
+
* @see https://github.com/Intenseloop/reroute
|
|
7
7
|
*
|
|
8
8
|
* Built with Bun <3
|
|
9
9
|
*/
|
|
10
10
|
import { createRequire } from "node:module";
|
|
11
11
|
var __defProp = Object.defineProperty;
|
|
12
|
+
var __returnValue = (v) => v;
|
|
13
|
+
function __exportSetter(name, newValue) {
|
|
14
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
15
|
+
}
|
|
12
16
|
var __export = (target, all) => {
|
|
13
17
|
for (var name in all)
|
|
14
18
|
__defProp(target, name, {
|
|
15
19
|
get: all[name],
|
|
16
20
|
enumerable: true,
|
|
17
21
|
configurable: true,
|
|
18
|
-
set: (
|
|
22
|
+
set: __exportSetter.bind(all, name)
|
|
19
23
|
});
|
|
20
24
|
};
|
|
21
25
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
@@ -196,6 +200,364 @@ var init_content = __esm(() => {
|
|
|
196
200
|
init_metadata();
|
|
197
201
|
});
|
|
198
202
|
|
|
203
|
+
// packages/core/src/i18n/catalog.ts
|
|
204
|
+
function getMessage(catalog, key) {
|
|
205
|
+
if (!(catalog && key))
|
|
206
|
+
return;
|
|
207
|
+
const parts = key.split(".");
|
|
208
|
+
let current = catalog;
|
|
209
|
+
for (const part of parts) {
|
|
210
|
+
if (current == null || typeof current === "string")
|
|
211
|
+
return;
|
|
212
|
+
current = current[part];
|
|
213
|
+
}
|
|
214
|
+
return typeof current === "string" ? current : undefined;
|
|
215
|
+
}
|
|
216
|
+
function lookupMessage(catalogs, locale, defaultLocale, key) {
|
|
217
|
+
return getMessage(catalogs[locale], key) ?? (locale !== defaultLocale ? getMessage(catalogs[defaultLocale], key) : undefined);
|
|
218
|
+
}
|
|
219
|
+
var init_catalog = () => {};
|
|
220
|
+
|
|
221
|
+
// packages/core/src/i18n/discover.ts
|
|
222
|
+
import { readdir as readdir2 } from "node:fs/promises";
|
|
223
|
+
import { join as join2 } from "node:path";
|
|
224
|
+
async function loadCatalog(filePath) {
|
|
225
|
+
try {
|
|
226
|
+
const text = await Bun.file(filePath).text();
|
|
227
|
+
return JSON.parse(text);
|
|
228
|
+
} catch {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
async function loadLocaleCatalogs(absDir) {
|
|
233
|
+
const entries = await readdir2(absDir, { withFileTypes: true });
|
|
234
|
+
const catalogs = {};
|
|
235
|
+
const locales = [];
|
|
236
|
+
for (const entry of entries) {
|
|
237
|
+
if (!(entry.isFile() && entry.name.endsWith(".json")))
|
|
238
|
+
continue;
|
|
239
|
+
const locale = entry.name.slice(0, -".json".length);
|
|
240
|
+
if (!locale)
|
|
241
|
+
continue;
|
|
242
|
+
const catalog = await loadCatalog(join2(absDir, entry.name));
|
|
243
|
+
if (!catalog)
|
|
244
|
+
continue;
|
|
245
|
+
catalogs[locale] = catalog;
|
|
246
|
+
locales.push(locale);
|
|
247
|
+
}
|
|
248
|
+
return { catalogs, locales };
|
|
249
|
+
}
|
|
250
|
+
function sortLocales(locales, defaultLocale) {
|
|
251
|
+
locales.sort((a, b) => {
|
|
252
|
+
if (a === defaultLocale)
|
|
253
|
+
return -1;
|
|
254
|
+
if (b === defaultLocale)
|
|
255
|
+
return 1;
|
|
256
|
+
return a.localeCompare(b);
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
async function discoverI18n(cwd, options = {}) {
|
|
260
|
+
const localesDir = options.localesDir ?? DEFAULT_LOCALES_DIR;
|
|
261
|
+
const defaultLocale = options.defaultLocale ?? DEFAULT_LOCALE;
|
|
262
|
+
const cookie = options.cookie ?? DEFAULT_COOKIE;
|
|
263
|
+
const redirectContentOnNegotiate = options.redirectContentOnNegotiate ?? true;
|
|
264
|
+
const absDir = join2(cwd, localesDir);
|
|
265
|
+
const disabled = {
|
|
266
|
+
enabled: false,
|
|
267
|
+
defaultLocale,
|
|
268
|
+
locales: [],
|
|
269
|
+
localesDir,
|
|
270
|
+
cookie,
|
|
271
|
+
redirectContentOnNegotiate,
|
|
272
|
+
catalogs: {}
|
|
273
|
+
};
|
|
274
|
+
let catalogs;
|
|
275
|
+
let locales;
|
|
276
|
+
try {
|
|
277
|
+
({ catalogs, locales } = await loadLocaleCatalogs(absDir));
|
|
278
|
+
} catch {
|
|
279
|
+
return disabled;
|
|
280
|
+
}
|
|
281
|
+
if (locales.length === 0) {
|
|
282
|
+
return disabled;
|
|
283
|
+
}
|
|
284
|
+
sortLocales(locales, defaultLocale);
|
|
285
|
+
if (!catalogs[defaultLocale]) {
|
|
286
|
+
console.warn(`[reroute/i18n] defaultLocale "${defaultLocale}" has no catalog; using "${locales[0]}"`);
|
|
287
|
+
}
|
|
288
|
+
return {
|
|
289
|
+
enabled: true,
|
|
290
|
+
defaultLocale: catalogs[defaultLocale] ? defaultLocale : locales[0],
|
|
291
|
+
locales,
|
|
292
|
+
localesDir,
|
|
293
|
+
cookie,
|
|
294
|
+
redirectContentOnNegotiate,
|
|
295
|
+
catalogs
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
var DEFAULT_LOCALE = "en-US", DEFAULT_LOCALES_DIR = "locales", DEFAULT_COOKIE = "reroute-locale";
|
|
299
|
+
var init_discover = () => {};
|
|
300
|
+
|
|
301
|
+
// packages/core/src/i18n/messages.ts
|
|
302
|
+
import { IntlMessageFormat } from "intl-messageformat";
|
|
303
|
+
function formatMessage(message, locale, values) {
|
|
304
|
+
if (!values || Object.keys(values).length === 0) {
|
|
305
|
+
if (!/\{[^}]+\}/.test(message))
|
|
306
|
+
return message;
|
|
307
|
+
}
|
|
308
|
+
const cacheKey = `${locale}\x00${message}`;
|
|
309
|
+
let formatter = formatterCache.get(cacheKey);
|
|
310
|
+
if (!formatter) {
|
|
311
|
+
formatter = new IntlMessageFormat(message, locale);
|
|
312
|
+
formatterCache.set(cacheKey, formatter);
|
|
313
|
+
}
|
|
314
|
+
try {
|
|
315
|
+
const result = formatter.format(values);
|
|
316
|
+
return typeof result === "string" ? result : String(result);
|
|
317
|
+
} catch {
|
|
318
|
+
return message;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
function createTranslator(catalogs, locale, defaultLocale) {
|
|
322
|
+
return (key, values) => {
|
|
323
|
+
const message = lookupMessage(catalogs, locale, defaultLocale, key);
|
|
324
|
+
if (message == null)
|
|
325
|
+
return key;
|
|
326
|
+
return formatMessage(message, locale, values);
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
var formatterCache;
|
|
330
|
+
var init_messages = __esm(() => {
|
|
331
|
+
init_catalog();
|
|
332
|
+
formatterCache = new Map;
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
// packages/core/src/i18n/negotiate.ts
|
|
336
|
+
function negotiateLocale(acceptLanguage, availableLocales, defaultLocale) {
|
|
337
|
+
if (!availableLocales.length)
|
|
338
|
+
return defaultLocale;
|
|
339
|
+
if (!acceptLanguage)
|
|
340
|
+
return defaultLocale;
|
|
341
|
+
const availableLower = new Map(availableLocales.map((l) => [l.toLowerCase(), l]));
|
|
342
|
+
const byLang = new Map;
|
|
343
|
+
for (const locale of availableLocales) {
|
|
344
|
+
const lang = locale.split("-")[0].toLowerCase();
|
|
345
|
+
if (!byLang.has(lang))
|
|
346
|
+
byLang.set(lang, locale);
|
|
347
|
+
}
|
|
348
|
+
const ranges = acceptLanguage.split(",").map((part) => {
|
|
349
|
+
const [tag, ...params] = part.trim().split(";");
|
|
350
|
+
let q = 1;
|
|
351
|
+
for (const p of params) {
|
|
352
|
+
const [k, v] = p.trim().split("=");
|
|
353
|
+
if (k === "q" && v)
|
|
354
|
+
q = Number.parseFloat(v) || 0;
|
|
355
|
+
}
|
|
356
|
+
return { tag: tag.trim().toLowerCase(), q };
|
|
357
|
+
}).filter((r) => r.tag && r.q > 0).sort((a, b) => b.q - a.q);
|
|
358
|
+
for (const { tag } of ranges) {
|
|
359
|
+
if (tag === "*")
|
|
360
|
+
return defaultLocale;
|
|
361
|
+
const exact = availableLower.get(tag);
|
|
362
|
+
if (exact)
|
|
363
|
+
return exact;
|
|
364
|
+
const langOnly = byLang.get(tag.split("-")[0]);
|
|
365
|
+
if (langOnly)
|
|
366
|
+
return langOnly;
|
|
367
|
+
}
|
|
368
|
+
return defaultLocale;
|
|
369
|
+
}
|
|
370
|
+
function parseCookieValue(cookieHeader, name) {
|
|
371
|
+
if (!cookieHeader)
|
|
372
|
+
return;
|
|
373
|
+
const parts = cookieHeader.split(";");
|
|
374
|
+
for (const part of parts) {
|
|
375
|
+
const idx = part.indexOf("=");
|
|
376
|
+
if (idx === -1)
|
|
377
|
+
continue;
|
|
378
|
+
const key = part.slice(0, idx).trim();
|
|
379
|
+
if (key === name) {
|
|
380
|
+
return decodeURIComponent(part.slice(idx + 1).trim());
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
function buildLocaleCookie(name, locale, maxAgeSeconds = 60 * 60 * 24 * 365) {
|
|
386
|
+
return `${name}=${encodeURIComponent(locale)}; Path=/; Max-Age=${maxAgeSeconds}; SameSite=Lax`;
|
|
387
|
+
}
|
|
388
|
+
var init_negotiate = () => {};
|
|
389
|
+
|
|
390
|
+
// packages/core/src/i18n/pathname.ts
|
|
391
|
+
var exports_pathname = {};
|
|
392
|
+
__export(exports_pathname, {
|
|
393
|
+
toOgLocale: () => toOgLocale,
|
|
394
|
+
parseContentPath: () => parseContentPath,
|
|
395
|
+
normalizePathname: () => normalizePathname,
|
|
396
|
+
looksLikeLocale: () => looksLikeLocale,
|
|
397
|
+
localizeHref: () => localizeHref,
|
|
398
|
+
localizeContentHref: () => localizeContentHref,
|
|
399
|
+
hreflangTags: () => hreflangTags,
|
|
400
|
+
contentKey: () => contentKey
|
|
401
|
+
});
|
|
402
|
+
function looksLikeLocale(segment) {
|
|
403
|
+
return /^[a-z]{2}(?:-[A-Za-z0-9]{2,8})*$/i.test(segment);
|
|
404
|
+
}
|
|
405
|
+
function normalizePathname(pathname) {
|
|
406
|
+
const pathOnly = pathname.split("?")[0].split("#")[0];
|
|
407
|
+
if (!pathOnly || pathOnly === "/")
|
|
408
|
+
return "/";
|
|
409
|
+
return pathOnly.startsWith("/") ? pathOnly : `/${pathOnly}`;
|
|
410
|
+
}
|
|
411
|
+
function parseContentPath(pathname, availableLocales = [], collections) {
|
|
412
|
+
const normalized = normalizePathname(pathname);
|
|
413
|
+
const parts = normalized.split("/").filter(Boolean);
|
|
414
|
+
if (parts.length < 2)
|
|
415
|
+
return;
|
|
416
|
+
const [collection, second, third] = parts;
|
|
417
|
+
if (collections && !collections.includes(collection)) {
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
const localeSet = new Set(availableLocales.map((l) => l.toLowerCase()));
|
|
421
|
+
if (parts.length >= 3 && third) {
|
|
422
|
+
const secondIsLocale = localeSet.size > 0 ? localeSet.has(second.toLowerCase()) : looksLikeLocale(second);
|
|
423
|
+
if (secondIsLocale) {
|
|
424
|
+
const locale = availableLocales.find((l) => l.toLowerCase() === second.toLowerCase()) || second;
|
|
425
|
+
return {
|
|
426
|
+
collection,
|
|
427
|
+
name: third,
|
|
428
|
+
locale,
|
|
429
|
+
routingPathname: `/${collection}/${third}`,
|
|
430
|
+
pathname: normalized
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
return {
|
|
435
|
+
collection,
|
|
436
|
+
name: second,
|
|
437
|
+
routingPathname: `/${collection}/${second}`,
|
|
438
|
+
pathname: normalized
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
function localizeContentHref(collection, name, locale, defaultLocale) {
|
|
442
|
+
if (!locale || locale === defaultLocale) {
|
|
443
|
+
return `/${collection}/${name}`;
|
|
444
|
+
}
|
|
445
|
+
return `/${collection}/${locale}/${name}`;
|
|
446
|
+
}
|
|
447
|
+
function localizeHref(to, locale, defaultLocale, availableLocales = [], collections) {
|
|
448
|
+
try {
|
|
449
|
+
const url = new URL(to, "http://local");
|
|
450
|
+
const parsed = parseContentPath(url.pathname, availableLocales, collections);
|
|
451
|
+
if (!parsed)
|
|
452
|
+
return to;
|
|
453
|
+
url.pathname = localizeContentHref(parsed.collection, parsed.name, locale, defaultLocale);
|
|
454
|
+
return `${url.pathname}${url.search}${url.hash}`;
|
|
455
|
+
} catch {
|
|
456
|
+
return to;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
function contentKey(collection, name, locale, defaultLocale = "en-US") {
|
|
460
|
+
if (locale && locale !== defaultLocale) {
|
|
461
|
+
return `${collection}:${name}:${locale}`;
|
|
462
|
+
}
|
|
463
|
+
return `${collection}:${name}`;
|
|
464
|
+
}
|
|
465
|
+
function toOgLocale(locale) {
|
|
466
|
+
return locale.replace(/-/g, "_");
|
|
467
|
+
}
|
|
468
|
+
function hreflangTags(baseUrl, collection, name, locales, defaultLocale) {
|
|
469
|
+
const base = baseUrl.replace(/\/$/, "");
|
|
470
|
+
const tags = [];
|
|
471
|
+
for (const locale of locales) {
|
|
472
|
+
const path = localizeContentHref(collection, name, locale, defaultLocale);
|
|
473
|
+
tags.push(`<link rel="alternate" hreflang="${locale}" href="${base}${path}" />`);
|
|
474
|
+
}
|
|
475
|
+
const defaultPath = localizeContentHref(collection, name, defaultLocale, defaultLocale);
|
|
476
|
+
tags.push(`<link rel="alternate" hreflang="x-default" href="${base}${defaultPath}" />`);
|
|
477
|
+
return tags.join(`
|
|
478
|
+
`);
|
|
479
|
+
}
|
|
480
|
+
var init_pathname = () => {};
|
|
481
|
+
|
|
482
|
+
// packages/core/src/i18n/resolve.ts
|
|
483
|
+
function resolveLocale(input) {
|
|
484
|
+
const {
|
|
485
|
+
pathname,
|
|
486
|
+
cookieHeader,
|
|
487
|
+
acceptLanguage,
|
|
488
|
+
availableLocales,
|
|
489
|
+
defaultLocale,
|
|
490
|
+
cookieName = DEFAULT_COOKIE,
|
|
491
|
+
collections
|
|
492
|
+
} = input;
|
|
493
|
+
const parsed = parseContentPath(pathname, availableLocales, collections);
|
|
494
|
+
const availableLower = new Set(availableLocales.map((l) => l.toLowerCase()));
|
|
495
|
+
const isAvailable = (locale) => !!locale && availableLower.has(locale.toLowerCase());
|
|
496
|
+
if (parsed?.locale && isAvailable(parsed.locale)) {
|
|
497
|
+
const locale = availableLocales.find((l) => l.toLowerCase() === parsed.locale?.toLowerCase()) || parsed.locale;
|
|
498
|
+
if (locale === defaultLocale && parsed.pathname !== parsed.routingPathname) {
|
|
499
|
+
return {
|
|
500
|
+
locale,
|
|
501
|
+
routingPathname: parsed.routingPathname,
|
|
502
|
+
fromPath: true,
|
|
503
|
+
redirectTo: parsed.routingPathname,
|
|
504
|
+
parsed: { ...parsed, locale }
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
return {
|
|
508
|
+
locale,
|
|
509
|
+
routingPathname: parsed.routingPathname,
|
|
510
|
+
fromPath: true,
|
|
511
|
+
parsed: { ...parsed, locale }
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
const routingPathname = parsed?.routingPathname ?? pathname.split("?")[0];
|
|
515
|
+
const cookieLocale = parseCookieValue(cookieHeader, cookieName);
|
|
516
|
+
if (isAvailable(cookieLocale)) {
|
|
517
|
+
const locale = availableLocales.find((l) => l.toLowerCase() === cookieLocale.toLowerCase()) || cookieLocale;
|
|
518
|
+
return {
|
|
519
|
+
locale,
|
|
520
|
+
routingPathname,
|
|
521
|
+
fromPath: false,
|
|
522
|
+
parsed: parsed ? { ...parsed, locale: undefined } : undefined
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
const negotiated = negotiateLocale(acceptLanguage, availableLocales, defaultLocale);
|
|
526
|
+
return {
|
|
527
|
+
locale: negotiated,
|
|
528
|
+
routingPathname,
|
|
529
|
+
fromPath: false,
|
|
530
|
+
parsed: parsed ? { ...parsed, locale: undefined } : undefined
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
function contentNegotiateRedirect(resolution, defaultLocale, enabled) {
|
|
534
|
+
if (!enabled)
|
|
535
|
+
return;
|
|
536
|
+
if (resolution.fromPath)
|
|
537
|
+
return;
|
|
538
|
+
if (resolution.locale === defaultLocale)
|
|
539
|
+
return;
|
|
540
|
+
const parsed = resolution.parsed;
|
|
541
|
+
if (!parsed)
|
|
542
|
+
return;
|
|
543
|
+
return localizeContentHref(parsed.collection, parsed.name, resolution.locale, defaultLocale);
|
|
544
|
+
}
|
|
545
|
+
var init_resolve = __esm(() => {
|
|
546
|
+
init_discover();
|
|
547
|
+
init_negotiate();
|
|
548
|
+
init_pathname();
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
// packages/core/src/i18n/index.ts
|
|
552
|
+
var init_i18n = __esm(() => {
|
|
553
|
+
init_catalog();
|
|
554
|
+
init_discover();
|
|
555
|
+
init_messages();
|
|
556
|
+
init_negotiate();
|
|
557
|
+
init_pathname();
|
|
558
|
+
init_resolve();
|
|
559
|
+
});
|
|
560
|
+
|
|
199
561
|
// packages/telemetry/src/server/context.ts
|
|
200
562
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
201
563
|
var contextStorage;
|
|
@@ -790,6 +1152,148 @@ function compressStreamIfAccepted(stream, contentType, _acceptEncoding) {
|
|
|
790
1152
|
}
|
|
791
1153
|
var init_compression = () => {};
|
|
792
1154
|
|
|
1155
|
+
// packages/core/src/ssr/lib/route-match.ts
|
|
1156
|
+
function getPatternParts(pattern) {
|
|
1157
|
+
return pattern.split("/").filter(Boolean);
|
|
1158
|
+
}
|
|
1159
|
+
function isDynamicPatternPart(patternPart) {
|
|
1160
|
+
return patternPart.startsWith(":");
|
|
1161
|
+
}
|
|
1162
|
+
function isCatchAllPatternPart(patternPart) {
|
|
1163
|
+
return patternPart.startsWith(":...");
|
|
1164
|
+
}
|
|
1165
|
+
function isCatchAllParamName(paramName) {
|
|
1166
|
+
return paramName.startsWith("...");
|
|
1167
|
+
}
|
|
1168
|
+
function getPatternPartSpecificity(patternPart) {
|
|
1169
|
+
if (isCatchAllPatternPart(patternPart)) {
|
|
1170
|
+
return 2;
|
|
1171
|
+
}
|
|
1172
|
+
if (isDynamicPatternPart(patternPart)) {
|
|
1173
|
+
return 1;
|
|
1174
|
+
}
|
|
1175
|
+
return 0;
|
|
1176
|
+
}
|
|
1177
|
+
function compareRouteSpecificity(a, b) {
|
|
1178
|
+
const aPatternParts = getPatternParts(a.pattern);
|
|
1179
|
+
const bPatternParts = getPatternParts(b.pattern);
|
|
1180
|
+
const aDepth = aPatternParts.length;
|
|
1181
|
+
const bDepth = bPatternParts.length;
|
|
1182
|
+
if (aDepth !== bDepth) {
|
|
1183
|
+
return bDepth - aDepth;
|
|
1184
|
+
}
|
|
1185
|
+
for (let i = 0;i < aPatternParts.length; i++) {
|
|
1186
|
+
const aSpecificity = getPatternPartSpecificity(aPatternParts[i]);
|
|
1187
|
+
const bSpecificity = getPatternPartSpecificity(bPatternParts[i]);
|
|
1188
|
+
if (aSpecificity !== bSpecificity) {
|
|
1189
|
+
return aSpecificity - bSpecificity;
|
|
1190
|
+
}
|
|
1191
|
+
if (aSpecificity === 0 && aPatternParts[i] !== bPatternParts[i]) {
|
|
1192
|
+
return aPatternParts[i].localeCompare(bPatternParts[i]);
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
return a.pattern.localeCompare(b.pattern);
|
|
1196
|
+
}
|
|
1197
|
+
function matchCatchAllParam(paramName, patternIndex, patternLength, pathnameParts, pathnameIndex, params) {
|
|
1198
|
+
if (patternIndex !== patternLength - 1 || pathnameIndex >= pathnameParts.length) {
|
|
1199
|
+
return false;
|
|
1200
|
+
}
|
|
1201
|
+
params[paramName.slice(3)] = pathnameParts.slice(pathnameIndex).join("/");
|
|
1202
|
+
return true;
|
|
1203
|
+
}
|
|
1204
|
+
function matchDynamicParam(paramName, pathnameParts, pathnameIndex, params) {
|
|
1205
|
+
const pathnamePart = pathnameParts[pathnameIndex];
|
|
1206
|
+
if (pathnamePart === undefined) {
|
|
1207
|
+
return null;
|
|
1208
|
+
}
|
|
1209
|
+
params[paramName] = pathnamePart;
|
|
1210
|
+
return pathnameIndex + 1;
|
|
1211
|
+
}
|
|
1212
|
+
function matchPatternPart(patternPart, patternIndex, patternLength, pathnameParts, pathnameIndex, params) {
|
|
1213
|
+
if (isDynamicPatternPart(patternPart)) {
|
|
1214
|
+
const paramName = patternPart.slice(1);
|
|
1215
|
+
if (isCatchAllParamName(paramName)) {
|
|
1216
|
+
return matchCatchAllParam(paramName, patternIndex, patternLength, pathnameParts, pathnameIndex, params) ? "catch-all" : null;
|
|
1217
|
+
}
|
|
1218
|
+
return matchDynamicParam(paramName, pathnameParts, pathnameIndex, params);
|
|
1219
|
+
}
|
|
1220
|
+
if (patternPart !== pathnameParts[pathnameIndex]) {
|
|
1221
|
+
return null;
|
|
1222
|
+
}
|
|
1223
|
+
return pathnameIndex + 1;
|
|
1224
|
+
}
|
|
1225
|
+
function matchRoutePattern(pattern, pathname) {
|
|
1226
|
+
const patternParts = getPatternParts(pattern);
|
|
1227
|
+
const pathnameParts = pathname.split("/").filter(Boolean);
|
|
1228
|
+
const params = {};
|
|
1229
|
+
let pathnameIndex = 0;
|
|
1230
|
+
for (let i = 0;i < patternParts.length; i++) {
|
|
1231
|
+
const nextPathnameIndex = matchPatternPart(patternParts[i], i, patternParts.length, pathnameParts, pathnameIndex, params);
|
|
1232
|
+
if (nextPathnameIndex === null) {
|
|
1233
|
+
return null;
|
|
1234
|
+
}
|
|
1235
|
+
if (nextPathnameIndex === "catch-all") {
|
|
1236
|
+
return params;
|
|
1237
|
+
}
|
|
1238
|
+
pathnameIndex = nextPathnameIndex;
|
|
1239
|
+
}
|
|
1240
|
+
return pathnameIndex === pathnameParts.length ? params : null;
|
|
1241
|
+
}
|
|
1242
|
+
function matchRoutes(routes, pathname) {
|
|
1243
|
+
for (const route of routes) {
|
|
1244
|
+
const params = matchRoutePattern(route.pattern, pathname);
|
|
1245
|
+
if (params) {
|
|
1246
|
+
return { route, params };
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
return null;
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
// packages/core/src/ssr/lib/content-path.ts
|
|
1253
|
+
var exports_content_path = {};
|
|
1254
|
+
__export(exports_content_path, {
|
|
1255
|
+
resolveContentPathParts: () => resolveContentPathParts
|
|
1256
|
+
});
|
|
1257
|
+
function resolveContentPathParts(pathname) {
|
|
1258
|
+
const pathOnly = pathname.split("?")[0].split("#")[0];
|
|
1259
|
+
const parts = pathOnly.split("/").filter(Boolean);
|
|
1260
|
+
if (parts.length < 2)
|
|
1261
|
+
return null;
|
|
1262
|
+
const g = globalThis;
|
|
1263
|
+
const locales = g.__REROUTE_I18N__?.locales || [];
|
|
1264
|
+
const defaultLocale = g.__REROUTE_I18N__?.defaultLocale || "en-US";
|
|
1265
|
+
const parsed = parseContentPath(pathOnly, locales);
|
|
1266
|
+
if (parsed) {
|
|
1267
|
+
const locale = parsed.locale || defaultLocale;
|
|
1268
|
+
return {
|
|
1269
|
+
collection: parsed.collection,
|
|
1270
|
+
name: parsed.name,
|
|
1271
|
+
locale: parsed.locale,
|
|
1272
|
+
key: contentKey(parsed.collection, parsed.name, locale, defaultLocale),
|
|
1273
|
+
routingPathname: parsed.routingPathname
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
if (parts.length >= 3 && looksLikeLocale(parts[1])) {
|
|
1277
|
+
const locale = parts[1];
|
|
1278
|
+
return {
|
|
1279
|
+
collection: parts[0],
|
|
1280
|
+
name: parts[2],
|
|
1281
|
+
locale,
|
|
1282
|
+
key: contentKey(parts[0], parts[2], locale, defaultLocale),
|
|
1283
|
+
routingPathname: `/${parts[0]}/${parts[2]}`
|
|
1284
|
+
};
|
|
1285
|
+
}
|
|
1286
|
+
return {
|
|
1287
|
+
collection: parts[0],
|
|
1288
|
+
name: parts[1],
|
|
1289
|
+
key: `${parts[0]}:${parts[1]}`,
|
|
1290
|
+
routingPathname: `/${parts[0]}/${parts[1]}`
|
|
1291
|
+
};
|
|
1292
|
+
}
|
|
1293
|
+
var init_content_path = __esm(() => {
|
|
1294
|
+
init_pathname();
|
|
1295
|
+
});
|
|
1296
|
+
|
|
793
1297
|
// packages/core/src/ssr/lib/compute/content.ts
|
|
794
1298
|
function checkStatusCache(statusCacheKey, maxAgeMs) {
|
|
795
1299
|
if (maxAgeMs <= 0)
|
|
@@ -842,6 +1346,14 @@ async function handleNonStreamingMode(ssrData, pathname, task, cacheKey, statusC
|
|
|
842
1346
|
}
|
|
843
1347
|
return result;
|
|
844
1348
|
}
|
|
1349
|
+
async function runContentDataTask(streaming, ssrData, pathname, task, set, cacheKey, statusCacheKey, maxAgeMs, pendingTasks) {
|
|
1350
|
+
if (streaming) {
|
|
1351
|
+
handleStreamingMode(ssrData, pathname, task, set, cacheKey, statusCacheKey, maxAgeMs, pendingTasks);
|
|
1352
|
+
} else {
|
|
1353
|
+
await handleNonStreamingMode(ssrData, pathname, task, cacheKey, statusCacheKey, maxAgeMs);
|
|
1354
|
+
}
|
|
1355
|
+
return set.status !== 200 ? set.status : undefined;
|
|
1356
|
+
}
|
|
845
1357
|
async function computeContentData(pathname, options, searchParams, sharedSsrData) {
|
|
846
1358
|
const streaming = options.streaming === true;
|
|
847
1359
|
const ssrData = streaming && sharedSsrData ? sharedSsrData : {};
|
|
@@ -851,18 +1363,20 @@ async function computeContentData(pathname, options, searchParams, sharedSsrData
|
|
|
851
1363
|
const maxAge = options.maxAge || 0;
|
|
852
1364
|
const maxAgeMs = maxAge * 1000;
|
|
853
1365
|
try {
|
|
854
|
-
const
|
|
855
|
-
if (
|
|
1366
|
+
const resolved = resolveContentPathParts(pathname);
|
|
1367
|
+
if (!resolved) {
|
|
856
1368
|
return { data: ssrData, pendingTasks };
|
|
857
1369
|
}
|
|
1370
|
+
const parts = [resolved.collection, resolved.name];
|
|
1371
|
+
if (resolved.locale)
|
|
1372
|
+
parts.splice(1, 0, resolved.locale);
|
|
858
1373
|
const g = globalThis;
|
|
859
|
-
const
|
|
860
|
-
const exp = g.__REROUTE_SSR_EXPORTS__?.[key];
|
|
1374
|
+
const exp = g.__REROUTE_SSR_EXPORTS__?.[resolved.key];
|
|
861
1375
|
const dataFn = exp?.ssr?.data;
|
|
862
1376
|
if (typeof dataFn !== "function") {
|
|
863
1377
|
return { data: ssrData, pendingTasks };
|
|
864
1378
|
}
|
|
865
|
-
const cacheKey = `content:${pathname}:${
|
|
1379
|
+
const cacheKey = `content:${pathname}:${resolved.name}:${resolved.locale || ""}`;
|
|
866
1380
|
const statusCacheKey = `status:${cacheKey}`;
|
|
867
1381
|
const cachedStatus = checkStatusCache(statusCacheKey, maxAgeMs);
|
|
868
1382
|
if (cachedStatus && cachedStatus !== 200) {
|
|
@@ -875,22 +1389,13 @@ async function computeContentData(pathname, options, searchParams, sharedSsrData
|
|
|
875
1389
|
}
|
|
876
1390
|
const set = { status: 200 };
|
|
877
1391
|
const task = createDataTask(dataFn, pathname, parts, searchParams, set, options.headers);
|
|
878
|
-
|
|
879
|
-
handleStreamingMode(ssrData, pathname, task, set, cacheKey, statusCacheKey, maxAgeMs, pendingTasks);
|
|
880
|
-
if (set.status !== 200) {
|
|
881
|
-
statusOverride = set.status;
|
|
882
|
-
}
|
|
883
|
-
} else {
|
|
884
|
-
await handleNonStreamingMode(ssrData, pathname, task, cacheKey, statusCacheKey, maxAgeMs);
|
|
885
|
-
if (set.status !== 200) {
|
|
886
|
-
statusOverride = set.status;
|
|
887
|
-
}
|
|
888
|
-
}
|
|
1392
|
+
statusOverride = await runContentDataTask(streaming, ssrData, pathname, task, set, cacheKey, statusCacheKey, maxAgeMs, pendingTasks) ?? statusOverride;
|
|
889
1393
|
} catch {}
|
|
890
1394
|
return { data: ssrData, error, statusOverride, pendingTasks };
|
|
891
1395
|
}
|
|
892
1396
|
var init_content2 = __esm(() => {
|
|
893
1397
|
init_cache();
|
|
1398
|
+
init_content_path();
|
|
894
1399
|
init_imports();
|
|
895
1400
|
});
|
|
896
1401
|
|
|
@@ -1089,7 +1594,8 @@ async function computeRouteData(pathname, clientDir, _cwd, isWatchMode, options,
|
|
|
1089
1594
|
}).catch(() => {}));
|
|
1090
1595
|
};
|
|
1091
1596
|
try {
|
|
1092
|
-
const
|
|
1597
|
+
const resolved = resolveContentPathParts(pathname);
|
|
1598
|
+
const pathnameOnly = (resolved?.routingPathname || pathname).split("?")[0];
|
|
1093
1599
|
const match = typeof routesModule?.matchRoute === "function" ? routesModule.matchRoute(pathnameOnly) : null;
|
|
1094
1600
|
const route = match?.route;
|
|
1095
1601
|
const params = match?.params || {};
|
|
@@ -1252,44 +1758,18 @@ function handleFlattenedResult(entries, set, ctx, cache, setError, setStatus) {
|
|
|
1252
1758
|
}
|
|
1253
1759
|
var init_routes = __esm(() => {
|
|
1254
1760
|
init_cache();
|
|
1761
|
+
init_content_path();
|
|
1255
1762
|
init_imports();
|
|
1256
1763
|
});
|
|
1257
1764
|
|
|
1258
1765
|
// packages/core/src/ssr/lib/compute/index.ts
|
|
1259
|
-
function matchPatternUtil(pattern, pathname) {
|
|
1260
|
-
const patternParts = pattern.split("/").filter(Boolean);
|
|
1261
|
-
const pathnameParts = pathname.split("/").filter(Boolean);
|
|
1262
|
-
if (patternParts.length !== pathnameParts.length) {
|
|
1263
|
-
return null;
|
|
1264
|
-
}
|
|
1265
|
-
const params = {};
|
|
1266
|
-
for (let i = 0;i < patternParts.length; i++) {
|
|
1267
|
-
const patternPart = patternParts[i];
|
|
1268
|
-
const pathnamePart = pathnameParts[i];
|
|
1269
|
-
if (patternPart.startsWith(":")) {
|
|
1270
|
-
params[patternPart.slice(1)] = pathnamePart;
|
|
1271
|
-
} else if (patternPart !== pathnamePart) {
|
|
1272
|
-
return null;
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
return params;
|
|
1276
|
-
}
|
|
1277
1766
|
function createBundledRoutesModule(bundledRoutes, bundledLayouts) {
|
|
1278
1767
|
const bundledNotFoundRoutes = globalThis.__REROUTE_NOT_FOUND_ROUTES__;
|
|
1279
1768
|
return {
|
|
1280
1769
|
routes: bundledRoutes,
|
|
1281
1770
|
layouts: bundledLayouts,
|
|
1282
1771
|
notFoundRoutes: bundledNotFoundRoutes,
|
|
1283
|
-
matchRoute: (pathname) =>
|
|
1284
|
-
for (const route of bundledRoutes) {
|
|
1285
|
-
const pattern = String(route?.pattern || "");
|
|
1286
|
-
const match = matchPatternUtil(pattern, pathname);
|
|
1287
|
-
if (match) {
|
|
1288
|
-
return { route, params: match };
|
|
1289
|
-
}
|
|
1290
|
-
}
|
|
1291
|
-
return null;
|
|
1292
|
-
}
|
|
1772
|
+
matchRoute: (pathname) => matchRoutes(bundledRoutes, pathname)
|
|
1293
1773
|
};
|
|
1294
1774
|
}
|
|
1295
1775
|
async function loadRoutesModule(cwd, isWatchMode) {
|
|
@@ -1371,33 +1851,31 @@ var init_compute = __esm(() => {
|
|
|
1371
1851
|
});
|
|
1372
1852
|
|
|
1373
1853
|
// packages/core/src/ssr/lib/modules.ts
|
|
1374
|
-
import { readdir as
|
|
1854
|
+
import { readdir as readdir3, stat as stat3 } from "node:fs/promises";
|
|
1375
1855
|
async function importContentModuleForPath(pathname, clientDir, cwd, isWatchMode) {
|
|
1376
1856
|
try {
|
|
1377
|
-
const
|
|
1378
|
-
|
|
1379
|
-
if (parts.length < 2)
|
|
1857
|
+
const resolved = resolveContentPathParts(pathname);
|
|
1858
|
+
if (!resolved)
|
|
1380
1859
|
return null;
|
|
1381
|
-
const collection =
|
|
1382
|
-
const
|
|
1383
|
-
const registryModule = await tryRegistryImport(collection, name, cwd, isWatchMode);
|
|
1860
|
+
const { collection, name, locale } = resolved;
|
|
1861
|
+
const registryModule = await tryRegistryImport(collection, name, cwd, isWatchMode, locale);
|
|
1384
1862
|
if (registryModule)
|
|
1385
1863
|
return registryModule;
|
|
1386
1864
|
const chunkModule = await tryChunkImport(collection, name, cwd, isWatchMode);
|
|
1387
1865
|
if (chunkModule)
|
|
1388
1866
|
return chunkModule;
|
|
1389
|
-
const sourceModule = await trySourceImport(collection, name, clientDir, isWatchMode);
|
|
1867
|
+
const sourceModule = await trySourceImport(collection, name, clientDir, isWatchMode, locale);
|
|
1390
1868
|
if (sourceModule)
|
|
1391
1869
|
return sourceModule;
|
|
1392
1870
|
} catch {}
|
|
1393
1871
|
return null;
|
|
1394
1872
|
}
|
|
1395
|
-
async function tryRegistryImport(collection, name, cwd, isWatchMode) {
|
|
1873
|
+
async function tryRegistryImport(collection, name, cwd, isWatchMode, locale) {
|
|
1396
1874
|
try {
|
|
1397
1875
|
const registryPath = join(cwd, ".reroute", "content.ts");
|
|
1398
1876
|
const reg = await dynamicImport(registryPath, isWatchMode);
|
|
1399
1877
|
const get = reg?.getContentEntry;
|
|
1400
|
-
const entry = typeof get === "function" ? get(collection, name) : undefined;
|
|
1878
|
+
const entry = typeof get === "function" ? get(collection, name, locale) : undefined;
|
|
1401
1879
|
const moduleUrl = entry?.module;
|
|
1402
1880
|
if (!moduleUrl?.endsWith(".js"))
|
|
1403
1881
|
return null;
|
|
@@ -1423,7 +1901,7 @@ async function tryRegistryImport(collection, name, cwd, isWatchMode) {
|
|
|
1423
1901
|
async function tryChunkImport(collection, name, cwd, isWatchMode) {
|
|
1424
1902
|
try {
|
|
1425
1903
|
const chunkDir = join(cwd, ".reroute", "chunks", collection);
|
|
1426
|
-
const files = await
|
|
1904
|
+
const files = await readdir3(chunkDir);
|
|
1427
1905
|
const matches = files.filter((n) => n.startsWith(`${name}.`) && n.endsWith(".js"));
|
|
1428
1906
|
if (!matches.length)
|
|
1429
1907
|
return null;
|
|
@@ -1443,23 +1921,23 @@ async function tryChunkImport(collection, name, cwd, isWatchMode) {
|
|
|
1443
1921
|
} catch {}
|
|
1444
1922
|
return null;
|
|
1445
1923
|
}
|
|
1446
|
-
async function trySourceImport(collection, name, clientDir, isWatchMode) {
|
|
1924
|
+
async function trySourceImport(collection, name, clientDir, isWatchMode, locale) {
|
|
1447
1925
|
try {
|
|
1448
|
-
const
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
if (await Bun.file(srcTsx).exists()) {
|
|
1452
|
-
absSrc = srcTsx;
|
|
1453
|
-
} else if (await Bun.file(srcTs).exists()) {
|
|
1454
|
-
absSrc = srcTs;
|
|
1926
|
+
const candidates = [];
|
|
1927
|
+
if (locale) {
|
|
1928
|
+
candidates.push(join(clientDir, "routes", collection, "content", locale, `${name}.tsx`), join(clientDir, "routes", collection, "content", locale, `${name}.ts`));
|
|
1455
1929
|
}
|
|
1456
|
-
|
|
1457
|
-
|
|
1930
|
+
candidates.push(join(clientDir, "routes", collection, "content", `${name}.tsx`), join(clientDir, "routes", collection, "content", `${name}.ts`));
|
|
1931
|
+
for (const absSrc of candidates) {
|
|
1932
|
+
if (await Bun.file(absSrc).exists()) {
|
|
1933
|
+
return await dynamicImport(absSrc, isWatchMode);
|
|
1934
|
+
}
|
|
1458
1935
|
}
|
|
1459
1936
|
} catch {}
|
|
1460
1937
|
return null;
|
|
1461
1938
|
}
|
|
1462
1939
|
var init_modules = __esm(() => {
|
|
1940
|
+
init_content_path();
|
|
1463
1941
|
init_imports();
|
|
1464
1942
|
});
|
|
1465
1943
|
|
|
@@ -1490,14 +1968,11 @@ function touchModule(key) {
|
|
|
1490
1968
|
}
|
|
1491
1969
|
async function seedSSRModuleForPath(pathname, clientDir, cwd, isWatchMode) {
|
|
1492
1970
|
try {
|
|
1493
|
-
const
|
|
1494
|
-
|
|
1495
|
-
if (parts.length < 2) {
|
|
1971
|
+
const resolved = resolveContentPathParts(pathname);
|
|
1972
|
+
if (!resolved) {
|
|
1496
1973
|
return;
|
|
1497
1974
|
}
|
|
1498
|
-
const
|
|
1499
|
-
const name = parts[1];
|
|
1500
|
-
const key = `${collection}:${name}`;
|
|
1975
|
+
const { key } = resolved;
|
|
1501
1976
|
const mod = await importContentModuleForPath(pathname, clientDir, cwd, isWatchMode);
|
|
1502
1977
|
if (!mod) {
|
|
1503
1978
|
return;
|
|
@@ -1517,42 +1992,25 @@ async function seedSSRModuleForPath(pathname, clientDir, cwd, isWatchMode) {
|
|
|
1517
1992
|
}
|
|
1518
1993
|
var MAX_SSR_MODULES = 200, moduleAccessOrder;
|
|
1519
1994
|
var init_seed = __esm(() => {
|
|
1995
|
+
init_content_path();
|
|
1520
1996
|
init_modules();
|
|
1521
1997
|
moduleAccessOrder = [];
|
|
1522
1998
|
});
|
|
1523
1999
|
|
|
1524
2000
|
// packages/core/src/ssr/lib/data.ts
|
|
1525
|
-
function matchPattern(pattern, pathname) {
|
|
1526
|
-
const patternParts = pattern.split("/").filter(Boolean);
|
|
1527
|
-
const pathnameParts = pathname.split("/").filter(Boolean);
|
|
1528
|
-
if (patternParts.length !== pathnameParts.length) {
|
|
1529
|
-
return null;
|
|
1530
|
-
}
|
|
1531
|
-
const params = {};
|
|
1532
|
-
for (let i = 0;i < patternParts.length; i++) {
|
|
1533
|
-
const patternPart = patternParts[i];
|
|
1534
|
-
const pathnamePart = pathnameParts[i];
|
|
1535
|
-
if (patternPart.startsWith(":")) {
|
|
1536
|
-
params[patternPart.slice(1)] = pathnamePart;
|
|
1537
|
-
} else if (patternPart !== pathnamePart) {
|
|
1538
|
-
return null;
|
|
1539
|
-
}
|
|
1540
|
-
}
|
|
1541
|
-
return params;
|
|
1542
|
-
}
|
|
1543
2001
|
function loadContentData(pathname, searchParams) {
|
|
1544
2002
|
try {
|
|
1545
|
-
const
|
|
1546
|
-
if (
|
|
2003
|
+
const resolved = resolveContentPathParts(pathname);
|
|
2004
|
+
if (!resolved)
|
|
1547
2005
|
return null;
|
|
1548
|
-
const key =
|
|
2006
|
+
const key = resolved.key;
|
|
1549
2007
|
const g = globalThis;
|
|
1550
2008
|
const exp = g.__REROUTE_SSR_EXPORTS__?.[key];
|
|
1551
2009
|
const dataFn = exp?.ssr?.data;
|
|
1552
2010
|
if (typeof dataFn === "function") {
|
|
1553
2011
|
const rawResult = dataFn({
|
|
1554
2012
|
pathname,
|
|
1555
|
-
params: { name:
|
|
2013
|
+
params: { name: resolved.name },
|
|
1556
2014
|
searchParams
|
|
1557
2015
|
});
|
|
1558
2016
|
const result = processDataResult(rawResult, pathname, pathname);
|
|
@@ -1574,16 +2032,7 @@ async function loadRouteDataInternal(pathname, clientDir, cwd, isWatchMode, sear
|
|
|
1574
2032
|
routes = m?.routes;
|
|
1575
2033
|
matchRouteFn = m?.matchRoute;
|
|
1576
2034
|
} else {
|
|
1577
|
-
matchRouteFn = (pathname2) =>
|
|
1578
|
-
for (const route of routes || []) {
|
|
1579
|
-
const pattern = String(route?.pattern || "");
|
|
1580
|
-
const match2 = matchPattern(pattern, pathname2);
|
|
1581
|
-
if (match2) {
|
|
1582
|
-
return { route, params: match2 };
|
|
1583
|
-
}
|
|
1584
|
-
}
|
|
1585
|
-
return null;
|
|
1586
|
-
};
|
|
2035
|
+
matchRouteFn = (pathname2) => matchRoutes(routes || [], pathname2);
|
|
1587
2036
|
}
|
|
1588
2037
|
const pathnameOnly = pathname.split("?")[0];
|
|
1589
2038
|
const match = typeof matchRouteFn === "function" ? matchRouteFn(pathnameOnly) : null;
|
|
@@ -1724,6 +2173,7 @@ function createLazyMarker(pathname, key) {
|
|
|
1724
2173
|
};
|
|
1725
2174
|
}
|
|
1726
2175
|
var init_data = __esm(() => {
|
|
2176
|
+
init_content_path();
|
|
1727
2177
|
init_imports();
|
|
1728
2178
|
init_seed();
|
|
1729
2179
|
});
|
|
@@ -1924,18 +2374,53 @@ function replaceAppRoot(html, appHtml, appId) {
|
|
|
1924
2374
|
var init_html = () => {};
|
|
1925
2375
|
|
|
1926
2376
|
// packages/core/src/og/discovery.ts
|
|
2377
|
+
import { readdir as readdir4 } from "node:fs/promises";
|
|
1927
2378
|
import { pathToFileURL as pathToFileURL4 } from "node:url";
|
|
2379
|
+
function isCatchAllRouteDirectory(name) {
|
|
2380
|
+
return CATCH_ALL_ROUTE_DIRECTORY.test(name);
|
|
2381
|
+
}
|
|
2382
|
+
async function listDynamicRouteDirectories(baseDir) {
|
|
2383
|
+
try {
|
|
2384
|
+
const entries = await readdir4(baseDir, { withFileTypes: true });
|
|
2385
|
+
return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => DYNAMIC_ROUTE_DIRECTORY.test(name)).sort((a, b) => {
|
|
2386
|
+
const aIsCatchAll = isCatchAllRouteDirectory(a);
|
|
2387
|
+
const bIsCatchAll = isCatchAllRouteDirectory(b);
|
|
2388
|
+
if (aIsCatchAll !== bIsCatchAll) {
|
|
2389
|
+
return Number(aIsCatchAll) - Number(bIsCatchAll);
|
|
2390
|
+
}
|
|
2391
|
+
return a.localeCompare(b);
|
|
2392
|
+
});
|
|
2393
|
+
} catch {
|
|
2394
|
+
return [];
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
async function collectOGCandidatePaths(currentDir, parts, depth, pathsToTry, allowPartialFallback) {
|
|
2398
|
+
if (depth === parts.length) {
|
|
2399
|
+
pathsToTry.push(join(currentDir, "[og].tsx"));
|
|
2400
|
+
return;
|
|
2401
|
+
}
|
|
2402
|
+
const literalDir = join(currentDir, parts[depth]);
|
|
2403
|
+
try {
|
|
2404
|
+
await readdir4(literalDir);
|
|
2405
|
+
await collectOGCandidatePaths(literalDir, parts, depth + 1, pathsToTry, true);
|
|
2406
|
+
} catch {}
|
|
2407
|
+
const dynamicDirs = await listDynamicRouteDirectories(currentDir);
|
|
2408
|
+
for (const dynamicDir of dynamicDirs) {
|
|
2409
|
+
if (isCatchAllRouteDirectory(dynamicDir)) {
|
|
2410
|
+
pathsToTry.push(join(currentDir, dynamicDir, "[og].tsx"));
|
|
2411
|
+
continue;
|
|
2412
|
+
}
|
|
2413
|
+
await collectOGCandidatePaths(join(currentDir, dynamicDir), parts, depth + 1, pathsToTry, false);
|
|
2414
|
+
}
|
|
2415
|
+
if (allowPartialFallback) {
|
|
2416
|
+
pathsToTry.push(join(currentDir, "[og].tsx"));
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
1928
2419
|
async function findOGImageForPath(pathname, clientDir) {
|
|
1929
2420
|
const parts = pathname.split("/").filter(Boolean).filter((p) => !p.startsWith("__reroute"));
|
|
1930
2421
|
const routesDir = join(clientDir, "routes");
|
|
1931
2422
|
const pathsToTry = [];
|
|
1932
|
-
|
|
1933
|
-
for (let i = parts.length;i > 0; i--) {
|
|
1934
|
-
const dirPath = join(routesDir, ...parts.slice(0, i), "[og].tsx");
|
|
1935
|
-
pathsToTry.push(dirPath);
|
|
1936
|
-
}
|
|
1937
|
-
}
|
|
1938
|
-
pathsToTry.push(join(routesDir, "[og].tsx"));
|
|
2423
|
+
await collectOGCandidatePaths(routesDir, parts, 0, pathsToTry, true);
|
|
1939
2424
|
const uniquePaths = [...new Set(pathsToTry)];
|
|
1940
2425
|
for (const path of uniquePaths) {
|
|
1941
2426
|
try {
|
|
@@ -1959,28 +2444,28 @@ async function loadOGImageComponent(ogPath, isWatchMode) {
|
|
|
1959
2444
|
function extractParamsFromPath(pathname, ogPath, clientDir) {
|
|
1960
2445
|
const params = {};
|
|
1961
2446
|
const ogDir = ogPath.replace(/\/\[og\]\.tsx$/, "");
|
|
1962
|
-
const
|
|
1963
|
-
const relativePath = ogDir.replace(
|
|
2447
|
+
const routesDir = join(clientDir, "routes");
|
|
2448
|
+
const relativePath = ogDir.replace(routesDir, "").split("/").filter(Boolean);
|
|
1964
2449
|
const pathnameParts = pathname.split("/").filter(Boolean);
|
|
1965
2450
|
for (let i = 0;i < relativePath.length && i < pathnameParts.length; i++) {
|
|
1966
2451
|
const part = relativePath[i];
|
|
1967
|
-
const
|
|
1968
|
-
if (
|
|
1969
|
-
|
|
1970
|
-
|
|
2452
|
+
const catchAllMatch = part.match(/^\[\.\.\.([^\]]+)\]$/);
|
|
2453
|
+
if (catchAllMatch) {
|
|
2454
|
+
params[catchAllMatch[1]] = pathnameParts.slice(i).join("/");
|
|
2455
|
+
break;
|
|
1971
2456
|
}
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
const match = lastRelativePart.match(/^\[([^\]]+)\]$/);
|
|
1976
|
-
if (match) {
|
|
1977
|
-
const paramName = match[1];
|
|
1978
|
-
params[paramName] = pathnameParts[relativePath.length - 1];
|
|
2457
|
+
const dynamicMatch = part.match(/^\[([^\]]+)\]$/);
|
|
2458
|
+
if (dynamicMatch) {
|
|
2459
|
+
params[dynamicMatch[1]] = pathnameParts[i];
|
|
1979
2460
|
}
|
|
1980
2461
|
}
|
|
1981
2462
|
return params;
|
|
1982
2463
|
}
|
|
1983
|
-
var
|
|
2464
|
+
var CATCH_ALL_ROUTE_DIRECTORY, DYNAMIC_ROUTE_DIRECTORY;
|
|
2465
|
+
var init_discovery2 = __esm(() => {
|
|
2466
|
+
CATCH_ALL_ROUTE_DIRECTORY = /^\[\.\.\.([^\]]+)\]$/;
|
|
2467
|
+
DYNAMIC_ROUTE_DIRECTORY = /^\[(?:\.\.\.)?[^\]]+\]$/;
|
|
2468
|
+
});
|
|
1984
2469
|
|
|
1985
2470
|
// packages/core/src/og/meta.ts
|
|
1986
2471
|
async function generateOGImageMetaTags(pathname, clientDir, ogConfig) {
|
|
@@ -2071,7 +2556,9 @@ async function extractPageMetadata(pathname, clientDir, cwd, isWatchMode, curren
|
|
|
2071
2556
|
let perPageHead = "";
|
|
2072
2557
|
let pageLang;
|
|
2073
2558
|
let statusOverride = currentStatusOverride;
|
|
2074
|
-
|
|
2559
|
+
const resolved = resolveContentPathParts(pathname);
|
|
2560
|
+
const routingPathname = resolved?.routingPathname || pathname;
|
|
2561
|
+
await extractLayoutMetadata(routingPathname, clientDir, cwd, isWatchMode, (head) => {
|
|
2075
2562
|
perPageHead += head;
|
|
2076
2563
|
}, (lang) => {
|
|
2077
2564
|
if (!pageLang)
|
|
@@ -2106,8 +2593,8 @@ ${ogMetaTags}`;
|
|
|
2106
2593
|
perPageHead += head;
|
|
2107
2594
|
}, (lang) => {
|
|
2108
2595
|
pageLang = lang;
|
|
2109
|
-
}, ogConfig, titleSuffix);
|
|
2110
|
-
const routeResult = await extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, statusOverride, ssrData, ogConfig, titleSuffix);
|
|
2596
|
+
}, ogConfig, titleSuffix, baseUrl);
|
|
2597
|
+
const routeResult = await extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, statusOverride, ssrData, ogConfig, titleSuffix, routingPathname);
|
|
2111
2598
|
perPageHead += routeResult.head;
|
|
2112
2599
|
if (routeResult.lang)
|
|
2113
2600
|
pageLang = routeResult.lang;
|
|
@@ -2147,14 +2634,42 @@ async function extractLayoutMetadata(pathname, clientDir, cwd, isWatchMode, addH
|
|
|
2147
2634
|
}
|
|
2148
2635
|
} catch {}
|
|
2149
2636
|
}
|
|
2150
|
-
function
|
|
2637
|
+
function resolveContentLocales(collection, name, fallbackLocales) {
|
|
2638
|
+
const g = globalThis;
|
|
2639
|
+
const byCollection = g.__REROUTE_COLLECTIONS__;
|
|
2640
|
+
const items = byCollection?.[collection] || [];
|
|
2641
|
+
const localesForEntry = [
|
|
2642
|
+
...new Set(items.filter((it) => it.name === name && it.locale).map((it) => String(it.locale)))
|
|
2643
|
+
];
|
|
2644
|
+
return localesForEntry.length > 0 ? localesForEntry : fallbackLocales;
|
|
2645
|
+
}
|
|
2646
|
+
function addContentI18nHead(addHead, baseUrl, collection, name, locales, defaultLocale, activeLocale) {
|
|
2647
|
+
if (locales.length > 1) {
|
|
2648
|
+
addHead(`
|
|
2649
|
+
${hreflangTags(baseUrl, collection, name, locales, defaultLocale)}`);
|
|
2650
|
+
}
|
|
2651
|
+
addHead(`
|
|
2652
|
+
<meta property="og:locale" content="${toOgLocale(activeLocale)}" />`);
|
|
2653
|
+
for (const loc of locales) {
|
|
2654
|
+
if (loc === activeLocale)
|
|
2655
|
+
continue;
|
|
2656
|
+
addHead(`
|
|
2657
|
+
<meta property="og:locale:alternate" content="${toOgLocale(loc)}" />`);
|
|
2658
|
+
}
|
|
2659
|
+
const canonicalPath = localizeContentHref(collection, name, activeLocale, defaultLocale);
|
|
2660
|
+
const base = baseUrl.replace(/\/$/, "");
|
|
2661
|
+
addHead(`
|
|
2662
|
+
<link rel="canonical" href="${base}${canonicalPath}" />`);
|
|
2663
|
+
addHead(`
|
|
2664
|
+
<meta property="og:url" content="${base}${canonicalPath}" />`);
|
|
2665
|
+
}
|
|
2666
|
+
function extractContentMetadata(pathname, addHead, setLang, ogConfig, titleSuffix, baseUrl) {
|
|
2151
2667
|
try {
|
|
2152
|
-
const
|
|
2153
|
-
if (
|
|
2668
|
+
const resolved = resolveContentPathParts(pathname);
|
|
2669
|
+
if (!resolved)
|
|
2154
2670
|
return;
|
|
2155
|
-
const key = `${parts[0]}:${parts[1]}`;
|
|
2156
2671
|
const g = globalThis;
|
|
2157
|
-
const exp = g.__REROUTE_SSR_EXPORTS__?.[key];
|
|
2672
|
+
const exp = g.__REROUTE_SSR_EXPORTS__?.[resolved.key];
|
|
2158
2673
|
const meta = exp?.meta;
|
|
2159
2674
|
const ssr = exp?.ssr;
|
|
2160
2675
|
addHead(buildHeadFromMeta(meta, ogConfig, titleSuffix));
|
|
@@ -2165,15 +2680,20 @@ ${ssrHead}`);
|
|
|
2165
2680
|
const lang = extractSSRLang(ssr);
|
|
2166
2681
|
if (lang)
|
|
2167
2682
|
setLang(lang);
|
|
2683
|
+
const i18n = g.__REROUTE_I18N__;
|
|
2684
|
+
if (i18n?.enabled && baseUrl && i18n.locales && i18n.locales.length > 1) {
|
|
2685
|
+
const locales = resolveContentLocales(resolved.collection, resolved.name, i18n.locales);
|
|
2686
|
+
addContentI18nHead(addHead, baseUrl, resolved.collection, resolved.name, locales, i18n.defaultLocale || "en-US", i18n.locale || i18n.defaultLocale || "en-US");
|
|
2687
|
+
}
|
|
2168
2688
|
} catch {}
|
|
2169
2689
|
}
|
|
2170
2690
|
function getContentMetaFromExports(pathname) {
|
|
2171
2691
|
try {
|
|
2172
|
-
const
|
|
2173
|
-
if (
|
|
2692
|
+
const resolved = resolveContentPathParts(pathname);
|
|
2693
|
+
if (!resolved)
|
|
2174
2694
|
return;
|
|
2175
|
-
const slug =
|
|
2176
|
-
const key =
|
|
2695
|
+
const slug = resolved.name;
|
|
2696
|
+
const key = resolved.key;
|
|
2177
2697
|
const g = globalThis;
|
|
2178
2698
|
const exp = g.__REROUTE_SSR_EXPORTS__?.[key];
|
|
2179
2699
|
const meta = exp?.meta;
|
|
@@ -2187,9 +2707,10 @@ function getContentMetaFromExports(pathname) {
|
|
|
2187
2707
|
return;
|
|
2188
2708
|
}
|
|
2189
2709
|
}
|
|
2190
|
-
async function extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode, statusOverride, ssrData, ogConfig, titleSuffix) {
|
|
2710
|
+
async function extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode, statusOverride, ssrData, ogConfig, titleSuffix, routingPathname) {
|
|
2191
2711
|
const pathnameOnly = pathname.split("?")[0];
|
|
2192
|
-
const
|
|
2712
|
+
const matchPath = (routingPathname || pathname).split("?")[0];
|
|
2713
|
+
const match = typeof m.matchRoute === "function" ? m.matchRoute(matchPath) : null;
|
|
2193
2714
|
const r = match?.route;
|
|
2194
2715
|
if (!r) {
|
|
2195
2716
|
return { head: "", statusOverride: statusOverride || 404 };
|
|
@@ -2229,7 +2750,7 @@ ${ssrHead}`;
|
|
|
2229
2750
|
}
|
|
2230
2751
|
return { head: "", statusOverride };
|
|
2231
2752
|
}
|
|
2232
|
-
async function extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, currentStatusOverride, ssrData, ogConfig, titleSuffix) {
|
|
2753
|
+
async function extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, currentStatusOverride, ssrData, ogConfig, titleSuffix, routingPathname) {
|
|
2233
2754
|
let head = "";
|
|
2234
2755
|
let lang;
|
|
2235
2756
|
let statusOverride = currentStatusOverride;
|
|
@@ -2239,14 +2760,14 @@ async function extractRouteMetadata(pathname, clientDir, cwd, isWatchMode, curre
|
|
|
2239
2760
|
if (!m) {
|
|
2240
2761
|
return { head, lang, statusOverride: statusOverride || 404 };
|
|
2241
2762
|
}
|
|
2242
|
-
const
|
|
2243
|
-
const match = typeof m.matchRoute === "function" ? m.matchRoute(
|
|
2763
|
+
const matchPath = (routingPathname || pathname).split("?")[0];
|
|
2764
|
+
const match = typeof m.matchRoute === "function" ? m.matchRoute(matchPath) : null;
|
|
2244
2765
|
const r = match?.route;
|
|
2245
2766
|
if (!r) {
|
|
2246
2767
|
statusOverride = statusOverride || 404;
|
|
2247
2768
|
}
|
|
2248
2769
|
if (r && typeof r.path === "string") {
|
|
2249
|
-
const result = await extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode, statusOverride, ssrData, ogConfig, titleSuffix);
|
|
2770
|
+
const result = await extractMatchedRouteMetadata(pathname, clientDir, m, isWatchMode, statusOverride, ssrData, ogConfig, titleSuffix, routingPathname);
|
|
2250
2771
|
head = result.head;
|
|
2251
2772
|
lang = result.lang;
|
|
2252
2773
|
statusOverride = result.statusOverride;
|
|
@@ -2421,34 +2942,34 @@ function applyTitleSuffixToHead(headContent, titleSuffix) {
|
|
|
2421
2942
|
}
|
|
2422
2943
|
var init_metadata2 = __esm(() => {
|
|
2423
2944
|
init_metadata();
|
|
2945
|
+
init_pathname();
|
|
2424
2946
|
init_meta();
|
|
2425
2947
|
init_compute();
|
|
2948
|
+
init_content_path();
|
|
2426
2949
|
init_imports();
|
|
2427
2950
|
});
|
|
2428
2951
|
|
|
2429
2952
|
// packages/core/src/ssr/lib/preload.ts
|
|
2430
|
-
import { readdir as
|
|
2953
|
+
import { readdir as readdir5, stat as stat4 } from "node:fs/promises";
|
|
2431
2954
|
async function preloadContentModule(pathname, clientDir, cwd, isWatchMode) {
|
|
2432
2955
|
let extraHead = "";
|
|
2433
2956
|
let hydrationScript = "";
|
|
2434
2957
|
let statusOverride;
|
|
2435
2958
|
try {
|
|
2436
|
-
const
|
|
2437
|
-
const
|
|
2438
|
-
if (
|
|
2959
|
+
const { resolveContentPathParts: resolveContentPathParts2 } = await Promise.resolve().then(() => (init_content_path(), exports_content_path));
|
|
2960
|
+
const resolved = resolveContentPathParts2(pathname);
|
|
2961
|
+
if (!resolved) {
|
|
2439
2962
|
return { extraHead, hydrationScript };
|
|
2440
2963
|
}
|
|
2441
|
-
const collection =
|
|
2442
|
-
const name = parts[1];
|
|
2964
|
+
const { collection, name, key, locale } = resolved;
|
|
2443
2965
|
if (!await isContentCollection(clientDir, collection)) {
|
|
2444
2966
|
return { extraHead, hydrationScript };
|
|
2445
2967
|
}
|
|
2446
|
-
const modulePath = await findContentModulePath(collection, name, clientDir, cwd, isWatchMode);
|
|
2968
|
+
const modulePath = await findContentModulePath(collection, name, clientDir, cwd, isWatchMode, locale);
|
|
2447
2969
|
if (!modulePath) {
|
|
2448
2970
|
statusOverride = 404;
|
|
2449
2971
|
return { extraHead, hydrationScript, statusOverride };
|
|
2450
2972
|
}
|
|
2451
|
-
const key = `${collection}:${name}`;
|
|
2452
2973
|
extraHead += `
|
|
2453
2974
|
<link rel="modulepreload" href="${modulePath}" />`;
|
|
2454
2975
|
hydrationScript += `<script>
|
|
@@ -2490,12 +3011,12 @@ async function findLatestCandidate(chunkDir, candidates) {
|
|
|
2490
3011
|
}
|
|
2491
3012
|
return latest;
|
|
2492
3013
|
}
|
|
2493
|
-
async function findContentModulePath(collection, name, clientDir, cwd, isWatchMode) {
|
|
3014
|
+
async function findContentModulePath(collection, name, clientDir, cwd, isWatchMode, locale) {
|
|
2494
3015
|
try {
|
|
2495
3016
|
const registryPath = join(cwd, ".reroute", "content.ts");
|
|
2496
3017
|
const reg = await dynamicImport(registryPath, isWatchMode);
|
|
2497
3018
|
const get = reg?.getContentEntry;
|
|
2498
|
-
const entry = typeof get === "function" ? get(collection, name) : undefined;
|
|
3019
|
+
const entry = typeof get === "function" ? get(collection, name, locale) : undefined;
|
|
2499
3020
|
const moduleUrl = entry?.module;
|
|
2500
3021
|
if (moduleUrl?.endsWith(".js")) {
|
|
2501
3022
|
return moduleUrl;
|
|
@@ -2503,7 +3024,7 @@ async function findContentModulePath(collection, name, clientDir, cwd, isWatchMo
|
|
|
2503
3024
|
} catch {}
|
|
2504
3025
|
try {
|
|
2505
3026
|
const chunkDir = join(cwd, ".reroute", "chunks", collection);
|
|
2506
|
-
const files = await
|
|
3027
|
+
const files = await readdir5(chunkDir);
|
|
2507
3028
|
const candidates = files.filter((n) => n.startsWith(`${name}.`) && n.endsWith(".js"));
|
|
2508
3029
|
if (candidates.length) {
|
|
2509
3030
|
const latest = await findLatestCandidate(chunkDir, candidates);
|
|
@@ -2511,13 +3032,18 @@ async function findContentModulePath(collection, name, clientDir, cwd, isWatchMo
|
|
|
2511
3032
|
}
|
|
2512
3033
|
} catch {}
|
|
2513
3034
|
try {
|
|
2514
|
-
const
|
|
2515
|
-
const
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
3035
|
+
const contentRoot = join(clientDir, "routes", collection, "content");
|
|
3036
|
+
const candidates = locale ? [
|
|
3037
|
+
join(contentRoot, locale, `${name}.tsx`),
|
|
3038
|
+
join(contentRoot, locale, `${name}.ts`),
|
|
3039
|
+
join(contentRoot, `${name}.tsx`),
|
|
3040
|
+
join(contentRoot, `${name}.ts`)
|
|
3041
|
+
] : [join(contentRoot, `${name}.tsx`), join(contentRoot, `${name}.ts`)];
|
|
3042
|
+
for (const abs of candidates) {
|
|
3043
|
+
if (await Bun.file(abs).exists()) {
|
|
3044
|
+
const rel = abs.startsWith(clientDir) ? abs.slice(clientDir.length).replace(/^[/\\]/, "") : join("routes", collection, "content", `${name}.tsx`);
|
|
3045
|
+
return `/${rel.replace(/\\+/g, "/")}`;
|
|
3046
|
+
}
|
|
2521
3047
|
}
|
|
2522
3048
|
} catch {}
|
|
2523
3049
|
return null;
|
|
@@ -2711,11 +3237,18 @@ function duplicateQueryParamData(ssrData) {
|
|
|
2711
3237
|
return duplicated;
|
|
2712
3238
|
}
|
|
2713
3239
|
function getContentKeyFromPathname(pathname) {
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
3240
|
+
return resolveContentPathParts(pathname)?.key ?? null;
|
|
3241
|
+
}
|
|
3242
|
+
function createI18nScript(i18n) {
|
|
3243
|
+
if (!i18n?.enabled)
|
|
3244
|
+
return "";
|
|
3245
|
+
try {
|
|
3246
|
+
const json = escapeJsonForScript(JSON.stringify(i18n));
|
|
3247
|
+
return `<script>(function(){try{var w=(typeof window!=='undefined'?window:globalThis);w.__REROUTE_I18N__=${json};}catch(e){}})();</script>`;
|
|
3248
|
+
} catch (error) {
|
|
3249
|
+
console.error("[reroute] Failed to serialize i18n hydration:", error);
|
|
3250
|
+
return "";
|
|
3251
|
+
}
|
|
2719
3252
|
}
|
|
2720
3253
|
function createContentCaptureScript() {
|
|
2721
3254
|
return `<script>(function(){try{var w=window;w.__REROUTE_INITIAL_HYDRATION__=true;var h={};document.querySelectorAll('[data-reroute-key]').forEach(function(el){var k=el.getAttribute('data-reroute-key');if(k)h[k]=el.innerHTML;});w.__REROUTE_CONTENT_HTML__=h;var r=document.querySelector('[data-reroute-route="ssr"]');if(r)w.__REROUTE_ROUTE_HTML__=r.innerHTML;}catch(e){}})();</script>`;
|
|
@@ -2791,13 +3324,14 @@ function createSSRPathnameScript(pathname) {
|
|
|
2791
3324
|
return "";
|
|
2792
3325
|
}
|
|
2793
3326
|
}
|
|
2794
|
-
function createDataScript(ssrData, errorMsg, pathname, browserTelemetryConfig, traceContext, titleSuffix) {
|
|
3327
|
+
function createDataScript(ssrData, errorMsg, pathname, browserTelemetryConfig, traceContext, titleSuffix, i18n) {
|
|
2795
3328
|
let script = "";
|
|
2796
3329
|
script += createContentCaptureScript();
|
|
2797
3330
|
script += createSSRPathnameScript(pathname);
|
|
2798
3331
|
if (pathname) {
|
|
2799
3332
|
script += createSSRExportsScript(pathname);
|
|
2800
3333
|
}
|
|
3334
|
+
script += createI18nScript(i18n);
|
|
2801
3335
|
script += createTelemetryConfigScript(browserTelemetryConfig);
|
|
2802
3336
|
script += createTraceContextScript(traceContext);
|
|
2803
3337
|
script += createTitleSuffixScript(titleSuffix);
|
|
@@ -2817,7 +3351,9 @@ function createDataScript(ssrData, errorMsg, pathname, browserTelemetryConfig, t
|
|
|
2817
3351
|
}
|
|
2818
3352
|
return script;
|
|
2819
3353
|
}
|
|
2820
|
-
var init_data2 = () => {
|
|
3354
|
+
var init_data2 = __esm(() => {
|
|
3355
|
+
init_content_path();
|
|
3356
|
+
});
|
|
2821
3357
|
|
|
2822
3358
|
// packages/core/src/ssr/lib/scripts/feeds.ts
|
|
2823
3359
|
function createFeedsScript() {
|
|
@@ -3045,10 +3581,10 @@ function generateCollectionScripts(byCollectionForSSR) {
|
|
|
3045
3581
|
} catch {}
|
|
3046
3582
|
return "";
|
|
3047
3583
|
}
|
|
3048
|
-
function generateHydrationScripts(ssrData, isWatchMode, ssrError, collectionScripts = "", preloadScript = "", bundleUrl = "", pathname = "", browserTelemetryConfig, traceContext, titleSuffix) {
|
|
3584
|
+
function generateHydrationScripts(ssrData, isWatchMode, ssrError, collectionScripts = "", preloadScript = "", bundleUrl = "", pathname = "", browserTelemetryConfig, traceContext, titleSuffix, i18n) {
|
|
3049
3585
|
let scripts = preloadScript;
|
|
3050
3586
|
scripts += collectionScripts;
|
|
3051
|
-
scripts += createDataScript(ssrData, isWatchMode ? ssrError : undefined, pathname, browserTelemetryConfig, traceContext, titleSuffix);
|
|
3587
|
+
scripts += createDataScript(ssrData, isWatchMode ? ssrError : undefined, pathname, browserTelemetryConfig, traceContext, titleSuffix, i18n);
|
|
3052
3588
|
scripts += createFeedsScript();
|
|
3053
3589
|
scripts += createLlmsScript();
|
|
3054
3590
|
if (bundleUrl) {
|
|
@@ -3211,7 +3747,7 @@ async function renderSSRDocument(options) {
|
|
|
3211
3747
|
const browserTelemetryConfig = serializeBrowserTelemetryConfig2(browserTelemetryConfigRaw);
|
|
3212
3748
|
const traceContext = getTraceContextForInjection(options.parentSpan);
|
|
3213
3749
|
const hydrationScript = await withSpan("ssr.generate.scripts", async (span) => {
|
|
3214
|
-
const script = generateHydrationScripts(setup2.ssrData, isWatchMode, setup2.ssrError, collectionScripts, setup2.preloadHydrationScript, bundleUrl, pathname, browserTelemetryConfig, traceContext, options.titleSuffix);
|
|
3750
|
+
const script = generateHydrationScripts(setup2.ssrData, isWatchMode, setup2.ssrError, collectionScripts, setup2.preloadHydrationScript, bundleUrl, pathname, browserTelemetryConfig, traceContext, options.titleSuffix, options.i18n);
|
|
3215
3751
|
span.setAttribute("reroute.scripts.size", script.length);
|
|
3216
3752
|
return script;
|
|
3217
3753
|
});
|
|
@@ -3229,12 +3765,13 @@ async function renderSSRDocument(options) {
|
|
|
3229
3765
|
dedent(setup2.metadataResult.perPageHead)
|
|
3230
3766
|
].filter(Boolean).join(`
|
|
3231
3767
|
`));
|
|
3768
|
+
const i18nLocale = options.i18n?.enabled ? String(options.i18n.locale || "") : "";
|
|
3232
3769
|
const html2 = withSpanSync("ssr.apply.template", (span) => {
|
|
3233
3770
|
const result = applyIndexTemplate(baseTemplate, appHtml, {
|
|
3234
3771
|
head: [setup2.inlineStyleTag, combinedHead].filter(Boolean).join(`
|
|
3235
3772
|
`),
|
|
3236
3773
|
hydrationScript,
|
|
3237
|
-
lang: setup2.metadataResult.pageLang || lang,
|
|
3774
|
+
lang: setup2.metadataResult.pageLang || i18nLocale || lang,
|
|
3238
3775
|
appId
|
|
3239
3776
|
});
|
|
3240
3777
|
span.setAttributes({
|
|
@@ -4412,6 +4949,55 @@ async function discoverRoutes(cwd, isWatchMode) {
|
|
|
4412
4949
|
}
|
|
4413
4950
|
return { staticRoutes, dynamicRoutes };
|
|
4414
4951
|
}
|
|
4952
|
+
function groupNamedCollectionItems(items) {
|
|
4953
|
+
const byName = new Map;
|
|
4954
|
+
for (const item of items) {
|
|
4955
|
+
const name = String(item.name || "");
|
|
4956
|
+
if (!name)
|
|
4957
|
+
continue;
|
|
4958
|
+
const list = byName.get(name) || [];
|
|
4959
|
+
list.push(item);
|
|
4960
|
+
byName.set(name, list);
|
|
4961
|
+
}
|
|
4962
|
+
return byName;
|
|
4963
|
+
}
|
|
4964
|
+
function resolveItemHref(collection, item, defaultLocale, localize) {
|
|
4965
|
+
const name = String(item.name || "");
|
|
4966
|
+
const locale = item.locale || defaultLocale;
|
|
4967
|
+
if (name)
|
|
4968
|
+
return localize(collection, name, locale, defaultLocale);
|
|
4969
|
+
return String(item.href || "");
|
|
4970
|
+
}
|
|
4971
|
+
function buildNamedCollectionSitemapEntries(collection, name, variants, defaultLocale, base, localize) {
|
|
4972
|
+
const locales = [
|
|
4973
|
+
...new Set(variants.map((v) => v.locale || defaultLocale).filter(Boolean))
|
|
4974
|
+
];
|
|
4975
|
+
const alternates = locales.length > 1 ? [
|
|
4976
|
+
...locales.map((locale) => ({
|
|
4977
|
+
hreflang: locale,
|
|
4978
|
+
href: `${base}${localize(collection, name, locale, defaultLocale)}`
|
|
4979
|
+
})),
|
|
4980
|
+
{
|
|
4981
|
+
hreflang: "x-default",
|
|
4982
|
+
href: `${base}${localize(collection, name, defaultLocale, defaultLocale)}`
|
|
4983
|
+
}
|
|
4984
|
+
] : undefined;
|
|
4985
|
+
const entries = [];
|
|
4986
|
+
for (const item of variants) {
|
|
4987
|
+
const href = resolveItemHref(collection, item, defaultLocale, localize);
|
|
4988
|
+
if (!href)
|
|
4989
|
+
continue;
|
|
4990
|
+
const meta = item.meta || {};
|
|
4991
|
+
entries.push({
|
|
4992
|
+
loc: `${base}${href}`,
|
|
4993
|
+
lastmod: meta.date ? new Date(meta.date).toISOString() : undefined,
|
|
4994
|
+
changefreq: "weekly",
|
|
4995
|
+
priority: 0.7,
|
|
4996
|
+
alternates
|
|
4997
|
+
});
|
|
4998
|
+
}
|
|
4999
|
+
return entries;
|
|
5000
|
+
}
|
|
4415
5001
|
async function discoverCollectionContent(cwd, collection, isWatchMode, baseUrl) {
|
|
4416
5002
|
const entries = [];
|
|
4417
5003
|
try {
|
|
@@ -4423,18 +5009,26 @@ async function discoverCollectionContent(cwd, collection, isWatchMode, baseUrl)
|
|
|
4423
5009
|
const url = `${Bun.pathToFileURL(collectionFile).href}${isWatchMode ? `?t=${Date.now()}` : ""}`;
|
|
4424
5010
|
const mod = await import(url);
|
|
4425
5011
|
const items = mod.items || [];
|
|
5012
|
+
const defaultLocale = mod.defaultLocale || "en-US";
|
|
5013
|
+
const { localizeContentHref: localizeContentHref2 } = await Promise.resolve().then(() => (init_pathname(), exports_pathname));
|
|
5014
|
+
const base = baseUrl.replace(/\/$/, "");
|
|
5015
|
+
const byName = groupNamedCollectionItems(items);
|
|
5016
|
+
for (const [name, variants] of byName) {
|
|
5017
|
+
entries.push(...buildNamedCollectionSitemapEntries(collection, name, variants, defaultLocale, base, localizeContentHref2));
|
|
5018
|
+
}
|
|
4426
5019
|
for (const item of items) {
|
|
5020
|
+
if (item.name)
|
|
5021
|
+
continue;
|
|
4427
5022
|
const href = String(item.href || "");
|
|
5023
|
+
if (!href)
|
|
5024
|
+
continue;
|
|
4428
5025
|
const meta = item.meta || {};
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
};
|
|
4436
|
-
entries.push(entry);
|
|
4437
|
-
}
|
|
5026
|
+
entries.push({
|
|
5027
|
+
loc: `${base}${href}`,
|
|
5028
|
+
lastmod: meta.date ? new Date(meta.date).toISOString() : undefined,
|
|
5029
|
+
changefreq: "weekly",
|
|
5030
|
+
priority: 0.7
|
|
5031
|
+
});
|
|
4438
5032
|
}
|
|
4439
5033
|
} catch (error) {
|
|
4440
5034
|
console.error(`[reroute] Failed to discover collection ${collection}:`, error);
|
|
@@ -4729,11 +5323,17 @@ async function discoverCollectionFeedItems(cwd, collection, isWatchMode, baseUrl
|
|
|
4729
5323
|
const url = `${Bun.pathToFileURL(collectionFile).href}${isWatchMode ? `?t=${Date.now()}` : ""}`;
|
|
4730
5324
|
const mod = await import(url);
|
|
4731
5325
|
const contentItems = mod.items || [];
|
|
5326
|
+
const defaultLocale = mod.defaultLocale || "en-US";
|
|
5327
|
+
const { localizeContentHref: localizeContentHref2 } = await Promise.resolve().then(() => (init_pathname(), exports_pathname));
|
|
4732
5328
|
for (const item of contentItems) {
|
|
4733
|
-
const
|
|
5329
|
+
const name = String(item.name || "");
|
|
5330
|
+
const locale = item.locale || defaultLocale;
|
|
5331
|
+
const href = name ? localizeContentHref2(collection, name, locale, defaultLocale) : String(item.href || "");
|
|
4734
5332
|
const meta = item.meta || {};
|
|
4735
5333
|
if (href) {
|
|
4736
|
-
|
|
5334
|
+
const rssItem = createRSSItemFromMetaAndHref(href, meta, baseUrl, item, rssConfig);
|
|
5335
|
+
rssItem.locale = locale;
|
|
5336
|
+
items.push(rssItem);
|
|
4737
5337
|
}
|
|
4738
5338
|
}
|
|
4739
5339
|
} catch (error) {
|
|
@@ -4999,7 +5599,7 @@ function generateRSSXML(feed, options = {}) {
|
|
|
4999
5599
|
<link>${escapeXml(feed.link)}</link>
|
|
5000
5600
|
<description>${escapeXml(feed.description)}</description>
|
|
5001
5601
|
<lastBuildDate>${lastBuildDate}</lastBuildDate>
|
|
5002
|
-
<language
|
|
5602
|
+
<language>${escapeXml(feed.language || "en")}</language>
|
|
5003
5603
|
<atom:link href="${escapeXml(feed.link)}" rel="self" type="application/rss+xml" />
|
|
5004
5604
|
${itemsXML}
|
|
5005
5605
|
</channel>
|
|
@@ -5161,6 +5761,7 @@ async function generateSitemap(discovery4, baseUrl, options = {}) {
|
|
|
5161
5761
|
return createSingleSitemap(allEntries);
|
|
5162
5762
|
}
|
|
5163
5763
|
function generateSitemapXML(entries) {
|
|
5764
|
+
const hasAlternates = entries.some((e) => e.alternates && e.alternates.length > 0);
|
|
5164
5765
|
const urlsetEntries = entries.map((entry) => {
|
|
5165
5766
|
let xml = ` <url>
|
|
5166
5767
|
<loc>${escapeXml2(entry.loc)}</loc>`;
|
|
@@ -5176,13 +5777,20 @@ function generateSitemapXML(entries) {
|
|
|
5176
5777
|
xml += `
|
|
5177
5778
|
<priority>${entry.priority.toFixed(1)}</priority>`;
|
|
5178
5779
|
}
|
|
5780
|
+
if (entry.alternates?.length) {
|
|
5781
|
+
for (const alt of entry.alternates) {
|
|
5782
|
+
xml += `
|
|
5783
|
+
<xhtml:link rel="alternate" hreflang="${escapeXml2(alt.hreflang)}" href="${escapeXml2(alt.href)}" />`;
|
|
5784
|
+
}
|
|
5785
|
+
}
|
|
5179
5786
|
xml += `
|
|
5180
5787
|
</url>`;
|
|
5181
5788
|
return xml;
|
|
5182
5789
|
}).join(`
|
|
5183
5790
|
`);
|
|
5791
|
+
const xhtmlNs = hasAlternates ? ' xmlns:xhtml="http://www.w3.org/1999/xhtml"' : "";
|
|
5184
5792
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
5185
|
-
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
5793
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"${xhtmlNs}>
|
|
5186
5794
|
${urlsetEntries}
|
|
5187
5795
|
</urlset>`;
|
|
5188
5796
|
}
|
|
@@ -5280,7 +5888,8 @@ async function renderSSRDocumentStream(options) {
|
|
|
5280
5888
|
...parts
|
|
5281
5889
|
};
|
|
5282
5890
|
});
|
|
5283
|
-
const
|
|
5891
|
+
const i18nLocale = options.i18n?.enabled ? String(options.i18n.locale || "") : "";
|
|
5892
|
+
const pageLang = setup2.metadataResult.pageLang || i18nLocale || lang;
|
|
5284
5893
|
let headWithLang = htmlHead.replace(/<html([^>]*)>/i, (_m, attrs) => {
|
|
5285
5894
|
const hasLang = /(^|\s)lang\s*=/.test(attrs);
|
|
5286
5895
|
const newAttrs = hasLang ? attrs.replace(/lang\s*=\s*("[^"]*"|'[^']*'|[^\s>]+)/i, `lang="${pageLang}"`) : `${attrs} lang="${pageLang}"`;
|
|
@@ -5323,7 +5932,8 @@ async function renderSSRDocumentStream(options) {
|
|
|
5323
5932
|
parentSpan: options.parentSpan,
|
|
5324
5933
|
timeout: options.timeout,
|
|
5325
5934
|
ssrExport: setup2.metadataResult.ssrExport,
|
|
5326
|
-
titleSuffix: options.titleSuffix
|
|
5935
|
+
titleSuffix: options.titleSuffix,
|
|
5936
|
+
i18n: options.i18n
|
|
5327
5937
|
});
|
|
5328
5938
|
if (debug)
|
|
5329
5939
|
console.log(`[renderStream] ${pathname} - returning stream: ${(performance.now() - t0).toFixed(2)}ms`);
|
|
@@ -5436,7 +6046,7 @@ function buildStreamingScripts(ctx) {
|
|
|
5436
6046
|
ssrDataSnapshot[key] = value;
|
|
5437
6047
|
}
|
|
5438
6048
|
}
|
|
5439
|
-
const dataScript = createDataScript(ssrDataSnapshot, ctx.isWatchMode ? ctx.ssrError : undefined, ctx.pathname, ctx.browserTelemetryConfig, ctx.traceContext, ctx.titleSuffix);
|
|
6049
|
+
const dataScript = createDataScript(ssrDataSnapshot, ctx.isWatchMode ? ctx.ssrError : undefined, ctx.pathname, ctx.browserTelemetryConfig, ctx.traceContext, ctx.titleSuffix, ctx.i18n);
|
|
5440
6050
|
const feedsScript = createFeedsScript();
|
|
5441
6051
|
const llmsScript = createLlmsScript();
|
|
5442
6052
|
let allScripts = dataScript + feedsScript + llmsScript + collectionScripts + ctx.preloadHydrationScript;
|
|
@@ -5568,6 +6178,7 @@ var init_src = __esm(() => {
|
|
|
5568
6178
|
init_bundler();
|
|
5569
6179
|
init_config();
|
|
5570
6180
|
init_content();
|
|
6181
|
+
init_i18n();
|
|
5571
6182
|
init_llms();
|
|
5572
6183
|
init_og();
|
|
5573
6184
|
init_robots();
|
|
@@ -5580,6 +6191,7 @@ var init_src = __esm(() => {
|
|
|
5580
6191
|
var exports_core = {};
|
|
5581
6192
|
__export(exports_core, {
|
|
5582
6193
|
toPromise: () => toPromise,
|
|
6194
|
+
toOgLocale: () => toOgLocale,
|
|
5583
6195
|
toBytes: () => toBytes,
|
|
5584
6196
|
stripStart: () => stripStart,
|
|
5585
6197
|
stripHtmlTags: () => stripHtmlTags,
|
|
@@ -5591,6 +6203,7 @@ __export(exports_core, {
|
|
|
5591
6203
|
setGlobalSSRData: () => setGlobalSSRData,
|
|
5592
6204
|
setGlobalCollections: () => setGlobalCollections,
|
|
5593
6205
|
seedSSRModuleForPath: () => seedSSRModuleForPath,
|
|
6206
|
+
resolveLocale: () => resolveLocale,
|
|
5594
6207
|
resetSSRAccessTracking: () => resetSSRAccessTracking,
|
|
5595
6208
|
renderSSRDocumentStream: () => renderSSRDocumentStream,
|
|
5596
6209
|
renderSSRDocument: () => renderSSRDocument,
|
|
@@ -5599,7 +6212,17 @@ __export(exports_core, {
|
|
|
5599
6212
|
processCollections: () => processCollections,
|
|
5600
6213
|
preloadContentModule: () => preloadContentModule,
|
|
5601
6214
|
performSSRSetup: () => performSSRSetup,
|
|
6215
|
+
parseCookieValue: () => parseCookieValue,
|
|
6216
|
+
parseContentPath: () => parseContentPath,
|
|
6217
|
+
normalizePathname: () => normalizePathname,
|
|
6218
|
+
negotiateLocale: () => negotiateLocale,
|
|
5602
6219
|
mergeLayoutData: () => mergeLayoutData,
|
|
6220
|
+
matchRoutes: () => matchRoutes,
|
|
6221
|
+
matchRoutePattern: () => matchRoutePattern,
|
|
6222
|
+
lookupMessage: () => lookupMessage,
|
|
6223
|
+
looksLikeLocale: () => looksLikeLocale,
|
|
6224
|
+
localizeHref: () => localizeHref,
|
|
6225
|
+
localizeContentHref: () => localizeContentHref,
|
|
5603
6226
|
loadRoutesModule: () => loadRoutesModule,
|
|
5604
6227
|
loadOGImageComponent: () => loadOGImageComponent,
|
|
5605
6228
|
loadIndexHtml: () => loadIndexHtml,
|
|
@@ -5612,11 +6235,13 @@ __export(exports_core, {
|
|
|
5612
6235
|
inlineTailwindCSS: () => inlineTailwindCSS,
|
|
5613
6236
|
importContentModuleForPath: () => importContentModuleForPath,
|
|
5614
6237
|
htmlToMarkdown: () => htmlToMarkdown,
|
|
6238
|
+
hreflangTags: () => hreflangTags,
|
|
5615
6239
|
gzipIfAccepted: () => gzipIfAccepted,
|
|
5616
6240
|
getSitemapExcludedRoutes: () => getSitemapExcludedRoutes,
|
|
5617
6241
|
getRedirectSourcePaths: () => getRedirectSourcePaths,
|
|
5618
6242
|
getPatternDepth: () => getPatternDepth,
|
|
5619
6243
|
getMimeType: () => getMimeType,
|
|
6244
|
+
getMessage: () => getMessage,
|
|
5620
6245
|
getMatchingLayouts: () => getMatchingLayouts,
|
|
5621
6246
|
getContentMeta: () => getContentMeta,
|
|
5622
6247
|
generateSitemapXML: () => generateSitemapXML,
|
|
@@ -5633,6 +6258,7 @@ __export(exports_core, {
|
|
|
5633
6258
|
generateContentHash: () => generateContentHash,
|
|
5634
6259
|
generateCollectionScripts: () => generateCollectionScripts,
|
|
5635
6260
|
generateAtomXML: () => generateAtomXML,
|
|
6261
|
+
formatMessage: () => formatMessage,
|
|
5636
6262
|
formatAsText: () => formatAsText,
|
|
5637
6263
|
formatAsMarkdown: () => formatAsMarkdown,
|
|
5638
6264
|
findOGImageForPath: () => findOGImageForPath,
|
|
@@ -5652,10 +6278,12 @@ __export(exports_core, {
|
|
|
5652
6278
|
discoverRoutes: () => discoverRoutes,
|
|
5653
6279
|
discoverRobotsData: () => discoverRobotsData,
|
|
5654
6280
|
discoverRSSData: () => discoverRSSData,
|
|
6281
|
+
discoverI18n: () => discoverI18n,
|
|
5655
6282
|
discoverCollections: () => discoverCollections,
|
|
5656
6283
|
discoverCollectionContent: () => discoverCollectionContent,
|
|
5657
6284
|
defineConfig: () => defineConfig,
|
|
5658
6285
|
deduplicateMetaTags: () => deduplicateMetaTags,
|
|
6286
|
+
createTranslator: () => createTranslator,
|
|
5659
6287
|
createLlmsScript: () => createLlmsScript,
|
|
5660
6288
|
createLayoutDataKey: () => createLayoutDataKey,
|
|
5661
6289
|
createLayoutCacheKey: () => createLayoutCacheKey,
|
|
@@ -5663,13 +6291,17 @@ __export(exports_core, {
|
|
|
5663
6291
|
createDataScript: () => createDataScript,
|
|
5664
6292
|
createCollectionScript: () => createCollectionScript,
|
|
5665
6293
|
createBundlePreload: () => createBundlePreload,
|
|
6294
|
+
contentNegotiateRedirect: () => contentNegotiateRedirect,
|
|
6295
|
+
contentKey: () => contentKey,
|
|
5666
6296
|
computeSSRDataForPath: () => computeSSRDataForPath,
|
|
5667
6297
|
computeSSRData: () => computeSSRData,
|
|
5668
6298
|
computeRouteData: () => computeRouteData,
|
|
5669
6299
|
computeLayoutData: () => computeLayoutData,
|
|
5670
6300
|
computeContentData: () => computeContentData,
|
|
5671
6301
|
compressStreamIfAccepted: () => compressStreamIfAccepted,
|
|
6302
|
+
compareRouteSpecificity: () => compareRouteSpecificity,
|
|
5672
6303
|
cleanupPathScopedSSRData: () => cleanupPathScopedSSRData,
|
|
6304
|
+
buildLocaleCookie: () => buildLocaleCookie,
|
|
5673
6305
|
buildHeadFromMeta: () => buildHeadFromMeta,
|
|
5674
6306
|
blockSearchCrawlers: () => blockSearchCrawlers,
|
|
5675
6307
|
blockAITrainingCrawlers: () => blockAITrainingCrawlers,
|
|
@@ -5685,6 +6317,9 @@ __export(exports_core, {
|
|
|
5685
6317
|
SEARCH_CRAWLERS: () => SEARCH_CRAWLERS,
|
|
5686
6318
|
LRUCache: () => LRUCache,
|
|
5687
6319
|
DefaultOGTemplate: () => DefaultOGTemplate,
|
|
6320
|
+
DEFAULT_LOCALES_DIR: () => DEFAULT_LOCALES_DIR,
|
|
6321
|
+
DEFAULT_LOCALE: () => DEFAULT_LOCALE,
|
|
6322
|
+
DEFAULT_COOKIE: () => DEFAULT_COOKIE,
|
|
5688
6323
|
AI_CRAWLERS: () => AI_CRAWLERS
|
|
5689
6324
|
});
|
|
5690
6325
|
var init_core = __esm(() => {
|
|
@@ -5699,7 +6334,7 @@ import { createElement as createElement2 } from "react";
|
|
|
5699
6334
|
|
|
5700
6335
|
// packages/elysia/src/libs/image.ts
|
|
5701
6336
|
import { existsSync } from "node:fs";
|
|
5702
|
-
import { join as
|
|
6337
|
+
import { join as join3 } from "node:path";
|
|
5703
6338
|
import sharp from "sharp";
|
|
5704
6339
|
var imageCache = new Map;
|
|
5705
6340
|
var MAX_CACHE_SIZE = 100;
|
|
@@ -5742,8 +6377,8 @@ async function loadFromDiskCache(cacheKey) {
|
|
|
5742
6377
|
if (!diskCacheDir)
|
|
5743
6378
|
return null;
|
|
5744
6379
|
try {
|
|
5745
|
-
const cachePath =
|
|
5746
|
-
const imagePath =
|
|
6380
|
+
const cachePath = join3(diskCacheDir, `${cacheKey}.json`);
|
|
6381
|
+
const imagePath = join3(diskCacheDir, `${cacheKey}.img`);
|
|
5747
6382
|
if (!(existsSync(cachePath) && existsSync(imagePath))) {
|
|
5748
6383
|
return null;
|
|
5749
6384
|
}
|
|
@@ -5765,8 +6400,8 @@ async function saveToDiskCache(cacheKey, result) {
|
|
|
5765
6400
|
if (!diskCacheDir)
|
|
5766
6401
|
return;
|
|
5767
6402
|
try {
|
|
5768
|
-
const cachePath =
|
|
5769
|
-
const imagePath =
|
|
6403
|
+
const cachePath = join3(diskCacheDir, `${cacheKey}.json`);
|
|
6404
|
+
const imagePath = join3(diskCacheDir, `${cacheKey}.img`);
|
|
5770
6405
|
await Bun.write(cachePath, JSON.stringify({
|
|
5771
6406
|
contentType: result.contentType,
|
|
5772
6407
|
format: result.format,
|
|
@@ -6187,7 +6822,7 @@ function registerContentRoutes(app, cwd, collectionCache, directive, maxAge, isW
|
|
|
6187
6822
|
// packages/elysia/src/routes/image.ts
|
|
6188
6823
|
init_core();
|
|
6189
6824
|
import { existsSync as existsSync2 } from "node:fs";
|
|
6190
|
-
import { join as
|
|
6825
|
+
import { join as join4 } from "node:path";
|
|
6191
6826
|
function parseNumericParam(value) {
|
|
6192
6827
|
if (!value)
|
|
6193
6828
|
return;
|
|
@@ -6234,8 +6869,8 @@ function registerImageRoutes(app, options) {
|
|
|
6234
6869
|
}
|
|
6235
6870
|
function resolveInternalImagePath(url, clientDir2) {
|
|
6236
6871
|
const cleanUrl = url.startsWith("/") ? url.slice(1) : url;
|
|
6237
|
-
const imagePath =
|
|
6238
|
-
const normalizedPath =
|
|
6872
|
+
const imagePath = join4(clientDir2, cleanUrl);
|
|
6873
|
+
const normalizedPath = join4(clientDir2, cleanUrl);
|
|
6239
6874
|
if (!normalizedPath.startsWith(clientDir2)) {
|
|
6240
6875
|
return { error: "Access denied" };
|
|
6241
6876
|
}
|
|
@@ -7213,44 +7848,60 @@ async function loadContentMeta(clientDir, collection, slug, isWatchMode, meta) {
|
|
|
7213
7848
|
return;
|
|
7214
7849
|
}
|
|
7215
7850
|
}
|
|
7216
|
-
async function
|
|
7851
|
+
async function loadMatchedRouteModule(clientDir, routePath, isWatchMode) {
|
|
7852
|
+
const { existsSync: existsSync3 } = await import("node:fs");
|
|
7853
|
+
const { pathToFileURL: pathToFileURL8 } = await import("node:url");
|
|
7854
|
+
const normalizedRoutePath = routePath === "" ? "index" : routePath;
|
|
7855
|
+
const possiblePaths = [
|
|
7856
|
+
`${clientDir}/routes/${normalizedRoutePath}.tsx`,
|
|
7857
|
+
`${clientDir}/routes/${normalizedRoutePath}/index.tsx`,
|
|
7858
|
+
`${clientDir}/routes/${normalizedRoutePath}.ts`,
|
|
7859
|
+
`${clientDir}/routes/${normalizedRoutePath}/index.ts`,
|
|
7860
|
+
`${clientDir}/routes/${normalizedRoutePath}.mdx`,
|
|
7861
|
+
`${clientDir}/routes/${normalizedRoutePath}/index.mdx`,
|
|
7862
|
+
`${clientDir}/routes/${normalizedRoutePath}.md`,
|
|
7863
|
+
`${clientDir}/routes/${normalizedRoutePath}/index.md`
|
|
7864
|
+
];
|
|
7865
|
+
for (const possiblePath of possiblePaths) {
|
|
7866
|
+
if (existsSync3(possiblePath)) {
|
|
7867
|
+
return await import(pathToFileURL8(possiblePath).href + (isWatchMode ? `?t=${Date.now()}` : ""));
|
|
7868
|
+
}
|
|
7869
|
+
}
|
|
7870
|
+
return null;
|
|
7871
|
+
}
|
|
7872
|
+
async function loadOgImageFromRoute(cwd, clientDir, pathname, isWatchMode) {
|
|
7217
7873
|
try {
|
|
7874
|
+
const pathnameOnly = pathname.split("?")[0];
|
|
7218
7875
|
const routesGlobal = globalThis.__REROUTE_ROUTES__;
|
|
7219
7876
|
if (routesGlobal && Array.isArray(routesGlobal)) {
|
|
7220
|
-
const
|
|
7221
|
-
|
|
7222
|
-
const pattern = r.pattern.replace(/:[^/]+/g, "[^/]+");
|
|
7223
|
-
const regex = new RegExp(`^${pattern}$`);
|
|
7224
|
-
return regex.test(pathname);
|
|
7225
|
-
}
|
|
7226
|
-
return r.pattern === pathname;
|
|
7227
|
-
});
|
|
7228
|
-
if (matchedRoute) {
|
|
7877
|
+
const matchedRoute2 = matchRoutes(routesGlobal, pathnameOnly)?.route;
|
|
7878
|
+
if (matchedRoute2) {
|
|
7229
7879
|
return {
|
|
7230
|
-
meta:
|
|
7231
|
-
ogImage:
|
|
7880
|
+
meta: matchedRoute2.meta,
|
|
7881
|
+
ogImage: matchedRoute2.ssr?.ogImage
|
|
7232
7882
|
};
|
|
7233
7883
|
}
|
|
7234
7884
|
}
|
|
7235
7885
|
const { pathToFileURL: pathToFileURL8 } = await import("node:url");
|
|
7236
|
-
const
|
|
7237
|
-
const
|
|
7238
|
-
const
|
|
7239
|
-
const
|
|
7240
|
-
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
`${clientDir}/routes/${cleanPath}/index.ts`
|
|
7244
|
-
];
|
|
7245
|
-
for (const routePath of possiblePaths) {
|
|
7246
|
-
if (existsSync3(routePath)) {
|
|
7247
|
-
const routeMod = await import(pathToFileURL8(routePath).href + (isWatchMode ? `?t=${Date.now()}` : ""));
|
|
7886
|
+
const routesPath = `${cwd}/.reroute/routes.ts`;
|
|
7887
|
+
const routesMod = await import(pathToFileURL8(routesPath).href + (isWatchMode ? `?t=${Date.now()}` : ""));
|
|
7888
|
+
const match = typeof routesMod.matchRoute === "function" ? routesMod.matchRoute(pathnameOnly) : Array.isArray(routesMod.routes) ? matchRoutes(routesMod.routes, pathnameOnly) : null;
|
|
7889
|
+
const matchedRoute = match?.route;
|
|
7890
|
+
if (matchedRoute && typeof matchedRoute.path === "string") {
|
|
7891
|
+
const routeMod = await loadMatchedRouteModule(clientDir, String(matchedRoute.path), isWatchMode);
|
|
7892
|
+
if (routeMod) {
|
|
7248
7893
|
return {
|
|
7249
7894
|
meta: routeMod.meta,
|
|
7250
7895
|
ogImage: routeMod.ssr?.ogImage
|
|
7251
7896
|
};
|
|
7252
7897
|
}
|
|
7253
7898
|
}
|
|
7899
|
+
if (matchedRoute) {
|
|
7900
|
+
return {
|
|
7901
|
+
meta: matchedRoute.meta,
|
|
7902
|
+
ogImage: matchedRoute.ssr?.ogImage
|
|
7903
|
+
};
|
|
7904
|
+
}
|
|
7254
7905
|
} catch (error) {
|
|
7255
7906
|
console.warn("[reroute/og] Error loading route metadata:", error);
|
|
7256
7907
|
}
|
|
@@ -7323,14 +7974,14 @@ function registerOGRoutes(app, options) {
|
|
|
7323
7974
|
}
|
|
7324
7975
|
return;
|
|
7325
7976
|
}
|
|
7326
|
-
function getFontPaths(fontPath, baseDir,
|
|
7977
|
+
function getFontPaths(fontPath, baseDir, join5) {
|
|
7327
7978
|
const fontRelativePath = fontPath.replace(/^(\.\/)?src\/client\/assets\//, "").replace(/^assets\//, "");
|
|
7328
7979
|
return [
|
|
7329
|
-
|
|
7330
|
-
|
|
7331
|
-
|
|
7332
|
-
|
|
7333
|
-
|
|
7980
|
+
join5(clientDir, "assets", fontRelativePath),
|
|
7981
|
+
join5(baseDir, ".reroute", "assets", fontRelativePath),
|
|
7982
|
+
join5(cwd, ".reroute", "assets", fontRelativePath),
|
|
7983
|
+
join5(cwd, fontPath),
|
|
7984
|
+
join5(baseDir, fontPath)
|
|
7334
7985
|
];
|
|
7335
7986
|
}
|
|
7336
7987
|
async function tryLoadFont(font, possiblePaths, existsSync3) {
|
|
@@ -7353,14 +8004,14 @@ function registerOGRoutes(app, options) {
|
|
|
7353
8004
|
if (!ogConfig.fonts || ogConfig.fonts.length === 0) {
|
|
7354
8005
|
return [];
|
|
7355
8006
|
}
|
|
7356
|
-
const { join:
|
|
8007
|
+
const { join: join5, dirname } = await import("node:path");
|
|
7357
8008
|
const { existsSync: existsSync3 } = await import("node:fs");
|
|
7358
8009
|
const isCompiledBinary = typeof Bun !== "undefined" && process.argv[0]?.endsWith(process.argv[1]);
|
|
7359
8010
|
const baseDir = isCompiledBinary ? dirname(process.argv[1]) : cwd;
|
|
7360
8011
|
const loadedFonts = [];
|
|
7361
8012
|
for (const font of ogConfig.fonts) {
|
|
7362
8013
|
try {
|
|
7363
|
-
const possiblePaths = getFontPaths(font.path, baseDir,
|
|
8014
|
+
const possiblePaths = getFontPaths(font.path, baseDir, join5);
|
|
7364
8015
|
const loadedFont = await tryLoadFont(font, possiblePaths, existsSync3);
|
|
7365
8016
|
if (loadedFont) {
|
|
7366
8017
|
loadedFonts.push(loadedFont);
|
|
@@ -7688,42 +8339,52 @@ async function registerMainFeedRoute(app, cwd, collections2, baseUrl, isWatchMod
|
|
|
7688
8339
|
function registerCollectionFeedRoutes(app, collections2, options) {
|
|
7689
8340
|
for (const collection of collections2) {
|
|
7690
8341
|
options.availableFeeds.push(`/${collection}/feed.xml`);
|
|
7691
|
-
app.get(`/${collection}/feed.xml`, async () =>
|
|
7692
|
-
|
|
7693
|
-
|
|
7694
|
-
|
|
7695
|
-
|
|
7696
|
-
|
|
7697
|
-
|
|
7698
|
-
|
|
7699
|
-
|
|
7700
|
-
|
|
7701
|
-
|
|
7702
|
-
|
|
7703
|
-
|
|
7704
|
-
|
|
7705
|
-
|
|
7706
|
-
|
|
7707
|
-
|
|
7708
|
-
|
|
7709
|
-
|
|
7710
|
-
|
|
7711
|
-
|
|
7712
|
-
|
|
7713
|
-
|
|
7714
|
-
|
|
7715
|
-
options.
|
|
7716
|
-
|
|
7717
|
-
|
|
7718
|
-
|
|
7719
|
-
|
|
7720
|
-
|
|
7721
|
-
|
|
7722
|
-
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
|
|
8342
|
+
app.get(`/${collection}/feed.xml`, async ({ request }) => handleCollectionFeed(collection, request, options));
|
|
8343
|
+
}
|
|
8344
|
+
}
|
|
8345
|
+
function filterFeedItemsByLang(items, lang) {
|
|
8346
|
+
if (!lang)
|
|
8347
|
+
return items;
|
|
8348
|
+
return items.filter((item) => !item.locale || item.locale === lang);
|
|
8349
|
+
}
|
|
8350
|
+
function buildCollectionFeed(collection, items, lang, options) {
|
|
8351
|
+
return {
|
|
8352
|
+
title: createFeedTitle(options.rssConfig?.title, collection),
|
|
8353
|
+
link: lang ? `${options.baseUrl}/${collection}/feed.xml?lang=${encodeURIComponent(lang)}` : `${options.baseUrl}/${collection}/feed.xml`,
|
|
8354
|
+
description: options.rssConfig?.description ?? `Latest ${collection} updates`,
|
|
8355
|
+
items,
|
|
8356
|
+
language: lang || items[0]?.locale || "en"
|
|
8357
|
+
};
|
|
8358
|
+
}
|
|
8359
|
+
async function handleCollectionFeed(collection, request, options) {
|
|
8360
|
+
const lang = new URL(request.url).searchParams.get("lang") || undefined;
|
|
8361
|
+
const cacheKey = lang ? `rss:${collection}:${lang}` : `rss:${collection}`;
|
|
8362
|
+
try {
|
|
8363
|
+
const cached = options.rssCache.get(cacheKey);
|
|
8364
|
+
if (cached) {
|
|
8365
|
+
return feedResponse(cached, options.format, {
|
|
8366
|
+
maxAge: options.maxAge,
|
|
8367
|
+
cacheStatus: "HIT"
|
|
8368
|
+
});
|
|
8369
|
+
}
|
|
8370
|
+
const discovery5 = await getOrDiscoverRSSData(options.cwd, [collection], options.baseUrl, options.isWatchMode, options.rssConfig);
|
|
8371
|
+
const items = filterFeedItemsByLang(discovery5.collections.get(collection) ?? [], lang);
|
|
8372
|
+
if (items.length === 0)
|
|
8373
|
+
throw new NotFoundError8;
|
|
8374
|
+
const xml = generateFeed(buildCollectionFeed(collection, items, lang, options), {
|
|
8375
|
+
format: options.format,
|
|
8376
|
+
limit: options.limit
|
|
7726
8377
|
});
|
|
8378
|
+
options.rssCache.set(cacheKey, xml);
|
|
8379
|
+
return feedResponse(xml, options.format, {
|
|
8380
|
+
maxAge: options.maxAge,
|
|
8381
|
+
cacheStatus: "MISS"
|
|
8382
|
+
});
|
|
8383
|
+
} catch (error) {
|
|
8384
|
+
if (error instanceof NotFoundError8)
|
|
8385
|
+
throw error;
|
|
8386
|
+
console.error(`[reroute] Failed to generate ${collection} feed:`, error);
|
|
8387
|
+
throw new NotFoundError8;
|
|
7727
8388
|
}
|
|
7728
8389
|
}
|
|
7729
8390
|
async function discoverRoutesWithFeeds(ssrDataRoutes, collections2, options) {
|
|
@@ -7899,11 +8560,11 @@ function scoreEntry(entry, terms) {
|
|
|
7899
8560
|
return { score, matchedHeadings };
|
|
7900
8561
|
}
|
|
7901
8562
|
function searchEntries(entries, query, options = {}) {
|
|
7902
|
-
const { collections: collections2, page = 1, pageSize = 20 } = options;
|
|
8563
|
+
const { collections: collections2, page = 1, pageSize = 20, locale } = options;
|
|
7903
8564
|
const terms = query.toLowerCase().split(/\s+/).filter((t) => t.length > 1);
|
|
7904
8565
|
if (terms.length === 0)
|
|
7905
8566
|
return { results: [], total: 0 };
|
|
7906
|
-
const scored = entries.filter((entry) => !collections2?.length || collections2.includes(entry.collection)).map((entry) => ({ entry, ...scoreEntry(entry, terms) })).filter((item) => item.score > 0).sort((a, b) => b.score - a.score);
|
|
8567
|
+
const scored = entries.filter((entry) => !collections2?.length || collections2.includes(entry.collection)).filter((entry) => !(locale && entry.locale) || entry.locale === locale).map((entry) => ({ entry, ...scoreEntry(entry, terms) })).filter((item) => item.score > 0).sort((a, b) => b.score - a.score);
|
|
7907
8568
|
const total = scored.length;
|
|
7908
8569
|
const startIndex = (page - 1) * pageSize;
|
|
7909
8570
|
const paginatedScored = scored.slice(startIndex, startIndex + pageSize);
|
|
@@ -7954,10 +8615,12 @@ function registerSearchRoute(app, cwd, directive, maxAge, searchConfig) {
|
|
|
7954
8615
|
const page = query.page ? Math.max(1, Number.parseInt(String(query.page), 10)) : 1;
|
|
7955
8616
|
const requestedPageSize = query.pageSize ? Number.parseInt(String(query.pageSize), 10) : defaultPageSize;
|
|
7956
8617
|
const pageSize = Math.min(Math.max(1, requestedPageSize), maxPageSize);
|
|
8618
|
+
const locale = query.lang ? String(query.lang) : undefined;
|
|
7957
8619
|
const { results, total } = searchEntries(index.entries, searchQuery, {
|
|
7958
8620
|
collections: collections2,
|
|
7959
8621
|
page,
|
|
7960
|
-
pageSize
|
|
8622
|
+
pageSize,
|
|
8623
|
+
locale
|
|
7961
8624
|
});
|
|
7962
8625
|
return Response.json({
|
|
7963
8626
|
total,
|
|
@@ -8061,9 +8724,115 @@ function registerSitemapRoutes(app, options) {
|
|
|
8061
8724
|
// packages/elysia/src/routes/ssr.ts
|
|
8062
8725
|
init_core();
|
|
8063
8726
|
init_server2();
|
|
8064
|
-
import { join as
|
|
8727
|
+
import { join as join6 } from "node:path";
|
|
8065
8728
|
import { trace as trace4 } from "@opentelemetry/api";
|
|
8066
8729
|
import { NotFoundError as NotFoundError10 } from "elysia";
|
|
8730
|
+
|
|
8731
|
+
// packages/elysia/src/libs/i18n.ts
|
|
8732
|
+
init_core();
|
|
8733
|
+
import { join as join5 } from "node:path";
|
|
8734
|
+
var cachedI18n = null;
|
|
8735
|
+
async function loadI18nState(cwd) {
|
|
8736
|
+
const path2 = join5(cwd, ".reroute", "i18n.json");
|
|
8737
|
+
try {
|
|
8738
|
+
const file = Bun.file(path2);
|
|
8739
|
+
if (!await file.exists()) {
|
|
8740
|
+
return {
|
|
8741
|
+
enabled: false,
|
|
8742
|
+
defaultLocale: "en-US",
|
|
8743
|
+
locales: [],
|
|
8744
|
+
localesDir: "locales",
|
|
8745
|
+
cookie: "reroute-locale",
|
|
8746
|
+
redirectContentOnNegotiate: true,
|
|
8747
|
+
catalogs: {}
|
|
8748
|
+
};
|
|
8749
|
+
}
|
|
8750
|
+
const stat5 = await file.stat();
|
|
8751
|
+
const mtime = stat5?.mtime?.getTime?.() ?? Date.now();
|
|
8752
|
+
if (cachedI18n && cachedI18n.cwd === cwd && cachedI18n.mtime === mtime) {
|
|
8753
|
+
return cachedI18n.data;
|
|
8754
|
+
}
|
|
8755
|
+
const data = await file.json();
|
|
8756
|
+
cachedI18n = { cwd, data, mtime };
|
|
8757
|
+
return data;
|
|
8758
|
+
} catch {
|
|
8759
|
+
return {
|
|
8760
|
+
enabled: false,
|
|
8761
|
+
defaultLocale: "en-US",
|
|
8762
|
+
locales: [],
|
|
8763
|
+
localesDir: "locales",
|
|
8764
|
+
cookie: "reroute-locale",
|
|
8765
|
+
redirectContentOnNegotiate: true,
|
|
8766
|
+
catalogs: {}
|
|
8767
|
+
};
|
|
8768
|
+
}
|
|
8769
|
+
}
|
|
8770
|
+
async function listContentCollections(cwd) {
|
|
8771
|
+
try {
|
|
8772
|
+
const { readdir: readdir6 } = await import("node:fs/promises");
|
|
8773
|
+
const dir = join5(cwd, ".reroute", "collections");
|
|
8774
|
+
const entries = await readdir6(dir);
|
|
8775
|
+
return entries.filter((f) => f.endsWith(".js")).map((f) => f.replace(/\.js$/, ""));
|
|
8776
|
+
} catch {
|
|
8777
|
+
return [];
|
|
8778
|
+
}
|
|
8779
|
+
}
|
|
8780
|
+
async function resolveI18nForRequest(cwd, pathname, headers2, collections2) {
|
|
8781
|
+
const i18n2 = await loadI18nState(cwd);
|
|
8782
|
+
const disabled = {
|
|
8783
|
+
enabled: false,
|
|
8784
|
+
locale: i18n2.defaultLocale,
|
|
8785
|
+
defaultLocale: i18n2.defaultLocale,
|
|
8786
|
+
locales: [],
|
|
8787
|
+
cookie: i18n2.cookie,
|
|
8788
|
+
catalogs: {},
|
|
8789
|
+
hydration: { enabled: false }
|
|
8790
|
+
};
|
|
8791
|
+
if (!i18n2.enabled || i18n2.locales.length === 0) {
|
|
8792
|
+
return disabled;
|
|
8793
|
+
}
|
|
8794
|
+
const knownCollections = collections2?.length ? collections2 : await listContentCollections(cwd);
|
|
8795
|
+
const resolution = resolveLocale({
|
|
8796
|
+
pathname,
|
|
8797
|
+
cookieHeader: headers2.cookie,
|
|
8798
|
+
acceptLanguage: headers2["accept-language"],
|
|
8799
|
+
availableLocales: i18n2.locales,
|
|
8800
|
+
defaultLocale: i18n2.defaultLocale,
|
|
8801
|
+
cookieName: i18n2.cookie,
|
|
8802
|
+
collections: knownCollections.length > 0 ? knownCollections : undefined
|
|
8803
|
+
});
|
|
8804
|
+
let redirectTo = resolution.redirectTo;
|
|
8805
|
+
if (!redirectTo && i18n2.redirectContentOnNegotiate && knownCollections.length > 0) {
|
|
8806
|
+
redirectTo = contentNegotiateRedirect(resolution, i18n2.defaultLocale, true);
|
|
8807
|
+
}
|
|
8808
|
+
const cookieValue = buildLocaleCookie(i18n2.cookie, resolution.locale);
|
|
8809
|
+
const hydration = {
|
|
8810
|
+
enabled: true,
|
|
8811
|
+
locale: resolution.locale,
|
|
8812
|
+
defaultLocale: i18n2.defaultLocale,
|
|
8813
|
+
locales: i18n2.locales,
|
|
8814
|
+
cookie: i18n2.cookie,
|
|
8815
|
+
catalogs: i18n2.catalogs,
|
|
8816
|
+
collections: knownCollections
|
|
8817
|
+
};
|
|
8818
|
+
try {
|
|
8819
|
+
globalThis.__REROUTE_I18N__ = hydration;
|
|
8820
|
+
} catch {}
|
|
8821
|
+
return {
|
|
8822
|
+
enabled: true,
|
|
8823
|
+
locale: resolution.locale,
|
|
8824
|
+
defaultLocale: i18n2.defaultLocale,
|
|
8825
|
+
locales: i18n2.locales,
|
|
8826
|
+
cookie: i18n2.cookie,
|
|
8827
|
+
catalogs: i18n2.catalogs,
|
|
8828
|
+
collections: knownCollections,
|
|
8829
|
+
setCookie: cookieValue,
|
|
8830
|
+
redirectTo,
|
|
8831
|
+
hydration
|
|
8832
|
+
};
|
|
8833
|
+
}
|
|
8834
|
+
|
|
8835
|
+
// packages/elysia/src/routes/ssr.ts
|
|
8067
8836
|
if (typeof process !== "undefined") {
|
|
8068
8837
|
process.on("unhandledRejection", (reason, _promise) => {
|
|
8069
8838
|
console.error("[reroute] Unhandled Promise Rejection:", reason);
|
|
@@ -8085,6 +8854,28 @@ function isOtelAvailable3() {
|
|
|
8085
8854
|
return false;
|
|
8086
8855
|
}
|
|
8087
8856
|
}
|
|
8857
|
+
async function applyI18nForSSR(cwd, pathname, headers2, set, fallbackLang) {
|
|
8858
|
+
const i18nResult = await resolveI18nForRequest(cwd, pathname, headers2);
|
|
8859
|
+
if (i18nResult.redirectTo && i18nResult.redirectTo !== pathname) {
|
|
8860
|
+
const redirectHeaders = {
|
|
8861
|
+
Location: i18nResult.redirectTo
|
|
8862
|
+
};
|
|
8863
|
+
if (i18nResult.setCookie) {
|
|
8864
|
+
redirectHeaders["Set-Cookie"] = i18nResult.setCookie;
|
|
8865
|
+
}
|
|
8866
|
+
return {
|
|
8867
|
+
redirect: new Response(null, { status: 302, headers: redirectHeaders }),
|
|
8868
|
+
effectiveLang: fallbackLang
|
|
8869
|
+
};
|
|
8870
|
+
}
|
|
8871
|
+
if (i18nResult.setCookie) {
|
|
8872
|
+
set.headers["set-cookie"] = i18nResult.setCookie;
|
|
8873
|
+
}
|
|
8874
|
+
return {
|
|
8875
|
+
hydration: i18nResult.enabled ? i18nResult.hydration : undefined,
|
|
8876
|
+
effectiveLang: i18nResult.enabled ? i18nResult.locale : fallbackLang
|
|
8877
|
+
};
|
|
8878
|
+
}
|
|
8088
8879
|
function registerSSRRoutes(app, options) {
|
|
8089
8880
|
const {
|
|
8090
8881
|
rootComponent,
|
|
@@ -8124,7 +8915,7 @@ function registerSSRRoutes(app, options) {
|
|
|
8124
8915
|
let contentRoutes = [];
|
|
8125
8916
|
let dynamicRoutes = [];
|
|
8126
8917
|
try {
|
|
8127
|
-
const manifestPath =
|
|
8918
|
+
const manifestPath = join6(cwd, ".reroute", "manifest.json");
|
|
8128
8919
|
const { readFileSync } = __require("node:fs");
|
|
8129
8920
|
const manifestText = readFileSync(manifestPath, "utf-8");
|
|
8130
8921
|
const manifest = JSON.parse(manifestText);
|
|
@@ -8160,6 +8951,9 @@ function registerSSRRoutes(app, options) {
|
|
|
8160
8951
|
request.headers.forEach((value, key) => {
|
|
8161
8952
|
headers2[key.toLowerCase()] = value;
|
|
8162
8953
|
});
|
|
8954
|
+
const i18n2 = await applyI18nForSSR(cwd, pathname, headers2, set, lang);
|
|
8955
|
+
if (i18n2.redirect)
|
|
8956
|
+
return i18n2.redirect;
|
|
8163
8957
|
const parentSpan = store.telemetrySpan;
|
|
8164
8958
|
return withParentSpan(parentSpan, async () => {
|
|
8165
8959
|
let isFirstStreamingRequest = false;
|
|
@@ -8242,7 +9036,7 @@ function registerSSRRoutes(app, options) {
|
|
|
8242
9036
|
cachedIndexHtml,
|
|
8243
9037
|
debug,
|
|
8244
9038
|
head,
|
|
8245
|
-
lang,
|
|
9039
|
+
lang: i18n2.effectiveLang,
|
|
8246
9040
|
appId,
|
|
8247
9041
|
maxAge: serverMaxAge,
|
|
8248
9042
|
searchParams,
|
|
@@ -8253,7 +9047,8 @@ function registerSSRRoutes(app, options) {
|
|
|
8253
9047
|
parentSpan: renderSpan,
|
|
8254
9048
|
headers: headers2,
|
|
8255
9049
|
timeout: options.streamingTimeout,
|
|
8256
|
-
titleSuffix: options.titleSuffix
|
|
9050
|
+
titleSuffix: options.titleSuffix,
|
|
9051
|
+
i18n: i18n2.hydration
|
|
8257
9052
|
});
|
|
8258
9053
|
renderSpan?.setAttribute("http.response.status_code", result.status);
|
|
8259
9054
|
if (debug)
|
|
@@ -8424,7 +9219,7 @@ function registerSSRRoutes(app, options) {
|
|
|
8424
9219
|
isWatchMode,
|
|
8425
9220
|
bundleUrl,
|
|
8426
9221
|
head,
|
|
8427
|
-
lang,
|
|
9222
|
+
lang: i18n2.effectiveLang,
|
|
8428
9223
|
appId,
|
|
8429
9224
|
maxAge: serverMaxAge,
|
|
8430
9225
|
searchParams,
|
|
@@ -8434,7 +9229,8 @@ function registerSSRRoutes(app, options) {
|
|
|
8434
9229
|
autoCanonical: options.autoCanonical,
|
|
8435
9230
|
parentSpan: renderSpan,
|
|
8436
9231
|
headers: headers2,
|
|
8437
|
-
titleSuffix: options.titleSuffix
|
|
9232
|
+
titleSuffix: options.titleSuffix,
|
|
9233
|
+
i18n: i18n2.hydration
|
|
8438
9234
|
});
|
|
8439
9235
|
renderSpan?.setAttribute("http.response.status_code", renderResult.status);
|
|
8440
9236
|
return renderResult;
|
|
@@ -9012,4 +9808,4 @@ export {
|
|
|
9012
9808
|
reroute
|
|
9013
9809
|
};
|
|
9014
9810
|
|
|
9015
|
-
//# debugId=
|
|
9811
|
+
//# debugId=27029E2CFF5EA81E64756E2164756E21
|