Skip to content

@lastshotlabs/slingshot

npm install @lastshotlabs/slingshot

Apply auto-defaults and literal defaults to a create input, producing a full entity record ready for persistence.

For each field that is absent from input but has a default defined in its FieldDef, the default is resolved as follows:

  1. Built-in auto-default ('uuid', 'cuid', 'now'): delegated to resolveAutoDefault (with customAutoDefault forwarded).
  2. Custom string default: if customAutoDefault is provided and the default value is a string that is not a built-in sentinel, the resolver is called. If it returns a non-undefined value, that value is used; otherwise the literal string is used as-is.
  3. Literal default (number, boolean, or unresolved string): applied directly as the field value.

Fields already present in input are never overwritten.

function applyDefaults(input: Record<string, unknown>, fields: Record<string, FieldDef>, customAutoDefault?: CustomAutoDefaultResolver,): Record<string, unknown>

Source: packages/slingshot-entity/src/configDriven/fieldUtils.ts

Apply onUpdate fields to an update payload, injecting computed values for fields that declare an onUpdate sentinel.

Resolution order for each field with a non-undefined onUpdate:

  1. Built-in sentinel ('now'): sets the field to new Date().
  2. Custom sentinel (any other string): if customOnUpdate is provided, it is invoked with the sentinel string. When the resolver returns a non-undefined value, that value is written to the field. If the resolver returns undefined, the field is left unchanged (the sentinel is silently ignored).

Values already present in input for non-onUpdate fields are preserved. onUpdate fields are always overwritten regardless of whether the caller included them in input.

function applyOnUpdate(input: Record<string, unknown>, fields: Record<string, FieldDef>, customOnUpdate?: CustomOnUpdateResolver,): Record<string, unknown>

Source: packages/slingshot-entity/src/configDriven/fieldUtils.ts

function assertProductionReadiness(config: AuditConfig, options?: ProductionReadinessAuditOptions,): ProductionReadinessReport

Source: src/prodReadiness.ts

Hono middleware that records an audit log entry for every HTTP request.

The entry is written after the route handler resolves, so c.res.status is available. Exclusion checks (method and path filters) run at the same point — the route still executes; only the log write is skipped.

The write is fire-and-forget: it never blocks or delays the response, and any write failure is swallowed internally (logged via console.error).

function auditLog(options: AuditLogMiddlewareOptions): MiddlewareHandler<AppEnv>

Source: src/framework/middleware/auditLog.ts

function auditProductionReadiness(config: AuditConfig, options: ProductionReadinessAuditOptions = {},): ProductionReadinessReport

Source: src/prodReadiness.ts

Hono middleware that blocks requests from known-bad IP addresses.

Block-list entries are validated eagerly at construction time (startup), so misconfigured CIDR strings cause an immediate error rather than a silent miss at request time.

If blockList is empty, the middleware is a no-op passthrough.

function botProtection({ blockList = [] }: BotProtectionOptions): MiddlewareHandler

Source: src/framework/middleware/botProtection.ts

Delete a cached entry by exact key across ALL cache backends.

Requires an app reference so cache invalidation uses the correct instance-owned adapters.

async function bustCache(key: string, app: object): void

Source: src/framework/middleware/cacheResponse.ts

Delete cached entries matching a glob pattern across ALL cache backends.

async function bustCachePattern(pattern: string, app: object): void

Source: src/framework/middleware/cacheResponse.ts

Hono middleware that caches full HTTP responses in a configured backend store.

On a cache hit the cached status, headers, and body are returned immediately with an x-cache: HIT header — the downstream route handler is not called. On a cache miss the route handler runs normally; if the response status is 2xx the response is serialised and stored, then re-sent with x-cache: MISS. Non-2xx responses are never cached.

Cache keys are automatically namespaced by appName and, when present, by tenantId, so two tenants can never observe each other’s cached responses.

Security: the following response headers are never stored in the cache to prevent session fixation, CSRF token leakage, and auth bypass: set-cookie, www-authenticate, authorization, x-csrf-token, proxy-authenticate.

function cacheResponse({ ttl, key, store: storeOverride, }: CacheOptions): MiddlewareHandler<AppEnv>

Source: src/framework/middleware/cacheResponse.ts

Close all job queues tracked in the metrics state (best-effort).

async function closeMetricsQueues(state: MetricsState): Promise<void>

Source: src/framework/metrics/registry.ts

Create the Slingshot application instance.

Runs the full bootstrap pipeline: config validation → secret resolution → infrastructure connection → context creation → plugin lifecycle → route mounting → OpenAPI docs → context finalization. On failure, all acquired resources (database connections, bus, secrets provider) are torn down before the error is re-thrown.

async function createApp<T extends object = object>(config: CreateAppConfig<T>,): Promise<CreateAppResult>

Source: src/app.ts

Create an AuditLogProvider for the configured storage backend.

function createAuditLogProvider(options: AuditLogOptions): AuditLogProvider

Source: src/framework/auditLog/index.ts

Creates the slingshot-auth plugin instance for use with createApp(), createServer(), or as a standalone Hono plugin via plugin.setup().

The plugin bootstraps all auth subsystems (session store, adapters, rate limiting, credential stuffing detection, OAuth providers, MFA, SAML, SCIM, etc.) and mounts the corresponding route handlers on the Hono app.

Remarks: - In standalone mode (no SlingshotFrameworkConfig), config.runtime.password is required. - Production boot requires an explicit security.signing.sessionBinding choice. Without it a stolen JWT+session pair is usable from any IP or browser. Set security.signing.sessionBinding to either a real binding policy or false to acknowledge the risk explicitly. - OAuth routes are provided by @lastshotlabs/slingshot-oauth and mounted by that plugin.

function createAuthPlugin(rawConfig: AuthPluginConfig): StandalonePlugin

Source: packages/slingshot-auth/src/plugin.ts

Factory function that creates a new InProcessAdapter instance.

Prefer this over new InProcessAdapter() in application code — it returns the SlingshotEventBus interface rather than the concrete class, keeping the call site decoupled from the implementation.

Remarks: Each call returns a fully independent instance — listeners, pending handlers, and the listener registrations and pending handler sets are all owned by the returned object and never shared. Calling createInProcessAdapter() twice produces two completely isolated buses.

function createInProcessAdapter(serializationOpts?: EventBusSerializationOptions,): SlingshotEventBus

Source: packages/slingshot-core/src/eventBus.ts

Create an in-memory EntityAdapter for the given entity config.

  • Stores records in a Map keyed by primary key
  • Supports TTL via per-entry expiresAt
  • Soft-delete: sets the configured field instead of removing
  • Cursor pagination using cursor field values
  • Tenant scoping in list operations
function createMemoryEntityAdapter<Entity, CreateInput, UpdateInput>(config: ResolvedEntityConfig, operations?: Record<string, OperationConfig>,): EntityAdapter<Entity, CreateInput, UpdateInput> & Record<string, unknown>

Source: packages/slingshot-entity/src/configDriven/memoryAdapter.ts

Create a fresh, instance-scoped metrics state container.

function createMetricsState(): MetricsState

Source: src/framework/metrics/registry.ts

Creates a MongoDB-backed EntityAdapter for the given entity config.

function createMongoEntityAdapter<Entity, CreateInput, UpdateInput>(conn: Connection, mongoosePkg: MongooseModule, config: ResolvedEntityConfig, operations?: Record<string, OperationConfig>,): EntityAdapter<Entity, CreateInput, UpdateInput> & Record<string, unknown>

Source: packages/slingshot-entity/src/configDriven/mongoAdapter.ts

Create a config-driven Postgres entity adapter.

The adapter is fully lazy — table creation is deferred to the first query via ensureTable(), which is idempotent and runs at most once per adapter instance (guarded by the initialized flag in closure).

Generic type parameters let callers get back properly-typed records and inputs:

  • Entity — the full entity type returned by getById, create, update, list.
  • CreateInput — the input accepted by create.
  • UpdateInput — the partial input accepted by update.
function createPostgresEntityAdapter<Entity, CreateInput, UpdateInput>(pool: PgPool, config: ResolvedEntityConfig, operations?: Record<string, OperationConfig>,): EntityAdapter<Entity, CreateInput, UpdateInput> & Record<string, unknown>

Source: packages/slingshot-entity/src/configDriven/postgresAdapter.ts

Create a stateless HMAC-signed URL. The signature covers the HTTP method, storage key, expiry timestamp, and any extra query params so that:

  • Expired URLs are rejected (replay prevention)
  • URLs are method-bound (a GET URL can’t be replayed as a PUT)
  • Tampering with the key, expiry, or any extra param invalidates the signature
function createPresignedUrl(base: string, key: string, opts: { method: string; expiry: number; extra?: Record<string, string> }, secret: string | string[],): string

Source: src/lib/signing.ts

Create a Redis-backed EntityAdapter for the given entity config.

Records are stored as JSON strings under prefixed keys (default format: ${storageName}:${appName}:${pk}). Supports TTL expiration, soft-delete, cursor pagination, and tenant-scoped list operations.

The key format can be customised via config._conventions.redisKey.

function createRedisEntityAdapter<Entity, CreateInput, UpdateInput>(redis: RedisLike, appName: string, config: ResolvedEntityConfig, operations?: Record<string, OperationConfig>,): EntityAdapter<Entity, CreateInput, UpdateInput> & Record<string, unknown>

Source: packages/slingshot-entity/src/configDriven/redisAdapter.ts

Redis pub/sub transport for horizontal WebSocket scaling.

Uses two ioredis clients — one for publishing and one for subscribing — as required by the Redis pub/sub protocol (a client in subscribe mode cannot issue regular commands).

Uses psubscribe on <prefix>* so that joining new rooms never requires an additional SUBSCRIBE call.

Self-echo prevention: every published message is wrapped with the origin passed in from ws.ts (the server instance UUID). Messages whose origin matches the local instance are dropped by the caller — the origin is forwarded intact to the onMessage callback.

function createRedisTransport(opts: RedisTransportOptions): WsTransportAdapter

Source: src/framework/ws/redisTransport.ts

Drop-in replacement for createRoute from @hono/zod-openapi.

Automatically registers unnamed request body and response schemas as named OpenAPI components so they appear in components/schemas instead of being inlined at every use site. Generated names follow the convention:

{Method}{PathSegments}Request {Method}{PathSegments}{Status}

Schemas already named via .openapi("Name") are never overwritten.

function createRoute<T extends RouteConfig>(config: T): T

Source: packages/slingshot-core/src/createRoute.ts

Create a new OpenAPIHono router pre-configured with the Slingshot AppEnv type and the shared defaultHook for validation error handling.

All plugin and framework routes use this factory so that error formatting and context variable typing are consistent across the entire application.

Remarks: Use createRouter() (not new Hono() or new OpenAPIHono()) for any router that: - Declares OpenAPI routes via router.openapi(createRoute(...), handler) - Needs access to typed AppVariables (requestId, tenantId, slingshotCtx, etc.) - Should participate in the shared defaultHook validation error pipeline

Remarks: A plain new Hono() is acceptable for middleware-only routers that never call c.get('slingshotCtx') or declare OpenAPI routes.

function createRouter(): void

Source: packages/slingshot-core/src/context.ts

Create and start a Slingshot HTTP/WebSocket server.

Wraps createApp with server-level concerns: port binding, TLS, WebSocket transport, SSE endpoint registration, worker auto-loading, and graceful shutdown signal handling (SIGTERM/SIGINT). Multiple concurrent servers are supported — each registers its own shutdown callback.

async function createServer<T extends object = object>(config: CreateServerConfig<T>,): Promise<Server<SocketData<T>>>

Source: src/server.ts

Create the Slingshot admin plugin with automatic framework wiring.

This is a thin adapter around createAdminPlugin (from @lastshotlabs/slingshot-admin) that defers route registration to the setupPost lifecycle phase. This is intentional: plugins register their PERMISSIONS_STATE_KEY in setupRoutes, and setupPost runs after all setupRoutes phases have completed, ensuring the permissions state is fully populated before admin routes are mounted.

Lifecycle note (Rule 17): setupRoutes is intentionally a no-op here. Route registration happens in setupPost after all other plugins’ setupRoutes have run. The setup convenience method delegates to setupPost for standalone usage.

Cross-plugin state: Resolved permissions are published back to ctx.pluginState under PERMISSIONS_STATE_KEY (if not already set) so other plugins that run after admin can read the canonical permissions object.

function createSlingshotAdminPlugin(config: SlingshotAdminPluginConfig): SlingshotPlugin

Source: src/framework/admin/index.ts

Create a SQLite-backed EntityAdapter for the given entity config.

Auto-creates the table and indexes on first use. Handles domain ↔ storage mapping including dates (epoch ms), JSON (serialised text), booleans (0/1), and snake_case column names. Supports soft-delete, cursor pagination, TTL (via a configurable expiry column), and tenant-scoped list operations.

function createSqliteEntityAdapter<Entity, CreateInput, UpdateInput>(db: SqliteDb, config: ResolvedEntityConfig, operations?: Record<string, OperationConfig>,): EntityAdapter<Entity, CreateInput, UpdateInput> & Record<string, unknown>

Source: packages/slingshot-entity/src/configDriven/sqliteAdapter.ts

Create the default SSE upgrade handler for an endpoint.

Mirrors createWsUpgradeHandler in its auth semantics: resolves the authenticated Actor from the request’s session cookie or bearer token via the optional actorResolver, then returns a populated SseClientData object. The upgrade never rejects on auth failure — unauthenticated connections receive actor: ANONYMOUS_ACTOR and proceed normally. Gate access in a middleware layer or inside your own upgrade wrapper if you need hard rejection.

The generic T parameter extends the base SseClientData shape so you can carry custom fields (e.g., roomId) through the client lifecycle. Those fields must be populated by a wrapping upgrade function — this factory only fills id, actor, requestTenantId, and endpoint.

function createSseUpgradeHandler<T extends object = object>(endpoint: string, actorResolver?: RequestActorResolver | null,): (req: Request) => Promise<SseClientData<T>>

Source: src/framework/sse/index.ts

Create a TenantService backed by a Mongoose connection.

function createTenantService(conn: Connection, getTenantCache?: () => { delete(tenantId: string): void } | null, ): TenantService

Source: src/framework/tenancy/service.ts

Create the default WebSocket upgrade handler for a Bun HTTP server.

Resolves the authenticated Actor from the upgrade request’s session cookie or bearer token (via the optional actorResolver), then calls server.upgrade() to promote the connection to a WebSocket. If the upgrade succeeds the handler returns undefined (Bun expects no response for successful upgrades); on failure it returns a 400 JSON error response.

Requests without a credential may proceed as anonymous. A request that presents a standard Slingshot credential but cannot resolve it is rejected with 401 so clients can refresh or retry instead of opening a misleading anonymous connection.

function createWsUpgradeHandler(server: Server<BaseSocketData>, endpoint: string, actorResolver?: RequestActorResolver | null): void

Source: src/framework/ws/index.ts

Build a Zod schema for cursor-based pagination query parameters (limit, cursor).

function cursorParams(defaults?: CursorParamDefaults): void

Source: src/framework/lib/pagination.ts

Build a Zod schema for a cursor-paginated response and register it in the OpenAPI schema registry under the given name.

function cursorResponse<T extends ZodType>(itemSchema: T, name: string): void

Source: src/framework/lib/pagination.ts

Decode an opaque cursor string back to pagination state.

function decodeCursor(cursor: string): Record<string, unknown>

Source: packages/slingshot-entity/src/configDriven/fieldUtils.ts

The built-in Zod validation error formatter used by defaultHook.

Produces { error, details, requestId } where details is a per-field breakdown. Assign config.validationErrorFormatter in your app config to replace this with a custom formatter that matches your API’s error contract.

Remarks: This function never throws. It is also the automatic fallback inside defaultHook when a custom ValidationErrorFormatter throws — so overriding it is safe to do without worrying about breaking the fallback path.

Source: packages/slingshot-core/src/context.ts

Declare a Slingshot application.

Identity wrapper that provides typed inference for app.config.ts without forcing users to annotate the config object themselves. The return value is the config object, ready to be passed to createServer() by the framework runner.

function defineApp<T extends object = object>(config: AppConfig<T>): AppConfig<T>

Source: src/defineApp.ts

Declare a named typed capability that packages can publish and require explicitly.

function defineCapability<TValue>(name: string): PackageCapabilityHandle<TValue>

Source: packages/slingshot-core/src/packageAuthoring.ts

Canonical top-level code-first authoring surface for packages.

function definePackage(input: DefinePackageInput): SlingshotPackageDefinition

Source: packages/slingshot-core/src/packageAuthoring.ts

Declare a provider-owned package public contract. The returned object owns the package’s typed public surface — capabilities and public entity refs — and gates definePackage(...) so capability ownership and dependency wiring can be validated at authoring time.

function definePackageContract<const TName extends string>(contractName: TName,): PackageContract<TName>

Source: packages/slingshot-core/src/packageAuthoring.ts

Delete an upload record by key. Returns true if it existed.

async function deleteUploadRecord(key: string, app: object): Promise<boolean>

Source: src/framework/upload/registry.ts

Encode cursor pagination state to an opaque base64url string.

function encodeCursor(values: Record<string, unknown>): string

Source: packages/slingshot-entity/src/configDriven/fieldUtils.ts

Declare a package-owned entity module.

Standard wiring is the default and should cover the normal case where the framework can resolve the adapter from the entity config and active persistence backend.

function entity<
const TConfig extends ResolvedEntityConfig,
const TOperations extends EntityOperationsInput = undefined,
>(config: { /** Resolved entity config to mount. */ readonly config: TConfig; /** Operation map or `defineOperations(...)` result used for generated routes. */ readonly operations?: TOperations; /** Additional custom routes mounted inside the entity route shell. */ readonly extraRoutes?: readonly EntityExtraRoute[]; /** Generated-route executor overrides. */ readonly overrides?: EntityRouteExecutorOverrides; /** Optional realtime channel declarations. */ readonly channels?: EntityChannelConfig; /** Optional route path override relative to the package mount path. */ readonly path?: string; /** Optional parent path prefix for nested entity routes. */ readonly parentPath?: string; /** Adapter wiring override. Defaults to `{ mode: 'standard' }`. */ readonly wiring?: EntityModuleWiring; }): PackageEntityModule< PackageEntityAdapterFor<TConfig, NormalizeOperationsInput<TOperations>>, EntityMiddlewareNamesOf<TConfig> >; export function entity(config:

Source: packages/slingshot-entity/src/packageAuthoring.ts

Create a typed entity ref that can be used outside the owning package.

Pass a local entity module for same-package typed lookups, or attach plugin when exporting a ref for another package to consume.

function entityRef<TAdapter>(entity: SlingshotPackageEntityModuleLike<TAdapter>, options?: { plugin?: string },): PackageEntityRef<TAdapter>; /** * Create a typed entity ref directly from a package/entity name pair. * * @deprecated For cross-package entity access, prefer publishing a typed ref through a * package contract: `Matches.publicEntities(

Source: packages/slingshot-core/src/packageAuthoring.ts

The field builder namespace — the only way to create FieldDef values for use in EntityConfig.fields.

Each method returns a typed FieldDef with sensible defaults. Pass FieldOptions to control optionality, defaults, immutability, and primary key status.

Source: packages/slingshot-core/src/entityConfig.ts

Generate Zod validation schemas from a resolved entity config.

All four schemas are derived in a single pass over config.fields, with additional passes for config.indexes, config.tenant, and pagination defaults. The function is pure — it has no side effects and can be called at any time.

function generateSchemas(config: ResolvedEntityConfig, inputVariant?: string,): GeneratedSchemas

Source: packages/slingshot-entity/src/configDriven/schemaGen.ts

Resolve the canonical actor for a Hono request context.

Reads the actor variable published by the auth middleware (identify, bearerAuth, or a custom identity middleware). Returns ANONYMOUS_ACTOR when no actor has been published.

function getActor(c: Context<AppEnv>): Actor

Source: packages/slingshot-core/src/actorContext.ts

Resolve the current actor ID from request context.

Returns null for anonymous requests.

function getActorId(c: Context<AppEnv>): string | null

Source: packages/slingshot-core/src/actorContext.ts

Resolve the current actor tenant scope from request context.

Returns null for tenantless actors and single-tenant requests.

function getActorTenantId(c: Context<AppEnv>): string | null

Source: packages/slingshot-core/src/actorContext.ts

Extract the real client IP address from a Hono request context.

When trustProxy is false (the default), returns the raw socket address. When trustProxy is a number N, reads the Nth entry from the right of the X-Forwarded-For header chain, then falls back to X-Real-IP, then the socket address.

IPv4-mapped IPv6 addresses (::ffff:1.2.3.4) are normalised to plain IPv4. Returns 'unknown' if no address is available.

Remarks: The trustProxy setting is read from SlingshotContext (if available on the context variable slingshotCtx) or from the symbol attached by setStandaloneTrustProxy. Never trust X-Forwarded-For headers if your server is directly internet-facing — clients can spoof them to bypass IP-based rate limiting.

Remarks: IPv6-mapped IPv4 normalisation: addresses in the form ::ffff:1.2.3.4 (IPv4 mapped into the IPv6 address space) are automatically normalised to plain IPv4 notation (1.2.3.4). This affects the socket IP, the X-Forwarded-For entries, and the X-Real-IP value — all are normalised before being returned. The normalisation is purely cosmetic and does not affect routing or security semantics.

function getClientIp<E extends AppEnv>(c: Context<E>): string

Source: packages/slingshot-core/src/clientIp.ts

Retrieve the SlingshotContext for a Hono app instance.

The context is attached by createApp() after all plugins have been initialised. Use this in plugin setupPost hooks and in application code outside request handlers (e.g., job workers, CLI commands, shutdown hooks).

function getContext(app: object): SlingshotContext

Source: packages/slingshot-core/src/context/contextStore.ts

Retrieve the SlingshotContext for a Hono app instance, or null if not attached.

Use this when context availability is optional — for example, in standalone plugin setup that may run before or without a full createApp() call.

function getContextOrNull(app: object): SlingshotContext | null

Source: packages/slingshot-core/src/context/contextStore.ts

Context-aware Mongo getter. Returns the instance-scoped connections from SlingshotContext. Throws if no SlingshotContext is attached to the app. Returns null when Mongo is not configured on the context.

function getMongoFromApp(app: object,): { auth: Connection | null; app: Connection | null } | null

Source: src/lib/mongo.ts

Get the mongoose module (lazy-loaded). Useful for consumers that need the mongoose module without a connection (e.g., Schema class access).

function getMongooseModule(): MongooseModule

Source: src/lib/mongo.ts

Context-aware Redis getter. Returns the instance-scoped Redis from SlingshotContext, or null when Redis is not configured on the context. Throws if no SlingshotContext is attached to the app.

function getRedisFromApp(app: object): RedisClass | null

Source: src/lib/redis.ts

Resolve the request-scoped tenant ID from the Hono context.

This is the tenant context set by tenant-resolution middleware (e.g. from a header or subdomain), distinct from getActorTenantId which returns the tenant the actor belongs to. They usually match but can differ for cross-tenant operations.

Returns null in single-tenant mode or when tenant resolution is not active.

function getRequestTenantId(c: Context<AppEnv>): string | null

Source: packages/slingshot-core/src/actorContext.ts

Get the list of unique user IDs currently present in a room.

function getRoomPresence(state: WsState, endpoint: string, room: string): string[]

Source: src/framework/ws/presence.ts

List all rooms with at least one subscriber on a given endpoint.

function getRooms(state: WsState, endpoint: string): string[]

Source: src/framework/ws/rooms.ts

List all socket IDs subscribed to a specific room.

function getRoomSubscribers(state: WsState, endpoint: string, room: string): string[]

Source: src/framework/ws/rooms.ts

Retrieve the SlingshotContext associated with a server. Available after createServer() completes. Used by test helpers.

function getServerContext(server: object): SlingshotContext | null

Source: src/server.ts

Retrieve the SlingshotContext from a Hono request context.

The context variable slingshotCtx is set by the framework’s context middleware on every request. Use this in route handlers when you need access to instance-scoped state (persistence, plugins, event bus, secrets, etc.).

Remarks: Timing: safe to call inside any route handler, error handler, or response middleware that runs after the framework’s context middleware. Do NOT call it in constructor-time code, module-level code, or plugin setup phases — slingshotCtx is a per-request variable that only exists within the Hono request pipeline. For access outside a request, use getContext(app) from the framework layer instead.

function getSlingshotCtx(c: Context<AppEnv>): SlingshotContext

Source: packages/slingshot-core/src/context.ts

Get the set of rooms a specific socket is currently subscribed to.

function getSubscriptions<T extends WithRooms>(ws: ServerWebSocket<T>): string[]

Source: src/framework/ws/rooms.ts

Retrieve an upload record by key. Returns null if not found.

async function getUploadRecord(key: string, app: object): Promise<UploadRecord | null>

Source: src/framework/upload/registry.ts

Get the list of rooms a specific user is currently present in (across all endpoints).

function getUserPresence(state: WsState, userId: string): string[]

Source: src/framework/ws/presence.ts

Hono middleware that parses a multipart or form-encoded file upload and stores the parsed results on the request context for the downstream route handler.

Performs a fast Content-Length pre-check before reading the body to reject obviously oversized requests without buffering them, avoiding Bun’s connection-kill behaviour on payload overflow.

Parsed results are set on c.get('uploadResults').

function handleUpload(opts?: UploadMiddlewareOptions): MiddlewareHandler<AppEnv>

Source: src/framework/middleware/upload.ts

Sign data with the active key (first element of secret). Normalizes string | string[] so that an array is never passed directly to createHmac() — which would silently call .toString() and produce “[object Array]” as the key.

function hmacSign(data: string, secret: string | string[]): string

Source: src/lib/signing.ts

Verify sig against data using one of the provided keys. Keys are tried newest-first (index 0 is the active signing key).

Key ordering convention: put the current (newest) key first; rotated keys after. The common case (valid current-key signature) succeeds on the first comparison; old rotated keys only matter for in-flight tokens.

MUST use timingSafeEqual — never === — to prevent timing side-channel leaks. This is the most common HMAC implementation mistake.

function hmacVerify(data: string, sig: string, secret: string | string[]): boolean

Source: src/lib/signing.ts

Idempotency middleware. Reads the Idempotency-Key header and returns a cached response if one exists for this user + key combination. Otherwise calls the next handler, stores the response, and returns it.

On write collision (two concurrent identical requests), the second request re-reads and returns the first-stored result.

When signing.idempotencyKeys: true, keys are HMAC’d before storage to prevent enumeration. When off, raw keys are stored (slight enumeration risk).

function idempotent(opts?: IdempotencyOptions): MiddlewareHandler<AppEnv>

Source: src/framework/lib/idempotency.ts

Increment a named counter metric.

function incrementCounter(state: MetricsState, name: string, labels: Labels, amount = 1,): void

Source: src/framework/metrics/registry.ts

Convenience builder for compound indexes.

function index(fields: string[], opts?: { direction?: 'asc' | 'desc'; unique?: boolean },): IndexDef

Source: packages/slingshot-core/src/entityConfig.ts

Inspect the effective module graph of a package without reading framework internals.

function inspectPackage(pkg: SlingshotPackageDefinition): PackageInspection

Source: packages/slingshot-core/src/packageAuthoring.ts

Immediately remove a specific tenant from the resolution cache.

Call this after provisioning, updating, or disabling a tenant so that the next request for that tenant calls onResolve instead of serving a stale cached result.

function invalidateTenantCache(cache: TenantResolutionCache | null | undefined, tenantId: string,): void

Source: src/framework/middleware/tenant.ts

True when the user holds at least one live socket in the room.

Presence is the only reliable liveness signal for a room member: the engine’s per-player connected flag exists only while a game runtime is active, so a lobby (no runtime yet) has no other way to tell whether the host is still there. Apps use this to detect an absent host and offer recovery.

function isUserPresent(state: WsState, endpoint: string, room: string, userId: string,): boolean

Source: src/framework/ws/presence.ts

Create a StorageAdapter that persists files in the local filesystem.

All keys are resolved relative to config.directory. Parent directories are created automatically on put. get returns null for missing files rather than throwing. delete silently ignores missing files.

Remarks: Path traversal protection — all keys are validated by resolveKey before any filesystem operation. Keys that are empty, absolute, or that resolve to a path outside config.directory result in a 400 HttpError, not a filesystem access.

function localStorage(config: LocalStorageConfig): StorageAdapter

Source: src/framework/adapters/localStorage.ts

Verbose-mode console logger.

Writes to console.log when LOGGING_VERBOSE=true or when NODE_ENV is not 'production'. Silenced in production by default.

function log(...args: unknown[]): void

Source: src/framework/lib/logger.ts

Read an entity adapter from plugin-owned state when available.

Returns null when the plugin has not published that entity adapter. Throws when the owning plugin’s state shape is malformed.

function maybeEntityAdapter<TAdapter extends object = object>(input: PluginStateMap | PluginStateCarrier | object | null | undefined, lookup: EntityAdapterLookupInput<TAdapter>,): TAdapter | null

Source: packages/slingshot-core/src/pluginState.ts

HMAC-sign a cursor string when cursor signing is enabled, otherwise return it unchanged.

function maybeSignCursor(cursor: string | null, signing?: { config: SigningConfig | null; secret: string | string[] | null },): string | null

Source: src/framework/lib/pagination.ts

Create a StorageAdapter that stores files in-process in a Map.

Remarks: Ephemeral, in-process only — all stored data lives in heap memory and is discarded when the process exits or the adapter is garbage-collected. This adapter is suitable for development, testing, and single-process environments only. It must not be used in production multi-process deployments because files stored in one process are invisible to other processes.

Remarks: Entries are evicted via LRU when the store reaches DEFAULT_MAX_ENTRIES (imported from slingshot-core) to prevent unbounded memory growth.

function memoryStorage(): StorageAdapter

Source: src/framework/adapters/memoryStorage.ts

Hono middleware that records Prometheus-compatible HTTP metrics for every non-excluded request.

Records two metrics per request:

  • http_requests_total — counter labelled by method, path, status, and optionally tenant.
  • http_request_duration_seconds — histogram labelled by method, path, and optionally tenant.

The normalizePath function collapses dynamic path segments (e.g. /users/123 to /users/:id) to keep cardinality manageable. Use a custom normalizePath for application-specific path shapes.

function metricsCollector(options: MetricsMiddlewareOptions): MiddlewareHandler<AppEnv>

Source: src/framework/middleware/metrics.ts

Record an observation in a named histogram metric.

function observeHistogram(state: MetricsState, name: string, labels: Labels, value: number, buckets: number[] = DEFAULT_BUCKETS,): void

Source: src/framework/metrics/registry.ts

Build a Zod schema for offset-based pagination query parameters (limit, offset).

Both params are strings (from query strings) — call parseOffsetParams() to convert them to numbers before passing to a repository.

function offsetParams(defaults?: OffsetParamDefaults): void

Source: packages/slingshot-core/src/pagination.ts

Fluent builder namespace for entity operation definitions.

Each method accepts the operation-specific config (without the kind discriminant) and injects the correct kind string. Pass the results into defineOperations() to validate field references and freeze the config.

Remarks: op.*() builders are pure — they perform no validation. Validation (field existence, constraint checks) happens when the returned config is passed to defineOperations().

Source: packages/slingshot-entity/src/builders/op.ts

Build a Zod schema for a standard offset-paginated response envelope and register it in components/schemas under name.

The schema wraps an array of itemSchema with total, limit, and offset fields.

function paginatedResponse<T extends ZodType>(itemSchema: T, name: string): void

Source: packages/slingshot-core/src/pagination.ts

Parse raw cursor pagination query strings into typed, clamped values.

When cursor signing is configured, the incoming cursor is verified before use. An invalid signature sets invalidCursor: true and clears the cursor.

function parseCursorParams(raw: { limit?: string; cursor?: string }, defaults?: CursorParamDefaults, signing?: { config: SigningConfig | null; secret: string | string[] | null },): ParsedCursorParams &

Source: src/framework/lib/pagination.ts

Parse and clamp raw offset pagination query strings to safe numeric values.

Converts the string values produced by Hono’s query parsing into validated numbers, applying configured defaults when the client omits a parameter and clamping to the allowed range.

function parseOffsetParams(raw: { limit?: string; offset?: string }, defaults?: OffsetParamDefaults,): ParsedOffsetParams

Source: packages/slingshot-core/src/pagination.ts

Parse multipart file uploads from a Hono request context.

Extracts files from the configured form fields, validates size and MIME type, stores each file via the configured storage adapter, and registers them in the upload registry.

async function parseUpload(c: Context<AppEnv>, opts?: UploadOpts,): Promise<UploadResult[]>

Source: src/framework/upload/upload.ts

Publish a capability implementation from a package during bootstrap finalization.

function provideCapability<TValue>(capability: PackageCapabilityHandle<TValue>, resolve: PublishedPackageCapability<TValue>['resolve'],): PublishedPackageCapability<TValue>

Source: packages/slingshot-core/src/packageAuthoring.ts

Publish a message to all subscribers of a WebSocket room.

Uses Bun’s native room broadcast for the fast path. Falls back to per-socket delivery when volatile mode, exclude sets, or delivery tracking are enabled. Also fans out to the cross-instance transport when configured.

function publish(state: WsState, endpoint: string, room: string, data: unknown, options?: PublishOptions,): void

Source: src/framework/ws/rooms.ts

Hono middleware that enforces request-rate limits per client — an authenticated user or display when there is one, and the client IP only for anonymous traffic — with optional secondary limiting by HTTP fingerprint.

Rate-limit buckets are namespaced per tenant when a tenantId is present on the request context, so each tenant gets independent counters.

Relies on the RateLimitAdapter registered in SlingshotContext — the adapter is resolved at request time via getRateLimitAdapter.

function rateLimit({ windowMs, max, fingerprintLimit = false, onStoreError = 'allow', }: RateLimitOptions): MiddlewareHandler<AppEnv>

Source: src/framework/middleware/rateLimit.ts

Register an async callback that will be invoked at scrape time to produce gauge values.

function registerGaugeCallback(state: MetricsState, name: string, cb: GaugeCallback): void

Source: src/framework/metrics/registry.ts

Registers a Zod schema as a named entry in components/schemas.

Use this for shared schemas (e.g. shared error types, reusable response shapes) that aren’t directly attached to a specific route. Schemas already registered under the same name are silently skipped.

function registerSchema<T extends ZodType>(name: string, schema: T): T

Source: packages/slingshot-core/src/createRoute.ts

Registers multiple Zod schemas at once as named entries in components/schemas. Object keys become the schema names. Returns the same object so you can destructure or re-export the schemas normally.

Schemas already registered (e.g. via a prior registerSchema call) are skipped.

Source: packages/slingshot-core/src/createRoute.ts

Store a new upload record. Keyed by the storage key.

async function registerUpload(record: UploadRecord, app: object): Promise<void>

Source: src/framework/upload/registry.ts

The relation builder namespace — creates informational RelationDef values for use in EntityConfig.relations.

Relations are metadata only — they inform code generators and admin tools but do NOT cause automatic joins in adapters.

Source: packages/slingshot-core/src/entityConfig.ts

Hono middleware that generates and propagates a unique request identifier.

A fresh UUID v4 is generated server-side on every request. Client-supplied X-Request-Id headers are intentionally ignored — accepting client-provided values would allow audit log spoofing and idempotency key manipulation.

The ID is:

  • Set on the Hono context via c.set('requestId', id) so it is accessible in all subsequent middleware and route handlers.
  • Written to the X-Request-Id response header after the handler chain completes, allowing clients to correlate requests with server-side logs.

Source: src/framework/middleware/requestId.ts

Hono middleware that emits a structured RequestLogEntry for every non-excluded HTTP request.

The log level is derived automatically from the response status:

  • "info" for 2xx/3xx
  • "warn" for 4xx
  • "error" for 5xx or unhandled exceptions

If the handler throws an unhandled error the exception is captured in entry.err, the entry is emitted, and then the error is re-thrown so Hono’s error handler can still process it. The onLog callback is always called inside a try/catch — a failing logger never affects the response.

function requestLogger(options: RequestLoggerOptions = {}): MiddlewareHandler<AppEnv>

Source: src/framework/middleware/requestLogger.ts

Middleware factory that verifies a CAPTCHA token from the request body.

When no config is provided, falls back to the captcha configuration from the app’s SlingshotContext. If neither is available, the middleware is a no-op (passes through to the next handler).

function requireCaptcha(config?: CaptchaConfig): MiddlewareHandler<AppEnv>

Source: src/framework/middleware/captcha.ts

Middleware that verifies the client has HMAC-signed the canonical request.

Canonical string: METHOD\nPATH\nCANONICAL_QUERY\nTIMESTAMP\nBODY

When signing.requestSigning is false (or not configured), the middleware is a no-op pass-through.

function requireSignedRequest(opts?: RequestSigningOptions): MiddlewareHandler<AppEnv>

Source: src/framework/middleware/requestSigning.ts

Entrypoint for declaring package domain routes, with withServices() to bind a typed service bag for handler IntelliSense.

Source: packages/slingshot-core/src/packageAuthoring.ts

function s3Storage(config: S3StorageConfig): StorageAdapter

Source: src/framework/adapters/s3Storage.ts

Complete list of all security.* event keys defined in SlingshotEventMap.

Used by the audit log plugin to identify events that must never reach browser clients. The array is frozen and typed as ReadonlyArray<SecurityEventKey>.

Source: packages/slingshot-core/src/eventBus.ts

Serialize all collected metrics into Prometheus exposition format.

Gauge callbacks are invoked at serialization time. Counter and histogram values are read from the in-memory state.

async function serializeMetrics(state: MetricsState): Promise<string>

Source: src/framework/metrics/registry.ts

SHA-256 hash a string and return the lowercase hex digest.

Centralised to avoid duplicate implementations across modules. Uses Node’s built-in crypto.createHash — synchronous and available in all environments.

function sha256(input: string): string

Source: packages/slingshot-core/src/crypto.ts

Returns "base64url(value).hmac".

function signCookieValue(value: string, secret: string | string[]): string

Source: src/lib/signing.ts

Returns "base64url(payload).hmac".

function signCursor(payload: string, secret: string | string[]): string

Source: src/lib/signing.ts

Constant-time string comparison to prevent timing attacks on secret verification.

Uses Node.js’s native crypto.timingSafeEqual so that the comparison time is independent of how many characters match. When the strings differ in length, a same-buffer compare is performed to burn equivalent time before returning false.

function timingSafeEqual(a: string, b: string): boolean

Source: packages/slingshot-core/src/crypto.ts

Convert a snake_case string to camelCase.

Used by SQL adapters to map database column names back to domain field names.

function toCamelCase(str: string): string

Source: packages/slingshot-entity/src/configDriven/fieldUtils.ts

Convert a camelCase string to snake_case.

Used by SQL adapters to map domain field names to database column names.

function toSnakeCase(str: string): string

Source: packages/slingshot-entity/src/configDriven/fieldUtils.ts

Parse and validate the JSON body of a Request against a Zod schema.

async function validate<T extends z.ZodType>(schema: T, req: Request,): Promise<z.output<T>>

Source: src/framework/lib/validate.ts

Returns the original value or null if the signature is invalid.

function verifyCookieValue(signed: string, secret: string | string[]): string | null

Source: src/lib/signing.ts

Returns the original payload or null if the signature is invalid.

function verifyCursor(cursor: string, secret: string | string[]): string | null

Source: src/lib/signing.ts

Verify an HMAC-signed URL. Returns the key and any extra params, or null if the URL is expired, tampered, or method-mismatched.

function verifyPresignedUrl(url: string, method: string, secret: string | string[],): void

Source: src/lib/signing.ts

Hono middleware that authenticates incoming webhook requests using HMAC signature verification.

Verification steps (in order):

  1. Timestamp replay protection (optional) — if options.timestamp is provided, the request timestamp header is validated against tolerance. Requests outside the tolerance window are rejected with 401.
  2. Signature header — the signature header (default x-webhook-signature) must be present; missing signatures yield 401.
  3. Secret resolution — the HMAC secret is resolved; dynamic functions (e.g. per-tenant secret lookups) are awaited. Resolver errors yield 500.
  4. HMAC comparison — the request body is HMAC-hashed and compared against the provided signature using timing-safe comparison. Mismatches yield 401.

The request body is read via c.req.text() which Hono caches, so downstream handlers can still call c.req.json() without issues.

function webhookAuth(options: WebhookAuthOptions): MiddlewareHandler<AppEnv>

Source: src/framework/middleware/webhookAuth.ts

Adds an OpenAPI security requirement to a route without affecting TypeScript type inference on the handler. Pass each security scheme as a separate object.

Use this instead of inlining security in createRoute(...) — inlining a field typed as { [name: string]: string[] } breaks c.req.valid() inference.

function withSecurity<T extends RouteConfig>(route: T, ...schemes: Array<Record<string, string[]>>): T

Source: packages/slingshot-core/src/createRoute.ts

Produces a collision-safe composite key for scoping rooms to an endpoint.

Both endpoint and room are percent-encoded before joining with :. Since encodeURIComponent encodes :%3A, the literal : separator can only come from this function — not from endpoint or room values.

Examples: wsEndpointKey(“/chat”, “general”) → “%2Fchat:general” wsEndpointKey(“/chat”, “room:1”) → “%2Fchat:room%3A1” wsEndpointKey(“/a:b”, “c”) → “%2Fa%3Ab:c” wsEndpointKey(“/notifications”, “x”) → “%2Fnotifications:x”

Used for: in-memory room maps, Redis channel names, Redis message keys. NOT used for: SQLite or MongoDB schemas (those store endpoint + room separately).

function wsEndpointKey(endpoint: string, room: string): string

Source: src/framework/ws/namespace.ts

Derive a Mongoose SchemaDefinition from a Zod object schema.

Business fields are auto-converted from Zod types to Mongoose types. DB-specific concerns (ObjectId refs, type overrides, subdocuments) are declared via config.

The id field is automatically excluded (Mongoose provides _id).

function zodToMongoose(zodSchema: ZodObjectLike, config: ZodToMongooseConfig = {},): Record<string, unknown>

Source: src/framework/lib/zodToMongoose.ts

Cookie name for the CSRF synchronizer token. Set as a readable (non-HttpOnly) cookie so that JavaScript can copy it into the header.

Source: packages/slingshot-core/src/constants.ts

Cookie name for the long-lived refresh token (HttpOnly, secure). Used by the auth plugin to issue new access tokens without re-authentication.

Source: packages/slingshot-core/src/constants.ts

Cookie name for the session access token (HttpOnly, short-lived). Used by the auth plugin to set and read the primary session credential.

Source: packages/slingshot-core/src/constants.ts

HTTP request header name for the CSRF token submitted by the client. The CSRF middleware compares this value against COOKIE_CSRF_TOKEN.

Source: packages/slingshot-core/src/constants.ts

HTTP header name for the client-provided idempotency key. Used by the idempotency middleware to deduplicate mutating requests.

Source: packages/slingshot-core/src/constants.ts

HTTP header name for the refresh token (alternative to cookie transport).

Source: packages/slingshot-core/src/constants.ts

HTTP header name for the per-request trace identifier. Set by the request-id middleware and echoed in all error responses.

Source: packages/slingshot-core/src/constants.ts

HTTP header name for the HMAC request signature. Used by the webhook signing middleware to verify inbound webhook authenticity.

Source: packages/slingshot-core/src/constants.ts

HTTP header name for the request timestamp included in the HMAC signature. The signing middleware rejects requests with a timestamp outside the replay window.

Source: packages/slingshot-core/src/constants.ts

HTTP header name for the session access token (alternative to cookie transport). Used by SPA and mobile clients that manage tokens in memory.

Source: packages/slingshot-core/src/constants.ts

HTTP 409 error for a guarded or required transaction mutation that did not apply.

Source: packages/slingshot-core/src/transactions.ts

HTTP-aware error carrying a response status and optional machine-readable code.

Source: packages/slingshot-core/src/errors.ts

Default no-op transport. Single-instance — all messages go through Bun’s native server.publish() only. No cross-instance delivery.

Source: src/framework/ws/transport.ts

Source: src/prodReadiness.ts

HTTP 400 error for a missing or malformed declarative transaction binding.

Source: packages/slingshot-core/src/transactions.ts

Thrown when commit fails, including whether rollback can be proven.

Source: packages/slingshot-core/src/transactions.ts

Reports framework-owned post-commit failures without claiming the database rolled back.

Source: packages/slingshot-core/src/transactions.ts

Thrown when a retained scope or scoped adapter is used after its callback settles.

Source: packages/slingshot-core/src/transactions.ts

Thrown for a forged scope, a foreign-app scope, or a scope owned by another manager.

Source: packages/slingshot-core/src/transactions.ts

Thrown when nested or entity work targets a store different from the active scope.

Source: packages/slingshot-core/src/transactions.ts

Thrown when an app cannot provide a real transaction for the requested store.

Source: packages/slingshot-core/src/transactions.ts

Thrown after rollback when a callback returned with scope-bound work still pending.

Source: packages/slingshot-core/src/transactions.ts

HTTP 400 error that preserves structured Zod validation issues.

Source: packages/slingshot-core/src/errors.ts

Source: src/config/types/meta.ts

A single audit log entry recording an HTTP request or admin action.

Stored by AuditLogProvider.logEntry() and queryable via AuditLogProvider.getLogs(). The audit middleware creates entries automatically for authenticated requests.

Source: packages/slingshot-core/src/auditLog.ts

Source: src/framework/middleware/auditLog.ts

Configuration for creating an audit log provider.

Source: src/framework/auditLog/index.ts

Query parameters for retrieving audit log entries.

Source: src/framework/auditLog/index.ts

Database/store connection configuration for slingshot-auth.

Controls which persistence backends are used for sessions, OAuth state, and the user auth adapter. Each field is optional — defaults are chosen by the bootstrap layer based on what is available (Redis → SQLite → memory).

Remarks: When running under the full framework (createApp / createServer), connection objects are provided automatically via SlingshotFrameworkConfig. These fields are only relevant in standalone mode or when explicitly overriding framework-provided connections.

Source: packages/slingshot-auth/src/types/config.ts

Security configuration for slingshot-auth.

Controls JWT signing, CSRF protection, bearer token auth, captcha integration, trust-proxy behavior, and CORS origins used for CSRF origin checking.

Source: packages/slingshot-auth/src/types/config.ts

Source: src/config/types/security.ts

Source: src/framework/middleware/botProtection.ts

CAPTCHA middleware configuration for protecting public auth endpoints.

When configured, the CAPTCHA middleware validates a client-submitted token before allowing registration, login, or password-reset requests to proceed.

Source: packages/slingshot-core/src/captcha.ts

Source: src/app.ts

The result of createApp: the assembled OpenAPI-enabled Hono application and its frozen instance-scoped context.

Source: src/app.ts

Source: src/server.ts

Options for creating a new tenant.

Source: src/framework/tenancy/service.ts

Options for cursor-paginated adapter list operations.

Pass cursor from a previous PaginatedResult.nextCursor to fetch the next page. Omit cursor to start from the beginning. Combine with sortDir to reverse traversal.

Source: packages/slingshot-core/src/entityConfig.ts

Default values for cursor-based pagination query parameters.

Source: src/framework/lib/pagination.ts

A single page of cursor-paginated results.

Source: src/framework/lib/pagination.ts

Source: src/config/types/db.ts

The response body shape produced by defaultValidationErrorFormatter. Clients can use details for per-field error display and requestId for support.

Source: packages/slingshot-core/src/context.ts

Input contract for definePackage(...).

Source: packages/slingshot-core/src/packageAuthoring.ts

Domain route contract used by package-first authoring and compiled into framework routes.

Source: packages/slingshot-core/src/packageAuthoring.ts

The typed adapter interface generated for an entity by slingshot-data.

Provides CRUD operations with full type inference from the entity’s field definitions. The create, update, delete, and list methods handle soft-delete logic transparently when the entity is configured with softDelete.

Source: packages/slingshot-core/src/entityConfig.ts

The complete entity definition — the single source of truth for an entity’s schema, persistence, and route/channel configuration.

Pass this to defineEntity() which validates it and derives _pkField and _storageName. The resolved result is deep-frozen and registered with the entity registry.

Source: packages/slingshot-core/src/entityConfig.ts

Resolved field definition — the normalised shape stored in EntityConfig.fields.

Created by the field.*() builders. Plugins should treat this as opaque.

Generic parameters preserve literal types for precise InferCreateInput narrowing:

  • T — the FieldType token
  • IsOptionaltrue or false literal
  • Default — the exact default value type (e.g. 'uuid', 'now', 'member', undefined)
  • OnUpdate'now' or undefined

All parameters have wide defaults so existing FieldDef usages without type params continue to compile without changes.

Source: packages/slingshot-core/src/entityConfig.ts

Options shared by all field.*() builders.

Control optional/required status, default values, immutability, and primary key designation.

Source: packages/slingshot-core/src/entityConfig.ts

The four Zod schemas generated from a ResolvedEntityConfig.

Each schema is a z.ZodObject so callers can merge, extend, or .parse() it.

Source: packages/slingshot-entity/src/configDriven/schemaGen.ts

Per-endpoint WebSocket heartbeat configuration.

The server sends periodic pings; sockets that fail to respond with a pong within the timeout window are closed automatically.

Source: src/framework/ws/heartbeat.ts

Out-of-request hook services. Mirrors the accessor surface PackageDomainRouteContext exposes to request-scoped route handlers, plus the raw pluginState map as an escape hatch for callers that need slots no typed accessor yet covers.

Always construct via buildHookServices() at the hook call site — never fabricate one by hand. Hook payloads in plugin lifecycle callbacks should declare services: HookServices (or services?: HookServices for callbacks that can fire from worker isolates that cannot reach the app).

Source: packages/slingshot-core/src/hookServices.ts

Storage contract for idempotency key deduplication.

When a client retries a mutating request with the same Idempotency-Key header, the idempotency middleware looks up the cached response via this adapter and returns it instead of executing the handler again.

Remarks: Implementations must respect the ttlSeconds argument in set() — records should expire automatically after the configured TTL. The framework sets a default TTL of 24 hours for idempotency records.

Source: packages/slingshot-core/src/idempotencyAdapter.ts

Source: src/framework/lib/idempotency.ts

A compound index definition for an entity.

Created via the index() helper and listed in EntityConfig.indexes. Adapters use these definitions to create backing store indexes at startup.

Source: packages/slingshot-core/src/entityConfig.ts

Source: src/config/types/jobs.ts

Source: src/framework/adapters/localStorage.ts

Source: src/config/types/logging.ts

Source: src/config/types/metrics.ts

Source: src/framework/middleware/metrics.ts

Observability configuration for the Slingshot framework.

Groups tracing, and future observability concerns (e.g., profiling) under a single namespace.

Source: src/config/types/observability.ts

Default overrides for offset-based pagination query parameters. All fields are optional — omitted fields fall back to framework defaults (limit=50, offset=0, maxLimit=200).

Source: packages/slingshot-core/src/pagination.ts

Typed, named token a package publishes and consumers resolve to exchange a capability value across packages.

Source: packages/slingshot-core/src/packageAuthoring.ts

Typed capability lookup helpers exposed to package domain routes.

Source: packages/slingshot-core/src/packageAuthoring.ts

Provider-owned package public contract. Binds capabilities and public entity refs to a single package, validates capability ownership at definePackage(...) time, and carries identity metadata on every ref/capability it produces so the framework can validate the cross-package graph at boot.

Source: packages/slingshot-core/src/packageAuthoring.ts

Full handler context available to package-authored domain routes.

Source: packages/slingshot-core/src/packageAuthoring.ts

Package-owned entity module returned by entity(...).

Source: packages/slingshot-entity/src/packageAuthoring.ts

Lookup helper for framework-managed entity adapters owned by the app.

Source: packages/slingshot-core/src/packageAuthoring.ts

Lightweight typed entity handle used for package-local and cross-package adapter lookups.

Source: packages/slingshot-core/src/packageAuthoring.ts

Static inspection output for a package’s effective modules and capability graph.

Source: packages/slingshot-core/src/packageAuthoring.ts

Canonical request metadata exposed to package-authored route handlers.

Source: packages/slingshot-core/src/packageAuthoring.ts

Cursor pagination configuration for an entity’s list operation.

cursor.fields are the tie-breaking fields used to construct stable, opaque cursors. Typically ['createdAt', 'id'] for stable time-ordered pagination.

Source: packages/slingshot-core/src/entityConfig.ts

Parsed and validated cursor pagination parameters ready for adapter consumption.

Source: src/framework/lib/pagination.ts

Parsed and clamped offset pagination parameters ready for use in a query.

Source: packages/slingshot-core/src/pagination.ts

Server-level permissions configuration.

When set, the framework bootstraps a shared PermissionsAdapter, PermissionRegistry, and PermissionEvaluator from the existing infra connection and writes them to ctx.pluginState at PERMISSIONS_STATE_KEY before any plugin setup phase runs.

Plugins that accept permissions in their own config remain backward compatible - an explicit plugin-level config takes precedence over the server-level bootstrap.

Requires @lastshotlabs/slingshot-permissions to be installed. A clear error is thrown at startup if the package is missing.

Source: src/config/types/permissions.ts

Source: src/config/types/upload.ts

Source: src/prodReadiness.ts

Source: src/prodReadiness.ts

Source: src/prodReadiness.ts

Published capability resolver registered by a package during bootstrap.

Source: packages/slingshot-core/src/packageAuthoring.ts

Source: src/framework/ws/rooms.ts

Source: src/framework/middleware/rateLimit.ts

Source: src/lib/redis.ts

Source: src/framework/ws/redisTransport.ts

Informational relation metadata for an entity field.

Relations are NOT automatically joined by adapters — they are metadata hints for code generation, admin UIs, and schema documentation tools. Joins must be done manually in operation configs (op.derive, op.lookup) or at the application layer.

Source: packages/slingshot-core/src/entityConfig.ts

Structured log entry emitted for each HTTP request by requestLogger.

Compatible with common structured-logging sinks (Pino, Winston, Datadog, etc.) when serialised as JSON.

Source: src/framework/middleware/requestLogger.ts

Source: src/framework/middleware/requestLogger.ts

Source: src/framework/middleware/requestSigning.ts

The validated, frozen output of defineEntity().

Extends EntityConfig with derived fields computed at definition time:

  • _pkField — the primary key field name
  • _storageName — the table/collection name with namespace applied
  • _systemFields — resolved audit, ownership, and tenant field names
  • _storageFields — resolved Mongo PK and TTL column names
  • _conventions — resolved storage convention overrides (Redis key, ID gen, etc.)

The object is deeply frozen — all nested configs are immutable after defineEntity() returns.

Source: packages/slingshot-core/src/entityConfig.ts

The resolved result of pairing an entity config with its named operation configs.

Produced by op.define() (in slingshot-data) and consumed by the executor and codegen layers. The operations map is keyed by operation name (e.g. 'getByRoom').

Source: packages/slingshot-core/src/operations.ts

Resolved persistence repositories for the application instance.

Created by resolveFrameworkPersistence() during server bootstrap and wired into SlingshotContext by createApp(). All repositories are instance-scoped — no shared module-level state across app instances.

Remarks: Access these repositories via ctx.persistence.* in plugin setupPost hooks and in framework middleware. Never access them before createApp() completes.

Source: packages/slingshot-core/src/context/slingshotContext.ts

Configuration for the S3-compatible storage adapter.

Compatible with AWS S3, Cloudflare R2, MinIO, and any S3-compatible endpoint.

Source: src/framework/adapters/s3Storage.ts

Source: src/config/types/security.ts

Configuration for the Slingshot-integrated admin plugin.

Extends AdminPluginConfig with optional overrides for accessProvider, managedUserProvider, and permissions. When these are omitted, sensible framework defaults are resolved automatically:

  • accessProvider defaults to createSlingshotAuthAccessProvider, which reads permissions from the auth runtime context.
  • managedUserProvider defaults to createSlingshotManagedUserProvider, constructed from the auth runtime adapter, config, and session repository.
  • permissions defaults to the value stored under PERMISSIONS_STATE_KEY in ctx.pluginState — set by the community plugin or another permissions source during its setupRoutes phase.

All three are required at route-registration time. If permissions is not provided and no plugin has populated PERMISSIONS_STATE_KEY, setupPost throws.

Source: src/framework/admin/index.ts

The instance-scoped runtime state container for a Slingshot application.

Created by createApp(), attached to the Hono app instance via WeakMap, and accessible from route handlers via getContext(app).

Replaces module-level singletons with instance-scoped state. Each createApp() invocation produces its own context — no shared globals, no cross-instance leakage.

Source: packages/slingshot-core/src/context/slingshotContext.ts

The typed in-process event bus shared across all Slingshot plugins.

Each createApp() call produces its own bus instance attached to SlingshotContext.bus. Plugins subscribe and emit events through this interface without depending on a specific implementation (in-process, Redis Streams, etc.).

Remarks: Server-side policy consumers should prefer onEnvelope() so they can inspect canonical metadata such as scope and exposure without re-deriving it from payloads.

Source: packages/slingshot-core/src/eventBus.ts

Central event map for all built-in Slingshot events.

Typed key to payload pairs consumed by SlingshotEventBus. Plugin packages extend this map via TypeScript module augmentation in their own events.ts file, never by modifying this interface directly.

Source: packages/slingshot-core/src/eventMap.ts

Immutable package definition consumed by createApp({ packages }).

Source: packages/slingshot-core/src/packageAuthoring.ts

The core plugin contract for Slingshot framework plugins.

Plugins extend the framework by implementing one or more lifecycle phase methods. The framework calls each phase in a fixed order during server bootstrap, giving plugins deterministic control over when their middleware and routes are registered.

Remarks: Declare dependencies to ensure prerequisite plugins are registered first. The framework resolves dependency order before calling any plugin phases. Plugin runtime state should be published with publishPluginState(ctx.pluginState, plugin.name, state) in the earliest lifecycle phase where it becomes canonical, so it stays instance-scoped rather than module-global and dependent plugins can read it in later phases. The framework seals plugin state after bootstrap.

Source: packages/slingshot-core/src/plugin.ts

The resolved application configuration stored on SlingshotContext.

A normalised snapshot of the user-supplied app config after all defaults are applied and all referenced infrastructure handles are resolved. Accessed via ctx.config.

Remarks: Unknown types for external handles: several fields (redis, mongo, signing, captcha) are typed as unknown rather than their concrete types (ioredis Redis, Mongoose Connection, etc.) to keep slingshot-core free of hard dependencies on those packages. Cast them to the correct type at use sites in the framework layer using a JSDoc boundary comment to document the cast.

Remarks: Frozen at creation: this object is frozen by createApp() before it is stored on SlingshotContext. Mutations after creation will be silently ignored in non-strict environments and will throw in strict mode. Build new config snapshots rather than attempting to patch the existing one.

Remarks: WebSocket configuration: SlingshotResolvedConfig does not carry WebSocket state — WS runtime state is held on SlingshotContext.ws which starts as null and is populated by createServer() after the Bun server initialises. Do not access ctx.ws during plugin setup phases; it will always be null at that point.

Source: packages/slingshot-core/src/context/slingshotContext.ts

Source: src/config/types/sse.ts

Configuration for a single SSE endpoint in CreateServerConfig.sse.endpoints.

Each endpoint specifies which client-safe events it streams, an optional auth/upgrade hook, an optional per-client filter, and a heartbeat interval.

Source: packages/slingshot-core/src/sse.ts

A plugin that guarantees a setup implementation for standalone (non-framework) usage.

Use this type when a plain Hono app calls plugin.setup(app, config, bus) directly instead of going through the full framework orchestrator. Narrow SlingshotPlugin to StandalonePlugin when you need a compile-time guarantee that setup is present.

Remarks: The key guarantee: assigning a value to StandalonePlugin is a compile-time error if setup is missing or optional. This prevents a runtime crash when calling plugin.setup(...) in a plain Hono context where the framework lifecycle is absent.

Remarks: A StandalonePlugin can still implement setupMiddleware, setupRoutes, and setupPost — those fields are inherited from SlingshotPlugin. If the plugin is later registered with a full Slingshot app, the framework will call the phase methods and never call setup. Both paths can coexist without double-execution risk.

Source: packages/slingshot-core/src/plugin.ts

Pluggable object storage adapter for the upload middleware.

Implement this interface to connect any storage backend (S3, R2, local disk, etc.) to the Slingshot upload infrastructure. Registered via the uploads plugin configuration.

Source: packages/slingshot-core/src/storageAdapter.ts

Multi-tenant scoping configuration for an entity.

When set, the framework ensures that all queries are automatically scoped to the current tenant context. The field must exist in EntityConfig.fields and should be of type 'string'.

Source: packages/slingshot-core/src/entityConfig.ts

Read-only representation of a tenant record.

Source: src/framework/tenancy/service.ts

CRUD service for managing tenant records.

Supports creation, soft-deletion (with reactivation), lookup, and listing.

Source: src/framework/tenancy/service.ts

Configuration for distributed tracing via OpenTelemetry.

Slingshot instruments bootstrap phases, request lifecycles, and plugin lifecycle calls with OTel spans. The framework depends on @opentelemetry/api only — install an OTel SDK and exporter in your app to collect spans.

When enabled is false or omitted, no tracer is created and no spans are recorded. The OTel API returns no-op implementations in that case, so there is zero runtime overhead.

Source: src/config/types/observability.ts

Bind an entity resolution to one open transaction scope.

Source: packages/slingshot-core/src/transactions.ts

Framework-owned entry point for imperative package/domain transactions.

Source: packages/slingshot-core/src/transactions.ts

One sanitized framework-owned effect that failed after database commit.

Source: packages/slingshot-core/src/transactions.ts

Opaque identity for one framework-owned transaction.

A scope contains no database driver. Obtain it only from TransactionManager.run and pass it back through scope-aware framework APIs.

Source: packages/slingshot-core/src/transactions.ts

Common request context shared by package-authored domain route handlers.

Source: packages/slingshot-core/src/packageAuthoring.ts

Request validation contract for package-authored domain routes.

Source: packages/slingshot-core/src/packageAuthoring.ts

OpenAPI-oriented response metadata for package-authored domain routes.

Source: packages/slingshot-core/src/packageAuthoring.ts

Source: src/config/types/upload.ts

Options for configuring file upload parsing and storage.

Source: src/framework/upload/upload.ts

Metadata record stored when a file is uploaded via the framework upload middleware.

Used to verify ownership and tenancy when users request presigned download URLs or initiate delete operations. Stored in the UploadRegistryRepository.

Source: packages/slingshot-core/src/uploadRegistry.ts

Storage contract for tracking upload ownership and metadata.

Implementations store UploadRecord entries keyed by the storage key. The upload middleware calls register() after a successful upload. Presigned-download and delete handlers call get() to verify ownership.

Source: packages/slingshot-core/src/uploadRegistry.ts

Metadata about a completed upload, populated by the upload middleware and stored in c.get('uploadResults') for route handlers to inspect.

Source: packages/slingshot-core/src/storageAdapter.ts

Source: src/config/types/validation.ts

A single field-level validation error detail produced by the default formatter.

Source: packages/slingshot-core/src/context.ts

Source: src/config/types/versioning.ts

Source: src/framework/middleware/webhookAuth.ts

Source: src/framework/middleware/webhookAuth.ts

Source: src/config/types/ws.ts

Passed to every incoming event handler and middleware.

Source: src/config/types/ws.ts

Source: src/config/types/ws.ts

Storage contract for WebSocket message persistence.

Implementations store messages per (endpoint, room) scope with configurable max count and TTL-based expiration. Used by the framework’s WS history and session-recovery features.

Source: packages/slingshot-core/src/wsMessages.ts

Instance-scoped WebSocket runtime state container.

Populated by createServer() after the Bun server is started. null on the context when the application has no WebSocket endpoints configured.

Remarks: The socket registry uses unknown types to prevent slingshot-core from importing Bun types. Cast to ServerWebSocket<SocketData> at use sites in the framework layer.

Source: packages/slingshot-core/src/context/slingshotContext.ts

Pluggable transport for cross-instance WebSocket message delivery.

publish() is called on every room broadcast — the transport fans out the message to other server instances (e.g. via Redis pub/sub).

connect() is called once at server startup. The onMessage callback should be invoked when a message arrives from another instance — it will be delivered to local sockets via Bun’s native server.publish().

disconnect() is called on graceful shutdown.

Source: src/framework/ws/transport.ts

Cross-instance WebSocket transport adapter.

Used by the framework to fan out WS messages across multiple server instances in a distributed deployment (e.g., via Redis Pub/Sub). A null handle means single-instance deployment with no cross-instance delivery.

Remarks: Defined here (not in framework internals) so SlingshotContext can reference it without a circular dependency on the framework’s transport layer.

Source: packages/slingshot-core/src/context/slingshotContext.ts

Source: src/app.ts

Canonical declarative app config shape.

Alias of CreateServerConfig surfaced under a friendlier name. Users author this in app.config.ts and the framework boots from the default export.

Source: src/defineApp.ts

The Hono Env type for all Slingshot routers.

Pass this as the generic parameter to Hono, OpenAPIHono, and Context to get fully-typed access to request variables set by the framework middleware.

Source: packages/slingshot-core/src/context.ts

Source: src/config/types/tenancy.ts

The Hono context variable bag set by framework middleware on every request.

These variables are accessible via c.get('variableName') in route handlers. They are populated by the framework before any plugin or user route runs.

Source: packages/slingshot-core/src/context.ts

Source: src/app.ts

Full plugin configuration object for createAuthPlugin.

Combines the Zod-validated base config with the runtime field (standalone-only dependencies injected outside of Zod validation).

Source: packages/slingshot-auth/src/types/config.ts

Source: src/app.ts

Source: src/app.ts

Supported CAPTCHA verification providers.

  • 'recaptcha' — Google reCAPTCHA v2 or v3
  • 'hcaptcha' — hCaptcha
  • 'turnstile' — Cloudflare Turnstile

Source: packages/slingshot-core/src/captcha.ts

Source: src/app.ts

Source: src/framework/lib/createDtoMapper.ts

Source: src/app.ts

Supported adapter-wiring strategies for a package-owned entity module.

Source: packages/slingshot-entity/src/packageAuthoring.ts

Source: packages/slingshot-core/src/entityConfig.ts

All supported field type tokens for use with field.*() builders.

Each token maps to a TypeScript type via FieldTypeMap and controls how adapters store and serialise field values for each backing store.

Source: packages/slingshot-core/src/entityConfig.ts

Source: ./app

Infer the CreateInput type from a fields record.

Excludes auto-managed fields (auto-generated defaults and onUpdate fields); fields with a default or marked optional become optional, while the rest are required.

Source: packages/slingshot-core/src/entityConfig.ts

Infer the full entity type (all fields, respecting optional).

Source: packages/slingshot-core/src/entityConfig.ts

Infers an entity’s update-input shape from its field definitions — mutable fields only, each optional, and nullable when the field itself is optional.

Source: packages/slingshot-core/src/entityConfig.ts

Source: src/app.ts

Severity level for a structured request log entry.

  • "info" — successful responses (status < 400).
  • "warn" — client-error responses (status 400–499).
  • "error" — server-error responses (status >= 500) or unhandled exceptions.

Source: src/framework/middleware/requestLogger.ts

Source: src/app.ts

Source: src/app.ts

Source: src/app.ts

Source: src/app.ts

Source: ./app

Source: src/lib/mongo.ts

Source: src/app.ts

Source: src/app.ts

Union of all supported declarative operation configuration types. Used as the value type in ResolvedOperations.operations and PipeStep.config.

Source: packages/slingshot-core/src/operations.ts

Strongly typed adapter surface inferred from an entity config and optional operation map.

Source: packages/slingshot-entity/src/packageAuthoring.ts

Source: src/app.ts

Source: src/app.ts

Source: src/prodReadiness.ts

Source: src/prodReadiness.ts

Source: src/prodReadiness.ts

Source: src/app.ts

Source: src/app.ts

Source: src/app.ts

Source: src/config/types/secrets.ts

Extracts the subset of SlingshotEventMap keys that belong to the security.* namespace.

Source: packages/slingshot-core/src/eventMap.ts

Source: src/app.ts

Per-socket data attached to every WebSocket connection by the Bun server.

This type is the data object passed to all ws.* handler callbacks (open, message, close, drain). The generic T parameter lets plugins attach custom fields (e.g., roomId) at upgrade time. The base fields are populated by createWsUpgradeHandler.

Source: src/framework/ws/index.ts

Soft-delete configuration for an entity.

When set, delete operations update a field instead of removing the record. Two strategies are supported:

  • { field, value } — sets the field to a specific value (e.g., status: 'deleted')
  • { field, strategy: 'non-null' } — sets a nullable field to a non-null timestamp

Soft-deleted records are excluded from list and getById queries by default.

Source: packages/slingshot-core/src/entityConfig.ts

Source: src/framework/sse/index.ts

Source: src/framework/sse/index.ts

Source: src/app.ts

Source: src/config/types/tenancy.ts

Outcome that can be stated truthfully after a commit failure.

Source: packages/slingshot-core/src/transactions.ts

Result value produced by one declarative transaction step.

Source: packages/slingshot-core/src/transactions.ts

Stores reserved for real framework-owned transaction implementations.

Source: packages/slingshot-core/src/transactions.ts

Best-effort binding input exposed for handler convenience.

Object bodies are merged with params/query at runtime. Array and primitive bodies are passed through directly because they cannot be meaningfully merged into a record.

Source: packages/slingshot-core/src/packageAuthoring.ts

Response metadata keyed by HTTP status code.

Source: packages/slingshot-core/src/packageAuthoring.ts

Options for the handleUpload middleware.

All fields are optional overrides of the app-level upload configuration stored in SlingshotContext. Values provided here take precedence over the app-level defaults for a specific route.

See UploadOpts (from @framework/upload/upload) for available fields: maxFileSize, maxFiles, allowedMimeTypes, keyPrefix, etc.

Source: src/framework/middleware/upload.ts

A function that converts Zod issues into a custom validation error response body.

Override this in your app config to control the shape of 400 validation errors. The default is defaultValidationErrorFormatter which produces DefaultValidationErrorBody.

Remarks: If the formatter throws, defaultHook catches the error and falls back to defaultValidationErrorFormatter automatically — a buggy custom formatter will not cause a 500. The formatter must be synchronous; async formatters are not supported.

Source: packages/slingshot-core/src/context.ts

Authentication level required for a WebSocket event or endpoint.

  • 'userAuth' — requires an authenticated user session.
  • 'bearer' — requires a valid bearer token.
  • 'none' — no authentication required.

Source: src/config/types/ws.ts

The return value is sent as the ack result when the client included an ackId. Throw to send an ack error response instead. Returning undefined → ack result is null.

Source: src/config/types/ws.ts

Guard called before each incoming event handler. Returns true to allow, false to deny (ack error ‘forbidden’ sent if ackId present).

Source: src/config/types/ws.ts

Source: src/framework/lib/zodToMongoose.ts

Source: src/framework/lib/zodToMongoose.ts

Source: ./app

Create a RepoFactories object that produces a composite adapter covering all the supplied entities, plus any cross-entity transaction or pipe operations.

Each entry in entities maps a key name to an { config, operations? } pair. The returned factories object has a factory for every StoreType (memory, redis, sqlite, mongo, postgres). When a factory is called by resolveRepo(), it instantiates an individual adapter for each entity, wires any composite operations against the full adapters map, and combines everything into a single composite object that also exposes a clear() method.

TypeScript infers the full shape of the composite adapter from both the entity map and the composite operations map, including all operation method signatures.

Why composite operations? op.transaction and op.pipe need access to multiple entity adapters simultaneously — they cannot be wired inside a single entity’s adapter factory. Declare them here so they receive the full adapters map at wiring time.

Atomicity:

  • memory — steps run sequentially but earlier writes are not rolled back after failure.
  • sqlite — steps are wrapped in an explicit BEGIN / COMMIT / ROLLBACK block.
  • postgres — transaction ops run on a single pg client inside BEGIN / COMMIT / ROLLBACK, so all steps share one real database transaction.
  • mongo, redis — no transaction wrapper is applied yet. These backends require backend-specific session or multi-command transaction support and are left for future work.

Source: packages/slingshot-entity/src/configDriven/composition.ts

Create a toDto mapper function from a Zod schema.

The Zod schema defines which fields exist in the DTO. The config declares how to transform DB-specific types (ObjectId refs, Dates, subdocuments).

Handles automatically:

  • _id -> id (toString)
  • ObjectId refs -> string (toString), with field renaming via refs
  • Date fields -> ISO string via dates
  • Subdocument arrays via subdocs
  • Nullable/optional fields -> null coercion (from undefined)
  • All other fields -> passthrough

Source: src/framework/lib/createDtoMapper.ts

Create TestableRepoFactories for a resolved entity config without operations.

Source: packages/slingshot-entity/src/configDriven/createEntityFactories.ts

Define an entity — the entry point for the config-driven persistence system.

Validates the config (primary key presence, soft-delete field existence, index field references, pagination cursor fields, and search config) then returns a deep-frozen ResolvedEntityConfig with _pkField and _storageName derived automatically.

Remarks: Storage name derivation: _storageName is derived from name by converting to snake_case, applying English pluralisation rules, and prepending namespace_ when a namespace is provided. Examples:

Remarks: | Name | Namespace | _storageName | |---------------|------------|------------------------| | Message | 'chat' | 'chat_messages' | | MyEntity | 'chat' | 'chat_my_entities' | | Category | — | 'categories' | | Activity | — | 'activities' | | Box | — | 'boxes' | | Status | — | 'statuses' |

Remarks: Pluralisation rules applied in order: 1. Ends in y preceded by a consonant → replace y with ies (categorycategories, activityactivities). Vowel-preceded y (day, key) gets a plain s suffix. 2. Ends in s, x, z, sh, or ch → append es (boxboxes). 3. All other cases → append s.

Remarks: To override the derived name (e.g. for an irregular plural or a legacy table), set storage.sqlite.tableName / storage.postgres.tableName / storage.mongo.collectionName in EntityStorageHints. The _storageName value itself cannot be overridden — it is used as the canonical key for event bus routing and WebSocket room names regardless of backing-store table names.

Source: packages/slingshot-core/src/entityConfig.ts

Declare and validate operations for an entity.

Operations describe business-logic queries and mutations beyond basic CRUD. This function:

  1. Validates that all field references in operation configs point to real fields on the entity (e.g. transition.field, fieldUpdate.set, search.fields).
  2. Deep-freezes the resulting operations object (CLAUDE.md rule 12).

Source: packages/slingshot-entity/src/defineOperations.ts

Declare a package-owned non-entity route group and optional domain-local services.

Source: packages/slingshot-core/src/packageAuthoring.ts