@cloudbase/ai 3.3.14-alpha.2 → 3.6.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.
- package/.eslintrc.js +1 -0
- package/dist/cjs/AI.d.ts +5 -3
- package/dist/cjs/AI.js +64 -24
- package/dist/cjs/errors.d.ts +10 -0
- package/dist/cjs/errors.js +38 -0
- package/dist/cjs/index.d.ts +3 -1
- package/dist/cjs/index.js +14 -6
- package/dist/cjs/models/image-model.d.ts +2 -1
- package/dist/cjs/models/image-model.js +33 -12
- package/dist/cjs/type.d.ts +3 -1
- package/dist/cjs/type.js +1 -1
- package/dist/cjs/utils.d.ts +1 -1
- package/dist/cjs/utils.js +9 -4
- package/dist/esm/AI.d.ts +5 -3
- package/dist/esm/AI.js +64 -24
- package/dist/esm/errors.d.ts +10 -0
- package/dist/esm/errors.js +35 -0
- package/dist/esm/index.d.ts +3 -1
- package/dist/esm/index.js +14 -6
- package/dist/esm/models/image-model.d.ts +2 -1
- package/dist/esm/models/image-model.js +33 -12
- package/dist/esm/type.d.ts +3 -1
- package/dist/esm/type.js +1 -1
- package/dist/esm/utils.d.ts +1 -1
- package/dist/esm/utils.js +9 -4
- package/dist/miniprogram/index.js +1 -1
- package/package.json +4 -4
- package/src/AI.ts +53 -16
- package/src/errors.ts +23 -0
- package/src/index.ts +13 -4
- package/src/models/image-model.ts +49 -8
- package/src/type.ts +15 -2
- package/src/utils.ts +18 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudbase/ai",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.2",
|
|
4
4
|
"description": "cloudbase js sdk ai module",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"author": "",
|
|
31
31
|
"license": "Apache-2.0",
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@cloudbase/types": "3.
|
|
34
|
-
"@cloudbase/utilities": "3.
|
|
33
|
+
"@cloudbase/types": "3.6.2",
|
|
34
|
+
"@cloudbase/utilities": "3.6.2",
|
|
35
35
|
"@mattiasbuelens/web-streams-adapter": "^0.1.0",
|
|
36
36
|
"text-encoding-shim": "^1.0.5",
|
|
37
37
|
"web-streams-polyfill": "^4.0.0"
|
|
@@ -39,5 +39,5 @@
|
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@cloudbase/adapter-interface": "^0.7.1"
|
|
41
41
|
},
|
|
42
|
-
"gitHead": "
|
|
42
|
+
"gitHead": "859557576897d4778857c12fb8d7fe8ca1f3a052"
|
|
43
43
|
}
|
package/src/AI.ts
CHANGED
|
@@ -11,19 +11,28 @@ import { langEvent } from '@cloudbase/utilities'
|
|
|
11
11
|
const { MODELS } = models
|
|
12
12
|
|
|
13
13
|
class AI {
|
|
14
|
-
public aiBaseUrl: string
|
|
15
|
-
public aiBotBaseUrl: string
|
|
16
14
|
public bot: Bot
|
|
17
15
|
public i18n: ICloudbaseConfig['i18n']
|
|
18
16
|
defaultHeaders: { [x: string]: any }
|
|
17
|
+
private _getBaseUrl?: () => string
|
|
18
|
+
|
|
19
|
+
/** 动态获取 aiBaseUrl,支持 registerEndPointWithKey 后端点变更生效 */
|
|
20
|
+
get aiBaseUrl(): string {
|
|
21
|
+
return `${this._getBaseUrl ? this._getBaseUrl() : this.baseUrl}/ai`
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** 动态获取 aiBotBaseUrl,支持 registerEndPointWithKey 后端点变更生效 */
|
|
25
|
+
get aiBotBaseUrl(): string {
|
|
26
|
+
return `${this._getBaseUrl ? this._getBaseUrl() : this.baseUrl}/aibot`
|
|
27
|
+
}
|
|
19
28
|
|
|
20
29
|
constructor(
|
|
21
30
|
private req: SDKRequestInterface,
|
|
22
31
|
public baseUrl: string,
|
|
23
32
|
i18n: ICloudbaseConfig['i18n'],
|
|
33
|
+
getBaseUrl?: () => string,
|
|
24
34
|
) {
|
|
25
|
-
this.
|
|
26
|
-
this.aiBotBaseUrl = `${baseUrl}/aibot`
|
|
35
|
+
this._getBaseUrl = getBaseUrl
|
|
27
36
|
this.bot = new Bot(this.botRequest, this.aiBotBaseUrl)
|
|
28
37
|
this.i18n = i18n
|
|
29
38
|
|
|
@@ -35,25 +44,42 @@ class AI {
|
|
|
35
44
|
async handleResponseData(responseData: Promise<unknown> | ReadableStream<Uint8Array>, header?: Headers) {
|
|
36
45
|
const GO_TO_AI_TEXT = `${this.i18n.t('请检查调用方式,或前往云开发 AI+ 首页查看文档')}:https://tcb.cloud.tencent.com/dev#/ai`
|
|
37
46
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
throw new Error(`${this.i18n.t('AI+ 请求出错,错误码')}:${json.code},${this.i18n.t('错误信息')}:${
|
|
43
|
-
json.message
|
|
47
|
+
const throwIfError = (json: unknown) => {
|
|
48
|
+
if (typeof json === 'object' && json && 'code' in json && (json as any).code !== 'NORMAL') {
|
|
49
|
+
throw new Error(`${this.i18n.t('AI+ 请求出错,错误码')}:${(json as any).code},${this.i18n.t('错误信息')}:${
|
|
50
|
+
(json as any).message
|
|
44
51
|
}\n${GO_TO_AI_TEXT}\n${JSON.stringify(json, null, 2)}`,)
|
|
45
52
|
}
|
|
53
|
+
}
|
|
46
54
|
|
|
55
|
+
// 非流式请求:
|
|
56
|
+
// - 小程序/Web 适配器返回 Promise(has 'then')
|
|
57
|
+
// - Node 适配器已将 body 解析为普通对象(无 'then'、无 getReader)
|
|
58
|
+
// 两种情况都按 JSON 校验错误码后原样返回
|
|
59
|
+
if (typeof responseData === 'object' && responseData && typeof (responseData as any).getReader !== 'function') {
|
|
60
|
+
const json = 'then' in responseData ? await responseData : responseData
|
|
61
|
+
throwIfError(json)
|
|
47
62
|
return responseData
|
|
48
63
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
64
|
+
|
|
65
|
+
// 判断 responseData 是否是 ReadableStream 实例(兼容 Node.js 适配器非流式场景已解析为 JSON 对象的情况)
|
|
66
|
+
const isStream = typeof (responseData as any)?.getReader === 'function'
|
|
67
|
+
|
|
68
|
+
if (!isStream) {
|
|
69
|
+
// responseData 已经是解析后的 JSON 对象(如 Node.js 适配器非流式返回),直接检查错误码
|
|
70
|
+
const json = responseData as unknown as Record<string, unknown>
|
|
52
71
|
if (typeof json === 'object' && json && 'code' in json && json.code !== 'NORMAL') {
|
|
53
72
|
throw new Error(`${this.i18n.t('AI+ 请求出错,错误码')}:${json.code},${this.i18n.t('错误信息')}:${
|
|
54
73
|
json.message
|
|
55
74
|
}\n${GO_TO_AI_TEXT}\n${JSON.stringify(json, null, 2)}`,)
|
|
56
75
|
}
|
|
76
|
+
return responseData
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// 流式请求,如果接口出错,会变成传 json 格式的响应,通过 header 判断格式
|
|
80
|
+
if (header?.get?.('content-type')?.includes('application/json')) {
|
|
81
|
+
const json = await readableStream2JsonObject(responseData as ReadableStream<Uint8Array>)
|
|
82
|
+
throwIfError(json)
|
|
57
83
|
}
|
|
58
84
|
return responseData
|
|
59
85
|
}
|
|
@@ -102,7 +128,7 @@ class AI {
|
|
|
102
128
|
method: 'post',
|
|
103
129
|
headers: { [this.i18n?.LANG_HEADER_KEY]: this.i18n?.lang, ...fetchHeaders, ...headers },
|
|
104
130
|
body: JSON.stringify(data),
|
|
105
|
-
url,
|
|
131
|
+
url: this.resolveUrl(url),
|
|
106
132
|
stream,
|
|
107
133
|
timeout,
|
|
108
134
|
})) as { data: Promise<unknown> | ReadableStream<Uint8Array>; header?: Headers }
|
|
@@ -111,8 +137,9 @@ class AI {
|
|
|
111
137
|
}
|
|
112
138
|
|
|
113
139
|
botRequest: types.BotReq = async ({ method, url, data = {}, headers, stream, timeout }) => {
|
|
140
|
+
const resolvedUrl = this.resolveUrl(url)
|
|
114
141
|
if (method === 'get') {
|
|
115
|
-
return this.handleResponseData((await this.req.fetch({ url: `${
|
|
142
|
+
return this.handleResponseData((await this.req.fetch({ url: `${resolvedUrl}?${objectToParam(data)}`, method, headers, stream, timeout })).data,)
|
|
116
143
|
}
|
|
117
144
|
|
|
118
145
|
const fetchHeaders = {
|
|
@@ -122,7 +149,7 @@ class AI {
|
|
|
122
149
|
stream && Object.assign(fetchHeaders, { Accept: 'text/event-stream' })
|
|
123
150
|
|
|
124
151
|
const { data: responseData, header } = (await this.req.fetch({
|
|
125
|
-
url,
|
|
152
|
+
url: resolvedUrl,
|
|
126
153
|
body: JSON.stringify(data),
|
|
127
154
|
headers: {
|
|
128
155
|
[this.i18n?.LANG_HEADER_KEY]: this.i18n?.lang,
|
|
@@ -149,6 +176,16 @@ class AI {
|
|
|
149
176
|
}
|
|
150
177
|
models.toolMap.set(functionTool.name, functionTool.fn)
|
|
151
178
|
}
|
|
179
|
+
|
|
180
|
+
/** 动态替换 URL 中的 origin 部分,支持 registerEndPointWithKey 后生效 */
|
|
181
|
+
private resolveUrl(url: string): string {
|
|
182
|
+
if (!this._getBaseUrl) return url
|
|
183
|
+
const currentBase = this._getBaseUrl()
|
|
184
|
+
if (currentBase !== this.baseUrl && url.startsWith(this.baseUrl)) {
|
|
185
|
+
return url.replace(this.baseUrl, currentBase)
|
|
186
|
+
}
|
|
187
|
+
return url
|
|
188
|
+
}
|
|
152
189
|
}
|
|
153
190
|
|
|
154
191
|
export { AI }
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 参数校验错误类
|
|
3
|
+
* 用于统一参数校验错误的格式
|
|
4
|
+
*/
|
|
5
|
+
export class InvalidParamsError extends Error {
|
|
6
|
+
public code: string
|
|
7
|
+
public field?: string
|
|
8
|
+
|
|
9
|
+
constructor(message: string, field?: string) {
|
|
10
|
+
super(message)
|
|
11
|
+
this.name = 'InvalidParamsError'
|
|
12
|
+
this.code = 'INVALID_PARAMS'
|
|
13
|
+
this.field = field
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
toJSON() {
|
|
17
|
+
return {
|
|
18
|
+
code: this.code,
|
|
19
|
+
message: this.message,
|
|
20
|
+
field: this.field,
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -58,6 +58,8 @@ interface AIInitOption {
|
|
|
58
58
|
interface ICreateAI {
|
|
59
59
|
req: SDKRequestInterface
|
|
60
60
|
baseUrl?: string
|
|
61
|
+
/** 动态获取 baseUrl 的函数,若提供则优先使用,支持端点变更后请求自动跟随 */
|
|
62
|
+
getBaseUrl?: () => string
|
|
61
63
|
env?: string
|
|
62
64
|
getAccessToken?: () => Promise<{ accessToken: string }>
|
|
63
65
|
handleReqInstance?: HandleRequestInstanceFunc
|
|
@@ -74,8 +76,11 @@ interface ICreateAI {
|
|
|
74
76
|
*
|
|
75
77
|
* 其他参数可按需传入覆盖函数逻辑。
|
|
76
78
|
*/
|
|
77
|
-
function createAI({ env, baseUrl, req, getAccessToken, handleReqInstance, i18n }: ICreateAI) {
|
|
79
|
+
function createAI({ env, baseUrl, getBaseUrl: getBaseUrlFunc, req, getAccessToken, handleReqInstance, i18n }: ICreateAI) {
|
|
78
80
|
const getBaseUrl = () => {
|
|
81
|
+
if (getBaseUrlFunc != null) {
|
|
82
|
+
return getBaseUrlFunc()
|
|
83
|
+
}
|
|
79
84
|
if (baseUrl != null) {
|
|
80
85
|
return baseUrl
|
|
81
86
|
}
|
|
@@ -95,7 +100,7 @@ function createAI({ env, baseUrl, req, getAccessToken, handleReqInstance, i18n }
|
|
|
95
100
|
return handleReqInstance({ req })
|
|
96
101
|
}
|
|
97
102
|
|
|
98
|
-
return new AI(getReq(), getBaseUrl(), i18n)
|
|
103
|
+
return new AI(getReq(), getBaseUrl(), i18n, getBaseUrlFunc)
|
|
99
104
|
}
|
|
100
105
|
|
|
101
106
|
// 兼容
|
|
@@ -130,9 +135,12 @@ function ai(
|
|
|
130
135
|
return `${PROTOCOL}${BASE_URL}`
|
|
131
136
|
}
|
|
132
137
|
|
|
133
|
-
|
|
138
|
+
// 若用户传了静态 baseUrl 则使用静态值,否则传入动态获取函数支持端点变更后生效
|
|
139
|
+
if (options?.baseUrl) {
|
|
140
|
+
return createAI({ req, baseUrl: options.baseUrl, handleReqInstance: ({ req }) => req, i18n: this.config.i18n })
|
|
141
|
+
}
|
|
134
142
|
|
|
135
|
-
return createAI({ req, baseUrl, handleReqInstance: ({ req }) => req, i18n: this.config.i18n })
|
|
143
|
+
return createAI({ req, baseUrl: getUrlFromCloud(), getBaseUrl: getUrlFromCloud, handleReqInstance: ({ req }) => req, i18n: this.config.i18n })
|
|
136
144
|
}
|
|
137
145
|
|
|
138
146
|
const component: ICloudbaseComponent = {
|
|
@@ -150,6 +158,7 @@ function registerAi(app: ICloudbase) {
|
|
|
150
158
|
|
|
151
159
|
export { AI, Bot, createAi, createAI, restModels as models, registerAi, utils }
|
|
152
160
|
export * from './type'
|
|
161
|
+
export * from './errors'
|
|
153
162
|
|
|
154
163
|
try {
|
|
155
164
|
(window as any).registerAi = registerAi
|
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
// HunyuanEditImageInput,
|
|
9
9
|
// HunyuanEditImageOutput,
|
|
10
10
|
} from '../type'
|
|
11
|
+
import { InvalidParamsError } from '../errors'
|
|
11
12
|
|
|
12
13
|
interface HunyuanImageGenerateFn {
|
|
13
14
|
(input: HunyuanARGenerateImageInput): Promise<HunyuanARGenerateImageOutput>
|
|
@@ -19,28 +20,53 @@ type GenerateImageFn<TProvider> = TProvider extends 'hunyuan-image'
|
|
|
19
20
|
: (input: unknown) => Promise<unknown>
|
|
20
21
|
|
|
21
22
|
export class DefaultImageModel<TProvider extends string> {
|
|
22
|
-
public defaultGenerateImageSubUrl = 'images/generations'
|
|
23
|
+
public defaultGenerateImageSubUrl = 'images/ar/generations'
|
|
23
24
|
|
|
24
|
-
public generateImageSubUrlConfig: Record<string,
|
|
25
|
-
'hunyuan-image':
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
},
|
|
25
|
+
public generateImageSubUrlConfig: Record<string, Array<[RegExp, string]>> = {
|
|
26
|
+
'hunyuan-image': [
|
|
27
|
+
[/^hunyuan-image(-v[12](\..*)?)?$/, 'images/generations'],
|
|
28
|
+
],
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/** 生成图片 */
|
|
32
32
|
public generateImage: GenerateImageFn<TProvider>
|
|
33
33
|
|
|
34
|
-
constructor(
|
|
34
|
+
constructor(
|
|
35
|
+
private req: ModelReq,
|
|
36
|
+
public baseUrl: string,
|
|
37
|
+
public provider: TProvider,
|
|
38
|
+
) {
|
|
35
39
|
this.generateImage = this.generateImageImpl.bind(this) as GenerateImageFn<TProvider>
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
/** generateImage 的实际实现 */
|
|
39
43
|
private async generateImageImpl(input: HunyuanARGenerateImageInput | HunyuanGenerateImageInput,): Promise<HunyuanARGenerateImageOutput | HunyuanGenerateImageOutput> {
|
|
44
|
+
// 当模型为 HY-Image-v3.0-I2I-ToB-v1.0.1 且 provider 为空或为 hunyuan-image 时校验参数
|
|
45
|
+
if (
|
|
46
|
+
typeof input === 'object' && input && 'model' in input && input.model === 'HY-Image-v3.0-I2I-ToB-v1.0.1' && (this.provider === '' || this.provider === 'hunyuan-image')
|
|
47
|
+
) {
|
|
48
|
+
const typedInput = input
|
|
49
|
+
const imageUrls = typedInput.image_urls as string[] | undefined
|
|
50
|
+
const images = typedInput.images as string[] | undefined
|
|
51
|
+
|
|
52
|
+
if (imageUrls && imageUrls.length > 1) {
|
|
53
|
+
throw new InvalidParamsError(
|
|
54
|
+
'当模型为 HY-Image-v3.0-I2I-ToB-v1.0.1 时,image_urls 最多只能有 1 个元素',
|
|
55
|
+
'image_urls',
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
if (images && images.length > 1) {
|
|
59
|
+
throw new InvalidParamsError(
|
|
60
|
+
'当模型为 HY-Image-v3.0-I2I-ToB-v1.0.1 时,images 最多只能有 1 个元素',
|
|
61
|
+
'images',
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
40
66
|
let subUrl = this.defaultGenerateImageSubUrl
|
|
41
67
|
|
|
42
68
|
if (typeof input === 'object' && input && 'model' in input && typeof input.model === 'string') {
|
|
43
|
-
const newSubUrl = this.
|
|
69
|
+
const newSubUrl = this.getGenerateImageSubUrl(this.provider, input.model)
|
|
44
70
|
if (newSubUrl) subUrl = newSubUrl
|
|
45
71
|
}
|
|
46
72
|
|
|
@@ -56,4 +82,19 @@ export class DefaultImageModel<TProvider extends string> {
|
|
|
56
82
|
private getGenerateUrl(subUrl: string) {
|
|
57
83
|
return `${this.baseUrl}/${this.provider}/${subUrl}`
|
|
58
84
|
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 根据 provider 与 model 解析生成图片的子路径。
|
|
88
|
+
* 按配置顺序用 RegExp 匹配,命中即返回对应 subUrl。
|
|
89
|
+
*/
|
|
90
|
+
private getGenerateImageSubUrl(provider: string, model: string): string | undefined {
|
|
91
|
+
const rules = this.generateImageSubUrlConfig[provider]
|
|
92
|
+
if (!rules) return undefined
|
|
93
|
+
|
|
94
|
+
for (const [pattern, subUrl] of rules) {
|
|
95
|
+
if (pattern.test(model)) return subUrl
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return undefined
|
|
99
|
+
}
|
|
59
100
|
}
|
package/src/type.ts
CHANGED
|
@@ -231,12 +231,17 @@ export interface HunyuanGenerateImageInput {
|
|
|
231
231
|
|
|
232
232
|
export interface HunyuanARGenerateImageInput {
|
|
233
233
|
/** 模型名称:hunyuan-image-v3.0-v1.0.4(推荐)或 hunyuan-image-v3.0-v1.0.1 */
|
|
234
|
-
model:
|
|
234
|
+
model:
|
|
235
|
+
| 'HY-Image-3.0-Plus-4090-Tob-v1.0'
|
|
236
|
+
| 'HY-Image-v3.0-I2I-ToB-v1.0.1'
|
|
237
|
+
| 'hunyuan-image-v3.0-v1.0.4'
|
|
238
|
+
| 'hunyuan-image-v3.0-v1.0.1'
|
|
239
|
+
| 'hunyuan-image-v3.0-v1.0.5'
|
|
235
240
|
/** 生成图片使用的文本,不超过 8192 字符 */
|
|
236
241
|
prompt: string
|
|
237
242
|
/**
|
|
238
243
|
* 图片尺寸,格式 "${宽}x${高}",默认 "1024x1024"
|
|
239
|
-
* hunyuan-image-v3.0-v1.0.4:宽高 [512, 2048],面积不超过 1024x1024
|
|
244
|
+
* HY-Image-3.0-Plus-4090-Tob-v1.0 hunyuan-image-v3.0-v1.0.4:宽高 [512, 2048],面积不超过 1024x1024
|
|
240
245
|
* hunyuan-image-v3.0-v1.0.1:支持固定尺寸列表
|
|
241
246
|
*/
|
|
242
247
|
size?: string
|
|
@@ -248,6 +253,14 @@ export interface HunyuanARGenerateImageInput {
|
|
|
248
253
|
revise?: { value: boolean }
|
|
249
254
|
/** 改写是否开启 thinking 模式,默认开启。开启后效果提升但耗时增加(最大 60s) */
|
|
250
255
|
enable_thinking?: { value: boolean }
|
|
256
|
+
/**
|
|
257
|
+
* 垫图url列表,与image二选一,优先选image,大小不超过10MB,支持 jpg jpeg png 格式,最多3张图,image_urls和images必有一个非空
|
|
258
|
+
*/
|
|
259
|
+
image_urls?: string[]
|
|
260
|
+
/**
|
|
261
|
+
* 垫图base64列表,与image_url二选一,优先选image,大小不超过10MB,支持 jpg jpeg png 格式,最多3张图
|
|
262
|
+
*/
|
|
263
|
+
images?: string[]
|
|
251
264
|
}
|
|
252
265
|
|
|
253
266
|
export interface HunyuanARGenerateImageOutput {
|
package/src/utils.ts
CHANGED
|
@@ -10,7 +10,15 @@ import type {
|
|
|
10
10
|
} from './type'
|
|
11
11
|
import { TextDecoder } from 'text-encoding-shim'
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* 检测当前环境是否原生支持完整的 Web Streams API(Node.js >= 18 或现代浏览器)
|
|
15
|
+
* 如果原生支持,则无需使用 polyfill,避免 web-streams-adapter 在高版本 Node.js 中的兼容问题
|
|
16
|
+
*/
|
|
17
|
+
const hasNativeStreams = typeof globalThis.ReadableStream === 'function'
|
|
18
|
+
&& typeof globalThis.TransformStream === 'function'
|
|
19
|
+
&& typeof globalThis.ReadableStream.prototype.pipeThrough === 'function'
|
|
20
|
+
|
|
21
|
+
export const ReadableStream = (hasNativeStreams ? globalThis.ReadableStream : _ReadableStream) as {
|
|
14
22
|
prototype: ReadableStream
|
|
15
23
|
|
|
16
24
|
new (
|
|
@@ -23,7 +31,7 @@ export const ReadableStream = _ReadableStream as {
|
|
|
23
31
|
new <R = any>(underlyingSource?: UnderlyingSource<R>, strategy?: QueuingStrategy<R>): ReadableStream<R>
|
|
24
32
|
}
|
|
25
33
|
|
|
26
|
-
export const TransformStream = _TransformStream as {
|
|
34
|
+
export const TransformStream = (hasNativeStreams ? globalThis.TransformStream : _TransformStream) as {
|
|
27
35
|
prototype: TransformStream
|
|
28
36
|
|
|
29
37
|
new <I = any, O = any>(
|
|
@@ -50,7 +58,14 @@ export const createEventSourceParserTransformStream = () => {
|
|
|
50
58
|
})
|
|
51
59
|
}
|
|
52
60
|
|
|
53
|
-
|
|
61
|
+
/**
|
|
62
|
+
* 将任意 ReadableStream 转换为当前环境使用的 ReadableStream 实现
|
|
63
|
+
* - 在原生支持 Web Streams 的环境(Node.js >= 18、现代浏览器)中,直接返回原始 stream(无需转换)
|
|
64
|
+
* - 在不支持原生 Web Streams 的环境(旧浏览器、小程序)中,使用 web-streams-adapter 进行转换
|
|
65
|
+
*/
|
|
66
|
+
export const toPolyfillReadable: (readable: any) => any = hasNativeStreams
|
|
67
|
+
? readable => readable
|
|
68
|
+
: createReadableStreamWrapper(ReadableStream)
|
|
54
69
|
|
|
55
70
|
export class TextDecoderStream {
|
|
56
71
|
private handle: TextDecoder
|