octane 0.2.12 → 0.2.13

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 (243) hide show
  1. package/README.md +5 -0
  2. package/dist/behavior-root.d.ts +13 -3
  3. package/dist/behavior-root.js +28 -5
  4. package/dist/cjs/behavior-root.cjs +32 -6
  5. package/dist/cjs/class-names.cjs +49 -0
  6. package/dist/cjs/constants.cjs +9 -0
  7. package/dist/cjs/css.cjs +6 -27
  8. package/dist/cjs/data-encoding.cjs +160 -0
  9. package/dist/cjs/dom-binding-handoff.cjs +93 -0
  10. package/dist/cjs/dom-binding-protocol.cjs +115 -0
  11. package/dist/cjs/dom-binding-styles.cjs +292 -0
  12. package/dist/cjs/dom-bindings.cjs +700 -0
  13. package/dist/cjs/dom-focused-move.cjs +66 -0
  14. package/dist/cjs/dom-tables.cjs +4 -94
  15. package/dist/cjs/error-codes.client.generated.cjs +33 -0
  16. package/dist/cjs/error-codes.server.generated.cjs +19 -0
  17. package/dist/cjs/hydration/control-capture.cjs +244 -0
  18. package/dist/cjs/hydration/event-capture.cjs +125 -43
  19. package/dist/cjs/hydration/interaction-config.cjs +50 -2
  20. package/dist/cjs/hydration-markers.cjs +37 -0
  21. package/dist/cjs/independent-hydration-protocol.cjs +106 -0
  22. package/dist/cjs/index.cjs +6 -0
  23. package/dist/cjs/runtime.cjs +2791 -215
  24. package/dist/cjs/runtime.server.cjs +716 -76
  25. package/dist/cjs/server/early-signals.cjs +45 -0
  26. package/dist/cjs/server/index.cjs +44 -0
  27. package/dist/cjs/server/rpc-batch.cjs +149 -0
  28. package/dist/cjs/server/rpc-stream.cjs +146 -0
  29. package/dist/cjs/server/rpc.cjs +34 -15
  30. package/dist/cjs/server/signal-query-observation.cjs +158 -0
  31. package/dist/cjs/server/streamed-region.cjs +52 -0
  32. package/dist/cjs/server/streamed-signals.cjs +512 -0
  33. package/dist/cjs/server-call.cjs +103 -0
  34. package/dist/cjs/server-rpc-batch-client.cjs +141 -0
  35. package/dist/cjs/server-rpc-client.cjs +94 -27
  36. package/dist/cjs/server-rpc-protocol.cjs +141 -0
  37. package/dist/cjs/server-rpc-stream-client.cjs +118 -0
  38. package/dist/cjs/signals/actions.cjs +474 -0
  39. package/dist/cjs/signals/client.cjs +4 -1
  40. package/dist/cjs/signals/computations.cjs +460 -0
  41. package/dist/cjs/signals/control-binding.cjs +368 -0
  42. package/dist/cjs/signals/derived-facade.cjs +50 -0
  43. package/dist/cjs/signals/document-owner.cjs +71 -0
  44. package/dist/cjs/signals/early-values.cjs +155 -0
  45. package/dist/cjs/signals/encoding.cjs +6 -95
  46. package/dist/cjs/signals/engine.cjs +276 -12
  47. package/dist/cjs/signals/errors.cjs +18 -0
  48. package/dist/cjs/signals/facade.cjs +477 -0
  49. package/dist/cjs/signals/graph.cjs +163 -20
  50. package/dist/cjs/signals/handle-protocol.cjs +36 -0
  51. package/dist/cjs/signals/index.cjs +81 -2
  52. package/dist/cjs/signals/native-read-client.cjs +10 -0
  53. package/dist/cjs/signals/owner-context.cjs +112 -0
  54. package/dist/cjs/signals/query-attempt-observer.cjs +68 -0
  55. package/dist/cjs/signals/query-facade.cjs +72 -0
  56. package/dist/cjs/signals/read-protocol.cjs +32 -0
  57. package/dist/cjs/signals/requests.cjs +287 -14
  58. package/dist/cjs/signals/scalar-computations.cjs +76 -0
  59. package/dist/cjs/signals/server.cjs +4 -1
  60. package/dist/cjs/signals/transition-candidate.cjs +567 -0
  61. package/dist/cjs/signals/transition-state.cjs +106 -0
  62. package/dist/cjs/signals/types.cjs +50 -0
  63. package/dist/cjs/stream-protocol.cjs +3 -0
  64. package/dist/cjs/streamed-signals-protocol.cjs +159 -0
  65. package/dist/cjs/style-values.cjs +122 -0
  66. package/dist/cjs/version.cjs +1 -1
  67. package/dist/class-names.d.ts +5 -0
  68. package/dist/class-names.js +25 -0
  69. package/dist/compiler/bundler.js +34 -6
  70. package/dist/compiler/compile.js +2234 -559
  71. package/dist/compiler/dom-binding-program.js +935 -0
  72. package/dist/compiler/dom-binding-request.js +57 -0
  73. package/dist/compiler/dom-bindings.js +2245 -0
  74. package/dist/compiler/hook-deps.js +26 -0
  75. package/dist/compiler/hydrate-boundaries.js +358 -15
  76. package/dist/compiler/index.d.ts +38 -1
  77. package/dist/compiler/index.js +1 -0
  78. package/dist/compiler/native-attribute-reads.js +127 -0
  79. package/dist/compiler/native-read-diagnostics.js +48 -9
  80. package/dist/compiler/native-read-types.js +55 -32
  81. package/dist/compiler/server-context.js +118 -0
  82. package/dist/compiler/signal-attempt-reads.js +479 -0
  83. package/dist/compiler/signal-declarations.js +557 -0
  84. package/dist/compiler/signal-start-reads.js +413 -0
  85. package/dist/compiler/slot-hooks.js +57 -10
  86. package/dist/compiler/template-ir.js +200 -0
  87. package/dist/compiler/typescript.d.ts +2 -0
  88. package/dist/compiler/typescript.js +2 -0
  89. package/dist/compiler/vite.d.ts +3 -1
  90. package/dist/compiler/vite.js +122 -4
  91. package/dist/compiler/volar.d.ts +6 -1
  92. package/dist/compiler/volar.js +674 -143
  93. package/dist/constants.d.ts +1 -0
  94. package/dist/constants.js +10 -0
  95. package/dist/css.d.ts +2 -5
  96. package/dist/css.js +2 -23
  97. package/dist/data-encoding.d.ts +9 -0
  98. package/dist/data-encoding.js +134 -0
  99. package/dist/dom-binding-classes.d.ts +15 -0
  100. package/dist/dom-binding-classes.js +129 -0
  101. package/dist/dom-binding-controls.d.ts +2 -0
  102. package/dist/dom-binding-controls.js +6 -0
  103. package/dist/dom-binding-handoff.d.ts +55 -0
  104. package/dist/dom-binding-handoff.js +62 -0
  105. package/dist/dom-binding-program.d.ts +300 -0
  106. package/dist/dom-binding-program.js +1625 -0
  107. package/dist/dom-binding-projections.d.ts +15 -0
  108. package/dist/dom-binding-projections.js +187 -0
  109. package/dist/dom-binding-protocol.d.ts +13 -0
  110. package/dist/dom-binding-protocol.js +88 -0
  111. package/dist/dom-binding-signals.d.ts +21 -0
  112. package/dist/dom-binding-signals.js +109 -0
  113. package/dist/dom-binding-styles.d.ts +17 -0
  114. package/dist/dom-binding-styles.js +272 -0
  115. package/dist/dom-bindings.d.ts +89 -0
  116. package/dist/dom-bindings.js +670 -0
  117. package/dist/dom-focused-move.d.ts +6 -0
  118. package/dist/dom-focused-move.js +42 -0
  119. package/dist/dom-tables.d.ts +1 -3
  120. package/dist/dom-tables.js +1 -91
  121. package/dist/error-codes.client.generated.d.ts +9 -0
  122. package/dist/error-codes.client.generated.js +33 -0
  123. package/dist/error-codes.server.generated.d.ts +5 -0
  124. package/dist/error-codes.server.generated.js +19 -0
  125. package/dist/hydration/control-capture.d.ts +62 -0
  126. package/dist/hydration/control-capture.js +223 -0
  127. package/dist/hydration/document-lifecycle.d.ts +23 -0
  128. package/dist/hydration/document-lifecycle.js +80 -0
  129. package/dist/hydration/event-capture.d.ts +20 -1
  130. package/dist/hydration/event-capture.js +128 -42
  131. package/dist/hydration/independent-island.d.ts +45 -0
  132. package/dist/hydration/independent-island.js +233 -0
  133. package/dist/hydration/index.d.ts +8 -1
  134. package/dist/hydration/index.js +55 -1
  135. package/dist/hydration/interaction-config.d.ts +5 -0
  136. package/dist/hydration/interaction-config.js +44 -1
  137. package/dist/hydration/stream-delivery.d.ts +32 -0
  138. package/dist/hydration/stream-delivery.js +333 -0
  139. package/dist/hydration/stream-receiver.d.ts +26 -0
  140. package/dist/hydration/stream-receiver.js +204 -0
  141. package/dist/hydration/stream-result-receiver.d.ts +70 -0
  142. package/dist/hydration/stream-result-receiver.js +246 -0
  143. package/dist/hydration/streamed-signals.d.ts +44 -0
  144. package/dist/hydration/streamed-signals.js +186 -0
  145. package/dist/hydration/types.d.ts +6 -0
  146. package/dist/hydration-markers.d.ts +7 -0
  147. package/dist/hydration-markers.js +10 -0
  148. package/dist/independent-hydration-protocol.d.ts +31 -0
  149. package/dist/independent-hydration-protocol.js +80 -0
  150. package/dist/index.d.ts +2 -0
  151. package/dist/index.js +4 -0
  152. package/dist/internal/signal-read.d.ts +1 -0
  153. package/dist/internal/signal-read.js +4 -0
  154. package/dist/jsx-runtime.d.ts +45 -6
  155. package/dist/public-types.d.ts +15 -1
  156. package/dist/runtime.d.ts +259 -21
  157. package/dist/runtime.js +2812 -220
  158. package/dist/runtime.server.d.ts +86 -6
  159. package/dist/runtime.server.js +712 -76
  160. package/dist/server/early-signals.d.ts +14 -0
  161. package/dist/server/early-signals.js +34 -0
  162. package/dist/server/index.d.ts +10 -2
  163. package/dist/server/index.js +48 -1
  164. package/dist/server/rpc-batch.d.ts +17 -0
  165. package/dist/server/rpc-batch.js +129 -0
  166. package/dist/server/rpc-stream.d.ts +9 -0
  167. package/dist/server/rpc-stream.js +125 -0
  168. package/dist/server/rpc.d.ts +5 -1
  169. package/dist/server/rpc.js +37 -13
  170. package/dist/server/signal-query-observation.d.ts +3 -0
  171. package/dist/server/signal-query-observation.js +134 -0
  172. package/dist/server/streamed-region.d.ts +15 -0
  173. package/dist/server/streamed-region.js +30 -0
  174. package/dist/server/streamed-signals.d.ts +45 -0
  175. package/dist/server/streamed-signals.js +488 -0
  176. package/dist/server-call.d.ts +41 -0
  177. package/dist/server-call.js +75 -0
  178. package/dist/server-rpc-batch-client.d.ts +7 -0
  179. package/dist/server-rpc-batch-client.js +119 -0
  180. package/dist/server-rpc-client.d.ts +3 -1
  181. package/dist/server-rpc-client.js +99 -27
  182. package/dist/server-rpc-protocol.d.ts +47 -0
  183. package/dist/server-rpc-protocol.js +109 -0
  184. package/dist/server-rpc-stream-client.d.ts +5 -0
  185. package/dist/server-rpc-stream-client.js +98 -0
  186. package/dist/signals/actions.d.ts +12 -0
  187. package/dist/signals/actions.js +466 -0
  188. package/dist/signals/client.d.ts +2 -0
  189. package/dist/signals/client.js +1 -0
  190. package/dist/signals/computations.d.ts +37 -0
  191. package/dist/signals/computations.js +455 -0
  192. package/dist/signals/control-binding.d.ts +31 -0
  193. package/dist/signals/control-binding.js +353 -0
  194. package/dist/signals/derived-facade.d.ts +3 -0
  195. package/dist/signals/derived-facade.js +25 -0
  196. package/dist/signals/document-owner.d.ts +10 -0
  197. package/dist/signals/document-owner.js +43 -0
  198. package/dist/signals/early-values.d.ts +24 -0
  199. package/dist/signals/early-values.js +124 -0
  200. package/dist/signals/encoding.d.ts +1 -3
  201. package/dist/signals/encoding.js +3 -93
  202. package/dist/signals/engine.d.ts +53 -4
  203. package/dist/signals/engine.js +275 -16
  204. package/dist/signals/errors.d.ts +7 -0
  205. package/dist/signals/errors.js +16 -0
  206. package/dist/signals/facade.d.ts +74 -0
  207. package/dist/signals/facade.js +452 -0
  208. package/dist/signals/graph.d.ts +50 -5
  209. package/dist/signals/graph.js +170 -19
  210. package/dist/signals/handle-protocol.d.ts +4 -0
  211. package/dist/signals/handle-protocol.js +11 -0
  212. package/dist/signals/index.d.ts +12 -3
  213. package/dist/signals/index.js +71 -2
  214. package/dist/signals/native-read-client.d.ts +3 -0
  215. package/dist/signals/native-read-client.js +10 -0
  216. package/dist/signals/owner-context.d.ts +22 -0
  217. package/dist/signals/owner-context.js +77 -0
  218. package/dist/signals/query-attempt-observer.d.ts +49 -0
  219. package/dist/signals/query-attempt-observer.js +41 -0
  220. package/dist/signals/query-facade.d.ts +3 -0
  221. package/dist/signals/query-facade.js +49 -0
  222. package/dist/signals/read-protocol.d.ts +32 -3
  223. package/dist/signals/read-protocol.js +26 -0
  224. package/dist/signals/requests.d.ts +38 -5
  225. package/dist/signals/requests.js +298 -15
  226. package/dist/signals/scalar-computations.d.ts +2 -0
  227. package/dist/signals/scalar-computations.js +60 -0
  228. package/dist/signals/server.d.ts +2 -0
  229. package/dist/signals/server.js +1 -0
  230. package/dist/signals/transition-candidate.d.ts +71 -0
  231. package/dist/signals/transition-candidate.js +557 -0
  232. package/dist/signals/transition-state.d.ts +51 -0
  233. package/dist/signals/transition-state.js +70 -0
  234. package/dist/signals/types.d.ts +95 -5
  235. package/dist/signals/types.js +20 -0
  236. package/dist/stream-protocol.d.ts +0 -5
  237. package/dist/stream-protocol.js +3 -0
  238. package/dist/streamed-signals-protocol.d.ts +60 -0
  239. package/dist/streamed-signals-protocol.js +130 -0
  240. package/dist/style-values.d.ts +3 -0
  241. package/dist/style-values.js +96 -0
  242. package/dist/version.js +1 -1
  243. package/package.json +37 -1
@@ -0,0 +1,70 @@
1
+ import { type StreamedRegionPlacementFrame, type StreamedSignalResultFrame, type StreamFrameIdentity } from '../streamed-signals-protocol.js';
2
+ import type { HistoricalFrameLease, StreamedRegionRegistration } from './stream-receiver.js';
3
+ export interface StreamedResultConsumer {
4
+ /** False defers this validated frame; reattaching the same consumer retries its bounded mailbox. */
5
+ accept(frame: StreamedSignalResultFrame): void | false;
6
+ /** True transfers this bounded completed mailbox to consumer-owned retention, without publishing it. */
7
+ retainCompleted?(frames: StreamedSignalResultFrame[]): boolean;
8
+ fail(error: StreamedReceiverError): void;
9
+ }
10
+ export interface StreamedResultReceiverOptions {
11
+ readonly buildId: string;
12
+ readonly documentId: string;
13
+ readonly ownerKey: string;
14
+ readonly maxPendingFrames?: number;
15
+ readonly maxPendingBytes?: number;
16
+ readonly pendingTimeoutMs?: number;
17
+ readonly onError?: (error: StreamedReceiverError) => void;
18
+ }
19
+ export type StreamedFrameDisposition = 'accepted' | 'stale';
20
+ export declare class StreamedReceiverError extends Error {
21
+ readonly code: 'identity' | 'sequence' | 'protocol' | 'overflow' | 'timeout' | 'terminal' | 'styles' | 'historical-frame' | 'placement';
22
+ constructor(code: 'identity' | 'sequence' | 'protocol' | 'overflow' | 'timeout' | 'terminal' | 'styles' | 'historical-frame' | 'placement', message: string);
23
+ }
24
+ interface ResultState {
25
+ sequence: number;
26
+ opened: boolean;
27
+ resource?: 'promise' | 'stream';
28
+ values: number;
29
+ terminal: boolean;
30
+ frames: StreamedSignalResultFrame[];
31
+ bytes: number;
32
+ consumer?: StreamedResultConsumer;
33
+ timer?: ReturnType<typeof setTimeout>;
34
+ failure?: StreamedReceiverError;
35
+ }
36
+ export interface StreamedSelectionState {
37
+ identity: StreamFrameIdentity;
38
+ result: ResultState;
39
+ placementSequence: number;
40
+ contentRevision: number;
41
+ region?: StreamedRegionRegistration;
42
+ historical?: HistoricalFrameLease;
43
+ pendingPlacement?: {
44
+ cancel(): void;
45
+ };
46
+ failure?: StreamedReceiverError;
47
+ }
48
+ export interface StreamedResultReceiver {
49
+ registerSelection(identity: StreamFrameIdentity, contentRevision?: number): void;
50
+ attachResult(identity: StreamFrameIdentity, consumer: StreamedResultConsumer): () => void;
51
+ receive(frame: unknown): Promise<StreamedFrameDisposition>;
52
+ receiveJson(json: string): Promise<StreamedFrameDisposition>;
53
+ /** Fail only the exact current selection; false means stale or already failed. */
54
+ failSelection(identity: StreamFrameIdentity, error: StreamedReceiverError): boolean;
55
+ dispose(): void;
56
+ }
57
+ /**
58
+ * Accept streamed results without HTML placement. Valid unregistered placement
59
+ * frames still advance their sequence and return stale, as on the full receiver.
60
+ */
61
+ export declare function createStreamedResultReceiver(options: StreamedResultReceiverOptions): StreamedResultReceiver;
62
+ /**
63
+ * Internal static seam: the full receiver supplies DOM placement while both
64
+ * variants retain the same selection, result, failure and cleanup authority.
65
+ */
66
+ export declare function createStreamedResultReceiverState(options: StreamedResultReceiverOptions, commitPlacement?: (state: StreamedSelectionState, frame: StreamedRegionPlacementFrame, isCurrent: (state: StreamedSelectionState, identity: StreamFrameIdentity) => boolean) => Promise<StreamedFrameDisposition>): {
67
+ receiver: StreamedResultReceiver;
68
+ current: (identity: StreamFrameIdentity) => StreamedSelectionState | undefined;
69
+ };
70
+ export {};
@@ -0,0 +1,246 @@
1
+ import {
2
+ decodeStreamedRendererFrame,
3
+ isStreamedRendererFrame,
4
+ sameStreamFrameIdentity
5
+ } from "../streamed-signals-protocol.js";
6
+ class StreamedReceiverError extends Error {
7
+ constructor(code, message) {
8
+ super(message);
9
+ this.code = code;
10
+ this.name = "StreamedReceiverError";
11
+ }
12
+ code;
13
+ }
14
+ function retainCompletedResult(result) {
15
+ if (result.frames.at(-1)?.kind === "complete" && result.consumer?.retainCompleted?.(result.frames) === true) {
16
+ result.frames = [];
17
+ result.bytes = 0;
18
+ }
19
+ }
20
+ const DEFAULT_PENDING_FRAMES = 64;
21
+ const DEFAULT_PENDING_BYTES = 1024 * 1024;
22
+ const DEFAULT_PENDING_TIMEOUT = 3e4;
23
+ function counter(value, fallback) {
24
+ const result = value ?? fallback;
25
+ if (!Number.isSafeInteger(result) || result <= 0) {
26
+ throw new RangeError("Stream receiver limits must be positive safe integers.");
27
+ }
28
+ return result;
29
+ }
30
+ function slotKey(identity) {
31
+ return JSON.stringify([identity.instanceKey, identity.nodeKey]);
32
+ }
33
+ function frameBytes(frame) {
34
+ return new TextEncoder().encode(JSON.stringify(frame)).byteLength;
35
+ }
36
+ function createStreamedResultReceiver(options) {
37
+ return createStreamedResultReceiverState(options).receiver;
38
+ }
39
+ function createStreamedResultReceiverState(options, commitPlacement) {
40
+ const maxFrames = counter(options.maxPendingFrames, DEFAULT_PENDING_FRAMES);
41
+ const maxBytes = counter(options.maxPendingBytes, DEFAULT_PENDING_BYTES);
42
+ const timeoutMs = counter(options.pendingTimeoutMs, DEFAULT_PENDING_TIMEOUT);
43
+ const selections = /* @__PURE__ */ new Map();
44
+ let disposed = false;
45
+ const report = (error, state) => {
46
+ if (state !== void 0) {
47
+ if (state.failure !== void 0) return;
48
+ state.failure = error;
49
+ state.pendingPlacement?.cancel();
50
+ if (!state.result.terminal) {
51
+ state.result.failure = error;
52
+ try {
53
+ state.result.consumer?.fail(error);
54
+ } catch {
55
+ }
56
+ state.result.frames.length = 0;
57
+ state.result.bytes = 0;
58
+ }
59
+ if (state.result.timer !== void 0) clearTimeout(state.result.timer);
60
+ state.result.terminal = true;
61
+ }
62
+ options.onError?.(error);
63
+ };
64
+ const current = (identity) => {
65
+ if (identity.buildId !== options.buildId || identity.documentId !== options.documentId || identity.ownerKey !== options.ownerKey) {
66
+ return;
67
+ }
68
+ const state = selections.get(slotKey(identity));
69
+ return state !== void 0 && sameStreamFrameIdentity(state.identity, identity) ? state : void 0;
70
+ };
71
+ const isCurrent = (state, identity) => !disposed && state.failure === void 0 && current(identity) === state;
72
+ const registerSelection = (identity, contentRevision = 0) => {
73
+ if (!isStreamedRendererFrame({
74
+ identity,
75
+ sequence: 0,
76
+ channel: "result",
77
+ kind: "complete"
78
+ })) {
79
+ throw new StreamedReceiverError("identity", "Invalid streamed selection identity.");
80
+ }
81
+ if (identity.buildId !== options.buildId || identity.documentId !== options.documentId || identity.ownerKey !== options.ownerKey || !Number.isSafeInteger(contentRevision) || contentRevision < 0) {
82
+ throw new StreamedReceiverError("identity", "Streamed selection has the wrong authority.");
83
+ }
84
+ const key = slotKey(identity);
85
+ const previous = selections.get(key);
86
+ if (previous !== void 0) {
87
+ previous.pendingPlacement?.cancel();
88
+ if (previous.result.timer !== void 0) clearTimeout(previous.result.timer);
89
+ previous.historical?.release();
90
+ }
91
+ const state = {
92
+ identity,
93
+ result: { sequence: 0, opened: false, values: 0, terminal: false, frames: [], bytes: 0 },
94
+ placementSequence: 0,
95
+ contentRevision
96
+ };
97
+ selections.set(key, state);
98
+ state.result.timer = setTimeout(() => {
99
+ report(new StreamedReceiverError("timeout", "Streamed result timed out."), state);
100
+ }, timeoutMs);
101
+ };
102
+ const attachResult = (identity, consumer) => {
103
+ const state = current(identity);
104
+ if (state === void 0) {
105
+ throw new StreamedReceiverError("identity", "Cannot attach a result to a stale selection.");
106
+ }
107
+ if (state.result.consumer !== void 0 && state.result.consumer !== consumer) {
108
+ throw new StreamedReceiverError("identity", "A streamed result already has a consumer.");
109
+ }
110
+ state.result.consumer = consumer;
111
+ if (state.result.failure !== void 0) {
112
+ consumer.fail(state.result.failure);
113
+ return () => {
114
+ if (state.result.consumer === consumer) state.result.consumer = void 0;
115
+ };
116
+ }
117
+ let accepted = 0;
118
+ try {
119
+ for (const frame of state.result.frames) {
120
+ if (consumer.accept(frame) === false) break;
121
+ accepted++;
122
+ }
123
+ } finally {
124
+ if (accepted === state.result.frames.length) state.result.bytes = 0;
125
+ else {
126
+ for (let index = 0; index < accepted; index++) {
127
+ state.result.bytes -= frameBytes(state.result.frames[index]);
128
+ }
129
+ }
130
+ state.result.frames.splice(0, accepted);
131
+ }
132
+ retainCompletedResult(state.result);
133
+ return () => {
134
+ if (state.result.consumer === consumer) state.result.consumer = void 0;
135
+ };
136
+ };
137
+ const receiveResult = (state, frame) => {
138
+ const result = state.result;
139
+ if (result.terminal || frame.sequence !== result.sequence) {
140
+ throw new StreamedReceiverError("sequence", "Invalid or duplicate streamed result sequence.");
141
+ }
142
+ result.sequence++;
143
+ if (!result.opened) {
144
+ if (frame.kind !== "open") {
145
+ throw new StreamedReceiverError("terminal", "A streamed result must begin with open.");
146
+ }
147
+ result.opened = true;
148
+ result.resource = frame.resource;
149
+ } else if (frame.kind === "open") {
150
+ throw new StreamedReceiverError("terminal", "A streamed result cannot open twice.");
151
+ } else if (frame.kind === "value") {
152
+ result.values++;
153
+ if (result.resource === "promise" && result.values > 1) {
154
+ throw new StreamedReceiverError(
155
+ "terminal",
156
+ "A promise result emitted more than one value."
157
+ );
158
+ }
159
+ } else {
160
+ if (frame.kind === "complete" && result.resource === "promise" && result.values !== 1) {
161
+ throw new StreamedReceiverError(
162
+ "terminal",
163
+ "A promise result completed without one value."
164
+ );
165
+ }
166
+ }
167
+ if (result.consumer === void 0 || result.frames.length !== 0 || result.consumer.accept(frame) === false) {
168
+ const bytes = frameBytes(frame);
169
+ if (result.frames.length + 1 > maxFrames || result.bytes + bytes > maxBytes) {
170
+ throw new StreamedReceiverError("overflow", "Streamed result mailbox exceeded its bound.");
171
+ }
172
+ result.frames.push(frame);
173
+ result.bytes += bytes;
174
+ }
175
+ if (frame.kind === "complete" || frame.kind === "error") {
176
+ result.terminal = true;
177
+ if (result.timer !== void 0) clearTimeout(result.timer);
178
+ }
179
+ if (frame.kind === "complete") retainCompletedResult(result);
180
+ return "accepted";
181
+ };
182
+ const receivePlacement = async (state, frame) => {
183
+ if (frame.sequence !== state.placementSequence) {
184
+ throw new StreamedReceiverError("sequence", "Invalid or duplicate placement sequence.");
185
+ }
186
+ state.placementSequence++;
187
+ const registration = state.region;
188
+ if (registration === void 0 || registration.isActive()) return "stale";
189
+ if (frame.contentRevision <= state.contentRevision) return "stale";
190
+ if (frame.mode === "delta" && frame.baseRevision !== state.contentRevision) return "stale";
191
+ return commitPlacement?.(state, frame, isCurrent) ?? "stale";
192
+ };
193
+ const receive = async (value) => {
194
+ if (disposed) return "stale";
195
+ if (!isStreamedRendererFrame(value)) {
196
+ const error = new StreamedReceiverError("protocol", "Malformed streamed renderer frame.");
197
+ report(error);
198
+ throw error;
199
+ }
200
+ const frame = value;
201
+ const state = current(frame.identity);
202
+ if (state === void 0 || state.failure !== void 0) return "stale";
203
+ try {
204
+ return frame.channel === "result" ? receiveResult(state, frame) : await receivePlacement(state, frame);
205
+ } catch (error) {
206
+ if (disposed || current(frame.identity) !== state) return "stale";
207
+ const receiverError = error instanceof StreamedReceiverError ? error : new StreamedReceiverError("protocol", "Streamed renderer frame failed.");
208
+ report(receiverError, state);
209
+ throw receiverError;
210
+ }
211
+ };
212
+ const receiver = {
213
+ registerSelection,
214
+ attachResult,
215
+ receive,
216
+ receiveJson(json) {
217
+ return receive(decodeStreamedRendererFrame(json));
218
+ },
219
+ failSelection(identity, error) {
220
+ if (disposed) return false;
221
+ const state = current(identity);
222
+ if (state === void 0 || state.failure !== void 0) return false;
223
+ report(error, state);
224
+ return true;
225
+ },
226
+ dispose() {
227
+ if (disposed) return;
228
+ disposed = true;
229
+ for (const state of selections.values()) {
230
+ try {
231
+ report(new StreamedReceiverError("terminal", "Streamed receiver was disposed."), state);
232
+ } catch {
233
+ } finally {
234
+ state.historical?.release();
235
+ }
236
+ }
237
+ selections.clear();
238
+ }
239
+ };
240
+ return { receiver, current };
241
+ }
242
+ export {
243
+ StreamedReceiverError,
244
+ createStreamedResultReceiver,
245
+ createStreamedResultReceiverState
246
+ };
@@ -0,0 +1,44 @@
1
+ import { type NativeSignalManifest } from '../signals/native-read-seeds.js';
2
+ export type { NativeSignalManifest } from '../signals/native-read-seeds.js';
3
+ import type { SignalOwnerIdentity } from '../signals/types.js';
4
+ import { type StreamedRendererDeliveryOptions } from './stream-delivery.js';
5
+ import { type StreamedRegionReceiver } from './stream-receiver.js';
6
+ import { type StreamedResultReceiver } from './stream-result-receiver.js';
7
+ export { installSignalDocumentLifecycle, type SignalDocumentLifecycleOptions, } from './document-lifecycle.js';
8
+ export interface StreamedSignalHydrationOptions extends StreamedRendererDeliveryOptions {
9
+ readonly buildId: string;
10
+ readonly documentId: string;
11
+ /** Custom authority; pass it to hydrateRoot or use runWithSignalOwner in behavior callbacks. */
12
+ readonly signalOwner?: SignalOwnerIdentity;
13
+ /**
14
+ * Initial-response data only. Install once, before live signal access or stream
15
+ * attachment. Only the document scope is initialized; instance snapshots stay
16
+ * historical. A failed join retires newly initialized authority rather than
17
+ * rolling state back. The caller supplies the matching build/document identity.
18
+ */
19
+ readonly initialSignals?: NativeSignalManifest;
20
+ readonly target?: Record<string, unknown>;
21
+ }
22
+ export interface StreamedSignalResults {
23
+ readonly signalOwner: SignalOwnerIdentity;
24
+ readonly receiver: StreamedResultReceiver;
25
+ dispose(): void;
26
+ /** Permanently fence this document's old ingress without restoring its early mailbox. */
27
+ suspend(): void;
28
+ }
29
+ export interface StreamedSignalHydration extends StreamedSignalResults {
30
+ readonly receiver: StreamedRegionReceiver;
31
+ }
32
+ /**
33
+ * Upgrade the server's pre-module mailboxes before behavior reads or hydration.
34
+ * No component root is required. An optional hydrateRoot receives the returned
35
+ * owner so its instance-local descriptors join the same server-authorized
36
+ * selections without starting duplicate browser loaders.
37
+ */
38
+ export declare function bootstrapStreamedSignalHydration(options: StreamedSignalHydrationOptions): StreamedSignalHydration;
39
+ /**
40
+ * Upgrade the same pre-module mailboxes when the host owns DOM delivery.
41
+ * Results join the existing signal owner synchronously, without region placement
42
+ * support. Use bootstrapStreamedSignalHydration to register streamed HTML ranges.
43
+ */
44
+ export declare function bootstrapStreamedSignalResults(options: StreamedSignalHydrationOptions): StreamedSignalResults;
@@ -0,0 +1,186 @@
1
+ import {
2
+ documentSignalOwner,
3
+ enableSignalDocument,
4
+ installStreamedSignalOwnerActivator
5
+ } from "../signals/document-owner.js";
6
+ import { attachStreamedSignalResult, initializeDocumentSignalOwner } from "../signals/facade.js";
7
+ import { registerSignalOwnerDocument } from "../signals/early-values.js";
8
+ import { retireSignalOwnerIdentity } from "../signals/owner-context.js";
9
+ import {
10
+ parseNativeSignalManifest
11
+ } from "../signals/native-read-seeds.js";
12
+ import {
13
+ isStreamFrameIdentity,
14
+ isStreamedRendererFrame,
15
+ streamFrameIdentityKey
16
+ } from "../streamed-signals-protocol.js";
17
+ import {
18
+ installStreamedRendererGlobal
19
+ } from "./stream-delivery.js";
20
+ import { createStreamedRegionReceiver } from "./stream-receiver.js";
21
+ import {
22
+ createStreamedResultReceiver
23
+ } from "./stream-result-receiver.js";
24
+ import {
25
+ installSignalDocumentLifecycle
26
+ } from "./document-lifecycle.js";
27
+ const STREAMED_SIGNAL_SELECTIONS = "__octaneStreamedSignalSelections";
28
+ function documentOwner(owner) {
29
+ return "documentOwner" in owner ? owner.documentOwner : owner;
30
+ }
31
+ function bootstrapStreamedSignalHydration(options) {
32
+ return bootstrapStreamedSignals(options, createStreamedRegionReceiver);
33
+ }
34
+ function bootstrapStreamedSignalResults(options) {
35
+ return bootstrapStreamedSignals(options, createStreamedResultReceiver);
36
+ }
37
+ function bootstrapStreamedSignals(options, createReceiver) {
38
+ if (!options.buildId || !options.documentId) {
39
+ throw new TypeError("Streamed signal hydration requires buildId and documentId.");
40
+ }
41
+ const target = options.target ?? globalThis;
42
+ const signalOwner = options.signalOwner ?? documentSignalOwner(document);
43
+ const receiver = createReceiver({
44
+ buildId: options.buildId,
45
+ documentId: options.documentId,
46
+ ownerKey: signalOwner.scopeKey,
47
+ ...options.maxPendingFrames === void 0 ? {} : { maxPendingFrames: options.maxPendingFrames },
48
+ ...options.maxPendingBytes === void 0 ? {} : { maxPendingBytes: options.maxPendingBytes },
49
+ ...options.timeoutMs === void 0 ? {} : { pendingTimeoutMs: options.timeoutMs }
50
+ });
51
+ const early = target[STREAMED_SIGNAL_SELECTIONS];
52
+ if (early === void 0 || early === null || typeof early !== "object" || early.version !== 1 || !Array.isArray(early.identities) || typeof early.register !== "function") {
53
+ receiver.dispose();
54
+ throw new Error("The streamed signal selection bootstrap is missing or incompatible.");
55
+ }
56
+ if (early.overflow === true) {
57
+ receiver.dispose();
58
+ throw new Error("The pre-module streamed signal selection mailbox overflowed.");
59
+ }
60
+ const selections = /* @__PURE__ */ new Map();
61
+ const owners = /* @__PURE__ */ new Map();
62
+ let disposed = false;
63
+ const attach = (selection, owner) => {
64
+ if (selection.detach !== void 0 || selection.identity.instanceKey !== owner.instanceKey)
65
+ return;
66
+ selection.detach = attachStreamedSignalResult(receiver, owner, selection.identity);
67
+ };
68
+ const register = (candidate) => {
69
+ if (disposed) return;
70
+ if (!isStreamFrameIdentity(candidate) || candidate.buildId !== options.buildId || candidate.documentId !== options.documentId || candidate.ownerKey !== signalOwner.scopeKey) {
71
+ throw new Error("A streamed signal selection has the wrong authority.");
72
+ }
73
+ const slot = JSON.stringify([candidate.instanceKey, candidate.nodeKey]);
74
+ const previous = selections.get(slot);
75
+ previous?.detach?.();
76
+ receiver.registerSelection(candidate);
77
+ const selection = { identity: candidate };
78
+ selections.set(slot, selection);
79
+ const owner = owners.get(candidate.instanceKey);
80
+ if (owner !== void 0) attach(selection, owner);
81
+ else if (candidate.nodeKey.startsWith("g:")) {
82
+ attach(selection, {
83
+ scopeKey: signalOwner.scopeKey,
84
+ documentOwner: signalOwner,
85
+ instanceOwner: signalOwner,
86
+ instanceKey: candidate.instanceKey
87
+ });
88
+ }
89
+ };
90
+ const originalRegister = early.register;
91
+ let uninstallOwnerActivator;
92
+ let initialized = false;
93
+ try {
94
+ uninstallOwnerActivator = installStreamedSignalOwnerActivator((owner) => {
95
+ if (disposed || !("documentOwner" in owner) || documentOwner(owner) !== signalOwner) return;
96
+ if (owners.has(owner.instanceKey)) return;
97
+ owners.set(owner.instanceKey, owner);
98
+ for (const selection of selections.values()) attach(selection, owner);
99
+ });
100
+ if (options.initialSignals !== void 0) {
101
+ const manifest = parseNativeSignalManifest(JSON.stringify(options.initialSignals));
102
+ initializeDocumentSignalOwner(
103
+ signalOwner,
104
+ manifest.scopes.find((scope) => scope.scopeKey === signalOwner.scopeKey) ?? {
105
+ version: 1,
106
+ scopeKey: signalOwner.scopeKey,
107
+ entries: []
108
+ }
109
+ );
110
+ initialized = true;
111
+ }
112
+ registerSignalOwnerDocument(signalOwner, document);
113
+ enableSignalDocument();
114
+ early.register = register;
115
+ for (const identity of early.identities) register(identity);
116
+ early.identities.length = 0;
117
+ } catch (error) {
118
+ uninstallOwnerActivator?.();
119
+ if (early.register === register) early.register = originalRegister;
120
+ for (const selection of selections.values()) selection.detach?.();
121
+ receiver.dispose();
122
+ if (initialized) retireSignalOwnerIdentity(signalOwner);
123
+ throw error;
124
+ }
125
+ const earlyRenderer = target.__octaneStreamedRenderer;
126
+ if (earlyRenderer !== void 0 && earlyRenderer !== null && typeof earlyRenderer === "object" && earlyRenderer.version === 1 && Array.isArray(earlyRenderer.frames)) {
127
+ const current = new Set(
128
+ [...selections.values()].map(({ identity }) => streamFrameIdentityKey(identity))
129
+ );
130
+ let retained = 0;
131
+ for (const frame of earlyRenderer.frames) {
132
+ if (isStreamedRendererFrame(frame) && frame.channel === "result" && current.has(streamFrameIdentityKey(frame.identity))) {
133
+ void receiver.receive(frame).catch(() => {
134
+ });
135
+ } else {
136
+ earlyRenderer.frames[retained++] = frame;
137
+ }
138
+ }
139
+ earlyRenderer.frames.length = retained;
140
+ }
141
+ let uninstallDelivery;
142
+ try {
143
+ uninstallDelivery = installStreamedRendererGlobal(receiver, target, options);
144
+ } catch (error) {
145
+ uninstallOwnerActivator();
146
+ early.register = originalRegister;
147
+ for (const selection of selections.values()) selection.detach?.();
148
+ receiver.dispose();
149
+ if (initialized) retireSignalOwnerIdentity(signalOwner);
150
+ throw error;
151
+ }
152
+ const installedRenderer = target.__octaneStreamedRenderer;
153
+ const close = (restore) => {
154
+ if (disposed) return;
155
+ disposed = true;
156
+ if (early.register === register) early.register = restore ? originalRegister : () => {
157
+ };
158
+ uninstallOwnerActivator();
159
+ for (const selection of selections.values()) selection.detach?.();
160
+ const ownsIngress = target.__octaneStreamedRenderer === installedRenderer;
161
+ uninstallDelivery();
162
+ if (!restore && ownsIngress) {
163
+ target.__octaneStreamedRenderer = { receive() {
164
+ } };
165
+ if (earlyRenderer) earlyRenderer.frames.length = 0;
166
+ }
167
+ selections.clear();
168
+ owners.clear();
169
+ receiver.dispose();
170
+ };
171
+ return {
172
+ signalOwner,
173
+ receiver,
174
+ dispose() {
175
+ close(true);
176
+ },
177
+ suspend() {
178
+ close(false);
179
+ }
180
+ };
181
+ }
182
+ export {
183
+ bootstrapStreamedSignalHydration,
184
+ bootstrapStreamedSignalResults,
185
+ installSignalDocumentLifecycle
186
+ };
@@ -49,6 +49,12 @@ export type HydrationPrefetchFunction = (context: HydrationPrefetchContext) => v
49
49
  export type HydrateWhen = HydrationStrategy | (() => HydrationStrategy);
50
50
  type HydrateCommonOptions = {
51
51
  when: HydrateWhen;
52
+ /**
53
+ * Require this boundary to activate without evaluating or hydrating its
54
+ * lexical parent. The compiler rejects the boundary when it cannot prove a
55
+ * standalone capture, ownership, ID, and style contract.
56
+ */
57
+ independent?: boolean;
52
58
  fallback?: unknown;
53
59
  onHydrated?: () => void;
54
60
  };
@@ -0,0 +1,7 @@
1
+ /** Inert compiler/bundler manifest for one independently activatable boundary. */
2
+ export declare const INDEPENDENT_HYDRATE_MANIFEST_ATTR = "data-octane-independent";
3
+ export declare const HYDRATE_INDEPENDENT_ATTR = "data-octane-hydrate-independent";
4
+ /** Compiler-owned stable key for a native control that can receive input before activation. */
5
+ export declare const HYDRATE_INPUT_ATTR = "data-octane-input";
6
+ /** Server-only writable-signal identity joined to a compiler control site. */
7
+ export declare const SIGNAL_CONTROL_ATTR = "data-octane-signal-control";
@@ -0,0 +1,10 @@
1
+ const INDEPENDENT_HYDRATE_MANIFEST_ATTR = "data-octane-independent";
2
+ const HYDRATE_INDEPENDENT_ATTR = "data-octane-hydrate-independent";
3
+ const HYDRATE_INPUT_ATTR = "data-octane-input";
4
+ const SIGNAL_CONTROL_ATTR = "data-octane-signal-control";
5
+ export {
6
+ HYDRATE_INDEPENDENT_ATTR,
7
+ HYDRATE_INPUT_ATTR,
8
+ INDEPENDENT_HYDRATE_MANIFEST_ATTR,
9
+ SIGNAL_CONTROL_ATTR
10
+ };
@@ -0,0 +1,31 @@
1
+ import type { EncodedSignalValue } from './signals/types.js';
2
+ export interface IndependentHydrateCapture {
3
+ readonly name: string;
4
+ readonly type: 'json';
5
+ }
6
+ export interface IndependentHydrateManifestTemplate {
7
+ readonly version: 1;
8
+ readonly boundaryId: string;
9
+ readonly exportName: string;
10
+ readonly captureSchema: readonly IndependentHydrateCapture[];
11
+ readonly hookSeed: number;
12
+ readonly idSeed: number;
13
+ readonly signalSites: readonly string[];
14
+ readonly parentDependencies: false;
15
+ }
16
+ export interface IndependentHydrateBuildRecord {
17
+ readonly moduleId: string;
18
+ readonly styles: readonly string[];
19
+ }
20
+ /** Compiler proof plus request-specific encoded captures for one island. */
21
+ export interface IndependentHydrateManifest extends IndependentHydrateManifestTemplate {
22
+ readonly buildId: string;
23
+ /** Per-render instance boundary, not the compiler template lookup key. */
24
+ readonly boundaryId: string;
25
+ readonly moduleId: string;
26
+ readonly captures: readonly EncodedSignalValue[];
27
+ readonly styles: readonly string[];
28
+ }
29
+ export declare function isIndependentHydrateManifest(value: unknown): value is IndependentHydrateManifest;
30
+ export declare function createIndependentHydrateManifest(template: IndependentHydrateManifestTemplate, values: readonly unknown[], instanceBoundaryId: string, buildId: string, build: IndependentHydrateBuildRecord): IndependentHydrateManifest;
31
+ export declare function serializeIndependentHydrateManifest(manifest: IndependentHydrateManifest): string;