@warp-drive-mirror/react 5.7.0-alpha.31

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/LICENSE.md ADDED
@@ -0,0 +1,23 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017-2025 Ember.js and contributors
4
+ Copyright (c) 2011-2017 Tilde, Inc. and contributors
5
+ Copyright (c) 2011 LivingSocial Inc.
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,96 @@
1
+ <p align="center">
2
+ <img
3
+ class="project-logo"
4
+ src="./logos/NCC-1701-a-blue.svg#gh-light-mode-only"
5
+ alt="WarpDrive"
6
+ width="120px"
7
+ title="WarpDrive" />
8
+ <img
9
+ class="project-logo"
10
+ src="./logos/NCC-1701-a.svg#gh-dark-mode-only"
11
+ alt="WarpDrive"
12
+ width="120px"
13
+ title="WarpDrive" />
14
+ </p>
15
+
16
+ <h3 align="center">:electron: Components, Hooks and Utilities for using <em style="color: lightgreen">Warp</em><strong style="color: magenta">Drive</strong> with <strong style="color: lightblue">React</strong></h3>
17
+
18
+ ---
19
+
20
+ ```sh
21
+ pnpm install @warp-drive-mirror/react
22
+ ```
23
+
24
+ **Tagged Releases**
25
+
26
+ - ![NPM Canary Version](https://img.shields.io/npm/v/%40warp-drive%2Freact/canary?label=@canary&color=FFBF00)
27
+ - ![NPM Beta Version](https://img.shields.io/npm/v/%40warp-drive%2Freact/bet?label=@beta&color=ff00ff)
28
+ - ![NPM Stable Version](https://img.shields.io/npm/v/%40warp-drive%2Freact/latest?label=@latest&color=90EE90)
29
+ - ![NPM LTS Version](https://img.shields.io/npm/v/%40warp-drive%2Freact/lts?label=@lts&color=0096FF)
30
+ - ![NPM LTS-4-12 Version](https://img.shields.io/npm/v/%40warp-drive%2Freact/lts-4-12?label=@lts-4-12&color=bbbbbb)
31
+
32
+ ## About
33
+
34
+ This library provides reactive utilities for working with promises and requests, building over these primitives to provide functions and components that enable you to build robust performant apps with elegant control flow
35
+
36
+ ---
37
+
38
+ ### ♥️ Credits
39
+
40
+ <details>
41
+ <summary>Brought to you with ♥️ love by <a href="https://emberjs.com" title="EmberJS">🐹 Ember</a></summary>
42
+
43
+ <style type="text/css">
44
+ img.project-logo {
45
+ padding: 0 5em 1em 5em;
46
+ width: 100px;
47
+ border-bottom: 2px solid #0969da;
48
+ margin: 0 auto;
49
+ display: block;
50
+ }
51
+ details > summary {
52
+ font-size: 1.1rem;
53
+ line-height: 1rem;
54
+ margin-bottom: 1rem;
55
+ }
56
+ details {
57
+ font-size: 1rem;
58
+ }
59
+ details > summary strong {
60
+ display: inline-block;
61
+ padding: .2rem 0;
62
+ color: #000;
63
+ border-bottom: 3px solid #0969da;
64
+ }
65
+
66
+ details > details {
67
+ margin-left: 2rem;
68
+ }
69
+ details > details > summary {
70
+ font-size: 1rem;
71
+ line-height: 1rem;
72
+ margin-bottom: 1rem;
73
+ }
74
+ details > details > summary strong {
75
+ display: inline-block;
76
+ padding: .2rem 0;
77
+ color: #555;
78
+ border-bottom: 2px solid #555;
79
+ }
80
+ details > details {
81
+ font-size: .85rem;
82
+ }
83
+
84
+ @media (prefers-color-scheme: dark) {
85
+ details > summary strong {
86
+ color: #fff;
87
+ }
88
+ }
89
+ @media (prefers-color-scheme: dark) {
90
+ details > details > summary strong {
91
+ color: #afaba0;
92
+ border-bottom: 2px solid #afaba0;
93
+ }
94
+ }
95
+ </style>
96
+ </details>
package/addon-main.cjs ADDED
@@ -0,0 +1,5 @@
1
+ 'use strict';
2
+
3
+ const { addonShim } = require('@warp-drive-mirror/core/addon-shim.cjs');
4
+
5
+ module.exports = addonShim(__dirname);
@@ -0,0 +1,11 @@
1
+ import { Signal } from "signal-polyfill";
2
+ import { type JSX, type ReactNode, type Context } from "react";
3
+ export declare function useWatcher(): {
4
+ watcher: Signal.subtle.Watcher;
5
+ } | null;
6
+ export declare const WatcherContext: Context<{
7
+ watcher: Signal.subtle.Watcher;
8
+ } | null>;
9
+ export declare function ReactiveContext({ children }: {
10
+ children: ReactNode;
11
+ }): JSX.Element;
@@ -0,0 +1,140 @@
1
+ import { RequestArgs, type ContentFeatures, type RecoveryFeatures, type RequestLoadingState, type RequestState } from "@warp-drive-mirror/core/store/-private";
2
+ import type { StructuredErrorDocument } from "@warp-drive-mirror/core/types/request";
3
+ import { JSX, ReactNode } from "react";
4
+ interface ChromeComponentProps<RT> {
5
+ children: ReactNode;
6
+ state: RequestState | null;
7
+ features: ContentFeatures<RT>;
8
+ }
9
+ export interface RequestProps<
10
+ RT,
11
+ E
12
+ > extends RequestArgs<RT, E> {
13
+ chrome?: React.FC<ChromeComponentProps<RT>>;
14
+ states: RequestStates<RT, E>;
15
+ }
16
+ interface RequestStates<
17
+ RT,
18
+ E
19
+ > {
20
+ /**
21
+ * The block to render when the component is idle and waiting to be given a request.
22
+ *
23
+ */
24
+ idle?: React.FC<{}>;
25
+ /**
26
+ * The block to render when the request is loading.
27
+ *
28
+ */
29
+ loading?: React.FC<{
30
+ state: RequestLoadingState;
31
+ }>;
32
+ /**
33
+ * The block to render when the request was cancelled.
34
+ *
35
+ */
36
+ cancelled?: React.FC<{
37
+ /**
38
+ * The Error the request rejected with.
39
+ */
40
+ error: StructuredErrorDocument<E>;
41
+ /**
42
+ * Utilities to assist in recovering from the error.
43
+ */
44
+ features: RecoveryFeatures;
45
+ }>;
46
+ /**
47
+ * The block to render when the request failed. If this block is not provided,
48
+ * the error will be rethrown.
49
+ *
50
+ * Thus it is required to provide an error block and proper error handling if
51
+ * you do not want the error to crash the application.
52
+ */
53
+ error: React.FC<{
54
+ /**
55
+ * The Error the request rejected with.
56
+ */
57
+ error: StructuredErrorDocument<E>;
58
+ /**
59
+ * Utilities to assist in recovering from the error.
60
+ */
61
+ features: RecoveryFeatures;
62
+ }>;
63
+ /**
64
+ * The block to render when the request succeeded.
65
+ *
66
+ */
67
+ content: React.FC<{
68
+ result: RT;
69
+ features: ContentFeatures<RT>;
70
+ }>;
71
+ }
72
+ export declare function Throw({ error }: {
73
+ error: Error;
74
+ }): never;
75
+ /**
76
+ * The `<Request />` component is a powerful tool for managing data fetching and
77
+ * state in your React application. It provides a declarative approach to reactive
78
+ * control-flow for managing requests and state in your application.
79
+ *
80
+ * The `<Request />` component is ideal for handling "boundaries", outside which some
81
+ * state is still allowed to be unresolved and within which it MUST be resolved.
82
+ *
83
+ * ## Request States
84
+ *
85
+ * `<Request />` has five states, only one of which will be active and rendered at a time.
86
+ *
87
+ * - `idle`: The component is waiting to be given a request to monitor
88
+ * - `loading`: The request is in progress
89
+ * - `error`: The request failed
90
+ * - `content`: The request succeeded
91
+ * - `cancelled`: The request was cancelled
92
+ *
93
+ * Additionally, the `content` state has a `refresh` method that can be used to
94
+ * refresh the request in the background, which is available as a sub-state of
95
+ * the `content` state.
96
+ *
97
+ * ### Example Usage
98
+ *
99
+ * ```tsx
100
+ * import { Request } from "@warp-drive-mirror/react";
101
+ *
102
+ * export function UserPreview($props: { id: string | null }) {
103
+ * return (
104
+ * <Request
105
+ * query={findRecord('user', $props.id)}
106
+ * states={{
107
+ * idle: () => <div>Waiting for User Selection</div>,
108
+ * loading: ({ state }) => <div>Loading user data...</div>,
109
+ * cancelled: ({ error, features }) => (
110
+ * <div>
111
+ * <p>Request Cancelled</p>
112
+ * <p><button onClick={features.retry}>Start Again?</button></p>
113
+ * </div>
114
+ * ),
115
+ * error: ({ error, features }) => (
116
+ * <div>
117
+ * <p>Error: {error.message}</p>
118
+ * <p><button onClick={features.retry}>Try Again?</button></p>
119
+ * </div>
120
+ * ),
121
+ * content: ({ result, features }) => (
122
+ * <div>
123
+ * <h2>User Details</h2>
124
+ * <p>ID: {result.id}</p>
125
+ * <p>Name: {result.name}</p>
126
+ * </div>
127
+ * ),
128
+ * }}
129
+ * />
130
+ * );
131
+ * }
132
+ *
133
+ * ```
134
+ *
135
+ */
136
+ export declare function Request<
137
+ RT,
138
+ E
139
+ >($props: RequestProps<RT, E>): JSX.Element;
140
+ export {};
@@ -0,0 +1,7 @@
1
+ import { Store } from "@warp-drive-mirror/core";
2
+ import { JSX, ReactNode } from "react";
3
+ export declare function useStore(): Store;
4
+ export declare function StoreProvider($props: {
5
+ Store: Store;
6
+ children: ReactNode;
7
+ }): JSX.Element;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * React-specific reactivity integration, components
3
+ * and hooks for WarpDrive.
4
+ *
5
+ * @module
6
+ */
7
+ export { ReactiveContext } from "./-private/reactive-context.js";
8
+ export { StoreProvider, useStore } from "./-private/store-provider.js";
9
+ export { Request, Throw } from "./-private/request.js";
@@ -0,0 +1,3 @@
1
+ import { type HooksOptions, type SignalHooks } from "@warp-drive-mirror/core/configure";
2
+ export declare function settled(): Promise<void>;
3
+ export declare function buildSignalConfig(options: HooksOptions): SignalHooks;
package/dist/index.js ADDED
@@ -0,0 +1,265 @@
1
+ import { R as ReactiveContext } from "./reactive-context-zIDLf-L0.js";
2
+ import { Store } from '@warp-drive-mirror/core';
3
+ import { useMemo, createContext, use, useRef, useEffect } from 'react';
4
+ import { macroCondition, getGlobalConfig } from '@embroider/macros';
5
+ import { jsx, Fragment } from 'react/jsx-runtime';
6
+ import { DISPOSE, createRequestSubscription, signal } from '@warp-drive-mirror/core/store/-private';
7
+ import '@warp-drive-mirror/core/request';
8
+ const StoreContext = /*#__PURE__*/createContext(null);
9
+ function useStore() {
10
+ const store = use(StoreContext);
11
+ macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
12
+ if (!test) {
13
+ throw new Error("No Store provided via context. Please ensure you are using <StoreProvider> to provide a Store instance.");
14
+ }
15
+ })(store) : {};
16
+ return store;
17
+ }
18
+ function StoreProvider($props) {
19
+ const store = useMemo(() => new Store(), [$props.Store]);
20
+ return /*#__PURE__*/jsx(StoreContext, {
21
+ value: store,
22
+ children: $props.children
23
+ });
24
+ }
25
+ const deferred = /* @__PURE__ */new WeakMap();
26
+ function deferDecorator(proto, prop, desc) {
27
+ let map = deferred.get(proto);
28
+ if (!map) {
29
+ map = /* @__PURE__ */new Map();
30
+ deferred.set(proto, map);
31
+ }
32
+ map.set(prop, desc);
33
+ }
34
+ function findDeferredDecorator(target, prop) {
35
+ var _a;
36
+ let cursor = target.prototype;
37
+ while (cursor) {
38
+ let desc = (_a = deferred.get(cursor)) == null ? void 0 : _a.get(prop);
39
+ if (desc) {
40
+ return desc;
41
+ }
42
+ cursor = cursor.prototype;
43
+ }
44
+ }
45
+ function decorateFieldV2(prototype, prop, decorators, initializer) {
46
+ let desc = {
47
+ configurable: true,
48
+ enumerable: true,
49
+ writable: true,
50
+ initializer: null
51
+ };
52
+ if (initializer) {
53
+ desc.initializer = initializer;
54
+ }
55
+ for (let decorator of decorators) {
56
+ desc = decorator(prototype, prop, desc) || desc;
57
+ }
58
+ if (desc.initializer === void 0) {
59
+ Object.defineProperty(prototype, prop, desc);
60
+ } else {
61
+ deferDecorator(prototype, prop, desc);
62
+ }
63
+ }
64
+ function initializeDeferredDecorator(target, prop) {
65
+ let desc = findDeferredDecorator(target.constructor, prop);
66
+ if (desc) {
67
+ Object.defineProperty(target, prop, {
68
+ enumerable: desc.enumerable,
69
+ configurable: desc.configurable,
70
+ writable: desc.writable,
71
+ value: desc.initializer ? desc.initializer.call(target) : void 0
72
+ });
73
+ }
74
+ }
75
+ const IdleBlockMissingError = new Error("No idle block provided for <Request> component, and no query or request was provided.");
76
+ class ReactiveArgs {
77
+ static {
78
+ decorateFieldV2(this.prototype, "request", [signal]);
79
+ }
80
+ #request = (initializeDeferredDecorator(this, "request"), void 0);
81
+ static {
82
+ decorateFieldV2(this.prototype, "query", [signal]);
83
+ }
84
+ #query = (initializeDeferredDecorator(this, "query"), void 0);
85
+ static {
86
+ decorateFieldV2(this.prototype, "autorefresh", [signal]);
87
+ }
88
+ #autorefresh = (initializeDeferredDecorator(this, "autorefresh"), void 0);
89
+ static {
90
+ decorateFieldV2(this.prototype, "autorefreshThreshold", [signal]);
91
+ }
92
+ #autorefreshThreshold = (initializeDeferredDecorator(this, "autorefreshThreshold"), void 0);
93
+ static {
94
+ decorateFieldV2(this.prototype, "autorefreshBehavior", [signal]);
95
+ }
96
+ #autorefreshBehavior = (initializeDeferredDecorator(this, "autorefreshBehavior"), void 0);
97
+ }
98
+ const DefaultChrome = ({
99
+ children
100
+ }) => {
101
+ return /*#__PURE__*/jsx(Fragment, {
102
+ children: children
103
+ });
104
+ };
105
+ function Throw({
106
+ error
107
+ }) {
108
+ throw error;
109
+ }
110
+
111
+ /**
112
+ * The `<Request />` component is a powerful tool for managing data fetching and
113
+ * state in your React application. It provides a declarative approach to reactive
114
+ * control-flow for managing requests and state in your application.
115
+ *
116
+ * The `<Request />` component is ideal for handling "boundaries", outside which some
117
+ * state is still allowed to be unresolved and within which it MUST be resolved.
118
+ *
119
+ * ## Request States
120
+ *
121
+ * `<Request />` has five states, only one of which will be active and rendered at a time.
122
+ *
123
+ * - `idle`: The component is waiting to be given a request to monitor
124
+ * - `loading`: The request is in progress
125
+ * - `error`: The request failed
126
+ * - `content`: The request succeeded
127
+ * - `cancelled`: The request was cancelled
128
+ *
129
+ * Additionally, the `content` state has a `refresh` method that can be used to
130
+ * refresh the request in the background, which is available as a sub-state of
131
+ * the `content` state.
132
+ *
133
+ * ### Example Usage
134
+ *
135
+ * ```tsx
136
+ * import { Request } from "@warp-drive-mirror/react";
137
+ *
138
+ * export function UserPreview($props: { id: string | null }) {
139
+ * return (
140
+ * <Request
141
+ * query={findRecord('user', $props.id)}
142
+ * states={{
143
+ * idle: () => <div>Waiting for User Selection</div>,
144
+ * loading: ({ state }) => <div>Loading user data...</div>,
145
+ * cancelled: ({ error, features }) => (
146
+ * <div>
147
+ * <p>Request Cancelled</p>
148
+ * <p><button onClick={features.retry}>Start Again?</button></p>
149
+ * </div>
150
+ * ),
151
+ * error: ({ error, features }) => (
152
+ * <div>
153
+ * <p>Error: {error.message}</p>
154
+ * <p><button onClick={features.retry}>Try Again?</button></p>
155
+ * </div>
156
+ * ),
157
+ * content: ({ result, features }) => (
158
+ * <div>
159
+ * <h2>User Details</h2>
160
+ * <p>ID: {result.id}</p>
161
+ * <p>Name: {result.name}</p>
162
+ * </div>
163
+ * ),
164
+ * }}
165
+ * />
166
+ * );
167
+ * }
168
+ *
169
+ * ```
170
+ *
171
+ */
172
+ function Request($props) {
173
+ return /*#__PURE__*/jsx(ReactiveContext, {
174
+ children: /*#__PURE__*/jsx(InternalRequest, {
175
+ ...$props
176
+ })
177
+ });
178
+ }
179
+ function isStrictModeRender() {
180
+ const count = useRef(0);
181
+
182
+ // in debug we need to skip every second invocation
183
+ if (macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG)) {
184
+ if (count.current++ % 2 === 1) {
185
+ return true;
186
+ }
187
+ }
188
+ return false;
189
+ }
190
+ function InternalRequest($props) {
191
+ const isStrict = isStrictModeRender();
192
+ const store = $props.store ?? useStore();
193
+ const Chrome = $props.chrome ?? DefaultChrome;
194
+ const sink = useRef(null);
195
+ const args = useRef(null);
196
+ if (!args.current) {
197
+ args.current = new ReactiveArgs();
198
+ }
199
+ Object.assign(args.current, $props);
200
+ if (sink.current && (sink.current.store !== store || $props.subscription)) {
201
+ sink.current[DISPOSE]();
202
+ sink.current = null;
203
+ }
204
+ if (!sink.current && !$props.subscription) {
205
+ sink.current = createRequestSubscription(store, args.current);
206
+ }
207
+ const initialized = useRef(null);
208
+ const effect = () => {
209
+ if (sink.current && (!initialized.current || initialized.current.disposable !== sink.current)) {
210
+ initialized.current = {
211
+ disposable: sink.current,
212
+ dispose: () => {
213
+ sink.current?.[DISPOSE]();
214
+ initialized.current = null;
215
+ sink.current = null;
216
+ }
217
+ };
218
+ }
219
+ return sink.current ? initialized.current.dispose : undefined;
220
+ };
221
+ let maybeEffect = effect;
222
+ if (macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG)) {
223
+ if (isStrict) {
224
+ maybeEffect = () => {
225
+ if (initialized.current) {
226
+ return effect();
227
+ }
228
+ return () => {
229
+ // initialize our actual effect
230
+ effect();
231
+ // in strict mode we don't want to run the teardown
232
+ // for the second invocation
233
+ };
234
+ };
235
+ }
236
+ }
237
+ useEffect(maybeEffect, [sink.current]);
238
+ const state = $props.subscription ?? sink.current;
239
+ const slots = $props.states;
240
+ return /*#__PURE__*/jsx(Chrome, {
241
+ state: state.isIdle ? null : state.reqState,
242
+ features: state.contentFeatures,
243
+ children:
244
+ // prettier-ignore
245
+ state.isIdle && slots.idle ? /*#__PURE__*/jsx(slots.idle, {}) : state.isIdle ? /*#__PURE__*/jsx(Throw, {
246
+ error: IdleBlockMissingError
247
+ }) : state.reqState.isLoading ? slots.loading ? /*#__PURE__*/jsx(slots.loading, {
248
+ state: state.reqState.loadingState
249
+ }) : '' : state.reqState.isCancelled && slots.cancelled ? /*#__PURE__*/jsx(slots.cancelled, {
250
+ error: state.reqState.reason,
251
+ features: state.errorFeatures
252
+ }) : state.reqState.isError && slots.error ? /*#__PURE__*/jsx(slots.error, {
253
+ error: state.reqState.reason,
254
+ features: state.errorFeatures
255
+ }) : state.reqState.isSuccess ? slots.content ? /*#__PURE__*/jsx(slots.content, {
256
+ result: state.reqState.value,
257
+ features: state.contentFeatures
258
+ }) : /*#__PURE__*/jsx(Throw, {
259
+ error: new Error('No content block provided for <Request> component.')
260
+ }) : !state.reqState.isCancelled ? /*#__PURE__*/jsx(Throw, {
261
+ error: state.reqState.reason
262
+ }) : '' // never
263
+ });
264
+ }
265
+ export { ReactiveContext, Request, StoreProvider, Throw, useStore };
@@ -0,0 +1,115 @@
1
+ import { use } from 'react';
2
+ import { Signal } from 'signal-polyfill';
3
+ import { setupSignals } from '@warp-drive-mirror/core/configure';
4
+ import { W as WatcherContext } from "./reactive-context-zIDLf-L0.js";
5
+ import { macroCondition, getGlobalConfig } from '@embroider/macros';
6
+
7
+ /**
8
+ * Unlike reactive frameworks, React does not have the ability to support
9
+ * fine-grained reactivity. However, we can approximate it to "good enough"
10
+ * granularity by keeping track of signals used within a specific context.
11
+ *
12
+ * React also does not have a built-in way to memoize functions the way that
13
+ * reactive frameworks do, but by building overtop of other Signal libraries
14
+ * we can provide this.
15
+ *
16
+ * Due to the above limitations, @warp-drive-mirror/react/install is built
17
+ * overtop @warp-drive/tc39-proposal-signals/install.
18
+ *
19
+ * The TC39 Watcher especially is valuable here, as it allows us to subscribe to changes
20
+ * to the dependency graph of a memo and not just a signal.
21
+ */
22
+
23
+ function tryConsumeContext(signal) {
24
+ // eslint-disable-next-line no-console
25
+ const logError = console.error;
26
+ try {
27
+ // eslint-disable-next-line no-console
28
+ console.error = () => {};
29
+ // ensure signals are watched by our closest watcher
30
+ const watcher = use(WatcherContext);
31
+ // eslint-disable-next-line no-console
32
+ console.error = logError;
33
+ watcher?.watcher.watch(signal);
34
+ if (macroCondition(getGlobalConfig().WarpDriveMirror.activeLogging.LOG_REACT_SIGNAL_INTEGRATION)) {
35
+ if (getGlobalConfig().WarpDriveMirror.debug.LOG_REACT_SIGNAL_INTEGRATION || globalThis.getWarpDriveRuntimeConfig().debug.LOG_REACT_SIGNAL_INTEGRATION) {
36
+ // eslint-disable-next-line no-console
37
+ console.log(`[WarpDrive] Consumed Context Signal`, signal, watcher);
38
+ }
39
+ }
40
+ } catch {
41
+ // eslint-disable-next-line no-console
42
+ console.error = logError;
43
+ // if we are not in a React context, we will Error
44
+ // so we just ignore it.
45
+ if (macroCondition(getGlobalConfig().WarpDriveMirror.activeLogging.LOG_REACT_SIGNAL_INTEGRATION)) {
46
+ if (getGlobalConfig().WarpDriveMirror.debug.LOG_REACT_SIGNAL_INTEGRATION || globalThis.getWarpDriveRuntimeConfig().debug.LOG_REACT_SIGNAL_INTEGRATION) {
47
+ // eslint-disable-next-line no-console
48
+ console.log(`[WarpDrive] No Context Available To Consume Signal`, signal);
49
+ }
50
+ }
51
+ }
52
+ }
53
+ let pending;
54
+ async function settled() {
55
+ if (macroCondition(getGlobalConfig().WarpDriveMirror.env.TESTING)) {
56
+ // in testing mode we provide a test waiter integration
57
+ if (!pending || !pending.length) return;
58
+ const current = pending ?? [];
59
+ pending = [];
60
+ await Promise.allSettled(current);
61
+ await Promise.resolve();
62
+ await Promise.resolve();
63
+ await Promise.resolve();
64
+ return settled();
65
+ }
66
+ }
67
+ function buildSignalConfig(options) {
68
+ return {
69
+ createSignal: (obj, key) => new Signal.State(macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? {
70
+ obj,
71
+ key
72
+ } : null, {
73
+ equals: () => false
74
+ }),
75
+ notifySignal: signal => {
76
+ if (macroCondition(getGlobalConfig().WarpDriveMirror.activeLogging.LOG_REACT_SIGNAL_INTEGRATION)) {
77
+ if (getGlobalConfig().WarpDriveMirror.debug.LOG_REACT_SIGNAL_INTEGRATION || globalThis.getWarpDriveRuntimeConfig().debug.LOG_REACT_SIGNAL_INTEGRATION) {
78
+ if (Signal.subtle.hasSinks(signal)) {
79
+ // eslint-disable-next-line no-console
80
+ console.log(`[WarpDrive] Notifying Signal`, signal);
81
+ } else {
82
+ // eslint-disable-next-line no-console
83
+ console.log(`[WarpDrive] Notified Signal That Has No Watcher`, signal);
84
+ }
85
+ }
86
+ }
87
+ signal.set(signal.get());
88
+ },
89
+ consumeSignal: signal => {
90
+ tryConsumeContext(signal);
91
+ void signal.get();
92
+ },
93
+ createMemo: (object, key, fn) => {
94
+ const memo = new Signal.Computed(fn);
95
+ return () => {
96
+ tryConsumeContext(memo);
97
+ return memo.get();
98
+ };
99
+ },
100
+ waitFor: promise => {
101
+ if (macroCondition(getGlobalConfig().WarpDriveMirror.env.TESTING)) {
102
+ pending = pending || [];
103
+ const newPromise = promise.finally(() => {
104
+ pending = pending.filter(p => p !== newPromise);
105
+ });
106
+ pending.push(newPromise);
107
+ return newPromise;
108
+ }
109
+ return promise;
110
+ },
111
+ willSyncFlushWatchers: () => false
112
+ };
113
+ }
114
+ setupSignals(buildSignalConfig);
115
+ export { buildSignalConfig, settled };