jazz-tools 0.20.1 → 0.20.2
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/.turbo/turbo-build.log +48 -48
- package/CHANGELOG.md +10 -0
- package/dist/{chunk-2OPP7KWV.js → chunk-Q5RNSSUM.js} +121 -22
- package/dist/chunk-Q5RNSSUM.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/inspector/{chunk-MCTB5ZJC.js → chunk-6JPVMI3V.js} +302 -182
- package/dist/inspector/chunk-6JPVMI3V.js.map +1 -0
- package/dist/inspector/{custom-element-5YWVZBWA.js → custom-element-PWRX4VCA.js} +1337 -206
- package/dist/inspector/custom-element-PWRX4VCA.js.map +1 -0
- package/dist/inspector/in-app.d.ts +1 -0
- package/dist/inspector/in-app.d.ts.map +1 -1
- package/dist/inspector/index.d.ts +1 -0
- package/dist/inspector/index.d.ts.map +1 -1
- package/dist/inspector/index.js +1044 -17
- package/dist/inspector/index.js.map +1 -1
- package/dist/inspector/pages/home.d.ts +4 -1
- package/dist/inspector/pages/home.d.ts.map +1 -1
- package/dist/inspector/pages/performance/PerformancePage.d.ts +7 -0
- package/dist/inspector/pages/performance/PerformancePage.d.ts.map +1 -0
- package/dist/inspector/pages/performance/SubscriptionDetailPanel.d.ts +8 -0
- package/dist/inspector/pages/performance/SubscriptionDetailPanel.d.ts.map +1 -0
- package/dist/inspector/pages/performance/SubscriptionRow.d.ts +11 -0
- package/dist/inspector/pages/performance/SubscriptionRow.d.ts.map +1 -0
- package/dist/inspector/pages/performance/Timeline.d.ts +12 -0
- package/dist/inspector/pages/performance/Timeline.d.ts.map +1 -0
- package/dist/inspector/pages/performance/helpers.d.ts +5 -0
- package/dist/inspector/pages/performance/helpers.d.ts.map +1 -0
- package/dist/inspector/pages/performance/index.d.ts +3 -0
- package/dist/inspector/pages/performance/index.d.ts.map +1 -0
- package/dist/inspector/pages/performance/types.d.ts +13 -0
- package/dist/inspector/pages/performance/types.d.ts.map +1 -0
- package/dist/inspector/pages/performance/usePerformanceEntries.d.ts +3 -0
- package/dist/inspector/pages/performance/usePerformanceEntries.d.ts.map +1 -0
- package/dist/inspector/register-custom-element.js +3 -1
- package/dist/inspector/register-custom-element.js.map +1 -1
- package/dist/inspector/standalone.js +1 -1
- package/dist/inspector/tests/pages/performance/PerformancePage.test.d.ts +2 -0
- package/dist/inspector/tests/pages/performance/PerformancePage.test.d.ts.map +1 -0
- package/dist/inspector/tests/pages/performance/SubscriptionDetailPanel.test.d.ts +2 -0
- package/dist/inspector/tests/pages/performance/SubscriptionDetailPanel.test.d.ts.map +1 -0
- package/dist/inspector/tests/pages/performance/SubscriptionRow.test.d.ts +2 -0
- package/dist/inspector/tests/pages/performance/SubscriptionRow.test.d.ts.map +1 -0
- package/dist/inspector/tests/pages/performance/Timeline.test.d.ts +2 -0
- package/dist/inspector/tests/pages/performance/Timeline.test.d.ts.map +1 -0
- package/dist/inspector/tests/pages/performance/helpers.test.d.ts +2 -0
- package/dist/inspector/tests/pages/performance/helpers.test.d.ts.map +1 -0
- package/dist/inspector/viewer/delete-local-data.d.ts.map +1 -1
- package/dist/inspector/viewer/header.d.ts +4 -2
- package/dist/inspector/viewer/header.d.ts.map +1 -1
- package/dist/inspector/viewer/page-stack.d.ts +3 -1
- package/dist/inspector/viewer/page-stack.d.ts.map +1 -1
- package/dist/react-core/hooks.d.ts +2 -2
- package/dist/react-core/hooks.d.ts.map +1 -1
- package/dist/react-core/index.js +50 -18
- package/dist/react-core/index.js.map +1 -1
- package/dist/react-core/subscription-provider.d.ts.map +1 -1
- package/dist/react-native-core/media/image.d.ts +1 -1
- package/dist/svelte/jazz.class.svelte.d.ts.map +1 -1
- package/dist/svelte/jazz.class.svelte.js +27 -22
- package/dist/testing.js +1 -1
- package/dist/tools/coValues/interfaces.d.ts.map +1 -1
- package/dist/tools/exports.d.ts +1 -1
- package/dist/tools/exports.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/runtimeConverters/coValueSchemaTransformation.d.ts.map +1 -1
- package/dist/tools/subscribe/SubscriptionCache.d.ts +2 -2
- package/dist/tools/subscribe/SubscriptionCache.d.ts.map +1 -1
- package/dist/tools/subscribe/SubscriptionScope.d.ts +19 -12
- package/dist/tools/subscribe/SubscriptionScope.d.ts.map +1 -1
- package/dist/tools/subscribe/errorReporting.d.ts +6 -0
- package/dist/tools/subscribe/errorReporting.d.ts.map +1 -1
- package/dist/tools/subscribe/index.d.ts +4 -4
- package/dist/tools/subscribe/index.d.ts.map +1 -1
- package/dist/tools/subscribe/types.d.ts +48 -3
- package/dist/tools/subscribe/types.d.ts.map +1 -1
- package/dist/tools/subscribe/utils.d.ts +1 -1
- package/dist/tools/subscribe/utils.d.ts.map +1 -1
- package/dist/tools/tests/SubscriptionScope.performance.test.d.ts +2 -0
- package/dist/tools/tests/SubscriptionScope.performance.test.d.ts.map +1 -0
- package/package.json +4 -4
- package/src/inspector/in-app.tsx +41 -3
- package/src/inspector/index.tsx +5 -1
- package/src/inspector/pages/home.tsx +26 -3
- package/src/inspector/pages/performance/PerformancePage.tsx +215 -0
- package/src/inspector/pages/performance/SubscriptionDetailPanel.tsx +182 -0
- package/src/inspector/pages/performance/SubscriptionRow.tsx +242 -0
- package/src/inspector/pages/performance/Timeline.tsx +513 -0
- package/src/inspector/pages/performance/helpers.ts +70 -0
- package/src/inspector/pages/performance/index.ts +2 -0
- package/src/inspector/pages/performance/types.ts +12 -0
- package/src/inspector/pages/performance/usePerformanceEntries.ts +53 -0
- package/src/inspector/register-custom-element.ts +3 -0
- package/src/inspector/tests/pages/performance/PerformancePage.test.tsx +83 -0
- package/src/inspector/tests/pages/performance/SubscriptionDetailPanel.test.tsx +68 -0
- package/src/inspector/tests/pages/performance/SubscriptionRow.test.tsx +93 -0
- package/src/inspector/tests/pages/performance/Timeline.test.tsx +57 -0
- package/src/inspector/tests/pages/performance/helpers.test.ts +91 -0
- package/src/inspector/viewer/delete-local-data.tsx +24 -5
- package/src/inspector/viewer/header.tsx +96 -17
- package/src/inspector/viewer/page-stack.tsx +22 -18
- package/src/react-core/hooks.ts +34 -4
- package/src/react-core/subscription-provider.tsx +17 -8
- package/src/svelte/jazz.class.svelte.ts +51 -33
- package/src/tools/coValues/interfaces.ts +3 -0
- package/src/tools/exports.ts +1 -0
- package/src/tools/implementation/zodSchema/runtimeConverters/coValueSchemaTransformation.ts +13 -0
- package/src/tools/subscribe/SubscriptionCache.ts +6 -4
- package/src/tools/subscribe/SubscriptionScope.ts +141 -23
- package/src/tools/subscribe/errorReporting.ts +1 -1
- package/src/tools/subscribe/index.ts +1 -1
- package/src/tools/subscribe/types.ts +62 -9
- package/src/tools/subscribe/utils.ts +2 -2
- package/src/tools/tests/SubscriptionScope.performance.test.ts +149 -0
- package/dist/chunk-2OPP7KWV.js.map +0 -1
- package/dist/inspector/chunk-MCTB5ZJC.js.map +0 -1
- package/dist/inspector/custom-element-5YWVZBWA.js.map +0 -1
package/src/react-core/hooks.ts
CHANGED
|
@@ -101,6 +101,7 @@ export function useCoValueSubscription<
|
|
|
101
101
|
resolve?: ResolveQueryStrict<S, R>;
|
|
102
102
|
unstable_branch?: BranchDefinition;
|
|
103
103
|
},
|
|
104
|
+
source?: string,
|
|
104
105
|
): CoValueSubscription<S, R> | null {
|
|
105
106
|
const resolve = getResolveQuery(Schema, options?.resolve);
|
|
106
107
|
const subscriptions = useCoValueSubscriptions(
|
|
@@ -108,6 +109,7 @@ export function useCoValueSubscription<
|
|
|
108
109
|
[id],
|
|
109
110
|
resolve,
|
|
110
111
|
options?.unstable_branch,
|
|
112
|
+
source,
|
|
111
113
|
);
|
|
112
114
|
return (subscriptions[0] ?? null) as CoValueSubscription<S, R> | null;
|
|
113
115
|
}
|
|
@@ -140,6 +142,7 @@ function useCoValueSubscriptions(
|
|
|
140
142
|
ids: readonly (string | undefined | null)[],
|
|
141
143
|
resolve: ResolveQuery<any>,
|
|
142
144
|
branch?: BranchDefinition,
|
|
145
|
+
source?: string,
|
|
143
146
|
): (SubscriptionScope<CoValue> | null)[] {
|
|
144
147
|
const contextManager = useJazzContext();
|
|
145
148
|
const agent = useAgent();
|
|
@@ -169,6 +172,9 @@ function useCoValueSubscriptions(
|
|
|
169
172
|
subscription.callerStack = callerStack;
|
|
170
173
|
}
|
|
171
174
|
|
|
175
|
+
// Track performance for root subscriptions
|
|
176
|
+
subscription.trackLoadingPerformance(source ?? "unknown");
|
|
177
|
+
|
|
172
178
|
return subscription;
|
|
173
179
|
});
|
|
174
180
|
|
|
@@ -428,7 +434,12 @@ export function useCoState<
|
|
|
428
434
|
},
|
|
429
435
|
): TSelectorReturn {
|
|
430
436
|
useImportCoValueContent(id, options?.preloaded);
|
|
431
|
-
const subscription = useCoValueSubscription(
|
|
437
|
+
const subscription = useCoValueSubscription(
|
|
438
|
+
Schema,
|
|
439
|
+
id,
|
|
440
|
+
options,
|
|
441
|
+
`useCoState`,
|
|
442
|
+
);
|
|
432
443
|
return useSubscriptionSelector(subscription, options);
|
|
433
444
|
}
|
|
434
445
|
|
|
@@ -471,7 +482,12 @@ export function useSuspenseCoState<
|
|
|
471
482
|
): TSelectorReturn {
|
|
472
483
|
useImportCoValueContent(id, options?.preloaded);
|
|
473
484
|
|
|
474
|
-
const subscription = useCoValueSubscription(
|
|
485
|
+
const subscription = useCoValueSubscription(
|
|
486
|
+
Schema,
|
|
487
|
+
id,
|
|
488
|
+
options,
|
|
489
|
+
"useSuspenseCoState",
|
|
490
|
+
);
|
|
475
491
|
|
|
476
492
|
if (!subscription) {
|
|
477
493
|
throw new Error("Subscription not found");
|
|
@@ -534,6 +550,7 @@ export function useAccountSubscription<
|
|
|
534
550
|
resolve?: ResolveQueryStrict<S, R>;
|
|
535
551
|
unstable_branch?: BranchDefinition;
|
|
536
552
|
},
|
|
553
|
+
source?: string,
|
|
537
554
|
) {
|
|
538
555
|
const contextManager = useJazzContext();
|
|
539
556
|
|
|
@@ -570,6 +587,9 @@ export function useAccountSubscription<
|
|
|
570
587
|
subscription.callerStack = callerStack;
|
|
571
588
|
}
|
|
572
589
|
|
|
590
|
+
// Track performance for root subscriptions
|
|
591
|
+
subscription.trackLoadingPerformance(source ?? "unknown");
|
|
592
|
+
|
|
573
593
|
return {
|
|
574
594
|
subscription,
|
|
575
595
|
contextManager,
|
|
@@ -727,7 +747,11 @@ export function useAccount<
|
|
|
727
747
|
unstable_branch?: BranchDefinition;
|
|
728
748
|
},
|
|
729
749
|
): TSelectorReturn {
|
|
730
|
-
const subscription = useAccountSubscription(
|
|
750
|
+
const subscription = useAccountSubscription(
|
|
751
|
+
AccountSchema,
|
|
752
|
+
options,
|
|
753
|
+
"useAccount",
|
|
754
|
+
);
|
|
731
755
|
return useSubscriptionSelector(subscription, options);
|
|
732
756
|
}
|
|
733
757
|
|
|
@@ -765,7 +789,11 @@ export function useSuspenseAccount<
|
|
|
765
789
|
unstable_branch?: BranchDefinition;
|
|
766
790
|
},
|
|
767
791
|
): TSelectorReturn {
|
|
768
|
-
const subscription = useAccountSubscription(
|
|
792
|
+
const subscription = useAccountSubscription(
|
|
793
|
+
AccountSchema,
|
|
794
|
+
options,
|
|
795
|
+
"useSuspenseAccount",
|
|
796
|
+
);
|
|
769
797
|
|
|
770
798
|
if (!subscription) {
|
|
771
799
|
throw new Error(
|
|
@@ -1054,6 +1082,7 @@ export function useSuspenseCoStates<
|
|
|
1054
1082
|
ids,
|
|
1055
1083
|
resolve,
|
|
1056
1084
|
options?.unstable_branch,
|
|
1085
|
+
"useSuspenseCoStates",
|
|
1057
1086
|
) as SubscriptionScope<CoValue>[];
|
|
1058
1087
|
useSuspendUntilLoaded(subscriptionScopes);
|
|
1059
1088
|
return useSubscriptionsSelector(subscriptionScopes, options);
|
|
@@ -1123,6 +1152,7 @@ export function useCoStates<
|
|
|
1123
1152
|
ids,
|
|
1124
1153
|
resolve,
|
|
1125
1154
|
options?.unstable_branch,
|
|
1155
|
+
"useCoStates",
|
|
1126
1156
|
) as SubscriptionScope<CoValue>[];
|
|
1127
1157
|
return useSubscriptionsSelector(subscriptionScopes, options);
|
|
1128
1158
|
}
|
|
@@ -39,10 +39,15 @@ export function createCoValueSubscriptionContext<
|
|
|
39
39
|
loadingFallback?: React.ReactNode;
|
|
40
40
|
unavailableFallback?: React.ReactNode;
|
|
41
41
|
}>) => {
|
|
42
|
-
const subscription = useCoValueSubscription(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
const subscription = useCoValueSubscription(
|
|
43
|
+
schema,
|
|
44
|
+
id,
|
|
45
|
+
{
|
|
46
|
+
...options,
|
|
47
|
+
resolve: resolve,
|
|
48
|
+
},
|
|
49
|
+
"CoValueSubscriptionProvider",
|
|
50
|
+
);
|
|
46
51
|
|
|
47
52
|
const loadState = useSubscriptionSelector(subscription, {
|
|
48
53
|
select: (value) => value.$jazz.loadingState,
|
|
@@ -104,10 +109,14 @@ export function createAccountSubscriptionContext<
|
|
|
104
109
|
loadingFallback?: React.ReactNode;
|
|
105
110
|
unavailableFallback?: React.ReactNode;
|
|
106
111
|
}>) => {
|
|
107
|
-
const subscription = useAccountSubscription(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
112
|
+
const subscription = useAccountSubscription(
|
|
113
|
+
schema,
|
|
114
|
+
{
|
|
115
|
+
...options,
|
|
116
|
+
resolve: resolve,
|
|
117
|
+
},
|
|
118
|
+
"AccountSubscriptionProvider",
|
|
119
|
+
);
|
|
111
120
|
|
|
112
121
|
const loadState = useSubscriptionSelector(subscription, {
|
|
113
122
|
select: (value) => value.$jazz.loadingState,
|
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
AnyAccountSchema,
|
|
5
5
|
BranchDefinition,
|
|
6
6
|
CoValue,
|
|
7
|
+
CoValueClass,
|
|
7
8
|
CoValueClassOrSchema,
|
|
8
9
|
CoValueFromRaw,
|
|
9
10
|
SchemaResolveQuery,
|
|
@@ -15,10 +16,11 @@ import type {
|
|
|
15
16
|
ResolveQueryStrict,
|
|
16
17
|
} from "jazz-tools";
|
|
17
18
|
import {
|
|
19
|
+
captureStack,
|
|
18
20
|
coValueClassFromCoValueClassOrSchema,
|
|
19
|
-
subscribeToCoValue,
|
|
20
21
|
CoValueLoadingState,
|
|
21
22
|
getUnloadedCoValueWithoutId,
|
|
23
|
+
SubscriptionScope,
|
|
22
24
|
} from "jazz-tools";
|
|
23
25
|
import { untrack } from "svelte";
|
|
24
26
|
import { createSubscriber } from "svelte/reactivity";
|
|
@@ -69,6 +71,7 @@ export class CoState<
|
|
|
69
71
|
id: CoStateId | (() => CoStateId),
|
|
70
72
|
options?: CoStateOptions<V, R> | (() => CoStateOptions<V, R>),
|
|
71
73
|
) {
|
|
74
|
+
const callerStack = captureStack();
|
|
72
75
|
this.#id = $derived.by(typeof id === "function" ? id : () => id);
|
|
73
76
|
this.#options = $derived.by(
|
|
74
77
|
typeof options === "function" ? options : () => options,
|
|
@@ -89,29 +92,36 @@ export class CoState<
|
|
|
89
92
|
getUnloadedCoValueWithoutId(CoValueLoadingState.UNAVAILABLE),
|
|
90
93
|
);
|
|
91
94
|
}
|
|
95
|
+
|
|
92
96
|
const agent = "me" in ctx ? ctx.me : ctx.guest;
|
|
97
|
+
const node = "node" in agent ? agent.node : agent.$jazz.localNode;
|
|
93
98
|
const resolve = getResolveQuery(Schema, options?.resolve);
|
|
99
|
+
const cls = coValueClassFromCoValueClassOrSchema(Schema) as CoValueClass<Loaded<V, R>>;
|
|
94
100
|
|
|
95
|
-
const
|
|
96
|
-
|
|
101
|
+
const subscriptionScope = new SubscriptionScope<Loaded<V, R>>(
|
|
102
|
+
node,
|
|
103
|
+
resolve,
|
|
97
104
|
id,
|
|
98
|
-
{
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
onError: (value) => {
|
|
103
|
-
this.update(value);
|
|
104
|
-
},
|
|
105
|
-
syncResolution: true,
|
|
106
|
-
unstable_branch: options?.unstable_branch,
|
|
107
|
-
},
|
|
108
|
-
(value) => {
|
|
109
|
-
this.update(value as Loaded<V, R>);
|
|
110
|
-
},
|
|
105
|
+
{ ref: cls, optional: false },
|
|
106
|
+
false, // skipRetry
|
|
107
|
+
false, // bestEffortResolution
|
|
108
|
+
options?.unstable_branch,
|
|
111
109
|
);
|
|
112
110
|
|
|
111
|
+
subscriptionScope.callerStack = callerStack;
|
|
112
|
+
|
|
113
|
+
// Track performance for Svelte subscriptions
|
|
114
|
+
subscriptionScope.trackLoadingPerformance("CoState");
|
|
115
|
+
|
|
116
|
+
subscriptionScope.subscribe(() => {
|
|
117
|
+
const value = subscriptionScope.getCurrentValue();
|
|
118
|
+
this.update(value);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
this.update(subscriptionScope.getCurrentValue());
|
|
122
|
+
|
|
113
123
|
return () => {
|
|
114
|
-
|
|
124
|
+
subscriptionScope.destroy();
|
|
115
125
|
};
|
|
116
126
|
});
|
|
117
127
|
});
|
|
@@ -150,6 +160,7 @@ export class AccountCoState<
|
|
|
150
160
|
Schema: A,
|
|
151
161
|
options?: CoStateOptions<A, R> | (() => CoStateOptions<A, R>),
|
|
152
162
|
) {
|
|
163
|
+
const callerStack = captureStack();
|
|
153
164
|
this.#options = $derived.by(
|
|
154
165
|
typeof options === "function" ? options : () => options,
|
|
155
166
|
);
|
|
@@ -170,27 +181,34 @@ export class AccountCoState<
|
|
|
170
181
|
}
|
|
171
182
|
|
|
172
183
|
const me = ctx.me;
|
|
184
|
+
const node = me.$jazz.localNode;
|
|
173
185
|
const resolve = getResolveQuery(Schema, options?.resolve);
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
186
|
+
const cls = coValueClassFromCoValueClassOrSchema(Schema) as CoValueClass<Loaded<A, R>>;
|
|
187
|
+
|
|
188
|
+
const subscriptionScope = new SubscriptionScope<Loaded<A, R>>(
|
|
189
|
+
node,
|
|
190
|
+
resolve,
|
|
177
191
|
me.$jazz.id,
|
|
178
|
-
{
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
this.update(value);
|
|
183
|
-
},
|
|
184
|
-
syncResolution: true,
|
|
185
|
-
unstable_branch: options?.unstable_branch,
|
|
186
|
-
},
|
|
187
|
-
(value) => {
|
|
188
|
-
this.update(value as Loaded<A, R>);
|
|
189
|
-
},
|
|
192
|
+
{ ref: cls, optional: false },
|
|
193
|
+
false, // skipRetry
|
|
194
|
+
false, // bestEffortResolution
|
|
195
|
+
options?.unstable_branch,
|
|
190
196
|
);
|
|
191
197
|
|
|
198
|
+
subscriptionScope.callerStack = callerStack;
|
|
199
|
+
|
|
200
|
+
// Track performance for Svelte subscriptions
|
|
201
|
+
subscriptionScope.trackLoadingPerformance("AccountCoState");
|
|
202
|
+
|
|
203
|
+
subscriptionScope.subscribe(() => {
|
|
204
|
+
const value = subscriptionScope.getCurrentValue();
|
|
205
|
+
this.update(value);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
this.update(subscriptionScope.getCurrentValue());
|
|
209
|
+
|
|
192
210
|
return () => {
|
|
193
|
-
|
|
211
|
+
subscriptionScope.destroy();
|
|
194
212
|
};
|
|
195
213
|
});
|
|
196
214
|
});
|
package/src/tools/exports.ts
CHANGED
|
@@ -39,6 +39,19 @@ import {
|
|
|
39
39
|
schemaFieldToCoFieldDef,
|
|
40
40
|
} from "./schemaFieldToCoFieldDef.js";
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* A platform agnostic way to check if we're in development mode
|
|
44
|
+
*
|
|
45
|
+
* Works in Node.js and bundled code, falls back to false if process is not available
|
|
46
|
+
*/
|
|
47
|
+
const isDev = (function () {
|
|
48
|
+
try {
|
|
49
|
+
return process.env.NODE_ENV === "development";
|
|
50
|
+
} catch {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
})();
|
|
54
|
+
|
|
42
55
|
// Note: if you're editing this function, edit the `isAnyCoValueSchema`
|
|
43
56
|
// function in `zodReExport.ts` as well
|
|
44
57
|
export function isAnyCoValueSchema(
|
|
@@ -2,6 +2,7 @@ import { LocalNode } from "cojson";
|
|
|
2
2
|
import type {
|
|
3
3
|
CoValue,
|
|
4
4
|
CoValueClassOrSchema,
|
|
5
|
+
Loaded,
|
|
5
6
|
RefEncoded,
|
|
6
7
|
RefsToResolve,
|
|
7
8
|
ResolveQuery,
|
|
@@ -188,7 +189,7 @@ export class SubscriptionCache {
|
|
|
188
189
|
skipRetry?: boolean,
|
|
189
190
|
bestEffortResolution?: boolean,
|
|
190
191
|
branch?: BranchDefinition,
|
|
191
|
-
): SubscriptionScope<
|
|
192
|
+
): SubscriptionScope<Loaded<S, ResolveQuery<S>>> {
|
|
192
193
|
// Handle undefined/null id case
|
|
193
194
|
if (!id) {
|
|
194
195
|
throw new Error("Cannot create subscription with undefined or null id");
|
|
@@ -201,7 +202,9 @@ export class SubscriptionCache {
|
|
|
201
202
|
// Found existing entry - cancel any pending cleanup since we're reusing it
|
|
202
203
|
this.cancelCleanup(matchingEntry);
|
|
203
204
|
|
|
204
|
-
return matchingEntry.subscriptionScope as SubscriptionScope<
|
|
205
|
+
return matchingEntry.subscriptionScope as SubscriptionScope<
|
|
206
|
+
Loaded<S, ResolveQuery<S>>
|
|
207
|
+
>;
|
|
205
208
|
}
|
|
206
209
|
|
|
207
210
|
// Create new SubscriptionScope
|
|
@@ -212,9 +215,8 @@ export class SubscriptionCache {
|
|
|
212
215
|
};
|
|
213
216
|
|
|
214
217
|
// Create new SubscriptionScope with all required parameters
|
|
215
|
-
const subscriptionScope = new SubscriptionScope<
|
|
218
|
+
const subscriptionScope = new SubscriptionScope<Loaded<S, ResolveQuery<S>>>(
|
|
216
219
|
node,
|
|
217
|
-
// @ts-expect-error the SubscriptionScope is too generic for TS to infer its instances are CoValues
|
|
218
220
|
resolve,
|
|
219
221
|
id,
|
|
220
222
|
refEncoded,
|
|
@@ -4,7 +4,6 @@ import {
|
|
|
4
4
|
CoList,
|
|
5
5
|
CoMap,
|
|
6
6
|
type CoValue,
|
|
7
|
-
type ID,
|
|
8
7
|
MaybeLoaded,
|
|
9
8
|
NotLoaded,
|
|
10
9
|
type RefEncoded,
|
|
@@ -23,6 +22,7 @@ import {
|
|
|
23
22
|
} from "./JazzError.js";
|
|
24
23
|
import type {
|
|
25
24
|
BranchDefinition,
|
|
25
|
+
SubscriptionPerformanceDetail,
|
|
26
26
|
SubscriptionValue,
|
|
27
27
|
SubscriptionValueLoading,
|
|
28
28
|
} from "./types.js";
|
|
@@ -30,6 +30,7 @@ import { CoValueLoadingState, NotLoadedCoValueState } from "./types.js";
|
|
|
30
30
|
import {
|
|
31
31
|
captureError,
|
|
32
32
|
isCustomErrorReportingEnabled,
|
|
33
|
+
isDev,
|
|
33
34
|
} from "./errorReporting.js";
|
|
34
35
|
import {
|
|
35
36
|
createCoValue,
|
|
@@ -40,11 +41,21 @@ import {
|
|
|
40
41
|
} from "./utils.js";
|
|
41
42
|
|
|
42
43
|
export class SubscriptionScope<D extends CoValue> {
|
|
44
|
+
static isProfilingEnabled = isDev;
|
|
45
|
+
|
|
46
|
+
static setProfilingEnabled(enabled: boolean) {
|
|
47
|
+
this.isProfilingEnabled = enabled;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
static enableProfiling() {
|
|
51
|
+
this.isProfilingEnabled = true;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private performanceUuid: string | undefined;
|
|
55
|
+
private performanceSource: string | undefined;
|
|
56
|
+
|
|
43
57
|
childNodes = new Map<string, SubscriptionScope<CoValue>>();
|
|
44
|
-
childValues: Map<string, SubscriptionValue<
|
|
45
|
-
string,
|
|
46
|
-
SubscriptionValue<D, any>
|
|
47
|
-
>();
|
|
58
|
+
childValues: Map<string, SubscriptionValue<CoValue>> = new Map();
|
|
48
59
|
/**
|
|
49
60
|
* Explicitly-loaded child ids that are unloaded
|
|
50
61
|
*/
|
|
@@ -53,7 +64,7 @@ export class SubscriptionScope<D extends CoValue> {
|
|
|
53
64
|
* Autoloaded child ids that are unloaded
|
|
54
65
|
*/
|
|
55
66
|
private pendingAutoloadedChildren: Set<string> = new Set();
|
|
56
|
-
value: SubscriptionValue<D
|
|
67
|
+
value: SubscriptionValue<D> | SubscriptionValueLoading;
|
|
57
68
|
private childErrors: Map<string, JazzError> = new Map();
|
|
58
69
|
private validationErrors: Map<string, JazzError> = new Map();
|
|
59
70
|
errorFromChildren: JazzError | undefined;
|
|
@@ -81,9 +92,9 @@ export class SubscriptionScope<D extends CoValue> {
|
|
|
81
92
|
|
|
82
93
|
constructor(
|
|
83
94
|
public node: LocalNode,
|
|
84
|
-
resolve: RefsToResolve<
|
|
85
|
-
public id:
|
|
86
|
-
public schema: RefEncoded<
|
|
95
|
+
resolve: RefsToResolve<any>,
|
|
96
|
+
public id: string,
|
|
97
|
+
public schema: RefEncoded<CoValue>,
|
|
87
98
|
public skipRetry = false,
|
|
88
99
|
public bestEffortResolution = false,
|
|
89
100
|
public unstable_branch?: BranchDefinition,
|
|
@@ -141,7 +152,110 @@ export class SubscriptionScope<D extends CoValue> {
|
|
|
141
152
|
);
|
|
142
153
|
}
|
|
143
154
|
|
|
144
|
-
|
|
155
|
+
trackLoadingPerformance(source: string) {
|
|
156
|
+
if (!SubscriptionScope.isProfilingEnabled) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Already tracking this subscription
|
|
161
|
+
if (this.performanceUuid) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const currentState = this.getCurrentRawValue();
|
|
166
|
+
|
|
167
|
+
this.performanceUuid = crypto.randomUUID();
|
|
168
|
+
this.performanceSource = source;
|
|
169
|
+
|
|
170
|
+
const detail: SubscriptionPerformanceDetail = {
|
|
171
|
+
type: "jazz-subscription",
|
|
172
|
+
uuid: this.performanceUuid,
|
|
173
|
+
id: this.id,
|
|
174
|
+
source,
|
|
175
|
+
resolve: this.resolve,
|
|
176
|
+
status: "pending",
|
|
177
|
+
startTime: performance.now(),
|
|
178
|
+
callerStack: this.callerStack?.stack,
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
performance.mark(`jazz.subscription.start:${this.performanceUuid}`, {
|
|
182
|
+
detail,
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
if (currentState !== CoValueLoadingState.LOADING) {
|
|
186
|
+
this.emitLoadingComplete(currentState);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Subscribe to get notified when loading completes
|
|
191
|
+
const unsubscribe = this.subscribe(() => {
|
|
192
|
+
const rawValue = this.getCurrentRawValue();
|
|
193
|
+
|
|
194
|
+
if (rawValue === CoValueLoadingState.LOADING) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
this.emitLoadingComplete(rawValue);
|
|
199
|
+
unsubscribe();
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
private emitLoadingComplete(rawValue: D | NotLoadedCoValueState) {
|
|
204
|
+
if (!this.performanceUuid) return;
|
|
205
|
+
|
|
206
|
+
const isError = typeof rawValue === "string";
|
|
207
|
+
const endTime = performance.now();
|
|
208
|
+
|
|
209
|
+
let errorType: SubscriptionPerformanceDetail["errorType"];
|
|
210
|
+
if (isError) {
|
|
211
|
+
if (
|
|
212
|
+
rawValue === CoValueLoadingState.UNAVAILABLE ||
|
|
213
|
+
rawValue === CoValueLoadingState.UNAUTHORIZED ||
|
|
214
|
+
rawValue === CoValueLoadingState.DELETED
|
|
215
|
+
) {
|
|
216
|
+
errorType = rawValue;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const detail: SubscriptionPerformanceDetail = {
|
|
221
|
+
type: "jazz-subscription",
|
|
222
|
+
uuid: this.performanceUuid,
|
|
223
|
+
id: this.id,
|
|
224
|
+
source: this.performanceSource ?? "unknown",
|
|
225
|
+
resolve: this.resolve,
|
|
226
|
+
status: isError ? "error" : "loaded",
|
|
227
|
+
startTime: 0, // Will be calculated from measure
|
|
228
|
+
endTime,
|
|
229
|
+
errorType,
|
|
230
|
+
devtools: {
|
|
231
|
+
track: "Jazz 🎶",
|
|
232
|
+
properties: [
|
|
233
|
+
["id", this.id],
|
|
234
|
+
["source", this.performanceSource ?? "unknown"],
|
|
235
|
+
],
|
|
236
|
+
tooltipText: this.getCreationStackLines(false),
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
performance.mark(`jazz.subscription.end:${this.performanceUuid}`, {
|
|
241
|
+
detail,
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
try {
|
|
245
|
+
performance.measure(
|
|
246
|
+
`${detail.source}(${this.id}, ${JSON.stringify(this.resolve)})`,
|
|
247
|
+
{
|
|
248
|
+
start: `jazz.subscription.start:${this.performanceUuid}`,
|
|
249
|
+
end: `jazz.subscription.end:${this.performanceUuid}`,
|
|
250
|
+
detail,
|
|
251
|
+
},
|
|
252
|
+
);
|
|
253
|
+
} catch {
|
|
254
|
+
// Marks may have been cleared
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
updateValue(value: SubscriptionValue<D>) {
|
|
145
259
|
this.value = value;
|
|
146
260
|
|
|
147
261
|
// Flags that the value has changed and we need to trigger an update
|
|
@@ -285,7 +399,7 @@ export class SubscriptionScope<D extends CoValue> {
|
|
|
285
399
|
|
|
286
400
|
handleChildUpdate(
|
|
287
401
|
id: string,
|
|
288
|
-
value: SubscriptionValue<
|
|
402
|
+
value: SubscriptionValue<CoValue> | SubscriptionValueLoading,
|
|
289
403
|
key?: string,
|
|
290
404
|
) {
|
|
291
405
|
if (value.type === CoValueLoadingState.LOADING) {
|
|
@@ -469,7 +583,7 @@ export class SubscriptionScope<D extends CoValue> {
|
|
|
469
583
|
return CoValueLoadingState.LOADING;
|
|
470
584
|
}
|
|
471
585
|
|
|
472
|
-
private getCreationStackLines() {
|
|
586
|
+
private getCreationStackLines(fullFrame: boolean = true) {
|
|
473
587
|
const stack = this.callerStack?.stack;
|
|
474
588
|
|
|
475
589
|
if (!stack) {
|
|
@@ -492,6 +606,10 @@ export class SubscriptionScope<D extends CoValue> {
|
|
|
492
606
|
(result += "Subscription created "), (result += creationAppFrame.trim());
|
|
493
607
|
}
|
|
494
608
|
|
|
609
|
+
if (!fullFrame) {
|
|
610
|
+
return result;
|
|
611
|
+
}
|
|
612
|
+
|
|
495
613
|
result += "\nFull subscription creation stack:";
|
|
496
614
|
for (const line of creationStackLines.slice(0, 8)) {
|
|
497
615
|
result += "\n " + line.trim();
|
|
@@ -555,7 +673,7 @@ export class SubscriptionScope<D extends CoValue> {
|
|
|
555
673
|
this.dirty = false;
|
|
556
674
|
}
|
|
557
675
|
|
|
558
|
-
subscribers = new Set<(value: SubscriptionValue<D
|
|
676
|
+
subscribers = new Set<(value: SubscriptionValue<D>) => void>();
|
|
559
677
|
subscriberChangeCallbacks = new Set<(count: number) => void>();
|
|
560
678
|
|
|
561
679
|
/**
|
|
@@ -578,7 +696,7 @@ export class SubscriptionScope<D extends CoValue> {
|
|
|
578
696
|
});
|
|
579
697
|
}
|
|
580
698
|
|
|
581
|
-
subscribe(listener: (value: SubscriptionValue<D
|
|
699
|
+
subscribe(listener: (value: SubscriptionValue<D>) => void) {
|
|
582
700
|
this.subscribers.add(listener);
|
|
583
701
|
this.notifySubscriberChange();
|
|
584
702
|
|
|
@@ -588,7 +706,7 @@ export class SubscriptionScope<D extends CoValue> {
|
|
|
588
706
|
};
|
|
589
707
|
}
|
|
590
708
|
|
|
591
|
-
setListener(listener: (value: SubscriptionValue<D
|
|
709
|
+
setListener(listener: (value: SubscriptionValue<D>) => void) {
|
|
592
710
|
const hadListener = this.subscribers.has(listener);
|
|
593
711
|
this.subscribers.add(listener);
|
|
594
712
|
// Only notify if this is a new listener (count actually changed)
|
|
@@ -624,11 +742,11 @@ export class SubscriptionScope<D extends CoValue> {
|
|
|
624
742
|
this.silenceUpdates = true;
|
|
625
743
|
|
|
626
744
|
if (value[TypeSym] === "CoMap" || value[TypeSym] === "Account") {
|
|
627
|
-
const map = value as CoMap;
|
|
745
|
+
const map = value as unknown as CoMap;
|
|
628
746
|
|
|
629
747
|
this.loadCoMapKey(map, key, true);
|
|
630
748
|
} else if (value[TypeSym] === "CoList") {
|
|
631
|
-
const list = value as CoList;
|
|
749
|
+
const list = value as unknown as CoList;
|
|
632
750
|
|
|
633
751
|
this.loadCoListKey(list, key, true);
|
|
634
752
|
}
|
|
@@ -650,7 +768,7 @@ export class SubscriptionScope<D extends CoValue> {
|
|
|
650
768
|
*
|
|
651
769
|
* Used to make the autoload work on closed subscription scopes
|
|
652
770
|
*/
|
|
653
|
-
pullValue(listener: (value: SubscriptionValue<D
|
|
771
|
+
pullValue(listener: (value: SubscriptionValue<D>) => void) {
|
|
654
772
|
if (!this.closed) {
|
|
655
773
|
throw new Error("Cannot pull a non-closed subscription scope");
|
|
656
774
|
}
|
|
@@ -707,7 +825,7 @@ export class SubscriptionScope<D extends CoValue> {
|
|
|
707
825
|
const child = new SubscriptionScope(
|
|
708
826
|
this.node,
|
|
709
827
|
true,
|
|
710
|
-
id
|
|
828
|
+
id,
|
|
711
829
|
descriptor,
|
|
712
830
|
this.skipRetry,
|
|
713
831
|
this.bestEffortResolution,
|
|
@@ -751,7 +869,7 @@ export class SubscriptionScope<D extends CoValue> {
|
|
|
751
869
|
coValueType === "Account" ||
|
|
752
870
|
coValueType === "Group"
|
|
753
871
|
) {
|
|
754
|
-
const map = value as CoMap;
|
|
872
|
+
const map = value as unknown as CoMap;
|
|
755
873
|
const keys =
|
|
756
874
|
"$each" in depth ? map.$jazz.raw.keys() : Object.keys(depth);
|
|
757
875
|
|
|
@@ -763,7 +881,7 @@ export class SubscriptionScope<D extends CoValue> {
|
|
|
763
881
|
}
|
|
764
882
|
}
|
|
765
883
|
} else if (value[TypeSym] === "CoList") {
|
|
766
|
-
const list = value as CoList;
|
|
884
|
+
const list = value as unknown as CoList;
|
|
767
885
|
|
|
768
886
|
const descriptor = list.$jazz.getItemsDescriptor();
|
|
769
887
|
|
|
@@ -782,7 +900,7 @@ export class SubscriptionScope<D extends CoValue> {
|
|
|
782
900
|
}
|
|
783
901
|
}
|
|
784
902
|
} else if (value[TypeSym] === "CoStream") {
|
|
785
|
-
const stream = value as CoFeed;
|
|
903
|
+
const stream = value as unknown as CoFeed;
|
|
786
904
|
const descriptor = stream.$jazz.getItemsDescriptor();
|
|
787
905
|
|
|
788
906
|
if (descriptor && isRefEncoded(descriptor)) {
|
|
@@ -969,7 +1087,7 @@ export class SubscriptionScope<D extends CoValue> {
|
|
|
969
1087
|
const child = new SubscriptionScope(
|
|
970
1088
|
this.node,
|
|
971
1089
|
resolve,
|
|
972
|
-
id
|
|
1090
|
+
id,
|
|
973
1091
|
descriptor,
|
|
974
1092
|
this.skipRetry,
|
|
975
1093
|
this.bestEffortResolution,
|
|
@@ -5,7 +5,7 @@ import type { JazzError } from "./JazzError";
|
|
|
5
5
|
*
|
|
6
6
|
* Works in Node.js and bundled code, falls back to false if process is not available
|
|
7
7
|
*/
|
|
8
|
-
const isDev = (function () {
|
|
8
|
+
export const isDev = (function () {
|
|
9
9
|
try {
|
|
10
10
|
return process.env.NODE_ENV === "development";
|
|
11
11
|
} catch {
|
|
@@ -100,7 +100,7 @@ export function accessChildById<D extends CoValue>(
|
|
|
100
100
|
|
|
101
101
|
// TODO: this doesn't check the subscription tree loading state
|
|
102
102
|
if (value?.type === CoValueLoadingState.LOADED) {
|
|
103
|
-
return value.value;
|
|
103
|
+
return value.value as D;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
const childNode = subscriptionScope.childNodes.get(childId);
|