weifuwu 0.27.28 → 0.28.2

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.
@@ -1,20 +0,0 @@
1
- import type { Middleware } from '../types.ts';
2
- /** Options for {@link compress}. */
3
- export interface CompressOptions {
4
- /** Compression level (1-9, default: 6). */
5
- level?: number;
6
- /** Minimum response body size in bytes to compress (default: 1024). */
7
- threshold?: number;
8
- }
9
- /**
10
- * Response compression middleware (brotli, gzip, deflate).
11
- *
12
- * Automatically selects the best encoding based on `Accept-Encoding` header.
13
- * Skips compression for small responses, images, audio, video, and already-encoded responses.
14
- *
15
- * ```ts
16
- * import { compress } from 'weifuwu'
17
- * app.use(compress())
18
- * ```
19
- */
20
- export declare function compress(options?: CompressOptions): Middleware;
@@ -1,25 +0,0 @@
1
- import type { Middleware, Context } from '../types.ts';
2
- /** Options for {@link cors}. */
3
- export interface CORSOptions {
4
- /** Allowed origin(s). Default `'*'`. If `credentials: true`, reflects the request origin. */
5
- origin?: string | string[] | ((origin: string) => string | boolean | undefined);
6
- /** Allowed HTTP methods. Default: `GET, HEAD, PUT, PATCH, POST, DELETE`. */
7
- methods?: string[];
8
- /** Allowed request headers. Default: `Content-Type, Authorization`. */
9
- allowedHeaders?: string[];
10
- /** Exposed response headers. */
11
- exposedHeaders?: string[];
12
- /** Whether to expose `Access-Control-Allow-Credentials`. */
13
- credentials?: boolean;
14
- /** `Access-Control-Max-Age` in seconds. */
15
- maxAge?: number;
16
- }
17
- /**
18
- * CORS middleware.
19
- *
20
- * ```ts
21
- * import { cors } from 'weifuwu'
22
- * app.use(cors({ origin: 'https://myapp.com', credentials: true }))
23
- * ```
24
- */
25
- export declare function cors(options?: CORSOptions): Middleware<Context, Context>;
@@ -1,24 +0,0 @@
1
- import { Router } from '../core/router.ts';
2
- /** Options for {@link health}. */
3
- export interface HealthOptions {
4
- /** Health check endpoint path (default: `'/__health'`). */
5
- path?: string;
6
- /** Async function that throws if the service is unhealthy. Called on each request. */
7
- check?: () => Promise<void>;
8
- }
9
- /**
10
- * Health check endpoint.
11
- *
12
- * Returns 200 with `'OK'` if the check passes, 503 if it fails.
13
- *
14
- * ```ts
15
- * import { health } from 'weifuwu'
16
- *
17
- * app.use(health({
18
- * check: async () => {
19
- * await db.query('SELECT 1')
20
- * },
21
- * }))
22
- * ```
23
- */
24
- export declare function health(options?: HealthOptions): Router;
@@ -1,33 +0,0 @@
1
- import type { Middleware, Context } from '../types.ts';
2
- /** Options for {@link helmet}. Set any header to `false` to omit it. */
3
- export interface HelmetOptions {
4
- /** `Content-Security-Policy` header value. */
5
- contentSecurityPolicy?: string | false;
6
- /** `Cross-Origin-Embedder-Policy` header value. */
7
- crossOriginEmbedderPolicy?: string | false;
8
- /** `Cross-Origin-Opener-Policy` header value. */
9
- crossOriginOpenerPolicy?: string | false;
10
- /** `Cross-Origin-Resource-Policy` header value. */
11
- crossOriginResourcePolicy?: string | false;
12
- /** `Origin-Agent-Cluster` header value. */
13
- originAgentCluster?: string | false;
14
- /** `Referrer-Policy` header value. */
15
- referrerPolicy?: string | false;
16
- /** `Strict-Transport-Security` header value. */
17
- strictTransportSecurity?: string | false;
18
- /** `X-Content-Type-Options` header value. */
19
- xContentTypeOptions?: string | false;
20
- /** `X-DNS-Prefetch-Control` header value. */
21
- xDnsPrefetchControl?: string | false;
22
- /** `X-Download-Options` header value. */
23
- xDownloadOptions?: string | false;
24
- /** `X-Frame-Options` header value. */
25
- xFrameOptions?: string | false;
26
- /** `X-Permitted-Cross-Domain-Policies` header value. */
27
- xPermittedCrossDomainPolicies?: string | false;
28
- /** `X-XSS-Protection` header value. */
29
- xXssProtection?: string | false;
30
- /** `Permissions-Policy` header value. */
31
- permissionsPolicy?: string | false;
32
- }
33
- export declare function helmet(options?: HelmetOptions): Middleware<Context, Context>;
@@ -1,44 +0,0 @@
1
- import type { Redis, Context, Middleware, Closeable } from '../types.ts';
2
- /** Options for {@link rateLimit}. */
3
- export interface RateLimitOptions {
4
- /** Maximum requests within the window (default: 100). */
5
- max?: number;
6
- /** Window duration in ms (default: 60000 = 1 minute). */
7
- window?: number;
8
- /** Custom key function. Default: IP from `x-forwarded-for` or `x-real-ip` or `cf-connecting-ip`. */
9
- key?: (req: Request, ctx: Context) => string;
10
- /** Custom 429 response body." */
11
- message?: string;
12
- /** Store backend. `'memory'` (default) or `'redis'`. */
13
- store?: 'memory' | 'redis';
14
- /** Redis client (required when `store: 'redis'`). */
15
- redis?: Redis;
16
- /** Redis key prefix (default: `'ratelimit:'`). */
17
- prefix?: string;
18
- }
19
- /** Rate limit module — middleware + stats. */
20
- export interface RateLimitModule extends Middleware<Context, Context>, Closeable {
21
- stats(): {
22
- store: string;
23
- entries?: number;
24
- maxEntries: number;
25
- };
26
- }
27
- /**
28
- * Rate limiting middleware (in-memory or Redis-backed).
29
- *
30
- * Limits requests per key (default: client IP) within a rolling window.
31
- * Returns 429 when the limit is exceeded, with `Retry-After` header.
32
- *
33
- * ```ts
34
- * import { rateLimit } from 'weifuwu'
35
- *
36
- * // In-memory (single process)
37
- * app.use(rateLimit({ max: 60, window: 60_000 }))
38
- *
39
- * // Redis-backed (multi-process)
40
- * import { Redis } from 'ioredis'
41
- * app.use(rateLimit({ store: 'redis', redis: new Redis(), max: 100 }))
42
- * ```
43
- */
44
- export declare function rateLimit(options?: RateLimitOptions): RateLimitModule;
@@ -1,40 +0,0 @@
1
- import type { Context, Middleware } from '../types.ts';
2
- declare module '../types.ts' {
3
- interface Context {
4
- requestId: string;
5
- }
6
- }
7
- /** Options for {@link requestId}. */
8
- /** Request ID module — a {@link Middleware} that injects `ctx.requestId`. */
9
- export type RequestIdModule = Middleware<Context, Context & {
10
- requestId: string;
11
- }>;
12
- export interface RequestIdOptions {
13
- /** Header name for request ID (default: `'X-Request-ID'`). */
14
- header?: string;
15
- /** Custom ID generator (default: `crypto.randomUUID`). */
16
- generator?: () => string;
17
- }
18
- /**
19
- * Request ID middleware.
20
- *
21
- * @deprecated Use `trace()` from 'weifuwu' instead — it injects `ctx.trace.requestId`
22
- * along with `traceId` and `elapsed()` in a single middleware.
23
- *
24
- * ```ts
25
- * // Old:
26
- * app.use(requestId())
27
- * ctx.requestId
28
- *
29
- * // New:
30
- * app.use(trace())
31
- * ctx.trace.requestId
32
- * ```
33
- *
34
- * Reads an incoming `X-Request-ID` header (or custom header name) from the
35
- * request. If absent, generates a new UUID. Sets the response header and
36
- * injects `ctx.requestId`.
37
- */
38
- export declare function requestId(options?: RequestIdOptions): Middleware<Context, Context & {
39
- requestId: string;
40
- }>;
@@ -1,23 +0,0 @@
1
- import type { Handler } from '../types.ts';
2
- /** Options for {@link serveStatic}. */
3
- export interface ServeStaticOptions {
4
- /** Directory index filename (default: `'index.html'`). */
5
- index?: string;
6
- /** `Cache-Control max-age` in seconds. */
7
- maxAge?: number;
8
- /** Add `immutable` to `Cache-Control` (requires `maxAge`). */
9
- immutable?: boolean;
10
- }
11
- /**
12
- * Static file serving handler.
13
- *
14
- * Serves files from a root directory. Supports ETag/304, directory index,
15
- * Content-Type detection by extension, and directory traversal protection.
16
- *
17
- * ```ts
18
- * import { serveStatic, Router } from 'weifuwu'
19
- * const app = new Router()
20
- * app.get('/static/*', serveStatic('./public'))
21
- * ```
22
- */
23
- export declare function serveStatic(root: string, options?: ServeStaticOptions): Handler;
@@ -1,55 +0,0 @@
1
- import type { Context, Middleware } from '../types.ts';
2
- declare module '../types.ts' {
3
- interface Context {
4
- parsed: Record<string, unknown>;
5
- }
6
- }
7
- /** Upload middleware — a {@link Middleware} that injects `ctx.parsed` with file fields. */
8
- export type UploadModule = Middleware<Context, Context & {
9
- parsed: Record<string, unknown>;
10
- }>;
11
- /** A parsed file from a multipart upload. */
12
- export interface UploadedFile {
13
- /** Original filename from the client. */
14
- name: string;
15
- /** MIME type from the `Content-Type` part header. */
16
- type: string;
17
- /** File size in bytes. */
18
- size: number;
19
- /** Path where the file was saved (when `dir` option is set). */
20
- path?: string;
21
- /** File content as Buffer (when `dir` option is not set). */
22
- buffer?: Buffer;
23
- }
24
- /** Options for {@link upload}. */
25
- export interface UploadOptions {
26
- /** Directory to save uploaded files. If not set, files stay in memory via `.buffer`. */
27
- dir?: string;
28
- /** Maximum file size in bytes. Default: 10 MB. Set `0` to allow unlimited. */
29
- maxFileSize?: number;
30
- /** Allowed MIME types (e.g. `['image/jpeg', 'image/png']`). Empty array allows all. */
31
- allowedTypes?: string[];
32
- }
33
- /**
34
- * Multipart file upload middleware.
35
- *
36
- * Parses `multipart/form-data` requests, extracting files and fields.
37
- * Files can be saved to disk (`dir` option) or kept in memory as Buffers.
38
- * Parsed fields are available in `ctx.parsed`.
39
- *
40
- * ```ts
41
- * import { upload } from 'weifuwu'
42
- *
43
- * // Save to disk
44
- * app.use(upload({ dir: './uploads', maxFileSize: 5_000_000 }))
45
- *
46
- * // In-memory
47
- * app.post('/upload', async (req, ctx) => {
48
- * const file = ctx.parsed?.file as UploadedFile
49
- * console.log(file.name, file.type, file.buffer!.length)
50
- * })
51
- * ```
52
- */
53
- export declare function upload(options?: UploadOptions): Middleware<Context, Context & {
54
- parsed: Record<string, unknown>;
55
- }>;
@@ -1,32 +0,0 @@
1
- import type { ZodSchema } from 'zod';
2
- import type { Middleware } from '../types.ts';
3
- declare module '../types.ts' {
4
- interface Context {
5
- parsed: Record<string, unknown>;
6
- }
7
- }
8
- /** Validation middleware — a {@link Middleware} that injects `ctx.parsed` with validated data. */
9
- export type ValidateModule = Middleware;
10
- export interface ValidationSchemas {
11
- body?: ZodSchema;
12
- query?: ZodSchema;
13
- params?: ZodSchema;
14
- headers?: ZodSchema;
15
- }
16
- /**
17
- * Request validation middleware using Zod schemas.
18
- *
19
- * Validates `params`, `query`, `body`, and/or `headers` against schemas.
20
- * Returns 422 with error details on mismatch.
21
- * Injects `ctx.parsed` with validated-and-transformed values.
22
- *
23
- * ```ts
24
- * import { z } from 'zod'
25
- *
26
- * app.get('/users/:id', validate({
27
- * params: z.object({ id: z.string() }),
28
- * query: z.object({ include: z.string().optional() }),
29
- * }), handler)
30
- * ```
31
- */
32
- export declare function validate(schemas?: ValidationSchemas): Middleware;
@@ -1,4 +0,0 @@
1
- import type { PostgresOptions, PostgresClient } from './types.ts';
2
- /** Migration tracking table name. Created automatically on first migrate(). */
3
- export declare const MIGRATIONS_TABLE = "_weifuwu_migrations";
4
- export declare function postgres(opts?: string | PostgresOptions): PostgresClient;
@@ -1,3 +0,0 @@
1
- export { postgres, MIGRATIONS_TABLE } from './client.ts';
2
- export { PgModule } from './module.ts';
3
- export type { PostgresOptions, PostgresClient, PostgresInjected } from './types.ts';
@@ -1,12 +0,0 @@
1
- import type { SqlClient, Closeable } from '../types.ts';
2
- import type { PostgresClient } from './types.ts';
3
- export declare class PgModule implements Closeable {
4
- protected sql: SqlClient;
5
- protected pg: PostgresClient;
6
- constructor(pg: PostgresClient);
7
- transaction<T>(fn: (sql: SqlClient) => Promise<T>, retryOpts?: {
8
- maxRetries?: number;
9
- }): Promise<T>;
10
- migrate(): Promise<void>;
11
- close(): Promise<void>;
12
- }
@@ -1,42 +0,0 @@
1
- import type { SqlClient, Context, Middleware, Closeable } from '../types.ts';
2
- declare module '../types.ts' {
3
- interface Context {
4
- sql: SqlClient;
5
- }
6
- }
7
- export interface PostgresInjected {
8
- sql: SqlClient;
9
- }
10
- export interface PostgresOptions {
11
- connection?: string | Record<string, unknown>;
12
- signal?: AbortSignal;
13
- closeTimeout?: number;
14
- max?: number;
15
- ssl?: boolean | Record<string, unknown>;
16
- idle_timeout?: number;
17
- connect_timeout?: number;
18
- /** Per-statement timeout in ms. Set to 0 to disable. Default: 30_000. */
19
- statementTimeout?: number;
20
- /** Called after every query completes. Receives query text, duration in ms, and row count. */
21
- onQuery?: (query: string, durationMs: number, rowCount: number) => void;
22
- }
23
- export interface PostgresClient extends Middleware<Context, Context & PostgresInjected>, Closeable {
24
- sql: SqlClient;
25
- /** Creates the migration tracking table (_weifuwu_migrations). Called once at startup. */
26
- migrate: () => Promise<void>;
27
- /** Record that a module's migration has been applied (idempotent). */
28
- markMigrated: (moduleName: string) => Promise<void>;
29
- /** Check whether a module has already been migrated. */
30
- isMigrated: (moduleName: string) => Promise<boolean>;
31
- transaction: <T>(fn: (sql: any) => Promise<T>, retryOpts?: {
32
- maxRetries?: number;
33
- }) => Promise<T>;
34
- /** Snapshot of connection pool state: active, idle, waiting, max connections. */
35
- poolStats: () => {
36
- active: number;
37
- idle: number;
38
- waiting: number;
39
- max: number;
40
- };
41
- close: () => Promise<void>;
42
- }
@@ -1,9 +0,0 @@
1
- /**
2
- * Cron expression parsing utilities (moved from cron-utils.ts).
3
- * Used internally by queue for scheduled job execution.
4
- *
5
- * All functions operate in local timezone.
6
- */
7
- export declare function parsePattern(pattern: string): Set<number>[];
8
- export declare function matches(fields: Set<number>[], date: Date): boolean;
9
- export declare function cronNext(expr: string, from?: Date): number;
@@ -1,2 +0,0 @@
1
- import type { Queue, QueueOptions } from './types.ts';
2
- export declare function queue(opts?: QueueOptions): Queue;
@@ -1,61 +0,0 @@
1
- import type { Redis, Context, Middleware, Closeable } from '../types.ts';
2
- declare module '../types.ts' {
3
- interface Context {
4
- queue: Queue;
5
- }
6
- }
7
- export interface QueueJob<T = unknown> {
8
- id: string;
9
- type: string;
10
- payload: T;
11
- createdAt: number;
12
- runAt: number;
13
- schedule?: string;
14
- }
15
- export interface QueueOptions {
16
- /** Backend store. Default: 'memory'. */
17
- store?: 'memory' | 'pg' | 'redis';
18
- redis?: Redis;
19
- url?: string;
20
- prefix?: string;
21
- pollInterval?: number;
22
- /** PostgreSQL client (required when store: 'pg'). */
23
- pg?: {
24
- sql: import('../types.ts').SqlClient;
25
- };
26
- }
27
- export interface QueueInjected {
28
- queue: Queue;
29
- }
30
- export interface QueueJobWithError<T = unknown> extends QueueJob<T> {
31
- error: string;
32
- failedAt: number;
33
- }
34
- export interface Queue extends Middleware<Context, Context & QueueInjected>, Closeable {
35
- /** Register a cron job. Uses queue's backend (memory/pg/redis) for execution. */
36
- cron(pattern: string, handler: () => void | Promise<void>): {
37
- stop: () => void;
38
- };
39
- add<T>(type: string, payload: T, opts?: {
40
- delay?: number;
41
- schedule?: string;
42
- }): Promise<string>;
43
- process<T>(type: string, handler: (job: QueueJob<T>) => Promise<void>): void;
44
- run(): Promise<void>;
45
- stats(): {
46
- running: boolean;
47
- inflight: number;
48
- processed: number;
49
- failed: number;
50
- handlers: number;
51
- maxConcurrent: number;
52
- };
53
- jobs(limit?: number): Promise<QueueJob[]>;
54
- failedJobs(limit?: number): Promise<QueueJobWithError[]>;
55
- retryFailed(jobId: string): Promise<boolean>;
56
- retryAllFailed(type?: string): Promise<number>;
57
- dashboard(): import('../core/router.ts').Router;
58
- /** Create the jobs table (PG mode only; safe to call multiple times). */
59
- migrate?(): Promise<void>;
60
- close(): Promise<void>;
61
- }
@@ -1,2 +0,0 @@
1
- import type { RedisOptions, RedisClient } from './types.ts';
2
- export declare function redis(opts?: string | RedisOptions): RedisClient;
@@ -1,2 +0,0 @@
1
- export { redis } from './client.ts';
2
- export type { RedisOptions, RedisClient, RedisInjected } from './types.ts';
@@ -1,17 +0,0 @@
1
- import type { Redis, RedisOptions as IORedisOptions, Context, Middleware, Closeable } from '../types.ts';
2
- declare module '../types.ts' {
3
- interface Context {
4
- redis: Redis;
5
- }
6
- }
7
- export type { Redis };
8
- export type RedisOptions = IORedisOptions & {
9
- url?: string;
10
- };
11
- export interface RedisInjected {
12
- redis: Redis;
13
- }
14
- export interface RedisClient extends Middleware<Context, Context & RedisInjected>, Closeable {
15
- redis: Redis;
16
- close: () => Promise<void>;
17
- }
@@ -1,193 +0,0 @@
1
- import type { Context, Handler, SqlClient } from '../types.ts';
2
- import { Router } from '../core/router.ts';
3
- import { WebSocket as WSWebSocket } from 'ws';
4
- export interface TestResponse {
5
- readonly status: number;
6
- readonly headers: Headers;
7
- json<T = unknown>(): Promise<T>;
8
- text(): Promise<string>;
9
- }
10
- export declare class TestRequest {
11
- private headers;
12
- private ctxMixin;
13
- private bodyData;
14
- private app;
15
- private method;
16
- private path;
17
- constructor(app: TestApp, method: string, path: string);
18
- /** Set a request header */
19
- header(name: string, value: string): this;
20
- /** Mix properties into ctx (simulating middleware injection) */
21
- with(mixin: Partial<Context>): this;
22
- /** Shortcut: set ctx.user */
23
- withUser(user: unknown): this;
24
- /** Shortcut: set ctx.tenant */
25
- withTenant(tenant: {
26
- id: string;
27
- name: string;
28
- role: string;
29
- }): this;
30
- /** Set JSON request body */
31
- body(data: unknown): this;
32
- /** Set raw text body */
33
- rawBody(data: string): this;
34
- /** Send the request and return the response */
35
- send(): Promise<TestResponse>;
36
- }
37
- export declare class TestApp {
38
- private router;
39
- private wsServer;
40
- private wsConnections;
41
- constructor();
42
- /**
43
- * Register a WebSocket handler.
44
- */
45
- ws(path: string, handler: import('../core/router.ts').WebSocketHandler): this;
46
- /** Get the raw Router (for advanced use). */
47
- get _router(): Router;
48
- /** Add global middleware */
49
- use(mw: any): this;
50
- /** Register a GET route — supports route-level middleware via spread args. */
51
- get(path: string, ...args: any[]): this;
52
- /** Register a POST route. */
53
- post(path: string, ...args: any[]): this;
54
- /** Register a PUT route. */
55
- put(path: string, ...args: any[]): this;
56
- /** Register a PATCH route. */
57
- patch(path: string, ...args: any[]): this;
58
- /** Register a DELETE route. */
59
- delete(path: string, ...args: any[]): this;
60
- /** Start building a GET request */
61
- getReq(path: string): TestRequest;
62
- /** Start building a POST request */
63
- postReq(path: string): TestRequest;
64
- /** Start building a PUT request */
65
- putReq(path: string): TestRequest;
66
- /** Start building a PATCH request */
67
- patchReq(path: string): TestRequest;
68
- /** Start building a DELETE request */
69
- deleteReq(path: string): TestRequest;
70
- /** Get the underlying handler (for advanced usage) */
71
- handler(): Handler;
72
- /** Start building a WebSocket connection to the given path. */
73
- wsReq(path: string): TestWSRequest;
74
- /**
75
- * Internal: ensure HTTP server is running for WebSocket connections.
76
- * Starts on a random port.
77
- */
78
- _ensureServer(): Promise<string>;
79
- /**
80
- * Internal: register a WS connection for cleanup.
81
- */
82
- _trackConnection(conn: TestWSConnection): void;
83
- /**
84
- * Cleanup all WebSocket connections and stop the server.
85
- */
86
- close(): Promise<void>;
87
- }
88
- /** Start building a WebSocket test connection. */
89
- export declare class TestWSRequest {
90
- private app;
91
- private path;
92
- private _timeout;
93
- constructor(app: TestApp, path: string);
94
- /** Set the timeout for operations (default: 5000ms). */
95
- timeout(ms: number): this;
96
- /**
97
- * Connect to the WebSocket endpoint.
98
- * Starts a real HTTP server (random port) if not already running.
99
- */
100
- connect(): Promise<TestWSConnection>;
101
- }
102
- /**
103
- * A connected WebSocket for testing.
104
- *
105
- * ```ts
106
- * const conn = await app.wsReq('/echo').connect()
107
- * conn.send('hello')
108
- * const msg = await conn.receive()
109
- * assert.equal(msg, 'hello')
110
- * conn.close()
111
- * ```
112
- */
113
- export declare class TestWSConnection {
114
- private ws;
115
- private _timeout;
116
- private messageQueue;
117
- private resolveQueue;
118
- private _closed;
119
- constructor(ws: WSWebSocket, timeout?: number);
120
- /** Send a text message. */
121
- send(data: string): void;
122
- /** Send a JSON message. */
123
- json(data: unknown): void;
124
- /**
125
- * Wait for the next message. Returns the raw text.
126
- * Throws on timeout or if the connection is closed.
127
- */
128
- receive(timeout?: number): Promise<string>;
129
- /** Wait for the next message and parse as JSON. */
130
- receiveJson<T = unknown>(): Promise<T>;
131
- /**
132
- * Assert that no message is received within the given silence period.
133
- * Useful for verifying that something did NOT happen.
134
- */
135
- expectSilent(ms: number): Promise<void>;
136
- /** Close the connection. */
137
- close(): void;
138
- /** Whether the connection is closed. */
139
- get closed(): boolean;
140
- }
141
- /** Create a new test app */
142
- export declare function testApp(): TestApp;
143
- /**
144
- * Result of createTestDb().
145
- */
146
- export interface TestDb {
147
- /** Tagged-template SQL client connected to the test database. */
148
- sql: SqlClient;
149
- /** Connection URL of the test database. */
150
- url: string;
151
- /** Schema name used for this test session. */
152
- schema: string;
153
- /** Destroy the test database (drop schema). */
154
- destroy: () => Promise<void>;
155
- }
156
- /**
157
- * Create an isolated test database schema for integration testing.
158
- *
159
- * Uses PostgreSQL schemas for isolation — no separate database needed.
160
- * Each call creates a unique schema under the same database.
161
- *
162
- * ```ts
163
- * const db = await createTestDb()
164
- * await db.sql`CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT)`
165
- * // ... run tests ...
166
- * await db.destroy() // drops the schema
167
- * ```
168
- *
169
- * Uses `TEST_DATABASE_URL` or `DATABASE_URL` env var.
170
- */
171
- export declare function createTestDb(options?: {
172
- /** Database URL. Default: TEST_DATABASE_URL or DATABASE_URL. */
173
- url?: string;
174
- /** Schema name. Default: auto-generated 'test_<timestamp>_<random>'. */
175
- schema?: string;
176
- }): Promise<TestDb>;
177
- /**
178
- * Run a test callback within an isolated transaction that is rolled back
179
- * after completion. This provides the fastest isolation — no cleanup needed.
180
- *
181
- * ```ts
182
- * await withTestDb(async (sql) => {
183
- * await sql`INSERT INTO users ...`
184
- * // All changes are rolled back after this callback returns
185
- * })
186
- * ```
187
- *
188
- * @param optionsOrFn Either a URL string or options object, or the callback directly.
189
- * @param fn Async callback receiving a tagged-template sql client.
190
- */
191
- export declare function withTestDb(optionsOrFn: string | {
192
- url?: string;
193
- } | ((sql: SqlClient) => Promise<void>), fn?: (sql: SqlClient) => Promise<void>): Promise<void>;