From 3a60f3c58abe2c2cdd20abfc6aa94d71cbd49b23 Mon Sep 17 00:00:00 2001 From: "anthropic-code-agent[bot]" <242468646+Claude@users.noreply.github.com> Date: Tue, 14 Apr 2026 06:18:02 +0000 Subject: [PATCH 1/3] Initial plan From f6fe8a0c1896c3f23cc8623b84e9f22dd483f8b0 Mon Sep 17 00:00:00 2001 From: "anthropic-code-agent[bot]" <242468646+Claude@users.noreply.github.com> Date: Tue, 14 Apr 2026 06:23:53 +0000 Subject: [PATCH 2/3] Add AuthPlugin to demo/mock environment to restore Setup App menu - Import and register AuthPlugin in createKernel.ts before SetupPlugin - Provide mock auth config for demo environment (secret + baseUrl) - Ensure correct plugin order to avoid 'sys' namespace collision - Remove duplicate setupAppConfig registration from browser.ts, server.ts, and test files - Replace setupAppConfig with AuthPlugin + SetupPlugin in console config - All i18n tests pass successfully Agent-Logs-Url: https://github.com/objectstack-ai/objectui/sessions/ad7046f8-9652-4470-b9fa-c1dbdb78ab9a Co-authored-by: xuyushun441-sys <255036401+xuyushun441-sys@users.noreply.github.com> --- apps/console/objectstack.config.ts | 20 ++++++++++++++++--- .../src/__tests__/i18n-translations.test.ts | 5 +++-- apps/console/src/mocks/browser.ts | 5 +++-- apps/console/src/mocks/createKernel.ts | 10 ++++++++++ apps/console/src/mocks/server.ts | 5 +++-- 5 files changed, 36 insertions(+), 9 deletions(-) diff --git a/apps/console/objectstack.config.ts b/apps/console/objectstack.config.ts index fcd3c82a7..48b476e79 100644 --- a/apps/console/objectstack.config.ts +++ b/apps/console/objectstack.config.ts @@ -4,7 +4,7 @@ const require = createRequire(import.meta.url); // @ts-ignore globalThis.require = require; -import { sharedConfig, appConfigs, setupAppConfig } from './objectstack.shared'; +import { sharedConfig, appConfigs } from './objectstack.shared'; // @ts-ignore import * as MSWPluginPkg from '@objectstack/plugin-msw'; @@ -13,6 +13,10 @@ import * as ObjectQLPluginPkg from '@objectstack/objectql'; // @ts-ignore import * as HonoServerPluginPkg from '@objectstack/plugin-hono-server'; // @ts-ignore +import * as AuthPluginPkg from '@objectstack/plugin-auth'; +// @ts-ignore +import * as SetupPluginPkg from '@objectstack/plugin-setup'; +// @ts-ignore import * as DriverMemoryPkg from '@objectstack/driver-memory'; // @ts-ignore import * as RuntimePkg from '@objectstack/runtime'; @@ -25,6 +29,8 @@ const InMemoryDriver = DriverMemoryPkg.InMemoryDriver || (DriverMemoryPkg as any const DriverPlugin = RuntimePkg.DriverPlugin || (RuntimePkg as any).default?.DriverPlugin || (RuntimePkg as any).default; const AppPlugin = RuntimePkg.AppPlugin || (RuntimePkg as any).default?.AppPlugin || (RuntimePkg as any).default; const HonoServerPlugin = HonoServerPluginPkg.HonoServerPlugin || (HonoServerPluginPkg as any).default?.HonoServerPlugin || (HonoServerPluginPkg as any).default; +const AuthPlugin = AuthPluginPkg.AuthPlugin || (AuthPluginPkg as any).default?.AuthPlugin || (AuthPluginPkg as any).default; +const SetupPlugin = SetupPluginPkg.SetupPlugin || (SetupPluginPkg as any).default?.SetupPlugin || (SetupPluginPkg as any).default; const createMemoryI18n = CorePkg.createMemoryI18n || (CorePkg as any).default?.createMemoryI18n; import { ConsolePlugin } from './plugin'; @@ -70,6 +76,10 @@ class MemoryI18nPlugin { * * MemoryI18nPlugin MUST come before AppPlugin so that the i18n service * exists when AppPlugin.start() → loadTranslations() runs. + * + * AuthPlugin before SetupPlugin: both use namespace 'sys', and the + * ObjectQL registry requires the package that owns objects (AuthPlugin → + * com.objectstack.system) to register first. */ const plugins: any[] = [ new MemoryI18nPlugin(), @@ -77,8 +87,12 @@ const plugins: any[] = [ new DriverPlugin(new InMemoryDriver(), 'memory'), // Each example stack loaded as an independent AppPlugin ...appConfigs.map((config: any) => new AppPlugin(config)), - // Setup App registered via AppPlugin so ObjectQLPlugin discovers it - new AppPlugin(setupAppConfig), + // Auth & Setup plugins (replaces setupAppConfig) + new AuthPlugin({ + secret: process.env.AUTH_SECRET || 'objectui-server-secret', + baseUrl: process.env.BASE_URL || 'http://localhost:3000', + }), + new SetupPlugin(), new HonoServerPlugin({ port: 3000 }), new ConsolePlugin(), ]; diff --git a/apps/console/src/__tests__/i18n-translations.test.ts b/apps/console/src/__tests__/i18n-translations.test.ts index ab8ca8704..e0e91ae75 100644 --- a/apps/console/src/__tests__/i18n-translations.test.ts +++ b/apps/console/src/__tests__/i18n-translations.test.ts @@ -13,7 +13,7 @@ import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { setupServer } from 'msw/node'; import { createKernel, type KernelResult } from '../mocks/createKernel'; import { createAuthHandlers } from '../mocks/authHandlers'; -import { appConfigs, setupAppConfig } from '../../objectstack.shared'; +import { appConfigs } from '../../objectstack.shared'; import { crmLocales } from '@object-ui/example-crm'; // Expected values from the CRM i18n bundles — avoid hard-coding in assertions @@ -26,7 +26,8 @@ describe('i18n translations pipeline', () => { beforeAll(async () => { result = await createKernel({ - appConfigs: [...appConfigs, setupAppConfig], + // SetupPlugin is registered in createKernel, so no need for setupAppConfig here + appConfigs: [...appConfigs], persistence: false, mswOptions: { enableBrowser: false, diff --git a/apps/console/src/mocks/browser.ts b/apps/console/src/mocks/browser.ts index 44fb9f69e..31786fd3e 100644 --- a/apps/console/src/mocks/browser.ts +++ b/apps/console/src/mocks/browser.ts @@ -16,7 +16,7 @@ import { setupWorker } from 'msw/browser'; import { ObjectKernel } from '@objectstack/runtime'; import { InMemoryDriver } from '@objectstack/driver-memory'; import type { MSWPlugin } from '@objectstack/plugin-msw'; -import { appConfigs, setupAppConfig, customReportsConfig } from '../../objectstack.shared'; +import { appConfigs, customReportsConfig } from '../../objectstack.shared'; import { createKernel } from './createKernel'; import { createAuthHandlers } from './authHandlers'; @@ -43,7 +43,8 @@ export async function startMockServer() { if (import.meta.env.DEV) console.log('[MSW] Starting ObjectStack Runtime (Browser Mode)...'); const result = await createKernel({ - appConfigs: [...appConfigs, setupAppConfig, customReportsConfig], + // SetupPlugin is registered in createKernel, so no need for setupAppConfig here + appConfigs: [...appConfigs, customReportsConfig], mswOptions: { enableBrowser: false, baseUrl: '/api/v1', diff --git a/apps/console/src/mocks/createKernel.ts b/apps/console/src/mocks/createKernel.ts index 3a8062d0e..09e0804c4 100644 --- a/apps/console/src/mocks/createKernel.ts +++ b/apps/console/src/mocks/createKernel.ts @@ -17,6 +17,7 @@ import { ObjectQLPlugin } from '@objectstack/objectql'; import { InMemoryDriver, MemoryAnalyticsService } from '@objectstack/driver-memory'; import { MSWPlugin } from '@objectstack/plugin-msw'; import type { MSWPluginOptions } from '@objectstack/plugin-msw'; +import { AuthPlugin } from '@objectstack/plugin-auth'; import { SetupPlugin } from '@objectstack/plugin-setup'; import type { Cube } from '@objectstack/spec/data'; import { http, HttpResponse } from 'msw'; @@ -317,6 +318,15 @@ export async function createKernel(options: KernelOptions): Promise Date: Tue, 14 Apr 2026 06:29:55 +0000 Subject: [PATCH 3/3] Fix plugin order: SetupPlugin must load before AuthPlugin AuthPlugin's init() method tries to contribute menu items to the setupNav service, which is only registered after SetupPlugin's init() runs. The previous order had AuthPlugin loading first, causing it to silently fail when trying to contribute navigation items. Correct order: 1. SetupPlugin (registers setupNav service in init phase) 2. AuthPlugin (contributes to setupNav in init phase) This ensures the Setup App menu is populated with auth-related items: - Users - Organizations - Teams - API Keys - Sessions Agent-Logs-Url: https://github.com/objectstack-ai/objectui/sessions/07edc3ef-a3a9-4926-bd1a-db0c2513b862 Co-authored-by: xuyushun441-sys <255036401+xuyushun441-sys@users.noreply.github.com> --- apps/console/objectstack.config.ts | 10 +++++----- apps/console/src/mocks/createKernel.ts | 10 ++++------ objectstack.config.ts | 10 ++++------ 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/apps/console/objectstack.config.ts b/apps/console/objectstack.config.ts index 48b476e79..ce779e17c 100644 --- a/apps/console/objectstack.config.ts +++ b/apps/console/objectstack.config.ts @@ -77,9 +77,8 @@ class MemoryI18nPlugin { * MemoryI18nPlugin MUST come before AppPlugin so that the i18n service * exists when AppPlugin.start() → loadTranslations() runs. * - * AuthPlugin before SetupPlugin: both use namespace 'sys', and the - * ObjectQL registry requires the package that owns objects (AuthPlugin → - * com.objectstack.system) to register first. + * SetupPlugin MUST load before AuthPlugin so that the setupNav service + * is registered and available when AuthPlugin.init() tries to contribute menu items. */ const plugins: any[] = [ new MemoryI18nPlugin(), @@ -87,12 +86,13 @@ const plugins: any[] = [ new DriverPlugin(new InMemoryDriver(), 'memory'), // Each example stack loaded as an independent AppPlugin ...appConfigs.map((config: any) => new AppPlugin(config)), - // Auth & Setup plugins (replaces setupAppConfig) + // SetupPlugin must come before AuthPlugin (setupNav service dependency) + new SetupPlugin(), + // AuthPlugin contributes to setupNav during init, so it must come AFTER SetupPlugin new AuthPlugin({ secret: process.env.AUTH_SECRET || 'objectui-server-secret', baseUrl: process.env.BASE_URL || 'http://localhost:3000', }), - new SetupPlugin(), new HonoServerPlugin({ port: 3000 }), new ConsolePlugin(), ]; diff --git a/apps/console/src/mocks/createKernel.ts b/apps/console/src/mocks/createKernel.ts index 09e0804c4..1fae23303 100644 --- a/apps/console/src/mocks/createKernel.ts +++ b/apps/console/src/mocks/createKernel.ts @@ -318,16 +318,14 @@ export async function createKernel(options: KernelOptions): Promise