create-octane-xplat 0.7.3 → 0.10.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 (30) hide show
  1. package/README.md +28 -8
  2. package/index.mjs +112 -14
  3. package/package.json +15 -8
  4. package/scaffold.mjs +531 -0
  5. package/template/.agents/skills/xplat/SKILL.md +109 -40
  6. package/template/.agents/skills/xplat/references/components.md +149 -96
  7. package/template/.agents/skills/xplat/references/navigation.md +81 -31
  8. package/template/.agents/skills/xplat/references/platform.md +74 -35
  9. package/template/.agents/skills/xplat/references/styling.md +80 -27
  10. package/template/AGENTS.md +1 -1
  11. package/template/package.json +11 -9
  12. package/template/pnpm-workspace.yaml +66 -33
  13. package/template/src/App.tsrx +17 -8
  14. package/template/src/process.d.ts +7 -0
  15. package/template/src/style.css +24 -6
  16. package/template/tsconfig.json +1 -1
  17. package/template/vite.config.native.mts +3 -2
  18. package/template/vite.config.ts +5 -3
  19. package/template/App_Resources/iOS/src/OctaneShaders.metal +0 -128
  20. package/template/App_Resources/iOS/src/ShaderEffectRegistration.swift +0 -31
  21. package/template/patches/@nativescript-community__octane@0.2.1.patch +0 -16
  22. package/template/patches/@nativescript-community__vite-octane@0.2.1.patch +0 -41
  23. package/template/patches/@nativescript__core@9.1.2.patch +0 -794
  24. package/template/patches/@nativescript__core@9.1.3-next.2.patch +0 -428
  25. package/template/patches/@nativescript__vite@8.0.11.patch +0 -569
  26. package/template/patches/@nativescript__vite@8.0.13.patch +0 -233
  27. package/template/patches/@tsrx__typescript-plugin@0.4.11.patch +0 -11
  28. package/template/patches/css@3.0.0.patch +0 -52
  29. package/template/patches/octane@0.6.3.patch +0 -1149
  30. /package/template/src/{index.ts → main.ts} +0 -0
@@ -1,1149 +0,0 @@
1
- diff --git a/dist/cjs/runtime.cjs b/dist/cjs/runtime.cjs
2
- index 6f4f11c..dc96ffa 100644
3
- --- a/dist/cjs/runtime.cjs
4
- +++ b/dist/cjs/runtime.cjs
5
- @@ -354,6 +354,7 @@ var import_stream_protocol = require("./stream-protocol.cjs");
6
- var import_renderer_bridge = require("./renderer-bridge.cjs");
7
- var import_context_identity = require("./context-identity.cjs");
8
- var import_native_read_client = require("./signals/native-read-client.cjs");
9
- +var import_local_hook = require("./signals/local-hook.cjs");
10
- var import_native_read_collector = require("./signals/native-read-collector.cjs");
11
- var import_native_read_retry = require("./signals/native-read-retry.cjs");
12
- var import_transition_state = require("./signals/transition-state.cjs");
13
- @@ -7604,6 +7605,7 @@ function nativeLocalHook(name, initialize, dispose, slot) {
14
- }
15
- return cell.nativeValue;
16
- }
17
- +(0, import_local_hook.registerLocalSignalHook)(() => CURRENT_SCOPE === null ? null : nativeLocalHook);
18
- function useState(initial, slot) {
19
- const s = readStateHook(initial, slot, arguments.length === 1);
20
- return [s.value, s.setter];
21
- diff --git a/dist/cjs/signals/client.cjs b/dist/cjs/signals/client.cjs
22
- index 28e2844..af40518 100644
23
- --- a/dist/cjs/signals/client.cjs
24
- +++ b/dist/cjs/signals/client.cjs
25
- @@ -23,13 +23,13 @@ __export(client_exports, {
26
- });
27
- module.exports = __toCommonJS(client_exports);
28
- __reExport(client_exports, require("./index.cjs"), module.exports);
29
- -var import_runtime = require("../runtime.cjs");
30
- var import_engine = require("./engine.cjs");
31
- +var import_local_hook = require("./local-hook.cjs");
32
- function disposeLocalSignal(cell) {
33
- cell.scope.dispose();
34
- }
35
- function useSignal$(initial, slot) {
36
- - const cell = (0, import_runtime.nativeLocalHook)(
37
- + const cell = (0, import_local_hook.localSignalHook)(
38
- "useSignal$",
39
- () => {
40
- const value = typeof initial === "function" ? initial() : initial;
41
- diff --git a/dist/cjs/signals/document-owner.cjs b/dist/cjs/signals/document-owner.cjs
42
- index ea6b304..56a7439 100644
43
- --- a/dist/cjs/signals/document-owner.cjs
44
- +++ b/dist/cjs/signals/document-owner.cjs
45
- @@ -54,7 +54,9 @@ function enableSignalDocument(abi = 1) {
46
- if (defaultInstalled)
47
- return;
48
- defaultInstalled = true;
49
- - (0, import_owner_context.installDefaultSignalOwner)(() => typeof document === "undefined" ? null : documentSignalOwner(document));
50
- + if (typeof document === "undefined")
51
- + return;
52
- + (0, import_owner_context.installDefaultSignalOwner)(() => documentSignalOwner(document));
53
- }
54
- function installStreamedSignalOwnerActivator(activate) {
55
- if (streamedSignalOwnerActivator !== void 0) {
56
- diff --git a/dist/cjs/signals/index.cjs b/dist/cjs/signals/index.cjs
57
- index 865afcf..08dd675 100644
58
- --- a/dist/cjs/signals/index.cjs
59
- +++ b/dist/cjs/signals/index.cjs
60
- @@ -34,6 +34,7 @@ __export(signals_exports, {
61
- __derivedAt: () => import_derived_facade.__derivedAt,
62
- __derivedScalarAt: () => import_facade.__derivedScalarAt,
63
- __enableSignalDocument: () => import_document_owner.enableSignalDocument,
64
- + __enableUniversalSignalDocument: () => import_universal_owner.enableUniversalSignalDocument,
65
- __queryAt: () => import_query_facade.__queryAt,
66
- __signalAt: () => import_facade.__signalAt,
67
- __startSignalReads: () => import_facade.__startSignalReads,
68
- @@ -65,6 +66,7 @@ module.exports = __toCommonJS(signals_exports);
69
- var import_engine = require("./engine.cjs");
70
- var import_control_binding = require("./control-binding.cjs");
71
- var import_document_owner = require("./document-owner.cjs");
72
- +var import_universal_owner = require("./universal-owner.cjs");
73
- var import_requests = require("./requests.cjs");
74
- var import_actions = require("./actions.cjs");
75
- var import_derived_facade = require("./derived-facade.cjs");
76
- @@ -92,6 +94,7 @@ var import_types = require("./types.cjs");
77
- __derivedAt,
78
- __derivedScalarAt,
79
- __enableSignalDocument,
80
- + __enableUniversalSignalDocument,
81
- __queryAt,
82
- __signalAt,
83
- __startSignalReads,
84
- diff --git a/dist/cjs/signals/local-hook.cjs b/dist/cjs/signals/local-hook.cjs
85
- new file mode 100644
86
- index 0000000..4858595
87
- --- /dev/null
88
- +++ b/dist/cjs/signals/local-hook.cjs
89
- @@ -0,0 +1,44 @@
90
- +"use strict";
91
- +var __defProp = Object.defineProperty;
92
- +var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
93
- +var __getOwnPropNames = Object.getOwnPropertyNames;
94
- +var __hasOwnProp = Object.prototype.hasOwnProperty;
95
- +var __export = (target, all) => {
96
- + for (var name in all)
97
- + __defProp(target, name, { get: all[name], enumerable: true });
98
- +};
99
- +var __copyProps = (to, from, except, desc) => {
100
- + if (from && typeof from === "object" || typeof from === "function") {
101
- + for (let key of __getOwnPropNames(from))
102
- + if (!__hasOwnProp.call(to, key) && key !== except)
103
- + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
104
- + }
105
- + return to;
106
- +};
107
- +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
108
- +var local_hook_exports = {};
109
- +__export(local_hook_exports, {
110
- + localSignalHook: () => localSignalHook,
111
- + registerLocalSignalHook: () => registerLocalSignalHook
112
- +});
113
- +module.exports = __toCommonJS(local_hook_exports);
114
- +const probes = [];
115
- +function registerLocalSignalHook(probe) {
116
- + probes.push(probe);
117
- + return () => {
118
- + const index = probes.indexOf(probe);
119
- + if (index !== -1) probes.splice(index, 1);
120
- + };
121
- +}
122
- +function localSignalHook(name, initialize, dispose, slot) {
123
- + for (let index = probes.length - 1; index >= 0; index--) {
124
- + const hook = probes[index]();
125
- + if (hook !== null) return hook(name, initialize, dispose, slot);
126
- + }
127
- + throw new Error(`${name} requires an active Octane component render.`);
128
- +}
129
- +// Annotate the CommonJS export names for ESM import in node:
130
- +0 && (module.exports = {
131
- + localSignalHook,
132
- + registerLocalSignalHook
133
- +});
134
- diff --git a/dist/cjs/signals/universal-owner.cjs b/dist/cjs/signals/universal-owner.cjs
135
- new file mode 100644
136
- index 0000000..00c323a
137
- --- /dev/null
138
- +++ b/dist/cjs/signals/universal-owner.cjs
139
- @@ -0,0 +1,46 @@
140
- +"use strict";
141
- +var __defProp = Object.defineProperty;
142
- +var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
143
- +var __getOwnPropNames = Object.getOwnPropertyNames;
144
- +var __hasOwnProp = Object.prototype.hasOwnProperty;
145
- +var __export = (target, all) => {
146
- + for (var name in all)
147
- + __defProp(target, name, { get: all[name], enumerable: true });
148
- +};
149
- +var __copyProps = (to, from, except, desc) => {
150
- + if (from && typeof from === "object" || typeof from === "function") {
151
- + for (let key of __getOwnPropNames(from))
152
- + if (!__hasOwnProp.call(to, key) && key !== except)
153
- + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
154
- + }
155
- + return to;
156
- +};
157
- +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
158
- +var universal_owner_exports = {};
159
- +__export(universal_owner_exports, {
160
- + enableUniversalSignalDocument: () => enableUniversalSignalDocument,
161
- + installUniversalSignalDocumentProvider: () => installUniversalSignalDocumentProvider,
162
- + universalSignalDocument: () => universalSignalDocument
163
- +});
164
- +module.exports = __toCommonJS(universal_owner_exports);
165
- +var import_owner_context = require("./owner-context.cjs");
166
- +let universalOwner;
167
- +let provider;
168
- +function installUniversalSignalDocumentProvider(next) {
169
- + provider = next;
170
- +}
171
- +function universalSignalDocument() {
172
- + return provider?.() ?? (universalOwner ??= Object.freeze({ scopeKey: "octane:universal" }));
173
- +}
174
- +function enableUniversalSignalDocument(abi = 1) {
175
- + if (abi !== 1) {
176
- + throw new TypeError("Unsupported universal signal owner ABI.");
177
- + }
178
- + (0, import_owner_context.installDefaultSignalOwner)(universalSignalDocument);
179
- +}
180
- +// Annotate the CommonJS export names for ESM import in node:
181
- +0 && (module.exports = {
182
- + enableUniversalSignalDocument,
183
- + installUniversalSignalDocumentProvider,
184
- + universalSignalDocument
185
- +});
186
- diff --git a/dist/compiler/compile.js b/dist/compiler/compile.js
187
- index cdf5a08..64a3571 100644
188
- --- a/dist/compiler/compile.js
189
- +++ b/dist/compiler/compile.js
190
- @@ -2275,7 +2275,7 @@ function classifyViewTransitionOwnership(astBody, production, ownComponents) {
191
-
192
- function hookRuntimeModulesForCompile(options, universalUnits = []) {
193
- const modules = new Set(options?.__hookRuntimeModules || []);
194
- - if (options?.nativeReads === true) {
195
- + if (options?.nativeReads === true || options?.__universalSignalReads === true) {
196
- modules.add('octane/signals/client');
197
- modules.add('octane/signals/server');
198
- }
199
- @@ -10112,6 +10112,11 @@ function compileInternal(
200
- universalRuntime: undefined,
201
- rendererBoundaries: undefined,
202
- rendererRegistry: undefined,
203
- + // Universal owners observe reads at render time; the inner
204
- + // compile must not emit the DOM native-read runtime helpers,
205
- + // but signal hook classification still applies.
206
- + nativeReads: false,
207
- + __universalSignalReads: options.nativeReads === true,
208
- __hookRuntimeModules: [...(options?.__hookRuntimeModules || []), renderer.module],
209
- __runtimeImportRoutes: [
210
- ...(options?.__runtimeImportRoutes ?? []),
211
- @@ -10360,6 +10365,10 @@ function compileInternal(
212
- autoMemo: autoMemoEnabled,
213
- strongMemo: strongMemoEnabled,
214
- nativeReads: options?.nativeReads === true,
215
- + // Universal renders observe signal reads at runtime through the owner
216
- + // environment; hook classification still needs to know the module imports
217
- + // the signals runtime even though no DOM native-read helpers are emitted.
218
- + signalReads: options?.nativeReads === true || options?.__universalSignalReads === true,
219
- nativeModuleStyles: options?.nativeReads === true && hasModuleStyleMaps(ast.body),
220
- // A split Hydrate query module is invoked as the existing server-rendered
221
- // boundary body. Its sole component child must therefore keep the server's
222
- @@ -11805,6 +11814,10 @@ function compileServer(
223
- compilerNameSuffixes: null,
224
- mode: 'server',
225
- nativeReads: options?.nativeReads === true,
226
- + // Universal renders observe signal reads at runtime through the owner
227
- + // environment; hook classification still needs to know the module imports
228
- + // the signals runtime even though no DOM native-read helpers are emitted.
229
- + signalReads: options?.nativeReads === true || options?.__universalSignalReads === true,
230
- nativeModuleStyles: options?.nativeReads === true && hasModuleStyleMaps(ast.body),
231
- hmr: false, // SSR never hot-swaps in place; client/server production slot shapes stay aligned
232
- dev: !!(options && options.dev),
233
- @@ -18960,7 +18973,7 @@ function slotKeyedHookName(n, ctx) {
234
- ctx.foreignImportLocals?.has(local) === true;
235
- if (
236
- imported !== undefined &&
237
- - (HOOK_NAMES.has(imported) || (ctx.nativeReads && NATIVE_SIGNAL_HOOK_NAMES.has(imported)))
238
- + (HOOK_NAMES.has(imported) || (ctx.signalReads && NATIVE_SIGNAL_HOOK_NAMES.has(imported)))
239
- )
240
- return imported;
241
- if (!shadowsImport && HOOK_NAMES.has(local)) return local;
242
- @@ -18970,7 +18983,7 @@ function slotKeyedHookName(n, ctx) {
243
- const imported = n._octaneImportedHook ?? n._octaneHookRuntimeImportedHook;
244
- if (
245
- imported !== undefined &&
246
- - (HOOK_NAMES.has(imported) || (ctx.nativeReads && NATIVE_SIGNAL_HOOK_NAMES.has(imported)))
247
- + (HOOK_NAMES.has(imported) || (ctx.signalReads && NATIVE_SIGNAL_HOOK_NAMES.has(imported)))
248
- ) {
249
- return imported;
250
- }
251
- @@ -19817,7 +19830,7 @@ function rewriteHookCalls(node, ctx, componentName, localRoot = false) {
252
- // enforced by rejectHookInJsLoop.
253
- const isBuiltin =
254
- (HOOK_NAMES.has(name) ||
255
- - (ctx.nativeReads &&
256
- + (ctx.signalReads &&
257
- hookRuntimeImportedName !== undefined &&
258
- NATIVE_SIGNAL_HOOK_NAMES.has(name))) &&
259
- (generated ||
260
- @@ -19946,7 +19959,7 @@ function rewriteHookCalls(node, ctx, componentName, localRoot = false) {
261
- ) {
262
- const name = n._octaneImportedHook ?? n._octaneHookRuntimeImportedHook;
263
- const isBuiltin =
264
- - HOOK_NAMES.has(name) || (ctx.nativeReads && NATIVE_SIGNAL_HOOK_NAMES.has(name));
265
- + HOOK_NAMES.has(name) || (ctx.signalReads && NATIVE_SIGNAL_HOOK_NAMES.has(name));
266
- const isServerUse = name === 'use' && ctx.mode === 'server';
267
- if (isBuiltin || isServerUse) {
268
- if (isBuiltin) {
269
- diff --git a/dist/compiler/native-read-diagnostics.js b/dist/compiler/native-read-diagnostics.js
270
- index 3ec74f3..0816e98 100644
271
- --- a/dist/compiler/native-read-diagnostics.js
272
- +++ b/dist/compiler/native-read-diagnostics.js
273
- @@ -87,9 +87,12 @@ export function assertNativeReadOptions(options) {
274
- if (
275
- options?.nativeReads === true &&
276
- options.renderer?.target != null &&
277
- - options.renderer.target !== 'dom'
278
- + options.renderer.target !== 'dom' &&
279
- + options.renderer.target !== 'universal'
280
- ) {
281
- - throw new Error('Octane native signal reads support only the DOM client and server.');
282
- + throw new Error(
283
- + 'Octane native signal reads support only the DOM client, DOM server, and universal renderers.',
284
- + );
285
- }
286
- }
287
-
288
- @@ -108,11 +111,11 @@ export function analyzeNativeReadDiagnostics(ast, source, filename, options = {}
289
- filename,
290
- rendererBoundaries: options.rendererBoundaries,
291
- });
292
- - const unsupported = boundaries.find(
293
- - (boundary) =>
294
- - boundary.childRenderer !== 'dom' &&
295
- - options.rendererRegistry?.[boundary.childRenderer]?.target !== 'dom',
296
- - );
297
- + const unsupported = boundaries.find((boundary) => {
298
- + if (boundary.childRenderer === 'dom') return false;
299
- + const target = options.rendererRegistry?.[boundary.childRenderer]?.target;
300
- + return target !== 'dom' && target !== 'universal';
301
- + });
302
- if (unsupported)
303
- return [
304
- nativeReadDiagnostic(
305
- diff --git a/dist/compiler/slot-hooks.js b/dist/compiler/slot-hooks.js
306
- index 7b2f867..2c1d36c 100644
307
- --- a/dist/compiler/slot-hooks.js
308
- +++ b/dist/compiler/slot-hooks.js
309
- @@ -1182,12 +1182,12 @@ function walk(node, owner, st) {
310
- }
311
- const imported =
312
- node._octaneImportedHook ??
313
- - (st.nativeReads ? node._octaneHookRuntimeImportedHook : undefined);
314
- + (st.signalReads ? node._octaneHookRuntimeImportedHook : undefined);
315
- collectStateGetterEdit(node, imported, st);
316
- if (
317
- !st.manualSlots &&
318
- imported &&
319
- - (HOOK_NAMES.has(imported) || (st.nativeReads && NATIVE_SIGNAL_HOOK_NAMES.has(imported)))
320
- + (HOOK_NAMES.has(imported) || (st.signalReads && NATIVE_SIGNAL_HOOK_NAMES.has(imported)))
321
- ) {
322
- const local =
323
- node.callee?.type === 'Identifier'
324
- @@ -1398,7 +1398,11 @@ export function slotHooks(source, id, options) {
325
- HOOK_NAMES.has(name),
326
- );
327
- const manualProviders = options?.manualSlots ? findManualHookProviders(ast) : new Map();
328
- - const nativeReadActivation = options?.nativeReads === true && importsNativeRenderer(ast);
329
- + // Universal renderers observe reads at render time; the DOM collection
330
- + // driver and its activation helper only apply to dom targets.
331
- + const universalTarget = options?.renderer?.target === 'universal';
332
- + const nativeReadActivation =
333
- + options?.nativeReads === true && !universalTarget && importsNativeRenderer(ast);
334
- const signalLowering = signalDeclarationSourceEdits(ast, id, source);
335
- const pureCalls = collectPureFactoryCalls(
336
- ast,
337
- @@ -1487,7 +1491,8 @@ export function slotHooks(source, id, options) {
338
- ]),
339
- ),
340
- manualSlots: options?.manualSlots === true,
341
- - nativeReads: options?.nativeReads === true,
342
- + nativeReads: options?.nativeReads === true && !universalTarget,
343
- + signalReads: options?.nativeReads === true,
344
- locals: importInfo.locals,
345
- source,
346
- inferred,
347
- @@ -1590,7 +1595,9 @@ export function slotHooks(source, id, options) {
348
- ? 'enableServerSignalBindings'
349
- : nativeReadActivation
350
- ? 'enableSignalBindings'
351
- - : '__enableSignalDocument';
352
- + : universalTarget
353
- + ? '__enableUniversalSignalDocument'
354
- + : '__enableSignalDocument';
355
- const local = allocSlotName(st, `_$${imported}`);
356
- let specifiers = signalHelperImports.get(request);
357
- if (specifiers === undefined) signalHelperImports.set(request, (specifiers = []));
358
- diff --git a/dist/node/runtime.js b/dist/node/runtime.js
359
- index 21d10d9..2a0b420 100644
360
- --- a/dist/node/runtime.js
361
- +++ b/dist/node/runtime.js
362
- @@ -162,6 +162,7 @@ import {
363
- import { isRendererContext, registerClientRendererBridge } from "./renderer-bridge.js";
364
- import { defineRemovedContextMembers, registerContext } from "./context-identity.js";
365
- import { createNativeReadDriver } from "./signals/native-read-client.js";
366
- +import { registerLocalSignalHook } from "./signals/local-hook.js";
367
- import {
368
- validateNativeReadWitness
369
- } from "./signals/native-read-collector.js";
370
- @@ -7456,6 +7457,7 @@ function nativeLocalHook(name, initialize, dispose, slot) {
371
- }
372
- return cell.nativeValue;
373
- }
374
- +registerLocalSignalHook(() => CURRENT_SCOPE === null ? null : nativeLocalHook);
375
- function useState(initial, slot) {
376
- const s = readStateHook(initial, slot, arguments.length === 1);
377
- return [s.value, s.setter];
378
- diff --git a/dist/node/signals/client.js b/dist/node/signals/client.js
379
- index 21a39c3..3f85700 100644
380
- --- a/dist/node/signals/client.js
381
- +++ b/dist/node/signals/client.js
382
- @@ -1,11 +1,11 @@
383
- export * from "./index.js";
384
- -import { nativeLocalHook } from "../runtime.js";
385
- import { createLocalScope } from "./engine.js";
386
- +import { localSignalHook } from "./local-hook.js";
387
- function disposeLocalSignal(cell) {
388
- cell.scope.dispose();
389
- }
390
- function useSignal$(initial, slot) {
391
- - const cell = nativeLocalHook(
392
- + const cell = localSignalHook(
393
- "useSignal$",
394
- () => {
395
- const value = typeof initial === "function" ? initial() : initial;
396
- diff --git a/dist/node/signals/document-owner.js b/dist/node/signals/document-owner.js
397
- index 0decc92..59a9486 100644
398
- --- a/dist/node/signals/document-owner.js
399
- +++ b/dist/node/signals/document-owner.js
400
- @@ -27,7 +27,9 @@ function enableSignalDocument(abi = 1) {
401
- if (defaultInstalled)
402
- return;
403
- defaultInstalled = true;
404
- - installDefaultSignalOwner(() => typeof document === "undefined" ? null : documentSignalOwner(document));
405
- + if (typeof document === "undefined")
406
- + return;
407
- + installDefaultSignalOwner(() => documentSignalOwner(document));
408
- }
409
- function installStreamedSignalOwnerActivator(activate) {
410
- if (streamedSignalOwnerActivator !== void 0) {
411
- diff --git a/dist/node/signals/index.js b/dist/node/signals/index.js
412
- index 8ae19e5..0bf09f5 100644
413
- --- a/dist/node/signals/index.js
414
- +++ b/dist/node/signals/index.js
415
- @@ -1,6 +1,7 @@
416
- import { createScope } from "./engine.js";
417
- import { bindSignalControl } from "./control-binding.js";
418
- import { enableSignalDocument } from "./document-owner.js";
419
- +import { enableUniversalSignalDocument } from "./universal-owner.js";
420
- import { createResource, query } from "./requests.js";
421
- import { ActionUncertainError, action$, isActionUncertain, optimistic$ } from "./actions.js";
422
- import { __derivedAt, derived$ } from "./derived-facade.js";
423
- @@ -58,6 +59,7 @@ export {
424
- __derivedAt,
425
- __derivedScalarAt,
426
- enableSignalDocument as __enableSignalDocument,
427
- + enableUniversalSignalDocument as __enableUniversalSignalDocument,
428
- __queryAt,
429
- __signalAt,
430
- __startSignalReads,
431
- diff --git a/dist/node/signals/local-hook.js b/dist/node/signals/local-hook.js
432
- new file mode 100644
433
- index 0000000..77c63f5
434
- --- /dev/null
435
- +++ b/dist/node/signals/local-hook.js
436
- @@ -0,0 +1,19 @@
437
- +const probes = [];
438
- +function registerLocalSignalHook(probe) {
439
- + probes.push(probe);
440
- + return () => {
441
- + const index = probes.indexOf(probe);
442
- + if (index !== -1) probes.splice(index, 1);
443
- + };
444
- +}
445
- +function localSignalHook(name, initialize, dispose, slot) {
446
- + for (let index = probes.length - 1; index >= 0; index--) {
447
- + const hook = probes[index]();
448
- + if (hook !== null) return hook(name, initialize, dispose, slot);
449
- + }
450
- + throw new Error(`${name} requires an active Octane component render.`);
451
- +}
452
- +export {
453
- + localSignalHook,
454
- + registerLocalSignalHook
455
- +};
456
- diff --git a/dist/node/signals/universal-owner.js b/dist/node/signals/universal-owner.js
457
- new file mode 100644
458
- index 0000000..ff5eb43
459
- --- /dev/null
460
- +++ b/dist/node/signals/universal-owner.js
461
- @@ -0,0 +1,20 @@
462
- +import { installDefaultSignalOwner } from "./owner-context.js";
463
- +let universalOwner;
464
- +let provider;
465
- +function installUniversalSignalDocumentProvider(next) {
466
- + provider = next;
467
- +}
468
- +function universalSignalDocument() {
469
- + return provider?.() ?? (universalOwner ??= Object.freeze({ scopeKey: "octane:universal" }));
470
- +}
471
- +function enableUniversalSignalDocument(abi = 1) {
472
- + if (abi !== 1) {
473
- + throw new TypeError("Unsupported universal signal owner ABI.");
474
- + }
475
- + installDefaultSignalOwner(universalSignalDocument);
476
- +}
477
- +export {
478
- + enableUniversalSignalDocument,
479
- + installUniversalSignalDocumentProvider,
480
- + universalSignalDocument
481
- +};
482
- diff --git a/dist/node/universal-core.js b/dist/node/universal-core.js
483
- index 4dbe2f9..8184bd9 100644
484
- --- a/dist/node/universal-core.js
485
- +++ b/dist/node/universal-core.js
486
- @@ -17,6 +17,14 @@ import {
487
- } from "./profiling.js";
488
- import { getRendererHostFlusher } from "./renderer-bridge.js";
489
- import { resolveLazyDefaultProps } from "./shared-value-helpers.js";
490
- +import { universalSignalDocument } from "./signals/universal-owner.js";
491
- +import { registerLocalSignalHook } from "./signals/local-hook.js";
492
- +import { retireSignalOwnerIdentity, runWithSignalOwner } from "./signals/owner-context.js";
493
- +import {
494
- + beginNativeWriteGuard,
495
- + endNativeWriteGuard,
496
- + setNativeReadObserver
497
- +} from "./signals/read-protocol.js";
498
- import { __methodDep } from "./method-dep.js";
499
- const UNIVERSAL_PLAN = /* @__PURE__ */ Symbol.for("octane.universal.plan");
500
- const UNIVERSAL_VALUE = /* @__PURE__ */ Symbol.for("octane.universal.value");
501
- @@ -842,6 +850,7 @@ function draftOwner(record, parent, replayPath) {
502
- boundaryThenable: record.boundaryThenable,
503
- isBoundary: record.isBoundary,
504
- canHandleSuspense: record.canHandleSuspense,
505
- + signalReads: null,
506
- visibility: parent?.visibility ?? record.visibility,
507
- contextStable: null
508
- };
509
- @@ -1012,6 +1021,7 @@ function executeOwner(owner, build, initialRenderCount = 0) {
510
- owner.contextStable = null;
511
- owner.needsRender = false;
512
- owner.implicitSlot = 0;
513
- + owner.signalReads = NO_SIGNAL_READS;
514
- const previousOwner = CURRENT_OWNER;
515
- const previousAttemptOwner = attempt.owner;
516
- CURRENT_OWNER = owner;
517
- @@ -1023,13 +1033,18 @@ function executeOwner(owner, build, initialRenderCount = 0) {
518
- const profileFrame = typeof __OCTANE_PROFILE_ENABLED__ !== "undefined" && __OCTANE_PROFILE_ENABLED__ && component !== null ? __profileBeginRender(owner.record, component, owner.record.mounted) : null;
519
- let didThrow = false;
520
- let thrown;
521
- + const signalOwner = universalSignalOwner(owner.record);
522
- + const previousReadObserver = setNativeReadObserver(observeUniversalSignalRead);
523
- + const writeGuard = beginNativeWriteGuard();
524
- try {
525
- - output = build();
526
- + output = runWithSignalOwner(signalOwner, build);
527
- } catch (error) {
528
- didThrow = true;
529
- - thrown = error;
530
- - throw error;
531
- + thrown = isThenable(error) ? new UniversalSuspense(error) : error;
532
- + throw thrown;
533
- } finally {
534
- + endNativeWriteGuard(writeGuard);
535
- + setNativeReadObserver(previousReadObserver);
536
- if (typeof __OCTANE_PROFILE_ENABLED__ !== "undefined" && __OCTANE_PROFILE_ENABLED__) {
537
- __profileEndRender(profileFrame, didThrow, thrown);
538
- }
539
- @@ -1196,6 +1211,8 @@ function disposeUncommittedDraft(owner) {
540
- owner.record.componentProps = null;
541
- owner.record.range = null;
542
- owner.record.updates.clear();
543
- + disposeUniversalSignalReads(owner.record);
544
- + disposeUniversalLocalHooks(owner.hooks);
545
- for (const hook of owner.hooks.values()) {
546
- if (hook.kind === "effect-event") hook.cell.active = false;
547
- }
548
- @@ -3142,6 +3159,85 @@ function scheduleOwner(owner, slot) {
549
- }
550
- owner.root.scheduleOwned(owner);
551
- }
552
- +const UNIVERSAL_SIGNAL_OWNERS = /* @__PURE__ */ new WeakMap();
553
- +function universalSignalOwner(record) {
554
- + let owner = UNIVERSAL_SIGNAL_OWNERS.get(record);
555
- + if (owner === void 0) {
556
- + const documentOwner = universalSignalDocument();
557
- + const identity = {
558
- + scopeKey: documentOwner.scopeKey,
559
- + documentOwner,
560
- + // The identity object itself is the opaque per-instance token — the
561
- + // same shape DOM scopes use, so identity maps never retain the record.
562
- + instanceOwner: null,
563
- + instanceKey: `u:${record.id}`
564
- + };
565
- + identity.instanceOwner = identity;
566
- + owner = Object.freeze(identity);
567
- + UNIVERSAL_SIGNAL_OWNERS.set(record, owner);
568
- + }
569
- + return owner;
570
- +}
571
- +const NO_SIGNAL_READS = /* @__PURE__ */ new Set();
572
- +function observeUniversalSignalRead(source) {
573
- + const owner = CURRENT_OWNER;
574
- + if (owner === null) return;
575
- + if (owner.signalReads === NO_SIGNAL_READS) owner.signalReads = /* @__PURE__ */ new Set();
576
- + owner.signalReads.add(source);
577
- +}
578
- +function commitUniversalSignalReads(record, reads) {
579
- + if (reads === null) return;
580
- + let subscriptions = record.signalSubscriptions;
581
- + if (subscriptions !== void 0) {
582
- + for (const [source, unsubscribe] of subscriptions) {
583
- + if (!reads.has(source)) {
584
- + subscriptions.delete(source);
585
- + unsubscribe();
586
- + }
587
- + }
588
- + }
589
- + for (const source of reads) {
590
- + if (subscriptions?.has(source)) continue;
591
- + if (subscriptions === void 0) {
592
- + subscriptions = /* @__PURE__ */ new Map();
593
- + record.signalSubscriptions = subscriptions;
594
- + }
595
- + subscriptions.set(
596
- + source,
597
- + source.subscribe(() => {
598
- + if (!record.disposed) scheduleOwner(record);
599
- + })
600
- + );
601
- + }
602
- + if (subscriptions !== void 0 && subscriptions.size === 0) {
603
- + record.signalSubscriptions = void 0;
604
- + }
605
- +}
606
- +function disposeUniversalSignalReads(record) {
607
- + const subscriptions = record.signalSubscriptions;
608
- + if (subscriptions !== void 0) {
609
- + record.signalSubscriptions = void 0;
610
- + for (const unsubscribe of subscriptions.values()) unsubscribe();
611
- + }
612
- + const owner = UNIVERSAL_SIGNAL_OWNERS.get(record);
613
- + if (owner !== void 0) retireSignalOwnerIdentity(owner);
614
- +}
615
- +function disposeUniversalLocalHooks(hooks) {
616
- + for (const hook of hooks.values()) {
617
- + if (hook.kind === "local") hook.dispose(hook.value);
618
- + }
619
- +}
620
- +function universalLocalHook(_name, initialize, dispose, slot) {
621
- + const owner = currentDraftOwner();
622
- + const resolved = resolveHookSlot(slot);
623
- + let cell = owner.hooks.get(resolved);
624
- + if (cell === void 0) {
625
- + cell = { kind: "local", value: initialize(), dispose };
626
- + owner.hooks.set(resolved, cell);
627
- + }
628
- + return cell.value;
629
- +}
630
- +registerLocalSignalHook(() => CURRENT_OWNER === null ? null : universalLocalHook);
631
- function currentDraftOwner() {
632
- currentAttempt();
633
- const owner = activateLazyLeafOwner();
634
- @@ -5520,7 +5616,7 @@ class UniversalRootImpl {
635
- }
636
- let result;
637
- try {
638
- - result = event.handler(payload);
639
- + result = runWithSignalOwner(universalSignalOwner(event.owner), () => event.handler(payload));
640
- } catch (error) {
641
- if (!routeUniversalOwnerError(event.owner, error)) throw error;
642
- }
643
- @@ -6096,6 +6192,8 @@ class UniversalRootImpl {
644
- draft.record.componentProps = null;
645
- draft.record.range = null;
646
- draft.record.updates.clear();
647
- + disposeUniversalSignalReads(draft.record);
648
- + disposeUniversalLocalHooks(draft.hooks);
649
- for (const hook of draft.hooks.values()) {
650
- if (hook.kind === "effect-event") hook.cell.active = false;
651
- }
652
- @@ -6776,6 +6874,7 @@ class UniversalRootImpl {
653
- owner.componentProps = draftOwner2.componentProps;
654
- owner.componentRevision = draftOwner2.componentRevision;
655
- owner.hooks = draftOwner2.hooks;
656
- + commitUniversalSignalReads(owner, draftOwner2.signalReads);
657
- for (const [slot, applied] of draftOwner2.appliedUpdates) {
658
- const queue = owner.updates.get(slot);
659
- if (queue !== applied.queue || applied.lane) continue;
660
- @@ -6809,6 +6908,7 @@ class UniversalRootImpl {
661
- record.componentRevision = draft.componentRevision;
662
- record.parent = draft.parent?.record ?? null;
663
- record.hooks = draft.hooks;
664
- + commitUniversalSignalReads(record, draft.signalReads);
665
- record.effectOrder = [...draft.seenEffects];
666
- for (let index = 0; index < draft.seenEffects.length; index++) {
667
- draft.seenEffects[index].previous = null;
668
- @@ -8455,6 +8555,8 @@ class UniversalRootImpl {
669
- owner.componentProps = null;
670
- owner.range = null;
671
- owner.updates.clear();
672
- + disposeUniversalSignalReads(owner);
673
- + disposeUniversalLocalHooks(owner.hooks);
674
- }
675
- for (const draft of draftOwnersParentFirst) {
676
- const record = draft.record;
677
- @@ -8464,6 +8566,7 @@ class UniversalRootImpl {
678
- record.parent = draft.parent?.record ?? null;
679
- }
680
- record.hooks = draft.hooks;
681
- + commitUniversalSignalReads(record, draft.signalReads);
682
- record.effectOrder = [...draft.seenEffects];
683
- for (let index = 0; index < draft.seenEffects.length; index++) {
684
- draft.seenEffects[index].previous = null;
685
- @@ -8985,6 +9088,8 @@ class UniversalRootImpl {
686
- owner.componentProps = null;
687
- owner.range = null;
688
- owner.updates.clear();
689
- + disposeUniversalSignalReads(owner);
690
- + disposeUniversalLocalHooks(owner.hooks);
691
- }
692
- const deactivatedRegionCells = /* @__PURE__ */ new Set();
693
- for (const bridge of regionBridges) {
694
- diff --git a/dist/node/universal-native.js b/dist/node/universal-native.js
695
- index 55ac9b6..3ff9a57 100644
696
- --- a/dist/node/universal-native.js
697
- +++ b/dist/node/universal-native.js
698
- @@ -6,9 +6,11 @@ import {
699
- import {
700
- universalContext
701
- } from "./universal-core.js";
702
- +import { enableUniversalSignalDocument } from "./signals/universal-owner.js";
703
- import { registerRendererContext, renderRendererContextProvider } from "./renderer-bridge.js";
704
- import { CONTEXT_TAG } from "./runtime-tags.js";
705
- import { registerContext } from "./context-identity.js";
706
- +enableUniversalSignalDocument();
707
- // @__NO_SIDE_EFFECTS__
708
- function createContext(defaultValue) {
709
- const context = ((props, scope) => scope === void 0 ? universalContext(context, props.value, props.children) : renderRendererContextProvider(context, props, scope));
710
- diff --git a/dist/node/universal.js b/dist/node/universal.js
711
- index 6427a01..8049b78 100644
712
- --- a/dist/node/universal.js
713
- +++ b/dist/node/universal.js
714
- @@ -8,6 +8,9 @@ import {
715
- createUniversalHostBoundary,
716
- registerUniversalHostBridge
717
- } from "./universal-dom-boundary.js";
718
- +import { documentSignalOwner } from "./signals/document-owner.js";
719
- +import { installUniversalSignalDocumentProvider } from "./signals/universal-owner.js";
720
- +installUniversalSignalDocumentProvider(() => documentSignalOwner(document));
721
- export {
722
- createContext,
723
- createSubSlot,
724
- diff --git a/dist/runtime.js b/dist/runtime.js
725
- index ee2a2bd..4f9f1b5 100644
726
- --- a/dist/runtime.js
727
- +++ b/dist/runtime.js
728
- @@ -161,6 +161,7 @@ import {
729
- import { isRendererContext, registerClientRendererBridge } from "./renderer-bridge.js";
730
- import { defineRemovedContextMembers, registerContext } from "./context-identity.js";
731
- import { createNativeReadDriver } from "./signals/native-read-client.js";
732
- +import { registerLocalSignalHook } from "./signals/local-hook.js";
733
- import {
734
- validateNativeReadWitness
735
- } from "./signals/native-read-collector.js";
736
- @@ -7455,6 +7456,7 @@ function nativeLocalHook(name, initialize, dispose, slot) {
737
- }
738
- return cell.nativeValue;
739
- }
740
- +registerLocalSignalHook(() => CURRENT_SCOPE === null ? null : nativeLocalHook);
741
- function useState(initial, slot) {
742
- const s = readStateHook(initial, slot, arguments.length === 1);
743
- return [s.value, s.setter];
744
- diff --git a/dist/signals/client.d.ts b/dist/signals/client.d.ts
745
- index 6388c2f..f9e9862 100644
746
- --- a/dist/signals/client.d.ts
747
- +++ b/dist/signals/client.d.ts
748
- @@ -1,4 +1,4 @@
749
- -/** Optional component hooks for the native-read DOM compiler mode. */
750
- +/** Optional component hooks for the native-read compiler mode (DOM and universal). */
751
- export * from './index.js';
752
- import type { WritableSignal } from './types.js';
753
- /** A writable signal owned by this compiler-assigned component hook slot. */
754
- diff --git a/dist/signals/client.js b/dist/signals/client.js
755
- index 21a39c3..3f85700 100644
756
- --- a/dist/signals/client.js
757
- +++ b/dist/signals/client.js
758
- @@ -1,11 +1,11 @@
759
- export * from "./index.js";
760
- -import { nativeLocalHook } from "../runtime.js";
761
- import { createLocalScope } from "./engine.js";
762
- +import { localSignalHook } from "./local-hook.js";
763
- function disposeLocalSignal(cell) {
764
- cell.scope.dispose();
765
- }
766
- function useSignal$(initial, slot) {
767
- - const cell = nativeLocalHook(
768
- + const cell = localSignalHook(
769
- "useSignal$",
770
- () => {
771
- const value = typeof initial === "function" ? initial() : initial;
772
- diff --git a/dist/signals/document-owner.js b/dist/signals/document-owner.js
773
- index cd4e628..078dcd3 100644
774
- --- a/dist/signals/document-owner.js
775
- +++ b/dist/signals/document-owner.js
776
- @@ -26,7 +26,9 @@ function enableSignalDocument(abi = 1) {
777
- if (defaultInstalled)
778
- return;
779
- defaultInstalled = true;
780
- - installDefaultSignalOwner(() => typeof document === "undefined" ? null : documentSignalOwner(document));
781
- + if (typeof document === "undefined")
782
- + return;
783
- + installDefaultSignalOwner(() => documentSignalOwner(document));
784
- }
785
- function installStreamedSignalOwnerActivator(activate) {
786
- if (streamedSignalOwnerActivator !== void 0) {
787
- diff --git a/dist/signals/index.d.ts b/dist/signals/index.d.ts
788
- index 95f32a2..9855985 100644
789
- --- a/dist/signals/index.d.ts
790
- +++ b/dist/signals/index.d.ts
791
- @@ -3,6 +3,7 @@ export { createScope } from './engine.js';
792
- export { bindSignalControl } from './control-binding.js';
793
- export type { SignalControlBinding } from './control-handoff.js';
794
- export { enableSignalDocument as __enableSignalDocument } from './document-owner.js';
795
- +export { enableUniversalSignalDocument as __enableUniversalSignalDocument } from './universal-owner.js';
796
- export { createResource, query } from './requests.js';
797
- export { ActionUncertainError, action$, isActionUncertain, optimistic$ } from './actions.js';
798
- export { __derivedAt, derived$ } from './derived-facade.js';
799
- diff --git a/dist/signals/index.js b/dist/signals/index.js
800
- index 8ae19e5..0bf09f5 100644
801
- --- a/dist/signals/index.js
802
- +++ b/dist/signals/index.js
803
- @@ -1,6 +1,7 @@
804
- import { createScope } from "./engine.js";
805
- import { bindSignalControl } from "./control-binding.js";
806
- import { enableSignalDocument } from "./document-owner.js";
807
- +import { enableUniversalSignalDocument } from "./universal-owner.js";
808
- import { createResource, query } from "./requests.js";
809
- import { ActionUncertainError, action$, isActionUncertain, optimistic$ } from "./actions.js";
810
- import { __derivedAt, derived$ } from "./derived-facade.js";
811
- @@ -58,6 +59,7 @@ export {
812
- __derivedAt,
813
- __derivedScalarAt,
814
- enableSignalDocument as __enableSignalDocument,
815
- + enableUniversalSignalDocument as __enableUniversalSignalDocument,
816
- __queryAt,
817
- __signalAt,
818
- __startSignalReads,
819
- diff --git a/dist/signals/local-hook.d.ts b/dist/signals/local-hook.d.ts
820
- new file mode 100644
821
- index 0000000..d6c1770
822
- --- /dev/null
823
- +++ b/dist/signals/local-hook.d.ts
824
- @@ -0,0 +1,16 @@
825
- +/**
826
- + * Renderer-provided slots for optional signal hooks.
827
- + *
828
- + * `useSignal$` allocates a component-local signal cell, but the cell itself
829
- + * lives in whichever renderer is currently rendering — DOM hook slots on the
830
- + * client/server, universal owner slots under `target: 'universal'` renderers.
831
- + * `octane/signals` cannot import either runtime (both import the signal
832
- + * engine), so each renderer registers a probe at module evaluation; the probe
833
- + * answers only while one of its own owners is executing, which also settles
834
- + * nesting (a universal boundary inside a DOM render probes last and wins).
835
- + */
836
- +export type LocalSignalHook = <T>(name: string, initialize: () => T, dispose: (value: T) => void, slot?: symbol | number) => T;
837
- +/** @internal Renderer runtimes register once, at module evaluation. */
838
- +export declare function registerLocalSignalHook(probe: () => LocalSignalHook | null): () => void;
839
- +/** @internal Dispatch to the innermost renderer that currently owns a render. */
840
- +export declare function localSignalHook<T>(name: string, initialize: () => T, dispose: (value: T) => void, slot?: symbol | number): T;
841
- diff --git a/dist/signals/local-hook.js b/dist/signals/local-hook.js
842
- new file mode 100644
843
- index 0000000..77c63f5
844
- --- /dev/null
845
- +++ b/dist/signals/local-hook.js
846
- @@ -0,0 +1,19 @@
847
- +const probes = [];
848
- +function registerLocalSignalHook(probe) {
849
- + probes.push(probe);
850
- + return () => {
851
- + const index = probes.indexOf(probe);
852
- + if (index !== -1) probes.splice(index, 1);
853
- + };
854
- +}
855
- +function localSignalHook(name, initialize, dispose, slot) {
856
- + for (let index = probes.length - 1; index >= 0; index--) {
857
- + const hook = probes[index]();
858
- + if (hook !== null) return hook(name, initialize, dispose, slot);
859
- + }
860
- + throw new Error(`${name} requires an active Octane component render.`);
861
- +}
862
- +export {
863
- + localSignalHook,
864
- + registerLocalSignalHook
865
- +};
866
- diff --git a/dist/signals/universal-owner.d.ts b/dist/signals/universal-owner.d.ts
867
- new file mode 100644
868
- index 0000000..0e57f3a
869
- --- /dev/null
870
- +++ b/dist/signals/universal-owner.d.ts
871
- @@ -0,0 +1,10 @@
872
- +import type { SignalOwner } from './types.js';
873
- +/**
874
- + * @internal A DOM runtime aliases the ambient owner so universal-boundary and
875
- + * DOM renders resolve the same document scope.
876
- + */
877
- +export declare function installUniversalSignalDocumentProvider(next: () => SignalOwner): void;
878
- +/** @internal Process-wide signal document for host-neutral renderers. */
879
- +export declare function universalSignalDocument(): SignalOwner;
880
- +/** @internal Compiler capability for ambient signal reads under universal renderers. */
881
- +export declare function enableUniversalSignalDocument(abi?: number): void;
882
- diff --git a/dist/signals/universal-owner.js b/dist/signals/universal-owner.js
883
- new file mode 100644
884
- index 0000000..ff5eb43
885
- --- /dev/null
886
- +++ b/dist/signals/universal-owner.js
887
- @@ -0,0 +1,20 @@
888
- +import { installDefaultSignalOwner } from "./owner-context.js";
889
- +let universalOwner;
890
- +let provider;
891
- +function installUniversalSignalDocumentProvider(next) {
892
- + provider = next;
893
- +}
894
- +function universalSignalDocument() {
895
- + return provider?.() ?? (universalOwner ??= Object.freeze({ scopeKey: "octane:universal" }));
896
- +}
897
- +function enableUniversalSignalDocument(abi = 1) {
898
- + if (abi !== 1) {
899
- + throw new TypeError("Unsupported universal signal owner ABI.");
900
- + }
901
- + installDefaultSignalOwner(universalSignalDocument);
902
- +}
903
- +export {
904
- + enableUniversalSignalDocument,
905
- + installUniversalSignalDocumentProvider,
906
- + universalSignalDocument
907
- +};
908
- diff --git a/dist/universal-core.js b/dist/universal-core.js
909
- index 4dbe2f9..8184bd9 100644
910
- --- a/dist/universal-core.js
911
- +++ b/dist/universal-core.js
912
- @@ -17,6 +17,14 @@ import {
913
- } from "./profiling.js";
914
- import { getRendererHostFlusher } from "./renderer-bridge.js";
915
- import { resolveLazyDefaultProps } from "./shared-value-helpers.js";
916
- +import { universalSignalDocument } from "./signals/universal-owner.js";
917
- +import { registerLocalSignalHook } from "./signals/local-hook.js";
918
- +import { retireSignalOwnerIdentity, runWithSignalOwner } from "./signals/owner-context.js";
919
- +import {
920
- + beginNativeWriteGuard,
921
- + endNativeWriteGuard,
922
- + setNativeReadObserver
923
- +} from "./signals/read-protocol.js";
924
- import { __methodDep } from "./method-dep.js";
925
- const UNIVERSAL_PLAN = /* @__PURE__ */ Symbol.for("octane.universal.plan");
926
- const UNIVERSAL_VALUE = /* @__PURE__ */ Symbol.for("octane.universal.value");
927
- @@ -842,6 +850,7 @@ function draftOwner(record, parent, replayPath) {
928
- boundaryThenable: record.boundaryThenable,
929
- isBoundary: record.isBoundary,
930
- canHandleSuspense: record.canHandleSuspense,
931
- + signalReads: null,
932
- visibility: parent?.visibility ?? record.visibility,
933
- contextStable: null
934
- };
935
- @@ -1012,6 +1021,7 @@ function executeOwner(owner, build, initialRenderCount = 0) {
936
- owner.contextStable = null;
937
- owner.needsRender = false;
938
- owner.implicitSlot = 0;
939
- + owner.signalReads = NO_SIGNAL_READS;
940
- const previousOwner = CURRENT_OWNER;
941
- const previousAttemptOwner = attempt.owner;
942
- CURRENT_OWNER = owner;
943
- @@ -1023,13 +1033,18 @@ function executeOwner(owner, build, initialRenderCount = 0) {
944
- const profileFrame = typeof __OCTANE_PROFILE_ENABLED__ !== "undefined" && __OCTANE_PROFILE_ENABLED__ && component !== null ? __profileBeginRender(owner.record, component, owner.record.mounted) : null;
945
- let didThrow = false;
946
- let thrown;
947
- + const signalOwner = universalSignalOwner(owner.record);
948
- + const previousReadObserver = setNativeReadObserver(observeUniversalSignalRead);
949
- + const writeGuard = beginNativeWriteGuard();
950
- try {
951
- - output = build();
952
- + output = runWithSignalOwner(signalOwner, build);
953
- } catch (error) {
954
- didThrow = true;
955
- - thrown = error;
956
- - throw error;
957
- + thrown = isThenable(error) ? new UniversalSuspense(error) : error;
958
- + throw thrown;
959
- } finally {
960
- + endNativeWriteGuard(writeGuard);
961
- + setNativeReadObserver(previousReadObserver);
962
- if (typeof __OCTANE_PROFILE_ENABLED__ !== "undefined" && __OCTANE_PROFILE_ENABLED__) {
963
- __profileEndRender(profileFrame, didThrow, thrown);
964
- }
965
- @@ -1196,6 +1211,8 @@ function disposeUncommittedDraft(owner) {
966
- owner.record.componentProps = null;
967
- owner.record.range = null;
968
- owner.record.updates.clear();
969
- + disposeUniversalSignalReads(owner.record);
970
- + disposeUniversalLocalHooks(owner.hooks);
971
- for (const hook of owner.hooks.values()) {
972
- if (hook.kind === "effect-event") hook.cell.active = false;
973
- }
974
- @@ -3142,6 +3159,85 @@ function scheduleOwner(owner, slot) {
975
- }
976
- owner.root.scheduleOwned(owner);
977
- }
978
- +const UNIVERSAL_SIGNAL_OWNERS = /* @__PURE__ */ new WeakMap();
979
- +function universalSignalOwner(record) {
980
- + let owner = UNIVERSAL_SIGNAL_OWNERS.get(record);
981
- + if (owner === void 0) {
982
- + const documentOwner = universalSignalDocument();
983
- + const identity = {
984
- + scopeKey: documentOwner.scopeKey,
985
- + documentOwner,
986
- + // The identity object itself is the opaque per-instance token — the
987
- + // same shape DOM scopes use, so identity maps never retain the record.
988
- + instanceOwner: null,
989
- + instanceKey: `u:${record.id}`
990
- + };
991
- + identity.instanceOwner = identity;
992
- + owner = Object.freeze(identity);
993
- + UNIVERSAL_SIGNAL_OWNERS.set(record, owner);
994
- + }
995
- + return owner;
996
- +}
997
- +const NO_SIGNAL_READS = /* @__PURE__ */ new Set();
998
- +function observeUniversalSignalRead(source) {
999
- + const owner = CURRENT_OWNER;
1000
- + if (owner === null) return;
1001
- + if (owner.signalReads === NO_SIGNAL_READS) owner.signalReads = /* @__PURE__ */ new Set();
1002
- + owner.signalReads.add(source);
1003
- +}
1004
- +function commitUniversalSignalReads(record, reads) {
1005
- + if (reads === null) return;
1006
- + let subscriptions = record.signalSubscriptions;
1007
- + if (subscriptions !== void 0) {
1008
- + for (const [source, unsubscribe] of subscriptions) {
1009
- + if (!reads.has(source)) {
1010
- + subscriptions.delete(source);
1011
- + unsubscribe();
1012
- + }
1013
- + }
1014
- + }
1015
- + for (const source of reads) {
1016
- + if (subscriptions?.has(source)) continue;
1017
- + if (subscriptions === void 0) {
1018
- + subscriptions = /* @__PURE__ */ new Map();
1019
- + record.signalSubscriptions = subscriptions;
1020
- + }
1021
- + subscriptions.set(
1022
- + source,
1023
- + source.subscribe(() => {
1024
- + if (!record.disposed) scheduleOwner(record);
1025
- + })
1026
- + );
1027
- + }
1028
- + if (subscriptions !== void 0 && subscriptions.size === 0) {
1029
- + record.signalSubscriptions = void 0;
1030
- + }
1031
- +}
1032
- +function disposeUniversalSignalReads(record) {
1033
- + const subscriptions = record.signalSubscriptions;
1034
- + if (subscriptions !== void 0) {
1035
- + record.signalSubscriptions = void 0;
1036
- + for (const unsubscribe of subscriptions.values()) unsubscribe();
1037
- + }
1038
- + const owner = UNIVERSAL_SIGNAL_OWNERS.get(record);
1039
- + if (owner !== void 0) retireSignalOwnerIdentity(owner);
1040
- +}
1041
- +function disposeUniversalLocalHooks(hooks) {
1042
- + for (const hook of hooks.values()) {
1043
- + if (hook.kind === "local") hook.dispose(hook.value);
1044
- + }
1045
- +}
1046
- +function universalLocalHook(_name, initialize, dispose, slot) {
1047
- + const owner = currentDraftOwner();
1048
- + const resolved = resolveHookSlot(slot);
1049
- + let cell = owner.hooks.get(resolved);
1050
- + if (cell === void 0) {
1051
- + cell = { kind: "local", value: initialize(), dispose };
1052
- + owner.hooks.set(resolved, cell);
1053
- + }
1054
- + return cell.value;
1055
- +}
1056
- +registerLocalSignalHook(() => CURRENT_OWNER === null ? null : universalLocalHook);
1057
- function currentDraftOwner() {
1058
- currentAttempt();
1059
- const owner = activateLazyLeafOwner();
1060
- @@ -5520,7 +5616,7 @@ class UniversalRootImpl {
1061
- }
1062
- let result;
1063
- try {
1064
- - result = event.handler(payload);
1065
- + result = runWithSignalOwner(universalSignalOwner(event.owner), () => event.handler(payload));
1066
- } catch (error) {
1067
- if (!routeUniversalOwnerError(event.owner, error)) throw error;
1068
- }
1069
- @@ -6096,6 +6192,8 @@ class UniversalRootImpl {
1070
- draft.record.componentProps = null;
1071
- draft.record.range = null;
1072
- draft.record.updates.clear();
1073
- + disposeUniversalSignalReads(draft.record);
1074
- + disposeUniversalLocalHooks(draft.hooks);
1075
- for (const hook of draft.hooks.values()) {
1076
- if (hook.kind === "effect-event") hook.cell.active = false;
1077
- }
1078
- @@ -6776,6 +6874,7 @@ class UniversalRootImpl {
1079
- owner.componentProps = draftOwner2.componentProps;
1080
- owner.componentRevision = draftOwner2.componentRevision;
1081
- owner.hooks = draftOwner2.hooks;
1082
- + commitUniversalSignalReads(owner, draftOwner2.signalReads);
1083
- for (const [slot, applied] of draftOwner2.appliedUpdates) {
1084
- const queue = owner.updates.get(slot);
1085
- if (queue !== applied.queue || applied.lane) continue;
1086
- @@ -6809,6 +6908,7 @@ class UniversalRootImpl {
1087
- record.componentRevision = draft.componentRevision;
1088
- record.parent = draft.parent?.record ?? null;
1089
- record.hooks = draft.hooks;
1090
- + commitUniversalSignalReads(record, draft.signalReads);
1091
- record.effectOrder = [...draft.seenEffects];
1092
- for (let index = 0; index < draft.seenEffects.length; index++) {
1093
- draft.seenEffects[index].previous = null;
1094
- @@ -8455,6 +8555,8 @@ class UniversalRootImpl {
1095
- owner.componentProps = null;
1096
- owner.range = null;
1097
- owner.updates.clear();
1098
- + disposeUniversalSignalReads(owner);
1099
- + disposeUniversalLocalHooks(owner.hooks);
1100
- }
1101
- for (const draft of draftOwnersParentFirst) {
1102
- const record = draft.record;
1103
- @@ -8464,6 +8566,7 @@ class UniversalRootImpl {
1104
- record.parent = draft.parent?.record ?? null;
1105
- }
1106
- record.hooks = draft.hooks;
1107
- + commitUniversalSignalReads(record, draft.signalReads);
1108
- record.effectOrder = [...draft.seenEffects];
1109
- for (let index = 0; index < draft.seenEffects.length; index++) {
1110
- draft.seenEffects[index].previous = null;
1111
- @@ -8985,6 +9088,8 @@ class UniversalRootImpl {
1112
- owner.componentProps = null;
1113
- owner.range = null;
1114
- owner.updates.clear();
1115
- + disposeUniversalSignalReads(owner);
1116
- + disposeUniversalLocalHooks(owner.hooks);
1117
- }
1118
- const deactivatedRegionCells = /* @__PURE__ */ new Set();
1119
- for (const bridge of regionBridges) {
1120
- diff --git a/dist/universal-native.js b/dist/universal-native.js
1121
- index 55ac9b6..3ff9a57 100644
1122
- --- a/dist/universal-native.js
1123
- +++ b/dist/universal-native.js
1124
- @@ -6,9 +6,11 @@ import {
1125
- import {
1126
- universalContext
1127
- } from "./universal-core.js";
1128
- +import { enableUniversalSignalDocument } from "./signals/universal-owner.js";
1129
- import { registerRendererContext, renderRendererContextProvider } from "./renderer-bridge.js";
1130
- import { CONTEXT_TAG } from "./runtime-tags.js";
1131
- import { registerContext } from "./context-identity.js";
1132
- +enableUniversalSignalDocument();
1133
- // @__NO_SIDE_EFFECTS__
1134
- function createContext(defaultValue) {
1135
- const context = ((props, scope) => scope === void 0 ? universalContext(context, props.value, props.children) : renderRendererContextProvider(context, props, scope));
1136
- diff --git a/dist/universal.js b/dist/universal.js
1137
- index 6427a01..8049b78 100644
1138
- --- a/dist/universal.js
1139
- +++ b/dist/universal.js
1140
- @@ -8,6 +8,9 @@ import {
1141
- createUniversalHostBoundary,
1142
- registerUniversalHostBridge
1143
- } from "./universal-dom-boundary.js";
1144
- +import { documentSignalOwner } from "./signals/document-owner.js";
1145
- +import { installUniversalSignalDocumentProvider } from "./signals/universal-owner.js";
1146
- +installUniversalSignalDocumentProvider(() => documentSignalOwner(document));
1147
- export {
1148
- createContext,
1149
- createSubSlot,