@mintlify/prebuild 1.0.1186 → 1.0.1188
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/dist/prebuild/update/ConfigUpdater.d.ts +90 -0
- package/dist/prebuild/update/docsConfig/generateAsyncApiDivisions.d.ts +2 -1
- package/dist/prebuild/update/docsConfig/generateAsyncApiDivisions.js +22 -2
- package/dist/prebuild/update/docsConfig/generateAsyncApiFromDocsConfig.d.ts +1 -0
- package/dist/prebuild/update/docsConfig/generateAsyncApiFromDocsConfig.js +2 -1
- package/dist/prebuild/update/docsConfig/generateGraphqlDivisions.d.ts +27 -0
- package/dist/prebuild/update/docsConfig/generateGraphqlDivisions.js +259 -0
- package/dist/prebuild/update/docsConfig/generateOpenApiDivisions.d.ts +2 -1
- package/dist/prebuild/update/docsConfig/generateOpenApiDivisions.js +21 -1
- package/dist/prebuild/update/docsConfig/generateOpenApiFromDocsConfig.d.ts +1 -0
- package/dist/prebuild/update/docsConfig/generateOpenApiFromDocsConfig.js +4 -1
- package/dist/prebuild/update/docsConfig/generatedRouteCollisions.d.ts +8 -0
- package/dist/prebuild/update/docsConfig/generatedRouteCollisions.js +10 -0
- package/dist/prebuild/update/docsConfig/index.d.ts +3 -0
- package/dist/prebuild/update/docsConfig/index.js +23 -7
- package/dist/prebuild/update/docsConfig/loadRemoteGraphqlSdl.d.ts +18 -0
- package/dist/prebuild/update/docsConfig/loadRemoteGraphqlSdl.js +217 -0
- package/dist/prebuild/update/index.d.ts +90 -0
- package/dist/prebuild/update/preserveAutoGeneratedMetadata.js +5 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +6 -6
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { lookup } from 'node:dns/promises';
|
|
2
|
+
import { request } from 'node:https';
|
|
3
|
+
import { BlockList, isIP } from 'node:net';
|
|
4
|
+
const MAX_REMOTE_REDIRECTS = 5;
|
|
5
|
+
export const MAX_GRAPHQL_SCHEMA_BYTES = 5 * 1024 * 1024;
|
|
6
|
+
const REMOTE_SCHEMA_TIMEOUT_MS = 10_000;
|
|
7
|
+
const blockedAddresses = new BlockList();
|
|
8
|
+
for (const [network, prefix] of [
|
|
9
|
+
['0.0.0.0', 8],
|
|
10
|
+
['10.0.0.0', 8],
|
|
11
|
+
['100.64.0.0', 10],
|
|
12
|
+
['127.0.0.0', 8],
|
|
13
|
+
['169.254.0.0', 16],
|
|
14
|
+
['172.16.0.0', 12],
|
|
15
|
+
['192.0.0.0', 24],
|
|
16
|
+
['192.0.2.0', 24],
|
|
17
|
+
['192.88.99.0', 24],
|
|
18
|
+
['192.168.0.0', 16],
|
|
19
|
+
['198.18.0.0', 15],
|
|
20
|
+
['198.51.100.0', 24],
|
|
21
|
+
['203.0.113.0', 24],
|
|
22
|
+
['224.0.0.0', 4],
|
|
23
|
+
['240.0.0.0', 4],
|
|
24
|
+
]) {
|
|
25
|
+
blockedAddresses.addSubnet(network, prefix, 'ipv4');
|
|
26
|
+
}
|
|
27
|
+
for (const [network, prefix] of [
|
|
28
|
+
['::', 128],
|
|
29
|
+
['::1', 128],
|
|
30
|
+
['::', 96],
|
|
31
|
+
['64:ff9b:1::', 48],
|
|
32
|
+
['100::', 64],
|
|
33
|
+
['2001::', 32],
|
|
34
|
+
['2001:2::', 48],
|
|
35
|
+
['2001:10::', 28],
|
|
36
|
+
['2001:20::', 28],
|
|
37
|
+
['2001:db8::', 32],
|
|
38
|
+
['2002::', 16],
|
|
39
|
+
['3fff::', 20],
|
|
40
|
+
['5f00::', 16],
|
|
41
|
+
['fc00::', 7],
|
|
42
|
+
['fe80::', 10],
|
|
43
|
+
['fec0::', 10],
|
|
44
|
+
['ff00::', 8],
|
|
45
|
+
]) {
|
|
46
|
+
blockedAddresses.addSubnet(network, prefix, 'ipv6');
|
|
47
|
+
}
|
|
48
|
+
export const isGlobalIpAddress = (address) => {
|
|
49
|
+
const family = isIP(address);
|
|
50
|
+
const normalized = address.toLowerCase();
|
|
51
|
+
if (family === 6 && normalized.startsWith('::ffff:')) {
|
|
52
|
+
const mappedAddress = normalized.slice('::ffff:'.length);
|
|
53
|
+
if (isIP(mappedAddress) === 4)
|
|
54
|
+
return isGlobalIpAddress(mappedAddress);
|
|
55
|
+
const [high, low] = mappedAddress.split(':').map((part) => Number.parseInt(part, 16));
|
|
56
|
+
if (high != null && low != null && Number.isFinite(high) && Number.isFinite(low)) {
|
|
57
|
+
return isGlobalIpAddress(`${high >> 8}.${high & 0xff}.${low >> 8}.${low & 0xff}`);
|
|
58
|
+
}
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
return family !== 0 && !blockedAddresses.check(address, family === 4 ? 'ipv4' : 'ipv6');
|
|
62
|
+
};
|
|
63
|
+
async function defaultResolveHostname(hostname) {
|
|
64
|
+
if (isIP(hostname))
|
|
65
|
+
return [{ address: hostname, family: isIP(hostname) }];
|
|
66
|
+
return (await lookup(hostname, { all: true }));
|
|
67
|
+
}
|
|
68
|
+
export function createPinnedLookup(resolved) {
|
|
69
|
+
return ((_hostname, _options, callback) => {
|
|
70
|
+
callback(null, resolved.address, resolved.family);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
async function resolveAndValidate(url, resolveHostname) {
|
|
74
|
+
if (url.protocol !== 'https:') {
|
|
75
|
+
throw new Error(`GraphQL schema redirects must use HTTPS: ${url.href}`);
|
|
76
|
+
}
|
|
77
|
+
const hostname = url.hostname.toLowerCase().replace(/^\[|\]$/g, '');
|
|
78
|
+
if (hostname === 'localhost' || hostname.endsWith('.localhost')) {
|
|
79
|
+
throw new Error(`GraphQL schema host must be public: ${hostname}`);
|
|
80
|
+
}
|
|
81
|
+
let addresses;
|
|
82
|
+
try {
|
|
83
|
+
addresses = await resolveHostname(hostname);
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
const detail = error instanceof Error ? `: ${error.message}` : '';
|
|
87
|
+
throw new Error(`Unable to resolve GraphQL schema host ${hostname}${detail}`);
|
|
88
|
+
}
|
|
89
|
+
// Reject ambiguous split-horizon answers so every address associated with the host is safe.
|
|
90
|
+
if (addresses.length === 0 || addresses.some(({ address }) => !isGlobalIpAddress(address))) {
|
|
91
|
+
throw new Error(`GraphQL schema host must resolve only to public addresses: ${hostname}`);
|
|
92
|
+
}
|
|
93
|
+
return addresses[0];
|
|
94
|
+
}
|
|
95
|
+
function requestPinned(url, resolved, requestImpl, timeoutMs, maxBytes) {
|
|
96
|
+
return new Promise((resolve, reject) => {
|
|
97
|
+
let responseRef;
|
|
98
|
+
let requestRef;
|
|
99
|
+
let settled = false;
|
|
100
|
+
const finish = (callback, value) => {
|
|
101
|
+
if (settled)
|
|
102
|
+
return;
|
|
103
|
+
settled = true;
|
|
104
|
+
clearTimeout(deadlineTimer);
|
|
105
|
+
callback(value);
|
|
106
|
+
};
|
|
107
|
+
const hostname = url.hostname.replace(/^\[|\]$/g, '');
|
|
108
|
+
const options = {
|
|
109
|
+
agent: false,
|
|
110
|
+
lookup: createPinnedLookup(resolved),
|
|
111
|
+
servername: isIP(hostname) ? undefined : hostname,
|
|
112
|
+
headers: { Host: url.host },
|
|
113
|
+
};
|
|
114
|
+
const deadlineTimer = setTimeout(() => {
|
|
115
|
+
const error = new Error('timeout');
|
|
116
|
+
responseRef?.destroy(error);
|
|
117
|
+
requestRef.destroy(error);
|
|
118
|
+
finish(reject, error);
|
|
119
|
+
}, timeoutMs);
|
|
120
|
+
try {
|
|
121
|
+
requestRef = requestImpl(url, options, (response) => {
|
|
122
|
+
responseRef = response;
|
|
123
|
+
const chunks = [];
|
|
124
|
+
let totalBytes = 0;
|
|
125
|
+
const contentLength = Number(response.headers['content-length']);
|
|
126
|
+
if (Number.isFinite(contentLength) && contentLength > maxBytes) {
|
|
127
|
+
response.destroy();
|
|
128
|
+
finish(reject, new Error(`GraphQL schema ${url.href} exceeds the ${maxBytes} byte limit`));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
response.on('data', (chunk) => {
|
|
132
|
+
const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
133
|
+
totalBytes += bytes.byteLength;
|
|
134
|
+
if (totalBytes > maxBytes) {
|
|
135
|
+
response.destroy();
|
|
136
|
+
finish(reject, new Error(`GraphQL schema ${url.href} exceeds the ${maxBytes} byte limit`));
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
chunks.push(new Uint8Array(bytes));
|
|
140
|
+
});
|
|
141
|
+
response.on('end', () => {
|
|
142
|
+
finish(resolve, {
|
|
143
|
+
statusCode: response.statusCode ?? 0,
|
|
144
|
+
statusMessage: response.statusMessage ?? '',
|
|
145
|
+
headers: response.headers,
|
|
146
|
+
body: Buffer.concat(chunks).toString('utf8'),
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
response.on('error', (error) => finish(reject, error));
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
finish(reject, error);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
requestRef.on('error', (error) => finish(reject, error));
|
|
157
|
+
requestRef.end();
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
export async function loadRemoteGraphqlSdl(source, options = {}) {
|
|
161
|
+
const timeoutMs = options.timeoutMs ?? REMOTE_SCHEMA_TIMEOUT_MS;
|
|
162
|
+
const maxBytes = options.maxBytes ?? MAX_GRAPHQL_SCHEMA_BYTES;
|
|
163
|
+
const resolveHostname = options.resolveHostname ?? defaultResolveHostname;
|
|
164
|
+
const requestImpl = options.requestImpl ?? request;
|
|
165
|
+
const deadline = Date.now() + timeoutMs;
|
|
166
|
+
let currentUrl = new URL(source);
|
|
167
|
+
const withTimeout = async (pending, remainingMs) => {
|
|
168
|
+
let timeout;
|
|
169
|
+
try {
|
|
170
|
+
return await Promise.race([
|
|
171
|
+
pending,
|
|
172
|
+
new Promise((_resolve, reject) => {
|
|
173
|
+
timeout = setTimeout(() => reject(new Error('timeout')), remainingMs);
|
|
174
|
+
}),
|
|
175
|
+
]);
|
|
176
|
+
}
|
|
177
|
+
finally {
|
|
178
|
+
if (timeout)
|
|
179
|
+
clearTimeout(timeout);
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
for (let redirects = 0; redirects <= MAX_REMOTE_REDIRECTS; redirects++) {
|
|
183
|
+
let remainingMs = deadline - Date.now();
|
|
184
|
+
if (remainingMs <= 0)
|
|
185
|
+
throw new Error(`Timed out loading GraphQL schema ${source}`);
|
|
186
|
+
let response;
|
|
187
|
+
try {
|
|
188
|
+
const resolved = await withTimeout(resolveAndValidate(currentUrl, resolveHostname), remainingMs);
|
|
189
|
+
remainingMs = deadline - Date.now();
|
|
190
|
+
if (remainingMs <= 0)
|
|
191
|
+
throw new Error('timeout');
|
|
192
|
+
response = await requestPinned(currentUrl, resolved, requestImpl, remainingMs, maxBytes);
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
if (Date.now() >= deadline || (error instanceof Error && error.message === 'timeout')) {
|
|
196
|
+
throw new Error(`Timed out loading GraphQL schema ${source}`);
|
|
197
|
+
}
|
|
198
|
+
throw error;
|
|
199
|
+
}
|
|
200
|
+
if (response.statusCode >= 300 && response.statusCode < 400) {
|
|
201
|
+
const location = response.headers.location;
|
|
202
|
+
if (typeof location !== 'string') {
|
|
203
|
+
throw new Error(`GraphQL schema redirect from ${currentUrl.href} has no location`);
|
|
204
|
+
}
|
|
205
|
+
if (redirects === MAX_REMOTE_REDIRECTS) {
|
|
206
|
+
throw new Error(`Too many redirects loading GraphQL schema ${source}`);
|
|
207
|
+
}
|
|
208
|
+
currentUrl = new URL(location, currentUrl);
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
if (response.statusCode < 200 || response.statusCode >= 300) {
|
|
212
|
+
throw new Error(`Unable to load GraphQL schema ${currentUrl.href}: ${response.statusCode} ${response.statusMessage}`);
|
|
213
|
+
}
|
|
214
|
+
return response.body;
|
|
215
|
+
}
|
|
216
|
+
throw new Error(`Too many redirects loading GraphQL schema ${source}`);
|
|
217
|
+
}
|