@life-palette/uploader 0.2.1
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.md +50 -0
- package/dist/index.cjs +575 -0
- package/dist/index.d.cts +195 -0
- package/dist/index.d.mts +195 -0
- package/dist/index.mjs +565 -0
- package/package.json +62 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { AnalyzeMediaOptions, MediaAnalysisResult } from "@life-palette/media";
|
|
2
|
+
//#region src/file-url.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* OSS URL 处理:图片缩略、实况照片配对、文件名解析等。
|
|
5
|
+
*
|
|
6
|
+
* 这些工具属于 OSS 契约的一部分——既被上传器消费,也被前端展示层消费。
|
|
7
|
+
*/
|
|
8
|
+
export interface FileData {
|
|
9
|
+
cover?: string;
|
|
10
|
+
extension?: string;
|
|
11
|
+
live_photo_video?: {
|
|
12
|
+
url?: string;
|
|
13
|
+
video_variants?: Array<{
|
|
14
|
+
quality?: string;
|
|
15
|
+
url?: string;
|
|
16
|
+
}>;
|
|
17
|
+
};
|
|
18
|
+
type?: string;
|
|
19
|
+
url?: string;
|
|
20
|
+
[key: string]: unknown;
|
|
21
|
+
}
|
|
22
|
+
export interface FileParseOptions {
|
|
23
|
+
format?: string;
|
|
24
|
+
resize?: number;
|
|
25
|
+
}
|
|
26
|
+
export interface FileParseResult extends FileData {
|
|
27
|
+
baseSrc: string;
|
|
28
|
+
cover: string;
|
|
29
|
+
fileType: "IMAGE" | "VIDEO";
|
|
30
|
+
thumbnailUrl: string;
|
|
31
|
+
videoSrc: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 解析文件数据,生成展示所需的 URL
|
|
35
|
+
* - IMAGE: thumbnailUrl(缩略图)、baseSrc(原图/转格式)、videoSrc(实况视频)
|
|
36
|
+
* - VIDEO: cover(封面截图)
|
|
37
|
+
*/
|
|
38
|
+
export declare function fileParse(data: FileData, options?: FileParseOptions): FileParseResult;
|
|
39
|
+
/**
|
|
40
|
+
* 判断文件是否为视频
|
|
41
|
+
*/
|
|
42
|
+
export declare function isVideo(file: {
|
|
43
|
+
type?: string;
|
|
44
|
+
}): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* 判断文件是否为实况照片(有 videoSrc 但本身不是视频)
|
|
47
|
+
*/
|
|
48
|
+
export declare function isLivePhoto(file: {
|
|
49
|
+
type?: string;
|
|
50
|
+
videoSrc?: string | null;
|
|
51
|
+
}): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* 生成 OSS 视频截帧 URL
|
|
54
|
+
*/
|
|
55
|
+
export declare function getVideoThumbnailUrl(videoUrl: string): string;
|
|
56
|
+
/**
|
|
57
|
+
* 生成 OSS 图片处理参数(resize + quality + webp)
|
|
58
|
+
*/
|
|
59
|
+
export declare function generateOssImageParams(originalWidth: number, originalHeight: number, targetWidth: number, quality?: number): string;
|
|
60
|
+
/**
|
|
61
|
+
* 解析文件名 → baseName + ext + isVideo
|
|
62
|
+
*/
|
|
63
|
+
export declare function parseFileName(fileName: string): {
|
|
64
|
+
baseName: string;
|
|
65
|
+
ext: string;
|
|
66
|
+
isVideo: boolean;
|
|
67
|
+
};
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region src/live-photo.d.ts
|
|
70
|
+
/**
|
|
71
|
+
* Live Photo pairing utilities.
|
|
72
|
+
*/
|
|
73
|
+
/**
|
|
74
|
+
* 检测文件列表中的 Live Photo 配对(同名 image + video)。
|
|
75
|
+
*/
|
|
76
|
+
export declare function detectLivePhotoPairs<T extends {
|
|
77
|
+
name: string;
|
|
78
|
+
type?: string;
|
|
79
|
+
}>(files: T[]): Array<{
|
|
80
|
+
image: T;
|
|
81
|
+
video: T;
|
|
82
|
+
}>;
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region src/pool.d.ts
|
|
85
|
+
/**
|
|
86
|
+
* Concurrency-limited async pool.
|
|
87
|
+
*
|
|
88
|
+
* Lightweight replacement for `p-limit` (≈ 30 lines, no dependency).
|
|
89
|
+
*/
|
|
90
|
+
export declare class PromisePool {
|
|
91
|
+
private readonly limit;
|
|
92
|
+
private active;
|
|
93
|
+
private readonly queue;
|
|
94
|
+
constructor(limit: number);
|
|
95
|
+
run<T>(task: () => Promise<T>): Promise<T>;
|
|
96
|
+
private next;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Retry an async operation with exponential backoff.
|
|
100
|
+
*/
|
|
101
|
+
export declare function withRetry<T>(task: () => Promise<T>, attempts: number, baseDelayMs?: number): Promise<T>;
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region src/uploader.d.ts
|
|
104
|
+
export interface OSSFile {
|
|
105
|
+
address?: string;
|
|
106
|
+
arthash?: string;
|
|
107
|
+
arthash_codec?: string;
|
|
108
|
+
blurhash?: string;
|
|
109
|
+
colors?: unknown[];
|
|
110
|
+
created_at: string;
|
|
111
|
+
file_md5: string;
|
|
112
|
+
height?: number;
|
|
113
|
+
is_private: boolean;
|
|
114
|
+
live_photo_video_id?: number;
|
|
115
|
+
live_photo_video_sec_uid?: string;
|
|
116
|
+
name: string;
|
|
117
|
+
sec_uid: string;
|
|
118
|
+
size: number;
|
|
119
|
+
taken_at?: string;
|
|
120
|
+
type: string;
|
|
121
|
+
updated_at: string;
|
|
122
|
+
url: string;
|
|
123
|
+
width?: number;
|
|
124
|
+
}
|
|
125
|
+
export interface UploadToken {
|
|
126
|
+
accessid: string;
|
|
127
|
+
dir: string;
|
|
128
|
+
expire: number;
|
|
129
|
+
host: string;
|
|
130
|
+
key: string;
|
|
131
|
+
policy: string;
|
|
132
|
+
signature: string;
|
|
133
|
+
}
|
|
134
|
+
export interface CompletePart {
|
|
135
|
+
etag: string;
|
|
136
|
+
part_number: number;
|
|
137
|
+
}
|
|
138
|
+
export type UploadStage = "compress" | "analyze" | "md5" | "upload" | "complete";
|
|
139
|
+
export interface UploadProgress {
|
|
140
|
+
percent: number;
|
|
141
|
+
stage: UploadStage;
|
|
142
|
+
}
|
|
143
|
+
export interface UploadOptions {
|
|
144
|
+
/** 媒体分析参数 */
|
|
145
|
+
analysis?: Omit<AnalyzeMediaOptions, "onProgress">;
|
|
146
|
+
/** 是否在上传前执行浏览器端媒体分析,默认 true */
|
|
147
|
+
analyze?: boolean;
|
|
148
|
+
/** 压缩图片 */
|
|
149
|
+
compress?: boolean;
|
|
150
|
+
/** 是否私有 */
|
|
151
|
+
isPrivate?: boolean;
|
|
152
|
+
/** 手动地理位置(经纬度) */
|
|
153
|
+
location?: {
|
|
154
|
+
lat: number;
|
|
155
|
+
lng: number;
|
|
156
|
+
};
|
|
157
|
+
/** 最大文件大小 MB(压缩用) */
|
|
158
|
+
maxSizeMB?: number;
|
|
159
|
+
/** 进度回调 */
|
|
160
|
+
onProgress?: (progress: UploadProgress) => void;
|
|
161
|
+
/** 已经计算好的分析结果,可避免上传前重复分析 */
|
|
162
|
+
precomputedAnalysis?: MediaAnalysisResult;
|
|
163
|
+
}
|
|
164
|
+
/** 仅上传文件到 OSS,不创建 DB 记录 */
|
|
165
|
+
export interface UploadToOSSResult {
|
|
166
|
+
file_name: string;
|
|
167
|
+
file_size: number;
|
|
168
|
+
key: string;
|
|
169
|
+
md5: string;
|
|
170
|
+
parts?: CompletePart[];
|
|
171
|
+
upload_id?: string;
|
|
172
|
+
}
|
|
173
|
+
export interface UploaderConfig {
|
|
174
|
+
/** API 基础路径,如 https://api.lpalette.cn/api/v1 */
|
|
175
|
+
apiBaseUrl: string;
|
|
176
|
+
/** 分片大小(字节),默认 5MB */
|
|
177
|
+
chunkSize?: number;
|
|
178
|
+
/** 带浏览器 metadata 的完成接口,默认 /file/upload/complete */
|
|
179
|
+
completeEndpoint?: string;
|
|
180
|
+
/** 获取 token 的函数 */
|
|
181
|
+
getToken: () => string | null;
|
|
182
|
+
/** 分片阈值(字节),默认 5MB */
|
|
183
|
+
multipartThreshold?: number;
|
|
184
|
+
/** 分片并发数,默认 4 */
|
|
185
|
+
partConcurrency?: number;
|
|
186
|
+
/** 单片失败重试次数,默认 3 */
|
|
187
|
+
partRetries?: number;
|
|
188
|
+
}
|
|
189
|
+
export declare function createOssUploader(config: UploaderConfig): {
|
|
190
|
+
associateLivePhotos: (results: OSSFile[]) => Promise<OSSFile[]>;
|
|
191
|
+
upload: (file: File, options?: UploadOptions) => Promise<OSSFile>;
|
|
192
|
+
uploadBatch: (files: File[], options?: UploadOptions, concurrency?: number, maxRetries?: number) => Promise<OSSFile[]>;
|
|
193
|
+
uploadToOSS: (file: File, options?: UploadOptions) => Promise<UploadToOSSResult>;
|
|
194
|
+
};
|
|
195
|
+
//#endregion
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { AnalyzeMediaOptions, MediaAnalysisResult } from "@life-palette/media";
|
|
2
|
+
//#region src/file-url.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* OSS URL 处理:图片缩略、实况照片配对、文件名解析等。
|
|
5
|
+
*
|
|
6
|
+
* 这些工具属于 OSS 契约的一部分——既被上传器消费,也被前端展示层消费。
|
|
7
|
+
*/
|
|
8
|
+
export interface FileData {
|
|
9
|
+
cover?: string;
|
|
10
|
+
extension?: string;
|
|
11
|
+
live_photo_video?: {
|
|
12
|
+
url?: string;
|
|
13
|
+
video_variants?: Array<{
|
|
14
|
+
quality?: string;
|
|
15
|
+
url?: string;
|
|
16
|
+
}>;
|
|
17
|
+
};
|
|
18
|
+
type?: string;
|
|
19
|
+
url?: string;
|
|
20
|
+
[key: string]: unknown;
|
|
21
|
+
}
|
|
22
|
+
export interface FileParseOptions {
|
|
23
|
+
format?: string;
|
|
24
|
+
resize?: number;
|
|
25
|
+
}
|
|
26
|
+
export interface FileParseResult extends FileData {
|
|
27
|
+
baseSrc: string;
|
|
28
|
+
cover: string;
|
|
29
|
+
fileType: "IMAGE" | "VIDEO";
|
|
30
|
+
thumbnailUrl: string;
|
|
31
|
+
videoSrc: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 解析文件数据,生成展示所需的 URL
|
|
35
|
+
* - IMAGE: thumbnailUrl(缩略图)、baseSrc(原图/转格式)、videoSrc(实况视频)
|
|
36
|
+
* - VIDEO: cover(封面截图)
|
|
37
|
+
*/
|
|
38
|
+
export declare function fileParse(data: FileData, options?: FileParseOptions): FileParseResult;
|
|
39
|
+
/**
|
|
40
|
+
* 判断文件是否为视频
|
|
41
|
+
*/
|
|
42
|
+
export declare function isVideo(file: {
|
|
43
|
+
type?: string;
|
|
44
|
+
}): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* 判断文件是否为实况照片(有 videoSrc 但本身不是视频)
|
|
47
|
+
*/
|
|
48
|
+
export declare function isLivePhoto(file: {
|
|
49
|
+
type?: string;
|
|
50
|
+
videoSrc?: string | null;
|
|
51
|
+
}): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* 生成 OSS 视频截帧 URL
|
|
54
|
+
*/
|
|
55
|
+
export declare function getVideoThumbnailUrl(videoUrl: string): string;
|
|
56
|
+
/**
|
|
57
|
+
* 生成 OSS 图片处理参数(resize + quality + webp)
|
|
58
|
+
*/
|
|
59
|
+
export declare function generateOssImageParams(originalWidth: number, originalHeight: number, targetWidth: number, quality?: number): string;
|
|
60
|
+
/**
|
|
61
|
+
* 解析文件名 → baseName + ext + isVideo
|
|
62
|
+
*/
|
|
63
|
+
export declare function parseFileName(fileName: string): {
|
|
64
|
+
baseName: string;
|
|
65
|
+
ext: string;
|
|
66
|
+
isVideo: boolean;
|
|
67
|
+
};
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region src/live-photo.d.ts
|
|
70
|
+
/**
|
|
71
|
+
* Live Photo pairing utilities.
|
|
72
|
+
*/
|
|
73
|
+
/**
|
|
74
|
+
* 检测文件列表中的 Live Photo 配对(同名 image + video)。
|
|
75
|
+
*/
|
|
76
|
+
export declare function detectLivePhotoPairs<T extends {
|
|
77
|
+
name: string;
|
|
78
|
+
type?: string;
|
|
79
|
+
}>(files: T[]): Array<{
|
|
80
|
+
image: T;
|
|
81
|
+
video: T;
|
|
82
|
+
}>;
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region src/pool.d.ts
|
|
85
|
+
/**
|
|
86
|
+
* Concurrency-limited async pool.
|
|
87
|
+
*
|
|
88
|
+
* Lightweight replacement for `p-limit` (≈ 30 lines, no dependency).
|
|
89
|
+
*/
|
|
90
|
+
export declare class PromisePool {
|
|
91
|
+
private readonly limit;
|
|
92
|
+
private active;
|
|
93
|
+
private readonly queue;
|
|
94
|
+
constructor(limit: number);
|
|
95
|
+
run<T>(task: () => Promise<T>): Promise<T>;
|
|
96
|
+
private next;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Retry an async operation with exponential backoff.
|
|
100
|
+
*/
|
|
101
|
+
export declare function withRetry<T>(task: () => Promise<T>, attempts: number, baseDelayMs?: number): Promise<T>;
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region src/uploader.d.ts
|
|
104
|
+
export interface OSSFile {
|
|
105
|
+
address?: string;
|
|
106
|
+
arthash?: string;
|
|
107
|
+
arthash_codec?: string;
|
|
108
|
+
blurhash?: string;
|
|
109
|
+
colors?: unknown[];
|
|
110
|
+
created_at: string;
|
|
111
|
+
file_md5: string;
|
|
112
|
+
height?: number;
|
|
113
|
+
is_private: boolean;
|
|
114
|
+
live_photo_video_id?: number;
|
|
115
|
+
live_photo_video_sec_uid?: string;
|
|
116
|
+
name: string;
|
|
117
|
+
sec_uid: string;
|
|
118
|
+
size: number;
|
|
119
|
+
taken_at?: string;
|
|
120
|
+
type: string;
|
|
121
|
+
updated_at: string;
|
|
122
|
+
url: string;
|
|
123
|
+
width?: number;
|
|
124
|
+
}
|
|
125
|
+
export interface UploadToken {
|
|
126
|
+
accessid: string;
|
|
127
|
+
dir: string;
|
|
128
|
+
expire: number;
|
|
129
|
+
host: string;
|
|
130
|
+
key: string;
|
|
131
|
+
policy: string;
|
|
132
|
+
signature: string;
|
|
133
|
+
}
|
|
134
|
+
export interface CompletePart {
|
|
135
|
+
etag: string;
|
|
136
|
+
part_number: number;
|
|
137
|
+
}
|
|
138
|
+
export type UploadStage = "compress" | "analyze" | "md5" | "upload" | "complete";
|
|
139
|
+
export interface UploadProgress {
|
|
140
|
+
percent: number;
|
|
141
|
+
stage: UploadStage;
|
|
142
|
+
}
|
|
143
|
+
export interface UploadOptions {
|
|
144
|
+
/** 媒体分析参数 */
|
|
145
|
+
analysis?: Omit<AnalyzeMediaOptions, "onProgress">;
|
|
146
|
+
/** 是否在上传前执行浏览器端媒体分析,默认 true */
|
|
147
|
+
analyze?: boolean;
|
|
148
|
+
/** 压缩图片 */
|
|
149
|
+
compress?: boolean;
|
|
150
|
+
/** 是否私有 */
|
|
151
|
+
isPrivate?: boolean;
|
|
152
|
+
/** 手动地理位置(经纬度) */
|
|
153
|
+
location?: {
|
|
154
|
+
lat: number;
|
|
155
|
+
lng: number;
|
|
156
|
+
};
|
|
157
|
+
/** 最大文件大小 MB(压缩用) */
|
|
158
|
+
maxSizeMB?: number;
|
|
159
|
+
/** 进度回调 */
|
|
160
|
+
onProgress?: (progress: UploadProgress) => void;
|
|
161
|
+
/** 已经计算好的分析结果,可避免上传前重复分析 */
|
|
162
|
+
precomputedAnalysis?: MediaAnalysisResult;
|
|
163
|
+
}
|
|
164
|
+
/** 仅上传文件到 OSS,不创建 DB 记录 */
|
|
165
|
+
export interface UploadToOSSResult {
|
|
166
|
+
file_name: string;
|
|
167
|
+
file_size: number;
|
|
168
|
+
key: string;
|
|
169
|
+
md5: string;
|
|
170
|
+
parts?: CompletePart[];
|
|
171
|
+
upload_id?: string;
|
|
172
|
+
}
|
|
173
|
+
export interface UploaderConfig {
|
|
174
|
+
/** API 基础路径,如 https://api.lpalette.cn/api/v1 */
|
|
175
|
+
apiBaseUrl: string;
|
|
176
|
+
/** 分片大小(字节),默认 5MB */
|
|
177
|
+
chunkSize?: number;
|
|
178
|
+
/** 带浏览器 metadata 的完成接口,默认 /file/upload/complete */
|
|
179
|
+
completeEndpoint?: string;
|
|
180
|
+
/** 获取 token 的函数 */
|
|
181
|
+
getToken: () => string | null;
|
|
182
|
+
/** 分片阈值(字节),默认 5MB */
|
|
183
|
+
multipartThreshold?: number;
|
|
184
|
+
/** 分片并发数,默认 4 */
|
|
185
|
+
partConcurrency?: number;
|
|
186
|
+
/** 单片失败重试次数,默认 3 */
|
|
187
|
+
partRetries?: number;
|
|
188
|
+
}
|
|
189
|
+
export declare function createOssUploader(config: UploaderConfig): {
|
|
190
|
+
associateLivePhotos: (results: OSSFile[]) => Promise<OSSFile[]>;
|
|
191
|
+
upload: (file: File, options?: UploadOptions) => Promise<OSSFile>;
|
|
192
|
+
uploadBatch: (files: File[], options?: UploadOptions, concurrency?: number, maxRetries?: number) => Promise<OSSFile[]>;
|
|
193
|
+
uploadToOSS: (file: File, options?: UploadOptions) => Promise<UploadToOSSResult>;
|
|
194
|
+
};
|
|
195
|
+
//#endregion
|