1895 extensibility v1 application tokens 3 (#16504)

- moves applicationRoleId to application entity
- add new `APPLICATION` FieldActorSource and `APPLICATION`
JwtTokenTypeEnum value
- create a new token with applicationId when executing a function
- when applicationId is in token, check for application.defaultRole
permissions
-use twenty-shared types in `twenty-sdk/application`
- create a new import from generate called "Twenty" that you can use
directly without having to set TWENTY_API_KEY AND TWENTY_API_URL (keep
metadata or core parameter only)
- provide to serverless unique one time BEARER TOKEN to run it

Result
<img width="977" height="566" alt="image"
src="https://github.com/user-attachments/assets/e78428a0-5b13-4975-aa13-58ee3b32450c"
/>

<img width="910" height="596" alt="image"
src="https://github.com/user-attachments/assets/6ec72bf5-7655-4093-a45e-ad269595a324"
/>

<img width="741" height="568" alt="image"
src="https://github.com/user-attachments/assets/7683944c-fd79-4417-8fb2-8e4815cc112f"
/>
This commit is contained in:
martmull
2025-12-15 17:44:23 +01:00
committed by GitHub
parent e33f18bfa8
commit e289f3056e
103 changed files with 1427 additions and 512 deletions
@@ -4,10 +4,12 @@ import {
type Application,
} from '@/application';
import { type Sources } from '@/types';
import { type RoleManifest } from '@/application/roleManifestType';
export type ApplicationManifest = {
application: Application;
objects: ObjectManifest[];
serverlessFunctions: ServerlessFunctionManifest[];
roles?: RoleManifest[];
sources: Sources;
};
@@ -1,46 +1,10 @@
import { type ApplicationVariables } from '@/application';
import { type PermissionFlagType } from '@/constants';
import { type SyncableEntityOptions } from '@/application/syncableEntityOptionsType';
type ObjectPermission = {
objectMetadataId: string;
canReadObjectRecords?: boolean;
canUpdateObjectRecords?: boolean;
canSoftDeleteObjectRecords?: boolean;
canDestroyObjectRecords?: boolean;
};
type FieldPermission = {
objectMetadataId: string;
fieldMetadataId: string;
canReadFieldValue?: boolean;
canUpdateFieldValue?: boolean;
};
type Role = {
label: string;
description?: string;
icon?: string;
canUpdateAllSettings?: boolean;
canAccessAllTools?: boolean;
canReadAllObjectRecords?: boolean;
canUpdateAllObjectRecords?: boolean;
canSoftDeleteAllObjectRecords?: boolean;
canDestroyAllObjectRecords?: boolean;
canBeAssignedToUsers?: boolean;
canBeAssignedToAgents?: boolean;
canBeAssignedToApiKeys?: boolean;
canBeAssignedToApplications?: boolean;
universalIdentifier: string;
objectPermissions?: ObjectPermission[];
fieldPermissions?: FieldPermission[];
permissionFlags?: PermissionFlagType[];
};
export type Application = {
universalIdentifier: string;
export type Application = SyncableEntityOptions & {
displayName?: string;
description?: string;
icon?: string;
applicationVariables?: ApplicationVariables;
applicationRole?: Role;
functionRoleUniversalIdentifier?: string;
};
@@ -1,5 +1,6 @@
type ApplicationVariable = {
universalIdentifier: string;
import { type SyncableEntityOptions } from '@/application/syncableEntityOptionsType';
type ApplicationVariable = SyncableEntityOptions & {
value?: string;
description?: string;
isSecret?: boolean;
@@ -0,0 +1 @@
export const DEFAULT_API_KEY_NAME = 'TWENTY_API_KEY';
@@ -0,0 +1 @@
export const DEFAULT_API_URL_NAME = 'TWENTY_API_URL';
@@ -1,14 +1,23 @@
import { type FieldMetadataType } from '@/types';
import {
type FieldMetadataType,
type FieldMetadataSettings,
type FieldMetadataOptions,
type FieldMetadataDefaultValue,
} from '@/types';
import { type SyncableEntityOptions } from '@/application/syncableEntityOptionsType';
export type FieldManifest = {
universalIdentifier: string;
type: FieldMetadataType;
export type FieldManifest<
T extends FieldMetadataType = Exclude<
FieldMetadataType,
FieldMetadataType.RELATION
>,
> = SyncableEntityOptions & {
type: T;
label: string;
description?: string;
icon?: string;
defaultValue?: any;
options?: any;
settings?: any;
defaultValue?: FieldMetadataDefaultValue<T>;
options?: FieldMetadataOptions<T>;
settings?: FieldMetadataSettings<T>;
isNullable?: boolean;
isFieldUiReadOnly?: boolean;
};
@@ -10,9 +10,12 @@
export type { ApplicationManifest } from './applicationManifestType';
export type { Application } from './applicationType';
export type { ApplicationVariables } from './applicationVariablesType';
export { DEFAULT_API_KEY_NAME } from './constants/DefaultApiKeyName';
export { DEFAULT_API_URL_NAME } from './constants/DefaultApiUrlName';
export type { FieldManifest } from './fieldManifestType';
export type { ObjectManifest } from './objectManifestType';
export type { PackageJson } from './packageJsonType';
export type { RoleManifest } from './roleManifestType';
export type {
ServerlessFunctionManifest,
DatabaseEventTrigger,
@@ -20,3 +23,4 @@ export type {
RouteTrigger,
ServerlessFunctionTriggerManifest,
} from './serverlessFunctionManifestType';
export type { SyncableEntityOptions } from './syncableEntityOptionsType';
@@ -1,7 +1,7 @@
import { type FieldManifest } from '@/application';
import { type SyncableEntityOptions } from '@/application/syncableEntityOptionsType';
export type ObjectManifest = {
universalIdentifier: string;
export type ObjectManifest = SyncableEntityOptions & {
nameSingular: string;
namePlural: string;
labelSingular: string;
@@ -0,0 +1,63 @@
import { type PermissionFlagType } from '@/constants';
import { type SyncableEntityOptions } from '@/application/syncableEntityOptionsType';
type WithObjectIdentifier = {
objectUniversalIdentifier: string;
objectNameSingular?: never;
};
type WithObjectName = {
objectNameSingular: string;
objectUniversalIdentifier?: never;
};
type BaseObjectPermission = {
canReadObjectRecords?: boolean;
canUpdateObjectRecords?: boolean;
canSoftDeleteObjectRecords?: boolean;
canDestroyObjectRecords?: boolean;
};
type ObjectPermission =
| (BaseObjectPermission & WithObjectIdentifier)
| (BaseObjectPermission & WithObjectName);
type WithFieldIdentifier = {
fieldUniversalIdentifier: string;
fieldName?: never;
};
type WithFieldName = {
fieldName: string;
fieldUniversalIdentifier?: never;
};
type BaseFieldPermission = {
canReadFieldValue?: boolean;
canUpdateFieldValue?: boolean;
};
type FieldPermission =
| (BaseFieldPermission & WithObjectIdentifier & WithFieldIdentifier)
| (BaseFieldPermission & WithObjectIdentifier & WithFieldName)
| (BaseFieldPermission & WithObjectName & WithFieldIdentifier)
| (BaseFieldPermission & WithObjectName & WithFieldName);
export type RoleManifest = SyncableEntityOptions & {
label: string;
description?: string;
icon?: string;
canUpdateAllSettings?: boolean;
canAccessAllTools?: boolean;
canReadAllObjectRecords?: boolean;
canUpdateAllObjectRecords?: boolean;
canSoftDeleteAllObjectRecords?: boolean;
canDestroyAllObjectRecords?: boolean;
canBeAssignedToUsers?: boolean;
canBeAssignedToAgents?: boolean;
canBeAssignedToApiKeys?: boolean;
canBeAssignedToApplications?: boolean;
objectPermissions?: ObjectPermission[];
fieldPermissions?: FieldPermission[];
permissionFlags?: PermissionFlagType[];
};
@@ -1,7 +1,7 @@
import { type HTTPMethod } from '@/types';
import { type SyncableEntityOptions } from '@/application/syncableEntityOptionsType';
export type ServerlessFunctionManifest = {
universalIdentifier: string;
export type ServerlessFunctionManifest = SyncableEntityOptions & {
name?: string;
description?: string;
timeoutSeconds?: number;
@@ -23,10 +23,9 @@ export type CronTrigger = {
export type RouteTrigger = {
type: 'route';
path: string;
httpMethod: HTTPMethod;
httpMethod: `${HTTPMethod}`;
isAuthRequired: boolean;
};
export type ServerlessFunctionTriggerManifest = {
universalIdentifier: string;
} & (CronTrigger | DatabaseEventTrigger | RouteTrigger);
export type ServerlessFunctionTriggerManifest = SyncableEntityOptions &
(CronTrigger | DatabaseEventTrigger | RouteTrigger);
@@ -0,0 +1 @@
export type SyncableEntityOptions = { universalIdentifier: string };