@fitzzero/quickdraw-core 3.5.0 → 3.7.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/README.md +113 -64
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.js +61 -66
- package/dist/client/index.js.map +1 -1
- package/dist/client/testing.d.ts +1 -1
- package/dist/client/testing.js.map +1 -1
- package/dist/server/express/index.d.ts +37 -0
- package/dist/server/express/index.js +60 -0
- package/dist/server/express/index.js.map +1 -0
- package/dist/server/index.d.ts +227 -1
- package/dist/server/index.js +400 -142
- package/dist/server/index.js.map +1 -1
- package/dist/server/testing-prisma.d.ts +101 -0
- package/dist/server/testing-prisma.js +172 -0
- package/dist/server/testing-prisma.js.map +1 -0
- package/dist/server/testing.js +5 -22
- package/dist/server/testing.js.map +1 -1
- package/dist/shared/index.js.map +1 -1
- package/dist/{types-BJj94_XW.d.ts → types-B1z5aXdR.d.ts} +11 -0
- package/eslint-config/index.mjs +1 -2
- package/eslint-plugin-quickdraw/index.mjs +15 -7
- package/eslint-plugin-quickdraw/rules/no-cross-service-mutations.mjs +31 -32
- package/eslint-plugin-quickdraw/rules/no-direct-prisma-mutations.mjs +17 -18
- package/eslint-plugin-quickdraw/rules/no-raw-button-strings.mjs +52 -0
- package/eslint-plugin-quickdraw/rules/no-raw-service-room-string.mjs +140 -0
- package/eslint-plugin-quickdraw/rules/no-raw-socket-emit.mjs +20 -22
- package/eslint-plugin-quickdraw/rules/no-raw-socket-on.mjs +17 -17
- package/eslint-plugin-quickdraw/rules/no-raw-tooltip-strings.mjs +59 -0
- package/eslint-plugin-quickdraw/rules/no-raw-typography-strings.mjs +52 -0
- package/eslint-plugin-quickdraw/rules/no-service-method-record.mjs +3 -3
- package/eslint-plugin-quickdraw/rules/no-unsafe-payload-cast.mjs +8 -8
- package/eslint-plugin-quickdraw/rules/require-zod-schema.mjs +15 -20
- package/package.json +74 -50
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ipKeyGenerator, rateLimit } from 'express-rate-limit';
|
|
2
|
+
|
|
3
|
+
// src/server/express/rateLimit.ts
|
|
4
|
+
function handler(_req, res, _next, options) {
|
|
5
|
+
const retryAfterSec = Math.max(1, Math.ceil((options.windowMs ?? 6e4) / 1e3));
|
|
6
|
+
if (!res.getHeader("Retry-After")) {
|
|
7
|
+
res.setHeader("Retry-After", String(retryAfterSec));
|
|
8
|
+
}
|
|
9
|
+
res.status(options.statusCode ?? 429).json({ error: "Rate limit exceeded" });
|
|
10
|
+
}
|
|
11
|
+
var jsonLimiter = {
|
|
12
|
+
standardHeaders: true,
|
|
13
|
+
legacyHeaders: false,
|
|
14
|
+
handler
|
|
15
|
+
};
|
|
16
|
+
function stripIp(raw) {
|
|
17
|
+
const ip = raw ?? "unknown";
|
|
18
|
+
return ip.startsWith("::ffff:") ? ip.slice(7) : ip;
|
|
19
|
+
}
|
|
20
|
+
function bearerOrIp(req) {
|
|
21
|
+
const auth = req.headers.authorization ?? "";
|
|
22
|
+
if (auth.startsWith("Bearer ")) return auth.slice(7);
|
|
23
|
+
return ipKeyGenerator(stripIp(req.ip));
|
|
24
|
+
}
|
|
25
|
+
function createJsonRateLimiter(options) {
|
|
26
|
+
return rateLimit({ ...jsonLimiter, ...options });
|
|
27
|
+
}
|
|
28
|
+
function createAuthLimiter(overrides = {}) {
|
|
29
|
+
return createJsonRateLimiter({
|
|
30
|
+
windowMs: 15 * 60 * 1e3,
|
|
31
|
+
max: 20,
|
|
32
|
+
skip: (req) => req.path.endsWith("/status"),
|
|
33
|
+
...overrides
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function createAuthStatusLimiter(overrides = {}) {
|
|
37
|
+
return createJsonRateLimiter({
|
|
38
|
+
windowMs: 15 * 60 * 1e3,
|
|
39
|
+
max: 120,
|
|
40
|
+
...overrides
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function createWebhookLimiter(overrides = {}) {
|
|
44
|
+
return createJsonRateLimiter({
|
|
45
|
+
windowMs: 60 * 1e3,
|
|
46
|
+
max: 300,
|
|
47
|
+
...overrides
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
function createPublicApiLimiter(overrides = {}) {
|
|
51
|
+
return createJsonRateLimiter({
|
|
52
|
+
windowMs: 60 * 1e3,
|
|
53
|
+
max: 60,
|
|
54
|
+
...overrides
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { bearerOrIp, createAuthLimiter, createAuthStatusLimiter, createJsonRateLimiter, createPublicApiLimiter, createWebhookLimiter, stripIp };
|
|
59
|
+
//# sourceMappingURL=index.js.map
|
|
60
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/server/express/rateLimit.ts"],"names":[],"mappings":";;;AAqBA,SAAS,OAAA,CAAQ,IAAA,EAAe,GAAA,EAAe,KAAA,EAAqB,OAAA,EAAwB;AAC1F,EAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,MAAM,OAAA,CAAQ,QAAA,IAAY,GAAA,IAAU,GAAI,CAAC,CAAA;AAChF,EAAA,IAAI,CAAC,GAAA,CAAI,SAAA,CAAU,aAAa,CAAA,EAAG;AACjC,IAAA,GAAA,CAAI,SAAA,CAAU,aAAA,EAAe,MAAA,CAAO,aAAa,CAAC,CAAA;AAAA,EACpD;AACA,EAAA,GAAA,CAAI,MAAA,CAAO,QAAQ,UAAA,IAAc,GAAG,EAAE,IAAA,CAAK,EAAE,KAAA,EAAO,qBAAA,EAAuB,CAAA;AAC7E;AAEA,IAAM,WAAA,GAA8B;AAAA,EAClC,eAAA,EAAiB,IAAA;AAAA,EACjB,aAAA,EAAe,KAAA;AAAA,EACf;AACF,CAAA;AAGO,SAAS,QAAQ,GAAA,EAAiC;AACvD,EAAA,MAAM,KAAK,GAAA,IAAO,SAAA;AAClB,EAAA,OAAO,GAAG,UAAA,CAAW,SAAS,IAAI,EAAA,CAAG,KAAA,CAAM,CAAC,CAAA,GAAI,EAAA;AAClD;AAOO,SAAS,WAAW,GAAA,EAAsB;AAC/C,EAAA,MAAM,IAAA,GAAO,GAAA,CAAI,OAAA,CAAQ,aAAA,IAAiB,EAAA;AAC1C,EAAA,IAAI,KAAK,UAAA,CAAW,SAAS,GAAG,OAAO,IAAA,CAAK,MAAM,CAAC,CAAA;AACnD,EAAA,OAAO,cAAA,CAAe,OAAA,CAAQ,GAAA,CAAI,EAAE,CAAC,CAAA;AACvC;AAKO,SAAS,sBAAsB,OAAA,EAAkD;AACtF,EAAA,OAAO,UAAU,EAAE,GAAG,WAAA,EAAa,GAAG,SAAS,CAAA;AACjD;AAGO,SAAS,iBAAA,CAAkB,SAAA,GAA4B,EAAC,EAA4B;AACzF,EAAA,OAAO,qBAAA,CAAsB;AAAA,IAC3B,QAAA,EAAU,KAAK,EAAA,GAAK,GAAA;AAAA,IACpB,GAAA,EAAK,EAAA;AAAA,IACL,MAAM,CAAC,GAAA,KAAQ,GAAA,CAAI,IAAA,CAAK,SAAS,SAAS,CAAA;AAAA,IAC1C,GAAG;AAAA,GACJ,CAAA;AACH;AAGO,SAAS,uBAAA,CAAwB,SAAA,GAA4B,EAAC,EAA4B;AAC/F,EAAA,OAAO,qBAAA,CAAsB;AAAA,IAC3B,QAAA,EAAU,KAAK,EAAA,GAAK,GAAA;AAAA,IACpB,GAAA,EAAK,GAAA;AAAA,IACL,GAAG;AAAA,GACJ,CAAA;AACH;AAGO,SAAS,oBAAA,CAAqB,SAAA,GAA4B,EAAC,EAA4B;AAC5F,EAAA,OAAO,qBAAA,CAAsB;AAAA,IAC3B,UAAU,EAAA,GAAK,GAAA;AAAA,IACf,GAAA,EAAK,GAAA;AAAA,IACL,GAAG;AAAA,GACJ,CAAA;AACH;AAGO,SAAS,sBAAA,CAAuB,SAAA,GAA4B,EAAC,EAA4B;AAC9F,EAAA,OAAO,qBAAA,CAAsB;AAAA,IAC3B,UAAU,EAAA,GAAK,GAAA;AAAA,IACf,GAAA,EAAK,EAAA;AAAA,IACL,GAAG;AAAA,GACJ,CAAA;AACH","file":"index.js","sourcesContent":["/**\n * Express rate-limit presets built on express-rate-limit.\n *\n * Lives in the dedicated `/server/express` subpath so the core `/server`\n * entry point carries no express-rate-limit dependency. All presets are\n * factories (not module-level singletons) so env/config is read at call time.\n *\n * Note: distinct from the Socket.IO `createRateLimiter` exported from\n * `/server` — these protect REST routes (OAuth, webhooks, public APIs).\n */\n\nimport type { NextFunction, Request, Response } from \"express\";\nimport {\n ipKeyGenerator,\n rateLimit,\n type Options,\n type RateLimitRequestHandler,\n} from \"express-rate-limit\";\n\ntype PartialOptions = Partial<Options>;\n\nfunction handler(_req: Request, res: Response, _next: NextFunction, options: Options): void {\n const retryAfterSec = Math.max(1, Math.ceil((options.windowMs ?? 60_000) / 1000));\n if (!res.getHeader(\"Retry-After\")) {\n res.setHeader(\"Retry-After\", String(retryAfterSec));\n }\n res.status(options.statusCode ?? 429).json({ error: \"Rate limit exceeded\" });\n}\n\nconst jsonLimiter: PartialOptions = {\n standardHeaders: true,\n legacyHeaders: false,\n handler,\n};\n\n/** Normalize IPv4-mapped IPv6 addresses (::ffff:1.2.3.4 → 1.2.3.4). */\nexport function stripIp(raw: string | undefined): string {\n const ip = raw ?? \"unknown\";\n return ip.startsWith(\"::ffff:\") ? ip.slice(7) : ip;\n}\n\n/**\n * Key by Bearer token when present, falling back to client IP. Lets\n * token-authenticated clients get their own bucket instead of sharing\n * a NAT'd IP.\n */\nexport function bearerOrIp(req: Request): string {\n const auth = req.headers.authorization ?? \"\";\n if (auth.startsWith(\"Bearer \")) return auth.slice(7);\n return ipKeyGenerator(stripIp(req.ip));\n}\n\n/**\n * Base factory: JSON 429 body + Retry-After header + standard headers.\n */\nexport function createJsonRateLimiter(options: PartialOptions): RateLimitRequestHandler {\n return rateLimit({ ...jsonLimiter, ...options });\n}\n\n/** OAuth flows: 20 requests / 15 min per IP (status sub-routes excluded). */\nexport function createAuthLimiter(overrides: PartialOptions = {}): RateLimitRequestHandler {\n return createJsonRateLimiter({\n windowMs: 15 * 60 * 1000,\n max: 20,\n skip: (req) => req.path.endsWith(\"/status\"),\n ...overrides,\n });\n}\n\n/** Auth status polling: 120 requests / 15 min per IP. */\nexport function createAuthStatusLimiter(overrides: PartialOptions = {}): RateLimitRequestHandler {\n return createJsonRateLimiter({\n windowMs: 15 * 60 * 1000,\n max: 120,\n ...overrides,\n });\n}\n\n/** Inbound webhooks: 300 requests / min per IP. */\nexport function createWebhookLimiter(overrides: PartialOptions = {}): RateLimitRequestHandler {\n return createJsonRateLimiter({\n windowMs: 60 * 1000,\n max: 300,\n ...overrides,\n });\n}\n\n/** Generic public API: 60 requests / min per IP. */\nexport function createPublicApiLimiter(overrides: PartialOptions = {}): RateLimitRequestHandler {\n return createJsonRateLimiter({\n windowMs: 60 * 1000,\n max: 60,\n ...overrides,\n });\n}\n"]}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -827,6 +827,10 @@ interface DiscordUser {
|
|
|
827
827
|
* Discord OAuth provider configuration.
|
|
828
828
|
*/
|
|
829
829
|
declare const discordProvider: OAuthProvider<DiscordUser>;
|
|
830
|
+
/**
|
|
831
|
+
* Get Discord avatar URL.
|
|
832
|
+
*/
|
|
833
|
+
declare function getDiscordAvatarUrl(user: DiscordUser): string;
|
|
830
834
|
|
|
831
835
|
/**
|
|
832
836
|
* Google user information.
|
|
@@ -843,6 +847,206 @@ interface GoogleUser {
|
|
|
843
847
|
*/
|
|
844
848
|
declare const googleProvider: OAuthProvider<GoogleUser>;
|
|
845
849
|
|
|
850
|
+
/**
|
|
851
|
+
* Mock OAuth provider for local development and tests.
|
|
852
|
+
*
|
|
853
|
+
* Implements a real OAuth 2.0 authorization-code flow served by the app's own
|
|
854
|
+
* API, so `createOAuthURL` and `exchangeOAuthCode` work unchanged — the mock
|
|
855
|
+
* is just a provider whose authorize/token/userinfo endpoints the app mounts
|
|
856
|
+
* via `registerMockOAuthProvider`. Users are supplied by the app (typically
|
|
857
|
+
* seeded demo accounts); no real credentials are involved.
|
|
858
|
+
*
|
|
859
|
+
* Production hard-block: routes are never mounted when NODE_ENV is
|
|
860
|
+
* "production" or ENABLE_MOCK_OAUTH !== "true", and every handler re-checks
|
|
861
|
+
* NODE_ENV at request time. Apps should add a third layer and refuse to boot
|
|
862
|
+
* in production with the flag set.
|
|
863
|
+
*/
|
|
864
|
+
|
|
865
|
+
interface MockOAuthUser {
|
|
866
|
+
id: string;
|
|
867
|
+
email: string;
|
|
868
|
+
name: string;
|
|
869
|
+
picture?: string | null;
|
|
870
|
+
}
|
|
871
|
+
declare const DEFAULT_MOCK_PATH_PREFIX = "/auth/mock/provider";
|
|
872
|
+
declare function isMockOAuthEnabled(): boolean;
|
|
873
|
+
interface MockOAuthProviderOptions {
|
|
874
|
+
/**
|
|
875
|
+
* Base URL the API server can use to reach itself for the token/userinfo
|
|
876
|
+
* exchange (server-side fetch). Defaults to apiBaseUrl — override in
|
|
877
|
+
* containers/codespaces where the public URL isn't self-reachable
|
|
878
|
+
* (e.g. "http://localhost:4000").
|
|
879
|
+
*/
|
|
880
|
+
internalBaseUrl?: string;
|
|
881
|
+
/** Route prefix for the mock endpoints. Default: "/auth/mock/provider". */
|
|
882
|
+
pathPrefix?: string;
|
|
883
|
+
}
|
|
884
|
+
/**
|
|
885
|
+
* Create the mock OAuth provider definition.
|
|
886
|
+
*
|
|
887
|
+
* `parseUserInfo` returns a GoogleUser-compatible shape with `id` set to the
|
|
888
|
+
* user's email, so `providerAccountId` stays stable across database re-seeds.
|
|
889
|
+
*/
|
|
890
|
+
declare function createMockOAuthProvider(apiBaseUrl: string, options?: MockOAuthProviderOptions): OAuthProvider<GoogleUser>;
|
|
891
|
+
interface MockRequest {
|
|
892
|
+
url?: string;
|
|
893
|
+
originalUrl?: string;
|
|
894
|
+
query?: Record<string, unknown>;
|
|
895
|
+
headers: Record<string, string | string[] | undefined>;
|
|
896
|
+
body?: unknown;
|
|
897
|
+
}
|
|
898
|
+
interface MockResponse {
|
|
899
|
+
status(code: number): MockResponse;
|
|
900
|
+
json(body: unknown): unknown;
|
|
901
|
+
send(body: string): unknown;
|
|
902
|
+
redirect(url: string): unknown;
|
|
903
|
+
}
|
|
904
|
+
type MockHandler = (req: MockRequest, res: MockResponse) => void | Promise<void>;
|
|
905
|
+
interface MockOAuthRouter {
|
|
906
|
+
get(path: string, handler: MockHandler): unknown;
|
|
907
|
+
post(path: string, handler: MockHandler): unknown;
|
|
908
|
+
}
|
|
909
|
+
interface RegisterMockOAuthOptions {
|
|
910
|
+
/**
|
|
911
|
+
* Supply the users shown in the dev login picker (typically seeded demo
|
|
912
|
+
* accounts). Injected so core never touches the app's database.
|
|
913
|
+
*/
|
|
914
|
+
listUsers: () => Promise<MockOAuthUser[]>;
|
|
915
|
+
/** Route prefix — must match createMockOAuthProvider's. */
|
|
916
|
+
pathPrefix?: string;
|
|
917
|
+
/**
|
|
918
|
+
* Extra origins allowed for redirect_uri beyond CLIENT_URL /
|
|
919
|
+
* EXTRA_ALLOWED_ORIGINS / localhost / private LAN IPs.
|
|
920
|
+
*/
|
|
921
|
+
allowedRedirectOrigins?: string[];
|
|
922
|
+
logger?: Logger;
|
|
923
|
+
}
|
|
924
|
+
/**
|
|
925
|
+
* Mount the mock OAuth provider endpoints (authorize, token, userinfo) on an
|
|
926
|
+
* Express-compatible router.
|
|
927
|
+
*
|
|
928
|
+
* No-ops (returning false) unless `isMockOAuthEnabled()` — i.e. in production
|
|
929
|
+
* or without ENABLE_MOCK_OAUTH=true the routes are never mounted.
|
|
930
|
+
*/
|
|
931
|
+
declare function registerMockOAuthProvider(router: MockOAuthRouter, options: RegisterMockOAuthOptions): boolean;
|
|
932
|
+
|
|
933
|
+
/**
|
|
934
|
+
* Origin validation utility for OAuth redirect and CORS security.
|
|
935
|
+
*/
|
|
936
|
+
declare const OAUTH_RETURN_ORIGIN_COOKIE = "oauth_return_origin";
|
|
937
|
+
interface ValidateOriginOptions {
|
|
938
|
+
/**
|
|
939
|
+
* The primary web client origin. Defaults to process.env.CLIENT_URL.
|
|
940
|
+
*/
|
|
941
|
+
clientUrl?: string;
|
|
942
|
+
/**
|
|
943
|
+
* Additional exact-match origins. Defaults to the comma-separated
|
|
944
|
+
* process.env.EXTRA_ALLOWED_ORIGINS. Lets a single API back multiple web
|
|
945
|
+
* hosts (e.g. prod + staging).
|
|
946
|
+
*/
|
|
947
|
+
extraAllowedOrigins?: string[];
|
|
948
|
+
/**
|
|
949
|
+
* App-specific origin patterns (e.g. preview-deploy subdomains).
|
|
950
|
+
*/
|
|
951
|
+
allowedPatterns?: RegExp[];
|
|
952
|
+
/**
|
|
953
|
+
* Allow GitHub Codespace forwarded-port origins
|
|
954
|
+
* (https://{workspace}-{username}-{port}.app.github.dev). Default: true.
|
|
955
|
+
*/
|
|
956
|
+
allowCodespaces?: boolean;
|
|
957
|
+
/**
|
|
958
|
+
* Allow http://localhost:* when NODE_ENV !== "production". Default: true.
|
|
959
|
+
*/
|
|
960
|
+
allowLocalhostInDev?: boolean;
|
|
961
|
+
}
|
|
962
|
+
/**
|
|
963
|
+
* Validates if an origin is safe for OAuth redirect / CORS.
|
|
964
|
+
*
|
|
965
|
+
* Only the origin (scheme + host + port) is compared, never the path, to
|
|
966
|
+
* prevent path-injection bypasses.
|
|
967
|
+
*
|
|
968
|
+
* @param origin - The origin to validate
|
|
969
|
+
* @param options - Override env-derived defaults
|
|
970
|
+
* @returns The validated origin if allowed, null otherwise
|
|
971
|
+
*/
|
|
972
|
+
declare function validateRedirectOrigin(origin: string, options?: ValidateOriginOptions): string | null;
|
|
973
|
+
|
|
974
|
+
/**
|
|
975
|
+
* Secure session cookie helpers.
|
|
976
|
+
*
|
|
977
|
+
* Uses a structural response type so the module works with Express (or any
|
|
978
|
+
* compatible framework) without a runtime/type dependency on it.
|
|
979
|
+
*/
|
|
980
|
+
declare const SESSION_COOKIE = "session";
|
|
981
|
+
interface CookieSettings {
|
|
982
|
+
httpOnly: boolean;
|
|
983
|
+
secure: boolean;
|
|
984
|
+
sameSite: "lax" | "none";
|
|
985
|
+
path: string;
|
|
986
|
+
domain?: string;
|
|
987
|
+
maxAge?: number;
|
|
988
|
+
}
|
|
989
|
+
interface CookieResponse {
|
|
990
|
+
cookie(name: string, value: string, options: CookieSettings): unknown;
|
|
991
|
+
clearCookie(name: string, options: CookieSettings): unknown;
|
|
992
|
+
}
|
|
993
|
+
interface SessionCookieOptions {
|
|
994
|
+
/** Cookie name. Default: "session". */
|
|
995
|
+
cookieName?: string;
|
|
996
|
+
/** Lifetime in ms. Default: 30 days. */
|
|
997
|
+
maxAgeMs?: number;
|
|
998
|
+
/** Cookie domain. Defaults to process.env.COOKIE_DOMAIN. */
|
|
999
|
+
domain?: string;
|
|
1000
|
+
}
|
|
1001
|
+
declare function setSessionCookie(res: CookieResponse, jwt: string, options?: SessionCookieOptions): void;
|
|
1002
|
+
declare function clearSessionCookie(res: CookieResponse, options?: SessionCookieOptions): void;
|
|
1003
|
+
|
|
1004
|
+
/**
|
|
1005
|
+
* REST authentication middleware factory.
|
|
1006
|
+
*
|
|
1007
|
+
* Authenticates requests via session cookie or Bearer token, verifies the JWT,
|
|
1008
|
+
* then checks session revocation via an injected lookup (the app owns the
|
|
1009
|
+
* database). Uses structural request/response types so there is no runtime or
|
|
1010
|
+
* type dependency on Express.
|
|
1011
|
+
*/
|
|
1012
|
+
interface AuthRequest {
|
|
1013
|
+
cookies?: Record<string, string>;
|
|
1014
|
+
headers: {
|
|
1015
|
+
authorization?: string;
|
|
1016
|
+
};
|
|
1017
|
+
userId?: string;
|
|
1018
|
+
}
|
|
1019
|
+
interface AuthResponse {
|
|
1020
|
+
status(code: number): {
|
|
1021
|
+
json(body: unknown): unknown;
|
|
1022
|
+
};
|
|
1023
|
+
}
|
|
1024
|
+
interface RequireAuthOptions {
|
|
1025
|
+
/**
|
|
1026
|
+
* Look up the session for a token. Return null when the session does not
|
|
1027
|
+
* exist; sessions past expiresAt are rejected. This mirrors the socket auth
|
|
1028
|
+
* path so a revoked/logged-out session can no longer authenticate REST
|
|
1029
|
+
* requests until the JWT naturally expires.
|
|
1030
|
+
*/
|
|
1031
|
+
getSession: (token: string) => Promise<{
|
|
1032
|
+
expiresAt: Date;
|
|
1033
|
+
} | null>;
|
|
1034
|
+
/** JWT signing secret. Defaults to process.env.JWT_SECRET. */
|
|
1035
|
+
jwtSecret?: string;
|
|
1036
|
+
/** Cookie to read the JWT from. Default: "session". */
|
|
1037
|
+
cookieName?: string;
|
|
1038
|
+
}
|
|
1039
|
+
/**
|
|
1040
|
+
* Extract a JWT from the session cookie or Authorization header
|
|
1041
|
+
* (cookie takes priority).
|
|
1042
|
+
*/
|
|
1043
|
+
declare function extractBearerOrCookieToken(req: AuthRequest, cookieName?: string): string | null;
|
|
1044
|
+
/**
|
|
1045
|
+
* Create an Express-compatible middleware that attaches req.userId on success
|
|
1046
|
+
* and responds 401 on failure.
|
|
1047
|
+
*/
|
|
1048
|
+
declare function createRequireAuth(options: RequireAuthOptions): (req: AuthRequest, res: AuthResponse, next: () => void) => Promise<void>;
|
|
1049
|
+
|
|
846
1050
|
/**
|
|
847
1051
|
* Environment variable validation utilities.
|
|
848
1052
|
* Helps ensure required environment variables are set before the application starts.
|
|
@@ -927,6 +1131,28 @@ declare function checkEnv(options: ValidateEnvOptions): EnvValidationResult;
|
|
|
927
1131
|
*/
|
|
928
1132
|
declare function requireEnv(name: string, defaultValue?: string): string;
|
|
929
1133
|
|
|
1134
|
+
/**
|
|
1135
|
+
* AES-256-GCM encryption helpers for at-rest secrets (e.g. stored OAuth tokens).
|
|
1136
|
+
*
|
|
1137
|
+
* Requires ENCRYPTION_KEY: a 64-character hex string (32 bytes).
|
|
1138
|
+
* Ciphertext format: "iv:authTag:ciphertext" (all hex).
|
|
1139
|
+
*/
|
|
1140
|
+
|
|
1141
|
+
declare function encrypt(plaintext: string): string;
|
|
1142
|
+
declare function decrypt(ciphertext: string): string;
|
|
1143
|
+
/**
|
|
1144
|
+
* Returns true when the value looks like AES-256-GCM ciphertext
|
|
1145
|
+
* (iv:authTag:data, all hex). Plaintext OAuth tokens (e.g. gho_xxx) will not match.
|
|
1146
|
+
*/
|
|
1147
|
+
declare function isEncrypted(value: string): boolean;
|
|
1148
|
+
/**
|
|
1149
|
+
* Decrypt if the value is in encrypted format, otherwise return as-is.
|
|
1150
|
+
* Allows graceful handling of pre-migration plaintext tokens.
|
|
1151
|
+
*/
|
|
1152
|
+
declare function decryptIfEncrypted(value: string): string;
|
|
1153
|
+
/** Safe wrapper that returns `null` instead of throwing on invalid/stale ciphertext. */
|
|
1154
|
+
declare function tryDecrypt(ciphertext: string, logger?: Logger): string | null;
|
|
1155
|
+
|
|
930
1156
|
/**
|
|
931
1157
|
* Options for customizing field generation.
|
|
932
1158
|
*/
|
|
@@ -1106,4 +1332,4 @@ declare function createMcpRoutes(router: Router, options: McpHttpRoutesOptions):
|
|
|
1106
1332
|
*/
|
|
1107
1333
|
declare function generateToolMetadata(options: GenerateToolMetadataOptions): void;
|
|
1108
1334
|
|
|
1109
|
-
export { AdminListPayload, AdminListResponse, AdminSetACLPayload, AdminSubscribersResponse, BaseService, BaseServiceInstance, BaseServiceOptions, type DiscordUser, type EnvValidationResult, type GenerateToolMetadataOptions, type GoogleUser, InstallAdminMethodsOptions, type JWTPayload, type McpHttpRoutesOptions, ServiceMethodContext as McpMethodContext, ServiceMethodDefinition as McpMethodDefinition, McpRegistry, type McpRegistryInstance, type McpRegistryOptions, type McpServiceInstance, type McpStdioServerOptions, type McpToolDefinition, type MethodSpec, type OAuthConfig, type OAuthProvider, type OAuthTokenResponse, PrismaDelegate, QuickdrawServerOptions, QuickdrawServerResult, QuickdrawSocket, type RateLimitOptions, type RateLimiter, type RedisAdapterOptions, type RedisAdapterResult, type ServiceInfo, type ServiceMethodInfo, ServiceRegistry, ServiceRegistryInstance, type ServiceRegistryOptions, type ServiceToolSpec, type ValidateEnvOptions, type ZodToAdminFieldsOptions, applyRateLimitMiddleware, bootstrapMcpServer, checkEnv, createJWT, createMcpRoutes, createMcpStdioServer, createOAuthURL, createQuickdrawServer, createRateLimiter, createTieredRateLimiter, discordProvider, exchangeOAuthCode, generateToolMetadata, getDefaultEntityFields, googleProvider, isRedisAdapterAvailable, mergeWithDefaultFields, requireEnv, setupRedisAdapter, validateEnv, verifyJWT, zodToAdminFields };
|
|
1335
|
+
export { AdminListPayload, AdminListResponse, AdminSetACLPayload, AdminSubscribersResponse, type AuthRequest, type AuthResponse, BaseService, BaseServiceInstance, BaseServiceOptions, type CookieResponse, type CookieSettings, DEFAULT_MOCK_PATH_PREFIX, type DiscordUser, type EnvValidationResult, type GenerateToolMetadataOptions, type GoogleUser, InstallAdminMethodsOptions, type JWTPayload, type McpHttpRoutesOptions, ServiceMethodContext as McpMethodContext, ServiceMethodDefinition as McpMethodDefinition, McpRegistry, type McpRegistryInstance, type McpRegistryOptions, type McpServiceInstance, type McpStdioServerOptions, type McpToolDefinition, type MethodSpec, type MockOAuthProviderOptions, type MockOAuthRouter, type MockOAuthUser, OAUTH_RETURN_ORIGIN_COOKIE, type OAuthConfig, type OAuthProvider, type OAuthTokenResponse, PrismaDelegate, QuickdrawServerOptions, QuickdrawServerResult, QuickdrawSocket, type RateLimitOptions, type RateLimiter, type RedisAdapterOptions, type RedisAdapterResult, type RegisterMockOAuthOptions, type RequireAuthOptions, SESSION_COOKIE, type ServiceInfo, type ServiceMethodInfo, ServiceRegistry, ServiceRegistryInstance, type ServiceRegistryOptions, type ServiceToolSpec, type SessionCookieOptions, type ValidateEnvOptions, type ValidateOriginOptions, type ZodToAdminFieldsOptions, applyRateLimitMiddleware, bootstrapMcpServer, checkEnv, clearSessionCookie, createJWT, createMcpRoutes, createMcpStdioServer, createMockOAuthProvider, createOAuthURL, createQuickdrawServer, createRateLimiter, createRequireAuth, createTieredRateLimiter, decrypt, decryptIfEncrypted, discordProvider, encrypt, exchangeOAuthCode, extractBearerOrCookieToken, generateToolMetadata, getDefaultEntityFields, getDiscordAvatarUrl, googleProvider, isEncrypted, isMockOAuthEnabled, isRedisAdapterAvailable, mergeWithDefaultFields, registerMockOAuthProvider, requireEnv, setSessionCookie, setupRedisAdapter, tryDecrypt, validateEnv, validateRedirectOrigin, verifyJWT, zodToAdminFields };
|