Skip to content

Commit a51cd9c

Browse files
committed
2 parents c58400a + 1c70bee commit a51cd9c

1 file changed

Lines changed: 87 additions & 26 deletions

File tree

content/docs/guides/client-sdk.mdx

Lines changed: 87 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ The `@objectstack/client` is the official TypeScript client for ObjectStack. It
1717
- **Batch Operations**: Efficient bulk create/update/upsert/delete with transaction support
1818
- **Query Builder**: Programmatic query construction with `createQuery()` and `createFilter()`
1919
- **Standardized Errors**: Machine-readable error codes with retry guidance
20-
- **100% Protocol Compliant**: Implements all 13 API namespaces and 95+ methods defined in `@objectstack/spec`
20+
- **100% Protocol Compliant**: Implements all 15 API namespaces defined in `@objectstack/spec`
2121

2222
## Installation
2323

@@ -105,19 +105,21 @@ if (discovery.services?.auth?.enabled) {
105105

106106
## Protocol Coverage
107107

108-
The `@objectstack/client` SDK aims to implement the ObjectStack API protocol specification. It covers all 13 API namespaces defined in `@objectstack/spec`:
108+
The `@objectstack/client` SDK aims to implement the ObjectStack API protocol specification. It covers all 15 API namespaces defined in `@objectstack/spec`:
109109

110110
| Namespace | Status | Methods | Purpose |
111111
|:----------|:------:|:--------|:--------|
112112
| **discovery** || 1 | API version & capabilities detection |
113113
| **meta** || 7 | Metadata operations (objects, views, plugins) |
114114
| **data** || 10 | CRUD & query operations |
115115
| **auth** || 5 | Authentication & user management |
116+
| **permissions** || 3 | Access control checks |
116117
| **packages** || 6 | Plugin/package lifecycle management |
117118
| **views** || 5 | UI view definitions |
118119
| **workflow** || 5 | Workflow state transitions |
119-
| **analytics** || 2 | Analytics queries |
120+
| **analytics** || 3 | Analytics queries |
120121
| **automation** || 1 | Automation triggers |
122+
| **storage** || 2 | File upload & download |
121123
| **i18n** || 3 | Internationalization |
122124
| **notifications** || 7 | Push notifications |
123125
| **realtime** || 6 | WebSocket subscriptions |
@@ -219,15 +221,21 @@ const result = await client.analytics.query({
219221
limit: 100,
220222
});
221223

222-
// Get cube metadata
223-
const meta = await client.analytics.getMeta();
224+
// Get cube metadata for a specific cube
225+
const meta = await client.analytics.meta('account');
226+
227+
// Explain a query plan
228+
const explained = await client.analytics.explain({
229+
cube: 'account',
230+
measures: ['revenue.sum'],
231+
});
224232
```
225233

226234
### `client.packages` — Package Management
227235

228236
```typescript
229237
const packages = await client.packages.list();
230-
await client.packages.install({ manifest: { name: 'plugin-auth', version: '1.0.0' } });
238+
await client.packages.install({ name: 'plugin-auth', version: '1.0.0' });
231239
await client.packages.enable('plugin-auth');
232240
await client.packages.disable('plugin-auth');
233241
await client.packages.uninstall('plugin-auth');
@@ -260,12 +268,17 @@ await client.workflow.reject({ object: 'approval', recordId, reason: 'Incomplete
260268
// Realtime — WebSocket subscriptions
261269
await client.realtime.connect({ protocol: 'websocket' });
262270
await client.realtime.subscribe({ channel: 'account', event: 'update' });
263-
await client.realtime.setPresence({ status: 'online' });
271+
await client.realtime.unsubscribe('subscription-id');
272+
await client.realtime.setPresence('account', { status: 'online' });
273+
await client.realtime.getPresence('account');
264274
await client.realtime.disconnect();
265275

266276
// Notifications — Push notification management
267277
await client.notifications.registerDevice({ token: 'device-token', platform: 'ios' });
268-
await client.notifications.list({ unreadOnly: true });
278+
await client.notifications.unregisterDevice('device-id');
279+
await client.notifications.getPreferences();
280+
await client.notifications.updatePreferences({ email: true, push: false });
281+
await client.notifications.list({ read: false });
269282
await client.notifications.markRead(['notif-1', 'notif-2']);
270283
await client.notifications.markAllRead();
271284

@@ -309,20 +322,39 @@ Build complex queries programmatically:
309322
import { createQuery, createFilter } from '@objectstack/client';
310323

311324
const query = createQuery('account')
312-
.select(['name', 'industry', 'revenue'])
313-
.where(
314-
createFilter()
315-
.and('industry', '=', 'Technology')
316-
.and('revenue', '>', 10000)
317-
.build()
318-
)
319-
.orderBy('-revenue')
325+
.select('name', 'industry', 'revenue')
326+
.where((f) => {
327+
f.equals('industry', 'Technology');
328+
f.greaterThan('revenue', 10000);
329+
})
330+
.orderBy('revenue', 'desc')
320331
.limit(50)
321332
.build();
322333

323334
const results = await client.data.query('account', query);
324335
```
325336

337+
### Filter Builder Methods
338+
339+
The `FilterBuilder` provides a rich set of filter methods:
340+
341+
```typescript
342+
import { createFilter } from '@objectstack/client';
343+
344+
const filter = createFilter()
345+
.equals('status', 'active') // field = value
346+
.notEquals('type', 'archived') // field != value
347+
.greaterThan('revenue', 10000) // field > value
348+
.lessThanOrEqual('age', 100) // field <= value
349+
.in('category', ['A', 'B', 'C']) // field IN (...)
350+
.like('name', '%Corp%') // field LIKE pattern
351+
.contains('name', 'Corp') // LIKE %Corp%
352+
.startsWith('name', 'Acme') // LIKE Acme%
353+
.isNull('deleted_at') // field IS NULL
354+
.between('created_at', '2024-01', '2024-12')
355+
.build();
356+
```
357+
326358
---
327359

328360
## Query Options
@@ -389,9 +421,11 @@ interface ClientConfig {
389421
/** Bearer token for authentication (if auth plugin installed) */
390422
token?: string;
391423
/** Custom fetch implementation (e.g. for SSR or testing) */
392-
fetch?: typeof fetch;
393-
/** Request timeout in ms (default: 30000) */
394-
timeout?: number;
424+
fetch?: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
425+
/** Logger instance for debugging */
426+
logger?: Logger;
427+
/** Enable debug logging */
428+
debug?: boolean;
395429
}
396430
```
397431

@@ -406,20 +440,48 @@ pnpm add @objectstack/client-react
406440
```
407441

408442
```typescript
409-
import { useObjectStack, useFind, useGet } from '@objectstack/client-react';
443+
import { ObjectStackProvider, useClient, useQuery } from '@objectstack/client-react';
444+
import { ObjectStackClient } from '@objectstack/client';
410445

446+
// 1. Wrap your app with the provider
447+
const client = new ObjectStackClient({ baseUrl: 'http://localhost:3004' });
448+
449+
function App() {
450+
return (
451+
<ObjectStackProvider client={client}>
452+
<AccountList />
453+
</ObjectStackProvider>
454+
);
455+
}
456+
457+
// 2. Use hooks in child components
411458
function AccountList() {
412-
const { data: accounts, loading } = useFind('account', {
459+
const { data, isLoading, error, refetch } = useQuery('account', {
413460
filters: ['status', '=', 'active'],
414461
sort: ['-created_at'],
415462
top: 20,
416463
});
417464

418-
if (loading) return <div>Loading...</div>;
419-
return accounts.map(a => <div key={a.id}>{a.name}</div>);
465+
if (isLoading) return <div>Loading...</div>;
466+
if (error) return <div>Error: {error.message}</div>;
467+
return data?.records.map(a => <div key={a.id}>{a.name}</div>);
420468
}
421469
```
422470

471+
### Available Hooks
472+
473+
| Hook | Purpose |
474+
|:-----|:--------|
475+
| `useClient()` | Access the `ObjectStackClient` instance from context |
476+
| `useQuery(object, options)` | Query data with auto caching and refetching |
477+
| `useMutation(object)` | Create/update/delete mutations |
478+
| `usePagination(object, options)` | Paginated data queries |
479+
| `useInfiniteQuery(object, options)` | Infinite scroll queries |
480+
| `useObject(name)` | Get object metadata |
481+
| `useView(object, type)` | Get view definition |
482+
| `useFields(object)` | Get field definitions |
483+
| `useMetadata(type, name)` | Get arbitrary metadata |
484+
423485
---
424486

425487
## Testing
@@ -449,7 +511,7 @@ cd packages/client
449511
pnpm test:integration
450512
```
451513

452-
Integration tests verify end-to-end communication with a live ObjectStack server across all 13 API namespaces.
514+
Integration tests verify end-to-end communication with a live ObjectStack server across all 15 API namespaces.
453515

454516
<Callout type="info">
455517
**Test coverage**: Integration test specifications cover discovery/connection, authentication, metadata operations, CRUD operations (basic, batch, advanced queries), permissions, workflow, realtime, notifications, AI services, i18n, analytics, packages, views, storage, and automation.
@@ -461,10 +523,9 @@ Integration tests verify end-to-end communication with a live ObjectStack server
461523

462524
For detailed information about the client's protocol implementation:
463525

464-
- **[Protocol Compliance Matrix](https://github.com/objectstack-ai/spec/blob/main/packages/client/CLIENT_SPEC_COMPLIANCE.md)** — Method-by-method verification of all 95+ API methods across 13 namespaces
526+
- **[Protocol Compliance Matrix](https://github.com/objectstack-ai/spec/blob/main/packages/client/CLIENT_SPEC_COMPLIANCE.md)** — Method-by-method verification of all API methods across 15 namespaces
465527
- **[Integration Test Specifications](https://github.com/objectstack-ai/spec/blob/main/packages/client/CLIENT_SERVER_INTEGRATION_TESTS.md)** — Comprehensive test cases for client-server communication
466528
- **[Quick Reference Guide](https://github.com/objectstack-ai/spec/blob/main/packages/client/QUICK_REFERENCE.md)** — Developer navigation and API reference
467-
- **[中文合规性报告](https://github.com/objectstack-ai/spec/blob/main/packages/client/CLIENT_SPEC_COMPLIANCE_CN.md)** — Chinese language compliance verification report
468529

469530
---
470531

0 commit comments

Comments
 (0)