@guren/server 0.2.0-alpha.7 → 1.0.0-rc.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/Application-DtWDHXr1.d.ts +2110 -0
  2. package/dist/BroadcastManager-AkIWUGJo.d.ts +466 -0
  3. package/dist/CacheManager-BkvHEOZX.d.ts +244 -0
  4. package/dist/ConsoleKernel-CqCVrdZs.d.ts +207 -0
  5. package/dist/EventManager-CmIoLt7r.d.ts +207 -0
  6. package/dist/Gate-CNkBYf8m.d.ts +268 -0
  7. package/dist/HealthManager-DUyMIzsZ.d.ts +141 -0
  8. package/dist/I18nManager-Dtgzsf5n.d.ts +270 -0
  9. package/dist/LogManager-7mxnkaPM.d.ts +256 -0
  10. package/dist/MailManager-DpMvYiP9.d.ts +292 -0
  11. package/dist/Scheduler-BstvSca7.d.ts +469 -0
  12. package/dist/StorageManager-oZTHqaza.d.ts +337 -0
  13. package/dist/api-token-JOif2CtG.d.ts +1792 -0
  14. package/dist/app-key-CsBfRC_Q.d.ts +214 -0
  15. package/dist/auth/index.d.ts +418 -0
  16. package/dist/auth/index.js +6742 -0
  17. package/dist/authorization/index.d.ts +129 -0
  18. package/dist/authorization/index.js +621 -0
  19. package/dist/broadcasting/index.d.ts +233 -0
  20. package/dist/broadcasting/index.js +907 -0
  21. package/dist/cache/index.d.ts +233 -0
  22. package/dist/cache/index.js +817 -0
  23. package/dist/encryption/index.d.ts +222 -0
  24. package/dist/encryption/index.js +602 -0
  25. package/dist/events/index.d.ts +155 -0
  26. package/dist/events/index.js +330 -0
  27. package/dist/health/index.d.ts +185 -0
  28. package/dist/health/index.js +379 -0
  29. package/dist/i18n/index.d.ts +101 -0
  30. package/dist/i18n/index.js +597 -0
  31. package/dist/index-9_Jzj5jo.d.ts +7 -0
  32. package/dist/index.d.ts +2628 -619
  33. package/dist/index.js +22229 -3116
  34. package/dist/lambda/index.d.ts +156 -0
  35. package/dist/lambda/index.js +91 -0
  36. package/dist/logging/index.d.ts +50 -0
  37. package/dist/logging/index.js +557 -0
  38. package/dist/mail/index.d.ts +288 -0
  39. package/dist/mail/index.js +695 -0
  40. package/dist/mcp/index.d.ts +139 -0
  41. package/dist/mcp/index.js +382 -0
  42. package/dist/notifications/index.d.ts +271 -0
  43. package/dist/notifications/index.js +741 -0
  44. package/dist/queue/index.d.ts +423 -0
  45. package/dist/queue/index.js +958 -0
  46. package/dist/runtime/index.d.ts +93 -0
  47. package/dist/runtime/index.js +834 -0
  48. package/dist/scheduling/index.d.ts +41 -0
  49. package/dist/scheduling/index.js +836 -0
  50. package/dist/storage/index.d.ts +196 -0
  51. package/dist/storage/index.js +832 -0
  52. package/dist/vite/index.js +203 -3
  53. package/package.json +93 -6
  54. package/dist/chunk-FK2XQSBF.js +0 -160
@@ -0,0 +1,1792 @@
1
+ import { MiddlewareHandler, Context } from 'hono';
2
+
3
+ /** Accessor function: transforms a record field value after reading from DB. */
4
+ type AccessorFn<T = unknown> = (record: PlainObject) => T;
5
+ /** Mutator function: transforms a field value before writing to DB. */
6
+ type MutatorFn<T = unknown> = (value: T, record: PlainObject) => unknown;
7
+ /** Map of field names to accessor functions. */
8
+ type AccessorDefinitions = Record<string, AccessorFn>;
9
+ /** Map of field names to mutator functions. */
10
+ type MutatorDefinitions = Record<string, MutatorFn>;
11
+
12
+ type FieldKey<TRecord extends PlainObject> = keyof TRecord & string;
13
+ /** Comparison operators supported by the QueryBuilder. */
14
+ type WhereOperator = '=' | '!=' | '>' | '<' | '>=' | '<=' | 'like' | 'in' | 'not in' | 'is null' | 'is not null';
15
+ /** A single field-level condition. */
16
+ interface SimpleCondition {
17
+ type: 'simple';
18
+ field: string;
19
+ operator: WhereOperator;
20
+ value: unknown;
21
+ }
22
+ /** A group of conditions joined by AND or OR. */
23
+ interface GroupCondition {
24
+ type: 'group';
25
+ boolean: 'and' | 'or';
26
+ conditions: WhereCondition[];
27
+ }
28
+ /** A where condition - either simple or grouped. */
29
+ type WhereCondition = SimpleCondition | GroupCondition;
30
+ /** Options carried by the QueryBuilder for query execution. */
31
+ interface QueryBuilderOptions {
32
+ orderBy: Array<{
33
+ column: string;
34
+ direction: OrderDirection;
35
+ }>;
36
+ limitValue?: number;
37
+ offsetValue?: number;
38
+ selectFields?: readonly string[];
39
+ trx?: unknown;
40
+ }
41
+ /**
42
+ * Fluent query builder for the Guren ORM.
43
+ *
44
+ * Provides a chainable API for constructing database queries with
45
+ * support for complex where conditions, ordering, pagination, and more.
46
+ *
47
+ * Implements the thenable pattern so it can be directly awaited,
48
+ * resolving to the result of `get()`.
49
+ *
50
+ * @example
51
+ * // Fluent chaining
52
+ * const posts = await Post.where('status', 'published')
53
+ * .where('views', '>', 100)
54
+ * .orderBy('createdAt', 'desc')
55
+ * .limit(10)
56
+ * .get()
57
+ *
58
+ * // Thenable - await directly
59
+ * const active = await User.where('active', true)
60
+ *
61
+ * // Pagination
62
+ * const page = await Post.where('status', 'published').paginate(1, 20)
63
+ */
64
+ declare class QueryBuilder<TRecord extends PlainObject = PlainObject, TResult extends PlainObject = TRecord> {
65
+ private conditions;
66
+ private options;
67
+ private modelClass;
68
+ private table;
69
+ private adapter;
70
+ private eagerLoad;
71
+ private eagerLoadConstraints;
72
+ constructor(modelClass: typeof Model, options?: {
73
+ trx?: unknown;
74
+ });
75
+ /**
76
+ * Add a where condition (AND).
77
+ *
78
+ * Supports three calling signatures:
79
+ * - `where(field, value)` - equality check
80
+ * - `where(field, operator, value)` - comparison
81
+ * - `where(object)` - multiple equality conditions
82
+ */
83
+ where<TKey extends FieldKey<TRecord>>(field: TKey, value: TRecord[TKey]): this;
84
+ where<TKey extends FieldKey<TRecord>>(field: TKey, operator: WhereOperator, value: unknown): this;
85
+ where(conditions: Partial<Record<FieldKey<TRecord>, unknown>>): this;
86
+ /**
87
+ * Add an OR where condition.
88
+ *
89
+ * Same overloads as `where()`, but joins with OR logic.
90
+ * Creates an OR group containing the new condition(s).
91
+ */
92
+ orWhere<TKey extends FieldKey<TRecord>>(field: TKey, value: TRecord[TKey]): this;
93
+ orWhere<TKey extends FieldKey<TRecord>>(field: TKey, operator: WhereOperator, value: unknown): this;
94
+ orWhere(conditions: Partial<Record<FieldKey<TRecord>, unknown>>): this;
95
+ /**
96
+ * Add a WHERE NULL condition.
97
+ * @param field - Column to check for NULL
98
+ */
99
+ whereNull(field: FieldKey<TRecord>): this;
100
+ /**
101
+ * Add a WHERE NOT NULL condition.
102
+ * @param field - Column to check for NOT NULL
103
+ */
104
+ whereNotNull(field: FieldKey<TRecord>): this;
105
+ /**
106
+ * Add a WHERE IN condition.
107
+ * @param field - Column to check
108
+ * @param values - Array of values to match against
109
+ */
110
+ whereIn<TKey extends FieldKey<TRecord>>(field: TKey, values: readonly TRecord[TKey][]): this;
111
+ /**
112
+ * Add a WHERE NOT IN condition.
113
+ * @param field - Column to check
114
+ * @param values - Array of values to exclude
115
+ */
116
+ whereNotIn<TKey extends FieldKey<TRecord>>(field: TKey, values: readonly TRecord[TKey][]): this;
117
+ /**
118
+ * Add an ORDER BY clause. Can be called multiple times to sort by multiple columns.
119
+ * @param field - Column to sort by
120
+ * @param direction - Sort direction (default: 'asc')
121
+ */
122
+ orderBy(field: FieldKey<TRecord>, direction?: OrderDirection): this;
123
+ /**
124
+ * Set the maximum number of records to return.
125
+ * @param n - Maximum record count
126
+ */
127
+ limit(n: number): this;
128
+ /**
129
+ * Set the number of records to skip.
130
+ * @param n - Number of records to skip
131
+ */
132
+ offset(n: number): this;
133
+ /**
134
+ * Limit the columns returned in the result.
135
+ * @param fields - Column names to select
136
+ */
137
+ select<TKey extends FieldKey<TRecord>>(...fields: readonly TKey[]): QueryBuilder<TRecord, Pick<TRecord, TKey>>;
138
+ /**
139
+ * Apply a named query scope defined on the model.
140
+ *
141
+ * @param name - The scope name
142
+ * @returns this (for chaining)
143
+ *
144
+ * @example
145
+ * const results = await Post.where('author', 'John')
146
+ * .scope('published')
147
+ * .scope('popular')
148
+ * .get()
149
+ */
150
+ scope(name: string): this;
151
+ /**
152
+ * Eager-load relationships on query results.
153
+ *
154
+ * Supports string names, arrays, dot notation for nested relations,
155
+ * and constraint callbacks.
156
+ *
157
+ * @example
158
+ * // Simple
159
+ * await User.where('active', true).with('posts').get()
160
+ *
161
+ * // Multiple
162
+ * await User.where('active', true).with('posts', 'comments').get()
163
+ *
164
+ * // Nested (dot notation)
165
+ * await User.where('active', true).with('posts.comments').get()
166
+ */
167
+ with(...relations: (string | Record<string, (q: QueryBuilder<any>) => void>)[]): this;
168
+ /**
169
+ * Execute the query and return all matching records.
170
+ * @returns Array of matching records
171
+ */
172
+ get(): Promise<TResult[]>;
173
+ /**
174
+ * Execute the query and return the first matching record.
175
+ * @returns The first record or null
176
+ */
177
+ first(): Promise<TResult | null>;
178
+ /**
179
+ * Execute the query and return the first matching record, or throw.
180
+ * @returns The first record
181
+ * @throws Error if no record matches
182
+ */
183
+ firstOrFail(): Promise<TResult>;
184
+ /**
185
+ * Count the number of records matching the current conditions.
186
+ * @returns The count of matching records
187
+ */
188
+ count(): Promise<number>;
189
+ /**
190
+ * Paginate the query results.
191
+ * @param page - Page number (1-based, default: 1)
192
+ * @param perPage - Records per page (default: 15)
193
+ * @returns Paginated result with data and metadata
194
+ */
195
+ paginate(page?: number, perPage?: number): Promise<PaginatedResult<TResult>>;
196
+ /**
197
+ * Bulk update records matching the current conditions.
198
+ * @param data - Data to set on matching records
199
+ * @returns The updated record (adapter-dependent)
200
+ */
201
+ update(data: PlainObject): Promise<TRecord>;
202
+ /**
203
+ * Bulk delete records matching the current conditions.
204
+ * @returns Number of deleted records (adapter-dependent)
205
+ */
206
+ delete(): Promise<number | PlainObject | void>;
207
+ /**
208
+ * Makes QueryBuilder a thenable so it can be directly awaited.
209
+ * Resolves to the result of `get()`.
210
+ */
211
+ then<TResult1 = TResult[], TResult2 = never>(onfulfilled?: ((value: TResult[]) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
212
+ /**
213
+ * Catch handler for the thenable interface.
214
+ */
215
+ catch<TCatch = never>(onrejected?: ((reason: unknown) => TCatch | PromiseLike<TCatch>) | null): Promise<TResult[] | TCatch>;
216
+ /** Get the internal conditions (used by adapters). */
217
+ getConditions(): WhereCondition[];
218
+ /** Get the internal query options (used by adapters). */
219
+ getOptions(): QueryBuilderOptions;
220
+ private addSimpleCondition;
221
+ private executeQuery;
222
+ /**
223
+ * Attempt to convert the current conditions to a simple WhereClause
224
+ * for backward compatibility with basic adapters.
225
+ * Returns null if conditions are too complex.
226
+ */
227
+ private toSimpleWhereClause;
228
+ /**
229
+ * Load eager relations onto fetched results.
230
+ * Supports dot notation for nested relations (e.g., 'posts.comments').
231
+ */
232
+ private readonly loadEagerRelations;
233
+ }
234
+
235
+ /** A named global scope function. */
236
+ type ScopeFunction = (q: QueryBuilder<any>) => QueryBuilder<any>;
237
+ /**
238
+ * Registry for named global scopes on a model.
239
+ *
240
+ * Supports adding, removing, and applying multiple named scopes.
241
+ * Used internally by Model to manage global query constraints.
242
+ */
243
+ declare class GlobalScopeRegistry {
244
+ private scopes;
245
+ add(name: string, fn: ScopeFunction): void;
246
+ remove(name: string): void;
247
+ has(name: string): boolean;
248
+ names(): string[];
249
+ /** Apply all scopes (or all except excluded) to a query builder. */
250
+ apply<T extends PlainObject>(builder: QueryBuilder<T>, except?: string[]): QueryBuilder<T>;
251
+ clear(): void;
252
+ get size(): number;
253
+ }
254
+
255
+ /**
256
+ * Model lifecycle hook names.
257
+ *
258
+ * "Before" hooks (`creating`, `updating`, `deleting`, `saving`) fire before
259
+ * the database operation. If they return `false`, the operation is aborted.
260
+ *
261
+ * "After" hooks (`created`, `updated`, `deleted`, `saved`) fire after the
262
+ * database operation completes.
263
+ *
264
+ * `saving`/`saved` fire for both create and update operations.
265
+ */
266
+ type HookName = 'creating' | 'created' | 'updating' | 'updated' | 'deleting' | 'deleted' | 'saving' | 'saved';
267
+ /**
268
+ * Callback signature for model lifecycle hooks.
269
+ *
270
+ * @param data - The record data being operated on
271
+ * @returns void for after-hooks. Returning `false` from a before-hook aborts the operation.
272
+ */
273
+ type HookCallback<T = Record<string, unknown>> = (data: T) => void | Promise<void> | false | Promise<false>;
274
+ /**
275
+ * Map of hook names to their callbacks.
276
+ * All hooks are optional.
277
+ */
278
+ type ModelHooks = {
279
+ [K in HookName]?: HookCallback;
280
+ };
281
+
282
+ /**
283
+ * Base interface for model observers.
284
+ *
285
+ * Observers allow extracting lifecycle hook logic into dedicated classes.
286
+ * Each method corresponds to a model lifecycle event and is optional.
287
+ *
288
+ * @example
289
+ * class UserObserver implements ModelObserver {
290
+ * async creating(data) { data.slug = slugify(data.name) }
291
+ * async created(data) { await sendWelcomeEmail(data) }
292
+ * }
293
+ *
294
+ * User.observe(UserObserver)
295
+ */
296
+ interface ModelObserver {
297
+ creating?(data: PlainObject): void | Promise<void> | false | Promise<false>;
298
+ created?(data: PlainObject): void | Promise<void>;
299
+ updating?(data: PlainObject): void | Promise<void> | false | Promise<false>;
300
+ updated?(data: PlainObject): void | Promise<void>;
301
+ deleting?(data: PlainObject): void | Promise<void> | false | Promise<false>;
302
+ deleted?(data: PlainObject): void | Promise<void>;
303
+ saving?(data: PlainObject): void | Promise<void> | false | Promise<false>;
304
+ saved?(data: PlainObject): void | Promise<void>;
305
+ }
306
+ type ModelObserverConstructor = new () => ModelObserver;
307
+
308
+ /** Generic plain object type used throughout the ORM. */
309
+ type PlainObject = Record<string, unknown>;
310
+ type RelationShape = Record<string, unknown>;
311
+ /** Supported cast types for attribute casting. */
312
+ type CastType = 'json' | 'date' | 'boolean' | 'number' | 'string';
313
+ /**
314
+ * Value type for where clause conditions.
315
+ * Supports single values, arrays (for IN queries), or null.
316
+ */
317
+ type WhereValue<Value> = Value | readonly Value[] | null;
318
+ /**
319
+ * Where clause for filtering records.
320
+ * Supports equality and IN (array) queries.
321
+ *
322
+ * @example
323
+ * // Single value (equality)
324
+ * { status: 'active' }
325
+ *
326
+ * // Array value (IN query)
327
+ * { id: [1, 2, 3] }
328
+ *
329
+ * // Multiple conditions (AND)
330
+ * { status: 'active', role: 'admin' }
331
+ */
332
+ type WhereClause<TRecord extends PlainObject = PlainObject> = Partial<{
333
+ [K in keyof TRecord & string]?: WhereValue<TRecord[K]>;
334
+ }>;
335
+ /** Sort direction for ordering queries. */
336
+ type OrderDirection = 'asc' | 'desc';
337
+ /** Normalized order definition with column and direction. */
338
+ type OrderDefinition<TRecord extends PlainObject = PlainObject> = {
339
+ column: keyof TRecord & string;
340
+ direction: OrderDirection;
341
+ };
342
+ /**
343
+ * Flexible order expression input.
344
+ * @example
345
+ * 'createdAt' // Column name (ascending)
346
+ * ['createdAt', 'desc'] // Tuple [column, direction]
347
+ * { column: 'createdAt', direction: 'desc' } // Object form
348
+ */
349
+ type OrderExpression<TRecord extends PlainObject = PlainObject> = (keyof TRecord & string) | readonly [keyof TRecord & string, OrderDirection] | {
350
+ column: keyof TRecord & string;
351
+ direction?: OrderDirection;
352
+ };
353
+ /** Input for orderBy - single expression or array of expressions. */
354
+ type OrderByInput<TRecord extends PlainObject = PlainObject> = OrderExpression<TRecord> | readonly OrderExpression<TRecord>[];
355
+ /** Normalized array of order definitions. */
356
+ type OrderByClause<TRecord extends PlainObject = PlainObject> = readonly OrderDefinition<TRecord>[];
357
+ /** Options for findMany queries. */
358
+ interface FindManyOptions<TRecord extends PlainObject = PlainObject> {
359
+ /** Filter conditions */
360
+ where?: WhereClause<TRecord>;
361
+ /** Sort order */
362
+ orderBy?: OrderByClause<TRecord>;
363
+ /** Maximum number of records to return */
364
+ limit?: number;
365
+ /** Number of records to skip */
366
+ offset?: number;
367
+ }
368
+ /** Options for paginated queries. */
369
+ interface PaginateOptions<TRecord extends PlainObject = PlainObject> {
370
+ /** Page number (1-based, default: 1) */
371
+ page?: number;
372
+ /** Records per page (default: 15) */
373
+ perPage?: number;
374
+ /** Filter conditions */
375
+ where?: WhereClause<TRecord>;
376
+ /** Sort order */
377
+ orderBy?: OrderByInput<TRecord>;
378
+ }
379
+ /** Pagination metadata returned with paginated results. */
380
+ interface PaginationMeta {
381
+ /** Total number of records matching the query */
382
+ total: number;
383
+ /** Number of records per page */
384
+ perPage: number;
385
+ /** Current page number (1-based) */
386
+ currentPage: number;
387
+ /** Total number of pages */
388
+ totalPages: number;
389
+ /** Whether there are more pages after this one */
390
+ hasMore: boolean;
391
+ /** Index of first record on this page (1-based) */
392
+ from: number;
393
+ /** Index of last record on this page */
394
+ to: number;
395
+ }
396
+ /** Result of a paginated query. */
397
+ interface PaginatedResult<TRecord extends PlainObject = PlainObject> {
398
+ /** Records for the current page */
399
+ data: TRecord[];
400
+ /** Pagination metadata */
401
+ meta: PaginationMeta;
402
+ }
403
+ /**
404
+ * Interface for ORM adapters that power the Model class.
405
+ * The default adapter is DrizzleAdapter.
406
+ */
407
+ interface ORMAdapter {
408
+ /** Run operations in a database transaction. */
409
+ transaction?<TResult>(callback: (trx: unknown) => Promise<TResult>): Promise<TResult>;
410
+ /** Find multiple records with optional filtering, ordering, and pagination. */
411
+ findMany<TRecord extends PlainObject = PlainObject>(table: unknown, options?: FindManyOptions<TRecord>, queryOptions?: AdapterQueryOptions): Promise<TRecord[]>;
412
+ /** Find a single record by unique criteria. */
413
+ findUnique<TRecord extends PlainObject = PlainObject>(table: unknown, where: WhereClause<TRecord>, queryOptions?: AdapterQueryOptions): Promise<TRecord | null>;
414
+ /** Create a new record. */
415
+ create<TRecord extends PlainObject = PlainObject>(table: unknown, data: PlainObject, writeOptions?: AdapterQueryOptions): Promise<TRecord>;
416
+ /** Update records matching criteria. */
417
+ update?<TRecord extends PlainObject = PlainObject>(table: unknown, where: WhereClause<TRecord>, data: PlainObject, writeOptions?: AdapterQueryOptions): Promise<TRecord>;
418
+ /** Delete records matching criteria. */
419
+ delete?<TRecord extends PlainObject = PlainObject>(table: unknown, where: WhereClause<TRecord>, writeOptions?: AdapterQueryOptions): Promise<number | PlainObject | void>;
420
+ /** Count records matching criteria. */
421
+ count?<TRecord extends PlainObject = PlainObject>(table: unknown, where?: WhereClause<TRecord>, queryOptions?: AdapterQueryOptions): Promise<number>;
422
+ }
423
+ interface AdapterQueryOptions {
424
+ trx?: unknown;
425
+ }
426
+ type ModelWriteOptions = AdapterQueryOptions;
427
+ type ModelQueryOptions = AdapterQueryOptions;
428
+ type TransactionHandle = NonNullable<AdapterQueryOptions['trx']>;
429
+ type SelectFrom<TDatabase> = TDatabase extends {
430
+ select: (...args: any[]) => infer TSelect;
431
+ } ? TSelect extends {
432
+ from: (...args: any[]) => infer TResult;
433
+ } ? TResult : never : never;
434
+ /**
435
+ * ActiveRecord-style base class for database models.
436
+ *
437
+ * Provides a Laravel Eloquent-like API for database operations including
438
+ * CRUD, querying, pagination, and eager-loading of relationships.
439
+ *
440
+ * @example
441
+ * // Define a model
442
+ * class User extends Model<UserRecord> {
443
+ * static override table = users // Drizzle table
444
+ * static override readonly recordType = {} as UserRecord
445
+ * }
446
+ *
447
+ * // Query records
448
+ * const allUsers = await User.all()
449
+ * const user = await User.find(1)
450
+ * const activeUsers = await User.where({ status: 'active' })
451
+ *
452
+ * // Create and update
453
+ * const newUser = await User.create({ name: 'John', email: 'john@example.com' })
454
+ * await User.update({ id: 1 }, { name: 'Jane' })
455
+ *
456
+ * // Pagination
457
+ * const page = await User.paginate({ page: 1, perPage: 10 })
458
+ *
459
+ * // Relationships
460
+ * const usersWithPosts = await User.with('posts')
461
+ */
462
+ declare abstract class Model<TRecord extends PlainObject = PlainObject> {
463
+ /** The ORM adapter used for database operations. */
464
+ protected static ormAdapter: ORMAdapter;
465
+ /** The database table (e.g., Drizzle table schema). */
466
+ protected static table: unknown;
467
+ /** Type marker for TypeScript inference. Define as `{} as YourRecordType`. */
468
+ static readonly recordType: unknown;
469
+ /** Type marker for insert/update payload inference. Define as `{} as typeof table.$inferInsert`. */
470
+ static readonly createType: unknown;
471
+ protected static relationDefinitions?: Map<string, RelationDefinition>;
472
+ /** Type marker for relation types. Define relation types here for type inference. */
473
+ static relationTypes: RelationShape;
474
+ /**
475
+ * Named query scopes for reusable query constraints.
476
+ *
477
+ * @example
478
+ * class Post extends Model<PostRecord> {
479
+ * static scopes = {
480
+ * published: (q: QueryBuilder<PostRecord>) => q.where('status', 'published'),
481
+ * popular: (q: QueryBuilder<PostRecord>) => q.where('views', '>', 1000),
482
+ * }
483
+ * }
484
+ * // Usage: Post.scope('published').scope('popular').get()
485
+ */
486
+ static scopes?: Record<string, (q: QueryBuilder<any>) => QueryBuilder<any>>;
487
+ /**
488
+ * Default scope applied to all queries on this model.
489
+ * Override this to automatically filter queries (e.g., soft deletes).
490
+ *
491
+ * @example
492
+ * static defaultScope = (q: QueryBuilder<any>) => q.whereNull('deletedAt')
493
+ */
494
+ static defaultScope?: (q: QueryBuilder<any>) => QueryBuilder<any>;
495
+ /**
496
+ * Model lifecycle hooks that fire during create, update, and delete operations.
497
+ *
498
+ * @example
499
+ * class User extends Model<UserRecord> {
500
+ * static hooks: ModelHooks = {
501
+ * creating: async (data) => { data.password = await hash(data.password as string) },
502
+ * created: async (data) => { console.log('User created:', data) },
503
+ * }
504
+ * }
505
+ */
506
+ static hooks?: ModelHooks;
507
+ /**
508
+ * Attribute casting definitions for automatic type conversion.
509
+ *
510
+ * Casts are applied when reading records from the database and when
511
+ * writing records to the database.
512
+ *
513
+ * @example
514
+ * class Post extends Model<PostRecord> {
515
+ * static casts = {
516
+ * metadata: 'json',
517
+ * publishedAt: 'date',
518
+ * isActive: 'boolean',
519
+ * viewCount: 'number',
520
+ * }
521
+ * }
522
+ */
523
+ static casts?: Record<string, CastType>;
524
+ /**
525
+ * Whitelist of fields allowed for mass assignment.
526
+ * If set, only these fields will be accepted in `create()` and `update()`.
527
+ *
528
+ * @example
529
+ * class User extends Model<UserRecord> {
530
+ * static fillable = ['name', 'email', 'password']
531
+ * }
532
+ */
533
+ static fillable?: string[];
534
+ /**
535
+ * Blacklist of fields excluded from mass assignment.
536
+ * Defaults to `['id']`. Ignored if `fillable` is set.
537
+ *
538
+ * @example
539
+ * class Post extends Model<PostRecord> {
540
+ * static guarded = ['id', 'createdAt']
541
+ * }
542
+ */
543
+ static guarded?: string[];
544
+ /**
545
+ * Accessor functions for computed/virtual attributes.
546
+ * Applied after reading records from the database.
547
+ *
548
+ * @example
549
+ * class User extends Model<UserRecord> {
550
+ * static accessors = {
551
+ * fullName: (record) => `${record.firstName} ${record.lastName}`,
552
+ * }
553
+ * }
554
+ */
555
+ static accessors?: AccessorDefinitions;
556
+ /**
557
+ * Mutator functions for transforming attributes before persistence.
558
+ *
559
+ * @example
560
+ * class User extends Model<UserRecord> {
561
+ * static mutators = {
562
+ * email: (value) => String(value).toLowerCase(),
563
+ * }
564
+ * }
565
+ */
566
+ static mutators?: MutatorDefinitions;
567
+ /**
568
+ * Fields to exclude from serialization output.
569
+ *
570
+ * @example
571
+ * class User extends Model<UserRecord> {
572
+ * static hidden = ['passwordHash', 'rememberToken']
573
+ * }
574
+ */
575
+ static hidden?: string[];
576
+ /**
577
+ * Whitelist of fields to include in serialization output.
578
+ * When set, only these fields appear. Takes precedence over `hidden`.
579
+ */
580
+ static visible?: string[];
581
+ /**
582
+ * Virtual accessor attributes to include in serialization output.
583
+ *
584
+ * @example
585
+ * class User extends Model<UserRecord> {
586
+ * static appends = ['fullName']
587
+ * static accessors = { fullName: (r) => `${r.firstName} ${r.lastName}` }
588
+ * }
589
+ */
590
+ static appends?: string[];
591
+ /** Registered model observers. */
592
+ protected static observers?: ModelObserver[];
593
+ /** Named global scopes registry. */
594
+ protected static globalScopeRegistry?: GlobalScopeRegistry;
595
+ /**
596
+ * Set a custom ORM adapter for this model.
597
+ * @param adapter - The adapter to use
598
+ */
599
+ static useAdapter(adapter: ORMAdapter): void;
600
+ /**
601
+ * Get the current ORM adapter.
602
+ * @returns The configured adapter
603
+ */
604
+ static getAdapter(): ORMAdapter;
605
+ /**
606
+ * Run operations inside a database transaction.
607
+ *
608
+ * @example
609
+ * await User.transaction(async (trx) => {
610
+ * const user = await User.create({ name: 'John' }, { trx })
611
+ * await Profile.create({ userId: user.id }, { trx })
612
+ * })
613
+ */
614
+ static transaction<T extends typeof Model, TResult>(this: T, callback: (trx: TransactionHandle, scope: TransactionModelScope<T>) => Promise<TResult>): Promise<TResult>;
615
+ /**
616
+ * Create a transaction-bound model scope that automatically forwards `trx`
617
+ * to query and write operations.
618
+ *
619
+ * @example
620
+ * await User.transaction(async (trx, txUser) => {
621
+ * await txUser.create({ name: 'Shinji' })
622
+ * await txUser.update({ id: 1 }, { name: 'Ikari' })
623
+ * })
624
+ */
625
+ static inTransaction<T extends typeof Model>(this: T, trx: TransactionHandle): TransactionModelScope<T>;
626
+ /**
627
+ * Register a model observer class.
628
+ *
629
+ * @example
630
+ * User.observe(UserObserver)
631
+ */
632
+ static observe(ObserverClass: ModelObserverConstructor): void;
633
+ /** Clear all registered observers. */
634
+ static clearObservers(): void;
635
+ protected static getGlobalScopes(): GlobalScopeRegistry;
636
+ /**
637
+ * Register a named global scope.
638
+ *
639
+ * @example
640
+ * User.addGlobalScope('active', (q) => q.where('active', true))
641
+ */
642
+ static addGlobalScope(name: string, fn: ScopeFunction): void;
643
+ /** Remove a named global scope. */
644
+ static removeGlobalScope(name: string): void;
645
+ /**
646
+ * Start a query excluding specific global scope(s).
647
+ *
648
+ * @example
649
+ * const all = await User.withoutGlobalScope('active').get()
650
+ */
651
+ static withoutGlobalScope<T extends typeof Model>(this: T, ...names: string[]): QueryBuilder<TRecordFor<T>>;
652
+ /**
653
+ * Start a query with no global scopes applied (also skips defaultScope).
654
+ *
655
+ * @example
656
+ * const all = await User.withoutGlobalScopes().get()
657
+ */
658
+ static withoutGlobalScopes<T extends typeof Model>(this: T): QueryBuilder<TRecordFor<T>>;
659
+ /**
660
+ * Serialize a record for API/JSON output.
661
+ * Applies hidden/visible filtering, accessors, and appends.
662
+ *
663
+ * @example
664
+ * const json = User.serialize(user)
665
+ */
666
+ static serialize<T extends typeof Model>(this: T, record: TRecordFor<T>): PlainObject;
667
+ /**
668
+ * Serialize an array of records.
669
+ *
670
+ * @example
671
+ * const json = User.serializeMany(users)
672
+ */
673
+ static serializeMany<T extends typeof Model>(this: T, records: TRecordFor<T>[]): PlainObject[];
674
+ /**
675
+ * Apply attribute casts to a record read from the database.
676
+ *
677
+ * @param record - The raw record from the database
678
+ * @returns The record with cast attributes applied
679
+ */
680
+ static applyCasts<T extends PlainObject>(record: T): T;
681
+ /**
682
+ * Apply all read-time transforms: casts then accessors.
683
+ * Used internally after fetching records from the database.
684
+ */
685
+ protected static applyReadTransforms<T extends PlainObject>(record: T): T;
686
+ /**
687
+ * Filter input data based on mass assignment protection rules.
688
+ *
689
+ * If `fillable` is defined, only fields listed in `fillable` are kept.
690
+ * Otherwise, fields listed in `guarded` (default: `['id']`) are removed.
691
+ *
692
+ * @param data - The input data to filter
693
+ * @returns Filtered data safe for mass assignment
694
+ */
695
+ static filterFillable(data: PlainObject): PlainObject;
696
+ protected static preparePersistencePayload(data: PlainObject): Promise<PlainObject>;
697
+ protected static getRelationDefinitions(): Map<string, RelationDefinition>;
698
+ /** @internal */
699
+ static getRelationDefinition(name: string): RelationDefinition | undefined;
700
+ static resolveTable(): unknown;
701
+ /**
702
+ * Retrieve all records from the table.
703
+ *
704
+ * @returns Array of all records
705
+ *
706
+ * @example
707
+ * const users = await User.all()
708
+ */
709
+ static all<T extends typeof Model>(this: T, queryOptions?: ModelQueryOptions): Promise<Array<TRecordFor<T>>>;
710
+ /**
711
+ * Find a record by its primary key.
712
+ *
713
+ * @param id - The primary key value
714
+ * @param key - The primary key column name (default: 'id')
715
+ * @returns The record or null if not found
716
+ *
717
+ * @example
718
+ * const user = await User.find(1)
719
+ * const userByEmail = await User.find('john@example.com', 'email')
720
+ */
721
+ static find<T extends typeof Model>(this: T, id: TRecordFor<T>[keyof TRecordFor<T> & string], key?: keyof TRecordFor<T> & string, queryOptions?: ModelQueryOptions): Promise<TRecordFor<T> | null>;
722
+ /**
723
+ * Find a record by primary key or throw an error.
724
+ *
725
+ * @param id - The primary key value
726
+ * @param key - The primary key column name (default: 'id')
727
+ * @returns The record
728
+ * @throws Error if record not found
729
+ *
730
+ * @example
731
+ * const user = await User.findOrFail(1) // Throws if not found
732
+ */
733
+ static findOrFail<T extends typeof Model>(this: T, id: TRecordFor<T>[keyof TRecordFor<T> & string], key?: keyof TRecordFor<T> & string, queryOptions?: ModelQueryOptions): Promise<TRecordFor<T>>;
734
+ /**
735
+ * Find a record by primary key with eager-loaded relations.
736
+ *
737
+ * @param id - The primary key value
738
+ * @param relations - Relation name(s) to eager load
739
+ * @param key - The primary key column name (default: 'id')
740
+ * @returns The record with loaded relations, or null if not found
741
+ *
742
+ * @example
743
+ * const post = await Post.findWith(1, 'author')
744
+ * const post = await Post.findWith(1, ['author', 'tags'])
745
+ */
746
+ static findWith<T extends typeof Model, K extends RelationKey<T>>(this: T, id: TRecordFor<T>[keyof TRecordFor<T> & string], relations: K | readonly K[], key?: keyof TRecordFor<T> & string): Promise<(TRecordFor<T> & RelationTypePick<T, K | readonly K[]>) | null>;
747
+ /**
748
+ * Find a record by primary key with eager-loaded relations, or throw.
749
+ *
750
+ * @param id - The primary key value
751
+ * @param relations - Relation name(s) to eager load
752
+ * @param key - The primary key column name (default: 'id')
753
+ * @returns The record with loaded relations
754
+ * @throws ModelNotFoundException if record not found
755
+ *
756
+ * @example
757
+ * const post = await Post.findWithOrFail(1, 'author')
758
+ * const post = await Post.findWithOrFail(1, ['author', 'tags'])
759
+ */
760
+ static findWithOrFail<T extends typeof Model, K extends RelationKey<T>>(this: T, id: TRecordFor<T>[keyof TRecordFor<T> & string], relations: K | readonly K[], key?: keyof TRecordFor<T> & string): Promise<TRecordFor<T> & RelationTypePick<T, K | readonly K[]>>;
761
+ /**
762
+ * Get the first record matching the conditions.
763
+ *
764
+ * @param where - Optional filter conditions
765
+ * @returns The first matching record or null
766
+ *
767
+ * @example
768
+ * const admin = await User.first({ role: 'admin' })
769
+ */
770
+ static first<T extends typeof Model>(this: T, where?: WhereClauseFor<T>, queryOptions?: ModelQueryOptions): Promise<TRecordFor<T> | null>;
771
+ /**
772
+ * Start a fluent query with where conditions.
773
+ *
774
+ * Returns a QueryBuilder that is thenable, so it can be directly awaited.
775
+ *
776
+ * @example
777
+ * // Object form - multiple equality conditions
778
+ * const activeUsers = await User.where({ status: 'active' })
779
+ *
780
+ * // Field + value - equality
781
+ * const admins = await User.where('role', 'admin')
782
+ *
783
+ * // Field + operator + value - comparison
784
+ * const recent = await Post.where('views', '>', 100)
785
+ *
786
+ * // Fluent chaining
787
+ * const posts = await Post.where('status', 'published')
788
+ * .where('views', '>', 100)
789
+ * .orderBy('createdAt', 'desc')
790
+ * .limit(10)
791
+ * .get()
792
+ */
793
+ static where<T extends typeof Model>(this: T, conditions: WhereClauseFor<T>): QueryBuilder<TRecordFor<T>>;
794
+ static where<T extends typeof Model>(this: T, field: keyof TRecordFor<T> & string, value: unknown): QueryBuilder<TRecordFor<T>>;
795
+ static where<T extends typeof Model>(this: T, field: keyof TRecordFor<T> & string, operator: WhereOperator, value: unknown): QueryBuilder<TRecordFor<T>>;
796
+ /**
797
+ * Start a fluent query with a WHERE NULL condition.
798
+ * @param field - Column to check for NULL
799
+ */
800
+ static whereNull<T extends typeof Model>(this: T, field: keyof TRecordFor<T> & string): QueryBuilder<TRecordFor<T>>;
801
+ /**
802
+ * Start a fluent query with a WHERE NOT NULL condition.
803
+ * @param field - Column to check for NOT NULL
804
+ */
805
+ static whereNotNull<T extends typeof Model>(this: T, field: keyof TRecordFor<T> & string): QueryBuilder<TRecordFor<T>>;
806
+ /**
807
+ * Start a fluent query with a WHERE IN condition.
808
+ * @param field - Column to check
809
+ * @param values - Array of values to match against
810
+ */
811
+ static whereIn<T extends typeof Model>(this: T, field: keyof TRecordFor<T> & string, values: readonly TRecordFor<T>[keyof TRecordFor<T> & string][]): QueryBuilder<TRecordFor<T>>;
812
+ /**
813
+ * Start a fluent query with a WHERE NOT IN condition.
814
+ * @param field - Column to check
815
+ * @param values - Array of values to exclude
816
+ */
817
+ static whereNotIn<T extends typeof Model>(this: T, field: keyof TRecordFor<T> & string, values: readonly TRecordFor<T>[keyof TRecordFor<T> & string][]): QueryBuilder<TRecordFor<T>>;
818
+ /**
819
+ * Start a fluent query with a typed field selection.
820
+ *
821
+ * @example
822
+ * const rows = await User.select('id', 'name')
823
+ * const first = await User.select('id').first()
824
+ */
825
+ static select<T extends typeof Model, Keys extends keyof TRecordFor<T> & string>(this: T, ...fields: readonly Keys[]): QueryBuilder<TRecordFor<T>, Pick<TRecordFor<T>, Keys>>;
826
+ /**
827
+ * Start a new QueryBuilder for fluent query construction.
828
+ *
829
+ * @returns A fresh QueryBuilder instance
830
+ *
831
+ * @example
832
+ * const results = await User.newQuery()
833
+ * .where('status', 'active')
834
+ * .orderBy('name')
835
+ * .limit(10)
836
+ * .get()
837
+ */
838
+ static newQuery<T extends typeof Model>(this: T, queryOptions?: ModelQueryOptions): QueryBuilder<TRecordFor<T>>;
839
+ /**
840
+ * Create a new QueryBuilder without applying any default scopes.
841
+ * Useful for querying soft-deleted records or bypassing global filters.
842
+ *
843
+ * @returns A fresh QueryBuilder instance with no scopes applied
844
+ */
845
+ static newQueryWithoutScopes<T extends typeof Model>(this: T, queryOptions?: ModelQueryOptions): QueryBuilder<TRecordFor<T>>;
846
+ /**
847
+ * Apply a named query scope.
848
+ *
849
+ * @param name - The scope name defined in `static scopes`
850
+ * @returns A QueryBuilder with the scope applied
851
+ *
852
+ * @example
853
+ * const published = await Post.scope('published').get()
854
+ * const popularPublished = await Post.scope('published').scope('popular').get()
855
+ */
856
+ static scope<T extends typeof Model>(this: T, name: string): QueryBuilder<TRecordFor<T>>;
857
+ /**
858
+ * Define a one-to-many relationship.
859
+ *
860
+ * @param name - Relation name (used in `with()` calls)
861
+ * @param related - The related model class
862
+ * @param foreignKey - Foreign key column on the related model
863
+ * @param localKey - Local key column on this model
864
+ *
865
+ * @example
866
+ * class User extends Model<UserRecord> {
867
+ * static {
868
+ * this.hasMany('posts', Post, 'userId', 'id')
869
+ * }
870
+ * }
871
+ * // Later: User.with('posts')
872
+ */
873
+ static hasMany<This extends typeof Model, Related extends typeof Model, ForeignKey extends keyof TRecordFor<Related> & string, LocalKey extends keyof TRecordFor<This> & string, Name extends RelationKeyOrString<This>>(this: This, name: Name, related: Related | (() => Related | Promise<Related>), foreignKey: ForeignKey, localKey: LocalKey): void;
874
+ /**
875
+ * Define a many-to-one (inverse) relationship.
876
+ *
877
+ * @param name - Relation name (used in `with()` calls)
878
+ * @param related - The related model class
879
+ * @param foreignKey - Foreign key column on this model
880
+ * @param ownerKey - Primary key column on the related model
881
+ *
882
+ * @example
883
+ * class Post extends Model<PostRecord> {
884
+ * static {
885
+ * this.belongsTo('author', User, 'userId', 'id')
886
+ * }
887
+ * }
888
+ * // Later: Post.with('author')
889
+ */
890
+ static belongsTo<This extends typeof Model, Related extends typeof Model, ForeignKey extends keyof TRecordFor<This> & string, OwnerKey extends keyof TRecordFor<Related> & string, Name extends RelationKeyOrString<This>>(this: This, name: Name, related: Related | (() => Related | Promise<Related>), foreignKey: ForeignKey, ownerKey: OwnerKey): void;
891
+ /**
892
+ * Define a one-to-one relationship.
893
+ *
894
+ * @param name - Relation name (used in `with()` calls)
895
+ * @param related - The related model class
896
+ * @param foreignKey - Foreign key column on the related model
897
+ * @param localKey - Local key column on this model
898
+ *
899
+ * @example
900
+ * class User extends Model<UserRecord> {
901
+ * static {
902
+ * this.hasOne('profile', Profile, 'userId', 'id')
903
+ * }
904
+ * }
905
+ * // Later: User.with('profile')
906
+ */
907
+ static hasOne<This extends typeof Model, Related extends typeof Model, ForeignKey extends keyof TRecordFor<Related> & string, LocalKey extends keyof TRecordFor<This> & string, Name extends RelationKeyOrString<This>>(this: This, name: Name, related: Related | (() => Related | Promise<Related>), foreignKey: ForeignKey, localKey: LocalKey): void;
908
+ /**
909
+ * Define a many-to-many relationship via a pivot table.
910
+ *
911
+ * @param name - Relation name (used in `with()` calls)
912
+ * @param related - The related model class
913
+ * @param pivotTable - The pivot/junction table (e.g., Drizzle table schema)
914
+ * @param foreignPivotKey - Column on pivot table referencing this model
915
+ * @param relatedPivotKey - Column on pivot table referencing the related model
916
+ * @param parentKey - Local key on this model (default: 'id')
917
+ * @param relatedKey - Local key on the related model (default: 'id')
918
+ *
919
+ * @example
920
+ * class User extends Model<UserRecord> {
921
+ * static {
922
+ * this.belongsToMany('roles', Role, userRoles, 'userId', 'roleId', 'id', 'id')
923
+ * }
924
+ * }
925
+ * // Later: User.with('roles')
926
+ */
927
+ static belongsToMany<This extends typeof Model, Related extends typeof Model, Name extends RelationKeyOrString<This>>(this: This, name: Name, related: Related | (() => Related | Promise<Related>), pivotTable: unknown, foreignPivotKey: string, relatedPivotKey: string, parentKey?: string, relatedKey?: string): void;
928
+ /**
929
+ * Define a has-many-through relationship.
930
+ *
931
+ * @param name - Relation name (used in `with()` calls)
932
+ * @param related - The final related model class
933
+ * @param through - The intermediate model class
934
+ * @param firstKey - Foreign key on the intermediate model referencing this model
935
+ * @param secondKey - Foreign key on the related model referencing the intermediate model
936
+ * @param localKey - Local key on this model (default: 'id')
937
+ * @param secondLocalKey - Local key on the intermediate model (default: 'id')
938
+ *
939
+ * @example
940
+ * class Country extends Model<CountryRecord> {
941
+ * static {
942
+ * this.hasManyThrough('posts', Post, User, 'countryId', 'userId', 'id', 'id')
943
+ * }
944
+ * }
945
+ * // Later: Country.with('posts')
946
+ */
947
+ static hasManyThrough<This extends typeof Model, Related extends typeof Model, Through extends typeof Model, Name extends RelationKeyOrString<This>>(this: This, name: Name, related: Related | (() => Related | Promise<Related>), through: Through | (() => Through | Promise<Through>), firstKey: string, secondKey: string, localKey?: string, secondLocalKey?: string): void;
948
+ /**
949
+ * Map of type strings to model classes for polymorphic relationships.
950
+ *
951
+ * @example
952
+ * Model.morphMap = { Post, Video }
953
+ */
954
+ static morphMap?: Record<string, typeof Model>;
955
+ /**
956
+ * Define a one-to-many polymorphic relationship.
957
+ *
958
+ * @param name - Relation name
959
+ * @param related - The related model class
960
+ * @param morphName - Base name for the type/id columns (e.g. 'commentable' → commentableType + commentableId)
961
+ * @param localKey - Local key on this model (default: 'id')
962
+ *
963
+ * @example
964
+ * Post.morphMany('comments', Comment, 'commentable', 'id')
965
+ */
966
+ static morphMany<This extends typeof Model, Related extends typeof Model, Name extends RelationKeyOrString<This>>(this: This, name: Name, related: Related | (() => Related | Promise<Related>), morphName: string, localKey?: string): void;
967
+ /**
968
+ * Define the inverse of a polymorphic relationship.
969
+ *
970
+ * @param name - Relation name
971
+ * @param morphName - Base name for the type/id columns
972
+ *
973
+ * @example
974
+ * Comment.morphTo('commentable', 'commentable')
975
+ */
976
+ static morphTo<This extends typeof Model, Name extends RelationKeyOrString<This>>(this: This, name: Name, morphName: string): void;
977
+ /**
978
+ * Get records sorted by the specified order.
979
+ *
980
+ * @param order - Order expression(s)
981
+ * @param where - Optional filter conditions
982
+ * @returns Sorted array of records
983
+ *
984
+ * @example
985
+ * // Single column ascending
986
+ * await User.orderBy('createdAt')
987
+ *
988
+ * // Single column descending
989
+ * await User.orderBy(['createdAt', 'desc'])
990
+ *
991
+ * // Multiple columns
992
+ * await User.orderBy([['lastName', 'asc'], ['firstName', 'asc']])
993
+ *
994
+ * // With where clause
995
+ * await User.orderBy('name', { status: 'active' })
996
+ */
997
+ static orderBy<T extends typeof Model>(this: T, order: OrderByInput<TRecordFor<T>>, where?: WhereClauseFor<T>, queryOptions?: ModelQueryOptions): Promise<TRecordFor<T>[]>;
998
+ /**
999
+ * Get paginated records.
1000
+ *
1001
+ * @param options - Pagination options
1002
+ * @returns Paginated result with data and metadata
1003
+ *
1004
+ * @example
1005
+ * const result = await User.paginate({ page: 1, perPage: 10 })
1006
+ * // result.data - Array of users
1007
+ * // result.meta.total - Total count
1008
+ * // result.meta.hasMore - Whether there are more pages
1009
+ *
1010
+ * // With filtering and ordering
1011
+ * await User.paginate({
1012
+ * page: 2,
1013
+ * perPage: 20,
1014
+ * where: { status: 'active' },
1015
+ * orderBy: ['createdAt', 'desc']
1016
+ * })
1017
+ */
1018
+ static paginate<T extends typeof Model>(this: T, options?: PaginateOptions<TRecordFor<T>>, queryOptions?: ModelQueryOptions): Promise<PaginatedResult<TRecordFor<T>>>;
1019
+ /**
1020
+ * Paginate records with eager-loaded relationships.
1021
+ *
1022
+ * @param relations - Relation name(s) to load
1023
+ * @param options - Pagination options
1024
+ * @returns Paginated result with loaded relationships
1025
+ *
1026
+ * @example
1027
+ * const result = await User.withPaginate('posts', { page: 1, perPage: 10 })
1028
+ * // result.data - Users with their posts loaded
1029
+ * // result.meta - Pagination metadata
1030
+ */
1031
+ static withPaginate<T extends typeof Model, K extends RelationKey<T>>(this: T, relations: K | readonly K[], options?: PaginateOptions<TRecordFor<T>>): Promise<PaginatedResult<TRecordFor<T> & RelationTypePick<T, K | readonly K[]>>>;
1032
+ /**
1033
+ * Create a new record.
1034
+ *
1035
+ * @param data - Record data to insert
1036
+ * @returns The created record
1037
+ *
1038
+ * @example
1039
+ * const user = await User.create({
1040
+ * name: 'John Doe',
1041
+ * email: 'john@example.com'
1042
+ * })
1043
+ */
1044
+ static create<T extends typeof Model>(this: T, data: TCreateFor<T>, writeOptions?: ModelWriteOptions): Promise<TRecordFor<T>>;
1045
+ /**
1046
+ * Update records matching the conditions.
1047
+ *
1048
+ * @param where - Filter conditions to identify records
1049
+ * @param data - Data to update
1050
+ * @returns The updated record
1051
+ *
1052
+ * @example
1053
+ * await User.update({ id: 1 }, { name: 'Jane Doe' })
1054
+ */
1055
+ static update<T extends typeof Model>(this: T, where: WhereClauseFor<T>, data: Partial<TCreateFor<T>>, writeOptions?: ModelWriteOptions): Promise<TRecordFor<T>>;
1056
+ /**
1057
+ * Delete records matching the conditions.
1058
+ *
1059
+ * @param where - Filter conditions to identify records
1060
+ * @returns Number of deleted records or void depending on adapter
1061
+ *
1062
+ * @example
1063
+ * await User.delete({ id: 1 })
1064
+ * await User.delete({ status: 'inactive' })
1065
+ */
1066
+ static delete<T extends typeof Model>(this: T, where: WhereClauseFor<T>, writeOptions?: ModelWriteOptions): Promise<number | PlainObject | void>;
1067
+ /**
1068
+ * Get a raw Drizzle query builder for complex queries.
1069
+ *
1070
+ * @param db - Optional Drizzle database instance
1071
+ * @returns Drizzle query builder starting with `select().from(table)`
1072
+ *
1073
+ * @example
1074
+ * // Simple query
1075
+ * const users = await User.query(db)
1076
+ * .where(eq(users.status, 'active'))
1077
+ * .limit(10)
1078
+ *
1079
+ * // With joins
1080
+ * const usersWithPosts = await User.query(db)
1081
+ * .leftJoin(posts, eq(users.id, posts.userId))
1082
+ */
1083
+ static query<TDatabase extends {
1084
+ select: (...args: any[]) => any;
1085
+ } = {
1086
+ select: (...args: any[]) => any;
1087
+ }>(// eslint-disable-line @typescript-eslint/no-explicit-any
1088
+ this: typeof Model, db?: TDatabase): SelectFrom<TDatabase>;
1089
+ /**
1090
+ * Eager-load relationships on records.
1091
+ *
1092
+ * @param relations - Relation name(s) to load
1093
+ * @param where - Optional filter conditions
1094
+ * @returns Records with loaded relationships
1095
+ *
1096
+ * @example
1097
+ * // Single relation
1098
+ * const usersWithPosts = await User.with('posts')
1099
+ *
1100
+ * // Multiple relations
1101
+ * const usersWithAll = await User.with(['posts', 'comments'])
1102
+ *
1103
+ * // With filtering
1104
+ * const activeUsersWithPosts = await User.with('posts', { status: 'active' })
1105
+ */
1106
+ static with<T extends typeof Model, K extends RelationKey<T>>(this: T, relations: K | readonly K[], where?: WhereClauseFor<T>): Promise<Array<TRecordFor<T> & RelationTypePick<T, K | readonly K[]>>>;
1107
+ /** @internal Used by QueryBuilder for eager loading. */
1108
+ static loadRelationInto<T extends typeof Model>(this: T, records: Array<PlainObject>, relationName: string): Promise<void>;
1109
+ protected static loadHasMany(records: Array<PlainObject>, definition: HasManyRelationDefinition): Promise<void>;
1110
+ protected static loadHasOne(records: Array<PlainObject>, definition: HasOneRelationDefinition): Promise<void>;
1111
+ protected static loadBelongsTo(records: Array<PlainObject>, definition: BelongsToRelationDefinition): Promise<void>;
1112
+ protected static loadBelongsToMany(records: Array<PlainObject>, definition: BelongsToManyRelationDefinition): Promise<void>;
1113
+ protected static loadHasManyThrough(records: Array<PlainObject>, definition: HasManyThroughRelationDefinition): Promise<void>;
1114
+ protected static loadMorphMany(records: Array<PlainObject>, definition: MorphManyRelationDefinition): Promise<void>;
1115
+ protected static loadMorphTo(records: Array<PlainObject>, definition: MorphToRelationDefinition): Promise<void>;
1116
+ }
1117
+ type TRecordFor<T extends typeof Model> = T extends {
1118
+ recordType: infer R;
1119
+ } ? R extends PlainObject ? R : PlainObject : PlainObject;
1120
+ type TCreateFor<T extends typeof Model> = T extends {
1121
+ createType: infer R;
1122
+ } ? R extends PlainObject ? R : PlainObject : PlainObject;
1123
+ type WhereClauseFor<T extends typeof Model> = WhereClause<TRecordFor<T>>;
1124
+ type FieldFor<T extends typeof Model> = keyof TRecordFor<T> & string;
1125
+ type RelationTypesFor<T extends typeof Model> = T extends {
1126
+ relationTypes: infer R;
1127
+ } ? R extends RelationShape ? R : {} : {};
1128
+ type RelationKey<T extends typeof Model> = keyof RelationTypesFor<T> & string;
1129
+ type RelationKeyOrString<T extends typeof Model> = RelationKey<T> extends never ? string : RelationKey<T>;
1130
+ type RelationNameUnion<Names> = Names extends readonly (infer Items)[] ? Items : Names;
1131
+ type RelationTypePick<T extends typeof Model, Names> = RelationNameUnion<Names> extends infer Keys ? Keys extends string ? {
1132
+ [K in Keys & keyof RelationTypesFor<T>]: RelationTypesFor<T>[K];
1133
+ } : {} : {};
1134
+ interface TransactionModelScope<T extends typeof Model> {
1135
+ readonly trx: TransactionHandle;
1136
+ all(): Promise<TRecordFor<T>[]>;
1137
+ find(id: unknown): Promise<TRecordFor<T> | null>;
1138
+ findOrFail(id: unknown): Promise<TRecordFor<T>>;
1139
+ first(where?: WhereClauseFor<T>): Promise<TRecordFor<T> | null>;
1140
+ where(conditions: WhereClauseFor<T>): QueryBuilder<TRecordFor<T>>;
1141
+ where(field: FieldFor<T>, value: unknown): QueryBuilder<TRecordFor<T>>;
1142
+ where(field: FieldFor<T>, operator: WhereOperator, value: unknown): QueryBuilder<TRecordFor<T>>;
1143
+ newQuery(): QueryBuilder<TRecordFor<T>>;
1144
+ create(data: TCreateFor<T>): Promise<TRecordFor<T>>;
1145
+ update(where: WhereClauseFor<T>, data: Partial<TCreateFor<T>>): Promise<TRecordFor<T>>;
1146
+ delete(where: WhereClauseFor<T>): Promise<number | PlainObject | void>;
1147
+ paginate(options?: PaginateOptions<TRecordFor<T>>): Promise<PaginatedResult<TRecordFor<T>>>;
1148
+ }
1149
+ interface BaseRelationDefinition {
1150
+ type: 'hasMany' | 'hasOne' | 'belongsTo' | 'belongsToMany' | 'hasManyThrough' | 'morphMany' | 'morphTo';
1151
+ name: string;
1152
+ related: typeof Model | (() => typeof Model | Promise<typeof Model>);
1153
+ }
1154
+ interface HasManyRelationDefinition extends BaseRelationDefinition {
1155
+ type: 'hasMany';
1156
+ foreignKey: string;
1157
+ localKey: string;
1158
+ }
1159
+ interface HasOneRelationDefinition extends BaseRelationDefinition {
1160
+ type: 'hasOne';
1161
+ foreignKey: string;
1162
+ localKey: string;
1163
+ }
1164
+ interface BelongsToRelationDefinition extends BaseRelationDefinition {
1165
+ type: 'belongsTo';
1166
+ foreignKey: string;
1167
+ ownerKey: string;
1168
+ }
1169
+ interface BelongsToManyRelationDefinition extends BaseRelationDefinition {
1170
+ type: 'belongsToMany';
1171
+ pivotTable: unknown;
1172
+ foreignPivotKey: string;
1173
+ relatedPivotKey: string;
1174
+ parentKey: string;
1175
+ relatedKey: string;
1176
+ }
1177
+ interface HasManyThroughRelationDefinition extends BaseRelationDefinition {
1178
+ type: 'hasManyThrough';
1179
+ through: typeof Model | (() => typeof Model | Promise<typeof Model>);
1180
+ firstKey: string;
1181
+ secondKey: string;
1182
+ localKey: string;
1183
+ secondLocalKey: string;
1184
+ }
1185
+ type RelationDefinition = HasManyRelationDefinition | HasOneRelationDefinition | BelongsToRelationDefinition | BelongsToManyRelationDefinition | HasManyThroughRelationDefinition | MorphManyRelationDefinition | MorphToRelationDefinition;
1186
+ interface MorphManyRelationDefinition extends BaseRelationDefinition {
1187
+ type: 'morphMany';
1188
+ morphName: string;
1189
+ localKey: string;
1190
+ }
1191
+ interface MorphToRelationDefinition {
1192
+ type: 'morphTo';
1193
+ name: string;
1194
+ related: undefined;
1195
+ morphName: string;
1196
+ }
1197
+
1198
+ type SessionData = Record<string, unknown>;
1199
+ interface SessionStore {
1200
+ /**
1201
+ * Read a session by its opaque identifier.
1202
+ * Returns undefined when the session does not exist or has expired.
1203
+ */
1204
+ read(id: string): Promise<SessionData | undefined>;
1205
+ /**
1206
+ * Persist a session using upsert semantics for the given opaque identifier.
1207
+ */
1208
+ write(id: string, data: SessionData, ttlSeconds: number): Promise<void>;
1209
+ /**
1210
+ * Destroy a session. Implementations must treat repeated calls as safe.
1211
+ */
1212
+ destroy(id: string): Promise<void>;
1213
+ }
1214
+ declare class MemorySessionStore implements SessionStore {
1215
+ private readonly now;
1216
+ private readonly store;
1217
+ constructor(now?: () => number);
1218
+ read(id: string): Promise<SessionData | undefined>;
1219
+ write(id: string, data: SessionData, ttlSeconds: number): Promise<void>;
1220
+ destroy(id: string): Promise<void>;
1221
+ }
1222
+ interface SessionOptions {
1223
+ cookieName?: string;
1224
+ cookiePath?: string;
1225
+ cookieDomain?: string;
1226
+ cookieSecure?: boolean;
1227
+ cookieSameSite?: 'Strict' | 'Lax' | 'None';
1228
+ cookieHttpOnly?: boolean;
1229
+ cookieMaxAgeSeconds?: number;
1230
+ ttlSeconds?: number;
1231
+ store?: SessionStore;
1232
+ }
1233
+ interface Session {
1234
+ readonly id: string;
1235
+ readonly isNew: boolean;
1236
+ get<T = unknown>(key: string): T | undefined;
1237
+ set<T = unknown>(key: string, value: T): void;
1238
+ has(key: string): boolean;
1239
+ forget(key: string): void;
1240
+ flush(): void;
1241
+ all(): SessionData;
1242
+ regenerate(): void;
1243
+ invalidate(): void;
1244
+ flash(key: string, value: unknown): void;
1245
+ getFlash<T = unknown>(key: string): T | undefined;
1246
+ reflash(): void;
1247
+ keep(...keys: string[]): void;
1248
+ }
1249
+ interface CreateSessionMiddlewareOptions extends SessionOptions {
1250
+ }
1251
+ declare function createSessionMiddleware(options?: CreateSessionMiddlewareOptions): MiddlewareHandler;
1252
+ declare function getSessionFromContext<T extends Session = Session>(ctx: {
1253
+ get: (key: string) => unknown;
1254
+ }): T | undefined;
1255
+
1256
+ type AuthCredentials = Record<string, unknown>;
1257
+ interface Authenticatable {
1258
+ getAuthIdentifier(): unknown;
1259
+ getAuthPassword(): string | null | undefined;
1260
+ getRememberToken?(): string | null | undefined;
1261
+ setRememberToken?(token: string | null): void | Promise<void>;
1262
+ }
1263
+ interface Guard<User = Authenticatable> {
1264
+ check(): Promise<boolean>;
1265
+ guest(): Promise<boolean>;
1266
+ user<T = User>(): Promise<T | null>;
1267
+ id(): Promise<unknown>;
1268
+ login<T = User>(user: T, remember?: boolean): Promise<void>;
1269
+ logout(): Promise<void>;
1270
+ attempt(credentials: AuthCredentials, remember?: boolean): Promise<boolean>;
1271
+ validate(credentials: AuthCredentials): Promise<User | null>;
1272
+ session<T extends Session = Session>(): T | undefined;
1273
+ }
1274
+ interface UserProvider<User = Authenticatable> {
1275
+ retrieveById(identifier: unknown): Promise<User | null>;
1276
+ retrieveByCredentials(credentials: AuthCredentials): Promise<User | null>;
1277
+ validateCredentials(user: User, credentials: AuthCredentials): Promise<boolean>;
1278
+ getId(user: User): unknown;
1279
+ setRememberToken?(user: User, token: string | null): Promise<void> | void;
1280
+ getRememberToken?(user: User): Promise<string | null> | string | null;
1281
+ }
1282
+ interface GuardContext {
1283
+ ctx: Context;
1284
+ session: Session | undefined;
1285
+ manager: AuthManagerContract;
1286
+ }
1287
+ type GuardFactory<User = Authenticatable> = (context: GuardContext) => Guard<User>;
1288
+ interface ProviderFactory<User = Authenticatable> {
1289
+ (manager: AuthManagerContract): UserProvider<User>;
1290
+ }
1291
+ interface AuthManagerOptions {
1292
+ defaultGuard?: string;
1293
+ }
1294
+ interface AttachContextOptions {
1295
+ guard?: string;
1296
+ }
1297
+ interface AuthContext<User = Authenticatable> {
1298
+ check(): Promise<boolean>;
1299
+ guest(): Promise<boolean>;
1300
+ user<T = User>(): Promise<T | null>;
1301
+ userOrFail<T = User>(): Promise<T>;
1302
+ id(): Promise<unknown>;
1303
+ login<T = User>(user: T, remember?: boolean): Promise<void>;
1304
+ attempt(credentials: AuthCredentials, remember?: boolean): Promise<boolean>;
1305
+ logout(): Promise<void>;
1306
+ guard<T = User>(name?: string): Guard<T>;
1307
+ session<T extends Session = Session>(): T | undefined;
1308
+ }
1309
+ interface AuthManagerContract {
1310
+ registerGuard<User = Authenticatable>(name: string, factory: GuardFactory<User>): void;
1311
+ registerProvider<User = Authenticatable>(name: string, factory: ProviderFactory<User>): void;
1312
+ getProvider<User = Authenticatable>(name: string): UserProvider<User>;
1313
+ createGuard<User = Authenticatable>(name: string, context: GuardContext): Guard<User>;
1314
+ guardNames(): string[];
1315
+ setDefaultGuard(name: string): void;
1316
+ getDefaultGuard(): string;
1317
+ createAuthContext(ctx: Context, options?: AttachContextOptions): AuthContext;
1318
+ }
1319
+
1320
+ interface PasswordHasher {
1321
+ hash(plain: string): Promise<string>;
1322
+ verify(hashed: string, plain: string): Promise<boolean>;
1323
+ needsRehash?(hashed: string): boolean;
1324
+ }
1325
+
1326
+ declare abstract class BaseUserProvider<User extends Authenticatable = Authenticatable> implements UserProvider<User> {
1327
+ abstract retrieveById(identifier: unknown): Promise<User | null>;
1328
+ abstract retrieveByCredentials(credentials: AuthCredentials): Promise<User | null>;
1329
+ abstract validateCredentials(user: User, credentials: AuthCredentials): Promise<boolean>;
1330
+ abstract getId(user: User): unknown;
1331
+ setRememberToken(user: User, token: string | null): Promise<void>;
1332
+ getRememberToken(user: User): Promise<string | null>;
1333
+ }
1334
+
1335
+ interface ModelUserProviderOptions {
1336
+ idColumn?: string;
1337
+ usernameColumn?: string;
1338
+ passwordColumn?: string;
1339
+ rememberTokenColumn?: string;
1340
+ hasher?: PasswordHasher;
1341
+ credentialsPasswordField?: string;
1342
+ }
1343
+ declare class ModelUserProvider<User extends Authenticatable = Authenticatable> extends BaseUserProvider<User> {
1344
+ private readonly model;
1345
+ private readonly idColumn;
1346
+ private readonly usernameColumn;
1347
+ private readonly passwordColumn;
1348
+ private readonly rememberTokenColumn;
1349
+ private readonly hasher;
1350
+ private readonly credentialsPasswordField;
1351
+ constructor(model: typeof Model, options?: ModelUserProviderOptions);
1352
+ private cast;
1353
+ retrieveById(identifier: unknown): Promise<User | null>;
1354
+ retrieveByCredentials(credentials: AuthCredentials): Promise<User | null>;
1355
+ validateCredentials(user: User, credentials: AuthCredentials): Promise<boolean>;
1356
+ getId(user: User): unknown;
1357
+ setRememberToken(user: User, token: string | null): Promise<void>;
1358
+ getRememberToken(user: User): Promise<string | null>;
1359
+ }
1360
+
1361
+ declare class AuthManager implements AuthManagerContract {
1362
+ private readonly guards;
1363
+ private readonly providers;
1364
+ private defaultGuard;
1365
+ constructor(options?: AuthManagerOptions);
1366
+ registerGuard<User>(name: string, factory: GuardFactory<User>): void;
1367
+ registerProvider<User>(name: string, factory: ProviderFactory<User>): void;
1368
+ getProvider<User>(name: string): UserProvider<User>;
1369
+ createGuard<User>(name: string, context: GuardContext): Guard<User>;
1370
+ guardNames(): string[];
1371
+ setDefaultGuard(name: string): void;
1372
+ getDefaultGuard(): string;
1373
+ createAuthContext(ctx: Context, options?: AttachContextOptions): AuthContext;
1374
+ attempt(name: string, ctx: Context, credentials: AuthCredentials, remember?: boolean): Promise<boolean>;
1375
+ /**
1376
+ * Shorthand method to register a model-based authentication provider and session guard.
1377
+ * This simplifies the common case of authenticating users via a database model.
1378
+ *
1379
+ * @param model - The model class to use for user authentication
1380
+ * @param options - Options for the ModelUserProvider (partial, with defaults)
1381
+ * @param providerName - Name for the provider (defaults to 'users')
1382
+ * @param guardName - Name for the guard (defaults to 'web')
1383
+ */
1384
+ useModel(model: typeof Model<PlainObject>, options?: Partial<ModelUserProviderOptions>, providerName?: string, guardName?: string): void;
1385
+ }
1386
+
1387
+ interface OAuthProviderConfig {
1388
+ clientId: string;
1389
+ clientSecret: string;
1390
+ redirectUri: string;
1391
+ authorizeUrl: string;
1392
+ tokenUrl: string;
1393
+ userInfoUrl: string;
1394
+ scopes?: string[];
1395
+ tokenAuthMethod?: 'client_secret_post' | 'client_secret_basic';
1396
+ userInfoMethod?: 'GET' | 'POST';
1397
+ mapProfile?: (raw: Record<string, unknown>, token: OAuthTokenResult) => OAuthUserProfile;
1398
+ }
1399
+ interface OAuthTokenResult {
1400
+ accessToken: string;
1401
+ tokenType?: string;
1402
+ refreshToken?: string;
1403
+ expiresIn?: number;
1404
+ scope?: string;
1405
+ raw: Record<string, unknown>;
1406
+ }
1407
+ interface OAuthUserProfile {
1408
+ id: string;
1409
+ email?: string;
1410
+ name?: string;
1411
+ avatar?: string;
1412
+ token: OAuthTokenResult;
1413
+ raw: Record<string, unknown>;
1414
+ }
1415
+ interface OAuthStatePayload {
1416
+ provider: string;
1417
+ redirectTo?: string;
1418
+ expiresAt: Date;
1419
+ }
1420
+ interface OAuthStateStore {
1421
+ store(stateHash: string, payload: OAuthStatePayload): Promise<void>;
1422
+ find(stateHash: string): Promise<OAuthStatePayload | null>;
1423
+ delete(stateHash: string): Promise<void>;
1424
+ }
1425
+ interface OAuthStateConfig {
1426
+ expiresIn?: number;
1427
+ stateLength?: number;
1428
+ hashAlgorithm?: 'sha256' | 'sha512';
1429
+ }
1430
+ interface OAuthAuthorizeOptions {
1431
+ scope?: string[];
1432
+ redirectTo?: string;
1433
+ state?: string;
1434
+ extraParams?: Record<string, string>;
1435
+ }
1436
+ interface OAuthCallbackPayload {
1437
+ code: string;
1438
+ state: string;
1439
+ }
1440
+ interface OAuthManagerOptions {
1441
+ stateStore?: OAuthStateStore;
1442
+ stateConfig?: OAuthStateConfig;
1443
+ }
1444
+ declare class MemoryOAuthStateStore implements OAuthStateStore {
1445
+ private readonly states;
1446
+ store(stateHash: string, payload: OAuthStatePayload): Promise<void>;
1447
+ find(stateHash: string): Promise<OAuthStatePayload | null>;
1448
+ delete(stateHash: string): Promise<void>;
1449
+ clear(): void;
1450
+ }
1451
+ declare class OAuthManager {
1452
+ private readonly providers;
1453
+ private readonly stateStore;
1454
+ private readonly stateConfig;
1455
+ constructor(options?: OAuthManagerOptions);
1456
+ registerProvider(name: string, config: OAuthProviderConfig): void;
1457
+ providerNames(): string[];
1458
+ getProvider(name: string): OAuthProviderConfig;
1459
+ authorize(providerName: string, options?: OAuthAuthorizeOptions): Promise<{
1460
+ url: string;
1461
+ state: string;
1462
+ expiresAt: Date;
1463
+ }>;
1464
+ user(providerName: string, payload: OAuthCallbackPayload): Promise<OAuthUserProfile>;
1465
+ }
1466
+ declare function createOAuthManager(options?: OAuthManagerOptions): OAuthManager;
1467
+ declare function createOAuthState(provider: string, store: OAuthStateStore, config?: OAuthStateConfig, redirectTo?: string, fixedState?: string): Promise<{
1468
+ state: string;
1469
+ expiresAt: Date;
1470
+ }>;
1471
+ declare function verifyOAuthState(state: string, provider: string, store: OAuthStateStore, config?: OAuthStateConfig): Promise<OAuthStatePayload | null>;
1472
+ declare function buildOAuthAuthorizeUrl(provider: OAuthProviderConfig, state: string, options?: {
1473
+ scope?: string[];
1474
+ extraParams?: Record<string, string>;
1475
+ }): string;
1476
+ declare function exchangeOAuthCode(provider: OAuthProviderConfig, code: string): Promise<OAuthTokenResult>;
1477
+ declare function fetchOAuthUserProfile(provider: OAuthProviderConfig, token: OAuthTokenResult): Promise<OAuthUserProfile>;
1478
+ interface OAuthProviderFactoryInput {
1479
+ clientId: string;
1480
+ clientSecret: string;
1481
+ redirectUri: string;
1482
+ scopes?: string[];
1483
+ }
1484
+ declare function createGitHubOAuthProviderConfig(input: OAuthProviderFactoryInput): OAuthProviderConfig;
1485
+ declare function createGoogleOAuthProviderConfig(input: OAuthProviderFactoryInput): OAuthProviderConfig;
1486
+ declare function createDiscordOAuthProviderConfig(input: OAuthProviderFactoryInput): OAuthProviderConfig;
1487
+ declare function buildOAuthRedirectUrl(baseUrl: string, token: string, email?: string): string;
1488
+ declare function parseOAuthRedirectUrl(url: string): {
1489
+ token: string | null;
1490
+ email: string | null;
1491
+ };
1492
+
1493
+ /**
1494
+ * API token data stored in the backing store.
1495
+ */
1496
+ interface ApiToken {
1497
+ id: string;
1498
+ name: string;
1499
+ hashedToken: string;
1500
+ userId: string | number;
1501
+ abilities: string[];
1502
+ lastUsedAt: Date | null;
1503
+ expiresAt: Date | null;
1504
+ createdAt: Date;
1505
+ }
1506
+ /**
1507
+ * Store interface for API tokens.
1508
+ * Implement this for database-backed storage.
1509
+ */
1510
+ interface ApiTokenStore {
1511
+ /**
1512
+ * Store a new API token.
1513
+ */
1514
+ store(token: ApiToken): Promise<void>;
1515
+ /**
1516
+ * Find a token by its hashed value.
1517
+ */
1518
+ findByHashedToken(hashedToken: string): Promise<ApiToken | null>;
1519
+ /**
1520
+ * Find all tokens for a user.
1521
+ */
1522
+ findByUserId(userId: string | number): Promise<ApiToken[]>;
1523
+ /**
1524
+ * Delete a token by its ID.
1525
+ */
1526
+ delete(id: string): Promise<void>;
1527
+ /**
1528
+ * Delete all tokens for a user.
1529
+ */
1530
+ deleteForUser(userId: string | number): Promise<void>;
1531
+ /**
1532
+ * Update the last used timestamp.
1533
+ */
1534
+ updateLastUsed(id: string, timestamp: Date): Promise<void>;
1535
+ }
1536
+ /**
1537
+ * In-memory token store for testing.
1538
+ * Do NOT use in production - tokens will be lost on restart.
1539
+ */
1540
+ declare class MemoryApiTokenStore implements ApiTokenStore {
1541
+ private tokens;
1542
+ private byHash;
1543
+ store(token: ApiToken): Promise<void>;
1544
+ findByHashedToken(hashedToken: string): Promise<ApiToken | null>;
1545
+ findByUserId(userId: string | number): Promise<ApiToken[]>;
1546
+ delete(id: string): Promise<void>;
1547
+ deleteForUser(userId: string | number): Promise<void>;
1548
+ updateLastUsed(id: string, timestamp: Date): Promise<void>;
1549
+ /**
1550
+ * Clear all tokens (useful for testing).
1551
+ */
1552
+ clear(): void;
1553
+ /**
1554
+ * Get the number of stored tokens.
1555
+ */
1556
+ get size(): number;
1557
+ }
1558
+ /**
1559
+ * Configuration for API token creation.
1560
+ */
1561
+ interface CreateApiTokenOptions {
1562
+ /**
1563
+ * Human-readable name for the token.
1564
+ */
1565
+ name: string;
1566
+ /**
1567
+ * User ID the token belongs to.
1568
+ */
1569
+ userId: string | number;
1570
+ /**
1571
+ * Token abilities/scopes.
1572
+ * @default ['*'] (all abilities)
1573
+ */
1574
+ abilities?: string[];
1575
+ /**
1576
+ * Token expiration time in milliseconds from now.
1577
+ * @default null (never expires)
1578
+ */
1579
+ expiresIn?: number | null;
1580
+ /**
1581
+ * Token byte length (before encoding).
1582
+ * @default 32
1583
+ */
1584
+ tokenLength?: number;
1585
+ }
1586
+ /**
1587
+ * Result of creating an API token.
1588
+ */
1589
+ interface CreateApiTokenResult {
1590
+ /**
1591
+ * The full token to give to the user.
1592
+ * Format: {id}|{plainToken}
1593
+ * This is the ONLY time the plain token is available.
1594
+ */
1595
+ plainTextToken: string;
1596
+ /**
1597
+ * The token record (without the plain token).
1598
+ */
1599
+ token: ApiToken;
1600
+ }
1601
+ /**
1602
+ * Create a new API token.
1603
+ *
1604
+ * @example
1605
+ * ```ts
1606
+ * const { plainTextToken, token } = await createApiToken(store, {
1607
+ * name: 'My App Token',
1608
+ * userId: user.id,
1609
+ * abilities: ['read', 'write'],
1610
+ * expiresIn: 30 * 24 * 60 * 60 * 1000, // 30 days
1611
+ * })
1612
+ *
1613
+ * // Return plainTextToken to user - this is the only time it's available
1614
+ * return ctx.json({ token: plainTextToken })
1615
+ * ```
1616
+ */
1617
+ declare function createApiToken(store: ApiTokenStore, options: CreateApiTokenOptions): Promise<CreateApiTokenResult>;
1618
+ /**
1619
+ * Parse a plain text token into its components.
1620
+ */
1621
+ declare function parseApiToken(plainTextToken: string): {
1622
+ id: string;
1623
+ token: string;
1624
+ } | null;
1625
+ /**
1626
+ * Verify an API token and return the associated user ID.
1627
+ *
1628
+ * @example
1629
+ * ```ts
1630
+ * const result = await verifyApiToken(plainTextToken, store)
1631
+ *
1632
+ * if (!result) {
1633
+ * return ctx.json({ error: 'Invalid token' }, 401)
1634
+ * }
1635
+ *
1636
+ * console.log(`User ${result.userId} authenticated with abilities:`, result.abilities)
1637
+ * ```
1638
+ */
1639
+ declare function verifyApiToken(plainTextToken: string, store: ApiTokenStore, options?: {
1640
+ updateLastUsed?: boolean;
1641
+ }): Promise<{
1642
+ token: ApiToken;
1643
+ userId: string | number;
1644
+ abilities: string[];
1645
+ } | null>;
1646
+ /**
1647
+ * Check if a token has a specific ability.
1648
+ */
1649
+ declare function tokenCan(token: ApiToken | {
1650
+ abilities: string[];
1651
+ }, ability: string): boolean;
1652
+ /**
1653
+ * Check if a token has all specified abilities.
1654
+ */
1655
+ declare function tokenCanAll(token: ApiToken | {
1656
+ abilities: string[];
1657
+ }, abilities: string[]): boolean;
1658
+ /**
1659
+ * Check if a token has any of the specified abilities.
1660
+ */
1661
+ declare function tokenCanAny(token: ApiToken | {
1662
+ abilities: string[];
1663
+ }, abilities: string[]): boolean;
1664
+ /**
1665
+ * Revoke (delete) an API token.
1666
+ *
1667
+ * @example
1668
+ * ```ts
1669
+ * await revokeApiToken(tokenId, store)
1670
+ * ```
1671
+ */
1672
+ declare function revokeApiToken(id: string, store: ApiTokenStore): Promise<void>;
1673
+ /**
1674
+ * Revoke all API tokens for a user.
1675
+ *
1676
+ * @example
1677
+ * ```ts
1678
+ * // Revoke all tokens when user changes password
1679
+ * await revokeAllApiTokens(user.id, store)
1680
+ * ```
1681
+ */
1682
+ declare function revokeAllApiTokens(userId: string | number, store: ApiTokenStore): Promise<void>;
1683
+ /**
1684
+ * Get all API tokens for a user.
1685
+ *
1686
+ * @example
1687
+ * ```ts
1688
+ * const tokens = await getUserApiTokens(user.id, store)
1689
+ * // Returns tokens without the plain text (only metadata)
1690
+ * ```
1691
+ */
1692
+ declare function getUserApiTokens(userId: string | number, store: ApiTokenStore): Promise<ApiToken[]>;
1693
+ /**
1694
+ * Context key for storing the authenticated token.
1695
+ */
1696
+ declare const API_TOKEN_KEY = "guren:api-token";
1697
+ /**
1698
+ * Options for the bearer token middleware.
1699
+ */
1700
+ interface BearerTokenMiddlewareOptions {
1701
+ /**
1702
+ * Token store implementation.
1703
+ */
1704
+ store: ApiTokenStore;
1705
+ /**
1706
+ * Function to load the user from the user ID.
1707
+ */
1708
+ loadUser?: (userId: string | number) => Promise<unknown>;
1709
+ /**
1710
+ * Required abilities for this route.
1711
+ * If not specified, any valid token is accepted.
1712
+ */
1713
+ abilities?: string[];
1714
+ /**
1715
+ * Custom handler when authentication fails.
1716
+ */
1717
+ onUnauthorized?: (ctx: Context) => Response | Promise<Response>;
1718
+ /**
1719
+ * Custom handler when token lacks required abilities.
1720
+ */
1721
+ onForbidden?: (ctx: Context, required: string[]) => Response | Promise<Response>;
1722
+ /**
1723
+ * Header name to extract the token from.
1724
+ * @default 'Authorization'
1725
+ */
1726
+ headerName?: string;
1727
+ /**
1728
+ * Whether to update the token's lastUsedAt timestamp.
1729
+ * @default true
1730
+ */
1731
+ updateLastUsed?: boolean;
1732
+ }
1733
+ /**
1734
+ * Create middleware that authenticates requests using Bearer tokens.
1735
+ *
1736
+ * @example
1737
+ * ```ts
1738
+ * // Basic usage
1739
+ * app.use('/api/*', createBearerTokenMiddleware({ store }))
1740
+ *
1741
+ * // With ability requirement
1742
+ * router.delete('/api/posts/:id', [PostController, 'destroy'],
1743
+ * createBearerTokenMiddleware({
1744
+ * store,
1745
+ * abilities: ['posts:delete'],
1746
+ * })
1747
+ * )
1748
+ *
1749
+ * // With user loading
1750
+ * app.use('/api/*', createBearerTokenMiddleware({
1751
+ * store,
1752
+ * loadUser: async (userId) => User.find(userId),
1753
+ * }))
1754
+ * ```
1755
+ */
1756
+ declare function createBearerTokenMiddleware(options: BearerTokenMiddlewareOptions): MiddlewareHandler;
1757
+ /**
1758
+ * Get the authenticated API token from the request context.
1759
+ *
1760
+ * @example
1761
+ * ```ts
1762
+ * router.get('/api/me', async (ctx) => {
1763
+ * const { token, userId, abilities } = getApiToken(ctx)!
1764
+ * return ctx.json({ userId, tokenName: token.name, abilities })
1765
+ * })
1766
+ * ```
1767
+ */
1768
+ declare function getApiToken(ctx: Context): {
1769
+ token: ApiToken;
1770
+ userId: string | number;
1771
+ abilities: string[];
1772
+ } | null;
1773
+ /**
1774
+ * Get the authenticated API token from the request context, or throw.
1775
+ *
1776
+ * @throws {AuthenticationException} When no token is present in the context.
1777
+ *
1778
+ * @example
1779
+ * ```ts
1780
+ * router.get('/api/me', async (ctx) => {
1781
+ * const { token, userId, abilities } = getApiTokenOrFail(ctx)
1782
+ * return ctx.json({ userId, tokenName: token.name, abilities })
1783
+ * })
1784
+ * ```
1785
+ */
1786
+ declare function getApiTokenOrFail(ctx: Context): {
1787
+ token: ApiToken;
1788
+ userId: string | number;
1789
+ abilities: string[];
1790
+ };
1791
+
1792
+ export { parseOAuthRedirectUrl as $, AuthManager as A, BaseUserProvider as B, type CreateSessionMiddlewareOptions as C, type SessionStore as D, buildOAuthAuthorizeUrl as E, buildOAuthRedirectUrl as F, type Guard as G, createApiToken as H, createBearerTokenMiddleware as I, createDiscordOAuthProviderConfig as J, createGitHubOAuthProviderConfig as K, createGoogleOAuthProviderConfig as L, MemoryApiTokenStore as M, createOAuthManager as N, OAuthManager as O, type ProviderFactory as P, createOAuthState as Q, createSessionMiddleware as R, type Session as S, exchangeOAuthCode as T, type UserProvider as U, fetchOAuthUserProfile as V, getApiToken as W, getApiTokenOrFail as X, getSessionFromContext as Y, getUserApiTokens as Z, parseApiToken as _, type AuthContext as a, revokeAllApiTokens as a0, revokeApiToken as a1, tokenCan as a2, tokenCanAll as a3, tokenCanAny as a4, verifyApiToken as a5, verifyOAuthState as a6, type PasswordHasher as a7, type PlainObject as a8, Model as a9, type AttachContextOptions as aa, type AuthManagerContract as ab, type ApiToken as b, API_TOKEN_KEY as c, type ApiTokenStore as d, type AuthCredentials as e, type AuthManagerOptions as f, type Authenticatable as g, type BearerTokenMiddlewareOptions as h, type CreateApiTokenOptions as i, type CreateApiTokenResult as j, type GuardContext as k, type GuardFactory as l, MemoryOAuthStateStore as m, MemorySessionStore as n, ModelUserProvider as o, type OAuthAuthorizeOptions as p, type OAuthCallbackPayload as q, type OAuthManagerOptions as r, type OAuthProviderConfig as s, type OAuthProviderFactoryInput as t, type OAuthStateConfig as u, type OAuthStatePayload as v, type OAuthStateStore as w, type OAuthTokenResult as x, type OAuthUserProfile as y, type SessionData as z };