@qelos/integrator-express 4.2.0 → 4.2.2

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 CHANGED
@@ -160,6 +160,14 @@ import { requireUser } from '@qelos/integrator-express';
160
160
  app.get('/private', requireUser((req, res) => res.json(req.qelos.user)));
161
161
  ```
162
162
 
163
+ ## MCP OAuth
164
+
165
+ When your custom domain serves MCP clients as an OAuth issuer, add `/login` and
166
+ `/mcp/authorize` routes and use the re-exported MCP helpers
167
+ (`resolveMcpLoginRedirect`, `decodeMcpOAuthStatePayload`,
168
+ `completeMcpAuthorizationCallback`, …). See the Qelos docs:
169
+ [MCP OAuth for integrator apps](https://docs.qelos.io/auth/mcp-oauth-integrators).
170
+
163
171
  ## Workspace resolution
164
172
 
165
173
  `req.qelos.workspace` defaults to whatever the managed Qelos app reports on
@@ -204,7 +212,18 @@ createQelosIntegrator({
204
212
  });
205
213
  ```
206
214
 
207
- ## Requirements
215
+ ## Version support
216
+
217
+ | Runtime | Supported versions |
218
+ |---------|-------------------|
219
+ | Node.js | >= 18 (uses global `fetch` and `Headers.getSetCookie`) |
220
+ | Express | 4.17+ and 5.x |
221
+
222
+ The integrator is tested against Express 4 and Express 5 in CI (`pnpm --filter
223
+ @qelos/integrator-express test`). Express is a peer dependency — install the
224
+ major version your app already uses; no integrator-specific adapter is required.
208
225
 
209
- - Node.js >= 18 (uses global `fetch` and `Headers.getSetCookie`).
210
- - Express 4 or 5.
226
+ When upgrading from Express 4 to 5, see the [Express 5 migration
227
+ guide](https://expressjs.com/en/guide/migrating-5.html). This package uses only
228
+ APIs that are stable across both majors (middleware, `req.headers`, response
229
+ headers, and request streaming for the proxy).
package/dist/index.d.ts CHANGED
@@ -10,6 +10,7 @@ export { rewriteSetCookieDomain, rewriteSetCookieDomains } from './cookies';
10
10
  export { resolveQelosProxyTarget } from './proxy-target';
11
11
  export type { QelosExpressConfig, QelosRequestContext, } from './types';
12
12
  export { completeSocialAuthCallback, getSocialAuthSetCookieParts, parseSocialCallbackRefreshToken, type SocialAuthCallbackPayload, type SocialCallbackInput, } from './social-auth';
13
+ export { completeMcpAuthorizationCallback, appendMcpAccessDeniedRedirect, buildMcpAuthorizePath, buildMcpAuthorizePathFromQuery, buildMcpConsentPageUrl, buildMcpLoginRedirectUrl, buildMcpTokenExchangeBody, decodeMcpOAuthStatePayload, parseMcpCallbackParams, resolveMcpLoginRedirect, type CompleteMcpAuthorizationCallbackOptions, type DecodedMcpOAuthStatePayload, type McpAuthorizeOptions, type McpCallbackInput, type McpCallbackParams, type McpPagePathOptions, type McpTokenExchangeOptions, type McpTokenExchangeResult, } from './mcp-auth';
13
14
  export interface QelosIntegrator {
14
15
  /**
15
16
  * User-resolution middleware. Forwards inbound cookies to `/api/me` and
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseSocialCallbackRefreshToken = exports.getSocialAuthSetCookieParts = exports.completeSocialAuthCallback = exports.resolveQelosProxyTarget = exports.rewriteSetCookieDomains = exports.rewriteSetCookieDomain = exports.createRequestSdk = exports.createQelosProxy = exports.requireUser = exports.createQelosMiddleware = void 0;
3
+ exports.resolveMcpLoginRedirect = exports.parseMcpCallbackParams = exports.decodeMcpOAuthStatePayload = exports.buildMcpTokenExchangeBody = exports.buildMcpLoginRedirectUrl = exports.buildMcpConsentPageUrl = exports.buildMcpAuthorizePathFromQuery = exports.buildMcpAuthorizePath = exports.appendMcpAccessDeniedRedirect = exports.completeMcpAuthorizationCallback = exports.parseSocialCallbackRefreshToken = exports.getSocialAuthSetCookieParts = exports.completeSocialAuthCallback = exports.resolveQelosProxyTarget = exports.rewriteSetCookieDomains = exports.rewriteSetCookieDomain = exports.createRequestSdk = exports.createQelosProxy = exports.requireUser = exports.createQelosMiddleware = void 0;
4
4
  exports.createQelosIntegrator = createQelosIntegrator;
5
5
  const middleware_1 = require("./middleware");
6
6
  const proxy_1 = require("./proxy");
@@ -20,6 +20,17 @@ var social_auth_1 = require("./social-auth");
20
20
  Object.defineProperty(exports, "completeSocialAuthCallback", { enumerable: true, get: function () { return social_auth_1.completeSocialAuthCallback; } });
21
21
  Object.defineProperty(exports, "getSocialAuthSetCookieParts", { enumerable: true, get: function () { return social_auth_1.getSocialAuthSetCookieParts; } });
22
22
  Object.defineProperty(exports, "parseSocialCallbackRefreshToken", { enumerable: true, get: function () { return social_auth_1.parseSocialCallbackRefreshToken; } });
23
+ var mcp_auth_1 = require("./mcp-auth");
24
+ Object.defineProperty(exports, "completeMcpAuthorizationCallback", { enumerable: true, get: function () { return mcp_auth_1.completeMcpAuthorizationCallback; } });
25
+ Object.defineProperty(exports, "appendMcpAccessDeniedRedirect", { enumerable: true, get: function () { return mcp_auth_1.appendMcpAccessDeniedRedirect; } });
26
+ Object.defineProperty(exports, "buildMcpAuthorizePath", { enumerable: true, get: function () { return mcp_auth_1.buildMcpAuthorizePath; } });
27
+ Object.defineProperty(exports, "buildMcpAuthorizePathFromQuery", { enumerable: true, get: function () { return mcp_auth_1.buildMcpAuthorizePathFromQuery; } });
28
+ Object.defineProperty(exports, "buildMcpConsentPageUrl", { enumerable: true, get: function () { return mcp_auth_1.buildMcpConsentPageUrl; } });
29
+ Object.defineProperty(exports, "buildMcpLoginRedirectUrl", { enumerable: true, get: function () { return mcp_auth_1.buildMcpLoginRedirectUrl; } });
30
+ Object.defineProperty(exports, "buildMcpTokenExchangeBody", { enumerable: true, get: function () { return mcp_auth_1.buildMcpTokenExchangeBody; } });
31
+ Object.defineProperty(exports, "decodeMcpOAuthStatePayload", { enumerable: true, get: function () { return mcp_auth_1.decodeMcpOAuthStatePayload; } });
32
+ Object.defineProperty(exports, "parseMcpCallbackParams", { enumerable: true, get: function () { return mcp_auth_1.parseMcpCallbackParams; } });
33
+ Object.defineProperty(exports, "resolveMcpLoginRedirect", { enumerable: true, get: function () { return mcp_auth_1.resolveMcpLoginRedirect; } });
23
34
  /**
24
35
  * Build both the user-resolution middleware and the `/api/**` reverse proxy
25
36
  * from a single config. When the proxy is enabled (the default), `/api/` is
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAyDA,sDAkBC;AA1ED,6CAAmF;AACnF,mCAA2C;AAG3C,2CAGsB;AAFpB,mHAAA,qBAAqB,OAAA;AACrB,yGAAA,WAAW,OAAA;AAOb,iCAA2C;AAAlC,yGAAA,gBAAgB,OAAA;AAGzB,6CAAiD;AAAxC,+GAAA,gBAAgB,OAAA;AAGzB,qCAA4E;AAAnE,iHAAA,sBAAsB,OAAA;AAAE,kHAAA,uBAAuB,OAAA;AACxD,+CAAyD;AAAhD,uHAAA,uBAAuB,OAAA;AAOhC,6CAMuB;AALrB,yHAAA,0BAA0B,OAAA;AAC1B,0HAAA,2BAA2B,OAAA;AAC3B,8HAAA,+BAA+B,OAAA;AAoBjC;;;;;GAKG;AACH,SAAgB,qBAAqB,CACnC,OAAgC;IAEhC,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,KAAK,IAAI,CAAC;IAE1D,IAAI,MAAM,GAAuB,OAAO,CAAC,MAAM,CAAC;IAChD,IAAI,YAAY,EAAE,CAAC;QACjB,MAAM,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC;QACzD,MAAM,cAAc,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;QACtF,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,GAAG,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,OAAO,EAAE,GAAG,iBAAiB,CAAC,EAAE,CAAC;QAC7E,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,IAAA,kCAAqB,EAAC,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;IACjE,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,IAAA,wBAAgB,EAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEjE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;AAC/B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AA8EA,sDAkBC;AA/FD,6CAAmF;AACnF,mCAA2C;AAG3C,2CAGsB;AAFpB,mHAAA,qBAAqB,OAAA;AACrB,yGAAA,WAAW,OAAA;AAOb,iCAA2C;AAAlC,yGAAA,gBAAgB,OAAA;AAGzB,6CAAiD;AAAxC,+GAAA,gBAAgB,OAAA;AAGzB,qCAA4E;AAAnE,iHAAA,sBAAsB,OAAA;AAAE,kHAAA,uBAAuB,OAAA;AACxD,+CAAyD;AAAhD,uHAAA,uBAAuB,OAAA;AAOhC,6CAMuB;AALrB,yHAAA,0BAA0B,OAAA;AAC1B,0HAAA,2BAA2B,OAAA;AAC3B,8HAAA,+BAA+B,OAAA;AAKjC,uCAmBoB;AAlBlB,4HAAA,gCAAgC,OAAA;AAChC,yHAAA,6BAA6B,OAAA;AAC7B,iHAAA,qBAAqB,OAAA;AACrB,0HAAA,8BAA8B,OAAA;AAC9B,kHAAA,sBAAsB,OAAA;AACtB,oHAAA,wBAAwB,OAAA;AACxB,qHAAA,yBAAyB,OAAA;AACzB,sHAAA,0BAA0B,OAAA;AAC1B,kHAAA,sBAAsB,OAAA;AACtB,mHAAA,uBAAuB,OAAA;AA0BzB;;;;;GAKG;AACH,SAAgB,qBAAqB,CACnC,OAAgC;IAEhC,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,KAAK,IAAI,CAAC;IAE1D,IAAI,MAAM,GAAuB,OAAO,CAAC,MAAM,CAAC;IAChD,IAAI,YAAY,EAAE,CAAC;QACjB,MAAM,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC;QACzD,MAAM,cAAc,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;QACtF,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,GAAG,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,OAAO,EAAE,GAAG,iBAAiB,CAAC,EAAE,CAAC;QAC7E,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,IAAA,kCAAqB,EAAC,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;IACjE,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,IAAA,wBAAgB,EAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEjE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type QelosSDK from '@qelos/sdk';
2
+ import type { McpCallbackInput, McpTokenExchangeResult } from '@qelos/sdk';
3
+ export interface CompleteMcpAuthorizationCallbackOptions {
4
+ redirectUri: string;
5
+ codeVerifier: string;
6
+ }
7
+ /**
8
+ * Parse an MCP OAuth callback and exchange the authorization code for tokens.
9
+ * Use when your app owns the MCP client callback URL (e.g. a local loopback server).
10
+ */
11
+ export declare function completeMcpAuthorizationCallback(sdk: QelosSDK, input: McpCallbackInput, options: CompleteMcpAuthorizationCallbackOptions): Promise<McpTokenExchangeResult>;
12
+ export { appendMcpAccessDeniedRedirect, buildMcpAuthorizePath, buildMcpAuthorizePathFromQuery, buildMcpConsentPageUrl, buildMcpLoginRedirectUrl, buildMcpTokenExchangeBody, decodeMcpOAuthStatePayload, parseMcpCallbackParams, resolveMcpLoginRedirect, type DecodedMcpOAuthStatePayload, type McpAuthorizeOptions, type McpCallbackInput, type McpCallbackParams, type McpPagePathOptions, type McpTokenExchangeOptions, type McpTokenExchangeResult, } from '@qelos/sdk';
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveMcpLoginRedirect = exports.parseMcpCallbackParams = exports.decodeMcpOAuthStatePayload = exports.buildMcpTokenExchangeBody = exports.buildMcpLoginRedirectUrl = exports.buildMcpConsentPageUrl = exports.buildMcpAuthorizePathFromQuery = exports.buildMcpAuthorizePath = exports.appendMcpAccessDeniedRedirect = void 0;
4
+ exports.completeMcpAuthorizationCallback = completeMcpAuthorizationCallback;
5
+ const sdk_1 = require("@qelos/sdk");
6
+ /**
7
+ * Parse an MCP OAuth callback and exchange the authorization code for tokens.
8
+ * Use when your app owns the MCP client callback URL (e.g. a local loopback server).
9
+ */
10
+ async function completeMcpAuthorizationCallback(sdk, input, options) {
11
+ const params = (0, sdk_1.parseMcpCallbackParams)(input);
12
+ if (params.error) {
13
+ throw new Error(params.errorDescription || params.error);
14
+ }
15
+ if (!params.code) {
16
+ throw new Error('missing authorization code');
17
+ }
18
+ return sdk.authentication.exchangeMcpAuthorizationCode({
19
+ code: params.code,
20
+ redirectUri: options.redirectUri,
21
+ codeVerifier: options.codeVerifier,
22
+ });
23
+ }
24
+ var sdk_2 = require("@qelos/sdk");
25
+ Object.defineProperty(exports, "appendMcpAccessDeniedRedirect", { enumerable: true, get: function () { return sdk_2.appendMcpAccessDeniedRedirect; } });
26
+ Object.defineProperty(exports, "buildMcpAuthorizePath", { enumerable: true, get: function () { return sdk_2.buildMcpAuthorizePath; } });
27
+ Object.defineProperty(exports, "buildMcpAuthorizePathFromQuery", { enumerable: true, get: function () { return sdk_2.buildMcpAuthorizePathFromQuery; } });
28
+ Object.defineProperty(exports, "buildMcpConsentPageUrl", { enumerable: true, get: function () { return sdk_2.buildMcpConsentPageUrl; } });
29
+ Object.defineProperty(exports, "buildMcpLoginRedirectUrl", { enumerable: true, get: function () { return sdk_2.buildMcpLoginRedirectUrl; } });
30
+ Object.defineProperty(exports, "buildMcpTokenExchangeBody", { enumerable: true, get: function () { return sdk_2.buildMcpTokenExchangeBody; } });
31
+ Object.defineProperty(exports, "decodeMcpOAuthStatePayload", { enumerable: true, get: function () { return sdk_2.decodeMcpOAuthStatePayload; } });
32
+ Object.defineProperty(exports, "parseMcpCallbackParams", { enumerable: true, get: function () { return sdk_2.parseMcpCallbackParams; } });
33
+ Object.defineProperty(exports, "resolveMcpLoginRedirect", { enumerable: true, get: function () { return sdk_2.resolveMcpLoginRedirect; } });
34
+ //# sourceMappingURL=mcp-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-auth.js","sourceRoot":"","sources":["../src/mcp-auth.ts"],"names":[],"mappings":";;;AAaA,4EAkBC;AA7BD,oCAAoD;AAOpD;;;GAGG;AACI,KAAK,UAAU,gCAAgC,CACpD,GAAa,EACb,KAAuB,EACvB,OAAgD;IAEhD,MAAM,MAAM,GAAG,IAAA,4BAAsB,EAAC,KAAK,CAAC,CAAC;IAC7C,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,gBAAgB,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3D,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;IAED,OAAO,GAAG,CAAC,cAAc,CAAC,4BAA4B,CAAC;QACrD,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,YAAY,EAAE,OAAO,CAAC,YAAY;KACnC,CAAC,CAAC;AACL,CAAC;AAED,kCAiBoB;AAhBlB,oHAAA,6BAA6B,OAAA;AAC7B,4GAAA,qBAAqB,OAAA;AACrB,qHAAA,8BAA8B,OAAA;AAC9B,6GAAA,sBAAsB,OAAA;AACtB,+GAAA,wBAAwB,OAAA;AACxB,gHAAA,yBAAyB,OAAA;AACzB,iHAAA,0BAA0B,OAAA;AAC1B,6GAAA,sBAAsB,OAAA;AACtB,8GAAA,uBAAuB,OAAA"}
package/dist/types.d.ts CHANGED
@@ -54,13 +54,11 @@ export interface QelosRequestContext {
54
54
  */
55
55
  sdk: QelosSDK;
56
56
  }
57
- declare module 'express' {
58
- interface Request {
59
- qelos: QelosRequestContext;
60
- }
61
- }
62
- declare module 'express-serve-static-core' {
63
- interface Request {
64
- qelos: QelosRequestContext;
57
+ declare global {
58
+ namespace Express {
59
+ interface Request {
60
+ qelos: QelosRequestContext;
61
+ }
65
62
  }
66
63
  }
64
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qelos/integrator-express",
3
- "version": "4.2.0",
3
+ "version": "4.2.2",
4
4
  "description": "Express middleware that identifies the Qelos user and active workspace before your route handlers run",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -47,13 +47,13 @@
47
47
  }
48
48
  },
49
49
  "dependencies": {
50
- "@qelos/global-types": "4.2.0",
51
- "@qelos/sdk": "4.2.0"
50
+ "@qelos/global-types": "4.2.2",
51
+ "@qelos/sdk": "4.2.2"
52
52
  },
53
53
  "devDependencies": {
54
- "@types/express": "^4.17.21",
55
- "@types/express-serve-static-core": "^4.19.6",
56
- "express": "^4.21.2",
54
+ "@types/express": "^5.0.0",
55
+ "express": "^5.0.0",
56
+ "express4": "npm:express@^4.21.2",
57
57
  "tsx": "^4.21.0",
58
58
  "typescript": "^5.6.3"
59
59
  },
@@ -61,6 +61,8 @@
61
61
  "type-check": "tsc --noEmit",
62
62
  "build": "tsc",
63
63
  "pre-build": "tsc",
64
- "test": "node --import tsx --test src/**/*.test.ts test/**/*.test.ts"
64
+ "test": "pnpm run test:express5 && pnpm run test:express4",
65
+ "test:express5": "node --import tsx --test src/**/*.test.ts test/middleware.test.ts",
66
+ "test:express4": "node --import tsx --test test/middleware.express4.test.ts"
65
67
  }
66
68
  }