mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-22 04:26:23 +08:00
feat(server): entitlement based model (#14996)
#### PR Dependency Tree * **PR #14996** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Admin mutations to grant/revoke commercial entitlements. * New Doc comment-update permission. * Realtime user/workspace quota-state endpoints and live-update rooms. * **Bug Fixes** * More accurate readable-doc filtering and permission evaluation. * **Refactor** * Workspace feature management moved to entitlement-based model; permission and quota pipelines redesigned. * Admin workspace UI now edits flags only (feature toggles removed). * **Tests** * Extensive new and updated tests for permissions, entitlements, quota, projection, and backfills. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/toeverything/AFFiNE/pull/14996?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -1,24 +1,24 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { ActionForbidden } from '../../../base';
|
||||
import { QuotaStateService } from '../../../core/quota/state';
|
||||
import { Models, WorkspaceRole } from '../../../models';
|
||||
|
||||
@Injectable()
|
||||
export class ByokEntitlementPolicy {
|
||||
constructor(private readonly models: Models) {}
|
||||
|
||||
private isUserPlanEntitled(features: string[]) {
|
||||
return (
|
||||
features.includes('pro_plan_v1') ||
|
||||
features.includes('lifetime_pro_plan_v1') ||
|
||||
features.includes('unlimited_copilot')
|
||||
);
|
||||
}
|
||||
constructor(
|
||||
private readonly models: Models,
|
||||
private readonly quotaState: QuotaStateService
|
||||
) {}
|
||||
|
||||
async hasAiPlan(userId?: string) {
|
||||
if (!userId) return false;
|
||||
const features = await this.models.userFeature.list(userId);
|
||||
return this.isUserPlanEntitled(features);
|
||||
const state = await this.quotaState.reconcileUserQuotaState(userId);
|
||||
const flags = state.flags as { unlimitedCopilot?: boolean };
|
||||
return (
|
||||
flags.unlimitedCopilot ||
|
||||
['pro', 'lifetime_pro', 'ai'].includes(state.plan)
|
||||
);
|
||||
}
|
||||
|
||||
async hasManagementAccess(workspaceId: string, userId?: string) {
|
||||
@@ -59,7 +59,7 @@ export class ByokEntitlementPolicy {
|
||||
async hasLocalEntitlement(workspaceId: string, userId?: string) {
|
||||
if (env.selfhosted) return true;
|
||||
|
||||
if (await this.models.workspaceFeature.has(workspaceId, 'team_plan_v1')) {
|
||||
if (await this.hasWorkspaceTeamPlan(workspaceId)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ export class ByokEntitlementPolicy {
|
||||
async hasServerEntitlement(workspaceId: string) {
|
||||
if (env.selfhosted) return true;
|
||||
|
||||
if (await this.models.workspaceFeature.has(workspaceId, 'team_plan_v1')) {
|
||||
if (await this.hasWorkspaceTeamPlan(workspaceId)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -102,4 +102,20 @@ export class ByokEntitlementPolicy {
|
||||
throw new ActionForbidden('BYOK requires Pro, Team, or Believer.');
|
||||
}
|
||||
}
|
||||
|
||||
private async hasWorkspaceTeamPlan(workspaceId: string) {
|
||||
try {
|
||||
const state =
|
||||
await this.quotaState.reconcileWorkspaceQuotaState(workspaceId);
|
||||
return ['team', 'selfhost_team'].includes(state.plan);
|
||||
} catch (error) {
|
||||
if (
|
||||
error instanceof Error &&
|
||||
error.message === 'Workspace owner not found'
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import { SafeIntResolver } from 'graphql-scalars';
|
||||
|
||||
import { Throttle } from '../../../base';
|
||||
import { CurrentUser } from '../../../core/auth';
|
||||
import { AccessController } from '../../../core/permission';
|
||||
import { PermissionAccess } from '../../../core/permission';
|
||||
import { WorkspaceType } from '../../../core/workspaces';
|
||||
import { ByokEntitlementPolicy } from './policy';
|
||||
import { ByokKeyConfig, ByokLocalLeaseProvider, ByokService } from './service';
|
||||
@@ -259,7 +259,7 @@ class CreateWorkspaceByokLocalLeaseInput {
|
||||
@Resolver(() => WorkspaceType)
|
||||
export class WorkspaceByokResolver {
|
||||
constructor(
|
||||
private readonly ac: AccessController,
|
||||
private readonly ac: PermissionAccess,
|
||||
private readonly entitlement: ByokEntitlementPolicy,
|
||||
private readonly byok: ByokService
|
||||
) {}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Injectable, OnModuleInit } from '@nestjs/common';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { OnEvent } from '../../../base';
|
||||
import { AccessController } from '../../../core/permission';
|
||||
import { PermissionAccess } from '../../../core/permission';
|
||||
import {
|
||||
RealtimePublisher,
|
||||
RealtimeRegistry,
|
||||
@@ -19,7 +19,7 @@ export function workspaceEmbeddingRoom(workspaceId: string) {
|
||||
@Injectable()
|
||||
export class CopilotEmbeddingRealtimeProvider implements OnModuleInit {
|
||||
constructor(
|
||||
private readonly ac: AccessController,
|
||||
private readonly ac: PermissionAccess,
|
||||
private readonly models: Models,
|
||||
private readonly context: CopilotContextService,
|
||||
private readonly registry: RealtimeRegistry,
|
||||
|
||||
@@ -37,10 +37,7 @@ import {
|
||||
UserFriendlyError,
|
||||
} from '../../../base';
|
||||
import { CurrentUser } from '../../../core/auth';
|
||||
import {
|
||||
AccessController,
|
||||
WorkspacePolicyService,
|
||||
} from '../../../core/permission';
|
||||
import { PermissionAccess } from '../../../core/permission';
|
||||
import {
|
||||
ContextBlob,
|
||||
ContextCategories,
|
||||
@@ -60,7 +57,7 @@ import { getSignal, MAX_EMBEDDABLE_SIZE, readStream } from '../utils';
|
||||
import { CopilotContextService } from './service';
|
||||
|
||||
async function assertAccess(
|
||||
ac: AccessController,
|
||||
ac: PermissionAccess,
|
||||
userId: string,
|
||||
workspaceId: string
|
||||
) {
|
||||
@@ -73,7 +70,7 @@ async function assertAccess(
|
||||
|
||||
async function getSession(
|
||||
context: CopilotContextService,
|
||||
ac: AccessController,
|
||||
ac: PermissionAccess,
|
||||
userId: string,
|
||||
contextId: string,
|
||||
options: { workspaceId?: string; sessionId?: string } = {}
|
||||
@@ -292,7 +289,7 @@ class ContextMatchedDocChunk implements DocChunkSimilarity {
|
||||
@Resolver(() => CopilotType)
|
||||
export class CopilotContextRootResolver {
|
||||
constructor(
|
||||
private readonly ac: AccessController,
|
||||
private readonly ac: PermissionAccess,
|
||||
private readonly event: EventBus,
|
||||
private readonly mutex: RequestMutex,
|
||||
private readonly chatSession: ChatSessionService,
|
||||
@@ -441,8 +438,7 @@ export class CopilotContextRootResolver {
|
||||
@Resolver(() => CopilotContextType)
|
||||
export class CopilotContextResolver {
|
||||
constructor(
|
||||
private readonly ac: AccessController,
|
||||
private readonly policy: WorkspacePolicyService,
|
||||
private readonly ac: PermissionAccess,
|
||||
private readonly models: Models,
|
||||
private readonly mutex: RequestMutex,
|
||||
private readonly context: CopilotContextService,
|
||||
@@ -745,7 +741,11 @@ export class CopilotContextResolver {
|
||||
const blobId = createHash('sha256').update(buffer).digest('base64url');
|
||||
const { filename, mimetype } = content;
|
||||
|
||||
await this.policy.assertCanUploadBlob(user.id, session.workspaceId);
|
||||
await this.ac
|
||||
.user(user.id)
|
||||
.workspace(session.workspaceId)
|
||||
.allowLocal()
|
||||
.assert('Workspace.Blobs.Write');
|
||||
await this.storage.put(user.id, session.workspaceId, blobId, buffer);
|
||||
const file = await session.addFile(
|
||||
blobId,
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
ImageFormatNotSupported,
|
||||
sniffMime,
|
||||
} from '../../../base';
|
||||
import { WorkspacePolicyService } from '../../../core/permission';
|
||||
import { PermissionAccess } from '../../../core/permission';
|
||||
import { processImage } from '../../../native';
|
||||
import { CompatSubmissionStore } from '../compat/submission-store';
|
||||
import type { PromptMessage } from '../providers/types';
|
||||
@@ -29,7 +29,7 @@ type CreateInboxMessage = {
|
||||
export class ConversationInboxService {
|
||||
constructor(
|
||||
private readonly chatSession: ChatSessionService,
|
||||
private readonly policy: WorkspacePolicyService,
|
||||
private readonly ac: PermissionAccess,
|
||||
private readonly storage: CopilotStorage,
|
||||
private readonly submissions: CompatSubmissionStore
|
||||
) {}
|
||||
@@ -49,7 +49,11 @@ export class ConversationInboxService {
|
||||
);
|
||||
|
||||
if (blobs.length) {
|
||||
await this.policy.assertCanUploadBlob(userId, session.config.workspaceId);
|
||||
await this.ac
|
||||
.user(userId)
|
||||
.workspace(session.config.workspaceId)
|
||||
.allowLocal()
|
||||
.assert('Workspace.Blobs.Write');
|
||||
}
|
||||
|
||||
for (const blob of blobs) {
|
||||
|
||||
@@ -14,16 +14,8 @@ export class ConversationPolicy {
|
||||
) {}
|
||||
|
||||
async getQuota(userId: string) {
|
||||
const isCopilotUser = await this.models.userFeature.has(
|
||||
userId,
|
||||
'unlimited_copilot'
|
||||
);
|
||||
|
||||
let limit: number | undefined;
|
||||
if (!isCopilotUser) {
|
||||
const quota = await this.quota.getUserQuota(userId);
|
||||
limit = quota.copilotActionLimit;
|
||||
}
|
||||
const quota = await this.quota.getUserQuota(userId);
|
||||
const limit = quota.copilotActionLimit;
|
||||
|
||||
const used = await this.models.copilotSession.countUserMessages(userId);
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { pick } from 'lodash-es';
|
||||
import z from 'zod/v3';
|
||||
|
||||
import { DocReader, DocWriter } from '../../../core/doc';
|
||||
import { AccessController } from '../../../core/permission';
|
||||
import { PermissionAccess } from '../../../core/permission';
|
||||
import { clearEmbeddingChunk } from '../../../models';
|
||||
import { IndexerService } from '../../indexer';
|
||||
import { CopilotContextService } from '../context/service';
|
||||
@@ -99,7 +99,7 @@ function defineTool<T extends z.ZodTypeAny>(
|
||||
@Injectable()
|
||||
export class WorkspaceMcpProvider {
|
||||
constructor(
|
||||
private readonly ac: AccessController,
|
||||
private readonly ac: PermissionAccess,
|
||||
private readonly reader: DocReader,
|
||||
private readonly writer: DocWriter,
|
||||
private readonly context: CopilotContextService,
|
||||
|
||||
@@ -28,7 +28,7 @@ import {
|
||||
TooManyRequest,
|
||||
} from '../../base';
|
||||
import { CurrentUser } from '../../core/auth';
|
||||
import { AccessController, DocAction } from '../../core/permission';
|
||||
import { DocAction, PermissionAccess } from '../../core/permission';
|
||||
import { UserType } from '../../core/user';
|
||||
import type { ListSessionOptions, UpdateChatSession } from '../../models';
|
||||
import { CompatHistoryProjector } from './compat/history-projector';
|
||||
@@ -365,7 +365,7 @@ export class CopilotResolver {
|
||||
private readonly modelNames = new Map<string, string>();
|
||||
|
||||
constructor(
|
||||
private readonly ac: AccessController,
|
||||
private readonly ac: PermissionAccess,
|
||||
private readonly mutex: RequestMutex,
|
||||
private readonly prompt: PromptService,
|
||||
private readonly chatSession: ChatSessionService,
|
||||
@@ -815,7 +815,7 @@ export class CopilotResolver {
|
||||
@Throttle()
|
||||
@Resolver(() => UserType)
|
||||
export class UserCopilotResolver {
|
||||
constructor(private readonly ac: AccessController) {}
|
||||
constructor(private readonly ac: PermissionAccess) {}
|
||||
|
||||
@ResolveField(() => CopilotType)
|
||||
async copilot(
|
||||
|
||||
+9
-11
@@ -2,8 +2,7 @@ import { Injectable } from '@nestjs/common';
|
||||
import { ModuleRef } from '@nestjs/core';
|
||||
|
||||
import { ServerFeature, ServerService } from '../../../../core';
|
||||
import { SubscriptionService } from '../../../payment/service';
|
||||
import { SubscriptionPlan, SubscriptionStatus } from '../../../payment/types';
|
||||
import { QuotaStateService } from '../../../../core/quota/state';
|
||||
import type { ChatSession } from '../../session';
|
||||
import { type ToolsConfig } from '../../types';
|
||||
import { getTools } from '../../utils';
|
||||
@@ -47,15 +46,14 @@ export class CapabilityPolicyHost {
|
||||
}
|
||||
|
||||
try {
|
||||
const subscription = await this.moduleRef
|
||||
.get(SubscriptionService, { strict: false })
|
||||
.select(SubscriptionPlan.AI)
|
||||
.getSubscription({
|
||||
userId,
|
||||
plan: SubscriptionPlan.AI,
|
||||
} as never);
|
||||
|
||||
return subscription?.status === SubscriptionStatus.Active;
|
||||
const state = await this.moduleRef
|
||||
.get(QuotaStateService, { strict: false })
|
||||
.reconcileUserQuotaState(userId);
|
||||
const flags = state.flags as { unlimitedCopilot?: boolean };
|
||||
return (
|
||||
!!flags.unlimitedCopilot ||
|
||||
['pro', 'lifetime_pro', 'ai'].includes(state.plan)
|
||||
);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { Models } from '../../../models';
|
||||
import { QuotaStateService } from '../../../core/quota/state';
|
||||
import { PromptService } from '../prompt/service';
|
||||
|
||||
export const DEFAULT_EMBEDDING_MODEL = 'gemini-embedding-001';
|
||||
@@ -9,7 +9,7 @@ export const DEFAULT_RERANK_MODEL = 'gpt-4o-mini';
|
||||
@Injectable()
|
||||
export class TaskPolicy {
|
||||
constructor(
|
||||
private readonly models: Models,
|
||||
private readonly quotaState: QuotaStateService,
|
||||
private readonly prompts: PromptService
|
||||
) {}
|
||||
|
||||
@@ -25,10 +25,11 @@ export class TaskPolicy {
|
||||
const prompt = await this.prompts.get('Transcript audio');
|
||||
if (!prompt) return;
|
||||
|
||||
const hasAccess = await this.models.userFeature.has(
|
||||
userId,
|
||||
'unlimited_copilot'
|
||||
);
|
||||
const state = await this.quotaState.reconcileUserQuotaState(userId);
|
||||
const flags = state.flags as { unlimitedCopilot?: boolean };
|
||||
const hasAccess =
|
||||
!!flags.unlimitedCopilot ||
|
||||
['pro', 'lifetime_pro', 'ai'].includes(state.plan);
|
||||
return prompt.optionalModels[hasAccess ? 1 : 0] ?? prompt.model;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { Config } from '../../../base';
|
||||
import { DocReader, DocWriter } from '../../../core/doc';
|
||||
import { AccessController } from '../../../core/permission';
|
||||
import { PermissionAccess } from '../../../core/permission';
|
||||
import { Models } from '../../../models';
|
||||
import { IndexerService } from '../../indexer';
|
||||
import type { NodeTextMiddleware } from '../config';
|
||||
@@ -48,7 +48,7 @@ export type ProviderSpecificToolResolver = (
|
||||
export class ToolRuntime {
|
||||
constructor(
|
||||
private readonly config: Config,
|
||||
private readonly ac: AccessController,
|
||||
private readonly ac: PermissionAccess,
|
||||
private readonly context: CopilotContextService,
|
||||
private readonly docReader: DocReader,
|
||||
private readonly docWriter: DocWriter,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { AccessController } from '../../../core/permission';
|
||||
import { PermissionAccess } from '../../../core/permission';
|
||||
import { toolError } from './error';
|
||||
import { defineTool } from './tool';
|
||||
import type { ContextSession, CopilotChatOptions } from './types';
|
||||
@@ -9,7 +9,7 @@ import type { ContextSession, CopilotChatOptions } from './types';
|
||||
const logger = new Logger('ContextBlobReadTool');
|
||||
|
||||
export const buildBlobContentGetter = (
|
||||
ac: AccessController,
|
||||
ac: PermissionAccess,
|
||||
context: ContextSession | null
|
||||
) => {
|
||||
const getBlobContent = async (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import type { AccessController } from '../../../core/permission';
|
||||
import type { PermissionAccess } from '../../../core/permission';
|
||||
import type { Models } from '../../../models';
|
||||
import type { IndexerService, SearchDoc } from '../../indexer';
|
||||
import { workspaceSyncRequiredError } from './doc-sync';
|
||||
@@ -9,7 +9,7 @@ import { defineTool } from './tool';
|
||||
import type { CopilotChatOptions } from './types';
|
||||
|
||||
export const buildDocKeywordSearchGetter = (
|
||||
ac: AccessController,
|
||||
ac: PermissionAccess,
|
||||
indexerService: IndexerService,
|
||||
models: Models
|
||||
) => {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Logger } from '@nestjs/common';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { DocReader } from '../../../core/doc';
|
||||
import { AccessController } from '../../../core/permission';
|
||||
import { PermissionAccess } from '../../../core/permission';
|
||||
import { Models } from '../../../models';
|
||||
import {
|
||||
documentSyncPendingError,
|
||||
@@ -18,7 +18,7 @@ const isToolError = (result: ToolError | object): result is ToolError =>
|
||||
'type' in result && result.type === 'error';
|
||||
|
||||
export const buildDocContentGetter = (
|
||||
ac: AccessController,
|
||||
ac: PermissionAccess,
|
||||
docReader: DocReader,
|
||||
models: Models
|
||||
) => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { omit } from 'lodash-es';
|
||||
import { z } from 'zod';
|
||||
|
||||
import type { AccessController } from '../../../core/permission';
|
||||
import type { PermissionAccess } from '../../../core/permission';
|
||||
import {
|
||||
type ChunkSimilarity,
|
||||
clearEmbeddingChunk,
|
||||
@@ -19,7 +19,7 @@ const getEmbeddingRouteContext = (options: CopilotChatOptions) => ({
|
||||
});
|
||||
|
||||
export const buildDocSearchGetter = (
|
||||
ac: AccessController,
|
||||
ac: PermissionAccess,
|
||||
context: CopilotContextService,
|
||||
sessionId: string | undefined,
|
||||
models: Models
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Logger } from '@nestjs/common';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { DocWriter } from '../../../core/doc';
|
||||
import { AccessController } from '../../../core/permission';
|
||||
import { PermissionAccess } from '../../../core/permission';
|
||||
import { toolError } from './error';
|
||||
import { defineTool } from './tool';
|
||||
import type { CopilotChatOptions } from './types';
|
||||
@@ -15,7 +15,7 @@ const stripLeadingH1 = (content: string) =>
|
||||
const sanitizeTitle = (title: string) => title.replace(/[\r\n]+/g, ' ').trim();
|
||||
|
||||
export const buildDocCreateHandler = (
|
||||
ac: AccessController,
|
||||
ac: PermissionAccess,
|
||||
writer: DocWriter
|
||||
) => {
|
||||
return async (
|
||||
@@ -57,7 +57,7 @@ export const buildDocCreateHandler = (
|
||||
};
|
||||
|
||||
export const buildDocUpdateHandler = (
|
||||
ac: AccessController,
|
||||
ac: PermissionAccess,
|
||||
writer: DocWriter
|
||||
) => {
|
||||
return async (
|
||||
@@ -95,7 +95,7 @@ export const buildDocUpdateHandler = (
|
||||
};
|
||||
|
||||
export const buildDocUpdateMetaHandler = (
|
||||
ac: AccessController,
|
||||
ac: PermissionAccess,
|
||||
writer: DocWriter
|
||||
) => {
|
||||
return async (options: CopilotChatOptions, docId: string, title: string) => {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Injectable, OnModuleInit } from '@nestjs/common';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { CopilotTranscriptionJobNotFound } from '../../../base';
|
||||
import { AccessController } from '../../../core/permission';
|
||||
import { PermissionAccess } from '../../../core/permission';
|
||||
import {
|
||||
RealtimeRegistry,
|
||||
realtimeTranscriptTaskRoom,
|
||||
@@ -13,7 +13,7 @@ import { CopilotTranscriptionReader } from './reader';
|
||||
@Injectable()
|
||||
export class CopilotTranscriptRealtimeProvider implements OnModuleInit {
|
||||
constructor(
|
||||
private readonly ac: AccessController,
|
||||
private readonly ac: PermissionAccess,
|
||||
private readonly transcript: CopilotTranscriptionReader,
|
||||
private readonly registry: RealtimeRegistry
|
||||
) {}
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
type FileUpload,
|
||||
} from '../../../base';
|
||||
import { CurrentUser } from '../../../core/auth';
|
||||
import { AccessController } from '../../../core/permission';
|
||||
import { PermissionAccess } from '../../../core/permission';
|
||||
import { CopilotType } from '../resolver';
|
||||
import type { TranscriptionJob } from './job';
|
||||
import { buildLegacyProjection } from './projection';
|
||||
@@ -295,7 +295,7 @@ const FinishedStatus: Set<AiJobStatus> = new Set([
|
||||
@Resolver(() => CopilotType)
|
||||
export class CopilotTranscriptionResolver {
|
||||
constructor(
|
||||
private readonly ac: AccessController,
|
||||
private readonly ac: PermissionAccess,
|
||||
private readonly transcript: CopilotTranscriptionService
|
||||
) {}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
UserFriendlyError,
|
||||
} from '../../../base';
|
||||
import { CurrentUser } from '../../../core/auth';
|
||||
import { AccessController } from '../../../core/permission';
|
||||
import { PermissionAccess } from '../../../core/permission';
|
||||
import { WorkspaceType } from '../../../core/workspaces';
|
||||
import { COPILOT_LOCKER } from '../resolver';
|
||||
import { MAX_EMBEDDABLE_SIZE } from '../utils';
|
||||
@@ -49,7 +49,7 @@ export class CopilotWorkspaceConfigType {
|
||||
*/
|
||||
@Resolver(() => WorkspaceType)
|
||||
export class CopilotWorkspaceEmbeddingResolver {
|
||||
constructor(private readonly ac: AccessController) {}
|
||||
constructor(private readonly ac: PermissionAccess) {}
|
||||
|
||||
@ResolveField(() => CopilotWorkspaceConfigType, {
|
||||
complexity: 2,
|
||||
@@ -70,7 +70,7 @@ export class CopilotWorkspaceEmbeddingResolver {
|
||||
@Resolver(() => CopilotWorkspaceConfigType)
|
||||
export class CopilotWorkspaceEmbeddingConfigResolver {
|
||||
constructor(
|
||||
private readonly ac: AccessController,
|
||||
private readonly ac: PermissionAccess,
|
||||
private readonly mutex: Mutex,
|
||||
private readonly copilotWorkspace: CopilotWorkspaceService
|
||||
) {}
|
||||
|
||||
Reference in New Issue
Block a user