cirrojs 0.0.4 → 0.0.5

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,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
13
13
 
14
14
  ## [Unreleased]
15
15
 
16
+ ## [0.0.5] - 2026-06-18
17
+
18
+ ### Added
19
+ - New `cirrojs/server` entry point exporting the server-only API (`createIsland`, `createMarkdown`, and the `MarkdownConfig`, `RenderResult`, `ToC` types).
20
+
21
+ ### Changed
22
+ - Moved `createIsland` and `createMarkdown` from the main entry point (`cirrojs`) to `cirrojs/server` to keep server-only dependencies (`react-dom/server`, remark/rehype/prismjs) out of the client bundle.
23
+ - Changed the `genCssFn` signature to take a single `GenCssFnOpt` options object (`{ mediaAtRule?, layer? }`) instead of positional arguments.
24
+
16
25
  ## [0.0.4] - 2026-06-17
17
26
 
18
27
  ### Added
@@ -32,7 +41,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
32
41
  ## 0.0.1 - 2026-06-15
33
42
  - initial release
34
43
 
35
- [Unreleased]: https://github.com/osawa-naotaka/cirro/compare/v0.0.4...HEAD
44
+ [Unreleased]: https://github.com/osawa-naotaka/cirro/compare/v0.0.5...HEAD
45
+ [0.0.5]: https://github.com/osawa-naotaka/cirro/compare/v0.0.4...v0.0.5
36
46
  [0.0.4]: https://github.com/osawa-naotaka/cirro/compare/v0.0.3...v0.0.4
37
47
  [0.0.3]: https://github.com/osawa-naotaka/cirro/compare/v0.0.2...v0.0.3
38
48
  [0.0.2]: https://github.com/osawa-naotaka/cirro/compare/v0.0.1...v0.0.2
package/dist/cli.js CHANGED
@@ -1 +1 @@
1
- import{c as e,l as t,o as n,r}from"./css-BpSvZXlg.js";import{Fragment as i,createElement as a}from"react";import{renderToStaticMarkup as o}from"react-dom/server";import{dirname as s,join as c,resolve as l}from"node:path";import{mkdir as u,readFile as d,writeFile as f}from"node:fs/promises";import{build as p,createServer as m,createServerModuleRunner as h}from"vite";import{createServer as g}from"node:http";function _(e,t,n){return a(i,null,e,a(`script`,{async:!0,type:`module`,src:t,key:`cirro-client`}),a(`link`,{rel:`stylesheet`,href:n,key:`cirro-css`}))}function v(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 y(){await p();let i=await m({server:{middlewareMode:!0,hmr:!1},appType:`custom`}),a=h(i.environments.ssr);try{let p=i.config,m=v(p),h=p.root,g=l(h,p.build.outDir),y=l(h,m.routes),b=JSON.parse(await d(c(g,`.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,getCssRegistry:C,initCssRegistry:w}=await a.import(y);for(let i of n(S)){if(i.isCss){w(),o(i.render());let t=r(C()),n=c(g,e(i.url));await u(s(n),{recursive:!0}),await f(n,t),console.log(`wrote ${n} (url: ${i.url})`);continue}let n=`<!DOCTYPE html>${o(_(i.render(),x,i.cssPath))}`,a=c(g,t(i.url));await u(s(a),{recursive:!0}),await f(a,n),console.log(`wrote ${a} (url: ${i.url})`)}}finally{await i.close()}}function b(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 x(e=5173){let t=await m({server:{middlewareMode:!0},appType:`custom`}),i=h(t.environments.ssr),a=v(t.config),c=t.config.root,u=l(c,a.routes),d=s(l(c,a.islands)).replaceAll(`\\`,`/`),f=g((e,a)=>{t.middlewares(e,a,async()=>{let s=e.url??`/`;try{let{routes:e,getCssRegistry:c,initCssRegistry:l}=await i.import(u),d=n(e);if(s.endsWith(`.css`)){let e=d.find(e=>e.isCss&&e.url===s);if(!e){a.statusCode=404,a.end();return}l(),o(e.render());let t=r(c());a.statusCode=200,a.setHeader(`Content-Type`,`text/css; charset=utf-8`),a.end(t);return}let f=new URL(s,`http://localhost`).pathname.replace(/\/+$/,``)||`/`,p=d.find(e=>(e.url.replace(/\/+$/,``)||`/`)===f);if(!p){a.statusCode=404,a.setHeader(`Content-Type`,`text/html; charset=utf-8`),a.end(`<!DOCTYPE html><meta charset="utf-8"><h1>404 Not Found</h1>`);return}let m=`<!DOCTYPE html>${o(_(p.render(),`/@id/__x00__virtual:cirro/client`,p.cssPath))}`;m=await t.transformIndexHtml(s,m),a.statusCode=200,a.setHeader(`Content-Type`,`text/html; charset=utf-8`),a.end(m)}catch(e){a.statusCode=500,a.end(String(e))}})}),p=`${l(c,a.watchDir??`./src`).replaceAll(`\\`,`/`).replace(/\/+$/,``)}/`;t.watcher.on(`change`,e=>{let n=e.replaceAll(`\\`,`/`);n.startsWith(d)||n.startsWith(p)&&(b(t,e),t.ws.send({type:`full-reload`}))}),f.listen(e,()=>{console.log(`cirro dev: http://localhost:${e}`)})}async function S(e){let t=e[0];t===`dev`?await x():t===`build`?await y():(console.error(`usage: cirro <dev|build>`),process.exit(1))}export{S as main};
1
+ import{c as e,l as t,o as n,r}from"./css-DDEJecy6.js";import{Fragment as i,createElement as a}from"react";import{renderToStaticMarkup as o}from"react-dom/server";import{dirname as s,join as c,resolve as l}from"node:path";import{mkdir as u,readFile as d,writeFile as f}from"node:fs/promises";import{build as p,createServer as m,createServerModuleRunner as h}from"vite";import{createServer as g}from"node:http";function _(e,t,n){return a(i,null,e,a(`script`,{async:!0,type:`module`,src:t,key:`cirro-client`}),a(`link`,{rel:`stylesheet`,href:n,precedence:`default`,key:`cirro-css`}))}function v(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 y(){await p();let i=await m({server:{middlewareMode:!0,hmr:!1},appType:`custom`}),a=h(i.environments.ssr);try{let p=i.config,m=v(p),h=p.root,g=l(h,p.build.outDir),y=l(h,m.routes),b=JSON.parse(await d(c(g,`.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,getCssRegistry:C,initCssRegistry:w}=await a.import(y);for(let i of n(S)){if(i.isCss){w(),o(i.render());let t=r(C()),n=c(g,e(i.url));await u(s(n),{recursive:!0}),await f(n,t),console.log(`wrote ${n} (url: ${i.url})`);continue}let n=`<!DOCTYPE html>${o(_(i.render(),x,i.cssPath))}`,a=c(g,t(i.url));await u(s(a),{recursive:!0}),await f(a,n),console.log(`wrote ${a} (url: ${i.url})`)}}finally{await i.close()}}function b(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 x(e=5173){let t=await m({server:{middlewareMode:!0},appType:`custom`}),i=h(t.environments.ssr),a=v(t.config),c=t.config.root,u=l(c,a.routes),d=s(l(c,a.islands)).replaceAll(`\\`,`/`),f=g((e,a)=>{t.middlewares(e,a,async()=>{let s=e.url??`/`;try{let{routes:e,getCssRegistry:c,initCssRegistry:l}=await i.import(u),d=n(e);if(s.endsWith(`.css`)){let e=d.find(e=>e.isCss&&e.url===s);if(!e){a.statusCode=404,a.end();return}l(),o(e.render());let t=r(c());a.statusCode=200,a.setHeader(`Content-Type`,`text/css; charset=utf-8`),a.end(t);return}let f=new URL(s,`http://localhost`).pathname.replace(/\/+$/,``)||`/`,p=d.find(e=>(e.url.replace(/\/+$/,``)||`/`)===f);if(!p){a.statusCode=404,a.setHeader(`Content-Type`,`text/html; charset=utf-8`),a.end(`<!DOCTYPE html><meta charset="utf-8"><h1>404 Not Found</h1>`);return}let m=`<!DOCTYPE html>${o(_(p.render(),`/@id/__x00__virtual:cirro/client`,p.cssPath))}`;m=await t.transformIndexHtml(s,m),a.statusCode=200,a.setHeader(`Content-Type`,`text/html; charset=utf-8`),a.end(m)}catch(e){a.statusCode=500,a.end(String(e))}})}),p=`${l(c,a.watchDir??`./src`).replaceAll(`\\`,`/`).replace(/\/+$/,``)}/`;t.watcher.on(`change`,e=>{let n=e.replaceAll(`\\`,`/`);n.startsWith(d)||n.startsWith(p)&&(b(t,e),t.ws.send({type:`full-reload`}))}),f.listen(e,()=>{console.log(`cirro dev: http://localhost:${e}`)})}async function S(e){let t=e[0];t===`dev`?await x():t===`build`?await y():(console.error(`usage: cirro <dev|build>`),process.exit(1))}export{S as main};
@@ -0,0 +1,4 @@
1
+ function e(e){return e}function t(e){let t=[];for(let n of e)if(`getStaticPaths`in n){for(let e of n.getStaticPaths())t.push({url:n.path(e),isCss:!1,cssPath:n.cssPath,render:()=>n.component({params:e})});t.push({url:n.cssPath,isCss:!0,cssPath:n.cssPath,render:()=>n.component({params:n.getStaticPaths()[0]})})}else t.push({url:n.path,isCss:!1,cssPath:i(n.path,`index.css`),render:()=>n.component({params:{}})}),t.push({url:i(n.path,`index.css`),isCss:!0,cssPath:i(n.path,`index.css`),render:()=>n.component({params:{}})});return t}function n(e){return e===`/`?`index.html`:`${e.replace(/^\/+|\/+$/g,``)}/index.html`}function r(e){return e===`/`?`index.css`:`${e.replace(/^\/+|\/+$/g,``)}`}function i(...e){return e.reduce((e,t)=>e.endsWith(`/`)&&t.startsWith(`/`)?`${e}${t.substring(1)}`:e.endsWith(`/`)||t.startsWith(`/`)?`${e}${t}`:`${e}/${t}`,``)}let a=[];function o(e,t){a.push([e,t])}function s(){a=[]}function c(){return a}function l(e,t){let n=t?.selector??`&`,r=t?.atrules??[],i=p(e),a=`${t?.name??`cirro`}-${i.toString(16)}`;return f([...r,n],e,a),a}function u(e){let t=[];return e.layer&&t.push(`@layer ${e.layer}`),e.mediaAtRule&&t.push(`@media (${e.mediaAtRule})`),(e,n)=>l(e,{atrules:t,name:n?.name,selector:n?.selector})}function d(e){let t=`@charset "utf-8";
2
+ @layer base, font, low, main, high;
3
+ `;for(let[n,r]of e)t+=n.reduceRight((e,t)=>`${t} { ${e} }`,Object.entries(r).map(([e,t])=>`${e.replaceAll(`_`,`-`)}: ${t};`).join(` `)),t+=`
4
+ `;return t}function f(e,t,n){o(e.map(e=>e.replaceAll(`&`,`.${n}`)),t)}function p(...e){return m(e.map(e=>JSON.stringify(e)).join(``))}function m(e){let t=5381;for(let n of[...e])t=(t<<5)+t+n.charCodeAt(0)&4294967295;return t>>>0}export{s as a,r as c,c as i,n as l,u as n,t as o,d as r,e as s,l as t};
package/dist/index.d.ts CHANGED
@@ -1,52 +1,5 @@
1
- import { ComponentProps, ComponentType, ReactElement } from "react";
2
- import { ToC, ToC as ToC$1 } from "remark-export-toc";
3
- import { PluggableList } from "unified";
4
- import { Schema } from "hast-util-sanitize";
1
+ import { ReactElement } from "react";
5
2
 
6
- //#region src/island.d.ts
7
- type IslandRegistry = Record<string, ComponentType<any>>;
8
- declare function createIsland<R extends IslandRegistry>(islands: R): <K extends keyof R & string>({
9
- name,
10
- props
11
- }: {
12
- name: K;
13
- props: ComponentProps<R[K]>;
14
- }) => import("react").DetailedReactHTMLElement<{
15
- "data-island": K;
16
- "data-props": string;
17
- dangerouslySetInnerHTML: {
18
- __html: string;
19
- };
20
- }, HTMLElement>;
21
- //#endregion
22
- //#region src/markdown.d.ts
23
- interface MarkdownConfig {
24
- remarkPlugins?: PluggableList;
25
- rehypePlugins?: PluggableList;
26
- sanitizeSchema?: (defaults: Schema) => Schema;
27
- toc?: boolean | {
28
- prefix?: string;
29
- startLevel?: number;
30
- };
31
- highlight?: boolean;
32
- }
33
- interface RenderResult {
34
- body: ReactElement;
35
- toc: ToC$1[];
36
- }
37
- declare function createMarkdown(config?: MarkdownConfig): {
38
- Markdown: ({
39
- source,
40
- className
41
- }: {
42
- source: string;
43
- className?: string;
44
- }) => ReactElement;
45
- render: (source: string, options?: {
46
- className?: string;
47
- }) => RenderResult;
48
- };
49
- //#endregion
50
3
  //#region src/router.d.ts
51
4
  type Params = Record<string, string>;
52
5
  type StaticRoute = {
@@ -547,10 +500,11 @@ type CssOpt = {
547
500
  selector?: string;
548
501
  };
549
502
  declare function css(properties: Properties, opt?: CssOpt): string;
550
- type CssFnT = (properties: Properties, opt?: {
551
- name?: string;
552
- selector?: string;
553
- }) => string;
554
- declare function genCssFn(mediaAtRule: string, layer?: string): CssFnT;
503
+ type CssFnT = (properties: Properties, opt?: Omit<CssOpt, "atrules">) => string;
504
+ type GenCssFnOpt = {
505
+ mediaAtRule?: string;
506
+ layer?: string;
507
+ };
508
+ declare function genCssFn(opt: GenCssFnOpt): CssFnT;
555
509
  //#endregion
556
- export { type AnyRoute, type CssOpt, type DynamicRoute, type MarkdownConfig, type Params, type Properties, type RenderResult, type ResolvedPage, type StaticRoute, type ToC, createIsland, createMarkdown, css, expandRoutes, genCssFn, getCssRegistry, initCssRegistry, route, urlToFilePath };
510
+ export { type AnyRoute, type CssOpt, type DynamicRoute, type Params, type Properties, type ResolvedPage, type StaticRoute, css, expandRoutes, genCssFn, getCssRegistry, initCssRegistry, route, urlToFilePath };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{a as e,i as t,l as n,n as r,o as i,s as a,t as o}from"./css-BpSvZXlg.js";import{createElement as s}from"react";import{renderToString as c}from"react-dom/server";import l from"rehype-prism";import u,{defaultSchema as d}from"rehype-sanitize";import f from"rehype-stringify";import p from"remark-export-toc";import m from"remark-parse";import h from"remark-rehype";import{unified as g}from"unified";import{jsx as _}from"react/jsx-runtime";function v(e){return function({name:t,props:n}){let r=c(s(e[t],n));return s(`div`,{"data-island":t,"data-props":JSON.stringify(n),dangerouslySetInnerHTML:{__html:r}})}}function y(e={}){let t={prefix:`heading`,startLevel:2,...typeof e.toc==`object`?e.toc:{}},n={...d,clobber:(d.clobber??[]).filter(e=>e!==`id`)},r=e.sanitizeSchema?e.sanitizeSchema(n):n,i=g().use(m).use(e.remarkPlugins??[]).use(e.toc?[[p,t]]:[]).use(h).use(e.rehypePlugins??[]).use(u,r).use(e.highlight?[l]:[]).use(f).freeze();function a(e,t){return _(`div`,{className:t,dangerouslySetInnerHTML:{__html:e}})}function o(e,t){let n=i.processSync(e),r=n.data.toc??[];return{body:a(String(n),t?.className),toc:r}}function s({source:e,className:t}){return o(e,{className:t}).body}return{Markdown:s,render:o}}export{v as createIsland,y as createMarkdown,o as css,i as expandRoutes,r as genCssFn,t as getCssRegistry,e as initCssRegistry,a as route,n as urlToFilePath};
1
+ import{a as e,i as t,l as n,n as r,o as i,s as a,t as o}from"./css-DDEJecy6.js";export{o as css,i as expandRoutes,r as genCssFn,t as getCssRegistry,e as initCssRegistry,a as route,n as urlToFilePath};
@@ -0,0 +1,50 @@
1
+ import { ComponentProps, ComponentType, ReactElement } from "react";
2
+ import { ToC, ToC as ToC$1 } from "remark-export-toc";
3
+ import { PluggableList } from "unified";
4
+ import { Schema } from "hast-util-sanitize";
5
+
6
+ //#region src/island.d.ts
7
+ type IslandRegistry = Record<string, ComponentType<any>>;
8
+ declare function createIsland<R extends IslandRegistry>(islands: R): <K extends keyof R & string>({
9
+ name,
10
+ props
11
+ }: {
12
+ name: K;
13
+ props: ComponentProps<R[K]>;
14
+ }) => import("react").DetailedReactHTMLElement<{
15
+ "data-island": K;
16
+ "data-props": string;
17
+ dangerouslySetInnerHTML: {
18
+ __html: string;
19
+ };
20
+ }, HTMLElement>;
21
+ //#endregion
22
+ //#region src/markdown.d.ts
23
+ interface MarkdownConfig {
24
+ remarkPlugins?: PluggableList;
25
+ rehypePlugins?: PluggableList;
26
+ sanitizeSchema?: (defaults: Schema) => Schema;
27
+ toc?: boolean | {
28
+ prefix?: string;
29
+ startLevel?: number;
30
+ };
31
+ highlight?: boolean;
32
+ }
33
+ interface RenderResult {
34
+ body: ReactElement;
35
+ toc: ToC$1[];
36
+ }
37
+ declare function createMarkdown(config?: MarkdownConfig): {
38
+ Markdown: ({
39
+ source,
40
+ className
41
+ }: {
42
+ source: string;
43
+ className?: string;
44
+ }) => ReactElement;
45
+ render: (source: string, options?: {
46
+ className?: string;
47
+ }) => RenderResult;
48
+ };
49
+ //#endregion
50
+ export { type MarkdownConfig, type RenderResult, type ToC, createIsland, createMarkdown };
package/dist/server.js ADDED
@@ -0,0 +1 @@
1
+ import{createElement as e}from"react";import{renderToString as t}from"react-dom/server";import n from"rehype-prism";import r,{defaultSchema as i}from"rehype-sanitize";import a from"rehype-stringify";import o from"remark-export-toc";import s from"remark-parse";import c from"remark-rehype";import{unified as l}from"unified";import{jsx as u}from"react/jsx-runtime";function d(n){return function({name:r,props:i}){let a=t(e(n[r],i));return e(`div`,{"data-island":r,"data-props":JSON.stringify(i),dangerouslySetInnerHTML:{__html:a}})}}function f(e={}){let t={prefix:`heading`,startLevel:2,...typeof e.toc==`object`?e.toc:{}},d={...i,clobber:(i.clobber??[]).filter(e=>e!==`id`)},f=e.sanitizeSchema?e.sanitizeSchema(d):d,p=l().use(s).use(e.remarkPlugins??[]).use(e.toc?[[o,t]]:[]).use(c).use(e.rehypePlugins??[]).use(r,f).use(e.highlight?[n]:[]).use(a).freeze();function m(e,t){return u(`div`,{className:t,dangerouslySetInnerHTML:{__html:e}})}function h(e,t){let n=p.processSync(e),r=n.data.toc??[];return{body:m(String(n),t?.className),toc:r}}function g({source:e,className:t}){return h(e,{className:t}).body}return{Markdown:g,render:h}}export{d as createIsland,f as createMarkdown};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cirrojs",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "React islands SSG with strict CSP (no unsafe-inline). Vite-based, MPA-first.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -19,6 +19,10 @@
19
19
  "types": "./dist/index.d.ts",
20
20
  "default": "./dist/index.js"
21
21
  },
22
+ "./server": {
23
+ "types": "./dist/server.d.ts",
24
+ "default": "./dist/server.js"
25
+ },
22
26
  "./vite": {
23
27
  "types": "./dist/vite.d.ts",
24
28
  "default": "./dist/vite.js"
@@ -1,4 +0,0 @@
1
- import{resolve as e}from"node:path";function t(e){return e}function n(t){let n=[];for(let r of t)if(`getStaticPaths`in r){for(let e of r.getStaticPaths())n.push({url:r.path(e),isCss:!1,cssPath:r.cssPath,render:()=>r.component({params:e})});n.push({url:r.cssPath,isCss:!0,cssPath:r.cssPath,render:()=>r.component({params:r.getStaticPaths()[0]})})}else n.push({url:r.path,isCss:!1,cssPath:e(r.path,`index.css`),render:()=>r.component({params:{}})}),n.push({url:e(r.path,`index.css`),isCss:!0,cssPath:e(r.path,`index.css`),render:()=>r.component({params:{}})});return n}function r(e){return e===`/`?`index.html`:`${e.replace(/^\/+|\/+$/g,``)}/index.html`}function i(e){return e===`/`?`index.css`:`${e.replace(/^\/+|\/+$/g,``)}`}let a=[];function o(e,t){a.push([e,t])}function s(){a=[]}function c(){return a}function l(e,t){let n=t?.selector??`&`,r=t?.atrules??[],i=p(e),a=`${t?.name??`cirro`}-${i.toString(16)}`;return f([...r,n],e,a),a}function u(e,t=`main`){return(n,r)=>l(n,{atrules:[`@layer ${t}`,`@media (${e})`],name:r?.name,selector:r?.selector})}function d(e){let t=`@charset "utf-8";
2
- @layer base, font, low, main, high;
3
- `;for(let[n,r]of e)t+=n.reduceRight((e,t)=>`${t} { ${e} }`,Object.entries(r).map(([e,t])=>`${e.replaceAll(`_`,`-`)}: ${t};`).join(` `)),t+=`
4
- `;return t}function f(e,t,n){o(e.map(e=>e.replaceAll(`&`,`.${n}`)),t)}function p(...e){return m(e.map(e=>JSON.stringify(e)).join(``))}function m(e){let t=5381;for(let n of[...e])t=(t<<5)+t+n.charCodeAt(0)&4294967295;return t>>>0}export{s as a,i as c,c as i,r as l,u as n,n as o,d as r,t as s,l as t};