fix(site/v0.8.0): 站点版本同步 + 现场失败修复(file:// 打不开 OPFS 的可操作错误)
用户报告"站点演示失败了",实测复现并定位根因: - 现象:直接双击 site/demo.html(file://)→ 点「🌲 Aria」→ "❌ 数据库初始化失败: Failed to open AriaEngine database "demo""(Memory 正常)。 - 根因:file:// 属不透明来源,Chromium 拒绝 navigator.storage.getDirectory() 并抛 SecurityError;此时 isSecureContext 仍为 true、API 也存在,无法提前探测。 引擎把它包成 ARIA_OPEN_ERROR 时丢掉了底层错误 → 消息对用户不可操作。 - 修复:OPFSBackend.open() 显式检查并抛 ARIA_OPFS_UNAVAILABLE,消息给出两条出路 (用 http(s) 打开 / 改用 mode:'memory'),原始 SecurityError 挂 cause; site/demo.html 额外用中文说明"为什么失败 + 怎么修"。 顺带修掉一个更普遍的问题:DatabaseError 的第三个参数只进 details,err.cause 恒为 undefined,而文档/注释多处写"底层错误作为 cause 保留"。现在两者都成立 (details 语义不变;cause 声明为公开字段并接入标准错误链)。 站点版本同步:demo.html(title / 状态栏 / SQL 预置脚本 / console 日志)与 benchmark.html(title)此前仍是 v0.7.4(日志甚至是 v0.4.2)→ 统一 v0.8.0; docs.html 的 AriaEngine 版本演进列表补上 v0.8.0 条目、错误码表补 ARIA_OPFS_UNAVAILABLE;README 补"OPFS 需要 http(s) 页面"的浏览器兼容说明。 回归与门禁:tests/engine/aria-opfs-unavailable.test.ts(5 项,含正常环境正控); 变异 R19 / R20 均被拦住(总计 42/42);93 套件 / 1985 用例;覆盖率 90.59 / 82.61 / 94.14 / 93.50(阈值 90/82/94/93);e2e 14/14;lint + 两份 tsc 干净; dist 重建(251,731 B / gzip 63,431 B)并已同步全部体积宣称。
This commit is contained in:
Vendored
+33
-1
@@ -29,6 +29,18 @@ class DatabaseError extends Error {
|
||||
this.code = code;
|
||||
this.details = details;
|
||||
this.name = 'DatabaseError';
|
||||
// v0.8.0(review 修复):把底层错误同时挂到**标准** `Error.cause` 上。
|
||||
//
|
||||
// 修复前第三个参数只存进 `details`,`err.cause` 恒为 undefined —— 而文档与
|
||||
// 代码注释多处写的是"底层错误作为 cause 保留"(实测被打脸:探针打印
|
||||
// `e.cause?.code` 得到 undefined)。`details` 语义保持不变(向后兼容),
|
||||
// `cause` 让标准错误链工具(日志/监控/Node 的 error.cause 约定)能看到根因。
|
||||
//
|
||||
// 注意:target 是 ES2020(lib 无 ES2022 的 ErrorOptions),因此用赋值而不是
|
||||
// `super(message, { cause })`;运行时所有现代引擎都支持该属性。
|
||||
if (details !== undefined) {
|
||||
this.cause = details;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -2314,7 +2326,27 @@ class OPFSBackend {
|
||||
}
|
||||
async open(name) {
|
||||
this.dbName = name;
|
||||
this.root = await navigator.storage.getDirectory();
|
||||
// v0.8.0(review 修复):OPFS 不可用时给出**可操作的**错误,而不是让上层
|
||||
// 只能报一句 "Failed to open AriaEngine database"。
|
||||
//
|
||||
// 真实场景(实测):用 file:// 直接打开页面时 Chromium 认为本地文件"不适合
|
||||
// Web 应用访问",`navigator.storage.getDirectory()` 抛 SecurityError —— 而
|
||||
// `isSecureContext` 仍是 true、API 也**存在**,所以只有真正调用才会发现。
|
||||
// 修复前这个 SecurityError 被 `ARIA_OPEN_ERROR` 吞成一句无从下手的消息
|
||||
//(cause 没往上带),用户不知道是"环境不支持"还是"库坏了"。
|
||||
if (typeof navigator === 'undefined' || !navigator.storage
|
||||
|| typeof navigator.storage.getDirectory !== 'function') {
|
||||
throw new DatabaseError('OPFS is not available in this environment: navigator.storage.getDirectory is missing. ' +
|
||||
"Use the http(s) protocol (file:// is rejected by browsers) or switch to mode: 'memory' / a KVStore backend.", 'ARIA_OPFS_UNAVAILABLE');
|
||||
}
|
||||
try {
|
||||
this.root = await navigator.storage.getDirectory();
|
||||
}
|
||||
catch (error) {
|
||||
throw new DatabaseError(`OPFS is not accessible here (${error.name}: ${error.message}). ` +
|
||||
'Chromium blocks OPFS for file:// pages — serve the page over http(s) ' +
|
||||
"(e.g. `npx serve .` / `node tests/e2e/server.cjs`) or use mode: 'memory'.", 'ARIA_OPFS_UNAVAILABLE', error);
|
||||
}
|
||||
this.dbDir = await this.root.getDirectoryHandle(name, { create: true });
|
||||
// v0.4.5: 清理崩溃残留临时文件(不阻塞打开)
|
||||
await this.cleanupStaleFiles();
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+8
@@ -236,6 +236,14 @@ interface MetonaPlugin {
|
||||
declare class DatabaseError extends Error {
|
||||
code: string;
|
||||
details?: unknown | undefined;
|
||||
/**
|
||||
* 底层错误(第三个构造参数)。
|
||||
*
|
||||
* v0.8.0:显式声明为公开字段 —— target 是 ES2020(lib 里 `Error` 还没有
|
||||
* `cause`),不声明的话 TypeScript 使用者读 `err.cause` 会编译失败,
|
||||
* 而运行时它确实存在。
|
||||
*/
|
||||
cause?: unknown;
|
||||
constructor(message: string, code: string, details?: unknown | undefined);
|
||||
}
|
||||
declare const VERSION = "0.8.0";
|
||||
|
||||
Vendored
+33
-1
@@ -25,6 +25,18 @@ class DatabaseError extends Error {
|
||||
this.code = code;
|
||||
this.details = details;
|
||||
this.name = 'DatabaseError';
|
||||
// v0.8.0(review 修复):把底层错误同时挂到**标准** `Error.cause` 上。
|
||||
//
|
||||
// 修复前第三个参数只存进 `details`,`err.cause` 恒为 undefined —— 而文档与
|
||||
// 代码注释多处写的是"底层错误作为 cause 保留"(实测被打脸:探针打印
|
||||
// `e.cause?.code` 得到 undefined)。`details` 语义保持不变(向后兼容),
|
||||
// `cause` 让标准错误链工具(日志/监控/Node 的 error.cause 约定)能看到根因。
|
||||
//
|
||||
// 注意:target 是 ES2020(lib 无 ES2022 的 ErrorOptions),因此用赋值而不是
|
||||
// `super(message, { cause })`;运行时所有现代引擎都支持该属性。
|
||||
if (details !== undefined) {
|
||||
this.cause = details;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -2310,7 +2322,27 @@ class OPFSBackend {
|
||||
}
|
||||
async open(name) {
|
||||
this.dbName = name;
|
||||
this.root = await navigator.storage.getDirectory();
|
||||
// v0.8.0(review 修复):OPFS 不可用时给出**可操作的**错误,而不是让上层
|
||||
// 只能报一句 "Failed to open AriaEngine database"。
|
||||
//
|
||||
// 真实场景(实测):用 file:// 直接打开页面时 Chromium 认为本地文件"不适合
|
||||
// Web 应用访问",`navigator.storage.getDirectory()` 抛 SecurityError —— 而
|
||||
// `isSecureContext` 仍是 true、API 也**存在**,所以只有真正调用才会发现。
|
||||
// 修复前这个 SecurityError 被 `ARIA_OPEN_ERROR` 吞成一句无从下手的消息
|
||||
//(cause 没往上带),用户不知道是"环境不支持"还是"库坏了"。
|
||||
if (typeof navigator === 'undefined' || !navigator.storage
|
||||
|| typeof navigator.storage.getDirectory !== 'function') {
|
||||
throw new DatabaseError('OPFS is not available in this environment: navigator.storage.getDirectory is missing. ' +
|
||||
"Use the http(s) protocol (file:// is rejected by browsers) or switch to mode: 'memory' / a KVStore backend.", 'ARIA_OPFS_UNAVAILABLE');
|
||||
}
|
||||
try {
|
||||
this.root = await navigator.storage.getDirectory();
|
||||
}
|
||||
catch (error) {
|
||||
throw new DatabaseError(`OPFS is not accessible here (${error.name}: ${error.message}). ` +
|
||||
'Chromium blocks OPFS for file:// pages — serve the page over http(s) ' +
|
||||
"(e.g. `npx serve .` / `node tests/e2e/server.cjs`) or use mode: 'memory'.", 'ARIA_OPFS_UNAVAILABLE', error);
|
||||
}
|
||||
this.dbDir = await this.root.getDirectoryHandle(name, { create: true });
|
||||
// v0.4.5: 清理崩溃残留临时文件(不阻塞打开)
|
||||
await this.cleanupStaleFiles();
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+33
-1
@@ -31,6 +31,18 @@
|
||||
this.code = code;
|
||||
this.details = details;
|
||||
this.name = 'DatabaseError';
|
||||
// v0.8.0(review 修复):把底层错误同时挂到**标准** `Error.cause` 上。
|
||||
//
|
||||
// 修复前第三个参数只存进 `details`,`err.cause` 恒为 undefined —— 而文档与
|
||||
// 代码注释多处写的是"底层错误作为 cause 保留"(实测被打脸:探针打印
|
||||
// `e.cause?.code` 得到 undefined)。`details` 语义保持不变(向后兼容),
|
||||
// `cause` 让标准错误链工具(日志/监控/Node 的 error.cause 约定)能看到根因。
|
||||
//
|
||||
// 注意:target 是 ES2020(lib 无 ES2022 的 ErrorOptions),因此用赋值而不是
|
||||
// `super(message, { cause })`;运行时所有现代引擎都支持该属性。
|
||||
if (details !== undefined) {
|
||||
this.cause = details;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -2316,7 +2328,27 @@
|
||||
}
|
||||
async open(name) {
|
||||
this.dbName = name;
|
||||
this.root = await navigator.storage.getDirectory();
|
||||
// v0.8.0(review 修复):OPFS 不可用时给出**可操作的**错误,而不是让上层
|
||||
// 只能报一句 "Failed to open AriaEngine database"。
|
||||
//
|
||||
// 真实场景(实测):用 file:// 直接打开页面时 Chromium 认为本地文件"不适合
|
||||
// Web 应用访问",`navigator.storage.getDirectory()` 抛 SecurityError —— 而
|
||||
// `isSecureContext` 仍是 true、API 也**存在**,所以只有真正调用才会发现。
|
||||
// 修复前这个 SecurityError 被 `ARIA_OPEN_ERROR` 吞成一句无从下手的消息
|
||||
//(cause 没往上带),用户不知道是"环境不支持"还是"库坏了"。
|
||||
if (typeof navigator === 'undefined' || !navigator.storage
|
||||
|| typeof navigator.storage.getDirectory !== 'function') {
|
||||
throw new DatabaseError('OPFS is not available in this environment: navigator.storage.getDirectory is missing. ' +
|
||||
"Use the http(s) protocol (file:// is rejected by browsers) or switch to mode: 'memory' / a KVStore backend.", 'ARIA_OPFS_UNAVAILABLE');
|
||||
}
|
||||
try {
|
||||
this.root = await navigator.storage.getDirectory();
|
||||
}
|
||||
catch (error) {
|
||||
throw new DatabaseError(`OPFS is not accessible here (${error.name}: ${error.message}). ` +
|
||||
'Chromium blocks OPFS for file:// pages — serve the page over http(s) ' +
|
||||
"(e.g. `npx serve .` / `node tests/e2e/server.cjs`) or use mode: 'memory'.", 'ARIA_OPFS_UNAVAILABLE', error);
|
||||
}
|
||||
this.dbDir = await this.root.getDirectoryHandle(name, { create: true });
|
||||
// v0.4.5: 清理崩溃残留临时文件(不阻塞打开)
|
||||
await this.cleanupStaleFiles();
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+33
-1
@@ -27,6 +27,18 @@ class DatabaseError extends Error {
|
||||
this.code = code;
|
||||
this.details = details;
|
||||
this.name = 'DatabaseError';
|
||||
// v0.8.0(review 修复):把底层错误同时挂到**标准** `Error.cause` 上。
|
||||
//
|
||||
// 修复前第三个参数只存进 `details`,`err.cause` 恒为 undefined —— 而文档与
|
||||
// 代码注释多处写的是"底层错误作为 cause 保留"(实测被打脸:探针打印
|
||||
// `e.cause?.code` 得到 undefined)。`details` 语义保持不变(向后兼容),
|
||||
// `cause` 让标准错误链工具(日志/监控/Node 的 error.cause 约定)能看到根因。
|
||||
//
|
||||
// 注意:target 是 ES2020(lib 无 ES2022 的 ErrorOptions),因此用赋值而不是
|
||||
// `super(message, { cause })`;运行时所有现代引擎都支持该属性。
|
||||
if (details !== undefined) {
|
||||
this.cause = details;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2308,7 +2320,27 @@ class OPFSBackend {
|
||||
}
|
||||
async open(name) {
|
||||
this.dbName = name;
|
||||
this.root = await navigator.storage.getDirectory();
|
||||
// v0.8.0(review 修复):OPFS 不可用时给出**可操作的**错误,而不是让上层
|
||||
// 只能报一句 "Failed to open AriaEngine database"。
|
||||
//
|
||||
// 真实场景(实测):用 file:// 直接打开页面时 Chromium 认为本地文件"不适合
|
||||
// Web 应用访问",`navigator.storage.getDirectory()` 抛 SecurityError —— 而
|
||||
// `isSecureContext` 仍是 true、API 也**存在**,所以只有真正调用才会发现。
|
||||
// 修复前这个 SecurityError 被 `ARIA_OPEN_ERROR` 吞成一句无从下手的消息
|
||||
//(cause 没往上带),用户不知道是"环境不支持"还是"库坏了"。
|
||||
if (typeof navigator === 'undefined' || !navigator.storage
|
||||
|| typeof navigator.storage.getDirectory !== 'function') {
|
||||
throw new DatabaseError('OPFS is not available in this environment: navigator.storage.getDirectory is missing. ' +
|
||||
"Use the http(s) protocol (file:// is rejected by browsers) or switch to mode: 'memory' / a KVStore backend.", 'ARIA_OPFS_UNAVAILABLE');
|
||||
}
|
||||
try {
|
||||
this.root = await navigator.storage.getDirectory();
|
||||
}
|
||||
catch (error) {
|
||||
throw new DatabaseError(`OPFS is not accessible here (${error.name}: ${error.message}). ` +
|
||||
'Chromium blocks OPFS for file:// pages — serve the page over http(s) ' +
|
||||
"(e.g. `npx serve .` / `node tests/e2e/server.cjs`) or use mode: 'memory'.", 'ARIA_OPFS_UNAVAILABLE', error);
|
||||
}
|
||||
this.dbDir = await this.root.getDirectoryHandle(name, { create: true });
|
||||
// v0.4.5: 清理崩溃残留临时文件(不阻塞打开)
|
||||
await this.cleanupStaleFiles();
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+33
-1
@@ -27,6 +27,18 @@ class DatabaseError extends Error {
|
||||
this.code = code;
|
||||
this.details = details;
|
||||
this.name = 'DatabaseError';
|
||||
// v0.8.0(review 修复):把底层错误同时挂到**标准** `Error.cause` 上。
|
||||
//
|
||||
// 修复前第三个参数只存进 `details`,`err.cause` 恒为 undefined —— 而文档与
|
||||
// 代码注释多处写的是"底层错误作为 cause 保留"(实测被打脸:探针打印
|
||||
// `e.cause?.code` 得到 undefined)。`details` 语义保持不变(向后兼容),
|
||||
// `cause` 让标准错误链工具(日志/监控/Node 的 error.cause 约定)能看到根因。
|
||||
//
|
||||
// 注意:target 是 ES2020(lib 无 ES2022 的 ErrorOptions),因此用赋值而不是
|
||||
// `super(message, { cause })`;运行时所有现代引擎都支持该属性。
|
||||
if (details !== undefined) {
|
||||
this.cause = details;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2308,7 +2320,27 @@ class OPFSBackend {
|
||||
}
|
||||
async open(name) {
|
||||
this.dbName = name;
|
||||
this.root = await navigator.storage.getDirectory();
|
||||
// v0.8.0(review 修复):OPFS 不可用时给出**可操作的**错误,而不是让上层
|
||||
// 只能报一句 "Failed to open AriaEngine database"。
|
||||
//
|
||||
// 真实场景(实测):用 file:// 直接打开页面时 Chromium 认为本地文件"不适合
|
||||
// Web 应用访问",`navigator.storage.getDirectory()` 抛 SecurityError —— 而
|
||||
// `isSecureContext` 仍是 true、API 也**存在**,所以只有真正调用才会发现。
|
||||
// 修复前这个 SecurityError 被 `ARIA_OPEN_ERROR` 吞成一句无从下手的消息
|
||||
//(cause 没往上带),用户不知道是"环境不支持"还是"库坏了"。
|
||||
if (typeof navigator === 'undefined' || !navigator.storage
|
||||
|| typeof navigator.storage.getDirectory !== 'function') {
|
||||
throw new DatabaseError('OPFS is not available in this environment: navigator.storage.getDirectory is missing. ' +
|
||||
"Use the http(s) protocol (file:// is rejected by browsers) or switch to mode: 'memory' / a KVStore backend.", 'ARIA_OPFS_UNAVAILABLE');
|
||||
}
|
||||
try {
|
||||
this.root = await navigator.storage.getDirectory();
|
||||
}
|
||||
catch (error) {
|
||||
throw new DatabaseError(`OPFS is not accessible here (${error.name}: ${error.message}). ` +
|
||||
'Chromium blocks OPFS for file:// pages — serve the page over http(s) ' +
|
||||
"(e.g. `npx serve .` / `node tests/e2e/server.cjs`) or use mode: 'memory'.", 'ARIA_OPFS_UNAVAILABLE', error);
|
||||
}
|
||||
this.dbDir = await this.root.getDirectoryHandle(name, { create: true });
|
||||
// v0.4.5: 清理崩溃残留临时文件(不阻塞打开)
|
||||
await this.cleanupStaleFiles();
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user