Skip to main content

Generator architecture

yarn generate is the registry compiler for Open Saasframe. It scans enabled modules, applies built-in generator extensions, loads optional module-declared plugins, and emits the generated files consumed by routing, DI bootstrap, CLI dispatch, widgets, notifications, search, and other runtime registries.

High-level flow​

Two extension layers​

Open Saasframe uses two additive extension layers during generation:

  • Built-in generator extensions in packages/cli/src/lib/generators/extensions/
  • Module-declared generator plugins exposed from a module's optional generators.ts

Built-in extensions​

These are framework-owned registries that every app can rely on without extra plugin authoring:

  • search configs
  • notifications and notification renderers
  • payments client notification adapters
  • notification handlers
  • message types, objects, and client renderers
  • AI tools
  • events
  • analytics widgets/config
  • translatable fields
  • enrichers
  • interceptors
  • component overrides
  • inbox actions
  • guards
  • command interceptors
  • frontend/backend page middleware
  • dashboard widgets
  • injection widgets and injection tables

Module-declared plugins​

Modules can extend generation without editing the generator package by exporting generatorPlugins from generators.ts.

Plugin contract summary:

FieldMeaning
idUnique registry/plugin family ID
conventionFileModule-local file to scan for plugin entries
importPrefixPrefix for generated import variable names
configExpr(importName, moduleId)Expression that turns a discovered module file into one generated entry
outputFileNameGenerated file produced by the plugin
buildOutput(...)Function that renders the generated TypeScript source
bootstrapRegistrationOptional bootstrap-time registration contribution

This is what keeps generator architecture additive: new registry families can ship as module-owned plugin definitions rather than as hard-coded cases in the root generator.

Core generated files​

These are the primary generated files emitted by the core generator pipeline.

Generated filePurpose
modules.generated.tsFull discovered module graph, including rich runtime metadata used by framework registries and compatibility paths.
modules.runtime.generated.tsRuntime-focused module registry used by the current lightweight bootstrap/runtime path.
modules.app.generated.tsApp bootstrap registry used by application startup without route-heavy coupling.
modules.cli.generated.tsCLI module registry loaded by yarn saasframe for module-owned commands.
cli-modules.generated.tsConvenience export/wrapper around the generated CLI module list.
bootstrap-modules.generated.tsBootstrap-oriented module registry helpers used during startup assembly.
bootstrap-registrations.generated.tsGenerated bootstrap registration calls, including optional plugin-contributed registrations.
entities.generated.tsMikroORM entity registry for discovered modules.
entities.ids.generated.tsStable generated entity ID constants.
entity-fields-registry.tsGenerated entity-fields registry used by encryption and related metadata consumers.
di.generated.tsDiscovered DI registrars for enabled modules.
frontend-routes.generated.tsFrontend route manifest with lazy route-loading metadata.
backend-routes.generated.tsBackend route manifest with lazy route-loading metadata.
api-routes.generated.tsAPI route manifest with method/path metadata and lazy handlers.
subscribers.generated.tsLegacy/generated subscriber registry compatibility file.
openapi.generated.jsonGenerated OpenAPI document built from discovered API routes and route metadata.
module-package-sources.cssGenerated stylesheet that tracks module package source markers for runtime styling/diagnostics.

Built-in extension outputs​

These generated files come from built-in generator extensions.

Generated fileSource extensionPurpose
search.generated.tssearchSearch module config registry.
notifications.generated.tsnotificationsNotification type registry.
notifications.client.generated.tsnotificationsClient-side notification renderers.
payments.client.generated.tsnotificationsPayment-related notification/client adapters.
notification-handlers.generated.tsnotificationsReactive notification side-effect handlers.
message-types.generated.tsmessagesMessage type registry.
message-objects.generated.tsmessagesMessage object registry.
messages.client.generated.tsmessagesClient-side message object renderers/adapters.
ai-tools.generated.tsai-toolsAI/MCP tool registry.
events.generated.tseventsEvent definitions and event registry metadata.
analytics.generated.tsanalyticsAnalytics/dashboard configuration registry.
translations-fields.generated.tstranslatable-fieldsTranslatable field declarations by module/entity.
enrichers.generated.tsenrichersResponse enricher registry.
interceptors.generated.tsinterceptorsAPI interceptor registry.
component-overrides.generated.tscomponent-overridesUI component override registry.
inbox-actions.generated.tsinbox-actionsInbox action registry.
guards.generated.tsguardsMutation/page/runtime guard registry.
command-interceptors.generated.tscommand-interceptorsCommand interceptor registry.
frontend-middleware.generated.tspage-middlewareFrontend page middleware registry.
backend-middleware.generated.tspage-middlewareBackend page middleware registry.
dashboard-widgets.generated.tsdashboard-widgetsDashboard widget registry.
injection-widgets.generated.tsinjection-widgetsInjection widget registry.
injection-tables.generated.tsinjection-widgetsInjection table/slot registry.

Why this architecture exists​

  • Module owners keep CLI, UI, API, and generation logic close to the same feature boundary.
  • Disabling a module naturally removes its discovered registries and plugin output.
  • Standalone apps and monorepos share the same mental model, even though one scans source trees and the other scans compiled package output.
  • The generator remains additive: new registry families can be introduced without destabilizing the root CLI entrypoint.

Relationship to cache CLI​

The cache command is a normal cli.ts discovery case, not a generator plugin. It is documented separately in Cache CLI architecture. That page focuses on cache-specific runtime behavior, while this page documents the broader generator system that makes module-owned commands discoverable.