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.
- package/README.md +5 -0
- package/dist/behavior-root.d.ts +13 -3
- package/dist/behavior-root.js +28 -5
- package/dist/cjs/behavior-root.cjs +32 -6
- package/dist/cjs/class-names.cjs +49 -0
- package/dist/cjs/constants.cjs +9 -0
- package/dist/cjs/css.cjs +6 -27
- package/dist/cjs/data-encoding.cjs +160 -0
- package/dist/cjs/dom-binding-handoff.cjs +93 -0
- package/dist/cjs/dom-binding-protocol.cjs +115 -0
- package/dist/cjs/dom-binding-styles.cjs +292 -0
- package/dist/cjs/dom-bindings.cjs +700 -0
- package/dist/cjs/dom-focused-move.cjs +66 -0
- package/dist/cjs/dom-tables.cjs +4 -94
- package/dist/cjs/error-codes.client.generated.cjs +33 -0
- package/dist/cjs/error-codes.server.generated.cjs +19 -0
- package/dist/cjs/hydration/control-capture.cjs +244 -0
- package/dist/cjs/hydration/event-capture.cjs +125 -43
- package/dist/cjs/hydration/interaction-config.cjs +50 -2
- package/dist/cjs/hydration-markers.cjs +37 -0
- package/dist/cjs/independent-hydration-protocol.cjs +106 -0
- package/dist/cjs/index.cjs +6 -0
- package/dist/cjs/runtime.cjs +2791 -215
- package/dist/cjs/runtime.server.cjs +716 -76
- package/dist/cjs/server/early-signals.cjs +45 -0
- package/dist/cjs/server/index.cjs +44 -0
- package/dist/cjs/server/rpc-batch.cjs +149 -0
- package/dist/cjs/server/rpc-stream.cjs +146 -0
- package/dist/cjs/server/rpc.cjs +34 -15
- package/dist/cjs/server/signal-query-observation.cjs +158 -0
- package/dist/cjs/server/streamed-region.cjs +52 -0
- package/dist/cjs/server/streamed-signals.cjs +512 -0
- package/dist/cjs/server-call.cjs +103 -0
- package/dist/cjs/server-rpc-batch-client.cjs +141 -0
- package/dist/cjs/server-rpc-client.cjs +94 -27
- package/dist/cjs/server-rpc-protocol.cjs +141 -0
- package/dist/cjs/server-rpc-stream-client.cjs +118 -0
- package/dist/cjs/signals/actions.cjs +474 -0
- package/dist/cjs/signals/client.cjs +4 -1
- package/dist/cjs/signals/computations.cjs +460 -0
- package/dist/cjs/signals/control-binding.cjs +368 -0
- package/dist/cjs/signals/derived-facade.cjs +50 -0
- package/dist/cjs/signals/document-owner.cjs +71 -0
- package/dist/cjs/signals/early-values.cjs +155 -0
- package/dist/cjs/signals/encoding.cjs +6 -95
- package/dist/cjs/signals/engine.cjs +276 -12
- package/dist/cjs/signals/errors.cjs +18 -0
- package/dist/cjs/signals/facade.cjs +477 -0
- package/dist/cjs/signals/graph.cjs +163 -20
- package/dist/cjs/signals/handle-protocol.cjs +36 -0
- package/dist/cjs/signals/index.cjs +81 -2
- package/dist/cjs/signals/native-read-client.cjs +10 -0
- package/dist/cjs/signals/owner-context.cjs +112 -0
- package/dist/cjs/signals/query-attempt-observer.cjs +68 -0
- package/dist/cjs/signals/query-facade.cjs +72 -0
- package/dist/cjs/signals/read-protocol.cjs +32 -0
- package/dist/cjs/signals/requests.cjs +287 -14
- package/dist/cjs/signals/scalar-computations.cjs +76 -0
- package/dist/cjs/signals/server.cjs +4 -1
- package/dist/cjs/signals/transition-candidate.cjs +567 -0
- package/dist/cjs/signals/transition-state.cjs +106 -0
- package/dist/cjs/signals/types.cjs +50 -0
- package/dist/cjs/stream-protocol.cjs +3 -0
- package/dist/cjs/streamed-signals-protocol.cjs +159 -0
- package/dist/cjs/style-values.cjs +122 -0
- package/dist/cjs/version.cjs +1 -1
- package/dist/class-names.d.ts +5 -0
- package/dist/class-names.js +25 -0
- package/dist/compiler/bundler.js +34 -6
- package/dist/compiler/compile.js +2234 -559
- package/dist/compiler/dom-binding-program.js +935 -0
- package/dist/compiler/dom-binding-request.js +57 -0
- package/dist/compiler/dom-bindings.js +2245 -0
- package/dist/compiler/hook-deps.js +26 -0
- package/dist/compiler/hydrate-boundaries.js +358 -15
- package/dist/compiler/index.d.ts +38 -1
- package/dist/compiler/index.js +1 -0
- package/dist/compiler/native-attribute-reads.js +127 -0
- package/dist/compiler/native-read-diagnostics.js +48 -9
- package/dist/compiler/native-read-types.js +55 -32
- package/dist/compiler/server-context.js +118 -0
- package/dist/compiler/signal-attempt-reads.js +479 -0
- package/dist/compiler/signal-declarations.js +557 -0
- package/dist/compiler/signal-start-reads.js +413 -0
- package/dist/compiler/slot-hooks.js +57 -10
- package/dist/compiler/template-ir.js +200 -0
- package/dist/compiler/typescript.d.ts +2 -0
- package/dist/compiler/typescript.js +2 -0
- package/dist/compiler/vite.d.ts +3 -1
- package/dist/compiler/vite.js +122 -4
- package/dist/compiler/volar.d.ts +6 -1
- package/dist/compiler/volar.js +674 -143
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +10 -0
- package/dist/css.d.ts +2 -5
- package/dist/css.js +2 -23
- package/dist/data-encoding.d.ts +9 -0
- package/dist/data-encoding.js +134 -0
- package/dist/dom-binding-classes.d.ts +15 -0
- package/dist/dom-binding-classes.js +129 -0
- package/dist/dom-binding-controls.d.ts +2 -0
- package/dist/dom-binding-controls.js +6 -0
- package/dist/dom-binding-handoff.d.ts +55 -0
- package/dist/dom-binding-handoff.js +62 -0
- package/dist/dom-binding-program.d.ts +300 -0
- package/dist/dom-binding-program.js +1625 -0
- package/dist/dom-binding-projections.d.ts +15 -0
- package/dist/dom-binding-projections.js +187 -0
- package/dist/dom-binding-protocol.d.ts +13 -0
- package/dist/dom-binding-protocol.js +88 -0
- package/dist/dom-binding-signals.d.ts +21 -0
- package/dist/dom-binding-signals.js +109 -0
- package/dist/dom-binding-styles.d.ts +17 -0
- package/dist/dom-binding-styles.js +272 -0
- package/dist/dom-bindings.d.ts +89 -0
- package/dist/dom-bindings.js +670 -0
- package/dist/dom-focused-move.d.ts +6 -0
- package/dist/dom-focused-move.js +42 -0
- package/dist/dom-tables.d.ts +1 -3
- package/dist/dom-tables.js +1 -91
- package/dist/error-codes.client.generated.d.ts +9 -0
- package/dist/error-codes.client.generated.js +33 -0
- package/dist/error-codes.server.generated.d.ts +5 -0
- package/dist/error-codes.server.generated.js +19 -0
- package/dist/hydration/control-capture.d.ts +62 -0
- package/dist/hydration/control-capture.js +223 -0
- package/dist/hydration/document-lifecycle.d.ts +23 -0
- package/dist/hydration/document-lifecycle.js +80 -0
- package/dist/hydration/event-capture.d.ts +20 -1
- package/dist/hydration/event-capture.js +128 -42
- package/dist/hydration/independent-island.d.ts +45 -0
- package/dist/hydration/independent-island.js +233 -0
- package/dist/hydration/index.d.ts +8 -1
- package/dist/hydration/index.js +55 -1
- package/dist/hydration/interaction-config.d.ts +5 -0
- package/dist/hydration/interaction-config.js +44 -1
- package/dist/hydration/stream-delivery.d.ts +32 -0
- package/dist/hydration/stream-delivery.js +333 -0
- package/dist/hydration/stream-receiver.d.ts +26 -0
- package/dist/hydration/stream-receiver.js +204 -0
- package/dist/hydration/stream-result-receiver.d.ts +70 -0
- package/dist/hydration/stream-result-receiver.js +246 -0
- package/dist/hydration/streamed-signals.d.ts +44 -0
- package/dist/hydration/streamed-signals.js +186 -0
- package/dist/hydration/types.d.ts +6 -0
- package/dist/hydration-markers.d.ts +7 -0
- package/dist/hydration-markers.js +10 -0
- package/dist/independent-hydration-protocol.d.ts +31 -0
- package/dist/independent-hydration-protocol.js +80 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -0
- package/dist/internal/signal-read.d.ts +1 -0
- package/dist/internal/signal-read.js +4 -0
- package/dist/jsx-runtime.d.ts +45 -6
- package/dist/public-types.d.ts +15 -1
- package/dist/runtime.d.ts +259 -21
- package/dist/runtime.js +2812 -220
- package/dist/runtime.server.d.ts +86 -6
- package/dist/runtime.server.js +712 -76
- package/dist/server/early-signals.d.ts +14 -0
- package/dist/server/early-signals.js +34 -0
- package/dist/server/index.d.ts +10 -2
- package/dist/server/index.js +48 -1
- package/dist/server/rpc-batch.d.ts +17 -0
- package/dist/server/rpc-batch.js +129 -0
- package/dist/server/rpc-stream.d.ts +9 -0
- package/dist/server/rpc-stream.js +125 -0
- package/dist/server/rpc.d.ts +5 -1
- package/dist/server/rpc.js +37 -13
- package/dist/server/signal-query-observation.d.ts +3 -0
- package/dist/server/signal-query-observation.js +134 -0
- package/dist/server/streamed-region.d.ts +15 -0
- package/dist/server/streamed-region.js +30 -0
- package/dist/server/streamed-signals.d.ts +45 -0
- package/dist/server/streamed-signals.js +488 -0
- package/dist/server-call.d.ts +41 -0
- package/dist/server-call.js +75 -0
- package/dist/server-rpc-batch-client.d.ts +7 -0
- package/dist/server-rpc-batch-client.js +119 -0
- package/dist/server-rpc-client.d.ts +3 -1
- package/dist/server-rpc-client.js +99 -27
- package/dist/server-rpc-protocol.d.ts +47 -0
- package/dist/server-rpc-protocol.js +109 -0
- package/dist/server-rpc-stream-client.d.ts +5 -0
- package/dist/server-rpc-stream-client.js +98 -0
- package/dist/signals/actions.d.ts +12 -0
- package/dist/signals/actions.js +466 -0
- package/dist/signals/client.d.ts +2 -0
- package/dist/signals/client.js +1 -0
- package/dist/signals/computations.d.ts +37 -0
- package/dist/signals/computations.js +455 -0
- package/dist/signals/control-binding.d.ts +31 -0
- package/dist/signals/control-binding.js +353 -0
- package/dist/signals/derived-facade.d.ts +3 -0
- package/dist/signals/derived-facade.js +25 -0
- package/dist/signals/document-owner.d.ts +10 -0
- package/dist/signals/document-owner.js +43 -0
- package/dist/signals/early-values.d.ts +24 -0
- package/dist/signals/early-values.js +124 -0
- package/dist/signals/encoding.d.ts +1 -3
- package/dist/signals/encoding.js +3 -93
- package/dist/signals/engine.d.ts +53 -4
- package/dist/signals/engine.js +275 -16
- package/dist/signals/errors.d.ts +7 -0
- package/dist/signals/errors.js +16 -0
- package/dist/signals/facade.d.ts +74 -0
- package/dist/signals/facade.js +452 -0
- package/dist/signals/graph.d.ts +50 -5
- package/dist/signals/graph.js +170 -19
- package/dist/signals/handle-protocol.d.ts +4 -0
- package/dist/signals/handle-protocol.js +11 -0
- package/dist/signals/index.d.ts +12 -3
- package/dist/signals/index.js +71 -2
- package/dist/signals/native-read-client.d.ts +3 -0
- package/dist/signals/native-read-client.js +10 -0
- package/dist/signals/owner-context.d.ts +22 -0
- package/dist/signals/owner-context.js +77 -0
- package/dist/signals/query-attempt-observer.d.ts +49 -0
- package/dist/signals/query-attempt-observer.js +41 -0
- package/dist/signals/query-facade.d.ts +3 -0
- package/dist/signals/query-facade.js +49 -0
- package/dist/signals/read-protocol.d.ts +32 -3
- package/dist/signals/read-protocol.js +26 -0
- package/dist/signals/requests.d.ts +38 -5
- package/dist/signals/requests.js +298 -15
- package/dist/signals/scalar-computations.d.ts +2 -0
- package/dist/signals/scalar-computations.js +60 -0
- package/dist/signals/server.d.ts +2 -0
- package/dist/signals/server.js +1 -0
- package/dist/signals/transition-candidate.d.ts +71 -0
- package/dist/signals/transition-candidate.js +557 -0
- package/dist/signals/transition-state.d.ts +51 -0
- package/dist/signals/transition-state.js +70 -0
- package/dist/signals/types.d.ts +95 -5
- package/dist/signals/types.js +20 -0
- package/dist/stream-protocol.d.ts +0 -5
- package/dist/stream-protocol.js +3 -0
- package/dist/streamed-signals-protocol.d.ts +60 -0
- package/dist/streamed-signals-protocol.js +130 -0
- package/dist/style-values.d.ts +3 -0
- package/dist/style-values.js +96 -0
- package/dist/version.js +1 -1
- package/package.json +37 -1
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
import {
|
|
2
|
+
adoptResourceValue,
|
|
3
|
+
createDeclaredSignalCell,
|
|
4
|
+
getResourceSelectionAuthority,
|
|
5
|
+
getSignalScope
|
|
6
|
+
} from "./engine.js";
|
|
7
|
+
import { createDeclaredDerivedCell } from "./computations.js";
|
|
8
|
+
import { resolveCurrentSignalHandle, resolveSignalHandleForOwner } from "./facade.js";
|
|
9
|
+
import {
|
|
10
|
+
ScopedNode,
|
|
11
|
+
assertWritable,
|
|
12
|
+
isThenable,
|
|
13
|
+
pure,
|
|
14
|
+
signalBatch,
|
|
15
|
+
subscribeNode,
|
|
16
|
+
untrack
|
|
17
|
+
} from "./graph.js";
|
|
18
|
+
import { captureSignalOwner, currentSignalOwner, runWithSignalOwner } from "./owner-context.js";
|
|
19
|
+
import { forwardNativeTransitionConsumer } from "./read-protocol.js";
|
|
20
|
+
import {
|
|
21
|
+
SIGNAL_HANDLE,
|
|
22
|
+
SIGNAL_BINDING_READ,
|
|
23
|
+
SIGNAL_BINDING_SUBSCRIBE,
|
|
24
|
+
SIGNAL_BINDING_IDENTITY,
|
|
25
|
+
SIGNAL_OWNER_RESOLVE
|
|
26
|
+
} from "./types.js";
|
|
27
|
+
const uncertainReceipts = /* @__PURE__ */ new WeakSet();
|
|
28
|
+
const noAuthority = /* @__PURE__ */ Symbol();
|
|
29
|
+
let activeOperation;
|
|
30
|
+
let excludedOperation;
|
|
31
|
+
const managers = /* @__PURE__ */ new WeakMap();
|
|
32
|
+
class OptimisticManager {
|
|
33
|
+
constructor(source) {
|
|
34
|
+
this.source = source;
|
|
35
|
+
const owner = getSignalScope(source);
|
|
36
|
+
if (!owner) throw new TypeError("An optimistic source needs a live Octane scope.");
|
|
37
|
+
this.owner = owner;
|
|
38
|
+
this.version$ = createDeclaredSignalCell(
|
|
39
|
+
this.owner,
|
|
40
|
+
`@octane/optimistic-version/${source.key}`,
|
|
41
|
+
0
|
|
42
|
+
);
|
|
43
|
+
this.view$ = createDeclaredDerivedCell(this.owner, `@octane/optimistic/${source.key}`, () => {
|
|
44
|
+
this.version$.get();
|
|
45
|
+
return this.read();
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
source;
|
|
49
|
+
compareAuthority;
|
|
50
|
+
owner;
|
|
51
|
+
version$;
|
|
52
|
+
view$;
|
|
53
|
+
overlays = [];
|
|
54
|
+
read(exclude) {
|
|
55
|
+
const snapshot = this.source.snapshot();
|
|
56
|
+
const selectionAuthority = getResourceSelectionAuthority(this.source);
|
|
57
|
+
for (let index = this.overlays.length - 1; index >= 0; index--) {
|
|
58
|
+
const overlay = this.overlays[index];
|
|
59
|
+
if (overlay.operation !== exclude && overlay.requestKey === snapshot.requestKey && overlay.selectionAuthority === selectionAuthority) {
|
|
60
|
+
return overlay.value;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return this.source.get();
|
|
64
|
+
}
|
|
65
|
+
latest(fallback, exclude) {
|
|
66
|
+
const snapshot = this.source.snapshot();
|
|
67
|
+
const selectionAuthority = getResourceSelectionAuthority(this.source);
|
|
68
|
+
for (let index = this.overlays.length - 1; index >= 0; index--) {
|
|
69
|
+
const overlay = this.overlays[index];
|
|
70
|
+
if (overlay.operation !== exclude && overlay.requestKey === snapshot.requestKey && overlay.selectionAuthority === selectionAuthority) {
|
|
71
|
+
return overlay.value;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return this.source.latest(fallback);
|
|
75
|
+
}
|
|
76
|
+
snapshot(exclude) {
|
|
77
|
+
const snapshot = this.source.snapshot();
|
|
78
|
+
const selectionAuthority = getResourceSelectionAuthority(this.source);
|
|
79
|
+
for (let index = this.overlays.length - 1; index >= 0; index--) {
|
|
80
|
+
const overlay = this.overlays[index];
|
|
81
|
+
if (overlay.operation !== exclude && overlay.requestKey === snapshot.requestKey && overlay.selectionAuthority === selectionAuthority) {
|
|
82
|
+
return Object.freeze({
|
|
83
|
+
status: "ready",
|
|
84
|
+
value: overlay.value,
|
|
85
|
+
refreshing: snapshot.refreshing,
|
|
86
|
+
connection: snapshot.connection,
|
|
87
|
+
complete: snapshot.complete,
|
|
88
|
+
...snapshot.requestKey === void 0 ? {} : { requestKey: snapshot.requestKey }
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return snapshot;
|
|
93
|
+
}
|
|
94
|
+
apply(operation, value) {
|
|
95
|
+
assertWritable();
|
|
96
|
+
if (operation.status !== "pending") {
|
|
97
|
+
throw new Error(`Action operation "${operation.id}" is no longer writable.`);
|
|
98
|
+
}
|
|
99
|
+
let overlay = operation.targets.get(this);
|
|
100
|
+
const snapshot = this.source.snapshot();
|
|
101
|
+
if (!overlay && snapshot.status !== "ready") {
|
|
102
|
+
throw new Error("An optimistic write requires ready source authority.");
|
|
103
|
+
}
|
|
104
|
+
const previous = this.read();
|
|
105
|
+
const next = typeof value === "function" ? untrack(() => pure(() => value(previous))) : value;
|
|
106
|
+
if (!overlay) {
|
|
107
|
+
overlay = {
|
|
108
|
+
operation,
|
|
109
|
+
requestKey: snapshot.requestKey,
|
|
110
|
+
selectionAuthority: getResourceSelectionAuthority(this.source),
|
|
111
|
+
value: next
|
|
112
|
+
};
|
|
113
|
+
this.overlays.push(overlay);
|
|
114
|
+
operation.targets.set(this, overlay);
|
|
115
|
+
} else {
|
|
116
|
+
overlay.value = next;
|
|
117
|
+
}
|
|
118
|
+
this.publish();
|
|
119
|
+
return overlay;
|
|
120
|
+
}
|
|
121
|
+
remove(operation) {
|
|
122
|
+
const index = this.overlays.findIndex((overlay) => overlay.operation === operation);
|
|
123
|
+
if (index < 0) return;
|
|
124
|
+
this.overlays.splice(index, 1);
|
|
125
|
+
if (!this.owner.retired) this.publish();
|
|
126
|
+
}
|
|
127
|
+
adopt(overlay, value) {
|
|
128
|
+
assertWritable();
|
|
129
|
+
const snapshot = this.source.snapshot();
|
|
130
|
+
if (snapshot.requestKey !== overlay.requestKey || getResourceSelectionAuthority(this.source) !== overlay.selectionAuthority) {
|
|
131
|
+
throw new Error("An action cannot adopt authority for a different query selection.");
|
|
132
|
+
}
|
|
133
|
+
if (this.source.kind !== "async" && this.source.kind !== "signal") {
|
|
134
|
+
throw new TypeError("Only a writable or query source can adopt an authoritative value.");
|
|
135
|
+
}
|
|
136
|
+
if (this.compareAuthority) {
|
|
137
|
+
const current = this.source.latest(noAuthority);
|
|
138
|
+
if (current === noAuthority) {
|
|
139
|
+
throw new Error("An action needs current authority to compare receipt revisions.");
|
|
140
|
+
}
|
|
141
|
+
const order = untrack(() => pure(() => this.compareAuthority(value, current)));
|
|
142
|
+
if (!Number.isFinite(order)) {
|
|
143
|
+
throw new TypeError("An authority revision comparator must return a finite number.");
|
|
144
|
+
}
|
|
145
|
+
if (order <= 0) {
|
|
146
|
+
this.remove(overlay.operation);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (this.source.kind === "async") {
|
|
151
|
+
if (!adoptResourceValue(this.source, overlay.requestKey, value)) {
|
|
152
|
+
throw new Error("The pinned query selection is no longer current.");
|
|
153
|
+
}
|
|
154
|
+
} else {
|
|
155
|
+
this.source.set(value);
|
|
156
|
+
}
|
|
157
|
+
this.remove(overlay.operation);
|
|
158
|
+
}
|
|
159
|
+
publish() {
|
|
160
|
+
this.version$.set((version) => version + 1);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
function managerFor(source$, owner, compareAuthority) {
|
|
164
|
+
const resolved = owner ? resolveSignalHandleForOwner(source$, owner) : resolveCurrentSignalHandle(source$);
|
|
165
|
+
if (!(resolved instanceof ScopedNode)) {
|
|
166
|
+
throw new TypeError("optimistic$ requires an Octane signal source.");
|
|
167
|
+
}
|
|
168
|
+
let manager = managers.get(resolved);
|
|
169
|
+
if (!manager) {
|
|
170
|
+
manager = new OptimisticManager(resolved);
|
|
171
|
+
managers.set(resolved, manager);
|
|
172
|
+
}
|
|
173
|
+
if (compareAuthority && manager.compareAuthority !== compareAuthority) {
|
|
174
|
+
if (manager.compareAuthority) {
|
|
175
|
+
throw new Error("An optimistic source cannot use conflicting authority revision policies.");
|
|
176
|
+
}
|
|
177
|
+
manager.compareAuthority = compareAuthority;
|
|
178
|
+
}
|
|
179
|
+
return manager;
|
|
180
|
+
}
|
|
181
|
+
class OptimisticDescriptor {
|
|
182
|
+
constructor(source$, compareAuthority) {
|
|
183
|
+
this.source$ = source$;
|
|
184
|
+
this.compareAuthority = compareAuthority;
|
|
185
|
+
this.key = `optimistic:${source$.key}`;
|
|
186
|
+
}
|
|
187
|
+
source$;
|
|
188
|
+
compareAuthority;
|
|
189
|
+
[SIGNAL_HANDLE] = true;
|
|
190
|
+
kind = "signal";
|
|
191
|
+
key;
|
|
192
|
+
[SIGNAL_OWNER_RESOLVE](owner) {
|
|
193
|
+
return this.manager(owner).view$;
|
|
194
|
+
}
|
|
195
|
+
manager(owner) {
|
|
196
|
+
return managerFor(this.source$, owner, this.compareAuthority);
|
|
197
|
+
}
|
|
198
|
+
get() {
|
|
199
|
+
const manager = this.manager(activeOperation?.owner ?? void 0);
|
|
200
|
+
return excludedOperation ? manager.read(excludedOperation) : manager.view$.get();
|
|
201
|
+
}
|
|
202
|
+
[SIGNAL_BINDING_READ]() {
|
|
203
|
+
return this.manager().view$[SIGNAL_BINDING_READ]();
|
|
204
|
+
}
|
|
205
|
+
[SIGNAL_BINDING_SUBSCRIBE](notify, onRetire) {
|
|
206
|
+
const owner = currentSignalOwner();
|
|
207
|
+
if (!owner) throw new Error("An optimistic subscription needs an active signal owner.");
|
|
208
|
+
const run = captureSignalOwner(owner);
|
|
209
|
+
return this.manager().view$[SIGNAL_BINDING_SUBSCRIBE](
|
|
210
|
+
forwardNativeTransitionConsumer(notify, () => run(notify)),
|
|
211
|
+
onRetire === void 0 ? void 0 : () => run(onRetire)
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
[SIGNAL_BINDING_IDENTITY]() {
|
|
215
|
+
return this.source$[SIGNAL_BINDING_IDENTITY]();
|
|
216
|
+
}
|
|
217
|
+
latest(fallback) {
|
|
218
|
+
return this.manager().latest(fallback, excludedOperation);
|
|
219
|
+
}
|
|
220
|
+
snapshot() {
|
|
221
|
+
const manager = this.manager();
|
|
222
|
+
return excludedOperation ? manager.snapshot(excludedOperation) : manager.view$.snapshot();
|
|
223
|
+
}
|
|
224
|
+
subscribe(notify) {
|
|
225
|
+
const owner = currentSignalOwner();
|
|
226
|
+
if (!owner) throw new Error("An optimistic subscription needs an active signal owner.");
|
|
227
|
+
const run = captureSignalOwner(owner);
|
|
228
|
+
return this.manager().view$.subscribe(
|
|
229
|
+
forwardNativeTransitionConsumer(notify, () => run(notify))
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
set(value) {
|
|
233
|
+
if (!activeOperation) {
|
|
234
|
+
throw new Error("An optimistic write must belong to action$ or use operation.set().");
|
|
235
|
+
}
|
|
236
|
+
this.apply(activeOperation, value);
|
|
237
|
+
}
|
|
238
|
+
apply(operation, value) {
|
|
239
|
+
const manager = this.manager(operation.owner ?? void 0);
|
|
240
|
+
operation.bind(this, manager);
|
|
241
|
+
manager.apply(operation, value);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
class ActionUncertainError extends Error {
|
|
245
|
+
constructor(operationId2, options) {
|
|
246
|
+
super(`Action operation "${operationId2}" may have been accepted.`, options);
|
|
247
|
+
this.operationId = operationId2;
|
|
248
|
+
this.name = "ActionUncertainError";
|
|
249
|
+
}
|
|
250
|
+
operationId;
|
|
251
|
+
code = "OCTANE_ACTION_UNCERTAIN";
|
|
252
|
+
}
|
|
253
|
+
function operationId(key) {
|
|
254
|
+
const randomUUID = globalThis.crypto?.randomUUID;
|
|
255
|
+
if (typeof randomUUID !== "function") {
|
|
256
|
+
throw new Error("action$ requires crypto.randomUUID() for operation identity.");
|
|
257
|
+
}
|
|
258
|
+
return `${key}:${randomUUID.call(globalThis.crypto)}`;
|
|
259
|
+
}
|
|
260
|
+
function transportIsUncertain(error) {
|
|
261
|
+
return (typeof error === "object" || typeof error === "function") && error !== null && error.code === "OCTANE_RPC_UNCERTAIN";
|
|
262
|
+
}
|
|
263
|
+
class Operation {
|
|
264
|
+
constructor(key) {
|
|
265
|
+
this.key = key;
|
|
266
|
+
this.id = operationId(key);
|
|
267
|
+
}
|
|
268
|
+
key;
|
|
269
|
+
id;
|
|
270
|
+
owner = currentSignalOwner();
|
|
271
|
+
status = "pending";
|
|
272
|
+
targets = /* @__PURE__ */ new Map();
|
|
273
|
+
waits;
|
|
274
|
+
descriptors = /* @__PURE__ */ new Map();
|
|
275
|
+
set(signal$, value) {
|
|
276
|
+
if (!(signal$ instanceof OptimisticDescriptor)) {
|
|
277
|
+
throw new TypeError("operation.set() requires a signal from optimistic$().");
|
|
278
|
+
}
|
|
279
|
+
const manager = this.descriptors.get(signal$);
|
|
280
|
+
if (manager) {
|
|
281
|
+
manager.apply(this, value);
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
signal$.apply(this, value);
|
|
285
|
+
}
|
|
286
|
+
bind(descriptor, manager) {
|
|
287
|
+
this.descriptors.set(
|
|
288
|
+
descriptor,
|
|
289
|
+
manager
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
adopt(value) {
|
|
293
|
+
if (this.status !== "pending" && this.status !== "uncertain")
|
|
294
|
+
throw new Error(`Action operation "${this.id}" is settled.`);
|
|
295
|
+
if (this.targets.size !== 1) {
|
|
296
|
+
throw new Error("operation.adopt() requires exactly one optimistic source.");
|
|
297
|
+
}
|
|
298
|
+
const [manager, overlay] = this.targets.entries().next().value;
|
|
299
|
+
manager.adopt(overlay, value);
|
|
300
|
+
this.targets.delete(manager);
|
|
301
|
+
this.descriptors.clear();
|
|
302
|
+
this.status = "confirmed";
|
|
303
|
+
this.notifyWaits();
|
|
304
|
+
}
|
|
305
|
+
uncertain() {
|
|
306
|
+
if (this.status !== "pending") throw new Error(`Action operation "${this.id}" is settled.`);
|
|
307
|
+
this.status = "uncertain";
|
|
308
|
+
this.notifyWaits();
|
|
309
|
+
const receipt = Object.freeze({ status: "uncertain", operationId: this.id });
|
|
310
|
+
uncertainReceipts.add(receipt);
|
|
311
|
+
return receipt;
|
|
312
|
+
}
|
|
313
|
+
until(read, options) {
|
|
314
|
+
if (this.status !== "pending") return Promise.reject(new Error("The action is settled."));
|
|
315
|
+
if (typeof read !== "function")
|
|
316
|
+
return Promise.reject(new TypeError("until() requires a read."));
|
|
317
|
+
const timeout = options?.timeout;
|
|
318
|
+
if (timeout !== void 0 && (!Number.isFinite(timeout) || timeout < 0)) {
|
|
319
|
+
return Promise.reject(new RangeError("until() timeout must be a nonnegative number."));
|
|
320
|
+
}
|
|
321
|
+
const managers2 = [...this.targets.keys()];
|
|
322
|
+
if (!managers2.length) {
|
|
323
|
+
return Promise.reject(new Error("until() requires a pinned optimistic source."));
|
|
324
|
+
}
|
|
325
|
+
return new Promise((resolve, reject) => {
|
|
326
|
+
let ended = false;
|
|
327
|
+
let timer;
|
|
328
|
+
const stops = [];
|
|
329
|
+
const finish = (error) => {
|
|
330
|
+
if (ended) return;
|
|
331
|
+
ended = true;
|
|
332
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
333
|
+
for (const stop of stops) stop();
|
|
334
|
+
this.waits?.delete(check);
|
|
335
|
+
if (error === void 0) resolve();
|
|
336
|
+
else reject(error);
|
|
337
|
+
};
|
|
338
|
+
const check = () => {
|
|
339
|
+
if (ended) return;
|
|
340
|
+
if (this.status !== "pending") {
|
|
341
|
+
finish(
|
|
342
|
+
this.status === "confirmed" ? void 0 : new Error(`The action is ${this.status}.`)
|
|
343
|
+
);
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
if (managers2.some((manager) => manager.owner.retired)) {
|
|
347
|
+
finish(new Error("The optimistic owner was retired."));
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
const previous = excludedOperation;
|
|
351
|
+
excludedOperation = this;
|
|
352
|
+
try {
|
|
353
|
+
for (const [manager, overlay] of this.targets) {
|
|
354
|
+
if (manager.source.snapshot().requestKey !== overlay.requestKey || getResourceSelectionAuthority(manager.source) !== overlay.selectionAuthority) {
|
|
355
|
+
finish(new Error("The pinned optimistic selection is no longer current."));
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
if (runWithSignalOwner(managers2[0].owner, read)) finish();
|
|
360
|
+
} catch (error) {
|
|
361
|
+
if (!isThenable(error)) finish(error);
|
|
362
|
+
} finally {
|
|
363
|
+
excludedOperation = previous;
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
(this.waits ??= /* @__PURE__ */ new Set()).add(check);
|
|
367
|
+
for (const manager of managers2) stops.push(subscribeNode(manager.source, check));
|
|
368
|
+
if (timeout !== void 0) {
|
|
369
|
+
timer = setTimeout(
|
|
370
|
+
() => finish(new Error("The optimistic confirmation timed out.")),
|
|
371
|
+
timeout
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
check();
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
confirm() {
|
|
378
|
+
if (this.status !== "pending") return;
|
|
379
|
+
this.status = "confirmed";
|
|
380
|
+
this.clear();
|
|
381
|
+
this.notifyWaits();
|
|
382
|
+
}
|
|
383
|
+
reject() {
|
|
384
|
+
if (this.status !== "pending" && this.status !== "uncertain") return;
|
|
385
|
+
assertWritable();
|
|
386
|
+
this.status = "rejected";
|
|
387
|
+
this.clear();
|
|
388
|
+
this.notifyWaits();
|
|
389
|
+
}
|
|
390
|
+
notifyWaits() {
|
|
391
|
+
if (this.waits) for (const check of this.waits) check();
|
|
392
|
+
}
|
|
393
|
+
clear() {
|
|
394
|
+
for (const manager of this.targets.keys()) manager.remove(this);
|
|
395
|
+
this.targets.clear();
|
|
396
|
+
this.descriptors.clear();
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
function optimistic$(source$, options) {
|
|
400
|
+
if (!source$ || typeof source$.get !== "function") {
|
|
401
|
+
throw new TypeError("optimistic$ requires a signal source.");
|
|
402
|
+
}
|
|
403
|
+
if (options?.compareAuthority !== void 0 && typeof options.compareAuthority !== "function") {
|
|
404
|
+
throw new TypeError("An authority revision policy must be a comparator function.");
|
|
405
|
+
}
|
|
406
|
+
return new OptimisticDescriptor(source$, options?.compareAuthority);
|
|
407
|
+
}
|
|
408
|
+
function action$(keyOrHandler, handler) {
|
|
409
|
+
const key = typeof keyOrHandler === "string" ? keyOrHandler : "action";
|
|
410
|
+
const execute = typeof keyOrHandler === "function" ? keyOrHandler : handler;
|
|
411
|
+
if (!key.trim() || typeof execute !== "function") {
|
|
412
|
+
throw new TypeError("action$ requires a handler and an optional nonempty key.");
|
|
413
|
+
}
|
|
414
|
+
return function(...args) {
|
|
415
|
+
const operation = new Operation(key);
|
|
416
|
+
const previous = activeOperation;
|
|
417
|
+
activeOperation = operation;
|
|
418
|
+
let result;
|
|
419
|
+
try {
|
|
420
|
+
result = signalBatch(() => execute.call(this, operation, ...args));
|
|
421
|
+
} catch (error) {
|
|
422
|
+
activeOperation = previous;
|
|
423
|
+
if (transportIsUncertain(error)) {
|
|
424
|
+
operation.uncertain();
|
|
425
|
+
throw new ActionUncertainError(operation.id, { cause: error });
|
|
426
|
+
}
|
|
427
|
+
operation.reject();
|
|
428
|
+
throw error;
|
|
429
|
+
}
|
|
430
|
+
activeOperation = previous;
|
|
431
|
+
let asyncResult;
|
|
432
|
+
try {
|
|
433
|
+
asyncResult = isThenable(result);
|
|
434
|
+
} catch (error) {
|
|
435
|
+
operation.reject();
|
|
436
|
+
throw error;
|
|
437
|
+
}
|
|
438
|
+
if (!asyncResult) {
|
|
439
|
+
if (!isActionUncertain(result)) operation.confirm();
|
|
440
|
+
return result;
|
|
441
|
+
}
|
|
442
|
+
return Promise.resolve(result).then(
|
|
443
|
+
(value) => {
|
|
444
|
+
if (!isActionUncertain(value)) operation.confirm();
|
|
445
|
+
return value;
|
|
446
|
+
},
|
|
447
|
+
(error) => {
|
|
448
|
+
if (transportIsUncertain(error)) {
|
|
449
|
+
operation.uncertain();
|
|
450
|
+
throw new ActionUncertainError(operation.id, { cause: error });
|
|
451
|
+
}
|
|
452
|
+
operation.reject();
|
|
453
|
+
throw error;
|
|
454
|
+
}
|
|
455
|
+
);
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
function isActionUncertain(value) {
|
|
459
|
+
return value instanceof ActionUncertainError || (typeof value === "object" || typeof value === "function") && value !== null && uncertainReceipts.has(value);
|
|
460
|
+
}
|
|
461
|
+
export {
|
|
462
|
+
ActionUncertainError,
|
|
463
|
+
action$,
|
|
464
|
+
isActionUncertain,
|
|
465
|
+
optimistic$
|
|
466
|
+
};
|
package/dist/signals/client.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/** Optional component hooks for the native-read DOM compiler mode. */
|
|
2
|
+
export * from './index.js';
|
|
1
3
|
import type { WritableSignal } from './types.js';
|
|
2
4
|
/** A writable signal owned by this compiler-assigned component hook slot. */
|
|
3
5
|
export declare function useSignal$<T>(initial: T | (() => T), slot?: symbol): WritableSignal<T>;
|
package/dist/signals/client.js
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ScopedNode, type GraphOwner, type CandidateProducer, type SignalCandidateFrame } from './graph.js';
|
|
2
|
+
import { type DerivedCompute, type DerivedOptions, type DerivedSignal, type Scope } from './types.js';
|
|
3
|
+
export declare function createDeclaredDerivedCell<T>(owner: Scope, key: string, compute: DerivedCompute<T>, options?: DerivedOptions): DerivedSignal<T>;
|
|
4
|
+
export declare class DerivedBinding<T> {
|
|
5
|
+
readonly owner: Scope & GraphOwner;
|
|
6
|
+
readonly node: ScopedNode<T>;
|
|
7
|
+
private readonly options?;
|
|
8
|
+
private current;
|
|
9
|
+
private compute;
|
|
10
|
+
private frozen;
|
|
11
|
+
private candidate;
|
|
12
|
+
constructor(owner: Scope & GraphOwner, node: ScopedNode<T>, compute: DerivedCompute<T>, options?: DerivedOptions | undefined);
|
|
13
|
+
forkCandidate(target: ScopedNode<T>, frame: SignalCandidateFrame): CandidateProducer;
|
|
14
|
+
private static context;
|
|
15
|
+
private static notify;
|
|
16
|
+
private read;
|
|
17
|
+
private readDependency;
|
|
18
|
+
private static readValue;
|
|
19
|
+
private valid;
|
|
20
|
+
private validDependencies;
|
|
21
|
+
private evaluate;
|
|
22
|
+
private static observePromise;
|
|
23
|
+
private observeIterator;
|
|
24
|
+
private next;
|
|
25
|
+
private static queueNext;
|
|
26
|
+
private static observeStep;
|
|
27
|
+
private accept;
|
|
28
|
+
private fail;
|
|
29
|
+
private finish;
|
|
30
|
+
private invalidate;
|
|
31
|
+
private invalidateGraph;
|
|
32
|
+
private stop;
|
|
33
|
+
/** Stop only unfinished asynchronous reads; settled dependency edges stay live. */
|
|
34
|
+
suspend(): boolean;
|
|
35
|
+
resume(): void;
|
|
36
|
+
dispose(): void;
|
|
37
|
+
}
|