fragment-ts
v2.0.0
Published
Spring Boot-style framework for TypeScript with Express and TypeORM
Readme
Fragment TS
Fragment TS is a Spring Boot-inspired TypeScript framework for Express and TypeORM, built around dependency injection and decorators, with a fully modular CLI.
This README is intentionally long and comprehensive so it can serve as a landing page for the framework site.
Table of Contents
- Overview
- Quick Start
- Philosophy
- Project Structure
- Bootstrapping
- Dependency Injection
- HTTP Pipeline
- TypeORM
- Plugins
- Notifications
- Jobs and Cron
- Documentation Generator
- CLI Overview
- Configuration
- Testing
- Logging
- Troubleshooting
- FAQ
- Glossary
Overview
Fragment TS is designed for teams who want consistency, explicit structure, and fast iteration in TypeScript. The framework centers on class decorators that describe behavior and a DI container that resolves dependencies.
Key ideas:
- Everything is a class with metadata.
- No hidden magic: configuration is in
fragment.json. - One unified CLI that can be called programmatically.
- Features are optional but designed to work together.
Quick Start
- Install the CLI:
npm install -g fragment-ts - Initialize:
fragment init my-app - Move into the directory:
cd my-app - Initialize Env:
fragment env:init - Run the dev server:
fragment serve
Hello World example:
import {
FragmentApplication,
FragmentWebApplication,
Controller,
Get,
} from "fragment-ts";
@Controller("/")
class HelloController {
@Get()
index() {
return { message: "Hello Fragment" };
}
}
@FragmentApplication({ port: 3000 })
class App {}
async function bootstrap() {
const app = new FragmentWebApplication();
await app.bootstrap(App);
}
bootstrap();Philosophy
Fragment TS borrows the clarity of Spring Boot and the ergonomics of modern TypeScript. Your application should read like an architecture diagram. Your configuration should be explicit and stable. Your framework should be a partner, not a black box.
Project Structure
Structure is controlled by fragment.json:
layered:src/controllers,src/services,src/repositoriesmodule:src/modules/<name>/...feature:src/features/<name>/...
The CLI generators honor the structure you choose.
Bootstrapping
import { FragmentApplication, FragmentWebApplication } from "fragment-ts";
@FragmentApplication({ port: 3000, autoScan: true })
class Application {}
async function bootstrap() {
const app = new FragmentWebApplication();
await app.bootstrap(Application);
}
bootstrap();Dependency Injection
Constructor injection is automatic, property injection is opt-in.
import { Service, Autowired, Value } from "fragment-ts";
@Service()
class MailService {
@Value("${MAIL_FROM:[email protected]}")
private from!: string;
}
@Service()
class UserService {
constructor(private mailer: MailService) {}
@Autowired()
private secondaryMailer!: MailService;
}HTTP Pipeline
Fragment wraps Express and adds middleware, guards, interceptors, and exception filters.
import { Controller, Get, FragmentGuard } from "fragment-ts";
class AuthGuard {
canActivate(req: any) {
return !!req.user;
}
}
@FragmentGuard(AuthGuard)
@Controller("/secure")
class SecureController {
@Get()
profile() {
return { ok: true };
}
}TypeORM
TypeORM is wired through TypeORMModule and fragment.json.
Use @InjectRepository to access repositories.
Plugins
Plugins are first-class and can be installed with fragment add <package>.
Use qualifiers to disambiguate multiple plugin instances.
Mailers can be registered via @Mailer or via config-driven providers in fragment.json.
Templates can be registered with @MailTemplate.
Notifications
Notifications resolve channels through @NotificationChannel metadata.
Default channels are configured in fragment.json.
Jobs and Cron
Jobs can be defined with @Job() and scheduled with @Cron() or the fluent scheduler.
Documentation Generator
Use @ApiTag, @ApiOperation, @ApiResponse, and @ApiProperty to generate OpenAPI-style docs.
Runtime docs are served at /docs and /docs.json.
Per-module runtime docs can be served at /docs/modules/:module.
CLI Overview
The CLI (fragment or frg) provides scaffolding, diagnostics, and automation.
Selected commands:
- fragment init [dir]
- fragment init --type=plugin
- fragment serve
- fragment build
- fragment test
- fragment lint
- fragment route:list
- fragment config:cache
- fragment cache:clear
- fragment env:init
- fragment env:list
- fragment env:use
- fragment env:diff [file]
- fragment doc:generate
- fragment plugin:list
- fragment plugin:info
- fragment plugin:remove
- fragment plugin:enable
- fragment plugin:disable
- fragment add
- fragment make:controller
- fragment make:service
- fragment make:resource
- fragment make:dto
- fragment make:middleware
- fragment make:guard
- fragment make:job
- fragment make:mail
- fragment make:notification
- fragment make:view
- fragment make:store
- fragment make:component
- fragment make:template
Configuration
Fragment is configured via fragment.json.
Example:
{
"structure": { "type": "module" },
"verbose": false,
"logging": { "level": "info", "structured": false },
"docs": {
"path": "/docs",
"enabled": true,
"perModule": true,
"perModuleRoutes": true
},
"database": {
"type": "postgres",
"host": "localhost",
"port": 5432,
"username": "postgres",
"password": "password",
"database": "fragment"
},
"mail": {
"default": "primary",
"mailers": {
"primary": { "driver": "console", "from": "[email protected]" }
}
},
"notifications": { "defaultChannels": ["mail"] },
"jobs": { "enabled": true, "timezone": "UTC" },
"plugins": ["my-fragment-plugin"],
"pluginAutoQualify": true
}Configuration keys (high-level):
- structure.type
- verbose
- logging.level
- logging.structured
- database.*
- database.entities
- database.migrations
- mail.default
- mail.mailers
- mail.templatesDir
- mail.queue.enabled
- notifications.defaultChannels
- jobs.enabled
- jobs.timezone
- docs.enabled
- docs.path
- docs.outputDir
- docs.template
- docs.perModule
- docs.perModuleRoutes
- plugins
- pluginAutoQualify
Testing
Fragment includes a lightweight test runner:
import { describe, it, expect, initTestRunner } from "fragment-ts";
initTestRunner();
describe("math", () => {
it("adds", () => {
expect(1 + 1).toBe(2);
});
});Logging
Use FragmentLogger with configurable levels and structured output.
verbose or logging.level controls the output verbosity.
Feature Index
Core decorators:
- @FragmentApplication(options)
- @Controller(path?)
- @Service()
- @FragmentRepository()
- @Injectable(scope?)
- @AutoConfiguration()
Injection decorators:
- @Autowired()
- @Inject(token)
- @InjectRepository(entity)
- @Value(expression)
- @Qualifier(name)
- @Optional()
- @Lazy()
HTTP decorators:
- @Get(path?)
- @Post(path?)
- @Put(path?)
- @Delete(path?)
- @Patch(path?)
- @Body()
- @Param(name?)
- @Query(name?)
- @Header(name?)
- @Req()
- @Res()
Pipeline decorators:
- @FragmentMiddleware(MiddlewareClass)
- @FragmentGuard(GuardClass)
- @FragmentInterceptor(InterceptorClass)
- @FragmentExceptionFilter(ExceptionFilterClass)
Lifecycle decorators:
- @PostConstruct()
- @PreDestroy()
- @OnStartup(order?)
- @OnShutdown(order?)
Plugin decorators:
- @Plugin(options)
- @Plugin(token, qualifier?) (property)
- @OnPluginInit(order?)
- @OnPluginShutdown(order?)
Mail decorators:
- @Mailer(options)
- @Mail(qualifier?) (property)
- @MailTemplate(options)
Notification decorators:
- @NotificationChannel(options)
Jobs decorators:
- @Job(options)
- @Cron(expression, options?)
Docs decorators:
- @ApiTag(tag)
- @ApiOperation({ summary, description })
- @ApiResponse({ status, description, type, isArray, example })
- @ApiProperty({ description, required, example, type })
Troubleshooting
- If decorators are not executed, ensure
experimentalDecoratorsandemitDecoratorMetadataare true. - If no components are discovered, check scan patterns and file suffixes.
- If MobX is missing, install it and rerun the build.
- If docs output is empty, confirm controllers are registered and
@Api*metadata exists.
FAQ
Q: Does Fragment require TypeORM? A: No, but TypeORM integration is first-class.
Q: Can I run commands programmatically?
A: Yes. Use CommandRunner.run().
Q: How do I disable docs routes?
A: Set docs.enabled to false in fragment.json.
Glossary
- Plugin: External extension with lifecycle hooks.
- Module: A grouped feature in module structure.
Best Practices
- Use
@FragmentApplication(options)to register core application components. - Use
@Controller(path?)to register core application components. - Use
@Service()to register core application components. - Use
@FragmentRepository()to register core application components. - Use
@Injectable(scope?)to register core application components. - Use
@AutoConfiguration()to register core application components. @Autowired()clarifies injection intent and dependency scope.@Inject(token)clarifies injection intent and dependency scope.@InjectRepository(entity)clarifies injection intent and dependency scope.@Value(expression)clarifies injection intent and dependency scope.@Qualifier(name)clarifies injection intent and dependency scope.@Optional()clarifies injection intent and dependency scope.@Lazy()clarifies injection intent and dependency scope.@Get(path?)defines routing and request binding explicitly.@Post(path?)defines routing and request binding explicitly.@Put(path?)defines routing and request binding explicitly.@Delete(path?)defines routing and request binding explicitly.@Patch(path?)defines routing and request binding explicitly.@Body()defines routing and request binding explicitly.@Param(name?)defines routing and request binding explicitly.@Query(name?)defines routing and request binding explicitly.@Header(name?)defines routing and request binding explicitly.@Req()defines routing and request binding explicitly.@Res()defines routing and request binding explicitly.@FragmentMiddleware(MiddlewareClass)keeps cross-cutting concerns declarative.@FragmentGuard(GuardClass)keeps cross-cutting concerns declarative.@FragmentInterceptor(InterceptorClass)keeps cross-cutting concerns declarative.@FragmentExceptionFilter(ExceptionFilterClass)keeps cross-cutting concerns declarative.@PostConstruct()ensures deterministic lifecycle order.@PreDestroy()ensures deterministic lifecycle order.@OnStartup(order?)ensures deterministic lifecycle order.@OnShutdown(order?)ensures deterministic lifecycle order.@Plugin(options)exposes plugin lifecycle and injection points.@Plugin(token, qualifier?) (property)exposes plugin lifecycle and injection points.@OnPluginInit(order?)exposes plugin lifecycle and injection points.@OnPluginShutdown(order?)exposes plugin lifecycle and injection points.@Mailer(options)keeps mail logic modular and testable.@Mail(qualifier?) (property)keeps mail logic modular and testable.@MailTemplate(options)keeps mail logic modular and testable.@NotificationChannel(options)registers custom delivery channels.@Job(options)schedules background work consistently.@Cron(expression, options?)schedules background work consistently.@ApiTag(tag)keeps API docs close to controllers.@ApiOperation({ summary, description })keeps API docs close to controllers.@ApiResponse({ status, description, type, isArray, example })keeps API docs close to controllers.@ApiProperty({ description, required, example, type })keeps API docs close to controllers.- CLI:
fragment init [dir]is part of the primary workflow. - CLI:
fragment init --type=pluginis part of the primary workflow. - CLI:
fragment serveis part of the primary workflow. - CLI:
fragment buildis part of the primary workflow. - CLI:
fragment testis part of the primary workflow. - CLI:
fragment lintis part of the primary workflow. - CLI:
fragment route:listis part of the primary workflow. - CLI:
fragment config:cacheis part of the primary workflow. - CLI:
fragment cache:clearis part of the primary workflow. - CLI:
fragment env:initis part of the primary workflow. - CLI:
fragment env:listis part of the primary workflow. - CLI:
fragment env:use <file>is part of the primary workflow. - CLI:
fragment env:diff [file]is part of the primary workflow. - CLI:
fragment doc:generateis part of the primary workflow. - CLI:
fragment plugin:listis part of the primary workflow. - CLI:
fragment plugin:info <name>is part of the primary workflow. - CLI:
fragment plugin:remove <name>is part of the primary workflow. - CLI:
fragment plugin:enable <name>is part of the primary workflow. - CLI:
fragment plugin:disable <name>is part of the primary workflow. - CLI:
fragment add <package>is part of the primary workflow. - CLI:
fragment make:controller <name>is part of the primary workflow. - CLI:
fragment make:service <name>is part of the primary workflow. - CLI:
fragment make:resource <name>is part of the primary workflow. - CLI:
fragment make:dto <name>is part of the primary workflow. - CLI:
fragment make:middleware <name>is part of the primary workflow. - CLI:
fragment make:guard <name>is part of the primary workflow. - CLI:
fragment make:job <name>is part of the primary workflow. - CLI:
fragment make:mail <name>is part of the primary workflow. - CLI:
fragment make:notification <name>is part of the primary workflow. - CLI:
fragment make:view <name>is part of the primary workflow. - CLI:
fragment make:store <name>is part of the primary workflow. - CLI:
fragment make:component <name>is part of the primary workflow. - CLI:
fragment make:template <name>is part of the primary workflow. - Config:
structure.typeis a stable knob for behavior. - Config:
verboseis a stable knob for behavior. - Config:
logging.levelis a stable knob for behavior. - Config:
logging.structuredis a stable knob for behavior. - Config:
database.*is a stable knob for behavior. - Config:
database.entitiesis a stable knob for behavior. - Config:
database.migrationsis a stable knob for behavior. - Config:
mail.defaultis a stable knob for behavior. - Config:
mail.mailersis a stable knob for behavior. - Config:
mail.templatesDiris a stable knob for behavior. - Config:
mail.queue.enabledis a stable knob for behavior. - Config:
notifications.defaultChannelsis a stable knob for behavior. - Config:
jobs.enabledis a stable knob for behavior. - Config:
jobs.timezoneis a stable knob for behavior. - Config:
docs.enabledis a stable knob for behavior. - Config:
docs.pathis a stable knob for behavior. - Config:
docs.outputDiris a stable knob for behavior. - Config:
docs.templateis a stable knob for behavior. - Config:
docs.perModuleis a stable knob for behavior. - Config:
docs.perModuleRoutesis a stable knob for behavior. - Config:
pluginsis a stable knob for behavior. - Config:
pluginAutoQualifyis a stable knob for behavior.
