@kodycodes/cli 1.19.2 → 1.20.1

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.
Files changed (45) hide show
  1. package/dist/cli.d.ts +1 -0
  2. package/dist/cli.js +101 -5
  3. package/dist/cli.js.map +1 -1
  4. package/dist/dev-command.d.ts +8 -0
  5. package/dist/dev-command.js +23 -0
  6. package/dist/dev-command.js.map +1 -1
  7. package/dist/help.js +14 -4
  8. package/dist/help.js.map +1 -1
  9. package/dist/local-execute.d.ts +9 -0
  10. package/dist/local-execute.js +38 -11
  11. package/dist/local-execute.js.map +1 -1
  12. package/dist/local-package-graph.d.ts +7 -0
  13. package/dist/local-package-graph.js +67 -1
  14. package/dist/local-package-graph.js.map +1 -1
  15. package/dist/local-package-run.d.ts +7 -0
  16. package/dist/local-package-run.js +34 -7
  17. package/dist/local-package-run.js.map +1 -1
  18. package/dist/mock/install-mock-fetch-shim.d.ts +19 -0
  19. package/dist/mock/install-mock-fetch-shim.js +36 -0
  20. package/dist/mock/install-mock-fetch-shim.js.map +1 -0
  21. package/dist/mock/load-package-mocks.d.ts +19 -0
  22. package/dist/mock/load-package-mocks.js +115 -0
  23. package/dist/mock/load-package-mocks.js.map +1 -0
  24. package/dist/mock/mock-fetch-gateway.d.ts +64 -0
  25. package/dist/mock/mock-fetch-gateway.js +242 -0
  26. package/dist/mock/mock-fetch-gateway.js.map +1 -0
  27. package/dist/mock/mock-gateway-fetch-shim.d.ts +15 -0
  28. package/dist/mock/mock-gateway-fetch-shim.js +104 -0
  29. package/dist/mock/mock-gateway-fetch-shim.js.map +1 -0
  30. package/dist/mock/mock-server.js +19 -2
  31. package/dist/mock/mock-server.js.map +1 -1
  32. package/dist/mock/mock-storage.d.ts +11 -0
  33. package/dist/mock/mock-storage.js +65 -0
  34. package/dist/mock/mock-storage.js.map +1 -1
  35. package/dist/mock/mock-supported.d.ts +1 -1
  36. package/dist/mock/mock-supported.js +2 -0
  37. package/dist/mock/mock-supported.js.map +1 -1
  38. package/dist/package-app-dev.d.ts +5 -0
  39. package/dist/package-app-dev.js +38 -10
  40. package/dist/package-app-dev.js.map +1 -1
  41. package/dist/package-local-runtime-source.js +8 -0
  42. package/dist/package-local-runtime-source.js.map +1 -1
  43. package/dist/structured-error.d.ts +1 -1
  44. package/dist/structured-error.js.map +1 -1
  45. package/package.json +2 -1
@@ -0,0 +1,36 @@
1
+ /**
2
+ * When `.kody/mocks.ts` is active under `--target mock`, embed the CLI-owned
3
+ * gateway-fetch shim and ensure the workerd entry side-effect imports it.
4
+ *
5
+ * Keep the origin `.__kody_virtual__/runtime.js` module (CAF / packageStorage
6
+ * re-exports). Register the mock wrap under a *flat* module name so bare
7
+ * `kody:runtime` does not path-join under `.__kody_virtual__/` (same workerd
8
+ * rule as kentcdodds/kody local-execute-package-graph).
9
+ */
10
+ import { writeFile } from 'node:fs/promises';
11
+ import { join } from 'node:path';
12
+ import { localExecuteGatewayFetchShimModuleName } from '../local-package-graph.js';
13
+ import { createMockGatewayFetchShimSource } from './mock-gateway-fetch-shim.js';
14
+ const mockShimFileName = 'mock-gateway-fetch-shim.js';
15
+ /** Flat workerd module name — must not contain `/` (path-join hazard). */
16
+ export const mockGatewayFetchShimModuleName = '.__kody_mock_gateway_fetch__.js';
17
+ export async function installMockFetchShimModules(input) {
18
+ const withoutDup = input.packageModules.filter((module) => module.name !== mockGatewayFetchShimModuleName);
19
+ await writeFile(join(input.workDir, mockShimFileName), createMockGatewayFetchShimSource());
20
+ const originShimNames = withoutDup
21
+ .map((module) => module.name)
22
+ .filter((name) => name === localExecuteGatewayFetchShimModuleName);
23
+ return {
24
+ packageModules: [
25
+ ...withoutDup,
26
+ {
27
+ name: mockGatewayFetchShimModuleName,
28
+ file: mockShimFileName,
29
+ },
30
+ ],
31
+ // Origin first (runtime re-exports + secret wrap), mock last so ambient
32
+ // fetch is fail-closed through the Node MSW gateway.
33
+ sideEffectModules: [...originShimNames, mockGatewayFetchShimModuleName],
34
+ };
35
+ }
36
+ //# sourceMappingURL=install-mock-fetch-shim.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-mock-fetch-shim.js","sourceRoot":"","sources":["../../src/mock/install-mock-fetch-shim.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,sCAAsC,EAAE,MAAM,2BAA2B,CAAA;AAElF,OAAO,EAAE,gCAAgC,EAAE,MAAM,8BAA8B,CAAA;AAE/E,MAAM,gBAAgB,GAAG,4BAA4B,CAAA;AAErD,0EAA0E;AAC1E,MAAM,CAAC,MAAM,8BAA8B,GAAG,iCAAiC,CAAA;AAE/E,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,KAGjD;IAIA,MAAM,UAAU,GAAG,KAAK,CAAC,cAAc,CAAC,MAAM,CAC7C,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,8BAA8B,CAC1D,CAAA;IACD,MAAM,SAAS,CACd,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,gBAAgB,CAAC,EACrC,gCAAgC,EAAE,CAClC,CAAA;IACD,MAAM,eAAe,GAAG,UAAU;SAChC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC;SAC5B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,sCAAsC,CAAC,CAAA;IACnE,OAAO;QACN,cAAc,EAAE;YACf,GAAG,UAAU;YACb;gBACC,IAAI,EAAE,8BAA8B;gBACpC,IAAI,EAAE,gBAAgB;aACtB;SACD;QACD,wEAAwE;QACxE,qDAAqD;QACrD,iBAAiB,EAAE,CAAC,GAAG,eAAe,EAAE,8BAA8B,CAAC;KACvE,CAAA;AACF,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Load optional `<packageRoot>/.kody/mocks.ts` for `--target mock` outbound
3
+ * fetch mocking. Missing file → no handlers (packages without mocks keep
4
+ * native workerd fetch). Never imported into published package bundles.
5
+ */
6
+ import type { RequestHandler } from 'msw';
7
+ export declare const packageMocksRelativePath = ".kody/mocks.ts";
8
+ export type LoadedPackageMocks = {
9
+ path: string;
10
+ handlers: Array<RequestHandler>;
11
+ };
12
+ export declare function resolvePackageMocksPath(packageRoot: string): Promise<string | null>;
13
+ /**
14
+ * Bundle and evaluate `.kody/mocks.ts`. Expects `export const handlers = […]`
15
+ * (MSW `http.*` handlers) or a default export of that array.
16
+ */
17
+ export declare function loadPackageMocks(packageRoot: string): Promise<LoadedPackageMocks | null>;
18
+ /** Write a tiny helper so tests can assert the relative path without importing fs. */
19
+ export declare function packageMocksPathFor(packageRoot: string): string;
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Load optional `<packageRoot>/.kody/mocks.ts` for `--target mock` outbound
3
+ * fetch mocking. Missing file → no handlers (packages without mocks keep
4
+ * native workerd fetch). Never imported into published package bundles.
5
+ */
6
+ import * as esbuild from 'esbuild';
7
+ import { access, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
8
+ import { createRequire } from 'node:module';
9
+ import { tmpdir } from 'node:os';
10
+ import { join } from 'node:path';
11
+ import { pathToFileURL } from 'node:url';
12
+ import { StructuredCliError } from '../structured-error.js';
13
+ const requireFromCli = createRequire(import.meta.url);
14
+ export const packageMocksRelativePath = '.kody/mocks.ts';
15
+ export async function resolvePackageMocksPath(packageRoot) {
16
+ const path = join(packageRoot, packageMocksRelativePath);
17
+ try {
18
+ await access(path);
19
+ return path;
20
+ }
21
+ catch {
22
+ return null;
23
+ }
24
+ }
25
+ /**
26
+ * Bundle and evaluate `.kody/mocks.ts`. Expects `export const handlers = […]`
27
+ * (MSW `http.*` handlers) or a default export of that array.
28
+ */
29
+ export async function loadPackageMocks(packageRoot) {
30
+ const path = await resolvePackageMocksPath(packageRoot);
31
+ if (!path)
32
+ return null;
33
+ const workDir = await mkdtemp(join(tmpdir(), 'kody-mocks-'));
34
+ const outfile = join(workDir, 'mocks.mjs');
35
+ try {
36
+ const mswHref = pathToFileURL(requireFromCli.resolve('msw')).href;
37
+ let result;
38
+ try {
39
+ result = await esbuild.build({
40
+ entryPoints: [path],
41
+ bundle: true,
42
+ platform: 'node',
43
+ format: 'esm',
44
+ target: 'node22',
45
+ outfile,
46
+ write: true,
47
+ logLevel: 'silent',
48
+ // Leave MSW external; rewrite the import to the CLI-resolved absolute URL.
49
+ external: ['msw', 'msw/*'],
50
+ });
51
+ }
52
+ catch (error) {
53
+ const messages = error && typeof error === 'object' && 'errors' in error
54
+ ? error.errors.map((item) => item.text)
55
+ : [error instanceof Error ? error.message : String(error)];
56
+ throw new StructuredCliError({
57
+ code: 'bundle_failed',
58
+ message: `Could not bundle ${packageMocksRelativePath} for --target mock.`,
59
+ target: 'mock',
60
+ where: path,
61
+ fix: 'Fix TypeScript/syntax errors in .kody/mocks.ts and retry. Import handlers from `msw` (provided by @kodycodes/cli).',
62
+ details: { errors: messages },
63
+ });
64
+ }
65
+ if (result.errors.length > 0) {
66
+ throw new StructuredCliError({
67
+ code: 'bundle_failed',
68
+ message: `Could not bundle ${packageMocksRelativePath} for --target mock.`,
69
+ target: 'mock',
70
+ where: path,
71
+ fix: 'Fix TypeScript/syntax errors in .kody/mocks.ts and retry.',
72
+ details: {
73
+ errors: result.errors.map((error) => error.text),
74
+ },
75
+ });
76
+ }
77
+ const bundled = await readFile(outfile, 'utf8');
78
+ const rewritten = bundled.replace(/(from\s*|import\s*\(|require\s*\()\s*(['"])msw\2/g, (_match, prefix, quote) => `${prefix}${quote}${mswHref}${quote}`);
79
+ await writeFile(outfile, rewritten);
80
+ const mod = (await import(pathToFileURL(outfile).href));
81
+ const raw = mod.handlers ?? mod.default;
82
+ if (!Array.isArray(raw)) {
83
+ throw new StructuredCliError({
84
+ code: 'package_manifest_invalid',
85
+ message: `${packageMocksRelativePath} must export \`handlers\` (or default) as an array of MSW http handlers.`,
86
+ target: 'mock',
87
+ where: path,
88
+ fix: `export const handlers = [http.get('https://api.example.com/…', () => HttpResponse.json({ ok: true }))]`,
89
+ });
90
+ }
91
+ return { path, handlers: raw };
92
+ }
93
+ catch (error) {
94
+ if (error instanceof StructuredCliError)
95
+ throw error;
96
+ throw new StructuredCliError({
97
+ code: 'bundle_failed',
98
+ message: `Could not load ${packageMocksRelativePath}.`,
99
+ target: 'mock',
100
+ where: path,
101
+ fix: 'Ensure the file exports MSW handlers and that `msw` is resolvable from the package (or rely on the CLI’s dependency).',
102
+ details: {
103
+ cause: error instanceof Error ? error.message : String(error),
104
+ },
105
+ });
106
+ }
107
+ finally {
108
+ await rm(workDir, { recursive: true, force: true });
109
+ }
110
+ }
111
+ /** Write a tiny helper so tests can assert the relative path without importing fs. */
112
+ export function packageMocksPathFor(packageRoot) {
113
+ return join(packageRoot, packageMocksRelativePath);
114
+ }
115
+ //# sourceMappingURL=load-package-mocks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-package-mocks.js","sourceRoot":"","sources":["../../src/mock/load-package-mocks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Node-side mock outbound fetch gateway: match MSW handlers from
3
+ * `.kody/mocks.ts`, optionally passthrough allowlisted hosts to real network,
4
+ * otherwise fail closed with `unmocked_request` + a paste-ready handler stub.
5
+ */
6
+ import { type RequestHandler } from 'msw';
7
+ import { StructuredCliError } from '../structured-error.js';
8
+ import type { KodyTarget } from '../target.js';
9
+ export type MockGatewayFetchRequest = {
10
+ url?: string;
11
+ method?: string;
12
+ headers?: Record<string, string>;
13
+ bodyBase64?: string;
14
+ };
15
+ export type MockGatewayFetchResult = {
16
+ status: number;
17
+ statusText: string;
18
+ headers: Record<string, string>;
19
+ bodyBase64: string;
20
+ };
21
+ export type MockFetchGateway = {
22
+ /** True when `.kody/mocks.ts` loaded (shim should be injected). */
23
+ enabled: boolean;
24
+ handlers: ReadonlyArray<RequestHandler>;
25
+ passthroughHosts: ReadonlyArray<string>;
26
+ allowPrivateNetwork: boolean;
27
+ handle: (args: unknown, signal?: AbortSignal) => Promise<MockGatewayFetchResult>;
28
+ };
29
+ export declare function parsePassthroughHosts(raw: string | undefined): Array<string>;
30
+ export declare function createMockFetchGateway(input: {
31
+ handlers: ReadonlyArray<RequestHandler>;
32
+ passthroughHosts?: ReadonlyArray<string>;
33
+ allowPrivateNetwork?: boolean;
34
+ fetchFn?: typeof fetch;
35
+ }): MockFetchGateway;
36
+ export declare function dispatchMockGatewayFetch(input: {
37
+ handlers: ReadonlyArray<RequestHandler>;
38
+ passthroughHosts: ReadonlyArray<string>;
39
+ allowPrivateNetwork: boolean;
40
+ request: MockGatewayFetchRequest;
41
+ fetchFn?: typeof fetch;
42
+ signal?: AbortSignal;
43
+ }): Promise<MockGatewayFetchResult>;
44
+ export declare function hostMatchesPassthrough(hostname: string, hosts: ReadonlyArray<string>): boolean;
45
+ export declare function unmockedRequestError(method: string, url: string): StructuredCliError;
46
+ export declare function buildHandlerStub(method: string, url: string): string;
47
+ /** Bridge interceptor: handle `kody.gatewayFetch` when a mock gateway is active. */
48
+ export declare function tryHandleMockGatewayFetchCall(input: {
49
+ gateway: MockFetchGateway | undefined;
50
+ path: ReadonlyArray<string>;
51
+ args: ReadonlyArray<unknown>;
52
+ signal?: AbortSignal;
53
+ }): Promise<MockGatewayFetchResult> | null;
54
+ /**
55
+ * Load `.kody/mocks.ts` only for `--target mock` when the file exists.
56
+ * Packages without the file keep native workerd fetch (no shim).
57
+ */
58
+ export declare function resolveMockFetchGateway(input: {
59
+ target: KodyTarget;
60
+ packageRoot?: string;
61
+ passthroughHosts?: ReadonlyArray<string>;
62
+ allowPrivateNetwork?: boolean;
63
+ onStatus?: (message: string) => void;
64
+ }): Promise<MockFetchGateway | undefined>;
@@ -0,0 +1,242 @@
1
+ /**
2
+ * Node-side mock outbound fetch gateway: match MSW handlers from
3
+ * `.kody/mocks.ts`, optionally passthrough allowlisted hosts to real network,
4
+ * otherwise fail closed with `unmocked_request` + a paste-ready handler stub.
5
+ */
6
+ import { getResponse, isPassthroughResponse } from 'msw';
7
+ import { StructuredCliError } from '../structured-error.js';
8
+ import { loadPackageMocks } from './load-package-mocks.js';
9
+ export function parsePassthroughHosts(raw) {
10
+ if (!raw?.trim())
11
+ return [];
12
+ return [
13
+ ...new Set(raw
14
+ .split(',')
15
+ .map((part) => part.trim().toLowerCase())
16
+ .filter(Boolean)),
17
+ ];
18
+ }
19
+ export function createMockFetchGateway(input) {
20
+ const passthroughHosts = input.passthroughHosts ?? [];
21
+ const allowPrivateNetwork = input.allowPrivateNetwork === true;
22
+ const fetchFn = input.fetchFn ?? fetch;
23
+ return {
24
+ enabled: true,
25
+ handlers: input.handlers,
26
+ passthroughHosts,
27
+ allowPrivateNetwork,
28
+ handle: async (args, signal) => {
29
+ const request = readGatewayRequest(args);
30
+ return await dispatchMockGatewayFetch({
31
+ handlers: input.handlers,
32
+ passthroughHosts,
33
+ allowPrivateNetwork,
34
+ request,
35
+ fetchFn,
36
+ signal,
37
+ });
38
+ },
39
+ };
40
+ }
41
+ export async function dispatchMockGatewayFetch(input) {
42
+ const method = (input.request.method ?? 'GET').toUpperCase();
43
+ const url = String(input.request.url ?? '');
44
+ if (!url) {
45
+ throw new StructuredCliError({
46
+ code: 'unmocked_request',
47
+ message: 'Mock gatewayFetch requires request.url.',
48
+ target: 'mock',
49
+ fix: 'Pass an absolute URL from ambient fetch.',
50
+ });
51
+ }
52
+ let parsed;
53
+ try {
54
+ parsed = new URL(url);
55
+ }
56
+ catch {
57
+ throw new StructuredCliError({
58
+ code: 'unmocked_request',
59
+ message: `Mock gatewayFetch URL is not absolute: ${JSON.stringify(url)}.`,
60
+ target: 'mock',
61
+ where: `${method} ${url}`,
62
+ fix: 'Use an absolute https:// URL in package code under --target mock.',
63
+ });
64
+ }
65
+ if (hostMatchesPassthrough(parsed.hostname, input.passthroughHosts)) {
66
+ assertPassthroughAllowed(parsed, input.allowPrivateNetwork);
67
+ return await realNetworkFetch({
68
+ request: input.request,
69
+ method,
70
+ url: parsed.href,
71
+ fetchFn: input.fetchFn ?? fetch,
72
+ signal: input.signal,
73
+ });
74
+ }
75
+ const headers = new Headers(input.request.headers ?? {});
76
+ const body = input.request.bodyBase64 != null && input.request.bodyBase64 !== ''
77
+ ? Buffer.from(input.request.bodyBase64, 'base64')
78
+ : undefined;
79
+ const requestInit = {
80
+ method,
81
+ headers,
82
+ ...(body !== undefined && method !== 'GET' && method !== 'HEAD'
83
+ ? { body }
84
+ : {}),
85
+ signal: input.signal,
86
+ };
87
+ const request = new Request(parsed.href, requestInit);
88
+ const response = await getResponse([...input.handlers], request);
89
+ if (!response || isPassthroughResponse(response)) {
90
+ throw unmockedRequestError(method, parsed.href);
91
+ }
92
+ return await serializeResponse(response);
93
+ }
94
+ function readGatewayRequest(args) {
95
+ const record = args && typeof args === 'object' && !Array.isArray(args)
96
+ ? args
97
+ : {};
98
+ const nested = record.request && typeof record.request === 'object' && !Array.isArray(record.request)
99
+ ? record.request
100
+ : record;
101
+ return {
102
+ url: typeof nested.url === 'string' ? nested.url : undefined,
103
+ method: typeof nested.method === 'string' ? nested.method : undefined,
104
+ headers: nested.headers && typeof nested.headers === 'object' && !Array.isArray(nested.headers)
105
+ ? nested.headers
106
+ : undefined,
107
+ bodyBase64: typeof nested.bodyBase64 === 'string' ? nested.bodyBase64 : undefined,
108
+ };
109
+ }
110
+ export function hostMatchesPassthrough(hostname, hosts) {
111
+ const target = hostname.toLowerCase();
112
+ return hosts.some((entry) => {
113
+ const normalized = entry.trim().toLowerCase();
114
+ if (!normalized)
115
+ return false;
116
+ if (normalized.startsWith('*.')) {
117
+ const suffix = normalized.slice(1);
118
+ return target.endsWith(suffix) && target.length > suffix.length;
119
+ }
120
+ return target === normalized;
121
+ });
122
+ }
123
+ function assertPassthroughAllowed(url, allowPrivateNetwork) {
124
+ if (allowPrivateNetwork)
125
+ return;
126
+ if (url.protocol !== 'http:' && url.protocol !== 'https:') {
127
+ throw new StructuredCliError({
128
+ code: 'unmocked_request',
129
+ message: `Passthrough refused for non-http(s) URL ${url.href}.`,
130
+ target: 'mock',
131
+ where: url.href,
132
+ });
133
+ }
134
+ const host = url.hostname.toLowerCase();
135
+ const privateHost = host === 'localhost' ||
136
+ host === '127.0.0.1' ||
137
+ host === '::1' ||
138
+ host === '[::1]' ||
139
+ host.endsWith('.local') ||
140
+ /^10\./.test(host) ||
141
+ /^192\.168\./.test(host) ||
142
+ /^172\.(1[6-9]|2\d|3[0-1])\./.test(host);
143
+ if (privateHost) {
144
+ throw new StructuredCliError({
145
+ code: 'unmocked_request',
146
+ message: `Passthrough to private/local host ${JSON.stringify(host)} requires --allow-private-network.`,
147
+ target: 'mock',
148
+ where: url.href,
149
+ fix: 'Add --allow-private-network, or mock this host in .kody/mocks.ts instead of --passthrough.',
150
+ });
151
+ }
152
+ }
153
+ async function realNetworkFetch(input) {
154
+ const headers = new Headers(input.request.headers ?? {});
155
+ // Credentials stay fake on mock — never forward opaque credential handles
156
+ // or Authorization that would look like a real secret placement.
157
+ headers.delete('x-kody-credential-client');
158
+ const body = input.request.bodyBase64 != null && input.request.bodyBase64 !== ''
159
+ ? Buffer.from(input.request.bodyBase64, 'base64')
160
+ : undefined;
161
+ const response = await input.fetchFn(input.url, {
162
+ method: input.method,
163
+ headers,
164
+ ...(body !== undefined && input.method !== 'GET' && input.method !== 'HEAD'
165
+ ? { body }
166
+ : {}),
167
+ signal: input.signal,
168
+ redirect: 'manual',
169
+ });
170
+ return await serializeResponse(response);
171
+ }
172
+ async function serializeResponse(response) {
173
+ const bytes = new Uint8Array(await response.arrayBuffer());
174
+ return {
175
+ status: response.status,
176
+ statusText: response.statusText,
177
+ headers: Object.fromEntries(response.headers.entries()),
178
+ bodyBase64: Buffer.from(bytes).toString('base64'),
179
+ };
180
+ }
181
+ export function unmockedRequestError(method, url) {
182
+ const stub = buildHandlerStub(method, url);
183
+ return new StructuredCliError({
184
+ code: 'unmocked_request',
185
+ message: `Unmocked ${method} ${url} under --target mock.`,
186
+ target: 'mock',
187
+ where: `${method} ${url}`,
188
+ fix: `Add a handler in .kody/mocks.ts (or pass --passthrough ${safeHost(url)} for real network without secrets):\n\n${stub}`,
189
+ details: { method, url, handlerStub: stub },
190
+ });
191
+ }
192
+ export function buildHandlerStub(method, url) {
193
+ const verb = method.toLowerCase();
194
+ const httpMethod = ['get', 'post', 'put', 'patch', 'delete', 'options', 'head'].includes(verb)
195
+ ? verb
196
+ : 'all';
197
+ return [
198
+ `import { http, HttpResponse } from 'msw'`,
199
+ ``,
200
+ `export const handlers = [`,
201
+ ` http.${httpMethod}(${JSON.stringify(url)}, () =>`,
202
+ ` HttpResponse.json({ /* TODO */ }, { status: 200 }),`,
203
+ ` ),`,
204
+ `]`,
205
+ ].join('\n');
206
+ }
207
+ function safeHost(url) {
208
+ try {
209
+ return new URL(url).hostname;
210
+ }
211
+ catch {
212
+ return 'example.com';
213
+ }
214
+ }
215
+ /** Bridge interceptor: handle `kody.gatewayFetch` when a mock gateway is active. */
216
+ export function tryHandleMockGatewayFetchCall(input) {
217
+ if (!input.gateway?.enabled)
218
+ return null;
219
+ if (input.path.join('.') !== 'kody.gatewayFetch')
220
+ return null;
221
+ return input.gateway.handle(input.args[0], input.signal);
222
+ }
223
+ /**
224
+ * Load `.kody/mocks.ts` only for `--target mock` when the file exists.
225
+ * Packages without the file keep native workerd fetch (no shim).
226
+ */
227
+ export async function resolveMockFetchGateway(input) {
228
+ if (input.target !== 'mock')
229
+ return undefined;
230
+ if (!input.packageRoot)
231
+ return undefined;
232
+ const loaded = await loadPackageMocks(input.packageRoot);
233
+ if (!loaded)
234
+ return undefined;
235
+ input.onStatus?.(`Loaded ${loaded.handlers.length} MSW handler${loaded.handlers.length === 1 ? '' : 's'} from .kody/mocks.ts (outbound fetch fail-closed on mock).`);
236
+ return createMockFetchGateway({
237
+ handlers: loaded.handlers,
238
+ passthroughHosts: input.passthroughHosts,
239
+ allowPrivateNetwork: input.allowPrivateNetwork,
240
+ });
241
+ }
242
+ //# sourceMappingURL=mock-fetch-gateway.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-fetch-gateway.js","sourceRoot":"","sources":["../../src/mock/mock-fetch-gateway.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Mock-only workerd side-effect module (flat name
3
+ * `.__kody_mock_gateway_fetch__.js` — see install-mock-fetch-shim.ts).
4
+ * Wraps ambient `fetch` so every outbound request hops through the Node bridge
5
+ * as `kody.gatewayFetch` (MSW matching / passthrough / unmocked_request).
6
+ * Origin's `.__kody_virtual__/runtime.js` stays for CAF / packageStorage.
7
+ */
8
+ /**
9
+ * Source for the CLI-owned mock gateway-fetch shim. Side-effect imported before
10
+ * user code; fetch calls happen after `__kodyInstallLocalBridge`.
11
+ *
12
+ * Registered under a flat module name so bare `"kody:runtime"` resolves to the
13
+ * host module (path-like names like `.__kody_virtual__/runtime.js` path-join).
14
+ */
15
+ export declare function createMockGatewayFetchShimSource(): string;
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Mock-only workerd side-effect module (flat name
3
+ * `.__kody_mock_gateway_fetch__.js` — see install-mock-fetch-shim.ts).
4
+ * Wraps ambient `fetch` so every outbound request hops through the Node bridge
5
+ * as `kody.gatewayFetch` (MSW matching / passthrough / unmocked_request).
6
+ * Origin's `.__kody_virtual__/runtime.js` stays for CAF / packageStorage.
7
+ */
8
+ import { localWorkerModuleNames } from '../local-runtime-source.js';
9
+ /**
10
+ * Source for the CLI-owned mock gateway-fetch shim. Side-effect imported before
11
+ * user code; fetch calls happen after `__kodyInstallLocalBridge`.
12
+ *
13
+ * Registered under a flat module name so bare `"kody:runtime"` resolves to the
14
+ * host module (path-like names like `.__kody_virtual__/runtime.js` path-join).
15
+ */
16
+ export function createMockGatewayFetchShimSource() {
17
+ return `
18
+ import { kody } from ${JSON.stringify(localWorkerModuleNames.runtime)};
19
+
20
+ const __kodyNativeFetch = globalThis.fetch.bind(globalThis);
21
+ const __kodyNullBodyStatuses = new Set([101, 103, 204, 205, 304]);
22
+
23
+ function __kodyBytesToBase64(bytes) {
24
+ let binary = '';
25
+ for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
26
+ return btoa(binary);
27
+ }
28
+
29
+ function __kodyBase64ToBytes(value) {
30
+ const binary = atob(String(value ?? ''));
31
+ const bytes = new Uint8Array(binary.length);
32
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
33
+ return bytes;
34
+ }
35
+
36
+ async function __kodyBodyToBytes(body) {
37
+ if (body == null) return null;
38
+ if (typeof body === 'string') return new TextEncoder().encode(body);
39
+ if (body instanceof Uint8Array) return body;
40
+ if (body instanceof ArrayBuffer) return new Uint8Array(body);
41
+ if (ArrayBuffer.isView(body)) {
42
+ return new Uint8Array(body.buffer, body.byteOffset, body.byteLength);
43
+ }
44
+ if (typeof Blob !== 'undefined' && body instanceof Blob) {
45
+ return new Uint8Array(await body.arrayBuffer());
46
+ }
47
+ if (typeof URLSearchParams !== 'undefined' && body instanceof URLSearchParams) {
48
+ return new TextEncoder().encode(body.toString());
49
+ }
50
+ if (body && typeof body.getReader === 'function') {
51
+ return new Uint8Array(await new Response(body).arrayBuffer());
52
+ }
53
+ if (typeof FormData !== 'undefined' && body instanceof FormData) {
54
+ throw new Error(
55
+ 'Mock fetch gateway does not support FormData bodies yet; use Uint8Array, Blob, or string.',
56
+ );
57
+ }
58
+ throw new Error('Mock fetch gateway could not serialize the request body.');
59
+ }
60
+
61
+ globalThis.fetch = async (input, init) => {
62
+ let url;
63
+ let method = 'GET';
64
+ let headers = {};
65
+ let bodyBytes = null;
66
+ if (typeof input === 'string' || input instanceof URL) {
67
+ url = String(input);
68
+ method = String(init?.method ?? 'GET');
69
+ headers = Object.fromEntries(new Headers(init?.headers).entries());
70
+ if (init?.body != null) bodyBytes = await __kodyBodyToBytes(init.body);
71
+ } else {
72
+ const merged = new Request(input, init);
73
+ url = merged.url;
74
+ method = merged.method;
75
+ headers = Object.fromEntries(merged.headers.entries());
76
+ if (method !== 'GET' && method !== 'HEAD') {
77
+ bodyBytes = new Uint8Array(await merged.arrayBuffer());
78
+ }
79
+ }
80
+ const result = await kody.gatewayFetch({
81
+ request: {
82
+ url,
83
+ method,
84
+ headers,
85
+ ...(bodyBytes != null ? { bodyBase64: __kodyBytesToBase64(bodyBytes) } : {}),
86
+ },
87
+ });
88
+ const bytes = __kodyBase64ToBytes(result.bodyBase64 ?? '');
89
+ return new Response(
90
+ __kodyNullBodyStatuses.has(result.status) ? null : bytes,
91
+ {
92
+ status: result.status,
93
+ statusText: result.statusText ?? '',
94
+ headers: result.headers ?? {},
95
+ },
96
+ );
97
+ };
98
+
99
+ // Retain a reference so workerd keeps the binding available for debugging.
100
+ void __kodyNativeFetch;
101
+ export {};
102
+ `.trimStart();
103
+ }
104
+ //# sourceMappingURL=mock-gateway-fetch-shim.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-gateway-fetch-shim.js","sourceRoot":"","sources":["../../src/mock/mock-gateway-fetch-shim.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAA;AAEnE;;;;;;GAMG;AACH,MAAM,UAAU,gCAAgC;IAC/C,OAAO;uBACe,IAAI,CAAC,SAAS,CAAC,sBAAsB,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoFpE,CAAC,SAAS,EAAE,CAAA;AACb,CAAC"}