counterfact 1.4.4 → 1.4.6

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.
@@ -3,6 +3,22 @@ import koaProxy from "koa-proxies";
3
3
  import { isProxyEnabledForPath } from "./is-proxy-enabled-for-path.js";
4
4
  const debug = createDebug("counterfact:server:create-koa-app");
5
5
  const HTTP_STATUS_CODE_OK = 200;
6
+ const HEADERS_TO_DROP = new Set([
7
+ // body may not be gzip anymore
8
+ "content-encoding",
9
+ // length can change when Koa serializes
10
+ "content-length",
11
+ // hop-by-hop
12
+ "transfer-encoding",
13
+ "connection",
14
+ "keep-alive",
15
+ "upgrade",
16
+ "proxy-authenticate",
17
+ "proxy-authorization",
18
+ "te",
19
+ "trailer",
20
+ "trailers",
21
+ ]);
6
22
  function addCors(ctx, headers) {
7
23
  // Always append CORS headers, reflecting back the headers requested if any
8
24
  ctx.set("Access-Control-Allow-Origin", headers?.origin ?? "*");
@@ -58,7 +74,9 @@ export function koaMiddleware(dispatcher, config, proxy = koaProxy) {
58
74
  ctx.body = response.body;
59
75
  if (response.headers) {
60
76
  for (const [key, value] of Object.entries(response.headers)) {
61
- ctx.set(key, value.toString());
77
+ if (!HEADERS_TO_DROP.has(key.toLowerCase())) {
78
+ ctx.set(key, value.toString());
79
+ }
62
80
  }
63
81
  }
64
82
  ctx.status = response.status ?? HTTP_STATUS_CODE_OK;
@@ -12,6 +12,7 @@ import { ModuleDependencyGraph } from "./module-dependency-graph.js";
12
12
  import { uncachedImport } from "./uncached-import.js";
13
13
  const { uncachedRequire } = await import("./uncached-require.cjs");
14
14
  const debug = createDebug("counterfact:server:module-loader");
15
+ import { escapePathForWindows, unescapePathForWindows, } from "../util/windows-escape.js";
15
16
  function isContextModule(module) {
16
17
  return "Context" in module && typeof module.Context === "function";
17
18
  }
@@ -49,9 +50,9 @@ export class ModuleLoader extends EventTarget {
49
50
  return;
50
51
  }
51
52
  const parts = nodePath.parse(pathName.replace(this.basePath, ""));
52
- const url = `/${parts.dir}/${parts.name}`
53
+ const url = unescapePathForWindows(`/${parts.dir}/${parts.name}`
53
54
  .replaceAll("\\", "/")
54
- .replaceAll(/\/+/gu, "/");
55
+ .replaceAll(/\/+/gu, "/"));
55
56
  if (eventName === "unlink") {
56
57
  this.registry.remove(url);
57
58
  this.dispatchEvent(new Event("remove"));
@@ -86,16 +87,17 @@ export class ModuleLoader extends EventTarget {
86
87
  const fullPath = nodePath
87
88
  .join(this.basePath, directory, file.name)
88
89
  .replaceAll("\\", "/");
89
- await this.loadEndpoint(fullPath);
90
+ await this.loadEndpoint(escapePathForWindows(fullPath));
90
91
  });
91
92
  await Promise.all(imports);
92
93
  }
93
94
  async loadEndpoint(pathName) {
94
95
  debug("importing module: %s", pathName);
95
96
  const directory = dirname(pathName.slice(this.basePath.length)).replaceAll("\\", "/");
96
- const url = `/${nodePath.join(directory, nodePath.parse(basename(pathName)).name)}`
97
+ const url = unescapePathForWindows(`/${nodePath.join(directory, nodePath.parse(basename(pathName)).name)}`
97
98
  .replaceAll("\\", "/")
98
- .replaceAll(/\/+/gu, "/");
99
+ .replaceAll(/\/+/gu, "/"));
100
+ debug(`loading pathName from dependencyGraph: ${pathName}`);
99
101
  this.dependencyGraph.load(pathName);
100
102
  try {
101
103
  const doImport = (await determineModuleKind(pathName)) === "commonjs"
@@ -121,6 +123,7 @@ export class ModuleLoader extends EventTarget {
121
123
  }
122
124
  if (url === "/index")
123
125
  this.registry.add("/", endpoint);
126
+ debug(`adding "${url}" to registry`);
124
127
  this.registry.add(url, endpoint);
125
128
  }
126
129
  catch (error) {
@@ -57,6 +57,7 @@ export class Registry {
57
57
  debug("handler for %s: %o", url, handler);
58
58
  const execute = handler.module?.[httpRequestMethod];
59
59
  if (!execute) {
60
+ debug(`Could not find a ${httpRequestMethod} method matching ${url}\n`);
60
61
  return () => ({
61
62
  body: `Could not find a ${httpRequestMethod} method matching ${url}\n`,
62
63
  contentType: "text/plain",
@@ -7,6 +7,7 @@ import createDebug from "debug";
7
7
  import { ensureDirectoryExists } from "../util/ensure-directory-exists.js";
8
8
  import { CONTEXT_FILE_TOKEN } from "./context-file-token.js";
9
9
  import { Script } from "./script.js";
10
+ import { escapePathForWindows } from "../util/windows-escape.js";
10
11
  const debug = createDebug("counterfact:server:repository");
11
12
  const __dirname = dirname(fileURLToPath(import.meta.url)).replaceAll("\\", "/");
12
13
  debug("dirname is %s", __dirname);
@@ -46,7 +47,7 @@ export class Repository {
46
47
  debug("all %i scripts are finished", this.scripts.size);
47
48
  const writeFiles = Array.from(this.scripts.entries(), async ([path, script]) => {
48
49
  const contents = await script.contents();
49
- const fullPath = nodePath.join(destination, path).replaceAll("\\", "/");
50
+ const fullPath = escapePathForWindows(nodePath.join(destination, path).replaceAll("\\", "/"));
50
51
  await ensureDirectoryExists(fullPath);
51
52
  const shouldWriteRoutes = routes && path.startsWith("routes");
52
53
  const shouldWriteTypes = types && !path.startsWith("routes");
@@ -0,0 +1,12 @@
1
+ const UNICODE_RATIO_SYMBOL = "∶"; // U+2236
2
+ const REGULAR_COLON = ":";
3
+ export function escapePathForWindows(path) {
4
+ if (path.at(1) === ":") {
5
+ return (path.slice(0, 2) +
6
+ path.slice(2).replaceAll(REGULAR_COLON, UNICODE_RATIO_SYMBOL));
7
+ }
8
+ return path.replaceAll(REGULAR_COLON, UNICODE_RATIO_SYMBOL);
9
+ }
10
+ export function unescapePathForWindows(path) {
11
+ return path.replaceAll(UNICODE_RATIO_SYMBOL, REGULAR_COLON);
12
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "counterfact",
3
- "version": "1.4.4",
3
+ "version": "1.4.6",
4
4
  "description": "a library for building a fake REST API for testing",
5
5
  "type": "module",
6
6
  "main": "./dist/app.js",
@@ -73,7 +73,7 @@
73
73
  "eslint-plugin-prettier": "5.5.4",
74
74
  "eslint-plugin-unused-imports": "4.2.0",
75
75
  "husky": "9.1.7",
76
- "jest": "30.1.2",
76
+ "jest": "30.1.3",
77
77
  "jest-retries": "1.0.1",
78
78
  "node-mocks-http": "1.17.2",
79
79
  "rimraf": "6.0.1",