paygate-mcp 5.0.0 → 5.2.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/README.md +94 -0
- package/dist/audit.d.ts +1 -1
- package/dist/audit.d.ts.map +1 -1
- package/dist/audit.js.map +1 -1
- package/dist/expiry-scanner.d.ts +99 -0
- package/dist/expiry-scanner.d.ts.map +1 -0
- package/dist/expiry-scanner.js +216 -0
- package/dist/expiry-scanner.js.map +1 -0
- package/dist/key-templates.d.ts +80 -0
- package/dist/key-templates.d.ts.map +1 -0
- package/dist/key-templates.js +129 -0
- package/dist/key-templates.js.map +1 -0
- package/dist/server.d.ts +10 -5
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +185 -13
- package/dist/server.js.map +1 -1
- package/dist/store.d.ts +5 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +7 -0
- package/dist/store.js.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/webhook.d.ts +1 -1
- package/dist/webhook.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -77,6 +77,8 @@ Agent → PayGate (auth + billing) → Your MCP Server (stdio or HTTP)
|
|
|
77
77
|
- **Webhook Delivery Log** — `GET /webhooks/log` returns a queryable log of all webhook delivery attempts with timestamps, HTTP status codes, response times, success/failure, retry attempts, event counts, and event types — filter by success status, time range, and limit
|
|
78
78
|
- **Webhook Pause/Resume** — `POST /webhooks/pause` and `POST /webhooks/resume` temporarily halt webhook delivery during maintenance — events are buffered (not lost) and flushed on resume, with pause state visible in `/webhooks/stats`
|
|
79
79
|
- **Key Aliases** — `POST /keys/alias` assigns human-readable aliases (e.g. `my-service`, `prod-backend`) to API keys — use aliases in any admin endpoint (topup, revoke, suspend, resume, clone, transfer, usage) instead of opaque key IDs, with uniqueness enforcement, format validation, state file persistence, and audit trail
|
|
80
|
+
- **Key Expiry Scanner** — Proactive background scanner that detects expiring API keys before they expire — configurable scan interval and notification thresholds (default: 7d, 24h, 1h), de-duplicated `key.expiry_warning` webhook events, audit trail, `GET /keys/expiring?within=86400` query endpoint, and graceful shutdown
|
|
81
|
+
- **Key Templates** — Named templates for API key creation — define reusable presets (credits, ACL, quotas, IP, tags, namespace, expiry TTL, spending limit, auto-topup) and create keys with `template: "free-tier"` — explicit params override template defaults, CRUD admin API, Prometheus gauge, file persistence, max 100 templates
|
|
80
82
|
- **Config Hot Reload** — `POST /config/reload` reloads pricing, rate limits, webhooks, quotas, and behavior flags from config file without server restart
|
|
81
83
|
- **Webhook Events** — POST batched usage events to any URL for external billing/alerting
|
|
82
84
|
- **Config File Mode** — Load all settings from a JSON file (`--config`)
|
|
@@ -359,6 +361,10 @@ A real-time admin UI for managing keys, viewing usage, and monitoring tool calls
|
|
|
359
361
|
| `/webhooks/pause` | POST | `X-Admin-Key` | Pause webhook delivery (events buffered until resumed) |
|
|
360
362
|
| `/webhooks/resume` | POST | `X-Admin-Key` | Resume webhook delivery and flush buffered events |
|
|
361
363
|
| `/keys/alias` | POST | `X-Admin-Key` | Set or clear a human-readable alias for an API key |
|
|
364
|
+
| `/keys/expiring` | GET | `X-Admin-Key` | List keys expiring within a time window (`?within=86400` seconds) |
|
|
365
|
+
| `/keys/templates` | GET | `X-Admin-Key` | List all key templates |
|
|
366
|
+
| `/keys/templates` | POST | `X-Admin-Key` | Create or update a key template |
|
|
367
|
+
| `/keys/templates/delete` | POST | `X-Admin-Key` | Delete a key template |
|
|
362
368
|
| `/config/reload` | POST | `X-Admin-Key` | Hot-reload config file (pricing, rate limits, webhooks, quotas) |
|
|
363
369
|
| `/health` | GET | None | Health check (status, uptime, version, in-flight, Redis/webhook status) |
|
|
364
370
|
| `/` | GET | None | Root endpoint (endpoint list) |
|
|
@@ -1237,6 +1243,94 @@ curl -X POST http://localhost:3402/keys/alias \
|
|
|
1237
1243
|
| Clone | Cloned keys do **not** inherit the source key's alias |
|
|
1238
1244
|
| Audit | `key.alias_set` event logged for every set/clear operation |
|
|
1239
1245
|
|
|
1246
|
+
### Key Expiry Scanner
|
|
1247
|
+
|
|
1248
|
+
Proactive background scanner that detects API keys approaching expiration and sends webhook notifications before they expire — even if the keys are not actively being used:
|
|
1249
|
+
|
|
1250
|
+
```bash
|
|
1251
|
+
# Query keys expiring within 24 hours (default)
|
|
1252
|
+
curl http://localhost:3402/keys/expiring \
|
|
1253
|
+
-H "X-Admin-Key: YOUR_ADMIN_KEY"
|
|
1254
|
+
# → { "within": 86400, "count": 2, "scanner": { ... }, "keys": [ ... ] }
|
|
1255
|
+
|
|
1256
|
+
# Query keys expiring within 7 days
|
|
1257
|
+
curl http://localhost:3402/keys/expiring?within=604800 \
|
|
1258
|
+
-H "X-Admin-Key: YOUR_ADMIN_KEY"
|
|
1259
|
+
```
|
|
1260
|
+
|
|
1261
|
+
Configure the scanner in your config file:
|
|
1262
|
+
|
|
1263
|
+
```json
|
|
1264
|
+
{
|
|
1265
|
+
"expiryScanner": {
|
|
1266
|
+
"enabled": true,
|
|
1267
|
+
"intervalSeconds": 3600,
|
|
1268
|
+
"thresholds": [604800, 86400, 3600]
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
```
|
|
1272
|
+
|
|
1273
|
+
| Field | Description |
|
|
1274
|
+
|-------|-------------|
|
|
1275
|
+
| `enabled` | Enable/disable the background scanner. Default: `true` |
|
|
1276
|
+
| `intervalSeconds` | How often to scan (seconds). Default: `3600` (1 hour). Min: 60 |
|
|
1277
|
+
| `thresholds` | Seconds before expiry to notify. Default: `[604800, 86400, 3600]` (7d, 24h, 1h) |
|
|
1278
|
+
| Webhook | Fires `key.expiry_warning` events with key name, alias, namespace, expiry time, and remaining seconds |
|
|
1279
|
+
| De-duplication | Each key+threshold pair is only notified once (no duplicate alerts) |
|
|
1280
|
+
| Progressive | Largest threshold fires first, then progressively smaller thresholds on subsequent scans |
|
|
1281
|
+
| Audit | `key.expiry_warning` event logged for every notification |
|
|
1282
|
+
| Endpoint | `GET /keys/expiring?within=N` lists keys expiring within N seconds (default: 86400) |
|
|
1283
|
+
|
|
1284
|
+
### Key Templates
|
|
1285
|
+
|
|
1286
|
+
Named templates for API key creation. Define reusable presets and create keys with `template: "free-tier"`:
|
|
1287
|
+
|
|
1288
|
+
```bash
|
|
1289
|
+
# Create a template
|
|
1290
|
+
curl -X POST http://localhost:3402/keys/templates \
|
|
1291
|
+
-H "X-Admin-Key: YOUR_ADMIN_KEY" \
|
|
1292
|
+
-d '{
|
|
1293
|
+
"name": "free-tier",
|
|
1294
|
+
"description": "Free plan with basic access",
|
|
1295
|
+
"credits": 50,
|
|
1296
|
+
"allowedTools": ["search", "read"],
|
|
1297
|
+
"deniedTools": ["admin"],
|
|
1298
|
+
"tags": {"plan": "free"},
|
|
1299
|
+
"namespace": "public",
|
|
1300
|
+
"expiryTtlSeconds": 2592000,
|
|
1301
|
+
"spendingLimit": 200
|
|
1302
|
+
}'
|
|
1303
|
+
|
|
1304
|
+
# List all templates
|
|
1305
|
+
curl http://localhost:3402/keys/templates \
|
|
1306
|
+
-H "X-Admin-Key: YOUR_ADMIN_KEY"
|
|
1307
|
+
|
|
1308
|
+
# Create a key from template (inherits all defaults)
|
|
1309
|
+
curl -X POST http://localhost:3402/keys \
|
|
1310
|
+
-H "X-Admin-Key: YOUR_ADMIN_KEY" \
|
|
1311
|
+
-d '{"name": "new-user", "template": "free-tier"}'
|
|
1312
|
+
|
|
1313
|
+
# Create a key from template with overrides
|
|
1314
|
+
curl -X POST http://localhost:3402/keys \
|
|
1315
|
+
-H "X-Admin-Key: YOUR_ADMIN_KEY" \
|
|
1316
|
+
-d '{"name": "vip-user", "template": "free-tier", "credits": 500, "tags": {"plan": "vip"}}'
|
|
1317
|
+
|
|
1318
|
+
# Delete a template
|
|
1319
|
+
curl -X POST http://localhost:3402/keys/templates/delete \
|
|
1320
|
+
-H "X-Admin-Key: YOUR_ADMIN_KEY" \
|
|
1321
|
+
-d '{"name": "free-tier"}'
|
|
1322
|
+
```
|
|
1323
|
+
|
|
1324
|
+
| Feature | Details |
|
|
1325
|
+
|---------|---------|
|
|
1326
|
+
| Fields | credits, allowedTools, deniedTools, quota, ipAllowlist, spendingLimit, tags, namespace, expiryTtlSeconds, autoTopup |
|
|
1327
|
+
| Override | Explicit params in `POST /keys` always override template defaults |
|
|
1328
|
+
| TTL | `expiryTtlSeconds` sets expiry relative to key creation time (0 = never) |
|
|
1329
|
+
| Limit | Max 100 templates per server |
|
|
1330
|
+
| Persistence | `-templates.json` alongside state file, survives restarts |
|
|
1331
|
+
| Audit | `template.created`, `template.updated`, `template.deleted` events |
|
|
1332
|
+
| Prometheus | `paygate_templates_total` gauge tracks template count |
|
|
1333
|
+
|
|
1240
1334
|
### IP Allowlisting
|
|
1241
1335
|
|
|
1242
1336
|
Restrict API keys to specific IP addresses or CIDR ranges:
|
package/dist/audit.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* session lifecycle, and admin operations. Ring buffer with configurable
|
|
6
6
|
* max size and age-based retention. Zero external dependencies.
|
|
7
7
|
*/
|
|
8
|
-
export type AuditEventType = 'key.created' | 'key.revoked' | 'key.suspended' | 'key.resumed' | 'key.cloned' | 'key.rotated' | 'key.topup' | 'key.acl_updated' | 'key.expiry_updated' | 'key.quota_updated' | 'key.tags_updated' | 'key.ip_updated' | 'key.limit_updated' | 'gate.allow' | 'gate.deny' | 'session.created' | 'session.destroyed' | 'oauth.client_registered' | 'oauth.token_issued' | 'oauth.token_revoked' | 'team.created' | 'team.updated' | 'team.deleted' | 'team.key_assigned' | 'team.key_removed' | 'admin.auth_failed' | 'admin.alerts_configured' | 'webhook.dead_letter_cleared' | 'webhook.replayed' | 'webhook.test' | 'webhook.pause' | 'webhook.resume' | 'key.alias_set' | 'token.created' | 'token.revoked' | 'billing.refund' | 'key.auto_topup_configured' | 'key.auto_topped_up' | 'admin_key.created' | 'admin_key.revoked' | 'group.created' | 'group.updated' | 'group.deleted' | 'group.key_assigned' | 'group.key_removed' | 'key.credits_transferred' | 'keys.exported' | 'keys.imported' | 'webhook_filter.created' | 'webhook_filter.updated' | 'webhook_filter.deleted' | 'config.reloaded';
|
|
8
|
+
export type AuditEventType = 'key.created' | 'key.revoked' | 'key.suspended' | 'key.resumed' | 'key.cloned' | 'key.rotated' | 'key.topup' | 'key.acl_updated' | 'key.expiry_updated' | 'key.quota_updated' | 'key.tags_updated' | 'key.ip_updated' | 'key.limit_updated' | 'gate.allow' | 'gate.deny' | 'session.created' | 'session.destroyed' | 'oauth.client_registered' | 'oauth.token_issued' | 'oauth.token_revoked' | 'team.created' | 'team.updated' | 'team.deleted' | 'team.key_assigned' | 'team.key_removed' | 'admin.auth_failed' | 'admin.alerts_configured' | 'webhook.dead_letter_cleared' | 'webhook.replayed' | 'webhook.test' | 'webhook.pause' | 'webhook.resume' | 'key.alias_set' | 'key.expiry_warning' | 'template.created' | 'template.updated' | 'template.deleted' | 'token.created' | 'token.revoked' | 'billing.refund' | 'key.auto_topup_configured' | 'key.auto_topped_up' | 'admin_key.created' | 'admin_key.revoked' | 'group.created' | 'group.updated' | 'group.deleted' | 'group.key_assigned' | 'group.key_removed' | 'key.credits_transferred' | 'keys.exported' | 'keys.imported' | 'webhook_filter.created' | 'webhook_filter.updated' | 'webhook_filter.deleted' | 'config.reloaded';
|
|
9
9
|
export interface AuditEvent {
|
|
10
10
|
/** Monotonically increasing ID */
|
|
11
11
|
id: number;
|
package/dist/audit.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,MAAM,cAAc,GAEtB,aAAa,GACb,aAAa,GACb,eAAe,GACf,aAAa,GACb,YAAY,GACZ,aAAa,GACb,WAAW,GACX,iBAAiB,GACjB,oBAAoB,GACpB,mBAAmB,GACnB,kBAAkB,GAClB,gBAAgB,GAChB,mBAAmB,GAEnB,YAAY,GACZ,WAAW,GAEX,iBAAiB,GACjB,mBAAmB,GAEnB,yBAAyB,GACzB,oBAAoB,GACpB,qBAAqB,GAErB,cAAc,GACd,cAAc,GACd,cAAc,GACd,mBAAmB,GACnB,kBAAkB,GAElB,mBAAmB,GACnB,yBAAyB,GAEzB,6BAA6B,GAC7B,kBAAkB,GAClB,cAAc,GACd,eAAe,GACf,gBAAgB,GAEhB,eAAe,GAEf,eAAe,GACf,eAAe,GAEf,gBAAgB,GAEhB,2BAA2B,GAC3B,oBAAoB,GAEpB,mBAAmB,GACnB,mBAAmB,GAEnB,eAAe,GACf,eAAe,GACf,eAAe,GACf,oBAAoB,GACpB,mBAAmB,GAEnB,yBAAyB,GAEzB,eAAe,GACf,eAAe,GAEf,wBAAwB,GACxB,wBAAwB,GACxB,wBAAwB,GAExB,iBAAiB,CAAC;AAEtB,MAAM,WAAW,UAAU;IACzB,kCAAkC;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,IAAI,EAAE,cAAc,CAAC;IACrB,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,iDAAiD;IACjD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,cAAc;IAC7B,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,WAAW,EAAE,MAAM,CAAC;IACpB,wEAAwE;IACxE,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;IACzB,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB;AAUD,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,YAAY,CAA+C;gBAEvD,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC;IAU5C;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,UAAU;IAoB7G;;OAEG;IACH,KAAK,CAAC,CAAC,GAAE,UAAe,GAAG,gBAAgB;IAoC3C;;OAEG;IACH,KAAK,IAAI;QACP,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACrC,cAAc,EAAE,MAAM,CAAC;QACvB,aAAa,EAAE,MAAM,CAAC;KACvB;IA0BD;;OAEG;IACH,SAAS,IAAI,UAAU,EAAE;IAIzB;;OAEG;IACH,SAAS,CAAC,CAAC,GAAE,UAAe,GAAG,MAAM;IASrC;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;OAEG;IACH,gBAAgB,IAAI,MAAM;IAS1B;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb;;OAEG;IACH,OAAO,IAAI,IAAI;CAMhB;AAID,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGnD"}
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"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"}
|
package/dist/audit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExpiryScanner — Proactive background scanner for expiring API keys.
|
|
3
|
+
*
|
|
4
|
+
* Unlike the reactive key_expiry_soon alert (which only fires during gate evaluation),
|
|
5
|
+
* this scanner runs on a configurable interval and catches expiring keys even when idle.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Configurable scan interval (default: 1 hour)
|
|
9
|
+
* - Multiple notification thresholds (e.g., 7d, 24h, 1h before expiry)
|
|
10
|
+
* - De-duplication: same key+threshold pair is only notified once
|
|
11
|
+
* - Fires key.expiry_warning webhook events
|
|
12
|
+
* - Audit trail for all notifications
|
|
13
|
+
* - Graceful shutdown (clears interval timer)
|
|
14
|
+
*/
|
|
15
|
+
import { ApiKeyRecord } from './types';
|
|
16
|
+
export interface ExpiryScannerConfig {
|
|
17
|
+
/** Whether the scanner is enabled. Default: true when thresholds are configured. */
|
|
18
|
+
enabled: boolean;
|
|
19
|
+
/** How often to scan, in seconds. Default: 3600 (1 hour). Min: 60. */
|
|
20
|
+
intervalSeconds: number;
|
|
21
|
+
/** Seconds before expiry to send notifications. Default: [604800, 86400, 3600] (7d, 24h, 1h). */
|
|
22
|
+
thresholds: number[];
|
|
23
|
+
}
|
|
24
|
+
export interface ExpiryWarning {
|
|
25
|
+
/** The API key (full, for internal use — mask before exposing) */
|
|
26
|
+
key: string;
|
|
27
|
+
/** Key name */
|
|
28
|
+
name: string;
|
|
29
|
+
/** Key alias (if set) */
|
|
30
|
+
alias?: string;
|
|
31
|
+
/** Key namespace */
|
|
32
|
+
namespace: string;
|
|
33
|
+
/** ISO string when the key expires */
|
|
34
|
+
expiresAt: string;
|
|
35
|
+
/** Seconds remaining until expiry */
|
|
36
|
+
remainingSeconds: number;
|
|
37
|
+
/** Human-readable time remaining */
|
|
38
|
+
remainingHuman: string;
|
|
39
|
+
/** Which threshold triggered this warning (seconds) */
|
|
40
|
+
thresholdSeconds: number;
|
|
41
|
+
}
|
|
42
|
+
export declare const DEFAULT_EXPIRY_SCANNER_CONFIG: ExpiryScannerConfig;
|
|
43
|
+
export declare class ExpiryScanner {
|
|
44
|
+
private config;
|
|
45
|
+
private timer;
|
|
46
|
+
/** De-duplication: "keyPrefix:threshold" → timestamp of last notification */
|
|
47
|
+
private readonly notified;
|
|
48
|
+
/** Callback for each warning — wired by the server to emit webhooks/audit */
|
|
49
|
+
onWarning: ((warning: ExpiryWarning) => void) | null;
|
|
50
|
+
/** Key provider — returns all key records for scanning */
|
|
51
|
+
private getKeys;
|
|
52
|
+
constructor(config?: Partial<ExpiryScannerConfig>);
|
|
53
|
+
/**
|
|
54
|
+
* Start the background scanner.
|
|
55
|
+
* @param getKeys Function that returns all key records to scan
|
|
56
|
+
*/
|
|
57
|
+
start(getKeys: () => ApiKeyRecord[]): void;
|
|
58
|
+
/**
|
|
59
|
+
* Stop the scanner and clear all state.
|
|
60
|
+
*/
|
|
61
|
+
destroy(): void;
|
|
62
|
+
/**
|
|
63
|
+
* Run a scan now (also called by the interval timer).
|
|
64
|
+
* Returns warnings found in this scan.
|
|
65
|
+
*/
|
|
66
|
+
scan(): ExpiryWarning[];
|
|
67
|
+
/**
|
|
68
|
+
* Query keys expiring within a time window (for the admin endpoint).
|
|
69
|
+
* Does NOT trigger notifications — this is a read-only query.
|
|
70
|
+
*/
|
|
71
|
+
static queryExpiring(keys: ApiKeyRecord[], withinSeconds: number): Array<{
|
|
72
|
+
keyPrefix: string;
|
|
73
|
+
name: string;
|
|
74
|
+
alias?: string;
|
|
75
|
+
namespace: string;
|
|
76
|
+
expiresAt: string;
|
|
77
|
+
remainingSeconds: number;
|
|
78
|
+
remainingHuman: string;
|
|
79
|
+
suspended: boolean;
|
|
80
|
+
}>;
|
|
81
|
+
/**
|
|
82
|
+
* Get scanner status (for /health or diagnostics).
|
|
83
|
+
*/
|
|
84
|
+
get status(): {
|
|
85
|
+
enabled: boolean;
|
|
86
|
+
intervalSeconds: number;
|
|
87
|
+
thresholds: number[];
|
|
88
|
+
notifiedCount: number;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Clear de-duplication state (for testing).
|
|
92
|
+
*/
|
|
93
|
+
clearNotified(): void;
|
|
94
|
+
/**
|
|
95
|
+
* Update config at runtime (for config hot-reload).
|
|
96
|
+
*/
|
|
97
|
+
updateConfig(config: Partial<ExpiryScannerConfig>): void;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=expiry-scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expiry-scanner.d.ts","sourceRoot":"","sources":["../src/expiry-scanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAIvC,MAAM,WAAW,mBAAmB;IAClC,oFAAoF;IACpF,OAAO,EAAE,OAAO,CAAC;IACjB,sEAAsE;IACtE,eAAe,EAAE,MAAM,CAAC;IACxB,iGAAiG;IACjG,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,kEAAkE;IAClE,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe;IACf,IAAI,EAAE,MAAM,CAAC;IACb,yBAAyB;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,gBAAgB,EAAE,MAAM,CAAC;IACzB,oCAAoC;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,uDAAuD;IACvD,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,eAAO,MAAM,6BAA6B,EAAE,mBAI3C,CAAC;AAIF,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,KAAK,CAA+C;IAC5D,6EAA6E;IAC7E,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6B;IACtD,6EAA6E;IAC7E,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC,GAAG,IAAI,CAAQ;IAC5D,0DAA0D;IAC1D,OAAO,CAAC,OAAO,CAAuC;gBAE1C,MAAM,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC;IAQjD;;;OAGG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,YAAY,EAAE,GAAG,IAAI;IAU1C;;OAEG;IACH,OAAO,IAAI,IAAI;IASf;;;OAGG;IACH,IAAI,IAAI,aAAa,EAAE;IAiEvB;;;OAGG;IACH,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,EAAE,aAAa,EAAE,MAAM,GAAG,KAAK,CAAC;QACvE,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,gBAAgB,EAAE,MAAM,CAAC;QACzB,cAAc,EAAE,MAAM,CAAC;QACvB,SAAS,EAAE,OAAO,CAAC;KACpB,CAAC;IA0CF;;OAEG;IACH,IAAI,MAAM,IAAI;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,eAAe,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,EAAE,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAOvG;IAED;;OAEG;IACH,aAAa,IAAI,IAAI;IAIrB;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAAG,IAAI;CAWzD"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ExpiryScanner — Proactive background scanner for expiring API keys.
|
|
4
|
+
*
|
|
5
|
+
* Unlike the reactive key_expiry_soon alert (which only fires during gate evaluation),
|
|
6
|
+
* this scanner runs on a configurable interval and catches expiring keys even when idle.
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Configurable scan interval (default: 1 hour)
|
|
10
|
+
* - Multiple notification thresholds (e.g., 7d, 24h, 1h before expiry)
|
|
11
|
+
* - De-duplication: same key+threshold pair is only notified once
|
|
12
|
+
* - Fires key.expiry_warning webhook events
|
|
13
|
+
* - Audit trail for all notifications
|
|
14
|
+
* - Graceful shutdown (clears interval timer)
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.ExpiryScanner = exports.DEFAULT_EXPIRY_SCANNER_CONFIG = void 0;
|
|
18
|
+
exports.DEFAULT_EXPIRY_SCANNER_CONFIG = {
|
|
19
|
+
enabled: true,
|
|
20
|
+
intervalSeconds: 3600,
|
|
21
|
+
thresholds: [604800, 86400, 3600], // 7 days, 24 hours, 1 hour
|
|
22
|
+
};
|
|
23
|
+
// ─── Scanner Class ────────────────────────────────────────────────────────────
|
|
24
|
+
class ExpiryScanner {
|
|
25
|
+
config;
|
|
26
|
+
timer = null;
|
|
27
|
+
/** De-duplication: "keyPrefix:threshold" → timestamp of last notification */
|
|
28
|
+
notified = new Map();
|
|
29
|
+
/** Callback for each warning — wired by the server to emit webhooks/audit */
|
|
30
|
+
onWarning = null;
|
|
31
|
+
/** Key provider — returns all key records for scanning */
|
|
32
|
+
getKeys = null;
|
|
33
|
+
constructor(config) {
|
|
34
|
+
this.config = { ...exports.DEFAULT_EXPIRY_SCANNER_CONFIG, ...config };
|
|
35
|
+
// Enforce minimum interval
|
|
36
|
+
if (this.config.intervalSeconds < 60)
|
|
37
|
+
this.config.intervalSeconds = 60;
|
|
38
|
+
// Sort thresholds descending (largest first) for consistent scanning
|
|
39
|
+
this.config.thresholds = [...this.config.thresholds].sort((a, b) => b - a);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Start the background scanner.
|
|
43
|
+
* @param getKeys Function that returns all key records to scan
|
|
44
|
+
*/
|
|
45
|
+
start(getKeys) {
|
|
46
|
+
if (!this.config.enabled)
|
|
47
|
+
return;
|
|
48
|
+
if (this.config.thresholds.length === 0)
|
|
49
|
+
return;
|
|
50
|
+
this.getKeys = getKeys;
|
|
51
|
+
// Run immediately on start, then on interval
|
|
52
|
+
this.scan();
|
|
53
|
+
this.timer = setInterval(() => this.scan(), this.config.intervalSeconds * 1000);
|
|
54
|
+
this.timer.unref(); // Don't prevent process exit
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Stop the scanner and clear all state.
|
|
58
|
+
*/
|
|
59
|
+
destroy() {
|
|
60
|
+
if (this.timer) {
|
|
61
|
+
clearInterval(this.timer);
|
|
62
|
+
this.timer = null;
|
|
63
|
+
}
|
|
64
|
+
this.notified.clear();
|
|
65
|
+
this.getKeys = null;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Run a scan now (also called by the interval timer).
|
|
69
|
+
* Returns warnings found in this scan.
|
|
70
|
+
*/
|
|
71
|
+
scan() {
|
|
72
|
+
if (!this.getKeys)
|
|
73
|
+
return [];
|
|
74
|
+
const keys = this.getKeys();
|
|
75
|
+
const now = Date.now();
|
|
76
|
+
const warnings = [];
|
|
77
|
+
for (const record of keys) {
|
|
78
|
+
// Skip keys without expiry, revoked, or already expired
|
|
79
|
+
if (!record.expiresAt)
|
|
80
|
+
continue;
|
|
81
|
+
if (!record.active)
|
|
82
|
+
continue;
|
|
83
|
+
const expiresMs = new Date(record.expiresAt).getTime();
|
|
84
|
+
if (isNaN(expiresMs))
|
|
85
|
+
continue;
|
|
86
|
+
const remainingMs = expiresMs - now;
|
|
87
|
+
if (remainingMs <= 0)
|
|
88
|
+
continue; // Already expired
|
|
89
|
+
const remainingSeconds = Math.round(remainingMs / 1000);
|
|
90
|
+
// Check each threshold (sorted descending)
|
|
91
|
+
for (const threshold of this.config.thresholds) {
|
|
92
|
+
if (remainingSeconds <= threshold) {
|
|
93
|
+
const dedupeKey = `${record.key.slice(0, 10)}:${threshold}`;
|
|
94
|
+
// Skip if already notified for this key+threshold
|
|
95
|
+
if (this.notified.has(dedupeKey))
|
|
96
|
+
continue;
|
|
97
|
+
const warning = {
|
|
98
|
+
key: record.key,
|
|
99
|
+
name: record.name,
|
|
100
|
+
alias: record.alias,
|
|
101
|
+
namespace: record.namespace,
|
|
102
|
+
expiresAt: record.expiresAt,
|
|
103
|
+
remainingSeconds,
|
|
104
|
+
remainingHuman: formatDuration(remainingSeconds),
|
|
105
|
+
thresholdSeconds: threshold,
|
|
106
|
+
};
|
|
107
|
+
warnings.push(warning);
|
|
108
|
+
this.notified.set(dedupeKey, now);
|
|
109
|
+
// Emit callback
|
|
110
|
+
if (this.onWarning) {
|
|
111
|
+
try {
|
|
112
|
+
this.onWarning(warning);
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
// Swallow callback errors — scanner must not crash
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Only fire the most specific (smallest) threshold per key per scan
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Cleanup old de-duplication entries (older than 2x the largest threshold)
|
|
124
|
+
const maxThreshold = this.config.thresholds[0] || 0;
|
|
125
|
+
const cleanupCutoff = now - maxThreshold * 2 * 1000;
|
|
126
|
+
for (const [k, ts] of this.notified) {
|
|
127
|
+
if (ts < cleanupCutoff)
|
|
128
|
+
this.notified.delete(k);
|
|
129
|
+
}
|
|
130
|
+
return warnings;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Query keys expiring within a time window (for the admin endpoint).
|
|
134
|
+
* Does NOT trigger notifications — this is a read-only query.
|
|
135
|
+
*/
|
|
136
|
+
static queryExpiring(keys, withinSeconds) {
|
|
137
|
+
const now = Date.now();
|
|
138
|
+
const results = [];
|
|
139
|
+
for (const record of keys) {
|
|
140
|
+
if (!record.expiresAt)
|
|
141
|
+
continue;
|
|
142
|
+
if (!record.active)
|
|
143
|
+
continue;
|
|
144
|
+
const expiresMs = new Date(record.expiresAt).getTime();
|
|
145
|
+
if (isNaN(expiresMs))
|
|
146
|
+
continue;
|
|
147
|
+
const remainingMs = expiresMs - now;
|
|
148
|
+
if (remainingMs <= 0)
|
|
149
|
+
continue; // Already expired
|
|
150
|
+
const remainingSeconds = Math.round(remainingMs / 1000);
|
|
151
|
+
if (remainingSeconds > withinSeconds)
|
|
152
|
+
continue;
|
|
153
|
+
results.push({
|
|
154
|
+
keyPrefix: record.key.slice(0, 10) + '...',
|
|
155
|
+
name: record.name,
|
|
156
|
+
alias: record.alias,
|
|
157
|
+
namespace: record.namespace,
|
|
158
|
+
expiresAt: record.expiresAt,
|
|
159
|
+
remainingSeconds,
|
|
160
|
+
remainingHuman: formatDuration(remainingSeconds),
|
|
161
|
+
suspended: record.suspended || false,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
// Sort by remaining time ascending (most urgent first)
|
|
165
|
+
results.sort((a, b) => a.remainingSeconds - b.remainingSeconds);
|
|
166
|
+
return results;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Get scanner status (for /health or diagnostics).
|
|
170
|
+
*/
|
|
171
|
+
get status() {
|
|
172
|
+
return {
|
|
173
|
+
enabled: this.config.enabled,
|
|
174
|
+
intervalSeconds: this.config.intervalSeconds,
|
|
175
|
+
thresholds: this.config.thresholds,
|
|
176
|
+
notifiedCount: this.notified.size,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Clear de-duplication state (for testing).
|
|
181
|
+
*/
|
|
182
|
+
clearNotified() {
|
|
183
|
+
this.notified.clear();
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Update config at runtime (for config hot-reload).
|
|
187
|
+
*/
|
|
188
|
+
updateConfig(config) {
|
|
189
|
+
if (config.intervalSeconds !== undefined) {
|
|
190
|
+
this.config.intervalSeconds = Math.max(60, config.intervalSeconds);
|
|
191
|
+
}
|
|
192
|
+
if (config.thresholds !== undefined) {
|
|
193
|
+
this.config.thresholds = [...config.thresholds].sort((a, b) => b - a);
|
|
194
|
+
}
|
|
195
|
+
if (config.enabled !== undefined) {
|
|
196
|
+
this.config.enabled = config.enabled;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
exports.ExpiryScanner = ExpiryScanner;
|
|
201
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
202
|
+
function formatDuration(seconds) {
|
|
203
|
+
if (seconds < 60)
|
|
204
|
+
return `${seconds}s`;
|
|
205
|
+
if (seconds < 3600)
|
|
206
|
+
return `${Math.round(seconds / 60)}m`;
|
|
207
|
+
if (seconds < 86400) {
|
|
208
|
+
const hours = Math.floor(seconds / 3600);
|
|
209
|
+
const mins = Math.round((seconds % 3600) / 60);
|
|
210
|
+
return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`;
|
|
211
|
+
}
|
|
212
|
+
const days = Math.floor(seconds / 86400);
|
|
213
|
+
const hours = Math.round((seconds % 86400) / 3600);
|
|
214
|
+
return hours > 0 ? `${days}d ${hours}h` : `${days}d`;
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=expiry-scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expiry-scanner.js","sourceRoot":"","sources":["../src/expiry-scanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KeyTemplateManager — Named templates for API key creation.
|
|
3
|
+
*
|
|
4
|
+
* Templates define reusable presets for key creation (credits, ACL, quotas, etc.).
|
|
5
|
+
* Instead of passing all options every time, use `template: "free-tier"` in POST /keys.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - CRUD: create, update, list, get, delete templates
|
|
9
|
+
* - File persistence (-templates.json alongside state file)
|
|
10
|
+
* - Templates define: credits, allowedTools, deniedTools, quota, ipAllowlist,
|
|
11
|
+
* spendingLimit, tags, namespace, expiryTtlSeconds, autoTopup
|
|
12
|
+
* - Max 100 templates
|
|
13
|
+
*/
|
|
14
|
+
import { QuotaConfig } from './types';
|
|
15
|
+
export interface KeyTemplate {
|
|
16
|
+
/** Unique template name (alphanumeric, hyphens, underscores, 1-50 chars) */
|
|
17
|
+
name: string;
|
|
18
|
+
/** Human-readable description */
|
|
19
|
+
description: string;
|
|
20
|
+
/** Initial credits for keys created from this template */
|
|
21
|
+
credits: number;
|
|
22
|
+
/** Whitelist: only these tools are accessible. Empty = all tools allowed. */
|
|
23
|
+
allowedTools: string[];
|
|
24
|
+
/** Blacklist: these tools are always denied. */
|
|
25
|
+
deniedTools: string[];
|
|
26
|
+
/** Per-key quota overrides. Undefined = use global defaults. */
|
|
27
|
+
quota?: QuotaConfig;
|
|
28
|
+
/** IP allowlist. Empty = all IPs allowed. */
|
|
29
|
+
ipAllowlist: string[];
|
|
30
|
+
/** Max total credits this key can spend. 0 = unlimited. */
|
|
31
|
+
spendingLimit: number;
|
|
32
|
+
/** Arbitrary key-value metadata tags. */
|
|
33
|
+
tags: Record<string, string>;
|
|
34
|
+
/** Namespace for multi-tenant isolation. */
|
|
35
|
+
namespace: string;
|
|
36
|
+
/** TTL in seconds from creation. 0 = never expires. */
|
|
37
|
+
expiryTtlSeconds: number;
|
|
38
|
+
/** Auto-topup configuration. Undefined = disabled. */
|
|
39
|
+
autoTopup?: {
|
|
40
|
+
threshold: number;
|
|
41
|
+
amount: number;
|
|
42
|
+
maxDaily: number;
|
|
43
|
+
};
|
|
44
|
+
/** ISO timestamp when template was created */
|
|
45
|
+
createdAt: string;
|
|
46
|
+
/** ISO timestamp of last update */
|
|
47
|
+
updatedAt: string;
|
|
48
|
+
}
|
|
49
|
+
export declare class KeyTemplateManager {
|
|
50
|
+
private templates;
|
|
51
|
+
private readonly filePath;
|
|
52
|
+
constructor(filePath?: string);
|
|
53
|
+
/**
|
|
54
|
+
* Create or update a template.
|
|
55
|
+
*/
|
|
56
|
+
set(name: string, data: Partial<Omit<KeyTemplate, 'name' | 'createdAt' | 'updatedAt'>>): {
|
|
57
|
+
success: boolean;
|
|
58
|
+
error?: string;
|
|
59
|
+
template?: KeyTemplate;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Get a template by name.
|
|
63
|
+
*/
|
|
64
|
+
get(name: string): KeyTemplate | null;
|
|
65
|
+
/**
|
|
66
|
+
* Delete a template.
|
|
67
|
+
*/
|
|
68
|
+
delete(name: string): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* List all templates.
|
|
71
|
+
*/
|
|
72
|
+
list(): KeyTemplate[];
|
|
73
|
+
/**
|
|
74
|
+
* Get template count.
|
|
75
|
+
*/
|
|
76
|
+
get count(): number;
|
|
77
|
+
private saveToFile;
|
|
78
|
+
private loadFromFile;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=key-templates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-templates.d.ts","sourceRoot":"","sources":["../src/key-templates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAItC,MAAM,WAAW,WAAW;IAC1B,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,0DAA0D;IAC1D,OAAO,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,gDAAgD;IAChD,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,gEAAgE;IAChE,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,6CAA6C;IAC7C,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,2DAA2D;IAC3D,aAAa,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,gBAAgB,EAAE,MAAM,CAAC;IACzB,sDAAsD;IACtD,SAAS,CAAC,EAAE;QACV,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,SAAS,CAAkC;IACnD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;gBAE7B,QAAQ,CAAC,EAAE,MAAM;IAO7B;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,GAAG,WAAW,CAAC,CAAC,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,WAAW,CAAA;KAAE;IAqCrJ;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAIrC;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAM7B;;OAEG;IACH,IAAI,IAAI,WAAW,EAAE;IAIrB;;OAEG;IACH,IAAI,KAAK,IAAI,MAAM,CAElB;IAID,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,YAAY;CAgBrB"}
|