s3db.js 5.1.0 → 6.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/dist/s3db.es.js CHANGED
@@ -8937,6 +8937,9 @@ function getBehavior(behaviorName) {
8937
8937
  const AVAILABLE_BEHAVIORS = Object.keys(behaviors);
8938
8938
  const DEFAULT_BEHAVIOR = "user-management";
8939
8939
 
8940
+ function createIdGeneratorWithSize(size) {
8941
+ return customAlphabet(urlAlphabet, size);
8942
+ }
8940
8943
  class Resource extends EventEmitter {
8941
8944
  /**
8942
8945
  * Create a new Resource instance
@@ -8957,6 +8960,8 @@ class Resource extends EventEmitter {
8957
8960
  * @param {boolean} [config.allNestedObjectsOptional=false] - Make nested objects optional
8958
8961
  * @param {Object} [config.hooks={}] - Custom hooks
8959
8962
  * @param {Object} [config.options={}] - Additional options
8963
+ * @param {Function} [config.idGenerator] - Custom ID generator function
8964
+ * @param {number} [config.idSize=22] - Size for auto-generated IDs
8960
8965
  * @example
8961
8966
  * const users = new Resource({
8962
8967
  * name: 'users',
@@ -8981,6 +8986,30 @@ class Resource extends EventEmitter {
8981
8986
  * }]
8982
8987
  * }
8983
8988
  * });
8989
+ *
8990
+ * // With custom ID size
8991
+ * const shortIdUsers = new Resource({
8992
+ * name: 'users',
8993
+ * client: s3Client,
8994
+ * attributes: { name: 'string|required' },
8995
+ * idSize: 8 // Generate 8-character IDs
8996
+ * });
8997
+ *
8998
+ * // With custom ID generator function
8999
+ * const customIdUsers = new Resource({
9000
+ * name: 'users',
9001
+ * client: s3Client,
9002
+ * attributes: { name: 'string|required' },
9003
+ * idGenerator: () => `user_${Date.now()}_${Math.random().toString(36).substr(2, 5)}`
9004
+ * });
9005
+ *
9006
+ * // With custom ID generator using size parameter
9007
+ * const longIdUsers = new Resource({
9008
+ * name: 'users',
9009
+ * client: s3Client,
9010
+ * attributes: { name: 'string|required' },
9011
+ * idGenerator: 32 // Generate 32-character IDs (same as idSize: 32)
9012
+ * });
8984
9013
  */
8985
9014
  constructor(config) {
8986
9015
  super();
@@ -9004,7 +9033,9 @@ ${validation.errors.join("\n")}`);
9004
9033
  partitions = {},
9005
9034
  paranoid = true,
9006
9035
  allNestedObjectsOptional = true,
9007
- hooks = {}
9036
+ hooks = {},
9037
+ idGenerator: customIdGenerator,
9038
+ idSize = 22
9008
9039
  } = config;
9009
9040
  this.name = name;
9010
9041
  this.client = client;
@@ -9013,6 +9044,7 @@ ${validation.errors.join("\n")}`);
9013
9044
  this.observers = observers;
9014
9045
  this.parallelism = parallelism;
9015
9046
  this.passphrase = passphrase ?? "secret";
9047
+ this.idGenerator = this.configureIdGenerator(customIdGenerator, idSize);
9016
9048
  this.config = {
9017
9049
  cache,
9018
9050
  hooks,
@@ -9044,6 +9076,25 @@ ${validation.errors.join("\n")}`);
9044
9076
  }
9045
9077
  }
9046
9078
  }
9079
+ /**
9080
+ * Configure ID generator based on provided options
9081
+ * @param {Function|number} customIdGenerator - Custom ID generator function or size
9082
+ * @param {number} idSize - Size for auto-generated IDs
9083
+ * @returns {Function} Configured ID generator function
9084
+ * @private
9085
+ */
9086
+ configureIdGenerator(customIdGenerator, idSize) {
9087
+ if (typeof customIdGenerator === "function") {
9088
+ return customIdGenerator;
9089
+ }
9090
+ if (typeof customIdGenerator === "number" && customIdGenerator > 0) {
9091
+ return createIdGeneratorWithSize(customIdGenerator);
9092
+ }
9093
+ if (typeof idSize === "number" && idSize > 0) {
9094
+ return createIdGeneratorWithSize(idSize);
9095
+ }
9096
+ return idGenerator;
9097
+ }
9047
9098
  /**
9048
9099
  * Get resource options (for backward compatibility with tests)
9049
9100
  */
@@ -9392,7 +9443,7 @@ ${validation.errors.join("\n")}`);
9392
9443
  validation: errors
9393
9444
  });
9394
9445
  }
9395
- if (!id && id !== 0) id = idGenerator();
9446
+ if (!id && id !== 0) id = this.idGenerator();
9396
9447
  const mappedData = await this.schema.mapper(validated);
9397
9448
  const behaviorImpl = getBehavior(this.behavior);
9398
9449
  const { mappedData: processedMetadata, body } = await behaviorImpl.handleInsert({
@@ -9401,10 +9452,19 @@ ${validation.errors.join("\n")}`);
9401
9452
  mappedData
9402
9453
  });
9403
9454
  const key = this.getResourceKey(id);
9455
+ let contentType = void 0;
9456
+ if (body && body !== "") {
9457
+ try {
9458
+ JSON.parse(body);
9459
+ contentType = "application/json";
9460
+ } catch {
9461
+ }
9462
+ }
9404
9463
  await this.client.putObject({
9405
9464
  metadata: processedMetadata,
9406
9465
  key,
9407
- body
9466
+ body,
9467
+ contentType
9408
9468
  });
9409
9469
  const final = merge({ id }, validated);
9410
9470
  await this.executeHooks("afterInsert", final);
@@ -9599,10 +9659,18 @@ ${validation.errors.join("\n")}`);
9599
9659
  } catch (error) {
9600
9660
  }
9601
9661
  }
9662
+ let finalContentType = existingContentType;
9663
+ if (finalBody && finalBody !== "" && !finalContentType) {
9664
+ try {
9665
+ JSON.parse(finalBody);
9666
+ finalContentType = "application/json";
9667
+ } catch {
9668
+ }
9669
+ }
9602
9670
  await this.client.putObject({
9603
9671
  key,
9604
9672
  body: finalBody,
9605
- contentType: existingContentType,
9673
+ contentType: finalContentType,
9606
9674
  metadata: processedMetadata
9607
9675
  });
9608
9676
  validated.id = id;
@@ -9699,9 +9767,7 @@ ${validation.errors.join("\n")}`);
9699
9767
  } else {
9700
9768
  prefix = `resource=${this.name}/v=${this.version}`;
9701
9769
  }
9702
- const count = await this.client.count({
9703
- prefix
9704
- });
9770
+ const count = await this.client.count({ prefix });
9705
9771
  this.emit("count", count);
9706
9772
  return count;
9707
9773
  }
@@ -10369,10 +10435,19 @@ ${validation.errors.join("\n")}`);
10369
10435
  ...processedMetadata,
10370
10436
  _version: this.version
10371
10437
  };
10438
+ let contentType = void 0;
10439
+ if (body && body !== "") {
10440
+ try {
10441
+ JSON.parse(body);
10442
+ contentType = "application/json";
10443
+ } catch {
10444
+ }
10445
+ }
10372
10446
  await this.client.putObject({
10373
10447
  key: partitionKey,
10374
10448
  metadata: partitionMetadata,
10375
- body
10449
+ body,
10450
+ contentType
10376
10451
  });
10377
10452
  }
10378
10453
  }
@@ -10544,10 +10619,19 @@ ${validation.errors.join("\n")}`);
10544
10619
  _version: this.version
10545
10620
  };
10546
10621
  if (partitionMetadata.undefined !== void 0) delete partitionMetadata.undefined;
10622
+ let contentType = void 0;
10623
+ if (body && body !== "") {
10624
+ try {
10625
+ JSON.parse(body);
10626
+ contentType = "application/json";
10627
+ } catch {
10628
+ }
10629
+ }
10547
10630
  await this.client.putObject({
10548
10631
  key: newPartitionKey,
10549
10632
  metadata: partitionMetadata,
10550
- body
10633
+ body,
10634
+ contentType
10551
10635
  });
10552
10636
  } catch (error) {
10553
10637
  console.warn(`New partition object could not be created for ${partitionName}:`, error.message);
@@ -10570,10 +10654,19 @@ ${validation.errors.join("\n")}`);
10570
10654
  _version: this.version
10571
10655
  };
10572
10656
  if (partitionMetadata.undefined !== void 0) delete partitionMetadata.undefined;
10657
+ let contentType = void 0;
10658
+ if (body && body !== "") {
10659
+ try {
10660
+ JSON.parse(body);
10661
+ contentType = "application/json";
10662
+ } catch {
10663
+ }
10664
+ }
10573
10665
  await this.client.putObject({
10574
10666
  key: newPartitionKey,
10575
10667
  metadata: partitionMetadata,
10576
- body
10668
+ body,
10669
+ contentType
10577
10670
  });
10578
10671
  } catch (error) {
10579
10672
  console.warn(`Partition object could not be updated for ${partitionName}:`, error.message);
@@ -10608,11 +10701,20 @@ ${validation.errors.join("\n")}`);
10608
10701
  ...processedMetadata,
10609
10702
  _version: this.version
10610
10703
  };
10704
+ let contentType = void 0;
10705
+ if (body && body !== "") {
10706
+ try {
10707
+ JSON.parse(body);
10708
+ contentType = "application/json";
10709
+ } catch {
10710
+ }
10711
+ }
10611
10712
  try {
10612
10713
  await this.client.putObject({
10613
10714
  key: partitionKey,
10614
10715
  metadata: partitionMetadata,
10615
- body
10716
+ body,
10717
+ contentType
10616
10718
  });
10617
10719
  } catch (error) {
10618
10720
  console.warn(`Partition object could not be updated for ${partitionName}:`, error.message);
@@ -10741,6 +10843,20 @@ function validateResourceConfig(config) {
10741
10843
  errors.push(`Resource '${field}' must be a boolean`);
10742
10844
  }
10743
10845
  }
10846
+ if (config.idGenerator !== void 0) {
10847
+ if (typeof config.idGenerator !== "function" && typeof config.idGenerator !== "number") {
10848
+ errors.push("Resource 'idGenerator' must be a function or a number (size)");
10849
+ } else if (typeof config.idGenerator === "number" && config.idGenerator <= 0) {
10850
+ errors.push("Resource 'idGenerator' size must be greater than 0");
10851
+ }
10852
+ }
10853
+ if (config.idSize !== void 0) {
10854
+ if (typeof config.idSize !== "number" || !Number.isInteger(config.idSize)) {
10855
+ errors.push("Resource 'idSize' must be an integer");
10856
+ } else if (config.idSize <= 0) {
10857
+ errors.push("Resource 'idSize' must be greater than 0");
10858
+ }
10859
+ }
10744
10860
  if (config.partitions !== void 0) {
10745
10861
  if (typeof config.partitions !== "object" || Array.isArray(config.partitions)) {
10746
10862
  errors.push("Resource 'partitions' must be an object");
@@ -10796,7 +10912,7 @@ class Database extends EventEmitter {
10796
10912
  this.version = "1";
10797
10913
  this.s3dbVersion = (() => {
10798
10914
  try {
10799
- return true ? "5.0.0" : "latest";
10915
+ return true ? "5.2.0" : "latest";
10800
10916
  } catch (e) {
10801
10917
  return "latest";
10802
10918
  }