@spfn/core 0.1.0-alpha.8 → 0.1.0-alpha.82

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 (61) hide show
  1. package/README.md +169 -195
  2. package/dist/auto-loader-JFaZ9gON.d.ts +80 -0
  3. package/dist/cache/index.d.ts +211 -0
  4. package/dist/cache/index.js +1013 -0
  5. package/dist/cache/index.js.map +1 -0
  6. package/dist/client/index.d.ts +131 -92
  7. package/dist/client/index.js +93 -85
  8. package/dist/client/index.js.map +1 -1
  9. package/dist/codegen/generators/index.d.ts +19 -0
  10. package/dist/codegen/generators/index.js +1521 -0
  11. package/dist/codegen/generators/index.js.map +1 -0
  12. package/dist/codegen/index.d.ts +76 -60
  13. package/dist/codegen/index.js +1506 -735
  14. package/dist/codegen/index.js.map +1 -1
  15. package/dist/database-errors-BNNmLTJE.d.ts +86 -0
  16. package/dist/db/index.d.ts +844 -44
  17. package/dist/db/index.js +1281 -1307
  18. package/dist/db/index.js.map +1 -1
  19. package/dist/env/index.d.ts +508 -0
  20. package/dist/env/index.js +1127 -0
  21. package/dist/env/index.js.map +1 -0
  22. package/dist/errors/index.d.ts +136 -0
  23. package/dist/errors/index.js +172 -0
  24. package/dist/errors/index.js.map +1 -0
  25. package/dist/index-DHiAqhKv.d.ts +101 -0
  26. package/dist/index.d.ts +3 -374
  27. package/dist/index.js +2424 -2178
  28. package/dist/index.js.map +1 -1
  29. package/dist/logger/index.d.ts +94 -0
  30. package/dist/logger/index.js +795 -0
  31. package/dist/logger/index.js.map +1 -0
  32. package/dist/middleware/index.d.ts +60 -0
  33. package/dist/middleware/index.js +918 -0
  34. package/dist/middleware/index.js.map +1 -0
  35. package/dist/route/index.d.ts +21 -53
  36. package/dist/route/index.js +1259 -219
  37. package/dist/route/index.js.map +1 -1
  38. package/dist/server/index.d.ts +18 -0
  39. package/dist/server/index.js +2419 -2059
  40. package/dist/server/index.js.map +1 -1
  41. package/dist/types/index.d.ts +121 -0
  42. package/dist/types/index.js +38 -0
  43. package/dist/types/index.js.map +1 -0
  44. package/dist/types-BXibIEyj.d.ts +60 -0
  45. package/package.json +67 -17
  46. package/dist/auto-loader-C44TcLmM.d.ts +0 -125
  47. package/dist/bind-pssq1NRT.d.ts +0 -34
  48. package/dist/postgres-errors-CY_Es8EJ.d.ts +0 -1703
  49. package/dist/scripts/index.d.ts +0 -24
  50. package/dist/scripts/index.js +0 -1201
  51. package/dist/scripts/index.js.map +0 -1
  52. package/dist/scripts/templates/api-index.template.txt +0 -10
  53. package/dist/scripts/templates/api-tag.template.txt +0 -11
  54. package/dist/scripts/templates/contract.template.txt +0 -87
  55. package/dist/scripts/templates/entity-type.template.txt +0 -31
  56. package/dist/scripts/templates/entity.template.txt +0 -19
  57. package/dist/scripts/templates/index.template.txt +0 -10
  58. package/dist/scripts/templates/repository.template.txt +0 -37
  59. package/dist/scripts/templates/routes-id.template.txt +0 -59
  60. package/dist/scripts/templates/routes-index.template.txt +0 -44
  61. package/dist/types-SlzTr8ZO.d.ts +0 -143
@@ -1,67 +1,257 @@
1
- import { P as PoolConfig, R as RetryConfig } from '../postgres-errors-CY_Es8EJ.js';
2
- export { h as DatabaseClients, D as DbConnectionType, m as DrizzleConfigOptions, y as Page, x as Pageable, Q as QueryBuilder, n as Repository, t as RepositoryScope, G as TransactionContext, H as TransactionDB, T as Transactional, I as TransactionalOptions, W as WrappedDb, p as clearRepositoryCache, e as closeDatabase, c as createDatabaseFromEnv, d as db, k as detectDialect, B as foreignKey, J as fromPostgresError, l as generateDrizzleConfigFile, b as getDatabase, f as getDatabaseInfo, a as getDb, j as getDrizzleConfig, g as getRawDb, o as getRepository, q as getRepositoryCacheSize, u as getScopedCacheSize, r as getScopedRepository, E as getTransaction, z as id, i as initDatabase, v as isInRepositoryScope, C as optionalForeignKey, F as runWithTransaction, s as setDatabase, A as timestamps, w as withRepositoryScope } from '../postgres-errors-CY_Es8EJ.js';
3
- import { Sql } from 'postgres';
4
- import { PgTable } from 'drizzle-orm/pg-core';
5
- import 'drizzle-orm/postgres-js';
6
- import 'hono';
7
- import 'drizzle-orm/pg-core/query-builders/raw';
8
- import 'drizzle-orm';
1
+ import { PostgresJsDatabase } from 'drizzle-orm/postgres-js';
2
+ import postgres, { Sql } from 'postgres';
3
+ import * as drizzle_orm from 'drizzle-orm';
4
+ import { SQL } from 'drizzle-orm';
5
+ import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
6
+ import { PgColumn, PgTable } from 'drizzle-orm/pg-core';
7
+ import * as hono from 'hono';
8
+ import { D as DatabaseError } from '../database-errors-BNNmLTJE.js';
9
9
 
10
10
  /**
11
- * Table Name Utilities
11
+ * Database Configuration
12
12
  *
13
- * Helper functions for extracting table names from Drizzle table objects.
14
- * Used by Repository for accessing db.query API with dynamic table names.
13
+ * DB 연결 Connection Pool 설정
14
+ *
15
+ * ✅ 구현 완료:
16
+ * - 환경별 Connection Pool 설정
17
+ * - 재시도 설정 (Exponential Backoff)
18
+ * - 환경변수 기반 설정
19
+ *
20
+ * 🔗 관련 파일:
21
+ * - src/server/core/db/connection.ts (연결 로직)
22
+ * - src/server/core/db/index.ts (메인 export)
23
+ */
24
+
25
+ interface DatabaseClients {
26
+ /** Primary database for writes (or both read/write if no replica) */
27
+ write?: PostgresJsDatabase;
28
+ /** Replica database for reads (optional, falls back to write) */
29
+ read?: PostgresJsDatabase;
30
+ /** Raw postgres client for write operations (for cleanup) */
31
+ writeClient?: Sql;
32
+ /** Raw postgres client for read operations (for cleanup) */
33
+ readClient?: Sql;
34
+ }
35
+ /**
36
+ * Health check configuration
37
+ */
38
+ interface HealthCheckConfig {
39
+ enabled: boolean;
40
+ interval: number;
41
+ reconnect: boolean;
42
+ maxRetries: number;
43
+ retryInterval: number;
44
+ }
45
+ /**
46
+ * Query performance monitoring configuration
47
+ */
48
+ interface MonitoringConfig {
49
+ enabled: boolean;
50
+ slowThreshold: number;
51
+ logQueries: boolean;
52
+ }
53
+ /**
54
+ * Database initialization options
55
+ */
56
+ interface DatabaseOptions {
57
+ /**
58
+ * Connection pool configuration
59
+ * Overrides environment variables and defaults
60
+ */
61
+ pool?: Partial<PoolConfig>;
62
+ /**
63
+ * Health check configuration
64
+ * Periodic checks to ensure database connection is alive
65
+ */
66
+ healthCheck?: Partial<HealthCheckConfig>;
67
+ /**
68
+ * Query performance monitoring configuration
69
+ * Tracks slow queries and logs performance metrics
70
+ */
71
+ monitoring?: Partial<MonitoringConfig>;
72
+ }
73
+ /**
74
+ * Connection Pool 설정
75
+ */
76
+ interface PoolConfig {
77
+ max: number;
78
+ idleTimeout: number;
79
+ }
80
+ /**
81
+ * 재시도 설정
82
+ */
83
+ interface RetryConfig {
84
+ maxRetries: number;
85
+ initialDelay: number;
86
+ maxDelay: number;
87
+ factor: number;
88
+ }
89
+
90
+ /**
91
+ * Database factory with automatic environment variable detection
92
+ * Supports: Single primary, Primary + Replica
15
93
  */
16
94
 
17
95
  /**
18
- * Get table name from Drizzle table object
96
+ * Create database client(s) from environment variables
19
97
  *
20
- * Uses WeakMap cache to avoid repeated Symbol lookups for better performance.
98
+ * Supported patterns (priority order):
99
+ * 1. Single primary: DATABASE_URL
100
+ * 2. Primary + Replica: DATABASE_WRITE_URL + DATABASE_READ_URL
101
+ * 3. Legacy replica: DATABASE_URL + DATABASE_REPLICA_URL
21
102
  *
22
- * @param table - Drizzle table schema
23
- * @returns Table name string
103
+ * @param options - Optional database configuration (pool settings, etc.)
104
+ * @returns Database client(s) or undefined if no configuration found
105
+ *
106
+ * @example
107
+ * ```bash
108
+ * # Single primary (most common)
109
+ * DATABASE_URL=postgresql://localhost:5432/mydb
110
+ *
111
+ * # Primary + Replica
112
+ * DATABASE_WRITE_URL=postgresql://primary:5432/mydb
113
+ * DATABASE_READ_URL=postgresql://replica:5432/mydb
114
+ *
115
+ * # Legacy (backward compatibility)
116
+ * DATABASE_URL=postgresql://primary:5432/mydb
117
+ * DATABASE_REPLICA_URL=postgresql://replica:5432/mydb
118
+ * ```
24
119
  *
25
120
  * @example
26
121
  * ```typescript
27
- * import { users } from './schema';
28
- * const name = getTableName(users); // 'users'
122
+ * // Custom pool configuration
123
+ * const db = await createDatabaseFromEnv({
124
+ * pool: { max: 50, idleTimeout: 60 }
125
+ * });
29
126
  * ```
30
127
  */
31
- declare function getTableName(table: PgTable): string;
128
+ declare function createDatabaseFromEnv(options?: DatabaseOptions): Promise<DatabaseClients>;
129
+
130
+ /**
131
+ * Global Database instance manager
132
+ * Provides singleton access to database across all modules
133
+ * Supports Primary + Replica pattern with separate read/write instances
134
+ */
32
135
 
33
136
  /**
34
- * Database Connection Logic
137
+ * DB connection type
138
+ */
139
+ type DbConnectionType = 'read' | 'write';
140
+ /**
141
+ * Get global database write instance
35
142
  *
36
- * DB 연결 생성 재시도 로직
143
+ * @returns Database write instance or undefined if not initialized
37
144
  *
38
- * ✅ 구현 완료:
39
- * - Exponential Backoff 재시도 로직
40
- * - 연결 테스트 쿼리
41
- * - 상세한 에러 로깅
42
- * - 연결 성공/실패 로깅
43
- * - Logger 적용 (console.log 대체)
145
+ * @example
146
+ * ```typescript
147
+ * import { getDatabase } from '@spfn/core/db';
44
148
  *
45
- * ⚠️ 개선 필요:
46
- * - 에러 타입별 처리 (네트워크 vs 인증)
47
- * - Graceful Shutdown 로직
149
+ * const db = getDatabase();
150
+ * if (db) {
151
+ * const users = await db.select().from(usersTable);
152
+ * }
153
+ * ```
154
+ */
155
+ declare function getDatabase(type?: DbConnectionType): PostgresJsDatabase<Record<string, unknown>> | undefined;
156
+ /**
157
+ * Set global database instances (for testing or manual configuration)
48
158
  *
49
- * 💡 향후 고려사항:
50
- * - 연결 이벤트 리스너
51
- * - 연결 상태 메트릭 수집
52
- * - 연결 풀 동적 조정
159
+ * @param write - Database write instance
160
+ * @param read - Database read instance (optional, defaults to write)
53
161
  *
54
- * 🔗 관련 파일:
55
- * - src/server/core/db/config.ts (설정)
56
- * - src/server/core/db/index.ts (메인 export)
57
- * - src/server/core/logger/ (Logger)
162
+ * @example
163
+ * ```typescript
164
+ * import { setDatabase } from '@spfn/core/db';
165
+ * import { drizzle } from 'drizzle-orm/postgres-js';
166
+ * import postgres from 'postgres';
58
167
  *
59
- * 📝 TODO: improvements.md 참고
60
- * - #7: Connection Pool 모니터링 (Pool 이벤트 리스너, 활성/유휴 연결 추적)
61
- * - #9: Slow Query 로깅 (쿼리 실행 시간 측정 및 임계값 로깅)
62
- * - #10: Graceful Shutdown (SIGTERM 처리, 진행 중인 쿼리 완료 대기)
63
- * - #11: Read Replica 지원 (읽기/쓰기 분리)
168
+ * const writeClient = postgres('postgresql://primary:5432/mydb');
169
+ * const readClient = postgres('postgresql://replica:5432/mydb');
170
+ * setDatabase(drizzle(writeClient), drizzle(readClient));
171
+ * ```
64
172
  */
173
+ declare function setDatabase(write: PostgresJsDatabase<Record<string, unknown>> | undefined, read?: PostgresJsDatabase<Record<string, unknown>> | undefined): void;
174
+ /**
175
+ * Initialize database from environment variables
176
+ * Automatically called by server startup
177
+ *
178
+ * Supported environment variables:
179
+ * - DATABASE_URL (single primary)
180
+ * - DATABASE_WRITE_URL + DATABASE_READ_URL (primary + replica)
181
+ * - DATABASE_URL + DATABASE_REPLICA_URL (legacy replica)
182
+ * - DB_POOL_MAX (connection pool max size)
183
+ * - DB_POOL_IDLE_TIMEOUT (connection idle timeout in seconds)
184
+ * - DB_HEALTH_CHECK_ENABLED (enable health checks, default: true)
185
+ * - DB_HEALTH_CHECK_INTERVAL (health check interval in ms, default: 60000)
186
+ * - DB_HEALTH_CHECK_RECONNECT (enable auto-reconnect, default: true)
187
+ * - DB_HEALTH_CHECK_MAX_RETRIES (max reconnection attempts, default: 3)
188
+ * - DB_HEALTH_CHECK_RETRY_INTERVAL (retry interval in ms, default: 5000)
189
+ * - DB_MONITORING_ENABLED (enable query monitoring, default: true in dev, false in prod)
190
+ * - DB_MONITORING_SLOW_THRESHOLD (slow query threshold in ms, default: 1000)
191
+ * - DB_MONITORING_LOG_QUERIES (log actual SQL queries, default: false)
192
+ *
193
+ * Configuration priority:
194
+ * 1. options parameter (ServerConfig)
195
+ * 2. Environment variables
196
+ * 3. Defaults (based on NODE_ENV)
197
+ *
198
+ * @param options - Optional database configuration (pool settings, etc.)
199
+ * @returns Object with write and read instances
200
+ *
201
+ * @example
202
+ * ```typescript
203
+ * import { initDatabase } from '@spfn/core/db';
204
+ *
205
+ * // Manual initialization (not needed if using server startup)
206
+ * const { write, read } = await initDatabase();
207
+ * if (write) {
208
+ * console.log('Database connected');
209
+ * }
210
+ * ```
211
+ *
212
+ * @example
213
+ * ```typescript
214
+ * // Custom pool configuration
215
+ * const { write, read } = await initDatabase({
216
+ * pool: { max: 50, idleTimeout: 60 }
217
+ * });
218
+ * ```
219
+ */
220
+ declare function initDatabase(options?: DatabaseOptions): Promise<{
221
+ write?: PostgresJsDatabase<Record<string, unknown>>;
222
+ read?: PostgresJsDatabase<Record<string, unknown>>;
223
+ }>;
224
+ /**
225
+ * Close all database connections and cleanup
226
+ *
227
+ * Properly closes postgres connection pools with timeout.
228
+ * Should be called during graceful shutdown or after tests.
229
+ *
230
+ * @example
231
+ * ```typescript
232
+ * import { closeDatabase } from '@spfn/core/db';
233
+ *
234
+ * // During graceful shutdown
235
+ * process.on('SIGTERM', async () => {
236
+ * await closeDatabase();
237
+ * process.exit(0);
238
+ * });
239
+ *
240
+ * // In tests
241
+ * afterAll(async () => {
242
+ * await closeDatabase();
243
+ * });
244
+ * ```
245
+ */
246
+ declare function closeDatabase(): Promise<void>;
247
+ /**
248
+ * Get database connection info (for debugging)
249
+ */
250
+ declare function getDatabaseInfo(): {
251
+ hasWrite: boolean;
252
+ hasRead: boolean;
253
+ isReplica: boolean;
254
+ };
65
255
 
66
256
  /**
67
257
  * Exponential Backoff로 DB 연결 생성
@@ -71,7 +261,7 @@ declare function getTableName(table: PgTable): string;
71
261
  * @param retryConfig - 재시도 설정
72
262
  * @returns PostgreSQL 클라이언트
73
263
  */
74
- declare function createDatabaseConnection(connectionString: string, poolConfig: PoolConfig, retryConfig: RetryConfig): Promise<Sql<{}>>;
264
+ declare function createDatabaseConnection(connectionString: string, poolConfig: PoolConfig, retryConfig: RetryConfig): Promise<postgres.Sql<{}>>;
75
265
  /**
76
266
  * DB 연결 상태 확인
77
267
  *
@@ -80,4 +270,614 @@ declare function createDatabaseConnection(connectionString: string, poolConfig:
80
270
  */
81
271
  declare function checkConnection(client: Sql): Promise<boolean>;
82
272
 
83
- export { PoolConfig, RetryConfig, checkConnection, createDatabaseConnection, getTableName };
273
+ /**
274
+ * Drizzle Kit configuration generator
275
+ * Automatically generates drizzle.config.ts from environment variables
276
+ */
277
+ interface DrizzleConfigOptions {
278
+ /** Database connection URL (defaults to process.env.DATABASE_URL) */
279
+ databaseUrl?: string;
280
+ /** Schema files glob pattern or array of patterns (defaults to './src/server/entities/\*\*\/*.ts') */
281
+ schema?: string | string[];
282
+ /** Migration output directory (defaults to './src/server/drizzle') */
283
+ out?: string;
284
+ /** Database dialect (auto-detected from URL if not provided) */
285
+ dialect?: 'postgresql' | 'mysql' | 'sqlite';
286
+ /** Current working directory for discovering package schemas */
287
+ cwd?: string;
288
+ /** Disable automatic package schema discovery */
289
+ disablePackageDiscovery?: boolean;
290
+ /** Only include schemas from specific package (e.g., '@spfn/cms') */
291
+ packageFilter?: string;
292
+ }
293
+ /**
294
+ * Detect database dialect from connection URL
295
+ */
296
+ declare function detectDialect(url: string): 'postgresql' | 'mysql' | 'sqlite';
297
+ /**
298
+ * Generate Drizzle Kit configuration
299
+ *
300
+ * @param options - Configuration options
301
+ * @returns Drizzle Kit configuration object
302
+ *
303
+ * @example
304
+ * ```ts
305
+ * // Zero-config (reads from process.env.DATABASE_URL)
306
+ * const config = getDrizzleConfig();
307
+ *
308
+ * // Custom config
309
+ * const config = getDrizzleConfig({
310
+ * databaseUrl: 'postgresql://localhost/mydb',
311
+ * schema: './src/db/schema/*.ts',
312
+ * out: './migrations',
313
+ * });
314
+ * ```
315
+ */
316
+ declare function getDrizzleConfig(options?: DrizzleConfigOptions): {
317
+ schema: string | string[];
318
+ out: string;
319
+ dialect: "postgresql" | "mysql" | "sqlite";
320
+ dbCredentials: {
321
+ url: string;
322
+ };
323
+ };
324
+ /**
325
+ * Generate drizzle.config.ts file content
326
+ *
327
+ * @param options - Configuration options
328
+ * @returns File content as string
329
+ */
330
+ declare function generateDrizzleConfigFile(options?: DrizzleConfigOptions): string;
331
+
332
+ /**
333
+ * Standard auto-incrementing primary key
334
+ *
335
+ * @returns bigserial primary key column
336
+ *
337
+ * @example
338
+ * ```typescript
339
+ * export const users = pgTable('users', {
340
+ * id: id(),
341
+ * // ...
342
+ * });
343
+ * ```
344
+ */
345
+ declare function id(): drizzle_orm.IsPrimaryKey<drizzle_orm.NotNull<drizzle_orm_pg_core.PgBigSerial53BuilderInitial<"id">>>;
346
+ /**
347
+ * Standard timestamp fields (createdAt, updatedAt)
348
+ *
349
+ * Both fields are timezone-aware, auto-set to current time on creation.
350
+ * When autoUpdate is enabled, updatedAt will be automatically updated on record updates.
351
+ *
352
+ * @param options - Optional configuration
353
+ * @param options.autoUpdate - Automatically update updatedAt on record updates (default: false)
354
+ * @returns Object with createdAt and updatedAt columns
355
+ *
356
+ * @example
357
+ * ```typescript
358
+ * // Without auto-update
359
+ * export const users = pgTable('users', {
360
+ * id: id(),
361
+ * email: text('email'),
362
+ * ...timestamps(),
363
+ * });
364
+ *
365
+ * // With auto-update
366
+ * export const posts = pgTable('posts', {
367
+ * id: id(),
368
+ * title: text('title'),
369
+ * ...timestamps({ autoUpdate: true }),
370
+ * });
371
+ * ```
372
+ */
373
+ declare function timestamps(options?: {
374
+ autoUpdate?: boolean;
375
+ }): {
376
+ createdAt: drizzle_orm.NotNull<drizzle_orm.HasDefault<drizzle_orm_pg_core.PgTimestampBuilderInitial<"created_at">>>;
377
+ updatedAt: drizzle_orm.NotNull<drizzle_orm.HasDefault<drizzle_orm_pg_core.PgTimestampBuilderInitial<"updated_at">>>;
378
+ };
379
+ /**
380
+ * Foreign key reference to another table
381
+ *
382
+ * Creates a bigserial column with cascade delete.
383
+ * Type-safe: ensures the reference points to a valid PostgreSQL column.
384
+ *
385
+ * @param name - Column name (e.g., 'author' creates 'author_id')
386
+ * @param reference - Reference to parent table column
387
+ * @param options - Optional foreign key options
388
+ *
389
+ * @example
390
+ * ```typescript
391
+ * import { users } from './users';
392
+ *
393
+ * export const posts = pgTable('posts', {
394
+ * id: id(),
395
+ * authorId: foreignKey('author', () => users.id),
396
+ * ...timestamps(),
397
+ * });
398
+ * ```
399
+ */
400
+ declare function foreignKey<T extends PgColumn>(name: string, reference: () => T, options?: {
401
+ onDelete?: 'cascade' | 'set null' | 'restrict' | 'no action';
402
+ }): drizzle_orm.NotNull<drizzle_orm_pg_core.PgBigSerial53BuilderInitial<`${string}_id`>>;
403
+ /**
404
+ * Optional foreign key reference (nullable)
405
+ *
406
+ * Type-safe: ensures the reference points to a valid PostgreSQL column.
407
+ *
408
+ * @param name - Column name (e.g., 'author' creates 'author_id')
409
+ * @param reference - Reference to parent table column
410
+ * @param options - Optional foreign key options
411
+ *
412
+ * @example
413
+ * ```typescript
414
+ * export const posts = pgTable('posts', {
415
+ * id: id(),
416
+ * authorId: optionalForeignKey('author', () => users.id),
417
+ * });
418
+ * ```
419
+ */
420
+ declare function optionalForeignKey<T extends PgColumn>(name: string, reference: () => T, options?: {
421
+ onDelete?: 'cascade' | 'set null' | 'restrict' | 'no action';
422
+ }): drizzle_orm_pg_core.PgBigSerial53BuilderInitial<`${string}_id`>;
423
+
424
+ /**
425
+ * Database Schema Helper
426
+ *
427
+ * Provides utilities for creating isolated PostgreSQL schemas for SPFN functions
428
+ */
429
+ /**
430
+ * Create a namespaced PostgreSQL schema for a function
431
+ *
432
+ * @param packageName - NPM package name (e.g., '@spfn/cms', 'spfn-auth')
433
+ * @returns PostgreSQL schema object for creating tables
434
+ *
435
+ * @example
436
+ * ```typescript
437
+ * // @spfn/cms → spfn_cms schema
438
+ * import { createFunctionSchema } from '@spfn/core/db';
439
+ *
440
+ * const schema = createFunctionSchema('@spfn/cms');
441
+ *
442
+ * export const labels = schema.table('labels', {
443
+ * id: id(),
444
+ * name: text('name').notNull(),
445
+ * });
446
+ * // Creates table: spfn_cms.labels
447
+ * ```
448
+ */
449
+ declare function createFunctionSchema(packageName: string): drizzle_orm_pg_core.PgSchema<string>;
450
+ /**
451
+ * Convert package name to PostgreSQL schema name
452
+ *
453
+ * @param packageName - NPM package name
454
+ * @returns Schema name in PostgreSQL format
455
+ *
456
+ * @example
457
+ * ```typescript
458
+ * packageNameToSchema('@spfn/cms') // 'spfn_cms'
459
+ * packageNameToSchema('@company/spfn-auth') // 'company_spfn_auth'
460
+ * packageNameToSchema('spfn-storage') // 'spfn_storage'
461
+ * ```
462
+ */
463
+ declare function packageNameToSchema(packageName: string): string;
464
+ /**
465
+ * Get recommended schema name for a package
466
+ *
467
+ * @param packageName - NPM package name
468
+ * @returns Object with schema name and whether it's scoped
469
+ *
470
+ * @example
471
+ * ```typescript
472
+ * getSchemaInfo('@spfn/cms')
473
+ * // { schemaName: 'spfn_cms', isScoped: true, scope: 'spfn' }
474
+ *
475
+ * getSchemaInfo('spfn-auth')
476
+ * // { schemaName: 'spfn_auth', isScoped: false, scope: null }
477
+ * ```
478
+ */
479
+ declare function getSchemaInfo(packageName: string): {
480
+ schemaName: string;
481
+ isScoped: boolean;
482
+ scope: string | null;
483
+ };
484
+
485
+ /**
486
+ * AsyncLocalStorage-based Transaction Context
487
+ *
488
+ * Uses Node.js AsyncLocalStorage to propagate transactions throughout the async call chain.
489
+ *
490
+ * Features:
491
+ * - AsyncLocalStorage-based context management
492
+ * - Type-safe transaction propagation across async chains
493
+ * - Transaction ID tracking for debugging and tracing
494
+ * - Nested transaction detection and logging
495
+ * - Transaction nesting level tracking
496
+ */
497
+
498
+ /**
499
+ * Transaction database type
500
+ * Uses Record<string, unknown> to accept any schema shape
501
+ */
502
+ type TransactionDB = PostgresJsDatabase<Record<string, unknown>>;
503
+ /**
504
+ * Transaction context stored in AsyncLocalStorage
505
+ */
506
+ type TransactionContext = {
507
+ /** The actual Drizzle transaction object */
508
+ tx: TransactionDB;
509
+ /** Unique transaction ID for logging and tracing */
510
+ txId: string;
511
+ level: number;
512
+ };
513
+ /**
514
+ * Get current transaction from AsyncLocalStorage
515
+ *
516
+ * @returns Transaction if available, null otherwise
517
+ */
518
+ declare function getTransaction(): TransactionDB | null;
519
+ /**
520
+ * Run a function within a transaction context
521
+ *
522
+ * The transaction will be available to all async operations within the callback
523
+ * via getTransaction().
524
+ *
525
+ * @param tx - Drizzle transaction object
526
+ * @param txId - Unique ID for the transaction
527
+ * @param callback - Function to run within transaction context
528
+ * @returns Result of the callback
529
+ */
530
+ declare function runWithTransaction<T>(tx: TransactionDB, txId: string, // Add txId parameter
531
+ callback: () => Promise<T>): Promise<T>;
532
+
533
+ /**
534
+ * Transaction middleware options
535
+ */
536
+ interface TransactionalOptions {
537
+ /**
538
+ * Slow transaction warning threshold in milliseconds
539
+ * @default 1000 (1 second)
540
+ */
541
+ slowThreshold?: number;
542
+ /**
543
+ * Enable transaction logging
544
+ * @default true
545
+ */
546
+ enableLogging?: boolean;
547
+ /**
548
+ * Transaction timeout in milliseconds
549
+ *
550
+ * If transaction exceeds this duration, it will be aborted with TransactionError.
551
+ *
552
+ * @default 30000 (30 seconds) or TRANSACTION_TIMEOUT environment variable
553
+ *
554
+ * @example
555
+ * ```typescript
556
+ * // Default timeout (30s or TRANSACTION_TIMEOUT env var)
557
+ * Transactional()
558
+ *
559
+ * // Custom timeout for specific route (60s)
560
+ * Transactional({ timeout: 60000 })
561
+ *
562
+ * // Disable timeout
563
+ * Transactional({ timeout: 0 })
564
+ * ```
565
+ */
566
+ timeout?: number;
567
+ }
568
+ /**
569
+ * Transaction middleware for Hono routes
570
+ *
571
+ * Automatically wraps route handlers in a database transaction.
572
+ * Commits on success, rolls back on error.
573
+ *
574
+ * @example
575
+ * ```typescript
576
+ * // In your route file
577
+ * export const middlewares = [Transactional()];
578
+ *
579
+ * export async function POST(c: RouteContext) {
580
+ * // All DB operations run in a transaction
581
+ * const [user] = await db.insert(users).values(body).returning();
582
+ * await db.insert(profiles).values({ userId: user.id });
583
+ * // Auto-commits on success
584
+ * return c.json(user, 201);
585
+ * }
586
+ * ```
587
+ *
588
+ * @example
589
+ * ```typescript
590
+ * // With custom options
591
+ * export const middlewares = [
592
+ * Transactional({
593
+ * slowThreshold: 2000, // Warn if transaction takes > 2s
594
+ * enableLogging: false, // Disable logging
595
+ * timeout: 60000, // 60 second timeout for long operations
596
+ * })
597
+ * ];
598
+ * ```
599
+ *
600
+ * 🔄 Transaction behavior:
601
+ * - Success: Auto-commit
602
+ * - Error: Auto-rollback
603
+ * - Detects context.error to trigger rollback
604
+ *
605
+ * 📊 Transaction logging:
606
+ * - Auto-logs transaction start/commit/rollback
607
+ * - Measures and records execution time
608
+ * - Warns about slow transactions (default: > 1s)
609
+ */
610
+ declare function Transactional(options?: TransactionalOptions): hono.MiddlewareHandler<any, string, {}>;
611
+
612
+ /**
613
+ * PostgreSQL Error Conversion Utilities
614
+ *
615
+ * Converts PostgreSQL-specific error codes to custom error types
616
+ * @see https://www.postgresql.org/docs/current/errcodes-appendix.html
617
+ */
618
+
619
+ /**
620
+ * Convert PostgreSQL error to custom DatabaseError
621
+ *
622
+ * Maps PostgreSQL error codes to appropriate error classes with correct status codes
623
+ *
624
+ * @param error - PostgreSQL error object (from pg driver or Drizzle)
625
+ * @returns Custom DatabaseError instance
626
+ *
627
+ * @example
628
+ * ```typescript
629
+ * import { fromPostgresError } from '@spfn/core/db';
630
+ *
631
+ * try {
632
+ * await db.insert(users).values(data);
633
+ * } catch (pgError) {
634
+ * throw fromPostgresError(pgError);
635
+ * }
636
+ * ```
637
+ */
638
+ declare function fromPostgresError(error: any): DatabaseError;
639
+
640
+ /**
641
+ * Database Helper Functions
642
+ *
643
+ * Type-safe helper functions for common database operations.
644
+ * Automatically handles:
645
+ * - Transaction context detection
646
+ * - Read/Write database separation
647
+ * - Type inference from table schema
648
+ *
649
+ * @example
650
+ * ```typescript
651
+ * // Simple object-based where
652
+ * const user = await findOne(users, { id: 1 });
653
+ * const labels = await findMany(cmsLabels, { section: 'hero' });
654
+ *
655
+ * // Complex SQL-based where
656
+ * const user = await findOne(users, and(eq(users.id, 1), gt(users.age, 18)));
657
+ * const labels = await findMany(cmsLabels, {
658
+ * where: or(like(cmsLabels.key, 'hero.%'), eq(cmsLabels.section, 'footer')),
659
+ * limit: 10
660
+ * });
661
+ * ```
662
+ */
663
+
664
+ /**
665
+ * Infer SELECT model from PgTable
666
+ */
667
+ type InferSelectModel<T extends PgTable> = T['$inferSelect'];
668
+ /**
669
+ * Infer INSERT model from PgTable
670
+ */
671
+ type InferInsertModel<T extends PgTable> = T['$inferInsert'];
672
+ /**
673
+ * Object-based where condition (AND only, equality only)
674
+ */
675
+ type WhereObject<T> = {
676
+ [K in keyof T]?: T[K];
677
+ };
678
+ /**
679
+ * Find a single record
680
+ *
681
+ * @param table - Drizzle table schema
682
+ * @param where - Object or SQL condition
683
+ * @returns Single record or null
684
+ *
685
+ * @example
686
+ * ```typescript
687
+ * // Object-based
688
+ * const user = await findOne(users, { id: 1 });
689
+ * const label = await findOne(cmsLabels, { key: 'hero.title', section: 'hero' });
690
+ *
691
+ * // SQL-based
692
+ * const user = await findOne(users, and(eq(users.id, 1), gt(users.age, 18)));
693
+ * ```
694
+ */
695
+ declare function findOne<T extends PgTable>(table: T, where: WhereObject<InferSelectModel<T>>): Promise<InferSelectModel<T> | null>;
696
+ declare function findOne<T extends PgTable>(table: T, where: SQL | undefined): Promise<InferSelectModel<T> | null>;
697
+ /**
698
+ * Find multiple records
699
+ *
700
+ * @param table - Drizzle table schema
701
+ * @param options - Query options (where, orderBy, limit, offset)
702
+ * @returns Array of records
703
+ *
704
+ * @example
705
+ * ```typescript
706
+ * // Simple object where
707
+ * const labels = await findMany(cmsLabels, { section: 'hero' });
708
+ *
709
+ * // With options
710
+ * const labels = await findMany(cmsLabels, {
711
+ * where: { section: 'hero' },
712
+ * orderBy: desc(cmsLabels.updatedAt),
713
+ * limit: 10,
714
+ * offset: 0
715
+ * });
716
+ *
717
+ * // Complex SQL where
718
+ * const labels = await findMany(cmsLabels, {
719
+ * where: and(
720
+ * like(cmsLabels.key, 'hero.%'),
721
+ * eq(cmsLabels.section, 'hero')
722
+ * ),
723
+ * limit: 10
724
+ * });
725
+ * ```
726
+ */
727
+ declare function findMany<T extends PgTable>(table: T, options?: {
728
+ where?: WhereObject<InferSelectModel<T>> | SQL | undefined;
729
+ orderBy?: SQL | SQL[];
730
+ limit?: number;
731
+ offset?: number;
732
+ }): Promise<InferSelectModel<T>[]>;
733
+ /**
734
+ * Create a new record
735
+ *
736
+ * @param table - Drizzle table schema
737
+ * @param data - Insert data
738
+ * @returns Created record
739
+ *
740
+ * @example
741
+ * ```typescript
742
+ * const user = await create(users, {
743
+ * email: 'test@example.com',
744
+ * name: 'Test User'
745
+ * });
746
+ * ```
747
+ */
748
+ declare function create<T extends PgTable>(table: T, data: InferInsertModel<T>): Promise<InferSelectModel<T>>;
749
+ /**
750
+ * Create multiple records
751
+ *
752
+ * @param table - Drizzle table schema
753
+ * @param data - Array of insert data
754
+ * @returns Array of created records
755
+ *
756
+ * @example
757
+ * ```typescript
758
+ * const users = await createMany(users, [
759
+ * { email: 'user1@example.com', name: 'User 1' },
760
+ * { email: 'user2@example.com', name: 'User 2' }
761
+ * ]);
762
+ * ```
763
+ */
764
+ declare function createMany<T extends PgTable>(table: T, data: InferInsertModel<T>[]): Promise<InferSelectModel<T>[]>;
765
+ /**
766
+ * Upsert a record (INSERT or UPDATE on conflict)
767
+ *
768
+ * @param table - Drizzle table schema
769
+ * @param data - Insert data
770
+ * @param options - Conflict resolution options
771
+ * @returns Upserted record
772
+ *
773
+ * @example
774
+ * ```typescript
775
+ * // Basic upsert
776
+ * const cache = await upsert(cmsPublishedCache, {
777
+ * section: 'home',
778
+ * locale: 'ko',
779
+ * content: {...}
780
+ * }, {
781
+ * target: [cmsPublishedCache.section, cmsPublishedCache.locale],
782
+ * set: {
783
+ * content: data.content,
784
+ * updatedAt: new Date()
785
+ * }
786
+ * });
787
+ *
788
+ * // With SQL expression
789
+ * const cache = await upsert(cmsPublishedCache, data, {
790
+ * target: [cmsPublishedCache.section, cmsPublishedCache.locale],
791
+ * set: {
792
+ * content: data.content,
793
+ * version: sql`${cmsPublishedCache.version} + 1`
794
+ * }
795
+ * });
796
+ * ```
797
+ */
798
+ declare function upsert<T extends PgTable>(table: T, data: InferInsertModel<T>, options: {
799
+ target: PgColumn[];
800
+ set?: Partial<InferInsertModel<T>> | Record<string, SQL | any>;
801
+ }): Promise<InferSelectModel<T>>;
802
+ /**
803
+ * Update a single record
804
+ *
805
+ * @param table - Drizzle table schema
806
+ * @param where - Object or SQL condition
807
+ * @param data - Update data
808
+ * @returns Updated record or null
809
+ *
810
+ * @example
811
+ * ```typescript
812
+ * // Object-based where
813
+ * const user = await updateOne(users, { id: 1 }, { name: 'Updated Name' });
814
+ *
815
+ * // SQL-based where
816
+ * const user = await updateOne(users, eq(users.id, 1), { name: 'Updated Name' });
817
+ * ```
818
+ */
819
+ declare function updateOne<T extends PgTable>(table: T, where: WhereObject<InferSelectModel<T>> | SQL | undefined, data: Partial<InferInsertModel<T>>): Promise<InferSelectModel<T> | null>;
820
+ /**
821
+ * Update multiple records
822
+ *
823
+ * @param table - Drizzle table schema
824
+ * @param where - Object or SQL condition
825
+ * @param data - Update data
826
+ * @returns Array of updated records
827
+ *
828
+ * @example
829
+ * ```typescript
830
+ * const users = await updateMany(users,
831
+ * { role: 'user' },
832
+ * { verified: true }
833
+ * );
834
+ * ```
835
+ */
836
+ declare function updateMany<T extends PgTable>(table: T, where: WhereObject<InferSelectModel<T>> | SQL | undefined, data: Partial<InferInsertModel<T>>): Promise<InferSelectModel<T>[]>;
837
+ /**
838
+ * Delete a single record
839
+ *
840
+ * @param table - Drizzle table schema
841
+ * @param where - Object or SQL condition
842
+ * @returns Deleted record or null
843
+ *
844
+ * @example
845
+ * ```typescript
846
+ * // Object-based where
847
+ * const user = await deleteOne(users, { id: 1 });
848
+ *
849
+ * // SQL-based where
850
+ * const user = await deleteOne(users, eq(users.id, 1));
851
+ * ```
852
+ */
853
+ declare function deleteOne<T extends PgTable>(table: T, where: WhereObject<InferSelectModel<T>> | SQL | undefined): Promise<InferSelectModel<T> | null>;
854
+ /**
855
+ * Delete multiple records
856
+ *
857
+ * @param table - Drizzle table schema
858
+ * @param where - Object or SQL condition
859
+ * @returns Array of deleted records
860
+ *
861
+ * @example
862
+ * ```typescript
863
+ * const users = await deleteMany(users, { verified: false });
864
+ * ```
865
+ */
866
+ declare function deleteMany<T extends PgTable>(table: T, where: WhereObject<InferSelectModel<T>> | SQL | undefined): Promise<InferSelectModel<T>[]>;
867
+ /**
868
+ * Count records
869
+ *
870
+ * @param table - Drizzle table schema
871
+ * @param where - Optional object or SQL condition
872
+ * @returns Number of records
873
+ *
874
+ * @example
875
+ * ```typescript
876
+ * const total = await count(users);
877
+ * const activeUsers = await count(users, { active: true });
878
+ * const adults = await count(users, gt(users.age, 18));
879
+ * ```
880
+ */
881
+ declare function count<T extends PgTable>(table: T, where?: WhereObject<InferSelectModel<T>> | SQL | undefined): Promise<number>;
882
+
883
+ export { type DatabaseClients, type DrizzleConfigOptions, type PoolConfig, type RetryConfig, type TransactionContext, type TransactionDB, Transactional, type TransactionalOptions, checkConnection, closeDatabase, count, create, createDatabaseConnection, createDatabaseFromEnv, createFunctionSchema, createMany, deleteMany, deleteOne, detectDialect, findMany, findOne, foreignKey, fromPostgresError, generateDrizzleConfigFile, getDatabase, getDatabaseInfo, getDrizzleConfig, getSchemaInfo, getTransaction, id, initDatabase, optionalForeignKey, packageNameToSchema, runWithTransaction, setDatabase, timestamps, updateMany, updateOne, upsert };