@tomo-inc/wallet-utils 0.0.18 → 0.0.19
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/dist/index.cjs +5 -0
- package/dist/index.d.cts +8 -2
- package/dist/index.d.ts +8 -2
- package/dist/index.js +5 -0
- package/package.json +3 -2
- package/project.json +1 -1
- package/src/__tests__/browser.test.ts +130 -0
- package/src/__tests__/cache.test.ts +215 -0
- package/src/__tests__/email.test.ts +43 -0
- package/src/__tests__/global-config.test.ts +109 -0
- package/src/__tests__/index.test.ts +43 -0
- package/src/__tests__/password.test.ts +34 -0
- package/src/__tests__/string.test.ts +125 -0
- package/src/cache.ts +1 -1
- package/src/index.ts +5 -1
- package/vitest.config.ts +13 -0
package/dist/index.cjs
CHANGED
|
@@ -11,6 +11,7 @@ var cache_exports = {};
|
|
|
11
11
|
__export(cache_exports, {
|
|
12
12
|
clear: () => clear,
|
|
13
13
|
get: () => get,
|
|
14
|
+
isKeyExist: () => isKeyExist,
|
|
14
15
|
remove: () => remove,
|
|
15
16
|
set: () => set,
|
|
16
17
|
setKeyNS: () => setKeyNS
|
|
@@ -323,21 +324,25 @@ function calcCtrLength(str) {
|
|
|
323
324
|
|
|
324
325
|
// src/index.ts
|
|
325
326
|
var CubeStages = {
|
|
327
|
+
"prod-dogeos": "prod",
|
|
326
328
|
prod: "prod",
|
|
327
329
|
pre: "prod",
|
|
328
330
|
dev: "gamma"
|
|
329
331
|
};
|
|
330
332
|
var CubeOrgIds = {
|
|
333
|
+
"prod-dogeos": "Org#49944bce-9daf-423f-a982-269f6d0d301b",
|
|
331
334
|
prod: "Org#49944bce-9daf-423f-a982-269f6d0d301b",
|
|
332
335
|
pre: "Org#71c13f6d-b992-4660-874d-2ae0fadc789f",
|
|
333
336
|
dev: "Org#3d07a75a-1188-4bd0-acfa-671a198b83eb"
|
|
334
337
|
};
|
|
335
338
|
var RelayOrigins = {
|
|
339
|
+
"prod-dogeos": "https://social-relay.tomo.inc",
|
|
336
340
|
prod: "https://social-relay.tomo.inc",
|
|
337
341
|
pre: "https://social-relay.tomo.inc",
|
|
338
342
|
dev: "https://social-relay-dev.tomo.inc"
|
|
339
343
|
};
|
|
340
344
|
var TomoApiDomains = {
|
|
345
|
+
"prod-dogeos": "https://mydoge-wallet.tomo.inc",
|
|
341
346
|
prod: "https://wallet-pro.tomo.inc",
|
|
342
347
|
pre: "https://wallet-pre-wlfi.tomo.inc",
|
|
343
348
|
dev: "https://wallet-test.tomo.inc"
|
package/dist/index.d.cts
CHANGED
|
@@ -2,15 +2,17 @@ declare function get(key: string): any;
|
|
|
2
2
|
declare function set(key: string, val: any, isTemp: boolean): boolean;
|
|
3
3
|
declare function remove(key: string): void;
|
|
4
4
|
declare function clear(): void;
|
|
5
|
+
declare function isKeyExist(key: string): boolean;
|
|
5
6
|
declare function setKeyNS(NS: string): void;
|
|
6
7
|
|
|
7
8
|
declare const cache_clear: typeof clear;
|
|
8
9
|
declare const cache_get: typeof get;
|
|
10
|
+
declare const cache_isKeyExist: typeof isKeyExist;
|
|
9
11
|
declare const cache_remove: typeof remove;
|
|
10
12
|
declare const cache_set: typeof set;
|
|
11
13
|
declare const cache_setKeyNS: typeof setKeyNS;
|
|
12
14
|
declare namespace cache {
|
|
13
|
-
export { cache_clear as clear, cache_get as get, cache_remove as remove, cache_set as set, cache_setKeyNS as setKeyNS };
|
|
15
|
+
export { cache_clear as clear, cache_get as get, cache_isKeyExist as isKeyExist, cache_remove as remove, cache_set as set, cache_setKeyNS as setKeyNS };
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
declare const getBrowserName: () => string;
|
|
@@ -66,24 +68,28 @@ declare function calcCtrLength(str: string): {
|
|
|
66
68
|
originLen: number;
|
|
67
69
|
};
|
|
68
70
|
|
|
69
|
-
type TomoStage = "prod" | "pre" | "dev";
|
|
71
|
+
type TomoStage = "prod" | "pre" | "dev" | "prod-dogeos";
|
|
70
72
|
type CubeStage = "gamma" | "prod";
|
|
71
73
|
declare const CubeStages: {
|
|
74
|
+
"prod-dogeos": string;
|
|
72
75
|
prod: string;
|
|
73
76
|
pre: string;
|
|
74
77
|
dev: string;
|
|
75
78
|
};
|
|
76
79
|
declare const CubeOrgIds: {
|
|
80
|
+
"prod-dogeos": string;
|
|
77
81
|
prod: string;
|
|
78
82
|
pre: string;
|
|
79
83
|
dev: string;
|
|
80
84
|
};
|
|
81
85
|
declare const RelayOrigins: {
|
|
86
|
+
"prod-dogeos": string;
|
|
82
87
|
prod: string;
|
|
83
88
|
pre: string;
|
|
84
89
|
dev: string;
|
|
85
90
|
};
|
|
86
91
|
declare const TomoApiDomains: {
|
|
92
|
+
"prod-dogeos": string;
|
|
87
93
|
prod: string;
|
|
88
94
|
pre: string;
|
|
89
95
|
dev: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -2,15 +2,17 @@ declare function get(key: string): any;
|
|
|
2
2
|
declare function set(key: string, val: any, isTemp: boolean): boolean;
|
|
3
3
|
declare function remove(key: string): void;
|
|
4
4
|
declare function clear(): void;
|
|
5
|
+
declare function isKeyExist(key: string): boolean;
|
|
5
6
|
declare function setKeyNS(NS: string): void;
|
|
6
7
|
|
|
7
8
|
declare const cache_clear: typeof clear;
|
|
8
9
|
declare const cache_get: typeof get;
|
|
10
|
+
declare const cache_isKeyExist: typeof isKeyExist;
|
|
9
11
|
declare const cache_remove: typeof remove;
|
|
10
12
|
declare const cache_set: typeof set;
|
|
11
13
|
declare const cache_setKeyNS: typeof setKeyNS;
|
|
12
14
|
declare namespace cache {
|
|
13
|
-
export { cache_clear as clear, cache_get as get, cache_remove as remove, cache_set as set, cache_setKeyNS as setKeyNS };
|
|
15
|
+
export { cache_clear as clear, cache_get as get, cache_isKeyExist as isKeyExist, cache_remove as remove, cache_set as set, cache_setKeyNS as setKeyNS };
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
declare const getBrowserName: () => string;
|
|
@@ -66,24 +68,28 @@ declare function calcCtrLength(str: string): {
|
|
|
66
68
|
originLen: number;
|
|
67
69
|
};
|
|
68
70
|
|
|
69
|
-
type TomoStage = "prod" | "pre" | "dev";
|
|
71
|
+
type TomoStage = "prod" | "pre" | "dev" | "prod-dogeos";
|
|
70
72
|
type CubeStage = "gamma" | "prod";
|
|
71
73
|
declare const CubeStages: {
|
|
74
|
+
"prod-dogeos": string;
|
|
72
75
|
prod: string;
|
|
73
76
|
pre: string;
|
|
74
77
|
dev: string;
|
|
75
78
|
};
|
|
76
79
|
declare const CubeOrgIds: {
|
|
80
|
+
"prod-dogeos": string;
|
|
77
81
|
prod: string;
|
|
78
82
|
pre: string;
|
|
79
83
|
dev: string;
|
|
80
84
|
};
|
|
81
85
|
declare const RelayOrigins: {
|
|
86
|
+
"prod-dogeos": string;
|
|
82
87
|
prod: string;
|
|
83
88
|
pre: string;
|
|
84
89
|
dev: string;
|
|
85
90
|
};
|
|
86
91
|
declare const TomoApiDomains: {
|
|
92
|
+
"prod-dogeos": string;
|
|
87
93
|
prod: string;
|
|
88
94
|
pre: string;
|
|
89
95
|
dev: string;
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ var cache_exports = {};
|
|
|
9
9
|
__export(cache_exports, {
|
|
10
10
|
clear: () => clear,
|
|
11
11
|
get: () => get,
|
|
12
|
+
isKeyExist: () => isKeyExist,
|
|
12
13
|
remove: () => remove,
|
|
13
14
|
set: () => set,
|
|
14
15
|
setKeyNS: () => setKeyNS
|
|
@@ -321,21 +322,25 @@ function calcCtrLength(str) {
|
|
|
321
322
|
|
|
322
323
|
// src/index.ts
|
|
323
324
|
var CubeStages = {
|
|
325
|
+
"prod-dogeos": "prod",
|
|
324
326
|
prod: "prod",
|
|
325
327
|
pre: "prod",
|
|
326
328
|
dev: "gamma"
|
|
327
329
|
};
|
|
328
330
|
var CubeOrgIds = {
|
|
331
|
+
"prod-dogeos": "Org#49944bce-9daf-423f-a982-269f6d0d301b",
|
|
329
332
|
prod: "Org#49944bce-9daf-423f-a982-269f6d0d301b",
|
|
330
333
|
pre: "Org#71c13f6d-b992-4660-874d-2ae0fadc789f",
|
|
331
334
|
dev: "Org#3d07a75a-1188-4bd0-acfa-671a198b83eb"
|
|
332
335
|
};
|
|
333
336
|
var RelayOrigins = {
|
|
337
|
+
"prod-dogeos": "https://social-relay.tomo.inc",
|
|
334
338
|
prod: "https://social-relay.tomo.inc",
|
|
335
339
|
pre: "https://social-relay.tomo.inc",
|
|
336
340
|
dev: "https://social-relay-dev.tomo.inc"
|
|
337
341
|
};
|
|
338
342
|
var TomoApiDomains = {
|
|
343
|
+
"prod-dogeos": "https://mydoge-wallet.tomo.inc",
|
|
339
344
|
prod: "https://wallet-pro.tomo.inc",
|
|
340
345
|
pre: "https://wallet-pre-wlfi.tomo.inc",
|
|
341
346
|
dev: "https://wallet-test.tomo.inc"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tomo-inc/wallet-utils",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.19",
|
|
4
4
|
"author": "tomo.inc",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|
|
@@ -20,9 +20,10 @@
|
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@types/node": "^20.0.0",
|
|
23
|
+
"@vitest/coverage-v8": "4.0.14",
|
|
23
24
|
"tsup": "^8.0.0",
|
|
24
25
|
"typescript": "^5.0.0",
|
|
25
|
-
"vitest": "^
|
|
26
|
+
"vitest": "^4.0.14"
|
|
26
27
|
},
|
|
27
28
|
"scripts": {
|
|
28
29
|
"build": "tsup"
|
package/project.json
CHANGED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
2
|
+
import { getBrowserName } from "../broswer";
|
|
3
|
+
|
|
4
|
+
describe("browser utilities", () => {
|
|
5
|
+
const originalWindow = global.window;
|
|
6
|
+
const originalNavigator = global.navigator;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
// Reset window and navigator
|
|
10
|
+
delete (global as any).window;
|
|
11
|
+
delete (global as any).navigator;
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
global.window = originalWindow;
|
|
16
|
+
global.navigator = originalNavigator;
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe("getBrowserName", () => {
|
|
20
|
+
it("should return empty string in Node.js environment", () => {
|
|
21
|
+
expect(getBrowserName()).toBe("");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should detect Chrome", () => {
|
|
25
|
+
(global as any).window = {
|
|
26
|
+
navigator: {
|
|
27
|
+
userAgent:
|
|
28
|
+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
expect(getBrowserName()).toBe("Chrome");
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("should detect Safari", () => {
|
|
35
|
+
(global as any).window = {
|
|
36
|
+
navigator: {
|
|
37
|
+
userAgent:
|
|
38
|
+
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15",
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
expect(getBrowserName()).toBe("Safari");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("should detect Firefox", () => {
|
|
45
|
+
(global as any).window = {
|
|
46
|
+
navigator: {
|
|
47
|
+
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0",
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
expect(getBrowserName()).toBe("Firefox");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("should detect Edge", () => {
|
|
54
|
+
(global as any).window = {
|
|
55
|
+
navigator: {
|
|
56
|
+
userAgent:
|
|
57
|
+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0",
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
expect(getBrowserName()).toBe("Edge");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("should detect Opera", () => {
|
|
64
|
+
// According to the code, Chrome detection (line 22) comes before Opera detection (line 32)
|
|
65
|
+
// So if userAgent contains "Chrome/", it will be detected as Chrome
|
|
66
|
+
// We test with Opera/ prefix (older Opera versions that don't include Chrome/)
|
|
67
|
+
(global as any).window = {
|
|
68
|
+
navigator: {
|
|
69
|
+
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Opera/12.0",
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
expect(getBrowserName()).toBe("Opera");
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("should detect Opera with OPR (but will be detected as Chrome due to code order)", () => {
|
|
76
|
+
// Modern Opera includes "Chrome/" in userAgent, so it will be detected as Chrome
|
|
77
|
+
// This test documents the actual behavior
|
|
78
|
+
(global as any).window = {
|
|
79
|
+
navigator: {
|
|
80
|
+
userAgent:
|
|
81
|
+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 OPR/106.0.0.0",
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
// Due to code order, Chrome detection comes first, so this returns "Chrome"
|
|
85
|
+
expect(getBrowserName()).toBe("Chrome");
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("should detect Brave when userAgent does not contain Chrome/ or Safari/", () => {
|
|
89
|
+
// Brave detection relies on navigator.brave
|
|
90
|
+
// But Chrome detection (line 22) comes before Brave detection (line 26)
|
|
91
|
+
// Also Safari detection (line 9) comes before Brave
|
|
92
|
+
// So we need userAgent that doesn't match Safari or Chrome
|
|
93
|
+
// We test with userAgent that doesn't have Chrome/ or Safari/ but has brave property
|
|
94
|
+
(global as any).window = {
|
|
95
|
+
navigator: {
|
|
96
|
+
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)",
|
|
97
|
+
brave: {
|
|
98
|
+
isBrave: vi.fn(() => true),
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
expect(getBrowserName()).toBe("Brave");
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("should detect Chrome even with brave property when userAgent contains Chrome/", () => {
|
|
106
|
+
// This documents the actual behavior: Chrome detection comes before Brave
|
|
107
|
+
// So even if navigator.brave exists, if userAgent has "Chrome/", it returns "Chrome"
|
|
108
|
+
(global as any).window = {
|
|
109
|
+
navigator: {
|
|
110
|
+
userAgent:
|
|
111
|
+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
|
112
|
+
brave: {
|
|
113
|
+
isBrave: vi.fn(() => true),
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
// Due to code order, Chrome detection comes first
|
|
118
|
+
expect(getBrowserName()).toBe("Chrome");
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("should return empty string for unknown browser", () => {
|
|
122
|
+
(global as any).window = {
|
|
123
|
+
navigator: {
|
|
124
|
+
userAgent: "Unknown Browser/1.0",
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
expect(getBrowserName()).toBe("");
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
});
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
2
|
+
import { get, set, remove, clear, isKeyExist, setKeyNS } from "../cache";
|
|
3
|
+
|
|
4
|
+
// Mock localStorage and sessionStorage
|
|
5
|
+
const createStorageMock = () => {
|
|
6
|
+
const store: Record<string, string> = {};
|
|
7
|
+
const mock: any = {
|
|
8
|
+
getItem: vi.fn((key: string) => store[key] || null),
|
|
9
|
+
setItem: vi.fn((key: string, value: string) => {
|
|
10
|
+
store[key] = value.toString();
|
|
11
|
+
// Also set as property for hasOwnProperty check
|
|
12
|
+
mock[key] = value.toString();
|
|
13
|
+
}),
|
|
14
|
+
removeItem: vi.fn((key: string) => {
|
|
15
|
+
delete store[key];
|
|
16
|
+
delete mock[key];
|
|
17
|
+
}),
|
|
18
|
+
clear: vi.fn(() => {
|
|
19
|
+
Object.keys(store).forEach((key) => {
|
|
20
|
+
delete store[key];
|
|
21
|
+
delete mock[key];
|
|
22
|
+
});
|
|
23
|
+
}),
|
|
24
|
+
get length() {
|
|
25
|
+
return Object.keys(store).length;
|
|
26
|
+
},
|
|
27
|
+
key: vi.fn((index: number) => Object.keys(store)[index] || null),
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
return mock;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const localStorageMock = createStorageMock();
|
|
34
|
+
const sessionStorageMock = createStorageMock();
|
|
35
|
+
|
|
36
|
+
describe("cache utilities", () => {
|
|
37
|
+
beforeEach(() => {
|
|
38
|
+
// Reset stores
|
|
39
|
+
localStorageMock.clear();
|
|
40
|
+
sessionStorageMock.clear();
|
|
41
|
+
// Reset mocks
|
|
42
|
+
vi.clearAllMocks();
|
|
43
|
+
// Set up window object
|
|
44
|
+
(global as any).window = {
|
|
45
|
+
localStorage: localStorageMock,
|
|
46
|
+
sessionStorage: sessionStorageMock,
|
|
47
|
+
};
|
|
48
|
+
// Reset key namespace
|
|
49
|
+
setKeyNS("tomo-");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe("set and get", () => {
|
|
53
|
+
it("should set and get value from localStorage", () => {
|
|
54
|
+
const result = set("test-key", "test-value", false);
|
|
55
|
+
expect(result).toBe(true);
|
|
56
|
+
expect(localStorageMock.setItem).toHaveBeenCalled();
|
|
57
|
+
|
|
58
|
+
const value = get("test-key");
|
|
59
|
+
expect(value).toBe("test-value");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("should set and get value from sessionStorage", () => {
|
|
63
|
+
const result = set("test-key", "test-value", true);
|
|
64
|
+
expect(result).toBe(true);
|
|
65
|
+
expect(sessionStorageMock.setItem).toHaveBeenCalled();
|
|
66
|
+
|
|
67
|
+
const value = get("test-key");
|
|
68
|
+
expect(value).toBe("test-value");
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("should set and get complex objects", () => {
|
|
72
|
+
const obj = { name: "test", count: 123 };
|
|
73
|
+
set("obj-key", obj, false);
|
|
74
|
+
const value = get("obj-key");
|
|
75
|
+
expect(value).toEqual(obj);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("should set and get arrays", () => {
|
|
79
|
+
const arr = [1, 2, 3];
|
|
80
|
+
set("arr-key", arr, false);
|
|
81
|
+
const value = get("arr-key");
|
|
82
|
+
expect(value).toEqual(arr);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe("remove", () => {
|
|
87
|
+
it("should remove key from both storages", () => {
|
|
88
|
+
set("test-key", "value", false);
|
|
89
|
+
remove("test-key");
|
|
90
|
+
expect(localStorageMock.removeItem).toHaveBeenCalled();
|
|
91
|
+
expect(sessionStorageMock.removeItem).toHaveBeenCalled();
|
|
92
|
+
|
|
93
|
+
const value = get("test-key");
|
|
94
|
+
expect(value).toBeNull();
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe("clear", () => {
|
|
99
|
+
it("should clear both storages", () => {
|
|
100
|
+
set("key1", "value1", false);
|
|
101
|
+
set("key2", "value2", true);
|
|
102
|
+
clear();
|
|
103
|
+
expect(localStorageMock.clear).toHaveBeenCalled();
|
|
104
|
+
expect(sessionStorageMock.clear).toHaveBeenCalled();
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
describe("setKeyNS", () => {
|
|
109
|
+
it("should change key namespace", () => {
|
|
110
|
+
setKeyNS("custom-");
|
|
111
|
+
set("test-key", "value", false);
|
|
112
|
+
expect(localStorageMock.setItem).toHaveBeenCalledWith("custom-test-key", expect.any(String));
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("should not change namespace if empty string", () => {
|
|
116
|
+
setKeyNS("custom-");
|
|
117
|
+
setKeyNS("");
|
|
118
|
+
set("test-key", "value", false);
|
|
119
|
+
// Should still use the previous namespace
|
|
120
|
+
expect(localStorageMock.setItem).toHaveBeenCalledWith("custom-test-key", expect.any(String));
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("should not change namespace if not a string", () => {
|
|
124
|
+
setKeyNS("prefix-");
|
|
125
|
+
setKeyNS(123 as any);
|
|
126
|
+
set("k", "v", false);
|
|
127
|
+
expect(localStorageMock.setItem).toHaveBeenCalledWith("prefix-k", expect.any(String));
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
describe("edge cases", () => {
|
|
132
|
+
it("should return null for non-existent key", () => {
|
|
133
|
+
const value = get("non-existent");
|
|
134
|
+
expect(value).toBeNull();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("should handle invalid JSON gracefully", () => {
|
|
138
|
+
// Key must exist so get() proceeds to getItem and JSON.parse (hits catch)
|
|
139
|
+
set("corrupted-key", "x", false);
|
|
140
|
+
const errSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
141
|
+
localStorageMock.getItem = vi.fn(() => "invalid json");
|
|
142
|
+
const value = get("corrupted-key");
|
|
143
|
+
expect(value).toBeNull();
|
|
144
|
+
expect(errSpy).toHaveBeenCalled();
|
|
145
|
+
errSpy.mockRestore();
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("should return null when val has wrong format (no type/data)", () => {
|
|
149
|
+
// Key must exist so get() reaches getItem and the format check (lines 39-46)
|
|
150
|
+
set("bad-format", "x", false);
|
|
151
|
+
localStorageMock.getItem = vi.fn(() => JSON.stringify({ foo: "bar" }));
|
|
152
|
+
const value = get("bad-format");
|
|
153
|
+
expect(value).toBeNull();
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe("SSR / no window", () => {
|
|
158
|
+
it("get should return null when window is undefined", () => {
|
|
159
|
+
delete (global as any).window;
|
|
160
|
+
const value = get("any-key");
|
|
161
|
+
expect(value).toBeNull();
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("set should return false when window is undefined", () => {
|
|
165
|
+
delete (global as any).window;
|
|
166
|
+
const result = set("key", "value", false);
|
|
167
|
+
expect(result).toBe(false);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("remove should no-op when window is undefined", () => {
|
|
171
|
+
delete (global as any).window;
|
|
172
|
+
expect(() => remove("key")).not.toThrow();
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("clear should no-op when window is undefined", () => {
|
|
176
|
+
delete (global as any).window;
|
|
177
|
+
expect(() => clear()).not.toThrow();
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("isKeyExist should return false when window is undefined", () => {
|
|
181
|
+
delete (global as any).window;
|
|
182
|
+
expect(isKeyExist("any-key")).toBe(false);
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
describe("set QUOTA exceeded", () => {
|
|
187
|
+
it("should clear and retry setItem when QUOTA error", () => {
|
|
188
|
+
const clearSpy = vi.spyOn(localStorageMock, "clear");
|
|
189
|
+
let callCount = 0;
|
|
190
|
+
localStorageMock.setItem = vi.fn((key: string, value: string) => {
|
|
191
|
+
callCount++;
|
|
192
|
+
if (callCount === 1) {
|
|
193
|
+
const err = new Error("QuotaExceededError") as Error & { name?: string };
|
|
194
|
+
err.name = "QuotaExceededError";
|
|
195
|
+
throw err;
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
const result = set("quota-key", "value", false);
|
|
199
|
+
expect(clearSpy).toHaveBeenCalled();
|
|
200
|
+
expect(localStorageMock.setItem).toHaveBeenCalledTimes(2);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("should return false when setItem throws non-QUOTA error (catch branch)", () => {
|
|
204
|
+
localStorageMock.setItem = vi.fn(() => {
|
|
205
|
+
const err = new Error("SecurityError") as Error & { name?: string };
|
|
206
|
+
err.name = "SecurityError";
|
|
207
|
+
throw err;
|
|
208
|
+
});
|
|
209
|
+
const result = set("sec-key", "value", false);
|
|
210
|
+
expect(result).toBe(false);
|
|
211
|
+
expect(localStorageMock.setItem).toHaveBeenCalledTimes(1);
|
|
212
|
+
expect(localStorageMock.clear).not.toHaveBeenCalled();
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { maskEmail, isEmail } from "../email";
|
|
3
|
+
|
|
4
|
+
describe("email utilities", () => {
|
|
5
|
+
describe("maskEmail", () => {
|
|
6
|
+
it("should mask email with username length >= 4", () => {
|
|
7
|
+
expect(maskEmail("alice@example.com")).toBe("al***@example.com");
|
|
8
|
+
// "testuser" has 8 chars, slice(0, -3) = "testu", so result is "testu***"
|
|
9
|
+
expect(maskEmail("testuser@example.com")).toBe("testu***@example.com");
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("should mask email with username length < 4", () => {
|
|
13
|
+
expect(maskEmail("abc@example.com")).toBe("abc*@example.com");
|
|
14
|
+
expect(maskEmail("ab@example.com")).toBe("ab**@example.com");
|
|
15
|
+
expect(maskEmail("a@example.com")).toBe("a***@example.com");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("should return undefined for empty email", () => {
|
|
19
|
+
expect(maskEmail("")).toBeUndefined();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("should return null for invalid email format", () => {
|
|
23
|
+
expect(maskEmail("invalid")).toBeNull();
|
|
24
|
+
expect(maskEmail("no-at-sign")).toBeNull();
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe("isEmail", () => {
|
|
29
|
+
it("should validate correct email addresses", () => {
|
|
30
|
+
expect(isEmail("test@example.com")).toBe(true);
|
|
31
|
+
expect(isEmail("user.name@example.co.uk")).toBe(true);
|
|
32
|
+
expect(isEmail("user+tag@example.com")).toBe(true);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("should reject invalid email addresses", () => {
|
|
36
|
+
expect(isEmail("invalid")).toBe(false);
|
|
37
|
+
expect(isEmail("@example.com")).toBe(false);
|
|
38
|
+
expect(isEmail("test@")).toBe(false);
|
|
39
|
+
expect(isEmail("test@example")).toBe(false);
|
|
40
|
+
expect(isEmail("test @example.com")).toBe(false);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
ChainTypeEnum,
|
|
4
|
+
SupportedChainTypes,
|
|
5
|
+
ProviderProtocol,
|
|
6
|
+
ProviderStandard,
|
|
7
|
+
} from "../global-config";
|
|
8
|
+
|
|
9
|
+
describe("global-config", () => {
|
|
10
|
+
describe("ChainTypeEnum", () => {
|
|
11
|
+
it("should have all chain types defined", () => {
|
|
12
|
+
expect(ChainTypeEnum.BITCOIN).toBe("bitcoin");
|
|
13
|
+
expect(ChainTypeEnum.DOGECOIN).toBe("dogecoin");
|
|
14
|
+
expect(ChainTypeEnum.EVM).toBe("evm");
|
|
15
|
+
expect(ChainTypeEnum.SOLANA).toBe("solana");
|
|
16
|
+
expect(ChainTypeEnum.SUI).toBe("sui");
|
|
17
|
+
expect(ChainTypeEnum.TON).toBe("ton");
|
|
18
|
+
expect(ChainTypeEnum.TRON).toBe("tron");
|
|
19
|
+
expect(ChainTypeEnum.COSMOS).toBe("cosmos");
|
|
20
|
+
expect(ChainTypeEnum.APTOS).toBe("aptos");
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe("SupportedChainTypes", () => {
|
|
25
|
+
it("should have configuration for DOGECOIN chain", () => {
|
|
26
|
+
const config = SupportedChainTypes[ChainTypeEnum.DOGECOIN];
|
|
27
|
+
expect(config.chainId).toBe("3");
|
|
28
|
+
expect(config.chainIndex).toBe(300);
|
|
29
|
+
expect(config.support).toBe(true);
|
|
30
|
+
expect(config.gasFee).toBe(0.5);
|
|
31
|
+
expect(config.dust).toBe(0.0001);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("should have configuration for EVM chain", () => {
|
|
35
|
+
const config = SupportedChainTypes[ChainTypeEnum.EVM];
|
|
36
|
+
expect(config.chainId).toBe("1");
|
|
37
|
+
expect(config.chainIndex).toBe(100);
|
|
38
|
+
expect(config.support).toBe(true);
|
|
39
|
+
expect(config.gasFee).toBe(0.00001);
|
|
40
|
+
expect(config.dust).toBe(0);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("should have configuration for SOLANA chain", () => {
|
|
44
|
+
const config = SupportedChainTypes[ChainTypeEnum.SOLANA];
|
|
45
|
+
expect(config.chainId).toBe("501");
|
|
46
|
+
expect(config.chainIndex).toBe(50100);
|
|
47
|
+
expect(config.support).toBe(true);
|
|
48
|
+
expect(config.gasFee).toBe(0.0001);
|
|
49
|
+
expect(config.dust).toBe(0);
|
|
50
|
+
expect(config.reserve).toBe(0.0009);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("should have configuration for TRON chain", () => {
|
|
54
|
+
const config = SupportedChainTypes[ChainTypeEnum.TRON];
|
|
55
|
+
expect(config.chainId).toBe("19484");
|
|
56
|
+
expect(config.chainIndex).toBe(1948400);
|
|
57
|
+
expect(config.support).toBe(true);
|
|
58
|
+
expect(config.gasFee).toBe(0.5);
|
|
59
|
+
expect(config.dust).toBe(0);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("should have configuration for BITCOIN chain", () => {
|
|
63
|
+
const config = SupportedChainTypes[ChainTypeEnum.BITCOIN];
|
|
64
|
+
expect(config.chainId).toBe("0");
|
|
65
|
+
expect(config.chainIndex).toBe(0);
|
|
66
|
+
expect(config.support).toBe(false);
|
|
67
|
+
expect(config.gasFee).toBe(0.00001);
|
|
68
|
+
expect(config.dust).toBe(0.0001);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("should have configuration for unsupported chains", () => {
|
|
72
|
+
const unsupportedChains = [
|
|
73
|
+
ChainTypeEnum.SUI,
|
|
74
|
+
ChainTypeEnum.TON,
|
|
75
|
+
ChainTypeEnum.COSMOS,
|
|
76
|
+
ChainTypeEnum.APTOS,
|
|
77
|
+
];
|
|
78
|
+
unsupportedChains.forEach((chainType) => {
|
|
79
|
+
const config = SupportedChainTypes[chainType];
|
|
80
|
+
expect(config.support).toBe(false);
|
|
81
|
+
expect(config.gasFee).toBe(0);
|
|
82
|
+
expect(config.dust).toBe(0);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("should have all ChainTypeEnum in SupportedChainTypes", () => {
|
|
87
|
+
const allChainTypes = Object.values(ChainTypeEnum);
|
|
88
|
+
allChainTypes.forEach((chainType) => {
|
|
89
|
+
expect(SupportedChainTypes[chainType]).toBeDefined();
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe("ProviderProtocol", () => {
|
|
95
|
+
it("should have expected values", () => {
|
|
96
|
+
expect(ProviderProtocol.INJECT).toBe("inject");
|
|
97
|
+
expect(ProviderProtocol.DEEPLINK).toBe("deeplink");
|
|
98
|
+
expect(ProviderProtocol.WALLET_CONNECT).toBe("wallet-connect");
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe("ProviderStandard", () => {
|
|
103
|
+
it("should have expected values", () => {
|
|
104
|
+
expect(ProviderStandard.NORMAL).toBe("normal");
|
|
105
|
+
expect(ProviderStandard.EIP1193).toBe("eip1193");
|
|
106
|
+
expect(ProviderStandard.WALLET_STANDARD).toBe("wallet-standard");
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
cache,
|
|
4
|
+
CubeStages,
|
|
5
|
+
CubeOrgIds,
|
|
6
|
+
RelayOrigins,
|
|
7
|
+
TomoApiDomains,
|
|
8
|
+
} from "../index";
|
|
9
|
+
|
|
10
|
+
describe("index", () => {
|
|
11
|
+
it("should export cache module", () => {
|
|
12
|
+
expect(cache).toBeDefined();
|
|
13
|
+
expect(cache.get).toBeDefined();
|
|
14
|
+
expect(cache.set).toBeDefined();
|
|
15
|
+
expect(cache.remove).toBeDefined();
|
|
16
|
+
expect(cache.clear).toBeDefined();
|
|
17
|
+
expect(cache.setKeyNS).toBeDefined();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("CubeStages should map stage to cube stage", () => {
|
|
21
|
+
expect(CubeStages.prod).toBe("prod");
|
|
22
|
+
expect(CubeStages.pre).toBe("prod");
|
|
23
|
+
expect(CubeStages.dev).toBe("gamma");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("CubeOrgIds should have org ids per stage", () => {
|
|
27
|
+
expect(CubeOrgIds.prod).toMatch(/^Org#/);
|
|
28
|
+
expect(CubeOrgIds.pre).toMatch(/^Org#/);
|
|
29
|
+
expect(CubeOrgIds.dev).toMatch(/^Org#/);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("RelayOrigins should have relay URLs", () => {
|
|
33
|
+
expect(RelayOrigins.prod).toBe("https://social-relay.tomo.inc");
|
|
34
|
+
expect(RelayOrigins.pre).toBe("https://social-relay.tomo.inc");
|
|
35
|
+
expect(RelayOrigins.dev).toBe("https://social-relay-dev.tomo.inc");
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("TomoApiDomains should have wallet API URLs", () => {
|
|
39
|
+
expect(TomoApiDomains.prod).toContain("tomo.inc");
|
|
40
|
+
expect(TomoApiDomains.pre).toContain("tomo.inc");
|
|
41
|
+
expect(TomoApiDomains.dev).toContain("tomo.inc");
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { validatePassword } from "../password";
|
|
3
|
+
|
|
4
|
+
describe("password validation", () => {
|
|
5
|
+
it("should validate password with letters and numbers", () => {
|
|
6
|
+
expect(validatePassword("password123")).toBe(true);
|
|
7
|
+
expect(validatePassword("Password123")).toBe(true);
|
|
8
|
+
expect(validatePassword("PASSWORD123")).toBe(true);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("should reject password without letters", () => {
|
|
12
|
+
expect(validatePassword("12345678")).toBe(false);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("should reject password without numbers", () => {
|
|
16
|
+
expect(validatePassword("password")).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should reject password too short", () => {
|
|
20
|
+
expect(validatePassword("pass123")).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("should reject password too long", () => {
|
|
24
|
+
expect(validatePassword("a".repeat(33) + "123")).toBe(false);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("should accept password with exactly 8 characters", () => {
|
|
28
|
+
expect(validatePassword("pass1234")).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("should accept password with exactly 32 characters", () => {
|
|
32
|
+
expect(validatePassword("a".repeat(30) + "12")).toBe(true);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { stripHexPrefix, compareString, subs, getExplorerUrl, calcCtrLength } from "../string";
|
|
3
|
+
|
|
4
|
+
describe("string utilities", () => {
|
|
5
|
+
describe("stripHexPrefix", () => {
|
|
6
|
+
it("should strip 0x prefix", () => {
|
|
7
|
+
expect(stripHexPrefix("0x123abc")).toBe("123abc");
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("should return original string if no prefix", () => {
|
|
11
|
+
expect(stripHexPrefix("123abc")).toBe("123abc");
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should handle non-string input", () => {
|
|
15
|
+
expect(stripHexPrefix(123 as any)).toBe(123);
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe("compareString", () => {
|
|
20
|
+
it("should compare strings case-insensitively", () => {
|
|
21
|
+
expect(compareString("Hello", "hello")).toBe(true);
|
|
22
|
+
expect(compareString("WORLD", "world")).toBe(true);
|
|
23
|
+
expect(compareString("Test", "test")).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("should return false for different strings", () => {
|
|
27
|
+
expect(compareString("Hello", "World")).toBe(false);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe("subs", () => {
|
|
32
|
+
it("should substitute template variables", () => {
|
|
33
|
+
const template = "Hello {name}, you are {age} years old";
|
|
34
|
+
const data = { name: "Alice", age: 30 };
|
|
35
|
+
const result = subs(template, data);
|
|
36
|
+
expect(result).toBe("Hello Alice, you are 30 years old");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("should handle array of objects", () => {
|
|
40
|
+
const template = "{name}: {value}";
|
|
41
|
+
const data = [
|
|
42
|
+
{ name: "key1", value: "value1" },
|
|
43
|
+
{ name: "key2", value: "value2" },
|
|
44
|
+
];
|
|
45
|
+
const result = subs(template, data);
|
|
46
|
+
expect(result).toBe("key1: value1key2: value2");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("should handle escaped braces", () => {
|
|
50
|
+
// In the string "\\{literal\\}", the backslashes escape the braces
|
|
51
|
+
// The regex /\\?\{([^}]+)\}/g matches \{literal\}, and since match.charAt(0) == "\\",
|
|
52
|
+
// it returns match.slice(1) which is "{literal\}"
|
|
53
|
+
const template = "\\{literal\\} {name}";
|
|
54
|
+
const data = { name: "Alice" };
|
|
55
|
+
const result = subs(template, data);
|
|
56
|
+
// The actual behavior: escaped braces become "{literal\}" (backslash is preserved)
|
|
57
|
+
expect(result).toBe("{literal\\} Alice");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("should handle missing variables", () => {
|
|
61
|
+
const template = "Hello {name}, {missing}";
|
|
62
|
+
const data = { name: "Alice" };
|
|
63
|
+
const result = subs(template, data);
|
|
64
|
+
expect(result).toBe("Hello Alice, ");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("should use custom regexp when provided", () => {
|
|
68
|
+
const template = "Hello {{name}}";
|
|
69
|
+
const data = { name: "Bob" };
|
|
70
|
+
const result = subs(template, data, /\{\{([^}]+)\}\}/g);
|
|
71
|
+
expect(result).toBe("Hello Bob");
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe("getExplorerUrl", () => {
|
|
76
|
+
it("should return correct explorer URL for Ethereum", () => {
|
|
77
|
+
const url = getExplorerUrl(100, { txId: "0x123" });
|
|
78
|
+
expect(url).toBe("https://etherscan.io/tx/0x123");
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("should return correct explorer URL for Solana", () => {
|
|
82
|
+
const url = getExplorerUrl(50100, { txId: "abc123" });
|
|
83
|
+
expect(url).toBe("https://solscan.io/tx/abc123");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("should return correct explorer URL for BSC", () => {
|
|
87
|
+
const url = getExplorerUrl(5600, { txId: "0x456" });
|
|
88
|
+
expect(url).toBe("https://bscscan.com/tx/0x456");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("should throw error for unsupported chain", () => {
|
|
92
|
+
expect(() => getExplorerUrl(99999, { txId: "0x123" })).toThrow();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("should throw when chainIndex has no explorer tpl", () => {
|
|
96
|
+
expect(() => getExplorerUrl(0, { txId: "0x123" })).toThrow("chainIndex 0 tpl not found");
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe("calcCtrLength", () => {
|
|
101
|
+
it("should calculate length for English text", () => {
|
|
102
|
+
const result = calcCtrLength("Hello");
|
|
103
|
+
expect(result.len).toBe(5);
|
|
104
|
+
expect(result.originLen).toBe(5);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("should calculate length for Chinese text", () => {
|
|
108
|
+
const result = calcCtrLength("你好");
|
|
109
|
+
expect(result.len).toBe(4); // Chinese characters count as 2
|
|
110
|
+
expect(result.originLen).toBe(2);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("should handle mixed text", () => {
|
|
114
|
+
const result = calcCtrLength("Hello你好");
|
|
115
|
+
expect(result.len).toBe(9); // 5 + 4
|
|
116
|
+
expect(result.originLen).toBe(7); // 5 + 2
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("should trim whitespace", () => {
|
|
120
|
+
const result = calcCtrLength(" Hello ");
|
|
121
|
+
expect(result.len).toBe(5);
|
|
122
|
+
expect(result.originLen).toBe(5);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
});
|
package/src/cache.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -7,27 +7,31 @@ export * from "./global-config";
|
|
|
7
7
|
export * from "./password";
|
|
8
8
|
export * from "./string";
|
|
9
9
|
|
|
10
|
-
export type TomoStage = "prod" | "pre" | "dev";
|
|
10
|
+
export type TomoStage = "prod" | "pre" | "dev" | "prod-dogeos";
|
|
11
11
|
export type CubeStage = "gamma" | "prod";
|
|
12
12
|
export const CubeStages = {
|
|
13
|
+
"prod-dogeos": "prod",
|
|
13
14
|
prod: "prod",
|
|
14
15
|
pre: "prod",
|
|
15
16
|
dev: "gamma",
|
|
16
17
|
};
|
|
17
18
|
|
|
18
19
|
export const CubeOrgIds = {
|
|
20
|
+
"prod-dogeos": "Org#49944bce-9daf-423f-a982-269f6d0d301b",
|
|
19
21
|
prod: "Org#49944bce-9daf-423f-a982-269f6d0d301b",
|
|
20
22
|
pre: "Org#71c13f6d-b992-4660-874d-2ae0fadc789f",
|
|
21
23
|
dev: "Org#3d07a75a-1188-4bd0-acfa-671a198b83eb",
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
export const RelayOrigins = {
|
|
27
|
+
"prod-dogeos": "https://social-relay.tomo.inc",
|
|
25
28
|
prod: "https://social-relay.tomo.inc",
|
|
26
29
|
pre: "https://social-relay.tomo.inc",
|
|
27
30
|
dev: "https://social-relay-dev.tomo.inc",
|
|
28
31
|
};
|
|
29
32
|
|
|
30
33
|
export const TomoApiDomains = {
|
|
34
|
+
"prod-dogeos": "https://mydoge-wallet.tomo.inc",
|
|
31
35
|
prod: "https://wallet-pro.tomo.inc",
|
|
32
36
|
pre: "https://wallet-pre-wlfi.tomo.inc",
|
|
33
37
|
dev: "https://wallet-test.tomo.inc",
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { defineConfig } from "vitest/config";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
globals: true,
|
|
6
|
+
environment: "node",
|
|
7
|
+
coverage: {
|
|
8
|
+
provider: "v8",
|
|
9
|
+
reporter: ["text", "json", "html"],
|
|
10
|
+
exclude: ["node_modules/", "dist/", "**/*.config.*", "**/__tests__/**", "**/*.test.ts", "**/*.spec.ts"],
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
});
|