Skip to content

Commit bc0f249

Browse files
authored
Merge pull request #582 from objectstack-ai/copilot/implement-objectql-database-objects
2 parents 78e6b06 + d746197 commit bc0f249

12 files changed

Lines changed: 695 additions & 38 deletions

packages/plugins/plugin-auth/README.md

Lines changed: 77 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Authentication & Identity Plugin for ObjectStack.
44

5-
> **✨ Status:** Better-Auth library successfully integrated! Core authentication structure is in place with better-auth v1.4.18. Full API integration and advanced features are in active development.
5+
> **✨ Status:** ObjectQL-based authentication implementation! Uses ObjectQL for data persistence (no third-party ORM required). Core authentication structure is in place with better-auth v1.4.18.
66
77
## Features
88

@@ -12,6 +12,7 @@ Authentication & Identity Plugin for ObjectStack.
1212
- ✅ Service registration in ObjectKernel
1313
- ✅ Configuration schema support
1414
-**Better-Auth library integration (v1.4.18)**
15+
-**ObjectQL-based database implementation (no ORM required)**
1516
-**Direct request forwarding to better-auth handler**
1617
-**Wildcard routing (`/api/v1/auth/*`)**
1718
-**Full better-auth API access via `auth.api`**
@@ -28,10 +29,18 @@ Authentication & Identity Plugin for ObjectStack.
2829
-**Magic Links** - Passwordless authentication (when enabled)
2930
-**Organizations** - Multi-tenant support (when enabled)
3031

31-
### In Active Development
32-
- 🔄 **Database Adapter** - Drizzle ORM integration for data persistence
32+
### ObjectQL-Based Database Architecture
33+
-**Native ObjectQL Data Persistence** - Uses ObjectQL's IDataEngine interface
34+
-**No Third-Party ORM** - No dependency on drizzle-orm or other ORMs
35+
-**Better-Auth Native Schema** - Uses better-auth's naming conventions for seamless migration
36+
-**Object Definitions** - Auth objects defined using ObjectStack's Object Protocol
37+
- `user` - User accounts (better-auth native table name)
38+
- `session` - Active sessions (better-auth native table name)
39+
- `account` - OAuth provider accounts (better-auth native table name)
40+
- `verification` - Email/phone verification tokens (better-auth native table name)
41+
-**ObjectQL Adapter** - Custom adapter bridges better-auth to ObjectQL
3342

34-
The plugin uses [better-auth](https://www.better-auth.com/) for robust, production-ready authentication functionality. All requests are forwarded directly to better-auth's universal handler, ensuring full compatibility with all better-auth features.
43+
The plugin uses [better-auth](https://www.better-auth.com/) for robust, production-ready authentication functionality. All requests are forwarded directly to better-auth's universal handler, ensuring full compatibility with all better-auth features. Data persistence is handled by ObjectQL using **better-auth's native naming conventions** (camelCase) to ensure seamless migration for existing better-auth users.
3544

3645
## Installation
3746

@@ -41,18 +50,22 @@ pnpm add @objectstack/plugin-auth
4150

4251
## Usage
4352

44-
### Basic Setup
53+
### Basic Setup with ObjectQL
4554

4655
```typescript
4756
import { ObjectKernel } from '@objectstack/core';
4857
import { AuthPlugin } from '@objectstack/plugin-auth';
58+
import { ObjectQL } from '@objectstack/objectql';
59+
60+
// Initialize ObjectQL as the data engine
61+
const dataEngine = new ObjectQL();
4962

5063
const kernel = new ObjectKernel({
5164
plugins: [
5265
new AuthPlugin({
5366
secret: process.env.AUTH_SECRET,
5467
baseUrl: 'http://localhost:3000',
55-
databaseUrl: process.env.DATABASE_URL,
68+
// ObjectQL will be automatically injected by the kernel
5669
providers: [
5770
{
5871
id: 'google',
@@ -65,13 +78,14 @@ const kernel = new ObjectKernel({
6578
});
6679
```
6780

81+
**Note:** The `databaseUrl` parameter is no longer used. The plugin now uses ObjectQL's IDataEngine interface, which is provided by the kernel's `data` service. This allows the plugin to work with any ObjectQL-compatible driver (memory, SQL, NoSQL, etc.) without requiring a specific ORM.
82+
6883
### With Organization Support
6984

7085
```typescript
7186
new AuthPlugin({
7287
secret: process.env.AUTH_SECRET,
7388
baseUrl: 'http://localhost:3000',
74-
databaseUrl: process.env.DATABASE_URL,
7589
plugins: {
7690
organization: true, // Enable organization/teams
7791
twoFactor: true, // Enable 2FA
@@ -142,10 +156,12 @@ This package provides authentication services powered by better-auth. Current im
142156
7. ✅ Full better-auth API support
143157
8. ✅ OAuth providers (configurable)
144158
9. ✅ 2FA, passkeys, magic links (configurable)
145-
10. 🔄 Database adapter integration (in progress)
159+
10. ✅ ObjectQL-based database implementation (no ORM required)
146160

147161
### Architecture
148162

163+
#### Request Flow
164+
149165
The plugin uses a **direct forwarding** approach:
150166

151167
```typescript
@@ -164,6 +180,59 @@ This architecture provides:
164180
-**Type safety** - Full TypeScript support from better-auth
165181
-**Programmatic API** - Access auth methods via `authManager.api`
166182

183+
#### ObjectQL Database Architecture
184+
185+
The plugin uses **ObjectQL** for data persistence instead of third-party ORMs:
186+
187+
```typescript
188+
// Object definitions use better-auth's native naming conventions
189+
export const AuthUser = ObjectSchema.create({
190+
name: 'user', // better-auth native table name
191+
fields: {
192+
id: Field.text({ label: 'User ID', required: true }),
193+
email: Field.email({ label: 'Email', required: true }),
194+
emailVerified: Field.boolean({ label: 'Email Verified' }), // camelCase
195+
name: Field.text({ label: 'Name', required: true }),
196+
createdAt: Field.datetime({ label: 'Created At' }), // camelCase
197+
updatedAt: Field.datetime({ label: 'Updated At' }), // camelCase
198+
// ... other fields
199+
},
200+
indexes: [
201+
{ fields: ['email'], unique: true }
202+
]
203+
});
204+
```
205+
206+
**Benefits:**
207+
-**No ORM Dependencies** - No drizzle-orm, Prisma, or other ORMs required
208+
-**Unified Data Layer** - Uses same data engine as rest of ObjectStack
209+
-**Driver Agnostic** - Works with memory, SQL, NoSQL via ObjectQL drivers
210+
-**Type-Safe** - Zod-based schemas provide runtime + compile-time safety
211+
-**"Data as Code"** - Object definitions are versioned, declarative code
212+
-**Metadata Driven** - Supports migrations, validation, indexing via metadata
213+
-**Seamless Migration** - Uses better-auth's native naming (camelCase) for easy migration
214+
215+
**Database Objects:**
216+
Uses better-auth's native table and field names for compatibility:
217+
- `user` - User accounts (id, email, name, emailVerified, createdAt, etc.)
218+
- `session` - Active sessions (id, token, userId, expiresAt, ipAddress, etc.)
219+
- `account` - OAuth provider accounts (id, providerId, accountId, userId, tokens, etc.)
220+
- `verification` - Verification tokens (id, value, identifier, expiresAt, etc.)
221+
222+
**Adapter:**
223+
The `createObjectQLAdapter()` function bridges better-auth's database interface to ObjectQL's IDataEngine using better-auth's native naming conventions:
224+
225+
```typescript
226+
// Better-auth → ObjectQL Adapter (no name conversion needed)
227+
const adapter = createObjectQLAdapter(dataEngine);
228+
229+
// Better-auth uses this adapter for all database operations
230+
const auth = betterAuth({
231+
database: adapter,
232+
// ... other config
233+
});
234+
```
235+
167236
## Development
168237

169238
```bash

packages/plugins/plugin-auth/package.json

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,5 @@
1818
"@types/node": "^25.2.2",
1919
"typescript": "^5.0.0",
2020
"vitest": "^4.0.18"
21-
},
22-
"peerDependencies": {
23-
"drizzle-orm": "^0.41.0"
24-
},
25-
"peerDependenciesMeta": {
26-
"drizzle-orm": {
27-
"optional": true
28-
}
2921
}
3022
}

packages/plugins/plugin-auth/src/auth-manager.ts

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import { betterAuth } from 'better-auth';
44
import type { Auth, BetterAuthOptions } from 'better-auth';
55
import type { AuthConfig } from '@objectstack/spec/system';
6+
import type { IDataEngine } from '@objectstack/core';
7+
import { createObjectQLAdapter } from './objectql-adapter.js';
68

79
/**
810
* Extended options for AuthManager
@@ -13,6 +15,12 @@ export interface AuthManagerOptions extends Partial<AuthConfig> {
1315
* If not provided, one will be created from config
1416
*/
1517
authInstance?: Auth<any>;
18+
19+
/**
20+
* ObjectQL Data Engine instance
21+
* Required for database operations using ObjectQL instead of third-party ORMs
22+
*/
23+
dataEngine?: IDataEngine;
1624
}
1725

1826
/**
@@ -82,25 +90,24 @@ export class AuthManager {
8290
}
8391

8492
/**
85-
* Create database configuration
86-
* TODO: Implement proper database adapter when drizzle-orm is available
93+
* Create database configuration using ObjectQL adapter
8794
*/
8895
private createDatabaseConfig(): any {
89-
// If databaseUrl is provided, we would use drizzle adapter
90-
// For now, this is a placeholder configuration
91-
if (this.config.databaseUrl) {
92-
console.warn(
93-
'Database URL provided but adapter integration not yet complete. ' +
94-
'Install drizzle-orm and configure a proper adapter for production use.'
95-
);
96+
// Use ObjectQL adapter if dataEngine is provided
97+
if (this.config.dataEngine) {
98+
return createObjectQLAdapter(this.config.dataEngine);
9699
}
97100

98-
// Return a minimal configuration that better-auth can work with
99-
// This will need to be replaced with a proper adapter
100-
return {
101-
// Placeholder - will be replaced with actual adapter
102-
adapter: 'in-memory' as any,
103-
};
101+
// Fallback warning if no dataEngine is provided
102+
console.warn(
103+
'⚠️ WARNING: No dataEngine provided to AuthManager! ' +
104+
'Using in-memory storage. This is NOT suitable for production. ' +
105+
'Please provide a dataEngine instance (e.g., ObjectQL) in AuthManagerOptions.'
106+
);
107+
108+
// Return a minimal in-memory configuration as fallback
109+
// This allows the system to work in development/testing without a real database
110+
return undefined; // better-auth will use its default in-memory adapter
104111
}
105112

106113
/**

packages/plugins/plugin-auth/src/auth-plugin.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,17 @@ export class AuthPlugin implements Plugin {
6767
throw new Error('AuthPlugin: secret is required');
6868
}
6969

70-
// Initialize auth manager
71-
this.authManager = new AuthManager(this.options);
70+
// Get data engine service for database operations
71+
const dataEngine = ctx.getService<any>('data');
72+
if (!dataEngine) {
73+
ctx.logger.warn('No data engine service found - auth will use in-memory storage');
74+
}
75+
76+
// Initialize auth manager with data engine
77+
this.authManager = new AuthManager({
78+
...this.options,
79+
dataEngine,
80+
});
7281

7382
// Register auth service
7483
ctx.registerService('auth', this.authManager);

packages/plugins/plugin-auth/src/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
*
66
* Authentication & Identity Plugin for ObjectStack
77
* Powered by better-auth for robust, secure authentication
8+
* Uses ObjectQL for data persistence (no third-party ORM required)
89
*/
910

10-
export * from './auth-plugin';
11-
export * from './auth-manager';
11+
export * from './auth-plugin.js';
12+
export * from './auth-manager.js';
13+
export * from './objectql-adapter.js';
14+
export * from './objects/index.js';
1215
export type { AuthConfig, AuthProviderConfig, AuthPluginConfig } from '@objectstack/spec/system';

0 commit comments

Comments
 (0)