@rsc-kit/mcp 0.29.7 → 0.29.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/report.js CHANGED
@@ -11,7 +11,7 @@
11
11
  import { existsSync, readFileSync, statSync } from "node:fs";
12
12
  import { join, resolve } from "node:path";
13
13
  /** Where a build leaves its report, in the order worth looking. */
14
- const LIKELY = [".rsc", "build", "dist", ".output"];
14
+ const LIKELY = [".rsc-kit", "build", ".rsc", "dist", ".output"];
15
15
  export class NoReport extends Error {
16
16
  constructor(root) {
17
17
  super(`No build report under ${root}. This server answers from what the last build ` +
@@ -1 +1 @@
1
- {"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,EAAE;AACF,8EAA8E;AAC9E,2EAA2E;AAC3E,6EAA6E;AAC7E,yEAAyE;AACzE,EAAE;AACF,6EAA6E;AAC7E,2EAA2E;AAC3E,mDAAmD;AAEnD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiD1C,mEAAmE;AACnE,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;AAEpD,MAAM,OAAO,QAAS,SAAQ,KAAK;IACjC,YAAY,IAAY;QACtB,KAAK,CACH,yBAAyB,IAAI,iDAAiD;YAC5E,uEAAuE,CAC1E,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAED,qCAAqC;AACrC,MAAM,UAAU,UAAU,CAAC,IAAY;IAKrC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3B,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,mBAAmB,CAAC,CAAC;QAElD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QAEhC,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAgB;YAC9D,0EAA0E;YAC1E,uEAAuE;YACvE,wDAAwD;YACxD,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK;YAC7B,IAAI,EAAE,IAAI;SACX,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,0FAA0F;AAC1F,MAAM,CAAC,MAAM,OAAO,GAA2B;IAC7C,MAAM,EAAE,iDAAiD;IACzD,KAAK,EAAE,oDAAoD;IAC3D,OAAO,EACL,uFAAuF;IACzF,OAAO,EAAE,sBAAsB;IAC/B,KAAK,EAAE,kBAAkB;CAC1B,CAAC;AAEF,8DAA8D;AAC9D,MAAM,UAAU,QAAQ,CACtB,MAAmB,EACnB,GAAW;IAEX,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;IAC5E,MAAM,OAAO,GAAG,CAAC,SAAiB,EAAE,EAAE,CACpC,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC;IAElE,OAAO,CACL,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACzC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACvC,IAAI,CACL,CAAC;AACJ,CAAC","sourcesContent":["// Reading what the build wrote down.\n//\n// Everything this server answers comes from one file: `build-report.json`, in\n// the build's own output directory. Nothing here runs a build, imports the\n// app, or re-derives the route tree — the build already decided all of this,\n// and a second implementation would be a second thing that can be wrong.\n//\n// The consequence to be honest about: an answer is only as fresh as the last\n// build. So every answer says when it was built, and a missing report says\n// \"run a build\" rather than \"there are no routes\".\n\nimport { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\n\nexport interface ReportedRoute {\n url: string;\n component: string;\n type: string;\n reason: string | null;\n warning: string | null;\n /** How it was stored, when that is worth knowing - \"no client components, so ships no javascript\". */\n note?: string | null;\n clientJs: number | null;\n}\n\nexport interface ReportedApiRoute {\n url: string;\n name: string;\n type: string;\n reason: string | null;\n /** Stored, and froze a value that will not be the same tomorrow. Absent from older reports. */\n warning?: string | null;\n}\n\nexport interface ReportedAction {\n id: string;\n name: string;\n file: string;\n /** Built by createActionClient, so its middleware ran. */\n client: boolean;\n /** A read (GET) rather than a mutation. */\n query: boolean;\n}\n\nexport interface BuildReport {\n version: number;\n routes: ReportedRoute[];\n apis: ReportedApiRoute[];\n /** Absent from reports written before actions were audited. */\n actions?: ReportedAction[];\n /**\n * Server files importing `cache` from React, relative to the source dir.\n * React's memoises only inside a component render; in a guard, an action\n * or an api route it calls straight through. Absent from older reports.\n */\n reactCache?: string[];\n /** Server files importing a client library: the packages, and who imports the file. Absent from older reports. */\n clientImports?: { file: string; packages: string[]; from: string | null }[];\n totals: { static: number; partial: number; dynamic: number; failed: number };\n}\n\n/** Where a build leaves its report, in the order worth looking. */\nconst LIKELY = [\".rsc\", \"build\", \"dist\", \".output\"];\n\nexport class NoReport extends Error {\n constructor(root: string) {\n super(\n `No build report under ${root}. This server answers from what the last build ` +\n \"decided, so there has to have been one — run the build and ask again.\",\n );\n this.name = \"NoReport\";\n }\n}\n\n/** The report, and how old it is. */\nexport function loadReport(root: string): {\n report: BuildReport;\n builtAt: Date;\n from: string;\n} {\n const base = resolve(root);\n\n for (const dir of LIKELY) {\n const file = join(base, dir, \"build-report.json\");\n\n if (!existsSync(file)) continue;\n\n return {\n report: JSON.parse(readFileSync(file, \"utf-8\")) as BuildReport,\n // The file's own mtime rather than a timestamp inside it: a stamp written\n // into the file changes the file on every build even when nothing else\n // did, which defeats every cache keyed on its contents.\n builtAt: statSync(file).mtime,\n from: file,\n };\n }\n\n throw new NoReport(base);\n}\n\n/** What each classification means, in one line, for an answer that has to stand alone. */\nexport const MEANING: Record<string, string> = {\n frozen: \"stored whole at build time and served as a file\",\n shell: \"a stored shell, with the rest rendered per request\",\n blocked:\n \"REFUSED — nothing could paint before it read the request, so the build did not finish\",\n dynamic: \"answered per request\",\n error: \"failed to render\",\n};\n\n/** A route by url, tolerating a trailing slash either way. */\nexport function routeFor(\n report: BuildReport,\n url: string,\n): ReportedRoute | ReportedApiRoute | null {\n const wanted = (url.split(\"?\")[0].replace(/\\/+$/, \"\") || \"/\").toLowerCase();\n const matches = (candidate: string) =>\n (candidate.replace(/\\/+$/, \"\") || \"/\").toLowerCase() === wanted;\n\n return (\n report.routes.find((r) => matches(r.url)) ??\n report.apis.find((a) => matches(a.url)) ??\n null\n );\n}\n"]}
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,EAAE;AACF,8EAA8E;AAC9E,2EAA2E;AAC3E,6EAA6E;AAC7E,yEAAyE;AACzE,EAAE;AACF,6EAA6E;AAC7E,2EAA2E;AAC3E,mDAAmD;AAEnD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiD1C,mEAAmE;AACnE,MAAM,MAAM,GAAG,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;AAEhE,MAAM,OAAO,QAAS,SAAQ,KAAK;IACjC,YAAY,IAAY;QACtB,KAAK,CACH,yBAAyB,IAAI,iDAAiD;YAC5E,uEAAuE,CAC1E,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAED,qCAAqC;AACrC,MAAM,UAAU,UAAU,CAAC,IAAY;IAKrC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3B,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,mBAAmB,CAAC,CAAC;QAElD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QAEhC,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAgB;YAC9D,0EAA0E;YAC1E,uEAAuE;YACvE,wDAAwD;YACxD,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK;YAC7B,IAAI,EAAE,IAAI;SACX,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,0FAA0F;AAC1F,MAAM,CAAC,MAAM,OAAO,GAA2B;IAC7C,MAAM,EAAE,iDAAiD;IACzD,KAAK,EAAE,oDAAoD;IAC3D,OAAO,EACL,uFAAuF;IACzF,OAAO,EAAE,sBAAsB;IAC/B,KAAK,EAAE,kBAAkB;CAC1B,CAAC;AAEF,8DAA8D;AAC9D,MAAM,UAAU,QAAQ,CACtB,MAAmB,EACnB,GAAW;IAEX,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;IAC5E,MAAM,OAAO,GAAG,CAAC,SAAiB,EAAE,EAAE,CACpC,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC;IAElE,OAAO,CACL,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACzC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACvC,IAAI,CACL,CAAC;AACJ,CAAC","sourcesContent":["// Reading what the build wrote down.\n//\n// Everything this server answers comes from one file: `build-report.json`, in\n// the build's own output directory. Nothing here runs a build, imports the\n// app, or re-derives the route tree — the build already decided all of this,\n// and a second implementation would be a second thing that can be wrong.\n//\n// The consequence to be honest about: an answer is only as fresh as the last\n// build. So every answer says when it was built, and a missing report says\n// \"run a build\" rather than \"there are no routes\".\n\nimport { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\n\nexport interface ReportedRoute {\n url: string;\n component: string;\n type: string;\n reason: string | null;\n warning: string | null;\n /** How it was stored, when that is worth knowing - \"no client components, so ships no javascript\". */\n note?: string | null;\n clientJs: number | null;\n}\n\nexport interface ReportedApiRoute {\n url: string;\n name: string;\n type: string;\n reason: string | null;\n /** Stored, and froze a value that will not be the same tomorrow. Absent from older reports. */\n warning?: string | null;\n}\n\nexport interface ReportedAction {\n id: string;\n name: string;\n file: string;\n /** Built by createActionClient, so its middleware ran. */\n client: boolean;\n /** A read (GET) rather than a mutation. */\n query: boolean;\n}\n\nexport interface BuildReport {\n version: number;\n routes: ReportedRoute[];\n apis: ReportedApiRoute[];\n /** Absent from reports written before actions were audited. */\n actions?: ReportedAction[];\n /**\n * Server files importing `cache` from React, relative to the source dir.\n * React's memoises only inside a component render; in a guard, an action\n * or an api route it calls straight through. Absent from older reports.\n */\n reactCache?: string[];\n /** Server files importing a client library: the packages, and who imports the file. Absent from older reports. */\n clientImports?: { file: string; packages: string[]; from: string | null }[];\n totals: { static: number; partial: number; dynamic: number; failed: number };\n}\n\n/** Where a build leaves its report, in the order worth looking. */\nconst LIKELY = [\".rsc-kit\", \"build\", \".rsc\", \"dist\", \".output\"];\n\nexport class NoReport extends Error {\n constructor(root: string) {\n super(\n `No build report under ${root}. This server answers from what the last build ` +\n \"decided, so there has to have been one — run the build and ask again.\",\n );\n this.name = \"NoReport\";\n }\n}\n\n/** The report, and how old it is. */\nexport function loadReport(root: string): {\n report: BuildReport;\n builtAt: Date;\n from: string;\n} {\n const base = resolve(root);\n\n for (const dir of LIKELY) {\n const file = join(base, dir, \"build-report.json\");\n\n if (!existsSync(file)) continue;\n\n return {\n report: JSON.parse(readFileSync(file, \"utf-8\")) as BuildReport,\n // The file's own mtime rather than a timestamp inside it: a stamp written\n // into the file changes the file on every build even when nothing else\n // did, which defeats every cache keyed on its contents.\n builtAt: statSync(file).mtime,\n from: file,\n };\n }\n\n throw new NoReport(base);\n}\n\n/** What each classification means, in one line, for an answer that has to stand alone. */\nexport const MEANING: Record<string, string> = {\n frozen: \"stored whole at build time and served as a file\",\n shell: \"a stored shell, with the rest rendered per request\",\n blocked:\n \"REFUSED — nothing could paint before it read the request, so the build did not finish\",\n dynamic: \"answered per request\",\n error: \"failed to render\",\n};\n\n/** A route by url, tolerating a trailing slash either way. */\nexport function routeFor(\n report: BuildReport,\n url: string,\n): ReportedRoute | ReportedApiRoute | null {\n const wanted = (url.split(\"?\")[0].replace(/\\/+$/, \"\") || \"/\").toLowerCase();\n const matches = (candidate: string) =>\n (candidate.replace(/\\/+$/, \"\") || \"/\").toLowerCase() === wanted;\n\n return (\n report.routes.find((r) => matches(r.url)) ??\n report.apis.find((a) => matches(a.url)) ??\n null\n );\n}\n"]}
@@ -167,6 +167,32 @@ the class); your rules come after the component's.
167
167
  height and scrolls inside, so the snapshot is one screen.
168
168
  </Aside>
169
169
 
170
+ ## Pages that ship no JavaScript
171
+
172
+ A page with nothing interactive on it ships no runtime, so a link from it is
173
+ an ordinary page load - there is no router to run `<ViewTransition>`. The
174
+ browser can still animate that load on its own, with one rule of CSS and no
175
+ JavaScript at all:
176
+
177
+ ```css title="src/app/styles.css"
178
+ @media (prefers-reduced-motion: no-preference) {
179
+ @view-transition {
180
+ navigation: auto;
181
+ }
182
+ }
183
+ ```
184
+
185
+ With it on both pages, a same-site link animates from one document to the
186
+ next - a crossfade by default, shaped with the same `::view-transition-*`
187
+ selectors as above, and `view-transition-name` on an element on both pages
188
+ for a shared one. Chrome, Edge and Safari 18.2+ do it; elsewhere the link is
189
+ the page load it always was.
190
+
191
+ The same caution as the page fade applies: it never makes a navigation
192
+ faster, and on WebKit a large page is expensive to snapshot. On pages that
193
+ do ship the runtime it has no effect - their navigations are the router's,
194
+ not page loads.
195
+
170
196
  ## Coming back to a page you were just on
171
197
 
172
198
  A navigation to a page still being held reveals it rather than refetching it,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rsc-kit/mcp",
3
- "version": "0.29.7",
3
+ "version": "0.29.8",
4
4
  "description": "An MCP server over what an rsc-kit build decided: the routes, why each one is static or not, and what it costs the browser.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@modelcontextprotocol/sdk": "^1.30.0",
37
- "create-rsc-kit": "^0.29.7",
37
+ "create-rsc-kit": "^0.29.8",
38
38
  "zod": "^3.25"
39
39
  },
40
40
  "devDependencies": {