@forklaunch/core 0.14.9 → 0.14.11-beta.1
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 +125 -74
- package/lib/http/index.d.ts +125 -74
- package/lib/http/index.js +86 -28
- package/lib/http/index.js.map +1 -1
- package/lib/http/index.mjs +88 -28
- package/lib/http/index.mjs.map +1 -1
- package/package.json +9 -9
package/lib/http/index.mjs
CHANGED
@@ -81,6 +81,9 @@ function isTypedHandler(maybeTypedHandler) {
|
|
81
81
|
|
82
82
|
// src/http/middleware/request/auth.middleware.ts
|
83
83
|
import { isNever } from "@forklaunch/common";
|
84
|
+
import {
|
85
|
+
prettyPrintParseErrors
|
86
|
+
} from "@forklaunch/validator";
|
84
87
|
|
85
88
|
// src/http/discriminateAuthMethod.ts
|
86
89
|
import { jwtVerify } from "jose";
|
@@ -99,10 +102,12 @@ function createHmacToken({
|
|
99
102
|
const hmac = createHmac("sha256", secretKey);
|
100
103
|
const bodyString = body ? `${safeStringify(body)}
|
101
104
|
` : void 0;
|
102
|
-
hmac.update(
|
105
|
+
hmac.update(
|
106
|
+
`${method}
|
103
107
|
${path}
|
104
|
-
${bodyString}${timestamp}
|
105
|
-
${nonce}`
|
108
|
+
${bodyString}${timestamp.toISOString()}
|
109
|
+
${nonce}`
|
110
|
+
);
|
106
111
|
return hmac.digest("base64");
|
107
112
|
}
|
108
113
|
|
@@ -122,6 +127,12 @@ function isJwtAuthMethod(maybeJwtAuthMethod) {
|
|
122
127
|
}
|
123
128
|
|
124
129
|
// src/http/discriminateAuthMethod.ts
|
130
|
+
var DEFAULT_TTL = 60 * 1e3 * 5;
|
131
|
+
var memoizedJwks = {
|
132
|
+
value: null,
|
133
|
+
lastUpdated: null,
|
134
|
+
ttl: DEFAULT_TTL
|
135
|
+
};
|
125
136
|
async function discriminateAuthMethod(auth) {
|
126
137
|
let authMethod;
|
127
138
|
if (isBasicAuthMethod(auth)) {
|
@@ -146,8 +157,17 @@ async function discriminateAuthMethod(auth) {
|
|
146
157
|
} else {
|
147
158
|
let jwks;
|
148
159
|
if ("jwksPublicKeyUrl" in jwt) {
|
149
|
-
|
150
|
-
|
160
|
+
if (memoizedJwks.value && memoizedJwks.lastUpdated && Date.now() - memoizedJwks.lastUpdated.getTime() < memoizedJwks.ttl) {
|
161
|
+
jwks = memoizedJwks.value;
|
162
|
+
} else {
|
163
|
+
const jwksResponse = await fetch(jwt.jwksPublicKeyUrl);
|
164
|
+
jwks = (await jwksResponse.json()).keys;
|
165
|
+
memoizedJwks.value = jwks;
|
166
|
+
memoizedJwks.lastUpdated = /* @__PURE__ */ new Date();
|
167
|
+
memoizedJwks.ttl = parseInt(
|
168
|
+
jwksResponse.headers.get("cache-control")?.split("=")[1] ?? `${DEFAULT_TTL / 1e3}`
|
169
|
+
) * 1e3;
|
170
|
+
}
|
151
171
|
} else if ("jwksPublicKey" in jwt) {
|
152
172
|
jwks = [jwt.jwksPublicKey];
|
153
173
|
}
|
@@ -157,6 +177,9 @@ async function discriminateAuthMethod(auth) {
|
|
157
177
|
const { payload } = await jwtVerify(token, key);
|
158
178
|
return payload;
|
159
179
|
} catch {
|
180
|
+
memoizedJwks.value = null;
|
181
|
+
memoizedJwks.lastUpdated = null;
|
182
|
+
memoizedJwks.ttl = DEFAULT_TTL;
|
160
183
|
continue;
|
161
184
|
}
|
162
185
|
}
|
@@ -260,7 +283,7 @@ function parseHmacTokenPart(part, expectedKey) {
|
|
260
283
|
if (key !== expectedKey || rest.length === 0) return void 0;
|
261
284
|
return rest.join("=");
|
262
285
|
}
|
263
|
-
async function checkAuthorizationToken(
|
286
|
+
async function checkAuthorizationToken(req, authorizationMethod, authorizationToken, globalOptions) {
|
264
287
|
if (authorizationMethod == null) {
|
265
288
|
return void 0;
|
266
289
|
}
|
@@ -275,7 +298,7 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
275
298
|
if (!tokenParts.length || !tokenPrefix) {
|
276
299
|
return invalidAuthorizationTokenFormat;
|
277
300
|
}
|
278
|
-
let
|
301
|
+
let sessionPayload;
|
279
302
|
const { type, auth } = await discriminateAuthMethod(
|
280
303
|
collapsedAuthorizationMethod
|
281
304
|
);
|
@@ -299,7 +322,7 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
299
322
|
method: req?.method ?? "",
|
300
323
|
path: req?.path ?? "",
|
301
324
|
body: req?.body,
|
302
|
-
timestamp: parsedTimestamp,
|
325
|
+
timestamp: new Date(parsedTimestamp),
|
303
326
|
nonce: parsedNonce,
|
304
327
|
signature: parsedSignature,
|
305
328
|
secretKey: collapsedAuthorizationMethod.hmac.secretKeys[parsedKeyId]
|
@@ -307,7 +330,7 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
307
330
|
if (!verificationResult) {
|
308
331
|
return invalidAuthorizationSignature;
|
309
332
|
}
|
310
|
-
|
333
|
+
sessionPayload = null;
|
311
334
|
break;
|
312
335
|
}
|
313
336
|
case "jwt": {
|
@@ -320,7 +343,7 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
320
343
|
if (!decodedJwt) {
|
321
344
|
return invalidAuthorizationToken;
|
322
345
|
}
|
323
|
-
|
346
|
+
sessionPayload = decodedJwt;
|
324
347
|
} catch (error) {
|
325
348
|
req?.openTelemetryCollector.error(error);
|
326
349
|
return invalidAuthorizationToken;
|
@@ -333,7 +356,7 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
333
356
|
return invalidAuthorizationTokenFormat;
|
334
357
|
}
|
335
358
|
if (auth.decodeResource) {
|
336
|
-
|
359
|
+
sessionPayload = await auth.decodeResource(token);
|
337
360
|
} else {
|
338
361
|
const [username, password] = Buffer.from(token, "base64").toString("utf-8").split(":");
|
339
362
|
if (!username || !password) {
|
@@ -342,7 +365,7 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
342
365
|
if (!auth.login(username, password)) {
|
343
366
|
return invalidAuthorizationLogin;
|
344
367
|
}
|
345
|
-
|
368
|
+
sessionPayload = {
|
346
369
|
sub: username
|
347
370
|
};
|
348
371
|
}
|
@@ -352,16 +375,29 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
352
375
|
isNever(type);
|
353
376
|
return [401, "Invalid Authorization method."];
|
354
377
|
}
|
355
|
-
if (isHmacMethod(collapsedAuthorizationMethod) &&
|
378
|
+
if (isHmacMethod(collapsedAuthorizationMethod) && sessionPayload == null) {
|
356
379
|
return;
|
357
380
|
}
|
358
|
-
if (
|
381
|
+
if (sessionPayload == null) {
|
359
382
|
return invalidAuthorizationToken;
|
360
383
|
}
|
384
|
+
req.session = sessionPayload;
|
385
|
+
if (collapsedAuthorizationMethod.sessionSchema) {
|
386
|
+
const parsedSession = req.schemaValidator.parse(
|
387
|
+
collapsedAuthorizationMethod.sessionSchema,
|
388
|
+
sessionPayload
|
389
|
+
);
|
390
|
+
if (!parsedSession.ok) {
|
391
|
+
return [
|
392
|
+
400,
|
393
|
+
`Invalid session: ${prettyPrintParseErrors(parsedSession.errors, "Session")}`
|
394
|
+
];
|
395
|
+
}
|
396
|
+
}
|
361
397
|
if (hasScopeChecks(collapsedAuthorizationMethod)) {
|
362
398
|
if (collapsedAuthorizationMethod.surfaceScopes) {
|
363
399
|
const resourceScopes = await collapsedAuthorizationMethod.surfaceScopes(
|
364
|
-
|
400
|
+
sessionPayload,
|
365
401
|
req
|
366
402
|
);
|
367
403
|
if (collapsedAuthorizationMethod.scopeHeirarchy) {
|
@@ -380,7 +416,7 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
380
416
|
return [500, "No permission surfacing function provided."];
|
381
417
|
}
|
382
418
|
const resourcePermissions = await collapsedAuthorizationMethod.surfacePermissions(
|
383
|
-
|
419
|
+
sessionPayload,
|
384
420
|
req
|
385
421
|
);
|
386
422
|
if ("allowedPermissions" in collapsedAuthorizationMethod && collapsedAuthorizationMethod.allowedPermissions) {
|
@@ -402,7 +438,7 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
402
438
|
return [500, "No role surfacing function provided."];
|
403
439
|
}
|
404
440
|
const resourceRoles = await collapsedAuthorizationMethod.surfaceRoles(
|
405
|
-
|
441
|
+
sessionPayload,
|
406
442
|
req
|
407
443
|
);
|
408
444
|
if ("allowedRoles" in collapsedAuthorizationMethod && collapsedAuthorizationMethod.allowedRoles) {
|
@@ -422,10 +458,10 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
422
458
|
async function parseRequestAuth(req, res, next) {
|
423
459
|
const auth = req.contractDetails.auth;
|
424
460
|
const [error, message] = await checkAuthorizationToken(
|
461
|
+
req,
|
425
462
|
auth,
|
426
|
-
req._globalOptions?.()?.auth,
|
427
463
|
req.headers[auth?.headerName ?? "Authorization"] || req.headers[auth?.headerName ?? "authorization"],
|
428
|
-
req
|
464
|
+
req._globalOptions?.()?.auth
|
429
465
|
) ?? [];
|
430
466
|
if (error != null) {
|
431
467
|
res.type("text/plain");
|
@@ -804,7 +840,7 @@ function enrichDetails(path, contractDetails, requestSchema, responseSchemas, op
|
|
804
840
|
// src/http/middleware/request/parse.middleware.ts
|
805
841
|
import { isRecord } from "@forklaunch/common";
|
806
842
|
import {
|
807
|
-
prettyPrintParseErrors
|
843
|
+
prettyPrintParseErrors as prettyPrintParseErrors2
|
808
844
|
} from "@forklaunch/validator";
|
809
845
|
|
810
846
|
// src/http/guards/hasSend.ts
|
@@ -843,7 +879,7 @@ function parse(req, res, next) {
|
|
843
879
|
req.version = version;
|
844
880
|
res.version = req.version;
|
845
881
|
} else {
|
846
|
-
runningParseErrors +=
|
882
|
+
runningParseErrors += prettyPrintParseErrors2(
|
847
883
|
parsingResult.errors,
|
848
884
|
`Version ${version} request`
|
849
885
|
);
|
@@ -901,7 +937,7 @@ function parse(req, res, next) {
|
|
901
937
|
res.status(400);
|
902
938
|
if (hasSend(res)) {
|
903
939
|
res.send(
|
904
|
-
`${collectedParseErrors ??
|
940
|
+
`${collectedParseErrors ?? prettyPrintParseErrors2(parsedRequest.errors, "Request")}
|
905
941
|
|
906
942
|
Correlation id: ${req.context.correlationId ?? "No correlation ID"}`
|
907
943
|
);
|
@@ -911,7 +947,7 @@ Correlation id: ${req.context.correlationId ?? "No correlation ID"}`
|
|
911
947
|
return;
|
912
948
|
case "warning":
|
913
949
|
req.openTelemetryCollector.warn(
|
914
|
-
collectedParseErrors ??
|
950
|
+
collectedParseErrors ?? prettyPrintParseErrors2(parsedRequest.errors, "Request")
|
915
951
|
);
|
916
952
|
break;
|
917
953
|
case "none":
|
@@ -3196,7 +3232,7 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
|
|
3196
3232
|
|
3197
3233
|
// src/http/middleware/response/parse.middleware.ts
|
3198
3234
|
import {
|
3199
|
-
prettyPrintParseErrors as
|
3235
|
+
prettyPrintParseErrors as prettyPrintParseErrors3
|
3200
3236
|
} from "@forklaunch/validator";
|
3201
3237
|
|
3202
3238
|
// src/http/guards/isResponseCompiledSchema.ts
|
@@ -3258,13 +3294,13 @@ function parse2(req, res, next) {
|
|
3258
3294
|
);
|
3259
3295
|
const parseErrors = [];
|
3260
3296
|
if (!parsedHeaders.ok) {
|
3261
|
-
const headerErrors =
|
3297
|
+
const headerErrors = prettyPrintParseErrors3(parsedHeaders.errors, "Header");
|
3262
3298
|
if (headerErrors) {
|
3263
3299
|
parseErrors.push(headerErrors);
|
3264
3300
|
}
|
3265
3301
|
}
|
3266
3302
|
if (!parsedResponse.ok) {
|
3267
|
-
const responseErrors =
|
3303
|
+
const responseErrors = prettyPrintParseErrors3(
|
3268
3304
|
parsedResponse.errors,
|
3269
3305
|
"Response"
|
3270
3306
|
);
|
@@ -3889,12 +3925,36 @@ function mapToFetch(schemaValidator, routerMap) {
|
|
3889
3925
|
return (version ? toRecord2(toRecord2(flattenedFetchMap[path])[method ?? "GET"])[version] : toRecord2(flattenedFetchMap[path])[method ?? "GET"])(path, reqInit[0]);
|
3890
3926
|
});
|
3891
3927
|
}
|
3892
|
-
function sdkClient(schemaValidator, routerMap) {
|
3893
|
-
|
3928
|
+
function sdkClient(schemaValidator, routerMap, options2) {
|
3929
|
+
if (options2?.lazyEvaluation) {
|
3930
|
+
let _sdk;
|
3931
|
+
let _fetch;
|
3932
|
+
const lazyClient = {
|
3933
|
+
_finalizedSdk: true,
|
3934
|
+
get sdk() {
|
3935
|
+
if (!_sdk) {
|
3936
|
+
_sdk = mapToSdk(schemaValidator, routerMap);
|
3937
|
+
}
|
3938
|
+
return _sdk;
|
3939
|
+
},
|
3940
|
+
get fetch() {
|
3941
|
+
if (!_fetch) {
|
3942
|
+
_fetch = mapToFetch(schemaValidator, routerMap);
|
3943
|
+
}
|
3944
|
+
return _fetch;
|
3945
|
+
}
|
3946
|
+
};
|
3947
|
+
return lazyClient;
|
3948
|
+
}
|
3949
|
+
const client = {
|
3894
3950
|
_finalizedSdk: true,
|
3895
3951
|
sdk: mapToSdk(schemaValidator, routerMap),
|
3896
3952
|
fetch: mapToFetch(schemaValidator, routerMap)
|
3897
3953
|
};
|
3954
|
+
if (options2?.optimizePerformance) {
|
3955
|
+
return client;
|
3956
|
+
}
|
3957
|
+
return client;
|
3898
3958
|
}
|
3899
3959
|
|
3900
3960
|
// src/http/sdk/sdkRouter.ts
|