{"version":3,"sources":["../src/auth-plugin.ts","../src/auth-manager.ts","../src/objectql-adapter.ts","../src/auth-schema-config.ts","../src/set-initial-password.ts","../src/manifest.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { Plugin, PluginContext, IHttpServer } from '@objectstack/core';\nimport type { BetterAuthOptions } from 'better-auth';\nimport { AuthConfig, type SocialProviderConfig, SystemObjectName, SystemUserId } from '@objectstack/spec/system';\nimport {\n  // ADR-0048 — the Setup/Studio/Account apps moved to their own packages\n  // (@objectstack/{setup,studio,account}); plugin-auth no longer registers them.\n  SystemOverviewDashboard,\n  SystemOverviewDatasets,\n} from '@objectstack/platform-objects/apps';\nimport { SysOrganizationDetailPage, SysUserDetailPage } from '@objectstack/platform-objects/pages';\nimport { AuthManager, type AuthManagerOptions } from './auth-manager.js';\nimport { runSetInitialPassword } from './set-initial-password.js';\nimport {\n  authIdentityObjects,\n  authPluginManifestHeader,\n} from './manifest.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   * Override the datasource that owns the identity tables (sys_user,\n   * sys_session, …) when AuthPlugin's manifest is registered.\n   *\n   * Defaults to `'cloud'` (control-plane DB) so the historical\n   * single-tenant control-plane behaviour is preserved. Per-project\n   * kernels in objectos pass `'default'` so identity tables live in the\n   * project's own database — each project owns its own users.\n   */\n  manifestDatasource?: string;\n\n  /**\n   * Application-specific organization roles to register with Better-Auth's\n   * organization plugin so invitations to those roles aren't rejected with\n   * ROLE_NOT_FOUND. Forwarded as-is to AuthManager. See\n   * {@link AuthManagerOptions.additionalOrgRoles} for details.\n   */\n  additionalOrgRoles?: string[];\n\n  /**\n   * Pass-through to better-auth's `databaseHooks` option. Used by\n   * platform consumers (objectos kernel) to attach a\n   * `user.create.after` hook that auto-provisions a personal\n   * organization for JIT-created SSO users — better-auth's adapter\n   * bypasses kernel-level ObjectQL middleware, so this is the only\n   * hook point that fires for every user creation path (email signup,\n   * social/OIDC sign-in, admin-created accounts).\n   */\n  databaseHooks?: BetterAuthOptions['databaseHooks'];\n}\n\n/**\n * Authentication Plugin\n * \n * Provides authentication and identity services for ObjectStack applications.\n * \n * **Dual-Mode Operation:**\n * - **Server mode** (HonoServerPlugin active): Registers HTTP routes at basePath,\n *   forwarding all auth requests to better-auth's universal handler.\n * - **MSW/Mock mode** (no HTTP server): Gracefully skips route registration but\n *   still registers the `auth` service, allowing HttpDispatcher.handleAuth() to\n *   simulate auth flows (sign-up, sign-in, etc.) for development and testing.\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) — always\n * - `app.com.objectstack.system` service (system object definitions) — always\n * - HTTP routes for authentication endpoints — only when HTTP server is available\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: string[] = ['com.objectstack.engine.objectql']; // manifest service required\n  \n  private options: AuthPluginOptions;\n  private authManager: AuthManager | null = null;\n  private configuredSocialProviders: SocialProviderConfig | undefined;\n\n  constructor(options: AuthPluginOptions = {}) {\n    this.options = {\n      registerRoutes: true,\n      basePath: '/api/v1/auth',\n      ...options\n    };\n  }\n\n  /**\n   * Open-source provider fallback: enable Google sign-in from conventional\n   * provider env vars when the application did not configure Google itself.\n   * Enterprise / product packages can contribute richer provider sets through\n   * the `auth:configure` hook below.\n   */\n  private applyEnvSocialProviderFallbacks(config: AuthManagerOptions & AuthPluginOptions): void {\n    const env = (globalThis as any)?.process?.env as Record<string, string | undefined> | undefined;\n    if (String(env?.OS_AUTH_GOOGLE_ENABLED ?? 'true').toLowerCase() === 'false') return;\n    const googleClientId = env?.GOOGLE_CLIENT_ID;\n    const googleClientSecret = env?.GOOGLE_CLIENT_SECRET;\n    if (!googleClientId || !googleClientSecret) return;\n\n    const socialProviders = {\n      ...(config.socialProviders ?? {}),\n    } as NonNullable<AuthPluginOptions['socialProviders']>;\n\n    if (!socialProviders.google) {\n      socialProviders.google = {\n        clientId: googleClientId,\n        clientSecret: googleClientSecret,\n        enabled: true,\n      };\n      config.socialProviders = socialProviders;\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    const authConfig: AuthManagerOptions & AuthPluginOptions = {\n      ...this.options,\n      dataEngine,\n    };\n    this.applyEnvSocialProviderFallbacks(authConfig);\n\n    // Open extension point for packages that contribute auth providers\n    // (enterprise SSO, hosted control-plane SSO, etc.) without forking\n    // framework's AuthPlugin. Handlers mutate the draft config in place.\n    await ctx.trigger('auth:configure', authConfig, ctx);\n    this.configuredSocialProviders = authConfig.socialProviders\n      ? { ...authConfig.socialProviders }\n      : undefined;\n\n    // Initialize auth manager with data engine\n    this.authManager = new AuthManager(authConfig);\n\n    // Register auth service\n    ctx.registerService('auth', this.authManager);\n\n    ctx.getService<{ register(m: any): void }>('manifest').register({\n      ...authPluginManifestHeader,\n      ...(this.options.manifestDatasource\n        ? { defaultDatasource: this.options.manifestDatasource }\n        : {}),\n      objects: authIdentityObjects,\n      // ADR-0048 — Setup/Studio/Account apps (and the Setup nav contributions)\n      // moved to their own one-app packages (@objectstack/{setup,studio,account}),\n      // each registering under its own package id so /apps/<packageId> resolves\n      // unambiguously. plugin-auth keeps only the auth objects + their pages.\n      // Slotted record-detail pages for system objects — currently\n      // sys_organization gets a Members / Invitations / Teams tab strip\n      // (see SysOrganizationDetailPage for the rationale and the\n      // intentionally-omitted OAuth / SSO tabs).\n      pages: [SysOrganizationDetailPage, SysUserDetailPage],\n      // List views for each Setup-nav object are defined on the schema\n      // itself via the canonical `listViews` map (e.g.\n      // sys_user.listViews.{all_users,unverified,two_factor}). Registering\n      // top-level views here is the legacy pre-M10.30c pattern — it caused\n      // duplicate \"Users\"/\"Roles\"/\"Sessions\" tabs to appear alongside the\n      // schema-derived ones, sometimes referencing nonexistent fields\n      // (e.g. legacy `users.view` had phone/status/active columns that do\n      // not exist on sys_user). Schema-embedded listViews is the single\n      // source of truth.\n      dashboards: [SystemOverviewDashboard],\n      // ADR-0021 — datasets backing the System Overview dashboard's widgets.\n      datasets: SystemOverviewDatasets,\n    });\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    // Setup App translations are now loaded by `PlatformObjectsPlugin`\n    // (in @objectstack/platform-objects). Translation bundles belong with\n    // the package that defines them; auth-plugin no longer piggy-backs on\n    // its kernel:ready hook for this.\n\n    // Defer HTTP route registration to kernel:ready hook.\n    // This ensures all plugins (including HonoServerPlugin) have completed\n    // their init and start phases before we attempt to look up the\n    // http-server service — making AuthPlugin resilient to plugin\n    // loading order.\n    if (this.options.registerRoutes) {\n      ctx.hook('kernel:ready', async () => {\n        // Inject the email service if available so better-auth callbacks\n        // (sendResetPassword / sendVerificationEmail / sendInvitationEmail\n        // / sendMagicLink) can actually deliver mail. Resolved here on\n        // kernel:ready so EmailServicePlugin has had a chance to register.\n        if (this.authManager) {\n          await this.bindAuthSettings(ctx);\n\n          try {\n            const emailSvc = ctx.getService<any>('email');\n            if (emailSvc) {\n              this.authManager.setEmailService(emailSvc);\n              ctx.logger.info('Auth: email service wired (transactional mail enabled)');\n            }\n          } catch {\n            ctx.logger.info('Auth: no email service registered — auth callbacks will log instead of sending');\n          }\n\n          // Bind the email brand name (`{{appName}}`) to the live\n          // `branding.workspace_name` setting so the admin UI can rename the\n          // product without a redeploy. Only an *explicitly set* value\n          // overrides the configured `appName` — when the operator hasn't\n          // customised it (resolver returns the manifest default), we clear\n          // the override so the deployment's `appName` (e.g. `OS_APP_NAME`)\n          // keeps precedence. Mirrors EmailServicePlugin's settings binding.\n          try {\n            const settings = ctx.getService<any>('settings');\n            if (settings && typeof settings.get === 'function') {\n              const applyBrand = async () => {\n                try {\n                  const resolved = await settings.get('branding', 'workspace_name', {});\n                  const explicit = resolved && resolved.source !== 'default'\n                    ? resolved.value\n                    : undefined;\n                  this.authManager?.setAppName(\n                    typeof explicit === 'string' ? explicit : undefined,\n                  );\n                } catch (err: any) {\n                  ctx.logger.warn(\n                    'Auth: failed to apply branding.workspace_name: ' + (err?.message ?? err),\n                  );\n                }\n              };\n              await applyBrand();\n              if (typeof settings.subscribe === 'function') {\n                settings.subscribe('branding', () => {\n                  void applyBrand();\n                });\n                ctx.logger.info('Auth: bound appName to settings namespace=branding');\n              }\n            }\n          } catch {\n            // settings service is optional — keep the configured appName.\n          }\n        }\n\n        let httpServer: IHttpServer | null = null;\n        try {\n          httpServer = ctx.getService<IHttpServer>('http-server');\n        } catch {\n          // Service not found — expected in MSW/mock mode\n        }\n\n        if (httpServer) {\n          // Auto-detect the actual server URL when no explicit baseUrl was\n          // configured, or when the configured baseUrl uses a different port\n          // than the running server (e.g. port 3000 configured but 3002 bound).\n          // getPort() is optional on IHttpServer; duck-type check for it.\n          const serverWithPort = httpServer as IHttpServer & { getPort?: () => number };\n          if (this.authManager && typeof serverWithPort.getPort === 'function') {\n            const actualPort = serverWithPort.getPort();\n            if (actualPort) {\n              const configuredUrl = this.options.baseUrl || 'http://localhost:3000';\n              const configuredOrigin = new URL(configuredUrl).origin;\n              const actualUrl = `http://localhost:${actualPort}`;\n\n              // Only auto-correct the port when the configured URL is already a\n              // localhost URL (development mode). In production (Vercel/cloud) the\n              // configured baseUrl is the real public hostname — never overwrite it\n              // with a localhost URL, which would break OAuth callback URLs.\n              const configuredIsLocalhost = configuredOrigin.startsWith('http://localhost');\n              if (configuredIsLocalhost && configuredOrigin !== actualUrl) {\n                this.authManager.setRuntimeBaseUrl(actualUrl);\n                ctx.logger.info(\n                  `Auth baseUrl auto-updated to ${actualUrl} (configured: ${configuredUrl})`,\n                );\n              }\n            }\n          }\n\n          // Route registration errors should propagate (server misconfiguration)\n          this.registerAuthRoutes(httpServer, ctx);\n          ctx.logger.info(`Auth routes registered at ${this.options.basePath}`);\n        } else {\n          ctx.logger.warn(\n            'No HTTP server available — auth routes not registered. ' +\n            'Auth service is still available for MSW/mock environments via HttpDispatcher.'\n          );\n        }\n      });\n    }\n\n    // Dev-only: provision a known, loginable platform admin on an empty DB.\n    // Registered as its own kernel:ready hook (independent of registerRoutes)\n    // so it runs whenever the runtime boots in development.\n    ctx.hook('kernel:ready', async () => {\n      await this.maybeSeedDevAdmin(ctx);\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  /**\n   * Bind the small open-source auth settings namespace to better-auth config.\n   *\n   * Only explicit settings values (stored or OS_AUTH_* env overrides) affect\n   * runtime config. Manifest defaults are UI defaults and do not mask code or\n   * deployment configuration.\n   */\n  private async bindAuthSettings(ctx: PluginContext): Promise<void> {\n    if (!this.authManager) return;\n\n    let settings: any;\n    try {\n      settings = ctx.getService<any>('settings');\n    } catch {\n      return;\n    }\n    if (!settings || typeof settings.getNamespace !== 'function') return;\n\n    const applySettings = async (): Promise<void> => {\n      if (!this.authManager) return;\n      try {\n        const payload = await settings.getNamespace('auth');\n        const values: Record<string, unknown> = {};\n        const sources: Record<string, string | undefined> = {};\n        for (const [key, entry] of Object.entries(payload.values as Record<string, any>)) {\n          values[key] = entry?.value;\n          sources[key] = entry?.source;\n        }\n\n        const isExplicit = (key: string) => (sources[key] ?? 'default') !== 'default';\n        const asBoolean = (value: unknown, fallback: boolean): boolean => {\n          if (typeof value === 'boolean') return value;\n          if (typeof value === 'string') return value.toLowerCase() !== 'false';\n          if (typeof value === 'number') return value !== 0;\n          return fallback;\n        };\n        const asTrimmedString = (value: unknown): string | undefined => {\n          if (typeof value !== 'string') return undefined;\n          const trimmed = value.trim();\n          return trimmed ? trimmed : undefined;\n        };\n        const asPositiveInt = (value: unknown): number | undefined => {\n          const n = Math.floor(Number(value));\n          return Number.isFinite(n) && n > 0 ? n : undefined;\n        };\n\n        const patch: Partial<AuthManagerOptions> = {};\n        const emailAndPassword: Partial<NonNullable<AuthConfig['emailAndPassword']>> = {};\n        if (isExplicit('email_password_enabled')) {\n          emailAndPassword.enabled = asBoolean(values.email_password_enabled, true);\n        }\n        if (isExplicit('signup_enabled')) {\n          emailAndPassword.disableSignUp = !asBoolean(values.signup_enabled, true);\n        }\n        if (isExplicit('require_email_verification')) {\n          emailAndPassword.requireEmailVerification = asBoolean(\n            values.require_email_verification,\n            false,\n          );\n        }\n        // Password policy — better-auth enforces these bounds on sign-up and\n        // password reset. Ignore malformed/non-positive values (keep the default).\n        if (isExplicit('password_min_length')) {\n          const n = asPositiveInt(values.password_min_length);\n          if (n !== undefined) emailAndPassword.minPasswordLength = n;\n        }\n        if (isExplicit('password_max_length')) {\n          const n = asPositiveInt(values.password_max_length);\n          if (n !== undefined) emailAndPassword.maxPasswordLength = n;\n        }\n        if (Object.keys(emailAndPassword).length > 0) {\n          patch.emailAndPassword = emailAndPassword as AuthManagerOptions['emailAndPassword'];\n        }\n\n        // Session lifetime — days → seconds for better-auth's `session`\n        // (`expiresIn` = absolute lifetime; `updateAge` = refresh threshold).\n        const session: { expiresIn?: number; updateAge?: number } = {};\n        if (isExplicit('session_expiry_days')) {\n          const d = asPositiveInt(values.session_expiry_days);\n          if (d !== undefined) session.expiresIn = d * 86_400;\n        }\n        if (isExplicit('session_refresh_days')) {\n          const d = asPositiveInt(values.session_refresh_days);\n          if (d !== undefined) session.updateAge = d * 86_400;\n        }\n        if (Object.keys(session).length > 0) {\n          patch.session = session as AuthManagerOptions['session'];\n        }\n\n        if (\n          isExplicit('google_enabled') ||\n          isExplicit('google_client_id') ||\n          isExplicit('google_client_secret')\n        ) {\n          const socialProviders = {\n            ...(this.configuredSocialProviders ?? {}),\n          } as NonNullable<SocialProviderConfig>;\n          const env = (globalThis as any)?.process?.env as Record<string, string | undefined> | undefined;\n          const googleEnabledFromEnv = env?.OS_AUTH_GOOGLE_ENABLED != null\n            ? asBoolean(env.OS_AUTH_GOOGLE_ENABLED, true)\n            : undefined;\n          const googleClientId = asTrimmedString(values.google_client_id) ?? env?.GOOGLE_CLIENT_ID;\n          const googleClientSecret = asTrimmedString(values.google_client_secret) ?? env?.GOOGLE_CLIENT_SECRET;\n          if (googleEnabledFromEnv ?? (isExplicit('google_enabled') ? asBoolean(values.google_enabled, true) : true)) {\n            if (!socialProviders.google && googleClientId && googleClientSecret) {\n              socialProviders.google = {\n                clientId: googleClientId,\n                clientSecret: googleClientSecret,\n                enabled: true,\n              };\n            }\n          } else {\n            delete socialProviders.google;\n          }\n          patch.socialProviders = Object.keys(socialProviders).length > 0\n            ? socialProviders\n            : undefined;\n        }\n\n        if (Object.keys(patch).length > 0) {\n          this.authManager.applyConfigPatch(patch);\n        }\n      } catch (err: any) {\n        ctx.logger.warn('Auth: failed to apply auth settings: ' + (err?.message ?? err));\n      }\n    };\n\n    await applySettings();\n    if (typeof settings.subscribe === 'function') {\n      settings.subscribe('auth', () => {\n        void applySettings();\n      });\n      ctx.logger.info('Auth: bound to settings namespace=auth');\n    }\n  }\n\n  async destroy(): Promise<void> {\n    // Cleanup if needed\n    this.authManager = null;\n  }\n\n  /**\n   * Dev-only admin bootstrap.\n   *\n   * On an EMPTY database (zero users), provision a well-known, loginable\n   * admin (admin@objectos.ai / admin123 by default) so backend debugging\n   * never blocks on a first-run sign-up wizard. The account is created\n   * through better-auth's real server-side `signUpEmail` pipeline (hashed\n   * credential + the same hooks the HTTP endpoint runs), so it is fully\n   * loginable; plugin-security's first-user middleware then promotes it to\n   * platform admin automatically.\n   *\n   * This replaces two earlier, divergent seeds:\n   *   • the CLI-side HTTP seed (`os dev`), which POSTed the public sign-up\n   *     endpoint from the parent process — racing server readiness and\n   *     targeting a hard-coded port that broke under dev port auto-shift; and\n   *   • plugin-dev's raw `sys_user` insert, which produced a credential-less,\n   *     un-loginable row.\n   * Running it in-process needs no port and no readiness polling.\n   *\n   * Idempotent and non-destructive: it only ever acts on a zero-user DB and\n   * never touches an existing account, so a custom password is never\n   * overwritten.\n   *\n   * HARD-GATED to development (NODE_ENV==='development'): a known-credential\n   * admin can never be provisioned in production. Opt out within dev via\n   * OS_SEED_ADMIN=0 (or false/off/no).\n   */\n  private async maybeSeedDevAdmin(ctx: PluginContext): Promise<void> {\n    if (process.env.NODE_ENV !== 'development') return;\n    const flag = String(process.env.OS_SEED_ADMIN ?? '').trim().toLowerCase();\n    if (['0', 'false', 'off', 'no'].includes(flag)) return;\n\n    const email = process.env.OS_SEED_ADMIN_EMAIL?.trim() || 'admin@objectos.ai';\n    const password = process.env.OS_SEED_ADMIN_PASSWORD?.trim() || 'admin123';\n    const name = process.env.OS_SEED_ADMIN_NAME?.trim() || 'Dev Admin';\n\n    let ql: any;\n    try { ql = ctx.getService<any>('objectql'); } catch { /* unavailable */ }\n    if (!ql || typeof ql.find !== 'function') return;\n\n    try {\n      // Only seed when no HUMAN user exists yet. A fresh DB still contains\n      // the system service account (SystemUserId.SYSTEM, role='system'),\n      // which must NOT count — mirror plugin-security's first-user detection\n      // so the seed fires on a genuinely empty DB. Any real human user (or a\n      // prior sign-up) disables the seed for good; we never touch or\n      // overwrite an existing account.\n      const rows = await ql\n        .find(SystemObjectName.USER, { where: {}, limit: 50 }, { context: { isSystem: true } })\n        .catch(() => []);\n      const humans = (Array.isArray(rows) ? rows : [])\n        .filter((u: any) => u && u.id !== SystemUserId.SYSTEM && u.role !== 'system');\n      if (humans.length > 0) {\n        ctx.logger.debug('[auth] dev admin seed skipped — a user already exists');\n        return;\n      }\n\n      if (!this.authManager) return;\n      const api: any = await this.authManager.getApi();\n      if (typeof api?.signUpEmail !== 'function') {\n        ctx.logger.warn('[auth] dev admin seed skipped — signUpEmail unavailable');\n        return;\n      }\n\n      // Real auth pipeline: creates sys_user + a hashed `credential` account\n      // and runs the sign-up hooks. The dev-mode OS_DISABLE_SIGNUP bypass\n      // (auth-manager.ts) lets this through on an empty DB even when sign-up\n      // is otherwise disabled.\n      await api.signUpEmail({ body: { email, password, name } });\n      ctx.logger.info(`🔑 Dev admin seeded: ${email} / ${password}`);\n      // Surface the credentials in the `serve` startup banner. The\n      // ctx.logger line above is swallowed by serve's boot-quiet window\n      // (the seed runs during runtime.start(), before stdout is restored),\n      // so the CLI reads this off the `auth` service and prints it after\n      // the banner instead.\n      this.authManager.devSeedResult = { email, password };\n    } catch (err: any) {\n      // Best-effort. The common benign case is a race where a real sign-up\n      // landed first (unique-email violation) — treat as \"already seeded\".\n      ctx.logger.warn(`[auth] dev admin seed skipped: ${err?.message ?? err}`);\n    }\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 /config before the wildcard so it takes precedence.\n    // better-auth has no /config endpoint, so without this explicit route\n    // the wildcard below forwards the request and better-auth returns 404.\n    rawApp.get(`${basePath}/config`, (c: any) => {\n      try {\n        const config = this.authManager!.getPublicConfig();\n        return c.json({ success: true, data: config });\n      } catch (error) {\n        const err = error instanceof Error ? error : new Error(String(error));\n        return c.json({ success: false, error: { code: 'auth_config_error', message: err.message } }, 500);\n      }\n    });\n\n    // Bootstrap status — does an owner exist yet? Used by the Account SPA's\n    // root route to decide between rendering /login (normal flow) and\n    // /setup (first-run owner creation). Public, unauthenticated; only\n    // returns a boolean so it can be polled before the user has any\n    // credentials.\n    rawApp.get(`${basePath}/bootstrap-status`, async (c: any) => {\n      try {\n        const dataEngine = this.authManager!.getDataEngine();\n        if (!dataEngine) {\n          // No data engine wired (e.g. MSW/mock mode) — assume bootstrapped\n          // so the SPA falls through to its normal login flow.\n          return c.json({ hasOwner: true });\n        }\n        const count = await dataEngine.count('sys_user', {});\n        return c.json({ hasOwner: (count ?? 0) > 0 });\n      } catch (error) {\n        ctx.logger.warn('[AuthPlugin] bootstrap-status check failed; assuming bootstrapped', error as Error);\n        return c.json({ hasOwner: true });\n      }\n    });\n\n    // Device Authorization Grant (RFC 8628) endpoints — `/device/code`,\n    // `/device/token`, `/device/approve`, `/device/deny`, `/device` — are\n    // provided by better-auth's `device-authorization` plugin and reach\n    // the wildcard handler below. Enable via\n    // `AuthPluginConfig.deviceAuthorization`.\n\n    // Set an INITIAL local password for users who signed in via SSO and\n    // have no `credential` account yet. This is the \"Set local password\"\n    // affordance on a per-environment kernel — it lets a user that the\n    // platform onboarded via the objectstack-cloud OAuth provider sign in\n    // with email/password against this environment going forward without\n    // needing the SSO round-trip. Requires a valid session (so we know\n    // which user is asking) and refuses if a credential already exists\n    // (the user should use better-auth's /change-password endpoint in\n    // that case so the current password is verified).\n    //\n    // The body is `runSetInitialPassword` (shared with the cloud\n    // AuthProxyPlugin) so both mount points wrap better-auth's server-only\n    // `auth.api.setPassword` identically — see set-initial-password.ts.\n    rawApp.post(`${basePath}/set-initial-password`, async (c: any) => {\n      try {\n        const authApi = await this.authManager!.getApi();\n        const { status, body } = await runSetInitialPassword(authApi as any, c.req.raw);\n        return c.json(body, status);\n      } catch (error) {\n        const err = error instanceof Error ? error : new Error(String(error));\n        ctx.logger.error('[AuthPlugin] set-initial-password failed', err);\n        return c.json({ success: false, error: { code: 'internal', message: err.message } }, 500);\n      }\n    });\n\n    // ────────────────────────────────────────────────────────────────────\n    // OAuth admin: toggle the `disabled` flag on a registered OAuth client.\n    //\n    // Why this lives here (and not as a plain data-layer UPDATE on\n    // sys_oauth_application): better-auth 1.6.11's stock admin update\n    // endpoint (`/admin/oauth2/update-client`) does NOT accept `disabled`\n    // in its Zod body schema, so the field gets silently stripped before\n    // it reaches `updateClientEndpoint`. The column exists, the runtime\n    // honours it everywhere (introspect, token, authorize, public-client\n    // lookup), but no client-facing API can flip it.\n    //\n    // We close the gap by writing through better-auth's own adapter under\n    // the `/api/v1/auth/*` namespace so all OAuth-application mutations\n    // remain auth-routed (no generic data-layer bypass for the `oauth_client`\n    // model). When upstream adds `disabled` to `adminUpdateOAuthClient`'s\n    // schema, this route can be deleted and the sys_oauth_application\n    // action retargeted to the stock endpoint.\n    //\n    // Upstream tracking: https://github.com/better-auth/better-auth\n    rawApp.post(`${basePath}/admin/oauth2/toggle-disabled`, async (c: any) => {\n      try {\n        let body: any = {};\n        try { body = await c.req.json(); } catch { body = {}; }\n        const clientId: unknown = body?.client_id;\n        const disabled: unknown = body?.disabled;\n        if (typeof clientId !== 'string' || clientId.length === 0) {\n          return c.json({ success: false, error: { code: 'invalid_request', message: 'client_id is required' } }, 400);\n        }\n        if (typeof disabled !== 'boolean') {\n          return c.json({ success: false, error: { code: 'invalid_request', message: 'disabled must be a boolean' } }, 400);\n        }\n\n        const authApi = await this.authManager!.getApi();\n        const session = await authApi.getSession({ headers: c.req.raw.headers });\n        if (!session?.user?.id) {\n          return c.json({ success: false, error: { code: 'unauthorized', message: 'Sign in first' } }, 401);\n        }\n        // The customSession plugin synthesizes `user.role = 'admin'` for\n        // platform admins (admin_full_access permission set) and active-org\n        // owners/admins; anyone else is denied.\n        if ((session.user as any).role !== 'admin') {\n          return c.json({ success: false, error: { code: 'forbidden', message: 'Admin role required' } }, 403);\n        }\n\n        // Write through the same ObjectQL data engine that better-auth's\n        // adapter uses. We target the snake_case table name (`sys_oauth_application`,\n        // mapped from better-auth's internal `oauthClient` model via\n        // `auth-schema-config.ts`) because `$context.adapter`'s model-lookup\n        // helper does not see plugin-provided model names from outside\n        // better-auth's own endpoint invocation context. This is the same\n        // physical row the better-auth runtime reads at introspect / token\n        // / authorize time, so the toggle is fully honoured.\n        const dataEngine: any = this.authManager!.getDataEngine();\n        if (!dataEngine) {\n          return c.json({ success: false, error: { code: 'unavailable', message: 'Data engine unavailable' } }, 503);\n        }\n\n        const existing = await dataEngine.findOne('sys_oauth_application', {\n          where: { client_id: clientId },\n        });\n        if (!existing) {\n          return c.json({ success: false, error: { code: 'not_found', message: 'OAuth client not found' } }, 404);\n        }\n\n        const updated = await dataEngine.update('sys_oauth_application', {\n          id: existing.id,\n          disabled,\n          updated_at: new Date(Math.floor(Date.now() / 1000) * 1000),\n        });\n        if (!updated) {\n          return c.json({ success: false, error: { code: 'internal', message: 'Unable to update OAuth client' } }, 500);\n        }\n\n        return c.json({\n          success: true,\n          data: {\n            client_id: clientId,\n            disabled,\n          },\n        });\n      } catch (error) {\n        const err = error instanceof Error ? error : new Error(String(error));\n        ctx.logger.error('[AuthPlugin] toggle-disabled failed', err);\n        return c.json({ success: false, error: { code: 'internal', message: err.message } }, 500);\n      }\n    });\n\n    // ────────────────────────────────────────────────────────────────────\n    // OAuth self-service: register an OAuth application for the signed-in\n    // user. Thin wrapper over better-auth's `/oauth2/create-client`\n    // endpoint (session-required, auto-stamps `user_id` from the session).\n    //\n    // Why this wrapper exists: the Account-app action surfaces a\n    // user-friendly textarea for \"Redirect URLs\" (one per line), but\n    // better-auth's Zod body schema requires `redirect_uris: string[]`.\n    // The metadata-driven action runner POSTs param values verbatim, so\n    // without a translation layer the upstream call fails validation with\n    // `Invalid input: expected array, received string`. We split the\n    // textarea on newlines, trim, drop empties, and forward to\n    // `createOAuthClient` so the row gets persisted with the caller's\n    // user_id and shows up in the `mine` listView.\n    //\n    // Upstream alternative would be enabling `allowDynamicClientRegistration`\n    // on `/oauth2/register`, but DCR has additional security implications\n    // (rate limiting, scope restriction) we don't want to enable broadly\n    // just to fix UX. Keeping the wrapper scoped to the self-service flow.\n    rawApp.post(`${basePath}/sys-oauth-application/register`, async (c: any) => {\n      try {\n        let body: any = {};\n        try { body = await c.req.json(); } catch { body = {}; }\n\n        const name: unknown = body?.name;\n        const redirectUrlsInput: unknown = body?.redirectURLs;\n        const type: unknown = body?.type;\n\n        if (typeof name !== 'string' || name.trim().length === 0) {\n          return c.json({ success: false, error: { code: 'invalid_request', message: 'name is required' } }, 400);\n        }\n        if (typeof redirectUrlsInput !== 'string' || redirectUrlsInput.trim().length === 0) {\n          return c.json({ success: false, error: { code: 'invalid_request', message: 'redirectURLs is required' } }, 400);\n        }\n\n        const redirectUris = redirectUrlsInput\n          .split(/[\\r\\n]+/)\n          .map((line) => line.trim())\n          .filter((line) => line.length > 0);\n        if (redirectUris.length === 0) {\n          return c.json({ success: false, error: { code: 'invalid_request', message: 'redirectURLs must contain at least one URL' } }, 400);\n        }\n\n        const allowedTypes = new Set(['web', 'native', 'user-agent-based']);\n        const safeType = typeof type === 'string' && allowedTypes.has(type) ? type : 'web';\n\n        const authApi: any = await this.authManager!.getApi();\n        if (!authApi?.createOAuthClient) {\n          return c.json({ success: false, error: { code: 'unavailable', message: 'OIDC provider is not enabled on this environment' } }, 503);\n        }\n\n        // Forward request headers so better-auth can resolve the caller's\n        // session (sessionMiddleware on /oauth2/create-client). Without\n        // the session the row would lack `user_id` and never appear in\n        // the My Applications view.\n        let result: any;\n        try {\n          result = await authApi.createOAuthClient({\n            body: {\n              client_name: name.trim(),\n              redirect_uris: redirectUris,\n              type: safeType,\n            },\n            headers: c.req.raw.headers,\n          });\n        } catch (err: any) {\n          const status = typeof err?.status === 'number' ? err.status : 500;\n          const code = err?.body?.error ?? 'oauth_register_failed';\n          const message = err?.body?.error_description ?? err?.message ?? 'Unable to register OAuth client';\n          return c.json({ success: false, error: { code, message } }, status);\n        }\n\n        // Mirror the response shape consumed by the action's resultDialog\n        // (`client.client_id`, `client.client_secret`).\n        return c.json({ success: true, data: { client: result } });\n      } catch (error) {\n        const err = error instanceof Error ? error : new Error(String(error));\n        ctx.logger.error('[AuthPlugin] sys-oauth-application/register failed', err);\n        return c.json({ success: false, error: { code: 'internal', message: err.message } }, 500);\n      }\n    });\n\n    // Register wildcard route to forward all auth requests to better-auth.\n    // better-auth is configured with basePath matching our route prefix, so we\n    // forward the original request directly — no path rewriting needed.\n    rawApp.all(`${basePath}/*`, async (c: any) => {\n      try {\n        // Forward the original request to better-auth handler\n        const response = await this.authManager!.handleRequest(c.req.raw);\n\n        // better-auth catches internal errors and returns error Responses\n        // without throwing, so the catch block below would never trigger.\n        // We proactively log server errors here for observability.\n        if (response.status >= 500) {\n          try {\n            const body = await response.clone().text();\n            ctx.logger.error('[AuthPlugin] better-auth returned server error', new Error(`HTTP ${response.status}: ${body}`));\n          } catch {\n            ctx.logger.error('[AuthPlugin] better-auth returned server error', new Error(`HTTP ${response.status}: (unable to read body)`));\n          }\n        }\n\n        // Public-cache JWKS: it's static JSON that only changes when the\n        // signing key rotates (default ~30 days). better-auth doesn't set\n        // any Cache-Control header, so every relying party currently\n        // re-fetches it on every JWT verification (≈700 ms warm against a\n        // Container DO + Neon). Add a conservative public cache so CF's\n        // edge can short-circuit repeated fetches. The 5-min freshness +\n        // 24 h SWR window is well inside better-auth's default rotation\n        // and matches what most IdPs publish (Auth0, Cognito, Google).\n        try {\n          const url = c.req.url as string;\n          if (response.ok && /\\/jwks(\\?|$)/.test(url)) {\n            const existing = response.headers.get('cache-control');\n            if (!existing) {\n              response.headers.set(\n                'cache-control',\n                'public, max-age=300, stale-while-revalidate=86400',\n              );\n            }\n          }\n        } catch { /* best-effort header annotation */ }\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    // OIDC / OAuth 2.0 Authorization Server Metadata (RFC 8414) and\n    // OpenID Connect Discovery 1.0 require the well-known documents to be\n    // served from the **root** of the issuer URL — not under our auth\n    // basePath. `@better-auth/oauth-provider` ships dedicated helpers for\n    // this case (`oauthProviderAuthServerMetadata` /\n    // `oauthProviderOpenIdConfigMetadata`) which we mount here so external\n    // OIDC clients can discover the IdP at the canonical paths.\n    //\n    // Honour the same `OS_OIDC_PROVIDER_ENABLED` env-var override that\n    // `AuthManager.buildPlugins()` uses — without this check the\n    // discovery routes would NOT mount when an operator flipped the\n    // env var on without editing the config file, leaving external\n    // OIDC clients unable to discover the IdP.\n    const oidcEnv = (globalThis as any)?.process?.env?.OS_OIDC_PROVIDER_ENABLED;\n    const oidcFromEnv = oidcEnv != null ? String(oidcEnv).toLowerCase() === 'true' : undefined;\n    const oidcEnabled = oidcFromEnv ?? this.options.plugins?.oidcProvider ?? false;\n    if (oidcEnabled) {\n      void this.registerOidcDiscoveryRoutes(rawApp, ctx).catch((error) => {\n        ctx.logger.error('Failed to register OIDC discovery routes', error as Error);\n      });\n    }\n\n    ctx.logger.info(`Auth routes registered: All requests under ${basePath}/* forwarded to better-auth`);\n  }\n\n  /**\n   * Mount the OIDC / OAuth 2.0 well-known discovery documents at the root\n   * URL. Required by RFC 8414 §3 and OpenID Connect Discovery 1.0 §4 — the\n   * documents must live at `/.well-known/{oauth-authorization-server,openid-configuration}`\n   * relative to the issuer, not under the auth basePath.\n   */\n  private async registerOidcDiscoveryRoutes(rawApp: any, ctx: PluginContext): Promise<void> {\n    const auth = await this.authManager!.getAuthInstance();\n    const { oauthProviderAuthServerMetadata, oauthProviderOpenIdConfigMetadata } = await import(\n      '@better-auth/oauth-provider'\n    );\n\n    const authServerHandler = oauthProviderAuthServerMetadata(auth as any);\n    const openidConfigHandler = oauthProviderOpenIdConfigMetadata(auth as any);\n\n    // Cache-Control for OIDC discovery docs. These describe stable issuer\n    // configuration (endpoints, supported scopes, signing algs); they\n    // change only on app redeploy. CF edge can short-circuit repeated\n    // fetches and dramatically cut SSO first-call latency.\n    const DISCOVERY_CACHE = 'public, max-age=300, stale-while-revalidate=86400';\n    const withDiscoveryCache = async (handler: (req: Request) => Promise<Response> | Response, req: Request): Promise<Response> => {\n      const resp = await handler(req);\n      try {\n        if (resp.ok && !resp.headers.get('cache-control')) {\n          resp.headers.set('cache-control', DISCOVERY_CACHE);\n        }\n      } catch { /* best-effort */ }\n      return resp;\n    };\n\n    rawApp.get('/.well-known/oauth-authorization-server', (c: any) => withDiscoveryCache(authServerHandler, c.req.raw));\n    rawApp.get('/.well-known/openid-configuration', (c: any) => withDiscoveryCache(openidConfigHandler, c.req.raw));\n\n    ctx.logger.info(\n      'OIDC discovery endpoints mounted at /.well-known/{oauth-authorization-server,openid-configuration}',\n    );\n  }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Auth, BetterAuthOptions } from 'better-auth';\n// better-auth value imports (betterAuth + plugins) are deferred via dynamic\n// import() in getOrCreateAuth() / buildPluginList() so that disabled plugins\n// never get loaded into the process. See Stage 2F (RSS investigation).\nimport type {\n  AuthConfig,\n  EmailAndPasswordConfig,\n  AuthPluginConfig,\n  OidcProvidersConfig,\n} from '@objectstack/spec/system';\nimport type { IDataEngine } from '@objectstack/core';\nimport type { IEmailService } from '@objectstack/spec/contracts';\nimport { readEnvWithDeprecation } from '@objectstack/types';\nimport { createObjectQLAdapterFactory } from './objectql-adapter.js';\nimport {\n  AUTH_USER_CONFIG,\n  AUTH_SESSION_CONFIG,\n  AUTH_ACCOUNT_CONFIG,\n  AUTH_VERIFICATION_CONFIG,\n  buildOrganizationPluginSchema,\n  buildTwoFactorPluginSchema,\n  buildOauthProviderPluginSchema,\n  buildDeviceAuthorizationPluginSchema,\n  buildJwtPluginSchema,\n  buildAdminPluginSchema,\n} from './auth-schema-config.js';\n\n/**\n * Detect WebContainer (StackBlitz) environment.\n *\n * WebContainer reports itself as Node.js but runs inside a browser. Several\n * Node APIs are polyfilled with significant behavioural differences — most\n * notably `node:async_hooks.AsyncLocalStorage`, whose `run()` does NOT\n * propagate the store across `await` boundaries the way Node's native\n * implementation does.\n */\nfunction isWebContainerRuntime(): boolean {\n  if (typeof globalThis === 'undefined') return false;\n  const proc = (globalThis as any).process;\n  return (\n    Boolean(proc?.versions?.webcontainer) ||\n    Boolean(proc?.env?.SHELL?.includes?.('jsh')) ||\n    Boolean(proc?.env?.STACKBLITZ)\n  );\n}\n\n/**\n * Synchronous AsyncLocalStorage polyfill compatible with better-auth's\n * `requestStateAsyncStorage` slot.\n *\n * Behaviour:\n * - `run(store, fn)` sets the current store synchronously before invoking\n *   `fn` and restores the previous store after `fn` (and any promise it\n *   returns) settles.\n * - `getStore()` returns the current store.\n *\n * Why a polyfill is needed in WebContainer:\n * - WebContainer's `node:async_hooks` does not propagate ALS context through\n *   `await`, so better-auth's `runWithRequestState(map, () => handler(req))`\n *   wrap loses the store as soon as the call chain awaits anything (e.g.\n *   the inner `customSession` → `getSession()` call). All endpoints that\n *   read request-state via `defineRequestState()` then throw\n *   \"No request state found\".\n *\n * Single-flight caveat:\n * - This polyfill is process-global, not async-context-local. In a real\n *   server it could leak state across concurrent requests. That risk is\n *   acceptable here because:\n *   1) It is only installed when WebContainer is detected (dev / preview\n *      sandboxes that handle one request at a time).\n *   2) Each request still wraps the entire handler in `runWithRequestState`\n *      with a fresh WeakMap, so the in-flight request always sees its own\n *      store as long as nothing else mutates the slot mid-flight.\n */\nclass WebContainerRequestStateAsyncLocalStorage<T> {\n  private current: T | undefined = undefined;\n\n  run<R>(store: T, fn: () => R): R {\n    const prev = this.current;\n    this.current = store;\n    try {\n      const result = fn() as unknown;\n      if (result && typeof (result as Promise<unknown>).then === 'function') {\n        return (result as Promise<unknown>).finally(() => {\n          this.current = prev;\n        }) as unknown as R;\n      }\n      this.current = prev;\n      return result as R;\n    } catch (err) {\n      this.current = prev;\n      throw err;\n    }\n  }\n\n  getStore(): T | undefined {\n    return this.current;\n  }\n}\n\n/**\n * Pre-populate better-auth's global `requestStateAsyncStorage` slot with the\n * synchronous polyfill when running inside WebContainer.\n *\n * Better-auth caches its AsyncLocalStorage instance on\n * `globalThis[Symbol.for('better-auth:global')].context.requestStateAsyncStorage`\n * the first time `ensureAsyncStorage()` runs (see\n * `@better-auth/core/dist/context/request-state.mjs`). By seeding that slot\n * BEFORE any better-auth code touches it, every call to\n * `runWithRequestState` / `getCurrentRequestState` — including the\n * `@better-auth/core` copy that `plugin-auth` imports directly and the copy\n * bundled with `better-auth` itself — share the same working polyfill.\n *\n * Outside WebContainer this is a no-op so production deployments keep\n * Node's native AsyncLocalStorage.\n */\nfunction installWebContainerRequestStatePolyfill(): void {\n  if (!isWebContainerRuntime()) return;\n  const sym = Symbol.for('better-auth:global');\n  const g = globalThis as any;\n  if (!g[sym]) {\n    g[sym] = { version: '0.0.0-polyfill', epoch: 0, context: {} };\n  }\n  if (!g[sym].context) g[sym].context = {};\n  if (!g[sym].context.requestStateAsyncStorage) {\n    g[sym].context.requestStateAsyncStorage = new WebContainerRequestStateAsyncLocalStorage();\n    // eslint-disable-next-line no-console\n    console.warn(\n      '[AuthManager] WebContainer detected: installed synchronous request-state polyfill ' +\n        '(node:async_hooks AsyncLocalStorage does not propagate context across await in WebContainer).',\n    );\n  }\n}\n\nfunction readBooleanEnv(name: string, legacyName?: string): boolean | undefined {\n  const env = (globalThis as any)?.process?.env as Record<string, string | undefined> | undefined;\n  const raw = env?.[name] ?? (legacyName ? env?.[legacyName] : undefined);\n  if (raw == null) return undefined;\n  const normalized = String(raw).trim().toLowerCase();\n  return !['0', 'false', 'off', 'no'].includes(normalized);\n}\n\nfunction readDisableSignUpEnv(): boolean | undefined {\n  const signupEnabled = readBooleanEnv('OS_AUTH_SIGNUP_ENABLED');\n  if (signupEnabled != null) return !signupEnabled;\n  return readBooleanEnv('OS_DISABLE_SIGNUP');\n}\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   * Base path for auth routes\n   * Forwarded to better-auth's basePath option so it can match incoming\n   * request URLs without manual path rewriting.\n   * @default '/api/v1/auth'\n   */\n  basePath?: string;\n\n  /**\n   * OIDC / Generic OAuth2 providers for enterprise SSO.\n   * Each entry is passed to better-auth's genericOAuth plugin.\n   */\n  oidcProviders?: OidcProvidersConfig;\n\n  /**\n   * Application-specific organization roles to register with Better-Auth's\n   * organization plugin. Each name becomes a valid role for invitations and\n   * member assignments without going through Better-Auth's default\n   * `owner|admin|member` whitelist.\n   *\n   * The ObjectStack SecurityPlugin handles real RBAC enforcement by matching\n   * these role names against `permission` metadata (PermissionSets / Profiles),\n   * so Better-Auth only needs to accept them as opaque strings. Each role is\n   * registered with the minimum access-control privileges (equivalent to\n   * Better-Auth's `member` role) so it cannot inadvertently grant org-level\n   * admin capabilities.\n   *\n   * Typical source: the union of `permission` metadata names that have\n   * `isProfile: true`, collected from the loaded stack at CLI boot.\n   *\n   * @example ['sales_rep', 'sales_manager', 'service_agent']\n   */\n  additionalOrgRoles?: string[];\n\n  /**\n   * Optional outbound email service used by better-auth callbacks\n   * (`sendResetPassword`, `sendVerificationEmail`, `sendInvitationEmail`,\n   * `sendMagicLink`). When omitted, those callbacks degrade to logging\n   * the action URL — keeping flows usable in pilots / local dev — but\n   * production deployments SHOULD wire one via `setEmailService()`.\n   *\n   * Resolved lazily through {@link AuthManager.getEmailService}; safe\n   * to set after construction. AuthPlugin wires this from the kernel\n   * service registry on `kernel:ready`.\n   */\n  emailService?: IEmailService;\n\n  /**\n   * Display name used by built-in auth email templates (`{{appName}}`\n   * placeholder). Defaults to `'ObjectStack'` when omitted.\n   */\n  appName?: string;\n\n  /**\n   * Pass-through to better-auth's `databaseHooks` option. better-auth fires\n   * these around its own adapter writes (e.g. when `genericOAuth` creates\n   * a JIT user during SSO login), which the kernel-level ObjectQL\n   * middleware does NOT observe — better-auth's adapter goes through\n   * `dataEngine` directly, bypassing the `ql.registerMiddleware` chain.\n   *\n   * The platform uses this to attach a `user.create.after` hook that\n   * auto-provisions a personal organization for every newly-created user\n   * (mirroring what SecurityPlugin's middleware does for direct\n   * ObjectQL inserts) so SSO-arriving users don't land on the empty\n   * \"create organization\" screen.\n   */\n  databaseHooks?: BetterAuthOptions['databaseHooks'];\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  /**\n   * Result of the dev-only admin seed (set by `AuthPlugin.maybeSeedDevAdmin`\n   * when it provisions the well-known admin on an empty DB). The `serve`\n   * command reads this after boot to surface the credentials in the startup\n   * banner. Undefined when no seed ran (production, opt-out, or a DB that\n   * already had a user).\n   */\n  public devSeedResult?: { email: string; password: string };\n\n  constructor(config: AuthManagerOptions) {\n    this.config = config;\n\n    // WebContainer (StackBlitz) compatibility — install a synchronous\n    // AsyncLocalStorage polyfill for better-auth's request-state global\n    // BEFORE better-auth ever instantiates its own. See the helper for the\n    // full rationale.\n    installWebContainerRequestStatePolyfill();\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 async getOrCreateAuth(): Promise<Auth<any>> {\n    if (!this.auth) {\n      this.auth = await this.createAuthInstance();\n    }\n    return this.auth;\n  }\n\n  /**\n   * Create a better-auth instance from configuration\n   */\n  private async createAuthInstance(): Promise<Auth<any>> {\n    const { betterAuth } = await import('better-auth');\n    const { createAuthMiddleware } = await import('better-auth/api');\n    const plugins = await this.buildPluginList();\n    const passwordHasher = await this.resolvePasswordHasher();\n    const betterAuthConfig: BetterAuthOptions = {\n      // Base configuration\n      secret: this.config.secret || this.generateSecret(),\n      baseURL: this.config.baseUrl || 'http://localhost:3000',\n      basePath: this.config.basePath || '/api/v1/auth',\n\n      // Database adapter configuration\n      database: this.createDatabaseConfig(),\n\n      // Model/field mapping: camelCase (better-auth) → snake_case (ObjectStack)\n      // These declarations tell better-auth the actual table/column names used\n      // by ObjectStack's protocol layer, enabling automatic transformation via\n      // createAdapterFactory.\n      user: {\n        ...AUTH_USER_CONFIG,\n      },\n      account: {\n        ...AUTH_ACCOUNT_CONFIG,\n        // Allow OIDC/OAuth callbacks to implicitly link the incoming\n        // identity to a pre-existing local user when the emails match.\n        //\n        // ObjectStack's platform SSO (\"objectstack-cloud\" provider) is the\n        // canonical case: cloud is the IdP for every project, so a user\n        // arriving via SSO is — by construction — the same person who was\n        // auto-seeded as the project owner when the project was created.\n        // Without trusting the provider, better-auth's safety check rejects\n        // the link with `error=account_not_linked` because the seeded user\n        // row has `emailVerified=false` (no actual verification ever runs\n        // in the IdP-mediated flow). See packages/plugins/plugin-auth/\n        // node_modules/better-auth/dist/oauth2/link-account.mjs:22.\n        //\n        // Custom-deployment consumers can extend the trusted set via\n        // `config.account.accountLinking.trustedProviders`; we always\n        // include `objectstack-cloud` because it is the platform IdP.\n        accountLinking: {\n          enabled: true,\n          // better-auth's account-linking gate has TWO independent clauses\n          // (see link-account.mjs:22). Trusting the provider only satisfies\n          // the first clause; the second — `requireLocalEmailVerified &&\n          // !dbUser.user.emailVerified` — still blocks linking when the\n          // pre-existing local user row has `emailVerified=false` (the\n          // default for owner-seeded rows). Disabling the local-email gate\n          // is safe here because the OAuth side is what we actually trust:\n          // the incoming identity was verified by the IdP. Consumers who\n          // need the stricter behavior can override via config.\n          requireLocalEmailVerified: false,\n          ...((this.config as any)?.account?.accountLinking ?? {}),\n          trustedProviders: Array.from(new Set([\n            'objectstack-cloud',\n            ...((this.config as any)?.account?.accountLinking?.trustedProviders ?? []),\n          ])),\n        },\n      },\n      verification: {\n        ...AUTH_VERIFICATION_CONFIG,\n      },\n\n      // Social / OAuth providers\n      ...(this.config.socialProviders ? { socialProviders: this.config.socialProviders as any } : {}),\n\n      // Email and password configuration.\n      // `disableSignUp`: env overrides config/settings so deployments can\n      // lock the registration policy without relying on UI state.\n      emailAndPassword: (() => {\n        const disableSignUpFromEnv = readDisableSignUpEnv();\n        const effectiveDisableSignUp = disableSignUpFromEnv ?? this.config.emailAndPassword?.disableSignUp;\n        return {\n          enabled: this.config.emailAndPassword?.enabled ?? true,\n          ...(passwordHasher ? { password: passwordHasher } : {}),\n          ...(effectiveDisableSignUp != null\n            ? { disableSignUp: effectiveDisableSignUp } : {}),\n          ...(this.config.emailAndPassword?.requireEmailVerification != null\n            ? { requireEmailVerification: this.config.emailAndPassword.requireEmailVerification } : {}),\n          ...(this.config.emailAndPassword?.minPasswordLength != null\n            ? { minPasswordLength: this.config.emailAndPassword.minPasswordLength } : {}),\n          ...(this.config.emailAndPassword?.maxPasswordLength != null\n            ? { maxPasswordLength: this.config.emailAndPassword.maxPasswordLength } : {}),\n          ...(this.config.emailAndPassword?.resetPasswordTokenExpiresIn != null\n            ? { resetPasswordTokenExpiresIn: this.config.emailAndPassword.resetPasswordTokenExpiresIn } : {}),\n          ...(this.config.emailAndPassword?.autoSignIn != null\n            ? { autoSignIn: this.config.emailAndPassword.autoSignIn } : {}),\n          ...(this.config.emailAndPassword?.revokeSessionsOnPasswordReset != null\n            ? { revokeSessionsOnPasswordReset: this.config.emailAndPassword.revokeSessionsOnPasswordReset } : {}),\n        sendResetPassword: async ({ user, url, token }: { user: { id: string; email: string; name?: string }; url: string; token: string }) => {\n          const email = this.getEmailService();\n          if (!email) {\n            console.warn(\n              `[AuthManager] Password-reset requested for ${user.email} but no email service is wired. URL: ${url}`,\n            );\n            return;\n          }\n          const ttlSec = this.config.emailAndPassword?.resetPasswordTokenExpiresIn ?? 60 * 60;\n          try {\n            await email.sendTemplate({\n              template: 'auth.password_reset',\n              to: { address: user.email, ...(user.name ? { name: user.name } : {}) },\n              data: {\n                user: { name: user.name || user.email, email: user.email, id: user.id },\n                resetUrl: url,\n                token,\n                expiresInMinutes: Math.round(ttlSec / 60),\n                appName: this.getAppName(),\n              },\n              relatedObject: 'sys_user',\n              relatedId: user.id,\n            });\n          } catch (err: any) {\n            // Do NOT rethrow: the user account exists; an email-transport failure\n            // (missing template, bad credentials, network blip) must not turn\n            // the user-facing reset request into a 500. The user can retry via\n            // the \"forgot password\" flow.\n            console.error(`[AuthManager] sendResetPassword failed (swallowed): ${err?.message ?? err}`);\n          }\n        },\n        };\n      })(),\n\n      // Email verification\n      ...(this.config.emailVerification || this.config.emailService ? {\n        emailVerification: {\n          ...(this.config.emailVerification?.sendOnSignUp != null\n            ? { sendOnSignUp: this.config.emailVerification.sendOnSignUp } : {}),\n          ...(this.config.emailVerification?.sendOnSignIn != null\n            ? { sendOnSignIn: this.config.emailVerification.sendOnSignIn } : {}),\n          ...(this.config.emailVerification?.autoSignInAfterVerification != null\n            ? { autoSignInAfterVerification: this.config.emailVerification.autoSignInAfterVerification } : {}),\n          ...(this.config.emailVerification?.expiresIn != null\n            ? { expiresIn: this.config.emailVerification.expiresIn } : {}),\n          sendVerificationEmail: async ({ user, url, token }: { user: { id: string; email: string; name?: string }; url: string; token: string }) => {\n            const email = this.getEmailService();\n            if (!email) {\n              console.warn(\n                `[AuthManager] Verification email requested for ${user.email} but no email service is wired. URL: ${url}`,\n              );\n              return;\n            }\n            const ttlSec = this.config.emailVerification?.expiresIn ?? 60 * 60;\n            try {\n              await email.sendTemplate({\n                template: 'auth.verify_email',\n                to: { address: user.email, ...(user.name ? { name: user.name } : {}) },\n                data: {\n                  user: { name: user.name || user.email, email: user.email, id: user.id },\n                  verificationUrl: url,\n                  token,\n                  expiresInMinutes: Math.round(ttlSec / 60),\n                  appName: this.getAppName(),\n                },\n                relatedObject: 'sys_user',\n                relatedId: user.id,\n              });\n            } catch (err: any) {\n              // Do NOT rethrow: the user account exists; an email-transport\n              // failure must not turn signup or /send-verification-email into\n              // a 500. The \"Resend verification email\" UI lets the user retry.\n              console.error(`[AuthManager] sendVerificationEmail failed (swallowed): ${err?.message ?? err}`);\n            }\n          },\n        },\n      } : {}),\n\n      // Session configuration\n      session: {\n        ...AUTH_SESSION_CONFIG,\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      // better-auth plugins — registered based on AuthPluginConfig flags\n      plugins,\n\n      // Database hooks (fired by better-auth's adapter writes — these run\n      // for SSO JIT-provisioning too, unlike kernel-level ObjectQL\n      // middleware which better-auth's adapter bypasses).\n      ...(this.config.databaseHooks ? { databaseHooks: this.config.databaseHooks } : {}),\n\n      // Bootstrap bypass for `disableSignUp`. The first-run owner wizard\n      // (`/_account/setup`) calls `POST /auth/sign-up/email` to create\n      // the very first user — if `OS_DISABLE_SIGNUP=true` is set on a\n      // fresh install we'd lock the operator out of their own instance.\n      // Solution: when the request hits `/sign-up/email` AND no users\n      // exist yet, temporarily flip `disableSignUp` off for *this*\n      // request's context. Once the owner is created the next request\n      // sees `userCount > 0` and the toggle is enforced again.\n      hooks: {\n        before: createAuthMiddleware(async (ctx: any) => {\n          if (ctx?.path !== '/sign-up/email') return;\n          const ep = ctx?.context?.options?.emailAndPassword;\n          if (!ep?.disableSignUp) return;\n          try {\n            const adapter = ctx.context.adapter;\n            const existing = await adapter.findOne({ model: 'user', where: [] });\n            if (!existing) {\n              ctx.context.__osDisableSignUpOrig = ep.disableSignUp;\n              ep.disableSignUp = false;\n            }\n          } catch {\n            // Adapter not ready → keep disableSignUp on.\n          }\n        }),\n        after: createAuthMiddleware(async (ctx: any) => {\n          if (ctx?.path !== '/sign-up/email') return;\n          const ep = ctx?.context?.options?.emailAndPassword;\n          if (ep && ctx.context.__osDisableSignUpOrig !== undefined) {\n            ep.disableSignUp = ctx.context.__osDisableSignUpOrig;\n            delete ctx.context.__osDisableSignUpOrig;\n          }\n        }),\n      },\n\n      // Trusted origins for CSRF protection (supports wildcards like \"https://*.example.com\")\n      // Auto-includes origins from OS_CORS_ORIGIN env var so CORS and CSRF stay in sync.\n      ...(() => {\n        const origins: string[] = [...(this.config.trustedOrigins || [])];\n        // Sync with OS_CORS_ORIGIN env var (comma-separated)\n        const corsOrigin = readEnvWithDeprecation('OS_CORS_ORIGIN', 'CORS_ORIGIN');\n        if (corsOrigin && corsOrigin !== '*') {\n          corsOrigin.split(',').map(s => s.trim()).filter(Boolean).forEach(o => {\n            if (!origins.includes(o)) origins.push(o);\n          });\n        }\n        // When CORS allows all origins (default) and no explicit trustedOrigins,\n        // trust all localhost ports in development for convenience. Also trust\n        // `*.localhost` subdomains so per-project tenant subdomains (the dev\n        // default root domain — see project-provisioning.ts) pass CSRF checks\n        // without operators having to configure trustedOrigins manually.\n        if (!origins.length && (!corsOrigin || corsOrigin === '*')) {\n          origins.push('http://localhost:*');\n          origins.push('http://*.localhost:*');\n          origins.push('https://*.localhost:*');\n        }\n        return origins.length ? { trustedOrigins: origins } : {};\n      })(),\n\n      // Advanced options (cross-subdomain cookies, secure cookies, CSRF, etc.)\n      ...(this.config.advanced ? {\n        advanced: {\n          ...(this.config.advanced.crossSubDomainCookies\n            ? { crossSubDomainCookies: this.config.advanced.crossSubDomainCookies } : {}),\n          ...(this.config.advanced.useSecureCookies != null\n            ? { useSecureCookies: this.config.advanced.useSecureCookies } : {}),\n          ...(this.config.advanced.disableCSRFCheck != null\n            ? { disableCSRFCheck: this.config.advanced.disableCSRFCheck } : {}),\n          ...(this.config.advanced.cookiePrefix != null\n            ? { cookiePrefix: this.config.advanced.cookiePrefix } : {}),\n        },\n      } : {}),\n    };\n\n    return betterAuth(betterAuthConfig);\n  }\n\n  /**\n   * Detect WebContainer (StackBlitz) and swap in a pure-JS scrypt hasher.\n   *\n   * better-auth defaults to `@better-auth/utils/password.node`, which calls\n   * `node:crypto.scrypt`. WebContainer polyfills that API incompletely and\n   * signup throws `TypeError: y.run is not a function`.\n   *\n   * We can't dynamic-import `@better-auth/utils/password` because that\n   * package's `exports` map gates the pure-JS build behind a non-`\"node\"`\n   * condition — Node-the-runtime (which WebContainer reports itself as)\n   * always resolves to `password.node.mjs`. So we reimplement the same hash\n   * here using `@noble/hashes/scrypt` directly, with byte-identical params\n   * (N=16384, r=16, p=1, dkLen=64) and the same `{saltHex}:{keyHex}` storage\n   * format. Hashes produced by either implementation verify against the\n   * other — no migration needed.\n   *\n   * Returns `undefined` outside WebContainer so production deployments keep\n   * the native (fast) hasher and never load `@noble/hashes`.\n   */\n  private async resolvePasswordHasher(): Promise<\n    { hash: (password: string) => Promise<string>; verify: (args: { hash: string; password: string }) => Promise<boolean> } | undefined\n  > {\n    if (!isWebContainerRuntime()) return undefined;\n    try {\n      const { scryptAsync } = await import('@noble/hashes/scrypt.js');\n      const PARAMS = { N: 16384, r: 16, p: 1, dkLen: 64, maxmem: 128 * 16384 * 16 * 2 } as const;\n      const toHex = (b: Uint8Array): string => {\n        let s = '';\n        for (let i = 0; i < b.length; i++) s += b[i]!.toString(16).padStart(2, '0');\n        return s;\n      };\n      const generateKey = (password: string, saltHex: string): Promise<Uint8Array> =>\n        scryptAsync(password.normalize('NFKC'), saltHex, PARAMS);\n      return {\n        hash: async (password: string) => {\n          const saltBytes = (globalThis as any).crypto.getRandomValues(new Uint8Array(16));\n          const saltHex = toHex(saltBytes);\n          const key = await generateKey(password, saltHex);\n          return `${saltHex}:${toHex(key)}`;\n        },\n        verify: async ({ hash, password }) => {\n          const [saltHex, keyHex] = hash.split(':');\n          if (!saltHex || !keyHex) throw new Error('Invalid password hash');\n          const target = await generateKey(password, saltHex);\n          return toHex(target) === keyHex;\n        },\n      };\n    } catch (err: any) {\n      console.warn(\n        `[AuthManager] WebContainer detected but pure-JS scrypt unavailable: ${err?.message ?? err}. Falling back to default.`,\n      );\n      return undefined;\n    }\n  }\n\n  /**\n   * Build the list of better-auth plugins based on AuthPluginConfig flags.\n   *\n   * Each plugin that introduces its own database tables is configured with\n   * a `schema` option containing the appropriate snake_case field mappings,\n   * so that `createAdapterFactory` transforms them automatically.\n   */\n  private async buildPluginList(): Promise<any[]> {\n    const pluginConfig: Partial<AuthPluginConfig> = this.config.plugins ?? {};\n    const plugins: any[] = [];\n\n    // Defaults — kept in sync with `AuthPluginConfigSchema` in\n    // @objectstack/spec/system/auth-config.zod.ts. The frontend AuthProvider\n    // (in @object-ui/app-shell) calls `/api/v1/auth/organization/list` on\n    // every load; making the org plugin opt-out (default true) avoids\n    // 404s and the noisy \"Failed to load organizations\" warning.\n    //\n    // `OS_OIDC_PROVIDER_ENABLED` lets operators flip the OIDC IdP on\n    // without re-deploying with a code change (mirrors the\n    // `OS_MULTI_ORG_ENABLED` / `OS_DISABLE_SIGNUP` pattern). When set, the\n    // env var WINS over the config-file setting so platform operators can\n    // override per-environment without touching the application bundle.\n    const oidcEnv = (globalThis as any)?.process?.env?.OS_OIDC_PROVIDER_ENABLED;\n    const oidcFromEnv = oidcEnv != null ? String(oidcEnv).toLowerCase() === 'true' : undefined;\n    const twoFactorFromEnv = readBooleanEnv('OS_AUTH_TWO_FACTOR');\n    const enabled = {\n      organization: pluginConfig.organization ?? true,\n      twoFactor: twoFactorFromEnv ?? pluginConfig.twoFactor ?? false,\n      passkeys: pluginConfig.passkeys ?? false,\n      magicLink: pluginConfig.magicLink ?? false,\n      oidcProvider: oidcFromEnv ?? pluginConfig.oidcProvider ?? false,\n      deviceAuthorization: pluginConfig.deviceAuthorization ?? false,\n      admin: pluginConfig.admin ?? false,\n    };\n\n    // bearer() — ALWAYS enabled.\n    //\n    // Enables token-based authentication for cross-origin and mobile clients\n    // where third-party cookies are blocked (e.g. Safari ITP, Chrome CHIPS,\n    // native apps). The plugin:\n    //   • Accepts `Authorization: Bearer <token>` on incoming requests and\n    //     transparently resolves the session as if a cookie had been sent.\n    //   • Emits a `set-auth-token` response header on sign-in / session-refresh\n    //     that the client can store (e.g. in `localStorage`) and replay on\n    //     subsequent requests.\n    //\n    // This mirrors how Salesforce, Notion, Supabase and first-party mobile\n    // SDKs handle auth. Cookie-based auth remains available for same-origin\n    // browser deployments; bearer is additive, not a replacement.\n    const { bearer } = await import('better-auth/plugins/bearer');\n    plugins.push(bearer());\n\n    if (enabled.organization) {\n      const { organization } = await import('better-auth/plugins/organization');\n      // Build a `roles` map that registers each app-supplied org role\n      // (e.g. CRM's sales_rep, sales_manager) as a valid Better-Auth role\n      // so invitations to those roles aren't rejected with ROLE_NOT_FOUND.\n      // Real RBAC enforcement is handled by ObjectStack's SecurityPlugin,\n      // which matches the role name against `permission` metadata\n      // (PermissionSets). Here we register them with minimum org-plugin\n      // capabilities (same as the built-in `member` role) so they cannot\n      // inadvertently grant org-level admin powers.\n      let customOrgRoles: Record<string, any> | undefined;\n      const extra = this.config.additionalOrgRoles;\n      if (extra && extra.length > 0) {\n        try {\n          const accessMod = await import('better-auth/plugins/organization/access');\n          const { defaultAc, memberAc, defaultRoles: importedDefaultRoles } = accessMod as any;\n          // Better-Auth's `hasPermission` does `{...options.roles || defaultRoles}`\n          // (precedence: `||` then spread). When we pass our own `roles`, the\n          // built-in owner/admin/member are silently dropped, so even the org\n          // owner loses `invitation:create` and every mutation 403s. We must\n          // re-include the defaults alongside our extras.\n          const defaultRoles = importedDefaultRoles || null;\n          if (defaultAc && memberAc && typeof memberAc.statements === 'object') {\n            const built: Record<string, any> = defaultRoles ? { ...defaultRoles } : {};\n            const stmts = memberAc.statements;\n            for (const name of extra) {\n              if (!name) continue;\n              if (built[name]) continue;\n              built[name] = defaultAc.newRole(stmts);\n            }\n            customOrgRoles = built;\n          }\n        } catch {\n          customOrgRoles = undefined;\n        }\n      }\n      plugins.push(organization({\n        schema: buildOrganizationPluginSchema(),\n        // Enable the team sub-feature so the framework's `sys_team` /\n        // `sys_team_member` tables (already declared in platform-objects)\n        // are actually wired up to better-auth's CRUD endpoints\n        // (`/organization/{create,update,remove,list}-team[s]` and\n        // `/organization/{add,remove,list}-team-member[s]`). The Account\n        // portal exposes a Teams page; without this flag those endpoints\n        // 404 and the section silently breaks.\n        teams: { enabled: true },\n        // Without a mailer wired in framework, requiring email verification\n        // before accepting invitations dead-ends every invite flow with\n        // FORBIDDEN EMAIL_VERIFICATION_REQUIRED…. Default-off here keeps\n        // the built-in /accept-invitation route usable for pilots; operators\n        // who wire a real mailer can re-enable downstream.\n        requireEmailVerificationOnInvitation: false,\n        ...(customOrgRoles ? { roles: customOrgRoles } : {}),\n        // ── Slug-change guard ─────────────────────────────────────\n        // An org's slug is baked into every env hostname at creation\n        // time (see service-tenant `project-provisioning.ts`). Renaming\n        // it while live envs exist would silently desync the URL from\n        // the org identity. Block the change here; the cloud Console\n        // surfaces this as an actionable error and points users to\n        // `change_hostname` or archiving the env. Org `name` (display\n        // label) is unaffected — only `slug` is guarded.\n        //\n        // We resolve the data engine lazily so non-cloud apps (which\n        // never seed `sys_environment`) keep working: any lookup error\n        // is treated as \"no envs to protect\".\n        organizationHooks: {\n          // Gate fresh organization creation behind the multi-org flag.\n          // The plugin itself is always installed (so list/update/invite endpoints\n          // keep responding); only the `create` operation is denied when the\n          // deployment is provisioned in single-org mode. Resolution order:\n          // 1. explicit `OS_MULTI_ORG_ENABLED` (wins for backwards compat),\n          // 2. else `OS_MULTI_TENANT` (multi-tenant deployments are always\n          //    multi-org), default `'false'` → single-org / per-env runtime.\n          beforeCreateOrganization: async () => {\n            const env = (globalThis as any)?.process?.env ?? {};\n            const explicit = env.OS_MULTI_ORG_ENABLED;\n            const legacy = explicit === undefined\n              ? readEnvWithDeprecation('OS_MULTI_ORG_ENABLED', 'OS_MULTI_TENANT')\n              : explicit;\n            const flag = String(legacy ?? 'false').toLowerCase();\n            if (flag === 'false') {\n              const { APIError } = await import('better-auth/api');\n              throw new APIError('FORBIDDEN', {\n                message:\n                  'Creating additional organizations is disabled on this deployment.',\n              });\n            }\n          },\n          beforeUpdateOrganization: async ({ organization, member }: any) => {\n            const newSlug = organization?.slug;\n            const orgId = member?.organizationId;\n            if (!newSlug || !orgId) return;\n\n            const dataEngine = this.config.dataEngine as any;\n            if (!dataEngine) return;\n\n            let currentSlug: string | undefined;\n            try {\n              const current = await dataEngine.findOne('sys_organization', {\n                where: { id: orgId },\n              });\n              currentSlug = current?.slug;\n            } catch {\n              return;\n            }\n            if (!currentSlug || currentSlug === newSlug) return;\n\n            let activeEnvs = 0;\n            try {\n              const envs = await dataEngine.find('sys_environment', {\n                where: { organization_id: orgId },\n              });\n              activeEnvs = (envs ?? []).filter(\n                (e: any) => e?.status !== 'archived' && e?.status !== 'failed',\n              ).length;\n            } catch {\n              return;\n            }\n\n            if (activeEnvs > 0) {\n              const { APIError } = await import('better-auth/api');\n              throw new APIError('FORBIDDEN', {\n                message:\n                  `Cannot change organization slug while ${activeEnvs} active ` +\n                  `environment(s) still reference it. Archive those environments ` +\n                  `or rename their hostnames first.`,\n              });\n            }\n          },\n        },\n        // No mailer is wired in framework yet — log the accept URL so\n        // operators / UI can fall back to copy-paste flows. Replace this\n        // with a real mail integration when available.\n        sendInvitationEmail: async ({ email: recipientEmail, invitation, organization: org, inviter }) => {\n          const baseUrl = (this.config.baseUrl ?? '').replace(/\\/$/, '');\n          const acceptUrl = `${baseUrl}/accept-invitation/${invitation.id}`;\n          const emailService = this.getEmailService();\n          if (!emailService) {\n            console.warn(\n              `[AuthManager] Invitation email not configured. ` +\n              `To: ${recipientEmail} (org: ${org?.name ?? invitation.organizationId}, ` +\n              `role: ${invitation.role}, inviter: ${inviter?.user?.email ?? 'unknown'}) ` +\n              `URL: ${acceptUrl}`,\n            );\n            return;\n          }\n          try {\n            await emailService.sendTemplate({\n              template: 'auth.invitation',\n              to: recipientEmail,\n              data: {\n                inviter: {\n                  name: inviter?.user?.name ?? inviter?.user?.email ?? 'A teammate',\n                  email: inviter?.user?.email ?? '',\n                },\n                organization: { name: org?.name ?? invitation.organizationId },\n                role: invitation.role || '',\n                acceptUrl,\n                appName: this.getAppName(),\n              },\n              relatedObject: 'sys_invitation',\n              relatedId: invitation.id,\n            });\n          } catch (err: any) {\n            // Do NOT rethrow: the invitation row was already persisted by\n            // better-auth; an email-transport failure must not turn the\n            // invite request into a 500. The admin can resend the invite.\n            console.error(`[AuthManager] sendInvitationEmail failed (swallowed): ${err?.message ?? err}`);\n          }\n        },\n      }));\n    }\n\n    if (enabled.twoFactor) {\n      const { twoFactor } = await import('better-auth/plugins/two-factor');\n      plugins.push(twoFactor({\n        schema: buildTwoFactorPluginSchema(),\n      }));\n    }\n\n    if (enabled.admin) {\n      const { admin } = await import('better-auth/plugins/admin');\n      // Platform admin: ban/unban, set-password, impersonate, set-role.\n      // Schema mapping ensures the plugin's added user/session columns\n      // match ObjectStack's snake_case conventions (ban_reason,\n      // ban_expires, impersonated_by). `role` and `banned` are already\n      // snake_case-compatible.\n      plugins.push(admin({\n        schema: buildAdminPluginSchema(),\n      }));\n    }\n\n    if (enabled.magicLink) {\n      const { magicLink } = await import('better-auth/plugins/magic-link');\n      // magic-link reuses the `verification` table — no extra schema mapping needed.\n      plugins.push(magicLink({\n        sendMagicLink: async ({ email: recipientEmail, url, token }) => {\n          const emailService = this.getEmailService();\n          if (!emailService) {\n            console.warn(\n              `[AuthManager] Magic-link requested for ${recipientEmail} but no email service is wired. URL: ${url}`,\n            );\n            return;\n          }\n          try {\n            await emailService.sendTemplate({\n              template: 'auth.magic_link',\n              to: recipientEmail,\n              data: {\n                magicLinkUrl: url,\n                token,\n                expiresInMinutes: 10,\n                appName: this.getAppName(),\n              },\n            });\n          } catch (err: any) {\n            console.error(`[AuthManager] sendMagicLink failed: ${err?.message ?? err}`);\n            throw err;\n          }\n        },\n      }));\n    }\n\n    // OIDC / Generic OAuth2 providers (enterprise SSO via genericOAuth plugin)\n    if (this.config.oidcProviders?.length) {\n      const { genericOAuth } = await import('better-auth/plugins/generic-oauth');\n      plugins.push(genericOAuth({\n        config: this.config.oidcProviders.map(p => ({\n          providerId: p.providerId,\n          ...(p.discoveryUrl ? { discoveryUrl: p.discoveryUrl } : {}),\n          ...(p.issuer ? { issuer: p.issuer } : {}),\n          ...(p.authorizationUrl ? { authorizationUrl: p.authorizationUrl } : {}),\n          ...(p.tokenUrl ? { tokenUrl: p.tokenUrl } : {}),\n          ...(p.userInfoUrl ? { userInfoUrl: p.userInfoUrl } : {}),\n          clientId: p.clientId,\n          clientSecret: p.clientSecret,\n          ...(p.scopes ? { scopes: p.scopes } : {}),\n          ...(p.pkce != null ? { pkce: p.pkce } : {}),\n        })),\n      }));\n    }\n\n    // OAuth/OIDC Provider — turn this server into an OpenID Connect Identity\n    // Provider so external apps can SSO via ObjectStack. Adds the\n    // `/oauth2/{authorize,token,userinfo,register,consent,endsession}` and\n    // `/.well-known/openid-configuration` endpoints under the auth route.\n    //\n    // Migrated from the deprecated `better-auth/plugins/oidc-provider` to the\n    // standalone `@better-auth/oauth-provider` package. The new plugin uses\n    // `oauthClient`, `oauthAccessToken`, `oauthRefreshToken`, and `oauthConsent`\n    // models — see `buildOauthProviderPluginSchema()` for the snake_case\n    // mappings to ObjectStack's `sys_oauth_*` tables.\n    if (enabled.oidcProvider) {\n      // The new @better-auth/oauth-provider package requires the `jwt`\n      // plugin (used to sign id_tokens / JWT access tokens). Register it\n      // automatically — it is otherwise an internal implementation detail\n      // and forcing every consumer to opt in would be poor DX.\n      const { jwt } = await import('better-auth/plugins');\n      plugins.push(jwt({ schema: buildJwtPluginSchema() }));\n\n      const { oauthProvider } = await import('@better-auth/oauth-provider');\n      const baseUrl = (this.config.baseUrl ?? '').replace(/\\/$/, '');\n      const uiBase = (this.config.uiBasePath ?? '/_console').replace(/\\/$/, '');\n      plugins.push(oauthProvider({\n        // Console SPA renders both pages (replaces the legacy Account SPA at\n        // /_account). Override `uiBasePath` in AuthConfig if Console is\n        // mounted elsewhere.\n        loginPage: `${baseUrl}${uiBase}/login`,\n        consentPage: `${baseUrl}${uiBase}/oauth/consent`,\n        schema: buildOauthProviderPluginSchema(),\n      }));\n    }\n\n    // Device Authorization Grant (RFC 8628) — for CLI / TV-style devices.\n    // Exposes the standard `/device/{code,token,approve,deny}` endpoints\n    // and persists pending requests in `sys_device_code`.\n    //\n    // The verification URI points at the account portal page that lets a\n    // signed-in user approve or deny a pending CLI login. The page reads\n    // the `user_code` query parameter that better-auth appends to\n    // `verification_uri_complete`.\n    if (enabled.deviceAuthorization) {\n      const { deviceAuthorization } = await import('better-auth/plugins/device-authorization');\n      const baseUrl = (this.config.baseUrl ?? '').replace(/\\/$/, '');\n      const uiBase = (this.config.uiBasePath ?? '/_console').replace(/\\/$/, '');\n      plugins.push(deviceAuthorization({\n        verificationUri: `${baseUrl}${uiBase}/auth/device`,\n        schema: buildDeviceAuthorizationPluginSchema(),\n      }));\n    }\n\n    // customSession() — augments the session payload with a derived `role`\n    // field so frontend gating (e.g. AppShell's `isAdmin = user.role === 'admin'`)\n    // works without each consumer having to re-query permission sets.\n    //\n    // It also returns a `roles: string[]` array: the stored `user.role`\n    // string split on commas (the admin plugin stores multi-role users as\n    // e.g. `\"admin,manager\"`), with `'admin'` appended (deduplicated) when\n    // the user is promoted below. Consumers that match on individual role\n    // names (e.g. the Console approvals inbox resolving `role:<name>`\n    // approvers) must read `roles` — `user.role` is *replaced* by the\n    // literal `'admin'` on promotion, so business roles such as `manager`\n    // only survive in the array.\n    //\n    // Better-auth's `sys_user` table doesn't carry a `role` column. We derive\n    // it from two sources:\n    //\n    //   1. **Platform admin** — a `sys_user_permission_set` row that points at\n    //      the `admin_full_access` permission set with `organization_id = null`\n    //      (seeded by `bootstrapPlatformAdmin`).\n    //   2. **Organization admin** — a `sys_member` row in the user's *active*\n    //      organization (`session.activeOrganizationId`) with role `owner` or\n    //      `admin`. Org owners/admins are entitled to manage org-scoped\n    //      metadata such as saved list views, dashboards, etc.\n    //\n    // Either path synthesizes `user.role = 'admin'` so the frontend can gate\n    // metadata-edit affordances uniformly. The raw membership role remains\n    // available via the `organization` plugin's `member` payload for\n    // finer-grained checks.\n    const dataEngine = this.config.dataEngine;\n    if (dataEngine) {\n      const { customSession } = await import('better-auth/plugins/custom-session');\n      plugins.push(customSession(async ({ user, session }) => {\n        if (!user?.id) return { user, session };\n\n        const isPlatformAdmin = async (): Promise<boolean> => {\n          try {\n            const links = await dataEngine.find('sys_user_permission_set', {\n              where: { user_id: user.id },\n              limit: 50,\n            });\n            const platformLinks = (Array.isArray(links) ? links : []).filter(\n              (l: any) => !l.organization_id,\n            );\n            if (platformLinks.length === 0) return false;\n            const sets = await dataEngine.find('sys_permission_set', { limit: 50 });\n            const adminSet = (Array.isArray(sets) ? sets : []).find(\n              (r: any) => r.name === 'admin_full_access',\n            );\n            if (!adminSet) return false;\n            return platformLinks.some(\n              (l: any) => l.permission_set_id === adminSet.id,\n            );\n          } catch {\n            return false;\n          }\n        };\n\n        const isActiveOrgAdmin = async (): Promise<boolean> => {\n          try {\n            const orgId = (session as any)?.activeOrganizationId;\n            if (!orgId) return false;\n            const members = await dataEngine.find('sys_member', {\n              where: { user_id: user.id, organization_id: orgId },\n              limit: 5,\n            });\n            return (Array.isArray(members) ? members : []).some((m: any) => {\n              // better-auth org plugin stores roles as either a single string\n              // or a comma-separated list (e.g. `\"owner,admin\"`). Treat any\n              // membership that includes `owner` or `admin` as administrative.\n              const raw = typeof m?.role === 'string' ? m.role : '';\n              const roles = raw.split(',').map((s: string) => s.trim().toLowerCase());\n              return roles.includes('owner') || roles.includes('admin');\n            });\n          } catch {\n            return false;\n          }\n        };\n\n        const platformAdmin = await isPlatformAdmin();\n        const promote = platformAdmin || (await isActiveOrgAdmin());\n        const storedRole = typeof (user as any).role === 'string' ? (user as any).role : '';\n        const roles = storedRole\n          .split(',')\n          .map((s: string) => s.trim())\n          .filter(Boolean);\n        if (promote && !roles.includes('admin')) roles.push('admin');\n        if (!promote) return { user: { ...user, roles, isPlatformAdmin: platformAdmin }, session };\n        return { user: { ...user, role: 'admin', roles, isPlatformAdmin: platformAdmin }, session };\n      }));\n    }\n\n    return plugins;\n  }\n\n  /**\n   * Create database configuration using ObjectQL adapter\n   *\n   * better-auth resolves the `database` option as follows:\n   * - `undefined`            → in-memory adapter\n   * - `typeof fn === \"function\"` → treated as `DBAdapterInstance`, called with `(options)`\n   * - otherwise              → forwarded to Kysely adapter factory (pool/dialect)\n   *\n   * A raw `CustomAdapter` object would fall into the third branch and fail\n   * silently.  We therefore wrap the ObjectQL adapter in a factory function\n   * so it is correctly recognised as a `DBAdapterInstance`.\n   */\n  private createDatabaseConfig(): any {\n    // Use ObjectQL adapter factory if dataEngine is provided\n    if (this.config.dataEngine) {\n      // createObjectQLAdapterFactory returns an AdapterFactory\n      // (options => DBAdapter) which better-auth invokes via getBaseAdapter().\n      // The factory is created by better-auth's createAdapterFactory and\n      // automatically applies modelName/fields transformations declared in\n      // the betterAuth config above.\n      return createObjectQLAdapterFactory(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 = readEnvWithDeprecation('OS_AUTH_SECRET', ['AUTH_SECRET', 'BETTER_AUTH_SECRET']);\n    if (envSecret) return envSecret;\n\n    // No secret configured. In production this is FATAL: a predictable\n    // `dev-secret-<timestamp>` makes session tokens forgeable (session\n    // forgery). Refuse to boot rather than run insecurely.\n    if (process.env.NODE_ENV === 'production') {\n      throw new Error(\n        '[auth] OS_AUTH_SECRET is required in production but is not set. ' +\n        'Refusing to boot with a temporary development secret — session tokens ' +\n        'would be forgeable. Set OS_AUTH_SECRET to a strong random value.'\n      );\n    }\n\n    // Development / test only: fall back to an ephemeral secret, loudly.\n    const fallbackSecret = 'dev-secret-' + Date.now();\n    console.warn(\n      '⚠️  WARNING: No OS_AUTH_SECRET environment variable set! ' +\n      'Using a temporary development secret. ' +\n      'This is NOT secure for production use. ' +\n      'Please set OS_AUTH_SECRET in your environment variables.'\n    );\n    return fallbackSecret;\n  }\n\n  /**\n   * Update the base URL at runtime.\n   *\n   * This **must** be called before the first request triggers lazy\n   * initialisation of the better-auth instance — typically from a\n   * `kernel:ready` hook where the actual server port is known.\n   *\n   * If the auth instance has already been created this is a no-op and\n   * a warning is emitted.\n   */\n  setRuntimeBaseUrl(url: string): void {\n    if (this.auth) {\n      console.warn(\n        '[AuthManager] setRuntimeBaseUrl() called after the auth instance was already created — ignoring. ' +\n        'Ensure this method is called before the first request.',\n      );\n      return;\n    }\n    this.config = { ...this.config, baseUrl: url };\n  }\n\n  /**\n   * Merge runtime configuration into the manager.\n   *\n   * Settings-backed auth policy can change after the manager is constructed.\n   * better-auth itself is created lazily, so changing config before the first\n   * request is enough. If an instance already exists, reset it so the next\n   * request rebuilds with the new policy.\n   */\n  applyConfigPatch(patch: Partial<AuthManagerOptions>): void {\n    const next: AuthManagerOptions = {\n      ...this.config,\n      ...patch,\n      ...(patch.emailAndPassword\n        ? {\n          emailAndPassword: {\n            ...(this.config.emailAndPassword ?? {}),\n            ...patch.emailAndPassword,\n          },\n        }\n        : {}),\n      ...(patch.plugins\n        ? {\n          plugins: {\n            ...(this.config.plugins ?? {}),\n            ...patch.plugins,\n          },\n        }\n        : {}),\n    };\n\n    if ('socialProviders' in patch) {\n      next.socialProviders = patch.socialProviders;\n    }\n\n    this.config = next;\n    if (this.auth && !patch.authInstance) {\n      this.auth = null;\n    }\n  }\n\n  /**\n   * Inject (or replace) the outbound email service used by better-auth\n   * callbacks. Safe to call after construction but BEFORE the first\n   * request hits the auth handler — callbacks read this via\n   * {@link getEmailService} when invoked.\n   *\n   * AuthPlugin calls this on `kernel:ready` once `ctx.getService('email')`\n   * resolves. For tests / serverless, callers may invoke directly.\n   */\n  setEmailService(email: IEmailService | undefined): void {\n    this.config.emailService = email;\n  }\n\n  /** @internal Used by callback closures. */\n  private getEmailService(): IEmailService | undefined {\n    return this.config.emailService;\n  }\n\n  /**\n   * Override the brand name surfaced in built-in auth emails (`{{appName}}`),\n   * sourced from the live `branding.workspace_name` setting.\n   *\n   * AuthPlugin calls this on `kernel:ready` (and again whenever the setting\n   * changes) once the `settings` service resolves. Passing `undefined` clears\n   * the override so resolution falls back to the configured `appName`. The\n   * value only reflects an *explicitly set* setting — when the operator has\n   * not customised it, AuthPlugin passes `undefined` so a deployment's\n   * configured `appName` (e.g. `OS_APP_NAME`) keeps precedence.\n   */\n  setAppName(name: string | undefined): void {\n    this.appNameOverride = name?.trim() || undefined;\n  }\n  private appNameOverride?: string;\n\n  /** @internal `{{appName}}` placeholder value for built-in templates. */\n  private getAppName(): string {\n    return this.appNameOverride ?? this.config.appName ?? 'ObjectStack';\n  }\n\n  /**\n   * Get the underlying better-auth instance\n   * Useful for advanced use cases\n   */\n  getAuthInstance(): Promise<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   * better-auth catches internal errors (database / adapter / ORM) and\n   * returns a 500 Response instead of throwing.  We therefore inspect the\n   * response status and log server errors so they are not silently swallowed.\n   *\n   * @param request - Web standard Request object\n   * @returns Web standard Response object\n   */\n  async handleRequest(request: Request): Promise<Response> {\n    // Dev DX: better-auth's CSRF protection rejects state-changing requests\n    // (e.g. `/sign-in/email`) with a 403 when neither `Origin` nor `Referer`\n    // is present. Browsers always send one; non-browser API clients (curl,\n    // fetch from a script, integration tests) often don't, so they hit an\n    // opaque 403 in local dev. A request with *no* Origin header is never a\n    // browser-driven cross-site attack — CSRF is fundamentally cross-origin —\n    // so in non-production we synthesize a same-origin `Origin` from the\n    // request URL. It matches the dev localhost trusted-origins set, so the\n    // CSRF check passes without weakening protection in production (gated on\n    // NODE_ENV, the same dev signal used for the fallback auth secret above).\n    if (\n      process.env.NODE_ENV !== 'production' &&\n      !request.headers.get('origin') &&\n      !request.headers.get('referer')\n    ) {\n      try {\n        const headers = new Headers(request.headers);\n        headers.set('origin', new URL(request.url).origin);\n        request = new Request(request, { headers });\n      } catch {\n        /* malformed URL — leave the request untouched */\n      }\n    }\n\n    const auth = await this.getOrCreateAuth();\n    // better-auth's HTTP entrypoint (`createBetterAuth.handler`) wraps execution\n    // in `runWithAdapter` but NOT `runWithRequestState`. Endpoints that read\n    // request-state via `defineRequestState()` (e.g. `should-session-refresh`,\n    // `oauth`) therefore throw \"No request state found\" when reached via HTTP.\n    // The `customSession` plugin triggers this by invoking the inner\n    // `getSession()` endpoint directly, bypassing `to-auth-endpoints`'\n    // auto-wrap. We establish the ALS store here so all downstream endpoint\n    // calls inherit a valid request-state WeakMap.\n    const { runWithRequestState } = await import('@better-auth/core/context');\n    const response = await runWithRequestState(new WeakMap(), () => auth.handler(request));\n\n    if (response.status >= 500) {\n      try {\n        const body = await response.clone().text();\n        console.error('[AuthManager] better-auth returned error:', response.status, body);\n      } catch {\n        console.error('[AuthManager] better-auth returned error:', response.status, '(unable to read body)');\n      }\n    }\n\n    return response;\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  async getApi(): Promise<Auth<any>['api']> {\n    const auth = await this.getOrCreateAuth();\n    return auth.api;\n  }\n\n  /**\n   * Get the underlying better-auth context for low-level operations such as\n   * `internalAdapter.createAccount` / `password.hash`.\n   *\n   * Used by routes that need to write to better-auth's tables outside the\n   * normal endpoint surface — currently only `set-initial-password`, which\n   * provisions a credential account for SSO-onboarded users so they can\n   * sign in with email/password going forward.\n   */\n  async getAuthContext(): Promise<any> {\n    const auth = await this.getOrCreateAuth();\n    return (auth as any).$context;\n  }\n\n  // ---------------------------------------------------------------------------\n  // Device Flow (CLI browser-based login)\n  //\n  // The device authorization flow (RFC 8628) is now handled entirely by\n  // better-auth's `device-authorization` plugin. Endpoints are exposed at\n  // `${basePath}/device/{code,token,approve,deny}` and persisted in\n  // `sys_device_code`. Enable via `plugins.deviceAuthorization: true` in\n  // AuthPluginConfig.\n  // ---------------------------------------------------------------------------\n\n  getPublicConfig() {\n    // Extract social providers info (without sensitive data)\n    const socialProviders = [];\n    if (this.config.socialProviders) {\n      for (const [id, providerConfig] of Object.entries(this.config.socialProviders)) {\n        if (providerConfig.enabled !== false) {\n          // Map provider ID to friendly name\n          const nameMap: Record<string, string> = {\n            google: 'Google',\n            github: 'GitHub',\n            microsoft: 'Microsoft',\n            apple: 'Apple',\n            facebook: 'Facebook',\n            twitter: 'Twitter',\n            discord: 'Discord',\n            gitlab: 'GitLab',\n            linkedin: 'LinkedIn',\n          };\n\n          socialProviders.push({\n            id,\n            name: nameMap[id] || id.charAt(0).toUpperCase() + id.slice(1),\n            enabled: true,\n            type: 'social' as const,\n          });\n        }\n      }\n    }\n\n    // Append OIDC providers\n    if (this.config.oidcProviders?.length) {\n      for (const p of this.config.oidcProviders) {\n        socialProviders.push({\n          id: p.providerId,\n          name: p.name ?? (p.providerId.charAt(0).toUpperCase() + p.providerId.slice(1)),\n          enabled: true,\n          type: 'oidc' as const,\n        });\n      }\n    }\n\n    // Extract email/password config (safe fields only). Deployment env can\n    // lock registration policy; otherwise we fall back to configured/settings\n    // `emailAndPassword.disableSignUp` (default `false`).\n    const emailPasswordConfig: Partial<EmailAndPasswordConfig> = this.config.emailAndPassword ?? {};\n    const disableSignUpFromEnv = readDisableSignUpEnv();\n    const emailPassword = {\n      enabled: emailPasswordConfig.enabled !== false, // Default to true\n      disableSignUp: disableSignUpFromEnv ?? emailPasswordConfig.disableSignUp ?? false,\n      requireEmailVerification: emailPasswordConfig.requireEmailVerification ?? false,\n    };\n\n    // Extract enabled features\n    const pluginConfig: Partial<AuthPluginConfig> = this.config.plugins ?? {};\n    // Multi-org capability (UI org-switcher, \"create org\" action, etc.).\n    // Resolution order: explicit `OS_MULTI_ORG_ENABLED` wins, else fall\n    // back to legacy `OS_MULTI_TENANT` (multi-tenant deployments are always\n    // multi-org); default `'false'` → single-org / per-env runtime.\n    const multiOrgEnv = (globalThis as any)?.process?.env ?? {};\n    const multiOrgRaw = multiOrgEnv.OS_MULTI_ORG_ENABLED !== undefined\n      ? multiOrgEnv.OS_MULTI_ORG_ENABLED\n      : (readEnvWithDeprecation('OS_MULTI_ORG_ENABLED', 'OS_MULTI_TENANT') ?? 'false');\n    const multiOrgEnabled = String(multiOrgRaw).toLowerCase() !== 'false';\n\n    // Legal links shown beneath the login / register cards. Defaults to\n    // the public ObjectStack pages so vanilla deployments don't link to\n    // dead `#` anchors; operators who deploy ObjectStack on their own\n    // domain typically override these with their own legal docs via the\n    // `OS_TERMS_URL` / `OS_PRIVACY_URL` env vars. Set the env var to the\n    // empty string to suppress the link entirely.\n    const DEFAULT_TERMS_URL = 'https://objectstack.ai/terms';\n    const DEFAULT_PRIVACY_URL = 'https://objectstack.ai/privacy';\n    const rawTermsUrl = (globalThis as any)?.process?.env?.OS_TERMS_URL;\n    const rawPrivacyUrl = (globalThis as any)?.process?.env?.OS_PRIVACY_URL;\n    const resolveLegalUrl = (raw: unknown, fallback: string): string | undefined => {\n      if (typeof raw !== 'string') return fallback;\n      const trimmed = raw.trim();\n      // Explicit empty string (`OS_TERMS_URL=`) opts out of the link.\n      if (trimmed === '') return undefined;\n      return trimmed;\n    };\n    const termsUrl = resolveLegalUrl(rawTermsUrl, DEFAULT_TERMS_URL);\n    const privacyUrl = resolveLegalUrl(rawPrivacyUrl, DEFAULT_PRIVACY_URL);\n\n    // OIDC Provider — same env-var override as in `buildPlugins()`. The\n    // /auth/config response MUST match what's actually wired, otherwise the\n    // frontend will render UI for endpoints that 404.\n    const oidcEnv = (globalThis as any)?.process?.env?.OS_OIDC_PROVIDER_ENABLED;\n    const oidcFromEnv = oidcEnv != null ? String(oidcEnv).toLowerCase() === 'true' : undefined;\n    const twoFactorFromEnv = readBooleanEnv('OS_AUTH_TWO_FACTOR');\n\n    const features = {\n      twoFactor: twoFactorFromEnv ?? pluginConfig.twoFactor ?? false,\n      passkeys: pluginConfig.passkeys ?? false,\n      magicLink: pluginConfig.magicLink ?? false,\n      organization: pluginConfig.organization ?? true,\n      multiOrgEnabled,\n      oidcProvider: oidcFromEnv ?? pluginConfig.oidcProvider ?? false,\n      deviceAuthorization: pluginConfig.deviceAuthorization ?? false,\n      admin: pluginConfig.admin ?? false,\n      ...(termsUrl ? { termsUrl } : {}),\n      ...(privacyUrl ? { privacyUrl } : {}),\n    };\n\n    return {\n      emailPassword,\n      socialProviders,\n      features,\n    };\n  }\n\n  /**\n   * Returns the data engine wired into this auth manager. Used by route\n   * handlers (e.g. bootstrap-status) that need to query identity tables\n   * directly without going through better-auth.\n   */\n  public getDataEngine(): IDataEngine | undefined {\n    return this.config.dataEngine;\n  }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { IDataEngine } from '@objectstack/core';\nimport { createAdapterFactory } from 'better-auth/adapters';\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// Internal helpers\n// ---------------------------------------------------------------------------\n\n/**\n * better-auth datetime columns (snake_case) per model.\n *\n * When the underlying driver stored these as JavaScript `Date` objects\n * (legacy behaviour), the libsql HTTP transport coerces the value to a REAL\n * column and round-trips it as a string like `\"1779497911249.0\"`. That\n * string is not a valid Date string (it has a trailing `.0`), so\n * `new Date(...)` produces `Invalid Date` and better-auth's client treats\n * the session as expired — causing a login/redirect loop.\n *\n * We normalise these legacy values back to ISO strings on **read** so the\n * factory's `supportsDates: false` parser can turn them into real Date\n * objects. New writes always go through better-auth's own\n * `Date → ISO string` conversion (because we declare `supportsDates: false`\n * below), so no further `.0`-suffixed values will ever be created.\n */\nconst LEGACY_DATETIME_FIELDS_BY_MODEL: Record<string, string[]> = {\n  user: ['created_at', 'updated_at'],\n  session: ['expires_at', 'created_at', 'updated_at'],\n  account: [\n    'access_token_expires_at',\n    'refresh_token_expires_at',\n    'created_at',\n    'updated_at',\n  ],\n  verification: ['expires_at', 'created_at', 'updated_at'],\n};\n\nconst NUMERIC_STRING_RE = /^-?\\d+(\\.\\d+)?$/;\n\n/**\n * If `value` looks like a stringified epoch-ms (optionally with `.0`),\n * convert it to an ISO 8601 string. Otherwise return it unchanged.\n */\nfunction normaliseLegacyDate(value: unknown): unknown {\n  if (typeof value !== 'string') return value;\n  if (!NUMERIC_STRING_RE.test(value)) return value;\n  const n = parseFloat(value);\n  if (!Number.isFinite(n)) return value;\n  // Heuristic: epoch milliseconds are at least 10 digits (year 2001+).\n  if (Math.abs(n) < 1e10) return value;\n  const d = new Date(n);\n  if (Number.isNaN(d.getTime())) return value;\n  return d.toISOString();\n}\n\n/**\n * Walk a record and rewrite any legacy `.0`-suffixed datetime values\n * into ISO strings. Mutates and returns the record.\n */\nfunction normaliseLegacyDates<T extends Record<string, any> | null | undefined>(\n  model: string,\n  record: T,\n): T {\n  if (!record) return record;\n  const cols = LEGACY_DATETIME_FIELDS_BY_MODEL[model];\n  if (!cols) return record;\n  for (const col of cols) {\n    if (col in record) {\n      (record as Record<string, unknown>)[col] = normaliseLegacyDate(\n        (record as Record<string, unknown>)[col],\n      );\n    }\n  }\n  return record;\n}\n\n/**\n * Convert better-auth where clause to ObjectQL query format.\n *\n * Field names in the incoming {@link CleanedWhere} are expected to already be\n * in snake_case (transformed by `createAdapterFactory`).\n */\nfunction convertWhere(where: CleanedWhere[]): Record<string, any> {\n  const filter: Record<string, any> = {};\n\n  for (const condition of where) {\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// ---------------------------------------------------------------------------\n// Adapter factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create an ObjectQL adapter **factory** for better-auth.\n *\n * Uses better-auth's official `createAdapterFactory` so that model-name and\n * field-name transformations (declared via `modelName` / `fields` in the\n * betterAuth config) are applied **automatically** before any data reaches\n * ObjectQL. This eliminates the need for manual camelCase ↔ snake_case\n * conversion inside the adapter.\n *\n * The returned value is an `AdapterFactory` – a function of type\n * `(options: BetterAuthOptions) => DBAdapter` – which is the shape expected\n * by `betterAuth({ database: … })`.\n *\n * @param dataEngine - ObjectQL data engine instance\n * @returns better-auth AdapterFactory\n */\nexport function createObjectQLAdapterFactory(dataEngine: IDataEngine) {\n  return createAdapterFactory({\n    config: {\n      adapterId: 'objectql',\n      // We let better-auth handle Date↔string and boolean↔0/1 conversion so\n      // that values land in the underlying SQL driver as primitive strings\n      // and integers. Some drivers (e.g. libsql over the HTTP transport)\n      // otherwise mangle `Date` objects into `\"<epoch>.0\"` strings that\n      // break the client-side session parser.\n      supportsBooleans: false,\n      supportsDates: false,\n      supportsJSON: true,\n    },\n    adapter: () => ({\n      create: async <T extends Record<string, any>>(\n        { model, data, select: _select }: { model: string; data: T; select?: string[] },\n      ): Promise<T> => {\n        const result = await dataEngine.insert(model, data);\n        return normaliseLegacyDates(model, result) as T;\n      },\n\n      findOne: async <T>(\n        { model, where, select, join: _join }: { model: string; where: CleanedWhere[]; select?: string[]; join?: any },\n      ): Promise<T | null> => {\n        const filter = convertWhere(where);\n\n        const result = await dataEngine.findOne(model, { where: filter, fields: select });\n\n        return result ? (normaliseLegacyDates(model, result) as T) : null;\n      },\n\n      findMany: async <T>(\n        { model, where, limit, offset, sortBy, join: _join }: {\n          model: string; where?: CleanedWhere[]; limit: number;\n          offset?: number; sortBy?: { field: string; direction: 'asc' | 'desc' }; join?: any;\n        },\n      ): Promise<T[]> => {\n        const filter = where ? convertWhere(where) : {};\n\n        const orderBy = sortBy\n          ? [{ field: sortBy.field, order: sortBy.direction as 'asc' | 'desc' }]\n          : undefined;\n\n        const results = await dataEngine.find(model, {\n          where: filter,\n          limit: limit || 100,\n          offset,\n          orderBy,\n        });\n\n        return results.map((r) => normaliseLegacyDates(model, r as Record<string, any>)) as T[];\n      },\n\n      count: async (\n        { model, where }: { model: string; where?: CleanedWhere[] },\n      ): Promise<number> => {\n        const filter = where ? convertWhere(where) : {};\n        return await dataEngine.count(model, { where: filter });\n      },\n\n      update: async <T>(\n        { model, where, update }: { model: string; where: CleanedWhere[]; update: T },\n      ): Promise<T | null> => {\n        const filter = convertWhere(where);\n\n        // ObjectQL requires an ID for updates – find the record first\n        const record = await dataEngine.findOne(model, { where: filter });\n        if (!record) return null;\n\n        const result = await dataEngine.update(model, { ...(update as any), id: record.id });\n        return result ? (normaliseLegacyDates(model, result) as T) : null;\n      },\n\n      updateMany: async (\n        { model, where, update }: { model: string; where: CleanedWhere[]; update: Record<string, any> },\n      ): Promise<number> => {\n        const filter = convertWhere(where);\n\n        // Sequential updates: ObjectQL requires an ID per update\n        const records = await dataEngine.find(model, { where: filter });\n        for (const record of records) {\n          await dataEngine.update(model, { ...update, id: record.id });\n        }\n        return records.length;\n      },\n\n      delete: async (\n        { model, where }: { model: string; where: CleanedWhere[] },\n      ): Promise<void> => {\n        const filter = convertWhere(where);\n\n        const record = await dataEngine.findOne(model, { where: filter });\n        if (!record) return;\n\n        await dataEngine.delete(model, { where: { id: record.id } });\n      },\n\n      deleteMany: async (\n        { model, where }: { model: string; where: CleanedWhere[] },\n      ): Promise<number> => {\n        const filter = convertWhere(where);\n\n        const records = await dataEngine.find(model, { where: filter });\n        for (const record of records) {\n          await dataEngine.delete(model, { where: { id: record.id } });\n        }\n        return records.length;\n      },\n    }),\n  });\n}\n\n// ---------------------------------------------------------------------------\n// Legacy adapter (kept for backward compatibility)\n// ---------------------------------------------------------------------------\n\n/**\n * Create a raw ObjectQL adapter for better-auth (without factory wrapping).\n *\n * > **Prefer {@link createObjectQLAdapterFactory}** for production use.\n * > The factory version leverages `createAdapterFactory` and automatically\n * > handles model-name + field-name transformations declared in the\n * > better-auth config.\n *\n * This function is retained for direct / low-level usage where callers\n * manage field-name conversion themselves.\n *\n * @param dataEngine - ObjectQL data engine instance\n * @returns better-auth CustomAdapter (raw, without factory wrapping)\n */\nexport function createObjectQLAdapter(dataEngine: IDataEngine) {\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      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      const result = await dataEngine.findOne(objectName, { where: filter, fields: select });\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      const orderBy = sortBy ? [{ field: sortBy.field, order: sortBy.direction as 'asc' | 'desc' }] : undefined;\n      const results = await dataEngine.find(objectName, { where: filter, limit: limit || 100, offset, orderBy });\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      return await dataEngine.count(objectName, { where: 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      const record = await dataEngine.findOne(objectName, { where: filter });\n      if (!record) return null;\n      const result = await dataEngine.update(objectName, { ...update, id: record.id });\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      const records = await dataEngine.find(objectName, { where: filter });\n      for (const record of records) {\n        await dataEngine.update(objectName, { ...update, id: record.id });\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      const record = await dataEngine.findOne(objectName, { where: filter });\n      if (!record) return;\n      await dataEngine.delete(objectName, { where: { 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      const records = await dataEngine.find(objectName, { where: filter });\n      for (const record of records) {\n        await dataEngine.delete(objectName, { where: { id: record.id } });\n      }\n      return records.length;\n    },\n  };\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { SystemObjectName } from '@objectstack/spec/system';\n\n/**\n * better-auth ↔ ObjectStack Schema Mapping\n *\n * better-auth uses camelCase field names internally (e.g. `emailVerified`, `userId`)\n * while ObjectStack's protocol layer uses snake_case (e.g. `email_verified`, `user_id`).\n *\n * These constants declare the `modelName` and `fields` mappings for each core auth\n * model, following better-auth's official schema customisation API\n * ({@link https://www.better-auth.com/docs/concepts/database}).\n *\n * The mappings serve two purposes:\n * 1. `modelName` — maps the default model name to the ObjectStack protocol name\n *    (e.g. `user` → `sys_user`).\n * 2. `fields`   — maps camelCase field names to their snake_case database column\n *    equivalents. Only fields whose names differ need to be listed; fields that\n *    are already identical (e.g. `email`, `name`, `token`) are omitted.\n *\n * These mappings are consumed by:\n * - The `betterAuth()` configuration in {@link AuthManager} so that\n *   `getAuthTables()` builds the correct schema.\n * - The ObjectQL adapter factory (via `createAdapterFactory`) which uses the\n *   schema to transform data and where-clauses automatically.\n */\n\n// ---------------------------------------------------------------------------\n// User model\n// ---------------------------------------------------------------------------\n\n/**\n * better-auth `user` model mapping.\n *\n * | camelCase (better-auth) | snake_case (ObjectStack) |\n * |:------------------------|:-------------------------|\n * | emailVerified           | email_verified           |\n * | createdAt               | created_at               |\n * | updatedAt               | updated_at               |\n */\nexport const AUTH_USER_CONFIG = {\n  modelName: SystemObjectName.USER, // 'sys_user'\n  fields: {\n    emailVerified: 'email_verified',\n    createdAt: 'created_at',\n    updatedAt: 'updated_at',\n  },\n} as const;\n\n// ---------------------------------------------------------------------------\n// Session model\n// ---------------------------------------------------------------------------\n\n/**\n * better-auth `session` model mapping.\n *\n * | camelCase (better-auth) | snake_case (ObjectStack) |\n * |:------------------------|:-------------------------|\n * | userId                  | user_id                  |\n * | expiresAt               | expires_at               |\n * | createdAt               | created_at               |\n * | updatedAt               | updated_at               |\n * | ipAddress               | ip_address               |\n * | userAgent               | user_agent               |\n */\nexport const AUTH_SESSION_CONFIG = {\n  modelName: SystemObjectName.SESSION, // 'sys_session'\n  fields: {\n    userId: 'user_id',\n    expiresAt: 'expires_at',\n    createdAt: 'created_at',\n    updatedAt: 'updated_at',\n    ipAddress: 'ip_address',\n    userAgent: 'user_agent',\n  },\n} as const;\n\n// ---------------------------------------------------------------------------\n// Account model\n// ---------------------------------------------------------------------------\n\n/**\n * better-auth `account` model mapping.\n *\n * | camelCase (better-auth)   | snake_case (ObjectStack)       |\n * |:--------------------------|:-------------------------------|\n * | userId                    | user_id                        |\n * | providerId                | provider_id                    |\n * | accountId                 | account_id                     |\n * | accessToken               | access_token                   |\n * | refreshToken              | refresh_token                  |\n * | idToken                   | id_token                       |\n * | accessTokenExpiresAt      | access_token_expires_at        |\n * | refreshTokenExpiresAt     | refresh_token_expires_at       |\n * | createdAt                 | created_at                     |\n * | updatedAt                 | updated_at                     |\n */\nexport const AUTH_ACCOUNT_CONFIG = {\n  modelName: SystemObjectName.ACCOUNT, // 'sys_account'\n  fields: {\n    userId: 'user_id',\n    providerId: 'provider_id',\n    accountId: 'account_id',\n    accessToken: 'access_token',\n    refreshToken: 'refresh_token',\n    idToken: 'id_token',\n    accessTokenExpiresAt: 'access_token_expires_at',\n    refreshTokenExpiresAt: 'refresh_token_expires_at',\n    createdAt: 'created_at',\n    updatedAt: 'updated_at',\n  },\n} as const;\n\n// ---------------------------------------------------------------------------\n// Verification model\n// ---------------------------------------------------------------------------\n\n/**\n * better-auth `verification` model mapping.\n *\n * | camelCase (better-auth) | snake_case (ObjectStack) |\n * |:------------------------|:-------------------------|\n * | expiresAt               | expires_at               |\n * | createdAt               | created_at               |\n * | updatedAt               | updated_at               |\n */\nexport const AUTH_VERIFICATION_CONFIG = {\n  modelName: SystemObjectName.VERIFICATION, // 'sys_verification'\n  fields: {\n    expiresAt: 'expires_at',\n    createdAt: 'created_at',\n    updatedAt: 'updated_at',\n  },\n} as const;\n\n// ===========================================================================\n// Plugin Table Mappings\n// ===========================================================================\n//\n// better-auth plugins (organization, two-factor, etc.) introduce additional\n// tables with their own camelCase field names.  The mappings below are passed\n// to the plugin's `schema` option so that `createAdapterFactory` transforms\n// them to snake_case automatically, just like the core models above.\n// ===========================================================================\n\n// ---------------------------------------------------------------------------\n// Organization plugin – organization table\n// ---------------------------------------------------------------------------\n\n/**\n * better-auth Organization plugin `organization` model mapping.\n *\n * | camelCase (better-auth) | snake_case (ObjectStack) |\n * |:------------------------|:-------------------------|\n * | createdAt               | created_at               |\n * | updatedAt               | updated_at               |\n */\nexport const AUTH_ORGANIZATION_SCHEMA = {\n  modelName: SystemObjectName.ORGANIZATION, // 'sys_organization'\n  fields: {\n    createdAt: 'created_at',\n    updatedAt: 'updated_at',\n  },\n} as const;\n\n// ---------------------------------------------------------------------------\n// Organization plugin – member table\n// ---------------------------------------------------------------------------\n\n/**\n * better-auth Organization plugin `member` model mapping.\n *\n * | camelCase (better-auth) | snake_case (ObjectStack) |\n * |:------------------------|:-------------------------|\n * | organizationId          | organization_id          |\n * | userId                  | user_id                  |\n * | createdAt               | created_at               |\n */\nexport const AUTH_MEMBER_SCHEMA = {\n  modelName: SystemObjectName.MEMBER, // 'sys_member'\n  fields: {\n    organizationId: 'organization_id',\n    userId: 'user_id',\n    createdAt: 'created_at',\n  },\n} as const;\n\n// ---------------------------------------------------------------------------\n// Organization plugin – invitation table\n// ---------------------------------------------------------------------------\n\n/**\n * better-auth Organization plugin `invitation` model mapping.\n *\n * | camelCase (better-auth) | snake_case (ObjectStack) |\n * |:------------------------|:-------------------------|\n * | organizationId          | organization_id          |\n * | inviterId               | inviter_id               |\n * | expiresAt               | expires_at               |\n * | createdAt               | created_at               |\n * | teamId                  | team_id                  |\n */\nexport const AUTH_INVITATION_SCHEMA = {\n  modelName: SystemObjectName.INVITATION, // 'sys_invitation'\n  fields: {\n    organizationId: 'organization_id',\n    inviterId: 'inviter_id',\n    expiresAt: 'expires_at',\n    createdAt: 'created_at',\n    teamId: 'team_id',\n  },\n} as const;\n\n// ---------------------------------------------------------------------------\n// Organization plugin – session additional fields\n// ---------------------------------------------------------------------------\n\n/**\n * Organization plugin adds `activeOrganizationId` (and optionally\n * `activeTeamId`) to the session model. These field mappings are\n * injected via the organization plugin's `schema.session.fields`.\n */\nexport const AUTH_ORG_SESSION_FIELDS = {\n  activeOrganizationId: 'active_organization_id',\n  activeTeamId: 'active_team_id',\n} as const;\n\n// ---------------------------------------------------------------------------\n// Organization plugin – team table (optional, when teams enabled)\n// ---------------------------------------------------------------------------\n\n/**\n * better-auth Organization plugin `team` model mapping.\n *\n * | camelCase (better-auth) | snake_case (ObjectStack) |\n * |:------------------------|:-------------------------|\n * | organizationId          | organization_id          |\n * | createdAt               | created_at               |\n * | updatedAt               | updated_at               |\n */\nexport const AUTH_TEAM_SCHEMA = {\n  modelName: SystemObjectName.TEAM, // 'sys_team'\n  fields: {\n    organizationId: 'organization_id',\n    createdAt: 'created_at',\n    updatedAt: 'updated_at',\n  },\n} as const;\n\n// ---------------------------------------------------------------------------\n// Organization plugin – teamMember table (optional, when teams enabled)\n// ---------------------------------------------------------------------------\n\n/**\n * better-auth Organization plugin `teamMember` model mapping.\n *\n * | camelCase (better-auth) | snake_case (ObjectStack) |\n * |:------------------------|:-------------------------|\n * | teamId                  | team_id                  |\n * | userId                  | user_id                  |\n * | createdAt               | created_at               |\n */\nexport const AUTH_TEAM_MEMBER_SCHEMA = {\n  modelName: SystemObjectName.TEAM_MEMBER, // 'sys_team_member'\n  fields: {\n    teamId: 'team_id',\n    userId: 'user_id',\n    createdAt: 'created_at',\n  },\n} as const;\n\n// ---------------------------------------------------------------------------\n// Two-Factor plugin – twoFactor table\n// ---------------------------------------------------------------------------\n\n/**\n * better-auth Two-Factor plugin `twoFactor` model mapping.\n *\n * | camelCase (better-auth) | snake_case (ObjectStack) |\n * |:------------------------|:-------------------------|\n * | backupCodes             | backup_codes             |\n * | userId                  | user_id                  |\n */\nexport const AUTH_TWO_FACTOR_SCHEMA = {\n  modelName: SystemObjectName.TWO_FACTOR, // 'sys_two_factor'\n  fields: {\n    backupCodes: 'backup_codes',\n    userId: 'user_id',\n  },\n} as const;\n\n/**\n * Two-Factor plugin adds a `twoFactorEnabled` field to the user model.\n */\nexport const AUTH_TWO_FACTOR_USER_FIELDS = {\n  twoFactorEnabled: 'two_factor_enabled',\n} as const;\n\n// ---------------------------------------------------------------------------\n// Admin plugin – user/session field additions\n// ---------------------------------------------------------------------------\n\n/**\n * Admin plugin adds platform-level admin fields to the `user` model.\n *\n * | camelCase (better-auth) | snake_case (ObjectStack) |\n * |:------------------------|:-------------------------|\n * | banReason               | ban_reason               |\n * | banExpires              | ban_expires              |\n *\n * `role` and `banned` already have matching snake_case names and are\n * therefore omitted from this mapping (better-auth's database hooks\n * read them by the auto-derived column names).\n */\nexport const AUTH_ADMIN_USER_FIELDS = {\n  banReason: 'ban_reason',\n  banExpires: 'ban_expires',\n} as const;\n\n/**\n * Admin plugin adds an `impersonatedBy` field to the session model\n * recording the operator user id when an admin impersonates someone.\n */\nexport const AUTH_ADMIN_SESSION_FIELDS = {\n  impersonatedBy: 'impersonated_by',\n} as const;\n\n// ---------------------------------------------------------------------------\n// OAuth Provider plugin – oauthClient table\n// ---------------------------------------------------------------------------\n\n/**\n * `@better-auth/oauth-provider` plugin `oauthClient` model mapping.\n *\n * The model name (`oauthClient`) is mapped to the existing\n * `sys_oauth_application` table to preserve data continuity from the\n * deprecated `oidc-provider` plugin.\n *\n * | camelCase (better-auth)    | snake_case (ObjectStack)        |\n * |:---------------------------|:--------------------------------|\n * | clientId                   | client_id                       |\n * | clientSecret               | client_secret                   |\n * | skipConsent                | skip_consent                    |\n * | enableEndSession           | enable_end_session              |\n * | subjectType                | subject_type                    |\n * | userId                     | user_id                         |\n * | createdAt                  | created_at                      |\n * | updatedAt                  | updated_at                      |\n * | redirectUris               | redirect_uris                   |\n * | postLogoutRedirectUris     | post_logout_redirect_uris       |\n * | tokenEndpointAuthMethod    | token_endpoint_auth_method      |\n * | grantTypes                 | grant_types                     |\n * | responseTypes              | response_types                  |\n * | requirePKCE                | require_pkce                    |\n * | softwareId                 | software_id                     |\n * | softwareVersion            | software_version                |\n * | softwareStatement          | software_statement              |\n * | referenceId                | reference_id                    |\n */\nexport const AUTH_OAUTH_CLIENT_SCHEMA = {\n  modelName: SystemObjectName.OAUTH_APPLICATION, // 'sys_oauth_application'\n  fields: {\n    clientId: 'client_id',\n    clientSecret: 'client_secret',\n    skipConsent: 'skip_consent',\n    enableEndSession: 'enable_end_session',\n    subjectType: 'subject_type',\n    userId: 'user_id',\n    createdAt: 'created_at',\n    updatedAt: 'updated_at',\n    redirectUris: 'redirect_uris',\n    postLogoutRedirectUris: 'post_logout_redirect_uris',\n    tokenEndpointAuthMethod: 'token_endpoint_auth_method',\n    grantTypes: 'grant_types',\n    responseTypes: 'response_types',\n    requirePKCE: 'require_pkce',\n    softwareId: 'software_id',\n    softwareVersion: 'software_version',\n    softwareStatement: 'software_statement',\n    referenceId: 'reference_id',\n  },\n} as const;\n\n/**\n * @deprecated Use {@link AUTH_OAUTH_CLIENT_SCHEMA}. Retained as an alias for\n * historical imports; the new package renamed `oauthApplication` → `oauthClient`.\n */\nexport const AUTH_OAUTH_APPLICATION_SCHEMA = AUTH_OAUTH_CLIENT_SCHEMA;\n\n// ---------------------------------------------------------------------------\n// OAuth Provider plugin – oauthAccessToken table\n// ---------------------------------------------------------------------------\n\n/**\n * `@better-auth/oauth-provider` plugin `oauthAccessToken` model mapping.\n *\n * In the new package, access tokens and refresh tokens are stored in\n * **separate** models. `oauthAccessToken` no longer carries a refresh token;\n * see {@link AUTH_OAUTH_REFRESH_TOKEN_SCHEMA} for the companion model.\n *\n * | camelCase (better-auth) | snake_case (ObjectStack) |\n * |:------------------------|:-------------------------|\n * | clientId                | client_id                |\n * | sessionId               | session_id               |\n * | userId                  | user_id                  |\n * | referenceId             | reference_id             |\n * | refreshId               | refresh_id               |\n * | expiresAt               | expires_at               |\n * | createdAt               | created_at               |\n */\nexport const AUTH_OAUTH_ACCESS_TOKEN_SCHEMA = {\n  modelName: SystemObjectName.OAUTH_ACCESS_TOKEN, // 'sys_oauth_access_token'\n  fields: {\n    clientId: 'client_id',\n    sessionId: 'session_id',\n    userId: 'user_id',\n    referenceId: 'reference_id',\n    refreshId: 'refresh_id',\n    expiresAt: 'expires_at',\n    createdAt: 'created_at',\n  },\n} as const;\n\n// ---------------------------------------------------------------------------\n// OAuth Provider plugin – oauthRefreshToken table\n// ---------------------------------------------------------------------------\n\n/**\n * `@better-auth/oauth-provider` plugin `oauthRefreshToken` model mapping.\n *\n * Refresh tokens are linked to a session (via `session_id`) and to the\n * issuing client. Each access token rotation produces a new refresh-token\n * row.\n *\n * | camelCase (better-auth) | snake_case (ObjectStack) |\n * |:------------------------|:-------------------------|\n * | clientId                | client_id                |\n * | sessionId               | session_id               |\n * | userId                  | user_id                  |\n * | referenceId             | reference_id             |\n * | expiresAt               | expires_at               |\n * | createdAt               | created_at               |\n * | authTime                | auth_time                |\n */\nexport const AUTH_OAUTH_REFRESH_TOKEN_SCHEMA = {\n  modelName: SystemObjectName.OAUTH_REFRESH_TOKEN, // 'sys_oauth_refresh_token'\n  fields: {\n    clientId: 'client_id',\n    sessionId: 'session_id',\n    userId: 'user_id',\n    referenceId: 'reference_id',\n    expiresAt: 'expires_at',\n    createdAt: 'created_at',\n    authTime: 'auth_time',\n  },\n} as const;\n\n// ---------------------------------------------------------------------------\n// OAuth Provider plugin – oauthConsent table\n// ---------------------------------------------------------------------------\n\n/**\n * `@better-auth/oauth-provider` plugin `oauthConsent` model mapping.\n *\n * The new package dropped the boolean `consentGiven` flag — the presence of\n * a row implies consent was given for the listed scopes. A new\n * `referenceId` column was added for client-supplied correlation.\n *\n * | camelCase (better-auth) | snake_case (ObjectStack) |\n * |:------------------------|:-------------------------|\n * | clientId                | client_id                |\n * | userId                  | user_id                  |\n * | referenceId             | reference_id             |\n * | createdAt               | created_at               |\n * | updatedAt               | updated_at               |\n */\nexport const AUTH_OAUTH_CONSENT_SCHEMA = {\n  modelName: SystemObjectName.OAUTH_CONSENT, // 'sys_oauth_consent'\n  fields: {\n    clientId: 'client_id',\n    userId: 'user_id',\n    referenceId: 'reference_id',\n    createdAt: 'created_at',\n    updatedAt: 'updated_at',\n  },\n} as const;\n\n// ---------------------------------------------------------------------------\n// Device Authorization plugin – deviceCode table\n// ---------------------------------------------------------------------------\n\n/**\n * better-auth `device-authorization` plugin `deviceCode` model mapping.\n *\n * Implements RFC 8628 (OAuth 2.0 Device Authorization Grant). Stores\n * pending device-flow requests issued via `POST /device/code`, polled at\n * `POST /device/token`, and approved/denied via `POST /device/{approve,deny}`.\n *\n * | camelCase (better-auth) | snake_case (ObjectStack) |\n * |:------------------------|:-------------------------|\n * | deviceCode              | device_code              |\n * | userCode                | user_code                |\n * | userId                  | user_id                  |\n * | expiresAt               | expires_at               |\n * | lastPolledAt            | last_polled_at           |\n * | pollingInterval         | polling_interval         |\n * | clientId                | client_id                |\n */\nexport const AUTH_DEVICE_CODE_SCHEMA = {\n  modelName: SystemObjectName.DEVICE_CODE, // 'sys_device_code'\n  fields: {\n    deviceCode: 'device_code',\n    userCode: 'user_code',\n    userId: 'user_id',\n    expiresAt: 'expires_at',\n    lastPolledAt: 'last_polled_at',\n    pollingInterval: 'polling_interval',\n    clientId: 'client_id',\n  },\n} as const;\n\n/**\n * Builds the `schema` option for better-auth's `twoFactor()` plugin.\n *\n * @returns An object suitable for `twoFactor({ schema: … })`\n */\nexport function buildTwoFactorPluginSchema() {\n  return {\n    twoFactor: AUTH_TWO_FACTOR_SCHEMA,\n    user: {\n      fields: AUTH_TWO_FACTOR_USER_FIELDS,\n    },\n  };\n}\n\n/**\n * Builds the `schema` option for better-auth's `admin()` plugin.\n *\n * The admin plugin extends the user model with `role`/`banned`/`banReason`/\n * `banExpires` and the session model with `impersonatedBy`. Only the\n * snake_case-differing fields are mapped explicitly.\n */\nexport function buildAdminPluginSchema() {\n  return {\n    user: {\n      fields: AUTH_ADMIN_USER_FIELDS,\n    },\n    session: {\n      fields: AUTH_ADMIN_SESSION_FIELDS,\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Helper: build organization plugin schema option\n// ---------------------------------------------------------------------------\n\n/**\n * Builds the `schema` option for better-auth's `organization()` plugin.\n *\n * The organization plugin accepts a `schema` sub-option that allows\n * customising model names and field names for each table it manages.\n * This helper assembles the correct snake_case mappings from the\n * individual `AUTH_*_SCHEMA` constants above.\n *\n * @returns An object suitable for `organization({ schema: … })`\n */\nexport function buildOrganizationPluginSchema() {\n  return {\n    organization: AUTH_ORGANIZATION_SCHEMA,\n    member: AUTH_MEMBER_SCHEMA,\n    invitation: AUTH_INVITATION_SCHEMA,\n    team: AUTH_TEAM_SCHEMA,\n    teamMember: AUTH_TEAM_MEMBER_SCHEMA,\n    session: {\n      fields: AUTH_ORG_SESSION_FIELDS,\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// JWT plugin – jwks table\n// ---------------------------------------------------------------------------\n\n/**\n * better-auth `jwt` plugin `jwks` model mapping.\n *\n * The JWT plugin maintains a small set of rotating asymmetric key pairs\n * used to sign and verify issued JWTs (id_tokens for OIDC, JWT access\n * tokens). It is required by the `@better-auth/oauth-provider` plugin.\n *\n * | camelCase (better-auth) | snake_case (ObjectStack) |\n * |:------------------------|:-------------------------|\n * | publicKey               | public_key               |\n * | privateKey              | private_key              |\n * | createdAt               | created_at               |\n * | expiresAt               | expires_at               |\n */\nexport const AUTH_JWKS_SCHEMA = {\n  modelName: SystemObjectName.JWKS, // 'sys_jwks'\n  fields: {\n    publicKey: 'public_key',\n    privateKey: 'private_key',\n    createdAt: 'created_at',\n    expiresAt: 'expires_at',\n  },\n} as const;\n\n/**\n * Builds the `schema` option for better-auth's `jwt()` plugin.\n *\n * @returns An object suitable for `jwt({ schema: … })`\n */\nexport function buildJwtPluginSchema() {\n  return {\n    jwks: AUTH_JWKS_SCHEMA,\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Helper: build OAuth provider plugin schema option\n// ---------------------------------------------------------------------------\n\n/**\n * Builds the `schema` option for `@better-auth/oauth-provider`'s\n * `oauthProvider()` plugin.\n *\n * The plugin manages four tables: `oauthClient` (registered client apps —\n * mapped to ObjectStack's `sys_oauth_application` table for backwards\n * compatibility), `oauthAccessToken` (issued access tokens),\n * `oauthRefreshToken` (issued refresh tokens, linked to a session), and\n * `oauthConsent` (recorded user consents).\n *\n * @returns An object suitable for `oauthProvider({ schema: … })`\n */\nexport function buildOauthProviderPluginSchema() {\n  return {\n    oauthClient: AUTH_OAUTH_CLIENT_SCHEMA,\n    oauthAccessToken: AUTH_OAUTH_ACCESS_TOKEN_SCHEMA,\n    oauthRefreshToken: AUTH_OAUTH_REFRESH_TOKEN_SCHEMA,\n    oauthConsent: AUTH_OAUTH_CONSENT_SCHEMA,\n  };\n}\n\n/**\n * @deprecated Use {@link buildOauthProviderPluginSchema}. Retained as an\n * alias for callers that imported the previous name during the migration\n * from the deprecated `better-auth/plugins/oidc-provider` plugin.\n */\nexport const buildOidcProviderPluginSchema = buildOauthProviderPluginSchema;\n\n// ---------------------------------------------------------------------------\n// Helper: build device-authorization plugin schema option\n// ---------------------------------------------------------------------------\n\n/**\n * Builds the `schema` option for better-auth's `deviceAuthorization()` plugin.\n *\n * The plugin manages a single `deviceCode` table tracking pending RFC 8628\n * device-flow requests. This helper returns the snake_case mappings that\n * point the plugin at ObjectStack's `sys_device_code` object.\n *\n * @returns An object suitable for `deviceAuthorization({ schema: … })`\n */\nexport function buildDeviceAuthorizationPluginSchema() {\n  return {\n    deviceCode: AUTH_DEVICE_CODE_SCHEMA,\n  };\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Shared `set-initial-password` handler.\n *\n * better-auth ships a `setPassword` operation that does EXACTLY what we want\n * (require a session, enforce min/max length, link a `credential` account if\n * none exists, refuse if one already does). But it is registered with\n * `createAuthEndpoint({ ... })` — note: NO leading path string — which means\n * better-auth deliberately exposes it as a **server-only** `auth.api.setPassword`\n * call and gives it no HTTP route. Setting a password without proving the old\n * one is privilege-sensitive, so it must not be reachable over the wire by\n * default.\n *\n * To let an SSO-onboarded user set an *initial* local password from the\n * browser, we wrap that server API in our own authenticated HTTP route. This\n * helper is the single source of truth for that route body so the two mount\n * points — the full `AuthPlugin` (host kernel) and the cloud `AuthProxyPlugin`\n * (per-environment runtime) — stay in lockstep instead of hand-copying ~50\n * lines of hash/createAccount logic (the original drift that let #1544 ship a\n * route on one path but not the other).\n */\n\n/** Minimal shape of the better-auth server API we depend on. */\nexport interface SetPasswordCapableApi {\n  setPassword(opts: { body: { newPassword: string }; headers: Headers }): Promise<unknown>;\n}\n\nexport interface SetInitialPasswordResult {\n  /** HTTP status to return to the caller. */\n  status: number;\n  /** JSON body; mirrors the `{ success, error: { code, message } }` envelope the client parses. */\n  body: { success: boolean; error?: { code: string; message: string } };\n}\n\n/**\n * Run set-initial-password against the environment's better-auth API.\n *\n * @param authApi   the better-auth server api (`auth.api`, via `AuthManager.getApi()`)\n * @param request   the raw Web `Request` — its `headers` carry the session\n *                  cookie that better-auth's session middleware reads, and its\n *                  body carries `{ newPassword }`.\n */\nexport async function runSetInitialPassword(\n  authApi: SetPasswordCapableApi,\n  request: Request,\n): Promise<SetInitialPasswordResult> {\n  let parsed: unknown;\n  try {\n    parsed = await request.json();\n  } catch {\n    parsed = {};\n  }\n  const newPassword: unknown = (parsed as { newPassword?: unknown } | null)?.newPassword;\n  if (typeof newPassword !== 'string' || newPassword.length === 0) {\n    return {\n      status: 400,\n      body: { success: false, error: { code: 'invalid_request', message: 'newPassword is required' } },\n    };\n  }\n\n  try {\n    // better-auth's session middleware reads the session from `headers`;\n    // length checks + the \"already set\" guard happen inside setPassword.\n    await authApi.setPassword({ body: { newPassword }, headers: request.headers });\n    return { status: 200, body: { success: true } };\n  } catch (error) {\n    return mapSetPasswordError(error);\n  }\n}\n\n/**\n * Map a better-auth `APIError` (better-call: `{ statusCode, status, body: { code, message } }`)\n * onto our response envelope. The client only surfaces `error.message`, but we\n * preserve the status code and code string for parity with the change/reset\n * flows. `PASSWORD_ALREADY_SET` is normalised to 409 so callers can tell\n * \"already has a password → use change-password\" apart from validation errors.\n */\nfunction mapSetPasswordError(error: unknown): SetInitialPasswordResult {\n  const e = error as {\n    statusCode?: number;\n    status?: number | string;\n    body?: { code?: string; message?: string };\n    message?: string;\n  } | null;\n\n  const code = e?.body?.code ?? 'internal';\n  const message = e?.body?.message ?? e?.message ?? 'set-initial-password failed';\n  const rawStatus =\n    typeof e?.statusCode === 'number' ? e.statusCode : typeof e?.status === 'number' ? e.status : 500;\n  const status = code === 'PASSWORD_ALREADY_SET' ? 409 : rawStatus;\n\n  return { status, body: { success: false, error: { code, message } } };\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Canonical plugin-auth manifest source.\n *\n * Both `objectstack.config.ts` (compile-time) and `auth-plugin.ts`\n * (runtime `manifest.register`) import from this file so the two\n * registration paths cannot drift (D7).\n */\n\nimport {\n  SysAccount,\n  SysApiKey,\n  SysDeviceCode,\n  SysInvitation,\n  SysMember,\n  SysJwks,\n  SysOauthAccessToken,\n  SysOauthApplication,\n  SysOauthConsent,\n  SysOauthRefreshToken,\n  SysOrganization,\n  SysSession,\n  SysTeam,\n  SysTeamMember,\n  SysTwoFactor,\n  SysUser,\n  SysUserPreference,\n  SysVerification,\n} from '@objectstack/platform-objects/identity';\n\nexport const AUTH_PLUGIN_ID = 'com.objectstack.plugin-auth';\nexport const AUTH_PLUGIN_VERSION = '3.0.1';\n\n/** Identity objects owned by plugin-auth. */\nexport const authIdentityObjects: any[] = [\n  SysUser,\n  SysSession,\n  SysAccount,\n  SysVerification,\n  SysOrganization,\n  SysMember,\n  SysInvitation,\n  SysTeam,\n  SysTeamMember,\n  SysApiKey,\n  SysTwoFactor,\n  SysUserPreference,\n  SysOauthApplication,\n  SysOauthAccessToken,\n  SysOauthRefreshToken,\n  SysOauthConsent,\n  SysJwks,\n  SysDeviceCode,\n];\n\n/** Manifest header shared by compile-time config and runtime registration. */\nexport const authPluginManifestHeader = {\n  id: AUTH_PLUGIN_ID,\n  namespace: 'sys',\n  version: AUTH_PLUGIN_VERSION,\n  type: 'plugin' as const,\n  scope: 'system' as const,\n  defaultDatasource: 'cloud',\n  name: 'Authentication & Identity Plugin',\n  description: 'Core authentication objects for ObjectStack (User, Session, Account, Verification)',\n};\n"],"mappings":"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","names":["SystemObjectName","SystemObjectName","organization","dataEngine","roles","SystemObjectName"]}