Claude Cursor GitHub Copilot Skill

sveltekit-routing-load-review

Statically review SvelteKit route files (+page.js, +page.server.js, +layout.js, +layout.server.js, +server.ts) to verify universal-vs-server load placement, catching server-only secrets, database clients, or privileged API access that would leak into or execute inside the browser

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download vincentchuwaichow-vanguard-frontier-agentic-skills_frontend_sveltekit-routing-load-review-febe32a.zip · 8 KB
Part of vincentchuwaichow/vanguard-frontier-agentic — 293 skills

Install

skills CLI npx skills add https://github.com/VincentChuWaiChow/vanguard-frontier-agentic/tree/master/skills/frontend/sveltekit-routing-load-review
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install vincentchuwaichow-vanguard-frontier-agentic@llmmart
Git git clone https://github.com/VincentChuWaiChow/vanguard-frontier-agentic.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole vincentchuwaichow/vanguard-frontier-agentic collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

SvelteKit Routing & Load Function Review

Purpose

Review SvelteKit route files for correct universal-vs-server load function placement without re-litigating progressive-enhancement UX, form-action design, or component styling in every response. This skill exists because SvelteKit's universal load functions (+page.js / +layout.js) run on the server for the initial SSR render and again in the browser on every subsequent client-side navigation — a fact that is routinely missed and turns a misplaced database call or secret reference into a client-side credential exposure, not just a style defect.

When to use

Use this skill when the user asks to:

  • review a new or changed SvelteKit route's load functions before merge,
  • investigate a secret, database error, or unexpected network call surfacing in the browser console or network tab for a SvelteKit route,
  • determine whether data-fetching for a given route is placed in the correct file (+page.js vs +page.server.js, +layout.js vs +layout.server.js),
  • audit +layout/+page/+server file precedence for a route tree.

Do not use this skill for:

  • progressive-enhancement or <form> action / use:enhance UX review — use sveltekit-progressive-enhancement-review instead,
  • pure component-internal state with no load function involved,
  • live performance profiling of load waterfalls — that needs runtime tracing, not static review.

Context7 Documentation Protocol

  • Resolve the library ID with resolve-library-id (matched result: /sveltejs/kit) before citing any SvelteKit-specific claim.
  • Before asserting the universal-vs-server execution model, call query-docs against /sveltejs/kit for "load functions" and quote the precise rule: a universal load (+page.js/+layout.js) runs on the server during SSR and hydration, then runs again in the browser on every subsequent client-side navigation (or always in the browser if SSR is disabled / the route is a SPA); a server load (+page.server.js/+layout.server.js) always runs only on the server. If both exist for a route, the server load runs first and its return value becomes the data property passed into the universal load.
  • Verify the SvelteKit major version installed in the repo (package.json) before asserting version-specific behavior of $env/static/private / $env/dynamic/private enforcement or server-only module protection — this has evolved across releases (private $env/* client-side imports were blocked starting in a 1.0-pre release).
  • If Context7 is unavailable, fall back to the official_docs URLs in this skill's metadata.json and label the claim documentation-based, unverified against current release.
  • Never assume a repo's SvelteKit config (kit.env.privatePrefix, adapter, ssr/csr page options) matches defaults without reading svelte.config.js and any per-route page-option exports — page options change when/whether a universal load ever runs on the server at all.

Lean operating rules

  • First classify every load-bearing route file as universal (+page.js, +layout.js) or server (+page.server.js, +layout.server.js) by filename suffix alone — never by guessing from content or route name.
  • Treat every universal load function as browser-reachable code, full stop. It is not "mostly server-side" or "server-side on first load" — SvelteKit re-runs it client-side on every subsequent navigation by default.
  • Do not assume SvelteKit's build-time $env/static/private / $env/dynamic/private import guard catches every leak. It blocks direct imports of those modules from client-reachable files, but it does not catch manual process.env reads, a $lib/server-protected module re-exporting a secret through a non-.server module, or a secret being copied into the plain object a server load returns.
  • Trace secrets and DB clients through the full import graph, including transitive $lib imports — a universal load that imports an innocuous-looking $lib/utils.js which itself imports $lib/server/db.js is still a leak path (and SvelteKit's server-only module protection should catch that specific case at build time; verify it does, do not assume).
  • Treat any private value present in the plain object a server load (or +layout.server.js) returns as a candidate leak the moment a universal load, a client component, or page.data/$page.data can read it — server load output crosses the server/client boundary via devalue serialization, it is not automatically safe just because it originated server-side.
  • Never mark a +page.server.js or +layout.server.js file itself as a browser-exposure risk for containing secrets or DB calls — those files are always server-only by SvelteKit's routing contract; the risk is in what they choose to return, not that they execute.
  • Do not flag deep or repeated +layout.server.js logic as a leak; flag it as a MEDIUM duplication/maintainability finding only, distinct from HIGH-severity leak findings.
  • Never execute, build, or run application code as part of this review; this is a static-review skill (Read/Grep/Glob only).

References

Load these only when needed:

  • Review workflow and findings contract — use for the step-by-step review procedure, the leak-tracing decision tree, and the required output shape.
  • Routing conventions — load only when +layout/+page/+server file precedence or route-tree structure (not just load placement) is in question.

Response minimum

Return, at minimum:

  • the route(s) and file(s) in scope, each labeled universal or server load,
  • ranked findings with file:line evidence and the full import/data-flow trace for any leak finding,
  • evidence level per finding (repo evidence, documentation-based, or inference),
  • verdict (approve / approve-with-notes / block),
  • open questions or scope the review could not cover (e.g., unverified svelte.config.js env prefix, unread transitive $lib module).
Files (vanguard-frontier-agentic)
  • references
    • routing-conventions.md 4.4 KB
      # Routing Conventions: File Roles and Precedence
      
      Use this reference only when a review also needs to assess `+layout`/`+page`/`+server` file precedence or route-tree structure — not for a load-placement-only review (see `workflow-and-output.md` for that).
      
      ## Officially grounded file roles
      
      Per SvelteKit's routing documentation:
      
      - **`+page.svelte`** — the component rendered for a route.
      - **`+page.js`** — exports a universal `load` (typed `PageLoad`). Runs on the server during SSR/hydration, then again in the browser on subsequent client-side navigations (subject to page options).
      - **`+page.server.js`** — exports a server `load` (typed `PageServerLoad`), always server-only. Renaming `+page.js` to `+page.server.js` is the documented mechanism for moving a load function that needs a database or private env var out of universal-execution scope. Can also export form `actions`.
      - **`+layout.svelte`** — wraps child routes; layouts nest by directory structure.
      - **`+layout.js` / `+layout.server.js`** — same universal/server split as page equivalents, but the returned data is available to the layout's own component and to every child route via `await parent()`.
      - **`+server.js`/`+server.ts`** — exports HTTP method handlers (`GET`, `POST`, etc.) for a route, making it an API endpoint rather than a page. Always server-only.
      
      ## Precedence and data flow
      
      - If a route has both a server `load` and a universal `load` (e.g., `+page.server.js` and `+page.js` in the same directory), **the server `load` runs first**. Its return value becomes the `data` property on the `LoadEvent` passed into the universal `load`. Do not describe these as running "in parallel" or "independently" — they are sequential and dependent.
      - A server `load`'s return value must be serializable via devalue (JSON-representable types plus `BigInt`, `Date`, `Map`, `Set`, `RegExp`, and repeated/cyclical references). A universal `load` has no such restriction and may return non-serializable values (component constructors, class instances, functions) — this asymmetry is a useful signal during review: if a "server load" is returning something devalue cannot serialize, either the classification is wrong or the code will fail at runtime, not just leak.
      - A `+layout.server.js`'s data is available to every nested route's `load` via the `parent()` function — trace `parent()` calls when checking whether a leak in a layout's server `load` return value actually reaches a specific deeply nested universal `load`.
      - Prerendered routes invoke `load` at build time, not per-request — flag this distinction only if the review scope includes prerendering/page-option correctness; it does not change the leak-tracing rules above.
      
      ## Review-relevant precedence pitfalls
      
      - Do not assume a `+page.server.js` with no corresponding `+page.js` implies the route has no client-reachable data flow — the server `load`'s return value still reaches the client as `data`/`$page.data` for the page component itself, even with no universal `load` present. Apply the same leak-tracing rules from `workflow-and-output.md` regardless of whether a sibling universal `load` exists.
      - Do not assume `+layout.js`/`+layout.server.js` data is scoped narrowly — it is available to the entire subtree beneath that layout, which widens the blast radius of any leak found there compared to a single `+page.js`.
      - A `+server.ts` in the same directory as a `+page.js`/`+page.server.js` is a separate concern from page load functions; do not conflate an API endpoint's own request-handling logic with the page's load-function review unless the page's universal `load` calls that endpoint via `fetch()`, in which case trace the endpoint's response shape for any leaked field the same way you would trace a server `load`'s return value.
      
      ## When to push back
      
      Push back if the user asks you to:
      
      - "just put it in `+page.js` so it fetches faster" when the data source requires a private credential or database access — that is not faster, it is a credential-exposure defect.
      - treat a `+layout.server.js` leak as low-severity because "it's just the layout" — layout-scoped leaks reach a wider client-visible subtree than a single page's leak, not a narrower one.
      - skip verifying the installed SvelteKit version's `$env`/server-only-module enforcement because "the docs say it's blocked" — documentation describes the current release's behavior; it does not prove the repo's pinned version enforces it the same way.
      
    • workflow-and-output.md 7.5 KB
      # Review Workflow and Findings Contract
      
      Use this reference for the step-by-step review procedure, the leak-tracing decision tree, and the required output shape for a SvelteKit routing/load review.
      
      > Version note: `$env/*` client-import enforcement and server-only module protection are Vite-plugin-driven and have evolved across SvelteKit releases. Verify the installed `@sveltejs/kit` version in `package.json` before asserting exact enforcement behavior; do not assume the latest documented behavior applies to an older installed version.
      
      ## What people get wrong
      
      The naive assumption is:
      
      > "`+page.js` is the client file and `+page.server.js` is the server file — as long as I don't put a DB call directly in `+page.js`, I'm safe."
      
      That is incomplete in two ways:
      
      1. `+page.js` (and `+layout.js`) are **universal** — SvelteKit runs them on the server for the first SSR render, then re-runs them **in the browser** for every subsequent client-side navigation. It is not "the client file"; it is "the file that runs in both places," and the browser-execution half is where secrets leak.
      2. A secret can leak without ever being imported into a universal `load` file directly — it leaks the moment it appears anywhere inside the plain object a server `load` *returns*, because that object is serialized (via devalue) and shipped to the browser as `data`/`$page.data` regardless of whether anything downstream "needed" it.
      
      ## Step-by-step workflow
      
      1. **Inventory route files.** For every route directory in scope, list `+page.js`, `+page.server.js`, `+layout.js`, `+layout.server.js`, and `+server.ts`/`+server.js` present. Classify each by filename suffix alone: `.server.` → server load, otherwise → universal load. Do not infer classification from file content or route name.
      2. **Confirm page options.** Read any `export const ssr` / `export const csr` in `+page.js`/`+layout.js` for the route. If `ssr = false`, the "universal load runs server-first" assumption is void — the universal load runs client-only, in a SPA-style mount, from the start. If `csr = false`, the universal load never re-runs client-side on navigation (full-page reloads instead) — note this because it changes (lowers) the leak surface but should still be verified rather than assumed.
      3. **Trace each universal load's imports.** For every `+page.js`/`+layout.js` in scope, follow its import graph, including transitive `$lib` imports, looking for:
         - direct imports from `$env/static/private` or `$env/dynamic/private` (SvelteKit's Vite plugin should block this at build time for client-reachable files — verify the repo's SvelteKit version actually enforces this, do not assume),
         - imports of a module under `$lib/server/` or named `*.server.js`/`*.server.ts` (SvelteKit's server-only module protection should block this too — same verification caveat),
         - manual `process.env.<SECRET>` reads that bypass both of the above guards,
         - a database client (Prisma, Drizzle, raw driver, etc.) instantiated or imported directly.
      4. **Trace server-`load` return values.** For every `+page.server.js`/`+layout.server.js` in scope, inspect the object literal(s) returned by `load`. Flag any field that is a raw secret, API key, session token, or full DB-record dump not intended for client consumption — that object becomes `data` in the child universal `load` and `$page.data` in every component, i.e. it is client-visible the instant it is returned, independent of whether the universal `load` "does" anything with it.
      5. **Check route-tree precedence** only if `+layout`/`+page`/`+server` structural correctness is also in question — load `references/routing-conventions.md` for that sub-review.
      6. **Rank and report findings** per the output shape below.
      
      ## Leak-tracing decision tree
      
      - Universal `load` (or a module it transitively imports) directly imports `$env/static/private`, `$env/dynamic/private`, or reads `process.env.<SECRET>` → **HIGH**. State whether the repo's SvelteKit version's build-time guard would catch this import path or whether it is a bypass (e.g., `process.env` read, or a non-`.server`-suffixed module outside `$lib/server/` that re-exports a value originally sourced from a private env var).
      - Universal `load` imports a `$lib/server/*` or `*.server.js` module directly → **HIGH** unless the repo's verified SvelteKit version enforces server-only module protection for that exact import path, in which case this is a build-time-blocked case; still flag it as a MEDIUM code-smell (the import should never have been attempted) rather than close the finding silently.
      - Server `load` (`+page.server.js`/`+layout.server.js`) returns an object containing a raw secret, token, or credential intended only for server-to-service calls → **HIGH**, regardless of whether any universal `load` or component currently reads that field. The leak is the serialization to the client, not the eventual consumption.
      - Server `load` output is consumed unchanged by a child universal `load` that then spreads or forwards it further (e.g., into a client-side third-party SDK init call) → **HIGH**, trace and cite both hops.
      - `+page.server.js`/`+layout.server.js` contains a DB call or secret access with no client-visible leak in its return value → **not a finding for this skill**; this is expected, correct placement.
      - Duplicate near-identical server `load` logic repeated across sibling `+page.server.js` files that could be consolidated into a shared `+layout.server.js` → **MEDIUM**, maintainability/duplication, not a security finding.
      - `+server.ts` (API route) referenced by a universal `load`'s `fetch()` call, where the `+server.ts` handler itself correctly guards secrets server-side → **not a finding**; note it as an alternative-pattern observation only if the review scope includes route-tree precedence.
      
      ## Adversarial checklist
      
      Before closing a review with no HIGH findings, confirm:
      
      - Did you classify every file by filename suffix, not by assumption?
      - For every universal `load`, did you check `ssr`/`csr` page options before asserting when/whether it runs server-side vs. client-side?
      - Did you follow *transitive* `$lib` imports, not just the direct imports in the load file itself?
      - Did you inspect the actual object returned by every server `load`, not just whether it "looks like" it fetches sensitive data?
      - Did you verify the installed SvelteKit version's enforcement behavior for `$env/*/private` and server-only modules rather than assuming current docs apply unconditionally?
      - If you found zero leaks, is that because none exist, or because you didn't trace far enough?
      
      ## Output shape
      
      Every review response must include:
      
      1. **Scope** — routes and files reviewed, each labeled universal-load or server-load (or both, if the route has paired files).
      2. **Findings** — ranked HIGH → MEDIUM → LOW, each with `file:line`, the classification (misplacement vs. leak vs. duplication), the full import/data-flow trace for any leak finding, and a concrete fix sketch (e.g., "move to `+page.server.js`" or "strip `apiKey` field from the returned object before it reaches `data`").
      3. **Evidence level** per finding: `repo evidence` (read the actual file/import), `documentation-based` (asserting SvelteKit's enforcement behavior from docs without confirming the installed version), or `inference` (plausible but unverified, e.g., a dynamic import you could not statically resolve).
      4. **Verdict** — approve / approve-with-notes / block. A single HIGH leak finding is a block.
      5. **Open questions** — anything the review could not verify (unread `svelte.config.js`, unresolved dynamic import, unconfirmed SvelteKit version).
      
  • metadata.json 1.1 KB
    {
      "id": "sveltekit-routing-load-review",
      "name": "SvelteKit Routing & Load Function Review",
      "type": "skill",
      "provider": "frontend",
      "harnesses": [
        "claude-code",
        "cursor",
        "codex",
        "gemini",
        "kiro",
        "other"
      ],
      "summary": "Reviews SvelteKit route files for correct universal-vs-server load placement, preventing server-only logic from executing in the browser.",
      "source_type": "original",
      "official_docs": [
        "https://kit.svelte.dev/docs/load",
        "https://kit.svelte.dev/docs/routing",
        "https://svelte.dev/docs/kit/load",
        "https://svelte.dev/docs/kit/routing"
      ],
      "security_notes": "Server-only secrets, database clients, or privileged third-party API keys reachable from a +page.js/+layout.js (universal load, which runs in the browser too) is a credential-exposure defect — escalate as HIGH, not a style preference. Static-review-only skill: it reads and greps route source but never executes, builds, or runs application code.",
      "last_verified": "2026-07-02",
      "path": "skills/frontend/sveltekit-routing-load-review",
      "author": "github: VincentChuWaiChow",
      "version": "0.1.0"
    }
    
  • SKILL.md 6.4 KB
    ---
    name: sveltekit-routing-load-review
    description: Statically review SvelteKit route files (+page.js, +page.server.js, +layout.js, +layout.server.js, +server.ts) to verify universal-vs-server load placement, catching server-only secrets, database clients, or privileged API access that would leak into or execute inside the browser.
    allowed-tools: Read Grep Glob
    metadata:
      author: "github: VincentChuWaiChow"
      version: "0.1.0"
      updated: "2026-07-02"
      category: architecture
    ---
    
    # SvelteKit Routing & Load Function Review
    
    ## Purpose
    
    Review SvelteKit route files for correct universal-vs-server `load` function placement without re-litigating progressive-enhancement UX, form-action design, or component styling in every response. This skill exists because SvelteKit's universal `load` functions (`+page.js` / `+layout.js`) run on the server for the initial SSR render **and again in the browser** on every subsequent client-side navigation — a fact that is routinely missed and turns a misplaced database call or secret reference into a client-side credential exposure, not just a style defect.
    
    ## When to use
    
    Use this skill when the user asks to:
    
    - review a new or changed SvelteKit route's `load` functions before merge,
    - investigate a secret, database error, or unexpected network call surfacing in the browser console or network tab for a SvelteKit route,
    - determine whether data-fetching for a given route is placed in the correct file (`+page.js` vs `+page.server.js`, `+layout.js` vs `+layout.server.js`),
    - audit `+layout`/`+page`/`+server` file precedence for a route tree.
    
    Do not use this skill for:
    
    - progressive-enhancement or `<form>` action / `use:enhance` UX review — use `sveltekit-progressive-enhancement-review` instead,
    - pure component-internal state with no `load` function involved,
    - live performance profiling of load waterfalls — that needs runtime tracing, not static review.
    
    ## Context7 Documentation Protocol
    
    - Resolve the library ID with `resolve-library-id` (matched result: `/sveltejs/kit`) before citing any SvelteKit-specific claim.
    - Before asserting the universal-vs-server execution model, call `query-docs` against `/sveltejs/kit` for "load functions" and quote the precise rule: a universal `load` (`+page.js`/`+layout.js`) runs on the server during SSR and hydration, then runs **again in the browser** on every subsequent client-side navigation (or always in the browser if SSR is disabled / the route is a SPA); a server `load` (`+page.server.js`/`+layout.server.js`) always runs only on the server. If both exist for a route, the server `load` runs first and its return value becomes the `data` property passed into the universal `load`.
    - Verify the SvelteKit major version installed in the repo (`package.json`) before asserting version-specific behavior of `$env/static/private` / `$env/dynamic/private` enforcement or server-only module protection — this has evolved across releases (private `$env/*` client-side imports were blocked starting in a 1.0-pre release).
    - If Context7 is unavailable, fall back to the `official_docs` URLs in this skill's `metadata.json` and label the claim `documentation-based, unverified against current release`.
    - Never assume a repo's SvelteKit config (`kit.env.privatePrefix`, adapter, `ssr`/`csr` page options) matches defaults without reading `svelte.config.js` and any per-route page-option exports — page options change when/whether a universal `load` ever runs on the server at all.
    
    ## Lean operating rules
    
    - First classify every load-bearing route file as universal (`+page.js`, `+layout.js`) or server (`+page.server.js`, `+layout.server.js`) by filename suffix alone — never by guessing from content or route name.
    - Treat every universal `load` function as browser-reachable code, full stop. It is not "mostly server-side" or "server-side on first load" — SvelteKit re-runs it client-side on every subsequent navigation by default.
    - Do not assume SvelteKit's build-time `$env/static/private` / `$env/dynamic/private` import guard catches every leak. It blocks direct imports of those modules from client-reachable files, but it does not catch manual `process.env` reads, a `$lib/server`-protected module re-exporting a secret through a non-`.server` module, or a secret being copied into the plain object a server `load` returns.
    - Trace secrets and DB clients through the full import graph, including transitive `$lib` imports — a universal `load` that imports an innocuous-looking `$lib/utils.js` which itself imports `$lib/server/db.js` is still a leak path (and SvelteKit's server-only module protection should catch that specific case at build time; verify it does, do not assume).
    - Treat any private value present in the plain object a server `load` (or `+layout.server.js`) returns as a candidate leak the moment a universal `load`, a client component, or `page.data`/`$page.data` can read it — server `load` output crosses the server/client boundary via devalue serialization, it is not automatically safe just because it originated server-side.
    - Never mark a `+page.server.js` or `+layout.server.js` file itself as a browser-exposure risk for containing secrets or DB calls — those files are always server-only by SvelteKit's routing contract; the risk is in what they choose to *return*, not that they execute.
    - Do not flag deep or repeated `+layout.server.js` logic as a leak; flag it as a MEDIUM duplication/maintainability finding only, distinct from HIGH-severity leak findings.
    - Never execute, build, or run application code as part of this review; this is a static-review skill (Read/Grep/Glob only).
    
    ## References
    
    Load these only when needed:
    
    - [Review workflow and findings contract](references/workflow-and-output.md) — use for the step-by-step review procedure, the leak-tracing decision tree, and the required output shape.
    - [Routing conventions](references/routing-conventions.md) — load only when `+layout`/`+page`/`+server` file precedence or route-tree structure (not just load placement) is in question.
    
    ## Response minimum
    
    Return, at minimum:
    
    - the route(s) and file(s) in scope, each labeled universal or server load,
    - ranked findings with file:line evidence and the full import/data-flow trace for any leak finding,
    - evidence level per finding (`repo evidence`, `documentation-based`, or `inference`),
    - verdict (approve / approve-with-notes / block),
    - open questions or scope the review could not cover (e.g., unverified `svelte.config.js` env prefix, unread transitive `$lib` module).
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related