fetchvault 1.0.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/dist/core.js ADDED
@@ -0,0 +1,280 @@
1
+ import { getCircuitBreaker } from './circuit.js';
2
+ import { inFlight, withDeduplication } from './dedup.js';
3
+ import { createMiddlewareError, runAfterResponseHooks, runBeforeRequestHooks } from './middleware.js';
4
+ import { executeMockRequest } from './mock.js';
5
+ import { calculateRetryDelay, shouldRetry, waitForRetryDelay } from './retry.js';
6
+ import { createTimeoutSignal } from './timeout.js';
7
+ const DEFAULT_RETRIES = 3;
8
+ const JSON_CONTENT_TYPE = 'application/json';
9
+ const defaultContext = {
10
+ circuitMap: new Map(),
11
+ dedupMap: inFlight
12
+ };
13
+ /**
14
+ * Creates an isolated FetchVault engine.
15
+ *
16
+ * @param context Optional per-engine circuit and dedup stores.
17
+ * @returns Request function that follows the FetchVault result pattern.
18
+ * @example
19
+ * const engine = createFetchVaultEngine({ circuitMap: new Map(), dedupMap: new Map() })
20
+ */
21
+ export function createFetchVaultEngine(context = {}) {
22
+ const scoped = {
23
+ circuitMap: context.circuitMap ?? defaultContext.circuitMap,
24
+ dedupMap: context.dedupMap ?? defaultContext.dedupMap
25
+ };
26
+ return async function engine(url, options) {
27
+ try {
28
+ const normalized = normalizeOptions(url, options);
29
+ const execute = () => executePipeline(normalized, scoped);
30
+ if (normalized.deduplicate) {
31
+ return withDeduplication(normalized.request, execute, scoped.dedupMap);
32
+ }
33
+ return execute();
34
+ }
35
+ catch (cause) {
36
+ return createFailure('UNKNOWN', 'Unexpected FetchVault failure.', null, cause);
37
+ }
38
+ };
39
+ }
40
+ const defaultEngine = createFetchVaultEngine();
41
+ /**
42
+ * Executes a resilient fetch call using FetchVault defaults.
43
+ *
44
+ * @param url Target URL.
45
+ * @param options Optional request configuration.
46
+ * @returns Discriminated result union with data or structured error.
47
+ * @example
48
+ * const result = await fetchvault<{ id: string }>('/users/1')
49
+ */
50
+ export async function fetchvault(url, options) {
51
+ return defaultEngine(url, options);
52
+ }
53
+ async function executePipeline(normalized, context) {
54
+ const beforeResult = await runBeforePipeline(normalized.request, normalized.options.beforeRequest ?? []);
55
+ if ('error' in beforeResult) {
56
+ return beforeResult;
57
+ }
58
+ if (normalized.options.mock) {
59
+ return executeMockPipeline(beforeResult, normalized.options);
60
+ }
61
+ const breaker = resolveCircuitBreaker(beforeResult.url, context.circuitMap);
62
+ if (!breaker.canRequest()) {
63
+ return createFailure('CIRCUIT_OPEN', 'Circuit breaker is open. Request blocked.', null);
64
+ }
65
+ return executeNetworkPipeline(beforeResult, normalized.options, normalized.retries, breaker);
66
+ }
67
+ function normalizeOptions(url, options) {
68
+ const finalOptions = options ?? {};
69
+ const method = finalOptions.method ?? 'GET';
70
+ const headers = { ...(finalOptions.headers ?? {}) };
71
+ const body = serializeBody(finalOptions.body, headers);
72
+ return {
73
+ request: { url, method, headers, body },
74
+ options: finalOptions,
75
+ retries: finalOptions.retries ?? DEFAULT_RETRIES,
76
+ deduplicate: method === 'GET' && (finalOptions.deduplicate ?? true)
77
+ };
78
+ }
79
+ function serializeBody(body, headers) {
80
+ if (body === undefined || body === null) {
81
+ return body;
82
+ }
83
+ if (typeof body === 'string' || body instanceof FormData || body instanceof URLSearchParams) {
84
+ return body;
85
+ }
86
+ if (!hasContentTypeHeader(headers)) {
87
+ headers['Content-Type'] = JSON_CONTENT_TYPE;
88
+ }
89
+ return JSON.stringify(body);
90
+ }
91
+ function hasContentTypeHeader(headers) {
92
+ return Object.keys(headers).some((key) => key.toLowerCase() === 'content-type');
93
+ }
94
+ async function runBeforePipeline(request, hooks) {
95
+ try {
96
+ return await runBeforeRequestHooks(request, hooks);
97
+ }
98
+ catch (cause) {
99
+ return {
100
+ data: null,
101
+ error: createMiddlewareError(cause),
102
+ statusCode: null
103
+ };
104
+ }
105
+ }
106
+ async function executeMockPipeline(request, options) {
107
+ const mocked = await executeMockRequest(request, options.mock);
108
+ const validated = validateAndMap(mocked.statusCode, mocked.data, options.schema);
109
+ if (validated.error) {
110
+ return validated;
111
+ }
112
+ const afterHooked = await runAfterPipeline(mocked.statusCode, mocked.headers, validated.data, options.afterResponse ?? []);
113
+ return afterHooked;
114
+ }
115
+ function resolveCircuitBreaker(requestUrl, circuitMap) {
116
+ return getCircuitBreaker(circuitMap, extractBaseUrl(requestUrl));
117
+ }
118
+ function extractBaseUrl(requestUrl) {
119
+ try {
120
+ return new URL(requestUrl).origin;
121
+ }
122
+ catch {
123
+ return requestUrl;
124
+ }
125
+ }
126
+ async function executeNetworkPipeline(request, options, retries, breaker) {
127
+ let timeoutBundle;
128
+ try {
129
+ timeoutBundle = createTimeoutSignal(options.timeout, options.signal);
130
+ }
131
+ catch (cause) {
132
+ return createFailure('UNKNOWN', 'Invalid timeout configuration.', null, cause);
133
+ }
134
+ const requestWithSignal = { ...request, signal: timeoutBundle.signal };
135
+ try {
136
+ return await retryLoop(requestWithSignal, options, retries, breaker, timeoutBundle.didTimeout);
137
+ }
138
+ finally {
139
+ timeoutBundle.cleanup();
140
+ }
141
+ }
142
+ async function retryLoop(request, options, retries, breaker, didTimeout) {
143
+ for (let attempt = 1; attempt <= retries + 1; attempt += 1) {
144
+ const attemptResult = await performAttempt(request, options, attempt, retries, didTimeout);
145
+ if (isRetrySignal(attemptResult)) {
146
+ await waitForRetryDelay(calculateRetryDelay(attempt));
147
+ continue;
148
+ }
149
+ updateCircuitState(breaker, attemptResult);
150
+ return attemptResult;
151
+ }
152
+ return createFailure('UNKNOWN', 'Unexpected retry loop exit.', null);
153
+ }
154
+ async function performAttempt(request, options, attempt, retries, didTimeout) {
155
+ let response;
156
+ try {
157
+ response = await fetch(request.url, toFetchInit(request));
158
+ }
159
+ catch (cause) {
160
+ if (shouldRetry(null, attempt, retries)) {
161
+ return { kind: 'retry' };
162
+ }
163
+ return createNetworkFailure(cause, didTimeout());
164
+ }
165
+ return handleResponseOutcome(response, options, attempt, retries);
166
+ }
167
+ function isRetrySignal(value) {
168
+ return typeof value === 'object' && value !== null && 'kind' in value && value.kind === 'retry';
169
+ }
170
+ async function handleResponseOutcome(response, options, attempt, retries) {
171
+ if (response.status >= 500 && shouldRetry(response.status, attempt, retries)) {
172
+ return { kind: 'retry' };
173
+ }
174
+ if (response.status >= 400) {
175
+ const errorBody = await parseErrorBody(response);
176
+ return createFailure('HTTP_ERROR', `Request failed with status ${response.status}.`, response.status, errorBody);
177
+ }
178
+ const parsedBody = await parseSuccessBody(response);
179
+ if ('error' in parsedBody) {
180
+ return parsedBody.error;
181
+ }
182
+ const validated = validateAndMap(response.status, parsedBody.data, options.schema);
183
+ if (validated.error) {
184
+ return validated;
185
+ }
186
+ return runAfterPipeline(response.status, responseHeaders(response), validated.data, options.afterResponse ?? []);
187
+ }
188
+ async function parseSuccessBody(response) {
189
+ try {
190
+ return { data: await parseBody(response) };
191
+ }
192
+ catch (cause) {
193
+ return {
194
+ error: createFailure('PARSE_ERROR', 'Failed to parse successful response body.', response.status, cause)
195
+ };
196
+ }
197
+ }
198
+ async function parseErrorBody(response) {
199
+ try {
200
+ return await parseBody(response);
201
+ }
202
+ catch {
203
+ return null;
204
+ }
205
+ }
206
+ async function parseBody(response) {
207
+ const contentType = response.headers.get('content-type')?.toLowerCase() ?? '';
208
+ if (contentType.includes(JSON_CONTENT_TYPE)) {
209
+ return response.json();
210
+ }
211
+ return response.text();
212
+ }
213
+ function validateAndMap(statusCode, data, schema) {
214
+ if (!schema) {
215
+ return { data: data, error: null, statusCode };
216
+ }
217
+ try {
218
+ const parsed = schema.parse(data);
219
+ return { data: parsed, error: null, statusCode };
220
+ }
221
+ catch (cause) {
222
+ return createFailure('VALIDATION_ERROR', 'Schema validation failed.', statusCode, cause);
223
+ }
224
+ }
225
+ async function runAfterPipeline(statusCode, headers, data, hooks) {
226
+ const response = { statusCode, headers, raw: data, data };
227
+ try {
228
+ const transformed = await runAfterResponseHooks(response, hooks);
229
+ return { data: transformed.data, error: null, statusCode: transformed.statusCode };
230
+ }
231
+ catch (cause) {
232
+ return {
233
+ data: null,
234
+ error: createMiddlewareError(cause),
235
+ statusCode
236
+ };
237
+ }
238
+ }
239
+ function responseHeaders(response) {
240
+ const headers = {};
241
+ response.headers.forEach((value, key) => {
242
+ headers[key] = value;
243
+ });
244
+ return headers;
245
+ }
246
+ function toFetchInit(request) {
247
+ return {
248
+ method: request.method,
249
+ headers: request.headers,
250
+ body: request.body,
251
+ signal: request.signal
252
+ };
253
+ }
254
+ function createNetworkFailure(cause, timedOut) {
255
+ if (timedOut) {
256
+ return createFailure('TIMEOUT', 'Request timed out.', null, cause);
257
+ }
258
+ return createFailure('NETWORK_ERROR', 'Network request failed.', null, cause);
259
+ }
260
+ function updateCircuitState(breaker, result) {
261
+ if (result.error) {
262
+ const isServerOrNetwork = result.statusCode === null || result.statusCode >= 500;
263
+ if (isServerOrNetwork) {
264
+ breaker.recordFailure();
265
+ return;
266
+ }
267
+ breaker.recordSuccess();
268
+ return;
269
+ }
270
+ breaker.recordSuccess();
271
+ }
272
+ function createFailure(code, message, statusCode, cause) {
273
+ return {
274
+ data: null,
275
+ error: { code, message, cause },
276
+ statusCode
277
+ };
278
+ }
279
+ export default fetchvault;
280
+ //# sourceMappingURL=core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { VaultRequest, VaultResult } from './types.js';
2
+ /**
3
+ * Default in-flight request map used by the top-level `fetchvault` function.
4
+ *
5
+ * @example
6
+ * const pending = inFlight.size
7
+ */
8
+ export declare const inFlight: Map<string, Promise<VaultResult<unknown>>>;
9
+ /**
10
+ * Creates a deterministic request key for deduplication.
11
+ *
12
+ * @param request Normalized request payload.
13
+ * @returns Stable string key representing URL, method, headers, and body.
14
+ * @example
15
+ * const key = createDedupKey({ url: '/users', method: 'GET', headers: {} })
16
+ */
17
+ export declare function createDedupKey(request: VaultRequest): string;
18
+ /**
19
+ * Wraps request execution with GET-only deduplication semantics.
20
+ *
21
+ * @param request Normalized request payload.
22
+ * @param execute Function that executes the actual request.
23
+ * @param store Optional custom in-flight map for scoped deduplication.
24
+ * @returns Existing in-flight promise or a newly created one.
25
+ * @example
26
+ * const result = await withDeduplication(req, () => fetchData())
27
+ */
28
+ export declare function withDeduplication<T>(request: VaultRequest, execute: () => Promise<VaultResult<T>>, store?: Map<string, Promise<VaultResult<unknown>>>): Promise<VaultResult<T>>;
29
+ //# sourceMappingURL=dedup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dedup.d.ts","sourceRoot":"","sources":["../src/dedup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE3D;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,4CAAmD,CAAA;AAExE;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAI5D;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EACjC,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EACtC,KAAK,GAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAY,GAC3D,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAgBzB"}
package/dist/dedup.js ADDED
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Default in-flight request map used by the top-level `fetchvault` function.
3
+ *
4
+ * @example
5
+ * const pending = inFlight.size
6
+ */
7
+ export const inFlight = new Map();
8
+ /**
9
+ * Creates a deterministic request key for deduplication.
10
+ *
11
+ * @param request Normalized request payload.
12
+ * @returns Stable string key representing URL, method, headers, and body.
13
+ * @example
14
+ * const key = createDedupKey({ url: '/users', method: 'GET', headers: {} })
15
+ */
16
+ export function createDedupKey(request) {
17
+ const headers = serializeHeaders(request.headers);
18
+ const body = stableSerialize(request.body);
19
+ return `${request.method}|${request.url}|${headers}|${body}`;
20
+ }
21
+ /**
22
+ * Wraps request execution with GET-only deduplication semantics.
23
+ *
24
+ * @param request Normalized request payload.
25
+ * @param execute Function that executes the actual request.
26
+ * @param store Optional custom in-flight map for scoped deduplication.
27
+ * @returns Existing in-flight promise or a newly created one.
28
+ * @example
29
+ * const result = await withDeduplication(req, () => fetchData())
30
+ */
31
+ export function withDeduplication(request, execute, store = inFlight) {
32
+ if (request.method !== 'GET') {
33
+ return execute();
34
+ }
35
+ const key = createDedupKey(request);
36
+ const existing = store.get(key);
37
+ if (existing) {
38
+ return existing;
39
+ }
40
+ const pending = execute().finally(() => {
41
+ store.delete(key);
42
+ });
43
+ store.set(key, pending);
44
+ return pending;
45
+ }
46
+ function serializeHeaders(headers) {
47
+ const entries = Object.entries(headers)
48
+ .map(([key, value]) => [key.toLowerCase(), value])
49
+ .sort(([left], [right]) => left.localeCompare(right));
50
+ return entries.map(([key, value]) => `${key}:${value}`).join('&');
51
+ }
52
+ function stableSerialize(value) {
53
+ if (value === undefined) {
54
+ return 'undefined';
55
+ }
56
+ if (value === null || typeof value !== 'object') {
57
+ return JSON.stringify(value);
58
+ }
59
+ if (Array.isArray(value)) {
60
+ const serializedItems = value.map((item) => stableSerialize(item)).join(',');
61
+ return `[${serializedItems}]`;
62
+ }
63
+ const record = value;
64
+ const keys = Object.keys(record).sort((left, right) => left.localeCompare(right));
65
+ const serialized = keys
66
+ .map((key) => `${JSON.stringify(key)}:${stableSerialize(record[key])}`)
67
+ .join(',');
68
+ return `{${serialized}}`;
69
+ }
70
+ //# sourceMappingURL=dedup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dedup.js","sourceRoot":"","sources":["../src/dedup.ts"],"names":[],"mappings":"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"}
package/dist/index.cjs ADDED
@@ -0,0 +1,29 @@
1
+ 'use strict';
2
+
3
+ const load = () => import('./index.js');
4
+
5
+ const fetchvault = async (...args) => {
6
+ const mod = await load();
7
+ return mod.fetchvault(...args);
8
+ };
9
+
10
+ const createClient = (...args) => {
11
+ const lazyMethod = async (method, ...methodArgs) => {
12
+ const mod = await load();
13
+ const client = mod.createClient(...args);
14
+ return client[method](...methodArgs);
15
+ };
16
+
17
+ return {
18
+ get: (...methodArgs) => lazyMethod('get', ...methodArgs),
19
+ post: (...methodArgs) => lazyMethod('post', ...methodArgs),
20
+ put: (...methodArgs) => lazyMethod('put', ...methodArgs),
21
+ patch: (...methodArgs) => lazyMethod('patch', ...methodArgs),
22
+ delete: (...methodArgs) => lazyMethod('delete', ...methodArgs)
23
+ };
24
+ };
25
+
26
+ module.exports = fetchvault;
27
+ module.exports.default = fetchvault;
28
+ module.exports.fetchvault = fetchvault;
29
+ module.exports.createClient = createClient;
@@ -0,0 +1,4 @@
1
+ export { default, fetchvault } from './core.js';
2
+ export { createClient } from './client.js';
3
+ export type { InferSchema, VaultClient, VaultClientConfig, VaultError, VaultFailure, VaultMockConfig, VaultOptions, VaultRequestHook, VaultResponseHook, VaultResult, VaultSchema, VaultSuccess } from './types.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,YAAY,EACV,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,EACX,WAAW,EACX,YAAY,EACb,MAAM,YAAY,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { default, fetchvault } from './core.js';
2
+ export { createClient } from './client.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,31 @@
1
+ import type { VaultError, VaultRequest, VaultRequestHook, VaultResponse, VaultResponseHook } from './types.js';
2
+ /**
3
+ * Runs request hooks sequentially and returns the final request.
4
+ *
5
+ * @param request Initial request payload.
6
+ * @param hooks Ordered request hook list.
7
+ * @returns Request after all hook transformations.
8
+ * @example
9
+ * const nextReq = await runBeforeRequestHooks(req, [addAuthHeader])
10
+ */
11
+ export declare function runBeforeRequestHooks(request: VaultRequest, hooks?: Array<VaultRequestHook>): Promise<VaultRequest>;
12
+ /**
13
+ * Runs response hooks sequentially and returns the final response.
14
+ *
15
+ * @param response Initial response payload.
16
+ * @param hooks Ordered response hook list.
17
+ * @returns Response after all hook transformations.
18
+ * @example
19
+ * const nextRes = await runAfterResponseHooks(res, [logResponse])
20
+ */
21
+ export declare function runAfterResponseHooks(response: VaultResponse, hooks?: Array<VaultResponseHook>): Promise<VaultResponse>;
22
+ /**
23
+ * Converts thrown middleware exceptions into FetchVault error objects.
24
+ *
25
+ * @param cause Original thrown middleware value.
26
+ * @returns Normalized middleware error.
27
+ * @example
28
+ * const error = createMiddlewareError(new Error('hook failed'))
29
+ */
30
+ export declare function createMiddlewareError(cause: unknown): VaultError;
31
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EAClB,MAAM,YAAY,CAAA;AAEnB;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,YAAY,EACrB,KAAK,GAAE,KAAK,CAAC,gBAAgB,CAAM,GAClC,OAAO,CAAC,YAAY,CAAC,CAOvB;AAED;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,aAAa,EACvB,KAAK,GAAE,KAAK,CAAC,iBAAiB,CAAM,GACnC,OAAO,CAAC,aAAa,CAAC,CAOxB;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CAMhE"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Runs request hooks sequentially and returns the final request.
3
+ *
4
+ * @param request Initial request payload.
5
+ * @param hooks Ordered request hook list.
6
+ * @returns Request after all hook transformations.
7
+ * @example
8
+ * const nextReq = await runBeforeRequestHooks(req, [addAuthHeader])
9
+ */
10
+ export async function runBeforeRequestHooks(request, hooks = []) {
11
+ let current = request;
12
+ for (const hook of hooks) {
13
+ current = await hook(current);
14
+ }
15
+ return current;
16
+ }
17
+ /**
18
+ * Runs response hooks sequentially and returns the final response.
19
+ *
20
+ * @param response Initial response payload.
21
+ * @param hooks Ordered response hook list.
22
+ * @returns Response after all hook transformations.
23
+ * @example
24
+ * const nextRes = await runAfterResponseHooks(res, [logResponse])
25
+ */
26
+ export async function runAfterResponseHooks(response, hooks = []) {
27
+ let current = response;
28
+ for (const hook of hooks) {
29
+ current = await hook(current);
30
+ }
31
+ return current;
32
+ }
33
+ /**
34
+ * Converts thrown middleware exceptions into FetchVault error objects.
35
+ *
36
+ * @param cause Original thrown middleware value.
37
+ * @returns Normalized middleware error.
38
+ * @example
39
+ * const error = createMiddlewareError(new Error('hook failed'))
40
+ */
41
+ export function createMiddlewareError(cause) {
42
+ return {
43
+ code: 'MIDDLEWARE_ERROR',
44
+ message: 'A middleware hook threw an error.',
45
+ cause
46
+ };
47
+ }
48
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAQA;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,OAAqB,EACrB,QAAiC,EAAE;IAEnC,IAAI,OAAO,GAAG,OAAO,CAAA;IACrB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAAA;IAC/B,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,QAAuB,EACvB,QAAkC,EAAE;IAEpC,IAAI,OAAO,GAAG,QAAQ,CAAA;IACtB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAAA;IAC/B,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAc;IAClD,OAAO;QACL,IAAI,EAAE,kBAAkB;QACxB,OAAO,EAAE,mCAAmC;QAC5C,KAAK;KACN,CAAA;AACH,CAAC"}
package/dist/mock.d.ts ADDED
@@ -0,0 +1,30 @@
1
+ import type { VaultMockConfig, VaultRequest, VaultResponse } from './types.js';
2
+ /**
3
+ * Resolves optional mock delay into milliseconds.
4
+ *
5
+ * @param delay Delay value from mock config.
6
+ * @returns Delay in milliseconds.
7
+ * @example
8
+ * const delayMs = resolveMockDelay('150ms')
9
+ */
10
+ export declare function resolveMockDelay(delay: string | number | undefined): number;
11
+ /**
12
+ * Creates a normalized `VaultResponse` from mock data.
13
+ *
14
+ * @param config Mock configuration.
15
+ * @returns Normalized mock response payload.
16
+ * @example
17
+ * const response = buildMockResponse({ data: { ok: true } })
18
+ */
19
+ export declare function buildMockResponse(config: VaultMockConfig): VaultResponse;
20
+ /**
21
+ * Executes a mock request with optional artificial latency.
22
+ *
23
+ * @param request Request context for observability and future extensions.
24
+ * @param config Mock configuration.
25
+ * @returns Mock response after optional delay.
26
+ * @example
27
+ * const response = await executeMockRequest(req, { data: { ok: true }, delay: '200ms' })
28
+ */
29
+ export declare function executeMockRequest(request: VaultRequest, config: VaultMockConfig): Promise<VaultResponse>;
30
+ //# sourceMappingURL=mock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../src/mock.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAI9E;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAM3E;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,eAAe,GAAG,aAAa,CAQxE;AAED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,aAAa,CAAC,CAQxB"}
package/dist/mock.js ADDED
@@ -0,0 +1,56 @@
1
+ import { parseTimeout } from './timeout.js';
2
+ const DEFAULT_MOCK_STATUS = 200;
3
+ /**
4
+ * Resolves optional mock delay into milliseconds.
5
+ *
6
+ * @param delay Delay value from mock config.
7
+ * @returns Delay in milliseconds.
8
+ * @example
9
+ * const delayMs = resolveMockDelay('150ms')
10
+ */
11
+ export function resolveMockDelay(delay) {
12
+ if (delay === undefined) {
13
+ return 0;
14
+ }
15
+ return parseTimeout(delay);
16
+ }
17
+ /**
18
+ * Creates a normalized `VaultResponse` from mock data.
19
+ *
20
+ * @param config Mock configuration.
21
+ * @returns Normalized mock response payload.
22
+ * @example
23
+ * const response = buildMockResponse({ data: { ok: true } })
24
+ */
25
+ export function buildMockResponse(config) {
26
+ const statusCode = config.status ?? DEFAULT_MOCK_STATUS;
27
+ return {
28
+ statusCode,
29
+ headers: {},
30
+ raw: config.data,
31
+ data: config.data
32
+ };
33
+ }
34
+ /**
35
+ * Executes a mock request with optional artificial latency.
36
+ *
37
+ * @param request Request context for observability and future extensions.
38
+ * @param config Mock configuration.
39
+ * @returns Mock response after optional delay.
40
+ * @example
41
+ * const response = await executeMockRequest(req, { data: { ok: true }, delay: '200ms' })
42
+ */
43
+ export async function executeMockRequest(request, config) {
44
+ const _requestContext = request;
45
+ const delayMs = resolveMockDelay(config.delay);
46
+ if (delayMs > 0) {
47
+ await wait(delayMs);
48
+ }
49
+ return buildMockResponse(config);
50
+ }
51
+ function wait(delayMs) {
52
+ return new Promise((resolve) => {
53
+ setTimeout(resolve, delayMs);
54
+ });
55
+ }
56
+ //# sourceMappingURL=mock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock.js","sourceRoot":"","sources":["../src/mock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAG3C,MAAM,mBAAmB,GAAG,GAAG,CAAA;AAE/B;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAkC;IACjE,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,CAAC,CAAA;IACV,CAAC;IAED,OAAO,YAAY,CAAC,KAAK,CAAC,CAAA;AAC5B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAuB;IACvD,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,IAAI,mBAAmB,CAAA;IACvD,OAAO;QACL,UAAU;QACV,OAAO,EAAE,EAAE;QACX,GAAG,EAAE,MAAM,CAAC,IAAI;QAChB,IAAI,EAAE,MAAM,CAAC,IAAI;KAClB,CAAA;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAqB,EACrB,MAAuB;IAEvB,MAAM,eAAe,GAAG,OAAO,CAAA;IAC/B,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAC9C,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,MAAM,IAAI,CAAC,OAAO,CAAC,CAAA;IACrB,CAAC;IAED,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAA;AAClC,CAAC;AAED,SAAS,IAAI,CAAC,OAAe;IAC3B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IAC9B,CAAC,CAAC,CAAA;AACJ,CAAC"}