s3db.js 5.2.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/README.md +1168 -54
- package/dist/s3db.cjs.js +128 -12
- package/dist/s3db.cjs.min.js +11 -11
- package/dist/s3db.es.js +128 -12
- package/dist/s3db.es.min.js +11 -11
- package/dist/s3db.iife.js +128 -12
- package/dist/s3db.iife.min.js +11 -11
- package/package.json +1 -1
package/dist/s3db.cjs.js
CHANGED
|
@@ -8941,6 +8941,9 @@ function getBehavior(behaviorName) {
|
|
|
8941
8941
|
const AVAILABLE_BEHAVIORS = Object.keys(behaviors);
|
|
8942
8942
|
const DEFAULT_BEHAVIOR = "user-management";
|
|
8943
8943
|
|
|
8944
|
+
function createIdGeneratorWithSize(size) {
|
|
8945
|
+
return nanoid.customAlphabet(nanoid.urlAlphabet, size);
|
|
8946
|
+
}
|
|
8944
8947
|
class Resource extends EventEmitter {
|
|
8945
8948
|
/**
|
|
8946
8949
|
* Create a new Resource instance
|
|
@@ -8961,6 +8964,8 @@ class Resource extends EventEmitter {
|
|
|
8961
8964
|
* @param {boolean} [config.allNestedObjectsOptional=false] - Make nested objects optional
|
|
8962
8965
|
* @param {Object} [config.hooks={}] - Custom hooks
|
|
8963
8966
|
* @param {Object} [config.options={}] - Additional options
|
|
8967
|
+
* @param {Function} [config.idGenerator] - Custom ID generator function
|
|
8968
|
+
* @param {number} [config.idSize=22] - Size for auto-generated IDs
|
|
8964
8969
|
* @example
|
|
8965
8970
|
* const users = new Resource({
|
|
8966
8971
|
* name: 'users',
|
|
@@ -8985,6 +8990,30 @@ class Resource extends EventEmitter {
|
|
|
8985
8990
|
* }]
|
|
8986
8991
|
* }
|
|
8987
8992
|
* });
|
|
8993
|
+
*
|
|
8994
|
+
* // With custom ID size
|
|
8995
|
+
* const shortIdUsers = new Resource({
|
|
8996
|
+
* name: 'users',
|
|
8997
|
+
* client: s3Client,
|
|
8998
|
+
* attributes: { name: 'string|required' },
|
|
8999
|
+
* idSize: 8 // Generate 8-character IDs
|
|
9000
|
+
* });
|
|
9001
|
+
*
|
|
9002
|
+
* // With custom ID generator function
|
|
9003
|
+
* const customIdUsers = new Resource({
|
|
9004
|
+
* name: 'users',
|
|
9005
|
+
* client: s3Client,
|
|
9006
|
+
* attributes: { name: 'string|required' },
|
|
9007
|
+
* idGenerator: () => `user_${Date.now()}_${Math.random().toString(36).substr(2, 5)}`
|
|
9008
|
+
* });
|
|
9009
|
+
*
|
|
9010
|
+
* // With custom ID generator using size parameter
|
|
9011
|
+
* const longIdUsers = new Resource({
|
|
9012
|
+
* name: 'users',
|
|
9013
|
+
* client: s3Client,
|
|
9014
|
+
* attributes: { name: 'string|required' },
|
|
9015
|
+
* idGenerator: 32 // Generate 32-character IDs (same as idSize: 32)
|
|
9016
|
+
* });
|
|
8988
9017
|
*/
|
|
8989
9018
|
constructor(config) {
|
|
8990
9019
|
super();
|
|
@@ -9008,7 +9037,9 @@ ${validation.errors.join("\n")}`);
|
|
|
9008
9037
|
partitions = {},
|
|
9009
9038
|
paranoid = true,
|
|
9010
9039
|
allNestedObjectsOptional = true,
|
|
9011
|
-
hooks = {}
|
|
9040
|
+
hooks = {},
|
|
9041
|
+
idGenerator: customIdGenerator,
|
|
9042
|
+
idSize = 22
|
|
9012
9043
|
} = config;
|
|
9013
9044
|
this.name = name;
|
|
9014
9045
|
this.client = client;
|
|
@@ -9017,6 +9048,7 @@ ${validation.errors.join("\n")}`);
|
|
|
9017
9048
|
this.observers = observers;
|
|
9018
9049
|
this.parallelism = parallelism;
|
|
9019
9050
|
this.passphrase = passphrase ?? "secret";
|
|
9051
|
+
this.idGenerator = this.configureIdGenerator(customIdGenerator, idSize);
|
|
9020
9052
|
this.config = {
|
|
9021
9053
|
cache,
|
|
9022
9054
|
hooks,
|
|
@@ -9048,6 +9080,25 @@ ${validation.errors.join("\n")}`);
|
|
|
9048
9080
|
}
|
|
9049
9081
|
}
|
|
9050
9082
|
}
|
|
9083
|
+
/**
|
|
9084
|
+
* Configure ID generator based on provided options
|
|
9085
|
+
* @param {Function|number} customIdGenerator - Custom ID generator function or size
|
|
9086
|
+
* @param {number} idSize - Size for auto-generated IDs
|
|
9087
|
+
* @returns {Function} Configured ID generator function
|
|
9088
|
+
* @private
|
|
9089
|
+
*/
|
|
9090
|
+
configureIdGenerator(customIdGenerator, idSize) {
|
|
9091
|
+
if (typeof customIdGenerator === "function") {
|
|
9092
|
+
return customIdGenerator;
|
|
9093
|
+
}
|
|
9094
|
+
if (typeof customIdGenerator === "number" && customIdGenerator > 0) {
|
|
9095
|
+
return createIdGeneratorWithSize(customIdGenerator);
|
|
9096
|
+
}
|
|
9097
|
+
if (typeof idSize === "number" && idSize > 0) {
|
|
9098
|
+
return createIdGeneratorWithSize(idSize);
|
|
9099
|
+
}
|
|
9100
|
+
return idGenerator;
|
|
9101
|
+
}
|
|
9051
9102
|
/**
|
|
9052
9103
|
* Get resource options (for backward compatibility with tests)
|
|
9053
9104
|
*/
|
|
@@ -9396,7 +9447,7 @@ ${validation.errors.join("\n")}`);
|
|
|
9396
9447
|
validation: errors
|
|
9397
9448
|
});
|
|
9398
9449
|
}
|
|
9399
|
-
if (!id && id !== 0) id = idGenerator();
|
|
9450
|
+
if (!id && id !== 0) id = this.idGenerator();
|
|
9400
9451
|
const mappedData = await this.schema.mapper(validated);
|
|
9401
9452
|
const behaviorImpl = getBehavior(this.behavior);
|
|
9402
9453
|
const { mappedData: processedMetadata, body } = await behaviorImpl.handleInsert({
|
|
@@ -9405,10 +9456,19 @@ ${validation.errors.join("\n")}`);
|
|
|
9405
9456
|
mappedData
|
|
9406
9457
|
});
|
|
9407
9458
|
const key = this.getResourceKey(id);
|
|
9459
|
+
let contentType = void 0;
|
|
9460
|
+
if (body && body !== "") {
|
|
9461
|
+
try {
|
|
9462
|
+
JSON.parse(body);
|
|
9463
|
+
contentType = "application/json";
|
|
9464
|
+
} catch {
|
|
9465
|
+
}
|
|
9466
|
+
}
|
|
9408
9467
|
await this.client.putObject({
|
|
9409
9468
|
metadata: processedMetadata,
|
|
9410
9469
|
key,
|
|
9411
|
-
body
|
|
9470
|
+
body,
|
|
9471
|
+
contentType
|
|
9412
9472
|
});
|
|
9413
9473
|
const final = lodashEs.merge({ id }, validated);
|
|
9414
9474
|
await this.executeHooks("afterInsert", final);
|
|
@@ -9603,10 +9663,18 @@ ${validation.errors.join("\n")}`);
|
|
|
9603
9663
|
} catch (error) {
|
|
9604
9664
|
}
|
|
9605
9665
|
}
|
|
9666
|
+
let finalContentType = existingContentType;
|
|
9667
|
+
if (finalBody && finalBody !== "" && !finalContentType) {
|
|
9668
|
+
try {
|
|
9669
|
+
JSON.parse(finalBody);
|
|
9670
|
+
finalContentType = "application/json";
|
|
9671
|
+
} catch {
|
|
9672
|
+
}
|
|
9673
|
+
}
|
|
9606
9674
|
await this.client.putObject({
|
|
9607
9675
|
key,
|
|
9608
9676
|
body: finalBody,
|
|
9609
|
-
contentType:
|
|
9677
|
+
contentType: finalContentType,
|
|
9610
9678
|
metadata: processedMetadata
|
|
9611
9679
|
});
|
|
9612
9680
|
validated.id = id;
|
|
@@ -9703,9 +9771,7 @@ ${validation.errors.join("\n")}`);
|
|
|
9703
9771
|
} else {
|
|
9704
9772
|
prefix = `resource=${this.name}/v=${this.version}`;
|
|
9705
9773
|
}
|
|
9706
|
-
const count = await this.client.count({
|
|
9707
|
-
prefix
|
|
9708
|
-
});
|
|
9774
|
+
const count = await this.client.count({ prefix });
|
|
9709
9775
|
this.emit("count", count);
|
|
9710
9776
|
return count;
|
|
9711
9777
|
}
|
|
@@ -10373,10 +10439,19 @@ ${validation.errors.join("\n")}`);
|
|
|
10373
10439
|
...processedMetadata,
|
|
10374
10440
|
_version: this.version
|
|
10375
10441
|
};
|
|
10442
|
+
let contentType = void 0;
|
|
10443
|
+
if (body && body !== "") {
|
|
10444
|
+
try {
|
|
10445
|
+
JSON.parse(body);
|
|
10446
|
+
contentType = "application/json";
|
|
10447
|
+
} catch {
|
|
10448
|
+
}
|
|
10449
|
+
}
|
|
10376
10450
|
await this.client.putObject({
|
|
10377
10451
|
key: partitionKey,
|
|
10378
10452
|
metadata: partitionMetadata,
|
|
10379
|
-
body
|
|
10453
|
+
body,
|
|
10454
|
+
contentType
|
|
10380
10455
|
});
|
|
10381
10456
|
}
|
|
10382
10457
|
}
|
|
@@ -10548,10 +10623,19 @@ ${validation.errors.join("\n")}`);
|
|
|
10548
10623
|
_version: this.version
|
|
10549
10624
|
};
|
|
10550
10625
|
if (partitionMetadata.undefined !== void 0) delete partitionMetadata.undefined;
|
|
10626
|
+
let contentType = void 0;
|
|
10627
|
+
if (body && body !== "") {
|
|
10628
|
+
try {
|
|
10629
|
+
JSON.parse(body);
|
|
10630
|
+
contentType = "application/json";
|
|
10631
|
+
} catch {
|
|
10632
|
+
}
|
|
10633
|
+
}
|
|
10551
10634
|
await this.client.putObject({
|
|
10552
10635
|
key: newPartitionKey,
|
|
10553
10636
|
metadata: partitionMetadata,
|
|
10554
|
-
body
|
|
10637
|
+
body,
|
|
10638
|
+
contentType
|
|
10555
10639
|
});
|
|
10556
10640
|
} catch (error) {
|
|
10557
10641
|
console.warn(`New partition object could not be created for ${partitionName}:`, error.message);
|
|
@@ -10574,10 +10658,19 @@ ${validation.errors.join("\n")}`);
|
|
|
10574
10658
|
_version: this.version
|
|
10575
10659
|
};
|
|
10576
10660
|
if (partitionMetadata.undefined !== void 0) delete partitionMetadata.undefined;
|
|
10661
|
+
let contentType = void 0;
|
|
10662
|
+
if (body && body !== "") {
|
|
10663
|
+
try {
|
|
10664
|
+
JSON.parse(body);
|
|
10665
|
+
contentType = "application/json";
|
|
10666
|
+
} catch {
|
|
10667
|
+
}
|
|
10668
|
+
}
|
|
10577
10669
|
await this.client.putObject({
|
|
10578
10670
|
key: newPartitionKey,
|
|
10579
10671
|
metadata: partitionMetadata,
|
|
10580
|
-
body
|
|
10672
|
+
body,
|
|
10673
|
+
contentType
|
|
10581
10674
|
});
|
|
10582
10675
|
} catch (error) {
|
|
10583
10676
|
console.warn(`Partition object could not be updated for ${partitionName}:`, error.message);
|
|
@@ -10612,11 +10705,20 @@ ${validation.errors.join("\n")}`);
|
|
|
10612
10705
|
...processedMetadata,
|
|
10613
10706
|
_version: this.version
|
|
10614
10707
|
};
|
|
10708
|
+
let contentType = void 0;
|
|
10709
|
+
if (body && body !== "") {
|
|
10710
|
+
try {
|
|
10711
|
+
JSON.parse(body);
|
|
10712
|
+
contentType = "application/json";
|
|
10713
|
+
} catch {
|
|
10714
|
+
}
|
|
10715
|
+
}
|
|
10615
10716
|
try {
|
|
10616
10717
|
await this.client.putObject({
|
|
10617
10718
|
key: partitionKey,
|
|
10618
10719
|
metadata: partitionMetadata,
|
|
10619
|
-
body
|
|
10720
|
+
body,
|
|
10721
|
+
contentType
|
|
10620
10722
|
});
|
|
10621
10723
|
} catch (error) {
|
|
10622
10724
|
console.warn(`Partition object could not be updated for ${partitionName}:`, error.message);
|
|
@@ -10745,6 +10847,20 @@ function validateResourceConfig(config) {
|
|
|
10745
10847
|
errors.push(`Resource '${field}' must be a boolean`);
|
|
10746
10848
|
}
|
|
10747
10849
|
}
|
|
10850
|
+
if (config.idGenerator !== void 0) {
|
|
10851
|
+
if (typeof config.idGenerator !== "function" && typeof config.idGenerator !== "number") {
|
|
10852
|
+
errors.push("Resource 'idGenerator' must be a function or a number (size)");
|
|
10853
|
+
} else if (typeof config.idGenerator === "number" && config.idGenerator <= 0) {
|
|
10854
|
+
errors.push("Resource 'idGenerator' size must be greater than 0");
|
|
10855
|
+
}
|
|
10856
|
+
}
|
|
10857
|
+
if (config.idSize !== void 0) {
|
|
10858
|
+
if (typeof config.idSize !== "number" || !Number.isInteger(config.idSize)) {
|
|
10859
|
+
errors.push("Resource 'idSize' must be an integer");
|
|
10860
|
+
} else if (config.idSize <= 0) {
|
|
10861
|
+
errors.push("Resource 'idSize' must be greater than 0");
|
|
10862
|
+
}
|
|
10863
|
+
}
|
|
10748
10864
|
if (config.partitions !== void 0) {
|
|
10749
10865
|
if (typeof config.partitions !== "object" || Array.isArray(config.partitions)) {
|
|
10750
10866
|
errors.push("Resource 'partitions' must be an object");
|
|
@@ -10800,7 +10916,7 @@ class Database extends EventEmitter {
|
|
|
10800
10916
|
this.version = "1";
|
|
10801
10917
|
this.s3dbVersion = (() => {
|
|
10802
10918
|
try {
|
|
10803
|
-
return true ? "5.
|
|
10919
|
+
return true ? "5.2.0" : "latest";
|
|
10804
10920
|
} catch (e) {
|
|
10805
10921
|
return "latest";
|
|
10806
10922
|
}
|