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 CHANGED
@@ -81,7 +81,7 @@ await users.list(); // Cached result
81
81
 
82
82
  | Parameter | Type | Default | Description |
83
83
  |-----------|------|---------|-------------|
84
- | `driverType` | string | `'s3'` | Cache driver: `'memory'` or `'s3'` |
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
- driverType: 'memory',
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
- driverType: 'memory',
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.driverType === "memory") {
7615
+ } else if (this.config.driver === "memory") {
7616
7616
  this.driver = new memory_cache_class_default(this.config.memoryOptions || {});
7617
- } else if (this.config.driverType === "filesystem") {
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.4.1" : "latest");
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 = { ...data, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
14537
- await plugin.processReplicatorEvent("update", resource.name, completeData.id, completeData, beforeData);
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.replicatorLogResource) {
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);