Skip to content

Commit 99c2dc9

Browse files
authored
Merge branch 'main' into comments
2 parents 5ab3e4b + f507c72 commit 99c2dc9

8 files changed

Lines changed: 541 additions & 13 deletions

File tree

blocks/canvas/ew-editor-wysiwyg/ew-editor-wysiwyg.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ export class EwEditorWysiwyg extends LitElement {
4646
static properties = {
4747
ctx: { type: Object },
4848
_cookieReady: { state: true },
49-
_loading: { state: true },
5049
};
5150

5251
connectedCallback() {
@@ -98,10 +97,8 @@ export class EwEditorWysiwyg extends LitElement {
9897

9998
_syncCanvasVisibility() {
10099
const view = this._canvasActiveView ?? 'layout';
101-
const portReady = this.hasAttribute(WYSIWYG_PORT_READY_ATTR);
102100
const showWysiwyg = view === 'layout' || view === 'split';
103101
this.hidden = !showWysiwyg;
104-
this._loading = showWysiwyg && !portReady;
105102
hideSelectionToolbar();
106103
}
107104

@@ -223,7 +220,7 @@ export class EwEditorWysiwyg extends LitElement {
223220
`;
224221
}
225222
return html`
226-
<div class="ew-editor-wysiwyg-surface" ?hidden=${this._loading}>
223+
<div class="ew-editor-wysiwyg-surface">
227224
${body}
228225
</div>
229226
`;

blocks/edit/prose/index.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ import { forceSave } from './forcesave.js';
3131
import { createCommentsController } from './plugins/comments/helpers/controller.js';
3232
import { createCommentsStore } from './plugins/comments/helpers/comments-store.js';
3333

34+
// Rapid-reconnect guard (COR-44): y-websocket resets its backoff counter on
35+
// every successful onopen, so a close that follows a brief successful
36+
// handshake reschedules at 100ms. Single users behind corporate proxies can
37+
// sustain thousands of WS upgrades/sec/IP through this path. The guard below
38+
// detects open-then-close cycles shorter than MIN_HEALTHY_SESSION_MS and
39+
// applies a manual exponential backoff before letting the provider reconnect.
40+
const MIN_HEALTHY_SESSION_MS = 5000;
41+
const SHORT_SESSION_BASE_MS = 1000;
42+
const SHORT_SESSION_MAX_MS = 30000;
43+
3444
async function checkDoc(path) {
3545
return daFetch(path, { method: 'HEAD' });
3646
}
@@ -58,6 +68,13 @@ export async function createConnection(path) {
5868
provider.maxBackoffTime = 30000;
5969

6070
let lastSentToken = token || null;
71+
let lastOpenAt = 0;
72+
let failedShortSessions = 0;
73+
74+
provider.on('status', (st) => {
75+
if (st?.status === 'connected') lastOpenAt = Date.now();
76+
});
77+
6178
provider.on('connection-close', async (event) => {
6279
if (event?.code === 4401 || event?.code === 4403) {
6380
provider.shouldConnect = false;
@@ -80,6 +97,29 @@ export async function createConnection(path) {
8097
provider.connect();
8198
return;
8299
}
100+
101+
// Non-auth close: rapid-reconnect guard. y-websocket's own 100ms
102+
// setTimeout(setupWS) still fires from onclose, but provider.disconnect()
103+
// flips shouldConnect=false so that timer's setupWS call no-ops. The
104+
// manual setTimeout below is what re-arms the connection.
105+
const sessionMs = lastOpenAt ? Date.now() - lastOpenAt : 0;
106+
lastOpenAt = 0;
107+
if (sessionMs >= MIN_HEALTHY_SESSION_MS) {
108+
failedShortSessions = 0;
109+
} else {
110+
const delay = Math.min(
111+
2 ** failedShortSessions * SHORT_SESSION_BASE_MS,
112+
SHORT_SESSION_MAX_MS,
113+
);
114+
failedShortSessions += 1;
115+
provider.shouldConnect = false;
116+
provider.disconnect();
117+
setTimeout(() => {
118+
provider.shouldConnect = true;
119+
provider.connect();
120+
}, delay);
121+
}
122+
83123
const fresh = await getAuthToken();
84124
provider.protocols = fresh ? ['yjs', fresh] : ['yjs'];
85125
lastSentToken = fresh;

blocks/sheet/sheet.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import getPathDetails from '../shared/pathDetails.js';
33
import { getNx } from '../../scripts/utils.js';
44
import '../edit/da-title/da-title.js';
55
import { getData } from './utils/index.js';
6-
import { staleCheck, showDaDialog } from './utils/utils.js';
6+
import { staleCheck, showDaDialog, restoreVersion } from './utils/utils.js';
77
import { convertSheets } from '../edit/utils/helpers.js';
88

99
const { default: getStyle } = await import(`${getNx()}/utils/styles.js`);
@@ -52,10 +52,7 @@ class DaSheetPanes extends LitElement {
5252
verReview.addEventListener('restore', async () => {
5353
const daTitle = document.querySelector('da-title');
5454
const daSheet = document.querySelector('.da-sheet');
55-
56-
const initSheet = (await import('./utils/index.js')).default;
57-
daTitle.sheet = await initSheet(daSheet, verReview.data);
58-
staleCheck.markSynced(verReview.data);
55+
await restoreVersion(daTitle, daSheet, verReview.data);
5956
verReview.remove();
6057
});
6158

blocks/sheet/utils/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ function resetSheets(el) {
1616
if (!el.jexcel) return;
1717
delete el.jexcel;
1818
el.innerHTML = '';
19-
el.className = '';
19+
el.classList.remove('jexcel_tabs');
2020
}
2121

2222
function finishSetup(el, data) {

blocks/sheet/utils/utils.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ export const saveSheets = async (sheets) => {
9393

9494
const debouncedSaveSheets = debounce(saveSheets, DEBOUNCE_TIME);
9595

96+
export async function restoreVersion(daTitle, daSheet, versionData) {
97+
const initSheet = (await import('./index.js')).default;
98+
daTitle.sheet = await initSheet(daSheet, versionData);
99+
return saveSheets(daSheet.jexcel);
100+
}
101+
96102
export function handleSave(jexcel, view) {
97103
// markEdited must precede the config bail so config edits still mark dirty for stale-detection.
98104
staleCheck.markEdited();

0 commit comments

Comments
 (0)