diff --git a/packages/app/src/providers/app-state-provider/dynamic-blocksuite.tsx b/packages/app/src/providers/app-state-provider/dynamic-blocksuite.tsx index 3f81edf0bc..a012a00576 100644 --- a/packages/app/src/providers/app-state-provider/dynamic-blocksuite.tsx +++ b/packages/app/src/providers/app-state-provider/dynamic-blocksuite.tsx @@ -13,7 +13,7 @@ import type { LoadWorkspaceHandler, CreateEditorHandler, } from './context'; -import { downloadWorkspace, getToken } from '@pathfinder/data-services'; +import { downloadWorkspace, token } from '@pathfinder/data-services'; import { WebsocketProvider } from './y-websocket'; const getEditorParams = (workspaceId: string) => { @@ -55,11 +55,9 @@ const DynamicBlocksuite = ({ providers: [IndexedDBDocProvider], }).register(BlockSchema); - const refreshToken = getToken()?.refreshToken; - if ( websocket && - refreshToken && + token.refresh && location.search.includes('sync=websocket') ) { // FIXME: if add websocket provider, the first page will be blank @@ -71,7 +69,7 @@ const DynamicBlocksuite = ({ workspace.doc, { params: { - token: refreshToken, + token: token.refresh, }, awareness: workspace.meta.awareness.awareness, } diff --git a/packages/app/src/providers/app-state-provider/provider.tsx b/packages/app/src/providers/app-state-provider/provider.tsx index 41e18901f5..8e8ff28c79 100644 --- a/packages/app/src/providers/app-state-provider/provider.tsx +++ b/packages/app/src/providers/app-state-provider/provider.tsx @@ -2,11 +2,9 @@ import { useMemo, useState, useEffect, useCallback, useRef } from 'react'; import type { ReactNode } from 'react'; import dynamic from 'next/dynamic'; import { - authorizationEvent, + token, AccessTokenMessage, getWorkspaces, - WorkspaceType, - getWorkspaceDetail, } from '@pathfinder/data-services'; import { AppState, AppStateContext } from './context'; import type { @@ -171,10 +169,10 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => { synced: true, })); }; - authorizationEvent.onChange(callback); + token.onChange(callback); return () => { - authorizationEvent.removeCallback(callback); + token.offChange(callback); }; }, [loadWorkspaceHandler]); diff --git a/packages/data-services/src/request/events.ts b/packages/data-services/src/request/events.ts index d4444bcb63..ae90c6756d 100644 --- a/packages/data-services/src/request/events.ts +++ b/packages/data-services/src/request/events.ts @@ -1,6 +1,6 @@ import { AccessTokenMessage } from './token'; -type Callback = (user: AccessTokenMessage | null) => void; +export type Callback = (user: AccessTokenMessage | null) => void; export class AuthorizationEvent { private callbacks: Callback[] = []; diff --git a/packages/data-services/src/request/index.ts b/packages/data-services/src/request/index.ts index e7b83ac13e..6e79ef23e9 100644 --- a/packages/data-services/src/request/index.ts +++ b/packages/data-services/src/request/index.ts @@ -1,19 +1,9 @@ import ky from 'ky'; import { token } from './token'; -export const request = ky.extend({ +export const bareClient = ky.extend({ retry: 1, hooks: { - beforeRequest: [ - async request => { - if (!request.headers.has('token') || request.headers.get('token')) { - if (token.isLogin) { - if (token.isExpired) await token.refreshToken(); - request.headers.set('Authorization', token.token); - } - } - }, - ], // afterResponse: [ // async (_request, _options, response) => { // if (response.status === 200) { @@ -27,6 +17,19 @@ export const request = ky.extend({ // return response; // }, // ], + }, +}); +export const client = bareClient.extend({ + hooks: { + beforeRequest: [ + async request => { + if (token.isLogin) { + if (token.isExpired) await token.refreshToken(); + request.headers.set('Authorization', token.token); + } + }, + ], + beforeRetry: [ async ({ request }) => { await token.refreshToken(); diff --git a/packages/data-services/src/request/token.ts b/packages/data-services/src/request/token.ts index 34c94226ec..37f35c66f5 100644 --- a/packages/data-services/src/request/token.ts +++ b/packages/data-services/src/request/token.ts @@ -1,5 +1,5 @@ -import { request } from '.'; -import { AuthorizationEvent } from './events'; +import { bareClient } from '.'; +import { AuthorizationEvent, Callback } from './events'; export interface AccessTokenMessage { create_at: number; @@ -25,12 +25,7 @@ type LoginResponse = { }; const login = (params: LoginParams): Promise => - request - .post('/api/user/token', { - json: params, - headers: { token: undefined }, - }) - .json(); + bareClient.post('/api/user/token', { json: params }).json(); function b64DecodeUnicode(str: string) { // Going backwards: from byte stream, to percent-encoding, to original string. @@ -80,6 +75,8 @@ class Token { this._refreshToken = login.refresh; this._user = Token.parse(login.token); + this._event.triggerChange(this._user); + setRefreshToken(login.refresh); } @@ -99,14 +96,16 @@ class Token { } this._setToken(await this._padding); this._padding = undefined; - - this._event.triggerChange(this._user); } get token() { return this._accessToken; } + get refresh() { + return this._refreshToken; + } + get isLogin() { return !!this._refreshToken; } @@ -126,6 +125,14 @@ class Token { return null; } } + + onChange(callback: Callback) { + this._event.onChange(callback); + } + + offChange(callback: Callback) { + this._event.removeCallback(callback); + } } export const token = new Token(); diff --git a/packages/data-services/src/sdks/user.ts b/packages/data-services/src/sdks/user.ts index c873b44042..7c5fc879b5 100644 --- a/packages/data-services/src/sdks/user.ts +++ b/packages/data-services/src/sdks/user.ts @@ -1,4 +1,4 @@ -import { request } from '../request'; +import { client } from '../request'; export interface GetUserByEmailParams { email: string; @@ -16,5 +16,5 @@ export interface User { export async function getUserByEmail( params: GetUserByEmailParams ): Promise { - return request.get('/api/user', { json: params }).json(); + return client.get('/api/user', { json: params }).json(); } diff --git a/packages/data-services/src/sdks/workspace.ts b/packages/data-services/src/sdks/workspace.ts index f1c4dcc44d..4b362709a6 100644 --- a/packages/data-services/src/sdks/workspace.ts +++ b/packages/data-services/src/sdks/workspace.ts @@ -1,4 +1,4 @@ -import { request } from '../request'; +import { client } from '../request'; import { User } from './user'; export interface GetWorkspaceDetailParams { @@ -26,7 +26,7 @@ export interface Workspace { } export async function getWorkspaces(): Promise { - return request.get('/api/workspace').json(); + return client.get('/api/workspace').json(); } export interface WorkspaceDetail extends Workspace { @@ -37,7 +37,7 @@ export interface WorkspaceDetail extends Workspace { export async function getWorkspaceDetail( params: GetWorkspaceDetailParams ): Promise { - return request.get(`/api/workspace/${params.id}`).json(); + return client.get(`/api/workspace/${params.id}`).json(); } export interface Permission { @@ -68,7 +68,7 @@ export interface GetWorkspaceMembersParams { export async function getWorkspaceMembers( params: GetWorkspaceDetailParams ): Promise { - return request.get(`/api/workspace/${params.id}/permission`).json(); + return client.get(`/api/workspace/${params.id}/permission`).json(); } export interface CreateWorkspaceParams { @@ -79,7 +79,7 @@ export interface CreateWorkspaceParams { export async function createWorkspace( params: CreateWorkspaceParams ): Promise { - return request.post('/api/workspace', { json: params }).json(); + return client.post('/api/workspace', { json: params }).json(); } export interface UpdateWorkspaceParams { @@ -90,7 +90,7 @@ export interface UpdateWorkspaceParams { export async function updateWorkspace( params: UpdateWorkspaceParams ): Promise { - return request + return client .post(`/api/workspace/${params.id}`, { json: { public: params.public, @@ -106,7 +106,7 @@ export interface DeleteWorkspaceParams { export async function deleteWorkspace( params: DeleteWorkspaceParams ): Promise { - await request.delete(`/api/workspace/${params.id}`); + await client.delete(`/api/workspace/${params.id}`); } export interface InviteMemberParams { @@ -118,7 +118,7 @@ export interface InviteMemberParams { * Notice: Only support normal(contrast to private) workspace. */ export async function inviteMember(params: InviteMemberParams): Promise { - return request + return client .post(`/api/workspace/${params.id}/permission`, { json: { email: params.email, @@ -132,7 +132,7 @@ export interface RemoveMemberParams { } export async function removeMember(params: RemoveMemberParams): Promise { - await request.delete(`/api/permission/${params.permissionId}`); + await client.delete(`/api/permission/${params.permissionId}`); } export interface AcceptInvitingParams { @@ -142,7 +142,7 @@ export interface AcceptInvitingParams { export async function acceptInviting( params: AcceptInvitingParams ): Promise { - await request.post(`/api/invitation/${params.invitingCode}`); + await client.post(`/api/invitation/${params.invitingCode}`); } export interface DownloadWOrkspaceParams { @@ -151,15 +151,15 @@ export interface DownloadWOrkspaceParams { export async function downloadWorkspace( params: DownloadWOrkspaceParams ): Promise { - return request.get(`/api/workspace/${params.workspaceId}/doc`).arrayBuffer(); + return client.get(`/api/workspace/${params.workspaceId}/doc`).arrayBuffer(); } export async function uploadBlob(params: { blob: Blob }): Promise { - return request.post('/api/blob', { body: params.blob }).text(); + return client.post('/api/blob', { body: params.blob }).text(); } export async function getBlob(params: { blobId: string; }): Promise { - return request.get(`/api/blob/${params.blobId}`).arrayBuffer(); + return client.get(`/api/blob/${params.blobId}`).arrayBuffer(); }