jazz-tools 0.19.7 → 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.
Files changed (167) hide show
  1. package/.turbo/turbo-build.log +65 -59
  2. package/CHANGELOG.md +34 -3
  3. package/dist/{chunk-CUS6O5NE.js → chunk-FFEEPZEG.js} +454 -122
  4. package/dist/chunk-FFEEPZEG.js.map +1 -0
  5. package/dist/expo/polyfills.js +22 -0
  6. package/dist/expo/polyfills.js.map +1 -0
  7. package/dist/index.js +26 -6
  8. package/dist/index.js.map +1 -1
  9. package/dist/react/hooks.d.ts +1 -1
  10. package/dist/react/hooks.d.ts.map +1 -1
  11. package/dist/react/index.d.ts +1 -1
  12. package/dist/react/index.d.ts.map +1 -1
  13. package/dist/react/index.js +5 -1
  14. package/dist/react/index.js.map +1 -1
  15. package/dist/react-core/hooks.d.ts +59 -0
  16. package/dist/react-core/hooks.d.ts.map +1 -1
  17. package/dist/react-core/index.js +133 -34
  18. package/dist/react-core/index.js.map +1 -1
  19. package/dist/react-core/tests/testUtils.d.ts +1 -0
  20. package/dist/react-core/tests/testUtils.d.ts.map +1 -1
  21. package/dist/react-core/tests/useSuspenseAccount.test.d.ts +2 -0
  22. package/dist/react-core/tests/useSuspenseAccount.test.d.ts.map +1 -0
  23. package/dist/react-core/tests/useSuspenseCoState.test.d.ts +2 -0
  24. package/dist/react-core/tests/useSuspenseCoState.test.d.ts.map +1 -0
  25. package/dist/react-core/use.d.ts +3 -0
  26. package/dist/react-core/use.d.ts.map +1 -0
  27. package/dist/react-native/index.d.ts +1 -1
  28. package/dist/react-native/index.d.ts.map +1 -1
  29. package/dist/react-native/index.js +717 -9
  30. package/dist/react-native/index.js.map +1 -1
  31. package/dist/react-native/polyfills.js +22 -0
  32. package/dist/react-native/polyfills.js.map +1 -0
  33. package/dist/react-native-core/crypto/RNCrypto.d.ts +2 -0
  34. package/dist/react-native-core/crypto/RNCrypto.d.ts.map +1 -0
  35. package/dist/react-native-core/crypto/RNCrypto.js +3 -0
  36. package/dist/react-native-core/crypto/RNCrypto.js.map +1 -0
  37. package/dist/react-native-core/hooks.d.ts +1 -1
  38. package/dist/react-native-core/hooks.d.ts.map +1 -1
  39. package/dist/react-native-core/index.d.ts.map +1 -1
  40. package/dist/react-native-core/index.js +5 -1
  41. package/dist/react-native-core/index.js.map +1 -1
  42. package/dist/react-native-core/platform.d.ts +2 -1
  43. package/dist/react-native-core/platform.d.ts.map +1 -1
  44. package/dist/testing.js +1 -1
  45. package/dist/testing.js.map +1 -1
  46. package/dist/tools/coValues/account.d.ts +3 -3
  47. package/dist/tools/coValues/account.d.ts.map +1 -1
  48. package/dist/tools/coValues/coFeed.d.ts +3 -3
  49. package/dist/tools/coValues/coFeed.d.ts.map +1 -1
  50. package/dist/tools/coValues/coList.d.ts +4 -4
  51. package/dist/tools/coValues/coList.d.ts.map +1 -1
  52. package/dist/tools/coValues/coMap.d.ts +7 -7
  53. package/dist/tools/coValues/coMap.d.ts.map +1 -1
  54. package/dist/tools/coValues/coPlainText.d.ts +2 -2
  55. package/dist/tools/coValues/coPlainText.d.ts.map +1 -1
  56. package/dist/tools/coValues/coVector.d.ts +2 -2
  57. package/dist/tools/coValues/coVector.d.ts.map +1 -1
  58. package/dist/tools/coValues/deepLoading.d.ts +24 -0
  59. package/dist/tools/coValues/deepLoading.d.ts.map +1 -1
  60. package/dist/tools/coValues/group.d.ts +2 -2
  61. package/dist/tools/coValues/group.d.ts.map +1 -1
  62. package/dist/tools/coValues/interfaces.d.ts +7 -7
  63. package/dist/tools/coValues/interfaces.d.ts.map +1 -1
  64. package/dist/tools/coValues/schemaUnion.d.ts +2 -2
  65. package/dist/tools/coValues/schemaUnion.d.ts.map +1 -1
  66. package/dist/tools/config.d.ts +3 -0
  67. package/dist/tools/config.d.ts.map +1 -0
  68. package/dist/tools/exports.d.ts +2 -0
  69. package/dist/tools/exports.d.ts.map +1 -1
  70. package/dist/tools/implementation/ContextManager.d.ts +3 -0
  71. package/dist/tools/implementation/ContextManager.d.ts.map +1 -1
  72. package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts +2 -2
  73. package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts.map +1 -1
  74. package/dist/tools/implementation/zodSchema/schemaTypes/CoDiscriminatedUnionSchema.d.ts +2 -2
  75. package/dist/tools/implementation/zodSchema/schemaTypes/CoDiscriminatedUnionSchema.d.ts.map +1 -1
  76. package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts +2 -2
  77. package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts.map +1 -1
  78. package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts +4 -4
  79. package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts.map +1 -1
  80. package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts +4 -4
  81. package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts.map +1 -1
  82. package/dist/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.d.ts +4 -4
  83. package/dist/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.d.ts.map +1 -1
  84. package/dist/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts +2 -2
  85. package/dist/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts.map +1 -1
  86. package/dist/tools/implementation/zodSchema/schemaTypes/GroupSchema.d.ts +2 -2
  87. package/dist/tools/implementation/zodSchema/schemaTypes/GroupSchema.d.ts.map +1 -1
  88. package/dist/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.d.ts +2 -2
  89. package/dist/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.d.ts.map +1 -1
  90. package/dist/tools/implementation/zodSchema/schemaTypes/RichTextSchema.d.ts +2 -2
  91. package/dist/tools/implementation/zodSchema/schemaTypes/RichTextSchema.d.ts.map +1 -1
  92. package/dist/tools/implementation/zodSchema/zodCo.d.ts.map +1 -1
  93. package/dist/tools/subscribe/CoValueCoreSubscription.d.ts +8 -22
  94. package/dist/tools/subscribe/CoValueCoreSubscription.d.ts.map +1 -1
  95. package/dist/tools/subscribe/JazzError.d.ts.map +1 -1
  96. package/dist/tools/subscribe/SubscriptionCache.d.ts +51 -0
  97. package/dist/tools/subscribe/SubscriptionCache.d.ts.map +1 -0
  98. package/dist/tools/subscribe/SubscriptionScope.d.ts +27 -2
  99. package/dist/tools/subscribe/SubscriptionScope.d.ts.map +1 -1
  100. package/dist/tools/subscribe/errorReporting.d.ts +31 -0
  101. package/dist/tools/subscribe/errorReporting.d.ts.map +1 -0
  102. package/dist/tools/subscribe/utils.d.ts +9 -1
  103. package/dist/tools/subscribe/utils.d.ts.map +1 -1
  104. package/dist/tools/testing.d.ts +2 -2
  105. package/dist/tools/testing.d.ts.map +1 -1
  106. package/dist/tools/tests/SubscriptionCache.test.d.ts +2 -0
  107. package/dist/tools/tests/SubscriptionCache.test.d.ts.map +1 -0
  108. package/dist/tools/tests/errorReporting.test.d.ts +2 -0
  109. package/dist/tools/tests/errorReporting.test.d.ts.map +1 -0
  110. package/package.json +22 -7
  111. package/src/react/hooks.tsx +2 -0
  112. package/src/react/index.ts +1 -14
  113. package/src/react-core/hooks.ts +181 -16
  114. package/src/react-core/tests/createCoValueSubscriptionContext.test.tsx +18 -8
  115. package/src/react-core/tests/testUtils.tsx +67 -5
  116. package/src/react-core/tests/useCoState.test.ts +3 -7
  117. package/src/react-core/tests/useSubscriptionSelector.test.ts +3 -7
  118. package/src/react-core/tests/useSuspenseAccount.test.tsx +343 -0
  119. package/src/react-core/tests/useSuspenseCoState.test.tsx +1182 -0
  120. package/src/react-core/use.ts +46 -0
  121. package/src/react-native/index.ts +1 -1
  122. package/src/react-native-core/crypto/RNCrypto.ts +1 -0
  123. package/src/react-native-core/hooks.tsx +2 -0
  124. package/src/react-native-core/index.ts +2 -0
  125. package/src/react-native-core/platform.ts +2 -1
  126. package/src/react-native-core/polyfills/index.js +28 -0
  127. package/src/tools/coValues/account.ts +3 -4
  128. package/src/tools/coValues/coFeed.ts +3 -2
  129. package/src/tools/coValues/coList.ts +4 -4
  130. package/src/tools/coValues/coMap.ts +4 -4
  131. package/src/tools/coValues/coPlainText.ts +2 -2
  132. package/src/tools/coValues/coVector.ts +2 -2
  133. package/src/tools/coValues/deepLoading.ts +31 -0
  134. package/src/tools/coValues/group.ts +2 -2
  135. package/src/tools/coValues/interfaces.ts +21 -26
  136. package/src/tools/coValues/schemaUnion.ts +2 -2
  137. package/src/tools/config.ts +9 -0
  138. package/src/tools/exports.ts +4 -0
  139. package/src/tools/implementation/ContextManager.ts +13 -0
  140. package/src/tools/implementation/zodSchema/schemaTypes/AccountSchema.ts +2 -2
  141. package/src/tools/implementation/zodSchema/schemaTypes/CoDiscriminatedUnionSchema.ts +2 -2
  142. package/src/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.ts +2 -2
  143. package/src/tools/implementation/zodSchema/schemaTypes/CoListSchema.ts +4 -4
  144. package/src/tools/implementation/zodSchema/schemaTypes/CoMapSchema.ts +4 -4
  145. package/src/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.ts +4 -10
  146. package/src/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.ts +2 -2
  147. package/src/tools/implementation/zodSchema/schemaTypes/GroupSchema.ts +2 -2
  148. package/src/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.ts +2 -2
  149. package/src/tools/implementation/zodSchema/schemaTypes/RichTextSchema.ts +2 -2
  150. package/src/tools/subscribe/CoValueCoreSubscription.ts +71 -100
  151. package/src/tools/subscribe/JazzError.ts +9 -6
  152. package/src/tools/subscribe/SubscriptionCache.ts +272 -0
  153. package/src/tools/subscribe/SubscriptionScope.ts +218 -29
  154. package/src/tools/subscribe/errorReporting.ts +67 -0
  155. package/src/tools/subscribe/utils.ts +77 -0
  156. package/src/tools/testing.ts +0 -3
  157. package/src/tools/tests/CoValueCoreSubscription.test.ts +46 -12
  158. package/src/tools/tests/ContextManager.test.ts +85 -0
  159. package/src/tools/tests/SubscriptionCache.test.ts +237 -0
  160. package/src/tools/tests/coMap.test.ts +5 -7
  161. package/src/tools/tests/deepLoading.test.ts +47 -47
  162. package/src/tools/tests/errorReporting.test.ts +103 -0
  163. package/src/tools/tests/load.test.ts +21 -1
  164. package/src/tools/tests/request.test.ts +2 -1
  165. package/src/tools/tests/subscribe.test.ts +44 -0
  166. package/tsup.config.ts +17 -0
  167. package/dist/chunk-CUS6O5NE.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.isAvailable()) {
3988
- this.handleAvailableSource();
3988
+ if (!isRawCoID(source.id)) {
3989
+ this.emit(CoValueLoadingState.UNAVAILABLE);
3989
3990
  return;
3990
3991
  }
3991
3992
  if (this.branchName) {
3992
- this.handleBranchCheckout();
3993
+ this.handleBranching(this.branchName, this.branchOwnerId);
3993
3994
  return;
3994
3995
  }
3995
- this.loadCoValue();
3996
+ this.subscribe(this.source);
3996
3997
  }
3997
- /**
3998
- * Handles the case where the CoValue source is immediately available.
3999
- * Either subscribes directly or attempts to get the requested branch.
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
- const branch = this.source.getBranch(this.branchName, this.branchOwnerId);
4007
- if (branch.isAvailable()) {
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
- * Attempts to checkout a specific branch of the CoValue.
4019
- * This is called when the source isn't available but a branch is requested.
4020
- */
4021
- handleBranchCheckout() {
4022
- this.localNode.checkoutBranch(this.source.id, this.branchName, this.branchOwnerId).then((value) => {
4023
- if (this.unsubscribed) return;
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.subscribeToUnavailableSource();
4044
- this.emit(CoValueLoadingState.UNAVAILABLE);
4018
+ this.subscribe(branch);
4045
4019
  }
4046
4020
  /**
4047
- * Loads the CoValue core from the network/storage.
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
- loadCoValue() {
4051
- this.localNode.loadCoValueCore(this.source.id, void 0, this.skipRetry).then((value) => {
4052
- if (this.unsubscribed) return;
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
- * Subscribes to state changes of an unavailable CoValue source.
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
- subscribeToUnavailableSource() {
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
- if (this.branchName) {
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
- this.emit(value2);
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 isReadyForEmit(value) {
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
 
@@ -4122,16 +4095,17 @@ var JazzError = class _JazzError {
4122
4095
  this.issues = issues;
4123
4096
  }
4124
4097
  toString() {
4125
- return this.issues.map((issue) => {
4098
+ let result = this.issues.map((issue) => {
4126
4099
  let message = `${issue.message}`;
4127
- if (this.id) {
4128
- message += ` from ${this.id}`;
4129
- }
4130
4100
  if (issue.path.length > 0) {
4131
- message += ` on path ${issue.path.join(".")}`;
4101
+ if (this.id) {
4102
+ message += `. Subscription starts from ${this.id}`;
4103
+ }
4104
+ message += ` and the value is on path ${issue.path.join(".")}`;
4132
4105
  }
4133
4106
  return message;
4134
4107
  }).join("\n");
4108
+ return result;
4135
4109
  }
4136
4110
  prependPath(item) {
4137
4111
  if (this.issues.length === 0) {
@@ -4147,6 +4121,34 @@ var JazzError = class _JazzError {
4147
4121
  }
4148
4122
  };
4149
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
+
4150
4152
  // src/tools/subscribe/utils.ts
4151
4153
  import { RawAccount as RawAccount4 } from "cojson";
4152
4154
 
@@ -4187,10 +4189,52 @@ function createCoValue(ref2, raw, subscriptionScope) {
4187
4189
  id: subscriptionScope.id
4188
4190
  };
4189
4191
  }
4192
+ function resolvedPromise(value) {
4193
+ const promise = Promise.resolve(value);
4194
+ promise.status = "fulfilled";
4195
+ promise.value = value;
4196
+ return promise;
4197
+ }
4198
+ function rejectedPromise(reason) {
4199
+ const promise = Promise.reject(reason);
4200
+ promise.status = "rejected";
4201
+ promise.reason = reason;
4202
+ return promise;
4203
+ }
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;
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;
4233
+ }
4190
4234
 
4191
4235
  // src/tools/subscribe/SubscriptionScope.ts
4192
4236
  var SubscriptionScope = class _SubscriptionScope {
4193
- constructor(node, resolve, id, schema, skipRetry = false, bestEffortResolution = false, unstable_branch) {
4237
+ constructor(node, resolve, id, schema, skipRetry = false, bestEffortResolution = false, unstable_branch, callerStack) {
4194
4238
  this.node = node;
4195
4239
  this.id = id;
4196
4240
  this.schema = schema;
@@ -4244,6 +4288,8 @@ var SubscriptionScope = class _SubscriptionScope {
4244
4288
  this.triggerUpdate();
4245
4289
  };
4246
4290
  this.subscribers = /* @__PURE__ */ new Set();
4291
+ this.subscriberChangeCallbacks = /* @__PURE__ */ new Set();
4292
+ this.callerStack = callerStack;
4247
4293
  this.resolve = resolve;
4248
4294
  this.value = { type: CoValueLoadingState.LOADING, id };
4249
4295
  let lastUpdate;
@@ -4281,36 +4327,35 @@ var SubscriptionScope = class _SubscriptionScope {
4281
4327
  handleUpdate(update) {
4282
4328
  if (update === CoValueLoadingState.UNAVAILABLE) {
4283
4329
  if (this.value.type === CoValueLoadingState.LOADING) {
4284
- this.updateValue(
4285
- new JazzError(this.id, CoValueLoadingState.UNAVAILABLE, [
4286
- {
4287
- code: CoValueLoadingState.UNAVAILABLE,
4288
- message: "The value is unavailable",
4289
- params: {
4290
- id: this.id
4291
- },
4292
- path: []
4293
- }
4294
- ])
4295
- );
4330
+ const error = new JazzError(this.id, CoValueLoadingState.UNAVAILABLE, [
4331
+ {
4332
+ code: CoValueLoadingState.UNAVAILABLE,
4333
+ message: `Jazz Unavailable Error: unable to load ${this.id}`,
4334
+ params: {
4335
+ id: this.id
4336
+ },
4337
+ path: []
4338
+ }
4339
+ ]);
4340
+ this.updateValue(error);
4296
4341
  }
4297
4342
  this.triggerUpdate();
4298
4343
  return;
4299
4344
  }
4300
4345
  if (!hasAccessToCoValue(update)) {
4301
4346
  if (this.value.type !== CoValueLoadingState.UNAUTHORIZED) {
4302
- this.updateValue(
4303
- new JazzError(this.id, CoValueLoadingState.UNAUTHORIZED, [
4304
- {
4305
- code: CoValueLoadingState.UNAUTHORIZED,
4306
- message: `The current user (${this.node.getCurrentAgent().id}) is not authorized to access this value`,
4307
- params: {
4308
- id: this.id
4309
- },
4310
- path: []
4311
- }
4312
- ])
4313
- );
4347
+ const message = `Jazz Authorization Error: The current user (${this.node.getCurrentAgent().id}) is not authorized to access ${this.id}`;
4348
+ const error = new JazzError(this.id, CoValueLoadingState.UNAUTHORIZED, [
4349
+ {
4350
+ code: CoValueLoadingState.UNAUTHORIZED,
4351
+ message,
4352
+ params: {
4353
+ id: this.id
4354
+ },
4355
+ path: []
4356
+ }
4357
+ ]);
4358
+ this.updateValue(error);
4314
4359
  this.triggerUpdate();
4315
4360
  }
4316
4361
  return;
@@ -4372,6 +4417,48 @@ var SubscriptionScope = class _SubscriptionScope {
4372
4417
  if (this.value.type !== CoValueLoadingState.LOADED) return true;
4373
4418
  return this.pendingLoadedChildren.size === 0;
4374
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
+ }
4375
4462
  getUnloadedValue(reason) {
4376
4463
  if (this.unloadedValue?.$jazz.loadingState === reason) {
4377
4464
  return this.unloadedValue;
@@ -4383,20 +4470,19 @@ var SubscriptionScope = class _SubscriptionScope {
4383
4470
  getCurrentValue() {
4384
4471
  const rawValue = this.getCurrentRawValue();
4385
4472
  if (rawValue === CoValueLoadingState.UNAUTHORIZED || rawValue === CoValueLoadingState.UNAVAILABLE || rawValue === CoValueLoadingState.LOADING) {
4473
+ this.logError();
4386
4474
  return this.getUnloadedValue(rawValue);
4387
4475
  }
4388
4476
  return rawValue;
4389
4477
  }
4390
4478
  getCurrentRawValue() {
4391
4479
  if (this.value.type === CoValueLoadingState.UNAUTHORIZED || this.value.type === CoValueLoadingState.UNAVAILABLE) {
4392
- console.error(this.value.toString());
4393
4480
  return this.value.type;
4394
4481
  }
4395
4482
  if (!this.shouldSendUpdates()) {
4396
4483
  return CoValueLoadingState.LOADING;
4397
4484
  }
4398
4485
  if (this.errorFromChildren) {
4399
- console.error(this.errorFromChildren.toString());
4400
4486
  return this.errorFromChildren.type;
4401
4487
  }
4402
4488
  if (this.value.type === CoValueLoadingState.LOADED) {
@@ -4404,6 +4490,51 @@ var SubscriptionScope = class _SubscriptionScope {
4404
4490
  }
4405
4491
  return CoValueLoadingState.LOADING;
4406
4492
  }
4493
+ getCreationStackLines() {
4494
+ const stack = this.callerStack?.stack;
4495
+ if (!stack) {
4496
+ return "";
4497
+ }
4498
+ const creationStackLines = stack.split("\n").slice(2, 15);
4499
+ const creationAppFrame = creationStackLines.find(
4500
+ (line) => !line.includes("node_modules") && !line.includes("useCoValueSubscription") && !line.includes("useCoState") && !line.includes("useAccount") && !line.includes("jazz-tools")
4501
+ );
4502
+ let result = "\n\n";
4503
+ if (creationAppFrame) {
4504
+ result += "Subscription created ", result += creationAppFrame.trim();
4505
+ }
4506
+ result += "\nFull subscription creation stack:";
4507
+ for (const line of creationStackLines.slice(0, 8)) {
4508
+ result += "\n " + line.trim();
4509
+ }
4510
+ return result;
4511
+ }
4512
+ getError() {
4513
+ if (this.value.type === CoValueLoadingState.UNAUTHORIZED || this.value.type === CoValueLoadingState.UNAVAILABLE) {
4514
+ return this.value;
4515
+ }
4516
+ if (this.errorFromChildren) {
4517
+ return this.errorFromChildren;
4518
+ }
4519
+ }
4520
+ logError() {
4521
+ const error = this.getError();
4522
+ if (!error || this.lastErrorLogged === error) {
4523
+ return;
4524
+ }
4525
+ if (error.type === CoValueLoadingState.UNAVAILABLE && this.skipRetry) {
4526
+ return;
4527
+ }
4528
+ this.lastErrorLogged = error;
4529
+ if (isCustomErrorReportingEnabled()) {
4530
+ captureError(new Error(error.toString(), { cause: this.callerStack }), {
4531
+ getPrettyStackTrace: () => this.getCreationStackLines(),
4532
+ jazzError: error
4533
+ });
4534
+ } else {
4535
+ console.error(`${error.toString()}${this.getCreationStackLines()}`);
4536
+ }
4537
+ }
4407
4538
  triggerUpdate() {
4408
4539
  if (!this.shouldSendUpdates()) return;
4409
4540
  if (!this.dirty) return;
@@ -4418,14 +4549,37 @@ var SubscriptionScope = class _SubscriptionScope {
4418
4549
  }
4419
4550
  this.dirty = false;
4420
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
+ }
4421
4569
  subscribe(listener) {
4422
4570
  this.subscribers.add(listener);
4571
+ this.notifySubscriberChange();
4423
4572
  return () => {
4424
4573
  this.subscribers.delete(listener);
4574
+ this.notifySubscriberChange();
4425
4575
  };
4426
4576
  }
4427
4577
  setListener(listener) {
4578
+ const hadListener = this.subscribers.has(listener);
4428
4579
  this.subscribers.add(listener);
4580
+ if (!hadListener) {
4581
+ this.notifySubscriberChange();
4582
+ }
4429
4583
  this.triggerUpdate();
4430
4584
  }
4431
4585
  subscribeToKey(key) {
@@ -4563,7 +4717,7 @@ var SubscriptionScope = class _SubscriptionScope {
4563
4717
  new JazzError(void 0, CoValueLoadingState.UNAVAILABLE, [
4564
4718
  {
4565
4719
  code: "validationError",
4566
- message: `The ref on position ${key} requested on ${stream.constructor.name} is missing`,
4720
+ message: `Jazz Validation Error: The ref on position ${key} is missing`,
4567
4721
  params: {},
4568
4722
  path: [key]
4569
4723
  }
@@ -4615,7 +4769,7 @@ var SubscriptionScope = class _SubscriptionScope {
4615
4769
  new JazzError(void 0, CoValueLoadingState.UNAVAILABLE, [
4616
4770
  {
4617
4771
  code: "validationError",
4618
- message: `The ref ${key} requested on ${map.constructor.name} is missing`,
4772
+ message: `Jazz Validation Error: The ref ${key} is required but missing`,
4619
4773
  params: {},
4620
4774
  path: [key]
4621
4775
  }
@@ -4646,7 +4800,7 @@ var SubscriptionScope = class _SubscriptionScope {
4646
4800
  new JazzError(void 0, CoValueLoadingState.UNAVAILABLE, [
4647
4801
  {
4648
4802
  code: "validationError",
4649
- message: `The ref on position ${key} requested on ${list.constructor.name} is missing`,
4803
+ message: `Jazz Validation Error: The ref on position ${key} is required but missing`,
4650
4804
  params: {},
4651
4805
  path: [key]
4652
4806
  }
@@ -4694,7 +4848,12 @@ var SubscriptionScope = class _SubscriptionScope {
4694
4848
  destroy() {
4695
4849
  this.closed = true;
4696
4850
  this.subscription.unsubscribe();
4851
+ const hadSubscribers = this.subscribers.size > 0;
4697
4852
  this.subscribers.clear();
4853
+ if (hadSubscribers) {
4854
+ this.notifySubscriberChange();
4855
+ }
4856
+ this.subscriberChangeCallbacks.clear();
4698
4857
  this.childNodes.forEach((child) => child.destroy());
4699
4858
  }
4700
4859
  };
@@ -6310,6 +6469,177 @@ var InMemoryKVStore = class {
6310
6469
  }
6311
6470
  };
6312
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
+
6313
6643
  // src/tools/implementation/ContextManager.ts
6314
6644
  function getAnonymousFallback() {
6315
6645
  const context = createAnonymousJazzContext({
@@ -6343,6 +6673,7 @@ var JazzContextManager = class {
6343
6673
  return;
6344
6674
  }
6345
6675
  this.authenticatingAccountID = null;
6676
+ this.subscriptionCache.clear();
6346
6677
  await this.props.onLogOut?.();
6347
6678
  if (this.props.logOutReplacement) {
6348
6679
  await this.props.logOutReplacement();
@@ -6440,6 +6771,7 @@ var JazzContextManager = class {
6440
6771
  };
6441
6772
  KvStoreContext.getInstance().initialize(this.getKvStore());
6442
6773
  this.authSecretStorage = new AuthSecretStorage(opts?.authSecretStorageKey);
6774
+ this.subscriptionCache = new SubscriptionCache();
6443
6775
  if (opts?.useAnonymousFallback) {
6444
6776
  this.value = getAnonymousFallback();
6445
6777
  }
@@ -6468,6 +6800,7 @@ var JazzContextManager = class {
6468
6800
  throw new Error("Not implemented");
6469
6801
  }
6470
6802
  async updateContext(props, context, authProps) {
6803
+ this.subscriptionCache.clear();
6471
6804
  if (!this.keepContextOpen) {
6472
6805
  this.context?.done();
6473
6806
  }
@@ -6505,6 +6838,9 @@ var JazzContextManager = class {
6505
6838
  getAuthenticatingAccountID() {
6506
6839
  return this.authenticatingAccountID;
6507
6840
  }
6841
+ getSubscriptionScopeCache() {
6842
+ return this.subscriptionCache;
6843
+ }
6508
6844
  async handleAnonymousAccountMigration(prevContext) {
6509
6845
  if (!this.props) {
6510
6846
  throw new Error("Props required");
@@ -6749,13 +7085,9 @@ function subscribeToCoValue(cls, id, options, listener) {
6749
7085
  switch (value.$jazz.loadingState) {
6750
7086
  case CoValueLoadingState.UNAVAILABLE:
6751
7087
  options.onUnavailable?.(value);
6752
- if (!options.skipRetry) {
6753
- console.error(value.toString());
6754
- }
6755
7088
  break;
6756
7089
  case CoValueLoadingState.UNAUTHORIZED:
6757
7090
  options.onUnauthorized?.(value);
6758
- console.error(value.toString());
6759
7091
  break;
6760
7092
  }
6761
7093
  };
@@ -6898,17 +7230,14 @@ async function exportCoValue(cls, id, options) {
6898
7230
  options.unstable_branch
6899
7231
  );
6900
7232
  const value = await new Promise((resolve2) => {
6901
- rootNode.setListener((value2) => {
6902
- if (value2.type === CoValueLoadingState.UNAVAILABLE) {
6903
- resolve2(null);
6904
- console.error(value2.toString());
6905
- } else if (value2.type === CoValueLoadingState.UNAUTHORIZED) {
7233
+ rootNode.setListener(() => {
7234
+ const value2 = rootNode.getCurrentValue();
7235
+ if (value2.$isLoaded) {
7236
+ resolve2(value2);
7237
+ } else if (value2.$jazz.loadingState === CoValueLoadingState.UNAVAILABLE || value2.$jazz.loadingState === CoValueLoadingState.UNAUTHORIZED) {
6906
7238
  resolve2(null);
6907
- console.error(value2.toString());
6908
- } else if (value2.type === CoValueLoadingState.LOADED) {
6909
- resolve2(value2.value);
7239
+ rootNode.destroy();
6910
7240
  }
6911
- rootNode.destroy();
6912
7241
  });
6913
7242
  });
6914
7243
  if (!value) {
@@ -7046,6 +7375,9 @@ export {
7046
7375
  Encoders,
7047
7376
  coField,
7048
7377
  CoValueLoadingState,
7378
+ enableCaptureErrorCause,
7379
+ setCustomErrorReporter,
7380
+ captureStack,
7049
7381
  SubscriptionScope,
7050
7382
  randomSessionProvider,
7051
7383
  createJazzContextFromExistingCredentials,
@@ -7062,4 +7394,4 @@ export {
7062
7394
  JazzContextManager
7063
7395
  };
7064
7396
  /* istanbul ignore file -- @preserve */
7065
- //# sourceMappingURL=chunk-CUS6O5NE.js.map
7397
+ //# sourceMappingURL=chunk-FFEEPZEG.js.map