mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 09:36:08 +08:00
bump version
This commit is contained in:
8 files changed
+82
-59
No files matched your search
@@ -111,6 +111,18 @@ Hydro 用户群:1085853538
|
||||
<details>
|
||||
<summary><h2>更新日志(点击展开)</h2></summary>
|
||||
|
||||
### Hydro 4.14.0 / UI 4.53.0
|
||||
- core: 修复能够越权查看隐藏题目的问题 [security]
|
||||
- ui: 优化提交记录详情富文本展示
|
||||
- ui: 支持头像缓存
|
||||
- ui: 禁止文本越界显示
|
||||
- vjudge: codeforces: 优化提交 ID 获取
|
||||
- ui: 默认禁用 sentry
|
||||
- core: 支持隐藏训练左侧用户栏
|
||||
- core: cli: 支持 eval
|
||||
- ui: 添加实验性 speculation rules 支持
|
||||
- core: 修复训练参加人数计数
|
||||
|
||||
### Hydro 4.13.4 / UI 4.52.3
|
||||
- framework: 修复 404 返回页
|
||||
- ui: 优化用户权限页布局
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@hydrooj/elastic-search",
|
||||
"version": "1.1.5",
|
||||
"version": "1.1.6",
|
||||
"main": "index.ts",
|
||||
"repository": "https://github.com/hydro-dev/Hydro",
|
||||
"author": "undefined <i@undefined.moe>",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hydrooj",
|
||||
"version": "4.13.4",
|
||||
"version": "4.14.0",
|
||||
"bin": "bin/hydrooj.js",
|
||||
"main": "src/plugin-api",
|
||||
"module": "src/plugin-api",
|
||||
|
||||
@@ -31,9 +31,13 @@ window.UiContext = JSON.parse(window.UiContext);
|
||||
window.UserContext = JSON.parse(window.UserContext);
|
||||
try { __webpack_public_path__ = UiContext.cdn_prefix; } catch (e) { }
|
||||
if ('serviceWorker' in navigator) {
|
||||
const encodedConfig = encodeURIComponent(JSON.stringify(UiContext.SWConfig));
|
||||
navigator.serviceWorker.register(`/service-worker.js?config=${encodedConfig}`).then((registration) => {
|
||||
navigator.serviceWorker.register('/service-worker.js').then((registration) => {
|
||||
console.log('SW registered: ', registration);
|
||||
fetch('/service-worker-config', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(UiContext.SWConfig),
|
||||
});
|
||||
}).catch((registrationError) => {
|
||||
console.log('SW registration failed: ', registrationError);
|
||||
});
|
||||
@@ -48,7 +52,7 @@ if (process.env.NODE_ENV === 'production' && UiContext.sentry_dsn) {
|
||||
if (!e.isUserFacingError) window._sentryEvents.push(e);
|
||||
};
|
||||
const script = document.createElement('script');
|
||||
script.src = new URL('sentry.js', __webpack_public_path__).href;
|
||||
script.src = new URL('/sentry.js', __webpack_public_path__).href;
|
||||
document.body.appendChild(script);
|
||||
}
|
||||
|
||||
|
||||
@@ -158,8 +158,8 @@ export function apply(ctx: Context) {
|
||||
`https://${that.request.host}`,
|
||||
SystemModel.get('server.url'),
|
||||
SystemModel.get('server.cdn'),
|
||||
...((SystemModel.get('server.assets') || '').split(',')).filter((i) => i),
|
||||
],
|
||||
assets: ((SystemModel.get('ui-default.assets') || '').split(',')).filter((i) => i) || [],
|
||||
domains: SystemModel.get('ui-default.domains') || [],
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@hydrooj/ui-default",
|
||||
"version": "4.52.3",
|
||||
"version": "4.53.0",
|
||||
"author": "undefined <i@undefined.moe>",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "index.ts",
|
||||
|
||||
@@ -114,19 +114,20 @@ interface ServiceWorkerConfig {
|
||||
hosts: string[];
|
||||
/** service domains */
|
||||
domains: string[];
|
||||
/** assets domains */
|
||||
assets: string[];
|
||||
preload?: string;
|
||||
}
|
||||
let config: ServiceWorkerConfig = null;
|
||||
|
||||
function initConfig() {
|
||||
config = JSON.parse(new URLSearchParams(location.search).get('config'));
|
||||
function initConfig(cfg) {
|
||||
config = cfg;
|
||||
config.hosts ||= [];
|
||||
config.domains = Array.from(new Set([location.host, ...(config.domains || [])]));
|
||||
console.log('Config:', config);
|
||||
}
|
||||
|
||||
self.addEventListener('install', (event) => event.waitUntil((async () => {
|
||||
initConfig();
|
||||
if (process.env.NODE_ENV === 'production' && config?.preload) {
|
||||
const [cache, manifest] = await Promise.all([
|
||||
caches.open(PRECACHE),
|
||||
@@ -140,7 +141,6 @@ self.addEventListener('install', (event) => event.waitUntil((async () => {
|
||||
})()));
|
||||
|
||||
self.addEventListener('activate', (event) => {
|
||||
initConfig();
|
||||
event.waitUntil(self.clients.claim());
|
||||
const valid = [PRECACHE];
|
||||
caches.keys().then((names) => names
|
||||
@@ -181,23 +181,47 @@ async function get(request: Request) {
|
||||
function transformUrl(url: string) {
|
||||
const urlObject = new URL(url);
|
||||
const path = urlObject.pathname;
|
||||
if (path.startsWith('/fs/') || path.includes('X-Amz')) urlObject.search = '';
|
||||
if (path.startsWith('/fs/') || path.toLowerCase().includes('x-amz')) urlObject.search = '';
|
||||
return urlObject.toString();
|
||||
}
|
||||
|
||||
async function cachedRespond(request: Request) {
|
||||
async function cached(request: Request, cacheKey: string, fetchFunc: () => Promise<Response>) {
|
||||
const url = transformUrl(request.url);
|
||||
const cachedResponse = await caches.match(url);
|
||||
if (cachedResponse) return cachedResponse;
|
||||
console.log(`Caching ${url}`);
|
||||
const urlObject = new URL(url);
|
||||
const isAsset = config.assets.some((i) => request.url.startsWith(i));
|
||||
const rewritable = !isAsset && config.domains.length > 1
|
||||
&& config.domains.includes(urlObject.hostname)
|
||||
&& urlObject.origin === location.origin;
|
||||
let targets = [url];
|
||||
if (rewritable) {
|
||||
targets = config.domains.map((i) => {
|
||||
const t = new URL(request.url);
|
||||
t.host = i;
|
||||
return transformUrl(t.toString());
|
||||
});
|
||||
}
|
||||
|
||||
if (!shouldCache(request)) return rewritable ? fetchFunc() : fetch(request);
|
||||
|
||||
const results = await Promise.all(targets.map((i) => caches.match(i)));
|
||||
const found = results.find((i) => i);
|
||||
if (found) {
|
||||
console.debug('Serve from cache %s <- %s', request.url, found.url);
|
||||
return found;
|
||||
}
|
||||
const [cache, response] = await Promise.all([
|
||||
caches.open(PRECACHE),
|
||||
get(request),
|
||||
caches.open(cacheKey),
|
||||
fetchFunc(),
|
||||
]);
|
||||
if (response.status === 206) return response; // partial response cannot be cached
|
||||
if (response.ok) {
|
||||
console.log(`Cached ${url}`);
|
||||
cache.put(url, response.clone());
|
||||
return response;
|
||||
}
|
||||
console.log(`Failed to cache ${url}`, response);
|
||||
// If response fails, re-fetch the original request to prevent
|
||||
// errors caused by different headers and do not cache them
|
||||
return fetch(request);
|
||||
}
|
||||
|
||||
@@ -206,6 +230,11 @@ self.addEventListener('fetch', (event: FetchEvent) => {
|
||||
event.respondWith(new Response('pong'));
|
||||
return;
|
||||
}
|
||||
if (event.request.url.endsWith('/service-worker-config')) {
|
||||
event.request.json().then((cfg) => initConfig(cfg));
|
||||
event.respondWith(new Response('ok'));
|
||||
return;
|
||||
}
|
||||
if (map.get(event.request.url)) {
|
||||
streamsaver(event);
|
||||
return;
|
||||
@@ -213,46 +242,24 @@ self.addEventListener('fetch', (event: FetchEvent) => {
|
||||
if (!['get', 'post', 'head'].includes(event.request.method.toLowerCase())) return;
|
||||
if (!config) return; // Don't do anything when not initialized
|
||||
const url = new URL(event.request.url);
|
||||
const rewritable = config.domains.length > 1
|
||||
&& config.domains.includes(url.hostname) && url.origin === location.origin;
|
||||
const isAsset = config.assets.some((i) => event.request.url.startsWith(i));
|
||||
const rewritable = !isAsset && config.domains.length > 1
|
||||
&& config.domains.includes(url.hostname)
|
||||
&& url.origin === location.origin;
|
||||
// Only handle whitelisted origins;
|
||||
if (!config.hosts.some((i) => event.request.url.startsWith(i))) return;
|
||||
if (!isAsset && !config.hosts.some((i) => event.request.url.startsWith(i))) return;
|
||||
// Do not cache range requests
|
||||
if (event.request.headers.get('range')?.trim()?.length) return;
|
||||
|
||||
if (shouldCache(event.request)) {
|
||||
event.respondWith((async () => {
|
||||
if (rewritable) {
|
||||
const targets = config.domains.map((i) => {
|
||||
const t = new URL(event.request.url);
|
||||
t.host = i;
|
||||
return transformUrl(t.toString());
|
||||
});
|
||||
const results = await Promise.all(targets.map((i) => caches.match(i)));
|
||||
return results.find((i) => i) || cachedRespond(event.request);
|
||||
}
|
||||
const transformedUrl = transformUrl(event.request.url);
|
||||
const cachedResponse = await caches.match(transformedUrl);
|
||||
if (cachedResponse) return cachedResponse;
|
||||
console.log(`Caching ${transformedUrl}`);
|
||||
const [cache, response] = await Promise.all([
|
||||
caches.open(PRECACHE),
|
||||
fetch(url, {
|
||||
method: event.request.method,
|
||||
headers: event.request.headers,
|
||||
redirect: event.request.redirect,
|
||||
keepalive: event.request.keepalive,
|
||||
referrer: event.request.referrer,
|
||||
referrerPolicy: event.request.referrerPolicy,
|
||||
signal: event.request.signal,
|
||||
}), // Fetch from url to prevent opaque response
|
||||
]);
|
||||
if (response.ok) {
|
||||
cache.put(transformedUrl, response.clone());
|
||||
return response;
|
||||
}
|
||||
console.log(`Failed to cache ${transformedUrl}`, response);
|
||||
// If response fails, re-fetch the original request to prevent
|
||||
// errors caused by different headers and do not cache them
|
||||
return fetch(event.request);
|
||||
})());
|
||||
} else if (rewritable) event.respondWith(get(event.request));
|
||||
event.respondWith((async () => cached(event.request, isAsset ? 'assets' : PRECACHE, () => (rewritable
|
||||
? get(event.request)
|
||||
: fetch(url, {
|
||||
method: event.request.method,
|
||||
headers: event.request.headers,
|
||||
redirect: event.request.redirect,
|
||||
keepalive: event.request.keepalive,
|
||||
referrer: event.request.referrer,
|
||||
referrerPolicy: event.request.referrerPolicy,
|
||||
signal: event.request.signal,
|
||||
}))))());
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@hydrooj/vjudge",
|
||||
"version": "1.9.9",
|
||||
"version": "1.9.10",
|
||||
"description": "Submit problems to remote oj",
|
||||
"main": "./src/index.ts",
|
||||
"repository": "https://github.com/hydro-dev/Hydro.git",
|
||||
|
||||
Reference in new issue
Block a user