@qelos/integrator-next 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 +109 -164
- package/dist/context.d.ts +5 -11
- package/dist/context.js +63 -43
- package/dist/context.js.map +1 -1
- package/dist/cookies.d.ts +19 -0
- package/dist/cookies.js +39 -0
- package/dist/cookies.js.map +1 -0
- package/dist/env-config.d.ts +3 -3
- package/dist/env-config.js +6 -7
- package/dist/env-config.js.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/me-client.d.ts +15 -0
- package/dist/me-client.js +35 -0
- package/dist/me-client.js.map +1 -0
- package/dist/middleware.d.ts +10 -34
- package/dist/middleware.js +75 -80
- package/dist/middleware.js.map +1 -1
- package/dist/pages.d.ts +5 -9
- package/dist/pages.js +61 -98
- package/dist/pages.js.map +1 -1
- package/dist/proxy-target.d.ts +17 -0
- package/dist/proxy-target.js +26 -0
- package/dist/proxy-target.js.map +1 -0
- package/dist/runtime/api-proxy.d.ts +16 -0
- package/dist/runtime/api-proxy.js +90 -0
- package/dist/runtime/api-proxy.js.map +1 -0
- package/dist/sdk-factory.d.ts +13 -16
- package/dist/sdk-factory.js +29 -79
- package/dist/sdk-factory.js.map +1 -1
- package/dist/types.d.ts +28 -16
- package/dist/types.js.map +1 -1
- package/package.json +8 -3
package/dist/env-config.js
CHANGED
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
* Recognized variables:
|
|
8
8
|
*
|
|
9
9
|
* - `QELOS_APP_URL` (required) — Qelos backend base URL.
|
|
10
|
-
* - `QELOS_API_TOKEN` — service-to-service token (skips
|
|
11
|
-
* - `QELOS_ACCESS_TOKEN_COOKIE` — defaults to `q_access_token`.
|
|
12
|
-
* - `QELOS_REFRESH_TOKEN_COOKIE` — defaults to `q_refresh_token`.
|
|
10
|
+
* - `QELOS_API_TOKEN` — service-to-service token (skips cookie identity).
|
|
13
11
|
* - `QELOS_REQUIRE_AUTH` — `"true"` to reject anonymous requests.
|
|
14
12
|
* - `QELOS_SKIP_PATHS` — comma-separated path prefixes to bypass.
|
|
13
|
+
* - `QELOS_DISABLE_PROXY` — `"true"` to disable auto `/api/` skip in middleware
|
|
14
|
+
* (when you are not using the BFF catch-all proxy).
|
|
15
15
|
*/
|
|
16
16
|
export function loadQelosConfigFromEnv(env = process.env) {
|
|
17
17
|
const appUrl = env.QELOS_APP_URL;
|
|
@@ -23,13 +23,12 @@ export function loadQelosConfigFromEnv(env = process.env) {
|
|
|
23
23
|
const config = { appUrl };
|
|
24
24
|
if (env.QELOS_API_TOKEN)
|
|
25
25
|
config.apiToken = env.QELOS_API_TOKEN;
|
|
26
|
-
if (env.QELOS_ACCESS_TOKEN_COOKIE)
|
|
27
|
-
config.accessTokenCookie = env.QELOS_ACCESS_TOKEN_COOKIE;
|
|
28
|
-
if (env.QELOS_REFRESH_TOKEN_COOKIE)
|
|
29
|
-
config.refreshTokenCookie = env.QELOS_REFRESH_TOKEN_COOKIE;
|
|
30
26
|
if (env.QELOS_REQUIRE_AUTH === 'true' || env.QELOS_REQUIRE_AUTH === '1') {
|
|
31
27
|
config.requireAuth = true;
|
|
32
28
|
}
|
|
29
|
+
if (env.QELOS_DISABLE_PROXY === 'true' || env.QELOS_DISABLE_PROXY === '1') {
|
|
30
|
+
config.disableProxy = true;
|
|
31
|
+
}
|
|
33
32
|
if (env.QELOS_SKIP_PATHS) {
|
|
34
33
|
config.skipPaths = env.QELOS_SKIP_PATHS.split(',')
|
|
35
34
|
.map((p) => p.trim())
|
package/dist/env-config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env-config.js","sourceRoot":"","sources":["../src/env-config.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACzE,MAAM,MAAM,GAAG,GAAG,CAAC,aAAa,CAAC;IACjC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,2EAA2E;YACzE,0EAA0E;YAC1E,4DAA4D,CAC/D,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAoB,EAAE,MAAM,EAAE,CAAC;IAC3C,IAAI,GAAG,CAAC,eAAe;QAAE,MAAM,CAAC,QAAQ,GAAG,GAAG,CAAC,eAAe,CAAC;IAC/D,IAAI,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"env-config.js","sourceRoot":"","sources":["../src/env-config.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACzE,MAAM,MAAM,GAAG,GAAG,CAAC,aAAa,CAAC;IACjC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,2EAA2E;YACzE,0EAA0E;YAC1E,4DAA4D,CAC/D,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAoB,EAAE,MAAM,EAAE,CAAC;IAC3C,IAAI,GAAG,CAAC,eAAe;QAAE,MAAM,CAAC,QAAQ,GAAG,GAAG,CAAC,eAAe,CAAC;IAC/D,IAAI,GAAG,CAAC,kBAAkB,KAAK,MAAM,IAAI,GAAG,CAAC,kBAAkB,KAAK,GAAG,EAAE,CAAC;QACxE,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC;IAC5B,CAAC;IACD,IAAI,GAAG,CAAC,mBAAmB,KAAK,MAAM,IAAI,GAAG,CAAC,mBAAmB,KAAK,GAAG,EAAE,CAAC;QAC1E,MAAM,CAAC,YAAY,GAAG,IAAI,CAAC;IAC7B,CAAC;IACD,IAAI,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACzB,MAAM,CAAC,SAAS,GAAG,GAAG,CAAC,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC;aAC/C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACpB,MAAM,CAAC,OAAO,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,IAAI,YAAY,GAA2B,IAAI,CAAC;AAEhD;;;;GAIG;AACH,MAAM,UAAU,qBAAqB;IACnC,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,YAAY,GAAG,sBAAsB,EAAE,CAAC;IAC1C,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,yBAAyB;IACvC,YAAY,GAAG,IAAI,CAAC;AACtB,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
export { createQelosMiddleware, qelosMiddleware, type CreateMiddlewareOptions, type
|
|
1
|
+
export { createQelosMiddleware, qelosMiddleware, type CreateMiddlewareOptions, type QelosMiddleware, } from './middleware';
|
|
2
2
|
export { loadQelosConfigFromEnv, getDefaultQelosConfig, } from './env-config';
|
|
3
|
-
export { createRequestSdk, type CreateSdkParams
|
|
3
|
+
export { createRequestSdk, type CreateSdkParams } from './sdk-factory';
|
|
4
4
|
export { getQelosContext, withQelosContext, runWithQelosContext, getStoredQelosContext, requireQelosUser, type GetQelosContextOptions, } from './context';
|
|
5
5
|
export { withQelosApi, withQelosSSR, requireQelosApiUser, type PagesIntegratorOptions, } from './pages';
|
|
6
6
|
export { withQelosRoute, type AppRouteHandler, type QelosAppRouteHandler, } from './route';
|
|
7
|
-
export { QELOS_USER_HEADER, QELOS_WORKSPACE_HEADER, type QelosNextConfig, type QelosRequestContext,
|
|
7
|
+
export { QELOS_USER_HEADER, QELOS_WORKSPACE_HEADER, type QelosNextConfig, type QelosRequestContext, } from './types';
|
|
8
|
+
export { rewriteSetCookieDomain, rewriteSetCookieDomains } from './cookies';
|
|
9
|
+
export { resolveQelosProxyTarget } from './proxy-target';
|
|
10
|
+
export { createQelosApiProxyHandlers } from './runtime/api-proxy';
|
|
8
11
|
export { completeSocialAuthCallback, applySocialAuthCookiesToServerResponse, getSocialAuthSetCookieParts, parseSocialCallbackRefreshToken, type SocialAuthCallbackPayload, type SocialCallbackInput, } from './social-auth';
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
export { createQelosMiddleware, qelosMiddleware, } from './middleware';
|
|
2
2
|
export { loadQelosConfigFromEnv, getDefaultQelosConfig, } from './env-config';
|
|
3
|
-
export { createRequestSdk
|
|
3
|
+
export { createRequestSdk } from './sdk-factory';
|
|
4
4
|
export { getQelosContext, withQelosContext, runWithQelosContext, getStoredQelosContext, requireQelosUser, } from './context';
|
|
5
5
|
export { withQelosApi, withQelosSSR, requireQelosApiUser, } from './pages';
|
|
6
6
|
export { withQelosRoute, } from './route';
|
|
7
7
|
export { QELOS_USER_HEADER, QELOS_WORKSPACE_HEADER, } from './types';
|
|
8
|
+
export { rewriteSetCookieDomain, rewriteSetCookieDomains } from './cookies';
|
|
9
|
+
export { resolveQelosProxyTarget } from './proxy-target';
|
|
10
|
+
export { createQelosApiProxyHandlers } from './runtime/api-proxy';
|
|
8
11
|
export { completeSocialAuthCallback, applySocialAuthCookiesToServerResponse, getSocialAuthSetCookieParts, parseSocialCallbackRefreshToken, } from './social-auth';
|
|
9
12
|
//# 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,OAAO,EACL,qBAAqB,EACrB,eAAe,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,eAAe,GAGhB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,gBAAgB,EAAwB,MAAM,eAAe,CAAC;AAEvE,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,gBAAgB,GAEjB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,mBAAmB,GAEpB,MAAM,SAAS,CAAC;AAEjB,OAAO,EACL,cAAc,GAGf,MAAM,SAAS,CAAC;AAEjB,OAAO,EACL,iBAAiB,EACjB,sBAAsB,GAGvB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAElE,OAAO,EACL,0BAA0B,EAC1B,sCAAsC,EACtC,2BAA2B,EAC3B,+BAA+B,GAGhC,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { IUser } from '@qelos/sdk/dist/authentication';
|
|
2
|
+
export declare function buildMeUrl(base: string): string;
|
|
3
|
+
export interface FetchMeIdentityParams {
|
|
4
|
+
base: string;
|
|
5
|
+
cookie?: string;
|
|
6
|
+
authorization?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Server-side `GET /api/me` against Qelos with inbound auth material forwarded.
|
|
10
|
+
* Does not rewrite `Set-Cookie`; callers apply {@link rewriteSetCookieDomain}.
|
|
11
|
+
*/
|
|
12
|
+
export declare function fetchMeIdentity(params: FetchMeIdentityParams): Promise<{
|
|
13
|
+
response: Response;
|
|
14
|
+
user: IUser | null;
|
|
15
|
+
}>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export function buildMeUrl(base) {
|
|
2
|
+
return `${base.replace(/\/+$/, '')}/api/me`;
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Server-side `GET /api/me` against Qelos with inbound auth material forwarded.
|
|
6
|
+
* Does not rewrite `Set-Cookie`; callers apply {@link rewriteSetCookieDomain}.
|
|
7
|
+
*/
|
|
8
|
+
export async function fetchMeIdentity(params) {
|
|
9
|
+
const headers = {};
|
|
10
|
+
if (params.cookie)
|
|
11
|
+
headers.cookie = params.cookie;
|
|
12
|
+
if (params.authorization)
|
|
13
|
+
headers.authorization = params.authorization;
|
|
14
|
+
let response;
|
|
15
|
+
try {
|
|
16
|
+
response = await fetch(buildMeUrl(params.base), {
|
|
17
|
+
method: 'GET',
|
|
18
|
+
headers,
|
|
19
|
+
redirect: 'manual',
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return { response: new Response(null, { status: 502 }), user: null };
|
|
24
|
+
}
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
return { response, user: null };
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
return { response, user: (await response.json()) };
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return { response, user: null };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=me-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"me-client.js","sourceRoot":"","sources":["../src/me-client.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,SAAS,CAAC;AAC9C,CAAC;AAQD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAA6B;IAE7B,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,IAAI,MAAM,CAAC,MAAM;QAAE,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAClD,IAAI,MAAM,CAAC,aAAa;QAAE,OAAO,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;IAEvE,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;YAC9C,MAAM,EAAE,KAAK;YACb,OAAO;YACP,QAAQ,EAAE,QAAQ;SACnB,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,QAAQ,EAAE,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACvE,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAClC,CAAC;IAED,IAAI,CAAC;QACH,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAU,EAAE,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAClC,CAAC;AACH,CAAC"}
|
package/dist/middleware.d.ts
CHANGED
|
@@ -1,38 +1,13 @@
|
|
|
1
1
|
import { NextResponse, type NextRequest } from 'next/server';
|
|
2
2
|
import type { IUser } from '@qelos/sdk/dist/authentication';
|
|
3
3
|
import type { IWorkspace } from '@qelos/sdk/workspaces';
|
|
4
|
-
import type { QelosNextConfig
|
|
5
|
-
export interface PendingCookie {
|
|
6
|
-
name: string;
|
|
7
|
-
value: string;
|
|
8
|
-
options: {
|
|
9
|
-
httpOnly: boolean;
|
|
10
|
-
secure: boolean;
|
|
11
|
-
sameSite: 'lax' | 'strict' | 'none';
|
|
12
|
-
path: string;
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Carrier passed to the App Router middleware token-refresh hook. Cookies
|
|
17
|
-
* pushed onto `pendingCookies` are written to the outbound `NextResponse`
|
|
18
|
-
* after identification completes — Next.js does not let us mutate the
|
|
19
|
-
* response headers after `NextResponse.next()` has been constructed, so we
|
|
20
|
-
* stage them here and flush them once the response object exists.
|
|
21
|
-
*/
|
|
22
|
-
export interface MiddlewareRefreshTarget {
|
|
23
|
-
req: NextRequest;
|
|
24
|
-
pendingCookies: PendingCookie[];
|
|
25
|
-
}
|
|
4
|
+
import type { QelosNextConfig } from './types';
|
|
26
5
|
export interface CreateMiddlewareOptions {
|
|
27
6
|
config: QelosNextConfig;
|
|
28
7
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
|
|
32
|
-
onTokenRefresh?: TokenRefreshHook<MiddlewareRefreshTarget>;
|
|
33
|
-
/**
|
|
34
|
-
* Resolve the active workspace for a request. Defaults to picking the first
|
|
35
|
-
* workspace returned from `sdk.workspaces.getList()`.
|
|
8
|
+
* Resolve the active workspace for a request. Defaults to whatever
|
|
9
|
+
* `/api/me` reports on `user.workspace` (the user's currently activated
|
|
10
|
+
* workspace, or `null` when none is active).
|
|
36
11
|
*/
|
|
37
12
|
resolveWorkspace?: (params: {
|
|
38
13
|
req: NextRequest;
|
|
@@ -43,11 +18,12 @@ export interface CreateMiddlewareOptions {
|
|
|
43
18
|
export type QelosMiddleware = (req: NextRequest) => Promise<NextResponse>;
|
|
44
19
|
/**
|
|
45
20
|
* Create a Next.js (App Router) edge middleware that identifies the user and
|
|
46
|
-
* the active workspace via
|
|
47
|
-
* application's own handler. Resolved identity
|
|
48
|
-
* handlers via request headers (`x-qelos-user-id`,
|
|
49
|
-
* use `getQelosContext()` from
|
|
50
|
-
* full user / workspace objects
|
|
21
|
+
* the active workspace via a same-origin BFF round-trip to Qelos `GET /api/me`
|
|
22
|
+
* before the request reaches the application's own handler. Resolved identity
|
|
23
|
+
* is forwarded to downstream handlers via request headers (`x-qelos-user-id`,
|
|
24
|
+
* `x-qelos-workspace-id`); use `getQelosContext()` from
|
|
25
|
+
* `@qelos/integrator-next/context` to obtain the full user / workspace objects
|
|
26
|
+
* inside server components or route handlers.
|
|
51
27
|
*/
|
|
52
28
|
export declare function createQelosMiddleware(options: CreateMiddlewareOptions): QelosMiddleware;
|
|
53
29
|
/**
|
package/dist/middleware.js
CHANGED
|
@@ -1,43 +1,25 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server';
|
|
2
|
+
import { rewriteSetCookieDomain } from './cookies';
|
|
2
3
|
import { applyQelosForwardHeaders } from './forward-headers';
|
|
3
4
|
import { getDefaultQelosConfig } from './env-config';
|
|
5
|
+
import { fetchMeIdentity } from './me-client';
|
|
6
|
+
import { resolveQelosProxyTarget } from './proxy-target';
|
|
4
7
|
import { createRequestSdk } from './sdk-factory';
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const authHeader = req.headers.get('authorization');
|
|
13
|
-
const headerAccess = authHeader && authHeader.toLowerCase().startsWith('bearer ')
|
|
14
|
-
? authHeader.slice(7).trim()
|
|
15
|
-
: undefined;
|
|
16
|
-
return {
|
|
17
|
-
accessToken: headerAccess || cookieAccess || undefined,
|
|
18
|
-
refreshToken: cookieRefresh || undefined,
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
function stagePendingCookies(pending, config, tokens) {
|
|
22
|
-
const accessCookie = config.accessTokenCookie || DEFAULT_ACCESS_COOKIE;
|
|
23
|
-
const refreshCookie = config.refreshTokenCookie || DEFAULT_REFRESH_COOKIE;
|
|
24
|
-
const secure = !/^http:\/\//i.test(config.appUrl);
|
|
25
|
-
const options = {
|
|
26
|
-
httpOnly: true,
|
|
27
|
-
secure,
|
|
28
|
-
sameSite: 'lax',
|
|
29
|
-
path: '/',
|
|
30
|
-
};
|
|
31
|
-
pending.push({ name: accessCookie, value: tokens.accessToken, options });
|
|
32
|
-
if (tokens.refreshToken) {
|
|
33
|
-
pending.push({ name: refreshCookie, value: tokens.refreshToken, options });
|
|
8
|
+
function mergeProxySkipPaths(config) {
|
|
9
|
+
const merged = [...(config.skipPaths ?? [])];
|
|
10
|
+
if (config.disableProxy !== true) {
|
|
11
|
+
const hasApiPrefix = merged.some((p) => p === '/api' || p === '/api/' || p.startsWith('/api/'));
|
|
12
|
+
if (!hasApiPrefix) {
|
|
13
|
+
merged.unshift('/api/');
|
|
14
|
+
}
|
|
34
15
|
}
|
|
16
|
+
return merged.length ? merged : undefined;
|
|
35
17
|
}
|
|
36
|
-
function shouldSkip(req,
|
|
37
|
-
if (!
|
|
18
|
+
function shouldSkip(req, skipPaths) {
|
|
19
|
+
if (!skipPaths?.length)
|
|
38
20
|
return false;
|
|
39
21
|
const path = req.nextUrl.pathname;
|
|
40
|
-
return
|
|
22
|
+
return skipPaths.some((prefix) => path.startsWith(prefix));
|
|
41
23
|
}
|
|
42
24
|
function unauthorized() {
|
|
43
25
|
return new NextResponse(JSON.stringify({ code: 'UNAUTHORIZED' }), {
|
|
@@ -47,72 +29,85 @@ function unauthorized() {
|
|
|
47
29
|
}
|
|
48
30
|
/**
|
|
49
31
|
* Create a Next.js (App Router) edge middleware that identifies the user and
|
|
50
|
-
* the active workspace via
|
|
51
|
-
* application's own handler. Resolved identity
|
|
52
|
-
* handlers via request headers (`x-qelos-user-id`,
|
|
53
|
-
* use `getQelosContext()` from
|
|
54
|
-
* full user / workspace objects
|
|
32
|
+
* the active workspace via a same-origin BFF round-trip to Qelos `GET /api/me`
|
|
33
|
+
* before the request reaches the application's own handler. Resolved identity
|
|
34
|
+
* is forwarded to downstream handlers via request headers (`x-qelos-user-id`,
|
|
35
|
+
* `x-qelos-workspace-id`); use `getQelosContext()` from
|
|
36
|
+
* `@qelos/integrator-next/context` to obtain the full user / workspace objects
|
|
37
|
+
* inside server components or route handlers.
|
|
55
38
|
*/
|
|
56
39
|
export function createQelosMiddleware(options) {
|
|
57
40
|
const { config, resolveWorkspace } = options;
|
|
58
|
-
const
|
|
59
|
-
(async ({ target, newTokens }) => {
|
|
60
|
-
stagePendingCookies(target.pendingCookies, config, newTokens);
|
|
61
|
-
});
|
|
41
|
+
const skipPathsEffective = mergeProxySkipPaths(config);
|
|
62
42
|
return async function qelosMiddleware(req) {
|
|
63
|
-
if (shouldSkip(req,
|
|
43
|
+
if (shouldSkip(req, skipPathsEffective)) {
|
|
64
44
|
return NextResponse.next();
|
|
65
45
|
}
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const sdk = createRequestSdk({
|
|
70
|
-
config,
|
|
71
|
-
tokens,
|
|
72
|
-
refreshTarget: { req, pendingCookies },
|
|
73
|
-
onTokenRefresh,
|
|
46
|
+
const getHeaders = () => ({
|
|
47
|
+
cookie: req.headers.get('cookie') ?? undefined,
|
|
48
|
+
authorization: req.headers.get('authorization') ?? undefined,
|
|
74
49
|
});
|
|
75
|
-
const
|
|
50
|
+
const sdk = createRequestSdk({ config, getHeaders });
|
|
51
|
+
const base = resolveQelosProxyTarget(config);
|
|
52
|
+
if (!base && !config.apiToken) {
|
|
53
|
+
if (config.requireAuth) {
|
|
54
|
+
return unauthorized();
|
|
55
|
+
}
|
|
56
|
+
const forwardedHeaders = new Headers(req.headers);
|
|
57
|
+
applyQelosForwardHeaders(forwardedHeaders, null, null);
|
|
58
|
+
return NextResponse.next({ request: { headers: forwardedHeaders } });
|
|
59
|
+
}
|
|
76
60
|
let user = null;
|
|
77
|
-
let
|
|
61
|
+
let setCookieValues = [];
|
|
62
|
+
const originalHost = req.headers.get('host');
|
|
63
|
+
if (base) {
|
|
64
|
+
const h = getHeaders();
|
|
65
|
+
const { response, user: meUser } = await fetchMeIdentity({
|
|
66
|
+
base,
|
|
67
|
+
cookie: h.cookie,
|
|
68
|
+
authorization: h.authorization,
|
|
69
|
+
});
|
|
70
|
+
user = meUser;
|
|
71
|
+
setCookieValues = response.headers.getSetCookie?.() ?? [];
|
|
72
|
+
}
|
|
78
73
|
let workspace = null;
|
|
79
|
-
let
|
|
80
|
-
if (
|
|
74
|
+
let workspaces = [];
|
|
75
|
+
if (user) {
|
|
81
76
|
try {
|
|
82
|
-
|
|
77
|
+
workspaces = await sdk.workspaces.getList();
|
|
83
78
|
}
|
|
84
79
|
catch {
|
|
85
|
-
|
|
80
|
+
workspaces = [];
|
|
81
|
+
}
|
|
82
|
+
if (resolveWorkspace) {
|
|
83
|
+
workspace =
|
|
84
|
+
(await resolveWorkspace({ req, user, workspaces })) || null;
|
|
86
85
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
catch {
|
|
92
|
-
workspaces = [];
|
|
93
|
-
}
|
|
94
|
-
if (workspaces.length) {
|
|
95
|
-
if (resolveWorkspace) {
|
|
96
|
-
workspace =
|
|
97
|
-
(await resolveWorkspace({ req, user, workspaces })) || null;
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
workspace = workspaces[0] || null;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
86
|
+
else {
|
|
87
|
+
workspace =
|
|
88
|
+
user.workspace ||
|
|
89
|
+
null;
|
|
103
90
|
}
|
|
104
91
|
}
|
|
105
|
-
if (
|
|
106
|
-
|
|
92
|
+
if (!user) {
|
|
93
|
+
if (config.requireAuth) {
|
|
94
|
+
return unauthorized();
|
|
95
|
+
}
|
|
96
|
+
const forwardedHeaders = new Headers(req.headers);
|
|
97
|
+
applyQelosForwardHeaders(forwardedHeaders, null, null);
|
|
98
|
+
const res = NextResponse.next({ request: { headers: forwardedHeaders } });
|
|
99
|
+
for (const value of setCookieValues) {
|
|
100
|
+
res.headers.append('set-cookie', rewriteSetCookieDomain(value, originalHost ?? undefined));
|
|
101
|
+
}
|
|
102
|
+
return res;
|
|
107
103
|
}
|
|
104
|
+
const forwardedHeaders = new Headers(req.headers);
|
|
108
105
|
applyQelosForwardHeaders(forwardedHeaders, user, workspace);
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
for (const cookie of pendingCookies) {
|
|
113
|
-
response.cookies.set(cookie.name, cookie.value, cookie.options);
|
|
106
|
+
const res = NextResponse.next({ request: { headers: forwardedHeaders } });
|
|
107
|
+
for (const value of setCookieValues) {
|
|
108
|
+
res.headers.append('set-cookie', rewriteSetCookieDomain(value, originalHost ?? undefined));
|
|
114
109
|
}
|
|
115
|
-
return
|
|
110
|
+
return res;
|
|
116
111
|
};
|
|
117
112
|
}
|
|
118
113
|
let defaultMiddleware = null;
|
package/dist/middleware.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAoB,MAAM,aAAa,CAAC;AAG7D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
|
package/dist/pages.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { IncomingMessage
|
|
1
|
+
import type { IncomingMessage } from 'node:http';
|
|
2
2
|
import type { GetServerSideProps, GetServerSidePropsContext, GetServerSidePropsResult, NextApiHandler } from 'next';
|
|
3
3
|
import type { IUser } from '@qelos/sdk/dist/authentication';
|
|
4
4
|
import type { IWorkspace } from '@qelos/sdk/workspaces';
|
|
5
|
-
import type { QelosNextConfig, QelosRequestContext
|
|
5
|
+
import type { QelosNextConfig, QelosRequestContext } from './types';
|
|
6
6
|
type CookieMap = Partial<Record<string, string>>;
|
|
7
7
|
interface RequestWithCookies extends IncomingMessage {
|
|
8
8
|
cookies?: CookieMap;
|
|
@@ -15,13 +15,9 @@ declare module 'http' {
|
|
|
15
15
|
export interface PagesIntegratorOptions {
|
|
16
16
|
config: QelosNextConfig;
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
|
|
21
|
-
onTokenRefresh?: TokenRefreshHook<ServerResponse>;
|
|
22
|
-
/**
|
|
23
|
-
* Resolve the active workspace for a request. Defaults to picking the first
|
|
24
|
-
* workspace returned from `sdk.workspaces.getList()`.
|
|
18
|
+
* Resolve the active workspace for a request. Defaults to whatever
|
|
19
|
+
* `/api/me` reports on `user.workspace` (the user's currently activated
|
|
20
|
+
* workspace, or `null` when none is active).
|
|
25
21
|
*/
|
|
26
22
|
resolveWorkspace?: (params: {
|
|
27
23
|
req: RequestWithCookies;
|