@sayrio/public 0.1.2 → 0.1.3
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 +1 -79
- package/dist/index.cjs +5 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +5 -0
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.js +5 -0
- package/dist/react/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -190,82 +190,4 @@ This package ships with full TypeScript definitions.
|
|
|
190
190
|
|
|
191
191
|
```ts
|
|
192
192
|
import type { Organization, Task } from "@sayrio/public";
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
---
|
|
196
|
-
|
|
197
|
-
## Basic HTML Example
|
|
198
|
-
|
|
199
|
-
This example shows how to use `@sayrio/public` in a **plain HTML file** with no
|
|
200
|
-
build tools.
|
|
201
|
-
|
|
202
|
-
> **Important:**
|
|
203
|
-
> This SDK is published as an **ES module**, so you must use
|
|
204
|
-
> `type="module"` and `import`.
|
|
205
|
-
> It does **not** create a global `Sayr` variable.
|
|
206
|
-
|
|
207
|
-
```html
|
|
208
|
-
<!DOCTYPE html>
|
|
209
|
-
<html lang="en">
|
|
210
|
-
<head>
|
|
211
|
-
<meta charset="utf-8" />
|
|
212
|
-
<title>Sayr Public SDK – HTML Example</title>
|
|
213
|
-
<style>
|
|
214
|
-
body {
|
|
215
|
-
background: #0b0b0b;
|
|
216
|
-
color: #e5e7eb;
|
|
217
|
-
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
218
|
-
padding: 24px;
|
|
219
|
-
}
|
|
220
|
-
</style>
|
|
221
|
-
</head>
|
|
222
|
-
|
|
223
|
-
<body>
|
|
224
|
-
<h1>Sayr Public SDK</h1>
|
|
225
|
-
<pre id="out">Loading…</pre>
|
|
226
|
-
|
|
227
|
-
<script type="module">
|
|
228
|
-
import Sayr from "https://esm.sh/@sayrio/public";
|
|
229
|
-
|
|
230
|
-
const out = document.getElementById("out");
|
|
231
|
-
|
|
232
|
-
function log(label, value) {
|
|
233
|
-
out.textContent +=
|
|
234
|
-
label + ": " + JSON.stringify(value, null, 2) + "\n\n";
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
const slug = "org";
|
|
238
|
-
|
|
239
|
-
// Fetch public organization
|
|
240
|
-
const org = await Sayr.org.get(slug);
|
|
241
|
-
log("Organization", org);
|
|
242
|
-
|
|
243
|
-
// Connect to public WebSocket
|
|
244
|
-
Sayr.ws(org.wsUrl, {
|
|
245
|
-
[Sayr.wsTypes.UPDATE_ORG]: (data) => {
|
|
246
|
-
log("Org updated", data);
|
|
247
|
-
},
|
|
248
|
-
|
|
249
|
-
[Sayr.wsTypes.UPDATE_TASK]: (task) => {
|
|
250
|
-
log("Task updated", task);
|
|
251
|
-
},
|
|
252
|
-
|
|
253
|
-
[Sayr.wsTypes.ERROR]: (err) => {
|
|
254
|
-
log("WebSocket error", err);
|
|
255
|
-
}
|
|
256
|
-
});
|
|
257
|
-
</script>
|
|
258
|
-
</body>
|
|
259
|
-
</html>
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
---
|
|
263
|
-
|
|
264
|
-
## Notes on Browser Usage
|
|
265
|
-
|
|
266
|
-
- This package **does not expose a global `Sayr`**
|
|
267
|
-
- Always use `type="module"` and `import`
|
|
268
|
-
- For legacy `<script>` usage, a UMD build is not currently provided
|
|
269
|
-
- `esm.sh` is recommended for CDN usage
|
|
270
|
-
|
|
271
|
-
---
|
|
193
|
+
```
|
package/dist/index.cjs
CHANGED
|
@@ -113,6 +113,11 @@ var wsTypes = {
|
|
|
113
113
|
DISCONNECTED: "DISCONNECTED"
|
|
114
114
|
};
|
|
115
115
|
function ws(url, handlers = {}) {
|
|
116
|
+
if (!url) {
|
|
117
|
+
throw new Error(
|
|
118
|
+
"[Sayr.ws] WebSocket URL is required. Did you forget to pass org.wsUrl?"
|
|
119
|
+
);
|
|
120
|
+
}
|
|
116
121
|
let socket;
|
|
117
122
|
let retry = 0;
|
|
118
123
|
let closed = false;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/org.ts","../src/ws.ts"],"sourcesContent":["import { org } from \"./org\";\r\nimport { ws, wsTypes } from \"./ws\";\r\n\r\nconst Sayr = { org, ws, wsTypes };\r\n\r\nexport default Sayr;\r\nexport { org, ws, wsTypes };\r\nexport * from \"./types\";","import {\r\n Organization,\r\n Label,\r\n Category,\r\n Task,\r\n Comment,\r\n Pagination,\r\n ApiSuccess\r\n} from \"./types\";\r\n\r\nconst API = \"https://sayr.io/api/public\";\r\n\r\nasync function get<T>(url: string): Promise<T> {\r\n const res = await fetch(url);\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n return json;\r\n}\r\n\r\nexport const org = {\r\n async get(slug: string): Promise<Organization> {\r\n const r = await get<ApiSuccess<Organization>>(\r\n `${API}/organization/${slug}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async labels(slug: string): Promise<Label[]> {\r\n const r = await get<ApiSuccess<Label[]>>(\r\n `${API}/organization/${slug}/labels`\r\n );\r\n return r.data;\r\n },\r\n\r\n async categories(\r\n slug: string,\r\n order: \"asc\" | \"desc\" = \"desc\"\r\n ): Promise<Category[]> {\r\n const r = await get<ApiSuccess<Category[]>>(\r\n `${API}/organization/${slug}/categories?order=${order}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async tasks(\r\n slug: string,\r\n opts?: { order?: \"asc\" | \"desc\"; limit?: number; page?: number }\r\n ): Promise<{ data: Task[]; pagination: Pagination }> {\r\n const q = new URLSearchParams({\r\n order: opts?.order ?? \"desc\",\r\n limit: String(opts?.limit ?? 5),\r\n page: String(opts?.page ?? 1)\r\n });\r\n\r\n const res = await fetch(\r\n `${API}/organization/${slug}/tasks?${q}`\r\n );\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n\r\n return {\r\n data: json.data,\r\n pagination: json.pagination\r\n };\r\n },\r\n\r\n async task(slug: string, shortId: number): Promise<Task> {\r\n const r = await get<ApiSuccess<Task>>(\r\n `${API}/organization/${slug}/tasks/${shortId}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async comments(\r\n slug: string,\r\n shortId: number,\r\n opts?: { order?: \"asc\" | \"desc\"; limit?: number; page?: number }\r\n ): Promise<{ data: Comment[]; pagination: Pagination }> {\r\n const q = new URLSearchParams({\r\n order: opts?.order ?? \"desc\",\r\n limit: String(opts?.limit ?? 5),\r\n page: String(opts?.page ?? 1)\r\n });\r\n\r\n const res = await fetch(\r\n `${API}/organization/${slug}/tasks/${shortId}/comments?${q}`\r\n );\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n\r\n return {\r\n data: json.data,\r\n pagination: json.pagination\r\n };\r\n }\r\n};","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\nexport const wsTypes: 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}\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 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 === wsTypes.PING) {\r\n socket.send(JSON.stringify({ type: wsTypes.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}"],"mappings":"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
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/org.ts","../src/ws.ts"],"sourcesContent":["import { org } from \"./org\";\r\nimport { ws, wsTypes } from \"./ws\";\r\n\r\nconst Sayr = { org, ws, wsTypes };\r\n\r\nexport default Sayr;\r\nexport { org, ws, wsTypes };\r\nexport * from \"./types\";","import {\r\n Organization,\r\n Label,\r\n Category,\r\n Task,\r\n Comment,\r\n Pagination,\r\n ApiSuccess\r\n} from \"./types\";\r\n\r\nconst API = \"https://sayr.io/api/public\";\r\n\r\nasync function get<T>(url: string): Promise<T> {\r\n const res = await fetch(url);\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n return json;\r\n}\r\n\r\nexport const org = {\r\n async get(slug: string): Promise<Organization> {\r\n const r = await get<ApiSuccess<Organization>>(\r\n `${API}/organization/${slug}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async labels(slug: string): Promise<Label[]> {\r\n const r = await get<ApiSuccess<Label[]>>(\r\n `${API}/organization/${slug}/labels`\r\n );\r\n return r.data;\r\n },\r\n\r\n async categories(\r\n slug: string,\r\n order: \"asc\" | \"desc\" = \"desc\"\r\n ): Promise<Category[]> {\r\n const r = await get<ApiSuccess<Category[]>>(\r\n `${API}/organization/${slug}/categories?order=${order}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async tasks(\r\n slug: string,\r\n opts?: { order?: \"asc\" | \"desc\"; limit?: number; page?: number }\r\n ): Promise<{ data: Task[]; pagination: Pagination }> {\r\n const q = new URLSearchParams({\r\n order: opts?.order ?? \"desc\",\r\n limit: String(opts?.limit ?? 5),\r\n page: String(opts?.page ?? 1)\r\n });\r\n\r\n const res = await fetch(\r\n `${API}/organization/${slug}/tasks?${q}`\r\n );\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n\r\n return {\r\n data: json.data,\r\n pagination: json.pagination\r\n };\r\n },\r\n\r\n async task(slug: string, shortId: number): Promise<Task> {\r\n const r = await get<ApiSuccess<Task>>(\r\n `${API}/organization/${slug}/tasks/${shortId}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async comments(\r\n slug: string,\r\n shortId: number,\r\n opts?: { order?: \"asc\" | \"desc\"; limit?: number; page?: number }\r\n ): Promise<{ data: Comment[]; pagination: Pagination }> {\r\n const q = new URLSearchParams({\r\n order: opts?.order ?? \"desc\",\r\n limit: String(opts?.limit ?? 5),\r\n page: String(opts?.page ?? 1)\r\n });\r\n\r\n const res = await fetch(\r\n `${API}/organization/${slug}/tasks/${shortId}/comments?${q}`\r\n );\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n\r\n return {\r\n data: json.data,\r\n pagination: json.pagination\r\n };\r\n }\r\n};","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\nexport const wsTypes: 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}\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 === wsTypes.PING) {\r\n socket.send(JSON.stringify({ type: wsTypes.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}"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -84,6 +84,11 @@ var wsTypes = {
|
|
|
84
84
|
DISCONNECTED: "DISCONNECTED"
|
|
85
85
|
};
|
|
86
86
|
function ws(url, handlers = {}) {
|
|
87
|
+
if (!url) {
|
|
88
|
+
throw new Error(
|
|
89
|
+
"[Sayr.ws] WebSocket URL is required. Did you forget to pass org.wsUrl?"
|
|
90
|
+
);
|
|
91
|
+
}
|
|
87
92
|
let socket;
|
|
88
93
|
let retry = 0;
|
|
89
94
|
let closed = false;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/org.ts","../src/ws.ts","../src/index.ts"],"sourcesContent":["import {\r\n Organization,\r\n Label,\r\n Category,\r\n Task,\r\n Comment,\r\n Pagination,\r\n ApiSuccess\r\n} from \"./types\";\r\n\r\nconst API = \"https://sayr.io/api/public\";\r\n\r\nasync function get<T>(url: string): Promise<T> {\r\n const res = await fetch(url);\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n return json;\r\n}\r\n\r\nexport const org = {\r\n async get(slug: string): Promise<Organization> {\r\n const r = await get<ApiSuccess<Organization>>(\r\n `${API}/organization/${slug}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async labels(slug: string): Promise<Label[]> {\r\n const r = await get<ApiSuccess<Label[]>>(\r\n `${API}/organization/${slug}/labels`\r\n );\r\n return r.data;\r\n },\r\n\r\n async categories(\r\n slug: string,\r\n order: \"asc\" | \"desc\" = \"desc\"\r\n ): Promise<Category[]> {\r\n const r = await get<ApiSuccess<Category[]>>(\r\n `${API}/organization/${slug}/categories?order=${order}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async tasks(\r\n slug: string,\r\n opts?: { order?: \"asc\" | \"desc\"; limit?: number; page?: number }\r\n ): Promise<{ data: Task[]; pagination: Pagination }> {\r\n const q = new URLSearchParams({\r\n order: opts?.order ?? \"desc\",\r\n limit: String(opts?.limit ?? 5),\r\n page: String(opts?.page ?? 1)\r\n });\r\n\r\n const res = await fetch(\r\n `${API}/organization/${slug}/tasks?${q}`\r\n );\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n\r\n return {\r\n data: json.data,\r\n pagination: json.pagination\r\n };\r\n },\r\n\r\n async task(slug: string, shortId: number): Promise<Task> {\r\n const r = await get<ApiSuccess<Task>>(\r\n `${API}/organization/${slug}/tasks/${shortId}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async comments(\r\n slug: string,\r\n shortId: number,\r\n opts?: { order?: \"asc\" | \"desc\"; limit?: number; page?: number }\r\n ): Promise<{ data: Comment[]; pagination: Pagination }> {\r\n const q = new URLSearchParams({\r\n order: opts?.order ?? \"desc\",\r\n limit: String(opts?.limit ?? 5),\r\n page: String(opts?.page ?? 1)\r\n });\r\n\r\n const res = await fetch(\r\n `${API}/organization/${slug}/tasks/${shortId}/comments?${q}`\r\n );\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n\r\n return {\r\n data: json.data,\r\n pagination: json.pagination\r\n };\r\n }\r\n};","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\nexport const wsTypes: 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}\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 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 === wsTypes.PING) {\r\n socket.send(JSON.stringify({ type: wsTypes.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}","import { org } from \"./org\";\r\nimport { ws, wsTypes } from \"./ws\";\r\n\r\nconst Sayr = { org, ws, wsTypes };\r\n\r\nexport default Sayr;\r\nexport { org, ws, wsTypes };\r\nexport * from \"./types\";"],"mappings":"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
|
|
1
|
+
{"version":3,"sources":["../src/org.ts","../src/ws.ts","../src/index.ts"],"sourcesContent":["import {\r\n Organization,\r\n Label,\r\n Category,\r\n Task,\r\n Comment,\r\n Pagination,\r\n ApiSuccess\r\n} from \"./types\";\r\n\r\nconst API = \"https://sayr.io/api/public\";\r\n\r\nasync function get<T>(url: string): Promise<T> {\r\n const res = await fetch(url);\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n return json;\r\n}\r\n\r\nexport const org = {\r\n async get(slug: string): Promise<Organization> {\r\n const r = await get<ApiSuccess<Organization>>(\r\n `${API}/organization/${slug}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async labels(slug: string): Promise<Label[]> {\r\n const r = await get<ApiSuccess<Label[]>>(\r\n `${API}/organization/${slug}/labels`\r\n );\r\n return r.data;\r\n },\r\n\r\n async categories(\r\n slug: string,\r\n order: \"asc\" | \"desc\" = \"desc\"\r\n ): Promise<Category[]> {\r\n const r = await get<ApiSuccess<Category[]>>(\r\n `${API}/organization/${slug}/categories?order=${order}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async tasks(\r\n slug: string,\r\n opts?: { order?: \"asc\" | \"desc\"; limit?: number; page?: number }\r\n ): Promise<{ data: Task[]; pagination: Pagination }> {\r\n const q = new URLSearchParams({\r\n order: opts?.order ?? \"desc\",\r\n limit: String(opts?.limit ?? 5),\r\n page: String(opts?.page ?? 1)\r\n });\r\n\r\n const res = await fetch(\r\n `${API}/organization/${slug}/tasks?${q}`\r\n );\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n\r\n return {\r\n data: json.data,\r\n pagination: json.pagination\r\n };\r\n },\r\n\r\n async task(slug: string, shortId: number): Promise<Task> {\r\n const r = await get<ApiSuccess<Task>>(\r\n `${API}/organization/${slug}/tasks/${shortId}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async comments(\r\n slug: string,\r\n shortId: number,\r\n opts?: { order?: \"asc\" | \"desc\"; limit?: number; page?: number }\r\n ): Promise<{ data: Comment[]; pagination: Pagination }> {\r\n const q = new URLSearchParams({\r\n order: opts?.order ?? \"desc\",\r\n limit: String(opts?.limit ?? 5),\r\n page: String(opts?.page ?? 1)\r\n });\r\n\r\n const res = await fetch(\r\n `${API}/organization/${slug}/tasks/${shortId}/comments?${q}`\r\n );\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n\r\n return {\r\n data: json.data,\r\n pagination: json.pagination\r\n };\r\n }\r\n};","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\nexport const wsTypes: 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}\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 === wsTypes.PING) {\r\n socket.send(JSON.stringify({ type: wsTypes.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}","import { org } from \"./org\";\r\nimport { ws, wsTypes } from \"./ws\";\r\n\r\nconst Sayr = { org, ws, wsTypes };\r\n\r\nexport default Sayr;\r\nexport { org, ws, wsTypes };\r\nexport * from \"./types\";"],"mappings":"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","names":[]}
|
package/dist/react/index.cjs
CHANGED
|
@@ -117,6 +117,11 @@ var wsTypes = {
|
|
|
117
117
|
DISCONNECTED: "DISCONNECTED"
|
|
118
118
|
};
|
|
119
119
|
function ws(url, handlers = {}) {
|
|
120
|
+
if (!url) {
|
|
121
|
+
throw new Error(
|
|
122
|
+
"[Sayr.ws] WebSocket URL is required. Did you forget to pass org.wsUrl?"
|
|
123
|
+
);
|
|
124
|
+
}
|
|
120
125
|
let socket;
|
|
121
126
|
let retry = 0;
|
|
122
127
|
let closed = false;
|
package/dist/react/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/react/index.ts","../../src/react/useOrg.ts","../../src/org.ts","../../src/ws.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 { org, 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 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 {\r\n Organization,\r\n Label,\r\n Category,\r\n Task,\r\n Comment,\r\n Pagination,\r\n ApiSuccess\r\n} from \"./types\";\r\n\r\nconst API = \"https://sayr.io/api/public\";\r\n\r\nasync function get<T>(url: string): Promise<T> {\r\n const res = await fetch(url);\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n return json;\r\n}\r\n\r\nexport const org = {\r\n async get(slug: string): Promise<Organization> {\r\n const r = await get<ApiSuccess<Organization>>(\r\n `${API}/organization/${slug}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async labels(slug: string): Promise<Label[]> {\r\n const r = await get<ApiSuccess<Label[]>>(\r\n `${API}/organization/${slug}/labels`\r\n );\r\n return r.data;\r\n },\r\n\r\n async categories(\r\n slug: string,\r\n order: \"asc\" | \"desc\" = \"desc\"\r\n ): Promise<Category[]> {\r\n const r = await get<ApiSuccess<Category[]>>(\r\n `${API}/organization/${slug}/categories?order=${order}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async tasks(\r\n slug: string,\r\n opts?: { order?: \"asc\" | \"desc\"; limit?: number; page?: number }\r\n ): Promise<{ data: Task[]; pagination: Pagination }> {\r\n const q = new URLSearchParams({\r\n order: opts?.order ?? \"desc\",\r\n limit: String(opts?.limit ?? 5),\r\n page: String(opts?.page ?? 1)\r\n });\r\n\r\n const res = await fetch(\r\n `${API}/organization/${slug}/tasks?${q}`\r\n );\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n\r\n return {\r\n data: json.data,\r\n pagination: json.pagination\r\n };\r\n },\r\n\r\n async task(slug: string, shortId: number): Promise<Task> {\r\n const r = await get<ApiSuccess<Task>>(\r\n `${API}/organization/${slug}/tasks/${shortId}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async comments(\r\n slug: string,\r\n shortId: number,\r\n opts?: { order?: \"asc\" | \"desc\"; limit?: number; page?: number }\r\n ): Promise<{ data: Comment[]; pagination: Pagination }> {\r\n const q = new URLSearchParams({\r\n order: opts?.order ?? \"desc\",\r\n limit: String(opts?.limit ?? 5),\r\n page: String(opts?.page ?? 1)\r\n });\r\n\r\n const res = await fetch(\r\n `${API}/organization/${slug}/tasks/${shortId}/comments?${q}`\r\n );\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n\r\n return {\r\n data: json.data,\r\n pagination: json.pagination\r\n };\r\n }\r\n};","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\nexport const wsTypes: 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}\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 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 === wsTypes.PING) {\r\n socket.send(JSON.stringify({ type: wsTypes.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}","import { useEffect, useState } from \"react\";\r\nimport { org, wsTypes } from \"..\";\r\nimport type { Task } from \"../types\";\r\nimport { useSayrWS } from \"./useSayrWS\";\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 org\r\n .tasks(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 [wsTypes.CREATE_TASK]: fetchTasks,\r\n [wsTypes.UPDATE_TASK]: fetchTasks\r\n });\r\n\r\n return { tasks, loading, refetch: fetchTasks };\r\n}","import { useEffect, useRef } from \"react\";\r\nimport { ws } from \"..\";\r\nimport { WSMessageType } 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 { org } from \"..\";\r\nimport type { Task } from \"../types\";\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 org\r\n .task(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 { org, wsTypes } from \"..\";\r\nimport type { Comment } from \"../types\";\r\nimport { useSayrWS } from \"./useSayrWS\";\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 org\r\n .comments(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 [wsTypes.UPDATE_TASK_COMMENTS]: fetchComments\r\n });\r\n\r\n return { comments, loading, refetch: fetchComments };\r\n}"],"mappings":"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","names":["import_react","import_react","import_react","import_react"]}
|
|
1
|
+
{"version":3,"sources":["../../src/react/index.ts","../../src/react/useOrg.ts","../../src/org.ts","../../src/ws.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 { org, 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 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 {\r\n Organization,\r\n Label,\r\n Category,\r\n Task,\r\n Comment,\r\n Pagination,\r\n ApiSuccess\r\n} from \"./types\";\r\n\r\nconst API = \"https://sayr.io/api/public\";\r\n\r\nasync function get<T>(url: string): Promise<T> {\r\n const res = await fetch(url);\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n return json;\r\n}\r\n\r\nexport const org = {\r\n async get(slug: string): Promise<Organization> {\r\n const r = await get<ApiSuccess<Organization>>(\r\n `${API}/organization/${slug}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async labels(slug: string): Promise<Label[]> {\r\n const r = await get<ApiSuccess<Label[]>>(\r\n `${API}/organization/${slug}/labels`\r\n );\r\n return r.data;\r\n },\r\n\r\n async categories(\r\n slug: string,\r\n order: \"asc\" | \"desc\" = \"desc\"\r\n ): Promise<Category[]> {\r\n const r = await get<ApiSuccess<Category[]>>(\r\n `${API}/organization/${slug}/categories?order=${order}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async tasks(\r\n slug: string,\r\n opts?: { order?: \"asc\" | \"desc\"; limit?: number; page?: number }\r\n ): Promise<{ data: Task[]; pagination: Pagination }> {\r\n const q = new URLSearchParams({\r\n order: opts?.order ?? \"desc\",\r\n limit: String(opts?.limit ?? 5),\r\n page: String(opts?.page ?? 1)\r\n });\r\n\r\n const res = await fetch(\r\n `${API}/organization/${slug}/tasks?${q}`\r\n );\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n\r\n return {\r\n data: json.data,\r\n pagination: json.pagination\r\n };\r\n },\r\n\r\n async task(slug: string, shortId: number): Promise<Task> {\r\n const r = await get<ApiSuccess<Task>>(\r\n `${API}/organization/${slug}/tasks/${shortId}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async comments(\r\n slug: string,\r\n shortId: number,\r\n opts?: { order?: \"asc\" | \"desc\"; limit?: number; page?: number }\r\n ): Promise<{ data: Comment[]; pagination: Pagination }> {\r\n const q = new URLSearchParams({\r\n order: opts?.order ?? \"desc\",\r\n limit: String(opts?.limit ?? 5),\r\n page: String(opts?.page ?? 1)\r\n });\r\n\r\n const res = await fetch(\r\n `${API}/organization/${slug}/tasks/${shortId}/comments?${q}`\r\n );\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n\r\n return {\r\n data: json.data,\r\n pagination: json.pagination\r\n };\r\n }\r\n};","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\nexport const wsTypes: 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}\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 === wsTypes.PING) {\r\n socket.send(JSON.stringify({ type: wsTypes.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}","import { useEffect, useState } from \"react\";\r\nimport { org, wsTypes } from \"..\";\r\nimport type { Task } from \"../types\";\r\nimport { useSayrWS } from \"./useSayrWS\";\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 org\r\n .tasks(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 [wsTypes.CREATE_TASK]: fetchTasks,\r\n [wsTypes.UPDATE_TASK]: fetchTasks\r\n });\r\n\r\n return { tasks, loading, refetch: fetchTasks };\r\n}","import { useEffect, useRef } from \"react\";\r\nimport { ws } from \"..\";\r\nimport { WSMessageType } 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 { org } from \"..\";\r\nimport type { Task } from \"../types\";\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 org\r\n .task(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 { org, wsTypes } from \"..\";\r\nimport type { Comment } from \"../types\";\r\nimport { useSayrWS } from \"./useSayrWS\";\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 org\r\n .comments(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 [wsTypes.UPDATE_TASK_COMMENTS]: fetchComments\r\n });\r\n\r\n return { comments, loading, refetch: fetchComments };\r\n}"],"mappings":"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","names":["import_react","import_react","import_react","import_react"]}
|
package/dist/react/index.js
CHANGED
|
@@ -87,6 +87,11 @@ var wsTypes = {
|
|
|
87
87
|
DISCONNECTED: "DISCONNECTED"
|
|
88
88
|
};
|
|
89
89
|
function ws(url, handlers = {}) {
|
|
90
|
+
if (!url) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
"[Sayr.ws] WebSocket URL is required. Did you forget to pass org.wsUrl?"
|
|
93
|
+
);
|
|
94
|
+
}
|
|
90
95
|
let socket;
|
|
91
96
|
let retry = 0;
|
|
92
97
|
let closed = false;
|
package/dist/react/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/react/useOrg.ts","../../src/org.ts","../../src/ws.ts","../../src/react/useTasks.ts","../../src/react/useSayrWS.ts","../../src/react/useTask.ts","../../src/react/useComments.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\r\nimport { org, 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 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 {\r\n Organization,\r\n Label,\r\n Category,\r\n Task,\r\n Comment,\r\n Pagination,\r\n ApiSuccess\r\n} from \"./types\";\r\n\r\nconst API = \"https://sayr.io/api/public\";\r\n\r\nasync function get<T>(url: string): Promise<T> {\r\n const res = await fetch(url);\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n return json;\r\n}\r\n\r\nexport const org = {\r\n async get(slug: string): Promise<Organization> {\r\n const r = await get<ApiSuccess<Organization>>(\r\n `${API}/organization/${slug}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async labels(slug: string): Promise<Label[]> {\r\n const r = await get<ApiSuccess<Label[]>>(\r\n `${API}/organization/${slug}/labels`\r\n );\r\n return r.data;\r\n },\r\n\r\n async categories(\r\n slug: string,\r\n order: \"asc\" | \"desc\" = \"desc\"\r\n ): Promise<Category[]> {\r\n const r = await get<ApiSuccess<Category[]>>(\r\n `${API}/organization/${slug}/categories?order=${order}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async tasks(\r\n slug: string,\r\n opts?: { order?: \"asc\" | \"desc\"; limit?: number; page?: number }\r\n ): Promise<{ data: Task[]; pagination: Pagination }> {\r\n const q = new URLSearchParams({\r\n order: opts?.order ?? \"desc\",\r\n limit: String(opts?.limit ?? 5),\r\n page: String(opts?.page ?? 1)\r\n });\r\n\r\n const res = await fetch(\r\n `${API}/organization/${slug}/tasks?${q}`\r\n );\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n\r\n return {\r\n data: json.data,\r\n pagination: json.pagination\r\n };\r\n },\r\n\r\n async task(slug: string, shortId: number): Promise<Task> {\r\n const r = await get<ApiSuccess<Task>>(\r\n `${API}/organization/${slug}/tasks/${shortId}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async comments(\r\n slug: string,\r\n shortId: number,\r\n opts?: { order?: \"asc\" | \"desc\"; limit?: number; page?: number }\r\n ): Promise<{ data: Comment[]; pagination: Pagination }> {\r\n const q = new URLSearchParams({\r\n order: opts?.order ?? \"desc\",\r\n limit: String(opts?.limit ?? 5),\r\n page: String(opts?.page ?? 1)\r\n });\r\n\r\n const res = await fetch(\r\n `${API}/organization/${slug}/tasks/${shortId}/comments?${q}`\r\n );\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n\r\n return {\r\n data: json.data,\r\n pagination: json.pagination\r\n };\r\n }\r\n};","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\nexport const wsTypes: 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}\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 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 === wsTypes.PING) {\r\n socket.send(JSON.stringify({ type: wsTypes.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}","import { useEffect, useState } from \"react\";\r\nimport { org, wsTypes } from \"..\";\r\nimport type { Task } from \"../types\";\r\nimport { useSayrWS } from \"./useSayrWS\";\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 org\r\n .tasks(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 [wsTypes.CREATE_TASK]: fetchTasks,\r\n [wsTypes.UPDATE_TASK]: fetchTasks\r\n });\r\n\r\n return { tasks, loading, refetch: fetchTasks };\r\n}","import { useEffect, useRef } from \"react\";\r\nimport { ws } from \"..\";\r\nimport { WSMessageType } 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 { org } from \"..\";\r\nimport type { Task } from \"../types\";\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 org\r\n .task(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 { org, wsTypes } from \"..\";\r\nimport type { Comment } from \"../types\";\r\nimport { useSayrWS } from \"./useSayrWS\";\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 org\r\n .comments(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 [wsTypes.UPDATE_TASK_COMMENTS]: fetchComments\r\n });\r\n\r\n return { comments, loading, refetch: fetchComments };\r\n}"],"mappings":";AAAA,SAAS,WAAW,gBAAgB;;;ACUpC,IAAM,MAAM;AAEZ,eAAe,IAAO,KAAyB;AAC3C,QAAM,MAAM,MAAM,MAAM,GAAG;AAC3B,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,MAAI,CAAC,KAAK,QAAS,OAAM;AACzB,SAAO;AACX;AAEO,IAAM,MAAM;AAAA,EACf,MAAM,IAAI,MAAqC;AAC3C,UAAM,IAAI,MAAM;AAAA,MACZ,GAAG,GAAG,iBAAiB,IAAI;AAAA,IAC/B;AACA,WAAO,EAAE;AAAA,EACb;AAAA,EAEA,MAAM,OAAO,MAAgC;AACzC,UAAM,IAAI,MAAM;AAAA,MACZ,GAAG,GAAG,iBAAiB,IAAI;AAAA,IAC/B;AACA,WAAO,EAAE;AAAA,EACb;AAAA,EAEA,MAAM,WACF,MACA,QAAwB,QACL;AACnB,UAAM,IAAI,MAAM;AAAA,MACZ,GAAG,GAAG,iBAAiB,IAAI,qBAAqB,KAAK;AAAA,IACzD;AACA,WAAO,EAAE;AAAA,EACb;AAAA,EAEA,MAAM,MACF,MACA,MACiD;AACjD,UAAM,IAAI,IAAI,gBAAgB;AAAA,MAC1B,OAAO,MAAM,SAAS;AAAA,MACtB,OAAO,OAAO,MAAM,SAAS,CAAC;AAAA,MAC9B,MAAM,OAAO,MAAM,QAAQ,CAAC;AAAA,IAChC,CAAC;AAED,UAAM,MAAM,MAAM;AAAA,MACd,GAAG,GAAG,iBAAiB,IAAI,UAAU,CAAC;AAAA,IAC1C;AACA,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,QAAI,CAAC,KAAK,QAAS,OAAM;AAEzB,WAAO;AAAA,MACH,MAAM,KAAK;AAAA,MACX,YAAY,KAAK;AAAA,IACrB;AAAA,EACJ;AAAA,EAEA,MAAM,KAAK,MAAc,SAAgC;AACrD,UAAM,IAAI,MAAM;AAAA,MACZ,GAAG,GAAG,iBAAiB,IAAI,UAAU,OAAO;AAAA,IAChD;AACA,WAAO,EAAE;AAAA,EACb;AAAA,EAEA,MAAM,SACF,MACA,SACA,MACoD;AACpD,UAAM,IAAI,IAAI,gBAAgB;AAAA,MAC1B,OAAO,MAAM,SAAS;AAAA,MACtB,OAAO,OAAO,MAAM,SAAS,CAAC;AAAA,MAC9B,MAAM,OAAO,MAAM,QAAQ,CAAC;AAAA,IAChC,CAAC;AAED,UAAM,MAAM,MAAM;AAAA,MACd,GAAG,GAAG,iBAAiB,IAAI,UAAU,OAAO,aAAa,CAAC;AAAA,IAC9D;AACA,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,QAAI,CAAC,KAAK,QAAS,OAAM;AAEzB,WAAO;AAAA,MACH,MAAM,KAAK;AAAA,MACX,YAAY,KAAK;AAAA,IACrB;AAAA,EACJ;AACJ;;;AC9EO,IAAM,UAAgD;AAAA,EACzD,mBAAmB;AAAA,EACnB,YAAY;AAAA,EACZ,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,aAAa;AAAA,EACb,sBAAsB;AAAA,EACtB,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,cAAc;AAAA,EACd,mBAAmB;AAAA,EACnB,wBAAwB;AAAA,EACxB,cAAc;AAClB;AAaO,SAAS,GAAG,KAAa,WAAqB,CAAC,GAAG;AACrD,MAAI;AACJ,MAAI,QAAQ;AACZ,MAAI,SAAS;AAEb,WAAS,UAAU;AACf,QAAI,OAAQ;AAEZ,aAAS,IAAI,UAAU,GAAG;AAE1B,WAAO,YAAY,CAAC,MAAM;AACtB,YAAM,MAAM,KAAK,MAAM,EAAE,IAAI;AAE7B,UAAI,IAAI,SAAS,QAAQ,MAAM;AAC3B,eAAO,KAAK,KAAK,UAAU,EAAE,MAAM,QAAQ,KAAK,CAAC,CAAC;AAClD;AAAA,MACJ;AAEA,eAAS,IAAI,IAAI,IAAI,IAAI,MAAM,GAAG;AAAA,IACtC;AAEA,WAAO,UAAU,MAAM;AACnB,UAAI,OAAQ;AACZ,iBAAW,SAAS,KAAK,IAAI,MAAO,KAAK,SAAS,GAAK,CAAC;AAAA,IAC5D;AAEA,WAAO,UAAU,MAAM,OAAO,MAAM;AAAA,EACxC;AAEA,UAAQ;AAER,SAAO;AAAA,IACH,QAAQ;AACJ,eAAS;AACT,cAAQ,MAAM;AAAA,IAClB;AAAA,EACJ;AACJ;;;AFhFO,SAAS,OAAO,MAAe;AAClC,QAAM,CAAC,MAAM,OAAO,IAAI,SAA8B,IAAI;AAC1D,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAC5C,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAkB,IAAI;AAEhD,YAAU,MAAM;AACZ,QAAI,CAAC,KAAM;AAEX,eAAW,IAAI;AACf,QACK,IAAI,IAAI,EACR,KAAK,OAAO,EACZ,MAAM,QAAQ,EACd,QAAQ,MAAM,WAAW,KAAK,CAAC;AAAA,EACxC,GAAG,CAAC,IAAI,CAAC;AAET,SAAO,EAAE,MAAM,SAAS,MAAM;AAClC;;;AGpBA,SAAS,aAAAA,YAAW,YAAAC,iBAAgB;;;ACApC,SAAS,aAAAC,YAAW,cAAc;AAQ3B,SAAS,UACZ,OACA,UACF;AACE,QAAM,UAAU,OAAqC,IAAI;AAEzD,EAAAC,WAAU,MAAM;AACZ,QAAI,CAAC,MAAO;AAEZ,YAAQ,UAAU,GAAG,OAAO,QAAQ;AAEpC,WAAO,MAAM;AACT,cAAQ,SAAS,MAAM;AACvB,cAAQ,UAAU;AAAA,IACtB;AAAA,EACJ,GAAG,CAAC,KAAK,CAAC;AAEV,SAAO;AACX;;;ADtBO,SAAS,SACZ,MACA,OACF;AACE,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAAiB,CAAC,CAAC;AAC7C,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,KAAK;AAE5C,WAAS,aAAa;AAClB,QAAI,CAAC,KAAM;AACX,eAAW,IAAI;AACf,QACK,MAAM,IAAI,EACV,KAAK,CAAC,MAAM,SAAS,EAAE,IAAI,CAAC,EAC5B,QAAQ,MAAM,WAAW,KAAK,CAAC;AAAA,EACxC;AAEA,EAAAC,WAAU,YAAY,CAAC,IAAI,CAAC;AAE5B,YAAU,OAAO;AAAA,IACb,CAAC,QAAQ,WAAW,GAAG;AAAA,IACvB,CAAC,QAAQ,WAAW,GAAG;AAAA,EAC3B,CAAC;AAED,SAAO,EAAE,OAAO,SAAS,SAAS,WAAW;AACjD;;;AE5BA,SAAS,aAAAC,YAAW,YAAAC,iBAAgB;AAI7B,SAAS,QACZ,MACA,SACF;AACE,QAAM,CAAC,MAAM,OAAO,IAAIC,UAAsB,IAAI;AAClD,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,KAAK;AAE5C,EAAAC,WAAU,MAAM;AACZ,QAAI,CAAC,QAAQ,WAAW,KAAM;AAE9B,eAAW,IAAI;AACf,QACK,KAAK,MAAM,OAAO,EAClB,KAAK,OAAO,EACZ,QAAQ,MAAM,WAAW,KAAK,CAAC;AAAA,EACxC,GAAG,CAAC,MAAM,OAAO,CAAC;AAElB,SAAO,EAAE,MAAM,QAAQ;AAC3B;;;ACtBA,SAAS,aAAAC,YAAW,YAAAC,iBAAgB;AAK7B,SAAS,YACZ,MACA,SACA,OACF;AACE,QAAM,CAAC,UAAU,WAAW,IAAIC,UAAoB,CAAC,CAAC;AACtD,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,KAAK;AAE5C,WAAS,gBAAgB;AACrB,QAAI,CAAC,QAAQ,WAAW,KAAM;AAE9B,eAAW,IAAI;AACf,QACK,SAAS,MAAM,OAAO,EACtB,KAAK,CAAC,MAAM,YAAY,EAAE,IAAI,CAAC,EAC/B,QAAQ,MAAM,WAAW,KAAK,CAAC;AAAA,EACxC;AAEA,EAAAC,WAAU,eAAe,CAAC,MAAM,OAAO,CAAC;AAExC,YAAU,OAAO;AAAA,IACb,CAAC,QAAQ,oBAAoB,GAAG;AAAA,EACpC,CAAC;AAED,SAAO,EAAE,UAAU,SAAS,SAAS,cAAc;AACvD;","names":["useEffect","useState","useEffect","useEffect","useState","useEffect","useEffect","useState","useState","useEffect","useEffect","useState","useState","useEffect"]}
|
|
1
|
+
{"version":3,"sources":["../../src/react/useOrg.ts","../../src/org.ts","../../src/ws.ts","../../src/react/useTasks.ts","../../src/react/useSayrWS.ts","../../src/react/useTask.ts","../../src/react/useComments.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\r\nimport { org, 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 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 {\r\n Organization,\r\n Label,\r\n Category,\r\n Task,\r\n Comment,\r\n Pagination,\r\n ApiSuccess\r\n} from \"./types\";\r\n\r\nconst API = \"https://sayr.io/api/public\";\r\n\r\nasync function get<T>(url: string): Promise<T> {\r\n const res = await fetch(url);\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n return json;\r\n}\r\n\r\nexport const org = {\r\n async get(slug: string): Promise<Organization> {\r\n const r = await get<ApiSuccess<Organization>>(\r\n `${API}/organization/${slug}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async labels(slug: string): Promise<Label[]> {\r\n const r = await get<ApiSuccess<Label[]>>(\r\n `${API}/organization/${slug}/labels`\r\n );\r\n return r.data;\r\n },\r\n\r\n async categories(\r\n slug: string,\r\n order: \"asc\" | \"desc\" = \"desc\"\r\n ): Promise<Category[]> {\r\n const r = await get<ApiSuccess<Category[]>>(\r\n `${API}/organization/${slug}/categories?order=${order}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async tasks(\r\n slug: string,\r\n opts?: { order?: \"asc\" | \"desc\"; limit?: number; page?: number }\r\n ): Promise<{ data: Task[]; pagination: Pagination }> {\r\n const q = new URLSearchParams({\r\n order: opts?.order ?? \"desc\",\r\n limit: String(opts?.limit ?? 5),\r\n page: String(opts?.page ?? 1)\r\n });\r\n\r\n const res = await fetch(\r\n `${API}/organization/${slug}/tasks?${q}`\r\n );\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n\r\n return {\r\n data: json.data,\r\n pagination: json.pagination\r\n };\r\n },\r\n\r\n async task(slug: string, shortId: number): Promise<Task> {\r\n const r = await get<ApiSuccess<Task>>(\r\n `${API}/organization/${slug}/tasks/${shortId}`\r\n );\r\n return r.data;\r\n },\r\n\r\n async comments(\r\n slug: string,\r\n shortId: number,\r\n opts?: { order?: \"asc\" | \"desc\"; limit?: number; page?: number }\r\n ): Promise<{ data: Comment[]; pagination: Pagination }> {\r\n const q = new URLSearchParams({\r\n order: opts?.order ?? \"desc\",\r\n limit: String(opts?.limit ?? 5),\r\n page: String(opts?.page ?? 1)\r\n });\r\n\r\n const res = await fetch(\r\n `${API}/organization/${slug}/tasks/${shortId}/comments?${q}`\r\n );\r\n const json = await res.json();\r\n if (!json.success) throw json;\r\n\r\n return {\r\n data: json.data,\r\n pagination: json.pagination\r\n };\r\n }\r\n};","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\nexport const wsTypes: 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}\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 === wsTypes.PING) {\r\n socket.send(JSON.stringify({ type: wsTypes.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}","import { useEffect, useState } from \"react\";\r\nimport { org, wsTypes } from \"..\";\r\nimport type { Task } from \"../types\";\r\nimport { useSayrWS } from \"./useSayrWS\";\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 org\r\n .tasks(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 [wsTypes.CREATE_TASK]: fetchTasks,\r\n [wsTypes.UPDATE_TASK]: fetchTasks\r\n });\r\n\r\n return { tasks, loading, refetch: fetchTasks };\r\n}","import { useEffect, useRef } from \"react\";\r\nimport { ws } from \"..\";\r\nimport { WSMessageType } 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 { org } from \"..\";\r\nimport type { Task } from \"../types\";\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 org\r\n .task(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 { org, wsTypes } from \"..\";\r\nimport type { Comment } from \"../types\";\r\nimport { useSayrWS } from \"./useSayrWS\";\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 org\r\n .comments(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 [wsTypes.UPDATE_TASK_COMMENTS]: fetchComments\r\n });\r\n\r\n return { comments, loading, refetch: fetchComments };\r\n}"],"mappings":";AAAA,SAAS,WAAW,gBAAgB;;;ACUpC,IAAM,MAAM;AAEZ,eAAe,IAAO,KAAyB;AAC3C,QAAM,MAAM,MAAM,MAAM,GAAG;AAC3B,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,MAAI,CAAC,KAAK,QAAS,OAAM;AACzB,SAAO;AACX;AAEO,IAAM,MAAM;AAAA,EACf,MAAM,IAAI,MAAqC;AAC3C,UAAM,IAAI,MAAM;AAAA,MACZ,GAAG,GAAG,iBAAiB,IAAI;AAAA,IAC/B;AACA,WAAO,EAAE;AAAA,EACb;AAAA,EAEA,MAAM,OAAO,MAAgC;AACzC,UAAM,IAAI,MAAM;AAAA,MACZ,GAAG,GAAG,iBAAiB,IAAI;AAAA,IAC/B;AACA,WAAO,EAAE;AAAA,EACb;AAAA,EAEA,MAAM,WACF,MACA,QAAwB,QACL;AACnB,UAAM,IAAI,MAAM;AAAA,MACZ,GAAG,GAAG,iBAAiB,IAAI,qBAAqB,KAAK;AAAA,IACzD;AACA,WAAO,EAAE;AAAA,EACb;AAAA,EAEA,MAAM,MACF,MACA,MACiD;AACjD,UAAM,IAAI,IAAI,gBAAgB;AAAA,MAC1B,OAAO,MAAM,SAAS;AAAA,MACtB,OAAO,OAAO,MAAM,SAAS,CAAC;AAAA,MAC9B,MAAM,OAAO,MAAM,QAAQ,CAAC;AAAA,IAChC,CAAC;AAED,UAAM,MAAM,MAAM;AAAA,MACd,GAAG,GAAG,iBAAiB,IAAI,UAAU,CAAC;AAAA,IAC1C;AACA,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,QAAI,CAAC,KAAK,QAAS,OAAM;AAEzB,WAAO;AAAA,MACH,MAAM,KAAK;AAAA,MACX,YAAY,KAAK;AAAA,IACrB;AAAA,EACJ;AAAA,EAEA,MAAM,KAAK,MAAc,SAAgC;AACrD,UAAM,IAAI,MAAM;AAAA,MACZ,GAAG,GAAG,iBAAiB,IAAI,UAAU,OAAO;AAAA,IAChD;AACA,WAAO,EAAE;AAAA,EACb;AAAA,EAEA,MAAM,SACF,MACA,SACA,MACoD;AACpD,UAAM,IAAI,IAAI,gBAAgB;AAAA,MAC1B,OAAO,MAAM,SAAS;AAAA,MACtB,OAAO,OAAO,MAAM,SAAS,CAAC;AAAA,MAC9B,MAAM,OAAO,MAAM,QAAQ,CAAC;AAAA,IAChC,CAAC;AAED,UAAM,MAAM,MAAM;AAAA,MACd,GAAG,GAAG,iBAAiB,IAAI,UAAU,OAAO,aAAa,CAAC;AAAA,IAC9D;AACA,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,QAAI,CAAC,KAAK,QAAS,OAAM;AAEzB,WAAO;AAAA,MACH,MAAM,KAAK;AAAA,MACX,YAAY,KAAK;AAAA,IACrB;AAAA,EACJ;AACJ;;;AC9EO,IAAM,UAAgD;AAAA,EACzD,mBAAmB;AAAA,EACnB,YAAY;AAAA,EACZ,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,aAAa;AAAA,EACb,sBAAsB;AAAA,EACtB,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,cAAc;AAAA,EACd,mBAAmB;AAAA,EACnB,wBAAwB;AAAA,EACxB,cAAc;AAClB;AAaO,SAAS,GAAG,KAAa,WAAqB,CAAC,GAAG;AACrD,MAAI,CAAC,KAAK;AACN,UAAM,IAAI;AAAA,MACN;AAAA,IAEJ;AAAA,EACJ;AACA,MAAI;AACJ,MAAI,QAAQ;AACZ,MAAI,SAAS;AAEb,WAAS,UAAU;AACf,QAAI,OAAQ;AAEZ,aAAS,IAAI,UAAU,GAAG;AAE1B,WAAO,YAAY,CAAC,MAAM;AACtB,YAAM,MAAM,KAAK,MAAM,EAAE,IAAI;AAE7B,UAAI,IAAI,SAAS,QAAQ,MAAM;AAC3B,eAAO,KAAK,KAAK,UAAU,EAAE,MAAM,QAAQ,KAAK,CAAC,CAAC;AAClD;AAAA,MACJ;AAEA,eAAS,IAAI,IAAI,IAAI,IAAI,MAAM,GAAG;AAAA,IACtC;AAEA,WAAO,UAAU,MAAM;AACnB,UAAI,OAAQ;AACZ,iBAAW,SAAS,KAAK,IAAI,MAAO,KAAK,SAAS,GAAK,CAAC;AAAA,IAC5D;AAEA,WAAO,UAAU,MAAM,OAAO,MAAM;AAAA,EACxC;AAEA,UAAQ;AAER,SAAO;AAAA,IACH,QAAQ;AACJ,eAAS;AACT,cAAQ,MAAM;AAAA,IAClB;AAAA,EACJ;AACJ;;;AFtFO,SAAS,OAAO,MAAe;AAClC,QAAM,CAAC,MAAM,OAAO,IAAI,SAA8B,IAAI;AAC1D,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAC5C,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAkB,IAAI;AAEhD,YAAU,MAAM;AACZ,QAAI,CAAC,KAAM;AAEX,eAAW,IAAI;AACf,QACK,IAAI,IAAI,EACR,KAAK,OAAO,EACZ,MAAM,QAAQ,EACd,QAAQ,MAAM,WAAW,KAAK,CAAC;AAAA,EACxC,GAAG,CAAC,IAAI,CAAC;AAET,SAAO,EAAE,MAAM,SAAS,MAAM;AAClC;;;AGpBA,SAAS,aAAAA,YAAW,YAAAC,iBAAgB;;;ACApC,SAAS,aAAAC,YAAW,cAAc;AAQ3B,SAAS,UACZ,OACA,UACF;AACE,QAAM,UAAU,OAAqC,IAAI;AAEzD,EAAAC,WAAU,MAAM;AACZ,QAAI,CAAC,MAAO;AAEZ,YAAQ,UAAU,GAAG,OAAO,QAAQ;AAEpC,WAAO,MAAM;AACT,cAAQ,SAAS,MAAM;AACvB,cAAQ,UAAU;AAAA,IACtB;AAAA,EACJ,GAAG,CAAC,KAAK,CAAC;AAEV,SAAO;AACX;;;ADtBO,SAAS,SACZ,MACA,OACF;AACE,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAAiB,CAAC,CAAC;AAC7C,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,KAAK;AAE5C,WAAS,aAAa;AAClB,QAAI,CAAC,KAAM;AACX,eAAW,IAAI;AACf,QACK,MAAM,IAAI,EACV,KAAK,CAAC,MAAM,SAAS,EAAE,IAAI,CAAC,EAC5B,QAAQ,MAAM,WAAW,KAAK,CAAC;AAAA,EACxC;AAEA,EAAAC,WAAU,YAAY,CAAC,IAAI,CAAC;AAE5B,YAAU,OAAO;AAAA,IACb,CAAC,QAAQ,WAAW,GAAG;AAAA,IACvB,CAAC,QAAQ,WAAW,GAAG;AAAA,EAC3B,CAAC;AAED,SAAO,EAAE,OAAO,SAAS,SAAS,WAAW;AACjD;;;AE5BA,SAAS,aAAAC,YAAW,YAAAC,iBAAgB;AAI7B,SAAS,QACZ,MACA,SACF;AACE,QAAM,CAAC,MAAM,OAAO,IAAIC,UAAsB,IAAI;AAClD,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,KAAK;AAE5C,EAAAC,WAAU,MAAM;AACZ,QAAI,CAAC,QAAQ,WAAW,KAAM;AAE9B,eAAW,IAAI;AACf,QACK,KAAK,MAAM,OAAO,EAClB,KAAK,OAAO,EACZ,QAAQ,MAAM,WAAW,KAAK,CAAC;AAAA,EACxC,GAAG,CAAC,MAAM,OAAO,CAAC;AAElB,SAAO,EAAE,MAAM,QAAQ;AAC3B;;;ACtBA,SAAS,aAAAC,YAAW,YAAAC,iBAAgB;AAK7B,SAAS,YACZ,MACA,SACA,OACF;AACE,QAAM,CAAC,UAAU,WAAW,IAAIC,UAAoB,CAAC,CAAC;AACtD,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,KAAK;AAE5C,WAAS,gBAAgB;AACrB,QAAI,CAAC,QAAQ,WAAW,KAAM;AAE9B,eAAW,IAAI;AACf,QACK,SAAS,MAAM,OAAO,EACtB,KAAK,CAAC,MAAM,YAAY,EAAE,IAAI,CAAC,EAC/B,QAAQ,MAAM,WAAW,KAAK,CAAC;AAAA,EACxC;AAEA,EAAAC,WAAU,eAAe,CAAC,MAAM,OAAO,CAAC;AAExC,YAAU,OAAO;AAAA,IACb,CAAC,QAAQ,oBAAoB,GAAG;AAAA,EACpC,CAAC;AAED,SAAO,EAAE,UAAU,SAAS,SAAS,cAAc;AACvD;","names":["useEffect","useState","useEffect","useEffect","useState","useEffect","useEffect","useState","useState","useEffect","useEffect","useState","useState","useEffect"]}
|