@plures/pluresdb 1.5.3 → 1.6.10
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 +174 -290
- package/dist/.tsbuildinfo +1 -1
- package/dist/local-first/unified-api.d.ts +110 -0
- package/dist/local-first/unified-api.d.ts.map +1 -0
- package/dist/local-first/unified-api.js +348 -0
- package/dist/local-first/unified-api.js.map +1 -0
- package/dist/node-index.d.ts +2 -0
- package/dist/node-index.d.ts.map +1 -1
- package/dist/node-index.js +4 -1
- package/dist/node-index.js.map +1 -1
- package/dist/util/debug.d.ts +3 -0
- package/dist/util/debug.d.ts.map +1 -0
- package/dist/util/debug.js +34 -0
- package/dist/util/debug.js.map +1 -0
- package/examples/browser-demo/README.md +204 -0
- package/examples/browser-demo/index.html +466 -0
- package/examples/browser-wasm-integration.md +411 -0
- package/examples/ipc-demo/README.md +127 -0
- package/examples/local-first-usage.ts +138 -0
- package/examples/native-ipc-integration.md +526 -0
- package/examples/tauri-demo/README.md +240 -0
- package/examples/tauri-integration.md +260 -0
- package/legacy/http/api-server.ts +131 -0
- package/legacy/index.ts +3 -0
- package/legacy/local-first/unified-api.ts +449 -0
- package/legacy/node-index.ts +4 -0
- package/legacy/plugins/README.md +181 -0
- package/legacy/plugins/example-embedding-plugin.ts +56 -0
- package/legacy/plugins/plugin-system.ts +315 -0
- package/legacy/tests/unit/local-first-api.test.ts +65 -0
- package/legacy/tests/unit/plugin-system.test.ts +388 -0
- package/legacy/util/debug.ts +14 -1
- package/package.json +8 -2
- package/scripts/validate-npm-publish.js +228 -0
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>PluresDB Browser Demo - Local-First Integration</title>
|
|
7
|
+
<style>
|
|
8
|
+
* {
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 0;
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
body {
|
|
15
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
16
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
17
|
+
padding: 20px;
|
|
18
|
+
min-height: 100vh;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.container {
|
|
22
|
+
max-width: 900px;
|
|
23
|
+
margin: 0 auto;
|
|
24
|
+
background: white;
|
|
25
|
+
border-radius: 12px;
|
|
26
|
+
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
|
|
27
|
+
overflow: hidden;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
header {
|
|
31
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
32
|
+
color: white;
|
|
33
|
+
padding: 30px;
|
|
34
|
+
text-align: center;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
header h1 {
|
|
38
|
+
font-size: 2.5em;
|
|
39
|
+
margin-bottom: 10px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
header p {
|
|
43
|
+
font-size: 1.1em;
|
|
44
|
+
opacity: 0.9;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.status {
|
|
48
|
+
background: #f0f4f8;
|
|
49
|
+
padding: 15px 30px;
|
|
50
|
+
border-bottom: 2px solid #e2e8f0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.status-badge {
|
|
54
|
+
display: inline-block;
|
|
55
|
+
padding: 6px 12px;
|
|
56
|
+
border-radius: 20px;
|
|
57
|
+
font-size: 0.9em;
|
|
58
|
+
font-weight: 600;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.status-badge.active {
|
|
62
|
+
background: #48bb78;
|
|
63
|
+
color: white;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.status-badge.fallback {
|
|
67
|
+
background: #ed8936;
|
|
68
|
+
color: white;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
main {
|
|
72
|
+
padding: 30px;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.section {
|
|
76
|
+
margin-bottom: 30px;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.section h2 {
|
|
80
|
+
color: #2d3748;
|
|
81
|
+
margin-bottom: 15px;
|
|
82
|
+
font-size: 1.5em;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.form-group {
|
|
86
|
+
margin-bottom: 15px;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
label {
|
|
90
|
+
display: block;
|
|
91
|
+
margin-bottom: 5px;
|
|
92
|
+
color: #4a5568;
|
|
93
|
+
font-weight: 600;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
input {
|
|
97
|
+
width: 100%;
|
|
98
|
+
padding: 12px;
|
|
99
|
+
border: 2px solid #e2e8f0;
|
|
100
|
+
border-radius: 6px;
|
|
101
|
+
font-size: 1em;
|
|
102
|
+
transition: border-color 0.3s;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
input:focus {
|
|
106
|
+
outline: none;
|
|
107
|
+
border-color: #667eea;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
button {
|
|
111
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
112
|
+
color: white;
|
|
113
|
+
border: none;
|
|
114
|
+
padding: 12px 24px;
|
|
115
|
+
border-radius: 6px;
|
|
116
|
+
font-size: 1em;
|
|
117
|
+
font-weight: 600;
|
|
118
|
+
cursor: pointer;
|
|
119
|
+
transition: transform 0.2s, box-shadow 0.2s;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
button:hover {
|
|
123
|
+
transform: translateY(-2px);
|
|
124
|
+
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
button:active {
|
|
128
|
+
transform: translateY(0);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.button-group {
|
|
132
|
+
display: flex;
|
|
133
|
+
gap: 10px;
|
|
134
|
+
flex-wrap: wrap;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
#output {
|
|
138
|
+
background: #2d3748;
|
|
139
|
+
color: #e2e8f0;
|
|
140
|
+
padding: 20px;
|
|
141
|
+
border-radius: 6px;
|
|
142
|
+
font-family: 'Courier New', monospace;
|
|
143
|
+
font-size: 0.9em;
|
|
144
|
+
max-height: 400px;
|
|
145
|
+
overflow-y: auto;
|
|
146
|
+
white-space: pre-wrap;
|
|
147
|
+
word-wrap: break-word;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.user-list {
|
|
151
|
+
list-style: none;
|
|
152
|
+
padding: 0;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.user-item {
|
|
156
|
+
background: #f7fafc;
|
|
157
|
+
padding: 15px;
|
|
158
|
+
margin-bottom: 10px;
|
|
159
|
+
border-radius: 6px;
|
|
160
|
+
border-left: 4px solid #667eea;
|
|
161
|
+
display: flex;
|
|
162
|
+
justify-content: space-between;
|
|
163
|
+
align-items: center;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.user-info {
|
|
167
|
+
flex: 1;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.user-name {
|
|
171
|
+
font-weight: 600;
|
|
172
|
+
color: #2d3748;
|
|
173
|
+
margin-bottom: 5px;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.user-email {
|
|
177
|
+
color: #718096;
|
|
178
|
+
font-size: 0.9em;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.delete-btn {
|
|
182
|
+
background: #fc8181;
|
|
183
|
+
padding: 8px 16px;
|
|
184
|
+
font-size: 0.9em;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.delete-btn:hover {
|
|
188
|
+
background: #f56565;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.info-box {
|
|
192
|
+
background: #ebf8ff;
|
|
193
|
+
border-left: 4px solid #4299e1;
|
|
194
|
+
padding: 15px;
|
|
195
|
+
border-radius: 6px;
|
|
196
|
+
margin-bottom: 20px;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.info-box strong {
|
|
200
|
+
color: #2c5282;
|
|
201
|
+
}
|
|
202
|
+
</style>
|
|
203
|
+
</head>
|
|
204
|
+
<body>
|
|
205
|
+
<div class="container">
|
|
206
|
+
<header>
|
|
207
|
+
<h1>🚀 PluresDB Browser Demo</h1>
|
|
208
|
+
<p>Local-First Database - Zero Network Overhead</p>
|
|
209
|
+
</header>
|
|
210
|
+
|
|
211
|
+
<div class="status">
|
|
212
|
+
<span>Integration Mode: </span>
|
|
213
|
+
<span id="mode-badge" class="status-badge fallback">Network (Fallback)</span>
|
|
214
|
+
<span style="margin-left: 15px; color: #718096;">
|
|
215
|
+
<span id="node-count">0</span> nodes stored
|
|
216
|
+
</span>
|
|
217
|
+
</div>
|
|
218
|
+
|
|
219
|
+
<main>
|
|
220
|
+
<div class="info-box">
|
|
221
|
+
<strong>ℹ️ Note:</strong> This demo currently runs in <strong>network fallback mode</strong> since WASM bindings are not yet fully implemented.
|
|
222
|
+
To use this demo, start the PluresDB server with <code>npm start</code>.
|
|
223
|
+
Once WASM is complete, this will run entirely in-browser with zero network overhead!
|
|
224
|
+
</div>
|
|
225
|
+
|
|
226
|
+
<!-- Add User Section -->
|
|
227
|
+
<div class="section">
|
|
228
|
+
<h2>📝 Add User</h2>
|
|
229
|
+
<div class="form-group">
|
|
230
|
+
<label for="userId">User ID</label>
|
|
231
|
+
<input type="text" id="userId" placeholder="e.g., user:alice" value="user:alice">
|
|
232
|
+
</div>
|
|
233
|
+
<div class="form-group">
|
|
234
|
+
<label for="userName">Name</label>
|
|
235
|
+
<input type="text" id="userName" placeholder="e.g., Alice Johnson" value="Alice Johnson">
|
|
236
|
+
</div>
|
|
237
|
+
<div class="form-group">
|
|
238
|
+
<label for="userEmail">Email</label>
|
|
239
|
+
<input type="email" id="userEmail" placeholder="e.g., alice@example.com" value="alice@example.com">
|
|
240
|
+
</div>
|
|
241
|
+
<button onclick="addUser()">➕ Add User</button>
|
|
242
|
+
</div>
|
|
243
|
+
|
|
244
|
+
<!-- Actions Section -->
|
|
245
|
+
<div class="section">
|
|
246
|
+
<h2>⚡ Actions</h2>
|
|
247
|
+
<div class="button-group">
|
|
248
|
+
<button onclick="listUsers()">📋 List All Users</button>
|
|
249
|
+
<button onclick="searchUsers()">🔍 Vector Search Demo</button>
|
|
250
|
+
<button onclick="clearOutput()">🗑️ Clear Output</button>
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
|
|
254
|
+
<!-- Users List -->
|
|
255
|
+
<div class="section" id="usersSection" style="display: none;">
|
|
256
|
+
<h2>👥 Users</h2>
|
|
257
|
+
<ul id="usersList" class="user-list"></ul>
|
|
258
|
+
</div>
|
|
259
|
+
|
|
260
|
+
<!-- Output Section -->
|
|
261
|
+
<div class="section">
|
|
262
|
+
<h2>📊 Output</h2>
|
|
263
|
+
<pre id="output">Ready. Click actions above to interact with the database.</pre>
|
|
264
|
+
</div>
|
|
265
|
+
</main>
|
|
266
|
+
</div>
|
|
267
|
+
|
|
268
|
+
<script type="module">
|
|
269
|
+
// Import PluresDB Local-First API
|
|
270
|
+
// Note: In production, this would use the actual module import
|
|
271
|
+
// For now, we'll use a mock implementation that demonstrates the network fallback
|
|
272
|
+
|
|
273
|
+
class MockPluresDBLocalFirst {
|
|
274
|
+
constructor() {
|
|
275
|
+
this.baseUrl = 'http://localhost:34567';
|
|
276
|
+
this.mode = 'network';
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
getMode() {
|
|
280
|
+
return this.mode;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
async put(id, data) {
|
|
284
|
+
try {
|
|
285
|
+
const response = await fetch(`${this.baseUrl}/api/put`, {
|
|
286
|
+
method: 'POST',
|
|
287
|
+
headers: { 'Content-Type': 'application/json' },
|
|
288
|
+
body: JSON.stringify({ id, data })
|
|
289
|
+
});
|
|
290
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
291
|
+
return id;
|
|
292
|
+
} catch (error) {
|
|
293
|
+
throw new Error(`Failed to connect to PluresDB server. Please start it with 'npm start'`);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
async get(id) {
|
|
298
|
+
const response = await fetch(`${this.baseUrl}/api/get?id=${encodeURIComponent(id)}`);
|
|
299
|
+
if (!response.ok && response.status !== 404) throw new Error(`HTTP ${response.status}`);
|
|
300
|
+
return response.status === 404 ? null : await response.json();
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
async list() {
|
|
304
|
+
const response = await fetch(`${this.baseUrl}/api/list`);
|
|
305
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
306
|
+
return await response.json();
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
async delete(id) {
|
|
310
|
+
const response = await fetch(`${this.baseUrl}/api/delete?id=${encodeURIComponent(id)}`, {
|
|
311
|
+
method: 'DELETE'
|
|
312
|
+
});
|
|
313
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
async vectorSearch(query, limit) {
|
|
317
|
+
const response = await fetch(`${this.baseUrl}/api/search`, {
|
|
318
|
+
method: 'POST',
|
|
319
|
+
headers: { 'Content-Type': 'application/json' },
|
|
320
|
+
body: JSON.stringify({ query, limit })
|
|
321
|
+
});
|
|
322
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
323
|
+
return await response.json();
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Initialize database
|
|
328
|
+
const db = new MockPluresDBLocalFirst();
|
|
329
|
+
window.db = db; // Make available to inline event handlers
|
|
330
|
+
|
|
331
|
+
// Update mode badge
|
|
332
|
+
const modeBadge = document.getElementById('mode-badge');
|
|
333
|
+
modeBadge.textContent = `${db.getMode().toUpperCase()} (Fallback)`;
|
|
334
|
+
modeBadge.className = 'status-badge fallback';
|
|
335
|
+
|
|
336
|
+
// Helper functions
|
|
337
|
+
function output(data) {
|
|
338
|
+
const outputEl = document.getElementById('output');
|
|
339
|
+
if (typeof data === 'object') {
|
|
340
|
+
outputEl.textContent = JSON.stringify(data, null, 2);
|
|
341
|
+
} else {
|
|
342
|
+
outputEl.textContent = data;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function updateNodeCount(count) {
|
|
347
|
+
document.getElementById('node-count').textContent = count;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Action: Add User
|
|
351
|
+
window.addUser = async function() {
|
|
352
|
+
try {
|
|
353
|
+
const id = document.getElementById('userId').value;
|
|
354
|
+
const name = document.getElementById('userName').value;
|
|
355
|
+
const email = document.getElementById('userEmail').value;
|
|
356
|
+
|
|
357
|
+
if (!id || !name || !email) {
|
|
358
|
+
output('❌ Please fill in all fields');
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
await db.put(id, {
|
|
363
|
+
type: 'User',
|
|
364
|
+
name,
|
|
365
|
+
email,
|
|
366
|
+
createdAt: new Date().toISOString()
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
output(`✅ User added successfully!\n\nID: ${id}\nName: ${name}\nEmail: ${email}`);
|
|
370
|
+
|
|
371
|
+
// Clear form
|
|
372
|
+
document.getElementById('userId').value = `user:${Date.now()}`;
|
|
373
|
+
document.getElementById('userName').value = '';
|
|
374
|
+
document.getElementById('userEmail').value = '';
|
|
375
|
+
|
|
376
|
+
// Refresh user list if visible
|
|
377
|
+
const usersSection = document.getElementById('usersSection');
|
|
378
|
+
if (usersSection.style.display !== 'none') {
|
|
379
|
+
await listUsers();
|
|
380
|
+
}
|
|
381
|
+
} catch (error) {
|
|
382
|
+
output(`❌ Error: ${error.message}`);
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
// Action: List Users
|
|
387
|
+
window.listUsers = async function() {
|
|
388
|
+
try {
|
|
389
|
+
const nodes = await db.list();
|
|
390
|
+
const users = nodes.filter(node => node.data?.type === 'User');
|
|
391
|
+
|
|
392
|
+
updateNodeCount(nodes.length);
|
|
393
|
+
|
|
394
|
+
if (users.length === 0) {
|
|
395
|
+
output('📭 No users found. Add some users first!');
|
|
396
|
+
document.getElementById('usersSection').style.display = 'none';
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Show users in the dedicated section
|
|
401
|
+
const usersList = document.getElementById('usersList');
|
|
402
|
+
usersList.innerHTML = '';
|
|
403
|
+
|
|
404
|
+
users.forEach(user => {
|
|
405
|
+
const li = document.createElement('li');
|
|
406
|
+
li.className = 'user-item';
|
|
407
|
+
li.innerHTML = `
|
|
408
|
+
<div class="user-info">
|
|
409
|
+
<div class="user-name">${user.data.name}</div>
|
|
410
|
+
<div class="user-email">${user.data.email}</div>
|
|
411
|
+
</div>
|
|
412
|
+
<button class="delete-btn" onclick="deleteUser('${user.id}')">Delete</button>
|
|
413
|
+
`;
|
|
414
|
+
usersList.appendChild(li);
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
document.getElementById('usersSection').style.display = 'block';
|
|
418
|
+
output(`✅ Found ${users.length} user(s)\n${nodes.length} total nodes in database`);
|
|
419
|
+
} catch (error) {
|
|
420
|
+
output(`❌ Error: ${error.message}`);
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
// Action: Delete User
|
|
425
|
+
window.deleteUser = async function(id) {
|
|
426
|
+
try {
|
|
427
|
+
await db.delete(id);
|
|
428
|
+
output(`✅ User ${id} deleted successfully`);
|
|
429
|
+
await listUsers();
|
|
430
|
+
} catch (error) {
|
|
431
|
+
output(`❌ Error: ${error.message}`);
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
// Action: Vector Search Demo
|
|
436
|
+
window.searchUsers = async function() {
|
|
437
|
+
try {
|
|
438
|
+
const results = await db.vectorSearch('Find users', 10);
|
|
439
|
+
output({
|
|
440
|
+
query: 'Find users',
|
|
441
|
+
results: results.length,
|
|
442
|
+
data: results
|
|
443
|
+
});
|
|
444
|
+
} catch (error) {
|
|
445
|
+
output(`❌ Error: ${error.message}\n\nNote: Vector search requires the server to be running.`);
|
|
446
|
+
}
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
// Action: Clear Output
|
|
450
|
+
window.clearOutput = function() {
|
|
451
|
+
output('Output cleared.');
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
// Initialize - try to get node count
|
|
455
|
+
(async function() {
|
|
456
|
+
try {
|
|
457
|
+
const nodes = await db.list();
|
|
458
|
+
updateNodeCount(nodes.length);
|
|
459
|
+
output(`✅ Connected to PluresDB server\n${nodes.length} nodes in database\n\nMode: ${db.getMode()} (fallback)`);
|
|
460
|
+
} catch (error) {
|
|
461
|
+
output(`⚠️ PluresDB server not running\n\nPlease start it with: npm start\n\nOnce started, refresh this page.`);
|
|
462
|
+
}
|
|
463
|
+
})();
|
|
464
|
+
</script>
|
|
465
|
+
</body>
|
|
466
|
+
</html>
|