@adrrr/tarmac 0.5.0 → 0.7.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/README.md +89 -77
- package/dist/args.js +23 -9
- package/dist/cli.js +36 -6
- package/dist/config.js +61 -1
- package/dist/fleet.js +70 -11
- package/dist/history.js +1 -1
- package/dist/limits.js +77 -7
- package/dist/render.js +350 -39
- package/dist/server.js +48 -6
- package/package.json +1 -1
package/dist/limits.js
CHANGED
|
@@ -37,18 +37,15 @@ export const LIMIT_WINDOWS = [
|
|
|
37
37
|
export const RESET_HORIZON_MS = 8 * 24 * 3600 * 1000;
|
|
38
38
|
/** Both windows, always — a window that could not be read is a gauge that says so. */
|
|
39
39
|
export function readLimits(rateLimits, now) {
|
|
40
|
-
// `rate_limits: []` and `rate_limits: "none"` are legal JSON and not a pair of windows.
|
|
41
|
-
// Neither may reach the lookup below as something to index.
|
|
42
|
-
const ok = rateLimits !== null && typeof rateLimits === 'object' && !Array.isArray(rateLimits);
|
|
43
40
|
return LIMIT_WINDOWS.map(({ key, label, said }) => {
|
|
44
|
-
const w =
|
|
45
|
-
const has = w !==
|
|
46
|
-
const v =
|
|
41
|
+
const w = windowAt(rateLimits, key);
|
|
42
|
+
const has = w !== undefined && 'used_percentage' in w;
|
|
43
|
+
const v = w?.used_percentage;
|
|
47
44
|
// Present and null: a window whose number has not been taken yet. Absent, or holding
|
|
48
45
|
// something that is not a percentage: the shape moved. The discriminant is the key.
|
|
49
46
|
const pct = has && typeof v === 'number' && Number.isFinite(v) && v >= 0 && v <= 100 ? Math.floor(v) : null;
|
|
50
47
|
const why = pct !== null ? null : rateLimits == null || (has && v === null) ? 'absent' : 'drift';
|
|
51
|
-
const at = has
|
|
48
|
+
const at = has ? resetOf(w) : null;
|
|
52
49
|
const resetsInMs = at === null ? null : at * 1000 - now;
|
|
53
50
|
return {
|
|
54
51
|
key,
|
|
@@ -60,3 +57,76 @@ export function readLimits(rateLimits, now) {
|
|
|
60
57
|
};
|
|
61
58
|
});
|
|
62
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* The windows two readings of the account describe DIFFERENTLY, by key, in the order above —
|
|
62
|
+
* meaning two windows that are BOTH still open at `now` and are not the same window.
|
|
63
|
+
*
|
|
64
|
+
* A fleet holds one reading per session and only one of them can be drawn, so the question is
|
|
65
|
+
* what the others were. It is settled on the reset and not the percentage: `resets_at` is where
|
|
66
|
+
* a window ENDS, so two readings naming the same one are two ages of a single allowance — the
|
|
67
|
+
* freshest is the one still true, and the age beside it says the rest. Percentages that differ
|
|
68
|
+
* under one reset are that same number caught at two frames, the normal state of a fleet, and
|
|
69
|
+
* warning about it would be a warning on every poll.
|
|
70
|
+
*
|
|
71
|
+
* The openness test is the other half, and without it this cries wolf every five hours. A
|
|
72
|
+
* session that idles keeps the frame it last drew, and the five-hour window rolls over four or
|
|
73
|
+
* five times a day: an overnight snapshot names the window it was taken in, which has since
|
|
74
|
+
* ended. That is not two accounts, it is one reading being old — a fact the fleet already
|
|
75
|
+
* prints, as that row's age and as the `!` beside it — so a window whose boundary is behind
|
|
76
|
+
* `now` is left out of the comparison rather than raised as a disagreement.
|
|
77
|
+
*
|
|
78
|
+
* What survives both rules is the thing nothing else on either surface can say: two windows
|
|
79
|
+
* open AT THE SAME TIME, which one allowance cannot have. Whether that is two accounts signed
|
|
80
|
+
* in at once or something stranger is published nowhere tarmac reads, so this reports that the
|
|
81
|
+
* readings are apart and never why.
|
|
82
|
+
*
|
|
83
|
+
* A reading that dates no window is not a reading that dates one differently: an absent
|
|
84
|
+
* boundary is compared with nothing, exactly as an absent percentage is drawn as nothing. And
|
|
85
|
+
* a boundary further out than `RESET_HORIZON_MS` is refused here as it is refused a countdown —
|
|
86
|
+
* a reset fifty thousand years away is not a window this account is in.
|
|
87
|
+
*
|
|
88
|
+
* Known blind spot, and the reason it is left open: two accounts whose windows happen to end at
|
|
89
|
+
* the same second read as one here, and their percentages then differ in silence. The only
|
|
90
|
+
* thing that would catch it is treating a percentage as evidence — and the shape that takes is
|
|
91
|
+
* "the fresher reading is lower than the older one", which cannot be true of one allowance and
|
|
92
|
+
* would be a false alarm the day a number is ever revised downward. A missed collision costs a
|
|
93
|
+
* warning nobody sees; the other rule costs a warning nobody can act on, on a fleet where
|
|
94
|
+
* nothing is wrong.
|
|
95
|
+
*/
|
|
96
|
+
export function windowsApart(a, b, now) {
|
|
97
|
+
const apart = [];
|
|
98
|
+
for (const { key } of LIMIT_WINDOWS) {
|
|
99
|
+
const at = openBoundary(windowAt(a, key), now);
|
|
100
|
+
const bt = openBoundary(windowAt(b, key), now);
|
|
101
|
+
if (at !== null && bt !== null && at !== bt)
|
|
102
|
+
apart.push(key);
|
|
103
|
+
}
|
|
104
|
+
return apart;
|
|
105
|
+
}
|
|
106
|
+
/** Whether this reading yielded a number for either window — a reading that measured something. */
|
|
107
|
+
export const measured = (rateLimits, now) => readLimits(rateLimits, now).some((g) => g.pct !== null);
|
|
108
|
+
/**
|
|
109
|
+
* The epoch a window rolls over at, when that window is still OPEN at `now` — and `null` for
|
|
110
|
+
* one that has already rolled over, one nothing dates, and one dated beyond the horizon.
|
|
111
|
+
*/
|
|
112
|
+
function openBoundary(w, now) {
|
|
113
|
+
const at = resetOf(w);
|
|
114
|
+
if (at === null)
|
|
115
|
+
return null;
|
|
116
|
+
const inMs = at * 1000 - now;
|
|
117
|
+
return inMs > 0 && inMs <= RESET_HORIZON_MS ? at : null;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* The window filed under `key`, or `undefined` when the payload carries nothing usable there.
|
|
121
|
+
*
|
|
122
|
+
* `rate_limits: []` and `rate_limits: "none"` are legal JSON and not a pair of windows, and
|
|
123
|
+
* neither may reach an index or a property read as something to look inside.
|
|
124
|
+
*/
|
|
125
|
+
function windowAt(rateLimits, key) {
|
|
126
|
+
if (rateLimits === null || rateLimits === undefined || typeof rateLimits !== 'object' || Array.isArray(rateLimits))
|
|
127
|
+
return undefined;
|
|
128
|
+
const w = rateLimits[key];
|
|
129
|
+
return w !== null && typeof w === 'object' && !Array.isArray(w) ? w : undefined;
|
|
130
|
+
}
|
|
131
|
+
/** The epoch a window rolls over at, or `null` when this reading does not name one. */
|
|
132
|
+
const resetOf = (w) => w !== undefined && typeof w.resets_at === 'number' && Number.isFinite(w.resets_at) ? w.resets_at : null;
|