@h-ai/storage 0.1.0-alpha.67 → 0.1.0-alpha.68
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.
- package/README.en.md +85 -14
- package/README.ja.md +85 -14
- package/README.md +125 -14
- package/dist/browser.d.ts +399 -93
- package/dist/browser.js +3 -2
- package/dist/{chunk-KXE6OO5T.js → chunk-C7FR45VO.js} +8 -5
- package/dist/chunk-C7FR45VO.js.map +1 -0
- package/dist/chunk-I4BSES63.js +357 -0
- package/dist/chunk-I4BSES63.js.map +1 -0
- package/dist/chunk-P65WYXJG.js +33 -0
- package/dist/chunk-P65WYXJG.js.map +1 -0
- package/dist/client/index.d.ts +57 -48
- package/dist/client/index.js +1 -1
- package/dist/node.d.ts +15 -11
- package/dist/node.js +296 -136
- package/dist/node.js.map +1 -1
- package/dist/schemas.d.ts +103 -0
- package/dist/schemas.js +3 -0
- package/dist/schemas.js.map +1 -0
- package/package.json +7 -2
- package/dist/chunk-25GYTRA7.js +0 -274
- package/dist/chunk-25GYTRA7.js.map +0 -1
- package/dist/chunk-KXE6OO5T.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/storage-schemas.ts"],"names":[],"mappings":";;;AAgBO,IAAM,qBAAA,GAAwB;AAa9B,IAAM,uBAAA,GAA0B;AA6BhC,SAAS,kBAAA,CAAmB,GAAA,EAAa,UAAA,GAAa,KAAA,EAAoC;AAC/F,EAAA,IAAI,cAAc,GAAA,KAAQ,EAAA;AACxB,IAAA,OAAO,MAAA;AACT,EAAA,IAAI,GAAA,CAAI,MAAK,KAAM,EAAA;AACjB,IAAA,OAAO,OAAA;AACT,EAAA,IAAI,IAAI,WAAA,EAAY,CAAE,MAAA,CAAO,GAAG,EAAE,UAAA,GAAa,qBAAA;AAC7C,IAAA,OAAO,SAAA;AACT,EAAA,IAAI,GAAA,CAAI,WAAW,GAAG,CAAA,IAAK,IAAI,QAAA,CAAS,IAAI,CAAA,IAAK,CAAC,GAAG,GAAG,EAAE,IAAA,CAAK,CAAA,IAAA,KAAQ,IAAA,CAAK,UAAA,CAAW,CAAC,CAAA,GAAI,MAAM,IAAA,CAAK,UAAA,CAAW,CAAC,CAAA,KAAM,GAAG,CAAA;AAC1H,IAAA,OAAO,YAAA;AACT,EAAA,IAAI,GAAA,CAAI,MAAM,GAAG,CAAA,CAAE,KAAK,CAAA,OAAA,KAAW,OAAA,KAAY,GAAA,IAAO,OAAA,KAAY,IAAI,CAAA;AACpE,IAAA,OAAO,UAAA;AACT,EAAA,OAAO,MAAA;AACT;AAGA,SAAS,UAAU,UAAA,EAAqB;AACtC,EAAA,OAAO,EAAE,MAAA,EAAO,CAAE,WAAA,CAAY,CAAC,KAAK,OAAA,KAAY;AAC9C,IAAA,MAAM,KAAA,GAAQ,kBAAA,CAAmB,GAAA,EAAK,UAAU,CAAA;AAChD,IAAA,IAAI,KAAA;AACF,MAAA,OAAA,CAAQ,QAAA,CAAS,EAAE,IAAA,EAAM,QAAA,EAAU,QAAQ,EAAE,eAAA,EAAiB,KAAA,EAAM,EAAG,CAAA;AAAA,EAC3E,CAAC,CAAA;AACH;AAYO,IAAM,gBAAA,GAAmB,UAAU,KAAK;AAYxC,IAAM,mBAAA,GAAsB,UAAU,IAAI;AAY1C,IAAM,uBAAA,GAA0B,EAAE,KAAA,CAAM,gBAAgB,EAAE,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,uBAAuB;AAY5F,IAAM,6BAAA,GAAgC,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,GAAM,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,MAAM","file":"chunk-P65WYXJG.js","sourcesContent":["/**\n * @h-ai/storage — 跨端输入约束;仅依赖 Zod,不加载 Provider、配置或 Node 模块。\n * @module storage-schemas\n */\nimport { z } from 'zod'\n\n/**\n * 对象键的 UTF-8 字节上限;不是 JavaScript 字符串长度。\n * @example\n * ```ts\n * import { STORAGE_KEY_MAX_BYTES } from '@h-ai/storage/schemas'\n *\n * const fits = new TextEncoder().encode('uploads/报告.pdf').length <= STORAGE_KEY_MAX_BYTES\n * void fits\n * ```\n */\nexport const STORAGE_KEY_MAX_BYTES = 1024\n\n/**\n * 单次公开 HTTP 删除请求的原始键数量上限;Node deleteMany 仍按 Provider 上限分批。\n * @example\n * ```ts\n * import { STORAGE_DELETE_MAX_KEYS } from '@h-ai/storage/schemas'\n *\n * const keys = ['a.txt', 'b.txt']\n * const page = keys.slice(0, STORAGE_DELETE_MAX_KEYS)\n * void page\n * ```\n */\nexport const STORAGE_DELETE_MAX_KEYS = 1000\n\n/**\n * 键校验失败类别;调用层据此生成本地化消息,不解析错误文本。\n * @example\n * ```ts\n * import type { StorageKeyIssue } from '@h-ai/storage'\n *\n * const value: StorageKeyIssue = 'tooLong'\n * void value\n * ```\n */\nexport type StorageKeyIssue = 'empty' | 'tooLong' | 'characters' | 'segments'\n\n/**\n * 检查跨端键边界,不归一化输入,不替代文件系统防逃逸或资源授权。\n *\n * @param key - 调用方视角的对象键,不含 Provider 配置前缀。\n * @param allowEmpty - 是否允许空字符串(用于列表前缀);纯空白仍无效。\n * @returns 首个失败类别;合法时为 undefined。\n * @example\n * ```ts\n * import { getStorageKeyIssue } from '@h-ai/storage/schemas'\n *\n * const unsafe = getStorageKeyIssue('../private.txt') // segments\n * const emptyPrefix = getStorageKeyIssue('', true) // undefined\n * void [unsafe, emptyPrefix]\n * ```\n */\nexport function getStorageKeyIssue(key: string, allowEmpty = false): StorageKeyIssue | undefined {\n if (allowEmpty && key === '')\n return undefined\n if (key.trim() === '')\n return 'empty'\n if (new TextEncoder().encode(key).byteLength > STORAGE_KEY_MAX_BYTES)\n return 'tooLong'\n if (key.startsWith('/') || key.includes('\\\\') || [...key].some(char => char.charCodeAt(0) < 32 || char.charCodeAt(0) === 127))\n return 'characters'\n if (key.split('/').some(segment => segment === '.' || segment === '..'))\n return 'segments'\n return undefined\n}\n\n/** 通过稳定 params 保留失败类别;默认 Zod 消息交由请求层按 locale 映射。 */\nfunction keySchema(allowEmpty: boolean) {\n return z.string().superRefine((key, context) => {\n const issue = getStorageKeyIssue(key, allowEmpty)\n if (issue)\n context.addIssue({ code: 'custom', params: { storageKeyIssue: issue } })\n })\n}\n\n/**\n * 文件键 Schema:非空、UTF-8 最多 1024 字节,无绝对路径、反斜线、控制符或点路径段。\n * @example\n * ```ts\n * import { StorageKeySchema } from '@h-ai/storage'\n *\n * const value = StorageKeySchema.parse('users/u1/report.pdf')\n * void value\n * ```\n */\nexport const StorageKeySchema = keySchema(false)\n\n/**\n * 列表前缀 Schema;允许空字符串与部分文件名,不把前缀当物理目录。\n * @example\n * ```ts\n * import { StoragePrefixSchema } from '@h-ai/storage'\n *\n * const value = StoragePrefixSchema.parse('users/u1/rep')\n * void value\n * ```\n */\nexport const StoragePrefixSchema = keySchema(true)\n\n/**\n * HTTP 批量删除键 Schema;按输入数量计数,重复键不能绕过上限。\n * @example\n * ```ts\n * import { StorageDeleteKeysSchema } from '@h-ai/storage'\n *\n * const value = StorageDeleteKeysSchema.parse(['users/u1/a.txt', 'users/u1/b.txt'])\n * void value\n * ```\n */\nexport const StorageDeleteKeysSchema = z.array(StorageKeySchema).min(1).max(STORAGE_DELETE_MAX_KEYS)\n\n/**\n * 预签名有效期,单位秒;整数 1–604800,不在此处填充 Node/HTTP 各自默认值。\n * @example\n * ```ts\n * import { StoragePresignExpiresInSchema } from '@h-ai/storage'\n *\n * const value = StoragePresignExpiresInSchema.parse(900)\n * void value\n * ```\n */\nexport const StoragePresignExpiresInSchema = z.number().int().min(1).max(604800)\n"]}
|
package/dist/client/index.d.ts
CHANGED
|
@@ -8,6 +8,13 @@
|
|
|
8
8
|
* 上传进度回调数据
|
|
9
9
|
*
|
|
10
10
|
* 由 `uploadWithPresignedUrl` 在上传过程中通过 `onProgress` 回调返回。
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import type { UploadProgress } from '@h-ai/storage'
|
|
14
|
+
*
|
|
15
|
+
* const value: UploadProgress = { loaded: 50, total: 100, percent: 50 }
|
|
16
|
+
* void value
|
|
17
|
+
* ```
|
|
11
18
|
*/
|
|
12
19
|
interface UploadProgress {
|
|
13
20
|
/** 已上传字节数 */
|
|
@@ -21,19 +28,33 @@ interface UploadProgress {
|
|
|
21
28
|
* 前端上传选项
|
|
22
29
|
*
|
|
23
30
|
* 控制 `uploadWithPresignedUrl` 的行为,包括内容类型、进度监听和取消。
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* import type { ClientUploadOptions } from '@h-ai/storage'
|
|
34
|
+
*
|
|
35
|
+
* const value: ClientUploadOptions = { contentType: 'text/plain', onProgress: progress => { document.title = `${progress.percent}%` } }
|
|
36
|
+
* void value
|
|
37
|
+
* ```
|
|
24
38
|
*/
|
|
25
39
|
interface ClientUploadOptions {
|
|
26
40
|
/** 内容类型(设置后会加到请求 Content-Type 头) */
|
|
27
41
|
contentType?: string;
|
|
28
42
|
/** 进度回调(设置后会使用 XMLHttpRequest;仅 lengthComputable=true 时回调) */
|
|
29
43
|
onProgress?: (progress: UploadProgress) => void;
|
|
30
|
-
/**
|
|
44
|
+
/** 取消上传;预取消不发送请求,进行中取消返回失败,完成后移除本次监听。取消不能撤销远端已写入对象。 */
|
|
31
45
|
abortController?: AbortController;
|
|
32
46
|
}
|
|
33
47
|
/**
|
|
34
48
|
* 前端下载选项
|
|
35
49
|
*
|
|
36
50
|
* 控制 `downloadWithPresignedUrl` / `downloadAndSave` 的行为。
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* import type { ClientDownloadOptions } from '@h-ai/storage'
|
|
54
|
+
*
|
|
55
|
+
* const value: ClientDownloadOptions = { filename: 'report.pdf', abortController: new AbortController() }
|
|
56
|
+
* void value
|
|
57
|
+
* ```
|
|
37
58
|
*/
|
|
38
59
|
interface ClientDownloadOptions {
|
|
39
60
|
/** 保存的文件名(仅 downloadAndSave 使用,默认为 'download') */
|
|
@@ -44,31 +65,19 @@ interface ClientDownloadOptions {
|
|
|
44
65
|
/**
|
|
45
66
|
* 使用签名 URL 上传文件
|
|
46
67
|
*
|
|
47
|
-
* @param url -
|
|
68
|
+
* @param url - 已成功获取的 S3 HTTP(S) 上传签名 URL;本地存储须使用应用的鉴权文件接口。
|
|
48
69
|
* @param data - 要上传的数据(File、Blob、ArrayBuffer 或字符串)
|
|
49
70
|
* @param options - 上传选项
|
|
50
|
-
* @returns
|
|
51
|
-
*
|
|
71
|
+
* @returns 上传结果;预取消不发送,进行中取消/网络失败/初始化异常结算为失败,终态移除本次监听。
|
|
72
|
+
* 取消不代表远端对象已回滚;上传完成后的撤销由应用另行授权删除。
|
|
52
73
|
* @example
|
|
53
74
|
* ```ts
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* })
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* // 使用签名 URL 上传
|
|
62
|
-
* const file = document.getElementById('fileInput').files[0]
|
|
63
|
-
* const result = await uploadWithPresignedUrl(uploadUrl, file, {
|
|
64
|
-
* contentType: 'image/png',
|
|
65
|
-
* onProgress: (p) => {
|
|
66
|
-
* // 在此更新进度条:p.percent
|
|
67
|
-
* }
|
|
68
|
-
* })
|
|
69
|
-
*
|
|
70
|
-
* if (result.success) {
|
|
71
|
-
* // 上传成功
|
|
75
|
+
* import { uploadWithPresignedUrl } from '@h-ai/storage/client'
|
|
76
|
+
*
|
|
77
|
+
* // url 由应用鉴权接口返回,且 S3 签名包含相同 Content-Type。
|
|
78
|
+
* async function upload(url: string, file: File) {
|
|
79
|
+
* const result = await uploadWithPresignedUrl(url, file, { contentType: file.type })
|
|
80
|
+
* if (!result.success) throw new Error(result.error)
|
|
72
81
|
* }
|
|
73
82
|
* ```
|
|
74
83
|
*/
|
|
@@ -82,18 +91,15 @@ declare function uploadWithPresignedUrl(url: string, data: File | Blob | ArrayBu
|
|
|
82
91
|
* @param url - 后端生成的下载签名 URL
|
|
83
92
|
* @param options - 下载选项
|
|
84
93
|
* @returns 下载结果(成功时 data 为 Blob)
|
|
85
|
-
*
|
|
86
94
|
* @example
|
|
87
95
|
* ```ts
|
|
88
|
-
*
|
|
89
|
-
* const result = await downloadWithPresignedUrl(downloadUrl)
|
|
90
|
-
* if (result.success) {
|
|
91
|
-
* const blob = result.data
|
|
92
|
-
* // 处理 blob...
|
|
93
|
-
* }
|
|
96
|
+
* import { downloadWithPresignedUrl } from '@h-ai/storage/client'
|
|
94
97
|
*
|
|
95
|
-
*
|
|
96
|
-
* await
|
|
98
|
+
* async function download(url: string) {
|
|
99
|
+
* const result = await downloadWithPresignedUrl(url)
|
|
100
|
+
* if (!result.success || !result.data) throw new Error(result.error ?? 'Empty download')
|
|
101
|
+
* return result.data
|
|
102
|
+
* }
|
|
97
103
|
* ```
|
|
98
104
|
*/
|
|
99
105
|
declare function downloadWithPresignedUrl(url: string, options?: ClientDownloadOptions): Promise<{
|
|
@@ -106,12 +112,15 @@ declare function downloadWithPresignedUrl(url: string, options?: ClientDownloadO
|
|
|
106
112
|
*
|
|
107
113
|
* @param url - 下载 URL
|
|
108
114
|
* @param options - 下载选项
|
|
109
|
-
*
|
|
115
|
+
* @returns 声明返回类型对应的操作结果。
|
|
110
116
|
* @example
|
|
111
117
|
* ```ts
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
118
|
+
* import { downloadAndSave } from '@h-ai/storage/client'
|
|
119
|
+
*
|
|
120
|
+
* async function save(url: string) {
|
|
121
|
+
* const result = await downloadAndSave(url, { filename: 'report.pdf' })
|
|
122
|
+
* if (!result.success) throw new Error(result.error)
|
|
123
|
+
* }
|
|
115
124
|
* ```
|
|
116
125
|
*/
|
|
117
126
|
declare function downloadAndSave(url: string, options?: ClientDownloadOptions): Promise<{
|
|
@@ -122,16 +131,16 @@ declare function downloadAndSave(url: string, options?: ClientDownloadOptions):
|
|
|
122
131
|
* 从 File 对象获取文件扩展名
|
|
123
132
|
*
|
|
124
133
|
* 取文件名中最后一个 '.' 之后的部分,转为小写。
|
|
125
|
-
*
|
|
134
|
+
* 没有点号或以点号结尾时返回空字符串;仅前导点号的文件名按其后文本返回扩展名。
|
|
126
135
|
*
|
|
127
136
|
* @param file - 浏览器 File 对象
|
|
128
137
|
* @returns 扩展名(不含点),如 'png'、'tar.gz' 返回 'gz'
|
|
129
|
-
*
|
|
130
138
|
* @example
|
|
131
139
|
* ```ts
|
|
132
|
-
* getFileExtension
|
|
133
|
-
*
|
|
134
|
-
* getFileExtension(new File([], '
|
|
140
|
+
* import { getFileExtension } from '@h-ai/storage/client'
|
|
141
|
+
*
|
|
142
|
+
* const extension = getFileExtension(new File(['hello'], 'report.txt'))
|
|
143
|
+
* void extension
|
|
135
144
|
* ```
|
|
136
145
|
*/
|
|
137
146
|
declare function getFileExtension(file: File): string;
|
|
@@ -143,11 +152,12 @@ declare function getFileExtension(file: File): string;
|
|
|
143
152
|
*
|
|
144
153
|
* @param extension - 文件扩展名(不含点,大小写不敏感)
|
|
145
154
|
* @returns MIME 类型字符串
|
|
146
|
-
*
|
|
147
155
|
* @example
|
|
148
156
|
* ```ts
|
|
149
|
-
* getMimeType
|
|
150
|
-
*
|
|
157
|
+
* import { getMimeType } from '@h-ai/storage/client'
|
|
158
|
+
*
|
|
159
|
+
* const mime = getMimeType('pdf')
|
|
160
|
+
* void mime
|
|
151
161
|
* ```
|
|
152
162
|
*/
|
|
153
163
|
declare function getMimeType(extension: string): string;
|
|
@@ -155,16 +165,15 @@ declare function getMimeType(extension: string): string;
|
|
|
155
165
|
* 格式化文件大小为人类可读字符串
|
|
156
166
|
*
|
|
157
167
|
* 使用 1024 进制,输出单位为 B/KB/MB/GB/TB。
|
|
158
|
-
*
|
|
168
|
+
* 非零值使用对应单位并保留 2 位小数。
|
|
159
169
|
*
|
|
160
170
|
* @param bytes - 字节数(非负整数)
|
|
161
171
|
* @returns 格式化后的字符串,如 '0 B'、'1.50 KB'、'2.30 MB'
|
|
162
|
-
*
|
|
163
172
|
* @example
|
|
164
173
|
* ```ts
|
|
165
|
-
* formatFileSize
|
|
166
|
-
*
|
|
167
|
-
* formatFileSize(
|
|
174
|
+
* import { formatFileSize } from '@h-ai/storage/client'
|
|
175
|
+
*
|
|
176
|
+
* void formatFileSize(1536)
|
|
168
177
|
* ```
|
|
169
178
|
*/
|
|
170
179
|
declare function formatFileSize(bytes: number): string;
|
package/dist/client/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { downloadAndSave, downloadWithPresignedUrl, formatFileSize, getFileExtension, getMimeType, uploadWithPresignedUrl } from '../chunk-
|
|
1
|
+
export { downloadAndSave, downloadWithPresignedUrl, formatFileSize, getFileExtension, getMimeType, uploadWithPresignedUrl } from '../chunk-I4BSES63.js';
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
package/dist/node.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { ClientDownloadOptions, ClientUploadOptions, UploadProgress, downloadAndSave, downloadWithPresignedUrl, formatFileSize, getFileExtension, getMimeType, uploadWithPresignedUrl } from './client/index.js';
|
|
2
2
|
import { StorageFunctions } from './browser.js';
|
|
3
|
-
export { ChecksumAlgorithm, ChecksumOperations, ChecksumOptions, CopyOptions, DirOperations, DownloadOptions, FileMetadata, FileOperations, HaiStorageError, ListOptions, ListResult, LocalConfig, LocalConfigSchema, PresignOperations, PresignOptions, PresignOptionsSchema, PresignUploadOptions, PresignUploadOptionsSchema, S3Config, S3ConfigSchema, StorageConfig, StorageConfigInput, StorageConfigSchema, StorageData, StorageOperationLogConfig, StorageOperationLogConfigSchema,
|
|
3
|
+
export { ChecksumAlgorithm, ChecksumOperations, ChecksumOptions, CopyOptions, DirOperations, DownloadOptions, FileMetadata, FileOperations, HaiStorageError, ListOptions, ListResult, LocalConfig, LocalConfigSchema, PresignOperations, PresignOptions, PresignOptionsSchema, PresignUploadOptions, PresignUploadOptionsSchema, S3Config, S3ConfigSchema, StorageConfig, StorageConfigInput, StorageConfigSchema, StorageData, StorageDeleteFailure, StorageDeleteResult, StorageDeleteSummary, StorageOperationLogConfig, StorageOperationLogConfigSchema, StorageType, StorageTypeSchema, UploadOptions } from './browser.js';
|
|
4
|
+
export { STORAGE_DELETE_MAX_KEYS, STORAGE_KEY_MAX_BYTES, StorageDeleteKeysSchema, StorageKeyIssue, StorageKeySchema, StoragePrefixSchema, StoragePresignExpiresInSchema, getStorageKeyIssue } from './schemas.js';
|
|
4
5
|
import 'zod';
|
|
5
6
|
import '@h-ai/core';
|
|
6
7
|
import 'node:buffer';
|
|
@@ -15,21 +16,24 @@ import 'node:buffer';
|
|
|
15
16
|
/**
|
|
16
17
|
* 存储服务单例
|
|
17
18
|
*
|
|
18
|
-
*
|
|
19
|
+
* 文件、目录及签名操作前须调用 `storage.init()`;checksum 为无状态工具,无需初始化。
|
|
19
20
|
* 初始化后通过 `storage.file`、`storage.dir`、`storage.presign` 访问各操作接口。
|
|
20
|
-
*
|
|
21
21
|
* @example
|
|
22
22
|
* ```ts
|
|
23
23
|
* import { storage } from '@h-ai/storage'
|
|
24
24
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
25
|
+
* const initialized = await storage.init({ type: 'local', root: './data/uploads' })
|
|
26
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
27
|
+
* try {
|
|
28
|
+
* const uploaded = await storage.file.put('reports/a.txt', 'hello', { ifNoneMatch: '*' })
|
|
29
|
+
* if (!uploaded.success) throw new Error(uploaded.error.message)
|
|
30
|
+
* const downloaded = await storage.file.get('reports/a.txt')
|
|
31
|
+
* if (!downloaded.success) throw new Error(downloaded.error.message)
|
|
32
|
+
* void downloaded.data
|
|
33
|
+
* } finally {
|
|
34
|
+
* const closed = await storage.close()
|
|
35
|
+
* if (!closed.success) throw new Error(closed.error.message)
|
|
36
|
+
* }
|
|
33
37
|
* ```
|
|
34
38
|
*/
|
|
35
39
|
declare const storage: StorageFunctions;
|