spearkit 0.3.0 → 0.3.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/docs/usage.md ADDED
@@ -0,0 +1,178 @@
1
+ # Usage tracking
2
+
3
+ Usage tracking records **who used what**: every successful command, component,
4
+ and prefix-command invocation becomes a `UsageEvent` that spearkit can persist to a
5
+ store and/or mirror into a Discord channel. Turn it on with the client's `usage`
6
+ option.
7
+
8
+ ## Usage tracking vs the logger
9
+
10
+ These look similar but answer different questions, and they are completely
11
+ independent sinks:
12
+
13
+ | | Logger | Usage tracking |
14
+ | --- | --- | --- |
15
+ | Question | *What is the bot doing?* (diagnostics) | *Who used which feature?* (audit) |
16
+ | Content | Free-form messages, levels, errors, internals | Structured `UsageEvent`s for successful uses |
17
+ | Sinks | Console / your log pipeline | A database store and/or a Discord channel |
18
+ | Configured by | the `logger` option | the `usage` option |
19
+
20
+ A failed or errored command shows up in your **logs**; it is not recorded as a
21
+ usage event. Reach for the [logger](./logging.md) for debugging, and usage
22
+ tracking for analytics, audit trails, and "top commands" dashboards.
23
+
24
+ ## Enabling it
25
+
26
+ Set the `usage` option. Provide a `store` (a database), a `channel` (a Discord
27
+ channel id to mirror events into), or both:
28
+
29
+ ```ts
30
+ import { MemoryUsageStore, SpearClient } from "spearkit";
31
+
32
+ const client = new SpearClient({
33
+ usage: {
34
+ store: new MemoryUsageStore(),
35
+ channel: "123456789012345678", // optional: also post each event here
36
+ },
37
+ });
38
+ ```
39
+
40
+ Once enabled, spearkit auto-tracks every successful command, component, and prefix
41
+ command — you write no tracking code in your handlers.
42
+
43
+ ## The usage event
44
+
45
+ Each tracked use is a `UsageEvent`:
46
+
47
+ ```ts
48
+ interface UsageEvent {
49
+ type: "command" | "prefix" | "component" | "event";
50
+ name: string; // command/component/event name
51
+ userId?: string;
52
+ userTag?: string;
53
+ guildId?: string | null;
54
+ channelId?: string | null;
55
+ detail?: string; // free-form extra detail
56
+ timestamp: Date;
57
+ }
58
+ ```
59
+
60
+ ## Stores (the database)
61
+
62
+ A store is any object implementing `UsageStore`:
63
+
64
+ ```ts
65
+ interface UsageStore {
66
+ record(event: UsageEvent): void | Promise<void>;
67
+ all(): UsageEvent[] | Promise<readonly UsageEvent[]>;
68
+ }
69
+ ```
70
+
71
+ spearkit ships two.
72
+
73
+ ### MemoryUsageStore
74
+
75
+ In-memory and synchronous — ideal for tests, prototypes, and live dashboards.
76
+ Pass an optional cap to keep only the most recent N events:
77
+
78
+ ```ts
79
+ import { MemoryUsageStore } from "spearkit";
80
+
81
+ const store = new MemoryUsageStore(1_000); // keep the last 1,000 events
82
+
83
+ store.all(); // readonly UsageEvent[]
84
+ store.size; // number of events held
85
+ store.byUser("123..."); // UsageEvent[] for one user id
86
+ store.clear(); // forget everything
87
+ ```
88
+
89
+ ### JsonFileUsageStore
90
+
91
+ Durable and dependency-free: appends one event per line as newline-delimited
92
+ JSON (`.jsonl`). `all()` reads the file back and parses it, so it behaves like a
93
+ small file-backed database:
94
+
95
+ ```ts
96
+ import { JsonFileUsageStore } from "spearkit";
97
+
98
+ const store = new JsonFileUsageStore("./usage.jsonl");
99
+
100
+ await store.record({ type: "command", name: "ping", timestamp: new Date() });
101
+ const events = await store.all(); // readonly UsageEvent[]
102
+ ```
103
+
104
+ The directory is created on demand. Because `all()` is async here (it reads from
105
+ disk), always `await` it.
106
+
107
+ ## Querying the store
108
+
109
+ `client.usage.store` is the store you configured — query it directly. Note that
110
+ `all()` may be synchronous (`MemoryUsageStore`) or asynchronous
111
+ (`JsonFileUsageStore`); awaiting works for both:
112
+
113
+ ```ts
114
+ const store = client.usage.store;
115
+ if (store !== undefined) {
116
+ const events = await store.all();
117
+ const topCommand = events.filter((e) => e.type === "command").length;
118
+ console.log(`${topCommand} command uses recorded`);
119
+ }
120
+ ```
121
+
122
+ ## The Discord channel reporter
123
+
124
+ Besides (or instead of) a store, you can mirror each event into a Discord
125
+ channel. Pass `channel` (a channel id) in the `usage` option; spearkit posts one
126
+ line per event using `formatUsage`:
127
+
128
+ ```ts
129
+ import { SpearClient } from "spearkit";
130
+
131
+ new SpearClient({ usage: { channel: "123456789012345678" } });
132
+ ```
133
+
134
+ `formatUsage(event)` is the default renderer (e.g. `` `command` **ping** by
135
+ user#0001 in <#…> ``). Override it with `format` to control the line:
136
+
137
+ ```ts
138
+ import { SpearClient, type UsageEvent } from "spearkit";
139
+
140
+ new SpearClient({
141
+ usage: {
142
+ channel: "123456789012345678",
143
+ format: (event: UsageEvent) => `${event.userTag ?? "someone"} used ${event.name}`,
144
+ },
145
+ });
146
+ ```
147
+
148
+ ## The usage tracker
149
+
150
+ `client.usage` is a `UsageTracker`. The client configures it from the `usage`
151
+ option, but you can drive it directly:
152
+
153
+ | Member | Description |
154
+ | ------ | ----------- |
155
+ | `setStore(store)` | Set (or swap) the persistence store. |
156
+ | `reportTo(channelId, format?)` | Mirror events into a channel, optionally with a custom formatter. |
157
+ | `track(event)` | Record a use. Returns immediately; storing/reporting run in the background. |
158
+ | `store` | The configured store, for querying. |
159
+ | `enabled` | `true` if a store or channel is configured. |
160
+
161
+ ```ts
162
+ import { JsonFileUsageStore } from "spearkit";
163
+
164
+ client.usage.setStore(new JsonFileUsageStore("./usage.jsonl"));
165
+ client.usage.reportTo("123456789012345678");
166
+
167
+ // Record a custom event yourself (e.g. a non-command action).
168
+ client.usage.track({ type: "event", name: "signup", timestamp: new Date() });
169
+ ```
170
+
171
+ Tracking is fire-and-forget: a slow store or channel never blocks command
172
+ handling, and any failure is logged rather than thrown.
173
+
174
+ ## See also
175
+
176
+ - [Logging](./logging.md) — diagnostics, the other sink.
177
+ - [Commands](./commands.md) / [Prefix commands](./prefix.md) / [Components](./components.md) — what gets tracked.
178
+ - [Client](./client.md) — the `usage` option.