foldkit 0.146.0 → 0.148.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/buildToken.d.ts +3 -0
- package/dist/buildToken.d.ts.map +1 -0
- package/dist/buildToken.js +21 -0
- package/dist/controlledDomState.d.ts +25 -0
- package/dist/controlledDomState.d.ts.map +1 -0
- package/dist/controlledDomState.js +240 -0
- package/dist/cssStyleProperties.d.ts +6 -0
- package/dist/cssStyleProperties.d.ts.map +1 -0
- package/dist/cssStyleProperties.js +91 -0
- package/dist/customElement/index.d.ts.map +1 -1
- package/dist/customElement/index.js +23 -0
- package/dist/domReflection.d.ts +73 -0
- package/dist/domReflection.d.ts.map +1 -0
- package/dist/domReflection.js +557 -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 +136 -0
- package/dist/experimental/server/host.d.ts.map +1 -0
- package/dist/experimental/server/host.js +359 -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 +43 -0
- package/dist/experimental/server/serialize.d.ts.map +1 -0
- package/dist/experimental/server/serialize.js +786 -0
- package/dist/experimental/server/server.d.ts +242 -0
- package/dist/experimental/server/server.d.ts.map +1 -0
- package/dist/experimental/server/server.js +946 -0
- package/dist/experimental/server/template.d.ts +53 -0
- package/dist/experimental/server/template.d.ts.map +1 -0
- package/dist/experimental/server/template.js +617 -0
- package/dist/html/index.d.ts +5 -0
- package/dist/html/index.d.ts.map +1 -1
- package/dist/html/index.js +474 -33
- package/dist/hydrate.d.ts +4 -0
- package/dist/hydrate.d.ts.map +1 -0
- package/dist/hydrate.js +850 -0
- package/dist/hydrationMarker.d.ts +10 -0
- package/dist/hydrationMarker.d.ts.map +1 -0
- package/dist/hydrationMarker.js +9 -0
- package/dist/hydrationMarkers.d.ts +15 -0
- package/dist/hydrationMarkers.d.ts.map +1 -0
- package/dist/hydrationMarkers.js +70 -0
- package/dist/nativeInnerHtml.d.ts +13 -0
- package/dist/nativeInnerHtml.d.ts.map +1 -0
- package/dist/nativeInnerHtml.js +30 -0
- package/dist/propertyProvenance.d.ts +33 -0
- package/dist/propertyProvenance.d.ts.map +1 -0
- package/dist/propertyProvenance.js +78 -0
- package/dist/propsModule.d.ts.map +1 -1
- package/dist/propsModule.js +149 -15
- 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 +99 -36
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +412 -71
- package/dist/snabbdom/attributes.d.ts.map +1 -1
- package/dist/snabbdom/attributes.js +65 -37
- 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/style.d.ts.map +1 -1
- package/dist/snabbdom/style.js +53 -34
- 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/test/apps/attributes.d.ts +1 -0
- package/dist/test/apps/attributes.d.ts.map +1 -1
- package/dist/test/apps/attributes.js +8 -1
- package/dist/test/apps/login.js +1 -1
- package/dist/test/matchers.d.ts.map +1 -1
- package/dist/test/matchers.js +2 -1
- package/dist/test/scene.d.ts.map +1 -1
- package/dist/test/scene.js +2 -1
- package/dist/vdom.d.ts.map +1 -1
- package/dist/vdom.js +25 -1
- package/package.json +9 -2
|
@@ -0,0 +1,359 @@
|
|
|
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 a field name into an existing `Vary` header value, parsing it as a
|
|
96
|
+
* comma-separated, case-insensitive list of field names. `Vary: *` already
|
|
97
|
+
* varies on everything and is returned unchanged, a token already present (in
|
|
98
|
+
* any case, and distinct from a longer name that merely starts with it, such as
|
|
99
|
+
* `Accept-Language` beside `Accept`) is not duplicated, and otherwise the field
|
|
100
|
+
* name is appended.
|
|
101
|
+
*
|
|
102
|
+
* A host whose response depends on a request header must declare that header in
|
|
103
|
+
* `Vary` so a shared cache does not serve one client's representation to
|
|
104
|
+
* another. The dev host, reference server, and scaffold merge through this one
|
|
105
|
+
* helper rather than assigning `Vary`, which would drop the fields already
|
|
106
|
+
* there.
|
|
107
|
+
*
|
|
108
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
109
|
+
*/
|
|
110
|
+
export const varyWith = (existing, fieldName) => {
|
|
111
|
+
const tokens = existing === undefined
|
|
112
|
+
? []
|
|
113
|
+
: existing
|
|
114
|
+
.split(',')
|
|
115
|
+
.map(token => token.trim())
|
|
116
|
+
.filter(token => token !== '');
|
|
117
|
+
const lowered = tokens.map(token => token.toLowerCase());
|
|
118
|
+
if (lowered.includes('*')) {
|
|
119
|
+
return '*';
|
|
120
|
+
}
|
|
121
|
+
if (lowered.includes(fieldName.toLowerCase())) {
|
|
122
|
+
return tokens.join(', ');
|
|
123
|
+
}
|
|
124
|
+
return [...tokens, fieldName].join(', ');
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Merges the `Accept` field name into an existing `Vary` header value.
|
|
128
|
+
*
|
|
129
|
+
* A page host that negotiates HTML on the `Accept` header must declare that in
|
|
130
|
+
* `Vary` so a shared cache does not serve one representation in place of the
|
|
131
|
+
* other.
|
|
132
|
+
*
|
|
133
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
134
|
+
*/
|
|
135
|
+
export const varyWithAccept = (existing) => varyWith(existing, 'Accept');
|
|
136
|
+
/**
|
|
137
|
+
* Resolves a request target against the origin the host serves, returning the
|
|
138
|
+
* absolute URL to hand the server entry, or `undefined` when the target names
|
|
139
|
+
* a different origin.
|
|
140
|
+
*
|
|
141
|
+
* A request target is not a URL. HTTP allows origin-form (`/page?q=1`) and
|
|
142
|
+
* absolute-form (`http://host/page`), and a client can send a network-path
|
|
143
|
+
* reference (`//elsewhere.example/page`) that resolves against no scheme at
|
|
144
|
+
* all. Resolving one of those against the host origin silently adopts the
|
|
145
|
+
* origin the client wrote, so an entry that derives redirects, canonical URLs,
|
|
146
|
+
* cookie domains, or tenant selection from `Request.url` would take them from
|
|
147
|
+
* the request rather than from the deployment. Only a target that resolves to
|
|
148
|
+
* the host's own origin is accepted; a host behind a proxy that must serve a
|
|
149
|
+
* different public origin passes that origin in explicitly.
|
|
150
|
+
*
|
|
151
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
152
|
+
*/
|
|
153
|
+
export const resolveRequestUrl = (requestTarget, origin) => {
|
|
154
|
+
let base;
|
|
155
|
+
try {
|
|
156
|
+
base = new URL(origin);
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
return undefined;
|
|
160
|
+
}
|
|
161
|
+
let resolved;
|
|
162
|
+
try {
|
|
163
|
+
resolved = new URL(requestTarget, base);
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
// Credentials in the target are refused rather than passed along. `origin`
|
|
169
|
+
// ignores them, so `http://user:pass@host/page` reads as same-origin here and
|
|
170
|
+
// then makes `new Request(url)` throw, turning a malformed request into a 500
|
|
171
|
+
// instead of the 400 it is.
|
|
172
|
+
if (resolved.username !== '' || resolved.password !== '') {
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
return resolved.origin === base.origin ? resolved.href : undefined;
|
|
176
|
+
};
|
|
177
|
+
const normalizePath = (path) => {
|
|
178
|
+
const segments = [];
|
|
179
|
+
for (const segment of path.split('/')) {
|
|
180
|
+
if (segment === '' || segment === '.') {
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
if (segment === '..') {
|
|
184
|
+
segments.pop();
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
segments.push(segment);
|
|
188
|
+
}
|
|
189
|
+
return segments.join('/');
|
|
190
|
+
};
|
|
191
|
+
// The `Sec-Fetch-Dest` values a browser sends for a subresource it fetches for
|
|
192
|
+
// an already-loaded page, as opposed to a navigation (`document`, `iframe`,
|
|
193
|
+
// `frame`) or a scripted fetch whose destination is `empty`. A request carrying
|
|
194
|
+
// one of these is never a page request, whatever it says it accepts.
|
|
195
|
+
const SUBRESOURCE_FETCH_DESTINATIONS = new Set([
|
|
196
|
+
'audio',
|
|
197
|
+
'audioworklet',
|
|
198
|
+
'embed',
|
|
199
|
+
'font',
|
|
200
|
+
'image',
|
|
201
|
+
'manifest',
|
|
202
|
+
'object',
|
|
203
|
+
'paintworklet',
|
|
204
|
+
'script',
|
|
205
|
+
'serviceworker',
|
|
206
|
+
'sharedworker',
|
|
207
|
+
'style',
|
|
208
|
+
'track',
|
|
209
|
+
'video',
|
|
210
|
+
'worker',
|
|
211
|
+
'xslt',
|
|
212
|
+
]);
|
|
213
|
+
const ASSET_EXTENSIONS = new Set([
|
|
214
|
+
'avif',
|
|
215
|
+
'bmp',
|
|
216
|
+
'cjs',
|
|
217
|
+
'css',
|
|
218
|
+
'csv',
|
|
219
|
+
'eot',
|
|
220
|
+
'gif',
|
|
221
|
+
'gz',
|
|
222
|
+
'ico',
|
|
223
|
+
'jpeg',
|
|
224
|
+
'jpg',
|
|
225
|
+
'js',
|
|
226
|
+
'json',
|
|
227
|
+
'map',
|
|
228
|
+
'mjs',
|
|
229
|
+
'mp3',
|
|
230
|
+
'mp4',
|
|
231
|
+
'ogg',
|
|
232
|
+
'otf',
|
|
233
|
+
'pdf',
|
|
234
|
+
'png',
|
|
235
|
+
'svg',
|
|
236
|
+
'ttf',
|
|
237
|
+
'txt',
|
|
238
|
+
'wasm',
|
|
239
|
+
'wav',
|
|
240
|
+
'webm',
|
|
241
|
+
'webmanifest',
|
|
242
|
+
'webp',
|
|
243
|
+
'woff',
|
|
244
|
+
'woff2',
|
|
245
|
+
'xml',
|
|
246
|
+
'zip',
|
|
247
|
+
]);
|
|
248
|
+
/**
|
|
249
|
+
* Classifies a request that no static file answered, from its path and, when
|
|
250
|
+
* the client sent one, its `Sec-Fetch-Dest`.
|
|
251
|
+
*
|
|
252
|
+
* A host answers a static miss by content negotiation, and a browser requests
|
|
253
|
+
* scripts, stylesheets, and images with `Accept: */*`, which accepts HTML. A
|
|
254
|
+
* request for a hashed asset that is no longer deployed would therefore be
|
|
255
|
+
* answered with the application shell at 200, so a stale bundle reads as a
|
|
256
|
+
* blank page rather than the 404 it is.
|
|
257
|
+
*
|
|
258
|
+
* The path is read first, so a request the URL alone settles is never made to
|
|
259
|
+
* depend on a header the client may or may not send.
|
|
260
|
+
*
|
|
261
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
262
|
+
*/
|
|
263
|
+
export const classifyRequest = (requestUrl, fetchDestination) => {
|
|
264
|
+
let pathname;
|
|
265
|
+
try {
|
|
266
|
+
pathname = new URL(requestUrl, 'http://localhost').pathname;
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
pathname = '';
|
|
270
|
+
}
|
|
271
|
+
// Read the path a static file server would resolve, not the raw one. A file
|
|
272
|
+
// server percent-decodes before it looks for a file, so `/assets/a%2Ejs` and
|
|
273
|
+
// `/assets/a.js` name the same asset; classifying the raw form reads the
|
|
274
|
+
// first as an ordinary page and answers a missing bundle with the shell.
|
|
275
|
+
try {
|
|
276
|
+
pathname = decodeURIComponent(pathname);
|
|
277
|
+
}
|
|
278
|
+
catch {
|
|
279
|
+
// An undecodable path names no file, so leave it as written.
|
|
280
|
+
}
|
|
281
|
+
const lastSegment = pathname.slice(pathname.lastIndexOf('/') + 1);
|
|
282
|
+
const separator = lastSegment.lastIndexOf('.');
|
|
283
|
+
if (separator > 0 &&
|
|
284
|
+
ASSET_EXTENSIONS.has(lastSegment.slice(separator + 1).toLowerCase())) {
|
|
285
|
+
return 'PathAsset';
|
|
286
|
+
}
|
|
287
|
+
if (fetchDestination !== undefined &&
|
|
288
|
+
SUBRESOURCE_FETCH_DESTINATIONS.has(fetchDestination.trim().toLowerCase())) {
|
|
289
|
+
return 'DestinationAsset';
|
|
290
|
+
}
|
|
291
|
+
return 'Page';
|
|
292
|
+
};
|
|
293
|
+
/**
|
|
294
|
+
* Decides whether a request path resolves to the `index.html` template, the
|
|
295
|
+
* way a static file server resolves it: percent-decoded, backslashes and
|
|
296
|
+
* repeated separators collapsed, and dot segments resolved. A host renders the
|
|
297
|
+
* application for such a request rather than serving the raw, unfilled
|
|
298
|
+
* template, so `/`, `/index.html`, `/%2findex.html`, and `/foo/../index.html`
|
|
299
|
+
* all resolve to it. An undecodable or null-byte path resolves to nothing.
|
|
300
|
+
*
|
|
301
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
302
|
+
*/
|
|
303
|
+
export const resolvesToIndexHtml = (requestUrl) => {
|
|
304
|
+
let pathname;
|
|
305
|
+
try {
|
|
306
|
+
pathname = new URL(requestUrl, 'http://localhost').pathname;
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
let decoded;
|
|
312
|
+
try {
|
|
313
|
+
decoded = decodeURIComponent(pathname);
|
|
314
|
+
}
|
|
315
|
+
catch {
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
if (decoded.includes('\0')) {
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
321
|
+
const normalized = normalizePath(decoded.replace(/\\/g, '/'));
|
|
322
|
+
return normalized === '' || normalized.toLowerCase() === 'index.html';
|
|
323
|
+
};
|
|
324
|
+
/**
|
|
325
|
+
* The answer a host gives for the methods it cannot hand to a server entry.
|
|
326
|
+
*
|
|
327
|
+
* The WHATWG `Request` constructor rejects `CONNECT`, `TRACE`, and `TRACK`, so
|
|
328
|
+
* an entry can never be handed one: forwarding it turns a malformed request
|
|
329
|
+
* into a 500. A host refuses them itself, with `405` and an `Allow` header
|
|
330
|
+
* naming what it does forward.
|
|
331
|
+
*
|
|
332
|
+
* On Node only `TRACE` reaches this rule. The HTTP parser rejects `TRACK` with
|
|
333
|
+
* a 400 before any handler runs, and `CONNECT` arrives on its own event rather
|
|
334
|
+
* than as an ordinary request. Both are named anyway, so a host on another
|
|
335
|
+
* runtime refuses them rather than handing one to `new Request`.
|
|
336
|
+
*
|
|
337
|
+
* Every other method reaches the entry, `OPTIONS` included. A preflight is a
|
|
338
|
+
* question about a resource, so the application answers it: the entry can allow
|
|
339
|
+
* one origin for one route and refuse it for another, which no host-level
|
|
340
|
+
* policy could express. The Vite dev host applies Vite's CORS option only to
|
|
341
|
+
* Vite-owned modules and assets. An application preflight therefore reaches
|
|
342
|
+
* the entry rather than middleware a deployed host has no counterpart for.
|
|
343
|
+
*
|
|
344
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
345
|
+
*/
|
|
346
|
+
export const HOST_METHOD_ANSWERS = {
|
|
347
|
+
refusedStatus: 405,
|
|
348
|
+
allow: 'GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS',
|
|
349
|
+
};
|
|
350
|
+
/**
|
|
351
|
+
* Whether a host refuses this method itself instead of calling the server
|
|
352
|
+
* entry. See {@link HOST_METHOD_ANSWERS}.
|
|
353
|
+
*
|
|
354
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
355
|
+
*/
|
|
356
|
+
export const isHostSettledMethod = (method) => {
|
|
357
|
+
const normalized = method.toUpperCase();
|
|
358
|
+
return (normalized === 'CONNECT' || normalized === 'TRACE' || normalized === 'TRACK');
|
|
359
|
+
};
|
|
@@ -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, HOST_METHOD_ANSWERS, InvalidHydrationRoot, InvalidRuntimeId, InvalidUrl, MissingBuildId, Rendered, Responded, SerializationError, acceptsHtml, classifyRequest, injectIntoTemplate, isHostSettledMethod, renderToString, resolveRequestUrl, resolvesToIndexHtml, toResponse, varyWith, varyWithAccept, } from './index.js';
|
|
2
|
+
export type { InjectIntoTemplateOptions, RequestClassification, ResponseOptions, RenderedApplication, HydratableRenderOptions, StaticRenderOptions, 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,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,UAAU,EACV,cAAc,EACd,QAAQ,EACR,SAAS,EACT,kBAAkB,EAClB,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACnB,UAAU,EACV,QAAQ,EACR,cAAc,GACf,MAAM,YAAY,CAAA;AAEnB,YAAY,EACV,yBAAyB,EACzB,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACnB,uBAAuB,EACvB,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, HOST_METHOD_ANSWERS, InvalidHydrationRoot, InvalidRuntimeId, InvalidUrl, MissingBuildId, Rendered, Responded, SerializationError, acceptsHtml, classifyRequest, injectIntoTemplate, isHostSettledMethod, renderToString, resolveRequestUrl, resolvesToIndexHtml, toResponse, varyWith, varyWithAccept, } from './index.js';
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { VNode } from '../../snabbdom/vnode.js';
|
|
2
|
+
/** Extra attributes appended to the serialized root element, used by
|
|
3
|
+
* `renderToString` to stamp the hydration marker without threading
|
|
4
|
+
* server-only concerns through view code. Root attributes are applied after
|
|
5
|
+
* the vnode's own data, so the stamp always wins over a same-named
|
|
6
|
+
* attribute in the view.
|
|
7
|
+
*
|
|
8
|
+
* `emitHydrationMarkers` turns on the key and identity markers hydration
|
|
9
|
+
* verifies adoption against. They are part of the hydration handoff, so a
|
|
10
|
+
* render nobody will hydrate carries none of them.
|
|
11
|
+
*
|
|
12
|
+
* @internal Not part of the `foldkit/experimental/server` surface; `renderToString` is the public entry to serialization.
|
|
13
|
+
*/
|
|
14
|
+
export type SerializeOptions = Readonly<{
|
|
15
|
+
rootAttributes?: Readonly<Record<string, string>>;
|
|
16
|
+
emitHydrationMarkers?: boolean;
|
|
17
|
+
}>;
|
|
18
|
+
/** Escapes a string for use as HTML text content.
|
|
19
|
+
*
|
|
20
|
+
* @internal Shared with the template injector; not part of the `foldkit/experimental/server` surface.
|
|
21
|
+
*/
|
|
22
|
+
export declare const escapeText: (value: string) => string;
|
|
23
|
+
/** Escapes a string for use inside a double-quoted HTML attribute value.
|
|
24
|
+
*
|
|
25
|
+
* @internal Shared with the template injector; not part of the `foldkit/experimental/server` surface.
|
|
26
|
+
*/
|
|
27
|
+
export declare const escapeAttributeValue: (value: string) => string;
|
|
28
|
+
export declare const controlledValueContent: (properties: Readonly<Record<string, unknown>> | undefined) => string | undefined;
|
|
29
|
+
/** Serializes a view-produced vnode tree to an HTML string. Event handlers and
|
|
30
|
+
* hooks are behavior, not markup, and are skipped; attrs, class, dataset,
|
|
31
|
+
* prop-backed attributes, and inline style are emitted in that order. A `null`
|
|
32
|
+
* tree serializes to an empty comment, mirroring how the runtime patches
|
|
33
|
+
* `null` as a comment node.
|
|
34
|
+
*
|
|
35
|
+
* A hydratable render also stamps a digest of each vnode's key and identity, so
|
|
36
|
+
* hydration can tell one logical entity from another; the raw key and the
|
|
37
|
+
* compiler's source identity never appear in the markup. A render that is not
|
|
38
|
+
* hydratable emits neither.
|
|
39
|
+
*
|
|
40
|
+
* @internal Not part of the `foldkit/experimental/server` surface; `renderToString` is the public entry to serialization.
|
|
41
|
+
*/
|
|
42
|
+
export declare const serializeHtml: (root: VNode | null, options?: SerializeOptions) => string;
|
|
43
|
+
//# sourceMappingURL=serialize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../../../src/experimental/server/serialize.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAA;AAGpD;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;IACtC,cAAc,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACjD,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B,CAAC,CAAA;AAsNF;;;GAGG;AACH,eAAO,MAAM,UAAU,GAAI,OAAO,MAAM,KAAG,MAM1C,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,oBAAoB,GAAI,OAAO,MAAM,KAAG,MAMpD,CAAA;AA0MD,eAAO,MAAM,sBAAsB,GACjC,YAAY,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,KACxD,MAAM,GAAG,SAMX,CAAA;AAugBD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,aAAa,GACxB,MAAM,KAAK,GAAG,IAAI,EAClB,UAAU,gBAAgB,KACzB,MAUF,CAAA"}
|