@onruntime/next-sitemap 0.6.1 → 0.7.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/dist/app/index.js CHANGED
@@ -1,9 +1,168 @@
1
- import * as fs from 'fs';
2
- import * as path from 'path';
3
- import { createJiti } from 'jiti';
4
- import stripJsonComments from 'strip-json-comments';
1
+ import { existsSync, readdirSync } from 'fs';
2
+ import { dirname, join, isAbsolute, relative, delimiter } from 'path';
3
+ import * as childProcess from 'child_process';
4
+ import { fileURLToPath } from 'url';
5
5
 
6
6
  // src/app/index.ts
7
+ var NO_STATIC_PARAMS = "NO_STATIC_PARAMS";
8
+ var spawnProcess = childProcess.spawn;
9
+ var __dirname$1 = dirname(fileURLToPath(import.meta.url));
10
+ var paramsCache = /* @__PURE__ */ new Map();
11
+ var isDev = process.env.NODE_ENV === "development";
12
+ async function executeWorker(directory, fileKey, debug) {
13
+ const absolutePath = join(directory, fileKey.replace("./", ""));
14
+ const projectRoot = process.cwd();
15
+ const distRoot = join(__dirname$1, "..");
16
+ const workerPath = join(distRoot, "worker.cjs");
17
+ const loaderPath = join(distRoot, "loader.js");
18
+ if (debug) {
19
+ console.log(`[next-sitemap] Worker path: ${workerPath}`);
20
+ console.log(`[next-sitemap] Worker exists: ${existsSync(workerPath)}`);
21
+ console.log(`[next-sitemap] Loader path: ${loaderPath}`);
22
+ console.log(`[next-sitemap] Loader exists: ${existsSync(loaderPath)}`);
23
+ }
24
+ return new Promise((resolve) => {
25
+ const nodePath = [
26
+ join(projectRoot, "node_modules"),
27
+ join(__dirname$1, "..", "node_modules")
28
+ ].join(delimiter);
29
+ const importFlag = ["--import", loaderPath];
30
+ const args = [...importFlag, workerPath, absolutePath, projectRoot];
31
+ const child = spawnProcess("node", args, {
32
+ cwd: projectRoot,
33
+ stdio: ["ignore", "pipe", "pipe"],
34
+ env: { ...process.env, NODE_PATH: nodePath }
35
+ });
36
+ let stdout = "";
37
+ let stderr = "";
38
+ child.stdout.on("data", (data) => {
39
+ stdout += data.toString();
40
+ });
41
+ child.stderr.on("data", (data) => {
42
+ stderr += data.toString();
43
+ });
44
+ child.on("close", (code) => {
45
+ if (debug && stderr) {
46
+ console.warn(`[next-sitemap] Worker stderr: ${stderr}`);
47
+ }
48
+ if (code !== 0 && code !== null) {
49
+ if (debug) console.warn(`[next-sitemap] Worker exited with code ${code}`);
50
+ resolve(null);
51
+ return;
52
+ }
53
+ try {
54
+ const lines = stdout.trim().split("\n");
55
+ const result = JSON.parse(lines[lines.length - 1]);
56
+ if (result.success) {
57
+ resolve(result.params);
58
+ } else {
59
+ if (result.error !== NO_STATIC_PARAMS && debug) {
60
+ console.warn(`[next-sitemap] Worker error: ${result.error}`);
61
+ }
62
+ resolve(null);
63
+ }
64
+ } catch {
65
+ if (debug) console.warn(`[next-sitemap] Failed to parse worker output: ${stdout}`);
66
+ resolve(null);
67
+ }
68
+ });
69
+ child.on("error", (err) => {
70
+ if (debug) console.warn(`[next-sitemap] Failed to spawn worker: ${err.message}`);
71
+ resolve(null);
72
+ });
73
+ });
74
+ }
75
+ async function getRouteParams(route, directory, debug) {
76
+ const cacheKey = route.fileKey;
77
+ if (paramsCache.has(cacheKey)) {
78
+ return paramsCache.get(cacheKey);
79
+ }
80
+ if (debug) {
81
+ console.log(`[next-sitemap] ${route.pathname}: executing static params via worker`);
82
+ }
83
+ const params = await executeWorker(directory, route.fileKey, debug);
84
+ paramsCache.set(cacheKey, params);
85
+ if (debug && params) {
86
+ console.log(`[next-sitemap] ${route.pathname}: got ${params.length} params`);
87
+ }
88
+ return params;
89
+ }
90
+ async function generateAllPaths(routes, directory, debug) {
91
+ const staticPaths = ["/"];
92
+ const dynamicRoutes = [];
93
+ for (const route of routes) {
94
+ if (route.dynamicSegments.length === 0) {
95
+ if (route.pathname !== "/") {
96
+ staticPaths.push(route.pathname);
97
+ }
98
+ } else {
99
+ dynamicRoutes.push(route);
100
+ }
101
+ }
102
+ const startTime = isDev ? Date.now() : 0;
103
+ if (isDev && dynamicRoutes.length > 0) {
104
+ console.log(`[next-sitemap] Generating sitemap for ${dynamicRoutes.length} dynamic routes (dev only, instant in production)...`);
105
+ }
106
+ const dynamicResults = await Promise.all(
107
+ dynamicRoutes.map(async (route) => {
108
+ const params = await getRouteParams(route, directory, debug);
109
+ if (!params || params.length === 0) {
110
+ if (debug) {
111
+ console.warn(`[next-sitemap] Skipping dynamic route ${route.pathname}: no static params or empty result.`);
112
+ }
113
+ return [];
114
+ }
115
+ const paths = [];
116
+ for (const param of params) {
117
+ let path = route.pathname;
118
+ let valid = true;
119
+ for (const segment of route.dynamicSegments) {
120
+ const value = param[segment];
121
+ if (value === void 0) {
122
+ if (debug) {
123
+ console.warn(`[next-sitemap] ${route.pathname}: missing param "${segment}" in`, param);
124
+ }
125
+ valid = false;
126
+ break;
127
+ }
128
+ path = path.replace(`[${segment}]`, value);
129
+ }
130
+ if (valid) paths.push(path);
131
+ }
132
+ return paths;
133
+ })
134
+ );
135
+ const allPaths = new Set(staticPaths);
136
+ for (const paths of dynamicResults) {
137
+ for (const path of paths) {
138
+ allPaths.add(path);
139
+ }
140
+ }
141
+ if (isDev && dynamicRoutes.length > 0) {
142
+ const elapsed = Date.now() - startTime;
143
+ console.log(`[next-sitemap] Done! Found ${allPaths.size} total URLs in ${elapsed}ms.`);
144
+ }
145
+ return Array.from(allPaths);
146
+ }
147
+ function pathsToEntries(paths, config) {
148
+ const { baseUrl, locales = [], defaultLocale, exclude, priority, changeFreq } = config;
149
+ return paths.filter((pathname) => !shouldExclude(pathname, exclude)).map((pathname) => {
150
+ const entry = {
151
+ url: buildUrl(baseUrl, pathname, defaultLocale, defaultLocale),
152
+ lastModified: /* @__PURE__ */ new Date(),
153
+ changeFrequency: getChangeFreq(pathname, changeFreq),
154
+ priority: getPriority(pathname, priority)
155
+ };
156
+ if (locales.length > 0) {
157
+ entry.alternates = {
158
+ languages: Object.fromEntries(
159
+ locales.map((locale) => [locale, buildUrl(baseUrl, pathname, locale, defaultLocale)])
160
+ )
161
+ };
162
+ }
163
+ return entry;
164
+ });
165
+ }
7
166
 
8
167
  // src/index.ts
9
168
  function calculateDepthPriority(pathname) {
@@ -109,13 +268,13 @@ ${allEntries}
109
268
  function findPageFiles(dir, baseDir = dir) {
110
269
  const files = [];
111
270
  try {
112
- const entries = fs.readdirSync(dir, { withFileTypes: true });
271
+ const entries = readdirSync(dir, { withFileTypes: true });
113
272
  for (const entry of entries) {
114
- const fullPath = path.join(dir, entry.name);
273
+ const fullPath = join(dir, entry.name);
115
274
  if (entry.isDirectory()) {
116
275
  files.push(...findPageFiles(fullPath, baseDir));
117
276
  } else if (/^page\.(tsx?|jsx?)$/.test(entry.name)) {
118
- const relativePath = "./" + path.relative(baseDir, fullPath).replace(/\\/g, "/");
277
+ const relativePath = "./" + relative(baseDir, fullPath).replace(/\\/g, "/");
119
278
  files.push(relativePath);
120
279
  }
121
280
  }
@@ -123,83 +282,12 @@ function findPageFiles(dir, baseDir = dir) {
123
282
  }
124
283
  return files;
125
284
  }
126
- function detectAppDirectory() {
127
- const srcApp = path.join(process.cwd(), "src/app");
128
- if (fs.existsSync(srcApp)) {
129
- return srcApp;
130
- }
131
- return path.join(process.cwd(), "app");
132
- }
133
- function resolveAppDirectory(options) {
134
- if (options.appDirectory) {
135
- return path.isAbsolute(options.appDirectory) ? options.appDirectory : path.join(process.cwd(), options.appDirectory);
285
+ function resolveAppDirectory(appDirectory) {
286
+ if (appDirectory) {
287
+ return isAbsolute(appDirectory) ? appDirectory : join(process.cwd(), appDirectory);
136
288
  }
137
- return detectAppDirectory();
138
- }
139
- function getPageKeys(options) {
140
- return findPageFiles(resolveAppDirectory(options));
141
- }
142
- var jitiCache = /* @__PURE__ */ new Map();
143
- function getTsconfigPaths(projectRoot, debug = false) {
144
- const alias = {};
145
- try {
146
- const tsconfigPath = path.join(projectRoot, "tsconfig.json");
147
- if (debug) {
148
- console.log("[next-sitemap] Looking for tsconfig at:", tsconfigPath);
149
- console.log("[next-sitemap] tsconfig exists:", fs.existsSync(tsconfigPath));
150
- }
151
- if (fs.existsSync(tsconfigPath)) {
152
- const content = fs.readFileSync(tsconfigPath, "utf-8");
153
- const withoutComments = stripJsonComments(content);
154
- const cleaned = withoutComments.replace(/,(\s*[}\]])/g, "$1");
155
- if (debug) {
156
- console.log("[next-sitemap] Cleaned tsconfig (first 500 chars):", cleaned.slice(0, 500));
157
- }
158
- const tsconfig = JSON.parse(cleaned);
159
- if (debug) {
160
- console.log("[next-sitemap] Parsed tsconfig paths:", tsconfig.compilerOptions?.paths);
161
- }
162
- const baseUrl = tsconfig.compilerOptions?.baseUrl || ".";
163
- const paths = tsconfig.compilerOptions?.paths || {};
164
- for (const [key, values] of Object.entries(paths)) {
165
- if (values.length > 0) {
166
- const aliasKey = key.replace(/\*$/, "");
167
- const aliasValue = path.join(projectRoot, baseUrl, values[0].replace(/\*$/, ""));
168
- alias[aliasKey] = aliasValue;
169
- }
170
- }
171
- }
172
- } catch (error) {
173
- if (debug) {
174
- console.error("[next-sitemap] Error parsing tsconfig:", error);
175
- }
176
- }
177
- return alias;
178
- }
179
- function getJiti(projectRoot, debug = false) {
180
- if (jitiCache.has(projectRoot)) {
181
- return jitiCache.get(projectRoot);
182
- }
183
- const alias = getTsconfigPaths(projectRoot, debug);
184
- if (debug) {
185
- console.log("[next-sitemap] Final alias config:", JSON.stringify(alias));
186
- }
187
- const jiti = createJiti(import.meta.url, {
188
- moduleCache: false,
189
- interopDefault: true,
190
- jsx: true,
191
- alias
192
- });
193
- jitiCache.set(projectRoot, jiti);
194
- return jiti;
195
- }
196
- async function importPage(appDirectory, key, debug = false) {
197
- const relativePath = key.replace("./", "");
198
- const absolutePath = path.join(appDirectory, relativePath);
199
- const projectRoot = process.cwd();
200
- const jiti = getJiti(projectRoot, debug);
201
- const module = await jiti.import(absolutePath);
202
- return module.default || module;
289
+ const srcApp = join(process.cwd(), "src/app");
290
+ return existsSync(srcApp) ? srcApp : join(process.cwd(), "app");
203
291
  }
204
292
  function extractRoutes(pageKeys, localeSegment) {
205
293
  const routes = [];
@@ -207,163 +295,64 @@ function extractRoutes(pageKeys, localeSegment) {
207
295
  if (key.includes("[...")) continue;
208
296
  let pathname = key.replace("./", "/").replace(/\/page\.(tsx?|jsx?)$/, "");
209
297
  if (localeSegment) {
210
- pathname = pathname.replace(
211
- new RegExp(`^/${localeSegment.replace(/[[\]]/g, "\\$&")}`),
212
- ""
213
- );
298
+ const escapedSegment = localeSegment.replace(/[[\]]/g, "\\$&");
299
+ pathname = pathname.replace(new RegExp(`^/${escapedSegment}`), "");
214
300
  }
215
301
  pathname = pathname.replace(/\/\([^)]+\)/g, "");
216
302
  if (/(?:^|\/)(src|app)(?:\/|$)/.test(pathname)) continue;
217
- if (!pathname || pathname === "") {
218
- pathname = "/";
219
- } else if (!pathname.startsWith("/")) {
303
+ pathname = pathname || "/";
304
+ if (pathname !== "/" && !pathname.startsWith("/")) {
220
305
  pathname = "/" + pathname;
221
306
  }
222
- const dynamicSegments = pathname.match(/\[([^\]]+)\]/g)?.map((s) => s.slice(1, -1)) || [];
223
- routes.push({
224
- pathname,
225
- dynamicSegments,
226
- key
227
- });
307
+ const dynamicSegments = pathname.match(/\[([^\]]+)\]/g)?.map((s) => s.slice(1, -1)) ?? [];
308
+ routes.push({ pathname, dynamicSegments, fileKey: key });
228
309
  }
229
310
  return routes;
230
311
  }
231
- async function getAllPaths(routes, appDirectory, debug = false) {
232
- const allPaths = ["/"];
233
- const seenPaths = /* @__PURE__ */ new Set(["/"]);
234
- for (const route of routes) {
235
- if (route.dynamicSegments.length === 0) {
236
- if (route.pathname !== "/" && !seenPaths.has(route.pathname)) {
237
- allPaths.push(route.pathname);
238
- seenPaths.add(route.pathname);
239
- }
240
- } else {
241
- let getParams = null;
242
- try {
243
- if (debug) {
244
- console.log(`[next-sitemap] ${route.pathname}: importing ${route.key}`);
245
- }
246
- const module = await importPage(appDirectory, route.key, debug);
247
- getParams = module.generateStaticParams || null;
248
- } catch (error) {
249
- if (debug) {
250
- console.warn(`[next-sitemap] ${route.pathname}: import failed:`, error);
251
- }
252
- }
253
- if (getParams) {
254
- try {
255
- const params = await getParams();
256
- if (debug) {
257
- console.log(`[next-sitemap] ${route.pathname}: generateStaticParams returned ${params.length} params`);
258
- }
259
- for (const param of params) {
260
- let dynamicPath = route.pathname;
261
- for (const segment of route.dynamicSegments) {
262
- const value = param[segment];
263
- if (value === void 0) {
264
- if (debug) {
265
- console.warn(`[next-sitemap] ${route.pathname}: missing param "${segment}" in`, param);
266
- }
267
- continue;
268
- }
269
- dynamicPath = dynamicPath.replace(`[${segment}]`, value);
270
- }
271
- if (!seenPaths.has(dynamicPath)) {
272
- allPaths.push(dynamicPath);
273
- seenPaths.add(dynamicPath);
274
- }
275
- }
276
- } catch (error) {
277
- console.error(`[next-sitemap] Error calling generateStaticParams for ${route.pathname}:`, error);
278
- }
279
- } else {
280
- if (debug) {
281
- console.warn(
282
- `[next-sitemap] Skipping dynamic route ${route.pathname}: no generateStaticParams exported. Use additionalSitemaps for routes that fetch data at runtime.`
283
- );
284
- }
285
- }
286
- }
287
- }
288
- return allPaths;
289
- }
290
- function pathsToEntries(paths, config) {
291
- const { baseUrl, locales = [], defaultLocale, exclude, priority, changeFreq } = config;
292
- const filteredPaths = paths.filter((pathname) => !shouldExclude(pathname, exclude));
293
- return filteredPaths.map((pathname) => {
294
- const entry = {
295
- url: buildUrl(baseUrl, pathname, defaultLocale, defaultLocale),
296
- lastModified: /* @__PURE__ */ new Date(),
297
- changeFrequency: getChangeFreq(pathname, changeFreq),
298
- priority: getPriority(pathname, priority)
299
- };
300
- if (locales.length > 0) {
301
- entry.alternates = {
302
- languages: Object.fromEntries(
303
- locales.map((locale) => [
304
- locale,
305
- buildUrl(baseUrl, pathname, locale, defaultLocale)
306
- ])
307
- )
308
- };
309
- }
310
- return entry;
311
- });
312
- }
313
312
  function createSitemapIndexHandler(options) {
314
313
  const { urlsPerSitemap = 5e3, locales = [], defaultLocale, additionalSitemaps, exclude, debug = false } = options;
315
314
  const localeSegment = options.localeSegment ?? (locales.length > 0 || defaultLocale ? "[locale]" : "");
316
- const appDir = resolveAppDirectory(options);
317
- const pageKeys = getPageKeys(options);
315
+ const appDir = resolveAppDirectory(options.appDirectory);
316
+ const pageKeys = findPageFiles(appDir);
318
317
  const routes = extractRoutes(pageKeys, localeSegment);
319
318
  return {
320
319
  GET: async () => {
321
320
  if (debug) {
322
- console.log(`[next-sitemap] Found ${routes.length} routes:`);
323
- routes.forEach((r) => {
324
- const isDynamic = r.dynamicSegments.length > 0;
325
- const segments = isDynamic ? ` [${r.dynamicSegments.join(", ")}]` : "";
326
- console.log(` ${r.pathname}${segments}${isDynamic ? " (dynamic)" : ""}`);
327
- });
321
+ console.log(`[next-sitemap] Found ${routes.length} routes`);
328
322
  }
329
- const allPaths = await getAllPaths(routes, appDir, debug);
330
- const filteredPaths = allPaths.filter((pathname) => !shouldExclude(pathname, exclude));
323
+ const allPaths = await generateAllPaths(routes, appDir, debug);
324
+ const filteredPaths = allPaths.filter((p) => !shouldExclude(p, exclude));
331
325
  const sitemapCount = Math.max(1, Math.ceil(filteredPaths.length / urlsPerSitemap));
332
- const xml = generateSitemapIndexXml(options.baseUrl, sitemapCount, {
333
- additionalSitemaps
334
- });
335
- return new Response(xml, {
336
- headers: { "Content-Type": "application/xml" }
337
- });
326
+ return new Response(
327
+ generateSitemapIndexXml(options.baseUrl, sitemapCount, { additionalSitemaps }),
328
+ { headers: { "Content-Type": "application/xml" } }
329
+ );
338
330
  }
339
331
  };
340
332
  }
341
333
  function createSitemapHandler(options) {
342
334
  const { urlsPerSitemap = 5e3, locales = [], defaultLocale, exclude, debug = false } = options;
343
335
  const localeSegment = options.localeSegment ?? (locales.length > 0 || defaultLocale ? "[locale]" : "");
344
- const appDir = resolveAppDirectory(options);
345
- const pageKeys = getPageKeys(options);
336
+ const appDir = resolveAppDirectory(options.appDirectory);
337
+ const pageKeys = findPageFiles(appDir);
346
338
  const routes = extractRoutes(pageKeys, localeSegment);
347
339
  const getFilteredPaths = async () => {
348
- const allPaths = await getAllPaths(routes, appDir, debug);
349
- return allPaths.filter((pathname) => !shouldExclude(pathname, exclude));
340
+ const allPaths = await generateAllPaths(routes, appDir, debug);
341
+ return allPaths.filter((p) => !shouldExclude(p, exclude));
350
342
  };
351
343
  return {
352
344
  generateStaticParams: async () => {
353
345
  const filteredPaths = await getFilteredPaths();
354
- const sitemapCount = Math.max(1, Math.ceil(filteredPaths.length / urlsPerSitemap));
355
- return Array.from({ length: sitemapCount }, (_, i) => ({ id: String(i) }));
346
+ const count = Math.max(1, Math.ceil(filteredPaths.length / urlsPerSitemap));
347
+ return Array.from({ length: count }, (_, i) => ({ id: String(i) }));
356
348
  },
357
349
  GET: async (_request, { params }) => {
358
350
  const { id } = await params;
359
351
  const sitemapId = parseInt(id, 10);
360
352
  const filteredPaths = await getFilteredPaths();
361
- const start = sitemapId * urlsPerSitemap;
362
- const end = start + urlsPerSitemap;
363
- const paths = filteredPaths.slice(start, end);
353
+ const paths = filteredPaths.slice(sitemapId * urlsPerSitemap, (sitemapId + 1) * urlsPerSitemap);
364
354
  const entries = pathsToEntries(paths, { ...options, exclude: void 0 });
365
- const xml = generateSitemapXml(entries);
366
- return new Response(xml, {
355
+ return new Response(generateSitemapXml(entries), {
367
356
  headers: { "Content-Type": "application/xml" }
368
357
  });
369
358
  }
package/dist/index.cjs CHANGED
@@ -1,5 +1,204 @@
1
1
  'use strict';
2
2
 
3
+ var fs = require('fs');
4
+ var path = require('path');
5
+ var childProcess = require('child_process');
6
+ var url = require('url');
7
+
8
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
9
+ function _interopNamespace(e) {
10
+ if (e && e.__esModule) return e;
11
+ var n = Object.create(null);
12
+ if (e) {
13
+ Object.keys(e).forEach(function (k) {
14
+ if (k !== 'default') {
15
+ var d = Object.getOwnPropertyDescriptor(e, k);
16
+ Object.defineProperty(n, k, d.get ? d : {
17
+ enumerable: true,
18
+ get: function () { return e[k]; }
19
+ });
20
+ }
21
+ });
22
+ }
23
+ n.default = e;
24
+ return Object.freeze(n);
25
+ }
26
+
27
+ var childProcess__namespace = /*#__PURE__*/_interopNamespace(childProcess);
28
+
29
+ // src/shared.ts
30
+ var JS_EXTENSIONS = /* @__PURE__ */ new Set([
31
+ ".js",
32
+ ".cjs",
33
+ ".mjs",
34
+ ".jsx",
35
+ ".ts",
36
+ ".cts",
37
+ ".mts",
38
+ ".tsx",
39
+ ".json",
40
+ ".node"
41
+ ]);
42
+ var NO_STATIC_PARAMS = "NO_STATIC_PARAMS";
43
+ var spawnProcess = childProcess__namespace.spawn;
44
+ var __dirname$1 = path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))));
45
+ var paramsCache = /* @__PURE__ */ new Map();
46
+ var isDev = process.env.NODE_ENV === "development";
47
+ async function executeWorker(directory, fileKey, debug) {
48
+ const absolutePath = path.join(directory, fileKey.replace("./", ""));
49
+ const projectRoot = process.cwd();
50
+ const distRoot = path.join(__dirname$1, "..");
51
+ const workerPath = path.join(distRoot, "worker.cjs");
52
+ const loaderPath = path.join(distRoot, "loader.js");
53
+ if (debug) {
54
+ console.log(`[next-sitemap] Worker path: ${workerPath}`);
55
+ console.log(`[next-sitemap] Worker exists: ${fs.existsSync(workerPath)}`);
56
+ console.log(`[next-sitemap] Loader path: ${loaderPath}`);
57
+ console.log(`[next-sitemap] Loader exists: ${fs.existsSync(loaderPath)}`);
58
+ }
59
+ return new Promise((resolve) => {
60
+ const nodePath = [
61
+ path.join(projectRoot, "node_modules"),
62
+ path.join(__dirname$1, "..", "node_modules")
63
+ ].join(path.delimiter);
64
+ const importFlag = ["--import", loaderPath];
65
+ const args = [...importFlag, workerPath, absolutePath, projectRoot];
66
+ const child = spawnProcess("node", args, {
67
+ cwd: projectRoot,
68
+ stdio: ["ignore", "pipe", "pipe"],
69
+ env: { ...process.env, NODE_PATH: nodePath }
70
+ });
71
+ let stdout = "";
72
+ let stderr = "";
73
+ child.stdout.on("data", (data) => {
74
+ stdout += data.toString();
75
+ });
76
+ child.stderr.on("data", (data) => {
77
+ stderr += data.toString();
78
+ });
79
+ child.on("close", (code) => {
80
+ if (debug && stderr) {
81
+ console.warn(`[next-sitemap] Worker stderr: ${stderr}`);
82
+ }
83
+ if (code !== 0 && code !== null) {
84
+ if (debug) console.warn(`[next-sitemap] Worker exited with code ${code}`);
85
+ resolve(null);
86
+ return;
87
+ }
88
+ try {
89
+ const lines = stdout.trim().split("\n");
90
+ const result = JSON.parse(lines[lines.length - 1]);
91
+ if (result.success) {
92
+ resolve(result.params);
93
+ } else {
94
+ if (result.error !== NO_STATIC_PARAMS && debug) {
95
+ console.warn(`[next-sitemap] Worker error: ${result.error}`);
96
+ }
97
+ resolve(null);
98
+ }
99
+ } catch {
100
+ if (debug) console.warn(`[next-sitemap] Failed to parse worker output: ${stdout}`);
101
+ resolve(null);
102
+ }
103
+ });
104
+ child.on("error", (err) => {
105
+ if (debug) console.warn(`[next-sitemap] Failed to spawn worker: ${err.message}`);
106
+ resolve(null);
107
+ });
108
+ });
109
+ }
110
+ async function getRouteParams(route, directory, debug) {
111
+ const cacheKey = route.fileKey;
112
+ if (paramsCache.has(cacheKey)) {
113
+ return paramsCache.get(cacheKey);
114
+ }
115
+ if (debug) {
116
+ console.log(`[next-sitemap] ${route.pathname}: executing static params via worker`);
117
+ }
118
+ const params = await executeWorker(directory, route.fileKey, debug);
119
+ paramsCache.set(cacheKey, params);
120
+ if (debug && params) {
121
+ console.log(`[next-sitemap] ${route.pathname}: got ${params.length} params`);
122
+ }
123
+ return params;
124
+ }
125
+ async function generateAllPaths(routes, directory, debug) {
126
+ const staticPaths = ["/"];
127
+ const dynamicRoutes = [];
128
+ for (const route of routes) {
129
+ if (route.dynamicSegments.length === 0) {
130
+ if (route.pathname !== "/") {
131
+ staticPaths.push(route.pathname);
132
+ }
133
+ } else {
134
+ dynamicRoutes.push(route);
135
+ }
136
+ }
137
+ const startTime = isDev ? Date.now() : 0;
138
+ if (isDev && dynamicRoutes.length > 0) {
139
+ console.log(`[next-sitemap] Generating sitemap for ${dynamicRoutes.length} dynamic routes (dev only, instant in production)...`);
140
+ }
141
+ const dynamicResults = await Promise.all(
142
+ dynamicRoutes.map(async (route) => {
143
+ const params = await getRouteParams(route, directory, debug);
144
+ if (!params || params.length === 0) {
145
+ if (debug) {
146
+ console.warn(`[next-sitemap] Skipping dynamic route ${route.pathname}: no static params or empty result.`);
147
+ }
148
+ return [];
149
+ }
150
+ const paths = [];
151
+ for (const param of params) {
152
+ let path = route.pathname;
153
+ let valid = true;
154
+ for (const segment of route.dynamicSegments) {
155
+ const value = param[segment];
156
+ if (value === void 0) {
157
+ if (debug) {
158
+ console.warn(`[next-sitemap] ${route.pathname}: missing param "${segment}" in`, param);
159
+ }
160
+ valid = false;
161
+ break;
162
+ }
163
+ path = path.replace(`[${segment}]`, value);
164
+ }
165
+ if (valid) paths.push(path);
166
+ }
167
+ return paths;
168
+ })
169
+ );
170
+ const allPaths = new Set(staticPaths);
171
+ for (const paths of dynamicResults) {
172
+ for (const path of paths) {
173
+ allPaths.add(path);
174
+ }
175
+ }
176
+ if (isDev && dynamicRoutes.length > 0) {
177
+ const elapsed = Date.now() - startTime;
178
+ console.log(`[next-sitemap] Done! Found ${allPaths.size} total URLs in ${elapsed}ms.`);
179
+ }
180
+ return Array.from(allPaths);
181
+ }
182
+ function pathsToEntries(paths, config) {
183
+ const { baseUrl, locales = [], defaultLocale, exclude, priority, changeFreq } = config;
184
+ return paths.filter((pathname) => !shouldExclude(pathname, exclude)).map((pathname) => {
185
+ const entry = {
186
+ url: buildUrl(baseUrl, pathname, defaultLocale, defaultLocale),
187
+ lastModified: /* @__PURE__ */ new Date(),
188
+ changeFrequency: getChangeFreq(pathname, changeFreq),
189
+ priority: getPriority(pathname, priority)
190
+ };
191
+ if (locales.length > 0) {
192
+ entry.alternates = {
193
+ languages: Object.fromEntries(
194
+ locales.map((locale) => [locale, buildUrl(baseUrl, pathname, locale, defaultLocale)])
195
+ )
196
+ };
197
+ }
198
+ return entry;
199
+ });
200
+ }
201
+
3
202
  // src/index.ts
4
203
  function calculateDepthPriority(pathname) {
5
204
  if (pathname === "/") return 1;
@@ -100,11 +299,19 @@ ${allEntries}
100
299
  </sitemapindex>`;
101
300
  }
102
301
 
302
+ exports.JS_EXTENSIONS = JS_EXTENSIONS;
303
+ exports.NO_STATIC_PARAMS = NO_STATIC_PARAMS;
103
304
  exports.buildUrl = buildUrl;
104
305
  exports.calculateDepthPriority = calculateDepthPriority;
306
+ exports.executeWorker = executeWorker;
307
+ exports.generateAllPaths = generateAllPaths;
105
308
  exports.generateSitemapIndexXml = generateSitemapIndexXml;
106
309
  exports.generateSitemapXml = generateSitemapXml;
107
310
  exports.getChangeFreq = getChangeFreq;
108
311
  exports.getPriority = getPriority;
312
+ exports.getRouteParams = getRouteParams;
313
+ exports.isDev = isDev;
109
314
  exports.normalizePath = normalizePath;
315
+ exports.paramsCache = paramsCache;
316
+ exports.pathsToEntries = pathsToEntries;
110
317
  exports.shouldExclude = shouldExclude;