@aiconnect/confidant 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/README.md +570 -0
- package/dist/api-client.d.ts +58 -0
- package/dist/api-client.d.ts.map +1 -0
- package/dist/api-client.js +101 -0
- package/dist/api-client.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +69 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/create.d.ts +3 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +51 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/delete.d.ts +3 -0
- package/dist/commands/delete.d.ts.map +1 -0
- package/dist/commands/delete.js +29 -0
- package/dist/commands/delete.js.map +1 -0
- package/dist/commands/get-request.d.ts +3 -0
- package/dist/commands/get-request.d.ts.map +1 -0
- package/dist/commands/get-request.js +89 -0
- package/dist/commands/get-request.js.map +1 -0
- package/dist/commands/get.d.ts +3 -0
- package/dist/commands/get.d.ts.map +1 -0
- package/dist/commands/get.js +29 -0
- package/dist/commands/get.js.map +1 -0
- package/dist/commands/request.d.ts +3 -0
- package/dist/commands/request.d.ts.map +1 -0
- package/dist/commands/request.js +289 -0
- package/dist/commands/request.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +40 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/crypto.d.ts +32 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +79 -0
- package/dist/crypto.js.map +1 -0
- package/dist/crypto.test.d.ts +5 -0
- package/dist/crypto.test.d.ts.map +1 -0
- package/dist/crypto.test.js +77 -0
- package/dist/crypto.test.js.map +1 -0
- package/dist/i18n.d.ts +55 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +63 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/network-detection.d.ts +11 -0
- package/dist/network-detection.d.ts.map +1 -0
- package/dist/network-detection.js +54 -0
- package/dist/network-detection.js.map +1 -0
- package/dist/network-detection.test.d.ts +2 -0
- package/dist/network-detection.test.d.ts.map +1 -0
- package/dist/network-detection.test.js +150 -0
- package/dist/network-detection.test.js.map +1 -0
- package/dist/rate-limiter.d.ts +61 -0
- package/dist/rate-limiter.d.ts.map +1 -0
- package/dist/rate-limiter.js +128 -0
- package/dist/rate-limiter.js.map +1 -0
- package/dist/rate-limiter.test.d.ts +5 -0
- package/dist/rate-limiter.test.d.ts.map +1 -0
- package/dist/rate-limiter.test.js +130 -0
- package/dist/rate-limiter.test.js.map +1 -0
- package/dist/registry.d.ts +136 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +182 -0
- package/dist/registry.js.map +1 -0
- package/dist/registry.test.d.ts +13 -0
- package/dist/registry.test.d.ts.map +1 -0
- package/dist/registry.test.js +308 -0
- package/dist/registry.test.js.map +1 -0
- package/dist/routes.d.ts +4 -0
- package/dist/routes.d.ts.map +1 -0
- package/dist/routes.js +931 -0
- package/dist/routes.js.map +1 -0
- package/dist/server.d.ts +27 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +79 -0
- package/dist/server.js.map +1 -0
- package/dist/storage.d.ts +150 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +298 -0
- package/dist/storage.js.map +1 -0
- package/dist/storage.test.d.ts +5 -0
- package/dist/storage.test.d.ts.map +1 -0
- package/dist/storage.test.js +466 -0
- package/dist/storage.test.js.map +1 -0
- package/dist/types.d.ts +144 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +56 -0
- package/dist/types.js.map +1 -0
- package/dist/url-helper.d.ts +16 -0
- package/dist/url-helper.d.ts.map +1 -0
- package/dist/url-helper.js +27 -0
- package/dist/url-helper.js.map +1 -0
- package/dist/url-helper.test.d.ts +2 -0
- package/dist/url-helper.test.d.ts.map +1 -0
- package/dist/url-helper.test.js +70 -0
- package/dist/url-helper.test.js.map +1 -0
- package/package.json +73 -0
- package/public/index.html +352 -0
package/README.md
ADDED
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
# Confidant
|
|
2
|
+
|
|
3
|
+
**The missing link between AI assistants and humans for secure secret sharing.**
|
|
4
|
+
|
|
5
|
+
When your AI assistant needs a password, API key, or any sensitive credential, where does it go? Through chat history. Logged. Stored. Exposed.
|
|
6
|
+
|
|
7
|
+
Confidant solves this. It creates a secure, time-limited channel where humans can submit secrets directly to AI assistants — without the secret ever touching chat logs.
|
|
8
|
+
|
|
9
|
+
## The Problem
|
|
10
|
+
|
|
11
|
+
AI assistants like [Clawdbot](https://github.com/clawdbot/clawdbot), Claude Code, and others are becoming trusted collaborators. They need credentials to help you:
|
|
12
|
+
|
|
13
|
+
- Deploy to your servers
|
|
14
|
+
- Access your APIs
|
|
15
|
+
- Configure your services
|
|
16
|
+
- Manage your accounts
|
|
17
|
+
|
|
18
|
+
But every time you paste a password in chat, it's logged somewhere. Chat history, model training data, audit logs. That's not secure.
|
|
19
|
+
|
|
20
|
+
## The Solution
|
|
21
|
+
|
|
22
|
+
Confidant provides a **pull-based secret handoff**:
|
|
23
|
+
|
|
24
|
+
1. **AI requests a secret** → Creates a secure request with a unique URL
|
|
25
|
+
2. **Human receives the URL** → Opens it in their browser
|
|
26
|
+
3. **Human submits the secret** → Direct browser-to-server, bypassing chat
|
|
27
|
+
4. **AI retrieves the secret** → Auto-polls until the secret arrives
|
|
28
|
+
5. **Secret self-destructs** → Deleted immediately after retrieval
|
|
29
|
+
|
|
30
|
+
The secret never passes through chat. It's a direct handshake between human and AI.
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
### Installation
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install -g confidant
|
|
38
|
+
# or
|
|
39
|
+
npx confidant
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Start the Server
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
confidant serve
|
|
46
|
+
# Server running on http://localhost:3000
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Request a Secret (AI side)
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
confidant request
|
|
53
|
+
# 🔗 Share this URL: http://localhost:3000/r/abc123...
|
|
54
|
+
# ⏳ Waiting for secret...
|
|
55
|
+
# ✅ Secret received!
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Multiple URL Options
|
|
59
|
+
|
|
60
|
+
When you create a request, Confidant automatically detects and displays multiple URL options for different deployment scenarios:
|
|
61
|
+
|
|
62
|
+
#### Localhost URL (Always Available)
|
|
63
|
+
Use when both CLI and user are on the same machine:
|
|
64
|
+
```bash
|
|
65
|
+
confidant request
|
|
66
|
+
# Access URLs:
|
|
67
|
+
#
|
|
68
|
+
# Localhost (primary):
|
|
69
|
+
# Use when both CLI and user are on the same machine
|
|
70
|
+
# http://localhost:3000/request/abc123
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
#### Local Network IP URL (Auto-Detected)
|
|
74
|
+
Automatically displayed when a private IP is detected on the same network:
|
|
75
|
+
```bash
|
|
76
|
+
confidant request
|
|
77
|
+
# Access URLs:
|
|
78
|
+
#
|
|
79
|
+
# Local Network IP:
|
|
80
|
+
# Use for cross-device access on the same network
|
|
81
|
+
# http://192.168.1.100:3000/request/abc123
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Use cases:
|
|
85
|
+
- **Mac Mini + iPhone**: CLI on Mac Mini, user on iPhone
|
|
86
|
+
- **Docker + Host**: CLI in Docker container, user on host machine
|
|
87
|
+
- **VM + External**: CLI in VM, user on host network
|
|
88
|
+
|
|
89
|
+
#### Tunneling Services (For External Access)
|
|
90
|
+
For containers, VMs, or when external access is needed, use tunneling services:
|
|
91
|
+
|
|
92
|
+
**ngrok** (Quick Setup)
|
|
93
|
+
```bash
|
|
94
|
+
# Install ngrok
|
|
95
|
+
brew install ngrok # or download from ngrok.com
|
|
96
|
+
|
|
97
|
+
# Expose server
|
|
98
|
+
ngrok http 3000
|
|
99
|
+
# Forwarding: https://abc123.ngrok.io -> http://localhost:3000
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Tailscale** (Mesh VPN)
|
|
103
|
+
```bash
|
|
104
|
+
# Install Tailscale
|
|
105
|
+
# Follow instructions at https://tailscale.com
|
|
106
|
+
|
|
107
|
+
# Get your Tailscale IP
|
|
108
|
+
tailscale ip -4
|
|
109
|
+
# Use this IP with Confidant
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Cloudflare Tunnel** (Zero Trust)
|
|
113
|
+
```bash
|
|
114
|
+
# Install cloudflared
|
|
115
|
+
# Follow instructions at https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/
|
|
116
|
+
|
|
117
|
+
# Start tunnel
|
|
118
|
+
cloudflared tunnel --url http://localhost:3000
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**localtunnel** (Simple, No Signup)
|
|
122
|
+
```bash
|
|
123
|
+
# Install localtunnel
|
|
124
|
+
npm install -g localtunnel
|
|
125
|
+
|
|
126
|
+
# Expose server
|
|
127
|
+
lt --port 3000
|
|
128
|
+
# Your URL is: https://abc123.loca.lt
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Choose the tunneling service that best fits your needs and security requirements.
|
|
132
|
+
|
|
133
|
+
### Expose with ngrok (for remote access)
|
|
134
|
+
|
|
135
|
+
For AI assistants running on remote servers, use [ngrok](https://ngrok.com) to expose your Confidant instance:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
# Install ngrok
|
|
139
|
+
brew install ngrok # or download from ngrok.com
|
|
140
|
+
|
|
141
|
+
# Expose the server
|
|
142
|
+
ngrok http 3000
|
|
143
|
+
# Forwarding: https://abc123.ngrok.io -> http://localhost:3000
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Then configure the CLI to use the public URL:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
export CONFIDANT_API_URL=https://abc123.ngrok.io
|
|
150
|
+
confidant request
|
|
151
|
+
# 🔗 Share this URL: https://abc123.ngrok.io/r/xyz789...
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Now anyone can submit secrets to your AI assistant from anywhere.
|
|
155
|
+
|
|
156
|
+
## How It Works
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
┌─────────────┐ 1. Request ┌─────────────┐
|
|
160
|
+
│ │ ─────────────────▶ │ │
|
|
161
|
+
│ AI │ │ Confidant │
|
|
162
|
+
│ Assistant │ ◀───────────────── │ Server │
|
|
163
|
+
│ │ 4. Secret │ │
|
|
164
|
+
└─────────────┘ └─────────────┘
|
|
165
|
+
▲
|
|
166
|
+
│ 3. Submit
|
|
167
|
+
│ (HTTPS)
|
|
168
|
+
┌─────────────┐
|
|
169
|
+
2. URL via chat │ │
|
|
170
|
+
─────────────────────────────▶ │ Human │
|
|
171
|
+
│ Browser │
|
|
172
|
+
└─────────────┘
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
The secret travels from browser → server → AI. Chat only carries the URL.
|
|
176
|
+
|
|
177
|
+
## Use Cases
|
|
178
|
+
|
|
179
|
+
### For AI Assistants (Clawdbot, etc.)
|
|
180
|
+
|
|
181
|
+
When your AI needs credentials:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# AI runs this
|
|
185
|
+
confidant request --quiet
|
|
186
|
+
# Outputs just the URL to share with the human
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
The AI shares the URL in chat, waits for submission, then uses the secret.
|
|
190
|
+
|
|
191
|
+
### For DevOps / CI/CD
|
|
192
|
+
|
|
193
|
+
Share deployment secrets without hardcoding:
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
# Create a one-time secret
|
|
197
|
+
confidant create --secret "$DEPLOY_KEY" --max-access-count 1
|
|
198
|
+
# Share the ID with your pipeline
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### For Team Collaboration
|
|
202
|
+
|
|
203
|
+
Share credentials securely with teammates:
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
# Create a secret that expires in 5 minutes
|
|
207
|
+
confidant create --secret "temp-password" --ttl 300000
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## CLI Reference
|
|
211
|
+
|
|
212
|
+
### `confidant serve`
|
|
213
|
+
Start the Confidant server.
|
|
214
|
+
|
|
215
|
+
### `confidant request`
|
|
216
|
+
Create a secret request and wait for submission.
|
|
217
|
+
|
|
218
|
+
Options:
|
|
219
|
+
- `--expires-in <seconds>` - Request expiration (default: 86400)
|
|
220
|
+
- `--poll-interval <seconds>` - Polling interval (default: 2)
|
|
221
|
+
- `--label <text>` - Optional label to describe what secret is being requested (max 200 characters)
|
|
222
|
+
- `--quiet` - Minimal output (just URLs and secret)
|
|
223
|
+
- `--json` - JSON output format (includes all URL fields)
|
|
224
|
+
- `--verbose` - Show detailed information including network detection
|
|
225
|
+
|
|
226
|
+
**Multi-URL Display**: When creating a request, Confidant automatically detects your local network IP and displays multiple URL options:
|
|
227
|
+
|
|
228
|
+
- **Localhost URL** (Always shown): For accessing from the same device (e.g., `http://localhost:3000/r/abc123`)
|
|
229
|
+
- **Local Network IP URL** (Auto-detected): For sharing with other devices on your local network (e.g., `http://192.168.1.100:3000/r/abc123`)
|
|
230
|
+
- **Tunneling Suggestions** (Always shown): For containers/VMs or external access (ngrok, Tailscale, Cloudflare Tunnel, localtunnel)
|
|
231
|
+
|
|
232
|
+
This makes it easy to share secrets across devices without needing external services like ngrok.
|
|
233
|
+
|
|
234
|
+
### `confidant create`
|
|
235
|
+
Create a secret directly.
|
|
236
|
+
|
|
237
|
+
Options:
|
|
238
|
+
- `--secret <value>` - The secret to store
|
|
239
|
+
- `--ttl <ms>` - Time-to-live in milliseconds
|
|
240
|
+
- `--max-access-count <n>` - Maximum access count
|
|
241
|
+
|
|
242
|
+
### `confidant get <id>`
|
|
243
|
+
Retrieve a secret by ID.
|
|
244
|
+
|
|
245
|
+
### `confidant delete <id>`
|
|
246
|
+
Delete a secret.
|
|
247
|
+
|
|
248
|
+
### `confidant status <id>`
|
|
249
|
+
Check secret status.
|
|
250
|
+
|
|
251
|
+
## API Endpoints
|
|
252
|
+
|
|
253
|
+
| Method | Endpoint | Description |
|
|
254
|
+
|--------|----------|-------------|
|
|
255
|
+
| POST | `/requests` | Create a secret request |
|
|
256
|
+
| GET | `/requests/:hash` | Secret submission form (HTML) |
|
|
257
|
+
| POST | `/requests/:hash` | Submit a secret |
|
|
258
|
+
| GET | `/requests/:id/poll` | Poll for secret availability |
|
|
259
|
+
| POST | `/secrets` | Create a secret directly |
|
|
260
|
+
| GET | `/secrets/:id` | Retrieve a secret |
|
|
261
|
+
| DELETE | `/secrets/:id` | Delete a secret |
|
|
262
|
+
| GET | `/health` | Health check |
|
|
263
|
+
|
|
264
|
+
## Deployment Options
|
|
265
|
+
|
|
266
|
+
### Local Development
|
|
267
|
+
```bash
|
|
268
|
+
npm run dev
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Docker
|
|
272
|
+
```bash
|
|
273
|
+
docker build -t confidant .
|
|
274
|
+
docker run -p 3000:3000 confidant
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### ngrok (Quick Public Access)
|
|
278
|
+
```bash
|
|
279
|
+
ngrok http 3000
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Production
|
|
283
|
+
For production, deploy behind a reverse proxy (nginx, Caddy) with proper TLS.
|
|
284
|
+
|
|
285
|
+
## Security Notes
|
|
286
|
+
|
|
287
|
+
- **No persistence by default**: Secrets live in memory only
|
|
288
|
+
- **Auto-expiration**: Secrets self-destruct after TTL or access limit
|
|
289
|
+
- **No chat logging**: Secrets bypass chat history entirely
|
|
290
|
+
- **HTTPS required**: Always use TLS in production (ngrok provides this automatically)
|
|
291
|
+
|
|
292
|
+
## Troubleshooting
|
|
293
|
+
|
|
294
|
+
### URL Access Issues
|
|
295
|
+
|
|
296
|
+
**Localhost URL not working?**
|
|
297
|
+
- Ensure Confidant server is running: `confidant serve`
|
|
298
|
+
- Check if port 3000 is available: `lsof -i :3000` (macOS/Linux) or `netstat -ano | findstr :3000` (Windows)
|
|
299
|
+
- Verify server is listening on correct port
|
|
300
|
+
|
|
301
|
+
**Local Network IP URL not accessible?**
|
|
302
|
+
- Verify both devices are on the same network
|
|
303
|
+
- Check firewall settings on the machine running Confidant
|
|
304
|
+
- Ensure the detected IP is correct (use `--verbose` flag to see detection results)
|
|
305
|
+
- Try pinging the IP from the other device: `ping 192.168.x.x`
|
|
306
|
+
|
|
307
|
+
**No local IP detected?**
|
|
308
|
+
- This is normal in some environments (cloud VMs, certain network configurations)
|
|
309
|
+
- Use localhost URL if CLI and user are on same machine
|
|
310
|
+
- Use tunneling services for external access
|
|
311
|
+
|
|
312
|
+
**Tunneling service not working?**
|
|
313
|
+
- Ensure tunnel is running and forwarding to correct port (3000)
|
|
314
|
+
- Check tunnel service status page for connection issues
|
|
315
|
+
- Verify tunnel URL matches the one displayed by Confidant
|
|
316
|
+
- Some tunnels may require authentication - check service documentation
|
|
317
|
+
|
|
318
|
+
**Cross-device scenarios not working?**
|
|
319
|
+
- Mac Mini + iPhone: Ensure both are on same Wi-Fi network
|
|
320
|
+
- Docker + Host: Use `--network host` flag or port mapping
|
|
321
|
+
- VM + Host: Configure VM network to use bridged or host-only adapter
|
|
322
|
+
|
|
323
|
+
### Verbose Mode
|
|
324
|
+
|
|
325
|
+
Use `--verbose` flag to see detailed information:
|
|
326
|
+
```bash
|
|
327
|
+
confidant request --verbose
|
|
328
|
+
# Shows network interface detection results
|
|
329
|
+
# Shows API response details
|
|
330
|
+
# Shows timing information
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
## Environment Variables
|
|
334
|
+
|
|
335
|
+
| Variable | Default | Description |
|
|
336
|
+
|----------|---------|-------------|
|
|
337
|
+
| `PORT` | 3000 | Server port |
|
|
338
|
+
| `CONFIDANT_API_URL` | http://localhost:3000 | API URL for CLI |
|
|
339
|
+
|
|
340
|
+
## Tech Stack
|
|
341
|
+
|
|
342
|
+
- **Runtime**: Node.js 18+
|
|
343
|
+
- **Language**: TypeScript
|
|
344
|
+
- **Framework**: Hono
|
|
345
|
+
- **Validation**: Zod
|
|
346
|
+
|
|
347
|
+
## Modular Registry System
|
|
348
|
+
|
|
349
|
+
Confidant includes a modular registry system that enables dynamic registration and management of components. This provides extensibility and allows for plugin-like architecture.
|
|
350
|
+
|
|
351
|
+
### Overview
|
|
352
|
+
|
|
353
|
+
The registry system provides:
|
|
354
|
+
- **Type-safe module registration** using TypeScript generics
|
|
355
|
+
- **Lifecycle hooks** (`init`, `destroy`) for module initialization and cleanup
|
|
356
|
+
- **Multiple registry types** for different component categories
|
|
357
|
+
- **Singleton instances** for consistent access across the application
|
|
358
|
+
|
|
359
|
+
### Module Types
|
|
360
|
+
|
|
361
|
+
#### Storage Modules
|
|
362
|
+
|
|
363
|
+
Storage modules handle data persistence and retrieval:
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
import { StorageModule, storageRegistry } from './registry.js';
|
|
367
|
+
|
|
368
|
+
const myStorage: StorageModule = {
|
|
369
|
+
name: 'my-storage',
|
|
370
|
+
|
|
371
|
+
async init() {
|
|
372
|
+
console.log('Initializing storage...');
|
|
373
|
+
},
|
|
374
|
+
|
|
375
|
+
async get(key: string) {
|
|
376
|
+
// Retrieve value by key
|
|
377
|
+
return value;
|
|
378
|
+
},
|
|
379
|
+
|
|
380
|
+
async set(key: string, value: any, ttl?: number) {
|
|
381
|
+
// Store value with optional TTL
|
|
382
|
+
},
|
|
383
|
+
|
|
384
|
+
async delete(key: string) {
|
|
385
|
+
// Delete value by key
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
// Register the module
|
|
390
|
+
await storageRegistry.register('my-storage', myStorage);
|
|
391
|
+
|
|
392
|
+
// Retrieve and use the module
|
|
393
|
+
const storage = storageRegistry.get('my-storage');
|
|
394
|
+
await storage?.set('key', 'value');
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
#### Validator Modules
|
|
398
|
+
|
|
399
|
+
Validator modules handle data validation:
|
|
400
|
+
|
|
401
|
+
```typescript
|
|
402
|
+
import { ValidatorModule, validatorRegistry } from './registry.js';
|
|
403
|
+
|
|
404
|
+
const myValidator: ValidatorModule = {
|
|
405
|
+
name: 'my-validator',
|
|
406
|
+
|
|
407
|
+
private errors: string[] = [],
|
|
408
|
+
|
|
409
|
+
async init() {
|
|
410
|
+
console.log('Initializing validator...');
|
|
411
|
+
},
|
|
412
|
+
|
|
413
|
+
validate(data: any): boolean {
|
|
414
|
+
this.errors = [];
|
|
415
|
+
// Validation logic
|
|
416
|
+
if (!data) {
|
|
417
|
+
this.errors.push('Data is required');
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
return true;
|
|
421
|
+
},
|
|
422
|
+
|
|
423
|
+
getErrors(): string[] {
|
|
424
|
+
return [...this.errors];
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
await validatorRegistry.register('my-validator', myValidator);
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
#### Transformer Modules
|
|
432
|
+
|
|
433
|
+
Transformer modules handle data transformation:
|
|
434
|
+
|
|
435
|
+
```typescript
|
|
436
|
+
import { TransformerModule, transformerRegistry } from './registry.js';
|
|
437
|
+
|
|
438
|
+
const myTransformer: TransformerModule = {
|
|
439
|
+
name: 'my-transformer',
|
|
440
|
+
|
|
441
|
+
async init() {
|
|
442
|
+
console.log('Initializing transformer...');
|
|
443
|
+
},
|
|
444
|
+
|
|
445
|
+
transform(data: any): any {
|
|
446
|
+
// Transform data
|
|
447
|
+
if (typeof data === 'string') {
|
|
448
|
+
return data.toUpperCase();
|
|
449
|
+
}
|
|
450
|
+
return data;
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
await transformerRegistry.register('my-transformer', myTransformer);
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### Lifecycle Hooks
|
|
458
|
+
|
|
459
|
+
Modules can implement optional lifecycle hooks:
|
|
460
|
+
|
|
461
|
+
```typescript
|
|
462
|
+
const moduleWithLifecycle = {
|
|
463
|
+
name: 'lifecycle-module',
|
|
464
|
+
|
|
465
|
+
// Called when module is registered
|
|
466
|
+
async init() {
|
|
467
|
+
console.log('Module initializing...');
|
|
468
|
+
// Setup resources, connections, etc.
|
|
469
|
+
},
|
|
470
|
+
|
|
471
|
+
// Called when module is unregistered
|
|
472
|
+
async destroy() {
|
|
473
|
+
console.log('Module cleaning up...');
|
|
474
|
+
// Release resources, close connections, etc.
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
### Registry API
|
|
480
|
+
|
|
481
|
+
#### `register(name: string, module: T): Promise<void>`
|
|
482
|
+
|
|
483
|
+
Register a module with the given name.
|
|
484
|
+
|
|
485
|
+
```typescript
|
|
486
|
+
await storageRegistry.register('redis', redisStorageModule);
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
#### `unregister(name: string): Promise<void>`
|
|
490
|
+
|
|
491
|
+
Unregister a module by name.
|
|
492
|
+
|
|
493
|
+
```typescript
|
|
494
|
+
await storageRegistry.unregister('redis');
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
#### `get(name: string): T | undefined`
|
|
498
|
+
|
|
499
|
+
Retrieve a registered module by name.
|
|
500
|
+
|
|
501
|
+
```typescript
|
|
502
|
+
const storage = storageRegistry.get('redis');
|
|
503
|
+
if (storage) {
|
|
504
|
+
await storage.get('key');
|
|
505
|
+
}
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
#### `has(name: string): boolean`
|
|
509
|
+
|
|
510
|
+
Check if a module is registered.
|
|
511
|
+
|
|
512
|
+
```typescript
|
|
513
|
+
if (storageRegistry.has('redis')) {
|
|
514
|
+
console.log('Redis storage is available');
|
|
515
|
+
}
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
#### `list(): string[]`
|
|
519
|
+
|
|
520
|
+
Get list of all registered module names.
|
|
521
|
+
|
|
522
|
+
```typescript
|
|
523
|
+
const modules = storageRegistry.list();
|
|
524
|
+
console.log('Available modules:', modules);
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
#### `clear(): Promise<void>`
|
|
528
|
+
|
|
529
|
+
Clear all registered modules.
|
|
530
|
+
|
|
531
|
+
```typescript
|
|
532
|
+
await storageRegistry.clear();
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
### Error Handling
|
|
536
|
+
|
|
537
|
+
The registry throws errors for invalid operations:
|
|
538
|
+
|
|
539
|
+
```typescript
|
|
540
|
+
try {
|
|
541
|
+
await storageRegistry.register('redis', redisModule);
|
|
542
|
+
await storageRegistry.register('redis', redisModule); // Error: duplicate
|
|
543
|
+
} catch (error) {
|
|
544
|
+
console.error('Registration failed:', error.message);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
try {
|
|
548
|
+
await storageRegistry.unregister('non-existent'); // Error: not found
|
|
549
|
+
} catch (error) {
|
|
550
|
+
console.error('Unregistration failed:', error.message);
|
|
551
|
+
}
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
### Example Modules
|
|
555
|
+
|
|
556
|
+
Confidant includes example modules:
|
|
557
|
+
|
|
558
|
+
- **MemoryStorageModule**: In-memory storage with TTL support
|
|
559
|
+
- **BasicValidatorModule**: Simple validation for non-empty data
|
|
560
|
+
- **UppercaseTransformerModule**: Transforms strings to uppercase
|
|
561
|
+
|
|
562
|
+
These are automatically registered on application startup.
|
|
563
|
+
|
|
564
|
+
## License
|
|
565
|
+
|
|
566
|
+
ISC
|
|
567
|
+
|
|
568
|
+
---
|
|
569
|
+
|
|
570
|
+
**Confidant**: Because your AI assistant shouldn't have to ask for passwords in public.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export interface SecretCreateResponse {
|
|
2
|
+
id: string;
|
|
3
|
+
expiresAt: string;
|
|
4
|
+
maxAccessCount: number;
|
|
5
|
+
}
|
|
6
|
+
export interface SecretGetResponse {
|
|
7
|
+
secret: string;
|
|
8
|
+
}
|
|
9
|
+
export interface SecretStatusResponse {
|
|
10
|
+
id: string;
|
|
11
|
+
expiresAt: string;
|
|
12
|
+
accessCount: number;
|
|
13
|
+
maxAccessCount: number;
|
|
14
|
+
}
|
|
15
|
+
export interface ErrorResponse {
|
|
16
|
+
error: string;
|
|
17
|
+
}
|
|
18
|
+
export interface CreateSecretRequestResponse {
|
|
19
|
+
id: string;
|
|
20
|
+
hash: string;
|
|
21
|
+
url: string;
|
|
22
|
+
expiresAt: string;
|
|
23
|
+
status: string;
|
|
24
|
+
label?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface PollSecretRequestResponse {
|
|
27
|
+
id: string;
|
|
28
|
+
status: string;
|
|
29
|
+
secret: string | null;
|
|
30
|
+
label?: string;
|
|
31
|
+
}
|
|
32
|
+
export declare class ApiClient {
|
|
33
|
+
private baseUrl;
|
|
34
|
+
constructor(baseUrl: string);
|
|
35
|
+
get apiUrl(): string;
|
|
36
|
+
private validateUrl;
|
|
37
|
+
private request;
|
|
38
|
+
createSecret(secret: string, ttl?: number, maxAccessCount?: number): Promise<SecretCreateResponse>;
|
|
39
|
+
getSecret(id: string): Promise<SecretGetResponse>;
|
|
40
|
+
deleteSecret(id: string): Promise<{
|
|
41
|
+
message: string;
|
|
42
|
+
}>;
|
|
43
|
+
getSecretStatus(id: string): Promise<SecretStatusResponse>;
|
|
44
|
+
/**
|
|
45
|
+
* Create a new secret request
|
|
46
|
+
* @param expiresIn Time to live in seconds (default: 86400)
|
|
47
|
+
* @param label Optional label to describe what secret is being requested
|
|
48
|
+
* @returns Secret request details
|
|
49
|
+
*/
|
|
50
|
+
createSecretRequest(expiresIn?: number, label?: string): Promise<CreateSecretRequestResponse>;
|
|
51
|
+
/**
|
|
52
|
+
* Poll for secret availability and retrieve if available
|
|
53
|
+
* @param id The request ID
|
|
54
|
+
* @returns Poll result with status and optional secret
|
|
55
|
+
*/
|
|
56
|
+
pollSecretRequest(id: string): Promise<PollSecretRequestResponse>;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=api-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,2BAA2B;IAC1C,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,EAAE,MAAM;IAK3B,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,OAAO,CAAC,WAAW;YAQL,OAAO;IA8Bf,YAAY,CAChB,MAAM,EAAE,MAAM,EACd,GAAG,CAAC,EAAE,MAAM,EACZ,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,oBAAoB,CAAC;IAmB1B,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAIjD,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAMtD,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAMhE;;;;;OAKG;IACG,mBAAmB,CACvB,SAAS,GAAE,MAAc,EACzB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,2BAA2B,CAAC;IAgBvC;;;;OAIG;IACG,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC;CAGxE"}
|