@analogjs/vite-plugin-nitro 3.0.0-alpha.7 → 3.0.0-alpha.70

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 (74) hide show
  1. package/package.json +31 -11
  2. package/src/index.d.ts +19 -9
  3. package/src/index.js +9 -2
  4. package/src/index.js.map +1 -1
  5. package/src/lib/build-server.d.ts +2 -2
  6. package/src/lib/build-server.js +45 -149
  7. package/src/lib/build-server.js.map +1 -1
  8. package/src/lib/build-sitemap.d.ts +23 -9
  9. package/src/lib/build-sitemap.js +132 -63
  10. package/src/lib/build-sitemap.js.map +1 -1
  11. package/src/lib/build-ssr.d.ts +3 -2
  12. package/src/lib/build-ssr.js +26 -18
  13. package/src/lib/build-ssr.js.map +1 -1
  14. package/src/lib/hooks/post-rendering-hook.d.ts +1 -1
  15. package/src/lib/hooks/post-rendering-hook.js +10 -6
  16. package/src/lib/hooks/post-rendering-hook.js.map +1 -1
  17. package/src/lib/options.d.ts +148 -106
  18. package/src/lib/plugins/dev-server-plugin.d.ts +3 -3
  19. package/src/lib/plugins/dev-server-plugin.js +99 -101
  20. package/src/lib/plugins/dev-server-plugin.js.map +1 -1
  21. package/src/lib/plugins/page-endpoints.d.ts +5 -5
  22. package/src/lib/plugins/page-endpoints.js +26 -46
  23. package/src/lib/plugins/page-endpoints.js.map +1 -1
  24. package/src/lib/plugins/server-fn-id-plugin.d.ts +11 -0
  25. package/src/lib/plugins/server-fn-id-plugin.js +27 -0
  26. package/src/lib/plugins/server-fn-id-plugin.js.map +1 -0
  27. package/src/lib/utils/debug.d.ts +5 -0
  28. package/src/lib/utils/debug.js +15 -0
  29. package/src/lib/utils/debug.js.map +1 -0
  30. package/src/lib/utils/derive-server-fn-id.d.ts +25 -0
  31. package/src/lib/utils/derive-server-fn-id.js +37 -0
  32. package/src/lib/utils/derive-server-fn-id.js.map +1 -0
  33. package/src/lib/utils/get-content-files.d.ts +55 -55
  34. package/src/lib/utils/get-content-files.js +95 -97
  35. package/src/lib/utils/get-content-files.js.map +1 -1
  36. package/src/lib/utils/get-page-handlers.d.ts +55 -58
  37. package/src/lib/utils/get-page-handlers.js +67 -84
  38. package/src/lib/utils/get-page-handlers.js.map +1 -1
  39. package/src/lib/utils/get-server-fn-handlers.d.ts +28 -0
  40. package/src/lib/utils/get-server-fn-handlers.js +45 -0
  41. package/src/lib/utils/get-server-fn-handlers.js.map +1 -0
  42. package/src/lib/utils/i18n-prerender.d.ts +36 -0
  43. package/src/lib/utils/i18n-prerender.js +23 -0
  44. package/src/lib/utils/i18n-prerender.js.map +1 -0
  45. package/src/lib/utils/inject-server-fn-ids.d.ts +17 -0
  46. package/src/lib/utils/inject-server-fn-ids.js +94 -0
  47. package/src/lib/utils/inject-server-fn-ids.js.map +1 -0
  48. package/src/lib/utils/load-esm.d.ts +18 -18
  49. package/src/lib/utils/node-web-bridge.d.ts +1 -1
  50. package/src/lib/utils/node-web-bridge.js +50 -45
  51. package/src/lib/utils/node-web-bridge.js.map +1 -1
  52. package/src/lib/utils/register-dev-middleware.d.ts +12 -12
  53. package/src/lib/utils/register-dev-middleware.js +41 -47
  54. package/src/lib/utils/register-dev-middleware.js.map +1 -1
  55. package/src/lib/utils/register-i18n-watcher.d.ts +15 -0
  56. package/src/lib/utils/register-i18n-watcher.js +27 -0
  57. package/src/lib/utils/register-i18n-watcher.js.map +1 -0
  58. package/src/lib/utils/renderers.d.ts +29 -49
  59. package/src/lib/utils/renderers.js +37 -80
  60. package/src/lib/utils/renderers.js.map +1 -1
  61. package/src/lib/utils/rolldown.d.ts +2 -0
  62. package/src/lib/utils/rolldown.js +12 -0
  63. package/src/lib/utils/rolldown.js.map +1 -0
  64. package/src/lib/utils/server-fn-endpoints.d.ts +41 -0
  65. package/src/lib/utils/server-fn-endpoints.js +57 -0
  66. package/src/lib/utils/server-fn-endpoints.js.map +1 -0
  67. package/src/lib/vite-plugin-nitro.d.ts +3 -3
  68. package/src/lib/vite-plugin-nitro.js +793 -678
  69. package/src/lib/vite-plugin-nitro.js.map +1 -1
  70. package/README.md +0 -125
  71. package/src/lib/options.js +0 -2
  72. package/src/lib/options.js.map +0 -1
  73. package/src/lib/utils/load-esm.js +0 -23
  74. package/src/lib/utils/load-esm.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"dev-server-plugin.js","sourceRoot":"","sources":["../../../../../../packages/vite-plugin-nitro/src/lib/plugins/dev-server-plugin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dev-server-plugin.js","names":[],"sources":["../../../../src/lib/plugins/dev-server-plugin.ts"],"sourcesContent":["// SSR dev server, middleware and error page source modified from\n// https://github.com/solidjs/solid-start/blob/main/packages/start/dev/server.js\n\nimport {\n Connect,\n Plugin,\n UserConfig,\n ViteDevServer,\n normalizePath,\n} from 'vite';\nimport { resolve } from 'node:path';\nimport { readFileSync } from 'node:fs';\nimport { createRouter as createRadixRouter, toRouteMatcher } from 'radix3';\nimport { defu } from 'defu';\nimport type { NitroRouteRules } from 'nitro/types';\n\nimport { registerDevServerMiddleware } from '../utils/register-dev-middleware.js';\nimport { registerI18nWatcher } from '../utils/register-i18n-watcher.js';\nimport { writeWebResponseToNode } from '../utils/node-web-bridge.js';\nimport { Options } from '../options.js';\nimport { detectLocaleFromRoute, setHtmlLang } from '../utils/i18n-prerender.js';\n\ntype ServerOptions = Options & { routeRules?: Record<string, any> | undefined };\n\nexport function devServerPlugin(options: ServerOptions): Plugin {\n const workspaceRoot = options?.workspaceRoot || process.cwd();\n const sourceRoot = options?.sourceRoot ?? 'src';\n const index = options.index || 'index.html';\n let config: UserConfig;\n let root: string;\n let isTest = false;\n\n return {\n name: 'analogjs-dev-ssr-plugin',\n config(userConfig, { mode }) {\n config = userConfig;\n root = normalizePath(resolve(workspaceRoot, config.root || '.') || '.');\n isTest = isTest ? isTest : mode === 'test';\n return {\n appType: 'custom',\n resolve: {\n alias: {\n '~analog/entry-server':\n options.entryServer || `${root}/${sourceRoot}/main.server.ts`,\n },\n },\n };\n },\n configureServer(viteServer) {\n if (isTest) {\n return;\n }\n\n return async () => {\n remove_html_middlewares(viteServer.middlewares);\n registerDevServerMiddleware(root, sourceRoot, viteServer);\n\n if (options.i18n) {\n registerI18nWatcher(viteServer);\n }\n\n viteServer.middlewares.use(async (req, res) => {\n let template = readFileSync(\n resolve(viteServer.config.root, index),\n 'utf-8',\n );\n\n template = await viteServer.transformIndexHtml(\n req.originalUrl as string,\n template,\n );\n\n const _routeRulesMatcher = toRouteMatcher(\n createRadixRouter({ routes: options.routeRules }),\n );\n const _getRouteRules = (path: string) =>\n defu(\n {},\n ..._routeRulesMatcher.matchAll(path).reverse(),\n ) as NitroRouteRules;\n\n try {\n let result: string | Response;\n // Check for route rules explicitly disabling SSR\n if (_getRouteRules(req.originalUrl as string).ssr === false) {\n result = template;\n } else {\n const entryServer = (\n await viteServer.ssrLoadModule('~analog/entry-server')\n )['default'];\n result = await entryServer(req.originalUrl, template, {\n req,\n res,\n });\n }\n\n if (result instanceof Response) {\n await writeWebResponseToNode(res, result);\n return;\n }\n\n // Inject lang attribute when i18n is configured\n let html = typeof result === 'string' ? result : template;\n if (options.i18n) {\n const locale = detectLocaleFromRoute(\n req.originalUrl as string,\n options.i18n,\n );\n html = setHtmlLang(html, locale);\n }\n\n res.setHeader('Content-Type', 'text/html');\n res.end(html);\n } catch (e) {\n viteServer.ssrFixStacktrace(e as Error);\n res.statusCode = 500;\n res.end(`\n <!DOCTYPE html>\n <html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <title>Error</title>\n <script type=\"module\">\n import { ErrorOverlay } from '/@vite/client'\n document.body.appendChild(new ErrorOverlay(${JSON.stringify(\n prepareError(req, e),\n ).replace(/</g, '\\\\u003c')}))\n </script>\n </head>\n <body>\n </body>\n </html>\n `);\n }\n });\n };\n },\n };\n}\n\n/**\n * Removes Vite internal middleware\n *\n * @param server\n */\nfunction remove_html_middlewares(server: ViteDevServer['middlewares']) {\n const html_middlewares = [\n 'viteIndexHtmlMiddleware',\n 'vite404Middleware',\n 'viteSpaFallbackMiddleware',\n 'viteHtmlFallbackMiddleware',\n ];\n for (let i = server.stack.length - 1; i > 0; i--) {\n const handler = server.stack[i]?.handle;\n const handlerName =\n typeof handler === 'function' ? handler.name : undefined;\n if (handlerName && html_middlewares.includes(handlerName)) {\n server.stack.splice(i, 1);\n }\n }\n}\n\n/**\n * Formats error for SSR message in error overlay\n * @param req\n * @param error\n * @returns\n */\nfunction prepareError(req: Connect.IncomingMessage, error: unknown) {\n const e = error as Error;\n return {\n message: `An error occured while server rendering ${req.url}:\\n\\n\\t${\n typeof e === 'string' ? e : e.message\n } `,\n stack: typeof e === 'string' ? '' : e.stack,\n };\n}\n"],"mappings":";;;;;;;;;;AAwBA,SAAgB,gBAAgB,SAAgC;CAC9D,MAAM,gBAAgB,SAAS,iBAAiB,QAAQ,KAAK;CAC7D,MAAM,aAAa,SAAS,cAAc;CAC1C,MAAM,QAAQ,QAAQ,SAAS;CAC/B,IAAI;CACJ,IAAI;CACJ,IAAI,SAAS;AAEb,QAAO;EACL,MAAM;EACN,OAAO,YAAY,EAAE,QAAQ;AAC3B,YAAS;AACT,UAAO,cAAc,QAAQ,eAAe,OAAO,QAAQ,IAAI,IAAI,IAAI;AACvE,YAAS,SAAS,SAAS,SAAS;AACpC,UAAO;IACL,SAAS;IACT,SAAS,EACP,OAAO,EACL,wBACE,QAAQ,eAAe,GAAG,KAAK,GAAG,WAAW,kBAChD,EACF;IACF;;EAEH,gBAAgB,YAAY;AAC1B,OAAI,OACF;AAGF,UAAO,YAAY;AACjB,4BAAwB,WAAW,YAAY;AAC/C,gCAA4B,MAAM,YAAY,WAAW;AAEzD,QAAI,QAAQ,KACV,qBAAoB,WAAW;AAGjC,eAAW,YAAY,IAAI,OAAO,KAAK,QAAQ;KAC7C,IAAI,WAAW,aACb,QAAQ,WAAW,OAAO,MAAM,MAAM,EACtC,QACD;AAED,gBAAW,MAAM,WAAW,mBAC1B,IAAI,aACJ,SACD;KAED,MAAM,qBAAqB,eACzB,aAAkB,EAAE,QAAQ,QAAQ,YAAY,CAAC,CAClD;KACD,MAAM,kBAAkB,SACtB,KACE,EAAE,EACF,GAAG,mBAAmB,SAAS,KAAK,CAAC,SAAS,CAC/C;AAEH,SAAI;MACF,IAAI;AAEJ,UAAI,eAAe,IAAI,YAAsB,CAAC,QAAQ,MACpD,UAAS;WACJ;OACL,MAAM,eACJ,MAAM,WAAW,cAAc,uBAAuB,EACtD;AACF,gBAAS,MAAM,YAAY,IAAI,aAAa,UAAU;QACpD;QACA;QACD,CAAC;;AAGJ,UAAI,kBAAkB,UAAU;AAC9B,aAAM,uBAAuB,KAAK,OAAO;AACzC;;MAIF,IAAI,OAAO,OAAO,WAAW,WAAW,SAAS;AACjD,UAAI,QAAQ,MAAM;OAChB,MAAM,SAAS,sBACb,IAAI,aACJ,QAAQ,KACT;AACD,cAAO,YAAY,MAAM,OAAO;;AAGlC,UAAI,UAAU,gBAAgB,YAAY;AAC1C,UAAI,IAAI,KAAK;cACN,GAAG;AACV,iBAAW,iBAAiB,EAAW;AACvC,UAAI,aAAa;AACjB,UAAI,IAAI;;;;;;;;iEAQ6C,KAAK,UAChD,aAAa,KAAK,EAAE,CACrB,CAAC,QAAQ,MAAM,UAAU,CAAC;;;;;;cAMjC;;MAEJ;;;EAGP;;;;;;;AAQH,SAAS,wBAAwB,QAAsC;CACrE,MAAM,mBAAmB;EACvB;EACA;EACA;EACA;EACD;AACD,MAAK,IAAI,IAAI,OAAO,MAAM,SAAS,GAAG,IAAI,GAAG,KAAK;EAChD,MAAM,UAAU,OAAO,MAAM,IAAI;EACjC,MAAM,cACJ,OAAO,YAAY,aAAa,QAAQ,OAAO,KAAA;AACjD,MAAI,eAAe,iBAAiB,SAAS,YAAY,CACvD,QAAO,MAAM,OAAO,GAAG,EAAE;;;;;;;;;AAW/B,SAAS,aAAa,KAA8B,OAAgB;CAClE,MAAM,IAAI;AACV,QAAO;EACL,SAAS,2CAA2C,IAAI,IAAI,SAC1D,OAAO,MAAM,WAAW,IAAI,EAAE,QAC/B;EACD,OAAO,OAAO,MAAM,WAAW,KAAK,EAAE;EACvC"}
@@ -1,7 +1,7 @@
1
1
  export declare function pageEndpointsPlugin(): {
2
- name: string;
3
- transform(_code: string, id: string): Promise<{
4
- code: string;
5
- map: null;
6
- } | undefined>;
2
+ name: string;
3
+ transform(_code: string, id: string): Promise<{
4
+ code: string;
5
+ map: null;
6
+ } | undefined>;
7
7
  };
@@ -1,48 +1,28 @@
1
- import { parseSync } from 'oxc-parser';
2
- import { normalizePath } from 'vite';
3
- import { SERVER_FETCH_FACTORY_SNIPPET } from '../utils/renderers.js';
4
- export function pageEndpointsPlugin() {
5
- return {
6
- name: 'analogjs-vite-plugin-nitro-rollup-page-endpoint',
7
- async transform(_code, id) {
8
- if (normalizePath(id).includes('/pages/') && id.endsWith('.server.ts')) {
9
- const result = parseSync(id, _code, {
10
- sourceType: 'module',
11
- lang: 'ts',
12
- });
13
- const fileExports = result.module.staticExports.flatMap((e) => e.entries
14
- .filter((entry) => entry.exportName.name !== null)
15
- .map((entry) => entry.exportName.name));
16
- // In h3 v2 / Nitro v3, event.node is undefined during prerendering
17
- // (which uses the fetch-based pipeline, not Node.js http). We use
18
- // optional chaining so that page endpoints work in both Node.js
19
- // server and fetch-based prerender contexts.
20
- // Nitro v3 no longer guarantees the private `nitro/deps/ofetch`
21
- // subpath that older codegen relied on.
22
- //
23
- // Page loaders expect Nitro-style `$fetch` semantics (parsed data plus
24
- // internal relative-route support), so construct a request-local fetch
25
- // using public APIs:
26
- // - `createFetch` from `ofetch` for `$fetch` behavior
27
- // - `fetchWithEvent` from `h3` for internal Nitro request routing
28
- //
29
- // This avoids both unstable private Nitro imports and assumptions about
30
- // a global runtime `$fetch` being available during prerender.
31
- const code = `
1
+ import { SERVER_FETCH_FACTORY_SNIPPET } from "../utils/renderers.js";
2
+ import { normalizePath } from "vite";
3
+ import { parseSync } from "oxc-parser";
4
+ //#region packages/vite-plugin-nitro/src/lib/plugins/page-endpoints.ts
5
+ function pageEndpointsPlugin() {
6
+ return {
7
+ name: "analogjs-vite-plugin-nitro-rollup-page-endpoint",
8
+ async transform(_code, id) {
9
+ if (normalizePath(id).includes("/pages/") && id.endsWith(".server.ts")) {
10
+ const fileExports = parseSync(id, _code, {
11
+ sourceType: "module",
12
+ lang: "ts"
13
+ }).module.staticExports.flatMap((e) => e.entries.filter((entry) => entry.exportName.name !== null).map((entry) => entry.exportName.name));
14
+ return {
15
+ code: `
32
16
  import { defineHandler, fetchWithEvent } from 'nitro/h3';
33
17
  import { createFetch } from 'ofetch';
34
18
 
35
- ${fileExports.includes('load')
36
- ? _code
37
- : `
19
+ ${fileExports.includes("load") ? _code : `
38
20
  ${_code}
39
21
  export const load = () => {
40
22
  return {};
41
23
  }`}
42
24
 
43
- ${fileExports.includes('action')
44
- ? ''
45
- : `
25
+ ${fileExports.includes("action") ? "" : `
46
26
  export const action = () => {
47
27
  return {};
48
28
  }
@@ -79,14 +59,14 @@ export function pageEndpointsPlugin() {
79
59
  }
80
60
  }
81
61
  });
82
- `;
83
- return {
84
- code,
85
- map: null,
86
- };
87
- }
88
- return;
89
- },
90
- };
62
+ `,
63
+ map: null
64
+ };
65
+ }
66
+ }
67
+ };
91
68
  }
69
+ //#endregion
70
+ export { pageEndpointsPlugin };
71
+
92
72
  //# sourceMappingURL=page-endpoints.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"page-endpoints.js","sourceRoot":"","sources":["../../../../../../packages/vite-plugin-nitro/src/lib/plugins/page-endpoints.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AAErE,MAAM,UAAU,mBAAmB;IACjC,OAAO;QACL,IAAI,EAAE,iDAAiD;QACvD,KAAK,CAAC,SAAS,CACb,KAAa,EACb,EAAU;YAEV,IAAI,aAAa,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;gBACvE,MAAM,MAAM,GAAG,SAAS,CAAC,EAAE,EAAE,KAAK,EAAE;oBAClC,UAAU,EAAE,QAAQ;oBACpB,IAAI,EAAE,IAAI;iBACX,CAAC,CAAC;gBAEH,MAAM,WAAW,GAAa,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CACtE,CAAC,CAAC,OAAO;qBACN,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,KAAK,IAAI,CAAC;qBACjD,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,IAAc,CAAC,CACnD,CAAC;gBAEF,mEAAmE;gBACnE,kEAAkE;gBAClE,gEAAgE;gBAChE,6CAA6C;gBAC7C,gEAAgE;gBAChE,wCAAwC;gBACxC,EAAE;gBACF,uEAAuE;gBACvE,uEAAuE;gBACvE,qBAAqB;gBACrB,sDAAsD;gBACtD,kEAAkE;gBAClE,EAAE;gBACF,wEAAwE;gBACxE,8DAA8D;gBAC9D,MAAM,IAAI,GAAG;;;;cAKP,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC;oBAC1B,CAAC,CAAC,KAAK;oBACP,CAAC,CAAC;kBACA,KAAK;;;kBAIX;;cAGE,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC;oBAC5B,CAAC,CAAC,EAAE;oBACJ,CAAC,CAAC;;;;eAKN;;;gBAGI,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WA8BjC,CAAC;gBAEJ,OAAO;oBACL,IAAI;oBACJ,GAAG,EAAE,IAAI;iBACV,CAAC;YACJ,CAAC;YAED,OAAO;QACT,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"page-endpoints.js","names":[],"sources":["../../../../src/lib/plugins/page-endpoints.ts"],"sourcesContent":["import { parseSync } from 'oxc-parser';\nimport { normalizePath } from 'vite';\nimport { SERVER_FETCH_FACTORY_SNIPPET } from '../utils/renderers.js';\n\nexport function pageEndpointsPlugin() {\n return {\n name: 'analogjs-vite-plugin-nitro-rollup-page-endpoint',\n async transform(\n _code: string,\n id: string,\n ): Promise<{ code: string; map: null } | undefined> {\n if (normalizePath(id).includes('/pages/') && id.endsWith('.server.ts')) {\n const result = parseSync(id, _code, {\n sourceType: 'module',\n lang: 'ts',\n });\n\n const fileExports: string[] = result.module.staticExports.flatMap((e) =>\n e.entries\n .filter((entry) => entry.exportName.name !== null)\n .map((entry) => entry.exportName.name as string),\n );\n\n // In h3 v2 / Nitro v3, event.node is undefined during prerendering\n // (which uses the fetch-based pipeline, not Node.js http). We use\n // optional chaining so that page endpoints work in both Node.js\n // server and fetch-based prerender contexts.\n // Nitro v3 no longer guarantees the private `nitro/deps/ofetch`\n // subpath that older codegen relied on.\n //\n // Page loaders expect Nitro-style `$fetch` semantics (parsed data plus\n // internal relative-route support), so construct a request-local fetch\n // using public APIs:\n // - `createFetch` from `ofetch` for `$fetch` behavior\n // - `fetchWithEvent` from `h3` for internal Nitro request routing\n //\n // This avoids both unstable private Nitro imports and assumptions about\n // a global runtime `$fetch` being available during prerender.\n const code = `\n import { defineHandler, fetchWithEvent } from 'nitro/h3';\n import { createFetch } from 'ofetch';\n\n ${\n fileExports.includes('load')\n ? _code\n : `\n ${_code}\n export const load = () => {\n return {};\n }`\n }\n\n ${\n fileExports.includes('action')\n ? ''\n : `\n export const action = () => {\n return {};\n }\n `\n }\n\n export default defineHandler(async(event) => {\n ${SERVER_FETCH_FACTORY_SNIPPET}\n\n if (event.method === 'GET') {\n try {\n return await load({\n params: event.context.params,\n req: event.node?.req,\n res: event.node?.res,\n fetch: serverFetch,\n event\n });\n } catch(e) {\n console.error(\\` An error occurred: \\${e}\\`)\n throw e;\n }\n } else {\n try {\n return await action({\n params: event.context.params,\n req: event.node?.req,\n res: event.node?.res,\n fetch: serverFetch,\n event\n });\n } catch(e) {\n console.error(\\` An error occurred: \\${e}\\`)\n throw e;\n }\n }\n });\n `;\n\n return {\n code,\n map: null,\n };\n }\n\n return;\n },\n };\n}\n"],"mappings":";;;;AAIA,SAAgB,sBAAsB;AACpC,QAAO;EACL,MAAM;EACN,MAAM,UACJ,OACA,IACkD;AAClD,OAAI,cAAc,GAAG,CAAC,SAAS,UAAU,IAAI,GAAG,SAAS,aAAa,EAAE;IAMtE,MAAM,cALS,UAAU,IAAI,OAAO;KAClC,YAAY;KACZ,MAAM;KACP,CAAC,CAEmC,OAAO,cAAc,SAAS,MACjE,EAAE,QACC,QAAQ,UAAU,MAAM,WAAW,SAAS,KAAK,CACjD,KAAK,UAAU,MAAM,WAAW,KAAe,CACnD;AA0ED,WAAO;KACL,MA1DW;;;;cAKP,YAAY,SAAS,OAAO,GACxB,QACA;kBACA,MAAM;;;mBAIX;;cAGC,YAAY,SAAS,SAAS,GAC1B,KACA;;;;gBAKL;;;gBAGG,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAkCnC,KAAK;KACN;;;EAKN"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Nitro-build transform that stamps the derived id into each `serverFn` config
3
+ * in a `*.server.ts`, so a function registers under the same opaque route the
4
+ * client proxy dispatches to. The SSR app build does the same via the platform
5
+ * plugin; this covers the separate Nitro server graph the dispatch handler pulls
6
+ * the modules into.
7
+ */
8
+ export declare function serverFnIdPlugin(projectRoot: string): {
9
+ name: string;
10
+ transform(code: string, id: string);
11
+ };
@@ -0,0 +1,27 @@
1
+ import { serverFnFileId } from "../utils/derive-server-fn-id.js";
2
+ import { injectServerFnIds } from "../utils/inject-server-fn-ids.js";
3
+ //#region packages/vite-plugin-nitro/src/lib/plugins/server-fn-id-plugin.ts
4
+ /**
5
+ * Nitro-build transform that stamps the derived id into each `serverFn` config
6
+ * in a `*.server.ts`, so a function registers under the same opaque route the
7
+ * client proxy dispatches to. The SSR app build does the same via the platform
8
+ * plugin; this covers the separate Nitro server graph the dispatch handler pulls
9
+ * the modules into.
10
+ */
11
+ function serverFnIdPlugin(projectRoot) {
12
+ return {
13
+ name: "analogjs-server-fn-id",
14
+ transform(code, id) {
15
+ if (!id.endsWith(".server.ts")) return;
16
+ const injected = injectServerFnIds(code, serverFnFileId(id, projectRoot));
17
+ return injected ? {
18
+ code: injected.code,
19
+ map: null
20
+ } : void 0;
21
+ }
22
+ };
23
+ }
24
+ //#endregion
25
+ export { serverFnIdPlugin };
26
+
27
+ //# sourceMappingURL=server-fn-id-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-fn-id-plugin.js","names":[],"sources":["../../../../src/lib/plugins/server-fn-id-plugin.ts"],"sourcesContent":["import { serverFnFileId } from '../utils/derive-server-fn-id.js';\nimport { injectServerFnIds } from '../utils/inject-server-fn-ids.js';\n\n/**\n * Nitro-build transform that stamps the derived id into each `serverFn` config\n * in a `*.server.ts`, so a function registers under the same opaque route the\n * client proxy dispatches to. The SSR app build does the same via the platform\n * plugin; this covers the separate Nitro server graph the dispatch handler pulls\n * the modules into.\n */\nexport function serverFnIdPlugin(projectRoot: string) {\n return {\n name: 'analogjs-server-fn-id',\n transform(code: string, id: string) {\n if (!id.endsWith('.server.ts')) {\n return;\n }\n const injected = injectServerFnIds(code, serverFnFileId(id, projectRoot));\n return injected ? { code: injected.code, map: null } : undefined;\n },\n };\n}\n"],"mappings":";;;;;;;;;;AAUA,SAAgB,iBAAiB,aAAqB;AACpD,QAAO;EACL,MAAM;EACN,UAAU,MAAc,IAAY;AAClC,OAAI,CAAC,GAAG,SAAS,aAAa,CAC5B;GAEF,MAAM,WAAW,kBAAkB,MAAM,eAAe,IAAI,YAAY,CAAC;AACzE,UAAO,WAAW;IAAE,MAAM,SAAS;IAAM,KAAK;IAAM,GAAG,KAAA;;EAE1D"}
@@ -0,0 +1,5 @@
1
+ export declare const debugNitro: unknown;
2
+ export declare const debugSsr: unknown;
3
+ export declare const debugPrerender: unknown;
4
+ /** All debug instances in this package, for external wrapping (e.g. file logging). */
5
+ export declare const debugInstances: unknown;
@@ -0,0 +1,15 @@
1
+ import { createDebug } from "obug";
2
+ //#region packages/vite-plugin-nitro/src/lib/utils/debug.ts
3
+ var debugNitro = createDebug("analog:nitro");
4
+ var debugSsr = createDebug("analog:nitro:ssr");
5
+ var debugPrerender = createDebug("analog:nitro:prerender");
6
+ /** All debug instances in this package, for external wrapping (e.g. file logging). */
7
+ var debugInstances = [
8
+ debugNitro,
9
+ debugSsr,
10
+ debugPrerender
11
+ ];
12
+ //#endregion
13
+ export { debugInstances, debugNitro, debugPrerender, debugSsr };
14
+
15
+ //# sourceMappingURL=debug.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug.js","names":[],"sources":["../../../../src/lib/utils/debug.ts"],"sourcesContent":["import { createDebug } from 'obug';\n\nexport const debugNitro = createDebug('analog:nitro');\nexport const debugSsr = createDebug('analog:nitro:ssr');\nexport const debugPrerender = createDebug('analog:nitro:prerender');\n\n/** All debug instances in this package, for external wrapping (e.g. file logging). */\nexport const debugInstances = [debugNitro, debugSsr, debugPrerender];\n"],"mappings":";;AAEA,IAAa,aAAa,YAAY,eAAe;AACrD,IAAa,WAAW,YAAY,mBAAmB;AACvD,IAAa,iBAAiB,YAAY,yBAAyB;;AAGnE,IAAa,iBAAiB;CAAC;CAAY;CAAU;CAAe"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Server-function ids are derived, never author-chosen, for security:
3
+ *
4
+ * - **Collision-free.** `hash(fileId + exportName)` is unique per file+export, so
5
+ * two functions can never share a route and hijack each other's dispatch — a
6
+ * real risk with hand-picked ids where two authors independently pick `getUser`.
7
+ * - **Non-enumerable.** The public route is an opaque digest, not a guessable
8
+ * verb like `/_analog/fn/deleteAccount`, shrinking the discoverable surface.
9
+ * - **Not author-controlled.** Authors cannot expose a meaningful or duplicate
10
+ * route by accident; the id is a pure function of location.
11
+ *
12
+ * Both build transforms (server registration + client proxy) MUST derive the
13
+ * same id, so this is the single source of truth for the algorithm and the
14
+ * `fileId` must be the **project-root-relative** POSIX path — identical across
15
+ * the client, SSR, and Nitro builds regardless of absolute checkout location.
16
+ */
17
+ /** Project-root-relative POSIX module path used as the stable hash input. */
18
+ export declare function serverFnFileId(absPath: string, projectRoot: string): string;
19
+ /**
20
+ * Derives the opaque, collision-free id for a server function from its
21
+ * project-root-relative file id and export name. 16 hex chars (64 bits) is far
22
+ * beyond birthday-collision range for any realistic function count while keeping
23
+ * the route short.
24
+ */
25
+ export declare function deriveServerFnId(fileId: string, exportName: string): string;
@@ -0,0 +1,37 @@
1
+ import { relative } from "node:path";
2
+ import { createHash } from "node:crypto";
3
+ //#region packages/vite-plugin-nitro/src/lib/utils/derive-server-fn-id.ts
4
+ var toPosix = (p) => p.replace(/\\/g, "/");
5
+ /**
6
+ * Server-function ids are derived, never author-chosen, for security:
7
+ *
8
+ * - **Collision-free.** `hash(fileId + exportName)` is unique per file+export, so
9
+ * two functions can never share a route and hijack each other's dispatch — a
10
+ * real risk with hand-picked ids where two authors independently pick `getUser`.
11
+ * - **Non-enumerable.** The public route is an opaque digest, not a guessable
12
+ * verb like `/_analog/fn/deleteAccount`, shrinking the discoverable surface.
13
+ * - **Not author-controlled.** Authors cannot expose a meaningful or duplicate
14
+ * route by accident; the id is a pure function of location.
15
+ *
16
+ * Both build transforms (server registration + client proxy) MUST derive the
17
+ * same id, so this is the single source of truth for the algorithm and the
18
+ * `fileId` must be the **project-root-relative** POSIX path — identical across
19
+ * the client, SSR, and Nitro builds regardless of absolute checkout location.
20
+ */
21
+ /** Project-root-relative POSIX module path used as the stable hash input. */
22
+ function serverFnFileId(absPath, projectRoot) {
23
+ return toPosix(relative(projectRoot, absPath));
24
+ }
25
+ /**
26
+ * Derives the opaque, collision-free id for a server function from its
27
+ * project-root-relative file id and export name. 16 hex chars (64 bits) is far
28
+ * beyond birthday-collision range for any realistic function count while keeping
29
+ * the route short.
30
+ */
31
+ function deriveServerFnId(fileId, exportName) {
32
+ return createHash("sha256").update(`${fileId}#${exportName}`).digest("hex").slice(0, 16);
33
+ }
34
+ //#endregion
35
+ export { deriveServerFnId, serverFnFileId };
36
+
37
+ //# sourceMappingURL=derive-server-fn-id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"derive-server-fn-id.js","names":[],"sources":["../../../../src/lib/utils/derive-server-fn-id.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { relative } from 'node:path';\n\n// Intentionally dependency-light (node built-ins only): this module is loaded by\n// the client scrub, so it must not drag in vite/nitro. POSIX-normalize inline.\nconst toPosix = (p: string): string => p.replace(/\\\\/g, '/');\n\n/**\n * Server-function ids are derived, never author-chosen, for security:\n *\n * - **Collision-free.** `hash(fileId + exportName)` is unique per file+export, so\n * two functions can never share a route and hijack each other's dispatch — a\n * real risk with hand-picked ids where two authors independently pick `getUser`.\n * - **Non-enumerable.** The public route is an opaque digest, not a guessable\n * verb like `/_analog/fn/deleteAccount`, shrinking the discoverable surface.\n * - **Not author-controlled.** Authors cannot expose a meaningful or duplicate\n * route by accident; the id is a pure function of location.\n *\n * Both build transforms (server registration + client proxy) MUST derive the\n * same id, so this is the single source of truth for the algorithm and the\n * `fileId` must be the **project-root-relative** POSIX path — identical across\n * the client, SSR, and Nitro builds regardless of absolute checkout location.\n */\n\n/** Project-root-relative POSIX module path used as the stable hash input. */\nexport function serverFnFileId(absPath: string, projectRoot: string): string {\n return toPosix(relative(projectRoot, absPath));\n}\n\n/**\n * Derives the opaque, collision-free id for a server function from its\n * project-root-relative file id and export name. 16 hex chars (64 bits) is far\n * beyond birthday-collision range for any realistic function count while keeping\n * the route short.\n */\nexport function deriveServerFnId(fileId: string, exportName: string): string {\n return createHash('sha256')\n .update(`${fileId}#${exportName}`)\n .digest('hex')\n .slice(0, 16);\n}\n"],"mappings":";;;AAKA,IAAM,WAAW,MAAsB,EAAE,QAAQ,OAAO,IAAI;;;;;;;;;;;;;;;;;;AAoB5D,SAAgB,eAAe,SAAiB,aAA6B;AAC3E,QAAO,QAAQ,SAAS,aAAa,QAAQ,CAAC;;;;;;;;AAShD,SAAgB,iBAAiB,QAAgB,YAA4B;AAC3E,QAAO,WAAW,SAAS,CACxB,OAAO,GAAG,OAAO,GAAG,aAAa,CACjC,OAAO,MAAM,CACb,MAAM,GAAG,GAAG"}
@@ -1,56 +1,56 @@
1
- import { PrerenderContentFile } from '../options';
1
+ import { PrerenderContentFile } from "../options";
2
2
  /**
3
- * Discovers content files with front matter and extracts metadata for prerendering.
4
- *
5
- * This function:
6
- * 1. Discovers all content files matching the specified glob pattern
7
- * 2. Reads each file and parses front matter metadata
8
- * 3. Extracts file name, extension, and path information
9
- * 4. Returns structured data for prerendering content pages
10
- *
11
- * @param workspaceRoot The workspace root directory path
12
- * @param rootDir The project root directory relative to workspace
13
- * @param glob The glob pattern to match content files (e.g., 'content/blog')
14
- * @returns Array of PrerenderContentFile objects with metadata and front matter
15
- *
16
- * Example usage:
17
- * const contentFiles = getMatchingContentFilesWithFrontMatter(
18
- * '/workspace',
19
- * 'apps/my-app',
20
- * 'content/blog'
21
- * );
22
- *
23
- * Sample discovered file paths:
24
- * - /workspace/apps/my-app/content/blog/first-post.md
25
- * - /workspace/apps/my-app/content/blog/2024/01/hello-world.md
26
- * - /workspace/apps/my-app/content/blog/tech/angular-v17.mdx
27
- * - /workspace/apps/my-app/content/blog/about/index.md
28
- *
29
- * Sample output structure:
30
- * {
31
- * name: 'first-post',
32
- * extension: 'md',
33
- * path: 'content/blog',
34
- * attributes: { title: 'My First Post', date: '2024-01-01', tags: ['intro'] }
35
- * }
36
- *
37
- * tinyglobby vs fast-glob comparison:
38
- * - Both support the same glob patterns for file discovery
39
- * - Both are efficient for finding content files
40
- * - tinyglobby is now used instead of fast-glob
41
- * - tinyglobby provides similar functionality with smaller bundle size
42
- * - tinyglobby's globSync returns absolute paths when absolute: true is set
43
- *
44
- * Front matter parsing:
45
- * - Uses front-matter library to parse YAML/TOML front matter
46
- * - Extracts metadata like title, date, tags, author, etc.
47
- * - Supports both YAML (---) and TOML (+++) delimiters
48
- * - Returns structured attributes for prerendering
49
- *
50
- * File path processing:
51
- * - Normalizes paths for cross-platform compatibility
52
- * - Extracts file name without extension
53
- * - Determines file extension for content type handling
54
- * - Maintains relative path structure for routing
55
- */
56
- export declare function getMatchingContentFilesWithFrontMatter(workspaceRoot: string, rootDir: string, glob: string): PrerenderContentFile[];
3
+ * Discovers content files with front matter and extracts metadata for prerendering.
4
+ *
5
+ * This function:
6
+ * 1. Discovers all content files matching the specified glob pattern
7
+ * 2. Reads each file and parses front matter metadata
8
+ * 3. Extracts file name, extension, and path information
9
+ * 4. Returns structured data for prerendering content pages
10
+ *
11
+ * @param workspaceRoot The workspace root directory path
12
+ * @param rootDir The project root directory relative to workspace
13
+ * @param glob The glob pattern to match content files (e.g., 'content/blog')
14
+ * @returns Array of PrerenderContentFile objects with metadata and front matter
15
+ *
16
+ * Example usage:
17
+ * const contentFiles = getMatchingContentFilesWithFrontMatter(
18
+ * '/workspace',
19
+ * 'apps/my-app',
20
+ * 'content/blog'
21
+ * );
22
+ *
23
+ * Sample discovered file paths:
24
+ * - /workspace/apps/my-app/content/blog/first-post.md
25
+ * - /workspace/apps/my-app/content/blog/2024/01/hello-world.md
26
+ * - /workspace/apps/my-app/content/blog/tech/angular-v17.mdx
27
+ * - /workspace/apps/my-app/content/blog/about/index.md
28
+ *
29
+ * Sample output structure:
30
+ * {
31
+ * name: 'first-post',
32
+ * extension: 'md',
33
+ * path: 'content/blog',
34
+ * attributes: { title: 'My First Post', date: '2024-01-01', tags: ['intro'] }
35
+ * }
36
+ *
37
+ * tinyglobby vs fast-glob comparison:
38
+ * - Both support the same glob patterns for file discovery
39
+ * - Both are efficient for finding content files
40
+ * - tinyglobby is now used instead of fast-glob
41
+ * - tinyglobby provides similar functionality with smaller bundle size
42
+ * - tinyglobby's globSync returns absolute paths when absolute: true is set
43
+ *
44
+ * Front matter parsing:
45
+ * - Uses front-matter library to parse YAML/TOML front matter
46
+ * - Extracts metadata like title, date, tags, author, etc.
47
+ * - Supports both YAML (---) and TOML (+++) delimiters
48
+ * - Returns structured attributes for prerendering
49
+ *
50
+ * File path processing:
51
+ * - Normalizes paths for cross-platform compatibility
52
+ * - Extracts file name without extension
53
+ * - Determines file extension for content type handling
54
+ * - Maintains relative path structure for routing
55
+ */
56
+ export declare function getMatchingContentFilesWithFrontMatter(workspaceRoot: string, rootDir: string, glob: string, recursive?: boolean): PrerenderContentFile[];
@@ -1,100 +1,98 @@
1
- import { readFileSync } from 'node:fs';
2
- import { join, relative, resolve } from 'node:path';
3
- import { normalizePath } from 'vite';
4
- import { createRequire } from 'node:module';
5
- import { globSync } from 'tinyglobby';
6
- const require = createRequire(import.meta.url);
1
+ import { normalizePath } from "vite";
2
+ import { join, relative, resolve } from "node:path";
3
+ import { readFileSync } from "node:fs";
4
+ import { globSync } from "tinyglobby";
5
+ import { createRequire } from "node:module";
6
+ //#region packages/vite-plugin-nitro/src/lib/utils/get-content-files.ts
7
+ var require = createRequire(import.meta.url);
7
8
  /**
8
- * Discovers content files with front matter and extracts metadata for prerendering.
9
- *
10
- * This function:
11
- * 1. Discovers all content files matching the specified glob pattern
12
- * 2. Reads each file and parses front matter metadata
13
- * 3. Extracts file name, extension, and path information
14
- * 4. Returns structured data for prerendering content pages
15
- *
16
- * @param workspaceRoot The workspace root directory path
17
- * @param rootDir The project root directory relative to workspace
18
- * @param glob The glob pattern to match content files (e.g., 'content/blog')
19
- * @returns Array of PrerenderContentFile objects with metadata and front matter
20
- *
21
- * Example usage:
22
- * const contentFiles = getMatchingContentFilesWithFrontMatter(
23
- * '/workspace',
24
- * 'apps/my-app',
25
- * 'content/blog'
26
- * );
27
- *
28
- * Sample discovered file paths:
29
- * - /workspace/apps/my-app/content/blog/first-post.md
30
- * - /workspace/apps/my-app/content/blog/2024/01/hello-world.md
31
- * - /workspace/apps/my-app/content/blog/tech/angular-v17.mdx
32
- * - /workspace/apps/my-app/content/blog/about/index.md
33
- *
34
- * Sample output structure:
35
- * {
36
- * name: 'first-post',
37
- * extension: 'md',
38
- * path: 'content/blog',
39
- * attributes: { title: 'My First Post', date: '2024-01-01', tags: ['intro'] }
40
- * }
41
- *
42
- * tinyglobby vs fast-glob comparison:
43
- * - Both support the same glob patterns for file discovery
44
- * - Both are efficient for finding content files
45
- * - tinyglobby is now used instead of fast-glob
46
- * - tinyglobby provides similar functionality with smaller bundle size
47
- * - tinyglobby's globSync returns absolute paths when absolute: true is set
48
- *
49
- * Front matter parsing:
50
- * - Uses front-matter library to parse YAML/TOML front matter
51
- * - Extracts metadata like title, date, tags, author, etc.
52
- * - Supports both YAML (---) and TOML (+++) delimiters
53
- * - Returns structured attributes for prerendering
54
- *
55
- * File path processing:
56
- * - Normalizes paths for cross-platform compatibility
57
- * - Extracts file name without extension
58
- * - Determines file extension for content type handling
59
- * - Maintains relative path structure for routing
60
- */
61
- export function getMatchingContentFilesWithFrontMatter(workspaceRoot, rootDir, glob) {
62
- // Dynamically require front-matter library
63
- // eslint-disable-next-line @typescript-eslint/no-var-requires
64
- const fm = require('front-matter');
65
- // Normalize the project root path for consistent path handling
66
- const root = normalizePath(resolve(workspaceRoot, rootDir));
67
- // Resolve the content directory path relative to the project root
68
- const resolvedDir = normalizePath(relative(root, join(root, glob)));
69
- // Discover all content files in the specified directory
70
- // Pattern: looks for any files in the resolved directory
71
- const contentFiles = globSync([`${root}/${resolvedDir}/*`], {
72
- dot: true,
73
- absolute: true,
74
- });
75
- // Process each discovered content file to extract metadata and front matter
76
- const mappedFilesWithFm = contentFiles.map((f) => {
77
- // Read the file contents as UTF-8 text
78
- const fileContents = readFileSync(f, 'utf8');
79
- // Parse front matter from the file content
80
- const raw = fm(fileContents);
81
- const filepath = normalizePath(f).replace(root, '');
82
- const match = filepath.match(/\/([^/.]+)(\.([^/.]+))?$/);
83
- let name = '';
84
- let extension = '';
85
- if (match) {
86
- name = match[1]; // File name without extension
87
- extension = match[3] || ''; // File extension or empty string if no extension
88
- }
89
- // Return structured content file data for prerendering
90
- return {
91
- name,
92
- extension,
93
- path: resolvedDir,
94
- attributes: raw.attributes,
95
- content: fileContents,
96
- };
97
- });
98
- return mappedFilesWithFm;
9
+ * Discovers content files with front matter and extracts metadata for prerendering.
10
+ *
11
+ * This function:
12
+ * 1. Discovers all content files matching the specified glob pattern
13
+ * 2. Reads each file and parses front matter metadata
14
+ * 3. Extracts file name, extension, and path information
15
+ * 4. Returns structured data for prerendering content pages
16
+ *
17
+ * @param workspaceRoot The workspace root directory path
18
+ * @param rootDir The project root directory relative to workspace
19
+ * @param glob The glob pattern to match content files (e.g., 'content/blog')
20
+ * @returns Array of PrerenderContentFile objects with metadata and front matter
21
+ *
22
+ * Example usage:
23
+ * const contentFiles = getMatchingContentFilesWithFrontMatter(
24
+ * '/workspace',
25
+ * 'apps/my-app',
26
+ * 'content/blog'
27
+ * );
28
+ *
29
+ * Sample discovered file paths:
30
+ * - /workspace/apps/my-app/content/blog/first-post.md
31
+ * - /workspace/apps/my-app/content/blog/2024/01/hello-world.md
32
+ * - /workspace/apps/my-app/content/blog/tech/angular-v17.mdx
33
+ * - /workspace/apps/my-app/content/blog/about/index.md
34
+ *
35
+ * Sample output structure:
36
+ * {
37
+ * name: 'first-post',
38
+ * extension: 'md',
39
+ * path: 'content/blog',
40
+ * attributes: { title: 'My First Post', date: '2024-01-01', tags: ['intro'] }
41
+ * }
42
+ *
43
+ * tinyglobby vs fast-glob comparison:
44
+ * - Both support the same glob patterns for file discovery
45
+ * - Both are efficient for finding content files
46
+ * - tinyglobby is now used instead of fast-glob
47
+ * - tinyglobby provides similar functionality with smaller bundle size
48
+ * - tinyglobby's globSync returns absolute paths when absolute: true is set
49
+ *
50
+ * Front matter parsing:
51
+ * - Uses front-matter library to parse YAML/TOML front matter
52
+ * - Extracts metadata like title, date, tags, author, etc.
53
+ * - Supports both YAML (---) and TOML (+++) delimiters
54
+ * - Returns structured attributes for prerendering
55
+ *
56
+ * File path processing:
57
+ * - Normalizes paths for cross-platform compatibility
58
+ * - Extracts file name without extension
59
+ * - Determines file extension for content type handling
60
+ * - Maintains relative path structure for routing
61
+ */
62
+ function getMatchingContentFilesWithFrontMatter(workspaceRoot, rootDir, glob, recursive = false) {
63
+ const fm = require("front-matter");
64
+ const root = normalizePath(resolve(workspaceRoot, rootDir));
65
+ const resolvedDir = normalizePath(relative(root, join(root, glob)));
66
+ const contentFiles = globSync([recursive ? `${root}/${resolvedDir}/**/*` : `${root}/${resolvedDir}/*`], {
67
+ dot: true,
68
+ absolute: true,
69
+ onlyFiles: true
70
+ });
71
+ const dirPrefix = `${root}/${resolvedDir}`;
72
+ return contentFiles.map((f) => {
73
+ const fileContents = readFileSync(f, "utf8");
74
+ const raw = fm(fileContents);
75
+ const match = normalizePath(f).replace(root, "").match(/\/([^/.]+)(\.([^/.]+))?$/);
76
+ let name = "";
77
+ let extension = "";
78
+ if (match) {
79
+ name = match[1];
80
+ extension = match[3] || "";
81
+ }
82
+ const relativeDir = normalizePath(relative(dirPrefix, f));
83
+ const lastSlash = relativeDir.lastIndexOf("/");
84
+ const relativePath = lastSlash === -1 ? "" : relativeDir.slice(0, lastSlash);
85
+ return {
86
+ name,
87
+ extension,
88
+ path: resolvedDir,
89
+ attributes: raw.attributes,
90
+ content: fileContents,
91
+ relativePath
92
+ };
93
+ });
99
94
  }
95
+ //#endregion
96
+ export { getMatchingContentFilesWithFrontMatter };
97
+
100
98
  //# sourceMappingURL=get-content-files.js.map