s3db.js 4.1.10 → 4.1.13
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 +786 -1706
- package/dist/s3db.cjs.js +392 -111
- package/dist/s3db.cjs.min.js +14 -12
- package/dist/s3db.es.js +380 -112
- package/dist/s3db.es.min.js +11 -9
- package/dist/s3db.iife.js +392 -111
- package/dist/s3db.iife.min.js +14 -12
- package/package.json +14 -14
package/dist/s3db.cjs.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/* istanbul ignore file */
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
5
|
+
|
|
4
6
|
var nanoid = require('nanoid');
|
|
5
7
|
var lodashEs = require('lodash-es');
|
|
6
8
|
var promisePool = require('@supercharge/promise-pool');
|
|
@@ -244,6 +246,8 @@ var substr = 'ab'.substr(-1) === 'b' ?
|
|
|
244
246
|
;
|
|
245
247
|
|
|
246
248
|
const idGenerator = nanoid.customAlphabet(nanoid.urlAlphabet, 22);
|
|
249
|
+
const passwordAlphabet = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789";
|
|
250
|
+
nanoid.customAlphabet(passwordAlphabet, 12);
|
|
247
251
|
|
|
248
252
|
var domain;
|
|
249
253
|
|
|
@@ -744,42 +748,85 @@ ${JSON.stringify(rest, null, 2)}`;
|
|
|
744
748
|
return `${this.name} | ${this.message}`;
|
|
745
749
|
}
|
|
746
750
|
}
|
|
747
|
-
class
|
|
751
|
+
class S3DBError extends BaseError {
|
|
752
|
+
constructor(message, details = {}) {
|
|
753
|
+
super({ message, ...details });
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
class DatabaseError extends S3DBError {
|
|
757
|
+
constructor(message, details = {}) {
|
|
758
|
+
super(message, details);
|
|
759
|
+
Object.assign(this, details);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
class ValidationError extends S3DBError {
|
|
763
|
+
constructor(message, details = {}) {
|
|
764
|
+
super(message, details);
|
|
765
|
+
Object.assign(this, details);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
class AuthenticationError extends S3DBError {
|
|
769
|
+
constructor(message, details = {}) {
|
|
770
|
+
super(message, details);
|
|
771
|
+
Object.assign(this, details);
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
class PermissionError extends S3DBError {
|
|
775
|
+
constructor(message, details = {}) {
|
|
776
|
+
super(message, details);
|
|
777
|
+
Object.assign(this, details);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
class EncryptionError extends S3DBError {
|
|
781
|
+
constructor(message, details = {}) {
|
|
782
|
+
super(message, details);
|
|
783
|
+
Object.assign(this, details);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
class ResourceNotFound extends S3DBError {
|
|
787
|
+
constructor({ bucket, resourceName, id, ...rest }) {
|
|
788
|
+
super(`Resource not found: ${resourceName}/${id} [bucket:${bucket}]`, {
|
|
789
|
+
bucket,
|
|
790
|
+
resourceName,
|
|
791
|
+
id,
|
|
792
|
+
...rest
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
class NoSuchBucket extends S3DBError {
|
|
748
797
|
constructor({ bucket, ...rest }) {
|
|
749
|
-
super(
|
|
798
|
+
super(`Bucket does not exists [bucket:${bucket}]`, { bucket, ...rest });
|
|
750
799
|
}
|
|
751
800
|
}
|
|
752
|
-
class NoSuchKey extends
|
|
801
|
+
class NoSuchKey extends S3DBError {
|
|
753
802
|
constructor({ bucket, key, ...rest }) {
|
|
754
|
-
super(
|
|
755
|
-
this.key = key;
|
|
803
|
+
super(`Key [${key}] does not exists [bucket:${bucket}/${key}]`, { bucket, key, ...rest });
|
|
756
804
|
}
|
|
757
805
|
}
|
|
758
806
|
class NotFound extends NoSuchKey {
|
|
759
807
|
}
|
|
760
|
-
class MissingMetadata extends
|
|
808
|
+
class MissingMetadata extends S3DBError {
|
|
761
809
|
constructor({ bucket, ...rest }) {
|
|
762
|
-
super(
|
|
810
|
+
super(`Missing metadata for bucket [bucket:${bucket}]`, { bucket, ...rest });
|
|
763
811
|
}
|
|
764
812
|
}
|
|
765
|
-
class InvalidResourceItem extends
|
|
813
|
+
class InvalidResourceItem extends S3DBError {
|
|
766
814
|
constructor({
|
|
767
815
|
bucket,
|
|
768
816
|
resourceName,
|
|
769
817
|
attributes,
|
|
770
818
|
validation
|
|
771
819
|
}) {
|
|
772
|
-
super({
|
|
820
|
+
super(`This item is not valid. Resource=${resourceName} [bucket:${bucket}].
|
|
821
|
+
${JSON.stringify(validation, null, 2)}`, {
|
|
773
822
|
bucket,
|
|
774
|
-
|
|
775
|
-
|
|
823
|
+
resourceName,
|
|
824
|
+
attributes,
|
|
825
|
+
validation
|
|
776
826
|
});
|
|
777
|
-
this.resourceName = resourceName;
|
|
778
|
-
this.attributes = attributes;
|
|
779
|
-
this.validation = validation;
|
|
780
827
|
}
|
|
781
828
|
}
|
|
782
|
-
class UnknownError extends
|
|
829
|
+
class UnknownError extends S3DBError {
|
|
783
830
|
}
|
|
784
831
|
const ErrorMap = {
|
|
785
832
|
"NotFound": NotFound,
|
|
@@ -808,9 +855,9 @@ class ConnectionString {
|
|
|
808
855
|
}
|
|
809
856
|
}
|
|
810
857
|
defineS3(uri) {
|
|
811
|
-
this.bucket = uri.hostname;
|
|
812
|
-
this.accessKeyId = uri.username;
|
|
813
|
-
this.secretAccessKey = uri.password;
|
|
858
|
+
this.bucket = decodeURIComponent(uri.hostname);
|
|
859
|
+
this.accessKeyId = decodeURIComponent(uri.username);
|
|
860
|
+
this.secretAccessKey = decodeURIComponent(uri.password);
|
|
814
861
|
this.endpoint = S3_DEFAULT_ENDPOINT;
|
|
815
862
|
if (["/", "", null].includes(uri.pathname)) {
|
|
816
863
|
this.keyPrefix = "";
|
|
@@ -822,14 +869,14 @@ class ConnectionString {
|
|
|
822
869
|
defineMinio(uri) {
|
|
823
870
|
this.forcePathStyle = true;
|
|
824
871
|
this.endpoint = uri.origin;
|
|
825
|
-
this.accessKeyId = uri.username;
|
|
826
|
-
this.secretAccessKey = uri.password;
|
|
872
|
+
this.accessKeyId = decodeURIComponent(uri.username);
|
|
873
|
+
this.secretAccessKey = decodeURIComponent(uri.password);
|
|
827
874
|
if (["/", "", null].includes(uri.pathname)) {
|
|
828
875
|
this.bucket = "s3db";
|
|
829
876
|
this.keyPrefix = "";
|
|
830
877
|
} else {
|
|
831
878
|
let [, bucket, ...subpath] = uri.pathname.split("/");
|
|
832
|
-
this.bucket = bucket;
|
|
879
|
+
this.bucket = decodeURIComponent(bucket);
|
|
833
880
|
this.keyPrefix = [...subpath || []].join("/");
|
|
834
881
|
}
|
|
835
882
|
}
|
|
@@ -8838,18 +8885,83 @@ function getBehavior(behaviorName) {
|
|
|
8838
8885
|
const DEFAULT_BEHAVIOR = "user-management";
|
|
8839
8886
|
|
|
8840
8887
|
class Resource extends EventEmitter {
|
|
8841
|
-
|
|
8842
|
-
|
|
8843
|
-
|
|
8844
|
-
|
|
8845
|
-
|
|
8846
|
-
|
|
8847
|
-
|
|
8848
|
-
|
|
8849
|
-
|
|
8850
|
-
|
|
8851
|
-
|
|
8888
|
+
/**
|
|
8889
|
+
* Create a new Resource instance
|
|
8890
|
+
* @param {Object} config - Resource configuration
|
|
8891
|
+
* @param {string} config.name - Resource name
|
|
8892
|
+
* @param {Object} config.client - S3 client instance
|
|
8893
|
+
* @param {string} [config.version='v0'] - Resource version
|
|
8894
|
+
* @param {Object} [config.attributes={}] - Resource attributes schema
|
|
8895
|
+
* @param {string} [config.behavior='user-management'] - Resource behavior strategy
|
|
8896
|
+
* @param {string} [config.passphrase='secret'] - Encryption passphrase
|
|
8897
|
+
* @param {number} [config.parallelism=10] - Parallelism for bulk operations
|
|
8898
|
+
* @param {Array} [config.observers=[]] - Observer instances
|
|
8899
|
+
* @param {boolean} [config.cache=false] - Enable caching
|
|
8900
|
+
* @param {boolean} [config.autoDecrypt=true] - Auto-decrypt secret fields
|
|
8901
|
+
* @param {boolean} [config.timestamps=false] - Enable automatic timestamps
|
|
8902
|
+
* @param {Object} [config.partitions={}] - Partition definitions
|
|
8903
|
+
* @param {boolean} [config.paranoid=true] - Security flag for dangerous operations
|
|
8904
|
+
* @param {boolean} [config.allNestedObjectsOptional=false] - Make nested objects optional
|
|
8905
|
+
* @param {Object} [config.hooks={}] - Custom hooks
|
|
8906
|
+
* @param {Object} [config.options={}] - Additional options
|
|
8907
|
+
* @example
|
|
8908
|
+
* const users = new Resource({
|
|
8909
|
+
* name: 'users',
|
|
8910
|
+
* client: s3Client,
|
|
8911
|
+
* attributes: {
|
|
8912
|
+
* name: 'string|required',
|
|
8913
|
+
* email: 'string|required',
|
|
8914
|
+
* password: 'secret|required'
|
|
8915
|
+
* },
|
|
8916
|
+
* behavior: 'user-management',
|
|
8917
|
+
* passphrase: 'my-secret-key',
|
|
8918
|
+
* timestamps: true,
|
|
8919
|
+
* partitions: {
|
|
8920
|
+
* byRegion: {
|
|
8921
|
+
* fields: { region: 'string' }
|
|
8922
|
+
* }
|
|
8923
|
+
* },
|
|
8924
|
+
* hooks: {
|
|
8925
|
+
* preInsert: [async (data) => {
|
|
8926
|
+
* console.log('Pre-insert hook:', data);
|
|
8927
|
+
* return data;
|
|
8928
|
+
* }]
|
|
8929
|
+
* }
|
|
8930
|
+
* });
|
|
8931
|
+
*/
|
|
8932
|
+
constructor(config) {
|
|
8852
8933
|
super();
|
|
8934
|
+
const validation = validateResourceConfig(config);
|
|
8935
|
+
if (!validation.isValid) {
|
|
8936
|
+
throw new Error(`Invalid Resource configuration:
|
|
8937
|
+
${validation.errors.join("\n")}`);
|
|
8938
|
+
}
|
|
8939
|
+
const {
|
|
8940
|
+
name,
|
|
8941
|
+
client,
|
|
8942
|
+
version = "1",
|
|
8943
|
+
attributes = {},
|
|
8944
|
+
behavior = DEFAULT_BEHAVIOR,
|
|
8945
|
+
passphrase = "secret",
|
|
8946
|
+
parallelism = 10,
|
|
8947
|
+
observers = [],
|
|
8948
|
+
cache = false,
|
|
8949
|
+
autoDecrypt = true,
|
|
8950
|
+
timestamps = false,
|
|
8951
|
+
partitions = {},
|
|
8952
|
+
paranoid = true,
|
|
8953
|
+
allNestedObjectsOptional = true,
|
|
8954
|
+
hooks = {},
|
|
8955
|
+
options = {}
|
|
8956
|
+
} = config;
|
|
8957
|
+
const mergedOptions = {
|
|
8958
|
+
cache: typeof options.cache === "boolean" ? options.cache : cache,
|
|
8959
|
+
autoDecrypt: typeof options.autoDecrypt === "boolean" ? options.autoDecrypt : autoDecrypt,
|
|
8960
|
+
timestamps: typeof options.timestamps === "boolean" ? options.timestamps : timestamps,
|
|
8961
|
+
paranoid: typeof options.paranoid === "boolean" ? options.paranoid : paranoid,
|
|
8962
|
+
allNestedObjectsOptional: typeof options.allNestedObjectsOptional === "boolean" ? options.allNestedObjectsOptional : allNestedObjectsOptional,
|
|
8963
|
+
partitions: options.partitions || partitions || {}
|
|
8964
|
+
};
|
|
8853
8965
|
this.name = name;
|
|
8854
8966
|
this.client = client;
|
|
8855
8967
|
this.version = version;
|
|
@@ -8857,15 +8969,14 @@ class Resource extends EventEmitter {
|
|
|
8857
8969
|
this.observers = observers;
|
|
8858
8970
|
this.parallelism = parallelism;
|
|
8859
8971
|
this.passphrase = passphrase ?? "secret";
|
|
8860
|
-
this.
|
|
8861
|
-
cache:
|
|
8862
|
-
|
|
8863
|
-
|
|
8864
|
-
|
|
8865
|
-
|
|
8866
|
-
|
|
8867
|
-
allNestedObjectsOptional:
|
|
8868
|
-
...options
|
|
8972
|
+
this.config = {
|
|
8973
|
+
cache: mergedOptions.cache,
|
|
8974
|
+
hooks,
|
|
8975
|
+
paranoid: mergedOptions.paranoid,
|
|
8976
|
+
timestamps: mergedOptions.timestamps,
|
|
8977
|
+
partitions: mergedOptions.partitions,
|
|
8978
|
+
autoDecrypt: mergedOptions.autoDecrypt,
|
|
8979
|
+
allNestedObjectsOptional: mergedOptions.allNestedObjectsOptional
|
|
8869
8980
|
};
|
|
8870
8981
|
this.hooks = {
|
|
8871
8982
|
preInsert: [],
|
|
@@ -8876,18 +8987,21 @@ class Resource extends EventEmitter {
|
|
|
8876
8987
|
afterDelete: []
|
|
8877
8988
|
};
|
|
8878
8989
|
this.attributes = attributes || {};
|
|
8879
|
-
if (
|
|
8990
|
+
if (this.config.timestamps) {
|
|
8880
8991
|
this.attributes.createdAt = "string|optional";
|
|
8881
8992
|
this.attributes.updatedAt = "string|optional";
|
|
8882
|
-
if (!this.
|
|
8883
|
-
this.
|
|
8993
|
+
if (!this.config.partitions) {
|
|
8994
|
+
this.config.partitions = {};
|
|
8995
|
+
}
|
|
8996
|
+
if (!this.config.partitions.byCreatedDate) {
|
|
8997
|
+
this.config.partitions.byCreatedDate = {
|
|
8884
8998
|
fields: {
|
|
8885
8999
|
createdAt: "date|maxlength:10"
|
|
8886
9000
|
}
|
|
8887
9001
|
};
|
|
8888
9002
|
}
|
|
8889
|
-
if (!this.
|
|
8890
|
-
this.
|
|
9003
|
+
if (!this.config.partitions.byUpdatedDate) {
|
|
9004
|
+
this.config.partitions.byUpdatedDate = {
|
|
8891
9005
|
fields: {
|
|
8892
9006
|
updatedAt: "date|maxlength:10"
|
|
8893
9007
|
}
|
|
@@ -8900,25 +9014,47 @@ class Resource extends EventEmitter {
|
|
|
8900
9014
|
passphrase,
|
|
8901
9015
|
version: this.version,
|
|
8902
9016
|
options: {
|
|
8903
|
-
|
|
8904
|
-
allNestedObjectsOptional: this.
|
|
9017
|
+
autoDecrypt: this.config.autoDecrypt,
|
|
9018
|
+
allNestedObjectsOptional: this.config.allNestedObjectsOptional
|
|
8905
9019
|
}
|
|
8906
9020
|
});
|
|
8907
|
-
this.validatePartitions();
|
|
8908
9021
|
this.setupPartitionHooks();
|
|
8909
|
-
|
|
8910
|
-
|
|
9022
|
+
this.validatePartitions();
|
|
9023
|
+
if (hooks) {
|
|
9024
|
+
for (const [event, hooksArr] of Object.entries(hooks)) {
|
|
8911
9025
|
if (Array.isArray(hooksArr) && this.hooks[event]) {
|
|
8912
9026
|
for (const fn of hooksArr) {
|
|
8913
|
-
|
|
9027
|
+
if (typeof fn === "function") {
|
|
9028
|
+
this.hooks[event].push(fn.bind(this));
|
|
9029
|
+
}
|
|
8914
9030
|
}
|
|
8915
9031
|
}
|
|
8916
9032
|
}
|
|
8917
9033
|
}
|
|
8918
9034
|
}
|
|
9035
|
+
/**
|
|
9036
|
+
* Get resource options (for backward compatibility with tests)
|
|
9037
|
+
*/
|
|
9038
|
+
get options() {
|
|
9039
|
+
return {
|
|
9040
|
+
timestamps: this.config.timestamps,
|
|
9041
|
+
partitions: this.config.partitions || {},
|
|
9042
|
+
cache: this.config.cache,
|
|
9043
|
+
autoDecrypt: this.config.autoDecrypt,
|
|
9044
|
+
paranoid: this.config.paranoid,
|
|
9045
|
+
allNestedObjectsOptional: this.config.allNestedObjectsOptional
|
|
9046
|
+
};
|
|
9047
|
+
}
|
|
8919
9048
|
export() {
|
|
8920
9049
|
const exported = this.schema.export();
|
|
8921
9050
|
exported.behavior = this.behavior;
|
|
9051
|
+
exported.timestamps = this.config.timestamps;
|
|
9052
|
+
exported.partitions = this.config.partitions || {};
|
|
9053
|
+
exported.paranoid = this.config.paranoid;
|
|
9054
|
+
exported.allNestedObjectsOptional = this.config.allNestedObjectsOptional;
|
|
9055
|
+
exported.autoDecrypt = this.config.autoDecrypt;
|
|
9056
|
+
exported.cache = this.config.cache;
|
|
9057
|
+
exported.hooks = this.hooks;
|
|
8922
9058
|
return exported;
|
|
8923
9059
|
}
|
|
8924
9060
|
/**
|
|
@@ -8928,18 +9064,21 @@ class Resource extends EventEmitter {
|
|
|
8928
9064
|
updateAttributes(newAttributes) {
|
|
8929
9065
|
const oldAttributes = this.attributes;
|
|
8930
9066
|
this.attributes = newAttributes;
|
|
8931
|
-
if (this.
|
|
9067
|
+
if (this.config.timestamps) {
|
|
8932
9068
|
newAttributes.createdAt = "string|optional";
|
|
8933
9069
|
newAttributes.updatedAt = "string|optional";
|
|
8934
|
-
if (!this.
|
|
8935
|
-
this.
|
|
9070
|
+
if (!this.config.partitions) {
|
|
9071
|
+
this.config.partitions = {};
|
|
9072
|
+
}
|
|
9073
|
+
if (!this.config.partitions.byCreatedDate) {
|
|
9074
|
+
this.config.partitions.byCreatedDate = {
|
|
8936
9075
|
fields: {
|
|
8937
9076
|
createdAt: "date|maxlength:10"
|
|
8938
9077
|
}
|
|
8939
9078
|
};
|
|
8940
9079
|
}
|
|
8941
|
-
if (!this.
|
|
8942
|
-
this.
|
|
9080
|
+
if (!this.config.partitions.byUpdatedDate) {
|
|
9081
|
+
this.config.partitions.byUpdatedDate = {
|
|
8943
9082
|
fields: {
|
|
8944
9083
|
updatedAt: "date|maxlength:10"
|
|
8945
9084
|
}
|
|
@@ -8951,10 +9090,13 @@ class Resource extends EventEmitter {
|
|
|
8951
9090
|
attributes: newAttributes,
|
|
8952
9091
|
passphrase: this.passphrase,
|
|
8953
9092
|
version: this.version,
|
|
8954
|
-
options:
|
|
9093
|
+
options: {
|
|
9094
|
+
autoDecrypt: this.config.autoDecrypt,
|
|
9095
|
+
allNestedObjectsOptional: this.config.allNestedObjectsOptional
|
|
9096
|
+
}
|
|
8955
9097
|
});
|
|
8956
|
-
this.validatePartitions();
|
|
8957
9098
|
this.setupPartitionHooks();
|
|
9099
|
+
this.validatePartitions();
|
|
8958
9100
|
return { oldAttributes, newAttributes };
|
|
8959
9101
|
}
|
|
8960
9102
|
/**
|
|
@@ -8985,15 +9127,24 @@ class Resource extends EventEmitter {
|
|
|
8985
9127
|
* Setup automatic partition hooks
|
|
8986
9128
|
*/
|
|
8987
9129
|
setupPartitionHooks() {
|
|
8988
|
-
|
|
8989
|
-
|
|
9130
|
+
if (!this.config.partitions) {
|
|
9131
|
+
return;
|
|
9132
|
+
}
|
|
9133
|
+
const partitions = this.config.partitions;
|
|
9134
|
+
if (Object.keys(partitions).length === 0) {
|
|
8990
9135
|
return;
|
|
8991
9136
|
}
|
|
8992
|
-
this.
|
|
9137
|
+
if (!this.hooks.afterInsert) {
|
|
9138
|
+
this.hooks.afterInsert = [];
|
|
9139
|
+
}
|
|
9140
|
+
this.hooks.afterInsert.push(async (data) => {
|
|
8993
9141
|
await this.createPartitionReferences(data);
|
|
8994
9142
|
return data;
|
|
8995
9143
|
});
|
|
8996
|
-
this.
|
|
9144
|
+
if (!this.hooks.afterDelete) {
|
|
9145
|
+
this.hooks.afterDelete = [];
|
|
9146
|
+
}
|
|
9147
|
+
this.hooks.afterDelete.push(async (data) => {
|
|
8997
9148
|
await this.deletePartitionReferences(data);
|
|
8998
9149
|
return data;
|
|
8999
9150
|
});
|
|
@@ -9018,8 +9169,11 @@ class Resource extends EventEmitter {
|
|
|
9018
9169
|
* @throws {Error} If partition fields don't exist in current schema
|
|
9019
9170
|
*/
|
|
9020
9171
|
validatePartitions() {
|
|
9021
|
-
|
|
9022
|
-
|
|
9172
|
+
if (!this.config.partitions) {
|
|
9173
|
+
return;
|
|
9174
|
+
}
|
|
9175
|
+
const partitions = this.config.partitions;
|
|
9176
|
+
if (Object.keys(partitions).length === 0) {
|
|
9023
9177
|
return;
|
|
9024
9178
|
}
|
|
9025
9179
|
const currentAttributes = Object.keys(this.attributes || {});
|
|
@@ -9126,10 +9280,10 @@ class Resource extends EventEmitter {
|
|
|
9126
9280
|
* // Returns: null
|
|
9127
9281
|
*/
|
|
9128
9282
|
getPartitionKey({ partitionName, id, data }) {
|
|
9129
|
-
|
|
9130
|
-
if (!partition) {
|
|
9283
|
+
if (!this.config.partitions || !this.config.partitions[partitionName]) {
|
|
9131
9284
|
throw new Error(`Partition '${partitionName}' not found`);
|
|
9132
9285
|
}
|
|
9286
|
+
const partition = this.config.partitions[partitionName];
|
|
9133
9287
|
const partitionSegments = [];
|
|
9134
9288
|
const sortedFields = Object.entries(partition.fields).sort(([a], [b]) => a.localeCompare(b));
|
|
9135
9289
|
for (const [fieldName, rule] of sortedFields) {
|
|
@@ -9185,6 +9339,12 @@ class Resource extends EventEmitter {
|
|
|
9185
9339
|
* name: 'Jane Smith',
|
|
9186
9340
|
* email: 'jane@example.com'
|
|
9187
9341
|
* });
|
|
9342
|
+
*
|
|
9343
|
+
* // Insert with auto-generated password for secret field
|
|
9344
|
+
* const user = await resource.insert({
|
|
9345
|
+
* name: 'John Doe',
|
|
9346
|
+
* email: 'john@example.com',
|
|
9347
|
+
* });
|
|
9188
9348
|
*/
|
|
9189
9349
|
async insert({ id, ...attributes }) {
|
|
9190
9350
|
if (this.options.timestamps) {
|
|
@@ -9280,7 +9440,7 @@ class Resource extends EventEmitter {
|
|
|
9280
9440
|
passphrase: this.passphrase,
|
|
9281
9441
|
version: objectVersion,
|
|
9282
9442
|
options: {
|
|
9283
|
-
...this.
|
|
9443
|
+
...this.config,
|
|
9284
9444
|
autoDecrypt: false,
|
|
9285
9445
|
// Disable decryption
|
|
9286
9446
|
autoEncrypt: false
|
|
@@ -9367,7 +9527,7 @@ class Resource extends EventEmitter {
|
|
|
9367
9527
|
*/
|
|
9368
9528
|
async update(id, attributes) {
|
|
9369
9529
|
const live = await this.get(id);
|
|
9370
|
-
if (this.
|
|
9530
|
+
if (this.config.timestamps) {
|
|
9371
9531
|
attributes.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9372
9532
|
}
|
|
9373
9533
|
const preProcessedData = await this.executeHooks("preUpdate", attributes);
|
|
@@ -9489,7 +9649,7 @@ class Resource extends EventEmitter {
|
|
|
9489
9649
|
async count({ partition = null, partitionValues = {} } = {}) {
|
|
9490
9650
|
let prefix;
|
|
9491
9651
|
if (partition && Object.keys(partitionValues).length > 0) {
|
|
9492
|
-
const partitionDef = this.
|
|
9652
|
+
const partitionDef = this.config.partitions[partition];
|
|
9493
9653
|
if (!partitionDef) {
|
|
9494
9654
|
throw new Error(`Partition '${partition}' not found`);
|
|
9495
9655
|
}
|
|
@@ -9574,9 +9734,9 @@ class Resource extends EventEmitter {
|
|
|
9574
9734
|
return results;
|
|
9575
9735
|
}
|
|
9576
9736
|
async deleteAll() {
|
|
9577
|
-
if (this.
|
|
9737
|
+
if (this.config.paranoid !== false) {
|
|
9578
9738
|
throw new Error(
|
|
9579
|
-
`deleteAll() is a dangerous operation and requires paranoid: false option. Current paranoid setting: ${this.
|
|
9739
|
+
`deleteAll() is a dangerous operation and requires paranoid: false option. Current paranoid setting: ${this.config.paranoid}`
|
|
9580
9740
|
);
|
|
9581
9741
|
}
|
|
9582
9742
|
const prefix = `resource=${this.name}/v=${this.version}`;
|
|
@@ -9593,9 +9753,9 @@ class Resource extends EventEmitter {
|
|
|
9593
9753
|
* @returns {Promise<Object>} Deletion report
|
|
9594
9754
|
*/
|
|
9595
9755
|
async deleteAllData() {
|
|
9596
|
-
if (this.
|
|
9756
|
+
if (this.config.paranoid !== false) {
|
|
9597
9757
|
throw new Error(
|
|
9598
|
-
`deleteAllData() is a dangerous operation and requires paranoid: false option. Current paranoid setting: ${this.
|
|
9758
|
+
`deleteAllData() is a dangerous operation and requires paranoid: false option. Current paranoid setting: ${this.config.paranoid}`
|
|
9599
9759
|
);
|
|
9600
9760
|
}
|
|
9601
9761
|
const prefix = `resource=${this.name}`;
|
|
@@ -9638,10 +9798,10 @@ class Resource extends EventEmitter {
|
|
|
9638
9798
|
async listIds({ partition = null, partitionValues = {}, limit, offset = 0 } = {}) {
|
|
9639
9799
|
let prefix;
|
|
9640
9800
|
if (partition && Object.keys(partitionValues).length > 0) {
|
|
9641
|
-
|
|
9642
|
-
if (!partitionDef) {
|
|
9801
|
+
if (!this.config.partitions || !this.config.partitions[partition]) {
|
|
9643
9802
|
throw new Error(`Partition '${partition}' not found`);
|
|
9644
9803
|
}
|
|
9804
|
+
const partitionDef = this.config.partitions[partition];
|
|
9645
9805
|
const partitionSegments = [];
|
|
9646
9806
|
const sortedFields = Object.entries(partitionDef.fields).sort(([a], [b]) => a.localeCompare(b));
|
|
9647
9807
|
for (const [fieldName, rule] of sortedFields) {
|
|
@@ -9732,10 +9892,10 @@ class Resource extends EventEmitter {
|
|
|
9732
9892
|
this.emit("list", { partition, partitionValues, count: validResults2.length, errors: errors2.length });
|
|
9733
9893
|
return validResults2;
|
|
9734
9894
|
}
|
|
9735
|
-
|
|
9736
|
-
if (!partitionDef) {
|
|
9895
|
+
if (!this.config.partitions || !this.config.partitions[partition]) {
|
|
9737
9896
|
throw new Error(`Partition '${partition}' not found`);
|
|
9738
9897
|
}
|
|
9898
|
+
const partitionDef = this.config.partitions[partition];
|
|
9739
9899
|
const partitionSegments = [];
|
|
9740
9900
|
const sortedFields = Object.entries(partitionDef.fields).sort(([a], [b]) => a.localeCompare(b));
|
|
9741
9901
|
for (const [fieldName, rule] of sortedFields) {
|
|
@@ -10040,16 +10200,14 @@ class Resource extends EventEmitter {
|
|
|
10040
10200
|
}
|
|
10041
10201
|
/**
|
|
10042
10202
|
* Generate definition hash for this resource
|
|
10043
|
-
* @returns {string} SHA256 hash of the
|
|
10203
|
+
* @returns {string} SHA256 hash of the resource definition (name + attributes)
|
|
10044
10204
|
*/
|
|
10045
10205
|
getDefinitionHash() {
|
|
10046
|
-
const
|
|
10047
|
-
|
|
10048
|
-
|
|
10049
|
-
|
|
10050
|
-
|
|
10051
|
-
}
|
|
10052
|
-
const stableString = jsonStableStringify(stableAttributes);
|
|
10206
|
+
const definition = {
|
|
10207
|
+
attributes: this.attributes,
|
|
10208
|
+
behavior: this.behavior
|
|
10209
|
+
};
|
|
10210
|
+
const stableString = jsonStableStringify(definition);
|
|
10053
10211
|
return `sha256:${crypto.createHash("sha256").update(stableString).digest("hex")}`;
|
|
10054
10212
|
}
|
|
10055
10213
|
/**
|
|
@@ -10078,7 +10236,7 @@ class Resource extends EventEmitter {
|
|
|
10078
10236
|
passphrase: this.passphrase,
|
|
10079
10237
|
version,
|
|
10080
10238
|
options: {
|
|
10081
|
-
...this.
|
|
10239
|
+
...this.config,
|
|
10082
10240
|
// For older versions, be more lenient with decryption
|
|
10083
10241
|
autoDecrypt: true,
|
|
10084
10242
|
autoEncrypt: true
|
|
@@ -10095,7 +10253,7 @@ class Resource extends EventEmitter {
|
|
|
10095
10253
|
* @param {Object} data - Inserted object data
|
|
10096
10254
|
*/
|
|
10097
10255
|
async createPartitionReferences(data) {
|
|
10098
|
-
const partitions = this.
|
|
10256
|
+
const partitions = this.config.partitions;
|
|
10099
10257
|
if (!partitions || Object.keys(partitions).length === 0) {
|
|
10100
10258
|
return;
|
|
10101
10259
|
}
|
|
@@ -10126,7 +10284,7 @@ class Resource extends EventEmitter {
|
|
|
10126
10284
|
* @param {Object} data - Deleted object data
|
|
10127
10285
|
*/
|
|
10128
10286
|
async deletePartitionReferences(data) {
|
|
10129
|
-
const partitions = this.
|
|
10287
|
+
const partitions = this.config.partitions;
|
|
10130
10288
|
if (!partitions || Object.keys(partitions).length === 0) {
|
|
10131
10289
|
return;
|
|
10132
10290
|
}
|
|
@@ -10218,7 +10376,7 @@ class Resource extends EventEmitter {
|
|
|
10218
10376
|
* @param {Object} data - Updated object data
|
|
10219
10377
|
*/
|
|
10220
10378
|
async updatePartitionReferences(data) {
|
|
10221
|
-
const partitions = this.
|
|
10379
|
+
const partitions = this.config.partitions;
|
|
10222
10380
|
if (!partitions || Object.keys(partitions).length === 0) {
|
|
10223
10381
|
return;
|
|
10224
10382
|
}
|
|
@@ -10274,10 +10432,10 @@ class Resource extends EventEmitter {
|
|
|
10274
10432
|
* });
|
|
10275
10433
|
*/
|
|
10276
10434
|
async getFromPartition({ id, partitionName, partitionValues = {} }) {
|
|
10277
|
-
|
|
10278
|
-
if (!partition) {
|
|
10435
|
+
if (!this.config.partitions || !this.config.partitions[partitionName]) {
|
|
10279
10436
|
throw new Error(`Partition '${partitionName}' not found`);
|
|
10280
10437
|
}
|
|
10438
|
+
const partition = this.config.partitions[partitionName];
|
|
10281
10439
|
const partitionSegments = [];
|
|
10282
10440
|
const sortedFields = Object.entries(partition.fields).sort(([a], [b]) => a.localeCompare(b));
|
|
10283
10441
|
for (const [fieldName, rule] of sortedFields) {
|
|
@@ -10325,6 +10483,98 @@ class Resource extends EventEmitter {
|
|
|
10325
10483
|
return data;
|
|
10326
10484
|
}
|
|
10327
10485
|
}
|
|
10486
|
+
function validateResourceConfig(config) {
|
|
10487
|
+
const errors = [];
|
|
10488
|
+
if (!config.name) {
|
|
10489
|
+
errors.push("Resource 'name' is required");
|
|
10490
|
+
} else if (typeof config.name !== "string") {
|
|
10491
|
+
errors.push("Resource 'name' must be a string");
|
|
10492
|
+
} else if (config.name.trim() === "") {
|
|
10493
|
+
errors.push("Resource 'name' cannot be empty");
|
|
10494
|
+
}
|
|
10495
|
+
if (!config.client) {
|
|
10496
|
+
errors.push("S3 'client' is required");
|
|
10497
|
+
}
|
|
10498
|
+
if (!config.attributes) {
|
|
10499
|
+
errors.push("Resource 'attributes' are required");
|
|
10500
|
+
} else if (typeof config.attributes !== "object" || Array.isArray(config.attributes)) {
|
|
10501
|
+
errors.push("Resource 'attributes' must be an object");
|
|
10502
|
+
} else if (Object.keys(config.attributes).length === 0) {
|
|
10503
|
+
errors.push("Resource 'attributes' cannot be empty");
|
|
10504
|
+
}
|
|
10505
|
+
if (config.version !== void 0 && typeof config.version !== "string") {
|
|
10506
|
+
errors.push("Resource 'version' must be a string");
|
|
10507
|
+
}
|
|
10508
|
+
if (config.behavior !== void 0 && typeof config.behavior !== "string") {
|
|
10509
|
+
errors.push("Resource 'behavior' must be a string");
|
|
10510
|
+
}
|
|
10511
|
+
if (config.passphrase !== void 0 && typeof config.passphrase !== "string") {
|
|
10512
|
+
errors.push("Resource 'passphrase' must be a string");
|
|
10513
|
+
}
|
|
10514
|
+
if (config.parallelism !== void 0) {
|
|
10515
|
+
if (typeof config.parallelism !== "number" || !Number.isInteger(config.parallelism)) {
|
|
10516
|
+
errors.push("Resource 'parallelism' must be an integer");
|
|
10517
|
+
} else if (config.parallelism < 1) {
|
|
10518
|
+
errors.push("Resource 'parallelism' must be greater than 0");
|
|
10519
|
+
}
|
|
10520
|
+
}
|
|
10521
|
+
if (config.observers !== void 0 && !Array.isArray(config.observers)) {
|
|
10522
|
+
errors.push("Resource 'observers' must be an array");
|
|
10523
|
+
}
|
|
10524
|
+
const booleanFields = ["cache", "autoDecrypt", "timestamps", "paranoid", "allNestedObjectsOptional"];
|
|
10525
|
+
for (const field of booleanFields) {
|
|
10526
|
+
if (config[field] !== void 0 && typeof config[field] !== "boolean") {
|
|
10527
|
+
errors.push(`Resource '${field}' must be a boolean`);
|
|
10528
|
+
}
|
|
10529
|
+
}
|
|
10530
|
+
if (config.partitions !== void 0) {
|
|
10531
|
+
if (typeof config.partitions !== "object" || Array.isArray(config.partitions)) {
|
|
10532
|
+
errors.push("Resource 'partitions' must be an object");
|
|
10533
|
+
} else {
|
|
10534
|
+
for (const [partitionName, partitionDef] of Object.entries(config.partitions)) {
|
|
10535
|
+
if (typeof partitionDef !== "object" || Array.isArray(partitionDef)) {
|
|
10536
|
+
errors.push(`Partition '${partitionName}' must be an object`);
|
|
10537
|
+
} else if (!partitionDef.fields) {
|
|
10538
|
+
errors.push(`Partition '${partitionName}' must have a 'fields' property`);
|
|
10539
|
+
} else if (typeof partitionDef.fields !== "object" || Array.isArray(partitionDef.fields)) {
|
|
10540
|
+
errors.push(`Partition '${partitionName}.fields' must be an object`);
|
|
10541
|
+
} else {
|
|
10542
|
+
for (const [fieldName, fieldType] of Object.entries(partitionDef.fields)) {
|
|
10543
|
+
if (typeof fieldType !== "string") {
|
|
10544
|
+
errors.push(`Partition '${partitionName}.fields.${fieldName}' must be a string`);
|
|
10545
|
+
}
|
|
10546
|
+
}
|
|
10547
|
+
}
|
|
10548
|
+
}
|
|
10549
|
+
}
|
|
10550
|
+
}
|
|
10551
|
+
if (config.hooks !== void 0) {
|
|
10552
|
+
if (typeof config.hooks !== "object" || Array.isArray(config.hooks)) {
|
|
10553
|
+
errors.push("Resource 'hooks' must be an object");
|
|
10554
|
+
} else {
|
|
10555
|
+
const validHookEvents = ["preInsert", "afterInsert", "preUpdate", "afterUpdate", "preDelete", "afterDelete"];
|
|
10556
|
+
for (const [event, hooksArr] of Object.entries(config.hooks)) {
|
|
10557
|
+
if (!validHookEvents.includes(event)) {
|
|
10558
|
+
errors.push(`Invalid hook event '${event}'. Valid events: ${validHookEvents.join(", ")}`);
|
|
10559
|
+
} else if (!Array.isArray(hooksArr)) {
|
|
10560
|
+
errors.push(`Resource 'hooks.${event}' must be an array`);
|
|
10561
|
+
} else {
|
|
10562
|
+
for (let i = 0; i < hooksArr.length; i++) {
|
|
10563
|
+
const hook = hooksArr[i];
|
|
10564
|
+
if (typeof hook !== "function") {
|
|
10565
|
+
if (typeof hook === "string") continue;
|
|
10566
|
+
continue;
|
|
10567
|
+
}
|
|
10568
|
+
}
|
|
10569
|
+
}
|
|
10570
|
+
}
|
|
10571
|
+
}
|
|
10572
|
+
}
|
|
10573
|
+
return {
|
|
10574
|
+
isValid: errors.length === 0,
|
|
10575
|
+
errors
|
|
10576
|
+
};
|
|
10577
|
+
}
|
|
10328
10578
|
|
|
10329
10579
|
class Database extends EventEmitter {
|
|
10330
10580
|
constructor(options) {
|
|
@@ -10332,7 +10582,7 @@ class Database extends EventEmitter {
|
|
|
10332
10582
|
this.version = "1";
|
|
10333
10583
|
this.s3dbVersion = (() => {
|
|
10334
10584
|
try {
|
|
10335
|
-
return true ? "4.1.
|
|
10585
|
+
return true ? "4.1.12" : "latest";
|
|
10336
10586
|
} catch (e) {
|
|
10337
10587
|
return "latest";
|
|
10338
10588
|
}
|
|
@@ -10345,10 +10595,21 @@ class Database extends EventEmitter {
|
|
|
10345
10595
|
this.plugins = options.plugins || [];
|
|
10346
10596
|
this.cache = options.cache;
|
|
10347
10597
|
this.passphrase = options.passphrase || "secret";
|
|
10598
|
+
let connectionString = options.connectionString;
|
|
10599
|
+
if (!connectionString && (options.bucket || options.accessKeyId || options.secretAccessKey)) {
|
|
10600
|
+
connectionString = ConnectionString.buildFromParams({
|
|
10601
|
+
bucket: options.bucket,
|
|
10602
|
+
region: options.region,
|
|
10603
|
+
accessKeyId: options.accessKeyId,
|
|
10604
|
+
secretAccessKey: options.secretAccessKey,
|
|
10605
|
+
endpoint: options.endpoint,
|
|
10606
|
+
forcePathStyle: options.forcePathStyle
|
|
10607
|
+
});
|
|
10608
|
+
}
|
|
10348
10609
|
this.client = options.client || new Client({
|
|
10349
10610
|
verbose: this.verbose,
|
|
10350
10611
|
parallelism: this.parallelism,
|
|
10351
|
-
connectionString
|
|
10612
|
+
connectionString
|
|
10352
10613
|
});
|
|
10353
10614
|
this.bucket = this.client.bucket;
|
|
10354
10615
|
this.keyPrefix = this.client.keyPrefix;
|
|
@@ -10373,15 +10634,18 @@ class Database extends EventEmitter {
|
|
|
10373
10634
|
name,
|
|
10374
10635
|
client: this.client,
|
|
10375
10636
|
version: currentVersion,
|
|
10376
|
-
options: {
|
|
10377
|
-
...versionData.options,
|
|
10378
|
-
partitions: resourceMetadata.partitions || versionData.options?.partitions || {}
|
|
10379
|
-
},
|
|
10380
10637
|
attributes: versionData.attributes,
|
|
10381
10638
|
behavior: versionData.behavior || "user-management",
|
|
10382
10639
|
parallelism: this.parallelism,
|
|
10383
10640
|
passphrase: this.passphrase,
|
|
10384
|
-
observers: [this]
|
|
10641
|
+
observers: [this],
|
|
10642
|
+
cache: this.cache,
|
|
10643
|
+
timestamps: versionData.options?.timestamps || false,
|
|
10644
|
+
partitions: resourceMetadata.partitions || versionData.options?.partitions || {},
|
|
10645
|
+
paranoid: versionData.options?.paranoid !== false,
|
|
10646
|
+
allNestedObjectsOptional: versionData.options?.allNestedObjectsOptional || false,
|
|
10647
|
+
autoDecrypt: versionData.options?.autoDecrypt !== false,
|
|
10648
|
+
hooks: versionData.options?.hooks || {}
|
|
10385
10649
|
});
|
|
10386
10650
|
}
|
|
10387
10651
|
}
|
|
@@ -10450,7 +10714,7 @@ class Database extends EventEmitter {
|
|
|
10450
10714
|
generateDefinitionHash(definition, behavior = void 0) {
|
|
10451
10715
|
const attributes = definition.attributes;
|
|
10452
10716
|
const stableAttributes = { ...attributes };
|
|
10453
|
-
if (definition.
|
|
10717
|
+
if (definition.timestamps) {
|
|
10454
10718
|
delete stableAttributes.createdAt;
|
|
10455
10719
|
delete stableAttributes.updatedAt;
|
|
10456
10720
|
}
|
|
@@ -10512,14 +10776,22 @@ class Database extends EventEmitter {
|
|
|
10512
10776
|
}
|
|
10513
10777
|
metadata.resources[name] = {
|
|
10514
10778
|
currentVersion: version,
|
|
10515
|
-
partitions:
|
|
10779
|
+
partitions: resource.config.partitions || {},
|
|
10516
10780
|
versions: {
|
|
10517
10781
|
...existingResource?.versions,
|
|
10518
10782
|
// Preserve previous versions
|
|
10519
10783
|
[version]: {
|
|
10520
10784
|
hash: definitionHash,
|
|
10521
10785
|
attributes: resourceDef.attributes,
|
|
10522
|
-
options:
|
|
10786
|
+
options: {
|
|
10787
|
+
timestamps: resource.config.timestamps,
|
|
10788
|
+
partitions: resource.config.partitions,
|
|
10789
|
+
paranoid: resource.config.paranoid,
|
|
10790
|
+
allNestedObjectsOptional: resource.config.allNestedObjectsOptional,
|
|
10791
|
+
autoDecrypt: resource.config.autoDecrypt,
|
|
10792
|
+
cache: resource.config.cache,
|
|
10793
|
+
hooks: resourceDef.hooks || {}
|
|
10794
|
+
},
|
|
10523
10795
|
behavior: resourceDef.behavior || "user-management",
|
|
10524
10796
|
createdAt: isNewVersion ? (/* @__PURE__ */ new Date()).toISOString() : existingVersionData?.createdAt
|
|
10525
10797
|
}
|
|
@@ -10572,10 +10844,9 @@ class Database extends EventEmitter {
|
|
|
10572
10844
|
observers: [],
|
|
10573
10845
|
client: this.client,
|
|
10574
10846
|
version: "temp",
|
|
10575
|
-
|
|
10576
|
-
|
|
10577
|
-
|
|
10578
|
-
}
|
|
10847
|
+
passphrase: this.passphrase,
|
|
10848
|
+
cache: this.cache,
|
|
10849
|
+
...options
|
|
10579
10850
|
});
|
|
10580
10851
|
const newHash = this.generateDefinitionHash(tempResource.export(), behavior);
|
|
10581
10852
|
const existingHash = this.generateDefinitionHash(this.resources[name].export(), this.resources[name].behavior);
|
|
@@ -10615,7 +10886,7 @@ class Database extends EventEmitter {
|
|
|
10615
10886
|
async createResource({ name, attributes, options = {}, behavior = "user-management" }) {
|
|
10616
10887
|
if (this.resources[name]) {
|
|
10617
10888
|
const existingResource = this.resources[name];
|
|
10618
|
-
Object.assign(existingResource.
|
|
10889
|
+
Object.assign(existingResource.config, {
|
|
10619
10890
|
cache: this.cache,
|
|
10620
10891
|
...options
|
|
10621
10892
|
});
|
|
@@ -10642,10 +10913,9 @@ class Database extends EventEmitter {
|
|
|
10642
10913
|
observers: [this],
|
|
10643
10914
|
client: this.client,
|
|
10644
10915
|
version,
|
|
10645
|
-
|
|
10646
|
-
|
|
10647
|
-
|
|
10648
|
-
}
|
|
10916
|
+
passphrase: this.passphrase,
|
|
10917
|
+
cache: this.cache,
|
|
10918
|
+
...options
|
|
10649
10919
|
});
|
|
10650
10920
|
this.resources[name] = resource;
|
|
10651
10921
|
await this.uploadMetadataFile();
|
|
@@ -17347,6 +17617,7 @@ class CachePlugin extends Plugin {
|
|
|
17347
17617
|
}
|
|
17348
17618
|
}
|
|
17349
17619
|
|
|
17620
|
+
exports.AuthenticationError = AuthenticationError;
|
|
17350
17621
|
exports.BaseError = BaseError;
|
|
17351
17622
|
exports.Cache = Cache;
|
|
17352
17623
|
exports.CachePlugin = CachePlugin;
|
|
@@ -17354,6 +17625,8 @@ exports.Client = Client;
|
|
|
17354
17625
|
exports.ConnectionString = ConnectionString;
|
|
17355
17626
|
exports.CostsPlugin = CostsPlugin;
|
|
17356
17627
|
exports.Database = Database;
|
|
17628
|
+
exports.DatabaseError = DatabaseError;
|
|
17629
|
+
exports.EncryptionError = EncryptionError;
|
|
17357
17630
|
exports.ErrorMap = ErrorMap;
|
|
17358
17631
|
exports.InvalidResourceItem = InvalidResourceItem;
|
|
17359
17632
|
exports.MemoryCache = MemoryCache;
|
|
@@ -17361,20 +17634,28 @@ exports.MissingMetadata = MissingMetadata;
|
|
|
17361
17634
|
exports.NoSuchBucket = NoSuchBucket;
|
|
17362
17635
|
exports.NoSuchKey = NoSuchKey;
|
|
17363
17636
|
exports.NotFound = NotFound;
|
|
17637
|
+
exports.PermissionError = PermissionError;
|
|
17364
17638
|
exports.Plugin = Plugin;
|
|
17365
17639
|
exports.PluginObject = PluginObject;
|
|
17366
17640
|
exports.ResourceIdsPageReader = ResourceIdsPageReader;
|
|
17367
17641
|
exports.ResourceIdsReader = ResourceIdsReader;
|
|
17642
|
+
exports.ResourceNotFound = ResourceNotFound;
|
|
17643
|
+
exports.ResourceNotFoundError = ResourceNotFound;
|
|
17368
17644
|
exports.ResourceReader = ResourceReader;
|
|
17369
17645
|
exports.ResourceWriter = ResourceWriter;
|
|
17370
17646
|
exports.S3Cache = S3Cache;
|
|
17647
|
+
exports.S3DB = S3db;
|
|
17648
|
+
exports.S3DBError = S3DBError;
|
|
17371
17649
|
exports.S3_DEFAULT_ENDPOINT = S3_DEFAULT_ENDPOINT;
|
|
17372
17650
|
exports.S3_DEFAULT_REGION = S3_DEFAULT_REGION;
|
|
17373
17651
|
exports.S3db = S3db;
|
|
17652
|
+
exports.S3dbError = S3DBError;
|
|
17374
17653
|
exports.UnknownError = UnknownError;
|
|
17654
|
+
exports.ValidationError = ValidationError;
|
|
17375
17655
|
exports.Validator = Validator;
|
|
17376
17656
|
exports.ValidatorManager = ValidatorManager;
|
|
17377
17657
|
exports.decrypt = decrypt;
|
|
17658
|
+
exports.default = S3db;
|
|
17378
17659
|
exports.encrypt = encrypt;
|
|
17379
17660
|
exports.sha256 = sha256;
|
|
17380
17661
|
exports.streamToString = streamToString;
|