atabey-shared 0.1.1-beta → 0.1.2
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 +79 -41
- package/dist/agent-identity.d.ts +1 -34
- package/dist/agent-identity.js +1 -76
- package/dist/agent-identity.js.map +1 -1
- package/dist/api-catalog.d.ts +1 -57
- package/dist/api-catalog.js +1 -253
- package/dist/api-catalog.js.map +1 -1
- package/dist/audit-chain.d.ts +1 -80
- package/dist/audit-chain.js +1 -261
- package/dist/audit-chain.js.map +1 -1
- package/dist/audit.d.ts +1 -121
- package/dist/audit.js +1 -321
- package/dist/audit.js.map +1 -1
- package/dist/constants.d.ts +1 -150
- package/dist/constants.js +1 -211
- package/dist/constants.js.map +1 -1
- package/dist/database.d.ts +1 -6
- package/dist/database.js +1 -15
- package/dist/database.js.map +1 -1
- package/dist/errors.d.ts +1 -46
- package/dist/errors.js +1 -68
- package/dist/errors.js.map +1 -1
- package/dist/file-lock.d.ts +1 -93
- package/dist/file-lock.js +1 -239
- package/dist/file-lock.js.map +1 -1
- package/dist/fs.d.ts +1 -9
- package/dist/fs.js +1 -53
- package/dist/fs.js.map +1 -1
- package/dist/index.d.ts +2 -31
- package/dist/index.js +2 -31
- package/dist/index.js.map +1 -1
- package/dist/job-queue.d.ts +1 -76
- package/dist/job-queue.js +1 -199
- package/dist/job-queue.js.map +1 -1
- package/dist/lock.d.ts +1 -82
- package/dist/lock.js +1 -158
- package/dist/lock.js.map +1 -1
- package/dist/logger.d.ts +1 -31
- package/dist/logger.js +1 -152
- package/dist/logger.js.map +1 -1
- package/dist/memory-prune.d.ts +1 -18
- package/dist/memory-prune.js +1 -47
- package/dist/memory-prune.js.map +1 -1
- package/dist/migrations.d.ts +1 -69
- package/dist/migrations.js +1 -393
- package/dist/migrations.js.map +1 -1
- package/dist/modules/agent/agent-identity.d.ts +34 -0
- package/dist/modules/agent/agent-identity.js +77 -0
- package/dist/modules/agent/agent-identity.js.map +1 -0
- package/dist/modules/agent/api-catalog.d.ts +57 -0
- package/dist/modules/agent/api-catalog.js +254 -0
- package/dist/modules/agent/api-catalog.js.map +1 -0
- package/dist/modules/agent/index.d.ts +3 -0
- package/dist/modules/agent/index.js +4 -0
- package/dist/modules/agent/index.js.map +1 -0
- package/dist/modules/agent/tokenizer.d.ts +54 -0
- package/dist/modules/agent/tokenizer.js +272 -0
- package/dist/modules/agent/tokenizer.js.map +1 -0
- package/dist/modules/concurrency/file-lock.d.ts +93 -0
- package/dist/modules/concurrency/file-lock.js +240 -0
- package/dist/modules/concurrency/file-lock.js.map +1 -0
- package/dist/modules/concurrency/index.d.ts +6 -0
- package/dist/modules/concurrency/index.js +7 -0
- package/dist/modules/concurrency/index.js.map +1 -0
- package/dist/modules/concurrency/job-queue.d.ts +76 -0
- package/dist/modules/concurrency/job-queue.js +200 -0
- package/dist/modules/concurrency/job-queue.js.map +1 -0
- package/dist/modules/concurrency/lock.d.ts +82 -0
- package/dist/modules/concurrency/lock.js +159 -0
- package/dist/modules/concurrency/lock.js.map +1 -0
- package/dist/modules/concurrency/resilience.d.ts +84 -0
- package/dist/modules/concurrency/resilience.js +217 -0
- package/dist/modules/concurrency/resilience.js.map +1 -0
- package/dist/modules/concurrency/worker-pool.d.ts +52 -0
- package/dist/modules/concurrency/worker-pool.js +229 -0
- package/dist/modules/concurrency/worker-pool.js.map +1 -0
- package/dist/modules/concurrency/worker-thread.d.ts +21 -0
- package/dist/modules/concurrency/worker-thread.js +67 -0
- package/dist/modules/concurrency/worker-thread.js.map +1 -0
- package/dist/modules/index.d.ts +14 -0
- package/dist/modules/index.js +15 -0
- package/dist/modules/index.js.map +1 -0
- package/dist/modules/observability/audit-chain.d.ts +80 -0
- package/dist/modules/observability/audit-chain.js +262 -0
- package/dist/modules/observability/audit-chain.js.map +1 -0
- package/dist/modules/observability/audit.d.ts +121 -0
- package/dist/modules/observability/audit.js +322 -0
- package/dist/modules/observability/audit.js.map +1 -0
- package/dist/modules/observability/index.d.ts +4 -0
- package/dist/modules/observability/index.js +5 -0
- package/dist/modules/observability/index.js.map +1 -0
- package/dist/modules/observability/logger.d.ts +31 -0
- package/dist/modules/observability/logger.js +153 -0
- package/dist/modules/observability/logger.js.map +1 -0
- package/dist/modules/observability/otel.d.ts +39 -0
- package/dist/modules/observability/otel.js +93 -0
- package/dist/modules/observability/otel.js.map +1 -0
- package/dist/modules/primitives/constants.d.ts +150 -0
- package/dist/modules/primitives/constants.js +212 -0
- package/dist/modules/primitives/constants.js.map +1 -0
- package/dist/modules/primitives/errors.d.ts +46 -0
- package/dist/modules/primitives/errors.js +69 -0
- package/dist/modules/primitives/errors.js.map +1 -0
- package/dist/modules/primitives/fs.d.ts +9 -0
- package/dist/modules/primitives/fs.js +54 -0
- package/dist/modules/primitives/fs.js.map +1 -0
- package/dist/modules/primitives/index.d.ts +7 -0
- package/dist/modules/primitives/index.js +8 -0
- package/dist/modules/primitives/index.js.map +1 -0
- package/dist/modules/primitives/outbound-http.d.ts +32 -0
- package/dist/modules/primitives/outbound-http.js +88 -0
- package/dist/modules/primitives/outbound-http.js.map +1 -0
- package/dist/modules/primitives/string.d.ts +1 -0
- package/dist/modules/primitives/string.js +30 -0
- package/dist/modules/primitives/string.js.map +1 -0
- package/dist/modules/primitives/time.d.ts +5 -0
- package/dist/modules/primitives/time.js +35 -0
- package/dist/modules/primitives/time.js.map +1 -0
- package/dist/modules/primitives/types.d.ts +27 -0
- package/dist/modules/primitives/types.js +17 -0
- package/dist/modules/primitives/types.js.map +1 -0
- package/dist/modules/sandbox/index.d.ts +3 -0
- package/dist/modules/sandbox/index.js +4 -0
- package/dist/modules/sandbox/index.js.map +1 -0
- package/dist/modules/sandbox/sandbox-fs.d.ts +28 -0
- package/dist/modules/sandbox/sandbox-fs.js +143 -0
- package/dist/modules/sandbox/sandbox-fs.js.map +1 -0
- package/dist/modules/sandbox/sandbox-runtime.d.ts +78 -0
- package/dist/modules/sandbox/sandbox-runtime.js +282 -0
- package/dist/modules/sandbox/sandbox-runtime.js.map +1 -0
- package/dist/modules/sandbox/sandbox.d.ts +54 -0
- package/dist/modules/sandbox/sandbox.js +179 -0
- package/dist/modules/sandbox/sandbox.js.map +1 -0
- package/dist/modules/security/index.d.ts +5 -0
- package/dist/modules/security/index.js +6 -0
- package/dist/modules/security/index.js.map +1 -0
- package/dist/modules/security/pii.d.ts +70 -0
- package/dist/modules/security/pii.js +276 -0
- package/dist/modules/security/pii.js.map +1 -0
- package/dist/modules/security/policy-gate.d.ts +42 -0
- package/dist/modules/security/policy-gate.js +172 -0
- package/dist/modules/security/policy-gate.js.map +1 -0
- package/dist/modules/security/retention.d.ts +68 -0
- package/dist/modules/security/retention.js +218 -0
- package/dist/modules/security/retention.js.map +1 -0
- package/dist/modules/security/secrets.d.ts +99 -0
- package/dist/modules/security/secrets.js +371 -0
- package/dist/modules/security/secrets.js.map +1 -0
- package/dist/modules/security/tls.d.ts +87 -0
- package/dist/modules/security/tls.js +154 -0
- package/dist/modules/security/tls.js.map +1 -0
- package/dist/modules/storage/database.d.ts +6 -0
- package/dist/modules/storage/database.js +16 -0
- package/dist/modules/storage/database.js.map +1 -0
- package/dist/modules/storage/index.d.ts +4 -0
- package/dist/modules/storage/index.js +5 -0
- package/dist/modules/storage/index.js.map +1 -0
- package/dist/modules/storage/memory-prune.d.ts +18 -0
- package/dist/modules/storage/memory-prune.js +48 -0
- package/dist/modules/storage/memory-prune.js.map +1 -0
- package/dist/modules/storage/migrations.d.ts +69 -0
- package/dist/modules/storage/migrations.js +394 -0
- package/dist/modules/storage/migrations.js.map +1 -0
- package/dist/modules/storage/storage.d.ts +341 -0
- package/dist/modules/storage/storage.js +1004 -0
- package/dist/modules/storage/storage.js.map +1 -0
- package/dist/otel.d.ts +1 -39
- package/dist/otel.js +1 -92
- package/dist/otel.js.map +1 -1
- package/dist/outbound-http.d.ts +1 -32
- package/dist/outbound-http.js +1 -87
- package/dist/outbound-http.js.map +1 -1
- package/dist/pii.d.ts +1 -70
- package/dist/pii.js +1 -275
- package/dist/pii.js.map +1 -1
- package/dist/policy-gate.d.ts +1 -42
- package/dist/policy-gate.js +1 -171
- package/dist/policy-gate.js.map +1 -1
- package/dist/resilience.d.ts +1 -84
- package/dist/resilience.js +1 -216
- package/dist/resilience.js.map +1 -1
- package/dist/retention.d.ts +1 -68
- package/dist/retention.js +1 -217
- package/dist/retention.js.map +1 -1
- package/dist/sandbox-fs.d.ts +1 -28
- package/dist/sandbox-fs.js +1 -142
- package/dist/sandbox-fs.js.map +1 -1
- package/dist/sandbox-runtime.d.ts +1 -78
- package/dist/sandbox-runtime.js +1 -281
- package/dist/sandbox-runtime.js.map +1 -1
- package/dist/sandbox.d.ts +1 -54
- package/dist/sandbox.js +1 -178
- package/dist/sandbox.js.map +1 -1
- package/dist/secrets.d.ts +1 -99
- package/dist/secrets.js +1 -370
- package/dist/secrets.js.map +1 -1
- package/dist/storage.d.ts +1 -341
- package/dist/storage.js +1 -1003
- package/dist/storage.js.map +1 -1
- package/dist/string.d.ts +1 -1
- package/dist/string.js +1 -29
- package/dist/string.js.map +1 -1
- package/dist/time.d.ts +1 -5
- package/dist/time.js +1 -34
- package/dist/time.js.map +1 -1
- package/dist/tls.d.ts +1 -87
- package/dist/tls.js +1 -153
- package/dist/tls.js.map +1 -1
- package/dist/tokenizer.d.ts +1 -54
- package/dist/tokenizer.js +1 -271
- package/dist/tokenizer.js.map +1 -1
- package/dist/types.d.ts +1 -27
- package/dist/types.js +1 -16
- package/dist/types.js.map +1 -1
- package/dist/worker-pool.d.ts +1 -52
- package/dist/worker-pool.js +1 -228
- package/dist/worker-pool.js.map +1 -1
- package/dist/worker-thread.d.ts +1 -21
- package/dist/worker-thread.js +1 -66
- package/dist/worker-thread.js.map +1 -1
- package/package.json +45 -34
package/README.md
CHANGED
|
@@ -1,32 +1,30 @@
|
|
|
1
|
-
# [GOV] Atabey Shared — Core Utility Library for AI Governance Platform
|
|
1
|
+
# [GOV] Atabey Shared — Core Utility Library for the AI Governance Platform
|
|
2
2
|
|
|
3
|
-
[](https://github.com/ysf-bkr/atabey)
|
|
4
4
|
[](https://www.npmjs.com/package/atabey-shared)
|
|
5
5
|
[](https://www.gnu.org/licenses/agpl-3.0)
|
|
6
6
|
|
|
7
|
-
**Atabey Shared** is the foundational utility package of the Atabey framework
|
|
7
|
+
**Atabey Shared** is the foundational utility package of the Atabey framework: shared constants and branded types, security filters (PII, secrets, TLS, policy gate), the SQLite holder and migrations, structured logging, audit chain, concurrency primitives (locks, job queue, worker pool) and the sandbox runtime — used by both `atabey` (core CLI/orchestrator) and `atabey-mcp` (MCP server).
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
## 📋 Package Overview
|
|
12
12
|
|
|
13
|
-
| Module | Files |
|
|
14
|
-
|
|
15
|
-
| **
|
|
16
|
-
| **
|
|
17
|
-
| **
|
|
18
|
-
| **
|
|
19
|
-
| **
|
|
20
|
-
| **
|
|
21
|
-
| **
|
|
22
|
-
| **File System** | `fs.ts` | Safe file write wrapper with automatic parent directory creation and encoding validation |
|
|
23
|
-
| **Database Holder** | `database.ts` | Singleton SQLite database holder for shared workspace storage |
|
|
13
|
+
| Module group | Files | Responsibility |
|
|
14
|
+
|--------------|-------|----------------|
|
|
15
|
+
| **primitives** | `constants`, `types`, `errors`, `fs`, `string`, `time`, `outbound-http` | Framework constants, branded types, error classes, safe fs, TLS-aware outbound HTTP |
|
|
16
|
+
| **storage** | `database`, `storage`, `migrations`, `memory-prune` | SQLite holder (singleton), schema migrations, memory pruning |
|
|
17
|
+
| **security** | `pii`, `secrets`, `tls`, `policy-gate`, `retention` | PII masking, AES-256-GCM vault, TLS/mTLS, fail-closed PolicyGate, retention |
|
|
18
|
+
| **concurrency** | `lock`, `file-lock`, `job-queue`, `worker-pool`, `worker-thread`, `resilience` | Distributed/file locks, DB-backed job queue, worker pool, circuit breaker |
|
|
19
|
+
| **sandbox** | `sandbox`, `sandbox-runtime`, `sandbox-fs` | OS sandbox (seatbelt/uid), fail-closed sandboxed file writes |
|
|
20
|
+
| **observability** | `logger`, `otel`, `audit`, `audit-chain` | Structured logging, OTel spans, HMAC-signed audit chain |
|
|
21
|
+
| **agent** | `agent-identity`, `api-catalog`, `tokenizer` | Signed agent identity, API endpoint catalog, `cl100k_base` tokenizer |
|
|
24
22
|
|
|
25
23
|
---
|
|
26
24
|
|
|
27
25
|
## 🚀 Installation
|
|
28
26
|
|
|
29
|
-
|
|
27
|
+
Designed as an **internal shared module** for the Atabey monorepo workspace, but installable independently:
|
|
30
28
|
|
|
31
29
|
```bash
|
|
32
30
|
npm install atabey-shared
|
|
@@ -34,52 +32,83 @@ npm install atabey-shared
|
|
|
34
32
|
|
|
35
33
|
---
|
|
36
34
|
|
|
35
|
+
## 🧩 Module Structure
|
|
36
|
+
|
|
37
|
+
The package is organized into focused **module groups**. `src/index.ts` is a barrel
|
|
38
|
+
that re-exports everything flat **plus** a `Modules.<Group>` namespace per group; the
|
|
39
|
+
flat `atabey-shared/*.js` entry points are kept as thin re-export shims for backward
|
|
40
|
+
compatibility.
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
packages/shared/
|
|
44
|
+
├── src/
|
|
45
|
+
│ ├── index.ts # Barrel: flat exports + `Modules.<Group>`
|
|
46
|
+
│ └── modules/
|
|
47
|
+
│ ├── primitives/ # constants, types, errors, fs, string, time, outbound-http
|
|
48
|
+
│ ├── storage/ # database, storage, migrations, memory-prune
|
|
49
|
+
│ ├── security/ # pii, secrets, tls, policy-gate, retention
|
|
50
|
+
│ ├── concurrency/ # lock, file-lock, job-queue, worker-pool, worker-thread, resilience
|
|
51
|
+
│ ├── sandbox/ # sandbox, sandbox-runtime, sandbox-fs
|
|
52
|
+
│ ├── observability/ # logger, otel, audit, audit-chain
|
|
53
|
+
│ └── agent/ # agent-identity, api-catalog, tokenizer
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Three import styles are supported:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
// 1. Flat — stable public API
|
|
60
|
+
import { maskText, logger } from "atabey-shared";
|
|
61
|
+
import { maskText } from "atabey-shared/pii.js";
|
|
62
|
+
|
|
63
|
+
// 2. Namespaced by module group
|
|
64
|
+
import { Modules } from "atabey-shared";
|
|
65
|
+
Modules.Security.maskText("user@example.com");
|
|
66
|
+
|
|
67
|
+
// 3. Deep module subpath
|
|
68
|
+
import { maskText } from "atabey-shared/security/pii.js";
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
37
73
|
## ⚙️ Core Modules Detail
|
|
38
74
|
|
|
39
75
|
### 1. PII Protection (KVKK/GDPR Compliance)
|
|
40
|
-
The `pii.ts` module scans and redacts sensitive data before it is logged to disk or sent to external LLM providers
|
|
76
|
+
The `pii.ts` module scans and redacts sensitive data before it is logged to disk or sent to external LLM providers.
|
|
41
77
|
```typescript
|
|
42
78
|
import { maskText } from "atabey-shared";
|
|
43
79
|
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
console.log(sanitizedText);
|
|
47
|
-
// Output: "My phone is ***-***-**** and email is ***@***"
|
|
80
|
+
const sanitized = maskText("My phone is +90 555 123 45 67 and email is admin@company.com");
|
|
81
|
+
// "My phone is ***-***-**** and email is ***@***"
|
|
48
82
|
```
|
|
49
83
|
|
|
50
84
|
### 2. Distributed Resource Locking
|
|
51
|
-
|
|
85
|
+
`lock.ts` provides a SQLite-backed `DistributedLock` (server-authoritative, with stale-lock reclaim) that prevents race conditions between parallel agents writing to shared resources. For a lightweight file-based lock, use `AtomicFileLock` from `file-lock.ts`.
|
|
52
86
|
```typescript
|
|
53
|
-
import {
|
|
87
|
+
import { DistributedLock } from "atabey-shared";
|
|
54
88
|
|
|
55
|
-
|
|
89
|
+
DistributedLock.initialize(); // once at startup
|
|
56
90
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
//
|
|
91
|
+
const owner = DistributedLock.getLocalOwnerId();
|
|
92
|
+
if (DistributedLock.acquire("PROJECT_MEMORY.md", owner, { ttlMs: 10000, reason: "memory sync" })) {
|
|
93
|
+
try {
|
|
94
|
+
// safe region: write the shared resource
|
|
95
|
+
} finally {
|
|
96
|
+
DistributedLock.release("PROJECT_MEMORY.md", owner);
|
|
61
97
|
}
|
|
62
|
-
} finally {
|
|
63
|
-
await lock.release();
|
|
64
98
|
}
|
|
65
99
|
```
|
|
66
100
|
|
|
67
|
-
### 3.
|
|
68
|
-
Structured logger wrapping `process.stdout
|
|
101
|
+
### 3. Structured Logger
|
|
102
|
+
Structured logger wrapping `process.stdout`/`process.stderr`, with file logging and JSON output.
|
|
69
103
|
```typescript
|
|
70
104
|
import { logger, LogLevel } from "atabey-shared";
|
|
71
105
|
|
|
72
|
-
logger.configure({
|
|
73
|
-
minLevel: LogLevel.DEBUG,
|
|
74
|
-
jsonFormat: true,
|
|
75
|
-
logFile: "./.atabey/logs/system.log"
|
|
76
|
-
});
|
|
77
|
-
|
|
106
|
+
logger.configure({ minLevel: LogLevel.DEBUG, jsonFormat: true, logFile: "./.atabey/logs/system.log" });
|
|
78
107
|
logger.info("Database migration completed", { durationMs: 142 });
|
|
79
108
|
```
|
|
80
109
|
|
|
81
110
|
### 4. Branded Types
|
|
82
|
-
|
|
111
|
+
Compile-time validation for workspace ID primitives to prevent mixing agent names, message IDs and task IDs.
|
|
83
112
|
```typescript
|
|
84
113
|
import { AgentID, TaskID, asAgentID, asTaskID } from "atabey-shared";
|
|
85
114
|
|
|
@@ -91,10 +120,19 @@ const task: TaskID = asTaskID("TASK-102");
|
|
|
91
120
|
|
|
92
121
|
## 📦 Dependencies
|
|
93
122
|
|
|
94
|
-
- **
|
|
95
|
-
- **
|
|
123
|
+
- **js-tiktoken**: `cl100k_base` BPE tokenizer for token accounting
|
|
124
|
+
- **better-sqlite3**, **chalk**, **zod** _(peer)_: storage, terminal styling and runtime validation
|
|
125
|
+
|
|
126
|
+
## 🔗 Related Packages
|
|
127
|
+
|
|
128
|
+
| Package | Role | Links |
|
|
129
|
+
|---------|------|-------|
|
|
130
|
+
| **atabey** | Core engine — CLI, agents, engines, orchestrator | [npm](https://www.npmjs.com/package/atabey) · [source](https://github.com/ysf-bkr/atabey/tree/main/packages/atabey) |
|
|
131
|
+
| **atabey-mcp** | MCP server — 40 tools & governance pipeline | [npm](https://www.npmjs.com/package/atabey-mcp) · [source](https://github.com/ysf-bkr/atabey/tree/main/packages/atabey-mcp) |
|
|
132
|
+
| **atabey-shared** | Shared utilities — constants, storage, PII, audit, locks | [npm](https://www.npmjs.com/package/atabey-shared) · [source](https://github.com/ysf-bkr/atabey/tree/main/packages/shared) |
|
|
133
|
+
|
|
134
|
+
> Full bilingual documentation (TR + EN): **[github.com/ysf-bkr/atabey](https://github.com/ysf-bkr/atabey#readme)**
|
|
96
135
|
|
|
97
|
-
---
|
|
98
136
|
|
|
99
137
|
## License
|
|
100
138
|
|
package/dist/agent-identity.d.ts
CHANGED
|
@@ -1,34 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Agent Identity — cryptographically signed agent tokens.
|
|
3
|
-
*
|
|
4
|
-
* Problem: `ATABEY_ACTIVE_AGENT` is a plain env var, so any tool/subprocess can
|
|
5
|
-
* impersonate `@manager` or `@security`. When `ATABEY_AGENT_SECRET` is set,
|
|
6
|
-
* Atabey accepts an HMAC-signed `ATABEY_AGENT_TOKEN` and verifies it
|
|
7
|
-
* (fail-closed on tampering/expiry). Set `ATABEY_AGENT_IDENTITY_REQUIRED=true`
|
|
8
|
-
* to refuse plain-env identity entirely.
|
|
9
|
-
*
|
|
10
|
-
* Token format: `${agent}.${issuedAt}.${expiresAt}.${hmacSha256Base64url}`
|
|
11
|
-
*/
|
|
12
|
-
export interface AgentIdentity {
|
|
13
|
-
agent: string;
|
|
14
|
-
issuedAt: number;
|
|
15
|
-
expiresAt: number;
|
|
16
|
-
}
|
|
17
|
-
export interface AgentTokenResult {
|
|
18
|
-
valid: boolean;
|
|
19
|
-
agent?: string;
|
|
20
|
-
reason?: string;
|
|
21
|
-
}
|
|
22
|
-
/** True when agent-token verification is mandatory (plain env rejected). */
|
|
23
|
-
export declare function isAgentIdentityEnforced(): boolean;
|
|
24
|
-
/** Sign an agent identity into a compact token. */
|
|
25
|
-
export declare function signAgentToken(agent: string, options?: {
|
|
26
|
-
ttlMs?: number;
|
|
27
|
-
key?: string | Buffer;
|
|
28
|
-
}): string;
|
|
29
|
-
/** Verify an agent token (signature + expiry). */
|
|
30
|
-
export declare function verifyAgentToken(token: string, options?: {
|
|
31
|
-
key?: string | Buffer;
|
|
32
|
-
}): AgentTokenResult;
|
|
33
|
-
/** Decode a token's identity without verification (for diagnostics only). */
|
|
34
|
-
export declare function decodeAgentToken(token: string): AgentIdentity | null;
|
|
1
|
+
export * from "./modules/agent/agent-identity.js";
|
package/dist/agent-identity.js
CHANGED
|
@@ -1,77 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
* Agent Identity — cryptographically signed agent tokens.
|
|
3
|
-
*
|
|
4
|
-
* Problem: `ATABEY_ACTIVE_AGENT` is a plain env var, so any tool/subprocess can
|
|
5
|
-
* impersonate `@manager` or `@security`. When `ATABEY_AGENT_SECRET` is set,
|
|
6
|
-
* Atabey accepts an HMAC-signed `ATABEY_AGENT_TOKEN` and verifies it
|
|
7
|
-
* (fail-closed on tampering/expiry). Set `ATABEY_AGENT_IDENTITY_REQUIRED=true`
|
|
8
|
-
* to refuse plain-env identity entirely.
|
|
9
|
-
*
|
|
10
|
-
* Token format: `${agent}.${issuedAt}.${expiresAt}.${hmacSha256Base64url}`
|
|
11
|
-
*/
|
|
12
|
-
import crypto from "crypto";
|
|
13
|
-
import { resolveAuditChainKey } from "./audit-chain.js";
|
|
14
|
-
function resolveKey(explicit) {
|
|
15
|
-
if (explicit) {
|
|
16
|
-
return Buffer.isBuffer(explicit) ? explicit : crypto.createHash("sha256").update(explicit, "utf8").digest();
|
|
17
|
-
}
|
|
18
|
-
const envSecret = process.env.ATABEY_AGENT_SECRET;
|
|
19
|
-
if (envSecret && envSecret.trim()) {
|
|
20
|
-
return crypto.createHash("sha256").update(envSecret.trim(), "utf8").digest();
|
|
21
|
-
}
|
|
22
|
-
return resolveAuditChainKey();
|
|
23
|
-
}
|
|
24
|
-
function timingSafeEqual(a, b) {
|
|
25
|
-
const ba = Buffer.from(a);
|
|
26
|
-
const bb = Buffer.from(b);
|
|
27
|
-
if (ba.length !== bb.length)
|
|
28
|
-
return false;
|
|
29
|
-
return crypto.timingSafeEqual(ba, bb);
|
|
30
|
-
}
|
|
31
|
-
/** True when agent-token verification is mandatory (plain env rejected). */
|
|
32
|
-
export function isAgentIdentityEnforced() {
|
|
33
|
-
return process.env.ATABEY_AGENT_IDENTITY_REQUIRED === "true";
|
|
34
|
-
}
|
|
35
|
-
/** Sign an agent identity into a compact token. */
|
|
36
|
-
export function signAgentToken(agent, options = {}) {
|
|
37
|
-
const key = resolveKey(options.key);
|
|
38
|
-
if (!key) {
|
|
39
|
-
throw new Error("[AGENT_IDENTITY] No signing key. Set ATABEY_AGENT_SECRET.");
|
|
40
|
-
}
|
|
41
|
-
const name = agent.replace(/^@/, "");
|
|
42
|
-
const issuedAt = Date.now();
|
|
43
|
-
const expiresAt = issuedAt + (options.ttlMs ?? 60 * 60 * 1000);
|
|
44
|
-
const payload = `${name}.${issuedAt}.${expiresAt}`;
|
|
45
|
-
const sig = crypto.createHmac("sha256", key).update(payload).digest("base64url");
|
|
46
|
-
return `${payload}.${sig}`;
|
|
47
|
-
}
|
|
48
|
-
/** Verify an agent token (signature + expiry). */
|
|
49
|
-
export function verifyAgentToken(token, options = {}) {
|
|
50
|
-
const key = resolveKey(options.key);
|
|
51
|
-
if (!key)
|
|
52
|
-
return { valid: false, reason: "No signing key configured." };
|
|
53
|
-
if (!token || typeof token !== "string")
|
|
54
|
-
return { valid: false, reason: "Empty token." };
|
|
55
|
-
const parts = token.split(".");
|
|
56
|
-
if (parts.length !== 4)
|
|
57
|
-
return { valid: false, reason: "Malformed token." };
|
|
58
|
-
const [name, issuedAt, expiresAt, sig] = parts;
|
|
59
|
-
const payload = `${name}.${issuedAt}.${expiresAt}`;
|
|
60
|
-
const expected = crypto.createHmac("sha256", key).update(payload).digest("base64url");
|
|
61
|
-
if (!timingSafeEqual(sig, expected))
|
|
62
|
-
return { valid: false, reason: "Signature mismatch." };
|
|
63
|
-
const exp = Number(expiresAt);
|
|
64
|
-
if (!Number.isFinite(exp))
|
|
65
|
-
return { valid: false, reason: "Invalid expiry." };
|
|
66
|
-
if (Date.now() > exp)
|
|
67
|
-
return { valid: false, reason: "Token expired." };
|
|
68
|
-
return { valid: true, agent: `@${name}` };
|
|
69
|
-
}
|
|
70
|
-
/** Decode a token's identity without verification (for diagnostics only). */
|
|
71
|
-
export function decodeAgentToken(token) {
|
|
72
|
-
const parts = token.split(".");
|
|
73
|
-
if (parts.length !== 4)
|
|
74
|
-
return null;
|
|
75
|
-
return { agent: `@${parts[0]}`, issuedAt: Number(parts[1]), expiresAt: Number(parts[2]) };
|
|
76
|
-
}
|
|
1
|
+
export * from "./modules/agent/agent-identity.js";
|
|
77
2
|
//# sourceMappingURL=agent-identity.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-identity.js","sourceRoot":"","sources":["../src/agent-identity.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"agent-identity.js","sourceRoot":"","sources":["../src/agent-identity.ts"],"names":[],"mappings":"AAAA,cAAc,mCAAmC,CAAC"}
|
package/dist/api-catalog.d.ts
CHANGED
|
@@ -1,57 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* API Catalog — endpoint registry, route/OpenAPI scanner, and drift detection.
|
|
3
|
-
*
|
|
4
|
-
* Purpose: let frontend/mobile agents integrate against the backend API using
|
|
5
|
-
* a compact JSON catalog instead of reading large route source files (token
|
|
6
|
-
* savings + zero context pollution).
|
|
7
|
-
*
|
|
8
|
-
* The scanner is HEURISTIC (regex/AST-lite) and covers:
|
|
9
|
-
* - Express / Fastify: app|router|server|fastify.get('/path', ...)
|
|
10
|
-
* - Fastify route(): fastify.route({ method, url, ... })
|
|
11
|
-
* - NestJS decorators: @Get('path') / @Post('path')
|
|
12
|
-
* - OpenAPI v3 / Swagger v2 JSON specs
|
|
13
|
-
*/
|
|
14
|
-
export interface ApiEndpoint {
|
|
15
|
-
method: string;
|
|
16
|
-
path: string;
|
|
17
|
-
tag?: string;
|
|
18
|
-
summary?: string;
|
|
19
|
-
authRequired: boolean;
|
|
20
|
-
requestSchema?: string;
|
|
21
|
-
responseSchema?: string;
|
|
22
|
-
source?: string;
|
|
23
|
-
updatedAt: string;
|
|
24
|
-
}
|
|
25
|
-
export interface ApiCatalog {
|
|
26
|
-
version: 1;
|
|
27
|
-
generatedAt: string;
|
|
28
|
-
endpoints: ApiEndpoint[];
|
|
29
|
-
}
|
|
30
|
-
export interface ApiDrift {
|
|
31
|
-
added: ApiEndpoint[];
|
|
32
|
-
removed: ApiEndpoint[];
|
|
33
|
-
changed: Array<{
|
|
34
|
-
previous: ApiEndpoint;
|
|
35
|
-
current: ApiEndpoint;
|
|
36
|
-
}>;
|
|
37
|
-
}
|
|
38
|
-
export declare function endpointKey(e: {
|
|
39
|
-
method: string;
|
|
40
|
-
path: string;
|
|
41
|
-
}): string;
|
|
42
|
-
export declare function normalizePath(p: string): string;
|
|
43
|
-
/** Parse an OpenAPI v3 or Swagger v2 spec object into endpoints. */
|
|
44
|
-
export declare function parseOpenApiSpec(spec: unknown): ApiEndpoint[];
|
|
45
|
-
/**
|
|
46
|
-
* Walk a project tree and collect endpoints from route source files and any
|
|
47
|
-
* OpenAPI/Swagger JSON specs.
|
|
48
|
-
*/
|
|
49
|
-
export declare function scanProjectForEndpoints(rootDir: string, options?: {
|
|
50
|
-
maxFiles?: number;
|
|
51
|
-
}): ApiEndpoint[];
|
|
52
|
-
export declare function dedupe(endpoints: ApiEndpoint[]): ApiEndpoint[];
|
|
53
|
-
/**
|
|
54
|
-
* Diff a previous catalog against a freshly scanned one.
|
|
55
|
-
*/
|
|
56
|
-
export declare function detectApiDrift(previous: ApiEndpoint[], current: ApiEndpoint[]): ApiDrift;
|
|
57
|
-
export declare function isApiDriftClean(drift: ApiDrift): boolean;
|
|
1
|
+
export * from "./modules/agent/api-catalog.js";
|
package/dist/api-catalog.js
CHANGED
|
@@ -1,254 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
* API Catalog — endpoint registry, route/OpenAPI scanner, and drift detection.
|
|
3
|
-
*
|
|
4
|
-
* Purpose: let frontend/mobile agents integrate against the backend API using
|
|
5
|
-
* a compact JSON catalog instead of reading large route source files (token
|
|
6
|
-
* savings + zero context pollution).
|
|
7
|
-
*
|
|
8
|
-
* The scanner is HEURISTIC (regex/AST-lite) and covers:
|
|
9
|
-
* - Express / Fastify: app|router|server|fastify.get('/path', ...)
|
|
10
|
-
* - Fastify route(): fastify.route({ method, url, ... })
|
|
11
|
-
* - NestJS decorators: @Get('path') / @Post('path')
|
|
12
|
-
* - OpenAPI v3 / Swagger v2 JSON specs
|
|
13
|
-
*/
|
|
14
|
-
import fs from "fs";
|
|
15
|
-
import path from "path";
|
|
16
|
-
const HTTP_METHODS = ["get", "post", "put", "patch", "delete", "options", "head"];
|
|
17
|
-
const ROUTE_EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
18
|
-
const SKIP_DIRS = new Set(["node_modules", "dist", "build", ".git", "coverage", ".atabey", ".next"]);
|
|
19
|
-
export function endpointKey(e) {
|
|
20
|
-
return `${e.method.toUpperCase()} ${normalizePath(e.path)}`;
|
|
21
|
-
}
|
|
22
|
-
export function normalizePath(p) {
|
|
23
|
-
if (!p)
|
|
24
|
-
return "/";
|
|
25
|
-
let out = p.trim();
|
|
26
|
-
if (!out.startsWith("/"))
|
|
27
|
-
out = `/${out}`;
|
|
28
|
-
// Collapse :param and {param} to a stable placeholder for drift comparison.
|
|
29
|
-
out = out.replace(/\{[^}]+\}/g, ":param").replace(/:[A-Za-z0-9_]+/g, ":param");
|
|
30
|
-
out = out.replace(/\/+$/, "");
|
|
31
|
-
return out || "/";
|
|
32
|
-
}
|
|
33
|
-
function defaultTag(p) {
|
|
34
|
-
const seg = p.split("/").filter(Boolean);
|
|
35
|
-
return seg[0] || "root";
|
|
36
|
-
}
|
|
37
|
-
/** Extract a route statement plus a few following lines for schema hints. */
|
|
38
|
-
function scanRouteSource(filePath, content) {
|
|
39
|
-
const now = new Date().toISOString();
|
|
40
|
-
const lines = content.split("\n");
|
|
41
|
-
const found = new Map();
|
|
42
|
-
const add = (method, rawPath, schemaHint, authHint) => {
|
|
43
|
-
if (!rawPath || rawPath === "*")
|
|
44
|
-
return;
|
|
45
|
-
const m = method.toUpperCase();
|
|
46
|
-
const p = rawPath;
|
|
47
|
-
const key = endpointKey({ method: m, path: p });
|
|
48
|
-
if (found.has(key))
|
|
49
|
-
return;
|
|
50
|
-
const schemaMatch = /(?:schema|body|response)\s*:\s*([A-Za-z0-9_.]+)/.exec(schemaHint);
|
|
51
|
-
found.set(key, {
|
|
52
|
-
method: m,
|
|
53
|
-
path: p.startsWith("/") ? p : `/${p}`,
|
|
54
|
-
tag: defaultTag(p),
|
|
55
|
-
authRequired: authHint,
|
|
56
|
-
requestSchema: schemaMatch?.[1],
|
|
57
|
-
source: filePath,
|
|
58
|
-
updatedAt: now,
|
|
59
|
-
});
|
|
60
|
-
};
|
|
61
|
-
const isRouteLine = (l) => /\.(get|post|put|patch|delete|options|head)\s*\(/.test(l) ||
|
|
62
|
-
/@(Get|Post|Put|Patch|Delete|Options|Head)\s*\(/.test(l) ||
|
|
63
|
-
/\broute\s*\(/.test(l);
|
|
64
|
-
for (let i = 0; i < lines.length; i++) {
|
|
65
|
-
const line = lines[i];
|
|
66
|
-
// Statement-bounded window: stop at the next route line or statement end
|
|
67
|
-
// so schema/auth hints cannot bleed into the following route.
|
|
68
|
-
let window = line;
|
|
69
|
-
for (let j = i + 1; j < Math.min(i + 12, lines.length); j++) {
|
|
70
|
-
if (isRouteLine(lines[j]))
|
|
71
|
-
break;
|
|
72
|
-
window += `\n${lines[j]}`;
|
|
73
|
-
if (/;\s*$/.test(lines[j]))
|
|
74
|
-
break;
|
|
75
|
-
}
|
|
76
|
-
const authHint = /\b(authenticate|authGuard|verifyToken|preHandler\s*:\s*\[?\s*auth|requireAuth|jwt)\b/i.test(window);
|
|
77
|
-
// Express / Fastify shorthand: app.get('/x', ...) / router.post("/x", ...)
|
|
78
|
-
const short = /\.(get|post|put|patch|delete|options|head)\s*\(\s*[`'"]([^`'"]+)[`'"]/gi;
|
|
79
|
-
let m;
|
|
80
|
-
while ((m = short.exec(line)) !== null) {
|
|
81
|
-
add(m[1], m[2], window, authHint);
|
|
82
|
-
}
|
|
83
|
-
// Fastify route({ method: 'GET', url: '/x' }) — method/url may be in either order.
|
|
84
|
-
if (/\broute\s*\(/.test(line) || /\burl\s*:/.test(line)) {
|
|
85
|
-
const methodM = /method\s*:\s*[`'"](\w+)[`'"]/i.exec(window);
|
|
86
|
-
const urlM = /url\s*:\s*[`'"]([^`'"]+)[`'"]/i.exec(window);
|
|
87
|
-
if (methodM && urlM)
|
|
88
|
-
add(methodM[1], urlM[1], window, authHint);
|
|
89
|
-
}
|
|
90
|
-
// NestJS decorators: @Get('path') @Post()
|
|
91
|
-
const dec = /@(Get|Post|Put|Patch|Delete|Options|Head)\s*\(\s*[`'"]?([^`'")]*)[`'"]?\s*\)/g;
|
|
92
|
-
while ((m = dec.exec(line)) !== null) {
|
|
93
|
-
add(m[1], m[2] || "/", window, authHint);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return [...found.values()];
|
|
97
|
-
}
|
|
98
|
-
/** Parse an OpenAPI v3 or Swagger v2 spec object into endpoints. */
|
|
99
|
-
export function parseOpenApiSpec(spec) {
|
|
100
|
-
const now = new Date().toISOString();
|
|
101
|
-
const doc = spec;
|
|
102
|
-
const paths = doc?.["paths"];
|
|
103
|
-
if (!paths || typeof paths !== "object")
|
|
104
|
-
return [];
|
|
105
|
-
const out = [];
|
|
106
|
-
for (const [rawPath, item] of Object.entries(paths)) {
|
|
107
|
-
if (!item || typeof item !== "object")
|
|
108
|
-
continue;
|
|
109
|
-
for (const method of HTTP_METHODS) {
|
|
110
|
-
const op = item[method];
|
|
111
|
-
if (!op)
|
|
112
|
-
continue;
|
|
113
|
-
const tags = Array.isArray(op["tags"]) ? op["tags"] : [];
|
|
114
|
-
const security = op["security"];
|
|
115
|
-
const requestSchema = refName(op["requestBody"]?.["content"]?.["application/json"]) ??
|
|
116
|
-
refName(op["parameters"]);
|
|
117
|
-
const responses = op["responses"];
|
|
118
|
-
const okResp = responses?.["200"] ?? responses?.["201"] ?? Object.values(responses || {})[0];
|
|
119
|
-
const responseSchema = refName((okResp?.["content"]?.["application/json"]) ?? okResp?.["schema"]);
|
|
120
|
-
out.push({
|
|
121
|
-
method: method.toUpperCase(),
|
|
122
|
-
path: rawPath,
|
|
123
|
-
tag: tags[0] || defaultTag(rawPath),
|
|
124
|
-
summary: typeof op["summary"] === "string" ? op["summary"] : undefined,
|
|
125
|
-
authRequired: Array.isArray(security) ? security.length > 0 : false,
|
|
126
|
-
requestSchema,
|
|
127
|
-
responseSchema,
|
|
128
|
-
source: "openapi",
|
|
129
|
-
updatedAt: now,
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
return out;
|
|
134
|
-
}
|
|
135
|
-
function refName(node) {
|
|
136
|
-
if (!node || typeof node !== "object")
|
|
137
|
-
return undefined;
|
|
138
|
-
const obj = node;
|
|
139
|
-
if (typeof obj["$ref"] === "string")
|
|
140
|
-
return obj["$ref"];
|
|
141
|
-
if (typeof obj["title"] === "string")
|
|
142
|
-
return obj["title"];
|
|
143
|
-
const schema = obj["schema"];
|
|
144
|
-
if (schema && typeof schema === "object") {
|
|
145
|
-
const s = schema;
|
|
146
|
-
if (typeof s["$ref"] === "string")
|
|
147
|
-
return s["$ref"];
|
|
148
|
-
if (typeof s["title"] === "string")
|
|
149
|
-
return s["title"];
|
|
150
|
-
}
|
|
151
|
-
return undefined;
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Walk a project tree and collect endpoints from route source files and any
|
|
155
|
-
* OpenAPI/Swagger JSON specs.
|
|
156
|
-
*/
|
|
157
|
-
export function scanProjectForEndpoints(rootDir, options = {}) {
|
|
158
|
-
const maxFiles = options.maxFiles ?? 5000;
|
|
159
|
-
const results = [];
|
|
160
|
-
let visited = 0;
|
|
161
|
-
const walk = (dir) => {
|
|
162
|
-
if (visited >= maxFiles)
|
|
163
|
-
return;
|
|
164
|
-
let entries;
|
|
165
|
-
try {
|
|
166
|
-
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
167
|
-
}
|
|
168
|
-
catch {
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
for (const entry of entries) {
|
|
172
|
-
if (visited >= maxFiles)
|
|
173
|
-
return;
|
|
174
|
-
const full = path.join(dir, entry.name);
|
|
175
|
-
if (entry.isDirectory()) {
|
|
176
|
-
if (SKIP_DIRS.has(entry.name))
|
|
177
|
-
continue;
|
|
178
|
-
walk(full);
|
|
179
|
-
}
|
|
180
|
-
else if (entry.isFile()) {
|
|
181
|
-
visited++;
|
|
182
|
-
const ext = path.extname(entry.name).toLowerCase();
|
|
183
|
-
try {
|
|
184
|
-
if (ext === ".json" && /openapi|swagger/i.test(entry.name)) {
|
|
185
|
-
const spec = JSON.parse(fs.readFileSync(full, "utf8"));
|
|
186
|
-
results.push(...parseOpenApiSpec(spec));
|
|
187
|
-
}
|
|
188
|
-
else if (ROUTE_EXTENSIONS.has(ext)) {
|
|
189
|
-
const content = fs.readFileSync(full, "utf8");
|
|
190
|
-
if (/\.(get|post|put|patch|delete)\(|@(Get|Post|Put|Patch|Delete)\(|\broute\(/.test(content)) {
|
|
191
|
-
results.push(...scanRouteSource(path.relative(rootDir, full), content));
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
catch {
|
|
196
|
-
/* skip unreadable files */
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
};
|
|
201
|
-
walk(rootDir);
|
|
202
|
-
return dedupe(results);
|
|
203
|
-
}
|
|
204
|
-
export function dedupe(endpoints) {
|
|
205
|
-
const map = new Map();
|
|
206
|
-
for (const e of endpoints) {
|
|
207
|
-
const key = endpointKey(e);
|
|
208
|
-
const existing = map.get(key);
|
|
209
|
-
if (!existing) {
|
|
210
|
-
map.set(key, e);
|
|
211
|
-
}
|
|
212
|
-
else {
|
|
213
|
-
// Prefer the record with richer schema info.
|
|
214
|
-
map.set(key, {
|
|
215
|
-
...existing,
|
|
216
|
-
requestSchema: existing.requestSchema ?? e.requestSchema,
|
|
217
|
-
responseSchema: existing.responseSchema ?? e.responseSchema,
|
|
218
|
-
authRequired: existing.authRequired || e.authRequired,
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
return [...map.values()].sort((a, b) => endpointKey(a).localeCompare(endpointKey(b)));
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* Diff a previous catalog against a freshly scanned one.
|
|
226
|
-
*/
|
|
227
|
-
export function detectApiDrift(previous, current) {
|
|
228
|
-
const prevMap = new Map(previous.map((e) => [endpointKey(e), e]));
|
|
229
|
-
const curMap = new Map(current.map((e) => [endpointKey(e), e]));
|
|
230
|
-
const added = [];
|
|
231
|
-
const removed = [];
|
|
232
|
-
const changed = [];
|
|
233
|
-
for (const [key, cur] of curMap) {
|
|
234
|
-
const prev = prevMap.get(key);
|
|
235
|
-
if (!prev) {
|
|
236
|
-
added.push(cur);
|
|
237
|
-
continue;
|
|
238
|
-
}
|
|
239
|
-
if ((prev.requestSchema ?? "") !== (cur.requestSchema ?? "") ||
|
|
240
|
-
(prev.responseSchema ?? "") !== (cur.responseSchema ?? "") ||
|
|
241
|
-
prev.authRequired !== cur.authRequired) {
|
|
242
|
-
changed.push({ previous: prev, current: cur });
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
for (const [key, prev] of prevMap) {
|
|
246
|
-
if (!curMap.has(key))
|
|
247
|
-
removed.push(prev);
|
|
248
|
-
}
|
|
249
|
-
return { added, removed, changed };
|
|
250
|
-
}
|
|
251
|
-
export function isApiDriftClean(drift) {
|
|
252
|
-
return drift.added.length === 0 && drift.removed.length === 0 && drift.changed.length === 0;
|
|
253
|
-
}
|
|
1
|
+
export * from "./modules/agent/api-catalog.js";
|
|
254
2
|
//# sourceMappingURL=api-catalog.js.map
|
package/dist/api-catalog.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-catalog.js","sourceRoot":"","sources":["../src/api-catalog.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"api-catalog.js","sourceRoot":"","sources":["../src/api-catalog.ts"],"names":[],"mappings":"AAAA,cAAc,gCAAgC,CAAC"}
|