@auto-engineer/server-generator-apollo-emmett
v1.158.0
Published
Code generator that scaffolds event-sourced GraphQL servers using Apollo Server, type-graphql, and the Emmett event sourcing framework. Takes a narrative model and produces a fully runnable server with commands, events, projections, queries, and reactors.
Downloads
4,355
Readme
@auto-engineer/server-generator-apollo-emmett
Code generator that scaffolds event-sourced GraphQL servers using Apollo Server, type-graphql, and the Emmett event sourcing framework. Takes a narrative model and produces a fully runnable server with commands, events, projections, queries, and reactors.
Purpose
Without this package, you would need to manually write event sourcing boilerplate (decide/evolve functions), GraphQL resolvers, command/event type definitions, projections, and reactor wiring for every moment in your narrative model.
This package reads a Model object (scenes, messages, integrations, narratives) and generates a complete server/ directory containing an Apollo GraphQL server that follows Emmett's event sourcing patterns -- including EJS-templated code for each moment type (command, query, react).
Installation
pnpm add @auto-engineer/server-generator-apollo-emmettQuick Start
1. Register the command handlers
import { COMMANDS } from '@auto-engineer/server-generator-apollo-emmett';
import { createMessageBus } from '@auto-engineer/message-bus';
const bus = createMessageBus();
COMMANDS.forEach((cmd) => bus.registerCommand(cmd));2. Generate a server from a model
await bus.send({
type: 'GenerateServer',
data: {
model: myModel, // a Model object from @auto-engineer/narrative
destination: '.',
},
requestId: 'req-1',
});This creates a server/ directory at the destination with a runnable Apollo GraphQL server.
3. Initialize a bare server (no model needed)
await bus.send({
type: 'InitializeServer',
data: {
destination: '.',
},
requestId: 'req-2',
});Creates a minimal server with a health endpoint, ready for incremental generation.
How-to Guides
Run via CLI
auto build:backend --destination=.
auto initialize:server --destination=.Handle generation results
const events = await bus.send({
type: 'GenerateServer',
data: { model, destination: '.' },
requestId: 'req-1',
});
for (const event of events) {
switch (event.type) {
case 'ServerGenerated':
console.log(`Server written to ${event.data.serverDir}`);
break;
case 'MomentGenerated':
console.log(`Generated: ${event.data.sceneName}/${event.data.momentName}`);
break;
case 'ServerGenerationFailed':
console.error(event.data.error);
break;
}
}Incremental generation with change sets
When the model changes, pass a changeSet to only regenerate affected moments:
await bus.send({
type: 'GenerateServer',
data: {
model,
destination: '.',
changeSet: {
added: ['scene-dir/moment-dir'],
removed: ['old-scene/old-moment'],
changed: ['scene-dir/updated-moment'],
sharedTypesChanged: false,
allAffected: ['scene-dir/moment-dir', 'scene-dir/updated-moment'],
deltas: {},
},
},
requestId: 'req-3',
});API Reference
Exports
import { COMMANDS } from '@auto-engineer/server-generator-apollo-emmett';
import type {
GenerateServerCommand,
GenerateServerEvents,
ServerGeneratedEvent,
ServerGenerationFailedEvent,
MomentGeneratedEvent,
InitializeServerCommand,
ServerInitializedEvent,
ServerInitializationFailedEvent,
} from '@auto-engineer/server-generator-apollo-emmett';Commands
| Command | CLI Alias | Description |
|---------|-----------|-------------|
| GenerateServer | build:backend | Generate event-sourced GraphQL server from a model |
| InitializeServer | initialize:server | Create a bare runnable server with health endpoint |
GenerateServerCommand
type GenerateServerCommand = Command<
'GenerateServer',
{
model: Model;
destination: string;
changeSet?: ChangeSet;
isFirstRun?: boolean;
newState?: GenerationState;
}
>;InitializeServerCommand
type InitializeServerCommand = Command<
'InitializeServer',
{
destination: string;
}
>;Events
| Event | Emitted when |
|-------|-------------|
| ServerGenerated | Full or incremental generation completes successfully |
| ServerGenerationFailed | Generation fails (includes error details, scene/moment context) |
| MomentGenerated | An individual moment is scaffolded |
| ServerInitialized | Bare server skeleton is created |
| ServerInitializationFailed | Server initialization fails |
Architecture
src/
├── index.ts # COMMANDS array, re-exports types
├── server.ts # Runtime server entry (copied into generated output)
├── commands/
│ ├── generate-server.ts # GenerateServer command handler
│ └── initialize-server.ts # InitializeServer command handler
├── codegen/
│ ├── scaffoldFromSchema.ts # Orchestrates file plan generation and writing
│ ├── templateHelpers.ts # Helpers for EJS templates
│ ├── types.ts # Message, Field, GwtCondition types
│ ├── extract/ # Extractors for commands, events, states, projections, queries
│ │ ├── commands.ts
│ │ ├── events.ts
│ │ ├── gwt.ts
│ │ ├── imports.ts
│ │ ├── messages.ts
│ │ ├── projection.ts
│ │ ├── query.ts
│ │ ├── states.ts
│ │ ├── step-converter.ts
│ │ ├── step-types.ts
│ │ └── type-helpers.ts
│ └── templates/ # EJS templates per moment type
│ ├── command/ # decide, evolve, handle, commands, events, state, mutation.resolver, register
│ ├── query/ # projection, query.resolver, events, state
│ └── react/ # react handler, register, events
├── domain/shared/ # Runtime code copied into generated server
│ ├── types.ts # GraphQLContext, ReactorContext
│ ├── graphql-types.ts # MutationResponse, MutationError
│ ├── ReadModel.ts # In-memory read model wrapper
│ ├── sendCommand.ts # Command dispatch helper
│ └── reactorSpecification.ts # Test helper for reactor assertions
└── utils/ # Runtime utilities copied into generated server
├── loadResolvers.ts # Glob-loads resolver classes
├── loadProjections.ts # Glob-loads projection definitions
└── loadRegisterFiles.ts # Glob-loads moment registration filesGeneration flow
flowchart TB
A[GenerateServer command] --> B{First run or change set?}
B -- First run --> C[Clean server directory]
B -- Incremental --> D[Remove deleted moments]
C --> E[Copy runtime files]
D --> E
E --> F[Extract messages from model specs]
F --> G[Build GWT mappings per moment]
G --> H[Render EJS templates into file plans]
H --> I[Write files to disk]
I --> J[Write config files: package.json, tsconfig, vitest, biome]
J --> K[Emit MomentGenerated / ServerGenerated events]Generated server structure
server/
├── src/
│ ├── server.ts # Apollo Server entry point with Emmett event store
│ ├── utils/
│ │ ├── loadResolvers.ts
│ │ ├── loadProjections.ts
│ │ └── loadRegisterFiles.ts
│ └── domain/
│ ├── shared/
│ │ ├── types.ts # GraphQLContext, ReactorContext
│ │ ├── graphql-types.ts # MutationResponse
│ │ ├── ReadModel.ts
│ │ └── sendCommand.ts
│ └── narratives/
│ ├── health/
│ │ └── query.resolver.ts
│ └── {narrative}_{scene}/
│ └── {moment}/
│ ├── commands.ts # (command type)
│ ├── events.ts
│ ├── state.ts
│ ├── decide.ts
│ ├── evolve.ts
│ ├── handle.ts
│ ├── mutation.resolver.ts
│ ├── decide.specs.ts
│ ├── register.ts
│ ├── projection.ts # (query type)
│ ├── projection.specs.ts
│ ├── query.resolver.ts
│ ├── react.ts # (react type)
│ └── react.specs.ts
├── package.json
├── tsconfig.json
├── vitest.config.ts
└── biome.jsonMoment types
| Type | Generated files | Pattern |
|------|----------------|---------|
| command | commands, events, state, decide, evolve, handle, mutation.resolver, decide.specs, register | Mutation resolver dispatches command; decide produces events; evolve updates state |
| query | events, projection, state, projection.specs, query.resolver | Query resolver reads from in-memory projection built from events |
| react | events, react handler, react.specs, register | Reactor listens to events and sends commands in response |
Key dependencies
| Package | Role |
|---------|------|
| @auto-engineer/narrative | Model type definitions (Scene, Moment, Model) |
| @auto-engineer/message-bus | Command handler registration and dispatch |
| @event-driven-io/emmett | Event sourcing runtime (event store, projections, message bus) |
| @event-driven-io/emmett-sqlite | SQLite-backed event store |
| apollo-server | GraphQL server |
| type-graphql | Decorator-based GraphQL schema definitions |
| ejs | Template rendering for code generation |
