@tiny-codes/react-easy 1.4.8 → 1.4.10
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/CHANGELOG.md +52 -0
- package/es/hooks/index.d.ts +3 -0
- package/es/hooks/index.js +3 -0
- package/es/hooks/index.js.map +1 -1
- package/es/hooks/useAudioPlayer.d.ts +7 -0
- package/es/hooks/useAudioPlayer.js +13 -0
- package/es/hooks/useAudioPlayer.js.map +1 -0
- package/es/hooks/useSSE.d.ts +26 -0
- package/es/hooks/useSSE.js +147 -0
- package/es/hooks/useSSE.js.map +1 -0
- package/es/hooks/useUserMedia.d.ts +11 -4
- package/es/hooks/useUserMedia.js +10 -8
- package/es/hooks/useUserMedia.js.map +1 -1
- package/es/utils/AudioPlayer.d.ts +166 -0
- package/es/utils/AudioPlayer.js +457 -0
- package/es/utils/AudioPlayer.js.map +1 -0
- package/es/utils/base64.d.ts +48 -0
- package/es/utils/base64.js +139 -0
- package/es/utils/base64.js.map +1 -0
- package/es/utils/crypto.d.ts +0 -30
- package/es/utils/crypto.js +8 -93
- package/es/utils/crypto.js.map +1 -1
- package/es/utils/index.d.ts +5 -1
- package/es/utils/index.js +5 -1
- package/es/utils/index.js.map +1 -1
- package/es/utils/stream.d.ts +17 -10
- package/es/utils/stream.js +13 -5
- package/es/utils/stream.js.map +1 -1
- package/lib/hooks/index.d.ts +3 -0
- package/lib/hooks/index.js +8 -0
- package/lib/hooks/index.js.map +2 -2
- package/lib/hooks/useAudioPlayer.d.ts +7 -0
- package/lib/hooks/useAudioPlayer.js +42 -0
- package/lib/hooks/useAudioPlayer.js.map +7 -0
- package/lib/hooks/useSSE.d.ts +26 -0
- package/lib/hooks/useSSE.js +128 -0
- package/lib/hooks/useSSE.js.map +7 -0
- package/lib/hooks/useUserMedia.d.ts +11 -4
- package/lib/hooks/useUserMedia.js +9 -7
- package/lib/hooks/useUserMedia.js.map +2 -2
- package/lib/utils/AudioPlayer.d.ts +166 -0
- package/lib/utils/AudioPlayer.js +305 -0
- package/lib/utils/AudioPlayer.js.map +7 -0
- package/lib/utils/base64.d.ts +48 -0
- package/lib/utils/base64.js +120 -0
- package/lib/utils/base64.js.map +7 -0
- package/lib/utils/crypto.d.ts +0 -30
- package/lib/utils/crypto.js +7 -66
- package/lib/utils/crypto.js.map +2 -2
- package/lib/utils/index.d.ts +5 -1
- package/lib/utils/index.js +28 -3
- package/lib/utils/index.js.map +2 -2
- package/lib/utils/stream.d.ts +17 -10
- package/lib/utils/stream.js +9 -4
- package/lib/utils/stream.js.map +2 -2
- package/package.json +2 -1
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/utils/AudioPlayer.ts"],
|
|
4
|
+
"sourcesContent": ["export type AudioSource = string | ReadableStreamDefaultReader<Uint8Array> | ArrayBuffer | Uint8Array | Blob;\n\nexport interface AudioPlayerInit {\n /**\n * - **EN:** Audio source (URL or streaming data)\n * - **CN:** 音频源(URL或流数据)\n */\n source?: AudioSource | (() => AudioSource | Promise<AudioSource>);\n /**\n * - **EN:** Initial volume level (0-1). Default is `0.5`\n * - **CN:** 初始音量级别(0-1)。默认值为`0.5`\n */\n volume?: number;\n /**\n * - **EN:** Callback when audio starts playing\n * - **CN:** 音频开始播放时的回调\n */\n onPlay?: () => void;\n /**\n * - **EN:** Callback when audio is paused\n * - **CN:** 音频暂停时的回调\n */\n onPause?: () => void;\n /**\n * - **EN:** Callback when audio is stopped\n * - **CN:** 音频停止时的回调\n */\n onStop?: () => void;\n\n /**\n * - **EN:** Callback when audio playback ends\n * - **CN:** 音频播放结束时的回调\n */\n onPlayEnd?: () => void;\n /**\n * - **EN:** Callback when an error occurs\n * - **CN:** 发生错误时的回调\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n onError?: (error: any) => void;\n}\n\n/**\n * - **EN:** An audio player class that supports URL or streaming data input\n * - **CN:** 一个音频播放器类,支持URL或流数据输入\n */\nclass AudioPlayer {\n private audio: HTMLAudioElement;\n private _volume: number;\n private audioContext: AudioContext | null = null;\n private gainNode: GainNode | null = null;\n private sourceNode: MediaElementAudioSourceNode | null = null;\n private options: AudioPlayerInit | undefined;\n private onPlayEnd: () => void;\n\n /**\n * - **EN:** Creates an audio player instance\n * - **CN:** 创建音频播放器实例\n *\n * @param source - can be a URL string or ReadableStreamDefaultReader |\n * 可以是URL字符串或ReadableStreamDefaultReader\n */\n constructor(options?: AudioPlayerInit) {\n const { source, volume } = options || {};\n this.options = options;\n this.audio = new Audio();\n this._volume = volume != null ? Math.min(1.0, Math.max(0, volume)) : 0.5; // Default volume 50%\n this.audio.volume = this._volume;\n if (typeof source === 'function') {\n const result = source();\n if (typeof result === 'object' && 'then' in result && typeof result.then === 'function') {\n result.then((data) => this.setAudioSource(data));\n } else {\n this.setAudioSource(result as AudioSource);\n }\n } else {\n this.setAudioSource(source);\n }\n this.onPlayEnd = () => {\n this.options?.onPlayEnd?.();\n };\n this.addEventListener('ended', this.onPlayEnd);\n }\n\n /**\n * - **EN:** Check if audio is currently playing\n * - **CN:** 检查音频是否正在播放\n */\n public get isPlaying() {\n return this.audioContext?.state === 'running';\n }\n /**\n * - **EN:** Get current playback time (seconds)\n * - **CN:** 获取当前播放时间(秒)\n */\n get currentTime(): number {\n return this.audio.currentTime;\n }\n /**\n * - **EN:** Get total audio duration (seconds)\n * - **CN:** 获取音频总时长(秒)\n */\n get duration(): number {\n return this.audio.duration;\n }\n /**\n * - **EN:** Get current volume value (0-1)\n * - **CN:** 获取当前音量值(0-1)\n */\n get volume(): number {\n return this._volume;\n }\n\n /**\n * - **EN:** Play audio. If previously paused, will resume from the pause position\n * - **CN:** 播放音频 如果之前暂停过,将从暂停位置继续播放\n */\n async play(): Promise<void> {\n if (!this.audioContext) {\n this.initAudioContext();\n }\n\n if (this.audioContext?.state === 'suspended') {\n await this.audioContext.resume();\n }\n\n try {\n await this.audio.play();\n this.options?.onPlay?.();\n } catch (error) {\n console.error('Error playing audio:', error);\n this.options?.onError?.(error);\n }\n }\n\n /**\n * - **EN:** Seek forward by a certain number of seconds\n * - **CN:** 向前跳转一定秒数\n *\n * @param seconds - number of seconds to seek forward | 要向前跳转的秒数\n */\n seekForward(seconds: number) {\n if (seconds < 0) {\n return;\n }\n if (!isNaN(this.audio.duration)) {\n this.audio.currentTime = Math.min(this.audio.currentTime + seconds, this.audio.duration);\n } else {\n this.audio.currentTime += seconds;\n }\n }\n /**\n * - **EN:** Seek backward by a certain number of seconds\n * - **CN:** 向后跳转一定秒数\n *\n * @param seconds - number of seconds to seek backward | 要向后跳转的秒数\n */\n seekBackward(seconds: number) {\n if (seconds < 0) {\n return;\n }\n this.audio.currentTime = Math.max(this.audio.currentTime - seconds, 0);\n }\n /**\n * - **EN:** Set current playback time (in seconds)\n * - **CN:** 设置当前播放时间(以秒为单位)\n *\n * @param time - time in seconds | 时间(秒)\n */\n seek(time: number) {\n // Ensure time is not less than 0\n const newTime = Math.max(0, time);\n // Ensure time is not greater than duration (if known)\n if (!isNaN(this.audio.duration)) {\n this.audio.currentTime = Math.min(newTime, this.audio.duration);\n } else {\n this.audio.currentTime = newTime;\n }\n }\n\n /**\n * - **EN:** Pause audio playback. When played again, will continue from current position\n * - **CN:** 暂停音频播放 再次播放时将从当前位置继续\n */\n pause(): void {\n this.audio.pause();\n this.options?.onPause?.();\n }\n\n /**\n * - **EN:** Stop audio playback. Progress will reset to the beginning\n * - **CN:** 停止音频播放 进度会重置到开始位置\n */\n stop(): void {\n this.audio.pause();\n this.audio.currentTime = 0;\n this.options?.onStop?.();\n }\n\n /**\n * - **EN:** Update audio source\n * - **CN:** 更新音频源\n *\n * @param source - can be a URL `string` or `ReadableStreamDefaultReader` |\n * 可以是URL字符串或`ReadableStreamDefaultReader`\n */\n async setAudioSource(source?: AudioSource) {\n this.audio.pause();\n this.audio.src = '';\n\n if (typeof source === 'string') {\n this.audio.src = source;\n } else {\n await this.handleStreamSource(source);\n }\n }\n\n /**\n * - **EN:** Increase volume (by 10% each time)\n * - **CN:** 增加音量(每次增加10%)\n *\n * @param percent - increase percentage (default 10%) | 增加百分比(默认10%)\n */\n volumeUp(percent = 0.1): void {\n this._volume = Math.min(1.0, this._volume + percent);\n this.updateVolume();\n }\n\n /**\n * - **EN:** Decrease volume (by 10% each time)\n * - **CN:** 降低音量(每次降低10%)\n *\n * @param percent - decrease percentage (default 10%) | 降低百分比(默认10%)\n */\n volumeDown(percent = 0.1): void {\n this._volume = Math.max(0, this._volume - percent);\n this.updateVolume();\n }\n\n /**\n * - **EN:** Set volume to a specific value (0-1)\n * - **CN:** 将音量设置为特定值(0-1)\n *\n * @param value - new volume value (0-1) | 新的音量值(0-1)\n */\n setVolume(value: number): void {\n this._volume = Math.min(1.0, Math.max(0, value));\n this.updateVolume();\n }\n\n /**\n * - **EN:** Add audio event listener\n * - **CN:** 添加音频事件监听器\n */\n addEventListener: HTMLAudioElement['addEventListener'] = (\n event: string,\n listener: EventListenerOrEventListenerObject\n ): void => {\n this.audio.addEventListener(event, listener);\n };\n\n /**\n * - **EN:** Remove audio event listener\n * - **CN:** 移除音频事件监听器\n */\n removeEventListener: HTMLAudioElement['removeEventListener'] = (\n event: string,\n listener: EventListenerOrEventListenerObject\n ): void => {\n this.audio.removeEventListener(event, listener);\n };\n\n /**\n * - **EN:** Release resources\n * - **CN:** 释放资源\n */\n dispose(): void {\n this.audio.pause();\n this.audio.src = '';\n this.removeEventListener('ended', this.onPlayEnd);\n\n if (this.audioContext) {\n try {\n this.audioContext.close();\n } catch (error) {\n console.error('Error closing AudioContext:', error);\n }\n this.audioContext = null;\n }\n\n this.sourceNode = null;\n this.gainNode = null;\n }\n\n /** Process streaming data source */\n private async handleStreamSource(source: Exclude<AudioSource, string> | undefined) {\n if (!source) return;\n try {\n let blob: Blob;\n if (source instanceof Blob) {\n blob = source;\n } else if (source instanceof ArrayBuffer || source instanceof Uint8Array) {\n blob = new Blob([source]);\n } else {\n // Create a new ReadableStream to read data from the reader\n const stream = new ReadableStream({\n async pull(controller) {\n try {\n const { done, value } = await source.read();\n if (done) {\n controller.close();\n } else {\n controller.enqueue(value);\n }\n } catch (err) {\n controller.error(err);\n }\n },\n });\n // Convert stream to Blob and create URL\n const response = new Response(stream);\n blob = await response.blob();\n }\n\n const url = URL.createObjectURL(blob);\n\n this.audio.src = url;\n\n // Release Blob URL after audio loads\n this.audio.onload = () => {\n URL.revokeObjectURL(url);\n };\n } catch (error) {\n console.error('Error processing audio stream:', error);\n }\n }\n\n /** Initialize Web Audio API for better volume control */\n private initAudioContext() {\n if (this.audioContext) return;\n\n this.audioContext = new AudioContext();\n this.sourceNode = this.audioContext.createMediaElementSource(this.audio);\n this.gainNode = this.audioContext.createGain();\n\n this.sourceNode.connect(this.gainNode);\n this.gainNode.connect(this.audioContext.destination);\n\n this.gainNode.gain.value = this._volume;\n }\n\n /** Update audio playback volume */\n private updateVolume(): void {\n if (this.gainNode) {\n this.gainNode.gain.value = this._volume;\n } else {\n this.audio.volume = this._volume;\n }\n }\n}\n\nexport default AudioPlayer;\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA8CA,IAAM,cAAN,MAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBhB,YAAY,SAA2B;AAbvC,SAAQ,eAAoC;AAC5C,SAAQ,WAA4B;AACpC,SAAQ,aAAiD;AA2MzD;AAAA;AAAA;AAAA;AAAA,4BAAyD,CACvD,OACA,aACS;AACT,WAAK,MAAM,iBAAiB,OAAO,QAAQ;AAAA,IAC7C;AAMA;AAAA;AAAA;AAAA;AAAA,+BAA+D,CAC7D,OACA,aACS;AACT,WAAK,MAAM,oBAAoB,OAAO,QAAQ;AAAA,IAChD;AA/ME,UAAM,EAAE,QAAQ,OAAO,IAAI,WAAW,CAAC;AACvC,SAAK,UAAU;AACf,SAAK,QAAQ,IAAI,MAAM;AACvB,SAAK,UAAU,UAAU,OAAO,KAAK,IAAI,GAAK,KAAK,IAAI,GAAG,MAAM,CAAC,IAAI;AACrE,SAAK,MAAM,SAAS,KAAK;AACzB,QAAI,OAAO,WAAW,YAAY;AAChC,YAAM,SAAS,OAAO;AACtB,UAAI,OAAO,WAAW,YAAY,UAAU,UAAU,OAAO,OAAO,SAAS,YAAY;AACvF,eAAO,KAAK,CAAC,SAAS,KAAK,eAAe,IAAI,CAAC;AAAA,MACjD,OAAO;AACL,aAAK,eAAe,MAAqB;AAAA,MAC3C;AAAA,IACF,OAAO;AACL,WAAK,eAAe,MAAM;AAAA,IAC5B;AACA,SAAK,YAAY,MAAM;AA9E3B;AA+EM,uBAAK,YAAL,mBAAc,cAAd;AAAA,IACF;AACA,SAAK,iBAAiB,SAAS,KAAK,SAAS;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAW,YAAY;AAxFzB;AAyFI,aAAO,UAAK,iBAAL,mBAAmB,WAAU;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,cAAsB;AACxB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,WAAmB;AACrB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,SAAiB;AACnB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAsB;AArH9B;AAsHI,QAAI,CAAC,KAAK,cAAc;AACtB,WAAK,iBAAiB;AAAA,IACxB;AAEA,UAAI,UAAK,iBAAL,mBAAmB,WAAU,aAAa;AAC5C,YAAM,KAAK,aAAa,OAAO;AAAA,IACjC;AAEA,QAAI;AACF,YAAM,KAAK,MAAM,KAAK;AACtB,uBAAK,YAAL,mBAAc,WAAd;AAAA,IACF,SAAS,OAAP;AACA,cAAQ,MAAM,wBAAwB,KAAK;AAC3C,uBAAK,YAAL,mBAAc,YAAd,4BAAwB;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAY,SAAiB;AAC3B,QAAI,UAAU,GAAG;AACf;AAAA,IACF;AACA,QAAI,CAAC,MAAM,KAAK,MAAM,QAAQ,GAAG;AAC/B,WAAK,MAAM,cAAc,KAAK,IAAI,KAAK,MAAM,cAAc,SAAS,KAAK,MAAM,QAAQ;AAAA,IACzF,OAAO;AACL,WAAK,MAAM,eAAe;AAAA,IAC5B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAa,SAAiB;AAC5B,QAAI,UAAU,GAAG;AACf;AAAA,IACF;AACA,SAAK,MAAM,cAAc,KAAK,IAAI,KAAK,MAAM,cAAc,SAAS,CAAC;AAAA,EACvE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,KAAK,MAAc;AAEjB,UAAM,UAAU,KAAK,IAAI,GAAG,IAAI;AAEhC,QAAI,CAAC,MAAM,KAAK,MAAM,QAAQ,GAAG;AAC/B,WAAK,MAAM,cAAc,KAAK,IAAI,SAAS,KAAK,MAAM,QAAQ;AAAA,IAChE,OAAO;AACL,WAAK,MAAM,cAAc;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAc;AAxLhB;AAyLI,SAAK,MAAM,MAAM;AACjB,qBAAK,YAAL,mBAAc,YAAd;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAa;AAjMf;AAkMI,SAAK,MAAM,MAAM;AACjB,SAAK,MAAM,cAAc;AACzB,qBAAK,YAAL,mBAAc,WAAd;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,eAAe,QAAsB;AACzC,SAAK,MAAM,MAAM;AACjB,SAAK,MAAM,MAAM;AAEjB,QAAI,OAAO,WAAW,UAAU;AAC9B,WAAK,MAAM,MAAM;AAAA,IACnB,OAAO;AACL,YAAM,KAAK,mBAAmB,MAAM;AAAA,IACtC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAS,UAAU,KAAW;AAC5B,SAAK,UAAU,KAAK,IAAI,GAAK,KAAK,UAAU,OAAO;AACnD,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW,UAAU,KAAW;AAC9B,SAAK,UAAU,KAAK,IAAI,GAAG,KAAK,UAAU,OAAO;AACjD,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAU,OAAqB;AAC7B,SAAK,UAAU,KAAK,IAAI,GAAK,KAAK,IAAI,GAAG,KAAK,CAAC;AAC/C,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA,EA4BA,UAAgB;AACd,SAAK,MAAM,MAAM;AACjB,SAAK,MAAM,MAAM;AACjB,SAAK,oBAAoB,SAAS,KAAK,SAAS;AAEhD,QAAI,KAAK,cAAc;AACrB,UAAI;AACF,aAAK,aAAa,MAAM;AAAA,MAC1B,SAAS,OAAP;AACA,gBAAQ,MAAM,+BAA+B,KAAK;AAAA,MACpD;AACA,WAAK,eAAe;AAAA,IACtB;AAEA,SAAK,aAAa;AAClB,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA,EAGA,MAAc,mBAAmB,QAAkD;AACjF,QAAI,CAAC;AAAQ;AACb,QAAI;AACF,UAAI;AACJ,UAAI,kBAAkB,MAAM;AAC1B,eAAO;AAAA,MACT,WAAW,kBAAkB,eAAe,kBAAkB,YAAY;AACxE,eAAO,IAAI,KAAK,CAAC,MAAM,CAAC;AAAA,MAC1B,OAAO;AAEL,cAAM,SAAS,IAAI,eAAe;AAAA,UAChC,MAAM,KAAK,YAAY;AACrB,gBAAI;AACF,oBAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,kBAAI,MAAM;AACR,2BAAW,MAAM;AAAA,cACnB,OAAO;AACL,2BAAW,QAAQ,KAAK;AAAA,cAC1B;AAAA,YACF,SAAS,KAAP;AACA,yBAAW,MAAM,GAAG;AAAA,YACtB;AAAA,UACF;AAAA,QACF,CAAC;AAED,cAAM,WAAW,IAAI,SAAS,MAAM;AACpC,eAAO,MAAM,SAAS,KAAK;AAAA,MAC7B;AAEA,YAAM,MAAM,IAAI,gBAAgB,IAAI;AAEpC,WAAK,MAAM,MAAM;AAGjB,WAAK,MAAM,SAAS,MAAM;AACxB,YAAI,gBAAgB,GAAG;AAAA,MACzB;AAAA,IACF,SAAS,OAAP;AACA,cAAQ,MAAM,kCAAkC,KAAK;AAAA,IACvD;AAAA,EACF;AAAA;AAAA,EAGQ,mBAAmB;AACzB,QAAI,KAAK;AAAc;AAEvB,SAAK,eAAe,IAAI,aAAa;AACrC,SAAK,aAAa,KAAK,aAAa,yBAAyB,KAAK,KAAK;AACvE,SAAK,WAAW,KAAK,aAAa,WAAW;AAE7C,SAAK,WAAW,QAAQ,KAAK,QAAQ;AACrC,SAAK,SAAS,QAAQ,KAAK,aAAa,WAAW;AAEnD,SAAK,SAAS,KAAK,QAAQ,KAAK;AAAA,EAClC;AAAA;AAAA,EAGQ,eAAqB;AAC3B,QAAI,KAAK,UAAU;AACjB,WAAK,SAAS,KAAK,QAAQ,KAAK;AAAA,IAClC,OAAO;AACL,WAAK,MAAM,SAAS,KAAK;AAAA,IAC3B;AAAA,EACF;AACF;AAEA,IAAO,sBAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* - **EN:** Encode a UTF-8 string into Base64 (standard or URL-safe).
|
|
3
|
+
* - **CN:** 将 UTF-8 字符串编码为 Base64(标准或 URL 安全格式)。
|
|
4
|
+
*
|
|
5
|
+
* @param content Input text to encode | 要编码的输入文本
|
|
6
|
+
*
|
|
7
|
+
* @returns Base64 encoded string | Base64 编码后的字符串
|
|
8
|
+
*/
|
|
9
|
+
export declare function stringToBase64(content: string, opts?: {
|
|
10
|
+
/**
|
|
11
|
+
* - **EN:** Use URL-safe Base64 if true (replace +/ with -_ and strip =)
|
|
12
|
+
* - **CN:** 为 true 时使用 URL 安全 Base64(将 +/ 替换为 -_ 并去掉 =)
|
|
13
|
+
*/
|
|
14
|
+
urlSafe?: boolean;
|
|
15
|
+
}): string;
|
|
16
|
+
/**
|
|
17
|
+
* - EN: Decode a Base64 (standard or URL-safe) string into UTF-8 text.
|
|
18
|
+
* - CN: 将(标准或 URL 安全)Base64 字符串解码为 UTF-8 文本。
|
|
19
|
+
*
|
|
20
|
+
* @param content Base64 encoded string | Base64 编码字符串
|
|
21
|
+
*
|
|
22
|
+
* @returns Decoded UTF-8 string | 解码后的 UTF-8 字符串
|
|
23
|
+
*/
|
|
24
|
+
export declare function base64ToString(content: string, opts?: {
|
|
25
|
+
/**
|
|
26
|
+
* - **EN:** Use URL-safe Base64 if true (replace +/ with -_ and strip =)
|
|
27
|
+
* - **CN:** 为 true 时使用 URL 安全 Base64(将 +/ 替换为 -_ 并去掉 =)
|
|
28
|
+
*/
|
|
29
|
+
urlSafe?: boolean;
|
|
30
|
+
}): string;
|
|
31
|
+
/**
|
|
32
|
+
* - **EN:** Convert an ArrayBuffer to a Base64 encoded string.
|
|
33
|
+
* - **CN:** 将 ArrayBuffer 转换为 Base64 编码的字符串。
|
|
34
|
+
*
|
|
35
|
+
* @param buf The ArrayBuffer to convert | 要转换的 ArrayBuffer
|
|
36
|
+
*
|
|
37
|
+
* @returns The Base64 encoded string | Base64 编码的字符串
|
|
38
|
+
*/
|
|
39
|
+
export declare function arrayBufferToBase64(buf: ArrayBuffer): string;
|
|
40
|
+
/**
|
|
41
|
+
* - **EN:** Decode a Base64 (standard or URL-safe) string into an ArrayBuffer.
|
|
42
|
+
* - **CN:** 将(标准或 URL 安全)Base64 字符串解码为 ArrayBuffer。
|
|
43
|
+
*
|
|
44
|
+
* @param base64 The Base64 encoded string | Base64 编码的字符串
|
|
45
|
+
*
|
|
46
|
+
* @returns The decoded ArrayBuffer | 解码后的 ArrayBuffer
|
|
47
|
+
*/
|
|
48
|
+
export declare function base64ToArrayBuffer(base64: string): ArrayBuffer;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/utils/base64.ts
|
|
20
|
+
var base64_exports = {};
|
|
21
|
+
__export(base64_exports, {
|
|
22
|
+
arrayBufferToBase64: () => arrayBufferToBase64,
|
|
23
|
+
base64ToArrayBuffer: () => base64ToArrayBuffer,
|
|
24
|
+
base64ToString: () => base64ToString,
|
|
25
|
+
stringToBase64: () => stringToBase64
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(base64_exports);
|
|
28
|
+
function stringToBase64(content, opts = {}) {
|
|
29
|
+
const { urlSafe = false } = opts;
|
|
30
|
+
if (content == null || content === "")
|
|
31
|
+
return "";
|
|
32
|
+
let base64;
|
|
33
|
+
const hasBuffer = typeof Buffer !== "undefined" && typeof Buffer.from === "function";
|
|
34
|
+
if (hasBuffer) {
|
|
35
|
+
base64 = Buffer.from(content, "utf8").toString("base64");
|
|
36
|
+
} else {
|
|
37
|
+
const encoder = new TextEncoder();
|
|
38
|
+
const bytes = encoder.encode(content);
|
|
39
|
+
let binary = "";
|
|
40
|
+
for (const i of bytes) {
|
|
41
|
+
binary += String.fromCharCode(i);
|
|
42
|
+
}
|
|
43
|
+
base64 = btoa(binary);
|
|
44
|
+
}
|
|
45
|
+
if (urlSafe) {
|
|
46
|
+
base64 = base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/u, "");
|
|
47
|
+
}
|
|
48
|
+
return base64;
|
|
49
|
+
}
|
|
50
|
+
function base64ToString(content, opts = {}) {
|
|
51
|
+
const { urlSafe = false } = opts;
|
|
52
|
+
if (content == null || content === "")
|
|
53
|
+
return "";
|
|
54
|
+
let normalized = content;
|
|
55
|
+
if (urlSafe) {
|
|
56
|
+
normalized = normalized.replace(/-/g, "+").replace(/_/g, "/");
|
|
57
|
+
}
|
|
58
|
+
const padNeeded = normalized.length % 4;
|
|
59
|
+
if (padNeeded === 2)
|
|
60
|
+
normalized += "==";
|
|
61
|
+
else if (padNeeded === 3)
|
|
62
|
+
normalized += "=";
|
|
63
|
+
else if (padNeeded === 1) {
|
|
64
|
+
throw new Error("Invalid Base64 string length");
|
|
65
|
+
}
|
|
66
|
+
const hasBuffer = typeof Buffer !== "undefined" && typeof Buffer.from === "function";
|
|
67
|
+
try {
|
|
68
|
+
if (hasBuffer) {
|
|
69
|
+
return Buffer.from(normalized, "base64").toString("utf8");
|
|
70
|
+
} else {
|
|
71
|
+
const binary = atob(normalized);
|
|
72
|
+
const len = binary.length;
|
|
73
|
+
const bytes = new Uint8Array(len);
|
|
74
|
+
for (let i = 0; i < len; i++) {
|
|
75
|
+
bytes[i] = binary.charCodeAt(i);
|
|
76
|
+
}
|
|
77
|
+
const decoder = new TextDecoder();
|
|
78
|
+
return decoder.decode(bytes);
|
|
79
|
+
}
|
|
80
|
+
} catch (e) {
|
|
81
|
+
throw new Error("Failed to decode Base64: " + (e instanceof Error ? e.message : String(e)));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function arrayBufferToBase64(buf) {
|
|
85
|
+
if (typeof Buffer !== "undefined") {
|
|
86
|
+
return Buffer.from(buf).toString("base64");
|
|
87
|
+
}
|
|
88
|
+
const bytes = new Uint8Array(buf);
|
|
89
|
+
const chunk = 32768;
|
|
90
|
+
let binary = "";
|
|
91
|
+
for (let i = 0; i < bytes.length; i += chunk) {
|
|
92
|
+
binary += String.fromCharCode(...bytes.subarray(i, i + chunk));
|
|
93
|
+
}
|
|
94
|
+
let base64 = btoa(binary);
|
|
95
|
+
const padding = (4 - base64.length % 4) % 4;
|
|
96
|
+
if (padding)
|
|
97
|
+
base64 += "=".repeat(padding);
|
|
98
|
+
return base64;
|
|
99
|
+
}
|
|
100
|
+
function base64ToArrayBuffer(base64) {
|
|
101
|
+
if (typeof Buffer !== "undefined") {
|
|
102
|
+
const buffer = Buffer.from(base64, "base64");
|
|
103
|
+
return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
104
|
+
}
|
|
105
|
+
const binaryString = atob(base64);
|
|
106
|
+
const len = binaryString.length;
|
|
107
|
+
const bytes = new Uint8Array(len);
|
|
108
|
+
for (let i = 0; i < len; i++) {
|
|
109
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
110
|
+
}
|
|
111
|
+
return bytes.buffer;
|
|
112
|
+
}
|
|
113
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
114
|
+
0 && (module.exports = {
|
|
115
|
+
arrayBufferToBase64,
|
|
116
|
+
base64ToArrayBuffer,
|
|
117
|
+
base64ToString,
|
|
118
|
+
stringToBase64
|
|
119
|
+
});
|
|
120
|
+
//# sourceMappingURL=base64.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/utils/base64.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * - **EN:** Encode a UTF-8 string into Base64 (standard or URL-safe).\n * - **CN:** 将 UTF-8 字符串编码为 Base64(标准或 URL 安全格式)。\n *\n * @param content Input text to encode | 要编码的输入文本\n *\n * @returns Base64 encoded string | Base64 编码后的字符串\n */\nexport function stringToBase64(\n content: string,\n opts: {\n /**\n * - **EN:** Use URL-safe Base64 if true (replace +/ with -_ and strip =)\n * - **CN:** 为 true 时使用 URL 安全 Base64(将 +/ 替换为 -_ 并去掉 =)\n */\n urlSafe?: boolean;\n } = {}\n): string {\n const { urlSafe = false } = opts;\n if (content == null || content === '') return '';\n\n let base64: string;\n const hasBuffer = typeof Buffer !== 'undefined' && typeof Buffer.from === 'function';\n if (hasBuffer) {\n // Node.js\n base64 = Buffer.from(content, 'utf8').toString('base64');\n } else {\n // Browser\n const encoder = new TextEncoder();\n const bytes = encoder.encode(content);\n let binary = '';\n for (const i of bytes) {\n binary += String.fromCharCode(i);\n }\n base64 = btoa(binary);\n }\n\n if (urlSafe) {\n // Replace chars and strip padding for URL-safe variant\n base64 = base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\n }\n return base64;\n}\n\n/**\n * - EN: Decode a Base64 (standard or URL-safe) string into UTF-8 text.\n * - CN: 将(标准或 URL 安全)Base64 字符串解码为 UTF-8 文本。\n *\n * @param content Base64 encoded string | Base64 编码字符串\n *\n * @returns Decoded UTF-8 string | 解码后的 UTF-8 字符串\n */\nexport function base64ToString(\n content: string,\n opts: {\n /**\n * - **EN:** Use URL-safe Base64 if true (replace +/ with -_ and strip =)\n * - **CN:** 为 true 时使用 URL 安全 Base64(将 +/ 替换为 -_ 并去掉 =)\n */\n urlSafe?: boolean;\n } = {}\n): string {\n const { urlSafe = false } = opts;\n if (content == null || content === '') return '';\n\n let normalized = content;\n if (urlSafe) {\n normalized = normalized.replace(/-/g, '+').replace(/_/g, '/');\n }\n // Restore padding if stripped\n const padNeeded = normalized.length % 4;\n if (padNeeded === 2) normalized += '==';\n else if (padNeeded === 3) normalized += '=';\n else if (padNeeded === 1) {\n throw new Error('Invalid Base64 string length');\n }\n\n const hasBuffer = typeof Buffer !== 'undefined' && typeof Buffer.from === 'function';\n try {\n if (hasBuffer) {\n return Buffer.from(normalized, 'base64').toString('utf8');\n } else {\n const binary = atob(normalized);\n const len = binary.length;\n const bytes = new Uint8Array(len);\n for (let i = 0; i < len; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n const decoder = new TextDecoder();\n return decoder.decode(bytes);\n }\n } catch (e) {\n throw new Error('Failed to decode Base64: ' + (e instanceof Error ? e.message : String(e)));\n }\n}\n\n/**\n * - **EN:** Convert an ArrayBuffer to a Base64 encoded string.\n * - **CN:** 将 ArrayBuffer 转换为 Base64 编码的字符串。\n *\n * @param buf The ArrayBuffer to convert | 要转换的 ArrayBuffer\n *\n * @returns The Base64 encoded string | Base64 编码的字符串\n */\nexport function arrayBufferToBase64(buf: ArrayBuffer): string {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(buf).toString('base64');\n }\n const bytes = new Uint8Array(buf);\n const chunk = 0x8000;\n let binary = '';\n for (let i = 0; i < bytes.length; i += chunk) {\n binary += String.fromCharCode(...bytes.subarray(i, i + chunk));\n }\n let base64 = btoa(binary);\n // Add padding for Base64\n const padding = (4 - (base64.length % 4)) % 4;\n if (padding) base64 += '='.repeat(padding);\n return base64;\n}\n\n/**\n * - **EN:** Decode a Base64 (standard or URL-safe) string into an ArrayBuffer.\n * - **CN:** 将(标准或 URL 安全)Base64 字符串解码为 ArrayBuffer。\n *\n * @param base64 The Base64 encoded string | Base64 编码的字符串\n *\n * @returns The decoded ArrayBuffer | 解码后的 ArrayBuffer\n */\nexport function base64ToArrayBuffer(base64: string): ArrayBuffer {\n if (typeof Buffer !== 'undefined') {\n const buffer = Buffer.from(base64, 'base64');\n return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);\n }\n const binaryString = atob(base64);\n const len = binaryString.length;\n const bytes = new Uint8Array(len);\n for (let i = 0; i < len; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return bytes.buffer;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/lib/utils/crypto.d.ts
CHANGED
|
@@ -24,33 +24,3 @@ export declare function encryptAES(text: string, key: string): Promise<string>;
|
|
|
24
24
|
* @returns The decrypted text
|
|
25
25
|
*/
|
|
26
26
|
export declare function decryptAES(encryptedText: string, key: string): Promise<string>;
|
|
27
|
-
/**
|
|
28
|
-
* - **EN:** Encode a UTF-8 string into Base64 (standard or URL-safe).
|
|
29
|
-
* - **CN:** 将 UTF-8 字符串编码为 Base64(标准或 URL 安全格式)。
|
|
30
|
-
*
|
|
31
|
-
* @param content Input text to encode | 要编码的输入文本
|
|
32
|
-
*
|
|
33
|
-
* @returns Base64 encoded string | Base64 编码后的字符串
|
|
34
|
-
*/
|
|
35
|
-
export declare function toBase64(content: string, opts?: {
|
|
36
|
-
/**
|
|
37
|
-
* - **EN:** Use URL-safe Base64 if true (replace +/ with -_ and strip =)
|
|
38
|
-
* - **CN:** 为 true 时使用 URL 安全 Base64(将 +/ 替换为 -_ 并去掉 =)
|
|
39
|
-
*/
|
|
40
|
-
urlSafe?: boolean;
|
|
41
|
-
}): string;
|
|
42
|
-
/**
|
|
43
|
-
* - EN: Decode a Base64 (standard or URL-safe) string into UTF-8 text.
|
|
44
|
-
* - CN: 将(标准或 URL 安全)Base64 字符串解码为 UTF-8 文本。
|
|
45
|
-
*
|
|
46
|
-
* @param content Base64 encoded string | Base64 编码字符串
|
|
47
|
-
*
|
|
48
|
-
* @returns Decoded UTF-8 string | 解码后的 UTF-8 字符串
|
|
49
|
-
*/
|
|
50
|
-
export declare function fromBase64(content: string, opts?: {
|
|
51
|
-
/**
|
|
52
|
-
* - **EN:** Use URL-safe Base64 if true (replace +/ with -_ and strip =)
|
|
53
|
-
* - **CN:** 为 true 时使用 URL 安全 Base64(将 +/ 替换为 -_ 并去掉 =)
|
|
54
|
-
*/
|
|
55
|
-
urlSafe?: boolean;
|
|
56
|
-
}): string;
|
package/lib/utils/crypto.js
CHANGED
|
@@ -22,29 +22,28 @@ __export(crypto_exports, {
|
|
|
22
22
|
advancedDecrypt: () => advancedDecrypt,
|
|
23
23
|
advancedEncrypt: () => advancedEncrypt,
|
|
24
24
|
decryptAES: () => decryptAES,
|
|
25
|
-
encryptAES: () => encryptAES
|
|
26
|
-
fromBase64: () => fromBase64,
|
|
27
|
-
toBase64: () => toBase64
|
|
25
|
+
encryptAES: () => encryptAES
|
|
28
26
|
});
|
|
29
27
|
module.exports = __toCommonJS(crypto_exports);
|
|
28
|
+
var import_base64 = require("./base64");
|
|
30
29
|
var import_math = require("./math");
|
|
31
30
|
var import_string = require("./string");
|
|
32
31
|
async function advancedEncrypt(plainText, key) {
|
|
33
32
|
const k1 = (0, import_string.randomChars)(36);
|
|
34
33
|
let e = await encryptAES(plainText, k1);
|
|
35
|
-
const b =
|
|
34
|
+
const b = (0, import_base64.stringToBase64)(k1);
|
|
36
35
|
const l = b.length;
|
|
37
36
|
const s = (0, import_math.random)(0, e.length);
|
|
38
37
|
e = e.substring(0, s) + b + e.substring(s);
|
|
39
|
-
const r =
|
|
38
|
+
const r = (0, import_base64.stringToBase64)(`${s}-${l}`);
|
|
40
39
|
const t = `${e}.${r}`;
|
|
41
40
|
return encryptAES(t, key);
|
|
42
41
|
}
|
|
43
42
|
async function advancedDecrypt(encryptedText, key) {
|
|
44
43
|
const decrypted = await decryptAES(encryptedText, key);
|
|
45
44
|
const [e, r] = decrypted.split(".");
|
|
46
|
-
const [s, l] =
|
|
47
|
-
const k1 =
|
|
45
|
+
const [s, l] = (0, import_base64.base64ToString)(r).split("-").map(Number);
|
|
46
|
+
const k1 = (0, import_base64.base64ToString)(e.substring(s, s + l));
|
|
48
47
|
return decryptAES(e.substring(0, s) + e.substring(s + l), k1);
|
|
49
48
|
}
|
|
50
49
|
async function encryptAES(text, key) {
|
|
@@ -107,69 +106,11 @@ async function decryptAES(encryptedText, key) {
|
|
|
107
106
|
return "";
|
|
108
107
|
}
|
|
109
108
|
}
|
|
110
|
-
function toBase64(content, opts = {}) {
|
|
111
|
-
const { urlSafe = false } = opts;
|
|
112
|
-
if (content == null || content === "")
|
|
113
|
-
return "";
|
|
114
|
-
let base64;
|
|
115
|
-
const hasBuffer = typeof Buffer !== "undefined" && typeof Buffer.from === "function";
|
|
116
|
-
if (hasBuffer) {
|
|
117
|
-
base64 = Buffer.from(content, "utf8").toString("base64");
|
|
118
|
-
} else {
|
|
119
|
-
const encoder = new TextEncoder();
|
|
120
|
-
const bytes = encoder.encode(content);
|
|
121
|
-
let binary = "";
|
|
122
|
-
for (const i of bytes) {
|
|
123
|
-
binary += String.fromCharCode(i);
|
|
124
|
-
}
|
|
125
|
-
base64 = btoa(binary);
|
|
126
|
-
}
|
|
127
|
-
if (urlSafe) {
|
|
128
|
-
base64 = base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/u, "");
|
|
129
|
-
}
|
|
130
|
-
return base64;
|
|
131
|
-
}
|
|
132
|
-
function fromBase64(content, opts = {}) {
|
|
133
|
-
const { urlSafe = false } = opts;
|
|
134
|
-
if (content == null || content === "")
|
|
135
|
-
return "";
|
|
136
|
-
let normalized = content;
|
|
137
|
-
if (urlSafe) {
|
|
138
|
-
normalized = normalized.replace(/-/g, "+").replace(/_/g, "/");
|
|
139
|
-
}
|
|
140
|
-
const padNeeded = normalized.length % 4;
|
|
141
|
-
if (padNeeded === 2)
|
|
142
|
-
normalized += "==";
|
|
143
|
-
else if (padNeeded === 3)
|
|
144
|
-
normalized += "=";
|
|
145
|
-
else if (padNeeded === 1) {
|
|
146
|
-
throw new Error("Invalid Base64 string length");
|
|
147
|
-
}
|
|
148
|
-
const hasBuffer = typeof Buffer !== "undefined" && typeof Buffer.from === "function";
|
|
149
|
-
try {
|
|
150
|
-
if (hasBuffer) {
|
|
151
|
-
return Buffer.from(normalized, "base64").toString("utf8");
|
|
152
|
-
} else {
|
|
153
|
-
const binary = atob(normalized);
|
|
154
|
-
const len = binary.length;
|
|
155
|
-
const bytes = new Uint8Array(len);
|
|
156
|
-
for (let i = 0; i < len; i++) {
|
|
157
|
-
bytes[i] = binary.charCodeAt(i);
|
|
158
|
-
}
|
|
159
|
-
const decoder = new TextDecoder();
|
|
160
|
-
return decoder.decode(bytes);
|
|
161
|
-
}
|
|
162
|
-
} catch (e) {
|
|
163
|
-
throw new Error("Failed to decode Base64: " + (e instanceof Error ? e.message : String(e)));
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
109
|
// Annotate the CommonJS export names for ESM import in node:
|
|
167
110
|
0 && (module.exports = {
|
|
168
111
|
advancedDecrypt,
|
|
169
112
|
advancedEncrypt,
|
|
170
113
|
decryptAES,
|
|
171
|
-
encryptAES
|
|
172
|
-
fromBase64,
|
|
173
|
-
toBase64
|
|
114
|
+
encryptAES
|
|
174
115
|
});
|
|
175
116
|
//# sourceMappingURL=crypto.js.map
|
package/lib/utils/crypto.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/crypto.ts"],
|
|
4
|
-
"sourcesContent": ["import { random } from './math';\nimport { randomChars } from './string';\n\n/** Secret. No description provided */\nexport async function advancedEncrypt(plainText: string, key: string) {\n const k1 = randomChars(36);\n let e = await encryptAES(plainText, k1);\n const b =
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["import { base64ToString, stringToBase64 } from './base64';\nimport { random } from './math';\nimport { randomChars } from './string';\n\n/** Secret. No description provided */\nexport async function advancedEncrypt(plainText: string, key: string) {\n const k1 = randomChars(36);\n let e = await encryptAES(plainText, k1);\n const b = stringToBase64(k1);\n const l = b.length;\n const s = random(0, e.length);\n e = e.substring(0, s) + b + e.substring(s);\n const r = stringToBase64(`${s}-${l}`);\n const t = `${e}.${r}`;\n return encryptAES(t, key);\n}\n\n/** Secret. No description provided */\nexport async function advancedDecrypt(encryptedText: string, key: string) {\n const decrypted = await decryptAES(encryptedText, key);\n const [e, r] = decrypted.split('.');\n const [s, l] = base64ToString(r).split('-').map(Number);\n const k1 = base64ToString(e.substring(s, s + l));\n return decryptAES(e.substring(0, s) + e.substring(s + l), k1);\n}\n\n/**\n * **EN**: General AES encryption function - supports both Node.js and browser environments\n *\n * **CN**: 通用 AES 加密函数 - 同时支持 Node.js 和浏览器环境\n *\n * @param {string} text The text to be encrypted | 要加密的文本\n * @param {string} key The encryption key | 加密密钥\n *\n * @returns {Promise<string>} The encrypted text | 加密后的文本\n */\nexport async function encryptAES(text: string, key: string): Promise<string> {\n const isNode = typeof process !== 'undefined' && process.versions != null && process.versions.node != null;\n\n if (isNode) {\n // Node.js\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const crypto = require('crypto');\n const derivedKey = crypto.createHash('sha256').update(key).digest();\n const iv = crypto.randomBytes(16);\n const cipher = crypto.createCipheriv('aes-256-cbc', derivedKey, iv);\n let encrypted = cipher.update(text, 'utf8', 'base64');\n encrypted += cipher.final('base64');\n return `${iv.toString('base64')}:${encrypted}`;\n } else {\n // Browsers\n try {\n const iv = crypto.getRandomValues(new Uint8Array(16));\n const encoder = new TextEncoder();\n const keyData = encoder.encode(key);\n const hashBuffer = await crypto.subtle.digest('SHA-256', keyData);\n const cryptoKey = await crypto.subtle.importKey('raw', hashBuffer, { name: 'AES-CBC' }, false, ['encrypt']);\n const textBytes = encoder.encode(text);\n const encryptedBuffer = await crypto.subtle.encrypt({ name: 'AES-CBC', iv }, cryptoKey, textBytes);\n const ivBase64 = btoa(String.fromCharCode(...iv));\n const encryptedBase64 = btoa(String.fromCharCode(...new Uint8Array(encryptedBuffer)));\n return `${ivBase64}:${encryptedBase64}`;\n } catch (error) {\n console.error('Encryption error:', error);\n throw error;\n }\n }\n}\n\n/**\n * **EN**: General AES decryption function - supports both Node.js and browser environments\n *\n * **CN**: 通用 AES 解密函数 - 同时支持 Node.js 和浏览器环境\n *\n * @param encryptedText The encrypted text (format: iv:encryptedContent, base64 encoded)\n * @param key The decryption key\n *\n * @returns The decrypted text\n */\nexport async function decryptAES(encryptedText: string, key: string): Promise<string> {\n const isNode = typeof process !== 'undefined' && process.versions != null && process.versions.node != null;\n try {\n const [ivBase64, encryptedBase64] = encryptedText.split(':');\n if (!ivBase64 || !encryptedBase64) {\n throw new Error('Invalid encrypted format');\n }\n if (isNode) {\n // Node.js\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const crypto = require('crypto');\n const iv = Buffer.from(ivBase64, 'base64');\n const encryptedBuffer = Buffer.from(encryptedBase64, 'base64');\n const derivedKey = crypto.createHash('sha256').update(key).digest();\n const decipher = crypto.createDecipheriv('aes-256-cbc', derivedKey, iv);\n let decrypted = decipher.update(encryptedBuffer);\n decrypted = Buffer.concat([decrypted, decipher.final()]);\n return decrypted.toString('utf8');\n } else {\n // Browsers\n const iv = Uint8Array.from(atob(ivBase64), (c) => c.charCodeAt(0));\n const encryptedData = Uint8Array.from(atob(encryptedBase64), (c) => c.charCodeAt(0));\n const encoder = new TextEncoder();\n const keyData = encoder.encode(key);\n const hashBuffer = await crypto.subtle.digest('SHA-256', keyData);\n const cryptoKey = await crypto.subtle.importKey('raw', hashBuffer, { name: 'AES-CBC' }, false, ['decrypt']);\n const decryptedBuffer = await crypto.subtle.decrypt({ name: 'AES-CBC', iv }, cryptoKey, encryptedData);\n const decoder = new TextDecoder();\n return decoder.decode(decryptedBuffer);\n }\n } catch (error) {\n console.error('Decryption error:', error);\n return '';\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["crypto"]
|
|
7
7
|
}
|
package/lib/utils/index.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
export * from './AudioPlayer';
|
|
2
|
+
export { default as AudioPlayer } from './AudioPlayer';
|
|
3
|
+
export * from './base64';
|
|
1
4
|
export * from './color';
|
|
5
|
+
export * from './crypto';
|
|
2
6
|
export * from './math';
|
|
7
|
+
export * from './stream';
|
|
3
8
|
export * from './string';
|
|
4
|
-
export * from './crypto';
|
package/lib/utils/index.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
5
11
|
var __copyProps = (to, from, except, desc) => {
|
|
6
12
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
7
13
|
for (let key of __getOwnPropNames(from))
|
|
@@ -11,20 +17,39 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
11
17
|
return to;
|
|
12
18
|
};
|
|
13
19
|
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
14
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
15
29
|
|
|
16
30
|
// src/utils/index.ts
|
|
17
31
|
var utils_exports = {};
|
|
32
|
+
__export(utils_exports, {
|
|
33
|
+
AudioPlayer: () => import_AudioPlayer.default
|
|
34
|
+
});
|
|
18
35
|
module.exports = __toCommonJS(utils_exports);
|
|
36
|
+
__reExport(utils_exports, require("./AudioPlayer"), module.exports);
|
|
37
|
+
var import_AudioPlayer = __toESM(require("./AudioPlayer"));
|
|
38
|
+
__reExport(utils_exports, require("./base64"), module.exports);
|
|
19
39
|
__reExport(utils_exports, require("./color"), module.exports);
|
|
40
|
+
__reExport(utils_exports, require("./crypto"), module.exports);
|
|
20
41
|
__reExport(utils_exports, require("./math"), module.exports);
|
|
42
|
+
__reExport(utils_exports, require("./stream"), module.exports);
|
|
21
43
|
__reExport(utils_exports, require("./string"), module.exports);
|
|
22
|
-
__reExport(utils_exports, require("./crypto"), module.exports);
|
|
23
44
|
// Annotate the CommonJS export names for ESM import in node:
|
|
24
45
|
0 && (module.exports = {
|
|
46
|
+
AudioPlayer,
|
|
47
|
+
...require("./AudioPlayer"),
|
|
48
|
+
...require("./base64"),
|
|
25
49
|
...require("./color"),
|
|
50
|
+
...require("./crypto"),
|
|
26
51
|
...require("./math"),
|
|
27
|
-
...require("./
|
|
28
|
-
...require("./
|
|
52
|
+
...require("./stream"),
|
|
53
|
+
...require("./string")
|
|
29
54
|
});
|
|
30
55
|
//# sourceMappingURL=index.js.map
|
package/lib/utils/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/index.ts"],
|
|
4
|
-
"sourcesContent": ["export * from './color';\nexport * from './math';\nexport * from './
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["export * from './AudioPlayer';\nexport { default as AudioPlayer } from './AudioPlayer';\nexport * from './base64';\nexport * from './color';\nexport * from './crypto';\nexport * from './math';\nexport * from './stream';\nexport * from './string';\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAAc,0BAAd;AACA,yBAAuC;AACvC,0BAAc,qBAFd;AAGA,0BAAc,oBAHd;AAIA,0BAAc,qBAJd;AAKA,0BAAc,mBALd;AAMA,0BAAc,qBANd;AAOA,0BAAc,qBAPd;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/lib/utils/stream.d.ts
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* - **CN:** 一个数据流时间切片器,用于将音频流分成固定时间段
|
|
4
4
|
*/
|
|
5
5
|
export declare class StreamTimeSlicerClass implements StreamTimeSlicer {
|
|
6
|
-
|
|
6
|
+
sliceMode: StreamTimeSlicerOptions['sliceMode'];
|
|
7
|
+
value: StreamTimeSlicerOptions['value'];
|
|
7
8
|
private readonly onSlice;
|
|
8
9
|
private channelChunks;
|
|
9
10
|
private startTs;
|
|
@@ -18,10 +19,21 @@ export declare class StreamTimeSlicerClass implements StreamTimeSlicer {
|
|
|
18
19
|
}
|
|
19
20
|
export interface StreamTimeSlicerOptions {
|
|
20
21
|
/**
|
|
21
|
-
* - **EN:**
|
|
22
|
-
*
|
|
22
|
+
* - **EN:** Mode of slicing
|
|
23
|
+
*
|
|
24
|
+
* - 'time': slice by time (ms)
|
|
25
|
+
* - 'size': slice by size (bytes)
|
|
26
|
+
* - **CN:** 切片模式
|
|
27
|
+
*
|
|
28
|
+
* - 'time': 按时间切片(毫秒)
|
|
29
|
+
* - 'size': 按大小切片(字节)
|
|
30
|
+
*/
|
|
31
|
+
sliceMode: 'time' | 'size';
|
|
32
|
+
/**
|
|
33
|
+
* - **EN:** Value for slicing (ms or bytes)
|
|
34
|
+
* - **CN:** 切片值(毫秒或字节)
|
|
23
35
|
*/
|
|
24
|
-
|
|
36
|
+
value: number;
|
|
25
37
|
/**
|
|
26
38
|
* - **EN:** Callback when a slice is reached
|
|
27
39
|
* - **CN:** 达到分片时回调
|
|
@@ -36,12 +48,7 @@ export interface StreamTimeSlicerOptions {
|
|
|
36
48
|
* - **EN:** stream time slicer
|
|
37
49
|
* - **CN:** 数据流时间切片器
|
|
38
50
|
*/
|
|
39
|
-
export interface StreamTimeSlicer {
|
|
40
|
-
/**
|
|
41
|
-
* - **EN:** Duration of each slice (ms)
|
|
42
|
-
* - **CN:** 每个分片的时长(毫秒)
|
|
43
|
-
*/
|
|
44
|
-
timeSlice: number;
|
|
51
|
+
export interface StreamTimeSlicer extends Readonly<Pick<StreamTimeSlicerOptions, 'sliceMode'>>, Pick<StreamTimeSlicerOptions, 'value'> {
|
|
45
52
|
/**
|
|
46
53
|
* - **EN:** Push a frame (multi-channel data obtained from the same callback)
|
|
47
54
|
* - **CN:** 推入一帧(同一次回调得到的多通道)
|
package/lib/utils/stream.js
CHANGED
|
@@ -26,7 +26,8 @@ var StreamTimeSlicerClass = class {
|
|
|
26
26
|
constructor(options) {
|
|
27
27
|
this.channelChunks = [];
|
|
28
28
|
this.startTs = null;
|
|
29
|
-
this.
|
|
29
|
+
this.sliceMode = options.sliceMode;
|
|
30
|
+
this.value = options.value;
|
|
30
31
|
this.onSlice = options.onSlice;
|
|
31
32
|
}
|
|
32
33
|
now() {
|
|
@@ -35,9 +36,13 @@ var StreamTimeSlicerClass = class {
|
|
|
35
36
|
shouldEmit(currentTs) {
|
|
36
37
|
if (this.startTs == null)
|
|
37
38
|
return false;
|
|
38
|
-
if (this.
|
|
39
|
+
if (this.value <= 0)
|
|
39
40
|
return true;
|
|
40
|
-
|
|
41
|
+
if (this.sliceMode === "time") {
|
|
42
|
+
return currentTs - this.startTs >= this.value;
|
|
43
|
+
} else {
|
|
44
|
+
return this.channelChunks.reduce((acc, arr) => acc + arr.length, 0) >= this.value;
|
|
45
|
+
}
|
|
41
46
|
}
|
|
42
47
|
emit(force = false) {
|
|
43
48
|
if (this.startTs == null)
|
|
@@ -79,7 +84,7 @@ var StreamTimeSlicerClass = class {
|
|
|
79
84
|
this.channelChunks[i].push(ch);
|
|
80
85
|
});
|
|
81
86
|
this.emit(false);
|
|
82
|
-
if (this.
|
|
87
|
+
if (this.value <= 0)
|
|
83
88
|
this.emit(true);
|
|
84
89
|
}
|
|
85
90
|
flush() {
|
package/lib/utils/stream.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/stream.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * - **EN:** A stream time slicer for splitting audio streams into fixed time segments\n * - **CN:** 一个数据流时间切片器,用于将音频流分成固定时间段\n */\nexport class StreamTimeSlicerClass implements StreamTimeSlicer {\n
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIO,IAAM,wBAAN,MAAwD;AAAA,
|
|
4
|
+
"sourcesContent": ["/**\n * - **EN:** A stream time slicer for splitting audio streams into fixed time segments\n * - **CN:** 一个数据流时间切片器,用于将音频流分成固定时间段\n */\nexport class StreamTimeSlicerClass implements StreamTimeSlicer {\n public sliceMode: StreamTimeSlicerOptions['sliceMode'];\n public value: StreamTimeSlicerOptions['value'];\n private readonly onSlice: (channels: Float32Array[], sliceDurationMs: number) => void;\n private channelChunks: Float32Array[][] = [];\n private startTs: number | null = null;\n\n constructor(options: StreamTimeSlicerOptions) {\n this.sliceMode = options.sliceMode;\n this.value = options.value;\n this.onSlice = options.onSlice;\n }\n\n private now() {\n return typeof performance !== 'undefined' ? performance.now() : Date.now();\n }\n\n private shouldEmit(currentTs: number) {\n if (this.startTs == null) return false;\n if (this.value <= 0) return true;\n if (this.sliceMode === 'time') {\n return currentTs - this.startTs >= this.value;\n } else {\n return this.channelChunks.reduce((acc, arr) => acc + arr.length, 0) >= this.value;\n }\n }\n\n private emit(force = false) {\n if (this.startTs == null) return;\n const currentTs = this.now();\n if (!force && !this.shouldEmit(currentTs)) return;\n\n // reset start time\n if (this.channelChunks.length === 0 || this.channelChunks.every((arr) => arr.length === 0)) {\n this.startTs = null;\n for (let i = 0; i < this.channelChunks.length; i++) this.channelChunks[i] = [];\n return;\n }\n\n // Merge each channel\n const merged: Float32Array[] = this.channelChunks.map((chArr) => {\n const total = chArr.reduce((s, a) => s + a.length, 0);\n const out = new Float32Array(total);\n let offset = 0;\n for (const seg of chArr) {\n out.set(seg, offset);\n offset += seg.length;\n }\n return out;\n });\n\n const sliceDur = this.startTs != null ? currentTs - this.startTs : 0;\n this.onSlice(merged, sliceDur);\n\n // Reset start time\n for (let i = 0; i < this.channelChunks.length; i++) this.channelChunks[i] = [];\n this.startTs = null;\n }\n\n push(channels: Float32Array[]) {\n if (!channels || channels.length === 0) return;\n if (this.startTs == null) this.startTs = this.now();\n\n while (this.channelChunks.length < channels.length) {\n this.channelChunks.push([]);\n }\n channels.forEach((ch, i) => {\n this.channelChunks[i].push(ch);\n });\n\n this.emit(false);\n if (this.value <= 0) this.emit(true); // immediate output mode\n }\n\n flush() {\n this.emit(true);\n }\n\n reset() {\n for (let i = 0; i < this.channelChunks.length; i++) this.channelChunks[i] = [];\n this.startTs = null;\n }\n\n duration() {\n return this.startTs == null ? 0 : this.now() - this.startTs;\n }\n}\nexport interface StreamTimeSlicerOptions {\n /**\n * - **EN:** Mode of slicing\n *\n * - 'time': slice by time (ms)\n * - 'size': slice by size (bytes)\n * - **CN:** 切片模式\n *\n * - 'time': 按时间切片(毫秒)\n * - 'size': 按大小切片(字节)\n */\n sliceMode: 'time' | 'size';\n /**\n * - **EN:** Value for slicing (ms or bytes)\n * - **CN:** 切片值(毫秒或字节)\n */\n value: number;\n /**\n * - **EN:** Callback when a slice is reached\n * - **CN:** 达到分片时回调\n *\n * @param channels - Multi-channel data, each channel is a Float32Array | 多通道数据,每个通道是一个\n * Float32Array\n * @param sliceDuration - Duration of the slice (ms) | 分片时长(ms)\n */\n onSlice: (channels: Float32Array[], sliceDuration: number) => void;\n}\n\n/**\n * - **EN:** stream time slicer\n * - **CN:** 数据流时间切片器\n */\nexport interface StreamTimeSlicer\n extends Readonly<Pick<StreamTimeSlicerOptions, 'sliceMode'>>,\n Pick<StreamTimeSlicerOptions, 'value'> {\n /**\n * - **EN:** Push a frame (multi-channel data obtained from the same callback)\n * - **CN:** 推入一帧(同一次回调得到的多通道)\n *\n * @param channels - Multi-channel data, each channel is a Float32Array | 多通道数据,每个通道是一个\n * Float32Array\n */\n push: (channels: Float32Array[]) => void;\n /**\n * - **EN:** Force output the current accumulation (output even if not enough timeSlice)\n * - **CN:** 强制输出当前累积(不足 timeSlice 也输出)\n */\n flush: () => void;\n /**\n * - **EN:** Clear the cache (do not output)\n * - **CN:** 清空缓存(不输出)\n */\n reset: () => void;\n /**\n * - **EN:** Get the accumulated duration from start to current (ms)\n * - **CN:** 获取从开始到当前已累计的时长(ms)\n */\n duration: () => number;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIO,IAAM,wBAAN,MAAwD;AAAA,EAO7D,YAAY,SAAkC;AAH9C,SAAQ,gBAAkC,CAAC;AAC3C,SAAQ,UAAyB;AAG/B,SAAK,YAAY,QAAQ;AACzB,SAAK,QAAQ,QAAQ;AACrB,SAAK,UAAU,QAAQ;AAAA,EACzB;AAAA,EAEQ,MAAM;AACZ,WAAO,OAAO,gBAAgB,cAAc,YAAY,IAAI,IAAI,KAAK,IAAI;AAAA,EAC3E;AAAA,EAEQ,WAAW,WAAmB;AACpC,QAAI,KAAK,WAAW;AAAM,aAAO;AACjC,QAAI,KAAK,SAAS;AAAG,aAAO;AAC5B,QAAI,KAAK,cAAc,QAAQ;AAC7B,aAAO,YAAY,KAAK,WAAW,KAAK;AAAA,IAC1C,OAAO;AACL,aAAO,KAAK,cAAc,OAAO,CAAC,KAAK,QAAQ,MAAM,IAAI,QAAQ,CAAC,KAAK,KAAK;AAAA,IAC9E;AAAA,EACF;AAAA,EAEQ,KAAK,QAAQ,OAAO;AAC1B,QAAI,KAAK,WAAW;AAAM;AAC1B,UAAM,YAAY,KAAK,IAAI;AAC3B,QAAI,CAAC,SAAS,CAAC,KAAK,WAAW,SAAS;AAAG;AAG3C,QAAI,KAAK,cAAc,WAAW,KAAK,KAAK,cAAc,MAAM,CAAC,QAAQ,IAAI,WAAW,CAAC,GAAG;AAC1F,WAAK,UAAU;AACf,eAAS,IAAI,GAAG,IAAI,KAAK,cAAc,QAAQ;AAAK,aAAK,cAAc,CAAC,IAAI,CAAC;AAC7E;AAAA,IACF;AAGA,UAAM,SAAyB,KAAK,cAAc,IAAI,CAAC,UAAU;AAC/D,YAAM,QAAQ,MAAM,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,QAAQ,CAAC;AACpD,YAAM,MAAM,IAAI,aAAa,KAAK;AAClC,UAAI,SAAS;AACb,iBAAW,OAAO,OAAO;AACvB,YAAI,IAAI,KAAK,MAAM;AACnB,kBAAU,IAAI;AAAA,MAChB;AACA,aAAO;AAAA,IACT,CAAC;AAED,UAAM,WAAW,KAAK,WAAW,OAAO,YAAY,KAAK,UAAU;AACnE,SAAK,QAAQ,QAAQ,QAAQ;AAG7B,aAAS,IAAI,GAAG,IAAI,KAAK,cAAc,QAAQ;AAAK,WAAK,cAAc,CAAC,IAAI,CAAC;AAC7E,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,KAAK,UAA0B;AAC7B,QAAI,CAAC,YAAY,SAAS,WAAW;AAAG;AACxC,QAAI,KAAK,WAAW;AAAM,WAAK,UAAU,KAAK,IAAI;AAElD,WAAO,KAAK,cAAc,SAAS,SAAS,QAAQ;AAClD,WAAK,cAAc,KAAK,CAAC,CAAC;AAAA,IAC5B;AACA,aAAS,QAAQ,CAAC,IAAI,MAAM;AAC1B,WAAK,cAAc,CAAC,EAAE,KAAK,EAAE;AAAA,IAC/B,CAAC;AAED,SAAK,KAAK,KAAK;AACf,QAAI,KAAK,SAAS;AAAG,WAAK,KAAK,IAAI;AAAA,EACrC;AAAA,EAEA,QAAQ;AACN,SAAK,KAAK,IAAI;AAAA,EAChB;AAAA,EAEA,QAAQ;AACN,aAAS,IAAI,GAAG,IAAI,KAAK,cAAc,QAAQ;AAAK,WAAK,cAAc,CAAC,IAAI,CAAC;AAC7E,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,WAAW;AACT,WAAO,KAAK,WAAW,OAAO,IAAI,KAAK,IAAI,IAAI,KAAK;AAAA,EACtD;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|