@tiny-codes/react-easy 1.4.9 → 1.4.11

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.
@@ -1,6 +1,8 @@
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;
5
7
  var __export = (target, all) => {
6
8
  for (var name in all)
@@ -14,6 +16,14 @@ var __copyProps = (to, from, except, desc) => {
14
16
  }
15
17
  return to;
16
18
  };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
17
27
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
28
 
19
29
  // src/utils/crypto.ts
@@ -22,7 +32,9 @@ __export(crypto_exports, {
22
32
  advancedDecrypt: () => advancedDecrypt,
23
33
  advancedEncrypt: () => advancedEncrypt,
24
34
  decryptAES: () => decryptAES,
25
- encryptAES: () => encryptAES
35
+ decryptWithCryptoJS: () => decryptWithCryptoJS,
36
+ encryptAES: () => encryptAES,
37
+ encryptWithCryptoJS: () => encryptWithCryptoJS
26
38
  });
27
39
  module.exports = __toCommonJS(crypto_exports);
28
40
  var import_base64 = require("./base64");
@@ -57,20 +69,24 @@ async function encryptAES(text, key) {
57
69
  encrypted += cipher.final("base64");
58
70
  return `${iv.toString("base64")}:${encrypted}`;
59
71
  } else {
60
- try {
61
- const iv = crypto.getRandomValues(new Uint8Array(16));
62
- const encoder = new TextEncoder();
63
- const keyData = encoder.encode(key);
64
- const hashBuffer = await crypto.subtle.digest("SHA-256", keyData);
65
- const cryptoKey = await crypto.subtle.importKey("raw", hashBuffer, { name: "AES-CBC" }, false, ["encrypt"]);
66
- const textBytes = encoder.encode(text);
67
- const encryptedBuffer = await crypto.subtle.encrypt({ name: "AES-CBC", iv }, cryptoKey, textBytes);
68
- const ivBase64 = btoa(String.fromCharCode(...iv));
69
- const encryptedBase64 = btoa(String.fromCharCode(...new Uint8Array(encryptedBuffer)));
70
- return `${ivBase64}:${encryptedBase64}`;
71
- } catch (error) {
72
- console.error("Encryption error:", error);
73
- throw error;
72
+ if (crypto.subtle) {
73
+ try {
74
+ const iv = crypto.getRandomValues(new Uint8Array(16));
75
+ const encoder = new TextEncoder();
76
+ const keyData = encoder.encode(key);
77
+ const hashBuffer = await crypto.subtle.digest("SHA-256", keyData);
78
+ const cryptoKey = await crypto.subtle.importKey("raw", hashBuffer, { name: "AES-CBC" }, false, ["encrypt"]);
79
+ const textBytes = encoder.encode(text);
80
+ const encryptedBuffer = await crypto.subtle.encrypt({ name: "AES-CBC", iv }, cryptoKey, textBytes);
81
+ const ivBase64 = btoa(String.fromCharCode(...iv));
82
+ const encryptedBase64 = btoa(String.fromCharCode(...new Uint8Array(encryptedBuffer)));
83
+ return `${ivBase64}:${encryptedBase64}`;
84
+ } catch (error) {
85
+ console.error("Encryption error:", error);
86
+ throw error;
87
+ }
88
+ } else {
89
+ return encryptWithCryptoJS(text, key);
74
90
  }
75
91
  }
76
92
  }
@@ -91,26 +107,109 @@ async function decryptAES(encryptedText, key) {
91
107
  decrypted = Buffer.concat([decrypted, decipher.final()]);
92
108
  return decrypted.toString("utf8");
93
109
  } else {
94
- const iv = Uint8Array.from(atob(ivBase64), (c) => c.charCodeAt(0));
95
- const encryptedData = Uint8Array.from(atob(encryptedBase64), (c) => c.charCodeAt(0));
96
- const encoder = new TextEncoder();
97
- const keyData = encoder.encode(key);
98
- const hashBuffer = await crypto.subtle.digest("SHA-256", keyData);
99
- const cryptoKey = await crypto.subtle.importKey("raw", hashBuffer, { name: "AES-CBC" }, false, ["decrypt"]);
100
- const decryptedBuffer = await crypto.subtle.decrypt({ name: "AES-CBC", iv }, cryptoKey, encryptedData);
101
- const decoder = new TextDecoder();
102
- return decoder.decode(decryptedBuffer);
110
+ if (crypto.subtle) {
111
+ const iv = Uint8Array.from(atob(ivBase64), (c) => c.charCodeAt(0));
112
+ const encryptedData = Uint8Array.from(atob(encryptedBase64), (c) => c.charCodeAt(0));
113
+ const encoder = new TextEncoder();
114
+ const keyData = encoder.encode(key);
115
+ const hashBuffer = await crypto.subtle.digest("SHA-256", keyData);
116
+ const cryptoKey = await crypto.subtle.importKey("raw", hashBuffer, { name: "AES-CBC" }, false, ["decrypt"]);
117
+ const decryptedBuffer = await crypto.subtle.decrypt({ name: "AES-CBC", iv }, cryptoKey, encryptedData);
118
+ const decoder = new TextDecoder();
119
+ return decoder.decode(decryptedBuffer);
120
+ } else {
121
+ return decryptWithCryptoJS(encryptedText, key);
122
+ }
103
123
  }
104
124
  } catch (error) {
105
125
  console.error("Decryption error:", error);
106
126
  return "";
107
127
  }
108
128
  }
129
+ async function encryptWithCryptoJS(text, key) {
130
+ const [
131
+ {
132
+ default: {
133
+ mode: { CBC },
134
+ lib: { WordArray }
135
+ }
136
+ },
137
+ { default: Pkcs7 },
138
+ { default: Base64 },
139
+ { default: Utf8 },
140
+ { default: SHA256 },
141
+ {
142
+ default: { encrypt }
143
+ }
144
+ ] = await Promise.all([
145
+ import("crypto-js/core.js"),
146
+ import("crypto-js/pad-pkcs7.js"),
147
+ import("crypto-js/enc-base64.js"),
148
+ import("crypto-js/enc-utf8.js"),
149
+ import("crypto-js/sha256.js"),
150
+ import("crypto-js/aes.js")
151
+ ]);
152
+ try {
153
+ const wordArray = Utf8.parse(text);
154
+ const keyArray = SHA256(key);
155
+ const iv = WordArray.random(16);
156
+ const encryptedBase64 = Base64.stringify(
157
+ encrypt(wordArray, keyArray, {
158
+ iv,
159
+ mode: CBC,
160
+ padding: Pkcs7
161
+ }).ciphertext
162
+ );
163
+ return `${Base64.stringify(iv)}:${encryptedBase64}`;
164
+ } catch (error) {
165
+ console.error("Encryption error:", error);
166
+ throw error;
167
+ }
168
+ }
169
+ async function decryptWithCryptoJS(encryptedText, key) {
170
+ const [ivBase64, encryptedBase64] = encryptedText.split(":");
171
+ const [
172
+ {
173
+ default: {
174
+ mode: { CBC }
175
+ }
176
+ },
177
+ { default: Pkcs7 },
178
+ { default: Base64 },
179
+ { default: Utf8 },
180
+ { default: SHA256 },
181
+ {
182
+ default: { decrypt }
183
+ }
184
+ ] = await Promise.all([
185
+ import("crypto-js/core.js"),
186
+ import("crypto-js/pad-pkcs7.js"),
187
+ import("crypto-js/enc-base64.js"),
188
+ import("crypto-js/enc-utf8.js"),
189
+ import("crypto-js/sha256.js"),
190
+ import("crypto-js/aes.js")
191
+ ]);
192
+ try {
193
+ const iv = Base64.parse(ivBase64);
194
+ const derivedKey = SHA256(key);
195
+ const decrypted = decrypt(encryptedBase64, derivedKey, {
196
+ iv,
197
+ mode: CBC,
198
+ padding: Pkcs7
199
+ });
200
+ return decrypted.toString(Utf8);
201
+ } catch (error) {
202
+ console.error("Decryption error:", error);
203
+ throw error;
204
+ }
205
+ }
109
206
  // Annotate the CommonJS export names for ESM import in node:
110
207
  0 && (module.exports = {
111
208
  advancedDecrypt,
112
209
  advancedEncrypt,
113
210
  decryptAES,
114
- encryptAES
211
+ decryptWithCryptoJS,
212
+ encryptAES,
213
+ encryptWithCryptoJS
115
214
  });
116
215
  //# sourceMappingURL=crypto.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/crypto.ts"],
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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",
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 if (crypto.subtle) {\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 } else {\n // let encrypt: typeof CryptoJS.AES.encrypt;\n // try {\n // const aes = await import('crypto-js/aes');\n // encrypt = aes.encrypt;\n // } catch (error) {\n // console.error('Load \"crypto-js/aes\" error:', error);\n // throw error;\n // }\n // try {\n // return encrypt(text, key).toString();\n // } catch (error) {\n // console.error('Encryption error:', error);\n // throw error;\n // }\n return encryptWithCryptoJS(text, key);\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 if (crypto.subtle) {\n // Browsers with Web Crypto API, in secure contexts (HTTPS)\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 } else {\n // Browsers without Web Crypto API, or insecure contexts (HTTP), fallback to CryptoJS\n // let decrypt: typeof CryptoJS.AES.decrypt;\n // let utf8: typeof CryptoJS.enc.Utf8;\n // try {\n // const [aes, encUtf8] = await Promise.all([import('crypto-js/aes'), import('crypto-js/enc-utf8')]);\n // decrypt = aes.decrypt;\n // utf8 = encUtf8.default;\n // } catch (error) {\n // console.error('Load \"crypto-js/aes\" error:', error);\n // throw error;\n // }\n // try {\n // const decrypted = decrypt(encryptedText, key);\n // return decrypted.toString(utf8);\n // } catch (error) {\n // console.error('Decryption error:', error);\n // throw error;\n // }\n return decryptWithCryptoJS(encryptedText, key);\n }\n }\n } catch (error) {\n console.error('Decryption error:', error);\n return '';\n }\n}\nexport async function encryptWithCryptoJS(text: string, key: string) {\n const [\n {\n default: {\n mode: { CBC },\n lib: { WordArray },\n },\n },\n { default: Pkcs7 },\n { default: Base64 },\n { default: Utf8 },\n { default: SHA256 },\n {\n default: { encrypt },\n },\n ] = await Promise.all([\n import('crypto-js/core.js'),\n import('crypto-js/pad-pkcs7.js'),\n import('crypto-js/enc-base64.js'),\n import('crypto-js/enc-utf8.js'),\n import('crypto-js/sha256.js'),\n import('crypto-js/aes.js'),\n ]);\n\n try {\n // Convert text and key to WordArray objects\n const wordArray = Utf8.parse(text);\n const keyArray = SHA256(key);\n const iv = WordArray.random(16);\n\n const encryptedBase64 = Base64.stringify(\n encrypt(wordArray, keyArray, {\n iv,\n mode: CBC,\n padding: Pkcs7,\n }).ciphertext\n );\n return `${Base64.stringify(iv)}:${encryptedBase64}`;\n } catch (error) {\n console.error('Encryption error:', error);\n throw error;\n }\n}\n\nexport async function decryptWithCryptoJS(encryptedText: string, key: string) {\n const [ivBase64, encryptedBase64] = encryptedText.split(':');\n\n const [\n {\n default: {\n mode: { CBC },\n },\n },\n { default: Pkcs7 },\n { default: Base64 },\n { default: Utf8 },\n { default: SHA256 },\n {\n default: { decrypt },\n },\n ] = await Promise.all([\n import('crypto-js/core.js'),\n import('crypto-js/pad-pkcs7.js'),\n import('crypto-js/enc-base64.js'),\n import('crypto-js/enc-utf8.js'),\n import('crypto-js/sha256.js'),\n import('crypto-js/aes.js'),\n ]);\n\n try {\n // Convert base64 strings to WordArray objects\n const iv = Base64.parse(ivBase64);\n // Derive key using SHA-256 (matching native implementation)\n const derivedKey = SHA256(key);\n const decrypted = decrypt(encryptedBase64, derivedKey, {\n iv,\n mode: CBC,\n padding: Pkcs7,\n });\n return decrypted.toString(Utf8);\n } catch (error) {\n console.error('Decryption error:', error);\n throw error;\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["crypto"]
7
7
  }
@@ -3,7 +3,8 @@
3
3
  * - **CN:** 一个数据流时间切片器,用于将音频流分成固定时间段
4
4
  */
5
5
  export declare class StreamTimeSlicerClass implements StreamTimeSlicer {
6
- timeSlice: number;
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:** Duration of each slice (ms)
22
- * - **CN:** 分片时长(ms)
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
- timeSlice: number;
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:** 推入一帧(同一次回调得到的多通道)
@@ -26,7 +26,8 @@ var StreamTimeSlicerClass = class {
26
26
  constructor(options) {
27
27
  this.channelChunks = [];
28
28
  this.startTs = null;
29
- this.timeSlice = options.timeSlice;
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.timeSlice <= 0)
39
+ if (this.value <= 0)
39
40
  return true;
40
- return currentTs - this.startTs >= this.timeSlice;
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.timeSlice <= 0)
87
+ if (this.value <= 0)
83
88
  this.emit(true);
84
89
  }
85
90
  flush() {
@@ -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 timeSlice: number;\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.timeSlice = options.timeSlice;\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.timeSlice <= 0) return true;\n return currentTs - this.startTs >= this.timeSlice;\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.timeSlice <= 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:** Duration of each slice (ms)\n * - **CN:** 分片时长(ms)\n */\n timeSlice: 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 /**\n * - **EN:** Duration of each slice (ms)\n * - **CN:** 每个分片的时长(毫秒)\n */\n timeSlice: number;\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,EAM7D,YAAY,SAAkC;AAH9C,SAAQ,gBAAkC,CAAC;AAC3C,SAAQ,UAAyB;AAG/B,SAAK,YAAY,QAAQ;AACzB,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,aAAa;AAAG,aAAO;AAChC,WAAO,YAAY,KAAK,WAAW,KAAK;AAAA,EAC1C;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,aAAa;AAAG,WAAK,KAAK,IAAI;AAAA,EACzC;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;",
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiny-codes/react-easy",
3
- "version": "1.4.9",
3
+ "version": "1.4.11",
4
4
  "description": "Simplify React and AntDesign development with practical components and hooks",
5
5
  "keywords": [
6
6
  "react",
@@ -41,6 +41,7 @@
41
41
  "@lexical/react": "^0.33.1",
42
42
  "@microsoft/fetch-event-source": "^2.0.1",
43
43
  "@stomp/stompjs": "^7.1.1",
44
+ "crypto-js": "^4.2.0",
44
45
  "i18next": "^24.2.3",
45
46
  "lexical": "^0.33.1",
46
47
  "react-contexify": "^6.0.0",
@@ -49,6 +50,7 @@
49
50
  "devDependencies": {
50
51
  "@tiny-codes/code-style-all-in-one": "^1.1.5",
51
52
  "@tiny-codes/eslint-plugin-react-hooks": "^4.6.0",
53
+ "@types/crypto-js": "^4.2.2",
52
54
  "@types/jest": "^29.5.14",
53
55
  "@types/node": "^22.15.32",
54
56
  "@types/react": "^19.0.12",