@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 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
- const status = errorResponse?.status ?? 500;
110
- const headers = new Headers(errorResponse?.headers);
111
- const body = serializeBody(errorResponse?.body, headers);
112
- return new Response(body, {
113
- status,
114
- statusText: errorResponse?.statusText,
115
- headers
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}`);
@@ -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
- const status = errorResponse?.status ?? 500;
108
- const headers = new Headers(errorResponse?.headers);
109
- const body = serializeBody(errorResponse?.body, headers);
110
- return new Response(body, {
111
- status,
112
- statusText: errorResponse?.statusText,
113
- headers
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":";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,MAAM,MAAA,GAAS,eAAe,MAAA,IAAU,GAAA;AACxC,EAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAQ,aAAA,EAAe,OAAO,CAAA;AAClD,EAAA,MAAM,IAAA,GAAO,aAAA,CAAc,aAAA,EAAe,IAAA,EAAM,OAAO,CAAA;AAEvD,EAAA,OAAO,IAAI,SAAS,IAAA,EAAM;AAAA,IACxB,MAAA;AAAA,IACA,YAAY,aAAA,EAAe,UAAA;AAAA,IAC3B;AAAA,GACD,CAAA;AACH;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;;;AC/BA,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,cAAA,GAAiB,IAAA;AAAA,IACnB,CAAA;AAAA,IACA,WAAA,GAAc;AACZ,MAAA,OAAO,cAAA;AAAA,IACT,CAAA;AAAA,IACA,aAAA,GAAgB;AACd,MAAA,cAAA,GAAiB,MAAA;AAAA,IACnB;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,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 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.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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@waitkit/core",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Development-only fetch interceptor for testing loading, error, and timeout states.",
5
5
  "type": "module",
6
6
  "license": "MIT",