jazz-tools 0.19.8 → 0.19.10
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 +44 -42
- package/CHANGELOG.md +19 -3
- package/dist/{chunk-2S3Z2CN6.js → chunk-FFEEPZEG.js} +367 -102
- package/dist/chunk-FFEEPZEG.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/react/hooks.d.ts +1 -1
- package/dist/react/hooks.d.ts.map +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +5 -1
- package/dist/react/index.js.map +1 -1
- package/dist/react-core/hooks.d.ts +59 -0
- package/dist/react-core/hooks.d.ts.map +1 -1
- package/dist/react-core/index.js +124 -36
- package/dist/react-core/index.js.map +1 -1
- package/dist/react-core/tests/testUtils.d.ts +1 -0
- package/dist/react-core/tests/testUtils.d.ts.map +1 -1
- package/dist/react-core/tests/useSuspenseAccount.test.d.ts +2 -0
- package/dist/react-core/tests/useSuspenseAccount.test.d.ts.map +1 -0
- package/dist/react-core/tests/useSuspenseCoState.test.d.ts +2 -0
- package/dist/react-core/tests/useSuspenseCoState.test.d.ts.map +1 -0
- package/dist/react-core/use.d.ts +3 -0
- package/dist/react-core/use.d.ts.map +1 -0
- package/dist/react-native/index.js +5 -1
- package/dist/react-native/index.js.map +1 -1
- package/dist/react-native-core/crypto/RNCrypto.d.ts +2 -0
- package/dist/react-native-core/crypto/RNCrypto.d.ts.map +1 -0
- package/dist/react-native-core/crypto/RNCrypto.js +3 -0
- package/dist/react-native-core/crypto/RNCrypto.js.map +1 -0
- package/dist/react-native-core/hooks.d.ts +1 -1
- package/dist/react-native-core/hooks.d.ts.map +1 -1
- package/dist/react-native-core/index.js +5 -1
- package/dist/react-native-core/index.js.map +1 -1
- package/dist/react-native-core/platform.d.ts +2 -1
- package/dist/react-native-core/platform.d.ts.map +1 -1
- package/dist/testing.js +1 -1
- package/dist/testing.js.map +1 -1
- package/dist/tools/coValues/interfaces.d.ts +1 -1
- package/dist/tools/coValues/interfaces.d.ts.map +1 -1
- package/dist/tools/implementation/ContextManager.d.ts +3 -0
- package/dist/tools/implementation/ContextManager.d.ts.map +1 -1
- package/dist/tools/subscribe/CoValueCoreSubscription.d.ts +8 -22
- package/dist/tools/subscribe/CoValueCoreSubscription.d.ts.map +1 -1
- package/dist/tools/subscribe/SubscriptionCache.d.ts +51 -0
- package/dist/tools/subscribe/SubscriptionCache.d.ts.map +1 -0
- package/dist/tools/subscribe/SubscriptionScope.d.ts +17 -1
- package/dist/tools/subscribe/SubscriptionScope.d.ts.map +1 -1
- package/dist/tools/subscribe/utils.d.ts +9 -1
- package/dist/tools/subscribe/utils.d.ts.map +1 -1
- package/dist/tools/testing.d.ts +2 -2
- package/dist/tools/testing.d.ts.map +1 -1
- package/dist/tools/tests/SubscriptionCache.test.d.ts +2 -0
- package/dist/tools/tests/SubscriptionCache.test.d.ts.map +1 -0
- package/package.json +13 -6
- package/src/react/hooks.tsx +2 -0
- package/src/react/index.ts +1 -14
- package/src/react-core/hooks.ts +167 -18
- package/src/react-core/tests/createCoValueSubscriptionContext.test.tsx +18 -8
- package/src/react-core/tests/testUtils.tsx +67 -5
- package/src/react-core/tests/useCoState.test.ts +3 -7
- package/src/react-core/tests/useSubscriptionSelector.test.ts +3 -7
- package/src/react-core/tests/useSuspenseAccount.test.tsx +343 -0
- package/src/react-core/tests/useSuspenseCoState.test.tsx +1182 -0
- package/src/react-core/use.ts +46 -0
- package/src/react-native-core/crypto/RNCrypto.ts +1 -0
- package/src/react-native-core/hooks.tsx +2 -0
- package/src/react-native-core/platform.ts +2 -1
- package/src/tools/coValues/interfaces.ts +2 -3
- package/src/tools/implementation/ContextManager.ts +13 -0
- package/src/tools/subscribe/CoValueCoreSubscription.ts +71 -100
- package/src/tools/subscribe/SubscriptionCache.ts +272 -0
- package/src/tools/subscribe/SubscriptionScope.ts +113 -7
- package/src/tools/subscribe/utils.ts +77 -0
- package/src/tools/testing.ts +0 -3
- package/src/tools/tests/CoValueCoreSubscription.test.ts +46 -12
- package/src/tools/tests/ContextManager.test.ts +85 -0
- package/src/tools/tests/SubscriptionCache.test.ts +237 -0
- package/src/tools/tests/coMap.test.ts +5 -7
- package/tsup.config.ts +1 -0
- package/dist/chunk-2S3Z2CN6.js.map +0 -1
|
@@ -3930,7 +3930,8 @@ function applyCoValueMigrations(instance) {
|
|
|
3930
3930
|
|
|
3931
3931
|
// src/tools/subscribe/CoValueCoreSubscription.ts
|
|
3932
3932
|
import {
|
|
3933
|
-
cojsonInternals as cojsonInternals4
|
|
3933
|
+
cojsonInternals as cojsonInternals4,
|
|
3934
|
+
isRawCoID
|
|
3934
3935
|
} from "cojson";
|
|
3935
3936
|
|
|
3936
3937
|
// src/tools/subscribe/types.ts
|
|
@@ -3984,101 +3985,62 @@ var CoValueCoreSubscription = class {
|
|
|
3984
3985
|
*/
|
|
3985
3986
|
initializeSubscription() {
|
|
3986
3987
|
const source = this.source;
|
|
3987
|
-
if (source.
|
|
3988
|
-
this.
|
|
3988
|
+
if (!isRawCoID(source.id)) {
|
|
3989
|
+
this.emit(CoValueLoadingState.UNAVAILABLE);
|
|
3989
3990
|
return;
|
|
3990
3991
|
}
|
|
3991
3992
|
if (this.branchName) {
|
|
3992
|
-
this.
|
|
3993
|
+
this.handleBranching(this.branchName, this.branchOwnerId);
|
|
3993
3994
|
return;
|
|
3994
3995
|
}
|
|
3995
|
-
this.
|
|
3996
|
+
this.subscribe(this.source);
|
|
3996
3997
|
}
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
handleAvailableSource() {
|
|
4002
|
-
if (!this.branchName || !cojsonInternals4.canBeBranched(this.source)) {
|
|
4003
|
-
this.subscribe(this.source.getCurrentContent());
|
|
3998
|
+
handleBranching(branchName, branchOwnerId) {
|
|
3999
|
+
const source = this.source;
|
|
4000
|
+
if (!source.isAvailable()) {
|
|
4001
|
+
this.waitForSourceToBecomeAvailable(branchName, branchOwnerId);
|
|
4004
4002
|
return;
|
|
4005
4003
|
}
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
this.subscribe(branch.getCurrentContent());
|
|
4004
|
+
if (!cojsonInternals4.canBeBranched(source)) {
|
|
4005
|
+
this.subscribe(source);
|
|
4009
4006
|
return;
|
|
4010
|
-
} else if (!this.source.hasBranch(this.branchName, this.branchOwnerId)) {
|
|
4011
|
-
this.source.createBranch(this.branchName, this.branchOwnerId);
|
|
4012
|
-
this.subscribe(branch.getCurrentContent());
|
|
4013
|
-
} else {
|
|
4014
|
-
this.handleBranchCheckout();
|
|
4015
4007
|
}
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
if (value !== CoValueLoadingState.UNAVAILABLE) {
|
|
4025
|
-
this.subscribe(value);
|
|
4026
|
-
} else {
|
|
4027
|
-
this.handleUnavailableBranch();
|
|
4008
|
+
const branch = source.getBranch(branchName, branchOwnerId);
|
|
4009
|
+
if (!branch.isAvailable() && !source.hasBranch(branchName, branchOwnerId)) {
|
|
4010
|
+
try {
|
|
4011
|
+
source.createBranch(branchName, branchOwnerId);
|
|
4012
|
+
} catch (error) {
|
|
4013
|
+
console.error("error creating branch", error);
|
|
4014
|
+
this.emit(CoValueLoadingState.UNAVAILABLE);
|
|
4015
|
+
return;
|
|
4028
4016
|
}
|
|
4029
|
-
}).catch((error) => {
|
|
4030
|
-
console.error(error);
|
|
4031
|
-
this.emit(CoValueLoadingState.UNAVAILABLE);
|
|
4032
|
-
});
|
|
4033
|
-
}
|
|
4034
|
-
/**
|
|
4035
|
-
* Handles the case where a branch checkout fails.
|
|
4036
|
-
* Determines whether to retry or report unavailability.
|
|
4037
|
-
*/
|
|
4038
|
-
handleUnavailableBranch() {
|
|
4039
|
-
const source = this.source;
|
|
4040
|
-
if (source.isAvailable()) {
|
|
4041
|
-
throw new Error("Branch is unavailable");
|
|
4042
4017
|
}
|
|
4043
|
-
this.
|
|
4044
|
-
this.emit(CoValueLoadingState.UNAVAILABLE);
|
|
4018
|
+
this.subscribe(branch);
|
|
4045
4019
|
}
|
|
4046
4020
|
/**
|
|
4047
|
-
* Loads
|
|
4048
|
-
* This is the fallback strategy when immediate availability fails.
|
|
4021
|
+
* Loads a CoValue core and emits an unavailable event if it is still unavailable after the retries.
|
|
4049
4022
|
*/
|
|
4050
|
-
|
|
4051
|
-
this.localNode.loadCoValueCore(
|
|
4052
|
-
if (
|
|
4053
|
-
if (value.isAvailable()) {
|
|
4054
|
-
this.subscribe(value.getCurrentContent());
|
|
4055
|
-
} else {
|
|
4056
|
-
this.subscribeToUnavailableSource();
|
|
4023
|
+
load(value) {
|
|
4024
|
+
this.localNode.loadCoValueCore(value.id, void 0, this.skipRetry).then(() => {
|
|
4025
|
+
if (!value.isAvailable()) {
|
|
4057
4026
|
this.emit(CoValueLoadingState.UNAVAILABLE);
|
|
4058
4027
|
}
|
|
4059
|
-
}).catch((error) => {
|
|
4060
|
-
console.error(error);
|
|
4061
|
-
this.emit(CoValueLoadingState.UNAVAILABLE);
|
|
4062
4028
|
});
|
|
4063
4029
|
}
|
|
4064
4030
|
/**
|
|
4065
|
-
*
|
|
4066
|
-
* This allows the subscription to become active when the source becomes available after a first loading attempt.
|
|
4031
|
+
* Waits for the source to become available and then tries to branch.
|
|
4067
4032
|
*/
|
|
4068
|
-
|
|
4033
|
+
waitForSourceToBecomeAvailable(branchName, branchOwnerId) {
|
|
4069
4034
|
const source = this.source;
|
|
4070
4035
|
const handleStateChange = (_, unsubFromStateChange) => {
|
|
4071
4036
|
if (!source.isAvailable()) {
|
|
4072
4037
|
return;
|
|
4073
4038
|
}
|
|
4074
4039
|
unsubFromStateChange();
|
|
4075
|
-
|
|
4076
|
-
this.handleBranchCheckout();
|
|
4077
|
-
} else {
|
|
4078
|
-
this.subscribe(source.getCurrentContent());
|
|
4079
|
-
}
|
|
4040
|
+
this.handleBranching(branchName, branchOwnerId);
|
|
4080
4041
|
};
|
|
4081
4042
|
this._unsubscribe = source.subscribe(handleStateChange);
|
|
4043
|
+
this.load(source);
|
|
4082
4044
|
}
|
|
4083
4045
|
/**
|
|
4084
4046
|
* Subscribes to a specific CoValue and notifies the listener.
|
|
@@ -4087,16 +4049,30 @@ var CoValueCoreSubscription = class {
|
|
|
4087
4049
|
subscribe(value) {
|
|
4088
4050
|
if (this.unsubscribed) return;
|
|
4089
4051
|
this._unsubscribe = value.subscribe((value2) => {
|
|
4090
|
-
|
|
4052
|
+
if (value2.isAvailable()) {
|
|
4053
|
+
this.emit(value2.getCurrentContent());
|
|
4054
|
+
}
|
|
4091
4055
|
});
|
|
4056
|
+
if (!value.isAvailable()) {
|
|
4057
|
+
this.load(value);
|
|
4058
|
+
}
|
|
4092
4059
|
}
|
|
4093
4060
|
emit(value) {
|
|
4094
4061
|
if (this.unsubscribed) return;
|
|
4095
|
-
if (!isReadyForEmit(value)) {
|
|
4062
|
+
if (!this.isReadyForEmit(value)) {
|
|
4096
4063
|
return;
|
|
4097
4064
|
}
|
|
4098
4065
|
this.listener(value);
|
|
4099
4066
|
}
|
|
4067
|
+
isReadyForEmit(value) {
|
|
4068
|
+
if (value === CoValueLoadingState.UNAVAILABLE) {
|
|
4069
|
+
return true;
|
|
4070
|
+
}
|
|
4071
|
+
if (!isCompletelyDownloaded(value)) {
|
|
4072
|
+
return false;
|
|
4073
|
+
}
|
|
4074
|
+
return true;
|
|
4075
|
+
}
|
|
4100
4076
|
/**
|
|
4101
4077
|
* Unsubscribes from all active subscriptions and marks the instance as unsubscribed.
|
|
4102
4078
|
* This prevents any further operations and ensures proper cleanup.
|
|
@@ -4107,10 +4083,7 @@ var CoValueCoreSubscription = class {
|
|
|
4107
4083
|
this._unsubscribe();
|
|
4108
4084
|
}
|
|
4109
4085
|
};
|
|
4110
|
-
function
|
|
4111
|
-
if (value === "unavailable") {
|
|
4112
|
-
return true;
|
|
4113
|
-
}
|
|
4086
|
+
function isCompletelyDownloaded(value) {
|
|
4114
4087
|
return value.core.verified?.header.meta?.type === "binary" || value.core.isCompletelyDownloaded();
|
|
4115
4088
|
}
|
|
4116
4089
|
|
|
@@ -4148,6 +4121,34 @@ var JazzError = class _JazzError {
|
|
|
4148
4121
|
}
|
|
4149
4122
|
};
|
|
4150
4123
|
|
|
4124
|
+
// src/tools/subscribe/errorReporting.ts
|
|
4125
|
+
var isDev = function() {
|
|
4126
|
+
try {
|
|
4127
|
+
return process.env.NODE_ENV === "development";
|
|
4128
|
+
} catch {
|
|
4129
|
+
return false;
|
|
4130
|
+
}
|
|
4131
|
+
}();
|
|
4132
|
+
var customErrorReporter;
|
|
4133
|
+
var captureErrorCause = isDev;
|
|
4134
|
+
function enableCaptureErrorCause(capture) {
|
|
4135
|
+
captureErrorCause = capture;
|
|
4136
|
+
}
|
|
4137
|
+
function setCustomErrorReporter(reporter) {
|
|
4138
|
+
customErrorReporter = reporter;
|
|
4139
|
+
}
|
|
4140
|
+
function isCustomErrorReportingEnabled() {
|
|
4141
|
+
return customErrorReporter !== void 0;
|
|
4142
|
+
}
|
|
4143
|
+
function captureStack() {
|
|
4144
|
+
return captureErrorCause ? new Error() : void 0;
|
|
4145
|
+
}
|
|
4146
|
+
function captureError(error, props) {
|
|
4147
|
+
if (customErrorReporter) {
|
|
4148
|
+
customErrorReporter(error, props);
|
|
4149
|
+
}
|
|
4150
|
+
}
|
|
4151
|
+
|
|
4151
4152
|
// src/tools/subscribe/utils.ts
|
|
4152
4153
|
import { RawAccount as RawAccount4 } from "cojson";
|
|
4153
4154
|
|
|
@@ -4188,33 +4189,47 @@ function createCoValue(ref2, raw, subscriptionScope) {
|
|
|
4188
4189
|
id: subscriptionScope.id
|
|
4189
4190
|
};
|
|
4190
4191
|
}
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
} catch {
|
|
4197
|
-
return false;
|
|
4198
|
-
}
|
|
4199
|
-
}();
|
|
4200
|
-
var customErrorReporter;
|
|
4201
|
-
var captureErrorCause = isDev;
|
|
4202
|
-
function enableCaptureErrorCause(capture) {
|
|
4203
|
-
captureErrorCause = capture;
|
|
4204
|
-
}
|
|
4205
|
-
function setCustomErrorReporter(reporter) {
|
|
4206
|
-
customErrorReporter = reporter;
|
|
4207
|
-
}
|
|
4208
|
-
function isCustomErrorReportingEnabled() {
|
|
4209
|
-
return customErrorReporter !== void 0;
|
|
4192
|
+
function resolvedPromise(value) {
|
|
4193
|
+
const promise = Promise.resolve(value);
|
|
4194
|
+
promise.status = "fulfilled";
|
|
4195
|
+
promise.value = value;
|
|
4196
|
+
return promise;
|
|
4210
4197
|
}
|
|
4211
|
-
function
|
|
4212
|
-
|
|
4198
|
+
function rejectedPromise(reason) {
|
|
4199
|
+
const promise = Promise.reject(reason);
|
|
4200
|
+
promise.status = "rejected";
|
|
4201
|
+
promise.reason = reason;
|
|
4202
|
+
return promise;
|
|
4213
4203
|
}
|
|
4214
|
-
function
|
|
4215
|
-
if (
|
|
4216
|
-
|
|
4204
|
+
function isEqualRefsToResolve(a, b) {
|
|
4205
|
+
if (a === b) {
|
|
4206
|
+
return true;
|
|
4207
|
+
}
|
|
4208
|
+
if (typeof a === "boolean" && typeof b === "boolean") {
|
|
4209
|
+
return a === b;
|
|
4210
|
+
}
|
|
4211
|
+
if (typeof a === "boolean" || typeof b === "boolean") {
|
|
4212
|
+
return false;
|
|
4213
|
+
}
|
|
4214
|
+
if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) {
|
|
4215
|
+
return false;
|
|
4217
4216
|
}
|
|
4217
|
+
const keysA = Object.keys(a);
|
|
4218
|
+
const keysB = Object.keys(b);
|
|
4219
|
+
if (keysA.length !== keysB.length) {
|
|
4220
|
+
return false;
|
|
4221
|
+
}
|
|
4222
|
+
for (const key of keysA) {
|
|
4223
|
+
if (!(key in b)) {
|
|
4224
|
+
return false;
|
|
4225
|
+
}
|
|
4226
|
+
const valueA = a[key];
|
|
4227
|
+
const valueB = b[key];
|
|
4228
|
+
if (!isEqualRefsToResolve(valueA, valueB)) {
|
|
4229
|
+
return false;
|
|
4230
|
+
}
|
|
4231
|
+
}
|
|
4232
|
+
return true;
|
|
4218
4233
|
}
|
|
4219
4234
|
|
|
4220
4235
|
// src/tools/subscribe/SubscriptionScope.ts
|
|
@@ -4273,6 +4288,7 @@ var SubscriptionScope = class _SubscriptionScope {
|
|
|
4273
4288
|
this.triggerUpdate();
|
|
4274
4289
|
};
|
|
4275
4290
|
this.subscribers = /* @__PURE__ */ new Set();
|
|
4291
|
+
this.subscriberChangeCallbacks = /* @__PURE__ */ new Set();
|
|
4276
4292
|
this.callerStack = callerStack;
|
|
4277
4293
|
this.resolve = resolve;
|
|
4278
4294
|
this.value = { type: CoValueLoadingState.LOADING, id };
|
|
@@ -4401,6 +4417,48 @@ var SubscriptionScope = class _SubscriptionScope {
|
|
|
4401
4417
|
if (this.value.type !== CoValueLoadingState.LOADED) return true;
|
|
4402
4418
|
return this.pendingLoadedChildren.size === 0;
|
|
4403
4419
|
}
|
|
4420
|
+
cachePromise(value, callback) {
|
|
4421
|
+
if (this.lastPromise?.value === value) {
|
|
4422
|
+
return this.lastPromise.promise;
|
|
4423
|
+
}
|
|
4424
|
+
const promise = callback();
|
|
4425
|
+
this.lastPromise = { value, promise };
|
|
4426
|
+
return promise;
|
|
4427
|
+
}
|
|
4428
|
+
getPromise() {
|
|
4429
|
+
const currentValue = this.getCurrentValue();
|
|
4430
|
+
if (currentValue.$isLoaded) {
|
|
4431
|
+
return resolvedPromise(currentValue);
|
|
4432
|
+
}
|
|
4433
|
+
if (currentValue.$jazz.loadingState !== CoValueLoadingState.LOADING) {
|
|
4434
|
+
const error = this.getError();
|
|
4435
|
+
return rejectedPromise(
|
|
4436
|
+
new Error(error?.toString() ?? "Unknown error", {
|
|
4437
|
+
cause: this.callerStack
|
|
4438
|
+
})
|
|
4439
|
+
);
|
|
4440
|
+
}
|
|
4441
|
+
return this.cachePromise(currentValue, () => {
|
|
4442
|
+
return new Promise((resolve, reject) => {
|
|
4443
|
+
const unsubscribe = this.subscribe(() => {
|
|
4444
|
+
const currentValue2 = this.getCurrentValue();
|
|
4445
|
+
if (currentValue2.$jazz.loadingState === CoValueLoadingState.LOADING) {
|
|
4446
|
+
return;
|
|
4447
|
+
}
|
|
4448
|
+
if (currentValue2.$isLoaded) {
|
|
4449
|
+
resolve(currentValue2);
|
|
4450
|
+
} else {
|
|
4451
|
+
reject(
|
|
4452
|
+
new Error(this.getError()?.toString() ?? "Unknown error", {
|
|
4453
|
+
cause: this.callerStack
|
|
4454
|
+
})
|
|
4455
|
+
);
|
|
4456
|
+
}
|
|
4457
|
+
unsubscribe();
|
|
4458
|
+
});
|
|
4459
|
+
});
|
|
4460
|
+
});
|
|
4461
|
+
}
|
|
4404
4462
|
getUnloadedValue(reason) {
|
|
4405
4463
|
if (this.unloadedValue?.$jazz.loadingState === reason) {
|
|
4406
4464
|
return this.unloadedValue;
|
|
@@ -4451,14 +4509,16 @@ var SubscriptionScope = class _SubscriptionScope {
|
|
|
4451
4509
|
}
|
|
4452
4510
|
return result;
|
|
4453
4511
|
}
|
|
4454
|
-
|
|
4455
|
-
let error;
|
|
4512
|
+
getError() {
|
|
4456
4513
|
if (this.value.type === CoValueLoadingState.UNAUTHORIZED || this.value.type === CoValueLoadingState.UNAVAILABLE) {
|
|
4457
|
-
|
|
4514
|
+
return this.value;
|
|
4458
4515
|
}
|
|
4459
4516
|
if (this.errorFromChildren) {
|
|
4460
|
-
|
|
4517
|
+
return this.errorFromChildren;
|
|
4461
4518
|
}
|
|
4519
|
+
}
|
|
4520
|
+
logError() {
|
|
4521
|
+
const error = this.getError();
|
|
4462
4522
|
if (!error || this.lastErrorLogged === error) {
|
|
4463
4523
|
return;
|
|
4464
4524
|
}
|
|
@@ -4489,14 +4549,37 @@ var SubscriptionScope = class _SubscriptionScope {
|
|
|
4489
4549
|
}
|
|
4490
4550
|
this.dirty = false;
|
|
4491
4551
|
}
|
|
4552
|
+
/**
|
|
4553
|
+
* Subscribe to subscriber count changes
|
|
4554
|
+
* Callback receives the total number of subscribers
|
|
4555
|
+
* Returns an unsubscribe function
|
|
4556
|
+
*/
|
|
4557
|
+
onSubscriberChange(callback) {
|
|
4558
|
+
this.subscriberChangeCallbacks.add(callback);
|
|
4559
|
+
return () => {
|
|
4560
|
+
this.subscriberChangeCallbacks.delete(callback);
|
|
4561
|
+
};
|
|
4562
|
+
}
|
|
4563
|
+
notifySubscriberChange() {
|
|
4564
|
+
const count = this.subscribers.size;
|
|
4565
|
+
this.subscriberChangeCallbacks.forEach((callback) => {
|
|
4566
|
+
callback(count);
|
|
4567
|
+
});
|
|
4568
|
+
}
|
|
4492
4569
|
subscribe(listener) {
|
|
4493
4570
|
this.subscribers.add(listener);
|
|
4571
|
+
this.notifySubscriberChange();
|
|
4494
4572
|
return () => {
|
|
4495
4573
|
this.subscribers.delete(listener);
|
|
4574
|
+
this.notifySubscriberChange();
|
|
4496
4575
|
};
|
|
4497
4576
|
}
|
|
4498
4577
|
setListener(listener) {
|
|
4578
|
+
const hadListener = this.subscribers.has(listener);
|
|
4499
4579
|
this.subscribers.add(listener);
|
|
4580
|
+
if (!hadListener) {
|
|
4581
|
+
this.notifySubscriberChange();
|
|
4582
|
+
}
|
|
4500
4583
|
this.triggerUpdate();
|
|
4501
4584
|
}
|
|
4502
4585
|
subscribeToKey(key) {
|
|
@@ -4765,7 +4848,12 @@ var SubscriptionScope = class _SubscriptionScope {
|
|
|
4765
4848
|
destroy() {
|
|
4766
4849
|
this.closed = true;
|
|
4767
4850
|
this.subscription.unsubscribe();
|
|
4851
|
+
const hadSubscribers = this.subscribers.size > 0;
|
|
4768
4852
|
this.subscribers.clear();
|
|
4853
|
+
if (hadSubscribers) {
|
|
4854
|
+
this.notifySubscriberChange();
|
|
4855
|
+
}
|
|
4856
|
+
this.subscriberChangeCallbacks.clear();
|
|
4769
4857
|
this.childNodes.forEach((child) => child.destroy());
|
|
4770
4858
|
}
|
|
4771
4859
|
};
|
|
@@ -6381,6 +6469,177 @@ var InMemoryKVStore = class {
|
|
|
6381
6469
|
}
|
|
6382
6470
|
};
|
|
6383
6471
|
|
|
6472
|
+
// src/tools/subscribe/SubscriptionCache.ts
|
|
6473
|
+
var SubscriptionCache = class {
|
|
6474
|
+
constructor(cleanupTimeout = 5e3) {
|
|
6475
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
6476
|
+
this.cleanupTimeout = cleanupTimeout;
|
|
6477
|
+
}
|
|
6478
|
+
/**
|
|
6479
|
+
* Get the inner set for a given id (read-only access)
|
|
6480
|
+
*/
|
|
6481
|
+
getIdSet(id) {
|
|
6482
|
+
return this.cache.get(id);
|
|
6483
|
+
}
|
|
6484
|
+
/**
|
|
6485
|
+
* Get the inner set for a given id, creating it if it doesn't exist
|
|
6486
|
+
*/
|
|
6487
|
+
getIdSetOrCreate(id) {
|
|
6488
|
+
let idSet = this.cache.get(id);
|
|
6489
|
+
if (!idSet) {
|
|
6490
|
+
idSet = /* @__PURE__ */ new Set();
|
|
6491
|
+
this.cache.set(id, idSet);
|
|
6492
|
+
}
|
|
6493
|
+
return idSet;
|
|
6494
|
+
}
|
|
6495
|
+
/**
|
|
6496
|
+
* Check if an entry matches the provided parameters
|
|
6497
|
+
*/
|
|
6498
|
+
matchesEntry(entry, schema, resolve, branch) {
|
|
6499
|
+
if (entry.schema !== schema) {
|
|
6500
|
+
return false;
|
|
6501
|
+
}
|
|
6502
|
+
if (!isEqualRefsToResolve(entry.resolve, resolve)) {
|
|
6503
|
+
return false;
|
|
6504
|
+
}
|
|
6505
|
+
const branchName = branch?.name;
|
|
6506
|
+
if (entry.branch?.name !== branchName) {
|
|
6507
|
+
return false;
|
|
6508
|
+
}
|
|
6509
|
+
const branchOwnerId = branch?.owner?.$jazz.id;
|
|
6510
|
+
if (entry.branch?.owner?.$jazz.id !== branchOwnerId) {
|
|
6511
|
+
return false;
|
|
6512
|
+
}
|
|
6513
|
+
return true;
|
|
6514
|
+
}
|
|
6515
|
+
/**
|
|
6516
|
+
* Find a matching cache entry by comparing against entry properties
|
|
6517
|
+
* Uses id-based nesting to quickly filter candidates
|
|
6518
|
+
*/
|
|
6519
|
+
findMatchingEntry(schema, id, resolve, branch) {
|
|
6520
|
+
const idSet = this.getIdSet(id);
|
|
6521
|
+
if (!idSet) {
|
|
6522
|
+
return void 0;
|
|
6523
|
+
}
|
|
6524
|
+
for (const entry of idSet) {
|
|
6525
|
+
if (this.matchesEntry(entry, schema, resolve, branch)) {
|
|
6526
|
+
return entry;
|
|
6527
|
+
}
|
|
6528
|
+
}
|
|
6529
|
+
return void 0;
|
|
6530
|
+
}
|
|
6531
|
+
/**
|
|
6532
|
+
* Handle subscriber count changes from SubscriptionScope
|
|
6533
|
+
*/
|
|
6534
|
+
handleSubscriberChange(entry, count) {
|
|
6535
|
+
entry.subscriberCount = count;
|
|
6536
|
+
if (count === 0) {
|
|
6537
|
+
this.scheduleCleanup(entry);
|
|
6538
|
+
} else {
|
|
6539
|
+
this.cancelCleanup(entry);
|
|
6540
|
+
}
|
|
6541
|
+
}
|
|
6542
|
+
/**
|
|
6543
|
+
* Schedule cleanup timeout for an entry
|
|
6544
|
+
*/
|
|
6545
|
+
scheduleCleanup(entry) {
|
|
6546
|
+
this.cancelCleanup(entry);
|
|
6547
|
+
entry.cleanupTimeoutId = setTimeout(() => {
|
|
6548
|
+
this.destroyEntry(entry);
|
|
6549
|
+
}, this.cleanupTimeout);
|
|
6550
|
+
}
|
|
6551
|
+
/**
|
|
6552
|
+
* Cancel pending cleanup timeout for an entry
|
|
6553
|
+
*/
|
|
6554
|
+
cancelCleanup(entry) {
|
|
6555
|
+
if (entry.cleanupTimeoutId !== void 0) {
|
|
6556
|
+
clearTimeout(entry.cleanupTimeoutId);
|
|
6557
|
+
entry.cleanupTimeoutId = void 0;
|
|
6558
|
+
}
|
|
6559
|
+
}
|
|
6560
|
+
/**
|
|
6561
|
+
* Destroy a cache entry and its SubscriptionScope
|
|
6562
|
+
*/
|
|
6563
|
+
destroyEntry(entry) {
|
|
6564
|
+
this.cancelCleanup(entry);
|
|
6565
|
+
entry.unsubscribeFromScope();
|
|
6566
|
+
try {
|
|
6567
|
+
entry.subscriptionScope.destroy();
|
|
6568
|
+
} catch (error) {
|
|
6569
|
+
console.error("Error destroying SubscriptionScope:", error);
|
|
6570
|
+
}
|
|
6571
|
+
const id = entry.subscriptionScope.id;
|
|
6572
|
+
const idSet = this.getIdSet(id);
|
|
6573
|
+
if (idSet) {
|
|
6574
|
+
idSet.delete(entry);
|
|
6575
|
+
if (idSet.size === 0) {
|
|
6576
|
+
this.cache.delete(id);
|
|
6577
|
+
}
|
|
6578
|
+
}
|
|
6579
|
+
}
|
|
6580
|
+
/**
|
|
6581
|
+
* Get or create a SubscriptionScope from the cache
|
|
6582
|
+
*/
|
|
6583
|
+
getOrCreate(node, schema, id, resolve, skipRetry, bestEffortResolution, branch) {
|
|
6584
|
+
if (!id) {
|
|
6585
|
+
throw new Error("Cannot create subscription with undefined or null id");
|
|
6586
|
+
}
|
|
6587
|
+
const matchingEntry = this.findMatchingEntry(schema, id, resolve, branch);
|
|
6588
|
+
if (matchingEntry) {
|
|
6589
|
+
this.cancelCleanup(matchingEntry);
|
|
6590
|
+
return matchingEntry.subscriptionScope;
|
|
6591
|
+
}
|
|
6592
|
+
const refEncoded = {
|
|
6593
|
+
ref: coValueClassFromCoValueClassOrSchema(schema),
|
|
6594
|
+
optional: true
|
|
6595
|
+
};
|
|
6596
|
+
const subscriptionScope = new SubscriptionScope(
|
|
6597
|
+
node,
|
|
6598
|
+
// @ts-expect-error the SubscriptionScope is too generic for TS to infer its instances are CoValues
|
|
6599
|
+
resolve,
|
|
6600
|
+
id,
|
|
6601
|
+
refEncoded,
|
|
6602
|
+
skipRetry ?? false,
|
|
6603
|
+
bestEffortResolution ?? false,
|
|
6604
|
+
branch
|
|
6605
|
+
);
|
|
6606
|
+
const handleSubscriberChange = (count) => {
|
|
6607
|
+
const idSet2 = this.getIdSet(id);
|
|
6608
|
+
if (idSet2 && idSet2.has(entry)) {
|
|
6609
|
+
this.handleSubscriberChange(entry, count);
|
|
6610
|
+
}
|
|
6611
|
+
};
|
|
6612
|
+
const entry = {
|
|
6613
|
+
subscriptionScope,
|
|
6614
|
+
schema,
|
|
6615
|
+
resolve,
|
|
6616
|
+
branch,
|
|
6617
|
+
subscriberCount: subscriptionScope.subscribers.size,
|
|
6618
|
+
unsubscribeFromScope: subscriptionScope.onSubscriberChange(
|
|
6619
|
+
handleSubscriberChange
|
|
6620
|
+
)
|
|
6621
|
+
};
|
|
6622
|
+
const idSet = this.getIdSetOrCreate(id);
|
|
6623
|
+
idSet.add(entry);
|
|
6624
|
+
return subscriptionScope;
|
|
6625
|
+
}
|
|
6626
|
+
/**
|
|
6627
|
+
* Clear all cache entries and destroy all SubscriptionScope instances
|
|
6628
|
+
*/
|
|
6629
|
+
clear() {
|
|
6630
|
+
const entriesToDestroy = [];
|
|
6631
|
+
for (const idSet of this.cache.values()) {
|
|
6632
|
+
for (const entry of idSet) {
|
|
6633
|
+
entriesToDestroy.push(entry);
|
|
6634
|
+
}
|
|
6635
|
+
}
|
|
6636
|
+
for (const entry of entriesToDestroy) {
|
|
6637
|
+
this.destroyEntry(entry);
|
|
6638
|
+
}
|
|
6639
|
+
this.cache.clear();
|
|
6640
|
+
}
|
|
6641
|
+
};
|
|
6642
|
+
|
|
6384
6643
|
// src/tools/implementation/ContextManager.ts
|
|
6385
6644
|
function getAnonymousFallback() {
|
|
6386
6645
|
const context = createAnonymousJazzContext({
|
|
@@ -6414,6 +6673,7 @@ var JazzContextManager = class {
|
|
|
6414
6673
|
return;
|
|
6415
6674
|
}
|
|
6416
6675
|
this.authenticatingAccountID = null;
|
|
6676
|
+
this.subscriptionCache.clear();
|
|
6417
6677
|
await this.props.onLogOut?.();
|
|
6418
6678
|
if (this.props.logOutReplacement) {
|
|
6419
6679
|
await this.props.logOutReplacement();
|
|
@@ -6511,6 +6771,7 @@ var JazzContextManager = class {
|
|
|
6511
6771
|
};
|
|
6512
6772
|
KvStoreContext.getInstance().initialize(this.getKvStore());
|
|
6513
6773
|
this.authSecretStorage = new AuthSecretStorage(opts?.authSecretStorageKey);
|
|
6774
|
+
this.subscriptionCache = new SubscriptionCache();
|
|
6514
6775
|
if (opts?.useAnonymousFallback) {
|
|
6515
6776
|
this.value = getAnonymousFallback();
|
|
6516
6777
|
}
|
|
@@ -6539,6 +6800,7 @@ var JazzContextManager = class {
|
|
|
6539
6800
|
throw new Error("Not implemented");
|
|
6540
6801
|
}
|
|
6541
6802
|
async updateContext(props, context, authProps) {
|
|
6803
|
+
this.subscriptionCache.clear();
|
|
6542
6804
|
if (!this.keepContextOpen) {
|
|
6543
6805
|
this.context?.done();
|
|
6544
6806
|
}
|
|
@@ -6576,6 +6838,9 @@ var JazzContextManager = class {
|
|
|
6576
6838
|
getAuthenticatingAccountID() {
|
|
6577
6839
|
return this.authenticatingAccountID;
|
|
6578
6840
|
}
|
|
6841
|
+
getSubscriptionScopeCache() {
|
|
6842
|
+
return this.subscriptionCache;
|
|
6843
|
+
}
|
|
6579
6844
|
async handleAnonymousAccountMigration(prevContext) {
|
|
6580
6845
|
if (!this.props) {
|
|
6581
6846
|
throw new Error("Props required");
|
|
@@ -7129,4 +7394,4 @@ export {
|
|
|
7129
7394
|
JazzContextManager
|
|
7130
7395
|
};
|
|
7131
7396
|
/* istanbul ignore file -- @preserve */
|
|
7132
|
-
//# sourceMappingURL=chunk-
|
|
7397
|
+
//# sourceMappingURL=chunk-FFEEPZEG.js.map
|