Fix authContext missing in ALS WorkspaceContext for global datasource (#15810)
Fixes https://github.com/twentyhq/twenty/issues/15809 ## Context We recently introduced a global datasource now consuming workspace context from ALS store however the authContext was missing (only the workspaceId was there) which "broke" event emission, now missing the workspaceMemberId This PR adds the missing authContext so we can access from anywhere in the datasource. We are still passing it as a parameters on repository level for legacy but in theory we should be able to remove it from everywhere and consume the context <img width="929" height="253" alt="Screenshot 2025-11-13 at 18 58 16" src="https://github.com/user-attachments/assets/3e04f264-95e6-4831-94f3-fc01603f19bd" />
This commit is contained in:
+1
-1
@@ -134,7 +134,7 @@ export abstract class CommonBaseQueryRunnerService<
|
||||
|
||||
if (isGlobalDatasourceEnabled) {
|
||||
return this.globalWorkspaceOrmManager.executeInWorkspaceContext(
|
||||
authContext.workspace.id,
|
||||
authContext,
|
||||
async () =>
|
||||
this.executeQueryAndEnrichResults(
|
||||
processedArgs,
|
||||
|
||||
+20
-10
@@ -16,10 +16,9 @@ import { EntitySchemaTransformer } from 'typeorm/entity-schema/EntitySchemaTrans
|
||||
import { EntityMetadataNotFoundError } from 'typeorm/error/EntityMetadataNotFoundError';
|
||||
import { EntityMetadataBuilder } from 'typeorm/metadata-builder/EntityMetadataBuilder';
|
||||
|
||||
import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface';
|
||||
import { type FeatureFlagMap } from 'src/engine/core-modules/feature-flag/interfaces/feature-flag-map.interface';
|
||||
import { type WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface';
|
||||
|
||||
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
|
||||
import {
|
||||
PermissionsException,
|
||||
PermissionsExceptionCode,
|
||||
@@ -67,6 +66,12 @@ export class GlobalWorkspaceDataSource extends DataSource {
|
||||
});
|
||||
}
|
||||
|
||||
get authContext(): WorkspaceAuthContext {
|
||||
const context = getWorkspaceContext();
|
||||
|
||||
return context.authContext;
|
||||
}
|
||||
|
||||
get featureFlagMap(): FeatureFlagMap {
|
||||
const context = getWorkspaceContext();
|
||||
|
||||
@@ -82,18 +87,18 @@ export class GlobalWorkspaceDataSource extends DataSource {
|
||||
override getRepository<Entity extends ObjectLiteral>(
|
||||
target: EntityTarget<Entity>,
|
||||
permissionOptions?: RolePermissionConfig,
|
||||
authContext?: AuthContext,
|
||||
): WorkspaceRepository<Entity> {
|
||||
const manager = this.createEntityManager();
|
||||
|
||||
return manager.getRepository(target, permissionOptions, authContext);
|
||||
return manager.getRepository(target, permissionOptions, this.authContext);
|
||||
}
|
||||
|
||||
override findMetadata(
|
||||
target: EntityTarget<ObjectLiteral>,
|
||||
): EntityMetadata | undefined {
|
||||
const context = getWorkspaceContext();
|
||||
const { workspaceId, metadataVersion } = context;
|
||||
const { authContext, metadataVersion } = context;
|
||||
const workspaceId = authContext.workspace.id;
|
||||
const cacheKey = `${workspaceId}-${metadataVersion}`;
|
||||
|
||||
const cachedEntityMetadata = this.getCachedEntityMetadata(cacheKey);
|
||||
@@ -123,12 +128,17 @@ export class GlobalWorkspaceDataSource extends DataSource {
|
||||
}
|
||||
|
||||
const context = getWorkspaceContext();
|
||||
const fullContext: WorkspaceInternalContext = {
|
||||
...context,
|
||||
eventEmitterService: this.eventEmitterService,
|
||||
};
|
||||
|
||||
return new WorkspaceEntityManager(fullContext, this, queryRunner);
|
||||
return new WorkspaceEntityManager(
|
||||
{
|
||||
workspaceId: context.authContext.workspace.id,
|
||||
objectMetadataMaps: context.objectMetadataMaps,
|
||||
featureFlagsMap: context.featureFlagsMap,
|
||||
eventEmitterService: this.eventEmitterService,
|
||||
},
|
||||
this,
|
||||
queryRunner,
|
||||
);
|
||||
}
|
||||
|
||||
override createQueryRunner(
|
||||
|
||||
+11
-8
@@ -2,13 +2,15 @@ import { Injectable, type Type } from '@nestjs/common';
|
||||
|
||||
import { type ObjectLiteral } from 'typeorm';
|
||||
|
||||
import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface';
|
||||
|
||||
import { WorkspaceFeatureFlagsMapCacheService } from 'src/engine/metadata-modules/workspace-feature-flags-map-cache/workspace-feature-flags-map-cache.service';
|
||||
import { WorkspaceMetadataCacheService } from 'src/engine/metadata-modules/workspace-metadata-cache/services/workspace-metadata-cache.service';
|
||||
import { WorkspacePermissionsCacheService } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.service';
|
||||
import { GlobalWorkspaceDataSourceService } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-datasource.service';
|
||||
import { type WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
|
||||
import {
|
||||
type WorkspaceContextForStorage,
|
||||
type WorkspaceContext,
|
||||
withWorkspaceContext,
|
||||
} from 'src/engine/twenty-orm/storage/workspace-context.storage';
|
||||
import { type RolePermissionConfig } from 'src/engine/twenty-orm/types/role-permission-config';
|
||||
@@ -64,21 +66,21 @@ export class GlobalWorkspaceOrmManager {
|
||||
}
|
||||
|
||||
async executeInWorkspaceContext<T>(
|
||||
workspaceId: string,
|
||||
authContext: WorkspaceAuthContext,
|
||||
fn: () => T | Promise<T>,
|
||||
): Promise<T> {
|
||||
const context = await this.loadWorkspaceContext(workspaceId);
|
||||
const context = await this.loadWorkspaceContext(authContext);
|
||||
const globalDataSource =
|
||||
this.globalWorkspaceDataSourceService.getGlobalWorkspaceDataSource();
|
||||
|
||||
if (
|
||||
!globalDataSource.hasWorkspaceEntityMetadataCacheForVersion(
|
||||
workspaceId,
|
||||
authContext.workspace.id,
|
||||
context.metadataVersion,
|
||||
)
|
||||
) {
|
||||
await globalDataSource.buildWorkspaceMetadata(
|
||||
workspaceId,
|
||||
authContext.workspace.id,
|
||||
context.metadataVersion,
|
||||
context.objectMetadataMaps,
|
||||
);
|
||||
@@ -88,8 +90,9 @@ export class GlobalWorkspaceOrmManager {
|
||||
}
|
||||
|
||||
private async loadWorkspaceContext(
|
||||
workspaceId: string,
|
||||
): Promise<WorkspaceContextForStorage> {
|
||||
authContext: WorkspaceAuthContext,
|
||||
): Promise<WorkspaceContext> {
|
||||
const workspaceId = authContext.workspace.id;
|
||||
const { objectMetadataMaps, metadataVersion } =
|
||||
await this.workspaceMetadataCacheService.getExistingOrRecomputeMetadataMaps(
|
||||
{
|
||||
@@ -108,7 +111,7 @@ export class GlobalWorkspaceOrmManager {
|
||||
});
|
||||
|
||||
return {
|
||||
workspaceId,
|
||||
authContext,
|
||||
objectMetadataMaps,
|
||||
metadataVersion,
|
||||
featureFlagsMap,
|
||||
|
||||
@@ -2,11 +2,13 @@ import { AsyncLocalStorage } from 'async_hooks';
|
||||
|
||||
import { type ObjectsPermissionsByRoleId } from 'twenty-shared/types';
|
||||
|
||||
import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface';
|
||||
|
||||
import { type FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { type ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
|
||||
|
||||
export type WorkspaceContextForStorage = {
|
||||
workspaceId: string;
|
||||
export type WorkspaceContext = {
|
||||
authContext: WorkspaceAuthContext;
|
||||
objectMetadataMaps: ObjectMetadataMaps;
|
||||
metadataVersion: number;
|
||||
featureFlagsMap: Record<FeatureFlagKey, boolean>;
|
||||
@@ -14,9 +16,9 @@ export type WorkspaceContextForStorage = {
|
||||
};
|
||||
|
||||
export const workspaceContextStorage =
|
||||
new AsyncLocalStorage<WorkspaceContextForStorage>();
|
||||
new AsyncLocalStorage<WorkspaceContext>();
|
||||
|
||||
export const getWorkspaceContext = (): WorkspaceContextForStorage => {
|
||||
export const getWorkspaceContext = (): WorkspaceContext => {
|
||||
const context = workspaceContextStorage.getStore();
|
||||
|
||||
if (!context) {
|
||||
@@ -29,14 +31,12 @@ export const getWorkspaceContext = (): WorkspaceContextForStorage => {
|
||||
};
|
||||
|
||||
export const withWorkspaceContext = <T>(
|
||||
context: WorkspaceContextForStorage,
|
||||
context: WorkspaceContext,
|
||||
fn: () => T | Promise<T>,
|
||||
): T | Promise<T> => {
|
||||
return workspaceContextStorage.run(context, fn);
|
||||
};
|
||||
|
||||
export const setWorkspaceContext = (
|
||||
context: WorkspaceContextForStorage,
|
||||
): void => {
|
||||
export const setWorkspaceContext = (context: WorkspaceContext): void => {
|
||||
workspaceContextStorage.enterWith(context);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user