@constructive-io/graphql-query 3.15.0 → 3.15.2

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.
@@ -2,18 +2,21 @@
2
2
  * Runtime sub-export for generated ORM code.
3
3
  *
4
4
  * Generated ORM clients need runtime dependencies at execution time.
5
- * This module re-exports two of the three so generated code can consolidate imports:
5
+ * This module re-exports so generated code can consolidate imports:
6
6
  * - @0no-co/graphql.web — parseType, print
7
7
  * - @constructive-io/graphql-types — GraphQLAdapter, GraphQLError, QueryResult
8
+ * - ./localhost-fetch — createFetch (isomorphic *.localhost-aware fetch)
8
9
  *
9
10
  * gql-ast is intentionally NOT re-exported here because the templates
10
11
  * use `import * as t from 'gql-ast'` — mixing it into this namespace
11
12
  * would pollute `t` with unrelated symbols like parseType and print.
12
13
  *
13
14
  * Usage in generated templates:
14
- * import { parseType, print } from '@constructive-io/graphql-query/runtime';
15
+ * import { parseType, print, createFetch } from '@constructive-io/graphql-query/runtime';
15
16
  * import * as t from 'gql-ast';
16
17
  * import type { GraphQLAdapter } from '@constructive-io/graphql-query/runtime';
17
18
  */
18
19
  // From @0no-co/graphql.web — GraphQL parsing/printing
19
20
  export { parseType, print } from '@0no-co/graphql.web';
21
+ // Isomorphic fetch with *.localhost DNS + Host header fix for Node.js
22
+ export { createFetch } from './localhost-fetch';
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Isomorphic fetch that resolves *.localhost subdomains and preserves
3
+ * Host headers across Node.js and browsers.
4
+ *
5
+ * Node.js has two issues with *.localhost subdomains:
6
+ * 1. DNS — fetch('http://auth.localhost:3000/') throws ENOTFOUND
7
+ * because undici doesn't resolve *.localhost to loopback.
8
+ * 2. Host header — Node's fetch treats Host as forbidden and silently
9
+ * drops it, breaking server-side subdomain routing.
10
+ *
11
+ * In browsers *.localhost resolves natively, so createFetch() returns
12
+ * globalThis.fetch as-is.
13
+ */
14
+ export function isLocalhostSubdomain(hostname) {
15
+ return hostname.endsWith('.localhost') && hostname !== 'localhost';
16
+ }
17
+ function buildNodeFetch(http, https) {
18
+ return (input, init) => {
19
+ const url = new URL(typeof input === 'string'
20
+ ? input
21
+ : input instanceof URL
22
+ ? input.href
23
+ : input.url);
24
+ if (!isLocalhostSubdomain(url.hostname)) {
25
+ return globalThis.fetch(input, init);
26
+ }
27
+ const originalHost = url.host;
28
+ url.hostname = 'localhost';
29
+ return new Promise((resolve, reject) => {
30
+ const headers = {
31
+ Host: originalHost,
32
+ };
33
+ if (init?.headers) {
34
+ const entries = init.headers instanceof Headers
35
+ ? Array.from(init.headers.entries())
36
+ : Array.isArray(init.headers)
37
+ ? init.headers
38
+ : Object.entries(init.headers);
39
+ for (const [key, value] of entries) {
40
+ headers[key] = value;
41
+ }
42
+ }
43
+ const protocol = url.protocol === 'https:' ? https : http;
44
+ const req = protocol.request(url, {
45
+ method: init?.method ?? 'GET',
46
+ headers,
47
+ }, (res) => {
48
+ const chunks = [];
49
+ res.on('data', (chunk) => chunks.push(chunk));
50
+ res.on('end', () => {
51
+ const body = Buffer.concat(chunks);
52
+ resolve(new Response(body, {
53
+ status: res.statusCode ?? 0,
54
+ statusText: res.statusMessage ?? '',
55
+ headers: res.headers,
56
+ }));
57
+ });
58
+ });
59
+ req.on('error', reject);
60
+ if (init?.signal) {
61
+ const onAbort = () => {
62
+ req.destroy(new Error('The operation was aborted'));
63
+ };
64
+ init.signal.addEventListener('abort', onAbort, { once: true });
65
+ req.on('close', () => {
66
+ init.signal.removeEventListener('abort', onAbort);
67
+ });
68
+ }
69
+ if (init?.body != null) {
70
+ req.write(typeof init.body === 'string' || init.body instanceof Uint8Array
71
+ ? init.body
72
+ : String(init.body));
73
+ }
74
+ req.end();
75
+ });
76
+ };
77
+ }
78
+ let _fetch;
79
+ /**
80
+ * Create an isomorphic fetch function.
81
+ *
82
+ * - In browsers (and Deno/Bun/edge): returns globalThis.fetch as-is.
83
+ * - In Node.js: returns a wrapper that uses node:http/node:https for
84
+ * *.localhost URLs (fixing DNS + Host header) and delegates everything
85
+ * else to globalThis.fetch.
86
+ *
87
+ * The result is cached — calling createFetch() multiple times returns
88
+ * the same function instance.
89
+ */
90
+ export function createFetch() {
91
+ if (_fetch)
92
+ return _fetch;
93
+ if (typeof process !== 'undefined' && process.versions?.node) {
94
+ try {
95
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
96
+ const http = require('node:http');
97
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
98
+ const https = require('node:https');
99
+ _fetch = buildNodeFetch(http, https);
100
+ return _fetch;
101
+ }
102
+ catch {
103
+ // node:http unavailable — fall through
104
+ }
105
+ }
106
+ _fetch = globalThis.fetch;
107
+ return _fetch;
108
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constructive-io/graphql-query",
3
- "version": "3.15.0",
3
+ "version": "3.15.2",
4
4
  "description": "Constructive GraphQL Query",
5
5
  "author": "Constructive <developers@constructive.io>",
6
6
  "main": "index.js",
@@ -36,7 +36,7 @@
36
36
  "grafast": "1.0.0",
37
37
  "graphile-build-pg": "5.0.0",
38
38
  "graphile-config": "1.0.0",
39
- "graphile-settings": "^4.22.0",
39
+ "graphile-settings": "^4.22.2",
40
40
  "graphql": "16.13.0",
41
41
  "inflection": "^3.0.0",
42
42
  "inflekt": "^0.7.1",
@@ -53,5 +53,5 @@
53
53
  "devDependencies": {
54
54
  "makage": "^0.3.0"
55
55
  },
56
- "gitHead": "434a578648cb04d3ed25e79a75c654f71573292f"
56
+ "gitHead": "a8ccaed4f3a7c6c82495241ee1581700db9dd2dd"
57
57
  }
@@ -2,18 +2,21 @@
2
2
  * Runtime sub-export for generated ORM code.
3
3
  *
4
4
  * Generated ORM clients need runtime dependencies at execution time.
5
- * This module re-exports two of the three so generated code can consolidate imports:
5
+ * This module re-exports so generated code can consolidate imports:
6
6
  * - @0no-co/graphql.web — parseType, print
7
7
  * - @constructive-io/graphql-types — GraphQLAdapter, GraphQLError, QueryResult
8
+ * - ./localhost-fetch — createFetch (isomorphic *.localhost-aware fetch)
8
9
  *
9
10
  * gql-ast is intentionally NOT re-exported here because the templates
10
11
  * use `import * as t from 'gql-ast'` — mixing it into this namespace
11
12
  * would pollute `t` with unrelated symbols like parseType and print.
12
13
  *
13
14
  * Usage in generated templates:
14
- * import { parseType, print } from '@constructive-io/graphql-query/runtime';
15
+ * import { parseType, print, createFetch } from '@constructive-io/graphql-query/runtime';
15
16
  * import * as t from 'gql-ast';
16
17
  * import type { GraphQLAdapter } from '@constructive-io/graphql-query/runtime';
17
18
  */
18
19
  export { parseType, print } from '@0no-co/graphql.web';
19
20
  export type { GraphQLAdapter, GraphQLError, QueryResult } from '@constructive-io/graphql-types';
21
+ export { createFetch } from './localhost-fetch';
22
+ export type { FetchFunction } from './localhost-fetch';
package/runtime/index.js CHANGED
@@ -3,22 +3,26 @@
3
3
  * Runtime sub-export for generated ORM code.
4
4
  *
5
5
  * Generated ORM clients need runtime dependencies at execution time.
6
- * This module re-exports two of the three so generated code can consolidate imports:
6
+ * This module re-exports so generated code can consolidate imports:
7
7
  * - @0no-co/graphql.web — parseType, print
8
8
  * - @constructive-io/graphql-types — GraphQLAdapter, GraphQLError, QueryResult
9
+ * - ./localhost-fetch — createFetch (isomorphic *.localhost-aware fetch)
9
10
  *
10
11
  * gql-ast is intentionally NOT re-exported here because the templates
11
12
  * use `import * as t from 'gql-ast'` — mixing it into this namespace
12
13
  * would pollute `t` with unrelated symbols like parseType and print.
13
14
  *
14
15
  * Usage in generated templates:
15
- * import { parseType, print } from '@constructive-io/graphql-query/runtime';
16
+ * import { parseType, print, createFetch } from '@constructive-io/graphql-query/runtime';
16
17
  * import * as t from 'gql-ast';
17
18
  * import type { GraphQLAdapter } from '@constructive-io/graphql-query/runtime';
18
19
  */
19
20
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.parseType = void 0;
21
+ exports.createFetch = exports.parseType = void 0;
21
22
  // From @0no-co/graphql.web — GraphQL parsing/printing
22
23
  var graphql_web_1 = require("@0no-co/graphql.web");
23
24
  Object.defineProperty(exports, "parseType", { enumerable: true, get: function () { return graphql_web_1.parseType; } });
24
25
  Object.defineProperty(exports, "print", { enumerable: true, get: function () { return graphql_web_1.print; } });
26
+ // Isomorphic fetch with *.localhost DNS + Host header fix for Node.js
27
+ var localhost_fetch_1 = require("./localhost-fetch");
28
+ Object.defineProperty(exports, "createFetch", { enumerable: true, get: function () { return localhost_fetch_1.createFetch; } });
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Isomorphic fetch that resolves *.localhost subdomains and preserves
3
+ * Host headers across Node.js and browsers.
4
+ *
5
+ * Node.js has two issues with *.localhost subdomains:
6
+ * 1. DNS — fetch('http://auth.localhost:3000/') throws ENOTFOUND
7
+ * because undici doesn't resolve *.localhost to loopback.
8
+ * 2. Host header — Node's fetch treats Host as forbidden and silently
9
+ * drops it, breaking server-side subdomain routing.
10
+ *
11
+ * In browsers *.localhost resolves natively, so createFetch() returns
12
+ * globalThis.fetch as-is.
13
+ */
14
+ export type FetchFunction = typeof globalThis.fetch;
15
+ export declare function isLocalhostSubdomain(hostname: string): boolean;
16
+ /**
17
+ * Create an isomorphic fetch function.
18
+ *
19
+ * - In browsers (and Deno/Bun/edge): returns globalThis.fetch as-is.
20
+ * - In Node.js: returns a wrapper that uses node:http/node:https for
21
+ * *.localhost URLs (fixing DNS + Host header) and delegates everything
22
+ * else to globalThis.fetch.
23
+ *
24
+ * The result is cached — calling createFetch() multiple times returns
25
+ * the same function instance.
26
+ */
27
+ export declare function createFetch(): FetchFunction;
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ /**
3
+ * Isomorphic fetch that resolves *.localhost subdomains and preserves
4
+ * Host headers across Node.js and browsers.
5
+ *
6
+ * Node.js has two issues with *.localhost subdomains:
7
+ * 1. DNS — fetch('http://auth.localhost:3000/') throws ENOTFOUND
8
+ * because undici doesn't resolve *.localhost to loopback.
9
+ * 2. Host header — Node's fetch treats Host as forbidden and silently
10
+ * drops it, breaking server-side subdomain routing.
11
+ *
12
+ * In browsers *.localhost resolves natively, so createFetch() returns
13
+ * globalThis.fetch as-is.
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.isLocalhostSubdomain = isLocalhostSubdomain;
17
+ exports.createFetch = createFetch;
18
+ function isLocalhostSubdomain(hostname) {
19
+ return hostname.endsWith('.localhost') && hostname !== 'localhost';
20
+ }
21
+ function buildNodeFetch(http, https) {
22
+ return (input, init) => {
23
+ const url = new URL(typeof input === 'string'
24
+ ? input
25
+ : input instanceof URL
26
+ ? input.href
27
+ : input.url);
28
+ if (!isLocalhostSubdomain(url.hostname)) {
29
+ return globalThis.fetch(input, init);
30
+ }
31
+ const originalHost = url.host;
32
+ url.hostname = 'localhost';
33
+ return new Promise((resolve, reject) => {
34
+ const headers = {
35
+ Host: originalHost,
36
+ };
37
+ if (init?.headers) {
38
+ const entries = init.headers instanceof Headers
39
+ ? Array.from(init.headers.entries())
40
+ : Array.isArray(init.headers)
41
+ ? init.headers
42
+ : Object.entries(init.headers);
43
+ for (const [key, value] of entries) {
44
+ headers[key] = value;
45
+ }
46
+ }
47
+ const protocol = url.protocol === 'https:' ? https : http;
48
+ const req = protocol.request(url, {
49
+ method: init?.method ?? 'GET',
50
+ headers,
51
+ }, (res) => {
52
+ const chunks = [];
53
+ res.on('data', (chunk) => chunks.push(chunk));
54
+ res.on('end', () => {
55
+ const body = Buffer.concat(chunks);
56
+ resolve(new Response(body, {
57
+ status: res.statusCode ?? 0,
58
+ statusText: res.statusMessage ?? '',
59
+ headers: res.headers,
60
+ }));
61
+ });
62
+ });
63
+ req.on('error', reject);
64
+ if (init?.signal) {
65
+ const onAbort = () => {
66
+ req.destroy(new Error('The operation was aborted'));
67
+ };
68
+ init.signal.addEventListener('abort', onAbort, { once: true });
69
+ req.on('close', () => {
70
+ init.signal.removeEventListener('abort', onAbort);
71
+ });
72
+ }
73
+ if (init?.body != null) {
74
+ req.write(typeof init.body === 'string' || init.body instanceof Uint8Array
75
+ ? init.body
76
+ : String(init.body));
77
+ }
78
+ req.end();
79
+ });
80
+ };
81
+ }
82
+ let _fetch;
83
+ /**
84
+ * Create an isomorphic fetch function.
85
+ *
86
+ * - In browsers (and Deno/Bun/edge): returns globalThis.fetch as-is.
87
+ * - In Node.js: returns a wrapper that uses node:http/node:https for
88
+ * *.localhost URLs (fixing DNS + Host header) and delegates everything
89
+ * else to globalThis.fetch.
90
+ *
91
+ * The result is cached — calling createFetch() multiple times returns
92
+ * the same function instance.
93
+ */
94
+ function createFetch() {
95
+ if (_fetch)
96
+ return _fetch;
97
+ if (typeof process !== 'undefined' && process.versions?.node) {
98
+ try {
99
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
100
+ const http = require('node:http');
101
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
102
+ const https = require('node:https');
103
+ _fetch = buildNodeFetch(http, https);
104
+ return _fetch;
105
+ }
106
+ catch {
107
+ // node:http unavailable — fall through
108
+ }
109
+ }
110
+ _fetch = globalThis.fetch;
111
+ return _fetch;
112
+ }