@anomira/node-sdk 0.1.6 → 0.1.7

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/index.d.cts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { Request, Response, NextFunction } from 'express';
2
2
  import { FastifyPluginAsync } from 'fastify';
3
3
 
4
- interface SentinelConfig {
5
- /** SDK API key — get this from the SentinelAPI dashboard */
4
+ interface AnomiraConfig {
5
+ /** SDK API key — get this from the Anomira dashboard */
6
6
  apiKey: string;
7
- /** Your app ID from the SentinelAPI dashboard */
7
+ /** Your app ID from the Anomira dashboard */
8
8
  appId: string;
9
9
  /**
10
10
  * Ingest endpoint URL.
@@ -13,7 +13,7 @@ interface SentinelConfig {
13
13
  ingestUrl?: string;
14
14
  /**
15
15
  * Geo-lookup endpoint URL for client-side geo-velocity checks.
16
- * Should point to your SentinelAPI ingest service geo endpoint.
16
+ * Should point to your Anomira ingest service geo endpoint.
17
17
  * If not provided, client-side geo-velocity is skipped (server-side still runs).
18
18
  * @example "https://ingest.anomira.io/v1/geo"
19
19
  */
@@ -40,7 +40,7 @@ interface SentinelConfig {
40
40
  debug?: boolean;
41
41
  /**
42
42
  * If true, automatically intercept console.log/info/warn/error/debug
43
- * and forward them to the SentinelAPI Logs dashboard.
43
+ * and forward them to the Anomira Logs dashboard.
44
44
  * Existing console output is preserved — logs still print to your terminal.
45
45
  * @default false
46
46
  */
@@ -116,6 +116,14 @@ type EventNameValue = typeof EventName[keyof typeof EventName];
116
116
  type FirewallField = "url" | "body" | "header" | "user_agent" | "ip";
117
117
  type FirewallOperator = "contains" | "equals" | "starts_with" | "ends_with" | "regex";
118
118
  type FirewallAction = "block" | "flag";
119
+ interface EndpointDeclaration {
120
+ /** HTTP method, e.g. "GET". Use "*" to match any method. */
121
+ method: string;
122
+ /** Express-style path, e.g. "/api/users/:id" — colons are normalized automatically. */
123
+ path: string;
124
+ /** Whether this endpoint requires authentication. Defaults to true. */
125
+ auth?: boolean;
126
+ }
119
127
  interface FirewallRule {
120
128
  id: string;
121
129
  field: FirewallField;
@@ -127,25 +135,25 @@ interface FirewallRule {
127
135
  }
128
136
 
129
137
  /**
130
- * SentinelClient — the core SDK object.
138
+ * AnomiraClient — the core SDK object.
131
139
  *
132
140
  * Instantiate once and reuse across your application:
133
141
  *
134
142
  * ```ts
135
- * import { SentinelAPI } from "@anomira/node-sdk";
143
+ * import { Anomira } from "@anomira/node-sdk";
136
144
  *
137
- * export const sentinel = new SentinelAPI({
145
+ * export const sentinel = new Anomira({
138
146
  * apiKey: process.env.SENTINEL_API_KEY!,
139
147
  * appId: process.env.SENTINEL_APP_ID!,
140
148
  * });
141
149
  * ```
142
150
  */
143
- declare class SentinelClient {
151
+ declare class AnomiraClient {
144
152
  #private;
145
- readonly config: Required<Omit<SentinelConfig, "getUserId" | "getIp" | "detect">> & {
146
- getUserId: NonNullable<SentinelConfig["getUserId"]>;
147
- getIp: NonNullable<SentinelConfig["getIp"]>;
148
- detect: Required<NonNullable<SentinelConfig["detect"]>>;
153
+ readonly config: Required<Omit<AnomiraConfig, "getUserId" | "getIp" | "detect">> & {
154
+ getUserId: NonNullable<AnomiraConfig["getUserId"]>;
155
+ getIp: NonNullable<AnomiraConfig["getIp"]>;
156
+ detect: Required<NonNullable<AnomiraConfig["detect"]>>;
149
157
  captureConsole: boolean;
150
158
  service: string;
151
159
  };
@@ -163,7 +171,7 @@ declare class SentinelClient {
163
171
  private readonly _origLog;
164
172
  private readonly _origWarn;
165
173
  private readonly _origError;
166
- constructor(config: SentinelConfig);
174
+ constructor(config: AnomiraConfig);
167
175
  /**
168
176
  * Track a custom security event.
169
177
  *
@@ -230,7 +238,7 @@ declare class SentinelClient {
230
238
  meta?: Record<string, unknown>;
231
239
  }): void;
232
240
  /**
233
- * Send a structured log entry to the SentinelAPI Logs dashboard.
241
+ * Send a structured log entry to the Anomira Logs dashboard.
234
242
  *
235
243
  * ```ts
236
244
  * sentinel.log("info", "User registered", { userId: user.id });
@@ -241,6 +249,21 @@ declare class SentinelClient {
241
249
  log(level: "debug" | "info" | "warn" | "error" | "fatal", message: string, meta?: Record<string, unknown> & {
242
250
  service?: string;
243
251
  }): void;
252
+ /**
253
+ * Declare your API's known endpoints so Anomira can flag undiscovered
254
+ * traffic as shadow endpoints.
255
+ *
256
+ * Call this once on startup after your routes are registered:
257
+ *
258
+ * ```ts
259
+ * await sentinel.declareEndpoints([
260
+ * { method: "GET", path: "/api/users/:id", auth: true },
261
+ * { method: "POST", path: "/api/orders", auth: true },
262
+ * { method: "GET", path: "/api/health", auth: false },
263
+ * ]);
264
+ * ```
265
+ */
266
+ declareEndpoints(endpoints: EndpointDeclaration[]): Promise<void>;
244
267
  /**
245
268
  * Flush all pending events immediately.
246
269
  * Useful before a graceful shutdown outside of the process lifecycle hooks.
@@ -278,10 +301,10 @@ declare class SentinelClient {
278
301
  *
279
302
  * ```ts
280
303
  * import express from "express";
281
- * import { SentinelAPI } from "@sentinelapi/node-sdk";
304
+ * import { Anomira } from "@sentinelapi/node-sdk";
282
305
  *
283
306
  * const app = express();
284
- * const sentinel = new SentinelAPI({ apiKey: "...", appId: "..." });
307
+ * const sentinel = new Anomira({ apiKey: "...", appId: "..." });
285
308
  *
286
309
  * app.use(sentinel.express()); // auto-instrument all routes
287
310
  *
@@ -290,7 +313,7 @@ declare class SentinelClient {
290
313
  * app.use(createExpressMiddleware(sentinel));
291
314
  * ```
292
315
  */
293
- declare function createExpressMiddleware(client: SentinelClient): (req: Request, res: Response, next: NextFunction) => void;
316
+ declare function createExpressMiddleware(client: AnomiraClient): (req: Request, res: Response, next: NextFunction) => void;
294
317
 
295
318
  /**
296
319
  * Typed Fastify plugin — exported separately for projects that want
@@ -304,14 +327,14 @@ declare function createExpressMiddleware(client: SentinelClient): (req: Request,
304
327
  *
305
328
  * ```ts
306
329
  * import Fastify from "fastify";
307
- * import { SentinelAPI } from "@sentinelapi/node-sdk";
330
+ * import { Anomira } from "@sentinelapi/node-sdk";
308
331
  *
309
332
  * const app = Fastify();
310
- * const sentinel = new SentinelAPI({ apiKey: "...", appId: "..." });
333
+ * const sentinel = new Anomira({ apiKey: "...", appId: "..." });
311
334
  *
312
335
  * await app.register(sentinel.fastify());
313
336
  * ```
314
337
  */
315
- declare function createFastifyPlugin(client: SentinelClient): FastifyPluginAsync;
338
+ declare function createFastifyPlugin(client: AnomiraClient): FastifyPluginAsync;
316
339
 
317
- export { EventName, type EventNameValue, type IngestPayload, type SdkEvent, SentinelClient as SentinelAPI, type SentinelConfig, createExpressMiddleware, createFastifyPlugin, SentinelClient as default };
340
+ export { AnomiraClient as Anomira, type AnomiraConfig, type EndpointDeclaration, EventName, type EventNameValue, type IngestPayload, type SdkEvent, AnomiraClient as SentinelAPI, type AnomiraConfig as SentinelConfig, createExpressMiddleware, createFastifyPlugin, AnomiraClient as default };
package/dist/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { Request, Response, NextFunction } from 'express';
2
2
  import { FastifyPluginAsync } from 'fastify';
3
3
 
4
- interface SentinelConfig {
5
- /** SDK API key — get this from the SentinelAPI dashboard */
4
+ interface AnomiraConfig {
5
+ /** SDK API key — get this from the Anomira dashboard */
6
6
  apiKey: string;
7
- /** Your app ID from the SentinelAPI dashboard */
7
+ /** Your app ID from the Anomira dashboard */
8
8
  appId: string;
9
9
  /**
10
10
  * Ingest endpoint URL.
@@ -13,7 +13,7 @@ interface SentinelConfig {
13
13
  ingestUrl?: string;
14
14
  /**
15
15
  * Geo-lookup endpoint URL for client-side geo-velocity checks.
16
- * Should point to your SentinelAPI ingest service geo endpoint.
16
+ * Should point to your Anomira ingest service geo endpoint.
17
17
  * If not provided, client-side geo-velocity is skipped (server-side still runs).
18
18
  * @example "https://ingest.anomira.io/v1/geo"
19
19
  */
@@ -40,7 +40,7 @@ interface SentinelConfig {
40
40
  debug?: boolean;
41
41
  /**
42
42
  * If true, automatically intercept console.log/info/warn/error/debug
43
- * and forward them to the SentinelAPI Logs dashboard.
43
+ * and forward them to the Anomira Logs dashboard.
44
44
  * Existing console output is preserved — logs still print to your terminal.
45
45
  * @default false
46
46
  */
@@ -116,6 +116,14 @@ type EventNameValue = typeof EventName[keyof typeof EventName];
116
116
  type FirewallField = "url" | "body" | "header" | "user_agent" | "ip";
117
117
  type FirewallOperator = "contains" | "equals" | "starts_with" | "ends_with" | "regex";
118
118
  type FirewallAction = "block" | "flag";
119
+ interface EndpointDeclaration {
120
+ /** HTTP method, e.g. "GET". Use "*" to match any method. */
121
+ method: string;
122
+ /** Express-style path, e.g. "/api/users/:id" — colons are normalized automatically. */
123
+ path: string;
124
+ /** Whether this endpoint requires authentication. Defaults to true. */
125
+ auth?: boolean;
126
+ }
119
127
  interface FirewallRule {
120
128
  id: string;
121
129
  field: FirewallField;
@@ -127,25 +135,25 @@ interface FirewallRule {
127
135
  }
128
136
 
129
137
  /**
130
- * SentinelClient — the core SDK object.
138
+ * AnomiraClient — the core SDK object.
131
139
  *
132
140
  * Instantiate once and reuse across your application:
133
141
  *
134
142
  * ```ts
135
- * import { SentinelAPI } from "@anomira/node-sdk";
143
+ * import { Anomira } from "@anomira/node-sdk";
136
144
  *
137
- * export const sentinel = new SentinelAPI({
145
+ * export const sentinel = new Anomira({
138
146
  * apiKey: process.env.SENTINEL_API_KEY!,
139
147
  * appId: process.env.SENTINEL_APP_ID!,
140
148
  * });
141
149
  * ```
142
150
  */
143
- declare class SentinelClient {
151
+ declare class AnomiraClient {
144
152
  #private;
145
- readonly config: Required<Omit<SentinelConfig, "getUserId" | "getIp" | "detect">> & {
146
- getUserId: NonNullable<SentinelConfig["getUserId"]>;
147
- getIp: NonNullable<SentinelConfig["getIp"]>;
148
- detect: Required<NonNullable<SentinelConfig["detect"]>>;
153
+ readonly config: Required<Omit<AnomiraConfig, "getUserId" | "getIp" | "detect">> & {
154
+ getUserId: NonNullable<AnomiraConfig["getUserId"]>;
155
+ getIp: NonNullable<AnomiraConfig["getIp"]>;
156
+ detect: Required<NonNullable<AnomiraConfig["detect"]>>;
149
157
  captureConsole: boolean;
150
158
  service: string;
151
159
  };
@@ -163,7 +171,7 @@ declare class SentinelClient {
163
171
  private readonly _origLog;
164
172
  private readonly _origWarn;
165
173
  private readonly _origError;
166
- constructor(config: SentinelConfig);
174
+ constructor(config: AnomiraConfig);
167
175
  /**
168
176
  * Track a custom security event.
169
177
  *
@@ -230,7 +238,7 @@ declare class SentinelClient {
230
238
  meta?: Record<string, unknown>;
231
239
  }): void;
232
240
  /**
233
- * Send a structured log entry to the SentinelAPI Logs dashboard.
241
+ * Send a structured log entry to the Anomira Logs dashboard.
234
242
  *
235
243
  * ```ts
236
244
  * sentinel.log("info", "User registered", { userId: user.id });
@@ -241,6 +249,21 @@ declare class SentinelClient {
241
249
  log(level: "debug" | "info" | "warn" | "error" | "fatal", message: string, meta?: Record<string, unknown> & {
242
250
  service?: string;
243
251
  }): void;
252
+ /**
253
+ * Declare your API's known endpoints so Anomira can flag undiscovered
254
+ * traffic as shadow endpoints.
255
+ *
256
+ * Call this once on startup after your routes are registered:
257
+ *
258
+ * ```ts
259
+ * await sentinel.declareEndpoints([
260
+ * { method: "GET", path: "/api/users/:id", auth: true },
261
+ * { method: "POST", path: "/api/orders", auth: true },
262
+ * { method: "GET", path: "/api/health", auth: false },
263
+ * ]);
264
+ * ```
265
+ */
266
+ declareEndpoints(endpoints: EndpointDeclaration[]): Promise<void>;
244
267
  /**
245
268
  * Flush all pending events immediately.
246
269
  * Useful before a graceful shutdown outside of the process lifecycle hooks.
@@ -278,10 +301,10 @@ declare class SentinelClient {
278
301
  *
279
302
  * ```ts
280
303
  * import express from "express";
281
- * import { SentinelAPI } from "@sentinelapi/node-sdk";
304
+ * import { Anomira } from "@sentinelapi/node-sdk";
282
305
  *
283
306
  * const app = express();
284
- * const sentinel = new SentinelAPI({ apiKey: "...", appId: "..." });
307
+ * const sentinel = new Anomira({ apiKey: "...", appId: "..." });
285
308
  *
286
309
  * app.use(sentinel.express()); // auto-instrument all routes
287
310
  *
@@ -290,7 +313,7 @@ declare class SentinelClient {
290
313
  * app.use(createExpressMiddleware(sentinel));
291
314
  * ```
292
315
  */
293
- declare function createExpressMiddleware(client: SentinelClient): (req: Request, res: Response, next: NextFunction) => void;
316
+ declare function createExpressMiddleware(client: AnomiraClient): (req: Request, res: Response, next: NextFunction) => void;
294
317
 
295
318
  /**
296
319
  * Typed Fastify plugin — exported separately for projects that want
@@ -304,14 +327,14 @@ declare function createExpressMiddleware(client: SentinelClient): (req: Request,
304
327
  *
305
328
  * ```ts
306
329
  * import Fastify from "fastify";
307
- * import { SentinelAPI } from "@sentinelapi/node-sdk";
330
+ * import { Anomira } from "@sentinelapi/node-sdk";
308
331
  *
309
332
  * const app = Fastify();
310
- * const sentinel = new SentinelAPI({ apiKey: "...", appId: "..." });
333
+ * const sentinel = new Anomira({ apiKey: "...", appId: "..." });
311
334
  *
312
335
  * await app.register(sentinel.fastify());
313
336
  * ```
314
337
  */
315
- declare function createFastifyPlugin(client: SentinelClient): FastifyPluginAsync;
338
+ declare function createFastifyPlugin(client: AnomiraClient): FastifyPluginAsync;
316
339
 
317
- export { EventName, type EventNameValue, type IngestPayload, type SdkEvent, SentinelClient as SentinelAPI, type SentinelConfig, createExpressMiddleware, createFastifyPlugin, SentinelClient as default };
340
+ export { AnomiraClient as Anomira, type AnomiraConfig, type EndpointDeclaration, EventName, type EventNameValue, type IngestPayload, type SdkEvent, AnomiraClient as SentinelAPI, type AnomiraConfig as SentinelConfig, createExpressMiddleware, createFastifyPlugin, AnomiraClient as default };
package/dist/index.js CHANGED
@@ -105,10 +105,10 @@ var EventBuffer = class {
105
105
  }
106
106
  }
107
107
  log(...args) {
108
- if (this.opts.debug) console.log("[SentinelAPI]", ...args);
108
+ if (this.opts.debug) console.log("[Anomira]", ...args);
109
109
  }
110
110
  warn(...args) {
111
- console.warn("[SentinelAPI]", ...args);
111
+ console.warn("[Anomira]", ...args);
112
112
  }
113
113
  };
114
114
  function sleep(ms) {
@@ -195,17 +195,15 @@ async function checkGeoVelocity(userId, ip, tsMs, lookupUrl) {
195
195
 
196
196
  // src/sensitive.ts
197
197
  var PATTERNS = [
198
- // ── Cryptographic keys and certificates ───────────────────────────────────
198
+ // ── Cryptographic private keys ────────────────────────────────────────────
199
+ // NOTE: -----BEGIN CERTIFICATE----- is intentionally excluded — public
200
+ // certificates are designed to be public and committing them is correct.
201
+ // Only PRIVATE keys are dangerous.
199
202
  {
200
203
  type: "private_key",
201
204
  label: "Private Key",
202
205
  regex: /-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/
203
206
  },
204
- {
205
- type: "certificate",
206
- label: "Certificate / Public Key",
207
- regex: /-----BEGIN CERTIFICATE-----/
208
- },
209
207
  // ── Cloud provider credentials ────────────────────────────────────────────
210
208
  {
211
209
  // AWS access key ID — highly specific, almost no false positives
@@ -338,11 +336,12 @@ var PATTERNS = [
338
336
  },
339
337
  // ── Nigeria-specific PII ──────────────────────────────────────────────────
340
338
  {
341
- // BVN / NIN: 11 digits, first digit 1-9 (not a phone starting with 0)
342
- // Require a non-digit boundary on both sides to reduce false positives
339
+ // BVN / NIN: 11 digits, first digit 1-9 (not a phone number starting with 0)
340
+ // Exclude: inside URLs (preceded by / : @ - %), hex strings (followed by a-f),
341
+ // and UUIDs/hashes (surrounded by alphanumeric chars)
343
342
  type: "bvn",
344
343
  label: "BVN / NIN",
345
- regex: /(?<!\d)[1-9]\d{10}(?!\d)/
344
+ regex: /(?<![/\-:@%=a-fA-F\w])[1-9]\d{10}(?![a-fA-F\d])/
346
345
  },
347
346
  {
348
347
  // Nigerian phone numbers: 080x, 081x, 070x, 090x, 091x — or with +234 prefix
@@ -409,7 +408,7 @@ var DEFAULT_INGEST_URL = "https://ingest.anomira.io/v1/events";
409
408
  var DEFAULT_BATCH_SIZE = 100;
410
409
  var DEFAULT_FLUSH_MS = 5e3;
411
410
  var DEFAULT_MAX_RETRIES = 3;
412
- var SentinelClient = class {
411
+ var AnomiraClient = class {
413
412
  constructor(config) {
414
413
  this.logBuffer = [];
415
414
  this.logFlushTimer = null;
@@ -508,7 +507,7 @@ var SentinelClient = class {
508
507
  console[method] = (...args) => {
509
508
  original(...args);
510
509
  const first = args[0];
511
- if (typeof first === "string" && first.startsWith("[SentinelAPI]")) return;
510
+ if (typeof first === "string" && first.startsWith("[Anomira]")) return;
512
511
  const message = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
513
512
  const ctx = requestContext.getStore();
514
513
  this.log(level, message, {
@@ -532,7 +531,7 @@ var SentinelClient = class {
532
531
  const data = await res.json();
533
532
  this.blockedIpCache = new Set(data.ips ?? []);
534
533
  if (this.config.debug && this.blockedIpCache.size > 0) {
535
- this._origLog(`[SentinelAPI] blocklist refreshed \u2014 ${this.blockedIpCache.size} blocked IPs`);
534
+ this._origLog(`[Anomira] blocklist refreshed \u2014 ${this.blockedIpCache.size} blocked IPs`);
536
535
  }
537
536
  } catch {
538
537
  }
@@ -560,7 +559,7 @@ var SentinelClient = class {
560
559
  })() : void 0
561
560
  }));
562
561
  if (this.config.debug && this.compiledRules.length > 0) {
563
- this._origLog(`[SentinelAPI] firewall rules refreshed \u2014 ${this.compiledRules.length} active rules`);
562
+ this._origLog(`[Anomira] firewall rules refreshed \u2014 ${this.compiledRules.length} active rules`);
564
563
  }
565
564
  } catch {
566
565
  }
@@ -611,7 +610,7 @@ var SentinelClient = class {
611
610
  signal: AbortSignal.timeout(8e3)
612
611
  });
613
612
  if (this.config.debug) {
614
- this._origLog(`[SentinelAPI] [logs] \u2705 sent ${batch.length} log entries (${res.status})`);
613
+ this._origLog(`[Anomira] [logs] \u2705 sent ${batch.length} log entries (${res.status})`);
615
614
  }
616
615
  } catch {
617
616
  this.logBuffer.unshift(...batch);
@@ -630,24 +629,24 @@ var SentinelClient = class {
630
629
  signal: AbortSignal.timeout(5e3)
631
630
  });
632
631
  if (res.status >= 300 && res.status < 400) {
633
- this._origWarn(`[SentinelAPI] \u274C Wrong ingest URL \u2014 got redirect to ${res.headers.get("location")}. Check SENTINEL_INGEST_URL.`);
632
+ this._origWarn(`[Anomira] \u274C Wrong ingest URL \u2014 got redirect to ${res.headers.get("location")}. Check SENTINEL_INGEST_URL.`);
634
633
  return;
635
634
  }
636
635
  if (res.ok) {
637
- this._origLog(`[SentinelAPI] \u2705 Connected (appId: ${this.config.appId.slice(0, 8)}\u2026)`);
636
+ this._origLog(`[Anomira] \u2705 Connected (appId: ${this.config.appId.slice(0, 8)}\u2026)`);
638
637
  return;
639
638
  }
640
639
  if (res.status === 401) {
641
- this._origWarn("[SentinelAPI] \u274C Invalid API key \u2014 check your SENTINEL_API_KEY");
640
+ this._origWarn("[Anomira] \u274C Invalid API key \u2014 check your SENTINEL_API_KEY");
642
641
  return;
643
642
  }
644
643
  if (res.status === 403) {
645
- this._origWarn("[SentinelAPI] \u274C App not found or appId mismatch \u2014 check your SENTINEL_APP_ID");
644
+ this._origWarn("[Anomira] \u274C App not found or appId mismatch \u2014 check your SENTINEL_APP_ID");
646
645
  return;
647
646
  }
648
- this._origWarn(`[SentinelAPI] \u26A0\uFE0F Ingest returned HTTP ${res.status} \u2014 check your configuration`);
647
+ this._origWarn(`[Anomira] \u26A0\uFE0F Ingest returned HTTP ${res.status} \u2014 check your configuration`);
649
648
  } catch {
650
- this._origWarn("[SentinelAPI] \u26A0\uFE0F Could not reach ingest endpoint \u2014 check SENTINEL_INGEST_URL (current: " + this.config.ingestUrl + ")");
649
+ this._origWarn("[Anomira] \u26A0\uFE0F Could not reach ingest endpoint \u2014 check SENTINEL_INGEST_URL (current: " + this.config.ingestUrl + ")");
651
650
  }
652
651
  }
653
652
  // ─── Public API ────────────────────────────────────────────────────────────
@@ -744,7 +743,7 @@ var SentinelClient = class {
744
743
  });
745
744
  }
746
745
  /**
747
- * Send a structured log entry to the SentinelAPI Logs dashboard.
746
+ * Send a structured log entry to the Anomira Logs dashboard.
748
747
  *
749
748
  * ```ts
750
749
  * sentinel.log("info", "User registered", { userId: user.id });
@@ -760,16 +759,47 @@ var SentinelClient = class {
760
759
  rest["sensitiveLeaks"] = leaks.map((l) => l.type);
761
760
  if (this.config.debug) {
762
761
  this._origWarn(
763
- `[SentinelAPI] \u26A0\uFE0F Sensitive data in log (${leaks.map((l) => l.label).join(", ")}): "${message.slice(0, 60)}\u2026"`
762
+ `[Anomira] \u26A0\uFE0F Sensitive data in log (${leaks.map((l) => l.label).join(", ")}): "${message.slice(0, 60)}\u2026"`
764
763
  );
765
764
  }
766
765
  }
767
766
  this.logBuffer.push({ level, service: service ?? this.config.service, message, meta: rest, ts: Date.now() });
768
767
  if (this.config.debug && leaks.length === 0) {
769
- this._origLog(`[SentinelAPI] log:${level} ${message}`);
768
+ this._origLog(`[Anomira] log:${level} ${message}`);
770
769
  }
771
770
  if (this.logBuffer.length >= 50) void this.#flushLogs();
772
771
  }
772
+ /**
773
+ * Declare your API's known endpoints so Anomira can flag undiscovered
774
+ * traffic as shadow endpoints.
775
+ *
776
+ * Call this once on startup after your routes are registered:
777
+ *
778
+ * ```ts
779
+ * await sentinel.declareEndpoints([
780
+ * { method: "GET", path: "/api/users/:id", auth: true },
781
+ * { method: "POST", path: "/api/orders", auth: true },
782
+ * { method: "GET", path: "/api/health", auth: false },
783
+ * ]);
784
+ * ```
785
+ */
786
+ async declareEndpoints(endpoints) {
787
+ if (this.disabled || endpoints.length === 0) return;
788
+ const url = this.config.ingestUrl.replace(/\/v1\/events$/, "/v1/declare-endpoints");
789
+ try {
790
+ await fetch(url, {
791
+ method: "POST",
792
+ headers: {
793
+ Authorization: `Bearer ${this.config.apiKey}`,
794
+ "Content-Type": "application/json",
795
+ "User-Agent": `@anomira/node-sdk/0.1.0`
796
+ },
797
+ body: JSON.stringify({ appId: this.config.appId, endpoints }),
798
+ signal: AbortSignal.timeout(1e4)
799
+ });
800
+ } catch {
801
+ }
802
+ }
773
803
  /**
774
804
  * Flush all pending events immediately.
775
805
  * Useful before a graceful shutdown outside of the process lifecycle hooks.
@@ -1110,6 +1140,6 @@ function createFastifyPlugin2(client) {
1110
1140
  };
1111
1141
  }
1112
1142
 
1113
- export { EventName, SentinelClient as SentinelAPI, createExpressMiddleware2 as createExpressMiddleware, createFastifyPlugin2 as createFastifyPlugin, SentinelClient as default };
1143
+ export { AnomiraClient as Anomira, EventName, AnomiraClient as SentinelAPI, createExpressMiddleware2 as createExpressMiddleware, createFastifyPlugin2 as createFastifyPlugin, AnomiraClient as default };
1114
1144
  //# sourceMappingURL=index.js.map
1115
1145
  //# sourceMappingURL=index.js.map