@qelos/integrator-nest 4.0.0 → 4.1.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 +65 -107
- package/dist/cookies.d.ts +19 -0
- package/dist/cookies.js +43 -0
- package/dist/cookies.js.map +1 -0
- package/dist/cookies.test.d.ts +1 -0
- package/dist/cookies.test.js +76 -0
- package/dist/cookies.test.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/middleware.js +71 -31
- package/dist/middleware.js.map +1 -1
- package/dist/module-options.d.ts +3 -0
- package/dist/module-options.js +21 -2
- package/dist/module-options.js.map +1 -1
- package/dist/module.d.ts +6 -3
- package/dist/module.js +38 -4
- package/dist/module.js.map +1 -1
- package/dist/proxy-target.d.ts +17 -0
- package/dist/proxy-target.js +29 -0
- package/dist/proxy-target.js.map +1 -0
- package/dist/proxy-target.test.d.ts +1 -0
- package/dist/proxy-target.test.js +86 -0
- package/dist/proxy-target.test.js.map +1 -0
- package/dist/proxy.middleware.d.ts +7 -0
- package/dist/proxy.middleware.js +197 -0
- package/dist/proxy.middleware.js.map +1 -0
- package/dist/request-utils.d.ts +2 -6
- package/dist/request-utils.js +1 -86
- package/dist/request-utils.js.map +1 -1
- package/dist/sdk-factory.d.ts +2 -10
- package/dist/sdk-factory.js +19 -77
- package/dist/sdk-factory.js.map +1 -1
- package/dist/types.d.ts +13 -41
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
# @qelos/integrator-nest
|
|
2
2
|
|
|
3
|
-
NestJS module
|
|
4
|
-
active workspace before your route handler runs, exposing them on
|
|
5
|
-
`request.qelos.user` / `request.qelos.workspace`.
|
|
3
|
+
NestJS module for [Qelos](https://qelos.io). It wires global middleware so your Nest host acts as a same-origin BFF for a managed Qelos app: requests under `/api/**` are proxied to Qelos (unless you opt out), and every other request resolves the current user up front so controllers and request-scoped providers can use `request.qelos` and the `Qelos*` decorators.
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
shape exposed by `@qelos/integrator-express`, `@qelos/integrator-fastify`,
|
|
9
|
-
`@qelos/integrator-nuxt`, `@qelos/plugin-netlify-api`, etc. It works with
|
|
10
|
-
both Nest's Express adapter and its Fastify adapter.
|
|
5
|
+
Works with Nest’s **Express** and **Fastify** HTTP adapters — request/response objects are handled generically.
|
|
11
6
|
|
|
12
7
|
## Install
|
|
13
8
|
|
|
14
9
|
```sh
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
npm install @nestjs/common @nestjs/core
|
|
10
|
+
pnpm add @qelos/integrator-nest @qelos/sdk
|
|
11
|
+
pnpm add @nestjs/common @nestjs/core
|
|
18
12
|
```
|
|
19
13
|
|
|
14
|
+
Requires **Node 18+**. The user-resolution middleware uses [`Response.headers.getSetCookie()`](https://developer.mozilla.org/docs/Web/API/Headers/getSetCookie) when probing `/api/me` so each upstream `Set-Cookie` can be forwarded individually.
|
|
15
|
+
|
|
20
16
|
## Quick start
|
|
21
17
|
|
|
22
18
|
```ts
|
|
@@ -28,7 +24,7 @@ import { QelosModule } from '@qelos/integrator-nest';
|
|
|
28
24
|
imports: [
|
|
29
25
|
QelosModule.forRoot({
|
|
30
26
|
config: {
|
|
31
|
-
appUrl: process.env.QELOS_APP_URL!, //
|
|
27
|
+
appUrl: process.env.QELOS_APP_URL!, // managed Qelos app origin
|
|
32
28
|
},
|
|
33
29
|
}),
|
|
34
30
|
],
|
|
@@ -36,31 +32,50 @@ import { QelosModule } from '@qelos/integrator-nest';
|
|
|
36
32
|
export class AppModule {}
|
|
37
33
|
```
|
|
38
34
|
|
|
39
|
-
`forRoot` registers
|
|
40
|
-
its scope, import the module without `forRoot` and apply the middleware
|
|
41
|
-
yourself in `configure`:
|
|
35
|
+
`forRoot` registers:
|
|
42
36
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
QelosMiddleware,
|
|
46
|
-
QelosModule,
|
|
47
|
-
type QelosModuleOptions,
|
|
48
|
-
} from '@qelos/integrator-nest';
|
|
49
|
-
import { type MiddlewareConsumer, Module, type NestModule } from '@nestjs/common';
|
|
37
|
+
1. **`QelosMiddleware`** on `*` — resolves `request.qelos` via `/api/me` cookie pass-through (unless the path is skipped).
|
|
38
|
+
2. **`QelosProxyMiddleware`** on `api/*splat` — reverse-proxies `/api/**` to the same resolved origin, unless `disableProxy: true`.
|
|
50
39
|
|
|
51
|
-
|
|
52
|
-
config: { appUrl: process.env.QELOS_APP_URL! },
|
|
53
|
-
};
|
|
40
|
+
User-defined controllers and routes still take precedence for paths they own; the proxy only handles `/api/**` traffic that reaches the middleware stack.
|
|
54
41
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
42
|
+
To narrow where the **resolver** runs, import the module and apply `QelosMiddleware` yourself (see Nest docs on `MiddlewareConsumer`). You still need `QELOS_MODULE_OPTIONS` and `QelosProxyMiddleware` provided if you split registration.
|
|
43
|
+
|
|
44
|
+
## API proxy
|
|
45
|
+
|
|
46
|
+
The proxy forwards the inbound request (method, URL path + query, body stream, and headers except hop-by-hop) to `<proxyTarget>` + the same path. Upstream `Set-Cookie` headers are rewritten so `Domain=` matches the inbound `Host` (port stripped), making Qelos session cookies first-party on your Nest host.
|
|
47
|
+
|
|
48
|
+
### Resolving the proxy target
|
|
49
|
+
|
|
50
|
+
The managed app URL (`config.appUrl`) is the default target. Env vars are dev-time overrides when `appUrl` is not reachable from localhost:
|
|
51
|
+
|
|
52
|
+
1. `QELOS_PROXY_TARGET`
|
|
53
|
+
2. `QELOS_IP`
|
|
54
|
+
3. `QELOS_API_IP`
|
|
55
|
+
4. `config.appUrl`
|
|
56
|
+
|
|
57
|
+
Whitespace-only env values are ignored. If nothing resolves, the proxy responds with **503**. The user resolver uses the same chain; without a target and without `apiToken`, anonymous requests are allowed unless `requireAuth` is set.
|
|
58
|
+
|
|
59
|
+
### Opting out
|
|
60
|
+
|
|
61
|
+
Set `disableProxy: true` in config to skip registering `QelosProxyMiddleware` — for example when you implement every `/api/*` route in Nest or terminate the proxy elsewhere.
|
|
62
|
+
|
|
63
|
+
WebSocket upgrades are **not** proxied.
|
|
64
|
+
|
|
65
|
+
## User-resolution middleware
|
|
66
|
+
|
|
67
|
+
On non-skipped paths, the middleware:
|
|
68
|
+
|
|
69
|
+
1. Builds a per-request SDK (`createRequestSdk`) — with `apiToken`, static auth; otherwise `extraHeaders` forwards the live `Cookie` and `Authorization` headers on every SDK call.
|
|
70
|
+
2. Resolves the proxy target (same priority as above).
|
|
71
|
+
3. If there is no target and no `apiToken`, returns anonymous context (or **401** when `requireAuth` is true).
|
|
72
|
+
4. If there is a target, `GET ${target}/api/me` with cookies and authorization forwarded. Each upstream `Set-Cookie` is appended to the outgoing response with `Domain=` rewritten to the inbound host.
|
|
73
|
+
5. On success, loads workspaces via `sdk.workspaces.getList()` (errors → empty list).
|
|
74
|
+
6. Sets **active workspace** to `resolveWorkspace()` if provided, else `user.workspace` from `/api/me` — **not** `workspaces[0]`.
|
|
75
|
+
|
|
76
|
+
When `disableProxy !== true`, `/api/` is **prepended** to `skipPaths` automatically so proxied `/api/**` traffic is not double-handled by this `/api/me` probe.
|
|
77
|
+
|
|
78
|
+
> Rotated cookies may include `Secure`. Over plain HTTP, browsers may drop them — use HTTPS locally or configure Qelos for non-Secure cookies in dev.
|
|
64
79
|
|
|
65
80
|
## Use in controllers
|
|
66
81
|
|
|
@@ -79,7 +94,6 @@ import type { IWorkspace } from '@qelos/sdk/workspaces';
|
|
|
79
94
|
@Controller()
|
|
80
95
|
export class AppController {
|
|
81
96
|
@Get('me')
|
|
82
|
-
// user/workspace are null when the request is anonymous
|
|
83
97
|
me(
|
|
84
98
|
@QelosUser() user: IUser | null,
|
|
85
99
|
@QelosWorkspace() workspace: IWorkspace | null,
|
|
@@ -87,7 +101,6 @@ export class AppController {
|
|
|
87
101
|
return { user, workspace };
|
|
88
102
|
}
|
|
89
103
|
|
|
90
|
-
// Short-circuit with 401 when there is no authenticated user.
|
|
91
104
|
@Get('private')
|
|
92
105
|
@UseGuards(QelosAuthGuard)
|
|
93
106
|
private(@QelosCtx() ctx: QelosRequestContext) {
|
|
@@ -96,71 +109,22 @@ export class AppController {
|
|
|
96
109
|
}
|
|
97
110
|
```
|
|
98
111
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
1. Reads the access token from `Authorization: Bearer ...` or the
|
|
102
|
-
`q_access_token` cookie, and the refresh token from `q_refresh_token`.
|
|
103
|
-
2. Builds a per-request Qelos SDK instance bound to those tokens.
|
|
104
|
-
3. Calls `sdk.authentication.getLoggedInUser()` and
|
|
105
|
-
`sdk.workspaces.getList()`.
|
|
106
|
-
4. Picks the active workspace (first by default — override with
|
|
107
|
-
`resolveWorkspace`).
|
|
108
|
-
5. Attaches everything to `request.qelos`.
|
|
109
|
-
|
|
110
|
-
The middleware never throws for anonymous requests by default — it just
|
|
111
|
-
leaves `request.qelos.user` and `request.qelos.workspace` as `null`. Pass
|
|
112
|
-
`requireAuth: true` to short-circuit anonymous requests with `401`, or use
|
|
113
|
-
the per-route `QelosAuthGuard` for finer-grained control.
|
|
114
|
-
|
|
115
|
-
## Token refresh
|
|
116
|
-
|
|
117
|
-
When the access token is rejected, the SDK tries to recover, in order:
|
|
118
|
-
|
|
119
|
-
1. The **refresh token** (`q_refresh_token`) via
|
|
120
|
-
`sdk.authentication.refreshToken()` — issues a new access + refresh pair.
|
|
121
|
-
2. The **cookie token** (the access token cookie itself) via
|
|
122
|
-
`sdk.authentication.refreshCookieToken()` — used for cookie-only sessions
|
|
123
|
-
that do not carry a separate refresh token (e.g. social-auth flows).
|
|
112
|
+
`QelosRequestContext`:
|
|
124
113
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
114
|
+
| field | description |
|
|
115
|
+
|--------------|-------------|
|
|
116
|
+
| `user` | `IUser` from `/api/me`, or `null`. |
|
|
117
|
+
| `workspace` | Active workspace or `null`. |
|
|
118
|
+
| `workspaces` | Workspaces from `getList()`. |
|
|
119
|
+
| `sdk` | Request-scoped `QelosSDK` forwarding cookies live. |
|
|
128
120
|
|
|
129
|
-
|
|
130
|
-
push the new tokens into a session store:
|
|
121
|
+
## API token mode
|
|
131
122
|
|
|
132
|
-
|
|
133
|
-
QelosModule.forRoot({
|
|
134
|
-
config: { appUrl: process.env.QELOS_APP_URL! },
|
|
135
|
-
onTokenRefresh: async ({ request, response, newTokens }) => {
|
|
136
|
-
await sessionStore.rotate(request.session.id, newTokens);
|
|
137
|
-
},
|
|
138
|
-
});
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
The hook receives `{ request, response, oldTokens, newTokens, sdk }`. The
|
|
142
|
-
`request` and `response` types are intentionally generic since Nest can run
|
|
143
|
-
on either Express or Fastify.
|
|
144
|
-
|
|
145
|
-
### Manual cookie refresh
|
|
146
|
-
|
|
147
|
-
Long-lived integrator-hosted sessions can also call the SDK directly to
|
|
148
|
-
proactively refresh the cookie token:
|
|
149
|
-
|
|
150
|
-
```ts
|
|
151
|
-
@Get('refresh-session')
|
|
152
|
-
async refresh(@QelosCtx() ctx: QelosRequestContext) {
|
|
153
|
-
const result = await ctx.sdk.authentication.refreshCookieToken();
|
|
154
|
-
// result.headers['set-cookie'] — fresh cookie value to forward
|
|
155
|
-
return { user: result.payload.user };
|
|
156
|
-
}
|
|
157
|
-
```
|
|
123
|
+
For service-to-service traffic, set `apiToken` — the middleware skips the `/api/me` cookie flow for identity (you still get an SDK with the static token). Pair with `requireAuth` / `QelosGuard` as needed.
|
|
158
124
|
|
|
159
125
|
## Async configuration
|
|
160
126
|
|
|
161
127
|
```ts
|
|
162
|
-
import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
163
|
-
|
|
164
128
|
QelosModule.forRootAsync({
|
|
165
129
|
imports: [ConfigModule],
|
|
166
130
|
inject: [ConfigService],
|
|
@@ -173,39 +137,33 @@ QelosModule.forRootAsync({
|
|
|
173
137
|
});
|
|
174
138
|
```
|
|
175
139
|
|
|
176
|
-
## Configuration
|
|
140
|
+
## Configuration reference
|
|
177
141
|
|
|
178
142
|
```ts
|
|
179
143
|
QelosModule.forRoot({
|
|
180
144
|
config: {
|
|
181
|
-
appUrl: 'https://
|
|
145
|
+
appUrl: 'https://your-managed-app.com',
|
|
182
146
|
|
|
183
|
-
// Service-to-service: use a static API token instead of cookies/refresh.
|
|
184
147
|
apiToken: process.env.QELOS_API_TOKEN,
|
|
185
148
|
|
|
186
|
-
// Cookie names. Defaults shown.
|
|
187
|
-
accessTokenCookie: 'q_access_token',
|
|
188
|
-
refreshTokenCookie: 'q_refresh_token',
|
|
189
|
-
|
|
190
|
-
// Reject anonymous requests with 401. Defaults to false.
|
|
191
149
|
requireAuth: false,
|
|
192
150
|
|
|
193
|
-
// Skip the middleware entirely for these path prefixes.
|
|
194
151
|
skipPaths: ['/health', '/metrics'],
|
|
195
152
|
|
|
196
|
-
|
|
153
|
+
disableProxy: false,
|
|
154
|
+
|
|
197
155
|
sdkOptions: {},
|
|
198
156
|
},
|
|
199
157
|
|
|
200
|
-
// Override workspace selection. Defaults to `workspaces[0]`.
|
|
201
158
|
resolveWorkspace: ({ request, user, workspaces }) => {
|
|
202
159
|
const headerId = request.headers['x-qelos-workspace'];
|
|
203
|
-
|
|
160
|
+
const raw = Array.isArray(headerId) ? headerId[0] : headerId;
|
|
161
|
+
return workspaces.find((w) => w._id === raw) || user.workspace || null;
|
|
204
162
|
},
|
|
205
163
|
});
|
|
206
164
|
```
|
|
207
165
|
|
|
208
166
|
## Requirements
|
|
209
167
|
|
|
210
|
-
- Node.js >= 18
|
|
211
|
-
- NestJS 9, 10, or 11
|
|
168
|
+
- Node.js >= 18
|
|
169
|
+
- NestJS 9, 10, or 11
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rewrite the `Domain=` attribute of a single `Set-Cookie` header value.
|
|
3
|
+
*
|
|
4
|
+
* - If the cookie contains a `Domain=<value>` attribute (case-insensitive), its
|
|
5
|
+
* value is replaced with `newDomain`, with any trailing `:port` suffix
|
|
6
|
+
* stripped first (cookie `Domain` attributes do not include a port).
|
|
7
|
+
* - If `newDomain` is `undefined` (or empty), the entire `; Domain=<value>`
|
|
8
|
+
* segment is removed so the browser scopes the cookie to the current host.
|
|
9
|
+
* - If no `Domain=` attribute is present, the input is returned unchanged.
|
|
10
|
+
*
|
|
11
|
+
* All other attributes, their casing/order and the original cookie name/value
|
|
12
|
+
* bytes are preserved.
|
|
13
|
+
*/
|
|
14
|
+
export declare function rewriteSetCookieDomain(setCookie: string, newDomain: string | undefined): string;
|
|
15
|
+
/**
|
|
16
|
+
* Apply {@link rewriteSetCookieDomain} to each entry of a `Set-Cookie` array
|
|
17
|
+
* (e.g. the result of `Headers.getSetCookie()`).
|
|
18
|
+
*/
|
|
19
|
+
export declare function rewriteSetCookieDomains(values: string[], newDomain: string | undefined): string[];
|
package/dist/cookies.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rewriteSetCookieDomain = rewriteSetCookieDomain;
|
|
4
|
+
exports.rewriteSetCookieDomains = rewriteSetCookieDomains;
|
|
5
|
+
/**
|
|
6
|
+
* Rewrite the `Domain=` attribute of a single `Set-Cookie` header value.
|
|
7
|
+
*
|
|
8
|
+
* - If the cookie contains a `Domain=<value>` attribute (case-insensitive), its
|
|
9
|
+
* value is replaced with `newDomain`, with any trailing `:port` suffix
|
|
10
|
+
* stripped first (cookie `Domain` attributes do not include a port).
|
|
11
|
+
* - If `newDomain` is `undefined` (or empty), the entire `; Domain=<value>`
|
|
12
|
+
* segment is removed so the browser scopes the cookie to the current host.
|
|
13
|
+
* - If no `Domain=` attribute is present, the input is returned unchanged.
|
|
14
|
+
*
|
|
15
|
+
* All other attributes, their casing/order and the original cookie name/value
|
|
16
|
+
* bytes are preserved.
|
|
17
|
+
*/
|
|
18
|
+
function rewriteSetCookieDomain(setCookie, newDomain) {
|
|
19
|
+
const domainSegment = /;\s*Domain\s*=\s*[^;]+/i;
|
|
20
|
+
if (!domainSegment.test(setCookie))
|
|
21
|
+
return setCookie;
|
|
22
|
+
const stripped = newDomain ? stripPort(newDomain) : '';
|
|
23
|
+
if (!stripped) {
|
|
24
|
+
return setCookie.replace(domainSegment, '');
|
|
25
|
+
}
|
|
26
|
+
return setCookie.replace(/(;\s*Domain\s*=\s*)[^;]+/i, `$1${stripped}`);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Apply {@link rewriteSetCookieDomain} to each entry of a `Set-Cookie` array
|
|
30
|
+
* (e.g. the result of `Headers.getSetCookie()`).
|
|
31
|
+
*/
|
|
32
|
+
function rewriteSetCookieDomains(values, newDomain) {
|
|
33
|
+
return values.map((value) => rewriteSetCookieDomain(value, newDomain));
|
|
34
|
+
}
|
|
35
|
+
function stripPort(host) {
|
|
36
|
+
if (host.startsWith('[')) {
|
|
37
|
+
const end = host.indexOf(']');
|
|
38
|
+
return end === -1 ? host : host.slice(1, end);
|
|
39
|
+
}
|
|
40
|
+
const colon = host.indexOf(':');
|
|
41
|
+
return colon === -1 ? host : host.slice(0, colon);
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=cookies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookies.js","sourceRoot":"","sources":["../src/cookies.ts"],"names":[],"mappings":";;AAaA,wDAeC;AAMD,0DAKC;AAvCD;;;;;;;;;;;;GAYG;AACH,SAAgB,sBAAsB,CACpC,SAAiB,EACjB,SAA6B;IAE7B,MAAM,aAAa,GAAG,yBAAyB,CAAC;IAChD,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IAErD,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACvD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,SAAS,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,SAAS,CAAC,OAAO,CACtB,2BAA2B,EAC3B,KAAK,QAAQ,EAAE,CAChB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAgB,uBAAuB,CACrC,MAAgB,EAChB,SAA6B;IAE7B,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,sBAAsB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC;AACzE,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC7B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC9B,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAChD,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAChC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
// Run with: `pnpm -F @qelos/integrator-nest test` (includes src/**/*.test.ts)
|
|
7
|
+
const node_test_1 = require("node:test");
|
|
8
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
9
|
+
const cookies_1 = require("./cookies");
|
|
10
|
+
(0, node_test_1.describe)('rewriteSetCookieDomain', () => {
|
|
11
|
+
(0, node_test_1.it)('replaces a leading-dot Domain value', () => {
|
|
12
|
+
const input = 'sid=abc; Path=/; Domain=.qelos.app; HttpOnly; Secure';
|
|
13
|
+
strict_1.default.equal((0, cookies_1.rewriteSetCookieDomain)(input, 'example.com'), 'sid=abc; Path=/; Domain=example.com; HttpOnly; Secure');
|
|
14
|
+
});
|
|
15
|
+
(0, node_test_1.it)('replaces a wildcard Domain value', () => {
|
|
16
|
+
const input = 'sid=abc; Path=/; Domain=*.qelos.app; HttpOnly';
|
|
17
|
+
strict_1.default.equal((0, cookies_1.rewriteSetCookieDomain)(input, 'example.com'), 'sid=abc; Path=/; Domain=example.com; HttpOnly');
|
|
18
|
+
});
|
|
19
|
+
(0, node_test_1.it)('returns the cookie unchanged when no Domain attribute is present', () => {
|
|
20
|
+
const input = 'sid=abc; Path=/; HttpOnly; Secure; SameSite=Lax';
|
|
21
|
+
strict_1.default.equal((0, cookies_1.rewriteSetCookieDomain)(input, 'example.com'), input);
|
|
22
|
+
});
|
|
23
|
+
(0, node_test_1.it)('strips the port from a host:port newDomain before substitution', () => {
|
|
24
|
+
const input = 'sid=abc; Domain=.qelos.app; Path=/';
|
|
25
|
+
strict_1.default.equal((0, cookies_1.rewriteSetCookieDomain)(input, 'localhost:3000'), 'sid=abc; Domain=localhost; Path=/');
|
|
26
|
+
});
|
|
27
|
+
(0, node_test_1.it)('preserves attribute order and other attributes across replacement', () => {
|
|
28
|
+
const input = 'sid=abc; Path=/; Domain=.qelos.app; HttpOnly; Secure; SameSite=Lax; Max-Age=3600';
|
|
29
|
+
strict_1.default.equal((0, cookies_1.rewriteSetCookieDomain)(input, 'example.com'), 'sid=abc; Path=/; Domain=example.com; HttpOnly; Secure; SameSite=Lax; Max-Age=3600');
|
|
30
|
+
});
|
|
31
|
+
(0, node_test_1.it)('preserves an Expires attribute (which contains commas) across replacement', () => {
|
|
32
|
+
const input = 'sid=abc; Domain=.qelos.app; Expires=Wed, 21 Oct 2026 07:28:00 GMT; Path=/';
|
|
33
|
+
strict_1.default.equal((0, cookies_1.rewriteSetCookieDomain)(input, 'example.com'), 'sid=abc; Domain=example.com; Expires=Wed, 21 Oct 2026 07:28:00 GMT; Path=/');
|
|
34
|
+
});
|
|
35
|
+
(0, node_test_1.it)('matches the Domain attribute name case-insensitively and preserves its casing', () => {
|
|
36
|
+
const input = 'sid=abc; domain=.qelos.app; Path=/';
|
|
37
|
+
strict_1.default.equal((0, cookies_1.rewriteSetCookieDomain)(input, 'example.com'), 'sid=abc; domain=example.com; Path=/');
|
|
38
|
+
});
|
|
39
|
+
(0, node_test_1.it)('strips the entire Domain segment when newDomain is undefined', () => {
|
|
40
|
+
const input = 'sid=abc; Path=/; Domain=.qelos.app; HttpOnly; Secure; SameSite=Lax';
|
|
41
|
+
strict_1.default.equal((0, cookies_1.rewriteSetCookieDomain)(input, undefined), 'sid=abc; Path=/; HttpOnly; Secure; SameSite=Lax');
|
|
42
|
+
});
|
|
43
|
+
(0, node_test_1.it)('strips the entire Domain segment when newDomain is an empty string', () => {
|
|
44
|
+
const input = 'sid=abc; Domain=.qelos.app; Path=/';
|
|
45
|
+
strict_1.default.equal((0, cookies_1.rewriteSetCookieDomain)(input, ''), 'sid=abc; Path=/');
|
|
46
|
+
});
|
|
47
|
+
(0, node_test_1.it)('removes the Domain segment when it is the last attribute', () => {
|
|
48
|
+
const input = 'sid=abc; Path=/; Domain=.qelos.app';
|
|
49
|
+
strict_1.default.equal((0, cookies_1.rewriteSetCookieDomain)(input, undefined), 'sid=abc; Path=/');
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
(0, node_test_1.describe)('rewriteSetCookieDomains', () => {
|
|
53
|
+
(0, node_test_1.it)('applies the rewrite to each entry of an array', () => {
|
|
54
|
+
const values = [
|
|
55
|
+
'a=1; Domain=.qelos.app; Path=/',
|
|
56
|
+
'b=2; Path=/; HttpOnly',
|
|
57
|
+
'c=3; Domain=*.qelos.app; Secure',
|
|
58
|
+
];
|
|
59
|
+
strict_1.default.deepEqual((0, cookies_1.rewriteSetCookieDomains)(values, 'example.com'), [
|
|
60
|
+
'a=1; Domain=example.com; Path=/',
|
|
61
|
+
'b=2; Path=/; HttpOnly',
|
|
62
|
+
'c=3; Domain=example.com; Secure',
|
|
63
|
+
]);
|
|
64
|
+
});
|
|
65
|
+
(0, node_test_1.it)('strips the Domain segment from each entry when newDomain is undefined', () => {
|
|
66
|
+
const values = [
|
|
67
|
+
'a=1; Domain=.qelos.app; Path=/',
|
|
68
|
+
'b=2; Domain=*.qelos.app; HttpOnly',
|
|
69
|
+
];
|
|
70
|
+
strict_1.default.deepEqual((0, cookies_1.rewriteSetCookieDomains)(values, undefined), [
|
|
71
|
+
'a=1; Path=/',
|
|
72
|
+
'b=2; HttpOnly',
|
|
73
|
+
]);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
//# sourceMappingURL=cookies.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookies.test.js","sourceRoot":"","sources":["../src/cookies.test.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,8 +2,11 @@ export { QELOS_MODULE_OPTIONS, QELOS_SDK } from './constants';
|
|
|
2
2
|
export { QelosModule } from './module';
|
|
3
3
|
export type { QelosModuleAsyncOptions, QelosOptionsFactory, } from './module';
|
|
4
4
|
export { QelosMiddleware } from './middleware';
|
|
5
|
+
export { QelosProxyMiddleware } from './proxy.middleware';
|
|
5
6
|
export { QelosAuthGuard, QelosGuard } from './guard';
|
|
6
7
|
export { QelosCtx, QelosSdk, QelosUser, QelosWorkspace } from './decorators';
|
|
7
8
|
export { createRequestSdk } from './sdk-factory';
|
|
8
9
|
export type { CreateSdkParams } from './sdk-factory';
|
|
9
|
-
export
|
|
10
|
+
export { rewriteSetCookieDomain, rewriteSetCookieDomains } from './cookies';
|
|
11
|
+
export { resolveQelosProxyTarget } from './proxy-target';
|
|
12
|
+
export type { AnyRequest, AnyResponse, QelosModuleOptions, QelosNestConfig, QelosRequestContext, WorkspaceResolver, } from './types';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createRequestSdk = exports.QelosWorkspace = exports.QelosUser = exports.QelosSdk = exports.QelosCtx = exports.QelosGuard = exports.QelosAuthGuard = exports.QelosMiddleware = exports.QelosModule = exports.QELOS_SDK = exports.QELOS_MODULE_OPTIONS = void 0;
|
|
3
|
+
exports.resolveQelosProxyTarget = exports.rewriteSetCookieDomains = exports.rewriteSetCookieDomain = exports.createRequestSdk = exports.QelosWorkspace = exports.QelosUser = exports.QelosSdk = exports.QelosCtx = exports.QelosGuard = exports.QelosAuthGuard = exports.QelosProxyMiddleware = exports.QelosMiddleware = exports.QelosModule = exports.QELOS_SDK = exports.QELOS_MODULE_OPTIONS = void 0;
|
|
4
4
|
var constants_1 = require("./constants");
|
|
5
5
|
Object.defineProperty(exports, "QELOS_MODULE_OPTIONS", { enumerable: true, get: function () { return constants_1.QELOS_MODULE_OPTIONS; } });
|
|
6
6
|
Object.defineProperty(exports, "QELOS_SDK", { enumerable: true, get: function () { return constants_1.QELOS_SDK; } });
|
|
@@ -8,6 +8,8 @@ var module_1 = require("./module");
|
|
|
8
8
|
Object.defineProperty(exports, "QelosModule", { enumerable: true, get: function () { return module_1.QelosModule; } });
|
|
9
9
|
var middleware_1 = require("./middleware");
|
|
10
10
|
Object.defineProperty(exports, "QelosMiddleware", { enumerable: true, get: function () { return middleware_1.QelosMiddleware; } });
|
|
11
|
+
var proxy_middleware_1 = require("./proxy.middleware");
|
|
12
|
+
Object.defineProperty(exports, "QelosProxyMiddleware", { enumerable: true, get: function () { return proxy_middleware_1.QelosProxyMiddleware; } });
|
|
11
13
|
var guard_1 = require("./guard");
|
|
12
14
|
Object.defineProperty(exports, "QelosAuthGuard", { enumerable: true, get: function () { return guard_1.QelosAuthGuard; } });
|
|
13
15
|
Object.defineProperty(exports, "QelosGuard", { enumerable: true, get: function () { return guard_1.QelosGuard; } });
|
|
@@ -18,4 +20,9 @@ Object.defineProperty(exports, "QelosUser", { enumerable: true, get: function ()
|
|
|
18
20
|
Object.defineProperty(exports, "QelosWorkspace", { enumerable: true, get: function () { return decorators_1.QelosWorkspace; } });
|
|
19
21
|
var sdk_factory_1 = require("./sdk-factory");
|
|
20
22
|
Object.defineProperty(exports, "createRequestSdk", { enumerable: true, get: function () { return sdk_factory_1.createRequestSdk; } });
|
|
23
|
+
var cookies_1 = require("./cookies");
|
|
24
|
+
Object.defineProperty(exports, "rewriteSetCookieDomain", { enumerable: true, get: function () { return cookies_1.rewriteSetCookieDomain; } });
|
|
25
|
+
Object.defineProperty(exports, "rewriteSetCookieDomains", { enumerable: true, get: function () { return cookies_1.rewriteSetCookieDomains; } });
|
|
26
|
+
var proxy_target_1 = require("./proxy-target");
|
|
27
|
+
Object.defineProperty(exports, "resolveQelosProxyTarget", { enumerable: true, get: function () { return proxy_target_1.resolveQelosProxyTarget; } });
|
|
21
28
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,yCAA8D;AAArD,iHAAA,oBAAoB,OAAA;AAAE,sGAAA,SAAS,OAAA;AACxC,mCAAuC;AAA9B,qGAAA,WAAW,OAAA;AAKpB,2CAA+C;AAAtC,6GAAA,eAAe,OAAA;AACxB,iCAAqD;AAA5C,uGAAA,cAAc,OAAA;AAAE,mGAAA,UAAU,OAAA;AACnC,2CAA6E;AAApE,sGAAA,QAAQ,OAAA;AAAE,sGAAA,QAAQ,OAAA;AAAE,uGAAA,SAAS,OAAA;AAAE,4GAAA,cAAc,OAAA;AACtD,6CAAiD;AAAxC,+GAAA,gBAAgB,OAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,yCAA8D;AAArD,iHAAA,oBAAoB,OAAA;AAAE,sGAAA,SAAS,OAAA;AACxC,mCAAuC;AAA9B,qGAAA,WAAW,OAAA;AAKpB,2CAA+C;AAAtC,6GAAA,eAAe,OAAA;AACxB,uDAA0D;AAAjD,wHAAA,oBAAoB,OAAA;AAC7B,iCAAqD;AAA5C,uGAAA,cAAc,OAAA;AAAE,mGAAA,UAAU,OAAA;AACnC,2CAA6E;AAApE,sGAAA,QAAQ,OAAA;AAAE,sGAAA,QAAQ,OAAA;AAAE,uGAAA,SAAS,OAAA;AAAE,4GAAA,cAAc,OAAA;AACtD,6CAAiD;AAAxC,+GAAA,gBAAgB,OAAA;AAEzB,qCAA4E;AAAnE,iHAAA,sBAAsB,OAAA;AAAE,kHAAA,uBAAuB,OAAA;AACxD,+CAAyD;AAAhD,uHAAA,uBAAuB,OAAA"}
|
package/dist/middleware.js
CHANGED
|
@@ -15,8 +15,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
15
15
|
exports.QelosMiddleware = void 0;
|
|
16
16
|
const common_1 = require("@nestjs/common");
|
|
17
17
|
const constants_1 = require("./constants");
|
|
18
|
-
const
|
|
18
|
+
const cookies_1 = require("./cookies");
|
|
19
|
+
const proxy_target_1 = require("./proxy-target");
|
|
19
20
|
const request_utils_1 = require("./request-utils");
|
|
21
|
+
const sdk_factory_1 = require("./sdk-factory");
|
|
22
|
+
function buildMeUrl(base) {
|
|
23
|
+
return `${base.replace(/\/+$/, '')}/api/me`;
|
|
24
|
+
}
|
|
20
25
|
let QelosMiddleware = class QelosMiddleware {
|
|
21
26
|
constructor(options) {
|
|
22
27
|
this.options = options;
|
|
@@ -25,32 +30,21 @@ let QelosMiddleware = class QelosMiddleware {
|
|
|
25
30
|
const request = req;
|
|
26
31
|
const response = res;
|
|
27
32
|
const { config, resolveWorkspace } = this.options;
|
|
28
|
-
const
|
|
29
|
-
(async ({ response: r, newTokens }) => {
|
|
30
|
-
(0, request_utils_1.writeTokensToCookies)(r, config, newTokens);
|
|
31
|
-
});
|
|
33
|
+
const sdkFetch = (config.sdkOptions?.fetch ?? globalThis.fetch);
|
|
32
34
|
if ((0, request_utils_1.shouldSkip)(request, config)) {
|
|
33
35
|
next();
|
|
34
36
|
return;
|
|
35
37
|
}
|
|
36
|
-
const
|
|
37
|
-
const sdk = (0, sdk_factory_1.createRequestSdk)({
|
|
38
|
-
config,
|
|
39
|
-
tokens,
|
|
40
|
-
request,
|
|
41
|
-
response,
|
|
42
|
-
onTokenRefresh,
|
|
43
|
-
});
|
|
38
|
+
const sdk = (0, sdk_factory_1.createRequestSdk)({ config, request });
|
|
44
39
|
const ctx = {
|
|
45
40
|
user: null,
|
|
46
41
|
workspace: null,
|
|
47
42
|
workspaces: [],
|
|
48
43
|
sdk,
|
|
49
|
-
tokens,
|
|
50
44
|
};
|
|
51
45
|
request.qelos = ctx;
|
|
52
|
-
const
|
|
53
|
-
if (!
|
|
46
|
+
const base = (0, proxy_target_1.resolveQelosProxyTarget)(config);
|
|
47
|
+
if (!base && !config.apiToken) {
|
|
54
48
|
if (config.requireAuth) {
|
|
55
49
|
next(new common_1.UnauthorizedException());
|
|
56
50
|
return;
|
|
@@ -58,10 +52,56 @@ let QelosMiddleware = class QelosMiddleware {
|
|
|
58
52
|
next();
|
|
59
53
|
return;
|
|
60
54
|
}
|
|
61
|
-
|
|
62
|
-
|
|
55
|
+
if (base) {
|
|
56
|
+
const headers = {};
|
|
57
|
+
const cookieHeader = request.headers.cookie;
|
|
58
|
+
const cookie = typeof cookieHeader === 'string'
|
|
59
|
+
? cookieHeader
|
|
60
|
+
: Array.isArray(cookieHeader)
|
|
61
|
+
? cookieHeader.join('; ')
|
|
62
|
+
: undefined;
|
|
63
|
+
if (cookie)
|
|
64
|
+
headers.cookie = cookie;
|
|
65
|
+
const rawAuth = request.headers.authorization;
|
|
66
|
+
const authHeader = Array.isArray(rawAuth) ? rawAuth[0] : rawAuth;
|
|
67
|
+
if (authHeader)
|
|
68
|
+
headers.authorization = authHeader;
|
|
69
|
+
const hostHeader = request.headers.host;
|
|
70
|
+
const originalHost = typeof hostHeader === 'string'
|
|
71
|
+
? hostHeader
|
|
72
|
+
: Array.isArray(hostHeader)
|
|
73
|
+
? hostHeader[0]
|
|
74
|
+
: undefined;
|
|
75
|
+
let upstream;
|
|
76
|
+
try {
|
|
77
|
+
upstream = await sdkFetch(buildMeUrl(base), {
|
|
78
|
+
method: 'GET',
|
|
79
|
+
headers,
|
|
80
|
+
redirect: 'manual',
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
if (config.requireAuth) {
|
|
85
|
+
next(new common_1.UnauthorizedException());
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
next();
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const setCookieValues = upstream.headers.getSetCookie?.() ?? [];
|
|
92
|
+
for (const value of setCookieValues) {
|
|
93
|
+
(0, request_utils_1.appendSetCookie)(response, (0, cookies_1.rewriteSetCookieDomain)(value, originalHost));
|
|
94
|
+
}
|
|
95
|
+
if (upstream.ok) {
|
|
96
|
+
try {
|
|
97
|
+
ctx.user = (await upstream.json());
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
ctx.user = null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
63
103
|
}
|
|
64
|
-
|
|
104
|
+
if (!ctx.user) {
|
|
65
105
|
if (config.requireAuth) {
|
|
66
106
|
next(new common_1.UnauthorizedException());
|
|
67
107
|
return;
|
|
@@ -75,18 +115,18 @@ let QelosMiddleware = class QelosMiddleware {
|
|
|
75
115
|
catch {
|
|
76
116
|
ctx.workspaces = [];
|
|
77
117
|
}
|
|
78
|
-
if (
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
ctx.workspace
|
|
89
|
-
|
|
118
|
+
if (resolveWorkspace) {
|
|
119
|
+
ctx.workspace =
|
|
120
|
+
(await resolveWorkspace({
|
|
121
|
+
request,
|
|
122
|
+
user: ctx.user,
|
|
123
|
+
workspaces: ctx.workspaces,
|
|
124
|
+
})) || null;
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
ctx.workspace =
|
|
128
|
+
ctx.user.workspace ||
|
|
129
|
+
null;
|
|
90
130
|
}
|
|
91
131
|
next();
|
|
92
132
|
}
|
package/dist/middleware.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAKwB;
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
|
package/dist/module-options.d.ts
CHANGED
|
@@ -3,5 +3,8 @@ import type { QelosModuleOptions, QelosNestConfig } from './types';
|
|
|
3
3
|
* `forRoot` / `forRootAsync` accept either a full {@link QelosModuleOptions}
|
|
4
4
|
* object or a shorthand {@link QelosNestConfig} (same shape as Express
|
|
5
5
|
* `createQelosMiddleware({ config })`).
|
|
6
|
+
*
|
|
7
|
+
* When `disableProxy` is not `true`, `/api/` is prepended to `skipPaths` so
|
|
8
|
+
* the user resolver does not shadow the `/api/**` proxy.
|
|
6
9
|
*/
|
|
7
10
|
export declare function normalizeModuleOptions(input: QelosNestConfig | QelosModuleOptions): QelosModuleOptions;
|