@nilejs/nile 0.0.1

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.
@@ -0,0 +1,646 @@
1
+ import { Context, Hono } from 'hono';
2
+ import { Result, ErrType, ResultMethods } from 'slang-ts';
3
+ import { Store } from 'hono-rate-limiter';
4
+ import z, { ZodTypeAny } from 'zod';
5
+
6
+ /**
7
+ * CORS options compatible with Hono's cors middleware
8
+ */
9
+ interface CorsOptions {
10
+ /**
11
+ * The value of "Access-Control-Allow-Origin" CORS header.
12
+ * Can be a string, array of strings, or a function that returns the allowed origin.
13
+ */
14
+ origin?: string | string[] | ((origin: string, c: Context) => string | undefined | null);
15
+ /**
16
+ * The value of "Access-Control-Allow-Methods" CORS header.
17
+ * Can be an array of HTTP methods or a function that returns allowed methods.
18
+ */
19
+ allowMethods?: string[] | ((origin: string, c: Context) => string[]);
20
+ /**
21
+ * The value of "Access-Control-Allow-Headers" CORS header.
22
+ */
23
+ allowHeaders?: string[];
24
+ /**
25
+ * The value of "Access-Control-Max-Age" CORS header.
26
+ */
27
+ maxAge?: number;
28
+ /**
29
+ * The value of "Access-Control-Allow-Credentials" CORS header.
30
+ */
31
+ credentials?: boolean;
32
+ /**
33
+ * The value of "Access-Control-Expose-Headers" CORS header.
34
+ */
35
+ exposeHeaders?: string[];
36
+ }
37
+ /**
38
+ * CORS resolver function that determines CORS behavior per request
39
+ * - Return `true` to allow the origin with default options
40
+ * - Return `false` to reject the request
41
+ * - Return a CorsOptions object to override options for this request
42
+ */
43
+ type CorsResolver = (origin: string, c: Context) => boolean | CorsOptions | undefined;
44
+ /**
45
+ * Per-route CORS configuration
46
+ */
47
+ interface CorsRouteRule {
48
+ /**
49
+ * Path pattern to match (e.g., '/api/*', '/uploads/*')
50
+ */
51
+ path: string;
52
+ /**
53
+ * Static CORS options for this route
54
+ */
55
+ options?: CorsOptions;
56
+ /**
57
+ * Dynamic resolver function to determine CORS behavior per request
58
+ */
59
+ resolver?: CorsResolver;
60
+ }
61
+ /**
62
+ * Main CORS configuration for the REST server
63
+ */
64
+ interface CorsConfig {
65
+ /**
66
+ * Enable or disable CORS
67
+ * - `true` or `'default'`: Use default CORS configuration
68
+ * - `false`: Disable CORS middleware entirely (no CORS headers are set)
69
+ */
70
+ enabled?: boolean | "default";
71
+ /**
72
+ * Default CORS options applied globally
73
+ */
74
+ defaults?: CorsOptions;
75
+ /**
76
+ * Additional route-specific CORS rules
77
+ */
78
+ addCors?: CorsRouteRule[];
79
+ }
80
+
81
+ interface RateLimitConfig {
82
+ windowMs?: number;
83
+ limit?: number;
84
+ standardHeaders?: boolean;
85
+ limitingHeader: string;
86
+ store?: Store;
87
+ diagnostics?: boolean;
88
+ }
89
+ interface RestConfig {
90
+ baseUrl: string;
91
+ host?: string;
92
+ port?: number;
93
+ diagnostics?: boolean;
94
+ enableStatic?: boolean;
95
+ enableStatus?: boolean;
96
+ rateLimiting?: RateLimitConfig;
97
+ allowedOrigins: string[];
98
+ cors?: CorsConfig;
99
+ uploads?: {
100
+ enforceContentType?: boolean;
101
+ limits?: {
102
+ maxFiles?: number;
103
+ maxFileSize?: number;
104
+ minFileSize?: number;
105
+ maxTotalSize?: number;
106
+ maxFilenameLength?: number;
107
+ };
108
+ allow?: {
109
+ mimeTypes?: string[];
110
+ extensions?: string[];
111
+ };
112
+ diagnostics?: boolean;
113
+ };
114
+ }
115
+
116
+ interface WebSocketContext {
117
+ connection: unknown;
118
+ headers?: Record<string, string>;
119
+ cookies?: Record<string, string>;
120
+ [key: string]: unknown;
121
+ }
122
+ interface RPCContext {
123
+ [key: string]: unknown;
124
+ }
125
+ interface BaseContext {
126
+ rest?: Context;
127
+ ws?: WebSocketContext;
128
+ rpc?: RPCContext;
129
+ }
130
+ interface Sessions {
131
+ rest?: Record<string, unknown>;
132
+ ws?: Record<string, unknown>;
133
+ rpc?: Record<string, unknown>;
134
+ }
135
+ interface Sessions {
136
+ rest?: Record<string, unknown>;
137
+ ws?: Record<string, unknown>;
138
+ rpc?: Record<string, unknown>;
139
+ }
140
+ interface NileLogger {
141
+ info: (input: {
142
+ atFunction: string;
143
+ message: string;
144
+ data?: unknown;
145
+ }) => string;
146
+ warn: (input: {
147
+ atFunction: string;
148
+ message: string;
149
+ data?: unknown;
150
+ }) => string;
151
+ error: (input: {
152
+ atFunction: string;
153
+ message: string;
154
+ data?: unknown;
155
+ }) => string;
156
+ }
157
+ interface Resources<TDB = unknown> {
158
+ logger?: NileLogger;
159
+ database?: TDB;
160
+ cache?: unknown;
161
+ [key: string]: unknown;
162
+ }
163
+ interface NileContext<TDB = unknown> {
164
+ readonly rest?: Context;
165
+ readonly ws?: WebSocketContext;
166
+ readonly rpc?: RPCContext;
167
+ sessions: Sessions;
168
+ readonly _store: Readonly<Map<string, unknown>>;
169
+ readonly get: <T = unknown>(key: string) => T | undefined;
170
+ readonly set: <T = unknown>(key: string, value: T) => void;
171
+ readonly resources?: Resources<TDB>;
172
+ /** Retrieve session data for a specific interface */
173
+ getSession: (name: keyof Sessions) => Record<string, unknown> | undefined;
174
+ /** Store session data for a specific interface */
175
+ setSession: (name: keyof Sessions, data: Record<string, unknown>) => void;
176
+ hookContext: HookContext;
177
+ updateHookState: (key: string, value: unknown) => void;
178
+ addHookLog: (phase: "before" | "after", logEntry: {
179
+ name: string;
180
+ input: unknown;
181
+ output: unknown;
182
+ passed: boolean;
183
+ }) => void;
184
+ setHookError: (error: string) => void;
185
+ setHookOutput: (output: unknown) => void;
186
+ resetHookContext: (actionName: string, input: unknown) => void;
187
+ }
188
+ type BeforeActionHandler<T, E> = (params: {
189
+ nileContext: NileContext<unknown>;
190
+ action: Action;
191
+ payload: unknown;
192
+ }) => Result<T, E>;
193
+ type AfterActionHandler<T, E> = (params: {
194
+ nileContext: NileContext<unknown>;
195
+ action: Action;
196
+ payload: unknown;
197
+ result: Result<T, E>;
198
+ }) => Result<T, E>;
199
+ type ServerRuntime = "bun" | "node";
200
+ interface ServerConfig {
201
+ serverName: string;
202
+ runtime?: ServerRuntime;
203
+ services: Services;
204
+ diagnostics?: boolean;
205
+ /** Print registered services table to console on boot (default: true) */
206
+ logServices?: boolean;
207
+ resources?: Resources<unknown>;
208
+ rest?: RestConfig;
209
+ websocket?: Record<string, unknown>;
210
+ rpc?: Record<string, unknown>;
211
+ onBeforeActionHandler?: BeforeActionHandler<unknown, unknown>;
212
+ onAfterActionHandler?: AfterActionHandler<unknown, unknown>;
213
+ onBoot?: {
214
+ fn: (context: NileContext<unknown>) => Promise<void> | void;
215
+ };
216
+ }
217
+ interface ExternalResponse {
218
+ status: boolean;
219
+ message: string;
220
+ data: Record<string, unknown>;
221
+ }
222
+ interface ExternalRequest {
223
+ intent: "explore" | "execute" | "schema";
224
+ service: string;
225
+ action: string;
226
+ payload: Record<string, unknown>;
227
+ }
228
+ interface NileServer {
229
+ config: ServerConfig;
230
+ engine: Engine;
231
+ context: NileContext<unknown>;
232
+ rest?: {
233
+ app: Hono;
234
+ config: RestConfig;
235
+ };
236
+ }
237
+
238
+ interface HookDefinition {
239
+ service: string;
240
+ action: string;
241
+ /** When true, hook failure stops the pipeline. Non-critical hooks log errors but continue. */
242
+ isCritical: boolean;
243
+ }
244
+ interface ActionResultConfig {
245
+ pipeline: boolean;
246
+ }
247
+ interface HookLogEntry {
248
+ name: string;
249
+ input: unknown;
250
+ output: unknown;
251
+ passed: boolean;
252
+ }
253
+ interface HookContext {
254
+ actionName: string;
255
+ input: unknown;
256
+ output?: unknown;
257
+ error?: string;
258
+ state: Record<string, unknown>;
259
+ log: {
260
+ before: HookLogEntry[];
261
+ after: HookLogEntry[];
262
+ };
263
+ }
264
+ type ActionHandler<T = unknown, E = string> = (data: Record<string, unknown>, context?: NileContext<unknown>) => Result<T, E> | Promise<Result<T, E>>;
265
+ interface Action {
266
+ name: string;
267
+ description: string;
268
+ isProtected?: boolean;
269
+ visibility?: {
270
+ rest?: boolean;
271
+ rpc?: boolean;
272
+ };
273
+ isSpecial?: {
274
+ contentType: "multipart/form-data" | "application/json" | "other";
275
+ uploadMode?: "flat" | "structured";
276
+ };
277
+ handler: ActionHandler;
278
+ validation?: z.ZodTypeAny | null;
279
+ hooks?: {
280
+ before?: HookDefinition[];
281
+ after?: HookDefinition[];
282
+ };
283
+ result?: ActionResultConfig;
284
+ accessControl?: string[];
285
+ meta?: Record<string, unknown>;
286
+ }
287
+ type Actions = Action[];
288
+ interface Service {
289
+ name: string;
290
+ description: string;
291
+ actions: Actions;
292
+ meta?: Record<string, unknown>;
293
+ }
294
+ type Services = Service[];
295
+ interface ServiceSummary {
296
+ name: string;
297
+ description: string;
298
+ meta?: Record<string, unknown>;
299
+ actions: string[];
300
+ }
301
+ interface ActionSummary {
302
+ name: string;
303
+ description: string;
304
+ isProtected: boolean;
305
+ validation: boolean;
306
+ accessControl: string[];
307
+ }
308
+ interface EngineOptions {
309
+ diagnostics?: boolean;
310
+ /** Optional logger from resources — used for diagnostics output when available */
311
+ logger?: {
312
+ info: (msg: string, data?: unknown) => void;
313
+ } | NileLogger;
314
+ services: Services;
315
+ onBeforeActionHandler?: BeforeActionHandler<unknown, unknown>;
316
+ onAfterActionHandler?: AfterActionHandler<unknown, unknown>;
317
+ }
318
+ /** Formalized return type of createEngine */
319
+ interface Engine {
320
+ getServices: () => Result<ServiceSummary[], string>;
321
+ getServiceActions: (serviceName: string) => Result<ActionSummary[], string>;
322
+ getAction: (serviceName: string, actionName: string) => Result<Action, string>;
323
+ executeAction: (serviceName: string, actionName: string, payload: unknown, nileContext: NileContext<unknown>) => Promise<Result<unknown, string>>;
324
+ }
325
+
326
+ /**
327
+ * Typed identity for defining a single action with full type inference.
328
+ * No runtime overhead — returns the config object as-is.
329
+ */
330
+ declare function createAction(config: Action): Action;
331
+ /**
332
+ * Typed identity for defining multiple actions with full type inference.
333
+ * No runtime overhead — returns the config array as-is.
334
+ */
335
+ declare function createActions(configs: Action[]): Action[];
336
+
337
+ /**
338
+ * Typed identity for defining a service with full type inference.
339
+ * No runtime overhead — returns the config object as-is.
340
+ */
341
+ declare function createService(config: Service): Service;
342
+ /**
343
+ * Typed identity for defining multiple services with full type inference.
344
+ * No runtime overhead — returns the config array as-is.
345
+ */
346
+ declare function createServices(configs: Service[]): Service[];
347
+
348
+ interface Log {
349
+ atFunction: string;
350
+ appName: string;
351
+ message: string;
352
+ data?: unknown;
353
+ level?: "info" | "warn" | "error";
354
+ log_id?: string;
355
+ }
356
+ /** Configuration for log file chunking behavior */
357
+ interface LoggerConfig {
358
+ /** Time-based chunking strategy. Default: 'none' (single file per app) */
359
+ chunking?: "monthly" | "daily" | "weekly" | "none";
360
+ }
361
+ /**
362
+ * Creates a new log entry with the provided log information.
363
+ * Supports optional chunking config to split logs into time-based files.
364
+ * @param log - The log object containing the log details
365
+ * @param config - Optional logger config for chunking behavior
366
+ * @returns The generated log ID (or JSON string in agentic mode)
367
+ * @throws {Error} If appName is missing in the log object
368
+ */
369
+ declare const createLog: (log: Log, config?: LoggerConfig) => string;
370
+ interface LogFilter {
371
+ appName?: string;
372
+ log_id?: string;
373
+ level?: "info" | "warn" | "error";
374
+ from?: Date;
375
+ to?: Date;
376
+ }
377
+ /**
378
+ * Retrieves logs based on the provided filters.
379
+ * Supports reading from chunked files when a LoggerConfig with chunking is provided.
380
+ * When chunking is enabled, uses from/to date filters to intelligently select
381
+ * only the relevant chunk files instead of scanning all files.
382
+ * @param filters - Optional filters to apply when retrieving logs
383
+ * @param config - Optional logger config matching the chunking used when writing
384
+ * @returns An array of log entries matching the filters
385
+ */
386
+ declare const getLogs: (filters?: LogFilter, config?: LoggerConfig) => Log[];
387
+
388
+ type LogInput = Omit<Log, "appName">;
389
+ /**
390
+ * Creates a logger instance bound to a specific app name.
391
+ * Optionally accepts a LoggerConfig for time-based file chunking.
392
+ * @param appName - The application name (determines log file/directory)
393
+ * @param config - Optional config for chunking (monthly, daily, weekly)
394
+ */
395
+ declare const createLogger: (appName: string, config?: LoggerConfig) => {
396
+ info: (input: LogInput) => string;
397
+ warn: (input: LogInput) => string;
398
+ error: (input: LogInput) => string;
399
+ };
400
+
401
+ /**
402
+ * Retrieves the runtime NileContext.
403
+ *
404
+ * Use this to access shared resources (database, logger) and context storage
405
+ * from anywhere in your application. Supports a TDB generic to provide
406
+ * end-to-end type safety for your database instance.
407
+ *
408
+ * @template TDB - The type of your database instance (e.g. typeof db)
409
+ * @returns The active NileContext<TDB>
410
+ * @throws If called before createNileServer has initialized the global context.
411
+ */
412
+ declare function getContext<TDB = unknown>(): NileContext<TDB>;
413
+ /**
414
+ * Bootstraps a Nile server instance.
415
+ *
416
+ * Wires together the Action Engine, shared NileContext, and interface layers (REST).
417
+ * This is the primary entry point for a Nile application. It handles service
418
+ * registration, resource attachment, and server lifecycle.
419
+ *
420
+ * @param config - Server configuration including services, rest options, and resources
421
+ * @returns A NileServer instance containing the engine and (optional) REST app
422
+ */
423
+ declare function createNileServer(config: ServerConfig): NileServer;
424
+
425
+ /**
426
+ * Database instance or transaction pointer type.
427
+ * Accepts a root DB instance (with .transaction method) or a transaction pointer.
428
+ *
429
+ * @example
430
+ * ```typescript
431
+ * type DBX = typeof db | Parameters<Parameters<typeof db.transaction>[0]>[0];
432
+ * ```
433
+ */
434
+ type DBX<TDB> = TDB extends {
435
+ transaction: (fn: (tx: infer TX) => unknown) => unknown;
436
+ } ? TDB | TX : TDB;
437
+ /**
438
+ * Standard params interface for functions that can optionally use a transaction.
439
+ *
440
+ * @example
441
+ * ```typescript
442
+ * const createCompany = async ({ company, dbx }: DBParams<typeof db> & { company: NewCompany }) => { ... }
443
+ * ```
444
+ */
445
+ interface DBParams<TDB> {
446
+ dbx?: DBX<TDB>;
447
+ }
448
+ /**
449
+ * Zod schemas generated from a Drizzle table.
450
+ */
451
+ interface TableSchemas<_TTable> {
452
+ insert: ZodTypeAny;
453
+ update: ZodTypeAny;
454
+ select: ZodTypeAny;
455
+ }
456
+ /**
457
+ * Configuration for the createModel factory.
458
+ *
459
+ * @property db - Explicit database instance. When omitted, resolved from Nile context at call time.
460
+ * @property name - Human-readable entity name for error messages (e.g. "task", "user").
461
+ * @property cursorColumn - Default column name for cursor-based pagination. Defaults to "id".
462
+ */
463
+ interface ModelOptions<TDB = unknown> {
464
+ db?: TDB;
465
+ name: string;
466
+ cursorColumn?: string;
467
+ }
468
+ /** Params for model methods that support transactions */
469
+ interface ModelWriteParams<TInsert, TDB> {
470
+ data: TInsert;
471
+ dbx?: DBX<TDB>;
472
+ }
473
+ /** Params for model update methods */
474
+ interface ModelUpdateParams<TSelect, TDB> {
475
+ id: string;
476
+ data: Partial<TSelect>;
477
+ dbx?: DBX<TDB>;
478
+ }
479
+ /** Offset-based pagination result */
480
+ interface OffsetPage<T> {
481
+ items: T[];
482
+ total: number;
483
+ hasMore: boolean;
484
+ }
485
+ /** Cursor-based pagination result */
486
+ interface CursorPage<T> {
487
+ items: T[];
488
+ nextCursor: string | null;
489
+ hasMore: boolean;
490
+ }
491
+ /** Offset pagination options */
492
+ interface OffsetPaginationOptions {
493
+ limit?: number;
494
+ offset?: number;
495
+ cursor?: never;
496
+ cursorColumn?: never;
497
+ }
498
+ /** Cursor pagination options — value is the cursor, column overrides model default */
499
+ interface CursorPaginationOptions {
500
+ limit?: number;
501
+ cursor: string;
502
+ cursorColumn?: string;
503
+ offset?: never;
504
+ }
505
+ type PaginationOptions = OffsetPaginationOptions | CursorPaginationOptions;
506
+ /** All CRUD operations returned by createModel */
507
+ interface ModelOperations<TSelect, TInsert, TDB> {
508
+ /** Insert a new record with auto-validation */
509
+ create(params: ModelWriteParams<TInsert, TDB>): Promise<Result<TSelect, string>>;
510
+ /** Insert a new record wrapped in a transaction */
511
+ createTx(params: ModelWriteParams<TInsert, TDB>): Promise<Result<TSelect, string>>;
512
+ /** Find a single record by UUID */
513
+ findById(id: string): Promise<Result<TSelect, string>>;
514
+ /** Update a record by UUID with auto-validation */
515
+ update(params: ModelUpdateParams<TSelect, TDB>): Promise<Result<TSelect, string>>;
516
+ /** Update a record wrapped in a transaction */
517
+ updateTx(params: ModelUpdateParams<TSelect, TDB>): Promise<Result<TSelect, string>>;
518
+ /** Delete a record by UUID, returns the deleted row */
519
+ delete(id: string): Promise<Result<TSelect, string>>;
520
+ /** Get all records ordered by newest first (when created_at/createdAt exists) */
521
+ findAll(): Promise<Result<TSelect[], string>>;
522
+ /** Paginated query — offset-based when offset is set, cursor-based when cursor is set */
523
+ findPaginated(options?: OffsetPaginationOptions): Promise<Result<OffsetPage<TSelect>, string>>;
524
+ findPaginated(options: CursorPaginationOptions): Promise<Result<CursorPage<TSelect>, string>>;
525
+ findPaginated(options?: PaginationOptions): Promise<Result<OffsetPage<TSelect> | CursorPage<TSelect>, string>>;
526
+ /** The underlying Drizzle table — escape hatch for custom queries */
527
+ table: unknown;
528
+ /** Auto-generated Zod schemas for insert/update/select validation */
529
+ schemas: TableSchemas<unknown>;
530
+ }
531
+
532
+ /**
533
+ * Creates a CRUD model for a Drizzle table, eliminating repetitive boilerplate.
534
+ *
535
+ * All methods return `Result<T, string>` — `Ok(data)` on success, `Err(message)` on failure.
536
+ * Validation, error handling, and transaction variants are built in.
537
+ *
538
+ * For anything beyond basic CRUD, use the exposed `table` and `schemas` properties
539
+ * to compose custom queries with Drizzle directly.
540
+ *
541
+ * @param table - Drizzle table definition (from pgTable, sqliteTable, etc.)
542
+ * @param options - Configuration: entity name, optional db instance, cursor column
543
+ * @returns Object with CRUD operations, plus escape hatches (table, schemas)
544
+ *
545
+ * @example
546
+ * ```typescript
547
+ * import { createModel } from "@nilejs/nile";
548
+ * import { tasks } from "./schema";
549
+ * import { db } from "./client";
550
+ *
551
+ * // Explicit db
552
+ * export const taskModel = createModel(tasks, { db, name: "task" });
553
+ *
554
+ * // Context-resolved db (resolved at call time)
555
+ * export const taskModel = createModel(tasks, { name: "task" });
556
+ *
557
+ * // Usage
558
+ * const result = await taskModel.create({ data: { title: "Ship it" } });
559
+ * const task = await taskModel.findById("uuid-123");
560
+ * const page = await taskModel.findPaginated({ limit: 20, offset: 0 });
561
+ * ```
562
+ */
563
+ declare function createModel<TTable extends {
564
+ $inferSelect: unknown;
565
+ $inferInsert: unknown;
566
+ }, TDB = unknown>(table: TTable, options: ModelOptions<TDB>): ModelOperations<TTable["$inferSelect"], TTable["$inferInsert"], TDB>;
567
+
568
+ /**
569
+ * Creates a transaction-aware variant of a database function.
570
+ * Expects the wrapped function to accept a single object parameter with optional dbx field.
571
+ *
572
+ * When dbx is root db (has .transaction method):
573
+ * - Creates new transaction and executes function inside it
574
+ * - On Result.isError, throws Error to trigger automatic rollback
575
+ * - Returns successful result or throws
576
+ *
577
+ * When dbx is tx pointer (no .transaction method):
578
+ * - Executes function directly within existing transaction scope
579
+ * - On Result.isError, throws Error to trigger parent transaction rollback
580
+ * - Returns successful result or throws
581
+ *
582
+ * Both cases ensure database rollback on any error by throwing.
583
+ *
584
+ * @example
585
+ * ```typescript
586
+ * const createCompanyTx = createTransactionVariant(createCompany);
587
+ * // Type-safe: requires all params from createCompany
588
+ * const result = await createCompanyTx({ company: {...}, dbx: tx });
589
+ * ```
590
+ */
591
+ declare function createTransactionVariant<TParams extends DBParams<TDB>, TData, TDB = unknown>(fn: (params: TParams) => Promise<Result<TData, unknown>>): (params: TParams) => Promise<Result<TData, unknown>>;
592
+
593
+ /**
594
+ * Generates Zod schemas (insert, update, select) from a Drizzle table.
595
+ *
596
+ * @param table - The Drizzle table definition
597
+ * @returns Object containing insert, update, and select Zod schemas
598
+ *
599
+ * @example
600
+ * ```typescript
601
+ * import { getZodSchema } from '@nilejs/nile';
602
+ * import { companies } from './schema';
603
+ *
604
+ * const schemas = getZodSchema(companies);
605
+ * const insert = schemas.insert.parse(data);
606
+ * const update = schemas.update.partial().parse(data);
607
+ * ```
608
+ */
609
+ declare function getZodSchema<TTable extends object>(table: TTable): TableSchemas<TTable>;
610
+
611
+ /**
612
+ * Parameters for the handleError utility.
613
+ *
614
+ * @property message - Human-readable error description, included in the returned Result error string
615
+ * @property data - Optional structured data logged alongside the error for debugging
616
+ * @property logger - Explicit logger instance; when omitted, resolves from the current Nile request context
617
+ * @property atFunction - Name of the calling function for log attribution; auto-inferred from stack trace when omitted
618
+ */
619
+ interface HandleErrorParams {
620
+ message: string;
621
+ data?: unknown;
622
+ logger?: NileLogger;
623
+ atFunction?: string;
624
+ }
625
+ /**
626
+ * Logs an error via the resolved logger and returns a typed Err result.
627
+ * Resolves the logger from the current Nile request context when not provided explicitly.
628
+ * The returned error string includes the log ID for traceability: `[logId] message`.
629
+ *
630
+ * @param params - Error details including message, optional data, logger, and caller function name
631
+ * @returns Always an Err variant — `ErrType<string> & ResultMethods<never>`, compatible with any `Result<T, E>` union
632
+ *
633
+ * @example
634
+ * ```typescript
635
+ * if (!user) {
636
+ * return handleError({
637
+ * message: "User not found",
638
+ * data: { userId },
639
+ * atFunction: "getUserById",
640
+ * });
641
+ * }
642
+ * ```
643
+ */
644
+ declare function handleError(params: HandleErrorParams): ErrType<string> & ResultMethods<never>;
645
+
646
+ export { type Action, type ActionHandler, type ActionResultConfig, type ActionSummary, type Actions, type AfterActionHandler, type BaseContext, type BeforeActionHandler, type CorsConfig, type CorsOptions, type CorsResolver, type CorsRouteRule, type CursorPage, type CursorPaginationOptions, type DBParams, type DBX, type Engine, type EngineOptions, type ExternalRequest, type ExternalResponse, type HookContext, type HookDefinition, type HookLogEntry, type Log, type LogFilter, type LoggerConfig, type ModelOperations, type ModelOptions, type NileContext, type NileLogger, type NileServer, type OffsetPage, type OffsetPaginationOptions, type RPCContext, type RateLimitConfig, type Resources, type RestConfig, type ServerConfig, type ServerRuntime, type Service, type ServiceSummary, type Services, type Sessions, type WebSocketContext, createAction, createActions, createLog, createLogger, createModel, createNileServer, createService, createServices, createTransactionVariant, getContext, getLogs, getZodSchema, handleError };