@sayrio/public 0.0.5

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.
@@ -0,0 +1,431 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/react/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ useComments: () => useComments,
24
+ useOrg: () => useOrg,
25
+ useSayrWS: () => useSayrWS,
26
+ useTask: () => useTask,
27
+ useTasks: () => useTasks
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+
31
+ // src/react/useOrg.ts
32
+ var import_react = require("react");
33
+
34
+ // src/client/index.ts
35
+ var DEFAULT_API = "https://api.sayr.io";
36
+ var config = {
37
+ fetch: globalThis.fetch,
38
+ baseUrl: DEFAULT_API
39
+ };
40
+ var hooks = {};
41
+ function setToken(token) {
42
+ config.token = token;
43
+ }
44
+ function setHeaders(headers) {
45
+ config.headers = {
46
+ ...config.headers,
47
+ ...headers
48
+ };
49
+ }
50
+ function setFetch(fn) {
51
+ config.fetch = fn;
52
+ }
53
+ function setBaseUrl(url) {
54
+ config.baseUrl = url.replace(/\/$/, "");
55
+ }
56
+ function setHooks(h) {
57
+ Object.assign(hooks, h);
58
+ }
59
+ function resetClient() {
60
+ config.token = void 0;
61
+ config.headers = void 0;
62
+ config.baseUrl = DEFAULT_API;
63
+ }
64
+ async function request(path, opts = {}) {
65
+ const url = path.startsWith("http") ? path : `${config.baseUrl}${path}`;
66
+ hooks.onRequest?.(url, opts);
67
+ let res;
68
+ try {
69
+ res = await config.fetch(url, {
70
+ method: opts.method ?? "GET",
71
+ headers: {
72
+ ...config.token ? { Authorization: `Bearer ${config.token}` } : {},
73
+ ...opts.body ? { "Content-Type": "application/json" } : {},
74
+ ...config.headers,
75
+ ...opts.headers
76
+ },
77
+ body: opts.body ? JSON.stringify(opts.body) : void 0,
78
+ signal: opts.signal
79
+ });
80
+ } catch (err) {
81
+ const error = {
82
+ success: false,
83
+ error: "NETWORK_ERROR",
84
+ message: "Failed to reach Sayr API"
85
+ };
86
+ hooks.onError?.(error);
87
+ throw error;
88
+ }
89
+ hooks.onResponse?.(res);
90
+ let json;
91
+ try {
92
+ json = await res.json();
93
+ } catch {
94
+ const error = {
95
+ success: false,
96
+ error: "INVALID_RESPONSE",
97
+ message: "Server returned invalid JSON",
98
+ status: res.status
99
+ };
100
+ hooks.onError?.(error);
101
+ throw error;
102
+ }
103
+ if (!res.ok || !json.success) {
104
+ const error = {
105
+ ...json,
106
+ success: false,
107
+ status: res.status
108
+ };
109
+ hooks.onError?.(error);
110
+ throw error;
111
+ }
112
+ return json;
113
+ }
114
+
115
+ // src/api/v1/org/org.ts
116
+ var org_default = {
117
+ /**
118
+ * Fetches a public organization by slug.
119
+ *
120
+ * @since v1.0.0
121
+ */
122
+ async get(slug, opts) {
123
+ const r = await request(
124
+ `/v1/organization/${slug}`,
125
+ opts
126
+ );
127
+ return r.data;
128
+ }
129
+ };
130
+
131
+ // src/shared/index.ts
132
+ function buildPaginationParams(params) {
133
+ return new URLSearchParams({
134
+ order: params?.order ?? "desc",
135
+ limit: String(params?.limit ?? 5),
136
+ page: String(params?.page ?? 1)
137
+ });
138
+ }
139
+
140
+ // src/api/v1/org/tasks.ts
141
+ var tasks_default = {
142
+ /**
143
+ * Lists public tasks for an organization.
144
+ *
145
+ * @since v1.0.0
146
+ */
147
+ async list(slug, params, opts) {
148
+ const q = buildPaginationParams(params);
149
+ const r = await request(
150
+ `/v1/organization/${slug}/tasks?${q}`,
151
+ opts
152
+ );
153
+ return {
154
+ data: r.data,
155
+ pagination: r.pagination
156
+ };
157
+ },
158
+ /**
159
+ * Fetches a single public task by short ID.
160
+ *
161
+ * @since v1.0.0
162
+ */
163
+ async get(slug, shortId, opts) {
164
+ const r = await request(
165
+ `/v1/organization/${slug}/tasks/${shortId}`,
166
+ opts
167
+ );
168
+ return r.data;
169
+ }
170
+ };
171
+
172
+ // src/api/v1/org/comments.ts
173
+ var comments_default = {
174
+ /**
175
+ * Lists public comments for a task.
176
+ *
177
+ * @since v1.0.0
178
+ */
179
+ async list(slug, shortId, params, opts) {
180
+ const q = buildPaginationParams(params);
181
+ const r = await request(
182
+ `/v1/organization/${slug}/tasks/${shortId}/comments?${q}`,
183
+ opts
184
+ );
185
+ return {
186
+ data: r.data,
187
+ pagination: r.pagination
188
+ };
189
+ }
190
+ };
191
+
192
+ // src/api/v1/org/labels.ts
193
+ var labels_default = {
194
+ /**
195
+ * Lists public labels for an organization.
196
+ *
197
+ * @since v1.0.0
198
+ */
199
+ async list(slug, opts) {
200
+ const r = await request(
201
+ `/v1/organization/${slug}/labels`,
202
+ opts
203
+ );
204
+ return r.data;
205
+ }
206
+ };
207
+
208
+ // src/api/v1/org/categories.ts
209
+ var categories_default = {
210
+ /**
211
+ * Lists public categories for an organization.
212
+ *
213
+ * @since v1.0.0
214
+ */
215
+ async list(slug, order = "desc", opts) {
216
+ const r = await request(
217
+ `/v1/organization/${slug}/categories?order=${order}`,
218
+ opts
219
+ );
220
+ return r.data;
221
+ }
222
+ };
223
+
224
+ // src/api/v1/org/index.ts
225
+ var OrgAPI = {
226
+ ...org_default,
227
+ tasks: tasks_default,
228
+ comments: comments_default,
229
+ labels: labels_default,
230
+ categories: categories_default
231
+ };
232
+ var org_default2 = OrgAPI;
233
+
234
+ // src/api/v1/me/index.ts
235
+ var me_default = {
236
+ /**
237
+ * Fetches the currently authenticated user.
238
+ *
239
+ * @since v1.0.0
240
+ */
241
+ async get(opts) {
242
+ const r = await request(
243
+ "/me",
244
+ opts
245
+ );
246
+ return r.data;
247
+ },
248
+ /**
249
+ * Lists organizations the current user belongs to.
250
+ *
251
+ * @since v1.0.0
252
+ */
253
+ async organizations(opts) {
254
+ const r = await request(
255
+ "/organizations",
256
+ opts
257
+ );
258
+ return r.data;
259
+ }
260
+ };
261
+
262
+ // src/api/v1/index.ts
263
+ var v1 = {
264
+ org: org_default2,
265
+ me: me_default
266
+ };
267
+ var v1_default = v1;
268
+
269
+ // src/ws/types.ts
270
+ var WS_EVENTS = {
271
+ CONNECTION_STATUS: "CONNECTION_STATUS",
272
+ SUBSCRIBED: "SUBSCRIBED",
273
+ ERROR: "ERROR",
274
+ PING: "PING",
275
+ PONG: "PONG",
276
+ UPDATE_ORG: "UPDATE_ORG",
277
+ CREATE_TASK: "CREATE_TASK",
278
+ UPDATE_TASK: "UPDATE_TASK",
279
+ UPDATE_TASK_COMMENTS: "UPDATE_TASK_COMMENTS",
280
+ UPDATE_TASK_VOTE: "UPDATE_TASK_VOTE",
281
+ UPDATE_LABELS: "UPDATE_LABELS",
282
+ UPDATE_VIEWS: "UPDATE_VIEWS",
283
+ UPDATE_CATEGORIES: "UPDATE_CATEGORIES",
284
+ UPDATE_ISSUE_TEMPLATES: "UPDATE_ISSUE_TEMPLATES",
285
+ DISCONNECTED: "DISCONNECTED"
286
+ };
287
+
288
+ // src/ws/index.ts
289
+ function ws(url, handlers = {}) {
290
+ if (!url) {
291
+ throw new Error(
292
+ "[Sayr.ws] WebSocket URL is required. Did you forget to pass org.wsUrl?"
293
+ );
294
+ }
295
+ let socket;
296
+ let retry = 0;
297
+ let closed = false;
298
+ function connect() {
299
+ if (closed) return;
300
+ socket = new WebSocket(url);
301
+ socket.onmessage = (e) => {
302
+ const msg = JSON.parse(e.data);
303
+ if (msg.type === WS_EVENTS.PING) {
304
+ socket.send(JSON.stringify({ type: WS_EVENTS.PONG }));
305
+ return;
306
+ }
307
+ handlers[msg.type]?.(msg.data, msg);
308
+ };
309
+ socket.onclose = () => {
310
+ if (closed) return;
311
+ setTimeout(connect, Math.min(1e3 * 2 ** retry++, 3e4));
312
+ };
313
+ socket.onerror = () => socket.close();
314
+ }
315
+ connect();
316
+ return {
317
+ close() {
318
+ closed = true;
319
+ socket?.close();
320
+ }
321
+ };
322
+ }
323
+
324
+ // src/index.ts
325
+ var SayrClient = {
326
+ setToken,
327
+ setHeaders,
328
+ setBaseUrl,
329
+ resetClient,
330
+ setHooks,
331
+ setFetch
332
+ };
333
+ var Sayr = {
334
+ // client configuration
335
+ client: SayrClient,
336
+ // APIs
337
+ v1: v1_default,
338
+ org: v1_default.org,
339
+ me: v1_default.me,
340
+ // realtime
341
+ ws,
342
+ WS_EVENTS
343
+ };
344
+ var index_default = Sayr;
345
+
346
+ // src/react/useOrg.ts
347
+ function useOrg(slug) {
348
+ const [data, setData] = (0, import_react.useState)(null);
349
+ const [loading, setLoading] = (0, import_react.useState)(false);
350
+ const [error, setError] = (0, import_react.useState)(null);
351
+ (0, import_react.useEffect)(() => {
352
+ if (!slug) return;
353
+ setLoading(true);
354
+ index_default.org.get(slug).then(setData).catch(setError).finally(() => setLoading(false));
355
+ }, [slug]);
356
+ return { data, loading, error };
357
+ }
358
+
359
+ // src/react/useTasks.ts
360
+ var import_react3 = require("react");
361
+
362
+ // src/react/useSayrWS.ts
363
+ var import_react2 = require("react");
364
+ function useSayrWS(wsUrl, handlers) {
365
+ const connRef = (0, import_react2.useRef)(null);
366
+ (0, import_react2.useEffect)(() => {
367
+ if (!wsUrl) return;
368
+ connRef.current = ws(wsUrl, handlers);
369
+ return () => {
370
+ connRef.current?.close();
371
+ connRef.current = null;
372
+ };
373
+ }, [wsUrl]);
374
+ return connRef;
375
+ }
376
+
377
+ // src/react/useTasks.ts
378
+ function useTasks(slug, wsUrl) {
379
+ const [tasks, setTasks] = (0, import_react3.useState)([]);
380
+ const [loading, setLoading] = (0, import_react3.useState)(false);
381
+ function fetchTasks() {
382
+ if (!slug) return;
383
+ setLoading(true);
384
+ index_default.org.tasks.list(slug).then((r) => setTasks(r.data)).finally(() => setLoading(false));
385
+ }
386
+ (0, import_react3.useEffect)(fetchTasks, [slug]);
387
+ useSayrWS(wsUrl, {
388
+ [index_default.WS_EVENTS.CREATE_TASK]: fetchTasks,
389
+ [index_default.WS_EVENTS.UPDATE_TASK]: fetchTasks
390
+ });
391
+ return { tasks, loading, refetch: fetchTasks };
392
+ }
393
+
394
+ // src/react/useTask.ts
395
+ var import_react4 = require("react");
396
+ function useTask(slug, shortId) {
397
+ const [task, setTask] = (0, import_react4.useState)(null);
398
+ const [loading, setLoading] = (0, import_react4.useState)(false);
399
+ (0, import_react4.useEffect)(() => {
400
+ if (!slug || shortId == null) return;
401
+ setLoading(true);
402
+ index_default.org.tasks.get(slug, shortId).then(setTask).finally(() => setLoading(false));
403
+ }, [slug, shortId]);
404
+ return { task, loading };
405
+ }
406
+
407
+ // src/react/useComments.ts
408
+ var import_react5 = require("react");
409
+ function useComments(slug, shortId, wsUrl) {
410
+ const [comments, setComments] = (0, import_react5.useState)([]);
411
+ const [loading, setLoading] = (0, import_react5.useState)(false);
412
+ function fetchComments() {
413
+ if (!slug || shortId == null) return;
414
+ setLoading(true);
415
+ index_default.org.comments.list(slug, shortId).then((r) => setComments(r.data)).finally(() => setLoading(false));
416
+ }
417
+ (0, import_react5.useEffect)(fetchComments, [slug, shortId]);
418
+ useSayrWS(wsUrl, {
419
+ [index_default.WS_EVENTS.UPDATE_TASK_COMMENTS]: fetchComments
420
+ });
421
+ return { comments, loading, refetch: fetchComments };
422
+ }
423
+ // Annotate the CommonJS export names for ESM import in node:
424
+ 0 && (module.exports = {
425
+ useComments,
426
+ useOrg,
427
+ useSayrWS,
428
+ useTask,
429
+ useTasks
430
+ });
431
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/react/index.ts","../../src/react/useOrg.ts","../../src/client/index.ts","../../src/api/v1/org/org.ts","../../src/shared/index.ts","../../src/api/v1/org/tasks.ts","../../src/api/v1/org/comments.ts","../../src/api/v1/org/labels.ts","../../src/api/v1/org/categories.ts","../../src/api/v1/org/index.ts","../../src/api/v1/me/index.ts","../../src/api/v1/index.ts","../../src/ws/types.ts","../../src/ws/index.ts","../../src/index.ts","../../src/react/useTasks.ts","../../src/react/useSayrWS.ts","../../src/react/useTask.ts","../../src/react/useComments.ts"],"sourcesContent":["export { useOrg } from \"./useOrg\";\r\nexport { useTasks } from \"./useTasks\";\r\nexport { useTask } from \"./useTask\";\r\nexport { useComments } from \"./useComments\";\r\nexport { useSayrWS } from \"./useSayrWS\";","import { useEffect, useState } from \"react\";\r\nimport Sayr, { Organization } from \"../index\";\r\n\r\nexport function useOrg(slug?: string) {\r\n const [data, setData] = useState<Organization | null>(null);\r\n const [loading, setLoading] = useState(false);\r\n const [error, setError] = useState<unknown>(null);\r\n\r\n useEffect(() => {\r\n if (!slug) return;\r\n\r\n setLoading(true);\r\n Sayr.org\r\n .get(slug)\r\n .then(setData)\r\n .catch(setError)\r\n .finally(() => setLoading(false));\r\n }, [slug]);\r\n\r\n return { data, loading, error };\r\n}","import { ApiError } from \"../types\";\r\n\r\n/* ────────────────────────────\r\n Types\r\n──────────────────────────── */\r\nexport type RequestOptions = {\r\n method?: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\r\n headers?: Record<string, string>;\r\n body?: Record<string, string>;\r\n signal?: AbortSignal;\r\n};\r\n\r\ntype Hooks = {\r\n onRequest?: (url: string, opts: RequestOptions) => void;\r\n onResponse?: (res: Response) => void;\r\n onError?: (error: ApiError | unknown) => void;\r\n};\r\n\r\ntype ClientConfig = {\r\n token?: string;\r\n headers?: Record<string, string>;\r\n fetch: typeof fetch;\r\n baseUrl: string;\r\n};\r\n\r\n/* ────────────────────────────\r\n Internal state\r\n──────────────────────────── */\r\nconst DEFAULT_API = \"https://api.sayr.io\";\r\n\r\nconst config: ClientConfig = {\r\n fetch: globalThis.fetch,\r\n baseUrl: DEFAULT_API\r\n};\r\n\r\nconst hooks: Hooks = {};\r\n\r\n/* ────────────────────────────\r\n Public config API\r\n──────────────────────────── */\r\nexport function setToken(token?: string) {\r\n config.token = token;\r\n}\r\n\r\nexport function getToken() {\r\n return config.token;\r\n}\r\n\r\nexport function setHeaders(headers?: Record<string, string>) {\r\n config.headers = {\r\n ...config.headers,\r\n ...headers\r\n };\r\n}\r\n\r\nexport function setFetch(fn: typeof fetch) {\r\n config.fetch = fn;\r\n}\r\n\r\nexport function setBaseUrl(url: string) {\r\n config.baseUrl = url.replace(/\\/$/, \"\");\r\n}\r\n\r\nexport function setHooks(h: Hooks) {\r\n Object.assign(hooks, h);\r\n}\r\n\r\nexport function resetClient() {\r\n config.token = undefined;\r\n config.headers = undefined;\r\n config.baseUrl = DEFAULT_API;\r\n}\r\n\r\n/* ────────────────────────────\r\n Request helper\r\n──────────────────────────── */\r\nexport async function request<T>(\r\n path: string,\r\n opts: RequestOptions = {}\r\n): Promise<T> {\r\n const url = path.startsWith(\"http\")\r\n ? path\r\n : `${config.baseUrl}${path}`;\r\n\r\n hooks.onRequest?.(url, opts);\r\n\r\n let res: Response;\r\n\r\n try {\r\n res = await config.fetch(url, {\r\n method: opts.method ?? \"GET\",\r\n headers: {\r\n ...(config.token\r\n ? { Authorization: `Bearer ${config.token}` }\r\n : {}),\r\n ...(opts.body\r\n ? { \"Content-Type\": \"application/json\" }\r\n : {}),\r\n ...config.headers,\r\n ...opts.headers\r\n },\r\n body: opts.body\r\n ? JSON.stringify(opts.body)\r\n : undefined,\r\n signal: opts.signal\r\n });\r\n } catch (err) {\r\n const error: ApiError = {\r\n success: false,\r\n error: \"NETWORK_ERROR\",\r\n message: \"Failed to reach Sayr API\"\r\n };\r\n hooks.onError?.(error);\r\n throw error;\r\n }\r\n\r\n hooks.onResponse?.(res);\r\n\r\n let json: any;\r\n try {\r\n json = await res.json();\r\n } catch {\r\n const error: ApiError = {\r\n success: false,\r\n error: \"INVALID_RESPONSE\",\r\n message: \"Server returned invalid JSON\",\r\n status: res.status\r\n };\r\n hooks.onError?.(error);\r\n throw error;\r\n }\r\n\r\n if (!res.ok || !json.success) {\r\n const error: ApiError = {\r\n ...json,\r\n success: false,\r\n status: res.status\r\n };\r\n hooks.onError?.(error);\r\n throw error;\r\n }\r\n\r\n return json;\r\n}","import { Organization, ApiSuccess } from \"../../../types\";\r\nimport { request, type RequestOptions } from \"../../../client\";\r\n\r\n/**\r\n * Organization core operations.\r\n */\r\nexport default {\r\n /**\r\n * Fetches a public organization by slug.\r\n *\r\n * @since v1.0.0\r\n */\r\n async get(\r\n slug: string,\r\n opts?: RequestOptions\r\n ): Promise<Organization> {\r\n const r = await request<ApiSuccess<Organization>>(\r\n `/v1/organization/${slug}`,\r\n opts\r\n );\r\n return r.data;\r\n }\r\n};","/* =======================\r\n * Shared params & helpers\r\n * ======================= */\r\n\r\nexport type Order = \"asc\" | \"desc\";\r\n\r\nexport interface PaginationParams {\r\n page?: number;\r\n limit?: number;\r\n}\r\n\r\nexport interface OrderedPaginationParams extends PaginationParams {\r\n order?: Order;\r\n}\r\n\r\nexport function buildPaginationParams(\r\n params?: OrderedPaginationParams\r\n): URLSearchParams {\r\n return new URLSearchParams({\r\n order: params?.order ?? \"desc\",\r\n limit: String(params?.limit ?? 5),\r\n page: String(params?.page ?? 1)\r\n });\r\n}","import {\r\n Task,\r\n Pagination,\r\n ApiSuccess\r\n} from \"../../../types\";\r\nimport { request, type RequestOptions } from \"../../../client\";\r\nimport {\r\n type OrderedPaginationParams,\r\n buildPaginationParams\r\n} from \"../../../shared\";\r\n\r\n/**\r\n * Organization tasks.\r\n */\r\nexport default {\r\n /**\r\n * Lists public tasks for an organization.\r\n *\r\n * @since v1.0.0\r\n */\r\n async list(\r\n slug: string,\r\n params?: OrderedPaginationParams,\r\n opts?: RequestOptions\r\n ): Promise<{ data: Task[]; pagination: Pagination }> {\r\n const q = buildPaginationParams(params);\r\n\r\n const r = await request<\r\n ApiSuccess<Task[]> & { pagination: Pagination }\r\n >(\r\n `/v1/organization/${slug}/tasks?${q}`,\r\n opts\r\n );\r\n\r\n return {\r\n data: r.data,\r\n pagination: r.pagination\r\n };\r\n },\r\n\r\n /**\r\n * Fetches a single public task by short ID.\r\n *\r\n * @since v1.0.0\r\n */\r\n async get(\r\n slug: string,\r\n shortId: number,\r\n opts?: RequestOptions\r\n ): Promise<Task> {\r\n const r = await request<ApiSuccess<Task>>(\r\n `/v1/organization/${slug}/tasks/${shortId}`,\r\n opts\r\n );\r\n return r.data;\r\n }\r\n};","import {\r\n Comment,\r\n Pagination,\r\n ApiSuccess\r\n} from \"../../../types\";\r\nimport { request, type RequestOptions } from \"../../../client\";\r\nimport {\r\n type OrderedPaginationParams,\r\n buildPaginationParams\r\n} from \"../../../shared\";\r\n\r\n/**\r\n * Organization task comments.\r\n */\r\nexport default {\r\n /**\r\n * Lists public comments for a task.\r\n *\r\n * @since v1.0.0\r\n */\r\n async list(\r\n slug: string,\r\n shortId: number,\r\n params?: OrderedPaginationParams,\r\n opts?: RequestOptions\r\n ): Promise<{ data: Comment[]; pagination: Pagination }> {\r\n const q = buildPaginationParams(params);\r\n\r\n const r = await request<\r\n ApiSuccess<Comment[]> & { pagination: Pagination }\r\n >(\r\n `/v1/organization/${slug}/tasks/${shortId}/comments?${q}`,\r\n opts\r\n );\r\n\r\n return {\r\n data: r.data,\r\n pagination: r.pagination\r\n };\r\n }\r\n};","import { Label, ApiSuccess } from \"../../../types\";\r\nimport { request, type RequestOptions } from \"../../../client\";\r\n\r\n/**\r\n * Organization labels.\r\n */\r\nexport default {\r\n /**\r\n * Lists public labels for an organization.\r\n *\r\n * @since v1.0.0\r\n */\r\n async list(\r\n slug: string,\r\n opts?: RequestOptions\r\n ): Promise<Label[]> {\r\n const r = await request<ApiSuccess<Label[]>>(\r\n `/v1/organization/${slug}/labels`,\r\n opts\r\n );\r\n return r.data;\r\n }\r\n};","import {\r\n Category,\r\n ApiSuccess\r\n} from \"../../../types\";\r\nimport { request, type RequestOptions } from \"../../../client\";\r\nimport { type Order } from \"../../../shared\";\r\n\r\n/**\r\n * Organization categories.\r\n */\r\nexport default {\r\n /**\r\n * Lists public categories for an organization.\r\n *\r\n * @since v1.0.0\r\n */\r\n async list(\r\n slug: string,\r\n order: Order = \"desc\",\r\n opts?: RequestOptions\r\n ): Promise<Category[]> {\r\n const r = await request<ApiSuccess<Category[]>>(\r\n `/v1/organization/${slug}/categories?order=${order}`,\r\n opts\r\n );\r\n return r.data;\r\n }\r\n};","import org from \"./org\";\r\nimport tasks from \"./tasks\";\r\nimport comments from \"./comments\";\r\nimport labels from \"./labels\";\r\nimport categories from \"./categories\";\r\n\r\n/**\r\n * Public Sayr Organization API — Version 1.\r\n *\r\n * @since v1.0.0\r\n */\r\nconst OrgAPI = {\r\n ...org,\r\n tasks,\r\n comments,\r\n labels,\r\n categories\r\n};\r\n\r\nexport default OrgAPI;","import { request, type RequestOptions } from \"../../../client\";\r\nimport { ApiSuccess, Organization } from \"../../../types\";\r\n\r\nexport interface Me {\r\n id: string;\r\n name: string | null;\r\n email: string | null;\r\n image: string | null;\r\n createdAt: string;\r\n}\r\n\r\n/**\r\n * Authenticated user API — Version 1.\r\n *\r\n * @since v1.0.0\r\n */\r\nexport default {\r\n /**\r\n * Fetches the currently authenticated user.\r\n *\r\n * @since v1.0.0\r\n */\r\n async get(opts?: RequestOptions): Promise<Me> {\r\n const r = await request<ApiSuccess<Me>>(\r\n \"/me\",\r\n opts\r\n );\r\n return r.data;\r\n },\r\n\r\n /**\r\n * Lists organizations the current user belongs to.\r\n *\r\n * @since v1.0.0\r\n */\r\n async organizations(\r\n opts?: RequestOptions\r\n ): Promise<Organization[]> {\r\n const r = await request<ApiSuccess<Organization[]>>(\r\n \"/organizations\",\r\n opts\r\n );\r\n return r.data;\r\n }\r\n};","import org from \"./org\";\r\nimport me from \"./me\";\r\nexport const v1 = {\r\n org,\r\n me\r\n};\r\n\r\nexport default v1;","export type WSMessageType =\r\n | \"CONNECTION_STATUS\"\r\n | \"SUBSCRIBED\"\r\n | \"ERROR\"\r\n | \"PING\"\r\n | \"PONG\"\r\n | \"UPDATE_ORG\"\r\n | \"CREATE_TASK\"\r\n | \"UPDATE_TASK\"\r\n | \"UPDATE_TASK_COMMENTS\"\r\n | \"UPDATE_TASK_VOTE\"\r\n | \"UPDATE_LABELS\"\r\n | \"UPDATE_VIEWS\"\r\n | \"UPDATE_CATEGORIES\"\r\n | \"UPDATE_ISSUE_TEMPLATES\"\r\n | \"DISCONNECTED\";\r\n\r\n/**\r\n * String enum replacement for WS event names.\r\n * Use this instead of raw strings.\r\n */\r\nexport const WS_EVENTS: Record<WSMessageType, WSMessageType> = {\r\n CONNECTION_STATUS: \"CONNECTION_STATUS\",\r\n SUBSCRIBED: \"SUBSCRIBED\",\r\n ERROR: \"ERROR\",\r\n PING: \"PING\",\r\n PONG: \"PONG\",\r\n UPDATE_ORG: \"UPDATE_ORG\",\r\n CREATE_TASK: \"CREATE_TASK\",\r\n UPDATE_TASK: \"UPDATE_TASK\",\r\n UPDATE_TASK_COMMENTS: \"UPDATE_TASK_COMMENTS\",\r\n UPDATE_TASK_VOTE: \"UPDATE_TASK_VOTE\",\r\n UPDATE_LABELS: \"UPDATE_LABELS\",\r\n UPDATE_VIEWS: \"UPDATE_VIEWS\",\r\n UPDATE_CATEGORIES: \"UPDATE_CATEGORIES\",\r\n UPDATE_ISSUE_TEMPLATES: \"UPDATE_ISSUE_TEMPLATES\",\r\n DISCONNECTED: \"DISCONNECTED\"\r\n};\r\n\r\nexport interface WSMessage<T = unknown> {\r\n type: WSMessageType;\r\n scope: \"PUBLIC\";\r\n data: T;\r\n meta?: { ts: number };\r\n}","import { WS_EVENTS, type WSMessage, type WSMessageType } from \"./types\";\r\n\r\ntype Handlers = Partial<\r\n Record<WSMessageType, (data: any, msg: WSMessage) => void>\r\n>;\r\n\r\nexport function ws(url: string, handlers: Handlers = {}) {\r\n if (!url) {\r\n throw new Error(\r\n \"[Sayr.ws] WebSocket URL is required. \" +\r\n \"Did you forget to pass org.wsUrl?\"\r\n );\r\n }\r\n let socket: WebSocket;\r\n let retry = 0;\r\n let closed = false;\r\n\r\n function connect() {\r\n if (closed) return;\r\n\r\n socket = new WebSocket(url);\r\n\r\n socket.onmessage = (e) => {\r\n const msg = JSON.parse(e.data) as WSMessage;\r\n\r\n if (msg.type === WS_EVENTS.PING) {\r\n socket.send(JSON.stringify({ type: WS_EVENTS.PONG }));\r\n return;\r\n }\r\n\r\n handlers[msg.type]?.(msg.data, msg);\r\n };\r\n\r\n socket.onclose = () => {\r\n if (closed) return;\r\n setTimeout(connect, Math.min(1000 * 2 ** retry++, 30000));\r\n };\r\n\r\n socket.onerror = () => socket.close();\r\n }\r\n\r\n connect();\r\n\r\n return {\r\n close() {\r\n closed = true;\r\n socket?.close();\r\n }\r\n };\r\n}","/* ────────────────────────────\r\n API versions\r\n──────────────────────────── */\r\nimport v1 from \"./api/v1\";\r\n\r\n/* ────────────────────────────\r\n Realtime\r\n──────────────────────────── */\r\nimport { ws } from \"./ws\";\r\nimport { WS_EVENTS } from \"./ws/types\";\r\n\r\n/* ────────────────────────────\r\n Client config\r\n──────────────────────────── */\r\nimport {\r\n setToken,\r\n setHeaders,\r\n setBaseUrl,\r\n resetClient,\r\n setHooks,\r\n setFetch\r\n} from \"./client\";\r\n\r\n/* ────────────────────────────\r\n Named exports (power users)\r\n──────────────────────────── */\r\n\r\n/**\r\n * Sayr Public API — Version 1.\r\n *\r\n * @since v1.0.0\r\n */\r\nexport const SayrV1 = v1;\r\n\r\n\r\n/**\r\n * Create a WebSocket connection for public real‑time updates.\r\n */\r\nexport const SayrWS = ws;\r\n\r\n/**\r\n * Typed WebSocket event constants.\r\n */\r\nexport const SayrWSEvents = WS_EVENTS;\r\n\r\n/**\r\n * Global client configuration helpers.\r\n */\r\nexport const SayrClient = {\r\n setToken,\r\n setHeaders,\r\n setBaseUrl,\r\n resetClient,\r\n setHooks,\r\n setFetch\r\n};\r\n\r\n/* ────────────────────────────\r\n Default facade\r\n──────────────────────────── */\r\n\r\n/**\r\n * Sayr Public SDK.\r\n *\r\n * Read‑only access to public Sayr data via REST and WebSockets.\r\n *\r\n * @since v1.0.0\r\n */\r\nconst Sayr: {\r\n /**\r\n * Client configuration helpers.\r\n */\r\n client: typeof SayrClient;\r\n\r\n /**\r\n * Versioned API namespaces.\r\n */\r\n v1: typeof v1;\r\n\r\n /**\r\n * Alias for the current API version (`v1`).\r\n *\r\n * @since v1.0.0\r\n */\r\n org: typeof v1.org;\r\n me: typeof v1.me;\r\n\r\n /**\r\n * WebSocket helper for real‑time updates.\r\n */\r\n ws: typeof ws;\r\n\r\n /**\r\n * WebSocket event constants.\r\n */\r\n WS_EVENTS: typeof WS_EVENTS;\r\n} = {\r\n // client configuration\r\n client: SayrClient,\r\n\r\n // APIs\r\n v1,\r\n org: v1.org,\r\n me: v1.me,\r\n\r\n // realtime\r\n ws,\r\n WS_EVENTS\r\n};\r\n\r\nexport default Sayr;\r\n\r\n/* ────────────────────────────\r\n Types & shared helpers\r\n──────────────────────────── */\r\nexport * from \"./types\";\r\nexport * from \"./shared\";\r\nexport * from \"./ws/types\";","import { useEffect, useState } from \"react\";\r\nimport type { Task } from \"../types\";\r\nimport { useSayrWS } from \"./useSayrWS\";\r\nimport Sayr from \"..\";\r\nexport function useTasks(\r\n slug?: string,\r\n wsUrl?: string\r\n) {\r\n const [tasks, setTasks] = useState<Task[]>([]);\r\n const [loading, setLoading] = useState(false);\r\n\r\n function fetchTasks() {\r\n if (!slug) return;\r\n setLoading(true);\r\n Sayr.org.tasks.list(slug)\r\n .then((r) => setTasks(r.data))\r\n .finally(() => setLoading(false));\r\n }\r\n\r\n useEffect(fetchTasks, [slug]);\r\n\r\n useSayrWS(wsUrl, {\r\n [Sayr.WS_EVENTS.CREATE_TASK]: fetchTasks,\r\n [Sayr.WS_EVENTS.UPDATE_TASK]: fetchTasks\r\n });\r\n\r\n return { tasks, loading, refetch: fetchTasks };\r\n}","import { useEffect, useRef } from \"react\";\r\nimport { WSMessageType } from \"../ws/types\";\r\nimport { ws } from \"../ws\";\r\n\r\ntype Handlers = Partial<\r\n Record<WSMessageType, (data: any, msg: any) => void>\r\n>;\r\n\r\nexport function useSayrWS(\r\n wsUrl?: string,\r\n handlers?: Handlers\r\n) {\r\n const connRef = useRef<ReturnType<typeof ws> | null>(null);\r\n\r\n useEffect(() => {\r\n if (!wsUrl) return;\r\n\r\n connRef.current = ws(wsUrl, handlers);\r\n\r\n return () => {\r\n connRef.current?.close();\r\n connRef.current = null;\r\n };\r\n }, [wsUrl]);\r\n\r\n return connRef;\r\n}","import { useEffect, useState } from \"react\";\r\nimport type { Task } from \"../types\";\r\nimport Sayr from \"..\";\r\n\r\nexport function useTask(\r\n slug?: string,\r\n shortId?: number\r\n) {\r\n const [task, setTask] = useState<Task | null>(null);\r\n const [loading, setLoading] = useState(false);\r\n\r\n useEffect(() => {\r\n if (!slug || shortId == null) return;\r\n\r\n setLoading(true);\r\n Sayr.org.tasks.get(slug, shortId)\r\n .then(setTask)\r\n .finally(() => setLoading(false));\r\n }, [slug, shortId]);\r\n\r\n return { task, loading };\r\n}","import { useEffect, useState } from \"react\";\r\nimport type { Comment } from \"../types\";\r\nimport { useSayrWS } from \"./useSayrWS\";\r\nimport Sayr from \"..\";\r\n\r\nexport function useComments(\r\n slug?: string,\r\n shortId?: number,\r\n wsUrl?: string\r\n) {\r\n const [comments, setComments] = useState<Comment[]>([]);\r\n const [loading, setLoading] = useState(false);\r\n\r\n function fetchComments() {\r\n if (!slug || shortId == null) return;\r\n\r\n setLoading(true);\r\n Sayr.org.comments.list(slug, shortId)\r\n .then((r) => setComments(r.data))\r\n .finally(() => setLoading(false));\r\n }\r\n\r\n useEffect(fetchComments, [slug, shortId]);\r\n\r\n useSayrWS(wsUrl, {\r\n [Sayr.WS_EVENTS.UPDATE_TASK_COMMENTS]: fetchComments\r\n });\r\n\r\n return { comments, loading, refetch: fetchComments };\r\n}"],"mappings":"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","names":["org_default","org_default","import_react","import_react","import_react","import_react"]}
@@ -0,0 +1,88 @@
1
+ import * as react from 'react';
2
+
3
+ interface Organization {
4
+ id: string;
5
+ name: string;
6
+ slug: string;
7
+ logo: string | null;
8
+ bannerImg: string | null;
9
+ description: string;
10
+ createdAt: string;
11
+ updatedAt: string;
12
+ wsUrl: string;
13
+ }
14
+ type TaskStatus = "backlog" | "todo" | "in-progress" | "done" | "canceled";
15
+ type TaskPriority = "none" | "low" | "medium" | "high" | "urgent";
16
+ interface Task {
17
+ id: string;
18
+ organizationId: string;
19
+ shortId: number | null;
20
+ visible: "public" | "private";
21
+ createdAt: string;
22
+ updatedAt: string;
23
+ title: string | null;
24
+ description: unknown | null;
25
+ status: TaskStatus;
26
+ priority: TaskPriority;
27
+ createdBy: string | null;
28
+ category: string | null;
29
+ voteCount: number;
30
+ descriptionHtml: string;
31
+ descriptionMarkdown: string;
32
+ }
33
+ interface CommentUser {
34
+ name: string | null;
35
+ image: string | null;
36
+ }
37
+ interface CommentReaction {
38
+ count: number;
39
+ users: string[];
40
+ }
41
+ interface Comment {
42
+ id: string;
43
+ organizationId: string;
44
+ taskId: string | null;
45
+ createdAt: string;
46
+ updatedAt: string;
47
+ content: unknown | null;
48
+ visibility: "public" | "internal";
49
+ contentHtml: string;
50
+ contentMarkdown: string;
51
+ createdBy: CommentUser | null;
52
+ reactions?: {
53
+ total: number;
54
+ reactions: Record<string, CommentReaction>;
55
+ };
56
+ }
57
+
58
+ type WSMessageType = "CONNECTION_STATUS" | "SUBSCRIBED" | "ERROR" | "PING" | "PONG" | "UPDATE_ORG" | "CREATE_TASK" | "UPDATE_TASK" | "UPDATE_TASK_COMMENTS" | "UPDATE_TASK_VOTE" | "UPDATE_LABELS" | "UPDATE_VIEWS" | "UPDATE_CATEGORIES" | "UPDATE_ISSUE_TEMPLATES" | "DISCONNECTED";
59
+
60
+ declare function useOrg(slug?: string): {
61
+ data: Organization | null;
62
+ loading: boolean;
63
+ error: unknown;
64
+ };
65
+
66
+ declare function useTasks(slug?: string, wsUrl?: string): {
67
+ tasks: Task[];
68
+ loading: boolean;
69
+ refetch: () => void;
70
+ };
71
+
72
+ declare function useTask(slug?: string, shortId?: number): {
73
+ task: Task | null;
74
+ loading: boolean;
75
+ };
76
+
77
+ declare function useComments(slug?: string, shortId?: number, wsUrl?: string): {
78
+ comments: Comment[];
79
+ loading: boolean;
80
+ refetch: () => void;
81
+ };
82
+
83
+ type Handlers = Partial<Record<WSMessageType, (data: any, msg: any) => void>>;
84
+ declare function useSayrWS(wsUrl?: string, handlers?: Handlers): react.RefObject<{
85
+ close(): void;
86
+ } | null>;
87
+
88
+ export { useComments, useOrg, useSayrWS, useTask, useTasks };
@@ -0,0 +1,88 @@
1
+ import * as react from 'react';
2
+
3
+ interface Organization {
4
+ id: string;
5
+ name: string;
6
+ slug: string;
7
+ logo: string | null;
8
+ bannerImg: string | null;
9
+ description: string;
10
+ createdAt: string;
11
+ updatedAt: string;
12
+ wsUrl: string;
13
+ }
14
+ type TaskStatus = "backlog" | "todo" | "in-progress" | "done" | "canceled";
15
+ type TaskPriority = "none" | "low" | "medium" | "high" | "urgent";
16
+ interface Task {
17
+ id: string;
18
+ organizationId: string;
19
+ shortId: number | null;
20
+ visible: "public" | "private";
21
+ createdAt: string;
22
+ updatedAt: string;
23
+ title: string | null;
24
+ description: unknown | null;
25
+ status: TaskStatus;
26
+ priority: TaskPriority;
27
+ createdBy: string | null;
28
+ category: string | null;
29
+ voteCount: number;
30
+ descriptionHtml: string;
31
+ descriptionMarkdown: string;
32
+ }
33
+ interface CommentUser {
34
+ name: string | null;
35
+ image: string | null;
36
+ }
37
+ interface CommentReaction {
38
+ count: number;
39
+ users: string[];
40
+ }
41
+ interface Comment {
42
+ id: string;
43
+ organizationId: string;
44
+ taskId: string | null;
45
+ createdAt: string;
46
+ updatedAt: string;
47
+ content: unknown | null;
48
+ visibility: "public" | "internal";
49
+ contentHtml: string;
50
+ contentMarkdown: string;
51
+ createdBy: CommentUser | null;
52
+ reactions?: {
53
+ total: number;
54
+ reactions: Record<string, CommentReaction>;
55
+ };
56
+ }
57
+
58
+ type WSMessageType = "CONNECTION_STATUS" | "SUBSCRIBED" | "ERROR" | "PING" | "PONG" | "UPDATE_ORG" | "CREATE_TASK" | "UPDATE_TASK" | "UPDATE_TASK_COMMENTS" | "UPDATE_TASK_VOTE" | "UPDATE_LABELS" | "UPDATE_VIEWS" | "UPDATE_CATEGORIES" | "UPDATE_ISSUE_TEMPLATES" | "DISCONNECTED";
59
+
60
+ declare function useOrg(slug?: string): {
61
+ data: Organization | null;
62
+ loading: boolean;
63
+ error: unknown;
64
+ };
65
+
66
+ declare function useTasks(slug?: string, wsUrl?: string): {
67
+ tasks: Task[];
68
+ loading: boolean;
69
+ refetch: () => void;
70
+ };
71
+
72
+ declare function useTask(slug?: string, shortId?: number): {
73
+ task: Task | null;
74
+ loading: boolean;
75
+ };
76
+
77
+ declare function useComments(slug?: string, shortId?: number, wsUrl?: string): {
78
+ comments: Comment[];
79
+ loading: boolean;
80
+ refetch: () => void;
81
+ };
82
+
83
+ type Handlers = Partial<Record<WSMessageType, (data: any, msg: any) => void>>;
84
+ declare function useSayrWS(wsUrl?: string, handlers?: Handlers): react.RefObject<{
85
+ close(): void;
86
+ } | null>;
87
+
88
+ export { useComments, useOrg, useSayrWS, useTask, useTasks };