@heybox/hb-sdk 0.8.1 → 0.8.2-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +2 -2
  3. package/dist/cli-chunks/{build-DPe1Ycjd.cjs → build-bVThH3Z5.cjs} +4 -4
  4. package/dist/cli-chunks/{context-BSUhAv3Z.cjs → context-DpKqGnjp.cjs} +2 -2
  5. package/dist/cli-chunks/{create-CaiKrGnb.cjs → create-BWC2343y.cjs} +1 -1
  6. package/dist/cli-chunks/{dev-BG1o8Q-0.cjs → dev-t14YpHHY.cjs} +9 -9
  7. package/dist/cli-chunks/{doctor-DutO2P5H.cjs → doctor-BWkrE0Hj.cjs} +1 -1
  8. package/dist/cli-chunks/{index-CKIyipP9.cjs → index-CDtcZVWv.cjs} +15 -15
  9. package/dist/cli-chunks/{index-Bur0U2z1.cjs → index-D3FMcOZq.cjs} +2 -2
  10. package/dist/cli-chunks/{index.esm-BPlpP-O0.cjs → index.esm-BrJBaJWS.cjs} +7 -7
  11. package/dist/cli-chunks/{login-C1JlLEza.cjs → login-DRMl7nFH.cjs} +2 -2
  12. package/dist/cli-chunks/{project-vite-Bd0WzAqQ.cjs → project-vite-CXgdzIYw.cjs} +1 -1
  13. package/dist/cli-chunks/{remote-DTFEf3Dj.cjs → remote-ibQybNiM.cjs} +6 -6
  14. package/dist/cli-chunks/{runtime-permission-env-C2S34ldj.cjs → runtime-permission-env-DiTeD75Q.cjs} +576 -20
  15. package/dist/cli-chunks/{session-zXVkHuhY.cjs → session-CIoBspg-.cjs} +1 -1
  16. package/dist/cli-chunks/{skill-CCB3DyXk.cjs → skill-5labzuWk.cjs} +2 -2
  17. package/dist/cli-chunks/{version-0qwlEyZC.cjs → version-QiVEs76a.cjs} +1 -1
  18. package/dist/cli.cjs +1 -1
  19. package/dist/devtools/browser-dev-host/assets/browser-dev-host-DxzOkljJ.js +101 -0
  20. package/dist/devtools/browser-dev-host/assets/{desktop-app-launch-DOfl5YvO.js → desktop-app-launch-B4KsgItx.js} +1 -1
  21. package/dist/devtools/browser-dev-host/assets/{index-CFr28-0O.js → index-9Nb3XhtI.js} +3 -3
  22. package/dist/devtools/browser-dev-host/index.html +2 -2
  23. package/dist/index.cjs.js +948 -44
  24. package/dist/index.esm.js +948 -44
  25. package/dist/miniapp-publish.cjs.js +536 -30
  26. package/dist/miniapp-publish.esm.js +536 -30
  27. package/dist/protocol.cjs.js +807 -2
  28. package/dist/protocol.esm.js +807 -2
  29. package/dist/vite.cjs.js +184 -1
  30. package/dist/vite.esm.js +184 -1
  31. package/package.json +7 -7
  32. package/skill/references/api-root.md +192 -8
  33. package/skill/references/recipes.md +45 -7
  34. package/skill/skill.json +5 -5
  35. package/types/core/errors.d.ts +33 -9
  36. package/types/core/handshake-state.d.ts +32 -2
  37. package/types/core/singleton.d.ts +265 -6
  38. package/types/miniapp-manifest/bindings.d.ts +65 -0
  39. package/types/miniapp-manifest/schema.d.ts +136 -19
  40. package/types/miniapp-publish/index.d.ts +425 -29
  41. package/types/modules/auth/index.d.ts +159 -5
  42. package/types/modules/cloud/index.d.ts +514 -40
  43. package/types/modules/companion/index.d.ts +1518 -17
  44. package/types/modules/device/index.d.ts +140 -9
  45. package/types/modules/environment/index.d.ts +172 -4
  46. package/types/modules/files/types.d.ts +1396 -21
  47. package/types/modules/navigation/app-pages/types.d.ts +81 -24
  48. package/types/modules/navigation/index.d.ts +230 -7
  49. package/types/modules/network/index.d.ts +297 -26
  50. package/types/modules/share/copy-link.d.ts +35 -5
  51. package/types/modules/share/index.d.ts +210 -0
  52. package/types/modules/share/screenshot.d.ts +23 -5
  53. package/types/modules/share/show-share-menu.d.ts +18 -5
  54. package/types/modules/share/types.d.ts +148 -23
  55. package/types/modules/storage/index.d.ts +139 -9
  56. package/types/modules/ui/index.d.ts +249 -18
  57. package/types/modules/user/get-info.d.ts +29 -8
  58. package/types/modules/user/index.d.ts +157 -0
  59. package/types/modules/user/revoke-authorization.d.ts +26 -2
  60. package/types/modules/user/steam-game-list.d.ts +96 -15
  61. package/types/modules/viewport/index.d.ts +158 -22
  62. package/types/protocol/types.d.ts +19 -1
  63. package/types/vite/index.d.ts +159 -1
  64. package/dist/devtools/browser-dev-host/assets/browser-dev-host-pUcws1MK.js +0 -101
@@ -1,34 +1,188 @@
1
- /** File/Directory 访问模式。 */
1
+ /**
2
+ * File/Directory 访问模式。
3
+ *
4
+ * `read` 允许读取、查询状态和枚举目录;`readwrite` 在此基础上允许创建和写入。
5
+ * 删除操作仍只对 sandbox 对象开放,外部授权即使为 `readwrite` 也不能删除。
6
+ */
2
7
  export type FileMode = 'read' | 'readwrite';
8
+ /**
9
+ * 用户选择文件时的筛选和授权选项。
10
+ *
11
+ * @remarks
12
+ * 省略 options 或传 `{}` 等同于 `{ mode: 'read', multiple: false }`,且不设置扩展名筛选。
13
+ * Host 返回的整批文件会先校验数量、结构、名称、mode 和 session 配额,再一次性注册;任一项
14
+ * 失败都不会保留部分授权。
15
+ */
3
16
  export interface PickFilesOptions {
17
+ /**
18
+ * 请求的访问模式,默认 `read`。Host 即使授予更高权限也会被 Runtime 收窄为 `read`;请求
19
+ * `readwrite` 但平台/选择器只能授予只读时返回 `FILE_ACCESS_DENIED`,不会静默降级。外部
20
+ * File 即使为 `readwrite` 也不能调用 `remove()`。
21
+ */
4
22
  mode?: FileMode;
23
+ /**
24
+ * 传给系统选择器的文件扩展名筛选,例如 `['.json', '.txt', '.tar.gz']`。
25
+ *
26
+ * @remarks
27
+ * 必须是数组;每项匹配 `/^\.[a-z0-9][a-z0-9._-]*$/i`,即以 `.` 和 ASCII 字母/数字开头,
28
+ * 后续只允许 ASCII 字母、数字、点、下划线或连字符。空串、缺少前导点、路径、通配符、空格
29
+ * 或 MIME type 会以 `INVALID_PARAMS` 拒绝。重复项在进入 Host 前按首次出现顺序去重。
30
+ * 该字段只影响系统选择器筛选,不读取或转换文件内容;不需要筛选时应省略。
31
+ */
5
32
  accept?: string[];
33
+ /**
34
+ * 是否允许选择多个文件,默认 `false`。`false` 时成功结果恰好一个;只有显式为 `true` 时
35
+ * 才接受多个结果,实际数量由系统选择器决定,但成功结果仍至少一个。
36
+ */
6
37
  multiple?: boolean;
7
38
  }
39
+ /**
40
+ * 用户选择目录时的授权选项。
41
+ *
42
+ * @remarks
43
+ * V1 只接受 `mode`,不支持文件扩展名筛选、多选或建议名称。省略 options、传 `{}` 或省略
44
+ * `mode` 都请求 `read`。Host 即使返回更高权限也会被 Runtime 收窄到请求模式;请求
45
+ * `readwrite` 但平台/选择器只授予只读时返回 `FILE_ACCESS_DENIED`,不会静默降级。
46
+ */
8
47
  export interface PickDirectoryOptions {
48
+ /**
49
+ * 请求的访问模式,默认 `read`。`read` 允许枚举、读取和查询派生目标;`readwrite` 还允许
50
+ * 创建/写入派生文件与目录,并可把所选目录作为 `network.download()` target。外部授权即使
51
+ * 为 `readwrite` 也不能调用 `remove()`。
52
+ */
9
53
  mode?: FileMode;
10
54
  }
55
+ /**
56
+ * 用户选择精确保存目标时的选项。
57
+ *
58
+ * @remarks
59
+ * V1 只接受 `suggestedName`,不支持 `accept`、扩展名筛选、访问模式或 overwrite;返回授权固定
60
+ * 为 `readwrite`。该名称是提供给 Host 系统保存界面的建议值,跨平台最终文件名以返回
61
+ * {@link FileHandle.name} 为准。
62
+ */
11
63
  export interface SaveFileOptions {
64
+ /**
65
+ * 提供给系统选择器的建议文件名。
66
+ *
67
+ * @remarks
68
+ * 必须是非空的单个规范 basename:不能以 `/` 开头或结尾,不能包含 `/`、`\\`、NUL、
69
+ * U+0000-U+001F / U+007F 控制字符或空 path segment,也不能等于 `.` 或 `..`。例如
70
+ * `report.json` 合法,`reports/report.json`、`../report.json` 与 `report\\latest.json` 非法并返回
71
+ * `INVALID_PARAMS`。SDK 不会自动添加或修改扩展名。
72
+ */
12
73
  suggestedName: string;
13
74
  }
75
+ /**
76
+ * {@link FileHandle.create} / {@link DirectoryHandle.create} 的创建选项。
77
+ *
78
+ * @remarks
79
+ * 两个字段都只接受 boolean,省略 options、传 `{}` 或省略单个字段时均使用 `false`。这些选项只影响
80
+ * 当前代理所指向的目标:不会把外部 File 授权扩张到父目录或兄弟项,也不会绕过当前代理的 `mode`、
81
+ * Runtime session、Mini-program identity、`filesystem` 权限或 Host capability 检查。
82
+ */
14
83
  export interface CreateOptions {
84
+ /**
85
+ * 是否同时创建目标路径中缺失的父目录,默认 `false`。
86
+ *
87
+ * `false` 时任一父目录缺失会失败;`true` 时 Host 在当前 sandbox 或已授权目录范围内创建缺失父目录。
88
+ * 它不改变目标已存在时的处理方式,也不能跨出当前逻辑 root。
89
+ */
15
90
  recursive?: boolean;
91
+ /**
92
+ * 目标已存在时是否失败,默认 `false`。
93
+ *
94
+ * `false` 是不破坏内容的 ensure-exists:同类型目标已存在时成功,不清空已有文件。`true` 要求本次
95
+ * 新建目标,文件或目录已存在时分别返回 `FILE_ALREADY_EXISTS` / `DIRECTORY_ALREADY_EXISTS`。
96
+ * 该字段只约束最终目标,不要求 `recursive` 创建的父目录也必须全新。
97
+ */
16
98
  exclusive?: boolean;
17
99
  }
100
+ /** 删除目录时的选项。 */
18
101
  export interface RemoveOptions {
19
102
  /** 是否递归删除目录内容,默认 `false`。 */
20
103
  recursive?: boolean;
21
104
  }
105
+ /** 枚举目录直接子项时的选项。 */
22
106
  export interface ListOptions {
107
+ /**
108
+ * 本次最多返回的直接子项数量,默认 `1000`。
109
+ *
110
+ * 必须是 `1` 到 `1000`(含)之间的 safe integer。`0`、负数、小数、`NaN`、无穷大或 unsafe
111
+ * integer 返回 `INVALID_PARAMS`;大于 `1000` 返回 `DIRECTORY_LIST_LIMIT_EXCEEDED`。该字段只是
112
+ * 单次结果上限,不是 offset、cursor 或递归深度,也没有配套的总数或截断标记。
113
+ */
23
114
  limit?: number;
24
115
  }
25
- /** 可同步派生 lazy File/Directory proxy 的逻辑根。 */
116
+ /**
117
+ * 可同步派生 lazy File/Directory proxy 的逻辑根。
118
+ *
119
+ * @remarks
120
+ * 派生只创建当前 SDK session 内的冻结代理,不执行 I/O,也不暴露宿主真实路径。
121
+ * 路径在调用时同步校验,后续读写才通过 Host 访问目标。
122
+ */
26
123
  export interface PathRoot {
27
124
  /**
28
125
  * 按规范相对路径派生文件代理。
29
126
  *
30
- * @param relativePath - 使用 `/` 分隔的规范相对路径。
31
- * @returns 延迟访问对应文件的代理。
127
+ * @param relativePath - 相对于当前逻辑根、使用 `/` 分隔的规范路径。必须是非空字符串,不能以
128
+ * `/` 开头或结尾,不能包含空 segment、反斜杠、NUL 或其他控制字符;任一 segment 恰为 `.` 或
129
+ * `..` 都会拒绝,包括整个参数 `'.'`。`.env`、`report..json` 等不等于点段的普通名称可以使用。
130
+ * @returns 当前 SDK session 内延迟访问目标文件的冻结
131
+ * [FileHandle](/reference/symbols/root/interfaces/FileHandle)。其 `kind` 固定为 `'file'`,`name` 是
132
+ * `relativePath` 的末段 basename,`mode` 继承当前逻辑根;因此 `files.sandbox.file()` 返回
133
+ * `readwrite`,从用户选择目录继续派生时则继承所选目录的 `read` 或 `readwrite`,不能通过子路径
134
+ * 提升权限。
135
+ * @throws [HbMiniProgramSDKError](/reference/symbols/root/classes/HbMiniProgramSDKError)
136
+ * `relativePath` 不是字符串、为空、以 `/` 开头或结尾,包含连续 `/`、任一 `.` / `..` 点段、
137
+ * 反斜杠或控制字符时,同步抛出 `INVALID_PARAMS`。
138
+ *
139
+ * @remarks
140
+ * 该方法同步校验路径并创建 lazy proxy,不检查文件是否存在或创建文件,不读取内容或元数据,不发送
141
+ * bridge 请求,也不会打开系统选择器。调用本身因此不需要用户手势,不会触发 Host operation,
142
+ * 不会占用 `pickFiles()` / `saveFile()` 的 direct handle 配额,也不会暴露宿主真实路径。
143
+ *
144
+ * 后续 I/O 才要求在 `package.json#heybox.permissions` 中声明并启用 `filesystem`,并由 Host 开放
145
+ * 对应 operation:[FileHandle](/reference/symbols/root/interfaces/FileHandle) 的 `create()`、`remove()`、
146
+ * `exists()`、`readText()`、`readBytes()`、`writeText()`、`writeBytes()`、`stat()` 分别使用
147
+ * `file.create`、`file.remove`、`file.exists`、`file.readText`、`file.readBytes`、`file.writeText`、
148
+ * `file.writeBytes`、`file.stat`。未声明或未启用权限时分别返回 `PERMISSION_NOT_DECLARED` 或
149
+ * `PERMISSION_DENIED`,Host 未开放具体 operation 时返回 `METHOD_FORBIDDEN`;这些错误在调用异步
150
+ * 方法时发生,不由本方法抛出。
151
+ *
152
+ * 代理只表达目标位置。`exists()` 可区分文件缺失或目标实际为目录;`create()` 可显式确保文件存在,
153
+ * `writeText()` / `writeBytes()` 也可隐式创建目标文件,但不会自动创建缺失的父目录。只读父目录派生
154
+ * 的文件可以读取与查询,调用 `create()`、写入或删除会返回 `FILE_ACCESS_DENIED`;外部目录派生的
155
+ * 文件即使是 `readwrite` 也不能删除。
156
+ *
157
+ * 若目标是目录或需要先创建父目录,使用
158
+ * [files.sandbox.directory()](/reference/sdk/files/sandbox/directory)。若要让用户选择现有的精确外部
159
+ * 文件,使用 [files.pickFiles()](/reference/sdk/files/pickFiles);若要让用户指定新的精确可写目标,
160
+ * 使用 [files.saveFile()](/reference/sdk/files/saveFile)。
161
+ *
162
+ * @example
163
+ * ```ts
164
+ * import hbSDK from '@heybox/hb-sdk'
165
+ *
166
+ * // 构造代理时没有 I/O,且不会隐式创建 reports 目录。
167
+ * const report = hbSDK.files.sandbox.file('reports/latest.json')
168
+ * console.log(report.kind, report.name, report.mode)
169
+ * // file, latest.json, readwrite
170
+ *
171
+ * await hbSDK.files.sandbox.directory('reports').create({ recursive: true })
172
+ * await report.writeText(JSON.stringify({ generatedAt: Date.now() }))
173
+ *
174
+ * if (await report.exists()) {
175
+ * console.log(await report.readText())
176
+ * console.log((await report.stat()).size)
177
+ * }
178
+ * ```
179
+ *
180
+ * @see [files.sandbox.directory()](/reference/sdk/files/sandbox/directory) 派生或创建沙箱目录。
181
+ * @see [files.pickFiles()](/reference/sdk/files/pickFiles) 通过可信用户操作取得现有外部文件授权。
182
+ * @see [files.saveFile()](/reference/sdk/files/saveFile) 通过可信用户操作取得精确可写目标。
183
+ * @see [FileHandle](/reference/symbols/root/interfaces/FileHandle) 查看创建、读写、状态与删除方法。
184
+ * @see [文件能力与沙箱](/guide/files-and-sandbox) 路径、权限、Host operation 与配额说明。
185
+ *
32
186
  * @since 0.8.0-alpha.2
33
187
  * @hbPlatform android
34
188
  * @hbPlatform ios
@@ -45,8 +199,59 @@ export interface PathRoot {
45
199
  /**
46
200
  * 按规范相对路径派生目录代理。
47
201
  *
48
- * @param relativePath - 使用 `/` 分隔的规范相对路径。
49
- * @returns 延迟访问对应目录的代理。
202
+ * @param relativePath - 相对于当前逻辑根、使用 `/` 分隔的规范路径。必须是非空字符串,不能以
203
+ * `/` 开头或结尾,不能包含空 segment、反斜杠、NUL 或其他控制字符。`.` 是仅有的特例:只有
204
+ * 整个参数等于 `'.'` 时才表示当前逻辑根;`./cache`、`cache/.`、`cache/../secret` 等含点段路径
205
+ * 不会被折叠或解析,而会直接拒绝。
206
+ * @returns 当前 SDK session 内延迟访问目标目录的冻结
207
+ * [DirectoryHandle](/reference/symbols/root/interfaces/DirectoryHandle)。其 `kind` 固定为
208
+ * `'directory'`,`name` 是末段 basename(传 `'.'` 时为 `'.'`),`mode` 继承当前逻辑根;因此
209
+ * `files.sandbox.directory()` 返回 `readwrite`,从用户选择目录继续派生时则继承所选目录的
210
+ * `read` 或 `readwrite`,不能通过子路径提升权限。
211
+ * @throws [HbMiniProgramSDKError](/reference/symbols/root/classes/HbMiniProgramSDKError)
212
+ * `relativePath` 不是字符串、为空、以 `/` 开头或结尾,包含连续 `/`、任何 `.` / `..` 点段、
213
+ * 反斜杠或控制字符时,同步抛出 `INVALID_PARAMS`;完整参数 `'.'` 除外。
214
+ *
215
+ * @remarks
216
+ * 该方法同步校验路径并创建 lazy proxy,不检查目录是否存在或创建目录,不执行文件 I/O,不发送
217
+ * bridge 请求,也不会打开系统选择器。调用本身因此不需要用户手势,不会触发 Host operation,
218
+ * 不会占用 picker / `saveFile()` 的 direct handle 配额,也不会暴露宿主真实路径。
219
+ *
220
+ * 后续 I/O 才要求在 `package.json#heybox.permissions` 中声明并启用 `filesystem`,并由 Host 开放
221
+ * 对应 operation:[DirectoryHandle](/reference/symbols/root/interfaces/DirectoryHandle) 的 `create()`、
222
+ * `exists()`、`list()`、`remove()` 分别使用 `directory.create`、`directory.exists`、
223
+ * `directory.list`、`directory.remove`。未声明或未启用权限时分别返回
224
+ * `PERMISSION_NOT_DECLARED` 或 `PERMISSION_DENIED`,Host 未开放具体 operation 时返回
225
+ * `METHOD_FORBIDDEN`;这些错误在调用异步方法时发生,不由本方法抛出。
226
+ *
227
+ * `files.sandbox.directory('.')` 是沙箱根目录的逻辑代理,可用于 `exists()` 或 `list()`,但不能删除;
228
+ * 对它调用 `remove()` 会返回 `FILE_ACCESS_DENIED`。普通子目录代理只表达目标位置:需要确保目录
229
+ * 存在时调用 `create()`,需要观察直接子项时调用 `list()`。若目标是文件,使用
230
+ * [files.sandbox.file()](/reference/sdk/files/sandbox/file);若要访问用户选择的外部目录,使用
231
+ * [files.pickDirectory()](/reference/sdk/files/pickDirectory)。
232
+ *
233
+ * @example
234
+ * ```ts
235
+ * import hbSDK from '@heybox/hb-sdk'
236
+ *
237
+ * // 构造代理时没有 I/O;父目录也不会被隐式创建。
238
+ * const reports = hbSDK.files.sandbox.directory('reports/2026')
239
+ * console.log(reports.kind, reports.name, reports.mode)
240
+ * // directory, 2026, readwrite
241
+ *
242
+ * await reports.create({ recursive: true })
243
+ *
244
+ * // `.` 只作为完整参数表示沙箱根;它不是可嵌入路径的点段。
245
+ * const root = hbSDK.files.sandbox.directory('.')
246
+ * const entries = await root.list({ limit: 100 })
247
+ * console.log(entries.map(entry => entry.name))
248
+ * ```
249
+ *
250
+ * @see [files.sandbox.file()](/reference/sdk/files/sandbox/file) 派生沙箱文件代理。
251
+ * @see [files.pickDirectory()](/reference/sdk/files/pickDirectory) 通过可信用户操作取得外部目录授权。
252
+ * @see [DirectoryHandle](/reference/symbols/root/interfaces/DirectoryHandle) 查看 `create()`、`exists()`、`list()` 与 `remove()`。
253
+ * @see [文件能力与沙箱](/guide/files-and-sandbox) 路径、权限、Host operation 与配额说明。
254
+ *
50
255
  * @since 0.8.0-alpha.2
51
256
  * @hbPlatform android
52
257
  * @hbPlatform ios
@@ -61,53 +266,1099 @@ export interface PathRoot {
61
266
  */
62
267
  directory(relativePath: string): DirectoryHandle;
63
268
  }
64
- /** Mini-program 私有 sandbox 的逻辑根。 */
269
+ /**
270
+ * Mini-program 私有 sandbox 的逻辑根。
271
+ *
272
+ * @remarks
273
+ * sandbox 按 Mini-program identity 隔离并由 Host 持久保存;它是逻辑根,不是本机路径。
274
+ * sandbox 派生对象固定为 `readwrite`,但每次 I/O 仍需已声明 `filesystem` 权限且 Host 支持对应 operation。
275
+ */
65
276
  export interface FileSystem extends PathRoot {
66
277
  }
67
- /** 当前 SDK session 中的文件代理。 */
278
+ /**
279
+ * 当前 SDK session 中的文件代理。
280
+ *
281
+ * @remarks
282
+ * 代理是冻结的能力对象,不是原生 `File` 或文件路径。picker / `saveFile()` 返回的精确授权仅在当前
283
+ * Runtime session 有效;sandbox 或已授权目录派生的逻辑代理不会在创建时执行 I/O。
284
+ */
68
285
  export interface FileHandle {
286
+ /** 可用于区分文件与目录的固定标记。 */
69
287
  readonly kind: 'file';
288
+ /** 文件 basename,不包含父目录或真实路径。 */
70
289
  readonly name: string;
290
+ /** 当前代理被授予的访问模式。 */
71
291
  readonly mode: FileMode;
292
+ /**
293
+ * 确保文件存在并返回同一个代理。
294
+ *
295
+ * @param options - 可选的父目录创建与目标独占创建设置。省略时等同于
296
+ * `{ recursive: false, exclusive: false }`;完整语义见 {@link CreateOptions}。
297
+ * @returns 当前同一个 `FileHandle` proxy;成功后 `result === file`。方法不会读取文件,且默认的
298
+ * ensure-exists 不会截断或改写已有内容。
299
+ * @throws {@link HbMiniProgramSDKError} options 非对象,或 `recursive` / `exclusive` 不是 boolean 时
300
+ * 返回 `INVALID_PARAMS`;代理不是 `readwrite` 时在发送 bridge 请求前返回 `FILE_ACCESS_DENIED`。
301
+ * @throws {@link HbMiniProgramSDKError} 未声明或未启用 `filesystem` 时返回
302
+ * `PERMISSION_NOT_DECLARED` / `PERMISSION_DENIED`;Host 未开放或未协商到 `file.create` 时返回
303
+ * `METHOD_FORBIDDEN`,旧 Runtime 可返回 `METHOD_NOT_FOUND`。
304
+ * @throws {@link HbMiniProgramSDKError} `recursive: false` 且父目录缺失时返回
305
+ * `DIRECTORY_NOT_FOUND`;目标实际是目录或路径中的祖先实际是文件时返回 `FILE_TYPE_MISMATCH`;
306
+ * `exclusive: true` 且文件已存在时返回 `FILE_ALREADY_EXISTS`。
307
+ * @throws {@link HbMiniProgramSDKError} 外部 direct handle 已失效或不属于当前 Runtime session 时返回
308
+ * `FILE_ACCESS_REVOKED`;Host 创建失败、响应异常或底层平台 I/O 失败时返回相应稳定文件错误码,
309
+ * 无法识别的 Host 错误统一为 `FILE_IO_FAILED`。
310
+ *
311
+ * @remarks
312
+ * 目标缺失时创建空文件。`recursive: true` 会在当前逻辑 root 内同时创建缺失父目录;它不会允许
313
+ * `..`、绝对路径或跨越用户授权边界。目标已是文件时,默认调用作为幂等的 ensure-exists 成功,
314
+ * 保留原内容;需要检测冲突时传 `exclusive: true`。若目标实际为目录,不会把目录替换为文件。
315
+ *
316
+ * 调用要求当前代理的 `mode === 'readwrite'`。sandbox 文件固定继承 `readwrite`;从用户选择的目录
317
+ * 派生时继承该目录的 `mode`,因此只读目录的后代不能创建。用户选择或 `saveFile()` 返回的精确
318
+ * 外部 File 也只能在获授 `readwrite` 时调用;操作仍局限于该精确文件,不能取得父目录或兄弟文件。
319
+ * Runtime 会重新校验 direct handle 的 session/provenance,Host 还会绑定当前 Mini-program identity。
320
+ * 该方法不需要可信用户手势,也不会创建新的 direct handle、消耗 1024 个外部授权句柄配额或暴露真实路径。
321
+ *
322
+ * 新 PC Host 支持该 operation;Android/iOS 需要 `1.3.396+` 并以 `system.describe` 实际宣告的
323
+ * operation 为准,OHOS 同样按 Host 协商结果启用。Android 的精确 SAF File 仅授予 `read`,因此
324
+ * 不能调用本方法;sandbox 或可写目录派生文件不受该精确 File 限制。Web、Browser Dev Host、旧 Host
325
+ * 或 operation 集不完整时 fail closed,不提供 Blob 或内存 fallback。
326
+ *
327
+ * `create()` 只创建空目标。父目录已经存在时,{@link FileHandle.writeText} /
328
+ * {@link FileHandle.writeBytes} 也可隐式创建文件并写入内容;它们不会自动创建父目录。若需要先确保
329
+ * 目录存在,使用 {@link DirectoryHandle.create};只需探测目标时使用 {@link FileHandle.exists}。
330
+ *
331
+ * @example
332
+ * ```ts
333
+ * import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
334
+ *
335
+ * const report = hbSDK.files.sandbox.file('reports/2026/summary.json')
336
+ * const sameReport = await report.create({ recursive: true })
337
+ * console.assert(sameReport === report)
338
+ *
339
+ * await report.writeText('{"ready":true}')
340
+ * await report.create() // 已存在时成功,原内容不变
341
+ * console.log(await report.readText())
342
+ *
343
+ * try {
344
+ * await report.create({ exclusive: true })
345
+ * } catch (error) {
346
+ * if (!(error instanceof HbMiniProgramSDKError) || error.code !== 'FILE_ALREADY_EXISTS') throw error
347
+ * }
348
+ * ```
349
+ *
350
+ * @see {@link CreateOptions}
351
+ * @see {@link FileHandle.exists}
352
+ * @see {@link FileHandle.writeText}
353
+ * @see {@link FileHandle.writeBytes}
354
+ * @see {@link DirectoryHandle.create}
355
+ * @see {@link FilesModule.pickDirectory | files.pickDirectory}
356
+ * @see {@link https://docs.xiaoheihe.cn/hb_sdk/guide/files-and-sandbox | 文件能力与沙箱}
357
+ * @see {@link https://docs.xiaoheihe.cn/hb_sdk/guide/error-handling | 错误处理}
358
+ * @see {@link https://docs.xiaoheihe.cn/hb_sdk/guide/permissions | 权限声明}
359
+ *
360
+ * @since 0.8.0-alpha.2
361
+ * @hbPlatform android
362
+ * @hbPlatform ios
363
+ * @hbPlatform ohos
364
+ * @hbPlatform windows
365
+ * @hbPlatform macos
366
+ * @hbClient android numeric-dot \>= 1.3.396
367
+ * @hbClient ios numeric-dot \>= 1.3.396
368
+ * @hbClient ohos none
369
+ * @hbClient windows none
370
+ * @hbClient macos none
371
+ */
72
372
  create(options?: CreateOptions): Promise<FileHandle>;
73
- /** 删除 sandbox 文件;外部授权文件不允许删除。 */
373
+ /**
374
+ * 删除当前代理指向的 sandbox 文件。
375
+ *
376
+ * @returns Host 完成删除后以 `undefined` resolve;当前 `FileHandle` 代理本身仍可复用,后续可用
377
+ * {@link FileHandle.exists | exists()} 确认目标已不存在,或用 {@link FileHandle.create | create()}
378
+ * 在同一位置重新创建文件。
379
+ * @throws {@link HbMiniProgramSDKError} 代理为只读,或来源是 `pickFiles()`、`saveFile()`、外部
380
+ * Directory 派生项/枚举项时返回 `FILE_ACCESS_DENIED`;外部授权即使为 `readwrite` 也不能删除。
381
+ * @throws {@link HbMiniProgramSDKError} 目标或祖先不存在时返回 `FILE_NOT_FOUND` /
382
+ * `DIRECTORY_NOT_FOUND`,目标实际是目录时可返回 `FILE_TYPE_MISMATCH`;授权失效或 Host 删除失败
383
+ * 时返回 `FILE_ACCESS_REVOKED` / `FILE_IO_FAILED` 等稳定文件错误码。
384
+ * @throws {@link HbMiniProgramSDKError} 未声明或未启用 `filesystem` 时返回
385
+ * `PERMISSION_NOT_DECLARED` / `PERMISSION_DENIED`;Host 未开放 `file.remove` operation 时返回
386
+ * `METHOD_FORBIDDEN`,旧 Runtime 不认识该 method 时可返回 `METHOD_NOT_FOUND`。
387
+ *
388
+ * @remarks
389
+ * 该方法只删除一个文件,不接受参数,也不删除目录。可删除对象必须同时来自当前
390
+ * Mini-program 的 sandbox 且为 `readwrite`;`files.sandbox.file()` 和 sandbox 目录的 `list()`
391
+ * 结果满足来源约束。若目标是目录,使用 {@link DirectoryHandle.remove};删除非空目录还需显式
392
+ * 传入 `{ recursive: true }`。
393
+ *
394
+ * `remove()` 不会先调用 `exists()`,也不是幂等的“确保不存在”操作:lazy sandbox 代理可以在
395
+ * 文件尚不存在时构造,此时调用删除会按 Host 结果抛出缺失错误。即使先由 `exists()` 返回
396
+ * `true`,目标仍可能在两次异步调用之间变化,因此仍应处理 `FILE_NOT_FOUND` /
397
+ * `DIRECTORY_NOT_FOUND`。调用不要求可信用户手势,也不占用外部 direct-handle 配额。
398
+ *
399
+ * 新 PC Host 支持该操作;Android/iOS `1.3.396+` 和 OHOS 仍以启动时
400
+ * `system.describe` 宣告的 `files.remove` operation 为准。Web、Browser Dev Host、旧 Host 或
401
+ * operation 缺失时 fail closed,不提供浏览器文件系统或内存 fallback。
402
+ *
403
+ * @example
404
+ * ```ts
405
+ * import hbSDK from '@heybox/hb-sdk'
406
+ *
407
+ * const draft = hbSDK.files.sandbox.file('draft.txt')
408
+ * await draft.writeText('temporary')
409
+ *
410
+ * if (await draft.exists()) {
411
+ * await draft.remove()
412
+ * }
413
+ * console.log(await draft.exists()) // false
414
+ *
415
+ * // 代理仍表示同一个 sandbox 位置,可以重新创建。
416
+ * await draft.create()
417
+ * ```
418
+ *
419
+ * @see {@link FileHandle.create}
420
+ * @see {@link FileHandle.exists}
421
+ * @see {@link DirectoryHandle.remove}
422
+ * @see [files.sandbox.file()](/reference/sdk/files/sandbox/file) 创建 sandbox 文件代理。
423
+ * @see [文件能力与沙箱](/guide/files-and-sandbox) 查看来源、平台与错误码边界。
424
+ */
74
425
  remove(): Promise<void>;
426
+ /**
427
+ * 检查当前代理是否仍解析到一个文件。
428
+ *
429
+ * @returns Host 能取得目标且确认其类型为文件时返回 `true`。目标文件不存在、任一祖先目录
430
+ * 不存在,或同一逻辑位置实际是目录时返回 `false`;这些正常的“不存在”结果不会抛出
431
+ * `FILE_NOT_FOUND`、`DIRECTORY_NOT_FOUND` 或 `FILE_TYPE_MISMATCH`。
432
+ * @throws {@link HbMiniProgramSDKError} 未声明或未启用 `filesystem` 权限时分别以
433
+ * `PERMISSION_NOT_DECLARED`、`PERMISSION_DENIED` 拒绝;当前 Host 未开放 `file.exists` 时以
434
+ * `METHOD_FORBIDDEN` 拒绝,旧 Runtime 也可能返回 `METHOD_NOT_FOUND`。
435
+ * @throws {@link HbMiniProgramSDKError} picker / `saveFile()` 返回的精确外部授权被撤销、句柄
436
+ * 不属于当前 Runtime session 或 registry 已释放时,以 `FILE_ACCESS_REVOKED` 拒绝,而不是返回
437
+ * `false`;SDK 已销毁或 Runtime 已卸载时分别以 `SDK_DESTROYED`、`RUNTIME_UNAVAILABLE` 拒绝。
438
+ * @throws {@link HbMiniProgramSDKError} Host 拒绝访问、`stat` 探测失败、返回非布尔 bridge 结果
439
+ * 或发生其他文件 I/O 失败时,以 `FILE_ACCESS_DENIED`、`FILE_IO_FAILED` 或对应 SDK / bridge
440
+ * 错误拒绝。调用方不应把所有异常都解释为“不存在”。
441
+ *
442
+ * @remarks
443
+ * 这是只读查询,不创建文件、不读取内容、不修改访问模式,也不要求可信用户手势。
444
+ * `mode: 'read'` 与 `mode: 'readwrite'` 的 {@link FileHandle} 均可调用;但成功返回 `true` 不会
445
+ * 授予写权限,后续 `create()`、写入或删除仍受当前 mode、来源和 Host operation 限制。
446
+ *
447
+ * Runtime 使用 Host 的文件状态原语完成检查,但该布尔结果不是 {@link FileHandle.stat | stat()}
448
+ * 的缓存或替代品,也不包含大小与时间戳。它只描述本次探测时的状态:目标可能在 resolve 后
449
+ * 被删除、替换或撤销授权,因此后续 `readText()`、`stat()` 或写入仍可能失败;不要用
450
+ * `exists()` 作为权限检查或消除并发竞态。
451
+ *
452
+ * 对 sandbox lazy proxy,返回 `false` 后可在 `readwrite` 模式下调用
453
+ * {@link FileHandle.create | create()} 显式确保文件存在;缺失父目录时由 `create({ recursive: true })`
454
+ * 决定是否一并创建。对 picker / `saveFile()` 的精确外部 FileHandle,授权失效属于错误,不等价于
455
+ * 文件不存在。若要检查目录,应使用 {@link DirectoryHandle.exists | DirectoryHandle.exists()},
456
+ * 目录位于当前文件代理对应位置时本方法返回 `false`。
457
+ *
458
+ * 新 PC Host 支持该操作;Android / iOS `1.3.396+` 仅在 `system.describe` 宣告
459
+ * `files.stat` 时逐项启用,OHOS 同样以 Host 实际协商结果为准。Web、Browser Dev Host、旧 Host
460
+ * 或缺少该 operation 的环境会 fail closed,不提供浏览器 File / Blob 或内存 fallback;页面应
461
+ * 处理 `METHOD_FORBIDDEN`,不要仅按操作系统推断可用性。
462
+ *
463
+ * @example
464
+ * ```ts
465
+ * import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
466
+ *
467
+ * const report = hbSDK.files.sandbox.file('reports/latest.json')
468
+ *
469
+ * try {
470
+ * if (!(await report.exists())) {
471
+ * await report.create({ recursive: true })
472
+ * await report.writeText('{}')
473
+ * }
474
+ *
475
+ * // exists() 之后状态仍可能变化,实际读取错误仍需处理。
476
+ * console.log(await report.readText())
477
+ * } catch (error) {
478
+ * if (error instanceof HbMiniProgramSDKError && error.code === 'METHOD_FORBIDDEN') {
479
+ * showFilesUnsupported()
480
+ * } else {
481
+ * throw error
482
+ * }
483
+ * }
484
+ * ```
485
+ *
486
+ * @see {@link FileHandle.create | FileHandle.create()} 确保 sandbox 文件存在。
487
+ * @see {@link FileHandle.stat | FileHandle.stat()} 读取文件大小与 Host 可提供的时间戳。
488
+ * @see {@link DirectoryHandle.exists | DirectoryHandle.exists()} 检查目录类型的目标。
489
+ * @see [files.sandbox.file()](/reference/sdk/files/sandbox/file) 创建 sandbox lazy FileHandle。
490
+ * @see [files.pickFiles()](/reference/sdk/files/pickFiles) 取得当前 session 的精确外部文件授权。
491
+ * @see [文件能力与沙箱](/guide/files-and-sandbox) 查看权限、平台与 Host operation 说明。
492
+ *
493
+ * @since 0.8.0-alpha.2
494
+ * @hbPlatform android
495
+ * @hbPlatform ios
496
+ * @hbPlatform ohos
497
+ * @hbPlatform windows
498
+ * @hbPlatform macos
499
+ * @hbClient android numeric-dot \>= 1.3.396
500
+ * @hbClient ios numeric-dot \>= 1.3.396
501
+ * @hbClient ohos none
502
+ * @hbClient windows none
503
+ * @hbClient macos none
504
+ */
75
505
  exists(): Promise<boolean>;
506
+ /**
507
+ * 将完整文件按文本读取。
508
+ *
509
+ * @returns Runtime 将 Host 返回的完整字节序列按严格 UTF-8 解码后的字符串。空文件返回 `''`;
510
+ * 换行、NUL 与其他合法 Unicode 内容保持不变。UTF-8 decoder 会剥离第一个开头 BOM;若解码结果
511
+ * 仍以 `U+FEFF` 开头,Runtime 再移除一个,因此一到两个连续前导 UTF-8 BOM 都不会出现在结果中。
512
+ * @throws {@link HbMiniProgramSDKError} 文件不是合法 UTF-8 时返回 `FILE_ENCODING_INVALID`,不会用
513
+ * replacement character 静默替换坏字节。需要无损读取任意二进制或保留 BOM 时使用
514
+ * {@link FileHandle.readBytes | readBytes()}。
515
+ * @throws {@link HbMiniProgramSDKError} 目标或祖先不存在时返回 `FILE_NOT_FOUND` / `DIRECTORY_NOT_FOUND`,
516
+ * 目标类型不匹配时返回 `FILE_TYPE_MISMATCH`。Android/iOS 当前对一次完整读取设 8 MiB 上限,
517
+ * 超限时返回 `FILE_TOO_LARGE`。
518
+ * @throws {@link HbMiniProgramSDKError} 普通 sandbox / picker / `saveFile()` 句柄未声明或未启用
519
+ * `filesystem` 时返回 `PERMISSION_NOT_DECLARED` / `PERMISSION_DENIED`;Host 未开放或未协商到
520
+ * `file.readText` 时返回 `METHOD_FORBIDDEN`,旧 Runtime 可返回 `METHOD_NOT_FOUND`。
521
+ * @throws {@link HbMiniProgramSDKError} 外部 direct handle 已失效、来自其他或已结束的 Runtime
522
+ * session 时返回 `FILE_ACCESS_REVOKED`;SDK / Runtime 已终止、调用超时、Host 返回无效内容或底层
523
+ * I/O 失败时返回 `SDK_DESTROYED`、`RUNTIME_DESTROYED`、`REQUEST_TIMEOUT` 或 `FILE_IO_FAILED` 等
524
+ * 对应 SDK 错误。
525
+ *
526
+ * @remarks
527
+ * 该方法读取并缓冲整个文件,没有 offset、range、stream、encoding 或 `AbortSignal` 参数。移动端
528
+ * Host 可以在内部按 chunk 读取,但公开 Promise 只在全部字节读取、复制和 UTF-8 解码完成后 resolve;
529
+ * 读取失败不会返回部分文本。8 MiB 是 Android/iOS 当前 Host 的原始文件字节上限,不是 JavaScript
530
+ * 字符串长度限制;新 PC Host 的限制由实际 Host I/O 合同决定。
531
+ *
532
+ * `mode: 'read'` 与 `mode: 'readwrite'` 句柄都可以读取,调用不需要可信用户手势,也不会弹出 picker、
533
+ * 创建文件、修改内容或延长外部授权寿命。picker / `saveFile()` 返回的 direct handle 只在当前
534
+ * Runtime session 有效;sandbox lazy ref 会在每次调用时按当前 Mini-program identity 解析。
535
+ * Companion `attachments.open()` 返回的只读 FileHandle 是受控例外:其 `readText()` 由 `companion`
536
+ * provenance 授权,不额外要求 `filesystem`,但仍受当前 Companion / Runtime session 生命周期约束。
537
+ *
538
+ * {@link FileHandle.writeText | writeText()} 执行相反方向的完整 UTF-8 编码与覆盖写入;它不会添加 BOM,
539
+ * 且要求 `mode === 'readwrite'`。若内容可能不是文本,或业务需要区分 BOM 和文件正文,应使用
540
+ * {@link FileHandle.readBytes | readBytes()} 获取原始字节并自行解析。
541
+ *
542
+ * @example
543
+ * ```ts
544
+ * import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
545
+ *
546
+ * const settings = hbSDK.files.sandbox.file('settings.json')
547
+ *
548
+ * try {
549
+ * const text = await settings.readText()
550
+ * const value = JSON.parse(text)
551
+ * console.log(value)
552
+ * } catch (error) {
553
+ * if (error instanceof HbMiniProgramSDKError && error.code === 'FILE_ENCODING_INVALID') {
554
+ * // readBytes() 保留原始字节和 BOM,可交给业务自己的格式解析器。
555
+ * const bytes = await settings.readBytes()
556
+ * console.warn('settings.json 不是 UTF-8', bytes)
557
+ * } else if (error instanceof HbMiniProgramSDKError && error.code === 'FILE_NOT_FOUND') {
558
+ * await settings.writeText('{}')
559
+ * } else {
560
+ * throw error
561
+ * }
562
+ * }
563
+ * ```
564
+ *
565
+ * @see {@link FileHandle.readBytes | FileHandle.readBytes()} 无损读取原始字节并保留 BOM。
566
+ * @see {@link FileHandle.writeText | FileHandle.writeText()} 以 UTF-8 覆盖写入完整字符串。
567
+ * @see {@link FileHandle.stat | FileHandle.stat()} 在读取前查看文件字节数。
568
+ * @see [files.pickFiles()](/reference/sdk/files/pickFiles) 取得当前 session 的外部文件授权。
569
+ * @see [文件能力与沙箱](/guide/files-and-sandbox) 查看权限、平台限制与错误码。
570
+ */
76
571
  readText(): Promise<string>;
572
+ /**
573
+ * 将字符串按 UTF-8 编码后完整写入文件。
574
+ *
575
+ * @param content - 要写入的 JavaScript 字符串。必须确实是 `string`;SDK 不会对对象调用
576
+ * `String()`,也不接受 `Uint8Array`、`Blob`、stream 或 encoding 选项。空字符串合法,会把目标
577
+ * 替换为空文件。需要精确控制原始字节时使用 {@link FileHandle.writeBytes | writeBytes()}。
578
+ * @returns Runtime 完成 UTF-8 编码且 Host 的完整写入请求成功后以 `undefined` resolve。移动端会
579
+ * 等待最后一个带 EOF 的 chunk 获得 Host 响应;该时点不返回写入字节数、文件元数据或新的
580
+ * `FileHandle`,也不承诺操作系统已执行物理 `fsync`。
581
+ * @throws {@link HbMiniProgramSDKError} `content` 不是字符串时在 Host I/O 前以
582
+ * `INVALID_PARAMS` 拒绝;当前代理的 `mode` 不是 `readwrite` 时在发送 bridge 请求前以
583
+ * `FILE_ACCESS_DENIED` 拒绝。
584
+ * @throws {@link HbMiniProgramSDKError} 未声明或未启用 `filesystem` 权限时分别以
585
+ * `PERMISSION_NOT_DECLARED`、`PERMISSION_DENIED` 拒绝;Host 未开放 `file.writeText` 时以
586
+ * `METHOD_FORBIDDEN` 拒绝,旧 Runtime 也可能返回 `METHOD_NOT_FOUND`。
587
+ * @throws {@link HbMiniProgramSDKError} 缺失父目录时返回 `DIRECTORY_NOT_FOUND`,路径中的祖先
588
+ * 或目标类型不匹配时返回 `FILE_TYPE_MISMATCH`。Android / iOS 对一次完整写入的 UTF-8 编码结果
589
+ * 设 `8 MiB` 上限,超过 `8 * 1024 * 1024` bytes 时返回 `FILE_TOO_LARGE`;该限制按字节而不是
590
+ * JavaScript 字符数计算。
591
+ * @throws {@link HbMiniProgramSDKError} 外部 direct handle 被撤销、不属于当前 Runtime session
592
+ * 或 registry 已释放时返回 `FILE_ACCESS_REVOKED`;SDK 已销毁、Runtime 已卸载、请求超时、Host
593
+ * 响应异常或底层 I/O 失败时,分别以 `SDK_DESTROYED`、`RUNTIME_UNAVAILABLE`、
594
+ * `REQUEST_TIMEOUT`、`FILE_IO_FAILED` 或对应稳定文件错误码拒绝。
595
+ *
596
+ * @remarks
597
+ * Runtime 使用标准 `TextEncoder` 把完整字符串编码为不带 BOM 的 UTF-8,再调用 Host 的完整文件
598
+ * 写原语。该方法不是 append、range write 或 stream:已有文件内容会被本次编码结果整体替换,
599
+ * 写入 `''` 会把文件截断为零字节。若 Host 在写入中途失败,Promise 会拒绝;公开合同不承诺失败
600
+ * 时回滚旧内容或提供跨进程原子替换,需要事务语义时应由业务使用临时文件和自己的提交协议。
601
+ *
602
+ * 目标文件本身不存在时可以隐式创建,因此通常不需要先调用
603
+ * {@link FileHandle.create | create()};但父目录必须已经存在,`writeText()` 不会递归创建目录。
604
+ * 需要创建父目录时先调用 {@link DirectoryHandle.create | DirectoryHandle.create()},或对文件调用
605
+ * `create({ recursive: true })`。不要用 `exists()` 后再写来消除竞态:目标可能在两次异步调用之间
606
+ * 变化,实际写入错误仍应处理。
607
+ *
608
+ * sandbox lazy FileHandle 固定继承 `readwrite`,并在每次调用时按当前 Mini-program identity 解析。
609
+ * `pickFiles({ mode: 'readwrite' })`、`pickDirectory({ mode: 'readwrite' })` 的派生文件和
610
+ * `saveFile()` 返回的精确外部 FileHandle 也可以写入,但授权范围不会因此扩张;direct handle 只在
611
+ * 当前 Runtime session 有效。只读 picker 结果、Android 的精确 SAF File 和 Companion attachment
612
+ * 会在本地 mode 检查时以 `FILE_ACCESS_DENIED` 拒绝。该方法不需要新的可信用户手势;只有最初
613
+ * 获取外部授权的 picker / `saveFile()` 需要手势。
614
+ *
615
+ * 新 PC Host 支持该操作;Android / iOS `1.3.396+` 仅在 `system.describe` 同时宣告
616
+ * `files.openWrite`、`files.write`、`files.release` 时逐项启用,OHOS 同样以 Host 实际协商结果为准。
617
+ * Web、Browser Dev Host、旧 Host 或 operation 集不完整时 fail closed,不提供浏览器 File / Blob
618
+ * 或内存 fallback。新 PC Host 的大小限制由实际 Host 合同决定,不应套用移动端 8 MiB 上限。
619
+ *
620
+ * {@link FileHandle.readText | readText()} 可按严格 UTF-8 读取完整内容,但会移除前导 BOM;写入后
621
+ * 仍可能因为外部修改、授权撤销或 Session 结束而读取失败。需要检查最终字节数或时间戳时,在
622
+ * 写入成功后另行调用 {@link FileHandle.stat | stat()}。
623
+ *
624
+ * @example
625
+ * ```ts
626
+ * import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
627
+ *
628
+ * const reports = hbSDK.files.sandbox.directory('reports')
629
+ * await reports.create({ recursive: true })
630
+ *
631
+ * const report = reports.file('latest.txt')
632
+ * await report.writeText('第一版\n') // 文件不存在时隐式创建。
633
+ *
634
+ * try {
635
+ * await report.writeText('第二版\n') // 完整替换,不会追加到第一版后面。
636
+ * console.log(await report.readText()) // 第二版
637
+ * } catch (error) {
638
+ * if (error instanceof HbMiniProgramSDKError && error.code === 'FILE_TOO_LARGE') {
639
+ * console.warn('文本的 UTF-8 编码结果超过当前平台上限')
640
+ * } else {
641
+ * throw error
642
+ * }
643
+ * }
644
+ * ```
645
+ *
646
+ * @see {@link FileHandle.readText | FileHandle.readText()} 按严格 UTF-8 读取完整文件。
647
+ * @see {@link FileHandle.writeBytes | FileHandle.writeBytes()} 写入调用方提供的原始字节。
648
+ * @see {@link FileHandle.create | FileHandle.create()} 显式确保文件和可选父目录存在。
649
+ * @see {@link FileHandle.stat | FileHandle.stat()} 在写入后读取文件大小与时间戳。
650
+ * @see {@link DirectoryHandle.create | DirectoryHandle.create()} 先创建缺失父目录。
651
+ * @see [files.pickFiles()](/reference/sdk/files/pickFiles) 取得可选的精确外部文件写授权。
652
+ * @see [files.saveFile()](/reference/sdk/files/saveFile) 让用户指定新的精确可写目标。
653
+ * @see [文件能力与沙箱](/guide/files-and-sandbox) 查看路径、权限、平台与配额边界。
654
+ *
655
+ * @since 0.8.0-alpha.2
656
+ * @hbPlatform android
657
+ * @hbPlatform ios
658
+ * @hbPlatform ohos
659
+ * @hbPlatform windows
660
+ * @hbPlatform macos
661
+ * @hbClient android numeric-dot \>= 1.3.396
662
+ * @hbClient ios numeric-dot \>= 1.3.396
663
+ * @hbClient ohos none
664
+ * @hbClient windows none
665
+ * @hbClient macos none
666
+ */
77
667
  writeText(content: string): Promise<void>;
668
+ /**
669
+ * 将完整文件读取为新的字节数组。
670
+ *
671
+ * @returns 包含完整文件原始字节的新 `Uint8Array`。空文件返回长度为 `0` 的数组。Runtime 会先
672
+ * 复制 Host 字节,SDK 验证 bridge 结果后再创建当前可见区间的副本,因此返回值不与 Host / bridge
673
+ * 响应共享可变存储;修改数组只改变调用方的本地副本,不会写回文件。
674
+ * @throws {@link HbMiniProgramSDKError} 目标或祖先不存在时返回 `FILE_NOT_FOUND` / `DIRECTORY_NOT_FOUND`,
675
+ * 目标类型不匹配时返回 `FILE_TYPE_MISMATCH`。Android / iOS 当前对一次完整读取设 `8 MiB`
676
+ * (`8 * 1024 * 1024` bytes)上限,超限时返回 `FILE_TOO_LARGE`。
677
+ * @throws {@link HbMiniProgramSDKError} 普通 sandbox / picker / `saveFile()` 句柄未声明或未启用
678
+ * `filesystem` 时返回 `PERMISSION_NOT_DECLARED` / `PERMISSION_DENIED`;Host 未开放或未协商到
679
+ * `file.readBytes` 时返回 `METHOD_FORBIDDEN`,旧 Runtime 可返回 `METHOD_NOT_FOUND`。
680
+ * @throws {@link HbMiniProgramSDKError} 外部 direct handle 被撤销、不属于当前或已结束的 Runtime
681
+ * session 时返回 `FILE_ACCESS_REVOKED`;Host 拒绝底层授权时也可能返回 `FILE_ACCESS_DENIED`。
682
+ * 握手失败、SDK / Runtime 已终止或不可用、调用超时、Host 返回非字节结果或底层 I/O 失败时,返回
683
+ * `HANDSHAKE_FAILED`、`SDK_DESTROYED`、`RUNTIME_DESTROYED`、`RUNTIME_UNAVAILABLE`、
684
+ * `REQUEST_TIMEOUT`、`FILE_IO_FAILED` 或对应稳定文件错误码。
685
+ *
686
+ * @remarks
687
+ * 该方法读取并缓冲整个文件,不提供 offset、range、stream、encoding、进度回调或 `AbortSignal`
688
+ * 参数。移动端 Host 可以在内部按 chunk 拉取,但公开 Promise 只在全部字节读取并复制完成后 resolve;
689
+ * 失败不会返回部分数组。8 MiB 是 Android / iOS 当前 Host 的原始文件字节上限,恰好等于上限允许;
690
+ * 新 PC Host 的限制由实际 Host I/O 合同决定。
691
+ *
692
+ * `readBytes()` 不解释内容格式:UTF-8 BOM、无效 UTF-8、NUL、压缩数据和图片头都会原样保留,也不会
693
+ * 因文本编码返回 `FILE_ENCODING_INVALID`。需要严格 UTF-8 字符串并移除前导 BOM 时使用
694
+ * {@link FileHandle.readText | readText()};需要把修改后的字节完整覆盖回文件时使用
695
+ * {@link FileHandle.writeBytes | writeBytes()}。
696
+ *
697
+ * `mode: 'read'` 与 `mode: 'readwrite'` 句柄都可以读取,调用不需要可信用户手势,也不会弹出 picker、
698
+ * 创建文件、修改内容或延长外部授权寿命。picker / `saveFile()` 返回的 direct handle 只在当前
699
+ * Runtime session 有效;sandbox lazy ref 会在每次调用时按当前 Mini-program identity 解析。
700
+ * Companion `attachments.open()` 返回的只读 FileHandle 是受控例外:其 `readBytes()` 由 `companion`
701
+ * provenance 授权,不额外要求 `filesystem`,但仍受当前 Companion / Runtime session 生命周期约束。
702
+ *
703
+ * 新 PC Host 支持该操作;Android / iOS `1.3.396+` 仅在 `system.describe` 同时宣告
704
+ * `files.openRead`、`files.read`、`files.release` 时逐项启用,OHOS 同样以 Host 实际协商结果为准。
705
+ * Web、Browser Dev Host 的普通 sandbox / picker 路径、旧 Host 或 operation 集不完整时 fail closed,
706
+ * 不提供浏览器 File / Blob、内存 fallback 或自动分段的公开 API;前述 Companion attachment 仍按
707
+ * 自身受控 provenance 判断。
708
+ *
709
+ * @example
710
+ * ```ts
711
+ * import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
712
+ *
713
+ * const avatar = hbSDK.files.sandbox.file('avatar.png')
714
+ *
715
+ * try {
716
+ * const bytes = await avatar.readBytes()
717
+ * const isPng =
718
+ * bytes.length >= 4 &&
719
+ * bytes[0] === 0x89 &&
720
+ * bytes[1] === 0x50 &&
721
+ * bytes[2] === 0x4e &&
722
+ * bytes[3] === 0x47
723
+ *
724
+ * console.log({ isPng, size: bytes.byteLength })
725
+ * bytes[0] = 0 // 只修改本地副本,不会写回 avatar.png
726
+ * } catch (error) {
727
+ * if (error instanceof HbMiniProgramSDKError && error.code === 'FILE_TOO_LARGE') {
728
+ * console.warn('请改用业务分片格式,或避免把大文件一次读入内存')
729
+ * } else {
730
+ * throw error
731
+ * }
732
+ * }
733
+ * ```
734
+ *
735
+ * @see {@link FileHandle.readText | FileHandle.readText()} 严格按 UTF-8 解码并处理前导 BOM。
736
+ * @see {@link FileHandle.writeBytes | FileHandle.writeBytes()} 完整覆盖写入原始字节。
737
+ * @see {@link FileHandle.stat | FileHandle.stat()} 在完整读取前查看文件字节数。
738
+ * @see [files.pickFiles()](/reference/sdk/files/pickFiles) 取得当前 session 的外部文件授权。
739
+ * @see [文件能力与沙箱](/guide/files-and-sandbox) 查看权限、平台限制与错误码。
740
+ */
78
741
  readBytes(): Promise<Uint8Array>;
742
+ /**
743
+ * 将原始字节完整写入文件。
744
+ *
745
+ * @param content - 要写入的 `Uint8Array`。SDK 在调用时只复制该 view 的当前可见字节区间;不会把
746
+ * `byteOffset` 之前或 `byteLength` 之后的 backing `ArrayBuffer` 内容一并写入。调用返回 Promise 后
747
+ * 再修改原数组不会改变本次写入。空数组合法,会把目标替换为零字节文件。
748
+ * @returns SDK 与 Runtime 完成输入复制且 Host 的完整写入请求成功后以 `undefined` resolve。移动端
749
+ * 会等待最后一个带 EOF 的 chunk 获得 Host 响应;该时点不返回写入字节数、文件元数据或新的
750
+ * `FileHandle`,也不承诺操作系统已执行物理 `fsync`。
751
+ * @throws {@link HbMiniProgramSDKError} `content` 不是 `Uint8Array`,或其 backing buffer 是
752
+ * `SharedArrayBuffer` 时,在发送 bridge 请求前返回 `INVALID_PARAMS`;当前代理不是 `readwrite`
753
+ * 时在输入复制和 Host I/O 前返回 `FILE_ACCESS_DENIED`。
754
+ * @throws {@link HbMiniProgramSDKError} 未声明或未启用 `filesystem` 权限时返回
755
+ * `PERMISSION_NOT_DECLARED` / `PERMISSION_DENIED`;Host 未开放或未协商到 `file.writeBytes` 时返回
756
+ * `METHOD_FORBIDDEN`,旧 Runtime 可返回 `METHOD_NOT_FOUND`。
757
+ * @throws {@link HbMiniProgramSDKError} 缺失父目录时返回 `DIRECTORY_NOT_FOUND`,路径中的祖先或
758
+ * 目标类型不匹配时返回 `FILE_TYPE_MISMATCH`。Android / iOS 对一次完整写入设 8 MiB 上限;当前
759
+ * view 的 `byteLength` 超过 `8 * 1024 * 1024` 时返回 `FILE_TOO_LARGE`。
760
+ * @throws {@link HbMiniProgramSDKError} 外部 direct handle 被撤销、不属于当前 Runtime session 或
761
+ * registry 已释放时返回 `FILE_ACCESS_REVOKED`;SDK 已销毁、Runtime 已卸载、请求超时、Host 响应
762
+ * 异常或底层 I/O 失败时,返回 `SDK_DESTROYED`、`RUNTIME_UNAVAILABLE`、`REQUEST_TIMEOUT`、
763
+ * `FILE_IO_FAILED` 或对应稳定文件错误码。
764
+ *
765
+ * @remarks
766
+ * SDK 会在调用同步阶段执行第一次防御性复制,Runtime 收到 payload 后再复制一次,再把独立的
767
+ * `Uint8Array` 交给 Host。因此本次写入只观察调用时 view 中的字节,不与调用方继续共享可变
768
+ * `ArrayBuffer`。`SharedArrayBuffer` backing 会被明确拒绝,不能借此建立跨 bridge 共享内存。
769
+ *
770
+ * 这是完整文件写入,不是 append、range write 或 stream:已有内容会被本次字节序列整体替换,
771
+ * 写入空数组会截断为零字节。若 Host 在写入中途失败,Promise 会拒绝;公开合同不承诺失败时
772
+ * 回滚旧内容或提供跨进程原子替换,需要事务语义时应由业务使用临时文件和自己的提交协议。
773
+ *
774
+ * 目标文件不存在时可以隐式创建,但父目录必须已经存在,`writeBytes()` 不会递归创建目录。
775
+ * 需要创建父目录时先调用 {@link DirectoryHandle.create | DirectoryHandle.create()},或对文件调用
776
+ * `create({ recursive: true })`。不必先用 `exists()` 检查文件;该检查也不能消除两次异步调用之间
777
+ * 的状态竞态,实际写入错误仍应处理。
778
+ *
779
+ * sandbox lazy FileHandle 固定继承 `readwrite`。`pickFiles({ mode: 'readwrite' })`、
780
+ * `pickDirectory({ mode: 'readwrite' })` 的派生文件和 `saveFile()` 返回的精确外部 FileHandle 也可
781
+ * 写入,但 direct handle 只在当前 Runtime session 有效,且授权范围不会扩张。只读 picker 结果、
782
+ * Android 的精确 SAF File 和 Companion attachment 返回 `FILE_ACCESS_DENIED`。该方法不需要新的
783
+ * 可信用户手势;只有最初取得外部授权的 picker / `saveFile()` 需要手势。
784
+ *
785
+ * 新 PC Host 支持该操作;Android / iOS `1.3.396+` 仅在 `system.describe` 同时宣告
786
+ * `files.openWrite`、`files.write`、`files.release` 时逐项启用,OHOS 同样以 Host 实际协商结果
787
+ * 为准。Web、Browser Dev Host、旧 Host 或 operation 集不完整时 fail closed,不提供浏览器
788
+ * File / Blob 或内存 fallback。新 PC Host 的大小限制由实际 Host 合同决定,不应套用移动端
789
+ * 8 MiB 上限。
790
+ *
791
+ * {@link FileHandle.readBytes | readBytes()} 返回完整文件的独立字节副本;
792
+ * {@link FileHandle.writeText | writeText()} 则先把字符串编码成不带 BOM 的 UTF-8,再执行相同的
793
+ * 完整替换语义。需要检查写入后的最终大小或时间戳时,成功后另行调用
794
+ * {@link FileHandle.stat | stat()}。
795
+ *
796
+ * @example
797
+ * ```ts
798
+ * import hbSDK from '@heybox/hb-sdk'
799
+ *
800
+ * const file = hbSDK.files.sandbox.file('header.bin')
801
+ * const backing = new Uint8Array([0xff, 0x89, 0x50, 0x4e, 0x47, 0xff])
802
+ * const visible = backing.subarray(1, 5)
803
+ *
804
+ * const writing = file.writeBytes(visible)
805
+ * visible.fill(0) // 不影响 writeBytes() 已取得的快照。
806
+ * await writing
807
+ *
808
+ * console.log([...await file.readBytes()]) // [137, 80, 78, 71]
809
+ * await file.writeBytes(new Uint8Array()) // 完整替换为空文件。
810
+ * ```
811
+ *
812
+ * @see {@link FileHandle.readBytes | FileHandle.readBytes()} 读取独立的原始字节副本。
813
+ * @see {@link FileHandle.writeText | FileHandle.writeText()} 以 UTF-8 写入完整字符串。
814
+ * @see {@link FileHandle.create | FileHandle.create()} 显式确保文件和可选父目录存在。
815
+ * @see {@link FileHandle.stat | FileHandle.stat()} 在写入后读取文件大小与时间戳。
816
+ * @see {@link DirectoryHandle.create | DirectoryHandle.create()} 先创建缺失父目录。
817
+ * @see [files.pickFiles()](/reference/sdk/files/pickFiles) 取得可选的精确外部文件写授权。
818
+ * @see [files.saveFile()](/reference/sdk/files/saveFile) 让用户指定新的精确可写目标。
819
+ * @see [文件能力与沙箱](/guide/files-and-sandbox) 查看路径、权限、平台与错误码边界。
820
+ */
79
821
  writeBytes(content: Uint8Array): Promise<void>;
822
+ /**
823
+ * 读取当前文件的元数据快照。
824
+ *
825
+ * @returns 新建的 {@link FileStat} 对象:`kind` 固定为 `'file'`,`size` 是 `0` 到
826
+ * `Number.MAX_SAFE_INTEGER` 的整数;Host 提供时还包含相互独立、非负有限数值的
827
+ * `modifiedAt` / `createdAt`。返回对象不是 `FileHandle`,也不会包含真实路径、内容或 Host 的额外字段。
828
+ * @throws {@link HbMiniProgramSDKError} 目标文件或任一祖先不存在时返回 `FILE_NOT_FOUND` /
829
+ * `DIRECTORY_NOT_FOUND`;目标实际是目录、direct handle 类型不匹配时返回 `FILE_TYPE_MISMATCH`。
830
+ * @throws {@link HbMiniProgramSDKError} 外部 direct handle 已撤销、不属于当前 Runtime session 或
831
+ * registry 已释放时返回 `FILE_ACCESS_REVOKED`;Host 拒绝读取元数据时返回 `FILE_ACCESS_DENIED`。
832
+ * @throws {@link HbMiniProgramSDKError} 普通 FileHandle 未声明或未启用 `filesystem` 时返回
833
+ * `PERMISSION_NOT_DECLARED` / `PERMISSION_DENIED`;Host 未开放或未协商到 `file.stat` 时返回
834
+ * `METHOD_FORBIDDEN`,旧 Runtime 可返回 `METHOD_NOT_FOUND`。Companion attachment 是受控例外:
835
+ * 它使用已启用的 `companion` 授权读取自身元数据,不要求另行声明 `filesystem`。
836
+ * @throws {@link HbMiniProgramSDKError} Host 返回非对象、错误的 `kind`,负数/小数/unsafe `size`,
837
+ * 或负数、非有限数值的时间戳时返回 `FILE_IO_FAILED`;未知 Host 错误和无法识别的响应同样规范为
838
+ * `FILE_IO_FAILED`。SDK 已销毁、Runtime 已卸载或请求超时时还可能返回 `SDK_DESTROYED`、
839
+ * `RUNTIME_UNAVAILABLE`、`REQUEST_TIMEOUT`。
840
+ *
841
+ * @remarks
842
+ * 这是只读操作,`mode: 'read'` 与 `mode: 'readwrite'` 均可调用,不要求可信用户手势,也不会读取
843
+ * 文件内容、创建文件、更新时间戳或占用新的 direct-handle 配额。Runtime 会重新校验 ref 的类型、
844
+ * 当前 session/provenance 与 Mini-program identity;通过结构校验不等于可以跨 session 复用句柄。
845
+ *
846
+ * 每次调用都会发送新的 `file.stat` 请求,并返回与 Host 响应分离的新对象;SDK 不缓存、冻结或持续
847
+ * 更新该对象。修改返回对象不会影响文件或后续结果,文件也可能在 Promise resolve 后立即被外部进程
848
+ * 修改、替换或删除。因此它只描述本次 Host 查询的快照,不能与之前的 `exists()` 或之后的
849
+ * `readText()` / `readBytes()` 组成原子检查。
850
+ *
851
+ * `size` 的公开约定单位是 byte,`modifiedAt` / `createdAt` 的公开约定单位是 Unix epoch
852
+ * milliseconds;但 Runtime 只能验证数值结构,不能证明 Host 使用了正确单位、时间来自文件系统或
853
+ * `size` 与稍后读取的内容仍一致。时间戳可分别缺失,也不要求为整数/safe integer、落在 JavaScript
854
+ * `Date` 可表示范围内、`createdAt <= modifiedAt` 或不晚于当前时间;用于排序和日期展示前应按业务范围
855
+ * 继续校验。
856
+ *
857
+ * 与 {@link FileHandle.exists | exists()} 不同,`stat()` 不会把缺失祖先、缺失目标或 kind mismatch
858
+ * 归一为 `false`,而会以对应错误拒绝。与 {@link FileHandle.readText | readText()} /
859
+ * {@link FileHandle.readBytes | readBytes()} 不同,它只读取元数据,不传输文件 body;Android/iOS 的
860
+ * 8 MiB 单次完整内容读写上限不限制可报告的 `size`,但 `size` 仍不能超过
861
+ * `Number.MAX_SAFE_INTEGER`。
862
+ *
863
+ * 新 PC Host 支持该 operation;Android/iOS `1.3.396+` 仅在 `system.describe` 宣告
864
+ * `files.stat` 时逐项启用,OHOS 同样以 Host 实际协商结果为准。Web、Browser Dev Host、旧 Host
865
+ * 或缺少该 operation 的环境会 fail closed,不提供浏览器 File / Blob 或内存 fallback。
866
+ *
867
+ * @example
868
+ * ```ts
869
+ * import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
870
+ *
871
+ * const report = hbSDK.files.sandbox.file('reports/latest.json')
872
+ *
873
+ * // exists() 只用于快速分支;文件仍可能在下一次异步调用前变化。
874
+ * if (await report.exists()) {
875
+ * try {
876
+ * const stat = await report.stat()
877
+ * console.log(`${stat.size} bytes`)
878
+ *
879
+ * if (stat.modifiedAt !== undefined) {
880
+ * const modifiedAt = new Date(stat.modifiedAt)
881
+ * if (!Number.isNaN(modifiedAt.getTime())) console.log(modifiedAt.toISOString())
882
+ * }
883
+ * } catch (error) {
884
+ * if (!(error instanceof HbMiniProgramSDKError) || error.code !== 'FILE_NOT_FOUND') throw error
885
+ * }
886
+ * }
887
+ * ```
888
+ *
889
+ * @see {@link FileStat}
890
+ * @see {@link FileHandle.exists}
891
+ * @see {@link FileHandle.readText}
892
+ * @see {@link FileHandle.readBytes}
893
+ * @see [files.sandbox.file()](/reference/sdk/files/sandbox/file) 创建 sandbox lazy FileHandle。
894
+ * @see [files.pickFiles()](/reference/sdk/files/pickFiles) 取得当前 session 的精确外部文件授权。
895
+ * @see {@link https://docs.xiaoheihe.cn/hb_sdk/guide/files-and-sandbox | 文件能力与沙箱}
896
+ * @see {@link https://docs.xiaoheihe.cn/hb_sdk/guide/error-handling | 错误处理}
897
+ * @see {@link https://docs.xiaoheihe.cn/hb_sdk/guide/permissions | 权限声明}
898
+ *
899
+ * @since 0.8.0-alpha.2
900
+ * @hbPlatform android
901
+ * @hbPlatform ios
902
+ * @hbPlatform ohos
903
+ * @hbPlatform windows
904
+ * @hbPlatform macos
905
+ * @hbClient android numeric-dot \>= 1.3.396
906
+ * @hbClient ios numeric-dot \>= 1.3.396
907
+ * @hbClient ohos none
908
+ * @hbClient windows none
909
+ * @hbClient macos none
910
+ */
80
911
  stat(): Promise<FileStat>;
81
912
  }
82
- /** 当前 SDK session 中的目录代理。 */
913
+ /**
914
+ * 当前 SDK session 中的目录代理。
915
+ *
916
+ * @remarks
917
+ * 目录既能执行目录操作,也是派生子 File/Directory 逻辑代理的根。派生代理继承目录的 `mode`,
918
+ * 不能通过子路径提升授权范围。
919
+ */
83
920
  export interface DirectoryHandle extends PathRoot {
921
+ /** 可用于区分文件与目录的固定标记。 */
84
922
  readonly kind: 'directory';
923
+ /** 目录 basename,不包含父目录或真实路径。 */
85
924
  readonly name: string;
925
+ /** 当前代理及其派生项被授予的访问模式。 */
86
926
  readonly mode: FileMode;
927
+ /**
928
+ * 确保目录存在并返回同一个代理。
929
+ *
930
+ * @param options - 可选的父目录创建与目标独占创建设置。省略时等同于
931
+ * `{ recursive: false, exclusive: false }`;完整语义见 {@link CreateOptions}。
932
+ * @returns Host 确认目录存在后返回当前同一个 `DirectoryHandle` proxy;成功后
933
+ * `result === directory`。不会创建新的授权 handle,也不会刷新或改变代理的 `name`、`mode`。
934
+ * @throws {@link HbMiniProgramSDKError} options 非对象,或 `recursive` / `exclusive` 不是 boolean 时
935
+ * 返回 `INVALID_PARAMS`;代理不是 `readwrite` 时在发送 bridge 请求前返回 `FILE_ACCESS_DENIED`。
936
+ * @throws {@link HbMiniProgramSDKError} 未声明或未启用 `filesystem` 时返回
937
+ * `PERMISSION_NOT_DECLARED` / `PERMISSION_DENIED`;Host 未开放或未协商到 `directory.create` 时返回
938
+ * `METHOD_FORBIDDEN`,旧 Runtime 可返回 `METHOD_NOT_FOUND`。
939
+ * @throws {@link HbMiniProgramSDKError} `recursive: false` 且任一父目录缺失时返回
940
+ * `DIRECTORY_NOT_FOUND`;目标实际是文件或路径中的祖先实际是文件时返回 `FILE_TYPE_MISMATCH`;
941
+ * `exclusive: true` 且目录已存在时返回 `DIRECTORY_ALREADY_EXISTS`。
942
+ * @throws {@link HbMiniProgramSDKError} 外部 direct handle 已失效、伪造或不属于当前 Runtime session
943
+ * 时返回 `FILE_ACCESS_REVOKED`;Host 创建失败或底层平台 I/O 失败时返回相应稳定文件错误码,
944
+ * 无法识别的 Host 错误统一为 `FILE_IO_FAILED`。SDK / Runtime 终止或请求超时还可能返回
945
+ * `SDK_DESTROYED`、`RUNTIME_DESTROYED`、`RUNTIME_UNAVAILABLE` 或 `REQUEST_TIMEOUT`。
946
+ *
947
+ * @remarks
948
+ * 目标缺失时创建空目录。`recursive: true` 会在当前逻辑 root 内同时创建缺失父目录;它不会允许
949
+ * `..`、绝对路径或越过 sandbox / 用户选择目录的授权边界。目标已是目录时,默认调用作为幂等的
950
+ * ensure-exists 成功,不删除、清空或重新创建其中内容;需要检测最终目标冲突时传
951
+ * `exclusive: true`。`exclusive` 只约束最终目录,`recursive` 创建的父目录可以已经存在。
952
+ * 若同一位置实际是文件,则不会把文件替换为目录。
953
+ *
954
+ * 调用要求当前代理的 `mode === 'readwrite'`。sandbox 目录固定继承 `readwrite`;从
955
+ * `files.pickDirectory({ mode: 'readwrite' })` 返回的外部目录派生后代时也可在该授权范围内创建,
956
+ * 但默认 `read` 的选择结果及其后代会在本地 mode 检查时拒绝。创建不会扩大授权到所选目录之外,
957
+ * 也不会让外部目录获得 `remove()` 权限;外部 direct handle 及其后代仍只在当前 Runtime session
958
+ * 有效。Runtime 会重新校验 direct handle 的 provenance,Host 还会绑定当前 Mini-program identity。
959
+ *
960
+ * 该方法要求 `package.json#heybox.permissions` 已声明并启用 `filesystem`,但不要求新的可信用户
961
+ * 手势;只有最初调用 `pickDirectory()` 取得外部授权时需要用户操作。它不占用新的外部 direct-handle
962
+ * 配额,也不暴露 Host 真实路径。
963
+ *
964
+ * 新 PC Host 支持该 operation;Android / iOS 需要 `1.3.396+` 并以 `system.describe` 实际宣告的
965
+ * operation 集为准,OHOS 同样按 Host 协商结果启用。Web、Browser Dev Host、旧 Host 或 operation
966
+ * 集不完整时 fail closed,不提供浏览器文件系统、OPFS 或内存 fallback。
967
+ *
968
+ * 创建目录后,可用当前代理的 {@link PathRoot.file | file()} / {@link PathRoot.directory | directory()}
969
+ * 同步派生后代代理,并用 {@link DirectoryHandle.list | list()} 枚举直接子项;派生与枚举结果继承
970
+ * 当前目录的 mode。若最终目标应是文件,使用 {@link FileHandle.create};它复用同一组
971
+ * `recursive` / `exclusive` 选项,但独占冲突返回 `FILE_ALREADY_EXISTS`。
972
+ *
973
+ * @example
974
+ * ```ts
975
+ * import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
976
+ *
977
+ * const reports = hbSDK.files.sandbox.directory('exports/2026')
978
+ * const sameReports = await reports.create({ recursive: true })
979
+ * console.assert(sameReports === reports)
980
+ *
981
+ * const summary = reports.file('summary.json')
982
+ * await summary.create()
983
+ * await summary.writeText('{"ready":true}')
984
+ * console.log((await reports.list()).map(entry => entry.name))
985
+ *
986
+ * try {
987
+ * await reports.create({ exclusive: true })
988
+ * } catch (error) {
989
+ * if (!(error instanceof HbMiniProgramSDKError) || error.code !== 'DIRECTORY_ALREADY_EXISTS') throw error
990
+ * }
991
+ * ```
992
+ *
993
+ * @see {@link CreateOptions}
994
+ * @see {@link FileHandle.create}
995
+ * @see {@link DirectoryHandle.exists}
996
+ * @see {@link DirectoryHandle.list}
997
+ * @see {@link FilesModule.pickDirectory | files.pickDirectory}
998
+ * @see {@link https://docs.xiaoheihe.cn/hb_sdk/guide/files-and-sandbox | 文件能力与沙箱}
999
+ * @see {@link https://docs.xiaoheihe.cn/hb_sdk/guide/error-handling | 错误处理}
1000
+ * @see {@link https://docs.xiaoheihe.cn/hb_sdk/guide/permissions | 权限声明}
1001
+ */
87
1002
  create(options?: CreateOptions): Promise<DirectoryHandle>;
88
- /** 删除 sandbox 目录;非空目录需要显式设置 `recursive`,外部授权目录不允许删除。 */
1003
+ /**
1004
+ * 删除当前代理指向的 sandbox 目录。
1005
+ *
1006
+ * @param options - 可选删除配置。省略 options、传 `{}` 或省略 `recursive` 都等同于
1007
+ * `{ recursive: false }`;此时只允许删除空目录。`recursive` 必须是 boolean,非对象 options、
1008
+ * 数组或其他类型会以 `INVALID_PARAMS` 拒绝。
1009
+ * @returns Host 报告目标目录删除完成后以 `undefined` resolve。不返回删除的子项数量、原目录
1010
+ * 内容或新的 handle;当前 `DirectoryHandle` 仍是同一逻辑位置的代理,可继续调用
1011
+ * {@link DirectoryHandle.exists | exists()} 或 {@link DirectoryHandle.create | create()}。
1012
+ * @throws {@link HbMiniProgramSDKError} 当前代理不是 `readwrite`,来源是 `pickDirectory()` 返回的
1013
+ * 外部目录,或从外部目录派生/枚举得到时,在发送 bridge 请求前以 `FILE_ACCESS_DENIED` 拒绝。
1014
+ * 外部目录授权即使为 `readwrite` 也不能删除其自身或任何后代。
1015
+ * @throws {@link HbMiniProgramSDKError} 删除 `files.sandbox.directory('.')` 表示的 sandbox 根目录时
1016
+ * 以 `FILE_ACCESS_DENIED` 拒绝;`recursive: true` 也不能绕过该边界。目标目录非空且
1017
+ * `recursive` 为默认的 `false` 时返回 `DIRECTORY_NOT_EMPTY`。
1018
+ * @throws {@link HbMiniProgramSDKError} 目标或任一祖先不存在时返回 `DIRECTORY_NOT_FOUND`,目标
1019
+ * 实际是文件或路径中的祖先类型不匹配时返回 `FILE_TYPE_MISMATCH`。删除已经不存在的目录不会
1020
+ * 当作幂等成功;需要“确保不存在”语义时应先接受缺失错误或在操作后调用 `exists()` 对账。
1021
+ * @throws {@link HbMiniProgramSDKError} 未声明或未启用 `filesystem` 权限时分别以
1022
+ * `PERMISSION_NOT_DECLARED`、`PERMISSION_DENIED` 拒绝;Host 未开放 `directory.remove` 时以
1023
+ * `METHOD_FORBIDDEN` 拒绝,旧 Runtime 也可能返回 `METHOD_NOT_FOUND`。
1024
+ * @throws {@link HbMiniProgramSDKError} SDK 已销毁、Runtime 已卸载、请求超时、Host 拒绝删除或
1025
+ * 发生底层 I/O 失败时,以 `SDK_DESTROYED`、`RUNTIME_UNAVAILABLE`、`REQUEST_TIMEOUT`、
1026
+ * `FILE_ACCESS_DENIED`、`FILE_IO_FAILED` 或 Host 保留的对应稳定文件错误码拒绝。
1027
+ *
1028
+ * @remarks
1029
+ * 该方法只对当前 Mini-program identity 的 sandbox 子目录开放,并要求代理的
1030
+ * `mode === 'readwrite'`。它不需要可信用户手势、不打开系统选择器、不暴露真实路径,也不会因为
1031
+ * 传入 `recursive: true` 而跨出当前逻辑目录。picker 只负责授予外部访问,不能授予删除外部目录
1032
+ * 树的能力;这一来源限制独立于 mode 和 Host 原生权限。
1033
+ *
1034
+ * `recursive: false` 是保护性默认值:空目录会删除,存在任意直接或间接子项时应返回
1035
+ * `DIRECTORY_NOT_EMPTY`,且不应由 Runtime 自动重试为递归删除。`recursive: true` 明确授权 Host
1036
+ * 删除该目录及其整个后代,包括文件、空目录和非空目录。Promise 只反映 Host 对本次请求的最终
1037
+ * 结果;公开合同不承诺多对象删除具备事务原子性或失败后自动恢复已删除子项。
1038
+ *
1039
+ * 删除成功后,当前代理对象不会失效或自动改变 `name` / `mode`。随后
1040
+ * {@link DirectoryHandle.exists | exists()} 应在目标仍不存在时返回 `false`,也可以调用
1041
+ * {@link DirectoryHandle.create | create()} 在同一 sandbox 位置重新创建。两次调用之间仍存在
1042
+ * 并发变化窗口,因此删除前的 `exists()` 或 `list()` 不能保证后续删除成功。
1043
+ *
1044
+ * 若只需删除单个 sandbox 文件,使用 {@link FileHandle.remove | FileHandle.remove()};它没有
1045
+ * `recursive` 选项。若希望保留目录并清理部分内容,应先通过 `list()` 取得直接子项,再按业务规则
1046
+ * 删除 sandbox 项;不要对外部授权项调用 remove。
1047
+ *
1048
+ * 新 PC Host 支持该操作;Android / iOS `1.3.396+` 仅在 `system.describe` 宣告
1049
+ * `files.remove` 时逐项启用,OHOS 同样以 Host 实际协商结果为准。Web、Browser Dev Host、旧 Host
1050
+ * 或缺少该 operation 的环境会 fail closed,不提供浏览器文件系统或内存 fallback;页面应处理
1051
+ * `METHOD_FORBIDDEN`,不要仅按操作系统推断可用性。
1052
+ *
1053
+ * @example
1054
+ * ```ts
1055
+ * import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
1056
+ *
1057
+ * const cache = hbSDK.files.sandbox.directory('cache')
1058
+ * await cache.create({ recursive: true })
1059
+ * await cache.file('index.json').writeText('{}')
1060
+ *
1061
+ * try {
1062
+ * await cache.remove() // 默认 recursive: false,非空目录会拒绝。
1063
+ * } catch (error) {
1064
+ * if (!(error instanceof HbMiniProgramSDKError) || error.code !== 'DIRECTORY_NOT_EMPTY') {
1065
+ * throw error
1066
+ * }
1067
+ * }
1068
+ *
1069
+ * await cache.remove({ recursive: true })
1070
+ * console.log(await cache.exists()) // false
1071
+ *
1072
+ * // 代理仍表示同一个 sandbox 位置。
1073
+ * await cache.create()
1074
+ * ```
1075
+ *
1076
+ * @see {@link DirectoryHandle.create | DirectoryHandle.create()} 显式确保目录和可选父目录存在。
1077
+ * @see {@link DirectoryHandle.exists | DirectoryHandle.exists()} 删除后确认当前目录是否仍存在。
1078
+ * @see {@link DirectoryHandle.list | DirectoryHandle.list()} 删除前枚举直接子项。
1079
+ * @see {@link FileHandle.remove | FileHandle.remove()} 删除单个 sandbox 文件。
1080
+ * @see [files.sandbox.directory()](/reference/sdk/files/sandbox/directory) 创建 sandbox 目录代理。
1081
+ * @see [files.pickDirectory()](/reference/sdk/files/pickDirectory) 取得不可删除的外部目录授权。
1082
+ * @see [文件能力与沙箱](/guide/files-and-sandbox) 查看来源、权限、平台和错误码边界。
1083
+ *
1084
+ * @since 0.8.0-alpha.2
1085
+ * @hbPlatform android
1086
+ * @hbPlatform ios
1087
+ * @hbPlatform ohos
1088
+ * @hbPlatform windows
1089
+ * @hbPlatform macos
1090
+ * @hbClient android numeric-dot \>= 1.3.396
1091
+ * @hbClient ios numeric-dot \>= 1.3.396
1092
+ * @hbClient ohos none
1093
+ * @hbClient windows none
1094
+ * @hbClient macos none
1095
+ */
89
1096
  remove(options?: RemoveOptions): Promise<void>;
1097
+ /**
1098
+ * 检查目录是否存在。
1099
+ *
1100
+ * @returns Runtime 对当前目录引用执行一次 Host `stat` 后得到的 boolean 快照。目标目录存在且 Host
1101
+ * 确认为目录时返回 `true`;目标或任一祖先不存在,目标实际是文件,或 Host 以
1102
+ * `FILE_NOT_FOUND`、`DIRECTORY_NOT_FOUND`、`FILE_TYPE_MISMATCH` 报告同类状态时返回 `false`;Host
1103
+ * stat 响应不是对象或 `kind` 不是 `'directory'` 时也按类型不匹配返回 `false`。不返回目录元数据、
1104
+ * 句柄或缺失原因。
1105
+ * @throws {@link HbMiniProgramSDKError} 未声明或未启用 `filesystem` 时返回
1106
+ * `PERMISSION_NOT_DECLARED` / `PERMISSION_DENIED`;Host 未开放或未协商到 `directory.exists`
1107
+ * (底层要求 `files.stat`)时返回 `METHOD_FORBIDDEN`,旧 Runtime 可返回 `METHOD_NOT_FOUND`。
1108
+ * @throws {@link HbMiniProgramSDKError} 外部 direct directory handle 被撤销、不属于当前或已结束的
1109
+ * Runtime session 时返回 `FILE_ACCESS_REVOKED`;Host 拒绝当前目录授权时返回 `FILE_ACCESS_DENIED`。
1110
+ * 这些授权错误不会被转换为 `false`。
1111
+ * @throws {@link HbMiniProgramSDKError} Host 返回未归类的错误、公开 bridge 返回非 boolean 结果或底层
1112
+ * I/O 失败时返回 `FILE_IO_FAILED` 或对应稳定文件错误码。握手失败、SDK / Runtime 已终止或不可用、
1113
+ * 调用超时时还可能返回 `HANDSHAKE_FAILED`、`SDK_DESTROYED`、`RUNTIME_DESTROYED`、
1114
+ * `RUNTIME_UNAVAILABLE`、`REQUEST_TIMEOUT`。
1115
+ *
1116
+ * @remarks
1117
+ * `exists()` 是只读探测,`mode: 'read'` 与 `mode: 'readwrite'` 均可调用;它不要求可信用户手势,
1118
+ * 不会创建目录、枚举子项、读取文件内容、延长外部授权寿命或占用新的 direct-handle 配额。sandbox
1119
+ * lazy ref 会在每次调用时按当前 Mini-program identity 解析;picker 返回的外部目录授权只在当前
1120
+ * Runtime session 有效。
1121
+ *
1122
+ * 每次调用都会发送新的 `directory.exists` 请求并重新查询 Host,不读取或更新 SDK 本地缓存。
1123
+ * 返回值只描述该次查询完成时的状态:目录可能在 Promise resolve 后立即被其他代码创建、删除或
1124
+ * 替换,因此先 `exists()` 再 `create()` / `list()` 存在 TOCTOU 竞态。必须继续处理后续操作自身的
1125
+ * `DIRECTORY_NOT_FOUND`、`FILE_TYPE_MISMATCH`、授权和 I/O 错误;需要确保目录存在时,直接调用
1126
+ * {@link DirectoryHandle.create | create()} 的幂等默认模式通常更合适。
1127
+ *
1128
+ * Runtime 内部通过 Host directory `stat` 判断 kind,但公开 `DirectoryHandle` 没有 `stat()` 方法,
1129
+ * `exists()` 也不会暴露 size、时间戳或其他目录元数据。{@link FileHandle.stat | FileHandle.stat()}
1130
+ * 只适用于文件;不要把它当作目录元数据入口。需要直接子项时调用
1131
+ * {@link DirectoryHandle.list | list()},它会重新访问 Host,不复用本次存在性结果。
1132
+ *
1133
+ * 新 PC Host 支持该操作;Android / iOS `1.3.396+` 仅在 `system.describe` 宣告 `files.stat` 时启用,
1134
+ * OHOS 同样以 Host 实际协商结果为准。Web、Browser Dev Host、旧 Host 或缺少该 operation 的环境
1135
+ * fail closed,返回 `METHOD_FORBIDDEN` / `METHOD_NOT_FOUND`,不会用浏览器 File / Blob 或内存目录
1136
+ * 伪造 `false`。该操作只读取元数据,不受移动端 8 MiB 完整文件内容读写上限影响。
1137
+ *
1138
+ * @example
1139
+ * ```ts
1140
+ * import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
1141
+ *
1142
+ * const cache = hbSDK.files.sandbox.directory('cache/images')
1143
+ *
1144
+ * try {
1145
+ * if (!(await cache.exists())) {
1146
+ * // 默认 create 是幂等的;recursive 同时确保父目录存在。
1147
+ * await cache.create({ recursive: true })
1148
+ * }
1149
+ *
1150
+ * // exists() 与 list() 不是原子操作,list() 的错误仍需处理。
1151
+ * const entries = await cache.list({ limit: 100 })
1152
+ * console.log(entries.map(entry => entry.name))
1153
+ * } catch (error) {
1154
+ * if (error instanceof HbMiniProgramSDKError && error.code === 'DIRECTORY_NOT_FOUND') {
1155
+ * console.warn('目录在检查后被删除,请刷新状态后重试')
1156
+ * } else {
1157
+ * throw error
1158
+ * }
1159
+ * }
1160
+ * ```
1161
+ *
1162
+ * @see {@link DirectoryHandle.create | DirectoryHandle.create()} 幂等确保目录及可选父目录存在。
1163
+ * @see {@link DirectoryHandle.list | DirectoryHandle.list()} 重新访问 Host 并枚举直接子项。
1164
+ * @see {@link FileHandle.exists | FileHandle.exists()} 对文件目标执行相同的存在性归一化。
1165
+ * @see {@link FileHandle.stat | FileHandle.stat()} 文件专属的公开元数据快照。
1166
+ * @see [files.sandbox.directory()](/reference/sdk/files/sandbox/directory) 创建 sandbox lazy DirectoryHandle。
1167
+ * @see [files.pickDirectory()](/reference/sdk/files/pickDirectory) 取得当前 session 的外部目录授权。
1168
+ * @see [文件能力与沙箱](/guide/files-and-sandbox) 查看权限、平台和错误边界。
1169
+ */
90
1170
  exists(): Promise<boolean>;
1171
+ /**
1172
+ * 枚举当前目录的直接子项。
1173
+ *
1174
+ * @param options - 可选的单次结果数量上限。省略 options、传 `{}` 或省略 `limit` 时使用
1175
+ * `1000`;完整范围见 {@link ListOptions}。
1176
+ * @returns 当前目录直接子项的冻结 {@link FileHandle} / {@link DirectoryHandle} 代理数组;空目录
1177
+ * 返回 `[]`。数组与每个代理都是本次调用的新结果,条目 `mode` 与当前目录严格一致,`name` 只含
1178
+ * basename,不包含父路径或 Host 真实路径。不会递归返回后代。
1179
+ * @throws {@link HbMiniProgramSDKError} options 不是对象,或 `limit` 不是正的 safe integer 时返回
1180
+ * `INVALID_PARAMS`;`limit > 1000`,或 Host 返回项目数超过有效 `limit` 时返回
1181
+ * `DIRECTORY_LIST_LIMIT_EXCEEDED`。
1182
+ * @throws {@link HbMiniProgramSDKError} 当前目录或任一祖先不存在时返回 `DIRECTORY_NOT_FOUND`,目标
1183
+ * 实际是文件时返回 `FILE_TYPE_MISMATCH`;外部 direct Directory 授权失效、来自其他或已结束的
1184
+ * Runtime session 时返回 `FILE_ACCESS_REVOKED`。
1185
+ * @throws {@link HbMiniProgramSDKError} 未声明或未启用 `filesystem` 时返回
1186
+ * `PERMISSION_NOT_DECLARED` / `PERMISSION_DENIED`;Host 未开放或未协商到 `directory.list` 时返回
1187
+ * `METHOD_FORBIDDEN`,旧 Runtime 可返回 `METHOD_NOT_FOUND`。
1188
+ * @throws {@link HbMiniProgramSDKError} Host 返回非数组、稀疏数组、非法 kind/name/mode/handle,或
1189
+ * 子项不能安全派生为当前目录的直接后代时返回 `FILE_IO_FAILED`;其他 Host 枚举或底层 I/O 失败
1190
+ * 返回对应稳定文件错误码,无法识别的 Host 错误统一为 `FILE_IO_FAILED`。
1191
+ *
1192
+ * @remarks
1193
+ * `list()` 只枚举一层,不排序、不去重,也不补齐分页。结果顺序以及达到 `limit` 时选择哪些条目
1194
+ * 由 Host 文件系统决定;调用方不能依赖字母序、创建时间序或跨调用稳定顺序。需要稳定展示时应按
1195
+ * `name` 等业务规则自行排序。公开结果没有 `total`、`hasMore` 或 continuation cursor,因此
1196
+ * `limit` 不应被当作可完整遍历超大目录的分页协议。
1197
+ *
1198
+ * Runtime 逐槽读取 Host 数组,拒绝稀疏或越界结果,并把每个 Host 文件/目录转换成当前目录的直接
1199
+ * 子逻辑引用;SDK 再验证所有 descriptor 都继承父目录 `mode`。从 `read` 目录列出的代理仍只读,
1200
+ * 从 `readwrite` 目录列出的代理可在原授权范围内写入,但枚举不会提升权限或扩大到父目录之外。
1201
+ *
1202
+ * 返回项不会作为新的 external direct handles 注册,因此不消耗 picker / `saveFile()` 共享的 1024
1203
+ * direct-handle 配额。它们仍依赖原目录的来源和生命周期:sandbox 子项按当前 Mini-program identity
1204
+ * 解析;外部目录的子项只在原 direct Directory 所属的当前 Runtime session 内有效,session 结束或
1205
+ * 授权撤销后后续操作会失败。列表只是本次枚举快照,返回后文件系统可以继续变化。
1206
+ *
1207
+ * `mode: 'read'` 与 `mode: 'readwrite'` 目录都能调用。该方法不要求可信用户手势,不创建、读取或
1208
+ * 修改文件内容;外部目录只有最初调用 `pickDirectory()` 时需要手势。新 PC Host 支持该操作;
1209
+ * Android / iOS `1.3.396+` 仅在 `system.describe` 宣告 `files.list` 时逐项启用,OHOS 同样以 Host
1210
+ * 实际协商结果为准。Web、Browser Dev Host、旧 Host 或 operation 缺失时 fail closed,不提供
1211
+ * 浏览器文件系统、File / Blob 或内存 fallback。
1212
+ *
1213
+ * 若只需判断目录本身是否存在,使用 {@link DirectoryHandle.exists | exists()}。已知子项名称时,
1214
+ * 可直接通过当前目录的 {@link PathRoot.file | file()} 或 {@link PathRoot.directory | directory()}
1215
+ * 构造 lazy proxy,无需先枚举;这两个方法同样不会执行 I/O 或占用 direct-handle 配额。
1216
+ *
1217
+ * @example
1218
+ * ```ts
1219
+ * import hbSDK from '@heybox/hb-sdk'
1220
+ *
1221
+ * const reports = hbSDK.files.sandbox.directory('reports')
1222
+ * await reports.create({ recursive: true })
1223
+ * await reports.file('summary.json').writeText('{}')
1224
+ * await reports.directory('archive').create()
1225
+ *
1226
+ * const entries = await reports.list({ limit: 100 })
1227
+ * const sorted = [...entries].sort((left, right) => left.name.localeCompare(right.name))
1228
+ * for (const entry of sorted) {
1229
+ * if (entry.kind === 'file') console.log('file', entry.name, await entry.stat())
1230
+ * else console.log('directory', entry.name, await entry.exists())
1231
+ * }
1232
+ * ```
1233
+ *
1234
+ * @see {@link ListOptions}
1235
+ * @see {@link FileSystemEntity}
1236
+ * @see {@link PathRoot.file | DirectoryHandle.file()} 构造已知名称的直接或嵌套文件代理。
1237
+ * @see {@link PathRoot.directory | DirectoryHandle.directory()} 构造已知名称的直接或嵌套目录代理。
1238
+ * @see {@link DirectoryHandle.exists | DirectoryHandle.exists()} 检查当前目录是否存在。
1239
+ * @see {@link FilesModule.pickDirectory | files.pickDirectory} 取得当前 session 的外部目录授权。
1240
+ * @see [文件能力与沙箱](/guide/files-and-sandbox) 查看权限、路径、平台与配额边界。
1241
+ */
91
1242
  list(options?: ListOptions): Promise<FileSystemEntity[]>;
92
1243
  }
1244
+ /** 目录枚举返回的文件或目录代理。 */
93
1245
  export type FileSystemEntity = FileHandle | DirectoryHandle;
1246
+ /**
1247
+ * {@link FileHandle.stat} 返回的文件元数据快照。
1248
+ *
1249
+ * @remarks
1250
+ * Runtime 与 SDK 会把 Host 结果规范为这四个公开字段;Host 的额外字段不会进入结果。每次 `stat()`
1251
+ * 返回新对象,它不是缓存或 live view,也不冻结;调用方修改字段不会改变文件或后续快照。
1252
+ *
1253
+ * 单位是公开合同而不是可从 number 结构证明的事实:`size` 按 byte 解释,时间字段按 Unix epoch
1254
+ * milliseconds 解释。SDK 无法验证 Host 实际单位、时间来源、字段之间的顺序关系或快照 resolve 后是否仍
1255
+ * 与磁盘一致。
1256
+ */
94
1257
  export interface FileStat {
1258
+ /** 固定为 `'file'`,用于和 Host 的目录状态区分。 */
95
1259
  kind: 'file';
1260
+ /**
1261
+ * 本次快照中的文件大小,公开约定单位为 byte。必须是 `0` 到 `Number.MAX_SAFE_INTEGER` 的整数;
1262
+ * `0` 表示空文件。负数、小数、`NaN`、Infinity、unsafe integer 或数字字符串会使 `stat()` 以
1263
+ * `FILE_IO_FAILED` 拒绝。
1264
+ */
96
1265
  size: number;
97
- /** Unix epoch milliseconds。 */
1266
+ /**
1267
+ * Host 可提供的最后修改时间,公开约定为 Unix epoch milliseconds。可独立省略;存在时只保证为
1268
+ * 非负有限 number,允许小数和超过 `Number.MAX_SAFE_INTEGER` 的值,不保证可构造有效 `Date`。
1269
+ */
98
1270
  modifiedAt?: number;
99
- /** Unix epoch milliseconds。 */
1271
+ /**
1272
+ * Host 可提供的创建时间,公开约定为 Unix epoch milliseconds。可独立省略;范围规则与
1273
+ * {@link FileStat.modifiedAt} 相同,也不保证早于或等于 `modifiedAt`。
1274
+ */
100
1275
  createdAt?: number;
101
1276
  }
102
- /** Mini-program 对外文件能力。 */
1277
+ /**
1278
+ * Mini-program 对外文件能力。
1279
+ *
1280
+ * @remarks
1281
+ * `sandbox` 提供隔离持久存储;picker 与 `saveFile()` 通过可信用户操作授予当前 Runtime session
1282
+ * 最小化的外部访问范围。所有能力要求声明 `filesystem`,具体 operation 还需由 Host 宣告支持。
1283
+ */
103
1284
  export interface FilesModule {
1285
+ /** 当前 Mini-program 的私有 sandbox 逻辑根。 */
104
1286
  readonly sandbox: FileSystem;
105
1287
  /**
106
1288
  * 让用户选择一个或多个文件并返回当前 session 的授权代理。
107
1289
  *
108
- * @param options - 访问模式、扩展名筛选与多选设置。
109
- * @returns 用户选择的文件代理。
110
- * @remarks Android `1.3.396` 的精确 SAF 文件仅支持只读选择;请求 `readwrite` 会返回 `FILE_ACCESS_DENIED`。
1290
+ * @param options - 可选访问模式、扩展名筛选与多选设置;完整默认值和校验见
1291
+ * {@link PickFilesOptions}。
1292
+ * @returns 非空的冻结 {@link FileHandle} 数组。默认单选时恰好一项;每项 `kind` 固定为
1293
+ * `'file'`,`name` 是安全 basename,`mode` 与请求模式一致,且不包含真实路径。用户取消会
1294
+ * 抛错,不返回空数组或 `undefined`。
1295
+ * @throws {@link HbMiniProgramSDKError} options、`mode`、`accept` 或 `multiple` 非法时返回
1296
+ * `INVALID_PARAMS`;缺少当前可信用户手势时返回 `USER_GESTURE_REQUIRED`;用户取消系统选择器
1297
+ * 时返回 `FILE_PICKER_CANCELLED`。
1298
+ * @throws {@link HbMiniProgramSDKError} 未声明或未启用 `filesystem` 时返回
1299
+ * `PERMISSION_NOT_DECLARED` / `PERMISSION_DENIED`;Host 未开放/未协商到 `files.external` 时返回
1300
+ * `METHOD_FORBIDDEN`,旧 Runtime 可返回 `METHOD_NOT_FOUND`;请求的 `readwrite` 未获 Host
1301
+ * 授予时返回 `FILE_ACCESS_DENIED`。
1302
+ * @throws {@link HbMiniProgramSDKError} 整批结果会让当前 session 的外部 direct handle 超过
1303
+ * 1024 时返回 `FILE_QUOTA_EXCEEDED`,且不保留部分结果;授权在完成前失效、Host 返回空数组、
1304
+ * 单选返回多项、结果结构/name/mode 非法或其他 picker/I/O 失败时返回
1305
+ * `FILE_ACCESS_REVOKED` / `FILE_IO_FAILED` 等稳定文件错误码。
1306
+ *
1307
+ * @remarks
1308
+ * 必须直接从按钮点击等可信用户操作调用。不要先 `await` 握手或其他异步任务;应提前通过
1309
+ * `getHandshakeState()` / `onHandshakeStateChange()` 控制按钮只在 ready 时可用,再在点击回调
1310
+ * 中立即调用 picker。取消是正常用户结果,应按 `FILE_PICKER_CANCELLED` 结束当前流程。
1311
+ *
1312
+ * 默认 `mode: 'read'`、`multiple: false` 且无 `accept`。返回的是用户选择范围内的精确外部
1313
+ * File direct handles,不是浏览器原生 `File`,不能扩张到父目录或兄弟文件;每项授权只在
1314
+ * 当前 Runtime session 有效,session 结束或授权撤销后不能恢复或持久化复用。单个 session
1315
+ * 的 picker / `saveFile()` direct handle 共享 1024 上限,每个返回文件占用一个。
1316
+ *
1317
+ * `read` File 可调用 `readText()`、`readBytes()`、`exists()` 与 `stat()`;写入、创建及作为
1318
+ * 下载替换目标需要 `readwrite`。外部精确 File 无论 mode 都不能删除。Android `1.3.396+`
1319
+ * 的精确 SAF 文件只支持只读选择,请求 `readwrite` 会返回 `FILE_ACCESS_DENIED`;其他平台也
1320
+ * 以 Host 实际授予结果为准。
1321
+ *
1322
+ * 新 PC Host 支持文件选择;Android/iOS 需要 `1.3.396+`,移动端继续以 `system.describe`
1323
+ * 实际声明的 operation 为准;OHOS 同样按 Host 宣告能力启用。Web、Browser Dev Host、旧 Host
1324
+ * 或 operation 集不完整时 fail closed,不提供浏览器 File/Blob 或内存 fallback。页面代码不应
1325
+ * 按操作系统猜测可用性,应处理 `METHOD_FORBIDDEN`。
1326
+ *
1327
+ * @example
1328
+ * ```ts
1329
+ * import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
1330
+ *
1331
+ * const chooseFilesButton = document.querySelector<HTMLButtonElement>('#choose-files')!
1332
+ *
1333
+ * chooseFilesButton.addEventListener('click', async () => {
1334
+ * try {
1335
+ * const files = await hbSDK.files.pickFiles({
1336
+ * mode: 'read',
1337
+ * accept: ['.json', '.txt'],
1338
+ * multiple: true,
1339
+ * })
1340
+ *
1341
+ * for (const file of files) {
1342
+ * console.log(file.kind, file.name, file.mode, await file.readText())
1343
+ * }
1344
+ * } catch (error) {
1345
+ * if (error instanceof HbMiniProgramSDKError && error.code === 'FILE_PICKER_CANCELLED') return
1346
+ * throw error
1347
+ * }
1348
+ * })
1349
+ * ```
1350
+ *
1351
+ * @see {@link PickFilesOptions}
1352
+ * @see {@link FileHandle}
1353
+ * @see {@link FileHandle.readText}
1354
+ * @see {@link FileHandle.readBytes}
1355
+ * @see {@link FileHandle.stat}
1356
+ * @see {@link FilesModule.pickDirectory | files.pickDirectory}
1357
+ * @see {@link FilesModule.saveFile | files.saveFile}
1358
+ * @see {@link https://docs.xiaoheihe.cn/hb_sdk/guide/files-and-sandbox | 文件能力与沙箱}
1359
+ * @see {@link https://docs.xiaoheihe.cn/hb_sdk/guide/error-handling | 错误处理}
1360
+ * @see {@link https://docs.xiaoheihe.cn/hb_sdk/guide/permissions | 权限声明}
1361
+ *
111
1362
  * @since 0.8.0-alpha.2
112
1363
  * @hbPlatform android
113
1364
  * @hbPlatform ios
@@ -124,8 +1375,70 @@ export interface FilesModule {
124
1375
  /**
125
1376
  * 让用户选择目录并返回当前 session 的授权代理。
126
1377
  *
127
- * @param options - 目录访问模式。
128
- * @returns 用户选择的目录代理。
1378
+ * @param options - 可选目录授权模式;省略时等同于 `{ mode: 'read' }`,完整规则见
1379
+ * {@link PickDirectoryOptions}。
1380
+ * @returns 用户选中的冻结 {@link DirectoryHandle} direct proxy。`kind` 固定为
1381
+ * `'directory'`,`name` 是安全 basename,`mode` 与请求模式一致;不包含真实路径。取消会抛错,
1382
+ * 不返回 `undefined`。
1383
+ * @throws {@link HbMiniProgramSDKError} options 或 `mode` 非法时返回 `INVALID_PARAMS`;缺少当前
1384
+ * 可信用户手势时返回 `USER_GESTURE_REQUIRED`;用户取消系统选择器时返回
1385
+ * `FILE_PICKER_CANCELLED`。
1386
+ * @throws {@link HbMiniProgramSDKError} 未声明或未启用 `filesystem` 时返回
1387
+ * `PERMISSION_NOT_DECLARED` / `PERMISSION_DENIED`;Host 未开放/未协商到 `files.external` 时返回
1388
+ * `METHOD_FORBIDDEN`,旧 Runtime 可返回 `METHOD_NOT_FOUND`;请求的 `readwrite` 未获 Host
1389
+ * 授予时返回 `FILE_ACCESS_DENIED`。
1390
+ * @throws {@link HbMiniProgramSDKError} 当前 session 的外部 direct handle 达到 1024 上限时返回
1391
+ * `FILE_QUOTA_EXCEEDED`;授权在完成前失效、Host 结果非法/mode 不匹配或其他 picker/I/O 失败时
1392
+ * 返回 `FILE_ACCESS_REVOKED` 或 `FILE_IO_FAILED` 等稳定文件错误码。
1393
+ *
1394
+ * @remarks
1395
+ * 必须直接从按钮点击等可信用户操作调用。不要先 `await` 握手或其他异步任务;应提前通过
1396
+ * `getHandshakeState()` / `onHandshakeStateChange()` 控制按钮只在 ready 时可用,再在点击回调
1397
+ * 中立即调用 picker。取消是正常用户结果,应按 `FILE_PICKER_CANCELLED` 结束当前流程。
1398
+ *
1399
+ * 默认授权模式为 `read`。返回的是用户选择范围的精确外部目录授权,只在当前 Runtime
1400
+ * session 有效;session 结束或授权撤销后不能恢复或持久化复用。其 `file()` / `directory()`
1401
+ * 派生项及 `list()` 结果继承 mode、不能提升权限,也不会继续占用 direct handle 配额。
1402
+ * `readwrite` 允许在授权目录内创建/写入以及作为 `network.download()` target,但外部目录及
1403
+ * 其后代仍不能删除。
1404
+ *
1405
+ * 单个 Runtime session 最多保留 1024 个 picker / `saveFile()` direct handles;每次成功的
1406
+ * `pickDirectory()` 占用一个。它与 sandbox 的逻辑代理不同:
1407
+ * {@link FileSystem.directory | files.sandbox.directory} 不打开选择器、无需用户手势、持久按
1408
+ * Mini-program 隔离,也不占用该 direct-handle 配额。
1409
+ *
1410
+ * 新 PC Host 支持目录选择;Android/iOS 需要 `1.3.396+`,移动端继续以 `system.describe`
1411
+ * 实际声明的 operation 为准;OHOS 同样按 Host 宣告能力启用。Web、Browser Dev Host、旧 Host
1412
+ * 或 operation 集不完整时 fail closed,不提供 Blob/内存 fallback。页面代码不应按操作系统
1413
+ * 猜测可用性,应处理 `METHOD_FORBIDDEN`。
1414
+ *
1415
+ * @example
1416
+ * ```ts
1417
+ * import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
1418
+ *
1419
+ * const chooseDirectoryButton = document.querySelector<HTMLButtonElement>('#choose-directory')!
1420
+ *
1421
+ * chooseDirectoryButton.addEventListener('click', async () => {
1422
+ * try {
1423
+ * const directory = await hbSDK.files.pickDirectory({ mode: 'readwrite' })
1424
+ * console.log(directory.kind, directory.name, directory.mode)
1425
+ * await directory.file('report.txt').writeText('done')
1426
+ * } catch (error) {
1427
+ * if (error instanceof HbMiniProgramSDKError && error.code === 'FILE_PICKER_CANCELLED') return
1428
+ * throw error
1429
+ * }
1430
+ * })
1431
+ * ```
1432
+ *
1433
+ * @see {@link PickDirectoryOptions}
1434
+ * @see {@link DirectoryHandle}
1435
+ * @see {@link FileSystem.directory | files.sandbox.directory}
1436
+ * @see {@link FilesModule.saveFile | files.saveFile}
1437
+ * @see {@link MiniProgramNetworkModule.download | network.download}
1438
+ * @see {@link https://docs.xiaoheihe.cn/hb_sdk/guide/files-and-sandbox | 文件能力与沙箱}
1439
+ * @see {@link https://docs.xiaoheihe.cn/hb_sdk/guide/error-handling | 错误处理}
1440
+ * @see {@link https://docs.xiaoheihe.cn/hb_sdk/guide/permissions | 权限声明}
1441
+ *
129
1442
  * @since 0.8.0-alpha.2
130
1443
  * @hbPlatform android
131
1444
  * @hbPlatform ios
@@ -142,8 +1455,70 @@ export interface FilesModule {
142
1455
  /**
143
1456
  * 让用户选择一个精确的文件保存目标。
144
1457
  *
145
- * @param options - 建议文件名。
146
- * @returns 具备读写权限的目标文件代理。
1458
+ * @param options - 必填的保存目标建议 basename;完整校验见 {@link SaveFileOptions}。
1459
+ * @returns 用户确认后的冻结 {@link FileHandle} direct proxy。`kind` 固定为 `'file'`,`name`
1460
+ * 是 Host 最终文件 basename,`mode` 固定为 `'readwrite'`;不包含真实路径,也不授予父目录或
1461
+ * 兄弟文件访问权。
1462
+ * @throws {@link HbMiniProgramSDKError} options 缺失/非对象、`suggestedName` 非字符串或不是规范
1463
+ * basename、或传入 V1 不支持的 `accept` 时返回 `INVALID_PARAMS`;缺少当前可信用户手势时
1464
+ * 返回 `USER_GESTURE_REQUIRED`;用户取消系统保存界面时返回 `FILE_PICKER_CANCELLED`。
1465
+ * @throws {@link HbMiniProgramSDKError} 未声明或未启用 `filesystem` 时返回
1466
+ * `PERMISSION_NOT_DECLARED` / `PERMISSION_DENIED`;Host 未开放/未协商到保存 operation 时返回
1467
+ * `METHOD_FORBIDDEN`,旧 Runtime 可返回 `METHOD_NOT_FOUND`。目标已存在且 Host 不能独占创建
1468
+ * 时返回 `FILE_ALREADY_EXISTS`,不会静默覆盖。
1469
+ * @throws {@link HbMiniProgramSDKError} 当前 session 的外部 direct handle 达到 1024 上限时返回
1470
+ * `FILE_QUOTA_EXCEEDED`;授权在完成前失效、Host 返回非精确 File、非 `readwrite` mode、非法
1471
+ * descriptor 或其他 picker/I/O 失败时返回 `FILE_ACCESS_REVOKED` / `FILE_IO_FAILED` 等稳定
1472
+ * 文件错误码。
1473
+ *
1474
+ * @remarks
1475
+ * 必须直接从按钮点击等可信用户操作调用。不要先 `await` 握手或其他异步任务;应提前通过
1476
+ * `getHandshakeState()` / `onHandshakeStateChange()` 控制按钮只在 ready 时可用,再在点击回调
1477
+ * 中立即调用。取消是正常用户结果,应按 `FILE_PICKER_CANCELLED` 结束当前流程。
1478
+ *
1479
+ * 返回的是当前 Runtime session 内一个精确外部 File 授权,不会额外保留或暴露父 Directory
1480
+ * handle。它占用 picker / `saveFile()` 共享的 1024 direct-handle 配额中的一个;session 结束
1481
+ * 或授权撤销后不能恢复或持久化复用。代理固定 `readwrite`,可调用 `writeText()` /
1482
+ * `writeBytes()`,或作为 {@link MiniProgramNetworkModule.download | network.download} 的 File
1483
+ * target;外部授权仍不能调用 `remove()`。
1484
+ *
1485
+ * V1 没有 overwrite 选项。当前新 PC Host 先让用户选择保存目录,再以 `suggestedName` 独占
1486
+ * 创建空文件;同名目标返回 `FILE_ALREADY_EXISTS`。其他 Host 可以展示平台原生保存界面,
1487
+ * 但成功结果仍只授权最终精确 File,且不能通过该 API 请求静默覆盖。
1488
+ *
1489
+ * 新 PC 与 iOS Host 支持该能力;Android 不提供 `files.saveFile`。OHOS 按 Host 实际宣告的
1490
+ * operation 启用。Web、Browser Dev Host、旧 Host 或 operation 集不完整时 fail closed,不
1491
+ * 提供 Blob/内存 fallback。页面代码不应仅按操作系统判断,应处理 `METHOD_FORBIDDEN`。
1492
+ *
1493
+ * @example
1494
+ * ```ts
1495
+ * import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
1496
+ *
1497
+ * const saveButton = document.querySelector<HTMLButtonElement>('#save-report')!
1498
+ *
1499
+ * saveButton.addEventListener('click', async () => {
1500
+ * try {
1501
+ * const file = await hbSDK.files.saveFile({ suggestedName: 'report.json' })
1502
+ * await file.writeText(JSON.stringify({ ok: true }))
1503
+ * console.log(file.kind, file.name, file.mode)
1504
+ * } catch (error) {
1505
+ * if (error instanceof HbMiniProgramSDKError && error.code === 'FILE_PICKER_CANCELLED') return
1506
+ * throw error
1507
+ * }
1508
+ * })
1509
+ * ```
1510
+ *
1511
+ * @see {@link SaveFileOptions}
1512
+ * @see {@link FileHandle}
1513
+ * @see {@link FileHandle.writeText}
1514
+ * @see {@link FileHandle.writeBytes}
1515
+ * @see {@link FilesModule.pickFiles | files.pickFiles}
1516
+ * @see {@link FilesModule.pickDirectory | files.pickDirectory}
1517
+ * @see {@link MiniProgramNetworkModule.download | network.download}
1518
+ * @see {@link https://docs.xiaoheihe.cn/hb_sdk/guide/files-and-sandbox | 文件能力与沙箱}
1519
+ * @see {@link https://docs.xiaoheihe.cn/hb_sdk/guide/error-handling | 错误处理}
1520
+ * @see {@link https://docs.xiaoheihe.cn/hb_sdk/guide/permissions | 权限声明}
1521
+ *
147
1522
  * @since 0.8.0-alpha.2
148
1523
  * @hbPlatform ios
149
1524
  * @hbPlatform ohos