@riebeckite/honox 0.0.1

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.
@@ -0,0 +1,3 @@
1
+ export type { ResolvedContentRoute } from "./src/content_route.js";
2
+ export { contentRouteSsgParams, resolveContentRoute, ssgEnumerableHandler, } from "./src/content_route.js";
3
+ export { mountRiebeckiteEndpoints } from "./src/endpoints.js";
package/dist/server.js ADDED
@@ -0,0 +1,131 @@
1
+ // src/content_route.ts
2
+ function resolveContentRoute(manifest, pathname) {
3
+ const path = normalizeRequestPath(pathname);
4
+ const entry = manifest.byPermalink.get(path);
5
+ if (entry) return { kind: "content", entry };
6
+ const redirect = manifest.redirects.get(path);
7
+ if (!redirect) return null;
8
+ const target = manifest.bySlug.get(redirect.slug);
9
+ if (!target) return null;
10
+ return {
11
+ kind: "redirect",
12
+ location: target.permalink,
13
+ status: redirect.status
14
+ };
15
+ }
16
+ function contentRouteSsgParams(routePath, params) {
17
+ return async (c, next) => {
18
+ if (c.req.path !== routePath || !isDynamicRoute(routePath)) {
19
+ await next();
20
+ return;
21
+ }
22
+ c.req.raw.ssgParams = typeof params === "function" ? await params(c) : params;
23
+ return c.notFound();
24
+ };
25
+ }
26
+ function ssgEnumerableHandler(handler) {
27
+ const enumerable = (...args) => Reflect.apply(handler, void 0, args);
28
+ return enumerable;
29
+ }
30
+ function isDynamicRoute(path) {
31
+ return path.split("/").some((segment) => segment.startsWith(":") || segment.includes("*"));
32
+ }
33
+ function normalizeRequestPath(pathname) {
34
+ const trailingSlash = pathname.length > 1 && pathname.endsWith("/");
35
+ const segments = pathname.split("/").filter(Boolean).map(decodeSegment);
36
+ const path = `/${segments.join("/")}`;
37
+ return trailingSlash ? `${path}/` : path;
38
+ }
39
+ function decodeSegment(segment) {
40
+ try {
41
+ return decodeURIComponent(segment);
42
+ } catch {
43
+ return segment;
44
+ }
45
+ }
46
+
47
+ // src/endpoints.ts
48
+ function mountRiebeckiteEndpoints(app, options) {
49
+ const endpoints = collectPluginEndpoints(options.config);
50
+ for (const endpoint of endpoints) {
51
+ app.get(endpoint.path, async (context) => {
52
+ const manifest = await options.content.getManifest();
53
+ const response = await endpoint.handler({
54
+ config: options.config,
55
+ manifest
56
+ });
57
+ return toHonoResponse(context, response);
58
+ });
59
+ }
60
+ }
61
+ function collectPluginEndpoints(config) {
62
+ const endpoints = config.plugins.flatMap(
63
+ (plugin) => (plugin.endpoints ?? []).map((endpoint) => ({
64
+ endpoint,
65
+ pluginName: plugin.name
66
+ }))
67
+ );
68
+ const registeredKeys = /* @__PURE__ */ new Map();
69
+ for (const { endpoint, pluginName } of endpoints) {
70
+ validateEndpointPath(endpoint.path);
71
+ const method = endpoint.method ?? "GET";
72
+ const key = `${method} ${endpoint.path}`;
73
+ const owner = registeredKeys.get(key);
74
+ if (owner) {
75
+ throw new Error(
76
+ `Duplicate Riebeckite plugin endpoint detected: ${key} is declared by both "${owner}" and "${pluginName}".`
77
+ );
78
+ }
79
+ registeredKeys.set(key, pluginName);
80
+ }
81
+ return endpoints.map(({ endpoint }) => endpoint);
82
+ }
83
+ function validateEndpointPath(path) {
84
+ if (!path.startsWith("/")) {
85
+ throw new Error(
86
+ `Invalid Riebeckite plugin endpoint path: "${path}" must start with "/".`
87
+ );
88
+ }
89
+ if (path.length === 1 || path.includes("?") || path.includes("#")) {
90
+ throw new Error(
91
+ `Invalid Riebeckite plugin endpoint path: "${path}" must be a static path without query or hash.`
92
+ );
93
+ }
94
+ if (/\s/.test(path) || path.includes("//") || path.includes(":")) {
95
+ throw new Error(
96
+ `Invalid Riebeckite plugin endpoint path: "${path}" contains unsupported dynamic or malformed segments.`
97
+ );
98
+ }
99
+ if (path === "/assets" || path.startsWith("/assets/")) {
100
+ throw new Error(
101
+ `Invalid Riebeckite plugin endpoint path: "${path}" conflicts with the static assets namespace.`
102
+ );
103
+ }
104
+ }
105
+ function toHonoResponse(context, response) {
106
+ const status = response.status ?? 200;
107
+ if ("json" in response) {
108
+ return context.json(response.json, status, response.headers);
109
+ }
110
+ if (response.body === void 0) {
111
+ return context.body("", status, response.headers);
112
+ }
113
+ const contentType = findHeader(response.headers, "content-type");
114
+ if (contentType?.startsWith("text/")) {
115
+ return context.text(response.body, status, response.headers);
116
+ }
117
+ return context.body(response.body, status, response.headers);
118
+ }
119
+ function findHeader(headers, name) {
120
+ if (!headers) return void 0;
121
+ const key = Object.keys(headers).find(
122
+ (header) => header.toLowerCase() === name.toLowerCase()
123
+ );
124
+ return key ? headers[key] : void 0;
125
+ }
126
+ export {
127
+ contentRouteSsgParams,
128
+ mountRiebeckiteEndpoints,
129
+ resolveContentRoute,
130
+ ssgEnumerableHandler
131
+ };
@@ -0,0 +1,6 @@
1
+ import { type ResolvedRiebeckiteConfig } from "@riebeckite/core";
2
+ export type GeneratedAssetPaths = {
3
+ pluginStyles: string;
4
+ themeStyles: string;
5
+ };
6
+ export declare function writeRiebeckiteAssetEntries(config: ResolvedRiebeckiteConfig, paths: GeneratedAssetPaths): void;
@@ -0,0 +1,3 @@
1
+ import type { ResolvedRiebeckiteConfig } from "@riebeckite/core";
2
+ import type { Plugin } from "vite";
3
+ export declare function riebeckiteClientModule(getConfig: () => ResolvedRiebeckiteConfig): Plugin;
@@ -0,0 +1,8 @@
1
+ import type { ResolvedRiebeckiteConfig } from "@riebeckite/core";
2
+ export type RiebeckiteConfigLoaderOptions = {
3
+ configRoot: string;
4
+ configFile?: string;
5
+ workspaceRoot?: string;
6
+ };
7
+ export declare function loadRiebeckiteConfig(options: RiebeckiteConfigLoaderOptions): Promise<ResolvedRiebeckiteConfig>;
8
+ export declare function resolveHonoxConfig(config: ResolvedRiebeckiteConfig, appRoot: string): ResolvedRiebeckiteConfig;
@@ -0,0 +1,33 @@
1
+ import type { ContentManifest, ContentManifestEntry } from "@riebeckite/core";
2
+ import type { Context, Handler, MiddlewareHandler } from "hono";
3
+ export type ResolvedContentRoute = {
4
+ kind: "content";
5
+ entry: ContentManifestEntry;
6
+ } | {
7
+ kind: "redirect";
8
+ location: string;
9
+ status: 301 | 302 | 307 | 308;
10
+ } | null;
11
+ export declare function resolveContentRoute(manifest: ContentManifest, pathname: string): ResolvedContentRoute;
12
+ type SsgParams = Record<string, string>[];
13
+ /**
14
+ * SSG parameter middleware for a catch-all content route.
15
+ *
16
+ * `ssgParams` from `hono/ssg` decides whether to emit params only from the
17
+ * request path. When a shallow catch-all (for example `/:slug{.+}`) is
18
+ * registered before a deeper one (`/tags/:slug{.+}`), the shallow route
19
+ * captures the enumeration request of the deeper route and injects its own
20
+ * params. This helper responds only to the enumeration request that belongs to
21
+ * `routePath`, so sibling catch-all routes can enumerate their own params.
22
+ */
23
+ export declare function contentRouteSsgParams(routePath: string, params: SsgParams | ((c: Context) => SsgParams | Promise<SsgParams>)): MiddlewareHandler;
24
+ /**
25
+ * Make a route handler visible to Hono's SSG route enumeration.
26
+ *
27
+ * `toSSG` skips any route whose final handler is a middleware, which Hono
28
+ * detects with `handler.length > 1`. A catch-all content route sometimes needs
29
+ * `next()` to defer to a more specific route, so wrapping the handler in a
30
+ * rest-parameter function keeps `length === 0` while preserving `(c, next)`.
31
+ */
32
+ export declare function ssgEnumerableHandler<H extends Handler<any, any, any>>(handler: H): H;
33
+ export {};
@@ -0,0 +1,15 @@
1
+ import type { ContentManager, ResolvedRiebeckiteConfig } from "@riebeckite/core";
2
+ export type RiebeckiteEndpointMountOptions = {
3
+ config: ResolvedRiebeckiteConfig;
4
+ content: ContentManager;
5
+ };
6
+ type HonoLikeApp = {
7
+ get(path: string, handler: (context: HonoLikeContext) => Promise<unknown>): void;
8
+ };
9
+ type HonoLikeContext = {
10
+ json(body: unknown, status?: number, headers?: Record<string, string>): unknown;
11
+ body(body: string, status?: number, headers?: Record<string, string>): unknown;
12
+ text(body: string, status?: number, headers?: Record<string, string>): unknown;
13
+ };
14
+ export declare function mountRiebeckiteEndpoints(app: HonoLikeApp, options: RiebeckiteEndpointMountOptions): void;
15
+ export {};
@@ -0,0 +1,17 @@
1
+ export type ScaffoldSiteOptions = {
2
+ readonly targetDirectory: string;
3
+ readonly name?: string;
4
+ readonly siteTitle?: string;
5
+ readonly description?: string;
6
+ readonly baseUrl?: string;
7
+ readonly locale?: string;
8
+ readonly overwrite?: boolean;
9
+ };
10
+ export type ScaffoldSiteResult = {
11
+ readonly targetDirectory: string;
12
+ readonly files: readonly string[];
13
+ };
14
+ export declare class ScaffoldSiteError extends Error {
15
+ constructor(message: string);
16
+ }
17
+ export declare function scaffoldRiebeckiteSite(options: ScaffoldSiteOptions): Promise<ScaffoldSiteResult>;
@@ -0,0 +1,12 @@
1
+ export type SiteTemplateVariables = {
2
+ readonly name: string;
3
+ readonly title: string;
4
+ readonly description: string;
5
+ readonly baseUrl: string;
6
+ readonly locale: string;
7
+ };
8
+ export type SiteTemplateFile = {
9
+ readonly path: string;
10
+ readonly content: string;
11
+ };
12
+ export declare function siteTemplateFiles(variables: SiteTemplateVariables): readonly SiteTemplateFile[];
@@ -0,0 +1,14 @@
1
+ import type { Plugin } from "vite";
2
+ import { type RiebeckiteSsgOptions } from "./ssg_plugin.js";
3
+ /**
4
+ * Root-relative SSG entry for a Riebeckite site. HonoX keeps the server entry
5
+ * at `app/server.ts`, so sites do not need to compute an absolute path.
6
+ */
7
+ export declare const defaultSsgEntry = "./app/server.ts";
8
+ export declare function riebeckiteSsgExtensionMap(): Record<string, string>;
9
+ /**
10
+ * Higher-level SSG factory that hides Riebeckite's internal entry and
11
+ * extension-map defaults. Use `riebeckiteSsg` directly when full control is
12
+ * required; this wrapper only fills in the values a normal site never sets.
13
+ */
14
+ export declare function createRiebeckiteSsg(options?: RiebeckiteSsgOptions): Plugin;
@@ -0,0 +1,10 @@
1
+ import { toSSG } from "hono/ssg";
2
+ import { type Plugin } from "vite";
3
+ type ToSsgOptions = NonNullable<Parameters<typeof toSSG>[2]>;
4
+ export type RiebeckiteSsgOptions = {
5
+ entry?: string;
6
+ plugins?: ToSsgOptions["plugins"];
7
+ extensionMap?: Record<string, string>;
8
+ };
9
+ export declare function riebeckiteSsg(options?: RiebeckiteSsgOptions): Plugin;
10
+ export {};
@@ -0,0 +1,48 @@
1
+ export type PrimitiveChildren = unknown;
2
+ export type PrimitiveProps = {
3
+ children?: PrimitiveChildren;
4
+ class?: string;
5
+ className?: string;
6
+ };
7
+ export type PrimitiveClassProps = {
8
+ class?: string;
9
+ className?: string;
10
+ };
11
+ export type ArticleProps = PrimitiveProps & {
12
+ "data-slot"?: string;
13
+ };
14
+ export type ArticleLayoutProps = PrimitiveProps & {
15
+ aside?: PrimitiveChildren;
16
+ };
17
+ export type ArticleHeaderProps = (PrimitiveClassProps & {
18
+ dangerouslySetInnerHTML: {
19
+ __html: string;
20
+ };
21
+ children?: never;
22
+ }) | (PrimitiveClassProps & {
23
+ dangerouslySetInnerHTML?: never;
24
+ children?: PrimitiveChildren;
25
+ });
26
+ export type ArticleContentProps = (PrimitiveClassProps & {
27
+ html: string;
28
+ children?: never;
29
+ "data-slot"?: string;
30
+ }) | (PrimitiveClassProps & {
31
+ html?: never;
32
+ children?: PrimitiveChildren;
33
+ "data-slot"?: string;
34
+ });
35
+ export type ArticleMetaProps = PrimitiveProps & {
36
+ label?: string;
37
+ };
38
+ export type SidebarProps = PrimitiveProps & {
39
+ label?: string;
40
+ };
41
+ export type ArticleFooterProps = PrimitiveProps;
42
+ export declare function Article(props: ArticleProps): import("hono/jsx/jsx-dev-runtime").JSX.Element;
43
+ export declare function ArticleLayout(props: ArticleLayoutProps): import("hono/jsx/jsx-dev-runtime").JSX.Element;
44
+ export declare function ArticleHeader(props: ArticleHeaderProps): import("hono/jsx/jsx-dev-runtime").JSX.Element;
45
+ export declare function ArticleMeta(props: ArticleMetaProps): import("hono/jsx/jsx-dev-runtime").JSX.Element;
46
+ export declare function ArticleContent(props: ArticleContentProps): import("hono/jsx/jsx-dev-runtime").JSX.Element;
47
+ export declare function ArticleFooter(props: ArticleFooterProps): import("hono/jsx/jsx-dev-runtime").JSX.Element;
48
+ export declare function Sidebar(props: SidebarProps): import("hono/jsx/jsx-dev-runtime").JSX.Element;
@@ -0,0 +1,113 @@
1
+ // src/ui/primitives.tsx
2
+ import { jsx, jsxs } from "hono/jsx/jsx-runtime";
3
+ function Article(props) {
4
+ return /* @__PURE__ */ jsx(
5
+ "article",
6
+ {
7
+ class: joinClassNames(
8
+ "article-shell rb-article",
9
+ props.class,
10
+ props.className
11
+ ),
12
+ "data-slot": props["data-slot"] ?? "article",
13
+ children: props.children
14
+ }
15
+ );
16
+ }
17
+ function ArticleLayout(props) {
18
+ return /* @__PURE__ */ jsxs(
19
+ "div",
20
+ {
21
+ class: joinClassNames(
22
+ "article-shell__layout rb-article-layout",
23
+ props.class,
24
+ props.className
25
+ ),
26
+ children: [
27
+ props.children,
28
+ props.aside
29
+ ]
30
+ }
31
+ );
32
+ }
33
+ function ArticleHeader(props) {
34
+ const className = joinClassNames(
35
+ "article-shell__lead rb-article-header",
36
+ props.class,
37
+ props.className
38
+ );
39
+ if (props.dangerouslySetInnerHTML !== void 0) {
40
+ return /* @__PURE__ */ jsx(
41
+ "header",
42
+ {
43
+ class: className,
44
+ dangerouslySetInnerHTML: props.dangerouslySetInnerHTML
45
+ }
46
+ );
47
+ }
48
+ return /* @__PURE__ */ jsx("header", { class: className, children: props.children });
49
+ }
50
+ function ArticleMeta(props) {
51
+ return /* @__PURE__ */ jsx(
52
+ "aside",
53
+ {
54
+ class: joinClassNames(
55
+ "article-frontmatter rb-article-meta",
56
+ props.class,
57
+ props.className
58
+ ),
59
+ "aria-label": props.label ?? "Article metadata",
60
+ children: props.children
61
+ }
62
+ );
63
+ }
64
+ function ArticleContent(props) {
65
+ const className = joinClassNames(
66
+ "article-shell__body rb-article-body",
67
+ props.class,
68
+ props.className
69
+ );
70
+ const dataSlot = props["data-slot"] ?? "article-body";
71
+ if (props.html !== void 0) {
72
+ return /* @__PURE__ */ jsx(
73
+ "div",
74
+ {
75
+ class: className,
76
+ "data-slot": dataSlot,
77
+ dangerouslySetInnerHTML: { __html: props.html }
78
+ }
79
+ );
80
+ }
81
+ return /* @__PURE__ */ jsx("div", { class: className, "data-slot": dataSlot, children: props.children });
82
+ }
83
+ function ArticleFooter(props) {
84
+ return /* @__PURE__ */ jsx(
85
+ "footer",
86
+ {
87
+ class: joinClassNames("rb-article-footer", props.class, props.className),
88
+ children: props.children
89
+ }
90
+ );
91
+ }
92
+ function Sidebar(props) {
93
+ return /* @__PURE__ */ jsx(
94
+ "aside",
95
+ {
96
+ class: joinClassNames("rb-sidebar", props.class, props.className),
97
+ "aria-label": props.label,
98
+ children: props.children
99
+ }
100
+ );
101
+ }
102
+ function joinClassNames(...classNames) {
103
+ return classNames.filter(Boolean).join(" ");
104
+ }
105
+ export {
106
+ Article,
107
+ ArticleContent,
108
+ ArticleFooter,
109
+ ArticleHeader,
110
+ ArticleLayout,
111
+ ArticleMeta,
112
+ Sidebar
113
+ };
@@ -0,0 +1,31 @@
1
+ import type { Plugin } from "vite";
2
+ import type { RiebeckiteSsgOptions } from "./ssg_plugin.js";
3
+ export type RiebeckiteIntegrationOptions = {
4
+ configRoot?: string;
5
+ workspaceRoot?: string;
6
+ appRoot?: string;
7
+ configFile?: string;
8
+ };
9
+ /**
10
+ * SSR externals Riebeckite's own runtime requires the application to leave
11
+ * external. These are internal to the integration: sites should not have to
12
+ * restate the Vite `environments.ssr.resolve.external` list.
13
+ */
14
+ export declare const defaultSsrExternals: readonly ["extend", "debug", "node:fs/promises", "node:path", "parse-numeric-range", "slugify", "vfile-matter"];
15
+ export type RiebeckiteViteOptions = RiebeckiteIntegrationOptions & {
16
+ /** Extra SSR externals appended after Riebeckite's defaults. */
17
+ ssrExternals?: readonly string[];
18
+ /** SSG overrides. A normal site does not need them. */
19
+ ssg?: RiebeckiteSsgOptions;
20
+ };
21
+ export declare function riebeckite(options?: RiebeckiteIntegrationOptions): Plugin[];
22
+ /**
23
+ * Higher-level helper that registers the complete Riebeckite Vite integration
24
+ * without exposing internal Vite/HonoX/SSR details. A site only needs to add
25
+ * its own plugins (for example the HonoX plugin and its deployment build
26
+ * plugin) around this call.
27
+ *
28
+ * `riebeckite`, `riebeckiteSsg`, and `riebeckiteSsgExtensionMap` remain
29
+ * available for callers that need the lower-level pieces.
30
+ */
31
+ export declare function riebeckiteVite(options?: RiebeckiteViteOptions): Plugin[];
@@ -0,0 +1,22 @@
1
+ import type { ResolvedRiebeckiteConfig, Tracer } from "@riebeckite/core";
2
+ import { type RiebeckiteConfigLoaderOptions } from "./config_loader.js";
3
+ export type HonoxApplicationOptions = {
4
+ root: string;
5
+ tracer?: Tracer;
6
+ };
7
+ export type ResolvedHonoxApplication = {
8
+ config: ResolvedRiebeckiteConfig;
9
+ configRoot: string;
10
+ appRoot: string;
11
+ contentRoot: string;
12
+ };
13
+ export type ResolveHonoxApplicationOptions = RiebeckiteConfigLoaderOptions & {
14
+ appRoot?: string;
15
+ };
16
+ export declare function resolveHonoxApplicationRoot(configRoot: string): Promise<string>;
17
+ export declare class HonoxApplicationRootError extends Error {
18
+ constructor(message: string);
19
+ }
20
+ export declare function resolveHonoxApplication(options: ResolveHonoxApplicationOptions): Promise<ResolvedHonoxApplication>;
21
+ export declare function startHonoxDevServer(options: HonoxApplicationOptions): Promise<void>;
22
+ export declare function buildHonoxApplication(options: HonoxApplicationOptions): Promise<void>;
@@ -0,0 +1,16 @@
1
+ export declare function createWorkspacePackageAliases(workspaceRoot: string): {
2
+ find: RegExp;
3
+ replacement: string;
4
+ }[];
5
+ export declare function workspacePackageResolver(workspaceRoot: string): {
6
+ name: string;
7
+ setup(buildApi: {
8
+ onResolve: (options: {
9
+ filter: RegExp;
10
+ }, callback: (args: {
11
+ path: string;
12
+ }) => {
13
+ path: string;
14
+ } | null) => void;
15
+ }): void;
16
+ };
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@riebeckite/honox",
3
+ "version": "0.0.1",
4
+ "license": "Apache-2.0",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "source": "./index.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "./server": {
16
+ "types": "./dist/server.d.ts",
17
+ "import": "./dist/server.js",
18
+ "source": "./server.ts",
19
+ "default": "./dist/server.js"
20
+ },
21
+ "./ui": {
22
+ "types": "./dist/src/ui/primitives.d.ts",
23
+ "import": "./dist/src/ui/primitives.js",
24
+ "source": "./src/ui/primitives.tsx",
25
+ "default": "./dist/src/ui/primitives.js"
26
+ }
27
+ },
28
+ "dependencies": {
29
+ "esbuild": "^0.28.2",
30
+ "hono": "^4.12.25",
31
+ "vite": "^8.0.9",
32
+ "@riebeckite/core": "0.0.1"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "files": [
38
+ "LICENSE",
39
+ "README.md",
40
+ "README_ja.md",
41
+ "dist"
42
+ ],
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "https://github.com/Rerurate514/riebeckite.git",
46
+ "directory": "packages/integrations/honox"
47
+ },
48
+ "homepage": "https://github.com/Rerurate514/riebeckite#readme",
49
+ "bugs": {
50
+ "url": "https://github.com/Rerurate514/riebeckite/issues"
51
+ },
52
+ "description": "HonoX and Vite integration for building Riebeckite sites.",
53
+ "keywords": [
54
+ "riebeckite",
55
+ "honox",
56
+ "vite",
57
+ "static-site-generator"
58
+ ],
59
+ "engines": {
60
+ "node": "^20.19.0 || >=22.12.0"
61
+ },
62
+ "sideEffects": false,
63
+ "scripts": {
64
+ "build": "node ../../../scripts/build_package.mjs"
65
+ }
66
+ }