Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): mark parts of old plugin API as deprecated, update docs #217

Merged
merged 1 commit into from
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 40 additions & 45 deletions docs/docs/04_api/01_service-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,72 +6,67 @@ The injectable `ClsService` provides the following API to manipulate the cls con

The `S` type parameter is used as the type of custom `ClsStore`.

- **_`get`_**`(): S`
Get the entire CLS context.
- **_`get`_**`(): S`
Get the entire CLS context.

- **_`get`_**`(key?: keyof S): S[key]`
Retrieve a value from the CLS context by key.
- **_`get`_**`(key?: keyof S): S[key]`
Retrieve a value from the CLS context by key.

- **_`getId`_**`(): string;`
Retrieve the request ID (a shorthand for `cls.get(CLS_ID)`)
- **_`getId`_**`(): string;`
Retrieve the request ID (a shorthand for `cls.get(CLS_ID)`)

- **_`has`_**`(key: keyof S): boolean`
Check if a key is in the CLS context.
- **_`has`_**`(key: keyof S): boolean`
Check if a key is in the CLS context.

- **_`set`_**`(key: keyof S, value: S[key]): void`
Set a value on the CLS context.
- **_`set`_**`(key: keyof S, value: S[key]): void`
Set a value on the CLS context.

- **_`setIfUndefined`_**`(key: keyof S, value: S[key]): void`
Set a value on the CLS context _only_ if it hasn't been already set. Useful for ensuring idempotence if you have multiple entry points.
- **_`setIfUndefined`_**`(key: keyof S, value: S[key]): void`
Set a value on the CLS context _only_ if it hasn't been already set. Useful for ensuring idempotence if you have multiple entry points.

- **_`run`_**`(callback: () => T): T`
**_`run`_**`(options: ClsContextOptions, callback: () => T): T;`
Run the callback in a shared CLS context. Optionally takes an [options object](#clscontextoptions) as the first parameter.
- **_`run`_**`(callback: () => T): T`
**_`run`_**`(options: ClsContextOptions, callback: () => T): T;`
Run the callback in a shared CLS context. Optionally takes an [options object](#clscontextoptions) as the first parameter.

- **_`runWith`_**`(store: S, callback: () => T): T`
Run the callback in a new CLS context (while supplying the default store).
- **_`runWith`_**`(store: S, callback: () => T): T`
Run the callback in a new CLS context (while supplying the default store).

- **_`enter`_**`(): void;`
**_`enter`_**`(options: ClsContextOptions): void`
Run any following code in a shared CLS context. Optionally takes an [options object](#clscontextoptions) as the first parameter.
- **_`enter`_**`(): void;`
**_`enter`_**`(options: ClsContextOptions): void`
Run any following code in a shared CLS context. Optionally takes an [options object](#clscontextoptions) as the first parameter.

- **_`enterWith`_**`(store: S): void`
Run any following code in a new CLS context (while supplying the default store).
- **_`enterWith`_**`(store: S): void`
Run any following code in a new CLS context (while supplying the default store).

- **_`exit`_**`(callback: () => T): T`
Run the callback _without_ access to a shared CLS context.
- **_`exit`_**`(callback: () => T): T`
Run the callback _without_ access to a shared CLS context.

- **_`isActive`_**`(): boolean`
Whether the current code runs within an active CLS context.
- **_`isActive`_**`(): boolean`
Whether the current code runs within an active CLS context.

The following methods only apply to the [Proxy](../03_features-and-use-cases/06_proxy-providers.md) feature:

- **_`getProxy`_**`(proxyToken: any): any`
Retrieve a Proxy provider from the CLS context based on its injection token.
- **_`getProxy`_**`(proxyToken: any): any`
Retrieve a Proxy provider from the CLS context based on its injection token.

- **_`setProxy`_**`(proxyToken: any, value? any): any`
Replace an instance of a Proxy provider in the CLS context based on its injection token.
- **_`setProxy`_**`(proxyToken: any, value? any): any`
Replace an instance of a Proxy provider in the CLS context based on its injection token.

- **_`resolveProxyProviders`_**`(proxyTokens?: any[]): Promise<void>`
Manually trigger resolution of registered Proxy Providers. If an array of injection tokens is provided, resolves only those Proxy Providers.

The following methods involve the [plugin lifecycle](../06_plugins/02_plugin-api.md):

- **_`initializePlugins`_**`(): Promise<void>`
Manually trigger `onClsInit` hooks of registered plugins.
- **_`resolveProxyProviders`_**`(proxyTokens?: any[]): Promise<void>`
Manually trigger resolution of registered Proxy Providers. If an array of injection tokens is provided, resolves only those Proxy Providers.

## ClsContextOptions

The `run` and `enter` methods can take an additional options object with the following settings:

- **_`ifNested?:`_**`'inherit' | 'reuse' | 'override'`
Sets the behavior of nested CLS context creation in case the method is invoked in an existing context. It has no effect if no parent context exist.
- `inherit` (default) - Run the callback with a shallow copy of the parent context.
Re-assignments of top-level properties will not be reflected in the parent context. However, modifications of existing properties _will_ be reflected.
- `reuse` - Reuse existing context without creating a new one. All modifications to the
existing context will be reflected.
- `override` - Run the callback with an new empty context.
No values from the parent context will be accessible within the wrapped code.
- **_`ifNested?:`_**`'inherit' | 'reuse' | 'override'`
Sets the behavior of nested CLS context creation in case the method is invoked in an existing context. It has no effect if no parent context exist.
- `inherit` (default) - Run the callback with a shallow copy of the parent context.
Re-assignments of top-level properties will not be reflected in the parent context. However, modifications of existing properties _will_ be reflected.
- `reuse` - Reuse existing context without creating a new one. All modifications to the
existing context will be reflected.
- `override` - Run the callback with an new empty context.
No values from the parent context will be accessible within the wrapped code.

::: Note

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/04_api/02_module-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ All of the **`Cls{Middleware,Guard,Interceptor}Options`** take the following par
Whether to automatically resolve Proxy Providers in the enhancer (if any are registered).

- **_`initializePlugins?:`_**`boolean` (default _`true`_)
Whether to run the `onClsInit` hook for plugins as a part of the CLS context registration (runs before `resolveProxyProviders` just after `setup`).
Whether to run the initialization hooks for plugins as a part of the CLS context registration.

The `ClsMiddlewareOptions` additionally takes the following parameters:

Expand Down
18 changes: 16 additions & 2 deletions docs/docs/06_plugins/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Plugins can hook into the lifecycle of the `ClsModule` and the CLS context setup

## Usage

To use a plugin, pass it to the `forRoot` method of the `ClsModule`:
To use a plugin, pass it to the `forRoot` or `forRootAsync` method of the `ClsModule`:

```ts
ClsModule.forRoot({
Expand All @@ -18,12 +18,26 @@ ClsModule.forRoot({
});
```

If you need to inject Plugins from an external module, use the `ClsModule.registerPlugins()` registration to import the containing module.
```ts
ClsModule.forRootAsync({
// highlight-start
plugins: [new MyPlugin()],
// highlight-end
});
```

~~If you need to inject Plugins from an external module, use the `ClsModule.registerPlugins()` registration to import the containing module.~~

```ts
ClsModule.registerPlugins([new MyPlugin()]);
```

:::warning

The `ClsModule.registerPlugins` method is deprecated and will be removed in a future release due to a major refactor of the plugin architecture. All plugins must be registered via the root method.

:::

## Available plugins

For a list of plugins managed by the author of `nestjs-cls`, see the [Available Plugins](./01_available-plugins/index.md) page.
Expand Down
12 changes: 11 additions & 1 deletion packages/core/src/lib/cls-module/cls.module.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DynamicModule, Module, Type } from '@nestjs/common';
import { DynamicModule, Logger, Module, Type } from '@nestjs/common';
import { ClsModuleAsyncOptions, ClsModuleOptions } from '../cls.options';
import { ClsPluginManager } from '../plugin/cls-plugin-manager';

Expand Down Expand Up @@ -83,8 +83,18 @@ export class ClsModule {

/**
* Registers the given Plugins the module along with `ClsService`.
* @deprecated
* All plugins must be registered in the `ClsModule.forRoot` or `ClsModule.forRootAsync` options.
*
* Since the plugin API is still experimental, this method will print a warning, throw error
* and will be eventually removed, possibly in a minor release.
*/
static registerPlugins(plugins: ClsPlugin[]): DynamicModule {
const logger = new Logger('ClsModule');
logger.warn(
'The `ClsModule.registerPlugins` method is deprecated and will be removed in a future release. ' +
'All plugins must be registered in the `ClsModule.forRoot` or `ClsModule.forRootAsync` options.',
);
return {
module: ClsModule,
imports: ClsPluginManager.registerPlugins(plugins),
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/lib/cls.options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ export class ClsInitializerCommonOptions {
resolveProxyProviders? = true;

/**
* Whether to run the onClsInit hook for plugins as a part
* of the CLS context registration (runs before `resolveProxyProviders` just after `setup`)
* Whether to run the initialization hooks for plugins as a part
* of the CLS context registration in this initializer
*
* Default: `true`
*/
Expand Down
7 changes: 7 additions & 0 deletions packages/core/src/lib/cls.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,13 @@ export class ClsService<S extends ClsStore = ClsStore> {
await ProxyProviderManager.resolveProxyProviders(proxySymbols);
}

/**
* @deprecated This method will be removed in a future release and replaced
* with a different mechanism for plugin initialization.
*
* Since the plugin API is still experimental, this method will become a np-op
* and will be eventually removed, possibly in a minor release.
*/
async initializePlugins() {
const { ClsPluginManager } = await import(
'./plugin/cls-plugin-manager'
Expand Down
Loading