securenow 8.14.0 → 8.14.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/cli/automation.js CHANGED
@@ -82,7 +82,7 @@ async function list(args, flags) {
82
82
 
83
83
  console.log('');
84
84
  const rows = rules.map((rule) => [
85
- ui.c.dim(ui.truncate(rule._id || rule.id, 12)),
85
+ ui.c.dim(rule.id || rule._id || ''),
86
86
  rule.name || '-',
87
87
  ui.statusBadge(rule.status || 'active'),
88
88
  formatApplications(rule),
package/cli/challenges.js CHANGED
@@ -64,7 +64,7 @@ async function list(args, flags) {
64
64
 
65
65
  console.log('');
66
66
  const rows = rules.map((r) => [
67
- ui.c.dim(ui.truncate(r.id || r._id, 12)),
67
+ ui.c.dim(r.id || r._id || ''),
68
68
  r.status === 'active' ? ui.statusBadge('active') : ui.statusBadge(r.status || 'unknown'),
69
69
  describeTarget(r),
70
70
  `pow:${r.difficulty}`,
package/cli/fp.js CHANGED
@@ -76,7 +76,7 @@ async function list(args, flags) {
76
76
  const rows = exclusions.map(e => {
77
77
  const scope = e.type === 'global' ? ui.c.cyan('All Rules') : `Rule: ${ui.truncate(e.ruleName || '?', 18)}`;
78
78
  return [
79
- ui.c.dim(ui.truncate(e._id, 12)),
79
+ ui.c.dim(e.id || e._id || ''),
80
80
  scope,
81
81
  ui.truncate(conditionsSummary(e.conditions, e.matchMode), 40),
82
82
  (e.matchMode || 'all').toUpperCase(),
package/cli/monitor.js CHANGED
@@ -351,7 +351,7 @@ async function notificationsList(args, flags) {
351
351
 
352
352
  console.log('');
353
353
  const rows = notifications.map(n => [
354
- ui.c.dim(ui.truncate(n._id, 12)),
354
+ ui.c.dim(n.id || n._id || ''),
355
355
  ui.statusBadge(n.read ? 'read' : 'unread'),
356
356
  ui.truncate(n.title || n.message || n.type || '', 50),
357
357
  n.ip || '—',
package/cli/rateLimits.js CHANGED
@@ -47,6 +47,16 @@ function describeTarget(rule) {
47
47
  return parts.join(' ') || 'all traffic';
48
48
  }
49
49
 
50
+ // The bucket each request counts against: "ip", "global", "header x-api-key", "cookie session".
51
+ function describeKey(rule) {
52
+ const keyBy = rule.keyBy || 'ip';
53
+ return rule.keyName && (keyBy === 'header' || keyBy === 'cookie') ? `${keyBy} ${rule.keyName}` : keyBy;
54
+ }
55
+
56
+ function isExpired(rule) {
57
+ return Boolean(rule.expiresAt) && new Date(rule.expiresAt).getTime() <= Date.now();
58
+ }
59
+
50
60
  function naturalText(args, flags) {
51
61
  return String(flags.text || flags.prompt || flags.query || args.join(' ') || '').trim();
52
62
  }
@@ -62,6 +72,11 @@ function draftFromFlags(flags) {
62
72
  if (flags.mode || flags['path-mode']) draft.pathMatchMode = flags.mode || flags['path-mode'];
63
73
  if (flags.method) draft.method = flags.method;
64
74
  if (flags['key-by'] || flags.keyBy) draft.keyBy = flags['key-by'] || flags.keyBy;
75
+ else if (flags.header) draft.keyBy = 'header';
76
+ else if (flags.cookie) draft.keyBy = 'cookie';
77
+ if (flags['key-name'] || flags.keyName || flags.header || flags.cookie) {
78
+ draft.keyName = flags['key-name'] || flags.keyName || flags.header || flags.cookie;
79
+ }
65
80
  if (flags.limit) draft.limit = Number(flags.limit);
66
81
  if (flags.window || flags['window-seconds']) draft.windowSeconds = parseWindow(flags.window || flags['window-seconds']);
67
82
  if (flags.duration) draft.duration = flags.duration;
@@ -76,7 +91,7 @@ function printParsedDraft(data) {
76
91
  ['Name', draft.name || '-'],
77
92
  ['Target', describeTarget(draft)],
78
93
  ['Limit', `${draft.limit || '-'} / ${draft.windowSeconds || '-'}s`],
79
- ['Key by', draft.keyBy || 'ip'],
94
+ ['Key by', describeKey(draft)],
80
95
  ['App', draft.appKey || 'all'],
81
96
  ['Environment', draft.environment || 'all'],
82
97
  ['Duration', draft.duration || 'none'],
@@ -107,16 +122,17 @@ async function list(args, flags) {
107
122
 
108
123
  console.log('');
109
124
  const rows = rules.map((r) => [
110
- ui.c.dim(ui.truncate(r.id || r._id, 12)),
111
- r.status === 'active' ? ui.statusBadge('active') : ui.statusBadge(r.status || 'unknown'),
125
+ ui.c.dim(r.id || r._id || ''),
126
+ ui.statusBadge(r.status === 'active' && isExpired(r) ? 'expired' : (r.status || 'unknown')),
112
127
  describeTarget(r),
113
128
  `${r.limit}/${r.windowSeconds}s`,
129
+ describeKey(r),
114
130
  r.applicationKey || ui.c.dim('all apps'),
115
131
  r.environment || ui.c.dim('all envs'),
116
132
  r.expiresAt ? new Date(r.expiresAt).toLocaleString() : ui.c.dim('permanent'),
117
133
  ui.timeAgo(r.createdAt),
118
134
  ]);
119
- ui.table(['ID', 'Status', 'Target', 'Limit', 'App', 'Env', 'Expires', 'Created'], rows);
135
+ ui.table(['ID', 'Status', 'Target', 'Limit', 'Per', 'App', 'Env', 'Expires', 'Created'], rows);
120
136
  console.log('');
121
137
  } catch (err) {
122
138
  s.fail('Failed to fetch rate limits');
@@ -167,7 +183,7 @@ async function fromText(args, flags) {
167
183
  if (flags.json) { ui.json(data); return; }
168
184
  const r = data.rateLimit;
169
185
  console.log('');
170
- console.log(` ${ui.c.green('ACTIVE')} ${describeTarget(r)} at ${r.limit}/${r.windowSeconds}s`);
186
+ console.log(` ${ui.c.green('ACTIVE')} ${describeTarget(r)} at ${r.limit}/${r.windowSeconds}s per ${describeKey(r)}`);
171
187
  console.log(` ${ui.c.dim('ID:')} ${r.id || r._id}`);
172
188
  console.log('');
173
189
  } catch (err) {
@@ -197,7 +213,7 @@ async function show(args, flags) {
197
213
  ['Status', r.status || '-'],
198
214
  ['Target', describeTarget(r)],
199
215
  ['Limit', `${r.limit}/${r.windowSeconds}s`],
200
- ['Key by', r.keyName ? `${r.keyBy} ${r.keyName}` : (r.keyBy || 'ip')],
216
+ ['Key by', describeKey(r)],
201
217
  ['App', r.applicationKey || 'all apps'],
202
218
  ['Environment', r.environment || 'all envs'],
203
219
  ['Reason', r.reason || '-'],
@@ -251,7 +267,7 @@ async function add(args, flags) {
251
267
  if (flags.json) { ui.json(data); return; }
252
268
  const r = data.rateLimit;
253
269
  console.log('');
254
- console.log(` ${ui.c.green('ACTIVE')} ${describeTarget(r)} at ${r.limit}/${r.windowSeconds}s`);
270
+ console.log(` ${ui.c.green('ACTIVE')} ${describeTarget(r)} at ${r.limit}/${r.windowSeconds}s per ${describeKey(r)}`);
255
271
  console.log(` ${ui.c.dim('ID:')} ${r.id || r._id}`);
256
272
  console.log('');
257
273
  } catch (err) {
@@ -330,7 +346,7 @@ async function test(args, flags) {
330
346
  if (data.limited) {
331
347
  console.log(` ${ui.c.bold(ui.c.yellow('RATE LIMITED'))} - ${data.matches.length} matching rule${data.matches.length !== 1 ? 's' : ''}`);
332
348
  for (const r of data.matches.slice(0, 5)) {
333
- console.log(` ${ui.c.dim(r.id || r._id)} ${describeTarget(r)} ${r.limit}/${r.windowSeconds}s`);
349
+ console.log(` ${ui.c.dim(r.id || r._id)} ${describeTarget(r)} ${r.limit}/${r.windowSeconds}s per ${describeKey(r)}`);
334
350
  }
335
351
  } else {
336
352
  console.log(` ${ui.c.bold(ui.c.green('NOT LIMITED'))} - no matching rate-limit rules`);
package/cli/security.js CHANGED
@@ -190,7 +190,7 @@ async function alertRulesList(args, flags) {
190
190
 
191
191
  console.log('');
192
192
  const rows = rules.map((r) => [
193
- ui.c.dim(ui.truncate(r._id || r.id, 12)),
193
+ ui.c.dim(r.id || r._id || ''),
194
194
  r.name || '—',
195
195
  ruleStatusBadge(r),
196
196
  r.mode === 'test' ? ui.c.yellow('test') : ui.c.dim('prod'),
@@ -836,7 +836,7 @@ async function alertRuleExclusions(args, flags) {
836
836
  if (flags.json) { ui.json(data); return; }
837
837
  console.log('');
838
838
  const rows = exclusions.map((e) => [
839
- ui.c.dim(ui.truncate(e._id, 12)),
839
+ ui.c.dim(e.id || e._id || ''),
840
840
  e.isActive === false ? ui.statusBadge('disabled') : ui.statusBadge('active'),
841
841
  e.matchMode || 'all',
842
842
  ui.truncate(e.reason || e.pathPattern || JSON.stringify(e.conditions || []), 72),
@@ -862,7 +862,7 @@ async function alertChannelsList(args, flags) {
862
862
 
863
863
  console.log('');
864
864
  const rows = channels.map(ch => [
865
- ui.c.dim(ui.truncate(ch._id, 12)),
865
+ ui.c.dim(ch.id || ch._id || ''),
866
866
  ch.name || '—',
867
867
  ch.type || '—',
868
868
  ui.statusBadge(ch.enabled !== false ? 'enabled' : 'disabled'),
@@ -891,7 +891,7 @@ async function alertHistoryList(args, flags) {
891
891
 
892
892
  console.log('');
893
893
  const rows = history.map(h => [
894
- ui.c.dim(ui.truncate(h._id, 12)),
894
+ ui.c.dim(h.id || h._id || ''),
895
895
  h.ruleName || h.type || '—',
896
896
  h.severity ? ui.statusBadge(h.severity) : '—',
897
897
  ui.truncate(h.message || h.description || '', 40),
@@ -938,7 +938,7 @@ async function blocklistList(args, flags) {
938
938
 
939
939
  console.log('');
940
940
  const rows = items.map(b => [
941
- ui.c.dim(ui.truncate(b._id, 12)),
941
+ ui.c.dim(b.id || b._id || ''),
942
942
  ui.c.red(describeBlockTarget(b)),
943
943
  ui.truncate(b.reason || '', 40),
944
944
  b.source || '—',
@@ -1011,7 +1011,7 @@ async function revokeList(args, flags) {
1011
1011
  if (flags.json) { ui.json(entries); return; }
1012
1012
  console.log('');
1013
1013
  ui.table(['ID', 'Type', 'Value', 'Scope', 'Expires'], entries.map((r) => [
1014
- ui.c.dim(ui.truncate(r._id || r.id, 12)),
1014
+ ui.c.dim(r.id || r._id || ''),
1015
1015
  r.type,
1016
1016
  ui.truncate(r.value, 28),
1017
1017
  r.applicationKey || ui.c.dim('all'),
@@ -1191,7 +1191,7 @@ async function allowlistList(args, flags) {
1191
1191
 
1192
1192
  console.log('');
1193
1193
  const rows = items.map(a => [
1194
- ui.c.dim(ui.truncate(a._id, 12)),
1194
+ ui.c.dim(a.id || a._id || ''),
1195
1195
  ui.c.green(a.ip || '—'),
1196
1196
  a.label || ui.c.dim('—'),
1197
1197
  ui.truncate(a.reason || '', 40),
@@ -1307,7 +1307,7 @@ async function trustedList(args, flags) {
1307
1307
 
1308
1308
  console.log('');
1309
1309
  const rows = items.map(t => [
1310
- ui.c.dim(ui.truncate(t._id, 12)),
1310
+ ui.c.dim(t.id || t._id || ''),
1311
1311
  ui.c.green(t.ip || t.cidr || '—'),
1312
1312
  t.label || t.description || ui.c.dim('—'),
1313
1313
  t.applicationKey || ui.c.dim('all apps'),
@@ -1494,7 +1494,7 @@ async function forensicsLibrary(args, flags) {
1494
1494
 
1495
1495
  console.log('');
1496
1496
  const rows = queries.map(q => [
1497
- ui.c.dim(ui.truncate(q._id, 12)),
1497
+ ui.c.dim(q.id || q._id || ''),
1498
1498
  q.name || q.title || '—',
1499
1499
  ui.truncate(q.description || q.query || '', 50),
1500
1500
  ui.timeAgo(q.createdAt),
@@ -1756,7 +1756,7 @@ async function instancesList(args, flags) {
1756
1756
 
1757
1757
  console.log('');
1758
1758
  const rows = instances.map(inst => [
1759
- ui.c.dim(ui.truncate(inst._id, 12)),
1759
+ ui.c.dim(inst.id || inst._id || ''),
1760
1760
  inst.name || inst.host || '—',
1761
1761
  inst.host || '—',
1762
1762
  inst.port != null ? String(inst.port) : '—',
package/cli/ui.js CHANGED
@@ -354,6 +354,7 @@ function statusBadge(status) {
354
354
  trusted: c.green('■ trusted'),
355
355
  enabled: c.green('● enabled'),
356
356
  disabled: c.dim('○ disabled'),
357
+ expired: c.dim('○ expired'),
357
358
  paused: c.yellow('◆ paused'),
358
359
  critical: c.red('▲ critical'),
359
360
  high: c.red('▲ high'),
package/firewall.js CHANGED
@@ -1478,7 +1478,7 @@ function init(options) {
1478
1478
  _rateLimitStore = require('./rate-limit-store').createRateLimitStore(storeSpec, {
1479
1479
  log: (...args) => { if (_options.log) fwLog(...args); },
1480
1480
  });
1481
- if (_options.log && _rateLimitStore) fwLog('[securenow] Firewall: shared rate-limit counters → %s', _rateLimitStore.describe());
1481
+ if (_options.log && _rateLimitStore) fwLog('[securenow] Firewall: shared rate-limit counters: connecting to %s', _rateLimitStore.describe());
1482
1482
  } catch (e) {
1483
1483
  _rateLimitStore = null;
1484
1484
  if (_options.log) fwWarn('[securenow] Firewall: rate-limit store disabled (%s); counting in-process', e.message);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securenow",
3
- "version": "8.14.0",
3
+ "version": "8.14.1",
4
4
  "mcpName": "ai.securenow/securenow",
5
5
  "description": "OpenTelemetry instrumentation for Node.js, Next.js, and Nuxt - Send traces and logs to any OTLP-compatible backend",
6
6
  "type": "commonjs",