@objectstack/plugin-auth 3.0.7 → 3.0.9

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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @objectstack/plugin-auth@3.0.7 build /home/runner/work/spec/spec/packages/plugins/plugin-auth
2
+ > @objectstack/plugin-auth@3.0.9 build /home/runner/work/spec/spec/packages/plugins/plugin-auth
3
3
  > tsup --config ../../../tsup.config.ts
4
4
 
5
5
  CLI Building entry: src/index.ts
@@ -10,13 +10,13 @@
10
10
  CLI Cleaning output folder
11
11
  ESM Build start
12
12
  CJS Build start
13
- CJS dist/index.js 19.59 KB
14
- CJS dist/index.js.map 40.10 KB
15
- CJS ⚡️ Build success in 68ms
16
- ESM dist/index.mjs 18.00 KB
17
- ESM dist/index.mjs.map 39.55 KB
18
- ESM ⚡️ Build success in 68ms
13
+ ESM dist/index.mjs 18.56 KB
14
+ ESM dist/index.mjs.map 40.85 KB
15
+ ESM ⚡️ Build success in 75ms
16
+ CJS dist/index.js 20.30 KB
17
+ CJS dist/index.js.map 41.41 KB
18
+ CJS ⚡️ Build success in 76ms
19
19
  DTS Build start
20
- DTS ⚡️ Build success in 6470ms
21
- DTS dist/index.d.mts 134.31 KB
22
- DTS dist/index.d.ts 134.31 KB
20
+ DTS ⚡️ Build success in 6422ms
21
+ DTS dist/index.d.mts 135.12 KB
22
+ DTS dist/index.d.ts 135.12 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.0.9
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [15e0df6]
8
+ - @objectstack/spec@3.0.9
9
+ - @objectstack/core@3.0.9
10
+
11
+ ## 3.0.8
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies [5a968a2]
16
+ - @objectstack/spec@3.0.8
17
+ - @objectstack/core@3.0.8
18
+
3
19
  ## 3.0.7
4
20
 
5
21
  ### Patch Changes
package/README.md CHANGED
@@ -34,10 +34,10 @@ Authentication & Identity Plugin for ObjectStack.
34
34
  - ✅ **No Third-Party ORM** - No dependency on drizzle-orm or other ORMs
35
35
  - ✅ **Better-Auth Native Schema** - Uses better-auth's naming conventions for seamless migration
36
36
  - ✅ **Object Definitions** - Auth objects defined using ObjectStack's Object Protocol
37
- - `user` - User accounts (better-auth native table name)
38
- - `session` - Active sessions (better-auth native table name)
39
- - `account` - OAuth provider accounts (better-auth native table name)
40
- - `verification` - Email/phone verification tokens (better-auth native table name)
37
+ - `sys_user` - User accounts (protocol name, mapped from better-auth's `user`)
38
+ - `sys_session` - Active sessions (protocol name, mapped from better-auth's `session`)
39
+ - `sys_account` - OAuth provider accounts (protocol name, mapped from better-auth's `account`)
40
+ - `sys_verification` - Email/phone verification tokens (protocol name, mapped from better-auth's `verification`)
41
41
  - ✅ **ObjectQL Adapter** - Custom adapter bridges better-auth to ObjectQL
42
42
 
43
43
  The plugin uses [better-auth](https://www.better-auth.com/) for robust, production-ready authentication functionality. All requests are forwarded directly to better-auth's universal handler, ensuring full compatibility with all better-auth features. Data persistence is handled by ObjectQL using **ObjectStack's snake_case naming conventions** for field names to maintain consistency across the platform.
@@ -187,7 +187,7 @@ The plugin uses **ObjectQL** for data persistence instead of third-party ORMs:
187
187
  ```typescript
188
188
  // Object definitions use ObjectStack's snake_case naming conventions
189
189
  export const AuthUser = ObjectSchema.create({
190
- name: 'user', // better-auth compatible table name
190
+ name: 'sys_user', // ObjectStack protocol name (better-auth model 'user' is mapped automatically)
191
191
  fields: {
192
192
  id: Field.text({ label: 'User ID', required: true }),
193
193
  email: Field.email({ label: 'Email', required: true }),
@@ -213,19 +213,25 @@ export const AuthUser = ObjectSchema.create({
213
213
  - ✅ **Compatible Schema** - Uses better-auth compatible table structure with ObjectStack's snake_case field naming
214
214
 
215
215
  **Database Objects:**
216
- Uses better-auth compatible table names with ObjectStack's snake_case field naming:
217
- - `user` - User accounts (id, email, name, email_verified, created_at, etc.)
218
- - `session` - Active sessions (id, token, user_id, expires_at, ip_address, etc.)
219
- - `account` - OAuth provider accounts (id, provider_id, account_id, user_id, tokens, etc.)
220
- - `verification` - Verification tokens (id, value, identifier, expires_at, etc.)
216
+ Uses ObjectStack `sys_` prefixed protocol names with snake_case field naming.
217
+ The adapter automatically maps better-auth model names to protocol names:
218
+ - `sys_user` (← better-auth `user`) - User accounts (id, email, name, email_verified, created_at, etc.)
219
+ - `sys_session` (← better-auth `session`) - Active sessions (id, token, user_id, expires_at, ip_address, etc.)
220
+ - `sys_account` (← better-auth `account`) - OAuth provider accounts (id, provider_id, account_id, user_id, tokens, etc.)
221
+ - `sys_verification` (← better-auth `verification`) - Verification tokens (id, value, identifier, expires_at, etc.)
221
222
 
222
223
  **Adapter:**
223
- The `createObjectQLAdapter()` function bridges better-auth's database interface to ObjectQL's IDataEngine with field name transformation:
224
+ The `createObjectQLAdapter()` function bridges better-auth's database interface to ObjectQL's IDataEngine. It includes a model→protocol name mapping (`AUTH_MODEL_TO_PROTOCOL`) that translates better-auth's hardcoded model names (e.g. `user`) to ObjectStack protocol names (e.g. `sys_user`):
224
225
 
225
226
  ```typescript
226
- // Better-auth → ObjectQL Adapter (handles snake_case transformation)
227
+ // Better-auth → ObjectQL Adapter (handles model name mapping + field transformation)
228
+ import { createObjectQLAdapter, AUTH_MODEL_TO_PROTOCOL } from '@objectstack/plugin-auth';
229
+
227
230
  const adapter = createObjectQLAdapter(dataEngine);
228
231
 
232
+ // Mapping: { user: 'sys_user', session: 'sys_session', account: 'sys_account', verification: 'sys_verification' }
233
+ console.log(AUTH_MODEL_TO_PROTOCOL);
234
+
229
235
  // Better-auth uses this adapter for all database operations
230
236
  const auth = betterAuth({
231
237
  database: adapter,
package/dist/index.d.mts CHANGED
@@ -2038,6 +2038,18 @@ declare class AuthManager {
2038
2038
  }>;
2039
2039
  }
2040
2040
 
2041
+ /**
2042
+ * Mapping from better-auth model names to ObjectStack protocol object names.
2043
+ *
2044
+ * better-auth uses hardcoded model names ('user', 'session', 'account', 'verification')
2045
+ * while ObjectStack's protocol layer uses `sys_` prefixed names. This map bridges the two.
2046
+ */
2047
+ declare const AUTH_MODEL_TO_PROTOCOL: Record<string, string>;
2048
+ /**
2049
+ * Resolve a better-auth model name to the ObjectStack protocol object name.
2050
+ * Falls back to the original model name for custom / non-core models.
2051
+ */
2052
+ declare function resolveProtocolName(model: string): string;
2041
2053
  /**
2042
2054
  * ObjectQL Adapter for better-auth
2043
2055
  *
@@ -2045,7 +2057,8 @@ declare class AuthManager {
2045
2057
  * This allows better-auth to use ObjectQL for data persistence instead of
2046
2058
  * third-party ORMs like drizzle-orm.
2047
2059
  *
2048
- * Uses better-auth's native naming conventions (camelCase) for seamless migration.
2060
+ * Model names from better-auth (e.g. 'user') are automatically mapped to
2061
+ * ObjectStack protocol names (e.g. 'sys_user') via {@link AUTH_MODEL_TO_PROTOCOL}.
2049
2062
  *
2050
2063
  * @param dataEngine - ObjectQL data engine instance
2051
2064
  * @returns better-auth CustomAdapter
@@ -2179,6 +2192,7 @@ declare const AuthUser: {
2179
2192
  label?: string | undefined;
2180
2193
  description?: string | undefined;
2181
2194
  format?: string | undefined;
2195
+ columnName?: string | undefined;
2182
2196
  defaultValue?: unknown;
2183
2197
  maxLength?: number | undefined;
2184
2198
  minLength?: number | undefined;
@@ -2457,6 +2471,7 @@ declare const AuthSession: {
2457
2471
  label?: string | undefined;
2458
2472
  description?: string | undefined;
2459
2473
  format?: string | undefined;
2474
+ columnName?: string | undefined;
2460
2475
  defaultValue?: unknown;
2461
2476
  maxLength?: number | undefined;
2462
2477
  minLength?: number | undefined;
@@ -2740,6 +2755,7 @@ declare const AuthAccount: {
2740
2755
  label?: string | undefined;
2741
2756
  description?: string | undefined;
2742
2757
  format?: string | undefined;
2758
+ columnName?: string | undefined;
2743
2759
  defaultValue?: unknown;
2744
2760
  maxLength?: number | undefined;
2745
2761
  minLength?: number | undefined;
@@ -3016,6 +3032,7 @@ declare const AuthVerification: {
3016
3032
  label?: string | undefined;
3017
3033
  description?: string | undefined;
3018
3034
  format?: string | undefined;
3035
+ columnName?: string | undefined;
3019
3036
  defaultValue?: unknown;
3020
3037
  maxLength?: number | undefined;
3021
3038
  minLength?: number | undefined;
@@ -3258,4 +3275,4 @@ declare const AuthVerification: {
3258
3275
  keyPrefix?: string | undefined;
3259
3276
  };
3260
3277
 
3261
- export { AuthAccount, AuthManager, type AuthManagerOptions, AuthPlugin, type AuthPluginOptions, AuthSession, AuthUser, AuthVerification, createObjectQLAdapter };
3278
+ export { AUTH_MODEL_TO_PROTOCOL, AuthAccount, AuthManager, type AuthManagerOptions, AuthPlugin, type AuthPluginOptions, AuthSession, AuthUser, AuthVerification, createObjectQLAdapter, resolveProtocolName };
package/dist/index.d.ts CHANGED
@@ -2038,6 +2038,18 @@ declare class AuthManager {
2038
2038
  }>;
2039
2039
  }
2040
2040
 
2041
+ /**
2042
+ * Mapping from better-auth model names to ObjectStack protocol object names.
2043
+ *
2044
+ * better-auth uses hardcoded model names ('user', 'session', 'account', 'verification')
2045
+ * while ObjectStack's protocol layer uses `sys_` prefixed names. This map bridges the two.
2046
+ */
2047
+ declare const AUTH_MODEL_TO_PROTOCOL: Record<string, string>;
2048
+ /**
2049
+ * Resolve a better-auth model name to the ObjectStack protocol object name.
2050
+ * Falls back to the original model name for custom / non-core models.
2051
+ */
2052
+ declare function resolveProtocolName(model: string): string;
2041
2053
  /**
2042
2054
  * ObjectQL Adapter for better-auth
2043
2055
  *
@@ -2045,7 +2057,8 @@ declare class AuthManager {
2045
2057
  * This allows better-auth to use ObjectQL for data persistence instead of
2046
2058
  * third-party ORMs like drizzle-orm.
2047
2059
  *
2048
- * Uses better-auth's native naming conventions (camelCase) for seamless migration.
2060
+ * Model names from better-auth (e.g. 'user') are automatically mapped to
2061
+ * ObjectStack protocol names (e.g. 'sys_user') via {@link AUTH_MODEL_TO_PROTOCOL}.
2049
2062
  *
2050
2063
  * @param dataEngine - ObjectQL data engine instance
2051
2064
  * @returns better-auth CustomAdapter
@@ -2179,6 +2192,7 @@ declare const AuthUser: {
2179
2192
  label?: string | undefined;
2180
2193
  description?: string | undefined;
2181
2194
  format?: string | undefined;
2195
+ columnName?: string | undefined;
2182
2196
  defaultValue?: unknown;
2183
2197
  maxLength?: number | undefined;
2184
2198
  minLength?: number | undefined;
@@ -2457,6 +2471,7 @@ declare const AuthSession: {
2457
2471
  label?: string | undefined;
2458
2472
  description?: string | undefined;
2459
2473
  format?: string | undefined;
2474
+ columnName?: string | undefined;
2460
2475
  defaultValue?: unknown;
2461
2476
  maxLength?: number | undefined;
2462
2477
  minLength?: number | undefined;
@@ -2740,6 +2755,7 @@ declare const AuthAccount: {
2740
2755
  label?: string | undefined;
2741
2756
  description?: string | undefined;
2742
2757
  format?: string | undefined;
2758
+ columnName?: string | undefined;
2743
2759
  defaultValue?: unknown;
2744
2760
  maxLength?: number | undefined;
2745
2761
  minLength?: number | undefined;
@@ -3016,6 +3032,7 @@ declare const AuthVerification: {
3016
3032
  label?: string | undefined;
3017
3033
  description?: string | undefined;
3018
3034
  format?: string | undefined;
3035
+ columnName?: string | undefined;
3019
3036
  defaultValue?: unknown;
3020
3037
  maxLength?: number | undefined;
3021
3038
  minLength?: number | undefined;
@@ -3258,4 +3275,4 @@ declare const AuthVerification: {
3258
3275
  keyPrefix?: string | undefined;
3259
3276
  };
3260
3277
 
3261
- export { AuthAccount, AuthManager, type AuthManagerOptions, AuthPlugin, type AuthPluginOptions, AuthSession, AuthUser, AuthVerification, createObjectQLAdapter };
3278
+ export { AUTH_MODEL_TO_PROTOCOL, AuthAccount, AuthManager, type AuthManagerOptions, AuthPlugin, type AuthPluginOptions, AuthSession, AuthUser, AuthVerification, createObjectQLAdapter, resolveProtocolName };
package/dist/index.js CHANGED
@@ -20,13 +20,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ AUTH_MODEL_TO_PROTOCOL: () => AUTH_MODEL_TO_PROTOCOL,
23
24
  AuthAccount: () => AuthAccount,
24
25
  AuthManager: () => AuthManager,
25
26
  AuthPlugin: () => AuthPlugin,
26
27
  AuthSession: () => AuthSession,
27
28
  AuthUser: () => AuthUser,
28
29
  AuthVerification: () => AuthVerification,
29
- createObjectQLAdapter: () => createObjectQLAdapter
30
+ createObjectQLAdapter: () => createObjectQLAdapter,
31
+ resolveProtocolName: () => resolveProtocolName
30
32
  });
31
33
  module.exports = __toCommonJS(index_exports);
32
34
 
@@ -34,6 +36,16 @@ module.exports = __toCommonJS(index_exports);
34
36
  var import_better_auth = require("better-auth");
35
37
 
36
38
  // src/objectql-adapter.ts
39
+ var import_system = require("@objectstack/spec/system");
40
+ var AUTH_MODEL_TO_PROTOCOL = {
41
+ user: import_system.SystemObjectName.USER,
42
+ session: import_system.SystemObjectName.SESSION,
43
+ account: import_system.SystemObjectName.ACCOUNT,
44
+ verification: import_system.SystemObjectName.VERIFICATION
45
+ };
46
+ function resolveProtocolName(model) {
47
+ return AUTH_MODEL_TO_PROTOCOL[model] ?? model;
48
+ }
37
49
  function createObjectQLAdapter(dataEngine) {
38
50
  function convertWhere(where) {
39
51
  const filter = {};
@@ -61,12 +73,12 @@ function createObjectQLAdapter(dataEngine) {
61
73
  }
62
74
  return {
63
75
  create: async ({ model, data, select: _select }) => {
64
- const objectName = model;
76
+ const objectName = resolveProtocolName(model);
65
77
  const result = await dataEngine.insert(objectName, data);
66
78
  return result;
67
79
  },
68
80
  findOne: async ({ model, where, select, join: _join }) => {
69
- const objectName = model;
81
+ const objectName = resolveProtocolName(model);
70
82
  const filter = convertWhere(where);
71
83
  const result = await dataEngine.findOne(objectName, {
72
84
  filter,
@@ -75,7 +87,7 @@ function createObjectQLAdapter(dataEngine) {
75
87
  return result ? result : null;
76
88
  },
77
89
  findMany: async ({ model, where, limit, offset, sortBy, join: _join }) => {
78
- const objectName = model;
90
+ const objectName = resolveProtocolName(model);
79
91
  const filter = where ? convertWhere(where) : {};
80
92
  const sort = sortBy ? [{
81
93
  field: sortBy.field,
@@ -90,12 +102,12 @@ function createObjectQLAdapter(dataEngine) {
90
102
  return results;
91
103
  },
92
104
  count: async ({ model, where }) => {
93
- const objectName = model;
105
+ const objectName = resolveProtocolName(model);
94
106
  const filter = where ? convertWhere(where) : {};
95
107
  return await dataEngine.count(objectName, { filter });
96
108
  },
97
109
  update: async ({ model, where, update }) => {
98
- const objectName = model;
110
+ const objectName = resolveProtocolName(model);
99
111
  const filter = convertWhere(where);
100
112
  const record = await dataEngine.findOne(objectName, { filter });
101
113
  if (!record) {
@@ -108,7 +120,7 @@ function createObjectQLAdapter(dataEngine) {
108
120
  return result ? result : null;
109
121
  },
110
122
  updateMany: async ({ model, where, update }) => {
111
- const objectName = model;
123
+ const objectName = resolveProtocolName(model);
112
124
  const filter = convertWhere(where);
113
125
  const records = await dataEngine.find(objectName, { filter });
114
126
  for (const record of records) {
@@ -120,7 +132,7 @@ function createObjectQLAdapter(dataEngine) {
120
132
  return records.length;
121
133
  },
122
134
  delete: async ({ model, where }) => {
123
- const objectName = model;
135
+ const objectName = resolveProtocolName(model);
124
136
  const filter = convertWhere(where);
125
137
  const record = await dataEngine.findOne(objectName, { filter });
126
138
  if (!record) {
@@ -129,7 +141,7 @@ function createObjectQLAdapter(dataEngine) {
129
141
  await dataEngine.delete(objectName, { filter: { id: record.id } });
130
142
  },
131
143
  deleteMany: async ({ model, where }) => {
132
- const objectName = model;
144
+ const objectName = resolveProtocolName(model);
133
145
  const filter = convertWhere(where);
134
146
  const records = await dataEngine.find(objectName, { filter });
135
147
  for (const record of records) {
@@ -362,7 +374,7 @@ var AuthPlugin = class {
362
374
  // src/objects/auth-user.object.ts
363
375
  var import_data = require("@objectstack/spec/data");
364
376
  var AuthUser = import_data.ObjectSchema.create({
365
- name: "user",
377
+ name: "sys_user",
366
378
  label: "User",
367
379
  pluralLabel: "Users",
368
380
  icon: "user",
@@ -436,7 +448,7 @@ var AuthUser = import_data.ObjectSchema.create({
436
448
  // src/objects/auth-session.object.ts
437
449
  var import_data2 = require("@objectstack/spec/data");
438
450
  var AuthSession = import_data2.ObjectSchema.create({
439
- name: "session",
451
+ name: "sys_session",
440
452
  label: "Session",
441
453
  pluralLabel: "Sessions",
442
454
  icon: "key",
@@ -505,7 +517,7 @@ var AuthSession = import_data2.ObjectSchema.create({
505
517
  // src/objects/auth-account.object.ts
506
518
  var import_data3 = require("@objectstack/spec/data");
507
519
  var AuthAccount = import_data3.ObjectSchema.create({
508
- name: "account",
520
+ name: "sys_account",
509
521
  label: "Account",
510
522
  pluralLabel: "Accounts",
511
523
  icon: "link",
@@ -592,7 +604,7 @@ var AuthAccount = import_data3.ObjectSchema.create({
592
604
  // src/objects/auth-verification.object.ts
593
605
  var import_data4 = require("@objectstack/spec/data");
594
606
  var AuthVerification = import_data4.ObjectSchema.create({
595
- name: "verification",
607
+ name: "sys_verification",
596
608
  label: "Verification",
597
609
  pluralLabel: "Verifications",
598
610
  icon: "shield-check",
@@ -650,12 +662,14 @@ var AuthVerification = import_data4.ObjectSchema.create({
650
662
  });
651
663
  // Annotate the CommonJS export names for ESM import in node:
652
664
  0 && (module.exports = {
665
+ AUTH_MODEL_TO_PROTOCOL,
653
666
  AuthAccount,
654
667
  AuthManager,
655
668
  AuthPlugin,
656
669
  AuthSession,
657
670
  AuthUser,
658
671
  AuthVerification,
659
- createObjectQLAdapter
672
+ createObjectQLAdapter,
673
+ resolveProtocolName
660
674
  });
661
675
  //# sourceMappingURL=index.js.map
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 // 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 * - created_at: Date\n * - updated_at: Date\n * - email: string (unique, lowercase)\n * - email_verified: 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', 'email_verified'],\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 created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updated_at: 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 email_verified: 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: ['created_at'], 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 * - created_at: Date\n * - updated_at: Date\n * - user_id: string\n * - expires_at: Date\n * - token: string\n * - ip_address: string | null\n * - user_agent: 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: ['user_id', 'expires_at', 'ip_address'],\n \n fields: {\n id: Field.text({\n label: 'Session ID',\n required: true,\n readonly: true,\n }),\n \n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n user_id: Field.text({\n label: 'User ID',\n required: true,\n }),\n \n expires_at: 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 ip_address: Field.text({\n label: 'IP Address',\n required: false,\n maxLength: 45, // Support IPv6\n }),\n \n user_agent: 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: ['user_id'], unique: false },\n { fields: ['expires_at'], 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 * - created_at: Date\n * - updated_at: Date\n * - provider_id: string (e.g., 'google', 'github')\n * - account_id: string (provider's user ID)\n * - user_id: string (link to user table)\n * - access_token: string | null\n * - refresh_token: string | null\n * - id_token: string | null\n * - access_token_expires_at: Date | null\n * - refresh_token_expires_at: 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: '{provider_id} - {account_id}',\n compactLayout: ['provider_id', 'user_id', 'account_id'],\n \n fields: {\n id: Field.text({\n label: 'Account ID',\n required: true,\n readonly: true,\n }),\n \n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n provider_id: Field.text({\n label: 'Provider ID',\n required: true,\n description: 'OAuth provider identifier (google, github, etc.)',\n }),\n \n account_id: Field.text({\n label: 'Provider Account ID',\n required: true,\n description: \"User's ID in the provider's system\",\n }),\n \n user_id: Field.text({\n label: 'User ID',\n required: true,\n description: 'Link to user table',\n }),\n \n access_token: Field.textarea({\n label: 'Access Token',\n required: false,\n }),\n \n refresh_token: Field.textarea({\n label: 'Refresh Token',\n required: false,\n }),\n \n id_token: Field.textarea({\n label: 'ID Token',\n required: false,\n }),\n \n access_token_expires_at: Field.datetime({\n label: 'Access Token Expires At',\n required: false,\n }),\n \n refresh_token_expires_at: 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: ['user_id'], unique: false },\n { fields: ['provider_id', 'account_id'], 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 * - created_at: Date\n * - updated_at: Date\n * - value: string (verification token/code)\n * - expires_at: 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', 'expires_at', 'created_at'],\n \n fields: {\n id: Field.text({\n label: 'Verification ID',\n required: true,\n readonly: true,\n }),\n \n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updated_at: 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 expires_at: 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: ['expires_at'], 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';\nimport { SystemObjectName } from '@objectstack/spec/system';\n\n/**\n * Mapping from better-auth model names to ObjectStack protocol object names.\n *\n * better-auth uses hardcoded model names ('user', 'session', 'account', 'verification')\n * while ObjectStack's protocol layer uses `sys_` prefixed names. This map bridges the two.\n */\nexport const AUTH_MODEL_TO_PROTOCOL: Record<string, string> = {\n user: SystemObjectName.USER,\n session: SystemObjectName.SESSION,\n account: SystemObjectName.ACCOUNT,\n verification: SystemObjectName.VERIFICATION,\n};\n\n/**\n * Resolve a better-auth model name to the ObjectStack protocol object name.\n * Falls back to the original model name for custom / non-core models.\n */\nexport function resolveProtocolName(model: string): string {\n return AUTH_MODEL_TO_PROTOCOL[model] ?? model;\n}\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 * Model names from better-auth (e.g. 'user') are automatically mapped to\n * ObjectStack protocol names (e.g. 'sys_user') via {@link AUTH_MODEL_TO_PROTOCOL}.\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 const objectName = resolveProtocolName(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 = resolveProtocolName(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 = resolveProtocolName(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 = resolveProtocolName(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 = resolveProtocolName(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 = resolveProtocolName(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 = resolveProtocolName(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 = resolveProtocolName(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 * - created_at: Date\n * - updated_at: Date\n * - email: string (unique, lowercase)\n * - email_verified: boolean\n * - name: string\n * - image: string | null\n */\nexport const AuthUser = ObjectSchema.create({\n name: 'sys_user',\n label: 'User',\n pluralLabel: 'Users',\n icon: 'user',\n description: 'User accounts for authentication',\n titleFormat: '{name} ({email})',\n compactLayout: ['name', 'email', 'email_verified'],\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 created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updated_at: 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 email_verified: 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: ['created_at'], 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 * - created_at: Date\n * - updated_at: Date\n * - user_id: string\n * - expires_at: Date\n * - token: string\n * - ip_address: string | null\n * - user_agent: string | null\n */\nexport const AuthSession = ObjectSchema.create({\n name: 'sys_session',\n label: 'Session',\n pluralLabel: 'Sessions',\n icon: 'key',\n description: 'Active user sessions',\n titleFormat: 'Session {token}',\n compactLayout: ['user_id', 'expires_at', 'ip_address'],\n \n fields: {\n id: Field.text({\n label: 'Session ID',\n required: true,\n readonly: true,\n }),\n \n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n user_id: Field.text({\n label: 'User ID',\n required: true,\n }),\n \n expires_at: 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 ip_address: Field.text({\n label: 'IP Address',\n required: false,\n maxLength: 45, // Support IPv6\n }),\n \n user_agent: 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: ['user_id'], unique: false },\n { fields: ['expires_at'], 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 * - created_at: Date\n * - updated_at: Date\n * - provider_id: string (e.g., 'google', 'github')\n * - account_id: string (provider's user ID)\n * - user_id: string (link to user table)\n * - access_token: string | null\n * - refresh_token: string | null\n * - id_token: string | null\n * - access_token_expires_at: Date | null\n * - refresh_token_expires_at: Date | null\n * - scope: string | null\n * - password: string | null (for email/password provider)\n */\nexport const AuthAccount = ObjectSchema.create({\n name: 'sys_account',\n label: 'Account',\n pluralLabel: 'Accounts',\n icon: 'link',\n description: 'OAuth and authentication provider accounts',\n titleFormat: '{provider_id} - {account_id}',\n compactLayout: ['provider_id', 'user_id', 'account_id'],\n \n fields: {\n id: Field.text({\n label: 'Account ID',\n required: true,\n readonly: true,\n }),\n \n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n provider_id: Field.text({\n label: 'Provider ID',\n required: true,\n description: 'OAuth provider identifier (google, github, etc.)',\n }),\n \n account_id: Field.text({\n label: 'Provider Account ID',\n required: true,\n description: \"User's ID in the provider's system\",\n }),\n \n user_id: Field.text({\n label: 'User ID',\n required: true,\n description: 'Link to user table',\n }),\n \n access_token: Field.textarea({\n label: 'Access Token',\n required: false,\n }),\n \n refresh_token: Field.textarea({\n label: 'Refresh Token',\n required: false,\n }),\n \n id_token: Field.textarea({\n label: 'ID Token',\n required: false,\n }),\n \n access_token_expires_at: Field.datetime({\n label: 'Access Token Expires At',\n required: false,\n }),\n \n refresh_token_expires_at: 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: ['user_id'], unique: false },\n { fields: ['provider_id', 'account_id'], 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 * - created_at: Date\n * - updated_at: Date\n * - value: string (verification token/code)\n * - expires_at: Date\n * - identifier: string (email or phone number)\n */\nexport const AuthVerification = ObjectSchema.create({\n name: 'sys_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', 'expires_at', 'created_at'],\n \n fields: {\n id: Field.text({\n label: 'Verification ID',\n required: true,\n readonly: true,\n }),\n \n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updated_at: 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 expires_at: 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: ['expires_at'], 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
@@ -2,6 +2,16 @@
2
2
  import { betterAuth } from "better-auth";
3
3
 
4
4
  // src/objectql-adapter.ts
5
+ import { SystemObjectName } from "@objectstack/spec/system";
6
+ var AUTH_MODEL_TO_PROTOCOL = {
7
+ user: SystemObjectName.USER,
8
+ session: SystemObjectName.SESSION,
9
+ account: SystemObjectName.ACCOUNT,
10
+ verification: SystemObjectName.VERIFICATION
11
+ };
12
+ function resolveProtocolName(model) {
13
+ return AUTH_MODEL_TO_PROTOCOL[model] ?? model;
14
+ }
5
15
  function createObjectQLAdapter(dataEngine) {
6
16
  function convertWhere(where) {
7
17
  const filter = {};
@@ -29,12 +39,12 @@ function createObjectQLAdapter(dataEngine) {
29
39
  }
30
40
  return {
31
41
  create: async ({ model, data, select: _select }) => {
32
- const objectName = model;
42
+ const objectName = resolveProtocolName(model);
33
43
  const result = await dataEngine.insert(objectName, data);
34
44
  return result;
35
45
  },
36
46
  findOne: async ({ model, where, select, join: _join }) => {
37
- const objectName = model;
47
+ const objectName = resolveProtocolName(model);
38
48
  const filter = convertWhere(where);
39
49
  const result = await dataEngine.findOne(objectName, {
40
50
  filter,
@@ -43,7 +53,7 @@ function createObjectQLAdapter(dataEngine) {
43
53
  return result ? result : null;
44
54
  },
45
55
  findMany: async ({ model, where, limit, offset, sortBy, join: _join }) => {
46
- const objectName = model;
56
+ const objectName = resolveProtocolName(model);
47
57
  const filter = where ? convertWhere(where) : {};
48
58
  const sort = sortBy ? [{
49
59
  field: sortBy.field,
@@ -58,12 +68,12 @@ function createObjectQLAdapter(dataEngine) {
58
68
  return results;
59
69
  },
60
70
  count: async ({ model, where }) => {
61
- const objectName = model;
71
+ const objectName = resolveProtocolName(model);
62
72
  const filter = where ? convertWhere(where) : {};
63
73
  return await dataEngine.count(objectName, { filter });
64
74
  },
65
75
  update: async ({ model, where, update }) => {
66
- const objectName = model;
76
+ const objectName = resolveProtocolName(model);
67
77
  const filter = convertWhere(where);
68
78
  const record = await dataEngine.findOne(objectName, { filter });
69
79
  if (!record) {
@@ -76,7 +86,7 @@ function createObjectQLAdapter(dataEngine) {
76
86
  return result ? result : null;
77
87
  },
78
88
  updateMany: async ({ model, where, update }) => {
79
- const objectName = model;
89
+ const objectName = resolveProtocolName(model);
80
90
  const filter = convertWhere(where);
81
91
  const records = await dataEngine.find(objectName, { filter });
82
92
  for (const record of records) {
@@ -88,7 +98,7 @@ function createObjectQLAdapter(dataEngine) {
88
98
  return records.length;
89
99
  },
90
100
  delete: async ({ model, where }) => {
91
- const objectName = model;
101
+ const objectName = resolveProtocolName(model);
92
102
  const filter = convertWhere(where);
93
103
  const record = await dataEngine.findOne(objectName, { filter });
94
104
  if (!record) {
@@ -97,7 +107,7 @@ function createObjectQLAdapter(dataEngine) {
97
107
  await dataEngine.delete(objectName, { filter: { id: record.id } });
98
108
  },
99
109
  deleteMany: async ({ model, where }) => {
100
- const objectName = model;
110
+ const objectName = resolveProtocolName(model);
101
111
  const filter = convertWhere(where);
102
112
  const records = await dataEngine.find(objectName, { filter });
103
113
  for (const record of records) {
@@ -330,7 +340,7 @@ var AuthPlugin = class {
330
340
  // src/objects/auth-user.object.ts
331
341
  import { ObjectSchema, Field } from "@objectstack/spec/data";
332
342
  var AuthUser = ObjectSchema.create({
333
- name: "user",
343
+ name: "sys_user",
334
344
  label: "User",
335
345
  pluralLabel: "Users",
336
346
  icon: "user",
@@ -404,7 +414,7 @@ var AuthUser = ObjectSchema.create({
404
414
  // src/objects/auth-session.object.ts
405
415
  import { ObjectSchema as ObjectSchema2, Field as Field2 } from "@objectstack/spec/data";
406
416
  var AuthSession = ObjectSchema2.create({
407
- name: "session",
417
+ name: "sys_session",
408
418
  label: "Session",
409
419
  pluralLabel: "Sessions",
410
420
  icon: "key",
@@ -473,7 +483,7 @@ var AuthSession = ObjectSchema2.create({
473
483
  // src/objects/auth-account.object.ts
474
484
  import { ObjectSchema as ObjectSchema3, Field as Field3 } from "@objectstack/spec/data";
475
485
  var AuthAccount = ObjectSchema3.create({
476
- name: "account",
486
+ name: "sys_account",
477
487
  label: "Account",
478
488
  pluralLabel: "Accounts",
479
489
  icon: "link",
@@ -560,7 +570,7 @@ var AuthAccount = ObjectSchema3.create({
560
570
  // src/objects/auth-verification.object.ts
561
571
  import { ObjectSchema as ObjectSchema4, Field as Field4 } from "@objectstack/spec/data";
562
572
  var AuthVerification = ObjectSchema4.create({
563
- name: "verification",
573
+ name: "sys_verification",
564
574
  label: "Verification",
565
575
  pluralLabel: "Verifications",
566
576
  icon: "shield-check",
@@ -617,12 +627,14 @@ var AuthVerification = ObjectSchema4.create({
617
627
  }
618
628
  });
619
629
  export {
630
+ AUTH_MODEL_TO_PROTOCOL,
620
631
  AuthAccount,
621
632
  AuthManager,
622
633
  AuthPlugin,
623
634
  AuthSession,
624
635
  AuthUser,
625
636
  AuthVerification,
626
- createObjectQLAdapter
637
+ createObjectQLAdapter,
638
+ resolveProtocolName
627
639
  };
628
640
  //# sourceMappingURL=index.mjs.map
@@ -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 // 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 * - created_at: Date\n * - updated_at: Date\n * - email: string (unique, lowercase)\n * - email_verified: 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', 'email_verified'],\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 created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updated_at: 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 email_verified: 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: ['created_at'], 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 * - created_at: Date\n * - updated_at: Date\n * - user_id: string\n * - expires_at: Date\n * - token: string\n * - ip_address: string | null\n * - user_agent: 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: ['user_id', 'expires_at', 'ip_address'],\n \n fields: {\n id: Field.text({\n label: 'Session ID',\n required: true,\n readonly: true,\n }),\n \n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n user_id: Field.text({\n label: 'User ID',\n required: true,\n }),\n \n expires_at: 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 ip_address: Field.text({\n label: 'IP Address',\n required: false,\n maxLength: 45, // Support IPv6\n }),\n \n user_agent: 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: ['user_id'], unique: false },\n { fields: ['expires_at'], 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 * - created_at: Date\n * - updated_at: Date\n * - provider_id: string (e.g., 'google', 'github')\n * - account_id: string (provider's user ID)\n * - user_id: string (link to user table)\n * - access_token: string | null\n * - refresh_token: string | null\n * - id_token: string | null\n * - access_token_expires_at: Date | null\n * - refresh_token_expires_at: 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: '{provider_id} - {account_id}',\n compactLayout: ['provider_id', 'user_id', 'account_id'],\n \n fields: {\n id: Field.text({\n label: 'Account ID',\n required: true,\n readonly: true,\n }),\n \n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n provider_id: Field.text({\n label: 'Provider ID',\n required: true,\n description: 'OAuth provider identifier (google, github, etc.)',\n }),\n \n account_id: Field.text({\n label: 'Provider Account ID',\n required: true,\n description: \"User's ID in the provider's system\",\n }),\n \n user_id: Field.text({\n label: 'User ID',\n required: true,\n description: 'Link to user table',\n }),\n \n access_token: Field.textarea({\n label: 'Access Token',\n required: false,\n }),\n \n refresh_token: Field.textarea({\n label: 'Refresh Token',\n required: false,\n }),\n \n id_token: Field.textarea({\n label: 'ID Token',\n required: false,\n }),\n \n access_token_expires_at: Field.datetime({\n label: 'Access Token Expires At',\n required: false,\n }),\n \n refresh_token_expires_at: 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: ['user_id'], unique: false },\n { fields: ['provider_id', 'account_id'], 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 * - created_at: Date\n * - updated_at: Date\n * - value: string (verification token/code)\n * - expires_at: 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', 'expires_at', 'created_at'],\n \n fields: {\n id: Field.text({\n label: 'Verification ID',\n required: true,\n readonly: true,\n }),\n \n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updated_at: 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 expires_at: 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: ['expires_at'], 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';\nimport { SystemObjectName } from '@objectstack/spec/system';\n\n/**\n * Mapping from better-auth model names to ObjectStack protocol object names.\n *\n * better-auth uses hardcoded model names ('user', 'session', 'account', 'verification')\n * while ObjectStack's protocol layer uses `sys_` prefixed names. This map bridges the two.\n */\nexport const AUTH_MODEL_TO_PROTOCOL: Record<string, string> = {\n user: SystemObjectName.USER,\n session: SystemObjectName.SESSION,\n account: SystemObjectName.ACCOUNT,\n verification: SystemObjectName.VERIFICATION,\n};\n\n/**\n * Resolve a better-auth model name to the ObjectStack protocol object name.\n * Falls back to the original model name for custom / non-core models.\n */\nexport function resolveProtocolName(model: string): string {\n return AUTH_MODEL_TO_PROTOCOL[model] ?? model;\n}\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 * Model names from better-auth (e.g. 'user') are automatically mapped to\n * ObjectStack protocol names (e.g. 'sys_user') via {@link AUTH_MODEL_TO_PROTOCOL}.\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 const objectName = resolveProtocolName(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 = resolveProtocolName(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 = resolveProtocolName(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 = resolveProtocolName(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 = resolveProtocolName(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 = resolveProtocolName(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 = resolveProtocolName(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 = resolveProtocolName(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 * - created_at: Date\n * - updated_at: Date\n * - email: string (unique, lowercase)\n * - email_verified: boolean\n * - name: string\n * - image: string | null\n */\nexport const AuthUser = ObjectSchema.create({\n name: 'sys_user',\n label: 'User',\n pluralLabel: 'Users',\n icon: 'user',\n description: 'User accounts for authentication',\n titleFormat: '{name} ({email})',\n compactLayout: ['name', 'email', 'email_verified'],\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 created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updated_at: 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 email_verified: 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: ['created_at'], 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 * - created_at: Date\n * - updated_at: Date\n * - user_id: string\n * - expires_at: Date\n * - token: string\n * - ip_address: string | null\n * - user_agent: string | null\n */\nexport const AuthSession = ObjectSchema.create({\n name: 'sys_session',\n label: 'Session',\n pluralLabel: 'Sessions',\n icon: 'key',\n description: 'Active user sessions',\n titleFormat: 'Session {token}',\n compactLayout: ['user_id', 'expires_at', 'ip_address'],\n \n fields: {\n id: Field.text({\n label: 'Session ID',\n required: true,\n readonly: true,\n }),\n \n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n user_id: Field.text({\n label: 'User ID',\n required: true,\n }),\n \n expires_at: 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 ip_address: Field.text({\n label: 'IP Address',\n required: false,\n maxLength: 45, // Support IPv6\n }),\n \n user_agent: 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: ['user_id'], unique: false },\n { fields: ['expires_at'], 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 * - created_at: Date\n * - updated_at: Date\n * - provider_id: string (e.g., 'google', 'github')\n * - account_id: string (provider's user ID)\n * - user_id: string (link to user table)\n * - access_token: string | null\n * - refresh_token: string | null\n * - id_token: string | null\n * - access_token_expires_at: Date | null\n * - refresh_token_expires_at: Date | null\n * - scope: string | null\n * - password: string | null (for email/password provider)\n */\nexport const AuthAccount = ObjectSchema.create({\n name: 'sys_account',\n label: 'Account',\n pluralLabel: 'Accounts',\n icon: 'link',\n description: 'OAuth and authentication provider accounts',\n titleFormat: '{provider_id} - {account_id}',\n compactLayout: ['provider_id', 'user_id', 'account_id'],\n \n fields: {\n id: Field.text({\n label: 'Account ID',\n required: true,\n readonly: true,\n }),\n \n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n provider_id: Field.text({\n label: 'Provider ID',\n required: true,\n description: 'OAuth provider identifier (google, github, etc.)',\n }),\n \n account_id: Field.text({\n label: 'Provider Account ID',\n required: true,\n description: \"User's ID in the provider's system\",\n }),\n \n user_id: Field.text({\n label: 'User ID',\n required: true,\n description: 'Link to user table',\n }),\n \n access_token: Field.textarea({\n label: 'Access Token',\n required: false,\n }),\n \n refresh_token: Field.textarea({\n label: 'Refresh Token',\n required: false,\n }),\n \n id_token: Field.textarea({\n label: 'ID Token',\n required: false,\n }),\n \n access_token_expires_at: Field.datetime({\n label: 'Access Token Expires At',\n required: false,\n }),\n \n refresh_token_expires_at: 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: ['user_id'], unique: false },\n { fields: ['provider_id', 'account_id'], 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 * - created_at: Date\n * - updated_at: Date\n * - value: string (verification token/code)\n * - expires_at: Date\n * - identifier: string (email or phone number)\n */\nexport const AuthVerification = ObjectSchema.create({\n name: 'sys_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', 'expires_at', 'created_at'],\n \n fields: {\n id: Field.text({\n label: 'Verification ID',\n required: true,\n readonly: true,\n }),\n \n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n \n updated_at: 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 expires_at: 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: ['expires_at'], 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,20 +1,20 @@
1
1
  {
2
2
  "name": "@objectstack/plugin-auth",
3
- "version": "3.0.7",
3
+ "version": "3.0.9",
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": "3.0.7",
11
- "@objectstack/spec": "3.0.7"
10
+ "@objectstack/core": "3.0.9",
11
+ "@objectstack/spec": "3.0.9"
12
12
  },
13
13
  "devDependencies": {
14
14
  "@types/node": "^25.2.3",
15
15
  "typescript": "^5.0.0",
16
16
  "vitest": "^4.0.18",
17
- "@objectstack/cli": "3.0.7"
17
+ "@objectstack/cli": "3.0.9"
18
18
  },
19
19
  "scripts": {
20
20
  "build": "tsup --config ../../../tsup.config.ts",
@@ -0,0 +1,113 @@
1
+ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
+
3
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
4
+ import {
5
+ createObjectQLAdapter,
6
+ AUTH_MODEL_TO_PROTOCOL,
7
+ resolveProtocolName,
8
+ } from './objectql-adapter';
9
+ import { SystemObjectName } from '@objectstack/spec/system';
10
+ import type { IDataEngine } from '@objectstack/core';
11
+
12
+ describe('AUTH_MODEL_TO_PROTOCOL mapping', () => {
13
+ it('should map all four core better-auth models to sys_ protocol names', () => {
14
+ expect(AUTH_MODEL_TO_PROTOCOL.user).toBe('sys_user');
15
+ expect(AUTH_MODEL_TO_PROTOCOL.session).toBe('sys_session');
16
+ expect(AUTH_MODEL_TO_PROTOCOL.account).toBe('sys_account');
17
+ expect(AUTH_MODEL_TO_PROTOCOL.verification).toBe('sys_verification');
18
+ });
19
+
20
+ it('should align with SystemObjectName constants', () => {
21
+ expect(AUTH_MODEL_TO_PROTOCOL.user).toBe(SystemObjectName.USER);
22
+ expect(AUTH_MODEL_TO_PROTOCOL.session).toBe(SystemObjectName.SESSION);
23
+ expect(AUTH_MODEL_TO_PROTOCOL.account).toBe(SystemObjectName.ACCOUNT);
24
+ expect(AUTH_MODEL_TO_PROTOCOL.verification).toBe(SystemObjectName.VERIFICATION);
25
+ });
26
+ });
27
+
28
+ describe('resolveProtocolName', () => {
29
+ it('should resolve core models to sys_ prefixed names', () => {
30
+ expect(resolveProtocolName('user')).toBe('sys_user');
31
+ expect(resolveProtocolName('session')).toBe('sys_session');
32
+ expect(resolveProtocolName('account')).toBe('sys_account');
33
+ expect(resolveProtocolName('verification')).toBe('sys_verification');
34
+ });
35
+
36
+ it('should fall back to original name for unknown models', () => {
37
+ expect(resolveProtocolName('organization')).toBe('organization');
38
+ expect(resolveProtocolName('custom_model')).toBe('custom_model');
39
+ });
40
+ });
41
+
42
+ describe('createObjectQLAdapter – model name mapping', () => {
43
+ let mockEngine: IDataEngine;
44
+
45
+ beforeEach(() => {
46
+ mockEngine = {
47
+ insert: vi.fn().mockResolvedValue({ id: '1' }),
48
+ findOne: vi.fn().mockResolvedValue({ id: '1' }),
49
+ find: vi.fn().mockResolvedValue([]),
50
+ count: vi.fn().mockResolvedValue(0),
51
+ update: vi.fn().mockResolvedValue({ id: '1' }),
52
+ delete: vi.fn().mockResolvedValue(undefined),
53
+ } as unknown as IDataEngine;
54
+ });
55
+
56
+ it('create: should call dataEngine.insert with sys_ protocol name', async () => {
57
+ const adapter = createObjectQLAdapter(mockEngine);
58
+ await adapter.create({ model: 'user', data: { email: 'a@b.com' } });
59
+ expect(mockEngine.insert).toHaveBeenCalledWith('sys_user', { email: 'a@b.com' });
60
+ });
61
+
62
+ it('findOne: should call dataEngine.findOne with sys_ protocol name', async () => {
63
+ const adapter = createObjectQLAdapter(mockEngine);
64
+ await adapter.findOne({
65
+ model: 'session',
66
+ where: [{ field: 'token', value: 'abc', operator: 'eq', connector: 'AND' }],
67
+ });
68
+ expect(mockEngine.findOne).toHaveBeenCalledWith('sys_session', expect.objectContaining({
69
+ filter: { token: 'abc' },
70
+ }));
71
+ });
72
+
73
+ it('findMany: should call dataEngine.find with sys_ protocol name', async () => {
74
+ const adapter = createObjectQLAdapter(mockEngine);
75
+ await adapter.findMany({ model: 'account', limit: 10 });
76
+ expect(mockEngine.find).toHaveBeenCalledWith('sys_account', expect.objectContaining({
77
+ limit: 10,
78
+ }));
79
+ });
80
+
81
+ it('count: should call dataEngine.count with sys_ protocol name', async () => {
82
+ const adapter = createObjectQLAdapter(mockEngine);
83
+ await adapter.count({ model: 'verification' });
84
+ expect(mockEngine.count).toHaveBeenCalledWith('sys_verification', expect.anything());
85
+ });
86
+
87
+ it('update: should call dataEngine with sys_ protocol name', async () => {
88
+ const adapter = createObjectQLAdapter(mockEngine);
89
+ await adapter.update({
90
+ model: 'user',
91
+ where: [{ field: 'id', value: '1', operator: 'eq', connector: 'AND' }],
92
+ update: { name: 'New' },
93
+ });
94
+ expect(mockEngine.findOne).toHaveBeenCalledWith('sys_user', expect.anything());
95
+ expect(mockEngine.update).toHaveBeenCalledWith('sys_user', expect.objectContaining({ name: 'New', id: '1' }));
96
+ });
97
+
98
+ it('delete: should call dataEngine with sys_ protocol name', async () => {
99
+ const adapter = createObjectQLAdapter(mockEngine);
100
+ await adapter.delete({
101
+ model: 'session',
102
+ where: [{ field: 'id', value: '1', operator: 'eq', connector: 'AND' }],
103
+ });
104
+ expect(mockEngine.findOne).toHaveBeenCalledWith('sys_session', expect.anything());
105
+ expect(mockEngine.delete).toHaveBeenCalledWith('sys_session', expect.anything());
106
+ });
107
+
108
+ it('should pass through unknown model names unchanged', async () => {
109
+ const adapter = createObjectQLAdapter(mockEngine);
110
+ await adapter.create({ model: 'organization', data: { name: 'Acme' } });
111
+ expect(mockEngine.insert).toHaveBeenCalledWith('organization', { name: 'Acme' });
112
+ });
113
+ });
@@ -2,6 +2,28 @@
2
2
 
3
3
  import type { IDataEngine } from '@objectstack/core';
4
4
  import type { CleanedWhere } from 'better-auth/adapters';
5
+ import { SystemObjectName } from '@objectstack/spec/system';
6
+
7
+ /**
8
+ * Mapping from better-auth model names to ObjectStack protocol object names.
9
+ *
10
+ * better-auth uses hardcoded model names ('user', 'session', 'account', 'verification')
11
+ * while ObjectStack's protocol layer uses `sys_` prefixed names. This map bridges the two.
12
+ */
13
+ export const AUTH_MODEL_TO_PROTOCOL: Record<string, string> = {
14
+ user: SystemObjectName.USER,
15
+ session: SystemObjectName.SESSION,
16
+ account: SystemObjectName.ACCOUNT,
17
+ verification: SystemObjectName.VERIFICATION,
18
+ };
19
+
20
+ /**
21
+ * Resolve a better-auth model name to the ObjectStack protocol object name.
22
+ * Falls back to the original model name for custom / non-core models.
23
+ */
24
+ export function resolveProtocolName(model: string): string {
25
+ return AUTH_MODEL_TO_PROTOCOL[model] ?? model;
26
+ }
5
27
 
6
28
  /**
7
29
  * ObjectQL Adapter for better-auth
@@ -10,7 +32,8 @@ import type { CleanedWhere } from 'better-auth/adapters';
10
32
  * This allows better-auth to use ObjectQL for data persistence instead of
11
33
  * third-party ORMs like drizzle-orm.
12
34
  *
13
- * Uses better-auth's native naming conventions (camelCase) for seamless migration.
35
+ * Model names from better-auth (e.g. 'user') are automatically mapped to
36
+ * ObjectStack protocol names (e.g. 'sys_user') via {@link AUTH_MODEL_TO_PROTOCOL}.
14
37
  *
15
38
  * @param dataEngine - ObjectQL data engine instance
16
39
  * @returns better-auth CustomAdapter
@@ -50,8 +73,7 @@ export function createObjectQLAdapter(dataEngine: IDataEngine) {
50
73
 
51
74
  return {
52
75
  create: async <T extends Record<string, any>>({ model, data, select: _select }: { model: string; data: T; select?: string[] }): Promise<T> => {
53
- // Use model name as-is (no conversion needed)
54
- const objectName = model;
76
+ const objectName = resolveProtocolName(model);
55
77
 
56
78
  // Note: select parameter is currently not supported by ObjectQL's insert operation
57
79
  // The full record is always returned after insertion
@@ -60,7 +82,7 @@ export function createObjectQLAdapter(dataEngine: IDataEngine) {
60
82
  },
61
83
 
62
84
  findOne: async <T>({ model, where, select, join: _join }: { model: string; where: CleanedWhere[]; select?: string[]; join?: any }): Promise<T | null> => {
63
- const objectName = model;
85
+ const objectName = resolveProtocolName(model);
64
86
  const filter = convertWhere(where);
65
87
 
66
88
  // Note: join parameter is not currently supported by ObjectQL's findOne operation
@@ -76,7 +98,7 @@ export function createObjectQLAdapter(dataEngine: IDataEngine) {
76
98
  },
77
99
 
78
100
  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[]> => {
79
- const objectName = model;
101
+ const objectName = resolveProtocolName(model);
80
102
  const filter = where ? convertWhere(where) : {};
81
103
 
82
104
  // Note: join parameter is not currently supported by ObjectQL's find operation
@@ -98,14 +120,14 @@ export function createObjectQLAdapter(dataEngine: IDataEngine) {
98
120
  },
99
121
 
100
122
  count: async ({ model, where }: { model: string; where?: CleanedWhere[] }): Promise<number> => {
101
- const objectName = model;
123
+ const objectName = resolveProtocolName(model);
102
124
  const filter = where ? convertWhere(where) : {};
103
125
 
104
126
  return await dataEngine.count(objectName, { filter });
105
127
  },
106
128
 
107
129
  update: async <T>({ model, where, update }: { model: string; where: CleanedWhere[]; update: Record<string, any> }): Promise<T | null> => {
108
- const objectName = model;
130
+ const objectName = resolveProtocolName(model);
109
131
  const filter = convertWhere(where);
110
132
 
111
133
  // Find the record first to get its ID
@@ -123,7 +145,7 @@ export function createObjectQLAdapter(dataEngine: IDataEngine) {
123
145
  },
124
146
 
125
147
  updateMany: async ({ model, where, update }: { model: string; where: CleanedWhere[]; update: Record<string, any> }): Promise<number> => {
126
- const objectName = model;
148
+ const objectName = resolveProtocolName(model);
127
149
  const filter = convertWhere(where);
128
150
 
129
151
  // Note: Sequential updates are used here because ObjectQL's IDataEngine interface
@@ -145,7 +167,7 @@ export function createObjectQLAdapter(dataEngine: IDataEngine) {
145
167
  },
146
168
 
147
169
  delete: async ({ model, where }: { model: string; where: CleanedWhere[] }): Promise<void> => {
148
- const objectName = model;
170
+ const objectName = resolveProtocolName(model);
149
171
  const filter = convertWhere(where);
150
172
 
151
173
  // Note: We need to find the record first to get its ID because ObjectQL's
@@ -160,7 +182,7 @@ export function createObjectQLAdapter(dataEngine: IDataEngine) {
160
182
  },
161
183
 
162
184
  deleteMany: async ({ model, where }: { model: string; where: CleanedWhere[] }): Promise<number> => {
163
- const objectName = model;
185
+ const objectName = resolveProtocolName(model);
164
186
  const filter = convertWhere(where);
165
187
 
166
188
  // Note: Sequential deletes are used here because ObjectQL's delete operation
@@ -21,7 +21,7 @@ import { ObjectSchema, Field } from '@objectstack/spec/data';
21
21
  * - password: string | null (for email/password provider)
22
22
  */
23
23
  export const AuthAccount = ObjectSchema.create({
24
- name: 'account',
24
+ name: 'sys_account',
25
25
  label: 'Account',
26
26
  pluralLabel: 'Accounts',
27
27
  icon: 'link',
@@ -16,7 +16,7 @@ import { ObjectSchema, Field } from '@objectstack/spec/data';
16
16
  * - user_agent: string | null
17
17
  */
18
18
  export const AuthSession = ObjectSchema.create({
19
- name: 'session',
19
+ name: 'sys_session',
20
20
  label: 'Session',
21
21
  pluralLabel: 'Sessions',
22
22
  icon: 'key',
@@ -15,7 +15,7 @@ import { ObjectSchema, Field } from '@objectstack/spec/data';
15
15
  * - image: string | null
16
16
  */
17
17
  export const AuthUser = ObjectSchema.create({
18
- name: 'user',
18
+ name: 'sys_user',
19
19
  label: 'User',
20
20
  pluralLabel: 'Users',
21
21
  icon: 'user',
@@ -14,7 +14,7 @@ import { ObjectSchema, Field } from '@objectstack/spec/data';
14
14
  * - identifier: string (email or phone number)
15
15
  */
16
16
  export const AuthVerification = ObjectSchema.create({
17
- name: 'verification',
17
+ name: 'sys_verification',
18
18
  label: 'Verification',
19
19
  pluralLabel: 'Verifications',
20
20
  icon: 'shield-check',