@osqd/bothandlerjs 0.4.0 → 0.5.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/config.d.ts CHANGED
@@ -3,6 +3,7 @@ import type { PresetName } from "./policy/presets.js";
3
3
  import type { Clock } from "./internal/clock.js";
4
4
  import type { DnsResolver } from "./internal/dns.js";
5
5
  import type { Detector } from "./detectors/types.js";
6
+ import type { CrawlerVerificationOptions } from "./detectors/crawler-verification.js";
6
7
  import type { BotSignature } from "./detectors/known-bots.js";
7
8
  import type { ActionParams, FalsePositivePolicy, Rule } from "./policy/types.js";
8
9
  import type { CustomHandler } from "./actions/types.js";
@@ -60,6 +61,15 @@ export interface BotHandlerConfig {
60
61
  detectors?: readonly Detector[];
61
62
  /** Appended to the built-in set. Ignored when `detectors` is given. */
62
63
  extraDetectors?: readonly Detector[];
64
+ /**
65
+ * How claimed crawler identities are confirmed or refuted.
66
+ *
67
+ * Chiefly `verifiers`: your own answer to "is this really Googlebot", for the many
68
+ * identities that publish no proof this library can check on its own. Also the two
69
+ * strictness flags, which were documented on the detector and reachable only by
70
+ * rebuilding the whole detector list.
71
+ */
72
+ crawlerVerification?: CrawlerVerificationOptions;
63
73
  /** A named starting policy. Combined with `rules`, which are evaluated first. */
64
74
  preset?: PresetName;
65
75
  /** Your own rules, evaluated before any preset's. */
@@ -1,6 +1,22 @@
1
1
  export declare function initFeed(): void;
2
2
  /** Applies filter state that arrived in the URL rather than from a click. */
3
3
  export declare function reflectFilterButtons(): void;
4
+ /**
5
+ * Fetches the entries this viewer never received, and merges them.
6
+ *
7
+ * They were never lost. The rate cap keeps a burst off the *stream* and the lag guard
8
+ * drops frames a slow socket cannot take, but both leave the ring alone — and the opening
9
+ * replay is droppable too, so a first load of a busy dashboard can arrive with most of the
10
+ * backlog missing. `/api/feed` serves that ring whole, and `ingest` is keyed on the request
11
+ * id, so merging it is idempotent: what is already held is refreshed, what is missing is
12
+ * added.
13
+ *
14
+ * On demand rather than on a timer. Skips happen exactly when the origin is busiest, and a
15
+ * dashboard that answered every skip by re-fetching the whole ring would be a load
16
+ * amplifier pointed at the process it is meant to be watching — which is the thing
17
+ * `maxEventsPerSecond` exists to prevent.
18
+ */
19
+ export declare function loadSkipped(): Promise<void>;
4
20
  export declare function drawFeed(): void;
5
21
  /** Drops every cached node. Used when the feed is cleared under the page's feet. */
6
22
  export declare function resetFeedCache(): void;
@@ -5,7 +5,25 @@ export declare function ms(value: number): string;
5
5
  export declare function uptime(milliseconds: number): string;
6
6
  export declare function rangeLabel(milliseconds: number): string;
7
7
  /** Wall-clock time for a feed row. Local, seconds included, because a feed moves in seconds. */
8
+ /**
9
+ * A time, always as 24-hour HH:MM:SS.
10
+ *
11
+ * Built from the local components rather than handed to `toLocaleTimeString`, which
12
+ * answers in whatever the viewer's locale prefers — so the same feed read "4:40:46 PM" on
13
+ * one operator's screen and "16:40:46" on the next, and a dashboard two people look at
14
+ * together should not disagree with itself about what time it is. Local time, not UTC:
15
+ * this is the clock on the wall next to the server somebody is watching.
16
+ */
8
17
  export declare function clockTime(at: number): string;
18
+ /** A date, always as DD-MM-YYYY. */
19
+ export declare function clockDate(at: number): string;
20
+ /**
21
+ * Both, for the places where the time alone is ambiguous.
22
+ *
23
+ * An actor's first sighting can be days back, and "first seen 09:14:02" invites the reader
24
+ * to assume it was this morning.
25
+ */
26
+ export declare function clockStamp(at: number): string;
9
27
  /**
10
28
  * What "this window" actually holds, said out loud.
11
29
  *
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The pager both tables use.
3
+ *
4
+ * One renderer rather than two, because the feed pages in the browser and the Actors
5
+ * table pages on the server and *neither of those facts belongs in the control*. What it
6
+ * needs to know is where you are and what it should do when you press something.
7
+ *
8
+ * Rendered twice per table, above and below. A table of fifty rows is taller than the
9
+ * window on most screens, and a pager only at the bottom means scrolling to the end to go
10
+ * back to the top of the next page.
11
+ */
12
+ export interface PagerModel {
13
+ /** Zero-based. */
14
+ page: number;
15
+ /** What the range reads: `1–50 of 212`. Total omitted where the total is not known. */
16
+ from: number;
17
+ to: number;
18
+ total?: number;
19
+ atStart: boolean;
20
+ atEnd: boolean;
21
+ /** Shown next to the range when the list is being held still. */
22
+ held?: string;
23
+ go: (page: number) => void;
24
+ size?: {
25
+ current: number;
26
+ choices: readonly number[];
27
+ set: (size: number) => void;
28
+ };
29
+ }
30
+ export declare function renderPager(host: HTMLElement, model: PagerModel, options: {
31
+ withSize: boolean;
32
+ }): void;
@@ -29,6 +29,33 @@ export interface State {
29
29
  bufferedWhilePaused: number;
30
30
  /** Frames the server dropped because *this* connection was too slow to take them. */
31
31
  laggedDrops: number;
32
+ /**
33
+ * Which page of the feed is showing, newest first, zero-based.
34
+ *
35
+ * Zero follows the live feed. Any other page is a position in history, so arriving
36
+ * requests must not shuffle it under the reader — see `feedFrozen`.
37
+ */
38
+ feedPage: number;
39
+ /**
40
+ * The matching rows as they stood when the reader left page zero.
41
+ *
42
+ * Without this, one request arriving while somebody reads page three moves every row
43
+ * down by one and they are silently reading different rows than the ones they were
44
+ * looking at. Frozen on leaving page zero, dropped on returning to it.
45
+ */
46
+ feedFrozen: Row[] | undefined;
47
+ /** Which page of the Actors table is showing. Paged on the server, by offset. */
48
+ actorsPage: number;
49
+ /** How many rows a page of each table holds. Chosen in the page, not configured. */
50
+ feedPageSize: number;
51
+ actorsPageSize: number;
52
+ /**
53
+ * How many skipped entries have already been fetched back and merged.
54
+ *
55
+ * The server's `skipped` only ever grows, so the badge subtracts this to say how many
56
+ * are *still* missing rather than how many ever were.
57
+ */
58
+ caughtUp: number;
32
59
  }
33
60
  export declare const state: State;
34
61
  /**
@@ -43,9 +70,42 @@ export declare const state: State;
43
70
  export declare function ingest(entry: DashboardEntry): void;
44
71
  export declare function clearFeed(): void;
45
72
  export declare function setSearch(value: string): void;
73
+ /** Back to the live first page, thawed. Called whenever what matches changes. */
74
+ export declare function resetPaging(): void;
75
+ /**
76
+ * Puts the ring back in time order after a bulk merge.
77
+ *
78
+ * `ingest` appends, because the stream delivers in order and appending is what that
79
+ * costs. A backlog fetched over HTTP is not in order relative to what is already held —
80
+ * it is *older* — so merging without this leaves yesterday's requests sitting at the
81
+ * newest end, which is where the feed reads from.
82
+ */
83
+ export declare function sortRows(): void;
46
84
  export declare function matches(row: Row): boolean;
85
+ /**
86
+ * Every row matching the filter, newest first.
87
+ *
88
+ * The whole set rather than a screenful: the feed pages through it, and the export means
89
+ * "what I am looking at" rather than "the first page of it".
90
+ */
91
+ export declare function matchingRows(limit?: number): Row[];
47
92
  /** The rows the feed would draw, newest first. Also what "export what I am looking at" means. */
48
93
  export declare function visibleRows(limit?: number): Row[];
94
+ /**
95
+ * One page of the feed, and what the pager needs to describe itself.
96
+ *
97
+ * Page zero reads live and is recomputed every draw. Any other page reads the list as it
98
+ * was when the reader left page zero, because a feed that renumbers itself under somebody
99
+ * paging through it is a feed they cannot read.
100
+ */
101
+ export declare function feedPage(size: number): {
102
+ rows: Row[];
103
+ page: number;
104
+ pages: number;
105
+ total: number;
106
+ };
107
+ /** Moves to a page, freezing the list on the way off page zero and thawing on the way back. */
108
+ export declare function goToFeedPage(page: number): void;
49
109
  export declare function matchingCount(): number;
50
110
  export declare function oldestAt(): number | undefined;
51
111
  export interface Aggregates {