@sculptor/core
v1.1.4
Published
<img src="https://raw.githubusercontent.com/imprakhartripathi/Sculptor/main/assets/sculptor-full-bg.png" alt="SculptorTS"/>
Readme
@sculptor/core
The SculptorTS core package boots the HTTP server and exposes the primary framework runtime API.
Version Policy
- Release line:
v1.1.0 - This release line adds a native Express builder, automatic app root discovery, and builder-aware startup while keeping the
v1.0.xpath intact. - Future changes should stay additive and backwards-conscious.
What This Package Does
- Starts an Express server from a registry
- Exposes a strongly typed Express builder through
createApp() - Loads runtime config and framework config
- Discovers the app root automatically when
rootDiris omitted - Creates the app router from packages, controllers, services, repositories, middlewares, and routes
- Flattens package composition internally while keeping the package index as the package contract
- Exposes the shared registry shape used by scaffolded apps
- Exposes
bootstrapApp({ listen: false })for validation and CI flows - Supports
startApp({ app })for builder-based startup - Exposes request context and a unified framework error pipeline
- Re-exports the package metadata, explicit DI decorators, and functional package types from
@sculptor/di
Public API
import {
createApp,
createRouter,
FunctionalRouter,
findAppRoot,
Req,
Res,
Nxt,
Err,
resolveRootDir,
startApp,
registry
} from "@sculptor/core";startApp(options)
Starts the app and returns the Node HTTP server.
Options:
registry: the app registryrootDir: app root. When omitted, the runtime usesSCULPTOR_ROOT_DIRor automatically discovers the nearest Sculptor root fromprocess.cwd()app: optional Express builder created bycreateApp()port: optional explicit port overridelisten: set tofalseto bootstrap without binding a socketonError: optional framework-level error hook
createApp()
Creates a chainable Express builder around the underlying Express instance.
Supported builder methods:
use()set()enable()disable()locals()engine()
The builder also exposes:
instancegetInstance()
It intentionally does not expose Express startup methods such as listen(), route(), render(), or param().
registry
The default empty registry shape exported by the package.
The current registry shape supports both the legacy flat arrays and the package-aware form:
packagescontrollersservicesrepositoriesmiddlewaresroutes
Package metadata can describe class-based or functional package outputs, and helper-linked file metadata stays outside the runtime DI container.
Re-exports
@sculptor/core also re-exports the router decorators and config helpers:
PackageAutoInjectServiceRepositoryMiddlewareControllerGetPatchPostPutDeleteUseFunctionalRoutercreateRouterloadConfiggetConfigredactConfig
It also re-exports the request typing helpers:
ReqResNxtErr
Startup Behavior
When startApp() runs:
rootDiris resolved from the supplied option,SCULPTOR_ROOT_DIR, or automatic discoverysculptor.jsonandprops.jsonare loaded from the app root- The runtime chooses a port
- Express middleware is attached
- The registry is turned into an Express router
- The server begins listening, unless
listen: falseis requested - The runtime logs the port and localhost URL
Startup output:
SculptorTS listening on port X
Local: http://localhost:XPort Resolution
Port resolution uses this order:
startApp({ port })process.env.PORTprops.jsonapp.port3000
If the resolved port is 0, the runtime reads the actual bound port from the server address and prints that instead.
Registry Behavior
| If the registry contains | Then the runtime does this |
| --- | --- |
| Packages | Flattens the package composition and registers the package-owned runtime pieces |
| Controllers | Scans the controller metadata and registers decorator-based routes |
| Routes | Mounts the Express routers directly |
| Both controllers and routes | Combines both into one app router |
| No routes | Starts a server, but nothing is mounted beyond Express body parsing |
| app provided | Uses the supplied builder instance and preserves its configuration |
| listen: false | Bootstraps the app, validates the registry, and returns without binding a socket |
| onError provided | Framework errors are routed through the lightweight hook before the JSON error response is sent |
Request Context
Every request gets a lightweight ctx object on req:
requestIdis generated automatically or read fromx-request-idmetais a request-scoped bag for middleware and handlersuseris available for app-specific auth context
Middleware can extend this object without needing a DI container.
Error Hooks
startApp({ onError }) and bootstrapApp({ onError }) pass framework-normalized errors to a lightweight hook.
The hook receives:
requestresponseroutemetadata when availabletimestamp- optional controller info
- the request
context
The framework still sends a consistent JSON response after the hook runs:
{
"error": {
"code": "RUNTIME_ERROR",
"message": "Something went wrong",
"status": 500
}
}This preserves Express compatibility while preventing HTML error pages from leaking out of framework-owned routes.
Config Behavior
| If props.json says | Then the runtime does this |
| --- | --- |
| app.port = 4000 | The app listens on 4000 unless PORT or startApp({ port }) overrides it |
| app.prefix = "/api" | The router is mounted under /api |
| No app.prefix | The router is mounted at the root |
Example
import { createApp, registry, startApp } from "@sculptor/core";
const app = createApp();
app.disable("x-powered-by");
await startApp({
registry,
app,
port: 3000
});Behavior Matrix
| If you do this | Then this happens |
| --- | --- |
| Call startApp() with no port | The runtime uses environment, config defaults, and automatic root discovery |
| Pass port: 0 | The OS chooses a free port and the runtime reports the actual port |
| Pass a registry with controllers | Decorator metadata is scanned and registered |
| Pass a registry with routes | Route routers are mounted directly |
| Pass a registry with functional routers | Functional builders are converted to Express routers |
| Pass an Express builder through app | The runtime uses that builder instance instead of creating a new one |
| Use loadConfig() | Framework and runtime config are loaded and cached per root directory |
| Use getConfig("app.port") | The merged runtime value is returned if present |
Package Scripts
npm run buildcompiles the packagenpm run prepackbuilds before publish
License
MIT
