s3db.js 4.1.8 → 4.1.10

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
@@ -9267,6 +9267,58 @@ class Resource extends EventEmitter {
9267
9267
  this.emit("get", data);
9268
9268
  return data;
9269
9269
  } catch (error) {
9270
+ if (error.message.includes("Cipher job failed") || error.message.includes("OperationError") || error.originalError?.message?.includes("Cipher job failed")) {
9271
+ try {
9272
+ console.warn(`Decryption failed for resource ${id}, attempting to get raw metadata`);
9273
+ const request = await this.client.headObject(key);
9274
+ const objectVersion = this.extractVersionFromKey(key) || this.version;
9275
+ const tempSchema = new Schema({
9276
+ name: this.name,
9277
+ attributes: this.attributes,
9278
+ passphrase: this.passphrase,
9279
+ version: objectVersion,
9280
+ options: {
9281
+ ...this.options,
9282
+ autoDecrypt: false,
9283
+ // Disable decryption
9284
+ autoEncrypt: false
9285
+ // Disable encryption
9286
+ }
9287
+ });
9288
+ let metadata = await tempSchema.unmapper(request.Metadata);
9289
+ const behaviorImpl = getBehavior(this.behavior);
9290
+ let body = "";
9291
+ if (request.ContentLength > 0) {
9292
+ try {
9293
+ const fullObject = await this.client.getObject(key);
9294
+ body = await streamToString(fullObject.Body);
9295
+ } catch (bodyError) {
9296
+ console.warn(`Failed to read body for resource ${id}:`, bodyError.message);
9297
+ body = "";
9298
+ }
9299
+ }
9300
+ const { metadata: processedMetadata } = await behaviorImpl.handleGet({
9301
+ resource: this,
9302
+ metadata,
9303
+ body
9304
+ });
9305
+ let data = processedMetadata;
9306
+ data.id = id;
9307
+ data._contentLength = request.ContentLength;
9308
+ data._lastModified = request.LastModified;
9309
+ data._hasContent = request.ContentLength > 0;
9310
+ data._mimeType = request.ContentType || null;
9311
+ data._version = objectVersion;
9312
+ data._decryptionFailed = true;
9313
+ if (request.VersionId) data._versionId = request.VersionId;
9314
+ if (request.Expiration) data._expiresAt = request.Expiration;
9315
+ data._definitionHash = this.getDefinitionHash();
9316
+ this.emit("get", data);
9317
+ return data;
9318
+ } catch (fallbackError) {
9319
+ console.error(`Fallback attempt also failed for resource ${id}:`, fallbackError.message);
9320
+ }
9321
+ }
9270
9322
  const enhancedError = new Error(`Failed to get resource with id '${id}': ${error.message}`);
9271
9323
  enhancedError.originalError = error;
9272
9324
  enhancedError.resourceId = id;
@@ -9656,11 +9708,27 @@ class Resource extends EventEmitter {
9656
9708
  if (limit) {
9657
9709
  filteredIds2 = filteredIds2.slice(0, limit);
9658
9710
  }
9659
- const { results: results2 } = await PromisePool.for(filteredIds2).withConcurrency(this.parallelism).process(async (id) => {
9660
- return await this.get(id);
9711
+ const { results: results2, errors: errors2 } = await PromisePool.for(filteredIds2).withConcurrency(this.parallelism).handleError(async (error, id) => {
9712
+ console.warn(`Failed to get resource ${id}:`, error.message);
9713
+ return null;
9714
+ }).process(async (id) => {
9715
+ try {
9716
+ return await this.get(id);
9717
+ } catch (error) {
9718
+ if (error.message.includes("Cipher job failed") || error.message.includes("OperationError")) {
9719
+ console.warn(`Decryption failed for ${id}, returning basic info`);
9720
+ return {
9721
+ id,
9722
+ _decryptionFailed: true,
9723
+ _error: error.message
9724
+ };
9725
+ }
9726
+ throw error;
9727
+ }
9661
9728
  });
9662
- this.emit("list", { partition, partitionValues, count: results2.length });
9663
- return results2;
9729
+ const validResults2 = results2.filter((item) => item !== null);
9730
+ this.emit("list", { partition, partitionValues, count: validResults2.length, errors: errors2.length });
9731
+ return validResults2;
9664
9732
  }
9665
9733
  const partitionDef = this.options.partitions[partition];
9666
9734
  if (!partitionDef) {
@@ -9691,11 +9759,29 @@ class Resource extends EventEmitter {
9691
9759
  if (limit) {
9692
9760
  filteredIds = filteredIds.slice(0, limit);
9693
9761
  }
9694
- const { results } = await PromisePool.for(filteredIds).withConcurrency(this.parallelism).process(async (id) => {
9695
- return await this.getFromPartition({ id, partitionName: partition, partitionValues });
9762
+ const { results, errors } = await PromisePool.for(filteredIds).withConcurrency(this.parallelism).handleError(async (error, id) => {
9763
+ console.warn(`Failed to get partition resource ${id}:`, error.message);
9764
+ return null;
9765
+ }).process(async (id) => {
9766
+ try {
9767
+ return await this.getFromPartition({ id, partitionName: partition, partitionValues });
9768
+ } catch (error) {
9769
+ if (error.message.includes("Cipher job failed") || error.message.includes("OperationError")) {
9770
+ console.warn(`Decryption failed for partition resource ${id}, returning basic info`);
9771
+ return {
9772
+ id,
9773
+ _partition: partition,
9774
+ _partitionValues: partitionValues,
9775
+ _decryptionFailed: true,
9776
+ _error: error.message
9777
+ };
9778
+ }
9779
+ throw error;
9780
+ }
9696
9781
  });
9697
- this.emit("list", { partition, partitionValues, count: results.length });
9698
- return results;
9782
+ const validResults = results.filter((item) => item !== null);
9783
+ this.emit("list", { partition, partitionValues, count: validResults.length, errors: errors.length });
9784
+ return validResults;
9699
9785
  }
9700
9786
  /**
9701
9787
  * Get multiple resources by their IDs
@@ -9706,11 +9792,30 @@ class Resource extends EventEmitter {
9706
9792
  * users.forEach(user => console.log(user.name));
9707
9793
  */
9708
9794
  async getMany(ids) {
9709
- const { results } = await PromisePool.for(ids).withConcurrency(this.client.parallelism).process(async (id) => {
9795
+ const { results, errors } = await PromisePool.for(ids).withConcurrency(this.client.parallelism).handleError(async (error, id) => {
9796
+ console.warn(`Failed to get resource ${id}:`, error.message);
9797
+ return {
9798
+ id,
9799
+ _error: error.message,
9800
+ _decryptionFailed: error.message.includes("Cipher job failed") || error.message.includes("OperationError")
9801
+ };
9802
+ }).process(async (id) => {
9710
9803
  this.emit("id", id);
9711
- const data = await this.get(id);
9712
- this.emit("data", data);
9713
- return data;
9804
+ try {
9805
+ const data = await this.get(id);
9806
+ this.emit("data", data);
9807
+ return data;
9808
+ } catch (error) {
9809
+ if (error.message.includes("Cipher job failed") || error.message.includes("OperationError")) {
9810
+ console.warn(`Decryption failed for ${id}, returning basic info`);
9811
+ return {
9812
+ id,
9813
+ _decryptionFailed: true,
9814
+ _error: error.message
9815
+ };
9816
+ }
9817
+ throw error;
9818
+ }
9714
9819
  });
9715
9820
  this.emit("getMany", ids.length);
9716
9821
  return results;
@@ -9725,9 +9830,28 @@ class Resource extends EventEmitter {
9725
9830
  async getAll() {
9726
9831
  let ids = await this.listIds();
9727
9832
  if (ids.length === 0) return [];
9728
- const { results } = await PromisePool.for(ids).withConcurrency(this.client.parallelism).process(async (id) => {
9729
- const data = await this.get(id);
9730
- return data;
9833
+ const { results, errors } = await PromisePool.for(ids).withConcurrency(this.client.parallelism).handleError(async (error, id) => {
9834
+ console.warn(`Failed to get resource ${id}:`, error.message);
9835
+ return {
9836
+ id,
9837
+ _error: error.message,
9838
+ _decryptionFailed: error.message.includes("Cipher job failed") || error.message.includes("OperationError")
9839
+ };
9840
+ }).process(async (id) => {
9841
+ try {
9842
+ const data = await this.get(id);
9843
+ return data;
9844
+ } catch (error) {
9845
+ if (error.message.includes("Cipher job failed") || error.message.includes("OperationError")) {
9846
+ console.warn(`Decryption failed for ${id}, returning basic info`);
9847
+ return {
9848
+ id,
9849
+ _decryptionFailed: true,
9850
+ _error: error.message
9851
+ };
9852
+ }
9853
+ throw error;
9854
+ }
9731
9855
  });
9732
9856
  this.emit("getAll", results.length);
9733
9857
  return results;
@@ -9942,7 +10066,27 @@ class Resource extends EventEmitter {
9942
10066
  * @returns {Object} Schema object for the version
9943
10067
  */
9944
10068
  async getSchemaForVersion(version) {
9945
- return this.schema;
10069
+ if (version === this.version) {
10070
+ return this.schema;
10071
+ }
10072
+ try {
10073
+ const compatibleSchema = new Schema({
10074
+ name: this.name,
10075
+ attributes: this.attributes,
10076
+ passphrase: this.passphrase,
10077
+ version,
10078
+ options: {
10079
+ ...this.options,
10080
+ // For older versions, be more lenient with decryption
10081
+ autoDecrypt: true,
10082
+ autoEncrypt: true
10083
+ }
10084
+ });
10085
+ return compatibleSchema;
10086
+ } catch (error) {
10087
+ console.warn(`Failed to create compatible schema for version ${version}, using current schema:`, error.message);
10088
+ return this.schema;
10089
+ }
9946
10090
  }
9947
10091
  /**
9948
10092
  * Create partition references after insert
@@ -10186,7 +10330,7 @@ class Database extends EventEmitter {
10186
10330
  this.version = "1";
10187
10331
  this.s3dbVersion = (() => {
10188
10332
  try {
10189
- return true ? "4.1.7" : "latest";
10333
+ return true ? "4.1.9" : "latest";
10190
10334
  } catch (e) {
10191
10335
  return "latest";
10192
10336
  }