@forklaunch/core 0.12.3 → 0.13.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/lib/http/index.d.mts +347 -118
- package/lib/http/index.d.ts +347 -118
- package/lib/http/index.js +258 -78
- package/lib/http/index.js.map +1 -1
- package/lib/http/index.mjs +256 -77
- package/lib/http/index.mjs.map +1 -1
- package/package.json +12 -11
package/lib/http/index.mjs
CHANGED
@@ -81,10 +81,10 @@ function isTypedHandler(maybeTypedHandler) {
|
|
81
81
|
|
82
82
|
// src/http/middleware/request/auth.middleware.ts
|
83
83
|
import { isNever } from "@forklaunch/common";
|
84
|
-
import { jwtVerify } from "jose";
|
85
84
|
|
86
85
|
// src/http/discriminateAuthMethod.ts
|
87
|
-
|
86
|
+
import { jwtVerify } from "jose";
|
87
|
+
async function discriminateAuthMethod(auth) {
|
88
88
|
if ("basic" in auth) {
|
89
89
|
return {
|
90
90
|
type: "basic",
|
@@ -93,18 +93,59 @@ function discriminateAuthMethod(auth) {
|
|
93
93
|
login: auth.basic.login
|
94
94
|
}
|
95
95
|
};
|
96
|
-
} else if ("jwt" in auth) {
|
96
|
+
} else if ("jwt" in auth && auth.jwt != null) {
|
97
|
+
const jwt = auth.jwt;
|
98
|
+
let verificationFunction;
|
99
|
+
if ("privateKey" in jwt) {
|
100
|
+
verificationFunction = async (token) => {
|
101
|
+
const { payload } = await jwtVerify(token, Buffer.from(jwt.privateKey));
|
102
|
+
return payload;
|
103
|
+
};
|
104
|
+
} else {
|
105
|
+
let jwks;
|
106
|
+
if ("jwksPublicKeyUrl" in jwt) {
|
107
|
+
const jwksResponse = await fetch(jwt.jwksPublicKeyUrl);
|
108
|
+
jwks = (await jwksResponse.json()).keys;
|
109
|
+
} else {
|
110
|
+
jwks = [jwt.jwksPublicKey];
|
111
|
+
}
|
112
|
+
verificationFunction = async (token) => {
|
113
|
+
for (const key of jwks) {
|
114
|
+
try {
|
115
|
+
const { payload } = await jwtVerify(token, key);
|
116
|
+
return payload;
|
117
|
+
} catch {
|
118
|
+
continue;
|
119
|
+
}
|
120
|
+
}
|
121
|
+
};
|
122
|
+
}
|
97
123
|
return {
|
98
124
|
type: "jwt",
|
99
125
|
auth: {
|
100
|
-
decodeResource: auth.decodeResource
|
126
|
+
decodeResource: auth.decodeResource,
|
127
|
+
verificationFunction
|
128
|
+
}
|
129
|
+
};
|
130
|
+
} else if ("secretKey" in auth) {
|
131
|
+
return {
|
132
|
+
type: "system",
|
133
|
+
auth: {
|
134
|
+
secretKey: auth.secretKey
|
101
135
|
}
|
102
136
|
};
|
103
137
|
} else {
|
104
138
|
return {
|
105
139
|
type: "jwt",
|
106
140
|
auth: {
|
107
|
-
decodeResource: auth.decodeResource
|
141
|
+
decodeResource: auth.decodeResource,
|
142
|
+
verificationFunction: async (token) => {
|
143
|
+
const { payload } = await jwtVerify(
|
144
|
+
token,
|
145
|
+
Buffer.from(process.env.JWT_SECRET_KEY)
|
146
|
+
);
|
147
|
+
return payload;
|
148
|
+
}
|
108
149
|
}
|
109
150
|
};
|
110
151
|
}
|
@@ -112,12 +153,22 @@ function discriminateAuthMethod(auth) {
|
|
112
153
|
|
113
154
|
// src/http/guards/hasPermissionChecks.ts
|
114
155
|
function hasPermissionChecks(maybePermissionedAuth) {
|
115
|
-
return typeof maybePermissionedAuth === "object" && maybePermissionedAuth !== null &&
|
156
|
+
return typeof maybePermissionedAuth === "object" && maybePermissionedAuth !== null && ("allowedPermissions" in maybePermissionedAuth || "forbiddenPermissions" in maybePermissionedAuth);
|
116
157
|
}
|
117
158
|
|
118
159
|
// src/http/guards/hasRoleChecks.ts
|
119
160
|
function hasRoleChecks(maybeRoledAuth) {
|
120
|
-
return typeof maybeRoledAuth === "object" && maybeRoledAuth !== null &&
|
161
|
+
return typeof maybeRoledAuth === "object" && maybeRoledAuth !== null && ("allowedRoles" in maybeRoledAuth || "forbiddenRoles" in maybeRoledAuth);
|
162
|
+
}
|
163
|
+
|
164
|
+
// src/http/guards/hasScopeChecks.ts
|
165
|
+
function hasScopeChecks(maybePermissionedAuth) {
|
166
|
+
return typeof maybePermissionedAuth === "object" && maybePermissionedAuth !== null && "requiredScope" in maybePermissionedAuth && maybePermissionedAuth.requiredScope != null;
|
167
|
+
}
|
168
|
+
|
169
|
+
// src/http/guards/isSystemAuthMethod.ts
|
170
|
+
function isSystemAuthMethod(maybeSystemAuthMethod) {
|
171
|
+
return typeof maybeSystemAuthMethod === "object" && maybeSystemAuthMethod !== null && "secretKey" in maybeSystemAuthMethod;
|
121
172
|
}
|
122
173
|
|
123
174
|
// src/http/middleware/request/auth.middleware.ts
|
@@ -145,23 +196,45 @@ var invalidAuthorizationLogin = [
|
|
145
196
|
403,
|
146
197
|
"Invalid Authorization login."
|
147
198
|
];
|
148
|
-
|
199
|
+
var invalidScope = [403, "Invalid scope for operation."];
|
200
|
+
var invalidAuthorizationMethod = [
|
201
|
+
401,
|
202
|
+
"Invalid Authorization method."
|
203
|
+
];
|
204
|
+
var authorizationTokenRequired = [
|
205
|
+
401,
|
206
|
+
"Authorization token required."
|
207
|
+
];
|
208
|
+
async function checkAuthorizationToken(authorizationMethod, globalOptions, authorizationToken, req) {
|
209
|
+
if (authorizationMethod == null) {
|
210
|
+
return void 0;
|
211
|
+
}
|
212
|
+
const collapsedAuthorizationMethod = {
|
213
|
+
...globalOptions,
|
214
|
+
...authorizationMethod
|
215
|
+
};
|
149
216
|
if (authorizationToken == null) {
|
150
|
-
return
|
217
|
+
return authorizationTokenRequired;
|
151
218
|
}
|
152
219
|
const [tokenPrefix, token] = authorizationToken.split(" ");
|
153
220
|
let resourceId;
|
154
|
-
const { type, auth } = discriminateAuthMethod(
|
221
|
+
const { type, auth } = await discriminateAuthMethod(
|
222
|
+
collapsedAuthorizationMethod
|
223
|
+
);
|
155
224
|
switch (type) {
|
225
|
+
case "system": {
|
226
|
+
if (token !== auth.secretKey || tokenPrefix !== collapsedAuthorizationMethod.tokenPrefix) {
|
227
|
+
return invalidAuthorizationToken;
|
228
|
+
}
|
229
|
+
resourceId = null;
|
230
|
+
break;
|
231
|
+
}
|
156
232
|
case "jwt": {
|
157
|
-
if (tokenPrefix !== (
|
233
|
+
if (tokenPrefix !== (collapsedAuthorizationMethod.tokenPrefix ?? "Bearer")) {
|
158
234
|
return invalidAuthorizationTokenFormat;
|
159
235
|
}
|
160
236
|
try {
|
161
|
-
const decodedJwt = await auth
|
162
|
-
token,
|
163
|
-
new TextEncoder().encode(process.env.JWT_SECRET)
|
164
|
-
)).payload;
|
237
|
+
const decodedJwt = "decodeResource" in auth && auth.decodeResource ? await auth.decodeResource(token) : "verificationFunction" in auth && auth.verificationFunction ? await auth.verificationFunction(token) : void 0;
|
165
238
|
if (!decodedJwt) {
|
166
239
|
return invalidAuthorizationSubject;
|
167
240
|
}
|
@@ -173,7 +246,7 @@ async function checkAuthorizationToken(authorizationMethod, authorizationToken,
|
|
173
246
|
break;
|
174
247
|
}
|
175
248
|
case "basic": {
|
176
|
-
if (tokenPrefix !== (
|
249
|
+
if (tokenPrefix !== (collapsedAuthorizationMethod.tokenPrefix ?? "Basic")) {
|
177
250
|
return invalidAuthorizationTokenFormat;
|
178
251
|
}
|
179
252
|
if (auth.decodeResource) {
|
@@ -196,62 +269,82 @@ async function checkAuthorizationToken(authorizationMethod, authorizationToken,
|
|
196
269
|
isNever(type);
|
197
270
|
return [401, "Invalid Authorization method."];
|
198
271
|
}
|
199
|
-
if (
|
200
|
-
|
201
|
-
|
272
|
+
if (isSystemAuthMethod(collapsedAuthorizationMethod) || resourceId == null) {
|
273
|
+
return;
|
274
|
+
}
|
275
|
+
if (hasScopeChecks(collapsedAuthorizationMethod)) {
|
276
|
+
if (collapsedAuthorizationMethod.surfaceScopes) {
|
277
|
+
const resourceScopes = await collapsedAuthorizationMethod.surfaceScopes(
|
278
|
+
resourceId,
|
279
|
+
req
|
280
|
+
);
|
281
|
+
if (collapsedAuthorizationMethod.scopeHeirarchy) {
|
282
|
+
if (collapsedAuthorizationMethod.requiredScope) {
|
283
|
+
if (!resourceScopes.has(collapsedAuthorizationMethod.requiredScope) || Array.from(resourceScopes).every(
|
284
|
+
(scope) => collapsedAuthorizationMethod.scopeHeirarchy?.indexOf(scope) ?? -1 > -1
|
285
|
+
)) {
|
286
|
+
return invalidScope;
|
287
|
+
}
|
288
|
+
}
|
289
|
+
}
|
202
290
|
}
|
203
|
-
|
291
|
+
}
|
292
|
+
if (hasPermissionChecks(collapsedAuthorizationMethod)) {
|
293
|
+
if (!collapsedAuthorizationMethod.surfacePermissions) {
|
294
|
+
return [500, "No permission surfacing function provided."];
|
295
|
+
}
|
296
|
+
const resourcePermissions = await collapsedAuthorizationMethod.surfacePermissions(
|
204
297
|
resourceId,
|
205
298
|
req
|
206
299
|
);
|
207
|
-
if ("allowedPermissions" in
|
208
|
-
if (resourcePermissions.intersection(
|
300
|
+
if ("allowedPermissions" in collapsedAuthorizationMethod && collapsedAuthorizationMethod.allowedPermissions) {
|
301
|
+
if (resourcePermissions.intersection(
|
302
|
+
collapsedAuthorizationMethod.allowedPermissions
|
303
|
+
).size === 0) {
|
209
304
|
return invalidAuthorizationTokenPermissions;
|
210
305
|
}
|
211
306
|
}
|
212
|
-
if ("forbiddenPermissions" in
|
307
|
+
if ("forbiddenPermissions" in collapsedAuthorizationMethod && collapsedAuthorizationMethod.forbiddenPermissions) {
|
213
308
|
if (resourcePermissions.intersection(
|
214
|
-
|
309
|
+
collapsedAuthorizationMethod.forbiddenPermissions
|
215
310
|
).size !== 0) {
|
216
311
|
return invalidAuthorizationTokenPermissions;
|
217
312
|
}
|
218
313
|
}
|
219
|
-
} else if (hasRoleChecks(
|
220
|
-
if (!
|
221
|
-
return [500, "No role
|
314
|
+
} else if (hasRoleChecks(collapsedAuthorizationMethod)) {
|
315
|
+
if (!collapsedAuthorizationMethod.surfaceRoles) {
|
316
|
+
return [500, "No role surfacing function provided."];
|
222
317
|
}
|
223
|
-
const resourceRoles = await
|
318
|
+
const resourceRoles = await collapsedAuthorizationMethod.surfaceRoles(
|
224
319
|
resourceId,
|
225
320
|
req
|
226
321
|
);
|
227
|
-
if ("allowedRoles" in
|
228
|
-
if (resourceRoles.intersection(
|
322
|
+
if ("allowedRoles" in collapsedAuthorizationMethod && collapsedAuthorizationMethod.allowedRoles) {
|
323
|
+
if (resourceRoles.intersection(collapsedAuthorizationMethod.allowedRoles).size === 0) {
|
229
324
|
return invalidAuthorizationTokenRoles;
|
230
325
|
}
|
231
326
|
}
|
232
|
-
if ("forbiddenRoles" in
|
233
|
-
if (resourceRoles.intersection(
|
327
|
+
if ("forbiddenRoles" in collapsedAuthorizationMethod && collapsedAuthorizationMethod.forbiddenRoles) {
|
328
|
+
if (resourceRoles.intersection(collapsedAuthorizationMethod.forbiddenRoles).size !== 0) {
|
234
329
|
return invalidAuthorizationTokenRoles;
|
235
330
|
}
|
236
331
|
}
|
237
332
|
} else {
|
238
|
-
return
|
333
|
+
return invalidAuthorizationMethod;
|
239
334
|
}
|
240
335
|
}
|
241
336
|
async function parseRequestAuth(req, res, next) {
|
242
337
|
const auth = req.contractDetails.auth;
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
return;
|
254
|
-
}
|
338
|
+
const [error, message] = await checkAuthorizationToken(
|
339
|
+
auth,
|
340
|
+
req._globalOptions?.auth,
|
341
|
+
req.headers[auth?.headerName ?? "Authorization"] || req.headers[auth?.headerName ?? "authorization"],
|
342
|
+
req
|
343
|
+
) ?? [];
|
344
|
+
if (error != null) {
|
345
|
+
res.type("text/plain");
|
346
|
+
res.status(error).send(message);
|
347
|
+
return;
|
255
348
|
}
|
256
349
|
next?.();
|
257
350
|
}
|
@@ -330,7 +423,7 @@ import { isNever as isNever2 } from "@forklaunch/common";
|
|
330
423
|
import { trace as trace2 } from "@opentelemetry/api";
|
331
424
|
import { logs } from "@opentelemetry/api-logs";
|
332
425
|
import pino from "pino";
|
333
|
-
import PinoPretty from "pino-pretty";
|
426
|
+
import * as PinoPretty from "pino-pretty";
|
334
427
|
|
335
428
|
// src/http/guards/isLoggerMeta.ts
|
336
429
|
function isLoggerMeta(arg) {
|
@@ -377,11 +470,35 @@ function normalizeLogArgs(args) {
|
|
377
470
|
const metadata = Object.assign({}, ...metaObjects);
|
378
471
|
return [metadata, message.trim()];
|
379
472
|
}
|
473
|
+
function safePrettyFormat(level, args, timestamp) {
|
474
|
+
try {
|
475
|
+
const [metadata, message] = normalizeLogArgs(args);
|
476
|
+
const formattedTimestamp = timestamp || (/* @__PURE__ */ new Date()).toISOString();
|
477
|
+
return `[${formattedTimestamp}] ${level.toUpperCase()}: ${message}${Object.keys(metadata).length > 0 ? `
|
478
|
+
${JSON.stringify(metadata, null, 2)}` : ""}`;
|
479
|
+
} catch (error) {
|
480
|
+
const fallbackMessage = args.map((arg) => {
|
481
|
+
try {
|
482
|
+
if (typeof arg === "string") return arg;
|
483
|
+
if (arg === null) return "null";
|
484
|
+
if (arg === void 0) return "undefined";
|
485
|
+
return JSON.stringify(arg);
|
486
|
+
} catch {
|
487
|
+
return "[Circular/Non-serializable Object]";
|
488
|
+
}
|
489
|
+
}).join(" ");
|
490
|
+
return `[${(/* @__PURE__ */ new Date()).toISOString()}] ${level.toUpperCase()}: ${fallbackMessage} [Pretty Print Error: ${error instanceof Error ? error.message : "Unknown error"}]`;
|
491
|
+
}
|
492
|
+
}
|
380
493
|
var PinoLogger = class _PinoLogger {
|
381
494
|
pinoLogger;
|
382
495
|
meta;
|
383
496
|
prettyPrinter = PinoPretty.prettyFactory({
|
384
|
-
colorize: true
|
497
|
+
colorize: true,
|
498
|
+
// Add error handling options
|
499
|
+
errorLikeObjectKeys: ["err", "error"],
|
500
|
+
ignore: "pid,hostname",
|
501
|
+
translateTime: "SYS:standard"
|
385
502
|
});
|
386
503
|
constructor(level, meta2 = {}) {
|
387
504
|
this.pinoLogger = pino({
|
@@ -394,7 +511,12 @@ var PinoLogger = class _PinoLogger {
|
|
394
511
|
timestamp: pino.stdTimeFunctions.isoTime,
|
395
512
|
transport: {
|
396
513
|
target: "pino-pretty",
|
397
|
-
options: {
|
514
|
+
options: {
|
515
|
+
colorize: true,
|
516
|
+
errorLikeObjectKeys: ["err", "error"],
|
517
|
+
ignore: "pid,hostname",
|
518
|
+
translateTime: "SYS:standard"
|
519
|
+
}
|
398
520
|
}
|
399
521
|
});
|
400
522
|
this.meta = meta2;
|
@@ -426,12 +548,21 @@ var PinoLogger = class _PinoLogger {
|
|
426
548
|
...meta2
|
427
549
|
};
|
428
550
|
this.pinoLogger[level](...normalizeLogArgs(filteredArgs));
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
551
|
+
const formattedBody = safePrettyFormat(level, filteredArgs);
|
552
|
+
try {
|
553
|
+
logs.getLogger(process.env.OTEL_SERVICE_NAME ?? "unknown").emit({
|
554
|
+
severityText: level,
|
555
|
+
severityNumber: mapSeverity(level),
|
556
|
+
body: formattedBody,
|
557
|
+
attributes: { ...this.meta, ...meta2 }
|
558
|
+
});
|
559
|
+
} catch (error) {
|
560
|
+
console.error("Failed to emit OpenTelemetry log:", error);
|
561
|
+
console.log(
|
562
|
+
`[${(/* @__PURE__ */ new Date()).toISOString()}] ${level.toUpperCase()}:`,
|
563
|
+
...filteredArgs
|
564
|
+
);
|
565
|
+
}
|
435
566
|
}
|
436
567
|
error = (msg, ...args) => this.log("error", msg, ...args);
|
437
568
|
info = (msg, ...args) => this.log("info", msg, ...args);
|
@@ -560,13 +691,14 @@ var httpServerDurationHistogram = metrics.getMeter(getEnvVar2("OTEL_SERVICE_NAME
|
|
560
691
|
});
|
561
692
|
|
562
693
|
// src/http/middleware/request/enrichDetails.middleware.ts
|
563
|
-
function enrichDetails(path, contractDetails, requestSchema, responseSchemas, openTelemetryCollector) {
|
694
|
+
function enrichDetails(path, contractDetails, requestSchema, responseSchemas, openTelemetryCollector, globalOptions) {
|
564
695
|
return (req, res, next) => {
|
565
696
|
req.originalPath = path;
|
566
697
|
req.contractDetails = contractDetails;
|
567
698
|
req.requestSchema = requestSchema;
|
568
699
|
res.responseSchemas = responseSchemas;
|
569
700
|
req.openTelemetryCollector = openTelemetryCollector;
|
701
|
+
req._globalOptions = globalOptions;
|
570
702
|
req.context?.span?.setAttribute(ATTR_API_NAME, req.contractDetails?.name);
|
571
703
|
const startTime = process.hrtime();
|
572
704
|
res.on("finish", () => {
|
@@ -602,6 +734,7 @@ function isRequestShape(maybeResponseShape) {
|
|
602
734
|
|
603
735
|
// src/http/middleware/request/parse.middleware.ts
|
604
736
|
function parse(req, res, next) {
|
737
|
+
const collapsedOptions = req.contractDetails.options?.requestValidation ?? (req._globalOptions?.validation === false ? "none" : req._globalOptions?.validation?.request);
|
605
738
|
const request = {
|
606
739
|
params: req.params,
|
607
740
|
query: req.query,
|
@@ -674,8 +807,9 @@ function parse(req, res, next) {
|
|
674
807
|
);
|
675
808
|
}
|
676
809
|
if (!parsedRequest.ok) {
|
677
|
-
switch (
|
810
|
+
switch (collapsedOptions) {
|
678
811
|
default:
|
812
|
+
case void 0:
|
679
813
|
case "error":
|
680
814
|
res.type("application/json");
|
681
815
|
res.status(400);
|
@@ -836,12 +970,13 @@ function discriminateResponseBodies(schemaValidator, responses) {
|
|
836
970
|
|
837
971
|
// src/http/router/expressLikeRouter.ts
|
838
972
|
var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
|
839
|
-
constructor(basePath, schemaValidator, internal, postEnrichMiddleware, openTelemetryCollector) {
|
973
|
+
constructor(basePath, schemaValidator, internal, postEnrichMiddleware, openTelemetryCollector, routerOptions) {
|
840
974
|
this.basePath = basePath;
|
841
975
|
this.schemaValidator = schemaValidator;
|
842
976
|
this.internal = internal;
|
843
977
|
this.postEnrichMiddleware = postEnrichMiddleware;
|
844
978
|
this.openTelemetryCollector = openTelemetryCollector;
|
979
|
+
this.routerOptions = routerOptions;
|
845
980
|
if (process.env.NODE_ENV !== "test" && !process.env.VITEST) {
|
846
981
|
process.on("uncaughtException", (err) => {
|
847
982
|
this.openTelemetryCollector.error(`Uncaught exception: ${err}`);
|
@@ -880,7 +1015,8 @@ var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
|
|
880
1015
|
contractDetails,
|
881
1016
|
requestSchema,
|
882
1017
|
responseSchemas,
|
883
|
-
this.openTelemetryCollector
|
1018
|
+
this.openTelemetryCollector,
|
1019
|
+
this.routerOptions
|
884
1020
|
),
|
885
1021
|
...this.postEnrichMiddleware,
|
886
1022
|
parse,
|
@@ -1573,7 +1709,8 @@ var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
|
|
1573
1709
|
this.schemaValidator,
|
1574
1710
|
this.internal,
|
1575
1711
|
this.postEnrichMiddleware,
|
1576
|
-
this.openTelemetryCollector
|
1712
|
+
this.openTelemetryCollector,
|
1713
|
+
this.routerOptions
|
1577
1714
|
);
|
1578
1715
|
this.cloneInternals(clone);
|
1579
1716
|
return clone;
|
@@ -1593,7 +1730,12 @@ var ForklaunchExpressLikeApplication = class extends ForklaunchExpressLikeRouter
|
|
1593
1730
|
schemaValidator,
|
1594
1731
|
internal,
|
1595
1732
|
postEnrichMiddleware,
|
1596
|
-
openTelemetryCollector
|
1733
|
+
openTelemetryCollector,
|
1734
|
+
{
|
1735
|
+
...appOptions,
|
1736
|
+
openapi: appOptions?.openapi !== false,
|
1737
|
+
mcp: appOptions?.mcp !== false
|
1738
|
+
}
|
1597
1739
|
);
|
1598
1740
|
this.schemaValidator = schemaValidator;
|
1599
1741
|
this.internal = internal;
|
@@ -1604,6 +1746,27 @@ var ForklaunchExpressLikeApplication = class extends ForklaunchExpressLikeRouter
|
|
1604
1746
|
}
|
1605
1747
|
};
|
1606
1748
|
|
1749
|
+
// src/http/cluster/isPortBound.ts
|
1750
|
+
import * as net from "net";
|
1751
|
+
function isPortBound(port, host = "localhost") {
|
1752
|
+
return new Promise((resolve) => {
|
1753
|
+
const socket = new net.Socket();
|
1754
|
+
socket.setTimeout(1e3);
|
1755
|
+
socket.on("connect", () => {
|
1756
|
+
socket.destroy();
|
1757
|
+
resolve(true);
|
1758
|
+
});
|
1759
|
+
socket.on("timeout", () => {
|
1760
|
+
socket.destroy();
|
1761
|
+
resolve(false);
|
1762
|
+
});
|
1763
|
+
socket.on("error", () => {
|
1764
|
+
resolve(false);
|
1765
|
+
});
|
1766
|
+
socket.connect(port, host);
|
1767
|
+
});
|
1768
|
+
}
|
1769
|
+
|
1607
1770
|
// src/http/guards/isPath.ts
|
1608
1771
|
function isPath(path) {
|
1609
1772
|
return path.startsWith("/");
|
@@ -2726,7 +2889,7 @@ function generateInputSchema(schemaValidator, body, params, query, requestHeader
|
|
2726
2889
|
} : {}
|
2727
2890
|
});
|
2728
2891
|
}
|
2729
|
-
function generateMcpServer(schemaValidator, protocol, host, port, version, application, options2, contentTypeMap) {
|
2892
|
+
function generateMcpServer(schemaValidator, protocol, host, port, version, application, appOptions, options2, contentTypeMap) {
|
2730
2893
|
if (!(schemaValidator instanceof ZodSchemaValidator)) {
|
2731
2894
|
throw new Error(
|
2732
2895
|
"Schema validator must be an instance of ZodSchemaValidator"
|
@@ -2747,6 +2910,9 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
|
|
2747
2910
|
])
|
2748
2911
|
].forEach(({ fullPath, router }) => {
|
2749
2912
|
router.routes.forEach((route) => {
|
2913
|
+
if (!(route.contractDetails.options?.mcp ?? router.routerOptions?.mcp ?? appOptions !== false)) {
|
2914
|
+
return;
|
2915
|
+
}
|
2750
2916
|
const inputSchemas = [];
|
2751
2917
|
if (route.contractDetails.versions) {
|
2752
2918
|
Object.values(route.contractDetails.versions).forEach((version2) => {
|
@@ -2950,6 +3116,11 @@ function isResponseCompiledSchema(schema) {
|
|
2950
3116
|
function parse2(req, res, next) {
|
2951
3117
|
let headers;
|
2952
3118
|
let responses;
|
3119
|
+
const collapsedOptions = req.contractDetails.options?.responseValidation ?? (req._globalOptions?.validation === false ? "none" : req._globalOptions?.validation?.response);
|
3120
|
+
if (collapsedOptions === "none") {
|
3121
|
+
next?.();
|
3122
|
+
return;
|
3123
|
+
}
|
2953
3124
|
const responseSchemas = res.responseSchemas;
|
2954
3125
|
const schemaValidator = req.schemaValidator;
|
2955
3126
|
if (!isResponseCompiledSchema(responseSchemas)) {
|
@@ -3011,6 +3182,7 @@ function parse2(req, res, next) {
|
|
3011
3182
|
if (parseErrors.length > 0) {
|
3012
3183
|
switch (req.contractDetails.options?.responseValidation) {
|
3013
3184
|
default:
|
3185
|
+
case void 0:
|
3014
3186
|
case "error":
|
3015
3187
|
res.type("text/plain");
|
3016
3188
|
res.status(500);
|
@@ -3239,13 +3411,16 @@ function transformBasePath(basePath) {
|
|
3239
3411
|
}
|
3240
3412
|
return `/${basePath}`;
|
3241
3413
|
}
|
3242
|
-
function generateOpenApiDocument(serverUrls, serverDescriptions, versionedTags, versionedPaths, versionedSecuritySchemes,
|
3414
|
+
function generateOpenApiDocument(serverUrls, serverDescriptions, versionedTags, versionedPaths, versionedSecuritySchemes, appOptions) {
|
3415
|
+
const { title, description, contact } = appOptions !== false ? appOptions ?? {} : {};
|
3243
3416
|
return {
|
3244
3417
|
[OPENAPI_DEFAULT_VERSION]: {
|
3245
3418
|
openapi: "3.1.0",
|
3246
3419
|
info: {
|
3247
|
-
title: process.env.API_TITLE || "API Definition",
|
3248
|
-
version:
|
3420
|
+
title: title || process.env.API_TITLE || "API Definition",
|
3421
|
+
version: "latest",
|
3422
|
+
description,
|
3423
|
+
contact
|
3249
3424
|
},
|
3250
3425
|
components: {
|
3251
3426
|
securitySchemes: versionedSecuritySchemes[OPENAPI_DEFAULT_VERSION]
|
@@ -3255,8 +3430,7 @@ function generateOpenApiDocument(serverUrls, serverDescriptions, versionedTags,
|
|
3255
3430
|
...serverUrls.map((url, index) => ({
|
3256
3431
|
url,
|
3257
3432
|
description: serverDescriptions?.[index]
|
3258
|
-
}))
|
3259
|
-
...otherServers || []
|
3433
|
+
}))
|
3260
3434
|
],
|
3261
3435
|
paths: versionedPaths[OPENAPI_DEFAULT_VERSION]
|
3262
3436
|
},
|
@@ -3266,8 +3440,10 @@ function generateOpenApiDocument(serverUrls, serverDescriptions, versionedTags,
|
|
3266
3440
|
{
|
3267
3441
|
openapi: "3.1.0",
|
3268
3442
|
info: {
|
3269
|
-
title: process.env.API_TITLE || "API Definition",
|
3270
|
-
version
|
3443
|
+
title: title || process.env.API_TITLE || "API Definition",
|
3444
|
+
version,
|
3445
|
+
description,
|
3446
|
+
contact
|
3271
3447
|
},
|
3272
3448
|
components: {
|
3273
3449
|
securitySchemes: versionedSecuritySchemes[version]
|
@@ -3277,8 +3453,7 @@ function generateOpenApiDocument(serverUrls, serverDescriptions, versionedTags,
|
|
3277
3453
|
...serverUrls.map((url, index) => ({
|
3278
3454
|
url,
|
3279
3455
|
description: serverDescriptions?.[index]
|
3280
|
-
}))
|
3281
|
-
...otherServers || []
|
3456
|
+
}))
|
3282
3457
|
],
|
3283
3458
|
paths
|
3284
3459
|
}
|
@@ -3382,11 +3557,11 @@ function generateOperationObject(schemaValidator, path, method, controllerName,
|
|
3382
3557
|
}
|
3383
3558
|
}
|
3384
3559
|
if (auth) {
|
3385
|
-
|
3560
|
+
coercedResponses[401] = {
|
3386
3561
|
description: httpStatusCodes_default[401],
|
3387
3562
|
content: contentResolver(schemaValidator, schemaValidator.string)
|
3388
3563
|
};
|
3389
|
-
|
3564
|
+
coercedResponses[403] = {
|
3390
3565
|
description: httpStatusCodes_default[403],
|
3391
3566
|
content: contentResolver(schemaValidator, schemaValidator.string)
|
3392
3567
|
};
|
@@ -3427,7 +3602,7 @@ function generateOperationObject(schemaValidator, path, method, controllerName,
|
|
3427
3602
|
}
|
3428
3603
|
return operationObject;
|
3429
3604
|
}
|
3430
|
-
function generateOpenApiSpecs(schemaValidator, serverUrls, serverDescriptions, application,
|
3605
|
+
function generateOpenApiSpecs(schemaValidator, serverUrls, serverDescriptions, application, appOptions) {
|
3431
3606
|
const versionedPaths = {
|
3432
3607
|
[OPENAPI_DEFAULT_VERSION]: {}
|
3433
3608
|
};
|
@@ -3451,7 +3626,10 @@ function generateOpenApiSpecs(schemaValidator, serverUrls, serverDescriptions, a
|
|
3451
3626
|
const openApiPath = openApiCompliantPath(
|
3452
3627
|
`${fullPath}${route.path === "/" ? "" : route.path}`
|
3453
3628
|
);
|
3454
|
-
const { name, summary, params, versions, auth } = route.contractDetails;
|
3629
|
+
const { name, summary, params, versions, auth, options: options2 } = route.contractDetails;
|
3630
|
+
if (!(options2?.openapi ?? router.routerOptions?.openapi ?? appOptions !== false)) {
|
3631
|
+
return;
|
3632
|
+
}
|
3455
3633
|
if (versions) {
|
3456
3634
|
for (const version of Object.keys(versions)) {
|
3457
3635
|
if (!versionedPaths[version]) {
|
@@ -3545,7 +3723,7 @@ function generateOpenApiSpecs(schemaValidator, serverUrls, serverDescriptions, a
|
|
3545
3723
|
versionedTags,
|
3546
3724
|
versionedPaths,
|
3547
3725
|
versionedSecuritySchemes,
|
3548
|
-
|
3726
|
+
appOptions
|
3549
3727
|
);
|
3550
3728
|
}
|
3551
3729
|
|
@@ -3613,11 +3791,11 @@ function mapToFetch(schemaValidator, routerMap) {
|
|
3613
3791
|
schemaValidator,
|
3614
3792
|
routerMap
|
3615
3793
|
);
|
3616
|
-
return (path, ...reqInit) => {
|
3794
|
+
return ((path, ...reqInit) => {
|
3617
3795
|
const method = reqInit[0]?.method;
|
3618
3796
|
const version = reqInit[0] != null && "version" in reqInit[0] ? reqInit[0].version : void 0;
|
3619
3797
|
return (version ? toRecord2(toRecord2(flattenedFetchMap[path])[method ?? "GET"])[version] : toRecord2(flattenedFetchMap[path])[method ?? "GET"])(path, reqInit[0]);
|
3620
|
-
};
|
3798
|
+
});
|
3621
3799
|
}
|
3622
3800
|
function sdkClient(schemaValidator, routerMap) {
|
3623
3801
|
return {
|
@@ -3700,6 +3878,7 @@ export {
|
|
3700
3878
|
isForklaunchRequest,
|
3701
3879
|
isForklaunchRouter,
|
3702
3880
|
isInformational,
|
3881
|
+
isPortBound,
|
3703
3882
|
isRedirection,
|
3704
3883
|
isServerError,
|
3705
3884
|
isSuccessful,
|