@spfn/core 0.1.0-alpha.64 → 0.1.0-alpha.68

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 (37) hide show
  1. package/README.md +5 -5
  2. package/dist/{auto-loader-CdsxOceW.d.ts → auto-loader-JFaZ9gON.d.ts} +3 -2
  3. package/dist/cache/index.d.ts +211 -0
  4. package/dist/cache/index.js +992 -0
  5. package/dist/cache/index.js.map +1 -0
  6. package/dist/client/index.d.ts +2 -2
  7. package/dist/codegen/generators/index.d.ts +7 -6
  8. package/dist/codegen/generators/index.js +208 -27
  9. package/dist/codegen/generators/index.js.map +1 -1
  10. package/dist/codegen/index.d.ts +67 -118
  11. package/dist/codegen/index.js +1419 -1295
  12. package/dist/codegen/index.js.map +1 -1
  13. package/dist/database-errors-CoPrcOpq.d.ts +86 -0
  14. package/dist/db/index.d.ts +316 -9
  15. package/dist/db/index.js +6 -6
  16. package/dist/db/index.js.map +1 -1
  17. package/dist/error-handler-wjLL3v-a.d.ts +44 -0
  18. package/dist/errors/index.d.ts +119 -0
  19. package/dist/errors/index.js +160 -0
  20. package/dist/errors/index.js.map +1 -0
  21. package/dist/index-DHiAqhKv.d.ts +101 -0
  22. package/dist/index.d.ts +2 -228
  23. package/dist/index.js +274 -292
  24. package/dist/index.js.map +1 -1
  25. package/dist/middleware/index.d.ts +33 -0
  26. package/dist/middleware/index.js +890 -0
  27. package/dist/middleware/index.js.map +1 -0
  28. package/dist/route/index.d.ts +172 -7
  29. package/dist/route/index.js +209 -70
  30. package/dist/route/index.js.map +1 -1
  31. package/dist/server/index.js +267 -176
  32. package/dist/server/index.js.map +1 -1
  33. package/dist/{types-Bd8YsFSU.d.ts → types-CAON3Mmg.d.ts} +1 -1
  34. package/package.json +19 -2
  35. package/dist/bind-CSzshBtm.d.ts +0 -17
  36. package/dist/contract-generator-CqKsfsNE.d.ts +0 -52
  37. package/dist/postgres-errors-lw1aRUFe.d.ts +0 -397
@@ -54,4 +54,4 @@ type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
54
54
  type RouteHandler<TContract extends RouteContract = any> = (c: RouteContext<TContract>) => Response | Promise<Response>;
55
55
  declare function isHttpMethod(value: unknown): value is HttpMethod;
56
56
 
57
- export { type HeaderRecord as H, type InferContract as I, type RouteContract as R, type RouteHandler as a, type RouteMeta as b, type RouteContext as c, type HttpMethod as d, isHttpMethod as i };
57
+ export { type HttpMethod as H, type InferContract as I, type RouteContext as R, type RouteContract as a, type RouteHandler as b, type HeaderRecord as c, type RouteMeta as d, isHttpMethod as i };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spfn/core",
3
- "version": "0.1.0-alpha.64",
3
+ "version": "0.1.0-alpha.68",
4
4
  "description": "SPFN Framework Core - File-based routing, transactions, repository pattern",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -31,6 +31,21 @@
31
31
  "import": "./dist/server/index.js",
32
32
  "require": "./dist/server/index.js"
33
33
  },
34
+ "./errors": {
35
+ "types": "./dist/errors/index.d.ts",
36
+ "import": "./dist/errors/index.js",
37
+ "require": "./dist/errors/index.js"
38
+ },
39
+ "./middleware": {
40
+ "types": "./dist/middleware/index.d.ts",
41
+ "import": "./dist/middleware/index.js",
42
+ "require": "./dist/middleware/index.js"
43
+ },
44
+ "./cache": {
45
+ "types": "./dist/cache/index.d.ts",
46
+ "import": "./dist/cache/index.js",
47
+ "require": "./dist/cache/index.js"
48
+ },
34
49
  "./codegen": {
35
50
  "types": "./dist/codegen/index.d.ts",
36
51
  "import": "./dist/codegen/index.js",
@@ -117,9 +132,10 @@
117
132
  "devDependencies": {
118
133
  "@types/micromatch": "^4.0.9",
119
134
  "@types/node": "^20.11.0",
135
+ "@vitest/coverage-v8": "^4.0.6",
120
136
  "drizzle-kit": "^0.31.5",
121
137
  "tsup": "^8.0.0",
122
- "vitest": "^3.2.4"
138
+ "vitest": "^4.0.6"
123
139
  },
124
140
  "files": [
125
141
  "dist",
@@ -137,6 +153,7 @@
137
153
  "test": "vitest",
138
154
  "test:unit": "vitest --config vitest.unit.config.ts",
139
155
  "test:integration": "vitest --config vitest.integration.config.ts",
156
+ "test:coverage": "vitest run --config vitest.unit.config.ts --coverage",
140
157
  "test:logger": "vitest src/logger",
141
158
  "test:errors": "vitest src/errors",
142
159
  "test:codegen": "vitest src/codegen",
@@ -1,17 +0,0 @@
1
- import { Context } from 'hono';
2
- import { R as RouteContract, c as RouteContext } from './types-Bd8YsFSU.js';
3
-
4
- /**
5
- * Contract-based Route Handler Wrapper
6
- *
7
- * Binds a contract to a route handler, providing automatic validation
8
- * and type-safe context creation.
9
- *
10
- * Features:
11
- * - Automatic params/query/body validation using TypeBox
12
- * - Type-safe RouteContext with contract-based inference
13
- * - Clean separation: bind() for validation, Hono for middleware
14
- */
15
- declare function bind<TContract extends RouteContract>(contract: TContract, handler: (c: RouteContext<TContract>) => Response | Promise<Response>): (rawContext: Context) => Promise<Response>;
16
-
17
- export { bind as b };
@@ -1,52 +0,0 @@
1
- /**
2
- * Generator Interface
3
- *
4
- * Defines the contract for code generators that can be orchestrated by the codegen system.
5
- */
6
- interface GeneratorOptions {
7
- /** Project root directory */
8
- cwd: string;
9
- /** Enable debug logging */
10
- debug?: boolean;
11
- /** Custom configuration options */
12
- [key: string]: any;
13
- }
14
- interface Generator {
15
- /** Unique generator name */
16
- name: string;
17
- /** File patterns to watch (glob patterns) */
18
- watchPatterns: string[];
19
- /**
20
- * Generate code once
21
- *
22
- * @param options - Generator options
23
- */
24
- generate(options: GeneratorOptions): Promise<void>;
25
- /**
26
- * Handle individual file changes (optional)
27
- *
28
- * If not provided, the orchestrator will call generate() on any file change.
29
- *
30
- * @param filePath - Changed file path (relative to cwd)
31
- * @param event - Type of file event
32
- */
33
- onFileChange?(filePath: string, event: 'add' | 'change' | 'unlink'): Promise<void>;
34
- }
35
-
36
- /**
37
- * Contract Generator
38
- *
39
- * Generates type-safe API client from contract definitions
40
- */
41
-
42
- interface ContractGeneratorConfig {
43
- /** Routes directory (default: src/server/routes) */
44
- routesDir?: string;
45
- /** Output path (default: src/lib/api.ts) */
46
- outputPath?: string;
47
- /** Base URL for API client */
48
- baseUrl?: string;
49
- }
50
- declare function createContractGenerator(config?: ContractGeneratorConfig): Generator;
51
-
52
- export { type ContractGeneratorConfig as C, type Generator as G, type GeneratorOptions as a, createContractGenerator as c };
@@ -1,397 +0,0 @@
1
- import * as drizzle_orm from 'drizzle-orm';
2
- import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
3
- import { PgColumn } from 'drizzle-orm/pg-core';
4
- import { PostgresJsDatabase } from 'drizzle-orm/postgres-js';
5
- import * as hono from 'hono';
6
-
7
- /**
8
- * Drizzle Kit configuration generator
9
- * Automatically generates drizzle.config.ts from environment variables
10
- */
11
- interface DrizzleConfigOptions {
12
- /** Database connection URL (defaults to process.env.DATABASE_URL) */
13
- databaseUrl?: string;
14
- /** Schema files glob pattern or array of patterns (defaults to './src/server/entities/\*\*\/*.ts') */
15
- schema?: string | string[];
16
- /** Migration output directory (defaults to './src/server/drizzle') */
17
- out?: string;
18
- /** Database dialect (auto-detected from URL if not provided) */
19
- dialect?: 'postgresql' | 'mysql' | 'sqlite';
20
- /** Current working directory for discovering package schemas */
21
- cwd?: string;
22
- /** Disable automatic package schema discovery */
23
- disablePackageDiscovery?: boolean;
24
- /** Only include schemas from specific package (e.g., '@spfn/cms') */
25
- packageFilter?: string;
26
- }
27
- /**
28
- * Detect database dialect from connection URL
29
- */
30
- declare function detectDialect(url: string): 'postgresql' | 'mysql' | 'sqlite';
31
- /**
32
- * Generate Drizzle Kit configuration
33
- *
34
- * @param options - Configuration options
35
- * @returns Drizzle Kit configuration object
36
- *
37
- * @example
38
- * ```ts
39
- * // Zero-config (reads from process.env.DATABASE_URL)
40
- * const config = getDrizzleConfig();
41
- *
42
- * // Custom config
43
- * const config = getDrizzleConfig({
44
- * databaseUrl: 'postgresql://localhost/mydb',
45
- * schema: './src/db/schema/*.ts',
46
- * out: './migrations',
47
- * });
48
- * ```
49
- */
50
- declare function getDrizzleConfig(options?: DrizzleConfigOptions): {
51
- schema: string | string[];
52
- out: string;
53
- dialect: "postgresql" | "mysql" | "sqlite";
54
- dbCredentials: {
55
- url: string;
56
- };
57
- };
58
- /**
59
- * Generate drizzle.config.ts file content
60
- *
61
- * @param options - Configuration options
62
- * @returns File content as string
63
- */
64
- declare function generateDrizzleConfigFile(options?: DrizzleConfigOptions): string;
65
-
66
- /**
67
- * Standard auto-incrementing primary key
68
- *
69
- * @returns bigserial primary key column
70
- *
71
- * @example
72
- * ```typescript
73
- * export const users = pgTable('users', {
74
- * id: id(),
75
- * // ...
76
- * });
77
- * ```
78
- */
79
- declare function id(): drizzle_orm.IsPrimaryKey<drizzle_orm.NotNull<drizzle_orm_pg_core.PgBigSerial53BuilderInitial<"id">>>;
80
- /**
81
- * Standard timestamp fields (createdAt, updatedAt)
82
- *
83
- * Both fields are timezone-aware, auto-set to current time on creation.
84
- * When autoUpdate is enabled, updatedAt will be automatically updated on record updates.
85
- *
86
- * @param options - Optional configuration
87
- * @param options.autoUpdate - Automatically update updatedAt on record updates (default: false)
88
- * @returns Object with createdAt and updatedAt columns
89
- *
90
- * @example
91
- * ```typescript
92
- * // Without auto-update
93
- * export const users = pgTable('users', {
94
- * id: id(),
95
- * email: text('email'),
96
- * ...timestamps(),
97
- * });
98
- *
99
- * // With auto-update
100
- * export const posts = pgTable('posts', {
101
- * id: id(),
102
- * title: text('title'),
103
- * ...timestamps({ autoUpdate: true }),
104
- * });
105
- * ```
106
- */
107
- declare function timestamps(options?: {
108
- autoUpdate?: boolean;
109
- }): {
110
- createdAt: drizzle_orm.NotNull<drizzle_orm.HasDefault<drizzle_orm_pg_core.PgTimestampBuilderInitial<"created_at">>>;
111
- updatedAt: drizzle_orm.NotNull<drizzle_orm.HasDefault<drizzle_orm_pg_core.PgTimestampBuilderInitial<"updated_at">>>;
112
- };
113
- /**
114
- * Foreign key reference to another table
115
- *
116
- * Creates a bigserial column with cascade delete.
117
- * Type-safe: ensures the reference points to a valid PostgreSQL column.
118
- *
119
- * @param name - Column name (e.g., 'author' creates 'author_id')
120
- * @param reference - Reference to parent table column
121
- * @param options - Optional foreign key options
122
- *
123
- * @example
124
- * ```typescript
125
- * import { users } from './users';
126
- *
127
- * export const posts = pgTable('posts', {
128
- * id: id(),
129
- * authorId: foreignKey('author', () => users.id),
130
- * ...timestamps(),
131
- * });
132
- * ```
133
- */
134
- declare function foreignKey<T extends PgColumn>(name: string, reference: () => T, options?: {
135
- onDelete?: 'cascade' | 'set null' | 'restrict' | 'no action';
136
- }): drizzle_orm.NotNull<drizzle_orm_pg_core.PgBigSerial53BuilderInitial<`${string}_id`>>;
137
- /**
138
- * Optional foreign key reference (nullable)
139
- *
140
- * Type-safe: ensures the reference points to a valid PostgreSQL column.
141
- *
142
- * @param name - Column name (e.g., 'author' creates 'author_id')
143
- * @param reference - Reference to parent table column
144
- * @param options - Optional foreign key options
145
- *
146
- * @example
147
- * ```typescript
148
- * export const posts = pgTable('posts', {
149
- * id: id(),
150
- * authorId: optionalForeignKey('author', () => users.id),
151
- * });
152
- * ```
153
- */
154
- declare function optionalForeignKey<T extends PgColumn>(name: string, reference: () => T, options?: {
155
- onDelete?: 'cascade' | 'set null' | 'restrict' | 'no action';
156
- }): drizzle_orm_pg_core.PgBigSerial53BuilderInitial<`${string}_id`>;
157
-
158
- /**
159
- * AsyncLocalStorage-based Transaction Context
160
- *
161
- * Uses Node.js AsyncLocalStorage to propagate transactions throughout the async call chain.
162
- *
163
- * Features:
164
- * - AsyncLocalStorage-based context management
165
- * - Type-safe transaction propagation across async chains
166
- * - Transaction ID tracking for debugging and tracing
167
- * - Nested transaction detection and logging
168
- * - Transaction nesting level tracking
169
- */
170
-
171
- /**
172
- * Transaction database type
173
- * Record<string, never> represents an empty schema; actual schema is determined at runtime
174
- */
175
- type TransactionDB = PostgresJsDatabase;
176
- /**
177
- * Transaction context stored in AsyncLocalStorage
178
- */
179
- type TransactionContext = {
180
- /** The actual Drizzle transaction object */
181
- tx: TransactionDB;
182
- /** Unique transaction ID for logging and tracing */
183
- txId: string;
184
- level: number;
185
- };
186
- /**
187
- * Get current transaction from AsyncLocalStorage
188
- *
189
- * @returns Transaction if available, null otherwise
190
- */
191
- declare function getTransaction(): TransactionDB | null;
192
- /**
193
- * Run a function within a transaction context
194
- *
195
- * The transaction will be available to all async operations within the callback
196
- * via getTransaction().
197
- *
198
- * @param tx - Drizzle transaction object
199
- * @param txId - Unique ID for the transaction
200
- * @param callback - Function to run within transaction context
201
- * @returns Result of the callback
202
- */
203
- declare function runWithTransaction<T>(tx: TransactionDB, txId: string, // Add txId parameter
204
- callback: () => Promise<T>): Promise<T>;
205
-
206
- /**
207
- * Transaction middleware options
208
- */
209
- interface TransactionalOptions {
210
- /**
211
- * Slow transaction warning threshold in milliseconds
212
- * @default 1000 (1 second)
213
- */
214
- slowThreshold?: number;
215
- /**
216
- * Enable transaction logging
217
- * @default true
218
- */
219
- enableLogging?: boolean;
220
- /**
221
- * Transaction timeout in milliseconds
222
- *
223
- * If transaction exceeds this duration, it will be aborted with TransactionError.
224
- *
225
- * @default 30000 (30 seconds) or TRANSACTION_TIMEOUT environment variable
226
- *
227
- * @example
228
- * ```typescript
229
- * // Default timeout (30s or TRANSACTION_TIMEOUT env var)
230
- * Transactional()
231
- *
232
- * // Custom timeout for specific route (60s)
233
- * Transactional({ timeout: 60000 })
234
- *
235
- * // Disable timeout
236
- * Transactional({ timeout: 0 })
237
- * ```
238
- */
239
- timeout?: number;
240
- }
241
- /**
242
- * Transaction middleware for Hono routes
243
- *
244
- * Automatically wraps route handlers in a database transaction.
245
- * Commits on success, rolls back on error.
246
- *
247
- * @example
248
- * ```typescript
249
- * // In your route file
250
- * export const middlewares = [Transactional()];
251
- *
252
- * export async function POST(c: RouteContext) {
253
- * // All DB operations run in a transaction
254
- * const [user] = await db.insert(users).values(body).returning();
255
- * await db.insert(profiles).values({ userId: user.id });
256
- * // Auto-commits on success
257
- * return c.json(user, 201);
258
- * }
259
- * ```
260
- *
261
- * @example
262
- * ```typescript
263
- * // With custom options
264
- * export const middlewares = [
265
- * Transactional({
266
- * slowThreshold: 2000, // Warn if transaction takes > 2s
267
- * enableLogging: false, // Disable logging
268
- * timeout: 60000, // 60 second timeout for long operations
269
- * })
270
- * ];
271
- * ```
272
- *
273
- * 🔄 Transaction behavior:
274
- * - Success: Auto-commit
275
- * - Error: Auto-rollback
276
- * - Detects context.error to trigger rollback
277
- *
278
- * 📊 Transaction logging:
279
- * - Auto-logs transaction start/commit/rollback
280
- * - Measures and records execution time
281
- * - Warns about slow transactions (default: > 1s)
282
- */
283
- declare function Transactional(options?: TransactionalOptions): hono.MiddlewareHandler<any, string, {}>;
284
-
285
- /**
286
- * Database Error Classes
287
- *
288
- * Type-safe error handling with custom error class hierarchy
289
- * Mapped to HTTP status codes for API responses
290
- */
291
- /**
292
- * Base Database Error
293
- *
294
- * Base class for all database-related errors
295
- */
296
- declare class DatabaseError<TDetails extends Record<string, unknown> = Record<string, unknown>> extends Error {
297
- readonly statusCode: number;
298
- readonly details?: TDetails;
299
- readonly timestamp: Date;
300
- constructor(message: string, statusCode?: number, details?: TDetails);
301
- /**
302
- * Serialize error for API response
303
- */
304
- toJSON(): {
305
- name: string;
306
- message: string;
307
- statusCode: number;
308
- details: TDetails | undefined;
309
- timestamp: string;
310
- };
311
- }
312
- /**
313
- * Connection Error (503 Service Unavailable)
314
- *
315
- * Database connection failure, connection pool exhaustion, etc.
316
- */
317
- declare class ConnectionError extends DatabaseError {
318
- constructor(message: string, details?: Record<string, any>);
319
- }
320
- /**
321
- * Query Error (500 Internal Server Error)
322
- *
323
- * SQL query execution failure, syntax errors, etc.
324
- */
325
- declare class QueryError extends DatabaseError {
326
- constructor(message: string, statusCode?: number, details?: Record<string, any>);
327
- }
328
- /**
329
- * Not Found Error (404 Not Found)
330
- *
331
- * Requested resource does not exist
332
- */
333
- declare class NotFoundError extends QueryError {
334
- constructor(resource: string, id: string | number);
335
- }
336
- /**
337
- * Validation Error (400 Bad Request)
338
- *
339
- * Input data validation failure
340
- */
341
- declare class ValidationError extends QueryError {
342
- constructor(message: string, details?: Record<string, any>);
343
- }
344
- /**
345
- * Transaction Error (500 Internal Server Error)
346
- *
347
- * Transaction start/commit/rollback failure
348
- */
349
- declare class TransactionError extends DatabaseError {
350
- constructor(message: string, statusCode?: number, details?: Record<string, any>);
351
- }
352
- /**
353
- * Deadlock Error (409 Conflict)
354
- *
355
- * Database deadlock detected
356
- */
357
- declare class DeadlockError extends TransactionError {
358
- constructor(message: string, details?: Record<string, any>);
359
- }
360
- /**
361
- * Duplicate Entry Error (409 Conflict)
362
- *
363
- * Unique constraint violation (e.g., duplicate email)
364
- */
365
- declare class DuplicateEntryError extends QueryError {
366
- constructor(field: string, value: string | number);
367
- }
368
-
369
- /**
370
- * PostgreSQL Error Conversion Utilities
371
- *
372
- * Converts PostgreSQL-specific error codes to custom error types
373
- * @see https://www.postgresql.org/docs/current/errcodes-appendix.html
374
- */
375
-
376
- /**
377
- * Convert PostgreSQL error to custom DatabaseError
378
- *
379
- * Maps PostgreSQL error codes to appropriate error classes with correct status codes
380
- *
381
- * @param error - PostgreSQL error object (from pg driver or Drizzle)
382
- * @returns Custom DatabaseError instance
383
- *
384
- * @example
385
- * ```typescript
386
- * import { fromPostgresError } from '@spfn/core/db';
387
- *
388
- * try {
389
- * await db.insert(users).values(data);
390
- * } catch (pgError) {
391
- * throw fromPostgresError(pgError);
392
- * }
393
- * ```
394
- */
395
- declare function fromPostgresError(error: any): DatabaseError;
396
-
397
- export { ConnectionError as C, DatabaseError as D, NotFoundError as N, QueryError as Q, Transactional as T, ValidationError as V, generateDrizzleConfigFile as a, fromPostgresError as b, type DrizzleConfigOptions as c, detectDialect as d, getTransaction as e, foreignKey as f, getDrizzleConfig as g, type TransactionContext as h, id as i, type TransactionalOptions as j, TransactionError as k, DeadlockError as l, DuplicateEntryError as m, type TransactionDB as n, optionalForeignKey as o, runWithTransaction as r, timestamps as t };