@blinkk/root 3.0.1 → 3.0.3
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/{chunk-FQBA5QSG.js → chunk-3Z5TNZEP.js} +3 -3
- package/dist/chunk-3Z5TNZEP.js.map +7 -0
- package/dist/{chunk-JCRXBB26.js → chunk-6NBKAR5Y.js} +2 -2
- package/dist/chunk-6NBKAR5Y.js.map +7 -0
- package/dist/chunk-6P3B7ZXL.js +1 -1
- package/dist/chunk-6P3B7ZXL.js.map +7 -1
- package/dist/{chunk-PVBPP5LN.js → chunk-7PSEEE6C.js} +10 -10
- package/dist/chunk-7PSEEE6C.js.map +7 -0
- package/dist/{chunk-M6WGW5VY.js → chunk-DU7JUEDY.js} +48 -6
- package/dist/chunk-DU7JUEDY.js.map +7 -0
- package/dist/{chunk-GSR74KEI.js → chunk-JTZWI4MH.js} +279 -73
- package/dist/chunk-JTZWI4MH.js.map +7 -0
- package/dist/{chunk-WAZTR3DX.js → chunk-KW7KTYGC.js} +2 -2
- package/dist/chunk-KW7KTYGC.js.map +7 -0
- package/dist/chunk-XSNCF7WU.js +1 -1
- package/dist/chunk-XSNCF7WU.js.map +7 -1
- package/dist/cli/build.d.ts +7 -0
- package/dist/cli/cli.d.ts +12 -0
- package/dist/cli/codegen.d.ts +5 -0
- package/dist/cli/create-package.d.ts +14 -0
- package/dist/cli/dev.d.ts +10 -0
- package/dist/cli/gae-deploy.d.ts +18 -0
- package/dist/cli/preview.d.ts +8 -0
- package/dist/cli/start.d.ts +8 -0
- package/dist/cli/startup/check-version.d.ts +17 -0
- package/dist/cli/startup/startup-tasks.d.ts +39 -0
- package/dist/cli.js +4 -4
- package/dist/cli.js.map +7 -1
- package/dist/core/components/Body.d.ts +23 -0
- package/dist/core/components/Head.d.ts +18 -0
- package/dist/core/components/Html.d.ts +24 -0
- package/dist/core/components/Script.d.ts +16 -0
- package/dist/core/config.d.ts +285 -0
- package/dist/core/core.d.ts +14 -0
- package/dist/core/hooks/useI18nContext.d.ts +11 -0
- package/dist/core/hooks/useRequestContext.d.ts +36 -0
- package/dist/core/hooks/useStringParams.d.ts +34 -0
- package/dist/core/hooks/useTranslations.d.ts +20 -0
- package/dist/core/hooks/useTranslationsMiddleware.d.ts +25 -0
- package/dist/core/pages/DevErrorPage.d.ts +9 -0
- package/dist/core/pages/DevNotFoundPage.d.ts +10 -0
- package/dist/core/pages/ErrorPage.d.ts +9 -0
- package/dist/core/plugin.d.ts +80 -0
- package/dist/core/pod.d.ts +54 -0
- package/dist/core/types.d.ts +228 -0
- package/dist/core.js +3 -3
- package/dist/core.js.map +7 -1
- package/dist/functions/functions.d.ts +1 -0
- package/dist/functions/server.d.ts +10 -0
- package/dist/functions.js +5 -5
- package/dist/functions.js.map +7 -1
- package/dist/jsx/jsx-dev-runtime.d.ts +10 -1
- package/dist/jsx/jsx-dev-runtime.js +2 -2
- package/dist/jsx/jsx-dev-runtime.js.map +7 -1
- package/dist/{jsx-C8BaDh-4.d.ts → jsx/jsx-render.d.ts} +3 -6
- package/dist/jsx/jsx-runtime.d.ts +120 -1
- package/dist/jsx/jsx-runtime.js +2 -2
- package/dist/jsx/jsx-runtime.js.map +7 -1
- package/dist/jsx/jsx.d.ts +37 -0
- package/dist/{jsx-dev-runtime-DUJrvx5P.d.ts → jsx/types.d.ts} +9 -125
- package/dist/jsx.js +3 -3
- package/dist/jsx.js.map +7 -1
- package/dist/middleware/common.d.ts +22 -0
- package/dist/middleware/hooks.d.ts +8 -0
- package/dist/middleware/middleware.d.ts +3 -0
- package/dist/middleware/multipart.d.ts +11 -0
- package/dist/middleware/redirects.d.ts +10 -0
- package/dist/middleware/session.d.ts +24 -0
- package/dist/middleware.js +2 -2
- package/dist/middleware.js.map +7 -1
- package/dist/node/element-graph.d.ts +51 -0
- package/dist/node/load-config.d.ts +17 -0
- package/dist/node/monorepo.d.ts +14 -0
- package/dist/node/node.d.ts +4 -0
- package/dist/node/pod-collector.d.ts +33 -0
- package/dist/node/pods-vite-plugin.d.ts +6 -0
- package/dist/node/vite-plugin-preact-alias.d.ts +10 -0
- package/dist/node/vite-plugin-prune-empty-chunks.d.ts +27 -0
- package/dist/node/vite-plugin-root-jsx-virtual.d.ts +16 -0
- package/dist/node/vite.d.ts +18 -0
- package/dist/node.js +2 -2
- package/dist/node.js.map +7 -1
- package/dist/render/accept-language.d.ts +8 -0
- package/dist/render/asset-map/asset-map.d.ts +25 -0
- package/dist/render/asset-map/build-asset-map.d.ts +47 -0
- package/dist/render/asset-map/dev-asset-map.d.ts +26 -0
- package/dist/render/countrie-language.d.ts +13 -0
- package/dist/render/html-minify.d.ts +3 -0
- package/dist/render/html-pretty.d.ts +3 -0
- package/dist/render/i18n-fallbacks.d.ts +11 -0
- package/dist/render/render.d.ts +91 -0
- package/dist/render/route-trie.d.ts +44 -0
- package/dist/render/router.d.ts +18 -0
- package/dist/render.js +9 -9
- package/dist/render.js.map +7 -1
- package/dist/utils/batch.d.ts +1 -0
- package/dist/utils/elements.d.ts +12 -0
- package/dist/utils/fsutils.d.ts +24 -0
- package/dist/utils/i18n.d.ts +8 -0
- package/dist/utils/ports.d.ts +8 -0
- package/dist/utils/rand.d.ts +10 -0
- package/dist/utils/url-path-params.d.ts +2 -0
- package/package.json +14 -15
- package/dist/chunk-FQBA5QSG.js.map +0 -1
- package/dist/chunk-GSR74KEI.js.map +0 -1
- package/dist/chunk-JCRXBB26.js.map +0 -1
- package/dist/chunk-M6WGW5VY.js.map +0 -1
- package/dist/chunk-PVBPP5LN.js.map +0 -1
- package/dist/chunk-WAZTR3DX.js.map +0 -1
- package/dist/cli.d.ts +0 -60
- package/dist/core.d.ts +0 -214
- package/dist/functions.d.ts +0 -14
- package/dist/jsx.d.ts +0 -2
- package/dist/middleware.d.ts +0 -43
- package/dist/node.d.ts +0 -91
- package/dist/render.d.ts +0 -8
- package/dist/types-Cksf99CK.d.ts +0 -827
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { PluginOption as VitePlugin } from 'vite';
|
|
2
|
+
import { RootConfig } from './config.js';
|
|
3
|
+
import { Pod, PodFactory } from './pod.js';
|
|
4
|
+
import { NextFunction, Request, Response, Server } from './types.js';
|
|
5
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
6
|
+
type PreBuildHook = (rootConfig: RootConfig) => MaybePromise<void>;
|
|
7
|
+
export interface PostBuildOptions {
|
|
8
|
+
/** Whether the build was SSR-only (no SSG pre-rendering). */
|
|
9
|
+
ssrOnly?: boolean;
|
|
10
|
+
}
|
|
11
|
+
type PostBuildHook = (rootConfig: RootConfig, options?: PostBuildOptions) => MaybePromise<void>;
|
|
12
|
+
export type ConfigureServerHook = (server: Server, options: ConfigureServerOptions) => MaybePromise<void> | MaybePromise<() => void>;
|
|
13
|
+
export interface ConfigureServerOptions {
|
|
14
|
+
type: 'dev' | 'preview' | 'prod';
|
|
15
|
+
rootConfig: RootConfig;
|
|
16
|
+
}
|
|
17
|
+
export interface PluginHooks {
|
|
18
|
+
/**
|
|
19
|
+
* Hook that runs before the build starts.
|
|
20
|
+
*/
|
|
21
|
+
preBuild?: PreBuildHook;
|
|
22
|
+
/**
|
|
23
|
+
* Hook that runs after the build completes.
|
|
24
|
+
*/
|
|
25
|
+
postBuild?: PostBuildHook;
|
|
26
|
+
/**
|
|
27
|
+
* Post-render hook that's called before the HTML is rendered to the response
|
|
28
|
+
* object. If a string is returned from this hook, it will replace the
|
|
29
|
+
* rendered HTML.
|
|
30
|
+
*/
|
|
31
|
+
preRender?: (html: string) => void | MaybePromise<string>;
|
|
32
|
+
}
|
|
33
|
+
export interface Plugin {
|
|
34
|
+
[key: string]: any;
|
|
35
|
+
/** The name of the plugin. */
|
|
36
|
+
name?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Configures the root.js express server. Any middleware defined by the plugin
|
|
39
|
+
* will be added to the server first. If a callback fn is returned, it will
|
|
40
|
+
* be called after the root.js middlewares are added.
|
|
41
|
+
*/
|
|
42
|
+
configureServer?: ConfigureServerHook;
|
|
43
|
+
/**
|
|
44
|
+
* Hook for file changes.
|
|
45
|
+
*/
|
|
46
|
+
onFileChange?: (eventName: 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir', path: string) => void;
|
|
47
|
+
/**
|
|
48
|
+
* Returns a list of deps to bundle for ssr. The files will be bundled and
|
|
49
|
+
* output to `dist/server/`. The return value should be a map of
|
|
50
|
+
* `{output filename => input filepath}`.
|
|
51
|
+
*
|
|
52
|
+
* E.g. a value of `{foo: 'path/to/bar.js'}` will output `dist/server/foo.js`.
|
|
53
|
+
*
|
|
54
|
+
* @experimental This config is subject to change to be incorporated into a
|
|
55
|
+
* broader config option called "ssr" or "ssrOptions".
|
|
56
|
+
*/
|
|
57
|
+
ssrInput?: () => {
|
|
58
|
+
[entryAlias: string]: string;
|
|
59
|
+
};
|
|
60
|
+
/** Adds vite plugins. */
|
|
61
|
+
vitePlugins?: VitePlugin[];
|
|
62
|
+
/** Plugin lifecycle callback hooks. */
|
|
63
|
+
hooks?: PluginHooks;
|
|
64
|
+
/** Custom 404 handler. */
|
|
65
|
+
handle404?: (req: Request, res: Response, next: NextFunction) => void | Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Registers a pod (a mini root.js site) that gets merged into the parent
|
|
68
|
+
* site at dev/build time. A plugin may return a single pod, an array of
|
|
69
|
+
* pods, or a factory that receives the rootConfig.
|
|
70
|
+
*/
|
|
71
|
+
pod?: Pod | Pod[] | PodFactory;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Runs the pre-hook configureServer method of every plugin, calls a callback
|
|
75
|
+
* function, and then runs the configureServer's post-hook if provided. Plugins
|
|
76
|
+
* provide a post-hook by returning a callback function from configureServer.
|
|
77
|
+
*/
|
|
78
|
+
export declare function configureServerPlugins(server: Server, callback: () => Promise<void>, plugins: Plugin[], options: ConfigureServerOptions): Promise<void>;
|
|
79
|
+
export declare function getVitePlugins(plugins: Plugin[]): VitePlugin[];
|
|
80
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { PluginOption as VitePlugin } from 'vite';
|
|
2
|
+
import { RootConfig } from './config.js';
|
|
3
|
+
export interface Pod {
|
|
4
|
+
/** Unique pod name, e.g. '@blinkk/root-docs-pod'. */
|
|
5
|
+
name: string;
|
|
6
|
+
/**
|
|
7
|
+
* URL prefix for pod routes. Routes within the pod are served under this
|
|
8
|
+
* mount path. Defaults to '/'.
|
|
9
|
+
*/
|
|
10
|
+
mount?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Priority for route conflict resolution. Higher values win when multiple
|
|
13
|
+
* pods register the same URL path. User-site routes always take precedence
|
|
14
|
+
* regardless of priority. Defaults to 0.
|
|
15
|
+
*/
|
|
16
|
+
priority?: number;
|
|
17
|
+
/** Absolute path to the pod's routes/ directory. */
|
|
18
|
+
routesDir?: string;
|
|
19
|
+
/** Absolute path(s) to the pod's elements/ directory(s). */
|
|
20
|
+
elementsDirs?: string[];
|
|
21
|
+
/** Absolute path to the pod's bundles/ directory. */
|
|
22
|
+
bundlesDir?: string;
|
|
23
|
+
/** Absolute path to the pod's collections/ directory (root-cms only). */
|
|
24
|
+
collectionsDir?: string;
|
|
25
|
+
/** Absolute path to the pod's translations/ directory. */
|
|
26
|
+
translationsDir?: string;
|
|
27
|
+
/** Extra Vite plugins contributed by the pod. */
|
|
28
|
+
vitePlugins?: VitePlugin[];
|
|
29
|
+
}
|
|
30
|
+
export type PodFactory = (ctx: {
|
|
31
|
+
rootConfig: RootConfig;
|
|
32
|
+
}) => Pod | Promise<Pod>;
|
|
33
|
+
export interface PodConfig {
|
|
34
|
+
/** Whether the pod is enabled. Defaults to true. */
|
|
35
|
+
enabled?: boolean;
|
|
36
|
+
/** Override the pod's mount path. */
|
|
37
|
+
mount?: string;
|
|
38
|
+
/** Override the pod's priority. */
|
|
39
|
+
priority?: number;
|
|
40
|
+
/** Filter pod routes. */
|
|
41
|
+
routes?: {
|
|
42
|
+
exclude?: (string | RegExp)[];
|
|
43
|
+
};
|
|
44
|
+
/** Configure pod collections. */
|
|
45
|
+
collections?: {
|
|
46
|
+
exclude?: string[];
|
|
47
|
+
/** Rename collection ids, e.g. {Posts: 'DocsPosts'}. */
|
|
48
|
+
rename?: Record<string, string>;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Helper to define a pod with type-checking.
|
|
53
|
+
*/
|
|
54
|
+
export declare function definePod(pod: Pod): Pod;
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { Express, Request as ExpressRequest, Response as ExpressResponse, NextFunction as ExpressNextFunction } from 'express';
|
|
2
|
+
import { ComponentType } from 'preact';
|
|
3
|
+
import { ViteDevServer } from 'vite';
|
|
4
|
+
import { Hooks } from '../middleware/hooks.js';
|
|
5
|
+
import { SaveSessionOptions, Session } from '../middleware/session.js';
|
|
6
|
+
import { Renderer } from '../render/render.js';
|
|
7
|
+
import { RootConfig } from './config.js';
|
|
8
|
+
/**
|
|
9
|
+
* Param values from the route, e.g. a route like `/route/[slug].tsx` will pass
|
|
10
|
+
* `{slug: 'foo'}`.
|
|
11
|
+
*/
|
|
12
|
+
export type RouteParams = Record<string, string>;
|
|
13
|
+
/**
|
|
14
|
+
* The `getStaticProps()` function is an optional function that routes can
|
|
15
|
+
* define to fetch and transform props before passing it to the route's
|
|
16
|
+
* component.
|
|
17
|
+
*/
|
|
18
|
+
export type GetStaticProps<T = unknown> = (ctx: {
|
|
19
|
+
rootConfig: RootConfig;
|
|
20
|
+
params: RouteParams;
|
|
21
|
+
}) => Promise<{
|
|
22
|
+
/** Props to pass to the component. */
|
|
23
|
+
props?: T;
|
|
24
|
+
/** The rendered locale. */
|
|
25
|
+
locale?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Translations to pass to `useTranslations()`. If provided, the translations
|
|
28
|
+
* map passed here will be merged with the translations from
|
|
29
|
+
* `/translations/{locale}.json`.
|
|
30
|
+
*/
|
|
31
|
+
translations?: Record<string, string>;
|
|
32
|
+
/** Set to true if the route should result in a 404 page. */
|
|
33
|
+
notFound?: boolean;
|
|
34
|
+
}>;
|
|
35
|
+
/**
|
|
36
|
+
* The `getStaticPaths()` is used by the SSG build to determine all of the
|
|
37
|
+
* paths that exist for a given route. This should be used alongside a
|
|
38
|
+
* parameterized route, e.g. `/routes/blog/[slug].tsx`.
|
|
39
|
+
*/
|
|
40
|
+
export type GetStaticPaths<T = RouteParams> = (ctx: {
|
|
41
|
+
rootConfig: RootConfig;
|
|
42
|
+
}) => Promise<{
|
|
43
|
+
paths: Array<{
|
|
44
|
+
params: T;
|
|
45
|
+
}>;
|
|
46
|
+
}>;
|
|
47
|
+
/** Multipart file type for the multipartMiddleware(). */
|
|
48
|
+
export interface MultipartFile {
|
|
49
|
+
fieldname: string;
|
|
50
|
+
originalName: string;
|
|
51
|
+
encoding: string;
|
|
52
|
+
mimetype: string;
|
|
53
|
+
buffer: Buffer;
|
|
54
|
+
}
|
|
55
|
+
export type RequestMiddleware = ((req: Request, res: Response) => any) | ((req: Request, res: Response, next: NextFunction) => any) | ((err: any, req: Request, res: Response, next: NextFunction) => any);
|
|
56
|
+
/** Root.js express app. */
|
|
57
|
+
export type Server = Express & {
|
|
58
|
+
use(middlewares: RequestMiddleware | RequestMiddleware[]): any;
|
|
59
|
+
use(urlPath: string, middlewares: RequestMiddleware | RequestMiddleware[]): any;
|
|
60
|
+
};
|
|
61
|
+
/** Root.js express request. */
|
|
62
|
+
export type Request = ExpressRequest & {
|
|
63
|
+
/** The root.js project config. */
|
|
64
|
+
rootConfig?: RootConfig & {
|
|
65
|
+
rootDir: string;
|
|
66
|
+
};
|
|
67
|
+
/** The vite dev server. This is only available when running `root dev`. */
|
|
68
|
+
viteServer?: ViteDevServer;
|
|
69
|
+
/** The root.js renderer, to render routes within middleware. */
|
|
70
|
+
renderer?: Renderer;
|
|
71
|
+
/** Logged in user for the request. */
|
|
72
|
+
user?: {
|
|
73
|
+
email: string;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Handler context, provided to route files that export a custom `handler()`
|
|
77
|
+
* function.
|
|
78
|
+
*/
|
|
79
|
+
handlerContext?: HandlerContext;
|
|
80
|
+
hooks: Hooks;
|
|
81
|
+
/** Gets and sets session data via cookie. */
|
|
82
|
+
session: Session;
|
|
83
|
+
/** Firebase functions uses rawBody for its multipart data. */
|
|
84
|
+
rawBody?: any;
|
|
85
|
+
/** Map of field name to file. */
|
|
86
|
+
files?: {
|
|
87
|
+
[fieldname: string]: MultipartFile;
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
/** Root.js express response. */
|
|
91
|
+
export type Response = ExpressResponse & {
|
|
92
|
+
session: Session;
|
|
93
|
+
saveSession: (options?: SaveSessionOptions) => void;
|
|
94
|
+
};
|
|
95
|
+
/** Root.js express next function. */
|
|
96
|
+
export type NextFunction = ExpressNextFunction;
|
|
97
|
+
/**
|
|
98
|
+
* A context variable passed to a route's `handle()` method within the req
|
|
99
|
+
* object.
|
|
100
|
+
*/
|
|
101
|
+
export interface HandlerContext<Props = any> {
|
|
102
|
+
/**
|
|
103
|
+
* The resolved route.
|
|
104
|
+
*/
|
|
105
|
+
route: Route;
|
|
106
|
+
/**
|
|
107
|
+
* Param values from the route, e.g. a route like `/route/[slug].tsx` will
|
|
108
|
+
* pass `{slug: 'foo'}`.
|
|
109
|
+
*/
|
|
110
|
+
params: RouteParams;
|
|
111
|
+
/**
|
|
112
|
+
* i18n locales to try for the user's http request. The priority order mimics
|
|
113
|
+
* the Firebase Hosting i18n fallback logic.
|
|
114
|
+
* https://firebase.google.com/docs/hosting/i18n-rewrites#priority-order
|
|
115
|
+
*/
|
|
116
|
+
i18nFallbackLocales: string[];
|
|
117
|
+
/**
|
|
118
|
+
* Iterates through the i18nFallbackLocales and returns the first available
|
|
119
|
+
* locale.
|
|
120
|
+
*/
|
|
121
|
+
getPreferredLocale: (availableLocales: string[]) => string;
|
|
122
|
+
/** Renders the default exported component from the route. */
|
|
123
|
+
render: HandlerRenderFn<Props>;
|
|
124
|
+
/**
|
|
125
|
+
* Renders a 404 page. When `nextRoute` is true, the next matching route
|
|
126
|
+
* handler will be invoked instead of rendering the default 404 page.
|
|
127
|
+
*/
|
|
128
|
+
render404: (options?: {
|
|
129
|
+
nextRoute?: boolean;
|
|
130
|
+
}) => Promise<void>;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* The `handle()` function can be exported by a route to define a custom express
|
|
134
|
+
* request handler. The `req` object will contain a `handlerContext` which
|
|
135
|
+
* contains the route's param values and also a `render()` method that can be
|
|
136
|
+
* used to render the route's default component.
|
|
137
|
+
*/
|
|
138
|
+
export type Handler = (req: Request, res: Response, next: NextFunction) => void | Promise<void>;
|
|
139
|
+
export interface StaticContentResult {
|
|
140
|
+
body: string;
|
|
141
|
+
contentType?: string;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* The `getStaticContent()` function is a SSG handler function for non-HTML
|
|
145
|
+
* routes, e.g. `routes/sitemap.xml.ts`.
|
|
146
|
+
*
|
|
147
|
+
* If the route exports a `getStaticProps()` function, the props returned from
|
|
148
|
+
* that function is passed to `getStaticContent()`. Otherwise a default props
|
|
149
|
+
* value is passed which includes the `rootConfig` and route param values.
|
|
150
|
+
*/
|
|
151
|
+
export type GetStaticContent = (props: any) => Promise<StaticContentResult | string> | StaticContentResult | string;
|
|
152
|
+
export interface RouteModule {
|
|
153
|
+
default?: ComponentType<unknown>;
|
|
154
|
+
getStaticPaths?: GetStaticPaths;
|
|
155
|
+
getStaticProps?: GetStaticProps;
|
|
156
|
+
handle?: Handler;
|
|
157
|
+
getStaticContent?: GetStaticContent;
|
|
158
|
+
}
|
|
159
|
+
export interface Route {
|
|
160
|
+
/** The relative path to the route file, e.g. `routes/index.tsx`. */
|
|
161
|
+
src: string;
|
|
162
|
+
/** The imported route module. */
|
|
163
|
+
module: RouteModule;
|
|
164
|
+
/** The locale used for the route. */
|
|
165
|
+
locale: string;
|
|
166
|
+
/**
|
|
167
|
+
* Returns `true` if the route is the default locale route mapped without the
|
|
168
|
+
* i18n url prefix. For example, a route may be mapped to `/foo` and
|
|
169
|
+
* `/[locale]/foo`. The `/foo` route would have `route.isDefaultLocale` set to
|
|
170
|
+
* `true` whereas for `/[locale]/foo` it would be `false`.
|
|
171
|
+
*/
|
|
172
|
+
isDefaultLocale: boolean;
|
|
173
|
+
/**
|
|
174
|
+
* The mapped URL path for the route, e.g.:
|
|
175
|
+
*
|
|
176
|
+
* routes/index.tsx => `/`.
|
|
177
|
+
* routes/events.tsx => `/events`.
|
|
178
|
+
* routes/blog/[slug].tsx => `/blog/[slug]`.
|
|
179
|
+
*
|
|
180
|
+
* Per the example above, this value may contain placeholder params.
|
|
181
|
+
*/
|
|
182
|
+
routePath: string;
|
|
183
|
+
/**
|
|
184
|
+
* The localized URL path for the route, e.g. `/[locale]/blog/[slug]`.
|
|
185
|
+
* Per the example above, this value contains placeholder params.
|
|
186
|
+
*/
|
|
187
|
+
localeRoutePath: string;
|
|
188
|
+
/**
|
|
189
|
+
* The name of the pod that contributed this route, or undefined if the
|
|
190
|
+
* route is from the user's project.
|
|
191
|
+
*/
|
|
192
|
+
podName?: string;
|
|
193
|
+
}
|
|
194
|
+
export interface HandlerRenderOptions {
|
|
195
|
+
/** HTTP status code to return. Defaults to 200. */
|
|
196
|
+
statusCode?: number;
|
|
197
|
+
/** The rendered locale. */
|
|
198
|
+
locale?: string;
|
|
199
|
+
/**
|
|
200
|
+
* Translations to pass to `useTranslations()`. If provided, the translations
|
|
201
|
+
* map passed here will be merged with the translations from
|
|
202
|
+
* `/translations/{locale}.json`.
|
|
203
|
+
*/
|
|
204
|
+
translations?: Record<string, string>;
|
|
205
|
+
}
|
|
206
|
+
export type HandlerRenderFn<Props = any> = (props: Props, options?: HandlerRenderOptions) => Promise<void>;
|
|
207
|
+
/**
|
|
208
|
+
* Sitemap is a map of URL path -> route info.
|
|
209
|
+
*/
|
|
210
|
+
export type Sitemap = Record<string, SitemapItem>;
|
|
211
|
+
/**
|
|
212
|
+
* Sitemap route info. The "default locale" route provides "alts" that can be
|
|
213
|
+
* used for outputting the localized url paths.
|
|
214
|
+
*/
|
|
215
|
+
export interface SitemapItem {
|
|
216
|
+
urlPath: string;
|
|
217
|
+
route: Route;
|
|
218
|
+
params: Record<string, string>;
|
|
219
|
+
locale: string;
|
|
220
|
+
hrefLang: string;
|
|
221
|
+
/**
|
|
222
|
+
* Hreflang alts.
|
|
223
|
+
*/
|
|
224
|
+
alts: Record<string, {
|
|
225
|
+
hrefLang: string;
|
|
226
|
+
urlPath: string;
|
|
227
|
+
}>;
|
|
228
|
+
}
|
package/dist/core.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
testPathHasParams,
|
|
7
7
|
useI18nContext,
|
|
8
8
|
useRequestContext
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-KW7KTYGC.js";
|
|
10
10
|
import {
|
|
11
11
|
configureServerPlugins,
|
|
12
12
|
getVitePlugins
|
|
@@ -120,7 +120,7 @@ function useTranslations() {
|
|
|
120
120
|
let i18nContext = null;
|
|
121
121
|
try {
|
|
122
122
|
i18nContext = useI18nContext();
|
|
123
|
-
} catch
|
|
123
|
+
} catch {
|
|
124
124
|
console.warn("I18nContext not found");
|
|
125
125
|
}
|
|
126
126
|
const translations = i18nContext?.translations || {};
|
|
@@ -198,4 +198,4 @@ export {
|
|
|
198
198
|
useTranslationMiddleware,
|
|
199
199
|
useTranslations
|
|
200
200
|
};
|
|
201
|
-
//# sourceMappingURL=core.js.map
|
|
201
|
+
//# sourceMappingURL=core.js.map
|
package/dist/core.js.map
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/config.ts","../src/core/components/Body.tsx","../src/core/components/Head.ts","../src/core/components/Script.ts","../src/core/hooks/useStringParams.tsx","../src/core/hooks/useTranslationsMiddleware.tsx","../src/core/hooks/useTranslations.ts","../src/core/pod.ts"],"sourcesContent":["import {UserConfig as ViteUserConfig} from 'vite';\nimport {JsxRenderOptions} from '../jsx/jsx-render.js';\nimport {HtmlMinifyOptions} from '../render/html-minify.js';\nimport {HtmlPrettyOptions} from '../render/html-pretty.js';\nimport {Plugin} from './plugin.js';\nimport {PodConfig} from './pod.js';\nimport {RequestMiddleware} from './types.js';\n\nexport interface RootUserConfig {\n /**\n * Canonical domain the website will serve on. Useful for things like the\n * sitemap, SEO tags, etc.\n */\n domain?: string;\n\n /**\n * The base URL path that the site will serve on. Defaults to `/`;\n */\n base?: string;\n\n /**\n * Config for auto-injecting custom element dependencies.\n */\n elements?: {\n /**\n * A list of directories to use to look for custom elements. The dir path\n * should be relative to the project dir, e.g. \"path/to/elements\".\n */\n include?: string[];\n\n /**\n * A list of RegEx patterns to exclude. The string passed to the RegEx is\n * the file URL relative to the project root, e.g. \"/elements/foo/foo.ts\".\n */\n exclude?: RegExp[];\n };\n\n /**\n * Config for manually injecting stylesheet entries as\n * `<link rel=\"stylesheet\">` tags.\n */\n styles?: {\n /**\n * Project-root-relative stylesheet files to include on every rendered\n * page, e.g. `styles/index.css`.\n *\n * Entries are normalized as URL paths, so both `styles/index.css` and\n * `/styles/index.css` resolve to `/styles/index.css`.\n *\n * Manual entries are injected first, then auto-collected CSS\n * dependencies are merged after. Duplicate URLs are de-duped so each\n * stylesheet is only injected once.\n */\n entries?: string[];\n };\n\n /**\n * Config options for localization and internationalization.\n */\n i18n?: RootI18nConfig;\n\n /**\n * Config options for the Root.js express server.\n */\n server?: RootServerConfig;\n\n /**\n * Build options for the `root build` command.\n */\n build?: RootBuildConfig;\n\n /**\n * Vite config.\n * @see {@link https://vitejs.dev/config/} for more information.\n */\n vite?: ViteUserConfig;\n\n /**\n * Config for the built-in JSX-to-HTML renderer.\n *\n * - `mode: 'pretty'` (default) — block-level elements render on their own\n * line with no indentation.\n * - `mode: 'minimal'` — compact output with no extra whitespace.\n *\n * Use `blockElements` to specify additional custom element tag names that\n * should be treated as block-level in pretty mode.\n *\n * @example\n * ```ts\n * export default defineConfig({\n * jsxRenderer: {\n * mode: 'pretty',\n * blockElements: ['my-card', 'my-section'],\n * },\n * });\n * ```\n */\n jsxRenderer?: JsxRenderOptions;\n\n /**\n * Whether to automatically minify HTML output. This is enabled by default,\n * in order to disable, pass `minifyHtml: false` to root.config.ts.\n */\n minifyHtml?: boolean;\n\n /**\n * Options to pass to html-minifier-terser.\n */\n minifyHtmlOptions?: HtmlMinifyOptions;\n\n /**\n * Whether to pretty print HTML output.\n */\n prettyHtml?: boolean;\n\n /**\n * Options to pass to js-beautify.\n */\n prettyHtmlOptions?: HtmlPrettyOptions;\n\n /**\n * Whether to include a sitemap.xml file to the build output.\n */\n sitemap?: boolean;\n\n /**\n * Plugins.\n */\n plugins?: Plugin[];\n\n /**\n * Per-pod user-level overrides. The key is the pod name as declared in\n * Pod.name.\n */\n pods?: Record<string, PodConfig>;\n\n /**\n * Experimental config options. Note: these are subject to change at any time.\n */\n experiments?: {\n /** Whether to render `<script>` tags with `async`. */\n enableScriptAsync?: boolean;\n };\n}\n\nexport type RootConfig = RootUserConfig & {\n rootDir: string;\n};\n\nexport interface LocaleGroup {\n label?: string;\n locales: string[];\n}\n\nexport interface RootI18nConfig {\n /**\n * Locales enabled for the site.\n */\n locales?: string[];\n\n /**\n * The default locale to use. Defaults is `en`.\n */\n defaultLocale?: string;\n\n /**\n * URL format for localized content. Default is `/[locale]/[base]/[path]`.\n */\n urlFormat?: string;\n\n /**\n * Localization groups, to help UIs (like Root.js CMS) logically group\n * locales.\n */\n groups?: Record<string, LocaleGroup>;\n}\n\nexport interface RootBuildConfig {\n /**\n * Excludes the `/intl/{defaultLocale}/...` path from the SSG build.\n */\n excludeDefaultLocaleFromIntlPaths?: boolean;\n}\n\nexport interface RootRedirectConfig {\n /**\n * The source path to redirect. Accepts placeholders in the format\n * `[key]` or `[...key]`. Use `[key]` for single segments and\n * `[...key]` for multi-segment wildcards.\n * @example \"/old-path/[id]\" or \"/old-path/[...wildcard]\"\n */\n source: string;\n\n /**\n * The destination to redirect to. Placeholders from the source can\n * optionally be inserted into the destination using the same\n * placeholder format.\n * @example \"/new-path/[id]\" or \"/new-path/[...wildcard]\"\n */\n destination: string;\n\n /**\n * The redirect type (`301` = permanent, `302` = temporary). If unspecified,\n * defaults to `302` (temporary).\n */\n type?: 301 | 302;\n}\n\nexport interface RootHeaderConfig {\n /** A glob pattern match (regex not supported yet). */\n source: string;\n headers: Array<{\n key: string;\n value: string;\n }>;\n}\n\nexport interface ContentSecurityPolicyConfig {\n directives?: Record<string, string[]>;\n reportOnly?: boolean;\n}\n\nexport interface XFrameOptionsConfig {\n action: 'DENY' | 'SAMEORIGIN';\n}\n\nexport interface RootSecurityConfig {\n /**\n * Content-Security-Policy config. If enabled, a nonce is auto-generated\n * for every request and appended to script and stylesheet tags. You can\n * validate your CSP headers using a tool like {@link https://csp-evaluator.withgoogle.com/}.\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP}\n */\n contentSecurityPolicy?: ContentSecurityPolicyConfig | boolean;\n\n /**\n * Strict-Transport-Security config. When enabled, the header value is set\n * to `Strict-Transport-Security: max-age=63072000; includeSubDomains; preload`.\n */\n strictTransportSecurity?: boolean;\n\n /**\n * X-Content-Type-Options config. When enabled, the header value is set to\n * `X-Content-Type-Options: nosniff`.\n */\n xContentTypeOptions?: boolean;\n\n /**\n * X-Frame-Options config. Setting this value to `true` will default the\n * header value to `X-Frame-Options: SAMEORIGIN`.\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options}\n */\n xFrameOptions?: 'DENY' | 'SAMEORIGIN' | boolean;\n\n /**\n * X-XSS-Protection config. When enabled, the header value is set to\n * `X-XSS-Protection: 1; mode=block`.\n */\n xXssProtection?: boolean;\n}\n\nexport interface RootServerConfig {\n /**\n * An array of middleware to add to the express server. These middleware are\n * added to the beginning of the express app.\n */\n middlewares?: RequestMiddleware[];\n\n /**\n * The `trailingSlash` config allows you to control how the server handles\n * trailing slashes. This config only affects URLs that do not have a file\n * extension (i.e. HTML paths).\n *\n * - When `true`, the server redirects URLs to add a trailing slash\n * - When `false`, the server redirects URLs to remove a trailing slash\n * - When unspecified, the server allows URLs with and without trailing slash\n */\n trailingSlash?: boolean;\n\n /**\n * Cookie secret for the session middleware.\n *\n * Generate a secure secret with:\n * ```\n * node -e \"console.log(require('crypto').randomBytes(32).toString('hex'))\"\n * ```\n */\n sessionCookieSecret?: string | string[];\n\n /**\n * List of redirects. Supports optional wildcards.\n *\n * @example\n * ```ts\n * redirects: [\n * {\n * source: '/old-path/[id]',\n * destination: '/new-path/[id]',\n * type: 301,\n * },\n * {\n * source: '/old-path/[...wildcard]',\n * destination: '/new-path/[...wildcard]',\n * },\n * ]\n * ```\n */\n redirects?: RootRedirectConfig[];\n\n /**\n * HTTP headers to add to a response.\n */\n headers?: RootHeaderConfig[];\n\n /**\n * HTTP security settings. By default, all security settings are enabled with\n * commonly used default values.\n */\n security?: RootSecurityConfig;\n\n /**\n * Home page URL path, which is printed when the dev server starts.\n */\n homePagePath?: string;\n}\n\nexport function defineConfig(config: RootUserConfig): RootUserConfig {\n return config;\n}\n","import {ComponentChildren, FunctionalComponent} from 'preact';\nimport {useContext} from 'preact/hooks';\nimport {HTML_CONTEXT} from './Html.js';\n\nexport type BodyProps = preact.JSX.HTMLAttributes<HTMLBodyElement> & {\n children?: ComponentChildren;\n};\n\n/**\n * The `<Body>` component can be used to update attrs in the `<body>` tag.\n *\n * Usage:\n *\n * ```tsx\n * <Body className=\"body\">\n * <h1>Hello world</h1>\n * </Body>\n * ```\n *\n * Output:\n *\n * ```html\n * <body class=\"body\">\n * <h1>Hello world</h1>\n * </body>\n */\nexport const Body: FunctionalComponent<BodyProps> = ({children, ...attrs}) => {\n const context = useContext(HTML_CONTEXT);\n if (!context) {\n throw new Error(\n 'HTML_CONTEXT not found, double-check usage of the <Body> component'\n );\n }\n context.bodyAttrs = attrs;\n return <>{children}</>;\n};\n","import {ComponentChildren, FunctionalComponent} from 'preact';\nimport {useContext} from 'preact/hooks';\nimport {HTML_CONTEXT} from './Html.js';\n\nexport type HeadProps = preact.JSX.HTMLAttributes<HTMLHeadElement> & {\n children?: ComponentChildren;\n};\n\n/**\n * The <Head> component can be used for injecting elements into the HTML head\n * tag from any part of a page. The <Head> can be added via any component or\n * sub-component and will automatically be hoisted to the `<head>` element.\n *\n * Usage:\n *\n * ```tsx\n * <Head>\n * <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n * </Head>\n * ```\n */\nexport const Head: FunctionalComponent<HeadProps> = ({children, ...attrs}) => {\n const context = useContext(HTML_CONTEXT);\n if (!context) {\n throw new Error(\n 'HTML_CONTEXT not found, double-check usage of the <Head> component'\n );\n }\n context.headComponents.push(children);\n context.headAttrs = attrs;\n return null;\n};\n","import {FunctionalComponent} from 'preact';\nimport {useContext} from 'preact/hooks';\nimport {HTML_CONTEXT} from './Html.js';\n\nexport type ScriptProps = preact.JSX.HTMLAttributes<HTMLScriptElement> & {\n // Cast the \"src\" attr to string. See:\n // https://github.com/blinkk/rootjs/issues/519\n src?: string;\n};\n\n/**\n * The <Script> component is used for rendering any custom script modules. At\n * the moment, the system only pre-renders and bundles files that are in the\n * `/bundles` folder at the root of the project.\n *\n * Usage:\n *\n * ```tsx\n * <Script src=\"/bundles/main.ts\" />\n * ```\n */\nexport const Script: FunctionalComponent<ScriptProps> = (props) => {\n const context = useContext(HTML_CONTEXT);\n if (!context) {\n throw new Error(\n 'HTML_CONTEXT not found, double-check usage of the <Script> component'\n );\n }\n context.scriptDeps.push(props);\n return null;\n};\n","import {ComponentChildren, FunctionalComponent, createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nexport type StringParamsContext = Record<string, string>;\n\nexport const STRING_PARAMS_CONTEXT = createContext<StringParamsContext | null>(\n null\n);\n\nexport interface StringParamsProviderProps {\n value?: StringParamsContext;\n children?: ComponentChildren;\n}\n\nexport const StringParamsProvider: FunctionalComponent<\n StringParamsProviderProps\n> = (props) => {\n // Allow for nested param values from parent content providers.\n const parent = useContext(STRING_PARAMS_CONTEXT) || {};\n const merged = {...parent, ...props.value};\n return (\n <STRING_PARAMS_CONTEXT.Provider value={merged}>\n {props.children}\n </STRING_PARAMS_CONTEXT.Provider>\n );\n};\n\n/**\n * A hook that returns a map of string params, configured via the\n * `StringParamsProvider` context provider. These params are automatically\n * applied to the `useTranslations()` hook.\n *\n *\n * Usage:\n *\n * ```\n * export default function Page() {\n * return (\n * <StringParamsProvider value={{name: 'Alice'}}>\n * <SayHello />\n * </StringParamsProvider>\n * );\n * }\n *\n * function SayHello() {\n * const t = useTranslations();\n * return <h1>{t('Hello, {name}!')}</h1>;\n * }\n * ```\n *\n * This should render `<h1>Hello, Alice!</h1>`.\n */\nexport function useStringParams() {\n return useContext(STRING_PARAMS_CONTEXT) || {};\n}\n","import {ComponentChildren, FunctionalComponent, createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\ntype TransformFn = (str: string) => string;\n\nexport interface TranslationMiddleware {\n /** Transform the string before translation lookup. */\n beforeTranslate?: TransformFn;\n /** Transform the string after translation lookup. */\n afterTranslate?: TransformFn;\n /** Transform the string before `{param}` values are replaced. */\n beforeReplaceParams?: TransformFn;\n /** Transform the string after `{param}` values are replaced. */\n afterReplaceParams?: TransformFn;\n}\n\nexport interface TranslationMiddlewareContext {\n beforeTranslateFns: TransformFn[];\n afterTranslateFns: TransformFn[];\n beforeReplaceParamsFns: TransformFn[];\n afterReplaceParamsFns: TransformFn[];\n}\n\nconst TRANSLATION_MIDDLEWARE_CONTEXT =\n createContext<TranslationMiddlewareContext | null>(null);\n\nexport interface TranslationMiddlewareProviderProps {\n value?: TranslationMiddleware;\n children?: ComponentChildren;\n}\n\nexport const TranslationMiddlewareProvider: FunctionalComponent<\n TranslationMiddlewareProviderProps\n> = (props) => {\n const parent = useContext(TRANSLATION_MIDDLEWARE_CONTEXT) || {\n beforeTranslateFns: [],\n afterTranslateFns: [],\n beforeReplaceParamsFns: [],\n afterReplaceParamsFns: [],\n };\n const merged: TranslationMiddlewareContext = {\n beforeTranslateFns: [...parent.beforeTranslateFns],\n afterTranslateFns: [...parent.afterTranslateFns],\n beforeReplaceParamsFns: [...parent.beforeReplaceParamsFns],\n afterReplaceParamsFns: [...parent.afterReplaceParamsFns],\n };\n if (props.value?.beforeTranslate) {\n merged.beforeTranslateFns.push(props.value.beforeTranslate);\n }\n if (props.value?.afterTranslate) {\n merged.afterTranslateFns.push(props.value.afterTranslate);\n }\n if (props.value?.beforeReplaceParams) {\n merged.beforeReplaceParamsFns.push(props.value.beforeReplaceParams);\n }\n if (props.value?.afterReplaceParams) {\n merged.afterReplaceParamsFns.push(props.value.afterReplaceParams);\n }\n return (\n <TRANSLATION_MIDDLEWARE_CONTEXT.Provider value={merged}>\n {props.children}\n </TRANSLATION_MIDDLEWARE_CONTEXT.Provider>\n );\n};\n\nexport function useTranslationMiddleware(): TranslationMiddlewareContext {\n return (\n useContext(TRANSLATION_MIDDLEWARE_CONTEXT) || {\n beforeTranslateFns: [],\n afterTranslateFns: [],\n beforeReplaceParamsFns: [],\n afterReplaceParamsFns: [],\n }\n );\n}\n","import {I18nContext, useI18nContext} from './useI18nContext.js';\nimport {useStringParams} from './useStringParams.js';\nimport {useTranslationMiddleware} from './useTranslationsMiddleware.js';\n\n/**\n * A hook that returns a function that can be used to translate a string, and\n * optionally replace any parameterized values that are surrounded in curly\n * braces.\n *\n * Usage:\n *\n * ```ts\n * const t = useTranslations();\n * t('Hello {name}', {name: 'Bob'});\n * // => 'Bounjour Bob'\n * ```\n */\nexport function useTranslations() {\n // Ignore I18nContext not found error when used with client-side rehydration.\n let i18nContext: I18nContext | null = null;\n try {\n i18nContext = useI18nContext();\n } catch (err) {\n console.warn('I18nContext not found');\n }\n const translations = i18nContext?.translations || {};\n const stringParams = useStringParams();\n const middleware = useTranslationMiddleware();\n\n function t(str: string, params?: Record<string, string | number>): string;\n function t(\n str: string | null | undefined,\n params?: Record<string, string | number>\n ): string | undefined {\n // Suppress verbatim `'undefined'` and `'null'` output, which can occur when\n // using `useTranslations` with undefined values.\n if (typeof str === 'undefined' || str === null) {\n // Return `undefined` to suppress empty props, e.g.\n // <a title={t(undefined)}>Learn more</a>\n return undefined;\n }\n let input = normalizeString(str);\n middleware.beforeTranslateFns.forEach((fn) => {\n input = fn(input);\n });\n let translation = translations[input] ?? input ?? '';\n middleware.afterTranslateFns.forEach((fn) => {\n translation = fn(translation);\n });\n\n // Replace string params, e.g. \"Hello, {name}\".\n middleware.beforeReplaceParamsFns.forEach((fn) => {\n translation = fn(translation);\n });\n if (testHasStringParams(translation)) {\n translation = replaceStringParams(translation, {\n ...stringParams,\n ...params,\n });\n }\n middleware.afterReplaceParamsFns.forEach((fn) => {\n translation = fn(translation);\n });\n\n return translation;\n }\n return t;\n}\n\n/**\n * Cleans a string that's used for translations. Performs the following:\n * - Removes any leading/trailing whitespace\n * - Removes spaces at the end of any line\n */\nexport function normalizeString(str: string) {\n const lines = String(str)\n .trim()\n .split('\\n')\n .map((line) => removeTrailingWhitespace(line));\n return lines.join('\\n');\n}\n\nfunction removeTrailingWhitespace(str: string) {\n return String(str)\n .trimEnd()\n .replace(/ $/, '');\n}\n\nfunction testHasStringParams(str: string) {\n return str.includes('{') && str.includes('}');\n}\n\n/**\n * Replaces string placeholder params, e.g.\n *\n * ```\n * replaceStringParams('Hello, {name}!', {name: 'Joe'})\n * // => 'Hello, Joe!'\n * ```\n */\nfunction replaceStringParams(\n str: string,\n params: Record<string, string | number>\n): string {\n return str.replace(/{([^}]+)}/g, (match, key) => {\n if (key in params) {\n return String(params[key]);\n }\n return match;\n });\n}\n","import {PluginOption as VitePlugin} from 'vite';\nimport {RootConfig} from './config.js';\n\nexport interface Pod {\n /** Unique pod name, e.g. '@blinkk/root-docs-pod'. */\n name: string;\n\n /**\n * URL prefix for pod routes. Routes within the pod are served under this\n * mount path. Defaults to '/'.\n */\n mount?: string;\n\n /**\n * Priority for route conflict resolution. Higher values win when multiple\n * pods register the same URL path. User-site routes always take precedence\n * regardless of priority. Defaults to 0.\n */\n priority?: number;\n\n /** Absolute path to the pod's routes/ directory. */\n routesDir?: string;\n\n /** Absolute path(s) to the pod's elements/ directory(s). */\n elementsDirs?: string[];\n\n /** Absolute path to the pod's bundles/ directory. */\n bundlesDir?: string;\n\n /** Absolute path to the pod's collections/ directory (root-cms only). */\n collectionsDir?: string;\n\n /** Absolute path to the pod's translations/ directory. */\n translationsDir?: string;\n\n /** Extra Vite plugins contributed by the pod. */\n vitePlugins?: VitePlugin[];\n}\n\nexport type PodFactory = (ctx: {rootConfig: RootConfig}) => Pod | Promise<Pod>;\n\nexport interface PodConfig {\n /** Whether the pod is enabled. Defaults to true. */\n enabled?: boolean;\n\n /** Override the pod's mount path. */\n mount?: string;\n\n /** Override the pod's priority. */\n priority?: number;\n\n /** Filter pod routes. */\n routes?: {\n exclude?: (string | RegExp)[];\n };\n\n /** Configure pod collections. */\n collections?: {\n exclude?: string[];\n /** Rename collection ids, e.g. {Posts: 'DocsPosts'}. */\n rename?: Record<string, string>;\n };\n}\n\n/**\n * Helper to define a pod with type-checking.\n */\nexport function definePod(pod: Pod): Pod {\n return pod;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAwUO,SAAS,aAAa,QAAwC;AACnE,SAAO;AACT;;;ACzUA,SAAQ,kBAAiB;AAiChB;AARF,IAAM,OAAuC,CAAC,EAAC,UAAU,GAAG,MAAK,MAAM;AAC5E,QAAM,UAAU,WAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,UAAQ,YAAY;AACpB,SAAO,gCAAG,UAAS;AACrB;;;AClCA,SAAQ,cAAAA,mBAAiB;AAoBlB,IAAM,OAAuC,CAAC,EAAC,UAAU,GAAG,MAAK,MAAM;AAC5E,QAAM,UAAUC,YAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,UAAQ,eAAe,KAAK,QAAQ;AACpC,UAAQ,YAAY;AACpB,SAAO;AACT;;;AC9BA,SAAQ,cAAAC,mBAAiB;AAoBlB,IAAM,SAA2C,CAAC,UAAU;AACjE,QAAM,UAAUC,YAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,UAAQ,WAAW,KAAK,KAAK;AAC7B,SAAO;AACT;;;AC9BA,SAAgD,qBAAoB;AACpE,SAAQ,cAAAC,mBAAiB;AAoBrB,gBAAAC,YAAA;AAhBG,IAAM,wBAAwB;AAAA,EACnC;AACF;AAOO,IAAM,uBAET,CAAC,UAAU;AAEb,QAAM,SAASD,YAAW,qBAAqB,KAAK,CAAC;AACrD,QAAM,SAAS,EAAC,GAAG,QAAQ,GAAG,MAAM,MAAK;AACzC,SACE,gBAAAC,KAAC,sBAAsB,UAAtB,EAA+B,OAAO,QACpC,gBAAM,UACT;AAEJ;AA2BO,SAAS,kBAAkB;AAChC,SAAOD,YAAW,qBAAqB,KAAK,CAAC;AAC/C;;;ACtDA,SAAgD,iBAAAE,sBAAoB;AACpE,SAAQ,cAAAC,mBAAiB;AA0DrB,gBAAAC,YAAA;AApCJ,IAAM,iCACJF,eAAmD,IAAI;AAOlD,IAAM,gCAET,CAAC,UAAU;AACb,QAAM,SAASC,YAAW,8BAA8B,KAAK;AAAA,IAC3D,oBAAoB,CAAC;AAAA,IACrB,mBAAmB,CAAC;AAAA,IACpB,wBAAwB,CAAC;AAAA,IACzB,uBAAuB,CAAC;AAAA,EAC1B;AACA,QAAM,SAAuC;AAAA,IAC3C,oBAAoB,CAAC,GAAG,OAAO,kBAAkB;AAAA,IACjD,mBAAmB,CAAC,GAAG,OAAO,iBAAiB;AAAA,IAC/C,wBAAwB,CAAC,GAAG,OAAO,sBAAsB;AAAA,IACzD,uBAAuB,CAAC,GAAG,OAAO,qBAAqB;AAAA,EACzD;AACA,MAAI,MAAM,OAAO,iBAAiB;AAChC,WAAO,mBAAmB,KAAK,MAAM,MAAM,eAAe;AAAA,EAC5D;AACA,MAAI,MAAM,OAAO,gBAAgB;AAC/B,WAAO,kBAAkB,KAAK,MAAM,MAAM,cAAc;AAAA,EAC1D;AACA,MAAI,MAAM,OAAO,qBAAqB;AACpC,WAAO,uBAAuB,KAAK,MAAM,MAAM,mBAAmB;AAAA,EACpE;AACA,MAAI,MAAM,OAAO,oBAAoB;AACnC,WAAO,sBAAsB,KAAK,MAAM,MAAM,kBAAkB;AAAA,EAClE;AACA,SACE,gBAAAC,KAAC,+BAA+B,UAA/B,EAAwC,OAAO,QAC7C,gBAAM,UACT;AAEJ;AAEO,SAAS,2BAAyD;AACvE,SACED,YAAW,8BAA8B,KAAK;AAAA,IAC5C,oBAAoB,CAAC;AAAA,IACrB,mBAAmB,CAAC;AAAA,IACpB,wBAAwB,CAAC;AAAA,IACzB,uBAAuB,CAAC;AAAA,EAC1B;AAEJ;;;ACzDO,SAAS,kBAAkB;AAEhC,MAAI,cAAkC;AACtC,MAAI;AACF,kBAAc,eAAe;AAAA,EAC/B,SAAS,KAAK;AACZ,YAAQ,KAAK,uBAAuB;AAAA,EACtC;AACA,QAAM,eAAe,aAAa,gBAAgB,CAAC;AACnD,QAAM,eAAe,gBAAgB;AACrC,QAAM,aAAa,yBAAyB;AAG5C,WAAS,EACP,KACA,QACoB;AAGpB,QAAI,OAAO,QAAQ,eAAe,QAAQ,MAAM;AAG9C,aAAO;AAAA,IACT;AACA,QAAI,QAAQ,gBAAgB,GAAG;AAC/B,eAAW,mBAAmB,QAAQ,CAAC,OAAO;AAC5C,cAAQ,GAAG,KAAK;AAAA,IAClB,CAAC;AACD,QAAI,cAAc,aAAa,KAAK,KAAK,SAAS;AAClD,eAAW,kBAAkB,QAAQ,CAAC,OAAO;AAC3C,oBAAc,GAAG,WAAW;AAAA,IAC9B,CAAC;AAGD,eAAW,uBAAuB,QAAQ,CAAC,OAAO;AAChD,oBAAc,GAAG,WAAW;AAAA,IAC9B,CAAC;AACD,QAAI,oBAAoB,WAAW,GAAG;AACpC,oBAAc,oBAAoB,aAAa;AAAA,QAC7C,GAAG;AAAA,QACH,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AACA,eAAW,sBAAsB,QAAQ,CAAC,OAAO;AAC/C,oBAAc,GAAG,WAAW;AAAA,IAC9B,CAAC;AAED,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAOO,SAAS,gBAAgB,KAAa;AAC3C,QAAM,QAAQ,OAAO,GAAG,EACrB,KAAK,EACL,MAAM,IAAI,EACV,IAAI,CAAC,SAAS,yBAAyB,IAAI,CAAC;AAC/C,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,yBAAyB,KAAa;AAC7C,SAAO,OAAO,GAAG,EACd,QAAQ,EACR,QAAQ,WAAW,EAAE;AAC1B;AAEA,SAAS,oBAAoB,KAAa;AACxC,SAAO,IAAI,SAAS,GAAG,KAAK,IAAI,SAAS,GAAG;AAC9C;AAUA,SAAS,oBACP,KACA,QACQ;AACR,SAAO,IAAI,QAAQ,cAAc,CAAC,OAAO,QAAQ;AAC/C,QAAI,OAAO,QAAQ;AACjB,aAAO,OAAO,OAAO,GAAG,CAAC;AAAA,IAC3B;AACA,WAAO;AAAA,EACT,CAAC;AACH;;;AC3CO,SAAS,UAAU,KAAe;AACvC,SAAO;AACT;","names":["useContext","useContext","useContext","useContext","useContext","jsx","createContext","useContext","jsx"]}
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/core/config.ts", "../src/core/components/Body.tsx", "../src/core/components/Head.ts", "../src/core/components/Script.ts", "../src/core/hooks/useStringParams.tsx", "../src/core/hooks/useTranslationsMiddleware.tsx", "../src/core/hooks/useTranslations.ts", "../src/core/pod.ts"],
|
|
4
|
+
"sourcesContent": ["import {UserConfig as ViteUserConfig} from 'vite';\nimport {JsxRenderOptions} from '../jsx/jsx-render.js';\nimport {HtmlMinifyOptions} from '../render/html-minify.js';\nimport {HtmlPrettyOptions} from '../render/html-pretty.js';\nimport {Plugin} from './plugin.js';\nimport {PodConfig} from './pod.js';\nimport {RequestMiddleware} from './types.js';\n\nexport interface RootUserConfig {\n /**\n * Canonical domain the website will serve on. Useful for things like the\n * sitemap, SEO tags, etc.\n */\n domain?: string;\n\n /**\n * The base URL path that the site will serve on. Defaults to `/`;\n */\n base?: string;\n\n /**\n * Config for auto-injecting custom element dependencies.\n */\n elements?: {\n /**\n * A list of directories to use to look for custom elements. The dir path\n * should be relative to the project dir, e.g. \"path/to/elements\".\n */\n include?: string[];\n\n /**\n * A list of RegEx patterns to exclude. The string passed to the RegEx is\n * the file URL relative to the project root, e.g. \"/elements/foo/foo.ts\".\n */\n exclude?: RegExp[];\n };\n\n /**\n * Config for manually injecting stylesheet entries as\n * `<link rel=\"stylesheet\">` tags.\n */\n styles?: {\n /**\n * Project-root-relative stylesheet files to include on every rendered\n * page, e.g. `styles/index.css`.\n *\n * Entries are normalized as URL paths, so both `styles/index.css` and\n * `/styles/index.css` resolve to `/styles/index.css`.\n *\n * Manual entries are injected first, then auto-collected CSS\n * dependencies are merged after. Duplicate URLs are de-duped so each\n * stylesheet is only injected once.\n */\n entries?: string[];\n };\n\n /**\n * Config options for localization and internationalization.\n */\n i18n?: RootI18nConfig;\n\n /**\n * Config options for the Root.js express server.\n */\n server?: RootServerConfig;\n\n /**\n * Build options for the `root build` command.\n */\n build?: RootBuildConfig;\n\n /**\n * Vite config.\n * @see {@link https://vitejs.dev/config/} for more information.\n */\n vite?: ViteUserConfig;\n\n /**\n * Config for the built-in JSX-to-HTML renderer.\n *\n * - `mode: 'pretty'` (default) \u2014 block-level elements render on their own\n * line with no indentation.\n * - `mode: 'minimal'` \u2014 compact output with no extra whitespace.\n *\n * Use `blockElements` to specify additional custom element tag names that\n * should be treated as block-level in pretty mode.\n *\n * @example\n * ```ts\n * export default defineConfig({\n * jsxRenderer: {\n * mode: 'pretty',\n * blockElements: ['my-card', 'my-section'],\n * },\n * });\n * ```\n */\n jsxRenderer?: JsxRenderOptions;\n\n /**\n * Whether to automatically minify HTML output. This is enabled by default,\n * in order to disable, pass `minifyHtml: false` to root.config.ts.\n */\n minifyHtml?: boolean;\n\n /**\n * Options to pass to html-minifier-terser.\n */\n minifyHtmlOptions?: HtmlMinifyOptions;\n\n /**\n * Whether to pretty print HTML output.\n */\n prettyHtml?: boolean;\n\n /**\n * Options to pass to js-beautify.\n */\n prettyHtmlOptions?: HtmlPrettyOptions;\n\n /**\n * Whether to include a sitemap.xml file to the build output.\n */\n sitemap?: boolean;\n\n /**\n * Plugins.\n */\n plugins?: Plugin[];\n\n /**\n * Per-pod user-level overrides. The key is the pod name as declared in\n * Pod.name.\n */\n pods?: Record<string, PodConfig>;\n\n /**\n * Experimental config options. Note: these are subject to change at any time.\n */\n experiments?: {\n /** Whether to render `<script>` tags with `async`. */\n enableScriptAsync?: boolean;\n };\n}\n\nexport type RootConfig = RootUserConfig & {\n rootDir: string;\n};\n\nexport interface LocaleGroup {\n label?: string;\n locales: string[];\n}\n\nexport interface RootI18nConfig {\n /**\n * Locales enabled for the site.\n */\n locales?: string[];\n\n /**\n * The default locale to use. Defaults is `en`.\n */\n defaultLocale?: string;\n\n /**\n * URL format for localized content. Default is `/[locale]/[base]/[path]`.\n */\n urlFormat?: string;\n\n /**\n * Localization groups, to help UIs (like Root.js CMS) logically group\n * locales.\n */\n groups?: Record<string, LocaleGroup>;\n}\n\nexport interface RootBuildConfig {\n /**\n * Excludes the `/intl/{defaultLocale}/...` path from the SSG build.\n */\n excludeDefaultLocaleFromIntlPaths?: boolean;\n}\n\nexport interface RootRedirectConfig {\n /**\n * The source path to redirect. Accepts placeholders in the format\n * `[key]` or `[...key]`. Use `[key]` for single segments and\n * `[...key]` for multi-segment wildcards.\n * @example \"/old-path/[id]\" or \"/old-path/[...wildcard]\"\n */\n source: string;\n\n /**\n * The destination to redirect to. Placeholders from the source can\n * optionally be inserted into the destination using the same\n * placeholder format.\n * @example \"/new-path/[id]\" or \"/new-path/[...wildcard]\"\n */\n destination: string;\n\n /**\n * The redirect type (`301` = permanent, `302` = temporary). If unspecified,\n * defaults to `302` (temporary).\n */\n type?: 301 | 302;\n}\n\nexport interface RootHeaderConfig {\n /** A glob pattern match (regex not supported yet). */\n source: string;\n headers: Array<{\n key: string;\n value: string;\n }>;\n}\n\nexport interface ContentSecurityPolicyConfig {\n directives?: Record<string, string[]>;\n reportOnly?: boolean;\n}\n\nexport interface XFrameOptionsConfig {\n action: 'DENY' | 'SAMEORIGIN';\n}\n\nexport interface RootSecurityConfig {\n /**\n * Content-Security-Policy config. If enabled, a nonce is auto-generated\n * for every request and appended to script and stylesheet tags. You can\n * validate your CSP headers using a tool like {@link https://csp-evaluator.withgoogle.com/}.\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP}\n */\n contentSecurityPolicy?: ContentSecurityPolicyConfig | boolean;\n\n /**\n * Strict-Transport-Security config. When enabled, the header value is set\n * to `Strict-Transport-Security: max-age=63072000; includeSubDomains; preload`.\n */\n strictTransportSecurity?: boolean;\n\n /**\n * X-Content-Type-Options config. When enabled, the header value is set to\n * `X-Content-Type-Options: nosniff`.\n */\n xContentTypeOptions?: boolean;\n\n /**\n * X-Frame-Options config. Setting this value to `true` will default the\n * header value to `X-Frame-Options: SAMEORIGIN`.\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options}\n */\n xFrameOptions?: 'DENY' | 'SAMEORIGIN' | boolean;\n\n /**\n * X-XSS-Protection config. When enabled, the header value is set to\n * `X-XSS-Protection: 1; mode=block`.\n */\n xXssProtection?: boolean;\n}\n\nexport interface RootServerConfig {\n /**\n * An array of middleware to add to the express server. These middleware are\n * added to the beginning of the express app.\n */\n middlewares?: RequestMiddleware[];\n\n /**\n * The `trailingSlash` config allows you to control how the server handles\n * trailing slashes. This config only affects URLs that do not have a file\n * extension (i.e. HTML paths).\n *\n * - When `true`, the server redirects URLs to add a trailing slash\n * - When `false`, the server redirects URLs to remove a trailing slash\n * - When unspecified, the server allows URLs with and without trailing slash\n */\n trailingSlash?: boolean;\n\n /**\n * Cookie secret for the session middleware.\n *\n * Generate a secure secret with:\n * ```\n * node -e \"console.log(require('crypto').randomBytes(32).toString('hex'))\"\n * ```\n */\n sessionCookieSecret?: string | string[];\n\n /**\n * List of redirects. Supports optional wildcards.\n *\n * @example\n * ```ts\n * redirects: [\n * {\n * source: '/old-path/[id]',\n * destination: '/new-path/[id]',\n * type: 301,\n * },\n * {\n * source: '/old-path/[...wildcard]',\n * destination: '/new-path/[...wildcard]',\n * },\n * ]\n * ```\n */\n redirects?: RootRedirectConfig[];\n\n /**\n * HTTP headers to add to a response.\n */\n headers?: RootHeaderConfig[];\n\n /**\n * HTTP security settings. By default, all security settings are enabled with\n * commonly used default values.\n */\n security?: RootSecurityConfig;\n\n /**\n * Home page URL path, which is printed when the dev server starts.\n */\n homePagePath?: string;\n}\n\nexport function defineConfig(config: RootUserConfig): RootUserConfig {\n return config;\n}\n", "import {ComponentChildren, FunctionalComponent} from 'preact';\nimport {useContext} from 'preact/hooks';\nimport {HTML_CONTEXT} from './Html.js';\n\nexport type BodyProps = preact.JSX.HTMLAttributes<HTMLBodyElement> & {\n children?: ComponentChildren;\n};\n\n/**\n * The `<Body>` component can be used to update attrs in the `<body>` tag.\n *\n * Usage:\n *\n * ```tsx\n * <Body className=\"body\">\n * <h1>Hello world</h1>\n * </Body>\n * ```\n *\n * Output:\n *\n * ```html\n * <body class=\"body\">\n * <h1>Hello world</h1>\n * </body>\n */\nexport const Body: FunctionalComponent<BodyProps> = ({children, ...attrs}) => {\n const context = useContext(HTML_CONTEXT);\n if (!context) {\n throw new Error(\n 'HTML_CONTEXT not found, double-check usage of the <Body> component'\n );\n }\n context.bodyAttrs = attrs;\n return <>{children}</>;\n};\n", "import {ComponentChildren, FunctionalComponent} from 'preact';\nimport {useContext} from 'preact/hooks';\nimport {HTML_CONTEXT} from './Html.js';\n\nexport type HeadProps = preact.JSX.HTMLAttributes<HTMLHeadElement> & {\n children?: ComponentChildren;\n};\n\n/**\n * The <Head> component can be used for injecting elements into the HTML head\n * tag from any part of a page. The <Head> can be added via any component or\n * sub-component and will automatically be hoisted to the `<head>` element.\n *\n * Usage:\n *\n * ```tsx\n * <Head>\n * <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n * </Head>\n * ```\n */\nexport const Head: FunctionalComponent<HeadProps> = ({children, ...attrs}) => {\n const context = useContext(HTML_CONTEXT);\n if (!context) {\n throw new Error(\n 'HTML_CONTEXT not found, double-check usage of the <Head> component'\n );\n }\n context.headComponents.push(children);\n context.headAttrs = attrs;\n return null;\n};\n", "import {FunctionalComponent} from 'preact';\nimport {useContext} from 'preact/hooks';\nimport {HTML_CONTEXT} from './Html.js';\n\nexport type ScriptProps = preact.JSX.HTMLAttributes<HTMLScriptElement> & {\n // Cast the \"src\" attr to string. See:\n // https://github.com/blinkk/rootjs/issues/519\n src?: string;\n};\n\n/**\n * The <Script> component is used for rendering any custom script modules. At\n * the moment, the system only pre-renders and bundles files that are in the\n * `/bundles` folder at the root of the project.\n *\n * Usage:\n *\n * ```tsx\n * <Script src=\"/bundles/main.ts\" />\n * ```\n */\nexport const Script: FunctionalComponent<ScriptProps> = (props) => {\n const context = useContext(HTML_CONTEXT);\n if (!context) {\n throw new Error(\n 'HTML_CONTEXT not found, double-check usage of the <Script> component'\n );\n }\n context.scriptDeps.push(props);\n return null;\n};\n", "import {ComponentChildren, FunctionalComponent, createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nexport type StringParamsContext = Record<string, string>;\n\nexport const STRING_PARAMS_CONTEXT = createContext<StringParamsContext | null>(\n null\n);\n\nexport interface StringParamsProviderProps {\n value?: StringParamsContext;\n children?: ComponentChildren;\n}\n\nexport const StringParamsProvider: FunctionalComponent<\n StringParamsProviderProps\n> = (props) => {\n // Allow for nested param values from parent content providers.\n const parent = useContext(STRING_PARAMS_CONTEXT) || {};\n const merged = {...parent, ...props.value};\n return (\n <STRING_PARAMS_CONTEXT.Provider value={merged}>\n {props.children}\n </STRING_PARAMS_CONTEXT.Provider>\n );\n};\n\n/**\n * A hook that returns a map of string params, configured via the\n * `StringParamsProvider` context provider. These params are automatically\n * applied to the `useTranslations()` hook.\n *\n *\n * Usage:\n *\n * ```\n * export default function Page() {\n * return (\n * <StringParamsProvider value={{name: 'Alice'}}>\n * <SayHello />\n * </StringParamsProvider>\n * );\n * }\n *\n * function SayHello() {\n * const t = useTranslations();\n * return <h1>{t('Hello, {name}!')}</h1>;\n * }\n * ```\n *\n * This should render `<h1>Hello, Alice!</h1>`.\n */\nexport function useStringParams() {\n return useContext(STRING_PARAMS_CONTEXT) || {};\n}\n", "import {ComponentChildren, FunctionalComponent, createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\ntype TransformFn = (str: string) => string;\n\nexport interface TranslationMiddleware {\n /** Transform the string before translation lookup. */\n beforeTranslate?: TransformFn;\n /** Transform the string after translation lookup. */\n afterTranslate?: TransformFn;\n /** Transform the string before `{param}` values are replaced. */\n beforeReplaceParams?: TransformFn;\n /** Transform the string after `{param}` values are replaced. */\n afterReplaceParams?: TransformFn;\n}\n\nexport interface TranslationMiddlewareContext {\n beforeTranslateFns: TransformFn[];\n afterTranslateFns: TransformFn[];\n beforeReplaceParamsFns: TransformFn[];\n afterReplaceParamsFns: TransformFn[];\n}\n\nconst TRANSLATION_MIDDLEWARE_CONTEXT =\n createContext<TranslationMiddlewareContext | null>(null);\n\nexport interface TranslationMiddlewareProviderProps {\n value?: TranslationMiddleware;\n children?: ComponentChildren;\n}\n\nexport const TranslationMiddlewareProvider: FunctionalComponent<\n TranslationMiddlewareProviderProps\n> = (props) => {\n const parent = useContext(TRANSLATION_MIDDLEWARE_CONTEXT) || {\n beforeTranslateFns: [],\n afterTranslateFns: [],\n beforeReplaceParamsFns: [],\n afterReplaceParamsFns: [],\n };\n const merged: TranslationMiddlewareContext = {\n beforeTranslateFns: [...parent.beforeTranslateFns],\n afterTranslateFns: [...parent.afterTranslateFns],\n beforeReplaceParamsFns: [...parent.beforeReplaceParamsFns],\n afterReplaceParamsFns: [...parent.afterReplaceParamsFns],\n };\n if (props.value?.beforeTranslate) {\n merged.beforeTranslateFns.push(props.value.beforeTranslate);\n }\n if (props.value?.afterTranslate) {\n merged.afterTranslateFns.push(props.value.afterTranslate);\n }\n if (props.value?.beforeReplaceParams) {\n merged.beforeReplaceParamsFns.push(props.value.beforeReplaceParams);\n }\n if (props.value?.afterReplaceParams) {\n merged.afterReplaceParamsFns.push(props.value.afterReplaceParams);\n }\n return (\n <TRANSLATION_MIDDLEWARE_CONTEXT.Provider value={merged}>\n {props.children}\n </TRANSLATION_MIDDLEWARE_CONTEXT.Provider>\n );\n};\n\nexport function useTranslationMiddleware(): TranslationMiddlewareContext {\n return (\n useContext(TRANSLATION_MIDDLEWARE_CONTEXT) || {\n beforeTranslateFns: [],\n afterTranslateFns: [],\n beforeReplaceParamsFns: [],\n afterReplaceParamsFns: [],\n }\n );\n}\n", "import {I18nContext, useI18nContext} from './useI18nContext.js';\nimport {useStringParams} from './useStringParams.js';\nimport {useTranslationMiddleware} from './useTranslationsMiddleware.js';\n\n/**\n * A hook that returns a function that can be used to translate a string, and\n * optionally replace any parameterized values that are surrounded in curly\n * braces.\n *\n * Usage:\n *\n * ```ts\n * const t = useTranslations();\n * t('Hello {name}', {name: 'Bob'});\n * // => 'Bounjour Bob'\n * ```\n */\nexport function useTranslations() {\n // Ignore I18nContext not found error when used with client-side rehydration.\n let i18nContext: I18nContext | null = null;\n try {\n i18nContext = useI18nContext();\n } catch {\n console.warn('I18nContext not found');\n }\n const translations = i18nContext?.translations || {};\n const stringParams = useStringParams();\n const middleware = useTranslationMiddleware();\n\n function t(str: string, params?: Record<string, string | number>): string;\n function t(\n str: string | null | undefined,\n params?: Record<string, string | number>\n ): string | undefined {\n // Suppress verbatim `'undefined'` and `'null'` output, which can occur when\n // using `useTranslations` with undefined values.\n if (typeof str === 'undefined' || str === null) {\n // Return `undefined` to suppress empty props, e.g.\n // <a title={t(undefined)}>Learn more</a>\n return undefined;\n }\n let input = normalizeString(str);\n middleware.beforeTranslateFns.forEach((fn) => {\n input = fn(input);\n });\n let translation = translations[input] ?? input ?? '';\n middleware.afterTranslateFns.forEach((fn) => {\n translation = fn(translation);\n });\n\n // Replace string params, e.g. \"Hello, {name}\".\n middleware.beforeReplaceParamsFns.forEach((fn) => {\n translation = fn(translation);\n });\n if (testHasStringParams(translation)) {\n translation = replaceStringParams(translation, {\n ...stringParams,\n ...params,\n });\n }\n middleware.afterReplaceParamsFns.forEach((fn) => {\n translation = fn(translation);\n });\n\n return translation;\n }\n return t;\n}\n\n/**\n * Cleans a string that's used for translations. Performs the following:\n * - Removes any leading/trailing whitespace\n * - Removes spaces at the end of any line\n */\nexport function normalizeString(str: string) {\n const lines = String(str)\n .trim()\n .split('\\n')\n .map((line) => removeTrailingWhitespace(line));\n return lines.join('\\n');\n}\n\nfunction removeTrailingWhitespace(str: string) {\n return String(str)\n .trimEnd()\n .replace(/ $/, '');\n}\n\nfunction testHasStringParams(str: string) {\n return str.includes('{') && str.includes('}');\n}\n\n/**\n * Replaces string placeholder params, e.g.\n *\n * ```\n * replaceStringParams('Hello, {name}!', {name: 'Joe'})\n * // => 'Hello, Joe!'\n * ```\n */\nfunction replaceStringParams(\n str: string,\n params: Record<string, string | number>\n): string {\n return str.replace(/{([^}]+)}/g, (match, key) => {\n if (key in params) {\n return String(params[key]);\n }\n return match;\n });\n}\n", "import {PluginOption as VitePlugin} from 'vite';\nimport {RootConfig} from './config.js';\n\nexport interface Pod {\n /** Unique pod name, e.g. '@blinkk/root-docs-pod'. */\n name: string;\n\n /**\n * URL prefix for pod routes. Routes within the pod are served under this\n * mount path. Defaults to '/'.\n */\n mount?: string;\n\n /**\n * Priority for route conflict resolution. Higher values win when multiple\n * pods register the same URL path. User-site routes always take precedence\n * regardless of priority. Defaults to 0.\n */\n priority?: number;\n\n /** Absolute path to the pod's routes/ directory. */\n routesDir?: string;\n\n /** Absolute path(s) to the pod's elements/ directory(s). */\n elementsDirs?: string[];\n\n /** Absolute path to the pod's bundles/ directory. */\n bundlesDir?: string;\n\n /** Absolute path to the pod's collections/ directory (root-cms only). */\n collectionsDir?: string;\n\n /** Absolute path to the pod's translations/ directory. */\n translationsDir?: string;\n\n /** Extra Vite plugins contributed by the pod. */\n vitePlugins?: VitePlugin[];\n}\n\nexport type PodFactory = (ctx: {rootConfig: RootConfig}) => Pod | Promise<Pod>;\n\nexport interface PodConfig {\n /** Whether the pod is enabled. Defaults to true. */\n enabled?: boolean;\n\n /** Override the pod's mount path. */\n mount?: string;\n\n /** Override the pod's priority. */\n priority?: number;\n\n /** Filter pod routes. */\n routes?: {\n exclude?: (string | RegExp)[];\n };\n\n /** Configure pod collections. */\n collections?: {\n exclude?: string[];\n /** Rename collection ids, e.g. {Posts: 'DocsPosts'}. */\n rename?: Record<string, string>;\n };\n}\n\n/**\n * Helper to define a pod with type-checking.\n */\nexport function definePod(pod: Pod): Pod {\n return pod;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["useContext", "useContext", "useContext", "useContext", "useContext", "jsx", "createContext", "useContext", "jsx"]
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './server.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { HttpsOptions } from 'firebase-functions/v2/https';
|
|
2
|
+
export interface ProdServerOptions {
|
|
3
|
+
rootDir?: string;
|
|
4
|
+
mode?: 'preview' | 'production';
|
|
5
|
+
httpsOptions?: HttpsOptions;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Firebase Function that runs a Root.js server running in SSR mode.
|
|
9
|
+
*/
|
|
10
|
+
export declare function server(options?: ProdServerOptions): import("firebase-functions/v2/https").HttpsFunction;
|
package/dist/functions.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createPreviewServer,
|
|
3
3
|
createProdServer
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-JTZWI4MH.js";
|
|
5
5
|
import "./chunk-6P3B7ZXL.js";
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-6NBKAR5Y.js";
|
|
7
|
+
import "./chunk-7PSEEE6C.js";
|
|
8
8
|
import "./chunk-XSNCF7WU.js";
|
|
9
9
|
|
|
10
10
|
// src/functions/server.ts
|
|
11
|
-
import path from "path";
|
|
11
|
+
import path from "node:path";
|
|
12
12
|
import { onRequest } from "firebase-functions/v2/https";
|
|
13
13
|
function server(options) {
|
|
14
14
|
let rootServer;
|
|
@@ -27,4 +27,4 @@ function server(options) {
|
|
|
27
27
|
export {
|
|
28
28
|
server
|
|
29
29
|
};
|
|
30
|
-
//# sourceMappingURL=functions.js.map
|
|
30
|
+
//# sourceMappingURL=functions.js.map
|
package/dist/functions.js.map
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/functions/server.ts"],
|
|
4
|
+
"sourcesContent": ["import path from 'node:path';\nimport {HttpsOptions, onRequest} from 'firebase-functions/v2/https';\nimport {createPreviewServer, createProdServer} from '../cli/cli.js';\nimport {Server} from '../core/types.js';\n\nexport interface ProdServerOptions {\n rootDir?: string;\n mode?: 'preview' | 'production';\n httpsOptions?: HttpsOptions;\n}\n\n/**\n * Firebase Function that runs a Root.js server running in SSR mode.\n */\nexport function server(options?: ProdServerOptions) {\n let rootServer: Server;\n const rootDir = path.resolve(options?.rootDir || process.cwd());\n return onRequest(options?.httpsOptions || {}, async (req, res) => {\n if (!rootServer) {\n if (options?.mode === 'preview') {\n rootServer = await createPreviewServer({rootDir});\n } else {\n rootServer = await createProdServer({rootDir});\n }\n }\n await rootServer(req, res);\n });\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;AAAA,OAAO,UAAU;AACjB,SAAsB,iBAAgB;AAa/B,SAAS,OAAO,SAA6B;AAClD,MAAI;AACJ,QAAM,UAAU,KAAK,QAAQ,SAAS,WAAW,QAAQ,IAAI,CAAC;AAC9D,SAAO,UAAU,SAAS,gBAAgB,CAAC,GAAG,OAAO,KAAK,QAAQ;AAChE,QAAI,CAAC,YAAY;AACf,UAAI,SAAS,SAAS,WAAW;AAC/B,qBAAa,MAAM,oBAAoB,EAAC,QAAO,CAAC;AAAA,MAClD,OAAO;AACL,qBAAa,MAAM,iBAAiB,EAAC,QAAO,CAAC;AAAA,MAC/C;AAAA,IACF;AACA,UAAM,WAAW,KAAK,GAAG;AAAA,EAC3B,CAAC;AACH;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @module jsx-dev-runtime
|
|
3
|
+
*
|
|
4
|
+
* Development JSX runtime entry point. For SSR, this is identical to the
|
|
5
|
+
* production runtime since there is no client-side diffing or dev warnings
|
|
6
|
+
* to add. TypeScript / bundlers look for this module when `jsxImportSource`
|
|
7
|
+
* is configured and the build is in development mode.
|
|
8
|
+
*/
|
|
9
|
+
export { jsx, jsx as jsxDEV, jsxs, Fragment } from './jsx-runtime.js';
|
|
10
|
+
export type { JSX } from './types.js';
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Fragment,
|
|
3
3
|
jsx
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-3Z5TNZEP.js";
|
|
5
5
|
export {
|
|
6
6
|
Fragment,
|
|
7
7
|
jsx,
|
|
8
8
|
jsx as jsxDEV,
|
|
9
9
|
jsx as jsxs
|
|
10
10
|
};
|
|
11
|
-
//# sourceMappingURL=jsx-dev-runtime.js.map
|
|
11
|
+
//# sourceMappingURL=jsx-dev-runtime.js.map
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
interface JsxRenderOptions {
|
|
1
|
+
import { VNode } from './jsx-runtime.js';
|
|
2
|
+
export interface JsxRenderOptions {
|
|
4
3
|
/** Render mode. `'pretty'` adds newlines around block elements; `'minimal'` outputs compact HTML. Default: `'pretty'`. */
|
|
5
4
|
mode?: 'pretty' | 'minimal';
|
|
6
5
|
/** Additional tag names to treat as block-level elements in pretty mode. */
|
|
@@ -9,6 +8,4 @@ interface JsxRenderOptions {
|
|
|
9
8
|
/**
|
|
10
9
|
* Renders a Preact VNode tree to an HTML string.
|
|
11
10
|
*/
|
|
12
|
-
declare function renderJsxToString(vnode: VNode, options?: JsxRenderOptions): string;
|
|
13
|
-
|
|
14
|
-
export { type JsxRenderOptions as J, renderJsxToString as r };
|
|
11
|
+
export declare function renderJsxToString(vnode: VNode, options?: JsxRenderOptions): string;
|