@botim/mp-debug-sdk 0.1.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.
@@ -0,0 +1,205 @@
1
+ import { EventType, EventLevel, ConsolePayload, NetworkPayload, ErrorPayload, CommandHandler, BotimConfig, ConsentInput, DeviceInfo } from './types.js';
2
+ export { AttachRequest, AttachResponse, BotimEnv, BridgePayload, CommandAckPayload, CommandContext, CommandPollResponse, CommandRejectedPayload, CommandRequest, DebugEvent, DebugEventBase, ErrorSource, EventMeta, LifecycleEvent, LifecyclePayload, NetworkPhase, PerfPayload, SCHEMA_VERSION, SerializedValue, StreamFrame, UploadAck, UploadBatch } from './types.js';
3
+
4
+ /**
5
+ * Errors that escape the SDK into host code.
6
+ *
7
+ * The SDK's no-throw invariant has exactly two carve-outs:
8
+ * - `BotimConfigError` — thrown synchronously by `enableRemoteDebug` when the
9
+ * resolved `BotimConfig` is missing or invalid. Prevents any I/O.
10
+ * - `BotimConsentError` — thrown synchronously by `enableRemoteDebug` when
11
+ * consent has not been granted in a `prod` build. Prevents any I/O.
12
+ *
13
+ * Both are intentionally synchronous and pre-installation: at the moment they
14
+ * fire, no globals have been wrapped, no listeners installed, no network sent.
15
+ */
16
+ declare class BotimConfigError extends Error {
17
+ readonly name = "BotimConfigError";
18
+ readonly code: string;
19
+ readonly path?: string;
20
+ constructor(message: string, opts?: {
21
+ code: string;
22
+ path?: string;
23
+ });
24
+ }
25
+ declare class BotimConsentError extends Error {
26
+ readonly name = "BotimConsentError";
27
+ constructor(message: string);
28
+ }
29
+
30
+ /**
31
+ * Built-in commands registered automatically when `enableRemoteDebug` runs.
32
+ *
33
+ * Most are thin shells over host-supplied callbacks: the SDK has no business
34
+ * deciding what "reload" means in a given mini-program, so the host registers
35
+ * the callback and the SDK exposes a stable wire-level command name.
36
+ */
37
+
38
+ interface BuiltinHostHooks {
39
+ /** Reload the mini-program. If absent, `reload` returns rejected. */
40
+ reload?: () => void | Promise<void>;
41
+ /** Return a JSON-serializable snapshot of host state. */
42
+ getState?: () => unknown | Promise<unknown>;
43
+ /** Apply a feature flag override. */
44
+ setFeatureFlag?: (key: string, value: unknown) => void | Promise<void>;
45
+ /**
46
+ * Capture a screenshot. Two return shapes are accepted:
47
+ * - a raw base64 string → assumed PNG (legacy form)
48
+ * - `{ data, format }` → format is one of 'png-base64' | 'jpeg-base64'
49
+ * so the admin viewer can pick the right MIME for the data URL.
50
+ * The SDK enforces a 1 MB base64 cap regardless.
51
+ */
52
+ screenshot?: () => ScreenshotResult | Promise<ScreenshotResult>;
53
+ }
54
+ type ScreenshotResult = string | {
55
+ data: string;
56
+ format?: 'png-base64' | 'jpeg-base64'
57
+ /**
58
+ * Self-contained HTML+CSS snapshot — `data` is a JSON string with
59
+ * the shape `{ html, viewport, url, capturedAt }`. Admin viewers
60
+ * render `html` inside a sandboxed `<iframe srcdoc>` so the result
61
+ * looks pixel-identical to the live page without any pixel encoding.
62
+ */
63
+ | 'html-snapshot';
64
+ };
65
+
66
+ /**
67
+ * Per-signature sliding-window event deduper.
68
+ *
69
+ * Without this, a `setInterval(() => undefined.foo, 16)` produces ~60
70
+ * `error` events per second; a flaky network endpoint in a tight retry
71
+ * loop can fire hundreds of `network` events per minute. The relay's hot
72
+ * retention is 24-48h — at those rates a single misbehaving session drowns
73
+ * out everything else, and the device's own ingest budget gets eaten by
74
+ * its own bug.
75
+ *
76
+ * Algorithm:
77
+ * - Compute a stable signature for each event (type + key payload bits).
78
+ * - First event with a given signature in a window: emit normally.
79
+ * - Subsequent events with the same signature within `windowMs`: drop +
80
+ * increment a counter.
81
+ * - When the window closes (next same-signature event OR a periodic sweep),
82
+ * emit ONE rollup event whose `meta.dedup` field carries the suppressed
83
+ * count and the time range.
84
+ *
85
+ * Types are carried verbatim — a suppressed `error` produces an `error`-typed
86
+ * rollup with the same level. Admin UIs / agents detect rollups by checking
87
+ * `meta.dedup` rather than a separate event type, so no schema bump is needed.
88
+ *
89
+ * Default behaviour: enabled, 1000 ms window, applies to console / network /
90
+ * error events only. lifecycle / bridge / perf / command-* events bypass.
91
+ */
92
+
93
+ interface DedupOptions {
94
+ /** Default true. Set false to disable deduping entirely. */
95
+ enabled?: boolean;
96
+ /** Sliding window per signature, in ms. Default 1000. */
97
+ windowMs?: number;
98
+ /** Hard cap on the number of tracked signatures. Default 500. Oldest entries evict on overflow. */
99
+ maxSignatures?: number;
100
+ }
101
+ interface SuppressionSummary {
102
+ signature: string;
103
+ type: EventType;
104
+ level: EventLevel;
105
+ /** Total suppressed (excludes the leading event that was emitted as a real event). */
106
+ count: number;
107
+ firstTs: number;
108
+ lastTs: number;
109
+ /** Human-readable label describing what was suppressed. */
110
+ label: string;
111
+ /** Original payload of the LAST suppressed occurrence — gives admins a
112
+ * recent-state look at the thing that's been firing in a loop. */
113
+ examplePayload: ConsolePayload | NetworkPayload | ErrorPayload | unknown;
114
+ }
115
+
116
+ interface RedactionConfig {
117
+ headers?: string[];
118
+ bodyPatterns?: RegExp[];
119
+ maxBodyBytes?: number;
120
+ }
121
+ interface SamplingConfig {
122
+ console?: number;
123
+ network?: number;
124
+ lifecycle?: number;
125
+ bridge?: number;
126
+ }
127
+ interface AppInfo {
128
+ name: string;
129
+ version: string;
130
+ build?: string;
131
+ }
132
+ interface RemoteDebugOptions {
133
+ /** When false, returns a no-op handle and installs nothing. */
134
+ enabled?: boolean;
135
+ /** Relay base URL, e.g. "https://debug.botim.dev". */
136
+ endpoint: string;
137
+ /**
138
+ * Optional override for the app identity reported in events. When omitted
139
+ * the SDK falls back to `config.appName` / `config.appVersion` resolved by
140
+ * the Vite plugin from `botim.{env}.json`.
141
+ */
142
+ app?: AppInfo;
143
+ /**
144
+ * Build-time-resolved mini-program identity. In typical usage this is
145
+ * `botimConfig` imported from `virtual:botim/config` (provided by the
146
+ * `@botim/debug-sdk/vite` plugin). REQUIRED.
147
+ */
148
+ config: BotimConfig;
149
+ /**
150
+ * Consent for telemetry. Required in `prod`; implicit in non-prod builds.
151
+ */
152
+ consent?: ConsentInput;
153
+ /** Built-in command host hooks (reload, getState, screenshot, etc.). */
154
+ builtins?: BuiltinHostHooks;
155
+ device?: Partial<DeviceInfo>;
156
+ redact?: RedactionConfig;
157
+ sampling?: SamplingConfig;
158
+ /**
159
+ * Sliding-window per-signature dedup. Default: enabled with a 1 s window
160
+ * applied to console / network / error events. Set `false` to disable.
161
+ * Repetitive events (e.g., a render-loop error firing 60×/s) collapse
162
+ * into one leading event + a synthesized rollup event whose
163
+ * `meta.dedup.count` carries the suppressed total.
164
+ */
165
+ dedup?: DedupOptions | false;
166
+ flushIntervalMs?: number;
167
+ bufferSize?: number;
168
+ maxBatchSize?: number;
169
+ maxRetries?: number;
170
+ /** Called for transport-level errors. SDK never throws into app code. */
171
+ onError?: (err: unknown) => void;
172
+ }
173
+ interface RemoteDebugHandle {
174
+ readonly sid: string | null;
175
+ flush(): Promise<void>;
176
+ stop(): Promise<void>;
177
+ /** Register a custom command handler. Idempotent on the name. */
178
+ registerCommand(name: string, handler: CommandHandler): void;
179
+ /** Remove a previously-registered command. Returns true if it existed. */
180
+ unregisterCommand(name: string): boolean;
181
+ }
182
+ declare const DEFAULT_REDACT_HEADERS: readonly string[];
183
+ declare const DEFAULT_BODY_PATTERNS: readonly RegExp[];
184
+ declare const DEFAULT_MAX_BODY_BYTES = 4096;
185
+ /**
186
+ * How often the transport drains the buffer to the relay.
187
+ *
188
+ * 8 seconds is deliberately slow: this is a debug telemetry channel, not a
189
+ * realtime one. With a 200ms cadence, a busy session producing ~10 events/sec
190
+ * would make ~5 ingest POSTs/second, hammering the device's network stack
191
+ * and the relay's write path for no human-visible benefit (admins poll at
192
+ * 2s anyway, so end-to-end perceived latency is dominated by their poll).
193
+ *
194
+ * The timer fully drains the buffer per tick (multiple POSTs back-to-back if
195
+ * needed, each capped at maxBatchSize), so the only cost of the longer
196
+ * interval is up to 8s of potential delay before an event reaches the relay.
197
+ *
198
+ * Hosts can opt for tighter latency by setting `flushIntervalMs` explicitly.
199
+ */
200
+ declare const DEFAULT_FLUSH_INTERVAL_MS = 8000;
201
+ declare const DEFAULT_BUFFER_SIZE = 1000;
202
+ declare const DEFAULT_MAX_BATCH_SIZE = 50;
203
+ declare function enableRemoteDebug(options: RemoteDebugOptions): Promise<RemoteDebugHandle>;
204
+
205
+ export { type AppInfo, BotimConfig, BotimConfigError, BotimConsentError, type BuiltinHostHooks, CommandHandler, ConsentInput, ConsolePayload, DEFAULT_BODY_PATTERNS, DEFAULT_BUFFER_SIZE, DEFAULT_FLUSH_INTERVAL_MS, DEFAULT_MAX_BATCH_SIZE, DEFAULT_MAX_BODY_BYTES, DEFAULT_REDACT_HEADERS, type DedupOptions, DeviceInfo, ErrorPayload, EventLevel, EventType, NetworkPayload, type RedactionConfig, type RemoteDebugHandle, type RemoteDebugOptions, type SamplingConfig, type SuppressionSummary, enableRemoteDebug };