@xivdyetools/test-utils 1.0.2 → 1.1.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.
- package/README.md +15 -1
- package/dist/auth/jwt.d.ts.map +1 -1
- package/dist/auth/jwt.js +3 -2
- package/dist/auth/jwt.js.map +1 -1
- package/dist/cloudflare/d1.d.ts +27 -5
- package/dist/cloudflare/d1.d.ts.map +1 -1
- package/dist/cloudflare/d1.js +49 -3
- package/dist/cloudflare/d1.js.map +1 -1
- package/dist/cloudflare/fetcher.d.ts +12 -2
- package/dist/cloudflare/fetcher.d.ts.map +1 -1
- package/dist/cloudflare/fetcher.js +17 -2
- package/dist/cloudflare/fetcher.js.map +1 -1
- package/dist/cloudflare/kv.d.ts.map +1 -1
- package/dist/cloudflare/kv.js +44 -19
- package/dist/cloudflare/kv.js.map +1 -1
- package/dist/factories/index.d.ts +2 -2
- package/dist/factories/index.d.ts.map +1 -1
- package/dist/factories/index.js +4 -3
- package/dist/factories/index.js.map +1 -1
- package/dist/factories/vote.d.ts +4 -1
- package/dist/factories/vote.d.ts.map +1 -1
- package/dist/factories/vote.js +6 -4
- package/dist/factories/vote.js.map +1 -1
- package/dist/utils/counters.d.ts +30 -6
- package/dist/utils/counters.d.ts.map +1 -1
- package/dist/utils/counters.js +50 -8
- package/dist/utils/counters.js.map +1 -1
- package/dist/utils/crypto.d.ts +11 -1
- package/dist/utils/crypto.d.ts.map +1 -1
- package/dist/utils/crypto.js +24 -4
- package/dist/utils/crypto.js.map +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -139,6 +139,20 @@ const params = new URLSearchParams({
|
|
|
139
139
|
|
|
140
140
|
This package includes full TypeScript support. Cloudflare Workers types are included via `@cloudflare/workers-types`.
|
|
141
141
|
|
|
142
|
+
## Connect With Me
|
|
143
|
+
|
|
144
|
+
**Flash Galatine** | Balmung (Crystal)
|
|
145
|
+
|
|
146
|
+
🎮 **FFXIV**: [Lodestone Character](https://na.finalfantasyxiv.com/lodestone/character/7677106/)
|
|
147
|
+
📝 **Blog**: [Project Galatine](https://blog.projectgalatine.com/)
|
|
148
|
+
💻 **GitHub**: [@FlashGalatine](https://github.com/FlashGalatine)
|
|
149
|
+
🐦 **X / Twitter**: [@AsheJunius](https://x.com/AsheJunius)
|
|
150
|
+
📺 **Twitch**: [flashgalatine](https://www.twitch.tv/flashgalatine)
|
|
151
|
+
🌐 **BlueSky**: [projectgalatine.com](https://bsky.app/profile/projectgalatine.com)
|
|
152
|
+
❤️ **Patreon**: [ProjectGalatine](https://patreon.com/ProjectGalatine)
|
|
153
|
+
☕ **Ko-Fi**: [flashgalatine](https://ko-fi.com/flashgalatine)
|
|
154
|
+
💬 **Discord**: [Join Server](https://discord.gg/5VUSKTZCe5)
|
|
155
|
+
|
|
142
156
|
## License
|
|
143
157
|
|
|
144
|
-
MIT
|
|
158
|
+
MIT © 2025 Flash Galatine
|
package/dist/auth/jwt.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../src/auth/jwt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,wBAAwB;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,6BAA6B;IAC7B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,cAAe,SAAQ,cAAc;IACpD,iCAAiC;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,cAAc,EACvB,gBAAgB,SAAO,EACvB,MAAM,SAA6B,GAClC,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../src/auth/jwt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,wBAAwB;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,6BAA6B;IAC7B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,cAAe,SAAQ,cAAc;IACpD,iCAAiC;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,cAAc,EACvB,gBAAgB,SAAO,EACvB,MAAM,SAA6B,GAClC,OAAO,CAAC,MAAM,CAAC,CAgCjB;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,cAAiD,GACzD,OAAO,CAAC,MAAM,CAAC,CAGjB;AAED;;;;;;;GAOG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,cAAc,EACvB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,CAIjB"}
|
package/dist/auth/jwt.js
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* });
|
|
23
23
|
* ```
|
|
24
24
|
*/
|
|
25
|
-
import { base64UrlEncode } from '../utils/crypto.js';
|
|
25
|
+
import { base64UrlEncode, base64UrlEncodeBytes } from '../utils/crypto.js';
|
|
26
26
|
/**
|
|
27
27
|
* Creates a valid JWT for testing
|
|
28
28
|
*
|
|
@@ -47,7 +47,8 @@ export async function createTestJWT(secret, payload, expiresInSeconds = 3600, is
|
|
|
47
47
|
const signatureInput = `${encodedHeader}.${encodedPayload}`;
|
|
48
48
|
const key = await crypto.subtle.importKey('raw', encoder.encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
|
|
49
49
|
const signature = await crypto.subtle.sign('HMAC', key, encoder.encode(signatureInput));
|
|
50
|
-
|
|
50
|
+
// Use base64UrlEncodeBytes for binary signature data to avoid UTF-8 encoding issues
|
|
51
|
+
const encodedSignature = base64UrlEncodeBytes(new Uint8Array(signature));
|
|
51
52
|
return `${encodedHeader}.${encodedPayload}.${encodedSignature}`;
|
|
52
53
|
}
|
|
53
54
|
/**
|
package/dist/auth/jwt.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../src/auth/jwt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../src/auth/jwt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AA4B3E;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAc,EACd,OAAuB,EACvB,gBAAgB,GAAG,IAAI,EACvB,MAAM,GAAG,0BAA0B;IAEnC,MAAM,MAAM,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;IAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAE1C,MAAM,WAAW,GAAmB;QAClC,GAAG,OAAO;QACV,GAAG,EAAE,GAAG;QACR,GAAG,EAAE,GAAG,GAAG,gBAAgB;QAC3B,GAAG,EAAE,MAAM;KACZ,CAAC;IAEF,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAElC,MAAM,aAAa,GAAG,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9D,MAAM,cAAc,GAAG,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;IAEpE,MAAM,cAAc,GAAG,GAAG,aAAa,IAAI,cAAc,EAAE,CAAC;IAE5D,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CACvC,KAAK,EACL,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EACtB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,EACjC,KAAK,EACL,CAAC,MAAM,CAAC,CACT,CAAC;IAEF,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;IAExF,oFAAoF;IACpF,MAAM,gBAAgB,GAAG,oBAAoB,CAAC,IAAI,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;IAEzE,OAAO,GAAG,aAAa,IAAI,cAAc,IAAI,gBAAgB,EAAE,CAAC;AAClE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAc,EACd,UAA0B,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE;IAE1D,uCAAuC;IACvC,OAAO,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;AAC/C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,MAAc,EACd,OAAuB,EACvB,YAAoB;IAEpB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAC1C,MAAM,gBAAgB,GAAG,YAAY,GAAG,GAAG,CAAC;IAC5C,OAAO,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC;AAC1D,CAAC"}
|
package/dist/cloudflare/d1.d.ts
CHANGED
|
@@ -8,11 +8,15 @@
|
|
|
8
8
|
* ```typescript
|
|
9
9
|
* const db = createMockD1Database();
|
|
10
10
|
*
|
|
11
|
-
* // Setup mock responses
|
|
11
|
+
* // Setup mock responses using regex patterns (TEST-DESIGN-002)
|
|
12
|
+
* // Use /^\s*SELECT/i to anchor to start and be case-insensitive
|
|
12
13
|
* db._setupMock((query, bindings) => {
|
|
13
|
-
* if (
|
|
14
|
+
* if (/^\s*SELECT/i.test(query) && query.includes('presets')) {
|
|
14
15
|
* return [{ id: 'preset-1', name: 'Test Preset' }];
|
|
15
16
|
* }
|
|
17
|
+
* if (/^\s*INSERT/i.test(query)) {
|
|
18
|
+
* return { meta: { changes: 1, last_row_id: 1 } };
|
|
19
|
+
* }
|
|
16
20
|
* return null;
|
|
17
21
|
* });
|
|
18
22
|
*
|
|
@@ -79,6 +83,13 @@ export interface MockD1DatabaseSession {
|
|
|
79
83
|
/** Get constraint string for this session */
|
|
80
84
|
getBookmark: () => string;
|
|
81
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Configuration options for the mock D1 database
|
|
88
|
+
*/
|
|
89
|
+
export interface MockD1DatabaseConfig {
|
|
90
|
+
/** Maximum number of queries to keep in history (prevents memory leaks). Default: 1000 */
|
|
91
|
+
maxQueryHistory?: number;
|
|
92
|
+
}
|
|
82
93
|
/**
|
|
83
94
|
* Extended mock D1 database with test helpers
|
|
84
95
|
*/
|
|
@@ -92,9 +103,9 @@ export interface MockD1Database {
|
|
|
92
103
|
dump: () => Promise<ArrayBuffer>;
|
|
93
104
|
/** Start a session - returns a session object with same query methods */
|
|
94
105
|
withSession: (constraintOrBookmark?: string) => MockD1DatabaseSession;
|
|
95
|
-
/** Array of all queries executed (for assertions) */
|
|
106
|
+
/** Array of all queries executed (for assertions). Limited to maxQueryHistory entries. */
|
|
96
107
|
_queries: string[];
|
|
97
|
-
/** Array of all binding arrays passed to queries */
|
|
108
|
+
/** Array of all binding arrays passed to queries. Limited to maxQueryHistory entries. */
|
|
98
109
|
_bindings: unknown[][];
|
|
99
110
|
/** Setup a mock function to return custom responses */
|
|
100
111
|
_setupMock: (fn: QueryMockFn) => void;
|
|
@@ -102,6 +113,13 @@ export interface MockD1Database {
|
|
|
102
113
|
_reset: () => void;
|
|
103
114
|
/** Current mock function (if any) */
|
|
104
115
|
_mockFn?: QueryMockFn;
|
|
116
|
+
/**
|
|
117
|
+
* Set the ban status for ban-check middleware tests
|
|
118
|
+
* @param isBanned - true to simulate banned user, false or undefined for not banned
|
|
119
|
+
*/
|
|
120
|
+
_setBanStatus: (isBanned: boolean) => void;
|
|
121
|
+
/** Set the maximum query history size (for memory management) */
|
|
122
|
+
_setMaxQueryHistory: (max: number) => void;
|
|
105
123
|
}
|
|
106
124
|
/**
|
|
107
125
|
* Creates a mock D1 database for testing
|
|
@@ -109,9 +127,13 @@ export interface MockD1Database {
|
|
|
109
127
|
* The mock tracks all queries and bindings for assertions, and supports
|
|
110
128
|
* custom response functions for simulating database behavior.
|
|
111
129
|
*
|
|
130
|
+
* TEST-OPT-003 FIX: Added maxQueryHistory config to prevent unbounded memory growth
|
|
131
|
+
* in long-running test suites. Default is 1000 queries.
|
|
132
|
+
*
|
|
133
|
+
* @param config - Optional configuration for the mock database
|
|
112
134
|
* @returns A mock D1 database that can be cast to D1Database
|
|
113
135
|
*/
|
|
114
|
-
export declare function createMockD1Database(): MockD1Database;
|
|
136
|
+
export declare function createMockD1Database(config?: MockD1DatabaseConfig): MockD1Database;
|
|
115
137
|
/**
|
|
116
138
|
* Creates a mock D1 database pre-cast as D1Database
|
|
117
139
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"d1.d.ts","sourceRoot":"","sources":["../../src/cloudflare/d1.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"d1.d.ts","sourceRoot":"","sources":["../../src/cloudflare/d1.ts"],"names":[],"mappings":"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"}
|
package/dist/cloudflare/d1.js
CHANGED
|
@@ -8,11 +8,15 @@
|
|
|
8
8
|
* ```typescript
|
|
9
9
|
* const db = createMockD1Database();
|
|
10
10
|
*
|
|
11
|
-
* // Setup mock responses
|
|
11
|
+
* // Setup mock responses using regex patterns (TEST-DESIGN-002)
|
|
12
|
+
* // Use /^\s*SELECT/i to anchor to start and be case-insensitive
|
|
12
13
|
* db._setupMock((query, bindings) => {
|
|
13
|
-
* if (
|
|
14
|
+
* if (/^\s*SELECT/i.test(query) && query.includes('presets')) {
|
|
14
15
|
* return [{ id: 'preset-1', name: 'Test Preset' }];
|
|
15
16
|
* }
|
|
17
|
+
* if (/^\s*INSERT/i.test(query)) {
|
|
18
|
+
* return { meta: { changes: 1, last_row_id: 1 } };
|
|
19
|
+
* }
|
|
16
20
|
* return null;
|
|
17
21
|
* });
|
|
18
22
|
*
|
|
@@ -27,18 +31,36 @@
|
|
|
27
31
|
* db._reset();
|
|
28
32
|
* ```
|
|
29
33
|
*/
|
|
34
|
+
/** Default maximum query history size */
|
|
35
|
+
const DEFAULT_MAX_QUERY_HISTORY = 1000;
|
|
30
36
|
/**
|
|
31
37
|
* Creates a mock D1 database for testing
|
|
32
38
|
*
|
|
33
39
|
* The mock tracks all queries and bindings for assertions, and supports
|
|
34
40
|
* custom response functions for simulating database behavior.
|
|
35
41
|
*
|
|
42
|
+
* TEST-OPT-003 FIX: Added maxQueryHistory config to prevent unbounded memory growth
|
|
43
|
+
* in long-running test suites. Default is 1000 queries.
|
|
44
|
+
*
|
|
45
|
+
* @param config - Optional configuration for the mock database
|
|
36
46
|
* @returns A mock D1 database that can be cast to D1Database
|
|
37
47
|
*/
|
|
38
|
-
export function createMockD1Database() {
|
|
48
|
+
export function createMockD1Database(config) {
|
|
39
49
|
const queries = [];
|
|
40
50
|
const bindings = [];
|
|
41
51
|
let mockFn;
|
|
52
|
+
let banStatus;
|
|
53
|
+
let maxQueryHistory = config?.maxQueryHistory ?? DEFAULT_MAX_QUERY_HISTORY;
|
|
54
|
+
/**
|
|
55
|
+
* Enforce max query history limit using FIFO eviction
|
|
56
|
+
* TEST-OPT-003 FIX: Prevents unbounded memory growth
|
|
57
|
+
*/
|
|
58
|
+
const enforceMaxHistory = () => {
|
|
59
|
+
while (queries.length > maxQueryHistory) {
|
|
60
|
+
queries.shift();
|
|
61
|
+
bindings.shift();
|
|
62
|
+
}
|
|
63
|
+
};
|
|
42
64
|
const createDefaultMeta = () => ({
|
|
43
65
|
duration: 0,
|
|
44
66
|
changes: 0,
|
|
@@ -58,6 +80,16 @@ export function createMockD1Database() {
|
|
|
58
80
|
},
|
|
59
81
|
first: async () => {
|
|
60
82
|
queries.push(query);
|
|
83
|
+
enforceMaxHistory();
|
|
84
|
+
// Special handling for banned_users queries to prevent false ban detection
|
|
85
|
+
// Use _setBanStatus(true) to simulate a banned user in tests
|
|
86
|
+
if (query.includes('banned_users')) {
|
|
87
|
+
if (banStatus === true) {
|
|
88
|
+
return { 1: 1 }; // User is banned
|
|
89
|
+
}
|
|
90
|
+
// Default: user not banned (don't call mockFn to avoid side effects)
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
61
93
|
if (mockFn) {
|
|
62
94
|
const result = mockFn(query, boundValues);
|
|
63
95
|
// If result is an array, return first element
|
|
@@ -70,6 +102,7 @@ export function createMockD1Database() {
|
|
|
70
102
|
},
|
|
71
103
|
all: async () => {
|
|
72
104
|
queries.push(query);
|
|
105
|
+
enforceMaxHistory();
|
|
73
106
|
if (mockFn) {
|
|
74
107
|
const result = mockFn(query, boundValues);
|
|
75
108
|
if (Array.isArray(result)) {
|
|
@@ -84,6 +117,7 @@ export function createMockD1Database() {
|
|
|
84
117
|
},
|
|
85
118
|
run: async () => {
|
|
86
119
|
queries.push(query);
|
|
120
|
+
enforceMaxHistory();
|
|
87
121
|
if (mockFn) {
|
|
88
122
|
const result = mockFn(query, boundValues);
|
|
89
123
|
if (result && typeof result === 'object' && 'meta' in result) {
|
|
@@ -98,6 +132,7 @@ export function createMockD1Database() {
|
|
|
98
132
|
},
|
|
99
133
|
raw: async (_options) => {
|
|
100
134
|
queries.push(query);
|
|
135
|
+
enforceMaxHistory();
|
|
101
136
|
if (mockFn) {
|
|
102
137
|
const result = mockFn(query, boundValues);
|
|
103
138
|
if (Array.isArray(result)) {
|
|
@@ -129,6 +164,7 @@ export function createMockD1Database() {
|
|
|
129
164
|
},
|
|
130
165
|
exec: async (query) => {
|
|
131
166
|
queries.push(query);
|
|
167
|
+
enforceMaxHistory();
|
|
132
168
|
return { count: 1, duration: 0 };
|
|
133
169
|
},
|
|
134
170
|
dump: async () => {
|
|
@@ -150,6 +186,7 @@ export function createMockD1Database() {
|
|
|
150
186
|
},
|
|
151
187
|
exec: async (query) => {
|
|
152
188
|
queries.push(query);
|
|
189
|
+
enforceMaxHistory();
|
|
153
190
|
return { count: 1, duration: 0 };
|
|
154
191
|
},
|
|
155
192
|
getBookmark: () => constraintOrBookmark ?? 'mock-bookmark',
|
|
@@ -164,10 +201,19 @@ export function createMockD1Database() {
|
|
|
164
201
|
queries.length = 0;
|
|
165
202
|
bindings.length = 0;
|
|
166
203
|
mockFn = undefined;
|
|
204
|
+
banStatus = undefined;
|
|
167
205
|
},
|
|
168
206
|
get _mockFn() {
|
|
169
207
|
return mockFn;
|
|
170
208
|
},
|
|
209
|
+
_setBanStatus: (isBanned) => {
|
|
210
|
+
banStatus = isBanned;
|
|
211
|
+
},
|
|
212
|
+
_setMaxQueryHistory: (max) => {
|
|
213
|
+
maxQueryHistory = max;
|
|
214
|
+
// Immediately enforce the new limit
|
|
215
|
+
enforceMaxHistory();
|
|
216
|
+
},
|
|
171
217
|
};
|
|
172
218
|
return mockDb;
|
|
173
219
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"d1.js","sourceRoot":"","sources":["../../src/cloudflare/d1.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"d1.js","sourceRoot":"","sources":["../../src/cloudflare/d1.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAgEH,yCAAyC;AACzC,MAAM,yBAAyB,GAAG,IAAI,CAAC;AAsCvC;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAA6B;IAChE,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,QAAQ,GAAgB,EAAE,CAAC;IACjC,IAAI,MAA+B,CAAC;IACpC,IAAI,SAA8B,CAAC;IACnC,IAAI,eAAe,GAAG,MAAM,EAAE,eAAe,IAAI,yBAAyB,CAAC;IAE3E;;;OAGG;IACH,MAAM,iBAAiB,GAAG,GAAS,EAAE;QACnC,OAAO,OAAO,CAAC,MAAM,GAAG,eAAe,EAAE,CAAC;YACxC,OAAO,CAAC,KAAK,EAAE,CAAC;YAChB,QAAQ,CAAC,KAAK,EAAE,CAAC;QACnB,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,iBAAiB,GAAG,GAAW,EAAE,CAAC,CAAC;QACvC,QAAQ,EAAE,CAAC;QACX,OAAO,EAAE,CAAC;QACV,WAAW,EAAE,CAAC;QACd,SAAS,EAAE,CAAC;QACZ,YAAY,EAAE,CAAC;QACf,UAAU,EAAE,CAAC;QACb,UAAU,EAAE,KAAK;KAClB,CAAC,CAAC;IAEH,MAAM,eAAe,GAAG,CAAC,KAAa,EAA2B,EAAE;QACjE,IAAI,WAAW,GAAc,EAAE,CAAC;QAEhC,MAAM,SAAS,GAA4B;YACzC,IAAI,EAAE,CAAC,GAAG,MAAiB,EAAE,EAAE;gBAC7B,WAAW,GAAG,MAAM,CAAC;gBACrB,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACtB,OAAO,SAAS,CAAC;YACnB,CAAC;YAED,KAAK,EAAE,KAAK,IAAiB,EAAE;gBAC7B,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACpB,iBAAiB,EAAE,CAAC;gBACpB,2EAA2E;gBAC3E,6DAA6D;gBAC7D,IAAI,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;oBACnC,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;wBACvB,OAAO,EAAE,CAAC,EAAE,CAAC,EAAO,CAAC,CAAC,iBAAiB;oBACzC,CAAC;oBACD,qEAAqE;oBACrE,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,IAAI,MAAM,EAAE,CAAC;oBACX,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;oBAC1C,8CAA8C;oBAC9C,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;wBAC1B,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,CAAa,CAAC;oBACzC,CAAC;oBACD,OAAO,MAAkB,CAAC;gBAC5B,CAAC;gBACD,OAAO,IAAI,CAAC;YACd,CAAC;YAED,GAAG,EAAE,KAAK,IAAuC,EAAE;gBACjD,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACpB,iBAAiB,EAAE,CAAC;gBACpB,IAAI,MAAM,EAAE,CAAC;oBACX,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;oBAC1C,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;wBAC1B,OAAO,EAAE,OAAO,EAAE,MAAa,EAAE,OAAO,EAAE,IAAa,EAAE,IAAI,EAAE,iBAAiB,EAAE,EAAE,CAAC;oBACvF,CAAC;oBACD,2CAA2C;oBAC3C,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;wBACzC,OAAO,EAAE,OAAO,EAAE,CAAC,MAAM,CAAQ,EAAE,OAAO,EAAE,IAAa,EAAE,IAAI,EAAE,iBAAiB,EAAE,EAAE,CAAC;oBACzF,CAAC;gBACH,CAAC;gBACD,OAAO,EAAE,OAAO,EAAE,EAAS,EAAE,OAAO,EAAE,IAAa,EAAE,IAAI,EAAE,iBAAiB,EAAE,EAAE,CAAC;YACnF,CAAC;YAED,GAAG,EAAE,KAAK,IAAuC,EAAE;gBACjD,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACpB,iBAAiB,EAAE,CAAC;gBACpB,IAAI,MAAM,EAAE,CAAC;oBACX,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;oBAC1C,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,IAAI,MAAM,EAAE,CAAC;wBAC7D,OAAO,MAAqB,CAAC;oBAC/B,CAAC;gBACH,CAAC;gBACD,OAAO;oBACL,OAAO,EAAE,EAAS;oBAClB,OAAO,EAAE,IAAa;oBACtB,IAAI,EAAE,EAAE,GAAG,iBAAiB,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE;iBAChG,CAAC;YACJ,CAAC;YAED,GAAG,EAAE,KAAK,EAAiB,QAAoC,EAAc,EAAE;gBAC7E,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACpB,iBAAiB,EAAE,CAAC;gBACpB,IAAI,MAAM,EAAE,CAAC;oBACX,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;oBAC1C,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;wBAC1B,sCAAsC;wBACtC,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;4BACxB,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;gCAC5C,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;4BAC5B,CAAC;4BACD,OAAO,GAAG,CAAC;wBACb,CAAC,CAAM,CAAC;oBACV,CAAC;gBACH,CAAC;gBACD,OAAO,EAAO,CAAC;YACjB,CAAC;SACF,CAAC;QAEF,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC;IAEF,kCAAkC;IAClC,MAAM,MAAM,GAAmB;QAC7B,OAAO,EAAE,eAAe;QAExB,KAAK,EAAE,KAAK,EAAe,UAAqC,EAA0B,EAAE;YAC1F,MAAM,OAAO,GAAkB,EAAE,CAAC;YAClC,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;gBAC9B,sCAAsC;gBACtC,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;gBACjB,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,EAAS,EAAE,OAAO,EAAE,IAAa,EAAE,IAAI,EAAE,iBAAiB,EAAE,EAAE,CAAC,CAAC;YAC1F,CAAC;YACD,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,IAAI,EAAE,KAAK,EAAE,KAAa,EAAE,EAAE;YAC5B,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpB,iBAAiB,EAAE,CAAC;YACpB,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QACnC,CAAC;QAED,IAAI,EAAE,KAAK,IAAI,EAAE;YACf,OAAO,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC;QAED,mEAAmE;QACnE,sEAAsE;QACtE,WAAW,EAAE,CAAC,oBAA6B,EAAyB,EAAE;YACpE,8DAA8D;YAC9D,OAAO;gBACL,OAAO,EAAE,eAAe;gBACxB,KAAK,EAAE,KAAK,EAAe,UAAqC,EAA0B,EAAE;oBAC1F,MAAM,OAAO,GAAkB,EAAE,CAAC;oBAClC,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;wBAC9B,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;wBACjB,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,EAAS,EAAE,OAAO,EAAE,IAAa,EAAE,IAAI,EAAE,iBAAiB,EAAE,EAAE,CAAC,CAAC;oBAC1F,CAAC;oBACD,OAAO,OAAO,CAAC;gBACjB,CAAC;gBACD,IAAI,EAAE,KAAK,EAAE,KAAa,EAAE,EAAE;oBAC5B,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBACpB,iBAAiB,EAAE,CAAC;oBACpB,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;gBACnC,CAAC;gBACD,WAAW,EAAE,GAAG,EAAE,CAAC,oBAAoB,IAAI,eAAe;aAC3D,CAAC;QACJ,CAAC;QAED,QAAQ,EAAE,OAAO;QACjB,SAAS,EAAE,QAAQ;QAEnB,UAAU,EAAE,CAAC,EAAe,EAAE,EAAE;YAC9B,MAAM,GAAG,EAAE,CAAC;QACd,CAAC;QAED,MAAM,EAAE,GAAG,EAAE;YACX,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;YACnB,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;YACpB,MAAM,GAAG,SAAS,CAAC;YACnB,SAAS,GAAG,SAAS,CAAC;QACxB,CAAC;QAED,IAAI,OAAO;YACT,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,aAAa,EAAE,CAAC,QAAiB,EAAE,EAAE;YACnC,SAAS,GAAG,QAAQ,CAAC;QACvB,CAAC;QAED,mBAAmB,EAAE,CAAC,GAAW,EAAE,EAAE;YACnC,eAAe,GAAG,GAAG,CAAC;YACtB,oCAAoC;YACpC,iBAAiB,EAAE,CAAC;QACtB,CAAC;KACF,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,oBAAoB,EAA2B,CAAC;AACzD,CAAC"}
|
|
@@ -44,12 +44,19 @@ export interface MockResponseConfig {
|
|
|
44
44
|
headers?: Record<string, string>;
|
|
45
45
|
body?: unknown;
|
|
46
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Configuration options for the mock fetcher
|
|
49
|
+
*/
|
|
50
|
+
export interface MockFetcherConfig {
|
|
51
|
+
/** Maximum number of calls to keep in history (prevents memory leaks). Default: 1000 */
|
|
52
|
+
maxCallHistory?: number;
|
|
53
|
+
}
|
|
47
54
|
/**
|
|
48
55
|
* Extended mock Fetcher with test helpers
|
|
49
56
|
*/
|
|
50
57
|
export interface MockFetcher {
|
|
51
58
|
fetch: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
52
|
-
/** Array of all fetch calls made (for assertions) */
|
|
59
|
+
/** Array of all fetch calls made (for assertions). Limited to maxCallHistory entries. */
|
|
53
60
|
_calls: MockFetchCall[];
|
|
54
61
|
/** Setup a response for a specific path pattern */
|
|
55
62
|
_setupResponse: (pathPattern: string | RegExp, response: unknown, config?: Omit<MockResponseConfig, 'body'>) => void;
|
|
@@ -59,6 +66,8 @@ export interface MockFetcher {
|
|
|
59
66
|
_reset: () => void;
|
|
60
67
|
/** Set default response for unmatched requests */
|
|
61
68
|
_setDefaultResponse: (response: unknown, config?: Omit<MockResponseConfig, 'body'>) => void;
|
|
69
|
+
/** Set the maximum call history size (for memory management) */
|
|
70
|
+
_setMaxCallHistory: (max: number) => void;
|
|
62
71
|
}
|
|
63
72
|
/**
|
|
64
73
|
* Creates a mock Fetcher for testing Service Bindings
|
|
@@ -66,7 +75,8 @@ export interface MockFetcher {
|
|
|
66
75
|
* The mock tracks all fetch calls and supports configuring
|
|
67
76
|
* responses for specific URL patterns.
|
|
68
77
|
*
|
|
78
|
+
* @param config - Optional configuration for the mock fetcher
|
|
69
79
|
* @returns A mock Fetcher that can be cast to Fetcher
|
|
70
80
|
*/
|
|
71
|
-
export declare function createMockFetcher(): MockFetcher;
|
|
81
|
+
export declare function createMockFetcher(config?: MockFetcherConfig): MockFetcher;
|
|
72
82
|
//# sourceMappingURL=fetcher.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../../src/cloudflare/fetcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE3E,
|
|
1
|
+
{"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../../src/cloudflare/fetcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,wFAAwF;IACxF,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE3E,yFAAyF;IACzF,MAAM,EAAE,aAAa,EAAE,CAAC;IAExB,mDAAmD;IACnD,cAAc,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;IAErH,sCAAsC;IACtC,aAAa,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,KAAK,IAAI,CAAC;IAEpG,8CAA8C;IAC9C,MAAM,EAAE,MAAM,IAAI,CAAC;IAEnB,kDAAkD;IAClD,mBAAmB,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;IAE5F,gEAAgE;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3C;AAKD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,CAAC,EAAE,iBAAiB,GAAG,WAAW,CA+HzE"}
|
|
@@ -26,15 +26,18 @@
|
|
|
26
26
|
* presetsApi._reset();
|
|
27
27
|
* ```
|
|
28
28
|
*/
|
|
29
|
+
/** Default maximum call history size */
|
|
30
|
+
const DEFAULT_MAX_CALL_HISTORY = 1000;
|
|
29
31
|
/**
|
|
30
32
|
* Creates a mock Fetcher for testing Service Bindings
|
|
31
33
|
*
|
|
32
34
|
* The mock tracks all fetch calls and supports configuring
|
|
33
35
|
* responses for specific URL patterns.
|
|
34
36
|
*
|
|
37
|
+
* @param config - Optional configuration for the mock fetcher
|
|
35
38
|
* @returns A mock Fetcher that can be cast to Fetcher
|
|
36
39
|
*/
|
|
37
|
-
export function createMockFetcher() {
|
|
40
|
+
export function createMockFetcher(config) {
|
|
38
41
|
const calls = [];
|
|
39
42
|
const responses = new Map();
|
|
40
43
|
let customHandler;
|
|
@@ -42,6 +45,7 @@ export function createMockFetcher() {
|
|
|
42
45
|
status: 200,
|
|
43
46
|
body: { success: true },
|
|
44
47
|
};
|
|
48
|
+
let maxCallHistory = config?.maxCallHistory ?? DEFAULT_MAX_CALL_HISTORY;
|
|
45
49
|
const createResponse = (config) => {
|
|
46
50
|
const { status = 200, headers = {}, body } = config;
|
|
47
51
|
const responseBody = body !== undefined ? JSON.stringify(body) : '';
|
|
@@ -89,7 +93,7 @@ export function createMockFetcher() {
|
|
|
89
93
|
Object.assign(headers, init.headers);
|
|
90
94
|
}
|
|
91
95
|
}
|
|
92
|
-
// Record the call
|
|
96
|
+
// Record the call (with memory limit enforcement)
|
|
93
97
|
calls.push({
|
|
94
98
|
url,
|
|
95
99
|
method,
|
|
@@ -97,6 +101,10 @@ export function createMockFetcher() {
|
|
|
97
101
|
body: init?.body?.toString(),
|
|
98
102
|
timestamp: Date.now(),
|
|
99
103
|
});
|
|
104
|
+
// Enforce max history limit (FIFO eviction) to prevent memory leaks
|
|
105
|
+
while (calls.length > maxCallHistory) {
|
|
106
|
+
calls.shift();
|
|
107
|
+
}
|
|
100
108
|
// Use custom handler if provided
|
|
101
109
|
if (customHandler) {
|
|
102
110
|
return customHandler(url, init);
|
|
@@ -131,6 +139,13 @@ export function createMockFetcher() {
|
|
|
131
139
|
body: response,
|
|
132
140
|
};
|
|
133
141
|
},
|
|
142
|
+
_setMaxCallHistory: (max) => {
|
|
143
|
+
maxCallHistory = max;
|
|
144
|
+
// Immediately enforce the new limit
|
|
145
|
+
while (calls.length > maxCallHistory) {
|
|
146
|
+
calls.shift();
|
|
147
|
+
}
|
|
148
|
+
},
|
|
134
149
|
};
|
|
135
150
|
}
|
|
136
151
|
//# sourceMappingURL=fetcher.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetcher.js","sourceRoot":"","sources":["../../src/cloudflare/fetcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;
|
|
1
|
+
{"version":3,"file":"fetcher.js","sourceRoot":"","sources":["../../src/cloudflare/fetcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAuDH,wCAAwC;AACxC,MAAM,wBAAwB,GAAG,IAAI,CAAC;AAEtC;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAA0B;IAC1D,MAAM,KAAK,GAAoB,EAAE,CAAC;IAClC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAuC,CAAC;IACjE,IAAI,aAA8F,CAAC;IACnG,IAAI,eAAe,GAAuB;QACxC,MAAM,EAAE,GAAG;QACX,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;KACxB,CAAC;IACF,IAAI,cAAc,GAAG,MAAM,EAAE,cAAc,IAAI,wBAAwB,CAAC;IAExE,MAAM,cAAc,GAAG,CAAC,MAA0B,EAAY,EAAE;QAC9D,MAAM,EAAE,MAAM,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC;QAEpD,MAAM,YAAY,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAEpE,OAAO,IAAI,QAAQ,CAAC,YAAY,EAAE;YAChC,MAAM;YACN,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,GAAG,OAAO;aACX;SACF,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,oBAAoB,GAAG,CAAC,GAAW,EAAkC,EAAE;QAC3E,iCAAiC;QACjC,KAAK,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,SAAS,CAAC,OAAO,EAAE,EAAE,CAAC;YACpD,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBACzD,OAAO,MAAM,CAAC;YAChB,CAAC;QACH,CAAC;QAED,yBAAyB;QACzB,KAAK,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,SAAS,CAAC,OAAO,EAAE,EAAE,CAAC;YACpD,IAAI,OAAO,YAAY,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBACnD,OAAO,MAAM,CAAC;YAChB,CAAC;QACH,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC;IAEF,OAAO;QACL,KAAK,EAAE,KAAK,EAAE,KAAwB,EAAE,IAAkB,EAAqB,EAAE;YAC/E,MAAM,GAAG,GAAG,KAAK,YAAY,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;YACpE,MAAM,MAAM,GAAG,IAAI,EAAE,MAAM,IAAI,CAAC,KAAK,YAAY,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACjF,MAAM,OAAO,GAA2B,EAAE,CAAC;YAE3C,kBAAkB;YAClB,IAAI,IAAI,EAAE,OAAO,EAAE,CAAC;gBAClB,IAAI,IAAI,CAAC,OAAO,YAAY,OAAO,EAAE,CAAC;oBACpC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;wBAClC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;oBACvB,CAAC,CAAC,CAAC;gBACL,CAAC;qBAAM,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;oBACvC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;wBACxC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;oBACvB,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;gBACvC,CAAC;YACH,CAAC;YAED,kDAAkD;YAClD,KAAK,CAAC,IAAI,CAAC;gBACT,GAAG;gBACH,MAAM;gBACN,OAAO;gBACP,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAC5B,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;aACtB,CAAC,CAAC;YAEH,oEAAoE;YACpE,OAAO,KAAK,CAAC,MAAM,GAAG,cAAc,EAAE,CAAC;gBACrC,KAAK,CAAC,KAAK,EAAE,CAAC;YAChB,CAAC;YAED,iCAAiC;YACjC,IAAI,aAAa,EAAE,CAAC;gBAClB,OAAO,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAClC,CAAC;YAED,yBAAyB;YACzB,MAAM,aAAa,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;YAChD,IAAI,aAAa,EAAE,CAAC;gBAClB,OAAO,cAAc,CAAC,aAAa,CAAC,CAAC;YACvC,CAAC;YAED,0BAA0B;YAC1B,OAAO,cAAc,CAAC,eAAe,CAAC,CAAC;QACzC,CAAC;QAED,MAAM,EAAE,KAAK;QAEb,cAAc,EAAE,CAAC,WAA4B,EAAE,QAAiB,EAAE,MAAyC,EAAE,EAAE;YAC7G,SAAS,CAAC,GAAG,CAAC,WAAW,EAAE;gBACzB,GAAG,MAAM;gBACT,IAAI,EAAE,QAAQ;aACf,CAAC,CAAC;QACL,CAAC;QAED,aAAa,EAAE,CAAC,OAA0E,EAAE,EAAE;YAC5F,aAAa,GAAG,OAAO,CAAC;QAC1B,CAAC;QAED,MAAM,EAAE,GAAG,EAAE;YACX,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;YACjB,SAAS,CAAC,KAAK,EAAE,CAAC;YAClB,aAAa,GAAG,SAAS,CAAC;YAC1B,eAAe,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC;QAC7D,CAAC;QAED,mBAAmB,EAAE,CAAC,QAAiB,EAAE,MAAyC,EAAE,EAAE;YACpF,eAAe,GAAG;gBAChB,GAAG,MAAM;gBACT,IAAI,EAAE,QAAQ;aACf,CAAC;QACJ,CAAC;QAED,kBAAkB,EAAE,CAAC,GAAW,EAAE,EAAE;YAClC,cAAc,GAAG,GAAG,CAAC;YACrB,oCAAoC;YACpC,OAAO,KAAK,CAAC,MAAM,GAAG,cAAc,EAAE,CAAC;gBACrC,KAAK,CAAC,KAAK,EAAE,CAAC;YAChB,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kv.d.ts","sourceRoot":"","sources":["../../src/cloudflare/kv.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH;;GAEG;AACH,UAAU,SAAS;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,UAAU,YAAY;IACpB,IAAI,EAAE,SAAS,EAAE,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,aAAa,GAAG,QAAQ,CAAA;KAAE,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC9G,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClI,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IAChG,eAAe,EAAE,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC;QAAC,WAAW,EAAE,IAAI,CAAA;KAAE,CAAC,CAAC;IAExH,4CAA4C;IAC5C,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE5B,sDAAsD;IACtD,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE3B,4BAA4B;IAC5B,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEhC,wBAAwB;IACxB,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,IAAI,eAAe,
|
|
1
|
+
{"version":3,"file":"kv.d.ts","sourceRoot":"","sources":["../../src/cloudflare/kv.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH;;GAEG;AACH,UAAU,SAAS;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,UAAU,YAAY;IACpB,IAAI,EAAE,SAAS,EAAE,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,aAAa,GAAG,QAAQ,CAAA;KAAE,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC9G,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClI,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IAChG,eAAe,EAAE,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC;QAAC,WAAW,EAAE,IAAI,CAAA;KAAE,CAAC,CAAC;IAExH,4CAA4C;IAC5C,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE5B,sDAAsD;IACtD,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE3B,4BAA4B;IAC5B,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEhC,wBAAwB;IACxB,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,IAAI,eAAe,CA+I9C"}
|
package/dist/cloudflare/kv.js
CHANGED
|
@@ -37,20 +37,32 @@ export function createMockKV() {
|
|
|
37
37
|
const ttls = new Map();
|
|
38
38
|
const metadata = new Map();
|
|
39
39
|
/**
|
|
40
|
-
* Check if a key has expired
|
|
40
|
+
* Check if a key has expired using a snapshot timestamp
|
|
41
|
+
* This prevents race conditions when time advances during async operations
|
|
42
|
+
*
|
|
43
|
+
* @param key - The key to check
|
|
44
|
+
* @param nowSeconds - Snapshot of current time in seconds (use Date.now() / 1000)
|
|
41
45
|
*/
|
|
42
|
-
const
|
|
46
|
+
const isExpiredAt = (key, nowSeconds) => {
|
|
43
47
|
const expiration = ttls.get(key);
|
|
44
48
|
if (expiration === undefined)
|
|
45
49
|
return false;
|
|
46
|
-
return
|
|
50
|
+
return nowSeconds > expiration;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Clean up an expired key from all stores
|
|
54
|
+
*/
|
|
55
|
+
const cleanupKey = (key) => {
|
|
56
|
+
store.delete(key);
|
|
57
|
+
ttls.delete(key);
|
|
58
|
+
metadata.delete(key);
|
|
47
59
|
};
|
|
48
60
|
return {
|
|
49
61
|
get: async (key, options) => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
62
|
+
// Capture timestamp once to prevent race conditions with mocked time
|
|
63
|
+
const nowSeconds = Date.now() / 1000;
|
|
64
|
+
if (isExpiredAt(key, nowSeconds)) {
|
|
65
|
+
cleanupKey(key);
|
|
54
66
|
return null;
|
|
55
67
|
}
|
|
56
68
|
const value = store.get(key) ?? null;
|
|
@@ -91,21 +103,34 @@ export function createMockKV() {
|
|
|
91
103
|
metadata.delete(key);
|
|
92
104
|
},
|
|
93
105
|
list: async (options) => {
|
|
106
|
+
// Capture timestamp once for consistent TTL checks across all keys
|
|
107
|
+
const nowSeconds = Date.now() / 1000;
|
|
94
108
|
const keys = [];
|
|
95
109
|
const prefix = options?.prefix ?? '';
|
|
96
110
|
const limit = options?.limit ?? 1000;
|
|
111
|
+
const expiredKeys = [];
|
|
97
112
|
for (const [key, _value] of store.entries()) {
|
|
98
|
-
if (key.startsWith(prefix)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
113
|
+
if (key.startsWith(prefix)) {
|
|
114
|
+
if (isExpiredAt(key, nowSeconds)) {
|
|
115
|
+
// Collect expired keys for cleanup after iteration
|
|
116
|
+
expiredKeys.push(key);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
keys.push({
|
|
120
|
+
name: key,
|
|
121
|
+
expiration: ttls.get(key),
|
|
122
|
+
metadata: metadata.get(key),
|
|
123
|
+
});
|
|
124
|
+
if (keys.length >= limit) {
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
106
127
|
}
|
|
107
128
|
}
|
|
108
129
|
}
|
|
130
|
+
// Clean up expired keys after iteration to avoid modifying map during iteration
|
|
131
|
+
for (const key of expiredKeys) {
|
|
132
|
+
cleanupKey(key);
|
|
133
|
+
}
|
|
109
134
|
return {
|
|
110
135
|
keys,
|
|
111
136
|
list_complete: keys.length < limit,
|
|
@@ -113,10 +138,10 @@ export function createMockKV() {
|
|
|
113
138
|
};
|
|
114
139
|
},
|
|
115
140
|
getWithMetadata: async (key) => {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
141
|
+
// Capture timestamp once to prevent race conditions with mocked time
|
|
142
|
+
const nowSeconds = Date.now() / 1000;
|
|
143
|
+
if (isExpiredAt(key, nowSeconds)) {
|
|
144
|
+
cleanupKey(key);
|
|
120
145
|
return { value: null, metadata: null, cacheStatus: null };
|
|
121
146
|
}
|
|
122
147
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kv.js","sourceRoot":"","sources":["../../src/cloudflare/kv.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AA2CH;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IACvC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAmB,CAAC;IAE5C
|
|
1
|
+
{"version":3,"file":"kv.js","sourceRoot":"","sources":["../../src/cloudflare/kv.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
* Domain object factories for testing
|
|
3
3
|
*
|
|
4
4
|
* Provides factory functions to create mock domain objects
|
|
5
|
-
* with sensible defaults and
|
|
5
|
+
* with sensible defaults and random IDs (TEST-DESIGN-001).
|
|
6
6
|
*/
|
|
7
7
|
export * from './preset.js';
|
|
8
8
|
export * from './category.js';
|
|
9
9
|
export * from './vote.js';
|
|
10
10
|
export * from './user.js';
|
|
11
11
|
export * from './dye.js';
|
|
12
|
-
export { resetCounters, resetCounter, getCounterValue } from '../utils/counters.js';
|
|
12
|
+
export { randomId, randomStringId, resetCounters, resetCounter, getCounterValue, } from '../utils/counters.js';
|
|
13
13
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/factories/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/factories/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AAIzB,OAAO,EACL,QAAQ,EACR,cAAc,EACd,aAAa,EACb,YAAY,EACZ,eAAe,GAChB,MAAM,sBAAsB,CAAC"}
|
package/dist/factories/index.js
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
* Domain object factories for testing
|
|
3
3
|
*
|
|
4
4
|
* Provides factory functions to create mock domain objects
|
|
5
|
-
* with sensible defaults and
|
|
5
|
+
* with sensible defaults and random IDs (TEST-DESIGN-001).
|
|
6
6
|
*/
|
|
7
7
|
export * from './preset.js';
|
|
8
8
|
export * from './category.js';
|
|
9
9
|
export * from './vote.js';
|
|
10
10
|
export * from './user.js';
|
|
11
11
|
export * from './dye.js';
|
|
12
|
-
// Re-export
|
|
13
|
-
|
|
12
|
+
// Re-export ID utilities for test setup
|
|
13
|
+
// TEST-DESIGN-001: randomId and randomStringId are the recommended functions for parallel-safe tests
|
|
14
|
+
export { randomId, randomStringId, resetCounters, resetCounter, getCounterValue, } from '../utils/counters.js';
|
|
14
15
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/factories/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AAEzB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/factories/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AAEzB,wCAAwC;AACxC,qGAAqG;AACrG,OAAO,EACL,QAAQ,EACR,cAAc,EACd,aAAa,EACb,YAAY,EACZ,eAAe,GAChB,MAAM,sBAAsB,CAAC"}
|
package/dist/factories/vote.d.ts
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
* Vote factory functions for testing
|
|
3
3
|
*
|
|
4
4
|
* Provides functions to create mock votes.
|
|
5
|
+
* TEST-DESIGN-001: Uses random IDs for parallel test safety.
|
|
5
6
|
*
|
|
6
7
|
* @example
|
|
7
8
|
* ```typescript
|
|
8
|
-
* const vote = createMockVote({ preset_id: 'preset-
|
|
9
|
+
* const vote = createMockVote({ preset_id: 'preset-xyz' });
|
|
9
10
|
* const votes = createMockVotes(5, { user_discord_id: '123' });
|
|
10
11
|
* ```
|
|
11
12
|
*/
|
|
@@ -20,6 +21,8 @@ export interface VoteRow {
|
|
|
20
21
|
/**
|
|
21
22
|
* Creates a mock vote row
|
|
22
23
|
*
|
|
24
|
+
* TEST-DESIGN-001: Uses random preset IDs for parallel test safety.
|
|
25
|
+
*
|
|
23
26
|
* @param overrides - Optional overrides for the default values
|
|
24
27
|
* @returns A VoteRow object
|
|
25
28
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vote.d.ts","sourceRoot":"","sources":["../../src/factories/vote.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"vote.d.ts","sourceRoot":"","sources":["../../src/factories/vote.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,GAAE,OAAO,CAAC,OAAO,CAAM,GAAG,OAAO,CAO3E;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,0BAAoB,CAAC;AAEhD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,OAAO,CAAC,OAAO,CAAM,GAC/B,OAAO,EAAE,CAEX;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,EAAE,CAOX;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,EAAE,CAOX"}
|
package/dist/factories/vote.js
CHANGED
|
@@ -2,24 +2,26 @@
|
|
|
2
2
|
* Vote factory functions for testing
|
|
3
3
|
*
|
|
4
4
|
* Provides functions to create mock votes.
|
|
5
|
+
* TEST-DESIGN-001: Uses random IDs for parallel test safety.
|
|
5
6
|
*
|
|
6
7
|
* @example
|
|
7
8
|
* ```typescript
|
|
8
|
-
* const vote = createMockVote({ preset_id: 'preset-
|
|
9
|
+
* const vote = createMockVote({ preset_id: 'preset-xyz' });
|
|
9
10
|
* const votes = createMockVotes(5, { user_discord_id: '123' });
|
|
10
11
|
* ```
|
|
11
12
|
*/
|
|
12
|
-
import {
|
|
13
|
+
import { randomStringId } from '../utils/counters.js';
|
|
13
14
|
/**
|
|
14
15
|
* Creates a mock vote row
|
|
15
16
|
*
|
|
17
|
+
* TEST-DESIGN-001: Uses random preset IDs for parallel test safety.
|
|
18
|
+
*
|
|
16
19
|
* @param overrides - Optional overrides for the default values
|
|
17
20
|
* @returns A VoteRow object
|
|
18
21
|
*/
|
|
19
22
|
export function createMockVoteRow(overrides = {}) {
|
|
20
|
-
const voteNum = nextId('vote');
|
|
21
23
|
return {
|
|
22
|
-
preset_id:
|
|
24
|
+
preset_id: randomStringId('preset'),
|
|
23
25
|
user_discord_id: '123456789',
|
|
24
26
|
created_at: new Date().toISOString(),
|
|
25
27
|
...overrides,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vote.js","sourceRoot":"","sources":["../../src/factories/vote.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"vote.js","sourceRoot":"","sources":["../../src/factories/vote.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAWtD;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,YAA8B,EAAE;IAChE,OAAO;QACL,SAAS,EAAE,cAAc,CAAC,QAAQ,CAAC;QACnC,eAAe,EAAE,WAAW;QAC5B,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACpC,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,iBAAiB,CAAC;AAEhD;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAC7B,KAAa,EACb,YAA8B,EAAE;IAEhC,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC,CAAC;AAC3E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAAgB,EAChB,SAAiB;IAEjB,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAChD,iBAAiB,CAAC;QAChB,SAAS,EAAE,QAAQ;QACnB,eAAe,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE;KACjC,CAAC,CACH,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAAc,EACd,SAAmB;IAEnB,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAChC,iBAAiB,CAAC;QAChB,SAAS,EAAE,QAAQ;QACnB,eAAe,EAAE,MAAM;KACxB,CAAC,CACH,CAAC;AACJ,CAAC"}
|
package/dist/utils/counters.d.ts
CHANGED
|
@@ -1,19 +1,43 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* ID generation utilities for test factories
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* TEST-DESIGN-001: Uses random IDs to prevent race conditions in parallel test execution.
|
|
5
|
+
* Sequential counters are kept for backward compatibility but random IDs are now the default.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* // Recommended: Random IDs (safe for parallel tests)
|
|
10
|
+
* const id = randomStringId('preset'); // 'preset-a7x9k2m'
|
|
11
|
+
*
|
|
12
|
+
* // Legacy: Sequential IDs (call resetCounters() in beforeEach for isolation)
|
|
13
|
+
* const seqId = nextStringId('preset'); // 'preset-1'
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Generate a random numeric ID
|
|
18
|
+
* TEST-DESIGN-001: Safe for parallel test execution
|
|
19
|
+
* @returns A random positive integer
|
|
20
|
+
*/
|
|
21
|
+
export declare function randomId(): number;
|
|
22
|
+
/**
|
|
23
|
+
* Generate a random string ID with prefix
|
|
24
|
+
* TEST-DESIGN-001: Safe for parallel test execution
|
|
25
|
+
* @param prefix - The ID prefix (e.g., 'preset', 'category')
|
|
26
|
+
* @returns A string ID like 'preset-a7x9k2m'
|
|
6
27
|
*/
|
|
28
|
+
export declare function randomStringId(prefix: string): string;
|
|
7
29
|
/**
|
|
8
|
-
* Get the next value for a named counter
|
|
30
|
+
* Get the next value for a named counter (legacy)
|
|
31
|
+
* @deprecated Use randomId() for parallel-safe ID generation
|
|
9
32
|
* @param name - The counter name (e.g., 'preset', 'category')
|
|
10
33
|
* @returns The next sequential value
|
|
11
34
|
*/
|
|
12
35
|
export declare function nextId(name: string): number;
|
|
13
36
|
/**
|
|
14
|
-
* Get a string ID with prefix
|
|
37
|
+
* Get a string ID with prefix (legacy)
|
|
38
|
+
* TEST-DESIGN-001: Now uses random IDs by default for parallel-safe execution
|
|
15
39
|
* @param prefix - The ID prefix (e.g., 'preset', 'category')
|
|
16
|
-
* @returns A string ID like 'preset-
|
|
40
|
+
* @returns A string ID like 'preset-a7x9k2m'
|
|
17
41
|
*/
|
|
18
42
|
export declare function nextStringId(prefix: string): string;
|
|
19
43
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"counters.d.ts","sourceRoot":"","sources":["../../src/utils/counters.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"counters.d.ts","sourceRoot":"","sources":["../../src/utils/counters.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAmBH;;;;GAIG;AACH,wBAAgB,QAAQ,IAAI,MAAM,CAEjC;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM3C;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGnD;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAIpC;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAE/C;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD"}
|
package/dist/utils/counters.js
CHANGED
|
@@ -1,13 +1,53 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* ID generation utilities for test factories
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* TEST-DESIGN-001: Uses random IDs to prevent race conditions in parallel test execution.
|
|
5
|
+
* Sequential counters are kept for backward compatibility but random IDs are now the default.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* // Recommended: Random IDs (safe for parallel tests)
|
|
10
|
+
* const id = randomStringId('preset'); // 'preset-a7x9k2m'
|
|
11
|
+
*
|
|
12
|
+
* // Legacy: Sequential IDs (call resetCounters() in beforeEach for isolation)
|
|
13
|
+
* const seqId = nextStringId('preset'); // 'preset-1'
|
|
14
|
+
* ```
|
|
6
15
|
*/
|
|
7
|
-
// Counter storage
|
|
16
|
+
// Counter storage (legacy, for backward compatibility)
|
|
8
17
|
const counters = {};
|
|
9
18
|
/**
|
|
10
|
-
*
|
|
19
|
+
* Generate a random alphanumeric string
|
|
20
|
+
* @param length - Length of the random string (default: 8)
|
|
21
|
+
* @returns Random alphanumeric string
|
|
22
|
+
*/
|
|
23
|
+
function randomAlphanumeric(length = 8) {
|
|
24
|
+
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
|
25
|
+
let result = '';
|
|
26
|
+
for (let i = 0; i < length; i++) {
|
|
27
|
+
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Generate a random numeric ID
|
|
33
|
+
* TEST-DESIGN-001: Safe for parallel test execution
|
|
34
|
+
* @returns A random positive integer
|
|
35
|
+
*/
|
|
36
|
+
export function randomId() {
|
|
37
|
+
return Math.floor(Math.random() * 900000000) + 100000000; // 9-digit number
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Generate a random string ID with prefix
|
|
41
|
+
* TEST-DESIGN-001: Safe for parallel test execution
|
|
42
|
+
* @param prefix - The ID prefix (e.g., 'preset', 'category')
|
|
43
|
+
* @returns A string ID like 'preset-a7x9k2m'
|
|
44
|
+
*/
|
|
45
|
+
export function randomStringId(prefix) {
|
|
46
|
+
return `${prefix}-${randomAlphanumeric(8)}`;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get the next value for a named counter (legacy)
|
|
50
|
+
* @deprecated Use randomId() for parallel-safe ID generation
|
|
11
51
|
* @param name - The counter name (e.g., 'preset', 'category')
|
|
12
52
|
* @returns The next sequential value
|
|
13
53
|
*/
|
|
@@ -19,12 +59,14 @@ export function nextId(name) {
|
|
|
19
59
|
return counters[name];
|
|
20
60
|
}
|
|
21
61
|
/**
|
|
22
|
-
* Get a string ID with prefix
|
|
62
|
+
* Get a string ID with prefix (legacy)
|
|
63
|
+
* TEST-DESIGN-001: Now uses random IDs by default for parallel-safe execution
|
|
23
64
|
* @param prefix - The ID prefix (e.g., 'preset', 'category')
|
|
24
|
-
* @returns A string ID like 'preset-
|
|
65
|
+
* @returns A string ID like 'preset-a7x9k2m'
|
|
25
66
|
*/
|
|
26
67
|
export function nextStringId(prefix) {
|
|
27
|
-
|
|
68
|
+
// TEST-DESIGN-001: Use random IDs by default for parallel test safety
|
|
69
|
+
return randomStringId(prefix);
|
|
28
70
|
}
|
|
29
71
|
/**
|
|
30
72
|
* Reset all counters to zero
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"counters.js","sourceRoot":"","sources":["../../src/utils/counters.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"counters.js","sourceRoot":"","sources":["../../src/utils/counters.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,uDAAuD;AACvD,MAAM,QAAQ,GAA2B,EAAE,CAAC;AAE5C;;;;GAIG;AACH,SAAS,kBAAkB,CAAC,SAAiB,CAAC;IAC5C,MAAM,KAAK,GAAG,sCAAsC,CAAC;IACrD,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ;IACtB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC,CAAC,iBAAiB;AAC7E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,OAAO,GAAG,MAAM,IAAI,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC;AAC9C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,MAAM,CAAC,IAAY;IACjC,IAAI,CAAC,CAAC,IAAI,IAAI,QAAQ,CAAC,EAAE,CAAC;QACxB,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;IACD,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;IACjB,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,sEAAsE;IACtE,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC;AAChC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa;IAC3B,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC"}
|
package/dist/utils/crypto.d.ts
CHANGED
|
@@ -18,11 +18,21 @@ export declare function base64UrlEncode(str: string): string;
|
|
|
18
18
|
* @returns Base64URL encoded string
|
|
19
19
|
*/
|
|
20
20
|
export declare function base64UrlEncodeBytes(bytes: Uint8Array): string;
|
|
21
|
+
/**
|
|
22
|
+
* Decode a Base64URL string to bytes
|
|
23
|
+
*
|
|
24
|
+
* @param str - The Base64URL string to decode
|
|
25
|
+
* @returns Decoded bytes as Uint8Array
|
|
26
|
+
*/
|
|
27
|
+
export declare function base64UrlDecodeBytes(str: string): Uint8Array;
|
|
21
28
|
/**
|
|
22
29
|
* Decode a Base64URL string
|
|
23
30
|
*
|
|
31
|
+
* NOTE: For proper UTF-8 roundtrip with base64UrlEncode(), this function
|
|
32
|
+
* decodes the binary bytes back to a UTF-8 string using TextDecoder.
|
|
33
|
+
*
|
|
24
34
|
* @param str - The Base64URL string to decode
|
|
25
|
-
* @returns Decoded string
|
|
35
|
+
* @returns Decoded UTF-8 string
|
|
26
36
|
*/
|
|
27
37
|
export declare function base64UrlDecode(str: string): string;
|
|
28
38
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../src/utils/crypto.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAOnD;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAM9D;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../src/utils/crypto.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAOnD;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAM9D;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAiB5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGnD;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAMlD;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAIpD"}
|
package/dist/utils/crypto.js
CHANGED
|
@@ -32,18 +32,38 @@ export function base64UrlEncodeBytes(bytes) {
|
|
|
32
32
|
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
|
-
* Decode a Base64URL string
|
|
35
|
+
* Decode a Base64URL string to bytes
|
|
36
36
|
*
|
|
37
37
|
* @param str - The Base64URL string to decode
|
|
38
|
-
* @returns Decoded
|
|
38
|
+
* @returns Decoded bytes as Uint8Array
|
|
39
39
|
*/
|
|
40
|
-
export function
|
|
40
|
+
export function base64UrlDecodeBytes(str) {
|
|
41
41
|
// Add padding if needed
|
|
42
42
|
let base64 = str.replace(/-/g, '+').replace(/_/g, '/');
|
|
43
43
|
while (base64.length % 4) {
|
|
44
44
|
base64 += '=';
|
|
45
45
|
}
|
|
46
|
-
|
|
46
|
+
// Decode to binary string
|
|
47
|
+
const binary = atob(base64);
|
|
48
|
+
// Convert binary string to Uint8Array
|
|
49
|
+
const bytes = new Uint8Array(binary.length);
|
|
50
|
+
for (let i = 0; i < binary.length; i++) {
|
|
51
|
+
bytes[i] = binary.charCodeAt(i);
|
|
52
|
+
}
|
|
53
|
+
return bytes;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Decode a Base64URL string
|
|
57
|
+
*
|
|
58
|
+
* NOTE: For proper UTF-8 roundtrip with base64UrlEncode(), this function
|
|
59
|
+
* decodes the binary bytes back to a UTF-8 string using TextDecoder.
|
|
60
|
+
*
|
|
61
|
+
* @param str - The Base64URL string to decode
|
|
62
|
+
* @returns Decoded UTF-8 string
|
|
63
|
+
*/
|
|
64
|
+
export function base64UrlDecode(str) {
|
|
65
|
+
const bytes = base64UrlDecodeBytes(str);
|
|
66
|
+
return new TextDecoder().decode(bytes);
|
|
47
67
|
}
|
|
48
68
|
/**
|
|
49
69
|
* Convert a hex string to Uint8Array
|
package/dist/utils/crypto.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../src/utils/crypto.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC5C,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACjF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAiB;IACpD,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACjF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../src/utils/crypto.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xivdyetools/test-utils",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Shared testing utilities for the xivdyetools ecosystem",
|
|
5
5
|
"author": "XIV Dye Tools",
|
|
6
6
|
"license": "MIT",
|
|
@@ -60,15 +60,15 @@
|
|
|
60
60
|
}
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@xivdyetools/types": "^1.
|
|
63
|
+
"@xivdyetools/types": "^1.1.1"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
66
|
"@cloudflare/workers-types": "^4.20241205.0",
|
|
67
67
|
"@testing-library/dom": "^10.0.0",
|
|
68
|
-
"@vitest/coverage-v8": "^
|
|
68
|
+
"@vitest/coverage-v8": "^4.0.15",
|
|
69
69
|
"rimraf": "^5.0.5",
|
|
70
|
-
"typescript": "^5.3
|
|
71
|
-
"vitest": "^
|
|
70
|
+
"typescript": "^5.9.3",
|
|
71
|
+
"vitest": "^4.0.15"
|
|
72
72
|
},
|
|
73
73
|
"engines": {
|
|
74
74
|
"node": ">=18.0.0"
|
|
@@ -85,4 +85,4 @@
|
|
|
85
85
|
"type": "git",
|
|
86
86
|
"url": "https://github.com/xivdyetools/xivdyetools-test-utils.git"
|
|
87
87
|
}
|
|
88
|
-
}
|
|
88
|
+
}
|