@nestjs-kit/better-auth 0.0.0-stage → 2.0.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/LICENSE +7 -0
- package/README.md +1078 -2
- package/dist/admin.cjs +88 -0
- package/dist/admin.cjs.map +1 -0
- package/dist/admin.d.cts +14 -0
- package/dist/admin.d.cts.map +1 -0
- package/dist/admin.d.mts +14 -0
- package/dist/admin.d.mts.map +1 -0
- package/dist/admin.mjs +85 -0
- package/dist/admin.mjs.map +1 -0
- package/dist/api-key.cjs +164 -0
- package/dist/api-key.cjs.map +1 -0
- package/dist/api-key.d.cts +42 -0
- package/dist/api-key.d.cts.map +1 -0
- package/dist/api-key.d.mts +42 -0
- package/dist/api-key.d.mts.map +1 -0
- package/dist/api-key.mjs +160 -0
- package/dist/api-key.mjs.map +1 -0
- package/dist/auth-contracts-Brh_Qko9.d.cts +1654 -0
- package/dist/auth-contracts-Brh_Qko9.d.cts.map +1 -0
- package/dist/auth-contracts-Cz7C4_Ch.d.mts +1654 -0
- package/dist/auth-contracts-Cz7C4_Ch.d.mts.map +1 -0
- package/dist/auth-decorators-B1mFnGJ6.mjs +284 -0
- package/dist/auth-decorators-B1mFnGJ6.mjs.map +1 -0
- package/dist/auth-decorators-Cu_nxWnF.cjs +421 -0
- package/dist/auth-decorators-Cu_nxWnF.cjs.map +1 -0
- package/dist/auth-errors-C3rbTV9p.mjs +301 -0
- package/dist/auth-errors-C3rbTV9p.mjs.map +1 -0
- package/dist/auth-errors-DmiKl0L_.cjs +378 -0
- package/dist/auth-errors-DmiKl0L_.cjs.map +1 -0
- package/dist/auth-guard-CLyhAEEj.cjs +136 -0
- package/dist/auth-guard-CLyhAEEj.cjs.map +1 -0
- package/dist/auth-guard-h9QB_l11.mjs +125 -0
- package/dist/auth-guard-h9QB_l11.mjs.map +1 -0
- package/dist/auth-module-BgcY2HpA.cjs +2809 -0
- package/dist/auth-module-BgcY2HpA.cjs.map +1 -0
- package/dist/auth-module-CtHx3gRU.mjs +2708 -0
- package/dist/auth-module-CtHx3gRU.mjs.map +1 -0
- package/dist/auth-scope-interceptor-BjxAL1-S.cjs +290 -0
- package/dist/auth-scope-interceptor-BjxAL1-S.cjs.map +1 -0
- package/dist/auth-scope-interceptor-DYPn3b8M.mjs +231 -0
- package/dist/auth-scope-interceptor-DYPn3b8M.mjs.map +1 -0
- package/dist/bridge-protocol-BDw8opAG.cjs +25 -0
- package/dist/bridge-protocol-BDw8opAG.cjs.map +1 -0
- package/dist/bridge-protocol-c66aEkr5.mjs +8 -0
- package/dist/bridge-protocol-c66aEkr5.mjs.map +1 -0
- package/dist/decorate-Cr4Q7bNE.cjs +319 -0
- package/dist/decorate-Cr4Q7bNE.cjs.map +1 -0
- package/dist/decorate-Dt0e9K6R.mjs +80 -0
- package/dist/decorate-Dt0e9K6R.mjs.map +1 -0
- package/dist/express.cjs +256 -0
- package/dist/express.cjs.map +1 -0
- package/dist/express.d.cts +37 -0
- package/dist/express.d.cts.map +1 -0
- package/dist/express.d.mts +37 -0
- package/dist/express.d.mts.map +1 -0
- package/dist/express.mjs +254 -0
- package/dist/express.mjs.map +1 -0
- package/dist/fastify.cjs +218 -0
- package/dist/fastify.cjs.map +1 -0
- package/dist/fastify.d.cts +28 -0
- package/dist/fastify.d.cts.map +1 -0
- package/dist/fastify.d.mts +28 -0
- package/dist/fastify.d.mts.map +1 -0
- package/dist/fastify.mjs +216 -0
- package/dist/fastify.mjs.map +1 -0
- package/dist/graphql.cjs +509 -0
- package/dist/graphql.cjs.map +1 -0
- package/dist/graphql.d.cts +38 -0
- package/dist/graphql.d.cts.map +1 -0
- package/dist/graphql.d.mts +38 -0
- package/dist/graphql.d.mts.map +1 -0
- package/dist/graphql.mjs +503 -0
- package/dist/graphql.mjs.map +1 -0
- package/dist/index.cjs +86 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +8 -0
- package/dist/microservices.cjs +231 -0
- package/dist/microservices.cjs.map +1 -0
- package/dist/microservices.d.cts +39 -0
- package/dist/microservices.d.cts.map +1 -0
- package/dist/microservices.d.mts +39 -0
- package/dist/microservices.d.mts.map +1 -0
- package/dist/microservices.mjs +222 -0
- package/dist/microservices.mjs.map +1 -0
- package/dist/organization.cjs +191 -0
- package/dist/organization.cjs.map +1 -0
- package/dist/organization.d.cts +40 -0
- package/dist/organization.d.cts.map +1 -0
- package/dist/organization.d.mts +40 -0
- package/dist/organization.d.mts.map +1 -0
- package/dist/organization.mjs +177 -0
- package/dist/organization.mjs.map +1 -0
- package/dist/platform-CZl7TY8j.mjs +414 -0
- package/dist/platform-CZl7TY8j.mjs.map +1 -0
- package/dist/platform-YICqqYv6.cjs +473 -0
- package/dist/platform-YICqqYv6.cjs.map +1 -0
- package/dist/platform.cjs +10 -0
- package/dist/platform.d.cts +43 -0
- package/dist/platform.d.cts.map +1 -0
- package/dist/platform.d.mts +43 -0
- package/dist/platform.d.mts.map +1 -0
- package/dist/platform.mjs +1 -0
- package/dist/plugin.cjs +323 -0
- package/dist/plugin.cjs.map +1 -0
- package/dist/plugin.d.cts +24 -0
- package/dist/plugin.d.cts.map +1 -0
- package/dist/plugin.d.mts +24 -0
- package/dist/plugin.d.mts.map +1 -0
- package/dist/plugin.mjs +321 -0
- package/dist/plugin.mjs.map +1 -0
- package/dist/principal-readings-Chmt6rQV.cjs +208 -0
- package/dist/principal-readings-Chmt6rQV.cjs.map +1 -0
- package/dist/principal-readings-Ied2staw.mjs +191 -0
- package/dist/principal-readings-Ied2staw.mjs.map +1 -0
- package/dist/rolldown-runtime-VH7oDXx4.cjs +28 -0
- package/dist/testing/conformance.cjs +6214 -0
- package/dist/testing/conformance.cjs.map +1 -0
- package/dist/testing/conformance.d.cts +528 -0
- package/dist/testing/conformance.d.cts.map +1 -0
- package/dist/testing/conformance.d.mts +528 -0
- package/dist/testing/conformance.d.mts.map +1 -0
- package/dist/testing/conformance.mjs +6204 -0
- package/dist/testing/conformance.mjs.map +1 -0
- package/dist/testing.cjs +221 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +64 -0
- package/dist/testing.d.cts.map +1 -0
- package/dist/testing.d.mts +64 -0
- package/dist/testing.d.mts.map +1 -0
- package/dist/testing.mjs +214 -0
- package/dist/testing.mjs.map +1 -0
- package/dist/websockets.cjs +396 -0
- package/dist/websockets.cjs.map +1 -0
- package/dist/websockets.d.cts +67 -0
- package/dist/websockets.d.cts.map +1 -0
- package/dist/websockets.d.mts +67 -0
- package/dist/websockets.d.mts.map +1 -0
- package/dist/websockets.mjs +383 -0
- package/dist/websockets.mjs.map +1 -0
- package/package.json +327 -3
package/dist/express.cjs
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_auth_errors = require("./auth-errors-DmiKl0L_.cjs");
|
|
3
|
+
const require_platform = require("./platform-YICqqYv6.cjs");
|
|
4
|
+
let node_http = require("node:http");
|
|
5
|
+
let node_stream = require("node:stream");
|
|
6
|
+
let path_to_regexp = require("path-to-regexp");
|
|
7
|
+
//#region src/express-platform.ts
|
|
8
|
+
const RAW_BODY = Symbol.for("@nestjs-kit/better-auth:raw-body");
|
|
9
|
+
function application(adapter) {
|
|
10
|
+
return adapter.getInstance();
|
|
11
|
+
}
|
|
12
|
+
function routerOptions(app) {
|
|
13
|
+
const router = app?.router;
|
|
14
|
+
if (typeof router !== "object" && typeof router !== "function" || router === null) throw new require_auth_errors.BetterAuthConfigurationError("UNSUPPORTED_EXPRESS_ROUTER", "The Express application does not expose its initialized router.", "Use Express 5.2.x with @nestjs/platform-express 12.x, or move controller routes outside the auth mount.");
|
|
15
|
+
const options = router;
|
|
16
|
+
if (typeof options.caseSensitive !== "boolean" || typeof options.strict !== "boolean") throw new require_auth_errors.BetterAuthConfigurationError("UNSUPPORTED_EXPRESS_ROUTER", "The initialized Express router does not expose compatible routing options.", "Use Express 5.2.x with @nestjs/platform-express 12.x, or move controller routes outside the auth mount.");
|
|
17
|
+
return {
|
|
18
|
+
caseSensitive: options.caseSensitive,
|
|
19
|
+
strict: options.strict
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function routeMayOverlapMount(path, basePath) {
|
|
23
|
+
const { tokens } = (0, path_to_regexp.parse)(path);
|
|
24
|
+
let literalPrefix = "";
|
|
25
|
+
let dynamic = false;
|
|
26
|
+
for (const token of tokens) {
|
|
27
|
+
if (token.type !== "text") {
|
|
28
|
+
dynamic = true;
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
literalPrefix += token.value;
|
|
32
|
+
}
|
|
33
|
+
const route = literalPrefix.toLowerCase();
|
|
34
|
+
const base = basePath.toLowerCase().replace(/(?<!\/)\/+$/, "") || "/";
|
|
35
|
+
if (base === "/") return route.startsWith("/");
|
|
36
|
+
if (!dynamic) {
|
|
37
|
+
const exact = route.replace(/(?<!\/)\/+$/, "") || "/";
|
|
38
|
+
return exact === base || exact.startsWith(`${base}/`);
|
|
39
|
+
}
|
|
40
|
+
if (base.startsWith(route)) return true;
|
|
41
|
+
return route === base || route.startsWith(`${base}/`);
|
|
42
|
+
}
|
|
43
|
+
function rawTarget(req) {
|
|
44
|
+
return req.originalUrl ?? req.url ?? "/";
|
|
45
|
+
}
|
|
46
|
+
function rawPath(req) {
|
|
47
|
+
const target = rawTarget(req);
|
|
48
|
+
const query = target.indexOf("?");
|
|
49
|
+
return query === -1 ? target : target.slice(0, query);
|
|
50
|
+
}
|
|
51
|
+
function declaredLength(headers, limit) {
|
|
52
|
+
const value = headers["content-length"];
|
|
53
|
+
const first = Array.isArray(value) ? value[0] : value;
|
|
54
|
+
if (typeof first !== "string" || !/^\d+$/.test(first)) return;
|
|
55
|
+
const parsed = Number(first);
|
|
56
|
+
return Number.isSafeInteger(parsed) ? parsed : limit + 1;
|
|
57
|
+
}
|
|
58
|
+
function requestUrl(req) {
|
|
59
|
+
const socket = req.socket;
|
|
60
|
+
return `${req.protocol ?? (socket.encrypted ? "https" : "http")}://${req.host ?? ""}${rawTarget(req)}`;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Identifies Express's request by the Node objects it extends, never by shape: a GraphQL
|
|
64
|
+
* context can carry client-parsed data, and JSON can reproduce any structural check.
|
|
65
|
+
* light-my-request's inject() re-parents Express's shared request prototype onto its own
|
|
66
|
+
* Readable-based request for the whole process, so a stream request is accepted too; its
|
|
67
|
+
* response must still be a ServerResponse bound to it in both directions.
|
|
68
|
+
*/
|
|
69
|
+
function isExpressRequest(value) {
|
|
70
|
+
if (!(value instanceof node_http.IncomingMessage || value instanceof node_stream.Readable)) return false;
|
|
71
|
+
const res = Reflect.get(value, "res");
|
|
72
|
+
return res instanceof node_http.ServerResponse && res.req === value && Reflect.get(value, "res") === res && typeof res.setHeader === "function" && typeof res.getHeader === "function";
|
|
73
|
+
}
|
|
74
|
+
function nativeResponse(value) {
|
|
75
|
+
if (typeof value !== "object" || value === null) return null;
|
|
76
|
+
const response = value;
|
|
77
|
+
return typeof response.setHeader === "function" && typeof response.getHeader === "function" ? value : null;
|
|
78
|
+
}
|
|
79
|
+
function proxyTrustOf(value) {
|
|
80
|
+
if (value === false || value === void 0) return {
|
|
81
|
+
mode: "none",
|
|
82
|
+
detail: "trust proxy = false"
|
|
83
|
+
};
|
|
84
|
+
if (value === true) return {
|
|
85
|
+
mode: "all",
|
|
86
|
+
detail: "trust proxy = true"
|
|
87
|
+
};
|
|
88
|
+
return {
|
|
89
|
+
mode: "partial",
|
|
90
|
+
detail: `trust proxy = ${typeof value === "function" ? "<function>" : Array.isArray(value) ? JSON.stringify(value) : String(value)}`
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function abortOnDisconnect(req, res) {
|
|
94
|
+
const controller = new AbortController();
|
|
95
|
+
const abort = () => controller.abort();
|
|
96
|
+
req.once("aborted", abort);
|
|
97
|
+
res.once("close", abort);
|
|
98
|
+
if (req.aborted || res.destroyed) abort();
|
|
99
|
+
return {
|
|
100
|
+
signal: controller.signal,
|
|
101
|
+
dispose: () => {
|
|
102
|
+
req.removeListener("aborted", abort);
|
|
103
|
+
res.removeListener("close", abort);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/** Express-specific two-phase HTTP integration. */
|
|
108
|
+
var ExpressPlatform = class {
|
|
109
|
+
options;
|
|
110
|
+
id = "express";
|
|
111
|
+
#warnedConsumedBody = false;
|
|
112
|
+
#applicationRoutes = [];
|
|
113
|
+
#application;
|
|
114
|
+
constructor(options = {}) {
|
|
115
|
+
this.options = options;
|
|
116
|
+
}
|
|
117
|
+
requests = {
|
|
118
|
+
isRequest: (value) => isExpressRequest(value),
|
|
119
|
+
isLive: (value) => isExpressRequest(value) && value.res?.writableEnded === false,
|
|
120
|
+
key: (value) => value,
|
|
121
|
+
headers: (value) => require_platform.toWebHeaders(value.headers),
|
|
122
|
+
request: (value) => {
|
|
123
|
+
const req = value;
|
|
124
|
+
return {
|
|
125
|
+
method: req.method ?? "GET",
|
|
126
|
+
url: requestUrl(req)
|
|
127
|
+
};
|
|
128
|
+
},
|
|
129
|
+
clientIp: (value) => this.clientIp(value),
|
|
130
|
+
param: (value, name) => {
|
|
131
|
+
const parameter = value.params?.[name];
|
|
132
|
+
return typeof parameter === "string" ? parameter : void 0;
|
|
133
|
+
},
|
|
134
|
+
cookieSink: (request, response) => {
|
|
135
|
+
const req = request;
|
|
136
|
+
const res = nativeResponse(response) ?? nativeResponse(req.res);
|
|
137
|
+
return res === null ? null : { append: (cookies) => require_platform.appendSetCookie(res, cookies) };
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
supports(adapter) {
|
|
141
|
+
return adapter.getType?.() === "express";
|
|
142
|
+
}
|
|
143
|
+
prepare(ctx) {
|
|
144
|
+
const app = application(ctx.adapter);
|
|
145
|
+
this.#application = app;
|
|
146
|
+
app.use((req, _res, next) => {
|
|
147
|
+
const binding = ctx.route(rawPath(req));
|
|
148
|
+
const method = (req.method ?? "GET").toUpperCase();
|
|
149
|
+
if (!binding || this.isApplicationRoute(method, rawPath(req)) || method === "GET" || method === "HEAD" || method === "OPTIONS" || !require_platform.mayHaveBody(method, req.headers)) {
|
|
150
|
+
next();
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const continueRequest = require_platform.bindAsyncContext(next);
|
|
154
|
+
if (req.readableEnded || req.readable === false) {
|
|
155
|
+
const recovered = require_platform.recoverConsumedBody(req);
|
|
156
|
+
req[RAW_BODY] = {
|
|
157
|
+
ok: true,
|
|
158
|
+
bytes: recovered ?? /* @__PURE__ */ new Uint8Array()
|
|
159
|
+
};
|
|
160
|
+
if (!this.#warnedConsumedBody) {
|
|
161
|
+
this.#warnedConsumedBody = true;
|
|
162
|
+
ctx.logger.warn("W_BODY_ALREADY_CONSUMED: an Express body parser ran before the auth capture; raw-signature webhooks may receive re-serialized bytes.");
|
|
163
|
+
}
|
|
164
|
+
continueRequest();
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
require_platform.readBoundedBody(req, {
|
|
168
|
+
limit: binding.bodyLimit,
|
|
169
|
+
declaredLength: declaredLength(req.headers, binding.bodyLimit),
|
|
170
|
+
drainOnOverflow: true,
|
|
171
|
+
drainCap: Math.min(Number.MAX_SAFE_INTEGER, binding.bodyLimit * 8)
|
|
172
|
+
}).then((captured) => {
|
|
173
|
+
req[RAW_BODY] = captured;
|
|
174
|
+
continueRequest();
|
|
175
|
+
}, (error) => continueRequest(error));
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
applicationRoutes(routes, bindings) {
|
|
179
|
+
const bodyRoutes = routes.flatMap((route) => {
|
|
180
|
+
if ([
|
|
181
|
+
"GET",
|
|
182
|
+
"HEAD",
|
|
183
|
+
"OPTIONS"
|
|
184
|
+
].includes(route.method)) return [];
|
|
185
|
+
const paths = route.paths.filter((path) => bindings.some((binding) => routeMayOverlapMount(path, binding.basePath)));
|
|
186
|
+
return paths.length ? [{
|
|
187
|
+
...route,
|
|
188
|
+
paths
|
|
189
|
+
}] : [];
|
|
190
|
+
});
|
|
191
|
+
const conditional = bodyRoutes.find((route) => route.conditions.length > 0);
|
|
192
|
+
if (conditional) throw new require_auth_errors.BetterAuthConfigurationError("CONDITIONAL_ROUTE_SHADOW", `${conditional.source} at '${conditional.paths.join(", ")}' uses ${conditional.conditions.join(" and ")} routing under an auth mount.`, "Move the controller route outside the auth mount or make its host and version routing unconditional.");
|
|
193
|
+
if (bodyRoutes.length === 0) {
|
|
194
|
+
this.#applicationRoutes = [];
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const { caseSensitive, strict } = routerOptions(this.#application);
|
|
198
|
+
this.#applicationRoutes = Object.freeze(bodyRoutes.flatMap((route) => route.paths.map((path) => ({
|
|
199
|
+
method: route.method,
|
|
200
|
+
regexp: (0, path_to_regexp.pathToRegexp)(path, {
|
|
201
|
+
end: true,
|
|
202
|
+
sensitive: caseSensitive,
|
|
203
|
+
trailing: !strict
|
|
204
|
+
}).regexp
|
|
205
|
+
}))));
|
|
206
|
+
}
|
|
207
|
+
mount(ctx) {
|
|
208
|
+
application(ctx.adapter).use((req, res, next) => {
|
|
209
|
+
if (!ctx.binding.matches(rawPath(req))) {
|
|
210
|
+
next();
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
const disconnect = abortOnDisconnect(req, res);
|
|
214
|
+
this.dispatch(ctx.binding, req, res, disconnect.signal).then(() => disconnect.dispose(), (error) => {
|
|
215
|
+
disconnect.dispose();
|
|
216
|
+
if (!disconnect.signal.aborted) next(error);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
proxyTrust(adapter) {
|
|
221
|
+
return proxyTrustOf(application(adapter).get("trust proxy"));
|
|
222
|
+
}
|
|
223
|
+
clientIp(req) {
|
|
224
|
+
if (this.options.clientIp) return this.options.clientIp(req);
|
|
225
|
+
return req.ip ?? null;
|
|
226
|
+
}
|
|
227
|
+
isApplicationRoute(method, pathname) {
|
|
228
|
+
return this.#applicationRoutes.some((route) => (route.method === "ALL" || route.method === method) && route.regexp.test(pathname));
|
|
229
|
+
}
|
|
230
|
+
async dispatch(binding, req, res, signal) {
|
|
231
|
+
const captured = req[RAW_BODY];
|
|
232
|
+
if (captured && !captured.ok && captured.reason === "aborted" || signal.aborted) return;
|
|
233
|
+
const response = captured && !captured.ok && captured.reason === "too-large" ? binding.payloadTooLarge() : await binding.handle({
|
|
234
|
+
method: req.method ?? "GET",
|
|
235
|
+
url: requestUrl(req),
|
|
236
|
+
headers: require_platform.toWebHeaders(req.headers),
|
|
237
|
+
body: captured?.ok ? captured.bytes : null,
|
|
238
|
+
clientIp: this.clientIp(req),
|
|
239
|
+
platformRequest: req,
|
|
240
|
+
signal
|
|
241
|
+
});
|
|
242
|
+
if (signal.aborted) {
|
|
243
|
+
await response.body?.cancel().catch(() => void 0);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
await require_platform.writeWebResponse(res, response, { head: req.method?.toUpperCase() === "HEAD" });
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
function expressPlatform(options) {
|
|
250
|
+
return new ExpressPlatform(options);
|
|
251
|
+
}
|
|
252
|
+
//#endregion
|
|
253
|
+
exports.ExpressPlatform = ExpressPlatform;
|
|
254
|
+
exports.expressPlatform = expressPlatform;
|
|
255
|
+
|
|
256
|
+
//# sourceMappingURL=express.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express.cjs","names":["BetterAuthConfigurationError","parse","IncomingMessage","Readable","ServerResponse","toWebHeaders","appendSetCookie","mayHaveBody","bindAsyncContext","recoverConsumedBody","readBoundedBody","pathToRegexp","writeWebResponse"],"sources":["../src/express-platform.ts"],"sourcesContent":["import {\n type IncomingHttpHeaders,\n IncomingMessage,\n ServerResponse,\n} from \"node:http\";\nimport { Readable } from \"node:stream\";\nimport type { AbstractHttpAdapter } from \"@nestjs/core\";\nimport { parse, pathToRegexp } from \"path-to-regexp\";\nimport type {\n ApplicationRouteDescriptor,\n AuthRouteBinding,\n ExpressPlatformOptions,\n HttpPlatform,\n PlatformMountContext,\n PlatformPrepareContext,\n ProxyTrust,\n} from \"./auth-contracts.js\";\nimport { BetterAuthConfigurationError } from \"./auth-errors.js\";\nimport {\n appendSetCookie,\n bindAsyncContext,\n mayHaveBody,\n readBoundedBody,\n recoverConsumedBody,\n toWebHeaders,\n writeWebResponse,\n} from \"./platform.js\";\n\nconst RAW_BODY = Symbol.for(\"@nestjs-kit/better-auth:raw-body\");\n\ntype Next = (error?: unknown) => void;\ntype CapturedBody = Awaited<ReturnType<typeof readBoundedBody>>;\ntype ExpressResponse = ServerResponse & { req?: ExpressRequest };\ntype ExpressRequest = IncomingMessage & {\n readonly originalUrl?: string;\n readonly protocol?: string;\n readonly host?: string;\n readonly ip?: string;\n readonly res?: ExpressResponse;\n readonly params?: Record<string, unknown>;\n readonly body?: unknown;\n readonly rawBody?: Buffer;\n [RAW_BODY]?: CapturedBody;\n};\ntype ExpressApplication = {\n use(\n handler: (req: ExpressRequest, res: ExpressResponse, next: Next) => void,\n ): unknown;\n get(setting: string): unknown;\n readonly router?: unknown;\n};\ntype ExpressRouterOptions = {\n readonly caseSensitive: boolean;\n readonly strict: boolean;\n};\ntype ApplicationRouteMatcher = {\n readonly method: string;\n readonly regexp: RegExp;\n};\n\nfunction application(adapter: AbstractHttpAdapter): ExpressApplication {\n return adapter.getInstance() as ExpressApplication;\n}\n\nfunction routerOptions(\n app: ExpressApplication | undefined,\n): ExpressRouterOptions {\n const router = app?.router;\n if (\n (typeof router !== \"object\" && typeof router !== \"function\") ||\n router === null\n ) {\n throw new BetterAuthConfigurationError(\n \"UNSUPPORTED_EXPRESS_ROUTER\",\n \"The Express application does not expose its initialized router.\",\n \"Use Express 5.2.x with @nestjs/platform-express 12.x, or move controller routes outside the auth mount.\",\n );\n }\n const options = router as Partial<ExpressRouterOptions>;\n if (\n typeof options.caseSensitive !== \"boolean\" ||\n typeof options.strict !== \"boolean\"\n ) {\n throw new BetterAuthConfigurationError(\n \"UNSUPPORTED_EXPRESS_ROUTER\",\n \"The initialized Express router does not expose compatible routing options.\",\n \"Use Express 5.2.x with @nestjs/platform-express 12.x, or move controller routes outside the auth mount.\",\n );\n }\n return { caseSensitive: options.caseSensitive, strict: options.strict };\n}\n\nfunction routeMayOverlapMount(path: string, basePath: string): boolean {\n const { tokens } = parse(path);\n let literalPrefix = \"\";\n let dynamic = false;\n for (const token of tokens) {\n if (token.type !== \"text\") {\n dynamic = true;\n break;\n }\n literalPrefix += token.value;\n }\n const route = literalPrefix.toLowerCase();\n const base = basePath.toLowerCase().replace(/(?<!\\/)\\/+$/, \"\") || \"/\";\n if (base === \"/\") {\n return route.startsWith(\"/\");\n }\n if (!dynamic) {\n const exact = route.replace(/(?<!\\/)\\/+$/, \"\") || \"/\";\n return exact === base || exact.startsWith(`${base}/`);\n }\n if (base.startsWith(route)) {\n return true;\n }\n return route === base || route.startsWith(`${base}/`);\n}\n\nfunction rawTarget(req: ExpressRequest): string {\n return req.originalUrl ?? req.url ?? \"/\";\n}\n\nfunction rawPath(req: ExpressRequest): string {\n const target = rawTarget(req);\n const query = target.indexOf(\"?\");\n return query === -1 ? target : target.slice(0, query);\n}\n\nfunction declaredLength(\n headers: IncomingHttpHeaders,\n limit: number,\n): number | undefined {\n const value = headers[\"content-length\"];\n const first = Array.isArray(value) ? value[0] : value;\n if (typeof first !== \"string\" || !/^\\d+$/.test(first)) {\n return undefined;\n }\n const parsed = Number(first);\n return Number.isSafeInteger(parsed) ? parsed : limit + 1;\n}\n\nfunction requestUrl(req: ExpressRequest): string {\n const socket = req.socket as typeof req.socket & { encrypted?: boolean };\n return `${req.protocol ?? (socket.encrypted ? \"https\" : \"http\")}://${req.host ?? \"\"}${rawTarget(req)}`;\n}\n\n/**\n * Identifies Express's request by the Node objects it extends, never by shape: a GraphQL\n * context can carry client-parsed data, and JSON can reproduce any structural check.\n * light-my-request's inject() re-parents Express's shared request prototype onto its own\n * Readable-based request for the whole process, so a stream request is accepted too; its\n * response must still be a ServerResponse bound to it in both directions.\n */\nfunction isExpressRequest(value: unknown): value is ExpressRequest {\n if (!(value instanceof IncomingMessage || value instanceof Readable)) {\n return false;\n }\n const res: unknown = Reflect.get(value, \"res\");\n return (\n res instanceof ServerResponse &&\n res.req === value &&\n Reflect.get(value, \"res\") === res &&\n typeof res.setHeader === \"function\" &&\n typeof res.getHeader === \"function\"\n );\n}\n\nfunction nativeResponse(value: unknown): ServerResponse | null {\n if (typeof value !== \"object\" || value === null) {\n return null;\n }\n const response = value as Partial<ServerResponse>;\n return typeof response.setHeader === \"function\" &&\n typeof response.getHeader === \"function\"\n ? (value as ServerResponse)\n : null;\n}\n\nfunction proxyTrustOf(value: unknown): ProxyTrust {\n if (value === false || value === undefined) {\n return { mode: \"none\", detail: \"trust proxy = false\" };\n }\n if (value === true) {\n return { mode: \"all\", detail: \"trust proxy = true\" };\n }\n const rendered =\n typeof value === \"function\"\n ? \"<function>\"\n : Array.isArray(value)\n ? JSON.stringify(value)\n : String(value);\n return { mode: \"partial\", detail: `trust proxy = ${rendered}` };\n}\n\nfunction abortOnDisconnect(\n req: ExpressRequest,\n res: ExpressResponse,\n): { signal: AbortSignal; dispose(): void } {\n const controller = new AbortController();\n const abort = () => controller.abort();\n req.once(\"aborted\", abort);\n res.once(\"close\", abort);\n if (req.aborted || res.destroyed) {\n abort();\n }\n return {\n signal: controller.signal,\n dispose: () => {\n req.removeListener(\"aborted\", abort);\n res.removeListener(\"close\", abort);\n },\n };\n}\n\n/** Express-specific two-phase HTTP integration. */\nexport class ExpressPlatform implements HttpPlatform {\n readonly id = \"express\";\n #warnedConsumedBody = false;\n #applicationRoutes: readonly ApplicationRouteMatcher[] = [];\n #application: ExpressApplication | undefined;\n\n constructor(private readonly options: ExpressPlatformOptions = {}) {}\n\n readonly requests = {\n isRequest: (value: unknown): boolean => isExpressRequest(value),\n isLive: (value: unknown): boolean =>\n isExpressRequest(value) && value.res?.writableEnded === false,\n key: (value: unknown): object => value as object,\n headers: (value: unknown): Headers =>\n toWebHeaders((value as ExpressRequest).headers),\n request: (value: unknown) => {\n const req = value as ExpressRequest;\n return { method: req.method ?? \"GET\", url: requestUrl(req) };\n },\n clientIp: (value: unknown): string | null =>\n this.clientIp(value as ExpressRequest),\n param: (value: unknown, name: string): string | undefined => {\n const parameter = (value as ExpressRequest).params?.[name];\n return typeof parameter === \"string\" ? parameter : undefined;\n },\n cookieSink: (request: unknown, response: unknown) => {\n const req = request as ExpressRequest;\n const res = nativeResponse(response) ?? nativeResponse(req.res);\n return res === null\n ? null\n : {\n append: (cookies: readonly string[]) =>\n appendSetCookie(res, cookies),\n };\n },\n };\n\n supports(adapter: AbstractHttpAdapter): boolean {\n return adapter.getType?.() === \"express\";\n }\n\n prepare(ctx: PlatformPrepareContext): void {\n const app = application(ctx.adapter);\n this.#application = app;\n app.use((req, _res, next) => {\n const binding = ctx.route(rawPath(req));\n const method = (req.method ?? \"GET\").toUpperCase();\n if (\n !binding ||\n this.isApplicationRoute(method, rawPath(req)) ||\n method === \"GET\" ||\n method === \"HEAD\" ||\n method === \"OPTIONS\" ||\n !mayHaveBody(method, req.headers)\n ) {\n next();\n return;\n }\n\n const continueRequest = bindAsyncContext(next);\n if (req.readableEnded || req.readable === false) {\n const recovered = recoverConsumedBody(req);\n req[RAW_BODY] = {\n ok: true,\n bytes: recovered ?? new Uint8Array(),\n };\n if (!this.#warnedConsumedBody) {\n this.#warnedConsumedBody = true;\n ctx.logger.warn(\n \"W_BODY_ALREADY_CONSUMED: an Express body parser ran before the auth capture; raw-signature webhooks may receive re-serialized bytes.\",\n );\n }\n continueRequest();\n return;\n }\n\n void readBoundedBody(req, {\n limit: binding.bodyLimit,\n declaredLength: declaredLength(req.headers, binding.bodyLimit),\n drainOnOverflow: true,\n drainCap: Math.min(Number.MAX_SAFE_INTEGER, binding.bodyLimit * 8),\n }).then(\n (captured) => {\n req[RAW_BODY] = captured;\n continueRequest();\n },\n (error: unknown) => continueRequest(error),\n );\n });\n }\n\n applicationRoutes(\n routes: readonly ApplicationRouteDescriptor[],\n bindings: readonly AuthRouteBinding[],\n ): void {\n const bodyRoutes = routes.flatMap((route) => {\n if ([\"GET\", \"HEAD\", \"OPTIONS\"].includes(route.method)) {\n return [];\n }\n const paths = route.paths.filter((path) =>\n bindings.some((binding) =>\n routeMayOverlapMount(path, binding.basePath),\n ),\n );\n return paths.length ? [{ ...route, paths }] : [];\n });\n const conditional = bodyRoutes.find((route) => route.conditions.length > 0);\n if (conditional) {\n throw new BetterAuthConfigurationError(\n \"CONDITIONAL_ROUTE_SHADOW\",\n `${conditional.source} at '${conditional.paths.join(\", \")}' uses ${conditional.conditions.join(\" and \")} routing under an auth mount.`,\n \"Move the controller route outside the auth mount or make its host and version routing unconditional.\",\n );\n }\n if (bodyRoutes.length === 0) {\n this.#applicationRoutes = [];\n return;\n }\n const { caseSensitive, strict } = routerOptions(this.#application);\n this.#applicationRoutes = Object.freeze(\n bodyRoutes.flatMap((route) =>\n route.paths.map((path) => ({\n method: route.method,\n regexp: pathToRegexp(path, {\n end: true,\n sensitive: caseSensitive,\n trailing: !strict,\n }).regexp,\n })),\n ),\n );\n }\n\n mount(ctx: PlatformMountContext): void {\n application(ctx.adapter).use((req, res, next) => {\n if (!ctx.binding.matches(rawPath(req))) {\n next();\n return;\n }\n const disconnect = abortOnDisconnect(req, res);\n void this.dispatch(ctx.binding, req, res, disconnect.signal).then(\n () => disconnect.dispose(),\n (error: unknown) => {\n disconnect.dispose();\n if (!disconnect.signal.aborted) {\n next(error);\n }\n },\n );\n });\n }\n\n proxyTrust(adapter: AbstractHttpAdapter): ProxyTrust {\n return proxyTrustOf(application(adapter).get(\"trust proxy\"));\n }\n\n private clientIp(req: ExpressRequest): string | null {\n if (this.options.clientIp) {\n return this.options.clientIp(req);\n }\n return req.ip ?? null;\n }\n\n private isApplicationRoute(method: string, pathname: string): boolean {\n return this.#applicationRoutes.some(\n (route) =>\n (route.method === \"ALL\" || route.method === method) &&\n route.regexp.test(pathname),\n );\n }\n\n private async dispatch(\n binding: AuthRouteBinding,\n req: ExpressRequest,\n res: ExpressResponse,\n signal: AbortSignal,\n ): Promise<void> {\n const captured = req[RAW_BODY];\n if (\n (captured && !captured.ok && captured.reason === \"aborted\") ||\n signal.aborted\n ) {\n return;\n }\n const response =\n captured && !captured.ok && captured.reason === \"too-large\"\n ? binding.payloadTooLarge()\n : await binding.handle({\n method: req.method ?? \"GET\",\n url: requestUrl(req),\n headers: toWebHeaders(req.headers),\n body: captured?.ok ? captured.bytes : null,\n clientIp: this.clientIp(req),\n platformRequest: req,\n signal,\n });\n if (signal.aborted) {\n await response.body?.cancel().catch(() => undefined);\n return;\n }\n await writeWebResponse(res, response, {\n head: req.method?.toUpperCase() === \"HEAD\",\n });\n }\n}\n\nexport function expressPlatform(\n options?: ExpressPlatformOptions,\n): ExpressPlatform {\n return new ExpressPlatform(options);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { J as PlatformMountContext, P as ExpressPlatformOptions, U as HttpPlatform, Y as PlatformPrepareContext, at as ProxyTrust, n as ApplicationRouteDescriptor, s as AuthRouteBinding } from "./auth-contracts-Brh_Qko9.cjs";
|
|
2
|
+
import { AbstractHttpAdapter } from "@nestjs/core";
|
|
3
|
+
//#region src/express-platform.d.ts
|
|
4
|
+
/** Express-specific two-phase HTTP integration. */
|
|
5
|
+
export declare class ExpressPlatform implements HttpPlatform {
|
|
6
|
+
#private;
|
|
7
|
+
private readonly options;
|
|
8
|
+
readonly id = "express";
|
|
9
|
+
constructor(options?: ExpressPlatformOptions);
|
|
10
|
+
readonly requests: {
|
|
11
|
+
isRequest: (value: unknown) => boolean;
|
|
12
|
+
isLive: (value: unknown) => boolean;
|
|
13
|
+
key: (value: unknown) => object;
|
|
14
|
+
headers: (value: unknown) => Headers;
|
|
15
|
+
request: (value: unknown) => {
|
|
16
|
+
method: string;
|
|
17
|
+
url: string;
|
|
18
|
+
};
|
|
19
|
+
clientIp: (value: unknown) => string | null;
|
|
20
|
+
param: (value: unknown, name: string) => string | undefined;
|
|
21
|
+
cookieSink: (request: unknown, response: unknown) => {
|
|
22
|
+
append: (cookies: readonly string[]) => boolean;
|
|
23
|
+
} | null;
|
|
24
|
+
};
|
|
25
|
+
supports(adapter: AbstractHttpAdapter): boolean;
|
|
26
|
+
prepare(ctx: PlatformPrepareContext): void;
|
|
27
|
+
applicationRoutes(routes: readonly ApplicationRouteDescriptor[], bindings: readonly AuthRouteBinding[]): void;
|
|
28
|
+
mount(ctx: PlatformMountContext): void;
|
|
29
|
+
proxyTrust(adapter: AbstractHttpAdapter): ProxyTrust;
|
|
30
|
+
private clientIp;
|
|
31
|
+
private isApplicationRoute;
|
|
32
|
+
private dispatch;
|
|
33
|
+
}
|
|
34
|
+
export declare function expressPlatform(options?: ExpressPlatformOptions): ExpressPlatform;
|
|
35
|
+
//#endregion
|
|
36
|
+
export type { ExpressPlatformOptions };
|
|
37
|
+
//# sourceMappingURL=express.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express.d.cts","names":[],"sources":["../src/express-platform.ts"],"mappings":";;;;qBAuNa,2BAA2B;;mBAMT;WALpB;EAKT,YAA6B,UAAS;WAE7B;IACP,YAAS;IACT,SAAM;IAEN,MAAG;IACH,UAAO,mBAAoB;IAE3B,UAAO;MAEI;MAA6B;;IAExC,WAAQ;IAER,QAAK,gBAAiB;IAItB,aAAU,kBAAmB;MAMH,SAAA;;;EAM5B,SAAS,SAAS;EAIlB,QAAQ,KAAK;EAkDb,kBACE,iBAAiB,8BACjB,mBAAmB;EAwCrB,MAAM,KAAK;EAmBX,WAAW,SAAS,sBAAsB;UAIlC;UAOA;UAQM;;wBAmCA,gBACd,UAAU,yBACT"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { J as PlatformMountContext, P as ExpressPlatformOptions, U as HttpPlatform, Y as PlatformPrepareContext, at as ProxyTrust, n as ApplicationRouteDescriptor, s as AuthRouteBinding } from "./auth-contracts-Cz7C4_Ch.mjs";
|
|
2
|
+
import { AbstractHttpAdapter } from "@nestjs/core";
|
|
3
|
+
//#region src/express-platform.d.ts
|
|
4
|
+
/** Express-specific two-phase HTTP integration. */
|
|
5
|
+
export declare class ExpressPlatform implements HttpPlatform {
|
|
6
|
+
#private;
|
|
7
|
+
private readonly options;
|
|
8
|
+
readonly id = "express";
|
|
9
|
+
constructor(options?: ExpressPlatformOptions);
|
|
10
|
+
readonly requests: {
|
|
11
|
+
isRequest: (value: unknown) => boolean;
|
|
12
|
+
isLive: (value: unknown) => boolean;
|
|
13
|
+
key: (value: unknown) => object;
|
|
14
|
+
headers: (value: unknown) => Headers;
|
|
15
|
+
request: (value: unknown) => {
|
|
16
|
+
method: string;
|
|
17
|
+
url: string;
|
|
18
|
+
};
|
|
19
|
+
clientIp: (value: unknown) => string | null;
|
|
20
|
+
param: (value: unknown, name: string) => string | undefined;
|
|
21
|
+
cookieSink: (request: unknown, response: unknown) => {
|
|
22
|
+
append: (cookies: readonly string[]) => boolean;
|
|
23
|
+
} | null;
|
|
24
|
+
};
|
|
25
|
+
supports(adapter: AbstractHttpAdapter): boolean;
|
|
26
|
+
prepare(ctx: PlatformPrepareContext): void;
|
|
27
|
+
applicationRoutes(routes: readonly ApplicationRouteDescriptor[], bindings: readonly AuthRouteBinding[]): void;
|
|
28
|
+
mount(ctx: PlatformMountContext): void;
|
|
29
|
+
proxyTrust(adapter: AbstractHttpAdapter): ProxyTrust;
|
|
30
|
+
private clientIp;
|
|
31
|
+
private isApplicationRoute;
|
|
32
|
+
private dispatch;
|
|
33
|
+
}
|
|
34
|
+
export declare function expressPlatform(options?: ExpressPlatformOptions): ExpressPlatform;
|
|
35
|
+
//#endregion
|
|
36
|
+
export type { ExpressPlatformOptions };
|
|
37
|
+
//# sourceMappingURL=express.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express.d.mts","names":[],"sources":["../src/express-platform.ts"],"mappings":";;;;qBAuNa,2BAA2B;;mBAMT;WALpB;EAKT,YAA6B,UAAS;WAE7B;IACP,YAAS;IACT,SAAM;IAEN,MAAG;IACH,UAAO,mBAAoB;IAE3B,UAAO;MAEI;MAA6B;;IAExC,WAAQ;IAER,QAAK,gBAAiB;IAItB,aAAU,kBAAmB;MAMH,SAAA;;;EAM5B,SAAS,SAAS;EAIlB,QAAQ,KAAK;EAkDb,kBACE,iBAAiB,8BACjB,mBAAmB;EAwCrB,MAAM,KAAK;EAmBX,WAAW,SAAS,sBAAsB;UAIlC;UAOA;UAQM;;wBAmCA,gBACd,UAAU,yBACT"}
|
package/dist/express.mjs
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { n as BetterAuthConfigurationError } from "./auth-errors-C3rbTV9p.mjs";
|
|
2
|
+
import { a as recoverConsumedBody, c as writeWebResponse, i as readBoundedBody, n as bindAsyncContext, o as toWebHeaders, r as mayHaveBody, t as appendSetCookie } from "./platform-CZl7TY8j.mjs";
|
|
3
|
+
import { IncomingMessage, ServerResponse } from "node:http";
|
|
4
|
+
import { Readable } from "node:stream";
|
|
5
|
+
import { parse, pathToRegexp } from "path-to-regexp";
|
|
6
|
+
//#region src/express-platform.ts
|
|
7
|
+
const RAW_BODY = Symbol.for("@nestjs-kit/better-auth:raw-body");
|
|
8
|
+
function application(adapter) {
|
|
9
|
+
return adapter.getInstance();
|
|
10
|
+
}
|
|
11
|
+
function routerOptions(app) {
|
|
12
|
+
const router = app?.router;
|
|
13
|
+
if (typeof router !== "object" && typeof router !== "function" || router === null) throw new BetterAuthConfigurationError("UNSUPPORTED_EXPRESS_ROUTER", "The Express application does not expose its initialized router.", "Use Express 5.2.x with @nestjs/platform-express 12.x, or move controller routes outside the auth mount.");
|
|
14
|
+
const options = router;
|
|
15
|
+
if (typeof options.caseSensitive !== "boolean" || typeof options.strict !== "boolean") throw new BetterAuthConfigurationError("UNSUPPORTED_EXPRESS_ROUTER", "The initialized Express router does not expose compatible routing options.", "Use Express 5.2.x with @nestjs/platform-express 12.x, or move controller routes outside the auth mount.");
|
|
16
|
+
return {
|
|
17
|
+
caseSensitive: options.caseSensitive,
|
|
18
|
+
strict: options.strict
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function routeMayOverlapMount(path, basePath) {
|
|
22
|
+
const { tokens } = parse(path);
|
|
23
|
+
let literalPrefix = "";
|
|
24
|
+
let dynamic = false;
|
|
25
|
+
for (const token of tokens) {
|
|
26
|
+
if (token.type !== "text") {
|
|
27
|
+
dynamic = true;
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
literalPrefix += token.value;
|
|
31
|
+
}
|
|
32
|
+
const route = literalPrefix.toLowerCase();
|
|
33
|
+
const base = basePath.toLowerCase().replace(/(?<!\/)\/+$/, "") || "/";
|
|
34
|
+
if (base === "/") return route.startsWith("/");
|
|
35
|
+
if (!dynamic) {
|
|
36
|
+
const exact = route.replace(/(?<!\/)\/+$/, "") || "/";
|
|
37
|
+
return exact === base || exact.startsWith(`${base}/`);
|
|
38
|
+
}
|
|
39
|
+
if (base.startsWith(route)) return true;
|
|
40
|
+
return route === base || route.startsWith(`${base}/`);
|
|
41
|
+
}
|
|
42
|
+
function rawTarget(req) {
|
|
43
|
+
return req.originalUrl ?? req.url ?? "/";
|
|
44
|
+
}
|
|
45
|
+
function rawPath(req) {
|
|
46
|
+
const target = rawTarget(req);
|
|
47
|
+
const query = target.indexOf("?");
|
|
48
|
+
return query === -1 ? target : target.slice(0, query);
|
|
49
|
+
}
|
|
50
|
+
function declaredLength(headers, limit) {
|
|
51
|
+
const value = headers["content-length"];
|
|
52
|
+
const first = Array.isArray(value) ? value[0] : value;
|
|
53
|
+
if (typeof first !== "string" || !/^\d+$/.test(first)) return;
|
|
54
|
+
const parsed = Number(first);
|
|
55
|
+
return Number.isSafeInteger(parsed) ? parsed : limit + 1;
|
|
56
|
+
}
|
|
57
|
+
function requestUrl(req) {
|
|
58
|
+
const socket = req.socket;
|
|
59
|
+
return `${req.protocol ?? (socket.encrypted ? "https" : "http")}://${req.host ?? ""}${rawTarget(req)}`;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Identifies Express's request by the Node objects it extends, never by shape: a GraphQL
|
|
63
|
+
* context can carry client-parsed data, and JSON can reproduce any structural check.
|
|
64
|
+
* light-my-request's inject() re-parents Express's shared request prototype onto its own
|
|
65
|
+
* Readable-based request for the whole process, so a stream request is accepted too; its
|
|
66
|
+
* response must still be a ServerResponse bound to it in both directions.
|
|
67
|
+
*/
|
|
68
|
+
function isExpressRequest(value) {
|
|
69
|
+
if (!(value instanceof IncomingMessage || value instanceof Readable)) return false;
|
|
70
|
+
const res = Reflect.get(value, "res");
|
|
71
|
+
return res instanceof ServerResponse && res.req === value && Reflect.get(value, "res") === res && typeof res.setHeader === "function" && typeof res.getHeader === "function";
|
|
72
|
+
}
|
|
73
|
+
function nativeResponse(value) {
|
|
74
|
+
if (typeof value !== "object" || value === null) return null;
|
|
75
|
+
const response = value;
|
|
76
|
+
return typeof response.setHeader === "function" && typeof response.getHeader === "function" ? value : null;
|
|
77
|
+
}
|
|
78
|
+
function proxyTrustOf(value) {
|
|
79
|
+
if (value === false || value === void 0) return {
|
|
80
|
+
mode: "none",
|
|
81
|
+
detail: "trust proxy = false"
|
|
82
|
+
};
|
|
83
|
+
if (value === true) return {
|
|
84
|
+
mode: "all",
|
|
85
|
+
detail: "trust proxy = true"
|
|
86
|
+
};
|
|
87
|
+
return {
|
|
88
|
+
mode: "partial",
|
|
89
|
+
detail: `trust proxy = ${typeof value === "function" ? "<function>" : Array.isArray(value) ? JSON.stringify(value) : String(value)}`
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function abortOnDisconnect(req, res) {
|
|
93
|
+
const controller = new AbortController();
|
|
94
|
+
const abort = () => controller.abort();
|
|
95
|
+
req.once("aborted", abort);
|
|
96
|
+
res.once("close", abort);
|
|
97
|
+
if (req.aborted || res.destroyed) abort();
|
|
98
|
+
return {
|
|
99
|
+
signal: controller.signal,
|
|
100
|
+
dispose: () => {
|
|
101
|
+
req.removeListener("aborted", abort);
|
|
102
|
+
res.removeListener("close", abort);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/** Express-specific two-phase HTTP integration. */
|
|
107
|
+
var ExpressPlatform = class {
|
|
108
|
+
options;
|
|
109
|
+
id = "express";
|
|
110
|
+
#warnedConsumedBody = false;
|
|
111
|
+
#applicationRoutes = [];
|
|
112
|
+
#application;
|
|
113
|
+
constructor(options = {}) {
|
|
114
|
+
this.options = options;
|
|
115
|
+
}
|
|
116
|
+
requests = {
|
|
117
|
+
isRequest: (value) => isExpressRequest(value),
|
|
118
|
+
isLive: (value) => isExpressRequest(value) && value.res?.writableEnded === false,
|
|
119
|
+
key: (value) => value,
|
|
120
|
+
headers: (value) => toWebHeaders(value.headers),
|
|
121
|
+
request: (value) => {
|
|
122
|
+
const req = value;
|
|
123
|
+
return {
|
|
124
|
+
method: req.method ?? "GET",
|
|
125
|
+
url: requestUrl(req)
|
|
126
|
+
};
|
|
127
|
+
},
|
|
128
|
+
clientIp: (value) => this.clientIp(value),
|
|
129
|
+
param: (value, name) => {
|
|
130
|
+
const parameter = value.params?.[name];
|
|
131
|
+
return typeof parameter === "string" ? parameter : void 0;
|
|
132
|
+
},
|
|
133
|
+
cookieSink: (request, response) => {
|
|
134
|
+
const req = request;
|
|
135
|
+
const res = nativeResponse(response) ?? nativeResponse(req.res);
|
|
136
|
+
return res === null ? null : { append: (cookies) => appendSetCookie(res, cookies) };
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
supports(adapter) {
|
|
140
|
+
return adapter.getType?.() === "express";
|
|
141
|
+
}
|
|
142
|
+
prepare(ctx) {
|
|
143
|
+
const app = application(ctx.adapter);
|
|
144
|
+
this.#application = app;
|
|
145
|
+
app.use((req, _res, next) => {
|
|
146
|
+
const binding = ctx.route(rawPath(req));
|
|
147
|
+
const method = (req.method ?? "GET").toUpperCase();
|
|
148
|
+
if (!binding || this.isApplicationRoute(method, rawPath(req)) || method === "GET" || method === "HEAD" || method === "OPTIONS" || !mayHaveBody(method, req.headers)) {
|
|
149
|
+
next();
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const continueRequest = bindAsyncContext(next);
|
|
153
|
+
if (req.readableEnded || req.readable === false) {
|
|
154
|
+
const recovered = recoverConsumedBody(req);
|
|
155
|
+
req[RAW_BODY] = {
|
|
156
|
+
ok: true,
|
|
157
|
+
bytes: recovered ?? /* @__PURE__ */ new Uint8Array()
|
|
158
|
+
};
|
|
159
|
+
if (!this.#warnedConsumedBody) {
|
|
160
|
+
this.#warnedConsumedBody = true;
|
|
161
|
+
ctx.logger.warn("W_BODY_ALREADY_CONSUMED: an Express body parser ran before the auth capture; raw-signature webhooks may receive re-serialized bytes.");
|
|
162
|
+
}
|
|
163
|
+
continueRequest();
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
readBoundedBody(req, {
|
|
167
|
+
limit: binding.bodyLimit,
|
|
168
|
+
declaredLength: declaredLength(req.headers, binding.bodyLimit),
|
|
169
|
+
drainOnOverflow: true,
|
|
170
|
+
drainCap: Math.min(Number.MAX_SAFE_INTEGER, binding.bodyLimit * 8)
|
|
171
|
+
}).then((captured) => {
|
|
172
|
+
req[RAW_BODY] = captured;
|
|
173
|
+
continueRequest();
|
|
174
|
+
}, (error) => continueRequest(error));
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
applicationRoutes(routes, bindings) {
|
|
178
|
+
const bodyRoutes = routes.flatMap((route) => {
|
|
179
|
+
if ([
|
|
180
|
+
"GET",
|
|
181
|
+
"HEAD",
|
|
182
|
+
"OPTIONS"
|
|
183
|
+
].includes(route.method)) return [];
|
|
184
|
+
const paths = route.paths.filter((path) => bindings.some((binding) => routeMayOverlapMount(path, binding.basePath)));
|
|
185
|
+
return paths.length ? [{
|
|
186
|
+
...route,
|
|
187
|
+
paths
|
|
188
|
+
}] : [];
|
|
189
|
+
});
|
|
190
|
+
const conditional = bodyRoutes.find((route) => route.conditions.length > 0);
|
|
191
|
+
if (conditional) throw new BetterAuthConfigurationError("CONDITIONAL_ROUTE_SHADOW", `${conditional.source} at '${conditional.paths.join(", ")}' uses ${conditional.conditions.join(" and ")} routing under an auth mount.`, "Move the controller route outside the auth mount or make its host and version routing unconditional.");
|
|
192
|
+
if (bodyRoutes.length === 0) {
|
|
193
|
+
this.#applicationRoutes = [];
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
const { caseSensitive, strict } = routerOptions(this.#application);
|
|
197
|
+
this.#applicationRoutes = Object.freeze(bodyRoutes.flatMap((route) => route.paths.map((path) => ({
|
|
198
|
+
method: route.method,
|
|
199
|
+
regexp: pathToRegexp(path, {
|
|
200
|
+
end: true,
|
|
201
|
+
sensitive: caseSensitive,
|
|
202
|
+
trailing: !strict
|
|
203
|
+
}).regexp
|
|
204
|
+
}))));
|
|
205
|
+
}
|
|
206
|
+
mount(ctx) {
|
|
207
|
+
application(ctx.adapter).use((req, res, next) => {
|
|
208
|
+
if (!ctx.binding.matches(rawPath(req))) {
|
|
209
|
+
next();
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const disconnect = abortOnDisconnect(req, res);
|
|
213
|
+
this.dispatch(ctx.binding, req, res, disconnect.signal).then(() => disconnect.dispose(), (error) => {
|
|
214
|
+
disconnect.dispose();
|
|
215
|
+
if (!disconnect.signal.aborted) next(error);
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
proxyTrust(adapter) {
|
|
220
|
+
return proxyTrustOf(application(adapter).get("trust proxy"));
|
|
221
|
+
}
|
|
222
|
+
clientIp(req) {
|
|
223
|
+
if (this.options.clientIp) return this.options.clientIp(req);
|
|
224
|
+
return req.ip ?? null;
|
|
225
|
+
}
|
|
226
|
+
isApplicationRoute(method, pathname) {
|
|
227
|
+
return this.#applicationRoutes.some((route) => (route.method === "ALL" || route.method === method) && route.regexp.test(pathname));
|
|
228
|
+
}
|
|
229
|
+
async dispatch(binding, req, res, signal) {
|
|
230
|
+
const captured = req[RAW_BODY];
|
|
231
|
+
if (captured && !captured.ok && captured.reason === "aborted" || signal.aborted) return;
|
|
232
|
+
const response = captured && !captured.ok && captured.reason === "too-large" ? binding.payloadTooLarge() : await binding.handle({
|
|
233
|
+
method: req.method ?? "GET",
|
|
234
|
+
url: requestUrl(req),
|
|
235
|
+
headers: toWebHeaders(req.headers),
|
|
236
|
+
body: captured?.ok ? captured.bytes : null,
|
|
237
|
+
clientIp: this.clientIp(req),
|
|
238
|
+
platformRequest: req,
|
|
239
|
+
signal
|
|
240
|
+
});
|
|
241
|
+
if (signal.aborted) {
|
|
242
|
+
await response.body?.cancel().catch(() => void 0);
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
await writeWebResponse(res, response, { head: req.method?.toUpperCase() === "HEAD" });
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
function expressPlatform(options) {
|
|
249
|
+
return new ExpressPlatform(options);
|
|
250
|
+
}
|
|
251
|
+
//#endregion
|
|
252
|
+
export { ExpressPlatform, expressPlatform };
|
|
253
|
+
|
|
254
|
+
//# sourceMappingURL=express.mjs.map
|