tempest-express-sdk 0.1.0 → 0.3.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.
package/dist/index.d.cts CHANGED
@@ -3,10 +3,11 @@ export { z } from 'zod';
3
3
  import * as tempest_db_js from 'tempest-db-js';
4
4
  import { Model, ModelClass, BaseRepository, InferModel, WhereInput, InferInsert, PaginationFilter as PaginationFilter$1, PaginationResult } from 'tempest-db-js';
5
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';
6
+ import { Request, RequestHandler, Response as Response$1, Router, ErrorRequestHandler, Express } from 'express';
7
+ import * as ws from 'ws';
8
+ import { Server } from 'node:http';
7
9
  import { OpenAPIRegistry } from '@asteasolutions/zod-to-openapi';
8
10
  export { OpenAPIRegistry } from '@asteasolutions/zod-to-openapi';
9
- import { Server } from 'node:http';
10
11
 
11
12
  /**
12
13
  * Request-scoped context propagation via `AsyncLocalStorage`.
@@ -1129,6 +1130,1120 @@ declare class AttemptThrottle {
1129
1130
  reset(key: string): Promise<void>;
1130
1131
  }
1131
1132
 
1133
+ /**
1134
+ * Trusted client-IP resolution, mirroring `utils.client_ip`.
1135
+ *
1136
+ * Reading the leftmost `X-Forwarded-For` entry is a security hole — that header
1137
+ * is client-controlled. Resolve from a SINGLE header the edge proxy sets itself
1138
+ * (e.g. `X-Real-IP`, `CF-Connecting-IP`), falling back to the socket peer.
1139
+ */
1140
+
1141
+ /** Options for {@link getClientIp}. */
1142
+ interface ClientIpOptions {
1143
+ /**
1144
+ * Name of the single edge-set header to trust (case-insensitive, e.g.
1145
+ * `"x-real-ip"`). Omit to use only the transport peer.
1146
+ */
1147
+ trustedHeader?: string;
1148
+ }
1149
+ /**
1150
+ * Resolve the client IP from an Express request.
1151
+ *
1152
+ * @param req - The inbound request.
1153
+ * @param options - The trusted header to read, if any.
1154
+ * @returns The resolved IP, or `"unknown"` when unavailable.
1155
+ */
1156
+ declare function getClientIp(req: Request, options?: ClientIpOptions): string;
1157
+
1158
+ /**
1159
+ * TOTP (RFC 6238) helper for MFA, mirroring `utils.totp.TOTPHelper`.
1160
+ *
1161
+ * Implemented natively over `node:crypto` (HMAC-SHA1) — no external OTP library
1162
+ * needed. Generates a base32 secret, builds the `otpauth://` provisioning URI
1163
+ * (scanned as a QR code), and verifies a 6-digit code with a clock-drift window.
1164
+ */
1165
+ /** Options for {@link TOTPHelper}. */
1166
+ interface TOTPOptions {
1167
+ /** Label shown in the authenticator app (e.g. the product name). */
1168
+ issuer: string;
1169
+ /** Time step in seconds. Default 30. */
1170
+ step?: number;
1171
+ /** Number of digits. Default 6. */
1172
+ digits?: number;
1173
+ }
1174
+ /** Stateless TOTP issuer + verifier. Construct one per app. */
1175
+ declare class TOTPHelper {
1176
+ private readonly issuer;
1177
+ private readonly step;
1178
+ private readonly digits;
1179
+ /**
1180
+ * @param options - Issuer label, time step and digit count.
1181
+ */
1182
+ constructor(options: TOTPOptions);
1183
+ /**
1184
+ * Generate a fresh base32 secret (80 bits).
1185
+ *
1186
+ * @returns A base32-encoded TOTP secret to persist on the user row.
1187
+ */
1188
+ generateSecret(): string;
1189
+ /**
1190
+ * Build the `otpauth://` provisioning URI (render as a QR code).
1191
+ *
1192
+ * @param secret - The base32 secret.
1193
+ * @param accountName - Identifier shown next to the issuer (e.g. the email).
1194
+ * @returns The `otpauth://totp/...` URI.
1195
+ */
1196
+ provisioningUri(secret: string, accountName: string): string;
1197
+ /**
1198
+ * Verify a code against the secret for the current time window.
1199
+ *
1200
+ * @param secret - The base32 secret.
1201
+ * @param code - The submitted code.
1202
+ * @param window - Tolerance in steps (±). Default 1 (previous/current/next).
1203
+ * @returns `true` when the code matches within the window.
1204
+ */
1205
+ verify(secret: string, code: string, window?: number): boolean;
1206
+ }
1207
+
1208
+ /**
1209
+ * Resilient HTTP client, mirroring `utils.http_client`.
1210
+ *
1211
+ * Wraps the native `fetch` with a retry policy (exponential backoff) and a
1212
+ * per-host circuit breaker: after N consecutive failures the breaker opens and
1213
+ * requests to that host fail fast with {@link CircuitOpenError} until a cooldown
1214
+ * elapses. No external dependency.
1215
+ */
1216
+ /** Raised when the per-host circuit breaker is open. */
1217
+ declare class CircuitOpenError extends Error {
1218
+ readonly host: string;
1219
+ constructor(host: string);
1220
+ }
1221
+ /** Retry configuration for {@link HTTPClient}. */
1222
+ declare class RetryPolicy {
1223
+ readonly maxRetries: number;
1224
+ readonly baseDelayMs: number;
1225
+ readonly retryOn: number[];
1226
+ /**
1227
+ * @param maxRetries - Additional attempts after the first. Default 2.
1228
+ * @param baseDelayMs - Base backoff in ms (doubles each attempt). Default 100.
1229
+ * @param retryOn - HTTP status codes that trigger a retry. Default 5xx + 429.
1230
+ */
1231
+ constructor(maxRetries?: number, baseDelayMs?: number, retryOn?: number[]);
1232
+ /** Backoff delay in ms before `attempt` (0-indexed). */
1233
+ sleepFor(attempt: number): number;
1234
+ }
1235
+ /** Options for {@link HTTPClient}. */
1236
+ interface HTTPClientOptions {
1237
+ /** Prepended to relative request paths. */
1238
+ baseUrl?: string;
1239
+ /** Headers merged into every request. */
1240
+ defaultHeaders?: Record<string, string>;
1241
+ /** Per-request timeout in ms. Default 30000. */
1242
+ timeoutMs?: number;
1243
+ /** Retry configuration. */
1244
+ retryPolicy?: RetryPolicy;
1245
+ /** Consecutive failures before the breaker opens. Default 5. */
1246
+ breakerThreshold?: number;
1247
+ /** Breaker cooldown in ms once open. Default 30000. */
1248
+ breakerCooldownMs?: number;
1249
+ }
1250
+ /** A `fetch` wrapper with retries and a per-host circuit breaker. */
1251
+ declare class HTTPClient {
1252
+ private readonly baseUrl;
1253
+ private readonly defaultHeaders;
1254
+ private readonly timeoutMs;
1255
+ private readonly retryPolicy;
1256
+ private readonly breakerThreshold;
1257
+ private readonly breakerCooldownMs;
1258
+ private readonly breakers;
1259
+ /**
1260
+ * @param options - Base URL, headers, timeout, retry and breaker settings.
1261
+ */
1262
+ constructor(options?: HTTPClientOptions);
1263
+ private resolve;
1264
+ private hostOf;
1265
+ private breakerCheck;
1266
+ private breakerRecord;
1267
+ /**
1268
+ * Perform a request with retries and breaker protection.
1269
+ *
1270
+ * @param method - HTTP method.
1271
+ * @param url - Absolute URL or a path resolved against `baseUrl`.
1272
+ * @param init - Extra `fetch` init (headers, body, …).
1273
+ * @returns The `Response`.
1274
+ * @throws {CircuitOpenError} When the per-host breaker is open.
1275
+ */
1276
+ request(method: string, url: string, init?: RequestInit): Promise<Response>;
1277
+ private sleep;
1278
+ /** GET request. */
1279
+ get(url: string, init?: RequestInit): Promise<Response>;
1280
+ /** POST request. */
1281
+ post(url: string, init?: RequestInit): Promise<Response>;
1282
+ /** PUT request. */
1283
+ put(url: string, init?: RequestInit): Promise<Response>;
1284
+ /** PATCH request. */
1285
+ patch(url: string, init?: RequestInit): Promise<Response>;
1286
+ /** DELETE request. */
1287
+ delete(url: string, init?: RequestInit): Promise<Response>;
1288
+ }
1289
+
1290
+ /**
1291
+ * System metrics, mirroring `utils.metrics.MetricsUtils`.
1292
+ *
1293
+ * Reads CPU, memory and process stats from Node's built-in `node:os` /
1294
+ * `process` — no native dependency (GPU metrics from the FastAPI SDK are out of
1295
+ * scope here). Includes a Prometheus text-format exporter.
1296
+ */
1297
+ /** CPU load metrics. */
1298
+ interface CPUMetrics {
1299
+ /** Number of logical cores. */
1300
+ cores: number;
1301
+ /** 1-minute load average (0 on platforms without load average). */
1302
+ load1: number;
1303
+ /** Load average over 1 minute as a fraction of core count. */
1304
+ loadPercent: number;
1305
+ }
1306
+ /** Memory usage metrics (bytes). */
1307
+ interface MemoryMetrics {
1308
+ /** Total system memory. */
1309
+ total: number;
1310
+ /** Free system memory. */
1311
+ free: number;
1312
+ /** Used system memory. */
1313
+ used: number;
1314
+ /** Used memory as a percentage of total. */
1315
+ usedPercent: number;
1316
+ /** Resident set size of the current process. */
1317
+ processRss: number;
1318
+ }
1319
+ /** A snapshot of system + process metrics. */
1320
+ interface SystemMetrics {
1321
+ cpu: CPUMetrics;
1322
+ memory: MemoryMetrics;
1323
+ /** Process uptime in seconds. */
1324
+ uptimeSeconds: number;
1325
+ }
1326
+ /** Read CPU load metrics. */
1327
+ declare function readCpu(): CPUMetrics;
1328
+ /** Read memory usage metrics. */
1329
+ declare function readMemory(): MemoryMetrics;
1330
+ /** Read a full system snapshot. */
1331
+ declare function readSystem(): SystemMetrics;
1332
+ /**
1333
+ * Render a snapshot as Prometheus text-format metrics.
1334
+ *
1335
+ * @param snapshot - A snapshot (defaults to a fresh {@link readSystem}).
1336
+ * @returns The Prometheus exposition text.
1337
+ */
1338
+ declare function toPrometheus(snapshot?: SystemMetrics): string;
1339
+ /** Stateless system-metrics reader + Prometheus exporter. */
1340
+ declare const MetricsUtils: {
1341
+ readonly cpu: typeof readCpu;
1342
+ readonly memory: typeof readMemory;
1343
+ readonly system: typeof readSystem;
1344
+ readonly toPrometheus: typeof toPrometheus;
1345
+ };
1346
+
1347
+ /**
1348
+ * Transactional email, mirroring `utils.email.EmailUtils`.
1349
+ *
1350
+ * Wraps the optional `nodemailer` peer (lazily imported) behind a tiny
1351
+ * `send` surface. The transport is created once from SMTP options and reused.
1352
+ */
1353
+ /** SMTP connection + sender options. */
1354
+ interface EmailOptions {
1355
+ /** SMTP host. */
1356
+ host: string;
1357
+ /** SMTP port. Default 587. */
1358
+ port?: number;
1359
+ /** Use TLS on connect. Default `false` (STARTTLS on 587). */
1360
+ secure?: boolean;
1361
+ /** SMTP auth user. */
1362
+ user?: string;
1363
+ /** SMTP auth password. */
1364
+ password?: string;
1365
+ /** Default `From` address. */
1366
+ from: string;
1367
+ }
1368
+ /** A single email message. */
1369
+ interface EmailMessage {
1370
+ /** Recipient(s). */
1371
+ to: string | string[];
1372
+ /** Subject line. */
1373
+ subject: string;
1374
+ /** Plain-text body. */
1375
+ text?: string;
1376
+ /** HTML body. */
1377
+ html?: string;
1378
+ /** Override the default `From`. */
1379
+ from?: string;
1380
+ }
1381
+ /** Sends transactional email over SMTP via `nodemailer`. */
1382
+ declare class EmailUtils {
1383
+ private readonly options;
1384
+ private transport;
1385
+ /**
1386
+ * @param options - SMTP connection and default sender.
1387
+ */
1388
+ constructor(options: EmailOptions);
1389
+ private ready;
1390
+ /**
1391
+ * Send an email message.
1392
+ *
1393
+ * @param message - The message (recipients, subject, body).
1394
+ */
1395
+ send(message: EmailMessage): Promise<void>;
1396
+ }
1397
+
1398
+ /**
1399
+ * Cache managers, mirroring `cache.redis_manager`.
1400
+ *
1401
+ * A narrow async cache interface ({@link CacheManager}) with two backends: an
1402
+ * in-process {@link MemoryCacheManager} (dev/tests/single replica) and a
1403
+ * {@link RedisCacheManager} backed by the optional `redis` peer (lazily
1404
+ * imported, like the auth helpers). Values are JSON-serialized.
1405
+ */
1406
+ /** Narrow async cache surface every backend implements. */
1407
+ interface CacheManager {
1408
+ /** Read a value by key, or `null` when missing/expired. */
1409
+ get<T>(key: string): Promise<T | null>;
1410
+ /** Write a value with an optional TTL in seconds. */
1411
+ set<T>(key: string, value: T, ttlSeconds?: number): Promise<void>;
1412
+ /** Delete a key. Idempotent. */
1413
+ delete(key: string): Promise<void>;
1414
+ /** Whether a live (non-expired) value exists for `key`. */
1415
+ has(key: string): Promise<boolean>;
1416
+ /** Remove every entry. */
1417
+ clear(): Promise<void>;
1418
+ }
1419
+ /** In-process {@link CacheManager} backed by a `Map`, with lazy TTL expiry. */
1420
+ declare class MemoryCacheManager implements CacheManager {
1421
+ private readonly store;
1422
+ private live;
1423
+ get<T>(key: string): Promise<T | null>;
1424
+ set<T>(key: string, value: T, ttlSeconds?: number): Promise<void>;
1425
+ delete(key: string): Promise<void>;
1426
+ has(key: string): Promise<boolean>;
1427
+ clear(): Promise<void>;
1428
+ }
1429
+ /** A minimal subset of the `redis` client this manager relies on. */
1430
+ interface RedisLike {
1431
+ get(key: string): Promise<string | null>;
1432
+ set(key: string, value: string, options?: {
1433
+ EX?: number;
1434
+ }): Promise<unknown>;
1435
+ del(key: string): Promise<unknown>;
1436
+ exists(key: string): Promise<number>;
1437
+ flushDb(): Promise<unknown>;
1438
+ }
1439
+ /** Redis-backed {@link CacheManager}. Pass a connected `redis` v4 client. */
1440
+ declare class RedisCacheManager implements CacheManager {
1441
+ private readonly client;
1442
+ private readonly prefix;
1443
+ /**
1444
+ * @param client - A connected `redis` (node-redis v4) client or compatible.
1445
+ * @param prefix - Optional key prefix applied to every operation.
1446
+ */
1447
+ constructor(client: RedisLike, prefix?: string);
1448
+ private key;
1449
+ get<T>(key: string): Promise<T | null>;
1450
+ set<T>(key: string, value: T, ttlSeconds?: number): Promise<void>;
1451
+ delete(key: string): Promise<void>;
1452
+ has(key: string): Promise<boolean>;
1453
+ clear(): Promise<void>;
1454
+ }
1455
+
1456
+ /**
1457
+ * Read-through memoization helper, mirroring `cache.decorator.cached`.
1458
+ *
1459
+ * Wraps an async function so its result is cached under a derived key. On a hit
1460
+ * the cached value is returned without calling the function; on a miss the
1461
+ * function runs and its result is stored with an optional TTL.
1462
+ */
1463
+
1464
+ /** Options for {@link cached}. */
1465
+ interface CachedOptions<A extends unknown[]> {
1466
+ /** The cache backend to read/write. */
1467
+ manager: CacheManager;
1468
+ /** Build the cache key from the call arguments. */
1469
+ key: (...args: A) => string;
1470
+ /** TTL in seconds for stored values. Omit for no expiry. */
1471
+ ttlSeconds?: number;
1472
+ }
1473
+ /**
1474
+ * Wrap an async function with read-through caching.
1475
+ *
1476
+ * @param fn - The async function to memoize.
1477
+ * @param options - Cache backend, key builder and optional TTL.
1478
+ * @returns A function with the same signature, served from cache when possible.
1479
+ *
1480
+ * @example
1481
+ * ```ts
1482
+ * const getUser = cached(fetchUser, {
1483
+ * manager,
1484
+ * key: (id: string) => `user:${id}`,
1485
+ * ttlSeconds: 60,
1486
+ * });
1487
+ * ```
1488
+ */
1489
+ declare function cached<A extends unknown[], R>(fn: (...args: A) => Promise<R>, options: CachedOptions<A>): (...args: A) => Promise<R>;
1490
+
1491
+ /**
1492
+ * Session model + store, mirroring `sessions.store` / `sessions.schemas`.
1493
+ *
1494
+ * Sessions are keyed by the SHA-256 hash of the opaque cookie value, so a leak
1495
+ * of the store yields no reusable cookies. The {@link SessionStore} interface is
1496
+ * narrow; {@link MemorySessionStore} is the in-process implementation for
1497
+ * dev/tests/single-replica (a Redis store is a planned follow-up).
1498
+ */
1499
+ /** A persisted session row. */
1500
+ interface Session {
1501
+ /** SHA-256 hash of the opaque cookie value (the store key). */
1502
+ idHash: string;
1503
+ /** The owning user id. */
1504
+ userId: string;
1505
+ /** Arbitrary JSON-serializable session payload. */
1506
+ data: Record<string, unknown>;
1507
+ /** Creation timestamp (epoch ms). */
1508
+ createdAt: number;
1509
+ /** Expiry timestamp (epoch ms). */
1510
+ expiresAt: number;
1511
+ }
1512
+ /** Persistence port every session backend implements. */
1513
+ interface SessionStore {
1514
+ /** Return the live session for `idHash`, or `null` when missing/expired. */
1515
+ get(idHash: string): Promise<Session | null>;
1516
+ /** Persist or overwrite a session. */
1517
+ set(session: Session): Promise<void>;
1518
+ /** Remove a single session. Idempotent. */
1519
+ delete(idHash: string): Promise<void>;
1520
+ /** Remove every session for `userId`; returns the count deleted. */
1521
+ deleteByUser(userId: string): Promise<number>;
1522
+ /** Return every live session for `userId` (oldest first). */
1523
+ listByUser(userId: string): Promise<Session[]>;
1524
+ }
1525
+ /** In-process {@link SessionStore} with a secondary user index. */
1526
+ declare class MemorySessionStore implements SessionStore {
1527
+ private readonly byHash;
1528
+ private live;
1529
+ get(idHash: string): Promise<Session | null>;
1530
+ set(session: Session): Promise<void>;
1531
+ delete(idHash: string): Promise<void>;
1532
+ deleteByUser(userId: string): Promise<number>;
1533
+ listByUser(userId: string): Promise<Session[]>;
1534
+ }
1535
+
1536
+ /**
1537
+ * Session service, mirroring `sessions.service`.
1538
+ *
1539
+ * Issues opaque session cookies, persists only their SHA-256 hash, and resolves
1540
+ * an incoming cookie back to a live {@link Session}. Built on the SDK's opaque
1541
+ * token helpers so the store never holds a usable cookie value.
1542
+ */
1543
+
1544
+ /** Options for {@link SessionService}. */
1545
+ interface SessionServiceOptions {
1546
+ /** The backing store. */
1547
+ store: SessionStore;
1548
+ /** Default session lifetime in seconds. Default 604800 (7 days). */
1549
+ ttlSeconds?: number;
1550
+ }
1551
+ /** A freshly created session and its one-time plaintext cookie value. */
1552
+ interface IssuedSession {
1553
+ /** The opaque cookie value to set on the client (shown once). */
1554
+ token: string;
1555
+ /** The persisted session row. */
1556
+ session: Session;
1557
+ }
1558
+ declare class SessionService {
1559
+ private readonly store;
1560
+ private readonly ttlSeconds;
1561
+ /**
1562
+ * @param options - Store and default TTL.
1563
+ */
1564
+ constructor(options: SessionServiceOptions);
1565
+ /**
1566
+ * Create a session for `userId` and return its one-time cookie value.
1567
+ *
1568
+ * @param userId - The owning user id.
1569
+ * @param data - Arbitrary session payload.
1570
+ * @param ttlSeconds - Override the default lifetime.
1571
+ * @returns The plaintext token (set as a cookie) and the stored session.
1572
+ */
1573
+ create(userId: string, data?: Record<string, unknown>, ttlSeconds?: number): Promise<IssuedSession>;
1574
+ /**
1575
+ * Resolve an opaque cookie value to its live session.
1576
+ *
1577
+ * @param token - The plaintext cookie value.
1578
+ * @returns The session, or `null` when missing/expired.
1579
+ */
1580
+ resolve(token: string): Promise<Session | null>;
1581
+ /**
1582
+ * Revoke a single session by its cookie value.
1583
+ *
1584
+ * @param token - The plaintext cookie value.
1585
+ */
1586
+ destroy(token: string): Promise<void>;
1587
+ /**
1588
+ * Revoke every session a user owns (global logout).
1589
+ *
1590
+ * @param userId - The user id.
1591
+ * @returns The number of sessions removed.
1592
+ */
1593
+ destroyByUser(userId: string): Promise<number>;
1594
+ /**
1595
+ * List a user's live sessions (e.g. an "active devices" view).
1596
+ *
1597
+ * @param userId - The user id.
1598
+ * @returns The user's sessions, oldest first.
1599
+ */
1600
+ listByUser(userId: string): Promise<Session[]>;
1601
+ }
1602
+
1603
+ /**
1604
+ * Session middleware, mirroring `sessions.middleware`.
1605
+ *
1606
+ * Reads the session cookie, resolves it to a live {@link Session} via the
1607
+ * {@link SessionService}, and attaches it to `req.session` (or `null` when
1608
+ * absent/expired). Pairs with {@link makeJwtAuthMiddleware} for JWT auth; use
1609
+ * whichever model fits the surface.
1610
+ */
1611
+
1612
+ declare global {
1613
+ namespace Express {
1614
+ /** The live session for this request, populated by the middleware. */
1615
+ interface Request {
1616
+ session?: Session | null;
1617
+ }
1618
+ }
1619
+ }
1620
+ /** Parse the `Cookie` header into a name → value map. */
1621
+ declare function parseCookies(header: string | undefined): Record<string, string>;
1622
+ /** Read the session cookie value from a request, or `null`. */
1623
+ declare function sessionCookie(req: Request, cookieName: string): string | null;
1624
+ /** Options for {@link makeSessionMiddleware}. */
1625
+ interface SessionMiddlewareOptions {
1626
+ /** Cookie name carrying the opaque session id. Default `sid`. */
1627
+ cookieName?: string;
1628
+ }
1629
+ /**
1630
+ * Build middleware that resolves the session cookie into `req.session`.
1631
+ *
1632
+ * @param service - The session service used to resolve cookies.
1633
+ * @param options - Cookie name.
1634
+ * @returns An Express middleware.
1635
+ */
1636
+ declare function makeSessionMiddleware(service: SessionService, options?: SessionMiddlewareOptions): RequestHandler;
1637
+
1638
+ /**
1639
+ * Server-Sent Events primitives, mirroring `sse.event_stream`.
1640
+ *
1641
+ * {@link ServerSentEvent} encodes the SSE wire format; {@link EventStream} is a
1642
+ * per-subscriber push queue exposed as an async iterator with an optional
1643
+ * heartbeat; {@link sseResponse} wires a stream to an Express response.
1644
+ */
1645
+
1646
+ /** A single Server-Sent Event. */
1647
+ interface ServerSentEventInit {
1648
+ /** The event payload (serialized to one or more `data:` lines). */
1649
+ data: string;
1650
+ /** Optional event name (`event:` line). */
1651
+ event?: string;
1652
+ /** Optional event id (`id:` line). */
1653
+ id?: string;
1654
+ /** Optional reconnection hint in ms (`retry:` line). */
1655
+ retry?: number;
1656
+ }
1657
+ /** An SSE event that can encode itself to the wire format. */
1658
+ declare class ServerSentEvent {
1659
+ private readonly init;
1660
+ constructor(init: ServerSentEventInit);
1661
+ /**
1662
+ * Encode to the SSE wire format (terminated by a blank line).
1663
+ *
1664
+ * @returns The encoded event block.
1665
+ */
1666
+ encode(): string;
1667
+ }
1668
+ /** Options for {@link EventStream}. */
1669
+ interface EventStreamOptions {
1670
+ /** Heartbeat interval in seconds (comment ping). `null` disables. Default 15. */
1671
+ heartbeatSeconds?: number | null;
1672
+ }
1673
+ /** A single subscriber's event queue, consumable as an async iterator. */
1674
+ declare class EventStream {
1675
+ private readonly queue;
1676
+ private waiter;
1677
+ private closed;
1678
+ private readonly heartbeatSeconds;
1679
+ /**
1680
+ * @param options - Heartbeat configuration.
1681
+ */
1682
+ constructor(options?: EventStreamOptions);
1683
+ /** Enqueue raw SSE-encoded text and wake the iterator. */
1684
+ private push;
1685
+ /**
1686
+ * Publish a data payload as an SSE event.
1687
+ *
1688
+ * @param data - The payload; objects are JSON-encoded.
1689
+ * @param event - Optional event name.
1690
+ */
1691
+ publish(data: unknown, event?: string): void;
1692
+ /** Publish a pre-built {@link ServerSentEvent}. */
1693
+ publishEvent(event: ServerSentEvent): void;
1694
+ /** Close the stream; the iterator finishes after draining. */
1695
+ close(): void;
1696
+ /**
1697
+ * Async iterator yielding encoded SSE chunks, with periodic heartbeats.
1698
+ *
1699
+ * @returns An async iterator of encoded event strings.
1700
+ */
1701
+ stream(): AsyncIterator<string> & AsyncIterable<string>;
1702
+ }
1703
+ /**
1704
+ * Stream an {@link EventStream} to an Express response as `text/event-stream`.
1705
+ *
1706
+ * Sets the SSE headers, writes each encoded chunk, and closes the stream when
1707
+ * the client disconnects.
1708
+ *
1709
+ * @param req - The Express request (used to detect disconnect).
1710
+ * @param res - The Express response to stream into.
1711
+ * @param stream - The event stream to drain.
1712
+ */
1713
+ declare function sseResponse(req: Request, res: Response$1, stream: EventStream): Promise<void>;
1714
+
1715
+ /**
1716
+ * In-process SSE broker, mirroring `sse.broker.SSEBroker`.
1717
+ *
1718
+ * Tracks subscribers per channel and fans published events out to every live
1719
+ * {@link EventStream} on that channel. Single-process (no cross-replica
1720
+ * transport yet — a Redis pub/sub backend is a planned follow-up).
1721
+ */
1722
+
1723
+ /** Fan-out hub mapping channels to subscriber streams. */
1724
+ declare class SSEBroker {
1725
+ private readonly streamOptions;
1726
+ private readonly channels;
1727
+ /**
1728
+ * @param streamOptions - Options applied to every {@link EventStream} created
1729
+ * by {@link register} (e.g. heartbeat interval).
1730
+ */
1731
+ constructor(streamOptions?: EventStreamOptions);
1732
+ /**
1733
+ * Register a new subscriber stream on `channel`.
1734
+ *
1735
+ * @param channel - The channel name.
1736
+ * @returns A fresh {@link EventStream} to serve to the subscriber.
1737
+ */
1738
+ register(channel: string): EventStream;
1739
+ /**
1740
+ * Remove a subscriber stream from `channel` and close it.
1741
+ *
1742
+ * @param channel - The channel name.
1743
+ * @param stream - The stream to remove.
1744
+ */
1745
+ unregister(channel: string, stream: EventStream): void;
1746
+ /**
1747
+ * Number of live subscribers on `channel`.
1748
+ *
1749
+ * @param channel - The channel name.
1750
+ * @returns The subscriber count.
1751
+ */
1752
+ localSubscribers(channel: string): number;
1753
+ /**
1754
+ * Publish an event to every subscriber on `channel`.
1755
+ *
1756
+ * @param channel - The channel name.
1757
+ * @param data - The payload (objects are JSON-encoded).
1758
+ * @param event - Optional event name.
1759
+ * @returns The number of subscribers the event was delivered to.
1760
+ */
1761
+ publish(channel: string, data: unknown, event?: string): number;
1762
+ }
1763
+
1764
+ /** WebSocket message envelope, mirroring `websockets.schemas`. */
1765
+
1766
+ /** The canonical message envelope exchanged over a socket. */
1767
+ declare const wsEnvelopeSchema: z.ZodObject<{
1768
+ type: z.ZodString;
1769
+ data: z.ZodOptional<z.ZodUnknown>;
1770
+ }, "strip", z.ZodTypeAny, {
1771
+ type: string;
1772
+ data?: unknown;
1773
+ }, {
1774
+ type: string;
1775
+ data?: unknown;
1776
+ }>;
1777
+ /** A typed message envelope. */
1778
+ type WSEnvelope = z.infer<typeof wsEnvelopeSchema>;
1779
+
1780
+ /**
1781
+ * In-process connection hub, mirroring `websockets.hub.WebSocketHub`.
1782
+ *
1783
+ * Transport-agnostic: it tracks {@link WebSocketLike} connections (anything with
1784
+ * `send`/`close`) so it works with the `ws` package or any compatible socket.
1785
+ * Supports per-user delivery, topic subscriptions, broadcast and a per-user
1786
+ * connection cap with oldest-eviction.
1787
+ */
1788
+
1789
+ /** The minimal socket surface the hub needs. */
1790
+ interface WebSocketLike {
1791
+ /** Send a text frame. */
1792
+ send(data: string): void;
1793
+ /** Close the socket, optionally with a status code. */
1794
+ close(code?: number): void;
1795
+ }
1796
+ /** A registered live connection. */
1797
+ interface WebSocketConnection {
1798
+ /** Unique connection id. */
1799
+ id: string;
1800
+ /** The owning user id. */
1801
+ userId: string;
1802
+ /** The underlying socket. */
1803
+ ws: WebSocketLike;
1804
+ /** Topics this connection is subscribed to. */
1805
+ topics: Set<string>;
1806
+ }
1807
+ /** Options for {@link WebSocketHub}. */
1808
+ interface WebSocketHubOptions {
1809
+ /** Max simultaneous connections per user (oldest evicted). Default 5. */
1810
+ maxPerUser?: number;
1811
+ }
1812
+ declare class WebSocketHub {
1813
+ private readonly byId;
1814
+ private readonly byUser;
1815
+ private readonly maxPerUser;
1816
+ /**
1817
+ * @param options - Per-user connection cap.
1818
+ */
1819
+ constructor(options?: WebSocketHubOptions);
1820
+ /**
1821
+ * Register a new connection for `userId`, evicting the oldest if over cap.
1822
+ *
1823
+ * @param userId - The owning user id.
1824
+ * @param ws - The socket to register.
1825
+ * @returns The created connection record.
1826
+ */
1827
+ register(userId: string, ws: WebSocketLike): WebSocketConnection;
1828
+ /**
1829
+ * Remove a connection and close its socket.
1830
+ *
1831
+ * @param connectionId - The connection id.
1832
+ * @param code - Optional WebSocket close code.
1833
+ */
1834
+ unregister(connectionId: string, code?: number): void;
1835
+ /** Subscribe a connection to a topic. */
1836
+ subscribe(connectionId: string, topic: string): void;
1837
+ /** Unsubscribe a connection from a topic. */
1838
+ unsubscribe(connectionId: string, topic: string): void;
1839
+ /** Serialize and send an envelope to a single connection. */
1840
+ private deliver;
1841
+ /**
1842
+ * Send an envelope to every connection of `userId`.
1843
+ *
1844
+ * @param userId - The target user.
1845
+ * @param envelope - The message envelope.
1846
+ * @returns The number of connections delivered to.
1847
+ */
1848
+ sendTo(userId: string, envelope: WSEnvelope): number;
1849
+ /**
1850
+ * Broadcast an envelope to all connections, or only a topic's subscribers.
1851
+ *
1852
+ * @param envelope - The message envelope.
1853
+ * @param topic - Optional topic to scope the broadcast.
1854
+ * @returns The number of connections delivered to.
1855
+ */
1856
+ broadcast(envelope: WSEnvelope, topic?: string): number;
1857
+ /** The set of users with at least one live connection. */
1858
+ onlineUsers(): Set<string>;
1859
+ /** Total live connection count. */
1860
+ connectionCount(): number;
1861
+ /** Number of connections subscribed to `topic`. */
1862
+ topicCount(topic: string): number;
1863
+ }
1864
+
1865
+ /** Handshake info passed to the authenticator. */
1866
+ interface HandshakeInfo {
1867
+ /** The request URL (includes the query string, e.g. `/ws?token=…`). */
1868
+ url: string;
1869
+ /** The raw request headers. */
1870
+ headers: Record<string, string | string[] | undefined>;
1871
+ }
1872
+ /** Options for {@link attachWebSocketHub}. */
1873
+ interface AttachWebSocketOptions {
1874
+ /** Path the WebSocket server listens on. Default `/ws`. */
1875
+ path?: string;
1876
+ /**
1877
+ * Resolve a user id from the handshake, or `null` to reject (closes 1008).
1878
+ * Default accepts every connection as `"anonymous"`.
1879
+ */
1880
+ authenticate?: (info: HandshakeInfo) => Promise<string | null> | string | null;
1881
+ /** Heartbeat interval in seconds (`0` disables). Default 30. */
1882
+ heartbeatSeconds?: number;
1883
+ /** Handler invoked for each inbound text message. */
1884
+ onMessage?: (connection: WebSocketConnection, message: string) => void;
1885
+ }
1886
+ /** Read a `token` query param from a handshake URL, or `null`. */
1887
+ declare function tokenFromUrl(url: string): string | null;
1888
+ /**
1889
+ * Attach a hub to an HTTP server over the `ws` package.
1890
+ *
1891
+ * @param server - The Node HTTP server (e.g. from `runServer`).
1892
+ * @param hub - The hub to register connections into.
1893
+ * @param options - Path, authenticator, heartbeat and message handler.
1894
+ * @returns The created `ws` `WebSocketServer` instance.
1895
+ * @throws {Error} When the optional `ws` peer is not installed.
1896
+ */
1897
+ declare function attachWebSocketHub(server: Server, hub: WebSocketHub, options?: AttachWebSocketOptions): Promise<ws.WebSocketServer>;
1898
+
1899
+ /**
1900
+ * Message broker, mirroring `queue.manager.AsyncBrokerManager`.
1901
+ *
1902
+ * A narrow async pub/sub surface ({@link BrokerManager}) with two backends: an
1903
+ * in-process {@link MemoryBroker} (dev/tests) and a {@link RabbitBroker} over the
1904
+ * optional `amqplib` peer (lazily imported). Messages are JSON-serialized.
1905
+ */
1906
+ /** A handler invoked for each delivered message. */
1907
+ type MessageHandler = (message: unknown) => Promise<void> | void;
1908
+ /** Narrow async pub/sub surface every backend implements. */
1909
+ interface BrokerManager {
1910
+ /** Publish a message to a named queue. */
1911
+ publish(queue: string, message: unknown): Promise<void>;
1912
+ /** Subscribe to a queue; resolves to an unsubscribe function. */
1913
+ subscribe(queue: string, handler: MessageHandler): Promise<() => Promise<void>>;
1914
+ /** Close the broker and release resources. */
1915
+ close(): Promise<void>;
1916
+ }
1917
+ /** In-process {@link BrokerManager} backed by handler sets. */
1918
+ declare class MemoryBroker implements BrokerManager {
1919
+ private readonly handlers;
1920
+ publish(queue: string, message: unknown): Promise<void>;
1921
+ subscribe(queue: string, handler: MessageHandler): Promise<() => Promise<void>>;
1922
+ close(): Promise<void>;
1923
+ }
1924
+ /** Options for {@link RabbitBroker}. */
1925
+ interface RabbitBrokerOptions {
1926
+ /** AMQP connection URL, e.g. `amqp://localhost`. */
1927
+ url: string;
1928
+ /** Whether queues are declared durable. Default `true`. */
1929
+ durable?: boolean;
1930
+ }
1931
+ /** RabbitMQ-backed {@link BrokerManager} over the optional `amqplib` peer. */
1932
+ declare class RabbitBroker implements BrokerManager {
1933
+ private readonly options;
1934
+ private connection;
1935
+ private channel;
1936
+ private readonly durable;
1937
+ /**
1938
+ * @param options - Connection URL and queue durability.
1939
+ */
1940
+ constructor(options: RabbitBrokerOptions);
1941
+ /** Lazily connect and open a channel. */
1942
+ private ready;
1943
+ publish(queue: string, message: unknown): Promise<void>;
1944
+ subscribe(queue: string, handler: MessageHandler): Promise<() => Promise<void>>;
1945
+ close(): Promise<void>;
1946
+ }
1947
+
1948
+ /**
1949
+ * Background task manager, mirroring `tasks.manager.AsyncTaskBrokerManager`.
1950
+ *
1951
+ * Rides on a {@link BrokerManager}: enqueue publishes a `{ name, payload }`
1952
+ * envelope to a task queue; a worker started with {@link TaskManager.start}
1953
+ * consumes it and dispatches to the registered handler. Defaults to an
1954
+ * in-process {@link MemoryBroker} so it works with zero infrastructure.
1955
+ */
1956
+
1957
+ /** A handler for a registered task. */
1958
+ type TaskHandler<P = unknown> = (payload: P) => Promise<void> | void;
1959
+ /** Options for {@link TaskManager}. */
1960
+ interface TaskManagerOptions {
1961
+ /** The broker to publish/consume on. Defaults to a {@link MemoryBroker}. */
1962
+ broker?: BrokerManager;
1963
+ /** Queue name used for the task stream. Default `tasks`. */
1964
+ queue?: string;
1965
+ }
1966
+ declare class TaskManager {
1967
+ private readonly broker;
1968
+ private readonly queue;
1969
+ private readonly handlers;
1970
+ private unsubscribe;
1971
+ /**
1972
+ * @param options - Broker and queue name.
1973
+ */
1974
+ constructor(options?: TaskManagerOptions);
1975
+ /**
1976
+ * Register a handler for a named task.
1977
+ *
1978
+ * @param name - The task name.
1979
+ * @param handler - The handler invoked with the task payload.
1980
+ */
1981
+ register<P = unknown>(name: string, handler: TaskHandler<P>): void;
1982
+ /**
1983
+ * Enqueue a task by name.
1984
+ *
1985
+ * @param name - The registered task name.
1986
+ * @param payload - The JSON-serializable payload.
1987
+ */
1988
+ enqueue(name: string, payload?: unknown): Promise<void>;
1989
+ /**
1990
+ * Start the worker: subscribe to the task queue and dispatch to handlers.
1991
+ * A task with no registered handler is logged and skipped.
1992
+ */
1993
+ start(): Promise<void>;
1994
+ /** Stop the worker (stops consuming; does not close the broker). */
1995
+ stop(): Promise<void>;
1996
+ }
1997
+
1998
+ /**
1999
+ * Feature-flag backends, mirroring `flags.backends`.
2000
+ *
2001
+ * A flag resolves to a boolean given a flag name and optional context. Backends
2002
+ * are composable — {@link CompositeFeatureFlagBackend} tries each in order and
2003
+ * returns the first definitive answer.
2004
+ */
2005
+ /** Arbitrary evaluation context (user id, roles, attributes). */
2006
+ type FlagContext = Record<string, unknown>;
2007
+ /** Resolves a flag to enabled/disabled, or `null` when it has no opinion. */
2008
+ interface FeatureFlagBackend {
2009
+ /** Resolve `flag`; `null` defers to the next backend. */
2010
+ resolve(flag: string, context?: FlagContext): Promise<boolean | null> | boolean | null;
2011
+ }
2012
+ /** Coerce a loose value (`"1"`, `"true"`, `"on"`, …) to a boolean. */
2013
+ declare function coerceFlag(value: unknown): boolean;
2014
+ /** In-memory backend backed by a `Map`, ideal for tests and overrides. */
2015
+ declare class MemoryFeatureFlagBackend implements FeatureFlagBackend {
2016
+ private readonly flags;
2017
+ /**
2018
+ * @param initial - Initial flag → enabled map.
2019
+ */
2020
+ constructor(initial?: Record<string, boolean>);
2021
+ /** Set or override a flag. */
2022
+ set(flag: string, enabled: boolean): void;
2023
+ resolve(flag: string): boolean | null;
2024
+ }
2025
+ /** Reads flags from env vars, e.g. flag `new-ui` → `FLAG_NEW_UI`. */
2026
+ declare class EnvFeatureFlagBackend implements FeatureFlagBackend {
2027
+ private readonly env;
2028
+ private readonly prefix;
2029
+ /**
2030
+ * @param env - Environment source (defaults to `process.env`).
2031
+ * @param prefix - Env var prefix. Default `FLAG_`.
2032
+ */
2033
+ constructor(env?: NodeJS.ProcessEnv, prefix?: string);
2034
+ private key;
2035
+ resolve(flag: string): boolean | null;
2036
+ }
2037
+ /** Tries each backend in order; first non-`null` answer wins. */
2038
+ declare class CompositeFeatureFlagBackend implements FeatureFlagBackend {
2039
+ private readonly backends;
2040
+ /**
2041
+ * @param backends - Backends in priority order.
2042
+ */
2043
+ constructor(backends: FeatureFlagBackend[]);
2044
+ resolve(flag: string, context?: FlagContext): Promise<boolean | null>;
2045
+ }
2046
+
2047
+ /**
2048
+ * Feature-flag service + Express guard, mirroring `flags.service` /
2049
+ * `flags.dependencies`.
2050
+ */
2051
+
2052
+ /** Evaluates flags against a backend, applying a default when undecided. */
2053
+ declare class FeatureFlags {
2054
+ private readonly backend;
2055
+ private readonly defaultEnabled;
2056
+ /**
2057
+ * @param backend - The resolving backend.
2058
+ * @param defaultEnabled - Value used when the backend returns `null`.
2059
+ */
2060
+ constructor(backend: FeatureFlagBackend, defaultEnabled?: boolean);
2061
+ /**
2062
+ * Whether `flag` is enabled for the given context.
2063
+ *
2064
+ * @param flag - The flag name.
2065
+ * @param context - Optional evaluation context.
2066
+ * @returns `true` when enabled (or default when the backend is undecided).
2067
+ */
2068
+ isEnabled(flag: string, context?: FlagContext): Promise<boolean>;
2069
+ }
2070
+ /**
2071
+ * Build middleware that rejects with 404 when `flag` is disabled (hiding the
2072
+ * route entirely, the common kill-switch behavior).
2073
+ *
2074
+ * @param flags - The flag service.
2075
+ * @param flag - The flag name to gate on.
2076
+ * @returns An Express middleware.
2077
+ */
2078
+ declare function makeFlagGuard(flags: FeatureFlags, flag: string): RequestHandler;
2079
+
2080
+ /**
2081
+ * File storage abstraction, mirroring `utils.storage_backends` / `utils.upload`.
2082
+ *
2083
+ * A narrow {@link UploadStorage} interface with a filesystem-backed
2084
+ * {@link LocalUploadStorage}. For S3/MinIO, implement the same interface over
2085
+ * your client (the interface intentionally avoids a hard cloud dependency).
2086
+ */
2087
+ /** The result of persisting an object. */
2088
+ interface UploadResult {
2089
+ /** The storage key (path within the backend). */
2090
+ key: string;
2091
+ /** A URL the object can be served from. */
2092
+ url: string;
2093
+ /** The stored byte size. */
2094
+ size: number;
2095
+ /** The declared content type, when known. */
2096
+ contentType?: string;
2097
+ }
2098
+ /** Options for {@link UploadStorage.save}. */
2099
+ interface SaveOptions {
2100
+ /** MIME type recorded on the result. */
2101
+ contentType?: string;
2102
+ }
2103
+ /** Narrow object-storage surface backends implement. */
2104
+ interface UploadStorage {
2105
+ /** Persist bytes under `key`, returning metadata. */
2106
+ save(key: string, data: Uint8Array, options?: SaveOptions): Promise<UploadResult>;
2107
+ /** Read bytes back by key. */
2108
+ read(key: string): Promise<Buffer>;
2109
+ /** Delete an object. Idempotent. */
2110
+ delete(key: string): Promise<void>;
2111
+ /** The URL an object is served from. */
2112
+ url(key: string): string;
2113
+ }
2114
+ /** Options for {@link LocalUploadStorage}. */
2115
+ interface LocalUploadStorageOptions {
2116
+ /** Filesystem root every key is written under. */
2117
+ root: string;
2118
+ /** Public base URL prefix for {@link LocalUploadStorage.url}. Default `""`. */
2119
+ baseUrl?: string;
2120
+ }
2121
+ /** Filesystem-backed {@link UploadStorage} for local/dev or single-host setups. */
2122
+ declare class LocalUploadStorage implements UploadStorage {
2123
+ private readonly root;
2124
+ private readonly baseUrl;
2125
+ /**
2126
+ * @param options - Filesystem root and public base URL.
2127
+ */
2128
+ constructor(options: LocalUploadStorageOptions);
2129
+ save(key: string, data: Uint8Array, options?: SaveOptions): Promise<UploadResult>;
2130
+ read(key: string): Promise<Buffer>;
2131
+ delete(key: string): Promise<void>;
2132
+ url(key: string): string;
2133
+ }
2134
+ /**
2135
+ * Build a `Content-Disposition` header value.
2136
+ *
2137
+ * @param filename - The download filename.
2138
+ * @param inline - When `true`, use `inline`; otherwise `attachment`.
2139
+ * @returns The header value (RFC 5987 `filename*` encoded).
2140
+ */
2141
+ declare function buildContentDisposition(filename: string, inline?: boolean): string;
2142
+
2143
+ /** Web Push DTOs (Zod), mirroring `webpush.schemas`. */
2144
+
2145
+ /** The browser-provided push subscription keys. */
2146
+ declare const webPushKeysSchema: z.ZodObject<{
2147
+ p256dh: z.ZodString;
2148
+ auth: z.ZodString;
2149
+ }, "strip", z.ZodTypeAny, {
2150
+ auth: string;
2151
+ p256dh: string;
2152
+ }, {
2153
+ auth: string;
2154
+ p256dh: string;
2155
+ }>;
2156
+ /** A browser push subscription. */
2157
+ declare const webPushSubscriptionSchema: z.ZodObject<{
2158
+ endpoint: z.ZodString;
2159
+ keys: z.ZodObject<{
2160
+ p256dh: z.ZodString;
2161
+ auth: z.ZodString;
2162
+ }, "strip", z.ZodTypeAny, {
2163
+ auth: string;
2164
+ p256dh: string;
2165
+ }, {
2166
+ auth: string;
2167
+ p256dh: string;
2168
+ }>;
2169
+ }, "strip", z.ZodTypeAny, {
2170
+ keys: {
2171
+ auth: string;
2172
+ p256dh: string;
2173
+ };
2174
+ endpoint: string;
2175
+ }, {
2176
+ keys: {
2177
+ auth: string;
2178
+ p256dh: string;
2179
+ };
2180
+ endpoint: string;
2181
+ }>;
2182
+ /** A push notification payload. */
2183
+ declare const webPushPayloadSchema: z.ZodObject<{
2184
+ title: z.ZodString;
2185
+ body: z.ZodOptional<z.ZodString>;
2186
+ url: z.ZodOptional<z.ZodString>;
2187
+ data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
2188
+ }, "strip", z.ZodTypeAny, {
2189
+ title: string;
2190
+ url?: string | undefined;
2191
+ data?: Record<string, unknown> | undefined;
2192
+ body?: string | undefined;
2193
+ }, {
2194
+ title: string;
2195
+ url?: string | undefined;
2196
+ data?: Record<string, unknown> | undefined;
2197
+ body?: string | undefined;
2198
+ }>;
2199
+ type WebPushKeys = z.infer<typeof webPushKeysSchema>;
2200
+ type WebPushSubscription = z.infer<typeof webPushSubscriptionSchema>;
2201
+ type WebPushPayload = z.infer<typeof webPushPayloadSchema>;
2202
+
2203
+ /**
2204
+ * Web Push (VAPID) dispatch, mirroring `webpush.dispatcher`.
2205
+ *
2206
+ * Wraps the optional `web-push` peer (lazily imported). A `410 Gone` / `404`
2207
+ * from the push service means the subscription is dead — surfaced as
2208
+ * {@link WebPushGoneError} so the caller can prune it from storage.
2209
+ */
2210
+
2211
+ /** A Web Push delivery failure. */
2212
+ declare class WebPushError extends Error {
2213
+ readonly statusCode?: number | undefined;
2214
+ constructor(message: string, statusCode?: number | undefined);
2215
+ }
2216
+ /** The subscription is expired/unsubscribed (410/404) — prune it. */
2217
+ declare class WebPushGoneError extends WebPushError {
2218
+ constructor(statusCode: number);
2219
+ }
2220
+ /** Options for {@link WebPushDispatcher}. */
2221
+ interface WebPushDispatcherOptions {
2222
+ /** VAPID public key. */
2223
+ publicKey: string;
2224
+ /** VAPID private key. */
2225
+ privateKey: string;
2226
+ /** VAPID subject (`mailto:` or site URL). */
2227
+ subject: string;
2228
+ }
2229
+ /** Sends Web Push notifications with configured VAPID details. */
2230
+ declare class WebPushDispatcher {
2231
+ private readonly options;
2232
+ /**
2233
+ * @param options - VAPID keys and subject.
2234
+ */
2235
+ constructor(options: WebPushDispatcherOptions);
2236
+ /**
2237
+ * Send a payload to a single subscription.
2238
+ *
2239
+ * @param subscription - The browser push subscription.
2240
+ * @param payload - The notification payload.
2241
+ * @throws {WebPushGoneError} When the subscription is expired (410/404).
2242
+ * @throws {WebPushError} On any other delivery failure.
2243
+ */
2244
+ send(subscription: WebPushSubscription, payload: WebPushPayload): Promise<void>;
2245
+ }
2246
+
1132
2247
  /**
1133
2248
  * Auth DTOs (Zod), mirroring `auth.schemas`.
1134
2249
  *
@@ -1197,14 +2312,14 @@ declare const userPublicSchema: z.ZodObject<{
1197
2312
  }, "strip", z.ZodTypeAny, {
1198
2313
  id: string;
1199
2314
  isActive: boolean;
1200
- email: string;
1201
2315
  name: string | null;
2316
+ email: string;
1202
2317
  roles: string[];
1203
2318
  }, {
1204
2319
  id: string;
1205
2320
  isActive: boolean;
1206
- email: string;
1207
2321
  name: string | null;
2322
+ email: string;
1208
2323
  roles: string[];
1209
2324
  }>;
1210
2325
  /** Response body for `POST /auth/signup` and `POST /auth/login`. */
@@ -1218,14 +2333,14 @@ declare const authResponseSchema: z.ZodObject<{
1218
2333
  }, "strip", z.ZodTypeAny, {
1219
2334
  id: string;
1220
2335
  isActive: boolean;
1221
- email: string;
1222
2336
  name: string | null;
2337
+ email: string;
1223
2338
  roles: string[];
1224
2339
  }, {
1225
2340
  id: string;
1226
2341
  isActive: boolean;
1227
- email: string;
1228
2342
  name: string | null;
2343
+ email: string;
1229
2344
  roles: string[];
1230
2345
  }>;
1231
2346
  tokens: z.ZodObject<{
@@ -1248,8 +2363,8 @@ declare const authResponseSchema: z.ZodObject<{
1248
2363
  user: {
1249
2364
  id: string;
1250
2365
  isActive: boolean;
1251
- email: string;
1252
2366
  name: string | null;
2367
+ email: string;
1253
2368
  roles: string[];
1254
2369
  };
1255
2370
  tokens: {
@@ -1262,8 +2377,8 @@ declare const authResponseSchema: z.ZodObject<{
1262
2377
  user: {
1263
2378
  id: string;
1264
2379
  isActive: boolean;
1265
- email: string;
1266
2380
  name: string | null;
2381
+ email: string;
1267
2382
  roles: string[];
1268
2383
  };
1269
2384
  tokens: {
@@ -1721,6 +2836,6 @@ interface RunServerOptions {
1721
2836
  declare function runServer(app: Express, options?: RunServerOptions): Promise<Server>;
1722
2837
 
1723
2838
  /** The installed SDK version. Single source of truth for the barrel + CLI. */
1724
- declare const VERSION = "0.1.0";
2839
+ declare const VERSION = "0.3.0";
1725
2840
 
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 };
2841
+ export { AppException, type AppExceptionHandlerOptions, type AppExceptionOptions, type AttachWebSocketOptions, AttemptThrottle, type AttemptThrottleOptions, type AuthResponse, type AuthRouterOptions, type AuthUser, type BaseAppSettings, BaseController, BaseModel, type BaseResponse, BaseService, type BrokerManager, CEP_PATTERN, CNPJ_PATTERN, CPF_PATTERN, type CPUMetrics, type CacheManager, type CachedOptions, type CatalogData, CircuitOpenError, type ClientIpOptions, CompositeFeatureFlagBackend, ConflictException, type CreateAppOpenApi, type CreateAppOptions, type CursorPaginationFilter, DEFAULT_LOCALE, type EmailMessage, type EmailOptions, EmailUtils, type Enum, type EnumHelpers, type EnumSpec, EnvFeatureFlagBackend, EventStream, type EventStreamOptions, type ExceptionDetails, ExpiredTokenException, type FeatureFlagBackend, FeatureFlags, type FlagContext, ForbiddenException, type GenerateOpenApiOptions, HTTPClient, type HTTPClientOptions, HTTP_500_MARKER, type HandshakeInfo, type HealthCheck, type HealthRouterOptions, InvalidTokenException, type IssuedSession, JSONLogger, JWTUtils, type JWTUtilsOptions, type JwtAuthOptions, type JwtClaims, LocalUploadStorage, type LocalUploadStorageOptions, type LogExtra, type LogLevel, type LoginInput, MemoryBroker, MemoryCacheManager, MemoryFeatureFlagBackend, type MemoryMetrics, MemorySessionStore, MemoryThrottleBackend, MessageCatalog, type MessageHandler, MetricsUtils, NotFoundException, type OpenApiDocument, type OpenApiInfo, PHONE_BR_PATTERN, type PaginationFilter, PasswordUtils, REQUEST_ID_HEADER, RabbitBroker, type RabbitBrokerOptions, RedisCacheManager, type RedisLike, type RedocOptions, type RefreshInput, Region, type RegionValue, type RegisterExceptionHandlersOptions, type RequestContext, type ResponseMapper, RetryPolicy, type RunServerOptions, SSEBroker, type SaveOptions, ServerSentEvent, type ServerSentEventInit, type Session, type SessionMiddlewareOptions, SessionService, type SessionServiceOptions, type SessionStore, type SignupInput, type StateBR, type SwaggerOptions, type SystemMetrics, TOTPHelper, type TOTPOptions, type TaskHandler, TaskManager, type TaskManagerOptions, type ThrottleBackend, type ThrottleStatus, type ToDictOptions, type TokenPair, TooManyRequestsException, type TooManyRequestsOptions, UF, type UFValue, UnauthorizedException, type UnhandledExceptionHandlerOptions, type UploadResult, type UploadStorage, UserAuthService, type UserAuthServiceOptions, type UserPublic, type UserStore, VERSION, ValidationException, type WSEnvelope, WebPushDispatcher, type WebPushDispatcherOptions, WebPushError, WebPushGoneError, type WebPushKeys, type WebPushPayload, type WebPushSubscription, type WebSocketConnection, WebSocketHub, type WebSocketHubOptions, type WebSocketLike, attachWebSocketHub, authResponseSchema, baseAppSettingsSchema, baseAppSettingsShape, baseResponseSchema, bearerToken, buildContentDisposition, cached, cepField, citiesByUf, cnpjField, coerceFlag, configureLogging, corsSettingsShape, cpfField, cpfOrCnpjField, createApp, createOpenApiRegistry, createdByColumn, cursorPaginationFilterSchema, cursorPaginationSchema, databaseSettingsShape, decodeCursor, defaultMessageCatalog, defineEnum, deletedAtColumn, encodeCursor, generateOpaqueToken, generateOpenApiDocument, getAuth, getClientIp, getConditions, getPaginationConditions, getRequestId, getState, hashOpaqueToken, isValidCep, isValidCity, isValidCnpj, isValidCpf, isValidCpfCnpj, isValidPhoneBr, isValidUf, listStates, loadSettings, loginSchema, makeAppExceptionHandler, makeAuthRouter, makeFlagGuard, makeHealthRouter, makeJwtAuthMiddleware, makeSessionMiddleware, makeUnhandledExceptionHandler, modifyDict, mountOpenApiJson, mountRedoc, mountSwaggerUi, normalizeCep, normalizeCnpj, normalizeCpf, normalizeCpfCnpj, normalizePhoneBr, normalizeUf, notFoundHandler, onlyDigits, paginationFilterSchema, paginationSchema, parseAcceptLanguage, parseCookies, phoneBrField, refreshSchema, registerExceptionHandlers, requestIdMiddleware, requireRoles, runServer, runWithRequestContext, serverSettingsShape, sessionCookie, setRequestId, signupSchema, sseResponse, statesByRegion, tableNameFor, toDict, toUtc, tokenFromUrl, tokenPairSchema, ufField, updatedByColumn, userPublicSchema, utcnow, verifyOpaqueToken, webPushKeysSchema, webPushPayloadSchema, webPushSubscriptionSchema, wsEnvelopeSchema };