cirrojs 0.0.17 → 0.0.18

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/CHANGELOG.md CHANGED
@@ -13,6 +13,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
13
13
 
14
14
  ## [Unreleased]
15
15
 
16
+ ## [0.0.18] - 2026-06-29
17
+
18
+ ### Added
19
+ - `defineRoutes`, exported from the package entry point. It is an identity helper that returns its route arguments as an `AnyRoute[]`, used to define a site's routes for export.
20
+
21
+ ### Changed
22
+ - A route's `path` is now the full output path (for example `/index.html`, `/about.html`, `/posts/hello.html`) instead of a clean URL. The build writes each page to that path verbatim, without appending `index.html`.
23
+ - `StaticRoute` now requires a `cssPath` field naming the output path of its generated stylesheet, matching `DynamicRoute` and `FileRoute`.
24
+ - Sites must export their routes as the default export (typically the result of `defineRoutes`) instead of a named `routes` export. The dev server reads the default export and reports an error when it is missing or is not an array.
25
+
16
26
  ## [0.0.17] - 2026-06-29
17
27
 
18
28
  ### Added
@@ -137,7 +147,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
137
147
  ## 0.0.1 - 2026-06-15
138
148
  - initial release
139
149
 
140
- [Unreleased]: https://github.com/osawa-naotaka/cirro/compare/v0.0.17...HEAD
150
+ [Unreleased]: https://github.com/osawa-naotaka/cirro/compare/v0.0.18...HEAD
151
+ [0.0.18]: https://github.com/osawa-naotaka/cirro/compare/v0.0.17...v0.0.18
141
152
  [0.0.17]: https://github.com/osawa-naotaka/cirro/compare/v0.0.16...v0.0.17
142
153
  [0.0.16]: https://github.com/osawa-naotaka/cirro/compare/v0.0.15...v0.0.16
143
154
  [0.0.15]: https://github.com/osawa-naotaka/cirro/compare/v0.0.14...v0.0.15
package/dist/cli.js CHANGED
@@ -1 +1,17 @@
1
- import{r as e}from"./css-D28QH0EJ.js";import{Fragment as t,createElement as n}from"react";import{renderToStaticMarkup as r}from"react-dom/server";import{dirname as i,extname as a,join as o,resolve as s}from"node:path";import{mkdir as c,readFile as l,writeFile as u}from"node:fs/promises";import{build as d,createServer as f,createServerModuleRunner as p}from"vite";import{createServer as m}from"node:http";function h(e){let t=[];for(let n of e)switch(n.type){case`static`:t.push({type:`html`,path:n.path,cssPath:o(n.path,`index.css`),render:()=>n.component({params:{}})}),t.push({type:`css`,path:o(n.path,`index.css`),render:()=>n.component({params:{}})});break;case`dynamic`:for(let e of n.getStaticPaths())t.push({type:`html`,path:n.path(e),cssPath:n.cssPath,render:()=>n.component({params:e})});t.push({type:`css`,path:n.cssPath,render:()=>n.component({params:n.getStaticPaths()[0]})});break;case`file`:t.push({type:`file`,path:n.path,ext:a(n.path),render:()=>n.component({params:{}})});break}return t}function g(e){return e===`/`?`index.html`:`${e.replace(/^\/+|\/+$/g,``)}/index.html`}function _(e){return e===`/`?`index.css`:`${e.replace(/^\/+|\/+$/g,``)}`}function v(e,r,i){return n(t,null,e,n(`script`,{async:!0,type:`module`,src:r,key:`cirro-client`}),n(`link`,{rel:`stylesheet`,href:i,precedence:`default`,key:`cirro-css`}))}function y(e){for(let t of e.plugins){let e=t.api;if(t.name===`cirro`&&e?.options)return e.options}throw Error(`cirro: plugin not found in Vite config (did you add cirro() to plugins?)`)}async function b(){process.env.CIRRO_COMMAND=`build`,await d();let t=await f({server:{middlewareMode:!0,hmr:!1},appType:`custom`}),n=p(t.environments.ssr);try{let a=t.config,d=y(a),f=a.root,p=s(f,a.build.outDir),m=s(f,d.routes),b=JSON.parse(await l(o(p,`.vite/manifest.json`),`utf-8`))[`virtual:cirro/client`];if(!b)throw Error(`cirro: manifest entry "virtual:cirro/client" not found`);let x=`/${b.file}`,{routes:S,runWithRegistry:C}=await n.import(m);for(let t of h(S))switch(t.type){case`css`:{let{registry:n}=C(()=>r(t.render())),a=e(n),s=o(p,_(t.path));await c(i(s),{recursive:!0}),await u(s,a),console.log(`wrote ${s} (url: ${t.path})`);break}case`html`:{let{result:e}=C(()=>`<!DOCTYPE html>${r(v(t.render(),x,t.cssPath))}`),n=o(p,g(t.path));await c(i(n),{recursive:!0}),await u(n,e),console.log(`wrote ${n} (url: ${t.path})`);break}case`file`:{let e=t.render(),n=o(p,t.path);await c(i(n),{recursive:!0}),await u(n,e),console.log(`wrote ${n} (url: ${t.path})`);break}}}finally{await t.close()}}const x=[[`.aac`,`audio/aac`],[`.abw`,`application/x-abiword`],[`.arc`,`application/x-freearc`],[`.avi`,`video/x-msvideo`],[`.azw`,`application/vnd.amazon.ebook`],[`.bin`,`application/octet-stream`],[`.bmp`,`image/bmp`],[`.bz`,`application/x-bzip`],[`.bz2`,`application/x-bzip2`],[`.csh`,`application/x-csh`],[`.css`,`text/css`],[`.csv`,`text/csv`],[`.doc`,`application/msword`],[`.docx`,`application/vnd.openxmlformats-officedocument.wordprocessingml.document`],[`.eot`,`application/vnd.ms-fontobject`],[`.epub`,`application/epub+zip`],[`.gz`,`application/gzip`],[`.gif`,`image/gif`],[`.htm`,`text/html`],[`.html`,`text/html`],[`.ico`,`image/vnd.microsoft.icon`],[`.ics`,`text/calendar`],[`.jar`,`application/java-archive`],[`.jpeg`,`image/jpeg`],[`.jpg`,`image/jpeg`],[`.js`,`text/javascript`],[`.json`,`application/json`],[`.jsonld`,`application/ld+json`],[`.mid`,`audio/midi`],[`.midi`,`audio/x-midi`],[`.mjs`,`text/javascript`],[`.mp3`,`audio/mpeg`],[`.mpeg`,`video/mpeg`],[`.mpkg`,`application/vnd.apple.installer+xml`],[`.odp`,`application/vnd.oasis.opendocument.presentation`],[`.ods`,`application/vnd.oasis.opendocument.spreadsheet`],[`.odt`,`application/vnd.oasis.opendocument.text`],[`.oga`,`audio/ogg`],[`.ogv`,`video/ogg`],[`.ogx`,`application/ogg`],[`.opus`,`audio/opus`],[`.otf`,`font/otf`],[`.png`,`image/png`],[`.pdf`,`application/pdf`],[`.php`,`application/x-httpd-php`],[`.ppt`,`application/vnd.ms-powerpoint`],[`.pptx`,`application/vnd.openxmlformats-officedocument.presentationml.presentation`],[`.rar`,`application/vnd.rar`],[`.rtf`,`application/rtf`],[`.sh`,`application/x-sh`],[`.svg`,`image/svg+xml`],[`.swf`,`application/x-shockwave-flash`],[`.tar`,`application/x-tar`],[`.tif`,`image/tiff`],[`.tiff`,`image/tiff`],[`.ts`,`video/mp2t`],[`.ttf`,`font/ttf`],[`.txt`,`text/plain`],[`.vsd`,`application/vnd.visio`],[`.wav`,`audio/wav`],[`.weba`,`audio/webm`],[`.webm`,`video/webm`],[`.webp`,`image/webp`],[`.woff`,`font/woff`],[`.woff2`,`font/woff2`],[`.xhtml`,`application/xhtml+xml`],[`.xls`,`application/vnd.ms-excel`],[`.xlsx`,`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`],[`.xml`,`application/xml`],[`.xul`,`application/vnd.mozilla.xul+xml`],[`.zip`,`application/zip`],[`.3gp`,`video/3gpp`],[`.3g2`,`video/3gpp2`],[`.7z`,`application/x-7z-compressed`]];function S(e){return x.find(t=>t[0]===e)?.[1]||`text/plain`}function C(e,t){let n=[t,t.replaceAll(`\\`,`/`)];for(let t of Object.values(e.environments)){let e=t.moduleGraph;if(!e)continue;let r=new Set,i=t=>{if(!r.has(t)){r.add(t),e.invalidateModule(t);for(let e of t.importers)i(e)}};for(let t of n){let n=e.getModulesByFile(t);if(n)for(let e of n)i(e)}}}async function w(t=5173){process.env.CIRRO_COMMAND=`dev`;let n=await f({server:{middlewareMode:!0},appType:`custom`}),a=p(n.environments.ssr),o=y(n.config),c=n.config.root,l=s(c,o.routes),u=i(s(c,o.islands)).replaceAll(`\\`,`/`),d=m((t,i)=>{function o(e,t){i.statusCode=200,i.setHeader(`Content-Type`,S(e)),i.end(t)}function s(e){i.statusCode=404,i.setHeader(`Content-Type`,S(e)),e===`.html`?i.end(`<!DOCTYPE html><meta charset="utf-8"><h1>404 Not Found</h1>`):i.end()}n.middlewares(t,i,async()=>{let c=t.url??`/`,u=new URL(c,`http://localhost`).pathname.replace(/\/+$/,``)||`/`;try{let{routes:t,runWithRegistry:i}=await a.import(l),d=h(t).find(e=>e.path===u);if(d===void 0){s(`.html`);return}switch(d.type){case`html`:{let{result:e}=i(()=>`<!DOCTYPE html>${r(v(d.render(),`/@id/__x00__virtual:cirro/client`,d.cssPath))}`);o(`.html`,await n.transformIndexHtml(c,e));break}case`css`:{let{registry:t}=i(()=>r(d.render()));o(`.css`,e(t));break}case`file`:{let e=d.render();o(d.ext,e);break}}return}catch(e){i.statusCode=500,e instanceof Error?i.end(e.stack):i.end(String(e))}})}),g=`${s(c,o.watchDir??`./src`).replaceAll(`\\`,`/`).replace(/\/+$/,``)}/`;n.watcher.on(`change`,e=>{let t=e.replaceAll(`\\`,`/`);t.startsWith(u)||t.startsWith(g)&&(C(n,e),n.ws.send({type:`full-reload`}))}),d.listen(t,()=>{console.log(`cirro dev: http://localhost:${t}`)})}async function T(e){let t=e[0];t===`dev`?await w():t===`build`?await b():(console.error(`usage: cirro <dev|build>`),process.exit(1))}export{T as main};
1
+ import{r as e}from"./css-D28QH0EJ.js";import{Fragment as t,createElement as n}from"react";import{renderToStaticMarkup as r}from"react-dom/server";import{dirname as i,extname as a,join as o,resolve as s}from"node:path";import{mkdir as c,readFile as l,writeFile as u}from"node:fs/promises";import{build as d,createServer as f,createServerModuleRunner as p}from"vite";import{createServer as m}from"node:http";function h(e){let t=[];for(let n of e)switch(n.type){case`static`:t.push({type:`html`,path:n.path,cssPath:n.cssPath,render:()=>n.component({params:{}})}),t.push({type:`css`,path:n.cssPath,render:()=>n.component({params:{}})});break;case`dynamic`:for(let e of n.getStaticPaths())t.push({type:`html`,path:n.path(e),cssPath:n.cssPath,render:()=>n.component({params:e})});t.push({type:`css`,path:n.cssPath,render:()=>n.component({params:n.getStaticPaths()[0]})});break;case`file`:t.push({type:`file`,path:n.path,ext:a(n.path),render:()=>n.component({params:{}})});break}return t}function g(e,r,i){return n(t,null,e,n(`script`,{async:!0,type:`module`,src:r,key:`cirro-client`}),n(`link`,{rel:`stylesheet`,href:i,precedence:`default`,key:`cirro-css`}))}function _(e){for(let t of e.plugins){let e=t.api;if(t.name===`cirro`&&e?.options)return e.options}throw Error(`cirro: plugin not found in Vite config (did you add cirro() to plugins?)`)}async function v(){process.env.CIRRO_COMMAND=`build`,await d();let t=await f({server:{middlewareMode:!0,hmr:!1},appType:`custom`}),n=p(t.environments.ssr);try{let a=Date.now(),d=t.config,f=_(d),p=d.root,m=s(p,d.build.outDir),v=s(p,f.routes),y=JSON.parse(await l(o(m,`.vite/manifest.json`),`utf-8`))[`virtual:cirro/client`];if(!y)throw Error(`cirro: manifest entry "virtual:cirro/client" not found`);let b=`/${y.file}`,{routes:x,runWithRegistry:S}=await n.import(v);for(let t of h(x))switch(t.type){case`css`:{let{registry:n}=S(()=>r(t.render())),a=e(n),s=o(m,t.path);await c(i(s),{recursive:!0}),await u(s,a),console.log(`wrote ${s} (url: ${t.path})`);break}case`html`:{let{result:e}=S(()=>`<!DOCTYPE html>${r(g(t.render(),b,t.cssPath))}`),n=o(m,t.path);await c(i(n),{recursive:!0}),await u(n,e),console.log(`wrote ${n} (url: ${t.path})`);break}case`file`:{let e=t.render(),n=o(m,t.path);await c(i(n),{recursive:!0}),await u(n,e),console.log(`wrote ${n} (url: ${t.path})`);break}}console.log(`build completed in ${Date.now()-a}ms`)}finally{await t.close()}}const y=[[`.aac`,`audio/aac`],[`.abw`,`application/x-abiword`],[`.arc`,`application/x-freearc`],[`.avi`,`video/x-msvideo`],[`.azw`,`application/vnd.amazon.ebook`],[`.bin`,`application/octet-stream`],[`.bmp`,`image/bmp`],[`.bz`,`application/x-bzip`],[`.bz2`,`application/x-bzip2`],[`.csh`,`application/x-csh`],[`.css`,`text/css`],[`.csv`,`text/csv`],[`.doc`,`application/msword`],[`.docx`,`application/vnd.openxmlformats-officedocument.wordprocessingml.document`],[`.eot`,`application/vnd.ms-fontobject`],[`.epub`,`application/epub+zip`],[`.gz`,`application/gzip`],[`.gif`,`image/gif`],[`.htm`,`text/html`],[`.html`,`text/html`],[`.ico`,`image/vnd.microsoft.icon`],[`.ics`,`text/calendar`],[`.jar`,`application/java-archive`],[`.jpeg`,`image/jpeg`],[`.jpg`,`image/jpeg`],[`.js`,`text/javascript`],[`.json`,`application/json`],[`.jsonld`,`application/ld+json`],[`.mid`,`audio/midi`],[`.midi`,`audio/x-midi`],[`.mjs`,`text/javascript`],[`.mp3`,`audio/mpeg`],[`.mpeg`,`video/mpeg`],[`.mpkg`,`application/vnd.apple.installer+xml`],[`.odp`,`application/vnd.oasis.opendocument.presentation`],[`.ods`,`application/vnd.oasis.opendocument.spreadsheet`],[`.odt`,`application/vnd.oasis.opendocument.text`],[`.oga`,`audio/ogg`],[`.ogv`,`video/ogg`],[`.ogx`,`application/ogg`],[`.opus`,`audio/opus`],[`.otf`,`font/otf`],[`.png`,`image/png`],[`.pdf`,`application/pdf`],[`.php`,`application/x-httpd-php`],[`.ppt`,`application/vnd.ms-powerpoint`],[`.pptx`,`application/vnd.openxmlformats-officedocument.presentationml.presentation`],[`.rar`,`application/vnd.rar`],[`.rtf`,`application/rtf`],[`.sh`,`application/x-sh`],[`.svg`,`image/svg+xml`],[`.swf`,`application/x-shockwave-flash`],[`.tar`,`application/x-tar`],[`.tif`,`image/tiff`],[`.tiff`,`image/tiff`],[`.ts`,`video/mp2t`],[`.ttf`,`font/ttf`],[`.txt`,`text/plain`],[`.vsd`,`application/vnd.visio`],[`.wav`,`audio/wav`],[`.weba`,`audio/webm`],[`.webm`,`video/webm`],[`.webp`,`image/webp`],[`.woff`,`font/woff`],[`.woff2`,`font/woff2`],[`.xhtml`,`application/xhtml+xml`],[`.xls`,`application/vnd.ms-excel`],[`.xlsx`,`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`],[`.xml`,`application/xml`],[`.xul`,`application/vnd.mozilla.xul+xml`],[`.zip`,`application/zip`],[`.3gp`,`video/3gpp`],[`.3g2`,`video/3gpp2`],[`.7z`,`application/x-7z-compressed`]];function b(e){return y.find(t=>t[0]===e)?.[1]||`text/plain`}function x(e,t){let n=[t,t.replaceAll(`\\`,`/`)];for(let t of Object.values(e.environments)){let e=t.moduleGraph;if(!e)continue;let r=new Set,i=t=>{if(!r.has(t)){r.add(t),e.invalidateModule(t);for(let e of t.importers)i(e)}};for(let t of n){let n=e.getModulesByFile(t);if(n)for(let e of n)i(e)}}}async function S(t=5173){process.env.CIRRO_COMMAND=`dev`;let n=await f({server:{middlewareMode:!0},appType:`custom`}),a=p(n.environments.ssr),o=_(n.config),c=n.config.root,l=s(c,o.routes),u=i(s(c,o.islands)).replaceAll(`\\`,`/`),d=m((t,i)=>{function o(e,t){i.statusCode=200,i.setHeader(`Content-Type`,b(e)),i.end(t)}function s(e,t){i.statusCode=404,i.setHeader(`Content-Type`,b(e)),e===`.html`?i.end(C(t)):i.end()}n.middlewares(t,i,async()=>{let c=t.url??`/`,u=new URL(c,`http://localhost`).pathname,d=new Set;u.endsWith(`.html`)||u.endsWith(`.htm`)?d.add(u):u.endsWith(`/`)?(d.add(`${u}index.html`),d.add(`${u}index.htm`)):(d.add(`${u}.html`),d.add(`${u}.htm`),d.add(u));try{let t=await a.import(l);if(typeof t.runWithRegistry!=`function`){s(`.html`,"you must export a `runWithRegistry` function");return}if(!Array.isArray(t.default)){s(`.html`,"you must define routes and export it as `default`");return}let i=h(t.default).find(e=>d.has(e.path));if(i===void 0){s(`.html`,`no route found for the requested path: ${u}`);return}switch(i.type){case`html`:{let{result:e}=t.runWithRegistry(()=>`<!DOCTYPE html>${r(g(i.render(),`/@id/__x00__virtual:cirro/client`,i.cssPath))}`);o(`.html`,await n.transformIndexHtml(c,e));break}case`css`:{let{registry:n}=t.runWithRegistry(()=>r(i.render()));o(`.css`,e(n));break}case`file`:{let e=i.render();o(i.ext,e);break}}return}catch(e){i.statusCode=500,i.setHeader(`Content-Type`,b(`.html`)),e instanceof Error?i.end(C(e.stack??String(e))):i.end(C(String(e)))}})}),v=`${s(c,o.watchDir??`./src`).replaceAll(`\\`,`/`).replace(/\/+$/,``)}/`;n.watcher.on(`change`,e=>{let t=e.replaceAll(`\\`,`/`);t.startsWith(u)||t.startsWith(v)&&(x(n,e),n.ws.send({type:`full-reload`}))}),d.listen(t,()=>{console.log(`cirro dev: http://localhost:${t}`)})}function C(e){return`
2
+ <!DOCTYPE html>
3
+ <html>
4
+ <head>
5
+ <title>Error - cirro</title>
6
+ <meta charset="utf-8">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+ <style>
9
+ body {
10
+ font-family: sans-serif;
11
+ background-color: #f8f8f8;
12
+ color: #333;
13
+ }
14
+ </style>
15
+ </head>
16
+ <body><h1>Error</h1><pre>${e}</pre></body>
17
+ </html>`}async function w(e){let t=e[0];t===`dev`?await S():t===`build`?await v():(console.error(`usage: cirro <dev|build>`),process.exit(1))}export{w as main};
package/dist/index.d.ts CHANGED
@@ -9,6 +9,7 @@ type Params = Record<string, unknown>;
9
9
  type StaticRoute = {
10
10
  type: "static";
11
11
  path: string;
12
+ cssPath: string;
12
13
  component: (props: {
13
14
  params: Record<string, never>;
14
15
  }) => ReactElement;
@@ -30,5 +31,6 @@ type FileRoute = {
30
31
  }) => string;
31
32
  };
32
33
  type AnyRoute = StaticRoute | DynamicRoute<any> | FileRoute;
34
+ declare function defineRoutes(...routes: AnyRoute[]): AnyRoute[];
33
35
  //#endregion
34
- export { type AnyRoute, type CssOpt, type DynamicRoute, type FileRoute, type Params, type Properties, type Registry, type StaticRoute, css, genCssFn, runWithRegistry };
36
+ export { type AnyRoute, type CssOpt, type DynamicRoute, type FileRoute, type Params, type Properties, type Registry, type StaticRoute, css, defineRoutes, genCssFn, runWithRegistry };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{n as e,t}from"./css-D28QH0EJ.js";import{runWithRegistry as n}from"cirrojs/registry";export{t as css,e as genCssFn,n as runWithRegistry};
1
+ import{n as e,t}from"./css-D28QH0EJ.js";import{runWithRegistry as n}from"cirrojs/registry";function r(...e){return e}export{t as css,r as defineRoutes,e as genCssFn,n as runWithRegistry};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cirrojs",
3
- "version": "0.0.17",
3
+ "version": "0.0.18",
4
4
  "description": "React islands SSG with strict CSP (no unsafe-inline). Vite-based, MPA-first.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -73,7 +73,7 @@
73
73
  },
74
74
  "scripts": {
75
75
  "build": "tsdown",
76
- "typecheck": "tsc -p tsconfig.build.json --noEmit",
76
+ "typecheck": "tsc -p tsconfig.json --noEmit",
77
77
  "format": "biome check --write ./src"
78
78
  }
79
79
  }