@veloxts/orm 0.7.0 → 0.7.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.
- package/CHANGELOG.md +16 -0
- package/dist/client.js +3 -4
- package/dist/index.d.ts +4 -76
- package/dist/index.js +2 -42
- package/dist/plugin.js +5 -12
- package/dist/tenant/client-pool.d.ts +0 -4
- package/dist/tenant/index.js +1 -17
- package/dist/tenant/middleware.js +3 -2
- package/dist/tenant/schema/manager.js +19 -20
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @veloxts/orm
|
|
2
2
|
|
|
3
|
+
## 0.7.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- chore(auth,core,create,cli,client,orm,mcp,router,validation,web): simplify code for clarity and maintainability
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @veloxts/core@0.7.2
|
|
10
|
+
|
|
11
|
+
## 0.7.1
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- security audit, bumps dependency packages
|
|
16
|
+
- Updated dependencies
|
|
17
|
+
- @veloxts/core@0.7.1
|
|
18
|
+
|
|
3
19
|
## 0.7.0
|
|
4
20
|
|
|
5
21
|
### Minor Changes
|
package/dist/client.js
CHANGED
|
@@ -126,16 +126,15 @@ export function createDatabase(config) {
|
|
|
126
126
|
updateCachedStatus();
|
|
127
127
|
try {
|
|
128
128
|
await config.client.$disconnect();
|
|
129
|
-
state.connectionState = 'disconnected';
|
|
130
|
-
state.connectedAt = undefined;
|
|
131
|
-
updateCachedStatus();
|
|
132
129
|
}
|
|
133
130
|
catch (error) {
|
|
131
|
+
throw new VeloxError(`Failed to disconnect from database: ${error instanceof Error ? error.message : String(error)}`, 500, 'DATABASE_DISCONNECTION_ERROR');
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
134
|
// Even if disconnect fails, mark as disconnected
|
|
135
135
|
state.connectionState = 'disconnected';
|
|
136
136
|
state.connectedAt = undefined;
|
|
137
137
|
updateCachedStatus();
|
|
138
|
-
throw new VeloxError(`Failed to disconnect from database: ${error instanceof Error ? error.message : String(error)}`, 500, 'DATABASE_DISCONNECTION_ERROR');
|
|
139
138
|
}
|
|
140
139
|
}
|
|
141
140
|
// Return the database wrapper object with proper getters for reactive properties
|
package/dist/index.d.ts
CHANGED
|
@@ -34,80 +34,8 @@
|
|
|
34
34
|
*/
|
|
35
35
|
/** ORM package version */
|
|
36
36
|
export declare const ORM_VERSION: string;
|
|
37
|
-
export type {
|
|
38
|
-
/**
|
|
39
|
-
* Connection state enum values
|
|
40
|
-
*/
|
|
41
|
-
ConnectionState,
|
|
42
|
-
/**
|
|
43
|
-
* Connection status information
|
|
44
|
-
*/
|
|
45
|
-
ConnectionStatus,
|
|
46
|
-
/**
|
|
47
|
-
* Base interface for Prisma clients
|
|
48
|
-
*/
|
|
49
|
-
DatabaseClient,
|
|
50
|
-
/**
|
|
51
|
-
* Configuration for database wrapper
|
|
52
|
-
*/
|
|
53
|
-
DatabaseWrapperConfig,
|
|
54
|
-
/**
|
|
55
|
-
* Infer client type from config
|
|
56
|
-
*/
|
|
57
|
-
InferClientType,
|
|
58
|
-
/**
|
|
59
|
-
* Infer database client type
|
|
60
|
-
*/
|
|
61
|
-
InferDatabaseClient,
|
|
62
|
-
/**
|
|
63
|
-
* Plugin configuration options
|
|
64
|
-
*/
|
|
65
|
-
OrmPluginConfig, } from './types.js';
|
|
37
|
+
export type { ConnectionState, ConnectionStatus, DatabaseClient, DatabaseWrapperConfig, InferClientType, InferDatabaseClient, OrmPluginConfig, } from './types.js';
|
|
66
38
|
export { isDatabaseClient } from './types.js';
|
|
67
|
-
export type {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
*/
|
|
71
|
-
Database, } from './client.js';
|
|
72
|
-
export {
|
|
73
|
-
/**
|
|
74
|
-
* Create a database wrapper with connection lifecycle management
|
|
75
|
-
*
|
|
76
|
-
* Use this for manual connection management. For automatic lifecycle
|
|
77
|
-
* management with VeloxApp, use `databasePlugin` instead.
|
|
78
|
-
*
|
|
79
|
-
* @example
|
|
80
|
-
* ```typescript
|
|
81
|
-
* const db = createDatabase({ client: new PrismaClient() });
|
|
82
|
-
* await db.connect();
|
|
83
|
-
*
|
|
84
|
-
* const users = await db.client.user.findMany();
|
|
85
|
-
*
|
|
86
|
-
* await db.disconnect();
|
|
87
|
-
* ```
|
|
88
|
-
*/
|
|
89
|
-
createDatabase, } from './client.js';
|
|
90
|
-
export {
|
|
91
|
-
/**
|
|
92
|
-
* Create a database plugin for VeloxApp integration
|
|
93
|
-
*
|
|
94
|
-
* This is the recommended way to integrate Prisma with VeloxTS.
|
|
95
|
-
* The plugin automatically:
|
|
96
|
-
* - Connects to the database when the app starts
|
|
97
|
-
* - Disconnects during graceful shutdown
|
|
98
|
-
* - Adds `ctx.db` to procedure handlers
|
|
99
|
-
*
|
|
100
|
-
* @example
|
|
101
|
-
* ```typescript
|
|
102
|
-
* import { veloxApp } from '@veloxts/core';
|
|
103
|
-
* import { PrismaClient } from '@prisma/client';
|
|
104
|
-
* import { databasePlugin } from '@veloxts/orm';
|
|
105
|
-
*
|
|
106
|
-
* const prisma = new PrismaClient();
|
|
107
|
-
* const app = await veloxApp({ port: 3030 });
|
|
108
|
-
*
|
|
109
|
-
* await app.register(databasePlugin({ client: prisma }));
|
|
110
|
-
* await app.start();
|
|
111
|
-
* ```
|
|
112
|
-
*/
|
|
113
|
-
databasePlugin, } from './plugin.js';
|
|
39
|
+
export type { Database } from './client.js';
|
|
40
|
+
export { createDatabase } from './client.js';
|
|
41
|
+
export { databasePlugin } from './plugin.js';
|
package/dist/index.js
CHANGED
|
@@ -42,48 +42,8 @@ const packageJson = require('../package.json');
|
|
|
42
42
|
/** ORM package version */
|
|
43
43
|
export const ORM_VERSION = packageJson.version ?? '0.0.0-unknown';
|
|
44
44
|
export { isDatabaseClient } from './types.js';
|
|
45
|
-
export {
|
|
46
|
-
/**
|
|
47
|
-
* Create a database wrapper with connection lifecycle management
|
|
48
|
-
*
|
|
49
|
-
* Use this for manual connection management. For automatic lifecycle
|
|
50
|
-
* management with VeloxApp, use `databasePlugin` instead.
|
|
51
|
-
*
|
|
52
|
-
* @example
|
|
53
|
-
* ```typescript
|
|
54
|
-
* const db = createDatabase({ client: new PrismaClient() });
|
|
55
|
-
* await db.connect();
|
|
56
|
-
*
|
|
57
|
-
* const users = await db.client.user.findMany();
|
|
58
|
-
*
|
|
59
|
-
* await db.disconnect();
|
|
60
|
-
* ```
|
|
61
|
-
*/
|
|
62
|
-
createDatabase, } from './client.js';
|
|
45
|
+
export { createDatabase } from './client.js';
|
|
63
46
|
// ============================================================================
|
|
64
47
|
// Plugin
|
|
65
48
|
// ============================================================================
|
|
66
|
-
export {
|
|
67
|
-
/**
|
|
68
|
-
* Create a database plugin for VeloxApp integration
|
|
69
|
-
*
|
|
70
|
-
* This is the recommended way to integrate Prisma with VeloxTS.
|
|
71
|
-
* The plugin automatically:
|
|
72
|
-
* - Connects to the database when the app starts
|
|
73
|
-
* - Disconnects during graceful shutdown
|
|
74
|
-
* - Adds `ctx.db` to procedure handlers
|
|
75
|
-
*
|
|
76
|
-
* @example
|
|
77
|
-
* ```typescript
|
|
78
|
-
* import { veloxApp } from '@veloxts/core';
|
|
79
|
-
* import { PrismaClient } from '@prisma/client';
|
|
80
|
-
* import { databasePlugin } from '@veloxts/orm';
|
|
81
|
-
*
|
|
82
|
-
* const prisma = new PrismaClient();
|
|
83
|
-
* const app = await veloxApp({ port: 3030 });
|
|
84
|
-
*
|
|
85
|
-
* await app.register(databasePlugin({ client: prisma }));
|
|
86
|
-
* await app.start();
|
|
87
|
-
* ```
|
|
88
|
-
*/
|
|
89
|
-
databasePlugin, } from './plugin.js';
|
|
49
|
+
export { databasePlugin } from './plugin.js';
|
package/dist/plugin.js
CHANGED
|
@@ -131,18 +131,13 @@ export function databasePlugin(config) {
|
|
|
131
131
|
'Ensure you are passing a valid Prisma client instance.');
|
|
132
132
|
}
|
|
133
133
|
const pluginName = config.name ?? DEFAULT_PLUGIN_NAME;
|
|
134
|
-
|
|
135
|
-
const state = {
|
|
136
|
-
database: null,
|
|
137
|
-
};
|
|
134
|
+
let database = null;
|
|
138
135
|
return definePlugin({
|
|
139
136
|
name: pluginName,
|
|
140
137
|
version: ORM_PLUGIN_VERSION,
|
|
141
138
|
async register(server) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
// Connect to the database
|
|
145
|
-
await state.database.connect();
|
|
139
|
+
database = createDatabase({ client: config.client });
|
|
140
|
+
await database.connect();
|
|
146
141
|
// Add database client to request context via onRequest hook
|
|
147
142
|
server.addHook('onRequest', async (request) => {
|
|
148
143
|
// The context should be created by @veloxts/core's onRequest hook
|
|
@@ -158,12 +153,10 @@ export function databasePlugin(config) {
|
|
|
158
153
|
});
|
|
159
154
|
}
|
|
160
155
|
});
|
|
161
|
-
// Register shutdown hook using Fastify's onClose hook
|
|
162
|
-
// This ensures the database disconnects during graceful shutdown
|
|
163
156
|
server.addHook('onClose', async () => {
|
|
164
|
-
if (
|
|
157
|
+
if (database?.isConnected) {
|
|
165
158
|
try {
|
|
166
|
-
await
|
|
159
|
+
await database.disconnect();
|
|
167
160
|
server.log.info('Database disconnected successfully during shutdown');
|
|
168
161
|
}
|
|
169
162
|
catch (error) {
|
|
@@ -32,7 +32,3 @@ import type { TenantClientPool as ITenantClientPool, TenantClientPoolConfig } fr
|
|
|
32
32
|
* ```
|
|
33
33
|
*/
|
|
34
34
|
export declare function createTenantClientPool<TClient extends DatabaseClient>(config: TenantClientPoolConfig<TClient>): ITenantClientPool<TClient>;
|
|
35
|
-
/**
|
|
36
|
-
* Type alias for the client pool
|
|
37
|
-
*/
|
|
38
|
-
export type { ITenantClientPool as TenantClientPool };
|
package/dist/tenant/index.js
CHANGED
|
@@ -53,23 +53,7 @@
|
|
|
53
53
|
// ============================================================================
|
|
54
54
|
// Errors
|
|
55
55
|
// ============================================================================
|
|
56
|
-
export { ClientCreateError, ClientDisconnectError,
|
|
57
|
-
// Client pool errors
|
|
58
|
-
ClientPoolExhaustedError, DeprovisionError, getTenantStatusError,
|
|
59
|
-
// Validation errors
|
|
60
|
-
InvalidSlugError,
|
|
61
|
-
// Utilities
|
|
62
|
-
isTenantError,
|
|
63
|
-
// Provisioning errors
|
|
64
|
-
ProvisionError, SchemaAlreadyExistsError,
|
|
65
|
-
// Schema errors
|
|
66
|
-
SchemaCreateError, SchemaDeleteError, SchemaListError, SchemaMigrateError, SchemaNotFoundError,
|
|
67
|
-
// Authorization error
|
|
68
|
-
TenantAccessDeniedError,
|
|
69
|
-
// Base error
|
|
70
|
-
TenantError, TenantIdMissingError, TenantMigratingError,
|
|
71
|
-
// Tenant errors
|
|
72
|
-
TenantNotFoundError, TenantPendingError, TenantSuspendedError, } from './errors.js';
|
|
56
|
+
export { ClientCreateError, ClientDisconnectError, ClientPoolExhaustedError, DeprovisionError, getTenantStatusError, InvalidSlugError, isTenantError, ProvisionError, SchemaAlreadyExistsError, SchemaCreateError, SchemaDeleteError, SchemaListError, SchemaMigrateError, SchemaNotFoundError, TenantAccessDeniedError, TenantError, TenantIdMissingError, TenantMigratingError, TenantNotFoundError, TenantPendingError, TenantSuspendedError, } from './errors.js';
|
|
73
57
|
// ============================================================================
|
|
74
58
|
// Client Pool
|
|
75
59
|
// ============================================================================
|
|
@@ -64,13 +64,14 @@ export function createTenantMiddleware(config) {
|
|
|
64
64
|
}
|
|
65
65
|
// Get tenant-scoped database client
|
|
66
66
|
const db = await clientPool.getClient(tenant.schemaName);
|
|
67
|
-
// Build extended context
|
|
68
67
|
const extendedCtx = {
|
|
69
68
|
...ctx,
|
|
70
69
|
tenant,
|
|
71
70
|
db,
|
|
72
|
-
...(publicClient ? { publicDb: publicClient } : {}),
|
|
73
71
|
};
|
|
72
|
+
if (publicClient) {
|
|
73
|
+
extendedCtx.publicDb = publicClient;
|
|
74
|
+
}
|
|
74
75
|
try {
|
|
75
76
|
// Continue to next middleware/handler
|
|
76
77
|
return await next({ ctx: extendedCtx });
|
|
@@ -44,25 +44,34 @@ const RESERVED_SCHEMAS = new Set([
|
|
|
44
44
|
'pg_temp',
|
|
45
45
|
'information_schema',
|
|
46
46
|
]);
|
|
47
|
+
/**
|
|
48
|
+
* Patterns that indicate dangerous input (SQL injection, shell injection, path traversal)
|
|
49
|
+
*/
|
|
50
|
+
const DANGEROUS_PATTERNS = [
|
|
51
|
+
/[;|&$`<>]/, // Shell metacharacters
|
|
52
|
+
/['"`]/, // SQL quotes
|
|
53
|
+
/\0/, // Null bytes
|
|
54
|
+
/\.\./, // Path traversal
|
|
55
|
+
/[\\/]/, // Path separators
|
|
56
|
+
];
|
|
47
57
|
/**
|
|
48
58
|
* Validate database URL format and check for injection patterns
|
|
49
59
|
*/
|
|
50
60
|
function validateDatabaseUrl(url) {
|
|
61
|
+
let parsed;
|
|
51
62
|
try {
|
|
52
|
-
|
|
53
|
-
// Only allow postgresql:// protocol
|
|
54
|
-
if (parsed.protocol !== 'postgresql:' && parsed.protocol !== 'postgres:') {
|
|
55
|
-
throw new Error('Invalid database protocol');
|
|
56
|
-
}
|
|
57
|
-
// Check for shell metacharacters
|
|
58
|
-
const DANGEROUS_CHARS = /[;|&$`<>(){}[\]!]/;
|
|
59
|
-
if (DANGEROUS_CHARS.test(url)) {
|
|
60
|
-
throw new Error('Database URL contains dangerous characters');
|
|
61
|
-
}
|
|
63
|
+
parsed = new URL(url);
|
|
62
64
|
}
|
|
63
65
|
catch {
|
|
64
66
|
throw new Error('Invalid database URL format');
|
|
65
67
|
}
|
|
68
|
+
if (parsed.protocol !== 'postgresql:' && parsed.protocol !== 'postgres:') {
|
|
69
|
+
throw new Error('Invalid database protocol');
|
|
70
|
+
}
|
|
71
|
+
const DANGEROUS_CHARS = /[;|&$`<>(){}[\]!]/;
|
|
72
|
+
if (DANGEROUS_CHARS.test(url)) {
|
|
73
|
+
throw new Error('Database URL contains dangerous characters');
|
|
74
|
+
}
|
|
66
75
|
}
|
|
67
76
|
/**
|
|
68
77
|
* Validate Prisma schema path to prevent path traversal
|
|
@@ -168,14 +177,6 @@ export function createTenantSchemaManager(config) {
|
|
|
168
177
|
if (!VALID_SLUG_REGEX.test(slug)) {
|
|
169
178
|
throw new InvalidSlugError(slug, 'slug must contain only lowercase letters, numbers, and hyphens');
|
|
170
179
|
}
|
|
171
|
-
// Check for dangerous patterns
|
|
172
|
-
const DANGEROUS_PATTERNS = [
|
|
173
|
-
/[;|&$`<>]/, // Shell metacharacters
|
|
174
|
-
/['"`]/, // SQL quotes
|
|
175
|
-
/\0/, // Null bytes
|
|
176
|
-
/\.\./, // Path traversal
|
|
177
|
-
/[\\/]/, // Path separators
|
|
178
|
-
];
|
|
179
180
|
for (const pattern of DANGEROUS_PATTERNS) {
|
|
180
181
|
if (pattern.test(slug)) {
|
|
181
182
|
throw new InvalidSlugError(slug, 'slug contains forbidden characters');
|
|
@@ -205,8 +206,6 @@ export function createTenantSchemaManager(config) {
|
|
|
205
206
|
if (RESERVED_SCHEMAS.has(schemaName.toLowerCase())) {
|
|
206
207
|
throw new Error(`Cannot use reserved schema name: ${schemaName}`);
|
|
207
208
|
}
|
|
208
|
-
// Additional security checks
|
|
209
|
-
const DANGEROUS_PATTERNS = [/[;|&$`<>]/, /['"`]/, /\0/, /\.\./, /[\\/]/];
|
|
210
209
|
for (const pattern of DANGEROUS_PATTERNS) {
|
|
211
210
|
if (pattern.test(schemaName)) {
|
|
212
211
|
throw new Error(`Schema name contains forbidden characters: ${schemaName}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veloxts/orm",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "Prisma wrapper with enhanced DX for VeloxTS framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"fastify": "5.7.4",
|
|
20
20
|
"pg": "8.18.0",
|
|
21
21
|
"pg-format": "1.0.4",
|
|
22
|
-
"@veloxts/core": "0.7.
|
|
22
|
+
"@veloxts/core": "0.7.2"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/pg": "8.16.0",
|