vite-plugin-automock 1.1.6 → 1.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
@@ -34,7 +34,7 @@ import { automock } from 'vite-plugin-automock'
34
34
  export default defineConfig({
35
35
  plugins: [
36
36
  automock({
37
- proxyBaseUrl: 'https://api.example.com', // Required: your API server URL
37
+ proxyBaseUrl: 'https://api.example.com', // Required for proxy/capture
38
38
  })
39
39
  ]
40
40
  })
@@ -52,14 +52,14 @@ That's it! The plugin will:
52
52
 
53
53
  | Option | Type | Required | Default | Description |
54
54
  | ------ | ---- | -------- | ------- | ----------- |
55
- | `proxyBaseUrl` | `string` | Yes | - | Base URL of your API server |
55
+ | `proxyBaseUrl` | `string` | No | - | Base URL of your API server. Required only when `proxy` or `capture` is used |
56
56
  | `mockDir` | `string` | No | `'mock'` | Directory to store mock files |
57
57
  | `apiPrefix` | `string` | No | `'/api'` | API path prefix to intercept |
58
58
  | `pathRewrite` | `(path: string) => string` | No | `(path) => path` | Function to rewrite request paths |
59
59
  | `enabled` | `boolean` | No | `true` | Global switch. When `false`, all requests pass through without mock handling |
60
60
  | `proxy` | `boolean` | No | `true` | Whether to proxy unmatched requests to `proxyBaseUrl` |
61
61
  | `capture` | `boolean` | No | `true` | Whether to auto-capture proxy responses and save as mock files |
62
- | `productionMock` | `boolean \| 'auto'` | No | `false` | Enable mock in production mode |
62
+ | `productionMock` | `boolean \| 'auto'` | No | `false` | Enable client-side mock bundle support |
63
63
  | `inspector` | `boolean \| InspectorOptions` | No | `false` | Enable visual mock inspector UI |
64
64
 
65
65
  ### Bundle Options
@@ -71,6 +71,8 @@ These options are available when using the `automock()` function (which includes
71
71
  | `bundleMockData` | `boolean` | `true` | Whether to bundle mock data for production |
72
72
  | `bundleOutputPath` | `string` | `'public/mock-data.json'` | Output path for the mock bundle file |
73
73
 
74
+ For a complete explanation of option interactions, see [Configuration Guide](docs/CONFIGURATION_CN.md).
75
+
74
76
  ### Inspector Options
75
77
 
76
78
  When `inspector` is an object:
@@ -114,22 +116,9 @@ export default defineConfig({
114
116
  })
115
117
  ```
116
118
 
117
- ## Fine-grained Control
118
-
119
- The `enabled`, `proxy`, and `capture` options provide independent control over the plugin's behavior:
120
-
121
- ### Record-only Mode
119
+ ## Behavior Modes
122
120
 
123
- Proxy to the backend and capture responses, but don't intercept requests with existing mocks:
124
-
125
- ```typescript
126
- automock({
127
- proxyBaseUrl: 'https://api.example.com',
128
- enabled: false, // Don't intercept
129
- proxy: true, // Proxy to backend
130
- capture: true, // Save responses as mock files
131
- })
132
- ```
121
+ The `enabled`, `proxy`, and `capture` options control different parts of the development middleware. `enabled=false` is a global bypass: the plugin will not read mocks, proxy, or capture.
133
122
 
134
123
  ### Mock-only Mode
135
124
 
@@ -144,16 +133,13 @@ automock({
144
133
  })
145
134
  ```
146
135
 
147
- ### Pure Proxy Mode
136
+ ### Pass-through Mode
148
137
 
149
- Bypass all mock handling, just proxy to backend:
138
+ Bypass all automock handling and let later Vite middleware, including `server.proxy`, handle the request:
150
139
 
151
140
  ```typescript
152
141
  automock({
153
- proxyBaseUrl: 'https://api.example.com',
154
- enabled: false, // Don't intercept
155
- proxy: true, // Proxy to backend
156
- capture: false, // Don't save mocks
142
+ enabled: false,
157
143
  })
158
144
  ```
159
145
 
@@ -265,7 +251,7 @@ automock({
265
251
 
266
252
  3. Initialize the client interceptor in your app (see [Client API Reference](#client-api-reference)).
267
253
 
268
- 4. The `productionMock: 'auto'` option automatically enables mock based on the environment.
254
+ 4. The `productionMock: 'auto'` option enables mock outside `production` mode and disables it in `production` mode.
269
255
 
270
256
  ## Mock Inspector
271
257
 
@@ -4,6 +4,24 @@ var MockInterceptor = class {
4
4
  constructor(options) {
5
5
  this.options = options;
6
6
  }
7
+ normalizeUrlPath(url, baseURL) {
8
+ if (!url) return "";
9
+ try {
10
+ const isAbsoluteUrl = /^[a-z][a-z\d+\-.]*:\/\//i.test(url);
11
+ const browserOrigin = typeof window !== "undefined" && window.location?.origin ? window.location.origin : "http://localhost";
12
+ if (isAbsoluteUrl) {
13
+ return new URL(url).pathname;
14
+ }
15
+ if (baseURL) {
16
+ const normalizedBase = baseURL.endsWith("/") ? baseURL : `${baseURL}/`;
17
+ const normalizedUrl = url.replace(/^\/+/, "");
18
+ return new URL(normalizedUrl, normalizedBase).pathname;
19
+ }
20
+ return new URL(url, browserOrigin).pathname;
21
+ } catch {
22
+ return url.split(/[?#]/)[0] || "";
23
+ }
24
+ }
7
25
  /**
8
26
  * Check if mock is enabled
9
27
  */
@@ -22,14 +40,19 @@ var MockInterceptor = class {
22
40
  * - "GET /api/v1/asset/xxx" (HTTP method + URL)
23
41
  * - "/api/v1/asset/xxx/get.js" (File path format from automock plugin)
24
42
  */
25
- findMock(url, method) {
43
+ findMock(url, method, baseURL) {
26
44
  const methodUpper = method.toUpperCase();
27
45
  const methodLower = method.toLowerCase();
46
+ const normalizedPath = this.normalizeUrlPath(url, baseURL);
28
47
  const httpMethodKey = `${methodUpper} ${url}`;
29
48
  if (this.options.mockData[httpMethodKey]) {
30
49
  return this.options.mockData[httpMethodKey];
31
50
  }
32
- const filePathKey = `${url}/${methodLower}.js`;
51
+ const normalizedHttpMethodKey = `${methodUpper} ${normalizedPath}`;
52
+ if (this.options.mockData[normalizedHttpMethodKey]) {
53
+ return this.options.mockData[normalizedHttpMethodKey];
54
+ }
55
+ const filePathKey = `${normalizedPath}/${methodLower}.js`;
33
56
  if (this.options.mockData[filePathKey]) {
34
57
  return this.options.mockData[filePathKey];
35
58
  }
@@ -38,21 +61,21 @@ var MockInterceptor = class {
38
61
  /**
39
62
  * Determine if request should be mocked
40
63
  */
41
- shouldMock(url, method) {
64
+ shouldMock(url, method, baseURL) {
42
65
  if (!this.isEnabled()) {
43
66
  return false;
44
67
  }
45
- const mock = this.findMock(url, method);
68
+ const mock = this.findMock(url, method, baseURL);
46
69
  return mock !== null && mock.enable;
47
70
  }
48
71
  /**
49
72
  * Get mock data for request
50
73
  */
51
- getMock(url, method) {
52
- if (!this.shouldMock(url, method)) {
74
+ getMock(url, method, baseURL) {
75
+ if (!this.shouldMock(url, method, baseURL)) {
53
76
  return null;
54
77
  }
55
- return this.findMock(url, method);
78
+ return this.findMock(url, method, baseURL);
56
79
  }
57
80
  /**
58
81
  * Setup axios interceptor
@@ -62,9 +85,10 @@ var MockInterceptor = class {
62
85
  async (config) => {
63
86
  const url = config.url || "";
64
87
  const method = config.method?.toUpperCase() || "GET";
65
- const mock = this.getMock(url, method);
88
+ const normalizedUrl = this.normalizeUrlPath(url, config.baseURL);
89
+ const mock = this.getMock(url, method, config.baseURL);
66
90
  if (mock) {
67
- this.options.onMockHit?.(url, method, mock);
91
+ this.options.onMockHit?.(normalizedUrl, method, mock);
68
92
  config.adapter = async () => {
69
93
  const { data, delay = 0, status = 200 } = mock;
70
94
  if (delay > 0) {
@@ -80,7 +104,7 @@ var MockInterceptor = class {
80
104
  };
81
105
  } else {
82
106
  const reason = !this.isEnabled() ? "Mock disabled globally" : "No matching mock found or mock disabled";
83
- this.options.onBypass?.(url, method, reason);
107
+ this.options.onBypass?.(normalizedUrl, method, reason);
84
108
  }
85
109
  return config;
86
110
  },
@@ -160,4 +184,4 @@ export {
160
184
  registerHttpInstance,
161
185
  initMockInterceptorForPureHttp
162
186
  };
163
- //# sourceMappingURL=chunk-DJWYFFPU.mjs.map
187
+ //# sourceMappingURL=chunk-2KRAWI7J.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client/interceptor.ts"],"sourcesContent":["import type {\n AxiosInstance,\n AxiosResponse,\n InternalAxiosRequestConfig,\n} from \"axios\";\n\ndeclare const __AUTOMOCK_ENABLED__: boolean;\n\nexport type MockBundleData = {\n enable: boolean;\n data: unknown;\n delay?: number;\n status?: number;\n isBinary?: boolean;\n};\n\nexport type MockInterceptorOptions = {\n mockData: Record<string, MockBundleData>;\n enabled?: boolean | (() => boolean);\n onMockHit?: (url: string, method: string, mock: MockBundleData) => void;\n onBypass?: (url: string, method: string, reason: string) => void;\n};\n\ntype MockEnabledState = boolean | undefined;\n\ndeclare global {\n interface Window {\n __MOCK_ENABLED__?: MockEnabledState;\n }\n}\n\nclass MockInterceptor {\n private options: MockInterceptorOptions;\n\n constructor(options: MockInterceptorOptions) {\n this.options = options;\n }\n\n private normalizeUrlPath(url: string, baseURL?: string): string {\n if (!url) return \"\";\n\n try {\n const isAbsoluteUrl = /^[a-z][a-z\\d+\\-.]*:\\/\\//i.test(url);\n const browserOrigin =\n typeof window !== \"undefined\" && window.location?.origin\n ? window.location.origin\n : \"http://localhost\";\n\n if (isAbsoluteUrl) {\n return new URL(url).pathname;\n }\n\n if (baseURL) {\n const normalizedBase = baseURL.endsWith(\"/\") ? baseURL : `${baseURL}/`;\n const normalizedUrl = url.replace(/^\\/+/, \"\");\n return new URL(normalizedUrl, normalizedBase).pathname;\n }\n\n return new URL(url, browserOrigin).pathname;\n } catch {\n return url.split(/[?#]/)[0] || \"\";\n }\n }\n\n /**\n * Check if mock is enabled\n */\n isEnabled(): boolean {\n // Check runtime flag first\n if (window.__MOCK_ENABLED__ !== undefined) {\n return window.__MOCK_ENABLED__;\n }\n // Check environment variable\n if (typeof this.options.enabled === \"function\") {\n return this.options.enabled();\n }\n return this.options.enabled ?? false;\n }\n\n /**\n * Find matching mock data for the request\n * Supports both formats:\n * - \"GET /api/v1/asset/xxx\" (HTTP method + URL)\n * - \"/api/v1/asset/xxx/get.js\" (File path format from automock plugin)\n */\n private findMock(url: string, method: string, baseURL?: string): MockBundleData | null {\n const methodUpper = method.toUpperCase();\n const methodLower = method.toLowerCase();\n const normalizedPath = this.normalizeUrlPath(url, baseURL);\n\n // Try HTTP method + URL format first (for compatibility)\n const httpMethodKey = `${methodUpper} ${url}`;\n if (this.options.mockData[httpMethodKey]) {\n return this.options.mockData[httpMethodKey];\n }\n\n const normalizedHttpMethodKey = `${methodUpper} ${normalizedPath}`;\n if (this.options.mockData[normalizedHttpMethodKey]) {\n return this.options.mockData[normalizedHttpMethodKey];\n }\n\n // Try file path format from automock plugin: /api/v1/asset/xxx/get.js\n const filePathKey = `${normalizedPath}/${methodLower}.js`;\n if (this.options.mockData[filePathKey]) {\n return this.options.mockData[filePathKey];\n }\n\n return null;\n }\n\n /**\n * Determine if request should be mocked\n */\n shouldMock(url: string, method: string, baseURL?: string): boolean {\n if (!this.isEnabled()) {\n return false;\n }\n\n const mock = this.findMock(url, method, baseURL);\n return mock !== null && mock.enable;\n }\n\n /**\n * Get mock data for request\n */\n getMock(url: string, method: string, baseURL?: string): MockBundleData | null {\n if (!this.shouldMock(url, method, baseURL)) {\n return null;\n }\n return this.findMock(url, method, baseURL);\n }\n\n /**\n * Setup axios interceptor\n */\n setupAxios(axiosInstance: AxiosInstance): void {\n axiosInstance.interceptors.request.use(\n async (config: InternalAxiosRequestConfig) => {\n const url = config.url || \"\";\n const method = config.method?.toUpperCase() || \"GET\";\n const normalizedUrl = this.normalizeUrlPath(url, config.baseURL);\n\n const mock = this.getMock(url, method, config.baseURL);\n\n if (mock) {\n // Trigger mock hit callback\n this.options.onMockHit?.(normalizedUrl, method, mock);\n\n // Set adapter to return mock data\n (config as InternalAxiosRequestConfig & { adapter: () => Promise<AxiosResponse> }).adapter = async () => {\n const { data, delay = 0, status = 200 } = mock;\n\n // Simulate delay\n if (delay > 0) {\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n\n return {\n data,\n status,\n statusText: \"OK\",\n headers: {},\n config,\n };\n };\n } else {\n // Trigger bypass callback\n const reason = !this.isEnabled()\n ? \"Mock disabled globally\"\n : \"No matching mock found or mock disabled\";\n this.options.onBypass?.(normalizedUrl, method, reason);\n }\n\n return config;\n },\n (error: unknown) => Promise.reject(error),\n );\n }\n}\n\n/**\n * Create mock interceptor instance\n */\nexport function createMockInterceptor(\n options: MockInterceptorOptions,\n): MockInterceptor {\n return new MockInterceptor(options);\n}\n\n/**\n * Load mock data from bundled JSON file\n */\nexport async function loadMockData(): Promise<Record<string, MockBundleData>> {\n try {\n // In production, mock-data.json is generated by automock plugin\n // Use absolute path to load it from dist directory\n const response = await fetch(\"/mock-data.json\");\n if (!response.ok) {\n console.warn(\n \"[MockInterceptor] Failed to load mock-data.json:\",\n response.statusText,\n );\n return {};\n }\n const data = (await response.json()) as Record<string, MockBundleData>;\n return data;\n } catch (error) {\n console.warn(\"[MockInterceptor] Failed to load mock-data.json:\", error);\n return {};\n }\n}\n\nasync function createInterceptorFromBundle(): Promise<MockInterceptor> {\n const mockData = await loadMockData();\n const isEnabled = typeof __AUTOMOCK_ENABLED__ !== \"undefined\" && __AUTOMOCK_ENABLED__;\n\n return new MockInterceptor({\n mockData,\n enabled: isEnabled,\n onMockHit: (url: string, method: string) => {\n console.log(`[MOCK HIT] ${method} ${url}`);\n },\n onBypass: (url: string, method: string, reason: string) => {\n console.log(`[MOCK BYPASS] ${method} ${url} - ${reason}`);\n },\n });\n}\n\nexport async function initMockInterceptor(\n axiosInstance?: AxiosInstance,\n): Promise<void> {\n if (!axiosInstance) {\n throw new Error(\n \"[MockInterceptor] axiosInstance is required. Please provide an axios instance.\",\n );\n }\n\n const interceptor = await createInterceptorFromBundle();\n interceptor.setupAxios(axiosInstance);\n}\n\nexport function setMockEnabled(enabled: boolean): void {\n window.__MOCK_ENABLED__ = enabled;\n}\n\nexport function isMockEnabled(): boolean {\n return !!window.__MOCK_ENABLED__;\n}\n\ntype HttpInstance = {\n constructor: { axiosInstance: AxiosInstance };\n};\n\nlet httpInstanceRef: HttpInstance | undefined;\n\nexport function registerHttpInstance(http: HttpInstance): void {\n httpInstanceRef = http;\n}\n\nexport async function initMockInterceptorForPureHttp(): Promise<void> {\n if (!httpInstanceRef) {\n throw new Error(\n \"[MockInterceptor] http instance not registered. Call registerHttpInstance(http) first.\",\n );\n }\n\n const interceptor = await createInterceptorFromBundle();\n interceptor.setupAxios(httpInstanceRef.constructor.axiosInstance);\n}\n"],"mappings":"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","names":[]}
@@ -22,6 +22,7 @@ declare global {
22
22
  declare class MockInterceptor {
23
23
  private options;
24
24
  constructor(options: MockInterceptorOptions);
25
+ private normalizeUrlPath;
25
26
  /**
26
27
  * Check if mock is enabled
27
28
  */
@@ -36,11 +37,11 @@ declare class MockInterceptor {
36
37
  /**
37
38
  * Determine if request should be mocked
38
39
  */
39
- shouldMock(url: string, method: string): boolean;
40
+ shouldMock(url: string, method: string, baseURL?: string): boolean;
40
41
  /**
41
42
  * Get mock data for request
42
43
  */
43
- getMock(url: string, method: string): MockBundleData | null;
44
+ getMock(url: string, method: string, baseURL?: string): MockBundleData | null;
44
45
  /**
45
46
  * Setup axios interceptor
46
47
  */
@@ -22,6 +22,7 @@ declare global {
22
22
  declare class MockInterceptor {
23
23
  private options;
24
24
  constructor(options: MockInterceptorOptions);
25
+ private normalizeUrlPath;
25
26
  /**
26
27
  * Check if mock is enabled
27
28
  */
@@ -36,11 +37,11 @@ declare class MockInterceptor {
36
37
  /**
37
38
  * Determine if request should be mocked
38
39
  */
39
- shouldMock(url: string, method: string): boolean;
40
+ shouldMock(url: string, method: string, baseURL?: string): boolean;
40
41
  /**
41
42
  * Get mock data for request
42
43
  */
43
- getMock(url: string, method: string): MockBundleData | null;
44
+ getMock(url: string, method: string, baseURL?: string): MockBundleData | null;
44
45
  /**
45
46
  * Setup axios interceptor
46
47
  */
@@ -36,6 +36,24 @@ var MockInterceptor = class {
36
36
  constructor(options) {
37
37
  this.options = options;
38
38
  }
39
+ normalizeUrlPath(url, baseURL) {
40
+ if (!url) return "";
41
+ try {
42
+ const isAbsoluteUrl = /^[a-z][a-z\d+\-.]*:\/\//i.test(url);
43
+ const browserOrigin = typeof window !== "undefined" && window.location?.origin ? window.location.origin : "http://localhost";
44
+ if (isAbsoluteUrl) {
45
+ return new URL(url).pathname;
46
+ }
47
+ if (baseURL) {
48
+ const normalizedBase = baseURL.endsWith("/") ? baseURL : `${baseURL}/`;
49
+ const normalizedUrl = url.replace(/^\/+/, "");
50
+ return new URL(normalizedUrl, normalizedBase).pathname;
51
+ }
52
+ return new URL(url, browserOrigin).pathname;
53
+ } catch {
54
+ return url.split(/[?#]/)[0] || "";
55
+ }
56
+ }
39
57
  /**
40
58
  * Check if mock is enabled
41
59
  */
@@ -54,14 +72,19 @@ var MockInterceptor = class {
54
72
  * - "GET /api/v1/asset/xxx" (HTTP method + URL)
55
73
  * - "/api/v1/asset/xxx/get.js" (File path format from automock plugin)
56
74
  */
57
- findMock(url, method) {
75
+ findMock(url, method, baseURL) {
58
76
  const methodUpper = method.toUpperCase();
59
77
  const methodLower = method.toLowerCase();
78
+ const normalizedPath = this.normalizeUrlPath(url, baseURL);
60
79
  const httpMethodKey = `${methodUpper} ${url}`;
61
80
  if (this.options.mockData[httpMethodKey]) {
62
81
  return this.options.mockData[httpMethodKey];
63
82
  }
64
- const filePathKey = `${url}/${methodLower}.js`;
83
+ const normalizedHttpMethodKey = `${methodUpper} ${normalizedPath}`;
84
+ if (this.options.mockData[normalizedHttpMethodKey]) {
85
+ return this.options.mockData[normalizedHttpMethodKey];
86
+ }
87
+ const filePathKey = `${normalizedPath}/${methodLower}.js`;
65
88
  if (this.options.mockData[filePathKey]) {
66
89
  return this.options.mockData[filePathKey];
67
90
  }
@@ -70,21 +93,21 @@ var MockInterceptor = class {
70
93
  /**
71
94
  * Determine if request should be mocked
72
95
  */
73
- shouldMock(url, method) {
96
+ shouldMock(url, method, baseURL) {
74
97
  if (!this.isEnabled()) {
75
98
  return false;
76
99
  }
77
- const mock = this.findMock(url, method);
100
+ const mock = this.findMock(url, method, baseURL);
78
101
  return mock !== null && mock.enable;
79
102
  }
80
103
  /**
81
104
  * Get mock data for request
82
105
  */
83
- getMock(url, method) {
84
- if (!this.shouldMock(url, method)) {
106
+ getMock(url, method, baseURL) {
107
+ if (!this.shouldMock(url, method, baseURL)) {
85
108
  return null;
86
109
  }
87
- return this.findMock(url, method);
110
+ return this.findMock(url, method, baseURL);
88
111
  }
89
112
  /**
90
113
  * Setup axios interceptor
@@ -94,9 +117,10 @@ var MockInterceptor = class {
94
117
  async (config) => {
95
118
  const url = config.url || "";
96
119
  const method = config.method?.toUpperCase() || "GET";
97
- const mock = this.getMock(url, method);
120
+ const normalizedUrl = this.normalizeUrlPath(url, config.baseURL);
121
+ const mock = this.getMock(url, method, config.baseURL);
98
122
  if (mock) {
99
- this.options.onMockHit?.(url, method, mock);
123
+ this.options.onMockHit?.(normalizedUrl, method, mock);
100
124
  config.adapter = async () => {
101
125
  const { data, delay = 0, status = 200 } = mock;
102
126
  if (delay > 0) {
@@ -112,7 +136,7 @@ var MockInterceptor = class {
112
136
  };
113
137
  } else {
114
138
  const reason = !this.isEnabled() ? "Mock disabled globally" : "No matching mock found or mock disabled";
115
- this.options.onBypass?.(url, method, reason);
139
+ this.options.onBypass?.(normalizedUrl, method, reason);
116
140
  }
117
141
  return config;
118
142
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/client/index.ts","../../src/client/interceptor.ts"],"sourcesContent":["export {\n createMockInterceptor,\n initMockInterceptor,\n initMockInterceptorForPureHttp,\n setMockEnabled,\n isMockEnabled,\n loadMockData,\n registerHttpInstance\n} from './interceptor'\n\nexport type { MockInterceptorOptions, MockBundleData } from './interceptor'\n","import type {\n AxiosInstance,\n AxiosResponse,\n InternalAxiosRequestConfig,\n} from \"axios\";\n\ndeclare const __AUTOMOCK_ENABLED__: boolean;\n\nexport type MockBundleData = {\n enable: boolean;\n data: unknown;\n delay?: number;\n status?: number;\n isBinary?: boolean;\n};\n\nexport type MockInterceptorOptions = {\n mockData: Record<string, MockBundleData>;\n enabled?: boolean | (() => boolean);\n onMockHit?: (url: string, method: string, mock: MockBundleData) => void;\n onBypass?: (url: string, method: string, reason: string) => void;\n};\n\ntype MockEnabledState = boolean | undefined;\n\ndeclare global {\n interface Window {\n __MOCK_ENABLED__?: MockEnabledState;\n }\n}\n\nclass MockInterceptor {\n private options: MockInterceptorOptions;\n\n constructor(options: MockInterceptorOptions) {\n this.options = options;\n }\n\n /**\n * Check if mock is enabled\n */\n isEnabled(): boolean {\n // Check runtime flag first\n if (window.__MOCK_ENABLED__ !== undefined) {\n return window.__MOCK_ENABLED__;\n }\n // Check environment variable\n if (typeof this.options.enabled === \"function\") {\n return this.options.enabled();\n }\n return this.options.enabled ?? false;\n }\n\n /**\n * Find matching mock data for the request\n * Supports both formats:\n * - \"GET /api/v1/asset/xxx\" (HTTP method + URL)\n * - \"/api/v1/asset/xxx/get.js\" (File path format from automock plugin)\n */\n private findMock(url: string, method: string): MockBundleData | null {\n const methodUpper = method.toUpperCase();\n const methodLower = method.toLowerCase();\n\n // Try HTTP method + URL format first (for compatibility)\n const httpMethodKey = `${methodUpper} ${url}`;\n if (this.options.mockData[httpMethodKey]) {\n return this.options.mockData[httpMethodKey];\n }\n\n // Try file path format from automock plugin: /api/v1/asset/xxx/get.js\n const filePathKey = `${url}/${methodLower}.js`;\n if (this.options.mockData[filePathKey]) {\n return this.options.mockData[filePathKey];\n }\n\n return null;\n }\n\n /**\n * Determine if request should be mocked\n */\n shouldMock(url: string, method: string): boolean {\n if (!this.isEnabled()) {\n return false;\n }\n\n const mock = this.findMock(url, method);\n return mock !== null && mock.enable;\n }\n\n /**\n * Get mock data for request\n */\n getMock(url: string, method: string): MockBundleData | null {\n if (!this.shouldMock(url, method)) {\n return null;\n }\n return this.findMock(url, method);\n }\n\n /**\n * Setup axios interceptor\n */\n setupAxios(axiosInstance: AxiosInstance): void {\n axiosInstance.interceptors.request.use(\n async (config: InternalAxiosRequestConfig) => {\n const url = config.url || \"\";\n const method = config.method?.toUpperCase() || \"GET\";\n\n const mock = this.getMock(url, method);\n\n if (mock) {\n // Trigger mock hit callback\n this.options.onMockHit?.(url, method, mock);\n\n // Set adapter to return mock data\n (config as InternalAxiosRequestConfig & { adapter: () => Promise<AxiosResponse> }).adapter = async () => {\n const { data, delay = 0, status = 200 } = mock;\n\n // Simulate delay\n if (delay > 0) {\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n\n return {\n data,\n status,\n statusText: \"OK\",\n headers: {},\n config,\n };\n };\n } else {\n // Trigger bypass callback\n const reason = !this.isEnabled()\n ? \"Mock disabled globally\"\n : \"No matching mock found or mock disabled\";\n this.options.onBypass?.(url, method, reason);\n }\n\n return config;\n },\n (error: unknown) => Promise.reject(error),\n );\n }\n}\n\n/**\n * Create mock interceptor instance\n */\nexport function createMockInterceptor(\n options: MockInterceptorOptions,\n): MockInterceptor {\n return new MockInterceptor(options);\n}\n\n/**\n * Load mock data from bundled JSON file\n */\nexport async function loadMockData(): Promise<Record<string, MockBundleData>> {\n try {\n // In production, mock-data.json is generated by automock plugin\n // Use absolute path to load it from dist directory\n const response = await fetch(\"/mock-data.json\");\n if (!response.ok) {\n console.warn(\n \"[MockInterceptor] Failed to load mock-data.json:\",\n response.statusText,\n );\n return {};\n }\n const data = (await response.json()) as Record<string, MockBundleData>;\n return data;\n } catch (error) {\n console.warn(\"[MockInterceptor] Failed to load mock-data.json:\", error);\n return {};\n }\n}\n\nasync function createInterceptorFromBundle(): Promise<MockInterceptor> {\n const mockData = await loadMockData();\n const isEnabled = typeof __AUTOMOCK_ENABLED__ !== \"undefined\" && __AUTOMOCK_ENABLED__;\n\n return new MockInterceptor({\n mockData,\n enabled: isEnabled,\n onMockHit: (url: string, method: string) => {\n console.log(`[MOCK HIT] ${method} ${url}`);\n },\n onBypass: (url: string, method: string, reason: string) => {\n console.log(`[MOCK BYPASS] ${method} ${url} - ${reason}`);\n },\n });\n}\n\nexport async function initMockInterceptor(\n axiosInstance?: AxiosInstance,\n): Promise<void> {\n if (!axiosInstance) {\n throw new Error(\n \"[MockInterceptor] axiosInstance is required. Please provide an axios instance.\",\n );\n }\n\n const interceptor = await createInterceptorFromBundle();\n interceptor.setupAxios(axiosInstance);\n}\n\nexport function setMockEnabled(enabled: boolean): void {\n window.__MOCK_ENABLED__ = enabled;\n}\n\nexport function isMockEnabled(): boolean {\n return !!window.__MOCK_ENABLED__;\n}\n\ntype HttpInstance = {\n constructor: { axiosInstance: AxiosInstance };\n};\n\nlet httpInstanceRef: HttpInstance | undefined;\n\nexport function registerHttpInstance(http: HttpInstance): void {\n httpInstanceRef = http;\n}\n\nexport async function initMockInterceptorForPureHttp(): Promise<void> {\n if (!httpInstanceRef) {\n throw new Error(\n \"[MockInterceptor] http instance not registered. Call registerHttpInstance(http) first.\",\n );\n }\n\n const interceptor = await createInterceptorFromBundle();\n interceptor.setupAxios(httpInstanceRef.constructor.axiosInstance);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/client/index.ts","../../src/client/interceptor.ts"],"sourcesContent":["export {\n createMockInterceptor,\n initMockInterceptor,\n initMockInterceptorForPureHttp,\n setMockEnabled,\n isMockEnabled,\n loadMockData,\n registerHttpInstance\n} from './interceptor'\n\nexport type { MockInterceptorOptions, MockBundleData } from './interceptor'\n","import type {\n AxiosInstance,\n AxiosResponse,\n InternalAxiosRequestConfig,\n} from \"axios\";\n\ndeclare const __AUTOMOCK_ENABLED__: boolean;\n\nexport type MockBundleData = {\n enable: boolean;\n data: unknown;\n delay?: number;\n status?: number;\n isBinary?: boolean;\n};\n\nexport type MockInterceptorOptions = {\n mockData: Record<string, MockBundleData>;\n enabled?: boolean | (() => boolean);\n onMockHit?: (url: string, method: string, mock: MockBundleData) => void;\n onBypass?: (url: string, method: string, reason: string) => void;\n};\n\ntype MockEnabledState = boolean | undefined;\n\ndeclare global {\n interface Window {\n __MOCK_ENABLED__?: MockEnabledState;\n }\n}\n\nclass MockInterceptor {\n private options: MockInterceptorOptions;\n\n constructor(options: MockInterceptorOptions) {\n this.options = options;\n }\n\n private normalizeUrlPath(url: string, baseURL?: string): string {\n if (!url) return \"\";\n\n try {\n const isAbsoluteUrl = /^[a-z][a-z\\d+\\-.]*:\\/\\//i.test(url);\n const browserOrigin =\n typeof window !== \"undefined\" && window.location?.origin\n ? window.location.origin\n : \"http://localhost\";\n\n if (isAbsoluteUrl) {\n return new URL(url).pathname;\n }\n\n if (baseURL) {\n const normalizedBase = baseURL.endsWith(\"/\") ? baseURL : `${baseURL}/`;\n const normalizedUrl = url.replace(/^\\/+/, \"\");\n return new URL(normalizedUrl, normalizedBase).pathname;\n }\n\n return new URL(url, browserOrigin).pathname;\n } catch {\n return url.split(/[?#]/)[0] || \"\";\n }\n }\n\n /**\n * Check if mock is enabled\n */\n isEnabled(): boolean {\n // Check runtime flag first\n if (window.__MOCK_ENABLED__ !== undefined) {\n return window.__MOCK_ENABLED__;\n }\n // Check environment variable\n if (typeof this.options.enabled === \"function\") {\n return this.options.enabled();\n }\n return this.options.enabled ?? false;\n }\n\n /**\n * Find matching mock data for the request\n * Supports both formats:\n * - \"GET /api/v1/asset/xxx\" (HTTP method + URL)\n * - \"/api/v1/asset/xxx/get.js\" (File path format from automock plugin)\n */\n private findMock(url: string, method: string, baseURL?: string): MockBundleData | null {\n const methodUpper = method.toUpperCase();\n const methodLower = method.toLowerCase();\n const normalizedPath = this.normalizeUrlPath(url, baseURL);\n\n // Try HTTP method + URL format first (for compatibility)\n const httpMethodKey = `${methodUpper} ${url}`;\n if (this.options.mockData[httpMethodKey]) {\n return this.options.mockData[httpMethodKey];\n }\n\n const normalizedHttpMethodKey = `${methodUpper} ${normalizedPath}`;\n if (this.options.mockData[normalizedHttpMethodKey]) {\n return this.options.mockData[normalizedHttpMethodKey];\n }\n\n // Try file path format from automock plugin: /api/v1/asset/xxx/get.js\n const filePathKey = `${normalizedPath}/${methodLower}.js`;\n if (this.options.mockData[filePathKey]) {\n return this.options.mockData[filePathKey];\n }\n\n return null;\n }\n\n /**\n * Determine if request should be mocked\n */\n shouldMock(url: string, method: string, baseURL?: string): boolean {\n if (!this.isEnabled()) {\n return false;\n }\n\n const mock = this.findMock(url, method, baseURL);\n return mock !== null && mock.enable;\n }\n\n /**\n * Get mock data for request\n */\n getMock(url: string, method: string, baseURL?: string): MockBundleData | null {\n if (!this.shouldMock(url, method, baseURL)) {\n return null;\n }\n return this.findMock(url, method, baseURL);\n }\n\n /**\n * Setup axios interceptor\n */\n setupAxios(axiosInstance: AxiosInstance): void {\n axiosInstance.interceptors.request.use(\n async (config: InternalAxiosRequestConfig) => {\n const url = config.url || \"\";\n const method = config.method?.toUpperCase() || \"GET\";\n const normalizedUrl = this.normalizeUrlPath(url, config.baseURL);\n\n const mock = this.getMock(url, method, config.baseURL);\n\n if (mock) {\n // Trigger mock hit callback\n this.options.onMockHit?.(normalizedUrl, method, mock);\n\n // Set adapter to return mock data\n (config as InternalAxiosRequestConfig & { adapter: () => Promise<AxiosResponse> }).adapter = async () => {\n const { data, delay = 0, status = 200 } = mock;\n\n // Simulate delay\n if (delay > 0) {\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n\n return {\n data,\n status,\n statusText: \"OK\",\n headers: {},\n config,\n };\n };\n } else {\n // Trigger bypass callback\n const reason = !this.isEnabled()\n ? \"Mock disabled globally\"\n : \"No matching mock found or mock disabled\";\n this.options.onBypass?.(normalizedUrl, method, reason);\n }\n\n return config;\n },\n (error: unknown) => Promise.reject(error),\n );\n }\n}\n\n/**\n * Create mock interceptor instance\n */\nexport function createMockInterceptor(\n options: MockInterceptorOptions,\n): MockInterceptor {\n return new MockInterceptor(options);\n}\n\n/**\n * Load mock data from bundled JSON file\n */\nexport async function loadMockData(): Promise<Record<string, MockBundleData>> {\n try {\n // In production, mock-data.json is generated by automock plugin\n // Use absolute path to load it from dist directory\n const response = await fetch(\"/mock-data.json\");\n if (!response.ok) {\n console.warn(\n \"[MockInterceptor] Failed to load mock-data.json:\",\n response.statusText,\n );\n return {};\n }\n const data = (await response.json()) as Record<string, MockBundleData>;\n return data;\n } catch (error) {\n console.warn(\"[MockInterceptor] Failed to load mock-data.json:\", error);\n return {};\n }\n}\n\nasync function createInterceptorFromBundle(): Promise<MockInterceptor> {\n const mockData = await loadMockData();\n const isEnabled = typeof __AUTOMOCK_ENABLED__ !== \"undefined\" && __AUTOMOCK_ENABLED__;\n\n return new MockInterceptor({\n mockData,\n enabled: isEnabled,\n onMockHit: (url: string, method: string) => {\n console.log(`[MOCK HIT] ${method} ${url}`);\n },\n onBypass: (url: string, method: string, reason: string) => {\n console.log(`[MOCK BYPASS] ${method} ${url} - ${reason}`);\n },\n });\n}\n\nexport async function initMockInterceptor(\n axiosInstance?: AxiosInstance,\n): Promise<void> {\n if (!axiosInstance) {\n throw new Error(\n \"[MockInterceptor] axiosInstance is required. Please provide an axios instance.\",\n );\n }\n\n const interceptor = await createInterceptorFromBundle();\n interceptor.setupAxios(axiosInstance);\n}\n\nexport function setMockEnabled(enabled: boolean): void {\n window.__MOCK_ENABLED__ = enabled;\n}\n\nexport function isMockEnabled(): boolean {\n return !!window.__MOCK_ENABLED__;\n}\n\ntype HttpInstance = {\n constructor: { axiosInstance: AxiosInstance };\n};\n\nlet httpInstanceRef: HttpInstance | undefined;\n\nexport function registerHttpInstance(http: HttpInstance): void {\n httpInstanceRef = http;\n}\n\nexport async function initMockInterceptorForPureHttp(): Promise<void> {\n if (!httpInstanceRef) {\n throw new Error(\n \"[MockInterceptor] http instance not registered. Call registerHttpInstance(http) first.\",\n );\n }\n\n const interceptor = await createInterceptorFromBundle();\n interceptor.setupAxios(httpInstanceRef.constructor.axiosInstance);\n}\n"],"mappings":"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","names":[]}
@@ -6,7 +6,7 @@ import {
6
6
  loadMockData,
7
7
  registerHttpInstance,
8
8
  setMockEnabled
9
- } from "../chunk-DJWYFFPU.mjs";
9
+ } from "../chunk-2KRAWI7J.mjs";
10
10
  export {
11
11
  createMockInterceptor,
12
12
  initMockInterceptor,
package/dist/index.d.mts CHANGED
@@ -7,17 +7,22 @@ interface InspectorOptions {
7
7
  enableToggle?: boolean;
8
8
  }
9
9
  interface AutomockPluginOptions {
10
+ /** Directory for mock files, default "mock". */
10
11
  mockDir?: string;
12
+ /** API path prefix handled by automock, default "/api". */
11
13
  apiPrefix?: string;
14
+ /** Rewrite request path before proxying to proxyBaseUrl. */
12
15
  pathRewrite?: (path: string) => string;
16
+ /** Real backend base URL. Required only when automock proxy/capture is used. */
13
17
  proxyBaseUrl?: string;
14
18
  inspector?: boolean | InspectorOptions;
19
+ /** Client-side production mock switch. Default false; "auto" enables outside production mode. */
15
20
  productionMock?: boolean | 'auto';
16
- /** Global switch, default true. When false, middleware passes through all requests. */
21
+ /** Global switch, default true. When false, middleware passes through all requests without proxy/capture. */
17
22
  enabled?: boolean;
18
23
  /** Whether to proxy unmatched requests to proxyBaseUrl, default true. */
19
24
  proxy?: boolean;
20
- /** Whether to capture and save new mock files from proxy responses, default true. */
25
+ /** Whether to capture and save JSON proxy responses as mock files, default true. */
21
26
  capture?: boolean;
22
27
  }
23
28
 
package/dist/index.d.ts CHANGED
@@ -7,17 +7,22 @@ interface InspectorOptions {
7
7
  enableToggle?: boolean;
8
8
  }
9
9
  interface AutomockPluginOptions {
10
+ /** Directory for mock files, default "mock". */
10
11
  mockDir?: string;
12
+ /** API path prefix handled by automock, default "/api". */
11
13
  apiPrefix?: string;
14
+ /** Rewrite request path before proxying to proxyBaseUrl. */
12
15
  pathRewrite?: (path: string) => string;
16
+ /** Real backend base URL. Required only when automock proxy/capture is used. */
13
17
  proxyBaseUrl?: string;
14
18
  inspector?: boolean | InspectorOptions;
19
+ /** Client-side production mock switch. Default false; "auto" enables outside production mode. */
15
20
  productionMock?: boolean | 'auto';
16
- /** Global switch, default true. When false, middleware passes through all requests. */
21
+ /** Global switch, default true. When false, middleware passes through all requests without proxy/capture. */
17
22
  enabled?: boolean;
18
23
  /** Whether to proxy unmatched requests to proxyBaseUrl, default true. */
19
24
  proxy?: boolean;
20
- /** Whether to capture and save new mock files from proxy responses, default true. */
25
+ /** Whether to capture and save JSON proxy responses as mock files, default true. */
21
26
  capture?: boolean;
22
27
  }
23
28