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

Update docs #106

Merged
merged 4 commits into from
Jan 22, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/run-tests.workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node: [16, 18, 20]
node: [18, 20]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
Expand Down
28 changes: 0 additions & 28 deletions .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs

This file was deleted.

874 changes: 0 additions & 874 deletions .yarn/releases/yarn-3.6.1.cjs

This file was deleted.

893 changes: 893 additions & 0 deletions .yarn/releases/yarn-4.0.2.cjs

Large diffs are not rendered by default.

6 changes: 1 addition & 5 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
nodeLinker: node-modules

plugins:
- path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
spec: "@yarnpkg/plugin-workspace-tools"

yarnPath: .yarn/releases/yarn-3.6.1.cjs
yarnPath: .yarn/releases/yarn-4.0.2.cjs
6 changes: 3 additions & 3 deletions docs/docs/01_introduction/01_installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@ import TabItem from '@theme/TabItem';
Install as any other NPM package using your favorite package manager.

<Tabs>
<TabItem value="apple" label="npm" default>
<TabItem value="npm" label="npm" default>

```sh
npm install nestjs-cls
```

</TabItem>
<TabItem value="orange" label="yarn">
<TabItem value="yarn" label="yarn">

```sh
yarn add nestjs-cls
```

</TabItem>
<TabItem value="banana" label="pnpm">
<TabItem value="pnpm" label="pnpm">

```sh
pnpm add nestjs-cls
Expand Down
4 changes: 3 additions & 1 deletion docs/docs/01_introduction/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ _Also, if you use some tracing library (like `otel`), it most likely already use

## Highlights

> **New**: Version `3.0` introduces [_Proxy Providers_](../03_features-and-use-cases/06_proxy-providers.md) as an alternative to the imperative API. (Minor breaking changes were introduced, see [Migration guide](../06_migration-guide/01_v2x-v3x.md)).
> **New** Version `4.0` brings support for [Plugins](!!) which enable pre-built integrations with other libraries and frameworks. (See [Migration guide](../10_migration-guide/01_v3x-v4x.md) for breaking changes).

> Version `3.0` introduces [_Proxy Providers_](../03_features-and-use-cases/06_proxy-providers.md) as an alternative to the imperative API. (Minor breaking changes were introduced, see [Migration guide](../10_migration-guide/01_v2x-v3x.md)).

> Version `2.0` brings advanced [type safety and type inference](../03_features-and-use-cases/05_type-safety-and-type-inference.md). However, it requires features from `typescript >= 4.4` - Namely allowing `symbol` members in interfaces. If you can't upgrade but still want to use this library, install version `1.6.2`, which lacks the typing features.
46 changes: 46 additions & 0 deletions docs/docs/02_setting-up-cls-context/04_using-a-decorator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Using a Decorator

The `@UseCls()` decorator can be used at a method level to declaratively wrap the method with a `cls.run()` call. This method should only be used [outside of the context of a web request](../03_features-and-use-cases/04_usage-outside-of-web-request.md).

:::info

Please keep in mind, that since the CLS context initialization _can_ be async, the `@UseCls()` decorator can _only_ be used on _async_ function (those that return a `Promise`).

:::

Since there is no request, the `setup` function will not receive a `Request` object. Instead, it will receive the `this` context of the class instance (this also applies to the `idGenerator`), the `ClsService` reference and all the arguments passed to the decorated method.

```ts
@Injectable()
class SomeService {
constructor(
private readonly cls: ClsService,
private readonly otherService: OtherService,
) {}

@UseCls<[string]>({
generateId: true,
// highlight-start
idGenerator: function (this: SomeService) {
return this.generateId();
},
setup: function (this: SomeService, cls: ClsService, value: string) {
cls.set('some-key', 'some-value');
},
// highlight-end
})
async startContextualWorkflow(value: string) {
return this.otherService.doSomething(value);
}

private generateId() {
return Math.random();
}
}
```

:::warning

It is important to define the `setup` and `idGenerator` functions as `function`s, not arrow functions, so that the `this` context is properly bound.

:::
9 changes: 0 additions & 9 deletions docs/docs/02_setting-up-cls-context/04_using-a-decurator.md

This file was deleted.

7 changes: 7 additions & 0 deletions docs/docs/02_setting-up-cls-context/05_using_cls_run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Using the ClsService Instance

All other methods of setting up the CLS context ultimately use the `ClsService#run` or `ClsService#enter` methods.

If all other attempts fail or you want to have a more fine-grained control over the CLS context, you can use `ClsService` instance to wrap any piece of code in a CLS context.

An example is available in the [Usage outside of web request](../03_features-and-use-cases/04_usage-outside-of-web-request.md) section.
2 changes: 1 addition & 1 deletion docs/docs/02_setting-up-cls-context/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Setting up the CLS context

This package provides **three** methods of setting up the CLS context for incoming requests. This is mainly due to the fact that different underlying platforms are compatible with only some of these methods - see [Compatibility considerations](../05_considerations/02_compatibility.md).
This package provides multiple methods of setting up the CLS context for incoming requests. This is mainly due to the fact that different underlying platforms are compatible with only some of these methods - see [Compatibility considerations](../05_considerations/02_compatibility.md).

For HTTP transports, the context can be preferably set up in a `ClsMiddleware`. For all other platforms, or cases where the `ClsMiddleware` is not applicable, this package also provides a `ClsGuard` and `ClsInterceptor`. While both of these also work with HTTP, they come with some caveats, see below.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Usage outside of web request

Sometimes, a part of the app that relies on the CLS storage might need to be called outside of the context of a web request - for example, in a Cron job, while consuming a Queue or during the application bootstrap. In such cases, there are no enhancers that can be bound to the handler to set up the context.
Sometimes, a part of the app that relies on the CLS storage might need to be called outside of the context of a web request - for example, in a Cron job, while consuming a Queue, during the application bootstrap or in CLI apps.

In such cases, there are no enhancers that can be bound to the handler to set up the context.

Therefore, you as the the developer are responsible for wrapping the execution with `ClsService#run`, or using the `@UseCls` decorator. In any case, if any following code depends on some context variables, these need to be set up manually.

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/04_api/01_service-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ The `S` type parameter is used as the type of custom `ClsStore`.

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

- **_`ifNested?:`_** `'inherit' | 'reuse' | 'override'`
- **_`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.
Expand Down
48 changes: 24 additions & 24 deletions docs/docs/04_api/02_module-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,26 @@

The `ClsModule.forRoot()` method takes the following **`ClsModuleOptions`**:

- **_`middleware?:`_ `ClsMiddlewareOptions`**
- **_`middleware?:`_**`ClsMiddlewareOptions`
An object with additional options for the `ClsMiddleware`, see [below](#middleware--enhancer-options).

- **_`guard?:`_ `ClsGuardOptions`**
- **_`guard?:`_**`ClsGuardOptions`
An object with additional options for the `ClsGuard`, see [below](#middleware--enhancer-options).

- **_`interceptor?:`_ `ClsInterceptorOptions`**
- **_`interceptor?:`_**`ClsInterceptorOptions`
An object with additional options for the `ClsInterceptor`, see [below](#middleware--enhancer-options).

- **_`global?:`_ `boolean`** (default _`false`_)
- **_`global?:`_**`boolean`\*\* (default _`false`_)
Whether to make the module global, so you do not have to import `ClsModule.forFeature()` in other modules.

- **_`proxyProviders?:`_ `Type[]`**
- **_`proxyProviders?:`_**`Type[]`
Array of [Proxy Providers](../03_features-and-use-cases/06_proxy-providers.md) that should be registered in the root module. Currently only accepts sync class Proxy providers, use `ClsModule.forFeatureAsync()` for more complex use-cases.

`ClsModule.forRootAsync()` is also available. You can supply the usual `imports`, `inject` and `useFactory` parameters as usual.

:::info

**Please note**: If you intend to use multiple enhancers at the same time (e.g. initialize the CLS context in a middleware and then set some CLS variables additional CLS variables in an interceptor), be aware that the only the first one in the chain will set the Request ID.
**Please note**: If you intend to use multiple enhancers at the same time (e.g. initialize the CLS context in a middleware and then set some additional CLS variables in an interceptor), be aware that the only the first one in the chain will set the Request ID.

:::

Expand All @@ -33,62 +33,62 @@ The `ClsModule.forFeature()` method can be used to register a [Proxy Providers](

The `ClsModule.forFeatureAsync()` method accepts either `ClsModuleProxyClassProviderOptions` or `ClsModuleProxyFactoryProviderOptions` that both accept these options:

- **_`provide?:`_ `any`**
- **_`provide?:`_**`any`
Custom injection token to use for the provider. In case of a class provider, this parameter is optional, as the class reference passed to `useClass` will be used by default.

- **_`imports?`_ `any[]`**
- **_`imports?`_**`any[]`
Optional list of imported modules that export the providers which are required for the provider.

- **_`extraProviders?:`_ `Provider[]`**
- **_`extraProviders?:`_**`Provider[]`
Optional list of additional providers that should be available to the Proxy. Useful for passing configuration from a parent dynamic module.

The `ClsModuleProxyClassProviderOptions` interface further accepts:

- **_`useClass:`_ `Type`**
- **_`useClass:`_**`Type`
The target class that will be used by this Proxy Provider. Make sure it is decorated with `@InjectableProxy`.

The `ClsModuleProxyFactoryProviderOptions` interface further accepts:

- **_`inject:`_ `any[]`**
- **_`inject:`_**`any[]`
An array of injection tokens for providers used in the `useFactory`.

- **_`useFactory:`_ `(...args: any[]) => any`**
- **_`useFactory:`_**`(...args: any[]) => any`
Factory function that accepts an array of providers in the order of the according tokens in the `inject` array. Returns (or resolves with) an object (or a function) that will be used by this Proxy Provider.

- **_`type?:`_ `'function' | 'object'`**
- **_`type?:`_**`'function' | 'object'`
Whether the Proxy Provider should be a function or an object. Defaults to `'object'`. See [Caveats](../03_features-and-use-cases/06_proxy-providers.md#caveats) for more information.

## Middleware & Enhancer options

All of the **`Cls{Middleware,Guard,Interceptor}Options`** take the following parameters (either in `ClsModuleOptions` or directly when instantiating them manually):

- **_`mount?:`_ `boolean`** (default _`false`_)
- **_`mount?:`_**`boolean` (default _`false`_)
Whether to automatically mount the middleware/guard/interceptor to every route (not applicable when instantiating them manually)

- **_`generateId?:`_ `boolean`** (default _`false`_)
- **_`generateId?:`_**`boolean` (default _`false`_)
Whether to automatically generate a request ID. It will be available under the `CLS_ID` key.

- **_`idGenerator?:`_ `(req: Request) => string | Promise<string>`**
**_`idGenerator?:`_ `(ctx: ExecutionContext) => string | Promise<string>`**
- **_`idGenerator?:`_**`(req: Request) => string | Promise<string>`
**_`idGenerator?:`_**`(ctx: ExecutionContext) => string | Promise<string>`
An optional function for generating the request ID. It takes the `Request` object (or the `ExecutionContext` in case of a Guard or Interceptor) as an argument and (synchronously or asynchronously) returns a string. The default implementation uses `Math.random()` to generate a string of 8 characters.

- **_`setup?:`_ `(cls: ClsService, req: Request) => void | Promise<void>;`**
**_`setup?:`_ `(cls: ClsService, ctx: ExecutionContext) => void | Promise<void>;`**
- **_`setup?:`_**`(cls: ClsService, req: Request) => void | Promise<void>;`
**_`setup?:`_**`(cls: ClsService, ctx: ExecutionContext) => void | Promise<void>;`
Function that executes after the CLS context had been initialised. It can be used to put additional variables in the CLS context.

- **_`resolveProxyProviders?:`_ `boolean`** (default _`true`_)
- **_`resolveProxyProviders?:`_**`boolean` (default _`true`_)
Whether to automatically resolve Proxy Providers in the enhancer (if any are registered).

- **_`initializePlugins?:`_ `boolean`** (default _`true`_)
- **_`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`).

The `ClsMiddlewareOptions` additionally takes the following parameters:

- **_`saveReq?:`_ `boolean`** (default _`true`_)
- **_`saveReq?:`_**`boolean` (default _`true`_)
Whether to store the _Request_ object to the context. It will be available under the `CLS_REQ` key.

- **_`saveRes?:`_ `boolean`** (default _`false`_)
- **_`saveRes?:`_**`boolean` (default _`false`_)
Whether to store the _Response_ object to the context. It will be available under the `CLS_RES` key

- **_`useEnterWith?:`_ `boolean`** (default _`false`_)
- **_`useEnterWith?:`_**`boolean` (default _`false`_)
Set to `true` to set up the context using a call to [`AsyncLocalStorage#enterWith`](https://nodejs.org/api/async_context.html#async_context_asynclocalstorage_enterwith_store) instead of wrapping the `next()` call with the safer [`AsyncLocalStorage#run`](https://nodejs.org/api/async_context.html#async_context_asynclocalstorage_run_store_callback_args). Most of the time this should not be necessary, but [some frameworks](#graphql) are known to lose the context with `run`.
28 changes: 0 additions & 28 deletions docs/docs/06_migration-guide/01_v2x-v3x.md

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Prisma adapter

## Installation

<Tabs>
<TabItem value="npm" label="npm" default>

```bash
npm install @nestjs-cls/transactional-adapter-prisma
```

</TabItem>
<TabItem value="yarn" label="yarn">

```bash
yarn add @nestjs-cls/transactional-adapter-prisma
```

</TabItem>
<TabItem value="pnpm" label="pnpm">

```bash
pnpm add @nestjs-cls/transactional-adapter-prisma
```

</TabItem>
</Tabs>

## Registration

```ts
ClsModule.forRoot({
plugins: [
new ClsPluginTransactional({
imports: [
// module in which the PrismaClient is provided
PrismaModule
],
adapter: new TransactionalAdapterPrisma({
// the injection token of the PrismaClient
prismaInjectionToken: PrismaService,
}),
}),
],
}),
```

## Typing & usage

The `tx` property on the `TransactionHost<TransactionalAdapterPrisma>` refers to the transactional `PrismaClient` instance when used in a transactional context. It is the instance that is passed to the `prisma.$transaction(( tx ) => { ... })` callback.

Outside of a transactional context, it refers to the regular `PrismaClient` instance (but is typed as the transactional one).

## Example

```ts title="user.service.ts"
@Injectable()
class UserService {
constructor(private readonly userRepository: UserRepository) {}

@Transactional()
async runTransaction() {
// highlight-start
// both methods are executed in the same transaction
const user = await this.userRepository.createUser('John');
const foundUser = await this.userRepository.getUserById(r1.id);
// highlight-end
assert(foundUser.id === user.id);
}
}
```

```ts title="user.repository.ts"
@Injectable()
class UserRepository {
constructor(
private readonly txHost: TransactionHost<TransactionalAdapterPrisma>,
) {}

async getUserById(id: number) {
// highlight-start
// txHost.tx is typed as the transactional PrismaClient
return this.txHost.tx.user.findUnique({ where: { id } });
// highlight-end
}

async createUser(name: string) {
return this.txHost.tx.user.create({
data: { name: name, email: `${name}@email.com` },
});
}
}
```

## Caveats

Since Prisma generates its own client to `node_modules`, this plugin works with the assumption that the types for the client are available as `@prisma/client`. If you have a different setup, you might need to use `declare module '@prisma/client'` to make typescript happy.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Creating a custom adapter

TODO: To be written.
Loading
Loading