@farm.js/msw 0.1.0-beta.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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Farm.js Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # @farm.js/msw
2
+
3
+ Run one set of [Mock Service Worker](https://mswjs.io/) handlers in the browser and during Farm
4
+ development SSR.
5
+
6
+ ## Install
7
+
8
+ ```bash
9
+ pnpm add -D @farm.js/msw
10
+ ```
11
+
12
+ ## Configure
13
+
14
+ ```ts
15
+ import { defineConfig } from "@farm.js/core";
16
+ import { msw } from "@farm.js/msw";
17
+
18
+ export default defineConfig({
19
+ plugins: [msw({ handlers: "./src/mocks/handlers.ts" })],
20
+ });
21
+ ```
22
+
23
+ ```ts
24
+ import { delay, http, HttpResponse } from "@farm.js/msw/handlers";
25
+
26
+ export const handlers = [
27
+ http.get("/api/products", async () => {
28
+ await delay(200);
29
+ return HttpResponse.json([{ id: "tractor", name: "Tractor" }]);
30
+ }),
31
+ ];
32
+ ```
33
+
34
+ The plugin starts MSW's Node interceptor before development requests reach Farm and starts the
35
+ browser worker before hydration. Handler changes are reloaded through Vite HMR. During a production
36
+ build the plugin removes itself from Farm's resolved configuration, so MSW is not bundled or
37
+ started.
38
+
39
+ ## Options
40
+
41
+ ```ts
42
+ msw({
43
+ handlers: "./src/mocks/handlers.ts",
44
+ browser: true,
45
+ server: true,
46
+ onUnhandledRequest: "bypass",
47
+ });
48
+ ```
49
+
50
+ Set `browser` or `server` to `false` when only one development runtime should be mocked. Use
51
+ `onUnhandledRequest: "warn"` or `"error"` when every request is expected to have a handler.
@@ -0,0 +1,12 @@
1
+ import type { MswUnhandledRequestBehavior } from "./config.js";
2
+ export interface MswBrowserRuntimeOptions {
3
+ workerUrl: string;
4
+ scope: string;
5
+ onUnhandledRequest: MswUnhandledRequestBehavior;
6
+ }
7
+ export interface FarmMswBrowserRuntime {
8
+ stop(): void;
9
+ }
10
+ /** Start the browser worker used by the Farm plugin during development. */
11
+ export declare function startMswBrowserRuntime(options: MswBrowserRuntimeOptions): Promise<FarmMswBrowserRuntime>;
12
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AAE/D,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB,EAAE,2BAA2B,CAAC;CACjD;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,IAAI,IAAI,CAAC;CACd;AAED,2EAA2E;AAC3E,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,qBAAqB,CAAC,CAkBhC"}
package/dist/client.js ADDED
@@ -0,0 +1,23 @@
1
+ "use client";
2
+ import { setupWorker } from "msw/browser";
3
+ import { handlers } from "virtual:farm-msw-handlers";
4
+ /** Start the browser worker used by the Farm plugin during development. */
5
+ export async function startMswBrowserRuntime(options) {
6
+ const worker = setupWorker(...handlers);
7
+ await worker.start({
8
+ onUnhandledRequest: options.onUnhandledRequest,
9
+ serviceWorker: {
10
+ url: options.workerUrl,
11
+ options: { scope: options.scope },
12
+ },
13
+ });
14
+ let stopped = false;
15
+ return {
16
+ stop() {
17
+ if (stopped)
18
+ return;
19
+ stopped = true;
20
+ worker.stop();
21
+ },
22
+ };
23
+ }
@@ -0,0 +1,22 @@
1
+ export type MswUnhandledRequestBehavior = "bypass" | "warn" | "error";
2
+ export interface MswPluginOptions {
3
+ /** Module exporting a `handlers` array. Resolved from the Farm app root. */
4
+ handlers: string;
5
+ /** Mock requests made by browser code. Defaults to true. */
6
+ browser?: boolean;
7
+ /** Mock requests made during development SSR and by server code. Defaults to true. */
8
+ server?: boolean;
9
+ /** How MSW handles requests that have no matching handler. Defaults to bypass. */
10
+ onUnhandledRequest?: MswUnhandledRequestBehavior;
11
+ /** Set false to leave the plugin configured without starting either runtime. */
12
+ enabled?: boolean;
13
+ }
14
+ export interface ResolvedMswOptions {
15
+ handlers: string;
16
+ browser: boolean;
17
+ server: boolean;
18
+ onUnhandledRequest: MswUnhandledRequestBehavior;
19
+ enabled: boolean;
20
+ }
21
+ export declare function resolveMswOptions(options: MswPluginOptions): ResolvedMswOptions;
22
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,2BAA2B,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;AAEtE,MAAM,WAAW,gBAAgB;IAC/B,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,sFAAsF;IACtF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,kFAAkF;IAClF,kBAAkB,CAAC,EAAE,2BAA2B,CAAC;IACjD,gFAAgF;IAChF,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,kBAAkB,EAAE,2BAA2B,CAAC;IAChD,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,GAAG,kBAAkB,CA2B/E"}
package/dist/config.js ADDED
@@ -0,0 +1,29 @@
1
+ export function resolveMswOptions(options) {
2
+ if (!options || typeof options !== "object" || Array.isArray(options)) {
3
+ throw new TypeError("msw options must be an object");
4
+ }
5
+ if (typeof options.handlers !== "string" || !options.handlers.trim()) {
6
+ throw new TypeError("msw handlers must be a non-empty module path");
7
+ }
8
+ assertBoolean(options.browser, "browser");
9
+ assertBoolean(options.server, "server");
10
+ assertBoolean(options.enabled, "enabled");
11
+ if (options.onUnhandledRequest !== undefined &&
12
+ options.onUnhandledRequest !== "bypass" &&
13
+ options.onUnhandledRequest !== "warn" &&
14
+ options.onUnhandledRequest !== "error") {
15
+ throw new TypeError('msw onUnhandledRequest must be "bypass", "warn", or "error"');
16
+ }
17
+ return {
18
+ handlers: options.handlers.trim(),
19
+ browser: options.browser ?? true,
20
+ server: options.server ?? true,
21
+ onUnhandledRequest: options.onUnhandledRequest ?? "bypass",
22
+ enabled: options.enabled ?? true,
23
+ };
24
+ }
25
+ function assertBoolean(value, key) {
26
+ if (value !== undefined && typeof value !== "boolean") {
27
+ throw new TypeError(`msw ${key} must be boolean`);
28
+ }
29
+ }
@@ -0,0 +1,3 @@
1
+ export { bypass, delay, graphql, http, HttpResponse, passthrough, ws } from "msw";
2
+ export type { GraphQLHandler, HttpHandler, RequestHandler } from "msw";
3
+ //# sourceMappingURL=handlers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../src/handlers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,KAAK,CAAC;AAClF,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC"}
@@ -0,0 +1 @@
1
+ export { bypass, delay, graphql, http, HttpResponse, passthrough, ws } from "msw";
@@ -0,0 +1,44 @@
1
+ import { type FarmPlugin } from "@farm.js/core/plugin";
2
+ import type { RequestHandler } from "msw";
3
+ import { type MswPluginOptions, type MswUnhandledRequestBehavior } from "./config.js";
4
+ export type { MswPluginOptions, MswUnhandledRequestBehavior };
5
+ interface MswPluginState {
6
+ server?: MswServerRuntime;
7
+ viteServer?: FarmViteDevServer;
8
+ closeListener?: () => void;
9
+ }
10
+ interface MswServerRuntime {
11
+ listen(options: {
12
+ onUnhandledRequest: MswUnhandledRequestBehavior;
13
+ }): void;
14
+ resetHandlers(...handlers: RequestHandler[]): void;
15
+ close(): void;
16
+ }
17
+ interface MswBrowserState {
18
+ stop(): void;
19
+ }
20
+ interface FarmModuleNode {
21
+ file?: string | null;
22
+ id?: string | null;
23
+ importedModules?: Set<FarmModuleNode>;
24
+ }
25
+ interface FarmViteDevServer {
26
+ ssrLoadModule(id: string): Promise<Record<string, unknown>>;
27
+ moduleGraph?: {
28
+ getModulesByFile(file: string): Set<FarmModuleNode> | undefined;
29
+ };
30
+ httpServer?: {
31
+ once(event: "close", listener: () => void): unknown;
32
+ off?(event: "close", listener: () => void): unknown;
33
+ } | null;
34
+ }
35
+ /**
36
+ * Use one MSW handler module for browser requests and development SSR.
37
+ * The plugin removes itself from production config, so neither MSW runtime is bundled or started there.
38
+ */
39
+ export declare function msw(options: MswPluginOptions): FarmPlugin<MswPluginState, Record<string, unknown>, MswBrowserState | undefined, {
40
+ workerUrl: string;
41
+ scope: string;
42
+ onUnhandledRequest: MswUnhandledRequestBehavior;
43
+ }>;
44
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgB,KAAK,UAAU,EAA+B,MAAM,sBAAsB,CAAC;AAClG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAC1C,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,2BAA2B,EACjC,MAAM,aAAa,CAAC;AAErB,YAAY,EAAE,gBAAgB,EAAE,2BAA2B,EAAE,CAAC;AAM9D,UAAU,cAAc;IACtB,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED,UAAU,gBAAgB;IACxB,MAAM,CAAC,OAAO,EAAE;QAAE,kBAAkB,EAAE,2BAA2B,CAAA;KAAE,GAAG,IAAI,CAAC;IAC3E,aAAa,CAAC,GAAG,QAAQ,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC;IACnD,KAAK,IAAI,IAAI,CAAC;CACf;AAED,UAAU,eAAe;IACvB,IAAI,IAAI,IAAI,CAAC;CACd;AAED,UAAU,cAAc;IACtB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,eAAe,CAAC,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;CACvC;AAED,UAAU,iBAAiB;IACzB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5D,WAAW,CAAC,EAAE;QACZ,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;KACjE,CAAC;IACF,UAAU,CAAC,EAAE;QACX,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC;QACpD,GAAG,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC;KACrD,GAAG,IAAI,CAAC;CACV;AAwBD;;;GAGG;AACH,wBAAgB,GAAG,CAAC,OAAO,EAAE,gBAAgB;;;;GA8G5C"}
package/dist/index.js ADDED
@@ -0,0 +1,209 @@
1
+ import { readFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { createRequire } from "node:module";
4
+ import { definePlugin } from "@farm.js/core/plugin";
5
+ import { resolveMswOptions, } from "./config.js";
6
+ const VIRTUAL_HANDLERS_ID = "virtual:farm-msw-handlers";
7
+ const RESOLVED_VIRTUAL_HANDLERS_ID = `\0${VIRTUAL_HANDLERS_ID}`;
8
+ const DEFAULT_WORKER_FILE = "mockServiceWorker.js";
9
+ /**
10
+ * Use one MSW handler module for browser requests and development SSR.
11
+ * The plugin removes itself from production config, so neither MSW runtime is bundled or started there.
12
+ */
13
+ export function msw(options) {
14
+ const resolved = resolveMswOptions(options);
15
+ let handlersFile = "";
16
+ const publicConfig = {
17
+ workerUrl: `/${DEFAULT_WORKER_FILE}`,
18
+ scope: "/",
19
+ onUnhandledRequest: resolved.onUnhandledRequest,
20
+ };
21
+ const browserClient = resolved.enabled && resolved.browser
22
+ ? {
23
+ public: publicConfig,
24
+ async setup({ public: config, isDev }) {
25
+ if (!isDev)
26
+ return undefined;
27
+ const runtime = await import("@farm.js/msw/client");
28
+ return runtime.startMswBrowserRuntime(config);
29
+ },
30
+ close({ state }) {
31
+ state?.stop();
32
+ },
33
+ }
34
+ : undefined;
35
+ let plugin;
36
+ plugin = definePlugin({
37
+ name: "farm:msw",
38
+ enforce: "pre",
39
+ configure(config, context) {
40
+ if (!resolved.enabled || context.isProd) {
41
+ return withoutPlugin(config, plugin);
42
+ }
43
+ const root = path.resolve(config.root ?? ".");
44
+ handlersFile = path.resolve(root, resolved.handlers);
45
+ const basePath = normalizeBasePath(config.basePath);
46
+ publicConfig.workerUrl = `${basePath === "/" ? "" : basePath}/${DEFAULT_WORKER_FILE}`;
47
+ publicConfig.scope = basePath === "/" ? "/" : `${basePath}/`;
48
+ if (!resolved.browser)
49
+ return;
50
+ const vite = config.vite ?? {};
51
+ return {
52
+ ...config,
53
+ vite: {
54
+ ...vite,
55
+ plugins: [
56
+ createMswVitePlugin({
57
+ handlersFile,
58
+ workerUrl: publicConfig.workerUrl,
59
+ scope: publicConfig.scope,
60
+ }),
61
+ ...(vite.plugins ?? []),
62
+ ],
63
+ },
64
+ };
65
+ },
66
+ setup() {
67
+ return {};
68
+ },
69
+ dev: {
70
+ async server(viteServer, { state }) {
71
+ if (!resolved.enabled || !resolved.server)
72
+ return;
73
+ const server = viteServer;
74
+ const handlers = await loadHandlers(server, handlersFile);
75
+ const { setupServer } = await import("msw/node");
76
+ const mockServer = setupServer(...handlers);
77
+ mockServer.listen({ onUnhandledRequest: resolved.onUnhandledRequest });
78
+ state.server = mockServer;
79
+ state.viteServer = server;
80
+ state.closeListener = () => closeMswServer(state);
81
+ server.httpServer?.once("close", state.closeListener);
82
+ },
83
+ async update(update, { state }) {
84
+ if (!state.server || !state.viteServer)
85
+ return;
86
+ if (!isHandlersUpdate(state.viteServer, handlersFile, update.file))
87
+ return;
88
+ const handlers = await loadHandlers(state.viteServer, handlersFile, Date.now());
89
+ state.server.resetHandlers(...handlers);
90
+ },
91
+ },
92
+ runtime: {
93
+ close({ state }) {
94
+ closeMswServer(state);
95
+ },
96
+ },
97
+ client: browserClient,
98
+ });
99
+ return plugin;
100
+ }
101
+ function withoutPlugin(config, plugin) {
102
+ if (!config.plugins?.includes(plugin))
103
+ return;
104
+ return {
105
+ ...config,
106
+ plugins: config.plugins.filter((candidate) => candidate !== plugin),
107
+ };
108
+ }
109
+ function createMswVitePlugin(input) {
110
+ const require = createRequire(import.meta.url);
111
+ const workerFile = require.resolve("msw/mockServiceWorker.js");
112
+ const workerSource = readFileSync(workerFile, "utf8");
113
+ return {
114
+ name: "farm:msw-vite",
115
+ enforce: "pre",
116
+ resolveId(id) {
117
+ return id === VIRTUAL_HANDLERS_ID ? RESOLVED_VIRTUAL_HANDLERS_ID : undefined;
118
+ },
119
+ load(id) {
120
+ if (id !== RESOLVED_VIRTUAL_HANDLERS_ID)
121
+ return undefined;
122
+ return renderVirtualHandlersModule(input.handlersFile);
123
+ },
124
+ configureServer(server) {
125
+ server.middlewares.use((request, response, next) => {
126
+ if (request.method !== "GET" && request.method !== "HEAD")
127
+ return next();
128
+ if (requestPathname(request.url) !== input.workerUrl)
129
+ return next();
130
+ response.statusCode = 200;
131
+ response.setHeader("Content-Type", "application/javascript; charset=utf-8");
132
+ response.setHeader("Cache-Control", "no-store");
133
+ response.setHeader("Service-Worker-Allowed", input.scope);
134
+ response.end(request.method === "HEAD" ? undefined : workerSource);
135
+ });
136
+ },
137
+ };
138
+ }
139
+ function renderVirtualHandlersModule(handlersFile) {
140
+ return `import * as handlerModule from ${JSON.stringify(toModuleId(handlersFile))};
141
+ const candidate = handlerModule.handlers ?? handlerModule.default;
142
+ if (!Array.isArray(candidate)) {
143
+ throw new TypeError(${JSON.stringify(invalidHandlersMessage(handlersFile))});
144
+ }
145
+ export const handlers = candidate;`;
146
+ }
147
+ async function loadHandlers(server, handlersFile, cacheBust) {
148
+ const id = `${toModuleId(handlersFile)}${cacheBust ? `?farm-msw=${cacheBust}` : ""}`;
149
+ const loaded = await server.ssrLoadModule(id);
150
+ const candidate = loaded.handlers ?? loaded.default;
151
+ if (!Array.isArray(candidate))
152
+ throw new TypeError(invalidHandlersMessage(handlersFile));
153
+ return candidate;
154
+ }
155
+ function closeMswServer(state) {
156
+ if (!state.server)
157
+ return;
158
+ state.server.close();
159
+ state.server = undefined;
160
+ if (state.closeListener) {
161
+ state.viteServer?.httpServer?.off?.("close", state.closeListener);
162
+ state.closeListener = undefined;
163
+ }
164
+ state.viteServer = undefined;
165
+ }
166
+ function isHandlersUpdate(server, handlersFile, changedFile) {
167
+ const normalizedChangedFile = normalizeFile(changedFile);
168
+ if (normalizedChangedFile === normalizeFile(handlersFile))
169
+ return true;
170
+ const handlerModules = server.moduleGraph?.getModulesByFile(handlersFile);
171
+ if (!handlerModules)
172
+ return false;
173
+ return [...handlerModules].some((module) => moduleDependsOnFile(module, normalizedChangedFile));
174
+ }
175
+ function moduleDependsOnFile(module, changedFile, seen = new Set()) {
176
+ if (seen.has(module))
177
+ return false;
178
+ seen.add(module);
179
+ if (moduleFile(module) === changedFile)
180
+ return true;
181
+ return [...(module.importedModules ?? [])].some((dependency) => moduleDependsOnFile(dependency, changedFile, seen));
182
+ }
183
+ function moduleFile(module) {
184
+ return normalizeFile(module.file ?? module.id?.split("?", 1)[0] ?? "");
185
+ }
186
+ function invalidHandlersMessage(handlersFile) {
187
+ return `[farm:msw] ${handlersFile} must export a handlers array (named or default export).`;
188
+ }
189
+ function normalizeBasePath(value) {
190
+ if (typeof value !== "string" || !value.trim() || value === "/")
191
+ return "/";
192
+ return `/${value.replace(/^\/+|\/+$/g, "")}`;
193
+ }
194
+ function requestPathname(url) {
195
+ if (!url)
196
+ return "";
197
+ try {
198
+ return new URL(url, "http://farm.local").pathname;
199
+ }
200
+ catch {
201
+ return "";
202
+ }
203
+ }
204
+ function normalizeFile(file) {
205
+ return path.normalize(file).replace(/\\/g, "/");
206
+ }
207
+ function toModuleId(file) {
208
+ return file.replace(/\\/g, "/");
209
+ }
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@farm.js/msw",
3
+ "version": "0.1.0-beta.0",
4
+ "description": "Shared browser and server API mocking for Farm.js development",
5
+ "keywords": [
6
+ "api-mocking",
7
+ "farm.js",
8
+ "mock-service-worker",
9
+ "msw",
10
+ "testing"
11
+ ],
12
+ "license": "MIT",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/farming-labs/farm.js",
16
+ "directory": "packages/farm-msw"
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "type": "module",
22
+ "main": "./dist/index.js",
23
+ "module": "./dist/index.js",
24
+ "types": "./dist/index.d.ts",
25
+ "exports": {
26
+ ".": {
27
+ "types": "./dist/index.d.ts",
28
+ "import": "./dist/index.js"
29
+ },
30
+ "./client": {
31
+ "types": "./dist/client.d.ts",
32
+ "import": "./dist/client.js"
33
+ },
34
+ "./handlers": {
35
+ "types": "./dist/handlers.d.ts",
36
+ "import": "./dist/handlers.js"
37
+ }
38
+ },
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "dependencies": {
43
+ "msw": "^2.15.0",
44
+ "@farm.js/core": "0.1.0-beta.87"
45
+ },
46
+ "devDependencies": {
47
+ "@types/node": "^20.10.5",
48
+ "typescript": "^5.3.3",
49
+ "vitest": "^3.2.7"
50
+ },
51
+ "engines": {
52
+ "node": ">=22.13.0"
53
+ },
54
+ "scripts": {
55
+ "build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc",
56
+ "dev": "tsc --watch",
57
+ "type-check": "tsc --noEmit",
58
+ "test": "vitest run"
59
+ }
60
+ }