hadars 0.2.0 → 0.2.2-rc.0

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,64 @@
1
+ import { H as HadarsEntryModule, a as HadarsOptions } from './hadars-mKu5txjW.cjs';
2
+
3
+ /**
4
+ * Cloudflare Workers adapter for hadars.
5
+ *
6
+ * After running `hadars build`, bundle your app with:
7
+ *
8
+ * hadars export cloudflare
9
+ *
10
+ * This produces a self-contained `cloudflare.mjs` that you deploy with:
11
+ *
12
+ * wrangler deploy
13
+ *
14
+ * Static assets (JS, CSS, fonts) under `.hadars/static/` must be served from
15
+ * R2 or another CDN — the Worker only handles HTML rendering. Route requests
16
+ * for static file extensions to R2 and everything else to the Worker.
17
+ *
18
+ * @example wrangler.toml
19
+ * name = "my-app"
20
+ * main = "cloudflare.mjs"
21
+ * compatibility_date = "2024-09-23"
22
+ * compatibility_flags = ["nodejs_compat"]
23
+ */
24
+
25
+ /**
26
+ * Pre-loaded SSR module and HTML template for single-file Cloudflare bundles
27
+ * produced by `hadars export cloudflare`. All I/O is eliminated at runtime —
28
+ * the Worker is fully self-contained.
29
+ */
30
+ interface CloudflareBundled {
31
+ /** The compiled SSR module — import it statically in your entry shim. */
32
+ ssrModule: HadarsEntryModule<any>;
33
+ /**
34
+ * The contents of `.hadars/static/out.html` — esbuild inlines this as a
35
+ * string when `hadars export cloudflare` runs.
36
+ */
37
+ outHtml: string;
38
+ }
39
+ /**
40
+ * The shape of a Cloudflare Workers export object.
41
+ * Return this as the default export of your Worker entry file.
42
+ */
43
+ interface CloudflareHandler {
44
+ fetch(request: Request, env: unknown, ctx: unknown): Promise<Response>;
45
+ }
46
+ /**
47
+ * Creates a Cloudflare Workers handler from a hadars config and a pre-bundled
48
+ * SSR module. Use this as the default export of your Worker entry.
49
+ *
50
+ * Unlike the Lambda adapter, Cloudflare Workers receive a standard Web
51
+ * `Request` and return a standard `Response` — no event format conversion is
52
+ * required. Static assets must be routed to R2/CDN via wrangler rules; this
53
+ * Worker handles only HTML rendering and API routes.
54
+ *
55
+ * @example — generated entry shim (created by `hadars export cloudflare`)
56
+ * import * as ssrModule from './.hadars/index.ssr.js';
57
+ * import outHtml from './.hadars/static/out.html';
58
+ * import { createCloudflareHandler } from 'hadars/cloudflare';
59
+ * import config from './hadars.config';
60
+ * export default createCloudflareHandler(config, { ssrModule, outHtml });
61
+ */
62
+ declare function createCloudflareHandler(options: HadarsOptions, bundled: CloudflareBundled): CloudflareHandler;
63
+
64
+ export { type CloudflareBundled, type CloudflareHandler, createCloudflareHandler };
@@ -0,0 +1,64 @@
1
+ import { H as HadarsEntryModule, a as HadarsOptions } from './hadars-mKu5txjW.js';
2
+
3
+ /**
4
+ * Cloudflare Workers adapter for hadars.
5
+ *
6
+ * After running `hadars build`, bundle your app with:
7
+ *
8
+ * hadars export cloudflare
9
+ *
10
+ * This produces a self-contained `cloudflare.mjs` that you deploy with:
11
+ *
12
+ * wrangler deploy
13
+ *
14
+ * Static assets (JS, CSS, fonts) under `.hadars/static/` must be served from
15
+ * R2 or another CDN — the Worker only handles HTML rendering. Route requests
16
+ * for static file extensions to R2 and everything else to the Worker.
17
+ *
18
+ * @example wrangler.toml
19
+ * name = "my-app"
20
+ * main = "cloudflare.mjs"
21
+ * compatibility_date = "2024-09-23"
22
+ * compatibility_flags = ["nodejs_compat"]
23
+ */
24
+
25
+ /**
26
+ * Pre-loaded SSR module and HTML template for single-file Cloudflare bundles
27
+ * produced by `hadars export cloudflare`. All I/O is eliminated at runtime —
28
+ * the Worker is fully self-contained.
29
+ */
30
+ interface CloudflareBundled {
31
+ /** The compiled SSR module — import it statically in your entry shim. */
32
+ ssrModule: HadarsEntryModule<any>;
33
+ /**
34
+ * The contents of `.hadars/static/out.html` — esbuild inlines this as a
35
+ * string when `hadars export cloudflare` runs.
36
+ */
37
+ outHtml: string;
38
+ }
39
+ /**
40
+ * The shape of a Cloudflare Workers export object.
41
+ * Return this as the default export of your Worker entry file.
42
+ */
43
+ interface CloudflareHandler {
44
+ fetch(request: Request, env: unknown, ctx: unknown): Promise<Response>;
45
+ }
46
+ /**
47
+ * Creates a Cloudflare Workers handler from a hadars config and a pre-bundled
48
+ * SSR module. Use this as the default export of your Worker entry.
49
+ *
50
+ * Unlike the Lambda adapter, Cloudflare Workers receive a standard Web
51
+ * `Request` and return a standard `Response` — no event format conversion is
52
+ * required. Static assets must be routed to R2/CDN via wrangler rules; this
53
+ * Worker handles only HTML rendering and API routes.
54
+ *
55
+ * @example — generated entry shim (created by `hadars export cloudflare`)
56
+ * import * as ssrModule from './.hadars/index.ssr.js';
57
+ * import outHtml from './.hadars/static/out.html';
58
+ * import { createCloudflareHandler } from 'hadars/cloudflare';
59
+ * import config from './hadars.config';
60
+ * export default createCloudflareHandler(config, { ssrModule, outHtml });
61
+ */
62
+ declare function createCloudflareHandler(options: HadarsOptions, bundled: CloudflareBundled): CloudflareHandler;
63
+
64
+ export { type CloudflareBundled, type CloudflareHandler, createCloudflareHandler };
@@ -0,0 +1,68 @@
1
+ import {
2
+ buildHeadHtml,
3
+ buildSsrHtml,
4
+ createProxyHandler,
5
+ createRenderCache,
6
+ getReactResponse,
7
+ makePrecontentHtmlGetter,
8
+ parseRequest
9
+ } from "./chunk-H72BZXOA.js";
10
+ import "./chunk-LY5MTHFV.js";
11
+ import "./chunk-OS3V4CPN.js";
12
+
13
+ // src/cloudflare.ts
14
+ import "react";
15
+ function createCloudflareHandler(options, bundled) {
16
+ const fetchHandler = options.fetch;
17
+ const handleProxy = createProxyHandler(options);
18
+ const getPrecontentHtml = makePrecontentHtmlGetter(Promise.resolve(bundled.outHtml));
19
+ const { ssrModule } = bundled;
20
+ const runHandler = async (req) => {
21
+ const request = parseRequest(req);
22
+ if (fetchHandler) {
23
+ const res = await fetchHandler(request);
24
+ if (res) return res;
25
+ }
26
+ const proxied = await handleProxy(request);
27
+ if (proxied) return proxied;
28
+ try {
29
+ const { default: Component, getInitProps, getFinalProps } = ssrModule;
30
+ const { head, status, getAppBody, finalize } = await getReactResponse(request, {
31
+ document: {
32
+ body: Component,
33
+ lang: "en",
34
+ getInitProps,
35
+ getFinalProps
36
+ }
37
+ });
38
+ if (request.headers.get("Accept") === "application/json") {
39
+ const { clientProps: clientProps2 } = await finalize();
40
+ const serverData = clientProps2.__serverData ?? {};
41
+ return new Response(JSON.stringify({ serverData }), {
42
+ status,
43
+ headers: { "Content-Type": "application/json; charset=utf-8" }
44
+ });
45
+ }
46
+ const bodyHtml = await getAppBody();
47
+ const { clientProps } = await finalize();
48
+ const headHtml = buildHeadHtml(head);
49
+ const html = await buildSsrHtml(bodyHtml, clientProps, headHtml, getPrecontentHtml);
50
+ return new Response(html, {
51
+ status,
52
+ headers: { "Content-Type": "text/html; charset=utf-8" }
53
+ });
54
+ } catch (err) {
55
+ console.error("[hadars] SSR render error:", err);
56
+ return new Response("Internal Server Error", { status: 500 });
57
+ }
58
+ };
59
+ const finalFetch = options.cache ? createRenderCache(options.cache, (req) => runHandler(req)) : (req) => runHandler(req);
60
+ return {
61
+ fetch: async (request, _env, ctx) => {
62
+ return await finalFetch(request, ctx) ?? new Response("Not Found", { status: 404 });
63
+ }
64
+ };
65
+ }
66
+ export {
67
+ createCloudflareHandler
68
+ };
@@ -1,6 +1,33 @@
1
- import { MetaHTMLAttributes, LinkHTMLAttributes, StyleHTMLAttributes, ScriptHTMLAttributes } from 'react';
2
-
3
- type HadarsGetInitialProps<T extends {}> = (req: HadarsRequest) => Promise<T> | T;
1
+ /**
2
+ * In-process GraphQL executor passed to `getInitProps` and `paths` during
3
+ * `hadars export static`. Hadars is executor-agnostic configure it in
4
+ * `hadars.config.ts` using any GraphQL library (e.g. `graphql-js`):
5
+ *
6
+ * ```ts
7
+ * import { graphql as gql, buildSchema } from 'graphql';
8
+ * const schema = buildSchema(`type Query { hello: String }`);
9
+ * const rootValue = { hello: () => 'world' };
10
+ *
11
+ * export default {
12
+ * graphql: (query, variables) =>
13
+ * gql({ schema, rootValue, source: query, variableValues: variables }),
14
+ * } satisfies HadarsOptions;
15
+ * ```
16
+ */
17
+ type GraphQLExecutor = (query: string, variables?: Record<string, unknown>) => Promise<{
18
+ data?: any;
19
+ errors?: ReadonlyArray<{
20
+ message: string;
21
+ }>;
22
+ }>;
23
+ /**
24
+ * Context passed as the second argument to `getInitProps` and `paths`
25
+ * during `hadars export static`. Not present in dev/run mode.
26
+ */
27
+ interface HadarsStaticContext {
28
+ graphql: GraphQLExecutor;
29
+ }
30
+ type HadarsGetInitialProps<T extends {}> = (req: HadarsRequest, ctx?: HadarsStaticContext) => Promise<T> | T;
4
31
  type HadarsGetClientProps<T extends {}> = (props: T) => Promise<T> | T;
5
32
  type HadarsGetFinalProps<T extends {}> = (props: HadarsProps<T>) => Promise<T> | T;
6
33
  type HadarsApp<T extends {}> = React.FC<HadarsProps<T>>;
@@ -10,43 +37,10 @@ type HadarsEntryModule<T extends {}> = {
10
37
  getFinalProps?: HadarsGetFinalProps<T>;
11
38
  getClientProps?: HadarsGetClientProps<T>;
12
39
  };
13
- interface AppHead {
14
- title: string;
15
- status: number;
16
- meta: Record<string, MetaProps>;
17
- link: Record<string, LinkProps>;
18
- style: Record<string, StyleProps>;
19
- script: Record<string, ScriptProps>;
20
- }
21
- type UnsuspendEntry = {
22
- status: 'pending';
23
- promise: Promise<unknown>;
24
- } | {
25
- status: 'fulfilled';
26
- value: unknown;
27
- } | {
28
- status: 'rejected';
29
- reason: unknown;
30
- };
31
- /** @internal Populated by the framework's render loop — use useServerData() instead. */
32
- interface AppUnsuspend {
33
- cache: Map<string, UnsuspendEntry>;
34
- }
35
- interface AppContext {
36
- path?: string;
37
- head: AppHead;
38
- /** @internal Framework use only — use the useServerData() hook instead. */
39
- _unsuspend?: AppUnsuspend;
40
- }
41
40
  type HadarsEntryBase = {
42
41
  location: string;
43
- context: AppContext;
44
42
  };
45
43
  type HadarsProps<T extends {}> = T & HadarsEntryBase;
46
- type MetaProps = MetaHTMLAttributes<HTMLMetaElement>;
47
- type LinkProps = LinkHTMLAttributes<HTMLLinkElement>;
48
- type StyleProps = StyleHTMLAttributes<HTMLStyleElement>;
49
- type ScriptProps = ScriptHTMLAttributes<HTMLScriptElement>;
50
44
  interface HadarsOptions {
51
45
  port?: number;
52
46
  entry: string;
@@ -183,6 +177,68 @@ interface HadarsOptions {
183
177
  key: string;
184
178
  ttl?: number;
185
179
  } | null | undefined>;
180
+ /**
181
+ * Static export path list. Required for `hadars export static`.
182
+ *
183
+ * Return an array of URL paths (e.g. `['/', '/about', '/blog/hello']`) that
184
+ * should be pre-rendered to HTML files. May be async.
185
+ *
186
+ * @example
187
+ * paths: () => ['/', '/about', '/contact']
188
+ *
189
+ * @example
190
+ * paths: async () => {
191
+ * const posts = await fetchBlogPosts();
192
+ * return ['/', ...posts.map(p => `/blog/${p.slug}`)];
193
+ * }
194
+ */
195
+ /**
196
+ * In-process GraphQL executor. Supply this to use the GraphQL data layer
197
+ * in `paths` and `getInitProps` during `hadars export static`.
198
+ * Has no effect in `dev` / `run` mode.
199
+ */
200
+ graphql?: GraphQLExecutor;
201
+ paths?: (ctx: HadarsStaticContext) => Promise<string[]> | string[];
202
+ /**
203
+ * Gatsby-compatible source plugins to run before `hadars export static`.
204
+ *
205
+ * Each entry mirrors Gatsby's `gatsby-config.js` plugin object format:
206
+ * `{ resolve: 'gatsby-source-contentful', options: { spaceId: '...', accessToken: '...' } }`
207
+ *
208
+ * The plugin must export a `sourceNodes` function with the standard Gatsby API.
209
+ * Hadars provides a thin shim covering the most-used surface:
210
+ * `actions.createNode`, `createNodeId`, `createContentDigest`, `cache`, `reporter`,
211
+ * `getNode`, `getNodes`, `getNodesByType`.
212
+ *
213
+ * After all sources have run, hadars auto-generates a GraphQL schema from the
214
+ * collected nodes and makes it available via `config.graphql` in `getInitProps`
215
+ * and `paths`. Requires `graphql` to be installed in the project.
216
+ *
217
+ * @example
218
+ * sources: [
219
+ * {
220
+ * resolve: 'gatsby-source-filesystem',
221
+ * options: { name: 'posts', path: './content/posts' },
222
+ * },
223
+ * ]
224
+ */
225
+ sources?: HadarsSourceEntry[];
226
+ }
227
+ /**
228
+ * A Gatsby-compatible source plugin entry, matching the format used in
229
+ * `gatsby-config.js` / `gatsby-config.ts`.
230
+ */
231
+ interface HadarsSourceEntry {
232
+ /**
233
+ * Package name (e.g. `'gatsby-source-contentful'`) or a pre-imported module
234
+ * object that exports `sourceNodes`. Using a module object lets you pass
235
+ * local source plugins without publishing them to npm.
236
+ */
237
+ resolve: string | {
238
+ sourceNodes?: (ctx: any, opts?: any) => Promise<void> | void;
239
+ };
240
+ /** Plugin options forwarded as the second argument to `sourceNodes`. */
241
+ options?: Record<string, unknown>;
186
242
  }
187
243
  type SwcPluginItem = string | [string, Record<string, unknown>] | {
188
244
  path: string;
@@ -196,4 +252,4 @@ interface HadarsRequest extends Request {
196
252
  cookies: Record<string, string>;
197
253
  }
198
254
 
199
- export type { AppContext as A, HadarsEntryModule as H, HadarsOptions as a, HadarsApp as b, HadarsGetClientProps as c, HadarsGetFinalProps as d, HadarsGetInitialProps as e, HadarsProps as f, HadarsRequest as g };
255
+ export type { GraphQLExecutor as G, HadarsEntryModule as H, HadarsOptions as a, HadarsApp as b, HadarsGetClientProps as c, HadarsGetFinalProps as d, HadarsGetInitialProps as e, HadarsProps as f, HadarsRequest as g, HadarsSourceEntry as h, HadarsStaticContext as i };
@@ -1,6 +1,33 @@
1
- import { MetaHTMLAttributes, LinkHTMLAttributes, StyleHTMLAttributes, ScriptHTMLAttributes } from 'react';
2
-
3
- type HadarsGetInitialProps<T extends {}> = (req: HadarsRequest) => Promise<T> | T;
1
+ /**
2
+ * In-process GraphQL executor passed to `getInitProps` and `paths` during
3
+ * `hadars export static`. Hadars is executor-agnostic configure it in
4
+ * `hadars.config.ts` using any GraphQL library (e.g. `graphql-js`):
5
+ *
6
+ * ```ts
7
+ * import { graphql as gql, buildSchema } from 'graphql';
8
+ * const schema = buildSchema(`type Query { hello: String }`);
9
+ * const rootValue = { hello: () => 'world' };
10
+ *
11
+ * export default {
12
+ * graphql: (query, variables) =>
13
+ * gql({ schema, rootValue, source: query, variableValues: variables }),
14
+ * } satisfies HadarsOptions;
15
+ * ```
16
+ */
17
+ type GraphQLExecutor = (query: string, variables?: Record<string, unknown>) => Promise<{
18
+ data?: any;
19
+ errors?: ReadonlyArray<{
20
+ message: string;
21
+ }>;
22
+ }>;
23
+ /**
24
+ * Context passed as the second argument to `getInitProps` and `paths`
25
+ * during `hadars export static`. Not present in dev/run mode.
26
+ */
27
+ interface HadarsStaticContext {
28
+ graphql: GraphQLExecutor;
29
+ }
30
+ type HadarsGetInitialProps<T extends {}> = (req: HadarsRequest, ctx?: HadarsStaticContext) => Promise<T> | T;
4
31
  type HadarsGetClientProps<T extends {}> = (props: T) => Promise<T> | T;
5
32
  type HadarsGetFinalProps<T extends {}> = (props: HadarsProps<T>) => Promise<T> | T;
6
33
  type HadarsApp<T extends {}> = React.FC<HadarsProps<T>>;
@@ -10,43 +37,10 @@ type HadarsEntryModule<T extends {}> = {
10
37
  getFinalProps?: HadarsGetFinalProps<T>;
11
38
  getClientProps?: HadarsGetClientProps<T>;
12
39
  };
13
- interface AppHead {
14
- title: string;
15
- status: number;
16
- meta: Record<string, MetaProps>;
17
- link: Record<string, LinkProps>;
18
- style: Record<string, StyleProps>;
19
- script: Record<string, ScriptProps>;
20
- }
21
- type UnsuspendEntry = {
22
- status: 'pending';
23
- promise: Promise<unknown>;
24
- } | {
25
- status: 'fulfilled';
26
- value: unknown;
27
- } | {
28
- status: 'rejected';
29
- reason: unknown;
30
- };
31
- /** @internal Populated by the framework's render loop — use useServerData() instead. */
32
- interface AppUnsuspend {
33
- cache: Map<string, UnsuspendEntry>;
34
- }
35
- interface AppContext {
36
- path?: string;
37
- head: AppHead;
38
- /** @internal Framework use only — use the useServerData() hook instead. */
39
- _unsuspend?: AppUnsuspend;
40
- }
41
40
  type HadarsEntryBase = {
42
41
  location: string;
43
- context: AppContext;
44
42
  };
45
43
  type HadarsProps<T extends {}> = T & HadarsEntryBase;
46
- type MetaProps = MetaHTMLAttributes<HTMLMetaElement>;
47
- type LinkProps = LinkHTMLAttributes<HTMLLinkElement>;
48
- type StyleProps = StyleHTMLAttributes<HTMLStyleElement>;
49
- type ScriptProps = ScriptHTMLAttributes<HTMLScriptElement>;
50
44
  interface HadarsOptions {
51
45
  port?: number;
52
46
  entry: string;
@@ -183,6 +177,68 @@ interface HadarsOptions {
183
177
  key: string;
184
178
  ttl?: number;
185
179
  } | null | undefined>;
180
+ /**
181
+ * Static export path list. Required for `hadars export static`.
182
+ *
183
+ * Return an array of URL paths (e.g. `['/', '/about', '/blog/hello']`) that
184
+ * should be pre-rendered to HTML files. May be async.
185
+ *
186
+ * @example
187
+ * paths: () => ['/', '/about', '/contact']
188
+ *
189
+ * @example
190
+ * paths: async () => {
191
+ * const posts = await fetchBlogPosts();
192
+ * return ['/', ...posts.map(p => `/blog/${p.slug}`)];
193
+ * }
194
+ */
195
+ /**
196
+ * In-process GraphQL executor. Supply this to use the GraphQL data layer
197
+ * in `paths` and `getInitProps` during `hadars export static`.
198
+ * Has no effect in `dev` / `run` mode.
199
+ */
200
+ graphql?: GraphQLExecutor;
201
+ paths?: (ctx: HadarsStaticContext) => Promise<string[]> | string[];
202
+ /**
203
+ * Gatsby-compatible source plugins to run before `hadars export static`.
204
+ *
205
+ * Each entry mirrors Gatsby's `gatsby-config.js` plugin object format:
206
+ * `{ resolve: 'gatsby-source-contentful', options: { spaceId: '...', accessToken: '...' } }`
207
+ *
208
+ * The plugin must export a `sourceNodes` function with the standard Gatsby API.
209
+ * Hadars provides a thin shim covering the most-used surface:
210
+ * `actions.createNode`, `createNodeId`, `createContentDigest`, `cache`, `reporter`,
211
+ * `getNode`, `getNodes`, `getNodesByType`.
212
+ *
213
+ * After all sources have run, hadars auto-generates a GraphQL schema from the
214
+ * collected nodes and makes it available via `config.graphql` in `getInitProps`
215
+ * and `paths`. Requires `graphql` to be installed in the project.
216
+ *
217
+ * @example
218
+ * sources: [
219
+ * {
220
+ * resolve: 'gatsby-source-filesystem',
221
+ * options: { name: 'posts', path: './content/posts' },
222
+ * },
223
+ * ]
224
+ */
225
+ sources?: HadarsSourceEntry[];
226
+ }
227
+ /**
228
+ * A Gatsby-compatible source plugin entry, matching the format used in
229
+ * `gatsby-config.js` / `gatsby-config.ts`.
230
+ */
231
+ interface HadarsSourceEntry {
232
+ /**
233
+ * Package name (e.g. `'gatsby-source-contentful'`) or a pre-imported module
234
+ * object that exports `sourceNodes`. Using a module object lets you pass
235
+ * local source plugins without publishing them to npm.
236
+ */
237
+ resolve: string | {
238
+ sourceNodes?: (ctx: any, opts?: any) => Promise<void> | void;
239
+ };
240
+ /** Plugin options forwarded as the second argument to `sourceNodes`. */
241
+ options?: Record<string, unknown>;
186
242
  }
187
243
  type SwcPluginItem = string | [string, Record<string, unknown>] | {
188
244
  path: string;
@@ -196,4 +252,4 @@ interface HadarsRequest extends Request {
196
252
  cookies: Record<string, string>;
197
253
  }
198
254
 
199
- export type { AppContext as A, HadarsEntryModule as H, HadarsOptions as a, HadarsApp as b, HadarsGetClientProps as c, HadarsGetFinalProps as d, HadarsGetInitialProps as e, HadarsProps as f, HadarsRequest as g };
255
+ export type { GraphQLExecutor as G, HadarsEntryModule as H, HadarsOptions as a, HadarsApp as b, HadarsGetClientProps as c, HadarsGetFinalProps as d, HadarsGetInitialProps as e, HadarsProps as f, HadarsRequest as g, HadarsSourceEntry as h, HadarsStaticContext as i };