Skip to content

Commit f80cc1a

Browse files
Copilothotlong
andcommitted
Fix all client-spec compliance issues identified in code review
- Fix permission routes to use /api/v1/auth (not /api/v1/permissions) per spec - Update permission check to use POST method with JSON body - Fix analytics.getMeta() → analytics.meta(cube) in all docs - Fix automation.trigger() signature to match implementation - Fix auth.refreshToken() to take string parameter - Fix permissions.getEffectivePermissions() to take no object argument - Fix storage.upload() and getDownloadUrl() signatures - Fix packages.install() to use manifest object - Remove unused beforeAll import from integration test - Add assertions to TC-DISC-004 test case - Update all server references to clarify external dependency - Remove non-existent hub namespace from documentation - Update CI/CD examples to show placeholder structure - Qualify compliance claims to be more accurate Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent b1e1669 commit f80cc1a

8 files changed

Lines changed: 94 additions & 72 deletions

File tree

content/docs/guides/client-sdk.mdx

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ if (discovery.services?.auth?.enabled) {
105105

106106
## Protocol Coverage
107107

108-
The `@objectstack/client` SDK is **100% compliant** with the ObjectStack API protocol specification. It implements all 13 API namespaces defined in `@objectstack/spec`:
108+
The `@objectstack/client` SDK aims to implement the ObjectStack API protocol specification. It covers all 13 API namespaces defined in `@objectstack/spec`:
109109

110110
| Namespace | Status | Methods | Purpose |
111111
|:----------|:------:|:--------|:--------|
@@ -124,7 +124,7 @@ The `@objectstack/client` SDK is **100% compliant** with the ObjectStack API pro
124124
| **ai** || 4 | AI services (NLQ, chat, insights) |
125125

126126
<Callout type="info">
127-
**Full compliance verification**: See [`CLIENT_SPEC_COMPLIANCE.md`](https://github.com/objectstack-ai/spec/blob/main/packages/client/CLIENT_SPEC_COMPLIANCE.md) for detailed method-by-method verification and [`CLIENT_SERVER_INTEGRATION_TESTS.md`](https://github.com/objectstack-ai/spec/blob/main/packages/client/CLIENT_SERVER_INTEGRATION_TESTS.md) for comprehensive integration test specifications.
127+
**Protocol compliance & verification**: See [`CLIENT_SPEC_COMPLIANCE.md`](https://github.com/objectstack-ai/spec/blob/main/packages/client/CLIENT_SPEC_COMPLIANCE.md) for detailed method-by-method verification and [`CLIENT_SERVER_INTEGRATION_TESTS.md`](https://github.com/objectstack-ai/spec/blob/main/packages/client/CLIENT_SERVER_INTEGRATION_TESTS.md) for comprehensive integration test specifications.
128128
</Callout>
129129

130130
---
@@ -243,12 +243,12 @@ await client.auth.login({ email: 'user@example.com', password: 'pass' });
243243
await client.auth.register({ email: 'new@example.com', password: 'pass' });
244244
await client.auth.me();
245245
await client.auth.logout();
246-
await client.auth.refreshToken({ refreshToken: 'token' });
246+
await client.auth.refreshToken('refresh-token-string');
247247

248248
// Permissions — Access control checks
249249
await client.permissions.check({ object: 'account', action: 'create' });
250250
await client.permissions.getObjectPermissions('account');
251-
await client.permissions.getEffectivePermissions('account');
251+
await client.permissions.getEffectivePermissions();
252252

253253
// Workflow — State machine management
254254
await client.workflow.getConfig('approval');
@@ -281,22 +281,22 @@ await client.i18n.getTranslations('zh-CN');
281281
await client.i18n.getFieldLabels('account', 'zh-CN');
282282

283283
// Automation — Trigger workflows and automations
284-
await client.automation.trigger({ trigger: 'send_welcome_email', payload: { userId } });
284+
await client.automation.trigger('send_welcome_email', { userId });
285285

286286
// Storage — File upload and management
287-
await client.storage.upload({ file: fileData, object: 'account', field: 'logo' });
288-
await client.storage.getDownloadUrl({ fileId: 'file-123' });
287+
await client.storage.upload(fileData, 'user');
288+
await client.storage.getDownloadUrl('file-123');
289289

290290
// Views — UI view management
291-
await client.views.list({ object: 'account' });
292-
await client.views.get(viewId);
293-
await client.views.create({ name: 'my_view', object: 'account', ... });
294-
await client.views.update(viewId, { ... });
295-
await client.views.delete(viewId);
291+
await client.views.list('account');
292+
await client.views.get('account', viewId);
293+
await client.views.create('account', { name: 'my_view', ... });
294+
await client.views.update('account', viewId, { ... });
295+
await client.views.delete('account', viewId);
296296
```
297297

298298
<Callout type="info">
299-
**Service availability**: Optional services (auth, workflow, ai, etc.) are only available when the corresponding plugin is installed on the server. Always check `client.discovery?.services` to verify service availability before calling these methods.
299+
**Service availability**: Optional services (workflow, ai, etc.) are only available when the corresponding plugin is installed on the server. Always check `client.discovery?.services` to verify service availability before calling these methods.
300300
</Callout>
301301

302302
---
@@ -437,12 +437,14 @@ Unit tests use mocks to verify client behavior without requiring a server.
437437

438438
### Integration Tests
439439

440+
**Note:** Integration tests require a running ObjectStack server. The server is provided by a separate repository and must be set up independently.
441+
440442
```bash
441-
# Terminal 1: Start test server
442-
cd packages/server
443-
pnpm dev:test
443+
# Prerequisite: Start an ObjectStack server with test data
444+
# For example, using the reference server repository
445+
# Follow the server repository's documentation for local setup
444446

445-
# Terminal 2: Run integration tests
447+
# From this repository, run the integration test script
446448
cd packages/client
447449
pnpm test:integration
448450
```

packages/client/CLIENT_SERVER_INTEGRATION_TESTS.md

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -838,20 +838,25 @@ export function expectValidResponse<T>(response: any): asserts response is T {
838838

839839
### Local Development
840840

841+
**Note:** Integration tests require a running ObjectStack server. The server is provided by a separate repository/package and is not included in this spec repository.
842+
841843
```bash
842-
# Start test server
843-
cd packages/server
844-
pnpm dev:test
844+
# Start test server (in the ObjectStack server repository)
845+
# Follow the server project's documentation for setup
846+
# Example: cd /path/to/objectstack-server && pnpm dev:test
845847

846-
# Run integration tests
848+
# Run integration tests (in this repository)
847849
cd packages/client
848850
pnpm test:integration
849851
```
850852

851853
### CI/CD Pipeline
852854

855+
**Note:** The workflow file referenced below is an example. Actual CI implementation will require setting up the test server infrastructure separately.
856+
853857
```yaml
854-
# .github/workflows/client-integration-tests.yml
858+
# Example: .github/workflows/client-integration-tests.yml
859+
# This workflow would need to be created and configured with proper server setup
855860
name: Client Integration Tests
856861

857862
on: [push, pull_request]
@@ -883,13 +888,15 @@ jobs:
883888
- name: Build spec
884889
run: pnpm --filter @objectstack/spec build
885890

891+
# Note: Server setup would require additional configuration
892+
# This is a placeholder showing the expected structure
886893
- name: Start test server
887-
run: pnpm --filter @objectstack/server dev:test &
894+
run: |
895+
# Server startup logic would go here
896+
# This depends on the ObjectStack server implementation
897+
echo "Server setup required"
888898
env:
889-
DATABASE_URL: postgres://postgres:test@localhost:5432/test
890-
891-
- name: Wait for server
892-
run: npx wait-on http://localhost:3000
899+
DATABASE_URL: postgresql://postgres:test@localhost:5432/test
893900

894901
- name: Run integration tests
895902
run: pnpm --filter @objectstack/client test:integration

packages/client/CLIENT_SPEC_COMPLIANCE.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ Protocol methods defined in `packages/spec/src/api/protocol.zod.ts`:
129129
**Notes:**
130130
- Permission endpoints are served under `/api/v1/auth` per spec's `plugin-rest-api.zod.ts`
131131
- Supports action types: `create`, `read`, `edit`, `delete`, `transfer`, `restore`, `purge`
132+
- `check()` uses POST method as per spec
133+
- `getObjectPermissions()` and `getEffectivePermissions()` use GET methods
132134

133135
---
134136

@@ -191,6 +193,7 @@ Protocol methods defined in `packages/spec/src/api/protocol.zod.ts`:
191193
**Notes:**
192194
- Schema defined in `packages/client/src/index.ts` (lines 50-59)
193195
- Allows triggering named automations with arbitrary payloads
196+
- Method signature: `trigger(triggerName: string, payload: any)`
194197

195198
---
196199

@@ -209,7 +212,7 @@ Protocol methods defined in `packages/spec/src/api/protocol.zod.ts`:
209212
| Spec Method | Request Schema | Response Schema | Client Method | Status |
210213
|-------------|----------------|-----------------|---------------|:------:|
211214
| Analytics Query | `AnalyticsQueryRequestSchema` | `AnalyticsResultResponseSchema` | `analytics.query()` ||
212-
| Get Analytics Meta | `GetAnalyticsMetaRequestSchema` | `AnalyticsMetadataResponseSchema` | `analytics.getMeta()` ||
215+
| Get Analytics Meta | `GetAnalyticsMetaRequestSchema` | `AnalyticsMetadataResponseSchema` | `analytics.meta(cube)` ||
213216

214217
---
215218

packages/client/QUICK_REFERENCE.md

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,14 @@ Runs existing unit tests:
6868

6969
### Integration Tests (New)
7070

71+
**Note:** Integration tests require a running ObjectStack server. The server is provided by a separate repository and must be set up independently.
72+
7173
```bash
72-
# Terminal 1: Start test server
73-
cd packages/server
74-
pnpm dev:test
74+
# Start test server (in the ObjectStack server repository)
75+
# Follow that project's documentation for test server setup
76+
# Example: cd /path/to/objectstack-server && pnpm dev:test
7577

76-
# Terminal 2: Run integration tests
78+
# Run integration tests (in this repository)
7779
cd packages/client
7880
pnpm test:integration
7981
```
@@ -93,17 +95,16 @@ Quick reference to all 13 implemented namespaces:
9395
| **Metadata** | `client.meta.*` | `await client.meta.getItem('object', 'contact')` |
9496
| **Data** | `client.data.*` | `await client.data.find('contact', { filters: { status: 'active' } })` |
9597
| **Auth** | `client.auth.*` | `await client.auth.login({ email, password })` |
96-
| **Packages** | `client.packages.*` | `await client.packages.install({ packageId })` |
97-
| **Views** | `client.views.*` | `await client.views.list({ object: 'contact' })` |
98+
| **Packages** | `client.packages.*` | `await client.packages.list()` |
99+
| **Views** | `client.views.*` | `await client.views.list('contact')` |
98100
| **Workflow** | `client.workflow.*` | `await client.workflow.transition({ object, recordId, transition })` |
99-
| **Analytics** | `client.analytics.*` | `await client.analytics.query({ object, aggregations })` |
100-
| **Automation** | `client.automation.*` | `await client.automation.trigger({ trigger, payload })` |
101+
| **Analytics** | `client.analytics.*` | `await client.analytics.meta('sales')` |
102+
| **Automation** | `client.automation.*` | `await client.automation.trigger('name', payload)` |
101103
| **i18n** | `client.i18n.*` | `await client.i18n.getTranslations('zh-CN')` |
102104
| **Notifications** | `client.notifications.*` | `await client.notifications.list({ unreadOnly: true })` |
103105
| **Realtime** | `client.realtime.*` | `await client.realtime.subscribe({ channel, event })` |
104106
| **AI** | `client.ai.*` | `await client.ai.nlq({ query: 'show active contacts' })` |
105-
| **Storage** | `client.storage.*` | `await client.storage.upload({ file, object, field })` |
106-
| **Hub** | `client.hub.*` | `await client.hub.connect()` |
107+
| **Storage** | `client.storage.*` | `await client.storage.upload(fileData, 'user')` |
107108

108109
## 🎯 Next Steps for Developers
109110

packages/client/README.md

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ const data = await retryableRequest(() =>
223223

224224
## Protocol Compliance
225225

226-
This client is **100% compliant** with the `@objectstack/spec` API protocol specification. It implements all 13 API namespaces:
226+
The `@objectstack/client` SDK implements all 13 API namespaces defined in the `@objectstack/spec` protocol specification:
227227

228228
| Namespace | Purpose | Status |
229229
|-----------|---------|:------:|
@@ -268,16 +268,21 @@ await client.auth.login({ email: 'user@example.com', password: 'pass' });
268268
await client.auth.register({ email: 'new@example.com', password: 'pass' });
269269
await client.auth.me();
270270
await client.auth.logout();
271+
await client.auth.refreshToken('refresh-token-string');
271272

272273
// Package Management
273274
await client.packages.list();
274-
await client.packages.install({ packageId: '@vendor/plugin' });
275+
await client.packages.install({
276+
name: 'vendor_plugin',
277+
label: 'Vendor Plugin',
278+
version: '1.0.0',
279+
});
275280
await client.packages.enable('plugin-id');
276281

277282
// Permissions
278283
await client.permissions.check({ object: 'contact', action: 'create' });
279284
await client.permissions.getObjectPermissions('contact');
280-
await client.permissions.getEffectivePermissions('contact');
285+
await client.permissions.getEffectivePermissions();
281286

282287
// Workflow
283288
await client.workflow.getConfig('approval');
@@ -309,14 +314,14 @@ await client.i18n.getFieldLabels('contact', 'zh-CN');
309314

310315
// Analytics
311316
await client.analytics.query({ object: 'sales', aggregations: ['sum:amount'] });
312-
await client.analytics.getMeta('sales');
317+
await client.analytics.meta('sales');
313318

314319
// Automation
315-
await client.automation.trigger({ trigger: 'send_welcome_email', payload: { userId } });
320+
await client.automation.trigger('send_welcome_email', { userId });
316321

317322
// File Storage
318-
await client.storage.upload({ file: fileData, object: 'contact', field: 'avatar' });
319-
await client.storage.getDownloadUrl({ fileId: 'file-123' });
323+
await client.storage.upload(fileData, 'user');
324+
await client.storage.getDownloadUrl('file-123');
320325
```
321326

322327
## Testing
@@ -329,15 +334,15 @@ pnpm test
329334

330335
### Integration Tests
331336

332-
Integration tests verify client-server communication across all protocol methods:
337+
**Note:** Integration tests require a running ObjectStack server. The server is provided by a separate repository and must be set up independently.
333338

334339
```bash
335-
# Start test server
336-
cd ../server
337-
pnpm dev:test
340+
# Start test server (in the ObjectStack server repository)
341+
# Follow that project's documentation for test server setup
342+
# Example: cd /path/to/objectstack-server && pnpm dev:test
338343

339-
# Run integration tests
340-
cd ../client
344+
# Run integration tests (in this repository)
345+
cd packages/client
341346
pnpm test:integration
342347
```
343348

packages/client/src/index.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -613,12 +613,10 @@ export class ObjectStackClient {
613613
*/
614614
check: async (request: CheckPermissionRequest): Promise<CheckPermissionResponse> => {
615615
const route = this.getRoute('permissions');
616-
const params = new URLSearchParams();
617-
params.set('object', request.object);
618-
params.set('action', request.action);
619-
if (request.recordId) params.set('recordId', request.recordId);
620-
if (request.field) params.set('field', request.field);
621-
const res = await this.fetch(`${this.baseUrl}${route}/check?${params.toString()}`);
616+
const res = await this.fetch(`${this.baseUrl}${route}/check`, {
617+
method: 'POST',
618+
body: JSON.stringify(request)
619+
});
622620
return this.unwrapResponse<CheckPermissionResponse>(res);
623621
},
624622

@@ -627,7 +625,7 @@ export class ObjectStackClient {
627625
*/
628626
getObjectPermissions: async (object: string): Promise<GetObjectPermissionsResponse> => {
629627
const route = this.getRoute('permissions');
630-
const res = await this.fetch(`${this.baseUrl}${route}/objects/${encodeURIComponent(object)}`);
628+
const res = await this.fetch(`${this.baseUrl}${route}/permissions/${encodeURIComponent(object)}`);
631629
return this.unwrapResponse<GetObjectPermissionsResponse>(res);
632630
},
633631

@@ -636,7 +634,7 @@ export class ObjectStackClient {
636634
*/
637635
getEffectivePermissions: async (): Promise<GetEffectivePermissionsResponse> => {
638636
const route = this.getRoute('permissions');
639-
const res = await this.fetch(`${this.baseUrl}${route}/effective`);
637+
const res = await this.fetch(`${this.baseUrl}${route}/permissions/effective`);
640638
return this.unwrapResponse<GetEffectivePermissionsResponse>(res);
641639
}
642640
};
@@ -1288,7 +1286,7 @@ export class ObjectStackClient {
12881286
storage: '/api/v1/storage',
12891287
automation: '/api/v1/automation',
12901288
packages: '/api/v1/packages',
1291-
permissions: '/api/v1/permissions',
1289+
permissions: '/api/v1/auth', // Permission endpoints are under /api/v1/auth per spec
12921290
realtime: '/api/v1/realtime',
12931291
workflow: '/api/v1/workflow',
12941292
views: '/api/v1/ui/views',

packages/client/tests/integration/01-discovery.test.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @see CLIENT_SERVER_INTEGRATION_TESTS.md for full test specification
88
*/
99

10-
import { describe, test, expect, beforeAll } from 'vitest';
10+
import { describe, test, expect } from 'vitest';
1111
import { ObjectStackClient } from '../../src/index';
1212

1313
const TEST_SERVER_URL = process.env.TEST_SERVER_URL || 'http://localhost:3000';
@@ -58,7 +58,11 @@ describe('Discovery & Connection', () => {
5858
await client.connect();
5959

6060
// After connection, client should have discovery info
61-
// This is tested implicitly by making actual API calls in other test suites
61+
expect(client.discovery).toBeDefined();
62+
expect(client.discovery?.version).toBeDefined();
63+
64+
// Verify that subsequent API calls can be made (routes are resolved)
65+
// This implicitly tests route resolution
6266
});
6367
});
6468
});

packages/client/tests/integration/README.md

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,17 @@ This directory contains integration tests that verify `@objectstack/client` agai
66

77
### Prerequisites
88

9-
1. **Start a test server:**
9+
**Note:** Integration tests require a running ObjectStack server with test data. The server is provided by a separate repository and must be set up independently.
10+
11+
1. **Start a test server (external dependency):**
1012
```bash
11-
cd ../../server
12-
pnpm dev:test
13+
# In the ObjectStack server repository (separate from this package)
14+
# Follow that project's documentation for test server setup
15+
# Example: cd /path/to/objectstack-server && pnpm dev:test
1316
```
1417

15-
2. **Run integration tests:**
18+
2. **Run integration tests (from this package):**
1619
```bash
17-
cd ../../client
1820
pnpm test:integration
1921
```
2022

@@ -62,9 +64,9 @@ Tests are organized by protocol namespace:
6264

6365
## CI/CD
6466

65-
Integration tests run automatically in CI when:
66-
- Pull requests are created
67-
- Changes are pushed to main branch
68-
- Manual workflow dispatch
67+
Integration tests can be run in CI, but require:
68+
- A running ObjectStack server instance (from separate repository)
69+
- Test database with sample data
70+
- Proper environment configuration
6971

70-
See `.github/workflows/client-integration-tests.yml` for the CI configuration.
72+
See `CLIENT_SERVER_INTEGRATION_TESTS.md` for example CI configuration structure.

0 commit comments

Comments
 (0)