@sayrio/public 1.0.0 → 1.0.2

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
@@ -6,9 +6,10 @@ real‑time updates via WebSockets.
6
6
 
7
7
  - ✅ REST + WebSocket
8
8
  - ✅ Browser‑safe
9
- - ✅ TypeScript first
9
+ - ✅ TypeScriptfirst
10
10
  - ✅ Zero runtime dependencies
11
11
  - ✅ Versioned API (`v1`)
12
+ - ✅ Consistent `ApiResult<T>` responses
12
13
 
13
14
  > React hooks are available via the **`@sayrio/public/react`** sub‑path export.
14
15
 
@@ -28,73 +29,154 @@ pnpm add @sayrio/public
28
29
 
29
30
  ---
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
+
31
50
  ## Usage
32
51
 
33
52
  ### Basic Usage (REST)
34
53
 
35
- Fetch public organization data.
54
+ Fetch a public organization.
36
55
 
37
- `Sayr.org` is an alias for the current API version (`v1`):
56
+ `Sayr.org` is an alias for the latest API version (`v1`).
38
57
 
39
58
  ```ts
40
59
  import Sayr from "@sayrio/public";
41
60
 
42
- const org = await Sayr.org.get("acme");
61
+ const res = await Sayr.org.get("acme");
43
62
 
44
- console.log(org.name);
63
+ if (!res.success) {
64
+ console.error(res.error);
65
+ return;
66
+ }
67
+
68
+ console.log(res.data.name);
45
69
  ```
46
70
 
47
71
  You can also use the versioned API explicitly:
48
72
 
49
73
  ```ts
50
- const org = await Sayr.v1.org.get("acme");
74
+ const res = await Sayr.v1.org.get("acme");
75
+ ```
76
+
77
+ ---
78
+
79
+ ## Organizations
80
+
81
+ ### Fetch an Organization
82
+
83
+ ```ts
84
+ const res = await Sayr.org.get("acme");
85
+
86
+ if (res.success) {
87
+ console.log(res.data);
88
+ }
51
89
  ```
52
90
 
53
91
  ---
54
92
 
55
- ### Listing Tasks
93
+ ## Tasks
56
94
 
57
- Retrieve tasks for an organization:
95
+ ### List Tasks (Paginated)
58
96
 
59
97
  ```ts
60
- const { data: tasks } = await Sayr.org.tasks.list("acme", {
98
+ const res = await Sayr.org.tasks.list("acme", {
61
99
  order: "desc",
62
- limit: 10
100
+ limit: 10,
101
+ });
102
+
103
+ if (!res.success) return;
104
+
105
+ res.data.items.forEach((task) => {
106
+ console.log(task.title);
63
107
  });
64
108
 
65
- console.log(tasks);
109
+ console.log(res.data.pagination);
110
+ ```
111
+
112
+ Returned shape:
113
+
114
+ ```ts
115
+ ApiResult<{
116
+ items: Task[];
117
+ pagination: Pagination;
118
+ }>
66
119
  ```
67
120
 
68
121
  ---
69
122
 
70
- ### Fetching a Single Task
123
+ ### Fetch a Single Task
71
124
 
72
125
  ```ts
73
- const task = await Sayr.org.tasks.get("acme", 42);
126
+ const res = await Sayr.org.tasks.get("acme", 42);
74
127
 
75
- console.log(task.title);
128
+ if (res.success) {
129
+ console.log(res.data.title);
130
+ }
76
131
  ```
77
132
 
78
133
  ---
79
134
 
80
- ### Task Comments
135
+ ## Comments
81
136
 
82
- Fetch comments for a specific task:
137
+ ### List Task Comments (Paginated)
83
138
 
84
139
  ```ts
85
- const { data: comments } =
86
- await Sayr.org.comments.list("acme", 42);
140
+ const res = await Sayr.org.comments.list("acme", 42);
141
+
142
+ if (!res.success) return;
143
+
144
+ res.data.items.forEach((comment) => {
145
+ console.log(comment.contentMarkdown);
146
+ });
147
+ ```
148
+
149
+ Returned shape:
87
150
 
88
- console.log(comments);
151
+ ```ts
152
+ ApiResult<{
153
+ items: Comment[];
154
+ pagination: Pagination;
155
+ }>
89
156
  ```
90
157
 
91
158
  ---
92
159
 
93
- ### Labels & Categories
160
+ ## Labels & Categories
161
+
162
+ ### Labels
163
+
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
94
173
 
95
174
  ```ts
96
- const labels = await Sayr.org.labels.list("acme");
97
- const categories = await Sayr.org.categories.list("acme");
175
+ const res = await Sayr.org.categories.list("acme", "desc");
176
+
177
+ if (res.success) {
178
+ console.log(res.data);
179
+ }
98
180
  ```
99
181
 
100
182
  ---
@@ -104,19 +186,27 @@ const categories = await Sayr.org.categories.list("acme");
104
186
  The `/me` namespace provides **read‑only access** to the currently
105
187
  authenticated user.
106
188
 
107
- > Authentication is required.
189
+ > Authentication is required
108
190
  > Set a token using `Sayr.client.setToken(...)`.
109
191
 
110
192
  ---
111
193
 
112
- ### Fetch Current User
194
+ ### Set Token
113
195
 
114
196
  ```ts
115
- Sayr.client.setToken(token);
197
+ Sayr.client.setToken("********");
198
+ ```
199
+
200
+ ---
116
201
 
117
- const me = await Sayr.me.get();
202
+ ### Fetch Current User
203
+
204
+ ```ts
205
+ const res = await Sayr.me.get();
118
206
 
119
- console.log(me.email);
207
+ if (res.success) {
208
+ console.log(res.data.email);
209
+ }
120
210
  ```
121
211
 
122
212
  ---
@@ -124,9 +214,11 @@ console.log(me.email);
124
214
  ### List Your Organizations
125
215
 
126
216
  ```ts
127
- const orgs = await Sayr.me.organizations();
217
+ const res = await Sayr.me.organizations();
128
218
 
129
- console.log(orgs);
219
+ if (res.success) {
220
+ console.log(res.data);
221
+ }
130
222
  ```
131
223
 
132
224
  ---
@@ -137,9 +229,9 @@ Subscribe to public real‑time events using WebSockets:
137
229
 
138
230
  ```ts
139
231
  Sayr.ws(org.wsUrl, {
140
- [Sayr.WS_EVENTS.UPDATE_TASK]: (task) => {
141
- console.log("Task updated", task);
142
- }
232
+ [Sayr.WS_EVENTS.UPDATE_TASK]: (data) => {
233
+ console.log("Task updated", data);
234
+ },
143
235
  });
144
236
  ```
145
237
 
@@ -158,14 +250,17 @@ Sayr.ws(org.wsUrl, {
158
250
  <script type="module">
159
251
  import Sayr from "https://esm.sh/@sayrio/public";
160
252
 
161
- const org = await Sayr.org.get("acme");
162
- console.log(org);
253
+ const res = await Sayr.org.get("acme");
254
+
255
+ if (res.success) {
256
+ console.log(res.data);
257
+ }
163
258
  </script>
164
259
  ```
165
260
 
166
261
  ---
167
262
 
168
- ## API
263
+ ## API Overview
169
264
 
170
265
  ### `Sayr.org` (latest)
171
266
 
@@ -181,18 +276,18 @@ Alias for `Sayr.v1.org`.
181
276
 
182
277
  #### Tasks
183
278
 
184
- | Method | Description |
185
- | --------------------------- | ---------------------- |
186
- | `tasks.list(slug, opts?)` | List tasks (paginated) |
187
- | `tasks.get(slug, shortId)` | Fetch a single task |
279
+ | Method | Description |
280
+ | -------------------------- | ---------------------- |
281
+ | `tasks.list(slug, opts?)` | List tasks (paginated) |
282
+ | `tasks.get(slug, shortId)` | Fetch a single task |
188
283
 
189
284
  ---
190
285
 
191
286
  #### Comments
192
287
 
193
- | Method | Description |
194
- | ------------------------------------- | ------------------ |
195
- | `comments.list(slug, shortId, opts?)` | List task comments |
288
+ | Method | Description |
289
+ | ------------------------------------- | ------------------------ |
290
+ | `comments.list(slug, shortId, opts?)` | List task comments |
196
291
 
197
292
  ---
198
293
 
@@ -206,8 +301,8 @@ Alias for `Sayr.v1.org`.
206
301
 
207
302
  #### Categories
208
303
 
209
- | Method | Description |
210
- | ------------------------------ | --------------- |
304
+ | Method | Description |
305
+ | ------------------------------- | --------------- |
211
306
  | `categories.list(slug, order?)` | List categories |
212
307
 
213
308
  ---
@@ -216,10 +311,10 @@ Alias for `Sayr.v1.org`.
216
311
 
217
312
  Authenticated user endpoints.
218
313
 
219
- | Method | Description |
220
- | ------------------- | -------------------------------------- |
221
- | `get()` | Fetch the current authenticated user |
222
- | `organizations()` | List organizations the user belongs to |
314
+ | Method | Description |
315
+ | ----------------- | -------------------------------------- |
316
+ | `get()` | Fetch the authenticated user |
317
+ | `organizations()` | List organizations the user belongs to |
223
318
 
224
319
  ---
225
320
 
@@ -229,7 +324,7 @@ Create a WebSocket connection for public events:
229
324
 
230
325
  ```ts
231
326
  const conn = Sayr.ws(wsUrl, {
232
- UPDATE_TASK: () => {}
327
+ UPDATE_TASK: () => {},
233
328
  });
234
329
 
235
330
  conn.close();
@@ -242,8 +337,9 @@ conn.close();
242
337
  Typed WebSocket event constants:
243
338
 
244
339
  ```ts
340
+ Sayr.WS_EVENTS.CREATE_TASK;
245
341
  Sayr.WS_EVENTS.UPDATE_TASK;
246
- Sayr.WS_EVENTS.UPDATE_ORG;
342
+ Sayr.WS_EVENTS.UPDATE_TASK_COMMENTS;
247
343
  Sayr.WS_EVENTS.ERROR;
248
344
  ```
249
345
 
@@ -257,8 +353,27 @@ This package ships with full TypeScript definitions:
257
353
  import type {
258
354
  Organization,
259
355
  Task,
260
- Comment
356
+ Comment,
357
+ Label,
358
+ Category,
261
359
  } from "@sayrio/public";
262
360
  ```
263
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";
375
+ ```
376
+
377
+ See **`@sayrio/public/react` README** for full hook documentation.
378
+
264
379
  ---
package/dist/index.cjs CHANGED
@@ -33,7 +33,6 @@ module.exports = __toCommonJS(index_exports);
33
33
  // src/client/index.ts
34
34
  var DEFAULT_API = "https://api.sayr.io";
35
35
  var config = {
36
- fetch: globalThis.fetch,
37
36
  baseUrl: DEFAULT_API
38
37
  };
39
38
  var hooks = {};
@@ -46,9 +45,6 @@ function setHeaders(headers) {
46
45
  ...headers
47
46
  };
48
47
  }
49
- function setFetch(fn) {
50
- config.fetch = fn;
51
- }
52
48
  function setBaseUrl(url) {
53
49
  config.baseUrl = url.replace(/\/$/, "");
54
50
  }
@@ -139,11 +135,23 @@ var org_default = {
139
135
  * @since v1.0.0
140
136
  */
141
137
  async get(slug, opts) {
142
- const r = await request(
143
- `/v1/organization/${slug}`,
144
- opts
145
- );
146
- return r.data;
138
+ try {
139
+ const r = await request(
140
+ `/v1/organization/${slug}`,
141
+ opts
142
+ );
143
+ return {
144
+ success: true,
145
+ data: r.data,
146
+ error: null
147
+ };
148
+ } catch (err) {
149
+ return {
150
+ success: false,
151
+ data: null,
152
+ error: err?.message ?? "Failed to fetch organization"
153
+ };
154
+ }
147
155
  }
148
156
  };
149
157
 
@@ -164,15 +172,27 @@ var tasks_default = {
164
172
  * @since v1.0.0
165
173
  */
166
174
  async list(slug, params, opts) {
167
- const q = buildPaginationParams(params);
168
- const r = await request(
169
- `/v1/organization/${slug}/tasks?${q}`,
170
- opts
171
- );
172
- return {
173
- data: r.data,
174
- pagination: r.pagination
175
- };
175
+ try {
176
+ const q = buildPaginationParams(params);
177
+ const r = await request(
178
+ `/v1/organization/${slug}/tasks?${q}`,
179
+ opts
180
+ );
181
+ return {
182
+ success: true,
183
+ data: {
184
+ items: r.data,
185
+ pagination: r.pagination
186
+ },
187
+ error: null
188
+ };
189
+ } catch (err) {
190
+ return {
191
+ success: false,
192
+ data: null,
193
+ error: err?.message ?? "Failed to fetch tasks"
194
+ };
195
+ }
176
196
  },
177
197
  /**
178
198
  * Fetches a single public task by short ID.
@@ -180,11 +200,23 @@ var tasks_default = {
180
200
  * @since v1.0.0
181
201
  */
182
202
  async get(slug, shortId, opts) {
183
- const r = await request(
184
- `/v1/organization/${slug}/tasks/${shortId}`,
185
- opts
186
- );
187
- return r.data;
203
+ try {
204
+ const r = await request(
205
+ `/v1/organization/${slug}/tasks/${shortId}`,
206
+ opts
207
+ );
208
+ return {
209
+ success: true,
210
+ data: r.data,
211
+ error: null
212
+ };
213
+ } catch (err) {
214
+ return {
215
+ success: false,
216
+ data: null,
217
+ error: err?.message ?? "Failed to fetch task"
218
+ };
219
+ }
188
220
  }
189
221
  };
190
222
 
@@ -196,15 +228,27 @@ var comments_default = {
196
228
  * @since v1.0.0
197
229
  */
198
230
  async list(slug, shortId, params, opts) {
199
- const q = buildPaginationParams(params);
200
- const r = await request(
201
- `/v1/organization/${slug}/tasks/${shortId}/comments?${q}`,
202
- opts
203
- );
204
- return {
205
- data: r.data,
206
- pagination: r.pagination
207
- };
231
+ try {
232
+ const q = buildPaginationParams(params);
233
+ const r = await request(
234
+ `/v1/organization/${slug}/tasks/${shortId}/comments?${q}`,
235
+ opts
236
+ );
237
+ return {
238
+ success: true,
239
+ data: {
240
+ items: r.data,
241
+ pagination: r.pagination
242
+ },
243
+ error: null
244
+ };
245
+ } catch (err) {
246
+ return {
247
+ success: false,
248
+ data: null,
249
+ error: err?.message ?? "Failed to fetch task comments"
250
+ };
251
+ }
208
252
  }
209
253
  };
210
254
 
@@ -216,11 +260,23 @@ var labels_default = {
216
260
  * @since v1.0.0
217
261
  */
218
262
  async list(slug, opts) {
219
- const r = await request(
220
- `/v1/organization/${slug}/labels`,
221
- opts
222
- );
223
- return r.data;
263
+ try {
264
+ const r = await request(
265
+ `/v1/organization/${slug}/labels`,
266
+ opts
267
+ );
268
+ return {
269
+ success: true,
270
+ data: r.data,
271
+ error: null
272
+ };
273
+ } catch (err) {
274
+ return {
275
+ success: false,
276
+ data: null,
277
+ error: err?.message ?? "Failed to fetch labels"
278
+ };
279
+ }
224
280
  }
225
281
  };
226
282
 
@@ -232,11 +288,23 @@ var categories_default = {
232
288
  * @since v1.0.0
233
289
  */
234
290
  async list(slug, order = "desc", opts) {
235
- const r = await request(
236
- `/v1/organization/${slug}/categories?order=${order}`,
237
- opts
238
- );
239
- return r.data;
291
+ try {
292
+ const r = await request(
293
+ `/v1/organization/${slug}/categories?order=${order}`,
294
+ opts
295
+ );
296
+ return {
297
+ success: true,
298
+ data: r.data,
299
+ error: null
300
+ };
301
+ } catch (err) {
302
+ return {
303
+ success: false,
304
+ data: null,
305
+ error: err?.message ?? "Failed to fetch categories"
306
+ };
307
+ }
240
308
  }
241
309
  };
242
310
 
@@ -252,29 +320,40 @@ var org_default2 = OrgAPI;
252
320
 
253
321
  // src/api/v1/me/index.ts
254
322
  var me_default = {
255
- /**
256
- * Fetches the currently authenticated user.
257
- *
258
- * @since v1.0.0
259
- */
260
323
  async get(opts) {
261
- const r = await request(
262
- "/me",
263
- opts
264
- );
265
- return r.data;
324
+ try {
325
+ const r = await request("/v1/me", opts);
326
+ return {
327
+ success: true,
328
+ data: r.data,
329
+ error: null
330
+ };
331
+ } catch (err) {
332
+ return {
333
+ success: false,
334
+ data: null,
335
+ error: err?.message ?? "Failed to fetch user"
336
+ };
337
+ }
266
338
  },
267
- /**
268
- * Lists organizations the current user belongs to.
269
- *
270
- * @since v1.0.0
271
- */
272
339
  async organizations(opts) {
273
- const r = await request(
274
- "/organizations",
275
- opts
276
- );
277
- return r.data;
340
+ try {
341
+ const r = await request(
342
+ "/v1/me/organizations",
343
+ opts
344
+ );
345
+ return {
346
+ success: true,
347
+ data: r.data,
348
+ error: null
349
+ };
350
+ } catch (err) {
351
+ return {
352
+ success: false,
353
+ data: null,
354
+ error: err?.message ?? "Failed to fetch organizations"
355
+ };
356
+ }
278
357
  }
279
358
  };
280
359
 
@@ -349,8 +428,7 @@ var SayrClient = {
349
428
  setHeaders,
350
429
  setBaseUrl,
351
430
  resetClient,
352
- setHooks,
353
- setFetch
431
+ setHooks
354
432
  };
355
433
  var Sayr = {
356
434
  // client configuration