querysub 0.344.0 → 0.345.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 +1 -1
- package/src/2-proxy/PathValueProxyWatcher.ts +1 -0
- package/src/3-path-functions/PathFunctionHelpers.ts +1 -1
- package/src/3-path-functions/PathFunctionRunner.ts +3 -0
- package/src/3-path-functions/syncSchema.ts +4 -1
- package/src/4-deploy/edgeClientWatcher.tsx +76 -82
- package/src/4-querysub/querysubPrediction.ts +1 -1
package/package.json
CHANGED
|
@@ -1636,6 +1636,7 @@ export class PathValueProxyWatcher {
|
|
|
1636
1636
|
// The calls have to happen after our local writes. This is because they are likely to
|
|
1637
1637
|
// influence the local writes, and we don't want our local writes to be always invalidated
|
|
1638
1638
|
call.runAtTime = getNextTime();
|
|
1639
|
+
call.fromProxy = watcher.debugName;
|
|
1639
1640
|
logErrors(runCall(call, metadata));
|
|
1640
1641
|
watcher.options.onCallCommit?.(call, metadata);
|
|
1641
1642
|
}
|
|
@@ -121,7 +121,7 @@ export function interceptCallsBase<T>(
|
|
|
121
121
|
}
|
|
122
122
|
interceptCalls.declare(interceptCallsBase);
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
/** Writes the function call allowing interceptors to capture it (vs runCall which just runs it). */
|
|
125
125
|
export function writeFunctionCall(config: {
|
|
126
126
|
domainName: string;
|
|
127
127
|
moduleId: string;
|
|
@@ -91,6 +91,9 @@ export interface CallSpec {
|
|
|
91
91
|
callerIP: string;
|
|
92
92
|
runAtTime: Time;
|
|
93
93
|
|
|
94
|
+
// Not just used for debugging, also used to add special proxy-related warnings.
|
|
95
|
+
fromProxy?: string;
|
|
96
|
+
|
|
94
97
|
filterable?: Filterable;
|
|
95
98
|
}
|
|
96
99
|
export function debugCallSpec(spec: CallSpec): string {
|
|
@@ -48,6 +48,9 @@ export type FunctionMetadata<F = unknown> = {
|
|
|
48
48
|
*/
|
|
49
49
|
delayCommit?: boolean;
|
|
50
50
|
|
|
51
|
+
/** By default, we try to finish calls in the start order when using Querysub.commitAsync, unless the caller explicitly says not to. However, if this is set, then we won't have this call finish or cause other calls to be finished in the start order. This makes locking less safe, but can be useful for long-running functions that shouldn't block other functions and which the order doesn't matter. */
|
|
52
|
+
noFinishInStartOrder?: boolean;
|
|
53
|
+
|
|
51
54
|
/** Too many locks can lag the server, and eventually cause crashes. Consider using Querysub.noLocks(() => ...) around code that is accessing too many values, assuming you don't want to lock them. However, if absolutely required, you can override max locks to allow as many locks to be created as you want until the server crashses... */
|
|
52
55
|
maxLocksOverride?: number;
|
|
53
56
|
};
|
|
@@ -363,7 +366,7 @@ export function syncSchema<Schema>(schema?: Schema2): SyncSchemaResult<Schema> {
|
|
|
363
366
|
moduleId,
|
|
364
367
|
functionId: name,
|
|
365
368
|
args,
|
|
366
|
-
metadata
|
|
369
|
+
metadata: metadata
|
|
367
370
|
});
|
|
368
371
|
}, {
|
|
369
372
|
debug() {
|
|
@@ -18,6 +18,8 @@ import { Button } from "../library-components/Button";
|
|
|
18
18
|
import { updateRootDiscoveryLocation } from "../-f-node-discovery/NodeDiscovery";
|
|
19
19
|
|
|
20
20
|
const SWITCH_SERVER_TIMEOUT = timeInSecond * 15;
|
|
21
|
+
const MAX_DISPLAY_INTERVAL = timeInMinute * 5;
|
|
22
|
+
const FINAL_DELAY = timeInSecond * 30;
|
|
21
23
|
|
|
22
24
|
let lastHashServer = "";
|
|
23
25
|
export function startEdgeNotifier() {
|
|
@@ -61,113 +63,105 @@ const notifyClients = throttleFunction(timeInMinute, async function notifyClient
|
|
|
61
63
|
// Track current notification state
|
|
62
64
|
let currentNotification: { close: () => void } | null = null;
|
|
63
65
|
let curHash = "";
|
|
66
|
+
let lastShownTime = 0;
|
|
64
67
|
function onLiveHashChange(liveHash: string, refreshThresholdTime: number) {
|
|
65
68
|
console.log(blue(`Received client liveHash ${liveHash}, prev hash: ${curHash}`));
|
|
66
69
|
if (liveHash === curHash) return;
|
|
67
70
|
let prevHash = curHash;
|
|
68
71
|
// Don't notify the user right away. Hopefully they refresh naturally, and we never have to notify them at all!
|
|
69
72
|
// Also, refresh BEFORE the server dies, not exactly when it is about to die
|
|
70
|
-
let
|
|
73
|
+
let delays = [0.4, 0.75, 1].map(x => delay(x * refreshThresholdTime));
|
|
74
|
+
|
|
71
75
|
console.log(blue(`Client liveHash changed ${liveHash}, prev hash: ${prevHash}`));
|
|
72
|
-
// If we are replacing an already existing notification, don't show immediately
|
|
73
|
-
let skipFirst = false;
|
|
74
|
-
if (currentNotification) {
|
|
75
|
-
currentNotification.close();
|
|
76
|
-
currentNotification = null;
|
|
77
|
-
skipFirst = true;
|
|
78
|
-
}
|
|
79
|
-
curHash = liveHash;
|
|
80
76
|
|
|
81
|
-
|
|
77
|
+
curHash = liveHash;
|
|
82
78
|
|
|
83
79
|
// Start notification loop
|
|
84
80
|
void (async () => {
|
|
85
81
|
// Show notifications at intervals
|
|
86
|
-
for (let
|
|
82
|
+
for (let delayTime of delays) {
|
|
83
|
+
await delayTime;
|
|
87
84
|
// Don't show if a newer notification is active
|
|
88
85
|
if (curHash !== liveHash) return;
|
|
89
86
|
|
|
90
|
-
let waitDuration = (notifyIntervals[i + 1] - notifyIntervals[i]) * duration;
|
|
91
|
-
// If the duration is short, and it's not the last one, skip it
|
|
92
|
-
if (i < notifyIntervals.length - 2 && waitDuration <= 30 * 1000) continue;
|
|
93
|
-
|
|
94
87
|
// Update the URL override for manual refreshes
|
|
95
88
|
if (!liveHash.startsWith("forced")) {
|
|
96
89
|
Querysub.localCommit(() => {
|
|
97
90
|
liveHashOverrideURL.value = { liveHash, time: Date.now() };
|
|
98
91
|
});
|
|
99
92
|
}
|
|
100
|
-
if (!skipFirst) {
|
|
101
|
-
if (currentNotification) {
|
|
102
|
-
currentNotification.close();
|
|
103
|
-
currentNotification = null;
|
|
104
|
-
}
|
|
105
|
-
// Show notification modal
|
|
106
|
-
let nextNotification = {
|
|
107
|
-
close: showModal({
|
|
108
|
-
onClose: () => {
|
|
109
|
-
if (currentNotification !== nextNotification) return;
|
|
110
|
-
currentNotification = null;
|
|
111
|
-
},
|
|
112
|
-
content: (
|
|
113
|
-
<div
|
|
114
|
-
title={`Live Hash: ${liveHash}, prev hash: ${prevHash}`}
|
|
115
|
-
className={
|
|
116
|
-
css.vbox(10).pad(20)
|
|
117
|
-
.hsla(0, 0, 0, 0.8)
|
|
118
|
-
.position("fixed")
|
|
119
|
-
.bottom(10)
|
|
120
|
-
.right(10)
|
|
121
|
-
.zIndex(1000)
|
|
122
|
-
+ " keepModalsOpen"
|
|
123
|
-
}
|
|
124
|
-
>
|
|
125
|
-
<div className={css.vbox(10).maxWidth(250)}>
|
|
126
|
-
<h3 className={css.margin(0)}>Server Update Available</h3>
|
|
127
|
-
<div>The server has been updated. Please refresh the page to ensure you don't experience compatibility issues.</div>
|
|
128
|
-
{i !== notifyIntervals.length - 2 && <div>This notification will be shown again at {formatNiceDateTime(Date.now() + waitDuration)}</div>}
|
|
129
|
-
{i === notifyIntervals.length - 2 && <div>The page will automatically refresh at {formatNiceDateTime(Date.now() + waitDuration)}</div>}
|
|
130
|
-
</div>
|
|
131
|
-
<div className={css.hbox(10).justifyContent("flex-end")}>
|
|
132
|
-
<button
|
|
133
|
-
className={css.pad(8, 16).hsl(200, 50, 50).color("white").pointer}
|
|
134
|
-
onClick={(e) => {
|
|
135
|
-
if (!liveHash.startsWith("forced")) {
|
|
136
|
-
Querysub.localCommit(() => {
|
|
137
|
-
liveHashOverrideURL.value = { liveHash, time: Date.now() };
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
window.location.reload();
|
|
141
|
-
}}
|
|
142
|
-
>
|
|
143
|
-
Refresh Now
|
|
144
|
-
</button>
|
|
145
|
-
<button
|
|
146
|
-
className={css.pad(8, 16).pointer}
|
|
147
|
-
onClick={(e) => {
|
|
148
|
-
if (currentNotification) {
|
|
149
|
-
currentNotification.close();
|
|
150
|
-
currentNotification = null;
|
|
151
|
-
}
|
|
152
|
-
}}
|
|
153
|
-
>
|
|
154
|
-
Dismiss
|
|
155
|
-
</button>
|
|
156
|
-
</div>
|
|
157
|
-
</div>
|
|
158
|
-
)
|
|
159
|
-
}).close
|
|
160
|
-
};
|
|
161
|
-
currentNotification = nextNotification;
|
|
162
|
-
}
|
|
163
|
-
skipFirst = false;
|
|
164
93
|
|
|
165
|
-
|
|
166
|
-
|
|
94
|
+
let timeSinceLastShown = Date.now() - lastShownTime;
|
|
95
|
+
let isLastDelay = delayTime === delays.at(-1);
|
|
96
|
+
if (timeSinceLastShown < MAX_DISPLAY_INTERVAL && !isLastDelay) continue;
|
|
97
|
+
|
|
98
|
+
lastShownTime = Date.now();
|
|
99
|
+
|
|
100
|
+
if (currentNotification) {
|
|
101
|
+
currentNotification.close();
|
|
102
|
+
currentNotification = null;
|
|
103
|
+
}
|
|
104
|
+
// Show notification modal
|
|
105
|
+
let nextNotification = {
|
|
106
|
+
close: showModal({
|
|
107
|
+
onClose: () => {
|
|
108
|
+
if (currentNotification !== nextNotification) return;
|
|
109
|
+
currentNotification = null;
|
|
110
|
+
},
|
|
111
|
+
content: (
|
|
112
|
+
<div
|
|
113
|
+
title={`Live Hash: ${liveHash}, prev hash: ${prevHash}`}
|
|
114
|
+
className={
|
|
115
|
+
css.vbox(10).pad(20)
|
|
116
|
+
.hsla(0, 0, 0, 0.8)
|
|
117
|
+
.position("fixed")
|
|
118
|
+
.bottom(10)
|
|
119
|
+
.right(10)
|
|
120
|
+
.zIndex(1000)
|
|
121
|
+
+ " keepModalsOpen"
|
|
122
|
+
}
|
|
123
|
+
>
|
|
124
|
+
<div className={css.vbox(10).maxWidth(250)}>
|
|
125
|
+
<h3 className={css.margin(0)}>Server Update Available</h3>
|
|
126
|
+
<div>The server has been updated. Please refresh the page to ensure you don't experience compatibility issues.</div>
|
|
127
|
+
{isLastDelay && <div>The page will automatically refresh shortly</div>}
|
|
128
|
+
</div>
|
|
129
|
+
<div className={css.hbox(10).justifyContent("flex-end")}>
|
|
130
|
+
<button
|
|
131
|
+
className={css.pad(8, 16).hsl(200, 50, 50).color("white").pointer}
|
|
132
|
+
onClick={(e) => {
|
|
133
|
+
if (!liveHash.startsWith("forced")) {
|
|
134
|
+
Querysub.localCommit(() => {
|
|
135
|
+
liveHashOverrideURL.value = { liveHash, time: Date.now() };
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
window.location.reload();
|
|
139
|
+
}}
|
|
140
|
+
>
|
|
141
|
+
Refresh Now
|
|
142
|
+
</button>
|
|
143
|
+
<button
|
|
144
|
+
className={css.pad(8, 16).pointer}
|
|
145
|
+
onClick={(e) => {
|
|
146
|
+
if (currentNotification) {
|
|
147
|
+
currentNotification.close();
|
|
148
|
+
currentNotification = null;
|
|
149
|
+
}
|
|
150
|
+
}}
|
|
151
|
+
>
|
|
152
|
+
Dismiss
|
|
153
|
+
</button>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
)
|
|
157
|
+
}).close
|
|
158
|
+
};
|
|
159
|
+
currentNotification = nextNotification;
|
|
167
160
|
}
|
|
168
161
|
|
|
169
162
|
// Only force refresh if this is still the current notification
|
|
170
|
-
if (curHash === liveHash) {
|
|
163
|
+
if (curHash === liveHash && currentNotification) {
|
|
164
|
+
await delay(FINAL_DELAY);
|
|
171
165
|
window.location.reload();
|
|
172
166
|
}
|
|
173
167
|
})();
|
|
@@ -418,7 +418,7 @@ export function getCallWrites(config: {
|
|
|
418
418
|
|
|
419
419
|
let finishInStartOrder: number | boolean | undefined;
|
|
420
420
|
|
|
421
|
-
if (config.useFinishReordering) {
|
|
421
|
+
if (config.useFinishReordering && !config.metadata?.noFinishInStartOrder && call.fromProxy) {
|
|
422
422
|
let triggerCaller = getCurrentCallCreationProxy();
|
|
423
423
|
if (!triggerCaller) {
|
|
424
424
|
require("debugbreak")(2);
|