@objectstack/plugin-auth 4.0.4 → 4.1.0
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/README.md +4 -1
- package/dist/index.d.mts +441 -19940
- package/dist/index.d.ts +441 -19940
- package/dist/index.js +704 -900
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +699 -880
- package/dist/index.mjs.map +1 -1
- package/package.json +35 -12
- package/.turbo/turbo-build.log +0 -78
- package/ARCHITECTURE.md +0 -176
- package/CHANGELOG.md +0 -333
- package/IMPLEMENTATION_SUMMARY.md +0 -192
- package/examples/basic-usage.ts +0 -107
- package/objectstack.config.ts +0 -24
- package/src/auth-manager.test.ts +0 -883
- package/src/auth-manager.ts +0 -419
- package/src/auth-plugin.test.ts +0 -446
- package/src/auth-plugin.ts +0 -314
- package/src/auth-schema-config.ts +0 -339
- package/src/index.ts +0 -16
- package/src/objectql-adapter.test.ts +0 -281
- package/src/objectql-adapter.ts +0 -279
- package/src/objects/auth-account.object.ts +0 -7
- package/src/objects/auth-session.object.ts +0 -7
- package/src/objects/auth-user.object.ts +0 -7
- package/src/objects/auth-verification.object.ts +0 -7
- package/src/objects/index.ts +0 -40
- package/src/objects/sys-account.object.ts +0 -111
- package/src/objects/sys-api-key.object.ts +0 -104
- package/src/objects/sys-invitation.object.ts +0 -93
- package/src/objects/sys-member.object.ts +0 -68
- package/src/objects/sys-organization.object.ts +0 -82
- package/src/objects/sys-session.object.ts +0 -84
- package/src/objects/sys-team-member.object.ts +0 -61
- package/src/objects/sys-team.object.ts +0 -69
- package/src/objects/sys-two-factor.object.ts +0 -73
- package/src/objects/sys-user-preference.object.ts +0 -82
- package/src/objects/sys-user.object.ts +0 -91
- package/src/objects/sys-verification.object.ts +0 -75
- package/tsconfig.json +0 -18
package/src/auth-plugin.ts
DELETED
|
@@ -1,314 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
-
|
|
3
|
-
import { Plugin, PluginContext, IHttpServer } from '@objectstack/core';
|
|
4
|
-
import { AuthConfig } from '@objectstack/spec/system';
|
|
5
|
-
import { AuthManager } from './auth-manager.js';
|
|
6
|
-
import {
|
|
7
|
-
SysUser, SysSession, SysAccount, SysVerification,
|
|
8
|
-
SysOrganization, SysMember, SysInvitation,
|
|
9
|
-
SysTeam, SysTeamMember,
|
|
10
|
-
SysApiKey, SysTwoFactor, SysUserPreference,
|
|
11
|
-
} from './objects/index.js';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Auth Plugin Options
|
|
15
|
-
* Extends AuthConfig from spec with additional runtime options
|
|
16
|
-
*/
|
|
17
|
-
export interface AuthPluginOptions extends Partial<AuthConfig> {
|
|
18
|
-
/**
|
|
19
|
-
* Whether to automatically register auth routes
|
|
20
|
-
* @default true
|
|
21
|
-
*/
|
|
22
|
-
registerRoutes?: boolean;
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Base path for auth routes
|
|
26
|
-
* @default '/api/v1/auth'
|
|
27
|
-
*/
|
|
28
|
-
basePath?: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Authentication Plugin
|
|
33
|
-
*
|
|
34
|
-
* Provides authentication and identity services for ObjectStack applications.
|
|
35
|
-
*
|
|
36
|
-
* **Dual-Mode Operation:**
|
|
37
|
-
* - **Server mode** (HonoServerPlugin active): Registers HTTP routes at basePath,
|
|
38
|
-
* forwarding all auth requests to better-auth's universal handler.
|
|
39
|
-
* - **MSW/Mock mode** (no HTTP server): Gracefully skips route registration but
|
|
40
|
-
* still registers the `auth` service, allowing HttpDispatcher.handleAuth() to
|
|
41
|
-
* simulate auth flows (sign-up, sign-in, etc.) for development and testing.
|
|
42
|
-
*
|
|
43
|
-
* Features:
|
|
44
|
-
* - Session management
|
|
45
|
-
* - User registration/login
|
|
46
|
-
* - OAuth providers (Google, GitHub, etc.)
|
|
47
|
-
* - Organization/team support
|
|
48
|
-
* - 2FA, passkeys, magic links
|
|
49
|
-
*
|
|
50
|
-
* This plugin registers:
|
|
51
|
-
* - `auth` service (auth manager instance) — always
|
|
52
|
-
* - `app.com.objectstack.system` service (system object definitions) — always
|
|
53
|
-
* - HTTP routes for authentication endpoints — only when HTTP server is available
|
|
54
|
-
*
|
|
55
|
-
* Integrates with better-auth library to provide comprehensive
|
|
56
|
-
* authentication capabilities including email/password, OAuth, 2FA,
|
|
57
|
-
* magic links, passkeys, and organization support.
|
|
58
|
-
*/
|
|
59
|
-
export class AuthPlugin implements Plugin {
|
|
60
|
-
name = 'com.objectstack.auth';
|
|
61
|
-
type = 'standard';
|
|
62
|
-
version = '1.0.0';
|
|
63
|
-
dependencies: string[] = ['com.objectstack.engine.objectql']; // manifest service required
|
|
64
|
-
|
|
65
|
-
private options: AuthPluginOptions;
|
|
66
|
-
private authManager: AuthManager | null = null;
|
|
67
|
-
|
|
68
|
-
constructor(options: AuthPluginOptions = {}) {
|
|
69
|
-
this.options = {
|
|
70
|
-
registerRoutes: true,
|
|
71
|
-
basePath: '/api/v1/auth',
|
|
72
|
-
...options
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async init(ctx: PluginContext): Promise<void> {
|
|
77
|
-
ctx.logger.info('Initializing Auth Plugin...');
|
|
78
|
-
|
|
79
|
-
// Validate required configuration
|
|
80
|
-
if (!this.options.secret) {
|
|
81
|
-
throw new Error('AuthPlugin: secret is required');
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Get data engine service for database operations
|
|
85
|
-
const dataEngine = ctx.getService<any>('data');
|
|
86
|
-
if (!dataEngine) {
|
|
87
|
-
ctx.logger.warn('No data engine service found - auth will use in-memory storage');
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Initialize auth manager with data engine
|
|
91
|
-
this.authManager = new AuthManager({
|
|
92
|
-
...this.options,
|
|
93
|
-
dataEngine,
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
// Register auth service
|
|
97
|
-
ctx.registerService('auth', this.authManager);
|
|
98
|
-
|
|
99
|
-
// Register system objects via the manifest service.
|
|
100
|
-
ctx.getService<{ register(m: any): void }>('manifest').register({
|
|
101
|
-
id: 'com.objectstack.system',
|
|
102
|
-
name: 'System',
|
|
103
|
-
version: '1.0.0',
|
|
104
|
-
type: 'plugin',
|
|
105
|
-
namespace: 'sys',
|
|
106
|
-
objects: [
|
|
107
|
-
SysUser, SysSession, SysAccount, SysVerification,
|
|
108
|
-
SysOrganization, SysMember, SysInvitation,
|
|
109
|
-
SysTeam, SysTeamMember,
|
|
110
|
-
SysApiKey, SysTwoFactor, SysUserPreference,
|
|
111
|
-
],
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
// Contribute navigation items to the Setup App (if SetupPlugin is loaded).
|
|
115
|
-
// Uses try/catch so AuthPlugin works independently of SetupPlugin.
|
|
116
|
-
try {
|
|
117
|
-
const setupNav = ctx.getService<{ contribute(c: any): void }>('setupNav');
|
|
118
|
-
if (setupNav) {
|
|
119
|
-
setupNav.contribute({
|
|
120
|
-
areaId: 'area_administration',
|
|
121
|
-
items: [
|
|
122
|
-
{ id: 'nav_users', type: 'object', label: 'Users', objectName: 'user', icon: 'users', order: 10 },
|
|
123
|
-
{ id: 'nav_organizations', type: 'object', label: 'Organizations', objectName: 'organization', icon: 'building-2', order: 20 },
|
|
124
|
-
{ id: 'nav_teams', type: 'object', label: 'Teams', objectName: 'team', icon: 'users-round', order: 30 },
|
|
125
|
-
{ id: 'nav_api_keys', type: 'object', label: 'API Keys', objectName: 'api_key', icon: 'key', order: 40 },
|
|
126
|
-
{ id: 'nav_sessions', type: 'object', label: 'Sessions', objectName: 'session', icon: 'monitor', order: 50 },
|
|
127
|
-
],
|
|
128
|
-
});
|
|
129
|
-
ctx.logger.info('Auth navigation items contributed to Setup App');
|
|
130
|
-
}
|
|
131
|
-
} catch {
|
|
132
|
-
// SetupPlugin not loaded — skip silently
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
ctx.logger.info('Auth Plugin initialized successfully');
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
async start(ctx: PluginContext): Promise<void> {
|
|
139
|
-
ctx.logger.info('Starting Auth Plugin...');
|
|
140
|
-
|
|
141
|
-
if (!this.authManager) {
|
|
142
|
-
throw new Error('Auth manager not initialized');
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Defer HTTP route registration to kernel:ready hook.
|
|
146
|
-
// This ensures all plugins (including HonoServerPlugin) have completed
|
|
147
|
-
// their init and start phases before we attempt to look up the
|
|
148
|
-
// http-server service — making AuthPlugin resilient to plugin
|
|
149
|
-
// loading order.
|
|
150
|
-
if (this.options.registerRoutes) {
|
|
151
|
-
ctx.hook('kernel:ready', async () => {
|
|
152
|
-
let httpServer: IHttpServer | null = null;
|
|
153
|
-
try {
|
|
154
|
-
httpServer = ctx.getService<IHttpServer>('http-server');
|
|
155
|
-
} catch {
|
|
156
|
-
// Service not found — expected in MSW/mock mode
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if (httpServer) {
|
|
160
|
-
// Auto-detect the actual server URL when no explicit baseUrl was
|
|
161
|
-
// configured, or when the configured baseUrl uses a different port
|
|
162
|
-
// than the running server (e.g. port 3000 configured but 3002 bound).
|
|
163
|
-
// getPort() is optional on IHttpServer; duck-type check for it.
|
|
164
|
-
const serverWithPort = httpServer as IHttpServer & { getPort?: () => number };
|
|
165
|
-
if (this.authManager && typeof serverWithPort.getPort === 'function') {
|
|
166
|
-
const actualPort = serverWithPort.getPort();
|
|
167
|
-
if (actualPort) {
|
|
168
|
-
const configuredUrl = this.options.baseUrl || 'http://localhost:3000';
|
|
169
|
-
const configuredOrigin = new URL(configuredUrl).origin;
|
|
170
|
-
const actualUrl = `http://localhost:${actualPort}`;
|
|
171
|
-
|
|
172
|
-
if (configuredOrigin !== actualUrl) {
|
|
173
|
-
this.authManager.setRuntimeBaseUrl(actualUrl);
|
|
174
|
-
ctx.logger.info(
|
|
175
|
-
`Auth baseUrl auto-updated to ${actualUrl} (configured: ${configuredUrl})`,
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Route registration errors should propagate (server misconfiguration)
|
|
182
|
-
this.registerAuthRoutes(httpServer, ctx);
|
|
183
|
-
ctx.logger.info(`Auth routes registered at ${this.options.basePath}`);
|
|
184
|
-
} else {
|
|
185
|
-
ctx.logger.warn(
|
|
186
|
-
'No HTTP server available — auth routes not registered. ' +
|
|
187
|
-
'Auth service is still available for MSW/mock environments via HttpDispatcher.'
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Register auth middleware on ObjectQL engine (if available)
|
|
194
|
-
try {
|
|
195
|
-
const ql = ctx.getService<any>('objectql');
|
|
196
|
-
if (ql && typeof ql.registerMiddleware === 'function') {
|
|
197
|
-
ql.registerMiddleware(async (opCtx: any, next: () => Promise<void>) => {
|
|
198
|
-
// If context already has userId or isSystem, skip auth resolution
|
|
199
|
-
if (opCtx.context?.userId || opCtx.context?.isSystem) {
|
|
200
|
-
return next();
|
|
201
|
-
}
|
|
202
|
-
// Future: resolve session from AsyncLocalStorage or request context
|
|
203
|
-
await next();
|
|
204
|
-
});
|
|
205
|
-
ctx.logger.info('Auth middleware registered on ObjectQL engine');
|
|
206
|
-
}
|
|
207
|
-
} catch (_e) {
|
|
208
|
-
ctx.logger.debug('ObjectQL engine not available, skipping auth middleware registration');
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
ctx.logger.info('Auth Plugin started successfully');
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
async destroy(): Promise<void> {
|
|
215
|
-
// Cleanup if needed
|
|
216
|
-
this.authManager = null;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Register authentication routes with HTTP server
|
|
221
|
-
*
|
|
222
|
-
* Uses better-auth's universal handler for all authentication requests.
|
|
223
|
-
* This forwards all requests under basePath to better-auth, which handles:
|
|
224
|
-
* - Email/password authentication
|
|
225
|
-
* - OAuth providers (Google, GitHub, etc.)
|
|
226
|
-
* - Session management
|
|
227
|
-
* - Password reset
|
|
228
|
-
* - Email verification
|
|
229
|
-
* - 2FA, passkeys, magic links (if enabled)
|
|
230
|
-
*/
|
|
231
|
-
private registerAuthRoutes(httpServer: IHttpServer, ctx: PluginContext): void {
|
|
232
|
-
if (!this.authManager) return;
|
|
233
|
-
|
|
234
|
-
const basePath = this.options.basePath || '/api/v1/auth';
|
|
235
|
-
|
|
236
|
-
// Get raw Hono app to use native wildcard routing
|
|
237
|
-
// Type assertion is safe here because we explicitly require Hono server as a dependency
|
|
238
|
-
if (!('getRawApp' in httpServer) || typeof (httpServer as any).getRawApp !== 'function') {
|
|
239
|
-
ctx.logger.error('HTTP server does not support getRawApp() - wildcard routing requires Hono server');
|
|
240
|
-
throw new Error(
|
|
241
|
-
'AuthPlugin requires HonoServerPlugin for wildcard routing support. ' +
|
|
242
|
-
'Please ensure HonoServerPlugin is loaded before AuthPlugin.'
|
|
243
|
-
);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const rawApp = (httpServer as any).getRawApp();
|
|
247
|
-
|
|
248
|
-
// Register auth config endpoint - public endpoint for frontend discovery
|
|
249
|
-
rawApp.get(`${basePath}/config`, async (c: any) => {
|
|
250
|
-
try {
|
|
251
|
-
const config = this.authManager!.getPublicConfig();
|
|
252
|
-
return c.json({
|
|
253
|
-
success: true,
|
|
254
|
-
data: config,
|
|
255
|
-
});
|
|
256
|
-
} catch (error) {
|
|
257
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
258
|
-
ctx.logger.error('Auth config error:', err);
|
|
259
|
-
|
|
260
|
-
return c.json({
|
|
261
|
-
success: false,
|
|
262
|
-
error: {
|
|
263
|
-
code: 'auth_config_error',
|
|
264
|
-
message: err.message,
|
|
265
|
-
},
|
|
266
|
-
}, 500);
|
|
267
|
-
}
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
// Register wildcard route to forward all auth requests to better-auth.
|
|
271
|
-
// better-auth is configured with basePath matching our route prefix, so we
|
|
272
|
-
// forward the original request directly — no path rewriting needed.
|
|
273
|
-
rawApp.all(`${basePath}/*`, async (c: any) => {
|
|
274
|
-
try {
|
|
275
|
-
// Forward the original request to better-auth handler
|
|
276
|
-
const response = await this.authManager!.handleRequest(c.req.raw);
|
|
277
|
-
|
|
278
|
-
// better-auth catches internal errors and returns error Responses
|
|
279
|
-
// without throwing, so the catch block below would never trigger.
|
|
280
|
-
// We proactively log server errors here for observability.
|
|
281
|
-
if (response.status >= 500) {
|
|
282
|
-
try {
|
|
283
|
-
const body = await response.clone().text();
|
|
284
|
-
ctx.logger.error('[AuthPlugin] better-auth returned server error', new Error(`HTTP ${response.status}: ${body}`));
|
|
285
|
-
} catch {
|
|
286
|
-
ctx.logger.error('[AuthPlugin] better-auth returned server error', new Error(`HTTP ${response.status}: (unable to read body)`));
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
return response;
|
|
291
|
-
} catch (error) {
|
|
292
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
293
|
-
ctx.logger.error('Auth request error:', err);
|
|
294
|
-
|
|
295
|
-
// Return error response
|
|
296
|
-
return new Response(
|
|
297
|
-
JSON.stringify({
|
|
298
|
-
success: false,
|
|
299
|
-
error: err.message,
|
|
300
|
-
}),
|
|
301
|
-
{
|
|
302
|
-
status: 500,
|
|
303
|
-
headers: { 'Content-Type': 'application/json' },
|
|
304
|
-
}
|
|
305
|
-
);
|
|
306
|
-
}
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
ctx.logger.info(`Auth routes registered: All requests under ${basePath}/* forwarded to better-auth`);
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
@@ -1,339 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
-
|
|
3
|
-
import { SystemObjectName } from '@objectstack/spec/system';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* better-auth ↔ ObjectStack Schema Mapping
|
|
7
|
-
*
|
|
8
|
-
* better-auth uses camelCase field names internally (e.g. `emailVerified`, `userId`)
|
|
9
|
-
* while ObjectStack's protocol layer uses snake_case (e.g. `email_verified`, `user_id`).
|
|
10
|
-
*
|
|
11
|
-
* These constants declare the `modelName` and `fields` mappings for each core auth
|
|
12
|
-
* model, following better-auth's official schema customisation API
|
|
13
|
-
* ({@link https://www.better-auth.com/docs/concepts/database}).
|
|
14
|
-
*
|
|
15
|
-
* The mappings serve two purposes:
|
|
16
|
-
* 1. `modelName` — maps the default model name to the ObjectStack protocol name
|
|
17
|
-
* (e.g. `user` → `sys_user`).
|
|
18
|
-
* 2. `fields` — maps camelCase field names to their snake_case database column
|
|
19
|
-
* equivalents. Only fields whose names differ need to be listed; fields that
|
|
20
|
-
* are already identical (e.g. `email`, `name`, `token`) are omitted.
|
|
21
|
-
*
|
|
22
|
-
* These mappings are consumed by:
|
|
23
|
-
* - The `betterAuth()` configuration in {@link AuthManager} so that
|
|
24
|
-
* `getAuthTables()` builds the correct schema.
|
|
25
|
-
* - The ObjectQL adapter factory (via `createAdapterFactory`) which uses the
|
|
26
|
-
* schema to transform data and where-clauses automatically.
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
// ---------------------------------------------------------------------------
|
|
30
|
-
// User model
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* better-auth `user` model mapping.
|
|
35
|
-
*
|
|
36
|
-
* | camelCase (better-auth) | snake_case (ObjectStack) |
|
|
37
|
-
* |:------------------------|:-------------------------|
|
|
38
|
-
* | emailVerified | email_verified |
|
|
39
|
-
* | createdAt | created_at |
|
|
40
|
-
* | updatedAt | updated_at |
|
|
41
|
-
*/
|
|
42
|
-
export const AUTH_USER_CONFIG = {
|
|
43
|
-
modelName: SystemObjectName.USER, // 'sys_user'
|
|
44
|
-
fields: {
|
|
45
|
-
emailVerified: 'email_verified',
|
|
46
|
-
createdAt: 'created_at',
|
|
47
|
-
updatedAt: 'updated_at',
|
|
48
|
-
},
|
|
49
|
-
} as const;
|
|
50
|
-
|
|
51
|
-
// ---------------------------------------------------------------------------
|
|
52
|
-
// Session model
|
|
53
|
-
// ---------------------------------------------------------------------------
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* better-auth `session` model mapping.
|
|
57
|
-
*
|
|
58
|
-
* | camelCase (better-auth) | snake_case (ObjectStack) |
|
|
59
|
-
* |:------------------------|:-------------------------|
|
|
60
|
-
* | userId | user_id |
|
|
61
|
-
* | expiresAt | expires_at |
|
|
62
|
-
* | createdAt | created_at |
|
|
63
|
-
* | updatedAt | updated_at |
|
|
64
|
-
* | ipAddress | ip_address |
|
|
65
|
-
* | userAgent | user_agent |
|
|
66
|
-
*/
|
|
67
|
-
export const AUTH_SESSION_CONFIG = {
|
|
68
|
-
modelName: SystemObjectName.SESSION, // 'sys_session'
|
|
69
|
-
fields: {
|
|
70
|
-
userId: 'user_id',
|
|
71
|
-
expiresAt: 'expires_at',
|
|
72
|
-
createdAt: 'created_at',
|
|
73
|
-
updatedAt: 'updated_at',
|
|
74
|
-
ipAddress: 'ip_address',
|
|
75
|
-
userAgent: 'user_agent',
|
|
76
|
-
},
|
|
77
|
-
} as const;
|
|
78
|
-
|
|
79
|
-
// ---------------------------------------------------------------------------
|
|
80
|
-
// Account model
|
|
81
|
-
// ---------------------------------------------------------------------------
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* better-auth `account` model mapping.
|
|
85
|
-
*
|
|
86
|
-
* | camelCase (better-auth) | snake_case (ObjectStack) |
|
|
87
|
-
* |:--------------------------|:-------------------------------|
|
|
88
|
-
* | userId | user_id |
|
|
89
|
-
* | providerId | provider_id |
|
|
90
|
-
* | accountId | account_id |
|
|
91
|
-
* | accessToken | access_token |
|
|
92
|
-
* | refreshToken | refresh_token |
|
|
93
|
-
* | idToken | id_token |
|
|
94
|
-
* | accessTokenExpiresAt | access_token_expires_at |
|
|
95
|
-
* | refreshTokenExpiresAt | refresh_token_expires_at |
|
|
96
|
-
* | createdAt | created_at |
|
|
97
|
-
* | updatedAt | updated_at |
|
|
98
|
-
*/
|
|
99
|
-
export const AUTH_ACCOUNT_CONFIG = {
|
|
100
|
-
modelName: SystemObjectName.ACCOUNT, // 'sys_account'
|
|
101
|
-
fields: {
|
|
102
|
-
userId: 'user_id',
|
|
103
|
-
providerId: 'provider_id',
|
|
104
|
-
accountId: 'account_id',
|
|
105
|
-
accessToken: 'access_token',
|
|
106
|
-
refreshToken: 'refresh_token',
|
|
107
|
-
idToken: 'id_token',
|
|
108
|
-
accessTokenExpiresAt: 'access_token_expires_at',
|
|
109
|
-
refreshTokenExpiresAt: 'refresh_token_expires_at',
|
|
110
|
-
createdAt: 'created_at',
|
|
111
|
-
updatedAt: 'updated_at',
|
|
112
|
-
},
|
|
113
|
-
} as const;
|
|
114
|
-
|
|
115
|
-
// ---------------------------------------------------------------------------
|
|
116
|
-
// Verification model
|
|
117
|
-
// ---------------------------------------------------------------------------
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* better-auth `verification` model mapping.
|
|
121
|
-
*
|
|
122
|
-
* | camelCase (better-auth) | snake_case (ObjectStack) |
|
|
123
|
-
* |:------------------------|:-------------------------|
|
|
124
|
-
* | expiresAt | expires_at |
|
|
125
|
-
* | createdAt | created_at |
|
|
126
|
-
* | updatedAt | updated_at |
|
|
127
|
-
*/
|
|
128
|
-
export const AUTH_VERIFICATION_CONFIG = {
|
|
129
|
-
modelName: SystemObjectName.VERIFICATION, // 'sys_verification'
|
|
130
|
-
fields: {
|
|
131
|
-
expiresAt: 'expires_at',
|
|
132
|
-
createdAt: 'created_at',
|
|
133
|
-
updatedAt: 'updated_at',
|
|
134
|
-
},
|
|
135
|
-
} as const;
|
|
136
|
-
|
|
137
|
-
// ===========================================================================
|
|
138
|
-
// Plugin Table Mappings
|
|
139
|
-
// ===========================================================================
|
|
140
|
-
//
|
|
141
|
-
// better-auth plugins (organization, two-factor, etc.) introduce additional
|
|
142
|
-
// tables with their own camelCase field names. The mappings below are passed
|
|
143
|
-
// to the plugin's `schema` option so that `createAdapterFactory` transforms
|
|
144
|
-
// them to snake_case automatically, just like the core models above.
|
|
145
|
-
// ===========================================================================
|
|
146
|
-
|
|
147
|
-
// ---------------------------------------------------------------------------
|
|
148
|
-
// Organization plugin – organization table
|
|
149
|
-
// ---------------------------------------------------------------------------
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* better-auth Organization plugin `organization` model mapping.
|
|
153
|
-
*
|
|
154
|
-
* | camelCase (better-auth) | snake_case (ObjectStack) |
|
|
155
|
-
* |:------------------------|:-------------------------|
|
|
156
|
-
* | createdAt | created_at |
|
|
157
|
-
* | updatedAt | updated_at |
|
|
158
|
-
*/
|
|
159
|
-
export const AUTH_ORGANIZATION_SCHEMA = {
|
|
160
|
-
modelName: SystemObjectName.ORGANIZATION, // 'sys_organization'
|
|
161
|
-
fields: {
|
|
162
|
-
createdAt: 'created_at',
|
|
163
|
-
updatedAt: 'updated_at',
|
|
164
|
-
},
|
|
165
|
-
} as const;
|
|
166
|
-
|
|
167
|
-
// ---------------------------------------------------------------------------
|
|
168
|
-
// Organization plugin – member table
|
|
169
|
-
// ---------------------------------------------------------------------------
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* better-auth Organization plugin `member` model mapping.
|
|
173
|
-
*
|
|
174
|
-
* | camelCase (better-auth) | snake_case (ObjectStack) |
|
|
175
|
-
* |:------------------------|:-------------------------|
|
|
176
|
-
* | organizationId | organization_id |
|
|
177
|
-
* | userId | user_id |
|
|
178
|
-
* | createdAt | created_at |
|
|
179
|
-
*/
|
|
180
|
-
export const AUTH_MEMBER_SCHEMA = {
|
|
181
|
-
modelName: SystemObjectName.MEMBER, // 'sys_member'
|
|
182
|
-
fields: {
|
|
183
|
-
organizationId: 'organization_id',
|
|
184
|
-
userId: 'user_id',
|
|
185
|
-
createdAt: 'created_at',
|
|
186
|
-
},
|
|
187
|
-
} as const;
|
|
188
|
-
|
|
189
|
-
// ---------------------------------------------------------------------------
|
|
190
|
-
// Organization plugin – invitation table
|
|
191
|
-
// ---------------------------------------------------------------------------
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* better-auth Organization plugin `invitation` model mapping.
|
|
195
|
-
*
|
|
196
|
-
* | camelCase (better-auth) | snake_case (ObjectStack) |
|
|
197
|
-
* |:------------------------|:-------------------------|
|
|
198
|
-
* | organizationId | organization_id |
|
|
199
|
-
* | inviterId | inviter_id |
|
|
200
|
-
* | expiresAt | expires_at |
|
|
201
|
-
* | createdAt | created_at |
|
|
202
|
-
* | teamId | team_id |
|
|
203
|
-
*/
|
|
204
|
-
export const AUTH_INVITATION_SCHEMA = {
|
|
205
|
-
modelName: SystemObjectName.INVITATION, // 'sys_invitation'
|
|
206
|
-
fields: {
|
|
207
|
-
organizationId: 'organization_id',
|
|
208
|
-
inviterId: 'inviter_id',
|
|
209
|
-
expiresAt: 'expires_at',
|
|
210
|
-
createdAt: 'created_at',
|
|
211
|
-
teamId: 'team_id',
|
|
212
|
-
},
|
|
213
|
-
} as const;
|
|
214
|
-
|
|
215
|
-
// ---------------------------------------------------------------------------
|
|
216
|
-
// Organization plugin – session additional fields
|
|
217
|
-
// ---------------------------------------------------------------------------
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Organization plugin adds `activeOrganizationId` (and optionally
|
|
221
|
-
* `activeTeamId`) to the session model. These field mappings are
|
|
222
|
-
* injected via the organization plugin's `schema.session.fields`.
|
|
223
|
-
*/
|
|
224
|
-
export const AUTH_ORG_SESSION_FIELDS = {
|
|
225
|
-
activeOrganizationId: 'active_organization_id',
|
|
226
|
-
activeTeamId: 'active_team_id',
|
|
227
|
-
} as const;
|
|
228
|
-
|
|
229
|
-
// ---------------------------------------------------------------------------
|
|
230
|
-
// Organization plugin – team table (optional, when teams enabled)
|
|
231
|
-
// ---------------------------------------------------------------------------
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* better-auth Organization plugin `team` model mapping.
|
|
235
|
-
*
|
|
236
|
-
* | camelCase (better-auth) | snake_case (ObjectStack) |
|
|
237
|
-
* |:------------------------|:-------------------------|
|
|
238
|
-
* | organizationId | organization_id |
|
|
239
|
-
* | createdAt | created_at |
|
|
240
|
-
* | updatedAt | updated_at |
|
|
241
|
-
*/
|
|
242
|
-
export const AUTH_TEAM_SCHEMA = {
|
|
243
|
-
modelName: SystemObjectName.TEAM, // 'sys_team'
|
|
244
|
-
fields: {
|
|
245
|
-
organizationId: 'organization_id',
|
|
246
|
-
createdAt: 'created_at',
|
|
247
|
-
updatedAt: 'updated_at',
|
|
248
|
-
},
|
|
249
|
-
} as const;
|
|
250
|
-
|
|
251
|
-
// ---------------------------------------------------------------------------
|
|
252
|
-
// Organization plugin – teamMember table (optional, when teams enabled)
|
|
253
|
-
// ---------------------------------------------------------------------------
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* better-auth Organization plugin `teamMember` model mapping.
|
|
257
|
-
*
|
|
258
|
-
* | camelCase (better-auth) | snake_case (ObjectStack) |
|
|
259
|
-
* |:------------------------|:-------------------------|
|
|
260
|
-
* | teamId | team_id |
|
|
261
|
-
* | userId | user_id |
|
|
262
|
-
* | createdAt | created_at |
|
|
263
|
-
*/
|
|
264
|
-
export const AUTH_TEAM_MEMBER_SCHEMA = {
|
|
265
|
-
modelName: SystemObjectName.TEAM_MEMBER, // 'sys_team_member'
|
|
266
|
-
fields: {
|
|
267
|
-
teamId: 'team_id',
|
|
268
|
-
userId: 'user_id',
|
|
269
|
-
createdAt: 'created_at',
|
|
270
|
-
},
|
|
271
|
-
} as const;
|
|
272
|
-
|
|
273
|
-
// ---------------------------------------------------------------------------
|
|
274
|
-
// Two-Factor plugin – twoFactor table
|
|
275
|
-
// ---------------------------------------------------------------------------
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* better-auth Two-Factor plugin `twoFactor` model mapping.
|
|
279
|
-
*
|
|
280
|
-
* | camelCase (better-auth) | snake_case (ObjectStack) |
|
|
281
|
-
* |:------------------------|:-------------------------|
|
|
282
|
-
* | backupCodes | backup_codes |
|
|
283
|
-
* | userId | user_id |
|
|
284
|
-
*/
|
|
285
|
-
export const AUTH_TWO_FACTOR_SCHEMA = {
|
|
286
|
-
modelName: SystemObjectName.TWO_FACTOR, // 'sys_two_factor'
|
|
287
|
-
fields: {
|
|
288
|
-
backupCodes: 'backup_codes',
|
|
289
|
-
userId: 'user_id',
|
|
290
|
-
},
|
|
291
|
-
} as const;
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* Two-Factor plugin adds a `twoFactorEnabled` field to the user model.
|
|
295
|
-
*/
|
|
296
|
-
export const AUTH_TWO_FACTOR_USER_FIELDS = {
|
|
297
|
-
twoFactorEnabled: 'two_factor_enabled',
|
|
298
|
-
} as const;
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* Builds the `schema` option for better-auth's `twoFactor()` plugin.
|
|
302
|
-
*
|
|
303
|
-
* @returns An object suitable for `twoFactor({ schema: … })`
|
|
304
|
-
*/
|
|
305
|
-
export function buildTwoFactorPluginSchema() {
|
|
306
|
-
return {
|
|
307
|
-
twoFactor: AUTH_TWO_FACTOR_SCHEMA,
|
|
308
|
-
user: {
|
|
309
|
-
fields: AUTH_TWO_FACTOR_USER_FIELDS,
|
|
310
|
-
},
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// ---------------------------------------------------------------------------
|
|
315
|
-
// Helper: build organization plugin schema option
|
|
316
|
-
// ---------------------------------------------------------------------------
|
|
317
|
-
|
|
318
|
-
/**
|
|
319
|
-
* Builds the `schema` option for better-auth's `organization()` plugin.
|
|
320
|
-
*
|
|
321
|
-
* The organization plugin accepts a `schema` sub-option that allows
|
|
322
|
-
* customising model names and field names for each table it manages.
|
|
323
|
-
* This helper assembles the correct snake_case mappings from the
|
|
324
|
-
* individual `AUTH_*_SCHEMA` constants above.
|
|
325
|
-
*
|
|
326
|
-
* @returns An object suitable for `organization({ schema: … })`
|
|
327
|
-
*/
|
|
328
|
-
export function buildOrganizationPluginSchema() {
|
|
329
|
-
return {
|
|
330
|
-
organization: AUTH_ORGANIZATION_SCHEMA,
|
|
331
|
-
member: AUTH_MEMBER_SCHEMA,
|
|
332
|
-
invitation: AUTH_INVITATION_SCHEMA,
|
|
333
|
-
team: AUTH_TEAM_SCHEMA,
|
|
334
|
-
teamMember: AUTH_TEAM_MEMBER_SCHEMA,
|
|
335
|
-
session: {
|
|
336
|
-
fields: AUTH_ORG_SESSION_FIELDS,
|
|
337
|
-
},
|
|
338
|
-
};
|
|
339
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @objectstack/plugin-auth
|
|
5
|
-
*
|
|
6
|
-
* Authentication & Identity Plugin for ObjectStack
|
|
7
|
-
* Powered by better-auth for robust, secure authentication
|
|
8
|
-
* Uses ObjectQL for data persistence (no third-party ORM required)
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
export * from './auth-plugin.js';
|
|
12
|
-
export * from './auth-manager.js';
|
|
13
|
-
export * from './objectql-adapter.js';
|
|
14
|
-
export * from './auth-schema-config.js';
|
|
15
|
-
export * from './objects/index.js';
|
|
16
|
-
export type { AuthConfig, AuthProviderConfig, AuthPluginConfig } from '@objectstack/spec/system';
|