@objectstack/plugin-auth 2.0.3 → 2.0.5
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/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +9 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +14 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/auth-plugin.ts +18 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @objectstack/plugin-auth@2.0.
|
|
2
|
+
> @objectstack/plugin-auth@2.0.5 build /home/runner/work/spec/spec/packages/plugins/plugin-auth
|
|
3
3
|
> tsup --config ../../../tsup.config.ts
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
[34mCLI[39m Cleaning output folder
|
|
11
11
|
[34mESM[39m Build start
|
|
12
12
|
[34mCJS[39m Build start
|
|
13
|
-
[
|
|
14
|
-
[
|
|
15
|
-
[
|
|
16
|
-
[
|
|
17
|
-
[
|
|
18
|
-
[
|
|
13
|
+
[32mCJS[39m [1mdist/index.js [22m[32m19.55 KB[39m
|
|
14
|
+
[32mCJS[39m [1mdist/index.js.map [22m[32m40.03 KB[39m
|
|
15
|
+
[32mCJS[39m ⚡️ Build success in 99ms
|
|
16
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m17.96 KB[39m
|
|
17
|
+
[32mESM[39m [1mdist/index.mjs.map [22m[32m39.47 KB[39m
|
|
18
|
+
[32mESM[39m ⚡️ Build success in 99ms
|
|
19
19
|
[34mDTS[39m Build start
|
|
20
|
-
[32mDTS[39m ⚡️ Build success in
|
|
20
|
+
[32mDTS[39m ⚡️ Build success in 13229ms
|
|
21
21
|
[32mDTS[39m [1mdist/index.d.mts [22m[32m339.64 KB[39m
|
|
22
22
|
[32mDTS[39m [1mdist/index.d.ts [22m[32m339.64 KB[39m
|
package/CHANGELOG.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -283,6 +283,20 @@ var AuthPlugin = class {
|
|
|
283
283
|
throw err;
|
|
284
284
|
}
|
|
285
285
|
}
|
|
286
|
+
try {
|
|
287
|
+
const ql = ctx.getService("objectql");
|
|
288
|
+
if (ql && typeof ql.registerMiddleware === "function") {
|
|
289
|
+
ql.registerMiddleware(async (opCtx, next) => {
|
|
290
|
+
if (opCtx.context?.userId || opCtx.context?.isSystem) {
|
|
291
|
+
return next();
|
|
292
|
+
}
|
|
293
|
+
await next();
|
|
294
|
+
});
|
|
295
|
+
ctx.logger.info("Auth middleware registered on ObjectQL engine");
|
|
296
|
+
}
|
|
297
|
+
} catch (_e) {
|
|
298
|
+
ctx.logger.debug("ObjectQL engine not available, skipping auth middleware registration");
|
|
299
|
+
}
|
|
286
300
|
ctx.logger.info("Auth Plugin started successfully");
|
|
287
301
|
}
|
|
288
302
|
async destroy() {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/auth-manager.ts","../src/objectql-adapter.ts","../src/auth-plugin.ts","../src/objects/auth-user.object.ts","../src/objects/auth-session.object.ts","../src/objects/auth-account.object.ts","../src/objects/auth-verification.object.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * @objectstack/plugin-auth\n * \n * Authentication & Identity Plugin for ObjectStack\n * Powered by better-auth for robust, secure authentication\n * Uses ObjectQL for data persistence (no third-party ORM required)\n */\n\nexport * from './auth-plugin.js';\nexport * from './auth-manager.js';\nexport * from './objectql-adapter.js';\nexport * from './objects/index.js';\nexport type { AuthConfig, AuthProviderConfig, AuthPluginConfig } from '@objectstack/spec/system';\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { betterAuth } from 'better-auth';\nimport type { Auth, BetterAuthOptions } from 'better-auth';\nimport type { AuthConfig } from '@objectstack/spec/system';\nimport type { IDataEngine } from '@objectstack/core';\nimport { createObjectQLAdapter } from './objectql-adapter.js';\n\n/**\n * Extended options for AuthManager\n */\nexport interface AuthManagerOptions extends Partial<AuthConfig> {\n /**\n * Better-Auth instance (for advanced use cases)\n * If not provided, one will be created from config\n */\n authInstance?: Auth<any>;\n \n /**\n * ObjectQL Data Engine instance\n * Required for database operations using ObjectQL instead of third-party ORMs\n */\n dataEngine?: IDataEngine;\n}\n\n/**\n * Authentication Manager\n * \n * Wraps better-auth and provides authentication services for ObjectStack.\n * Supports multiple authentication methods:\n * - Email/password\n * - OAuth providers (Google, GitHub, etc.)\n * - Magic links\n * - Two-factor authentication\n * - Passkeys\n * - Organization/teams\n */\nexport class AuthManager {\n private auth: Auth<any> | null = null;\n private config: AuthManagerOptions;\n\n constructor(config: AuthManagerOptions) {\n this.config = config;\n \n // Use provided auth instance\n if (config.authInstance) {\n this.auth = config.authInstance;\n }\n // Don't create auth instance automatically to avoid database initialization errors\n // It will be created lazily when needed\n }\n\n /**\n * Get or create the better-auth instance (lazy initialization)\n */\n private getOrCreateAuth(): Auth<any> {\n if (!this.auth) {\n this.auth = this.createAuthInstance();\n }\n return this.auth;\n }\n\n /**\n * Create a better-auth instance from configuration\n */\n private createAuthInstance(): Auth<any> {\n const betterAuthConfig: BetterAuthOptions = {\n // Base configuration\n secret: this.config.secret || this.generateSecret(),\n baseURL: this.config.baseUrl || 'http://localhost:3000',\n \n // Database adapter configuration\n // For now, we configure a basic setup that will be enhanced\n // when database URL is provided and drizzle-orm is available\n database: this.createDatabaseConfig(),\n \n // Email configuration\n emailAndPassword: {\n enabled: true,\n },\n \n // Session configuration\n session: {\n expiresIn: this.config.session?.expiresIn || 60 * 60 * 24 * 7, // 7 days default\n updateAge: this.config.session?.updateAge || 60 * 60 * 24, // 1 day default\n },\n };\n\n return betterAuth(betterAuthConfig);\n }\n\n /**\n * Create database configuration using ObjectQL adapter\n */\n private createDatabaseConfig(): any {\n // Use ObjectQL adapter if dataEngine is provided\n if (this.config.dataEngine) {\n return createObjectQLAdapter(this.config.dataEngine);\n }\n \n // Fallback warning if no dataEngine is provided\n console.warn(\n '⚠️ WARNING: No dataEngine provided to AuthManager! ' +\n 'Using in-memory storage. This is NOT suitable for production. ' +\n 'Please provide a dataEngine instance (e.g., ObjectQL) in AuthManagerOptions.'\n );\n \n // Return a minimal in-memory configuration as fallback\n // This allows the system to work in development/testing without a real database\n return undefined; // better-auth will use its default in-memory adapter\n }\n\n /**\n * Generate a secure secret if not provided\n */\n private generateSecret(): string {\n const envSecret = process.env.AUTH_SECRET;\n \n if (!envSecret) {\n // In production, a secret MUST be provided\n // For development/testing, we'll use a fallback but warn about it\n const fallbackSecret = 'dev-secret-' + Date.now();\n \n console.warn(\n '⚠️ WARNING: No AUTH_SECRET environment variable set! ' +\n 'Using a temporary development secret. ' +\n 'This is NOT secure for production use. ' +\n 'Please set AUTH_SECRET in your environment variables.'\n );\n \n return fallbackSecret;\n }\n \n return envSecret;\n }\n\n /**\n * Get the underlying better-auth instance\n * Useful for advanced use cases\n */\n getAuthInstance(): Auth<any> {\n return this.getOrCreateAuth();\n }\n\n /**\n * Handle an authentication request\n * Forwards the request directly to better-auth's universal handler\n * \n * @param request - Web standard Request object\n * @returns Web standard Response object\n */\n async handleRequest(request: Request): Promise<Response> {\n const auth = this.getOrCreateAuth();\n return await auth.handler(request);\n }\n\n /**\n * Get the better-auth API for programmatic access\n * Use this for server-side operations (e.g., creating users, checking sessions)\n */\n get api() {\n return this.getOrCreateAuth().api;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { IDataEngine } from '@objectstack/core';\nimport type { CleanedWhere } from 'better-auth/adapters';\n\n/**\n * ObjectQL Adapter for better-auth\n * \n * Bridges better-auth's database adapter interface with ObjectQL's IDataEngine.\n * This allows better-auth to use ObjectQL for data persistence instead of\n * third-party ORMs like drizzle-orm.\n * \n * Uses better-auth's native naming conventions (camelCase) for seamless migration.\n * \n * @param dataEngine - ObjectQL data engine instance\n * @returns better-auth CustomAdapter\n */\nexport function createObjectQLAdapter(dataEngine: IDataEngine) {\n /**\n * Convert better-auth where clause to ObjectQL query format\n */\n function convertWhere(where: CleanedWhere[]): Record<string, any> {\n const filter: Record<string, any> = {};\n \n for (const condition of where) {\n // Use field names as-is (no conversion needed)\n const fieldName = condition.field;\n \n if (condition.operator === 'eq') {\n filter[fieldName] = condition.value;\n } else if (condition.operator === 'ne') {\n filter[fieldName] = { $ne: condition.value };\n } else if (condition.operator === 'in') {\n filter[fieldName] = { $in: condition.value };\n } else if (condition.operator === 'gt') {\n filter[fieldName] = { $gt: condition.value };\n } else if (condition.operator === 'gte') {\n filter[fieldName] = { $gte: condition.value };\n } else if (condition.operator === 'lt') {\n filter[fieldName] = { $lt: condition.value };\n } else if (condition.operator === 'lte') {\n filter[fieldName] = { $lte: condition.value };\n } else if (condition.operator === 'contains') {\n filter[fieldName] = { $regex: condition.value };\n }\n }\n \n return filter;\n }\n\n return {\n create: async <T extends Record<string, any>>({ model, data, select: _select }: { model: string; data: T; select?: string[] }): Promise<T> => {\n // Use model name as-is (no conversion needed)\n const objectName = model;\n \n // Note: select parameter is currently not supported by ObjectQL's insert operation\n // The full record is always returned after insertion\n const result = await dataEngine.insert(objectName, data);\n return result as T;\n },\n \n findOne: async <T>({ model, where, select, join: _join }: { model: string; where: CleanedWhere[]; select?: string[]; join?: any }): Promise<T | null> => {\n const objectName = model;\n const filter = convertWhere(where);\n \n // Note: join parameter is not currently supported by ObjectQL's findOne operation\n // Joins/populate functionality is planned for future ObjectQL releases\n // For now, related data must be fetched separately\n \n const result = await dataEngine.findOne(objectName, {\n filter,\n select,\n });\n \n return result ? result as T : null;\n },\n \n findMany: async <T>({ model, where, limit, offset, sortBy, join: _join }: { model: string; where?: CleanedWhere[]; limit: number; offset?: number; sortBy?: { field: string; direction: 'asc' | 'desc' }; join?: any }): Promise<T[]> => {\n const objectName = model;\n const filter = where ? convertWhere(where) : {};\n \n // Note: join parameter is not currently supported by ObjectQL's find operation\n // Joins/populate functionality is planned for future ObjectQL releases\n \n const sort = sortBy ? [{\n field: sortBy.field,\n order: sortBy.direction as 'asc' | 'desc',\n }] : undefined;\n \n const results = await dataEngine.find(objectName, {\n filter,\n limit: limit || 100,\n skip: offset,\n sort,\n });\n \n return results as T[];\n },\n \n count: async ({ model, where }: { model: string; where?: CleanedWhere[] }): Promise<number> => {\n const objectName = model;\n const filter = where ? convertWhere(where) : {};\n \n return await dataEngine.count(objectName, { filter });\n },\n \n update: async <T>({ model, where, update }: { model: string; where: CleanedWhere[]; update: Record<string, any> }): Promise<T | null> => {\n const objectName = model;\n const filter = convertWhere(where);\n \n // Find the record first to get its ID\n const record = await dataEngine.findOne(objectName, { filter });\n if (!record) {\n return null;\n }\n \n const result = await dataEngine.update(objectName, {\n ...update,\n id: record.id,\n });\n \n return result ? result as T : null;\n },\n \n updateMany: async ({ model, where, update }: { model: string; where: CleanedWhere[]; update: Record<string, any> }): Promise<number> => {\n const objectName = model;\n const filter = convertWhere(where);\n \n // Note: Sequential updates are used here because ObjectQL's IDataEngine interface\n // requires an ID for updates. A future optimization could use a bulk update\n // operation if ObjectQL adds support for filter-based updates without IDs.\n \n // Find all matching records\n const records = await dataEngine.find(objectName, { filter });\n \n // Update each record\n for (const record of records) {\n await dataEngine.update(objectName, {\n ...update,\n id: record.id,\n });\n }\n \n return records.length;\n },\n \n delete: async ({ model, where }: { model: string; where: CleanedWhere[] }): Promise<void> => {\n const objectName = model;\n const filter = convertWhere(where);\n \n // Note: We need to find the record first to get its ID because ObjectQL's\n // delete operation requires an ID. Direct filter-based delete would be more\n // efficient if supported by ObjectQL in the future.\n const record = await dataEngine.findOne(objectName, { filter });\n if (!record) {\n return;\n }\n \n await dataEngine.delete(objectName, { filter: { id: record.id } });\n },\n \n deleteMany: async ({ model, where }: { model: string; where: CleanedWhere[] }): Promise<number> => {\n const objectName = model;\n const filter = convertWhere(where);\n \n // Note: Sequential deletes are used here because ObjectQL's delete operation\n // requires an ID in the filter. A future optimization could use a single\n // delete call with the original filter if ObjectQL supports it.\n \n // Find all matching records\n const records = await dataEngine.find(objectName, { filter });\n \n // Delete each record\n for (const record of records) {\n await dataEngine.delete(objectName, { filter: { id: record.id } });\n }\n \n return records.length;\n },\n };\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { Plugin, PluginContext, IHttpServer } from '@objectstack/core';\nimport { AuthConfig } from '@objectstack/spec/system';\nimport { AuthManager } from './auth-manager.js';\n\n/**\n * Auth Plugin Options\n * Extends AuthConfig from spec with additional runtime options\n */\nexport interface AuthPluginOptions extends Partial<AuthConfig> {\n /**\n * Whether to automatically register auth routes\n * @default true\n */\n registerRoutes?: boolean;\n \n /**\n * Base path for auth routes\n * @default '/api/v1/auth'\n */\n basePath?: string;\n}\n\n/**\n * Authentication Plugin\n * \n * Provides authentication and identity services for ObjectStack applications.\n * \n * Features:\n * - Session management\n * - User registration/login\n * - OAuth providers (Google, GitHub, etc.)\n * - Organization/team support\n * - 2FA, passkeys, magic links\n * \n * This plugin registers:\n * - `auth` service (auth manager instance)\n * - HTTP routes for authentication endpoints\n * \n * Integrates with better-auth library to provide comprehensive\n * authentication capabilities including email/password, OAuth, 2FA,\n * magic links, passkeys, and organization support.\n */\nexport class AuthPlugin implements Plugin {\n name = 'com.objectstack.auth';\n type = 'standard';\n version = '1.0.0';\n dependencies = ['com.objectstack.server.hono']; // Requires HTTP server\n \n private options: AuthPluginOptions;\n private authManager: AuthManager | null = null;\n\n constructor(options: AuthPluginOptions = {}) {\n this.options = {\n registerRoutes: true,\n basePath: '/api/v1/auth',\n ...options\n };\n }\n\n async init(ctx: PluginContext): Promise<void> {\n ctx.logger.info('Initializing Auth Plugin...');\n\n // Validate required configuration\n if (!this.options.secret) {\n throw new Error('AuthPlugin: secret is required');\n }\n\n // Get data engine service for database operations\n const dataEngine = ctx.getService<any>('data');\n if (!dataEngine) {\n ctx.logger.warn('No data engine service found - auth will use in-memory storage');\n }\n\n // Initialize auth manager with data engine\n this.authManager = new AuthManager({\n ...this.options,\n dataEngine,\n });\n\n // Register auth service\n ctx.registerService('auth', this.authManager);\n \n ctx.logger.info('Auth Plugin initialized successfully');\n }\n\n async start(ctx: PluginContext): Promise<void> {\n ctx.logger.info('Starting Auth Plugin...');\n\n if (!this.authManager) {\n throw new Error('Auth manager not initialized');\n }\n\n // Register HTTP routes if enabled\n if (this.options.registerRoutes) {\n try {\n const httpServer = ctx.getService<IHttpServer>('http-server');\n this.registerAuthRoutes(httpServer, ctx);\n ctx.logger.info(`Auth routes registered at ${this.options.basePath}`);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n ctx.logger.error('Failed to register auth routes:', err);\n throw err;\n }\n }\n\n ctx.logger.info('Auth Plugin started successfully');\n }\n\n async destroy(): Promise<void> {\n // Cleanup if needed\n this.authManager = null;\n }\n\n /**\n * Register authentication routes with HTTP server\n * \n * Uses better-auth's universal handler for all authentication requests.\n * This forwards all requests under basePath to better-auth, which handles:\n * - Email/password authentication\n * - OAuth providers (Google, GitHub, etc.)\n * - Session management\n * - Password reset\n * - Email verification\n * - 2FA, passkeys, magic links (if enabled)\n */\n private registerAuthRoutes(httpServer: IHttpServer, ctx: PluginContext): void {\n if (!this.authManager) return;\n\n const basePath = this.options.basePath || '/api/v1/auth';\n\n // Get raw Hono app to use native wildcard routing\n // Type assertion is safe here because we explicitly require Hono server as a dependency\n if (!('getRawApp' in httpServer) || typeof (httpServer as any).getRawApp !== 'function') {\n ctx.logger.error('HTTP server does not support getRawApp() - wildcard routing requires Hono server');\n throw new Error(\n 'AuthPlugin requires HonoServerPlugin for wildcard routing support. ' +\n 'Please ensure HonoServerPlugin is loaded before AuthPlugin.'\n );\n }\n\n const rawApp = (httpServer as any).getRawApp();\n\n // Register wildcard route to forward all auth requests to better-auth\n // Better-auth expects requests at its baseURL, so we need to preserve the full path\n rawApp.all(`${basePath}/*`, async (c: any) => {\n try {\n // Get the Web standard Request from Hono context\n const request = c.req.raw as Request;\n \n // Create a new Request with the path rewritten to match better-auth's expectations\n // Better-auth expects paths like /sign-in/email, /sign-up/email, etc.\n // We need to strip our basePath prefix\n const url = new URL(request.url);\n const authPath = url.pathname.replace(basePath, '');\n const rewrittenUrl = new URL(authPath || '/', url.origin);\n rewrittenUrl.search = url.search; // Preserve query params\n \n const rewrittenRequest = new Request(rewrittenUrl, {\n method: request.method,\n headers: request.headers,\n body: request.body,\n duplex: 'half' as any, // Required for Request with body\n });\n\n // Forward to better-auth handler\n const response = await this.authManager!.handleRequest(rewrittenRequest);\n \n return response;\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n ctx.logger.error('Auth request error:', err);\n \n // Return error response\n return new Response(\n JSON.stringify({\n success: false,\n error: err.message,\n }),\n {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n }\n );\n }\n });\n\n ctx.logger.info(`Auth routes registered: All requests under ${basePath}/* forwarded to better-auth`);\n }\n}\n\n\n\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * Auth User Object\n * \n * Uses better-auth's native schema for seamless migration:\n * - id: string\n * - createdAt: Date\n * - updatedAt: Date\n * - email: string (unique, lowercase)\n * - emailVerified: boolean\n * - name: string\n * - image: string | null\n */\nexport const AuthUser = ObjectSchema.create({\n name: 'user',\n label: 'User',\n pluralLabel: 'Users',\n icon: 'user',\n description: 'User accounts for authentication',\n titleFormat: '{name} ({email})',\n compactLayout: ['name', 'email', 'emailVerified'],\n \n fields: {\n // ID is auto-generated by ObjectQL\n id: Field.text({\n label: 'User ID',\n required: true,\n readonly: true,\n }),\n \n createdAt: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updatedAt: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n email: Field.email({\n label: 'Email',\n required: true,\n searchable: true,\n }),\n \n emailVerified: Field.boolean({\n label: 'Email Verified',\n defaultValue: false,\n }),\n \n name: Field.text({\n label: 'Name',\n required: true,\n searchable: true,\n maxLength: 255,\n }),\n \n image: Field.url({\n label: 'Profile Image',\n required: false,\n }),\n },\n \n // Database indexes for performance\n indexes: [\n { fields: ['email'], unique: true },\n { fields: ['createdAt'], unique: false },\n ],\n \n // Enable features\n enable: {\n trackHistory: true,\n searchable: true,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: true,\n mru: true,\n },\n \n // Validation Rules\n validations: [\n {\n name: 'email_unique',\n type: 'unique',\n severity: 'error',\n message: 'Email must be unique',\n fields: ['email'],\n caseSensitive: false,\n },\n ],\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * Auth Session Object\n * \n * Uses better-auth's native schema for seamless migration:\n * - id: string\n * - createdAt: Date\n * - updatedAt: Date\n * - userId: string\n * - expiresAt: Date\n * - token: string\n * - ipAddress: string | null\n * - userAgent: string | null\n */\nexport const AuthSession = ObjectSchema.create({\n name: 'session',\n label: 'Session',\n pluralLabel: 'Sessions',\n icon: 'key',\n description: 'Active user sessions',\n titleFormat: 'Session {token}',\n compactLayout: ['userId', 'expiresAt', 'ipAddress'],\n \n fields: {\n id: Field.text({\n label: 'Session ID',\n required: true,\n readonly: true,\n }),\n \n createdAt: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updatedAt: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n userId: Field.text({\n label: 'User ID',\n required: true,\n }),\n \n expiresAt: Field.datetime({\n label: 'Expires At',\n required: true,\n }),\n \n token: Field.text({\n label: 'Session Token',\n required: true,\n }),\n \n ipAddress: Field.text({\n label: 'IP Address',\n required: false,\n maxLength: 45, // Support IPv6\n }),\n \n userAgent: Field.textarea({\n label: 'User Agent',\n required: false,\n }),\n },\n \n // Database indexes for performance\n indexes: [\n { fields: ['token'], unique: true },\n { fields: ['userId'], unique: false },\n { fields: ['expiresAt'], unique: false },\n ],\n \n // Enable features\n enable: {\n trackHistory: false, // Sessions don't need history tracking\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'delete'], // No update for sessions\n trash: false, // Sessions should be hard deleted\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * Auth Account Object\n * \n * Uses better-auth's native schema for seamless migration:\n * - id: string\n * - createdAt: Date\n * - updatedAt: Date\n * - providerId: string (e.g., 'google', 'github')\n * - accountId: string (provider's user ID)\n * - userId: string (link to user table)\n * - accessToken: string | null\n * - refreshToken: string | null\n * - idToken: string | null\n * - accessTokenExpiresAt: Date | null\n * - refreshTokenExpiresAt: Date | null\n * - scope: string | null\n * - password: string | null (for email/password provider)\n */\nexport const AuthAccount = ObjectSchema.create({\n name: 'account',\n label: 'Account',\n pluralLabel: 'Accounts',\n icon: 'link',\n description: 'OAuth and authentication provider accounts',\n titleFormat: '{providerId} - {accountId}',\n compactLayout: ['providerId', 'userId', 'accountId'],\n \n fields: {\n id: Field.text({\n label: 'Account ID',\n required: true,\n readonly: true,\n }),\n \n createdAt: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updatedAt: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n providerId: Field.text({\n label: 'Provider ID',\n required: true,\n description: 'OAuth provider identifier (google, github, etc.)',\n }),\n \n accountId: Field.text({\n label: 'Provider Account ID',\n required: true,\n description: \"User's ID in the provider's system\",\n }),\n \n userId: Field.text({\n label: 'User ID',\n required: true,\n description: 'Link to user table',\n }),\n \n accessToken: Field.textarea({\n label: 'Access Token',\n required: false,\n }),\n \n refreshToken: Field.textarea({\n label: 'Refresh Token',\n required: false,\n }),\n \n idToken: Field.textarea({\n label: 'ID Token',\n required: false,\n }),\n \n accessTokenExpiresAt: Field.datetime({\n label: 'Access Token Expires At',\n required: false,\n }),\n \n refreshTokenExpiresAt: Field.datetime({\n label: 'Refresh Token Expires At',\n required: false,\n }),\n \n scope: Field.text({\n label: 'OAuth Scope',\n required: false,\n }),\n \n password: Field.text({\n label: 'Password Hash',\n required: false,\n description: 'Hashed password for email/password provider',\n }),\n },\n \n // Database indexes for performance\n indexes: [\n { fields: ['userId'], unique: false },\n { fields: ['providerId', 'accountId'], unique: true },\n ],\n \n // Enable features\n enable: {\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: true,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * Auth Verification Object\n * \n * Uses better-auth's native schema for seamless migration:\n * - id: string\n * - createdAt: Date\n * - updatedAt: Date\n * - value: string (verification token/code)\n * - expiresAt: Date\n * - identifier: string (email or phone number)\n */\nexport const AuthVerification = ObjectSchema.create({\n name: 'verification',\n label: 'Verification',\n pluralLabel: 'Verifications',\n icon: 'shield-check',\n description: 'Email and phone verification tokens',\n titleFormat: 'Verification for {identifier}',\n compactLayout: ['identifier', 'expiresAt', 'createdAt'],\n \n fields: {\n id: Field.text({\n label: 'Verification ID',\n required: true,\n readonly: true,\n }),\n \n createdAt: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updatedAt: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n value: Field.text({\n label: 'Verification Token',\n required: true,\n description: 'Token or code for verification',\n }),\n \n expiresAt: Field.datetime({\n label: 'Expires At',\n required: true,\n }),\n \n identifier: Field.text({\n label: 'Identifier',\n required: true,\n description: 'Email address or phone number',\n }),\n },\n \n // Database indexes for performance\n indexes: [\n { fields: ['value'], unique: true },\n { fields: ['identifier'], unique: false },\n { fields: ['expiresAt'], unique: false },\n ],\n \n // Enable features\n enable: {\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'create', 'delete'], // No list or update\n trash: false, // Hard delete expired tokens\n mru: false,\n },\n});\n"],"mappings":"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","names":["import_data","import_data","import_data"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/auth-manager.ts","../src/objectql-adapter.ts","../src/auth-plugin.ts","../src/objects/auth-user.object.ts","../src/objects/auth-session.object.ts","../src/objects/auth-account.object.ts","../src/objects/auth-verification.object.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * @objectstack/plugin-auth\n * \n * Authentication & Identity Plugin for ObjectStack\n * Powered by better-auth for robust, secure authentication\n * Uses ObjectQL for data persistence (no third-party ORM required)\n */\n\nexport * from './auth-plugin.js';\nexport * from './auth-manager.js';\nexport * from './objectql-adapter.js';\nexport * from './objects/index.js';\nexport type { AuthConfig, AuthProviderConfig, AuthPluginConfig } from '@objectstack/spec/system';\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { betterAuth } from 'better-auth';\nimport type { Auth, BetterAuthOptions } from 'better-auth';\nimport type { AuthConfig } from '@objectstack/spec/system';\nimport type { IDataEngine } from '@objectstack/core';\nimport { createObjectQLAdapter } from './objectql-adapter.js';\n\n/**\n * Extended options for AuthManager\n */\nexport interface AuthManagerOptions extends Partial<AuthConfig> {\n /**\n * Better-Auth instance (for advanced use cases)\n * If not provided, one will be created from config\n */\n authInstance?: Auth<any>;\n \n /**\n * ObjectQL Data Engine instance\n * Required for database operations using ObjectQL instead of third-party ORMs\n */\n dataEngine?: IDataEngine;\n}\n\n/**\n * Authentication Manager\n * \n * Wraps better-auth and provides authentication services for ObjectStack.\n * Supports multiple authentication methods:\n * - Email/password\n * - OAuth providers (Google, GitHub, etc.)\n * - Magic links\n * - Two-factor authentication\n * - Passkeys\n * - Organization/teams\n */\nexport class AuthManager {\n private auth: Auth<any> | null = null;\n private config: AuthManagerOptions;\n\n constructor(config: AuthManagerOptions) {\n this.config = config;\n \n // Use provided auth instance\n if (config.authInstance) {\n this.auth = config.authInstance;\n }\n // Don't create auth instance automatically to avoid database initialization errors\n // It will be created lazily when needed\n }\n\n /**\n * Get or create the better-auth instance (lazy initialization)\n */\n private getOrCreateAuth(): Auth<any> {\n if (!this.auth) {\n this.auth = this.createAuthInstance();\n }\n return this.auth;\n }\n\n /**\n * Create a better-auth instance from configuration\n */\n private createAuthInstance(): Auth<any> {\n const betterAuthConfig: BetterAuthOptions = {\n // Base configuration\n secret: this.config.secret || this.generateSecret(),\n baseURL: this.config.baseUrl || 'http://localhost:3000',\n \n // Database adapter configuration\n // For now, we configure a basic setup that will be enhanced\n // when database URL is provided and drizzle-orm is available\n database: this.createDatabaseConfig(),\n \n // Email configuration\n emailAndPassword: {\n enabled: true,\n },\n \n // Session configuration\n session: {\n expiresIn: this.config.session?.expiresIn || 60 * 60 * 24 * 7, // 7 days default\n updateAge: this.config.session?.updateAge || 60 * 60 * 24, // 1 day default\n },\n };\n\n return betterAuth(betterAuthConfig);\n }\n\n /**\n * Create database configuration using ObjectQL adapter\n */\n private createDatabaseConfig(): any {\n // Use ObjectQL adapter if dataEngine is provided\n if (this.config.dataEngine) {\n return createObjectQLAdapter(this.config.dataEngine);\n }\n \n // Fallback warning if no dataEngine is provided\n console.warn(\n '⚠️ WARNING: No dataEngine provided to AuthManager! ' +\n 'Using in-memory storage. This is NOT suitable for production. ' +\n 'Please provide a dataEngine instance (e.g., ObjectQL) in AuthManagerOptions.'\n );\n \n // Return a minimal in-memory configuration as fallback\n // This allows the system to work in development/testing without a real database\n return undefined; // better-auth will use its default in-memory adapter\n }\n\n /**\n * Generate a secure secret if not provided\n */\n private generateSecret(): string {\n const envSecret = process.env.AUTH_SECRET;\n \n if (!envSecret) {\n // In production, a secret MUST be provided\n // For development/testing, we'll use a fallback but warn about it\n const fallbackSecret = 'dev-secret-' + Date.now();\n \n console.warn(\n '⚠️ WARNING: No AUTH_SECRET environment variable set! ' +\n 'Using a temporary development secret. ' +\n 'This is NOT secure for production use. ' +\n 'Please set AUTH_SECRET in your environment variables.'\n );\n \n return fallbackSecret;\n }\n \n return envSecret;\n }\n\n /**\n * Get the underlying better-auth instance\n * Useful for advanced use cases\n */\n getAuthInstance(): Auth<any> {\n return this.getOrCreateAuth();\n }\n\n /**\n * Handle an authentication request\n * Forwards the request directly to better-auth's universal handler\n * \n * @param request - Web standard Request object\n * @returns Web standard Response object\n */\n async handleRequest(request: Request): Promise<Response> {\n const auth = this.getOrCreateAuth();\n return await auth.handler(request);\n }\n\n /**\n * Get the better-auth API for programmatic access\n * Use this for server-side operations (e.g., creating users, checking sessions)\n */\n get api() {\n return this.getOrCreateAuth().api;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { IDataEngine } from '@objectstack/core';\nimport type { CleanedWhere } from 'better-auth/adapters';\n\n/**\n * ObjectQL Adapter for better-auth\n * \n * Bridges better-auth's database adapter interface with ObjectQL's IDataEngine.\n * This allows better-auth to use ObjectQL for data persistence instead of\n * third-party ORMs like drizzle-orm.\n * \n * Uses better-auth's native naming conventions (camelCase) for seamless migration.\n * \n * @param dataEngine - ObjectQL data engine instance\n * @returns better-auth CustomAdapter\n */\nexport function createObjectQLAdapter(dataEngine: IDataEngine) {\n /**\n * Convert better-auth where clause to ObjectQL query format\n */\n function convertWhere(where: CleanedWhere[]): Record<string, any> {\n const filter: Record<string, any> = {};\n \n for (const condition of where) {\n // Use field names as-is (no conversion needed)\n const fieldName = condition.field;\n \n if (condition.operator === 'eq') {\n filter[fieldName] = condition.value;\n } else if (condition.operator === 'ne') {\n filter[fieldName] = { $ne: condition.value };\n } else if (condition.operator === 'in') {\n filter[fieldName] = { $in: condition.value };\n } else if (condition.operator === 'gt') {\n filter[fieldName] = { $gt: condition.value };\n } else if (condition.operator === 'gte') {\n filter[fieldName] = { $gte: condition.value };\n } else if (condition.operator === 'lt') {\n filter[fieldName] = { $lt: condition.value };\n } else if (condition.operator === 'lte') {\n filter[fieldName] = { $lte: condition.value };\n } else if (condition.operator === 'contains') {\n filter[fieldName] = { $regex: condition.value };\n }\n }\n \n return filter;\n }\n\n return {\n create: async <T extends Record<string, any>>({ model, data, select: _select }: { model: string; data: T; select?: string[] }): Promise<T> => {\n // Use model name as-is (no conversion needed)\n const objectName = model;\n \n // Note: select parameter is currently not supported by ObjectQL's insert operation\n // The full record is always returned after insertion\n const result = await dataEngine.insert(objectName, data);\n return result as T;\n },\n \n findOne: async <T>({ model, where, select, join: _join }: { model: string; where: CleanedWhere[]; select?: string[]; join?: any }): Promise<T | null> => {\n const objectName = model;\n const filter = convertWhere(where);\n \n // Note: join parameter is not currently supported by ObjectQL's findOne operation\n // Joins/populate functionality is planned for future ObjectQL releases\n // For now, related data must be fetched separately\n \n const result = await dataEngine.findOne(objectName, {\n filter,\n select,\n });\n \n return result ? result as T : null;\n },\n \n findMany: async <T>({ model, where, limit, offset, sortBy, join: _join }: { model: string; where?: CleanedWhere[]; limit: number; offset?: number; sortBy?: { field: string; direction: 'asc' | 'desc' }; join?: any }): Promise<T[]> => {\n const objectName = model;\n const filter = where ? convertWhere(where) : {};\n \n // Note: join parameter is not currently supported by ObjectQL's find operation\n // Joins/populate functionality is planned for future ObjectQL releases\n \n const sort = sortBy ? [{\n field: sortBy.field,\n order: sortBy.direction as 'asc' | 'desc',\n }] : undefined;\n \n const results = await dataEngine.find(objectName, {\n filter,\n limit: limit || 100,\n skip: offset,\n sort,\n });\n \n return results as T[];\n },\n \n count: async ({ model, where }: { model: string; where?: CleanedWhere[] }): Promise<number> => {\n const objectName = model;\n const filter = where ? convertWhere(where) : {};\n \n return await dataEngine.count(objectName, { filter });\n },\n \n update: async <T>({ model, where, update }: { model: string; where: CleanedWhere[]; update: Record<string, any> }): Promise<T | null> => {\n const objectName = model;\n const filter = convertWhere(where);\n \n // Find the record first to get its ID\n const record = await dataEngine.findOne(objectName, { filter });\n if (!record) {\n return null;\n }\n \n const result = await dataEngine.update(objectName, {\n ...update,\n id: record.id,\n });\n \n return result ? result as T : null;\n },\n \n updateMany: async ({ model, where, update }: { model: string; where: CleanedWhere[]; update: Record<string, any> }): Promise<number> => {\n const objectName = model;\n const filter = convertWhere(where);\n \n // Note: Sequential updates are used here because ObjectQL's IDataEngine interface\n // requires an ID for updates. A future optimization could use a bulk update\n // operation if ObjectQL adds support for filter-based updates without IDs.\n \n // Find all matching records\n const records = await dataEngine.find(objectName, { filter });\n \n // Update each record\n for (const record of records) {\n await dataEngine.update(objectName, {\n ...update,\n id: record.id,\n });\n }\n \n return records.length;\n },\n \n delete: async ({ model, where }: { model: string; where: CleanedWhere[] }): Promise<void> => {\n const objectName = model;\n const filter = convertWhere(where);\n \n // Note: We need to find the record first to get its ID because ObjectQL's\n // delete operation requires an ID. Direct filter-based delete would be more\n // efficient if supported by ObjectQL in the future.\n const record = await dataEngine.findOne(objectName, { filter });\n if (!record) {\n return;\n }\n \n await dataEngine.delete(objectName, { filter: { id: record.id } });\n },\n \n deleteMany: async ({ model, where }: { model: string; where: CleanedWhere[] }): Promise<number> => {\n const objectName = model;\n const filter = convertWhere(where);\n \n // Note: Sequential deletes are used here because ObjectQL's delete operation\n // requires an ID in the filter. A future optimization could use a single\n // delete call with the original filter if ObjectQL supports it.\n \n // Find all matching records\n const records = await dataEngine.find(objectName, { filter });\n \n // Delete each record\n for (const record of records) {\n await dataEngine.delete(objectName, { filter: { id: record.id } });\n }\n \n return records.length;\n },\n };\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { Plugin, PluginContext, IHttpServer } from '@objectstack/core';\nimport { AuthConfig } from '@objectstack/spec/system';\nimport { AuthManager } from './auth-manager.js';\n\n/**\n * Auth Plugin Options\n * Extends AuthConfig from spec with additional runtime options\n */\nexport interface AuthPluginOptions extends Partial<AuthConfig> {\n /**\n * Whether to automatically register auth routes\n * @default true\n */\n registerRoutes?: boolean;\n \n /**\n * Base path for auth routes\n * @default '/api/v1/auth'\n */\n basePath?: string;\n}\n\n/**\n * Authentication Plugin\n * \n * Provides authentication and identity services for ObjectStack applications.\n * \n * Features:\n * - Session management\n * - User registration/login\n * - OAuth providers (Google, GitHub, etc.)\n * - Organization/team support\n * - 2FA, passkeys, magic links\n * \n * This plugin registers:\n * - `auth` service (auth manager instance)\n * - HTTP routes for authentication endpoints\n * \n * Integrates with better-auth library to provide comprehensive\n * authentication capabilities including email/password, OAuth, 2FA,\n * magic links, passkeys, and organization support.\n */\nexport class AuthPlugin implements Plugin {\n name = 'com.objectstack.auth';\n type = 'standard';\n version = '1.0.0';\n dependencies = ['com.objectstack.server.hono']; // Requires HTTP server\n \n private options: AuthPluginOptions;\n private authManager: AuthManager | null = null;\n\n constructor(options: AuthPluginOptions = {}) {\n this.options = {\n registerRoutes: true,\n basePath: '/api/v1/auth',\n ...options\n };\n }\n\n async init(ctx: PluginContext): Promise<void> {\n ctx.logger.info('Initializing Auth Plugin...');\n\n // Validate required configuration\n if (!this.options.secret) {\n throw new Error('AuthPlugin: secret is required');\n }\n\n // Get data engine service for database operations\n const dataEngine = ctx.getService<any>('data');\n if (!dataEngine) {\n ctx.logger.warn('No data engine service found - auth will use in-memory storage');\n }\n\n // Initialize auth manager with data engine\n this.authManager = new AuthManager({\n ...this.options,\n dataEngine,\n });\n\n // Register auth service\n ctx.registerService('auth', this.authManager);\n \n ctx.logger.info('Auth Plugin initialized successfully');\n }\n\n async start(ctx: PluginContext): Promise<void> {\n ctx.logger.info('Starting Auth Plugin...');\n\n if (!this.authManager) {\n throw new Error('Auth manager not initialized');\n }\n\n // Register HTTP routes if enabled\n if (this.options.registerRoutes) {\n try {\n const httpServer = ctx.getService<IHttpServer>('http-server');\n this.registerAuthRoutes(httpServer, ctx);\n ctx.logger.info(`Auth routes registered at ${this.options.basePath}`);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n ctx.logger.error('Failed to register auth routes:', err);\n throw err;\n }\n }\n\n // Register auth middleware on ObjectQL engine (if available)\n try {\n const ql = ctx.getService<any>('objectql');\n if (ql && typeof ql.registerMiddleware === 'function') {\n ql.registerMiddleware(async (opCtx: any, next: () => Promise<void>) => {\n // If context already has userId or isSystem, skip auth resolution\n if (opCtx.context?.userId || opCtx.context?.isSystem) {\n return next();\n }\n // Future: resolve session from AsyncLocalStorage or request context\n await next();\n });\n ctx.logger.info('Auth middleware registered on ObjectQL engine');\n }\n } catch (_e) {\n ctx.logger.debug('ObjectQL engine not available, skipping auth middleware registration');\n }\n\n ctx.logger.info('Auth Plugin started successfully');\n }\n\n async destroy(): Promise<void> {\n // Cleanup if needed\n this.authManager = null;\n }\n\n /**\n * Register authentication routes with HTTP server\n * \n * Uses better-auth's universal handler for all authentication requests.\n * This forwards all requests under basePath to better-auth, which handles:\n * - Email/password authentication\n * - OAuth providers (Google, GitHub, etc.)\n * - Session management\n * - Password reset\n * - Email verification\n * - 2FA, passkeys, magic links (if enabled)\n */\n private registerAuthRoutes(httpServer: IHttpServer, ctx: PluginContext): void {\n if (!this.authManager) return;\n\n const basePath = this.options.basePath || '/api/v1/auth';\n\n // Get raw Hono app to use native wildcard routing\n // Type assertion is safe here because we explicitly require Hono server as a dependency\n if (!('getRawApp' in httpServer) || typeof (httpServer as any).getRawApp !== 'function') {\n ctx.logger.error('HTTP server does not support getRawApp() - wildcard routing requires Hono server');\n throw new Error(\n 'AuthPlugin requires HonoServerPlugin for wildcard routing support. ' +\n 'Please ensure HonoServerPlugin is loaded before AuthPlugin.'\n );\n }\n\n const rawApp = (httpServer as any).getRawApp();\n\n // Register wildcard route to forward all auth requests to better-auth\n // Better-auth expects requests at its baseURL, so we need to preserve the full path\n rawApp.all(`${basePath}/*`, async (c: any) => {\n try {\n // Get the Web standard Request from Hono context\n const request = c.req.raw as Request;\n \n // Create a new Request with the path rewritten to match better-auth's expectations\n // Better-auth expects paths like /sign-in/email, /sign-up/email, etc.\n // We need to strip our basePath prefix\n const url = new URL(request.url);\n const authPath = url.pathname.replace(basePath, '');\n const rewrittenUrl = new URL(authPath || '/', url.origin);\n rewrittenUrl.search = url.search; // Preserve query params\n \n const rewrittenRequest = new Request(rewrittenUrl, {\n method: request.method,\n headers: request.headers,\n body: request.body,\n duplex: 'half' as any, // Required for Request with body\n });\n\n // Forward to better-auth handler\n const response = await this.authManager!.handleRequest(rewrittenRequest);\n \n return response;\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n ctx.logger.error('Auth request error:', err);\n \n // Return error response\n return new Response(\n JSON.stringify({\n success: false,\n error: err.message,\n }),\n {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n }\n );\n }\n });\n\n ctx.logger.info(`Auth routes registered: All requests under ${basePath}/* forwarded to better-auth`);\n }\n}\n\n\n\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * Auth User Object\n * \n * Uses better-auth's native schema for seamless migration:\n * - id: string\n * - createdAt: Date\n * - updatedAt: Date\n * - email: string (unique, lowercase)\n * - emailVerified: boolean\n * - name: string\n * - image: string | null\n */\nexport const AuthUser = ObjectSchema.create({\n name: 'user',\n label: 'User',\n pluralLabel: 'Users',\n icon: 'user',\n description: 'User accounts for authentication',\n titleFormat: '{name} ({email})',\n compactLayout: ['name', 'email', 'emailVerified'],\n \n fields: {\n // ID is auto-generated by ObjectQL\n id: Field.text({\n label: 'User ID',\n required: true,\n readonly: true,\n }),\n \n createdAt: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updatedAt: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n email: Field.email({\n label: 'Email',\n required: true,\n searchable: true,\n }),\n \n emailVerified: Field.boolean({\n label: 'Email Verified',\n defaultValue: false,\n }),\n \n name: Field.text({\n label: 'Name',\n required: true,\n searchable: true,\n maxLength: 255,\n }),\n \n image: Field.url({\n label: 'Profile Image',\n required: false,\n }),\n },\n \n // Database indexes for performance\n indexes: [\n { fields: ['email'], unique: true },\n { fields: ['createdAt'], unique: false },\n ],\n \n // Enable features\n enable: {\n trackHistory: true,\n searchable: true,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: true,\n mru: true,\n },\n \n // Validation Rules\n validations: [\n {\n name: 'email_unique',\n type: 'unique',\n severity: 'error',\n message: 'Email must be unique',\n fields: ['email'],\n caseSensitive: false,\n },\n ],\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * Auth Session Object\n * \n * Uses better-auth's native schema for seamless migration:\n * - id: string\n * - createdAt: Date\n * - updatedAt: Date\n * - userId: string\n * - expiresAt: Date\n * - token: string\n * - ipAddress: string | null\n * - userAgent: string | null\n */\nexport const AuthSession = ObjectSchema.create({\n name: 'session',\n label: 'Session',\n pluralLabel: 'Sessions',\n icon: 'key',\n description: 'Active user sessions',\n titleFormat: 'Session {token}',\n compactLayout: ['userId', 'expiresAt', 'ipAddress'],\n \n fields: {\n id: Field.text({\n label: 'Session ID',\n required: true,\n readonly: true,\n }),\n \n createdAt: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updatedAt: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n userId: Field.text({\n label: 'User ID',\n required: true,\n }),\n \n expiresAt: Field.datetime({\n label: 'Expires At',\n required: true,\n }),\n \n token: Field.text({\n label: 'Session Token',\n required: true,\n }),\n \n ipAddress: Field.text({\n label: 'IP Address',\n required: false,\n maxLength: 45, // Support IPv6\n }),\n \n userAgent: Field.textarea({\n label: 'User Agent',\n required: false,\n }),\n },\n \n // Database indexes for performance\n indexes: [\n { fields: ['token'], unique: true },\n { fields: ['userId'], unique: false },\n { fields: ['expiresAt'], unique: false },\n ],\n \n // Enable features\n enable: {\n trackHistory: false, // Sessions don't need history tracking\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'delete'], // No update for sessions\n trash: false, // Sessions should be hard deleted\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * Auth Account Object\n * \n * Uses better-auth's native schema for seamless migration:\n * - id: string\n * - createdAt: Date\n * - updatedAt: Date\n * - providerId: string (e.g., 'google', 'github')\n * - accountId: string (provider's user ID)\n * - userId: string (link to user table)\n * - accessToken: string | null\n * - refreshToken: string | null\n * - idToken: string | null\n * - accessTokenExpiresAt: Date | null\n * - refreshTokenExpiresAt: Date | null\n * - scope: string | null\n * - password: string | null (for email/password provider)\n */\nexport const AuthAccount = ObjectSchema.create({\n name: 'account',\n label: 'Account',\n pluralLabel: 'Accounts',\n icon: 'link',\n description: 'OAuth and authentication provider accounts',\n titleFormat: '{providerId} - {accountId}',\n compactLayout: ['providerId', 'userId', 'accountId'],\n \n fields: {\n id: Field.text({\n label: 'Account ID',\n required: true,\n readonly: true,\n }),\n \n createdAt: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updatedAt: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n providerId: Field.text({\n label: 'Provider ID',\n required: true,\n description: 'OAuth provider identifier (google, github, etc.)',\n }),\n \n accountId: Field.text({\n label: 'Provider Account ID',\n required: true,\n description: \"User's ID in the provider's system\",\n }),\n \n userId: Field.text({\n label: 'User ID',\n required: true,\n description: 'Link to user table',\n }),\n \n accessToken: Field.textarea({\n label: 'Access Token',\n required: false,\n }),\n \n refreshToken: Field.textarea({\n label: 'Refresh Token',\n required: false,\n }),\n \n idToken: Field.textarea({\n label: 'ID Token',\n required: false,\n }),\n \n accessTokenExpiresAt: Field.datetime({\n label: 'Access Token Expires At',\n required: false,\n }),\n \n refreshTokenExpiresAt: Field.datetime({\n label: 'Refresh Token Expires At',\n required: false,\n }),\n \n scope: Field.text({\n label: 'OAuth Scope',\n required: false,\n }),\n \n password: Field.text({\n label: 'Password Hash',\n required: false,\n description: 'Hashed password for email/password provider',\n }),\n },\n \n // Database indexes for performance\n indexes: [\n { fields: ['userId'], unique: false },\n { fields: ['providerId', 'accountId'], unique: true },\n ],\n \n // Enable features\n enable: {\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: true,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * Auth Verification Object\n * \n * Uses better-auth's native schema for seamless migration:\n * - id: string\n * - createdAt: Date\n * - updatedAt: Date\n * - value: string (verification token/code)\n * - expiresAt: Date\n * - identifier: string (email or phone number)\n */\nexport const AuthVerification = ObjectSchema.create({\n name: 'verification',\n label: 'Verification',\n pluralLabel: 'Verifications',\n icon: 'shield-check',\n description: 'Email and phone verification tokens',\n titleFormat: 'Verification for {identifier}',\n compactLayout: ['identifier', 'expiresAt', 'createdAt'],\n \n fields: {\n id: Field.text({\n label: 'Verification ID',\n required: true,\n readonly: true,\n }),\n \n createdAt: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updatedAt: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n value: Field.text({\n label: 'Verification Token',\n required: true,\n description: 'Token or code for verification',\n }),\n \n expiresAt: Field.datetime({\n label: 'Expires At',\n required: true,\n }),\n \n identifier: Field.text({\n label: 'Identifier',\n required: true,\n description: 'Email address or phone number',\n }),\n },\n \n // Database indexes for performance\n indexes: [\n { fields: ['value'], unique: true },\n { fields: ['identifier'], unique: false },\n { fields: ['expiresAt'], unique: false },\n ],\n \n // Enable features\n enable: {\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'create', 'delete'], // No list or update\n trash: false, // Hard delete expired tokens\n mru: false,\n },\n});\n"],"mappings":"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","names":["import_data","import_data","import_data"]}
|
package/dist/index.mjs
CHANGED
|
@@ -251,6 +251,20 @@ var AuthPlugin = class {
|
|
|
251
251
|
throw err;
|
|
252
252
|
}
|
|
253
253
|
}
|
|
254
|
+
try {
|
|
255
|
+
const ql = ctx.getService("objectql");
|
|
256
|
+
if (ql && typeof ql.registerMiddleware === "function") {
|
|
257
|
+
ql.registerMiddleware(async (opCtx, next) => {
|
|
258
|
+
if (opCtx.context?.userId || opCtx.context?.isSystem) {
|
|
259
|
+
return next();
|
|
260
|
+
}
|
|
261
|
+
await next();
|
|
262
|
+
});
|
|
263
|
+
ctx.logger.info("Auth middleware registered on ObjectQL engine");
|
|
264
|
+
}
|
|
265
|
+
} catch (_e) {
|
|
266
|
+
ctx.logger.debug("ObjectQL engine not available, skipping auth middleware registration");
|
|
267
|
+
}
|
|
254
268
|
ctx.logger.info("Auth Plugin started successfully");
|
|
255
269
|
}
|
|
256
270
|
async destroy() {
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/auth-manager.ts","../src/objectql-adapter.ts","../src/auth-plugin.ts","../src/objects/auth-user.object.ts","../src/objects/auth-session.object.ts","../src/objects/auth-account.object.ts","../src/objects/auth-verification.object.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { betterAuth } from 'better-auth';\nimport type { Auth, BetterAuthOptions } from 'better-auth';\nimport type { AuthConfig } from '@objectstack/spec/system';\nimport type { IDataEngine } from '@objectstack/core';\nimport { createObjectQLAdapter } from './objectql-adapter.js';\n\n/**\n * Extended options for AuthManager\n */\nexport interface AuthManagerOptions extends Partial<AuthConfig> {\n /**\n * Better-Auth instance (for advanced use cases)\n * If not provided, one will be created from config\n */\n authInstance?: Auth<any>;\n \n /**\n * ObjectQL Data Engine instance\n * Required for database operations using ObjectQL instead of third-party ORMs\n */\n dataEngine?: IDataEngine;\n}\n\n/**\n * Authentication Manager\n * \n * Wraps better-auth and provides authentication services for ObjectStack.\n * Supports multiple authentication methods:\n * - Email/password\n * - OAuth providers (Google, GitHub, etc.)\n * - Magic links\n * - Two-factor authentication\n * - Passkeys\n * - Organization/teams\n */\nexport class AuthManager {\n private auth: Auth<any> | null = null;\n private config: AuthManagerOptions;\n\n constructor(config: AuthManagerOptions) {\n this.config = config;\n \n // Use provided auth instance\n if (config.authInstance) {\n this.auth = config.authInstance;\n }\n // Don't create auth instance automatically to avoid database initialization errors\n // It will be created lazily when needed\n }\n\n /**\n * Get or create the better-auth instance (lazy initialization)\n */\n private getOrCreateAuth(): Auth<any> {\n if (!this.auth) {\n this.auth = this.createAuthInstance();\n }\n return this.auth;\n }\n\n /**\n * Create a better-auth instance from configuration\n */\n private createAuthInstance(): Auth<any> {\n const betterAuthConfig: BetterAuthOptions = {\n // Base configuration\n secret: this.config.secret || this.generateSecret(),\n baseURL: this.config.baseUrl || 'http://localhost:3000',\n \n // Database adapter configuration\n // For now, we configure a basic setup that will be enhanced\n // when database URL is provided and drizzle-orm is available\n database: this.createDatabaseConfig(),\n \n // Email configuration\n emailAndPassword: {\n enabled: true,\n },\n \n // Session configuration\n session: {\n expiresIn: this.config.session?.expiresIn || 60 * 60 * 24 * 7, // 7 days default\n updateAge: this.config.session?.updateAge || 60 * 60 * 24, // 1 day default\n },\n };\n\n return betterAuth(betterAuthConfig);\n }\n\n /**\n * Create database configuration using ObjectQL adapter\n */\n private createDatabaseConfig(): any {\n // Use ObjectQL adapter if dataEngine is provided\n if (this.config.dataEngine) {\n return createObjectQLAdapter(this.config.dataEngine);\n }\n \n // Fallback warning if no dataEngine is provided\n console.warn(\n '⚠️ WARNING: No dataEngine provided to AuthManager! ' +\n 'Using in-memory storage. This is NOT suitable for production. ' +\n 'Please provide a dataEngine instance (e.g., ObjectQL) in AuthManagerOptions.'\n );\n \n // Return a minimal in-memory configuration as fallback\n // This allows the system to work in development/testing without a real database\n return undefined; // better-auth will use its default in-memory adapter\n }\n\n /**\n * Generate a secure secret if not provided\n */\n private generateSecret(): string {\n const envSecret = process.env.AUTH_SECRET;\n \n if (!envSecret) {\n // In production, a secret MUST be provided\n // For development/testing, we'll use a fallback but warn about it\n const fallbackSecret = 'dev-secret-' + Date.now();\n \n console.warn(\n '⚠️ WARNING: No AUTH_SECRET environment variable set! ' +\n 'Using a temporary development secret. ' +\n 'This is NOT secure for production use. ' +\n 'Please set AUTH_SECRET in your environment variables.'\n );\n \n return fallbackSecret;\n }\n \n return envSecret;\n }\n\n /**\n * Get the underlying better-auth instance\n * Useful for advanced use cases\n */\n getAuthInstance(): Auth<any> {\n return this.getOrCreateAuth();\n }\n\n /**\n * Handle an authentication request\n * Forwards the request directly to better-auth's universal handler\n * \n * @param request - Web standard Request object\n * @returns Web standard Response object\n */\n async handleRequest(request: Request): Promise<Response> {\n const auth = this.getOrCreateAuth();\n return await auth.handler(request);\n }\n\n /**\n * Get the better-auth API for programmatic access\n * Use this for server-side operations (e.g., creating users, checking sessions)\n */\n get api() {\n return this.getOrCreateAuth().api;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { IDataEngine } from '@objectstack/core';\nimport type { CleanedWhere } from 'better-auth/adapters';\n\n/**\n * ObjectQL Adapter for better-auth\n * \n * Bridges better-auth's database adapter interface with ObjectQL's IDataEngine.\n * This allows better-auth to use ObjectQL for data persistence instead of\n * third-party ORMs like drizzle-orm.\n * \n * Uses better-auth's native naming conventions (camelCase) for seamless migration.\n * \n * @param dataEngine - ObjectQL data engine instance\n * @returns better-auth CustomAdapter\n */\nexport function createObjectQLAdapter(dataEngine: IDataEngine) {\n /**\n * Convert better-auth where clause to ObjectQL query format\n */\n function convertWhere(where: CleanedWhere[]): Record<string, any> {\n const filter: Record<string, any> = {};\n \n for (const condition of where) {\n // Use field names as-is (no conversion needed)\n const fieldName = condition.field;\n \n if (condition.operator === 'eq') {\n filter[fieldName] = condition.value;\n } else if (condition.operator === 'ne') {\n filter[fieldName] = { $ne: condition.value };\n } else if (condition.operator === 'in') {\n filter[fieldName] = { $in: condition.value };\n } else if (condition.operator === 'gt') {\n filter[fieldName] = { $gt: condition.value };\n } else if (condition.operator === 'gte') {\n filter[fieldName] = { $gte: condition.value };\n } else if (condition.operator === 'lt') {\n filter[fieldName] = { $lt: condition.value };\n } else if (condition.operator === 'lte') {\n filter[fieldName] = { $lte: condition.value };\n } else if (condition.operator === 'contains') {\n filter[fieldName] = { $regex: condition.value };\n }\n }\n \n return filter;\n }\n\n return {\n create: async <T extends Record<string, any>>({ model, data, select: _select }: { model: string; data: T; select?: string[] }): Promise<T> => {\n // Use model name as-is (no conversion needed)\n const objectName = model;\n \n // Note: select parameter is currently not supported by ObjectQL's insert operation\n // The full record is always returned after insertion\n const result = await dataEngine.insert(objectName, data);\n return result as T;\n },\n \n findOne: async <T>({ model, where, select, join: _join }: { model: string; where: CleanedWhere[]; select?: string[]; join?: any }): Promise<T | null> => {\n const objectName = model;\n const filter = convertWhere(where);\n \n // Note: join parameter is not currently supported by ObjectQL's findOne operation\n // Joins/populate functionality is planned for future ObjectQL releases\n // For now, related data must be fetched separately\n \n const result = await dataEngine.findOne(objectName, {\n filter,\n select,\n });\n \n return result ? result as T : null;\n },\n \n findMany: async <T>({ model, where, limit, offset, sortBy, join: _join }: { model: string; where?: CleanedWhere[]; limit: number; offset?: number; sortBy?: { field: string; direction: 'asc' | 'desc' }; join?: any }): Promise<T[]> => {\n const objectName = model;\n const filter = where ? convertWhere(where) : {};\n \n // Note: join parameter is not currently supported by ObjectQL's find operation\n // Joins/populate functionality is planned for future ObjectQL releases\n \n const sort = sortBy ? [{\n field: sortBy.field,\n order: sortBy.direction as 'asc' | 'desc',\n }] : undefined;\n \n const results = await dataEngine.find(objectName, {\n filter,\n limit: limit || 100,\n skip: offset,\n sort,\n });\n \n return results as T[];\n },\n \n count: async ({ model, where }: { model: string; where?: CleanedWhere[] }): Promise<number> => {\n const objectName = model;\n const filter = where ? convertWhere(where) : {};\n \n return await dataEngine.count(objectName, { filter });\n },\n \n update: async <T>({ model, where, update }: { model: string; where: CleanedWhere[]; update: Record<string, any> }): Promise<T | null> => {\n const objectName = model;\n const filter = convertWhere(where);\n \n // Find the record first to get its ID\n const record = await dataEngine.findOne(objectName, { filter });\n if (!record) {\n return null;\n }\n \n const result = await dataEngine.update(objectName, {\n ...update,\n id: record.id,\n });\n \n return result ? result as T : null;\n },\n \n updateMany: async ({ model, where, update }: { model: string; where: CleanedWhere[]; update: Record<string, any> }): Promise<number> => {\n const objectName = model;\n const filter = convertWhere(where);\n \n // Note: Sequential updates are used here because ObjectQL's IDataEngine interface\n // requires an ID for updates. A future optimization could use a bulk update\n // operation if ObjectQL adds support for filter-based updates without IDs.\n \n // Find all matching records\n const records = await dataEngine.find(objectName, { filter });\n \n // Update each record\n for (const record of records) {\n await dataEngine.update(objectName, {\n ...update,\n id: record.id,\n });\n }\n \n return records.length;\n },\n \n delete: async ({ model, where }: { model: string; where: CleanedWhere[] }): Promise<void> => {\n const objectName = model;\n const filter = convertWhere(where);\n \n // Note: We need to find the record first to get its ID because ObjectQL's\n // delete operation requires an ID. Direct filter-based delete would be more\n // efficient if supported by ObjectQL in the future.\n const record = await dataEngine.findOne(objectName, { filter });\n if (!record) {\n return;\n }\n \n await dataEngine.delete(objectName, { filter: { id: record.id } });\n },\n \n deleteMany: async ({ model, where }: { model: string; where: CleanedWhere[] }): Promise<number> => {\n const objectName = model;\n const filter = convertWhere(where);\n \n // Note: Sequential deletes are used here because ObjectQL's delete operation\n // requires an ID in the filter. A future optimization could use a single\n // delete call with the original filter if ObjectQL supports it.\n \n // Find all matching records\n const records = await dataEngine.find(objectName, { filter });\n \n // Delete each record\n for (const record of records) {\n await dataEngine.delete(objectName, { filter: { id: record.id } });\n }\n \n return records.length;\n },\n };\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { Plugin, PluginContext, IHttpServer } from '@objectstack/core';\nimport { AuthConfig } from '@objectstack/spec/system';\nimport { AuthManager } from './auth-manager.js';\n\n/**\n * Auth Plugin Options\n * Extends AuthConfig from spec with additional runtime options\n */\nexport interface AuthPluginOptions extends Partial<AuthConfig> {\n /**\n * Whether to automatically register auth routes\n * @default true\n */\n registerRoutes?: boolean;\n \n /**\n * Base path for auth routes\n * @default '/api/v1/auth'\n */\n basePath?: string;\n}\n\n/**\n * Authentication Plugin\n * \n * Provides authentication and identity services for ObjectStack applications.\n * \n * Features:\n * - Session management\n * - User registration/login\n * - OAuth providers (Google, GitHub, etc.)\n * - Organization/team support\n * - 2FA, passkeys, magic links\n * \n * This plugin registers:\n * - `auth` service (auth manager instance)\n * - HTTP routes for authentication endpoints\n * \n * Integrates with better-auth library to provide comprehensive\n * authentication capabilities including email/password, OAuth, 2FA,\n * magic links, passkeys, and organization support.\n */\nexport class AuthPlugin implements Plugin {\n name = 'com.objectstack.auth';\n type = 'standard';\n version = '1.0.0';\n dependencies = ['com.objectstack.server.hono']; // Requires HTTP server\n \n private options: AuthPluginOptions;\n private authManager: AuthManager | null = null;\n\n constructor(options: AuthPluginOptions = {}) {\n this.options = {\n registerRoutes: true,\n basePath: '/api/v1/auth',\n ...options\n };\n }\n\n async init(ctx: PluginContext): Promise<void> {\n ctx.logger.info('Initializing Auth Plugin...');\n\n // Validate required configuration\n if (!this.options.secret) {\n throw new Error('AuthPlugin: secret is required');\n }\n\n // Get data engine service for database operations\n const dataEngine = ctx.getService<any>('data');\n if (!dataEngine) {\n ctx.logger.warn('No data engine service found - auth will use in-memory storage');\n }\n\n // Initialize auth manager with data engine\n this.authManager = new AuthManager({\n ...this.options,\n dataEngine,\n });\n\n // Register auth service\n ctx.registerService('auth', this.authManager);\n \n ctx.logger.info('Auth Plugin initialized successfully');\n }\n\n async start(ctx: PluginContext): Promise<void> {\n ctx.logger.info('Starting Auth Plugin...');\n\n if (!this.authManager) {\n throw new Error('Auth manager not initialized');\n }\n\n // Register HTTP routes if enabled\n if (this.options.registerRoutes) {\n try {\n const httpServer = ctx.getService<IHttpServer>('http-server');\n this.registerAuthRoutes(httpServer, ctx);\n ctx.logger.info(`Auth routes registered at ${this.options.basePath}`);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n ctx.logger.error('Failed to register auth routes:', err);\n throw err;\n }\n }\n\n ctx.logger.info('Auth Plugin started successfully');\n }\n\n async destroy(): Promise<void> {\n // Cleanup if needed\n this.authManager = null;\n }\n\n /**\n * Register authentication routes with HTTP server\n * \n * Uses better-auth's universal handler for all authentication requests.\n * This forwards all requests under basePath to better-auth, which handles:\n * - Email/password authentication\n * - OAuth providers (Google, GitHub, etc.)\n * - Session management\n * - Password reset\n * - Email verification\n * - 2FA, passkeys, magic links (if enabled)\n */\n private registerAuthRoutes(httpServer: IHttpServer, ctx: PluginContext): void {\n if (!this.authManager) return;\n\n const basePath = this.options.basePath || '/api/v1/auth';\n\n // Get raw Hono app to use native wildcard routing\n // Type assertion is safe here because we explicitly require Hono server as a dependency\n if (!('getRawApp' in httpServer) || typeof (httpServer as any).getRawApp !== 'function') {\n ctx.logger.error('HTTP server does not support getRawApp() - wildcard routing requires Hono server');\n throw new Error(\n 'AuthPlugin requires HonoServerPlugin for wildcard routing support. ' +\n 'Please ensure HonoServerPlugin is loaded before AuthPlugin.'\n );\n }\n\n const rawApp = (httpServer as any).getRawApp();\n\n // Register wildcard route to forward all auth requests to better-auth\n // Better-auth expects requests at its baseURL, so we need to preserve the full path\n rawApp.all(`${basePath}/*`, async (c: any) => {\n try {\n // Get the Web standard Request from Hono context\n const request = c.req.raw as Request;\n \n // Create a new Request with the path rewritten to match better-auth's expectations\n // Better-auth expects paths like /sign-in/email, /sign-up/email, etc.\n // We need to strip our basePath prefix\n const url = new URL(request.url);\n const authPath = url.pathname.replace(basePath, '');\n const rewrittenUrl = new URL(authPath || '/', url.origin);\n rewrittenUrl.search = url.search; // Preserve query params\n \n const rewrittenRequest = new Request(rewrittenUrl, {\n method: request.method,\n headers: request.headers,\n body: request.body,\n duplex: 'half' as any, // Required for Request with body\n });\n\n // Forward to better-auth handler\n const response = await this.authManager!.handleRequest(rewrittenRequest);\n \n return response;\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n ctx.logger.error('Auth request error:', err);\n \n // Return error response\n return new Response(\n JSON.stringify({\n success: false,\n error: err.message,\n }),\n {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n }\n );\n }\n });\n\n ctx.logger.info(`Auth routes registered: All requests under ${basePath}/* forwarded to better-auth`);\n }\n}\n\n\n\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * Auth User Object\n * \n * Uses better-auth's native schema for seamless migration:\n * - id: string\n * - createdAt: Date\n * - updatedAt: Date\n * - email: string (unique, lowercase)\n * - emailVerified: boolean\n * - name: string\n * - image: string | null\n */\nexport const AuthUser = ObjectSchema.create({\n name: 'user',\n label: 'User',\n pluralLabel: 'Users',\n icon: 'user',\n description: 'User accounts for authentication',\n titleFormat: '{name} ({email})',\n compactLayout: ['name', 'email', 'emailVerified'],\n \n fields: {\n // ID is auto-generated by ObjectQL\n id: Field.text({\n label: 'User ID',\n required: true,\n readonly: true,\n }),\n \n createdAt: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updatedAt: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n email: Field.email({\n label: 'Email',\n required: true,\n searchable: true,\n }),\n \n emailVerified: Field.boolean({\n label: 'Email Verified',\n defaultValue: false,\n }),\n \n name: Field.text({\n label: 'Name',\n required: true,\n searchable: true,\n maxLength: 255,\n }),\n \n image: Field.url({\n label: 'Profile Image',\n required: false,\n }),\n },\n \n // Database indexes for performance\n indexes: [\n { fields: ['email'], unique: true },\n { fields: ['createdAt'], unique: false },\n ],\n \n // Enable features\n enable: {\n trackHistory: true,\n searchable: true,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: true,\n mru: true,\n },\n \n // Validation Rules\n validations: [\n {\n name: 'email_unique',\n type: 'unique',\n severity: 'error',\n message: 'Email must be unique',\n fields: ['email'],\n caseSensitive: false,\n },\n ],\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * Auth Session Object\n * \n * Uses better-auth's native schema for seamless migration:\n * - id: string\n * - createdAt: Date\n * - updatedAt: Date\n * - userId: string\n * - expiresAt: Date\n * - token: string\n * - ipAddress: string | null\n * - userAgent: string | null\n */\nexport const AuthSession = ObjectSchema.create({\n name: 'session',\n label: 'Session',\n pluralLabel: 'Sessions',\n icon: 'key',\n description: 'Active user sessions',\n titleFormat: 'Session {token}',\n compactLayout: ['userId', 'expiresAt', 'ipAddress'],\n \n fields: {\n id: Field.text({\n label: 'Session ID',\n required: true,\n readonly: true,\n }),\n \n createdAt: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updatedAt: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n userId: Field.text({\n label: 'User ID',\n required: true,\n }),\n \n expiresAt: Field.datetime({\n label: 'Expires At',\n required: true,\n }),\n \n token: Field.text({\n label: 'Session Token',\n required: true,\n }),\n \n ipAddress: Field.text({\n label: 'IP Address',\n required: false,\n maxLength: 45, // Support IPv6\n }),\n \n userAgent: Field.textarea({\n label: 'User Agent',\n required: false,\n }),\n },\n \n // Database indexes for performance\n indexes: [\n { fields: ['token'], unique: true },\n { fields: ['userId'], unique: false },\n { fields: ['expiresAt'], unique: false },\n ],\n \n // Enable features\n enable: {\n trackHistory: false, // Sessions don't need history tracking\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'delete'], // No update for sessions\n trash: false, // Sessions should be hard deleted\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * Auth Account Object\n * \n * Uses better-auth's native schema for seamless migration:\n * - id: string\n * - createdAt: Date\n * - updatedAt: Date\n * - providerId: string (e.g., 'google', 'github')\n * - accountId: string (provider's user ID)\n * - userId: string (link to user table)\n * - accessToken: string | null\n * - refreshToken: string | null\n * - idToken: string | null\n * - accessTokenExpiresAt: Date | null\n * - refreshTokenExpiresAt: Date | null\n * - scope: string | null\n * - password: string | null (for email/password provider)\n */\nexport const AuthAccount = ObjectSchema.create({\n name: 'account',\n label: 'Account',\n pluralLabel: 'Accounts',\n icon: 'link',\n description: 'OAuth and authentication provider accounts',\n titleFormat: '{providerId} - {accountId}',\n compactLayout: ['providerId', 'userId', 'accountId'],\n \n fields: {\n id: Field.text({\n label: 'Account ID',\n required: true,\n readonly: true,\n }),\n \n createdAt: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updatedAt: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n providerId: Field.text({\n label: 'Provider ID',\n required: true,\n description: 'OAuth provider identifier (google, github, etc.)',\n }),\n \n accountId: Field.text({\n label: 'Provider Account ID',\n required: true,\n description: \"User's ID in the provider's system\",\n }),\n \n userId: Field.text({\n label: 'User ID',\n required: true,\n description: 'Link to user table',\n }),\n \n accessToken: Field.textarea({\n label: 'Access Token',\n required: false,\n }),\n \n refreshToken: Field.textarea({\n label: 'Refresh Token',\n required: false,\n }),\n \n idToken: Field.textarea({\n label: 'ID Token',\n required: false,\n }),\n \n accessTokenExpiresAt: Field.datetime({\n label: 'Access Token Expires At',\n required: false,\n }),\n \n refreshTokenExpiresAt: Field.datetime({\n label: 'Refresh Token Expires At',\n required: false,\n }),\n \n scope: Field.text({\n label: 'OAuth Scope',\n required: false,\n }),\n \n password: Field.text({\n label: 'Password Hash',\n required: false,\n description: 'Hashed password for email/password provider',\n }),\n },\n \n // Database indexes for performance\n indexes: [\n { fields: ['userId'], unique: false },\n { fields: ['providerId', 'accountId'], unique: true },\n ],\n \n // Enable features\n enable: {\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: true,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * Auth Verification Object\n * \n * Uses better-auth's native schema for seamless migration:\n * - id: string\n * - createdAt: Date\n * - updatedAt: Date\n * - value: string (verification token/code)\n * - expiresAt: Date\n * - identifier: string (email or phone number)\n */\nexport const AuthVerification = ObjectSchema.create({\n name: 'verification',\n label: 'Verification',\n pluralLabel: 'Verifications',\n icon: 'shield-check',\n description: 'Email and phone verification tokens',\n titleFormat: 'Verification for {identifier}',\n compactLayout: ['identifier', 'expiresAt', 'createdAt'],\n \n fields: {\n id: Field.text({\n label: 'Verification ID',\n required: true,\n readonly: true,\n }),\n \n createdAt: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updatedAt: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n value: Field.text({\n label: 'Verification Token',\n required: true,\n description: 'Token or code for verification',\n }),\n \n expiresAt: Field.datetime({\n label: 'Expires At',\n required: true,\n }),\n \n identifier: Field.text({\n label: 'Identifier',\n required: true,\n description: 'Email address or phone number',\n }),\n },\n \n // Database indexes for performance\n indexes: [\n { fields: ['value'], unique: true },\n { fields: ['identifier'], unique: false },\n { fields: ['expiresAt'], unique: false },\n ],\n \n // Enable features\n enable: {\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'create', 'delete'], // No list or update\n trash: false, // Hard delete expired tokens\n mru: false,\n },\n});\n"],"mappings":"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","names":["ObjectSchema","Field","ObjectSchema","Field","ObjectSchema","Field"]}
|
|
1
|
+
{"version":3,"sources":["../src/auth-manager.ts","../src/objectql-adapter.ts","../src/auth-plugin.ts","../src/objects/auth-user.object.ts","../src/objects/auth-session.object.ts","../src/objects/auth-account.object.ts","../src/objects/auth-verification.object.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { betterAuth } from 'better-auth';\nimport type { Auth, BetterAuthOptions } from 'better-auth';\nimport type { AuthConfig } from '@objectstack/spec/system';\nimport type { IDataEngine } from '@objectstack/core';\nimport { createObjectQLAdapter } from './objectql-adapter.js';\n\n/**\n * Extended options for AuthManager\n */\nexport interface AuthManagerOptions extends Partial<AuthConfig> {\n /**\n * Better-Auth instance (for advanced use cases)\n * If not provided, one will be created from config\n */\n authInstance?: Auth<any>;\n \n /**\n * ObjectQL Data Engine instance\n * Required for database operations using ObjectQL instead of third-party ORMs\n */\n dataEngine?: IDataEngine;\n}\n\n/**\n * Authentication Manager\n * \n * Wraps better-auth and provides authentication services for ObjectStack.\n * Supports multiple authentication methods:\n * - Email/password\n * - OAuth providers (Google, GitHub, etc.)\n * - Magic links\n * - Two-factor authentication\n * - Passkeys\n * - Organization/teams\n */\nexport class AuthManager {\n private auth: Auth<any> | null = null;\n private config: AuthManagerOptions;\n\n constructor(config: AuthManagerOptions) {\n this.config = config;\n \n // Use provided auth instance\n if (config.authInstance) {\n this.auth = config.authInstance;\n }\n // Don't create auth instance automatically to avoid database initialization errors\n // It will be created lazily when needed\n }\n\n /**\n * Get or create the better-auth instance (lazy initialization)\n */\n private getOrCreateAuth(): Auth<any> {\n if (!this.auth) {\n this.auth = this.createAuthInstance();\n }\n return this.auth;\n }\n\n /**\n * Create a better-auth instance from configuration\n */\n private createAuthInstance(): Auth<any> {\n const betterAuthConfig: BetterAuthOptions = {\n // Base configuration\n secret: this.config.secret || this.generateSecret(),\n baseURL: this.config.baseUrl || 'http://localhost:3000',\n \n // Database adapter configuration\n // For now, we configure a basic setup that will be enhanced\n // when database URL is provided and drizzle-orm is available\n database: this.createDatabaseConfig(),\n \n // Email configuration\n emailAndPassword: {\n enabled: true,\n },\n \n // Session configuration\n session: {\n expiresIn: this.config.session?.expiresIn || 60 * 60 * 24 * 7, // 7 days default\n updateAge: this.config.session?.updateAge || 60 * 60 * 24, // 1 day default\n },\n };\n\n return betterAuth(betterAuthConfig);\n }\n\n /**\n * Create database configuration using ObjectQL adapter\n */\n private createDatabaseConfig(): any {\n // Use ObjectQL adapter if dataEngine is provided\n if (this.config.dataEngine) {\n return createObjectQLAdapter(this.config.dataEngine);\n }\n \n // Fallback warning if no dataEngine is provided\n console.warn(\n '⚠️ WARNING: No dataEngine provided to AuthManager! ' +\n 'Using in-memory storage. This is NOT suitable for production. ' +\n 'Please provide a dataEngine instance (e.g., ObjectQL) in AuthManagerOptions.'\n );\n \n // Return a minimal in-memory configuration as fallback\n // This allows the system to work in development/testing without a real database\n return undefined; // better-auth will use its default in-memory adapter\n }\n\n /**\n * Generate a secure secret if not provided\n */\n private generateSecret(): string {\n const envSecret = process.env.AUTH_SECRET;\n \n if (!envSecret) {\n // In production, a secret MUST be provided\n // For development/testing, we'll use a fallback but warn about it\n const fallbackSecret = 'dev-secret-' + Date.now();\n \n console.warn(\n '⚠️ WARNING: No AUTH_SECRET environment variable set! ' +\n 'Using a temporary development secret. ' +\n 'This is NOT secure for production use. ' +\n 'Please set AUTH_SECRET in your environment variables.'\n );\n \n return fallbackSecret;\n }\n \n return envSecret;\n }\n\n /**\n * Get the underlying better-auth instance\n * Useful for advanced use cases\n */\n getAuthInstance(): Auth<any> {\n return this.getOrCreateAuth();\n }\n\n /**\n * Handle an authentication request\n * Forwards the request directly to better-auth's universal handler\n * \n * @param request - Web standard Request object\n * @returns Web standard Response object\n */\n async handleRequest(request: Request): Promise<Response> {\n const auth = this.getOrCreateAuth();\n return await auth.handler(request);\n }\n\n /**\n * Get the better-auth API for programmatic access\n * Use this for server-side operations (e.g., creating users, checking sessions)\n */\n get api() {\n return this.getOrCreateAuth().api;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { IDataEngine } from '@objectstack/core';\nimport type { CleanedWhere } from 'better-auth/adapters';\n\n/**\n * ObjectQL Adapter for better-auth\n * \n * Bridges better-auth's database adapter interface with ObjectQL's IDataEngine.\n * This allows better-auth to use ObjectQL for data persistence instead of\n * third-party ORMs like drizzle-orm.\n * \n * Uses better-auth's native naming conventions (camelCase) for seamless migration.\n * \n * @param dataEngine - ObjectQL data engine instance\n * @returns better-auth CustomAdapter\n */\nexport function createObjectQLAdapter(dataEngine: IDataEngine) {\n /**\n * Convert better-auth where clause to ObjectQL query format\n */\n function convertWhere(where: CleanedWhere[]): Record<string, any> {\n const filter: Record<string, any> = {};\n \n for (const condition of where) {\n // Use field names as-is (no conversion needed)\n const fieldName = condition.field;\n \n if (condition.operator === 'eq') {\n filter[fieldName] = condition.value;\n } else if (condition.operator === 'ne') {\n filter[fieldName] = { $ne: condition.value };\n } else if (condition.operator === 'in') {\n filter[fieldName] = { $in: condition.value };\n } else if (condition.operator === 'gt') {\n filter[fieldName] = { $gt: condition.value };\n } else if (condition.operator === 'gte') {\n filter[fieldName] = { $gte: condition.value };\n } else if (condition.operator === 'lt') {\n filter[fieldName] = { $lt: condition.value };\n } else if (condition.operator === 'lte') {\n filter[fieldName] = { $lte: condition.value };\n } else if (condition.operator === 'contains') {\n filter[fieldName] = { $regex: condition.value };\n }\n }\n \n return filter;\n }\n\n return {\n create: async <T extends Record<string, any>>({ model, data, select: _select }: { model: string; data: T; select?: string[] }): Promise<T> => {\n // Use model name as-is (no conversion needed)\n const objectName = model;\n \n // Note: select parameter is currently not supported by ObjectQL's insert operation\n // The full record is always returned after insertion\n const result = await dataEngine.insert(objectName, data);\n return result as T;\n },\n \n findOne: async <T>({ model, where, select, join: _join }: { model: string; where: CleanedWhere[]; select?: string[]; join?: any }): Promise<T | null> => {\n const objectName = model;\n const filter = convertWhere(where);\n \n // Note: join parameter is not currently supported by ObjectQL's findOne operation\n // Joins/populate functionality is planned for future ObjectQL releases\n // For now, related data must be fetched separately\n \n const result = await dataEngine.findOne(objectName, {\n filter,\n select,\n });\n \n return result ? result as T : null;\n },\n \n findMany: async <T>({ model, where, limit, offset, sortBy, join: _join }: { model: string; where?: CleanedWhere[]; limit: number; offset?: number; sortBy?: { field: string; direction: 'asc' | 'desc' }; join?: any }): Promise<T[]> => {\n const objectName = model;\n const filter = where ? convertWhere(where) : {};\n \n // Note: join parameter is not currently supported by ObjectQL's find operation\n // Joins/populate functionality is planned for future ObjectQL releases\n \n const sort = sortBy ? [{\n field: sortBy.field,\n order: sortBy.direction as 'asc' | 'desc',\n }] : undefined;\n \n const results = await dataEngine.find(objectName, {\n filter,\n limit: limit || 100,\n skip: offset,\n sort,\n });\n \n return results as T[];\n },\n \n count: async ({ model, where }: { model: string; where?: CleanedWhere[] }): Promise<number> => {\n const objectName = model;\n const filter = where ? convertWhere(where) : {};\n \n return await dataEngine.count(objectName, { filter });\n },\n \n update: async <T>({ model, where, update }: { model: string; where: CleanedWhere[]; update: Record<string, any> }): Promise<T | null> => {\n const objectName = model;\n const filter = convertWhere(where);\n \n // Find the record first to get its ID\n const record = await dataEngine.findOne(objectName, { filter });\n if (!record) {\n return null;\n }\n \n const result = await dataEngine.update(objectName, {\n ...update,\n id: record.id,\n });\n \n return result ? result as T : null;\n },\n \n updateMany: async ({ model, where, update }: { model: string; where: CleanedWhere[]; update: Record<string, any> }): Promise<number> => {\n const objectName = model;\n const filter = convertWhere(where);\n \n // Note: Sequential updates are used here because ObjectQL's IDataEngine interface\n // requires an ID for updates. A future optimization could use a bulk update\n // operation if ObjectQL adds support for filter-based updates without IDs.\n \n // Find all matching records\n const records = await dataEngine.find(objectName, { filter });\n \n // Update each record\n for (const record of records) {\n await dataEngine.update(objectName, {\n ...update,\n id: record.id,\n });\n }\n \n return records.length;\n },\n \n delete: async ({ model, where }: { model: string; where: CleanedWhere[] }): Promise<void> => {\n const objectName = model;\n const filter = convertWhere(where);\n \n // Note: We need to find the record first to get its ID because ObjectQL's\n // delete operation requires an ID. Direct filter-based delete would be more\n // efficient if supported by ObjectQL in the future.\n const record = await dataEngine.findOne(objectName, { filter });\n if (!record) {\n return;\n }\n \n await dataEngine.delete(objectName, { filter: { id: record.id } });\n },\n \n deleteMany: async ({ model, where }: { model: string; where: CleanedWhere[] }): Promise<number> => {\n const objectName = model;\n const filter = convertWhere(where);\n \n // Note: Sequential deletes are used here because ObjectQL's delete operation\n // requires an ID in the filter. A future optimization could use a single\n // delete call with the original filter if ObjectQL supports it.\n \n // Find all matching records\n const records = await dataEngine.find(objectName, { filter });\n \n // Delete each record\n for (const record of records) {\n await dataEngine.delete(objectName, { filter: { id: record.id } });\n }\n \n return records.length;\n },\n };\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { Plugin, PluginContext, IHttpServer } from '@objectstack/core';\nimport { AuthConfig } from '@objectstack/spec/system';\nimport { AuthManager } from './auth-manager.js';\n\n/**\n * Auth Plugin Options\n * Extends AuthConfig from spec with additional runtime options\n */\nexport interface AuthPluginOptions extends Partial<AuthConfig> {\n /**\n * Whether to automatically register auth routes\n * @default true\n */\n registerRoutes?: boolean;\n \n /**\n * Base path for auth routes\n * @default '/api/v1/auth'\n */\n basePath?: string;\n}\n\n/**\n * Authentication Plugin\n * \n * Provides authentication and identity services for ObjectStack applications.\n * \n * Features:\n * - Session management\n * - User registration/login\n * - OAuth providers (Google, GitHub, etc.)\n * - Organization/team support\n * - 2FA, passkeys, magic links\n * \n * This plugin registers:\n * - `auth` service (auth manager instance)\n * - HTTP routes for authentication endpoints\n * \n * Integrates with better-auth library to provide comprehensive\n * authentication capabilities including email/password, OAuth, 2FA,\n * magic links, passkeys, and organization support.\n */\nexport class AuthPlugin implements Plugin {\n name = 'com.objectstack.auth';\n type = 'standard';\n version = '1.0.0';\n dependencies = ['com.objectstack.server.hono']; // Requires HTTP server\n \n private options: AuthPluginOptions;\n private authManager: AuthManager | null = null;\n\n constructor(options: AuthPluginOptions = {}) {\n this.options = {\n registerRoutes: true,\n basePath: '/api/v1/auth',\n ...options\n };\n }\n\n async init(ctx: PluginContext): Promise<void> {\n ctx.logger.info('Initializing Auth Plugin...');\n\n // Validate required configuration\n if (!this.options.secret) {\n throw new Error('AuthPlugin: secret is required');\n }\n\n // Get data engine service for database operations\n const dataEngine = ctx.getService<any>('data');\n if (!dataEngine) {\n ctx.logger.warn('No data engine service found - auth will use in-memory storage');\n }\n\n // Initialize auth manager with data engine\n this.authManager = new AuthManager({\n ...this.options,\n dataEngine,\n });\n\n // Register auth service\n ctx.registerService('auth', this.authManager);\n \n ctx.logger.info('Auth Plugin initialized successfully');\n }\n\n async start(ctx: PluginContext): Promise<void> {\n ctx.logger.info('Starting Auth Plugin...');\n\n if (!this.authManager) {\n throw new Error('Auth manager not initialized');\n }\n\n // Register HTTP routes if enabled\n if (this.options.registerRoutes) {\n try {\n const httpServer = ctx.getService<IHttpServer>('http-server');\n this.registerAuthRoutes(httpServer, ctx);\n ctx.logger.info(`Auth routes registered at ${this.options.basePath}`);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n ctx.logger.error('Failed to register auth routes:', err);\n throw err;\n }\n }\n\n // Register auth middleware on ObjectQL engine (if available)\n try {\n const ql = ctx.getService<any>('objectql');\n if (ql && typeof ql.registerMiddleware === 'function') {\n ql.registerMiddleware(async (opCtx: any, next: () => Promise<void>) => {\n // If context already has userId or isSystem, skip auth resolution\n if (opCtx.context?.userId || opCtx.context?.isSystem) {\n return next();\n }\n // Future: resolve session from AsyncLocalStorage or request context\n await next();\n });\n ctx.logger.info('Auth middleware registered on ObjectQL engine');\n }\n } catch (_e) {\n ctx.logger.debug('ObjectQL engine not available, skipping auth middleware registration');\n }\n\n ctx.logger.info('Auth Plugin started successfully');\n }\n\n async destroy(): Promise<void> {\n // Cleanup if needed\n this.authManager = null;\n }\n\n /**\n * Register authentication routes with HTTP server\n * \n * Uses better-auth's universal handler for all authentication requests.\n * This forwards all requests under basePath to better-auth, which handles:\n * - Email/password authentication\n * - OAuth providers (Google, GitHub, etc.)\n * - Session management\n * - Password reset\n * - Email verification\n * - 2FA, passkeys, magic links (if enabled)\n */\n private registerAuthRoutes(httpServer: IHttpServer, ctx: PluginContext): void {\n if (!this.authManager) return;\n\n const basePath = this.options.basePath || '/api/v1/auth';\n\n // Get raw Hono app to use native wildcard routing\n // Type assertion is safe here because we explicitly require Hono server as a dependency\n if (!('getRawApp' in httpServer) || typeof (httpServer as any).getRawApp !== 'function') {\n ctx.logger.error('HTTP server does not support getRawApp() - wildcard routing requires Hono server');\n throw new Error(\n 'AuthPlugin requires HonoServerPlugin for wildcard routing support. ' +\n 'Please ensure HonoServerPlugin is loaded before AuthPlugin.'\n );\n }\n\n const rawApp = (httpServer as any).getRawApp();\n\n // Register wildcard route to forward all auth requests to better-auth\n // Better-auth expects requests at its baseURL, so we need to preserve the full path\n rawApp.all(`${basePath}/*`, async (c: any) => {\n try {\n // Get the Web standard Request from Hono context\n const request = c.req.raw as Request;\n \n // Create a new Request with the path rewritten to match better-auth's expectations\n // Better-auth expects paths like /sign-in/email, /sign-up/email, etc.\n // We need to strip our basePath prefix\n const url = new URL(request.url);\n const authPath = url.pathname.replace(basePath, '');\n const rewrittenUrl = new URL(authPath || '/', url.origin);\n rewrittenUrl.search = url.search; // Preserve query params\n \n const rewrittenRequest = new Request(rewrittenUrl, {\n method: request.method,\n headers: request.headers,\n body: request.body,\n duplex: 'half' as any, // Required for Request with body\n });\n\n // Forward to better-auth handler\n const response = await this.authManager!.handleRequest(rewrittenRequest);\n \n return response;\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n ctx.logger.error('Auth request error:', err);\n \n // Return error response\n return new Response(\n JSON.stringify({\n success: false,\n error: err.message,\n }),\n {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n }\n );\n }\n });\n\n ctx.logger.info(`Auth routes registered: All requests under ${basePath}/* forwarded to better-auth`);\n }\n}\n\n\n\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * Auth User Object\n * \n * Uses better-auth's native schema for seamless migration:\n * - id: string\n * - createdAt: Date\n * - updatedAt: Date\n * - email: string (unique, lowercase)\n * - emailVerified: boolean\n * - name: string\n * - image: string | null\n */\nexport const AuthUser = ObjectSchema.create({\n name: 'user',\n label: 'User',\n pluralLabel: 'Users',\n icon: 'user',\n description: 'User accounts for authentication',\n titleFormat: '{name} ({email})',\n compactLayout: ['name', 'email', 'emailVerified'],\n \n fields: {\n // ID is auto-generated by ObjectQL\n id: Field.text({\n label: 'User ID',\n required: true,\n readonly: true,\n }),\n \n createdAt: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updatedAt: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n email: Field.email({\n label: 'Email',\n required: true,\n searchable: true,\n }),\n \n emailVerified: Field.boolean({\n label: 'Email Verified',\n defaultValue: false,\n }),\n \n name: Field.text({\n label: 'Name',\n required: true,\n searchable: true,\n maxLength: 255,\n }),\n \n image: Field.url({\n label: 'Profile Image',\n required: false,\n }),\n },\n \n // Database indexes for performance\n indexes: [\n { fields: ['email'], unique: true },\n { fields: ['createdAt'], unique: false },\n ],\n \n // Enable features\n enable: {\n trackHistory: true,\n searchable: true,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: true,\n mru: true,\n },\n \n // Validation Rules\n validations: [\n {\n name: 'email_unique',\n type: 'unique',\n severity: 'error',\n message: 'Email must be unique',\n fields: ['email'],\n caseSensitive: false,\n },\n ],\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * Auth Session Object\n * \n * Uses better-auth's native schema for seamless migration:\n * - id: string\n * - createdAt: Date\n * - updatedAt: Date\n * - userId: string\n * - expiresAt: Date\n * - token: string\n * - ipAddress: string | null\n * - userAgent: string | null\n */\nexport const AuthSession = ObjectSchema.create({\n name: 'session',\n label: 'Session',\n pluralLabel: 'Sessions',\n icon: 'key',\n description: 'Active user sessions',\n titleFormat: 'Session {token}',\n compactLayout: ['userId', 'expiresAt', 'ipAddress'],\n \n fields: {\n id: Field.text({\n label: 'Session ID',\n required: true,\n readonly: true,\n }),\n \n createdAt: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updatedAt: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n userId: Field.text({\n label: 'User ID',\n required: true,\n }),\n \n expiresAt: Field.datetime({\n label: 'Expires At',\n required: true,\n }),\n \n token: Field.text({\n label: 'Session Token',\n required: true,\n }),\n \n ipAddress: Field.text({\n label: 'IP Address',\n required: false,\n maxLength: 45, // Support IPv6\n }),\n \n userAgent: Field.textarea({\n label: 'User Agent',\n required: false,\n }),\n },\n \n // Database indexes for performance\n indexes: [\n { fields: ['token'], unique: true },\n { fields: ['userId'], unique: false },\n { fields: ['expiresAt'], unique: false },\n ],\n \n // Enable features\n enable: {\n trackHistory: false, // Sessions don't need history tracking\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'delete'], // No update for sessions\n trash: false, // Sessions should be hard deleted\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * Auth Account Object\n * \n * Uses better-auth's native schema for seamless migration:\n * - id: string\n * - createdAt: Date\n * - updatedAt: Date\n * - providerId: string (e.g., 'google', 'github')\n * - accountId: string (provider's user ID)\n * - userId: string (link to user table)\n * - accessToken: string | null\n * - refreshToken: string | null\n * - idToken: string | null\n * - accessTokenExpiresAt: Date | null\n * - refreshTokenExpiresAt: Date | null\n * - scope: string | null\n * - password: string | null (for email/password provider)\n */\nexport const AuthAccount = ObjectSchema.create({\n name: 'account',\n label: 'Account',\n pluralLabel: 'Accounts',\n icon: 'link',\n description: 'OAuth and authentication provider accounts',\n titleFormat: '{providerId} - {accountId}',\n compactLayout: ['providerId', 'userId', 'accountId'],\n \n fields: {\n id: Field.text({\n label: 'Account ID',\n required: true,\n readonly: true,\n }),\n \n createdAt: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updatedAt: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n providerId: Field.text({\n label: 'Provider ID',\n required: true,\n description: 'OAuth provider identifier (google, github, etc.)',\n }),\n \n accountId: Field.text({\n label: 'Provider Account ID',\n required: true,\n description: \"User's ID in the provider's system\",\n }),\n \n userId: Field.text({\n label: 'User ID',\n required: true,\n description: 'Link to user table',\n }),\n \n accessToken: Field.textarea({\n label: 'Access Token',\n required: false,\n }),\n \n refreshToken: Field.textarea({\n label: 'Refresh Token',\n required: false,\n }),\n \n idToken: Field.textarea({\n label: 'ID Token',\n required: false,\n }),\n \n accessTokenExpiresAt: Field.datetime({\n label: 'Access Token Expires At',\n required: false,\n }),\n \n refreshTokenExpiresAt: Field.datetime({\n label: 'Refresh Token Expires At',\n required: false,\n }),\n \n scope: Field.text({\n label: 'OAuth Scope',\n required: false,\n }),\n \n password: Field.text({\n label: 'Password Hash',\n required: false,\n description: 'Hashed password for email/password provider',\n }),\n },\n \n // Database indexes for performance\n indexes: [\n { fields: ['userId'], unique: false },\n { fields: ['providerId', 'accountId'], unique: true },\n ],\n \n // Enable features\n enable: {\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: true,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * Auth Verification Object\n * \n * Uses better-auth's native schema for seamless migration:\n * - id: string\n * - createdAt: Date\n * - updatedAt: Date\n * - value: string (verification token/code)\n * - expiresAt: Date\n * - identifier: string (email or phone number)\n */\nexport const AuthVerification = ObjectSchema.create({\n name: 'verification',\n label: 'Verification',\n pluralLabel: 'Verifications',\n icon: 'shield-check',\n description: 'Email and phone verification tokens',\n titleFormat: 'Verification for {identifier}',\n compactLayout: ['identifier', 'expiresAt', 'createdAt'],\n \n fields: {\n id: Field.text({\n label: 'Verification ID',\n required: true,\n readonly: true,\n }),\n \n createdAt: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updatedAt: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n value: Field.text({\n label: 'Verification Token',\n required: true,\n description: 'Token or code for verification',\n }),\n \n expiresAt: Field.datetime({\n label: 'Expires At',\n required: true,\n }),\n \n identifier: Field.text({\n label: 'Identifier',\n required: true,\n description: 'Email address or phone number',\n }),\n },\n \n // Database indexes for performance\n indexes: [\n { fields: ['value'], unique: true },\n { fields: ['identifier'], unique: false },\n { fields: ['expiresAt'], unique: false },\n ],\n \n // Enable features\n enable: {\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'create', 'delete'], // No list or update\n trash: false, // Hard delete expired tokens\n mru: false,\n },\n});\n"],"mappings":"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","names":["ObjectSchema","Field","ObjectSchema","Field","ObjectSchema","Field"]}
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@objectstack/plugin-auth",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.5",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Authentication & Identity Plugin for ObjectStack",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"better-auth": "^1.4.18",
|
|
10
|
-
"@objectstack/core": "2.0.
|
|
11
|
-
"@objectstack/spec": "2.0.
|
|
10
|
+
"@objectstack/core": "2.0.5",
|
|
11
|
+
"@objectstack/spec": "2.0.5"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
14
|
"@types/node": "^25.2.2",
|
package/src/auth-plugin.ts
CHANGED
|
@@ -105,6 +105,24 @@ export class AuthPlugin implements Plugin {
|
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
// Register auth middleware on ObjectQL engine (if available)
|
|
109
|
+
try {
|
|
110
|
+
const ql = ctx.getService<any>('objectql');
|
|
111
|
+
if (ql && typeof ql.registerMiddleware === 'function') {
|
|
112
|
+
ql.registerMiddleware(async (opCtx: any, next: () => Promise<void>) => {
|
|
113
|
+
// If context already has userId or isSystem, skip auth resolution
|
|
114
|
+
if (opCtx.context?.userId || opCtx.context?.isSystem) {
|
|
115
|
+
return next();
|
|
116
|
+
}
|
|
117
|
+
// Future: resolve session from AsyncLocalStorage or request context
|
|
118
|
+
await next();
|
|
119
|
+
});
|
|
120
|
+
ctx.logger.info('Auth middleware registered on ObjectQL engine');
|
|
121
|
+
}
|
|
122
|
+
} catch (_e) {
|
|
123
|
+
ctx.logger.debug('ObjectQL engine not available, skipping auth middleware registration');
|
|
124
|
+
}
|
|
125
|
+
|
|
108
126
|
ctx.logger.info('Auth Plugin started successfully');
|
|
109
127
|
}
|
|
110
128
|
|