@monkeyplus/flow 6.0.6 → 6.0.8

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.
Files changed (57) hide show
  1. package/modules/content/module.mjs +17 -2
  2. package/modules/content/query.d.ts +25 -0
  3. package/modules/content/query.mjs +105 -19
  4. package/modules/content/runtime/client.d.ts +2 -0
  5. package/modules/content/runtime/client.mjs +1 -0
  6. package/modules/images/ipx.d.ts +2 -0
  7. package/modules/images/ipx.mjs +55 -0
  8. package/modules/images/module.d.ts +4 -0
  9. package/modules/images/module.mjs +146 -0
  10. package/modules/images/runtime/build.d.ts +6 -0
  11. package/modules/images/runtime/build.mjs +174 -0
  12. package/modules/images/runtime/helpers.d.ts +16 -0
  13. package/modules/images/runtime/helpers.mjs +45 -0
  14. package/modules/images/runtime/image.d.ts +7 -0
  15. package/modules/images/runtime/image.mjs +252 -0
  16. package/modules/images/runtime/renames.d.ts +2 -0
  17. package/modules/images/runtime/renames.mjs +79 -0
  18. package/modules/images/runtime/server.d.ts +3 -0
  19. package/modules/images/runtime/server.mjs +80 -0
  20. package/modules/images/runtime/types.d.ts +79 -0
  21. package/modules/images/runtime/types.mjs +0 -0
  22. package/modules/sitemap/handler.mjs +6 -7
  23. package/modules/sitemap/module.mjs +236 -22
  24. package/modules/sitemap/xml.d.ts +7 -0
  25. package/modules/sitemap/xml.mjs +87 -0
  26. package/package.json +7 -1
  27. package/server/lib/pages.mjs +20 -21
  28. package/server/lib/render.mjs +16 -0
  29. package/server/renderer.d.ts +1 -1
  30. package/server/renderer.mjs +2 -1
  31. package/src/public/components.d.ts +3 -0
  32. package/src/public/components.mjs +3 -0
  33. package/src/public/index.d.ts +5 -3
  34. package/src/public/index.mjs +1 -0
  35. package/src/public/modules/images.d.ts +2 -0
  36. package/src/public/modules/images.mjs +1 -0
  37. package/src/public/nitro.mjs +4 -1
  38. package/src/public/query-content.d.ts +7 -0
  39. package/src/public/query-content.mjs +130 -0
  40. package/src/public/vite.mjs +18 -2
  41. package/src/runtime/components/MkImage.d.ts +188 -0
  42. package/src/runtime/components/MkImage.mjs +131 -0
  43. package/src/runtime/components/MkLink.d.ts +22 -0
  44. package/src/runtime/components/MkLink.mjs +72 -0
  45. package/src/runtime/components/MkPicture.d.ts +199 -0
  46. package/src/runtime/components/MkPicture.mjs +172 -0
  47. package/src/runtime/components/image-shared.d.ts +28 -0
  48. package/src/runtime/components/image-shared.mjs +68 -0
  49. package/src/runtime/config.d.ts +22 -0
  50. package/src/runtime/config.mjs +5 -2
  51. package/src/runtime/locale-routing.d.ts +12 -0
  52. package/src/runtime/locale-routing.mjs +93 -0
  53. package/src/runtime/modules.mjs +1 -0
  54. package/src/runtime/page-discovery.mjs +8 -15
  55. package/src/runtime/pages.d.ts +16 -0
  56. package/src/runtime/virtual.d.ts +17 -0
  57. package/src/runtime/vue.mjs +6 -0
@@ -2,13 +2,14 @@ import { mkdirSync, writeFileSync } from "node:fs";
2
2
  import { dirname, resolve } from "node:path";
3
3
  import { resolvePackagePath } from "../../src/public/shared.mjs";
4
4
  import { defineFlowModule } from "../../src/runtime/config.mjs";
5
- function createGeneratedSitemapHandler(siteUrl, locales) {
5
+ function createGeneratedSitemapHandler(siteUrl, localeConfig) {
6
6
  return `
7
7
  import pageDefinitions from 'virtual:flow/pages';
8
8
 
9
9
  const dynamicRouteCache = new Map();
10
10
  const configuredSiteUrl = ${JSON.stringify(siteUrl || "")};
11
- const enabledLocales = ${JSON.stringify(locales)};
11
+ const localeConfig = ${JSON.stringify(localeConfig)};
12
+ const enabledLocales = localeConfig.locales;
12
13
 
13
14
  function escapeXml(value) {
14
15
  return value
@@ -27,6 +28,26 @@ function normalizePath(value) {
27
28
  return value.length > 1 && value.endsWith('/') ? value.slice(0, -1) : value;
28
29
  }
29
30
 
31
+ function ensureLeadingSlash(value) {
32
+ if (!value) {
33
+ return '/';
34
+ }
35
+
36
+ return value.startsWith('/') ? value : '/' + value;
37
+ }
38
+
39
+ function ensureTrailingSlash(value) {
40
+ if (value === '/' || value.endsWith('/')) {
41
+ return value;
42
+ }
43
+
44
+ return value + '/';
45
+ }
46
+
47
+ function preserveTrailingSlash(value, source) {
48
+ return source.endsWith('/') ? ensureTrailingSlash(value) : value;
49
+ }
50
+
30
51
  function replacePath(pattern, url) {
31
52
  let resolved = pattern;
32
53
 
@@ -53,8 +74,198 @@ function toPublicRoutePattern(url) {
53
74
  return normalizePath(url.replaceAll('*', ''));
54
75
  }
55
76
 
77
+ function trimLeadingSlash(value) {
78
+ let result = value;
79
+
80
+ while (result.startsWith('/')) {
81
+ result = result.slice(1);
82
+ }
83
+
84
+ return result;
85
+ }
86
+
87
+ function trimTrailingSlash(value) {
88
+ let result = value;
89
+
90
+ while (result.endsWith('/')) {
91
+ result = result.slice(0, -1);
92
+ }
93
+
94
+ return result;
95
+ }
96
+
97
+ function combineName(name, dynamicName) {
98
+ return trimTrailingSlash(name) + '/' + trimLeadingSlash(dynamicName);
99
+ }
100
+
101
+ function getLanguage(locale) {
102
+ const [language = localeConfig.language || 'es'] = locale.split('-');
103
+ return language;
104
+ }
105
+
106
+ function getLocation(locale) {
107
+ const [, location = localeConfig.location || 'ec'] = locale.split('-');
108
+ return location;
109
+ }
110
+
111
+ function getDefaultLocaleCode() {
112
+ return localeConfig.language + '-' + localeConfig.location;
113
+ }
114
+
115
+ function routeHasPrefix(route, prefix) {
116
+ return route === prefix || route === prefix + '/' || route.startsWith(prefix + '/');
117
+ }
118
+
119
+ function getLocalePrefixVariants(localeCode) {
120
+ const lang = getLanguage(localeCode);
121
+ const loc = getLocation(localeCode);
122
+ const prefixes = new Set();
123
+
124
+ if (loc === localeConfig.location) {
125
+ prefixes.add('/' + lang);
126
+ return [...prefixes];
127
+ }
128
+
129
+ prefixes.add('/' + lang + '-' + loc);
130
+ prefixes.add('/' + lang + '/' + loc);
131
+
132
+ return [...prefixes];
133
+ }
134
+
135
+ function getLocalePrefix(localeCode) {
136
+ if (localeConfig.prefixStrategy === 'manual') {
137
+ return '';
138
+ }
139
+
140
+ if (localeCode === getDefaultLocaleCode()) {
141
+ return '';
142
+ }
143
+
144
+ const lang = getLanguage(localeCode);
145
+ const loc = getLocation(localeCode);
146
+
147
+ if (loc === localeConfig.location) {
148
+ return '/' + lang;
149
+ }
150
+
151
+ if (localeConfig.prefixFormat === 'nested') {
152
+ return '/' + lang + '/' + loc;
153
+ }
154
+
155
+ return '/' + lang + '-' + loc;
156
+ }
157
+
158
+ function localizeRoutePattern(localeCode, route) {
159
+ const normalizedRoute = ensureLeadingSlash(route || '/');
160
+ const prefix = getLocalePrefix(localeCode);
161
+
162
+ if (!prefix) {
163
+ return normalizedRoute;
164
+ }
165
+
166
+ if (getLocalePrefixVariants(localeCode).some(candidate => routeHasPrefix(normalizedRoute, candidate))) {
167
+ return normalizedRoute;
168
+ }
169
+
170
+ if (normalizedRoute === '/') {
171
+ return ensureTrailingSlash(prefix);
172
+ }
173
+
174
+ return preserveTrailingSlash(normalizePath(prefix) + normalizedRoute, normalizedRoute);
175
+ }
176
+
177
+ function toPublicRoute(localeCode, route) {
178
+ const localizedRoute = localizeRoutePattern(localeCode, route);
179
+ const publicRoute = localizedRoute.replaceAll('*', '');
180
+
181
+ return preserveTrailingSlash(normalizePath(publicRoute), localizedRoute);
182
+ }
183
+
184
+ function toAbsoluteUrl(origin, url) {
185
+ return new URL(url, origin).toString();
186
+ }
187
+
188
+ function buildAlternateLink(hreflang, origin, url) {
189
+ return '<xhtml:link rel="alternate" hreflang="' + escapeXml(hreflang) + '" href="' + escapeXml(toAbsoluteUrl(origin, url)) + '"/>';
190
+ }
191
+
192
+ function buildUrl(origin, url, lastMod, alternates = []) {
193
+ return [
194
+ ' <url>',
195
+ ' <loc>' + escapeXml(toAbsoluteUrl(origin, url)) + '</loc>',
196
+ ' <lastmod>' + escapeXml(lastMod) + '</lastmod>',
197
+ ...alternates.map(alternate => ' ' + alternate),
198
+ ' </url>',
199
+ ].join('\\n');
200
+ }
201
+
202
+ function groupByName(entries) {
203
+ const grouped = new Map();
204
+
205
+ for (const entry of entries) {
206
+ const group = grouped.get(entry.name) || [];
207
+ group.push(entry);
208
+ grouped.set(entry.name, group);
209
+ }
210
+
211
+ return [...grouped.values()];
212
+ }
213
+
214
+ function buildLocalizedUrls(entries, origin, lastMod) {
215
+ const defaultLocale = getDefaultLocaleCode();
216
+
217
+ return groupByName(entries).map((pages) => {
218
+ const pagesByLanguage = pages.reduce((result, page) => {
219
+ const language = getLanguage(page.locale);
220
+ const group = result.get(language) || [];
221
+ group.push(page);
222
+ result.set(language, group);
223
+ return result;
224
+ }, new Map());
225
+ const defaultEntry = pages.find(page => page.locale === defaultLocale) || pages[0];
226
+ const alternates = [buildAlternateLink('x-default', origin, defaultEntry.url)];
227
+
228
+ for (const [language, localizedPages] of [...pagesByLanguage.entries()].sort(([left], [right]) => left.localeCompare(right))) {
229
+ const sortedPages = [...localizedPages].sort((left, right) => left.locale.localeCompare(right.locale));
230
+
231
+ if (sortedPages.length > 1) {
232
+ const languageDefault = sortedPages.find(page => getLocation(page.locale) === localeConfig.location) || sortedPages[0];
233
+ alternates.push(buildAlternateLink(language, origin, languageDefault.url));
234
+
235
+ for (const page of sortedPages) {
236
+ alternates.push(buildAlternateLink(page.locale, origin, page.url));
237
+ }
238
+
239
+ continue;
240
+ }
241
+
242
+ alternates.push(buildAlternateLink(language, origin, sortedPages[0].url));
243
+ }
244
+
245
+ return buildUrl(origin, defaultEntry.url, lastMod, alternates);
246
+ });
247
+ }
248
+
249
+ function buildSitemapXml(entries, origin) {
250
+ const normalizedEntries = entries
251
+ .map((entry) => typeof entry === 'string'
252
+ ? { url: entry, locale: localeConfig.language + '-' + localeConfig.location, name: entry }
253
+ : entry)
254
+ .sort((left, right) => left.url.localeCompare(right.url));
255
+ const lastMod = new Date().toISOString().split('T')[0];
256
+ const isMultiple = localeConfig.locales.length > 1;
257
+ const urls = isMultiple
258
+ ? buildLocalizedUrls(normalizedEntries, origin, lastMod)
259
+ : normalizedEntries.map(entry => buildUrl(origin, entry.url, lastMod));
260
+ const alternateNamespace = isMultiple
261
+ ? ' xmlns:xhtml="http://www.w3.org/1999/xhtml"'
262
+ : '';
263
+
264
+ return '<?xml version="1.0" encoding="UTF-8"?>\\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"' + alternateNamespace + '>\\n' + urls.join('\\n') + '\\n</urlset>';
265
+ }
266
+
56
267
  function createLocale(code) {
57
- const [lang = 'es', loc = 'ec'] = code.split('-');
268
+ const [lang = localeConfig.language || 'es', loc = localeConfig.location || 'ec'] = code.split('-');
58
269
 
59
270
  return {
60
271
  code,
@@ -91,7 +302,7 @@ async function getUrl(namePage, localeCode, options = {}) {
91
302
 
92
303
  if (localePage.dynamic && options.dynamicName) {
93
304
  const locale = createLocale(code);
94
- const ctx = createContext(definition, locale, localePage, localePage.url, {});
305
+ const ctx = createContext(definition, locale, localePage, toPublicRoute(code, localePage.url), {});
95
306
  const entries = await getDynamicEntries(definition, code, ctx);
96
307
  const entry = entries.find(candidate => candidate.name === options.dynamicName);
97
308
 
@@ -99,10 +310,10 @@ async function getUrl(namePage, localeCode, options = {}) {
99
310
  return undefined;
100
311
  }
101
312
 
102
- return replacePath(localePage.url, entry.url);
313
+ return replacePath(localizeRoutePattern(code, localePage.url), entry.url);
103
314
  }
104
315
 
105
- return toPublicRoutePattern(localePage.url);
316
+ return toPublicRoute(code, localePage.url);
106
317
  }
107
318
  }
108
319
 
@@ -125,19 +336,19 @@ async function getUrls(withLocale = false, omitNoPublish = false) {
125
336
 
126
337
  if (localePage.dynamic) {
127
338
  const locale = createLocale(localeCode);
128
- const ctx = createContext(definition, locale, localePage, localePage.url, {});
339
+ const ctx = createContext(definition, locale, localePage, toPublicRoute(localeCode, localePage.url), {});
129
340
  const entries = await getDynamicEntries(definition, localeCode, ctx);
130
341
 
131
342
  for (const entry of entries) {
132
- const url = replacePath(localePage.url, entry.url);
133
- urls.push(withLocale ? { url, locale: localeCode } : url);
343
+ const url = replacePath(localizeRoutePattern(localeCode, localePage.url), entry.url);
344
+ urls.push(withLocale ? { url, locale: localeCode, name: combineName(definition.name, entry.name) } : url);
134
345
  }
135
346
 
136
347
  continue;
137
348
  }
138
349
 
139
- const url = toPublicRoutePattern(localePage.url);
140
- urls.push(withLocale ? { url, locale: localeCode } : url);
350
+ const url = toPublicRoute(localeCode, localePage.url);
351
+ urls.push(withLocale ? { url, locale: localeCode, name: definition.name } : url);
141
352
  }
142
353
  }
143
354
 
@@ -201,12 +412,7 @@ export default async function sitemapHandler(event) {
201
412
  ? new URL(event.req.url, configuredSiteUrl || 'http://localhost')
202
413
  : new URL(configuredSiteUrl || 'http://localhost');
203
414
  const origin = configuredSiteUrl || requestUrl.origin;
204
-
205
- const xml = '<?xml version="1.0" encoding="UTF-8"?>\\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\\n' + urls
206
- .map((entry) => typeof entry === 'string'
207
- ? ' <url><loc>' + escapeXml(new URL(entry, origin).toString()) + '</loc></url>'
208
- : ' <url><loc>' + escapeXml(new URL(entry.url, origin).toString()) + '</loc><xhtml:link rel="alternate" hreflang="' + escapeXml(entry.locale) + '" href="' + escapeXml(new URL(entry.url, origin).toString()) + '" xmlns:xhtml="http://www.w3.org/1999/xhtml" /></url>')
209
- .join('\\n') + '\\n</urlset>';
415
+ const xml = buildSitemapXml(urls, origin);
210
416
 
211
417
  return new Response(xml, {
212
418
  headers: {
@@ -216,12 +422,18 @@ export default async function sitemapHandler(event) {
216
422
  }
217
423
  `;
218
424
  }
219
- function ensureGeneratedSitemapHandler(projectRoot, flowRuntimeConfig) {
425
+ function ensureGeneratedSitemapHandler(projectRoot, flowConfig) {
220
426
  const handlerPath = resolve(projectRoot, ".flow/generated/modules/sitemap/handler.mjs");
221
427
  mkdirSync(dirname(handlerPath), { recursive: true });
222
428
  writeFileSync(handlerPath, createGeneratedSitemapHandler(
223
- typeof flowRuntimeConfig.siteUrl === "string" ? flowRuntimeConfig.siteUrl : void 0,
224
- Array.isArray(flowRuntimeConfig.locale?.locales) ? flowRuntimeConfig.locale.locales : []
429
+ typeof flowConfig.siteUrl === "string" ? flowConfig.siteUrl : void 0,
430
+ {
431
+ locales: Array.isArray(flowConfig.locale?.locales) ? flowConfig.locale.locales : ["es-ec"],
432
+ language: typeof flowConfig.locale?.language === "string" ? flowConfig.locale.language : "es",
433
+ location: typeof flowConfig.locale?.location === "string" ? flowConfig.locale.location : "ec",
434
+ prefixStrategy: flowConfig.locale?.prefixStrategy === "manual" ? "manual" : "auto",
435
+ prefixFormat: flowConfig.locale?.prefixFormat === "nested" ? "nested" : "compact"
436
+ }
225
437
  ), "utf8");
226
438
  return handlerPath;
227
439
  }
@@ -235,9 +447,11 @@ export default defineFlowModule({
235
447
  prerender: true
236
448
  },
237
449
  setup(options, context) {
238
- const contextRuntimeConfig = typeof context.nitro.runtimeConfig.flow === "object" && context.nitro.runtimeConfig.flow ? context.nitro.runtimeConfig.flow : {};
239
450
  const localHandlerPath = resolve(context.projectRoot, "modules/sitemap/handler.ts");
240
- const handlerPath = context.projectRoot === resolvePackagePath() ? localHandlerPath : ensureGeneratedSitemapHandler(context.projectRoot, contextRuntimeConfig);
451
+ const handlerPath = context.projectRoot === resolvePackagePath() ? localHandlerPath : ensureGeneratedSitemapHandler(context.projectRoot, {
452
+ siteUrl: context.flowConfig.siteUrl,
453
+ locale: context.flowConfig.locale
454
+ });
241
455
  context.nitro.handlers.push({
242
456
  method: "get",
243
457
  route: options.route,
@@ -0,0 +1,7 @@
1
+ import type { PageUrlInfo } from '../../src/runtime/pages.ts';
2
+ export interface SitemapLocaleConfig {
3
+ locales: string[];
4
+ language: string;
5
+ location: string;
6
+ }
7
+ export declare function buildSitemapXml(entries: Array<string | PageUrlInfo>, origin: string, locale: SitemapLocaleConfig): string;
@@ -0,0 +1,87 @@
1
+ function escapeXml(value) {
2
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
3
+ }
4
+ function getLanguage(locale) {
5
+ const [language = "es"] = locale.split("-");
6
+ return language;
7
+ }
8
+ function getLocation(locale) {
9
+ const [, location = "ec"] = locale.split("-");
10
+ return location;
11
+ }
12
+ function toAbsoluteUrl(origin, url) {
13
+ return new URL(url, origin).toString();
14
+ }
15
+ function buildAlternateLink(hreflang, origin, url) {
16
+ return `<xhtml:link rel="alternate" hreflang="${escapeXml(hreflang)}" href="${escapeXml(toAbsoluteUrl(origin, url))}"/>`;
17
+ }
18
+ function buildUrl(origin, url, lastMod, alternates = []) {
19
+ const lines = [
20
+ " <url>",
21
+ ` <loc>${escapeXml(toAbsoluteUrl(origin, url))}</loc>`,
22
+ ` <lastmod>${escapeXml(lastMod)}</lastmod>`,
23
+ ...alternates.map((alternate) => ` ${alternate}`),
24
+ " </url>"
25
+ ];
26
+ return lines.join("\n");
27
+ }
28
+ function normalizeEntries(entries, locale) {
29
+ const defaultLocale = `${locale.language}-${locale.location}`;
30
+ return entries.map((entry) => {
31
+ if (typeof entry === "string") {
32
+ return {
33
+ url: entry,
34
+ locale: defaultLocale,
35
+ name: entry
36
+ };
37
+ }
38
+ return entry;
39
+ }).sort((left, right) => left.url.localeCompare(right.url));
40
+ }
41
+ function groupByName(entries) {
42
+ const grouped = /* @__PURE__ */ new Map();
43
+ for (const entry of entries) {
44
+ const group = grouped.get(entry.name) || [];
45
+ group.push(entry);
46
+ grouped.set(entry.name, group);
47
+ }
48
+ return [...grouped.values()];
49
+ }
50
+ function buildLocalizedUrls(entries, origin, locale, lastMod) {
51
+ const defaultLocale = `${locale.language}-${locale.location}`;
52
+ return groupByName(entries).map((pages) => {
53
+ const pagesByLanguage = pages.reduce((result, page) => {
54
+ const language = getLanguage(page.locale);
55
+ const group = result.get(language) || [];
56
+ group.push(page);
57
+ result.set(language, group);
58
+ return result;
59
+ }, /* @__PURE__ */ new Map());
60
+ const defaultEntry = pages.find((page) => page.locale === defaultLocale) || pages[0];
61
+ const alternates = [buildAlternateLink("x-default", origin, defaultEntry.url)];
62
+ for (const [language, localizedPages] of [...pagesByLanguage.entries()].sort(([left], [right]) => left.localeCompare(right))) {
63
+ const sortedPages = [...localizedPages].sort((left, right) => left.locale.localeCompare(right.locale));
64
+ if (sortedPages.length > 1) {
65
+ const languageDefault = sortedPages.find((page) => getLocation(page.locale) === locale.location) || sortedPages[0];
66
+ alternates.push(buildAlternateLink(language, origin, languageDefault.url));
67
+ for (const page of sortedPages) {
68
+ alternates.push(buildAlternateLink(page.locale, origin, page.url));
69
+ }
70
+ continue;
71
+ }
72
+ alternates.push(buildAlternateLink(language, origin, sortedPages[0].url));
73
+ }
74
+ return buildUrl(origin, defaultEntry.url, lastMod, alternates);
75
+ });
76
+ }
77
+ export function buildSitemapXml(entries, origin, locale) {
78
+ const normalizedEntries = normalizeEntries(entries, locale);
79
+ const lastMod = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
80
+ const isMultiple = locale.locales.length > 1;
81
+ const urls = isMultiple ? buildLocalizedUrls(normalizedEntries, origin, locale, lastMod) : normalizedEntries.map((entry) => buildUrl(origin, entry.url, lastMod));
82
+ const alternateNamespace = isMultiple ? ' xmlns:xhtml="http://www.w3.org/1999/xhtml"' : "";
83
+ return `<?xml version="1.0" encoding="UTF-8"?>
84
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"${alternateNamespace}>
85
+ ${urls.join("\n")}
86
+ </urlset>`;
87
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monkeyplus/flow",
3
- "version": "6.0.6",
3
+ "version": "6.0.8",
4
4
  "description": "@monkeyplus/flow package-first runtime with Vite, Nitro, Vue and a workspace playground.",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -40,6 +40,10 @@
40
40
  "types": "./modules/strapi/runtime/client.d.ts",
41
41
  "import": "./modules/strapi/runtime/client.mjs"
42
42
  },
43
+ "./modules/images": {
44
+ "types": "./src/public/modules/images.d.ts",
45
+ "import": "./src/public/modules/images.mjs"
46
+ },
43
47
  "./modules/sitemap": {
44
48
  "types": "./src/public/modules/sitemap.d.ts",
45
49
  "import": "./src/public/modules/sitemap.mjs"
@@ -72,8 +76,10 @@
72
76
  "@unhead/vue": "^3.1.0",
73
77
  "@vitejs/plugin-vue": "^6.0.5",
74
78
  "@vue/server-renderer": "^3.5.13",
79
+ "ipx": "^3.1.1",
75
80
  "nitro": "3.0.260429-beta",
76
81
  "std-env": "^4.0.0",
82
+ "ufo": "^1.6.1",
77
83
  "unhead": "^3.1.0",
78
84
  "unplugin-icons": "^23.0.1",
79
85
  "vite": "^8.0.5",
@@ -1,5 +1,7 @@
1
1
  import { createRequire } from "node:module";
2
2
  import pageDefinitions from "virtual:flow/pages";
3
+ import { getFlowImageRuntimeUtils } from "../../modules/images/runtime/server.mjs";
4
+ import { localizeRoutePattern, normalizePath, toPublicRoute } from "../../src/runtime/locale-routing.mjs";
3
5
  const dynamicRouteCache = /* @__PURE__ */ new Map();
4
6
  let runtimeConfigRequire;
5
7
  function getFlowRuntimeConfig() {
@@ -11,12 +13,6 @@ function getFlowRuntimeConfig() {
11
13
  return {};
12
14
  }
13
15
  }
14
- function normalizePath(value) {
15
- if (!value || value === "/") {
16
- return "/";
17
- }
18
- return value.length > 1 && value.endsWith("/") ? value.slice(0, -1) : value;
19
- }
20
16
  function scorePattern(pattern) {
21
17
  return normalizePath(pattern).split("/").filter(Boolean).reduce((score, segment) => {
22
18
  if (segment === "**") {
@@ -69,6 +65,7 @@ function createLocale(code) {
69
65
  };
70
66
  }
71
67
  function createContext(definition, locale, localePage, pathname, params, dynamic) {
68
+ const imageUtils = getFlowImageRuntimeUtils();
72
69
  return {
73
70
  dynamic,
74
71
  locale,
@@ -82,11 +79,12 @@ function createContext(definition, locale, localePage, pathname, params, dynamic
82
79
  return locale;
83
80
  },
84
81
  async getUrl(namePage, localeCode, options) {
85
- return await getUrl(namePage, localeCode, options);
82
+ return await getUrl(namePage, localeCode || locale.code, options);
86
83
  },
87
84
  async getUrls(withLocale, omitNoPublish) {
88
85
  return await getUrls(withLocale, omitNoPublish);
89
- }
86
+ },
87
+ ...imageUtils || {}
90
88
  }
91
89
  };
92
90
  }
@@ -109,9 +107,6 @@ function replacePath(pattern, url) {
109
107
  }
110
108
  return normalizePath(resolved.replaceAll("**", ""));
111
109
  }
112
- function toPublicRoutePattern(url) {
113
- return normalizePath(url.replaceAll("*", ""));
114
- }
115
110
  function combineName(name, dynamicName) {
116
111
  return `${name.replace(/\/*$/, "")}/${dynamicName.replace(/^\/*/, "")}`;
117
112
  }
@@ -147,6 +142,7 @@ async function resolveDynamicEntry(definition, localeCode, localePage, ctx, path
147
142
  export async function getUrl(namePage, localeCode, options = {}) {
148
143
  const enabledLocales = getEnabledLocaleCodes();
149
144
  const targetLocale = localeCode || enabledLocales[0];
145
+ const runtimeConfig = getFlowRuntimeConfig();
150
146
  for (const definition of pageDefinitions) {
151
147
  if (definition.name !== namePage) {
152
148
  continue;
@@ -154,32 +150,34 @@ export async function getUrl(namePage, localeCode, options = {}) {
154
150
  const localeEntries = targetLocale ? [targetLocale] : Object.keys(definition.locales);
155
151
  for (const code of localeEntries) {
156
152
  const localePage = definition.locales[code];
153
+ const localizedRoute = localizeRoutePattern(runtimeConfig.flow, code, localePage?.url || "/");
157
154
  if (!localePage) {
158
155
  continue;
159
156
  }
160
157
  if (options.url) {
161
- return replacePath(localePage.url, options.url);
158
+ return replacePath(localizedRoute, options.url);
162
159
  }
163
160
  if (options.params) {
164
- return replacePath(localePage.url, options.params);
161
+ return replacePath(localizedRoute, options.params);
165
162
  }
166
163
  if (localePage.dynamic && options.dynamicName) {
167
164
  const locale = createLocale(code);
168
- const ctx = createContext(definition, locale, localePage, localePage.url, {});
165
+ const ctx = createContext(definition, locale, localePage, toPublicRoute(runtimeConfig.flow, code, localePage.url), {});
169
166
  const entries = await getDynamicEntries(definition, code, ctx);
170
167
  const entry = entries.find((candidate) => candidate.name === options.dynamicName);
171
168
  if (!entry) {
172
169
  return void 0;
173
170
  }
174
- return replacePath(localePage.url, entry.url);
171
+ return replacePath(localizedRoute, entry.url);
175
172
  }
176
- return toPublicRoutePattern(localePage.url);
173
+ return toPublicRoute(runtimeConfig.flow, code, localePage.url);
177
174
  }
178
175
  }
179
176
  return void 0;
180
177
  }
181
178
  export async function getUrls(withLocale = false, omitNoPublish = false) {
182
179
  const enabledLocales = getEnabledLocaleCodes();
180
+ const runtimeConfig = getFlowRuntimeConfig();
183
181
  const urls = [];
184
182
  for (const definition of pageDefinitions) {
185
183
  if (omitNoPublish && definition.noPublish) {
@@ -191,15 +189,15 @@ export async function getUrls(withLocale = false, omitNoPublish = false) {
191
189
  }
192
190
  if (localePage.dynamic) {
193
191
  const locale = createLocale(localeCode);
194
- const ctx = createContext(definition, locale, localePage, localePage.url, {});
192
+ const ctx = createContext(definition, locale, localePage, toPublicRoute(runtimeConfig.flow, localeCode, localePage.url), {});
195
193
  const entries = await getDynamicEntries(definition, localeCode, ctx);
196
194
  for (const entry of entries) {
197
- const url2 = replacePath(localePage.url, entry.url);
195
+ const url2 = replacePath(localizeRoutePattern(runtimeConfig.flow, localeCode, localePage.url), entry.url);
198
196
  urls.push(withLocale ? { url: url2, locale: localeCode, name: combineName(definition.name, entry.name) } : url2);
199
197
  }
200
198
  continue;
201
199
  }
202
- const url = toPublicRoutePattern(localePage.url);
200
+ const url = toPublicRoute(runtimeConfig.flow, localeCode, localePage.url);
203
201
  urls.push(withLocale ? { url, locale: localeCode, name: definition.name } : url);
204
202
  }
205
203
  }
@@ -214,14 +212,15 @@ export async function resolvePage(pathname) {
214
212
  if (enabledLocales.length && !enabledLocales.includes(localeCode)) {
215
213
  continue;
216
214
  }
217
- const params = matchPattern(localePage.url, pathname);
215
+ const localizedRoute = localizeRoutePattern(runtimeConfig.flow, localeCode, localePage.url);
216
+ const params = matchPattern(localizedRoute, pathname);
218
217
  if (params) {
219
218
  candidates.push({
220
219
  definition,
221
220
  localeCode,
222
221
  localePage,
223
222
  params,
224
- score: scorePattern(localePage.url)
223
+ score: scorePattern(localizedRoute)
225
224
  });
226
225
  }
227
226
  }
@@ -5,7 +5,9 @@ import bases from "virtual:flow/bases";
5
5
  import layouts from "virtual:flow/layouts";
6
6
  import templates from "virtual:flow/templates";
7
7
  import { createSSRApp, defineComponent, h } from "vue";
8
+ import { getFlowImageRuntimeUtils } from "../../modules/images/runtime/server.mjs";
8
9
  import { installFlowVuePlugins } from "../../src/runtime/vue";
10
+ import { getUrl, getUrls } from "./pages.mjs";
9
11
  function escapeHtml(value) {
10
12
  return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
11
13
  }
@@ -104,6 +106,19 @@ async function renderBody(page) {
104
106
  params: page.params,
105
107
  path: page.pathname
106
108
  };
109
+ const imageUtils = getFlowImageRuntimeUtils();
110
+ const utils = {
111
+ getLocale() {
112
+ return page.locale;
113
+ },
114
+ async getUrl(namePage, localeCode, options) {
115
+ return await getUrl(namePage, localeCode || page.locale.code, options);
116
+ },
117
+ async getUrls(withLocale, omitNoPublish) {
118
+ return await getUrls(withLocale, omitNoPublish);
119
+ },
120
+ ...imageUtils || {}
121
+ };
107
122
  const TemplateRoot = defineComponent({
108
123
  render() {
109
124
  const viewNode = h(TemplateComponent, context);
@@ -117,6 +132,7 @@ async function renderBody(page) {
117
132
  });
118
133
  const app = createSSRApp(TemplateRoot);
119
134
  app.provide("context", context);
135
+ app.provide("utils", utils);
120
136
  const head = createHead();
121
137
  head.push(normalizeSeoToHead(page.head, fallbackTitle, fallbackDescription));
122
138
  app.use(head);
@@ -1,3 +1,3 @@
1
1
  export default function renderPage(input: Request | {
2
2
  req?: Request;
3
- }): Promise<Response | undefined>;
3
+ }): Promise<any>;
@@ -38,7 +38,8 @@ async function resolvePrerenderFetchHandler() {
38
38
  export default async function renderPage(input) {
39
39
  const viteEnvs = globalThis.__nitro_vite_envs__;
40
40
  const request = resolveRequest(input);
41
- const viteFetchHandler = viteEnvs?.ssr?.fetch;
41
+ const viteEnv = viteEnvs?.ssr;
42
+ const viteFetchHandler = typeof viteEnv?.fetch === "function" ? viteEnv.fetch.bind(viteEnv) : void 0;
42
43
  if (!request) {
43
44
  return new Response("Not Found", { status: 404 });
44
45
  }
@@ -1 +1,4 @@
1
1
  export { default as FlowIsland } from '../runtime/components/FlowIsland.ts';
2
+ export { default as MkImage } from '../runtime/components/MkImage.ts';
3
+ export { default as MkLink } from '../runtime/components/MkLink.ts';
4
+ export { default as MkPicture } from '../runtime/components/MkPicture.ts';
@@ -1 +1,4 @@
1
1
  export { default as FlowIsland } from "../runtime/components/FlowIsland.mjs";
2
+ export { default as MkImage } from "../runtime/components/MkImage.mjs";
3
+ export { default as MkLink } from "../runtime/components/MkLink.mjs";
4
+ export { default as MkPicture } from "../runtime/components/MkPicture.mjs";