Skip to content

Commit ce04662

Browse files
fix(client): align test with removed ai.chat method to fix CI
The ai.chat() method was intentionally removed from ObjectStackClient (consumers should use Vercel AI SDK useChat() directly), but the test still called it causing TypeError. Replaced the test with an assertion that the method is absent from the API surface. Agent-Logs-Url: https://github.com/objectstack-ai/spec/sessions/3bdafba4-a143-4f0e-97a6-7cf1e060da27 Co-authored-by: xuyushun441-sys <255036401+xuyushun441-sys@users.noreply.github.com>
1 parent e0587b3 commit ce04662

8 files changed

Lines changed: 174 additions & 22 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Fixed
11+
- **Client test aligned with removed `ai.chat` method** — Updated
12+
`@objectstack/client` test suite to match the current API surface where
13+
`ai.chat()` was removed in favour of the Vercel AI SDK `useChat()` hook.
14+
The obsolete test that called `client.ai.chat()` now asserts the method is
15+
absent, fixing the CI `@objectstack/client#test` failure.
16+
1017
### Added
1118
- **Discovery Schema — `ServiceStatus` enum & `handlerReady` field** — Added `'registered'`
1219
status to `ServiceInfoSchema` to distinguish routes that are declared in the dispatcher
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
title: Core Services
3+
description: Core Services protocol schemas
4+
---
5+
6+
{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs go in content/docs/guides/. */}
7+
8+
<Callout type="info">
9+
**Source:** `packages/spec/src/api/core-services.zod.ts`
10+
</Callout>
11+
12+
## TypeScript Usage
13+
14+
```typescript
15+
import { ServiceStatus } from '@objectstack/spec/api';
16+
import type { ServiceStatus } from '@objectstack/spec/api';
17+
18+
// Validate data
19+
const result = ServiceStatus.parse(data);
20+
```
21+
22+
---
23+
24+
## ServiceStatus
25+
26+
available = fully operational, registered = route declared but handler unverified, unavailable = not installed, degraded = partial, stub = placeholder that returns 501
27+
28+
### Allowed Values
29+
30+
* `available`
31+
* `registered`
32+
* `unavailable`
33+
* `degraded`
34+
* `stub`
35+
36+
37+
---
38+

content/docs/references/api/discovery.mdx

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,21 @@ description: Discovery protocol schemas
55

66
{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs go in content/docs/guides/. */}
77

8-
Service Status in Discovery Response
8+
Service Status Enum
99

10-
Reports per-service availability so clients can adapt their UI accordingly.
10+
Describes the operational state of a service in the discovery response.
11+
12+
- `available` – Fully operational: service is registered AND HTTP handler is verified.
13+
14+
- `registered` – Route is declared in the dispatcher table but the HTTP handler has
15+
16+
not been verified (may 501 at runtime).
17+
18+
- `unavailable` – Service is not installed / not registered in the kernel.
19+
20+
- `degraded` – Partially working (e.g., in-memory fallback, missing persistence).
21+
22+
- `stub` – Placeholder handler that always returns 501 Not Implemented.
1123

1224
<Callout type="info">
1325
**Source:** `packages/spec/src/api/discovery.zod.ts`
@@ -16,8 +28,8 @@ Reports per-service availability so clients can adapt their UI accordingly.
1628
## TypeScript Usage
1729

1830
```typescript
19-
import { ApiRoutes, Discovery, ServiceInfo, WellKnownCapabilities } from '@objectstack/spec/api';
20-
import type { ApiRoutes, Discovery, ServiceInfo, WellKnownCapabilities } from '@objectstack/spec/api';
31+
import { ApiRoutes, Discovery, RouteHealthEntry, RouteHealthReport, ServiceInfo, WellKnownCapabilities } from '@objectstack/spec/api';
32+
import type { ApiRoutes, Discovery, RouteHealthEntry, RouteHealthReport, ServiceInfo, WellKnownCapabilities } from '@objectstack/spec/api';
2133

2234
// Validate data
2335
const result = ApiRoutes.parse(data);
@@ -68,6 +80,39 @@ const result = ApiRoutes.parse(data);
6880
| **metadata** | `Record<string, any>` | optional | Custom metadata key-value pairs for extensibility |
6981

7082

83+
---
84+
85+
## RouteHealthEntry
86+
87+
### Properties
88+
89+
| Property | Type | Required | Description |
90+
| :--- | :--- | :--- | :--- |
91+
| **route** | `string` || Route path pattern |
92+
| **method** | `Enum<'GET' \| 'POST' \| 'PUT' \| 'DELETE' \| 'PATCH' \| 'HEAD' \| 'OPTIONS'>` || HTTP method (GET, POST, etc.) |
93+
| **service** | `string` || Target service name |
94+
| **declared** | `boolean` || Whether the route is declared in discovery/metadata |
95+
| **handlerRegistered** | `boolean` || Whether the HTTP handler is registered |
96+
| **healthStatus** | `Enum<'pass' \| 'fail' \| 'missing' \| 'skip'>` || pass = handler responds, fail = 501/503, missing = no handler (404), skip = not checked |
97+
| **message** | `string` | optional | Diagnostic message |
98+
99+
100+
---
101+
102+
## RouteHealthReport
103+
104+
### Properties
105+
106+
| Property | Type | Required | Description |
107+
| :--- | :--- | :--- | :--- |
108+
| **timestamp** | `string` || ISO 8601 timestamp of report generation |
109+
| **adapter** | `string` || Adapter or runtime that produced this report |
110+
| **totalDeclared** | `integer` || Total routes declared in discovery |
111+
| **totalRegistered** | `integer` || Routes with confirmed handler |
112+
| **totalMissing** | `integer` || Routes missing a handler |
113+
| **routes** | `Object[]` || Per-route health entries |
114+
115+
71116
---
72117

73118
## ServiceInfo
@@ -77,7 +122,8 @@ const result = ApiRoutes.parse(data);
77122
| Property | Type | Required | Description |
78123
| :--- | :--- | :--- | :--- |
79124
| **enabled** | `boolean` || |
80-
| **status** | `Enum<'available' \| 'unavailable' \| 'degraded' \| 'stub'>` || available = fully operational, unavailable = not installed, degraded = partial, stub = placeholder that throws |
125+
| **status** | `Enum<'available' \| 'registered' \| 'unavailable' \| 'degraded' \| 'stub'>` || available = fully operational, registered = route declared but handler unverified, unavailable = not installed, degraded = partial, stub = placeholder that returns 501 |
126+
| **handlerReady** | `boolean` | optional | Whether the HTTP handler is confirmed to be mounted. Omitted = readiness unknown/unverified; true = handler mounted; false = handler missing or stub (likely 501). |
81127
| **route** | `string` | optional | e.g. /api/v1/analytics |
82128
| **provider** | `string` | optional | e.g. "objectql", "plugin-redis", "driver-memory" |
83129
| **version** | `string` | optional | Semantic version of the service implementation (e.g. "3.0.6") |

content/docs/references/api/dispatcher.mdx

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ Architecture alignment:
3636
## TypeScript Usage
3737

3838
```typescript
39-
import { DispatcherConfig, DispatcherRoute } from '@objectstack/spec/api';
40-
import type { DispatcherConfig, DispatcherRoute } from '@objectstack/spec/api';
39+
import { DispatcherConfig, DispatcherErrorCode, DispatcherErrorResponse, DispatcherRoute } from '@objectstack/spec/api';
40+
import type { DispatcherConfig, DispatcherErrorCode, DispatcherErrorResponse, DispatcherRoute } from '@objectstack/spec/api';
4141

4242
// Validate data
4343
const result = DispatcherConfig.parse(data);
@@ -56,6 +56,32 @@ const result = DispatcherConfig.parse(data);
5656
| **proxyTarget** | `string` | optional | Proxy target URL when fallback is "proxy" |
5757

5858

59+
---
60+
61+
## DispatcherErrorCode
62+
63+
404 = route not found, 405 = method not allowed, 501 = not implemented (stub), 503 = service unavailable
64+
65+
### Allowed Values
66+
67+
* `404`
68+
* `405`
69+
* `501`
70+
* `503`
71+
72+
73+
---
74+
75+
## DispatcherErrorResponse
76+
77+
### Properties
78+
79+
| Property | Type | Required | Description |
80+
| :--- | :--- | :--- | :--- |
81+
| **success** | `boolean` || |
82+
| **error** | `Object` || |
83+
84+
5985
---
6086

6187
## DispatcherRoute

content/docs/references/api/meta.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"batch",
99
"connector",
1010
"contract",
11+
"core-services",
1112
"discovery",
1213
"dispatcher",
1314
"documentation",

content/docs/references/api/plugin-rest-api.mdx

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ Architecture Alignment:
116116
## TypeScript Usage
117117

118118
```typescript
119-
import { ErrorHandlingConfig, OpenApiGenerationConfig, RequestValidationConfig, ResponseEnvelopeConfig, RestApiEndpoint, RestApiPluginConfig, RestApiRouteCategory, RestApiRouteRegistration, ValidationMode } from '@objectstack/spec/api';
120-
import type { ErrorHandlingConfig, OpenApiGenerationConfig, RequestValidationConfig, ResponseEnvelopeConfig, RestApiEndpoint, RestApiPluginConfig, RestApiRouteCategory, RestApiRouteRegistration, ValidationMode } from '@objectstack/spec/api';
119+
import { ErrorHandlingConfig, HandlerStatus, OpenApiGenerationConfig, RequestValidationConfig, ResponseEnvelopeConfig, RestApiEndpoint, RestApiPluginConfig, RestApiRouteCategory, RestApiRouteRegistration, RouteCoverageEntry, RouteCoverageReport, ValidationMode } from '@objectstack/spec/api';
120+
import type { ErrorHandlingConfig, HandlerStatus, OpenApiGenerationConfig, RequestValidationConfig, ResponseEnvelopeConfig, RestApiEndpoint, RestApiPluginConfig, RestApiRouteCategory, RestApiRouteRegistration, RouteCoverageEntry, RouteCoverageReport, ValidationMode } from '@objectstack/spec/api';
121121

122122
// Validate data
123123
const result = ErrorHandlingConfig.parse(data);
@@ -143,6 +143,17 @@ const result = ErrorHandlingConfig.parse(data);
143143
| **redactFields** | `string[]` | optional | Field names to redact from error details |
144144

145145

146+
---
147+
148+
## HandlerStatus
149+
150+
### Allowed Values
151+
152+
* `implemented`
153+
* `stub`
154+
* `planned`
155+
156+
146157
---
147158

148159
## OpenApiGenerationConfig
@@ -228,6 +239,7 @@ const result = ErrorHandlingConfig.parse(data);
228239
| **rateLimit** | `string` | optional | Rate limit policy name |
229240
| **cacheable** | `boolean` || Whether response can be cached |
230241
| **cacheTtl** | `integer` | optional | Cache TTL in seconds |
242+
| **handlerStatus** | `Enum<'implemented' \| 'stub' \| 'planned'>` | optional | Handler implementation status: implemented (default if omitted), stub, or planned |
231243

232244

233245
---
@@ -290,6 +302,36 @@ const result = ErrorHandlingConfig.parse(data);
290302
| **documentation** | `Object` | optional | Documentation metadata for this route group |
291303

292304

305+
---
306+
307+
## RouteCoverageEntry
308+
309+
### Properties
310+
311+
| Property | Type | Required | Description |
312+
| :--- | :--- | :--- | :--- |
313+
| **path** | `string` || Full URL path (e.g. /api/v1/analytics/query) |
314+
| **method** | `Enum<'GET' \| 'POST' \| 'PUT' \| 'DELETE' \| 'PATCH' \| 'HEAD' \| 'OPTIONS'>` || HTTP method (GET, POST, etc.) |
315+
| **category** | `Enum<'discovery' \| 'metadata' \| 'data' \| 'batch' \| 'permission' \| 'analytics' \| 'automation' \| 'workflow' \| 'ui' \| 'realtime' \| 'notification' \| 'ai' \| 'i18n'>` || Route category |
316+
| **handlerStatus** | `Enum<'implemented' \| 'stub' \| 'planned'>` || Handler status |
317+
| **service** | `string` || Target service name |
318+
| **healthCheckPassed** | `boolean` | optional | Whether the health check probe succeeded |
319+
320+
321+
---
322+
323+
## RouteCoverageReport
324+
325+
### Properties
326+
327+
| Property | Type | Required | Description |
328+
| :--- | :--- | :--- | :--- |
329+
| **timestamp** | `string` || ISO 8601 timestamp |
330+
| **adapter** | `string` || Adapter name (e.g. "hono", "express", "nextjs") |
331+
| **summary** | `Object` || |
332+
| **entries** | `Object[]` || Per-endpoint coverage entries |
333+
334+
293335
---
294336

295337
## ValidationMode

content/docs/references/api/protocol.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import { AiInsightsRequest, AiInsightsResponse, AiNlqRequest, AiNlqResponse, AiS
4040
import type { AiInsightsRequest, AiInsightsResponse, AiNlqRequest, AiNlqResponse, AiSuggestRequest, AiSuggestResponse, AutomationTriggerRequest, AutomationTriggerResponse, BatchDataRequest, BatchDataResponse, CheckPermissionRequest, CheckPermissionResponse, CreateDataRequest, CreateDataResponse, CreateManyDataRequest, CreateManyDataResponse, DeleteDataRequest, DeleteDataResponse, DeleteManyDataRequest, DeleteManyDataResponse, DeleteViewRequest, DeleteViewResponse, FindDataRequest, FindDataResponse, GetDataRequest, GetDataResponse, GetDiscoveryRequest, GetDiscoveryResponse, GetEffectivePermissionsRequest, GetEffectivePermissionsResponse, GetFieldLabelsRequest, GetFieldLabelsResponse, GetLocalesRequest, GetLocalesResponse, GetMetaItemCachedRequest, GetMetaItemCachedResponse, GetMetaItemRequest, GetMetaItemResponse, GetMetaItemsRequest, GetMetaItemsResponse, GetMetaTypesRequest, GetMetaTypesResponse, GetNotificationPreferencesRequest, GetNotificationPreferencesResponse, GetObjectPermissionsRequest, GetObjectPermissionsResponse, GetPresenceRequest, GetPresenceResponse, GetTranslationsRequest, GetTranslationsResponse, GetUiViewRequest, GetViewRequest, GetWorkflowConfigRequest, GetWorkflowConfigResponse, GetWorkflowStateRequest, GetWorkflowStateResponse, HttpFindQueryParams, ListNotificationsRequest, ListNotificationsResponse, ListViewsRequest, MarkAllNotificationsReadRequest, MarkAllNotificationsReadResponse, MarkNotificationsReadRequest, MarkNotificationsReadResponse, NotificationPreferences, RealtimeConnectRequest, RealtimeConnectResponse, RealtimeDisconnectRequest, RealtimeDisconnectResponse, RealtimeSubscribeRequest, RealtimeSubscribeResponse, RealtimeUnsubscribeRequest, RealtimeUnsubscribeResponse, RegisterDeviceRequest, RegisterDeviceResponse, SaveMetaItemRequest, SaveMetaItemResponse, SetPresenceRequest, SetPresenceResponse, UnregisterDeviceRequest, UnregisterDeviceResponse, UpdateDataRequest, UpdateDataResponse, UpdateManyDataRequest, UpdateManyDataResponse, UpdateNotificationPreferencesRequest, UpdateNotificationPreferencesResponse, WorkflowApproveRequest, WorkflowApproveResponse, WorkflowRejectRequest, WorkflowRejectResponse, WorkflowState, WorkflowTransitionRequest, WorkflowTransitionResponse } from '@objectstack/spec/api';
4141

4242
// Validate data
43-
const result = AiNlqRequest.parse(data);
43+
const result = AiInsightsRequest.parse(data);
4444
```
4545

4646
---

packages/client/src/client.test.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -486,18 +486,10 @@ describe('AI namespace', () => {
486486
expect(opts.method).toBe('POST');
487487
});
488488

489-
it('should chat with AI', async () => {
490-
const { client, fetchMock } = createMockClient({
491-
success: true,
492-
data: { message: 'Here are the results...', conversationId: 'conv-1' }
493-
});
494-
const result = await client.ai.chat({
495-
message: 'Show me customer stats',
496-
conversationId: 'conv-1'
497-
});
498-
expect(result.conversationId).toBe('conv-1');
499-
const body = JSON.parse(fetchMock.mock.calls[0][1].body);
500-
expect(body.message).toBe('Show me customer stats');
489+
it('should not expose chat method (use Vercel AI SDK useChat directly)', () => {
490+
const { client } = createMockClient({ success: true, data: {} });
491+
// ai.chat was removed — consumers should use @ai-sdk/react useChat() directly
492+
expect(client.ai).not.toHaveProperty('chat');
501493
});
502494

503495
it('should get AI suggestions', async () => {

0 commit comments

Comments
 (0)