tempest-express-sdk 0.1.0

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,1726 @@
1
+ import { z } from 'zod';
2
+ export { z } from 'zod';
3
+ import * as tempest_db_js from 'tempest-db-js';
4
+ import { Model, ModelClass, BaseRepository, InferModel, WhereInput, InferInsert, PaginationFilter as PaginationFilter$1, PaginationResult } from 'tempest-db-js';
5
+ export { AsyncDriver, AsyncEngine, AsyncResult, AsyncSession, BaseRepository, BelongsTo, ColType, Column, ColumnFlags, CompiledQuery, CondNode, Condition, DeleteBuilder, DeleteNode, Dialect, EngineOptions, Executable, HasMany, InferInsert, InferModel, InsertBuilder, InsertNode, Model, ModelClass, NoResultError, NodeSqliteDriver, Operator, OrderTerm, PaginationResult, ParsedDatabaseUrl, PostgresDialect, QueryNode, RecordNotFound, Relation, RelationValue, PaginationFilter as RepositoryPaginationFilter, Returning, RowOf, SelectBuilder, SelectNode, SortDirection, SqliteDialect, SyncEngine, SyncSession, UpdateBuilder, UpdateNode, WhereArg, WhereInput, WithRelations, and, belongsTo, column, columnsOf, createEngine, createSyncEngine, del, detectDialect, getDialect, hasMany, insert, join, loadRelations, not, or, parseDatabaseUrl, select, sql, update } from 'tempest-db-js';
6
+ import { Request, RequestHandler, Router, ErrorRequestHandler, Express } from 'express';
7
+ import { OpenAPIRegistry } from '@asteasolutions/zod-to-openapi';
8
+ export { OpenAPIRegistry } from '@asteasolutions/zod-to-openapi';
9
+ import { Server } from 'node:http';
10
+
11
+ /**
12
+ * Request-scoped context propagation via `AsyncLocalStorage`.
13
+ *
14
+ * Mirrors `tempest_fastapi_sdk.core.context`: a per-request id that any layer
15
+ * (logger, exception handler, service) can read without threading it through
16
+ * every call. The store is populated by the request-id middleware and survives
17
+ * across `await` boundaries within the same request.
18
+ */
19
+ /** The shape of the per-request store. */
20
+ interface RequestContext {
21
+ /** Stable id correlating every log line of a single request. */
22
+ requestId: string;
23
+ }
24
+ /**
25
+ * Run `fn` with `context` bound as the active request context.
26
+ *
27
+ * @param context - The context to bind for the duration of `fn`.
28
+ * @param fn - The function to run within the bound context.
29
+ * @returns Whatever `fn` returns.
30
+ */
31
+ declare function runWithRequestContext<T>(context: RequestContext, fn: () => T): T;
32
+ /**
33
+ * Read the current request id, or `null` when called outside a request.
34
+ *
35
+ * @returns The active request id, or `null`.
36
+ */
37
+ declare function getRequestId(): string | null;
38
+ /**
39
+ * Overwrite the request id on the active context (no-op outside a request).
40
+ *
41
+ * @param requestId - The id to set.
42
+ */
43
+ declare function setRequestId(requestId: string): void;
44
+
45
+ /**
46
+ * Structured JSON logging, mirroring `tempest_fastapi_sdk.core.logging`.
47
+ *
48
+ * Emits one JSON object per line to stdout (or stderr for `error`), enriched
49
+ * with the active request id. Server errors (`500`) carry the
50
+ * {@link HTTP_500_MARKER} flag so an external log router can split them into a
51
+ * dedicated `500.log` sink.
52
+ */
53
+ /** Flag key marking a record as a captured HTTP 500 for sink routing. */
54
+ declare const HTTP_500_MARKER = "http_500";
55
+ /** Severity levels, ordered from least to most severe. */
56
+ type LogLevel = "debug" | "info" | "warning" | "error";
57
+ /** Free-form structured context merged into the emitted record. */
58
+ type LogExtra = Record<string, unknown>;
59
+ /** A minimal structured logger writing one JSON line per record. */
60
+ declare class JSONLogger {
61
+ private readonly name;
62
+ private readonly level;
63
+ /**
64
+ * @param name - Logger name embedded in every record.
65
+ * @param level - Minimum level to emit; quieter records are dropped.
66
+ */
67
+ constructor(name: string, level?: LogLevel);
68
+ /** Log a debug-level message. */
69
+ debug(message: string, extra?: LogExtra): void;
70
+ /** Log an info-level message. */
71
+ info(message: string, extra?: LogExtra): void;
72
+ /** Log a warning-level message. */
73
+ warning(message: string, extra?: LogExtra): void;
74
+ /** Log an error-level message. */
75
+ error(message: string, extra?: LogExtra): void;
76
+ /**
77
+ * Emit a record at `level` when it clears the configured threshold.
78
+ *
79
+ * @param level - The record severity.
80
+ * @param message - The human-readable message.
81
+ * @param extra - Structured context merged into the record.
82
+ */
83
+ log(level: LogLevel, message: string, extra?: LogExtra): void;
84
+ }
85
+ /**
86
+ * Build a {@link JSONLogger}.
87
+ *
88
+ * @param name - Logger name.
89
+ * @param level - Minimum level to emit (defaults to `info`).
90
+ * @returns A configured logger.
91
+ */
92
+ declare function configureLogging(name: string, level?: LogLevel): JSONLogger;
93
+
94
+ /**
95
+ * Enum helpers mirroring `BaseStrEnum` / `BaseIntEnum`.
96
+ *
97
+ * TypeScript has no Python-style `Enum`, so this module offers a factory that
98
+ * turns a plain literal map into a frozen object carrying the same
99
+ * introspection helpers (`values`/`keys`/`choices`/`has`/`from`) the FastAPI
100
+ * SDK exposes. The inferred type is the literal union of the member values, so
101
+ * it stays as strongly typed as a hand-written `as const` map.
102
+ */
103
+ /** A member-name → member-value map (string- or number-valued). */
104
+ type EnumSpec = Record<string, string | number>;
105
+ /** Introspection helpers attached to every built enum. */
106
+ interface EnumHelpers<S extends EnumSpec> {
107
+ /** Every member value, in declaration order. */
108
+ values(): Array<S[keyof S]>;
109
+ /** Every member name, in declaration order. */
110
+ keys(): Array<keyof S & string>;
111
+ /** `[value, name]` pairs, e.g. for building `<select>` options. */
112
+ choices(): Array<[S[keyof S], keyof S & string]>;
113
+ /** Whether `value` is the value of some member. */
114
+ hasValue(value: unknown): value is S[keyof S];
115
+ /** Whether `key` is the name of some member. */
116
+ hasKey(key: string): key is keyof S & string;
117
+ /** Resolve a member value from a raw value or member name, else `fallback`. */
118
+ from(value: unknown, fallback?: S[keyof S]): S[keyof S] | undefined;
119
+ }
120
+ /** A built enum: the literal member map plus {@link EnumHelpers}. */
121
+ type Enum<S extends EnumSpec> = Readonly<S> & EnumHelpers<S>;
122
+ /**
123
+ * Build a frozen enum object with introspection helpers from a literal spec.
124
+ *
125
+ * @param spec - The member-name → value map. Pass it inline so TypeScript
126
+ * infers the precise literal union (e.g. `defineEnum({ RED: "red" })`).
127
+ * @returns The frozen members merged with {@link EnumHelpers}.
128
+ */
129
+ declare function defineEnum<const S extends EnumSpec>(spec: S): Enum<S>;
130
+
131
+ /**
132
+ * Base application exception.
133
+ *
134
+ * Mirrors `tempest_fastapi_sdk.exceptions.base.AppException`: a single base any
135
+ * layer can throw, carrying an HTTP status, a stable machine-readable `code`,
136
+ * free-form `details`, optional response `headers`, and localization hooks
137
+ * (`messageKey` / `messageParams`). The exception handler
138
+ * ({@link registerExceptionHandlers}) serializes it to the canonical envelope:
139
+ *
140
+ * ```json
141
+ * { "detail": "<message>", "code": "<code>", "details": { } }
142
+ * ```
143
+ *
144
+ * Concrete projects either throw a domain subclass (for `instanceof` matching)
145
+ * or the base directly, overriding fields via the constructor options.
146
+ */
147
+ /** Free-form structured context attached to the response payload. */
148
+ type ExceptionDetails = Record<string, unknown>;
149
+ /** Constructor options for {@link AppException} and subclasses. */
150
+ interface AppExceptionOptions {
151
+ /** Override the default message; used verbatim as `detail` absent a catalog. */
152
+ message?: string;
153
+ /** Override the default machine-readable code on this instance only. */
154
+ code?: string;
155
+ /** Override the default HTTP status code on this instance only. */
156
+ statusCode?: number;
157
+ /** Structured context merged into the JSON response `details`. */
158
+ details?: ExceptionDetails;
159
+ /** Extra HTTP response headers. */
160
+ headers?: Record<string, string>;
161
+ /** Catalog key used to localize `detail`; falls back to `code`. */
162
+ messageKey?: string;
163
+ /** Values interpolated into the localized message template. */
164
+ messageParams?: Record<string, unknown>;
165
+ }
166
+ declare class AppException extends Error {
167
+ /** Default HTTP status code for the class. */
168
+ static statusCode: number;
169
+ /** Default human-readable message for the class. */
170
+ static message: string;
171
+ /** Default machine-readable code for the class. */
172
+ static code: string;
173
+ /** Default catalog key for the class (falls back to `code`). */
174
+ static messageKey: string | null;
175
+ readonly statusCode: number;
176
+ readonly code: string;
177
+ readonly details: ExceptionDetails;
178
+ readonly headers: Record<string, string>;
179
+ readonly messageKey: string | null;
180
+ readonly messageParams: Record<string, unknown>;
181
+ /**
182
+ * @param options - Per-instance overrides; omitted fields fall back to the
183
+ * static class defaults.
184
+ */
185
+ constructor(options?: AppExceptionOptions);
186
+ }
187
+
188
+ /**
189
+ * Concrete HTTP exception subclasses, mirroring the FastAPI SDK hierarchy.
190
+ *
191
+ * Each exists primarily for `instanceof` matching and to carry a sane default
192
+ * status/code/message. Throw them directly or subclass further for domain
193
+ * errors (e.g. `class UserNotFound extends NotFoundException {}`).
194
+ */
195
+
196
+ /** 409 — a write would violate a uniqueness/integrity rule. */
197
+ declare class ConflictException extends AppException {
198
+ static statusCode: number;
199
+ static message: string;
200
+ static code: string;
201
+ }
202
+ /** 404 — a single resource could not be located. Never for collections. */
203
+ declare class NotFoundException extends AppException {
204
+ static statusCode: number;
205
+ static message: string;
206
+ static code: string;
207
+ }
208
+ /** 401 — the caller is not authenticated. */
209
+ declare class UnauthorizedException extends AppException {
210
+ static statusCode: number;
211
+ static message: string;
212
+ static code: string;
213
+ }
214
+ /** 403 — the caller is authenticated but lacks permission. */
215
+ declare class ForbiddenException extends AppException {
216
+ static statusCode: number;
217
+ static message: string;
218
+ static code: string;
219
+ }
220
+ /** 422 — input failed a business rule beyond schema validation. */
221
+ declare class ValidationException extends AppException {
222
+ static statusCode: number;
223
+ static message: string;
224
+ static code: string;
225
+ }
226
+ /** 401 — a JWT failed signature or claim validation. */
227
+ declare class InvalidTokenException extends UnauthorizedException {
228
+ static message: string;
229
+ static code: string;
230
+ }
231
+ /** 401 — a JWT's `exp` claim is in the past. */
232
+ declare class ExpiredTokenException extends UnauthorizedException {
233
+ static message: string;
234
+ static code: string;
235
+ }
236
+ /** Options for {@link TooManyRequestsException}, adding a cooldown. */
237
+ interface TooManyRequestsOptions extends AppExceptionOptions {
238
+ /** Cooldown in seconds; sets `Retry-After` and `details.retryAfterSeconds`. */
239
+ retryAfterSeconds?: number;
240
+ }
241
+ /** 429 — the client exceeded a rate limit or attempt budget. */
242
+ declare class TooManyRequestsException extends AppException {
243
+ static statusCode: number;
244
+ static message: string;
245
+ static code: string;
246
+ /**
247
+ * @param options - Standard options plus an optional `retryAfterSeconds`
248
+ * that populates both the `Retry-After` header and `details`.
249
+ */
250
+ constructor(options?: TooManyRequestsOptions);
251
+ }
252
+
253
+ /**
254
+ * Lightweight message localization, mirroring `exceptions.i18n`.
255
+ *
256
+ * A {@link MessageCatalog} maps `code` → `{ locale: template }`. The exception
257
+ * handler negotiates a locale from the request `Accept-Language` header and
258
+ * resolves the exception's `messageKey` (or `code`) into a localized `detail`,
259
+ * interpolating `messageParams` via `{name}` placeholders. A missing
260
+ * translation falls back to the literal message, so partial catalogs are safe.
261
+ */
262
+ /** Default locale used when negotiation finds no match. */
263
+ declare const DEFAULT_LOCALE = "en";
264
+ /** A `code` → (`locale` → template) translation table. */
265
+ type CatalogData = Record<string, Record<string, string>>;
266
+ /**
267
+ * Parse an `Accept-Language` header into locales ordered by descending `q`.
268
+ *
269
+ * @param header - The raw header value, or `null`/`undefined`.
270
+ * @returns Lower-cased language tags, highest quality first.
271
+ */
272
+ declare function parseAcceptLanguage(header: string | null | undefined): string[];
273
+ /** A localized message catalog keyed by error `code`. */
274
+ declare class MessageCatalog {
275
+ private readonly data;
276
+ private readonly defaultLocale;
277
+ /**
278
+ * @param data - The translation table.
279
+ * @param defaultLocale - Locale used when negotiation matches nothing.
280
+ */
281
+ constructor(data?: CatalogData, defaultLocale?: string);
282
+ /**
283
+ * Pick the best locale for an `Accept-Language` header.
284
+ *
285
+ * Matches exact tags first, then the primary subtag (`pt-br` → `pt`),
286
+ * falling back to `defaultLocale`.
287
+ *
288
+ * @param header - The raw `Accept-Language` value.
289
+ * @param defaultLocale - Override the catalog's default for this call.
290
+ * @returns The negotiated locale tag.
291
+ */
292
+ negotiate(header: string | null | undefined, defaultLocale?: string): string;
293
+ /**
294
+ * Resolve a localized message for `code` in `locale`.
295
+ *
296
+ * @param code - The catalog key (an exception's `messageKey` or `code`).
297
+ * @param locale - The negotiated locale.
298
+ * @param params - Values interpolated into the template.
299
+ * @returns The localized string, or `null` when no template exists.
300
+ */
301
+ resolve(code: string, locale: string, params?: Record<string, unknown>): string | null;
302
+ }
303
+ /** Build an empty default catalog. */
304
+ declare function defaultMessageCatalog(): MessageCatalog;
305
+
306
+ /**
307
+ * Zod foundation shared by every DTO, mirroring `schemas.base.BaseSchema`.
308
+ *
309
+ * Pydantic uses class inheritance for shared config; Zod composes instead. This
310
+ * module re-exports a `z` already augmented with `.openapi()` (so every schema
311
+ * can carry OpenAPI metadata) and a {@link toDict} helper matching
312
+ * `BaseSchema.to_dict` (drop nullish, exclude keys, merge extras).
313
+ */
314
+
315
+ /** Options for {@link toDict}. */
316
+ interface ToDictOptions {
317
+ /** Field names to drop from the output. */
318
+ exclude?: string[];
319
+ /** Extra entries merged on top (override existing keys). */
320
+ include?: Record<string, unknown>;
321
+ }
322
+ /**
323
+ * Serialize a validated object to a plain record, dropping `null`/`undefined`,
324
+ * removing `exclude`d keys and merging `include` on top.
325
+ *
326
+ * @param data - The source object (typically a parsed schema).
327
+ * @param options - Keys to exclude and entries to merge in.
328
+ * @returns The cleaned record.
329
+ */
330
+ declare function toDict(data: Record<string, unknown>, options?: ToDictOptions): Record<string, unknown>;
331
+ /**
332
+ * Response schema fields every ORM record carries (`id`, `isActive`,
333
+ * `createdAt`, `updatedAt`). Mirrors `BaseResponseSchema`. Extend it with
334
+ * `baseResponseSchema.extend({ ... })` to build concrete `*ResponseSchema`s.
335
+ */
336
+ declare const baseResponseSchema: z.ZodObject<{
337
+ id: z.ZodString;
338
+ isActive: z.ZodBoolean;
339
+ createdAt: z.ZodDate;
340
+ updatedAt: z.ZodDate;
341
+ }, "strip", z.ZodTypeAny, {
342
+ id: string;
343
+ isActive: boolean;
344
+ createdAt: Date;
345
+ updatedAt: Date;
346
+ }, {
347
+ id: string;
348
+ isActive: boolean;
349
+ createdAt: Date;
350
+ updatedAt: Date;
351
+ }>;
352
+ /** The inferred TS type of a {@link baseResponseSchema} payload. */
353
+ type BaseResponse = z.infer<typeof baseResponseSchema>;
354
+
355
+ /**
356
+ * Pagination request/response primitives, mirroring `schemas.pagination`.
357
+ *
358
+ * Offset pagination ({@link paginationFilterSchema} / {@link paginationSchema})
359
+ * and cursor pagination ({@link cursorPaginationFilterSchema} /
360
+ * {@link cursorPaginationSchema}). Field names match the `tempest-db-js`
361
+ * `BaseRepository.paginate` arguments so a parsed filter forwards through with
362
+ * no renaming.
363
+ */
364
+
365
+ /**
366
+ * Filter schema for offset-paginated list endpoints. Subclass via `.extend`
367
+ * to add domain filters; {@link getConditions} strips the pagination keys.
368
+ */
369
+ declare const paginationFilterSchema: z.ZodObject<{
370
+ page: z.ZodDefault<z.ZodNumber>;
371
+ pageSize: z.ZodDefault<z.ZodNumber>;
372
+ orderBy: z.ZodOptional<z.ZodString>;
373
+ ascending: z.ZodDefault<z.ZodBoolean>;
374
+ }, "strip", z.ZodTypeAny, {
375
+ page: number;
376
+ pageSize: number;
377
+ ascending: boolean;
378
+ orderBy?: string | undefined;
379
+ }, {
380
+ page?: number | undefined;
381
+ pageSize?: number | undefined;
382
+ orderBy?: string | undefined;
383
+ ascending?: boolean | undefined;
384
+ }>;
385
+ /** The parsed shape of {@link paginationFilterSchema}. */
386
+ type PaginationFilter = z.infer<typeof paginationFilterSchema>;
387
+ /**
388
+ * Strip pagination/sort keys from a parsed filter, leaving only domain filters.
389
+ *
390
+ * @param filter - The parsed filter object (may carry extra domain fields).
391
+ * @param options - Extra exclude/include passed through to {@link toDict}.
392
+ * @returns The domain-level filter conditions.
393
+ */
394
+ declare function getConditions(filter: Record<string, unknown>, options?: ToDictOptions): Record<string, unknown>;
395
+ /**
396
+ * The pagination/sort keyword arguments to forward to `BaseRepository.paginate`.
397
+ *
398
+ * @param filter - The parsed pagination filter.
399
+ * @returns `{ page, pageSize, orderBy, ascending }`.
400
+ */
401
+ declare function getPaginationConditions(filter: PaginationFilter): {
402
+ page: number;
403
+ pageSize: number;
404
+ orderBy?: string;
405
+ ascending: boolean;
406
+ };
407
+ /**
408
+ * Build the offset-pagination response envelope for a given item schema.
409
+ *
410
+ * @param item - The zod schema for a single item.
411
+ * @returns A zod object schema `{ items, total, page, pageSize, pages }`.
412
+ */
413
+ declare function paginationSchema<T extends z.ZodTypeAny>(item: T): z.ZodObject<{
414
+ items: z.ZodArray<T, "many">;
415
+ total: z.ZodNumber;
416
+ page: z.ZodNumber;
417
+ pageSize: z.ZodNumber;
418
+ pages: z.ZodNumber;
419
+ }, "strip", z.ZodTypeAny, {
420
+ items: T["_output"][];
421
+ page: number;
422
+ pageSize: number;
423
+ total: number;
424
+ pages: number;
425
+ }, {
426
+ items: T["_input"][];
427
+ page: number;
428
+ pageSize: number;
429
+ total: number;
430
+ pages: number;
431
+ }>;
432
+ /** Filter schema for cursor-paginated endpoints. */
433
+ declare const cursorPaginationFilterSchema: z.ZodObject<{
434
+ cursor: z.ZodOptional<z.ZodString>;
435
+ limit: z.ZodDefault<z.ZodNumber>;
436
+ orderBy: z.ZodDefault<z.ZodString>;
437
+ ascending: z.ZodDefault<z.ZodBoolean>;
438
+ }, "strip", z.ZodTypeAny, {
439
+ orderBy: string;
440
+ ascending: boolean;
441
+ limit: number;
442
+ cursor?: string | undefined;
443
+ }, {
444
+ orderBy?: string | undefined;
445
+ ascending?: boolean | undefined;
446
+ cursor?: string | undefined;
447
+ limit?: number | undefined;
448
+ }>;
449
+ /** The parsed shape of {@link cursorPaginationFilterSchema}. */
450
+ type CursorPaginationFilter = z.infer<typeof cursorPaginationFilterSchema>;
451
+ /**
452
+ * Build the cursor-pagination response envelope for a given item schema.
453
+ *
454
+ * @param item - The zod schema for a single item.
455
+ * @returns A zod object schema `{ items, nextCursor, hasMore, limit }`.
456
+ */
457
+ declare function cursorPaginationSchema<T extends z.ZodTypeAny>(item: T): z.ZodObject<{
458
+ items: z.ZodArray<T, "many">;
459
+ nextCursor: z.ZodNullable<z.ZodString>;
460
+ hasMore: z.ZodBoolean;
461
+ limit: z.ZodNumber;
462
+ }, "strip", z.ZodTypeAny, {
463
+ items: T["_output"][];
464
+ limit: number;
465
+ nextCursor: string | null;
466
+ hasMore: boolean;
467
+ }, {
468
+ items: T["_input"][];
469
+ limit: number;
470
+ nextCursor: string | null;
471
+ hasMore: boolean;
472
+ }>;
473
+ /**
474
+ * Serialize a cursor payload to an opaque URL-safe base64 string (no padding).
475
+ *
476
+ * @param payload - The cursor state, e.g. `{ id, value }`.
477
+ * @returns The encoded cursor.
478
+ */
479
+ declare function encodeCursor(payload: Record<string, unknown>): string;
480
+ /**
481
+ * Decode a cursor produced by {@link encodeCursor}.
482
+ *
483
+ * @param cursor - The opaque cursor string.
484
+ * @returns The decoded payload.
485
+ * @throws {Error} When the cursor is not valid base64 or not a JSON object.
486
+ */
487
+ declare function decodeCursor(cursor: string): Record<string, unknown>;
488
+
489
+ /**
490
+ * Environment-driven settings, mirroring `settings.base.BaseAppSettings`.
491
+ *
492
+ * Pydantic-settings reads env vars into a frozen, validated model. Here a zod
493
+ * schema plays the same role: {@link loadSettings} parses `process.env` (env
494
+ * names are matched case-sensitively, like the FastAPI SDK) and returns a
495
+ * frozen, fully-typed object. Composable fragments ({@link serverSettingsShape}
496
+ * etc.) cover the common server/database/CORS knobs.
497
+ */
498
+
499
+ /** Server bind/runtime settings. Defaults bind to localhost. */
500
+ declare const serverSettingsShape: {
501
+ readonly HOST: z.ZodDefault<z.ZodString>;
502
+ readonly PORT: z.ZodDefault<z.ZodNumber>;
503
+ readonly DEBUG: z.ZodDefault<z.ZodBoolean>;
504
+ };
505
+ /** Database connection settings. */
506
+ declare const databaseSettingsShape: {
507
+ readonly DATABASE_URL: z.ZodDefault<z.ZodString>;
508
+ };
509
+ /** CORS settings. `CORS_ORIGINS` is a comma-separated list. */
510
+ declare const corsSettingsShape: {
511
+ readonly CORS_ORIGINS: z.ZodEffects<z.ZodDefault<z.ZodString>, string[], string | undefined>;
512
+ };
513
+ /** The combined base settings shape (server + database + CORS). */
514
+ declare const baseAppSettingsShape: {
515
+ readonly CORS_ORIGINS: z.ZodEffects<z.ZodDefault<z.ZodString>, string[], string | undefined>;
516
+ readonly DATABASE_URL: z.ZodDefault<z.ZodString>;
517
+ readonly HOST: z.ZodDefault<z.ZodString>;
518
+ readonly PORT: z.ZodDefault<z.ZodNumber>;
519
+ readonly DEBUG: z.ZodDefault<z.ZodBoolean>;
520
+ };
521
+ /** A zod object built from {@link baseAppSettingsShape}. */
522
+ declare const baseAppSettingsSchema: z.ZodObject<{
523
+ readonly CORS_ORIGINS: z.ZodEffects<z.ZodDefault<z.ZodString>, string[], string | undefined>;
524
+ readonly DATABASE_URL: z.ZodDefault<z.ZodString>;
525
+ readonly HOST: z.ZodDefault<z.ZodString>;
526
+ readonly PORT: z.ZodDefault<z.ZodNumber>;
527
+ readonly DEBUG: z.ZodDefault<z.ZodBoolean>;
528
+ }, "strip", z.ZodTypeAny, {
529
+ CORS_ORIGINS: string[];
530
+ DATABASE_URL: string;
531
+ HOST: string;
532
+ PORT: number;
533
+ DEBUG: boolean;
534
+ }, {
535
+ CORS_ORIGINS?: string | undefined;
536
+ DATABASE_URL?: string | undefined;
537
+ HOST?: string | undefined;
538
+ PORT?: number | undefined;
539
+ DEBUG?: boolean | undefined;
540
+ }>;
541
+ /** The parsed shape of {@link baseAppSettingsSchema}. */
542
+ type BaseAppSettings = z.infer<typeof baseAppSettingsSchema>;
543
+ /**
544
+ * Parse and freeze settings from an environment source.
545
+ *
546
+ * Extend the base shape with project fields:
547
+ *
548
+ * ```ts
549
+ * const settings = loadSettings(
550
+ * z.object({ ...baseAppSettingsShape, JWT_SECRET: z.string() }),
551
+ * );
552
+ * ```
553
+ *
554
+ * @param schema - The settings zod schema.
555
+ * @param env - The environment source (defaults to `process.env`).
556
+ * @returns The validated, frozen settings object.
557
+ * @throws {z.ZodError} When required env vars are missing or malformed.
558
+ */
559
+ declare function loadSettings<S extends z.ZodTypeAny>(schema: S, env?: NodeJS.ProcessEnv): Readonly<z.infer<S>>;
560
+
561
+ /**
562
+ * Derive a conventional table name from a model class name: the trailing
563
+ * `Model` suffix is stripped and the rest snake-cased (`UserModel` → `user`).
564
+ *
565
+ * @param className - The model class name.
566
+ * @returns The derived table name.
567
+ */
568
+ declare function tableNameFor(className: string): string;
569
+ /**
570
+ * Abstract base for every model. Concrete models extend it, set a static
571
+ * `tablename`, and declare their own columns:
572
+ *
573
+ * ```ts
574
+ * class UserModel extends BaseModel {
575
+ * static tablename = tableNameFor("UserModel"); // "user"
576
+ * email = column.varchar(320).notNull();
577
+ * name = column.text().notNull();
578
+ * }
579
+ * ```
580
+ */
581
+ declare abstract class BaseModel extends Model {
582
+ /** Primary key — a UUID v4 generated on insert. */
583
+ id: tempest_db_js.Column<string, tempest_db_js.ColumnFlags & {
584
+ primaryKey: true;
585
+ hasDefault: true;
586
+ } & {
587
+ hasDefault: true;
588
+ }>;
589
+ /** Soft-delete flag; `true` means the record is active. */
590
+ isActive: tempest_db_js.Column<boolean, tempest_db_js.ColumnFlags & {
591
+ notNull: true;
592
+ } & {
593
+ hasDefault: true;
594
+ }>;
595
+ /** Creation timestamp, set by the database on insert. */
596
+ createdAt: tempest_db_js.Column<Date, tempest_db_js.ColumnFlags & {
597
+ notNull: true;
598
+ } & {
599
+ hasDefault: true;
600
+ }>;
601
+ /** Last-update timestamp, refreshed by the database on every update. */
602
+ updatedAt: tempest_db_js.Column<Date, tempest_db_js.ColumnFlags & {
603
+ notNull: true;
604
+ } & {
605
+ hasDefault: true;
606
+ }>;
607
+ }
608
+ /**
609
+ * Soft-delete timestamp column (`deleted_at`). `null` while the row is alive;
610
+ * set when soft-deleted. Pairs with {@link BaseModel.isActive}.
611
+ *
612
+ * @returns A nullable datetime column builder, defaulting to `null`.
613
+ */
614
+ declare function deletedAtColumn(): tempest_db_js.Column<Date, tempest_db_js.ColumnFlags>;
615
+ /**
616
+ * `created_by` audit column: UUID of the user that created the row.
617
+ *
618
+ * @returns A nullable UUID column builder.
619
+ */
620
+ declare function createdByColumn(): tempest_db_js.Column<string, tempest_db_js.ColumnFlags>;
621
+ /**
622
+ * `updated_by` audit column: UUID of the user that last updated the row.
623
+ *
624
+ * @returns A nullable UUID column builder.
625
+ */
626
+ declare function updatedByColumn(): tempest_db_js.Column<string, tempest_db_js.ColumnFlags>;
627
+
628
+ /**
629
+ * Generic async service over a `tempest-db-js` repository.
630
+ *
631
+ * Mirrors `services.base.BaseService`: a thin business-logic layer wrapping a
632
+ * `BaseRepository`. Unlike a pure pass-through, every read method maps the raw
633
+ * ORM row through {@link ResponseMapper} into the response shape routers and
634
+ * controllers consume — that mapping is the layer's reason to exist. Override
635
+ * methods that need orchestration (multi-repository writes, side effects,
636
+ * domain rules); leave the rest.
637
+ */
638
+
639
+ /** Maps a raw ORM row to the response shape (sync or async). */
640
+ type ResponseMapper<C extends ModelClass, Resp> = (row: InferModel<C>) => Resp | Promise<Resp>;
641
+ declare class BaseService<C extends ModelClass, Resp> {
642
+ protected readonly repository: BaseRepository<C>;
643
+ protected readonly mapToResponse: ResponseMapper<C, Resp>;
644
+ /**
645
+ * @param repository - The repository to delegate persistence to.
646
+ * @param mapToResponse - Maps a raw row to the response shape.
647
+ */
648
+ constructor(repository: BaseRepository<C>, mapToResponse: ResponseMapper<C, Resp>);
649
+ /** Map a batch of rows to responses, preserving order. */
650
+ protected mapMany(rows: InferModel<C>[]): Promise<Resp[]>;
651
+ /**
652
+ * Fetch a single record by primary key and map it.
653
+ *
654
+ * @param id - The primary-key value.
655
+ * @returns The mapped response.
656
+ * @throws {RecordNotFound} When no row matches (404 convention).
657
+ */
658
+ getById(id: unknown): Promise<Resp>;
659
+ /**
660
+ * List records matching `filters` (or all), mapped to responses.
661
+ *
662
+ * @param filters - Optional filter conditions.
663
+ * @returns The mapped responses; `[]` when nothing matches.
664
+ */
665
+ list(filters?: WhereInput<InferModel<C>>): Promise<Resp[]>;
666
+ /**
667
+ * Count records matching `filters` (or the whole table).
668
+ *
669
+ * @param filters - Optional filter conditions.
670
+ * @returns The matching row count.
671
+ */
672
+ count(filters?: WhereInput<InferModel<C>>): Promise<number>;
673
+ /**
674
+ * Insert one record and map the created row.
675
+ *
676
+ * @param data - The insert payload.
677
+ * @returns The mapped, created response.
678
+ */
679
+ create(data: InferInsert<C>): Promise<Resp>;
680
+ /**
681
+ * Update records matching `filters`.
682
+ *
683
+ * @param filters - Which rows to update.
684
+ * @param set - The partial column values to write.
685
+ * @returns The number of rows affected.
686
+ */
687
+ update(filters: WhereInput<InferModel<C>>, set: Partial<InferModel<C>>): Promise<number>;
688
+ /**
689
+ * Delete records matching `filters`.
690
+ *
691
+ * @param filters - Which rows to delete.
692
+ * @returns The number of rows affected.
693
+ */
694
+ delete(filters: WhereInput<InferModel<C>>): Promise<number>;
695
+ /**
696
+ * Fetch a page of records with the items mapped to responses.
697
+ *
698
+ * @param filter - Page, size, ordering and filters.
699
+ * @returns The page envelope with mapped items.
700
+ */
701
+ paginate(filter?: PaginationFilter$1<InferModel<C>>): Promise<PaginationResult<Resp>>;
702
+ }
703
+
704
+ /**
705
+ * Generic controller bridging routers and services.
706
+ *
707
+ * Mirrors `controllers.base.BaseController`. Per the SDK layering
708
+ * (router → controller → service → repository), controllers are an intentional
709
+ * abstraction boundary kept present even when no orchestration is required, so
710
+ * the import graph stays uniform across services. Override a method when one
711
+ * endpoint must call several services or apply cross-cutting policy; otherwise
712
+ * the thin delegations stand in for the boundary.
713
+ */
714
+
715
+ declare class BaseController<C extends ModelClass, Resp> {
716
+ protected readonly service: BaseService<C, Resp>;
717
+ /**
718
+ * @param service - The service the controller delegates to.
719
+ */
720
+ constructor(service: BaseService<C, Resp>);
721
+ /**
722
+ * Fetch one record by primary key.
723
+ *
724
+ * @param id - The primary-key value.
725
+ * @returns The mapped response.
726
+ */
727
+ getById(id: unknown): Promise<Resp>;
728
+ /**
729
+ * List records matching `filters`.
730
+ *
731
+ * @param filters - Optional filter conditions.
732
+ * @returns The mapped responses.
733
+ */
734
+ list(filters?: WhereInput<InferModel<C>>): Promise<Resp[]>;
735
+ /**
736
+ * Count records matching `filters`.
737
+ *
738
+ * @param filters - Optional filter conditions.
739
+ * @returns The matching row count.
740
+ */
741
+ count(filters?: WhereInput<InferModel<C>>): Promise<number>;
742
+ /**
743
+ * Create a record.
744
+ *
745
+ * @param data - The insert payload.
746
+ * @returns The mapped, created response.
747
+ */
748
+ create(data: InferInsert<C>): Promise<Resp>;
749
+ /**
750
+ * Update records matching `filters`.
751
+ *
752
+ * @param filters - Which rows to update.
753
+ * @param set - The partial column values to write.
754
+ * @returns The number of rows affected.
755
+ */
756
+ update(filters: WhereInput<InferModel<C>>, set: Partial<InferModel<C>>): Promise<number>;
757
+ /**
758
+ * Delete records matching `filters`.
759
+ *
760
+ * @param filters - Which rows to delete.
761
+ * @returns The number of rows affected.
762
+ */
763
+ delete(filters: WhereInput<InferModel<C>>): Promise<number>;
764
+ /**
765
+ * Fetch a page of records.
766
+ *
767
+ * @param filter - Page, size, ordering and filters.
768
+ * @returns The page envelope with mapped items.
769
+ */
770
+ paginate(filter?: PaginationFilter$1<InferModel<C>>): Promise<PaginationResult<Resp>>;
771
+ }
772
+
773
+ /**
774
+ * Brazilian identity/contact helpers, mirroring `utils.regex`.
775
+ *
776
+ * Patterns, validators (format + check digits), normalizers, and ready-to-use
777
+ * Zod field schemas for the fields that show up in almost every BR API: CPF,
778
+ * CNPJ, CEP and phone. Validators accept masked or unmasked input; normalizers
779
+ * strip masks to a canonical digits-only form (and throw on invalid input).
780
+ */
781
+
782
+ /** Match a CPF in masked (`000.000.000-00`) or raw form. */
783
+ declare const CPF_PATTERN: RegExp;
784
+ /** Match a CNPJ in masked (`00.000.000/0000-00`) or raw form. */
785
+ declare const CNPJ_PATTERN: RegExp;
786
+ /** Match a BR phone with optional `+55`, DDD, mask or 9th digit. */
787
+ declare const PHONE_BR_PATTERN: RegExp;
788
+ /** Match a CEP in masked (`00000-000`) or raw form. */
789
+ declare const CEP_PATTERN: RegExp;
790
+ /**
791
+ * Strip every non-digit character from `value`.
792
+ *
793
+ * @param value - The raw input (masked CPF, phone, etc.).
794
+ * @returns A string of only the digits in `value`.
795
+ */
796
+ declare function onlyDigits(value: string): string;
797
+ /** Whether `value` is a syntactically valid CPF (format + check digits). */
798
+ declare function isValidCpf(value: string): boolean;
799
+ /** Whether `value` is a syntactically valid CNPJ (format + check digits). */
800
+ declare function isValidCnpj(value: string): boolean;
801
+ /** Whether `value` is a valid CPF or CNPJ. */
802
+ declare function isValidCpfCnpj(value: string): boolean;
803
+ /** Whether `value` looks like a CEP (eight-digit shape; no check digits). */
804
+ declare function isValidCep(value: string): boolean;
805
+ /** Whether `value` looks like a BR phone (10 or 11 digits, optional `+55`). */
806
+ declare function isValidPhoneBr(value: string): boolean;
807
+ /** Normalize a CPF to 11 digits, throwing when invalid. */
808
+ declare function normalizeCpf(value: string): string;
809
+ /** Normalize a CNPJ to 14 digits, throwing when invalid. */
810
+ declare function normalizeCnpj(value: string): string;
811
+ /** Normalize a CPF/CNPJ to digits only, throwing when invalid. */
812
+ declare function normalizeCpfCnpj(value: string): string;
813
+ /** Normalize a CEP to 8 digits, throwing when invalid. */
814
+ declare function normalizeCep(value: string): string;
815
+ /** Normalize a BR phone to digits only, throwing when invalid. */
816
+ declare function normalizePhoneBr(value: string): string;
817
+ /** Zod field: validates a CPF and normalizes it to 11 digits. */
818
+ declare const cpfField: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
819
+ /** Zod field: validates a CNPJ and normalizes it to 14 digits. */
820
+ declare const cnpjField: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
821
+ /** Zod field: accepts either a CPF or a CNPJ, normalized to digits. */
822
+ declare const cpfOrCnpjField: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
823
+ /** Zod field: validates a CEP and normalizes it to 8 digits. */
824
+ declare const cepField: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
825
+ /** Zod field: validates a BR phone and normalizes it to digits. */
826
+ declare const phoneBrField: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
827
+
828
+ /** The 27 Brazilian federative-unit acronyms. */
829
+ declare const UF: Enum<{
830
+ readonly AC: "AC";
831
+ readonly AL: "AL";
832
+ readonly AP: "AP";
833
+ readonly AM: "AM";
834
+ readonly BA: "BA";
835
+ readonly CE: "CE";
836
+ readonly DF: "DF";
837
+ readonly ES: "ES";
838
+ readonly GO: "GO";
839
+ readonly MA: "MA";
840
+ readonly MT: "MT";
841
+ readonly MS: "MS";
842
+ readonly MG: "MG";
843
+ readonly PA: "PA";
844
+ readonly PB: "PB";
845
+ readonly PR: "PR";
846
+ readonly PE: "PE";
847
+ readonly PI: "PI";
848
+ readonly RJ: "RJ";
849
+ readonly RN: "RN";
850
+ readonly RS: "RS";
851
+ readonly RO: "RO";
852
+ readonly RR: "RR";
853
+ readonly SC: "SC";
854
+ readonly SP: "SP";
855
+ readonly SE: "SE";
856
+ readonly TO: "TO";
857
+ }>;
858
+ /** A federative-unit acronym. */
859
+ type UFValue = ReturnType<typeof UF.values>[number];
860
+ /** The five official IBGE macro-regions. */
861
+ declare const Region: Enum<{
862
+ readonly NORTH: "Norte";
863
+ readonly NORTHEAST: "Nordeste";
864
+ readonly CENTRAL_WEST: "Centro-Oeste";
865
+ readonly SOUTHEAST: "Sudeste";
866
+ readonly SOUTH: "Sul";
867
+ }>;
868
+ /** A macro-region value. */
869
+ type RegionValue = ReturnType<typeof Region.values>[number];
870
+ /** A Brazilian federative unit and its municipalities. */
871
+ interface StateBR {
872
+ /** Federative-unit acronym (e.g. `"SP"`). */
873
+ uf: string;
874
+ /** Full state name (e.g. `"São Paulo"`). */
875
+ name: string;
876
+ /** The IBGE macro-region the state belongs to. */
877
+ region: RegionValue;
878
+ /** Alphabetically sorted municipality names. */
879
+ cities: string[];
880
+ }
881
+ /** All states, ordered by acronym. */
882
+ declare function listStates(): StateBR[];
883
+ /** The state for a UF acronym (case-insensitive), or `null`. */
884
+ declare function getState(uf: string): StateBR | null;
885
+ /** The municipalities of a UF, or `[]` for an unknown UF. */
886
+ declare function citiesByUf(uf: string): string[];
887
+ /** All states in a macro-region. */
888
+ declare function statesByRegion(region: RegionValue): StateBR[];
889
+ /** Whether `value` is a known UF acronym (case-insensitive). */
890
+ declare function isValidUf(value: string): boolean;
891
+ /** Normalize a UF to its uppercase acronym, throwing when unknown. */
892
+ declare function normalizeUf(value: string): string;
893
+ /** Whether `name` is a municipality of `uf` (accent/case-insensitive). */
894
+ declare function isValidCity(name: string, uf: string): boolean;
895
+ /** Zod field: validates a UF and normalizes it to its uppercase acronym. */
896
+ declare const ufField: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
897
+
898
+ /** Datetime helpers, mirroring `utils.datetime`. */
899
+ /**
900
+ * Return the current instant. JavaScript `Date` is always UTC-based internally;
901
+ * serialize with `.toISOString()` for a UTC wire format.
902
+ *
903
+ * @returns The current `Date`.
904
+ */
905
+ declare function utcnow(): Date;
906
+ /**
907
+ * Coerce a value to a `Date`. Accepts a `Date`, an ISO string or an epoch
908
+ * milliseconds number.
909
+ *
910
+ * @param value - The value to normalize.
911
+ * @returns The corresponding `Date`.
912
+ * @throws {Error} When the value cannot be parsed to a valid date.
913
+ */
914
+ declare function toUtc(value: Date | string | number): Date;
915
+
916
+ /** Dictionary helpers, mirroring `utils.dict`. */
917
+ /**
918
+ * Filter and extend a record in a single pass: drop `exclude`d keys and merge
919
+ * `include` on top (merged entries win).
920
+ *
921
+ * @param data - The source record.
922
+ * @param exclude - Keys to drop from the output.
923
+ * @param include - Extra entries to merge in.
924
+ * @returns A new record with the requested mutations.
925
+ */
926
+ declare function modifyDict(data: Record<string, unknown>, exclude?: string[], include?: Record<string, unknown>): Record<string, unknown>;
927
+
928
+ /**
929
+ * Single-use opaque tokens hashed at rest, mirroring `utils.opaque_token`.
930
+ *
931
+ * For flows where a secret is emailed/SMS'd and later presented back (password
932
+ * reset, email verification, magic links, API keys). The plaintext is shown
933
+ * once; only its SHA-256 digest is stored, so a DB leak exposes no usable
934
+ * tokens. Verification hashes the incoming plaintext and compares in constant
935
+ * time. Pure standard library (`node:crypto`).
936
+ */
937
+ /**
938
+ * Return the SHA-256 hex digest of a token's plaintext.
939
+ *
940
+ * @param plaintext - The token value to hash.
941
+ * @returns A 64-character lowercase hex digest.
942
+ */
943
+ declare function hashOpaqueToken(plaintext: string): string;
944
+ /**
945
+ * Generate a cryptographically random token and its digest.
946
+ *
947
+ * @param nbytes - Entropy in bytes for the URL-safe token (default 32).
948
+ * @returns `{ plaintext, tokenHash }` — show `plaintext` once, store `tokenHash`.
949
+ */
950
+ declare function generateOpaqueToken(nbytes?: number): {
951
+ plaintext: string;
952
+ tokenHash: string;
953
+ };
954
+ /**
955
+ * Constant-time check that `plaintext` hashes to `tokenHash`.
956
+ *
957
+ * @param plaintext - The token submitted by the caller.
958
+ * @param tokenHash - The stored SHA-256 hex digest.
959
+ * @returns `true` when the hashes match.
960
+ */
961
+ declare function verifyOpaqueToken(plaintext: string, tokenHash: string): boolean;
962
+
963
+ /**
964
+ * Password hashing backed by bcrypt, mirroring `utils.password.PasswordUtils`.
965
+ *
966
+ * `bcryptjs` is an optional peer dependency, imported lazily so that
967
+ * `import "tempest-express-sdk"` keeps working when it is not installed — the
968
+ * clear error is deferred to first use. Methods are async (the idiomatic Node
969
+ * bcrypt surface).
970
+ */
971
+ /** Hash and verify passwords using bcrypt. Stateless — construct once, reuse. */
972
+ declare class PasswordUtils {
973
+ private readonly rounds;
974
+ /**
975
+ * @param rounds - The bcrypt cost factor. Higher is slower and harder to
976
+ * brute-force. Defaults to 12.
977
+ */
978
+ constructor(rounds?: number);
979
+ /**
980
+ * Hash a plaintext password.
981
+ *
982
+ * @param plain - The plaintext password.
983
+ * @returns The bcrypt hash, ready to persist.
984
+ */
985
+ hash(plain: string): Promise<string>;
986
+ /**
987
+ * Verify a plaintext password against a stored hash. Returns `false` for
988
+ * malformed hashes rather than throwing.
989
+ *
990
+ * @param plain - The plaintext password to verify.
991
+ * @param hashed - The previously stored bcrypt hash.
992
+ * @returns `true` when the password matches.
993
+ */
994
+ verify(plain: string, hashed: string): Promise<boolean>;
995
+ }
996
+
997
+ /**
998
+ * JWT encode/decode backed by `jsonwebtoken`, mirroring `utils.jwt.JWTUtils`.
999
+ *
1000
+ * `jsonwebtoken` is an optional peer dependency, imported lazily so the SDK
1001
+ * imports without it; the clear error is deferred to first use. Every token
1002
+ * gets `iat`/`exp` automatically; pass `issuer` to add and verify `iss`.
1003
+ * Expired/invalid tokens raise the SDK's {@link ExpiredTokenException} /
1004
+ * {@link InvalidTokenException}.
1005
+ */
1006
+ /** JWT claims — a free-form payload. */
1007
+ type JwtClaims = Record<string, unknown>;
1008
+ /** Options for {@link JWTUtils}. */
1009
+ interface JWTUtilsOptions {
1010
+ /** Signing algorithm. Defaults to `HS256`. */
1011
+ algorithm?: "HS256" | "HS384" | "HS512" | "RS256" | "ES256";
1012
+ /** Default token lifetime in seconds. Defaults to 3600 (1 hour). */
1013
+ defaultTtlSeconds?: number;
1014
+ /** Value for the `iss` claim; when set, `decode` verifies it. */
1015
+ issuer?: string;
1016
+ }
1017
+ /** Encode and decode JWTs using a shared secret (or asymmetric key). */
1018
+ declare class JWTUtils {
1019
+ private readonly secret;
1020
+ private readonly algorithm;
1021
+ private readonly defaultTtlSeconds;
1022
+ private readonly issuer;
1023
+ /**
1024
+ * @param secret - The signing key (HMAC secret or private key).
1025
+ * @param options - Algorithm, default TTL and optional issuer.
1026
+ */
1027
+ constructor(secret: string, options?: JWTUtilsOptions);
1028
+ /**
1029
+ * Encode `payload` as a signed JWT.
1030
+ *
1031
+ * @param payload - Claims to include (typically `{ sub: "<user-id>" }`).
1032
+ * @param options - Override the default TTL for this call.
1033
+ * @returns The compact-serialized JWT.
1034
+ */
1035
+ encode(payload: JwtClaims, options?: {
1036
+ ttlSeconds?: number;
1037
+ }): Promise<string>;
1038
+ /**
1039
+ * Decode and verify a JWT.
1040
+ *
1041
+ * @param token - The token to decode.
1042
+ * @returns The decoded claims.
1043
+ * @throws {ExpiredTokenException} When `exp` is in the past.
1044
+ * @throws {InvalidTokenException} For any other validation failure.
1045
+ */
1046
+ decode(token: string): Promise<JwtClaims>;
1047
+ /**
1048
+ * Decode and verify a JWT, returning `null` on failure (soft auth).
1049
+ *
1050
+ * @param token - The token to decode.
1051
+ * @returns The decoded claims, or `null` when invalid/expired.
1052
+ */
1053
+ decodeOrNull(token: string): Promise<JwtClaims | null>;
1054
+ }
1055
+
1056
+ /**
1057
+ * Attempt throttling, mirroring `utils.throttle`.
1058
+ *
1059
+ * Sliding-window attempt counter for flows that must resist brute force
1060
+ * (login, OTP, code verification). The default {@link MemoryThrottleBackend} is
1061
+ * process-local; swap in a shared backend (e.g. Redis) for multi-instance
1062
+ * deployments by implementing {@link ThrottleBackend}.
1063
+ */
1064
+ /** The outcome of recording or inspecting an attempt. */
1065
+ interface ThrottleStatus {
1066
+ /** Whether the attempt is allowed (budget not yet exhausted). */
1067
+ allowed: boolean;
1068
+ /** Remaining attempts in the current window (never negative). */
1069
+ remaining: number;
1070
+ /** Seconds until the window resets (`0` when allowed). */
1071
+ retryAfterSeconds: number;
1072
+ }
1073
+ /** Pluggable storage of attempt timestamps per key. */
1074
+ interface ThrottleBackend {
1075
+ /** Record an attempt at `now` (epoch ms) and return timestamps in-window. */
1076
+ hit(key: string, windowMs: number, now: number): Promise<number[]>;
1077
+ /** Read the in-window attempt timestamps without recording a new one. */
1078
+ peek(key: string, windowMs: number, now: number): Promise<number[]>;
1079
+ /** Clear all recorded attempts for `key`. */
1080
+ reset(key: string): Promise<void>;
1081
+ }
1082
+ /** Process-local {@link ThrottleBackend} backed by a `Map`. */
1083
+ declare class MemoryThrottleBackend implements ThrottleBackend {
1084
+ private readonly store;
1085
+ private window;
1086
+ hit(key: string, windowMs: number, now: number): Promise<number[]>;
1087
+ peek(key: string, windowMs: number, now: number): Promise<number[]>;
1088
+ reset(key: string): Promise<void>;
1089
+ }
1090
+ /** Options for {@link AttemptThrottle}. */
1091
+ interface AttemptThrottleOptions {
1092
+ /** Maximum attempts allowed within the window. */
1093
+ maxAttempts: number;
1094
+ /** Sliding-window length in seconds. */
1095
+ windowSeconds: number;
1096
+ /** Storage backend. Defaults to a {@link MemoryThrottleBackend}. */
1097
+ backend?: ThrottleBackend;
1098
+ }
1099
+ /** A sliding-window attempt limiter keyed by an arbitrary string. */
1100
+ declare class AttemptThrottle {
1101
+ private readonly maxAttempts;
1102
+ private readonly windowMs;
1103
+ private readonly backend;
1104
+ /**
1105
+ * @param options - Budget, window and optional backend.
1106
+ */
1107
+ constructor(options: AttemptThrottleOptions);
1108
+ /** Build a status from a set of in-window attempt timestamps. */
1109
+ private status;
1110
+ /**
1111
+ * Inspect the current budget for `key` without recording an attempt.
1112
+ *
1113
+ * @param key - The throttle key (e.g. `login:<ip>`).
1114
+ * @returns The current status.
1115
+ */
1116
+ check(key: string): Promise<ThrottleStatus>;
1117
+ /**
1118
+ * Record an attempt for `key` and return the resulting status.
1119
+ *
1120
+ * @param key - The throttle key.
1121
+ * @returns The status after recording the attempt.
1122
+ */
1123
+ hit(key: string): Promise<ThrottleStatus>;
1124
+ /**
1125
+ * Clear all recorded attempts for `key` (e.g. after a successful login).
1126
+ *
1127
+ * @param key - The throttle key.
1128
+ */
1129
+ reset(key: string): Promise<void>;
1130
+ }
1131
+
1132
+ /**
1133
+ * Auth DTOs (Zod), mirroring `auth.schemas`.
1134
+ *
1135
+ * Request/response schemas for the bundled signup/login/refresh flows. All are
1136
+ * OpenAPI-registered shapes so they render in Swagger/Redoc when the auth
1137
+ * router's paths are registered.
1138
+ */
1139
+
1140
+ /** Request body for `POST /auth/signup`. */
1141
+ declare const signupSchema: z.ZodObject<{
1142
+ email: z.ZodString;
1143
+ password: z.ZodString;
1144
+ name: z.ZodOptional<z.ZodString>;
1145
+ }, "strip", z.ZodTypeAny, {
1146
+ password: string;
1147
+ email: string;
1148
+ name?: string | undefined;
1149
+ }, {
1150
+ password: string;
1151
+ email: string;
1152
+ name?: string | undefined;
1153
+ }>;
1154
+ /** Request body for `POST /auth/login`. */
1155
+ declare const loginSchema: z.ZodObject<{
1156
+ email: z.ZodString;
1157
+ password: z.ZodString;
1158
+ }, "strip", z.ZodTypeAny, {
1159
+ password: string;
1160
+ email: string;
1161
+ }, {
1162
+ password: string;
1163
+ email: string;
1164
+ }>;
1165
+ /** Request body for `POST /auth/refresh`. */
1166
+ declare const refreshSchema: z.ZodObject<{
1167
+ refreshToken: z.ZodString;
1168
+ }, "strip", z.ZodTypeAny, {
1169
+ refreshToken: string;
1170
+ }, {
1171
+ refreshToken: string;
1172
+ }>;
1173
+ /** A signed access/refresh token pair. */
1174
+ declare const tokenPairSchema: z.ZodObject<{
1175
+ accessToken: z.ZodString;
1176
+ refreshToken: z.ZodString;
1177
+ tokenType: z.ZodLiteral<"bearer">;
1178
+ expiresIn: z.ZodNumber;
1179
+ }, "strip", z.ZodTypeAny, {
1180
+ refreshToken: string;
1181
+ accessToken: string;
1182
+ tokenType: "bearer";
1183
+ expiresIn: number;
1184
+ }, {
1185
+ refreshToken: string;
1186
+ accessToken: string;
1187
+ tokenType: "bearer";
1188
+ expiresIn: number;
1189
+ }>;
1190
+ /** Public user projection returned by `GET /auth/me` and signup/login. */
1191
+ declare const userPublicSchema: z.ZodObject<{
1192
+ id: z.ZodString;
1193
+ email: z.ZodString;
1194
+ name: z.ZodNullable<z.ZodString>;
1195
+ isActive: z.ZodBoolean;
1196
+ roles: z.ZodArray<z.ZodString, "many">;
1197
+ }, "strip", z.ZodTypeAny, {
1198
+ id: string;
1199
+ isActive: boolean;
1200
+ email: string;
1201
+ name: string | null;
1202
+ roles: string[];
1203
+ }, {
1204
+ id: string;
1205
+ isActive: boolean;
1206
+ email: string;
1207
+ name: string | null;
1208
+ roles: string[];
1209
+ }>;
1210
+ /** Response body for `POST /auth/signup` and `POST /auth/login`. */
1211
+ declare const authResponseSchema: z.ZodObject<{
1212
+ user: z.ZodObject<{
1213
+ id: z.ZodString;
1214
+ email: z.ZodString;
1215
+ name: z.ZodNullable<z.ZodString>;
1216
+ isActive: z.ZodBoolean;
1217
+ roles: z.ZodArray<z.ZodString, "many">;
1218
+ }, "strip", z.ZodTypeAny, {
1219
+ id: string;
1220
+ isActive: boolean;
1221
+ email: string;
1222
+ name: string | null;
1223
+ roles: string[];
1224
+ }, {
1225
+ id: string;
1226
+ isActive: boolean;
1227
+ email: string;
1228
+ name: string | null;
1229
+ roles: string[];
1230
+ }>;
1231
+ tokens: z.ZodObject<{
1232
+ accessToken: z.ZodString;
1233
+ refreshToken: z.ZodString;
1234
+ tokenType: z.ZodLiteral<"bearer">;
1235
+ expiresIn: z.ZodNumber;
1236
+ }, "strip", z.ZodTypeAny, {
1237
+ refreshToken: string;
1238
+ accessToken: string;
1239
+ tokenType: "bearer";
1240
+ expiresIn: number;
1241
+ }, {
1242
+ refreshToken: string;
1243
+ accessToken: string;
1244
+ tokenType: "bearer";
1245
+ expiresIn: number;
1246
+ }>;
1247
+ }, "strip", z.ZodTypeAny, {
1248
+ user: {
1249
+ id: string;
1250
+ isActive: boolean;
1251
+ email: string;
1252
+ name: string | null;
1253
+ roles: string[];
1254
+ };
1255
+ tokens: {
1256
+ refreshToken: string;
1257
+ accessToken: string;
1258
+ tokenType: "bearer";
1259
+ expiresIn: number;
1260
+ };
1261
+ }, {
1262
+ user: {
1263
+ id: string;
1264
+ isActive: boolean;
1265
+ email: string;
1266
+ name: string | null;
1267
+ roles: string[];
1268
+ };
1269
+ tokens: {
1270
+ refreshToken: string;
1271
+ accessToken: string;
1272
+ tokenType: "bearer";
1273
+ expiresIn: number;
1274
+ };
1275
+ }>;
1276
+ type SignupInput = z.infer<typeof signupSchema>;
1277
+ type LoginInput = z.infer<typeof loginSchema>;
1278
+ type RefreshInput = z.infer<typeof refreshSchema>;
1279
+ type TokenPair = z.infer<typeof tokenPairSchema>;
1280
+ type UserPublic = z.infer<typeof userPublicSchema>;
1281
+ type AuthResponse = z.infer<typeof authResponseSchema>;
1282
+
1283
+ /**
1284
+ * User authentication service, mirroring `auth.service.UserAuthService`.
1285
+ *
1286
+ * Orchestrates signup / login / refresh over a pluggable {@link UserStore},
1287
+ * {@link PasswordUtils} and {@link JWTUtils}. It is ORM-agnostic — back the
1288
+ * store with a `tempest-db-js` repository (or anything else). MFA, email
1289
+ * activation and password-reset flows from the FastAPI SDK are not yet ported.
1290
+ */
1291
+
1292
+ /** A persisted user as the auth layer needs to see it. */
1293
+ interface AuthUser {
1294
+ /** Stable user id (string form). */
1295
+ id: string;
1296
+ /** Login email (lowercased by the service before lookup/create). */
1297
+ email: string;
1298
+ /** The stored bcrypt password hash. */
1299
+ passwordHash: string;
1300
+ /** Display name, or `null`. */
1301
+ name: string | null;
1302
+ /** Whether the account may log in. */
1303
+ isActive: boolean;
1304
+ /** Assigned role names. */
1305
+ roles: string[];
1306
+ }
1307
+ /** Persistence port the service depends on. Implement over any store. */
1308
+ interface UserStore {
1309
+ /** Find a user by (lowercased) email, or `null`. */
1310
+ findByEmail(email: string): Promise<AuthUser | null>;
1311
+ /** Find a user by id, or `null`. */
1312
+ findById(id: string): Promise<AuthUser | null>;
1313
+ /** Create a user from validated signup data + a password hash. */
1314
+ create(data: {
1315
+ email: string;
1316
+ passwordHash: string;
1317
+ name: string | null;
1318
+ }): Promise<AuthUser>;
1319
+ }
1320
+ /** Options for {@link UserAuthService}. */
1321
+ interface UserAuthServiceOptions {
1322
+ /** The user persistence port. */
1323
+ store: UserStore;
1324
+ /** Password hasher/verifier. */
1325
+ password: PasswordUtils;
1326
+ /** JWT encoder/decoder used to mint access + refresh tokens. */
1327
+ jwt: JWTUtils;
1328
+ /** Minimum password length enforced server-side. Default 12. */
1329
+ passwordMinLength?: number;
1330
+ /** Access-token lifetime in seconds. Default 3600. */
1331
+ accessTtlSeconds?: number;
1332
+ /** Refresh-token lifetime in seconds. Default 1209600 (14 days). */
1333
+ refreshTtlSeconds?: number;
1334
+ }
1335
+ declare class UserAuthService {
1336
+ private readonly store;
1337
+ private readonly password;
1338
+ private readonly jwt;
1339
+ private readonly passwordMinLength;
1340
+ private readonly accessTtlSeconds;
1341
+ private readonly refreshTtlSeconds;
1342
+ /**
1343
+ * @param options - Store, password/JWT helpers and token policy.
1344
+ */
1345
+ constructor(options: UserAuthServiceOptions);
1346
+ /** Mint a signed access + refresh token pair for `user`. */
1347
+ private issueTokens;
1348
+ /**
1349
+ * Register a new user and issue tokens.
1350
+ *
1351
+ * @param data - Validated signup payload.
1352
+ * @returns The public user and a fresh token pair.
1353
+ * @throws {ValidationException} When the password is too short.
1354
+ * @throws {ConflictException} When the email is already registered.
1355
+ */
1356
+ signup(data: SignupInput): Promise<AuthResponse>;
1357
+ /**
1358
+ * Authenticate a user by email + password.
1359
+ *
1360
+ * @param data - Validated login payload.
1361
+ * @returns The public user and a fresh token pair.
1362
+ * @throws {UnauthorizedException} On bad credentials or inactive account.
1363
+ */
1364
+ login(data: LoginInput): Promise<AuthResponse>;
1365
+ /**
1366
+ * Exchange a valid refresh token for a new token pair.
1367
+ *
1368
+ * @param refreshToken - The refresh token from a prior login.
1369
+ * @returns The public user and a fresh token pair.
1370
+ * @throws {UnauthorizedException} When the token is invalid or not a refresh
1371
+ * token, or the user no longer exists / is inactive.
1372
+ */
1373
+ refresh(refreshToken: string): Promise<AuthResponse>;
1374
+ }
1375
+
1376
+ /**
1377
+ * JWT auth middleware + role guards, mirroring `api.dependencies.auth`.
1378
+ *
1379
+ * {@link makeJwtAuthMiddleware} decodes a `Bearer` token and attaches the
1380
+ * claims to `req.auth`; {@link requireRoles} gates a route on role membership.
1381
+ * Failures raise the SDK's {@link UnauthorizedException} / {@link ForbiddenException}
1382
+ * so they render as the canonical error envelope.
1383
+ */
1384
+
1385
+ declare global {
1386
+ namespace Express {
1387
+ /** Decoded JWT claims, populated by {@link makeJwtAuthMiddleware}. */
1388
+ interface Request {
1389
+ auth?: JwtClaims;
1390
+ }
1391
+ }
1392
+ }
1393
+ /** Extract a `Bearer` token from the `Authorization` header, or `null`. */
1394
+ declare function bearerToken(req: Request): string | null;
1395
+ /** Read the decoded claims attached by the auth middleware, or `null`. */
1396
+ declare function getAuth(req: Request): JwtClaims | null;
1397
+ /** Options for {@link makeJwtAuthMiddleware}. */
1398
+ interface JwtAuthOptions {
1399
+ /** When `true` (default), a missing/invalid token rejects with 401. */
1400
+ required?: boolean;
1401
+ }
1402
+ /**
1403
+ * Build middleware that decodes the bearer token and sets `req.auth`.
1404
+ *
1405
+ * @param jwt - The JWT helper used to verify tokens.
1406
+ * @param options - Whether authentication is required.
1407
+ * @returns An Express middleware.
1408
+ */
1409
+ declare function makeJwtAuthMiddleware(jwt: JWTUtils, options?: JwtAuthOptions): RequestHandler;
1410
+ /**
1411
+ * Build middleware that requires the authenticated user to hold at least one
1412
+ * of `roles` (read from the `roles` claim). Must run after the auth middleware.
1413
+ *
1414
+ * @param roles - Acceptable role names.
1415
+ * @returns An Express middleware.
1416
+ */
1417
+ declare function requireRoles(...roles: string[]): RequestHandler;
1418
+
1419
+ /**
1420
+ * OpenAPI document generation from Zod schemas.
1421
+ *
1422
+ * Thin wrapper over `@asteasolutions/zod-to-openapi`. Register schemas and
1423
+ * paths on a {@link OpenAPIRegistry}, then call {@link generateOpenApiDocument}
1424
+ * to produce a spec that drives both Swagger UI and Redoc. Because every SDK
1425
+ * schema is built from the `.openapi()`-augmented `z`, descriptions, examples
1426
+ * and component names flow straight into the document.
1427
+ */
1428
+
1429
+ /** Minimal `info` block for the generated document. */
1430
+ interface OpenApiInfo {
1431
+ /** API title shown in the docs header. */
1432
+ title: string;
1433
+ /** API version string. */
1434
+ version: string;
1435
+ /** Optional long description (Markdown supported by the renderers). */
1436
+ description?: string;
1437
+ }
1438
+ /** Options for {@link generateOpenApiDocument}. */
1439
+ interface GenerateOpenApiOptions {
1440
+ /** The document `info` block. */
1441
+ info: OpenApiInfo;
1442
+ /** Server entries (`{ url, description }`). */
1443
+ servers?: Array<{
1444
+ url: string;
1445
+ description?: string;
1446
+ }>;
1447
+ /** Emit OpenAPI 3.1 instead of 3.0. Default `false` (3.0). */
1448
+ v31?: boolean;
1449
+ }
1450
+ /**
1451
+ * Create a fresh, empty {@link OpenAPIRegistry}.
1452
+ *
1453
+ * @returns A registry to register schemas and paths on.
1454
+ */
1455
+ declare function createOpenApiRegistry(): OpenAPIRegistry;
1456
+ /**
1457
+ * Generate an OpenAPI document from a populated registry.
1458
+ *
1459
+ * @param registry - The registry holding registered schemas and paths.
1460
+ * @param options - The `info` block, optional servers and version flag.
1461
+ * @returns The generated OpenAPI document (plain object, JSON-serializable).
1462
+ */
1463
+ declare function generateOpenApiDocument(registry: OpenAPIRegistry, options: GenerateOpenApiOptions): Record<string, unknown>;
1464
+
1465
+ /**
1466
+ * Auth router, mirroring `auth.router.make_auth_router`.
1467
+ *
1468
+ * Wires `POST /auth/signup`, `POST /auth/login`, `POST /auth/refresh` and a
1469
+ * guarded `GET /auth/me` to a {@link UserAuthService}. Pass an
1470
+ * {@link OpenAPIRegistry} to register the paths so they appear in Swagger/Redoc.
1471
+ */
1472
+
1473
+ /** Options for {@link makeAuthRouter}. */
1474
+ interface AuthRouterOptions {
1475
+ /** The authentication service handling the flows. */
1476
+ service: UserAuthService;
1477
+ /** The JWT helper used to guard `GET /auth/me`. */
1478
+ jwt: JWTUtils;
1479
+ /** Route prefix. Default `/auth`. */
1480
+ prefix?: string;
1481
+ /** When provided, OpenAPI paths are registered for Swagger/Redoc. */
1482
+ registry?: OpenAPIRegistry;
1483
+ }
1484
+ /**
1485
+ * Build the auth router.
1486
+ *
1487
+ * @param options - Service, JWT helper, prefix and optional OpenAPI registry.
1488
+ * @returns An Express router exposing the auth endpoints.
1489
+ */
1490
+ declare function makeAuthRouter(options: AuthRouterOptions): Router;
1491
+
1492
+ /**
1493
+ * Express error handling, mirroring `api.handlers`.
1494
+ *
1495
+ * Produces the canonical SDK envelope `{ detail, code, details }` for every
1496
+ * failure path: {@link AppException} subclasses, Zod validation errors (→ 422),
1497
+ * unmatched routes (→ 404) and uncaught errors (→ 500). A {@link MessageCatalog}
1498
+ * localizes `detail` from the request `Accept-Language` header. Server errors
1499
+ * are logged with the {@link HTTP_500_MARKER} flag for sink routing.
1500
+ */
1501
+
1502
+ /** Header carrying the per-request correlation id. */
1503
+ declare const REQUEST_ID_HEADER = "X-Request-ID";
1504
+ /**
1505
+ * Middleware that establishes a request id and binds the request context.
1506
+ *
1507
+ * Reuses an inbound `X-Request-ID` when present, otherwise generates one, sets
1508
+ * it on the response, and runs the rest of the chain inside
1509
+ * {@link runWithRequestContext} so loggers and handlers can read it.
1510
+ *
1511
+ * @returns The configured middleware.
1512
+ */
1513
+ declare function requestIdMiddleware(): RequestHandler;
1514
+ /** Options for {@link makeAppExceptionHandler}. */
1515
+ interface AppExceptionHandlerOptions {
1516
+ /** Catalog used to localize `detail`; `null` keeps the literal message. */
1517
+ catalog?: MessageCatalog | null;
1518
+ /** Locale used when `Accept-Language` is absent or unmatched. */
1519
+ defaultLocale?: string;
1520
+ /** Level used for 5xx `AppException` records (4xx always logs at `info`). */
1521
+ serverErrorLevel?: LogLevel;
1522
+ }
1523
+ /**
1524
+ * Build the error middleware for {@link AppException} subclasses.
1525
+ *
1526
+ * Zod errors are coerced into a 422 envelope (`code: "VALIDATION_ERROR"`) with
1527
+ * the field issues under `details.issues`. Anything else is passed to `next`.
1528
+ *
1529
+ * @param options - Localization and logging options.
1530
+ * @returns An Express error middleware.
1531
+ */
1532
+ declare function makeAppExceptionHandler(options?: AppExceptionHandlerOptions): ErrorRequestHandler;
1533
+ /** Options for {@link makeUnhandledExceptionHandler}. */
1534
+ interface UnhandledExceptionHandlerOptions {
1535
+ /** Surface the stack under `details.stack` (development only). */
1536
+ includeStack?: boolean;
1537
+ /** Level used to log the failure. */
1538
+ logLevel?: LogLevel;
1539
+ }
1540
+ /**
1541
+ * Build the catch-all error middleware for non-{@link AppException} errors.
1542
+ *
1543
+ * Logs the failure (flagged with {@link HTTP_500_MARKER}) and returns the
1544
+ * canonical 500 envelope. With `includeStack` the stack is added to the body —
1545
+ * never enable in production.
1546
+ *
1547
+ * @param options - Stack-exposure and logging options.
1548
+ * @returns An Express error middleware.
1549
+ */
1550
+ declare function makeUnhandledExceptionHandler(options?: UnhandledExceptionHandlerOptions): ErrorRequestHandler;
1551
+ /**
1552
+ * Build the fallback 404 handler for unmatched routes.
1553
+ *
1554
+ * @returns A request handler emitting the canonical 404 envelope.
1555
+ */
1556
+ declare function notFoundHandler(): RequestHandler;
1557
+ /** Options for {@link registerExceptionHandlers}. */
1558
+ interface RegisterExceptionHandlersOptions extends AppExceptionHandlerOptions, UnhandledExceptionHandlerOptions {
1559
+ /** Register the {@link notFoundHandler} for unmatched routes. Default `true`. */
1560
+ notFound?: boolean;
1561
+ }
1562
+ /**
1563
+ * Register the full error-handling stack on an Express app.
1564
+ *
1565
+ * Call this AFTER all routers are mounted. Order: 404 fallback (optional) →
1566
+ * {@link AppException}/Zod handler → catch-all 500 handler.
1567
+ *
1568
+ * @param app - The Express application.
1569
+ * @param options - Localization, logging and 404 options.
1570
+ */
1571
+ declare function registerExceptionHandlers(app: Express, options?: RegisterExceptionHandlersOptions): void;
1572
+
1573
+ /**
1574
+ * Native Swagger UI and Redoc mounting from a generated OpenAPI document.
1575
+ *
1576
+ * Swagger UI is served fully self-contained: its static assets ship with the
1577
+ * `swagger-ui-dist` dependency and are mounted locally (no CDN), with a small
1578
+ * inline initializer pointing at the spec endpoint. Redoc is served as a single
1579
+ * HTML page that loads the Redoc standalone bundle from a CDN (the renderer is
1580
+ * ~1 MB and intentionally not vendored); override {@link RedocOptions.scriptUrl}
1581
+ * to self-host it.
1582
+ */
1583
+
1584
+ /** A JSON-serializable OpenAPI document. */
1585
+ type OpenApiDocument = Record<string, unknown>;
1586
+ /**
1587
+ * Mount the OpenAPI document as JSON at `path`.
1588
+ *
1589
+ * @param app - The Express application.
1590
+ * @param path - Route to serve the document at (e.g. `/openapi.json`).
1591
+ * @param document - The generated OpenAPI document.
1592
+ */
1593
+ declare function mountOpenApiJson(app: Express, path: string, document: OpenApiDocument): void;
1594
+ /** Options for {@link mountSwaggerUi}. */
1595
+ interface SwaggerOptions {
1596
+ /** Page title. Default `"API docs"`. */
1597
+ title?: string;
1598
+ }
1599
+ /**
1600
+ * Mount Swagger UI at `path`, reading the spec from `specUrl`.
1601
+ *
1602
+ * Static assets are served from `${path}/assets` so the page is fully offline.
1603
+ *
1604
+ * @param app - The Express application.
1605
+ * @param path - Mount path for the UI (e.g. `/docs`).
1606
+ * @param specUrl - URL the UI fetches the OpenAPI document from.
1607
+ * @param options - Page options.
1608
+ */
1609
+ declare function mountSwaggerUi(app: Express, path: string, specUrl: string, options?: SwaggerOptions): void;
1610
+ /** Options for {@link mountRedoc}. */
1611
+ interface RedocOptions {
1612
+ /** Page title. Default `"API reference"`. */
1613
+ title?: string;
1614
+ /** URL of the Redoc standalone bundle. Defaults to the jsDelivr CDN. */
1615
+ scriptUrl?: string;
1616
+ }
1617
+ /**
1618
+ * Mount Redoc at `path`, reading the spec from `specUrl`.
1619
+ *
1620
+ * @param app - The Express application.
1621
+ * @param path - Mount path for Redoc (e.g. `/redoc`).
1622
+ * @param specUrl - URL Redoc fetches the OpenAPI document from.
1623
+ * @param options - Page and bundle options.
1624
+ */
1625
+ declare function mountRedoc(app: Express, path: string, specUrl: string, options?: RedocOptions): void;
1626
+
1627
+ /**
1628
+ * Health-check router, mirroring `api.routers.health`.
1629
+ *
1630
+ * A meta endpoint mounted at the root prefix (not under `/api`). Returns a
1631
+ * small JSON status payload and runs any registered async checks, surfacing
1632
+ * their pass/fail under `checks` and degrading the HTTP status to 503 when any
1633
+ * check fails.
1634
+ */
1635
+
1636
+ /** A named async health probe returning `true` when healthy. */
1637
+ interface HealthCheck {
1638
+ /** Probe name, surfaced under `checks`. */
1639
+ name: string;
1640
+ /** The probe; resolves `true` when the dependency is healthy. */
1641
+ check: () => Promise<boolean> | boolean;
1642
+ }
1643
+ /** Options for {@link makeHealthRouter}. */
1644
+ interface HealthRouterOptions {
1645
+ /** Route path within the router. Default `/health`. */
1646
+ path?: string;
1647
+ /** Optional dependency probes (e.g. database, cache). */
1648
+ checks?: HealthCheck[];
1649
+ }
1650
+ /**
1651
+ * Build a health-check router.
1652
+ *
1653
+ * @param options - Path and dependency probes.
1654
+ * @returns An Express router exposing the health endpoint.
1655
+ */
1656
+ declare function makeHealthRouter(options?: HealthRouterOptions): Router;
1657
+
1658
+ /**
1659
+ * Application factory and server runner, mirroring `api.app` + `api.server`.
1660
+ *
1661
+ * {@link createApp} wires the conventional middleware stack (JSON body parsing,
1662
+ * request-id propagation, optional CORS), mounts the health endpoint, lets the
1663
+ * caller register routers and OpenAPI paths via a `configure` hook, mounts
1664
+ * native Swagger UI + Redoc, then registers the error-handling stack last.
1665
+ * {@link runServer} starts listening and logs the bound address.
1666
+ */
1667
+
1668
+ /** OpenAPI documentation configuration for {@link createApp}. */
1669
+ interface CreateAppOpenApi extends GenerateOpenApiOptions {
1670
+ /** Registry holding the registered schemas and paths. */
1671
+ registry: OpenAPIRegistry;
1672
+ /** Route serving the spec JSON. Default `/openapi.json`. */
1673
+ jsonPath?: string;
1674
+ /** Swagger UI mount path, or `false` to disable. Default `/docs`. */
1675
+ swaggerPath?: string | false;
1676
+ /** Redoc mount path, or `false` to disable. Default `/redoc`. */
1677
+ redocPath?: string | false;
1678
+ /** Extra Swagger UI options. */
1679
+ swagger?: SwaggerOptions;
1680
+ /** Extra Redoc options. */
1681
+ redoc?: RedocOptions;
1682
+ }
1683
+ /** Options for {@link createApp}. */
1684
+ interface CreateAppOptions {
1685
+ /** Allowed CORS origins. `"*"` or a list; omit/`false` to disable CORS. */
1686
+ corsOrigins?: string | string[] | false;
1687
+ /** Health endpoint options, or `false` to omit it. Default mounts `/health`. */
1688
+ health?: HealthRouterOptions | false;
1689
+ /** Hook to mount routers and register OpenAPI paths before the error stack. */
1690
+ configure?: (app: Express) => void | Promise<void>;
1691
+ /** OpenAPI docs configuration; omit to skip Swagger/Redoc. */
1692
+ openapi?: CreateAppOpenApi;
1693
+ /** Message catalog for localized error responses. */
1694
+ catalog?: MessageCatalog;
1695
+ /** Error-handling options forwarded to {@link registerExceptionHandlers}. */
1696
+ errorHandling?: Omit<RegisterExceptionHandlersOptions, "catalog">;
1697
+ /** JSON body size limit (e.g. `"1mb"`). Default `"100kb"`. */
1698
+ jsonLimit?: string;
1699
+ }
1700
+ /**
1701
+ * Build a fully wired Express application.
1702
+ *
1703
+ * @param options - Middleware, health, OpenAPI docs and error options.
1704
+ * @returns The configured Express app, ready to {@link runServer}.
1705
+ */
1706
+ declare function createApp(options?: CreateAppOptions): Promise<Express>;
1707
+ /** Options for {@link runServer}. */
1708
+ interface RunServerOptions {
1709
+ /** Bind host. Default `127.0.0.1`. */
1710
+ host?: string;
1711
+ /** Bind port. Default `8000`. */
1712
+ port?: number;
1713
+ }
1714
+ /**
1715
+ * Start listening and log the bound address.
1716
+ *
1717
+ * @param app - The Express application from {@link createApp}.
1718
+ * @param options - Host and port.
1719
+ * @returns A promise resolving to the live HTTP server once listening.
1720
+ */
1721
+ declare function runServer(app: Express, options?: RunServerOptions): Promise<Server>;
1722
+
1723
+ /** The installed SDK version. Single source of truth for the barrel + CLI. */
1724
+ declare const VERSION = "0.1.0";
1725
+
1726
+ export { AppException, type AppExceptionHandlerOptions, type AppExceptionOptions, AttemptThrottle, type AttemptThrottleOptions, type AuthResponse, type AuthRouterOptions, type AuthUser, type BaseAppSettings, BaseController, BaseModel, type BaseResponse, BaseService, CEP_PATTERN, CNPJ_PATTERN, CPF_PATTERN, type CatalogData, ConflictException, type CreateAppOpenApi, type CreateAppOptions, type CursorPaginationFilter, DEFAULT_LOCALE, type Enum, type EnumHelpers, type EnumSpec, type ExceptionDetails, ExpiredTokenException, ForbiddenException, type GenerateOpenApiOptions, HTTP_500_MARKER, type HealthCheck, type HealthRouterOptions, InvalidTokenException, JSONLogger, JWTUtils, type JWTUtilsOptions, type JwtAuthOptions, type JwtClaims, type LogExtra, type LogLevel, type LoginInput, MemoryThrottleBackend, MessageCatalog, NotFoundException, type OpenApiDocument, type OpenApiInfo, PHONE_BR_PATTERN, type PaginationFilter, PasswordUtils, REQUEST_ID_HEADER, type RedocOptions, type RefreshInput, Region, type RegionValue, type RegisterExceptionHandlersOptions, type RequestContext, type ResponseMapper, type RunServerOptions, type SignupInput, type StateBR, type SwaggerOptions, type ThrottleBackend, type ThrottleStatus, type ToDictOptions, type TokenPair, TooManyRequestsException, type TooManyRequestsOptions, UF, type UFValue, UnauthorizedException, type UnhandledExceptionHandlerOptions, UserAuthService, type UserAuthServiceOptions, type UserPublic, type UserStore, VERSION, ValidationException, authResponseSchema, baseAppSettingsSchema, baseAppSettingsShape, baseResponseSchema, bearerToken, cepField, citiesByUf, cnpjField, configureLogging, corsSettingsShape, cpfField, cpfOrCnpjField, createApp, createOpenApiRegistry, createdByColumn, cursorPaginationFilterSchema, cursorPaginationSchema, databaseSettingsShape, decodeCursor, defaultMessageCatalog, defineEnum, deletedAtColumn, encodeCursor, generateOpaqueToken, generateOpenApiDocument, getAuth, getConditions, getPaginationConditions, getRequestId, getState, hashOpaqueToken, isValidCep, isValidCity, isValidCnpj, isValidCpf, isValidCpfCnpj, isValidPhoneBr, isValidUf, listStates, loadSettings, loginSchema, makeAppExceptionHandler, makeAuthRouter, makeHealthRouter, makeJwtAuthMiddleware, makeUnhandledExceptionHandler, modifyDict, mountOpenApiJson, mountRedoc, mountSwaggerUi, normalizeCep, normalizeCnpj, normalizeCpf, normalizeCpfCnpj, normalizePhoneBr, normalizeUf, notFoundHandler, onlyDigits, paginationFilterSchema, paginationSchema, parseAcceptLanguage, phoneBrField, refreshSchema, registerExceptionHandlers, requestIdMiddleware, requireRoles, runServer, runWithRequestContext, serverSettingsShape, setRequestId, signupSchema, statesByRegion, tableNameFor, toDict, toUtc, tokenPairSchema, ufField, updatedByColumn, userPublicSchema, utcnow, verifyOpaqueToken };