htmx-router 1.0.0-pre1 → 1.0.0-pre2

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.
Files changed (66) hide show
  1. package/cli/config.d.ts +13 -0
  2. package/cli/config.js +11 -0
  3. package/cli/index.d.ts +2 -0
  4. package/cli/index.js +38 -0
  5. package/cookies.d.ts +29 -0
  6. package/cookies.js +80 -0
  7. package/css.d.ts +21 -0
  8. package/css.js +60 -0
  9. package/defer.d.ts +14 -0
  10. package/defer.js +80 -0
  11. package/endpoint.d.ts +20 -0
  12. package/endpoint.js +40 -0
  13. package/event-source.d.ts +26 -0
  14. package/event-source.js +116 -0
  15. package/index.d.ts +19 -0
  16. package/index.js +2 -0
  17. package/internal/client.d.ts +1 -0
  18. package/internal/client.js +14 -0
  19. package/internal/compile/manifest.d.ts +1 -0
  20. package/internal/compile/manifest.js +179 -0
  21. package/internal/component/defer.d.ts +4 -0
  22. package/internal/component/defer.js +19 -0
  23. package/internal/component/head.d.ts +5 -0
  24. package/internal/component/head.js +22 -0
  25. package/internal/component/index.d.ts +4 -0
  26. package/internal/component/index.js +4 -0
  27. package/internal/component/scripts.d.ts +4 -0
  28. package/internal/component/scripts.js +23 -0
  29. package/internal/mount.d.ts +10 -0
  30. package/internal/mount.js +88 -0
  31. package/internal/request/http.d.ts +10 -0
  32. package/internal/request/http.js +61 -0
  33. package/internal/request/index.d.ts +17 -0
  34. package/internal/request/index.js +8 -0
  35. package/internal/request/native.d.ts +9 -0
  36. package/internal/request/native.js +48 -0
  37. package/internal/router.d.ts +15 -0
  38. package/internal/router.js +24 -0
  39. package/internal/util.d.ts +4 -0
  40. package/internal/util.js +49 -0
  41. package/package.json +1 -1
  42. package/response.d.ts +13 -0
  43. package/response.js +46 -0
  44. package/router.d.ts +33 -0
  45. package/router.js +206 -0
  46. package/shell.d.ts +120 -0
  47. package/shell.js +261 -0
  48. package/util/parameters.d.ts +10 -0
  49. package/util/parameters.js +1 -0
  50. package/util/path-builder.d.ts +1 -0
  51. package/util/path-builder.js +45 -0
  52. package/util/route.d.ts +2 -0
  53. package/util/route.js +58 -0
  54. package/vite/bundle-splitter.d.ts +4 -0
  55. package/vite/bundle-splitter.js +26 -0
  56. package/vite/client-island.d.ts +4 -0
  57. package/vite/client-island.js +14 -0
  58. package/vite/index.d.ts +3 -0
  59. package/vite/index.js +3 -0
  60. package/vite/router.d.ts +2 -0
  61. package/vite/router.js +29 -0
  62. package/example/eventdim-react/package.json +0 -67
  63. package/example/eventdim-react/server.js +0 -90
  64. package/example/island-react/global.d.ts +0 -8
  65. package/example/island-react/package.json +0 -38
  66. package/example/island-react/server.js +0 -58
@@ -0,0 +1,13 @@
1
+ type Config = {
2
+ framework: string;
3
+ client?: {
4
+ source: string;
5
+ output: {
6
+ server: string;
7
+ client: string;
8
+ };
9
+ };
10
+ component?: Record<string, string>;
11
+ };
12
+ export declare function ReadConfig(): Promise<Config>;
13
+ export {};
package/cli/config.js ADDED
@@ -0,0 +1,11 @@
1
+ import { existsSync } from "fs";
2
+ import { readFile } from "fs/promises";
3
+ const DEFAULT = {
4
+ framework: "generic"
5
+ };
6
+ export async function ReadConfig() {
7
+ const path = process.argv[2] || "./htmx.config.json";
8
+ if (!existsSync(path))
9
+ return DEFAULT;
10
+ return JSON.parse(await readFile(path, "utf-8"));
11
+ }
package/cli/index.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/cli/index.js ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ import chalk from 'chalk';
4
+ import { readFile, writeFile } from "fs/promises";
5
+ import * as components from "../internal/component/index.js";
6
+ import { CompileManifest } from "../internal/compile/manifest.js";
7
+ import { ReadConfig } from "./config.js";
8
+ const config = await ReadConfig();
9
+ console.info("");
10
+ if (config.client) {
11
+ console.info(`Generating ${chalk.green("client island")} manifest`);
12
+ const source = await readFile(config.client.source, "utf8");
13
+ await writeFile(config.client.output.server, CompileManifest(config.framework, source, true));
14
+ console.log(` - ${chalk.cyan("server")} ${chalk.gray(config.client.output.server)}`);
15
+ await writeFile(config.client.output.client, CompileManifest(config.framework, source, false));
16
+ console.log(` - ${chalk.cyan("client")} ${chalk.gray(config.client.output.client)}`);
17
+ console.log("");
18
+ }
19
+ if (config.component) {
20
+ console.info(`Generating ${chalk.green("components")} for ${chalk.cyan(config.framework)}`);
21
+ const padding = Math.max(...Object.keys(config.component).map(x => x.length)) || 0;
22
+ for (const key in config.component) {
23
+ const prefix = ` - ${chalk.cyan(key)}` + " ".repeat(padding + 1 - key.length);
24
+ const component = components[key];
25
+ if (!component) {
26
+ console.log(prefix + chalk.red("unknown component"));
27
+ continue;
28
+ }
29
+ const source = component[config.framework] || component["*"];
30
+ if (!source) {
31
+ console.log(prefix + chalk.red("unable to find definition for ") + chalk.cyan(config.framework));
32
+ continue;
33
+ }
34
+ const output = config.component[key];
35
+ await writeFile(output, source);
36
+ console.log(prefix + chalk.gray(output));
37
+ }
38
+ }
package/cookies.d.ts ADDED
@@ -0,0 +1,29 @@
1
+ export interface CookieOptions {
2
+ domain?: string | undefined;
3
+ expires?: Date;
4
+ httpOnly?: boolean;
5
+ maxAge?: number;
6
+ partitioned?: boolean;
7
+ path?: string;
8
+ priority?: "low" | "medium" | "high";
9
+ sameSite?: "lax" | "strict" | "none";
10
+ secure?: boolean;
11
+ }
12
+ /**
13
+ * Helper provided in the Generic and RouteContext which provides reading and updating cookies
14
+ */
15
+ export declare class Cookies {
16
+ private source;
17
+ private config;
18
+ private map;
19
+ constructor(source?: Document | string | null);
20
+ private parse;
21
+ get(name: string): string | null;
22
+ entries(): Array<[string, string]>;
23
+ [Symbol.iterator](): IterableIterator<[string, string]>;
24
+ has(name: string): boolean;
25
+ set(name: string, value: string, options?: CookieOptions): void;
26
+ unset(name: string): void;
27
+ /** Creates the response headers required to make the changes done to these cookies */
28
+ export(): string[];
29
+ }
package/cookies.js ADDED
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Helper provided in the Generic and RouteContext which provides reading and updating cookies
3
+ */
4
+ export class Cookies {
5
+ source;
6
+ config;
7
+ map;
8
+ constructor(source) {
9
+ this.source = source || null;
10
+ this.config = {};
11
+ this.map = {};
12
+ }
13
+ parse() {
14
+ if (this.source === null)
15
+ return;
16
+ const source = typeof this.source === "object" ? this.source.cookie : this.source;
17
+ for (const line of source.split("; ")) {
18
+ const [name, value] = line.split("=");
19
+ this.map[name] = value;
20
+ }
21
+ // keep source it document
22
+ if (typeof this.source === "string")
23
+ this.source = null;
24
+ }
25
+ get(name) {
26
+ this.parse();
27
+ return this.map[name] || null;
28
+ }
29
+ entries() {
30
+ this.parse();
31
+ return Object.entries(this.map);
32
+ }
33
+ *[Symbol.iterator]() {
34
+ this.parse();
35
+ for (const [key, value] of Object.entries(this.map)) {
36
+ yield [key, value];
37
+ }
38
+ }
39
+ has(name) {
40
+ this.parse();
41
+ return name in this.map;
42
+ }
43
+ set(name, value, options = {}) {
44
+ this.parse();
45
+ options.path ||= "/";
46
+ this.config[name] = options;
47
+ this.map[name] = value;
48
+ if (typeof this.source === "object")
49
+ document.cookie = `${name}=${value}`;
50
+ }
51
+ unset(name) {
52
+ this.parse();
53
+ return this.set(name, "", { maxAge: 0 });
54
+ }
55
+ /** Creates the response headers required to make the changes done to these cookies */
56
+ export() {
57
+ const headers = new Array();
58
+ for (const name in this.config) {
59
+ let config = "";
60
+ for (const opt in this.config[name]) {
61
+ const prop = opt === "maxAge"
62
+ ? "Max-Age"
63
+ : opt[0].toUpperCase() + opt.slice(1);
64
+ const raw = this.config[name][opt];
65
+ if (raw === true) {
66
+ config += `; ${prop}`;
67
+ continue;
68
+ }
69
+ if (raw === false)
70
+ continue;
71
+ let value = String(raw);
72
+ value = value[0].toUpperCase() + value.slice(1);
73
+ config += `; ${prop}=${value}`;
74
+ }
75
+ const cookie = name + "=" + this.map[name] + config + ";";
76
+ headers.push(cookie);
77
+ }
78
+ return headers;
79
+ }
80
+ }
package/css.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ import { RouteContext } from "./index.js";
2
+ /**
3
+ * Create a new css class to be included in the sheet
4
+ * Use .this as your class name in the source, and it will be replaced with a unique name
5
+ */
6
+ export declare class Style {
7
+ readonly name: string;
8
+ readonly style: string;
9
+ readonly hash: string;
10
+ constructor(name: string, style: string);
11
+ toString(): string;
12
+ }
13
+ export declare function GetSheetUrl(): string;
14
+ /**
15
+ * RouteTree mounting point
16
+ */
17
+ export declare const path = "_/style/$hash";
18
+ export declare const parameters: {
19
+ hash: StringConstructor;
20
+ };
21
+ export declare function loader(ctx: RouteContext<typeof parameters>): Promise<Response | null>;
package/css.js ADDED
@@ -0,0 +1,60 @@
1
+ import { QuickHash } from "./internal/util.js";
2
+ const classNamePattern = /^[a-zA-Z_][a-zA-Z0-9_-]*$/;
3
+ const registry = new Map();
4
+ let cache = null;
5
+ /**
6
+ * Create a new css class to be included in the sheet
7
+ * Use .this as your class name in the source, and it will be replaced with a unique name
8
+ */
9
+ export class Style {
10
+ name; // unique name generated based on the original name and hash of the style
11
+ style; // the mutated source
12
+ hash;
13
+ constructor(name, style) {
14
+ if (!name.match(classNamePattern))
15
+ throw new Error("Cannot use given name for CSS class");
16
+ this.hash = QuickHash(style);
17
+ this.name = `${name}-${this.hash}`;
18
+ style = style.replaceAll(".this", "." + this.name);
19
+ this.style = style;
20
+ registry.set(this.name, this);
21
+ cache = null;
22
+ }
23
+ toString() {
24
+ return this.name;
25
+ }
26
+ }
27
+ function BuildSheet() {
28
+ let composite = "";
29
+ let sheet = "";
30
+ for (const [key, def] of registry) {
31
+ composite += key;
32
+ sheet += def.style;
33
+ }
34
+ const hash = QuickHash(composite);
35
+ cache = { hash, sheet };
36
+ return cache;
37
+ }
38
+ function GetSheet() {
39
+ return cache || BuildSheet();
40
+ }
41
+ export function GetSheetUrl() {
42
+ const sheet = GetSheet();
43
+ return `/_/style/${sheet.hash}.css`;
44
+ }
45
+ /**
46
+ * RouteTree mounting point
47
+ */
48
+ export const path = "_/style/$hash";
49
+ export const parameters = {
50
+ hash: String
51
+ };
52
+ export async function loader(ctx) {
53
+ const build = GetSheet();
54
+ if (!ctx.params.hash.startsWith(build.hash))
55
+ return null;
56
+ const headers = new Headers();
57
+ headers.set("Content-Type", "text/css");
58
+ headers.set("Cache-Control", "public, max-age=604800");
59
+ return new Response(build.sheet, { headers });
60
+ }
package/defer.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ import { Parameterized, Parameterizer, ParameterShaper } from "./util/parameters.js";
2
+ import { RenderFunction } from "./index.js";
3
+ import { RouteContext } from "./router.js";
4
+ export declare function RegisterDeferral<T extends ParameterShaper>(shape: T, func: RenderFunction<T>, converter?: Parameterizer<T>): string;
5
+ export declare function Deferral<T extends ParameterShaper>(func: RenderFunction<T>, params?: Parameterized<T>): string;
6
+ /**
7
+ * RouteTree mounting point
8
+ */
9
+ export declare const path = "_/defer/$";
10
+ export declare const parameters: {
11
+ $: StringConstructor;
12
+ };
13
+ export declare function loader(ctx: RouteContext<typeof parameters>): Promise<Response | null>;
14
+ export declare const action: typeof loader;
package/defer.js ADDED
@@ -0,0 +1,80 @@
1
+ import { ServerOnlyWarning } from "./internal/util.js";
2
+ ServerOnlyWarning("dynamic-ref");
3
+ import { RouteContext } from "./router.js";
4
+ import { QuickHash } from "./internal/util.js";
5
+ const registry = new Map();
6
+ const index = new Map();
7
+ function MakeIdentity(func) {
8
+ const hash = QuickHash(String(func));
9
+ const name = `${encodeURIComponent(func.name)}-${hash}`;
10
+ const url = `/_/defer/${name}`;
11
+ return { name, url };
12
+ }
13
+ export function RegisterDeferral(shape, func, converter) {
14
+ const existing = index.get(func);
15
+ if (existing)
16
+ return existing.url;
17
+ const { url, name } = MakeIdentity(func);
18
+ registry.set(name, func);
19
+ index.set(func, { url, shape, converter });
20
+ return url;
21
+ }
22
+ export function Deferral(func, params) {
23
+ const entry = index.get(func);
24
+ let url;
25
+ if (!entry) {
26
+ const identity = MakeIdentity(func);
27
+ console.warn(`Warn: Function ${identity.name} has not registered before use`);
28
+ url = identity.url;
29
+ }
30
+ else {
31
+ url = entry.url;
32
+ }
33
+ if (!params)
34
+ return url;
35
+ const query = new URLSearchParams();
36
+ if (entry?.converter) {
37
+ const convert = entry.converter;
38
+ for (const key in convert) {
39
+ if (!(key in params))
40
+ throw new Error(`Missing parameter ${key}`);
41
+ const raw = params[key];
42
+ const str = convert[key](raw);
43
+ query.set(key, str);
44
+ }
45
+ }
46
+ else {
47
+ for (const key in params)
48
+ query.set(key, String(params[key]));
49
+ }
50
+ return url + "?" + query.toString();
51
+ }
52
+ /**
53
+ * RouteTree mounting point
54
+ */
55
+ export const path = "_/defer/$";
56
+ export const parameters = {
57
+ "$": String
58
+ };
59
+ export async function loader(ctx) {
60
+ const endpoint = registry.get(ctx.params["$"]);
61
+ if (!endpoint)
62
+ return null;
63
+ const prelude = {};
64
+ for (const [key, value] of ctx.url.searchParams)
65
+ prelude[key] = value;
66
+ const entry = index.get(endpoint);
67
+ if (!entry) {
68
+ console.warn(`Warn: Function ${endpoint.name} was not registered for defer use`);
69
+ return null;
70
+ }
71
+ const forward = new RouteContext(ctx, prelude, entry.shape);
72
+ const res = await endpoint(forward);
73
+ if (res instanceof Response)
74
+ return res;
75
+ if (res === null)
76
+ return null;
77
+ ctx.headers.set("X-Partial", "true");
78
+ return ctx.render(res);
79
+ }
80
+ export const action = loader;
package/endpoint.d.ts ADDED
@@ -0,0 +1,20 @@
1
+ import type { RenderFunction, RouteContext } from "./index.js";
2
+ /**
3
+ * Create a route-less endpoint
4
+ * The name is optional and will be inferred from the function if not given (helpful for network waterfalls)
5
+ */
6
+ export declare class Endpoint {
7
+ readonly render: RenderFunction<{}>;
8
+ readonly name: string;
9
+ readonly url: string;
10
+ constructor(render: RenderFunction<{}>, name?: string);
11
+ }
12
+ /**
13
+ * RouteTree mounting point
14
+ */
15
+ export declare const path = "_/endpoint/$";
16
+ export declare const parameters: {
17
+ $: StringConstructor;
18
+ };
19
+ export declare function loader(ctx: RouteContext<typeof parameters>): Promise<Response | null>;
20
+ export declare const action: typeof loader;
package/endpoint.js ADDED
@@ -0,0 +1,40 @@
1
+ import { ServerOnlyWarning } from "./internal/util.js";
2
+ ServerOnlyWarning("endpoint");
3
+ import { QuickHash } from "./internal/util.js";
4
+ const registry = new Map();
5
+ /**
6
+ * Create a route-less endpoint
7
+ * The name is optional and will be inferred from the function if not given (helpful for network waterfalls)
8
+ */
9
+ export class Endpoint {
10
+ render;
11
+ name;
12
+ url;
13
+ constructor(render, name) {
14
+ this.render = render;
15
+ name ||= render.name;
16
+ const hash = QuickHash(String(render));
17
+ this.name = name ? `${encodeURIComponent(name)}-${hash}` : hash;
18
+ this.url = `/_/endpoint/${this.name}`;
19
+ registry.set(this.name, this);
20
+ }
21
+ }
22
+ /**
23
+ * RouteTree mounting point
24
+ */
25
+ export const path = "_/endpoint/$";
26
+ export const parameters = {
27
+ "$": String
28
+ };
29
+ export async function loader(ctx) {
30
+ const endpoint = registry.get(ctx.params["$"]);
31
+ if (!endpoint)
32
+ return null;
33
+ const res = await endpoint.render(ctx);
34
+ if (res === null)
35
+ return null;
36
+ if (res instanceof Response)
37
+ return res;
38
+ return ctx.render(res);
39
+ }
40
+ export const action = loader;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Helper for Server-Sent-Events, with auto close on SIGTERM and SIGHUP messages
3
+ * Includes a keep alive empty packet sent every 30sec (because Chrome implodes at 120sec, and can be unreliable at 60sec)
4
+ */
5
+ export declare class EventSource {
6
+ private controller;
7
+ private timer;
8
+ private state;
9
+ readonly response: Response;
10
+ readonly url: string;
11
+ constructor(request: Request, keepAlive?: number);
12
+ get readyState(): number;
13
+ private sendBytes;
14
+ private sendText;
15
+ private keepAlive;
16
+ dispatch(type: string, data: string): boolean;
17
+ close(unlink?: boolean): boolean;
18
+ }
19
+ export declare class EventSourceSet extends Set<EventSource> {
20
+ /** Send update to all EventSources, auto closing failed dispatches */
21
+ dispatch(type: string, data: string): void;
22
+ /** Cull all closed connections */
23
+ cull(): void;
24
+ /** Close all connections */
25
+ closeAll(): void;
26
+ }
@@ -0,0 +1,116 @@
1
+ import { ServerOnlyWarning } from "./internal/util.js";
2
+ ServerOnlyWarning("event-source");
3
+ /**
4
+ * Helper for Server-Sent-Events, with auto close on SIGTERM and SIGHUP messages
5
+ * Includes a keep alive empty packet sent every 30sec (because Chrome implodes at 120sec, and can be unreliable at 60sec)
6
+ */
7
+ export class EventSource {
8
+ controller;
9
+ timer;
10
+ state;
11
+ response;
12
+ url; // just to make it polyfill
13
+ constructor(request, keepAlive = 30_000) {
14
+ this.controller = null;
15
+ this.state = 0;
16
+ this.url = request.url;
17
+ const stream = new ReadableStream({
18
+ start: (c) => { this.controller = c; this.state = 1; },
19
+ cancel: () => { this.close(); }
20
+ });
21
+ request.signal.addEventListener('abort', () => this.close());
22
+ this.response = new Response(stream, { headers });
23
+ this.timer = setInterval(() => this.keepAlive(), keepAlive);
24
+ register.add(this);
25
+ }
26
+ get readyState() {
27
+ return this.state;
28
+ }
29
+ sendBytes(chunk) {
30
+ if (!this.controller)
31
+ return false;
32
+ try {
33
+ this.controller.enqueue(chunk);
34
+ return true;
35
+ }
36
+ catch (e) {
37
+ console.error(e);
38
+ this.close(); // unbind on failure
39
+ return false;
40
+ }
41
+ }
42
+ sendText(chunk) {
43
+ return this.sendBytes(encoder.encode(chunk));
44
+ }
45
+ keepAlive() {
46
+ return this.sendText("\n\n");
47
+ }
48
+ dispatch(type, data) {
49
+ return this.sendText(`event: ${type}\ndata: ${data}\n\n`);
50
+ }
51
+ close(unlink = true) {
52
+ if (this.state === 2)
53
+ return false;
54
+ if (unlink)
55
+ register.delete(this);
56
+ try {
57
+ this.controller?.close();
58
+ }
59
+ catch (e) {
60
+ console.error(e);
61
+ this.controller = null;
62
+ return false;
63
+ }
64
+ // Cleanup
65
+ if (this.timer)
66
+ clearInterval(this.timer);
67
+ this.controller = null;
68
+ this.state = 2;
69
+ return true;
70
+ }
71
+ }
72
+ export class EventSourceSet extends Set {
73
+ /** Send update to all EventSources, auto closing failed dispatches */
74
+ dispatch(type, data) {
75
+ for (const stream of this) {
76
+ if (stream.readyState === 0)
77
+ continue; // skip initializing
78
+ const success = stream.dispatch(type, data);
79
+ if (!success)
80
+ this.delete(stream);
81
+ }
82
+ }
83
+ /** Cull all closed connections */
84
+ cull() {
85
+ for (const stream of this) {
86
+ if (stream.readyState !== 2)
87
+ continue;
88
+ this.delete(stream);
89
+ }
90
+ }
91
+ /** Close all connections */
92
+ closeAll() {
93
+ for (const stream of this)
94
+ stream.close();
95
+ this.clear();
96
+ }
97
+ }
98
+ // global for easy reuse
99
+ const encoder = new TextEncoder();
100
+ const headers = new Headers();
101
+ // Chunked encoding with immediate forwarding by proxies (i.e. nginx)
102
+ headers.set("X-Accel-Buffering", "no");
103
+ headers.set("Transfer-Encoding", "chunked");
104
+ headers.set("Content-Type", "text/event-stream");
105
+ headers.set("Keep-Alive", "timeout=120"); // the maximum keep alive chrome shouldn't ignore
106
+ headers.set("Connection", "keep-alive");
107
+ // Auto close all SSE streams when shutdown requested
108
+ // Without this graceful shutdowns will hang indefinitely
109
+ const register = new EventSourceSet();
110
+ function CloseAll() {
111
+ register.closeAll();
112
+ }
113
+ if (process) {
114
+ process.on('SIGTERM', CloseAll);
115
+ process.on('SIGTERM', CloseAll);
116
+ }
package/index.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import type { ParameterShaper } from "./util/parameters.js";
2
+ import type { RouteContext } from "./router.js";
3
+ import { createRequestHandler } from "./internal/request/index.js";
4
+ export type RenderFunction<T extends ParameterShaper = {}> = (ctx: RouteContext<T>) => Promise<Response | JSX.Element | null>;
5
+ export type CatchFunction<T extends ParameterShaper = {}> = (ctx: RouteContext<T>, err: unknown) => Promise<Response | JSX.Element>;
6
+ export type RouteModule<T extends ParameterShaper> = {
7
+ parameters?: T;
8
+ loader?: RenderFunction<T>;
9
+ action?: RenderFunction<T>;
10
+ error?: CatchFunction<T>;
11
+ route?: (params: Record<string, string>) => string;
12
+ };
13
+ export type ClientIslandManifest<T> = {
14
+ [K in keyof T]: ClientIsland<T[K]>;
15
+ };
16
+ type ClientIsland<T> = T extends (props: infer P) => JSX.Element ? (props: P & {
17
+ children?: JSX.Element;
18
+ }) => JSX.Element : T;
19
+ export { createRequestHandler, RouteContext };
package/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import { createRequestHandler } from "./internal/request/index.js";
2
+ export { createRequestHandler };
@@ -0,0 +1 @@
1
+ export declare function GetClientEntryURL(): Promise<string | undefined>;
@@ -0,0 +1,14 @@
1
+ import { ServerOnlyWarning } from "./util.js";
2
+ ServerOnlyWarning("client-url");
3
+ import { readFile } from "fs/promises";
4
+ export async function GetClientEntryURL() {
5
+ if (process.env.NODE_ENV !== "production")
6
+ return "/app/entry.client.ts";
7
+ const config = JSON.parse(await readFile("./dist/client/.vite/manifest.json", "utf8"));
8
+ for (const key in config) {
9
+ const def = config[key];
10
+ if (!def.isEntry)
11
+ continue;
12
+ return "/" + def.file;
13
+ }
14
+ }
@@ -0,0 +1 @@
1
+ export declare function CompileManifest(adapter: string, source: string, ssr: boolean): string;