@nokai/cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +193 -0
- package/dist/connection-manager.d.ts +45 -0
- package/dist/connection-manager.d.ts.map +1 -0
- package/dist/connection-manager.js +262 -0
- package/dist/connection-manager.js.map +1 -0
- package/dist/crypto.d.ts +8 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +42 -0
- package/dist/crypto.js.map +1 -0
- package/dist/db.d.ts +47 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +195 -0
- package/dist/db.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/message-protocol.d.ts +9 -0
- package/dist/message-protocol.d.ts.map +1 -0
- package/dist/message-protocol.js +85 -0
- package/dist/message-protocol.js.map +1 -0
- package/dist/peer-connection.d.ts +40 -0
- package/dist/peer-connection.d.ts.map +1 -0
- package/dist/peer-connection.js +159 -0
- package/dist/peer-connection.js.map +1 -0
- package/dist/profile.d.ts +11 -0
- package/dist/profile.d.ts.map +1 -0
- package/dist/profile.js +62 -0
- package/dist/profile.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +185 -0
- package/dist/server.js.map +1 -0
- package/dist/shared/constants.d.ts +20 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/constants.js +23 -0
- package/dist/shared/constants.js.map +1 -0
- package/dist/shared/index.d.ts +3 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/index.js +19 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/shared/types.d.ts +128 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +41 -0
- package/dist/shared/types.js.map +1 -0
- package/dist/signaling-client.d.ts +19 -0
- package/dist/signaling-client.d.ts.map +1 -0
- package/dist/signaling-client.js +83 -0
- package/dist/signaling-client.js.map +1 -0
- package/dist/tools/approve.d.ts +30 -0
- package/dist/tools/approve.d.ts.map +1 -0
- package/dist/tools/approve.js +46 -0
- package/dist/tools/approve.js.map +1 -0
- package/dist/tools/ask.d.ts +29 -0
- package/dist/tools/ask.d.ts.map +1 -0
- package/dist/tools/ask.js +43 -0
- package/dist/tools/ask.js.map +1 -0
- package/dist/tools/audit.d.ts +24 -0
- package/dist/tools/audit.d.ts.map +1 -0
- package/dist/tools/audit.js +39 -0
- package/dist/tools/audit.js.map +1 -0
- package/dist/tools/connect.d.ts +15 -0
- package/dist/tools/connect.d.ts.map +1 -0
- package/dist/tools/connect.js +62 -0
- package/dist/tools/connect.js.map +1 -0
- package/dist/tools/connections.d.ts +13 -0
- package/dist/tools/connections.d.ts.map +1 -0
- package/dist/tools/connections.js +34 -0
- package/dist/tools/connections.js.map +1 -0
- package/dist/tools/disconnect.d.ts +19 -0
- package/dist/tools/disconnect.d.ts.map +1 -0
- package/dist/tools/disconnect.js +23 -0
- package/dist/tools/disconnect.js.map +1 -0
- package/dist/tools/history.d.ts +24 -0
- package/dist/tools/history.d.ts.map +1 -0
- package/dist/tools/history.js +47 -0
- package/dist/tools/history.js.map +1 -0
- package/dist/tools/join.d.ts +22 -0
- package/dist/tools/join.d.ts.map +1 -0
- package/dist/tools/join.js +60 -0
- package/dist/tools/join.js.map +1 -0
- package/dist/tools/permissions.d.ts +24 -0
- package/dist/tools/permissions.d.ts.map +1 -0
- package/dist/tools/permissions.js +32 -0
- package/dist/tools/permissions.js.map +1 -0
- package/dist/tools/profile-tool.d.ts +29 -0
- package/dist/tools/profile-tool.d.ts.map +1 -0
- package/dist/tools/profile-tool.js +72 -0
- package/dist/tools/profile-tool.js.map +1 -0
- package/dist/tools/reconnect.d.ts +22 -0
- package/dist/tools/reconnect.d.ts.map +1 -0
- package/dist/tools/reconnect.js +88 -0
- package/dist/tools/reconnect.js.map +1 -0
- package/dist/tools/respond.d.ts +37 -0
- package/dist/tools/respond.d.ts.map +1 -0
- package/dist/tools/respond.js +31 -0
- package/dist/tools/respond.js.map +1 -0
- package/dist/tools/tell.d.ts +29 -0
- package/dist/tools/tell.d.ts.map +1 -0
- package/dist/tools/tell.js +45 -0
- package/dist/tools/tell.js.map +1 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 heiisenberrg
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# NokAI — Connecting AIs
|
|
2
|
+
|
|
3
|
+
> Every AI coding assistant is an island. NokAI makes them a team.
|
|
4
|
+
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
NokAI is an MCP server that enables **peer-to-peer communication between AI coding assistants**. Connect your Claude Code with your teammate's Cursor, exchange questions about each other's codebases, and even send action requests — all through encrypted WebRTC data channels.
|
|
8
|
+
|
|
9
|
+
**No code or conversation data ever touches the server.** The signaling server only brokers the initial handshake.
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Install globally
|
|
15
|
+
npm install -g nokai
|
|
16
|
+
|
|
17
|
+
# Add to Claude Code MCP settings
|
|
18
|
+
# See docs/setup/ for your specific tool
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Connect with a Teammate
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
You: "Connect me with my teammate"
|
|
25
|
+
NokAI: 🔗 Connection code: 847293 (expires in 5 minutes)
|
|
26
|
+
|
|
27
|
+
--- Your teammate ---
|
|
28
|
+
|
|
29
|
+
Teammate: "Join NokAI with code 847293"
|
|
30
|
+
NokAI: ✓ Connected with Michael!
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Ask Questions Across Codebases
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
You: "Ask Sara what the message type for /cmd_vel is
|
|
37
|
+
and build me the Flutter model for it"
|
|
38
|
+
|
|
39
|
+
NokAI: → Asking Sara...
|
|
40
|
+
← Sara: geometry_msgs/msg/Twist at 10Hz
|
|
41
|
+
Fields: linear.x (float64), angular.z (float64)
|
|
42
|
+
|
|
43
|
+
Building your Flutter model class...
|
|
44
|
+
✓ Created lib/models/twist_model.dart
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Supported Platforms
|
|
48
|
+
|
|
49
|
+
| Platform | Status | Setup Guide |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| Claude Code (CLI & VS Code) | ✅ Full support | [docs/setup/claude-code.md](docs/setup/claude-code.md) |
|
|
52
|
+
| Cursor | ✅ Full support | [docs/setup/cursor.md](docs/setup/cursor.md) |
|
|
53
|
+
| Windsurf (Codeium) | ✅ Full support | [docs/setup/windsurf.md](docs/setup/windsurf.md) |
|
|
54
|
+
| Any MCP tool | ✅ Full support | [docs/setup/generic-mcp.md](docs/setup/generic-mcp.md) |
|
|
55
|
+
|
|
56
|
+
## Tools (13)
|
|
57
|
+
|
|
58
|
+
### Connection
|
|
59
|
+
|
|
60
|
+
| Tool | Description |
|
|
61
|
+
|---|---|
|
|
62
|
+
| `nokai_connect` | Generate a 6-digit OTP connection code |
|
|
63
|
+
| `nokai_join` | Join using an OTP code |
|
|
64
|
+
| `nokai_reconnect` | Reconnect to a saved peer (no new OTP) |
|
|
65
|
+
| `nokai_disconnect` | Disconnect from a peer |
|
|
66
|
+
| `nokai_connections` | List all active and saved connections |
|
|
67
|
+
|
|
68
|
+
### Communication
|
|
69
|
+
|
|
70
|
+
| Tool | Description |
|
|
71
|
+
|---|---|
|
|
72
|
+
| `nokai_ask` | Ask a question to a peer's AI agent |
|
|
73
|
+
| `nokai_respond` | Reply to an incoming question |
|
|
74
|
+
| `nokai_tell` | Send an action request (requires read-write permission) |
|
|
75
|
+
|
|
76
|
+
### Management
|
|
77
|
+
|
|
78
|
+
| Tool | Description |
|
|
79
|
+
|---|---|
|
|
80
|
+
| `nokai_permissions` | View/change permission levels (read-only, read-write, ask-only) |
|
|
81
|
+
| `nokai_approve` | Toggle manual approval mode for incoming queries |
|
|
82
|
+
| `nokai_history` | Browse past message exchanges |
|
|
83
|
+
| `nokai_audit` | View audit log of all events |
|
|
84
|
+
| `nokai_profile` | Manage agent profile and capability cards |
|
|
85
|
+
|
|
86
|
+
## Architecture
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
Your Machine Teammate's Machine
|
|
90
|
+
┌────────────────┐ ┌────────────────┐
|
|
91
|
+
│ AI Assistant │ │ AI Assistant │
|
|
92
|
+
│ (Claude/Cursor) │ │ (Claude/Cursor) │
|
|
93
|
+
│ ↕ MCP │ │ ↕ MCP │
|
|
94
|
+
│ NokAI Server │◄══════════════════►│ NokAI Server │
|
|
95
|
+
│ (local) │ Encrypted P2P │ (local) │
|
|
96
|
+
└────────────────┘ (WebRTC) └────────────────┘
|
|
97
|
+
│ │
|
|
98
|
+
└──────── Signaling Server ───────────┘
|
|
99
|
+
(handshake only)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
- **P2P by default** — messages flow directly between machines
|
|
103
|
+
- **TURN fallback** — relay for firewalled networks (env vars)
|
|
104
|
+
- **Offline queue** — messages queued locally, delivered on reconnect
|
|
105
|
+
- **End-to-end encrypted** — WebRTC DTLS + Ed25519 signatures
|
|
106
|
+
|
|
107
|
+
## Security
|
|
108
|
+
|
|
109
|
+
| Feature | Implementation |
|
|
110
|
+
|---|---|
|
|
111
|
+
| Agent identity | Ed25519 keypair per agent |
|
|
112
|
+
| Connection auth | 6-digit OTP, 5-min expiry, single-use |
|
|
113
|
+
| Transport | WebRTC DTLS encryption |
|
|
114
|
+
| Server access | Signaling server never sees message content |
|
|
115
|
+
| Local storage | Private keys at `~/.nokai/profile.json` (chmod 600) |
|
|
116
|
+
| Reconnection | Peer confirmation required, public key verification |
|
|
117
|
+
|
|
118
|
+
## Self-Hosting the Signaling Server
|
|
119
|
+
|
|
120
|
+
The signaling server runs on Cloudflare Workers (free tier):
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
cd packages/signaling-server
|
|
124
|
+
npx wrangler d1 create nokai-signaling # Create D1 database
|
|
125
|
+
# Update wrangler.toml with the database ID
|
|
126
|
+
npx wrangler deploy # Deploy to Cloudflare
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Set your deployed URL as `NOKAI_SIGNALING_URL` in your MCP config.
|
|
130
|
+
|
|
131
|
+
## Environment Variables
|
|
132
|
+
|
|
133
|
+
| Variable | Required | Default | Description |
|
|
134
|
+
|---|---|---|---|
|
|
135
|
+
| `NOKAI_AGENT_NAME` | No | "Agent" | Your agent's display name |
|
|
136
|
+
| `NOKAI_SIGNALING_URL` | No | — | Signaling server WebSocket URL |
|
|
137
|
+
| `NOKAI_TURN_SERVER` | No | — | TURN relay server URL |
|
|
138
|
+
| `NOKAI_TURN_USERNAME` | No | — | TURN server username |
|
|
139
|
+
| `NOKAI_TURN_PASSWORD` | No | — | TURN server password |
|
|
140
|
+
|
|
141
|
+
## Development
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
# Clone and install
|
|
145
|
+
git clone https://github.com/heiisenberrg/nokAI.git
|
|
146
|
+
cd nokAI
|
|
147
|
+
npm install
|
|
148
|
+
|
|
149
|
+
# Build all packages
|
|
150
|
+
npm run build
|
|
151
|
+
|
|
152
|
+
# Run tests (125 tests)
|
|
153
|
+
npm test
|
|
154
|
+
|
|
155
|
+
# Dev mode (MCP server)
|
|
156
|
+
cd packages/mcp-server && npm run dev
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Project Structure
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
nokai/
|
|
163
|
+
├── packages/
|
|
164
|
+
│ ├── shared/ # Shared types, constants, type guards
|
|
165
|
+
│ ├── mcp-server/ # MCP server + P2P engine (13 tools)
|
|
166
|
+
│ │ ├── src/tools/ # Tool handlers
|
|
167
|
+
│ │ └── tests/ # 100+ tests
|
|
168
|
+
│ └── signaling-server/ # Cloudflare Workers signaling server
|
|
169
|
+
└── docs/setup/ # Platform-specific setup guides
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Roadmap
|
|
173
|
+
|
|
174
|
+
- [x] v0.1.0 — Core: connect, ask, respond via P2P
|
|
175
|
+
- [x] v0.2.0 — Reconnection, history, TURN, offline queue, approval mode
|
|
176
|
+
- [x] v0.3.0 — Actions (tell), permission levels
|
|
177
|
+
- [x] v0.4.0 — Audit logs, agent profiles
|
|
178
|
+
- [x] v1.0.0 — Multi-platform, npm packaging
|
|
179
|
+
- [ ] v1.1.0 — Web dashboard for connection management
|
|
180
|
+
- [ ] v1.2.0 — Agent capability discovery within organizations
|
|
181
|
+
- [ ] v2.0.0 — Cross-organization connections
|
|
182
|
+
|
|
183
|
+
## License
|
|
184
|
+
|
|
185
|
+
MIT — see [LICENSE](LICENSE)
|
|
186
|
+
|
|
187
|
+
## Contributing
|
|
188
|
+
|
|
189
|
+
Contributions welcome! Please open an issue first to discuss.
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
Built with frustration at copy-pasting between Slack and Claude.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import type { AgentProfile, PeerMessage, ConnectionRecord } from "./shared/index.js";
|
|
3
|
+
import { type NokaiDB } from "./db.js";
|
|
4
|
+
export declare class ConnectionManager extends EventEmitter {
|
|
5
|
+
private db;
|
|
6
|
+
private profile;
|
|
7
|
+
private activePeers;
|
|
8
|
+
private incomingHandler;
|
|
9
|
+
private heldQueries;
|
|
10
|
+
constructor(db: NokaiDB, profile: AgentProfile);
|
|
11
|
+
registerPeer(connectionId: string, peerName: string, peerPublicKey: string): void;
|
|
12
|
+
setPeerSend(connectionId: string, sendFn: (msg: string) => void): void;
|
|
13
|
+
private findPeerByName;
|
|
14
|
+
sendQuery(peerName: string, content: string, context?: string): PeerMessage;
|
|
15
|
+
sendResponse(peerName: string, replyTo: string, content: string, sourceFiles?: string[]): PeerMessage;
|
|
16
|
+
sendAction(peerName: string, content: string, context?: string): PeerMessage;
|
|
17
|
+
sendActionResult(peerName: string, replyTo: string, content: string, success: boolean, sourceFiles?: string[]): PeerMessage;
|
|
18
|
+
handleIncomingMessage(connectionId: string, rawData: string): void;
|
|
19
|
+
onIncomingMessage(handler: (msg: PeerMessage, peerName: string) => void): void;
|
|
20
|
+
getActiveConnections(): Array<{
|
|
21
|
+
connectionId: string;
|
|
22
|
+
peerName: string;
|
|
23
|
+
}>;
|
|
24
|
+
disconnectPeer(peerName: string): boolean;
|
|
25
|
+
setPeerClose(connectionId: string, closeFn: () => void): void;
|
|
26
|
+
reactivateConnection(connectionId: string, sendFn: (msg: string) => void): void;
|
|
27
|
+
queueMessage(connectionId: string, serializedMessage: string): void;
|
|
28
|
+
flushPendingMessages(connectionId: string): number;
|
|
29
|
+
getSavedConnections(): ConnectionRecord[];
|
|
30
|
+
findSavedConnection(peerName: string): ConnectionRecord | null;
|
|
31
|
+
holdQuery(peerName: string, query: {
|
|
32
|
+
id: string;
|
|
33
|
+
content: string;
|
|
34
|
+
timestamp: string;
|
|
35
|
+
}): void;
|
|
36
|
+
getHeldQueries(peerName: string): Array<{
|
|
37
|
+
id: string;
|
|
38
|
+
content: string;
|
|
39
|
+
peerName: string;
|
|
40
|
+
timestamp: string;
|
|
41
|
+
}>;
|
|
42
|
+
removeHeldQuery(peerName: string, messageId: string): boolean;
|
|
43
|
+
disconnectAll(): void;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=connection-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection-manager.d.ts","sourceRoot":"","sources":["../src/connection-manager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrF,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,SAAS,CAAC;AAkBvC,qBAAa,iBAAkB,SAAQ,YAAY;IACjD,OAAO,CAAC,EAAE,CAAU;IACpB,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,WAAW,CAAsC;IACzD,OAAO,CAAC,eAAe,CAA+D;IACtF,OAAO,CAAC,WAAW,CAAuG;gBAE9G,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY;IAM9C,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI;IAqBjF,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAOtE,OAAO,CAAC,cAAc;IAOtB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,WAAW;IA4B3E,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,WAAW;IA2BrG,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,WAAW;IAkC5E,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,WAAW;IAwB3H,qBAAqB,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAwBlE,iBAAiB,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAI9E,oBAAoB,IAAI,KAAK,CAAC;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAOzE,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAazC,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI;IAO7D,oBAAoB,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAyB/E,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,GAAG,IAAI;IAKnE,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAelD,mBAAmB,IAAI,gBAAgB,EAAE;IAIzC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IAK9D,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAM5F,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAI7G,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IAS7D,aAAa,IAAI,IAAI;CAGtB"}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConnectionManager = void 0;
|
|
4
|
+
const node_events_1 = require("node:events");
|
|
5
|
+
const message_protocol_js_1 = require("./message-protocol.js");
|
|
6
|
+
class ConnectionManager extends node_events_1.EventEmitter {
|
|
7
|
+
db;
|
|
8
|
+
profile;
|
|
9
|
+
activePeers = new Map(); // connectionId -> peer
|
|
10
|
+
incomingHandler = null;
|
|
11
|
+
heldQueries = new Map();
|
|
12
|
+
constructor(db, profile) {
|
|
13
|
+
super();
|
|
14
|
+
this.db = db;
|
|
15
|
+
this.profile = profile;
|
|
16
|
+
}
|
|
17
|
+
registerPeer(connectionId, peerName, peerPublicKey) {
|
|
18
|
+
this.activePeers.set(connectionId, {
|
|
19
|
+
connectionId,
|
|
20
|
+
peerName,
|
|
21
|
+
peerPublicKey,
|
|
22
|
+
send: null,
|
|
23
|
+
close: null,
|
|
24
|
+
});
|
|
25
|
+
this.db.saveConnection({
|
|
26
|
+
id: connectionId,
|
|
27
|
+
peerName,
|
|
28
|
+
peerPublicKey,
|
|
29
|
+
permission: "read-only",
|
|
30
|
+
createdAt: new Date().toISOString(),
|
|
31
|
+
lastConnected: new Date().toISOString(),
|
|
32
|
+
status: "active",
|
|
33
|
+
});
|
|
34
|
+
this.db.logEvent("connection_established", peerName, connectionId, null);
|
|
35
|
+
}
|
|
36
|
+
setPeerSend(connectionId, sendFn) {
|
|
37
|
+
const peer = this.activePeers.get(connectionId);
|
|
38
|
+
if (peer) {
|
|
39
|
+
peer.send = sendFn;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
findPeerByName(peerName) {
|
|
43
|
+
for (const peer of this.activePeers.values()) {
|
|
44
|
+
if (peer.peerName === peerName)
|
|
45
|
+
return peer;
|
|
46
|
+
}
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
sendQuery(peerName, content, context) {
|
|
50
|
+
const peer = this.findPeerByName(peerName);
|
|
51
|
+
if (!peer) {
|
|
52
|
+
throw new Error(`No active connection with peer: ${peerName}`);
|
|
53
|
+
}
|
|
54
|
+
if (!peer.send) {
|
|
55
|
+
throw new Error(`Data channel not ready for peer: ${peerName}`);
|
|
56
|
+
}
|
|
57
|
+
const msg = (0, message_protocol_js_1.createQueryMessage)(this.profile.name, content, context);
|
|
58
|
+
const serialized = (0, message_protocol_js_1.serializeMessage)(msg);
|
|
59
|
+
peer.send(serialized);
|
|
60
|
+
this.db.logEvent("query_sent", peerName, peer.connectionId, content.slice(0, 100));
|
|
61
|
+
this.db.saveMessage({
|
|
62
|
+
id: msg.id,
|
|
63
|
+
connectionId: peer.connectionId,
|
|
64
|
+
direction: "sent",
|
|
65
|
+
type: msg.type,
|
|
66
|
+
content: msg.content,
|
|
67
|
+
sourceFiles: null,
|
|
68
|
+
replyTo: null,
|
|
69
|
+
timestamp: msg.timestamp,
|
|
70
|
+
});
|
|
71
|
+
return msg;
|
|
72
|
+
}
|
|
73
|
+
sendResponse(peerName, replyTo, content, sourceFiles) {
|
|
74
|
+
const peer = this.findPeerByName(peerName);
|
|
75
|
+
if (!peer) {
|
|
76
|
+
throw new Error(`No active connection with peer: ${peerName}`);
|
|
77
|
+
}
|
|
78
|
+
if (!peer.send) {
|
|
79
|
+
throw new Error(`Data channel not ready for peer: ${peerName}`);
|
|
80
|
+
}
|
|
81
|
+
const msg = (0, message_protocol_js_1.createResponseMessage)(this.profile.name, replyTo, content, sourceFiles);
|
|
82
|
+
const serialized = (0, message_protocol_js_1.serializeMessage)(msg);
|
|
83
|
+
peer.send(serialized);
|
|
84
|
+
this.db.saveMessage({
|
|
85
|
+
id: msg.id,
|
|
86
|
+
connectionId: peer.connectionId,
|
|
87
|
+
direction: "sent",
|
|
88
|
+
type: msg.type,
|
|
89
|
+
content: msg.content,
|
|
90
|
+
sourceFiles: sourceFiles ? JSON.stringify(sourceFiles) : null,
|
|
91
|
+
replyTo,
|
|
92
|
+
timestamp: msg.timestamp,
|
|
93
|
+
});
|
|
94
|
+
return msg;
|
|
95
|
+
}
|
|
96
|
+
sendAction(peerName, content, context) {
|
|
97
|
+
const peer = this.findPeerByName(peerName);
|
|
98
|
+
if (!peer) {
|
|
99
|
+
throw new Error(`No active connection with peer: ${peerName}`);
|
|
100
|
+
}
|
|
101
|
+
if (!peer.send) {
|
|
102
|
+
throw new Error(`Data channel not ready for peer: ${peerName}`);
|
|
103
|
+
}
|
|
104
|
+
// Check permission — actions require read-write
|
|
105
|
+
const conn = this.db.getConnectionByPeerName(peerName);
|
|
106
|
+
if (conn && conn.permission !== "read-write") {
|
|
107
|
+
throw new Error(`Permission denied: ${peerName} has "${conn.permission}" access. Actions require "read-write".`);
|
|
108
|
+
}
|
|
109
|
+
const msg = (0, message_protocol_js_1.createActionMessage)(this.profile.name, content, context);
|
|
110
|
+
const serialized = (0, message_protocol_js_1.serializeMessage)(msg);
|
|
111
|
+
peer.send(serialized);
|
|
112
|
+
this.db.logEvent("action_sent", peerName, peer.connectionId, content.slice(0, 100));
|
|
113
|
+
this.db.saveMessage({
|
|
114
|
+
id: msg.id,
|
|
115
|
+
connectionId: peer.connectionId,
|
|
116
|
+
direction: "sent",
|
|
117
|
+
type: msg.type,
|
|
118
|
+
content: msg.content,
|
|
119
|
+
sourceFiles: null,
|
|
120
|
+
replyTo: null,
|
|
121
|
+
timestamp: msg.timestamp,
|
|
122
|
+
});
|
|
123
|
+
return msg;
|
|
124
|
+
}
|
|
125
|
+
sendActionResult(peerName, replyTo, content, success, sourceFiles) {
|
|
126
|
+
const peer = this.findPeerByName(peerName);
|
|
127
|
+
if (!peer || !peer.send) {
|
|
128
|
+
throw new Error(`No active connection with peer: ${peerName}`);
|
|
129
|
+
}
|
|
130
|
+
const msg = (0, message_protocol_js_1.createActionResultMessage)(this.profile.name, replyTo, content, success, sourceFiles);
|
|
131
|
+
const serialized = (0, message_protocol_js_1.serializeMessage)(msg);
|
|
132
|
+
peer.send(serialized);
|
|
133
|
+
this.db.saveMessage({
|
|
134
|
+
id: msg.id,
|
|
135
|
+
connectionId: peer.connectionId,
|
|
136
|
+
direction: "sent",
|
|
137
|
+
type: msg.type,
|
|
138
|
+
content: msg.content,
|
|
139
|
+
sourceFiles: sourceFiles ? JSON.stringify(sourceFiles) : null,
|
|
140
|
+
replyTo,
|
|
141
|
+
timestamp: msg.timestamp,
|
|
142
|
+
});
|
|
143
|
+
return msg;
|
|
144
|
+
}
|
|
145
|
+
handleIncomingMessage(connectionId, rawData) {
|
|
146
|
+
const msg = (0, message_protocol_js_1.parseMessage)(rawData);
|
|
147
|
+
if (!msg)
|
|
148
|
+
return;
|
|
149
|
+
const peer = this.activePeers.get(connectionId);
|
|
150
|
+
if (!peer)
|
|
151
|
+
return;
|
|
152
|
+
this.db.saveMessage({
|
|
153
|
+
id: msg.id,
|
|
154
|
+
connectionId,
|
|
155
|
+
direction: "received",
|
|
156
|
+
type: msg.type,
|
|
157
|
+
content: msg.content,
|
|
158
|
+
sourceFiles: "sourceFiles" in msg && msg.sourceFiles ? JSON.stringify(msg.sourceFiles) : null,
|
|
159
|
+
replyTo: "replyTo" in msg ? msg.replyTo : null,
|
|
160
|
+
timestamp: msg.timestamp,
|
|
161
|
+
});
|
|
162
|
+
this.db.logEvent(`${msg.type}_received`, peer.peerName, connectionId, msg.content.slice(0, 100));
|
|
163
|
+
if (this.incomingHandler) {
|
|
164
|
+
this.incomingHandler(msg, peer.peerName);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
onIncomingMessage(handler) {
|
|
168
|
+
this.incomingHandler = handler;
|
|
169
|
+
}
|
|
170
|
+
getActiveConnections() {
|
|
171
|
+
return Array.from(this.activePeers.values()).map((p) => ({
|
|
172
|
+
connectionId: p.connectionId,
|
|
173
|
+
peerName: p.peerName,
|
|
174
|
+
}));
|
|
175
|
+
}
|
|
176
|
+
disconnectPeer(peerName) {
|
|
177
|
+
for (const [id, peer] of this.activePeers.entries()) {
|
|
178
|
+
if (peer.peerName === peerName) {
|
|
179
|
+
if (peer.close)
|
|
180
|
+
peer.close();
|
|
181
|
+
this.activePeers.delete(id);
|
|
182
|
+
this.db.updateConnectionStatus(id, "dormant");
|
|
183
|
+
this.db.logEvent("connection_disconnected", peer.peerName, id, null);
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
setPeerClose(connectionId, closeFn) {
|
|
190
|
+
const peer = this.activePeers.get(connectionId);
|
|
191
|
+
if (peer) {
|
|
192
|
+
peer.close = closeFn;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
reactivateConnection(connectionId, sendFn) {
|
|
196
|
+
const conn = this.db.getConnection(connectionId);
|
|
197
|
+
if (!conn) {
|
|
198
|
+
throw new Error(`Connection not found: ${connectionId}`);
|
|
199
|
+
}
|
|
200
|
+
this.activePeers.set(connectionId, {
|
|
201
|
+
connectionId,
|
|
202
|
+
peerName: conn.peerName,
|
|
203
|
+
peerPublicKey: conn.peerPublicKey,
|
|
204
|
+
send: sendFn,
|
|
205
|
+
close: null,
|
|
206
|
+
});
|
|
207
|
+
this.db.updateConnectionStatus(connectionId, "active");
|
|
208
|
+
this.db.updateLastConnected(connectionId, new Date().toISOString());
|
|
209
|
+
this.db.logEvent("connection_reactivated", conn.peerName, connectionId, null);
|
|
210
|
+
// Flush any queued messages
|
|
211
|
+
const flushed = this.flushPendingMessages(connectionId);
|
|
212
|
+
if (flushed > 0) {
|
|
213
|
+
console.error(`[NokAI] Delivered ${flushed} queued message(s)`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
queueMessage(connectionId, serializedMessage) {
|
|
217
|
+
const id = `pending_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
218
|
+
this.db.savePendingMessage(id, connectionId, serializedMessage);
|
|
219
|
+
}
|
|
220
|
+
flushPendingMessages(connectionId) {
|
|
221
|
+
const pending = this.db.getPendingMessages(connectionId);
|
|
222
|
+
if (pending.length === 0)
|
|
223
|
+
return 0;
|
|
224
|
+
const peer = this.activePeers.get(connectionId);
|
|
225
|
+
if (!peer || !peer.send)
|
|
226
|
+
return 0;
|
|
227
|
+
for (const msg of pending) {
|
|
228
|
+
peer.send(msg.content);
|
|
229
|
+
}
|
|
230
|
+
this.db.clearPendingMessages(connectionId);
|
|
231
|
+
return pending.length;
|
|
232
|
+
}
|
|
233
|
+
getSavedConnections() {
|
|
234
|
+
return this.db.listDormantConnections();
|
|
235
|
+
}
|
|
236
|
+
findSavedConnection(peerName) {
|
|
237
|
+
const saved = this.db.listDormantConnections();
|
|
238
|
+
return saved.find((c) => c.peerName === peerName) ?? null;
|
|
239
|
+
}
|
|
240
|
+
holdQuery(peerName, query) {
|
|
241
|
+
const existing = this.heldQueries.get(peerName) || [];
|
|
242
|
+
existing.push({ ...query, peerName });
|
|
243
|
+
this.heldQueries.set(peerName, existing);
|
|
244
|
+
}
|
|
245
|
+
getHeldQueries(peerName) {
|
|
246
|
+
return this.heldQueries.get(peerName) || [];
|
|
247
|
+
}
|
|
248
|
+
removeHeldQuery(peerName, messageId) {
|
|
249
|
+
const existing = this.heldQueries.get(peerName) || [];
|
|
250
|
+
const idx = existing.findIndex((q) => q.id === messageId);
|
|
251
|
+
if (idx === -1)
|
|
252
|
+
return false;
|
|
253
|
+
existing.splice(idx, 1);
|
|
254
|
+
this.heldQueries.set(peerName, existing);
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
disconnectAll() {
|
|
258
|
+
this.activePeers.clear();
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
exports.ConnectionManager = ConnectionManager;
|
|
262
|
+
//# sourceMappingURL=connection-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection-manager.js","sourceRoot":"","sources":["../src/connection-manager.ts"],"names":[],"mappings":"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"}
|
package/dist/crypto.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface Keypair {
|
|
2
|
+
publicKey: string;
|
|
3
|
+
privateKey: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function generateKeypair(): Keypair;
|
|
6
|
+
export declare function sign(message: string, privateKeyHex: string): string;
|
|
7
|
+
export declare function verify(message: string, signatureHex: string, publicKeyHex: string): boolean;
|
|
8
|
+
//# sourceMappingURL=crypto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,eAAe,IAAI,OAAO,CAUzC;AAED,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CASnE;AAED,wBAAgB,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAa3F"}
|
package/dist/crypto.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateKeypair = generateKeypair;
|
|
4
|
+
exports.sign = sign;
|
|
5
|
+
exports.verify = verify;
|
|
6
|
+
const node_crypto_1 = require("node:crypto");
|
|
7
|
+
function generateKeypair() {
|
|
8
|
+
const { publicKey, privateKey } = (0, node_crypto_1.generateKeyPairSync)("ed25519", {
|
|
9
|
+
publicKeyEncoding: { type: "spki", format: "der" },
|
|
10
|
+
privateKeyEncoding: { type: "pkcs8", format: "der" },
|
|
11
|
+
});
|
|
12
|
+
return {
|
|
13
|
+
publicKey: publicKey.toString("hex"),
|
|
14
|
+
privateKey: privateKey.toString("hex"),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function sign(message, privateKeyHex) {
|
|
18
|
+
const privateKey = Buffer.from(privateKeyHex, "hex");
|
|
19
|
+
const keyObject = (0, node_crypto_1.createPrivateKey)({
|
|
20
|
+
key: privateKey,
|
|
21
|
+
format: "der",
|
|
22
|
+
type: "pkcs8",
|
|
23
|
+
});
|
|
24
|
+
const signature = (0, node_crypto_1.sign)(null, Buffer.from(message), keyObject);
|
|
25
|
+
return signature.toString("hex");
|
|
26
|
+
}
|
|
27
|
+
function verify(message, signatureHex, publicKeyHex) {
|
|
28
|
+
try {
|
|
29
|
+
const publicKey = Buffer.from(publicKeyHex, "hex");
|
|
30
|
+
const keyObject = (0, node_crypto_1.createPublicKey)({
|
|
31
|
+
key: publicKey,
|
|
32
|
+
format: "der",
|
|
33
|
+
type: "spki",
|
|
34
|
+
});
|
|
35
|
+
const signature = Buffer.from(signatureHex, "hex");
|
|
36
|
+
return (0, node_crypto_1.verify)(null, Buffer.from(message), keyObject, signature);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":";;AAOA,0CAUC;AAED,oBASC;AAED,wBAaC;AA3CD,6CAAiI;AAOjI,SAAgB,eAAe;IAC7B,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,IAAA,iCAAmB,EAAC,SAAS,EAAE;QAC/D,iBAAiB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE;QAClD,kBAAkB,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE;KACrD,CAAC,CAAC;IAEH,OAAO;QACL,SAAS,EAAE,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC;QACpC,UAAU,EAAE,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC;KACvC,CAAC;AACJ,CAAC;AAED,SAAgB,IAAI,CAAC,OAAe,EAAE,aAAqB;IACzD,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;IACrD,MAAM,SAAS,GAAG,IAAA,8BAAgB,EAAC;QACjC,GAAG,EAAE,UAAU;QACf,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,OAAO;KACd,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,IAAA,kBAAU,EAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,CAAC;IACpE,OAAO,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACnC,CAAC;AAED,SAAgB,MAAM,CAAC,OAAe,EAAE,YAAoB,EAAE,YAAoB;IAChF,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;QACnD,MAAM,SAAS,GAAG,IAAA,6BAAe,EAAC;YAChC,GAAG,EAAE,SAAS;YACd,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,MAAM;SACb,CAAC,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;QACnD,OAAO,IAAA,oBAAY,EAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IACxE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
package/dist/db.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ConnectionRecord, Permission } from "./shared/index.js";
|
|
2
|
+
export interface MessageRecord {
|
|
3
|
+
id: string;
|
|
4
|
+
connectionId: string;
|
|
5
|
+
direction: "sent" | "received";
|
|
6
|
+
type: string;
|
|
7
|
+
content: string;
|
|
8
|
+
sourceFiles: string | null;
|
|
9
|
+
replyTo: string | null;
|
|
10
|
+
timestamp: string;
|
|
11
|
+
}
|
|
12
|
+
export interface NokaiDB {
|
|
13
|
+
saveConnection(conn: ConnectionRecord): void;
|
|
14
|
+
getConnection(id: string): ConnectionRecord | null;
|
|
15
|
+
getConnectionByPeerName(peerName: string): ConnectionRecord | null;
|
|
16
|
+
listConnections(): ConnectionRecord[];
|
|
17
|
+
updateLastConnected(id: string, timestamp: string): void;
|
|
18
|
+
deleteConnection(id: string): void;
|
|
19
|
+
updateConnectionStatus(id: string, status: "active" | "dormant"): void;
|
|
20
|
+
getConnectionByPeerPublicKey(publicKey: string): ConnectionRecord | null;
|
|
21
|
+
listDormantConnections(): ConnectionRecord[];
|
|
22
|
+
saveMessage(msg: MessageRecord): void;
|
|
23
|
+
getMessages(connectionId: string, limit?: number): MessageRecord[];
|
|
24
|
+
savePendingMessage(id: string, connectionId: string, content: string): void;
|
|
25
|
+
getPendingMessages(connectionId: string): Array<{
|
|
26
|
+
id: string;
|
|
27
|
+
connectionId: string;
|
|
28
|
+
content: string;
|
|
29
|
+
createdAt: string;
|
|
30
|
+
}>;
|
|
31
|
+
clearPendingMessages(connectionId: string): void;
|
|
32
|
+
getApprovalMode(connectionId: string): "auto" | "manual";
|
|
33
|
+
setApprovalMode(connectionId: string, mode: "auto" | "manual"): void;
|
|
34
|
+
updatePermission(id: string, permission: Permission): void;
|
|
35
|
+
logEvent(eventType: string, peerName: string | null, connectionId: string | null, details: string | null): void;
|
|
36
|
+
getAuditLog(limit?: number): Array<{
|
|
37
|
+
id: number;
|
|
38
|
+
eventType: string;
|
|
39
|
+
peerName: string | null;
|
|
40
|
+
connectionId: string | null;
|
|
41
|
+
details: string | null;
|
|
42
|
+
timestamp: string;
|
|
43
|
+
}>;
|
|
44
|
+
close(): void;
|
|
45
|
+
}
|
|
46
|
+
export declare function createDatabase(dbPath: string): NokaiDB;
|
|
47
|
+
//# sourceMappingURL=db.d.ts.map
|
package/dist/db.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEtE,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,UAAU,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,OAAO;IACtB,cAAc,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC7C,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAAC;IACnD,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAAC;IACnE,eAAe,IAAI,gBAAgB,EAAE,CAAC;IACtC,mBAAmB,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzD,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,sBAAsB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,IAAI,CAAC;IACvE,4BAA4B,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAAC;IACzE,sBAAsB,IAAI,gBAAgB,EAAE,CAAC;IAC7C,WAAW,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAAC;IACtC,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,aAAa,EAAE,CAAC;IACnE,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5E,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1H,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IACjD,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;IACzD,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IACrE,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC3D,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IAChH,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvK,KAAK,IAAI,IAAI,CAAC;CACf;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAyNtD"}
|