@vendure/core
Version:
A modern, headless ecommerce framework
235 lines (234 loc) • 9.02 kB
TypeScript
import { ExecutionContext } from '@nestjs/common';
import { CurrencyCode, LanguageCode, Permission } from '@vendure/common/lib/generated-types';
import { ID, JsonCompatible } from '@vendure/common/lib/shared-types';
import { Request } from 'express';
import { TFunction } from 'i18next';
import { ReplicationMode } from 'typeorm';
import { REQUEST_CONTEXT_KEY, REQUEST_CONTEXT_MAP_KEY } from '../../common/constants';
import { CachedSession } from '../../config/session-cache/session-cache-strategy';
import { Channel } from '../../entity/channel/channel.entity';
import { ApiType } from './get-api-type';
export type SerializedRequestContext = {
_req?: any;
_session: JsonCompatible<Required<CachedSession>>;
_apiType: ApiType;
_channel: JsonCompatible<Channel>;
_languageCode: LanguageCode;
_isAuthorized: boolean;
_authorizedAsOwnerOnly: boolean;
};
/**
* This object is used to store the RequestContext on the Express Request object.
*/
interface RequestContextStore {
/**
* This is the default RequestContext for the handler.
*/
default: RequestContext;
/**
* If a transaction is started, the resulting RequestContext is stored here.
* This RequestContext will have a transaction manager attached via the
* TRANSACTION_MANAGER_KEY symbol.
*
* When a transaction is started, the TRANSACTION_MANAGER_KEY symbol is added to the RequestContext
* object. This is then detected inside the {@link internal_setRequestContext} function and the
* RequestContext object is stored in the RequestContextStore under the withTransactionManager key.
*/
withTransactionManager?: RequestContext;
}
interface RequestWithStores extends Request {
[REQUEST_CONTEXT_MAP_KEY]?: Map<Function, RequestContextStore>;
[REQUEST_CONTEXT_KEY]?: RequestContextStore;
}
/**
* @description
* This function is used to set the {@link RequestContext} on the `req` object. This is the underlying
* mechanism by which we are able to access the `RequestContext` from different places.
*
* For example, here is a diagram to show how, in an incoming API request, we are able to store
* and retrieve the `RequestContext` in a resolver:
* ```
* - query { product }
* |
* - AuthGuard.canActivate()
* | | creates a `RequestContext`, stores it on `req`
* |
* - product() resolver
* | @Ctx() decorator fetching `RequestContext` from `req`
* ```
*
* We named it this way to discourage usage outside the framework internals.
*/
export declare function internal_setRequestContext(req: RequestWithStores, ctx: RequestContext, executionContext?: ExecutionContext): void;
/**
* @description
* Gets the {@link RequestContext} from the `req` object. See {@link internal_setRequestContext}
* for more details on this mechanism.
*/
export declare function internal_getRequestContext(req: RequestWithStores, executionContext?: ExecutionContext): RequestContext;
/**
* @description
* The RequestContext holds information relevant to the current request, which may be
* required at various points of the stack.
*
* It is a good practice to inject the RequestContext (using the {@link Ctx} decorator) into
* _all_ resolvers & REST handler, and then pass it through to the service layer.
*
* This allows the service layer to access information about the current user, the active language,
* the active Channel, and so on. In addition, the {@link TransactionalConnection} relies on the
* presence of the RequestContext object in order to correctly handle per-request database transactions.
*
* The RequestContext also provides mechanisms for managing the database replication mode via the
* `setReplicationMode` method and the `replicationMode` getter. This allows for finer control
* over whether database queries within the context should be executed against the master or a replica
* database, which can be particularly useful in distributed database environments.
*
* @example
* ```ts
* \@Query()
* myQuery(\@Ctx() ctx: RequestContext) {
* return this.myService.getData(ctx);
* }
* ```
*
* @example
* ```ts
* \@Query()
* myMutation(\@Ctx() ctx: RequestContext) {
* ctx.setReplicationMode('master');
* return this.myService.getData(ctx);
* }
* ```
* @docsCategory request
*/
export declare class RequestContext {
private readonly _languageCode;
private readonly _currencyCode;
private readonly _channel;
private readonly _session?;
private readonly _isAuthorized;
private readonly _authorizedAsOwnerOnly;
private readonly _translationFn;
private readonly _apiType;
private readonly _req?;
private _replicationMode?;
/**
* @internal
*/
constructor(options: {
req?: Request;
apiType: ApiType;
channel: Channel;
session?: CachedSession;
languageCode?: LanguageCode;
currencyCode?: CurrencyCode;
isAuthorized: boolean;
authorizedAsOwnerOnly: boolean;
translationFn?: TFunction;
});
/**
* @description
* Creates an "empty" RequestContext object. This is only intended to be used
* when a service method must be called outside the normal request-response
* cycle, e.g. when programmatically populating data. Usually a better alternative
* is to use the {@link RequestContextService} `create()` method, which allows more control
* over the resulting RequestContext object.
*/
static empty(): RequestContext;
/**
* @description
* Creates a new RequestContext object from a serialized object created by the
* `serialize()` method.
*/
static deserialize(ctxObject: SerializedRequestContext): RequestContext;
/**
* @description
* Returns `true` if there is an active Session & User associated with this request,
* and that User has the specified permissions on the active Channel.
*/
userHasPermissions(permissions: Permission[]): boolean;
/**
* @description
* Serializes the RequestContext object into a JSON-compatible simple object.
* This is useful when you need to send a RequestContext object to another
* process, e.g. to pass it to the Job Queue via the {@link JobQueueService}.
*/
serialize(): SerializedRequestContext;
/**
* @description
* Creates a shallow copy of the RequestContext instance. This means that
* mutations to the copy itself will not affect the original, but deep mutations
* (e.g. copy.channel.code = 'new') *will* also affect the original.
*/
copy(): RequestContext;
/**
* @description
* The raw Express request object.
*/
get req(): Request | undefined;
/**
* @description
* Signals which API this request was received by, e.g. `admin` or `shop`.
*/
get apiType(): ApiType;
/**
* @description
* The active {@link Channel} of this request.
*/
get channel(): Channel;
get channelId(): ID;
get languageCode(): LanguageCode;
get currencyCode(): CurrencyCode;
get session(): CachedSession | undefined;
get activeUserId(): ID | undefined;
/**
* @description
* True if the current session is authorized to access the current resolver method.
*
* @deprecated Use `userHasPermissions()` method instead.
*/
get isAuthorized(): boolean;
/**
* @description
* True if the current anonymous session is only authorized to operate on entities that
* are owned by the current session.
*/
get authorizedAsOwnerOnly(): boolean;
/**
* @description
* Translate the given i18n key
*/
translate(key: string, variables?: {
[k: string]: any;
}): string;
/**
* Returns true if any element of arr1 appears in arr2.
*/
private arraysIntersect;
/**
* The Express "Request" object is huge and contains many circular
* references. We will preserve just a subset of the whole, by preserving
* only the serializable properties up to 2 levels deep.
* @private
*/
private shallowCloneRequestObject;
/**
* @description
* Sets the replication mode for the current RequestContext. This mode determines whether the operations
* within this context should interact with the master database or a replica. Use this method to explicitly
* define the replication mode for the context.
*
* @param mode - The replication mode to be set (e.g., 'master' or 'replica').
*/
setReplicationMode(mode: ReplicationMode): void;
/**
* @description
* Gets the current replication mode of the RequestContext. If no replication mode has been set,
* it returns `undefined`. This property indicates whether the context is configured to interact with
* the master database or a replica.
*
* @returns The current replication mode, or `undefined` if none is set.
*/
get replicationMode(): ReplicationMode | undefined;
}
export {};