@waitkit/core 0.1.1 → 0.2.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 +46 -0
- package/dist/index.cjs +35 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +35 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -95,6 +95,11 @@ waitkit.restore();
|
|
|
95
95
|
|
|
96
96
|
## Error Responses
|
|
97
97
|
|
|
98
|
+
Object bodies are serialized as JSON and receive `content-type:
|
|
99
|
+
application/json` when no content type is already provided.
|
|
100
|
+
When `statusText` is omitted, Waitkit uses the runtime `Response` default for
|
|
101
|
+
the configured status.
|
|
102
|
+
|
|
98
103
|
```ts
|
|
99
104
|
setupWaitKit({
|
|
100
105
|
enabled: import.meta.env.DEV,
|
|
@@ -114,6 +119,10 @@ setupWaitKit({
|
|
|
114
119
|
|
|
115
120
|
## Timeouts
|
|
116
121
|
|
|
122
|
+
Timeout rules throw a `WaitKitTimeoutError`. If a rule also has `delay`,
|
|
123
|
+
Waitkit waits for the delay first and then waits for `timeoutMs`, so the total
|
|
124
|
+
simulated wait can be `delay + timeoutMs`.
|
|
125
|
+
|
|
117
126
|
```ts
|
|
118
127
|
setupWaitKit({
|
|
119
128
|
enabled: import.meta.env.DEV,
|
|
@@ -121,6 +130,9 @@ setupWaitKit({
|
|
|
121
130
|
});
|
|
122
131
|
```
|
|
123
132
|
|
|
133
|
+
Waitkit does not currently cancel simulated delay or timeout sleeps when a
|
|
134
|
+
request `AbortSignal` aborts.
|
|
135
|
+
|
|
124
136
|
## Controller API
|
|
125
137
|
|
|
126
138
|
`setupWaitKit` returns a controller:
|
|
@@ -145,6 +157,25 @@ setupWaitKit({
|
|
|
145
157
|
|
|
146
158
|
The first matching rule is applied.
|
|
147
159
|
|
|
160
|
+
## Rule Matching
|
|
161
|
+
|
|
162
|
+
String, `RegExp`, and predicate URL matchers receive the request's full URL
|
|
163
|
+
string, including any query string. Use a predicate matcher if you want to
|
|
164
|
+
match only part of the URL.
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
setupWaitKit({
|
|
168
|
+
rules: [
|
|
169
|
+
{
|
|
170
|
+
url: (url) => new URL(url, window.location.origin).pathname === '/api/users',
|
|
171
|
+
delay: 1000,
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
When multiple rules match a request, the first matching rule in the array wins.
|
|
178
|
+
|
|
148
179
|
## Events
|
|
149
180
|
|
|
150
181
|
```ts
|
|
@@ -156,9 +187,24 @@ setupWaitKit({
|
|
|
156
187
|
onDelayStart: (event) => console.log(event.delayMs),
|
|
157
188
|
onDelayEnd: (event) => console.log(event.delayMs),
|
|
158
189
|
onError: (event) => console.error(event.error),
|
|
190
|
+
onScenarioChange: (event) => console.log(event.scenario),
|
|
159
191
|
});
|
|
160
192
|
```
|
|
161
193
|
|
|
194
|
+
Event payloads include the original `input` and `init`, normalized `url` and
|
|
195
|
+
`method`, and match events also include the matched `rule`, active `scenario`
|
|
196
|
+
name, and resolved `delayMs`. `onError` additionally receives the simulated
|
|
197
|
+
`error`.
|
|
198
|
+
|
|
199
|
+
The request lifecycle event names are stable: `onRequest`, `onMatch`,
|
|
200
|
+
`onDelayStart`, `onDelayEnd`, and `onError`.
|
|
201
|
+
|
|
202
|
+
`onScenarioChange` runs when `setScenario()` or `resetScenario()` changes the
|
|
203
|
+
active scenario. It does not run for the initial `activeScenario` value passed
|
|
204
|
+
to `setupWaitKit`, setting the same scenario again, or resetting when no
|
|
205
|
+
scenario is active. Its payload includes `previousScenario`, `scenario`, and
|
|
206
|
+
`reason` (`setScenario` or `resetScenario`).
|
|
207
|
+
|
|
162
208
|
## Production Safety
|
|
163
209
|
|
|
164
210
|
Waitkit does not force development-only usage. Gate it explicitly with your
|
package/dist/index.cjs
CHANGED
|
@@ -106,14 +106,18 @@ function getRequestMethod(input, init) {
|
|
|
106
106
|
|
|
107
107
|
// src/response.ts
|
|
108
108
|
function createErrorResponse(errorResponse) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
109
|
+
try {
|
|
110
|
+
const status = errorResponse?.status ?? 500;
|
|
111
|
+
const headers = new Headers(errorResponse?.headers);
|
|
112
|
+
const body = serializeBody(errorResponse?.body, headers);
|
|
113
|
+
return new Response(body, {
|
|
114
|
+
status,
|
|
115
|
+
statusText: errorResponse?.statusText,
|
|
116
|
+
headers
|
|
117
|
+
});
|
|
118
|
+
} catch (error) {
|
|
119
|
+
throw createResponseError(error);
|
|
120
|
+
}
|
|
117
121
|
}
|
|
118
122
|
function serializeBody(body, headers) {
|
|
119
123
|
if (body === void 0 || body === null) {
|
|
@@ -139,6 +143,12 @@ function isFormData(body) {
|
|
|
139
143
|
function isUrlSearchParams(body) {
|
|
140
144
|
return typeof URLSearchParams !== "undefined" && body instanceof URLSearchParams;
|
|
141
145
|
}
|
|
146
|
+
function createResponseError(error) {
|
|
147
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
148
|
+
return new Error(`WaitKit failed to create simulated error response: ${reason}`, {
|
|
149
|
+
cause: error
|
|
150
|
+
});
|
|
151
|
+
}
|
|
142
152
|
|
|
143
153
|
// src/setup-wait-kit.ts
|
|
144
154
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
@@ -221,13 +231,23 @@ function setupWaitKit(options) {
|
|
|
221
231
|
if (options.scenarios?.[name] === void 0) {
|
|
222
232
|
throw new Error(`WaitKit scenario "${name}" does not exist.`);
|
|
223
233
|
}
|
|
234
|
+
if (activeScenario === name) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const previousScenario = activeScenario;
|
|
224
238
|
activeScenario = name;
|
|
239
|
+
emitScenarioChange(options, previousScenario, activeScenario, "setScenario");
|
|
225
240
|
},
|
|
226
241
|
getScenario() {
|
|
227
242
|
return activeScenario;
|
|
228
243
|
},
|
|
229
244
|
resetScenario() {
|
|
245
|
+
if (activeScenario === void 0) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
const previousScenario = activeScenario;
|
|
230
249
|
activeScenario = void 0;
|
|
250
|
+
emitScenarioChange(options, previousScenario, activeScenario, "resetScenario");
|
|
231
251
|
}
|
|
232
252
|
};
|
|
233
253
|
}
|
|
@@ -302,6 +322,13 @@ function emitError(options, matchEvent, error) {
|
|
|
302
322
|
};
|
|
303
323
|
options.onError?.(errorEvent);
|
|
304
324
|
}
|
|
325
|
+
function emitScenarioChange(options, previousScenario, scenario, reason) {
|
|
326
|
+
options.onScenarioChange?.({
|
|
327
|
+
previousScenario,
|
|
328
|
+
scenario,
|
|
329
|
+
reason
|
|
330
|
+
});
|
|
331
|
+
}
|
|
305
332
|
function debug(options, message) {
|
|
306
333
|
if (options.debug === true) {
|
|
307
334
|
console.info(`[waitkit] ${message}`);
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/delay.ts","../src/matcher.ts","../src/response.ts","../src/setup-wait-kit.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["export class WaitKitTimeoutError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'WaitKitTimeoutError';\n }\n}\n","import type { DelayValue } from './types';\n\nexport function resolveDelay(delay: DelayValue | undefined): number {\n if (delay === undefined) {\n return 0;\n }\n\n if (typeof delay === 'number') {\n return delay;\n }\n\n const [min, max] = delay;\n return Math.floor(min + Math.random() * (max - min + 1));\n}\n\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nexport function validateDelay(delay: DelayValue | undefined): void {\n if (delay === undefined) {\n return;\n }\n\n if (typeof delay === 'number') {\n assertNonNegativeFiniteNumber(delay, 'delay');\n return;\n }\n\n const [min, max] = delay;\n assertNonNegativeFiniteNumber(min, 'delay min');\n assertNonNegativeFiniteNumber(max, 'delay max');\n\n if (min > max) {\n throw new Error('WaitKit delay range must have min less than or equal to max.');\n }\n}\n\nexport function validateRate(rate: number | undefined, name: string): void {\n if (rate === undefined) {\n return;\n }\n\n if (!Number.isFinite(rate) || rate < 0 || rate > 1) {\n throw new Error(`WaitKit ${name} must be a number between 0 and 1.`);\n }\n}\n\nexport function validateTimeoutMs(timeoutMs: number | undefined): void {\n if (timeoutMs === undefined) {\n return;\n }\n\n assertNonNegativeFiniteNumber(timeoutMs, 'timeoutMs');\n}\n\nfunction assertNonNegativeFiniteNumber(value: number, name: string): void {\n if (!Number.isFinite(value) || value < 0) {\n throw new Error(`WaitKit ${name} must be a non-negative finite number.`);\n }\n}\n","import type { WaitKitRule } from './types';\n\nexport function matchesRule(rule: WaitKitRule, url: string, method: string): boolean {\n return matchesUrl(rule.url, url) && matchesMethod(rule.method, method);\n}\n\nfunction matchesUrl(ruleUrl: WaitKitRule['url'], url: string): boolean {\n if (typeof ruleUrl === 'string') {\n return url.includes(ruleUrl);\n }\n\n if (ruleUrl instanceof RegExp) {\n return ruleUrl.test(url);\n }\n\n return ruleUrl(url);\n}\n\nfunction matchesMethod(ruleMethod: WaitKitRule['method'], method: string): boolean {\n if (ruleMethod === undefined) {\n return true;\n }\n\n const normalizedMethod = normalizeMethod(method);\n\n if (typeof ruleMethod === 'string') {\n return normalizeMethod(ruleMethod) === normalizedMethod;\n }\n\n return ruleMethod.some((item) => normalizeMethod(item) === normalizedMethod);\n}\n\nexport function normalizeMethod(method: string | undefined): string {\n return (method ?? 'GET').toUpperCase();\n}\n\nexport function getRequestUrl(input: RequestInfo | URL): string {\n if (typeof input === 'string') {\n return input;\n }\n\n if (input instanceof URL) {\n return input.toString();\n }\n\n return input.url;\n}\n\nexport function getRequestMethod(input: RequestInfo | URL, init?: RequestInit): string {\n if (init?.method !== undefined) {\n return normalizeMethod(init.method);\n }\n\n if (typeof input === 'string' || input instanceof URL) {\n return 'GET';\n }\n\n return normalizeMethod(input.method);\n}\n","import type { WaitKitErrorResponse } from './types';\n\nexport function createErrorResponse(errorResponse: WaitKitErrorResponse | undefined): Response {\n const status = errorResponse?.status ?? 500;\n const headers = new Headers(errorResponse?.headers);\n const body = serializeBody(errorResponse?.body, headers);\n\n return new Response(body, {\n status,\n statusText: errorResponse?.statusText,\n headers,\n });\n}\n\nfunction serializeBody(body: unknown, headers: Headers): BodyInit | null {\n if (body === undefined || body === null) {\n return null;\n }\n\n if (typeof body === 'string' || isBlob(body) || isFormData(body)) {\n return body;\n }\n\n if (body instanceof ArrayBuffer || ArrayBuffer.isView(body) || isUrlSearchParams(body)) {\n return body as BodyInit;\n }\n\n if (!headers.has('content-type')) {\n headers.set('content-type', 'application/json');\n }\n\n return JSON.stringify(body);\n}\n\nfunction isBlob(body: unknown): body is Blob {\n return typeof Blob !== 'undefined' && body instanceof Blob;\n}\n\nfunction isFormData(body: unknown): body is FormData {\n return typeof FormData !== 'undefined' && body instanceof FormData;\n}\n\nfunction isUrlSearchParams(body: unknown): body is URLSearchParams {\n return typeof URLSearchParams !== 'undefined' && body instanceof URLSearchParams;\n}\n","import { resolveDelay, sleep, validateDelay, validateRate, validateTimeoutMs } from './delay';\nimport { WaitKitTimeoutError } from './errors';\nimport { getRequestMethod, getRequestUrl, matchesRule } from './matcher';\nimport { createErrorResponse } from './response';\nimport type {\n WaitKitController,\n WaitKitErrorEvent,\n WaitKitMatchEvent,\n WaitKitOptions,\n WaitKitRequestEvent,\n WaitKitRule,\n} from './types';\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nexport function setupWaitKit(options: WaitKitOptions): WaitKitController {\n validateRuntime();\n validateOptions(options);\n\n const originalFetch = globalThis.fetch;\n let enabled = options.enabled ?? true;\n let activeScenario = options.activeScenario;\n let restored = false;\n\n const patchedFetch: typeof fetch = async (input, init) => {\n if (!enabled) {\n return originalFetch.call(globalThis, input, init);\n }\n\n const requestEvent = createRequestEvent(input, init);\n options.onRequest?.(requestEvent);\n\n const rule = findMatchingRule(getActiveRules(), requestEvent.url, requestEvent.method);\n\n if (rule === undefined) {\n return originalFetch.call(globalThis, input, init);\n }\n\n const delayMs = resolveDelay(rule.delay);\n const matchEvent = createMatchEvent(requestEvent, rule, activeScenario, delayMs);\n options.onMatch?.(matchEvent);\n\n if (delayMs > 0) {\n options.onDelayStart?.(matchEvent);\n debug(options, `${requestEvent.method} ${requestEvent.url} delayed by ${delayMs}ms`);\n await sleep(delayMs);\n options.onDelayEnd?.(matchEvent);\n }\n\n if (shouldTrigger(rule.timeoutRate)) {\n const timeoutMs = rule.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const error = new WaitKitTimeoutError(\n `WaitKit timed out ${requestEvent.method} ${requestEvent.url} after ${timeoutMs}ms.`,\n );\n emitError(options, matchEvent, error);\n debug(options, `${requestEvent.method} ${requestEvent.url} timed out after ${timeoutMs}ms`);\n await sleep(timeoutMs);\n throw error;\n }\n\n if (shouldTrigger(rule.errorRate)) {\n const response = createErrorResponse(rule.errorResponse);\n const error = new Error(\n `WaitKit simulated ${response.status} response for ${requestEvent.method} ${requestEvent.url}.`,\n );\n emitError(options, matchEvent, error);\n debug(options, `${requestEvent.method} ${requestEvent.url} returned ${response.status}`);\n return response;\n }\n\n return originalFetch.call(globalThis, input, init);\n };\n\n globalThis.fetch = patchedFetch;\n\n function getActiveRules(): readonly WaitKitRule[] {\n if (activeScenario === undefined) {\n return options.rules ?? [];\n }\n\n return options.scenarios?.[activeScenario] ?? [];\n }\n\n return {\n enable() {\n enabled = true;\n\n if (restored) {\n globalThis.fetch = patchedFetch;\n restored = false;\n }\n },\n disable() {\n enabled = false;\n },\n restore() {\n if (globalThis.fetch === patchedFetch) {\n globalThis.fetch = originalFetch;\n }\n\n enabled = false;\n restored = true;\n },\n isEnabled() {\n return enabled;\n },\n setScenario(name: string) {\n if (options.scenarios?.[name] === undefined) {\n throw new Error(`WaitKit scenario \"${name}\" does not exist.`);\n }\n\n activeScenario = name;\n },\n getScenario() {\n return activeScenario;\n },\n resetScenario() {\n activeScenario = undefined;\n },\n };\n}\n\nfunction validateRuntime(): void {\n if (typeof globalThis.fetch !== 'function') {\n throw new Error('WaitKit requires globalThis.fetch.');\n }\n\n if (typeof Response !== 'function') {\n throw new Error('WaitKit requires globalThis.Response.');\n }\n}\n\nfunction validateOptions(options: WaitKitOptions): void {\n validateRules(options.rules ?? []);\n\n if (options.scenarios !== undefined) {\n for (const rules of Object.values(options.scenarios)) {\n validateRules(rules);\n }\n }\n\n if (\n options.activeScenario !== undefined &&\n options.scenarios?.[options.activeScenario] === undefined\n ) {\n throw new Error(`WaitKit scenario \"${options.activeScenario}\" does not exist.`);\n }\n}\n\nfunction validateRules(rules: readonly WaitKitRule[]): void {\n for (const rule of rules) {\n validateDelay(rule.delay);\n validateRate(rule.errorRate, 'errorRate');\n validateRate(rule.timeoutRate, 'timeoutRate');\n validateTimeoutMs(rule.timeoutMs);\n validateStatus(rule.errorResponse?.status);\n }\n}\n\nfunction validateStatus(status: number | undefined): void {\n if (status === undefined) {\n return;\n }\n\n if (!Number.isInteger(status) || status < 200 || status > 599) {\n throw new Error('WaitKit errorResponse.status must be an integer between 200 and 599.');\n }\n}\n\nfunction createRequestEvent(input: RequestInfo | URL, init?: RequestInit): WaitKitRequestEvent {\n return {\n input,\n init,\n url: getRequestUrl(input),\n method: getRequestMethod(input, init),\n };\n}\n\nfunction createMatchEvent(\n requestEvent: WaitKitRequestEvent,\n rule: WaitKitRule,\n scenario: string | undefined,\n delayMs: number,\n): WaitKitMatchEvent {\n return {\n ...requestEvent,\n rule,\n scenario,\n delayMs,\n };\n}\n\nfunction findMatchingRule(\n rules: readonly WaitKitRule[],\n url: string,\n method: string,\n): WaitKitRule | undefined {\n return rules.find((rule) => matchesRule(rule, url, method));\n}\n\nfunction shouldTrigger(rate: number | undefined): boolean {\n if (rate === undefined || rate <= 0) {\n return false;\n }\n\n if (rate >= 1) {\n return true;\n }\n\n return Math.random() < rate;\n}\n\nfunction emitError(options: WaitKitOptions, matchEvent: WaitKitMatchEvent, error: Error): void {\n const errorEvent: WaitKitErrorEvent = {\n ...matchEvent,\n error,\n };\n\n options.onError?.(errorEvent);\n}\n\nfunction debug(options: WaitKitOptions, message: string): void {\n if (options.debug === true) {\n console.info(`[waitkit] ${message}`);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/delay.ts","../src/matcher.ts","../src/response.ts","../src/setup-wait-kit.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["export class WaitKitTimeoutError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'WaitKitTimeoutError';\n }\n}\n","import type { DelayValue } from './types';\n\nexport function resolveDelay(delay: DelayValue | undefined): number {\n if (delay === undefined) {\n return 0;\n }\n\n if (typeof delay === 'number') {\n return delay;\n }\n\n const [min, max] = delay;\n return Math.floor(min + Math.random() * (max - min + 1));\n}\n\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nexport function validateDelay(delay: DelayValue | undefined): void {\n if (delay === undefined) {\n return;\n }\n\n if (typeof delay === 'number') {\n assertNonNegativeFiniteNumber(delay, 'delay');\n return;\n }\n\n const [min, max] = delay;\n assertNonNegativeFiniteNumber(min, 'delay min');\n assertNonNegativeFiniteNumber(max, 'delay max');\n\n if (min > max) {\n throw new Error('WaitKit delay range must have min less than or equal to max.');\n }\n}\n\nexport function validateRate(rate: number | undefined, name: string): void {\n if (rate === undefined) {\n return;\n }\n\n if (!Number.isFinite(rate) || rate < 0 || rate > 1) {\n throw new Error(`WaitKit ${name} must be a number between 0 and 1.`);\n }\n}\n\nexport function validateTimeoutMs(timeoutMs: number | undefined): void {\n if (timeoutMs === undefined) {\n return;\n }\n\n assertNonNegativeFiniteNumber(timeoutMs, 'timeoutMs');\n}\n\nfunction assertNonNegativeFiniteNumber(value: number, name: string): void {\n if (!Number.isFinite(value) || value < 0) {\n throw new Error(`WaitKit ${name} must be a non-negative finite number.`);\n }\n}\n","import type { WaitKitRule } from './types';\n\nexport function matchesRule(rule: WaitKitRule, url: string, method: string): boolean {\n return matchesUrl(rule.url, url) && matchesMethod(rule.method, method);\n}\n\nfunction matchesUrl(ruleUrl: WaitKitRule['url'], url: string): boolean {\n if (typeof ruleUrl === 'string') {\n return url.includes(ruleUrl);\n }\n\n if (ruleUrl instanceof RegExp) {\n return ruleUrl.test(url);\n }\n\n return ruleUrl(url);\n}\n\nfunction matchesMethod(ruleMethod: WaitKitRule['method'], method: string): boolean {\n if (ruleMethod === undefined) {\n return true;\n }\n\n const normalizedMethod = normalizeMethod(method);\n\n if (typeof ruleMethod === 'string') {\n return normalizeMethod(ruleMethod) === normalizedMethod;\n }\n\n return ruleMethod.some((item) => normalizeMethod(item) === normalizedMethod);\n}\n\nexport function normalizeMethod(method: string | undefined): string {\n return (method ?? 'GET').toUpperCase();\n}\n\nexport function getRequestUrl(input: RequestInfo | URL): string {\n if (typeof input === 'string') {\n return input;\n }\n\n if (input instanceof URL) {\n return input.toString();\n }\n\n return input.url;\n}\n\nexport function getRequestMethod(input: RequestInfo | URL, init?: RequestInit): string {\n if (init?.method !== undefined) {\n return normalizeMethod(init.method);\n }\n\n if (typeof input === 'string' || input instanceof URL) {\n return 'GET';\n }\n\n return normalizeMethod(input.method);\n}\n","import type { WaitKitErrorResponse } from './types';\n\nexport function createErrorResponse(errorResponse: WaitKitErrorResponse | undefined): Response {\n try {\n const status = errorResponse?.status ?? 500;\n const headers = new Headers(errorResponse?.headers);\n const body = serializeBody(errorResponse?.body, headers);\n\n return new Response(body, {\n status,\n statusText: errorResponse?.statusText,\n headers,\n });\n } catch (error) {\n throw createResponseError(error);\n }\n}\n\nfunction serializeBody(body: unknown, headers: Headers): BodyInit | null {\n if (body === undefined || body === null) {\n return null;\n }\n\n if (typeof body === 'string' || isBlob(body) || isFormData(body)) {\n return body;\n }\n\n if (body instanceof ArrayBuffer || ArrayBuffer.isView(body) || isUrlSearchParams(body)) {\n return body as BodyInit;\n }\n\n if (!headers.has('content-type')) {\n headers.set('content-type', 'application/json');\n }\n\n return JSON.stringify(body);\n}\n\nfunction isBlob(body: unknown): body is Blob {\n return typeof Blob !== 'undefined' && body instanceof Blob;\n}\n\nfunction isFormData(body: unknown): body is FormData {\n return typeof FormData !== 'undefined' && body instanceof FormData;\n}\n\nfunction isUrlSearchParams(body: unknown): body is URLSearchParams {\n return typeof URLSearchParams !== 'undefined' && body instanceof URLSearchParams;\n}\n\nfunction createResponseError(error: unknown): Error {\n const reason = error instanceof Error ? error.message : String(error);\n\n return new Error(`WaitKit failed to create simulated error response: ${reason}`, {\n cause: error,\n });\n}\n","import { resolveDelay, sleep, validateDelay, validateRate, validateTimeoutMs } from './delay';\nimport { WaitKitTimeoutError } from './errors';\nimport { getRequestMethod, getRequestUrl, matchesRule } from './matcher';\nimport { createErrorResponse } from './response';\nimport type {\n WaitKitController,\n WaitKitErrorEvent,\n WaitKitMatchEvent,\n WaitKitOptions,\n WaitKitRequestEvent,\n WaitKitRule,\n WaitKitScenarioChangeReason,\n} from './types';\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nexport function setupWaitKit(options: WaitKitOptions): WaitKitController {\n validateRuntime();\n validateOptions(options);\n\n const originalFetch = globalThis.fetch;\n let enabled = options.enabled ?? true;\n let activeScenario = options.activeScenario;\n let restored = false;\n\n const patchedFetch: typeof fetch = async (input, init) => {\n if (!enabled) {\n return originalFetch.call(globalThis, input, init);\n }\n\n const requestEvent = createRequestEvent(input, init);\n options.onRequest?.(requestEvent);\n\n const rule = findMatchingRule(getActiveRules(), requestEvent.url, requestEvent.method);\n\n if (rule === undefined) {\n return originalFetch.call(globalThis, input, init);\n }\n\n const delayMs = resolveDelay(rule.delay);\n const matchEvent = createMatchEvent(requestEvent, rule, activeScenario, delayMs);\n options.onMatch?.(matchEvent);\n\n if (delayMs > 0) {\n options.onDelayStart?.(matchEvent);\n debug(options, `${requestEvent.method} ${requestEvent.url} delayed by ${delayMs}ms`);\n await sleep(delayMs);\n options.onDelayEnd?.(matchEvent);\n }\n\n if (shouldTrigger(rule.timeoutRate)) {\n const timeoutMs = rule.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const error = new WaitKitTimeoutError(\n `WaitKit timed out ${requestEvent.method} ${requestEvent.url} after ${timeoutMs}ms.`,\n );\n emitError(options, matchEvent, error);\n debug(options, `${requestEvent.method} ${requestEvent.url} timed out after ${timeoutMs}ms`);\n await sleep(timeoutMs);\n throw error;\n }\n\n if (shouldTrigger(rule.errorRate)) {\n const response = createErrorResponse(rule.errorResponse);\n const error = new Error(\n `WaitKit simulated ${response.status} response for ${requestEvent.method} ${requestEvent.url}.`,\n );\n emitError(options, matchEvent, error);\n debug(options, `${requestEvent.method} ${requestEvent.url} returned ${response.status}`);\n return response;\n }\n\n return originalFetch.call(globalThis, input, init);\n };\n\n globalThis.fetch = patchedFetch;\n\n function getActiveRules(): readonly WaitKitRule[] {\n if (activeScenario === undefined) {\n return options.rules ?? [];\n }\n\n return options.scenarios?.[activeScenario] ?? [];\n }\n\n return {\n enable() {\n enabled = true;\n\n if (restored) {\n globalThis.fetch = patchedFetch;\n restored = false;\n }\n },\n disable() {\n enabled = false;\n },\n restore() {\n if (globalThis.fetch === patchedFetch) {\n globalThis.fetch = originalFetch;\n }\n\n enabled = false;\n restored = true;\n },\n isEnabled() {\n return enabled;\n },\n setScenario(name: string) {\n if (options.scenarios?.[name] === undefined) {\n throw new Error(`WaitKit scenario \"${name}\" does not exist.`);\n }\n\n if (activeScenario === name) {\n return;\n }\n\n const previousScenario = activeScenario;\n activeScenario = name;\n emitScenarioChange(options, previousScenario, activeScenario, 'setScenario');\n },\n getScenario() {\n return activeScenario;\n },\n resetScenario() {\n if (activeScenario === undefined) {\n return;\n }\n\n const previousScenario = activeScenario;\n activeScenario = undefined;\n emitScenarioChange(options, previousScenario, activeScenario, 'resetScenario');\n },\n };\n}\n\nfunction validateRuntime(): void {\n if (typeof globalThis.fetch !== 'function') {\n throw new Error('WaitKit requires globalThis.fetch.');\n }\n\n if (typeof Response !== 'function') {\n throw new Error('WaitKit requires globalThis.Response.');\n }\n}\n\nfunction validateOptions(options: WaitKitOptions): void {\n validateRules(options.rules ?? []);\n\n if (options.scenarios !== undefined) {\n for (const rules of Object.values(options.scenarios)) {\n validateRules(rules);\n }\n }\n\n if (\n options.activeScenario !== undefined &&\n options.scenarios?.[options.activeScenario] === undefined\n ) {\n throw new Error(`WaitKit scenario \"${options.activeScenario}\" does not exist.`);\n }\n}\n\nfunction validateRules(rules: readonly WaitKitRule[]): void {\n for (const rule of rules) {\n validateDelay(rule.delay);\n validateRate(rule.errorRate, 'errorRate');\n validateRate(rule.timeoutRate, 'timeoutRate');\n validateTimeoutMs(rule.timeoutMs);\n validateStatus(rule.errorResponse?.status);\n }\n}\n\nfunction validateStatus(status: number | undefined): void {\n if (status === undefined) {\n return;\n }\n\n if (!Number.isInteger(status) || status < 200 || status > 599) {\n throw new Error('WaitKit errorResponse.status must be an integer between 200 and 599.');\n }\n}\n\nfunction createRequestEvent(input: RequestInfo | URL, init?: RequestInit): WaitKitRequestEvent {\n return {\n input,\n init,\n url: getRequestUrl(input),\n method: getRequestMethod(input, init),\n };\n}\n\nfunction createMatchEvent(\n requestEvent: WaitKitRequestEvent,\n rule: WaitKitRule,\n scenario: string | undefined,\n delayMs: number,\n): WaitKitMatchEvent {\n return {\n ...requestEvent,\n rule,\n scenario,\n delayMs,\n };\n}\n\nfunction findMatchingRule(\n rules: readonly WaitKitRule[],\n url: string,\n method: string,\n): WaitKitRule | undefined {\n return rules.find((rule) => matchesRule(rule, url, method));\n}\n\nfunction shouldTrigger(rate: number | undefined): boolean {\n if (rate === undefined || rate <= 0) {\n return false;\n }\n\n if (rate >= 1) {\n return true;\n }\n\n return Math.random() < rate;\n}\n\nfunction emitError(options: WaitKitOptions, matchEvent: WaitKitMatchEvent, error: Error): void {\n const errorEvent: WaitKitErrorEvent = {\n ...matchEvent,\n error,\n };\n\n options.onError?.(errorEvent);\n}\n\nfunction emitScenarioChange(\n options: WaitKitOptions,\n previousScenario: string | undefined,\n scenario: string | undefined,\n reason: WaitKitScenarioChangeReason,\n): void {\n options.onScenarioChange?.({\n previousScenario,\n scenario,\n reason,\n });\n}\n\nfunction debug(options: WaitKitOptions, message: string): void {\n if (options.debug === true) {\n console.info(`[waitkit] ${message}`);\n }\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -35,6 +35,12 @@ type WaitKitDelayEvent = WaitKitMatchEvent;
|
|
|
35
35
|
interface WaitKitErrorEvent extends WaitKitMatchEvent {
|
|
36
36
|
error: Error;
|
|
37
37
|
}
|
|
38
|
+
type WaitKitScenarioChangeReason = 'setScenario' | 'resetScenario';
|
|
39
|
+
interface WaitKitScenarioChangeEvent {
|
|
40
|
+
previousScenario?: string;
|
|
41
|
+
scenario?: string;
|
|
42
|
+
reason: WaitKitScenarioChangeReason;
|
|
43
|
+
}
|
|
38
44
|
interface WaitKitOptions {
|
|
39
45
|
enabled?: boolean;
|
|
40
46
|
rules?: readonly WaitKitRule[];
|
|
@@ -46,6 +52,7 @@ interface WaitKitOptions {
|
|
|
46
52
|
onDelayStart?: (event: WaitKitDelayEvent) => void;
|
|
47
53
|
onDelayEnd?: (event: WaitKitDelayEvent) => void;
|
|
48
54
|
onError?: (event: WaitKitErrorEvent) => void;
|
|
55
|
+
onScenarioChange?: (event: WaitKitScenarioChangeEvent) => void;
|
|
49
56
|
}
|
|
50
57
|
interface WaitKitController {
|
|
51
58
|
enable: () => void;
|
|
@@ -59,4 +66,4 @@ interface WaitKitController {
|
|
|
59
66
|
|
|
60
67
|
declare function setupWaitKit(options: WaitKitOptions): WaitKitController;
|
|
61
68
|
|
|
62
|
-
export { type DelayValue, type HttpMethod, type UrlMatcher, type WaitKitController, type WaitKitDelayEvent, type WaitKitErrorEvent, type WaitKitErrorResponse, type WaitKitMatchEvent, type WaitKitOptions, type WaitKitRequestEvent, type WaitKitRule, WaitKitTimeoutError, setupWaitKit };
|
|
69
|
+
export { type DelayValue, type HttpMethod, type UrlMatcher, type WaitKitController, type WaitKitDelayEvent, type WaitKitErrorEvent, type WaitKitErrorResponse, type WaitKitMatchEvent, type WaitKitOptions, type WaitKitRequestEvent, type WaitKitRule, type WaitKitScenarioChangeEvent, type WaitKitScenarioChangeReason, WaitKitTimeoutError, setupWaitKit };
|
package/dist/index.d.ts
CHANGED
|
@@ -35,6 +35,12 @@ type WaitKitDelayEvent = WaitKitMatchEvent;
|
|
|
35
35
|
interface WaitKitErrorEvent extends WaitKitMatchEvent {
|
|
36
36
|
error: Error;
|
|
37
37
|
}
|
|
38
|
+
type WaitKitScenarioChangeReason = 'setScenario' | 'resetScenario';
|
|
39
|
+
interface WaitKitScenarioChangeEvent {
|
|
40
|
+
previousScenario?: string;
|
|
41
|
+
scenario?: string;
|
|
42
|
+
reason: WaitKitScenarioChangeReason;
|
|
43
|
+
}
|
|
38
44
|
interface WaitKitOptions {
|
|
39
45
|
enabled?: boolean;
|
|
40
46
|
rules?: readonly WaitKitRule[];
|
|
@@ -46,6 +52,7 @@ interface WaitKitOptions {
|
|
|
46
52
|
onDelayStart?: (event: WaitKitDelayEvent) => void;
|
|
47
53
|
onDelayEnd?: (event: WaitKitDelayEvent) => void;
|
|
48
54
|
onError?: (event: WaitKitErrorEvent) => void;
|
|
55
|
+
onScenarioChange?: (event: WaitKitScenarioChangeEvent) => void;
|
|
49
56
|
}
|
|
50
57
|
interface WaitKitController {
|
|
51
58
|
enable: () => void;
|
|
@@ -59,4 +66,4 @@ interface WaitKitController {
|
|
|
59
66
|
|
|
60
67
|
declare function setupWaitKit(options: WaitKitOptions): WaitKitController;
|
|
61
68
|
|
|
62
|
-
export { type DelayValue, type HttpMethod, type UrlMatcher, type WaitKitController, type WaitKitDelayEvent, type WaitKitErrorEvent, type WaitKitErrorResponse, type WaitKitMatchEvent, type WaitKitOptions, type WaitKitRequestEvent, type WaitKitRule, WaitKitTimeoutError, setupWaitKit };
|
|
69
|
+
export { type DelayValue, type HttpMethod, type UrlMatcher, type WaitKitController, type WaitKitDelayEvent, type WaitKitErrorEvent, type WaitKitErrorResponse, type WaitKitMatchEvent, type WaitKitOptions, type WaitKitRequestEvent, type WaitKitRule, type WaitKitScenarioChangeEvent, type WaitKitScenarioChangeReason, WaitKitTimeoutError, setupWaitKit };
|
package/dist/index.js
CHANGED
|
@@ -104,14 +104,18 @@ function getRequestMethod(input, init) {
|
|
|
104
104
|
|
|
105
105
|
// src/response.ts
|
|
106
106
|
function createErrorResponse(errorResponse) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
107
|
+
try {
|
|
108
|
+
const status = errorResponse?.status ?? 500;
|
|
109
|
+
const headers = new Headers(errorResponse?.headers);
|
|
110
|
+
const body = serializeBody(errorResponse?.body, headers);
|
|
111
|
+
return new Response(body, {
|
|
112
|
+
status,
|
|
113
|
+
statusText: errorResponse?.statusText,
|
|
114
|
+
headers
|
|
115
|
+
});
|
|
116
|
+
} catch (error) {
|
|
117
|
+
throw createResponseError(error);
|
|
118
|
+
}
|
|
115
119
|
}
|
|
116
120
|
function serializeBody(body, headers) {
|
|
117
121
|
if (body === void 0 || body === null) {
|
|
@@ -137,6 +141,12 @@ function isFormData(body) {
|
|
|
137
141
|
function isUrlSearchParams(body) {
|
|
138
142
|
return typeof URLSearchParams !== "undefined" && body instanceof URLSearchParams;
|
|
139
143
|
}
|
|
144
|
+
function createResponseError(error) {
|
|
145
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
146
|
+
return new Error(`WaitKit failed to create simulated error response: ${reason}`, {
|
|
147
|
+
cause: error
|
|
148
|
+
});
|
|
149
|
+
}
|
|
140
150
|
|
|
141
151
|
// src/setup-wait-kit.ts
|
|
142
152
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
@@ -219,13 +229,23 @@ function setupWaitKit(options) {
|
|
|
219
229
|
if (options.scenarios?.[name] === void 0) {
|
|
220
230
|
throw new Error(`WaitKit scenario "${name}" does not exist.`);
|
|
221
231
|
}
|
|
232
|
+
if (activeScenario === name) {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
const previousScenario = activeScenario;
|
|
222
236
|
activeScenario = name;
|
|
237
|
+
emitScenarioChange(options, previousScenario, activeScenario, "setScenario");
|
|
223
238
|
},
|
|
224
239
|
getScenario() {
|
|
225
240
|
return activeScenario;
|
|
226
241
|
},
|
|
227
242
|
resetScenario() {
|
|
243
|
+
if (activeScenario === void 0) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const previousScenario = activeScenario;
|
|
228
247
|
activeScenario = void 0;
|
|
248
|
+
emitScenarioChange(options, previousScenario, activeScenario, "resetScenario");
|
|
229
249
|
}
|
|
230
250
|
};
|
|
231
251
|
}
|
|
@@ -300,6 +320,13 @@ function emitError(options, matchEvent, error) {
|
|
|
300
320
|
};
|
|
301
321
|
options.onError?.(errorEvent);
|
|
302
322
|
}
|
|
323
|
+
function emitScenarioChange(options, previousScenario, scenario, reason) {
|
|
324
|
+
options.onScenarioChange?.({
|
|
325
|
+
previousScenario,
|
|
326
|
+
scenario,
|
|
327
|
+
reason
|
|
328
|
+
});
|
|
329
|
+
}
|
|
303
330
|
function debug(options, message) {
|
|
304
331
|
if (options.debug === true) {
|
|
305
332
|
console.info(`[waitkit] ${message}`);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/delay.ts","../src/matcher.ts","../src/response.ts","../src/setup-wait-kit.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export class WaitKitTimeoutError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'WaitKitTimeoutError';\n }\n}\n","import type { DelayValue } from './types';\n\nexport function resolveDelay(delay: DelayValue | undefined): number {\n if (delay === undefined) {\n return 0;\n }\n\n if (typeof delay === 'number') {\n return delay;\n }\n\n const [min, max] = delay;\n return Math.floor(min + Math.random() * (max - min + 1));\n}\n\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nexport function validateDelay(delay: DelayValue | undefined): void {\n if (delay === undefined) {\n return;\n }\n\n if (typeof delay === 'number') {\n assertNonNegativeFiniteNumber(delay, 'delay');\n return;\n }\n\n const [min, max] = delay;\n assertNonNegativeFiniteNumber(min, 'delay min');\n assertNonNegativeFiniteNumber(max, 'delay max');\n\n if (min > max) {\n throw new Error('WaitKit delay range must have min less than or equal to max.');\n }\n}\n\nexport function validateRate(rate: number | undefined, name: string): void {\n if (rate === undefined) {\n return;\n }\n\n if (!Number.isFinite(rate) || rate < 0 || rate > 1) {\n throw new Error(`WaitKit ${name} must be a number between 0 and 1.`);\n }\n}\n\nexport function validateTimeoutMs(timeoutMs: number | undefined): void {\n if (timeoutMs === undefined) {\n return;\n }\n\n assertNonNegativeFiniteNumber(timeoutMs, 'timeoutMs');\n}\n\nfunction assertNonNegativeFiniteNumber(value: number, name: string): void {\n if (!Number.isFinite(value) || value < 0) {\n throw new Error(`WaitKit ${name} must be a non-negative finite number.`);\n }\n}\n","import type { WaitKitRule } from './types';\n\nexport function matchesRule(rule: WaitKitRule, url: string, method: string): boolean {\n return matchesUrl(rule.url, url) && matchesMethod(rule.method, method);\n}\n\nfunction matchesUrl(ruleUrl: WaitKitRule['url'], url: string): boolean {\n if (typeof ruleUrl === 'string') {\n return url.includes(ruleUrl);\n }\n\n if (ruleUrl instanceof RegExp) {\n return ruleUrl.test(url);\n }\n\n return ruleUrl(url);\n}\n\nfunction matchesMethod(ruleMethod: WaitKitRule['method'], method: string): boolean {\n if (ruleMethod === undefined) {\n return true;\n }\n\n const normalizedMethod = normalizeMethod(method);\n\n if (typeof ruleMethod === 'string') {\n return normalizeMethod(ruleMethod) === normalizedMethod;\n }\n\n return ruleMethod.some((item) => normalizeMethod(item) === normalizedMethod);\n}\n\nexport function normalizeMethod(method: string | undefined): string {\n return (method ?? 'GET').toUpperCase();\n}\n\nexport function getRequestUrl(input: RequestInfo | URL): string {\n if (typeof input === 'string') {\n return input;\n }\n\n if (input instanceof URL) {\n return input.toString();\n }\n\n return input.url;\n}\n\nexport function getRequestMethod(input: RequestInfo | URL, init?: RequestInit): string {\n if (init?.method !== undefined) {\n return normalizeMethod(init.method);\n }\n\n if (typeof input === 'string' || input instanceof URL) {\n return 'GET';\n }\n\n return normalizeMethod(input.method);\n}\n","import type { WaitKitErrorResponse } from './types';\n\nexport function createErrorResponse(errorResponse: WaitKitErrorResponse | undefined): Response {\n const status = errorResponse?.status ?? 500;\n const headers = new Headers(errorResponse?.headers);\n const body = serializeBody(errorResponse?.body, headers);\n\n return new Response(body, {\n status,\n statusText: errorResponse?.statusText,\n headers,\n });\n}\n\nfunction serializeBody(body: unknown, headers: Headers): BodyInit | null {\n if (body === undefined || body === null) {\n return null;\n }\n\n if (typeof body === 'string' || isBlob(body) || isFormData(body)) {\n return body;\n }\n\n if (body instanceof ArrayBuffer || ArrayBuffer.isView(body) || isUrlSearchParams(body)) {\n return body as BodyInit;\n }\n\n if (!headers.has('content-type')) {\n headers.set('content-type', 'application/json');\n }\n\n return JSON.stringify(body);\n}\n\nfunction isBlob(body: unknown): body is Blob {\n return typeof Blob !== 'undefined' && body instanceof Blob;\n}\n\nfunction isFormData(body: unknown): body is FormData {\n return typeof FormData !== 'undefined' && body instanceof FormData;\n}\n\nfunction isUrlSearchParams(body: unknown): body is URLSearchParams {\n return typeof URLSearchParams !== 'undefined' && body instanceof URLSearchParams;\n}\n","import { resolveDelay, sleep, validateDelay, validateRate, validateTimeoutMs } from './delay';\nimport { WaitKitTimeoutError } from './errors';\nimport { getRequestMethod, getRequestUrl, matchesRule } from './matcher';\nimport { createErrorResponse } from './response';\nimport type {\n WaitKitController,\n WaitKitErrorEvent,\n WaitKitMatchEvent,\n WaitKitOptions,\n WaitKitRequestEvent,\n WaitKitRule,\n} from './types';\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nexport function setupWaitKit(options: WaitKitOptions): WaitKitController {\n validateRuntime();\n validateOptions(options);\n\n const originalFetch = globalThis.fetch;\n let enabled = options.enabled ?? true;\n let activeScenario = options.activeScenario;\n let restored = false;\n\n const patchedFetch: typeof fetch = async (input, init) => {\n if (!enabled) {\n return originalFetch.call(globalThis, input, init);\n }\n\n const requestEvent = createRequestEvent(input, init);\n options.onRequest?.(requestEvent);\n\n const rule = findMatchingRule(getActiveRules(), requestEvent.url, requestEvent.method);\n\n if (rule === undefined) {\n return originalFetch.call(globalThis, input, init);\n }\n\n const delayMs = resolveDelay(rule.delay);\n const matchEvent = createMatchEvent(requestEvent, rule, activeScenario, delayMs);\n options.onMatch?.(matchEvent);\n\n if (delayMs > 0) {\n options.onDelayStart?.(matchEvent);\n debug(options, `${requestEvent.method} ${requestEvent.url} delayed by ${delayMs}ms`);\n await sleep(delayMs);\n options.onDelayEnd?.(matchEvent);\n }\n\n if (shouldTrigger(rule.timeoutRate)) {\n const timeoutMs = rule.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const error = new WaitKitTimeoutError(\n `WaitKit timed out ${requestEvent.method} ${requestEvent.url} after ${timeoutMs}ms.`,\n );\n emitError(options, matchEvent, error);\n debug(options, `${requestEvent.method} ${requestEvent.url} timed out after ${timeoutMs}ms`);\n await sleep(timeoutMs);\n throw error;\n }\n\n if (shouldTrigger(rule.errorRate)) {\n const response = createErrorResponse(rule.errorResponse);\n const error = new Error(\n `WaitKit simulated ${response.status} response for ${requestEvent.method} ${requestEvent.url}.`,\n );\n emitError(options, matchEvent, error);\n debug(options, `${requestEvent.method} ${requestEvent.url} returned ${response.status}`);\n return response;\n }\n\n return originalFetch.call(globalThis, input, init);\n };\n\n globalThis.fetch = patchedFetch;\n\n function getActiveRules(): readonly WaitKitRule[] {\n if (activeScenario === undefined) {\n return options.rules ?? [];\n }\n\n return options.scenarios?.[activeScenario] ?? [];\n }\n\n return {\n enable() {\n enabled = true;\n\n if (restored) {\n globalThis.fetch = patchedFetch;\n restored = false;\n }\n },\n disable() {\n enabled = false;\n },\n restore() {\n if (globalThis.fetch === patchedFetch) {\n globalThis.fetch = originalFetch;\n }\n\n enabled = false;\n restored = true;\n },\n isEnabled() {\n return enabled;\n },\n setScenario(name: string) {\n if (options.scenarios?.[name] === undefined) {\n throw new Error(`WaitKit scenario \"${name}\" does not exist.`);\n }\n\n activeScenario = name;\n },\n getScenario() {\n return activeScenario;\n },\n resetScenario() {\n activeScenario = undefined;\n },\n };\n}\n\nfunction validateRuntime(): void {\n if (typeof globalThis.fetch !== 'function') {\n throw new Error('WaitKit requires globalThis.fetch.');\n }\n\n if (typeof Response !== 'function') {\n throw new Error('WaitKit requires globalThis.Response.');\n }\n}\n\nfunction validateOptions(options: WaitKitOptions): void {\n validateRules(options.rules ?? []);\n\n if (options.scenarios !== undefined) {\n for (const rules of Object.values(options.scenarios)) {\n validateRules(rules);\n }\n }\n\n if (\n options.activeScenario !== undefined &&\n options.scenarios?.[options.activeScenario] === undefined\n ) {\n throw new Error(`WaitKit scenario \"${options.activeScenario}\" does not exist.`);\n }\n}\n\nfunction validateRules(rules: readonly WaitKitRule[]): void {\n for (const rule of rules) {\n validateDelay(rule.delay);\n validateRate(rule.errorRate, 'errorRate');\n validateRate(rule.timeoutRate, 'timeoutRate');\n validateTimeoutMs(rule.timeoutMs);\n validateStatus(rule.errorResponse?.status);\n }\n}\n\nfunction validateStatus(status: number | undefined): void {\n if (status === undefined) {\n return;\n }\n\n if (!Number.isInteger(status) || status < 200 || status > 599) {\n throw new Error('WaitKit errorResponse.status must be an integer between 200 and 599.');\n }\n}\n\nfunction createRequestEvent(input: RequestInfo | URL, init?: RequestInit): WaitKitRequestEvent {\n return {\n input,\n init,\n url: getRequestUrl(input),\n method: getRequestMethod(input, init),\n };\n}\n\nfunction createMatchEvent(\n requestEvent: WaitKitRequestEvent,\n rule: WaitKitRule,\n scenario: string | undefined,\n delayMs: number,\n): WaitKitMatchEvent {\n return {\n ...requestEvent,\n rule,\n scenario,\n delayMs,\n };\n}\n\nfunction findMatchingRule(\n rules: readonly WaitKitRule[],\n url: string,\n method: string,\n): WaitKitRule | undefined {\n return rules.find((rule) => matchesRule(rule, url, method));\n}\n\nfunction shouldTrigger(rate: number | undefined): boolean {\n if (rate === undefined || rate <= 0) {\n return false;\n }\n\n if (rate >= 1) {\n return true;\n }\n\n return Math.random() < rate;\n}\n\nfunction emitError(options: WaitKitOptions, matchEvent: WaitKitMatchEvent, error: Error): void {\n const errorEvent: WaitKitErrorEvent = {\n ...matchEvent,\n error,\n };\n\n options.onError?.(errorEvent);\n}\n\nfunction debug(options: WaitKitOptions, message: string): void {\n if (options.debug === true) {\n console.info(`[waitkit] ${message}`);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/delay.ts","../src/matcher.ts","../src/response.ts","../src/setup-wait-kit.ts"],"names":[],"mappings":";AAAO,IAAM,mBAAA,GAAN,cAAkC,KAAA,CAAM;AAAA,EAC7C,YAAY,OAAA,EAAiB;AAC3B,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,qBAAA;AAAA,EACd;AACF;;;ACHO,SAAS,aAAa,KAAA,EAAuC;AAClE,EAAA,IAAI,UAAU,MAAA,EAAW;AACvB,IAAA,OAAO,CAAA;AAAA,EACT;AAEA,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,CAAC,GAAA,EAAK,GAAG,CAAA,GAAI,KAAA;AACnB,EAAA,OAAO,IAAA,CAAK,MAAM,GAAA,GAAM,IAAA,CAAK,QAAO,IAAK,GAAA,GAAM,MAAM,CAAA,CAAE,CAAA;AACzD;AAEO,SAAS,MAAM,EAAA,EAA2B;AAC/C,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,IAAA,UAAA,CAAW,SAAS,EAAE,CAAA;AAAA,EACxB,CAAC,CAAA;AACH;AAEO,SAAS,cAAc,KAAA,EAAqC;AACjE,EAAA,IAAI,UAAU,MAAA,EAAW;AACvB,IAAA;AAAA,EACF;AAEA,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,6BAAA,CAA8B,OAAO,OAAO,CAAA;AAC5C,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,CAAC,GAAA,EAAK,GAAG,CAAA,GAAI,KAAA;AACnB,EAAA,6BAAA,CAA8B,KAAK,WAAW,CAAA;AAC9C,EAAA,6BAAA,CAA8B,KAAK,WAAW,CAAA;AAE9C,EAAA,IAAI,MAAM,GAAA,EAAK;AACb,IAAA,MAAM,IAAI,MAAM,8DAA8D,CAAA;AAAA,EAChF;AACF;AAEO,SAAS,YAAA,CAAa,MAA0B,IAAA,EAAoB;AACzE,EAAA,IAAI,SAAS,MAAA,EAAW;AACtB,IAAA;AAAA,EACF;AAEA,EAAA,IAAI,CAAC,OAAO,QAAA,CAAS,IAAI,KAAK,IAAA,GAAO,CAAA,IAAK,OAAO,CAAA,EAAG;AAClD,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,QAAA,EAAW,IAAI,CAAA,kCAAA,CAAoC,CAAA;AAAA,EACrE;AACF;AAEO,SAAS,kBAAkB,SAAA,EAAqC;AACrE,EAAA,IAAI,cAAc,MAAA,EAAW;AAC3B,IAAA;AAAA,EACF;AAEA,EAAA,6BAAA,CAA8B,WAAW,WAAW,CAAA;AACtD;AAEA,SAAS,6BAAA,CAA8B,OAAe,IAAA,EAAoB;AACxE,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,KAAK,CAAA,IAAK,QAAQ,CAAA,EAAG;AACxC,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,QAAA,EAAW,IAAI,CAAA,sCAAA,CAAwC,CAAA;AAAA,EACzE;AACF;;;AC5DO,SAAS,WAAA,CAAY,IAAA,EAAmB,GAAA,EAAa,MAAA,EAAyB;AACnF,EAAA,OAAO,UAAA,CAAW,KAAK,GAAA,EAAK,GAAG,KAAK,aAAA,CAAc,IAAA,CAAK,QAAQ,MAAM,CAAA;AACvE;AAEA,SAAS,UAAA,CAAW,SAA6B,GAAA,EAAsB;AACrE,EAAA,IAAI,OAAO,YAAY,QAAA,EAAU;AAC/B,IAAA,OAAO,GAAA,CAAI,SAAS,OAAO,CAAA;AAAA,EAC7B;AAEA,EAAA,IAAI,mBAAmB,MAAA,EAAQ;AAC7B,IAAA,OAAO,OAAA,CAAQ,KAAK,GAAG,CAAA;AAAA,EACzB;AAEA,EAAA,OAAO,QAAQ,GAAG,CAAA;AACpB;AAEA,SAAS,aAAA,CAAc,YAAmC,MAAA,EAAyB;AACjF,EAAA,IAAI,eAAe,MAAA,EAAW;AAC5B,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,gBAAA,GAAmB,gBAAgB,MAAM,CAAA;AAE/C,EAAA,IAAI,OAAO,eAAe,QAAA,EAAU;AAClC,IAAA,OAAO,eAAA,CAAgB,UAAU,CAAA,KAAM,gBAAA;AAAA,EACzC;AAEA,EAAA,OAAO,WAAW,IAAA,CAAK,CAAC,SAAS,eAAA,CAAgB,IAAI,MAAM,gBAAgB,CAAA;AAC7E;AAEO,SAAS,gBAAgB,MAAA,EAAoC;AAClE,EAAA,OAAA,CAAQ,MAAA,IAAU,OAAO,WAAA,EAAY;AACvC;AAEO,SAAS,cAAc,KAAA,EAAkC;AAC9D,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,iBAAiB,GAAA,EAAK;AACxB,IAAA,OAAO,MAAM,QAAA,EAAS;AAAA,EACxB;AAEA,EAAA,OAAO,KAAA,CAAM,GAAA;AACf;AAEO,SAAS,gBAAA,CAAiB,OAA0B,IAAA,EAA4B;AACrF,EAAA,IAAI,IAAA,EAAM,WAAW,MAAA,EAAW;AAC9B,IAAA,OAAO,eAAA,CAAgB,KAAK,MAAM,CAAA;AAAA,EACpC;AAEA,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,YAAiB,GAAA,EAAK;AACrD,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,OAAO,eAAA,CAAgB,MAAM,MAAM,CAAA;AACrC;;;ACxDO,SAAS,oBAAoB,aAAA,EAA2D;AAC7F,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,eAAe,MAAA,IAAU,GAAA;AACxC,IAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAQ,aAAA,EAAe,OAAO,CAAA;AAClD,IAAA,MAAM,IAAA,GAAO,aAAA,CAAc,aAAA,EAAe,IAAA,EAAM,OAAO,CAAA;AAEvD,IAAA,OAAO,IAAI,SAAS,IAAA,EAAM;AAAA,MACxB,MAAA;AAAA,MACA,YAAY,aAAA,EAAe,UAAA;AAAA,MAC3B;AAAA,KACD,CAAA;AAAA,EACH,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,oBAAoB,KAAK,CAAA;AAAA,EACjC;AACF;AAEA,SAAS,aAAA,CAAc,MAAe,OAAA,EAAmC;AACvE,EAAA,IAAI,IAAA,KAAS,MAAA,IAAa,IAAA,KAAS,IAAA,EAAM;AACvC,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI,OAAO,SAAS,QAAA,IAAY,MAAA,CAAO,IAAI,CAAA,IAAK,UAAA,CAAW,IAAI,CAAA,EAAG;AAChE,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI,IAAA,YAAgB,eAAe,WAAA,CAAY,MAAA,CAAO,IAAI,CAAA,IAAK,iBAAA,CAAkB,IAAI,CAAA,EAAG;AACtF,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI,CAAC,OAAA,CAAQ,GAAA,CAAI,cAAc,CAAA,EAAG;AAChC,IAAA,OAAA,CAAQ,GAAA,CAAI,gBAAgB,kBAAkB,CAAA;AAAA,EAChD;AAEA,EAAA,OAAO,IAAA,CAAK,UAAU,IAAI,CAAA;AAC5B;AAEA,SAAS,OAAO,IAAA,EAA6B;AAC3C,EAAA,OAAO,OAAO,IAAA,KAAS,WAAA,IAAe,IAAA,YAAgB,IAAA;AACxD;AAEA,SAAS,WAAW,IAAA,EAAiC;AACnD,EAAA,OAAO,OAAO,QAAA,KAAa,WAAA,IAAe,IAAA,YAAgB,QAAA;AAC5D;AAEA,SAAS,kBAAkB,IAAA,EAAwC;AACjE,EAAA,OAAO,OAAO,eAAA,KAAoB,WAAA,IAAe,IAAA,YAAgB,eAAA;AACnE;AAEA,SAAS,oBAAoB,KAAA,EAAuB;AAClD,EAAA,MAAM,SAAS,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AAEpE,EAAA,OAAO,IAAI,KAAA,CAAM,CAAA,mDAAA,EAAsD,MAAM,CAAA,CAAA,EAAI;AAAA,IAC/E,KAAA,EAAO;AAAA,GACR,CAAA;AACH;;;AC1CA,IAAM,kBAAA,GAAqB,GAAA;AAEpB,SAAS,aAAa,OAAA,EAA4C;AACvE,EAAA,eAAA,EAAgB;AAChB,EAAA,eAAA,CAAgB,OAAO,CAAA;AAEvB,EAAA,MAAM,gBAAgB,UAAA,CAAW,KAAA;AACjC,EAAA,IAAI,OAAA,GAAU,QAAQ,OAAA,IAAW,IAAA;AACjC,EAAA,IAAI,iBAAiB,OAAA,CAAQ,cAAA;AAC7B,EAAA,IAAI,QAAA,GAAW,KAAA;AAEf,EAAA,MAAM,YAAA,GAA6B,OAAO,KAAA,EAAO,IAAA,KAAS;AACxD,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,OAAO,aAAA,CAAc,IAAA,CAAK,UAAA,EAAY,KAAA,EAAO,IAAI,CAAA;AAAA,IACnD;AAEA,IAAA,MAAM,YAAA,GAAe,kBAAA,CAAmB,KAAA,EAAO,IAAI,CAAA;AACnD,IAAA,OAAA,CAAQ,YAAY,YAAY,CAAA;AAEhC,IAAA,MAAM,OAAO,gBAAA,CAAiB,cAAA,IAAkB,YAAA,CAAa,GAAA,EAAK,aAAa,MAAM,CAAA;AAErF,IAAA,IAAI,SAAS,MAAA,EAAW;AACtB,MAAA,OAAO,aAAA,CAAc,IAAA,CAAK,UAAA,EAAY,KAAA,EAAO,IAAI,CAAA;AAAA,IACnD;AAEA,IAAA,MAAM,OAAA,GAAU,YAAA,CAAa,IAAA,CAAK,KAAK,CAAA;AACvC,IAAA,MAAM,UAAA,GAAa,gBAAA,CAAiB,YAAA,EAAc,IAAA,EAAM,gBAAgB,OAAO,CAAA;AAC/E,IAAA,OAAA,CAAQ,UAAU,UAAU,CAAA;AAE5B,IAAA,IAAI,UAAU,CAAA,EAAG;AACf,MAAA,OAAA,CAAQ,eAAe,UAAU,CAAA;AACjC,MAAA,KAAA,CAAM,OAAA,EAAS,GAAG,YAAA,CAAa,MAAM,IAAI,YAAA,CAAa,GAAG,CAAA,YAAA,EAAe,OAAO,CAAA,EAAA,CAAI,CAAA;AACnF,MAAA,MAAM,MAAM,OAAO,CAAA;AACnB,MAAA,OAAA,CAAQ,aAAa,UAAU,CAAA;AAAA,IACjC;AAEA,IAAA,IAAI,aAAA,CAAc,IAAA,CAAK,WAAW,CAAA,EAAG;AACnC,MAAA,MAAM,SAAA,GAAY,KAAK,SAAA,IAAa,kBAAA;AACpC,MAAA,MAAM,QAAQ,IAAI,mBAAA;AAAA,QAChB,qBAAqB,YAAA,CAAa,MAAM,IAAI,YAAA,CAAa,GAAG,UAAU,SAAS,CAAA,GAAA;AAAA,OACjF;AACA,MAAA,SAAA,CAAU,OAAA,EAAS,YAAY,KAAK,CAAA;AACpC,MAAA,KAAA,CAAM,OAAA,EAAS,GAAG,YAAA,CAAa,MAAM,IAAI,YAAA,CAAa,GAAG,CAAA,iBAAA,EAAoB,SAAS,CAAA,EAAA,CAAI,CAAA;AAC1F,MAAA,MAAM,MAAM,SAAS,CAAA;AACrB,MAAA,MAAM,KAAA;AAAA,IACR;AAEA,IAAA,IAAI,aAAA,CAAc,IAAA,CAAK,SAAS,CAAA,EAAG;AACjC,MAAA,MAAM,QAAA,GAAW,mBAAA,CAAoB,IAAA,CAAK,aAAa,CAAA;AACvD,MAAA,MAAM,QAAQ,IAAI,KAAA;AAAA,QAChB,CAAA,kBAAA,EAAqB,SAAS,MAAM,CAAA,cAAA,EAAiB,aAAa,MAAM,CAAA,CAAA,EAAI,aAAa,GAAG,CAAA,CAAA;AAAA,OAC9F;AACA,MAAA,SAAA,CAAU,OAAA,EAAS,YAAY,KAAK,CAAA;AACpC,MAAA,KAAA,CAAM,OAAA,EAAS,CAAA,EAAG,YAAA,CAAa,MAAM,CAAA,CAAA,EAAI,aAAa,GAAG,CAAA,UAAA,EAAa,QAAA,CAAS,MAAM,CAAA,CAAE,CAAA;AACvF,MAAA,OAAO,QAAA;AAAA,IACT;AAEA,IAAA,OAAO,aAAA,CAAc,IAAA,CAAK,UAAA,EAAY,KAAA,EAAO,IAAI,CAAA;AAAA,EACnD,CAAA;AAEA,EAAA,UAAA,CAAW,KAAA,GAAQ,YAAA;AAEnB,EAAA,SAAS,cAAA,GAAyC;AAChD,IAAA,IAAI,mBAAmB,MAAA,EAAW;AAChC,MAAA,OAAO,OAAA,CAAQ,SAAS,EAAC;AAAA,IAC3B;AAEA,IAAA,OAAO,OAAA,CAAQ,SAAA,GAAY,cAAc,CAAA,IAAK,EAAC;AAAA,EACjD;AAEA,EAAA,OAAO;AAAA,IACL,MAAA,GAAS;AACP,MAAA,OAAA,GAAU,IAAA;AAEV,MAAA,IAAI,QAAA,EAAU;AACZ,QAAA,UAAA,CAAW,KAAA,GAAQ,YAAA;AACnB,QAAA,QAAA,GAAW,KAAA;AAAA,MACb;AAAA,IACF,CAAA;AAAA,IACA,OAAA,GAAU;AACR,MAAA,OAAA,GAAU,KAAA;AAAA,IACZ,CAAA;AAAA,IACA,OAAA,GAAU;AACR,MAAA,IAAI,UAAA,CAAW,UAAU,YAAA,EAAc;AACrC,QAAA,UAAA,CAAW,KAAA,GAAQ,aAAA;AAAA,MACrB;AAEA,MAAA,OAAA,GAAU,KAAA;AACV,MAAA,QAAA,GAAW,IAAA;AAAA,IACb,CAAA;AAAA,IACA,SAAA,GAAY;AACV,MAAA,OAAO,OAAA;AAAA,IACT,CAAA;AAAA,IACA,YAAY,IAAA,EAAc;AACxB,MAAA,IAAI,OAAA,CAAQ,SAAA,GAAY,IAAI,CAAA,KAAM,MAAA,EAAW;AAC3C,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,kBAAA,EAAqB,IAAI,CAAA,iBAAA,CAAmB,CAAA;AAAA,MAC9D;AAEA,MAAA,IAAI,mBAAmB,IAAA,EAAM;AAC3B,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,gBAAA,GAAmB,cAAA;AACzB,MAAA,cAAA,GAAiB,IAAA;AACjB,MAAA,kBAAA,CAAmB,OAAA,EAAS,gBAAA,EAAkB,cAAA,EAAgB,aAAa,CAAA;AAAA,IAC7E,CAAA;AAAA,IACA,WAAA,GAAc;AACZ,MAAA,OAAO,cAAA;AAAA,IACT,CAAA;AAAA,IACA,aAAA,GAAgB;AACd,MAAA,IAAI,mBAAmB,MAAA,EAAW;AAChC,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,gBAAA,GAAmB,cAAA;AACzB,MAAA,cAAA,GAAiB,MAAA;AACjB,MAAA,kBAAA,CAAmB,OAAA,EAAS,gBAAA,EAAkB,cAAA,EAAgB,eAAe,CAAA;AAAA,IAC/E;AAAA,GACF;AACF;AAEA,SAAS,eAAA,GAAwB;AAC/B,EAAA,IAAI,OAAO,UAAA,CAAW,KAAA,KAAU,UAAA,EAAY;AAC1C,IAAA,MAAM,IAAI,MAAM,oCAAoC,CAAA;AAAA,EACtD;AAEA,EAAA,IAAI,OAAO,aAAa,UAAA,EAAY;AAClC,IAAA,MAAM,IAAI,MAAM,uCAAuC,CAAA;AAAA,EACzD;AACF;AAEA,SAAS,gBAAgB,OAAA,EAA+B;AACtD,EAAA,aAAA,CAAc,OAAA,CAAQ,KAAA,IAAS,EAAE,CAAA;AAEjC,EAAA,IAAI,OAAA,CAAQ,cAAc,MAAA,EAAW;AACnC,IAAA,KAAA,MAAW,KAAA,IAAS,MAAA,CAAO,MAAA,CAAO,OAAA,CAAQ,SAAS,CAAA,EAAG;AACpD,MAAA,aAAA,CAAc,KAAK,CAAA;AAAA,IACrB;AAAA,EACF;AAEA,EAAA,IACE,OAAA,CAAQ,mBAAmB,MAAA,IAC3B,OAAA,CAAQ,YAAY,OAAA,CAAQ,cAAc,MAAM,MAAA,EAChD;AACA,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,kBAAA,EAAqB,OAAA,CAAQ,cAAc,CAAA,iBAAA,CAAmB,CAAA;AAAA,EAChF;AACF;AAEA,SAAS,cAAc,KAAA,EAAqC;AAC1D,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,aAAA,CAAc,KAAK,KAAK,CAAA;AACxB,IAAA,YAAA,CAAa,IAAA,CAAK,WAAW,WAAW,CAAA;AACxC,IAAA,YAAA,CAAa,IAAA,CAAK,aAAa,aAAa,CAAA;AAC5C,IAAA,iBAAA,CAAkB,KAAK,SAAS,CAAA;AAChC,IAAA,cAAA,CAAe,IAAA,CAAK,eAAe,MAAM,CAAA;AAAA,EAC3C;AACF;AAEA,SAAS,eAAe,MAAA,EAAkC;AACxD,EAAA,IAAI,WAAW,MAAA,EAAW;AACxB,IAAA;AAAA,EACF;AAEA,EAAA,IAAI,CAAC,OAAO,SAAA,CAAU,MAAM,KAAK,MAAA,GAAS,GAAA,IAAO,SAAS,GAAA,EAAK;AAC7D,IAAA,MAAM,IAAI,MAAM,sEAAsE,CAAA;AAAA,EACxF;AACF;AAEA,SAAS,kBAAA,CAAmB,OAA0B,IAAA,EAAyC;AAC7F,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,IAAA;AAAA,IACA,GAAA,EAAK,cAAc,KAAK,CAAA;AAAA,IACxB,MAAA,EAAQ,gBAAA,CAAiB,KAAA,EAAO,IAAI;AAAA,GACtC;AACF;AAEA,SAAS,gBAAA,CACP,YAAA,EACA,IAAA,EACA,QAAA,EACA,OAAA,EACmB;AACnB,EAAA,OAAO;AAAA,IACL,GAAG,YAAA;AAAA,IACH,IAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GACF;AACF;AAEA,SAAS,gBAAA,CACP,KAAA,EACA,GAAA,EACA,MAAA,EACyB;AACzB,EAAA,OAAO,KAAA,CAAM,KAAK,CAAC,IAAA,KAAS,YAAY,IAAA,EAAM,GAAA,EAAK,MAAM,CAAC,CAAA;AAC5D;AAEA,SAAS,cAAc,IAAA,EAAmC;AACxD,EAAA,IAAI,IAAA,KAAS,MAAA,IAAa,IAAA,IAAQ,CAAA,EAAG;AACnC,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,QAAQ,CAAA,EAAG;AACb,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO,IAAA,CAAK,QAAO,GAAI,IAAA;AACzB;AAEA,SAAS,SAAA,CAAU,OAAA,EAAyB,UAAA,EAA+B,KAAA,EAAoB;AAC7F,EAAA,MAAM,UAAA,GAAgC;AAAA,IACpC,GAAG,UAAA;AAAA,IACH;AAAA,GACF;AAEA,EAAA,OAAA,CAAQ,UAAU,UAAU,CAAA;AAC9B;AAEA,SAAS,kBAAA,CACP,OAAA,EACA,gBAAA,EACA,QAAA,EACA,MAAA,EACM;AACN,EAAA,OAAA,CAAQ,gBAAA,GAAmB;AAAA,IACzB,gBAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GACD,CAAA;AACH;AAEA,SAAS,KAAA,CAAM,SAAyB,OAAA,EAAuB;AAC7D,EAAA,IAAI,OAAA,CAAQ,UAAU,IAAA,EAAM;AAC1B,IAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,UAAA,EAAa,OAAO,CAAA,CAAE,CAAA;AAAA,EACrC;AACF","file":"index.js","sourcesContent":["export class WaitKitTimeoutError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'WaitKitTimeoutError';\n }\n}\n","import type { DelayValue } from './types';\n\nexport function resolveDelay(delay: DelayValue | undefined): number {\n if (delay === undefined) {\n return 0;\n }\n\n if (typeof delay === 'number') {\n return delay;\n }\n\n const [min, max] = delay;\n return Math.floor(min + Math.random() * (max - min + 1));\n}\n\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nexport function validateDelay(delay: DelayValue | undefined): void {\n if (delay === undefined) {\n return;\n }\n\n if (typeof delay === 'number') {\n assertNonNegativeFiniteNumber(delay, 'delay');\n return;\n }\n\n const [min, max] = delay;\n assertNonNegativeFiniteNumber(min, 'delay min');\n assertNonNegativeFiniteNumber(max, 'delay max');\n\n if (min > max) {\n throw new Error('WaitKit delay range must have min less than or equal to max.');\n }\n}\n\nexport function validateRate(rate: number | undefined, name: string): void {\n if (rate === undefined) {\n return;\n }\n\n if (!Number.isFinite(rate) || rate < 0 || rate > 1) {\n throw new Error(`WaitKit ${name} must be a number between 0 and 1.`);\n }\n}\n\nexport function validateTimeoutMs(timeoutMs: number | undefined): void {\n if (timeoutMs === undefined) {\n return;\n }\n\n assertNonNegativeFiniteNumber(timeoutMs, 'timeoutMs');\n}\n\nfunction assertNonNegativeFiniteNumber(value: number, name: string): void {\n if (!Number.isFinite(value) || value < 0) {\n throw new Error(`WaitKit ${name} must be a non-negative finite number.`);\n }\n}\n","import type { WaitKitRule } from './types';\n\nexport function matchesRule(rule: WaitKitRule, url: string, method: string): boolean {\n return matchesUrl(rule.url, url) && matchesMethod(rule.method, method);\n}\n\nfunction matchesUrl(ruleUrl: WaitKitRule['url'], url: string): boolean {\n if (typeof ruleUrl === 'string') {\n return url.includes(ruleUrl);\n }\n\n if (ruleUrl instanceof RegExp) {\n return ruleUrl.test(url);\n }\n\n return ruleUrl(url);\n}\n\nfunction matchesMethod(ruleMethod: WaitKitRule['method'], method: string): boolean {\n if (ruleMethod === undefined) {\n return true;\n }\n\n const normalizedMethod = normalizeMethod(method);\n\n if (typeof ruleMethod === 'string') {\n return normalizeMethod(ruleMethod) === normalizedMethod;\n }\n\n return ruleMethod.some((item) => normalizeMethod(item) === normalizedMethod);\n}\n\nexport function normalizeMethod(method: string | undefined): string {\n return (method ?? 'GET').toUpperCase();\n}\n\nexport function getRequestUrl(input: RequestInfo | URL): string {\n if (typeof input === 'string') {\n return input;\n }\n\n if (input instanceof URL) {\n return input.toString();\n }\n\n return input.url;\n}\n\nexport function getRequestMethod(input: RequestInfo | URL, init?: RequestInit): string {\n if (init?.method !== undefined) {\n return normalizeMethod(init.method);\n }\n\n if (typeof input === 'string' || input instanceof URL) {\n return 'GET';\n }\n\n return normalizeMethod(input.method);\n}\n","import type { WaitKitErrorResponse } from './types';\n\nexport function createErrorResponse(errorResponse: WaitKitErrorResponse | undefined): Response {\n try {\n const status = errorResponse?.status ?? 500;\n const headers = new Headers(errorResponse?.headers);\n const body = serializeBody(errorResponse?.body, headers);\n\n return new Response(body, {\n status,\n statusText: errorResponse?.statusText,\n headers,\n });\n } catch (error) {\n throw createResponseError(error);\n }\n}\n\nfunction serializeBody(body: unknown, headers: Headers): BodyInit | null {\n if (body === undefined || body === null) {\n return null;\n }\n\n if (typeof body === 'string' || isBlob(body) || isFormData(body)) {\n return body;\n }\n\n if (body instanceof ArrayBuffer || ArrayBuffer.isView(body) || isUrlSearchParams(body)) {\n return body as BodyInit;\n }\n\n if (!headers.has('content-type')) {\n headers.set('content-type', 'application/json');\n }\n\n return JSON.stringify(body);\n}\n\nfunction isBlob(body: unknown): body is Blob {\n return typeof Blob !== 'undefined' && body instanceof Blob;\n}\n\nfunction isFormData(body: unknown): body is FormData {\n return typeof FormData !== 'undefined' && body instanceof FormData;\n}\n\nfunction isUrlSearchParams(body: unknown): body is URLSearchParams {\n return typeof URLSearchParams !== 'undefined' && body instanceof URLSearchParams;\n}\n\nfunction createResponseError(error: unknown): Error {\n const reason = error instanceof Error ? error.message : String(error);\n\n return new Error(`WaitKit failed to create simulated error response: ${reason}`, {\n cause: error,\n });\n}\n","import { resolveDelay, sleep, validateDelay, validateRate, validateTimeoutMs } from './delay';\nimport { WaitKitTimeoutError } from './errors';\nimport { getRequestMethod, getRequestUrl, matchesRule } from './matcher';\nimport { createErrorResponse } from './response';\nimport type {\n WaitKitController,\n WaitKitErrorEvent,\n WaitKitMatchEvent,\n WaitKitOptions,\n WaitKitRequestEvent,\n WaitKitRule,\n WaitKitScenarioChangeReason,\n} from './types';\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nexport function setupWaitKit(options: WaitKitOptions): WaitKitController {\n validateRuntime();\n validateOptions(options);\n\n const originalFetch = globalThis.fetch;\n let enabled = options.enabled ?? true;\n let activeScenario = options.activeScenario;\n let restored = false;\n\n const patchedFetch: typeof fetch = async (input, init) => {\n if (!enabled) {\n return originalFetch.call(globalThis, input, init);\n }\n\n const requestEvent = createRequestEvent(input, init);\n options.onRequest?.(requestEvent);\n\n const rule = findMatchingRule(getActiveRules(), requestEvent.url, requestEvent.method);\n\n if (rule === undefined) {\n return originalFetch.call(globalThis, input, init);\n }\n\n const delayMs = resolveDelay(rule.delay);\n const matchEvent = createMatchEvent(requestEvent, rule, activeScenario, delayMs);\n options.onMatch?.(matchEvent);\n\n if (delayMs > 0) {\n options.onDelayStart?.(matchEvent);\n debug(options, `${requestEvent.method} ${requestEvent.url} delayed by ${delayMs}ms`);\n await sleep(delayMs);\n options.onDelayEnd?.(matchEvent);\n }\n\n if (shouldTrigger(rule.timeoutRate)) {\n const timeoutMs = rule.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const error = new WaitKitTimeoutError(\n `WaitKit timed out ${requestEvent.method} ${requestEvent.url} after ${timeoutMs}ms.`,\n );\n emitError(options, matchEvent, error);\n debug(options, `${requestEvent.method} ${requestEvent.url} timed out after ${timeoutMs}ms`);\n await sleep(timeoutMs);\n throw error;\n }\n\n if (shouldTrigger(rule.errorRate)) {\n const response = createErrorResponse(rule.errorResponse);\n const error = new Error(\n `WaitKit simulated ${response.status} response for ${requestEvent.method} ${requestEvent.url}.`,\n );\n emitError(options, matchEvent, error);\n debug(options, `${requestEvent.method} ${requestEvent.url} returned ${response.status}`);\n return response;\n }\n\n return originalFetch.call(globalThis, input, init);\n };\n\n globalThis.fetch = patchedFetch;\n\n function getActiveRules(): readonly WaitKitRule[] {\n if (activeScenario === undefined) {\n return options.rules ?? [];\n }\n\n return options.scenarios?.[activeScenario] ?? [];\n }\n\n return {\n enable() {\n enabled = true;\n\n if (restored) {\n globalThis.fetch = patchedFetch;\n restored = false;\n }\n },\n disable() {\n enabled = false;\n },\n restore() {\n if (globalThis.fetch === patchedFetch) {\n globalThis.fetch = originalFetch;\n }\n\n enabled = false;\n restored = true;\n },\n isEnabled() {\n return enabled;\n },\n setScenario(name: string) {\n if (options.scenarios?.[name] === undefined) {\n throw new Error(`WaitKit scenario \"${name}\" does not exist.`);\n }\n\n if (activeScenario === name) {\n return;\n }\n\n const previousScenario = activeScenario;\n activeScenario = name;\n emitScenarioChange(options, previousScenario, activeScenario, 'setScenario');\n },\n getScenario() {\n return activeScenario;\n },\n resetScenario() {\n if (activeScenario === undefined) {\n return;\n }\n\n const previousScenario = activeScenario;\n activeScenario = undefined;\n emitScenarioChange(options, previousScenario, activeScenario, 'resetScenario');\n },\n };\n}\n\nfunction validateRuntime(): void {\n if (typeof globalThis.fetch !== 'function') {\n throw new Error('WaitKit requires globalThis.fetch.');\n }\n\n if (typeof Response !== 'function') {\n throw new Error('WaitKit requires globalThis.Response.');\n }\n}\n\nfunction validateOptions(options: WaitKitOptions): void {\n validateRules(options.rules ?? []);\n\n if (options.scenarios !== undefined) {\n for (const rules of Object.values(options.scenarios)) {\n validateRules(rules);\n }\n }\n\n if (\n options.activeScenario !== undefined &&\n options.scenarios?.[options.activeScenario] === undefined\n ) {\n throw new Error(`WaitKit scenario \"${options.activeScenario}\" does not exist.`);\n }\n}\n\nfunction validateRules(rules: readonly WaitKitRule[]): void {\n for (const rule of rules) {\n validateDelay(rule.delay);\n validateRate(rule.errorRate, 'errorRate');\n validateRate(rule.timeoutRate, 'timeoutRate');\n validateTimeoutMs(rule.timeoutMs);\n validateStatus(rule.errorResponse?.status);\n }\n}\n\nfunction validateStatus(status: number | undefined): void {\n if (status === undefined) {\n return;\n }\n\n if (!Number.isInteger(status) || status < 200 || status > 599) {\n throw new Error('WaitKit errorResponse.status must be an integer between 200 and 599.');\n }\n}\n\nfunction createRequestEvent(input: RequestInfo | URL, init?: RequestInit): WaitKitRequestEvent {\n return {\n input,\n init,\n url: getRequestUrl(input),\n method: getRequestMethod(input, init),\n };\n}\n\nfunction createMatchEvent(\n requestEvent: WaitKitRequestEvent,\n rule: WaitKitRule,\n scenario: string | undefined,\n delayMs: number,\n): WaitKitMatchEvent {\n return {\n ...requestEvent,\n rule,\n scenario,\n delayMs,\n };\n}\n\nfunction findMatchingRule(\n rules: readonly WaitKitRule[],\n url: string,\n method: string,\n): WaitKitRule | undefined {\n return rules.find((rule) => matchesRule(rule, url, method));\n}\n\nfunction shouldTrigger(rate: number | undefined): boolean {\n if (rate === undefined || rate <= 0) {\n return false;\n }\n\n if (rate >= 1) {\n return true;\n }\n\n return Math.random() < rate;\n}\n\nfunction emitError(options: WaitKitOptions, matchEvent: WaitKitMatchEvent, error: Error): void {\n const errorEvent: WaitKitErrorEvent = {\n ...matchEvent,\n error,\n };\n\n options.onError?.(errorEvent);\n}\n\nfunction emitScenarioChange(\n options: WaitKitOptions,\n previousScenario: string | undefined,\n scenario: string | undefined,\n reason: WaitKitScenarioChangeReason,\n): void {\n options.onScenarioChange?.({\n previousScenario,\n scenario,\n reason,\n });\n}\n\nfunction debug(options: WaitKitOptions, message: string): void {\n if (options.debug === true) {\n console.info(`[waitkit] ${message}`);\n }\n}\n"]}
|