chore: bump version to 0.5.25

This commit is contained in:
liquidliang committed 2026-01-20 13:11:17 +08:00
1 parent 5571d3f1d9
commit 8bd7f30c19
8 files changed
+173 -22

No files matched your search

+3
View File
@@ -1 +1,4 @@
legacy-peer-deps=true
# 发布使用官方 npm registry
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
+23
View File
@@ -1,3 +1,26 @@
## 0.5.23 (2026-01-20)
### 🚀 Features
- 优化素材库 UI 交互、缩放缓存、Grid 布局及空间效率 ([c64e4a7](https://github.com/ljquan/aitu/commit/c64e4a7))
### 🔧 Chores
- bump version to 0.5.22 ([5571d3f](https://github.com/ljquan/aitu/commit/5571d3f))
- bump version to 0.5.21 ([55ad29c](https://github.com/ljquan/aitu/commit/55ad29c))
- bump version to 0.5.20 ([8bfc191](https://github.com/ljquan/aitu/commit/8bfc191))
- bump version to 0.5.19 ([8707a5b](https://github.com/ljquan/aitu/commit/8707a5b))
- bump version to 0.5.18 ([88c0dfd](https://github.com/ljquan/aitu/commit/88c0dfd))
- bump version to 0.5.17 ([91799c9](https://github.com/ljquan/aitu/commit/91799c9))
- bump version to 0.5.17 and update build time in version.json ([51b5f3f](https://github.com/ljquan/aitu/commit/51b5f3f))
- bump version to 0.5.17 ([c41c9bd](https://github.com/ljquan/aitu/commit/c41c9bd))
- docs(claude): 更新调试日志处理和命令行工具使用说明,添加后台清理任务日志记录示例 ([30cf458](https://github.com/ljquan/aitu/commit/30cf458))
- docs(claude): 添加 React 事件委托、筛选逻辑、Grid 布局及 UI 高度统一规则 ([dcabd75](https://github.com/ljquan/aitu/commit/dcabd75))
### ❤️ Thank You
- liquidliang <ljquan@qq.com>
## 0.5.17 (2026-01-20)
### 🚀 Features
+4 -1
View File
@@ -61,7 +61,7 @@
</script>
<!-- base href 由构建工具处理,CDN 模式下使用相对路径 -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
<meta name="app-version" content="0.5.17" />
<meta name="app-version" content="0.5.24" />
<link rel="icon" type="image/svg+xml" sizes="16x16" href="./icons/favicon-16x16.svg" />
<link rel="icon" type="image/svg+xml" sizes="32x32" href="./icons/favicon-32x32.svg" />
@@ -88,6 +88,9 @@
<meta name="msapplication-square310x310logo" content="./icons/icon-512x512.svg" />
<link rel="stylesheet" href="./src/styles.scss" />
<!-- CDN 智能选择器(可选,用于提前检测最佳 CDN) -->
<script src="./cdn-config.js" defer></script>
</head>
<body>
<div id="root"></div>
+3 -6
View File
@@ -1,9 +1,6 @@
{
"version": "0.5.22",
"buildTime": "2026-01-20T04:55:16.014Z",
"version": "0.5.25",
"buildTime": "2026-01-20T05:11:17.776Z",
"gitCommit": "unknown",
"changelog": [
"优化素材库 UI 交互、缩放缓存、Grid 布局及空间效率",
"封装函数不应被绕过、页面卸载清理定时器"
]
"changelog": []
}
+4 -2
View File
@@ -52,8 +52,10 @@ const CDN_CONFIG = {
degradeTimeout: 60 * 1000,
// 连续失败次数阈值
failThreshold: 3,
// 请求超时(毫秒)
fetchTimeout: 10000,
// 请求超时(毫秒)- 短超时策略:
// CDN 缓存命中通常 < 200ms,设置 1.5s 超时
// 超时后快速回退到服务器,避免 CDN 回源慢影响用户体验
fetchTimeout: 1500,
};
// CDN 源列表(按优先级排序)
+70 -9
View File
@@ -1,10 +1,6 @@
/// <reference lib="webworker" />
/* eslint-disable no-restricted-globals */
// fix: self redeclaration error and type casting
const sw = self as unknown as ServiceWorkerGlobalScope;
export { }; // Make this a module
// Import task queue module
import {
initTaskQueue,
@@ -33,9 +29,17 @@ import {
initMessageSender,
setDebugMode as setMessageSenderDebugMode,
setBroadcastCallback,
sendToClient,
broadcastToAllClients,
} from './task-queue/utils/message-bus';
import {
fetchFromCDNWithFallback,
getCDNStatusReport,
resetCDNStatus,
performHealthCheck,
} from './cdn-fallback';
// fix: self redeclaration error and type casting
const sw = self as unknown as ServiceWorkerGlobalScope;
export { }; // Make this a module
// Initialize task queue (instance used internally by handleTaskQueueMessage)
initTaskQueue(sw);
@@ -1404,6 +1408,27 @@ sw.addEventListener('message', (event: ExtendableMessageEvent) => {
event.source?.postMessage({
type: 'SW_DEBUG_LOGS_CLEARED',
});
} else if (event.data && event.data.type === 'SW_CDN_GET_STATUS') {
// 获取 CDN 状态
event.source?.postMessage({
type: 'SW_CDN_STATUS',
status: getCDNStatusReport(),
});
} else if (event.data && event.data.type === 'SW_CDN_RESET_STATUS') {
// 重置 CDN 状态
resetCDNStatus();
event.source?.postMessage({
type: 'SW_CDN_STATUS_RESET',
});
} else if (event.data && event.data.type === 'SW_CDN_HEALTH_CHECK') {
// 执行 CDN 健康检查
(async () => {
const results = await performHealthCheck(APP_VERSION);
event.source?.postMessage({
type: 'SW_CDN_HEALTH_CHECK_RESULT',
results: Object.fromEntries(results),
});
})();
} else if (event.data && event.data.type === 'SW_DEBUG_GET_CACHE_ENTRIES') {
// 获取缓存条目列表
const { cacheName, limit = 50, offset = 0 } = event.data;
@@ -3086,7 +3111,42 @@ async function handleStaticRequest(request: Request): Promise<Response> {
return cachedResponse;
}
// Cache miss - try network
// Cache miss - determine if this is a CDN-cacheable static resource
const resourcePath = url.pathname;
const isStaticResource = !isDevelopment && (
resourcePath.match(/\.(js|css|png|jpg|jpeg|gif|webp|svg|woff|woff2|ttf|eot|json|ico)$/i) ||
request.destination === 'script' ||
request.destination === 'style' ||
request.destination === 'image' ||
request.destination === 'font'
);
// ============================================
// CDN 优先策略:暂时禁用,等 npm 包发布后再启用
// TODO: npm publish aitu-app 后取消注释下面的代码
// ============================================
// if (isStaticResource) {
// try {
// console.log(`[SW CDN] Trying CDN first for: ${resourcePath}`);
// const cdnResult = await fetchFromCDNWithFallback(
// resourcePath,
// APP_VERSION,
// location.origin
// );
//
// if (cdnResult && cdnResult.response.ok) {
// console.log(`[SW CDN] Success from ${cdnResult.source}: ${resourcePath}`);
// // 缓存成功的响应
// const responseToCache = cdnResult.response.clone();
// cache.put(request, responseToCache);
// return cdnResult.response;
// }
// } catch (cdnError) {
// console.warn('[SW CDN] CDN sources failed, trying local server:', cdnError);
// }
// }
// 回退到本地服务器(开发模式或 CDN 失败)
try {
const response = await fetchQuick(request);
@@ -3134,7 +3194,7 @@ async function handleStaticRequest(request: Request): Promise<Response> {
return response;
} catch (networkError) {
console.error('Static resource unavailable:', request.url);
console.warn('[SW] Network failed, trying old caches:', request.url);
// Try to find the resource in any cache (including old version caches)
const allCacheNames = await caches.keys();
@@ -3144,7 +3204,7 @@ async function handleStaticRequest(request: Request): Promise<Response> {
const oldCache = await caches.open(cacheName);
const oldCachedResponse = await oldCache.match(request);
if (oldCachedResponse) {
// console.log(`Service Worker: Found resource in ${cacheName} after network failure`);
console.log(`[SW] Found resource in ${cacheName} after network failure`);
return oldCachedResponse;
}
} catch (e) {
@@ -3153,6 +3213,7 @@ async function handleStaticRequest(request: Request): Promise<Response> {
}
}
// 所有来源都失败了
return new Response('Resource unavailable offline', {
status: 503,
statusText: 'Service Unavailable',
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@aitu/source",
"version": "0.5.22",
"version": "0.5.25",
"license": "MIT",
"packageManager": "pnpm@10.21.0",
"description": "Aitu - An open-source whiteboard tool with AI-powered image/video creation, mind mapping, flowcharts, and freehand drawing",
@@ -132,6 +132,7 @@ function waitForIdle(timeout = 50): Promise<void> {
async function detectDatabaseVersion(dbName: string): Promise<number> {
return new Promise((resolve) => {
if (typeof indexedDB === 'undefined') {
console.warn('[WorkspaceStorage] IndexedDB not available, using min version');
resolve(WORKSPACE_DB_CONFIG.MIN_DATABASE_VERSION);
return;
}
@@ -143,11 +144,22 @@ async function detectDatabaseVersion(dbName: string): Promise<number> {
const db = request.result;
const version = db.version;
db.close();
resolve(Math.max(version, WORKSPACE_DB_CONFIG.MIN_DATABASE_VERSION));
const targetVersion = Math.max(version, WORKSPACE_DB_CONFIG.MIN_DATABASE_VERSION);
console.log(`[WorkspaceStorage] Detected DB version: ${version}, using: ${targetVersion}`);
resolve(targetVersion);
};
request.onerror = () => {
resolve(WORKSPACE_DB_CONFIG.MIN_DATABASE_VERSION);
request.onerror = (event) => {
// Try to get version from error event or use a safe high version
console.error('[WorkspaceStorage] Error detecting DB version:', event);
// Use a higher version to avoid downgrade - version 10 should be safe
resolve(10);
};
request.onblocked = () => {
// Database is blocked by another connection, use a safe high version
console.warn('[WorkspaceStorage] DB blocked, using safe version 10');
resolve(10);
};
});
}
@@ -226,10 +238,60 @@ class WorkspaceStorageService {
this.initialized = true;
} catch (error) {
console.error('[WorkspaceStorage] Failed to initialize:', error);
// Check if it's a version downgrade error
const errorMsg = String(error);
if (errorMsg.includes("can't be downgraded") || errorMsg.includes('version')) {
console.warn('[WorkspaceStorage] Version conflict detected, attempting recovery...');
// Try to delete the database and reinitialize
try {
await this.deleteDatabase();
await this.createStores();
await Promise.all([
this.foldersStore!.ready(),
this.boardsStore!.ready(),
this.stateStore!.ready(),
]);
this.initialized = true;
console.log('[WorkspaceStorage] Recovery successful, database recreated');
return;
} catch (recoveryError) {
console.error('[WorkspaceStorage] Recovery failed:', recoveryError);
}
}
throw new Error('Workspace storage initialization failed');
}
}
/**
* Delete the database (for recovery from version conflicts)
*/
private async deleteDatabase(): Promise<void> {
return new Promise((resolve, reject) => {
if (typeof indexedDB === 'undefined') {
resolve();
return;
}
const request = indexedDB.deleteDatabase(WORKSPACE_DB_CONFIG.DATABASE_NAME);
request.onsuccess = () => {
console.log('[WorkspaceStorage] Database deleted successfully');
resolve();
};
request.onerror = () => {
console.error('[WorkspaceStorage] Failed to delete database');
reject(new Error('Failed to delete database'));
};
request.onblocked = () => {
console.warn('[WorkspaceStorage] Database deletion blocked');
// Still resolve after a timeout
setTimeout(resolve, 1000);
};
});
}
// ========== Private Store Getters (ensure initialized) ==========
private getFoldersStore(): LocalForage {