UNPKG

workflow

Version:

Workflow SDK - Build durable, resilient, and observable workflows

143 lines (108 loc) • 7.39 kB
--- title: WorkflowModule description: NestJS module that builds workflow bundles and registers the workflow controller. type: reference summary: Import WorkflowModule.forRoot() in your AppModule to enable workflows in a NestJS app. prerequisites: - /docs/getting-started/nestjs --- NestJS module that provides workflow functionality. It builds the workflow bundles on module initialization (`onModuleInit`) and registers the [`WorkflowController`](/docs/api-reference/workflow-nest/workflow-controller) that serves the workflow runtime routes. ## Usage Add `WorkflowModule.forRoot()` to the `imports` array of your root module. ```typescript title="src/app.module.ts" lineNumbers import { Module } from "@nestjs/common"; import { WorkflowModule } from "workflow/nest"; // [!code highlight] @Module({ imports: [WorkflowModule.forRoot()], // [!code highlight] }) export class AppModule {} ``` If your NestJS project compiles to CommonJS via SWC, pass `moduleType` and `distDir` so the builder can rewrite imports in the generated bundles: ```typescript title="src/app.module.ts" lineNumbers import { Module } from "@nestjs/common"; import { WorkflowModule } from "workflow/nest"; @Module({ imports: [ WorkflowModule.forRoot({ moduleType: "commonjs", // [!code highlight] distDir: "dist", // [!code highlight] }), ], }) export class AppModule {} ``` ## API signature ### Static methods #### `forRoot(options?)` Configures the module and returns a NestJS `DynamicModule` registered as `global`. It provides the resolved options under the `WORKFLOW_MODULE_OPTIONS` token, and (unless `skipBuild` is set) creates a [`NestLocalBuilder`](/docs/api-reference/workflow-nest/nest-local-builder) that builds the workflow bundles when the module initializes. #### `forRootAsync(options)` Same as `forRoot`, with the options produced by a factory so they can come from other providers. {/* @skip-typecheck - config snippet, WorkflowModule imported above */} ```typescript title="src/app.module.ts" lineNumbers WorkflowModule.forRootAsync({ imports: [ConfigModule], inject: [ConfigService], useFactory: (config: ConfigService) => ({ basePath: config.get("API_PREFIX"), }), }); ``` | Parameter | Type | Description | | --- | --- | --- | | `imports` | `unknown[]` | Optional. Modules whose exported providers the factory injects. | | `inject` | `unknown[]` | Optional. Providers passed to `useFactory`, in order. | | `useFactory` | `(...args) => WorkflowModuleOptions \| Promise<WorkflowModuleOptions>` | Returns the module options. | ### Parameters | Parameter | Type | Description | | --- | --- | --- | | `options` | `WorkflowModuleOptions` | Optional. Configures the workflow build. | #### WorkflowModuleOptions Extends [`NestBuilderOptions`](/docs/api-reference/workflow-nest/nest-local-builder#nestbuilderoptions): all builder options are accepted, plus `skipBuild`: | Option | Type | Default | Description | | --- | --- | --- | --- | | `skipBuild` | `boolean` | `true` when `VERCEL` is set, else `false` | Skip building workflow bundles on startup. The bundles must already exist; startup fails with an explicit error if they do not. | | `basePath` | `string` | adopted from `app.setGlobalPrefix()` | Route prefix the workflow endpoints are served under, applied to generated callback and webhook URLs. Set it when a reverse proxy mounts the app on a sub-path NestJS cannot see. | | `manageWorldLifecycle` | `boolean` | `false` | Start the target World's background workers with the app and close them on shutdown. Required for self-hosted Worlds, which otherwise never pick up runs. | | `preloadBundles` | `boolean` | `false` when `VERCEL` is set, else `true` | Load the generated bundles during startup instead of on the first request. On Vercel, dedicated functions serve the bundles, so there is nothing to preload. | | `bypassBodyParser` | `boolean` | `true` | Keep the application's body parsers away from `.well-known/workflow/v1`, so queue deliveries are not rejected by Express's 100 KB limit and signed webhook bodies stay byte-exact. The application's own routes are untouched. On Fastify, where the body limit is enforced per instance rather than per route, nothing is patched and a limit low enough to reject deliveries is reported at startup instead. | | `workingDir` | `string` | `process.cwd()` | Working directory for the NestJS application. | | `dirs` | `string[]` | `['src']` | Directories to scan for workflow files. | | `outDir` | `string` | `'.nestjs/workflow'` (relative to `workingDir`) | Output directory for generated workflow bundles. | | `watch` | `boolean` | `false` | Deprecated and ignored. Watch mode is not implemented for this builder. Use `nest start --watch`, which re-runs the startup build. | | `moduleType` | `'es6' \| 'commonjs'` | `'es6'` | SWC module compilation type. Set to `'commonjs'` if your NestJS project compiles to CommonJS (CJS) through SWC. | | `distDir` | `string` | `'dist'` | Directory where NestJS compiles `.ts` source files to `.js` (relative to `workingDir`). Used when `moduleType` is `'commonjs'`. Should match the `outDir` in your `tsconfig.json`. | | `sourcemap` | `boolean \| 'inline' \| 'linked' \| 'external' \| 'both'` | `'inline'` (dev) / `false` (prod) | Controls source maps on generated workflow bundles. Defaults to `'inline'` in development and `false` in production. Can also be set via the `WORKFLOW_SOURCEMAP` environment variable. | ### Returns `forRoot()` and `forRootAsync()` return a `DynamicModule` to include in the `imports` array of your root module. ## Injecting the resolved options Both factories export the resolved options under `WORKFLOW_MODULE_OPTIONS`: {/* @skip-typecheck - NestJS decorators require special TypeScript config */} ```typescript title="src/some.service.ts" lineNumbers import { Inject, Injectable } from "@nestjs/common"; import { WORKFLOW_MODULE_OPTIONS, type WorkflowModuleOptions, } from "workflow/nest"; @Injectable() export class SomeService { constructor( @Inject(WORKFLOW_MODULE_OPTIONS) private readonly options: WorkflowModuleOptions ) {} } ``` The older `WORKFLOW_OPTIONS` token resolves to the same value and is kept for compatibility. ## Lifecycle | Hook | Behaviour | | --- | --- | | `onModuleInit` | Takes the application's body parsers off the workflow routes (unless `bypassBodyParser` is `false`), reconciles the base path against `app.setGlobalPrefix()`, builds the bundles (or verifies they exist when `skipBuild` is set), optionally starts the World, and preloads the bundles. | | `onApplicationShutdown` | Closes the World when `manageWorldLifecycle` is set. Call `app.enableShutdownHooks()` so this runs on a signal. | <Callout type="warn"> `WorkflowModule` reads NestJS's global prefix and HTTP adapter through the injector, which only works while a single copy of `@nestjs/core` is installed. With two copies the injection tokens differ, prefix handling and the body-parser bypass both stop working, and a warning is logged at startup. </Callout> <Callout type="warn"> Workflows and steps run outside the NestJS injector, so providers cannot be injected into `"use workflow"` or `"use step"` code. See [NestJS dependency injection is not available in workflows and steps](/docs/getting-started/nestjs#nestjs-dependency-injection-is-not-available-in-workflows-and-steps). </Callout>