@autobe/ui 0.30.0-dev.20260315 → 0.30.0

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.
Files changed (86) hide show
  1. package/LICENSE +661 -661
  2. package/lib/components/AutoBeChatMain.js +5 -5
  3. package/lib/components/AutoBeConfigModal.js +9 -9
  4. package/package.json +2 -2
  5. package/src/components/AutoBeAssistantMessageMovie.tsx +22 -22
  6. package/src/components/AutoBeChatMain.tsx +376 -376
  7. package/src/components/AutoBeChatSidebar.tsx +414 -414
  8. package/src/components/AutoBeConfigButton.tsx +83 -83
  9. package/src/components/AutoBeConfigModal.tsx +443 -443
  10. package/src/components/AutoBeStatusButton.tsx +75 -75
  11. package/src/components/AutoBeStatusModal.tsx +486 -486
  12. package/src/components/AutoBeUserMessageMovie.tsx +27 -27
  13. package/src/components/common/ActionButton.tsx +205 -205
  14. package/src/components/common/ActionButtonGroup.tsx +80 -80
  15. package/src/components/common/AutoBeConfigInput.tsx +185 -185
  16. package/src/components/common/ChatBubble.tsx +119 -119
  17. package/src/components/common/Collapsible.tsx +95 -95
  18. package/src/components/common/CompactSessionIndicator.tsx +73 -73
  19. package/src/components/common/CompactSessionList.tsx +82 -82
  20. package/src/components/common/index.ts +8 -8
  21. package/src/components/common/openai/OpenAIContent.tsx +53 -53
  22. package/src/components/common/openai/OpenAIUserAudioContent.tsx +70 -70
  23. package/src/components/common/openai/OpenAIUserFileContent.tsx +76 -76
  24. package/src/components/common/openai/OpenAIUserImageContent.tsx +34 -34
  25. package/src/components/common/openai/OpenAIUserTextContent.tsx +15 -15
  26. package/src/components/common/openai/index.ts +5 -5
  27. package/src/components/events/AutoBeCompleteEventMovie.tsx +402 -402
  28. package/src/components/events/AutoBeCorrectEventMovie.tsx +354 -354
  29. package/src/components/events/AutoBeEventGroupMovie.tsx +18 -18
  30. package/src/components/events/AutoBeEventMovie.tsx +158 -158
  31. package/src/components/events/AutoBeProgressEventMovie.tsx +217 -217
  32. package/src/components/events/AutoBeScenarioEventMovie.tsx +135 -135
  33. package/src/components/events/AutoBeStartEventMovie.tsx +82 -82
  34. package/src/components/events/AutoBeValidateEventMovie.tsx +249 -249
  35. package/src/components/events/README.md +300 -300
  36. package/src/components/events/common/CollapsibleEventGroup.tsx +211 -211
  37. package/src/components/events/common/EventCard.tsx +61 -61
  38. package/src/components/events/common/EventContent.tsx +31 -31
  39. package/src/components/events/common/EventHeader.tsx +85 -85
  40. package/src/components/events/common/EventIcon.tsx +82 -82
  41. package/src/components/events/common/ProgressBar.tsx +64 -64
  42. package/src/components/events/common/index.ts +13 -13
  43. package/src/components/events/groups/CorrectEventGroup.tsx +183 -183
  44. package/src/components/events/groups/ValidateEventGroup.tsx +143 -143
  45. package/src/components/events/groups/index.ts +8 -8
  46. package/src/components/events/index.ts +16 -16
  47. package/src/components/events/utils/eventGrouper.tsx +116 -116
  48. package/src/components/events/utils/index.ts +1 -1
  49. package/src/components/index.ts +13 -13
  50. package/src/components/upload/AutoBeChatUploadBox.tsx +425 -425
  51. package/src/components/upload/AutoBeChatUploadSendButton.tsx +66 -66
  52. package/src/components/upload/AutoBeFileUploadBox.tsx +123 -123
  53. package/src/components/upload/AutoBeUploadConfig.ts +5 -5
  54. package/src/components/upload/AutoBeVoiceRecoderButton.tsx +100 -100
  55. package/src/components/upload/index.ts +5 -5
  56. package/src/constant/color.ts +28 -28
  57. package/src/context/AutoBeAgentContext.tsx +245 -245
  58. package/src/context/AutoBeAgentSessionList.tsx +58 -58
  59. package/src/context/SearchParamsContext.tsx +49 -49
  60. package/src/hooks/index.ts +3 -3
  61. package/src/hooks/useEscapeKey.ts +24 -24
  62. package/src/hooks/useIsomorphicLayoutEffect.ts +8 -8
  63. package/src/hooks/useMediaQuery.ts +73 -73
  64. package/src/hooks/useSessionStorage.ts +10 -10
  65. package/src/icons/Receipt.tsx +74 -74
  66. package/src/index.ts +9 -9
  67. package/src/strategy/AutoBeAgentSessionStorageStrategy.ts +127 -127
  68. package/src/structure/AutoBeListener.ts +373 -373
  69. package/src/structure/AutoBeListenerState.ts +53 -53
  70. package/src/structure/IAutoBeAgentSessionStorageStrategy.ts +87 -87
  71. package/src/structure/IAutoBeEventGroup.ts +6 -6
  72. package/src/structure/index.ts +4 -4
  73. package/src/types/config.ts +44 -44
  74. package/src/types/index.ts +1 -1
  75. package/src/utils/AutoBeFileUploader.ts +279 -279
  76. package/src/utils/AutoBeVoiceRecorder.ts +95 -95
  77. package/src/utils/__tests__/crypto.test.ts +286 -286
  78. package/src/utils/__tests__/storage.test.ts +229 -229
  79. package/src/utils/crypto.ts +95 -95
  80. package/src/utils/index.ts +6 -6
  81. package/src/utils/number.ts +17 -17
  82. package/src/utils/storage.ts +96 -96
  83. package/src/utils/time.ts +14 -14
  84. package/tsconfig.json +9 -9
  85. package/vitest.config.ts +15 -15
  86. package/README.md +0 -261
@@ -1,229 +1,229 @@
1
- import { beforeEach, describe, expect, test, vi } from "vitest";
2
-
3
- import {
4
- clearEncryptedSessionStorage,
5
- getEncryptedSessionStorage,
6
- hasEncryptedSessionStorage,
7
- removeEncryptedSessionStorage,
8
- setEncryptedSessionStorage,
9
- } from "../storage";
10
-
11
- // Mock sessionStorage for testing
12
- const mockSessionStorage = {
13
- store: new Map<string, string>(),
14
- getItem: vi.fn((key: string) => mockSessionStorage.store.get(key) || null),
15
- setItem: vi.fn((key: string, value: string) => {
16
- mockSessionStorage.store.set(key, value);
17
- }),
18
- removeItem: vi.fn((key: string) => {
19
- mockSessionStorage.store.delete(key);
20
- }),
21
- clear: vi.fn(() => {
22
- mockSessionStorage.store.clear();
23
- }),
24
- };
25
-
26
- // Mock global sessionStorage
27
- Object.defineProperty(global, "sessionStorage", {
28
- value: mockSessionStorage,
29
- writable: true,
30
- });
31
-
32
- Object.defineProperty(global, "window", {
33
- value: { sessionStorage: mockSessionStorage },
34
- writable: true,
35
- });
36
-
37
- describe("Storage Utils", () => {
38
- beforeEach(() => {
39
- mockSessionStorage.store.clear();
40
- vi.clearAllMocks();
41
- });
42
-
43
- describe("encrypted sessionStorage operations", () => {
44
- test("should store and retrieve encrypted data", () => {
45
- const key = "test_key";
46
- const value = "sk-test123456789";
47
-
48
- setEncryptedSessionStorage(key, value);
49
- const retrieved = getEncryptedSessionStorage(key);
50
-
51
- expect(retrieved).toBe(value);
52
- expect(mockSessionStorage.setItem).toHaveBeenCalledWith(
53
- key,
54
- expect.any(String),
55
- );
56
- expect(mockSessionStorage.getItem).toHaveBeenCalledWith(key);
57
- });
58
-
59
- test("should store encrypted value, not plain text", () => {
60
- const key = "test_encrypted";
61
- const value = "secret-api-key";
62
-
63
- setEncryptedSessionStorage(key, value);
64
- const storedValue = mockSessionStorage.store.get(key);
65
-
66
- expect(storedValue).not.toBe(value); // Should not store plain text
67
- expect(storedValue).toBeTruthy(); // Should store something
68
- expect(storedValue!.length).toBeGreaterThan(0); // Should have content
69
- });
70
-
71
- test("should handle empty values correctly", () => {
72
- const key = "empty_test";
73
- const value = "";
74
-
75
- setEncryptedSessionStorage(key, value);
76
- const retrieved = getEncryptedSessionStorage(key);
77
-
78
- expect(retrieved).toBe("");
79
- });
80
-
81
- test("should return empty string for non-existent keys", () => {
82
- const result = getEncryptedSessionStorage("non_existent_key");
83
- expect(result).toBe("");
84
- });
85
-
86
- test("should remove encrypted data", () => {
87
- const key = "test_remove";
88
- const value = "test-value";
89
-
90
- setEncryptedSessionStorage(key, value);
91
- expect(getEncryptedSessionStorage(key)).toBe(value);
92
-
93
- removeEncryptedSessionStorage(key);
94
- expect(getEncryptedSessionStorage(key)).toBe("");
95
- expect(mockSessionStorage.removeItem).toHaveBeenCalledWith(key);
96
- });
97
-
98
- test("should check if encrypted data exists", () => {
99
- const key = "existence_test";
100
- const value = "test-value";
101
-
102
- // Initially should not exist
103
- expect(hasEncryptedSessionStorage(key)).toBe(false);
104
-
105
- // After storing should exist
106
- setEncryptedSessionStorage(key, value);
107
- expect(hasEncryptedSessionStorage(key)).toBe(true);
108
-
109
- // After removing should not exist
110
- removeEncryptedSessionStorage(key);
111
- expect(hasEncryptedSessionStorage(key)).toBe(false);
112
- });
113
-
114
- test("should handle storage errors gracefully", () => {
115
- const originalSetItem = mockSessionStorage.setItem;
116
- mockSessionStorage.setItem = vi.fn(() => {
117
- throw new Error("Storage quota exceeded");
118
- });
119
-
120
- // Should throw error with meaningful message
121
- expect(() => {
122
- setEncryptedSessionStorage("test", "value");
123
- }).toThrow(
124
- 'Failed to store encrypted data for key "test": Storage quota exceeded',
125
- );
126
-
127
- mockSessionStorage.setItem = originalSetItem; // Restore
128
- });
129
-
130
- test("should clear all sessionStorage data", () => {
131
- // Mock setItem to not throw for this test
132
- const originalSetItem = mockSessionStorage.setItem;
133
- mockSessionStorage.setItem = vi.fn((key: string, value: string) => {
134
- mockSessionStorage.store.set(key, value);
135
- });
136
-
137
- // Store some test data
138
- setEncryptedSessionStorage("key1", "value1");
139
- setEncryptedSessionStorage("key2", "value2");
140
-
141
- expect(hasEncryptedSessionStorage("key1")).toBe(true);
142
- expect(hasEncryptedSessionStorage("key2")).toBe(true);
143
-
144
- // Clear all
145
- clearEncryptedSessionStorage();
146
-
147
- expect(hasEncryptedSessionStorage("key1")).toBe(false);
148
- expect(hasEncryptedSessionStorage("key2")).toBe(false);
149
- expect(mockSessionStorage.clear).toHaveBeenCalled();
150
-
151
- mockSessionStorage.setItem = originalSetItem; // Restore
152
- });
153
- });
154
-
155
- describe("Unicode and special data", () => {
156
- const testCases = [
157
- { key: "korean", value: "안녕하세요" },
158
- { key: "emoji", value: "🚀🔐💎✨" },
159
- { key: "mixed", value: "Hello 안녕 🚀 World!" },
160
- { key: "api_key", value: "sk-proj-1234567890abcdefghijklmnop" },
161
- { key: "json", value: '{"name":"test","value":123}' },
162
- { key: "multiline", value: "line1\nline2\nline3" },
163
- ];
164
-
165
- test.each(testCases)(
166
- "should handle $key: $value correctly",
167
- ({ key, value }) => {
168
- // Mock setItem to not throw for unicode tests
169
- const originalSetItem = mockSessionStorage.setItem;
170
- mockSessionStorage.setItem = vi.fn((key: string, value: string) => {
171
- mockSessionStorage.store.set(key, value);
172
- });
173
-
174
- setEncryptedSessionStorage(key, value);
175
- const retrieved = getEncryptedSessionStorage(key);
176
-
177
- expect(retrieved).toBe(value);
178
- expect(hasEncryptedSessionStorage(key)).toBe(true);
179
-
180
- // Verify it's actually encrypted in storage
181
- const rawStored = mockSessionStorage.store.get(key);
182
- expect(rawStored).not.toBe(value);
183
- expect(rawStored).toBeTruthy();
184
-
185
- mockSessionStorage.setItem = originalSetItem; // Restore
186
- },
187
- );
188
- });
189
-
190
- describe("Edge cases", () => {
191
- test("should handle null/undefined gracefully", () => {
192
- // These should not throw
193
- expect(() => getEncryptedSessionStorage("")).not.toThrow();
194
- expect(() => hasEncryptedSessionStorage("")).not.toThrow();
195
- expect(() => removeEncryptedSessionStorage("")).not.toThrow();
196
- });
197
-
198
- test("should handle SSR environment (no window)", () => {
199
- const originalWindow = global.window;
200
- // @ts-ignore
201
- delete global.window;
202
-
203
- // Should not throw and return safe defaults
204
- expect(() => {
205
- setEncryptedSessionStorage("test", "value");
206
- const result = getEncryptedSessionStorage("test");
207
- expect(result).toBe("");
208
- const exists = hasEncryptedSessionStorage("test");
209
- expect(exists).toBe(false);
210
- removeEncryptedSessionStorage("test");
211
- clearEncryptedSessionStorage();
212
- }).not.toThrow();
213
-
214
- global.window = originalWindow; // Restore
215
- });
216
-
217
- test("should handle corrupted storage data", () => {
218
- const key = "corrupted_test";
219
-
220
- // Manually put invalid encrypted data
221
- mockSessionStorage.store.set(key, "invalid-base64-data!");
222
-
223
- // Should throw error on corrupted data
224
- expect(() => {
225
- getEncryptedSessionStorage(key);
226
- }).toThrow('Failed to retrieve encrypted data for key "corrupted_test"');
227
- });
228
- });
229
- });
1
+ import { beforeEach, describe, expect, test, vi } from "vitest";
2
+
3
+ import {
4
+ clearEncryptedSessionStorage,
5
+ getEncryptedSessionStorage,
6
+ hasEncryptedSessionStorage,
7
+ removeEncryptedSessionStorage,
8
+ setEncryptedSessionStorage,
9
+ } from "../storage";
10
+
11
+ // Mock sessionStorage for testing
12
+ const mockSessionStorage = {
13
+ store: new Map<string, string>(),
14
+ getItem: vi.fn((key: string) => mockSessionStorage.store.get(key) || null),
15
+ setItem: vi.fn((key: string, value: string) => {
16
+ mockSessionStorage.store.set(key, value);
17
+ }),
18
+ removeItem: vi.fn((key: string) => {
19
+ mockSessionStorage.store.delete(key);
20
+ }),
21
+ clear: vi.fn(() => {
22
+ mockSessionStorage.store.clear();
23
+ }),
24
+ };
25
+
26
+ // Mock global sessionStorage
27
+ Object.defineProperty(global, "sessionStorage", {
28
+ value: mockSessionStorage,
29
+ writable: true,
30
+ });
31
+
32
+ Object.defineProperty(global, "window", {
33
+ value: { sessionStorage: mockSessionStorage },
34
+ writable: true,
35
+ });
36
+
37
+ describe("Storage Utils", () => {
38
+ beforeEach(() => {
39
+ mockSessionStorage.store.clear();
40
+ vi.clearAllMocks();
41
+ });
42
+
43
+ describe("encrypted sessionStorage operations", () => {
44
+ test("should store and retrieve encrypted data", () => {
45
+ const key = "test_key";
46
+ const value = "sk-test123456789";
47
+
48
+ setEncryptedSessionStorage(key, value);
49
+ const retrieved = getEncryptedSessionStorage(key);
50
+
51
+ expect(retrieved).toBe(value);
52
+ expect(mockSessionStorage.setItem).toHaveBeenCalledWith(
53
+ key,
54
+ expect.any(String),
55
+ );
56
+ expect(mockSessionStorage.getItem).toHaveBeenCalledWith(key);
57
+ });
58
+
59
+ test("should store encrypted value, not plain text", () => {
60
+ const key = "test_encrypted";
61
+ const value = "secret-api-key";
62
+
63
+ setEncryptedSessionStorage(key, value);
64
+ const storedValue = mockSessionStorage.store.get(key);
65
+
66
+ expect(storedValue).not.toBe(value); // Should not store plain text
67
+ expect(storedValue).toBeTruthy(); // Should store something
68
+ expect(storedValue!.length).toBeGreaterThan(0); // Should have content
69
+ });
70
+
71
+ test("should handle empty values correctly", () => {
72
+ const key = "empty_test";
73
+ const value = "";
74
+
75
+ setEncryptedSessionStorage(key, value);
76
+ const retrieved = getEncryptedSessionStorage(key);
77
+
78
+ expect(retrieved).toBe("");
79
+ });
80
+
81
+ test("should return empty string for non-existent keys", () => {
82
+ const result = getEncryptedSessionStorage("non_existent_key");
83
+ expect(result).toBe("");
84
+ });
85
+
86
+ test("should remove encrypted data", () => {
87
+ const key = "test_remove";
88
+ const value = "test-value";
89
+
90
+ setEncryptedSessionStorage(key, value);
91
+ expect(getEncryptedSessionStorage(key)).toBe(value);
92
+
93
+ removeEncryptedSessionStorage(key);
94
+ expect(getEncryptedSessionStorage(key)).toBe("");
95
+ expect(mockSessionStorage.removeItem).toHaveBeenCalledWith(key);
96
+ });
97
+
98
+ test("should check if encrypted data exists", () => {
99
+ const key = "existence_test";
100
+ const value = "test-value";
101
+
102
+ // Initially should not exist
103
+ expect(hasEncryptedSessionStorage(key)).toBe(false);
104
+
105
+ // After storing should exist
106
+ setEncryptedSessionStorage(key, value);
107
+ expect(hasEncryptedSessionStorage(key)).toBe(true);
108
+
109
+ // After removing should not exist
110
+ removeEncryptedSessionStorage(key);
111
+ expect(hasEncryptedSessionStorage(key)).toBe(false);
112
+ });
113
+
114
+ test("should handle storage errors gracefully", () => {
115
+ const originalSetItem = mockSessionStorage.setItem;
116
+ mockSessionStorage.setItem = vi.fn(() => {
117
+ throw new Error("Storage quota exceeded");
118
+ });
119
+
120
+ // Should throw error with meaningful message
121
+ expect(() => {
122
+ setEncryptedSessionStorage("test", "value");
123
+ }).toThrow(
124
+ 'Failed to store encrypted data for key "test": Storage quota exceeded',
125
+ );
126
+
127
+ mockSessionStorage.setItem = originalSetItem; // Restore
128
+ });
129
+
130
+ test("should clear all sessionStorage data", () => {
131
+ // Mock setItem to not throw for this test
132
+ const originalSetItem = mockSessionStorage.setItem;
133
+ mockSessionStorage.setItem = vi.fn((key: string, value: string) => {
134
+ mockSessionStorage.store.set(key, value);
135
+ });
136
+
137
+ // Store some test data
138
+ setEncryptedSessionStorage("key1", "value1");
139
+ setEncryptedSessionStorage("key2", "value2");
140
+
141
+ expect(hasEncryptedSessionStorage("key1")).toBe(true);
142
+ expect(hasEncryptedSessionStorage("key2")).toBe(true);
143
+
144
+ // Clear all
145
+ clearEncryptedSessionStorage();
146
+
147
+ expect(hasEncryptedSessionStorage("key1")).toBe(false);
148
+ expect(hasEncryptedSessionStorage("key2")).toBe(false);
149
+ expect(mockSessionStorage.clear).toHaveBeenCalled();
150
+
151
+ mockSessionStorage.setItem = originalSetItem; // Restore
152
+ });
153
+ });
154
+
155
+ describe("Unicode and special data", () => {
156
+ const testCases = [
157
+ { key: "korean", value: "안녕하세요" },
158
+ { key: "emoji", value: "🚀🔐💎✨" },
159
+ { key: "mixed", value: "Hello 안녕 🚀 World!" },
160
+ { key: "api_key", value: "sk-proj-1234567890abcdefghijklmnop" },
161
+ { key: "json", value: '{"name":"test","value":123}' },
162
+ { key: "multiline", value: "line1\nline2\nline3" },
163
+ ];
164
+
165
+ test.each(testCases)(
166
+ "should handle $key: $value correctly",
167
+ ({ key, value }) => {
168
+ // Mock setItem to not throw for unicode tests
169
+ const originalSetItem = mockSessionStorage.setItem;
170
+ mockSessionStorage.setItem = vi.fn((key: string, value: string) => {
171
+ mockSessionStorage.store.set(key, value);
172
+ });
173
+
174
+ setEncryptedSessionStorage(key, value);
175
+ const retrieved = getEncryptedSessionStorage(key);
176
+
177
+ expect(retrieved).toBe(value);
178
+ expect(hasEncryptedSessionStorage(key)).toBe(true);
179
+
180
+ // Verify it's actually encrypted in storage
181
+ const rawStored = mockSessionStorage.store.get(key);
182
+ expect(rawStored).not.toBe(value);
183
+ expect(rawStored).toBeTruthy();
184
+
185
+ mockSessionStorage.setItem = originalSetItem; // Restore
186
+ },
187
+ );
188
+ });
189
+
190
+ describe("Edge cases", () => {
191
+ test("should handle null/undefined gracefully", () => {
192
+ // These should not throw
193
+ expect(() => getEncryptedSessionStorage("")).not.toThrow();
194
+ expect(() => hasEncryptedSessionStorage("")).not.toThrow();
195
+ expect(() => removeEncryptedSessionStorage("")).not.toThrow();
196
+ });
197
+
198
+ test("should handle SSR environment (no window)", () => {
199
+ const originalWindow = global.window;
200
+ // @ts-ignore
201
+ delete global.window;
202
+
203
+ // Should not throw and return safe defaults
204
+ expect(() => {
205
+ setEncryptedSessionStorage("test", "value");
206
+ const result = getEncryptedSessionStorage("test");
207
+ expect(result).toBe("");
208
+ const exists = hasEncryptedSessionStorage("test");
209
+ expect(exists).toBe(false);
210
+ removeEncryptedSessionStorage("test");
211
+ clearEncryptedSessionStorage();
212
+ }).not.toThrow();
213
+
214
+ global.window = originalWindow; // Restore
215
+ });
216
+
217
+ test("should handle corrupted storage data", () => {
218
+ const key = "corrupted_test";
219
+
220
+ // Manually put invalid encrypted data
221
+ mockSessionStorage.store.set(key, "invalid-base64-data!");
222
+
223
+ // Should throw error on corrupted data
224
+ expect(() => {
225
+ getEncryptedSessionStorage(key);
226
+ }).toThrow('Failed to retrieve encrypted data for key "corrupted_test"');
227
+ });
228
+ });
229
+ });
@@ -1,95 +1,95 @@
1
- /**
2
- * Simple and reliable encryption utilities using browser built-in functions
3
- * Uses TextEncoder/TextDecoder for proper Unicode support + XOR + Base64
4
- */
5
-
6
- const ENCRYPTION_KEY = "AutoBE_Secret_2024_v3.0_Unicode"; // Unicode-safe key
7
-
8
- /**
9
- * Simple encrypt using TextEncoder for Unicode safety
10
- *
11
- * @param text - Text to encrypt
12
- * @returns Encrypted base64 string
13
- */
14
- export const encrypt = (text: string): string => {
15
- if (!text) return "";
16
-
17
- try {
18
- // Use TextEncoder for proper Unicode → UTF-8 bytes conversion
19
- const encoder = new TextEncoder();
20
- const textBytes = encoder.encode(text);
21
-
22
- // Generate simple salt
23
- const salt = Math.random().toString(36).substring(2, 10);
24
- const keyBytes = encoder.encode(ENCRYPTION_KEY + salt);
25
-
26
- // XOR encryption on bytes level
27
- const encryptedBytes = new Uint8Array(textBytes.length);
28
- for (let i = 0; i < textBytes.length; i++) {
29
- encryptedBytes[i] = textBytes[i] ^ keyBytes[i % keyBytes.length];
30
- }
31
-
32
- // Convert to hex string for safe concatenation
33
- const encryptedHex = Array.from(encryptedBytes)
34
- .map((b) => b.toString(16).padStart(2, "0"))
35
- .join("");
36
-
37
- // Combine salt + encrypted hex
38
- const combined = salt + ":" + encryptedHex;
39
-
40
- // Base64 encode the final result (handle Unicode properly)
41
- const result = btoa(unescape(encodeURIComponent(combined)));
42
- return result;
43
- } catch (error) {
44
- throw new Error(
45
- `Encryption failed: ${error instanceof Error ? error.message : String(error)}`,
46
- );
47
- }
48
- };
49
-
50
- /**
51
- * Simple decrypt using TextDecoder for Unicode safety
52
- *
53
- * @param encryptedText - Base64 encrypted string
54
- * @returns Decrypted plain text
55
- */
56
- export const decrypt = (encryptedText: string): string => {
57
- if (!encryptedText) return "";
58
-
59
- try {
60
- // Base64 decode (handle Unicode properly)
61
- const combined = decodeURIComponent(escape(atob(encryptedText)));
62
- const parts = combined.split(":");
63
-
64
- if (parts.length !== 2) {
65
- throw new Error("Invalid encrypted format: expected salt:data format");
66
- }
67
-
68
- const salt = parts[0];
69
- const encryptedHex = parts[1];
70
-
71
- // Convert hex back to bytes
72
- const encryptedBytes = new Uint8Array(
73
- encryptedHex.match(/.{2}/g)?.map((hex) => parseInt(hex, 16)) || [],
74
- );
75
-
76
- // Recreate key
77
- const encoder = new TextEncoder();
78
- const keyBytes = encoder.encode(ENCRYPTION_KEY + salt);
79
-
80
- // XOR decryption
81
- const decryptedBytes = new Uint8Array(encryptedBytes.length);
82
- for (let i = 0; i < encryptedBytes.length; i++) {
83
- decryptedBytes[i] = encryptedBytes[i] ^ keyBytes[i % keyBytes.length];
84
- }
85
-
86
- // Use TextDecoder for proper UTF-8 → Unicode conversion
87
- const decoder = new TextDecoder();
88
- const result = decoder.decode(decryptedBytes);
89
- return result;
90
- } catch (error) {
91
- throw new Error(
92
- `Decryption failed: ${error instanceof Error ? error.message : String(error)}`,
93
- );
94
- }
95
- };
1
+ /**
2
+ * Simple and reliable encryption utilities using browser built-in functions
3
+ * Uses TextEncoder/TextDecoder for proper Unicode support + XOR + Base64
4
+ */
5
+
6
+ const ENCRYPTION_KEY = "AutoBE_Secret_2024_v3.0_Unicode"; // Unicode-safe key
7
+
8
+ /**
9
+ * Simple encrypt using TextEncoder for Unicode safety
10
+ *
11
+ * @param text - Text to encrypt
12
+ * @returns Encrypted base64 string
13
+ */
14
+ export const encrypt = (text: string): string => {
15
+ if (!text) return "";
16
+
17
+ try {
18
+ // Use TextEncoder for proper Unicode → UTF-8 bytes conversion
19
+ const encoder = new TextEncoder();
20
+ const textBytes = encoder.encode(text);
21
+
22
+ // Generate simple salt
23
+ const salt = Math.random().toString(36).substring(2, 10);
24
+ const keyBytes = encoder.encode(ENCRYPTION_KEY + salt);
25
+
26
+ // XOR encryption on bytes level
27
+ const encryptedBytes = new Uint8Array(textBytes.length);
28
+ for (let i = 0; i < textBytes.length; i++) {
29
+ encryptedBytes[i] = textBytes[i] ^ keyBytes[i % keyBytes.length];
30
+ }
31
+
32
+ // Convert to hex string for safe concatenation
33
+ const encryptedHex = Array.from(encryptedBytes)
34
+ .map((b) => b.toString(16).padStart(2, "0"))
35
+ .join("");
36
+
37
+ // Combine salt + encrypted hex
38
+ const combined = salt + ":" + encryptedHex;
39
+
40
+ // Base64 encode the final result (handle Unicode properly)
41
+ const result = btoa(unescape(encodeURIComponent(combined)));
42
+ return result;
43
+ } catch (error) {
44
+ throw new Error(
45
+ `Encryption failed: ${error instanceof Error ? error.message : String(error)}`,
46
+ );
47
+ }
48
+ };
49
+
50
+ /**
51
+ * Simple decrypt using TextDecoder for Unicode safety
52
+ *
53
+ * @param encryptedText - Base64 encrypted string
54
+ * @returns Decrypted plain text
55
+ */
56
+ export const decrypt = (encryptedText: string): string => {
57
+ if (!encryptedText) return "";
58
+
59
+ try {
60
+ // Base64 decode (handle Unicode properly)
61
+ const combined = decodeURIComponent(escape(atob(encryptedText)));
62
+ const parts = combined.split(":");
63
+
64
+ if (parts.length !== 2) {
65
+ throw new Error("Invalid encrypted format: expected salt:data format");
66
+ }
67
+
68
+ const salt = parts[0];
69
+ const encryptedHex = parts[1];
70
+
71
+ // Convert hex back to bytes
72
+ const encryptedBytes = new Uint8Array(
73
+ encryptedHex.match(/.{2}/g)?.map((hex) => parseInt(hex, 16)) || [],
74
+ );
75
+
76
+ // Recreate key
77
+ const encoder = new TextEncoder();
78
+ const keyBytes = encoder.encode(ENCRYPTION_KEY + salt);
79
+
80
+ // XOR decryption
81
+ const decryptedBytes = new Uint8Array(encryptedBytes.length);
82
+ for (let i = 0; i < encryptedBytes.length; i++) {
83
+ decryptedBytes[i] = encryptedBytes[i] ^ keyBytes[i % keyBytes.length];
84
+ }
85
+
86
+ // Use TextDecoder for proper UTF-8 → Unicode conversion
87
+ const decoder = new TextDecoder();
88
+ const result = decoder.decode(decryptedBytes);
89
+ return result;
90
+ } catch (error) {
91
+ throw new Error(
92
+ `Decryption failed: ${error instanceof Error ? error.message : String(error)}`,
93
+ );
94
+ }
95
+ };
@@ -1,6 +1,6 @@
1
- export * from "./AutoBeFileUploader";
2
- export * from "./AutoBeVoiceRecorder";
3
- export * from "./time";
4
- export * from "./crypto";
5
- export * from "./storage";
6
- export * from "./number";
1
+ export * from "./AutoBeFileUploader";
2
+ export * from "./AutoBeVoiceRecorder";
3
+ export * from "./time";
4
+ export * from "./crypto";
5
+ export * from "./storage";
6
+ export * from "./number";