From c5e3948c756c526bca4f035c4154288b957f26d4 Mon Sep 17 00:00:00 2001 From: "anthropic-code-agent[bot]" <242468646+Claude@users.noreply.github.com> Date: Tue, 14 Apr 2026 13:18:43 +0000 Subject: [PATCH] fix: resolve CI test failures in spec and objectql packages - Fix spec test: update test expectation to account for defaultDatasource being added during validation - Fix objectql SchemaRegistry mock: add missing getObjectOwner method to test mock - Fix objectql engine: use object FQN when calling getObjectOwner to ensure correct ownership lookup - Fix objectql datasource-mapping tests: rename SchemaRegistry.clear() to reset() and engine.create() to insert() Agent-Logs-Url: https://github.com/objectstack-ai/framework/sessions/ecd04cb1-085f-40cc-be05-b236c08a82eb Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- .../docs/references/api/auth-endpoints.mdx | 57 ++++++++++++++++++- content/docs/references/kernel/manifest.mdx | 1 + .../objectql/src/datasource-mapping.test.ts | 12 ++-- packages/objectql/src/engine.test.ts | 16 +++++- packages/objectql/src/engine.ts | 4 +- packages/spec/src/stack.test.ts | 6 +- 6 files changed, 85 insertions(+), 11 deletions(-) diff --git a/content/docs/references/api/auth-endpoints.mdx b/content/docs/references/api/auth-endpoints.mdx index ee3a1acb7..a78abc05c 100644 --- a/content/docs/references/api/auth-endpoints.mdx +++ b/content/docs/references/api/auth-endpoints.mdx @@ -24,8 +24,8 @@ the canonical API contract. ## TypeScript Usage ```typescript -import { AuthEndpoint } from '@objectstack/spec/api'; -import type { AuthEndpoint } from '@objectstack/spec/api'; +import { AuthEndpoint, AuthFeaturesConfig, AuthProviderInfo, EmailPasswordConfigPublic, GetAuthConfigResponse } from '@objectstack/spec/api'; +import type { AuthEndpoint, AuthFeaturesConfig, AuthProviderInfo, EmailPasswordConfigPublic, GetAuthConfigResponse } from '@objectstack/spec/api'; // Validate data const result = AuthEndpoint.parse(data); @@ -51,3 +51,56 @@ const result = AuthEndpoint.parse(data); --- +## AuthFeaturesConfig + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **twoFactor** | `boolean` | ✅ | Two-factor authentication enabled | +| **passkeys** | `boolean` | ✅ | Passkey/WebAuthn support enabled | +| **magicLink** | `boolean` | ✅ | Magic link login enabled | +| **organization** | `boolean` | ✅ | Multi-tenant organization support enabled | + + +--- + +## AuthProviderInfo + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **id** | `string` | ✅ | Provider ID (e.g., google, github, microsoft) | +| **name** | `string` | ✅ | Display name (e.g., Google, GitHub) | +| **enabled** | `boolean` | ✅ | Whether this provider is enabled | + + +--- + +## EmailPasswordConfigPublic + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **enabled** | `boolean` | ✅ | Whether email/password auth is enabled | +| **disableSignUp** | `boolean` | optional | Whether new user registration is disabled | +| **requireEmailVerification** | `boolean` | optional | Whether email verification is required | + + +--- + +## GetAuthConfigResponse + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **emailPassword** | `Object` | ✅ | Email/password authentication config | +| **socialProviders** | `Object[]` | ✅ | Available social/OAuth providers | +| **features** | `Object` | ✅ | Enabled authentication features | + + +--- + diff --git a/content/docs/references/kernel/manifest.mdx b/content/docs/references/kernel/manifest.mdx index 7d40ec963..2a32c7329 100644 --- a/content/docs/references/kernel/manifest.mdx +++ b/content/docs/references/kernel/manifest.mdx @@ -61,6 +61,7 @@ const result = Manifest.parse(data); | :--- | :--- | :--- | :--- | | **id** | `string` | ✅ | Unique package identifier (reverse domain style) | | **namespace** | `string` | optional | Short namespace identifier for metadata scoping (e.g. "crm", "todo") | +| **defaultDatasource** | `string` | ✅ | Default datasource for all objects in this package | | **version** | `string` | ✅ | Package version (semantic versioning) | | **type** | `Enum<'plugin' \| 'ui' \| 'driver' \| 'server' \| 'app' \| 'theme' \| 'agent' \| 'objectql' \| 'module' \| 'gateway' \| 'adapter'>` | ✅ | Type of package | | **name** | `string` | ✅ | Human-readable package name | diff --git a/packages/objectql/src/datasource-mapping.test.ts b/packages/objectql/src/datasource-mapping.test.ts index 9d0d8c078..a20bcdd35 100644 --- a/packages/objectql/src/datasource-mapping.test.ts +++ b/packages/objectql/src/datasource-mapping.test.ts @@ -35,7 +35,7 @@ describe('DatasourceMapping', () => { beforeEach(() => { engine = new ObjectQL(); - SchemaRegistry.clear(); + SchemaRegistry.reset(); }); it('should route objects by namespace', async () => { @@ -62,7 +62,7 @@ describe('DatasourceMapping', () => { ); // Test that it uses memory driver - const result = await engine.create('account', { name: 'Test Account' }); + const result = await engine.insert('account', { name: 'Test Account' }); expect(result).toBeDefined(); expect(result.name).toBe('Test Account'); }); @@ -91,7 +91,7 @@ describe('DatasourceMapping', () => { 'own' ); - const result = await engine.create('sys_user', { username: 'admin' }); + const result = await engine.insert('sys_user', { username: 'admin' }); expect(result).toBeDefined(); }); @@ -119,7 +119,7 @@ describe('DatasourceMapping', () => { ); // Should use turso (priority 50) not memory (priority 100) - const result = await engine.create('account', { name: 'Test' }); + const result = await engine.insert('account', { name: 'Test' }); expect(result).toBeDefined(); }); @@ -147,7 +147,7 @@ describe('DatasourceMapping', () => { ); // Should use memory (default) - const result = await engine.create('task', { title: 'Do something' }); + const result = await engine.insert('task', { title: 'Do something' }); expect(result).toBeDefined(); }); @@ -175,7 +175,7 @@ describe('DatasourceMapping', () => { ); // Should use turso (explicit) not memory (mapping) - const result = await engine.create('account', { name: 'Test' }); + const result = await engine.insert('account', { name: 'Test' }); expect(result).toBeDefined(); }); }); diff --git a/packages/objectql/src/engine.test.ts b/packages/objectql/src/engine.test.ts index 1b92eda7e..e11220f5e 100644 --- a/packages/objectql/src/engine.test.ts +++ b/packages/objectql/src/engine.test.ts @@ -6,6 +6,7 @@ import type { IDataDriver } from '@objectstack/spec/contracts'; // Mock the SchemaRegistry to avoid side effects between tests vi.mock('./registry', () => { const mockObjects = new Map(); + const mockContributors = new Map(); return { SchemaRegistry: { getObject: vi.fn((name) => mockObjects.get(name)), @@ -13,8 +14,18 @@ vi.mock('./registry', () => { registerObject: vi.fn((obj, packageId, namespace, ownership, priority) => { const fqn = namespace ? `${namespace}__${obj.name}` : obj.name; mockObjects.set(fqn, { ...obj, name: fqn }); + // Also track contributors for getObjectOwner + if (!mockContributors.has(fqn)) { + mockContributors.set(fqn, []); + } + const contributors = mockContributors.get(fqn); + contributors.push({ packageId, namespace, ownership, priority, definition: obj }); return fqn; }), + getObjectOwner: vi.fn((fqn) => { + const contributors = mockContributors.get(fqn); + return contributors?.find(c => c.ownership === 'own'); + }), registerNamespace: vi.fn(), registerKind: vi.fn(), registerItem: vi.fn(), @@ -25,7 +36,10 @@ vi.mock('./registry', () => { enabled: true, installedAt: new Date().toISOString(), })), - reset: vi.fn(() => mockObjects.clear()), + reset: vi.fn(() => { + mockObjects.clear(); + mockContributors.clear(); + }), metadata: { get: vi.fn(() => mockObjects) // Expose for verification if needed } diff --git a/packages/objectql/src/engine.ts b/packages/objectql/src/engine.ts index cd9c69fe4..f693d610c 100644 --- a/packages/objectql/src/engine.ts +++ b/packages/objectql/src/engine.ts @@ -618,7 +618,9 @@ export class ObjectQL implements IDataEngine { } // 3. Check package's defaultDatasource - const owner = SchemaRegistry.getObjectOwner(objectName); + // Use the object's FQN name (from getObject) for ownership lookup + const fqn = object?.name || objectName; + const owner = SchemaRegistry.getObjectOwner(fqn); if (owner?.packageId) { const manifest = this.manifests.get(owner.packageId); if (manifest?.defaultDatasource && manifest.defaultDatasource !== 'default') { diff --git a/packages/spec/src/stack.test.ts b/packages/spec/src/stack.test.ts index 2d238db61..3b4766cb2 100644 --- a/packages/spec/src/stack.test.ts +++ b/packages/spec/src/stack.test.ts @@ -430,8 +430,12 @@ describe('defineStack', () => { const result = defineStack(config); // Default is now strict=true, so result is validated and is a different object reference expect(result).not.toBe(config); // Validation creates new object - expect(result).toEqual(config); // But content is the same + // Validation may add defaults like defaultDatasource expect(result.manifest).toBeDefined(); + expect(result.manifest.id).toBe(baseManifest.id); + expect(result.manifest.name).toBe(baseManifest.name); + expect(result.manifest.version).toBe(baseManifest.version); + expect(result.manifest.type).toBe(baseManifest.type); }); it('should return config as-is when strict is false', () => {