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/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 +3 -2
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:
|
|
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.
|
|
10915
|
+
return true ? "5.2.0" : "latest";
|
|
10800
10916
|
} catch (e) {
|
|
10801
10917
|
return "latest";
|
|
10802
10918
|
}
|