weifuwu 0.27.2 → 0.27.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +0 -19
  2. package/dist/ai/provider.d.ts +45 -0
  3. package/dist/ai/stream.d.ts +13 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.js +131 -0
  6. package/dist/core/cookie.d.ts +36 -0
  7. package/dist/core/env.d.ts +69 -0
  8. package/dist/core/logger.d.ts +16 -0
  9. package/dist/core/router.d.ts +72 -0
  10. package/dist/core/serve.d.ts +38 -0
  11. package/dist/core/sse.d.ts +47 -0
  12. package/dist/core/trace.d.ts +95 -0
  13. package/dist/graphql.d.ts +16 -0
  14. package/dist/hub.d.ts +36 -0
  15. package/dist/index.d.ts +59 -0
  16. package/dist/index.js +3937 -0
  17. package/dist/mailer.d.ts +51 -0
  18. package/dist/middleware/compress.d.ts +20 -0
  19. package/dist/middleware/cors.d.ts +25 -0
  20. package/dist/middleware/csrf.d.ts +47 -0
  21. package/dist/middleware/flash.d.ts +90 -0
  22. package/dist/middleware/health.d.ts +24 -0
  23. package/dist/middleware/helmet.d.ts +33 -0
  24. package/dist/middleware/i18n.d.ts +39 -0
  25. package/dist/middleware/rate-limit.d.ts +44 -0
  26. package/dist/middleware/request-id.d.ts +40 -0
  27. package/dist/middleware/static.d.ts +23 -0
  28. package/dist/middleware/theme.d.ts +31 -0
  29. package/dist/middleware/upload.d.ts +55 -0
  30. package/dist/middleware/validate.d.ts +32 -0
  31. package/dist/postgres/client.d.ts +4 -0
  32. package/dist/postgres/index.d.ts +4 -0
  33. package/dist/postgres/module.d.ts +16 -0
  34. package/dist/postgres/schema/columns.d.ts +99 -0
  35. package/dist/postgres/schema/index.d.ts +6 -0
  36. package/dist/postgres/schema/sql.d.ts +22 -0
  37. package/dist/postgres/schema/table.d.ts +141 -0
  38. package/dist/postgres/schema/where.d.ts +29 -0
  39. package/dist/postgres/types.d.ts +49 -0
  40. package/dist/queue/cron.d.ts +9 -0
  41. package/dist/queue/index.d.ts +2 -0
  42. package/dist/queue/types.d.ts +61 -0
  43. package/dist/redis/client.d.ts +2 -0
  44. package/{redis/index.ts → dist/redis/index.d.ts} +2 -2
  45. package/dist/redis/types.d.ts +17 -0
  46. package/dist/test/test-utils.d.ts +193 -0
  47. package/dist/types.d.ts +50 -0
  48. package/package.json +10 -12
  49. package/ai/provider.ts +0 -129
  50. package/ai/stream.ts +0 -63
  51. package/cli.ts +0 -147
  52. package/core/cookie.ts +0 -114
  53. package/core/env.ts +0 -142
  54. package/core/logger.ts +0 -72
  55. package/core/router.ts +0 -795
  56. package/core/serve.ts +0 -294
  57. package/core/sse.ts +0 -85
  58. package/core/trace.ts +0 -146
  59. package/graphql.ts +0 -267
  60. package/hub.ts +0 -133
  61. package/index.ts +0 -71
  62. package/mailer.ts +0 -81
  63. package/middleware/compress.ts +0 -103
  64. package/middleware/cors.ts +0 -81
  65. package/middleware/csrf.ts +0 -112
  66. package/middleware/flash.ts +0 -144
  67. package/middleware/health.ts +0 -44
  68. package/middleware/helmet.ts +0 -98
  69. package/middleware/i18n.ts +0 -175
  70. package/middleware/rate-limit.ts +0 -167
  71. package/middleware/request-id.ts +0 -60
  72. package/middleware/static.ts +0 -149
  73. package/middleware/theme.ts +0 -84
  74. package/middleware/upload.ts +0 -168
  75. package/middleware/validate.ts +0 -186
  76. package/postgres/client.ts +0 -132
  77. package/postgres/index.ts +0 -4
  78. package/postgres/module.ts +0 -37
  79. package/postgres/schema/columns.ts +0 -186
  80. package/postgres/schema/index.ts +0 -36
  81. package/postgres/schema/sql.ts +0 -39
  82. package/postgres/schema/table.ts +0 -548
  83. package/postgres/schema/where.ts +0 -99
  84. package/postgres/types.ts +0 -48
  85. package/queue/cron.ts +0 -90
  86. package/queue/index.ts +0 -654
  87. package/queue/types.ts +0 -60
  88. package/redis/client.ts +0 -24
  89. package/redis/types.ts +0 -28
  90. package/types.ts +0 -78
@@ -0,0 +1,99 @@
1
+ import { SQL } from './sql.ts';
2
+ /** Reference to another table's column (foreign key). */
3
+ export interface ColumnReference {
4
+ /** Referenced table name. */
5
+ table: string;
6
+ /** Referenced column name (default: `'id'`). */
7
+ column: string;
8
+ /** `ON DELETE` action (e.g. `'cascade'`, `'set null'`). */
9
+ onDelete?: string;
10
+ }
11
+ /**
12
+ * Fluent column builder for DDL generation.
13
+ *
14
+ * ```ts
15
+ * text('name').notNull().unique()
16
+ * integer('user_id').references('users')
17
+ * timestamptz('created_at').default(sql`NOW()`)
18
+ * ```
19
+ */
20
+ export declare class ColumnBuilder<T> {
21
+ /** Column name. */
22
+ name: string;
23
+ /** SQL type string (e.g. `'TEXT'`, `'INTEGER'`). */
24
+ sqlType: string;
25
+ /** Whether this column is PRIMARY KEY. */
26
+ isPrimaryKey: boolean;
27
+ /** Whether this column allows NULL. */
28
+ isNullable: boolean;
29
+ /** Whether this column has a UNIQUE constraint. */
30
+ isUnique: boolean;
31
+ /** Whether the value is auto-generated (e.g. SERIAL, UUID defaults). */
32
+ isAutoGenerate: boolean;
33
+ /** DEFAULT expression as a raw SQL string. */
34
+ defaultExpr: string | null;
35
+ /** Foreign key reference, if any. */
36
+ ref: ColumnReference | null;
37
+ constructor(name: string, sqlType: string);
38
+ /** Mark as PRIMARY KEY (implies NOT NULL). */
39
+ primaryKey(): this;
40
+ /** Add NOT NULL constraint. */
41
+ notNull(): this;
42
+ /** Allow NULL values (default). */
43
+ nullable(): this;
44
+ /** Set a DEFAULT value. Accepts raw SQL, string, number, or boolean. */
45
+ default(expr: SQL | string | number | boolean): this;
46
+ /** Add UNIQUE constraint. */
47
+ unique(): this;
48
+ /** Add FOREIGN KEY reference to another table. */
49
+ references(table: string, column?: string, onDelete?: string): this;
50
+ }
51
+ /** Auto-incrementing integer primary key (`SERIAL`). */
52
+ export declare function serial(name: string): ColumnBuilder<number>;
53
+ /** UUID column. */
54
+ export declare function uuid(name: string): ColumnBuilder<string>;
55
+ /** TEXT column. */
56
+ export declare function text(name: string): ColumnBuilder<string>;
57
+ /** INTEGER column. */
58
+ export declare function integer(name: string): ColumnBuilder<number>;
59
+ /** BOOLEAN column (exported as `boolean`). */
60
+ export declare function boolean_(name: string): ColumnBuilder<boolean>;
61
+ export { boolean_ as boolean };
62
+ /** TIMESTAMPTZ column (timestamp with time zone). */
63
+ export declare function timestamptz(name: string): ColumnBuilder<string>;
64
+ /** JSONB column (stores arbitrary JSON data). */
65
+ export declare function jsonb<T = unknown>(name: string): ColumnBuilder<T>;
66
+ /** TEXT[] column (PostgreSQL array of text). */
67
+ export declare function textArray(name: string): ColumnBuilder<string[]>;
68
+ /** Vector column for pgvector (embedding storage). Requires `dimensions`. */
69
+ export declare function vector(name: string, dims: number): ColumnBuilder<number[]>;
70
+ export interface PartitionByDef {
71
+ type: 'RANGE' | 'LIST' | 'HASH';
72
+ column: string;
73
+ }
74
+ export declare function partitionBy(type: 'range' | 'list' | 'hash', column: string): PartitionByDef;
75
+ /**
76
+ * Create a pair of `created_at` / `updated_at` timestamp columns
77
+ * that default to `NOW()` and are NOT NULL.
78
+ *
79
+ * ```ts
80
+ * pgTable('users', {
81
+ * id: serial('id').primaryKey(),
82
+ * name: text('name'),
83
+ * ...timestamps(),
84
+ * })
85
+ * ```
86
+ */
87
+ export declare function timestamps(): {
88
+ readonly created_at: ColumnBuilder<string>;
89
+ readonly updated_at: ColumnBuilder<string>;
90
+ };
91
+ /**
92
+ * Convert a ColumnBuilder into a DDL column definition string.
93
+ *
94
+ * ```ts
95
+ * toDDL(text('name').notNull())
96
+ * // '"name" TEXT NOT NULL'
97
+ * ```
98
+ */
99
+ export declare function toDDL(col: ColumnBuilder<unknown>): string;
@@ -0,0 +1,6 @@
1
+ export { sql, SQL } from './sql.ts';
2
+ export { ColumnBuilder, serial, uuid, text, integer, boolean as boolean, boolean_, timestamptz, jsonb, textArray, vector, toDDL, partitionBy, timestamps, } from './columns.ts';
3
+ export type { PartitionByDef } from './columns.ts';
4
+ export { pgTable, Table, BoundTable } from './table.ts';
5
+ export type { IndexOptions, FindOptions, CreateOptions } from './table.ts';
6
+ export { eq, ne, gt, gte, lt, lte, isNull, isNotNull, like, contains, in_, and, or, not, } from './where.ts';
@@ -0,0 +1,22 @@
1
+ /**
2
+ * A parameterized SQL fragment with template strings and bound values.
3
+ * Used internally by the schema builder and where helpers.
4
+ */
5
+ export declare class SQL {
6
+ /** Template string parts (interleaved with values). */
7
+ strings: TemplateStringsArray;
8
+ /** Bound parameter values. */
9
+ values: unknown[];
10
+ constructor(strings: TemplateStringsArray, values: unknown[]);
11
+ /** Serialize to a raw SQL string (interpolating values inline for DDL use). */
12
+ toSQL(): string;
13
+ }
14
+ /**
15
+ * Tagged template helper for creating parameterized SQL fragments.
16
+ *
17
+ * ```ts
18
+ * sql`NOW()`
19
+ * sql`${column} ILIKE ${'%' + search + '%'}`
20
+ * ```
21
+ */
22
+ export declare function sql(strings: TemplateStringsArray, ...values: unknown[]): SQL;
@@ -0,0 +1,141 @@
1
+ import type { SqlClient } from '../../types.ts';
2
+ import { ColumnBuilder, type PartitionByDef } from './columns.ts';
3
+ import { SQL } from './sql.ts';
4
+ /** Options for table index creation. */
5
+ export interface IndexOptions {
6
+ /** Whether the index should be UNIQUE. */
7
+ unique?: boolean;
8
+ /** Index type: btree (default), hnsw (pgvector), gin (JSONB). */
9
+ type?: 'btree' | 'hnsw' | 'gin';
10
+ /** Create index in DESC order. */
11
+ desc?: boolean;
12
+ /** Custom operator class (e.g. `vector_cosine_ops`). */
13
+ operator?: string;
14
+ }
15
+ /** Options for CREATE TABLE. */
16
+ export interface CreateOptions {
17
+ /** Partition by clause (RANGE, LIST, or HASH). */
18
+ partitionBy?: PartitionByDef;
19
+ }
20
+ /** Options for find/read queries. */
21
+ export interface FindOptions {
22
+ /** ORDER BY clause: `{ column: 'asc' | 'desc' }`. */
23
+ orderBy?: Record<string, 'asc' | 'desc'>;
24
+ /** LIMIT. */
25
+ limit?: number;
26
+ /** OFFSET. */
27
+ offset?: number;
28
+ /** Columns to SELECT (default: all). */
29
+ select?: string[];
30
+ /** Include soft-deleted rows (also sets `withDeleted` context). */
31
+ withDeleted?: boolean;
32
+ }
33
+ /**
34
+ * Type-safe table schema + CRUD operations.
35
+ *
36
+ * Create an instance with {@link pgTable}, then call `.bind(sql)` to get a
37
+ * `BoundTable` for running queries.
38
+ *
39
+ * ```ts
40
+ * const users = pgTable('users', {
41
+ * id: serial('id').primaryKey(),
42
+ * name: text('name').notNull(),
43
+ * email: text('email').unique(),
44
+ * })
45
+ *
46
+ * const db = users.bind(sql)
47
+ * await db.create()
48
+ * await db.insert({ name: 'Alice', email: 'a@b.com' })
49
+ * const row = await db.findBy({ email: 'a@b.com' })
50
+ * ```
51
+ */
52
+ export declare class Table<R extends Record<string, unknown>> {
53
+ /** Database table name. */
54
+ readonly tableName: string;
55
+ /** All column builders (order-preserving). */
56
+ readonly columns: ColumnBuilder<unknown>[];
57
+ /** Column builders keyed by property name. */
58
+ readonly builders: Record<string, ColumnBuilder<unknown>>;
59
+ private colEntries;
60
+ constructor(tableName: string, builders: Record<string, ColumnBuilder<unknown>>);
61
+ /** Check if the table has a column with the given DB name. */
62
+ hasColumn(dbName: string): boolean;
63
+ /**
64
+ * Bind this table schema to a SQL connection, returning a `BoundTable`
65
+ * that can run queries without passing `sql` to every call.
66
+ */
67
+ bind(sql: SqlClient): BoundTable<R>;
68
+ /** Returns the primary key column name (DB name), or 'id' as fallback. */
69
+ private get pkColumn();
70
+ /** Adds `deleted_at IS NULL` condition if the table has soft delete and not explicitly excluded. */
71
+ private _softDeleteFilter;
72
+ create(sql: SqlClient, opts?: CreateOptions): Promise<void>;
73
+ drop(sql: SqlClient, opts?: {
74
+ cascade?: boolean;
75
+ }): Promise<void>;
76
+ createIndex(sql: SqlClient, columns: string | string[], opts?: IndexOptions): Promise<void>;
77
+ createUniqueIndex(sql: SqlClient, columns: string | string[]): Promise<void>;
78
+ private _buildConditions;
79
+ private _buildSET;
80
+ insert(sql: SqlClient, data: Partial<R>): Promise<R>;
81
+ insertMany(sql: SqlClient, data: Partial<R>[]): Promise<R[]>;
82
+ read(sql: SqlClient, id: string | number, opts?: Pick<FindOptions, 'select' | 'withDeleted'>): Promise<R | undefined>;
83
+ readMany(sql: SqlClient, where?: Partial<R> | SQL | SQL[], opts?: FindOptions): Promise<{
84
+ count: number;
85
+ data: R[];
86
+ }>;
87
+ update(sql: SqlClient, id: string | number, data: Partial<R>): Promise<R | undefined>;
88
+ updateMany(sql: SqlClient, where: Partial<R> | SQL | SQL[], data: Partial<R>): Promise<number>;
89
+ delete(sql: SqlClient, id: string | number): Promise<R | undefined>;
90
+ hardDelete(sql: SqlClient, id: string | number): Promise<R | undefined>;
91
+ deleteMany(sql: SqlClient, where: Partial<R> | SQL | SQL[]): Promise<number>;
92
+ hardDeleteMany(sql: SqlClient, where: Partial<R> | SQL | SQL[]): Promise<number>;
93
+ upsert(sql: SqlClient, data: Partial<R>, conflict: string | string[]): Promise<R>;
94
+ count(sql: SqlClient, where?: Partial<R> | SQL | SQL[]): Promise<number>;
95
+ }
96
+ export declare class BoundTable<R extends Record<string, unknown>> {
97
+ private inner;
98
+ private sql;
99
+ /** The underlying table name. */
100
+ get tableName(): string;
101
+ constructor(sql: SqlClient, tableName: string, builders: Record<string, ColumnBuilder<unknown>>);
102
+ create(opts?: CreateOptions): Promise<void>;
103
+ drop(opts?: {
104
+ cascade?: boolean;
105
+ }): Promise<void>;
106
+ createIndex(columns: string | string[], opts?: IndexOptions): Promise<void>;
107
+ createUniqueIndex(columns: string | string[]): Promise<void>;
108
+ insert(data: Partial<R>): Promise<R>;
109
+ insertMany(data: Partial<R>[]): Promise<R[]>;
110
+ read(id: string | number, opts?: Pick<FindOptions, 'select' | 'withDeleted'>): Promise<R | undefined>;
111
+ readMany(where?: Partial<R> | SQL | SQL[], opts?: FindOptions): Promise<{
112
+ count: number;
113
+ data: R[];
114
+ }>;
115
+ update(id: string | number, data: Partial<R>): Promise<R | undefined>;
116
+ updateMany(where: Partial<R> | SQL | SQL[], data: Partial<R>): Promise<number>;
117
+ delete(id: string | number): Promise<R | undefined>;
118
+ hardDelete(id: string | number): Promise<R | undefined>;
119
+ deleteMany(where: Partial<R> | SQL | SQL[]): Promise<number>;
120
+ hardDeleteMany(where: Partial<R> | SQL | SQL[]): Promise<number>;
121
+ upsert(data: Partial<R>, conflict: string | string[]): Promise<R>;
122
+ count(where?: Partial<R> | SQL | SQL[]): Promise<number>;
123
+ withSql(sql: SqlClient): BoundTable<R>;
124
+ }
125
+ /**
126
+ * Define a type-safe table schema.
127
+ *
128
+ * ```ts
129
+ * const users = pgTable('users', {
130
+ * id: serial('id').primaryKey(),
131
+ * name: text('name').notNull(),
132
+ * email: text('email').unique(),
133
+ * })
134
+ *
135
+ * // The generic type R preserves the column types:
136
+ * // Table<{ id: number; name: string; email: string }>
137
+ * ```
138
+ */
139
+ export declare function pgTable<R extends Record<string, unknown>>(tableName: string, builders: {
140
+ [K in keyof R]: ColumnBuilder<R[K]>;
141
+ }): Table<R>;
@@ -0,0 +1,29 @@
1
+ import { SQL } from './sql.ts';
2
+ /** Column equals value: `col = val`. */
3
+ export declare function eq(col: string, val: unknown): SQL;
4
+ /** Column not equals value: `col != val`. */
5
+ export declare function ne(col: string, val: unknown): SQL;
6
+ /** Column greater than value: `col > val`. */
7
+ export declare function gt(col: string, val: unknown): SQL;
8
+ /** Column greater than or equal value: `col >= val`. */
9
+ export declare function gte(col: string, val: unknown): SQL;
10
+ /** Column less than value: `col < val`. */
11
+ export declare function lt(col: string, val: unknown): SQL;
12
+ /** Column less than or equal value: `col <= val`. */
13
+ export declare function lte(col: string, val: unknown): SQL;
14
+ /** Column IS NULL. */
15
+ export declare function isNull(col: string): SQL;
16
+ /** Column IS NOT NULL. */
17
+ export declare function isNotNull(col: string): SQL;
18
+ /** Column LIKE pattern. */
19
+ export declare function like(col: string, pattern: string): SQL;
20
+ /** Negate a condition: `NOT (condition)`. */
21
+ export declare function not(condition: SQL): SQL;
22
+ /** JSONB containment: `col @> val` (does `col` contain `val`?). */
23
+ export declare function contains(col: string, val: Record<string, unknown>): SQL;
24
+ /** Column value is in array: `col = ANY(val)`. */
25
+ export declare function in_(col: string, val: unknown[]): SQL;
26
+ /** Combine conditions with AND. */
27
+ export declare function and(...conditions: SQL[]): SQL;
28
+ /** Combine conditions with OR. */
29
+ export declare function or(...conditions: SQL[]): SQL;
@@ -0,0 +1,49 @@
1
+ import type { SqlClient, Context, Middleware, Closeable } from '../types.ts';
2
+ import type { ColumnBuilder, BoundTable, Table } from './schema/index.ts';
3
+ declare module '../types.ts' {
4
+ interface Context {
5
+ sql: SqlClient;
6
+ }
7
+ }
8
+ export interface PostgresInjected {
9
+ sql: SqlClient;
10
+ }
11
+ export interface PostgresOptions {
12
+ connection?: string | Record<string, unknown>;
13
+ signal?: AbortSignal;
14
+ closeTimeout?: number;
15
+ max?: number;
16
+ ssl?: boolean | Record<string, unknown>;
17
+ idle_timeout?: number;
18
+ connect_timeout?: number;
19
+ /** Per-statement timeout in ms. Set to 0 to disable. Default: 30_000. */
20
+ statementTimeout?: number;
21
+ /** Called after every query completes. Receives query text, duration in ms, and row count. */
22
+ onQuery?: (query: string, durationMs: number, rowCount: number) => void;
23
+ }
24
+ export interface PostgresClient extends Middleware<Context, Context & PostgresInjected>, Closeable {
25
+ sql: SqlClient;
26
+ /** Creates the migration tracking table (_weifuwu_migrations). Called once at startup. */
27
+ migrate: () => Promise<void>;
28
+ /** Record that a module's migration has been applied (idempotent). */
29
+ markMigrated: (moduleName: string) => Promise<void>;
30
+ /** Check whether a module has already been migrated. */
31
+ isMigrated: (moduleName: string) => Promise<boolean>;
32
+ table: {
33
+ <R extends Record<string, unknown>>(tableName: string, builders: {
34
+ [K in keyof R]: ColumnBuilder<R[K]>;
35
+ }): BoundTable<R>;
36
+ <R extends Record<string, unknown>>(schema: Table<R>): BoundTable<R>;
37
+ };
38
+ transaction: <T>(fn: (sql: any) => Promise<T>, retryOpts?: {
39
+ maxRetries?: number;
40
+ }) => Promise<T>;
41
+ /** Snapshot of connection pool state: active, idle, waiting, max connections. */
42
+ poolStats: () => {
43
+ active: number;
44
+ idle: number;
45
+ waiting: number;
46
+ max: number;
47
+ };
48
+ close: () => Promise<void>;
49
+ }
@@ -0,0 +1,9 @@
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;
@@ -0,0 +1,2 @@
1
+ import type { Queue, QueueOptions } from './types.ts';
2
+ export declare function queue(opts?: QueueOptions): Queue;
@@ -0,0 +1,61 @@
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
+ }
@@ -0,0 +1,2 @@
1
+ import type { RedisOptions, RedisClient } from './types.ts';
2
+ export declare function redis(opts?: string | RedisOptions): RedisClient;
@@ -1,2 +1,2 @@
1
- export { redis } from './client.ts'
2
- export type { RedisOptions, RedisClient, RedisInjected } from './types.ts'
1
+ export { redis } from './client.ts';
2
+ export type { RedisOptions, RedisClient, RedisInjected } from './types.ts';
@@ -0,0 +1,17 @@
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
+ }
@@ -0,0 +1,193 @@
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>;