querysub 0.167.0 → 0.169.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "querysub",
3
- "version": "0.167.0",
3
+ "version": "0.169.0",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "note1": "note on node-forge fork, see https://github.com/digitalbazaar/forge/issues/744 for details",
@@ -1088,69 +1088,71 @@ export class PathValueProxyWatcher {
1088
1088
  try {
1089
1089
  let rawResult: Result;
1090
1090
  const handling = watcher.options.nestedCalls;
1091
+ let curFunction = baseFunction;
1091
1092
  if (handling === "inline") {
1092
- rawResult = inlineNestedCalls(() => {
1093
+ curFunction = () => inlineNestedCalls(baseFunction);
1094
+ }
1095
+ rawResult = interceptCalls({
1096
+ onCall(call, metadata) {
1097
+ if (PathValueProxyWatcher.BREAK_ON_CALL.size > 0 && !watcher.hasAnyUnsyncedAccesses()) {
1098
+ let hash = getPathStr2(call.ModuleId, call.FunctionId);
1099
+ if (PathValueProxyWatcher.BREAK_ON_CALL.has(hash)) {
1100
+ const unwatch = () => removeMatches(PathValueProxyWatcher.BREAK_ON_CALL, hash);
1101
+ debugger;
1102
+ unwatch;
1103
+ }
1104
+ }
1105
+ if (!watcher.options.canWrite) {
1106
+ throw new Error(`Cannot call a synced function in a watcher which does not have write permissions. If you want to call a function, you must also have write permissions.`);
1107
+ }
1108
+ if (handling === "throw") {
1109
+ // TODO: Support making inline calls, which is useful as it will check permissions. Although, it can
1110
+ // easily be slow, and adds a lot of complexity, so... maybe not... maybe always force the app
1111
+ // to do the permissions checks if they want them
1112
+ throw new Error(`Nested synced function calls are not allowed. Call the function directly, or use Querysub.onCommitFinished to wait for the function to finish.`);
1113
+ } else if (handling === "after" || handling === undefined) {
1114
+
1115
+ // We need to wait for predictions to finish, otherwise we run into situations
1116
+ // where we call a function which should change a parameter we want to pass
1117
+ // to another function, but because the first call didn't predict, the second
1118
+ // call gets a different values, causing all kinds of issues.
1119
+ if (watcher.pendingCalls.length === 0) {
1120
+ let waitPromise = onAllPredictionsFinished();
1121
+ if (waitPromise) {
1122
+ proxyWatcher.triggerOnPromiseFinish(waitPromise, {
1123
+ waitReason: "Waiting for predictions to finish",
1124
+ });
1125
+ }
1126
+ }
1127
+
1128
+ watcher.pendingCalls.push({ call, metadata });
1129
+ } else if (handling === "ignore") {
1130
+ } else if (handling === "inline") {
1131
+ throw new Error(`inlineNestedCalls should have prevented this call from being passed to us`);
1132
+ } else {
1133
+ let unhandled: never = handling;
1134
+ throw new Error(`Invalid handling type ${handling}`);
1135
+ }
1136
+ },
1137
+ code() {
1093
1138
  return authorityStorage.temporaryOverride(options.overrides, () =>
1094
1139
  runCodeWithDatabase(proxy, baseFunction)
1095
1140
  );
1096
- });
1097
- } else {
1098
- rawResult = interceptCalls({
1099
- onCall(call, metadata) {
1100
- if (PathValueProxyWatcher.BREAK_ON_CALL.size > 0 && !watcher.hasAnyUnsyncedAccesses()) {
1101
- let hash = getPathStr2(call.ModuleId, call.FunctionId);
1102
- if (PathValueProxyWatcher.BREAK_ON_CALL.has(hash)) {
1103
- const unwatch = () => removeMatches(PathValueProxyWatcher.BREAK_ON_CALL, hash);
1104
- debugger;
1105
- unwatch;
1106
- }
1107
- }
1108
- if (!watcher.options.canWrite) {
1109
- throw new Error(`Cannot call a synced function in a watcher which does not have write permissions. If you want to call a function, you must also have write permissions.`);
1110
- }
1111
- if (handling === "throw") {
1112
- // TODO: Support making inline calls, which is useful as it will check permissions. Although, it can
1113
- // easily be slow, and adds a lot of complexity, so... maybe not... maybe always force the app
1114
- // to do the permissions checks if they want them
1115
- throw new Error(`Nested synced function calls are not allowed. Call the function directly, or use Querysub.onCommitFinished to wait for the function to finish.`);
1116
- } else if (handling === "after" || handling === undefined) {
1117
-
1118
- // We need to wait for predictions to finish, otherwise we run into situations
1119
- // where we call a function which should change a parameter we want to pass
1120
- // to another function, but because the first call didn't predict, the second
1121
- // call gets a different values, causing all kinds of issues.
1122
- if (watcher.pendingCalls.length === 0) {
1123
- let waitPromise = onAllPredictionsFinished();
1124
- if (waitPromise) {
1125
- proxyWatcher.triggerOnPromiseFinish(waitPromise, {
1126
- waitReason: "Waiting for predictions to finish",
1127
- });
1128
- }
1129
- }
1141
+ },
1142
+ }) as Result;
1130
1143
 
1131
- watcher.pendingCalls.push({ call, metadata });
1132
- } else if (handling === "ignore") {
1133
- } else {
1134
- let unhandled: never = handling;
1135
- throw new Error(`Invalid handling type ${handling}`);
1136
- }
1137
- },
1138
- code() {
1139
- return authorityStorage.temporaryOverride(options.overrides, () =>
1140
- runCodeWithDatabase(proxy, baseFunction)
1141
- );
1142
- },
1143
- }) as Result;
1144
+ // NOTE: Deep clone non-local paths. It's too confusing for a partial object to be returned. Any issues caused by
1145
+ // this (aka, returning the entire database), would also happen if we manually added deep clones before
1146
+ // we returned values (and both should be throttled at a framework level so we don't break the database).
1147
+ // - For local paths there is a risk that there are functions
1148
+ try {
1149
+ rawResult = deepCloneCborx(rawResult);
1150
+ } catch {
1151
+ // Unfortunately, cborx throws on functions.
1152
+ // TODO: Use a recursive clone technique that doesn't throw on functions
1153
+ rawResult = atomicObjectRead(rawResult);
1144
1154
  }
1145
1155
 
1146
- // We use atomic object read, as our callers don't want a proxy.
1147
- // If they want to get a full object, they will have to destructure it themselves
1148
- // (as for us to destructure it would require further synchronization, which...
1149
- // is just annoying, and so we won't implement that unless it becomes very useful).
1150
- // (Also, if the result is a proxy is confuses promises into thinking it is another promise,
1151
- // which is annoying).
1152
- rawResult = atomicObjectRead(rawResult);
1153
-
1154
1156
  result = { result: rawResult };
1155
1157
  watcher.consecutiveErrors = 0;
1156
1158
  } catch (e: any) {