@sayrio/public 0.1.4 → 1.0.1

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/README.md CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  # @sayrio/public
3
2
 
4
3
  Public JavaScript & TypeScript SDK for **Sayr.io**.
@@ -7,167 +6,315 @@ real‑time updates via WebSockets.
7
6
 
8
7
  - ✅ REST + WebSocket
9
8
  - ✅ Browser‑safe
10
- - ✅ TypeScript first
11
- - ✅ React hooks included (`/react`)
9
+ - ✅ TypeScriptfirst
12
10
  - ✅ Zero runtime dependencies
11
+ - ✅ Versioned API (`v1`)
12
+ - ✅ Consistent `ApiResult<T>` responses
13
+
14
+ > React hooks are available via the **`@sayrio/public/react`** sub‑path export.
13
15
 
14
16
  ---
15
17
 
16
18
  ## Installation
17
19
 
18
- Install the public Sayr SDK using your preferred package manager:
19
-
20
20
  ```bash
21
21
  npm install @sayrio/public
22
22
  ```
23
+
23
24
  or
25
+
24
26
  ```bash
25
27
  pnpm add @sayrio/public
26
28
  ```
27
29
 
30
+ ---
31
+
32
+ ## Core Concepts
33
+
34
+ ### ✅ `ApiResult<T>`
35
+
36
+ All SDK methods return a **non‑throwing** result object:
37
+
38
+ ```ts
39
+ interface ApiResult<T> {
40
+ success: boolean;
41
+ data: T | null;
42
+ error: string | null;
43
+ }
44
+ ```
45
+
46
+ Always check `success` before accessing `data`.
47
+
48
+ ---
49
+
28
50
  ## Usage
29
51
 
30
52
  ### Basic Usage (REST)
31
53
 
32
- Fetch public organization data using the REST API:
54
+ Fetch a public organization.
55
+
56
+ `Sayr.org` is an alias for the latest API version (`v1`).
33
57
 
34
58
  ```ts
35
59
  import Sayr from "@sayrio/public";
36
60
 
37
- const org = await Sayr.org.get("acme");
61
+ const res = await Sayr.org.get("acme");
38
62
 
39
- console.log(org.name);
63
+ if (!res.success) {
64
+ console.error(res.error);
65
+ return;
66
+ }
67
+
68
+ console.log(res.data.name);
69
+ ```
70
+
71
+ You can also use the versioned API explicitly:
72
+
73
+ ```ts
74
+ const res = await Sayr.v1.org.get("acme");
40
75
  ```
41
76
 
42
77
  ---
43
78
 
44
- ### Listing Tasks
79
+ ## Organizations
45
80
 
46
- Retrieve tasks for an organization with pagination and ordering support:
81
+ ### Fetch an Organization
47
82
 
48
83
  ```ts
49
- const { data: tasks, pagination } =
50
- await Sayr.org.tasks("acme", {
51
- order: "desc",
52
- limit: 10
53
- });
84
+ const res = await Sayr.org.get("acme");
54
85
 
55
- console.log(tasks);
86
+ if (res.success) {
87
+ console.log(res.data);
88
+ }
56
89
  ```
57
90
 
58
91
  ---
59
92
 
60
- ### Task Comments
93
+ ## Tasks
61
94
 
62
- Fetch comments for a specific task:
95
+ ### List Tasks (Paginated)
63
96
 
64
97
  ```ts
65
- const { data: comments } =
66
- await Sayr.org.comments("acme", 12);
98
+ const res = await Sayr.org.tasks.list("acme", {
99
+ order: "desc",
100
+ limit: 10,
101
+ });
102
+
103
+ if (!res.success) return;
104
+
105
+ res.data.items.forEach((task) => {
106
+ console.log(task.title);
107
+ });
67
108
 
68
- console.log(comments);
109
+ console.log(res.data.pagination);
110
+ ```
111
+
112
+ Returned shape:
113
+
114
+ ```ts
115
+ ApiResult<{
116
+ items: Task[];
117
+ pagination: Pagination;
118
+ }>
119
+ ```
120
+
121
+ ---
122
+
123
+ ### Fetch a Single Task
124
+
125
+ ```ts
126
+ const res = await Sayr.org.tasks.get("acme", 42);
127
+
128
+ if (res.success) {
129
+ console.log(res.data.title);
130
+ }
69
131
  ```
70
132
 
71
133
  ---
72
134
 
73
- ### Real-Time Updates (WebSocket)
135
+ ## Comments
74
136
 
75
- Subscribe to public real-time events using WebSockets:
137
+ ### List Task Comments (Paginated)
76
138
 
77
139
  ```ts
78
- Sayr.ws(org.wsUrl, {
79
- [Sayr.wsTypes.UPDATE_ORG]: (data) => {
80
- console.log("Organization updated", data);
81
- },
140
+ const res = await Sayr.org.comments.list("acme", 42);
82
141
 
83
- [Sayr.wsTypes.UPDATE_TASK]: (task) => {
84
- console.log("Task updated", task);
85
- }
142
+ if (!res.success) return;
143
+
144
+ res.data.items.forEach((comment) => {
145
+ console.log(comment.contentMarkdown);
86
146
  });
87
147
  ```
88
148
 
89
- ### WebSocket Features
90
- - Automatic reconnection
91
- - Heartbeat support (PING / PONG)
92
- - Typed event constants
93
- - Public-safe payloads only
149
+ Returned shape:
150
+
151
+ ```ts
152
+ ApiResult<{
153
+ items: Comment[];
154
+ pagination: Pagination;
155
+ }>
156
+ ```
94
157
 
95
158
  ---
96
159
 
97
- ## React Hooks
160
+ ## Labels & Categories
161
+
162
+ ### Labels
98
163
 
99
- React hooks are available via a dedicated sub-path export:
164
+ ```ts
165
+ const res = await Sayr.org.labels.list("acme");
166
+
167
+ if (res.success) {
168
+ console.log(res.data);
169
+ }
170
+ ```
171
+
172
+ ### Categories
100
173
 
101
174
  ```ts
102
- import { useOrg, useTasks, useComments } from "@sayrio/public/react";
175
+ const res = await Sayr.org.categories.list("acme", "desc");
176
+
177
+ if (res.success) {
178
+ console.log(res.data);
179
+ }
103
180
  ```
104
181
 
105
182
  ---
106
183
 
107
- ### `useOrg`
184
+ ## Authenticated User (`/me`)
185
+
186
+ The `/me` namespace provides **read‑only access** to the currently
187
+ authenticated user.
108
188
 
109
- Fetch and subscribe to an organization:
189
+ > Authentication is required
190
+ > Set a token using `Sayr.client.setToken(...)`.
110
191
 
111
- ```tsx
112
- const { data: org, loading } = useOrg("acme");
192
+ ---
193
+
194
+ ### Set Token
195
+
196
+ ```ts
197
+ Sayr.client.setToken("********");
198
+ ```
199
+
200
+ ---
201
+
202
+ ### Fetch Current User
203
+
204
+ ```ts
205
+ const res = await Sayr.me.get();
206
+
207
+ if (res.success) {
208
+ console.log(res.data.email);
209
+ }
113
210
  ```
114
211
 
115
212
  ---
116
213
 
117
- ### `useTasks`
214
+ ### List Your Organizations
118
215
 
119
- Fetch and subscribe to tasks for an organization:
216
+ ```ts
217
+ const res = await Sayr.me.organizations();
120
218
 
121
- ```tsx
122
- const { tasks } = useTasks("acme", org?.wsUrl);
219
+ if (res.success) {
220
+ console.log(res.data);
221
+ }
123
222
  ```
124
223
 
125
224
  ---
126
225
 
127
- ### `useComments`
226
+ ## Real‑Time Updates (WebSocket)
128
227
 
129
- Fetch and subscribe to comments for a task:
228
+ Subscribe to public real‑time events using WebSockets:
130
229
 
131
- ```tsx
132
- const { comments } = useComments(
133
- "acme",
134
- task.shortId,
135
- org?.wsUrl
136
- );
230
+ ```ts
231
+ Sayr.ws(org.wsUrl, {
232
+ [Sayr.WS_EVENTS.UPDATE_TASK]: (data) => {
233
+ console.log("Task updated", data);
234
+ },
235
+ });
137
236
  ```
138
237
 
139
- Hooks automatically refresh when relevant WebSocket events occur.
238
+ ### WebSocket Features
239
+
240
+ - Automatic reconnection
241
+ - Heartbeat support (PING / PONG)
242
+ - Typed event constants
243
+ - Public‑safe payloads only
140
244
 
141
245
  ---
142
246
 
143
247
  ## Browser Usage (No Bundler)
144
248
 
145
- The SDK can be used directly in the browser via ESM:
146
-
147
249
  ```html
148
250
  <script type="module">
149
251
  import Sayr from "https://esm.sh/@sayrio/public";
150
252
 
151
- const org = await Sayr.org.get("acme");
152
- console.log(org);
253
+ const res = await Sayr.org.get("acme");
254
+
255
+ if (res.success) {
256
+ console.log(res.data);
257
+ }
153
258
  </script>
154
259
  ```
155
260
 
156
261
  ---
157
262
 
158
- ## API
263
+ ## API Overview
264
+
265
+ ### `Sayr.org` (latest)
266
+
267
+ Alias for `Sayr.v1.org`.
268
+
269
+ #### Organization
270
+
271
+ | Method | Description |
272
+ | ----------- | --------------------------- |
273
+ | `get(slug)` | Fetch a public organization |
274
+
275
+ ---
276
+
277
+ #### Tasks
278
+
279
+ | Method | Description |
280
+ | -------------------------- | ---------------------- |
281
+ | `tasks.list(slug, opts?)` | List tasks (paginated) |
282
+ | `tasks.get(slug, shortId)` | Fetch a single task |
283
+
284
+ ---
285
+
286
+ #### Comments
287
+
288
+ | Method | Description |
289
+ | ------------------------------------- | ------------------------ |
290
+ | `comments.list(slug, shortId, opts?)` | List task comments |
291
+
292
+ ---
293
+
294
+ #### Labels
295
+
296
+ | Method | Description |
297
+ | ------------------- | ------------------------ |
298
+ | `labels.list(slug)` | List organization labels |
299
+
300
+ ---
301
+
302
+ #### Categories
159
303
 
160
- ### `Sayr.org`
304
+ | Method | Description |
305
+ | ------------------------------- | --------------- |
306
+ | `categories.list(slug, order?)` | List categories |
161
307
 
162
- | Method | Description |
163
- | -------------------------------- | --------------------------- |
164
- | `get(slug)` | Fetch a public organization |
165
- | `labels(slug)` | List organization labels |
166
- | `categories(slug, order?)` | List categories |
167
- | `tasks(slug, opts?)` | List tasks (paginated) |
168
- | `task(slug, shortId)` | Fetch a single task |
169
- | `comments(slug, shortId, opts?)` | List task comments |
308
+ ---
309
+
310
+ ### `Sayr.me`
170
311
 
312
+ Authenticated user endpoints.
313
+
314
+ | Method | Description |
315
+ | ----------------- | -------------------------------------- |
316
+ | `get()` | Fetch the authenticated user |
317
+ | `organizations()` | List organizations the user belongs to |
171
318
 
172
319
  ---
173
320
 
@@ -177,22 +324,23 @@ Create a WebSocket connection for public events:
177
324
 
178
325
  ```ts
179
326
  const conn = Sayr.ws(wsUrl, {
180
- UPDATE_TASK: () => {}
327
+ UPDATE_TASK: () => {},
181
328
  });
182
329
 
183
- // Close the connection when no longer needed
184
330
  conn.close();
185
331
  ```
186
332
 
187
333
  ---
188
334
 
189
- ### `Sayr.wsTypes`
335
+ ### `WS_EVENTS`
336
+
337
+ Typed WebSocket event constants:
190
338
 
191
339
  ```ts
192
- Sayr.wsTypes.UPDATE_TASK
193
- Sayr.wsTypes.UPDATE_ORG
194
- Sayr.wsTypes.ERROR
195
- // ...
340
+ Sayr.WS_EVENTS.CREATE_TASK;
341
+ Sayr.WS_EVENTS.UPDATE_TASK;
342
+ Sayr.WS_EVENTS.UPDATE_TASK_COMMENTS;
343
+ Sayr.WS_EVENTS.ERROR;
196
344
  ```
197
345
 
198
346
  ---
@@ -202,5 +350,30 @@ Sayr.wsTypes.ERROR
202
350
  This package ships with full TypeScript definitions:
203
351
 
204
352
  ```ts
205
- import type { Organization, Task } from "@sayrio/public";
353
+ import type {
354
+ Organization,
355
+ Task,
356
+ Comment,
357
+ Label,
358
+ Category,
359
+ } from "@sayrio/public";
360
+ ```
361
+
362
+ ---
363
+
364
+ ## React Hooks
365
+
366
+ React bindings are available via:
367
+
368
+ ```ts
369
+ import {
370
+ useOrg,
371
+ useTasks,
372
+ useTask,
373
+ useComments,
374
+ } from "@sayrio/public/react";
206
375
  ```
376
+
377
+ See **`@sayrio/public/react` README** for full hook documentation.
378
+
379
+ ---