@mgcrea/mcp-unifi-protect 0.0.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/LICENSE +21 -0
- package/README.md +300 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +51 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +385 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/server-iu_3JECB.js +1743 -0
- package/dist/server-iu_3JECB.js.map +1 -0
- package/package.json +71 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
//#region src/config.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* The private (undocumented) Protect API, mounted under UniFi OS's proxy. This
|
|
6
|
+
* server deliberately wraps this rather than the official Integration API at
|
|
7
|
+
* `/proxy/protect/integration/v1`: the official one has NO historical query
|
|
8
|
+
* capability at all — its only query parameters in the entire published OpenAPI
|
|
9
|
+
* spec are `channel`, `highQuality` and `qualities` — so "what happened at the
|
|
10
|
+
* front door last night" is unanswerable through it.
|
|
11
|
+
*
|
|
12
|
+
* The trade is real and accepted: nothing below is contractual, and Ubiquiti
|
|
13
|
+
* moves these endpoints between Protect releases. `unifi_protect_get_system_info`
|
|
14
|
+
* reports the running version so a mismatch is visible, and
|
|
15
|
+
* `unifi_protect_request` reaches anything that moved without a code change.
|
|
16
|
+
*/
|
|
17
|
+
declare const PRIVATE_API_PATH = "/proxy/protect/api";
|
|
18
|
+
/** UniFi OS's own auth surface, which is NOT under the Protect proxy path. */
|
|
19
|
+
declare const LOGIN_PATH = "/api/auth/login";
|
|
20
|
+
/** The realtime channel. Not used yet — see the WebSocket note in the README. */
|
|
21
|
+
declare const UPDATES_WS_PATH = "/proxy/protect/ws/updates";
|
|
22
|
+
declare const ConfigSchema: z.ZodObject<{
|
|
23
|
+
baseUrl: z.ZodOptional<z.ZodString>;
|
|
24
|
+
username: z.ZodOptional<z.ZodString>;
|
|
25
|
+
password: z.ZodOptional<z.ZodString>;
|
|
26
|
+
totp: z.ZodOptional<z.ZodString>;
|
|
27
|
+
verifyTls: z.ZodDefault<z.ZodBoolean>;
|
|
28
|
+
allowWrites: z.ZodDefault<z.ZodBoolean>;
|
|
29
|
+
sessionFile: z.ZodString;
|
|
30
|
+
snapshotDir: z.ZodString;
|
|
31
|
+
maxRetries: z.ZodDefault<z.ZodNumber>;
|
|
32
|
+
maxDownloadBytes: z.ZodDefault<z.ZodNumber>;
|
|
33
|
+
deviceCacheTtlSeconds: z.ZodDefault<z.ZodNumber>;
|
|
34
|
+
}, z.core.$strict>;
|
|
35
|
+
type Config = z.infer<typeof ConfigSchema>;
|
|
36
|
+
/**
|
|
37
|
+
* The on-disk config document. Keys are camelCase to mirror `Config` rather
|
|
38
|
+
* than the env var names: this is a typed JSON file, not a shell.
|
|
39
|
+
*
|
|
40
|
+
* `.strict()` on purpose — a typo'd `userName` must be an error. Silently
|
|
41
|
+
* ignoring an unknown key looks exactly like "that setting had no effect",
|
|
42
|
+
* which is the worst way to learn your credentials came from somewhere else.
|
|
43
|
+
*/
|
|
44
|
+
declare const FileConfigSchema: z.ZodObject<{
|
|
45
|
+
host: z.ZodOptional<z.ZodString>;
|
|
46
|
+
username: z.ZodOptional<z.ZodString>;
|
|
47
|
+
password: z.ZodOptional<z.ZodString>;
|
|
48
|
+
verifyTls: z.ZodOptional<z.ZodBoolean>;
|
|
49
|
+
allowWrites: z.ZodOptional<z.ZodBoolean>;
|
|
50
|
+
sessionFile: z.ZodOptional<z.ZodString>;
|
|
51
|
+
snapshotDir: z.ZodOptional<z.ZodString>;
|
|
52
|
+
maxRetries: z.ZodOptional<z.ZodNumber>;
|
|
53
|
+
maxDownloadBytes: z.ZodOptional<z.ZodNumber>;
|
|
54
|
+
deviceCacheTtlSeconds: z.ZodOptional<z.ZodNumber>;
|
|
55
|
+
}, z.core.$strict>;
|
|
56
|
+
type FileConfig = z.infer<typeof FileConfigSchema>;
|
|
57
|
+
/**
|
|
58
|
+
* Normalize whatever someone pasted into a console origin, preserving the port.
|
|
59
|
+
*
|
|
60
|
+
* "192.168.1.1" -> "https://192.168.1.1"
|
|
61
|
+
* "10.0.0.1:8443" -> "https://10.0.0.1:8443"
|
|
62
|
+
* "https://udm.lan/protect/" -> "https://udm.lan"
|
|
63
|
+
*
|
|
64
|
+
* A port must survive: consoles are commonly reached on a non-443 port, and the
|
|
65
|
+
* normalizers in mcp-keycloak and mcp-shopify both drop it. Everything after
|
|
66
|
+
* the origin is discarded — the API paths are this server's business, and a
|
|
67
|
+
* pasted `/protect/dashboard` URL would otherwise be prefixed onto every call.
|
|
68
|
+
*
|
|
69
|
+
* `https` is forced: UniFi OS redirects plain HTTP, and following that redirect
|
|
70
|
+
* would send the session cookie over cleartext on the first hop.
|
|
71
|
+
*/
|
|
72
|
+
declare const normalizeBaseUrl: (raw: string) => string;
|
|
73
|
+
/** `readFileSync` does not expand `~`, but it is the natural thing to write in a config file. */
|
|
74
|
+
declare const expandTilde: (path: string) => string;
|
|
75
|
+
/**
|
|
76
|
+
* Where the config file lives, most specific first: an explicit override, then
|
|
77
|
+
* the XDG location, then the conventional `~/.config`.
|
|
78
|
+
*/
|
|
79
|
+
declare const resolveConfigPath: (env?: NodeJS.ProcessEnv) => string;
|
|
80
|
+
/** The session file sits beside the config file unless told otherwise. */
|
|
81
|
+
declare const resolveSessionPath: (env?: NodeJS.ProcessEnv) => string;
|
|
82
|
+
/**
|
|
83
|
+
* Environment first, config file second, **per field** — not whole-source.
|
|
84
|
+
* Docker and CI inject the environment and must keep working untouched, while a
|
|
85
|
+
* one-off `UNIFI_PROTECT_ALLOW_WRITES=0` still has to override a file that says
|
|
86
|
+
* `true`. Merging field by field is the only rule that gives both.
|
|
87
|
+
*/
|
|
88
|
+
declare const loadConfig: (env?: NodeJS.ProcessEnv, configPath?: string) => Config;
|
|
89
|
+
/** True once the server has everything it needs to reach a console. */
|
|
90
|
+
declare const isConfigured: (config: Config) => boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Returned by unifi_protect_auth_status and printed to stderr at startup. Prose
|
|
93
|
+
* rather than a code, because this is the text someone acts on when nothing
|
|
94
|
+
* works — and the server can no longer signal it by refusing to start.
|
|
95
|
+
*/
|
|
96
|
+
declare const setupInstructions: (config: Config) => string[];
|
|
97
|
+
//#endregion
|
|
98
|
+
//#region src/client/auth.d.ts
|
|
99
|
+
type Logger = {
|
|
100
|
+
debug?(...args: unknown[]): void;
|
|
101
|
+
warn?(...args: unknown[]): void;
|
|
102
|
+
error?(...args: unknown[]): void;
|
|
103
|
+
};
|
|
104
|
+
/** The two headers that authenticate every request to a UniFi OS console. */
|
|
105
|
+
type SessionHeaders = {
|
|
106
|
+
cookie: string;
|
|
107
|
+
"x-csrf-token": string;
|
|
108
|
+
};
|
|
109
|
+
type SessionStatus = {
|
|
110
|
+
authenticated: boolean;
|
|
111
|
+
/** Where the live session came from, for unifi_protect_auth_status. */
|
|
112
|
+
source: "none" | "restored" | "login";
|
|
113
|
+
username: string | undefined;
|
|
114
|
+
savedAt: string | undefined;
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* A pluggable source of console session headers. The client calls `headers()`
|
|
118
|
+
* on every request and `invalidate()` on a 401 to force the next call to
|
|
119
|
+
* re-run the handshake.
|
|
120
|
+
*/
|
|
121
|
+
type SessionProvider = {
|
|
122
|
+
headers(): Promise<SessionHeaders>;
|
|
123
|
+
invalidate(): void;
|
|
124
|
+
/** Force a fresh handshake now, optionally with a 2FA code. Used by auth_login. */
|
|
125
|
+
login(totp?: string): Promise<SessionStatus>;
|
|
126
|
+
/** Drop the session in memory and on disk. */
|
|
127
|
+
logout(): Promise<void>;
|
|
128
|
+
describe(): SessionStatus;
|
|
129
|
+
};
|
|
130
|
+
type SessionProviderOptions = {
|
|
131
|
+
config: Config;
|
|
132
|
+
fetch?: typeof fetch;
|
|
133
|
+
logger?: Logger;
|
|
134
|
+
now?: () => number;
|
|
135
|
+
};
|
|
136
|
+
declare const createSessionProvider: (opts: SessionProviderOptions) => SessionProvider;
|
|
137
|
+
/** For tests: fixed headers, no network, no disk. */
|
|
138
|
+
declare const staticSessionProvider: (headers?: SessionHeaders) => SessionProvider;
|
|
139
|
+
//#endregion
|
|
140
|
+
//#region src/client/protect.d.ts
|
|
141
|
+
/** Array values become repeated params, which is how Protect expects `types`. */
|
|
142
|
+
type Query = Record<string, string | number | boolean | string[] | undefined>;
|
|
143
|
+
declare const backoffMs: (attempt: number) => number;
|
|
144
|
+
declare const retryAfterMs: (res: Response) => number | undefined;
|
|
145
|
+
declare const buildQuery: (query: Query | undefined) => string;
|
|
146
|
+
type ProtectClientOptions = {
|
|
147
|
+
baseUrl: string;
|
|
148
|
+
session: SessionProvider;
|
|
149
|
+
maxRetries: number;
|
|
150
|
+
userAgent: string;
|
|
151
|
+
maxDownloadBytes: number;
|
|
152
|
+
fetch?: typeof fetch;
|
|
153
|
+
logger?: Logger;
|
|
154
|
+
};
|
|
155
|
+
type BinaryResult = {
|
|
156
|
+
bytes: Uint8Array;
|
|
157
|
+
contentType: string;
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* The private Protect API client. Every path passed in is relative to
|
|
161
|
+
* `/proxy/protect/api` — callers write `cameras/abc123`, not the full path.
|
|
162
|
+
*/
|
|
163
|
+
declare class ProtectClient {
|
|
164
|
+
readonly baseUrl: string;
|
|
165
|
+
private readonly session;
|
|
166
|
+
private readonly maxRetries;
|
|
167
|
+
private readonly userAgent;
|
|
168
|
+
private readonly maxDownloadBytes;
|
|
169
|
+
private readonly fetchImpl;
|
|
170
|
+
private readonly logger;
|
|
171
|
+
constructor(opts: ProtectClientOptions);
|
|
172
|
+
/** Absolute URL for a path relative to the private API root. */
|
|
173
|
+
url(path: string, query?: Query): string;
|
|
174
|
+
/**
|
|
175
|
+
* Perform one authenticated request, retrying on 401 (re-login), 429 and 5xx.
|
|
176
|
+
* Returns the raw Response so callers can decide between JSON and bytes.
|
|
177
|
+
*/
|
|
178
|
+
private send;
|
|
179
|
+
/** A JSON request against the private API. */
|
|
180
|
+
request<T = unknown>(method: string, path: string, opts?: {
|
|
181
|
+
query?: Query;
|
|
182
|
+
body?: unknown;
|
|
183
|
+
}): Promise<T>;
|
|
184
|
+
get<T = unknown>(path: string, query?: Query): Promise<T>;
|
|
185
|
+
post<T = unknown>(path: string, body?: unknown, query?: Query): Promise<T>;
|
|
186
|
+
patch<T = unknown>(path: string, body?: unknown, query?: Query): Promise<T>;
|
|
187
|
+
del<T = unknown>(path: string, query?: Query): Promise<T>;
|
|
188
|
+
/**
|
|
189
|
+
* Fetch a binary asset — a snapshot JPEG, an event thumbnail, an exported
|
|
190
|
+
* MP4. Size is checked against `maxDownloadBytes` from Content-Length where
|
|
191
|
+
* the console supplies one, and again after reading where it does not, so an
|
|
192
|
+
* unexpectedly huge export fails with a clear message rather than by
|
|
193
|
+
* exhausting the heap.
|
|
194
|
+
*/
|
|
195
|
+
requestBytes(path: string, opts?: {
|
|
196
|
+
query?: Query;
|
|
197
|
+
accept?: string;
|
|
198
|
+
}): Promise<BinaryResult>;
|
|
199
|
+
/** Status-aware prose, because this is the text someone acts on. */
|
|
200
|
+
private errorMessage;
|
|
201
|
+
}
|
|
202
|
+
//#endregion
|
|
203
|
+
//#region src/client/shape.d.ts
|
|
204
|
+
type Rec = Record<string, unknown>;
|
|
205
|
+
/** Apply a summarizer across an array, passing non-arrays through untouched. */
|
|
206
|
+
declare const summarizeEach: <T>(value: unknown, fn: (item: Rec) => T) => unknown;
|
|
207
|
+
/**
|
|
208
|
+
* Protect timestamps are milliseconds since the Unix epoch. Rendering them as
|
|
209
|
+
* ISO 8601 costs a few characters and saves the model from having to reason
|
|
210
|
+
* about a bare 13-digit integer — which it does get wrong, usually by reading
|
|
211
|
+
* it as seconds and landing in 1970.
|
|
212
|
+
*/
|
|
213
|
+
declare const isoTime: (value: unknown) => string | undefined;
|
|
214
|
+
/** An index from device id to display name, used to resolve event references. */
|
|
215
|
+
type NameIndex = ReadonlyMap<string, string>;
|
|
216
|
+
declare const buildNameIndex: (devices: unknown) => NameIndex;
|
|
217
|
+
declare const summarizeCamera: (camera: Rec) => Rec;
|
|
218
|
+
/**
|
|
219
|
+
* Events reference their camera by id. Resolving that to a name server-side is
|
|
220
|
+
* the single most useful thing this layer does: it removes a join the model
|
|
221
|
+
* would otherwise have to perform against a separate camera list, and get
|
|
222
|
+
* silently wrong. The id is kept too, since the write and snapshot tools need it.
|
|
223
|
+
*/
|
|
224
|
+
declare const summarizeEvent: (event: Rec, cameras?: NameIndex) => Rec;
|
|
225
|
+
declare const summarizeLight: (light: Rec) => Rec;
|
|
226
|
+
declare const summarizeSensor: (sensor: Rec) => Rec;
|
|
227
|
+
declare const summarizeViewer: (viewer: Rec) => Rec;
|
|
228
|
+
declare const summarizeChime: (chime: Rec) => Rec;
|
|
229
|
+
declare const summarizeLiveview: (liveview: Rec) => Rec;
|
|
230
|
+
declare const summarizeUser: (user: Rec) => Rec;
|
|
231
|
+
declare const summarizeNvr: (nvr: Rec) => Rec;
|
|
232
|
+
/**
|
|
233
|
+
* The bootstrap document is the entire console state and must never be returned
|
|
234
|
+
* raw — it is the single largest context bomb this API offers. This reduces it
|
|
235
|
+
* to the NVR summary plus per-type counts, which is what "tell me about my
|
|
236
|
+
* system" actually wants.
|
|
237
|
+
*/
|
|
238
|
+
declare const summarizeBootstrap: (bootstrap: Rec) => Rec;
|
|
239
|
+
//#endregion
|
|
240
|
+
//#region src/client/device-cache.d.ts
|
|
241
|
+
type DeviceCacheOptions = {
|
|
242
|
+
client: ProtectClient;
|
|
243
|
+
ttlSeconds: number;
|
|
244
|
+
now?: () => number;
|
|
245
|
+
};
|
|
246
|
+
/**
|
|
247
|
+
* A short-lived camera id→name index, used to resolve the `camera` reference on
|
|
248
|
+
* every event into something readable.
|
|
249
|
+
*
|
|
250
|
+
* It is cached because event search is the hot path and every result set needs
|
|
251
|
+
* the same index: fetching the camera list once per search rather than once per
|
|
252
|
+
* event is the difference between one extra request and none. The TTL is short
|
|
253
|
+
* because a renamed or newly adopted camera should appear without a restart,
|
|
254
|
+
* and a stale name is only ever cosmetic — the id travels alongside it.
|
|
255
|
+
*/
|
|
256
|
+
type DeviceCache = {
|
|
257
|
+
cameras(): Promise<NameIndex>;
|
|
258
|
+
invalidate(): void;
|
|
259
|
+
};
|
|
260
|
+
declare const createDeviceCache: (opts: DeviceCacheOptions) => DeviceCache;
|
|
261
|
+
//#endregion
|
|
262
|
+
//#region src/server.d.ts
|
|
263
|
+
declare const SERVER_NAME: string;
|
|
264
|
+
declare const SERVER_VERSION: string;
|
|
265
|
+
declare const USER_AGENT: string;
|
|
266
|
+
type CreateServerOptions = {
|
|
267
|
+
config: Config;
|
|
268
|
+
fetch?: typeof fetch;
|
|
269
|
+
logger?: Logger;
|
|
270
|
+
/** Override the session provider (tests, and the interactive login flow). */
|
|
271
|
+
session?: SessionProvider;
|
|
272
|
+
};
|
|
273
|
+
type CreatedServer = {
|
|
274
|
+
server: McpServer;
|
|
275
|
+
client: ProtectClient;
|
|
276
|
+
session: SessionProvider;
|
|
277
|
+
devices: DeviceCache;
|
|
278
|
+
};
|
|
279
|
+
declare const createServer: (opts: CreateServerOptions) => CreatedServer;
|
|
280
|
+
//#endregion
|
|
281
|
+
//#region src/client/session-store.d.ts
|
|
282
|
+
/**
|
|
283
|
+
* A console session: the bare cookie value plus the CSRF token that was current
|
|
284
|
+
* when it was issued. Both are needed on every request, and neither is derivable
|
|
285
|
+
* from the other, so they are stored and invalidated as one unit.
|
|
286
|
+
*/
|
|
287
|
+
type PersistedSession = {
|
|
288
|
+
/** The `TOKEN=<jwt>` pair, attributes already stripped. */
|
|
289
|
+
cookie: string;
|
|
290
|
+
csrfToken: string;
|
|
291
|
+
/** Which console this belongs to, so a changed host does not reuse a stale session. */
|
|
292
|
+
baseUrl: string;
|
|
293
|
+
/** Which account it was issued to, for the same reason. */
|
|
294
|
+
username: string;
|
|
295
|
+
savedAt: string;
|
|
296
|
+
};
|
|
297
|
+
/** Load a persisted session, or undefined if none / unreadable / not JSON. */
|
|
298
|
+
declare const loadSession: (path: string) => Promise<PersistedSession | undefined>;
|
|
299
|
+
/** Persist a session with owner-only permissions. */
|
|
300
|
+
declare const saveSession: (path: string, session: PersistedSession) => Promise<void>;
|
|
301
|
+
/** Remove a persisted session. Absent is success — logout is idempotent. */
|
|
302
|
+
declare const clearSession: (path: string) => Promise<void>;
|
|
303
|
+
//#endregion
|
|
304
|
+
//#region src/client/errors.d.ts
|
|
305
|
+
/** A non-2xx answer from the console. */
|
|
306
|
+
declare class ProtectApiError extends Error {
|
|
307
|
+
readonly name = "ProtectApiError";
|
|
308
|
+
readonly status: number;
|
|
309
|
+
/** The request path, so an error names what failed without a stack trace. */
|
|
310
|
+
readonly path: string | undefined;
|
|
311
|
+
readonly errors: unknown;
|
|
312
|
+
constructor(message: string, opts: {
|
|
313
|
+
status: number;
|
|
314
|
+
path?: string | undefined;
|
|
315
|
+
errors?: unknown;
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
/** The console rejected the credentials, or 2FA is required and was not supplied. */
|
|
319
|
+
declare class ProtectAuthError extends Error {
|
|
320
|
+
readonly name = "ProtectAuthError";
|
|
321
|
+
/** True when the console asked for a 2FA code rather than refusing the password. */
|
|
322
|
+
readonly needsTwoFactor: boolean;
|
|
323
|
+
constructor(message: string, opts?: {
|
|
324
|
+
needsTwoFactor?: boolean;
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
/** Thrown when a write path is reached while UNIFI_PROTECT_ALLOW_WRITES is off. */
|
|
328
|
+
declare class WritesDisabledError extends Error {
|
|
329
|
+
readonly name = "WritesDisabledError";
|
|
330
|
+
constructor(what: string);
|
|
331
|
+
}
|
|
332
|
+
/** Thrown when the server is asked to reach a console it has no credentials for. */
|
|
333
|
+
declare class NotConfiguredError extends Error {
|
|
334
|
+
readonly name = "NotConfiguredError";
|
|
335
|
+
constructor();
|
|
336
|
+
}
|
|
337
|
+
//#endregion
|
|
338
|
+
//#region src/tools/index.d.ts
|
|
339
|
+
type ToolContext = {
|
|
340
|
+
config: Config;
|
|
341
|
+
/** Register the mutating tools too. Off by default — see UNIFI_PROTECT_ALLOW_WRITES. */
|
|
342
|
+
allowWrites: boolean;
|
|
343
|
+
session: SessionProvider;
|
|
344
|
+
devices: DeviceCache;
|
|
345
|
+
};
|
|
346
|
+
/**
|
|
347
|
+
* Register the UniFi Protect tools.
|
|
348
|
+
*
|
|
349
|
+
* unifi_protect_auth_status comes first and unconditionally, so a server with no
|
|
350
|
+
* console configured is still a useful one — it can say what to set — rather
|
|
351
|
+
* than a connection that closes with its own error message swallowed.
|
|
352
|
+
*
|
|
353
|
+
* Read tools are then always registered; the write tools only when
|
|
354
|
+
* `allowWrites` is set, so with the flag off they are not merely refused — they
|
|
355
|
+
* are absent from tools/list and cannot be called at all. A refusal still lets a
|
|
356
|
+
* model try, retry, and reason about how to get around it; a tool that does not
|
|
357
|
+
* exist ends the conversation.
|
|
358
|
+
*/
|
|
359
|
+
declare const registerTools: (server: McpServer, client: ProtectClient, ctx: ToolContext) => void;
|
|
360
|
+
//#endregion
|
|
361
|
+
//#region src/tools/request.d.ts
|
|
362
|
+
/**
|
|
363
|
+
* Reject anything that is not a plain relative path. The server decides the
|
|
364
|
+
* host and the `/proxy/protect/api` prefix; letting a caller supply either
|
|
365
|
+
* would send the console session somewhere it does not belong.
|
|
366
|
+
*/
|
|
367
|
+
declare const assertSafePath: (path: string) => void;
|
|
368
|
+
//#endregion
|
|
369
|
+
//#region src/tools/util.d.ts
|
|
370
|
+
/**
|
|
371
|
+
* Convert a time expression to milliseconds since the Unix epoch.
|
|
372
|
+
*
|
|
373
|
+
* This exists because the console's `/events` endpoint takes JavaScript
|
|
374
|
+
* millisecond timestamps — not ISO 8601, and NOT Unix seconds. A seconds value
|
|
375
|
+
* is not rejected: it is interpreted as a moment in January 1970, so the query
|
|
376
|
+
* succeeds and returns an empty list. That reads as "nothing happened last
|
|
377
|
+
* night", which is the most expensive possible failure for this server.
|
|
378
|
+
*
|
|
379
|
+
* Accepts ISO 8601, a relative expression like "2h ago" or "30m", the literal
|
|
380
|
+
* "now", or a raw millisecond number.
|
|
381
|
+
*/
|
|
382
|
+
declare const toEpochMs: (value: string | number, now?: number) => number;
|
|
383
|
+
//#endregion
|
|
384
|
+
export { type BinaryResult, type Config, type CreateServerOptions, type CreatedServer, type DeviceCache, type FileConfig, LOGIN_PATH, type Logger, type NameIndex, NotConfiguredError, PRIVATE_API_PATH, type PersistedSession, ProtectApiError, ProtectAuthError, ProtectClient, type ProtectClientOptions, type Query, SERVER_NAME, SERVER_VERSION, type SessionHeaders, type SessionProvider, type SessionStatus, type ToolContext, UPDATES_WS_PATH, USER_AGENT, WritesDisabledError, assertSafePath, backoffMs, buildNameIndex, buildQuery, clearSession, createDeviceCache, createServer, createSessionProvider, expandTilde, isConfigured, isoTime, loadConfig, loadSession, normalizeBaseUrl, registerTools, resolveConfigPath, resolveSessionPath, retryAfterMs, saveSession, setupInstructions, staticSessionProvider, summarizeBootstrap, summarizeCamera, summarizeChime, summarizeEach, summarizeEvent, summarizeLight, summarizeLiveview, summarizeNvr, summarizeSensor, summarizeUser, summarizeViewer, toEpochMs };
|
|
385
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/config.ts","../src/client/auth.ts","../src/client/protect.ts","../src/client/shape.ts","../src/client/device-cache.ts","../src/server.ts","../src/client/session-store.ts","../src/client/errors.ts","../src/tools/index.ts","../src/tools/request.ts","../src/tools/util.ts"],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { A as saveSession, B as loadConfig, C as summarizeSensor, D as staticSessionProvider, E as createSessionProvider, F as LOGIN_PATH, H as resolveConfigPath, I as PRIVATE_API_PATH, L as UPDATES_WS_PATH, M as ProtectApiError, N as ProtectAuthError, O as clearSession, P as WritesDisabledError, R as expandTilde, S as summarizeNvr, T as summarizeViewer, U as resolveSessionPath, V as normalizeBaseUrl, W as setupInstructions, _ as summarizeChime, a as registerTools, b as summarizeLight, c as ProtectClient, d as retryAfterMs, f as createDeviceCache, g as summarizeCamera, h as summarizeBootstrap, i as createServer, j as NotConfiguredError, k as loadSession, l as backoffMs, m as isoTime, n as SERVER_VERSION, o as assertSafePath, p as buildNameIndex, r as USER_AGENT, s as toEpochMs, t as SERVER_NAME, u as buildQuery, v as summarizeEach, w as summarizeUser, x as summarizeLiveview, y as summarizeEvent, z as isConfigured } from "./server-iu_3JECB.js";
|
|
2
|
+
export { LOGIN_PATH, NotConfiguredError, PRIVATE_API_PATH, ProtectApiError, ProtectAuthError, ProtectClient, SERVER_NAME, SERVER_VERSION, UPDATES_WS_PATH, USER_AGENT, WritesDisabledError, assertSafePath, backoffMs, buildNameIndex, buildQuery, clearSession, createDeviceCache, createServer, createSessionProvider, expandTilde, isConfigured, isoTime, loadConfig, loadSession, normalizeBaseUrl, registerTools, resolveConfigPath, resolveSessionPath, retryAfterMs, saveSession, setupInstructions, staticSessionProvider, summarizeBootstrap, summarizeCamera, summarizeChime, summarizeEach, summarizeEvent, summarizeLight, summarizeLiveview, summarizeNvr, summarizeSensor, summarizeUser, summarizeViewer, toEpochMs };
|