octane 0.2.11 → 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 (264) 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/context-epoch.cjs +38 -0
  8. package/dist/cjs/css.cjs +6 -27
  9. package/dist/cjs/data-encoding.cjs +160 -0
  10. package/dist/cjs/dom-binding-handoff.cjs +93 -0
  11. package/dist/cjs/dom-binding-protocol.cjs +115 -0
  12. package/dist/cjs/dom-binding-styles.cjs +292 -0
  13. package/dist/cjs/dom-bindings.cjs +700 -0
  14. package/dist/cjs/dom-focused-move.cjs +66 -0
  15. package/dist/cjs/dom-stage.cjs +896 -0
  16. package/dist/cjs/dom-tables.cjs +4 -94
  17. package/dist/cjs/error-codes.client.generated.cjs +33 -0
  18. package/dist/cjs/error-codes.server.generated.cjs +24 -0
  19. package/dist/cjs/hydration/control-capture.cjs +244 -0
  20. package/dist/cjs/hydration/event-capture.cjs +125 -43
  21. package/dist/cjs/hydration/interaction-config.cjs +50 -2
  22. package/dist/cjs/hydration-markers.cjs +37 -0
  23. package/dist/cjs/independent-hydration-protocol.cjs +106 -0
  24. package/dist/cjs/index.cjs +9 -0
  25. package/dist/cjs/runtime.cjs +6397 -1683
  26. package/dist/cjs/runtime.server.cjs +1465 -213
  27. package/dist/cjs/server/early-signals.cjs +45 -0
  28. package/dist/cjs/server/index.cjs +47 -0
  29. package/dist/cjs/server/rpc-batch.cjs +149 -0
  30. package/dist/cjs/server/rpc-stream.cjs +146 -0
  31. package/dist/cjs/server/rpc.cjs +34 -15
  32. package/dist/cjs/server/signal-query-observation.cjs +158 -0
  33. package/dist/cjs/server/streamed-region.cjs +52 -0
  34. package/dist/cjs/server/streamed-signals.cjs +512 -0
  35. package/dist/cjs/server-call.cjs +103 -0
  36. package/dist/cjs/server-rpc-batch-client.cjs +141 -0
  37. package/dist/cjs/server-rpc-client.cjs +94 -27
  38. package/dist/cjs/server-rpc-protocol.cjs +141 -0
  39. package/dist/cjs/server-rpc-stream-client.cjs +118 -0
  40. package/dist/cjs/signals/actions.cjs +474 -0
  41. package/dist/cjs/signals/client.cjs +4 -1
  42. package/dist/cjs/signals/computations.cjs +460 -0
  43. package/dist/cjs/signals/control-binding.cjs +368 -0
  44. package/dist/cjs/signals/derived-facade.cjs +50 -0
  45. package/dist/cjs/signals/document-owner.cjs +71 -0
  46. package/dist/cjs/signals/early-values.cjs +155 -0
  47. package/dist/cjs/signals/encoding.cjs +6 -95
  48. package/dist/cjs/signals/engine.cjs +276 -12
  49. package/dist/cjs/signals/errors.cjs +18 -0
  50. package/dist/cjs/signals/facade.cjs +477 -0
  51. package/dist/cjs/signals/graph.cjs +166 -20
  52. package/dist/cjs/signals/handle-protocol.cjs +36 -0
  53. package/dist/cjs/signals/index.cjs +81 -2
  54. package/dist/cjs/signals/native-read-client.cjs +10 -0
  55. package/dist/cjs/signals/owner-context.cjs +112 -0
  56. package/dist/cjs/signals/query-attempt-observer.cjs +68 -0
  57. package/dist/cjs/signals/query-facade.cjs +72 -0
  58. package/dist/cjs/signals/read-protocol.cjs +54 -0
  59. package/dist/cjs/signals/requests.cjs +287 -14
  60. package/dist/cjs/signals/scalar-computations.cjs +76 -0
  61. package/dist/cjs/signals/server.cjs +4 -1
  62. package/dist/cjs/signals/transition-candidate.cjs +567 -0
  63. package/dist/cjs/signals/transition-state.cjs +106 -0
  64. package/dist/cjs/signals/types.cjs +50 -0
  65. package/dist/cjs/stream-protocol.cjs +3 -0
  66. package/dist/cjs/streamed-signals-protocol.cjs +159 -0
  67. package/dist/cjs/style-values.cjs +122 -0
  68. package/dist/cjs/trusted-html.cjs +30 -0
  69. package/dist/cjs/version.cjs +1 -1
  70. package/dist/class-names.d.ts +5 -0
  71. package/dist/class-names.js +25 -0
  72. package/dist/compiler/bundler.js +51 -22
  73. package/dist/compiler/compile.js +2534 -581
  74. package/dist/compiler/dom-binding-program.js +935 -0
  75. package/dist/compiler/dom-binding-request.js +57 -0
  76. package/dist/compiler/dom-bindings.js +2245 -0
  77. package/dist/compiler/hook-deps.js +759 -10
  78. package/dist/compiler/hydrate-boundaries.js +358 -15
  79. package/dist/compiler/index.d.ts +39 -2
  80. package/dist/compiler/index.js +1 -0
  81. package/dist/compiler/native-attribute-reads.js +127 -0
  82. package/dist/compiler/native-change-diagnostics.js +32 -38
  83. package/dist/compiler/native-read-diagnostics.js +69 -8
  84. package/dist/compiler/native-read-types.js +80 -34
  85. package/dist/compiler/parser.node.js +1 -1
  86. package/dist/compiler/renderer-boundaries.js +40 -0
  87. package/dist/compiler/server-context.js +118 -0
  88. package/dist/compiler/signal-attempt-reads.js +479 -0
  89. package/dist/compiler/signal-declarations.js +557 -0
  90. package/dist/compiler/signal-start-reads.js +413 -0
  91. package/dist/compiler/slot-hooks.d.ts +3 -1
  92. package/dist/compiler/slot-hooks.js +168 -34
  93. package/dist/compiler/strong-auto-memo.js +90 -0
  94. package/dist/compiler/strong-html.js +143 -0
  95. package/dist/compiler/strong-mode.js +764 -66
  96. package/dist/compiler/strong-template-policy.js +307 -0
  97. package/dist/compiler/template-ir.js +200 -0
  98. package/dist/compiler/typescript.d.ts +2 -0
  99. package/dist/compiler/typescript.js +2 -0
  100. package/dist/compiler/vite.d.ts +3 -1
  101. package/dist/compiler/vite.js +122 -4
  102. package/dist/compiler/volar.LICENSES.txt +1 -1
  103. package/dist/compiler/volar.d.ts +6 -1
  104. package/dist/compiler/volar.js +750 -1433
  105. package/dist/constants.d.ts +1 -0
  106. package/dist/constants.js +10 -0
  107. package/dist/context-epoch.d.ts +2 -0
  108. package/dist/context-epoch.js +13 -0
  109. package/dist/css.d.ts +2 -5
  110. package/dist/css.js +2 -23
  111. package/dist/data-encoding.d.ts +9 -0
  112. package/dist/data-encoding.js +134 -0
  113. package/dist/dom-binding-classes.d.ts +15 -0
  114. package/dist/dom-binding-classes.js +129 -0
  115. package/dist/dom-binding-controls.d.ts +2 -0
  116. package/dist/dom-binding-controls.js +6 -0
  117. package/dist/dom-binding-handoff.d.ts +55 -0
  118. package/dist/dom-binding-handoff.js +62 -0
  119. package/dist/dom-binding-program.d.ts +300 -0
  120. package/dist/dom-binding-program.js +1625 -0
  121. package/dist/dom-binding-projections.d.ts +15 -0
  122. package/dist/dom-binding-projections.js +187 -0
  123. package/dist/dom-binding-protocol.d.ts +13 -0
  124. package/dist/dom-binding-protocol.js +88 -0
  125. package/dist/dom-binding-signals.d.ts +21 -0
  126. package/dist/dom-binding-signals.js +109 -0
  127. package/dist/dom-binding-styles.d.ts +17 -0
  128. package/dist/dom-binding-styles.js +272 -0
  129. package/dist/dom-bindings.d.ts +89 -0
  130. package/dist/dom-bindings.js +670 -0
  131. package/dist/dom-focused-move.d.ts +6 -0
  132. package/dist/dom-focused-move.js +42 -0
  133. package/dist/dom-stage.d.ts +52 -0
  134. package/dist/dom-stage.js +872 -0
  135. package/dist/dom-tables.d.ts +1 -3
  136. package/dist/dom-tables.js +1 -91
  137. package/dist/error-codes.client.generated.d.ts +9 -0
  138. package/dist/error-codes.client.generated.js +33 -0
  139. package/dist/error-codes.server.generated.d.ts +6 -0
  140. package/dist/error-codes.server.generated.js +24 -0
  141. package/dist/hydration/control-capture.d.ts +62 -0
  142. package/dist/hydration/control-capture.js +223 -0
  143. package/dist/hydration/document-lifecycle.d.ts +23 -0
  144. package/dist/hydration/document-lifecycle.js +80 -0
  145. package/dist/hydration/event-capture.d.ts +20 -1
  146. package/dist/hydration/event-capture.js +128 -42
  147. package/dist/hydration/independent-island.d.ts +45 -0
  148. package/dist/hydration/independent-island.js +233 -0
  149. package/dist/hydration/index.d.ts +8 -1
  150. package/dist/hydration/index.js +55 -1
  151. package/dist/hydration/interaction-config.d.ts +5 -0
  152. package/dist/hydration/interaction-config.js +44 -1
  153. package/dist/hydration/stream-delivery.d.ts +32 -0
  154. package/dist/hydration/stream-delivery.js +333 -0
  155. package/dist/hydration/stream-receiver.d.ts +26 -0
  156. package/dist/hydration/stream-receiver.js +204 -0
  157. package/dist/hydration/stream-result-receiver.d.ts +70 -0
  158. package/dist/hydration/stream-result-receiver.js +246 -0
  159. package/dist/hydration/streamed-signals.d.ts +44 -0
  160. package/dist/hydration/streamed-signals.js +186 -0
  161. package/dist/hydration/types.d.ts +6 -0
  162. package/dist/hydration-markers.d.ts +7 -0
  163. package/dist/hydration-markers.js +10 -0
  164. package/dist/independent-hydration-protocol.d.ts +31 -0
  165. package/dist/independent-hydration-protocol.js +80 -0
  166. package/dist/index.d.ts +3 -0
  167. package/dist/index.js +6 -0
  168. package/dist/internal/signal-read.d.ts +1 -0
  169. package/dist/internal/signal-read.js +4 -0
  170. package/dist/jsx-runtime-strong.d.ts +33 -0
  171. package/dist/jsx-runtime.d.ts +58 -2
  172. package/dist/public-types.d.ts +15 -1
  173. package/dist/runtime.d.ts +297 -23
  174. package/dist/runtime.js +6405 -1679
  175. package/dist/runtime.server.d.ts +110 -27
  176. package/dist/runtime.server.js +1458 -213
  177. package/dist/server/early-signals.d.ts +14 -0
  178. package/dist/server/early-signals.js +34 -0
  179. package/dist/server/index.d.ts +11 -2
  180. package/dist/server/index.js +50 -1
  181. package/dist/server/rpc-batch.d.ts +17 -0
  182. package/dist/server/rpc-batch.js +129 -0
  183. package/dist/server/rpc-stream.d.ts +9 -0
  184. package/dist/server/rpc-stream.js +125 -0
  185. package/dist/server/rpc.d.ts +5 -1
  186. package/dist/server/rpc.js +37 -13
  187. package/dist/server/signal-query-observation.d.ts +3 -0
  188. package/dist/server/signal-query-observation.js +134 -0
  189. package/dist/server/streamed-region.d.ts +15 -0
  190. package/dist/server/streamed-region.js +30 -0
  191. package/dist/server/streamed-signals.d.ts +45 -0
  192. package/dist/server/streamed-signals.js +488 -0
  193. package/dist/server-call.d.ts +41 -0
  194. package/dist/server-call.js +75 -0
  195. package/dist/server-rpc-batch-client.d.ts +7 -0
  196. package/dist/server-rpc-batch-client.js +119 -0
  197. package/dist/server-rpc-client.d.ts +3 -1
  198. package/dist/server-rpc-client.js +99 -27
  199. package/dist/server-rpc-protocol.d.ts +47 -0
  200. package/dist/server-rpc-protocol.js +109 -0
  201. package/dist/server-rpc-stream-client.d.ts +5 -0
  202. package/dist/server-rpc-stream-client.js +98 -0
  203. package/dist/signals/actions.d.ts +12 -0
  204. package/dist/signals/actions.js +466 -0
  205. package/dist/signals/client.d.ts +2 -0
  206. package/dist/signals/client.js +1 -0
  207. package/dist/signals/computations.d.ts +37 -0
  208. package/dist/signals/computations.js +455 -0
  209. package/dist/signals/control-binding.d.ts +31 -0
  210. package/dist/signals/control-binding.js +353 -0
  211. package/dist/signals/derived-facade.d.ts +3 -0
  212. package/dist/signals/derived-facade.js +25 -0
  213. package/dist/signals/document-owner.d.ts +10 -0
  214. package/dist/signals/document-owner.js +43 -0
  215. package/dist/signals/early-values.d.ts +24 -0
  216. package/dist/signals/early-values.js +124 -0
  217. package/dist/signals/encoding.d.ts +1 -3
  218. package/dist/signals/encoding.js +3 -93
  219. package/dist/signals/engine.d.ts +53 -4
  220. package/dist/signals/engine.js +275 -16
  221. package/dist/signals/errors.d.ts +7 -0
  222. package/dist/signals/errors.js +16 -0
  223. package/dist/signals/facade.d.ts +74 -0
  224. package/dist/signals/facade.js +452 -0
  225. package/dist/signals/graph.d.ts +52 -6
  226. package/dist/signals/graph.js +174 -19
  227. package/dist/signals/handle-protocol.d.ts +4 -0
  228. package/dist/signals/handle-protocol.js +11 -0
  229. package/dist/signals/index.d.ts +12 -3
  230. package/dist/signals/index.js +71 -2
  231. package/dist/signals/native-read-client.d.ts +3 -0
  232. package/dist/signals/native-read-client.js +10 -0
  233. package/dist/signals/owner-context.d.ts +22 -0
  234. package/dist/signals/owner-context.js +77 -0
  235. package/dist/signals/query-attempt-observer.d.ts +49 -0
  236. package/dist/signals/query-attempt-observer.js +41 -0
  237. package/dist/signals/query-facade.d.ts +3 -0
  238. package/dist/signals/query-facade.js +49 -0
  239. package/dist/signals/read-protocol.d.ts +37 -2
  240. package/dist/signals/read-protocol.js +44 -0
  241. package/dist/signals/requests.d.ts +38 -5
  242. package/dist/signals/requests.js +298 -15
  243. package/dist/signals/scalar-computations.d.ts +2 -0
  244. package/dist/signals/scalar-computations.js +60 -0
  245. package/dist/signals/server.d.ts +2 -0
  246. package/dist/signals/server.js +1 -0
  247. package/dist/signals/transition-candidate.d.ts +71 -0
  248. package/dist/signals/transition-candidate.js +557 -0
  249. package/dist/signals/transition-state.d.ts +51 -0
  250. package/dist/signals/transition-state.js +70 -0
  251. package/dist/signals/types.d.ts +95 -5
  252. package/dist/signals/types.js +20 -0
  253. package/dist/stream-protocol.d.ts +0 -5
  254. package/dist/stream-protocol.js +3 -0
  255. package/dist/streamed-signals-protocol.d.ts +60 -0
  256. package/dist/streamed-signals-protocol.js +130 -0
  257. package/dist/style-values.d.ts +3 -0
  258. package/dist/style-values.js +96 -0
  259. package/dist/trusted-html.d.ts +17 -0
  260. package/dist/trusted-html.js +6 -0
  261. package/dist/universal-core.d.ts +6 -0
  262. package/dist/universal-core.js +214 -202
  263. package/dist/version.js +1 -1
  264. package/package.json +48 -5
@@ -0,0 +1,488 @@
1
+ import { encodeSignalValue } from "../data-encoding.js";
2
+ import {
3
+ encodeStreamedRendererFrameForScript,
4
+ isStreamFrameIdentity,
5
+ isStreamedRendererFrame
6
+ } from "../streamed-signals-protocol.js";
7
+ import { createServerSignalQueryAttemptObservations } from "./signal-query-observation.js";
8
+ const DEFAULT_MAX_FRAME_BYTES = 4 * 1024 * 1024;
9
+ const DEFAULT_MAX_TOTAL_BYTES = 64 * 1024 * 1024;
10
+ const DEFAULT_TIMEOUT = 3e4;
11
+ function positiveLimit(value, fallback) {
12
+ const limit = value ?? fallback;
13
+ if (!Number.isSafeInteger(limit) || limit <= 0) {
14
+ throw new RangeError("Streamed renderer limits must be positive safe integers.");
15
+ }
16
+ return limit;
17
+ }
18
+ function limits(options) {
19
+ return {
20
+ maxFrameBytes: positiveLimit(options.maxFrameBytes, DEFAULT_MAX_FRAME_BYTES),
21
+ maxTotalBytes: positiveLimit(options.maxTotalBytes, DEFAULT_MAX_TOTAL_BYTES),
22
+ timeoutMs: positiveLimit(options.timeoutMs, DEFAULT_TIMEOUT)
23
+ };
24
+ }
25
+ function isAsyncIterable(value) {
26
+ return value !== null && (typeof value === "object" || typeof value === "function") && typeof value[Symbol.asyncIterator] === "function";
27
+ }
28
+ async function* createStreamedSignalResultFrames(identity, result, options = {}) {
29
+ if (!isStreamFrameIdentity(identity)) throw new TypeError("Invalid streamed signal identity.");
30
+ let sequence = 0;
31
+ let resource = "promise";
32
+ let iterator;
33
+ const run = options.run ?? ((callback) => callback());
34
+ try {
35
+ const resolved = await result;
36
+ options.signal?.throwIfAborted();
37
+ if (isAsyncIterable(resolved)) {
38
+ resource = "stream";
39
+ iterator = run(() => resolved[Symbol.asyncIterator]());
40
+ yield { identity, sequence: sequence++, channel: "result", kind: "open", resource: "stream" };
41
+ for (; ; ) {
42
+ options.signal?.throwIfAborted();
43
+ const next = await run(() => iterator.next());
44
+ options.signal?.throwIfAborted();
45
+ if (next.done) break;
46
+ yield {
47
+ identity,
48
+ sequence: sequence++,
49
+ channel: "result",
50
+ kind: "value",
51
+ value: encodeSignalValue(next.value)
52
+ };
53
+ }
54
+ iterator = void 0;
55
+ } else {
56
+ yield {
57
+ identity,
58
+ sequence: sequence++,
59
+ channel: "result",
60
+ kind: "open",
61
+ resource: "promise"
62
+ };
63
+ yield {
64
+ identity,
65
+ sequence: sequence++,
66
+ channel: "result",
67
+ kind: "value",
68
+ value: encodeSignalValue(resolved)
69
+ };
70
+ }
71
+ yield { identity, sequence, channel: "result", kind: "complete" };
72
+ } catch {
73
+ if (sequence === 0) {
74
+ yield { identity, sequence: sequence++, channel: "result", kind: "open", resource };
75
+ }
76
+ yield { identity, sequence, channel: "result", kind: "error", code: "SERVER_RESULT_FAILED" };
77
+ } finally {
78
+ if (iterator !== void 0) {
79
+ try {
80
+ await run(() => iterator.return?.());
81
+ } catch {
82
+ }
83
+ }
84
+ }
85
+ }
86
+ function line(frame) {
87
+ if (!isStreamedRendererFrame(frame)) throw new TypeError("Invalid streamed renderer frame.");
88
+ return new TextEncoder().encode(JSON.stringify(frame) + "\n");
89
+ }
90
+ function createStreamedRendererFrameStream(frames, options = {}) {
91
+ const budget = limits(options);
92
+ const iterator = frames[Symbol.asyncIterator]();
93
+ let totalBytes = 0;
94
+ let finished = false;
95
+ let controller;
96
+ const timer = setTimeout(
97
+ () => fail(new Error("Streamed renderer response timed out.")),
98
+ budget.timeoutMs
99
+ );
100
+ const cleanup = () => {
101
+ clearTimeout(timer);
102
+ options.signal?.removeEventListener("abort", abort);
103
+ };
104
+ const closeIterator = () => {
105
+ try {
106
+ void Promise.resolve(iterator.return?.(void 0)).catch(() => {
107
+ });
108
+ } catch {
109
+ }
110
+ };
111
+ const fail = (error) => {
112
+ if (finished) return;
113
+ finished = true;
114
+ cleanup();
115
+ closeIterator();
116
+ controller?.error(error);
117
+ };
118
+ const abort = () => fail(options.signal?.reason ?? new DOMException("Aborted", "AbortError"));
119
+ return new ReadableStream(
120
+ {
121
+ start(streamController) {
122
+ controller = streamController;
123
+ options.signal?.addEventListener("abort", abort, { once: true });
124
+ if (options.signal?.aborted) abort();
125
+ },
126
+ async pull() {
127
+ if (finished) return;
128
+ try {
129
+ const next = await iterator.next();
130
+ if (finished) return;
131
+ if (next.done) {
132
+ finished = true;
133
+ cleanup();
134
+ controller.close();
135
+ return;
136
+ }
137
+ const encoded = line(next.value);
138
+ if (encoded.byteLength > budget.maxFrameBytes || totalBytes + encoded.byteLength > budget.maxTotalBytes) {
139
+ throw new Error("Streamed renderer response exceeded its byte budget.");
140
+ }
141
+ totalBytes += encoded.byteLength;
142
+ controller.enqueue(encoded);
143
+ } catch (error) {
144
+ fail(error);
145
+ }
146
+ },
147
+ cancel() {
148
+ if (finished) return;
149
+ finished = true;
150
+ cleanup();
151
+ closeIterator();
152
+ }
153
+ },
154
+ { highWaterMark: 0 }
155
+ );
156
+ }
157
+ function escapeAttribute(value) {
158
+ return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
159
+ }
160
+ function streamedRendererFrameScript(frame, nonce) {
161
+ const encoded = encodeStreamedRendererFrameForScript(frame);
162
+ return `<script${nonce === void 0 ? "" : ` nonce="${escapeAttribute(nonce)}"`}>globalThis.__octaneStreamedRenderer.receive(${encoded});</script>`;
163
+ }
164
+ function streamedSignalSelectionScript(identity, nonce) {
165
+ if (!isStreamFrameIdentity(identity)) throw new TypeError("Invalid streamed signal identity.");
166
+ const encoded = JSON.stringify(identity).replace(/&/g, "\\u0026").replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
167
+ return `<script${nonce === void 0 ? "" : ` nonce="${escapeAttribute(nonce)}"`}>(function(g){var k="__octaneStreamedRenderer",e=g[k];if(!e){var q=[];g[k]={version:1,frames:q,receive:function(f){if(q.length>=512){this.overflow=true;return;}q.push(f);}};}var z="__octaneStreamedSignalSelections",v=g[z];if(!v){var a=[];v=g[z]={version:1,identities:a,register:function(i){if(a.length>=256){this.overflow=true;return;}a.push(i);}};}v.register(${encoded});})(globalThis);</script>`;
168
+ }
169
+ function createStreamedSignalInjection(identity, result, options = {}) {
170
+ const budget = limits(options);
171
+ const iterator = createStreamedSignalResultFrames(identity, result, options)[Symbol.asyncIterator]();
172
+ let queued = options.announceSelection ? streamedSignalSelectionScript(identity, options.nonce) : "";
173
+ let pending = false;
174
+ let finished = false;
175
+ let subscribed = false;
176
+ let totalBytes = 0;
177
+ let notify;
178
+ let resolveDone;
179
+ let rejectDone;
180
+ const done = new Promise((resolve, reject) => {
181
+ resolveDone = resolve;
182
+ rejectDone = reject;
183
+ });
184
+ let timer;
185
+ const cleanup = () => {
186
+ clearTimeout(timer);
187
+ options.signal?.removeEventListener("abort", abort);
188
+ };
189
+ const closeIterator = () => {
190
+ try {
191
+ void Promise.resolve(iterator.return?.(void 0)).catch(() => {
192
+ });
193
+ } catch {
194
+ }
195
+ };
196
+ const fail = (error) => {
197
+ if (finished) return;
198
+ finished = true;
199
+ cleanup();
200
+ closeIterator();
201
+ rejectDone(error);
202
+ };
203
+ const pump = () => {
204
+ if (!subscribed || pending || queued !== "" || finished) return;
205
+ pending = true;
206
+ void iterator.next().then(
207
+ (next) => {
208
+ pending = false;
209
+ if (finished) return;
210
+ if (next.done) {
211
+ finished = true;
212
+ cleanup();
213
+ resolveDone();
214
+ return;
215
+ }
216
+ const html = streamedRendererFrameScript(next.value, options.nonce);
217
+ const bytes = new TextEncoder().encode(html).byteLength;
218
+ if (bytes > budget.maxFrameBytes || totalBytes + bytes > budget.maxTotalBytes) {
219
+ fail(new Error("Streamed renderer injection exceeded its byte budget."));
220
+ return;
221
+ }
222
+ totalBytes += bytes;
223
+ queued = html;
224
+ notify?.();
225
+ },
226
+ (error) => {
227
+ pending = false;
228
+ fail(error);
229
+ }
230
+ );
231
+ };
232
+ const abort = () => {
233
+ fail(options.signal?.reason ?? new DOMException("Aborted", "AbortError"));
234
+ };
235
+ timer = setTimeout(
236
+ () => fail(new Error("Streamed renderer injection timed out.")),
237
+ budget.timeoutMs
238
+ );
239
+ options.signal?.addEventListener("abort", abort, { once: true });
240
+ if (options.signal?.aborted) abort();
241
+ return {
242
+ streamedRenderer: true,
243
+ take() {
244
+ const html = queued;
245
+ queued = "";
246
+ return html;
247
+ },
248
+ subscribe(callback) {
249
+ notify = callback;
250
+ subscribed = true;
251
+ pump();
252
+ return () => {
253
+ if (notify === callback) notify = void 0;
254
+ };
255
+ },
256
+ accepted() {
257
+ pump();
258
+ },
259
+ cancel: fail,
260
+ done,
261
+ renderComplete() {
262
+ pump();
263
+ }
264
+ };
265
+ }
266
+ function createAutomaticStreamedSignalInjection(options, external) {
267
+ if (!options.buildId || !options.documentId) {
268
+ throw new TypeError("Automatic streamed signals require buildId and documentId.");
269
+ }
270
+ const budget = limits(options);
271
+ const selectionGeneration = options.selectionGeneration ?? 0;
272
+ if (!Number.isSafeInteger(selectionGeneration) || selectionGeneration < 0) {
273
+ throw new RangeError("selectionGeneration must be a nonnegative safe integer.");
274
+ }
275
+ const children = [];
276
+ const observedAttempts = /* @__PURE__ */ new Set();
277
+ let initialSelections = [];
278
+ let queued = "";
279
+ let active;
280
+ let subscribed = false;
281
+ let renderComplete = false;
282
+ let finished = false;
283
+ let totalBytes = 0;
284
+ let notify;
285
+ let timer;
286
+ let resolveDone;
287
+ let rejectDone;
288
+ const done = new Promise((resolve, reject) => {
289
+ resolveDone = resolve;
290
+ rejectDone = reject;
291
+ });
292
+ const cleanupChild = (child) => {
293
+ try {
294
+ child.unsubscribe();
295
+ } catch {
296
+ }
297
+ try {
298
+ child.release();
299
+ } catch {
300
+ }
301
+ };
302
+ const fail = (error) => {
303
+ if (finished) return;
304
+ finished = true;
305
+ if (timer !== void 0) clearTimeout(timer);
306
+ for (const child of children) {
307
+ try {
308
+ child.source.cancel?.(error);
309
+ } catch {
310
+ }
311
+ cleanupChild(child);
312
+ }
313
+ rejectDone(error);
314
+ };
315
+ const maybeDone = () => {
316
+ if (finished || !renderComplete || active !== void 0 || queued !== "") return;
317
+ for (const child of children) if (!child.done) return;
318
+ finished = true;
319
+ if (timer !== void 0) clearTimeout(timer);
320
+ for (const child of children) cleanupChild(child);
321
+ resolveDone();
322
+ };
323
+ const takeInitialSelections = () => {
324
+ const selections = initialSelections;
325
+ initialSelections = void 0;
326
+ let html = "";
327
+ for (const { identity, attempt } of selections ?? []) {
328
+ if (attempt.signal.aborted) continue;
329
+ const script = streamedSignalSelectionScript(identity, options.nonce);
330
+ const bytes = new TextEncoder().encode(script).byteLength;
331
+ if (bytes > budget.maxFrameBytes || totalBytes + bytes > budget.maxTotalBytes) {
332
+ const error = new Error("Automatic streamed signals exceeded their byte budget.");
333
+ fail(error);
334
+ throw error;
335
+ }
336
+ totalBytes += bytes;
337
+ html += script;
338
+ }
339
+ return html;
340
+ };
341
+ const pump = () => {
342
+ if (!subscribed || finished || active !== void 0 || queued !== "") return;
343
+ if (initialSelections !== void 0) {
344
+ try {
345
+ queued = takeInitialSelections();
346
+ } catch {
347
+ return;
348
+ }
349
+ if (queued !== "") {
350
+ notify?.();
351
+ return;
352
+ }
353
+ }
354
+ for (const child of children) {
355
+ const html = child.source.take();
356
+ if (html === "") continue;
357
+ const bytes = new TextEncoder().encode(html).byteLength;
358
+ if (bytes > budget.maxFrameBytes || totalBytes + bytes > budget.maxTotalBytes) {
359
+ fail(new Error("Automatic streamed signals exceeded their byte budget."));
360
+ return;
361
+ }
362
+ totalBytes += bytes;
363
+ active = child;
364
+ queued = html;
365
+ notify?.();
366
+ return;
367
+ }
368
+ maybeDone();
369
+ };
370
+ const addChild = (source, release, attempt) => {
371
+ const child = {
372
+ source,
373
+ release,
374
+ unsubscribe: () => {
375
+ },
376
+ ...attempt === void 0 ? {} : { attempt },
377
+ done: false
378
+ };
379
+ children.push(child);
380
+ child.unsubscribe = source.subscribe(pump);
381
+ source.done.then(
382
+ () => {
383
+ child.done = true;
384
+ pump();
385
+ },
386
+ (error) => {
387
+ if (child.attempt !== void 0 && !child.attempt.isCurrent()) {
388
+ child.done = true;
389
+ pump();
390
+ } else fail(error);
391
+ }
392
+ );
393
+ };
394
+ if (external !== void 0) addChild(external, () => {
395
+ });
396
+ return {
397
+ takeInitialSelections,
398
+ createSignalAttemptObservations: createServerSignalQueryAttemptObservations,
399
+ get streamedRenderer() {
400
+ return external?.streamedRenderer === true || children.some((child) => child.attempt !== void 0) ? true : void 0;
401
+ },
402
+ observeSignalAttempt(attempt, run) {
403
+ if (finished || !attempt.isCurrent()) {
404
+ attempt.release();
405
+ return;
406
+ }
407
+ const attemptKey = JSON.stringify([
408
+ attempt.ownerKey,
409
+ attempt.instanceKey,
410
+ attempt.nodeKey,
411
+ attempt.selectionKey,
412
+ attempt.attempt
413
+ ]);
414
+ if (observedAttempts.has(attemptKey)) {
415
+ attempt.release();
416
+ return;
417
+ }
418
+ if (children.length >= 256) {
419
+ attempt.release();
420
+ fail(new Error("Automatic streamed signals exceeded their channel budget."));
421
+ return;
422
+ }
423
+ observedAttempts.add(attemptKey);
424
+ if (timer === void 0) {
425
+ timer = setTimeout(
426
+ () => fail(new Error("Automatic streamed signals timed out.")),
427
+ budget.timeoutMs
428
+ );
429
+ }
430
+ const identity = {
431
+ protocol: 1,
432
+ buildId: options.buildId,
433
+ documentId: options.documentId,
434
+ ownerKey: attempt.ownerKey,
435
+ instanceKey: attempt.instanceKey,
436
+ nodeKey: attempt.nodeKey,
437
+ selectionKey: attempt.selectionKey,
438
+ selectionGeneration,
439
+ attempt: attempt.attempt
440
+ };
441
+ initialSelections?.push({ identity, attempt });
442
+ const source = createStreamedSignalInjection(identity, attempt.result, {
443
+ signal: attempt.signal,
444
+ run,
445
+ nonce: options.nonce,
446
+ announceSelection: initialSelections === void 0,
447
+ maxFrameBytes: budget.maxFrameBytes,
448
+ maxTotalBytes: budget.maxTotalBytes,
449
+ timeoutMs: budget.timeoutMs
450
+ });
451
+ addChild(source, attempt.release, attempt);
452
+ pump();
453
+ },
454
+ take() {
455
+ const html = queued;
456
+ queued = "";
457
+ return html;
458
+ },
459
+ subscribe(callback) {
460
+ notify = callback;
461
+ subscribed = true;
462
+ pump();
463
+ return () => {
464
+ if (notify === callback) notify = void 0;
465
+ };
466
+ },
467
+ accepted() {
468
+ const child = active;
469
+ active = void 0;
470
+ child?.source.accepted?.();
471
+ pump();
472
+ },
473
+ cancel: fail,
474
+ done,
475
+ renderComplete() {
476
+ renderComplete = true;
477
+ for (const child of children) child.source.renderComplete?.();
478
+ maybeDone();
479
+ }
480
+ };
481
+ }
482
+ export {
483
+ createAutomaticStreamedSignalInjection,
484
+ createStreamedRendererFrameStream,
485
+ createStreamedSignalInjection,
486
+ createStreamedSignalResultFrames,
487
+ streamedRendererFrameScript
488
+ };
@@ -0,0 +1,41 @@
1
+ /** Trusted, request-local capabilities. None of these fields are RPC arguments. */
2
+ export interface ServerCallContext<Viewer = unknown> {
3
+ readonly request: Request;
4
+ readonly signal: AbortSignal;
5
+ readonly viewer: Viewer;
6
+ readonly platform?: unknown;
7
+ }
8
+ /** Local caller options; the compiler never serializes these into RPC arguments. */
9
+ export interface ServerCallOptions {
10
+ signal?: AbortSignal;
11
+ }
12
+ export interface ServerFunctionTarget {
13
+ readonly id: string;
14
+ readonly module: string;
15
+ readonly export: string;
16
+ }
17
+ /** The host must authorize each invocation inside its own async request store. */
18
+ export interface ServerCallHost {
19
+ invoke<T>(target: ServerFunctionTarget, options: ServerCallOptions, execute: (context: ServerCallContext) => T): T | Promise<T>;
20
+ }
21
+ export interface ServerCallContextSource {
22
+ getStore(): ServerCallHost | undefined;
23
+ }
24
+ type CallerArguments<Args extends unknown[]> = Args extends [...infer Input, unknown] ? [...Input, options?: ServerCallOptions] : never;
25
+ export type ServerFunction<Fn extends (...args: any[]) => any> = (...args: CallerArguments<Parameters<Fn>>) => Promise<Awaited<ReturnType<Fn>>>;
26
+ export declare class InvalidServerFunctionPayloadError extends Error {
27
+ readonly code = "OCTANE_INVALID_RPC_PAYLOAD";
28
+ constructor(cause?: unknown);
29
+ }
30
+ /** @internal Host integration; the source contains no process-global request value. */
31
+ export declare function __setServerCallContextSource(source: ServerCallContextSource): void;
32
+ /** @internal Compiler target for exports with a final ServerCallContext parameter. */
33
+ export declare function __registerServerFunction<Fn extends (...args: any[]) => any>(fn: Fn, contextIndex: number, target: ServerFunctionTarget): ServerFunction<Fn>;
34
+ /**
35
+ * @internal Call a registered export in-process with the same per-invocation
36
+ * authorization as RPC. Returning/aliasing the export retains this wrapper.
37
+ */
38
+ export declare function __serverCall(fn: (...args: any[]) => unknown, args: unknown[], options?: ServerCallOptions): Promise<unknown>;
39
+ /** @internal Used only after the host has authorized this particular invocation. */
40
+ export declare function invokeServerFunction(fn: Function, args: unknown[], context?: ServerCallContext): unknown;
41
+ export {};
@@ -0,0 +1,75 @@
1
+ const SERVER_FUNCTION = /* @__PURE__ */ Symbol.for("octane.server.function");
2
+ const SERVER_CALL_SOURCE = /* @__PURE__ */ Symbol.for("octane.server.call-context");
3
+ const globals = globalThis;
4
+ class InvalidServerFunctionPayloadError extends Error {
5
+ code = "OCTANE_INVALID_RPC_PAYLOAD";
6
+ constructor(cause) {
7
+ super("Invalid server function arguments", { cause });
8
+ this.name = "InvalidServerFunctionPayloadError";
9
+ }
10
+ }
11
+ function __setServerCallContextSource(source) {
12
+ globals[SERVER_CALL_SOURCE] = source;
13
+ }
14
+ function registration(fn) {
15
+ return fn[SERVER_FUNCTION];
16
+ }
17
+ function __registerServerFunction(fn, contextIndex, target) {
18
+ if (!Number.isSafeInteger(contextIndex) || contextIndex < 0) {
19
+ throw new TypeError("Invalid server function context position");
20
+ }
21
+ const registered = Object.freeze({ fn, contextIndex, target: Object.freeze({ ...target }) });
22
+ const callable = (...args) => {
23
+ let options;
24
+ if (args.length === contextIndex + 1) {
25
+ options = args.pop();
26
+ }
27
+ return __serverCall(callable, args, options);
28
+ };
29
+ Object.defineProperty(callable, SERVER_FUNCTION, { value: registered });
30
+ return callable;
31
+ }
32
+ async function __serverCall(fn, args, options = {}) {
33
+ const registered = registration(fn);
34
+ if (registered === void 0) {
35
+ throw new TypeError("The server function is not registered");
36
+ }
37
+ if (options === null || typeof options !== "object" || Object.keys(options).some((key) => key !== "signal") || options.signal !== void 0 && !(options.signal instanceof AbortSignal)) {
38
+ throw new TypeError("Server function options accept only a local AbortSignal");
39
+ }
40
+ if (args.length > registered.contextIndex) {
41
+ throw new InvalidServerFunctionPayloadError();
42
+ }
43
+ options.signal?.throwIfAborted();
44
+ const host = globals[SERVER_CALL_SOURCE]?.getStore();
45
+ if (host === void 0) {
46
+ throw new Error("A contextual server function requires an active server request");
47
+ }
48
+ return host.invoke(
49
+ registered.target,
50
+ options,
51
+ (context) => invokeServerFunction(fn, args, context)
52
+ );
53
+ }
54
+ function invokeServerFunction(fn, args, context) {
55
+ const registered = registration(fn);
56
+ if (registered === void 0) return fn.apply(null, args);
57
+ if (context === void 0) {
58
+ throw new Error("A contextual server function requires trusted request context");
59
+ }
60
+ if (args.length > registered.contextIndex) {
61
+ throw new InvalidServerFunctionPayloadError();
62
+ }
63
+ context.signal.throwIfAborted();
64
+ const input = args.slice();
65
+ while (input.length < registered.contextIndex) input.push(void 0);
66
+ input.push(Object.freeze({ ...context }));
67
+ return registered.fn.apply(null, input);
68
+ }
69
+ export {
70
+ InvalidServerFunctionPayloadError,
71
+ __registerServerFunction,
72
+ __serverCall,
73
+ __setServerCallContextSource,
74
+ invokeServerFunction
75
+ };
@@ -0,0 +1,7 @@
1
+ import type { ServerCallOptions } from './server-call.js';
2
+ import { type ServerCallBatchOptions, type ServerResultLimits } from './server-rpc-protocol.js';
3
+ export declare const SERVER_BATCH_CONTENT_TYPE = "application/x-octane-rpc-batch+ndjson";
4
+ export type { ServerCallBatchOptions } from './server-rpc-protocol.js';
5
+ export declare function batchServerCalls<T>(options: ServerCallBatchOptions, callback: () => T): T;
6
+ /** @internal Called only after local argument encoding and abort validation. */
7
+ export declare function enqueueServerCall(hash: string, body: string, options: ServerCallOptions, limits?: ServerResultLimits): Promise<unknown> | undefined;