@async/framework 0.11.15 → 0.11.17

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/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.11.17 - 2026-06-19
4
+
5
+ - Added the stream backpatch protocol to `createBoundaryReceiver(...)` with
6
+ strict `attrs` validation for built numeric triples and no-build named
7
+ tuples.
8
+ - Added pending-slot replacement and reveal coordination for `as-ready`,
9
+ `forwards`, `backwards`, and `together` stream groups, including collapsed
10
+ and hidden tail visibility handling.
11
+ - Added the `AsyncStream` browser helper for no-build JSON stream patches,
12
+ template replacement, configured `data-async-*` attributes, and direct-child
13
+ reveal metadata synthesis.
14
+ - Added stream backpatch scenario-size coverage and updated browser scenario
15
+ budgets for the expanded public stream surface.
16
+ - Bundle size from bundled TypeScript source: `browser.ts` raw 221,403 B (221.4 KB / 0.221 MB), gzip 42,093 B (42.1 KB / 0.042 MB), br 34,797 B (34.8 KB / 0.035 MB) -> `browser.min.js` raw 95,027 B (95.0 KB / 0.095 MB), gzip 28,145 B (28.1 KB / 0.028 MB), br 24,793 B (24.8 KB / 0.025 MB); delta raw -126,376 B (-126.4 KB / -0.126 MB), gzip -13,948 B (-13.9 KB / -0.014 MB), br -10,004 B (-10.0 KB / -0.010 MB).
17
+
18
+ ## 0.11.16 - 2026-06-19
19
+
20
+ - Added runtime slice entrypoints for `@async/framework/runtime`,
21
+ `@async/framework/runtime/signals`, and `@async/framework/runtime/events`.
22
+ - Added generated package artifacts and installed-package coverage for runtime
23
+ slice subpaths.
24
+ - Added deterministic scenario-size fixtures and checks for runtime, router,
25
+ server-call, and boundary receiver examples.
26
+ - Added package-owned release evidence checks before release ensure so generated
27
+ release workflows verify bundle and scenario evidence before publishing.
28
+ - Bundle size from bundled TypeScript source: `browser.ts` raw 197,173 B (197.2 KB / 0.197 MB), gzip 37,198 B (37.2 KB / 0.037 MB), br 30,914 B (30.9 KB / 0.031 MB) -> `browser.min.js` raw 84,013 B (84.0 KB / 0.084 MB), gzip 24,894 B (24.9 KB / 0.025 MB), br 22,079 B (22.1 KB / 0.022 MB); delta raw -113,160 B (-113.2 KB / -0.113 MB), gzip -12,304 B (-12.3 KB / -0.012 MB), br -8,835 B (-8.8 KB / -0.009 MB).
29
+
3
30
  ## 0.11.15 - 2026-06-19
4
31
 
5
32
  - Made the source package private and kept its public surface to the minimal
package/README.md CHANGED
@@ -43,10 +43,10 @@ Async.start({ root: document });
43
43
 
44
44
  ## What It Is
45
45
 
46
- `@async/framework` is the Layer 1 runtime plus the first Layer 2 app/server
47
- primitives. It keeps the runtime small and explicit:
46
+ `@async/framework` is the L1 runtime plus the first L1.5 app/server and
47
+ streaming primitives. It keeps the runtime small and explicit:
48
48
 
49
- - No build step for Layer 1 consumers.
49
+ - No build step for L1 consumers.
50
50
  - No virtual DOM, diff path, hydration runtime, or component rerender loop.
51
51
  - Signals are the state boundary.
52
52
  - `Async.use(...)` registers app declarations before or after startup.
@@ -68,18 +68,14 @@ to the same runtime registries and HTML protocol.
68
68
  Async is designed as layers, so each level can stay useful without forcing the
69
69
  next level on every app.
70
70
 
71
- | Layer | Name | Requirement | Purpose |
71
+ | Shorthand | Name | Requirement | Purpose |
72
72
  | --- | --- | --- | --- |
73
- | 1 | Runtime bootloader | No build. CDN or direct ESM import. | Signals, async signals, scheduler, handlers, command events, lifecycle pseudo-events, scoped fragments, and boundary swaps. |
74
- | 2 | App/server layer | Light server integration. No app compiler required. | `Async.use(...)`, router modes, server function proxy, partial registry, SSR output, browser activation, and split browser/server cache. |
75
- | 3 | Authoring build | Build step required. | JSX, ESM, and TypeScript authoring that lowers into Layer 1 HTML attributes and Layer 2 registries. |
76
- | 4 | Chunk and resumability metadata | Build metadata required. | Lazy module manifests, visibility/prefetch hints, resource graphs, and resumability records that the bootloader can consume. |
77
- | 5 | Framework compiler | Compiler required. | Server/client partitioning, code motion, optimized registry generation, serialized closures, and deeper resumability transforms. |
78
- | 6 | TSRX and intent layer | Higher-level compiler required. | More declarative author intent, AI/compiler-friendly metadata, and source forms that generate lower-layer Async apps. |
79
-
80
- The package in this repository intentionally focuses on Layers 1 and 2. Layers
81
- 3 through 6 are higher authoring surfaces, not extra runtime requirements for
82
- plain HTML apps.
73
+ | L1 | Runtime bootloader | No build. CDN or direct ESM import. | Signals, async signals, scheduler, handlers, command events, lifecycle pseudo-events, scoped fragments, and boundary swaps. |
74
+ | L1.5 | App/server and streaming bridge | Light server integration. No app compiler required. | `Async.use(...)`, router modes, server function proxy, partial registry, SSR output, browser activation, split browser/server cache, and streamed boundary patches. |
75
+ | L2 | Build-required authoring and compiler profile | Build step required. | JSX, ESM, and TypeScript authoring, optimizer reports, generated plans, generated registries, chunks, manifests, and future resumability records that lower onto L1 and L1.5 protocols. |
76
+
77
+ The package in this repository intentionally focuses on L1 and L1.5. L2 is a
78
+ higher authoring surface, not an extra runtime requirement for plain HTML apps.
83
79
 
84
80
  ## Install
85
81
 
package/browser.d.ts CHANGED
@@ -513,10 +513,30 @@ export interface LoaderInstance {
513
513
  export type AsyncLoaderOptions = LoaderOptions;
514
514
  export type AsyncLoaderInstance = LoaderInstance;
515
515
 
516
+ export type AttributePatchValue = string | number | boolean | null | undefined;
517
+ export type BuiltAttributePatchTriples = readonly AttributePatchValue[];
518
+ export type NoBuildAttributePatchTuple = readonly [targetName: string, attrName: string, value: AttributePatchValue];
519
+ export type NoBuildAttributePatchTuples = readonly NoBuildAttributePatchTuple[];
520
+ export interface StreamReplacement {
521
+ target: string;
522
+ html?: TemplateLike;
523
+ template?: string;
524
+ mode?: "pending" | "boundary";
525
+ }
526
+ export interface StreamRevealMetadata {
527
+ group: string;
528
+ index: number;
529
+ count: number;
530
+ order?: "as-ready" | "forwards" | "backwards" | "together";
531
+ tail?: "collapsed" | "hidden";
532
+ }
516
533
  export interface BoundaryPatch {
517
534
  boundary: string;
518
535
  seq: number;
519
536
  html?: TemplateLike;
537
+ replace?: StreamReplacement | readonly StreamReplacement[];
538
+ attrs?: BuiltAttributePatchTriples | NoBuildAttributePatchTuples;
539
+ reveal?: StreamRevealMetadata;
520
540
  signals?: Record<string, unknown>;
521
541
  cache?: { browser?: Record<string, unknown> };
522
542
  redirect?: string;
@@ -526,17 +546,24 @@ export interface BoundaryPatch {
526
546
  meta?: Record<string, unknown>;
527
547
  }
528
548
 
549
+ export interface BoundaryPatchCounts {
550
+ applied: number;
551
+ ignored?: number;
552
+ }
553
+
529
554
  export type BoundaryApplyResult =
530
- | { status: "applied"; boundary: string; seq: number }
555
+ | { status: "applied"; boundary: string; seq: number; attrs?: BoundaryPatchCounts; replace?: BoundaryPatchCounts }
556
+ | { status: "buffered"; boundary: string; seq: number; reveal: Required<Pick<StreamRevealMetadata, "group" | "index" | "count">> & Pick<StreamRevealMetadata, "order" | "tail"> }
531
557
  | { status: "ignored-stale"; boundary: string; seq: number; lastSeq: number }
532
558
  | { status: "ignored-destroyed"; boundary: string; seq: number; parentScope?: string }
533
- | { status: "redirected"; boundary: string; seq: number; redirect: string }
559
+ | { status: "redirected"; boundary: string; seq: number; redirect: string; attrs?: BoundaryPatchCounts; replace?: BoundaryPatchCounts }
534
560
  | { status: "errored"; boundary: string; seq: number; error: Error };
535
561
 
536
562
  export interface BoundaryReceiverInspection {
537
563
  destroyed: boolean;
538
564
  boundaries: Record<string, { lastSeq: number; applied: number; ignored: number; errored?: number; lastStatus?: BoundaryApplyResult["status"] }>;
539
- recent: Array<{ boundary: string; seq: number; status: BoundaryApplyResult["status"]; lastSeq?: number; parentScope?: string; redirect?: string }>;
565
+ reveal: Record<string, { count: number; order: string; tail?: string; pending: number[]; committed: number[] }>;
566
+ recent: Array<{ boundary: string; seq: number; status: BoundaryApplyResult["status"]; lastSeq?: number; parentScope?: string; redirect?: string; attrs?: BoundaryPatchCounts; replace?: BoundaryPatchCounts; reveal?: StreamRevealMetadata }>;
540
567
  }
541
568
 
542
569
  export interface BoundaryReceiverOptions {
@@ -545,6 +572,7 @@ export interface BoundaryReceiverOptions {
545
572
  cache?: CacheRegistry;
546
573
  scheduler?: Scheduler;
547
574
  router?: Router;
575
+ attributes?: AttributeConfig;
548
576
  onApply?(result: BoundaryApplyResult, patch: BoundaryPatch): void;
549
577
  onIgnore?(result: BoundaryApplyResult, patch: BoundaryPatch): void;
550
578
  onError?(error: Error, result: BoundaryApplyResult, patch: BoundaryPatch): void;
@@ -560,6 +588,18 @@ export interface BoundaryReceiver {
560
588
  destroy(): void;
561
589
  }
562
590
 
591
+ export interface AsyncStreamApplyOptions extends Partial<BoundaryReceiverOptions> {
592
+ receiver?: BoundaryReceiver;
593
+ runtime?: AppRuntime;
594
+ root?: Document | Element | DocumentFragment;
595
+ }
596
+
597
+ export interface AsyncStreamNamespace {
598
+ applyScript(script: Element, options?: AsyncStreamApplyOptions): Promise<BoundaryApplyResult>;
599
+ applyCurrentScript(script?: Element, options?: AsyncStreamApplyOptions): Promise<BoundaryApplyResult>;
600
+ applyCurrentScript(options?: AsyncStreamApplyOptions): Promise<BoundaryApplyResult>;
601
+ }
602
+
563
603
  export interface RegistryStore {
564
604
  target: RuntimeTarget;
565
605
  register(type: RegistryType, id: string, value: unknown): string;
@@ -696,6 +736,7 @@ export interface AsyncNamespace extends AppHub {
696
736
  inspectRoots: AppHub["inspectRoots"];
697
737
  attributeName: typeof attributeName;
698
738
  defineAttributeConfig: typeof defineAttributeConfig;
739
+ AsyncStream: AsyncStreamNamespace;
699
740
  createBoundaryReceiver: typeof createBoundaryReceiver;
700
741
  createCacheRegistry: typeof createCacheRegistry;
701
742
  defineCache: typeof defineCache;
@@ -736,6 +777,7 @@ export declare function defineApp(initial?: AppDefinition): AppHub;
736
777
  export declare function readSnapshot(root?: Document | Element, options?: { attributes?: AttributeConfig }): RegistryRuntimeSnapshot;
737
778
  export declare function attributeName(attributes: AttributeConfig | undefined, type: keyof NormalizedAttributeConfig, name: string): string;
738
779
  export declare function defineAttributeConfig(config?: AttributeConfig): NormalizedAttributeConfig;
780
+ export declare const AsyncStream: AsyncStreamNamespace;
739
781
  export declare function createBoundaryReceiver(options: BoundaryReceiverOptions): BoundaryReceiver;
740
782
  export declare function createCacheRegistry(initialMap?: Record<string, CacheDefinition | CacheDefinitionOptions>, options?: { now?: () => number; registry?: RegistryStore; type?: "cache.browser" | "cache.server" }): CacheRegistry;
741
783
  export declare function defineCache(options?: CacheDefinitionOptions): CacheDefinition;