@zeyos/client 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/LICENSE +21 -0
- package/README.md +458 -0
- package/agents/README.md +66 -0
- package/agents/shared/business-app-benchmarks.md +111 -0
- package/agents/shared/zeyos-entity-map.md +142 -0
- package/agents/shared/zeyos-entity-reference.md +570 -0
- package/agents/shared/zeyos-query-patterns.md +89 -0
- package/agents/zeyos-account-intelligence/SKILL.md +34 -0
- package/agents/zeyos-account-intelligence/agents/openai.yaml +4 -0
- package/agents/zeyos-account-intelligence/references/workflows.md +84 -0
- package/agents/zeyos-billing-insights/SKILL.md +41 -0
- package/agents/zeyos-billing-insights/agents/openai.yaml +4 -0
- package/agents/zeyos-billing-insights/references/workflows.md +106 -0
- package/agents/zeyos-campaign-and-outreach/SKILL.md +44 -0
- package/agents/zeyos-campaign-and-outreach/agents/openai.yaml +4 -0
- package/agents/zeyos-campaign-and-outreach/references/workflows.md +100 -0
- package/agents/zeyos-collaboration-and-activity/SKILL.md +37 -0
- package/agents/zeyos-collaboration-and-activity/agents/openai.yaml +4 -0
- package/agents/zeyos-collaboration-and-activity/references/workflows.md +104 -0
- package/agents/zeyos-collections-and-dunning/SKILL.md +46 -0
- package/agents/zeyos-collections-and-dunning/agents/openai.yaml +4 -0
- package/agents/zeyos-collections-and-dunning/references/workflows.md +132 -0
- package/agents/zeyos-commerce-and-inventory/SKILL.md +38 -0
- package/agents/zeyos-commerce-and-inventory/agents/openai.yaml +4 -0
- package/agents/zeyos-commerce-and-inventory/references/workflows.md +101 -0
- package/agents/zeyos-mail-operations/SKILL.md +35 -0
- package/agents/zeyos-mail-operations/agents/openai.yaml +4 -0
- package/agents/zeyos-mail-operations/references/workflows.md +110 -0
- package/agents/zeyos-notes-and-sops/SKILL.md +31 -0
- package/agents/zeyos-notes-and-sops/agents/openai.yaml +4 -0
- package/agents/zeyos-notes-and-sops/references/workflows.md +85 -0
- package/agents/zeyos-platform-and-schema/SKILL.md +37 -0
- package/agents/zeyos-platform-and-schema/agents/openai.yaml +4 -0
- package/agents/zeyos-platform-and-schema/references/workflows.md +97 -0
- package/agents/zeyos-work-management/SKILL.md +45 -0
- package/agents/zeyos-work-management/agents/openai.yaml +4 -0
- package/agents/zeyos-work-management/references/workflows.md +148 -0
- package/docs/01-api-reference/01-data-retrieval.md +601 -0
- package/docs/01-api-reference/02-authentication.md +288 -0
- package/docs/01-api-reference/03-resources.md +270 -0
- package/docs/01-api-reference/04-schema.md +539 -0
- package/docs/01-api-reference/_category_.json +9 -0
- package/docs/02-javascript-client/01-getting-started.md +146 -0
- package/docs/02-javascript-client/02-authentication.md +287 -0
- package/docs/02-javascript-client/03-making-requests.md +572 -0
- package/docs/02-javascript-client/04-practical-guide.md +348 -0
- package/docs/02-javascript-client/_category_.json +9 -0
- package/docs/03-cli/01-getting-started.md +219 -0
- package/docs/03-cli/02-commands.md +407 -0
- package/docs/03-cli/03-configuration.md +220 -0
- package/docs/03-cli/_category_.json +9 -0
- package/docs/04-agent-workflows/00-coding-agents.md +35 -0
- package/docs/04-agent-workflows/01-agent-quickstart.md +147 -0
- package/docs/04-agent-workflows/02-agent-recipes.md +109 -0
- package/docs/04-agent-workflows/03-cli-coverage-and-escalation.md +65 -0
- package/docs/04-agent-workflows/_category_.json +9 -0
- package/docs/04-sample-apps/01-kanban.md +89 -0
- package/docs/04-sample-apps/02-crm.md +81 -0
- package/docs/04-sample-apps/03-dashboard.md +80 -0
- package/docs/04-sample-apps/_category_.json +9 -0
- package/docs/05-tutorials/00-application-developers.md +43 -0
- package/docs/05-tutorials/01-integration-architecture.md +60 -0
- package/docs/05-tutorials/02-build-your-own-zeyos-frontend.md +517 -0
- package/docs/05-tutorials/03-server-side-integrations.md +185 -0
- package/docs/05-tutorials/_category_.json +9 -0
- package/docs/intro.md +197 -0
- package/openapi/api.json +24308 -0
- package/openapi/auth.json +415 -0
- package/openapi/dbref.json +56223 -0
- package/openapi/oauth2.json +781 -0
- package/openapi/sdk.json +949 -0
- package/openapi/views.txt +642 -0
- package/package.json +49 -0
- package/samples/crm/README.md +28 -0
- package/samples/crm/index.html +327 -0
- package/samples/crm/js/api.js +208 -0
- package/samples/crm/js/auth.js +61 -0
- package/samples/crm/js/main.js +545 -0
- package/samples/crm/js/state.js +90 -0
- package/samples/crm/js/ui.js +51 -0
- package/samples/dashboard/README.md +28 -0
- package/samples/dashboard/index.html +280 -0
- package/samples/dashboard/js/api.js +197 -0
- package/samples/dashboard/js/auth.js +59 -0
- package/samples/dashboard/js/main.js +382 -0
- package/samples/dashboard/js/state.js +81 -0
- package/samples/dashboard/js/ui.js +48 -0
- package/samples/kanban/README.md +28 -0
- package/samples/kanban/index.html +263 -0
- package/samples/kanban/js/api.js +152 -0
- package/samples/kanban/js/auth.js +59 -0
- package/samples/kanban/js/constants.js +40 -0
- package/samples/kanban/js/kanban.js +246 -0
- package/samples/kanban/js/main.js +362 -0
- package/samples/kanban/js/modals.js +474 -0
- package/samples/kanban/js/settings.js +82 -0
- package/samples/kanban/js/state.js +118 -0
- package/samples/kanban/js/ui.js +49 -0
- package/scripts/generate-client.mjs +344 -0
- package/src/generated/operations.js +9772 -0
- package/src/generated/schema.js +8982 -0
- package/src/index.js +85 -0
- package/src/runtime/client.js +1208 -0
- package/src/runtime/error.js +29 -0
- package/src/runtime/http.js +174 -0
- package/src/runtime/request-shape.js +35 -0
- package/src/runtime/schema.js +206 -0
- package/src/runtime/suggest.js +74 -0
- package/src/runtime/token-store.js +105 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
---
|
|
2
|
+
sidebar_label: Practical Guide
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Practical Implementation Guide
|
|
6
|
+
|
|
7
|
+
This guide documents patterns and gotchas discovered while building a real application on top of the ZeyOS JavaScript client. It supplements the reference documentation with things that only become apparent once you start making actual API calls.
|
|
8
|
+
|
|
9
|
+
## HTTP Method Conventions
|
|
10
|
+
|
|
11
|
+
ZeyOS uses an unconventional but consistent REST convention that often surprises developers:
|
|
12
|
+
|
|
13
|
+
| Operation | HTTP Method | Notes |
|
|
14
|
+
|-----------|-------------|-------|
|
|
15
|
+
| List records | **POST** | Query params (filters, sort, fields) go in the request body |
|
|
16
|
+
| Get a record | **GET** | |
|
|
17
|
+
| Create a record | **PUT** | Not POST — ZeyOS uses PUT for creation |
|
|
18
|
+
| Update a record | **PATCH** | Partial updates; only send fields you want to change |
|
|
19
|
+
| Delete a record | **DELETE** | |
|
|
20
|
+
| Check existence | **HEAD** | Returns `true` (no body) on success |
|
|
21
|
+
|
|
22
|
+
The most important one to internalise: **list operations are POST requests**. This makes sense once you consider that complex queries with nested filters would quickly exceed URL length limits as query strings.
|
|
23
|
+
|
|
24
|
+
## Passing the Request Body for Update Operations
|
|
25
|
+
|
|
26
|
+
Generated methods accept the natural flat style for operations that have both a path parameter and a request body:
|
|
27
|
+
|
|
28
|
+
```js
|
|
29
|
+
await client.api.updateTicket({ ID: 42, status: 4, priority: 2 });
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The client routes known path/query/header parameters to the request URL and sends the remaining non-reserved keys as the body. Explicit `body` and `data` keys are still supported when you want to separate those concerns yourself:
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
await client.api.updateTicket({ ID: 42, body: { status: 4, priority: 2 } });
|
|
36
|
+
await client.api.updateTask({ ID: taskId, data: { name: 'New name', duedate: ts } });
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
For low-level `client.request()` calls, prefer explicit `body` because there is no generated operation metadata to tell the client which keys are URL parameters.
|
|
40
|
+
|
|
41
|
+
## `filter` vs `filters`
|
|
42
|
+
|
|
43
|
+
The ZeyOS API exposes two distinct filtering parameters, and the one you need depends on the field type:
|
|
44
|
+
|
|
45
|
+
| Parameter | Use for | Example |
|
|
46
|
+
|-----------|---------|---------|
|
|
47
|
+
| `filter` | Simple scalar fields (integers, strings, enums) | `filter: { visibility: 0, status: 1 }` |
|
|
48
|
+
| `filters` | GIN-indexed fields — foreign key references and array-type columns | `filters: { ticket: ticketId, project: projectId }` |
|
|
49
|
+
|
|
50
|
+
In practice this means:
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
// Listing tickets — status and visibility are scalar fields → use 'filter'
|
|
54
|
+
const tickets = await client.api.listTickets({
|
|
55
|
+
filters: { visibility: 0, project: projectId },
|
|
56
|
+
sort: ['-lastmodified'],
|
|
57
|
+
limit: 500,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Listing tasks for a ticket — 'ticket' is a GIN-indexed FK → use 'filters'
|
|
61
|
+
const tasks = await client.api.listTasks({
|
|
62
|
+
fields: ['ID', 'tasknum', 'name', 'duedate', 'assigneduser'],
|
|
63
|
+
filters: { ticket: ticketId, visibility: 0 },
|
|
64
|
+
sort: ['+name'],
|
|
65
|
+
limit: 200,
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
:::tip
|
|
70
|
+
When in doubt, use `filters`. It appears to handle both scalar and FK fields correctly. Using `filter` for a FK field silently returns unfiltered results rather than throwing an error, which makes this particularly easy to miss.
|
|
71
|
+
:::
|
|
72
|
+
|
|
73
|
+
## Always Include `visibility: 0`
|
|
74
|
+
|
|
75
|
+
ZeyOS records have a `visibility` field that controls soft-deletion and archiving. Records with `visibility > 0` are typically hidden from normal views. Always include `visibility: 0` in your filters unless you intentionally want to retrieve archived or deleted records:
|
|
76
|
+
|
|
77
|
+
```js
|
|
78
|
+
const filter = { visibility: 0 };
|
|
79
|
+
// Add resource-specific filters after
|
|
80
|
+
if (projectId) filter.project = projectId;
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Normalising List Responses
|
|
84
|
+
|
|
85
|
+
List operations are not perfectly uniform across the whole surface area. Use the shared helper so every call site follows the same response-shape handling:
|
|
86
|
+
|
|
87
|
+
```js
|
|
88
|
+
import { normalizeListResult } from '@zeyos/client';
|
|
89
|
+
|
|
90
|
+
const result = await client.api.listTickets({ filters: { visibility: 0 } });
|
|
91
|
+
const { data: tickets } = normalizeListResult(result);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Use `normalizeCountResult()` for count-only requests.
|
|
95
|
+
|
|
96
|
+
## Date and Timestamp Handling
|
|
97
|
+
|
|
98
|
+
ZeyOS stores all dates as **Unix timestamps in seconds** (not milliseconds). When reading:
|
|
99
|
+
|
|
100
|
+
```js
|
|
101
|
+
// Convert to a JavaScript Date
|
|
102
|
+
const date = new Date(ticket.duedate * 1000);
|
|
103
|
+
|
|
104
|
+
// Format for display
|
|
105
|
+
const label = new Date(ticket.duedate * 1000).toLocaleDateString(undefined, {
|
|
106
|
+
month: 'short', day: 'numeric', year: 'numeric',
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Check if overdue
|
|
110
|
+
const isOverdue = ticket.duedate * 1000 < Date.now();
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
When writing (e.g. from an HTML `<input type="date">`):
|
|
114
|
+
|
|
115
|
+
```js
|
|
116
|
+
const dueDateVal = form.querySelector('#due-date').value; // '2026-03-15'
|
|
117
|
+
const duedate = dueDateVal
|
|
118
|
+
? Math.floor(new Date(dueDateVal).getTime() / 1000)
|
|
119
|
+
: null;
|
|
120
|
+
|
|
121
|
+
await client.api.updateTicket({ ID: id, body: { duedate } });
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Selecting Fields for Performance
|
|
125
|
+
|
|
126
|
+
Always pass a `fields` array in list requests. Without it, every field on every record is returned, which can significantly increase payload size and response time:
|
|
127
|
+
|
|
128
|
+
```js
|
|
129
|
+
// ✗ Returns all fields for every ticket
|
|
130
|
+
const tickets = await client.api.listTickets({ limit: 500 });
|
|
131
|
+
|
|
132
|
+
// ✓ Returns only what you need
|
|
133
|
+
const tickets = await client.api.listTickets({
|
|
134
|
+
fields: ['ID', 'ticketnum', 'name', 'status', 'priority', 'duedate'],
|
|
135
|
+
filters: { visibility: 0 },
|
|
136
|
+
limit: 500,
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
For single-record GET operations, field selection is not available — all standard fields are returned. Use query flags like `extdata: 1` and `tags: 1` to opt into additional data:
|
|
141
|
+
|
|
142
|
+
```js
|
|
143
|
+
const ticket = await client.api.getTicket({ ID: id, extdata: 1, tags: 1 });
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Optimistic UI Updates with Server Verification
|
|
147
|
+
|
|
148
|
+
For immediate feedback on user actions (like drag-and-drop), apply the change to local state first, then confirm with the server and revert if it fails. Use the response body to confirm the actual resulting value:
|
|
149
|
+
|
|
150
|
+
```js
|
|
151
|
+
const fromStatus = ticket.status;
|
|
152
|
+
|
|
153
|
+
// 1. Optimistic update — instant visual feedback
|
|
154
|
+
ticket.status = toStatus;
|
|
155
|
+
updateColumn(fromStatus);
|
|
156
|
+
updateColumn(toStatus);
|
|
157
|
+
|
|
158
|
+
try {
|
|
159
|
+
// 2. Send PATCH — response body contains the updated record
|
|
160
|
+
const updated = await client.api.updateTicket({
|
|
161
|
+
ID: ticket.ID,
|
|
162
|
+
body: { status: toStatus },
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// 3. Confirm — use the server's value in case it was clamped or rejected
|
|
166
|
+
const confirmedStatus = updated?.status ?? toStatus;
|
|
167
|
+
if (confirmedStatus !== toStatus) {
|
|
168
|
+
ticket.status = confirmedStatus;
|
|
169
|
+
updateColumn(toStatus);
|
|
170
|
+
updateColumn(confirmedStatus);
|
|
171
|
+
}
|
|
172
|
+
} catch (err) {
|
|
173
|
+
// 4. Revert on failure
|
|
174
|
+
ticket.status = fromStatus;
|
|
175
|
+
updateColumn(fromStatus);
|
|
176
|
+
updateColumn(toStatus);
|
|
177
|
+
showError(`Move failed: ${err.message}`);
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Persisting Refreshed Tokens
|
|
182
|
+
|
|
183
|
+
When using token mode with `autoRefresh: true` in a trusted environment, the client silently refreshes expired access tokens. The refreshed tokens are stored in the `MemoryTokenStore` but lost on page reload unless you persist them explicitly. Call a sync function after important API operations:
|
|
184
|
+
|
|
185
|
+
```js
|
|
186
|
+
async function syncTokens() {
|
|
187
|
+
try {
|
|
188
|
+
const ts = await client.auth.getTokenSet();
|
|
189
|
+
if (ts?.accessToken) {
|
|
190
|
+
localStorage.setItem('zeyos_tokens', JSON.stringify({
|
|
191
|
+
accessToken: ts.accessToken,
|
|
192
|
+
refreshToken: ts.refreshToken,
|
|
193
|
+
expiresAt: ts.expiresAt,
|
|
194
|
+
refreshTokenExpiresAt: ts.refreshTokenExpiresAt,
|
|
195
|
+
}));
|
|
196
|
+
}
|
|
197
|
+
} catch {
|
|
198
|
+
// Non-critical — silently ignore
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Usage
|
|
203
|
+
const tickets = await client.api.listTickets({ filters: { visibility: 0 } });
|
|
204
|
+
await syncTokens(); // Persist any refreshed tokens
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Session Detection Without Tokens
|
|
208
|
+
|
|
209
|
+
If you don't have an OAuth token but the user is already logged into ZeyOS in the same browser, you can detect their session via the userinfo endpoint:
|
|
210
|
+
|
|
211
|
+
```js
|
|
212
|
+
async function trySessionAuth(instanceUrl) {
|
|
213
|
+
try {
|
|
214
|
+
const res = await fetch(`${instanceUrl}oauth2/v1/userinfo`, {
|
|
215
|
+
credentials: 'include',
|
|
216
|
+
});
|
|
217
|
+
if (res.ok) return await res.json();
|
|
218
|
+
} catch {
|
|
219
|
+
// No session
|
|
220
|
+
}
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const userInfo = await trySessionAuth('https://cloud.zeyos.com/demo/');
|
|
225
|
+
if (userInfo) {
|
|
226
|
+
// Session is active — initialize in session mode
|
|
227
|
+
const client = createZeyosClient({
|
|
228
|
+
platform: instanceUrl,
|
|
229
|
+
auth: { mode: 'session', session: { enabled: true, credentials: 'include' } },
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
:::note
|
|
235
|
+
Session mode requires that your app is served from the same origin as ZeyOS, or that the ZeyOS instance is configured to allow cross-origin requests with credentials. If you are on a different domain, token mode is more reliable.
|
|
236
|
+
:::
|
|
237
|
+
|
|
238
|
+
## Navigating to ZeyOS Views
|
|
239
|
+
|
|
240
|
+
To link users directly to a record inside the ZeyOS web interface, construct a URL in this format:
|
|
241
|
+
|
|
242
|
+
```
|
|
243
|
+
<INSTANCE_URL>?umi=<MODULE>&page=<PAGE>&id=<RECORD_ID>&tab=<TAB>
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Common examples:
|
|
247
|
+
|
|
248
|
+
```js
|
|
249
|
+
const baseUrl = 'https://cloud.zeyos.com/demo/';
|
|
250
|
+
|
|
251
|
+
// Link to a ticket
|
|
252
|
+
`${baseUrl}?umi=tickets&page=details_ticket&id=${ticketId}&tab=0`
|
|
253
|
+
|
|
254
|
+
// Link to a task (within the tickets module)
|
|
255
|
+
`${baseUrl}?umi=tickets&page=details_ticket&id=${taskId}&tab=0`
|
|
256
|
+
|
|
257
|
+
// Link to an account
|
|
258
|
+
`${baseUrl}?umi=accounts&page=details_account&id=${accountId}&tab=0`
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Extended Data (extdata)
|
|
262
|
+
|
|
263
|
+
Many ZeyOS entities support custom fields via `extdata`. These are returned as a nested object:
|
|
264
|
+
|
|
265
|
+
```js
|
|
266
|
+
// Request extended data in a list
|
|
267
|
+
const tickets = await client.api.listTickets({
|
|
268
|
+
fields: ['ID', 'name', 'extdata.region', 'extdata.customer_type'],
|
|
269
|
+
filters: { visibility: 0 },
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// Or include all extdata for single-record fetches
|
|
273
|
+
const ticket = await client.api.getTicket({ ID: id, extdata: 1 });
|
|
274
|
+
console.log(ticket.extdata); // { region: 'EMEA', customer_type: 'Enterprise', ... }
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
When saving extended data back, pass it as a plain object:
|
|
278
|
+
|
|
279
|
+
```js
|
|
280
|
+
await client.api.updateTicket({
|
|
281
|
+
ID: id,
|
|
282
|
+
body: {
|
|
283
|
+
extdata: { region: 'APAC', customer_type: 'SMB' },
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## Common Status and Priority Values
|
|
289
|
+
|
|
290
|
+
Ticket and task status and priority values are plain integers. The canonical values observed in the ZeyOS API:
|
|
291
|
+
|
|
292
|
+
### Ticket Status
|
|
293
|
+
|
|
294
|
+
| Value | Label |
|
|
295
|
+
|-------|-------|
|
|
296
|
+
| `0` | Not Started |
|
|
297
|
+
| `1` | Awaiting Acceptance |
|
|
298
|
+
| `2` | Accepted |
|
|
299
|
+
| `3` | Rejected |
|
|
300
|
+
| `4` | Active |
|
|
301
|
+
| `5` | Inactive |
|
|
302
|
+
| `6` | Feedback Required |
|
|
303
|
+
| `7` | Testing |
|
|
304
|
+
| `8` | Cancelled |
|
|
305
|
+
| `9` | Completed |
|
|
306
|
+
| `10` | Failed |
|
|
307
|
+
| `11` | Booked |
|
|
308
|
+
|
|
309
|
+
### Ticket Priority
|
|
310
|
+
|
|
311
|
+
| Value | Label |
|
|
312
|
+
|-------|-------|
|
|
313
|
+
| `0` | Lowest |
|
|
314
|
+
| `1` | Low |
|
|
315
|
+
| `2` | Medium |
|
|
316
|
+
| `3` | High |
|
|
317
|
+
| `4` | Highest |
|
|
318
|
+
|
|
319
|
+
## Error Handling Checklist
|
|
320
|
+
|
|
321
|
+
`ZeyosApiError` is thrown for all non-2xx responses. Key properties to check:
|
|
322
|
+
|
|
323
|
+
```js
|
|
324
|
+
import { ZeyosApiError } from '@zeyos/client';
|
|
325
|
+
|
|
326
|
+
try {
|
|
327
|
+
await client.api.updateTicket({ ID: id, body: data });
|
|
328
|
+
} catch (err) {
|
|
329
|
+
if (!(err instanceof ZeyosApiError)) throw err; // Re-throw unexpected errors
|
|
330
|
+
|
|
331
|
+
if (err.status === 401) {
|
|
332
|
+
// Session expired or token invalid — redirect to login
|
|
333
|
+
} else if (err.status === 403) {
|
|
334
|
+
// Insufficient permissions
|
|
335
|
+
} else if (err.status === 404) {
|
|
336
|
+
// Record does not exist
|
|
337
|
+
} else if (err.status === 409) {
|
|
338
|
+
// Conflict — record was modified since last read (check If-Match header usage)
|
|
339
|
+
} else {
|
|
340
|
+
// Generic error — err.body often contains a human-readable message
|
|
341
|
+
console.error(err.body?.message ?? err.message);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
:::tip
|
|
347
|
+
On 401, the client automatically retries with a refreshed token if `autoRefresh: true` is set, a refresh token is available, and OAuth client credentials are configured. You will only see a 401 error if the refresh also fails — typically meaning the user's session has fully expired.
|
|
348
|
+
:::
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
---
|
|
2
|
+
sidebar_label: Getting Started
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# CLI Getting Started
|
|
6
|
+
|
|
7
|
+
The ZeyOS CLI gives you fast, scriptable access to the ZeyOS REST API from your terminal. It is the default entry point for coding agents and shell automation against the CLI's curated resource registry.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
:::info Requirements
|
|
12
|
+
Node.js 18.3+ is required. The CLI has zero external dependencies beyond the bundled `@zeyos/client` package.
|
|
13
|
+
:::
|
|
14
|
+
|
|
15
|
+
### Published package (recommended)
|
|
16
|
+
|
|
17
|
+
Install the CLI globally from npm:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install -g @zeyos/cli
|
|
21
|
+
zeyos --help
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Running from source
|
|
25
|
+
|
|
26
|
+
If you are contributing to the CLI or need to run an unreleased version, clone the repository and run directly from the source tree:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Clone the repository
|
|
30
|
+
git clone <repo-url>
|
|
31
|
+
cd client
|
|
32
|
+
|
|
33
|
+
# Run directly
|
|
34
|
+
./cli/bin/zeyos.mjs --help
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
For convenience, create a symlink so you can run `zeyos` from anywhere:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
ln -s $(pwd)/cli/bin/zeyos.mjs /usr/local/bin/zeyos
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## First Login
|
|
44
|
+
|
|
45
|
+
Authenticate with your ZeyOS instance using the `login` command:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Interactive — prompts for URL, app ID, and secret
|
|
49
|
+
zeyos login
|
|
50
|
+
|
|
51
|
+
# Or provide all values upfront
|
|
52
|
+
zeyos login \
|
|
53
|
+
--base-url https://cloud.zeyos.com/demo \
|
|
54
|
+
--client-id myapp \
|
|
55
|
+
--secret "$ZEYOS_CLIENT_SECRET"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
For interactive use, omit `--secret`; the CLI prompts without echoing the secret to the terminal. Passing secrets as command-line arguments is best reserved for controlled automation.
|
|
59
|
+
|
|
60
|
+
**What happens:**
|
|
61
|
+
|
|
62
|
+
1. The CLI opens your browser to the ZeyOS authorization page
|
|
63
|
+
2. You log in and authorize the application
|
|
64
|
+
3. The CLI exchanges the authorization code for access + refresh tokens
|
|
65
|
+
4. Credentials are saved to `.zeyos/auth.json` in your project
|
|
66
|
+
|
|
67
|
+
:::tip Switching Instances
|
|
68
|
+
Use `--clean` to discard all saved credentials and start fresh:
|
|
69
|
+
```bash
|
|
70
|
+
zeyos login --clean
|
|
71
|
+
```
|
|
72
|
+
This is useful when switching between ZeyOS instances.
|
|
73
|
+
:::
|
|
74
|
+
|
|
75
|
+
## Your First Commands
|
|
76
|
+
|
|
77
|
+
Once logged in, you can start working with your data:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# Check who you're logged in as
|
|
81
|
+
zeyos whoami
|
|
82
|
+
|
|
83
|
+
# List tickets (table output by default)
|
|
84
|
+
zeyos list tickets
|
|
85
|
+
|
|
86
|
+
# Get a specific ticket with all details
|
|
87
|
+
zeyos get ticket 42 --all
|
|
88
|
+
|
|
89
|
+
# Count records
|
|
90
|
+
zeyos count accounts
|
|
91
|
+
|
|
92
|
+
# Create a new ticket
|
|
93
|
+
zeyos create ticket --name "Fix login bug" --status 0 --priority 3
|
|
94
|
+
|
|
95
|
+
# Update a ticket's status
|
|
96
|
+
zeyos update ticket 42 --status 4
|
|
97
|
+
|
|
98
|
+
# Delete a ticket
|
|
99
|
+
zeyos delete ticket 42
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Inspect the curated CLI-supported resource set at any time:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
zeyos resources
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
If the resource you need does not appear there, switch to [`@zeyos/client`](../02-javascript-client/01-getting-started.md).
|
|
109
|
+
|
|
110
|
+
## Discover the Schema
|
|
111
|
+
|
|
112
|
+
Inspect a resource's fields, types, foreign keys, and enum values before querying. This works offline -- no login required -- so it is a fast way to learn the data model:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
zeyos describe tickets
|
|
116
|
+
zeyos describe accounts --json
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Install Agent Skills
|
|
120
|
+
|
|
121
|
+
If you are driving the CLI from a coding agent (Claude, Codex, …), install the bundled ZeyOS skill packs into your project so the agent picks up the right query conventions:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
zeyos skills list # see the available skills
|
|
125
|
+
zeyos skills install # copy them into .claude/skills (or .codex)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
See the [Commands Reference](./02-commands.md#skills) for details.
|
|
129
|
+
|
|
130
|
+
## Working with Filters
|
|
131
|
+
|
|
132
|
+
Query specific records using JSON filter expressions:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# Tickets with status = 1 (In Progress)
|
|
136
|
+
zeyos list tickets --filter '{"status":1}'
|
|
137
|
+
|
|
138
|
+
# Combine multiple criteria (AND logic)
|
|
139
|
+
zeyos list tickets --filter '{"status":1,"priority":3}'
|
|
140
|
+
|
|
141
|
+
# Count matching records
|
|
142
|
+
zeyos count tickets --filter '{"status":1}'
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
For normal operational views, include `visibility: 0`:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
zeyos list tickets --filter '{"visibility":0,"status":1}'
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Sorting and Pagination
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# Sort by name ascending, then by last modified descending
|
|
155
|
+
zeyos list tickets --sort "+name,-lastmodified"
|
|
156
|
+
|
|
157
|
+
# Limit results and paginate
|
|
158
|
+
zeyos list tickets --limit 10
|
|
159
|
+
zeyos list tickets --limit 10 --offset 10 # page 2
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
When results fill the page limit, the CLI automatically shows pagination info:
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
Showing 1–10 of 47 (--offset 10 for next page)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Output Formats
|
|
169
|
+
|
|
170
|
+
Choose the format that fits your workflow:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
# Default: formatted table (human-readable)
|
|
174
|
+
zeyos list tickets
|
|
175
|
+
|
|
176
|
+
# JSON: for scripting and piping
|
|
177
|
+
zeyos list tickets --json
|
|
178
|
+
|
|
179
|
+
# YAML: for config-friendly output
|
|
180
|
+
zeyos list tickets --yaml
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
:::tip Piping
|
|
184
|
+
JSON output works great with tools like `jq`:
|
|
185
|
+
```bash
|
|
186
|
+
zeyos list tickets --json | jq '.[].name'
|
|
187
|
+
```
|
|
188
|
+
:::
|
|
189
|
+
|
|
190
|
+
## JSON-First Automation
|
|
191
|
+
|
|
192
|
+
For coding agents and non-interactive scripts, prefer `--json` output and JSON-first writes:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
zeyos create ticket --data '{"name":"Fix login bug","status":0,"priority":3,"visibility":0}' --json
|
|
196
|
+
zeyos update ticket 42 --data '{"status":4}' --json
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
`zeyos whoami --json` does not print access tokens. If a local tool explicitly needs the current token, use `zeyos whoami --show-token --json` and treat the output as a secret.
|
|
200
|
+
|
|
201
|
+
## Credential Storage
|
|
202
|
+
|
|
203
|
+
Tokens are saved to `.zeyos/auth.json` in your project directory (or the nearest parent that has one). For global credentials shared across projects:
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
zeyos login --global
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
This saves to `~/.config/zeyos/credentials.json` instead.
|
|
210
|
+
|
|
211
|
+
:::warning
|
|
212
|
+
Add `.zeyos/auth.json` to your `.gitignore` — it contains access tokens.
|
|
213
|
+
:::
|
|
214
|
+
|
|
215
|
+
## Next Steps
|
|
216
|
+
|
|
217
|
+
- **[Coding Agents](../04-agent-workflows/00-coding-agents.md)** -- CLI-first workflows and escalation guidance
|
|
218
|
+
- **[Commands Reference](./02-commands.md)** — Full reference for every command
|
|
219
|
+
- **[Configuration](./03-configuration.md)** — Config files, environment variables, and resource field customization
|