1895 extensibility v1 application tokens (#16365)

First PR to implement application tokens
- add new application role in twenty-server
- move duplicated constants and types to twenty-shared
- will  add role configuration utils into twenty-sdk in another PR
This commit is contained in:
martmull
2025-12-08 10:42:46 +01:00
committed by GitHub
parent 1f9a6b067a
commit 7f1e69740a
188 changed files with 977 additions and 457 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "create-twenty-app",
"version": "0.1.3",
"version": "0.2.0",
"description": "Command-line interface to create Twenty application",
"main": "dist/cli.cjs",
"bin": "dist/cli.cjs",
@@ -127,7 +127,7 @@ const createPackageJson = async ({
auth: 'twenty auth login',
},
dependencies: {
'twenty-sdk': '0.1.3',
'twenty-sdk': '0.2.0',
},
devDependencies: {
'@types/node': '^24.7.2',
@@ -904,6 +904,7 @@ export type CreateRoleInput = {
canAccessAllTools?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToAgents?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToApiKeys?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToApplications?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToUsers?: InputMaybe<Scalars['Boolean']>;
canDestroyAllObjectRecords?: InputMaybe<Scalars['Boolean']>;
canReadAllObjectRecords?: InputMaybe<Scalars['Boolean']>;
@@ -3794,6 +3795,7 @@ export type Role = {
objectPermissions?: Maybe<Array<ObjectPermission>>;
permissionFlags?: Maybe<Array<PermissionFlag>>;
standardId?: Maybe<Scalars['UUID']>;
universalIdentifier?: Maybe<Scalars['UUID']>;
workspaceMembers: Array<WorkspaceMember>;
};
@@ -4358,6 +4360,7 @@ export type UpdateRolePayload = {
canAccessAllTools?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToAgents?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToApiKeys?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToApplications?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToUsers?: InputMaybe<Scalars['Boolean']>;
canDestroyAllObjectRecords?: InputMaybe<Scalars['Boolean']>;
canReadAllObjectRecords?: InputMaybe<Scalars['Boolean']>;
@@ -887,6 +887,7 @@ export type CreateRoleInput = {
canAccessAllTools?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToAgents?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToApiKeys?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToApplications?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToUsers?: InputMaybe<Scalars['Boolean']>;
canDestroyAllObjectRecords?: InputMaybe<Scalars['Boolean']>;
canReadAllObjectRecords?: InputMaybe<Scalars['Boolean']>;
@@ -3631,6 +3632,7 @@ export type Role = {
objectPermissions?: Maybe<Array<ObjectPermission>>;
permissionFlags?: Maybe<Array<PermissionFlag>>;
standardId?: Maybe<Scalars['UUID']>;
universalIdentifier?: Maybe<Scalars['UUID']>;
workspaceMembers: Array<WorkspaceMember>;
};
@@ -4187,6 +4189,7 @@ export type UpdateRolePayload = {
canAccessAllTools?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToAgents?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToApiKeys?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToApplications?: InputMaybe<Scalars['Boolean']>;
canBeAssignedToUsers?: InputMaybe<Scalars['Boolean']>;
canDestroyAllObjectRecords?: InputMaybe<Scalars['Boolean']>;
canReadAllObjectRecords?: InputMaybe<Scalars['Boolean']>;
@@ -1,6 +1,7 @@
// IA Generated
import { type Sources } from '@/serverless-functions/types/sources.type';
import { flattenSources } from '@/serverless-functions/utils/flattenSources';
import { type Sources } from 'twenty-shared/types';
describe('flattenSources', () => {
it('flattens nested sources with root files', () => {
@@ -1,4 +1,4 @@
import { type Sources } from '@/serverless-functions/types/sources.type';
import { type Sources } from 'twenty-shared/types';
export const computeNewSources = ({
previousCode,
@@ -1,5 +1,5 @@
// IA Generated
import { type Sources } from '@/serverless-functions/types/sources.type';
import { type Sources } from 'twenty-shared/types';
type FlatSource = { path: string; content: string };
@@ -6,7 +6,7 @@ import { type Dispatch, type SetStateAction, useState } from 'react';
import { useRecoilState } from 'recoil';
import { type FindOneServerlessFunctionSourceCodeQuery } from '~/generated-metadata/graphql';
import { type ServerlessFunction } from '~/generated/graphql';
import { type Sources } from '@/serverless-functions/types/sources.type';
import { type Sources } from 'twenty-shared/types';
import { flattenSources } from '@/serverless-functions/utils/flattenSources';
import { isDefined } from 'twenty-shared/utils';
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "twenty-sdk",
"version": "0.1.3",
"version": "0.2.0",
"main": "dist/index.cjs",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
+1
View File
@@ -42,6 +42,7 @@
"command": "tsx {projectRoot}/scripts/generateBarrels.ts"
}
},
"typecheck": {},
"lint": {
"options": {
"lintFilePatterns": [
@@ -1,4 +1,4 @@
import { type SyncableEntityOptions } from './syncable-entity-options.type';
import { type SyncableEntityOptions } from '@/application/syncable-entity-options.type';
type ApplicationVariable = SyncableEntityOptions & {
value?: string;
@@ -1,4 +1,4 @@
import { type SyncableEntityOptions } from '../syncable-entity-options.type';
import { type SyncableEntityOptions } from '@/application/syncable-entity-options.type';
import {
type FieldMetadataType,
@@ -1,4 +1,4 @@
import { type SyncableEntityOptions } from '../syncable-entity-options.type';
import { type SyncableEntityOptions } from '@/application/syncable-entity-options.type';
import {
type RelationOnDeleteAction,
@@ -1,4 +1,4 @@
import { type SyncableEntityOptions } from './syncable-entity-options.type';
import { type SyncableEntityOptions } from '@/application/syncable-entity-options.type';
type RouteTrigger = {
type: 'route';
+8 -8
View File
@@ -17,13 +17,13 @@ export type {
LinksField,
PhonesField,
RichTextField,
} from './field-metadata/composite-fields';
export { FieldType } from './field-metadata/field-type';
export { Field } from './field-metadata/field.decorator';
export { OnDeleteAction } from './field-metadata/on-delete-action';
export { RelationType } from './field-metadata/relation-type';
export { Relation } from './field-metadata/relation.decorator';
} from './fields/composite-fields';
export { FieldType } from './fields/field-type';
export { Field } from './fields/field.decorator';
export { OnDeleteAction } from './fields/on-delete-action';
export { RelationType } from './fields/relation-type';
export { Relation } from './fields/relation.decorator';
export type { FunctionConfig } from './function-config';
export { Object } from './object-metadata/object.decorator';
export { STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from './object-metadata/standard-object-ids';
export { Object } from './objects/object.decorator';
export { STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from './objects/standard-object-ids';
export type { SyncableEntityOptions } from './syncable-entity-options.type';
@@ -1,4 +1,4 @@
import { type SyncableEntityOptions } from '../syncable-entity-options.type';
import { type SyncableEntityOptions } from '@/application/syncable-entity-options.type';
type ObjectMetadataOptions = SyncableEntityOptions & {
nameSingular: string;
@@ -1,8 +1,8 @@
import { existsSync } from 'fs';
import { AppSyncCommand } from '../../commands/app-sync.command';
import { AppUninstallCommand } from '../../commands/app-uninstall.command';
import { COVERED_APPLICATION_FOLDERS } from './constants/covered-applications-folder.constant';
import { getTestedApplicationPath } from './utils/get-tested-application-path.util';
import { AppSyncCommand } from '@/cli/commands/app-sync.command';
import { AppUninstallCommand } from '@/cli/commands/app-uninstall.command';
import { COVERED_APPLICATION_FOLDERS } from '@/cli/__tests__/e2e/constants/covered-applications-folder.constant';
import { getTestedApplicationPath } from '@/cli/__tests__/e2e/utils/get-tested-application-path.util';
describe.each(COVERED_APPLICATION_FOLDERS)(
'Application: "%s" install delete and reinstall test suite',
@@ -1,4 +1,4 @@
import { type TwentyConfig } from '../../../types/config.types';
import { type TwentyConfig } from '@/cli/services/config.service';
export const testConfig: TwentyConfig = {
apiUrl: 'http://localhost:3000',
@@ -1,5 +1,5 @@
import axios from 'axios';
import { SERVER_URL } from './constants/server-url.constant';
import { SERVER_URL } from '@/cli/__tests__/e2e/constants/server-url.constant';
describe('Twenty Server Health Check (E2E)', () => {
const HEALTH_ENDPOINT = `${SERVER_URL}/healthz`;
@@ -1,5 +1,5 @@
import { ConfigService } from '../../services/config.service';
import { testConfig } from './constants/testConfig';
import { ConfigService } from '@/cli/services/config.service';
import { testConfig } from '@/cli/__tests__/e2e/constants/testConfig';
beforeAll(() => {
jest
+3 -3
View File
@@ -1,9 +1,9 @@
#!/usr/bin/env node
import chalk from 'chalk';
import { Command, CommanderError } from 'commander';
import { AppCommand } from './commands/app.command';
import { AuthCommand } from './commands/auth.command';
import { ConfigService } from './services/config.service';
import { AppCommand } from '@/cli/commands/app.command';
import { AuthCommand } from '@/cli/commands/auth.command';
import { ConfigService } from '@/cli/services/config.service';
import packageJson from '../../package.json';
const program = new Command();
@@ -3,10 +3,10 @@ import * as fs from 'fs-extra';
import inquirer from 'inquirer';
import { join } from 'path';
import camelcase from 'lodash.camelcase';
import { CURRENT_EXECUTION_DIRECTORY } from '../constants/current-execution-directory';
import { getObjectDecoratedClass } from '../utils/get-object-decorated-class';
import { getFunctionBaseFile } from '../utils/get-function-base-file';
import { convertToLabel } from '../utils/convert-to-label';
import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/constants/current-execution-directory';
import { getObjectDecoratedClass } from '@/cli/utils/get-object-decorated-class';
import { getFunctionBaseFile } from '@/cli/utils/get-function-base-file';
import { convertToLabel } from '@/cli/utils/convert-to-label';
export enum SyncableEntity {
AGENT = 'agent',
@@ -1,6 +1,6 @@
import chalk from 'chalk';
import * as chokidar from 'chokidar';
import { CURRENT_EXECUTION_DIRECTORY } from '../constants/current-execution-directory';
import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/constants/current-execution-directory';
import { ApiService } from '@/cli/services/api.service';
import { loadManifest } from '@/cli/utils/load-manifest';
@@ -1,6 +1,6 @@
import chalk from 'chalk';
import { GenerateService } from '../services/generate.service';
import { CURRENT_EXECUTION_DIRECTORY } from '../constants/current-execution-directory';
import { GenerateService } from '@/cli/services/generate.service';
import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/constants/current-execution-directory';
export class AppGenerateCommand {
private generateService = new GenerateService();
@@ -1,9 +1,9 @@
import chalk from 'chalk';
import { CURRENT_EXECUTION_DIRECTORY } from '../constants/current-execution-directory';
import { ApiService } from '../services/api.service';
import { GenerateService } from '../services/generate.service';
import { type ApiResponse } from '../types/config.types';
import { loadManifest } from '../utils/load-manifest';
import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/constants/current-execution-directory';
import { ApiService } from '@/cli/services/api.service';
import { GenerateService } from '@/cli/services/generate.service';
import { type ApiResponse } from '@/cli/types/api-response.types';
import { loadManifest } from '@/cli/utils/load-manifest';
export class AppSyncCommand {
private apiService = new ApiService();
@@ -1,9 +1,9 @@
import chalk from 'chalk';
import inquirer from 'inquirer';
import { CURRENT_EXECUTION_DIRECTORY } from '../constants/current-execution-directory';
import { ApiService } from '../services/api.service';
import { type ApiResponse } from '../types/config.types';
import { loadManifest } from '../utils/load-manifest';
import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/constants/current-execution-directory';
import { ApiService } from '@/cli/services/api.service';
import { type ApiResponse } from '@/cli/types/api-response.types';
import { loadManifest } from '@/cli/utils/load-manifest';
export class AppUninstallCommand {
private apiService = new ApiService();
@@ -5,11 +5,11 @@ import {
isSyncableEntity,
SyncableEntity,
} from './app-add.command';
import { AppUninstallCommand } from './app-uninstall.command';
import { AppDevCommand } from './app-dev.command';
import { AppSyncCommand } from './app-sync.command';
import { formatPath } from '../utils/format-path';
import { AppGenerateCommand } from './app-generate.command';
import { AppUninstallCommand } from '@/cli/commands/app-uninstall.command';
import { AppDevCommand } from '@/cli/commands/app-dev.command';
import { AppSyncCommand } from '@/cli/commands/app-sync.command';
import { formatPath } from '@/cli/utils/format-path';
import { AppGenerateCommand } from '@/cli/commands/app-generate.command';
import { AppLogsCommand } from '@/cli/commands/app-logs.command';
export class AppCommand {
@@ -1,8 +1,8 @@
import chalk from 'chalk';
import { Command } from 'commander';
import inquirer from 'inquirer';
import { ApiService } from '../services/api.service';
import { ConfigService } from '../services/config.service';
import { ApiService } from '@/cli/services/api.service';
import { ConfigService } from '@/cli/services/config.service';
export class AuthCommand {
private configService = new ConfigService();
@@ -6,12 +6,12 @@ import {
printSchema,
} from 'graphql/index';
import { createClient } from 'graphql-sse';
import { type ApiResponse } from '@/cli/types/api-response.types';
import { ConfigService } from '@/cli/services/config.service';
import {
type ApiResponse,
type AppManifest,
type PackageJson,
} from '../types/config.types';
import { ConfigService } from './config.service';
type ApplicationManifest,
} from 'twenty-shared/application';
export class ApiService {
private client: AxiosInstance;
@@ -94,7 +94,7 @@ export class ApiService {
}: {
packageJson: PackageJson;
yarnLock: string;
manifest: AppManifest;
manifest: ApplicationManifest;
}): Promise<ApiResponse> {
try {
const mutation = `
@@ -1,7 +1,11 @@
import * as fs from 'fs-extra';
import * as os from 'os';
import * as path from 'path';
import { type TwentyConfig } from '../types/config.types';
export type TwentyConfig = {
apiUrl: string;
apiKey?: string;
};
type PersistedConfig = TwentyConfig & {
profiles?: Record<string, TwentyConfig>;
@@ -1,8 +1,8 @@
import { generate } from '@genql/cli';
import chalk from 'chalk';
import { join, resolve } from 'path';
import { ApiService } from './api.service';
import { ConfigService } from './config.service';
import { ApiService } from '@/cli/services/api.service';
import { ConfigService } from '@/cli/services/config.service';
export const GENERATED_FOLDER_NAME = 'generated';
@@ -0,0 +1,13 @@
type SuccessfulApiResponse<T = unknown> = {
success: true;
data: T;
message?: string;
};
type FailingApiResponse = {
success: false;
error?: unknown;
message?: string;
};
export type ApiResponse<T = unknown> =
| SuccessfulApiResponse<T>
| FailingApiResponse;
@@ -1,111 +0,0 @@
export interface TwentyConfig {
apiUrl: string;
apiKey?: string;
}
export type PackageJson = {
name: string;
license: string;
engines: {
node: string;
npm: string;
yarn: string;
};
packageManager: string;
version: string;
dependencies?: object;
devDependencies?: object;
};
type ApplicationVariable = {
universalIdentifier: string;
value?: string;
description?: string;
isSecret?: boolean;
};
export type Application = {
universalIdentifier: string;
displayName?: string;
description?: string;
icon?: string;
applicationVariables?: Record<string, ApplicationVariable>;
};
export type AppManifest = {
application: Application;
objects: ObjectManifest[];
serverlessFunctions: ServerlessFunctionManifest[];
sources: Sources;
};
export type ServerlessFunctionManifest = {
universalIdentifier: string;
name?: string;
description?: string;
timeoutSeconds?: number;
triggers: ServerlessFunctionTriggerManifest[];
handlerPath: string;
handlerName: string;
};
export type DatabaseEventTrigger = {
type: 'databaseEvent';
eventName: string;
};
export type CronTrigger = {
type: 'cron';
pattern: string;
};
export type RouteTrigger = {
type: 'route';
path: string;
httpMethod: string;
isAuthRequired: boolean;
};
export type ServerlessFunctionTriggerManifest = {
universalIdentifier: string;
} & (CronTrigger | DatabaseEventTrigger | RouteTrigger);
export type Sources = { [key: string]: string | Sources };
export type FieldMetadata = {
universalIdentifier: string;
type: string;
label: string;
description?: string;
icon?: string;
defaultValue?: any;
options?: any;
settings?: any;
isNullable?: boolean;
isFieldUiReadOnly?: boolean;
};
export type ObjectManifest = {
universalIdentifier: string;
nameSingular: string;
namePlural: string;
labelSingular: string;
labelPlural: string;
description?: string;
icon?: string;
fields: FieldMetadata[];
};
export type SuccessfulApiResponse<T = unknown> = {
success: true;
data: T;
message?: string;
};
export type FailingApiResponse = {
success: false;
error?: unknown;
message?: string;
};
export type ApiResponse<T = unknown> =
| SuccessfulApiResponse<T>
| FailingApiResponse;
@@ -1,4 +1,4 @@
import { convertToLabel } from '../convert-to-label';
import { convertToLabel } from '@/cli/utils/convert-to-label';
describe('convertToLabel', () => {
it('should convert to label', () => {
@@ -1,4 +1,4 @@
import { getFunctionBaseFile } from '../get-function-base-file';
import { getFunctionBaseFile } from '@/cli/utils/get-function-base-file';
describe('getFunctionBaseFile', () => {
it('should render proper file', () => {
@@ -1,4 +1,4 @@
import { getObjectDecoratedClass } from '../get-object-decorated-class';
import { getObjectDecoratedClass } from '@/cli/utils/get-object-decorated-class';
describe('getObjectDecoratedClass', () => {
it('should return proper object file', () => {
@@ -1,7 +1,7 @@
import { ensureDirSync, writeFileSync, removeSync } from 'fs-extra';
import { tmpdir } from 'node:os';
import { join, resolve } from 'node:path';
import { loadManifest } from '../load-manifest';
import { loadManifest } from '@/cli/utils/load-manifest';
import { v4 } from 'uuid';
const write = (root: string, file: string, content: string) => {
@@ -74,13 +74,13 @@ declare module 'twenty-sdk' {
icon?: string;
};
export const ObjectMetadata = (_: ObjectMetadataOptions): ClassDecorator => {
export const Object = (_: ObjectMetadataOptions): ClassDecorator => {
return () => {};
};
export class BaseObjectMetadata {}
export enum FieldMetadataType {
export enum FieldType {
TEXT = 'TEXT',
FULL_NAME = 'FULL_NAME',
ADDRESS = 'ADDRESS',
@@ -88,7 +88,7 @@ declare module 'twenty-sdk' {
DATE_TIME = 'DATE_TIME',
}
export const FieldMetadata: (_: any) => PropertyDecorator;
export const Field: (_: any) => PropertyDecorator;
}
`;
@@ -125,10 +125,9 @@ export const config: FunctionConfig = {
};`;
const objectMock = `import {
ObjectMetadata,
BaseObjectMetadata,
FieldMetadata,
FieldMetadataType
Object,
Field,
FieldType
} from 'twenty-sdk';
enum PostCardStatus {
@@ -138,7 +137,7 @@ enum PostCardStatus {
RETURNED = 'RETURNED',
}
@ObjectMetadata({
@Object({
universalIdentifier: '54b589ca-eeed-4950-a176-358418b85c05',
nameSingular: 'postCard',
namePlural: 'postCards',
@@ -147,32 +146,32 @@ enum PostCardStatus {
description: ' A post card object',
icon: 'IconMail',
})
export class PostCard extends BaseObjectMetadata {
@FieldMetadata({
export class PostCard {
@Field({
universalIdentifier: '58a0a314-d7ea-4865-9850-7fb84e72f30b',
type: FieldMetadataType.TEXT,
type: FieldType.TEXT,
label: 'Content',
description: "Postcard's content",
})
content: string;
@FieldMetadata({
@Field({
universalIdentifier: 'c6aa31f3-da76-4ac6-889f-475e226009ac',
type: FieldMetadataType.FULL_NAME,
type: FieldType.FULL_NAME,
label: 'Recipient name',
})
recipientName: string;
@FieldMetadata({
@Field({
universalIdentifier: '95045777-a0ad-49ec-98f9-22f9fc0c8266',
type: FieldMetadataType.ADDRESS,
type: FieldType.ADDRESS,
label: 'Recipient address',
})
recipientAddress: string;
@FieldMetadata({
@Field({
universalIdentifier: '87b675b8-dd8c-4448-b4ca-20e5a2234a1e',
type: FieldMetadataType.SELECT,
type: FieldType.SELECT,
label: 'Status',
defaultValue: \`'\${PostCardStatus.DRAFT}'\`,
options: [
@@ -204,9 +203,9 @@ export class PostCard extends BaseObjectMetadata {
})
status: 'draft' | 'sent' | 'delivered' | 'returned';
@FieldMetadata({
@Field({
universalIdentifier: 'e06abe72-5b44-4e7f-93be-afc185a3c433',
type: FieldMetadataType.DATE_TIME,
type: FieldType.DATE_TIME,
label: 'Delivered at',
isNullable: true,
defaultValue: null,
@@ -1,5 +1,5 @@
import { join } from 'path';
import { CURRENT_EXECUTION_DIRECTORY } from '../constants/current-execution-directory';
import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/constants/current-execution-directory';
export const formatPath = (appPath?: string) => {
return appPath && !appPath?.startsWith('/')
@@ -1,6 +1,6 @@
import * as fs from 'fs-extra';
import dotenv from 'dotenv';
import { findPathFile } from './find-path-file';
import { findPathFile } from '@/cli/utils/find-path-file';
export const loadEnvVariables = async (appPath: string) => {
let envFile = '';
@@ -32,20 +32,20 @@ import {
isTemplateExpression,
isVariableStatement,
} from 'typescript';
import { GENERATED_FOLDER_NAME } from '../services/generate.service';
import { GENERATED_FOLDER_NAME } from '@/cli/services/generate.service';
import { type Sources } from 'twenty-shared/types';
import {
type AppManifest,
type Application,
type FieldMetadata,
type ObjectManifest,
type PackageJson,
type ApplicationManifest,
type ServerlessFunctionManifest,
type Sources,
} from '../types/config.types';
import { findPathFile } from '../utils/find-path-file';
import { getTsProgramAndDiagnostics } from '../utils/get-ts-program-and-diagnostics';
import { parseJsoncFile, parseTextFile } from '../utils/jsonc-parser';
import { formatAndWarnTsDiagnostics } from './format-and-warn-ts-diagnostics';
type ObjectManifest,
type FieldManifest,
} from 'twenty-shared/application';
import { findPathFile } from '@/cli/utils/find-path-file';
import { getTsProgramAndDiagnostics } from '@/cli/utils/get-ts-program-and-diagnostics';
import { parseJsoncFile, parseTextFile } from '@/cli/utils/jsonc-parser';
import { formatAndWarnTsDiagnostics } from '@/cli/utils/format-and-warn-ts-diagnostics';
type JSONValue =
| string
@@ -161,7 +161,7 @@ const collectObjects = (program: Program) => {
const fieldDec = getDecorators(member)?.find(
(d) =>
isDecoratorNamed(d, 'FieldMetadata') ||
isDecoratorNamed(d, 'FieldManifest') ||
isDecoratorNamed(d, 'Field'),
);
@@ -185,7 +185,7 @@ const collectObjects = (program: Program) => {
}
fields.push({
...(fieldCfg as FieldMetadata),
...(fieldCfg as FieldManifest),
...(name ? { name } : {}),
});
}
@@ -490,7 +490,7 @@ export const loadManifest = async (
): Promise<{
packageJson: PackageJson;
yarnLock: string;
manifest: AppManifest;
manifest: ApplicationManifest;
shouldGenerate: boolean;
}> => {
const packageJson = await parseJsoncFile(
+1
View File
@@ -5,6 +5,7 @@
},
"include": [
"**/__mocks__/**/*",
"**/__tests__/**/*",
"vite.config.ts",
"scripts/generateBarrels.ts",
"jest.config.mjs",
@@ -0,0 +1,25 @@
import { type MigrationInterface, type QueryRunner } from 'typeorm';
export class AddApplicationRoleColumns1764923552610
implements MigrationInterface
{
name = 'AddApplicationRoleColumns1764923552610';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."roleTarget" ADD "targetApplicationId" uuid`,
);
await queryRunner.query(
`ALTER TABLE "core"."role" ADD "canBeAssignedToApplications" boolean NOT NULL DEFAULT true`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."role" DROP COLUMN "canBeAssignedToApplications"`,
);
await queryRunner.query(
`ALTER TABLE "core"."roleTarget" DROP COLUMN "targetApplicationId"`,
);
}
}
@@ -3,6 +3,7 @@ import { Inject, Injectable } from '@nestjs/common';
import { msg } from '@lingui/core/macro';
import { isDefined } from 'twenty-shared/utils';
import { Omit } from 'zod/v4/core/util.cjs';
import { type PermissionFlagType } from 'twenty-shared/constants';
import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface';
import { QueryResultFieldValue } from 'src/engine/api/graphql/workspace-query-runner/factories/query-result-getters/interfaces/query-result-field-value';
@@ -40,7 +41,6 @@ import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twent
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { type PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import {
PermissionsException,
PermissionsExceptionCode,
@@ -1,4 +1,4 @@
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { PermissionFlagType } from 'twenty-shared/constants';
export const OBJECTS_WITH_SETTINGS_PERMISSIONS_REQUIREMENTS = {
apiKey: PermissionFlagType.API_KEYS_AND_WEBHOOKS,
@@ -11,13 +11,13 @@ import {
} from '@nestjs/common';
import { Request, Response } from 'express';
import { PermissionFlagType } from 'twenty-shared/constants';
import { RestApiMetadataService } from 'src/engine/api/rest/metadata/rest-api-metadata.service';
import { cleanGraphQLResponse } from 'src/engine/api/rest/utils/clean-graphql-response.utils';
import { JwtAuthGuard } from 'src/engine/guards/jwt-auth.guard';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
@Controller('rest/metadata/*path')
@UseGuards(
@@ -2,6 +2,7 @@ import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Int, Mutation, Query, Resolver } from '@nestjs/graphql';
import GraphQLJSON from 'graphql-type-json';
import { PermissionFlagType } from 'twenty-shared/constants';
import { AdminPanelHealthService } from 'src/engine/core-modules/admin-panel/admin-panel-health.service';
import { AdminPanelQueueService } from 'src/engine/core-modules/admin-panel/admin-panel-queue.service';
@@ -34,7 +35,6 @@ import { ServerLevelImpersonateGuard } from 'src/engine/guards/server-level-impe
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { AdminPanelHealthServiceDataDTO } from './dtos/admin-panel-health-service-data.dto';
import { QueueMetricsDataDTO } from './dtos/queue-metrics-data.dto';
@@ -9,6 +9,7 @@ import {
} from '@nestjs/graphql';
import { type QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';
import { PermissionFlagType } from 'twenty-shared/constants';
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
import { ApiKeyEntity } from 'src/engine/core-modules/api-key/api-key.entity';
@@ -25,7 +26,6 @@ import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.ent
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { RoleDTO } from 'src/engine/metadata-modules/role/dtos/role.dto';
import { ApiKeyRoleService } from './services/api-key-role.service';
@@ -11,6 +11,7 @@ import {
} from '@nestjs/common';
import { type QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';
import { PermissionFlagType } from 'twenty-shared/constants';
import { RestApiExceptionFilter } from 'src/engine/api/rest/rest-api-exception.filter';
import { type ApiKeyEntity } from 'src/engine/core-modules/api-key/api-key.entity';
@@ -22,7 +23,6 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat
import { JwtAuthGuard } from 'src/engine/guards/jwt-auth.guard';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
/**
* rest/apiKeys is deprecated, use rest/metadata/apiKeys instead
@@ -16,6 +16,10 @@ import { ServerlessFunctionLayerModule } from 'src/engine/metadata-modules/serve
import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module';
import { WorkspaceMigrationBuilderGraphqlApiExceptionInterceptor } from 'src/engine/workspace-manager/workspace-migration-v2/interceptors/workspace-migration-builder-graphql-api-exception.interceptor';
import { WorkspaceMigrationV2Module } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-v2.module';
import { RoleTargetModule } from 'src/engine/metadata-modules/role-target/role-target.module';
import { ObjectPermissionModule } from 'src/engine/metadata-modules/object-permission/object-permission.module';
import { PermissionFlagModule } from 'src/engine/metadata-modules/permission-flag/permission-flag.module';
import { RoleModule } from 'src/engine/metadata-modules/role/role.module';
@Module({
imports: [
@@ -32,6 +36,10 @@ import { WorkspaceMigrationV2Module } from 'src/engine/workspace-manager/workspa
RouteTriggerModule,
WorkspaceMigrationV2Module,
PermissionsModule,
RoleModule,
RoleTargetModule,
ObjectPermissionModule,
PermissionFlagModule,
],
providers: [
ApplicationResolver,
@@ -3,6 +3,14 @@ import { Injectable, Logger } from '@nestjs/common';
import { parse } from 'path';
import { isDefined } from 'twenty-shared/utils';
import { Sources } from 'twenty-shared/types';
import {
ApplicationManifest,
FieldManifest,
ObjectManifest,
ServerlessFunctionManifest,
ServerlessFunctionTriggerManifest,
} from 'twenty-shared/application';
import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
import {
@@ -11,14 +19,7 @@ import {
} from 'src/engine/core-modules/application/application.exception';
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
import { ApplicationInput } from 'src/engine/core-modules/application/dtos/application.input';
import {
FieldManifest,
ObjectManifest,
ServerlessFunctionManifest,
ServerlessFunctionTriggerManifest,
} from 'src/engine/core-modules/application/types/application.types';
import { ApplicationVariableEntityService } from 'src/engine/core-modules/applicationVariable/application-variable.service';
import { Sources } from 'src/engine/core-modules/file-storage/types/source.type';
import { CronTriggerV2Service } from 'src/engine/metadata-modules/cron-trigger/services/cron-trigger-v2.service';
import { FlatCronTrigger } from 'src/engine/metadata-modules/cron-trigger/types/flat-cron-trigger.type';
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
@@ -37,6 +38,11 @@ import { ServerlessFunctionV2Service } from 'src/engine/metadata-modules/serverl
import { FlatServerlessFunction } from 'src/engine/metadata-modules/serverless-function/types/flat-serverless-function.type';
import { computeMetadataNameFromLabelOrThrow } from 'src/engine/metadata-modules/utils/compute-metadata-name-from-label-or-throw.util';
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration-v2/services/workspace-migration-validate-build-and-run-service';
import { RoleService } from 'src/engine/metadata-modules/role/role.service';
import { RoleTargetService } from 'src/engine/metadata-modules/role-target/services/role-target.service';
import { ObjectPermissionService } from 'src/engine/metadata-modules/object-permission/object-permission.service';
import { FieldPermissionService } from 'src/engine/metadata-modules/object-permission/field-permission/field-permission.service';
import { PermissionFlagService } from 'src/engine/metadata-modules/permission-flag/permission-flag.service';
@Injectable()
export class ApplicationSyncService {
@@ -55,6 +61,11 @@ export class ApplicationSyncService {
private readonly cronTriggerV2Service: CronTriggerV2Service,
private readonly routeTriggerV2Service: RouteTriggerV2Service,
private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService,
private readonly roleService: RoleService,
private readonly roleTargetService: RoleTargetService,
private readonly objectPermissionService: ObjectPermissionService,
private readonly fieldPermissionService: FieldPermissionService,
private readonly permissionService: PermissionFlagService,
) {}
public async synchronizeFromManifest({
@@ -124,6 +135,12 @@ export class ApplicationSyncService {
let serverlessFunctionLayerId = application.serverlessFunctionLayerId;
await this.syncApplicationRole({
applicationId: application.id,
manifest,
workspaceId,
});
if (manifest.serverlessFunctions.length > 0) {
if (!isDefined(serverlessFunctionLayerId)) {
serverlessFunctionLayerId = (
@@ -161,6 +178,114 @@ export class ApplicationSyncService {
});
}
private async syncApplicationRole({
manifest,
applicationId,
workspaceId,
}: {
manifest: ApplicationManifest;
applicationId: string;
workspaceId: string;
}) {
const applicationRole = manifest.application.applicationRole;
if (
isDefined(applicationRole) &&
isDefined(applicationRole.universalIdentifier)
) {
let role = await this.roleService.getRoleByUniversalIdentifier({
universalIdentifier: applicationRole.universalIdentifier,
workspaceId,
});
if (role) {
await this.roleService.updateRole({
input: {
id: role.id,
update: {
...applicationRole,
canAccessAllTools: false,
canUpdateAllSettings: false,
canBeAssignedToAgents: false,
canBeAssignedToUsers: false,
canBeAssignedToApiKeys: false,
canBeAssignedToApplications: true,
},
},
workspaceId,
});
} else {
role = await this.roleService.createRole({
input: {
canReadAllObjectRecords: true,
canUpdateAllObjectRecords: false,
canSoftDeleteAllObjectRecords: false,
canDestroyAllObjectRecords: false,
...applicationRole,
canAccessAllTools: false,
canUpdateAllSettings: false,
canBeAssignedToAgents: false,
canBeAssignedToUsers: false,
canBeAssignedToApiKeys: false,
canBeAssignedToApplications: true,
},
workspaceId,
applicationId: applicationId,
});
await this.roleTargetService.create({
createRoleTargetInput: {
roleId: role.id,
applicationId: applicationId,
universalIdentifier: role.universalIdentifier,
targetMetadataForeignKey: 'targetApplicationId',
targetId: applicationId,
},
workspaceId,
});
}
if (
isDefined(applicationRole.objectPermissions) &&
applicationRole.objectPermissions.length > 0
) {
await this.objectPermissionService.upsertObjectPermissions({
workspaceId,
input: {
roleId: role.id,
objectPermissions: applicationRole.objectPermissions,
},
});
}
if (
isDefined(applicationRole.fieldPermissions) &&
applicationRole.fieldPermissions.length > 0
) {
await this.fieldPermissionService.upsertFieldPermissions({
workspaceId,
input: {
roleId: role.id,
fieldPermissions: applicationRole.fieldPermissions,
},
});
}
if (
isDefined(applicationRole.permissionFlags) &&
applicationRole.permissionFlags.length > 0
) {
await this.permissionService.upsertPermissionFlags({
workspaceId,
input: {
roleId: role.id,
permissionFlagKeys: applicationRole.permissionFlags,
},
});
}
}
}
private async syncFields({
objectId,
fieldsToSync,
@@ -1,6 +1,8 @@
import { UseFilters, UseGuards, UseInterceptors } from '@nestjs/common';
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { PermissionFlagType } from 'twenty-shared/constants';
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
import { ApplicationExceptionFilter } from 'src/engine/core-modules/application/application-exception-filter';
import { ApplicationSyncService } from 'src/engine/core-modules/application/application-sync.service';
@@ -14,7 +16,6 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat
import { RequireFeatureFlag } from 'src/engine/guards/feature-flag.guard';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { WorkspaceMigrationBuilderGraphqlApiExceptionInterceptor } from 'src/engine/workspace-manager/workspace-migration-v2/interceptors/workspace-migration-builder-graphql-api-exception.interceptor';
@UseGuards(
@@ -1,16 +1,12 @@
import { ArgsType, Field } from '@nestjs/graphql';
import GraphQLJSON from 'graphql-type-json';
import {
AppManifest,
PackageJson,
} from 'src/engine/core-modules/application/types/application.types';
import { ApplicationManifest, PackageJson } from 'twenty-shared/application';
@ArgsType()
export class ApplicationInput {
@Field(() => GraphQLJSON, { nullable: false })
manifest: AppManifest;
manifest: ApplicationManifest;
@Field(() => GraphQLJSON, { nullable: false })
packageJson: PackageJson;
@@ -1,113 +0,0 @@
import { type FieldMetadataType } from 'twenty-shared/types';
import { type HTTPMethod } from 'src/engine/metadata-modules/route-trigger/route-trigger.entity';
export type PackageJson = {
name: string;
license: string;
engines: {
node: string;
npm: string;
yarn: string;
};
packageManager: string;
version: string;
dependencies?: object;
devDependencies?: object;
};
type ApplicationVariable = {
universalIdentifier: string;
value?: string;
description?: string;
isSecret?: boolean;
};
type Sources = { [key: string]: string | Sources };
type Application = {
universalIdentifier: string;
displayName?: string;
description?: string;
icon?: string;
applicationVariables?: Record<string, ApplicationVariable>;
};
export type AppManifest = {
application: Application;
objects: ObjectManifest[];
serverlessFunctions: ServerlessFunctionManifest[];
sources: Sources;
};
export type ServerlessFunctionManifest = {
universalIdentifier: string;
name?: string;
description?: string;
timeoutSeconds?: number;
handlerPath: string;
handlerName: string;
triggers: ServerlessFunctionTriggerManifest[];
};
export type ServerlessFunctionTriggerManifest = (
| {
type: 'cron';
pattern: string;
}
| {
type: 'databaseEvent';
eventName: string;
}
| {
type: 'route';
path: string;
httpMethod: HTTPMethod;
isAuthRequired: boolean;
}
) & {
universalIdentifier: string;
};
export type FieldManifest = {
universalIdentifier: string;
type: FieldMetadataType;
label: string;
description?: string;
icon?: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
defaultValue?: any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
options?: any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
settings?: any;
isNullable?: boolean;
isFieldUiReadOnly?: boolean;
};
export type ObjectManifest = {
universalIdentifier: string;
nameSingular: string;
namePlural: string;
labelSingular: string;
labelPlural: string;
description?: string;
icon?: string;
fields?: FieldManifest[];
};
interface AgentResponseFormat {
type: 'json' | 'text';
schema?: Record<string, unknown>;
}
export type AgentManifest = {
$schema?: string;
standardId: string;
name: string;
label: string;
description?: string;
icon?: string;
prompt: string;
modelId: string;
responseFormat?: AgentResponseFormat;
};
@@ -1,12 +1,13 @@
import { UseFilters, UseGuards } from '@nestjs/common';
import { Args, Mutation, Resolver } from '@nestjs/graphql';
import { PermissionFlagType } from 'twenty-shared/constants';
import { ApplicationVariableEntityExceptionFilter } from 'src/engine/core-modules/applicationVariable/application-variable-exception-filter';
import { ApplicationVariableEntityService } from 'src/engine/core-modules/applicationVariable/application-variable.service';
import { UpdateApplicationVariableEntityInput } from 'src/engine/core-modules/applicationVariable/dtos/update-application-variable.input';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
@UseGuards(
WorkspaceAuthGuard,
@@ -2,9 +2,9 @@ import { InjectRepository } from '@nestjs/typeorm';
import { isDefined } from 'twenty-shared/utils';
import { In, Not, Repository } from 'typeorm';
import { ApplicationVariables } from 'twenty-shared/application';
import { ApplicationVariableEntity } from 'src/engine/core-modules/applicationVariable/application-variable.entity';
import { AppManifest } from 'src/engine/core-modules/application/types/application.types';
export class ApplicationVariableEntityService {
constructor(
@@ -31,7 +31,7 @@ export class ApplicationVariableEntityService {
applicationVariables,
applicationId,
}: {
applicationVariables?: AppManifest['application']['applicationVariables'];
applicationVariables?: ApplicationVariables;
applicationId: string;
}) {
if (!isDefined(applicationVariables)) {
@@ -1,6 +1,8 @@
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { PermissionFlagType } from 'twenty-shared/constants';
import { ApprovedAccessDomainExceptionFilter } from 'src/engine/core-modules/approved-access-domain/approved-access-domain-exception-filter';
import { ApprovedAccessDomainDTO } from 'src/engine/core-modules/approved-access-domain/dtos/approved-access-domain.dto';
import { CreateApprovedAccessDomainInput } from 'src/engine/core-modules/approved-access-domain/dtos/create-approved-access.domain.input';
@@ -15,7 +17,6 @@ import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator';
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
@@ -7,6 +7,7 @@ import { SOURCE_LOCALE } from 'twenty-shared/translations';
import { TwoFactorAuthenticationStrategy } from 'twenty-shared/types';
import { assertIsDefinedOrThrow, isDefined } from 'twenty-shared/utils';
import { Repository } from 'typeorm';
import { PermissionFlagType } from 'twenty-shared/constants';
import { ApiKeyTokenInput } from 'src/engine/core-modules/auth/dto/api-key-token.input';
import { AppTokenInput } from 'src/engine/core-modules/auth/dto/app-token.input';
@@ -74,7 +75,6 @@ import { PublicEndpointGuard } from 'src/engine/guards/public-endpoint.guard';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { PermissionsService } from 'src/engine/metadata-modules/permissions/permissions.service';
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
@@ -11,6 +11,7 @@ import { PasswordUpdateNotifyEmail } from 'twenty-emails';
import { AppPath } from 'twenty-shared/types';
import { assertIsDefinedOrThrow, isDefined } from 'twenty-shared/utils';
import { Repository } from 'typeorm';
import { PermissionFlagType } from 'twenty-shared/constants';
import { NodeEnvironment } from 'src/engine/core-modules/twenty-config/interfaces/node-environment.interface';
@@ -64,7 +65,6 @@ import { WorkspaceInvitationService } from 'src/engine/core-modules/workspace-in
import { AuthProviderEnum } from 'src/engine/core-modules/workspace/types/workspace.type';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { PermissionsService } from 'src/engine/metadata-modules/permissions/permissions.service';
@Injectable()
@@ -6,6 +6,7 @@ import { msg } from '@lingui/core/macro';
import { Strategy } from 'passport-jwt';
import { assertIsDefinedOrThrow, isDefined } from 'twenty-shared/utils';
import { Repository } from 'typeorm';
import { PermissionFlagType } from 'twenty-shared/constants';
import { ApiKeyEntity } from 'src/engine/core-modules/api-key/api-key.entity';
import {
@@ -25,7 +26,6 @@ import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user
import { UserEntity } from 'src/engine/core-modules/user/user.entity';
import { userValidator } from 'src/engine/core-modules/user/user.validate';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { PermissionsService } from 'src/engine/metadata-modules/permissions/permissions.service';
@Injectable()
export class JwtAuthStrategy extends PassportStrategy(Strategy, 'jwt') {
@@ -4,6 +4,7 @@ import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
import { PermissionFlagType } from 'twenty-shared/constants';
import { BillingCheckoutSessionInput } from 'src/engine/core-modules/billing/dtos/inputs/billing-checkout-session.input';
import { BillingSessionInput } from 'src/engine/core-modules/billing/dtos/inputs/billing-session.input';
@@ -32,7 +33,6 @@ import { NoPermissionGuard } from 'src/engine/guards/no-permission.guard';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import {
PermissionsException,
PermissionsExceptionCode,
@@ -61,6 +61,7 @@ import { SubscriptionsModule } from 'src/engine/subscriptions/subscriptions.modu
import { TrashCleanupModule } from 'src/engine/trash-cleanup/trash-cleanup.module';
import { WorkspaceEventEmitterModule } from 'src/engine/workspace-event-emitter/workspace-event-emitter.module';
import { ChannelSyncModule } from 'src/modules/connected-account/channel-sync/channel-sync.module';
import { FlatPageLayoutTabModule } from 'src/engine/metadata-modules/flat-page-layout-tab/flat-page-layout-tab.module';
import { AuditModule } from './audit/audit.module';
import { ClientConfigModule } from './client-config/client-config.module';
@@ -138,6 +139,7 @@ import { FileModule } from './file/file.module';
ApiKeyModule,
WebhookModule,
PageLayoutModule,
FlatPageLayoutTabModule,
ImpersonationModule,
TrashCleanupModule,
],
@@ -1,6 +1,8 @@
import { UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { PermissionFlagType } from 'twenty-shared/constants';
import { EmailingDomainDriver } from 'src/engine/core-modules/emailing-domain/drivers/types/emailing-domain';
import { EmailingDomainDto } from 'src/engine/core-modules/emailing-domain/dtos/emailing-domain.dto';
import { EmailingDomainService } from 'src/engine/core-modules/emailing-domain/services/emailing-domain.service';
@@ -9,7 +11,6 @@ import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.ent
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
@UseGuards(
WorkspaceAuthGuard,
@@ -1,6 +1,6 @@
import { type Readable } from 'stream';
import { type Sources } from 'src/engine/core-modules/file-storage/types/source.type';
import { type Sources } from 'twenty-shared/types';
export interface StorageDriver {
delete(params: { folderPath: string; filename?: string }): Promise<void>;
@@ -4,6 +4,7 @@ import path, { dirname, join } from 'path';
import { type Readable } from 'stream';
import { isObject } from '@sniptt/guards';
import { type Sources } from 'twenty-shared/types';
import { type StorageDriver } from 'src/engine/core-modules/file-storage/drivers/interfaces/storage-driver.interface';
import {
@@ -11,8 +12,6 @@ import {
FileStorageExceptionCode,
} from 'src/engine/core-modules/file-storage/interfaces/file-storage-exception';
import { type Sources } from 'src/engine/core-modules/file-storage/types/source.type';
export interface LocalDriverOptions {
storagePath: string;
}
@@ -29,7 +29,8 @@ import {
FileStorageExceptionCode,
} from 'src/engine/core-modules/file-storage/interfaces/file-storage-exception';
import type { Sources } from 'src/engine/core-modules/file-storage/types/source.type';
import type { Sources } from 'twenty-shared/types';
import { readFileContent } from 'src/engine/core-modules/file-storage/utils/read-file-content';
import { readS3FolderContent } from 'src/engine/core-modules/file-storage/utils/read-s3-folder-content';
@@ -2,10 +2,11 @@ import { Injectable } from '@nestjs/common';
import { type Readable } from 'stream';
import { Sources } from 'twenty-shared/types';
import { type StorageDriver } from 'src/engine/core-modules/file-storage/drivers/interfaces/storage-driver.interface';
import { FileStorageDriverFactory } from 'src/engine/core-modules/file-storage/file-storage-driver.factory';
import { Sources } from 'src/engine/core-modules/file-storage/types/source.type';
@Injectable()
export class FileStorageService implements StorageDriver {
@@ -1 +0,0 @@
export type Sources = { [key: string]: string | Sources };
@@ -1,7 +1,6 @@
import { isDefined } from 'twenty-shared/utils';
import { isObject } from '@sniptt/guards';
import { type Sources } from 'src/engine/core-modules/file-storage/types/source.type';
import { type Sources } from 'twenty-shared/types';
export const readS3FolderContent = (
files: { path: string; fileContent: string }[],
@@ -2,6 +2,7 @@ import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Resolver } from '@nestjs/graphql';
import GraphQLUpload from 'graphql-upload/GraphQLUpload.mjs';
import { PermissionFlagType } from 'twenty-shared/constants';
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
@@ -15,7 +16,6 @@ import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.ent
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { streamToBuffer } from 'src/utils/stream-to-buffer';
@UseGuards(WorkspaceAuthGuard)
@@ -2,6 +2,7 @@ import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Resolver } from '@nestjs/graphql';
import GraphQLUpload from 'graphql-upload/GraphQLUpload.mjs';
import { PermissionFlagType } from 'twenty-shared/constants';
import type { FileUpload } from 'graphql-upload/processRequest.mjs';
@@ -14,7 +15,6 @@ import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.ent
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { streamToBuffer } from 'src/utils/stream-to-buffer';
@UseGuards(WorkspaceAuthGuard)
@@ -9,6 +9,7 @@ import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { ConnectedAccountProvider } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { PermissionFlagType } from 'twenty-shared/constants';
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
import { AuthGraphqlApiExceptionFilter } from 'src/engine/core-modules/auth/filters/auth-graphql-api-exception.filter';
@@ -25,7 +26,6 @@ import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.ent
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { ImapSmtpCalDavAPIService } from 'src/modules/connected-account/services/imap-smtp-caldav-apis.service';
@@ -3,6 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm';
import { isDefined } from 'twenty-shared/utils';
import { Repository } from 'typeorm';
import { PermissionFlagType } from 'twenty-shared/constants';
import { NodeEnvironment } from 'src/engine/core-modules/twenty-config/interfaces/node-environment.interface';
@@ -18,7 +19,6 @@ import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twent
import { twoFactorAuthenticationMethodsValidator } from 'src/engine/core-modules/two-factor-authentication/two-factor-authentication.validation';
import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
import { AuthProviderEnum } from 'src/engine/core-modules/workspace/types/workspace.type';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { PermissionsService } from 'src/engine/metadata-modules/permissions/permissions.service';
@Injectable()
@@ -1,6 +1,8 @@
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Resolver } from '@nestjs/graphql';
import { PermissionFlagType } from 'twenty-shared/constants';
import { AuthGraphqlApiExceptionFilter } from 'src/engine/core-modules/auth/filters/auth-graphql-api-exception.filter';
import { FeatureFlagDTO } from 'src/engine/core-modules/feature-flag/dtos/feature-flag-dto';
import { FeatureFlagException } from 'src/engine/core-modules/feature-flag/feature-flag.exception';
@@ -13,7 +15,6 @@ import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.ent
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
@Resolver()
@@ -1,13 +1,14 @@
import { UseGuards } from '@nestjs/common';
import { Mutation, Query, Resolver } from '@nestjs/graphql';
import { PermissionFlagType } from 'twenty-shared/constants';
import { PostgresCredentialsDTO } from 'src/engine/core-modules/postgres-credentials/dtos/postgres-credentials.dto';
import { PostgresCredentialsService } from 'src/engine/core-modules/postgres-credentials/postgres-credentials.service';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
@UseGuards(
WorkspaceAuthGuard,
@@ -4,6 +4,7 @@ import { InjectRepository } from '@nestjs/typeorm';
import { assertIsDefinedOrThrow } from 'twenty-shared/utils';
import { Repository } from 'typeorm';
import { PermissionFlagType } from 'twenty-shared/constants';
import { DomainValidRecords } from 'src/engine/core-modules/dns-manager/dtos/domain-valid-records';
import { DnsManagerService } from 'src/engine/core-modules/dns-manager/services/dns-manager.service';
@@ -22,7 +23,6 @@ import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.ent
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
@UseGuards(
WorkspaceAuthGuard,
@@ -1,9 +1,10 @@
import fs from 'fs/promises';
import { join } from 'path';
import { type PackageJson } from 'twenty-shared/application';
import { getLayerDependenciesDirName } from 'src/engine/core-modules/serverless/drivers/utils/get-layer-dependencies-dir-name';
import { LAST_LAYER_VERSION } from 'src/engine/core-modules/serverless/drivers/layers/last-layer-version';
import { type PackageJson } from 'src/engine/core-modules/application/types/application.types';
export type LayerDependencies = {
packageJson: PackageJson;
@@ -3,6 +3,8 @@
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { PermissionFlagType } from 'twenty-shared/constants';
import { EnterpriseFeaturesEnabledGuard } from 'src/engine/core-modules/auth/guards/enterprise-features-enabled.guard';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
@@ -22,7 +24,6 @@ import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.ent
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
@Resolver()
@@ -1,6 +1,7 @@
import { Inject, Injectable, Logger, Optional } from '@nestjs/common';
import { type ToolSet } from 'ai';
import { PermissionFlagType } from 'twenty-shared/constants';
import { CreateRecordService } from 'src/engine/core-modules/record-crud/services/create-record.service';
import { DeleteRecordService } from 'src/engine/core-modules/record-crud/services/delete-record.service';
@@ -21,7 +22,6 @@ import { AgentModelConfigService } from 'src/engine/metadata-modules/ai/ai-model
import { AiModelRegistryService } from 'src/engine/metadata-modules/ai/ai-models/services/ai-model-registry.service';
import { FieldMetadataToolsFactory } from 'src/engine/metadata-modules/field-metadata/tools/field-metadata-tools.factory';
import { ObjectMetadataToolsFactory } from 'src/engine/metadata-modules/object-metadata/tools/object-metadata-tools.factory';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { PermissionsService } from 'src/engine/metadata-modules/permissions/permissions.service';
// Type-only import to avoid circular dependency at file level
import type { WorkflowToolWorkspaceService } from 'src/modules/workflow/workflow-tools/services/workflow-tool.workspace-service';
@@ -0,0 +1,60 @@
import { Injectable } from '@nestjs/common';
import { PermissionFlagType } from 'twenty-shared/constants';
import { ToolType } from 'src/engine/core-modules/tool/enums/tool-type.enum';
import { HttpTool } from 'src/engine/core-modules/tool/tools/http-tool/http-tool';
import { SendEmailTool } from 'src/engine/core-modules/tool/tools/send-email-tool/send-email-tool';
import { type SendEmailInput } from 'src/engine/core-modules/tool/tools/send-email-tool/types/send-email-input.type';
import { type Tool } from 'src/engine/core-modules/tool/types/tool.type';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
@Injectable()
export class ToolRegistryService {
private readonly toolFactories: Map<ToolType, () => Tool>;
constructor(
private readonly sendEmailTool: SendEmailTool,
private readonly twentyConfigService: TwentyConfigService,
) {
this.toolFactories = new Map<ToolType, () => Tool>([
[
ToolType.HTTP_REQUEST,
() => {
const httpTool = new HttpTool(twentyConfigService);
return {
description: httpTool.description,
inputSchema: httpTool.inputSchema,
execute: (params) => httpTool.execute(params),
flag: PermissionFlagType.HTTP_REQUEST_TOOL,
};
},
],
[
ToolType.SEND_EMAIL,
() => ({
description: this.sendEmailTool.description,
inputSchema: this.sendEmailTool.inputSchema,
execute: (params) =>
this.sendEmailTool.execute(params as SendEmailInput),
flag: PermissionFlagType.SEND_EMAIL_TOOL,
}),
],
]);
}
getTool(toolType: ToolType): Tool {
const factory = this.toolFactories.get(toolType);
if (!factory) {
throw new Error(`Unknown tool type: ${toolType}`);
}
return factory();
}
getAllToolTypes(): ToolType[] {
return Array.from(this.toolFactories.keys());
}
}
@@ -1,8 +1,8 @@
import { type FlexibleSchema } from '@ai-sdk/provider-utils';
import { type PermissionFlagType } from 'twenty-shared/constants';
import { type ToolInput } from 'src/engine/core-modules/tool/types/tool-input.type';
import { type ToolOutput } from 'src/engine/core-modules/tool/types/tool-output.type';
import { type PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
export type Tool = {
description: string;
@@ -1,7 +1,10 @@
import { Field, ObjectType, registerEnumType } from '@nestjs/graphql';
import { IDField } from '@ptc-org/nestjs-query-graphql';
import { PermissionsOnAllObjectRecords } from 'twenty-shared/constants';
import {
PermissionsOnAllObjectRecords,
PermissionFlagType,
} from 'twenty-shared/constants';
import { type APP_LOCALES, SOURCE_LOCALE } from 'twenty-shared/translations';
import {
Column,
@@ -23,7 +26,6 @@ import { TwoFactorAuthenticationMethodEntity } from 'src/engine/core-modules/two
import { UserEntity } from 'src/engine/core-modules/user/user.entity';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import { ObjectPermissionDTO } from 'src/engine/metadata-modules/object-permission/dtos/object-permission.dto';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
registerEnumType(PermissionFlagType, {
name: 'PermissionFlagType',
@@ -2,6 +2,7 @@ import { UseGuards } from '@nestjs/common';
import { Args, Mutation, Resolver } from '@nestjs/graphql';
import GraphQLUpload from 'graphql-upload/GraphQLUpload.mjs';
import { PermissionFlagType } from 'twenty-shared/constants';
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
@@ -13,7 +14,6 @@ import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.ent
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { streamToBuffer } from 'src/utils/stream-to-buffer';
@Resolver()
@@ -17,6 +17,7 @@ import GraphQLUpload from 'graphql-upload/GraphQLUpload.mjs';
import { isDefined } from 'twenty-shared/utils';
import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
import { In, Repository } from 'typeorm';
import { PermissionFlagType } from 'twenty-shared/constants';
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
import { SupportDriver } from 'src/engine/core-modules/twenty-config/interfaces/support.interface';
@@ -62,7 +63,6 @@ import { NoPermissionGuard } from 'src/engine/guards/no-permission.guard';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import {
PermissionsException,
PermissionsExceptionCode,
@@ -10,6 +10,8 @@ import {
UseGuards,
} from '@nestjs/common';
import { PermissionFlagType } from 'twenty-shared/constants';
import { RestApiExceptionFilter } from 'src/engine/api/rest/rest-api-exception.filter';
import { CreateWebhookInput } from 'src/engine/core-modules/webhook/dtos/create-webhook.dto';
import { UpdateWebhookInput } from 'src/engine/core-modules/webhook/dtos/update-webhook.dto';
@@ -20,7 +22,6 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat
import { JwtAuthGuard } from 'src/engine/guards/jwt-auth.guard';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
/**
* rest/webhooks is deprecated, use rest/metadata/webhooks instead
@@ -2,6 +2,7 @@ import { UseGuards } from '@nestjs/common';
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { type QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';
import { PermissionFlagType } from 'twenty-shared/constants';
import { CreateWebhookInput } from 'src/engine/core-modules/webhook/dtos/create-webhook.dto';
import { DeleteWebhookInput } from 'src/engine/core-modules/webhook/dtos/delete-webhook.dto';
@@ -12,7 +13,6 @@ import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.ent
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { WebhookEntity } from './webhook.entity';
import { WebhookService } from './webhook.service';
@@ -2,6 +2,7 @@ import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Resolver } from '@nestjs/graphql';
import graphqlTypeJson from 'graphql-type-json';
import { PermissionFlagType } from 'twenty-shared/constants';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
@@ -12,7 +13,6 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
import { type OutputSchema } from 'src/modules/workflow/workflow-builder/workflow-schema/types/output-schema.type';
import { WorkflowSchemaWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-schema/workflow-schema.workspace-service';
@@ -1,6 +1,8 @@
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Resolver } from '@nestjs/graphql';
import { PermissionFlagType } from 'twenty-shared/constants';
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
import { buildCreatedByFromFullNameMetadata } from 'src/engine/core-modules/actor/utils/build-created-by-from-full-name-metadata.util';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
@@ -16,7 +18,6 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { WorkflowTriggerWorkspaceService } from 'src/modules/workflow/workflow-trigger/workspace-services/workflow-trigger.workspace-service';
@@ -1,6 +1,8 @@
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Resolver } from '@nestjs/graphql';
import { PermissionFlagType } from 'twenty-shared/constants';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { CreateWorkflowVersionEdgeInput } from 'src/engine/core-modules/workflow/dtos/create-workflow-version-edge-input.dto';
@@ -11,7 +13,6 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
import { WorkflowVersionEdgeWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-version-edge/workflow-version-edge.workspace-service';
@@ -1,6 +1,8 @@
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Resolver } from '@nestjs/graphql';
import { PermissionFlagType } from 'twenty-shared/constants';
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
@@ -22,7 +24,6 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
import { WorkflowVersionStepWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step.workspace-service';
import { WorkflowActionType } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type';
@@ -1,6 +1,8 @@
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Resolver } from '@nestjs/graphql';
import { PermissionFlagType } from 'twenty-shared/constants';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { CreateDraftFromWorkflowVersionInput } from 'src/engine/core-modules/workflow/dtos/create-draft-from-workflow-version-input.dto';
@@ -12,7 +14,6 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
import { WorkflowVersionWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-version/workflow-version.workspace-service';
@@ -1,6 +1,8 @@
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { PermissionFlagType } from 'twenty-shared/constants';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { UserEntity } from 'src/engine/core-modules/user/user.entity';
@@ -13,7 +15,6 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
@@ -8,6 +8,7 @@ import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
import { assertIsDefinedOrThrow, isDefined } from 'twenty-shared/utils';
import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
import { Repository } from 'typeorm';
import { PermissionFlagType } from 'twenty-shared/constants';
import { BillingSubscriptionService } from 'src/engine/core-modules/billing/services/billing-subscription.service';
import { BillingService } from 'src/engine/core-modules/billing/services/billing.service';
@@ -35,7 +36,6 @@ import {
WorkspaceNotFoundDefaultError,
} from 'src/engine/core-modules/workspace/workspace.exception';
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import {
PermissionsException,
PermissionsExceptionCode,
@@ -18,6 +18,7 @@ import assert from 'assert';
import GraphQLUpload from 'graphql-upload/GraphQLUpload.mjs';
import { assertIsDefinedOrThrow, isDefined } from 'twenty-shared/utils';
import { PermissionFlagType } from 'twenty-shared/constants';
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
@@ -70,7 +71,6 @@ import { PublicEndpointGuard } from 'src/engine/guards/public-endpoint.guard';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
import { RoleDTO } from 'src/engine/metadata-modules/role/dtos/role.dto';
import { RoleService } from 'src/engine/metadata-modules/role/role.service';
@@ -2,9 +2,9 @@ import { type ExecutionContext } from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';
import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
import { PermissionFlagType } from 'twenty-shared/constants';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { PermissionsException } from 'src/engine/metadata-modules/permissions/permissions.exception';
import { type PermissionsService } from 'src/engine/metadata-modules/permissions/permissions.service';
@@ -7,8 +7,8 @@ import { GqlExecutionContext } from '@nestjs/graphql';
import { msg } from '@lingui/core/macro';
import { isDefined } from 'class-validator';
import { PermissionFlagType } from 'twenty-shared/constants';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import {
PermissionsException,
PermissionsExceptionCode,

Some files were not shown because too many files have changed in this diff Show More