@rxferrix/client 0.11.0 → 0.13.0
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/dist/auth.d.ts +6 -0
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +96 -28
- package/dist/auth.js.map +1 -1
- package/dist/client.d.ts +2 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +47 -15
- package/dist/client.js.map +1 -1
- package/dist/limits.d.ts +28 -0
- package/dist/limits.d.ts.map +1 -0
- package/dist/limits.js +58 -0
- package/dist/limits.js.map +1 -0
- package/dist/local_query_set.d.ts +20 -4
- package/dist/local_query_set.d.ts.map +1 -1
- package/dist/local_query_set.js +63 -18
- package/dist/local_query_set.js.map +1 -1
- package/dist/protocol.d.ts +1 -1
- package/dist/protocol.js +1 -1
- package/dist/web_socket_manager.d.ts +10 -0
- package/dist/web_socket_manager.d.ts.map +1 -1
- package/dist/web_socket_manager.js +22 -0
- package/dist/web_socket_manager.js.map +1 -1
- package/package.json +1 -1
- package/src/auth.ts +102 -25
- package/src/client.ts +45 -15
- package/src/limits.ts +62 -0
- package/src/local_query_set.ts +68 -18
- package/src/protocol.ts +1 -1
- package/src/web_socket_manager.ts +21 -0
package/dist/limits.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { RxFerrixError } from "./errors.js";
|
|
2
|
+
/**
|
|
3
|
+
* The server's limit on one message, in UTF-8 bytes (docs/PROTOCOL.md, Limits). A larger one is answered with a
|
|
4
|
+
* `FatalError` and the socket is closed, and since the client sends again what the server never answered, the same
|
|
5
|
+
* message would end every socket after it. So nothing that large is ever queued.
|
|
6
|
+
*/
|
|
7
|
+
export declare const MAX_MESSAGE_BYTES: number;
|
|
8
|
+
/**
|
|
9
|
+
* The server's limit on the arguments of all the queries one socket watches, as JSON (docs/PROTOCOL.md, Limits). The
|
|
10
|
+
* query that crosses it is answered with a `FatalError`, and every new socket would re-add the same set and get the
|
|
11
|
+
* same answer: the query is refused here instead.
|
|
12
|
+
*/
|
|
13
|
+
export declare const MAX_QUERY_ARGS_BYTES: number;
|
|
14
|
+
/**
|
|
15
|
+
* How much of a `ModifyQuerySet` its queries' paths and arguments may take, in characters of their canonical JSON.
|
|
16
|
+
* A query set is re-sent whole on every new socket; this splits it into messages well under the limit (a character
|
|
17
|
+
* is at most three bytes, and escaping can add a little).
|
|
18
|
+
*/
|
|
19
|
+
export declare const MODIFY_QUERY_SET_CHARS = 400000;
|
|
20
|
+
/** The length of `s` as UTF-8. */
|
|
21
|
+
export declare function utf8Length(s: string): number;
|
|
22
|
+
/** About what a `Remove` takes in a `ModifyQuerySet`, in characters. */
|
|
23
|
+
export declare const REMOVE_CHARS = 40;
|
|
24
|
+
/** The error for one query too many, by the size of their arguments ({@link MAX_QUERY_ARGS_BYTES}). */
|
|
25
|
+
export declare function tooMuchWatched(udfPath: string): RxFerrixError;
|
|
26
|
+
/** The error for a call whose arguments (`json`: their JSON) don't fit in one message, or null. */
|
|
27
|
+
export declare function tooLarge(udfPath: string, json: string): RxFerrixError | null;
|
|
28
|
+
//# sourceMappingURL=limits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../src/limits.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,QAAkB,CAAC;AACjD;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,QAAkB,CAAC;AAGpD;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,SAAU,CAAC;AAE9C,kCAAkC;AAClC,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAa5C;AAED,wEAAwE;AACxE,eAAO,MAAM,YAAY,KAAK,CAAC;AAE/B,uGAAuG;AACvG,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAM7D;AAED,mGAAmG;AACnG,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAS5E"}
|
package/dist/limits.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { RxFerrixError } from "./errors.js";
|
|
2
|
+
/**
|
|
3
|
+
* The server's limit on one message, in UTF-8 bytes (docs/PROTOCOL.md, Limits). A larger one is answered with a
|
|
4
|
+
* `FatalError` and the socket is closed, and since the client sends again what the server never answered, the same
|
|
5
|
+
* message would end every socket after it. So nothing that large is ever queued.
|
|
6
|
+
*/
|
|
7
|
+
export const MAX_MESSAGE_BYTES = 2 * 1024 * 1024;
|
|
8
|
+
/**
|
|
9
|
+
* The server's limit on the arguments of all the queries one socket watches, as JSON (docs/PROTOCOL.md, Limits). The
|
|
10
|
+
* query that crosses it is answered with a `FatalError`, and every new socket would re-add the same set and get the
|
|
11
|
+
* same answer: the query is refused here instead.
|
|
12
|
+
*/
|
|
13
|
+
export const MAX_QUERY_ARGS_BYTES = 8 * 1024 * 1024;
|
|
14
|
+
/** Room kept in a message for what goes around the arguments: its type, ids and the function's path. */
|
|
15
|
+
const ENVELOPE_BYTES = 1024;
|
|
16
|
+
/**
|
|
17
|
+
* How much of a `ModifyQuerySet` its queries' paths and arguments may take, in characters of their canonical JSON.
|
|
18
|
+
* A query set is re-sent whole on every new socket; this splits it into messages well under the limit (a character
|
|
19
|
+
* is at most three bytes, and escaping can add a little).
|
|
20
|
+
*/
|
|
21
|
+
export const MODIFY_QUERY_SET_CHARS = 400_000;
|
|
22
|
+
/** The length of `s` as UTF-8. */
|
|
23
|
+
export function utf8Length(s) {
|
|
24
|
+
let bytes = 0;
|
|
25
|
+
for (let i = 0; i < s.length; i++) {
|
|
26
|
+
const c = s.charCodeAt(i);
|
|
27
|
+
if (c < 0x80)
|
|
28
|
+
bytes += 1;
|
|
29
|
+
else if (c < 0x800)
|
|
30
|
+
bytes += 2;
|
|
31
|
+
else if (c >= 0xd800 && c <= 0xdbff && i + 1 < s.length) {
|
|
32
|
+
// A surrogate pair: four bytes for the two code units.
|
|
33
|
+
bytes += 4;
|
|
34
|
+
i++;
|
|
35
|
+
}
|
|
36
|
+
else
|
|
37
|
+
bytes += 3;
|
|
38
|
+
}
|
|
39
|
+
return bytes;
|
|
40
|
+
}
|
|
41
|
+
/** About what a `Remove` takes in a `ModifyQuerySet`, in characters. */
|
|
42
|
+
export const REMOVE_CHARS = 40;
|
|
43
|
+
/** The error for one query too many, by the size of their arguments ({@link MAX_QUERY_ARGS_BYTES}). */
|
|
44
|
+
export function tooMuchWatched(udfPath) {
|
|
45
|
+
return new RxFerrixError(`Can't watch "${udfPath}" as well: the queries watched at once may hold at most ` +
|
|
46
|
+
`${MAX_QUERY_ARGS_BYTES >> 20} MiB of arguments`, { code: "args_too_large" });
|
|
47
|
+
}
|
|
48
|
+
/** The error for a call whose arguments (`json`: their JSON) don't fit in one message, or null. */
|
|
49
|
+
export function tooLarge(udfPath, json) {
|
|
50
|
+
const room = MAX_MESSAGE_BYTES - ENVELOPE_BYTES - udfPath.length;
|
|
51
|
+
// Each character is one to three bytes: only what is in between needs counting.
|
|
52
|
+
if (json.length * 3 <= room)
|
|
53
|
+
return null;
|
|
54
|
+
if (json.length <= room && utf8Length(json) <= room)
|
|
55
|
+
return null;
|
|
56
|
+
return new RxFerrixError(`The arguments of "${udfPath}" are too large: a message to the server holds at most ${MAX_MESSAGE_BYTES >> 20} MiB`, { code: "args_too_large" });
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=limits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limits.js","sourceRoot":"","sources":["../src/limits.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AACjD;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AACpD,wGAAwG;AACxG,MAAM,cAAc,GAAG,IAAI,CAAC;AAC5B;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,OAAO,CAAC;AAE9C,kCAAkC;AAClC,MAAM,UAAU,UAAU,CAAC,CAAS;IAClC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,MAAM,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC1B,IAAI,CAAC,GAAG,IAAI;YAAE,KAAK,IAAI,CAAC,CAAC;aACpB,IAAI,CAAC,GAAG,KAAK;YAAE,KAAK,IAAI,CAAC,CAAC;aAC1B,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC;YACxD,uDAAuD;YACvD,KAAK,IAAI,CAAC,CAAC;YACX,CAAC,EAAE,CAAC;QACN,CAAC;;YAAM,KAAK,IAAI,CAAC,CAAC;IACpB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,wEAAwE;AACxE,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,CAAC;AAE/B,uGAAuG;AACvG,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,OAAO,IAAI,aAAa,CACtB,gBAAgB,OAAO,0DAA0D;QAC/E,GAAG,oBAAoB,IAAI,EAAE,mBAAmB,EAClD,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAC3B,CAAC;AACJ,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,QAAQ,CAAC,OAAe,EAAE,IAAY;IACpD,MAAM,IAAI,GAAG,iBAAiB,GAAG,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;IACjE,gFAAgF;IAChF,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACzC,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACjE,OAAO,IAAI,aAAa,CACtB,qBAAqB,OAAO,0DAA0D,iBAAiB,IAAI,EAAE,MAAM,EACnH,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAC3B,CAAC;AACJ,CAAC"}
|
|
@@ -8,10 +8,16 @@ export interface LocalQuery {
|
|
|
8
8
|
refCount: number;
|
|
9
9
|
/** Whether an `Add` for this query is part of the server's query set on the current socket. */
|
|
10
10
|
onServer: boolean;
|
|
11
|
+
/** About what its arguments count for on the server ({@link LocalQuerySet.argsBytes}). */
|
|
12
|
+
readonly bytes: number;
|
|
11
13
|
}
|
|
12
14
|
export interface FlushResult {
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
+
/**
|
|
16
|
+
* The messages to send, in order; none when nothing changed (or nothing can be sent right now). Usually one. A
|
|
17
|
+
* query set too large for one message (it is sent whole on every new socket) is split into several, each one
|
|
18
|
+
* version after the last.
|
|
19
|
+
*/
|
|
20
|
+
messages: ModifyQuerySetMessage[];
|
|
15
21
|
/** Queries dropped locally by this flush (their last watcher left). Their results should be discarded. */
|
|
16
22
|
removed: QueryId[];
|
|
17
23
|
}
|
|
@@ -31,6 +37,16 @@ export declare class LocalQuerySet {
|
|
|
31
37
|
private readonly pendingRemoves;
|
|
32
38
|
/** The `newVersion` of the last ModifyQuerySet sent on this socket. */
|
|
33
39
|
private querySetVersion;
|
|
40
|
+
/** The sum of {@link LocalQuery.bytes} over the queries that have watchers. */
|
|
41
|
+
private bytes;
|
|
42
|
+
/**
|
|
43
|
+
* About what the server counts for the arguments of the watched queries (it caps their JSON at 8 MiB a socket).
|
|
44
|
+
* An upper bound: each query counts with its token, which holds its path as well. A query whose last watcher
|
|
45
|
+
* left no longer counts, though it is tracked until the next flush: that flush removes it before it adds anything.
|
|
46
|
+
*/
|
|
47
|
+
get argsBytes(): number;
|
|
48
|
+
/** What watching the query `token` would add to {@link argsBytes}; nothing if it has watchers already. */
|
|
49
|
+
costOf(token: QueryToken): number;
|
|
34
50
|
/** Adds a watcher; returns the query (created if needed) and whether a flush is needed. */
|
|
35
51
|
addRef(udfPath: string, args: Record<string, unknown>): {
|
|
36
52
|
query: LocalQuery;
|
|
@@ -44,8 +60,8 @@ export declare class LocalQuerySet {
|
|
|
44
60
|
queries(): IterableIterator<LocalQuery>;
|
|
45
61
|
get size(): number;
|
|
46
62
|
/**
|
|
47
|
-
* Drops queries without watchers and, if `canSend`, builds the
|
|
48
|
-
* in line with the local one (bumping the query set version).
|
|
63
|
+
* Drops queries without watchers and, if `canSend`, builds the ModifyQuerySets that bring the server's query set
|
|
64
|
+
* in line with the local one (bumping the query set version once per message).
|
|
49
65
|
*/
|
|
50
66
|
flush(canSend: boolean): FlushResult;
|
|
51
67
|
/** The server state is fresh on a new socket: nothing is subscribed and the query set version is 0. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local_query_set.d.ts","sourceRoot":"","sources":["../src/local_query_set.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"local_query_set.d.ts","sourceRoot":"","sources":["../src/local_query_set.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE7D,OAAO,KAAK,EAAE,qBAAqB,EAAE,OAAO,EAAwB,MAAM,eAAe,CAAC;AAE1F,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,+FAA+F;IAC/F,QAAQ,EAAE,OAAO,CAAC;IAClB,0FAA0F;IAC1F,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,QAAQ,EAAE,qBAAqB,EAAE,CAAC;IAClC,0GAA0G;IAC1G,OAAO,EAAE,OAAO,EAAE,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;IAC7D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkC;IACvD,2FAA2F;IAC3F,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAsB;IACrD,uEAAuE;IACvE,OAAO,CAAC,eAAe,CAAK;IAC5B,+EAA+E;IAC/E,OAAO,CAAC,KAAK,CAAK;IAElB;;;;OAIG;IACH,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,0GAA0G;IAC1G,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM;IAMjC,2FAA2F;IAC3F,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;QAAE,KAAK,EAAE,UAAU,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE;IAwBlG,yGAAyG;IACzG,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO;IAQrC,GAAG,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS;IAI9C,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS;IAIjD,2GAA2G;IAC3G,OAAO,IAAI,gBAAgB,CAAC,UAAU,CAAC;IAIvC,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;OAGG;IACH,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,WAAW;IAmDpC,uGAAuG;IACvG,iBAAiB,IAAI,IAAI;IAMzB,uEAAuE;IACvE,IAAI,mBAAmB,IAAI,MAAM,CAEhC;CACF"}
|
package/dist/local_query_set.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { queryToken } from "./canonical.js";
|
|
2
|
+
import { MODIFY_QUERY_SET_CHARS, REMOVE_CHARS, utf8Length } from "./limits.js";
|
|
2
3
|
/**
|
|
3
4
|
* The set of queries this client wants to be subscribed to.
|
|
4
5
|
*
|
|
@@ -15,11 +16,30 @@ export class LocalQuerySet {
|
|
|
15
16
|
pendingRemoves = new Set();
|
|
16
17
|
/** The `newVersion` of the last ModifyQuerySet sent on this socket. */
|
|
17
18
|
querySetVersion = 0;
|
|
19
|
+
/** The sum of {@link LocalQuery.bytes} over the queries that have watchers. */
|
|
20
|
+
bytes = 0;
|
|
21
|
+
/**
|
|
22
|
+
* About what the server counts for the arguments of the watched queries (it caps their JSON at 8 MiB a socket).
|
|
23
|
+
* An upper bound: each query counts with its token, which holds its path as well. A query whose last watcher
|
|
24
|
+
* left no longer counts, though it is tracked until the next flush: that flush removes it before it adds anything.
|
|
25
|
+
*/
|
|
26
|
+
get argsBytes() {
|
|
27
|
+
return this.bytes;
|
|
28
|
+
}
|
|
29
|
+
/** What watching the query `token` would add to {@link argsBytes}; nothing if it has watchers already. */
|
|
30
|
+
costOf(token) {
|
|
31
|
+
const tracked = this.byToken.get(token);
|
|
32
|
+
if (!tracked)
|
|
33
|
+
return utf8Length(token);
|
|
34
|
+
return tracked.refCount > 0 ? 0 : tracked.bytes;
|
|
35
|
+
}
|
|
18
36
|
/** Adds a watcher; returns the query (created if needed) and whether a flush is needed. */
|
|
19
37
|
addRef(udfPath, args) {
|
|
20
38
|
const token = queryToken(udfPath, args);
|
|
21
39
|
const existing = this.byToken.get(token);
|
|
22
40
|
if (existing) {
|
|
41
|
+
if (existing.refCount === 0)
|
|
42
|
+
this.bytes += existing.bytes;
|
|
23
43
|
existing.refCount += 1;
|
|
24
44
|
// refCount went 0 -> 1 before the flush: the query is revived without any server traffic.
|
|
25
45
|
return { query: existing, needsFlush: false };
|
|
@@ -31,7 +51,9 @@ export class LocalQuerySet {
|
|
|
31
51
|
args,
|
|
32
52
|
refCount: 1,
|
|
33
53
|
onServer: false,
|
|
54
|
+
bytes: utf8Length(token),
|
|
34
55
|
};
|
|
56
|
+
this.bytes += query.bytes;
|
|
35
57
|
this.byToken.set(token, query);
|
|
36
58
|
this.byId.set(query.queryId, query);
|
|
37
59
|
return { query, needsFlush: true };
|
|
@@ -41,6 +63,8 @@ export class LocalQuerySet {
|
|
|
41
63
|
const query = this.byToken.get(token);
|
|
42
64
|
if (!query)
|
|
43
65
|
return false;
|
|
66
|
+
if (query.refCount === 1)
|
|
67
|
+
this.bytes -= query.bytes;
|
|
44
68
|
query.refCount = Math.max(0, query.refCount - 1);
|
|
45
69
|
return query.refCount === 0;
|
|
46
70
|
}
|
|
@@ -58,8 +82,8 @@ export class LocalQuerySet {
|
|
|
58
82
|
return this.byToken.size;
|
|
59
83
|
}
|
|
60
84
|
/**
|
|
61
|
-
* Drops queries without watchers and, if `canSend`, builds the
|
|
62
|
-
* in line with the local one (bumping the query set version).
|
|
85
|
+
* Drops queries without watchers and, if `canSend`, builds the ModifyQuerySets that bring the server's query set
|
|
86
|
+
* in line with the local one (bumping the query set version once per message).
|
|
63
87
|
*/
|
|
64
88
|
flush(canSend) {
|
|
65
89
|
const removed = [];
|
|
@@ -73,25 +97,46 @@ export class LocalQuerySet {
|
|
|
73
97
|
this.pendingRemoves.add(query.queryId);
|
|
74
98
|
}
|
|
75
99
|
if (!canSend)
|
|
76
|
-
return {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
100
|
+
return { messages: [], removed };
|
|
101
|
+
// Split so that no message outgrows the server's limit. The removes go first: the server applies a message in
|
|
102
|
+
// order and caps what is live after each step, so a set near the cap is swapped by making room before using it.
|
|
103
|
+
const batches = [[]];
|
|
104
|
+
let chars = 0;
|
|
105
|
+
for (const queryId of this.pendingRemoves) {
|
|
106
|
+
let batch = batches[batches.length - 1];
|
|
107
|
+
if (chars + REMOVE_CHARS > MODIFY_QUERY_SET_CHARS) {
|
|
108
|
+
batch = [];
|
|
109
|
+
batches.push(batch);
|
|
110
|
+
chars = 0;
|
|
82
111
|
}
|
|
112
|
+
batch.push({ type: "Remove", queryId });
|
|
113
|
+
chars += REMOVE_CHARS;
|
|
83
114
|
}
|
|
84
|
-
for (const queryId of this.pendingRemoves)
|
|
85
|
-
modifications.push({ type: "Remove", queryId });
|
|
86
115
|
this.pendingRemoves.clear();
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
116
|
+
for (const query of this.byToken.values()) {
|
|
117
|
+
if (query.onServer)
|
|
118
|
+
continue;
|
|
119
|
+
// The token is the path and the canonical JSON of the arguments: about what the Add takes on the wire.
|
|
120
|
+
const size = query.token.length;
|
|
121
|
+
let batch = batches[batches.length - 1];
|
|
122
|
+
if (batch.length > 0 && chars + size > MODIFY_QUERY_SET_CHARS) {
|
|
123
|
+
batch = [];
|
|
124
|
+
batches.push(batch);
|
|
125
|
+
chars = 0;
|
|
126
|
+
}
|
|
127
|
+
batch.push({ type: "Add", queryId: query.queryId, udfPath: query.udfPath, args: query.args });
|
|
128
|
+
chars += size;
|
|
129
|
+
query.onServer = true;
|
|
130
|
+
}
|
|
131
|
+
const messages = [];
|
|
132
|
+
for (const modifications of batches) {
|
|
133
|
+
if (modifications.length === 0)
|
|
134
|
+
continue;
|
|
135
|
+
const baseVersion = this.querySetVersion;
|
|
136
|
+
this.querySetVersion += 1;
|
|
137
|
+
messages.push({ type: "ModifyQuerySet", baseVersion, newVersion: this.querySetVersion, modifications });
|
|
138
|
+
}
|
|
139
|
+
return { messages, removed };
|
|
95
140
|
}
|
|
96
141
|
/** The server state is fresh on a new socket: nothing is subscribed and the query set version is 0. */
|
|
97
142
|
resetForNewSocket() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local_query_set.js","sourceRoot":"","sources":["../src/local_query_set.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAmB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"local_query_set.js","sourceRoot":"","sources":["../src/local_query_set.ts"],"names":[],"mappings":"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"}
|
package/dist/protocol.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export type RequestId = number;
|
|
|
6
6
|
export type JSONValue = null | boolean | number | string | JSONValue[] | {
|
|
7
7
|
[key: string]: JSONValue;
|
|
8
8
|
};
|
|
9
|
-
export declare const CLIENT_VERSION = "0.
|
|
9
|
+
export declare const CLIENT_VERSION = "0.13.0";
|
|
10
10
|
export interface StateVersion {
|
|
11
11
|
querySet: number;
|
|
12
12
|
identity: number;
|
package/dist/protocol.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Wire types for the RxFerrix sync protocol (v1). See `docs/PROTOCOL.md` in the repository; that document is normative.
|
|
3
3
|
*/
|
|
4
|
-
export const CLIENT_VERSION = "0.
|
|
4
|
+
export const CLIENT_VERSION = "0.13.0";
|
|
5
5
|
export function versionsEqual(a, b) {
|
|
6
6
|
return a.querySet === b.querySet && a.identity === b.identity && a.ts === b.ts;
|
|
7
7
|
}
|
|
@@ -53,6 +53,9 @@ export declare class WebSocketManager {
|
|
|
53
53
|
private _hasEverConnected;
|
|
54
54
|
private lastCloseReason;
|
|
55
55
|
private retries;
|
|
56
|
+
/** `FatalError`s in the current streak, and when the last one came. */
|
|
57
|
+
private fatalErrors;
|
|
58
|
+
private lastFatalAt;
|
|
56
59
|
private reconnectTimer;
|
|
57
60
|
private watchdogTimer;
|
|
58
61
|
private connectTimer;
|
|
@@ -76,6 +79,13 @@ export declare class WebSocketManager {
|
|
|
76
79
|
resume(): void;
|
|
77
80
|
/** Drops the current socket and reconnects after a backoff delay. */
|
|
78
81
|
reconnect(reason: string): void;
|
|
82
|
+
/**
|
|
83
|
+
* The server refused something this client sent and ended the socket (`FatalError`). The client will send it
|
|
84
|
+
* again, or something like it, on the next socket, so each refusal that follows the last within a minute waits
|
|
85
|
+
* longer than the one before: nothing a healthy-looking socket says in between (its first Transition arrives
|
|
86
|
+
* before the refusal) starts the delays over.
|
|
87
|
+
*/
|
|
88
|
+
reconnectAfterFatal(reason: string): void;
|
|
79
89
|
/** Permanently closes the socket. */
|
|
80
90
|
stop(): void;
|
|
81
91
|
private rawSend;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web_socket_manager.d.ts","sourceRoot":"","sources":["../src/web_socket_manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AACvF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,wGAAwG;AACxG,eAAO,MAAM,4BAA4B,QAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"web_socket_manager.d.ts","sourceRoot":"","sources":["../src/web_socket_manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,8 @@ import { CLIENT_VERSION } from "./protocol.js";
|
|
|
3
3
|
export const SERVER_INACTIVITY_TIMEOUT_MS = 30_000;
|
|
4
4
|
const INITIAL_BACKOFF_MS = 250;
|
|
5
5
|
const MAX_BACKOFF_MS = 16_000;
|
|
6
|
+
/** `FatalError`s closer together than this are one streak ({@link WebSocketManager.reconnectAfterFatal}). */
|
|
7
|
+
const FATAL_STREAK_MS = 60_000;
|
|
6
8
|
/**
|
|
7
9
|
* A socket that hasn't opened after this long is dropped and retried (a black-holed connect would otherwise hang
|
|
8
10
|
* forever). As long as the silence threshold: a server that takes longer than that to accept is as good as down.
|
|
@@ -36,6 +38,9 @@ export class WebSocketManager {
|
|
|
36
38
|
_hasEverConnected = false;
|
|
37
39
|
lastCloseReason = null;
|
|
38
40
|
retries = 0;
|
|
41
|
+
/** `FatalError`s in the current streak, and when the last one came. */
|
|
42
|
+
fatalErrors = 0;
|
|
43
|
+
lastFatalAt = 0;
|
|
39
44
|
reconnectTimer = null;
|
|
40
45
|
watchdogTimer = null;
|
|
41
46
|
connectTimer = null;
|
|
@@ -114,6 +119,23 @@ export class WebSocketManager {
|
|
|
114
119
|
this.closeCurrent(reason);
|
|
115
120
|
this.scheduleReconnect(reason);
|
|
116
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* The server refused something this client sent and ended the socket (`FatalError`). The client will send it
|
|
124
|
+
* again, or something like it, on the next socket, so each refusal that follows the last within a minute waits
|
|
125
|
+
* longer than the one before: nothing a healthy-looking socket says in between (its first Transition arrives
|
|
126
|
+
* before the refusal) starts the delays over.
|
|
127
|
+
*/
|
|
128
|
+
reconnectAfterFatal(reason) {
|
|
129
|
+
if (this._state === "stopped")
|
|
130
|
+
return;
|
|
131
|
+
const now = Date.now();
|
|
132
|
+
if (now - this.lastFatalAt > FATAL_STREAK_MS)
|
|
133
|
+
this.fatalErrors = 0;
|
|
134
|
+
this.lastFatalAt = now;
|
|
135
|
+
this.retries = Math.max(this.retries, this.fatalErrors);
|
|
136
|
+
this.fatalErrors += 1;
|
|
137
|
+
this.reconnect(reason);
|
|
138
|
+
}
|
|
117
139
|
/** Permanently closes the socket. */
|
|
118
140
|
stop() {
|
|
119
141
|
if (this._state === "stopped")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web_socket_manager.js","sourceRoot":"","sources":["../src/web_socket_manager.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"web_socket_manager.js","sourceRoot":"","sources":["../src/web_socket_manager.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/auth.ts
CHANGED
|
@@ -171,8 +171,23 @@ interface StoredTokens {
|
|
|
171
171
|
|
|
172
172
|
/** Refresh access tokens that expire within this window instead of using them. */
|
|
173
173
|
const EXPIRY_LEEWAY_MS = 10_000;
|
|
174
|
-
/** A refresh
|
|
174
|
+
/** A refresh that hasn't been answered by then is given up (a black-holed connection after a network switch). */
|
|
175
175
|
const REFRESH_TIMEOUT_MS = 10_000;
|
|
176
|
+
/**
|
|
177
|
+
* While a refresh request is unanswered, the same request is sent again at these times after the first, next to the
|
|
178
|
+
* ones already out: the first answer to arrive is used. The server may have rotated the token for a request whose
|
|
179
|
+
* answer never arrives; it answers the same request the same way for 10 seconds after that (its default
|
|
180
|
+
* `refresh_reuse_grace`) and revokes the session for a rotated token presented later. Asking again early is the only
|
|
181
|
+
* way to still get that answer, and it costs a request that is merely slow nothing: it is not given up for it.
|
|
182
|
+
*/
|
|
183
|
+
const REFRESH_ASK_AGAIN_MS = [3_000, 6_000];
|
|
184
|
+
|
|
185
|
+
/** What `POST /api/auth/refresh` answered. */
|
|
186
|
+
interface RefreshAnswer {
|
|
187
|
+
ok: boolean;
|
|
188
|
+
status: number;
|
|
189
|
+
body: unknown;
|
|
190
|
+
}
|
|
176
191
|
|
|
177
192
|
function defaultStorage(): AuthStorage {
|
|
178
193
|
try {
|
|
@@ -409,37 +424,99 @@ export class RxFerrixAuth {
|
|
|
409
424
|
if (!before) return null;
|
|
410
425
|
const adopted = await this.adoptNewerStoredTokens(before);
|
|
411
426
|
if (adopted) return adopted;
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
const
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
// Offline: keep the session; the next reconnect or AuthError tries again.
|
|
425
|
-
throw new RxFerrixError("Could not reach the server to refresh the session", { code: "network_error", cause: e });
|
|
426
|
-
}
|
|
427
|
-
const body = (await res.json().catch(() => null)) as unknown;
|
|
428
|
-
if (epoch !== this.epoch || this.tokens !== t) return this.tokens?.accessToken ?? null;
|
|
429
|
-
if (res.ok) {
|
|
430
|
-
const next = toStored(body as AuthTokens);
|
|
431
|
-
await this.saveTokens(next);
|
|
432
|
-
return next.accessToken;
|
|
433
|
-
}
|
|
434
|
-
if (res.status === 401) {
|
|
427
|
+
// With our own tokens, then with each newer pair another tab turns out to have stored (a couple at most).
|
|
428
|
+
for (let round = 0; round < 3; round++) {
|
|
429
|
+
const t = this.tokens;
|
|
430
|
+
if (!t) return null;
|
|
431
|
+
const answer = await this.postRefresh(t.refreshToken, () => epoch === this.epoch && this.tokens === t);
|
|
432
|
+
if (epoch !== this.epoch || this.tokens !== t) return this.tokens?.accessToken ?? null;
|
|
433
|
+
if (answer.ok) {
|
|
434
|
+
const next = toStored(answer.body as AuthTokens);
|
|
435
|
+
await this.saveTokens(next);
|
|
436
|
+
return next.accessToken;
|
|
437
|
+
}
|
|
438
|
+
if (answer.status !== 401) throw errorFrom(answer.status, answer.body);
|
|
435
439
|
// Lost a race with another tab that rotated the token a moment ago: use its tokens.
|
|
436
440
|
const raced = await this.adoptNewerStoredTokens(t);
|
|
437
441
|
if (raced) return raced;
|
|
442
|
+
// Its tokens are newer than ours but their access token is used up as well: refresh with them. Signing out
|
|
443
|
+
// here would wipe them for every tab. Only if they are newer: an older pair left in storage (a write that
|
|
444
|
+
// failed) is a rotated token, and presenting it would revoke the session.
|
|
445
|
+
const stored = this.tokens;
|
|
446
|
+
if (stored !== t && stored !== null && stored.expiresAt > t.expiresAt) continue;
|
|
438
447
|
await this.saveTokens(null);
|
|
439
448
|
this.setState(SIGNED_OUT_STATE);
|
|
440
449
|
return null;
|
|
441
450
|
}
|
|
442
|
-
|
|
451
|
+
// Tabs kept handing each other tokens that were refused: not an answer. The caller tries again later.
|
|
452
|
+
throw new RxFerrixError("Could not refresh the session", { code: "network_error" });
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* `POST /api/auth/refresh`, sent again while it is unanswered (see {@link REFRESH_ASK_AGAIN_MS}) and once more
|
|
457
|
+
* right away when a request fails outright; the first complete answer wins. An answer whose body can't be read
|
|
458
|
+
* counts as none: the server may have rotated the token, and only asking again gets the new one.
|
|
459
|
+
*/
|
|
460
|
+
private postRefresh(refreshToken: string, stillWanted: () => boolean): Promise<RefreshAnswer> {
|
|
461
|
+
return new Promise<RefreshAnswer>((resolve, reject) => {
|
|
462
|
+
const abort = typeof AbortController === "function" ? new AbortController() : null;
|
|
463
|
+
const timers: ReturnType<typeof setTimeout>[] = [];
|
|
464
|
+
let asksLeft = REFRESH_ASK_AGAIN_MS.length;
|
|
465
|
+
let pending = 0;
|
|
466
|
+
let done = false;
|
|
467
|
+
const finish = (settle: () => void): void => {
|
|
468
|
+
if (done) return;
|
|
469
|
+
done = true;
|
|
470
|
+
for (const timer of timers) clearTimeout(timer);
|
|
471
|
+
settle();
|
|
472
|
+
// The requests still out: their answers are no longer needed (the server gives each the same one).
|
|
473
|
+
abort?.abort();
|
|
474
|
+
};
|
|
475
|
+
const fail = (cause: unknown): void =>
|
|
476
|
+
finish(() =>
|
|
477
|
+
// Offline: keep the session; the next reconnect or AuthError tries again.
|
|
478
|
+
reject(new RxFerrixError("Could not reach the server to refresh the session", { code: "network_error", cause })),
|
|
479
|
+
);
|
|
480
|
+
const ask = (): void => {
|
|
481
|
+
pending++;
|
|
482
|
+
const request = this.fetchImpl(`${this.baseUrl}/api/auth/refresh`, {
|
|
483
|
+
method: "POST",
|
|
484
|
+
headers: { "Content-Type": "application/json" },
|
|
485
|
+
body: JSON.stringify({ refreshToken }),
|
|
486
|
+
...(abort ? { signal: abort.signal } : {}),
|
|
487
|
+
}).then(async (res): Promise<RefreshAnswer> => {
|
|
488
|
+
const body = (await res.json().catch(() => null)) as unknown;
|
|
489
|
+
if (res.ok && body === null) throw new Error("the refresh answer could not be read");
|
|
490
|
+
return { ok: res.ok, status: res.status, body };
|
|
491
|
+
});
|
|
492
|
+
request.then(
|
|
493
|
+
(answer) => finish(() => resolve(answer)),
|
|
494
|
+
(cause: unknown) => {
|
|
495
|
+
pending--;
|
|
496
|
+
if (done) return;
|
|
497
|
+
// Failed outright (a network that just changed): the request may have arrived all the same.
|
|
498
|
+
if (asksLeft > 0 && stillWanted()) {
|
|
499
|
+
asksLeft--;
|
|
500
|
+
ask();
|
|
501
|
+
} else if (pending === 0) {
|
|
502
|
+
fail(cause);
|
|
503
|
+
}
|
|
504
|
+
},
|
|
505
|
+
);
|
|
506
|
+
};
|
|
507
|
+
for (const ms of REFRESH_ASK_AGAIN_MS) {
|
|
508
|
+
timers.push(
|
|
509
|
+
setTimeout(() => {
|
|
510
|
+
if (!done && asksLeft > 0 && stillWanted()) {
|
|
511
|
+
asksLeft--;
|
|
512
|
+
ask();
|
|
513
|
+
}
|
|
514
|
+
}, ms),
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
timers.push(setTimeout(() => fail(new Error(`no answer within ${REFRESH_TIMEOUT_MS} ms`)), REFRESH_TIMEOUT_MS));
|
|
518
|
+
ask();
|
|
519
|
+
});
|
|
443
520
|
}
|
|
444
521
|
|
|
445
522
|
private listenToOtherTabs(): void {
|