rari 0.2.18 → 0.2.19

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.
@@ -1,2 +1,2 @@
1
- import { ErrorBoundaryProps, FileRouteInfo, HttpRuntimeClient, LayoutProps, Link, LinkProps, LoadingProps, Navigate, NavigationOptions, NavigationState, Outlet, PageComponent, PageProps, Route, RouteComponent, RouteGenerationOptions, RouteMatch, RouteMeta, RouteParams, RouterConfig, RouterContext, RouterProvider, RouterProviderProps, Routes, RuntimeClient, SearchParams, buildSearchString, buildUrl, createHttpRuntimeClient, extractParamNames, findMatchingRoute, isDynamicRoute, isPathActive, joinPaths, normalizePathname, parseSearchParams, parseUrl, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, withRouter } from "./runtime-client-P4vvSVPV.js";
1
+ import { ErrorBoundaryProps, FileRouteInfo, HttpRuntimeClient, LayoutProps, Link, LinkProps, LoadingProps, Navigate, NavigationOptions, NavigationState, Outlet, PageComponent, PageProps, Route, RouteComponent, RouteGenerationOptions, RouteMatch, RouteMeta, RouteParams, RouterConfig, RouterContext, RouterProvider, RouterProviderProps, Routes, RuntimeClient, SearchParams, buildSearchString, buildUrl, createHttpRuntimeClient, extractParamNames, findMatchingRoute, isDynamicRoute, isPathActive, joinPaths, normalizePathname, parseSearchParams, parseUrl, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, withRouter } from "./runtime-client-CwQkaktd.js";
2
2
  export { type ErrorBoundaryProps, type FileRouteInfo, HttpRuntimeClient, type LayoutProps, Link, type LinkProps, type LoadingProps, Navigate, type NavigationOptions, type NavigationState, Outlet, type PageComponent, type PageProps, RouteComponent as Route, type RouteGenerationOptions, type RouteMatch, type RouteMeta, type RouteParams, type Route as RouteType, type RouterConfig, type RouterContext, RouterProvider, type RouterProviderProps, Routes, type RuntimeClient, type SearchParams, buildSearchString, buildUrl, createHttpRuntimeClient, extractParamNames, findMatchingRoute, isDynamicRoute, isPathActive, joinPaths, normalizePathname, parseSearchParams, parseUrl, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, withRouter };
package/dist/client.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { ErrorBoundaryProps, FileRouteInfo, HttpRuntimeClient, LayoutProps, Link, LinkProps, LoadingProps, Navigate, NavigationOptions, NavigationState, Outlet, PageComponent, PageProps, Route, RouteComponent, RouteGenerationOptions, RouteMatch, RouteMeta, RouteParams, RouterConfig, RouterContext, RouterProvider, RouterProviderProps, Routes, RuntimeClient, SearchParams, buildSearchString, buildUrl, createHttpRuntimeClient, extractParamNames, findMatchingRoute, isDynamicRoute, isPathActive, joinPaths, normalizePathname, parseSearchParams, parseUrl, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, withRouter } from "./runtime-client-P4vvSVPV.js";
1
+ import { ErrorBoundaryProps, FileRouteInfo, HttpRuntimeClient, LayoutProps, Link, LinkProps, LoadingProps, Navigate, NavigationOptions, NavigationState, Outlet, PageComponent, PageProps, Route, RouteComponent, RouteGenerationOptions, RouteMatch, RouteMeta, RouteParams, RouterConfig, RouterContext, RouterProvider, RouterProviderProps, Routes, RuntimeClient, SearchParams, buildSearchString, buildUrl, createHttpRuntimeClient, extractParamNames, findMatchingRoute, isDynamicRoute, isPathActive, joinPaths, normalizePathname, parseSearchParams, parseUrl, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, withRouter } from "./runtime-client-CwQkaktd.js";
2
2
  export { type ErrorBoundaryProps, type FileRouteInfo, HttpRuntimeClient, type LayoutProps, Link, type LinkProps, type LoadingProps, Navigate, type NavigationOptions, type NavigationState, Outlet, type PageComponent, type PageProps, RouteComponent as Route, type RouteGenerationOptions, type RouteMatch, type RouteMeta, type RouteParams, type Route as RouteType, type RouterConfig, type RouterContext, RouterProvider, type RouterProviderProps, Routes, type RuntimeClient, type SearchParams, buildSearchString, buildUrl, createHttpRuntimeClient, extractParamNames, findMatchingRoute, isDynamicRoute, isPathActive, joinPaths, normalizePathname, parseSearchParams, parseUrl, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, withRouter };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import { ErrorBoundaryProps, FileRouteInfo, HttpRuntimeClient, LayoutProps, Link, LinkProps, LoadingProps, Navigate, NavigationOptions, NavigationState, Outlet, PageComponent, PageProps, Route, RouteComponent, RouteGenerationOptions, RouteMatch, RouteMeta, RouteParams, RouterConfig, RouterContext, RouterProvider, RouterProviderProps, Routes, RuntimeClient, SearchParams, buildSearchString, buildUrl, createHttpRuntimeClient, extractParamNames, findMatchingRoute, getRoutePriority, isDynamicRoute, isPathActive, joinPaths, normalizePathname, parseSearchParams, parseUrl, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, withRouter } from "./runtime-client-P4vvSVPV.js";
2
- import { FileRouteGenerator, convertFilePatternToRoutePattern, createRouteManifest, defineRariConfig, generateFileRoutes, loadRouteManifest, rari, rariRouter, validateRoutes, watchFileRoutes } from "./server-CpxpL2un.js";
3
- export { ErrorBoundaryProps, FileRouteGenerator, FileRouteInfo, HttpRuntimeClient, LayoutProps, Link, LinkProps, LoadingProps, Navigate, NavigationOptions, NavigationState, Outlet, PageComponent, PageProps, RouteComponent as Route, RouteGenerationOptions, RouteMatch, RouteMeta, RouteParams, Route as RouteType, RouterConfig, RouterContext, RouterProvider, RouterProviderProps, Routes, RuntimeClient, SearchParams, buildSearchString, buildUrl, convertFilePatternToRoutePattern, createHttpRuntimeClient, createRouteManifest, defineRariConfig, extractParamNames, findMatchingRoute, generateFileRoutes, getRoutePriority, isDynamicRoute, isPathActive, joinPaths, loadRouteManifest, normalizePathname, parseSearchParams, parseUrl, rari, rariRouter, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, validateRoutes, watchFileRoutes, withRouter };
1
+ import { CacheConfig, ErrorBoundaryProps, FileRouteInfo, HttpRuntimeClient, LayoutProps, Link, LinkProps, LoadingProps, Navigate, NavigationOptions, NavigationState, Outlet, PageCacheConfig, PageComponent, PageProps, Route, RouteComponent, RouteGenerationOptions, RouteMatch, RouteMeta, RouteParams, RouterConfig, RouterContext, RouterProvider, RouterProviderProps, Routes, RuntimeClient, SearchParams, buildSearchString, buildUrl, createHttpRuntimeClient, extractParamNames, findMatchingRoute, getRoutePriority, isDynamicRoute, isPathActive, joinPaths, normalizePathname, parseSearchParams, parseUrl, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, withRouter } from "./runtime-client-CwQkaktd.js";
2
+ import { FileRouteGenerator, convertFilePatternToRoutePattern, createRouteManifest, defineRariConfig, defineRariOptions, generateFileRoutes, loadRouteManifest, rari, rariRouter, validateRoutes, watchFileRoutes } from "./server-Bna18v8X.js";
3
+ export { CacheConfig, ErrorBoundaryProps, FileRouteGenerator, FileRouteInfo, HttpRuntimeClient, LayoutProps, Link, LinkProps, LoadingProps, Navigate, NavigationOptions, NavigationState, Outlet, PageCacheConfig, PageComponent, PageProps, RouteComponent as Route, RouteGenerationOptions, RouteMatch, RouteMeta, RouteParams, Route as RouteType, RouterConfig, RouterContext, RouterProvider, RouterProviderProps, Routes, RuntimeClient, SearchParams, buildSearchString, buildUrl, convertFilePatternToRoutePattern, createHttpRuntimeClient, createRouteManifest, defineRariConfig, defineRariOptions, extractParamNames, findMatchingRoute, generateFileRoutes, getRoutePriority, isDynamicRoute, isPathActive, joinPaths, loadRouteManifest, normalizePathname, parseSearchParams, parseUrl, rari, rariRouter, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, validateRoutes, watchFileRoutes, withRouter };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { HttpRuntimeClient, Link, Navigate, Outlet, RouteComponent, Routes, buildSearchString, buildUrl, createHttpRuntimeClient, extractParamNames, findMatchingRoute, getRoutePriority, isDynamicRoute, isPathActive, joinPaths, normalizePathname, parseSearchParams, parseUrl, router_default, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, withRouter } from "./runtime-client-CcEhh-F7.js";
2
- import { FileRouteGenerator, convertFilePatternToRoutePattern, createRouteManifest, defineRariConfig, generateFileRoutes, loadRouteManifest, rari, rariRouter, validateRoutes, watchFileRoutes } from "./server-BrkE-3ny.js";
3
- import "./server-build-DaBgiV55.js";
2
+ import { FileRouteGenerator, convertFilePatternToRoutePattern, createRouteManifest, defineRariConfig, defineRariOptions, generateFileRoutes, loadRouteManifest, rari, rariRouter, validateRoutes, watchFileRoutes } from "./server-DYwz6RKf.js";
3
+ import "./server-build-BM8_GFF5.js";
4
4
 
5
- export { FileRouteGenerator, HttpRuntimeClient, Link, Navigate, Outlet, RouteComponent as Route, router_default as RouterProvider, Routes, buildSearchString, buildUrl, convertFilePatternToRoutePattern, createHttpRuntimeClient, createRouteManifest, defineRariConfig, extractParamNames, findMatchingRoute, generateFileRoutes, getRoutePriority, isDynamicRoute, isPathActive, joinPaths, loadRouteManifest, normalizePathname, parseSearchParams, parseUrl, rari, rariRouter, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, validateRoutes, watchFileRoutes, withRouter };
5
+ export { FileRouteGenerator, HttpRuntimeClient, Link, Navigate, Outlet, RouteComponent as Route, router_default as RouterProvider, Routes, buildSearchString, buildUrl, convertFilePatternToRoutePattern, createHttpRuntimeClient, createRouteManifest, defineRariConfig, defineRariOptions, extractParamNames, findMatchingRoute, generateFileRoutes, getRoutePriority, isDynamicRoute, isPathActive, joinPaths, loadRouteManifest, normalizePathname, parseSearchParams, parseUrl, rari, rariRouter, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, validateRoutes, watchFileRoutes, withRouter };
@@ -1,6 +1,18 @@
1
1
  import React$1, { ComponentType, ReactNode } from "react";
2
2
  import * as react_jsx_runtime0 from "react/jsx-runtime";
3
3
 
4
+ //#region src/router/cache.d.ts
5
+ interface CacheConfig {
6
+ routes?: Record<string, string>;
7
+ static?: string;
8
+ serverComponents?: string;
9
+ }
10
+ interface PageCacheConfig {
11
+ 'cache-control'?: string;
12
+ 'vary'?: string;
13
+ [key: string]: string | undefined;
14
+ }
15
+ //#endregion
4
16
  //#region src/router/types.d.ts
5
17
  interface Route {
6
18
  path: string;
@@ -18,6 +30,7 @@ interface RouteMeta {
18
30
  title?: string;
19
31
  description?: string;
20
32
  requiresAuth?: boolean;
33
+ cacheConfig?: PageCacheConfig;
21
34
  [key: string]: any;
22
35
  }
23
36
  interface RouteParams {
@@ -281,4 +294,4 @@ declare function createHttpRuntimeClient(options?: {
281
294
  ssl?: boolean;
282
295
  }): RuntimeClient;
283
296
  //#endregion
284
- export { ErrorBoundaryProps, FileRouteInfo, HttpRuntimeClient, LayoutProps, Link, LinkProps, LoadingProps, Navigate, NavigationOptions, NavigationState, Outlet, PageComponent, PageProps, Route, RouteComponent, RouteGenerationOptions, RouteMatch, RouteMeta, RouteParams, RouterConfig, RouterContext$1 as RouterContext, RouterProvider, RouterProviderProps, Routes, RuntimeClient, SearchParams, buildSearchString, buildUrl, createHttpRuntimeClient, extractParamNames, findMatchingRoute, getRoutePriority, isDynamicRoute, isPathActive, joinPaths, normalizePathname, parseSearchParams, parseUrl, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, withRouter };
297
+ export { CacheConfig, ErrorBoundaryProps, FileRouteInfo, HttpRuntimeClient, LayoutProps, Link, LinkProps, LoadingProps, Navigate, NavigationOptions, NavigationState, Outlet, PageCacheConfig, PageComponent, PageProps, Route, RouteComponent, RouteGenerationOptions, RouteMatch, RouteMeta, RouteParams, RouterConfig, RouterContext$1 as RouterContext, RouterProvider, RouterProviderProps, Routes, RuntimeClient, SearchParams, buildSearchString, buildUrl, createHttpRuntimeClient, extractParamNames, findMatchingRoute, getRoutePriority, isDynamicRoute, isPathActive, joinPaths, normalizePathname, parseSearchParams, parseUrl, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, withRouter };
@@ -1,4 +1,4 @@
1
- import { Route, RouteGenerationOptions } from "./runtime-client-P4vvSVPV.js";
1
+ import { CacheConfig, Route, RouteGenerationOptions } from "./runtime-client-CwQkaktd.js";
2
2
  import { Plugin, UserConfig } from "rolldown-vite";
3
3
 
4
4
  //#region src/router/file-routes.d.ts
@@ -60,10 +60,12 @@ interface RariOptions {
60
60
  projectRoot?: string;
61
61
  serverBuild?: ServerBuildOptions;
62
62
  serverHandler?: boolean;
63
+ caching?: CacheConfig;
63
64
  }
65
+ declare function defineRariOptions(config: RariOptions): RariOptions;
64
66
  declare function rari(options?: RariOptions): Plugin[];
65
67
  declare function defineRariConfig(config: UserConfig & {
66
68
  plugins?: Plugin[];
67
69
  }): UserConfig;
68
70
  //#endregion
69
- export { FileRouteGenerator, convertFilePatternToRoutePattern, createRouteManifest, defineRariConfig, generateFileRoutes, loadRouteManifest, rari, rariRouter, validateRoutes, watchFileRoutes };
71
+ export { FileRouteGenerator, convertFilePatternToRoutePattern, createRouteManifest, defineRariConfig, defineRariOptions, generateFileRoutes, loadRouteManifest, rari, rariRouter, validateRoutes, watchFileRoutes };
@@ -1,6 +1,6 @@
1
1
  import { __commonJS, __require, __toESM } from "./chunk-BLXvPPr8.js";
2
2
  import { analyzeFilePath } from "./runtime-client-CcEhh-F7.js";
3
- import { createServerBuildPlugin } from "./server-build-DaBgiV55.js";
3
+ import { createServerBuildPlugin } from "./server-build-BM8_GFF5.js";
4
4
  import fs, { promises } from "node:fs";
5
5
  import path from "node:path";
6
6
  import process$1 from "node:process";
@@ -5637,6 +5637,40 @@ function scanForClientComponents(srcDir) {
5637
5637
  scanDirectory(srcDir);
5638
5638
  return clientComponents;
5639
5639
  }
5640
+ function extractCacheConfigFromContent(content) {
5641
+ const ast = acorn.parse(content, {
5642
+ ecmaVersion: 2022,
5643
+ sourceType: "module",
5644
+ allowImportExportEverywhere: true
5645
+ });
5646
+ for (const node of ast.body) if (node.type === "ExportNamedDeclaration" && node.declaration && node.declaration.type === "VariableDeclaration") {
5647
+ for (const declarator of node.declaration.declarations) if (declarator.id && declarator.id.name === "cacheConfig" && declarator.init && declarator.init.type === "ObjectExpression") {
5648
+ const config = {};
5649
+ for (const prop of declarator.init.properties) if (prop.type === "Property" && prop.key && prop.value && prop.value.type === "Literal") {
5650
+ const keyName = prop.key.type === "Literal" ? prop.key.value : prop.key.name;
5651
+ if (keyName === "cache-control" || keyName === "vary") config[keyName] = prop.value.value;
5652
+ }
5653
+ return Object.keys(config).length > 0 ? config : void 0;
5654
+ }
5655
+ }
5656
+ return void 0;
5657
+ }
5658
+ function matchesPattern(pattern, path$5) {
5659
+ if (pattern === path$5) return true;
5660
+ if (pattern.endsWith("/*")) {
5661
+ const prefix = pattern.slice(0, -2);
5662
+ return path$5.startsWith(prefix);
5663
+ }
5664
+ if (pattern.includes("*")) {
5665
+ const regexPattern = pattern.replace(/\*/g, ".*").replace(/\//g, "\\/");
5666
+ const regex = /* @__PURE__ */ new RegExp(`^${regexPattern}$`);
5667
+ return regex.test(path$5);
5668
+ }
5669
+ return false;
5670
+ }
5671
+ function defineRariOptions(config) {
5672
+ return config;
5673
+ }
5640
5674
  function rari(options = {}) {
5641
5675
  const componentTypeCache = /* @__PURE__ */ new Map();
5642
5676
  const serverComponents = /* @__PURE__ */ new Set();
@@ -6028,7 +6062,7 @@ const ${componentName$1} = registerClientReference(
6028
6062
  const srcDir = path.join(projectRoot, "src");
6029
6063
  const discoverAndRegisterComponents = async () => {
6030
6064
  try {
6031
- const { ServerComponentBuilder, scanDirectory } = await import("./server-build-Cp6_RdeA.js");
6065
+ const { ServerComponentBuilder, scanDirectory } = await import("./server-build-DcbOtG3e.js");
6032
6066
  const builder = new ServerComponentBuilder(projectRoot, {
6033
6067
  outDir: "temp",
6034
6068
  serverDir: "server",
@@ -6045,7 +6079,8 @@ const ${componentName$1} = registerClientReference(
6045
6079
  headers: { "Content-Type": "application/json" },
6046
6080
  body: JSON.stringify({
6047
6081
  component_id: component.id,
6048
- component_code: component.code
6082
+ component_code: component.code,
6083
+ cache_config: component.cacheConfig
6049
6084
  })
6050
6085
  });
6051
6086
  if (!registerResponse.ok) {
@@ -6162,7 +6197,7 @@ const ${componentName$1} = registerClientReference(
6162
6197
  };
6163
6198
  const handleServerComponentHMR = async (filePath) => {
6164
6199
  try {
6165
- const { ServerComponentBuilder } = await import("./server-build-Cp6_RdeA.js");
6200
+ const { ServerComponentBuilder } = await import("./server-build-DcbOtG3e.js");
6166
6201
  const builder = new ServerComponentBuilder(projectRoot, {
6167
6202
  outDir: "temp",
6168
6203
  serverDir: "server",
@@ -6179,7 +6214,8 @@ const ${componentName$1} = registerClientReference(
6179
6214
  headers: { "Content-Type": "application/json" },
6180
6215
  body: JSON.stringify({
6181
6216
  component_id: component.id,
6182
- component_code: component.code
6217
+ component_code: component.code,
6218
+ cache_config: component.cacheConfig
6183
6219
  })
6184
6220
  });
6185
6221
  if (!registerResponse.ok) {
@@ -7507,7 +7543,49 @@ ${registrations.join("\n")}
7507
7543
  }
7508
7544
  };
7509
7545
  const serverBuildPlugin = createServerBuildPlugin(options.serverBuild);
7510
- return [mainPlugin, serverBuildPlugin];
7546
+ const cacheMiddlewarePlugin = {
7547
+ name: "rari:cache-middleware",
7548
+ configureServer(server) {
7549
+ server.middlewares.use((req, res, next) => {
7550
+ if (req.url?.startsWith("/@fs/")) {
7551
+ res.setHeader("Cache-Control", "no-cache");
7552
+ next();
7553
+ return;
7554
+ }
7555
+ const url = req.url || "";
7556
+ const pathname = url.split("?")[0];
7557
+ if (pathname && !pathname.includes(".") && !pathname.startsWith("/api") && !pathname.startsWith("/rsc")) {
7558
+ if (options.caching?.routes) {
7559
+ for (const [pattern, cacheControl] of Object.entries(options.caching.routes)) if (matchesPattern(pattern, pathname)) {
7560
+ res.setHeader("cache-control", cacheControl);
7561
+ break;
7562
+ }
7563
+ }
7564
+ const pagePath = pathname === "/" ? "/index" : pathname;
7565
+ const pageFilePath = path.join(process$1.cwd(), "src/pages", `${pagePath.slice(1) || "index"}.tsx`);
7566
+ if (fs.existsSync(pageFilePath)) {
7567
+ const pageContent = fs.readFileSync(pageFilePath, "utf-8");
7568
+ const cacheConfig = extractCacheConfigFromContent(pageContent);
7569
+ if (cacheConfig) Object.entries(cacheConfig).forEach(([key, value]) => {
7570
+ if (value) res.setHeader(key, value);
7571
+ });
7572
+ }
7573
+ }
7574
+ next();
7575
+ });
7576
+ },
7577
+ writeBundle() {
7578
+ if (options.caching) {
7579
+ const cacheConfigPath = path.join(process$1.cwd(), "dist", "cache-config.json");
7580
+ fs.writeFileSync(cacheConfigPath, JSON.stringify(options.caching, null, 2));
7581
+ }
7582
+ }
7583
+ };
7584
+ return [
7585
+ mainPlugin,
7586
+ serverBuildPlugin,
7587
+ cacheMiddlewarePlugin
7588
+ ];
7511
7589
  }
7512
7590
  function defineRariConfig(config) {
7513
7591
  return {
@@ -7517,4 +7595,4 @@ function defineRariConfig(config) {
7517
7595
  }
7518
7596
 
7519
7597
  //#endregion
7520
- export { FileRouteGenerator, convertFilePatternToRoutePattern, createRouteManifest, defineRariConfig, generateFileRoutes, loadRouteManifest, rari, rariRouter, validateRoutes, watchFileRoutes };
7598
+ export { FileRouteGenerator, convertFilePatternToRoutePattern, createRouteManifest, defineRariConfig, defineRariOptions, generateFileRoutes, loadRouteManifest, rari, rariRouter, validateRoutes, watchFileRoutes };
@@ -64,13 +64,33 @@ var ServerComponentBuilder = class {
64
64
  const code = fs.readFileSync(filePath, "utf-8");
65
65
  const dependencies = this.extractDependencies(code);
66
66
  const hasNodeImports = this.hasNodeImports(code);
67
+ const cacheConfig = this.extractCacheConfig(code);
67
68
  this.serverComponents.set(filePath, {
68
69
  filePath,
69
70
  originalCode: code,
70
71
  dependencies,
71
- hasNodeImports
72
+ hasNodeImports,
73
+ cacheConfig
72
74
  });
73
75
  }
76
+ extractCacheConfig(code) {
77
+ try {
78
+ const cacheConfigRegex = /export\s+const\s+cacheConfig\s*[:=]\s*(\{[^}]*\})/;
79
+ const match = code.match(cacheConfigRegex);
80
+ if (match) {
81
+ const configStr = match[1];
82
+ const cacheControlMatch = configStr.match(/'cache-control'\s*:\s*['"]([^'"]+)['"]/);
83
+ const varyMatch = configStr.match(/'vary'\s*:\s*['"]([^'"]+)['"]/);
84
+ const config = {};
85
+ if (cacheControlMatch) config["cache-control"] = cacheControlMatch[1];
86
+ if (varyMatch) config.vary = varyMatch[1];
87
+ return Object.keys(config).length > 0 ? config : void 0;
88
+ }
89
+ } catch (error) {
90
+ console.warn(`Failed to extract cache config from component: ${error}`);
91
+ }
92
+ return void 0;
93
+ }
74
94
  extractDependencies(code) {
75
95
  const dependencies = [];
76
96
  const importRegex = /import(?:\s+(?:\w+|\{[^}]*\}|\*\s+as\s+\w+)(?:\s*,\s*(?:\w+|\{[^}]*\}|\*\s+as\s+\w+))*\s+from\s+)?['"]([^'"]+)['"]/g;
@@ -118,7 +138,8 @@ var ServerComponentBuilder = class {
118
138
  const transformedCode = await this.buildComponentCodeOnly(filePath, componentId, component);
119
139
  components.push({
120
140
  id: componentId,
121
- code: transformedCode
141
+ code: transformedCode,
142
+ cacheConfig: component.cacheConfig
122
143
  });
123
144
  }
124
145
  return components;
@@ -0,0 +1,3 @@
1
+ import { ServerComponentBuilder, createServerBuildPlugin, scanDirectory } from "./server-build-BM8_GFF5.js";
2
+
3
+ export { ServerComponentBuilder, scanDirectory };
package/dist/server.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import { ErrorBoundaryProps, FileRouteInfo, HttpRuntimeClient, LayoutProps, Link, LinkProps, LoadingProps, Navigate, NavigationOptions, NavigationState, Outlet, PageComponent, PageProps, Route, RouteComponent, RouteGenerationOptions, RouteMatch, RouteMeta, RouteParams, RouterConfig, RouterContext, RouterProvider, RouterProviderProps, Routes, RuntimeClient, SearchParams, buildSearchString, buildUrl, createHttpRuntimeClient, extractParamNames, findMatchingRoute, getRoutePriority, isDynamicRoute, isPathActive, joinPaths, normalizePathname, parseSearchParams, parseUrl, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, withRouter } from "./runtime-client-P4vvSVPV.js";
2
- import { FileRouteGenerator, convertFilePatternToRoutePattern, createRouteManifest, defineRariConfig, generateFileRoutes, loadRouteManifest, rari, rariRouter, validateRoutes, watchFileRoutes } from "./server-CpxpL2un.js";
3
- export { ErrorBoundaryProps, FileRouteGenerator, FileRouteInfo, HttpRuntimeClient, LayoutProps, Link, LinkProps, LoadingProps, Navigate, NavigationOptions, NavigationState, Outlet, PageComponent, PageProps, RouteComponent as Route, RouteGenerationOptions, RouteMatch, RouteMeta, RouteParams, Route as RouteType, RouterConfig, RouterContext, RouterProvider, RouterProviderProps, Routes, RuntimeClient, SearchParams, buildSearchString, buildUrl, convertFilePatternToRoutePattern, createHttpRuntimeClient, createRouteManifest, defineRariConfig, extractParamNames, findMatchingRoute, generateFileRoutes, getRoutePriority, isDynamicRoute, isPathActive, joinPaths, loadRouteManifest, normalizePathname, parseSearchParams, parseUrl, rari, rariRouter, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, validateRoutes, watchFileRoutes, withRouter };
1
+ import { CacheConfig, ErrorBoundaryProps, FileRouteInfo, HttpRuntimeClient, LayoutProps, Link, LinkProps, LoadingProps, Navigate, NavigationOptions, NavigationState, Outlet, PageCacheConfig, PageComponent, PageProps, Route, RouteComponent, RouteGenerationOptions, RouteMatch, RouteMeta, RouteParams, RouterConfig, RouterContext, RouterProvider, RouterProviderProps, Routes, RuntimeClient, SearchParams, buildSearchString, buildUrl, createHttpRuntimeClient, extractParamNames, findMatchingRoute, getRoutePriority, isDynamicRoute, isPathActive, joinPaths, normalizePathname, parseSearchParams, parseUrl, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, withRouter } from "./runtime-client-CwQkaktd.js";
2
+ import { FileRouteGenerator, convertFilePatternToRoutePattern, createRouteManifest, defineRariConfig, defineRariOptions, generateFileRoutes, loadRouteManifest, rari, rariRouter, validateRoutes, watchFileRoutes } from "./server-Bna18v8X.js";
3
+ export { CacheConfig, ErrorBoundaryProps, FileRouteGenerator, FileRouteInfo, HttpRuntimeClient, LayoutProps, Link, LinkProps, LoadingProps, Navigate, NavigationOptions, NavigationState, Outlet, PageCacheConfig, PageComponent, PageProps, RouteComponent as Route, RouteGenerationOptions, RouteMatch, RouteMeta, RouteParams, Route as RouteType, RouterConfig, RouterContext, RouterProvider, RouterProviderProps, Routes, RuntimeClient, SearchParams, buildSearchString, buildUrl, convertFilePatternToRoutePattern, createHttpRuntimeClient, createRouteManifest, defineRariConfig, defineRariOptions, extractParamNames, findMatchingRoute, generateFileRoutes, getRoutePriority, isDynamicRoute, isPathActive, joinPaths, loadRouteManifest, normalizePathname, parseSearchParams, parseUrl, rari, rariRouter, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, validateRoutes, watchFileRoutes, withRouter };
package/dist/server.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { HttpRuntimeClient, Link, Navigate, Outlet, RouteComponent, Routes, buildSearchString, buildUrl, createHttpRuntimeClient, extractParamNames, findMatchingRoute, getRoutePriority, isDynamicRoute, isPathActive, joinPaths, normalizePathname, parseSearchParams, parseUrl, router_default, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, withRouter } from "./runtime-client-CcEhh-F7.js";
2
- import { FileRouteGenerator, convertFilePatternToRoutePattern, createRouteManifest, defineRariConfig, generateFileRoutes, loadRouteManifest, rari, rariRouter, validateRoutes, watchFileRoutes } from "./server-BrkE-3ny.js";
3
- import "./server-build-DaBgiV55.js";
2
+ import { FileRouteGenerator, convertFilePatternToRoutePattern, createRouteManifest, defineRariConfig, defineRariOptions, generateFileRoutes, loadRouteManifest, rari, rariRouter, validateRoutes, watchFileRoutes } from "./server-DYwz6RKf.js";
3
+ import "./server-build-BM8_GFF5.js";
4
4
 
5
- export { FileRouteGenerator, HttpRuntimeClient, Link, Navigate, Outlet, RouteComponent as Route, router_default as RouterProvider, Routes, buildSearchString, buildUrl, convertFilePatternToRoutePattern, createHttpRuntimeClient, createRouteManifest, defineRariConfig, extractParamNames, findMatchingRoute, generateFileRoutes, getRoutePriority, isDynamicRoute, isPathActive, joinPaths, loadRouteManifest, normalizePathname, parseSearchParams, parseUrl, rari, rariRouter, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, validateRoutes, watchFileRoutes, withRouter };
5
+ export { FileRouteGenerator, HttpRuntimeClient, Link, Navigate, Outlet, RouteComponent as Route, router_default as RouterProvider, Routes, buildSearchString, buildUrl, convertFilePatternToRoutePattern, createHttpRuntimeClient, createRouteManifest, defineRariConfig, defineRariOptions, extractParamNames, findMatchingRoute, generateFileRoutes, getRoutePriority, isDynamicRoute, isPathActive, joinPaths, loadRouteManifest, normalizePathname, parseSearchParams, parseUrl, rari, rariRouter, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, validateRoutes, watchFileRoutes, withRouter };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "rari",
3
3
  "type": "module",
4
- "version": "0.2.18",
4
+ "version": "0.2.19",
5
5
  "description": "Runtime Accelerated Rendering Infrastructure (Rari)",
6
6
  "author": "Ryan Skinner",
7
7
  "license": "MIT",
@@ -82,11 +82,11 @@
82
82
  "rollup-plugin-esbuild": "^6.2.1"
83
83
  },
84
84
  "optionalDependencies": {
85
- "rari-darwin-arm64": "0.2.13",
86
- "rari-darwin-x64": "0.2.13",
87
- "rari-linux-arm64": "0.2.13",
88
- "rari-linux-x64": "0.2.13",
89
- "rari-win32-x64": "0.2.13"
85
+ "rari-darwin-arm64": "0.2.14",
86
+ "rari-darwin-x64": "0.2.14",
87
+ "rari-linux-arm64": "0.2.14",
88
+ "rari-linux-x64": "0.2.14",
89
+ "rari-win32-x64": "0.2.14"
90
90
  },
91
91
  "devDependencies": {
92
92
  "@types/node": "^24.3.0",
@@ -0,0 +1,54 @@
1
+ export interface CacheConfig {
2
+ routes?: Record<string, string>
3
+ static?: string
4
+ serverComponents?: string
5
+ }
6
+
7
+ export interface PageCacheConfig {
8
+ 'cache-control'?: string
9
+ 'vary'?: string
10
+ [key: string]: string | undefined
11
+ }
12
+
13
+ const cacheConfigs = new Map<string, PageCacheConfig>()
14
+
15
+ export function registerPageCacheConfig(pagePath: string, config: PageCacheConfig): void {
16
+ cacheConfigs.set(pagePath, config)
17
+ }
18
+
19
+ export function getPageCacheConfig(pagePath: string): PageCacheConfig | undefined {
20
+ return cacheConfigs.get(pagePath)
21
+ }
22
+
23
+ export function clearPageCacheConfigs(): void {
24
+ cacheConfigs.clear()
25
+ }
26
+
27
+ export function getAllPageCacheConfigs(): Map<string, PageCacheConfig> {
28
+ return new Map(cacheConfigs)
29
+ }
30
+
31
+ export function extractPageCacheConfig(pageModule: any): PageCacheConfig | undefined {
32
+ if (pageModule && typeof pageModule === 'object') {
33
+ return pageModule.cacheConfig
34
+ }
35
+ return undefined
36
+ }
37
+
38
+ export function registerPageCacheConfigFromModule(pagePath: string, pageModule: any): void {
39
+ const cacheConfig = extractPageCacheConfig(pageModule)
40
+ if (cacheConfig) {
41
+ registerPageCacheConfig(pagePath, cacheConfig)
42
+ }
43
+ }
44
+
45
+ export function applyCacheHeaders(
46
+ headers: Record<string, string>,
47
+ cacheConfig: PageCacheConfig,
48
+ ): void {
49
+ for (const [key, value] of Object.entries(cacheConfig)) {
50
+ if (value !== undefined) {
51
+ headers[key.toLowerCase()] = value
52
+ }
53
+ }
54
+ }
@@ -1,4 +1,5 @@
1
1
  import type { ComponentType, ReactNode } from 'react'
2
+ import type { PageCacheConfig } from './cache'
2
3
 
3
4
  export interface Route {
4
5
  path: string
@@ -17,6 +18,7 @@ export interface RouteMeta {
17
18
  title?: string
18
19
  description?: string
19
20
  requiresAuth?: boolean
21
+ cacheConfig?: PageCacheConfig
20
22
  [key: string]: any
21
23
  }
22
24
 
package/src/server.ts CHANGED
@@ -49,6 +49,8 @@ export type {
49
49
  SearchParams,
50
50
  } from './router'
51
51
 
52
+ export type { CacheConfig, PageCacheConfig } from './router/cache'
53
+
52
54
  export {
53
55
  convertFilePatternToRoutePattern,
54
56
  createRouteManifest,
@@ -67,4 +69,4 @@ export { createHttpRuntimeClient, HttpRuntimeClient } from './runtime-client'
67
69
 
68
70
  export type { RuntimeClient } from './runtime-client'
69
71
 
70
- export { defineRariConfig, rari } from './vite'
72
+ export { defineRariConfig, defineRariOptions, rari } from './vite'
package/src/vite/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { Buffer } from 'node:buffer'
2
2
  import type { Plugin, UserConfig } from 'rolldown-vite'
3
+ import type { CacheConfig, PageCacheConfig } from '../router/cache'
3
4
  import type { ServerBuildOptions } from './server-build'
4
5
  import { spawn } from 'node:child_process'
5
6
  import fs from 'node:fs'
@@ -12,6 +13,7 @@ interface RariOptions {
12
13
  projectRoot?: string
13
14
  serverBuild?: ServerBuildOptions
14
15
  serverHandler?: boolean
16
+ caching?: CacheConfig
15
17
  }
16
18
 
17
19
  function scanForClientComponents(srcDir: string): Set<string> {
@@ -50,6 +52,75 @@ function scanForClientComponents(srcDir: string): Set<string> {
50
52
  return clientComponents
51
53
  }
52
54
 
55
+ export type { CacheConfig, PageCacheConfig } from '../router/cache'
56
+
57
+ function extractCacheConfigFromContent(content: string): PageCacheConfig | undefined {
58
+ const ast = acorn.parse(content, {
59
+ ecmaVersion: 2022,
60
+ sourceType: 'module',
61
+ allowImportExportEverywhere: true,
62
+ }) as any
63
+
64
+ for (const node of ast.body) {
65
+ if (
66
+ node.type === 'ExportNamedDeclaration'
67
+ && node.declaration
68
+ && node.declaration.type === 'VariableDeclaration'
69
+ ) {
70
+ for (const declarator of node.declaration.declarations) {
71
+ if (
72
+ declarator.id
73
+ && declarator.id.name === 'cacheConfig'
74
+ && declarator.init
75
+ && declarator.init.type === 'ObjectExpression'
76
+ ) {
77
+ const config: PageCacheConfig = {}
78
+
79
+ for (const prop of declarator.init.properties) {
80
+ if (
81
+ prop.type === 'Property'
82
+ && prop.key
83
+ && prop.value
84
+ && prop.value.type === 'Literal'
85
+ ) {
86
+ const keyName = prop.key.type === 'Literal' ? prop.key.value : prop.key.name
87
+ if (keyName === 'cache-control' || keyName === 'vary') {
88
+ config[keyName as keyof PageCacheConfig] = prop.value.value as string
89
+ }
90
+ }
91
+ }
92
+
93
+ return Object.keys(config).length > 0 ? config : undefined
94
+ }
95
+ }
96
+ }
97
+ }
98
+
99
+ return undefined
100
+ }
101
+
102
+ function matchesPattern(pattern: string, path: string): boolean {
103
+ if (pattern === path)
104
+ return true
105
+
106
+ if (pattern.endsWith('/*')) {
107
+ const prefix = pattern.slice(0, -2)
108
+ return path.startsWith(prefix)
109
+ }
110
+
111
+ if (pattern.includes('*')) {
112
+ const regexPattern = pattern.replace(/\*/g, '.*').replace(/\//g, '\\/')
113
+ const regex = new RegExp(`^${regexPattern}$`)
114
+ return regex.test(path)
115
+ }
116
+
117
+ return false
118
+ }
119
+
120
+ export function defineRariOptions(config: RariOptions): RariOptions {
121
+ return config
122
+ }
123
+
53
124
  export function rari(options: RariOptions = {}): Plugin[] {
54
125
  const componentTypeCache = new Map<string, 'client' | 'server' | 'unknown'>()
55
126
  const serverComponents = new Set<string>()
@@ -789,6 +860,7 @@ const ${componentName} = registerClientReference(
789
860
  body: JSON.stringify({
790
861
  component_id: component.id,
791
862
  component_code: component.code,
863
+ cache_config: component.cacheConfig,
792
864
  }),
793
865
  },
794
866
  )
@@ -1008,6 +1080,7 @@ const ${componentName} = registerClientReference(
1008
1080
  body: JSON.stringify({
1009
1081
  component_id: component.id,
1010
1082
  component_code: component.code,
1083
+ cache_config: component.cacheConfig,
1011
1084
  }),
1012
1085
  },
1013
1086
  )
@@ -2405,7 +2478,58 @@ ${registrations.join('\n')}
2405
2478
 
2406
2479
  const serverBuildPlugin = createServerBuildPlugin(options.serverBuild)
2407
2480
 
2408
- return [mainPlugin, serverBuildPlugin]
2481
+ const cacheMiddlewarePlugin: Plugin = {
2482
+ name: 'rari:cache-middleware',
2483
+ configureServer(server) {
2484
+ server.middlewares.use((req, res, next) => {
2485
+ if (req.url?.startsWith('/@fs/')) {
2486
+ res.setHeader('Cache-Control', 'no-cache')
2487
+ next()
2488
+ return
2489
+ }
2490
+
2491
+ const url = req.url || ''
2492
+ const pathname = url.split('?')[0]
2493
+
2494
+ if (pathname && !pathname.includes('.') && !pathname.startsWith('/api') && !pathname.startsWith('/rsc')) {
2495
+ if (options.caching?.routes) {
2496
+ for (const [pattern, cacheControl] of Object.entries(options.caching.routes)) {
2497
+ if (matchesPattern(pattern, pathname)) {
2498
+ res.setHeader('cache-control', cacheControl)
2499
+ break
2500
+ }
2501
+ }
2502
+ }
2503
+
2504
+ const pagePath = pathname === '/' ? '/index' : pathname
2505
+ const pageFilePath = path.join(process.cwd(), 'src/pages', `${pagePath.slice(1) || 'index'}.tsx`)
2506
+
2507
+ if (fs.existsSync(pageFilePath)) {
2508
+ const pageContent = fs.readFileSync(pageFilePath, 'utf-8')
2509
+ const cacheConfig = extractCacheConfigFromContent(pageContent)
2510
+
2511
+ if (cacheConfig) {
2512
+ Object.entries(cacheConfig).forEach(([key, value]) => {
2513
+ if (value) {
2514
+ res.setHeader(key, value)
2515
+ }
2516
+ })
2517
+ }
2518
+ }
2519
+ }
2520
+
2521
+ next()
2522
+ })
2523
+ },
2524
+ writeBundle() {
2525
+ if (options.caching) {
2526
+ const cacheConfigPath = path.join(process.cwd(), 'dist', 'cache-config.json')
2527
+ fs.writeFileSync(cacheConfigPath, JSON.stringify(options.caching, null, 2))
2528
+ }
2529
+ },
2530
+ }
2531
+
2532
+ return [mainPlugin, serverBuildPlugin, cacheMiddlewarePlugin]
2409
2533
  }
2410
2534
 
2411
2535
  export function defineRariConfig(
@@ -1,4 +1,5 @@
1
1
  import type { Plugin } from 'rolldown-vite'
2
+ import type { PageCacheConfig } from '../router/cache'
2
3
  import fs from 'node:fs'
3
4
  import path from 'node:path'
4
5
  import process from 'node:process'
@@ -14,6 +15,7 @@ export interface ServerComponentManifest {
14
15
  bundlePath: string
15
16
  dependencies: string[]
16
17
  hasNodeImports: boolean
18
+ cacheConfig?: PageCacheConfig
17
19
  }
18
20
  >
19
21
  version: string
@@ -35,6 +37,7 @@ export class ServerComponentBuilder {
35
37
  originalCode: string
36
38
  dependencies: string[]
37
39
  hasNodeImports: boolean
40
+ cacheConfig?: PageCacheConfig
38
41
  }
39
42
  >()
40
43
 
@@ -143,15 +146,45 @@ export class ServerComponentBuilder {
143
146
  const code = fs.readFileSync(filePath, 'utf-8')
144
147
  const dependencies = this.extractDependencies(code)
145
148
  const hasNodeImports = this.hasNodeImports(code)
149
+ const cacheConfig = this.extractCacheConfig(code)
146
150
 
147
151
  this.serverComponents.set(filePath, {
148
152
  filePath,
149
153
  originalCode: code,
150
154
  dependencies,
151
155
  hasNodeImports,
156
+ cacheConfig,
152
157
  })
153
158
  }
154
159
 
160
+ private extractCacheConfig(code: string): PageCacheConfig | undefined {
161
+ try {
162
+ const cacheConfigRegex = /export\s+const\s+cacheConfig\s*[:=]\s*(\{[^}]*\})/
163
+ const match = code.match(cacheConfigRegex)
164
+
165
+ if (match) {
166
+ const configStr = match[1]
167
+ const cacheControlMatch = configStr.match(/'cache-control'\s*:\s*['"]([^'"]+)['"]/)
168
+ const varyMatch = configStr.match(/'vary'\s*:\s*['"]([^'"]+)['"]/)
169
+
170
+ const config: PageCacheConfig = {}
171
+ if (cacheControlMatch) {
172
+ config['cache-control'] = cacheControlMatch[1]
173
+ }
174
+ if (varyMatch) {
175
+ config.vary = varyMatch[1]
176
+ }
177
+
178
+ return Object.keys(config).length > 0 ? config : undefined
179
+ }
180
+ }
181
+ catch (error) {
182
+ console.warn(`Failed to extract cache config from component: ${error}`)
183
+ }
184
+
185
+ return undefined
186
+ }
187
+
155
188
  private extractDependencies(code: string): string[] {
156
189
  const dependencies: string[] = []
157
190
  const importRegex
@@ -223,8 +256,8 @@ export class ServerComponentBuilder {
223
256
  )
224
257
  }
225
258
 
226
- async getTransformedComponentsForDevelopment(): Promise<Array<{ id: string, code: string }>> {
227
- const components: Array<{ id: string, code: string }> = []
259
+ async getTransformedComponentsForDevelopment(): Promise<Array<{ id: string, code: string, cacheConfig?: PageCacheConfig }>> {
260
+ const components: Array<{ id: string, code: string, cacheConfig?: PageCacheConfig }> = []
228
261
 
229
262
  for (const [filePath, component] of this.serverComponents) {
230
263
  const relativePath = path.relative(this.projectRoot, filePath)
@@ -235,6 +268,7 @@ export class ServerComponentBuilder {
235
268
  components.push({
236
269
  id: componentId,
237
270
  code: transformedCode,
271
+ cacheConfig: component.cacheConfig,
238
272
  })
239
273
  }
240
274
 
@@ -1,3 +0,0 @@
1
- import { ServerComponentBuilder, createServerBuildPlugin, scanDirectory } from "./server-build-DaBgiV55.js";
2
-
3
- export { ServerComponentBuilder, scanDirectory };