nucleus-core-ts 0.9.992 → 0.9.993
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/bin/cli.ts +131 -131
- package/dist/.build-ok +1 -1
- package/dist/client.js +1 -1
- package/dist/index.js +1 -1
- package/dist/src/Client/ApiCaller/client.d.ts +1 -0
- package/dist/src/Client/Proxy/httpProxy.js +88 -88
- package/dist/src/Client/Proxy/synthesizedAuth.js +10 -10
- package/dist/src/Client/Proxy/wsProxy.js +41 -41
- package/dist/src/Client/PubSub/usePubSub.js +97 -97
- package/dist/src/Client/PubSub/waitForReturn.js +29 -29
- package/dist/src/Client/Upload/progress.js +31 -31
- package/dist/src/Client/Upload/types.js +7 -7
- package/dist/src/Client/Upload/upload.js +21 -21
- package/package.json +1 -1
- package/scripts/generate-schema.ts +739 -739
- package/src/system.tables.json +5527 -5527
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Wait for the world to change, instead of retrying against a clock.
|
|
3
|
-
*
|
|
4
|
-
* A connection that has exhausted its attempts used to be dead until the person
|
|
5
|
-
* reloaded the page: ten tries with backoff is roughly three minutes, so a shut
|
|
6
|
-
* laptop, a lunch break or a slow deploy left realtime off for good while the
|
|
7
|
-
* page still looked alive.
|
|
8
|
-
*
|
|
9
|
-
* Retrying forever is not the answer either — that is precisely what produced a
|
|
10
|
-
* live install's reconnect storm. So this waits on events that mean something,
|
|
11
|
-
* and adds ONE slow backstop for the case the events cannot cover: a tab that
|
|
12
|
-
* is visible the whole time, on a machine that never went offline, while the
|
|
13
|
-
* API takes longer to come back than ten attempts allow. That tab receives no
|
|
14
|
-
* `visibilitychange` and no `online` — it would simply sit there dead for the
|
|
15
|
-
* rest of the day, which is the exact complaint this is meant to end. A single
|
|
16
|
-
* timer that fires minutes apart is not a storm; it is a floor.
|
|
17
|
-
*/ /**
|
|
18
|
-
* How long a tab that nobody touches waits before trying again on its own.
|
|
19
|
-
*
|
|
20
|
-
* Long enough that a hundred idle tabs cost the server nothing worth measuring;
|
|
21
|
-
* short enough that somebody who looks up from their work finds a live screen
|
|
22
|
-
* rather than a dead one.
|
|
1
|
+
/**
|
|
2
|
+
* Wait for the world to change, instead of retrying against a clock.
|
|
3
|
+
*
|
|
4
|
+
* A connection that has exhausted its attempts used to be dead until the person
|
|
5
|
+
* reloaded the page: ten tries with backoff is roughly three minutes, so a shut
|
|
6
|
+
* laptop, a lunch break or a slow deploy left realtime off for good while the
|
|
7
|
+
* page still looked alive.
|
|
8
|
+
*
|
|
9
|
+
* Retrying forever is not the answer either — that is precisely what produced a
|
|
10
|
+
* live install's reconnect storm. So this waits on events that mean something,
|
|
11
|
+
* and adds ONE slow backstop for the case the events cannot cover: a tab that
|
|
12
|
+
* is visible the whole time, on a machine that never went offline, while the
|
|
13
|
+
* API takes longer to come back than ten attempts allow. That tab receives no
|
|
14
|
+
* `visibilitychange` and no `online` — it would simply sit there dead for the
|
|
15
|
+
* rest of the day, which is the exact complaint this is meant to end. A single
|
|
16
|
+
* timer that fires minutes apart is not a storm; it is a floor.
|
|
17
|
+
*/ /**
|
|
18
|
+
* How long a tab that nobody touches waits before trying again on its own.
|
|
19
|
+
*
|
|
20
|
+
* Long enough that a hundred idle tabs cost the server nothing worth measuring;
|
|
21
|
+
* short enough that somebody who looks up from their work finds a live screen
|
|
22
|
+
* rather than a dead one.
|
|
23
23
|
*/ export const BACKSTOP_MS = 2 * 60 * 1000;
|
|
24
|
-
/**
|
|
25
|
-
* The events worth waking for. `focus` and `pageshow` are here because
|
|
26
|
-
* `visibilitychange` does not fire for a window that was merely behind another
|
|
27
|
-
* one, or for a page restored from the back/forward cache.
|
|
24
|
+
/**
|
|
25
|
+
* The events worth waking for. `focus` and `pageshow` are here because
|
|
26
|
+
* `visibilitychange` does not fire for a window that was merely behind another
|
|
27
|
+
* one, or for a page restored from the back/forward cache.
|
|
28
28
|
*/ const WINDOW_EVENTS = [
|
|
29
29
|
'online',
|
|
30
30
|
'focus',
|
|
31
31
|
'pageshow'
|
|
32
32
|
];
|
|
33
|
-
/**
|
|
34
|
-
* Calls `onReturn` the first time the machine is both online and looked at, or
|
|
35
|
-
* after the backstop if neither ever happens. Returns a disarm function.
|
|
33
|
+
/**
|
|
34
|
+
* Calls `onReturn` the first time the machine is both online and looked at, or
|
|
35
|
+
* after the backstop if neither ever happens. Returns a disarm function.
|
|
36
36
|
*/ export function armReturnListeners(env, onReturn) {
|
|
37
37
|
let fired = false;
|
|
38
38
|
let timer = null;
|
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* How long is "how long is left".
|
|
3
|
-
*
|
|
4
|
-
* The naive answer — bytes remaining divided by the rate since the last report
|
|
5
|
-
* — is unusable on a real connection. Between two packets the instantaneous
|
|
6
|
-
* rate swings by an order of magnitude, so the countdown reads "8 saniye", then
|
|
7
|
-
* "4 dakika", then "11 saniye", and the person watching learns to ignore it.
|
|
8
|
-
*
|
|
9
|
-
* So the rate is measured across a window instead: the oldest sample still
|
|
10
|
-
* inside WINDOW_MS against the newest. Long enough that one slow packet cannot
|
|
11
|
-
* move it much, short enough that a connection genuinely getting slower is
|
|
12
|
-
* reflected within a couple of seconds rather than being averaged away by a
|
|
13
|
-
* fast start.
|
|
1
|
+
/**
|
|
2
|
+
* How long is "how long is left".
|
|
3
|
+
*
|
|
4
|
+
* The naive answer — bytes remaining divided by the rate since the last report
|
|
5
|
+
* — is unusable on a real connection. Between two packets the instantaneous
|
|
6
|
+
* rate swings by an order of magnitude, so the countdown reads "8 saniye", then
|
|
7
|
+
* "4 dakika", then "11 saniye", and the person watching learns to ignore it.
|
|
8
|
+
*
|
|
9
|
+
* So the rate is measured across a window instead: the oldest sample still
|
|
10
|
+
* inside WINDOW_MS against the newest. Long enough that one slow packet cannot
|
|
11
|
+
* move it much, short enough that a connection genuinely getting slower is
|
|
12
|
+
* reflected within a couple of seconds rather than being averaged away by a
|
|
13
|
+
* fast start.
|
|
14
14
|
*/ const WINDOW_MS = 5000;
|
|
15
|
-
/**
|
|
16
|
-
* Below this, there is no answer worth giving.
|
|
17
|
-
*
|
|
18
|
-
* A rate computed from 80 ms of history is noise wearing a number, and the
|
|
19
|
-
* first estimate is the one people remember. Until the window has this much in
|
|
20
|
-
* it the remaining time is `null` and the screen shows a bar without a
|
|
21
|
-
* countdown — which is honest, and settles within a second on any real upload.
|
|
15
|
+
/**
|
|
16
|
+
* Below this, there is no answer worth giving.
|
|
17
|
+
*
|
|
18
|
+
* A rate computed from 80 ms of history is noise wearing a number, and the
|
|
19
|
+
* first estimate is the one people remember. Until the window has this much in
|
|
20
|
+
* it the remaining time is `null` and the screen shows a bar without a
|
|
21
|
+
* countdown — which is honest, and settles within a second on any real upload.
|
|
22
22
|
*/ const MIN_SPAN_MS = 700;
|
|
23
|
-
/**
|
|
24
|
-
* A short history of byte counts, from which a believable rate can be drawn.
|
|
25
|
-
*
|
|
26
|
-
* Deliberately a plain object with functions rather than a class: it has to be
|
|
27
|
-
* usable from a hook's ref, a plain script and a test, and it holds nothing
|
|
28
|
-
* that needs a lifecycle.
|
|
23
|
+
/**
|
|
24
|
+
* A short history of byte counts, from which a believable rate can be drawn.
|
|
25
|
+
*
|
|
26
|
+
* Deliberately a plain object with functions rather than a class: it has to be
|
|
27
|
+
* usable from a hook's ref, a plain script and a test, and it holds nothing
|
|
28
|
+
* that needs a lifecycle.
|
|
29
29
|
*/ export function createRateWindow(windowMs = WINDOW_MS) {
|
|
30
30
|
const samples = [];
|
|
31
31
|
return {
|
|
@@ -73,11 +73,11 @@
|
|
|
73
73
|
if (fraction >= 1) return 100;
|
|
74
74
|
return Math.min(99, Math.floor(fraction * 100));
|
|
75
75
|
}
|
|
76
|
-
/**
|
|
77
|
-
* Seconds left, or `null` when that cannot be said yet.
|
|
78
|
-
*
|
|
79
|
-
* Returns 0 — not null — once every byte is accounted for, because "done" is
|
|
80
|
-
* something we DO know and a screen should be able to close on it.
|
|
76
|
+
/**
|
|
77
|
+
* Seconds left, or `null` when that cannot be said yet.
|
|
78
|
+
*
|
|
79
|
+
* Returns 0 — not null — once every byte is accounted for, because "done" is
|
|
80
|
+
* something we DO know and a screen should be able to close on it.
|
|
81
81
|
*/ export function secondsRemaining(sentBytes, totalBytes, bytesPerSecond) {
|
|
82
82
|
if (totalBytes === null || totalBytes <= 0) return null;
|
|
83
83
|
const left = totalBytes - sentBytes;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* What an upload can honestly say about itself while it is happening.
|
|
3
|
-
*
|
|
4
|
-
* Every field that can be unknown is `null` rather than 0 or a guess. That is
|
|
5
|
-
* the whole design: a bar drawn at 0% that never moves, or a countdown that
|
|
6
|
-
* says "3 seconds" for four minutes, is worse than saying nothing — the person
|
|
7
|
-
* stops believing the screen, and then they do not believe it when it is right.
|
|
1
|
+
/**
|
|
2
|
+
* What an upload can honestly say about itself while it is happening.
|
|
3
|
+
*
|
|
4
|
+
* Every field that can be unknown is `null` rather than 0 or a guess. That is
|
|
5
|
+
* the whole design: a bar drawn at 0% that never moves, or a countdown that
|
|
6
|
+
* says "3 seconds" for four minutes, is worse than saying nothing — the person
|
|
7
|
+
* stops believing the screen, and then they do not believe it when it is right.
|
|
8
8
|
*/ export { };
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import { buildProgress, createRateWindow } from './progress';
|
|
2
|
-
/**
|
|
3
|
-
* An upload the browser can actually count.
|
|
4
|
-
*
|
|
5
|
-
* `XMLHttpRequest` and not `fetch`, and the reason is not preference: fetch
|
|
6
|
-
* reports NO upload progress at all. A request body stream would need
|
|
7
|
-
* `duplex: 'half'`, which is not supported across the browsers this has to run
|
|
8
|
-
* on, and even then it reports what the stream produced, not what the socket
|
|
9
|
-
* accepted. `xhr.upload.onprogress` is the only mechanism a browser gives that
|
|
10
|
-
* counts bytes handed to the network.
|
|
11
|
-
*
|
|
12
|
-
* It is also the reason a framework server action cannot be used here. A server
|
|
13
|
-
* action is a request the framework owns; it exposes nothing about its
|
|
14
|
-
* progress, it cannot be aborted, and it buffers the whole body in the web
|
|
15
|
-
* process before a byte reaches storage. Measured on a live install: a large
|
|
16
|
-
* video appeared to upload and then simply did not arrive.
|
|
2
|
+
/**
|
|
3
|
+
* An upload the browser can actually count.
|
|
4
|
+
*
|
|
5
|
+
* `XMLHttpRequest` and not `fetch`, and the reason is not preference: fetch
|
|
6
|
+
* reports NO upload progress at all. A request body stream would need
|
|
7
|
+
* `duplex: 'half'`, which is not supported across the browsers this has to run
|
|
8
|
+
* on, and even then it reports what the stream produced, not what the socket
|
|
9
|
+
* accepted. `xhr.upload.onprogress` is the only mechanism a browser gives that
|
|
10
|
+
* counts bytes handed to the network.
|
|
11
|
+
*
|
|
12
|
+
* It is also the reason a framework server action cannot be used here. A server
|
|
13
|
+
* action is a request the framework owns; it exposes nothing about its
|
|
14
|
+
* progress, it cannot be aborted, and it buffers the whole body in the web
|
|
15
|
+
* process before a byte reaches storage. Measured on a live install: a large
|
|
16
|
+
* video appeared to upload and then simply did not arrive.
|
|
17
17
|
*/ /** How often to report, at most. Every progress event would re-render for nothing. */ const MIN_REPORT_INTERVAL_MS = 120;
|
|
18
|
-
/**
|
|
19
|
-
* Posts a body and reports honest progress while it goes.
|
|
20
|
-
*
|
|
21
|
-
* Resolves either way and never rejects, because a caller that has to wrap
|
|
22
|
-
* every upload in try/catch ends up with one that does not, and then a failed
|
|
23
|
-
* upload looks like a successful one.
|
|
18
|
+
/**
|
|
19
|
+
* Posts a body and reports honest progress while it goes.
|
|
20
|
+
*
|
|
21
|
+
* Resolves either way and never rejects, because a caller that has to wrap
|
|
22
|
+
* every upload in try/catch ends up with one that does not, and then a failed
|
|
23
|
+
* upload looks like a successful one.
|
|
24
24
|
*/ export function uploadWithProgress(body, options) {
|
|
25
25
|
const xhr = options.createRequest ? options.createRequest() : new XMLHttpRequest();
|
|
26
26
|
const window = createRateWindow();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nucleus-core-ts",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.993",
|
|
4
4
|
"description": "Production-ready, enterprise-grade TypeScript framework for building multi-tenant APIs",
|
|
5
5
|
"author": "Hidayet Can Özcan <hidayetcan@gmail.com>",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|