@graffy/client 0.15.25-alpha.4 → 0.15.25-alpha.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.
Files changed (2) hide show
  1. package/package.json +4 -9
  2. package/index.cjs +0 -319
package/package.json CHANGED
@@ -2,13 +2,8 @@
2
2
  "name": "@graffy/client",
3
3
  "description": "Graffy client library for the browser, usin the `fetch()` or `WebSocket` APIs. This module is intended to be used with a Node.js server running Graffy Server.",
4
4
  "author": "aravind (https://github.com/aravindet)",
5
- "version": "0.15.25-alpha.4",
6
- "main": "./index.cjs",
7
- "exports": {
8
- "import": "./index.mjs",
9
- "require": "./index.cjs"
10
- },
11
- "module": "./index.mjs",
5
+ "version": "0.15.25-alpha.5",
6
+ "main": "./index.mjs",
12
7
  "types": "./types/index.d.ts",
13
8
  "repository": {
14
9
  "type": "git",
@@ -16,8 +11,8 @@
16
11
  },
17
12
  "license": "Apache-2.0",
18
13
  "dependencies": {
19
- "@graffy/stream": "0.15.25-alpha.4",
20
- "@graffy/common": "0.15.25-alpha.4",
14
+ "@graffy/stream": "0.15.25-alpha.5",
15
+ "@graffy/common": "0.15.25-alpha.5",
21
16
  "debug": "^4.3.3"
22
17
  }
23
18
  }
package/index.cjs DELETED
@@ -1,319 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
- var __publicField = (obj, key, value) => {
5
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
6
- return value;
7
- };
8
- const common = require("@graffy/common");
9
- const stream = require("@graffy/stream");
10
- const debug = require("debug");
11
- const _interopDefaultLegacy = (e) => e && typeof e === "object" && "default" in e ? e : { default: e };
12
- const debug__default = /* @__PURE__ */ _interopDefaultLegacy(debug);
13
- function getOptionsParam(options) {
14
- if (!options)
15
- return "";
16
- return encodeURIComponent(common.serialize(options));
17
- }
18
- const aggregateQueries = {};
19
- class AggregateQuery {
20
- constructor(url) {
21
- __publicField(this, "combinedQuery", []);
22
- __publicField(this, "readers", []);
23
- __publicField(this, "timer", null);
24
- this.url = url;
25
- }
26
- add(query) {
27
- common.add(this.combinedQuery, query);
28
- if (this.timer)
29
- clearTimeout(this.timer);
30
- this.timer = setTimeout(() => this.doFetch(), 0);
31
- return new Promise((resolve, reject) => {
32
- this.readers.push({ query, resolve, reject });
33
- });
34
- }
35
- async doFetch() {
36
- delete aggregateQueries[this.url];
37
- const response = await fetch(this.url, {
38
- method: "POST",
39
- headers: { "Content-Type": "application/json" },
40
- body: common.serialize(this.combinedQuery)
41
- });
42
- if (response.status !== 200) {
43
- const message = await response.text();
44
- const err = new Error(message);
45
- for (const reader of this.readers) {
46
- reader.reject(err);
47
- }
48
- return;
49
- }
50
- const data = await response.json();
51
- for (const reader of this.readers) {
52
- reader.resolve(data);
53
- }
54
- }
55
- }
56
- function makeQuery(url, query) {
57
- if (!aggregateQueries[url])
58
- aggregateQueries[url] = new AggregateQuery(url);
59
- return aggregateQueries[url].add(query);
60
- }
61
- const httpClient = (baseUrl, {
62
- getOptions = async () => {
63
- },
64
- watch = "sse",
65
- connInfoPath = "connection"
66
- } = {}) => (store) => {
67
- store.onWrite(connInfoPath, ({ url }) => {
68
- baseUrl = url;
69
- return { url };
70
- });
71
- store.onRead(connInfoPath, () => ({ url: baseUrl }));
72
- store.on("read", async (query, options) => {
73
- if (!fetch)
74
- throw Error("client.fetch.unavailable");
75
- const optionsParam = getOptionsParam(await getOptions("read", options));
76
- const url = `${baseUrl}?opts=${optionsParam}&op=read`;
77
- return makeQuery(url, query);
78
- });
79
- store.on("watch", async function* (query, options) {
80
- if (watch === "none")
81
- throw Error("client.no_watch");
82
- if (watch === "hang") {
83
- yield* stream.makeStream((push) => {
84
- push(void 0);
85
- });
86
- return;
87
- }
88
- if (!EventSource)
89
- throw Error("client.sse.unavailable");
90
- const optionsParam = getOptionsParam(await getOptions("watch", options));
91
- const url = `${baseUrl}?q=${common.encodeUrl(query)}&opts=${optionsParam}`;
92
- const source = new EventSource(url);
93
- yield* stream.makeStream((push, end) => {
94
- source.onmessage = ({ data }) => {
95
- push(common.deserialize(data));
96
- };
97
- source.onerror = (e) => {
98
- end(Error("client.sse.transport: " + e.message));
99
- };
100
- source.addEventListener("graffyerror", (e) => {
101
- end(Error("server." + e.data));
102
- });
103
- return () => {
104
- source.close();
105
- };
106
- });
107
- });
108
- store.on("write", async (change, options) => {
109
- if (!fetch)
110
- throw Error("client.fetch.unavailable");
111
- const optionsParam = getOptionsParam(await getOptions("write", options));
112
- const url = `${baseUrl}?opts=${optionsParam}&op=write`;
113
- return fetch(url, {
114
- method: "POST",
115
- headers: { "Content-Type": "application/json" },
116
- body: common.serialize(change)
117
- }).then((res) => {
118
- if (res.status === 200)
119
- return res.json();
120
- return res.text().then((message) => {
121
- throw Error("server." + message);
122
- });
123
- });
124
- });
125
- };
126
- const log = debug__default.default("graffy:client:socket");
127
- log.log = console.log.bind(console);
128
- const MIN_DELAY = 1e3;
129
- const MAX_DELAY = 3e5;
130
- const DELAY_GROWTH = 1.5;
131
- const INTERVAL = 2e3;
132
- const PING_TIMEOUT = 4e4;
133
- const RESET_TIMEOUT = 1e4;
134
- function Socket(url, { onUnhandled = void 0, onStatusChange = void 0 } = {}) {
135
- const handlers = {};
136
- const buffer = [];
137
- let isOpen = false;
138
- let isConnecting = false;
139
- let socket;
140
- let lastAlive;
141
- let lastAttempt;
142
- let attempts = 0;
143
- let connectTimer;
144
- let aliveTimer;
145
- function start(params, callback) {
146
- const id = common.makeId();
147
- const request = [id, ...params];
148
- handlers[id] = { request, callback };
149
- if (isAlive())
150
- send(request);
151
- return id;
152
- }
153
- function stop(id, params) {
154
- delete handlers[id];
155
- if (params)
156
- send([id, ...params]);
157
- }
158
- function connect() {
159
- log("Trying to connect to", url);
160
- isOpen = false;
161
- isConnecting = true;
162
- lastAttempt = Date.now();
163
- attempts++;
164
- socket = new globalThis.WebSocket(url);
165
- socket.onmessage = received;
166
- socket.onerror = closed;
167
- socket.onclose = closed;
168
- socket.onopen = opened;
169
- }
170
- function received(event) {
171
- const [id, ...data] = common.deserialize(event.data);
172
- setAlive();
173
- if (id === ":ping") {
174
- send([":pong"]);
175
- } else if (handlers[id]) {
176
- handlers[id].callback(...data);
177
- } else {
178
- onUnhandled && onUnhandled(id, ...data);
179
- }
180
- }
181
- function closed(_event) {
182
- log("Closed");
183
- if (isOpen && onStatusChange)
184
- onStatusChange(false);
185
- const wasOpen = isOpen;
186
- isOpen = false;
187
- isConnecting = false;
188
- lastAttempt = Date.now();
189
- if (wasOpen && !attempts) {
190
- connect();
191
- return;
192
- }
193
- maybeConnect();
194
- }
195
- function maybeConnect() {
196
- const connDelay = lastAttempt + Math.min(MAX_DELAY, MIN_DELAY * Math.pow(DELAY_GROWTH, attempts)) - Date.now();
197
- log("Will reconnect in", connDelay, "ms");
198
- if (connDelay <= 0) {
199
- connect();
200
- return;
201
- }
202
- clearTimeout(connectTimer);
203
- connectTimer = setTimeout(connect, connDelay);
204
- }
205
- function opened() {
206
- log("Connected", buffer.length, Object.keys(handlers).length);
207
- isOpen = true;
208
- isConnecting = false;
209
- lastAttempt = Date.now();
210
- setAlive();
211
- if (onStatusChange)
212
- onStatusChange(true);
213
- for (const id in handlers)
214
- send(handlers[id].request);
215
- while (buffer.length)
216
- send(buffer.shift());
217
- }
218
- function setAlive() {
219
- lastAlive = Date.now();
220
- log("Set alive", lastAlive - lastAttempt);
221
- if (lastAlive - lastAttempt > RESET_TIMEOUT)
222
- attempts = 0;
223
- }
224
- function isAlive() {
225
- log("Liveness check", isOpen ? "open" : "closed", Date.now() - lastAlive);
226
- clearTimeout(aliveTimer);
227
- aliveTimer = setTimeout(isAlive, INTERVAL);
228
- if (!isOpen) {
229
- if (!isConnecting)
230
- maybeConnect();
231
- return false;
232
- }
233
- if (Date.now() - lastAlive < PING_TIMEOUT)
234
- return true;
235
- socket.close();
236
- return false;
237
- }
238
- function send(req) {
239
- if (isAlive()) {
240
- socket.send(common.serialize(req));
241
- } else {
242
- buffer.push(req);
243
- }
244
- }
245
- connect();
246
- aliveTimer = setTimeout(isAlive, INTERVAL);
247
- return {
248
- start,
249
- stop,
250
- isAlive
251
- };
252
- }
253
- const wsClient = (url, {
254
- getOptions = (..._) => false,
255
- watch = void 0,
256
- connInfoPath = "connection"
257
- } = {}) => (store) => {
258
- if (!WebSocket)
259
- throw Error("client.websocket.unavailable");
260
- const socket = Socket(url, { onUnhandled, onStatusChange });
261
- let status = false;
262
- const statusWatcher = common.makeWatcher();
263
- function onUnhandled(id) {
264
- socket.stop(id, ["unwatch"]);
265
- }
266
- function onStatusChange(newStatus) {
267
- status = newStatus;
268
- statusWatcher.write({ status });
269
- }
270
- function once(op, payload, options) {
271
- return new Promise((resolve, reject) => {
272
- const id = socket.start(
273
- [op, payload, getOptions(op, options) || {}],
274
- (error, result) => {
275
- socket.stop(id);
276
- error ? reject(Error("server." + error)) : resolve(result);
277
- }
278
- );
279
- });
280
- }
281
- store.onWrite(connInfoPath, () => {
282
- status = socket.isAlive();
283
- return { status };
284
- });
285
- store.onRead(connInfoPath, () => ({ status }));
286
- store.onWatch(connInfoPath, () => statusWatcher.watch({ status }));
287
- store.on("read", (query, options) => once("read", query, options));
288
- store.on("write", (change, options) => once("write", change, options));
289
- store.on("watch", (query, options) => {
290
- if (watch === "none")
291
- throw Error("client.no_watch");
292
- const op = "watch";
293
- return stream.makeStream((push, end) => {
294
- const id = socket.start(
295
- [op, query, getOptions(op, options) || {}],
296
- (error, result) => {
297
- if (error) {
298
- socket.stop(id);
299
- end(Error("server." + error));
300
- return;
301
- }
302
- push(result);
303
- }
304
- );
305
- return () => {
306
- socket.stop(id, ["unwatch"]);
307
- };
308
- });
309
- });
310
- };
311
- const WSRE = /^wss?:\/\//;
312
- function GraffyClient(baseUrl, options) {
313
- if (WSRE.test(baseUrl)) {
314
- return wsClient(baseUrl, options);
315
- } else {
316
- return httpClient(baseUrl, options);
317
- }
318
- }
319
- module.exports = GraffyClient;