foldkit 0.166.0 → 0.167.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/dist/command/index.d.ts +4 -4
- package/dist/command/index.js +4 -4
- package/dist/dom/index.d.ts +6 -0
- package/dist/dom/index.d.ts.map +1 -1
- package/dist/dom/index.js +3 -0
- package/dist/dom/public.d.ts +2 -2
- package/dist/dom/public.d.ts.map +1 -1
- package/dist/dom/public.js +1 -1
- package/dist/{subscription/fromEvent.d.ts → dom/streamFromEvent.d.ts} +31 -31
- package/dist/dom/streamFromEvent.d.ts.map +1 -0
- package/dist/{subscription/fromEvent.js → dom/streamFromEvent.js} +20 -20
- package/dist/{subscription/keyBindings.d.ts → dom/streamFromKeyBindings.d.ts} +7 -7
- package/dist/dom/streamFromKeyBindings.d.ts.map +1 -0
- package/dist/{subscription/keyBindings.js → dom/streamFromKeyBindings.js} +62 -17
- package/dist/{subscription/fromMediaQuery.d.ts → dom/streamFromMediaQuery.d.ts} +7 -7
- package/dist/dom/streamFromMediaQuery.d.ts.map +1 -0
- package/dist/{subscription/fromMediaQuery.js → dom/streamFromMediaQuery.js} +4 -4
- package/dist/experimental/server/document.d.ts +43 -0
- package/dist/experimental/server/document.d.ts.map +1 -0
- package/dist/experimental/server/document.js +42 -0
- package/dist/experimental/server/entry.d.ts +14 -7
- package/dist/experimental/server/entry.d.ts.map +1 -1
- package/dist/experimental/server/entry.js +8 -6
- package/dist/experimental/server/fetch.d.ts +11 -8
- package/dist/experimental/server/fetch.d.ts.map +1 -1
- package/dist/experimental/server/fetch.js +16 -1
- package/dist/experimental/server/index.d.ts +1 -0
- package/dist/experimental/server/index.d.ts.map +1 -1
- package/dist/experimental/server/index.js +1 -0
- package/dist/experimental/server/public.d.ts +2 -2
- package/dist/experimental/server/public.d.ts.map +1 -1
- package/dist/experimental/server/public.js +1 -1
- package/dist/experimental/server/server.d.ts +1 -1
- package/dist/port/port.d.ts +8 -8
- package/dist/port/port.d.ts.map +1 -1
- package/dist/port/port.js +8 -8
- package/dist/port/public.d.ts +1 -1
- package/dist/port/public.d.ts.map +1 -1
- package/dist/port/public.js +1 -1
- package/dist/subscription/animationFrame.d.ts +4 -4
- package/dist/subscription/animationFrame.d.ts.map +1 -1
- package/dist/subscription/animationFrame.js +3 -3
- package/dist/subscription/public.d.ts +2 -8
- package/dist/subscription/public.d.ts.map +1 -1
- package/dist/subscription/public.js +2 -5
- package/dist/subscription/subscription.d.ts +9 -9
- package/dist/subscription/subscription.d.ts.map +1 -1
- package/dist/subscription/subscription.js +6 -6
- package/dist/update/public.d.ts +2 -2
- package/dist/update/public.d.ts.map +1 -1
- package/dist/update/public.js +1 -1
- package/dist/update/update.d.ts +109 -0
- package/dist/update/update.d.ts.map +1 -1
- package/dist/update/update.js +70 -0
- package/package.json +1 -1
- package/dist/subscription/fromEvent.d.ts.map +0 -1
- package/dist/subscription/fromMediaQuery.d.ts.map +0 -1
- package/dist/subscription/keyBindings.d.ts.map +0 -1
|
@@ -148,8 +148,12 @@ const validateBindings = (bindings, modKey) => {
|
|
|
148
148
|
const compileEnabledBindings = (bindings) => pipe(bindings, Array.filter(binding => binding.isEnabled !== false), Array.map(compileBinding));
|
|
149
149
|
const isSequence = (binding) => Array.length(binding.presses) > 1;
|
|
150
150
|
const isModifierEvent = (event) => Array.contains(MODIFIER_KEYS, normalizeKey(event.key));
|
|
151
|
+
const hasStringProperty = (value, key) => Predicate.hasProperty(value, key) && Predicate.isString(value[key]);
|
|
152
|
+
const hasBooleanProperty = (value, key) => Predicate.hasProperty(value, key) && Predicate.isBoolean(value[key]);
|
|
153
|
+
const hasFunctionProperty = (value, key) => Predicate.hasProperty(value, key) && Predicate.isFunction(value[key]);
|
|
151
154
|
const isEditableTarget = (target) => {
|
|
152
|
-
if (!(target
|
|
155
|
+
if (!hasStringProperty(target, 'tagName') ||
|
|
156
|
+
!hasBooleanProperty(target, 'isContentEditable')) {
|
|
153
157
|
return false;
|
|
154
158
|
}
|
|
155
159
|
const tag = String.toLowerCase(target.tagName);
|
|
@@ -159,12 +163,19 @@ const isEditableTarget = (target) => {
|
|
|
159
163
|
target.isContentEditable);
|
|
160
164
|
};
|
|
161
165
|
const isFromEditable = (event) => Array.some(event.composedPath(), isEditableTarget);
|
|
166
|
+
const isKeyboardEvent = (event) => hasStringProperty(event, 'key') &&
|
|
167
|
+
hasBooleanProperty(event, 'altKey') &&
|
|
168
|
+
hasBooleanProperty(event, 'ctrlKey') &&
|
|
169
|
+
hasBooleanProperty(event, 'metaKey') &&
|
|
170
|
+
hasBooleanProperty(event, 'shiftKey') &&
|
|
171
|
+
hasBooleanProperty(event, 'repeat') &&
|
|
172
|
+
hasBooleanProperty(event, 'isComposing');
|
|
162
173
|
const isAllowedWhileTyping = (binding, isEditable) => !isEditable || binding.whileTyping === 'Allow';
|
|
163
|
-
const resolveModKey = (configuredModKey) => {
|
|
174
|
+
const resolveModKey = (configuredModKey, userAgent) => {
|
|
164
175
|
if (configuredModKey !== undefined) {
|
|
165
176
|
return configuredModKey;
|
|
166
177
|
}
|
|
167
|
-
return APPLE_PLATFORM_PATTERN.test(
|
|
178
|
+
return APPLE_PLATFORM_PATTERN.test(userAgent) ? 'Meta' : 'Control';
|
|
168
179
|
};
|
|
169
180
|
const pressMatches = (press, event, modKey) => {
|
|
170
181
|
const isControlRequired = press.isControlRequired || (press.isModRequired && modKey === 'Control');
|
|
@@ -183,22 +194,28 @@ const resolveTarget = (target) => {
|
|
|
183
194
|
}
|
|
184
195
|
return target ?? document;
|
|
185
196
|
};
|
|
186
|
-
const resolveValidationModKey = (configuredModKey) => {
|
|
197
|
+
const resolveValidationModKey = (configuredModKey, target) => {
|
|
187
198
|
if (configuredModKey !== undefined) {
|
|
188
199
|
return Option.some(configuredModKey);
|
|
189
200
|
}
|
|
190
|
-
if (
|
|
201
|
+
if (target === undefined) {
|
|
202
|
+
if (typeof navigator === 'undefined') {
|
|
203
|
+
return Option.none();
|
|
204
|
+
}
|
|
205
|
+
return Option.some(resolveModKey(undefined, navigator.userAgent));
|
|
206
|
+
}
|
|
207
|
+
if (Predicate.isFunction(target)) {
|
|
191
208
|
return Option.none();
|
|
192
209
|
}
|
|
193
|
-
return Option.
|
|
210
|
+
return Option.map(resolveKnownOwnerWindow(target), ownerWindow => resolveModKey(undefined, ownerWindow.navigator.userAgent));
|
|
194
211
|
};
|
|
195
|
-
const
|
|
212
|
+
const compileStreamFromKeyBindingsConfig = (config) => {
|
|
196
213
|
const bindings = compileEnabledBindings(config.bindings);
|
|
197
214
|
const sequenceTimeout = Duration.toMillis(config.sequenceTimeout ?? DEFAULT_SEQUENCE_TIMEOUT);
|
|
198
215
|
if (!globalThis.Number.isFinite(sequenceTimeout) || sequenceTimeout <= 0) {
|
|
199
216
|
throw new Error('sequenceTimeout must be a finite duration above zero');
|
|
200
217
|
}
|
|
201
|
-
const maybeValidationModKey = resolveValidationModKey(config.modKey);
|
|
218
|
+
const maybeValidationModKey = resolveValidationModKey(config.modKey, config.target);
|
|
202
219
|
if (Option.isSome(maybeValidationModKey)) {
|
|
203
220
|
validateBindings(bindings, maybeValidationModKey.value);
|
|
204
221
|
}
|
|
@@ -292,7 +309,7 @@ const continueSequence = (context, sequence, event) => {
|
|
|
292
309
|
}
|
|
293
310
|
};
|
|
294
311
|
const handleKeyBindingEvent = (context, event) => {
|
|
295
|
-
if (!(event
|
|
312
|
+
if (!isKeyboardEvent(event)) {
|
|
296
313
|
return;
|
|
297
314
|
}
|
|
298
315
|
if (event.defaultPrevented || event.isComposing) {
|
|
@@ -324,18 +341,48 @@ const makeKeyBindingHandler = (config) => {
|
|
|
324
341
|
handleEvent: event => handleKeyBindingEvent(context, event),
|
|
325
342
|
};
|
|
326
343
|
};
|
|
344
|
+
const hasEventListeners = (value) => hasFunctionProperty(value, 'addEventListener') &&
|
|
345
|
+
hasFunctionProperty(value, 'removeEventListener');
|
|
346
|
+
const hasDocumentCapabilities = (value) => hasEventListeners(value) && Predicate.hasProperty(value, 'defaultView');
|
|
347
|
+
const isKeyBindingWindow = (value) => hasEventListeners(value) &&
|
|
348
|
+
Predicate.hasProperty(value, 'document') &&
|
|
349
|
+
hasDocumentCapabilities(value.document) &&
|
|
350
|
+
Predicate.hasProperty(value, 'navigator') &&
|
|
351
|
+
hasStringProperty(value.navigator, 'userAgent');
|
|
352
|
+
const isKeyBindingDocument = (value) => hasDocumentCapabilities(value) &&
|
|
353
|
+
(value.defaultView === null || isKeyBindingWindow(value.defaultView));
|
|
354
|
+
const resolveKnownOwnerWindow = (target) => {
|
|
355
|
+
if (isKeyBindingWindow(target)) {
|
|
356
|
+
return Option.some(target);
|
|
357
|
+
}
|
|
358
|
+
if (isKeyBindingDocument(target)) {
|
|
359
|
+
return Option.fromNullishOr(target.defaultView);
|
|
360
|
+
}
|
|
361
|
+
if (Predicate.hasProperty(target, 'ownerDocument') &&
|
|
362
|
+
isKeyBindingDocument(target.ownerDocument)) {
|
|
363
|
+
return Option.fromNullishOr(target.ownerDocument.defaultView);
|
|
364
|
+
}
|
|
365
|
+
return Option.none();
|
|
366
|
+
};
|
|
327
367
|
const resolveOwnerDocument = (target) => {
|
|
328
|
-
if (target
|
|
368
|
+
if (isKeyBindingDocument(target)) {
|
|
329
369
|
return target;
|
|
330
370
|
}
|
|
331
|
-
if (target
|
|
371
|
+
if (Predicate.hasProperty(target, 'ownerDocument') &&
|
|
372
|
+
isKeyBindingDocument(target.ownerDocument)) {
|
|
332
373
|
return target.ownerDocument;
|
|
333
374
|
}
|
|
375
|
+
if (Predicate.hasProperty(target, 'document') &&
|
|
376
|
+
isKeyBindingDocument(target.document)) {
|
|
377
|
+
return target.document;
|
|
378
|
+
}
|
|
334
379
|
return document;
|
|
335
380
|
};
|
|
336
381
|
const acquireKeyBindingListener = (config, emitMessage) => {
|
|
337
382
|
const target = resolveTarget(config.target);
|
|
338
|
-
const
|
|
383
|
+
const ownerDocument = resolveOwnerDocument(target);
|
|
384
|
+
const ownerWindow = ownerDocument.defaultView ?? window;
|
|
385
|
+
const modKey = resolveModKey(config.modKey, ownerWindow.navigator.userAgent);
|
|
339
386
|
validateBindings(config.bindings, modKey);
|
|
340
387
|
const handler = makeKeyBindingHandler({
|
|
341
388
|
bindings: config.bindings,
|
|
@@ -343,8 +390,6 @@ const acquireKeyBindingListener = (config, emitMessage) => {
|
|
|
343
390
|
modKey,
|
|
344
391
|
sequenceTimeout: config.sequenceTimeout,
|
|
345
392
|
});
|
|
346
|
-
const ownerDocument = resolveOwnerDocument(target);
|
|
347
|
-
const ownerWindow = ownerDocument.defaultView ?? window;
|
|
348
393
|
target.addEventListener('keydown', handler.handleEvent);
|
|
349
394
|
ownerWindow.addEventListener('blur', handler.clearSequence);
|
|
350
395
|
ownerDocument.addEventListener('visibilitychange', handler.clearSequence);
|
|
@@ -398,7 +443,7 @@ const keyBindingStream = (config) => Stream.callback(queue => {
|
|
|
398
443
|
* are rejected when the Stream is created.
|
|
399
444
|
*
|
|
400
445
|
* This helper returns a Stream, not a complete Subscription entry. Use
|
|
401
|
-
* `Subscription.
|
|
446
|
+
* `Subscription.persistentEntry` for a fixed table. When availability depends on
|
|
402
447
|
* the Model that owns the entry, build it inside `dependenciesToStream` and
|
|
403
448
|
* derive each binding's `isEnabled` from the dependency record. A dependency
|
|
404
449
|
* change opens a new Stream scope and resets any sequence in progress. If a
|
|
@@ -418,7 +463,7 @@ const keyBindingStream = (config) => Stream.callback(queue => {
|
|
|
418
463
|
* isPaletteOpen: model.paletteState._tag === 'Open',
|
|
419
464
|
* }),
|
|
420
465
|
* dependenciesToStream: ({ isPaletteOpen }) =>
|
|
421
|
-
*
|
|
466
|
+
* Dom.streamFromKeyBindings<Message>({
|
|
422
467
|
* bindings: [
|
|
423
468
|
* {
|
|
424
469
|
* keys: 'Escape',
|
|
@@ -442,4 +487,4 @@ const keyBindingStream = (config) => Stream.callback(queue => {
|
|
|
442
487
|
* }))
|
|
443
488
|
* ```
|
|
444
489
|
*/
|
|
445
|
-
export const
|
|
490
|
+
export const streamFromKeyBindings = (config) => keyBindingStream(compileStreamFromKeyBindingsConfig(config));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Stream } from 'effect';
|
|
2
2
|
/**
|
|
3
|
-
* Options for `
|
|
3
|
+
* Options for `streamFromMediaQuery`.
|
|
4
4
|
*
|
|
5
5
|
* `query` accepts any media query string supported by `window.matchMedia`,
|
|
6
6
|
* such as `'(prefers-reduced-motion: reduce)'`,
|
|
@@ -15,7 +15,7 @@ import { Stream } from 'effect';
|
|
|
15
15
|
* `Subscription.make` checks that output against the application's Message
|
|
16
16
|
* type.
|
|
17
17
|
*/
|
|
18
|
-
export type
|
|
18
|
+
export type StreamFromMediaQueryConfig<Output> = Readonly<{
|
|
19
19
|
query: string;
|
|
20
20
|
mapMatches: (isMatching: boolean) => Output;
|
|
21
21
|
}>;
|
|
@@ -36,15 +36,15 @@ export type FromMediaQueryConfig<Output> = Readonly<{
|
|
|
36
36
|
* server rendering as long as it runs only in the browser.
|
|
37
37
|
*
|
|
38
38
|
* This helper returns a Stream, not a Subscription entry. Pass it to
|
|
39
|
-
* `Subscription.
|
|
39
|
+
* `Subscription.persistentEntry` for a query the application always follows. To
|
|
40
40
|
* follow the query only in a particular Model state, use it with `Stream.when`
|
|
41
41
|
* inside a `Subscription.make` entry.
|
|
42
42
|
*
|
|
43
43
|
* @example
|
|
44
44
|
* ```typescript
|
|
45
45
|
* const subscriptions = Subscription.make<Model, Message>()(_entry => ({
|
|
46
|
-
* reducedMotion: Subscription.
|
|
47
|
-
*
|
|
46
|
+
* reducedMotion: Subscription.persistentEntry(
|
|
47
|
+
* Dom.streamFromMediaQuery({
|
|
48
48
|
* query: '(prefers-reduced-motion: reduce)',
|
|
49
49
|
* mapMatches: isMatching =>
|
|
50
50
|
* Message.ChangedReducedMotion({ isReducedMotion: isMatching }),
|
|
@@ -53,5 +53,5 @@ export type FromMediaQueryConfig<Output> = Readonly<{
|
|
|
53
53
|
* }))
|
|
54
54
|
* ```
|
|
55
55
|
*/
|
|
56
|
-
export declare const
|
|
57
|
-
//# sourceMappingURL=
|
|
56
|
+
export declare const streamFromMediaQuery: <Output>(config: StreamFromMediaQueryConfig<Output>) => Stream.Stream<Output>;
|
|
57
|
+
//# sourceMappingURL=streamFromMediaQuery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streamFromMediaQuery.d.ts","sourceRoot":"","sources":["../../src/dom/streamFromMediaQuery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE9C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,0BAA0B,CAAC,MAAM,IAAI,QAAQ,CAAC;IACxD,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,MAAM,CAAA;CAC5C,CAAC,CAAA;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,oBAAoB,GAAI,MAAM,UACjC,0BAA0B,CAAC,MAAM,CAAC,KACzC,MAAM,CAAC,MAAM,CAAC,MAAM,CAmBpB,CAAA"}
|
|
@@ -16,15 +16,15 @@ import { Effect, Queue, Stream } from 'effect';
|
|
|
16
16
|
* server rendering as long as it runs only in the browser.
|
|
17
17
|
*
|
|
18
18
|
* This helper returns a Stream, not a Subscription entry. Pass it to
|
|
19
|
-
* `Subscription.
|
|
19
|
+
* `Subscription.persistentEntry` for a query the application always follows. To
|
|
20
20
|
* follow the query only in a particular Model state, use it with `Stream.when`
|
|
21
21
|
* inside a `Subscription.make` entry.
|
|
22
22
|
*
|
|
23
23
|
* @example
|
|
24
24
|
* ```typescript
|
|
25
25
|
* const subscriptions = Subscription.make<Model, Message>()(_entry => ({
|
|
26
|
-
* reducedMotion: Subscription.
|
|
27
|
-
*
|
|
26
|
+
* reducedMotion: Subscription.persistentEntry(
|
|
27
|
+
* Dom.streamFromMediaQuery({
|
|
28
28
|
* query: '(prefers-reduced-motion: reduce)',
|
|
29
29
|
* mapMatches: isMatching =>
|
|
30
30
|
* Message.ChangedReducedMotion({ isReducedMotion: isMatching }),
|
|
@@ -33,7 +33,7 @@ import { Effect, Queue, Stream } from 'effect';
|
|
|
33
33
|
* }))
|
|
34
34
|
* ```
|
|
35
35
|
*/
|
|
36
|
-
export const
|
|
36
|
+
export const streamFromMediaQuery = (config) => Stream.callback(queue => Effect.acquireRelease(Effect.sync(() => {
|
|
37
37
|
const mediaQueryList = window.matchMedia(config.query);
|
|
38
38
|
const handleChange = (event) => {
|
|
39
39
|
Queue.offerUnsafe(queue, config.mapMatches(event.matches));
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Schema } from 'effect';
|
|
2
|
+
import type { RenderedApplication } from './server.js';
|
|
3
|
+
/** Browser assets supplied to the server entry's document renderer.
|
|
4
|
+
*
|
|
5
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
6
|
+
*/
|
|
7
|
+
export declare const DocumentAssets: Schema.Struct<{
|
|
8
|
+
readonly entryScript: Schema.String;
|
|
9
|
+
readonly stylesheets: Schema.$Array<Schema.String>;
|
|
10
|
+
readonly modulePreloads: Schema.$Array<Schema.String>;
|
|
11
|
+
}>;
|
|
12
|
+
/** The resolved browser asset URLs for one document.
|
|
13
|
+
*
|
|
14
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
15
|
+
*/
|
|
16
|
+
export type DocumentAssets = typeof DocumentAssets.Type;
|
|
17
|
+
/** Produces a complete HTML document from application markup and browser assets.
|
|
18
|
+
*
|
|
19
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
20
|
+
*/
|
|
21
|
+
export type DocumentRenderer = (application: RenderedApplication, assets: DocumentAssets) => string;
|
|
22
|
+
/** Author-owned defaults and additional head markup for {@link renderDocument}.
|
|
23
|
+
*
|
|
24
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
25
|
+
*/
|
|
26
|
+
export type DocumentOptions = Readonly<{
|
|
27
|
+
/** Default language, overridden by the application's Document. Defaults to English. */
|
|
28
|
+
lang?: string;
|
|
29
|
+
/** Trusted HTML to add to the head, such as a favicon or site-wide metadata. Never pass unescaped request data. */
|
|
30
|
+
head?: string;
|
|
31
|
+
}>;
|
|
32
|
+
/** Renders a complete document with UTF-8, a viewport, application metadata,
|
|
33
|
+
* stylesheets, module preloads, and the client entry. The application supplies
|
|
34
|
+
* the title, language, direction, canonical URL, and Open Graph URL. Additional
|
|
35
|
+
* head markup belongs to the server entry through {@link DocumentOptions}.
|
|
36
|
+
*
|
|
37
|
+
* The rendered application's hydration markers and Flags payload are preserved.
|
|
38
|
+
* Ambiguous application roots or handoff markers are rejected.
|
|
39
|
+
*
|
|
40
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
41
|
+
*/
|
|
42
|
+
export declare const renderDocument: (application: RenderedApplication, assets: DocumentAssets, options?: DocumentOptions) => string;
|
|
43
|
+
//# sourceMappingURL=document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../../../src/experimental/server/document.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAG/B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAGtD;;;GAGG;AACH,eAAO,MAAM,cAAc;;;;EAIzB,CAAA;AAEF;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,cAAc,CAAC,IAAI,CAAA;AAEvD;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,WAAW,EAAE,mBAAmB,EAChC,MAAM,EAAE,cAAc,KACnB,MAAM,CAAA;AAEX;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,uFAAuF;IACvF,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,mHAAmH;IACnH,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAC,CAAA;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,gBACZ,mBAAmB,UACxB,cAAc,YACb,eAAe,KACvB,MA4BF,CAAA"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Schema } from 'effect';
|
|
2
|
+
import { escapeAttributeValue } from './serialize.js';
|
|
3
|
+
import { injectIntoTemplate } from './template.js';
|
|
4
|
+
/** Browser assets supplied to the server entry's document renderer.
|
|
5
|
+
*
|
|
6
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
7
|
+
*/
|
|
8
|
+
export const DocumentAssets = Schema.Struct({
|
|
9
|
+
entryScript: Schema.String,
|
|
10
|
+
stylesheets: Schema.Array(Schema.String),
|
|
11
|
+
modulePreloads: Schema.Array(Schema.String),
|
|
12
|
+
});
|
|
13
|
+
/** Renders a complete document with UTF-8, a viewport, application metadata,
|
|
14
|
+
* stylesheets, module preloads, and the client entry. The application supplies
|
|
15
|
+
* the title, language, direction, canonical URL, and Open Graph URL. Additional
|
|
16
|
+
* head markup belongs to the server entry through {@link DocumentOptions}.
|
|
17
|
+
*
|
|
18
|
+
* The rendered application's hydration markers and Flags payload are preserved.
|
|
19
|
+
* Ambiguous application roots or handoff markers are rejected.
|
|
20
|
+
*
|
|
21
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
22
|
+
*/
|
|
23
|
+
export const renderDocument = (application, assets, options = {}) => {
|
|
24
|
+
const stylesheets = assets.stylesheets.map(href => `<link rel="stylesheet" crossorigin href="${escapeAttributeValue(href)}">`);
|
|
25
|
+
const modulePreloads = assets.modulePreloads.map(href => `<link rel="modulepreload" crossorigin href="${escapeAttributeValue(href)}">`);
|
|
26
|
+
const canonical = application.canonical === undefined ? '' : '<link rel="canonical" href="">';
|
|
27
|
+
const ogUrl = application.ogUrl === undefined ? '' : '<meta property="og:url" content="">';
|
|
28
|
+
const document = [
|
|
29
|
+
'<!doctype html>',
|
|
30
|
+
`<html lang="${escapeAttributeValue(options.lang ?? 'en')}">`,
|
|
31
|
+
'<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title></title>',
|
|
32
|
+
canonical,
|
|
33
|
+
ogUrl,
|
|
34
|
+
options.head ?? '',
|
|
35
|
+
...modulePreloads,
|
|
36
|
+
...stylesheets,
|
|
37
|
+
'</head><body><div id="root"></div>',
|
|
38
|
+
`<script type="module" crossorigin src="${escapeAttributeValue(assets.entryScript)}"></script>`,
|
|
39
|
+
'</body></html>',
|
|
40
|
+
].join('\n');
|
|
41
|
+
return injectIntoTemplate(document, application);
|
|
42
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { DocumentRenderer } from './document.js';
|
|
1
2
|
import type { RenderedApplication } from './server.js';
|
|
2
3
|
import { type InjectIntoTemplateOptions } from './template.js';
|
|
3
4
|
/** Optional HTTP metadata for a rendered application.
|
|
@@ -8,8 +9,7 @@ export type ResponseOptions = Readonly<{
|
|
|
8
9
|
status?: number;
|
|
9
10
|
headers?: HeadersInit;
|
|
10
11
|
}>;
|
|
11
|
-
/** A server entry result whose application markup still needs
|
|
12
|
-
* the host's HTML template.
|
|
12
|
+
/** A server entry result whose application markup still needs a document.
|
|
13
13
|
*
|
|
14
14
|
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
15
15
|
*/
|
|
@@ -62,12 +62,19 @@ export type EntryResult = Rendered | Responded;
|
|
|
62
62
|
export type EntryModule = Readonly<{
|
|
63
63
|
renderPage: (request: Request) => Promise<EntryResult>;
|
|
64
64
|
}>;
|
|
65
|
-
/**
|
|
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.
|
|
65
|
+
/** The server entry shape used when the application renders the complete HTML document.
|
|
69
66
|
*
|
|
70
67
|
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
71
68
|
*/
|
|
72
|
-
export
|
|
69
|
+
export type DocumentEntryModule = EntryModule & Readonly<{
|
|
70
|
+
renderDocument: DocumentRenderer;
|
|
71
|
+
}>;
|
|
72
|
+
/** Turns a server entry result into the Web `Response` a host sends. Supply a
|
|
73
|
+
* document renderer, or an HTML template for a host that owns one. Rendered
|
|
74
|
+
* applications default to status 200 with a UTF-8 HTML content type. Complete
|
|
75
|
+
* responses pass through unchanged without calling the document renderer.
|
|
76
|
+
*
|
|
77
|
+
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
78
|
+
*/
|
|
79
|
+
export declare const toResponse: (document: string | ((application: RenderedApplication) => string), result: EntryResult, options?: InjectIntoTemplateOptions) => Response;
|
|
73
80
|
//# sourceMappingURL=entry.d.ts.map
|
|
@@ -1 +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
|
|
1
|
+
{"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../../../src/experimental/server/entry.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACrD,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;;;GAGG;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,gBACN,mBAAmB,YACtB,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,aAAc,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;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,WAAW,GAC3C,QAAQ,CAAC;IACP,cAAc,EAAE,gBAAgB,CAAA;CACjC,CAAC,CAAA;AAEJ;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,aACX,MAAM,GAAG,CAAC,CAAC,WAAW,EAAE,mBAAmB,KAAK,MAAM,CAAC,UACzD,WAAW,YACT,yBAAyB,KAClC,QAqBA,CAAA"}
|
|
@@ -19,21 +19,23 @@ export const Responded = (response) => ({
|
|
|
19
19
|
_tag: 'Responded',
|
|
20
20
|
response,
|
|
21
21
|
});
|
|
22
|
-
/** Turns a server entry result into the Web `Response` a host sends.
|
|
23
|
-
*
|
|
24
|
-
* 200 with a UTF-8 HTML content type. Complete
|
|
25
|
-
* unchanged.
|
|
22
|
+
/** Turns a server entry result into the Web `Response` a host sends. Supply a
|
|
23
|
+
* document renderer, or an HTML template for a host that owns one. Rendered
|
|
24
|
+
* applications default to status 200 with a UTF-8 HTML content type. Complete
|
|
25
|
+
* responses pass through unchanged without calling the document renderer.
|
|
26
26
|
*
|
|
27
27
|
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
28
28
|
*/
|
|
29
|
-
export const toResponse = (
|
|
29
|
+
export const toResponse = (document, result, options) => Match.value(result).pipe(Match.tagsExhaustive({
|
|
30
30
|
Responded: ({ response }) => response,
|
|
31
31
|
Rendered: rendered => {
|
|
32
32
|
const headers = new Headers(rendered.headers);
|
|
33
33
|
if (!headers.has('content-type')) {
|
|
34
34
|
headers.set('content-type', 'text/html; charset=utf-8');
|
|
35
35
|
}
|
|
36
|
-
return new Response(
|
|
36
|
+
return new Response(typeof document === 'function'
|
|
37
|
+
? document(rendered.application)
|
|
38
|
+
: injectIntoTemplate(document, rendered.application, options), {
|
|
37
39
|
status: rendered.status ?? 200,
|
|
38
40
|
headers,
|
|
39
41
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type EntryResult } from './entry.js';
|
|
2
|
+
import type { RenderedApplication } from './server.js';
|
|
2
3
|
/** How {@link handleRequest} renders a page request.
|
|
3
4
|
*
|
|
4
5
|
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
@@ -9,16 +10,18 @@ export type HandleRequestOptions = Readonly<{
|
|
|
9
10
|
* result out.
|
|
10
11
|
*/
|
|
11
12
|
renderPage: (request: Request) => Promise<EntryResult>;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
}> & (Readonly<{
|
|
14
|
+
/** Produces the complete HTML document for a rendered application. */
|
|
15
|
+
renderDocument: (application: RenderedApplication) => string;
|
|
16
|
+
template?: never;
|
|
17
|
+
containerId?: never;
|
|
18
|
+
}> | Readonly<{
|
|
19
|
+
/** The unfilled HTML shell owned by a custom host. */
|
|
15
20
|
template: string;
|
|
16
|
-
/**
|
|
17
|
-
* The `id` of the empty container in {@link template} the rendered
|
|
18
|
-
* markup replaces. Defaults to `'root'`.
|
|
19
|
-
*/
|
|
21
|
+
/** The empty container replaced by the application. Defaults to `'root'`. */
|
|
20
22
|
containerId?: string;
|
|
21
|
-
|
|
23
|
+
renderDocument?: never;
|
|
24
|
+
}>);
|
|
22
25
|
/**
|
|
23
26
|
* Answers one request as a Web `fetch` handler: refuse methods the
|
|
24
27
|
* `Request` constructor cannot represent, classify a static miss so a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../../src/experimental/server/fetch.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../../src/experimental/server/fetch.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,WAAW,EAAc,MAAM,YAAY,CAAA;AAUzD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAGtD;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAC1C;;;OAGG;IACH,UAAU,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,WAAW,CAAC,CAAA;CACvD,CAAC,GACA,CACI,QAAQ,CAAC;IACP,sEAAsE;IACtE,cAAc,EAAE,CAAC,WAAW,EAAE,mBAAmB,KAAK,MAAM,CAAA;IAC5D,QAAQ,CAAC,EAAE,KAAK,CAAA;IAChB,WAAW,CAAC,EAAE,KAAK,CAAA;CACpB,CAAC,GACF,QAAQ,CAAC;IACP,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAA;IAChB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,cAAc,CAAC,EAAE,KAAK,CAAA;CACvB,CAAC,CACL,CAAA;AA8CH;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,aAAa,YACf,OAAO,WACP,oBAAoB,KAC5B,OAAO,CAAC,QAAQ,CAiDlB,CAAA"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Predicate } from 'effect';
|
|
1
2
|
import { toResponse } from './entry.js';
|
|
2
3
|
import { HOST_METHOD_ANSWERS, acceptsHtml, classifyRequest, isHostSettledMethod, resolvesToIndexHtml, varyWith, varyWithAccept, } from './host.js';
|
|
3
4
|
const withNegotiatedVary = (response) => {
|
|
@@ -16,6 +17,18 @@ const emptyResponse = (status, headers) => {
|
|
|
16
17
|
return new Response(null, { status, headers });
|
|
17
18
|
};
|
|
18
19
|
const injectOptions = (containerId) => containerId === undefined ? undefined : { containerId };
|
|
20
|
+
const documentFrom = (options) => {
|
|
21
|
+
const { renderDocument, template } = options;
|
|
22
|
+
if (Predicate.isFunction(renderDocument) && template === undefined) {
|
|
23
|
+
return renderDocument;
|
|
24
|
+
}
|
|
25
|
+
else if (Predicate.isString(template) && renderDocument === undefined) {
|
|
26
|
+
return template;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
throw new Error('[foldkit] handleRequest requires exactly one document source: a renderDocument function or an HTML template string.');
|
|
30
|
+
}
|
|
31
|
+
};
|
|
19
32
|
/**
|
|
20
33
|
* Answers one request as a Web `fetch` handler: refuse methods the
|
|
21
34
|
* `Request` constructor cannot represent, classify a static miss so a
|
|
@@ -62,10 +75,12 @@ export const handleRequest = async (request, options) => {
|
|
|
62
75
|
});
|
|
63
76
|
}
|
|
64
77
|
}
|
|
78
|
+
const document = documentFrom(options);
|
|
65
79
|
const result = await options.renderPage(request);
|
|
66
|
-
const rendered = toResponse(
|
|
80
|
+
const rendered = toResponse(document, result, injectOptions(options.containerId));
|
|
67
81
|
let response = rendered;
|
|
68
82
|
if (method === 'HEAD') {
|
|
83
|
+
await rendered.body?.cancel();
|
|
69
84
|
response = emptyResponse(rendered.status, rendered.headers);
|
|
70
85
|
}
|
|
71
86
|
if (negotiated) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/experimental/server/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/experimental/server/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { FOLDKIT_APP_ATTRIBUTE, FOLDKIT_FLAGS_ATTRIBUTE, FlagsEncodeError, HOST_METHOD_ANSWERS, InvalidHydrationRoot, InvalidRuntimeId, InvalidUrl, MissingBuildId, Rendered, Responded, SerializationError, acceptsHtml, classifyRequest, handleRequest, injectIntoTemplate, isHostSettledMethod, renderToString, resolveRequestUrl, resolvesToIndexHtml, toResponse, varyWith, varyWithAccept, } from './index.js';
|
|
2
|
-
export type { HandleRequestOptions, InjectIntoTemplateOptions, RequestClassification, ResponseOptions, RenderedApplication, HydratableRenderOptions, StaticRenderOptions, RenderOptions, RenderUrlOptions, RenderFlagsOptions, RenderUrlFlagsOptions, ApplicationConfig, ApplicationConfigWithFlags, EntryModule, EntryResult, RenderError, RoutingApplicationConfig, RoutingApplicationConfigWithFlags, } from './index.js';
|
|
1
|
+
export { DocumentAssets, FOLDKIT_APP_ATTRIBUTE, FOLDKIT_FLAGS_ATTRIBUTE, FlagsEncodeError, HOST_METHOD_ANSWERS, InvalidHydrationRoot, InvalidRuntimeId, InvalidUrl, MissingBuildId, Rendered, Responded, SerializationError, acceptsHtml, classifyRequest, handleRequest, injectIntoTemplate, isHostSettledMethod, renderToString, renderDocument, resolveRequestUrl, resolvesToIndexHtml, toResponse, varyWith, varyWithAccept, } from './index.js';
|
|
2
|
+
export type { DocumentOptions, DocumentRenderer, HandleRequestOptions, InjectIntoTemplateOptions, RequestClassification, ResponseOptions, RenderedApplication, HydratableRenderOptions, StaticRenderOptions, RenderOptions, RenderUrlOptions, RenderFlagsOptions, RenderUrlFlagsOptions, ApplicationConfig, ApplicationConfigWithFlags, DocumentEntryModule, EntryModule, EntryResult, RenderError, RoutingApplicationConfig, RoutingApplicationConfigWithFlags, } from './index.js';
|
|
3
3
|
//# sourceMappingURL=public.d.ts.map
|
|
@@ -1 +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,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACnB,UAAU,EACV,QAAQ,EACR,cAAc,GACf,MAAM,YAAY,CAAA;AAEnB,YAAY,EACV,oBAAoB,EACpB,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"}
|
|
1
|
+
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/experimental/server/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,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,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACnB,UAAU,EACV,QAAQ,EACR,cAAc,GACf,MAAM,YAAY,CAAA;AAEnB,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACpB,yBAAyB,EACzB,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACnB,uBAAuB,EACvB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,EACrB,iBAAiB,EACjB,0BAA0B,EAC1B,mBAAmB,EACnB,WAAW,EACX,WAAW,EACX,WAAW,EACX,wBAAwB,EACxB,iCAAiC,GAClC,MAAM,YAAY,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { FOLDKIT_APP_ATTRIBUTE, FOLDKIT_FLAGS_ATTRIBUTE, FlagsEncodeError, HOST_METHOD_ANSWERS, InvalidHydrationRoot, InvalidRuntimeId, InvalidUrl, MissingBuildId, Rendered, Responded, SerializationError, acceptsHtml, classifyRequest, handleRequest, injectIntoTemplate, isHostSettledMethod, renderToString, resolveRequestUrl, resolvesToIndexHtml, toResponse, varyWith, varyWithAccept, } from './index.js';
|
|
1
|
+
export { DocumentAssets, FOLDKIT_APP_ATTRIBUTE, FOLDKIT_FLAGS_ATTRIBUTE, FlagsEncodeError, HOST_METHOD_ANSWERS, InvalidHydrationRoot, InvalidRuntimeId, InvalidUrl, MissingBuildId, Rendered, Responded, SerializationError, acceptsHtml, classifyRequest, handleRequest, injectIntoTemplate, isHostSettledMethod, renderToString, renderDocument, resolveRequestUrl, resolvesToIndexHtml, toResponse, varyWith, varyWithAccept, } from './index.js';
|
|
@@ -8,7 +8,7 @@ export declare const __assertNoLiveBaseElement: (html: string) => void;
|
|
|
8
8
|
export declare const __assertNoDocumentStructureEscape: (html: string) => void;
|
|
9
9
|
export { FOLDKIT_APP_ATTRIBUTE, FOLDKIT_FLAGS_ATTRIBUTE };
|
|
10
10
|
/** The server render of one request: the body markup and the `Document` head
|
|
11
|
-
* fields for the
|
|
11
|
+
* fields for the document renderer or a custom host's template. Hydratable output
|
|
12
12
|
* contains a stamped root and, when the application declares Flags, its
|
|
13
13
|
* payload script. Static output carries no handoff markers.
|
|
14
14
|
*
|
package/dist/port/port.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export type OutboundTypeId = typeof OutboundTypeId;
|
|
|
10
10
|
/**
|
|
11
11
|
* A typed channel for values flowing from the host into the app. The app
|
|
12
12
|
* consumes the decoded values as a Subscription source via `Port.stream` or
|
|
13
|
-
* `Port.
|
|
13
|
+
* `Port.subscriptionEntry`; the host pushes encoded values through the
|
|
14
14
|
* `EmbedHandle` returned by `Runtime.embed`. Create with `Port.inbound`.
|
|
15
15
|
*/
|
|
16
16
|
export interface Inbound<Value, Encoded> {
|
|
@@ -94,7 +94,7 @@ export declare const __makeInboundChannel: () => __InboundChannel;
|
|
|
94
94
|
/**
|
|
95
95
|
* The decoded values arriving on an inbound Port, as a Stream. This is the
|
|
96
96
|
* atomic primitive for consuming a Port inside a Subscription entry; reach
|
|
97
|
-
* for `Port.
|
|
97
|
+
* for `Port.subscriptionEntry` when you want the common always-on form. Values
|
|
98
98
|
* sent while no Stream for the Port is running are dropped, except for
|
|
99
99
|
* values sent before the first Stream attaches, which are buffered and
|
|
100
100
|
* delivered to it in order (so host sends issued right after `Runtime.embed`
|
|
@@ -103,21 +103,21 @@ export declare const __makeInboundChannel: () => __InboundChannel;
|
|
|
103
103
|
export declare const stream: <Value, Encoded>(port: Inbound<Value, Encoded>) => Stream.Stream<Value>;
|
|
104
104
|
/**
|
|
105
105
|
* Builds a Subscription entry that wraps every decoded value arriving on an
|
|
106
|
-
* inbound Port into a Message. The entry
|
|
107
|
-
*
|
|
108
|
-
* inside `Subscription.make`. For
|
|
109
|
-
* from `Port.stream`.
|
|
106
|
+
* inbound Port into a Message. The entry has no Model dependencies of its own,
|
|
107
|
+
* though a parent can gate it when lifting the Subscription. Pass it as an
|
|
108
|
+
* entry value inside `Subscription.make`. For an entry gated by its own Model,
|
|
109
|
+
* build one from `Port.stream`.
|
|
110
110
|
*
|
|
111
111
|
* @example
|
|
112
112
|
* ```ts
|
|
113
113
|
* const subscriptions = Subscription.make<Model, Message>()(_entry => ({
|
|
114
|
-
* hostStep: Port.
|
|
114
|
+
* hostStep: Port.subscriptionEntry(ports.inbound.stepChanged, step =>
|
|
115
115
|
* ChangedStep({ step }),
|
|
116
116
|
* ),
|
|
117
117
|
* }))
|
|
118
118
|
* ```
|
|
119
119
|
*/
|
|
120
|
-
export declare const
|
|
120
|
+
export declare const subscriptionEntry: <Value, Encoded, Message>(port: Inbound<Value, Encoded>, toMessage: (value: Value) => Message) => import("../subscription/subscription.js").EntryWithoutKeepAlive<unknown, Message, Record<string, never>, never>;
|
|
121
121
|
/**
|
|
122
122
|
* Emits a value on an outbound Port. The value is encoded against the Port's
|
|
123
123
|
* Schema and delivered to every host listener subscribed through the
|
package/dist/port/port.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"port.d.ts","sourceRoot":"","sources":["../../src/port/port.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"port.d.ts","sourceRoot":"","sources":["../../src/port/port.ts"],"names":[],"mappings":"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"}
|