fix(server): config & update handle (#15173)

#### PR Dependency Tree


* **PR #15173** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added native document update validation to check incoming Yjs updates
for decodability before applying them.
* Introduced support for validation timeouts and cancellation during
update checks.
* Blob maintenance jobs now detect when object storage is unavailable
and skip related work gracefully.

* **Bug Fixes**
* Invalid (and oversized) updates are now filtered out earlier during
document ingestion.
* Background blob maintenance continues processing other work even if
one workspace fails.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2026-06-29 22:59:17 +08:00
committed by GitHub
parent 1b9e21f2de
commit a1363b3873
13 changed files with 517 additions and 60 deletions
+51
View File
@@ -162,6 +162,57 @@ import type {
export const mergeUpdatesInApplyWay = serverNativeModule.mergeUpdatesInApplyWay;
export async function validateDocUpdate(
update: Buffer,
options: { signal?: AbortSignal; timeoutMs?: number } = {}
): Promise<boolean> {
const signals = [];
if (options.signal) {
signals.push(options.signal);
}
if (options.timeoutMs !== undefined) {
signals.push(AbortSignal.timeout(options.timeoutMs));
}
const signal =
signals.length === 0
? undefined
: signals.length === 1
? signals[0]
: AbortSignal.any(signals);
if (signal?.aborted) {
throw signal.reason;
}
return await new Promise<boolean>((resolve, reject) => {
let settled = false;
const settle = (callback: () => void) => {
if (settled) return;
settled = true;
callback();
};
const onAbort = () => {
settle(() =>
reject(
signal?.reason instanceof Error
? signal.reason
: new Error('Doc update validation aborted')
)
);
};
signal?.addEventListener('abort', onAbort, { once: true });
serverNativeModule
.validateDocUpdate(update)
.then(
result => settle(() => resolve(result)),
error => settle(() => reject(error))
)
.finally(() => {
signal?.removeEventListener('abort', onAbort);
});
});
}
export const verifyChallengeResponse = async (
response: any,
bits: number,