Skip to content

Commit

Permalink
Remove namespaces support (#36)
Browse files Browse the repository at this point in the history
* chore: remove namespaces from code

* docs: remove namespaces from docs
  • Loading branch information
Papooch authored Jun 25, 2022
1 parent 7229c9d commit b32ef83
Show file tree
Hide file tree
Showing 12 changed files with 44 additions and 220 deletions.
1 change: 1 addition & 0 deletions .github/workflows/run-tests.workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
pull_request:
branches:
- main
- release/*

concurrency:
cancel-in-progress: true
Expand Down
59 changes: 1 addition & 58 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,8 @@ Most of these are to some extent solvable using _request-scoped_ providers or pa
- [REST](#rest)
- [GraphQL](#graphql)
- [Others](#others)
- [~~Namespaces~~](#namespaces-deprecated) (deprecated)

> **Notice**: I have deprecated [Namespaces](#namespaces-deprecated) since version `2.1.1` and will be removing them in `3.0` to make room for new features ([#31](https://github.com/Papooch/nestjs-cls/issues/31)). Namespace support was experimental from the begining, and I havent seen any justifiable use case to keep it around.
> **Notice**: I have deprecated [Namespaces](#namespaces-deprecated) since version `2.1.1` and will be removing them in `3.0` to make room for new features ([#31](https://github.com/Papooch/nestjs-cls/issues/31)). Namespace support was experimental from the beginning, and I haven't seen any justifiable use case to keep it around.
# Install

Expand Down Expand Up @@ -569,62 +568,6 @@ Below are listed platforms with which it is confirmed to work.

_Websocket Gateways_ don't respect globally bound enhancers, therefore it is required to bind the `ClsGuard` or `ClsIntercetor` manually on the `WebscocketGateway`. (See [#8](https://github.com/Papooch/nestjs-cls/issues/8))

# ~~Namespaces~~ (deprecated)

> **Warning**: Namespace support will be dropped in v3.0
The default CLS namespace that the `ClsService` provides should be enough for most application, but should you need it, this package provides a way to use multiple CLS namespaces simultaneously.

To use custom namespace provider, use `ClsModule.forFeature('my-namespace')`.

```ts
@Module({
imports: [ClsModule.forFeature('hello-namespace')],
providers: [HelloService],
controllers: [HelloController],
})
export class HelloModule {}
```

This creates a namespaced `ClsService` provider that you can inject using `@InjectCls`

```ts
// hello.service.ts

@Injectable()
class HelloService {
constructor(
@InjectCls('hello-namespace')
private readonly myCls: ClsService,
) {}

sayHello() {
return this.myCls.run('hi');
}
}

// hello.controller.ts
@Injectable()
export class HelloController {
constructor(
@InjectCls('hello-namespace')
private readonly myCls: ClsService,
private readonly helloService: HelloService,
);

@Get('/hello')
hello2() {
// setting up cls context manually
return this.myCls.run(() => {
this.myCls.set('hi', 'Hello');
return this.helloService.sayHello();
});
}
}
```

> **Note**: `@InjectCls('x')` is equivalent to `@Inject(getClsServiceToken('x'))`. If you don't pass an argument to `@InjectCls()`, the default ClsService will be injected and is equivalent to omitting the decorator altogether.
# Contributing

Contributing to a community project is always welcome, please see the [Contributing guide](./CONTRIBUTING.md) :)
72 changes: 7 additions & 65 deletions src/lib/cls-service-manager.ts
Original file line number Diff line number Diff line change
@@ -1,75 +1,17 @@
import { ClassProvider, ValueProvider } from '@nestjs/common';
import { CLS_DEFAULT_NAMESPACE } from './cls.constants';
import { ClsService } from './cls.service';
import { AsyncLocalStorage } from 'async_hooks';

/**
* Get ClsService injection token (as a string)
*/
export function getClsServiceToken(): string;
/**
* Get namespaced ClsService injection token (as a string)
* @param namespace name of the namespace
* @deprecated Namespace support will be removed in v3.0
*/
export function getClsServiceToken(namespace: string): string;
export function getClsServiceToken(namespace = CLS_DEFAULT_NAMESPACE) {
return `ClsService-${namespace}`;
}
import { ClsStore } from './cls.interfaces';
import { ClsService } from './cls.service';

export class ClsServiceManager {
private static namespaces: Record<
string,
AsyncLocalStorage<any> & { name?: string }
> = {};

private static clsServices: Map<string | typeof ClsService, ClsService> =
new Map([
[
ClsService,
new ClsService(this.resolveNamespace(CLS_DEFAULT_NAMESPACE)),
],
]);

private static resolveNamespace(name: string) {
if (!this.namespaces[name]) {
this.namespaces[name] = new AsyncLocalStorage();
this.namespaces[name].name = name;
}
return this.namespaces[name];
}

static addClsService(name: string = CLS_DEFAULT_NAMESPACE) {
const service = new ClsService(this.resolveNamespace(name));
this.clsServices.set(
getClsServiceToken(name),
new ClsService(this.resolveNamespace(name)),
);
return service;
}
private static als = new AsyncLocalStorage();
private static clsService = new ClsService(this.als);

/**
* Retrieve a ClsService outside of Nest's DI.
* @param name namespace name, omit for default
* @returns the ClsService with the given namespace
* @returns the ClsService
*/
static getClsService(name?: string) {
const cls = this.clsServices.get(
name ? getClsServiceToken(name) : ClsService,
);
if (!cls)
throw new Error(`ClsService with namespace ${name} does not exist`);
static getClsService<T extends ClsStore = ClsStore>(): ClsService<T> {
const cls = this.clsService as ClsService<T>;
return cls;
}

static getClsServicesAsProviders(): Array<
ClassProvider<ClsService> | ValueProvider<ClsService>
> {
return Array.from(this.clsServices.entries()).map(
([provide, service]) => ({
provide,
useValue: service,
}),
);
}
}
1 change: 0 additions & 1 deletion src/lib/cls.constants.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
export const CLS_REQ = Symbol('CLS_REQUEST');
export const CLS_RES = Symbol('CLS_RESPONSE');
export const CLS_ID = Symbol('CLS_ID');
export const CLS_DEFAULT_NAMESPACE = 'CLS_DEFAULT_NAMESPACE';
export const CLS_MODULE_OPTIONS = 'ClsModuleOptions';
export const CLS_MIDDLEWARE_OPTIONS = 'ClsMiddlewareOptions';
export const CLS_GUARD_OPTIONS = 'ClsGuardOptions';
Expand Down
15 changes: 3 additions & 12 deletions src/lib/cls.decorators.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,9 @@
import { Inject } from '@nestjs/common';
import { getClsServiceToken } from './cls-service-manager';
import { CLS_DEFAULT_NAMESPACE } from './cls.constants';
import { ClsService } from './cls.service';

/**
* Use to explicitly inject the ClsService
*/
export function InjectCls(): (target: any, key: string | symbol, index?: number) => void;

/**
* Use to inject a namespaced CLS service
* @param namespace name of the namespace
* @deprecated Namespace support will be removed in v3.0
*/
export function InjectCls(namespace: string): (target: any, key: string | symbol, index?: number) => void;
export function InjectCls(namespace = CLS_DEFAULT_NAMESPACE) {
return Inject(getClsServiceToken(namespace));
export function InjectCls() {
return Inject(ClsService);
}
2 changes: 1 addition & 1 deletion src/lib/cls.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export class ClsGuard implements CanActivate {
}

async canActivate(context: ExecutionContext): Promise<boolean> {
const cls = ClsServiceManager.getClsService(this.options.namespaceName);
const cls = ClsServiceManager.getClsService();
return cls.exit(async () => {
cls.enter();
if (this.options.generateId) {
Expand Down
2 changes: 1 addition & 1 deletion src/lib/cls.interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export class ClsInterceptor implements NestInterceptor {
}

intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const cls = ClsServiceManager.getClsService(this.options.namespaceName);
const cls = ClsServiceManager.getClsService();
return new Observable((subscriber) => {
cls.run(async () => {
if (this.options.generateId) {
Expand Down
36 changes: 1 addition & 35 deletions src/lib/cls.interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { ExecutionContext, ModuleMetadata } from '@nestjs/common';
import { CLS_DEFAULT_NAMESPACE } from './cls.constants';
import { ClsService } from './cls.service';

export class ClsModuleOptions {
Expand All @@ -23,20 +22,9 @@ export class ClsModuleOptions {
* An object with additional options for the `ClsInterceptor`
*/
interceptor?: ClsInterceptorOptions = null;

/**
* The namespace that will be set up. When used, `ClsService`
* must be injected using the `@InjectCls('name')` decorator.
* (most of the time you will not need to touch this setting)
* @deprecated Namespace support will be removed in v3.0
*/
namespaceName? = CLS_DEFAULT_NAMESPACE;
}

export type ClsModuleFactoryOptions = Omit<
ClsModuleOptions,
'global' | 'namespaceName'
>;
export type ClsModuleFactoryOptions = Omit<ClsModuleOptions, 'global'>;
export interface ClsModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
inject?: any[];
useFactory?: (
Expand All @@ -47,13 +35,6 @@ export interface ClsModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
* to import `ClsModule.forFeature()` in other modules
*/
global?: boolean;
/**
* The namespace that will be set up. When used, `ClsService`
* must be injected using the `@InjectCls('name')` decorator.
* (most of the time you will not need to touch this setting)
* @deprecated Namespace support will be removed in v3.0
*/
namespaceName?: string;
}

export class ClsMiddlewareOptions {
Expand Down Expand Up @@ -100,11 +81,6 @@ export class ClsMiddlewareOptions {
* some frameworks are known to lose the context wih `run`.
*/
useEnterWith? = false;

/**
* @deprecated Namespace support will be removed in v3.0
*/
readonly namespaceName?: string;
}

export class ClsGuardOptions {
Expand Down Expand Up @@ -132,11 +108,6 @@ export class ClsGuardOptions {
cls: ClsService,
context: ExecutionContext,
) => void | Promise<void>;

/**
* @deprecated Namespace support will be removed in v3.0
*/
readonly namespaceName?: string;
}

export class ClsInterceptorOptions {
Expand Down Expand Up @@ -164,11 +135,6 @@ export class ClsInterceptorOptions {
cls: ClsService,
context: ExecutionContext,
) => void | Promise<void>;

/**
* @deprecated Namespace support will be removed in v3.0
*/
readonly namespaceName?: string;
}

export interface ClsStore {
Expand Down
2 changes: 1 addition & 1 deletion src/lib/cls.middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class ClsMiddleware implements NestMiddleware {
this.options = { ...new ClsMiddlewareOptions(), ...options };
}
use = async (req: any, res: any, next: () => any) => {
const cls = ClsServiceManager.getClsService(this.options.namespaceName);
const cls = ClsServiceManager.getClsService();
const callback = async () => {
this.options.useEnterWith && cls.enter();
if (this.options.generateId) {
Expand Down
Loading

0 comments on commit b32ef83

Please sign in to comment.