teamplay 0.5.0-alpha.14 → 0.5.0-alpha.16
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/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/orm/Compat/hooksCompat.d.ts +0 -8
- package/dist/orm/Compat/hooksCompat.js +8 -38
- package/dist/react/convertToObserver.js +1 -4
- package/dist/react/renderAttemptDestroyer.d.ts +0 -8
- package/dist/react/renderAttemptDestroyer.js +2 -28
- package/dist/react/trapRender.js +2 -2
- package/dist/react/useSub.d.ts +17 -5
- package/dist/react/useSub.js +24 -28
- package/dist/react/useSuspendMemo.js +1 -5
- package/package.json +2 -2
- package/dist/react/compatComponentRegistry.d.ts +0 -4
- package/dist/react/compatComponentRegistry.js +0 -19
package/dist/index.d.ts
CHANGED
|
@@ -57,7 +57,7 @@ export { default as sub } from './orm/sub.js';
|
|
|
57
57
|
export { default as useSub, useAsyncSub, setUseDeferredValue as __setUseDeferredValue, setDefaultDefer as __setDefaultDefer } from './react/useSub.js';
|
|
58
58
|
export { default as useSuspendMemo, useSuspendMemoByKey } from './react/useSuspendMemo.js';
|
|
59
59
|
export declare const observer: ObserverFunction;
|
|
60
|
-
export { useBatch,
|
|
60
|
+
export { useBatch, useBatchDoc, useBatchDoc$, useBatchQuery, useBatchQuery$, useQueryIds, useBatchQueryIds, useAsyncQueryIds, useQueryDoc, useQueryDoc$, useBatchQueryDoc, useBatchQueryDoc$, useAsyncQueryDoc, useAsyncQueryDoc$ } from './orm/Compat/hooksCompat.js';
|
|
61
61
|
export { emit, useOn, useEmit } from './orm/Compat/eventsCompat.js';
|
|
62
62
|
export { useDidUpdate, useOnce, useSyncEffect } from './react/helpers.js';
|
|
63
63
|
export { connection, setConnection, getConnection, getDefaultFetchOnly, setDefaultFetchOnly, publicOnly, setPublicOnly } from './orm/connection.js';
|
package/dist/index.js
CHANGED
|
@@ -18,7 +18,7 @@ export { default as sub } from "./orm/sub.js";
|
|
|
18
18
|
export { default as useSub, useAsyncSub, setUseDeferredValue as __setUseDeferredValue, setDefaultDefer as __setDefaultDefer } from "./react/useSub.js";
|
|
19
19
|
export { default as useSuspendMemo, useSuspendMemoByKey } from "./react/useSuspendMemo.js";
|
|
20
20
|
export const observer = runtimeObserver;
|
|
21
|
-
export { useBatch,
|
|
21
|
+
export { useBatch, useBatchDoc, useBatchDoc$, useBatchQuery, useBatchQuery$, useQueryIds, useBatchQueryIds, useAsyncQueryIds, useQueryDoc, useQueryDoc$, useBatchQueryDoc, useBatchQueryDoc$, useAsyncQueryDoc, useAsyncQueryDoc$ } from './orm/Compat/hooksCompat.js';
|
|
22
22
|
export { emit, useOn, useEmit } from './orm/Compat/eventsCompat.js';
|
|
23
23
|
export { useDidUpdate, useOnce, useSyncEffect } from "./react/helpers.js";
|
|
24
24
|
export { connection, setConnection, getConnection, getDefaultFetchOnly, setDefaultFetchOnly, publicOnly, setPublicOnly } from "./orm/connection.js";
|
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
export const useBatch: any
|
|
2
|
-
export const useDoc: any
|
|
3
|
-
export const useDoc$: any
|
|
4
2
|
export const useBatchDoc: any
|
|
5
3
|
export const useBatchDoc$: any
|
|
6
|
-
export const useAsyncDoc: any
|
|
7
|
-
export const useAsyncDoc$: any
|
|
8
|
-
export const useQuery: any
|
|
9
|
-
export const useQuery$: any
|
|
10
|
-
export const useAsyncQuery: any
|
|
11
|
-
export const useAsyncQuery$: any
|
|
12
4
|
export const useBatchQuery: any
|
|
13
5
|
export const useBatchQuery$: any
|
|
14
6
|
export const useQueryIds: any
|
|
@@ -11,15 +11,6 @@ export function useBatch() {
|
|
|
11
11
|
if (promise)
|
|
12
12
|
throw promise;
|
|
13
13
|
}
|
|
14
|
-
export function useDoc$(collection, id, options) {
|
|
15
|
-
const $doc = getDocSignal(collection, id, 'useDoc');
|
|
16
|
-
const normalizedOptions = normalizeSyncSubOptions(options);
|
|
17
|
-
return useSub($doc, undefined, normalizedOptions);
|
|
18
|
-
}
|
|
19
|
-
export function useDoc(collection, id, options) {
|
|
20
|
-
const $doc = useDoc$(collection, id, options);
|
|
21
|
-
return [$doc.get(), $doc];
|
|
22
|
-
}
|
|
23
14
|
export function useBatchDoc(collection, id, options) {
|
|
24
15
|
const $doc = useBatchDoc$(collection, id, options);
|
|
25
16
|
if (!$doc)
|
|
@@ -31,16 +22,6 @@ export function useBatchDoc$(collection, id, _options) {
|
|
|
31
22
|
const options = _options ? { ..._options, ...BATCH_SUB_OPTIONS } : BATCH_SUB_OPTIONS;
|
|
32
23
|
return useSub($doc, undefined, options);
|
|
33
24
|
}
|
|
34
|
-
export function useAsyncDoc$(collection, id, options) {
|
|
35
|
-
const $doc = getDocSignal(collection, id, 'useAsyncDoc');
|
|
36
|
-
return useAsyncSub($doc, undefined, options);
|
|
37
|
-
}
|
|
38
|
-
export function useAsyncDoc(collection, id, options) {
|
|
39
|
-
const $doc = useAsyncDoc$(collection, id, options);
|
|
40
|
-
if (!$doc)
|
|
41
|
-
return [undefined, undefined];
|
|
42
|
-
return [$doc.get(), $doc];
|
|
43
|
-
}
|
|
44
25
|
function useSubscribedQuery(collection, query, options, hookName, subscribe) {
|
|
45
26
|
const normalizedQuery = normalizeQuery(query, hookName);
|
|
46
27
|
const $collection = getCollectionSignal(collection, query, hookName);
|
|
@@ -56,22 +37,13 @@ function getExtraQuerySignal($query, normalizedQuery) {
|
|
|
56
37
|
return $query;
|
|
57
38
|
return isExtraQuery(normalizedQuery) ? $query.extra : $query;
|
|
58
39
|
}
|
|
59
|
-
|
|
40
|
+
function useSyncQueryResult(collection, query, options, hookName) {
|
|
60
41
|
const normalizedOptions = normalizeSyncSubOptions(options);
|
|
61
|
-
const { $query } = useSubscribedQuery(collection, query, normalizedOptions,
|
|
62
|
-
return $query;
|
|
63
|
-
}
|
|
64
|
-
export function useQuery(collection, query, options) {
|
|
65
|
-
const normalizedOptions = normalizeSyncSubOptions(options);
|
|
66
|
-
const { $collection, $query } = useSubscribedQuery(collection, query, normalizedOptions, 'useQuery', useSub);
|
|
42
|
+
const { $collection, $query } = useSubscribedQuery(collection, query, normalizedOptions, hookName, useSub);
|
|
67
43
|
return [$query.get(), $collection];
|
|
68
44
|
}
|
|
69
|
-
|
|
70
|
-
const { $query } = useSubscribedQuery(collection, query, options,
|
|
71
|
-
return $query;
|
|
72
|
-
}
|
|
73
|
-
export function useAsyncQuery(collection, query, options) {
|
|
74
|
-
const { $collection, $query } = useSubscribedQuery(collection, query, options, 'useAsyncQuery', useAsyncSub);
|
|
45
|
+
function useAsyncQueryResult(collection, query, options, hookName) {
|
|
46
|
+
const { $collection, $query } = useSubscribedQuery(collection, query, options, hookName, useAsyncSub);
|
|
75
47
|
if (!$query)
|
|
76
48
|
return [undefined, $collection];
|
|
77
49
|
return [$query.get(), $collection];
|
|
@@ -92,7 +64,7 @@ export function useQueryIds(collection, ids = [], options = {}) {
|
|
|
92
64
|
const list = Array.isArray(ids) ? ids.slice() : [];
|
|
93
65
|
if (options?.reverse)
|
|
94
66
|
list.reverse();
|
|
95
|
-
const [docs, $collection] =
|
|
67
|
+
const [docs, $collection] = useSyncQueryResult(collection, { _id: { $in: list } }, options, 'useQueryIds');
|
|
96
68
|
if (!docs)
|
|
97
69
|
return [docs, $collection];
|
|
98
70
|
const docsById = new Map();
|
|
@@ -124,7 +96,7 @@ export function useAsyncQueryIds(collection, ids = [], options = {}) {
|
|
|
124
96
|
const list = Array.isArray(ids) ? ids.slice() : [];
|
|
125
97
|
if (options?.reverse)
|
|
126
98
|
list.reverse();
|
|
127
|
-
const [docs, $collection] =
|
|
99
|
+
const [docs, $collection] = useAsyncQueryResult(collection, { _id: { $in: list } }, options, 'useAsyncQueryIds');
|
|
128
100
|
if (docs == null)
|
|
129
101
|
return [undefined, $collection];
|
|
130
102
|
const docsById = new Map();
|
|
@@ -143,7 +115,7 @@ export function useQueryDoc(collection, query, options) {
|
|
|
143
115
|
$limit: 1,
|
|
144
116
|
$sort: normalized.$sort || { createdAt: -1 }
|
|
145
117
|
};
|
|
146
|
-
const [docs, $collection] =
|
|
118
|
+
const [docs, $collection] = useSyncQueryResult(collection, queryDoc, options, 'useQueryDoc');
|
|
147
119
|
const doc = docs && docs[0];
|
|
148
120
|
const docId = doc?._id ?? doc?.id;
|
|
149
121
|
const $doc = docId != null ? $collection[docId] : undefined;
|
|
@@ -179,7 +151,7 @@ export function useAsyncQueryDoc(collection, query, options) {
|
|
|
179
151
|
$limit: 1,
|
|
180
152
|
$sort: normalized.$sort || { createdAt: -1 }
|
|
181
153
|
};
|
|
182
|
-
const [docs, $collection] =
|
|
154
|
+
const [docs, $collection] = useAsyncQueryResult(collection, queryDoc, options, 'useAsyncQueryDoc');
|
|
183
155
|
if (docs == null)
|
|
184
156
|
return [undefined, undefined];
|
|
185
157
|
const doc = docs && docs[0];
|
|
@@ -247,7 +219,6 @@ function isExtraQuery(query) {
|
|
|
247
219
|
const BATCH_SUB_OPTIONS = Object.freeze({
|
|
248
220
|
async: false,
|
|
249
221
|
batch: true,
|
|
250
|
-
renderAttemptCleanup: true,
|
|
251
222
|
// Batch hooks are a hard suspense barrier. Deferred params can skip the barrier
|
|
252
223
|
// on route transitions and cause immediate reads from stale/empty local nodes.
|
|
253
224
|
defer: false
|
|
@@ -259,7 +230,6 @@ function normalizeSyncSubOptions(options) {
|
|
|
259
230
|
return {
|
|
260
231
|
...(options || {}),
|
|
261
232
|
async: false,
|
|
262
|
-
renderAttemptCleanup: true,
|
|
263
233
|
// Compat sync hooks are strict by design: no deferred snapshots between route/tab switches.
|
|
264
234
|
defer: false
|
|
265
235
|
};
|
|
@@ -7,7 +7,6 @@ import executionContextTracker from "./executionContextTracker.js";
|
|
|
7
7
|
import { pipeComponentMeta, useUnmount, useId, useTriggerUpdate } from "./helpers.js";
|
|
8
8
|
import trapRender from './trapRender.js';
|
|
9
9
|
import { scheduleReaction } from '../orm/batchScheduler.js';
|
|
10
|
-
import { isCompatComponent, unmarkCompatComponent } from "./compatComponentRegistry.js";
|
|
11
10
|
const DEFAULT_THROTTLE_TIMEOUT = 100;
|
|
12
11
|
export default function convertToObserver(BaseComponent, { forwardRef, cache: enableCache = true, throttle, ...options } = {}) {
|
|
13
12
|
throttle = normalizeThrottle(throttle);
|
|
@@ -33,7 +32,7 @@ export default function convertToObserver(BaseComponent, { forwardRef, cache: en
|
|
|
33
32
|
hasDeferredUpdateAfterExecutionContext = false;
|
|
34
33
|
triggerUpdate();
|
|
35
34
|
}
|
|
36
|
-
else
|
|
35
|
+
else {
|
|
37
36
|
if (hasDeferredUpdateAfterExecutionContext)
|
|
38
37
|
return;
|
|
39
38
|
hasDeferredUpdateAfterExecutionContext = true;
|
|
@@ -53,7 +52,6 @@ export default function convertToObserver(BaseComponent, { forwardRef, cache: en
|
|
|
53
52
|
if (!reactionRef.current)
|
|
54
53
|
throw Error(`NO REACTION REF - ${where}`);
|
|
55
54
|
destroyRef.current = undefined;
|
|
56
|
-
unmarkCompatComponent(componentId);
|
|
57
55
|
unobserve(reactionRef.current);
|
|
58
56
|
reactionRef.current = undefined;
|
|
59
57
|
destroyCache(where);
|
|
@@ -71,7 +69,6 @@ export default function convertToObserver(BaseComponent, { forwardRef, cache: en
|
|
|
71
69
|
}
|
|
72
70
|
// clean up observer on unmount
|
|
73
71
|
useUnmount(() => {
|
|
74
|
-
unmarkCompatComponent(componentId);
|
|
75
72
|
destroyRef.current?.('useUnmount()');
|
|
76
73
|
});
|
|
77
74
|
return reactionRef.current(...args);
|
|
@@ -1,17 +1,9 @@
|
|
|
1
|
-
type DestroyAttempt = () => unknown | Promise<unknown>;
|
|
2
1
|
declare class RenderAttemptDestroyer {
|
|
3
|
-
fns: DestroyAttempt[];
|
|
4
|
-
renderAttemptCleanupArmed: boolean;
|
|
5
2
|
suspenseGateArmed: boolean;
|
|
6
3
|
constructor();
|
|
7
|
-
add(fn: DestroyAttempt | undefined, { renderAttemptCleanup }?: {
|
|
8
|
-
renderAttemptCleanup?: boolean;
|
|
9
|
-
}): void;
|
|
10
|
-
armRenderAttemptCleanup(): void;
|
|
11
4
|
armSuspenseGate(): void;
|
|
12
5
|
consumeThenableHandling(): {
|
|
13
6
|
shouldKeepShellAlive: boolean;
|
|
14
|
-
destroyAttempt?: () => Promise<void>;
|
|
15
7
|
};
|
|
16
8
|
reset(): void;
|
|
17
9
|
}
|
|
@@ -1,45 +1,19 @@
|
|
|
1
1
|
class RenderAttemptDestroyer {
|
|
2
|
-
fns;
|
|
3
|
-
renderAttemptCleanupArmed;
|
|
4
2
|
suspenseGateArmed;
|
|
5
3
|
constructor() {
|
|
6
|
-
this.fns = [];
|
|
7
|
-
this.renderAttemptCleanupArmed = false;
|
|
8
4
|
this.suspenseGateArmed = false;
|
|
9
5
|
}
|
|
10
|
-
add(fn, { renderAttemptCleanup = false } = {}) {
|
|
11
|
-
if (typeof fn !== 'function')
|
|
12
|
-
return;
|
|
13
|
-
this.fns.push(fn);
|
|
14
|
-
if (renderAttemptCleanup)
|
|
15
|
-
this.renderAttemptCleanupArmed = true;
|
|
16
|
-
}
|
|
17
|
-
armRenderAttemptCleanup() {
|
|
18
|
-
this.renderAttemptCleanupArmed = true;
|
|
19
|
-
}
|
|
20
6
|
armSuspenseGate() {
|
|
21
7
|
this.suspenseGateArmed = true;
|
|
22
8
|
}
|
|
23
9
|
consumeThenableHandling() {
|
|
24
|
-
const
|
|
25
|
-
const shouldKeepShellAlive = this.suspenseGateArmed || shouldRunAttemptCleanup;
|
|
26
|
-
let destroyAttempt;
|
|
27
|
-
if (shouldRunAttemptCleanup) {
|
|
28
|
-
const fns = [...this.fns];
|
|
29
|
-
destroyAttempt = async () => {
|
|
30
|
-
await Promise.allSettled(fns.map(fn => fn()));
|
|
31
|
-
fns.length = 0;
|
|
32
|
-
};
|
|
33
|
-
}
|
|
10
|
+
const shouldKeepShellAlive = this.suspenseGateArmed;
|
|
34
11
|
this.reset();
|
|
35
12
|
return {
|
|
36
|
-
shouldKeepShellAlive
|
|
37
|
-
destroyAttempt
|
|
13
|
+
shouldKeepShellAlive
|
|
38
14
|
};
|
|
39
15
|
}
|
|
40
16
|
reset() {
|
|
41
|
-
this.fns.length = 0;
|
|
42
|
-
this.renderAttemptCleanupArmed = false;
|
|
43
17
|
this.suspenseGateArmed = false;
|
|
44
18
|
}
|
|
45
19
|
}
|
package/dist/react/trapRender.js
CHANGED
|
@@ -24,9 +24,9 @@ export default function trapRender({ render, cache, destroy, componentId }) {
|
|
|
24
24
|
destroyed = true;
|
|
25
25
|
throw err;
|
|
26
26
|
}
|
|
27
|
-
const { shouldKeepShellAlive
|
|
27
|
+
const { shouldKeepShellAlive } = renderAttemptDestroyer.consumeThenableHandling();
|
|
28
28
|
if (shouldKeepShellAlive) {
|
|
29
|
-
throw Promise.resolve(err)
|
|
29
|
+
throw Promise.resolve(err);
|
|
30
30
|
}
|
|
31
31
|
// TODO: this might only be needed only if promise is thrown
|
|
32
32
|
// (check if useUnmount in convertToObserver is called if a regular error is thrown)
|
package/dist/react/useSub.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AggregationFunction, AggregationParams, ClientAggregationFunction } from '@teamplay/utils/aggregation';
|
|
2
|
-
import type
|
|
2
|
+
import { type CollectionSignal, type ComputedQueryParamsInput, type DocumentSignal, type QueryParams, type RegisteredAggregationInput, type SignalModelConstructor, type SubResult, type TypedAggregationInput, type TypedAggregationSignal, type WildcardSignalPath } from '../orm/Signal.js';
|
|
3
3
|
export interface UseSubOptions {
|
|
4
4
|
/** Return `undefined` while loading instead of throwing a Suspense promise. */
|
|
5
5
|
async?: boolean;
|
|
@@ -7,9 +7,14 @@ export interface UseSubOptions {
|
|
|
7
7
|
defer?: boolean | number;
|
|
8
8
|
/** Batch Suspense promises across multiple subscriptions in one render attempt. */
|
|
9
9
|
batch?: boolean;
|
|
10
|
-
/** Enable cleanup for observer render attempts when a subscription suspends. */
|
|
11
|
-
renderAttemptCleanup?: boolean;
|
|
12
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Subscribe to a document signal in React async mode.
|
|
13
|
+
* @param signal Document signal to subscribe to.
|
|
14
|
+
* @param params Must be omitted for document subscriptions.
|
|
15
|
+
* @param options Subscription behavior options.
|
|
16
|
+
*/
|
|
17
|
+
export declare function useAsyncSub<TSignal extends DocumentSignal<any, any, any>>(signal: TSignal, options?: UseSubOptions): SubResult<TSignal>;
|
|
13
18
|
/**
|
|
14
19
|
* Subscribe to a document signal in React async mode.
|
|
15
20
|
* @param signal Document signal to subscribe to.
|
|
@@ -61,6 +66,13 @@ export declare function useAsyncSub<TDocument, TDocumentModel extends SignalMode
|
|
|
61
66
|
* @param options Subscription behavior options.
|
|
62
67
|
*/
|
|
63
68
|
export declare function useAsyncSub<TOutput = unknown, TCollection extends string = string>(signal: AggregationFunction<TOutput, TCollection>, params?: AggregationParams, options?: UseSubOptions): SubResult<AggregationFunction<TOutput, TCollection>, AggregationParams | undefined>;
|
|
69
|
+
/**
|
|
70
|
+
* Subscribe to a document signal in React.
|
|
71
|
+
* @param signal Document signal to subscribe to.
|
|
72
|
+
* @param params Must be omitted for document subscriptions.
|
|
73
|
+
* @param options Subscription behavior options.
|
|
74
|
+
*/
|
|
75
|
+
export default function useSub<TSignal extends DocumentSignal<any, any, any>>(signal: TSignal, options?: UseSubOptions): SubResult<TSignal>;
|
|
64
76
|
/**
|
|
65
77
|
* Subscribe to a document signal in React.
|
|
66
78
|
* @param signal Document signal to subscribe to.
|
|
@@ -112,8 +124,8 @@ export default function useSub<TDocument, TDocumentModel extends SignalModelCons
|
|
|
112
124
|
* @param options Subscription behavior options.
|
|
113
125
|
*/
|
|
114
126
|
export default function useSub<TOutput = unknown, TCollection extends string = string>(signal: AggregationFunction<TOutput, TCollection>, params?: AggregationParams, options?: UseSubOptions): SubResult<AggregationFunction<TOutput, TCollection>, AggregationParams | undefined>;
|
|
115
|
-
export declare function useSubDeferred(signal: unknown, params?: unknown, { async, defer, batch
|
|
116
|
-
export declare function useSubClassic(signal: unknown, params?: unknown, { async, batch
|
|
127
|
+
export declare function useSubDeferred(signal: unknown, params?: unknown, { async, defer, batch }?: UseSubOptions): unknown;
|
|
128
|
+
export declare function useSubClassic(signal: unknown, params?: unknown, { async, batch }?: UseSubOptions): unknown;
|
|
117
129
|
export declare function setTestThrottling(ms: number): void;
|
|
118
130
|
export declare function resetTestThrottling(): void;
|
|
119
131
|
export declare function setUseDeferredValue(value: boolean): void;
|
package/dist/react/useSub.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { useRef, useDeferredValue } from 'react';
|
|
2
2
|
import sub from "../orm/sub.js";
|
|
3
|
-
import { useScheduleUpdate, useCache, useDefer
|
|
3
|
+
import { useScheduleUpdate, useCache, useDefer } from "./helpers.js";
|
|
4
4
|
import executionContextTracker from "./executionContextTracker.js";
|
|
5
5
|
import * as promiseBatcher from "./promiseBatcher.js";
|
|
6
|
-
import
|
|
7
|
-
import { markCompatComponent } from "./compatComponentRegistry.js";
|
|
6
|
+
import { isPublicDocumentSignal } from "../orm/Signal.js";
|
|
8
7
|
const runtimeSub = sub;
|
|
8
|
+
const USE_SUB_OPTION_KEYS = new Set(['async', 'defer', 'batch']);
|
|
9
9
|
let TEST_THROTTLING = false;
|
|
10
10
|
// experimental feature to leverage useDeferredValue() to handle re-subscriptions.
|
|
11
11
|
// Currently it does lead to issues with extra rerenders and requires further investigation
|
|
@@ -13,10 +13,27 @@ let USE_DEFERRED_VALUE = true;
|
|
|
13
13
|
// by default we want to defer stuff if possible instead of throwing promises
|
|
14
14
|
let DEFAULT_DEFER = true;
|
|
15
15
|
export function useAsyncSub(signal, params, options) {
|
|
16
|
-
|
|
16
|
+
const normalized = normalizeUseSubArgs(signal, params, options);
|
|
17
|
+
return runUseSub(normalized.signal, normalized.params, { ...normalized.options, async: true });
|
|
17
18
|
}
|
|
18
19
|
export default function useSub(signal, params, options) {
|
|
19
|
-
|
|
20
|
+
const normalized = normalizeUseSubArgs(signal, params, options);
|
|
21
|
+
return runUseSub(normalized.signal, normalized.params, normalized.options);
|
|
22
|
+
}
|
|
23
|
+
function normalizeUseSubArgs(signal, params, options) {
|
|
24
|
+
if (options === undefined && params !== undefined && isPublicDocumentSignal(signal) && isUseSubOptions(params)) {
|
|
25
|
+
return {
|
|
26
|
+
signal,
|
|
27
|
+
params: undefined,
|
|
28
|
+
options: params
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return { signal, params, options };
|
|
32
|
+
}
|
|
33
|
+
function isUseSubOptions(value) {
|
|
34
|
+
if (value == null || typeof value !== 'object' || Array.isArray(value))
|
|
35
|
+
return false;
|
|
36
|
+
return Object.keys(value).every(key => USE_SUB_OPTION_KEYS.has(key));
|
|
20
37
|
}
|
|
21
38
|
function runUseSub(signal, params, options) {
|
|
22
39
|
if (USE_DEFERRED_VALUE) {
|
|
@@ -27,13 +44,10 @@ function runUseSub(signal, params, options) {
|
|
|
27
44
|
}
|
|
28
45
|
}
|
|
29
46
|
// version of sub() which works as a react hook and throws promise for Suspense
|
|
30
|
-
export function useSubDeferred(signal, params, { async = false, defer, batch = false
|
|
47
|
+
export function useSubDeferred(signal, params, { async = false, defer, batch = false } = {}) {
|
|
31
48
|
const $signalRef = useRef();
|
|
32
|
-
const componentId = useId();
|
|
33
49
|
const scheduleUpdate = useScheduleUpdate();
|
|
34
50
|
const observerDefer = useDefer();
|
|
35
|
-
if (renderAttemptCleanup)
|
|
36
|
-
markCompatComponent(componentId);
|
|
37
51
|
if (batch)
|
|
38
52
|
promiseBatcher.activate();
|
|
39
53
|
defer ??= observerDefer ?? DEFAULT_DEFER;
|
|
@@ -52,8 +66,6 @@ export function useSubDeferred(signal, params, { async = false, defer, batch = f
|
|
|
52
66
|
// On resubscribe we keep rendering previous signal and refresh in background.
|
|
53
67
|
if (!hasPreviousSignal) {
|
|
54
68
|
promiseBatcher.add(promise);
|
|
55
|
-
if (renderAttemptCleanup)
|
|
56
|
-
registerRenderAttemptCleanup(signal, params);
|
|
57
69
|
}
|
|
58
70
|
else {
|
|
59
71
|
scheduleUpdate(promise);
|
|
@@ -71,8 +83,6 @@ export function useSubDeferred(signal, params, { async = false, defer, batch = f
|
|
|
71
83
|
scheduleUpdate(promise);
|
|
72
84
|
return $signalRef.current;
|
|
73
85
|
}
|
|
74
|
-
if (renderAttemptCleanup)
|
|
75
|
-
registerRenderAttemptCleanup(signal, params);
|
|
76
86
|
throw promise;
|
|
77
87
|
// 2. if it's a signal, we save it into ref to make sure it's not garbage collected while component exists
|
|
78
88
|
}
|
|
@@ -85,13 +95,10 @@ export function useSubDeferred(signal, params, { async = false, defer, batch = f
|
|
|
85
95
|
}
|
|
86
96
|
// classic version which initially throws promise for Suspense
|
|
87
97
|
// but if we get a promise second time, we return the last signal and wait for promise to resolve
|
|
88
|
-
export function useSubClassic(signal, params, { async = false, batch = false
|
|
98
|
+
export function useSubClassic(signal, params, { async = false, batch = false } = {}) {
|
|
89
99
|
const id = executionContextTracker.newHookId();
|
|
90
|
-
const componentId = useId();
|
|
91
100
|
const cache = useCache(undefined);
|
|
92
101
|
const scheduleUpdate = useScheduleUpdate();
|
|
93
|
-
if (renderAttemptCleanup)
|
|
94
|
-
markCompatComponent(componentId);
|
|
95
102
|
if (batch)
|
|
96
103
|
promiseBatcher.activate();
|
|
97
104
|
const promiseOrSignal = params != null ? runtimeSub(signal, params) : runtimeSub(signal);
|
|
@@ -104,8 +111,6 @@ export function useSubClassic(signal, params, { async = false, batch = false, re
|
|
|
104
111
|
// On resubscribe we keep rendering previous signal and refresh in background.
|
|
105
112
|
if (!hasPreviousSignal) {
|
|
106
113
|
promiseBatcher.add(promise);
|
|
107
|
-
if (renderAttemptCleanup)
|
|
108
|
-
registerRenderAttemptCleanup(signal, params);
|
|
109
114
|
}
|
|
110
115
|
else {
|
|
111
116
|
scheduleUpdate(promise);
|
|
@@ -126,8 +131,6 @@ export function useSubClassic(signal, params, { async = false, batch = false, re
|
|
|
126
131
|
scheduleUpdate(promise);
|
|
127
132
|
return;
|
|
128
133
|
}
|
|
129
|
-
if (renderAttemptCleanup)
|
|
130
|
-
registerRenderAttemptCleanup(signal, params);
|
|
131
134
|
// in regular mode we throw the promise to be caught by Suspense
|
|
132
135
|
// this way we guarantee that the signal with all the data
|
|
133
136
|
// will always be there when component is rendered
|
|
@@ -180,10 +183,3 @@ function isThenable(value) {
|
|
|
180
183
|
(typeof value === 'object' || typeof value === 'function') &&
|
|
181
184
|
typeof value.then === 'function';
|
|
182
185
|
}
|
|
183
|
-
function registerRenderAttemptCleanup(_signal, _params) {
|
|
184
|
-
// Legacy hooks don't build per-hook init objects like Racer.
|
|
185
|
-
// We still need a marker so trapRender can defer observer-shell cleanup
|
|
186
|
-
// only when a real attempt cleanup exists.
|
|
187
|
-
// This path must not arm suspense-gate keep-alive by itself.
|
|
188
|
-
renderAttemptDestroyer.armRenderAttemptCleanup();
|
|
189
|
-
}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import executionContextTracker from "./executionContextTracker.js";
|
|
2
|
-
import { useCache
|
|
3
|
-
import { markCompatComponent } from "./compatComponentRegistry.js";
|
|
2
|
+
import { useCache } from "./helpers.js";
|
|
4
3
|
import renderAttemptDestroyer from "./renderAttemptDestroyer.js";
|
|
5
4
|
const IN_FLIGHT_BY_KEY = new Map();
|
|
6
5
|
export default function useSuspendMemo(factory, deps) {
|
|
7
6
|
if (typeof factory !== 'function')
|
|
8
7
|
throw Error('useSuspendMemo() expects a factory function');
|
|
9
8
|
deps = normalizeDeps(deps);
|
|
10
|
-
const componentId = useId();
|
|
11
9
|
const cache = useCache(undefined);
|
|
12
10
|
const hookId = executionContextTracker.newHookId();
|
|
13
11
|
const cacheKey = `suspendMemo:${hookId}`;
|
|
@@ -24,7 +22,6 @@ export default function useSuspendMemo(factory, deps) {
|
|
|
24
22
|
if (entry.status === 'done')
|
|
25
23
|
return entry.value;
|
|
26
24
|
if (entry.status === 'pending') {
|
|
27
|
-
markCompatComponent(componentId);
|
|
28
25
|
renderAttemptDestroyer.armSuspenseGate();
|
|
29
26
|
throw entry.promise;
|
|
30
27
|
}
|
|
@@ -45,7 +42,6 @@ export default function useSuspendMemo(factory, deps) {
|
|
|
45
42
|
});
|
|
46
43
|
entry.status = 'pending';
|
|
47
44
|
entry.promise = promise;
|
|
48
|
-
markCompatComponent(componentId);
|
|
49
45
|
renderAttemptDestroyer.armSuspenseGate();
|
|
50
46
|
throw promise;
|
|
51
47
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "teamplay",
|
|
3
|
-
"version": "0.5.0-alpha.
|
|
3
|
+
"version": "0.5.0-alpha.16",
|
|
4
4
|
"description": "Full-stack signals ORM with multiplayer",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -134,5 +134,5 @@
|
|
|
134
134
|
]
|
|
135
135
|
},
|
|
136
136
|
"license": "MIT",
|
|
137
|
-
"gitHead": "
|
|
137
|
+
"gitHead": "a6f311fb793aeeba904b81416400e609ab597174"
|
|
138
138
|
}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
export declare function markCompatComponent(componentId: string | undefined): void;
|
|
2
|
-
export declare function unmarkCompatComponent(componentId: string | undefined): void;
|
|
3
|
-
export declare function isCompatComponent(componentId: string | undefined): boolean;
|
|
4
|
-
export declare function __resetCompatComponentRegistryForTests(): void;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
const compatComponentIds = new Set();
|
|
2
|
-
export function markCompatComponent(componentId) {
|
|
3
|
-
if (!componentId)
|
|
4
|
-
return;
|
|
5
|
-
compatComponentIds.add(componentId);
|
|
6
|
-
}
|
|
7
|
-
export function unmarkCompatComponent(componentId) {
|
|
8
|
-
if (!componentId)
|
|
9
|
-
return;
|
|
10
|
-
compatComponentIds.delete(componentId);
|
|
11
|
-
}
|
|
12
|
-
export function isCompatComponent(componentId) {
|
|
13
|
-
if (!componentId)
|
|
14
|
-
return false;
|
|
15
|
-
return compatComponentIds.has(componentId);
|
|
16
|
-
}
|
|
17
|
-
export function __resetCompatComponentRegistryForTests() {
|
|
18
|
-
compatComponentIds.clear();
|
|
19
|
-
}
|