s3db.js 7.4.1 → 7.5.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/PLUGINS.md +3 -3
- package/dist/s3db.cjs.js +55 -21
- package/dist/s3db.cjs.min.js +1 -1
- package/dist/s3db.es.js +55 -21
- package/dist/s3db.es.min.js +1 -1
- package/dist/s3db.iife.js +55 -21
- package/dist/s3db.iife.min.js +1 -1
- package/mcp/server.js +1 -1
- package/package.json +1 -1
- package/src/database.class.js +22 -1
- package/src/plugins/cache.plugin.js +4 -4
- package/src/plugins/replicator.plugin.js +19 -19
- package/src/resource.class.js +31 -2
package/PLUGINS.md
CHANGED
|
@@ -81,7 +81,7 @@ await users.list(); // Cached result
|
|
|
81
81
|
|
|
82
82
|
| Parameter | Type | Default | Description |
|
|
83
83
|
|-----------|------|---------|-------------|
|
|
84
|
-
| `
|
|
84
|
+
| `driver` | string | `'s3'` | Cache driver: `'memory'` or `'s3'` |
|
|
85
85
|
| `ttl` | number | `300000` | Time-to-live in milliseconds (5 minutes) |
|
|
86
86
|
| `maxSize` | number | `1000` | Maximum number of items in cache (memory driver) |
|
|
87
87
|
| `includePartitions` | boolean | `true` | Include partition values in cache keys |
|
|
@@ -113,7 +113,7 @@ import { S3db, CachePlugin } from 's3db.js';
|
|
|
113
113
|
const s3db = new S3db({
|
|
114
114
|
connectionString: "s3://ACCESS_KEY:SECRET_KEY@BUCKET_NAME/databases/myapp",
|
|
115
115
|
plugins: [new CachePlugin({
|
|
116
|
-
|
|
116
|
+
driver: 'memory',
|
|
117
117
|
ttl: 600000, // 10 minutes
|
|
118
118
|
maxSize: 500
|
|
119
119
|
})]
|
|
@@ -3887,7 +3887,7 @@ const s3db = new S3db({
|
|
|
3887
3887
|
plugins: [
|
|
3888
3888
|
// Performance optimization
|
|
3889
3889
|
new CachePlugin({
|
|
3890
|
-
|
|
3890
|
+
driver: 'memory',
|
|
3891
3891
|
ttl: 600000
|
|
3892
3892
|
}),
|
|
3893
3893
|
|
package/dist/s3db.cjs.js
CHANGED
|
@@ -7610,11 +7610,11 @@ class CachePlugin extends plugin_class_default {
|
|
|
7610
7610
|
await super.setup(database);
|
|
7611
7611
|
}
|
|
7612
7612
|
async onSetup() {
|
|
7613
|
-
if (this.config.driver) {
|
|
7613
|
+
if (this.config.driver && typeof this.config.driver === "object") {
|
|
7614
7614
|
this.driver = this.config.driver;
|
|
7615
|
-
} else if (this.config.
|
|
7615
|
+
} else if (this.config.driver === "memory") {
|
|
7616
7616
|
this.driver = new memory_cache_class_default(this.config.memoryOptions || {});
|
|
7617
|
-
} else if (this.config.
|
|
7617
|
+
} else if (this.config.driver === "filesystem") {
|
|
7618
7618
|
if (this.config.partitionAware) {
|
|
7619
7619
|
this.driver = new PartitionAwareFilesystemCache({
|
|
7620
7620
|
partitionStrategy: this.config.partitionStrategy,
|
|
@@ -11196,6 +11196,14 @@ class Resource extends EventEmitter {
|
|
|
11196
11196
|
this.passphrase = passphrase ?? "secret";
|
|
11197
11197
|
this.versioningEnabled = versioningEnabled;
|
|
11198
11198
|
this.idGenerator = this.configureIdGenerator(customIdGenerator, idSize);
|
|
11199
|
+
if (typeof customIdGenerator === "number" && customIdGenerator > 0) {
|
|
11200
|
+
this.idSize = customIdGenerator;
|
|
11201
|
+
} else if (typeof idSize === "number" && idSize > 0) {
|
|
11202
|
+
this.idSize = idSize;
|
|
11203
|
+
} else {
|
|
11204
|
+
this.idSize = 22;
|
|
11205
|
+
}
|
|
11206
|
+
this.idGeneratorType = this.getIdGeneratorType(customIdGenerator, this.idSize);
|
|
11199
11207
|
this.config = {
|
|
11200
11208
|
cache,
|
|
11201
11209
|
hooks,
|
|
@@ -11251,7 +11259,7 @@ class Resource extends EventEmitter {
|
|
|
11251
11259
|
*/
|
|
11252
11260
|
configureIdGenerator(customIdGenerator, idSize) {
|
|
11253
11261
|
if (typeof customIdGenerator === "function") {
|
|
11254
|
-
return customIdGenerator;
|
|
11262
|
+
return () => String(customIdGenerator());
|
|
11255
11263
|
}
|
|
11256
11264
|
if (typeof customIdGenerator === "number" && customIdGenerator > 0) {
|
|
11257
11265
|
return nanoid.customAlphabet(nanoid.urlAlphabet, customIdGenerator);
|
|
@@ -11261,6 +11269,19 @@ class Resource extends EventEmitter {
|
|
|
11261
11269
|
}
|
|
11262
11270
|
return idGenerator;
|
|
11263
11271
|
}
|
|
11272
|
+
/**
|
|
11273
|
+
* Get a serializable representation of the ID generator type
|
|
11274
|
+
* @param {Function|number} customIdGenerator - Custom ID generator function or size
|
|
11275
|
+
* @param {number} idSize - Size for auto-generated IDs
|
|
11276
|
+
* @returns {string|number} Serializable ID generator type
|
|
11277
|
+
* @private
|
|
11278
|
+
*/
|
|
11279
|
+
getIdGeneratorType(customIdGenerator, idSize) {
|
|
11280
|
+
if (typeof customIdGenerator === "function") {
|
|
11281
|
+
return "custom_function";
|
|
11282
|
+
}
|
|
11283
|
+
return idSize;
|
|
11284
|
+
}
|
|
11264
11285
|
/**
|
|
11265
11286
|
* Get resource options (for backward compatibility with tests)
|
|
11266
11287
|
*/
|
|
@@ -13309,7 +13330,7 @@ class Database extends EventEmitter {
|
|
|
13309
13330
|
super();
|
|
13310
13331
|
this.version = "1";
|
|
13311
13332
|
this.s3dbVersion = (() => {
|
|
13312
|
-
const [ok, err, version] = try_fn_default(() => true ? "7.
|
|
13333
|
+
const [ok, err, version] = try_fn_default(() => true ? "7.5.0" : "latest");
|
|
13313
13334
|
return ok ? version : "latest";
|
|
13314
13335
|
})();
|
|
13315
13336
|
this.resources = {};
|
|
@@ -13380,6 +13401,18 @@ class Database extends EventEmitter {
|
|
|
13380
13401
|
const currentVersion = resourceMetadata.currentVersion || "v0";
|
|
13381
13402
|
const versionData = resourceMetadata.versions?.[currentVersion];
|
|
13382
13403
|
if (versionData) {
|
|
13404
|
+
let restoredIdGenerator, restoredIdSize;
|
|
13405
|
+
if (versionData.idGenerator !== void 0) {
|
|
13406
|
+
if (versionData.idGenerator === "custom_function") {
|
|
13407
|
+
restoredIdGenerator = void 0;
|
|
13408
|
+
restoredIdSize = versionData.idSize || 22;
|
|
13409
|
+
} else if (typeof versionData.idGenerator === "number") {
|
|
13410
|
+
restoredIdGenerator = versionData.idGenerator;
|
|
13411
|
+
restoredIdSize = versionData.idSize || versionData.idGenerator;
|
|
13412
|
+
}
|
|
13413
|
+
} else {
|
|
13414
|
+
restoredIdSize = versionData.idSize || 22;
|
|
13415
|
+
}
|
|
13383
13416
|
this.resources[name] = new resource_class_default({
|
|
13384
13417
|
name,
|
|
13385
13418
|
client: this.client,
|
|
@@ -13399,7 +13432,9 @@ class Database extends EventEmitter {
|
|
|
13399
13432
|
autoDecrypt: versionData.autoDecrypt !== void 0 ? versionData.autoDecrypt : true,
|
|
13400
13433
|
hooks: versionData.hooks || {},
|
|
13401
13434
|
versioningEnabled: this.versioningEnabled,
|
|
13402
|
-
map: versionData.map
|
|
13435
|
+
map: versionData.map,
|
|
13436
|
+
idGenerator: restoredIdGenerator,
|
|
13437
|
+
idSize: restoredIdSize
|
|
13403
13438
|
});
|
|
13404
13439
|
}
|
|
13405
13440
|
}
|
|
@@ -13560,6 +13595,8 @@ class Database extends EventEmitter {
|
|
|
13560
13595
|
autoDecrypt: resource.config.autoDecrypt,
|
|
13561
13596
|
cache: resource.config.cache,
|
|
13562
13597
|
hooks: resource.config.hooks,
|
|
13598
|
+
idSize: resource.idSize,
|
|
13599
|
+
idGenerator: resource.idGeneratorType,
|
|
13563
13600
|
createdAt: isNewVersion ? (/* @__PURE__ */ new Date()).toISOString() : existingVersionData?.createdAt
|
|
13564
13601
|
}
|
|
13565
13602
|
}
|
|
@@ -14515,6 +14552,10 @@ class ReplicatorPlugin extends plugin_class_default {
|
|
|
14515
14552
|
}
|
|
14516
14553
|
return filtered;
|
|
14517
14554
|
}
|
|
14555
|
+
async getCompleteData(resource, data) {
|
|
14556
|
+
const [ok, err, completeRecord] = await try_fn_default(() => resource.get(data.id));
|
|
14557
|
+
return ok ? completeRecord : data;
|
|
14558
|
+
}
|
|
14518
14559
|
installEventListeners(resource, database, plugin) {
|
|
14519
14560
|
if (!resource || this.eventListenersInstalled.has(resource.name) || resource.name === this.config.replicatorLogResource) {
|
|
14520
14561
|
return;
|
|
@@ -14533,8 +14574,9 @@ class ReplicatorPlugin extends plugin_class_default {
|
|
|
14533
14574
|
});
|
|
14534
14575
|
resource.on("update", async (data, beforeData) => {
|
|
14535
14576
|
const [ok, error] = await try_fn_default(async () => {
|
|
14536
|
-
const completeData =
|
|
14537
|
-
|
|
14577
|
+
const completeData = await plugin.getCompleteData(resource, data);
|
|
14578
|
+
const dataWithTimestamp = { ...completeData, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
14579
|
+
await plugin.processReplicatorEvent("update", resource.name, completeData.id, dataWithTimestamp, beforeData);
|
|
14538
14580
|
});
|
|
14539
14581
|
if (!ok) {
|
|
14540
14582
|
if (this.config.verbose) {
|
|
@@ -14556,14 +14598,6 @@ class ReplicatorPlugin extends plugin_class_default {
|
|
|
14556
14598
|
});
|
|
14557
14599
|
this.eventListenersInstalled.add(resource.name);
|
|
14558
14600
|
}
|
|
14559
|
-
/**
|
|
14560
|
-
* Get complete data by always fetching the full record from the resource
|
|
14561
|
-
* This ensures we always have the complete data regardless of behavior or data size
|
|
14562
|
-
*/
|
|
14563
|
-
async getCompleteData(resource, data) {
|
|
14564
|
-
const [ok, err, completeRecord] = await try_fn_default(() => resource.get(data.id));
|
|
14565
|
-
return ok ? completeRecord : data;
|
|
14566
|
-
}
|
|
14567
14601
|
async setup(database) {
|
|
14568
14602
|
this.database = database;
|
|
14569
14603
|
const [initOk, initError] = await try_fn_default(async () => {
|
|
@@ -14577,7 +14611,7 @@ class ReplicatorPlugin extends plugin_class_default {
|
|
|
14577
14611
|
throw initError;
|
|
14578
14612
|
}
|
|
14579
14613
|
const [logOk, logError] = await try_fn_default(async () => {
|
|
14580
|
-
if (this.config.
|
|
14614
|
+
if (this.config.persistReplicatorLog) {
|
|
14581
14615
|
const logRes = await database.createResource({
|
|
14582
14616
|
name: this.config.replicatorLogResource,
|
|
14583
14617
|
behavior: "body-overflow",
|
|
@@ -14604,6 +14638,10 @@ class ReplicatorPlugin extends plugin_class_default {
|
|
|
14604
14638
|
});
|
|
14605
14639
|
}
|
|
14606
14640
|
await this.uploadMetadataFile(database);
|
|
14641
|
+
for (const resourceName in database.resources) {
|
|
14642
|
+
const resource = database.resources[resourceName];
|
|
14643
|
+
this.installEventListeners(resource, database, this);
|
|
14644
|
+
}
|
|
14607
14645
|
const originalCreateResource = database.createResource.bind(database);
|
|
14608
14646
|
database.createResource = async (config) => {
|
|
14609
14647
|
const resource = await originalCreateResource(config);
|
|
@@ -14612,10 +14650,6 @@ class ReplicatorPlugin extends plugin_class_default {
|
|
|
14612
14650
|
}
|
|
14613
14651
|
return resource;
|
|
14614
14652
|
};
|
|
14615
|
-
for (const resourceName in database.resources) {
|
|
14616
|
-
const resource = database.resources[resourceName];
|
|
14617
|
-
this.installEventListeners(resource, database, this);
|
|
14618
|
-
}
|
|
14619
14653
|
}
|
|
14620
14654
|
createReplicator(driver, config, resources, client) {
|
|
14621
14655
|
return createReplicator(driver, config, resources, client);
|