s3db.js 13.2.1 → 13.2.2

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
@@ -23916,7 +23916,7 @@ ${errorDetails}`,
23916
23916
  data = await this.applyVersionMapping(data, objectVersion, this.version);
23917
23917
  }
23918
23918
  data = await this.executeHooks("afterGet", data);
23919
- this._emitWithDeprecation("get", "fetched", data, data.id);
23919
+ this._emitStandardized("get", "fetched", data, data.id);
23920
23920
  const value = data;
23921
23921
  return value;
23922
23922
  }
@@ -24626,7 +24626,7 @@ ${errorDetails}`,
24626
24626
  await this.executeHooks("beforeDelete", objectData);
24627
24627
  const key = this.getResourceKey(id);
24628
24628
  const [ok2, err2, response] = await tryFn(() => this.client.deleteObject(key));
24629
- this._emitWithDeprecation("delete", "deleted", {
24629
+ this._emitStandardized("delete", "deleted", {
24630
24630
  ...objectData,
24631
24631
  $before: { ...objectData },
24632
24632
  $after: null
@@ -24754,7 +24754,7 @@ ${errorDetails}`,
24754
24754
  }
24755
24755
  const count = await this.client.count({ prefix });
24756
24756
  await this.executeHooks("afterCount", { count, partition, partitionValues });
24757
- this._emitWithDeprecation("count", "counted", count);
24757
+ this._emitStandardized("count", "counted", count);
24758
24758
  return count;
24759
24759
  }
24760
24760
  /**
@@ -24777,7 +24777,7 @@ ${errorDetails}`,
24777
24777
  const result = await this.insert(attributes);
24778
24778
  return result;
24779
24779
  });
24780
- this._emitWithDeprecation("insertMany", "inserted-many", objects.length);
24780
+ this._emitStandardized("insertMany", "inserted-many", objects.length);
24781
24781
  return results;
24782
24782
  }
24783
24783
  /**
@@ -24812,7 +24812,7 @@ ${errorDetails}`,
24812
24812
  return response;
24813
24813
  });
24814
24814
  await this.executeHooks("afterDeleteMany", { ids, results });
24815
- this._emitWithDeprecation("deleteMany", "deleted-many", ids.length);
24815
+ this._emitStandardized("deleteMany", "deleted-many", ids.length);
24816
24816
  return results;
24817
24817
  }
24818
24818
  async deleteAll() {
@@ -24821,7 +24821,7 @@ ${errorDetails}`,
24821
24821
  }
24822
24822
  const prefix = `resource=${this.name}/data`;
24823
24823
  const deletedCount = await this.client.deleteAll({ prefix });
24824
- this._emitWithDeprecation("deleteAll", "deleted-all", {
24824
+ this._emitStandardized("deleteAll", "deleted-all", {
24825
24825
  version: this.version,
24826
24826
  prefix,
24827
24827
  deletedCount
@@ -24838,7 +24838,7 @@ ${errorDetails}`,
24838
24838
  }
24839
24839
  const prefix = `resource=${this.name}`;
24840
24840
  const deletedCount = await this.client.deleteAll({ prefix });
24841
- this._emitWithDeprecation("deleteAllData", "deleted-all-data", {
24841
+ this._emitStandardized("deleteAllData", "deleted-all-data", {
24842
24842
  resource: this.name,
24843
24843
  prefix,
24844
24844
  deletedCount
@@ -24908,7 +24908,7 @@ ${errorDetails}`,
24908
24908
  const idPart = parts.find((part) => part.startsWith("id="));
24909
24909
  return idPart ? idPart.replace("id=", "") : null;
24910
24910
  }).filter(Boolean);
24911
- this._emitWithDeprecation("listIds", "listed-ids", ids.length);
24911
+ this._emitStandardized("listIds", "listed-ids", ids.length);
24912
24912
  return ids;
24913
24913
  }
24914
24914
  /**
@@ -24950,12 +24950,12 @@ ${errorDetails}`,
24950
24950
  const [ok, err, ids] = await tryFn(() => this.listIds({ limit, offset }));
24951
24951
  if (!ok) throw err;
24952
24952
  const results = await this.processListResults(ids, "main");
24953
- this._emitWithDeprecation("list", "listed", { count: results.length, errors: 0 });
24953
+ this._emitStandardized("list", "listed", { count: results.length, errors: 0 });
24954
24954
  return results;
24955
24955
  }
24956
24956
  async listPartition({ partition, partitionValues, limit, offset = 0 }) {
24957
24957
  if (!this.config.partitions?.[partition]) {
24958
- this._emitWithDeprecation("list", "listed", { partition, partitionValues, count: 0, errors: 0 });
24958
+ this._emitStandardized("list", "listed", { partition, partitionValues, count: 0, errors: 0 });
24959
24959
  return [];
24960
24960
  }
24961
24961
  const partitionDef = this.config.partitions[partition];
@@ -24965,7 +24965,7 @@ ${errorDetails}`,
24965
24965
  const ids = this.extractIdsFromKeys(keys).slice(offset);
24966
24966
  const filteredIds = limit ? ids.slice(0, limit) : ids;
24967
24967
  const results = await this.processPartitionResults(filteredIds, partition, partitionDef, keys);
24968
- this._emitWithDeprecation("list", "listed", { partition, partitionValues, count: results.length, errors: 0 });
24968
+ this._emitStandardized("list", "listed", { partition, partitionValues, count: results.length, errors: 0 });
24969
24969
  return results;
24970
24970
  }
24971
24971
  /**
@@ -25010,7 +25010,7 @@ ${errorDetails}`,
25010
25010
  }
25011
25011
  return this.handleResourceError(err, id, context);
25012
25012
  });
25013
- this._emitWithDeprecation("list", "listed", { count: results.length, errors: 0 });
25013
+ this._emitStandardized("list", "listed", { count: results.length, errors: 0 });
25014
25014
  return results;
25015
25015
  }
25016
25016
  /**
@@ -25073,10 +25073,10 @@ ${errorDetails}`,
25073
25073
  */
25074
25074
  handleListError(error, { partition, partitionValues }) {
25075
25075
  if (error.message.includes("Partition '") && error.message.includes("' not found")) {
25076
- this._emitWithDeprecation("list", "listed", { partition, partitionValues, count: 0, errors: 1 });
25076
+ this._emitStandardized("list", "listed", { partition, partitionValues, count: 0, errors: 1 });
25077
25077
  return [];
25078
25078
  }
25079
- this._emitWithDeprecation("list", "listed", { partition, partitionValues, count: 0, errors: 1 });
25079
+ this._emitStandardized("list", "listed", { partition, partitionValues, count: 0, errors: 1 });
25080
25080
  return [];
25081
25081
  }
25082
25082
  /**
@@ -25109,7 +25109,7 @@ ${errorDetails}`,
25109
25109
  throw err;
25110
25110
  });
25111
25111
  const finalResults = await this.executeHooks("afterGetMany", results);
25112
- this._emitWithDeprecation("getMany", "fetched-many", ids.length);
25112
+ this._emitStandardized("getMany", "fetched-many", ids.length);
25113
25113
  return finalResults;
25114
25114
  }
25115
25115
  /**
@@ -25195,7 +25195,7 @@ ${errorDetails}`,
25195
25195
  hasTotalItems: totalItems !== null
25196
25196
  }
25197
25197
  };
25198
- this._emitWithDeprecation("page", "paginated", result2);
25198
+ this._emitStandardized("page", "paginated", result2);
25199
25199
  return result2;
25200
25200
  });
25201
25201
  if (ok) return result;
@@ -25265,7 +25265,7 @@ ${errorDetails}`,
25265
25265
  contentType
25266
25266
  }));
25267
25267
  if (!ok2) throw err2;
25268
- this._emitWithDeprecation("setContent", "content-set", { id, contentType, contentLength: buffer.length }, id);
25268
+ this._emitStandardized("setContent", "content-set", { id, contentType, contentLength: buffer.length }, id);
25269
25269
  return updatedData;
25270
25270
  }
25271
25271
  /**
@@ -25294,7 +25294,7 @@ ${errorDetails}`,
25294
25294
  }
25295
25295
  const buffer = Buffer.from(await response.Body.transformToByteArray());
25296
25296
  const contentType = response.ContentType || null;
25297
- this._emitWithDeprecation("content", "content-fetched", { id, contentLength: buffer.length, contentType }, id);
25297
+ this._emitStandardized("content", "content-fetched", { id, contentLength: buffer.length, contentType }, id);
25298
25298
  return {
25299
25299
  buffer,
25300
25300
  contentType
@@ -25326,7 +25326,7 @@ ${errorDetails}`,
25326
25326
  metadata: existingMetadata
25327
25327
  }));
25328
25328
  if (!ok2) throw err2;
25329
- this._emitWithDeprecation("deleteContent", "content-deleted", id, id);
25329
+ this._emitStandardized("deleteContent", "content-deleted", id, id);
25330
25330
  return response;
25331
25331
  }
25332
25332
  /**
@@ -25638,7 +25638,7 @@ ${errorDetails}`,
25638
25638
  const data = await this.get(id);
25639
25639
  data._partition = partitionName;
25640
25640
  data._partitionValues = partitionValues;
25641
- this._emitWithDeprecation("getFromPartition", "partition-fetched", data, data.id);
25641
+ this._emitStandardized("getFromPartition", "partition-fetched", data, data.id);
25642
25642
  return data;
25643
25643
  }
25644
25644
  /**
@@ -25887,6 +25887,123 @@ ${errorDetails}`,
25887
25887
  }
25888
25888
  return out;
25889
25889
  }
25890
+ // ============================================================================
25891
+ // STATE MACHINE METHODS
25892
+ // ============================================================================
25893
+ /**
25894
+ * Send an event to trigger a state transition
25895
+ * @param {string} id - Entity ID
25896
+ * @param {string} event - Event name
25897
+ * @param {Object} [eventData] - Event data
25898
+ * @returns {Promise<Object>} Transition result
25899
+ * @throws {Error} If no state machine is configured for this resource
25900
+ * @example
25901
+ * await orders.state('order-123', 'CONFIRM', { confirmedBy: 'user-456' });
25902
+ */
25903
+ async state(id, event, eventData) {
25904
+ if (!this._stateMachine) {
25905
+ throw new Error(
25906
+ `No state machine configured for resource '${this.name}'. Ensure StateMachinePlugin is installed and configured for this resource.`
25907
+ );
25908
+ }
25909
+ return this._stateMachine.send(id, event, eventData);
25910
+ }
25911
+ /**
25912
+ * Get current state of an entity
25913
+ * @param {string} id - Entity ID
25914
+ * @returns {Promise<string>} Current state
25915
+ * @throws {Error} If no state machine is configured for this resource
25916
+ * @example
25917
+ * const currentState = await orders.getState('order-123');
25918
+ */
25919
+ async getState(id) {
25920
+ if (!this._stateMachine) {
25921
+ throw new Error(
25922
+ `No state machine configured for resource '${this.name}'. Ensure StateMachinePlugin is installed and configured for this resource.`
25923
+ );
25924
+ }
25925
+ return this._stateMachine.getState(id);
25926
+ }
25927
+ /**
25928
+ * Check if a transition is valid
25929
+ * @param {string} id - Entity ID
25930
+ * @param {string} event - Event name
25931
+ * @returns {Promise<boolean>} True if transition is valid
25932
+ * @throws {Error} If no state machine is configured for this resource
25933
+ * @example
25934
+ * const canConfirm = await orders.canTransition('order-123', 'CONFIRM');
25935
+ */
25936
+ async canTransition(id, event) {
25937
+ if (!this._stateMachine) {
25938
+ throw new Error(
25939
+ `No state machine configured for resource '${this.name}'. Ensure StateMachinePlugin is installed and configured for this resource.`
25940
+ );
25941
+ }
25942
+ return this._stateMachine.canTransition(id, event);
25943
+ }
25944
+ /**
25945
+ * Get all valid events for the current state
25946
+ * @param {string} id - Entity ID
25947
+ * @returns {Promise<Array<string>>} Array of valid event names
25948
+ * @throws {Error} If no state machine is configured for this resource
25949
+ * @example
25950
+ * const events = await orders.getValidEvents('order-123');
25951
+ * // Returns: ['SHIP', 'CANCEL']
25952
+ */
25953
+ async getValidEvents(id) {
25954
+ if (!this._stateMachine) {
25955
+ throw new Error(
25956
+ `No state machine configured for resource '${this.name}'. Ensure StateMachinePlugin is installed and configured for this resource.`
25957
+ );
25958
+ }
25959
+ return this._stateMachine.getValidEvents(id);
25960
+ }
25961
+ /**
25962
+ * Initialize entity with initial state
25963
+ * @param {string} id - Entity ID
25964
+ * @param {Object} [context] - Initial context data
25965
+ * @returns {Promise<void>}
25966
+ * @throws {Error} If no state machine is configured for this resource
25967
+ * @example
25968
+ * await orders.initializeState('order-456', { customerId: 'user-123' });
25969
+ */
25970
+ async initializeState(id, context) {
25971
+ if (!this._stateMachine) {
25972
+ throw new Error(
25973
+ `No state machine configured for resource '${this.name}'. Ensure StateMachinePlugin is installed and configured for this resource.`
25974
+ );
25975
+ }
25976
+ return this._stateMachine.initializeEntity(id, context);
25977
+ }
25978
+ /**
25979
+ * Get transition history for an entity
25980
+ * @param {string} id - Entity ID
25981
+ * @param {Object} [options] - Query options
25982
+ * @param {number} [options.limit=100] - Maximum number of transitions
25983
+ * @param {Date} [options.fromDate] - Filter from date
25984
+ * @param {Date} [options.toDate] - Filter to date
25985
+ * @returns {Promise<Array<Object>>} Transition history
25986
+ * @throws {Error} If no state machine is configured for this resource
25987
+ * @example
25988
+ * const history = await orders.getStateHistory('order-123', { limit: 50 });
25989
+ */
25990
+ async getStateHistory(id, options) {
25991
+ if (!this._stateMachine) {
25992
+ throw new Error(
25993
+ `No state machine configured for resource '${this.name}'. Ensure StateMachinePlugin is installed and configured for this resource.`
25994
+ );
25995
+ }
25996
+ return this._stateMachine.getTransitionHistory(id, options);
25997
+ }
25998
+ /**
25999
+ * Internal method to attach state machine instance
26000
+ * This is called by StateMachinePlugin during initialization
26001
+ * @private
26002
+ * @param {Object} stateMachine - State machine instance
26003
+ */
26004
+ _attachStateMachine(stateMachine) {
26005
+ this._stateMachine = stateMachine;
26006
+ }
25890
26007
  }
25891
26008
  function validateResourceConfig(config) {
25892
26009
  const errors = [];
@@ -26047,7 +26164,7 @@ class Database extends EventEmitter {
26047
26164
  })();
26048
26165
  this.version = "1";
26049
26166
  this.s3dbVersion = (() => {
26050
- const [ok, err, version] = tryFn(() => true ? "13.2.1" : "latest");
26167
+ const [ok, err, version] = tryFn(() => true ? "13.2.2" : "latest");
26051
26168
  return ok ? version : "latest";
26052
26169
  })();
26053
26170
  this._resourcesMap = {};
@@ -30597,6 +30714,7 @@ class StateMachinePlugin extends Plugin {
30597
30714
  // entityId -> currentState
30598
30715
  });
30599
30716
  }
30717
+ await this._attachStateMachinesToResources();
30600
30718
  await this._setupTriggers();
30601
30719
  this.emit("db:plugin:initialized", { machines: Array.from(this.machines.keys()) });
30602
30720
  }
@@ -31438,6 +31556,58 @@ class StateMachinePlugin extends Plugin {
31438
31556
  }
31439
31557
  }
31440
31558
  }
31559
+ /**
31560
+ * Attach state machine instances to their associated resources
31561
+ * This enables the resource API: resource.state(id, event)
31562
+ * @private
31563
+ */
31564
+ async _attachStateMachinesToResources() {
31565
+ for (const [machineName, machineConfig] of Object.entries(this.config.stateMachines)) {
31566
+ const resourceConfig = machineConfig.config || machineConfig;
31567
+ if (!resourceConfig.resource) {
31568
+ if (this.config.verbose) {
31569
+ console.log(`[StateMachinePlugin] Machine '${machineName}' has no resource configured, skipping attachment`);
31570
+ }
31571
+ continue;
31572
+ }
31573
+ let resource;
31574
+ if (typeof resourceConfig.resource === "string") {
31575
+ resource = this.database.resources[resourceConfig.resource];
31576
+ if (!resource) {
31577
+ console.warn(
31578
+ `[StateMachinePlugin] Resource '${resourceConfig.resource}' not found for machine '${machineName}'. Resource API will not be available.`
31579
+ );
31580
+ continue;
31581
+ }
31582
+ } else {
31583
+ resource = resourceConfig.resource;
31584
+ }
31585
+ const machineProxy = {
31586
+ send: async (id, event, eventData) => {
31587
+ return this.send(machineName, id, event, eventData);
31588
+ },
31589
+ getState: async (id) => {
31590
+ return this.getState(machineName, id);
31591
+ },
31592
+ canTransition: async (id, event) => {
31593
+ return this.canTransition(machineName, id, event);
31594
+ },
31595
+ getValidEvents: async (id) => {
31596
+ return this.getValidEvents(machineName, id);
31597
+ },
31598
+ initializeEntity: async (id, context) => {
31599
+ return this.initializeEntity(machineName, id, context);
31600
+ },
31601
+ getTransitionHistory: async (id, options) => {
31602
+ return this.getTransitionHistory(machineName, id, options);
31603
+ }
31604
+ };
31605
+ resource._attachStateMachine(machineProxy);
31606
+ if (this.config.verbose) {
31607
+ console.log(`[StateMachinePlugin] Attached machine '${machineName}' to resource '${resource.name}'`);
31608
+ }
31609
+ }
31610
+ }
31441
31611
  async start() {
31442
31612
  if (this.config.verbose) {
31443
31613
  console.log(`[StateMachinePlugin] Started with ${this.machines.size} state machines`);