Files
Edu/apps/portal-shell/src/lib/apollo-client.ts
SpecialX 514e26ebb4 feat(portal-shell): implement portal-shell with apollo-router integration
M8: portal-shell unified frontend shell (Modular Monolith + micro-kernel).

- Apollo Client -> apollo-router (port 4010, RSC prefetch)

- 5 layouts: classic/focus/split/triple/canvas

- Registry + PluginLoader (dynamic import ssr:false)

- 3-layer props merge, Zustand PluginStore

- 4 widgets: grades/notification-bell/user-menu/class-selector

- config-service: new pluginConfig GraphQL resolver

- apollo-router: CORS + header propagation for portal-shell

- docker-compose.yml: portal-shell service block
2026-07-15 08:06:09 +08:00

76 lines
2.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Apollo Clientv2.1 M8 验收点)
*
* 所有 portal-shell 查询走 apollo-routerGraphQL 联邦入口):
* portal-shell → apollo-router :3000/graphql → 各子图iam/core-edu/content/msg/data-ana/ai/config-service
*
* 双端使用:
* - 服务端RSCcreateApolloClient() 每次请求新建实例ssrMode=true
* - 客户端getApolloClient() 单例,复用 InMemoryCache
*
* 关联portal-shell spec §5.5 RSC 预取、§5.6 统一 Hook、M8 验收标准
*/
import { ApolloClient, InMemoryCache, HttpLink, from } from "@apollo/client";
import { setContext } from "@apollo/client/link/context";
const APOLLO_ROUTER_URL =
process.env.NEXT_PUBLIC_APOLLO_ROUTER_URL ||
process.env.APOLLO_ROUTER_URL ||
"http://localhost:3000/graphql";
/**
* 创建 Apollo Client 实例。
*
* @param getAuthToken 可选,返回 JWT 用于注入 Authorization 头(客户端从 cookie/localStorage 读取)
*/
export function createApolloClient(
getAuthToken?: () => string | null,
): ApolloClient<unknown> {
const httpLink = new HttpLink({
uri: APOLLO_ROUTER_URL,
credentials: "include",
});
const authLink = setContext((_, { headers }) => {
const token = getAuthToken?.() ?? null;
return {
headers: {
...headers,
...(token ? { Authorization: `Bearer ${token}` } : {}),
},
};
});
return new ApolloClient({
link: from([authLink, httpLink]),
cache: new InMemoryCache(),
ssrMode: typeof window === "undefined",
defaultOptions: {
query: {
errorPolicy: "all",
fetchPolicy: typeof window === "undefined" ? "no-cache" : "cache-first",
},
watchQuery: {
errorPolicy: "all",
},
},
});
}
let clientSingleton: ApolloClient<unknown> | null = null;
/**
* 获取客户端 Apollo Client 单例(浏览器侧复用缓存)。
*/
export function getApolloClient(
getAuthToken?: () => string | null,
): ApolloClient<unknown> {
if (typeof window === "undefined") {
return createApolloClient(getAuthToken);
}
if (!clientSingleton) {
clientSingleton = createApolloClient(getAuthToken);
}
return clientSingleton;
}