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.
Files changed (58) hide show
  1. package/dist/command/index.d.ts +4 -4
  2. package/dist/command/index.js +4 -4
  3. package/dist/dom/index.d.ts +6 -0
  4. package/dist/dom/index.d.ts.map +1 -1
  5. package/dist/dom/index.js +3 -0
  6. package/dist/dom/public.d.ts +2 -2
  7. package/dist/dom/public.d.ts.map +1 -1
  8. package/dist/dom/public.js +1 -1
  9. package/dist/{subscription/fromEvent.d.ts → dom/streamFromEvent.d.ts} +31 -31
  10. package/dist/dom/streamFromEvent.d.ts.map +1 -0
  11. package/dist/{subscription/fromEvent.js → dom/streamFromEvent.js} +20 -20
  12. package/dist/{subscription/keyBindings.d.ts → dom/streamFromKeyBindings.d.ts} +7 -7
  13. package/dist/dom/streamFromKeyBindings.d.ts.map +1 -0
  14. package/dist/{subscription/keyBindings.js → dom/streamFromKeyBindings.js} +62 -17
  15. package/dist/{subscription/fromMediaQuery.d.ts → dom/streamFromMediaQuery.d.ts} +7 -7
  16. package/dist/dom/streamFromMediaQuery.d.ts.map +1 -0
  17. package/dist/{subscription/fromMediaQuery.js → dom/streamFromMediaQuery.js} +4 -4
  18. package/dist/experimental/server/document.d.ts +43 -0
  19. package/dist/experimental/server/document.d.ts.map +1 -0
  20. package/dist/experimental/server/document.js +42 -0
  21. package/dist/experimental/server/entry.d.ts +14 -7
  22. package/dist/experimental/server/entry.d.ts.map +1 -1
  23. package/dist/experimental/server/entry.js +8 -6
  24. package/dist/experimental/server/fetch.d.ts +11 -8
  25. package/dist/experimental/server/fetch.d.ts.map +1 -1
  26. package/dist/experimental/server/fetch.js +16 -1
  27. package/dist/experimental/server/index.d.ts +1 -0
  28. package/dist/experimental/server/index.d.ts.map +1 -1
  29. package/dist/experimental/server/index.js +1 -0
  30. package/dist/experimental/server/public.d.ts +2 -2
  31. package/dist/experimental/server/public.d.ts.map +1 -1
  32. package/dist/experimental/server/public.js +1 -1
  33. package/dist/experimental/server/server.d.ts +1 -1
  34. package/dist/port/port.d.ts +8 -8
  35. package/dist/port/port.d.ts.map +1 -1
  36. package/dist/port/port.js +8 -8
  37. package/dist/port/public.d.ts +1 -1
  38. package/dist/port/public.d.ts.map +1 -1
  39. package/dist/port/public.js +1 -1
  40. package/dist/subscription/animationFrame.d.ts +4 -4
  41. package/dist/subscription/animationFrame.d.ts.map +1 -1
  42. package/dist/subscription/animationFrame.js +3 -3
  43. package/dist/subscription/public.d.ts +2 -8
  44. package/dist/subscription/public.d.ts.map +1 -1
  45. package/dist/subscription/public.js +2 -5
  46. package/dist/subscription/subscription.d.ts +9 -9
  47. package/dist/subscription/subscription.d.ts.map +1 -1
  48. package/dist/subscription/subscription.js +6 -6
  49. package/dist/update/public.d.ts +2 -2
  50. package/dist/update/public.d.ts.map +1 -1
  51. package/dist/update/public.js +1 -1
  52. package/dist/update/update.d.ts +109 -0
  53. package/dist/update/update.d.ts.map +1 -1
  54. package/dist/update/update.js +70 -0
  55. package/package.json +1 -1
  56. package/dist/subscription/fromEvent.d.ts.map +0 -1
  57. package/dist/subscription/fromMediaQuery.d.ts.map +0 -1
  58. 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 instanceof HTMLElement)) {
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(navigator.userAgent) ? 'Meta' : 'Control';
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 (typeof navigator === 'undefined') {
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.some(resolveModKey(undefined));
210
+ return Option.map(resolveKnownOwnerWindow(target), ownerWindow => resolveModKey(undefined, ownerWindow.navigator.userAgent));
194
211
  };
195
- const compileKeyBindingsConfig = (config) => {
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 instanceof KeyboardEvent)) {
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 instanceof Document) {
368
+ if (isKeyBindingDocument(target)) {
329
369
  return target;
330
370
  }
331
- if (target instanceof Node && target.ownerDocument !== null) {
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 modKey = resolveModKey(config.modKey);
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.persistent` for a fixed table. When availability depends on
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
- * Subscription.keyBindings<Message>({
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 keyBindings = (config) => keyBindingStream(compileKeyBindingsConfig(config));
490
+ export const streamFromKeyBindings = (config) => keyBindingStream(compileStreamFromKeyBindingsConfig(config));
@@ -1,6 +1,6 @@
1
1
  import { Stream } from 'effect';
2
2
  /**
3
- * Options for `fromMediaQuery`.
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 FromMediaQueryConfig<Output> = Readonly<{
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.persistent` for a query the application always follows. To
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.persistent(
47
- * Subscription.fromMediaQuery({
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 fromMediaQuery: <Output>(config: FromMediaQueryConfig<Output>) => Stream.Stream<Output>;
57
- //# sourceMappingURL=fromMediaQuery.d.ts.map
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.persistent` for a query the application always follows. To
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.persistent(
27
- * Subscription.fromMediaQuery({
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 fromMediaQuery = (config) => Stream.callback(queue => Effect.acquireRelease(Effect.sync(() => {
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 to be placed in
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
- /** 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.
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 declare const toResponse: (template: string, result: EntryResult, options?: InjectIntoTemplateOptions) => Response;
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;;;;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,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;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,aACX,MAAM,UACR,WAAW,YACT,yBAAyB,KAClC,QAmBA,CAAA"}
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. 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.
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 = (template, result, options) => Match.value(result).pipe(Match.tagsExhaustive({
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(injectIntoTemplate(template, rendered.application, options), {
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
- * The unfilled HTML shell. Rendered markup is placed into its container.
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":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAc,MAAM,YAAY,CAAA;AAYzD;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAC1C;;;OAGG;IACH,UAAU,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,WAAW,CAAC,CAAA;IACtD;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAC,CAAA;AA8BF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,aAAa,YACf,OAAO,WACP,oBAAoB,KAC5B,OAAO,CAAC,QAAQ,CA+ClB,CAAA"}
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(options.template, result, injectOptions(options.containerId));
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,3 +1,4 @@
1
+ export * from './document.js';
1
2
  export * from './entry.js';
2
3
  export * from './fetch.js';
3
4
  export * from './host.js';
@@ -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,4 @@
1
+ export * from './document.js';
1
2
  export * from './entry.js';
2
3
  export * from './fetch.js';
3
4
  export * from './host.js';
@@ -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 host to place into its HTML template. Hydratable output
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
  *
@@ -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.subscription`; the host pushes encoded values through the
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.subscription` when you want the common always-on form. Values
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 is persistent: it runs for the
107
- * runtime's lifetime, independent of the Model. Pass it as an entry value
108
- * inside `Subscription.make`. For a Model-gated entry, build one yourself
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.subscription(ports.inbound.stepChanged, step =>
114
+ * hostStep: Port.subscriptionEntry(ports.inbound.stepChanged, step =>
115
115
  * ChangedStep({ step }),
116
116
  * ),
117
117
  * }))
118
118
  * ```
119
119
  */
120
- export declare const subscription: <Value, Encoded, Message>(port: Inbound<Value, Encoded>, toMessage: (value: Value) => Message) => import("../subscription/subscription.js").EntryWithoutKeepAlive<unknown, Message, Record<string, never>, never>;
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
@@ -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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"}