alepha
Version:
Easy-to-use modern TypeScript framework for building many kind of applications.
1,457 lines • 179 kB
TypeScript
import { Alepha, AlephaError, Page, PageQuery, Primitive, SchemaValidator, Static, StaticEncode, TNull, TObject, TOptional, TSchema, TUnion } from "alepha";
import { CryptoProvider, IssuerPrimitive, IssuerPrimitiveOptions, SecurityProvider, SigningConfig, UserAccount } from "alepha/security";
import { Page as Page$1, Repository } from "alepha/orm";
import { VerificationController, VerificationService } from "alepha/api/verifications";
import { CaptchaProvider } from "alepha/captcha";
import { OAuth2Profile, ServerAuthProvider, WithLinkFn, WithLoginFn } from "alepha/server/auth";
import { CacheProvider } from "alepha/cache";
import { DateTime, DateTimeProvider } from "alepha/datetime";
import { FileSystemProvider } from "alepha/system";
import { ParameterPrimitive } from "alepha/api/parameters";
import { BuildExtraConfigColumns, SQL, SQLWrapper } from "drizzle-orm";
import { LockConfig, LockStrength, PgColumn, PgColumnBuilderBase, PgDatabase, PgInsertValue, PgSelectBase, PgSequenceOptions, PgTableExtraConfigValue, PgTableWithColumns, PgTransaction, UpdateDeleteAction } from "drizzle-orm/pg-core";
import "drizzle-orm/pg-core/foreign-keys";
import { PgTransactionConfig } from "drizzle-orm/pg-core/session";
import { CryptoProvider as CryptoProvider$1 } from "alepha/crypto";
import * as DrizzleKit from "drizzle-kit/api";
import "drizzle-orm/d1";
import "drizzle-orm/sqlite-core";
import { FileController } from "alepha/api/files";
//#region ../../src/api/users/atoms/realmAuthSettingsAtom.d.ts
/**
* Tri-state field requirement for realm auth settings.
*
* - `"none"`: Field is disabled and not shown.
* - `"optional"`: Field is shown but not required.
* - `"required"`: Field is shown and required.
*/
type FieldRequirement = "none" | "optional" | "required";
/**
* Username-specific field requirement, extending {@link FieldRequirement}
* with an additional auto-derivation mode.
*
* - `"none"` / `"optional"` / `"required"`: same as {@link FieldRequirement}.
* - `"email"`: Field is hidden in the registration UI and the value is
* auto-derived from the user's email at signup. Same handling on
* credentials and OAuth flows. See `UsernameSlugger` for the rule and
* collision behavior.
*/
type UsernameFieldRequirement = FieldRequirement | "email";
declare const realmAuthSettingsAtom: import("alepha").Atom<import("zod").ZodObject<{
displayName: import("zod").ZodOptional<import("zod").ZodString>;
description: import("zod").ZodOptional<import("zod").ZodString>;
logoUrl: import("zod").ZodOptional<import("zod").ZodString>;
registrationAllowed: import("zod").ZodBoolean;
email: import("zod").ZodUnion<readonly [import("zod").ZodLiteral<"none">, import("zod").ZodLiteral<"optional">, import("zod").ZodLiteral<"required">]>;
username: import("zod").ZodUnion<readonly [import("zod").ZodLiteral<"none">, import("zod").ZodLiteral<"optional">, import("zod").ZodLiteral<"required">, import("zod").ZodLiteral<"email">]>;
usernameRegExp: import("zod").ZodString;
usernameBlocklist: import("zod").ZodArray<import("zod").ZodString>;
phoneNumber: import("zod").ZodUnion<readonly [import("zod").ZodLiteral<"none">, import("zod").ZodLiteral<"optional">, import("zod").ZodLiteral<"required">]>;
verifyEmailRequired: import("zod").ZodBoolean;
verifyPhoneRequired: import("zod").ZodBoolean;
firstNameLastName: import("zod").ZodUnion<readonly [import("zod").ZodLiteral<"none">, import("zod").ZodLiteral<"optional">, import("zod").ZodLiteral<"required">]>;
resetPasswordAllowed: import("zod").ZodBoolean;
captchaRequired: import("zod").ZodBoolean;
adminEmails: import("zod").ZodArray<import("zod").ZodString>;
adminUsernames: import("zod").ZodArray<import("zod").ZodString>;
defaultRoles: import("zod").ZodArray<import("zod").ZodString>;
verifyEmailUrl: import("zod").ZodOptional<import("zod").ZodString>;
passwordPolicy: import("zod").ZodObject<{
minLength: import("zod").ZodDefault<import("zod").ZodInt>;
requireUppercase: import("zod").ZodBoolean;
requireLowercase: import("zod").ZodBoolean;
requireNumbers: import("zod").ZodBoolean;
requireSpecialCharacters: import("zod").ZodBoolean;
}, import("zod/v4/core").$strip>;
loginRateLimit: import("zod").ZodObject<{
ipMaxAttempts: import("zod").ZodDefault<import("zod").ZodInt>;
accountMaxAttempts: import("zod").ZodDefault<import("zod").ZodInt>;
windowMs: import("zod").ZodDefault<import("zod").ZodInt>;
}, import("zod/v4/core").$strip>;
registrationIpMaxAttempts: import("zod").ZodDefault<import("zod").ZodInt>;
refreshToken: import("zod").ZodObject<{
expirationIdle: import("zod").ZodOptional<import("zod").ZodInt>;
}, import("zod/v4/core").$strip>;
}, import("zod/v4/core").$strip>, "alepha.api.users.realmAuthSettings">;
type RealmAuthSettings = Static<typeof realmAuthSettingsAtom.schema>;
//#endregion
//#region ../../src/api/users/audits/SessionAudits.d.ts
/**
* Authentication & session-security audit events.
*
* Holds two audit types:
* - `auth` — login / logout / token refresh / MFA.
* - `security` — rate limiting, session invalidation, and related guards.
*
* Failed events are logged with `success: false`; severity (`warning`) is
* derived centrally in `AuditService.create`. Register as a module variant
* and log via the exposed primitives:
* `sessionAudits(realm)?.auth.log("login", { success: false, … })`.
*/
declare class SessionAudits {
readonly auth: import("alepha/api/audits").AuditPrimitive;
readonly security: import("alepha/api/audits").AuditPrimitive;
}
//#endregion
//#region ../../src/api/users/audits/UserAudits.d.ts
/**
* User-management audit events.
*
* Holds the `user` audit type. Mirrors the `$notification`/`$job` holder
* pattern (see {@link UserNotifications}) — register as a module variant and
* log via the exposed primitive: `userAudits(realm)?.user.log("create", …)`.
*/
declare class UserAudits {
readonly user: import("alepha/api/audits").AuditPrimitive;
}
//#endregion
//#region ../../src/api/users/buckets/UserBuckets.d.ts
/**
* User-specific file storage wrapper service.
*
* This service provides file storage for user-related files such as:
* - User avatars/profile pictures
*
* Declared as a module variant — not auto-injected. It is instantiated
* lazily the first time something calls `alepha.inject(UserBuckets)`.
*/
declare class UserBuckets {
/**
* Bucket for user avatar storage.
*/
readonly avatars: import("alepha/bucket").BucketPrimitive;
}
//#endregion
//#region ../../src/orm/core/schemas/insertSchema.d.ts
/**
* Transforms a TObject schema for insert operations.
* All default properties at the root level are made optional.
* Generated columns are excluded entirely.
*
* @example
* Before: { name: string; age: number(default=0); fullName: generated }
* After: { name: string; age?: number; }
*/
type TObjectInsert<T extends TObject> = TObject<{ [K in keyof T["shape"] as T["shape"][K] extends {
[PG_GENERATED]: any;
} ? never : K]: T["shape"][K] extends {
[PG_DEFAULT]: any;
} | {
[PG_ORGANIZATION]: any;
} ? TOptional<Extract<T["shape"][K], TSchema>> : T["shape"][K]; }>;
//#endregion
//#region ../../src/orm/core/schemas/updateSchema.d.ts
/**
* Transforms a TObject schema for update operations.
* All optional properties at the root level are made nullable (i.e., `T | null`).
* Generated columns are excluded entirely.
*
* @example
* Before: { name?: string; age: number; fullName: generated }
* After: { name?: string | null; age: number; }
*/
type TObjectUpdate<T extends TObject> = TObject<{ [K in keyof T["shape"] as T["shape"][K] extends {
[PG_GENERATED]: any;
} ? never : K]: T["shape"][K] extends TOptional<infer U extends TSchema> ? TOptional<TUnion<[U, TNull]>> : T["shape"][K]; }>;
//#endregion
//#region ../../src/orm/core/primitives/$entity.d.ts
interface EntityPrimitiveOptions<T extends TObject, Keys = keyof Static<T>> {
/**
* The database table name that will be created for this entity.
* If not provided, name will be inferred from the $repository variable name.
*/
name: string;
/**
* TypeBox schema defining the table structure and column types.
*/
schema: T;
/**
* Database indexes to create for query optimization.
*/
indexes?: (Keys | {
/**
* Single column to index.
*/
column: Keys;
/**
* Whether this should be a unique index (enforces uniqueness constraint).
*/
unique?: boolean;
/**
* Custom name for the index. If not provided, generates name automatically.
*/
name?: string;
/**
* Partial index condition. Only rows matching this SQL expression are indexed.
*/
where?: SQL;
} | {
/**
* Multiple columns for composite index (order matters for query optimization).
*/
columns: Keys[];
/**
* Whether this should be a unique index (enforces uniqueness constraint).
*/
unique?: boolean;
/**
* Custom name for the index. If not provided, generates name automatically.
*/
name?: string;
/**
* Partial index condition. Only rows matching this SQL expression are indexed.
*/
where?: SQL;
} | {
/**
* SQL expressions for expression-based indexes.
*
* Can include column references and SQL functions like `LOWER()`, `UPPER()`, etc.
* Columns and expressions can be mixed together.
*
* @example
* ```ts
* // Case-insensitive unique username per realm
* indexes: [{
* expressions: (self) => [self.realm, sql`LOWER(${self.username})`],
* unique: true,
* name: "users_realm_username_lower_idx",
* }]
* ```
*/
expressions: (self: Record<Keys & string, any>) => (SQL | any)[];
/**
* Whether this should be a unique index (enforces uniqueness constraint).
*/
unique?: boolean;
/**
* Custom name for the index. If not provided, generates name automatically.
*/
name: string;
/**
* Partial index condition. Only rows matching this SQL expression are indexed.
*/
where?: SQL;
})[];
/**
* Foreign key constraints to maintain referential integrity.
*/
foreignKeys?: Array<{
/**
* Optional name for the foreign key constraint.
*/
name?: string;
/**
* Local columns that reference the foreign table.
*/
columns: Array<keyof Static<T>>;
/**
* Referenced columns in the foreign table.
* Must be EntityColumn references from other entities.
*/
foreignColumns: Array<() => EntityColumn<any>>;
}>;
/**
* Additional table constraints for data validation.
*
* Constraints enforce business rules at the database level, providing
* an additional layer of data integrity beyond application validation.
*
* **Constraint Types**:
* - **Unique constraints**: Prevent duplicate values across columns
* - **Check constraints**: Enforce custom validation rules with SQL expressions
*
* @example
* ```ts
* constraints: [
* {
* name: "unique_user_email",
* columns: ["email"],
* unique: true
* },
* {
* name: "valid_age_range",
* columns: ["age"],
* check: sql`age >= 0 AND age <= 150`
* },
* {
* name: "unique_user_username_per_tenant",
* columns: ["tenantId", "username"],
* unique: true
* }
* ]
* ```
*/
constraints?: Array<{
/**
* Columns involved in this constraint.
*/
columns: Array<keyof Static<T>>;
/**
* Optional name for the constraint.
*/
name?: string;
/**
* Whether this is a unique constraint.
*/
unique?: boolean | {};
/**
* SQL expression for check constraint validation.
*/
check?: SQL;
}>;
/**
* Advanced Drizzle ORM configuration for complex table setups.
*/
config?: (self: BuildExtraConfigColumns<string, FromSchema<T>, "pg">) => PgTableExtraConfigValue[];
}
declare class EntityPrimitive<T extends TObject = TObject> {
readonly options: EntityPrimitiveOptions<T>;
constructor(options: EntityPrimitiveOptions<T>);
alias(alias: string): this;
get cols(): EntityColumns<T>;
get name(): string;
get schema(): T;
protected _insertSchema?: TObjectInsert<T>;
get insertSchema(): TObjectInsert<T>;
protected _updateSchema?: TObjectUpdate<T>;
get updateSchema(): TObjectUpdate<T>;
}
/**
* Convert a schema to columns.
*/
type FromSchema<T extends TObject> = { [key in keyof T["properties"]]: PgColumnBuilderBase; };
type SchemaToTableConfig<T extends TObject> = {
name: string;
schema: string | undefined;
columns: { [key in keyof T["properties"]]: PgColumn; };
dialect: string;
};
type EntityColumn<T extends TObject> = {
name: string;
entity: EntityPrimitive<T>;
};
type EntityColumns<T extends TObject> = { [key in keyof T["properties"]]: EntityColumn<T>; };
//#endregion
//#region ../../src/orm/core/constants/PG_SYMBOLS.d.ts
declare const PG_DEFAULT: unique symbol;
declare const PG_PRIMARY_KEY: unique symbol;
declare const PG_CREATED_AT: unique symbol;
declare const PG_UPDATED_AT: unique symbol;
declare const PG_DELETED_AT: unique symbol;
declare const PG_VERSION: unique symbol;
declare const PG_IDENTITY: unique symbol;
declare const PG_ENUM: unique symbol;
declare const PG_REF: unique symbol;
declare const PG_GENERATED: unique symbol;
declare const PG_ORGANIZATION: unique symbol;
/**
* @deprecated Use `PG_IDENTITY` instead.
*/
declare const PG_SERIAL: unique symbol;
type PgSymbols = {
[PG_DEFAULT]: {};
[PG_PRIMARY_KEY]: {};
[PG_CREATED_AT]: {};
[PG_UPDATED_AT]: {};
[PG_DELETED_AT]: {};
[PG_VERSION]: {};
[PG_IDENTITY]: PgIdentityOptions;
[PG_REF]: PgRefOptions;
[PG_ENUM]: PgEnumOptions;
[PG_GENERATED]: PgGeneratedOptions;
[PG_ORGANIZATION]: PgOrganizationOptions;
/**
* @deprecated Use `PG_IDENTITY` instead.
*/
[PG_SERIAL]: {};
};
type PgSymbolKeys = keyof PgSymbols;
interface PgOrganizationOptions {
/**
* Fail-closed tenant scoping. When `true`, the repository (a) refuses any
* read/write with no resolved tenant instead of falling through to an
* unfiltered "see/write everything" query, and (b) drops the
* `OR organizationId IS NULL` "global row" escape — a scoped tenant never
* sees NULL/global rows. Use for security-sensitive tables. Defaults to
* `false` (the historic fail-open semantics).
*/
strict?: boolean;
}
type PgIdentityOptions = {
mode: "always" | "byDefault";
} & PgSequenceOptions & {
name?: string;
};
interface PgEnumOptions {
name?: string;
description?: string;
}
interface PgGeneratedOptions {
/**
* SQL expression for the generated column.
*/
expression: SQL;
/**
* Storage mode for the generated column.
* - `"stored"` — value is computed on write and stored on disk (default for PostgreSQL).
* - `"virtual"` — value is computed on read (default for SQLite).
*/
mode?: "stored" | "virtual";
}
interface PgRefOptions {
ref: () => {
name: string;
entity: EntityPrimitive;
};
actions?: {
onUpdate?: UpdateDeleteAction;
onDelete?: UpdateDeleteAction;
};
}
//#endregion
//#region ../../src/orm/core/errors/DbError.d.ts
declare class DbError extends AlephaError {
name: string;
constructor(message: string, cause?: unknown);
}
//#endregion
//#region ../../src/orm/core/helpers/pgAttr.d.ts
/**
* Type representation.
*/
type PgAttr<T extends TSchema, TAttr extends PgSymbolKeys> = T & { [K in TAttr]: PgSymbols[K]; };
interface PgAttrField {
key: string;
type: TSchema;
data: any;
nested?: any[];
one?: boolean;
}
//#endregion
//#region ../../src/orm/core/interfaces/FilterOperators.d.ts
interface FilterOperators<TValue> {
/**
* Test that two values are equal.
*
* Remember that the SQL standard dictates that
* two NULL values are not equal, so if you want to test
* whether a value is null, you may want to use
* `isNull` instead.
*
* ## Examples
*
* ```ts
* // Select cars made by Ford
* db.select().from(cars)
* .where(eq(cars.make, 'Ford'))
* ```
*
* @see isNull for a way to test equality to NULL.
*/
eq?: TValue;
/**
* Test that two values are not equal.
*
* Remember that the SQL standard dictates that
* two NULL values are not equal, so if you want to test
* whether a value is not null, you may want to use
* `isNotNull` instead.
*
* ## Examples
*
* ```ts
* // Select cars not made by Ford
* db.select().from(cars)
* .where(ne(cars.make, 'Ford'))
* ```
*
* @see isNotNull for a way to test whether a value is not null.
*/
ne?: TValue;
/**
* Test that the first expression passed is greater than
* the second expression.
*
* ## Examples
*
* ```ts
* // Select cars made after 2000.
* db.select().from(cars)
* .where(gt(cars.year, 2000))
* ```
*
* @see gte for greater-than-or-equal
*/
gt?: TValue;
/**
* Test that the first expression passed is greater than
* or equal to the second expression. Use `gt` to
* test whether an expression is strictly greater
* than another.
*
* ## Examples
*
* ```ts
* // Select cars made on or after 2000.
* db.select().from(cars)
* .where(gte(cars.year, 2000))
* ```
*
* @see gt for a strictly greater-than condition
*/
gte?: TValue;
/**
* Test that the first expression passed is less than
* the second expression.
*
* ## Examples
*
* ```ts
* // Select cars made before 2000.
* db.select().from(cars)
* .where(lt(cars.year, 2000))
* ```
*
* @see lte for greater-than-or-equal
*/
lt?: TValue;
/**
* Test that the first expression passed is less than
* or equal to the second expression.
*
* ## Examples
*
* ```ts
* // Select cars made before 2000.
* db.select().from(cars)
* .where(lte(cars.year, 2000))
* ```
*
* @see lt for a strictly less-than condition
*/
lte?: TValue;
/**
* Test whether the first parameter, a column or expression,
* has a value from a list passed as the second argument.
*
* ## Throws
*
* The argument passed in the second array can't be empty:
* if an empty is provided, this method will throw.
*
* ## Examples
*
* ```ts
* // Select cars made by Ford or GM.
* db.select().from(cars)
* .where(inArray(cars.make, ['Ford', 'GM']))
* ```
*
* @see notInArray for the inverse of this test
*/
inArray?: TValue[];
/**
* Test whether the first parameter, a column or expression,
* has a value that is not present in a list passed as the
* second argument.
*
* ## Throws
*
* The argument passed in the second array can't be empty:
* if an empty is provided, this method will throw.
*
* ## Examples
*
* ```ts
* // Select cars made by any company except Ford or GM.
* db.select().from(cars)
* .where(notInArray(cars.make, ['Ford', 'GM']))
* ```
*
* @see inArray for the inverse of this test
*/
notInArray?: TValue[];
/**
* Test whether an expression is not NULL. By the SQL standard,
* NULL is neither equal nor not equal to itself, so
* it's recommended to use `isNull` and `notIsNull` for
* comparisons to NULL.
*
* ## Examples
*
* ```ts
* // Select cars that have been discontinued.
* db.select().from(cars)
* .where(isNotNull(cars.discontinuedAt))
* ```
*
* @see isNull for the inverse of this test
*/
isNotNull?: true;
/**
* Test whether an expression is NULL. By the SQL standard,
* NULL is neither equal nor not equal to itself, so
* it's recommended to use `isNull` and `notIsNull` for
* comparisons to NULL.
*
* ## Examples
*
* ```ts
* // Select cars that have no discontinuedAt date.
* db.select().from(cars)
* .where(isNull(cars.discontinuedAt))
* ```
*
* @see isNotNull for the inverse of this test
*/
isNull?: true;
/**
* Test whether an expression is between two values. This
* is an easier way to express range tests, which would be
* expressed mathematically as `x <= a <= y` but in SQL
* would have to be like `a >= x AND a <= y`.
*
* Between is inclusive of the endpoints: if `column`
* is equal to `min` or `max`, it will be TRUE.
*
* ## Examples
*
* ```ts
* // Select cars made between 1990 and 2000
* db.select().from(cars)
* .where(between(cars.year, 1990, 2000))
* ```
*
* @see notBetween for the inverse of this test
*/
between?: [number, number];
/**
* Test whether an expression is not between two values.
*
* This, like `between`, includes its endpoints, so if
* the `column` is equal to `min` or `max`, in this case
* it will evaluate to FALSE.
*
* ## Examples
*
* ```ts
* // Exclude cars made in the 1970s
* db.select().from(cars)
* .where(notBetween(cars.year, 1970, 1979))
* ```
*
* @see between for the inverse of this test
*/
notBetween?: [number, number];
/**
* Compare a column to a pattern, which can include `%` and `_`
* characters to match multiple variations. Including `%`
* in the pattern matches zero or more characters, and including
* `_` will match a single character.
*
* ## Examples
*
* ```ts
* // Select all cars with 'Turbo' in their names.
* db.select().from(cars)
* .where(like(cars.name, '%Turbo%'))
* ```
*
* @see ilike for a case-insensitive version of this condition
*/
like?: string;
/**
* The inverse of like - this tests that a given column
* does not match a pattern, which can include `%` and `_`
* characters to match multiple variations. Including `%`
* in the pattern matches zero or more characters, and including
* `_` will match a single character.
*
* ## Examples
*
* ```ts
* // Select all cars that don't have "ROver" in their name.
* db.select().from(cars)
* .where(notLike(cars.name, '%Rover%'))
* ```
*
* @see like for the inverse condition
* @see notIlike for a case-insensitive version of this condition
*/
notLike?: string;
/**
* Case-insensitively compare a column to a pattern,
* which can include `%` and `_`
* characters to match multiple variations. Including `%`
* in the pattern matches zero or more characters, and including
* `_` will match a single character.
*
* Unlike like, this performs a case-insensitive comparison.
*
* ## Examples
*
* ```ts
* // Select all cars with 'Turbo' in their names.
* db.select().from(cars)
* .where(ilike(cars.name, '%Turbo%'))
* ```
*
* @see like for a case-sensitive version of this condition
*/
ilike?: string;
/**
* The inverse of ilike - this case-insensitively tests that a given column
* does not match a pattern, which can include `%` and `_`
* characters to match multiple variations. Including `%`
* in the pattern matches zero or more characters, and including
* `_` will match a single character.
*
* ## Examples
*
* ```ts
* // Select all cars that don't have "Rover" in their name.
* db.select().from(cars)
* .where(notLike(cars.name, '%Rover%'))
* ```
*
* @see ilike for the inverse condition
* @see notLike for a case-sensitive version of this condition
*/
notIlike?: string;
/**
* Syntactic sugar for case-insensitive substring matching.
* Automatically wraps the value with `%` wildcards on both sides.
*
* Equivalent to: `ilike: '%value%'`
*
* ## Examples
*
* ```ts
* // Select all cars with "Turbo" anywhere in their name.
* db.select().from(cars)
* .where({ name: { contains: 'Turbo' } })
* // Same as: .where(ilike(cars.name, '%Turbo%'))
* ```
*
* @see ilike for manual pattern matching
* @see startsWith for prefix matching
* @see endsWith for suffix matching
*/
contains?: string;
/**
* Syntactic sugar for case-insensitive prefix matching.
* Automatically appends a `%` wildcard to the end of the value.
*
* Equivalent to: `ilike: 'value%'`
*
* ## Examples
*
* ```ts
* // Select all cars whose names start with "Ford".
* db.select().from(cars)
* .where({ name: { startsWith: 'Ford' } })
* // Same as: .where(ilike(cars.name, 'Ford%'))
* ```
*
* @see ilike for manual pattern matching
* @see contains for substring matching
* @see endsWith for suffix matching
*/
startsWith?: string;
/**
* Syntactic sugar for case-insensitive suffix matching.
* Automatically prepends a `%` wildcard to the beginning of the value.
*
* Equivalent to: `ilike: '%value'`
*
* ## Examples
*
* ```ts
* // Select all cars whose names end with "Turbo".
* db.select().from(cars)
* .where({ name: { endsWith: 'Turbo' } })
* // Same as: .where(ilike(cars.name, '%Turbo'))
* ```
*
* @see ilike for manual pattern matching
* @see contains for substring matching
* @see startsWith for prefix matching
*/
endsWith?: string;
/**
* Test that a column or expression contains all elements of
* the list passed as the second argument.
*
* ## Throws
*
* The argument passed in the second array can't be empty:
* if an empty is provided, this method will throw.
*
* ## Examples
*
* ```ts
* // Select posts where its tags contain "Typescript" and "ORM".
* db.select().from(posts)
* .where(arrayContains(posts.tags, ['Typescript', 'ORM']))
* ```
*
* @see arrayContained to find if an array contains all elements of a column or expression
* @see arrayOverlaps to find if a column or expression contains any elements of an array
*/
arrayContains?: TValue;
/**
* Test that the list passed as the second argument contains
* all elements of a column or expression.
*
* ## Throws
*
* The argument passed in the second array can't be empty:
* if an empty is provided, this method will throw.
*
* ## Examples
*
* ```ts
* // Select posts where its tags contain "Typescript", "ORM" or both,
* // but filtering posts that have additional tags.
* db.select().from(posts)
* .where(arrayContained(posts.tags, ['Typescript', 'ORM']))
* ```
*
* @see arrayContains to find if a column or expression contains all elements of an array
* @see arrayOverlaps to find if a column or expression contains any elements of an array
*/
arrayContained?: TValue;
/**
* Test that a column or expression contains any elements of
* the list passed as the second argument.
*
* ## Throws
*
* The argument passed in the second array can't be empty:
* if an empty is provided, this method will throw.
*
* ## Examples
*
* ```ts
* // Select posts where its tags contain "Typescript", "ORM" or both.
* db.select().from(posts)
* .where(arrayOverlaps(posts.tags, ['Typescript', 'ORM']))
* ```
*
* @see arrayContains to find if a column or expression contains all elements of an array
* @see arrayContained to find if an array contains all elements of a column or expression
*/
arrayOverlaps?: TValue;
}
//#endregion
//#region ../../src/orm/core/interfaces/PgQuery.d.ts
/**
* Order direction for sorting
*/
type OrderDirection = "asc" | "desc";
/**
* Single order by clause with column and direction
*/
interface OrderByClause<T> {
column: keyof T;
direction?: OrderDirection;
}
/**
* Order by parameter - supports 3 modes:
* 1. String: orderBy: "name" (defaults to ASC)
* 2. Single object: orderBy: { column: "name", direction: "desc" }
* 3. Array: orderBy: [{ column: "name", direction: "asc" }, { column: "age", direction: "desc" }]
*/
type OrderBy<T> = keyof T | OrderByClause<T> | Array<OrderByClause<T>>;
/**
* Generic query interface for PostgreSQL entities
*/
interface PgQuery<T extends TObject = TObject> {
distinct?: (keyof Static<T>)[];
columns?: (keyof Static<T>)[];
where?: PgQueryWhereOrSQL<T>;
limit?: number;
offset?: number;
orderBy?: OrderBy<Static<T>>;
groupBy?: (keyof Static<T>)[];
}
type PgStatic<T extends TObject, Relations extends PgRelationMap<T>> = Static<T> & { [K in keyof Relations]: Static<Relations[K]["join"]["schema"]> & (Relations[K]["with"] extends PgRelationMap<TObject> ? PgStatic<Relations[K]["join"]["schema"], Relations[K]["with"]> : {}); };
interface PgQueryRelations<T extends TObject = TObject, Relations extends PgRelationMap<T> | undefined = undefined> extends PgQuery<T> {
with?: Relations;
where?: PgQueryWhereOrSQL<T, Relations>;
}
type PgRelationMap<Base extends TObject> = Record<string, PgRelation<Base>>;
type PgRelation<Base extends TObject> = {
type?: "left" | "inner" | "right";
join: {
schema: TObject;
name: string;
};
on: SQLWrapper | readonly [keyof Static<Base>, {
name: string;
}];
with?: PgRelationMap<TObject>;
};
//#endregion
//#region ../../src/orm/core/interfaces/PgQueryWhere.d.ts
type PgQueryWhere<T extends TObject, Relations extends PgRelationMap<TObject> | undefined = undefined> = (PgQueryWhereOperators<T> & PgQueryWhereConditions<T>) | (PgQueryWhereRelations<Relations> & PgQueryWhereOperators<T> & PgQueryWhereConditions<T, Relations>);
type PgQueryWhereOrSQL<T extends TObject, Relations extends PgRelationMap<TObject> | undefined = undefined> = SQLWrapper | PgQueryWhere<T, Relations>;
type PgQueryWhereOperators<T extends TObject> = { [Key in keyof Static<T>]?: FilterOperators<Static<T>[Key]> | Static<T>[Key]; };
type PgQueryWhereConditions<T extends TObject, Relations extends PgRelationMap<TObject> | undefined = undefined> = {
/**
* Combine a list of conditions with the `and` operator. Conditions
* that are equal `undefined` are automatically ignored.
*
* ## Examples
*
* ```ts
* db.select().from(cars)
* .where(
* and(
* eq(cars.make, 'Volvo'),
* eq(cars.year, 1950),
* )
* )
* ```
*/
and?: Array<PgQueryWhereOrSQL<T, Relations>>;
/**
* Combine a list of conditions with the `or` operator. Conditions
* that are equal `undefined` are automatically ignored.
*
* ## Examples
*
* ```ts
* db.select().from(cars)
* .where(
* or(
* eq(cars.make, 'GM'),
* eq(cars.make, 'Ford'),
* )
* )
* ```
*/
or?: Array<PgQueryWhereOrSQL<T, Relations>>;
/**
* Negate the meaning of an expression using the `not` keyword.
*
* ## Examples
*
* ```ts
* // Select cars _not_ made by GM or Ford.
* db.select().from(cars)
* .where(not(inArray(cars.make, ['GM', 'Ford'])))
* ```
*/
not?: PgQueryWhereOrSQL<T, Relations>;
/**
* Test whether a subquery evaluates to have any rows.
*
* ## Examples
*
* ```ts
* // Users whose `homeCity` column has a match in a cities
* // table.
* db
* .select()
* .from(users)
* .where(
* exists(db.select()
* .from(cities)
* .where(eq(users.homeCity, cities.id))),
* );
* ```
*
* @see notExists for the inverse of this test
*/
exists?: SQLWrapper;
/**
* Test whether a subquery evaluates to have no rows.
*
* @see exists for the inverse of this test
*/
notExists?: SQLWrapper;
};
type PgQueryWhereRelations<Relations extends PgRelationMap<TObject> | undefined = undefined> = Relations extends PgRelationMap<TObject> ? { [K in keyof Relations]?: PgQueryWhere<Relations[K]["join"]["schema"], Relations[K]["with"]>; } : {};
//#endregion
//#region ../../src/orm/core/interfaces/AggregateQuery.d.ts
type AggregateOp = "count" | "sum" | "avg" | "min" | "max";
/**
* Select definition for aggregate queries.
* - `true` means select the column value as-is (used for groupBy columns).
* - `{ sum: true, avg: true, ... }` means compute those aggregations.
*/
type AggregateColumnSelect = true | Partial<Record<AggregateOp, true>>;
type AggregateSelect<T extends TObject> = { [K in keyof Static<T>]?: AggregateColumnSelect; };
/**
* Maps a single column's select definition to its result type.
* - `true` → original column type
* - `{ sum: true, avg: true }` → `{ sum: number; avg: number }`
*/
type AggregateColumnResult<TValue, TSelect> = TSelect extends true ? TValue : { [Op in AggregateOp as TSelect extends Record<Op, true> ? Op : never]: number; };
/**
* Result type for an aggregate query.
*/
type AggregateResult<T extends TObject, S extends AggregateSelect<T>> = { [K in keyof S & keyof Static<T>]: AggregateColumnResult<Static<T>[K], NonNullable<S[K]>>; };
/**
* HAVING clause for aggregate queries.
* Only applies to columns with aggregate operations (not `true`).
*/
type AggregateHaving<T extends TObject, S extends AggregateSelect<T>> = { [K in keyof S & keyof Static<T>]?: S[K] extends true ? never : { [Op in AggregateOp as S[K] extends Record<Op, true> ? Op : never]?: {
gt?: number;
gte?: number;
lt?: number;
lte?: number;
eq?: number;
ne?: number;
}; }; };
/**
* Full aggregate query definition.
*/
interface AggregateQuery<T extends TObject, S extends AggregateSelect<T>> {
/**
* Columns and aggregate operations to select.
*/
select: S;
/**
* WHERE clause to filter rows before aggregation.
*/
where?: PgQueryWhereOrSQL<T>;
/**
* Columns to group by.
*/
groupBy?: (keyof Static<T>)[];
/**
* HAVING clause to filter groups after aggregation.
*/
having?: AggregateHaving<T, S>;
/**
* Order results. Supports dot notation for aggregate columns (e.g. "amount.sum").
*/
orderBy?: string | {
column: string;
direction: "asc" | "desc";
} | Array<{
column: string;
direction: "asc" | "desc";
}>;
/**
* Limit the number of results.
*/
limit?: number;
/**
* Offset for pagination.
*/
offset?: number;
}
//#endregion
//#region ../../src/orm/core/providers/DbCacheProvider.d.ts
/**
* Database query cache using a simple in-memory Map.
*
* Uses `{tableName}:{cacheKey}` as the storage key.
* Provides per-table invalidation for write-through cache busting.
*
* This is intentionally self-contained (no external cache dependencies)
* so the ORM module does not force `AlephaCache` on all consumers.
*/
declare class DbCacheProvider {
protected readonly dateTime: DateTimeProvider;
protected readonly store: Map<string, {
value: unknown;
expiresAt?: number;
}>;
protected storeKey(tableName: string, cacheKey: string): string;
/**
* Get a cached query result.
*/
get<T>(tableName: string, cacheKey: string): Promise<T | undefined>;
/**
* Store a query result in the cache.
*/
set<T>(tableName: string, cacheKey: string, value: T, ttl?: number): Promise<void>;
/**
* Invalidate all cached queries for a table.
*/
invalidateTable(tableName: string): Promise<void>;
}
//#endregion
//#region ../../src/orm/core/providers/SequenceProvider.d.ts
/**
* Portable, scoped numeric sequence provider — works identically on Postgres,
* SQLite, and Cloudflare D1.
*
* Implementation: a single `alepha_sequences` table holds one row per
* `(name, scope)` pair. Every call to {@link advance} runs an
* `INSERT ... ON CONFLICT (name, scope) DO UPDATE SET value = value + step`
* with `RETURNING value`, which is atomic on every supported driver:
*
* - **Postgres**: row-level lock on `ON CONFLICT DO UPDATE`.
* - **SQLite / D1**: writes are serialized, atomic by construction.
*
* The repository pattern is the same one used by `DatabaseCacheProvider.incr()`
* — see that file for the proof-of-design.
*
* Callers never instantiate this directly. They declare a {@link SequencePrimitive}
* via `$sequence()` and call `.next(scope?)` on the primitive — this provider is
* the engine behind that call.
*/
declare class SequenceProvider {
protected readonly repository: Repository$1<import("zod").ZodObject<{
id: PgAttr<PgAttr<import("zod").ZodString, typeof PG_PRIMARY_KEY>, typeof PG_DEFAULT>;
createdAt: PgAttr<PgAttr<import("zod").ZodString, typeof PG_CREATED_AT>, typeof PG_DEFAULT>;
updatedAt: PgAttr<PgAttr<import("zod").ZodString, typeof PG_UPDATED_AT>, typeof PG_DEFAULT>;
name: import("zod").ZodString;
scope: import("zod").ZodString;
value: import("zod").ZodInt;
}, import("zod/v4/core").$strip>>;
protected readonly crypto: CryptoProvider$1;
/**
* Atomically advance the counter for `(name, scope)` and return the new value.
*
* If the row doesn't exist yet, it's inserted with `value = start` and that
* value is returned. Subsequent calls increment by `step`.
*
* Scope defaults to "default" — pass any string to namespace per
* tenant / campaign / parent entity / etc.
*/
advance(name: string, scope?: string, opts?: {
startWith?: number;
incrementBy?: number;
}): Promise<number>;
/**
* Read the current value without advancing it. Returns `null` if the
* `(name, scope)` pair has never been advanced.
*/
peek(name: string, scope?: string): Promise<number | null>;
/**
* Reset the counter for `(name, scope)` to an explicit value. Creates the row
* if it doesn't exist.
*
* Mostly useful in tests and ops scripts — production code should rarely call
* this, since it can produce duplicate IDs if anything still holds a previously
* advanced value.
*/
reset(name: string, scope: string | undefined, value: number): Promise<void>;
}
//#endregion
//#region ../../src/orm/core/primitives/$sequence.d.ts
interface SequencePrimitiveOptions {
/**
* Sequence name. Defaults to the primitive's property key. Two primitives
* sharing the same name share the same counter table rows, which is rarely
* what you want — prefer letting the property key drive the name.
*/
name?: string;
/**
* Starting value used on the very first `.next()` for a `(name, scope)` pair.
* Defaults to `1`.
*/
startWith?: number;
/**
* Amount added on every call to `.next()`. Defaults to `1`.
*/
incrementBy?: number;
}
declare class SequencePrimitive extends Primitive<SequencePrimitiveOptions> {
protected readonly provider: SequenceProvider;
get name(): string;
/**
* Atomically advance the counter and return the new value.
*
* Scope defaults to "default". Pass any string to keep an independent counter
* per tenant / campaign / parent entity / etc.
*
* **Transaction semantics:** when called inside a `$transactional` block, the
* increment participates in that transaction — commit advances the counter,
* rollback unwinds it. This is intentionally different from PG-native
* `nextval()` (which leaves gaps on rollback). It means a failed insert that
* consumed a `shortId` returns the value to the pool instead of burning it.
*/
next(scope?: string): Promise<number>;
/**
* Read the current value without advancing it. Returns `null` if the
* `(name, scope)` pair has never been advanced.
*/
current(scope?: string): Promise<number | null>;
/**
* Reset the counter for the given scope to an explicit value. Creates the row
* if it doesn't exist. Mostly useful in tests and ops scripts.
*/
reset(value: number, scope?: string): Promise<void>;
}
//#endregion
//#region ../../src/orm/core/services/ModelBuilder.d.ts
/**
* Database-specific table configuration functions
*/
interface TableConfigBuilders<TConfig> {
index: (name: string) => {
on: (...columns: any[]) => TConfig;
};
uniqueIndex: (name: string) => {
on: (...columns: any[]) => TConfig;
};
unique: (name: string) => {
on: (...columns: any[]) => TConfig;
};
check: (name: string, sql: SQL) => TConfig;
foreignKey: (config: {
name: string;
columns: any[];
foreignColumns: any[];
}) => TConfig;
}
/**
* Abstract base class for transforming Alepha Primitives (Entity, Sequence, etc...)
* into drizzle models (tables, enums, sequences, etc...).
*/
declare abstract class ModelBuilder {
/**
* Build a table from an entity primitive.
*/
abstract buildTable(entity: EntityPrimitive, options: {
tables: Map<string, unknown>;
enums: Map<string, unknown>;
schemas: Map<string, unknown>;
schema: string;
}): void;
/**
* Build a sequence from a sequence primitive.
*/
abstract buildSequence(sequence: SequencePrimitive, options: {
sequences: Map<string, unknown>;
schema: string;
}): void;
/**
* Convert camelCase to snake_case for column names.
*/
protected toColumnName(str: string): string;
/**
* Build the table configuration function for any database.
* This includes indexes, foreign keys, constraints, and custom config.
*
* @param entity - The entity primitive
* @param builders - Database-specific builder functions
* @param tableResolver - Function to resolve entity references to table columns
* @param customConfigHandler - Optional handler for custom config
*/
protected buildTableConfig<TConfig, TSelf>(entity: EntityPrimitive, builders: TableConfigBuilders<TConfig>, tableResolver?: (entityName: string) => any, customConfigHandler?: (config: any, self: TSelf) => TConfig[]): ((self: TSelf) => TConfig[]) | undefined;
}
//#endregion
//#region ../../src/orm/core/providers/DrizzleKitProvider.d.ts
declare class DrizzleKitProvider {
protected readonly log: import("alepha/logger").Logger;
protected readonly dateTime: DateTimeProvider;
protected readonly alepha: Alepha;
/**
* Push-based synchronization using Drizzle Kit's introspection API.
*
* Reads the actual database state, diffs against current entity definitions,
* and applies changes. No stored snapshots — no drift, no corruption.
*
* - SQLite: uses `pushSQLiteSchema` (requires sync driver — node:sqlite shim or bun-sqlite)
* - PostgreSQL: uses `pushSchema` with schema filters
*
* Does nothing in production mode — use file-based migrations instead.
*/
synchronize(provider: DatabaseProvider): Promise<void>;
/**
* Generate SQL migration statements by diffing two schema states.
*
* Used by tests (schema validation) and CLI (`alepha db migrations generate`).
* Not part of the push sync flow.
*
* When `withoutSchema` is true, models are rebuilt without schema qualifiers
* so the generated SQL is portable across different PostgreSQL schemas.
*/
generateMigration(provider: DatabaseProvider, prevSnapshot?: any, options?: {
withoutSchema?: boolean;
}): Promise<{
statements: string[];
models: Record<string, unknown>;
snapshot?: any;
}>;
/**
* Load all tables, enums, sequences, etc. from the provider's repositories.
*/
getModels(provider: DatabaseProvider): Record<string, unknown>;
/**
* Build schema-free models for migration generation.
*
* Rebuilds all entities with `schema = "public"` so Drizzle produces
* SQL without schema qualifiers (e.g. `CREATE TABLE "users"` instead
* of `CREATE TABLE "myschema"."users"`).
*
* The actual schema is applied at migration execution time via `search_path`.
*/
getModelsWithoutSchema(provider: DatabaseProvider): Record<string, unknown>;
/**
* Preview schema push without executing any statements.
*
* Returns the SQL statements that would be executed, warnings, and
* whether data loss would occur. Does NOT execute any SQL.
*/
dryRunPush(provider: DatabaseProvider): Promise<{
statements: string[];
warnings: string[];
hasDataLoss: boolean;
}>;
protected pushSqlite(kit: typeof DrizzleKit, models: Record<string, unknown>, provider: DatabaseProvider): Promise<void>;
/**
* Push schema changes to PostgreSQL using Drizzle Kit's pushSchema with schema filters.
*/
protected pushPostgres(kit: typeof DrizzleKit, models: Record<string, unknown>, provider: DatabaseProvider): Promise<void>;
/**
* Execute a list of SQL statements against the provider.
*/
protected executeStatements(statements: string[], provider: DatabaseProvider): Promise<void>;
/**
* Execute SQL statements, ignoring "already exists" errors.
*
* Used by the fallback migration path where push may have partially
* applied changes before erroring, leaving some objects already created.
*/
protected executeStatementsLenient(statements: string[], provider: DatabaseProvider): Promise<void>;
protected createSchemaIfNotExists(provider: DatabaseProvider, schemaName: string): Promise<void>;
/**
* Wrap a Drizzle PgDatabase instance for compatibility with Drizzle Kit.
*
* Drizzle Kit's pushSchema expects execute() to return { rows: T[] }
* (node-postgres/pg format), but postgres.js returns a Result that
* extends Array directly — no .rows property.
*/
protected wrapDbForDrizzleKit(db: any): any;
/**
* Try to load the official Drizzle Kit API.
*/
importDrizzleKit(): typeof DrizzleKit;
}
//#endregion
//#region ../../src/orm/core/providers/drivers/DatabaseProvider.d.ts
type SQLLike = SQLWrapper | string;
declare abstract class DatabaseProvider {
protected readonly alepha: Alepha;
protected readonly dateTime: DateTimeProvider;
protected readonly log: import("alepha/logger").Logger;
protected abstract readonly builder: ModelBuilder;
protected readonly kit: DrizzleKitProvider;
abstract readonly db: PgDatabase<any>;
abstract readonly dialect: "postgresql" | "sqlite";
abstract readonly url: string;
readonly enums: Map<string, unknown>;
readonly tables: Map<string, unknown>;
readonly sequences: Map<string, unknown>;
readonly schemas: Map<string, unknown>;
protected readonly entityPrimitives: EntityPrimitive[];
protected readonly sequencePrimitives: SequencePrimitive[];
get name(): string;
get driver(): string;
/**
* Whether this driver supports SQL-level transactions (BEGIN/COMMIT/ROLLBACK).
*
* Drivers that do not (e.g. PGlite, Cloudflare D1) should override to `false`.
*/
get supportsTransactions(): boolean;
/**
* Raw database connection handle (e.g. DatabaseSync, bun:sqlite Database).
* Override in providers that expose native connections for introspection.
*/
get nativeConnection(): unknown;
get schema(): string;
/**
* Migration tracking table name, scoped by schema.
*
* Returns `migrations_{schema}` so that multiple schemas sharing the same
* database each get their own migration history (e.g. `migrations_lore`,
* `migrations_public`).
*/
get migrationsTable(): string;
/**
* Log a database query with structured metadata for devtools inspection.
*/
protected logQuery(sql: string, params: unknown[], duration: number, rowCount: number, error?: string): void;
protected parseOperation(sql: string): string;
table<T extends TObject>(entity: EntityPrimitive<T>): PgTableWithColumns<SchemaToTableConfig<T>>;
registerEntity(entity: EntityPrimitive): void;
registerSequence(sequence: SequencePrimitive): void;
/**
* Rebuild all models into fresh maps using a different schema.
*
* When called with `"public"`, produces schema-free models suitable for
* migration generation (no schema qualifiers in the SQL output).
*/
rebuildModels(targetSchema: string): {
tables: Map<string, unknown>;
enums: Map<string, unknown>;
sequences: Map<string, unknown>;
schemas: Map<string, unknown>;
};
/**
* Run a function inside a database transaction with implicit tx propagation.
*
* The transaction object is stored in `alepha.store` so that all Repository
* operations within `fn` automatically participate in the transaction without
* explicit `{ tx }` drilling.
*
* Nesting is safe — if already inside a `transactional()` block, the inner
* call reuses the outer transaction (no nested PG transactions / savepoints).
*/
transactional<R>(fn: () => Promise<R>, config?: PgTransactionConfig): Promise<R>;
abstract execute(statement: SQLLike): Promise<Record<string, unknown>[]>;
run<T extends TObject>(statement: SQLLike, schema: T): Promise<Array<Static<T>>>;
/**
* Get migrations folder path - can be overridden
*/
protected getMigrationsFolder(): string;
/**
* Migration orchestration.
*
* - Production: file-based migrations from the migrations folder
* - Dev / Test: push-based sync (introspects actual DB, no snapshots)
* - Serverless: skipped (migrations should be applied during deployment)
*/
migrate(): Promise<void>;
/**
* Provider-specific migration execution
* MUST be implemented by each provider
*/
protected abstract executeMigrations(migrationsFolder: string): Promise<void>;
/**
* For testing purposes, generate a unique schema name.
*
* Format: `test_alepha_{epoch_seconds}_{random8}`
* Example: `test_alepha_1739871618_k3m9x2p1`
*/
protected generateTestSchemaName(): string;
}
//#endregion
//#region ../../src/orm/core/services/QueryManager.d.ts
declare class QueryManager {
protected readonly alepha: Alepha;
/**
* Convert a query object to a SQL query.
*/
toSQL(query: PgQueryWhereOrSQL<TObject>, options: {
schema: TObject;
col: (key: string) => PgColumn;
joins?: PgJoin[];
dialect: "postgresql" | "sqlite";
}): SQL | undefined;
/**
* Check if an object has any filter operator properties.
*/
protected hasFilterOperatorProperties(obj: any): boolean;
/**
* Map a filter operator to a SQL query.
*/
mapOperatorToSql(operator: FilterOperators<any> | any, column: PgColumn, columnSchema?: TObject, columnName?: string, dialect?: "postgresql" | "sqlite"): SQL | undefined;
/**
* Parse pagination sort string to orderBy format.
* Format: "firstName,-lastName" -> [{ column: "firstName", direction: "asc" }, { column: "lastName", direction: "desc" }]
* - Columns separated by comma
* - Prefix with '-' for DESC direction
*
* @param sort Pagination sort string
* @returns