mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-25 14:28:51 +08:00
feat(core): integrate realtime features (#15003)
This commit is contained in:
@@ -1,11 +0,0 @@
|
||||
query listUserAccessTokens {
|
||||
currentUser {
|
||||
revealedAccessTokens {
|
||||
id
|
||||
name
|
||||
createdAt
|
||||
expiresAt
|
||||
token
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
query getWorkspaceEmbeddingStatus($workspaceId: String!) {
|
||||
queryWorkspaceEmbeddingStatus(workspaceId: $workspaceId) {
|
||||
total
|
||||
embedded
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
fragment CurrentUserProfile on UserType {
|
||||
id
|
||||
name
|
||||
email
|
||||
avatarUrl
|
||||
emailVerified
|
||||
features
|
||||
settings {
|
||||
receiveInvitationEmail
|
||||
receiveMentionEmail
|
||||
receiveCommentEmail
|
||||
}
|
||||
quota {
|
||||
name
|
||||
blobLimit
|
||||
storageQuota
|
||||
historyPeriod
|
||||
memberLimit
|
||||
humanReadable {
|
||||
name
|
||||
blobLimit
|
||||
storageQuota
|
||||
historyPeriod
|
||||
memberLimit
|
||||
}
|
||||
}
|
||||
quotaUsage {
|
||||
storageQuota
|
||||
}
|
||||
copilot {
|
||||
quota {
|
||||
limit
|
||||
used
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
#import './fragments/current-user-profile.gql'
|
||||
|
||||
query getCurrentUserProfile {
|
||||
currentUser {
|
||||
...CurrentUserProfile
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
query getDocDefaultRole($workspaceId: String!, $docId: String!) {
|
||||
workspace(id: $workspaceId) {
|
||||
doc(docId: $docId) {
|
||||
defaultRole
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
query getMembersByWorkspaceId(
|
||||
$workspaceId: String!
|
||||
$skip: Int
|
||||
$take: Int
|
||||
$query: String
|
||||
) {
|
||||
workspace(id: $workspaceId) {
|
||||
memberCount
|
||||
members(skip: $skip, take: $take, query: $query) {
|
||||
id
|
||||
name
|
||||
email
|
||||
avatarUrl
|
||||
permission
|
||||
inviteId
|
||||
emailVerified
|
||||
status
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
query getPageGrantedUsersList(
|
||||
$pagination: PaginationInput!
|
||||
$docId: String!
|
||||
$workspaceId: String!
|
||||
) {
|
||||
workspace(id: $workspaceId) {
|
||||
doc(docId: $docId) {
|
||||
grantedUsersList(pagination: $pagination) {
|
||||
totalCount
|
||||
pageInfo {
|
||||
endCursor
|
||||
hasNextPage
|
||||
}
|
||||
edges {
|
||||
node {
|
||||
role
|
||||
user {
|
||||
id
|
||||
name
|
||||
email
|
||||
avatarUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
query getWorkspaceInfo($workspaceId: String!) {
|
||||
workspace(id: $workspaceId) {
|
||||
permissions {
|
||||
Workspace_Administrators_Manage
|
||||
Workspace_Blobs_List
|
||||
Workspace_Blobs_Read
|
||||
Workspace_Blobs_Write
|
||||
Workspace_Copilot
|
||||
Workspace_CreateDoc
|
||||
Workspace_Delete
|
||||
Workspace_Organize_Read
|
||||
Workspace_Payment_Manage
|
||||
Workspace_Properties_Create
|
||||
Workspace_Properties_Delete
|
||||
Workspace_Properties_Read
|
||||
Workspace_Properties_Update
|
||||
Workspace_Read
|
||||
Workspace_Settings_Read
|
||||
Workspace_Settings_Update
|
||||
Workspace_Sync
|
||||
Workspace_TransferOwner
|
||||
Workspace_Users_Manage
|
||||
Workspace_Users_Read
|
||||
}
|
||||
role
|
||||
team
|
||||
}
|
||||
}
|
||||
@@ -41,42 +41,6 @@ export const credentialsRequirementsFragment = `fragment CredentialsRequirements
|
||||
...PasswordLimits
|
||||
}
|
||||
}`;
|
||||
export const currentUserProfileFragment = `fragment CurrentUserProfile on UserType {
|
||||
id
|
||||
name
|
||||
email
|
||||
avatarUrl
|
||||
emailVerified
|
||||
features
|
||||
settings {
|
||||
receiveInvitationEmail
|
||||
receiveMentionEmail
|
||||
receiveCommentEmail
|
||||
}
|
||||
quota {
|
||||
name
|
||||
blobLimit
|
||||
storageQuota
|
||||
historyPeriod
|
||||
memberLimit
|
||||
humanReadable {
|
||||
name
|
||||
blobLimit
|
||||
storageQuota
|
||||
historyPeriod
|
||||
memberLimit
|
||||
}
|
||||
}
|
||||
quotaUsage {
|
||||
storageQuota
|
||||
}
|
||||
copilot {
|
||||
quota {
|
||||
limit
|
||||
used
|
||||
}
|
||||
}
|
||||
}`;
|
||||
export const paginatedCopilotChatsFragment = `fragment PaginatedCopilotChats on PaginatedCopilotHistoriesType {
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
@@ -117,22 +81,6 @@ export const generateUserAccessTokenMutation = {
|
||||
}`,
|
||||
};
|
||||
|
||||
export const listUserAccessTokensQuery = {
|
||||
id: 'listUserAccessTokensQuery' as const,
|
||||
op: 'listUserAccessTokens',
|
||||
query: `query listUserAccessTokens {
|
||||
currentUser {
|
||||
revealedAccessTokens {
|
||||
id
|
||||
name
|
||||
createdAt
|
||||
expiresAt
|
||||
token
|
||||
}
|
||||
}
|
||||
}`,
|
||||
};
|
||||
|
||||
export const revokeUserAccessTokenMutation = {
|
||||
id: 'revokeUserAccessTokenMutation' as const,
|
||||
op: 'revokeUserAccessToken',
|
||||
@@ -1287,18 +1235,6 @@ export const matchFilesQuery = {
|
||||
}`,
|
||||
};
|
||||
|
||||
export const getWorkspaceEmbeddingStatusQuery = {
|
||||
id: 'getWorkspaceEmbeddingStatusQuery' as const,
|
||||
op: 'getWorkspaceEmbeddingStatus',
|
||||
query: `query getWorkspaceEmbeddingStatus($workspaceId: String!) {
|
||||
queryWorkspaceEmbeddingStatus(workspaceId: $workspaceId) {
|
||||
total
|
||||
embedded
|
||||
}
|
||||
}`,
|
||||
deprecations: ["'queryWorkspaceEmbeddingStatus' is deprecated: Use realtime subscription \"workspace.embedding.progress.changed\" instead."],
|
||||
};
|
||||
|
||||
export const queueWorkspaceEmbeddingMutation = {
|
||||
id: 'queueWorkspaceEmbeddingMutation' as const,
|
||||
op: 'queueWorkspaceEmbedding',
|
||||
@@ -1936,17 +1872,6 @@ export const getCurrentUserFeaturesQuery = {
|
||||
}`,
|
||||
};
|
||||
|
||||
export const getCurrentUserProfileQuery = {
|
||||
id: 'getCurrentUserProfileQuery' as const,
|
||||
op: 'getCurrentUserProfile',
|
||||
query: `query getCurrentUserProfile {
|
||||
currentUser {
|
||||
...CurrentUserProfile
|
||||
}
|
||||
}
|
||||
${currentUserProfileFragment}`,
|
||||
};
|
||||
|
||||
export const getCurrentUserQuery = {
|
||||
id: 'getCurrentUserQuery' as const,
|
||||
op: 'getCurrentUser',
|
||||
@@ -1988,18 +1913,6 @@ export const getDocCreatedByUpdatedByListQuery = {
|
||||
}`,
|
||||
};
|
||||
|
||||
export const getDocDefaultRoleQuery = {
|
||||
id: 'getDocDefaultRoleQuery' as const,
|
||||
op: 'getDocDefaultRole',
|
||||
query: `query getDocDefaultRole($workspaceId: String!, $docId: String!) {
|
||||
workspace(id: $workspaceId) {
|
||||
doc(docId: $docId) {
|
||||
defaultRole
|
||||
}
|
||||
}
|
||||
}`,
|
||||
};
|
||||
|
||||
export const getDocLastAccessedMembersQuery = {
|
||||
id: 'getDocLastAccessedMembersQuery' as const,
|
||||
op: 'getDocLastAccessedMembers',
|
||||
@@ -2118,27 +2031,6 @@ export const getMemberCountByWorkspaceIdQuery = {
|
||||
}`,
|
||||
};
|
||||
|
||||
export const getMembersByWorkspaceIdQuery = {
|
||||
id: 'getMembersByWorkspaceIdQuery' as const,
|
||||
op: 'getMembersByWorkspaceId',
|
||||
query: `query getMembersByWorkspaceId($workspaceId: String!, $skip: Int, $take: Int, $query: String) {
|
||||
workspace(id: $workspaceId) {
|
||||
memberCount
|
||||
members(skip: $skip, take: $take, query: $query) {
|
||||
id
|
||||
name
|
||||
email
|
||||
avatarUrl
|
||||
permission
|
||||
inviteId
|
||||
emailVerified
|
||||
status
|
||||
}
|
||||
}
|
||||
}`,
|
||||
deprecations: ["'permission' is deprecated: Use role instead"],
|
||||
};
|
||||
|
||||
export const oauthProvidersQuery = {
|
||||
id: 'oauthProvidersQuery' as const,
|
||||
op: 'oauthProviders',
|
||||
@@ -2149,35 +2041,6 @@ export const oauthProvidersQuery = {
|
||||
}`,
|
||||
};
|
||||
|
||||
export const getPageGrantedUsersListQuery = {
|
||||
id: 'getPageGrantedUsersListQuery' as const,
|
||||
op: 'getPageGrantedUsersList',
|
||||
query: `query getPageGrantedUsersList($pagination: PaginationInput!, $docId: String!, $workspaceId: String!) {
|
||||
workspace(id: $workspaceId) {
|
||||
doc(docId: $docId) {
|
||||
grantedUsersList(pagination: $pagination) {
|
||||
totalCount
|
||||
pageInfo {
|
||||
endCursor
|
||||
hasNextPage
|
||||
}
|
||||
edges {
|
||||
node {
|
||||
role
|
||||
user {
|
||||
id
|
||||
name
|
||||
email
|
||||
avatarUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
};
|
||||
|
||||
export const getPublicUserByIdQuery = {
|
||||
id: 'getPublicUserByIdQuery' as const,
|
||||
op: 'getPublicUserById',
|
||||
@@ -2262,39 +2125,6 @@ export const getUserQuery = {
|
||||
}`,
|
||||
};
|
||||
|
||||
export const getWorkspaceInfoQuery = {
|
||||
id: 'getWorkspaceInfoQuery' as const,
|
||||
op: 'getWorkspaceInfo',
|
||||
query: `query getWorkspaceInfo($workspaceId: String!) {
|
||||
workspace(id: $workspaceId) {
|
||||
permissions {
|
||||
Workspace_Administrators_Manage
|
||||
Workspace_Blobs_List
|
||||
Workspace_Blobs_Read
|
||||
Workspace_Blobs_Write
|
||||
Workspace_Copilot
|
||||
Workspace_CreateDoc
|
||||
Workspace_Delete
|
||||
Workspace_Organize_Read
|
||||
Workspace_Payment_Manage
|
||||
Workspace_Properties_Create
|
||||
Workspace_Properties_Delete
|
||||
Workspace_Properties_Read
|
||||
Workspace_Properties_Update
|
||||
Workspace_Read
|
||||
Workspace_Settings_Read
|
||||
Workspace_Settings_Update
|
||||
Workspace_Sync
|
||||
Workspace_TransferOwner
|
||||
Workspace_Users_Manage
|
||||
Workspace_Users_Read
|
||||
}
|
||||
role
|
||||
team
|
||||
}
|
||||
}`,
|
||||
};
|
||||
|
||||
export const getWorkspacePageByIdQuery = {
|
||||
id: 'getWorkspacePageByIdQuery' as const,
|
||||
op: 'getWorkspacePageById',
|
||||
@@ -2643,17 +2473,6 @@ export const mentionUserMutation = {
|
||||
}`,
|
||||
};
|
||||
|
||||
export const notificationCountQuery = {
|
||||
id: 'notificationCountQuery' as const,
|
||||
op: 'notificationCount',
|
||||
query: `query notificationCount {
|
||||
currentUser {
|
||||
notificationCount
|
||||
}
|
||||
}`,
|
||||
deprecations: ["'notificationCount' is deprecated: Use realtime subscription \"notification.count.changed\" instead."],
|
||||
};
|
||||
|
||||
export const pricesQuery = {
|
||||
id: 'pricesQuery' as const,
|
||||
op: 'prices',
|
||||
@@ -3117,19 +2936,6 @@ export const workspaceByokSettingsQuery = {
|
||||
}`,
|
||||
};
|
||||
|
||||
export const getWorkspaceConfigQuery = {
|
||||
id: 'getWorkspaceConfigQuery' as const,
|
||||
op: 'getWorkspaceConfig',
|
||||
query: `query getWorkspaceConfig($id: String!) {
|
||||
workspace(id: $id) {
|
||||
enableAi
|
||||
enableSharing
|
||||
enableUrlPreview
|
||||
enableDocEmbedding
|
||||
}
|
||||
}`,
|
||||
};
|
||||
|
||||
export const setEnableAiMutation = {
|
||||
id: 'setEnableAiMutation' as const,
|
||||
op: 'setEnableAi',
|
||||
@@ -3191,19 +2997,6 @@ export const acceptInviteByInviteIdMutation = {
|
||||
}`,
|
||||
};
|
||||
|
||||
export const getWorkspaceInviteLinkQuery = {
|
||||
id: 'getWorkspaceInviteLinkQuery' as const,
|
||||
op: 'getWorkspaceInviteLink',
|
||||
query: `query getWorkspaceInviteLink($id: String!) {
|
||||
workspace(id: $id) {
|
||||
inviteLink {
|
||||
link
|
||||
expireTime
|
||||
}
|
||||
}
|
||||
}`,
|
||||
};
|
||||
|
||||
export const createInviteLinkMutation = {
|
||||
id: 'createInviteLinkMutation' as const,
|
||||
op: 'createInviteLink',
|
||||
@@ -3244,34 +3037,6 @@ export const workspaceInvoicesQuery = {
|
||||
deprecations: ["'id' is deprecated: removed"],
|
||||
};
|
||||
|
||||
export const workspaceQuotaQuery = {
|
||||
id: 'workspaceQuotaQuery' as const,
|
||||
op: 'workspaceQuota',
|
||||
query: `query workspaceQuota($id: String!) {
|
||||
workspace(id: $id) {
|
||||
quota {
|
||||
name
|
||||
blobLimit
|
||||
storageQuota
|
||||
usedStorageQuota
|
||||
historyPeriod
|
||||
memberLimit
|
||||
memberCount
|
||||
overcapacityMemberCount
|
||||
humanReadable {
|
||||
name
|
||||
blobLimit
|
||||
storageQuota
|
||||
historyPeriod
|
||||
memberLimit
|
||||
memberCount
|
||||
overcapacityMemberCount
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
};
|
||||
|
||||
export const getWorkspaceRolePermissionsQuery = {
|
||||
id: 'getWorkspaceRolePermissionsQuery' as const,
|
||||
op: 'getWorkspaceRolePermissions',
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
query notificationCount {
|
||||
currentUser {
|
||||
notificationCount
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
query getWorkspaceConfig($id: String!) {
|
||||
workspace(id: $id) {
|
||||
enableAi
|
||||
enableSharing
|
||||
enableUrlPreview
|
||||
enableDocEmbedding
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
query getWorkspaceInviteLink($id: String!) {
|
||||
workspace(id: $id) {
|
||||
inviteLink {
|
||||
link
|
||||
expireTime
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
query workspaceQuota($id: String!) {
|
||||
workspace(id: $id) {
|
||||
quota {
|
||||
name
|
||||
blobLimit
|
||||
storageQuota
|
||||
usedStorageQuota
|
||||
historyPeriod
|
||||
memberLimit
|
||||
memberCount
|
||||
overcapacityMemberCount
|
||||
humanReadable {
|
||||
name
|
||||
blobLimit
|
||||
storageQuota
|
||||
historyPeriod
|
||||
memberLimit
|
||||
memberCount
|
||||
overcapacityMemberCount
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3785,25 +3785,6 @@ export type GenerateUserAccessTokenMutation = {
|
||||
};
|
||||
};
|
||||
|
||||
export type ListUserAccessTokensQueryVariables = Exact<{
|
||||
[key: string]: never;
|
||||
}>;
|
||||
|
||||
export type ListUserAccessTokensQuery = {
|
||||
__typename?: 'Query';
|
||||
currentUser: {
|
||||
__typename?: 'UserType';
|
||||
revealedAccessTokens: Array<{
|
||||
__typename?: 'RevealedAccessToken';
|
||||
id: string;
|
||||
name: string;
|
||||
createdAt: string;
|
||||
expiresAt: string | null;
|
||||
token: string;
|
||||
}>;
|
||||
} | null;
|
||||
};
|
||||
|
||||
export type RevokeUserAccessTokenMutationVariables = Exact<{
|
||||
id: Scalars['String']['input'];
|
||||
}>;
|
||||
@@ -5112,19 +5093,6 @@ export type MatchFilesQuery = {
|
||||
} | null;
|
||||
};
|
||||
|
||||
export type GetWorkspaceEmbeddingStatusQueryVariables = Exact<{
|
||||
workspaceId: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
export type GetWorkspaceEmbeddingStatusQuery = {
|
||||
__typename?: 'Query';
|
||||
queryWorkspaceEmbeddingStatus: {
|
||||
__typename?: 'ContextWorkspaceEmbeddingStatus';
|
||||
total: number;
|
||||
embedded: number;
|
||||
};
|
||||
};
|
||||
|
||||
export type QueueWorkspaceEmbeddingMutationVariables = Exact<{
|
||||
workspaceId: Scalars['String']['input'];
|
||||
docId: Array<Scalars['String']['input']> | Scalars['String']['input'];
|
||||
@@ -6271,43 +6239,6 @@ export type CredentialsRequirementsFragment = {
|
||||
};
|
||||
};
|
||||
|
||||
export type CurrentUserProfileFragment = {
|
||||
__typename?: 'UserType';
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
avatarUrl: string | null;
|
||||
emailVerified: boolean;
|
||||
features: Array<FeatureType>;
|
||||
settings: {
|
||||
__typename?: 'UserSettingsType';
|
||||
receiveInvitationEmail: boolean;
|
||||
receiveMentionEmail: boolean;
|
||||
receiveCommentEmail: boolean;
|
||||
};
|
||||
quota: {
|
||||
__typename?: 'UserQuotaType';
|
||||
name: string;
|
||||
blobLimit: number;
|
||||
storageQuota: number;
|
||||
historyPeriod: number;
|
||||
memberLimit: number;
|
||||
humanReadable: {
|
||||
__typename?: 'UserQuotaHumanReadableType';
|
||||
name: string;
|
||||
blobLimit: string;
|
||||
storageQuota: string;
|
||||
historyPeriod: string;
|
||||
memberLimit: string;
|
||||
};
|
||||
};
|
||||
quotaUsage: { __typename?: 'UserQuotaUsageType'; storageQuota: number };
|
||||
copilot: {
|
||||
__typename?: 'Copilot';
|
||||
quota: { __typename?: 'CopilotQuota'; limit: number | null; used: number };
|
||||
};
|
||||
};
|
||||
|
||||
export type PaginatedCopilotChatsFragment = {
|
||||
__typename?: 'PaginatedCopilotHistoriesType';
|
||||
pageInfo: {
|
||||
@@ -6388,54 +6319,6 @@ export type GetCurrentUserFeaturesQuery = {
|
||||
} | null;
|
||||
};
|
||||
|
||||
export type GetCurrentUserProfileQueryVariables = Exact<{
|
||||
[key: string]: never;
|
||||
}>;
|
||||
|
||||
export type GetCurrentUserProfileQuery = {
|
||||
__typename?: 'Query';
|
||||
currentUser: {
|
||||
__typename?: 'UserType';
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
avatarUrl: string | null;
|
||||
emailVerified: boolean;
|
||||
features: Array<FeatureType>;
|
||||
settings: {
|
||||
__typename?: 'UserSettingsType';
|
||||
receiveInvitationEmail: boolean;
|
||||
receiveMentionEmail: boolean;
|
||||
receiveCommentEmail: boolean;
|
||||
};
|
||||
quota: {
|
||||
__typename?: 'UserQuotaType';
|
||||
name: string;
|
||||
blobLimit: number;
|
||||
storageQuota: number;
|
||||
historyPeriod: number;
|
||||
memberLimit: number;
|
||||
humanReadable: {
|
||||
__typename?: 'UserQuotaHumanReadableType';
|
||||
name: string;
|
||||
blobLimit: string;
|
||||
storageQuota: string;
|
||||
historyPeriod: string;
|
||||
memberLimit: string;
|
||||
};
|
||||
};
|
||||
quotaUsage: { __typename?: 'UserQuotaUsageType'; storageQuota: number };
|
||||
copilot: {
|
||||
__typename?: 'Copilot';
|
||||
quota: {
|
||||
__typename?: 'CopilotQuota';
|
||||
limit: number | null;
|
||||
used: number;
|
||||
};
|
||||
};
|
||||
} | null;
|
||||
};
|
||||
|
||||
export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never }>;
|
||||
|
||||
export type GetCurrentUserQuery = {
|
||||
@@ -6481,19 +6364,6 @@ export type GetDocCreatedByUpdatedByListQuery = {
|
||||
};
|
||||
};
|
||||
|
||||
export type GetDocDefaultRoleQueryVariables = Exact<{
|
||||
workspaceId: Scalars['String']['input'];
|
||||
docId: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
export type GetDocDefaultRoleQuery = {
|
||||
__typename?: 'Query';
|
||||
workspace: {
|
||||
__typename?: 'WorkspaceType';
|
||||
doc: { __typename?: 'DocType'; defaultRole: DocRole };
|
||||
};
|
||||
};
|
||||
|
||||
export type GetDocLastAccessedMembersQueryVariables = Exact<{
|
||||
workspaceId: Scalars['String']['input'];
|
||||
docId: Scalars['String']['input'];
|
||||
@@ -6634,32 +6504,6 @@ export type GetMemberCountByWorkspaceIdQuery = {
|
||||
workspace: { __typename?: 'WorkspaceType'; memberCount: number };
|
||||
};
|
||||
|
||||
export type GetMembersByWorkspaceIdQueryVariables = Exact<{
|
||||
workspaceId: Scalars['String']['input'];
|
||||
skip?: InputMaybe<Scalars['Int']['input']>;
|
||||
take?: InputMaybe<Scalars['Int']['input']>;
|
||||
query?: InputMaybe<Scalars['String']['input']>;
|
||||
}>;
|
||||
|
||||
export type GetMembersByWorkspaceIdQuery = {
|
||||
__typename?: 'Query';
|
||||
workspace: {
|
||||
__typename?: 'WorkspaceType';
|
||||
memberCount: number;
|
||||
members: Array<{
|
||||
__typename?: 'InviteUserType';
|
||||
id: string;
|
||||
name: string | null;
|
||||
email: string | null;
|
||||
avatarUrl: string | null;
|
||||
permission: Permission;
|
||||
inviteId: string;
|
||||
emailVerified: boolean | null;
|
||||
status: WorkspaceMemberStatus;
|
||||
}>;
|
||||
};
|
||||
};
|
||||
|
||||
export type OauthProvidersQueryVariables = Exact<{ [key: string]: never }>;
|
||||
|
||||
export type OauthProvidersQuery = {
|
||||
@@ -6670,45 +6514,6 @@ export type OauthProvidersQuery = {
|
||||
};
|
||||
};
|
||||
|
||||
export type GetPageGrantedUsersListQueryVariables = Exact<{
|
||||
pagination: PaginationInput;
|
||||
docId: Scalars['String']['input'];
|
||||
workspaceId: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
export type GetPageGrantedUsersListQuery = {
|
||||
__typename?: 'Query';
|
||||
workspace: {
|
||||
__typename?: 'WorkspaceType';
|
||||
doc: {
|
||||
__typename?: 'DocType';
|
||||
grantedUsersList: {
|
||||
__typename?: 'PaginatedGrantedDocUserType';
|
||||
totalCount: number;
|
||||
pageInfo: {
|
||||
__typename?: 'PageInfo';
|
||||
endCursor: string | null;
|
||||
hasNextPage: boolean;
|
||||
};
|
||||
edges: Array<{
|
||||
__typename?: 'GrantedDocUserTypeEdge';
|
||||
node: {
|
||||
__typename?: 'GrantedDocUserType';
|
||||
role: DocRole;
|
||||
user: {
|
||||
__typename?: 'WorkspaceUserType';
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
avatarUrl: string | null;
|
||||
};
|
||||
};
|
||||
}>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export type GetPublicUserByIdQueryVariables = Exact<{
|
||||
id: Scalars['String']['input'];
|
||||
}>;
|
||||
@@ -6805,42 +6610,6 @@ export type GetUserQuery = {
|
||||
| null;
|
||||
};
|
||||
|
||||
export type GetWorkspaceInfoQueryVariables = Exact<{
|
||||
workspaceId: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
export type GetWorkspaceInfoQuery = {
|
||||
__typename?: 'Query';
|
||||
workspace: {
|
||||
__typename?: 'WorkspaceType';
|
||||
role: Permission;
|
||||
team: boolean;
|
||||
permissions: {
|
||||
__typename?: 'WorkspacePermissions';
|
||||
Workspace_Administrators_Manage: boolean;
|
||||
Workspace_Blobs_List: boolean;
|
||||
Workspace_Blobs_Read: boolean;
|
||||
Workspace_Blobs_Write: boolean;
|
||||
Workspace_Copilot: boolean;
|
||||
Workspace_CreateDoc: boolean;
|
||||
Workspace_Delete: boolean;
|
||||
Workspace_Organize_Read: boolean;
|
||||
Workspace_Payment_Manage: boolean;
|
||||
Workspace_Properties_Create: boolean;
|
||||
Workspace_Properties_Delete: boolean;
|
||||
Workspace_Properties_Read: boolean;
|
||||
Workspace_Properties_Update: boolean;
|
||||
Workspace_Read: boolean;
|
||||
Workspace_Settings_Read: boolean;
|
||||
Workspace_Settings_Update: boolean;
|
||||
Workspace_Sync: boolean;
|
||||
Workspace_TransferOwner: boolean;
|
||||
Workspace_Users_Manage: boolean;
|
||||
Workspace_Users_Read: boolean;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export type GetWorkspacePageByIdQueryVariables = Exact<{
|
||||
workspaceId: Scalars['String']['input'];
|
||||
pageId: Scalars['String']['input'];
|
||||
@@ -7268,13 +7037,6 @@ export type MentionUserMutation = {
|
||||
mentionUser: string;
|
||||
};
|
||||
|
||||
export type NotificationCountQueryVariables = Exact<{ [key: string]: never }>;
|
||||
|
||||
export type NotificationCountQuery = {
|
||||
__typename?: 'Query';
|
||||
currentUser: { __typename?: 'UserType'; notificationCount: number } | null;
|
||||
};
|
||||
|
||||
export type PricesQueryVariables = Exact<{ [key: string]: never }>;
|
||||
|
||||
export type PricesQuery = {
|
||||
@@ -7784,21 +7546,6 @@ export type WorkspaceByokSettingsQuery = {
|
||||
};
|
||||
};
|
||||
|
||||
export type GetWorkspaceConfigQueryVariables = Exact<{
|
||||
id: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
export type GetWorkspaceConfigQuery = {
|
||||
__typename?: 'Query';
|
||||
workspace: {
|
||||
__typename?: 'WorkspaceType';
|
||||
enableAi: boolean;
|
||||
enableSharing: boolean;
|
||||
enableUrlPreview: boolean;
|
||||
enableDocEmbedding: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
export type SetEnableAiMutationVariables = Exact<{
|
||||
id: Scalars['ID']['input'];
|
||||
enableAi: Scalars['Boolean']['input'];
|
||||
@@ -7864,22 +7611,6 @@ export type AcceptInviteByInviteIdMutation = {
|
||||
acceptInviteById: boolean;
|
||||
};
|
||||
|
||||
export type GetWorkspaceInviteLinkQueryVariables = Exact<{
|
||||
id: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
export type GetWorkspaceInviteLinkQuery = {
|
||||
__typename?: 'Query';
|
||||
workspace: {
|
||||
__typename?: 'WorkspaceType';
|
||||
inviteLink: {
|
||||
__typename?: 'InviteLink';
|
||||
link: string;
|
||||
expireTime: string;
|
||||
} | null;
|
||||
};
|
||||
};
|
||||
|
||||
export type CreateInviteLinkMutationVariables = Exact<{
|
||||
workspaceId: Scalars['String']['input'];
|
||||
expireTime: WorkspaceInviteLinkExpireTime;
|
||||
@@ -7928,38 +7659,6 @@ export type WorkspaceInvoicesQuery = {
|
||||
};
|
||||
};
|
||||
|
||||
export type WorkspaceQuotaQueryVariables = Exact<{
|
||||
id: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
export type WorkspaceQuotaQuery = {
|
||||
__typename?: 'Query';
|
||||
workspace: {
|
||||
__typename?: 'WorkspaceType';
|
||||
quota: {
|
||||
__typename?: 'WorkspaceQuotaType';
|
||||
name: string;
|
||||
blobLimit: number;
|
||||
storageQuota: number;
|
||||
usedStorageQuota: number;
|
||||
historyPeriod: number;
|
||||
memberLimit: number;
|
||||
memberCount: number;
|
||||
overcapacityMemberCount: number;
|
||||
humanReadable: {
|
||||
__typename?: 'WorkspaceQuotaHumanReadableType';
|
||||
name: string;
|
||||
blobLimit: string;
|
||||
storageQuota: string;
|
||||
historyPeriod: string;
|
||||
memberLimit: string;
|
||||
memberCount: string;
|
||||
overcapacityMemberCount: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export type GetWorkspaceRolePermissionsQueryVariables = Exact<{
|
||||
id: Scalars['String']['input'];
|
||||
}>;
|
||||
@@ -8016,11 +7715,6 @@ export type GrantWorkspaceTeamMemberMutation = {
|
||||
};
|
||||
|
||||
export type Queries =
|
||||
| {
|
||||
name: 'listUserAccessTokensQuery';
|
||||
variables: ListUserAccessTokensQueryVariables;
|
||||
response: ListUserAccessTokensQuery;
|
||||
}
|
||||
| {
|
||||
name: 'adminAllSharedLinksQuery';
|
||||
variables: AdminAllSharedLinksQueryVariables;
|
||||
@@ -8136,11 +7830,6 @@ export type Queries =
|
||||
variables: MatchFilesQueryVariables;
|
||||
response: MatchFilesQuery;
|
||||
}
|
||||
| {
|
||||
name: 'getWorkspaceEmbeddingStatusQuery';
|
||||
variables: GetWorkspaceEmbeddingStatusQueryVariables;
|
||||
response: GetWorkspaceEmbeddingStatusQuery;
|
||||
}
|
||||
| {
|
||||
name: 'getCopilotHistoryIdsQuery';
|
||||
variables: GetCopilotHistoryIdsQueryVariables;
|
||||
@@ -8226,11 +7915,6 @@ export type Queries =
|
||||
variables: GetCurrentUserFeaturesQueryVariables;
|
||||
response: GetCurrentUserFeaturesQuery;
|
||||
}
|
||||
| {
|
||||
name: 'getCurrentUserProfileQuery';
|
||||
variables: GetCurrentUserProfileQueryVariables;
|
||||
response: GetCurrentUserProfileQuery;
|
||||
}
|
||||
| {
|
||||
name: 'getCurrentUserQuery';
|
||||
variables: GetCurrentUserQueryVariables;
|
||||
@@ -8241,11 +7925,6 @@ export type Queries =
|
||||
variables: GetDocCreatedByUpdatedByListQueryVariables;
|
||||
response: GetDocCreatedByUpdatedByListQuery;
|
||||
}
|
||||
| {
|
||||
name: 'getDocDefaultRoleQuery';
|
||||
variables: GetDocDefaultRoleQueryVariables;
|
||||
response: GetDocDefaultRoleQuery;
|
||||
}
|
||||
| {
|
||||
name: 'getDocLastAccessedMembersQuery';
|
||||
variables: GetDocLastAccessedMembersQueryVariables;
|
||||
@@ -8271,21 +7950,11 @@ export type Queries =
|
||||
variables: GetMemberCountByWorkspaceIdQueryVariables;
|
||||
response: GetMemberCountByWorkspaceIdQuery;
|
||||
}
|
||||
| {
|
||||
name: 'getMembersByWorkspaceIdQuery';
|
||||
variables: GetMembersByWorkspaceIdQueryVariables;
|
||||
response: GetMembersByWorkspaceIdQuery;
|
||||
}
|
||||
| {
|
||||
name: 'oauthProvidersQuery';
|
||||
variables: OauthProvidersQueryVariables;
|
||||
response: OauthProvidersQuery;
|
||||
}
|
||||
| {
|
||||
name: 'getPageGrantedUsersListQuery';
|
||||
variables: GetPageGrantedUsersListQueryVariables;
|
||||
response: GetPageGrantedUsersListQuery;
|
||||
}
|
||||
| {
|
||||
name: 'getPublicUserByIdQuery';
|
||||
variables: GetPublicUserByIdQueryVariables;
|
||||
@@ -8311,11 +7980,6 @@ export type Queries =
|
||||
variables: GetUserQueryVariables;
|
||||
response: GetUserQuery;
|
||||
}
|
||||
| {
|
||||
name: 'getWorkspaceInfoQuery';
|
||||
variables: GetWorkspaceInfoQueryVariables;
|
||||
response: GetWorkspaceInfoQuery;
|
||||
}
|
||||
| {
|
||||
name: 'getWorkspacePageByIdQuery';
|
||||
variables: GetWorkspacePageByIdQueryVariables;
|
||||
@@ -8391,11 +8055,6 @@ export type Queries =
|
||||
variables: ListNotificationsQueryVariables;
|
||||
response: ListNotificationsQuery;
|
||||
}
|
||||
| {
|
||||
name: 'notificationCountQuery';
|
||||
variables: NotificationCountQueryVariables;
|
||||
response: NotificationCountQuery;
|
||||
}
|
||||
| {
|
||||
name: 'pricesQuery';
|
||||
variables: PricesQueryVariables;
|
||||
@@ -8426,26 +8085,11 @@ export type Queries =
|
||||
variables: WorkspaceByokSettingsQueryVariables;
|
||||
response: WorkspaceByokSettingsQuery;
|
||||
}
|
||||
| {
|
||||
name: 'getWorkspaceConfigQuery';
|
||||
variables: GetWorkspaceConfigQueryVariables;
|
||||
response: GetWorkspaceConfigQuery;
|
||||
}
|
||||
| {
|
||||
name: 'getWorkspaceInviteLinkQuery';
|
||||
variables: GetWorkspaceInviteLinkQueryVariables;
|
||||
response: GetWorkspaceInviteLinkQuery;
|
||||
}
|
||||
| {
|
||||
name: 'workspaceInvoicesQuery';
|
||||
variables: WorkspaceInvoicesQueryVariables;
|
||||
response: WorkspaceInvoicesQuery;
|
||||
}
|
||||
| {
|
||||
name: 'workspaceQuotaQuery';
|
||||
variables: WorkspaceQuotaQueryVariables;
|
||||
response: WorkspaceQuotaQuery;
|
||||
}
|
||||
| {
|
||||
name: 'getWorkspaceRolePermissionsQuery';
|
||||
variables: GetWorkspaceRolePermissionsQueryVariables;
|
||||
|
||||
@@ -235,11 +235,19 @@ class SocketManager {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.socket.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
const SOCKET_MANAGER_CACHE = new Map<string, SocketManager>();
|
||||
function getSocketManagerKey(endpoint: string, isSelfHosted: boolean) {
|
||||
return `${endpoint}:${isSelfHosted ? 'selfhosted' : 'cloud'}`;
|
||||
}
|
||||
|
||||
function getSocketManager(endpoint: string, isSelfHosted: boolean) {
|
||||
const key = `${endpoint}:${isSelfHosted ? 'selfhosted' : 'cloud'}`;
|
||||
const key = getSocketManagerKey(endpoint, isSelfHosted);
|
||||
let manager = SOCKET_MANAGER_CACHE.get(key);
|
||||
if (!manager) {
|
||||
manager = new SocketManager(endpoint, isSelfHosted);
|
||||
@@ -252,6 +260,12 @@ export class SocketConnection extends AutoReconnectConnection<{
|
||||
socket: Socket;
|
||||
disconnect: () => void;
|
||||
}> {
|
||||
static resetSharedConnection(endpoint: string, isSelfHosted: boolean) {
|
||||
SOCKET_MANAGER_CACHE.get(
|
||||
getSocketManagerKey(endpoint, isSelfHosted)
|
||||
)?.reset();
|
||||
}
|
||||
|
||||
manager = getSocketManager(this.endpoint, this.isSelfHosted);
|
||||
|
||||
constructor(
|
||||
|
||||
@@ -41,10 +41,15 @@ class FakeSocket {
|
||||
}
|
||||
}
|
||||
|
||||
const { resetSharedConnection } = vi.hoisted(() => ({
|
||||
resetSharedConnection: vi.fn(),
|
||||
}));
|
||||
const socket = new FakeSocket();
|
||||
|
||||
vi.mock('../../impls/cloud/socket', () => ({
|
||||
SocketConnection: class {
|
||||
static resetSharedConnection = resetSharedConnection;
|
||||
|
||||
readonly inner = { socket };
|
||||
status = 'connected';
|
||||
readonly maybeConnection = { socket };
|
||||
@@ -68,6 +73,7 @@ beforeEach(() => {
|
||||
socket.nextSubscriptionId = 0;
|
||||
socket.connected = true;
|
||||
socket.disconnected = false;
|
||||
resetSharedConnection.mockClear();
|
||||
});
|
||||
|
||||
test('getRealtimeInputKey is deterministic for realtime subscription inputs', () => {
|
||||
@@ -124,6 +130,33 @@ test('request rejects server ack error', async () => {
|
||||
);
|
||||
});
|
||||
|
||||
test('user profile request can bootstrap without authenticated context', async () => {
|
||||
const manager = new RealtimeManager();
|
||||
manager.setContext({
|
||||
endpoint: 'http://server',
|
||||
isSelfHosted: false,
|
||||
authenticated: false,
|
||||
});
|
||||
socket.nextRequestAck = { data: { user: null } };
|
||||
|
||||
await expect(manager.request('user.profile.get', {})).resolves.toEqual({
|
||||
user: null,
|
||||
});
|
||||
});
|
||||
|
||||
test('non-bootstrap request still requires authenticated context', async () => {
|
||||
const manager = new RealtimeManager();
|
||||
manager.setContext({
|
||||
endpoint: 'http://server',
|
||||
isSelfHosted: false,
|
||||
authenticated: false,
|
||||
});
|
||||
|
||||
await expect(manager.request('notification.count.get', {})).rejects.toThrow(
|
||||
'Realtime is not authenticated'
|
||||
);
|
||||
});
|
||||
|
||||
test('request rejects when aborted', async () => {
|
||||
const manager = new RealtimeManager();
|
||||
manager.setContext({
|
||||
@@ -203,7 +236,7 @@ test('unsubscribe leaves server room and clears status', async () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('context switch disconnects socket and completes subscriptions', async () => {
|
||||
test('context switch disconnects socket and keeps subscriptions for reauth', async () => {
|
||||
const manager = new RealtimeManager();
|
||||
manager.setContext({
|
||||
endpoint: 'http://server',
|
||||
@@ -223,11 +256,95 @@ test('context switch disconnects socket and completes subscriptions', async () =
|
||||
});
|
||||
|
||||
expect(socket.disconnected).toBe(true);
|
||||
expect(completed).toHaveBeenCalled();
|
||||
expect(completed).not.toHaveBeenCalled();
|
||||
expect(manager.getStatus()).toMatchObject({
|
||||
endpoint: 'http://other-server',
|
||||
connected: false,
|
||||
subscriptions: 0,
|
||||
subscriptions: 1,
|
||||
});
|
||||
});
|
||||
|
||||
test('auth context switch resets shared socket connection', () => {
|
||||
const manager = new RealtimeManager();
|
||||
manager.setContext({
|
||||
endpoint: 'http://server',
|
||||
isSelfHosted: false,
|
||||
authenticated: true,
|
||||
});
|
||||
|
||||
manager.setContext({
|
||||
endpoint: 'http://server',
|
||||
isSelfHosted: false,
|
||||
authenticated: false,
|
||||
});
|
||||
|
||||
expect(resetSharedConnection).toHaveBeenCalledWith('http://server', false);
|
||||
});
|
||||
|
||||
test('context switch resubscribes existing subscriptions on next connect', async () => {
|
||||
const manager = new RealtimeManager();
|
||||
manager.setContext({
|
||||
endpoint: 'http://server',
|
||||
isSelfHosted: false,
|
||||
authenticated: true,
|
||||
});
|
||||
const received: unknown[] = [];
|
||||
const subscription = manager
|
||||
.subscribe('notification.count.changed', {})
|
||||
.subscribe(event => received.push(event));
|
||||
await vi.waitFor(() => expect(received).toEqual([{ type: 'ready' }]));
|
||||
|
||||
manager.setContext({
|
||||
endpoint: 'http://other-server',
|
||||
isSelfHosted: false,
|
||||
authenticated: true,
|
||||
});
|
||||
await manager.request('notification.count.get', {});
|
||||
|
||||
await vi.waitFor(() =>
|
||||
expect(
|
||||
socket.emitted.filter(item => item.event === 'realtime:subscribe')
|
||||
).toHaveLength(2)
|
||||
);
|
||||
expect(received).toEqual([{ type: 'ready' }, { type: 'ready' }]);
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
|
||||
test('unsubscribe uses resubscribed server subscription id', async () => {
|
||||
const manager = new RealtimeManager();
|
||||
manager.setContext({
|
||||
endpoint: 'http://server',
|
||||
isSelfHosted: false,
|
||||
authenticated: true,
|
||||
});
|
||||
const subscription = manager
|
||||
.subscribe('notification.count.changed', {})
|
||||
.subscribe();
|
||||
await vi.waitFor(() => expect(manager.getStatus().subscriptions).toBe(1));
|
||||
|
||||
manager.setContext({
|
||||
endpoint: 'http://other-server',
|
||||
isSelfHosted: false,
|
||||
authenticated: true,
|
||||
});
|
||||
await manager.request('notification.count.get', {});
|
||||
await vi.waitFor(() =>
|
||||
expect(
|
||||
socket.emitted.filter(item => item.event === 'realtime:subscribe')
|
||||
).toHaveLength(2)
|
||||
);
|
||||
|
||||
subscription.unsubscribe();
|
||||
|
||||
expect(manager.getStatus().subscriptions).toBe(0);
|
||||
expect(socket.emitted.at(-1)).toEqual({
|
||||
event: 'realtime:unsubscribe',
|
||||
payload: {
|
||||
subscriptionId: 'sub-2',
|
||||
topic: 'notification.count.changed',
|
||||
input: {},
|
||||
clientVersion: 'test',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ export class RealtimeManager {
|
||||
private socketConnection?: SocketConnection;
|
||||
private socketKey?: string;
|
||||
private lastError?: { name: string; message: string };
|
||||
private subscriptionsNeedResubscribe = false;
|
||||
private readonly subscriptions = new Map<
|
||||
string,
|
||||
{
|
||||
@@ -44,21 +45,32 @@ export class RealtimeManager {
|
||||
input: RealtimeTopicInputOf<RealtimeTopicName>;
|
||||
inputKey: string;
|
||||
subject$: Subject<RealtimeEvent | RealtimeSubscriptionReady>;
|
||||
onResubscribed: (subscriptionId: string) => void;
|
||||
}
|
||||
>();
|
||||
|
||||
setContext(context: RealtimeContext) {
|
||||
const nextContext = { ...context };
|
||||
const previousContext = this.context;
|
||||
const changed =
|
||||
!this.context ||
|
||||
this.context.endpoint !== nextContext.endpoint ||
|
||||
this.context.isSelfHosted !== nextContext.isSelfHosted ||
|
||||
this.context.authenticated !== nextContext.authenticated;
|
||||
!previousContext ||
|
||||
previousContext.endpoint !== nextContext.endpoint ||
|
||||
previousContext.isSelfHosted !== nextContext.isSelfHosted ||
|
||||
previousContext.authenticated !== nextContext.authenticated;
|
||||
|
||||
this.context = nextContext;
|
||||
|
||||
if (changed) {
|
||||
this.resetConnection();
|
||||
if (
|
||||
previousContext &&
|
||||
previousContext.authenticated !== nextContext.authenticated
|
||||
) {
|
||||
SocketConnection.resetSharedConnection(
|
||||
previousContext.endpoint,
|
||||
previousContext.isSelfHosted
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +79,7 @@ export class RealtimeManager {
|
||||
input: RealtimeRequestInputOf<Op>,
|
||||
options?: { timeoutMs?: number; signal?: AbortSignal }
|
||||
): Promise<RealtimeRequestOutputOf<Op>> {
|
||||
const socket = await this.connect();
|
||||
const socket = await this.connect(op === 'user.profile.get');
|
||||
const timeoutMs = options?.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT;
|
||||
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
||||
let abortHandler: (() => void) | undefined;
|
||||
@@ -154,6 +166,9 @@ export class RealtimeManager {
|
||||
input,
|
||||
inputKey: getRealtimeInputKey(input),
|
||||
subject$,
|
||||
onResubscribed: nextSubscriptionId => {
|
||||
subscriptionId = nextSubscriptionId;
|
||||
},
|
||||
});
|
||||
subscriber.next({
|
||||
type: 'ready',
|
||||
@@ -167,7 +182,7 @@ export class RealtimeManager {
|
||||
}
|
||||
},
|
||||
error: error => subscriber.error(error),
|
||||
complete: () => subscriber.complete(),
|
||||
complete: () => {},
|
||||
});
|
||||
} catch (error) {
|
||||
this.lastError = normalizeError(error);
|
||||
@@ -209,8 +224,11 @@ export class RealtimeManager {
|
||||
};
|
||||
}
|
||||
|
||||
private async connect() {
|
||||
if (!this.context?.endpoint || !this.context.authenticated) {
|
||||
private async connect(allowUnauthenticated = false) {
|
||||
if (
|
||||
!this.context?.endpoint ||
|
||||
(!this.context.authenticated && !allowUnauthenticated)
|
||||
) {
|
||||
const error = new Error('Realtime is not authenticated');
|
||||
error.name = 'RealtimeUnauthenticated';
|
||||
throw error;
|
||||
@@ -232,6 +250,9 @@ export class RealtimeManager {
|
||||
this.socketConnection.inner.socket.on('realtime:event', this.handleEvent);
|
||||
this.socketConnection.inner.socket.off('connect', this.handleReconnect);
|
||||
this.socketConnection.inner.socket.on('connect', this.handleReconnect);
|
||||
if (this.subscriptionsNeedResubscribe && this.context.authenticated) {
|
||||
await this.resubscribeAll();
|
||||
}
|
||||
return this.socketConnection.inner.socket;
|
||||
}
|
||||
|
||||
@@ -272,6 +293,7 @@ export class RealtimeManager {
|
||||
|
||||
this.subscriptions.delete(subscriptionId);
|
||||
this.subscriptions.set(ack.data.subscriptionId, subscription);
|
||||
subscription.onResubscribed(ack.data.subscriptionId);
|
||||
subscription.subject$.next({
|
||||
type: 'ready',
|
||||
});
|
||||
@@ -281,6 +303,7 @@ export class RealtimeManager {
|
||||
subscription.subject$.error(error);
|
||||
}
|
||||
}
|
||||
this.subscriptionsNeedResubscribe = false;
|
||||
}
|
||||
|
||||
private resetConnection() {
|
||||
@@ -297,9 +320,6 @@ export class RealtimeManager {
|
||||
}
|
||||
this.socketConnection = undefined;
|
||||
this.socketKey = undefined;
|
||||
for (const subscription of this.subscriptions.values()) {
|
||||
subscription.subject$.complete();
|
||||
}
|
||||
this.subscriptions.clear();
|
||||
this.subscriptionsNeedResubscribe = this.subscriptions.size > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,50 @@
|
||||
import type { CommentChangeObjectType } from '@affine/graphql';
|
||||
|
||||
export type RealtimeRequestName = keyof RealtimeRequestMap;
|
||||
export type RealtimeTopicName = keyof RealtimeTopicMap;
|
||||
|
||||
export const WORKSPACE_MEMBERS_REQUEST_TAKE_MAX = 100;
|
||||
|
||||
export interface RealtimeRequestMap {
|
||||
'workspace.access.get': {
|
||||
input: { workspaceId: string };
|
||||
output: { access: WorkspaceAccessSnapshot };
|
||||
};
|
||||
'workspace.config.get': {
|
||||
input: { workspaceId: string };
|
||||
output: { config: WorkspaceConfigSnapshot };
|
||||
};
|
||||
'workspace.members.get': {
|
||||
input: {
|
||||
workspaceId: string;
|
||||
skip?: number;
|
||||
take?: number;
|
||||
query?: string;
|
||||
};
|
||||
output: { members: WorkspaceMemberSnapshot[]; memberCount: number };
|
||||
};
|
||||
'workspace.invite-link.get': {
|
||||
input: { workspaceId: string };
|
||||
output: { inviteLink: WorkspaceInviteLinkSnapshot | null };
|
||||
};
|
||||
'doc.share-state.get': {
|
||||
input: { workspaceId: string; docId: string };
|
||||
output: { state: DocShareStateSnapshot | null };
|
||||
};
|
||||
'doc.grants.get': {
|
||||
input: { workspaceId: string; docId: string; pagination: PaginationInput };
|
||||
output: PaginatedDocGrantedUsersSnapshot;
|
||||
};
|
||||
'user.profile.get': {
|
||||
input: Record<string, never>;
|
||||
output: { user: CurrentUserProfileSnapshot | null };
|
||||
};
|
||||
'user.settings.get': {
|
||||
input: Record<string, never>;
|
||||
output: { settings: UserSettingsSnapshot };
|
||||
};
|
||||
'user.access-tokens.get': {
|
||||
input: Record<string, never>;
|
||||
output: { tokens: AccessTokenSnapshot[] };
|
||||
};
|
||||
'notification.count.get': {
|
||||
input: Record<string, never>;
|
||||
output: { count: number };
|
||||
@@ -16,7 +57,7 @@ export interface RealtimeRequestMap {
|
||||
first?: number;
|
||||
};
|
||||
output: {
|
||||
changes: CommentChangeObjectType[];
|
||||
changes: CommentChangeSnapshot[];
|
||||
startCursor: string;
|
||||
endCursor: string;
|
||||
hasNextPage: boolean;
|
||||
@@ -44,6 +85,117 @@ export interface RealtimeRequestMap {
|
||||
};
|
||||
}
|
||||
|
||||
export type WorkspaceRoleSnapshot =
|
||||
| 'Owner'
|
||||
| 'Admin'
|
||||
| 'Collaborator'
|
||||
| 'External'
|
||||
| string;
|
||||
|
||||
export type DocRoleSnapshot =
|
||||
| 'Owner'
|
||||
| 'Manager'
|
||||
| 'Editor'
|
||||
| 'Commenter'
|
||||
| 'Reader'
|
||||
| 'External'
|
||||
| string;
|
||||
|
||||
export type PublicDocModeSnapshot = 'Page' | 'Edgeless' | string;
|
||||
|
||||
export interface WorkspaceAccessSnapshot {
|
||||
role: WorkspaceRoleSnapshot;
|
||||
permissions: Record<string, boolean>;
|
||||
team: boolean;
|
||||
}
|
||||
|
||||
export interface WorkspaceConfigSnapshot {
|
||||
enableAi: boolean;
|
||||
enableSharing: boolean;
|
||||
enableUrlPreview: boolean;
|
||||
enableDocEmbedding: boolean;
|
||||
}
|
||||
|
||||
export interface WorkspaceMemberSnapshot {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
avatarUrl: string | null;
|
||||
permission: WorkspaceRoleSnapshot;
|
||||
role: WorkspaceRoleSnapshot;
|
||||
inviteId: string;
|
||||
emailVerified: boolean | null;
|
||||
status: string;
|
||||
}
|
||||
|
||||
export interface WorkspaceInviteLinkSnapshot {
|
||||
link: string;
|
||||
expireTime: string;
|
||||
}
|
||||
|
||||
export interface DocShareStateSnapshot {
|
||||
public: boolean;
|
||||
mode: PublicDocModeSnapshot;
|
||||
defaultRole: DocRoleSnapshot;
|
||||
}
|
||||
|
||||
export interface PaginationInput {
|
||||
first: number;
|
||||
offset?: number;
|
||||
after?: string;
|
||||
}
|
||||
|
||||
export interface DocGrantedUserSnapshot {
|
||||
role: DocRoleSnapshot;
|
||||
user: {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
avatarUrl: string | null;
|
||||
};
|
||||
}
|
||||
|
||||
export interface PaginatedDocGrantedUsersSnapshot {
|
||||
totalCount: number;
|
||||
pageInfo: {
|
||||
endCursor: string | null;
|
||||
hasNextPage: boolean;
|
||||
};
|
||||
edges: { node: DocGrantedUserSnapshot }[];
|
||||
}
|
||||
|
||||
export interface CurrentUserProfileSnapshot {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
emailVerified: boolean;
|
||||
hasPassword: boolean | null;
|
||||
avatarUrl: string | null;
|
||||
features?: string[];
|
||||
}
|
||||
|
||||
export interface UserSettingsSnapshot {
|
||||
receiveInvitationEmail: boolean;
|
||||
receiveMentionEmail: boolean;
|
||||
receiveCommentEmail: boolean;
|
||||
}
|
||||
|
||||
export interface AccessTokenSnapshot {
|
||||
id: string;
|
||||
name: string;
|
||||
createdAt: string;
|
||||
expiresAt: string | null;
|
||||
}
|
||||
|
||||
export type CommentChangeActionSnapshot = 'update' | 'delete';
|
||||
|
||||
export interface CommentChangeSnapshot {
|
||||
id: string;
|
||||
action: CommentChangeActionSnapshot;
|
||||
item: object;
|
||||
commentId: string | null;
|
||||
}
|
||||
|
||||
export interface UserQuotaStateSnapshot {
|
||||
userId: string;
|
||||
plan: string;
|
||||
@@ -101,6 +253,42 @@ export type WorkspaceEmbeddingProgressReason =
|
||||
| 'resync';
|
||||
|
||||
export interface RealtimeTopicMap {
|
||||
'workspace.access.changed': {
|
||||
input: { workspaceId: string };
|
||||
event: { changed: true; reason: string };
|
||||
};
|
||||
'workspace.config.changed': {
|
||||
input: { workspaceId: string };
|
||||
event: { changed: true; reason: string };
|
||||
};
|
||||
'workspace.members.changed': {
|
||||
input: { workspaceId: string };
|
||||
event: { changed: true; reason: string };
|
||||
};
|
||||
'workspace.invite-link.changed': {
|
||||
input: { workspaceId: string };
|
||||
event: { changed: true; reason: string };
|
||||
};
|
||||
'doc.share-state.changed': {
|
||||
input: { workspaceId: string; docId: string };
|
||||
event: { changed: true; reason: string };
|
||||
};
|
||||
'doc.grants.changed': {
|
||||
input: { workspaceId: string; docId: string };
|
||||
event: { changed: true; reason: string };
|
||||
};
|
||||
'user.profile.changed': {
|
||||
input: Record<string, never>;
|
||||
event: { changed: true; reason: string };
|
||||
};
|
||||
'user.settings.changed': {
|
||||
input: Record<string, never>;
|
||||
event: { changed: true; reason: string };
|
||||
};
|
||||
'user.access-tokens.changed': {
|
||||
input: Record<string, never>;
|
||||
event: { changed: true; reason: string };
|
||||
};
|
||||
'notification.count.changed': {
|
||||
input: Record<string, never>;
|
||||
event: {
|
||||
|
||||
Reference in New Issue
Block a user