@graffy/server 0.15.16 → 0.15.19-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Readme.md +1 -1
- package/index.cjs +34 -30
- package/index.mjs +11 -6
- package/package.json +4 -4
- package/types/httpServer.d.ts +12 -1
package/Readme.md
CHANGED
|
@@ -4,4 +4,4 @@ Node.js library for building an API for a Graffy store.
|
|
|
4
4
|
|
|
5
5
|
This creates an HTTP request handler for serving an API that is compatible with Graffy Client. The request handler can be used with the Node.js built-in http, https and http2 `createServer()` and with Express.js.
|
|
6
6
|
|
|
7
|
-
See [Graffy documentation](https://
|
|
7
|
+
See [Graffy documentation](https://graffy.org#/GraffyServer) for more.
|
package/index.cjs
CHANGED
|
@@ -23,22 +23,21 @@ exports[Symbol.toStringTag] = "Module";
|
|
|
23
23
|
var url = require("url");
|
|
24
24
|
var common = require("@graffy/common");
|
|
25
25
|
var debug = require("debug");
|
|
26
|
-
var
|
|
26
|
+
var ws = require("ws");
|
|
27
27
|
function _interopDefaultLegacy(e) {
|
|
28
28
|
return e && typeof e === "object" && "default" in e ? e : { "default": e };
|
|
29
29
|
}
|
|
30
30
|
var url__default = /* @__PURE__ */ _interopDefaultLegacy(url);
|
|
31
31
|
var debug__default = /* @__PURE__ */ _interopDefaultLegacy(debug);
|
|
32
|
-
var WebSocket__default = /* @__PURE__ */ _interopDefaultLegacy(WebSocket);
|
|
33
32
|
const log$1 = debug__default["default"]("graffy:server:http");
|
|
34
|
-
function server$1(store) {
|
|
33
|
+
function server$1(store, { auth } = {}) {
|
|
35
34
|
if (!store)
|
|
36
35
|
throw new Error("server.store_undef");
|
|
37
36
|
return async (req, res) => {
|
|
38
37
|
const parsed = url__default["default"].parse(req.url, true);
|
|
39
|
-
const query = parsed.query.q && common.decodeUrl(parsed.query.q);
|
|
40
38
|
const options = parsed.query.opts && !Array.isArray(parsed.query.opts) && common.deserialize(decodeURIComponent(parsed.query.opts));
|
|
41
39
|
if (req.method === "GET") {
|
|
40
|
+
const query = parsed.query.q && common.decodeUrl(parsed.query.q);
|
|
42
41
|
try {
|
|
43
42
|
if (req.headers["accept"] === "text/event-stream") {
|
|
44
43
|
res.setHeader("content-type", "text/event-stream");
|
|
@@ -79,7 +78,7 @@ data: ${e.message}
|
|
|
79
78
|
}
|
|
80
79
|
} else if (req.method === "POST") {
|
|
81
80
|
try {
|
|
82
|
-
const op =
|
|
81
|
+
const op = parsed.query.op;
|
|
83
82
|
if (op !== "write" && op !== "read") {
|
|
84
83
|
throw Error("httpServer.unsupported_op: " + op);
|
|
85
84
|
}
|
|
@@ -87,6 +86,11 @@ data: ${e.message}
|
|
|
87
86
|
for await (const chunk of req)
|
|
88
87
|
chunks.push(chunk);
|
|
89
88
|
const payload = common.deserialize(Buffer.concat(chunks).toString());
|
|
89
|
+
if (auth && !await auth(op, payload, options)) {
|
|
90
|
+
res.writeHead(401);
|
|
91
|
+
res.end("unauthorized");
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
90
94
|
const value = await store.call(op, payload, options);
|
|
91
95
|
res.writeHead(200);
|
|
92
96
|
res.end(common.serialize(value));
|
|
@@ -107,14 +111,14 @@ const PING_INTERVAL = 3e4;
|
|
|
107
111
|
function server(store) {
|
|
108
112
|
if (!store)
|
|
109
113
|
throw new Error("server.store_undef");
|
|
110
|
-
const wss = new
|
|
111
|
-
wss.on("connection", function connection(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
+
const wss = new ws.WebSocketServer({ noServer: true });
|
|
115
|
+
wss.on("connection", function connection(ws2) {
|
|
116
|
+
ws2.graffyStreams = {};
|
|
117
|
+
ws2.on("message", async function message(msg) {
|
|
114
118
|
try {
|
|
115
119
|
const [id, op, payload, options] = common.deserialize(msg);
|
|
116
120
|
if (id === ":pong") {
|
|
117
|
-
|
|
121
|
+
ws2.pingPending = false;
|
|
118
122
|
return;
|
|
119
123
|
}
|
|
120
124
|
switch (op) {
|
|
@@ -122,10 +126,10 @@ function server(store) {
|
|
|
122
126
|
case "write":
|
|
123
127
|
try {
|
|
124
128
|
const result = await store.call(op, payload, options);
|
|
125
|
-
|
|
129
|
+
ws2.send(common.serialize([id, null, result]));
|
|
126
130
|
} catch (e) {
|
|
127
131
|
log(op + "error:" + e.message + " " + payload);
|
|
128
|
-
|
|
132
|
+
ws2.send(common.serialize([id, e.message]));
|
|
129
133
|
}
|
|
130
134
|
break;
|
|
131
135
|
case "watch":
|
|
@@ -133,44 +137,44 @@ function server(store) {
|
|
|
133
137
|
const stream = store.call("watch", payload, __spreadProps(__spreadValues({}, options), {
|
|
134
138
|
raw: true
|
|
135
139
|
}));
|
|
136
|
-
|
|
140
|
+
ws2.graffyStreams[id] = stream;
|
|
137
141
|
for await (const value of stream) {
|
|
138
|
-
|
|
142
|
+
ws2.send(common.serialize([id, null, value]));
|
|
139
143
|
}
|
|
140
144
|
} catch (e) {
|
|
141
145
|
log(op + "error:" + e.message + " " + payload);
|
|
142
|
-
|
|
146
|
+
ws2.send(common.serialize([id, e.message]));
|
|
143
147
|
}
|
|
144
148
|
break;
|
|
145
149
|
case "unwatch":
|
|
146
|
-
if (!
|
|
150
|
+
if (!ws2.graffyStreams[id])
|
|
147
151
|
break;
|
|
148
|
-
|
|
149
|
-
delete
|
|
152
|
+
ws2.graffyStreams[id].return();
|
|
153
|
+
delete ws2.graffyStreams[id];
|
|
150
154
|
break;
|
|
151
155
|
}
|
|
152
156
|
} catch (_) {
|
|
153
|
-
|
|
157
|
+
ws2.close();
|
|
154
158
|
}
|
|
155
159
|
});
|
|
156
|
-
|
|
157
|
-
for (const id in
|
|
158
|
-
|
|
159
|
-
delete
|
|
160
|
+
ws2.on("close", () => {
|
|
161
|
+
for (const id in ws2.graffyStreams) {
|
|
162
|
+
ws2.graffyStreams[id].return();
|
|
163
|
+
delete ws2.graffyStreams[id];
|
|
160
164
|
}
|
|
161
165
|
});
|
|
162
166
|
});
|
|
163
167
|
setInterval(function ping() {
|
|
164
|
-
wss.clients.forEach(function each(
|
|
165
|
-
if (
|
|
166
|
-
return
|
|
167
|
-
|
|
168
|
-
|
|
168
|
+
wss.clients.forEach(function each(ws2) {
|
|
169
|
+
if (ws2.pingPending)
|
|
170
|
+
return ws2.terminate();
|
|
171
|
+
ws2.pingPending = true;
|
|
172
|
+
ws2.send(common.serialize([":ping", Date.now()]));
|
|
169
173
|
});
|
|
170
174
|
}, PING_INTERVAL);
|
|
171
175
|
return async (request, socket, head) => {
|
|
172
|
-
wss.handleUpgrade(request, socket, head, function done(
|
|
173
|
-
wss.emit("connection",
|
|
176
|
+
wss.handleUpgrade(request, socket, head, function done(ws2) {
|
|
177
|
+
wss.emit("connection", ws2, request);
|
|
174
178
|
});
|
|
175
179
|
};
|
|
176
180
|
}
|
package/index.mjs
CHANGED
|
@@ -18,18 +18,18 @@ var __spreadValues = (a, b) => {
|
|
|
18
18
|
};
|
|
19
19
|
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
20
|
import url from "url";
|
|
21
|
-
import {
|
|
21
|
+
import { deserialize, decodeUrl, serialize } from "@graffy/common";
|
|
22
22
|
import debug from "debug";
|
|
23
|
-
import
|
|
23
|
+
import { WebSocketServer } from "ws";
|
|
24
24
|
const log$1 = debug("graffy:server:http");
|
|
25
|
-
function server$1(store) {
|
|
25
|
+
function server$1(store, { auth } = {}) {
|
|
26
26
|
if (!store)
|
|
27
27
|
throw new Error("server.store_undef");
|
|
28
28
|
return async (req, res) => {
|
|
29
29
|
const parsed = url.parse(req.url, true);
|
|
30
|
-
const query = parsed.query.q && decodeUrl(parsed.query.q);
|
|
31
30
|
const options = parsed.query.opts && !Array.isArray(parsed.query.opts) && deserialize(decodeURIComponent(parsed.query.opts));
|
|
32
31
|
if (req.method === "GET") {
|
|
32
|
+
const query = parsed.query.q && decodeUrl(parsed.query.q);
|
|
33
33
|
try {
|
|
34
34
|
if (req.headers["accept"] === "text/event-stream") {
|
|
35
35
|
res.setHeader("content-type", "text/event-stream");
|
|
@@ -70,7 +70,7 @@ data: ${e.message}
|
|
|
70
70
|
}
|
|
71
71
|
} else if (req.method === "POST") {
|
|
72
72
|
try {
|
|
73
|
-
const op =
|
|
73
|
+
const op = parsed.query.op;
|
|
74
74
|
if (op !== "write" && op !== "read") {
|
|
75
75
|
throw Error("httpServer.unsupported_op: " + op);
|
|
76
76
|
}
|
|
@@ -78,6 +78,11 @@ data: ${e.message}
|
|
|
78
78
|
for await (const chunk of req)
|
|
79
79
|
chunks.push(chunk);
|
|
80
80
|
const payload = deserialize(Buffer.concat(chunks).toString());
|
|
81
|
+
if (auth && !await auth(op, payload, options)) {
|
|
82
|
+
res.writeHead(401);
|
|
83
|
+
res.end("unauthorized");
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
81
86
|
const value = await store.call(op, payload, options);
|
|
82
87
|
res.writeHead(200);
|
|
83
88
|
res.end(serialize(value));
|
|
@@ -98,7 +103,7 @@ const PING_INTERVAL = 3e4;
|
|
|
98
103
|
function server(store) {
|
|
99
104
|
if (!store)
|
|
100
105
|
throw new Error("server.store_undef");
|
|
101
|
-
const wss = new
|
|
106
|
+
const wss = new WebSocketServer({ noServer: true });
|
|
102
107
|
wss.on("connection", function connection(ws) {
|
|
103
108
|
ws.graffyStreams = {};
|
|
104
109
|
ws.on("message", async function message(msg) {
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@graffy/server",
|
|
3
3
|
"description": "Node.js library for building an API for a Graffy store.",
|
|
4
4
|
"author": "aravind (https://github.com/aravindet)",
|
|
5
|
-
"version": "0.15.
|
|
5
|
+
"version": "0.15.19-alpha.1",
|
|
6
6
|
"main": "./index.cjs",
|
|
7
7
|
"exports": {
|
|
8
8
|
"import": "./index.mjs",
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
},
|
|
17
17
|
"license": "Apache-2.0",
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@graffy/common": "0.15.
|
|
20
|
-
"debug": "^4.3.
|
|
21
|
-
"ws": "^
|
|
19
|
+
"@graffy/common": "0.15.19-alpha.1",
|
|
20
|
+
"debug": "^4.3.3",
|
|
21
|
+
"ws": "^8.4.2"
|
|
22
22
|
}
|
|
23
23
|
}
|
package/types/httpServer.d.ts
CHANGED
|
@@ -1 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import('@graffy/core').default} GraffyStore
|
|
3
|
+
* @param {GraffyStore} store
|
|
4
|
+
* @param {{
|
|
5
|
+
* auth?: (operation: string, payload: any, options: any) => Promise<boolean>
|
|
6
|
+
* } | undefined} options
|
|
7
|
+
* @returns
|
|
8
|
+
*/
|
|
9
|
+
export default function server(store: any, { auth }?: {
|
|
10
|
+
auth?: (operation: string, payload: any, options: any) => Promise<boolean>;
|
|
11
|
+
}): (req: any, res: any) => Promise<void>;
|
|
12
|
+
export type GraffyStore = any;
|