foldkit 0.145.0 → 0.147.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.
- package/README.md +5 -2
- package/dist/customElement/index.d.ts.map +1 -1
- package/dist/customElement/index.js +23 -0
- package/dist/experimental/index.d.ts +1 -0
- package/dist/experimental/index.d.ts.map +1 -1
- package/dist/experimental/index.js +1 -0
- package/dist/experimental/machine/machine.d.ts +22 -3
- package/dist/experimental/machine/machine.d.ts.map +1 -1
- package/dist/experimental/machine/machine.js +8 -0
- package/dist/experimental/server/entry.d.ts +73 -0
- package/dist/experimental/server/entry.d.ts.map +1 -0
- package/dist/experimental/server/entry.js +41 -0
- package/dist/experimental/server/host.d.ts +42 -0
- package/dist/experimental/server/host.d.ts.map +1 -0
- package/dist/experimental/server/host.js +169 -0
- package/dist/experimental/server/index.d.ts +5 -0
- package/dist/experimental/server/index.d.ts.map +1 -0
- package/dist/experimental/server/index.js +4 -0
- package/dist/experimental/server/public.d.ts +3 -0
- package/dist/experimental/server/public.d.ts.map +1 -0
- package/dist/experimental/server/public.js +1 -0
- package/dist/experimental/server/serialize.d.ts +33 -0
- package/dist/experimental/server/serialize.d.ts.map +1 -0
- package/dist/experimental/server/serialize.js +563 -0
- package/dist/experimental/server/server.d.ts +201 -0
- package/dist/experimental/server/server.d.ts.map +1 -0
- package/dist/experimental/server/server.js +423 -0
- package/dist/experimental/server/template.d.ts +45 -0
- package/dist/experimental/server/template.d.ts.map +1 -0
- package/dist/experimental/server/template.js +182 -0
- package/dist/html/index.d.ts +5 -0
- package/dist/html/index.d.ts.map +1 -1
- package/dist/html/index.js +38 -4
- package/dist/hydrate.d.ts +4 -0
- package/dist/hydrate.d.ts.map +1 -0
- package/dist/hydrate.js +522 -0
- package/dist/hydrationMarker.d.ts +10 -0
- package/dist/hydrationMarker.d.ts.map +1 -0
- package/dist/hydrationMarker.js +9 -0
- package/dist/mount/index.d.ts +1 -1
- package/dist/runtime/public.d.ts +2 -2
- package/dist/runtime/public.d.ts.map +1 -1
- package/dist/runtime/public.js +1 -1
- package/dist/runtime/runtime.d.ts +75 -36
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +209 -71
- package/dist/snabbdom/h.d.ts +1 -0
- package/dist/snabbdom/h.d.ts.map +1 -1
- package/dist/snabbdom/h.js +85 -4
- package/dist/snabbdom/tovnode.d.ts.map +1 -1
- package/dist/snabbdom/tovnode.js +5 -1
- package/dist/tagName.d.ts +6 -0
- package/dist/tagName.d.ts.map +1 -0
- package/dist/tagName.js +11 -0
- package/dist/vdom.d.ts.map +1 -1
- package/dist/vdom.js +25 -1
- package/package.json +11 -4
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
-
Foldkit is a TypeScript frontend framework built on [Effect](https://effect.website/) and architected like [Elm](https://guide.elm-lang.org/architecture/). One Model, one update function, one way to do things. No hooks, no local state, no hidden mutations. It's all in on Effect with no escape hatch, though a program doesn't have to own the whole page: [`Runtime.embed`](https://foldkit.dev/core/embedding) runs a Foldkit widget inside any existing app, React included.
|
|
21
|
+
Foldkit is a TypeScript frontend framework built on [Effect](https://effect.website/) and architected like [Elm](https://guide.elm-lang.org/architecture/). One Model, one update function, one way to do things. No hooks, no local state, no hidden mutations. It's all in on Effect with no escape hatch, though a program doesn't have to own the whole page: [`Runtime.embed`](https://foldkit.dev/core/embedding) runs a Foldkit widget inside any existing app, React included. The same program also [renders on the server](https://foldkit.dev/core/server-rendering), at build time or per request, and hydrates in place.
|
|
22
22
|
|
|
23
23
|
Your Model is a [Schema](https://effect.website/docs/schema/introduction/) and side effects are values you return, not callbacks you fire. If you know Effect, Foldkit feels natural. If you're new to it, Foldkit is a good way in. Coming from React? [Start here](https://foldkit.dev/react/coming-from-react), or read the [same pixel-art editor built in both frameworks](https://foldkit.dev/react/foldkit-vs-react-side-by-side).
|
|
24
24
|
|
|
@@ -27,7 +27,7 @@ Your Model is a [Schema](https://effect.website/docs/schema/introduction/) and s
|
|
|
27
27
|
|
|
28
28
|
## Get Started
|
|
29
29
|
|
|
30
|
-
`create-foldkit-app` scaffolds a complete setup with Tailwind, TypeScript, [Oxlint](https://foldkit.dev/tooling/oxlint-plugin), Prettier, and the Vite plugin for state-preserving HMR,
|
|
30
|
+
`create-foldkit-app` scaffolds a complete setup with Tailwind, TypeScript, [Oxlint](https://foldkit.dev/tooling/oxlint-plugin), Prettier, and the Vite plugin for state-preserving HMR. Pick a rendering mode (browser-only SPA, static generation, or server rendering) and, for a SPA, the example to start from.
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
33
|
npx create-foldkit-app@latest
|
|
@@ -137,6 +137,7 @@ A complete system, not a collection of libraries you stitch together. Each of th
|
|
|
137
137
|
- **UI Components**: Accessible, keyboard-friendly primitives in the `@foldkit/ui` package.
|
|
138
138
|
- **Field Validation**: Per-field validation state modeled as a discriminated union.
|
|
139
139
|
- **Virtual DOM**: Declarative views with lazy memoization and keyed diffing, powered by [Snabbdom](https://github.com/snabbdom/snabbdom).
|
|
140
|
+
- **Server Rendering**: The same program rendered to HTML at build time (SSG) or per request (SSR), then hydrated in place.
|
|
140
141
|
- **DevTools**: In-browser overlay for inspecting Messages, Model, and Commands, with time-travel.
|
|
141
142
|
- **DevTools MCP**: Expose a running app to AI agents over the Model Context Protocol.
|
|
142
143
|
- **Crash View and Reporting**: A custom fallback UI when the update loop throws, plus a report callback.
|
|
@@ -169,6 +170,8 @@ Some of what you can build with Foldkit. [See all example apps on foldkit.dev](h
|
|
|
169
170
|
- **[Kanban](https://foldkit.dev/example-apps/kanban)**: Drag-and-drop kanban board with cross-column reordering and keyboard navigation
|
|
170
171
|
- **[Pixel Art](https://foldkit.dev/example-apps/pixel-art)**: Grid-based pixel editor with painting, erasing, and palette selection
|
|
171
172
|
- **[UI Showcase](https://foldkit.dev/example-apps/ui-showcase)**: Interactive showcase of every Foldkit UI component
|
|
173
|
+
- **[Static Site Generation](https://foldkit.dev/example-apps/ssg)**: Build-time prerendering with client hydration
|
|
174
|
+
- **[Server-Side Rendering](https://foldkit.dev/example-apps/ssr)**: Per-request rendering on an Effect HttpServer with cookie-derived Flags
|
|
172
175
|
- **[Typing Game](https://github.com/foldkit/foldkit/tree/main/packages/typing-game)**: Multiplayer typing game with Effect RPC backend ([play it live](https://typingterminal.com))
|
|
173
176
|
|
|
174
177
|
## License
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/customElement/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/customElement/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,23 @@ import { OnCustomEvent, Prop, customElement as customElementVNode, } from '../ht
|
|
|
4
4
|
* the same `On*` factory this module generates. */
|
|
5
5
|
export const kebabToPascal = (input) => pipe(input, String.split('-'), Array.map(String.capitalize), Array.join(''));
|
|
6
6
|
const IDENTIFIER_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
7
|
+
// A conservative subset of the custom-element name grammar: lowercase start,
|
|
8
|
+
// then only characters that cannot carry markup. The hyphen requirement is
|
|
9
|
+
// checked separately so its message stays specific.
|
|
10
|
+
const CUSTOM_ELEMENT_NAME_PATTERN = /^[a-z][a-z0-9._-]*$/;
|
|
11
|
+
// Hyphenated names the custom-element spec reserves for SVG and MathML, which
|
|
12
|
+
// `customElements.define` rejects with a SyntaxError. They pass the character
|
|
13
|
+
// grammar, so they are excluded by name.
|
|
14
|
+
const RESERVED_CUSTOM_ELEMENT_NAMES = new Set([
|
|
15
|
+
'annotation-xml',
|
|
16
|
+
'color-profile',
|
|
17
|
+
'font-face',
|
|
18
|
+
'font-face-src',
|
|
19
|
+
'font-face-uri',
|
|
20
|
+
'font-face-format',
|
|
21
|
+
'font-face-name',
|
|
22
|
+
'missing-glyph',
|
|
23
|
+
]);
|
|
7
24
|
const isValidPropertyName = (name) => IDENTIFIER_PATTERN.test(name);
|
|
8
25
|
const isValidEventName = (name) => {
|
|
9
26
|
if (String.isEmpty(name)) {
|
|
@@ -95,6 +112,12 @@ const validateNames = (input) => {
|
|
|
95
112
|
if (!input.tag.includes('-')) {
|
|
96
113
|
throw new Error(`${context}: tag '${input.tag}' is not a valid custom element name. Autonomous custom elements must contain at least one hyphen (e.g. 'fk-emoji-rating').`);
|
|
97
114
|
}
|
|
115
|
+
if (!CUSTOM_ELEMENT_NAME_PATTERN.test(input.tag)) {
|
|
116
|
+
throw new Error(`${context}: tag '${input.tag}' is not a valid custom element name. Names must be lowercase, start with a letter, and use only letters, numbers, hyphens, dots, and underscores.`);
|
|
117
|
+
}
|
|
118
|
+
if (RESERVED_CUSTOM_ELEMENT_NAMES.has(input.tag)) {
|
|
119
|
+
throw new Error(`${context}: tag '${input.tag}' is a reserved custom element name that the browser rejects.`);
|
|
120
|
+
}
|
|
98
121
|
for (const propertyName of input.propertyNames) {
|
|
99
122
|
if (!isValidPropertyName(propertyName)) {
|
|
100
123
|
throw new Error(`${context}: property name '${propertyName}' is not a valid JS identifier.`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/experimental/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/experimental/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAA;AAC7C,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAA"}
|
|
@@ -63,6 +63,8 @@ type GuardValueOf<GuardResult> = [GuardResult] extends [boolean] ? void : Option
|
|
|
63
63
|
* from the table, and Messages absent from a state's `on` record, are
|
|
64
64
|
* ignored: {@link Machine.step} reports them as `Ignored` rather than
|
|
65
65
|
* transitioning.
|
|
66
|
+
*
|
|
67
|
+
* @experimental Ships from `foldkit/experimental/machine`; expect breaking changes while the API settles.
|
|
66
68
|
*/
|
|
67
69
|
export type TransitionTable<State extends Tagged, Message extends Tagged, R = never> = Readonly<{
|
|
68
70
|
[SourceTag in TagOf<State>]?: Readonly<{
|
|
@@ -83,6 +85,8 @@ export type TransitionTable<State extends Tagged, Message extends Tagged, R = ne
|
|
|
83
85
|
*
|
|
84
86
|
* Only meaningful inside a {@link TransitionTable}: the source and trigger
|
|
85
87
|
* types flow in from the table position contextually.
|
|
88
|
+
*
|
|
89
|
+
* @experimental Ships from `foldkit/experimental/machine`; expect breaking changes while the API settles.
|
|
86
90
|
*/
|
|
87
91
|
export declare const to: <State extends Tagged, Message extends Tagged, SourceState extends State, TriggerMessage extends Message, const TargetTag extends TagOf<State>, R = never>(target: TargetTag, build: (input: NoInfer<EdgeInput<SourceState, TriggerMessage>>) => NoInfer<Variant<State, TargetTag>>, commands?: (input: NoInfer<EdgeInput<SourceState, TriggerMessage>>) => ReadonlyArray<Command<NoInfer<Message>, never, R>>) => Edge<State, Message, SourceState, TriggerMessage, void, R>;
|
|
88
92
|
/**
|
|
@@ -95,12 +99,16 @@ export declare const to: <State extends Tagged, Message extends Tagged, SourceSt
|
|
|
95
99
|
*
|
|
96
100
|
* The state and Message parameters are `NoInfer` so they resolve from the
|
|
97
101
|
* guard list's table position alone.
|
|
102
|
+
*
|
|
103
|
+
* @experimental Ships from `foldkit/experimental/machine`; expect breaking changes while the API settles.
|
|
98
104
|
*/
|
|
99
105
|
export declare const when: <State extends Tagged, Message extends Tagged, SourceState extends State, TriggerMessage extends Message, GuardResult extends Option.Option<unknown> | boolean, const TargetTag extends TagOf<State>, R = never>(guard: (state: NoInfer<SourceState>, message: NoInfer<TriggerMessage>) => GuardResult, target: TargetTag, build: (input: NoInfer<EdgeInput<SourceState, TriggerMessage, GuardValueOf<GuardResult>>>) => NoInfer<Variant<State, TargetTag>>, commands?: (input: NoInfer<EdgeInput<SourceState, TriggerMessage, GuardValueOf<GuardResult>>>) => ReadonlyArray<Command<NoInfer<Message>, never, R>>) => When<State, Message, SourceState, TriggerMessage, GuardValueOf<GuardResult>, R>;
|
|
100
106
|
/**
|
|
101
107
|
* The unconditional fallback at the end of a guard list. Its edge may carry
|
|
102
108
|
* Commands whose Effects need services, threading their requirements into the
|
|
103
109
|
* Machine's `R` the same way {@link to} and {@link when} do.
|
|
110
|
+
*
|
|
111
|
+
* @experimental Ships from `foldkit/experimental/machine`; expect breaking changes while the API settles.
|
|
104
112
|
*/
|
|
105
113
|
export declare const otherwise: <State extends Tagged, Message extends Tagged, SourceState extends State, TriggerMessage extends Message, R = never>(edge: Edge<State, Message, SourceState, TriggerMessage, void, R>) => Otherwise<State, Message, SourceState, TriggerMessage, R>;
|
|
106
114
|
/** A step that matched an Edge: the next state plus any transition-time Commands. */
|
|
@@ -119,7 +127,10 @@ export type Ignored<State extends Tagged, Message extends Tagged> = Readonly<{
|
|
|
119
127
|
messageTag: TagOf<Message>;
|
|
120
128
|
state: State;
|
|
121
129
|
}>;
|
|
122
|
-
/** The observable outcome of one step: `Transitioned` or `Ignored`.
|
|
130
|
+
/** The observable outcome of one step: `Transitioned` or `Ignored`.
|
|
131
|
+
*
|
|
132
|
+
* @experimental Ships from `foldkit/experimental/machine`; expect breaking changes while the API settles.
|
|
133
|
+
*/
|
|
123
134
|
export type TransitionResult<State extends Tagged, Message extends Tagged, R = never> = Transitioned<State, Message, R> | Ignored<State, Message>;
|
|
124
135
|
/** Which guard construct an Edge sits under, with its position in the guard list. */
|
|
125
136
|
export type EdgeGuard = Readonly<{
|
|
@@ -145,7 +156,10 @@ export type DeadTransition<State extends Tagged, Message extends Tagged> = Reado
|
|
|
145
156
|
edge: EdgeSummary<State, Message>;
|
|
146
157
|
reason: DeadTransitionReason;
|
|
147
158
|
}>;
|
|
148
|
-
/** A compiled state Machine: a pure transition function plus static analysis over the Edge set.
|
|
159
|
+
/** A compiled state Machine: a pure transition function plus static analysis over the Edge set.
|
|
160
|
+
*
|
|
161
|
+
* @experimental Ships from `foldkit/experimental/machine`; expect breaking changes while the API settles.
|
|
162
|
+
*/
|
|
149
163
|
export type Machine<State extends Tagged, Message extends Tagged, R = never> = Readonly<{
|
|
150
164
|
initial: State;
|
|
151
165
|
stateTags: ReadonlyArray<TagOf<State>>;
|
|
@@ -171,7 +185,10 @@ export type MachineSchemas<State extends Tagged, Message extends Tagged> = Reado
|
|
|
171
185
|
Type: Message;
|
|
172
186
|
}>;
|
|
173
187
|
}>;
|
|
174
|
-
/** The Machine definition: the initial state and the transition table.
|
|
188
|
+
/** The Machine definition: the initial state and the transition table.
|
|
189
|
+
*
|
|
190
|
+
* @experimental Ships from `foldkit/experimental/machine`; expect breaking changes while the API settles.
|
|
191
|
+
*/
|
|
175
192
|
export type MachineDefinition<State extends Tagged, Message extends Tagged, R = never> = Readonly<{
|
|
176
193
|
initial: State;
|
|
177
194
|
states: TransitionTable<State, Message, R>;
|
|
@@ -216,6 +233,8 @@ export type MachineDefinition<State extends Tagged, Message extends Tagged, R =
|
|
|
216
233
|
* })
|
|
217
234
|
* // machine.transition(...) returns Commands typed with UploadsClient in R.
|
|
218
235
|
* ```
|
|
236
|
+
*
|
|
237
|
+
* @experimental Ships from `foldkit/experimental/machine`; expect breaking changes while the API settles.
|
|
219
238
|
*/
|
|
220
239
|
export declare const define: <State extends Tagged, Message extends Tagged>(schemas: MachineSchemas<State, Message>) => <R = never>(definition: MachineDefinition<State, Message, R>) => Machine<State, Message, R>;
|
|
221
240
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../../src/experimental/machine/machine.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../../src/experimental/machine/machine.ts"],"names":[],"mappings":"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"}
|
|
@@ -25,6 +25,8 @@ const makeEdge = (target, build, commands) => {
|
|
|
25
25
|
*
|
|
26
26
|
* Only meaningful inside a {@link TransitionTable}: the source and trigger
|
|
27
27
|
* types flow in from the table position contextually.
|
|
28
|
+
*
|
|
29
|
+
* @experimental Ships from `foldkit/experimental/machine`; expect breaking changes while the API settles.
|
|
28
30
|
*/
|
|
29
31
|
export const to = (target, build, commands) => makeEdge(target, build, commands);
|
|
30
32
|
/**
|
|
@@ -37,6 +39,8 @@ export const to = (target, build, commands) => makeEdge(target, build, commands)
|
|
|
37
39
|
*
|
|
38
40
|
* The state and Message parameters are `NoInfer` so they resolve from the
|
|
39
41
|
* guard list's table position alone.
|
|
42
|
+
*
|
|
43
|
+
* @experimental Ships from `foldkit/experimental/machine`; expect breaking changes while the API settles.
|
|
40
44
|
*/
|
|
41
45
|
export const when = (guard, target, build, commands) => ({
|
|
42
46
|
_tag: 'When',
|
|
@@ -55,6 +59,8 @@ export const when = (guard, target, build, commands) => ({
|
|
|
55
59
|
* The unconditional fallback at the end of a guard list. Its edge may carry
|
|
56
60
|
* Commands whose Effects need services, threading their requirements into the
|
|
57
61
|
* Machine's `R` the same way {@link to} and {@link when} do.
|
|
62
|
+
*
|
|
63
|
+
* @experimental Ships from `foldkit/experimental/machine`; expect breaking changes while the API settles.
|
|
58
64
|
*/
|
|
59
65
|
export const otherwise = (edge) => ({
|
|
60
66
|
_tag: 'Otherwise',
|
|
@@ -114,6 +120,8 @@ const extractMemberTag = (member) => pipe(Option.some(member), Option.filter(Pre
|
|
|
114
120
|
* })
|
|
115
121
|
* // machine.transition(...) returns Commands typed with UploadsClient in R.
|
|
116
122
|
* ```
|
|
123
|
+
*
|
|
124
|
+
* @experimental Ships from `foldkit/experimental/machine`; expect breaking changes while the API settles.
|
|
117
125
|
*/
|
|
118
126
|
export const define = (schemas) => (definition) => {
|
|
119
127
|
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { RenderedApplication } from './server.js';
|
|
2
|
+
import { type InjectIntoTemplateOptions } from './template.js';
|
|
3
|
+
/** Optional HTTP metadata for a rendered application.
|
|
4
|
+
*
|
|
5
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
6
|
+
*/
|
|
7
|
+
export type ResponseOptions = Readonly<{
|
|
8
|
+
status?: number;
|
|
9
|
+
headers?: HeadersInit;
|
|
10
|
+
}>;
|
|
11
|
+
/** A server entry result whose application markup still needs to be placed in
|
|
12
|
+
* the host's HTML template.
|
|
13
|
+
*
|
|
14
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
15
|
+
*/
|
|
16
|
+
export type Rendered = Readonly<{
|
|
17
|
+
_tag: 'Rendered';
|
|
18
|
+
application: RenderedApplication;
|
|
19
|
+
status?: number;
|
|
20
|
+
headers?: HeadersInit;
|
|
21
|
+
}>;
|
|
22
|
+
/** Constructs a rendered server entry result with optional HTTP status and
|
|
23
|
+
* headers.
|
|
24
|
+
*
|
|
25
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
26
|
+
*/
|
|
27
|
+
export declare const Rendered: (application: RenderedApplication, options?: ResponseOptions) => Rendered;
|
|
28
|
+
/** A server entry result that bypasses application rendering and returns a
|
|
29
|
+
* complete Web `Response`, such as a redirect or another non-page response to
|
|
30
|
+
* a page request. A dedicated data API belongs on a separate backend rather
|
|
31
|
+
* than the render host; this is for responses the page request itself
|
|
32
|
+
* resolves without rendering the shell.
|
|
33
|
+
*
|
|
34
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
35
|
+
*/
|
|
36
|
+
export type Responded = Readonly<{
|
|
37
|
+
_tag: 'Responded';
|
|
38
|
+
response: Response;
|
|
39
|
+
}>;
|
|
40
|
+
/** Constructs a complete Web `Response` server entry result.
|
|
41
|
+
*
|
|
42
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
43
|
+
*/
|
|
44
|
+
export declare const Responded: (response: Response) => Responded;
|
|
45
|
+
/** The result of handling one request through a Foldkit server entry.
|
|
46
|
+
*
|
|
47
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
48
|
+
*/
|
|
49
|
+
export type EntryResult = Rendered | Responded;
|
|
50
|
+
/** The module shape a Foldkit server entry exports for hosts to call: one Web
|
|
51
|
+
* `Request` in, one delivery result out.
|
|
52
|
+
*
|
|
53
|
+
* The outer boundary is a `Promise` so Vite, build scripts, serverless
|
|
54
|
+
* functions, and long-running HTTP hosts can call it without owning the
|
|
55
|
+
* application's Effect requirements. The entry may use Effect internally and
|
|
56
|
+
* settles that work before returning. Rendering itself must run in the same
|
|
57
|
+
* Foldkit module instance as the application's view because the HTML builder's
|
|
58
|
+
* render frame is module-local.
|
|
59
|
+
*
|
|
60
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
61
|
+
*/
|
|
62
|
+
export type EntryModule = Readonly<{
|
|
63
|
+
renderPage: (request: Request) => Promise<EntryResult>;
|
|
64
|
+
}>;
|
|
65
|
+
/** Turns a server entry result into the Web `Response` a host sends. Rendered
|
|
66
|
+
* applications are injected into the supplied template and default to status
|
|
67
|
+
* 200 with a UTF-8 HTML content type. Complete responses pass through
|
|
68
|
+
* unchanged.
|
|
69
|
+
*
|
|
70
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
71
|
+
*/
|
|
72
|
+
export declare const toResponse: (template: string, result: EntryResult, options?: InjectIntoTemplateOptions) => Response;
|
|
73
|
+
//# sourceMappingURL=entry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../../../src/experimental/server/entry.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AACtD,OAAO,EACL,KAAK,yBAAyB,EAE/B,MAAM,eAAe,CAAA;AAEtB;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,WAAW,CAAA;CACtB,CAAC,CAAA;AAEF;;;;GAIG;AACH,MAAM,MAAM,QAAQ,GAAG,QAAQ,CAAC;IAC9B,IAAI,EAAE,UAAU,CAAA;IAChB,WAAW,EAAE,mBAAmB,CAAA;IAChC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,WAAW,CAAA;CACtB,CAAC,CAAA;AAEF;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GACnB,aAAa,mBAAmB,EAChC,UAAU,eAAe,KACxB,QAKD,CAAA;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,SAAS,GAAG,QAAQ,CAAC;IAC/B,IAAI,EAAE,WAAW,CAAA;IACjB,QAAQ,EAAE,QAAQ,CAAA;CACnB,CAAC,CAAA;AAEF;;;GAGG;AACH,eAAO,MAAM,SAAS,GAAI,UAAU,QAAQ,KAAG,SAG7C,CAAA;AAEF;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAA;AAE9C;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC;IACjC,UAAU,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,WAAW,CAAC,CAAA;CACvD,CAAC,CAAA;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,GACrB,UAAU,MAAM,EAChB,QAAQ,WAAW,EACnB,UAAU,yBAAyB,KAClC,QAmBA,CAAA"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Match as M } from 'effect';
|
|
2
|
+
import { injectIntoTemplate, } from './template.js';
|
|
3
|
+
/** Constructs a rendered server entry result with optional HTTP status and
|
|
4
|
+
* headers.
|
|
5
|
+
*
|
|
6
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
7
|
+
*/
|
|
8
|
+
export const Rendered = (application, options) => ({
|
|
9
|
+
_tag: 'Rendered',
|
|
10
|
+
application,
|
|
11
|
+
...(options?.status !== undefined ? { status: options.status } : {}),
|
|
12
|
+
...(options?.headers !== undefined ? { headers: options.headers } : {}),
|
|
13
|
+
});
|
|
14
|
+
/** Constructs a complete Web `Response` server entry result.
|
|
15
|
+
*
|
|
16
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
17
|
+
*/
|
|
18
|
+
export const Responded = (response) => ({
|
|
19
|
+
_tag: 'Responded',
|
|
20
|
+
response,
|
|
21
|
+
});
|
|
22
|
+
/** Turns a server entry result into the Web `Response` a host sends. Rendered
|
|
23
|
+
* applications are injected into the supplied template and default to status
|
|
24
|
+
* 200 with a UTF-8 HTML content type. Complete responses pass through
|
|
25
|
+
* unchanged.
|
|
26
|
+
*
|
|
27
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
28
|
+
*/
|
|
29
|
+
export const toResponse = (template, result, options) => M.value(result).pipe(M.tagsExhaustive({
|
|
30
|
+
Responded: ({ response }) => response,
|
|
31
|
+
Rendered: rendered => {
|
|
32
|
+
const headers = new Headers(rendered.headers);
|
|
33
|
+
if (!headers.has('content-type')) {
|
|
34
|
+
headers.set('content-type', 'text/html; charset=utf-8');
|
|
35
|
+
}
|
|
36
|
+
return new Response(injectIntoTemplate(template, rendered.application, options), {
|
|
37
|
+
status: rendered.status ?? 200,
|
|
38
|
+
headers,
|
|
39
|
+
});
|
|
40
|
+
},
|
|
41
|
+
}));
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decides whether a client accepts an HTML response, given its `Accept`
|
|
3
|
+
* header. An absent or empty header accepts anything. Otherwise the most
|
|
4
|
+
* specific media range that covers `text/html` (`text/html`, then `text/*`,
|
|
5
|
+
* then `*/*`) decides, using its `q` value, so `text/html;q=0` is refused
|
|
6
|
+
* even alongside `*/*`.
|
|
7
|
+
*
|
|
8
|
+
* A page host renders the application for a request that accepts HTML and
|
|
9
|
+
* serves a non-page response otherwise, so this is the negotiation a host runs
|
|
10
|
+
* before falling through to a render.
|
|
11
|
+
*
|
|
12
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
13
|
+
*/
|
|
14
|
+
export declare const acceptsHtml: (acceptHeader: string | undefined) => boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Merges the `Accept` field name into an existing `Vary` header value, parsing
|
|
17
|
+
* it as a comma-separated, case-insensitive list of field names. `Vary: *`
|
|
18
|
+
* already varies on everything and is returned unchanged, an existing `Accept`
|
|
19
|
+
* token (in any case, and distinct from `Accept-Language` or `Accept-Encoding`)
|
|
20
|
+
* is not duplicated, and otherwise `Accept` is appended.
|
|
21
|
+
*
|
|
22
|
+
* A page host that negotiates HTML on the `Accept` header must declare that in
|
|
23
|
+
* `Vary` so a shared cache does not serve one representation in place of the
|
|
24
|
+
* other. The dev host, reference server, and scaffold merge through this one
|
|
25
|
+
* helper so a comma-joined field-name string like `Accept-Language` is never
|
|
26
|
+
* mistaken for the `Accept` field.
|
|
27
|
+
*
|
|
28
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
29
|
+
*/
|
|
30
|
+
export declare const varyWithAccept: (existing: string | undefined) => string;
|
|
31
|
+
/**
|
|
32
|
+
* Decides whether a request path resolves to the `index.html` template, the
|
|
33
|
+
* way a static file server resolves it: percent-decoded, backslashes and
|
|
34
|
+
* repeated separators collapsed, and dot segments resolved. A host renders the
|
|
35
|
+
* application for such a request rather than serving the raw, unfilled
|
|
36
|
+
* template, so `/`, `/index.html`, `/%2findex.html`, and `/foo/../index.html`
|
|
37
|
+
* all resolve to it. An undecodable or null-byte path resolves to nothing.
|
|
38
|
+
*
|
|
39
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
40
|
+
*/
|
|
41
|
+
export declare const resolvesToIndexHtml: (requestUrl: string) => boolean;
|
|
42
|
+
//# sourceMappingURL=host.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../../src/experimental/server/host.ts"],"names":[],"mappings":"AA+DA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,WAAW,GAAI,cAAc,MAAM,GAAG,SAAS,KAAG,OAqB9D,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,cAAc,GAAI,UAAU,MAAM,GAAG,SAAS,KAAG,MAgB7D,CAAA;AAiBD;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,GAAI,YAAY,MAAM,KAAG,OAkBxD,CAAA"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// NOTE: request-classification primitives shared by the dev host (the Vite
|
|
2
|
+
// plugin), the reference server, and the scaffold, so development predicts
|
|
3
|
+
// production. `acceptsHtml` parses the `Accept` header the way a browser
|
|
4
|
+
// negotiates content, and `resolvesToIndexHtml` normalizes a request path the
|
|
5
|
+
// way a static file server does, both of which are easy to get subtly wrong
|
|
6
|
+
// when duplicated per host.
|
|
7
|
+
const HTML_RANGE_SPECIFICITY = {
|
|
8
|
+
'text/html': 3,
|
|
9
|
+
'text/*': 2,
|
|
10
|
+
'*/*': 1,
|
|
11
|
+
};
|
|
12
|
+
const qualityOf = (parameters) => {
|
|
13
|
+
for (const parameter of parameters) {
|
|
14
|
+
const separator = parameter.indexOf('=');
|
|
15
|
+
if (separator === -1) {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
const name = parameter.slice(0, separator).trim().toLowerCase();
|
|
19
|
+
if (name !== 'q') {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const value = Number(parameter.slice(separator + 1).trim());
|
|
23
|
+
return Number.isNaN(value) ? 1 : value;
|
|
24
|
+
}
|
|
25
|
+
return 1;
|
|
26
|
+
};
|
|
27
|
+
// NOTE: split on a delimiter only where it is not inside a double-quoted string,
|
|
28
|
+
// so a quoted media-type parameter (`text/html;profile="a,b"`) is not torn apart
|
|
29
|
+
// at the comma or semicolon inside its value. A backslash inside a quoted string
|
|
30
|
+
// escapes the next character, so an escaped quote (`"a\",b"`) does not end the
|
|
31
|
+
// string and its delimiter stays quoted.
|
|
32
|
+
const splitOutsideQuotes = (value, delimiter) => {
|
|
33
|
+
const parts = [];
|
|
34
|
+
let current = '';
|
|
35
|
+
let isInQuotes = false;
|
|
36
|
+
let isEscaped = false;
|
|
37
|
+
for (const character of value) {
|
|
38
|
+
if (isEscaped) {
|
|
39
|
+
current += character;
|
|
40
|
+
isEscaped = false;
|
|
41
|
+
}
|
|
42
|
+
else if (isInQuotes && character === '\\') {
|
|
43
|
+
current += character;
|
|
44
|
+
isEscaped = true;
|
|
45
|
+
}
|
|
46
|
+
else if (character === '"') {
|
|
47
|
+
isInQuotes = !isInQuotes;
|
|
48
|
+
current += character;
|
|
49
|
+
}
|
|
50
|
+
else if (character === delimiter && !isInQuotes) {
|
|
51
|
+
parts.push(current);
|
|
52
|
+
current = '';
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
current += character;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
parts.push(current);
|
|
59
|
+
return parts;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Decides whether a client accepts an HTML response, given its `Accept`
|
|
63
|
+
* header. An absent or empty header accepts anything. Otherwise the most
|
|
64
|
+
* specific media range that covers `text/html` (`text/html`, then `text/*`,
|
|
65
|
+
* then `*/*`) decides, using its `q` value, so `text/html;q=0` is refused
|
|
66
|
+
* even alongside `*/*`.
|
|
67
|
+
*
|
|
68
|
+
* A page host renders the application for a request that accepts HTML and
|
|
69
|
+
* serves a non-page response otherwise, so this is the negotiation a host runs
|
|
70
|
+
* before falling through to a render.
|
|
71
|
+
*
|
|
72
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
73
|
+
*/
|
|
74
|
+
export const acceptsHtml = (acceptHeader) => {
|
|
75
|
+
if (acceptHeader === undefined || acceptHeader.trim() === '') {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
let bestSpecificity = 0;
|
|
79
|
+
let bestQuality = 0;
|
|
80
|
+
for (const range of splitOutsideQuotes(acceptHeader, ',')) {
|
|
81
|
+
const parts = splitOutsideQuotes(range, ';');
|
|
82
|
+
const mediaType = parts[0]?.trim().toLowerCase() ?? '';
|
|
83
|
+
const specificity = HTML_RANGE_SPECIFICITY[mediaType];
|
|
84
|
+
if (specificity === undefined) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (specificity > bestSpecificity) {
|
|
88
|
+
bestSpecificity = specificity;
|
|
89
|
+
bestQuality = qualityOf(parts.slice(1));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return bestSpecificity > 0 && bestQuality > 0;
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Merges the `Accept` field name into an existing `Vary` header value, parsing
|
|
96
|
+
* it as a comma-separated, case-insensitive list of field names. `Vary: *`
|
|
97
|
+
* already varies on everything and is returned unchanged, an existing `Accept`
|
|
98
|
+
* token (in any case, and distinct from `Accept-Language` or `Accept-Encoding`)
|
|
99
|
+
* is not duplicated, and otherwise `Accept` is appended.
|
|
100
|
+
*
|
|
101
|
+
* A page host that negotiates HTML on the `Accept` header must declare that in
|
|
102
|
+
* `Vary` so a shared cache does not serve one representation in place of the
|
|
103
|
+
* other. The dev host, reference server, and scaffold merge through this one
|
|
104
|
+
* helper so a comma-joined field-name string like `Accept-Language` is never
|
|
105
|
+
* mistaken for the `Accept` field.
|
|
106
|
+
*
|
|
107
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
108
|
+
*/
|
|
109
|
+
export const varyWithAccept = (existing) => {
|
|
110
|
+
const tokens = existing === undefined
|
|
111
|
+
? []
|
|
112
|
+
: existing
|
|
113
|
+
.split(',')
|
|
114
|
+
.map(token => token.trim())
|
|
115
|
+
.filter(token => token !== '');
|
|
116
|
+
const lowered = tokens.map(token => token.toLowerCase());
|
|
117
|
+
if (lowered.includes('*')) {
|
|
118
|
+
return '*';
|
|
119
|
+
}
|
|
120
|
+
if (lowered.includes('accept')) {
|
|
121
|
+
return tokens.join(', ');
|
|
122
|
+
}
|
|
123
|
+
return [...tokens, 'Accept'].join(', ');
|
|
124
|
+
};
|
|
125
|
+
const normalizePath = (path) => {
|
|
126
|
+
const segments = [];
|
|
127
|
+
for (const segment of path.split('/')) {
|
|
128
|
+
if (segment === '' || segment === '.') {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (segment === '..') {
|
|
132
|
+
segments.pop();
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
segments.push(segment);
|
|
136
|
+
}
|
|
137
|
+
return segments.join('/');
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* Decides whether a request path resolves to the `index.html` template, the
|
|
141
|
+
* way a static file server resolves it: percent-decoded, backslashes and
|
|
142
|
+
* repeated separators collapsed, and dot segments resolved. A host renders the
|
|
143
|
+
* application for such a request rather than serving the raw, unfilled
|
|
144
|
+
* template, so `/`, `/index.html`, `/%2findex.html`, and `/foo/../index.html`
|
|
145
|
+
* all resolve to it. An undecodable or null-byte path resolves to nothing.
|
|
146
|
+
*
|
|
147
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
148
|
+
*/
|
|
149
|
+
export const resolvesToIndexHtml = (requestUrl) => {
|
|
150
|
+
let pathname;
|
|
151
|
+
try {
|
|
152
|
+
pathname = new URL(requestUrl, 'http://localhost').pathname;
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
let decoded;
|
|
158
|
+
try {
|
|
159
|
+
decoded = decodeURIComponent(pathname);
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
if (decoded.includes('\0')) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
const normalized = normalizePath(decoded.replace(/\\/g, '/'));
|
|
168
|
+
return normalized === '' || normalized.toLowerCase() === 'index.html';
|
|
169
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/experimental/server/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { FOLDKIT_APP_ATTRIBUTE, FOLDKIT_FLAGS_ATTRIBUTE, FlagsEncodeError, InvalidHydrationRoot, InvalidRuntimeId, InvalidUrl, Rendered, Responded, SerializationError, acceptsHtml, injectIntoTemplate, renderToString, resolvesToIndexHtml, toResponse, varyWithAccept, } from './index.js';
|
|
2
|
+
export type { InjectIntoTemplateOptions, ResponseOptions, RenderedApplication, RenderOptions, RenderUrlOptions, RenderFlagsOptions, RenderUrlFlagsOptions, ApplicationConfig, ApplicationConfigWithFlags, EntryModule, EntryResult, RenderError, RoutingApplicationConfig, RoutingApplicationConfigWithFlags, } from './index.js';
|
|
3
|
+
//# sourceMappingURL=public.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/experimental/server/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,UAAU,EACV,QAAQ,EACR,SAAS,EACT,kBAAkB,EAClB,WAAW,EACX,kBAAkB,EAClB,cAAc,EACd,mBAAmB,EACnB,UAAU,EACV,cAAc,GACf,MAAM,YAAY,CAAA;AAEnB,YAAY,EACV,yBAAyB,EACzB,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,EACrB,iBAAiB,EACjB,0BAA0B,EAC1B,WAAW,EACX,WAAW,EACX,WAAW,EACX,wBAAwB,EACxB,iCAAiC,GAClC,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { FOLDKIT_APP_ATTRIBUTE, FOLDKIT_FLAGS_ATTRIBUTE, FlagsEncodeError, InvalidHydrationRoot, InvalidRuntimeId, InvalidUrl, Rendered, Responded, SerializationError, acceptsHtml, injectIntoTemplate, renderToString, resolvesToIndexHtml, toResponse, varyWithAccept, } from './index.js';
|