s3db.js 7.3.10 → 7.4.1
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 +164 -0
- package/dist/s3db.cjs.js +74 -4
- package/dist/s3db.cjs.min.js +1 -1
- package/dist/s3db.d.ts +6 -0
- package/dist/s3db.es.js +74 -4
- package/dist/s3db.es.min.js +1 -1
- package/dist/s3db.iife.js +74 -4
- package/dist/s3db.iife.min.js +1 -1
- package/package.json +1 -1
- package/src/client.class.js +41 -1
- package/src/database.class.js +2 -1
- package/src/resource.class.js +49 -1
- package/src/s3db.d.ts +6 -0
package/dist/s3db.d.ts
CHANGED
|
@@ -47,6 +47,7 @@ declare module 's3db.js' {
|
|
|
47
47
|
idSize?: number;
|
|
48
48
|
versioningEnabled?: boolean;
|
|
49
49
|
map?: any;
|
|
50
|
+
events?: EventListenerConfig;
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
/** Partition configuration */
|
|
@@ -65,6 +66,11 @@ declare module 's3db.js' {
|
|
|
65
66
|
afterDelete?: Function[];
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
/** Event listener configuration */
|
|
70
|
+
export interface EventListenerConfig {
|
|
71
|
+
[eventName: string]: Function | Function[];
|
|
72
|
+
}
|
|
73
|
+
|
|
68
74
|
/** Query options */
|
|
69
75
|
export interface QueryOptions {
|
|
70
76
|
limit?: number;
|
package/dist/s3db.es.js
CHANGED
|
@@ -9650,7 +9650,13 @@ class Client extends EventEmitter {
|
|
|
9650
9650
|
if (metadata) {
|
|
9651
9651
|
for (const [k, v] of Object.entries(metadata)) {
|
|
9652
9652
|
const validKey = String(k).replace(/[^a-zA-Z0-9\-_]/g, "_");
|
|
9653
|
-
|
|
9653
|
+
const stringValue = String(v);
|
|
9654
|
+
const hasSpecialChars = /[^\x00-\x7F]/.test(stringValue);
|
|
9655
|
+
if (hasSpecialChars) {
|
|
9656
|
+
stringMetadata[validKey] = Buffer.from(stringValue, "utf8").toString("base64");
|
|
9657
|
+
} else {
|
|
9658
|
+
stringMetadata[validKey] = stringValue;
|
|
9659
|
+
}
|
|
9654
9660
|
}
|
|
9655
9661
|
}
|
|
9656
9662
|
const options = {
|
|
@@ -9687,6 +9693,28 @@ class Client extends EventEmitter {
|
|
|
9687
9693
|
let response, error;
|
|
9688
9694
|
try {
|
|
9689
9695
|
response = await this.sendCommand(new GetObjectCommand(options));
|
|
9696
|
+
if (response.Metadata) {
|
|
9697
|
+
const decodedMetadata = {};
|
|
9698
|
+
for (const [key2, value] of Object.entries(response.Metadata)) {
|
|
9699
|
+
if (typeof value === "string") {
|
|
9700
|
+
try {
|
|
9701
|
+
const decoded = Buffer.from(value, "base64").toString("utf8");
|
|
9702
|
+
const hasSpecialChars = /[^\x00-\x7F]/.test(decoded);
|
|
9703
|
+
const isValidBase64 = Buffer.from(decoded, "utf8").toString("base64") === value;
|
|
9704
|
+
if (isValidBase64 && hasSpecialChars && decoded !== value) {
|
|
9705
|
+
decodedMetadata[key2] = decoded;
|
|
9706
|
+
} else {
|
|
9707
|
+
decodedMetadata[key2] = value;
|
|
9708
|
+
}
|
|
9709
|
+
} catch (decodeError) {
|
|
9710
|
+
decodedMetadata[key2] = value;
|
|
9711
|
+
}
|
|
9712
|
+
} else {
|
|
9713
|
+
decodedMetadata[key2] = value;
|
|
9714
|
+
}
|
|
9715
|
+
}
|
|
9716
|
+
response.Metadata = decodedMetadata;
|
|
9717
|
+
}
|
|
9690
9718
|
return response;
|
|
9691
9719
|
} catch (err) {
|
|
9692
9720
|
error = err;
|
|
@@ -11070,6 +11098,7 @@ class Resource extends EventEmitter {
|
|
|
11070
11098
|
* @param {Function} [config.idGenerator] - Custom ID generator function
|
|
11071
11099
|
* @param {number} [config.idSize=22] - Size for auto-generated IDs
|
|
11072
11100
|
* @param {boolean} [config.versioningEnabled=false] - Enable versioning for this resource
|
|
11101
|
+
* @param {Object} [config.events={}] - Event listeners to automatically add
|
|
11073
11102
|
* @example
|
|
11074
11103
|
* const users = new Resource({
|
|
11075
11104
|
* name: 'users',
|
|
@@ -11091,6 +11120,14 @@ class Resource extends EventEmitter {
|
|
|
11091
11120
|
* beforeInsert: [async (data) => {
|
|
11092
11121
|
* return data;
|
|
11093
11122
|
* }]
|
|
11123
|
+
* },
|
|
11124
|
+
* events: {
|
|
11125
|
+
* insert: (ev) => console.log('Inserted:', ev.id),
|
|
11126
|
+
* update: [
|
|
11127
|
+
* (ev) => console.warn('Update detected'),
|
|
11128
|
+
* (ev) => console.log('Updated:', ev.id)
|
|
11129
|
+
* ],
|
|
11130
|
+
* delete: (ev) => console.log('Deleted:', ev.id)
|
|
11094
11131
|
* }
|
|
11095
11132
|
* });
|
|
11096
11133
|
*
|
|
@@ -11143,7 +11180,8 @@ class Resource extends EventEmitter {
|
|
|
11143
11180
|
hooks = {},
|
|
11144
11181
|
idGenerator: customIdGenerator,
|
|
11145
11182
|
idSize = 22,
|
|
11146
|
-
versioningEnabled = false
|
|
11183
|
+
versioningEnabled = false,
|
|
11184
|
+
events = {}
|
|
11147
11185
|
} = config;
|
|
11148
11186
|
this.name = name;
|
|
11149
11187
|
this.client = client;
|
|
@@ -11185,6 +11223,19 @@ class Resource extends EventEmitter {
|
|
|
11185
11223
|
}
|
|
11186
11224
|
}
|
|
11187
11225
|
}
|
|
11226
|
+
if (events && Object.keys(events).length > 0) {
|
|
11227
|
+
for (const [eventName, listeners] of Object.entries(events)) {
|
|
11228
|
+
if (Array.isArray(listeners)) {
|
|
11229
|
+
for (const listener of listeners) {
|
|
11230
|
+
if (typeof listener === "function") {
|
|
11231
|
+
this.on(eventName, listener);
|
|
11232
|
+
}
|
|
11233
|
+
}
|
|
11234
|
+
} else if (typeof listeners === "function") {
|
|
11235
|
+
this.on(eventName, listeners);
|
|
11236
|
+
}
|
|
11237
|
+
}
|
|
11238
|
+
}
|
|
11188
11239
|
this._initMiddleware();
|
|
11189
11240
|
}
|
|
11190
11241
|
/**
|
|
@@ -13224,6 +13275,24 @@ function validateResourceConfig(config) {
|
|
|
13224
13275
|
}
|
|
13225
13276
|
}
|
|
13226
13277
|
}
|
|
13278
|
+
if (config.events !== void 0) {
|
|
13279
|
+
if (typeof config.events !== "object" || Array.isArray(config.events)) {
|
|
13280
|
+
errors.push("Resource 'events' must be an object");
|
|
13281
|
+
} else {
|
|
13282
|
+
for (const [eventName, listeners] of Object.entries(config.events)) {
|
|
13283
|
+
if (Array.isArray(listeners)) {
|
|
13284
|
+
for (let i = 0; i < listeners.length; i++) {
|
|
13285
|
+
const listener = listeners[i];
|
|
13286
|
+
if (typeof listener !== "function") {
|
|
13287
|
+
errors.push(`Resource 'events.${eventName}[${i}]' must be a function`);
|
|
13288
|
+
}
|
|
13289
|
+
}
|
|
13290
|
+
} else if (typeof listeners !== "function") {
|
|
13291
|
+
errors.push(`Resource 'events.${eventName}' must be a function or array of functions`);
|
|
13292
|
+
}
|
|
13293
|
+
}
|
|
13294
|
+
}
|
|
13295
|
+
}
|
|
13227
13296
|
return {
|
|
13228
13297
|
isValid: errors.length === 0,
|
|
13229
13298
|
errors
|
|
@@ -13236,7 +13305,7 @@ class Database extends EventEmitter {
|
|
|
13236
13305
|
super();
|
|
13237
13306
|
this.version = "1";
|
|
13238
13307
|
this.s3dbVersion = (() => {
|
|
13239
|
-
const [ok, err, version] = try_fn_default(() => true ? "7.
|
|
13308
|
+
const [ok, err, version] = try_fn_default(() => true ? "7.4.1" : "latest");
|
|
13240
13309
|
return ok ? version : "latest";
|
|
13241
13310
|
})();
|
|
13242
13311
|
this.resources = {};
|
|
@@ -13607,7 +13676,8 @@ class Database extends EventEmitter {
|
|
|
13607
13676
|
versioningEnabled: this.versioningEnabled,
|
|
13608
13677
|
map: config.map,
|
|
13609
13678
|
idGenerator: config.idGenerator,
|
|
13610
|
-
idSize: config.idSize
|
|
13679
|
+
idSize: config.idSize,
|
|
13680
|
+
events: config.events || {}
|
|
13611
13681
|
});
|
|
13612
13682
|
resource.database = this;
|
|
13613
13683
|
this.resources[name] = resource;
|