Skip to content

@lastshotlabs/slingshot-entity

npm install @lastshotlabs/slingshot-entity

Shared field-mapping utilities for config-driven adapters.

  • camelCase ↔ snake_case conversion
  • SQL / Mongo type mapping
  • Record transformation (domain ↔ storage)
  • Auto-default resolution
  • Naming conventions per backend
function applyDefaults(input: Record<string, unknown>, fields: Record<string, FieldDef>, customAutoDefault?: CustomAutoDefaultResolver,): Record<string, unknown>

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

Shared field-mapping utilities for config-driven adapters.

  • camelCase ↔ snake_case conversion
  • SQL / Mongo type mapping
  • Record transformation (domain ↔ storage)
  • Auto-default resolution
  • Naming conventions per backend
function applyOnUpdate(input: Record<string, unknown>, fields: Record<string, FieldDef>, customOnUpdate?: CustomOnUpdateResolver,): Record<string, unknown>

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

Entity audit runner — combines all audit rules.

Pure function: (entityConfig, operations?) → EntityAuditResult

function auditEntity(config: ResolvedEntityConfig, operations?: Record<string, OperationConfig>,): EntityAuditResult

Source: packages/slingshot-entity/src/audits/index.ts

applyChannelConfig — builds subscribe guards and event forwarding for config-driven WebSocket entity channels.

Two responsibilities:

  1. Subscribe guard: parses room names, enforces auth/permissions/middleware
  2. Event forwarding: wires bus events to WS room publish calls
function buildEntityReceiveHandlers(channelConfig: EntityChannelConfig, entity: ResolvedEntityConfig, getWsState: () => WsState | null, publishFn: WsPublishFn<WsState>, endpoint: string,): Record<string, ChannelIncomingEventDeclaration>

Source: packages/slingshot-entity/src/channels/applyChannelConfig.ts

Arguments for resolvePolicy.

function buildPolicyAction(opName: string): PolicyAction

Source: packages/slingshot-entity/src/policy/resolvePolicy.ts

applyChannelConfig — builds subscribe guards and event forwarding for config-driven WebSocket entity channels.

Two responsibilities:

  1. Subscribe guard: parses room names, enforces auth/permissions/middleware
  2. Event forwarding: wires bus events to WS room publish calls
function buildSubscribeGuard(channelConfigs: Map<string, EntityChannelConfig>, deps: ChannelConfigDeps,): (ws: unknown, room: string) => Promise<boolean>

Source: packages/slingshot-entity/src/channels/applyChannelConfig.ts

createEntityPlugin — Plugin-level orchestration for config-driven entities.

Wires entities into the Slingshot plugin lifecycle:

  • setupRoutes: builds bare routes, applies config middleware, mounts onto app
  • setupPost: registers permission resource types and post-route integrations
  • teardown: unsubscribes cascade event handlers

Consumers wire entities via EntityPluginEntry — either with buildAdapter (manual) or with factories + entityKey (composite, zero-code). This keeps the package free of framework-internal dependencies.

function createEntityPlugin(pluginConfig: EntityPluginConfig): EntityPlugin

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

Helper used by feature packages whose adapter- or capability-dependent middleware handlers can only be wired after lifecycle hooks run.

The returned ref starts as a pass-through next() no-op. The package mounts middleware that forwards through ref.handler, then assigns the real handler from setupMiddleware or setupPost once its dependencies are resolved.

function createLazyMiddleware(): LazyMiddlewareRef

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

Config-driven memory adapter generator.

Produces an EntityAdapter backed by an in-memory Map with LRU eviction, optional TTL, soft-delete, cursor pagination, and tenant scoping.

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

Config-driven MongoDB adapter generator.

Lazily creates a Mongoose model from the entity config, including compound indices, TTL expiration, soft-delete, cursor pagination, and tenant scoping.

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

Zod schema validation for entity and operation definitions.

These schemas validate the structural correctness of configs. Cross-field validation (e.g., “softDelete field must exist in fields”) uses Zod’s .superRefine() for clear, composable error messages.

function createOperationValidator(fieldNames: readonly string[]): void

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

Config-driven PostgreSQL adapter generator.

Produces a full EntityAdapter implementation backed by a pg connection pool, driven entirely by ResolvedEntityConfig — no hand-written SQL schema required.

Features:

  • Auto-creates the table on first use (CREATE TABLE IF NOT EXISTS) with correct column types, NOT NULL constraints, and a PRIMARY KEY.
  • Creates compound indexes (CREATE INDEX IF NOT EXISTS) and unique constraints (CREATE UNIQUE INDEX IF NOT EXISTS) from config.indexes and config.uniques.
  • Optional TTL column (configurable, default _expires_at) when config.ttl.defaultSeconds is set.
  • Soft-delete: delete() writes the soft-delete field value instead of DELETE.
  • Cursor pagination: multi-field lexicographic cursors via buildCursorForRecord/decodeCursor.
  • create() uses plain INSERT; primary-key and unique conflicts reject consistently with the memory and SQLite adapters. Replacement requires an explicit update/upsert operation.
  • Spreads buildPostgresOperations() result to attach custom operation methods.
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

Config-driven Redis adapter generator.

Records are stored as JSON strings under prefixed keys. Supports TTL, soft-delete, cursor pagination, and tenant scoping.

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

Config-driven SQLite adapter generator.

Auto-creates the table on first use, generates indices for indexed fields, and handles domain ↔ storage mapping including dates, JSON, booleans, etc. Supports soft-delete, cursor pagination, TTL, and tenant scoping.

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

Shared field-mapping utilities for config-driven adapters.

  • camelCase ↔ snake_case conversion
  • SQL / Mongo type mapping
  • Record transformation (domain ↔ storage)
  • Auto-default resolution
  • Naming conventions per backend
function decodeCursor(cursor: string): Record<string, unknown>

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

Identifies a generated CRUD route (create/list/get/update/delete) or a named operation route (operations.${name}).

function defineEntityExecutor(builder: EntityRouteExecutorBuilder,): EntityRouteExecutorBuilder; export function defineEntityExecutor< const TRequest extends TypedRouteRequestSpec = TypedRouteRequestSpec, >(definition: EntityRouteExecutorDefinition<TRequest>): EntityRouteExecutorDefinition<TRequest>; export function defineEntityExecutor( builderOrDefinition: EntityRouteExecutorBuilder | EntityRouteExecutorDefinition, ): EntityRouteExecutorBuilder | EntityRouteExecutorDefinition

Source: packages/slingshot-entity/src/routing/entityRoutePlanning.ts

Identifies a generated CRUD route (create/list/get/update/delete) or a named operation route (operations.${name}).

function defineEntityRoute<
const TRequest extends TypedRouteRequestSpec = TypedRouteRequestSpec,
>(route: EntityExtraRoute<TRequest>): EntityExtraRoute<TRequest>

Source: packages/slingshot-entity/src/routing/entityRoutePlanning.ts

Configuration for definePolicyDispatch.

function definePolicyDispatch<TRecord, TInput, TKey extends string = string>(config: PolicyDispatchConfig<TRecord, TInput, TKey>,): PolicyResolver<TRecord, TInput>

Source: packages/slingshot-entity/src/policy/definePolicyDispatch.ts

Entity config differ — pure function that compares two entity definitions and produces a MigrationPlan describing what changed.

function diffEntityConfig(previous: ResolvedEntityConfig, current: ResolvedEntityConfig,): MigrationPlan

Source: packages/slingshot-entity/src/migrations/diff.ts

Shared field-mapping utilities for config-driven adapters.

  • camelCase ↔ snake_case conversion
  • SQL / Mongo type mapping
  • Record transformation (domain ↔ storage)
  • Auto-default resolution
  • Naming conventions per backend
function encodeCursor(values: Record<string, unknown>): string

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

Use the framework’s default adapter resolution for the entity.

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

Zod schema validation for entity and operation definitions.

These schemas validate the structural correctness of configs. Cross-field validation (e.g., “softDelete field must exist in fields”) uses Zod’s .superRefine() for clear, composable error messages.

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

Result of evaluating auth and permission requirements for an entity route.

async function evaluateRouteAuth(c: Context<AppEnv, string>, operationConfig: RouteOperationConfig | undefined, deps: EvaluateRouteAuthDeps,): Promise<RouteAuthResult>

Source: packages/slingshot-entity/src/routing/evaluateRouteAuth.ts

field.*() builder API for entity field definitions.

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

Register a policy resolver under a named key. Consumers call this from their plugin’s setupMiddleware phase, before any slingshot-entity setupRoutes runs for entities that reference the key.

Two call shapes are supported:

  • registerEntityPolicy(app, key, resolver) — legacy, key passed as a string
  • registerEntityPolicy(app, token) — typed token from definePolicy(...)

Registration after the registry has been frozen (which happens at the end of slingshot-entity.setupRoutes) throws. This prevents late registration from silently affecting requests in flight.

function freezeEntityPolicyRegistry(app: Hono<AppEnv>): void

Source: packages/slingshot-entity/src/policy/registerEntityPolicy.ts

Pure code generation function.

Takes entity definitions + optional operations → returns Record<string, string> where keys are filenames and values are file contents.

No side effects. No disk I/O. Fully testable.

function generate(config: ResolvedEntityConfig, options?: GenerateOptions,): Record<string, string>

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

Initial-migration generator for MongoDB.

Mongo is schemaless, so there is no CREATE TABLE analog — collections are created lazily on first insert. The “initial” migration for an entity is therefore just the index and unique-constraint creation.

Output is a mongosh-style script with db.getCollection(...).createIndex(...) calls. When run by slingshot migrate apply, statements are auto-awaited inside an async IIFE.

function generateInitialMigrationMongo(config: ResolvedEntityConfig): string

Source: packages/slingshot-entity/src/migrations/generators/initialMongo.ts

Initial-migration generators — emit CREATE TABLE + index DDL for an entity that has no prior snapshot.

The diff-based generators (generateMigrationPostgres, generateMigrationSqlite) only emit ALTER TABLE, which is correct for evolution but fails on a fresh database. A “Prisma-style” workflow needs the full create statement on first migration so the migration files capture the entire schema state.

Output is deterministic and uses the same section markers as the diff generators so users can edit individual sections without losing them on regeneration.

function generateInitialMigrationPostgres(config: ResolvedEntityConfig): string

Source: packages/slingshot-entity/src/migrations/generators/initial.ts

Initial-migration generators — emit CREATE TABLE + index DDL for an entity that has no prior snapshot.

The diff-based generators (generateMigrationPostgres, generateMigrationSqlite) only emit ALTER TABLE, which is correct for evolution but fails on a fresh database. A “Prisma-style” workflow needs the full create statement on first migration so the migration files capture the entire schema state.

Output is deterministic and uses the same section markers as the diff generators so users can edit individual sections without losing them on regeneration.

function generateInitialMigrationSqlite(config: ResolvedEntityConfig): string

Source: packages/slingshot-entity/src/migrations/generators/initial.ts

MongoDB migration generator — MigrationPlan → mongosh-runnable script.

Mongo is schemaless, so field additions are no-ops at the schema level. Field removals use $unset updateMany. Index changes use createIndex / dropIndex.

Collection and field names are never inlined as raw identifiers — they go through db.getCollection("...") and bracket notation so hyphens, dots, and reserved characters don’t break the generated JavaScript. Output is deterministic (no timestamps); section markers (CLAUDE.md rule 13) let users override specific sections without replacing the whole file.

function generateMigrationMongo(plan: MigrationPlan): string

Source: packages/slingshot-entity/src/migrations/generators/mongo.ts

PostgreSQL migration generator — MigrationPlan → SQL statements.

Output is deterministic (no timestamps) so re-running slingshot generate --migration with the same inputs produces byte-identical files. Section markers delimit each logical block so users can override specific sections without replacing the whole file (CLAUDE.md rule 13).

function generateMigrationPostgres(plan: MigrationPlan): string

Source: packages/slingshot-entity/src/migrations/generators/postgres.ts

Schema migrations — diff entity definitions and generate per-backend migration scripts.

function generateMigrations(previous: ResolvedEntityConfig, current: ResolvedEntityConfig, backends?: Backend[],): Record<string, string>

Source: packages/slingshot-entity/src/migrations/index.ts

SQLite migration generator — MigrationPlan → SQL statements.

Output is deterministic (no timestamps) so re-running slingshot generate --migration with the same inputs produces byte-identical files. Section markers delimit each logical block so users can override specific sections without replacing the whole file (CLAUDE.md rule 13).

function generateMigrationSqlite(plan: MigrationPlan): string

Source: packages/slingshot-entity/src/migrations/generators/sqlite.ts

Zod schema generation from entity config.

Derives four Zod schemas from a ResolvedEntityConfig at runtime, without any code generation step. Schemas are consumed by route handlers for request validation and by the REST API generator for OpenAPI type inference.

Generated schemas:

  1. entitySchema — Full record shape; optional fields become .optional().
  2. createSchema — Create input; excludes auto-default fields (uuid, now, cuid) and onUpdate fields. Fields with literal defaults or marked optional are optional in this schema.
  3. updateSchema — Partial update input; all included fields are .optional(). Excludes immutable fields and onUpdate fields.
  4. listOptionsSchema — Filter + pagination options for list endpoints. Includes enum/boolean fields, all indexed fields, the tenant field, and limit/cursor/sortDir.
function generateSchemas(config: ResolvedEntityConfig, inputVariant?: string,): GeneratedSchemas

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

createEntityPlugin — Plugin-level orchestration for config-driven entities.

Wires entities into the Slingshot plugin lifecycle:

  • setupRoutes: builds bare routes, applies config middleware, mounts onto app
  • setupPost: registers permission resource types and post-route integrations
  • teardown: unsubscribes cascade event handlers

Consumers wire entities via EntityPluginEntry — either with buildAdapter (manual) or with factories + entityKey (composite, zero-code). This keeps the package free of framework-internal dependencies.

function getEntityPluginToolingMetadata(plugin: unknown,): EntityPluginToolingMetadata | null

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

Register a policy resolver under a named key. Consumers call this from their plugin’s setupMiddleware phase, before any slingshot-entity setupRoutes runs for entities that reference the key.

Two call shapes are supported:

  • registerEntityPolicy(app, key, resolver) — legacy, key passed as a string
  • registerEntityPolicy(app, token) — typed token from definePolicy(...)

Registration after the registry has been frozen (which happens at the end of slingshot-entity.setupRoutes) throws. This prevents late registration from silently affecting requests in flight.

function getEntityPolicyResolver(app: Hono<AppEnv>, key: string,): PolicyResolver | undefined

Source: packages/slingshot-entity/src/policy/registerEntityPolicy.ts

index() and relation builders for entity definitions.

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

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

Snapshot store — read/write entity definition snapshots for diffing.

Snapshots are stored as JSON files in a configurable directory (default: .slingshot/snapshots/).

function loadSnapshot(snapshotDir: string, config: ResolvedEntityConfig,): EntitySnapshot | null

Source: packages/slingshot-entity/src/migrations/snapshotStore.ts

Writable plugin state used internally by the framework bootstrap lifecycle.

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

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

Identifies a generated CRUD route (create/list/get/update/delete) or a named operation route (operations.${name}).

function normalizeEntityRouteShape(path: string): string

Source: packages/slingshot-entity/src/routing/entityRoutePlanning.ts

op.*() builder API for operation definitions.

Each builder adds the kind discriminant and returns a typed config object. Pure functions — no side effects, no validation (that’s defineOperations’ job).

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

Identifies a generated CRUD route (create/list/get/update/delete) or a named operation route (operations.${name}).

function planEntityRoutes(entity: ResolvedEntityConfig, operations: Record<string, OperationConfig> | undefined, options?: { routePath?: string; parentPath?: string; extraRoutes?: readonly EntityExtraRoute[]; overrides?: EntityRouteExecutorOverrides; },): PlannedEntityRoute[]

Source: packages/slingshot-entity/src/routing/entityRoutePlanning.ts

Arguments for resolvePolicy.

function policyAppliesToOp(config: EntityRoutePolicyConfig, opName: string): boolean

Source: packages/slingshot-entity/src/policy/resolvePolicy.ts

Writable plugin state used internally by the framework bootstrap lifecycle.

function publishEntityAdaptersState<TAdapter extends object>(pluginState: PluginStateMap, pluginName: string, entityAdapters: Record<string, TAdapter>,): Readonly<EntityAdaptersPluginState<TAdapter> & Record<string, unknown>>

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

Register a policy resolver under a named key. Consumers call this from their plugin’s setupMiddleware phase, before any slingshot-entity setupRoutes runs for entities that reference the key.

Two call shapes are supported:

  • registerEntityPolicy(app, key, resolver) — legacy, key passed as a string
  • registerEntityPolicy(app, token) — typed token from definePolicy(...)

Registration after the registry has been frozen (which happens at the end of slingshot-entity.setupRoutes) throws. This prevents late registration from silently affecting requests in flight.

function registerEntityPolicy<TRecord = unknown, TInput = unknown>(app: Hono<AppEnv>, token: PolicyToken<TRecord, TInput>,): void; export function registerEntityPolicy<TRecord = unknown, TInput = unknown>( app: Hono<AppEnv>, key: string, resolver: PolicyResolver<TRecord, TInput>, ): void; export function registerEntityPolicy( app: Hono<AppEnv>, keyOrToken: string | PolicyToken<unknown, unknown>, maybeResolver?: PolicyResolver<unknown, unknown>, ): void

Source: packages/slingshot-entity/src/policy/registerEntityPolicy.ts

index() and relation builders for entity definitions.

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

Writable plugin state used internally by the framework bootstrap lifecycle.

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

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

Arguments for resolvePolicy.

async function resolvePolicy<TRecord, TInput>(args: ResolvePolicyArgs<TRecord, TInput>,): Promise<void>

Source: packages/slingshot-entity/src/policy/resolvePolicy.ts

Read the parsed JSON body from a Hono context without consuming the body stream. Relies on Hono’s built-in body caching — c.req.json() parses on first call and stores the result; subsequent calls return the cached value.

Returns null on:

  • non-JSON content type
  • empty body (GET/DELETE)
  • malformed JSON (resolver receives null input; it may deny)

Never throws — policy evaluation must never 500 on a client body issue.

async function safeReadJsonBody(c: Context): Promise<Record<string, unknown> | null>

Source: packages/slingshot-entity/src/policy/safeReadJsonBody.ts

Snapshot store — read/write entity definition snapshots for diffing.

Snapshots are stored as JSON files in a configurable directory (default: .slingshot/snapshots/).

function saveSnapshot(snapshotDir: string, config: ResolvedEntityConfig): void

Source: packages/slingshot-entity/src/migrations/snapshotStore.ts

Identifies a generated CRUD route (create/list/get/update/delete) or a named operation route (operations.${name}).

function scoreEntityRouteSpecificity(path: string): number

Source: packages/slingshot-entity/src/routing/entityRoutePlanning.ts

Shared naming helpers used by all generators.

Pure, stateless utility functions for converting entity field names and configs into backend-specific representations. Used by every code generator in this package — do not add generator-specific logic here.

function storageName(config: ResolvedEntityConfig, backend: 'sqlite' | 'postgres' | 'mongo' | 'redis',): string

Source: packages/slingshot-entity/src/lib/naming.ts

Shared field-mapping utilities for config-driven adapters.

  • camelCase ↔ snake_case conversion
  • SQL / Mongo type mapping
  • Record transformation (domain ↔ storage)
  • Auto-default resolution
  • Naming conventions per backend
function toCamelCase(str: string): string

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

Shared field-mapping utilities for config-driven adapters.

  • camelCase ↔ snake_case conversion
  • SQL / Mongo type mapping
  • Record transformation (domain ↔ storage)
  • Auto-default resolution
  • Naming conventions per backend
function toSnakeCase(str: string): string

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

Zod schema validation for entity and operation definitions.

These schemas validate the structural correctness of configs. Cross-field validation (e.g., “softDelete field must exist in fields”) uses Zod’s .superRefine() for clear, composable error messages.

function validateEntityConfig(config: unknown): ValidationResult

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

Zod schema validation for entity and operation definitions.

These schemas validate the structural correctness of configs. Cross-field validation (e.g., “softDelete field must exist in fields”) uses Zod’s .superRefine() for clear, composable error messages.

function validateOperations(operations: unknown, fieldNames: readonly string[],): ValidationResult

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

applyChannelConfig — builds subscribe guards and event forwarding for config-driven WebSocket entity channels.

Two responsibilities:

  1. Subscribe guard: parses room names, enforces auth/permissions/middleware
  2. Event forwarding: wires bus events to WS room publish calls
function wireChannelForwarding(channelConfig: EntityChannelConfig, entity: ResolvedEntityConfig, getWsState: () => WsState | null, bus: SlingshotEventBus, endpoint: string, publishFn: WsPublishFn<WsState>,): () => void

Source: packages/slingshot-entity/src/channels/applyChannelConfig.ts

CLI wrapper — calls generate(), handles snapshot lifecycle, writes files to disk.

Usage: slingshot-data generate —definition ./src/entities/message.ts —outdir ./src/generated/message

Or programmatically: import { writeGenerated } from ‘@lastshotlabs/slingshot-entity’; writeGenerated(messageConfig, { outDir: ’./src/generated/message’ });

function writeGenerated(config: ResolvedEntityConfig, options: WriteOptions,): Record<string, string>

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

Operation configuration types — canonical definitions.

12 declarative operation patterns + 1 custom escape hatch. Both the codegen package (slingshot-data) and the runtime framework import from here. Single source of truth — never duplicate these types in consumer packages.

Remarks: Operation configs are consumed by: - slingshot-data code generators to produce typed adapter implementations - The runtime framework’s op.* executor registry for live evaluation - InferOperationMethods<Ops, Entity> for TypeScript adapter method typing

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

Operation configuration types — canonical definitions.

12 declarative operation patterns + 1 custom escape hatch. Both the codegen package (slingshot-data) and the runtime framework import from here. Single source of truth — never duplicate these types in consumer packages.

Remarks: Operation configs are consumed by: - slingshot-data code generators to produce typed adapter implementations - The runtime framework’s op.* executor registry for live evaluation - InferOperationMethods<Ops, Entity> for TypeScript adapter method typing

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

applyChannelConfig — builds subscribe guards and event forwarding for config-driven WebSocket entity channels.

Two responsibilities:

  1. Subscribe guard: parses room names, enforces auth/permissions/middleware
  2. Event forwarding: wires bus events to WS room publish calls

Source: packages/slingshot-entity/src/channels/applyChannelConfig.ts

Operation configuration types — canonical definitions.

12 declarative operation patterns + 1 custom escape hatch. Both the codegen package (slingshot-data) and the runtime framework import from here. Single source of truth — never duplicate these types in consumer packages.

Remarks: Operation configs are consumed by: - slingshot-data code generators to produce typed adapter implementations - The runtime framework’s op.* executor registry for live evaluation - InferOperationMethods<Ops, Entity> for TypeScript adapter method typing

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

Operation configuration types — canonical definitions.

12 declarative operation patterns + 1 custom escape hatch. Both the codegen package (slingshot-data) and the runtime framework import from here. Single source of truth — never duplicate these types in consumer packages.

Remarks: Operation configs are consumed by: - slingshot-data code generators to produce typed adapter implementations - The runtime framework’s op.* executor registry for live evaluation - InferOperationMethods<Ops, Entity> for TypeScript adapter method typing

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

Operation configuration types — canonical definitions.

12 declarative operation patterns + 1 custom escape hatch. Both the codegen package (slingshot-data) and the runtime framework import from here. Single source of truth — never duplicate these types in consumer packages.

Remarks: Operation configs are consumed by: - slingshot-data code generators to produce typed adapter implementations - The runtime framework’s op.* executor registry for live evaluation - InferOperationMethods<Ops, Entity> for TypeScript adapter method typing

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

Operation configuration types — canonical definitions.

12 declarative operation patterns + 1 custom escape hatch. Both the codegen package (slingshot-data) and the runtime framework import from here. Single source of truth — never duplicate these types in consumer packages.

Remarks: Operation configs are consumed by: - slingshot-data code generators to produce typed adapter implementations - The runtime framework’s op.* executor registry for live evaluation - InferOperationMethods<Ops, Entity> for TypeScript adapter method typing

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

Operation configuration types — canonical definitions.

12 declarative operation patterns + 1 custom escape hatch. Both the codegen package (slingshot-data) and the runtime framework import from here. Single source of truth — never duplicate these types in consumer packages.

Remarks: Operation configs are consumed by: - slingshot-data code generators to produce typed adapter implementations - The runtime framework’s op.* executor registry for live evaluation - InferOperationMethods<Ops, Entity> for TypeScript adapter method typing

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

Operation configuration types — canonical definitions.

12 declarative operation patterns + 1 custom escape hatch. Both the codegen package (slingshot-data) and the runtime framework import from here. Single source of truth — never duplicate these types in consumer packages.

Remarks: Operation configs are consumed by: - slingshot-data code generators to produce typed adapter implementations - The runtime framework’s op.* executor registry for live evaluation - InferOperationMethods<Ops, Entity> for TypeScript adapter method typing

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

Operation configuration types — canonical definitions.

12 declarative operation patterns + 1 custom escape hatch. Both the codegen package (slingshot-data) and the runtime framework import from here. Single source of truth — never duplicate these types in consumer packages.

Remarks: Operation configs are consumed by: - slingshot-data code generators to produce typed adapter implementations - The runtime framework’s op.* executor registry for live evaluation - InferOperationMethods<Ops, Entity> for TypeScript adapter method typing

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

Instance-scoped map of plugin name -> plugin-owned state.

Each plugin stores its runtime state under its own plugin name key. Values are opaque to the framework; plugins own their state shape and expose typed accessors for dependent plugins.

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

Entity audit types — findings produced by audit rules.

Source: packages/slingshot-entity/src/audits/types.ts

Entity audit types — findings produced by audit rules.

Source: packages/slingshot-entity/src/audits/types.ts

Entity configuration types.

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

Identifies a generated CRUD route (create/list/get/update/delete) or a named operation route (operations.${name}).

Source: packages/slingshot-entity/src/routing/entityRoutePlanning.ts

createEntityPlugin — Plugin-level orchestration for config-driven entities.

Wires entities into the Slingshot plugin lifecycle:

  • setupRoutes: builds bare routes, applies config middleware, mounts onto app
  • setupPost: registers permission resource types and post-route integrations
  • teardown: unsubscribes cascade event handlers

Consumers wire entities via EntityPluginEntry — either with buildAdapter (manual) or with factories + entityKey (composite, zero-code). This keeps the package free of framework-internal dependencies.

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

createEntityPlugin — Plugin-level orchestration for config-driven entities.

Wires entities into the Slingshot plugin lifecycle:

  • setupRoutes: builds bare routes, applies config middleware, mounts onto app
  • setupPost: registers permission resource types and post-route integrations
  • teardown: unsubscribes cascade event handlers

Consumers wire entities via EntityPluginEntry — either with buildAdapter (manual) or with factories + entityKey (composite, zero-code). This keeps the package free of framework-internal dependencies.

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

createEntityPlugin — Plugin-level orchestration for config-driven entities.

Wires entities into the Slingshot plugin lifecycle:

  • setupRoutes: builds bare routes, applies config middleware, mounts onto app
  • setupPost: registers permission resource types and post-route integrations
  • teardown: unsubscribes cascade event handlers

Consumers wire entities via EntityPluginEntry — either with buildAdapter (manual) or with factories + entityKey (composite, zero-code). This keeps the package free of framework-internal dependencies.

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

createEntityPlugin — Plugin-level orchestration for config-driven entities.

Wires entities into the Slingshot plugin lifecycle:

  • setupRoutes: builds bare routes, applies config middleware, mounts onto app
  • setupPost: registers permission resource types and post-route integrations
  • teardown: unsubscribes cascade event handlers

Consumers wire entities via EntityPluginEntry — either with buildAdapter (manual) or with factories + entityKey (composite, zero-code). This keeps the package free of framework-internal dependencies.

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

Identifies a generated CRUD route (create/list/get/update/delete) or a named operation route (operations.${name}).

Source: packages/slingshot-entity/src/routing/entityRoutePlanning.ts

Identifies a generated CRUD route (create/list/get/update/delete) or a named operation route (operations.${name}).

Source: packages/slingshot-entity/src/routing/entityRoutePlanning.ts

Identifies a generated CRUD route (create/list/get/update/delete) or a named operation route (operations.${name}).

Source: packages/slingshot-entity/src/routing/entityRoutePlanning.ts

Identifies a generated CRUD route (create/list/get/update/delete) or a named operation route (operations.${name}).

Source: packages/slingshot-entity/src/routing/entityRoutePlanning.ts

Schema migration types.

Source: packages/slingshot-entity/src/migrations/types.ts

Config-driven entity & repository generation.

Plugin authors describe an entity’s shape declaratively using the field.*() builder API, then get generated TypeScript types, Zod schemas, adapter interfaces, and backend-specific implementations from a single source of truth.

import { defineEntity, field, index } from '@lastshotlabs/slingshot-core';
export const Message = defineEntity('Message', {
namespace: 'chat',
fields: {
id: field.string({ primary: true, default: 'uuid' }),
roomId: field.string(),
authorId: field.string(),
content: field.string(),
type: field.enum(['text', 'image', 'system'], { default: 'text' }),
metadata: field.json({ optional: true }),
createdAt: field.date({ default: 'now' }),
updatedAt: field.date({ default: 'now', onUpdate: 'now' }),
},
softDelete: { field: 'status', value: 'deleted' },
defaultSort: { field: 'createdAt', direction: 'desc' },
pagination: { cursor: { fields: ['createdAt', 'id'] }, defaultLimit: 50, maxLimit: 200 },
indexes: [
index(['roomId', 'createdAt'], { direction: 'desc' }),
index(['authorId', 'createdAt'], { direction: 'desc' }),
],
});

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

Config-driven entity & repository generation.

Plugin authors describe an entity’s shape declaratively using the field.*() builder API, then get generated TypeScript types, Zod schemas, adapter interfaces, and backend-specific implementations from a single source of truth.

import { defineEntity, field, index } from '@lastshotlabs/slingshot-core';
export const Message = defineEntity('Message', {
namespace: 'chat',
fields: {
id: field.string({ primary: true, default: 'uuid' }),
roomId: field.string(),
authorId: field.string(),
content: field.string(),
type: field.enum(['text', 'image', 'system'], { default: 'text' }),
metadata: field.json({ optional: true }),
createdAt: field.date({ default: 'now' }),
updatedAt: field.date({ default: 'now', onUpdate: 'now' }),
},
softDelete: { field: 'status', value: 'deleted' },
defaultSort: { field: 'createdAt', direction: 'desc' },
pagination: { cursor: { fields: ['createdAt', 'id'] }, defaultLimit: 50, maxLimit: 200 },
indexes: [
index(['roomId', 'createdAt'], { direction: 'desc' }),
index(['authorId', 'createdAt'], { direction: 'desc' }),
],
});

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

Entity configuration types.

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

Config-driven entity & repository generation.

Plugin authors describe an entity’s shape declaratively using the field.*() builder API, then get generated TypeScript types, Zod schemas, adapter interfaces, and backend-specific implementations from a single source of truth.

import { defineEntity, field, index } from '@lastshotlabs/slingshot-core';
export const Message = defineEntity('Message', {
namespace: 'chat',
fields: {
id: field.string({ primary: true, default: 'uuid' }),
roomId: field.string(),
authorId: field.string(),
content: field.string(),
type: field.enum(['text', 'image', 'system'], { default: 'text' }),
metadata: field.json({ optional: true }),
createdAt: field.date({ default: 'now' }),
updatedAt: field.date({ default: 'now', onUpdate: 'now' }),
},
softDelete: { field: 'status', value: 'deleted' },
defaultSort: { field: 'createdAt', direction: 'desc' },
pagination: { cursor: { fields: ['createdAt', 'id'] }, defaultLimit: 50, maxLimit: 200 },
indexes: [
index(['roomId', 'createdAt'], { direction: 'desc' }),
index(['authorId', 'createdAt'], { direction: 'desc' }),
],
});

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

Entity configuration types.

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

Result of evaluating auth and permission requirements for an entity route.

Source: packages/slingshot-entity/src/routing/evaluateRouteAuth.ts

Operation configuration types — canonical definitions.

12 declarative operation patterns + 1 custom escape hatch. Both the codegen package (slingshot-data) and the runtime framework import from here. Single source of truth — never duplicate these types in consumer packages.

Remarks: Operation configs are consumed by: - slingshot-data code generators to produce typed adapter implementations - The runtime framework’s op.* executor registry for live evaluation - InferOperationMethods<Ops, Entity> for TypeScript adapter method typing

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

Use the framework’s default adapter resolution for the entity.

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

Field type tokens and definition interfaces.

Source: packages/slingshot-entity/src/types/fields.ts

Field type tokens and definition interfaces.

Source: packages/slingshot-entity/src/types/fields.ts

Operation configuration types — canonical definitions.

12 declarative operation patterns + 1 custom escape hatch. Both the codegen package (slingshot-data) and the runtime framework import from here. Single source of truth — never duplicate these types in consumer packages.

Remarks: Operation configs are consumed by: - slingshot-data code generators to produce typed adapter implementations - The runtime framework’s op.* executor registry for live evaluation - InferOperationMethods<Ops, Entity> for TypeScript adapter method typing

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

Zod schema generation from entity config.

Derives four Zod schemas from a ResolvedEntityConfig at runtime, without any code generation step. Schemas are consumed by route handlers for request validation and by the REST API generator for OpenAPI type inference.

Generated schemas:

  1. entitySchema — Full record shape; optional fields become .optional().
  2. createSchema — Create input; excludes auto-default fields (uuid, now, cuid) and onUpdate fields. Fields with literal defaults or marked optional are optional in this schema.
  3. updateSchema — Partial update input; all included fields are .optional(). Excludes immutable fields and onUpdate fields.
  4. listOptionsSchema — Filter + pagination options for list endpoints. Includes enum/boolean fields, all indexed fields, the tenant field, and limit/cursor/sortDir.

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

Pure code generation function.

Takes entity definitions + optional operations → returns Record<string, string> where keys are filenames and values are file contents.

No side effects. No disk I/O. Fully testable.

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

Operation configuration types — canonical definitions.

12 declarative operation patterns + 1 custom escape hatch. Both the codegen package (slingshot-data) and the runtime framework import from here. Single source of truth — never duplicate these types in consumer packages.

Remarks: Operation configs are consumed by: - slingshot-data code generators to produce typed adapter implementations - The runtime framework’s op.* executor registry for live evaluation - InferOperationMethods<Ops, Entity> for TypeScript adapter method typing

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

Helper used by feature packages whose adapter- or capability-dependent middleware handlers can only be wired after lifecycle hooks run.

The returned ref starts as a pass-through next() no-op. The package mounts middleware that forwards through ref.handler, then assigns the real handler from setupMiddleware or setupPost once its dependencies are resolved.

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

Operation configuration types — canonical definitions.

12 declarative operation patterns + 1 custom escape hatch. Both the codegen package (slingshot-data) and the runtime framework import from here. Single source of truth — never duplicate these types in consumer packages.

Remarks: Operation configs are consumed by: - slingshot-data code generators to produce typed adapter implementations - The runtime framework’s op.* executor registry for live evaluation - InferOperationMethods<Ops, Entity> for TypeScript adapter method typing

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

Use the framework’s default adapter resolution for the entity.

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

Schema migration types.

Source: packages/slingshot-entity/src/migrations/types.ts

Use the framework’s default adapter resolution for the entity.

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

Use the framework’s default adapter resolution for the entity.

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

Entity configuration types.

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

Identifies a generated CRUD route (create/list/get/update/delete) or a named operation route (operations.${name}).

Source: packages/slingshot-entity/src/routing/entityRoutePlanning.ts

Configuration for definePolicyDispatch.

Source: packages/slingshot-entity/src/policy/definePolicyDispatch.ts

Entity configuration types.

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

Entity configuration types.

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

Config-driven entity & repository generation.

Plugin authors describe an entity’s shape declaratively using the field.*() builder API, then get generated TypeScript types, Zod schemas, adapter interfaces, and backend-specific implementations from a single source of truth.

import { defineEntity, field, index } from '@lastshotlabs/slingshot-core';
export const Message = defineEntity('Message', {
namespace: 'chat',
fields: {
id: field.string({ primary: true, default: 'uuid' }),
roomId: field.string(),
authorId: field.string(),
content: field.string(),
type: field.enum(['text', 'image', 'system'], { default: 'text' }),
metadata: field.json({ optional: true }),
createdAt: field.date({ default: 'now' }),
updatedAt: field.date({ default: 'now', onUpdate: 'now' }),
},
softDelete: { field: 'status', value: 'deleted' },
defaultSort: { field: 'createdAt', direction: 'desc' },
pagination: { cursor: { fields: ['createdAt', 'id'] }, defaultLimit: 50, maxLimit: 200 },
indexes: [
index(['roomId', 'createdAt'], { direction: 'desc' }),
index(['authorId', 'createdAt'], { direction: 'desc' }),
],
});

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

Config-driven entity & repository generation.

Plugin authors describe an entity’s shape declaratively using the field.*() builder API, then get generated TypeScript types, Zod schemas, adapter interfaces, and backend-specific implementations from a single source of truth.

import { defineEntity, field, index } from '@lastshotlabs/slingshot-core';
export const Message = defineEntity('Message', {
namespace: 'chat',
fields: {
id: field.string({ primary: true, default: 'uuid' }),
roomId: field.string(),
authorId: field.string(),
content: field.string(),
type: field.enum(['text', 'image', 'system'], { default: 'text' }),
metadata: field.json({ optional: true }),
createdAt: field.date({ default: 'now' }),
updatedAt: field.date({ default: 'now', onUpdate: 'now' }),
},
softDelete: { field: 'status', value: 'deleted' },
defaultSort: { field: 'createdAt', direction: 'desc' },
pagination: { cursor: { fields: ['createdAt', 'id'] }, defaultLimit: 50, maxLimit: 200 },
indexes: [
index(['roomId', 'createdAt'], { direction: 'desc' }),
index(['authorId', 'createdAt'], { direction: 'desc' }),
],
});

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

Config-driven entity & repository generation.

Plugin authors describe an entity’s shape declaratively using the field.*() builder API, then get generated TypeScript types, Zod schemas, adapter interfaces, and backend-specific implementations from a single source of truth.

import { defineEntity, field, index } from '@lastshotlabs/slingshot-core';
export const Message = defineEntity('Message', {
namespace: 'chat',
fields: {
id: field.string({ primary: true, default: 'uuid' }),
roomId: field.string(),
authorId: field.string(),
content: field.string(),
type: field.enum(['text', 'image', 'system'], { default: 'text' }),
metadata: field.json({ optional: true }),
createdAt: field.date({ default: 'now' }),
updatedAt: field.date({ default: 'now', onUpdate: 'now' }),
},
softDelete: { field: 'status', value: 'deleted' },
defaultSort: { field: 'createdAt', direction: 'desc' },
pagination: { cursor: { fields: ['createdAt', 'id'] }, defaultLimit: 50, maxLimit: 200 },
indexes: [
index(['roomId', 'createdAt'], { direction: 'desc' }),
index(['authorId', 'createdAt'], { direction: 'desc' }),
],
});

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

Operation configuration types — canonical definitions.

12 declarative operation patterns + 1 custom escape hatch. Both the codegen package (slingshot-data) and the runtime framework import from here. Single source of truth — never duplicate these types in consumer packages.

Remarks: Operation configs are consumed by: - slingshot-data code generators to produce typed adapter implementations - The runtime framework’s op.* executor registry for live evaluation - InferOperationMethods<Ops, Entity> for TypeScript adapter method typing

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

Arguments for resolvePolicy.

Source: packages/slingshot-entity/src/policy/resolvePolicy.ts

Result of evaluating auth and permission requirements for an entity route.

Source: packages/slingshot-entity/src/routing/evaluateRouteAuth.ts

Operation configuration types — canonical definitions.

12 declarative operation patterns + 1 custom escape hatch. Both the codegen package (slingshot-data) and the runtime framework import from here. Single source of truth — never duplicate these types in consumer packages.

Remarks: Operation configs are consumed by: - slingshot-data code generators to produce typed adapter implementations - The runtime framework’s op.* executor registry for live evaluation - InferOperationMethods<Ops, Entity> for TypeScript adapter method typing

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

Use the framework’s default adapter resolution for the entity.

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

Entity configuration types.

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

Operation configuration types — canonical definitions.

12 declarative operation patterns + 1 custom escape hatch. Both the codegen package (slingshot-data) and the runtime framework import from here. Single source of truth — never duplicate these types in consumer packages.

Remarks: Operation configs are consumed by: - slingshot-data code generators to produce typed adapter implementations - The runtime framework’s op.* executor registry for live evaluation - InferOperationMethods<Ops, Entity> for TypeScript adapter method typing

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

Operation configuration types — canonical definitions.

12 declarative operation patterns + 1 custom escape hatch. Both the codegen package (slingshot-data) and the runtime framework import from here. Single source of truth — never duplicate these types in consumer packages.

Remarks: Operation configs are consumed by: - slingshot-data code generators to produce typed adapter implementations - The runtime framework’s op.* executor registry for live evaluation - InferOperationMethods<Ops, Entity> for TypeScript adapter method typing

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

Zod schema validation for entity and operation definitions.

These schemas validate the structural correctness of configs. Cross-field validation (e.g., “softDelete field must exist in fields”) uses Zod’s .superRefine() for clear, composable error messages.

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

CLI wrapper — calls generate(), handles snapshot lifecycle, writes files to disk.

Usage: slingshot-data generate —definition ./src/entities/message.ts —outdir ./src/generated/message

Or programmatically: import { writeGenerated } from ‘@lastshotlabs/slingshot-entity’; writeGenerated(messageConfig, { outDir: ’./src/generated/message’ });

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

Entity audit types — findings produced by audit rules.

Source: packages/slingshot-entity/src/audits/types.ts

Field type tokens and definition interfaces.

Source: packages/slingshot-entity/src/types/fields.ts

The typed CRUD surface of a bare entity adapter.

Each method mirrors the HTTP verb and semantics used by the generated routes.

Source: packages/slingshot-entity/src/routing/adapterTypes.ts

applyChannelConfig — builds subscribe guards and event forwarding for config-driven WebSocket entity channels.

Two responsibilities:

  1. Subscribe guard: parses room names, enforces auth/permissions/middleware
  2. Event forwarding: wires bus events to WS room publish calls

Source: packages/slingshot-entity/src/channels/applyChannelConfig.ts

Operation configuration types — canonical definitions.

12 declarative operation patterns + 1 custom escape hatch. Both the codegen package (slingshot-data) and the runtime framework import from here. Single source of truth — never duplicate these types in consumer packages.

Remarks: Operation configs are consumed by: - slingshot-data code generators to produce typed adapter implementations - The runtime framework’s op.* executor registry for live evaluation - InferOperationMethods<Ops, Entity> for TypeScript adapter method typing

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

Config-driven entity & repository generation.

Plugin authors describe an entity’s shape declaratively using the field.*() builder API, then get generated TypeScript types, Zod schemas, adapter interfaces, and backend-specific implementations from a single source of truth.

import { defineEntity, field, index } from '@lastshotlabs/slingshot-core';
export const Message = defineEntity('Message', {
namespace: 'chat',
fields: {
id: field.string({ primary: true, default: 'uuid' }),
roomId: field.string(),
authorId: field.string(),
content: field.string(),
type: field.enum(['text', 'image', 'system'], { default: 'text' }),
metadata: field.json({ optional: true }),
createdAt: field.date({ default: 'now' }),
updatedAt: field.date({ default: 'now', onUpdate: 'now' }),
},
softDelete: { field: 'status', value: 'deleted' },
defaultSort: { field: 'createdAt', direction: 'desc' },
pagination: { cursor: { fields: ['createdAt', 'id'] }, defaultLimit: 50, maxLimit: 200 },
indexes: [
index(['roomId', 'createdAt'], { direction: 'desc' }),
index(['authorId', 'createdAt'], { direction: 'desc' }),
],
});

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

Config-driven entity & repository generation.

Plugin authors describe an entity’s shape declaratively using the field.*() builder API, then get generated TypeScript types, Zod schemas, adapter interfaces, and backend-specific implementations from a single source of truth.

import { defineEntity, field, index } from '@lastshotlabs/slingshot-core';
export const Message = defineEntity('Message', {
namespace: 'chat',
fields: {
id: field.string({ primary: true, default: 'uuid' }),
roomId: field.string(),
authorId: field.string(),
content: field.string(),
type: field.enum(['text', 'image', 'system'], { default: 'text' }),
metadata: field.json({ optional: true }),
createdAt: field.date({ default: 'now' }),
updatedAt: field.date({ default: 'now', onUpdate: 'now' }),
},
softDelete: { field: 'status', value: 'deleted' },
defaultSort: { field: 'createdAt', direction: 'desc' },
pagination: { cursor: { fields: ['createdAt', 'id'] }, defaultLimit: 50, maxLimit: 200 },
indexes: [
index(['roomId', 'createdAt'], { direction: 'desc' }),
index(['authorId', 'createdAt'], { direction: 'desc' }),
],
});

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

Entity configuration types.

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

Identifies a generated CRUD route (create/list/get/update/delete) or a named operation route (operations.${name}).

Source: packages/slingshot-entity/src/routing/entityRoutePlanning.ts

Use the framework’s default adapter resolution for the entity.

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

createEntityPlugin — Plugin-level orchestration for config-driven entities.

Wires entities into the Slingshot plugin lifecycle:

  • setupRoutes: builds bare routes, applies config middleware, mounts onto app
  • setupPost: registers permission resource types and post-route integrations
  • teardown: unsubscribes cascade event handlers

Consumers wire entities via EntityPluginEntry — either with buildAdapter (manual) or with factories + entityKey (composite, zero-code). This keeps the package free of framework-internal dependencies.

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

Identifies a generated CRUD route (create/list/get/update/delete) or a named operation route (operations.${name}).

Source: packages/slingshot-entity/src/routing/entityRoutePlanning.ts

Identifies a generated CRUD route (create/list/get/update/delete) or a named operation route (operations.${name}).

Source: packages/slingshot-entity/src/routing/entityRoutePlanning.ts

Entity configuration types.

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

Operation configuration types — canonical definitions.

12 declarative operation patterns + 1 custom escape hatch. Both the codegen package (slingshot-data) and the runtime framework import from here. Single source of truth — never duplicate these types in consumer packages.

Remarks: Operation configs are consumed by: - slingshot-data code generators to produce typed adapter implementations - The runtime framework’s op.* executor registry for live evaluation - InferOperationMethods<Ops, Entity> for TypeScript adapter method typing

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

Operation configuration types — canonical definitions.

12 declarative operation patterns + 1 custom escape hatch. Both the codegen package (slingshot-data) and the runtime framework import from here. Single source of truth — never duplicate these types in consumer packages.

Remarks: Operation configs are consumed by: - slingshot-data code generators to produce typed adapter implementations - The runtime framework’s op.* executor registry for live evaluation - InferOperationMethods<Ops, Entity> for TypeScript adapter method typing

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

Operation configuration types — canonical definitions.

12 declarative operation patterns + 1 custom escape hatch. Both the codegen package (slingshot-data) and the runtime framework import from here. Single source of truth — never duplicate these types in consumer packages.

Remarks: Operation configs are consumed by: - slingshot-data code generators to produce typed adapter implementations - The runtime framework’s op.* executor registry for live evaluation - InferOperationMethods<Ops, Entity> for TypeScript adapter method typing

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

Schema migration types.

Source: packages/slingshot-entity/src/migrations/types.ts

Operation configuration types — canonical definitions.

12 declarative operation patterns + 1 custom escape hatch. Both the codegen package (slingshot-data) and the runtime framework import from here. Single source of truth — never duplicate these types in consumer packages.

Remarks: Operation configs are consumed by: - slingshot-data code generators to produce typed adapter implementations - The runtime framework’s op.* executor registry for live evaluation - InferOperationMethods<Ops, Entity> for TypeScript adapter method typing

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

Use the framework’s default adapter resolution for the entity.

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

Entity configuration types.

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

applyChannelConfig — builds subscribe guards and event forwarding for config-driven WebSocket entity channels.

Two responsibilities:

  1. Subscribe guard: parses room names, enforces auth/permissions/middleware
  2. Event forwarding: wires bus events to WS room publish calls

Source: packages/slingshot-entity/src/channels/applyChannelConfig.ts

Multi-entity composition — combine multiple entity adapters into a single plugin adapter, optionally with operations.

Plugins typically persist several related entities together (e.g. rooms + messages). Rather than returning multiple separate factory objects, createCompositeFactories() merges them behind a single RepoFactories<CompositeAdapter> object. The composite adapter exposes each entity’s adapter under its own key, plus a clear() method that resets all entities simultaneously (useful in tests).

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

Config-driven adapter factory generator.

Pure runtime builder for entity repo factories. This package-side version intentionally stays free of app/framework wiring so workspace packages can depend on it without pulling in src/framework.

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

Entity definition entry point — dev-time only.

Validates config using Zod schema, resolves PK and storage name.

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

Operations definition entry point — dev-time only.

Validates operation configs using Zod schema against entity field names.

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