@interopio/gateway-server 0.8.1-beta.2 → 0.9.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/changelog.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  # Change Log
4
4
 
5
+ ## 0.9.0-beta.0 (2025-09-02)
6
+
7
+ ### Added
8
+ - allow disabling cors protocol handling via config
9
+
10
+ ### Fixed
11
+ - cors config source autoconfiguration (match only by path to properly handle preflight requests)
12
+
5
13
  ## 0.8.1-beta.2 (2025-08-27)
6
14
 
7
15
  ### Changed
package/dist/index.cjs CHANGED
@@ -44,7 +44,7 @@ var import_node_http2 = __toESM(require("node:http"), 1);
44
44
  var import_node_https = __toESM(require("node:https"), 1);
45
45
  var import_node_fs = require("node:fs");
46
46
  var import_node_async_hooks4 = require("node:async_hooks");
47
- var import_gateway6 = require("@interopio/gateway");
47
+ var import_gateway7 = require("@interopio/gateway");
48
48
 
49
49
  // src/logger.ts
50
50
  var import_gateway = require("@interopio/gateway");
@@ -1402,14 +1402,15 @@ upgradeMatcher.toString = () => "websocket upgrade";
1402
1402
  // src/app/route.ts
1403
1403
  var import_gateway4 = require("@interopio/gateway");
1404
1404
  async function configure(app, config, routes) {
1405
- const applyCors = (matcher, requestMethod, options) => {
1405
+ const applyCors = (request, options) => {
1406
1406
  if (options?.cors) {
1407
1407
  const cors = options.cors === true ? {
1408
1408
  allowOrigins: options.origins?.allow?.map(import_gateway4.IOGateway.Filtering.regexify),
1409
- allowMethods: requestMethod == void 0 ? void 0 : [requestMethod],
1410
- allowCredentials: options.authorize?.access !== "permitted"
1409
+ allowMethods: request.method === void 0 ? ["*"] : [request.method],
1410
+ allowCredentials: options.authorize?.access !== "permitted" ? true : void 0
1411
1411
  } : options.cors;
1412
- routes.cors.push([matcher, cors]);
1412
+ const path = request.path;
1413
+ routes.cors.push([path, cors]);
1413
1414
  }
1414
1415
  };
1415
1416
  const configurer = new class {
@@ -1419,7 +1420,7 @@ async function configure(app, config, routes) {
1419
1420
  if (options?.authorize) {
1420
1421
  routes.authorize.push([matcher, options.authorize]);
1421
1422
  }
1422
- applyCors(matcher, request.method, options);
1423
+ applyCors(request, options);
1423
1424
  const middleware = async (exchange, next) => {
1424
1425
  const { match: match2, variables } = await matcher(exchange);
1425
1426
  if (match2) {
@@ -1752,210 +1753,62 @@ var matchingCorsConfigSource = (opts) => {
1752
1753
  };
1753
1754
  };
1754
1755
 
1755
- // src/mock/server/exchange.ts
1756
- var import_web = __toESM(require("node:stream/web"), 1);
1757
- var MockServerHttpRequest = class extends AbstractHttpRequest {
1758
- #url;
1759
- #body;
1760
- upgrade = false;
1761
- constructor(url, method) {
1762
- super(new MapHttpHeaders());
1763
- if (typeof url === "string") {
1764
- if (URL.canParse(url)) {
1765
- url = new URL(url);
1766
- } else if (URL.canParse(url, "http://localhost")) {
1767
- url = new URL(url, "http://localhost");
1768
- } else {
1769
- throw new TypeError("URL cannot parse url");
1770
- }
1771
- }
1772
- this.#url = url;
1773
- this.method = method ?? "GET";
1774
- this.setHeader("Host", this.#url.hostname);
1775
- this.path = this.#url.pathname ?? "/";
1776
- }
1777
- method;
1778
- path;
1779
- get host() {
1780
- return super.parseHost(this.#url.host);
1781
- }
1782
- get protocol() {
1783
- return super.parseProtocol(this.#url.protocol.slice(0, -1));
1784
- }
1785
- get body() {
1786
- if (this.#body !== void 0) {
1787
- const blob = this.#body;
1788
- const asyncIterator = async function* () {
1789
- const bytes = await blob.bytes();
1790
- yield bytes;
1791
- }();
1792
- return import_web.default.ReadableStream.from(asyncIterator);
1793
- }
1794
- }
1795
- blob() {
1796
- const body = this.#body;
1797
- return body ? Promise.resolve(body) : Promise.reject(new Error(`no body set`));
1798
- }
1799
- async text() {
1800
- const blob = await this.blob();
1801
- return await blob.text();
1802
- }
1803
- async formData() {
1804
- const blob = await this.blob();
1805
- const text = await blob.text();
1806
- return new URLSearchParams(text);
1807
- }
1808
- async json() {
1809
- const blob = await this.blob();
1810
- if (blob.size === 0) {
1811
- return void 0;
1812
- }
1813
- const text = await blob.text();
1814
- return JSON.parse(text);
1815
- }
1816
- async writeBody(body) {
1817
- if (body === void 0) {
1818
- this.#body = new Blob([]);
1819
- return;
1820
- }
1821
- if (body instanceof ReadableStream) {
1822
- const chunks = [];
1823
- const reader = body.getReader();
1824
- let done = false;
1825
- while (!done) {
1826
- const { value, done: readDone } = await reader.read();
1827
- if (readDone) {
1828
- done = true;
1829
- } else {
1830
- chunks.push(value);
1831
- }
1832
- }
1833
- this.#body = new Blob(chunks);
1834
- } else {
1835
- body = await body;
1836
- if (typeof body === "string") {
1837
- this.#body = new Blob([body], { type: "text/plain" });
1838
- } else {
1839
- this.#body = new Blob([body]);
1840
- }
1841
- }
1842
- if (!this.headers.has("content-type")) {
1843
- this.setHeader("Content-Type", this.#body.type || "application/octet-stream");
1844
- }
1845
- }
1846
- get URL() {
1847
- return new URL(this.path + this.#url.search + this.#url.hash, `${this.protocol}://${this.host}`);
1848
- }
1849
- addHeader(name, value) {
1850
- this.headers.add(name, value);
1851
- return this;
1852
- }
1853
- setHeader(name, value) {
1854
- this.headers.set(name, value);
1855
- return this;
1856
- }
1857
- };
1858
- var MockServerHttpResponse = class extends AbstractServerHttpResponse {
1859
- #writeHandler;
1860
- #body = () => {
1861
- throw new Error("No content was written to the response body nor end was called on this response.");
1862
- };
1863
- constructor() {
1864
- super(new MapHttpHeaders());
1865
- this.#writeHandler = async (body) => {
1866
- const chunks = [];
1867
- let bodyStream;
1868
- this.#body = () => {
1869
- bodyStream ??= import_web.default.ReadableStream.from(chunks);
1870
- return bodyStream;
1871
- };
1872
- const reader = body.getReader();
1873
- let done = false;
1874
- do {
1875
- const { value, done: readDone } = await reader.read();
1876
- if (readDone) {
1877
- done = true;
1878
- } else {
1879
- chunks.push(value);
1880
- }
1881
- } while (!done);
1882
- return true;
1883
- };
1884
- }
1885
- get statusCode() {
1886
- return super.statusCode;
1887
- }
1888
- set writeHandler(handler) {
1889
- this.#body = () => {
1890
- throw new Error("Not available with custom write handler");
1891
- };
1892
- this.#writeHandler = handler;
1893
- }
1894
- getNativeResponse() {
1895
- throw new Error("This is a mock. No running server, no native response.");
1896
- }
1897
- applyStatusCode() {
1898
- }
1899
- applyHeaders() {
1900
- }
1901
- applyCookies() {
1902
- for (const cookie of this.cookies) {
1903
- this.headers.add("Set-Cookie", super.setCookieValue(cookie));
1904
- }
1905
- }
1906
- bodyInternal(body) {
1907
- const it = async function* () {
1908
- const resolved = await body;
1909
- if (resolved === void 0) {
1910
- return;
1911
- }
1912
- yield resolved;
1913
- }();
1914
- return this.#writeHandler(import_web.default.ReadableStream.from(it));
1915
- }
1916
- async end() {
1917
- return this.doCommit(async () => {
1918
- return await new Promise((resolve, reject) => {
1919
- this.#writeHandler(import_web.default.ReadableStream.from([]));
1920
- });
1921
- });
1922
- }
1923
- getBody() {
1924
- return this.#body();
1925
- }
1926
- };
1927
-
1928
1756
  // src/app/cors.ts
1929
- function mockUpgradeExchange(path) {
1930
- const request = new MockServerHttpRequest(path, "GET");
1931
- request.setHeader("Upgrade", "websocket");
1932
- request.upgrade = true;
1933
- return new DefaultWebExchange(request, new MockServerHttpResponse());
1934
- }
1935
- async function createCorsConfigSource(context) {
1757
+ var import_gateway6 = require("@interopio/gateway");
1758
+ function createCorsConfigSource(context) {
1936
1759
  const { sockets: routes, cors } = context;
1937
- const defaultCorsConfig = combineCorsConfig(PERMIT_DEFAULT_CONFIG, context.corsConfig);
1760
+ const defaultCorsConfig = context.corsConfig === false ? void 0 : combineCorsConfig(PERMIT_DEFAULT_CONFIG, context.corsConfig);
1938
1761
  const validatedConfigs = [];
1939
1762
  for (const [path, route] of routes) {
1940
1763
  let routeCorsConfig = defaultCorsConfig;
1941
- const upgradeExchange = mockUpgradeExchange(path);
1942
- for (const [matcher, config] of cors) {
1943
- if ((await matcher(upgradeExchange)).match) {
1944
- routeCorsConfig = combineCorsConfig(routeCorsConfig, config);
1764
+ for (const [matcher, config2] of cors) {
1765
+ if (import_gateway6.IOGateway.Filtering.valueMatches(matcher, path)) {
1766
+ if (config2 === void 0) {
1767
+ routeCorsConfig = void 0;
1768
+ } else {
1769
+ routeCorsConfig = routeCorsConfig === void 0 ? config2 : combineCorsConfig(routeCorsConfig, config2);
1770
+ }
1945
1771
  }
1946
1772
  }
1947
- routeCorsConfig = combineCorsConfig(routeCorsConfig, {
1773
+ const config = context.corsConfig === false ? void 0 : {
1948
1774
  allowOrigins: route.originFilters?.allow,
1949
- allowMethods: ["GET", "CONNECT"],
1950
- allowHeaders: ["Upgrade", "Connection", "Origin", "Sec-Websocket-Key", "Sec-Websocket-Version", "Sec-Websocket-Protocol", "Sec-Websocket-Extensions"],
1775
+ allowMethods: ["GET", "CONNECT", "OPTIONS"],
1776
+ allowHeaders: [
1777
+ "Upgrade",
1778
+ "Connection",
1779
+ "Origin",
1780
+ "Sec-Websocket-Key",
1781
+ "Sec-Websocket-Version",
1782
+ "Sec-Websocket-Protocol",
1783
+ "Sec-Websocket-Extensions"
1784
+ ],
1951
1785
  exposeHeaders: ["Sec-Websocket-Accept", "Sec-Websocket-Protocol", "Sec-Websocket-Extensions"],
1952
- allowCredentials: route.authorize?.access !== "permitted"
1953
- });
1954
- validatedConfigs.push([and([upgradeMatcher, pattern(path)]), validateCorsConfig(routeCorsConfig)]);
1786
+ allowCredentials: route.authorize?.access !== "permitted" ? true : void 0
1787
+ };
1788
+ routeCorsConfig = routeCorsConfig === void 0 ? config : combineCorsConfig(routeCorsConfig, config);
1789
+ validatedConfigs.push([
1790
+ and([upgradeMatcher, pattern(path)]),
1791
+ validateCorsConfig(routeCorsConfig)
1792
+ ]);
1955
1793
  }
1794
+ const appConfigs = [];
1956
1795
  for (const [matcher, config] of cors) {
1957
- const routeCorsConfig = combineCorsConfig(defaultCorsConfig, config);
1958
- validatedConfigs.push([matcher, validateCorsConfig(routeCorsConfig)]);
1796
+ let [, routeCorsConfig] = appConfigs.find(([m]) => String(m) === String(matcher)) ?? [matcher, defaultCorsConfig];
1797
+ routeCorsConfig = routeCorsConfig === void 0 ? config : combineCorsConfig(routeCorsConfig, config);
1798
+ let added = false;
1799
+ for (const entry of appConfigs) {
1800
+ if (String(entry[0]) === String(matcher)) {
1801
+ entry[1] = routeCorsConfig;
1802
+ added = true;
1803
+ break;
1804
+ }
1805
+ }
1806
+ if (!added) {
1807
+ appConfigs.push([matcher, routeCorsConfig]);
1808
+ }
1809
+ }
1810
+ for (const [matcher, config] of appConfigs) {
1811
+ validatedConfigs.push([pattern(matcher), validateCorsConfig(config)]);
1959
1812
  }
1960
1813
  validatedConfigs.push([pattern(/\/api\/.*/), validateCorsConfig(defaultCorsConfig)]);
1961
1814
  return matchingCorsConfigSource({ mappings: validatedConfigs });
@@ -2926,6 +2779,9 @@ function createSecurityConfig(context) {
2926
2779
  authorize.push(["any-exchange", defaultAccess]);
2927
2780
  return {
2928
2781
  authorize,
2782
+ cors: {
2783
+ disabled: context.corsConfig === false
2784
+ },
2929
2785
  basic: {
2930
2786
  disabled: context.authConfig?.type !== "basic",
2931
2787
  ...context.authConfig?.basic
@@ -2937,7 +2793,7 @@ function createSecurityConfig(context) {
2937
2793
  };
2938
2794
  }
2939
2795
  async function httpSecurity(context) {
2940
- const corsConfigSource = await createCorsConfigSource(context);
2796
+ const corsConfigSource = createCorsConfigSource(context);
2941
2797
  const config = createSecurityConfig(context);
2942
2798
  const { storage } = context;
2943
2799
  return config_default(config, { storage, corsConfigSource });
@@ -3354,7 +3210,7 @@ var Factory = async (options) => {
3354
3210
  storage: new import_node_async_hooks4.AsyncLocalStorage(),
3355
3211
  sockets: /* @__PURE__ */ new Map()
3356
3212
  };
3357
- const gw = import_gateway6.IOGateway.Factory({ ...options.gateway });
3213
+ const gw = import_gateway7.IOGateway.Factory({ ...options.gateway });
3358
3214
  if (options.gateway) {
3359
3215
  const config = options.gateway;
3360
3216
  await configure(async (configurer) => {