relayx-webjs 1.0.5 → 1.1.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/.claude/settings.local.json +10 -0
- package/CHANGELOG.md +3 -0
- package/LICENSE +1 -12
- package/README.md +133 -183
- package/example/stand-alone/example_chat.js +6 -3
- package/package.json +6 -3
- package/realtime/kv_storage.js +195 -0
- package/realtime/models/message.js +26 -0
- package/realtime/queue.js +660 -0
- package/realtime/realtime.js +147 -94
- package/realtime/utils.js +113 -0
- package/tests/test_kv.js +679 -0
- package/tests/test_queue.js +568 -0
package/tests/test_kv.js
ADDED
|
@@ -0,0 +1,679 @@
|
|
|
1
|
+
import { Realtime } from "../realtime/realtime.js";
|
|
2
|
+
import { KVStore } from "../realtime/kv_storage.js";
|
|
3
|
+
import { test, before, after } from 'node:test';
|
|
4
|
+
import assert from 'node:assert';
|
|
5
|
+
|
|
6
|
+
let realtime;
|
|
7
|
+
let kvStore;
|
|
8
|
+
const testNamespace = 'test-kv-store';
|
|
9
|
+
|
|
10
|
+
before(async () => {
|
|
11
|
+
// Initialize Realtime connection for KV testing
|
|
12
|
+
realtime = new Realtime({
|
|
13
|
+
api_key: process.env.AUTH_JWT,
|
|
14
|
+
secret: process.env.AUTH_SECRET
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
await realtime.init({
|
|
18
|
+
staging: true,
|
|
19
|
+
opts: {
|
|
20
|
+
debug: false
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
await realtime.connect();
|
|
25
|
+
|
|
26
|
+
// Small delay to ensure connection is fully established
|
|
27
|
+
await new Promise(resolve => setTimeout(resolve, 2500));
|
|
28
|
+
|
|
29
|
+
// Create KV store instance using Realtime's initKVStore method
|
|
30
|
+
kvStore = await realtime.initKVStore();
|
|
31
|
+
|
|
32
|
+
if (!kvStore) {
|
|
33
|
+
throw new Error("Failed to initialize KV store");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Verify KV store is working
|
|
37
|
+
const testInit = await kvStore.testIsKvStoreInitialized();
|
|
38
|
+
if (!testInit) {
|
|
39
|
+
throw new Error("KV store not properly initialized");
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
after(async () => {
|
|
44
|
+
// Clean up: delete all test keys
|
|
45
|
+
try {
|
|
46
|
+
const keys = await kvStore.keys();
|
|
47
|
+
for (const key of keys) {
|
|
48
|
+
await kvStore.delete(key);
|
|
49
|
+
}
|
|
50
|
+
} catch (err) {
|
|
51
|
+
console.error("Cleanup error:", err);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
realtime.close();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Constructor and Initialization Tests
|
|
58
|
+
test("Constructor - successful instantiation", () => {
|
|
59
|
+
const kv = new KVStore({
|
|
60
|
+
namespace: 'test',
|
|
61
|
+
jetstream: realtime.testGetJetstream()
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
assert.notStrictEqual(kv, null);
|
|
65
|
+
assert.notStrictEqual(kv, undefined);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("Test helper - testGetNamespace()", () => {
|
|
69
|
+
const namespace = kvStore.testGetNamespace();
|
|
70
|
+
assert.notStrictEqual(namespace, undefined);
|
|
71
|
+
assert.notStrictEqual(namespace, null);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("Test helper - testIsKvStoreInitialized()", () => {
|
|
75
|
+
const isInitialized = kvStore.testIsKvStoreInitialized();
|
|
76
|
+
assert.strictEqual(isInitialized, true);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("init() - validates namespace", async () => {
|
|
80
|
+
const kv = new KVStore({
|
|
81
|
+
namespace: null,
|
|
82
|
+
jetstream: realtime.testGetJetstream()
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
await assert.rejects(async () => {
|
|
86
|
+
await kv.init();
|
|
87
|
+
},
|
|
88
|
+
new Error("$namespace cannot be null / undefined / empty"),
|
|
89
|
+
"Expected error was not thrown");
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("init() - validates empty namespace", async () => {
|
|
93
|
+
const kv = new KVStore({
|
|
94
|
+
namespace: "",
|
|
95
|
+
jetstream: realtime.testGetJetstream()
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
await assert.rejects(async () => {
|
|
99
|
+
await kv.init();
|
|
100
|
+
},
|
|
101
|
+
new Error("$namespace cannot be null / undefined / empty"),
|
|
102
|
+
"Expected error was not thrown");
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("Test helper - testValidateInput()", () => {
|
|
106
|
+
const kv = new KVStore({
|
|
107
|
+
namespace: "",
|
|
108
|
+
jetstream: realtime.testGetJetstream()
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const validateInput = kv.testValidateInput();
|
|
112
|
+
|
|
113
|
+
assert.throws(() => {
|
|
114
|
+
validateInput();
|
|
115
|
+
},
|
|
116
|
+
new Error("$namespace cannot be null / undefined / empty"),
|
|
117
|
+
"Expected error was not thrown");
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Key Validation Tests
|
|
121
|
+
test("Test helper - testValidateKey() with null", () => {
|
|
122
|
+
const validateKey = kvStore.testValidateKey();
|
|
123
|
+
|
|
124
|
+
assert.throws(() => {
|
|
125
|
+
validateKey(null);
|
|
126
|
+
},
|
|
127
|
+
new Error("$key cannot be null / undefined"),
|
|
128
|
+
"Expected error for null key");
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test("Test helper - testValidateKey() with undefined", () => {
|
|
132
|
+
const validateKey = kvStore.testValidateKey();
|
|
133
|
+
|
|
134
|
+
assert.throws(() => {
|
|
135
|
+
validateKey(undefined);
|
|
136
|
+
},
|
|
137
|
+
new Error("$key cannot be null / undefined"),
|
|
138
|
+
"Expected error for undefined key");
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test("Test helper - testValidateKey() with non-string", () => {
|
|
142
|
+
const validateKey = kvStore.testValidateKey();
|
|
143
|
+
|
|
144
|
+
assert.throws(() => {
|
|
145
|
+
validateKey(123);
|
|
146
|
+
},
|
|
147
|
+
new Error("$key cannot be a string"),
|
|
148
|
+
"Expected error for number key");
|
|
149
|
+
|
|
150
|
+
assert.throws(() => {
|
|
151
|
+
validateKey({});
|
|
152
|
+
},
|
|
153
|
+
new Error("$key cannot be a string"),
|
|
154
|
+
"Expected error for object key");
|
|
155
|
+
|
|
156
|
+
assert.throws(() => {
|
|
157
|
+
validateKey([]);
|
|
158
|
+
},
|
|
159
|
+
new Error("$key cannot be a string"),
|
|
160
|
+
"Expected error for array key");
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test("Test helper - testValidateKey() with empty string", () => {
|
|
164
|
+
const validateKey = kvStore.testValidateKey();
|
|
165
|
+
|
|
166
|
+
assert.throws(() => {
|
|
167
|
+
validateKey("");
|
|
168
|
+
},
|
|
169
|
+
new Error("$key cannot be empty"),
|
|
170
|
+
"Expected error for empty key");
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test("Test helper - testValidateKey() with valid string", () => {
|
|
174
|
+
const validateKey = kvStore.testValidateKey();
|
|
175
|
+
|
|
176
|
+
// Should not throw
|
|
177
|
+
validateKey("valid-key");
|
|
178
|
+
validateKey("user.123");
|
|
179
|
+
validateKey("test_key");
|
|
180
|
+
validateKey("user/profile/data");
|
|
181
|
+
validateKey("config=value");
|
|
182
|
+
assert.ok(true);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test("Test helper - testValidateKey() with invalid characters", () => {
|
|
186
|
+
const validateKey = kvStore.testValidateKey();
|
|
187
|
+
|
|
188
|
+
// Should throw for invalid characters
|
|
189
|
+
assert.throws(() => {
|
|
190
|
+
validateKey("user:123");
|
|
191
|
+
},
|
|
192
|
+
new Error("$key can only contain alphanumeric characters and the following: _ - . = /"),
|
|
193
|
+
"Expected error for colon in key");
|
|
194
|
+
|
|
195
|
+
assert.throws(() => {
|
|
196
|
+
validateKey("user@domain");
|
|
197
|
+
},
|
|
198
|
+
new Error("$key can only contain alphanumeric characters and the following: _ - . = /"),
|
|
199
|
+
"Expected error for @ in key");
|
|
200
|
+
|
|
201
|
+
assert.throws(() => {
|
|
202
|
+
validateKey("key with spaces");
|
|
203
|
+
},
|
|
204
|
+
new Error("$key can only contain alphanumeric characters and the following: _ - . = /"),
|
|
205
|
+
"Expected error for spaces in key");
|
|
206
|
+
|
|
207
|
+
assert.throws(() => {
|
|
208
|
+
validateKey("key#hash");
|
|
209
|
+
},
|
|
210
|
+
new Error("$key can only contain alphanumeric characters and the following: _ - . = /"),
|
|
211
|
+
"Expected error for hash in key");
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// Value Validation Tests
|
|
215
|
+
test("Test helper - testValidateValue() with valid types", () => {
|
|
216
|
+
const validateValue = kvStore.testValidateValue();
|
|
217
|
+
|
|
218
|
+
// Should not throw for valid types
|
|
219
|
+
validateValue(null);
|
|
220
|
+
validateValue("string");
|
|
221
|
+
validateValue(42);
|
|
222
|
+
validateValue(3.14);
|
|
223
|
+
validateValue(true);
|
|
224
|
+
validateValue(false);
|
|
225
|
+
validateValue([1, 2, 3]);
|
|
226
|
+
validateValue({ foo: "bar" });
|
|
227
|
+
assert.ok(true);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
test("Test helper - testValidateValue() - currently allows functions and symbols", () => {
|
|
231
|
+
const validateValue = kvStore.testValidateValue();
|
|
232
|
+
|
|
233
|
+
// Note: Current implementation allows functions and symbols due to #isJSON implementation
|
|
234
|
+
// Not throwing errors is expected behavior
|
|
235
|
+
validateValue(() => {});
|
|
236
|
+
validateValue(Symbol('test'));
|
|
237
|
+
assert.ok(true);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
// JSON Validation Tests
|
|
241
|
+
test("Test helper - testIsJSON()", () => {
|
|
242
|
+
const isJSON = kvStore.testIsJSON();
|
|
243
|
+
|
|
244
|
+
assert.strictEqual(isJSON({ foo: "bar" }), true);
|
|
245
|
+
assert.strictEqual(isJSON({ nested: { obj: true } }), true);
|
|
246
|
+
assert.strictEqual(isJSON([1, 2, 3]), true);
|
|
247
|
+
assert.strictEqual(isJSON("string"), true);
|
|
248
|
+
assert.strictEqual(isJSON(123), true);
|
|
249
|
+
assert.strictEqual(isJSON(null), true);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
// Real KV Operations Tests
|
|
253
|
+
test("put() - validates key parameter", async () => {
|
|
254
|
+
await assert.rejects(async () => {
|
|
255
|
+
await kvStore.put(null, "value");
|
|
256
|
+
},
|
|
257
|
+
new Error("$key cannot be null / undefined"),
|
|
258
|
+
"Expected error for null key");
|
|
259
|
+
|
|
260
|
+
await assert.rejects(async () => {
|
|
261
|
+
await kvStore.put(undefined, "value");
|
|
262
|
+
},
|
|
263
|
+
new Error("$key cannot be null / undefined"),
|
|
264
|
+
"Expected error for undefined key");
|
|
265
|
+
|
|
266
|
+
await assert.rejects(async () => {
|
|
267
|
+
await kvStore.put("", "value");
|
|
268
|
+
},
|
|
269
|
+
new Error("$key cannot be empty"),
|
|
270
|
+
"Expected error for empty key");
|
|
271
|
+
|
|
272
|
+
await assert.rejects(async () => {
|
|
273
|
+
await kvStore.put(123, "value");
|
|
274
|
+
},
|
|
275
|
+
new Error("$key cannot be a string"),
|
|
276
|
+
"Expected error for non-string key");
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
test("put() - validation allows functions and symbols but storage may fail", async () => {
|
|
280
|
+
// Note: Current implementation's validation allows functions and symbols due to #isJSON implementation
|
|
281
|
+
// But actual storage to NATS will fail during JSON.stringify
|
|
282
|
+
// We're just testing that validation doesn't throw - not that storage works
|
|
283
|
+
const validateValue = kvStore.testValidateValue();
|
|
284
|
+
|
|
285
|
+
// These pass validation
|
|
286
|
+
validateValue(() => {});
|
|
287
|
+
validateValue(Symbol('test'));
|
|
288
|
+
|
|
289
|
+
assert.ok(true);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
test("put() and get() - string value", async () => {
|
|
293
|
+
// Create fresh KV store for this test
|
|
294
|
+
const kvStore = await realtime.initKVStore();
|
|
295
|
+
|
|
296
|
+
console.log(kvStore)
|
|
297
|
+
|
|
298
|
+
const key = "test.string";
|
|
299
|
+
const value = "Hello World!";
|
|
300
|
+
|
|
301
|
+
await kvStore.put(key, value);
|
|
302
|
+
const result = await kvStore.get(key);
|
|
303
|
+
|
|
304
|
+
assert.strictEqual(result, value);
|
|
305
|
+
|
|
306
|
+
// Cleanup
|
|
307
|
+
await kvStore.delete(key);
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
test("put() and get() - number value", async () => {
|
|
311
|
+
// Create fresh KV store for this test
|
|
312
|
+
const kvStore = await realtime.initKVStore();
|
|
313
|
+
|
|
314
|
+
const key = "test.number";
|
|
315
|
+
const value = 42;
|
|
316
|
+
|
|
317
|
+
await kvStore.put(key, value);
|
|
318
|
+
const result = await kvStore.get(key);
|
|
319
|
+
|
|
320
|
+
assert.strictEqual(result, value);
|
|
321
|
+
|
|
322
|
+
await kvStore.delete(key);
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
test("put() and get() - boolean value", async () => {
|
|
326
|
+
// Create fresh KV store for this test
|
|
327
|
+
const kvStore = await realtime.initKVStore();
|
|
328
|
+
|
|
329
|
+
const key = "test.boolean";
|
|
330
|
+
const value = true;
|
|
331
|
+
|
|
332
|
+
await kvStore.put(key, value);
|
|
333
|
+
const result = await kvStore.get(key);
|
|
334
|
+
|
|
335
|
+
assert.strictEqual(result, value);
|
|
336
|
+
|
|
337
|
+
await kvStore.delete(key);
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
test("put() and get() - null value", async () => {
|
|
341
|
+
// Create fresh KV store for this test
|
|
342
|
+
const kvStore = await realtime.initKVStore();
|
|
343
|
+
|
|
344
|
+
const key = "test.null";
|
|
345
|
+
const value = null;
|
|
346
|
+
|
|
347
|
+
await kvStore.put(key, value);
|
|
348
|
+
const result = await kvStore.get(key);
|
|
349
|
+
|
|
350
|
+
assert.strictEqual(result, value);
|
|
351
|
+
|
|
352
|
+
await kvStore.delete(key);
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
test("put() and get() - array value", async () => {
|
|
356
|
+
// Create fresh KV store for this test
|
|
357
|
+
const kvStore = await realtime.initKVStore();
|
|
358
|
+
|
|
359
|
+
const key = "test.array";
|
|
360
|
+
const value = [1, 2, 3, "four", { five: 5 }];
|
|
361
|
+
|
|
362
|
+
await kvStore.put(key, value);
|
|
363
|
+
const result = await kvStore.get(key);
|
|
364
|
+
|
|
365
|
+
assert.deepStrictEqual(result, value);
|
|
366
|
+
|
|
367
|
+
await kvStore.delete(key);
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
test("put() and get() - object value", async () => {
|
|
371
|
+
// Create fresh KV store for this test
|
|
372
|
+
const kvStore = await realtime.initKVStore();
|
|
373
|
+
|
|
374
|
+
const key = "test.object";
|
|
375
|
+
const value = {
|
|
376
|
+
name: "Alice",
|
|
377
|
+
age: 30,
|
|
378
|
+
active: true,
|
|
379
|
+
tags: ["user", "admin"]
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
await kvStore.put(key, value);
|
|
383
|
+
const result = await kvStore.get(key);
|
|
384
|
+
|
|
385
|
+
assert.deepStrictEqual(result, value);
|
|
386
|
+
|
|
387
|
+
await kvStore.delete(key);
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
test("put() - update existing key", async () => {
|
|
391
|
+
// Create fresh KV store for this test
|
|
392
|
+
const kvStore = await realtime.initKVStore();
|
|
393
|
+
|
|
394
|
+
const key = "test.update";
|
|
395
|
+
|
|
396
|
+
await kvStore.put(key, "initial value");
|
|
397
|
+
let result = await kvStore.get(key);
|
|
398
|
+
assert.strictEqual(result, "initial value");
|
|
399
|
+
|
|
400
|
+
await kvStore.put(key, "updated value");
|
|
401
|
+
result = await kvStore.get(key);
|
|
402
|
+
assert.strictEqual(result, "updated value");
|
|
403
|
+
|
|
404
|
+
await kvStore.delete(key);
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
test("get() - validates key parameter", async () => {
|
|
408
|
+
await assert.rejects(async () => {
|
|
409
|
+
await kvStore.get(null);
|
|
410
|
+
},
|
|
411
|
+
new Error("$key cannot be null / undefined"),
|
|
412
|
+
"Expected error for null key");
|
|
413
|
+
|
|
414
|
+
await assert.rejects(async () => {
|
|
415
|
+
await kvStore.get(undefined);
|
|
416
|
+
},
|
|
417
|
+
new Error("$key cannot be null / undefined"),
|
|
418
|
+
"Expected error for undefined key");
|
|
419
|
+
|
|
420
|
+
await assert.rejects(async () => {
|
|
421
|
+
await kvStore.get("");
|
|
422
|
+
},
|
|
423
|
+
new Error("$key cannot be empty"),
|
|
424
|
+
"Expected error for empty key");
|
|
425
|
+
|
|
426
|
+
await assert.rejects(async () => {
|
|
427
|
+
await kvStore.get(123);
|
|
428
|
+
},
|
|
429
|
+
new Error("$key cannot be a string"),
|
|
430
|
+
"Expected error for non-string key");
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
test("get() - returns null for non-existent key", async () => {
|
|
434
|
+
const result = await kvStore.get("non-existent-key-xyz");
|
|
435
|
+
assert.strictEqual(result, null);
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
test("delete() - validates key parameter", async () => {
|
|
439
|
+
await assert.rejects(async () => {
|
|
440
|
+
await kvStore.delete(null);
|
|
441
|
+
},
|
|
442
|
+
new Error("$key cannot be null / undefined"),
|
|
443
|
+
"Expected error for null key");
|
|
444
|
+
|
|
445
|
+
await assert.rejects(async () => {
|
|
446
|
+
await kvStore.delete(undefined);
|
|
447
|
+
},
|
|
448
|
+
new Error("$key cannot be null / undefined"),
|
|
449
|
+
"Expected error for undefined key");
|
|
450
|
+
|
|
451
|
+
await assert.rejects(async () => {
|
|
452
|
+
await kvStore.delete("");
|
|
453
|
+
},
|
|
454
|
+
new Error("$key cannot be empty"),
|
|
455
|
+
"Expected error for empty key");
|
|
456
|
+
|
|
457
|
+
await assert.rejects(async () => {
|
|
458
|
+
await kvStore.delete(123);
|
|
459
|
+
},
|
|
460
|
+
new Error("$key cannot be a string"),
|
|
461
|
+
"Expected error for non-string key");
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
test("delete() - successfully deletes key", async () => {
|
|
465
|
+
// Create fresh KV store for this test
|
|
466
|
+
const kvStore = await realtime.initKVStore();
|
|
467
|
+
|
|
468
|
+
const key = "test.delete";
|
|
469
|
+
|
|
470
|
+
await kvStore.put(key, "to be deleted");
|
|
471
|
+
let result = await kvStore.get(key);
|
|
472
|
+
assert.strictEqual(result, "to be deleted");
|
|
473
|
+
|
|
474
|
+
await kvStore.delete(key);
|
|
475
|
+
result = await kvStore.get(key);
|
|
476
|
+
assert.strictEqual(result, null);
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
test("delete() - deleting non-existent key does not throw", async () => {
|
|
480
|
+
// Create fresh KV store for this test
|
|
481
|
+
const kvStore = await realtime.initKVStore();
|
|
482
|
+
|
|
483
|
+
// Should not throw error
|
|
484
|
+
await kvStore.delete("non-existent-key-to-delete");
|
|
485
|
+
assert.ok(true);
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
test("keys() - returns array of keys", async () => {
|
|
489
|
+
// Create fresh KV store for this test
|
|
490
|
+
const kvStore = await realtime.initKVStore();
|
|
491
|
+
|
|
492
|
+
// Put multiple keys
|
|
493
|
+
await kvStore.put("keys.test1", "value1");
|
|
494
|
+
await kvStore.put("keys.test2", "value2");
|
|
495
|
+
await kvStore.put("keys.test3", "value3");
|
|
496
|
+
|
|
497
|
+
const keys = await kvStore.keys();
|
|
498
|
+
|
|
499
|
+
assert.strictEqual(Array.isArray(keys), true);
|
|
500
|
+
assert.ok(keys.includes("keys.test1"));
|
|
501
|
+
assert.ok(keys.includes("keys.test2"));
|
|
502
|
+
assert.ok(keys.includes("keys.test3"));
|
|
503
|
+
|
|
504
|
+
// Cleanup
|
|
505
|
+
await kvStore.delete("keys.test1");
|
|
506
|
+
await kvStore.delete("keys.test2");
|
|
507
|
+
await kvStore.delete("keys.test3");
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
test("keys() - returns empty array when no keys exist", async () => {
|
|
511
|
+
// Create fresh KV store for this test
|
|
512
|
+
const kvStore = await realtime.initKVStore();
|
|
513
|
+
|
|
514
|
+
// Clean up all keys first
|
|
515
|
+
const allKeys = await kvStore.keys();
|
|
516
|
+
for (const key of allKeys) {
|
|
517
|
+
await kvStore.delete(key);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
const keys = await kvStore.keys();
|
|
521
|
+
assert.strictEqual(Array.isArray(keys), true);
|
|
522
|
+
assert.strictEqual(keys.length, 0);
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
// Integration Test - Full Workflow
|
|
526
|
+
test("Integration - full KV workflow", async () => {
|
|
527
|
+
// Create fresh KV store for this test
|
|
528
|
+
const kvStore = await realtime.initKVStore();
|
|
529
|
+
|
|
530
|
+
const prefix = "integration.";
|
|
531
|
+
|
|
532
|
+
// 1. Put multiple keys with different value types
|
|
533
|
+
await kvStore.put(`${prefix}user.1`, { name: "Alice", age: 30 });
|
|
534
|
+
await kvStore.put(`${prefix}user.2`, { name: "Bob", age: 25 });
|
|
535
|
+
await kvStore.put(`${prefix}counter`, 42);
|
|
536
|
+
await kvStore.put(`${prefix}active`, true);
|
|
537
|
+
await kvStore.put(`${prefix}tags`, ["test", "integration"]);
|
|
538
|
+
|
|
539
|
+
// 2. Get all keys
|
|
540
|
+
const allKeys = await kvStore.keys();
|
|
541
|
+
assert.ok(allKeys.includes(`${prefix}user.1`));
|
|
542
|
+
assert.ok(allKeys.includes(`${prefix}user.2`));
|
|
543
|
+
assert.ok(allKeys.includes(`${prefix}counter`));
|
|
544
|
+
assert.ok(allKeys.includes(`${prefix}active`));
|
|
545
|
+
assert.ok(allKeys.includes(`${prefix}tags`));
|
|
546
|
+
|
|
547
|
+
// 3. Retrieve and verify values
|
|
548
|
+
const user1 = await kvStore.get(`${prefix}user.1`);
|
|
549
|
+
assert.deepStrictEqual(user1, { name: "Alice", age: 30 });
|
|
550
|
+
|
|
551
|
+
const counter = await kvStore.get(`${prefix}counter`);
|
|
552
|
+
assert.strictEqual(counter, 42);
|
|
553
|
+
|
|
554
|
+
const active = await kvStore.get(`${prefix}active`);
|
|
555
|
+
assert.strictEqual(active, true);
|
|
556
|
+
|
|
557
|
+
const tags = await kvStore.get(`${prefix}tags`);
|
|
558
|
+
assert.deepStrictEqual(tags, ["test", "integration"]);
|
|
559
|
+
|
|
560
|
+
// 4. Update a value
|
|
561
|
+
await kvStore.put(`${prefix}user.1`, { name: "Alice", age: 31 });
|
|
562
|
+
const updatedUser = await kvStore.get(`${prefix}user.1`);
|
|
563
|
+
assert.strictEqual(updatedUser.age, 31);
|
|
564
|
+
|
|
565
|
+
// 5. Delete keys
|
|
566
|
+
await kvStore.delete(`${prefix}user.2`);
|
|
567
|
+
const deletedUser = await kvStore.get(`${prefix}user.2`);
|
|
568
|
+
assert.strictEqual(deletedUser, null);
|
|
569
|
+
|
|
570
|
+
// 6. Verify remaining keys
|
|
571
|
+
const remainingKeys = await kvStore.keys();
|
|
572
|
+
assert.ok(remainingKeys.includes(`${prefix}user.1`));
|
|
573
|
+
assert.ok(!remainingKeys.includes(`${prefix}user.2`));
|
|
574
|
+
|
|
575
|
+
// Cleanup
|
|
576
|
+
await kvStore.delete(`${prefix}user.1`);
|
|
577
|
+
await kvStore.delete(`${prefix}counter`);
|
|
578
|
+
await kvStore.delete(`${prefix}active`);
|
|
579
|
+
await kvStore.delete(`${prefix}tags`);
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
// Edge Cases
|
|
583
|
+
test("Edge case - put and get with special characters in key", async () => {
|
|
584
|
+
// Create fresh KV store for this test
|
|
585
|
+
const kvStore = await realtime.initKVStore();
|
|
586
|
+
|
|
587
|
+
const key = "test.special-chars_123";
|
|
588
|
+
const value = { data: "special" };
|
|
589
|
+
|
|
590
|
+
await kvStore.put(key, value);
|
|
591
|
+
const result = await kvStore.get(key);
|
|
592
|
+
|
|
593
|
+
assert.deepStrictEqual(result, value);
|
|
594
|
+
|
|
595
|
+
await kvStore.delete(key);
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
test("Edge case - put and get with nested objects", async () => {
|
|
599
|
+
// Create fresh KV store for this test
|
|
600
|
+
const kvStore = await realtime.initKVStore();
|
|
601
|
+
|
|
602
|
+
const key = "test.nested";
|
|
603
|
+
const value = {
|
|
604
|
+
level1: {
|
|
605
|
+
level2: {
|
|
606
|
+
level3: {
|
|
607
|
+
deep: "value"
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
|
|
613
|
+
await kvStore.put(key, value);
|
|
614
|
+
const result = await kvStore.get(key);
|
|
615
|
+
|
|
616
|
+
assert.deepStrictEqual(result, value);
|
|
617
|
+
|
|
618
|
+
await kvStore.delete(key);
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
test("Edge case - put and get with empty object", async () => {
|
|
622
|
+
// Create fresh KV store for this test
|
|
623
|
+
const kvStore = await realtime.initKVStore();
|
|
624
|
+
|
|
625
|
+
const key = "test.empty-object";
|
|
626
|
+
const value = {};
|
|
627
|
+
|
|
628
|
+
await kvStore.put(key, value);
|
|
629
|
+
const result = await kvStore.get(key);
|
|
630
|
+
|
|
631
|
+
assert.deepStrictEqual(result, value);
|
|
632
|
+
|
|
633
|
+
await kvStore.delete(key);
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
test("Edge case - put and get with empty array", async () => {
|
|
637
|
+
// Create fresh KV store for this test
|
|
638
|
+
const kvStore = await realtime.initKVStore();
|
|
639
|
+
|
|
640
|
+
const key = "test.empty-array";
|
|
641
|
+
const value = [];
|
|
642
|
+
|
|
643
|
+
await kvStore.put(key, value);
|
|
644
|
+
const result = await kvStore.get(key);
|
|
645
|
+
|
|
646
|
+
assert.deepStrictEqual(result, value);
|
|
647
|
+
|
|
648
|
+
await kvStore.delete(key);
|
|
649
|
+
});
|
|
650
|
+
|
|
651
|
+
test("Edge case - put and get with zero", async () => {
|
|
652
|
+
// Create fresh KV store for this test
|
|
653
|
+
const kvStore = await realtime.initKVStore();
|
|
654
|
+
|
|
655
|
+
const key = "test.zero";
|
|
656
|
+
const value = 0;
|
|
657
|
+
|
|
658
|
+
await kvStore.put(key, value);
|
|
659
|
+
const result = await kvStore.get(key);
|
|
660
|
+
|
|
661
|
+
assert.strictEqual(result, value);
|
|
662
|
+
|
|
663
|
+
await kvStore.delete(key);
|
|
664
|
+
});
|
|
665
|
+
|
|
666
|
+
test("Edge case - put and get with false", async () => {
|
|
667
|
+
// Create fresh KV store for this test
|
|
668
|
+
const kvStore = await realtime.initKVStore();
|
|
669
|
+
|
|
670
|
+
const key = "test.false";
|
|
671
|
+
const value = false;
|
|
672
|
+
|
|
673
|
+
await kvStore.put(key, value);
|
|
674
|
+
const result = await kvStore.get(key);
|
|
675
|
+
|
|
676
|
+
assert.strictEqual(result, value);
|
|
677
|
+
|
|
678
|
+
await kvStore.delete(key);
|
|
679
|
+
});
|