@teslemetry/api 0.6.8 → 0.6.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/README.md CHANGED
@@ -101,9 +101,8 @@ vehicle.sse.onSignal("PackCurrent", (val) => console.log("Current:", val));
101
101
  vehicle.sse.onSignal("ChargerVoltage", (val) => console.log("Voltage:", val));
102
102
 
103
103
  // Monitor connection status
104
- teslemetry.sse.onConnection((isConnected) => {
105
- console.log(isConnected ? "Stream Connected" : "Stream Disconnected");
106
- });
104
+ teslemetry.sse.on("connect", () => console.log("Stream Connected"));
105
+ teslemetry.sse.on("disconnect", () => console.log("Stream Disconnected"));
107
106
 
108
107
  // Start streaming (connects to the shared Teslemetry stream)
109
108
  await teslemetry.sse.connect();
package/dist/index.cjs CHANGED
@@ -2989,12 +2989,23 @@ const getSseByVin_ = (options) => (options.client ?? client).sse.get({
2989
2989
 
2990
2990
  //#endregion
2991
2991
  //#region src/TeslemetryVehicleStream.ts
2992
+ /** Simple deferred promise pattern */
2993
+ var Deferred = class {
2994
+ promise;
2995
+ resolve;
2996
+ reject;
2997
+ constructor() {
2998
+ this.promise = new Promise((resolve, reject) => {
2999
+ this.resolve = resolve;
3000
+ this.reject = reject;
3001
+ });
3002
+ }
3003
+ };
2992
3004
  var TeslemetryVehicleStream = class extends events.EventEmitter {
2993
3005
  root;
2994
3006
  vin;
2995
3007
  fields = {};
2996
- _pendingFields = {};
2997
- _debounceTimeout = null;
3008
+ _fieldUpdateBatch = null;
2998
3009
  logger;
2999
3010
  data;
3000
3011
  constructor(root, vin) {
@@ -3025,25 +3036,45 @@ var TeslemetryVehicleStream = class extends events.EventEmitter {
3025
3036
  return;
3026
3037
  } else throw new Error(`Failed to get config: ${response.statusText}`);
3027
3038
  }
3028
- /** Safely add field configuration to the vehicle */
3029
- async updateFields(fields) {
3030
- this._pendingFields = {
3031
- ...this._pendingFields,
3039
+ /** Safely add field configuration to the vehicle
3040
+ * Returns a promise that resolves when the debounced update completes.
3041
+ * Multiple calls within the debounce window share the same promise.
3042
+ */
3043
+ updateFields(fields) {
3044
+ if (!this._fieldUpdateBatch) this._fieldUpdateBatch = {
3045
+ fields: {},
3046
+ deferred: new Deferred(),
3047
+ timeout: null
3048
+ };
3049
+ this._fieldUpdateBatch.fields = {
3050
+ ...this._fieldUpdateBatch.fields,
3032
3051
  ...fields
3033
3052
  };
3034
- if (this._debounceTimeout) clearTimeout(this._debounceTimeout);
3035
- this._debounceTimeout = setTimeout(async () => {
3036
- const data = await this.patchConfig(this._pendingFields);
3053
+ clearTimeout(this._fieldUpdateBatch.timeout);
3054
+ this._fieldUpdateBatch.timeout = setTimeout(() => this._flushFieldUpdate(), 1e3);
3055
+ return this._fieldUpdateBatch.deferred.promise;
3056
+ }
3057
+ /** Flush pending field updates to the API */
3058
+ async _flushFieldUpdate() {
3059
+ const batch = this._fieldUpdateBatch;
3060
+ this._fieldUpdateBatch = null;
3061
+ try {
3062
+ const data = await this.patchConfig(batch.fields);
3037
3063
  if (data?.updated_vehicles) {
3038
- this.logger.info(`Updated ${Object.keys(this._pendingFields).length} streaming fields for ${this.vin}`);
3064
+ this.logger.info(`Updated ${Object.keys(batch.fields).length} streaming fields for ${this.vin}`);
3039
3065
  this.fields = {
3040
3066
  ...this.fields,
3041
- ...this._pendingFields
3067
+ ...batch.fields
3042
3068
  };
3043
- this._pendingFields = {};
3044
- } else this.logger.error(`Error updating streaming config for ${this.vin}`, data);
3045
- this._debounceTimeout = null;
3046
- }, 1e3);
3069
+ batch.deferred.resolve();
3070
+ } else {
3071
+ const error = /* @__PURE__ */ new Error(`Error updating streaming config for ${this.vin}`);
3072
+ this.logger.error(error.message, data);
3073
+ batch.deferred.reject(error);
3074
+ }
3075
+ } catch (error) {
3076
+ batch.deferred.reject(error);
3077
+ }
3047
3078
  }
3048
3079
  /** Modify the field configuration of the vehicle */
3049
3080
  async patchConfig(fields) {
@@ -3067,15 +3098,15 @@ var TeslemetryVehicleStream = class extends events.EventEmitter {
3067
3098
  * Add a field to the vehicles streaming configuration
3068
3099
  * @param field Vehicle Signal
3069
3100
  * @param interval
3070
- * @returns
3101
+ * @returns Promise that resolves when the field is added
3071
3102
  */
3072
- async addField(field, interval) {
3103
+ addField(field, interval) {
3073
3104
  if (this.fields && this.fields[field] && (interval === void 0 || this.fields[field].interval_seconds === interval)) {
3074
3105
  this.logger.debug(`Streaming field ${field} already enabled @ ${this.fields[field]?.interval_seconds || "default"}s`);
3075
- return;
3106
+ return Promise.resolve();
3076
3107
  }
3077
3108
  const value = interval !== void 0 ? { interval_seconds: interval } : null;
3078
- this.updateFields({ [field]: value });
3109
+ return this.updateFields({ [field]: value });
3079
3110
  }
3080
3111
  /**
3081
3112
  * Helper to enable and listen for specific field signals
@@ -3084,8 +3115,8 @@ var TeslemetryVehicleStream = class extends events.EventEmitter {
3084
3115
  * @returns Off function to stop the listener
3085
3116
  */
3086
3117
  onSignal(field, callback) {
3087
- this.addField(field).catch((error) => {
3088
- this.logger.error(`Failed to add field ${field}:`, error);
3118
+ this.addField(field).catch(() => {
3119
+ this.logger.error(`Failed to add field ${field}`);
3089
3120
  });
3090
3121
  const data = this.root.sse.cache?.[this.vin]?.data?.[field];
3091
3122
  if (data !== void 0) callback(data);
@@ -3228,6 +3259,7 @@ var TeslemetryStream = class extends events.EventEmitter {
3228
3259
  else if ("credits" in event) this.emit("credits", event);
3229
3260
  else if ("vehicle_data" in event) this.emit("vehicle_data", event);
3230
3261
  else if ("config" in event) this.emit("config", event);
3262
+ this.emit("all", event);
3231
3263
  const vehicle = this.vehicles.get(event.vin);
3232
3264
  if (vehicle) {
3233
3265
  if ("state" in event) vehicle.emit("state", event);
@@ -5220,7 +5252,7 @@ const consoleLogger = {
5220
5252
 
5221
5253
  //#endregion
5222
5254
  //#region package.json
5223
- var version = "0.6.8";
5255
+ var version = "0.6.10";
5224
5256
 
5225
5257
  //#endregion
5226
5258
  //#region src/Teslemetry.ts
package/dist/index.d.cts CHANGED
@@ -1117,14 +1117,14 @@ type GetApiConfigByVinResponses = {
1117
1117
  resend_interval_seconds?: number;
1118
1118
  };
1119
1119
  /**
1120
- * If the vehicle is located at the active driver profiles saved home location. (Requires 2024.44.32)
1120
+ * If the vehicle is located at the active driver profile's saved home location. (Requires 2024.44.32)
1121
1121
  */
1122
1122
  LocatedAtHome?: {
1123
1123
  interval_seconds: number;
1124
1124
  resend_interval_seconds?: number;
1125
1125
  };
1126
1126
  /**
1127
- * If the vehicle is located at the active driver profiles saved work location. (Requires 2024.44.32)
1127
+ * If the vehicle is located at the active driver profile's saved work location. (Requires 2024.44.32)
1128
1128
  */
1129
1129
  LocatedAtWork?: {
1130
1130
  interval_seconds: number;
@@ -2936,14 +2936,14 @@ type PatchApiConfigByVinData = {
2936
2936
  resend_interval_seconds?: number;
2937
2937
  } | null;
2938
2938
  /**
2939
- * If the vehicle is located at the active driver profiles saved home location. (Requires 2024.44.32)
2939
+ * If the vehicle is located at the active driver profile's saved home location. (Requires 2024.44.32)
2940
2940
  */
2941
2941
  LocatedAtHome?: {
2942
2942
  interval_seconds: number;
2943
2943
  resend_interval_seconds?: number;
2944
2944
  } | null;
2945
2945
  /**
2946
- * If the vehicle is located at the active driver profiles saved work location. (Requires 2024.44.32)
2946
+ * If the vehicle is located at the active driver profile's saved work location. (Requires 2024.44.32)
2947
2947
  */
2948
2948
  LocatedAtWork?: {
2949
2949
  interval_seconds: number;
@@ -4760,14 +4760,14 @@ type PostApiConfigByVinData = {
4760
4760
  resend_interval_seconds?: number;
4761
4761
  } | null;
4762
4762
  /**
4763
- * If the vehicle is located at the active driver profiles saved home location. (Requires 2024.44.32)
4763
+ * If the vehicle is located at the active driver profile's saved home location. (Requires 2024.44.32)
4764
4764
  */
4765
4765
  LocatedAtHome?: {
4766
4766
  interval_seconds: number;
4767
4767
  resend_interval_seconds?: number;
4768
4768
  } | null;
4769
4769
  /**
4770
- * If the vehicle is located at the active driver profiles saved work location. (Requires 2024.44.32)
4770
+ * If the vehicle is located at the active driver profile's saved work location. (Requires 2024.44.32)
4771
4771
  */
4772
4772
  LocatedAtWork?: {
4773
4773
  interval_seconds: number;
@@ -6675,14 +6675,14 @@ type GetApi1VehiclesByVinFleetTelemetryConfigResponses = {
6675
6675
  resend_interval_seconds?: number;
6676
6676
  };
6677
6677
  /**
6678
- * If the vehicle is located at the active driver profiles saved home location. (Requires 2024.44.32)
6678
+ * If the vehicle is located at the active driver profile's saved home location. (Requires 2024.44.32)
6679
6679
  */
6680
6680
  LocatedAtHome?: {
6681
6681
  interval_seconds: number;
6682
6682
  resend_interval_seconds?: number;
6683
6683
  };
6684
6684
  /**
6685
- * If the vehicle is located at the active driver profiles saved work location. (Requires 2024.44.32)
6685
+ * If the vehicle is located at the active driver profile's saved work location. (Requires 2024.44.32)
6686
6686
  */
6687
6687
  LocatedAtWork?: {
6688
6688
  interval_seconds: number;
@@ -8422,8 +8422,8 @@ type GetSseByVin_Responses = {
8422
8422
  ChargeAmps?: number | null;
8423
8423
  ChargeCurrentRequest?: number | null;
8424
8424
  ChargeCurrentRequestMax?: number | null;
8425
- ChargeEnableRequest?: number | null;
8426
- ChargeLimitSoc?: boolean | null;
8425
+ ChargeEnableRequest?: boolean | null;
8426
+ ChargeLimitSoc?: number | null;
8427
8427
  ChargePort?: 'ChargePortUnknown' | 'ChargePortUS' | 'ChargePortEU' | 'ChargePortGB' | 'ChargePortCCS' | null;
8428
8428
  ChargePortColdWeatherMode?: boolean | null;
8429
8429
  ChargePortDoorOpen?: boolean | null;
@@ -8442,7 +8442,7 @@ type GetSseByVin_Responses = {
8442
8442
  DCChargingEnergyIn?: number | null;
8443
8443
  DCChargingPower?: number | null;
8444
8444
  DCDCEnable?: boolean | null;
8445
- DefrostForPreconditioning?: number | null;
8445
+ DefrostForPreconditioning?: boolean | null;
8446
8446
  DefrostMode?: 'DefrostModeStateUnknown' | 'DefrostModeStateOff' | 'DefrostModeStateNormal' | 'DefrostModeStateMax' | 'DefrostModeStateAutoDefog' | null;
8447
8447
  DestinationLocation?: {
8448
8448
  latitude: number;
@@ -8492,15 +8492,15 @@ type GetSseByVin_Responses = {
8492
8492
  TrunkFront: boolean;
8493
8493
  TrunkRear: boolean;
8494
8494
  } | null;
8495
- DriveRail?: number | null;
8495
+ DriveRail?: boolean | null;
8496
8496
  DriverSeatBelt?: 'BuckleStatusUnknown' | 'BuckleStatusUnlatched' | 'BuckleStatusLatched' | 'BuckleStatusFaulted' | null;
8497
8497
  DriverSeatOccupied?: boolean | null;
8498
- EfficiencyPackage?: number | null;
8499
- EmergencyLaneDepartureAvoidance?: number | null;
8498
+ EfficiencyPackage?: string | null;
8499
+ EmergencyLaneDepartureAvoidance?: boolean | null;
8500
8500
  EnergyRemaining?: number | null;
8501
8501
  EstBatteryRange?: number | null;
8502
8502
  EstimatedHoursToChargeTermination?: number | null;
8503
- EuropeVehicle?: number | null;
8503
+ EuropeVehicle?: boolean | null;
8504
8504
  ExpectedEnergyPercentAtTripArrival?: number | null;
8505
8505
  ExteriorColor?: string | null;
8506
8506
  FastChargerPresent?: boolean | null;
@@ -8522,7 +8522,7 @@ type GetSseByVin_Responses = {
8522
8522
  HvacLeftTemperatureRequest?: number | null;
8523
8523
  HvacPower?: 'HvacPowerStateUnknown' | 'HvacPowerStateOff' | 'HvacPowerStateOn' | 'HvacPowerStatePrecondition' | 'HvacPowerStateOverheatProtect' | null;
8524
8524
  HvacRightTemperatureRequest?: number | null;
8525
- HvacSteeringWheelHeatAuto?: number | null;
8525
+ HvacSteeringWheelHeatAuto?: boolean | null;
8526
8526
  HvacSteeringWheelHeatLevel?: number | null;
8527
8527
  Hvil?: 'HvilStatusUnknown' | 'HvilStatusFault' | 'HvilStatusOK' | null;
8528
8528
  IdealBatteryRange?: number | null;
@@ -8536,9 +8536,9 @@ type GetSseByVin_Responses = {
8536
8536
  LightsHazardsActive?: boolean | null;
8537
8537
  LightsHighBeams?: boolean | null;
8538
8538
  LightsTurnSignal?: 'TurnSignalStateUnknown' | 'TurnSignalStateOff' | 'TurnSignalStateLeft' | 'TurnSignalStateRight' | 'TurnSignalStateBoth' | null;
8539
- LocatedAtFavorite?: number | null;
8540
- LocatedAtHome?: number | null;
8541
- LocatedAtWork?: number | null;
8539
+ LocatedAtFavorite?: boolean | null;
8540
+ LocatedAtHome?: boolean | null;
8541
+ LocatedAtWork?: boolean | null;
8542
8542
  Location?: {
8543
8543
  latitude: number;
8544
8544
  longitude: number;
@@ -8561,7 +8561,7 @@ type GetSseByVin_Responses = {
8561
8561
  MinutesToArrival?: number | null;
8562
8562
  ModuleTempMax?: number | null;
8563
8563
  ModuleTempMin?: number | null;
8564
- NotEnoughPowerToHeat?: number | null;
8564
+ NotEnoughPowerToHeat?: boolean | null;
8565
8565
  NumBrickVoltageMax?: number | null;
8566
8566
  NumBrickVoltageMin?: number | null;
8567
8567
  NumModuleTempMax?: number | null;
@@ -8589,7 +8589,7 @@ type GetSseByVin_Responses = {
8589
8589
  RdWindow?: 'WindowStateUnknown' | 'WindowStateClosed' | 'WindowStatePartiallyOpen' | 'WindowStateOpened' | null;
8590
8590
  RearDefrostEnabled?: boolean | null;
8591
8591
  RearDisplayHvacEnabled?: boolean | null;
8592
- RearSeatHeaters?: number | null;
8592
+ RearSeatHeaters?: string | null;
8593
8593
  RemoteStartEnabled?: boolean | null;
8594
8594
  RightHandDrive?: boolean | null;
8595
8595
  RoofColor?: string | null;
@@ -8598,7 +8598,7 @@ type GetSseByVin_Responses = {
8598
8598
  RouteTrafficMinutesDelay?: number | null;
8599
8599
  RpWindow?: 'WindowStateUnknown' | 'WindowStateClosed' | 'WindowStatePartiallyOpen' | 'WindowStateOpened' | null;
8600
8600
  ScheduledChargingMode?: 'ScheduledChargingModeUnknown' | 'ScheduledChargingModeOff' | 'ScheduledChargingModeStartAt' | 'ScheduledChargingModeDepartBy' | null;
8601
- ScheduledChargingPending?: number | null;
8601
+ ScheduledChargingPending?: boolean | null;
8602
8602
  ScheduledChargingStartTime?: number | null;
8603
8603
  ScheduledDepartureTime?: number | null;
8604
8604
  SeatHeaterLeft?: number | null;
@@ -14188,6 +14188,7 @@ interface TeslemetryStreamOptions {
14188
14188
  };
14189
14189
  }
14190
14190
  type TeslemetryStreamEventMap$1 = {
14191
+ all: SseEvent;
14191
14192
  state: SseState;
14192
14193
  data: SseData;
14193
14194
  errors: SseErrors;
@@ -14267,16 +14268,20 @@ declare class TeslemetryVehicleStream extends EventEmitter {
14267
14268
  private root;
14268
14269
  vin: string;
14269
14270
  fields: FieldsRequest;
14270
- private _pendingFields;
14271
- private _debounceTimeout;
14271
+ private _fieldUpdateBatch;
14272
14272
  logger: Logger;
14273
14273
  data: TeslemetryVehicleStreamData;
14274
14274
  constructor(root: Teslemetry, vin: string);
14275
14275
  get cache(): VehicleCache;
14276
14276
  /** Get the current configuration for the vehicle */
14277
14277
  getConfig(): Promise<void>;
14278
- /** Safely add field configuration to the vehicle */
14278
+ /** Safely add field configuration to the vehicle
14279
+ * Returns a promise that resolves when the debounced update completes.
14280
+ * Multiple calls within the debounce window share the same promise.
14281
+ */
14279
14282
  updateFields(fields: FieldsRequest): Promise<void>;
14283
+ /** Flush pending field updates to the API */
14284
+ private _flushFieldUpdate;
14280
14285
  /** Modify the field configuration of the vehicle */
14281
14286
  patchConfig(fields: FieldsRequest): Promise<{
14282
14287
  updated_vehicles?: number;
@@ -14293,7 +14298,7 @@ declare class TeslemetryVehicleStream extends EventEmitter {
14293
14298
  * Add a field to the vehicles streaming configuration
14294
14299
  * @param field Vehicle Signal
14295
14300
  * @param interval
14296
- * @returns
14301
+ * @returns Promise that resolves when the field is added
14297
14302
  */
14298
14303
  addField(field: Signals, interval?: number): Promise<void>;
14299
14304
  /**
package/dist/index.d.mts CHANGED
@@ -1117,14 +1117,14 @@ type GetApiConfigByVinResponses = {
1117
1117
  resend_interval_seconds?: number;
1118
1118
  };
1119
1119
  /**
1120
- * If the vehicle is located at the active driver profiles saved home location. (Requires 2024.44.32)
1120
+ * If the vehicle is located at the active driver profile's saved home location. (Requires 2024.44.32)
1121
1121
  */
1122
1122
  LocatedAtHome?: {
1123
1123
  interval_seconds: number;
1124
1124
  resend_interval_seconds?: number;
1125
1125
  };
1126
1126
  /**
1127
- * If the vehicle is located at the active driver profiles saved work location. (Requires 2024.44.32)
1127
+ * If the vehicle is located at the active driver profile's saved work location. (Requires 2024.44.32)
1128
1128
  */
1129
1129
  LocatedAtWork?: {
1130
1130
  interval_seconds: number;
@@ -2936,14 +2936,14 @@ type PatchApiConfigByVinData = {
2936
2936
  resend_interval_seconds?: number;
2937
2937
  } | null;
2938
2938
  /**
2939
- * If the vehicle is located at the active driver profiles saved home location. (Requires 2024.44.32)
2939
+ * If the vehicle is located at the active driver profile's saved home location. (Requires 2024.44.32)
2940
2940
  */
2941
2941
  LocatedAtHome?: {
2942
2942
  interval_seconds: number;
2943
2943
  resend_interval_seconds?: number;
2944
2944
  } | null;
2945
2945
  /**
2946
- * If the vehicle is located at the active driver profiles saved work location. (Requires 2024.44.32)
2946
+ * If the vehicle is located at the active driver profile's saved work location. (Requires 2024.44.32)
2947
2947
  */
2948
2948
  LocatedAtWork?: {
2949
2949
  interval_seconds: number;
@@ -4760,14 +4760,14 @@ type PostApiConfigByVinData = {
4760
4760
  resend_interval_seconds?: number;
4761
4761
  } | null;
4762
4762
  /**
4763
- * If the vehicle is located at the active driver profiles saved home location. (Requires 2024.44.32)
4763
+ * If the vehicle is located at the active driver profile's saved home location. (Requires 2024.44.32)
4764
4764
  */
4765
4765
  LocatedAtHome?: {
4766
4766
  interval_seconds: number;
4767
4767
  resend_interval_seconds?: number;
4768
4768
  } | null;
4769
4769
  /**
4770
- * If the vehicle is located at the active driver profiles saved work location. (Requires 2024.44.32)
4770
+ * If the vehicle is located at the active driver profile's saved work location. (Requires 2024.44.32)
4771
4771
  */
4772
4772
  LocatedAtWork?: {
4773
4773
  interval_seconds: number;
@@ -6675,14 +6675,14 @@ type GetApi1VehiclesByVinFleetTelemetryConfigResponses = {
6675
6675
  resend_interval_seconds?: number;
6676
6676
  };
6677
6677
  /**
6678
- * If the vehicle is located at the active driver profiles saved home location. (Requires 2024.44.32)
6678
+ * If the vehicle is located at the active driver profile's saved home location. (Requires 2024.44.32)
6679
6679
  */
6680
6680
  LocatedAtHome?: {
6681
6681
  interval_seconds: number;
6682
6682
  resend_interval_seconds?: number;
6683
6683
  };
6684
6684
  /**
6685
- * If the vehicle is located at the active driver profiles saved work location. (Requires 2024.44.32)
6685
+ * If the vehicle is located at the active driver profile's saved work location. (Requires 2024.44.32)
6686
6686
  */
6687
6687
  LocatedAtWork?: {
6688
6688
  interval_seconds: number;
@@ -8422,8 +8422,8 @@ type GetSseByVin_Responses = {
8422
8422
  ChargeAmps?: number | null;
8423
8423
  ChargeCurrentRequest?: number | null;
8424
8424
  ChargeCurrentRequestMax?: number | null;
8425
- ChargeEnableRequest?: number | null;
8426
- ChargeLimitSoc?: boolean | null;
8425
+ ChargeEnableRequest?: boolean | null;
8426
+ ChargeLimitSoc?: number | null;
8427
8427
  ChargePort?: 'ChargePortUnknown' | 'ChargePortUS' | 'ChargePortEU' | 'ChargePortGB' | 'ChargePortCCS' | null;
8428
8428
  ChargePortColdWeatherMode?: boolean | null;
8429
8429
  ChargePortDoorOpen?: boolean | null;
@@ -8442,7 +8442,7 @@ type GetSseByVin_Responses = {
8442
8442
  DCChargingEnergyIn?: number | null;
8443
8443
  DCChargingPower?: number | null;
8444
8444
  DCDCEnable?: boolean | null;
8445
- DefrostForPreconditioning?: number | null;
8445
+ DefrostForPreconditioning?: boolean | null;
8446
8446
  DefrostMode?: 'DefrostModeStateUnknown' | 'DefrostModeStateOff' | 'DefrostModeStateNormal' | 'DefrostModeStateMax' | 'DefrostModeStateAutoDefog' | null;
8447
8447
  DestinationLocation?: {
8448
8448
  latitude: number;
@@ -8492,15 +8492,15 @@ type GetSseByVin_Responses = {
8492
8492
  TrunkFront: boolean;
8493
8493
  TrunkRear: boolean;
8494
8494
  } | null;
8495
- DriveRail?: number | null;
8495
+ DriveRail?: boolean | null;
8496
8496
  DriverSeatBelt?: 'BuckleStatusUnknown' | 'BuckleStatusUnlatched' | 'BuckleStatusLatched' | 'BuckleStatusFaulted' | null;
8497
8497
  DriverSeatOccupied?: boolean | null;
8498
- EfficiencyPackage?: number | null;
8499
- EmergencyLaneDepartureAvoidance?: number | null;
8498
+ EfficiencyPackage?: string | null;
8499
+ EmergencyLaneDepartureAvoidance?: boolean | null;
8500
8500
  EnergyRemaining?: number | null;
8501
8501
  EstBatteryRange?: number | null;
8502
8502
  EstimatedHoursToChargeTermination?: number | null;
8503
- EuropeVehicle?: number | null;
8503
+ EuropeVehicle?: boolean | null;
8504
8504
  ExpectedEnergyPercentAtTripArrival?: number | null;
8505
8505
  ExteriorColor?: string | null;
8506
8506
  FastChargerPresent?: boolean | null;
@@ -8522,7 +8522,7 @@ type GetSseByVin_Responses = {
8522
8522
  HvacLeftTemperatureRequest?: number | null;
8523
8523
  HvacPower?: 'HvacPowerStateUnknown' | 'HvacPowerStateOff' | 'HvacPowerStateOn' | 'HvacPowerStatePrecondition' | 'HvacPowerStateOverheatProtect' | null;
8524
8524
  HvacRightTemperatureRequest?: number | null;
8525
- HvacSteeringWheelHeatAuto?: number | null;
8525
+ HvacSteeringWheelHeatAuto?: boolean | null;
8526
8526
  HvacSteeringWheelHeatLevel?: number | null;
8527
8527
  Hvil?: 'HvilStatusUnknown' | 'HvilStatusFault' | 'HvilStatusOK' | null;
8528
8528
  IdealBatteryRange?: number | null;
@@ -8536,9 +8536,9 @@ type GetSseByVin_Responses = {
8536
8536
  LightsHazardsActive?: boolean | null;
8537
8537
  LightsHighBeams?: boolean | null;
8538
8538
  LightsTurnSignal?: 'TurnSignalStateUnknown' | 'TurnSignalStateOff' | 'TurnSignalStateLeft' | 'TurnSignalStateRight' | 'TurnSignalStateBoth' | null;
8539
- LocatedAtFavorite?: number | null;
8540
- LocatedAtHome?: number | null;
8541
- LocatedAtWork?: number | null;
8539
+ LocatedAtFavorite?: boolean | null;
8540
+ LocatedAtHome?: boolean | null;
8541
+ LocatedAtWork?: boolean | null;
8542
8542
  Location?: {
8543
8543
  latitude: number;
8544
8544
  longitude: number;
@@ -8561,7 +8561,7 @@ type GetSseByVin_Responses = {
8561
8561
  MinutesToArrival?: number | null;
8562
8562
  ModuleTempMax?: number | null;
8563
8563
  ModuleTempMin?: number | null;
8564
- NotEnoughPowerToHeat?: number | null;
8564
+ NotEnoughPowerToHeat?: boolean | null;
8565
8565
  NumBrickVoltageMax?: number | null;
8566
8566
  NumBrickVoltageMin?: number | null;
8567
8567
  NumModuleTempMax?: number | null;
@@ -8589,7 +8589,7 @@ type GetSseByVin_Responses = {
8589
8589
  RdWindow?: 'WindowStateUnknown' | 'WindowStateClosed' | 'WindowStatePartiallyOpen' | 'WindowStateOpened' | null;
8590
8590
  RearDefrostEnabled?: boolean | null;
8591
8591
  RearDisplayHvacEnabled?: boolean | null;
8592
- RearSeatHeaters?: number | null;
8592
+ RearSeatHeaters?: string | null;
8593
8593
  RemoteStartEnabled?: boolean | null;
8594
8594
  RightHandDrive?: boolean | null;
8595
8595
  RoofColor?: string | null;
@@ -8598,7 +8598,7 @@ type GetSseByVin_Responses = {
8598
8598
  RouteTrafficMinutesDelay?: number | null;
8599
8599
  RpWindow?: 'WindowStateUnknown' | 'WindowStateClosed' | 'WindowStatePartiallyOpen' | 'WindowStateOpened' | null;
8600
8600
  ScheduledChargingMode?: 'ScheduledChargingModeUnknown' | 'ScheduledChargingModeOff' | 'ScheduledChargingModeStartAt' | 'ScheduledChargingModeDepartBy' | null;
8601
- ScheduledChargingPending?: number | null;
8601
+ ScheduledChargingPending?: boolean | null;
8602
8602
  ScheduledChargingStartTime?: number | null;
8603
8603
  ScheduledDepartureTime?: number | null;
8604
8604
  SeatHeaterLeft?: number | null;
@@ -14188,6 +14188,7 @@ interface TeslemetryStreamOptions {
14188
14188
  };
14189
14189
  }
14190
14190
  type TeslemetryStreamEventMap$1 = {
14191
+ all: SseEvent;
14191
14192
  state: SseState;
14192
14193
  data: SseData;
14193
14194
  errors: SseErrors;
@@ -14267,16 +14268,20 @@ declare class TeslemetryVehicleStream extends EventEmitter {
14267
14268
  private root;
14268
14269
  vin: string;
14269
14270
  fields: FieldsRequest;
14270
- private _pendingFields;
14271
- private _debounceTimeout;
14271
+ private _fieldUpdateBatch;
14272
14272
  logger: Logger;
14273
14273
  data: TeslemetryVehicleStreamData;
14274
14274
  constructor(root: Teslemetry, vin: string);
14275
14275
  get cache(): VehicleCache;
14276
14276
  /** Get the current configuration for the vehicle */
14277
14277
  getConfig(): Promise<void>;
14278
- /** Safely add field configuration to the vehicle */
14278
+ /** Safely add field configuration to the vehicle
14279
+ * Returns a promise that resolves when the debounced update completes.
14280
+ * Multiple calls within the debounce window share the same promise.
14281
+ */
14279
14282
  updateFields(fields: FieldsRequest): Promise<void>;
14283
+ /** Flush pending field updates to the API */
14284
+ private _flushFieldUpdate;
14280
14285
  /** Modify the field configuration of the vehicle */
14281
14286
  patchConfig(fields: FieldsRequest): Promise<{
14282
14287
  updated_vehicles?: number;
@@ -14293,7 +14298,7 @@ declare class TeslemetryVehicleStream extends EventEmitter {
14293
14298
  * Add a field to the vehicles streaming configuration
14294
14299
  * @param field Vehicle Signal
14295
14300
  * @param interval
14296
- * @returns
14301
+ * @returns Promise that resolves when the field is added
14297
14302
  */
14298
14303
  addField(field: Signals, interval?: number): Promise<void>;
14299
14304
  /**
package/dist/index.mjs CHANGED
@@ -2989,12 +2989,23 @@ const getSseByVin_ = (options) => (options.client ?? client).sse.get({
2989
2989
 
2990
2990
  //#endregion
2991
2991
  //#region src/TeslemetryVehicleStream.ts
2992
+ /** Simple deferred promise pattern */
2993
+ var Deferred = class {
2994
+ promise;
2995
+ resolve;
2996
+ reject;
2997
+ constructor() {
2998
+ this.promise = new Promise((resolve, reject) => {
2999
+ this.resolve = resolve;
3000
+ this.reject = reject;
3001
+ });
3002
+ }
3003
+ };
2992
3004
  var TeslemetryVehicleStream = class extends EventEmitter {
2993
3005
  root;
2994
3006
  vin;
2995
3007
  fields = {};
2996
- _pendingFields = {};
2997
- _debounceTimeout = null;
3008
+ _fieldUpdateBatch = null;
2998
3009
  logger;
2999
3010
  data;
3000
3011
  constructor(root, vin) {
@@ -3025,25 +3036,45 @@ var TeslemetryVehicleStream = class extends EventEmitter {
3025
3036
  return;
3026
3037
  } else throw new Error(`Failed to get config: ${response.statusText}`);
3027
3038
  }
3028
- /** Safely add field configuration to the vehicle */
3029
- async updateFields(fields) {
3030
- this._pendingFields = {
3031
- ...this._pendingFields,
3039
+ /** Safely add field configuration to the vehicle
3040
+ * Returns a promise that resolves when the debounced update completes.
3041
+ * Multiple calls within the debounce window share the same promise.
3042
+ */
3043
+ updateFields(fields) {
3044
+ if (!this._fieldUpdateBatch) this._fieldUpdateBatch = {
3045
+ fields: {},
3046
+ deferred: new Deferred(),
3047
+ timeout: null
3048
+ };
3049
+ this._fieldUpdateBatch.fields = {
3050
+ ...this._fieldUpdateBatch.fields,
3032
3051
  ...fields
3033
3052
  };
3034
- if (this._debounceTimeout) clearTimeout(this._debounceTimeout);
3035
- this._debounceTimeout = setTimeout(async () => {
3036
- const data = await this.patchConfig(this._pendingFields);
3053
+ clearTimeout(this._fieldUpdateBatch.timeout);
3054
+ this._fieldUpdateBatch.timeout = setTimeout(() => this._flushFieldUpdate(), 1e3);
3055
+ return this._fieldUpdateBatch.deferred.promise;
3056
+ }
3057
+ /** Flush pending field updates to the API */
3058
+ async _flushFieldUpdate() {
3059
+ const batch = this._fieldUpdateBatch;
3060
+ this._fieldUpdateBatch = null;
3061
+ try {
3062
+ const data = await this.patchConfig(batch.fields);
3037
3063
  if (data?.updated_vehicles) {
3038
- this.logger.info(`Updated ${Object.keys(this._pendingFields).length} streaming fields for ${this.vin}`);
3064
+ this.logger.info(`Updated ${Object.keys(batch.fields).length} streaming fields for ${this.vin}`);
3039
3065
  this.fields = {
3040
3066
  ...this.fields,
3041
- ...this._pendingFields
3067
+ ...batch.fields
3042
3068
  };
3043
- this._pendingFields = {};
3044
- } else this.logger.error(`Error updating streaming config for ${this.vin}`, data);
3045
- this._debounceTimeout = null;
3046
- }, 1e3);
3069
+ batch.deferred.resolve();
3070
+ } else {
3071
+ const error = /* @__PURE__ */ new Error(`Error updating streaming config for ${this.vin}`);
3072
+ this.logger.error(error.message, data);
3073
+ batch.deferred.reject(error);
3074
+ }
3075
+ } catch (error) {
3076
+ batch.deferred.reject(error);
3077
+ }
3047
3078
  }
3048
3079
  /** Modify the field configuration of the vehicle */
3049
3080
  async patchConfig(fields) {
@@ -3067,15 +3098,15 @@ var TeslemetryVehicleStream = class extends EventEmitter {
3067
3098
  * Add a field to the vehicles streaming configuration
3068
3099
  * @param field Vehicle Signal
3069
3100
  * @param interval
3070
- * @returns
3101
+ * @returns Promise that resolves when the field is added
3071
3102
  */
3072
- async addField(field, interval) {
3103
+ addField(field, interval) {
3073
3104
  if (this.fields && this.fields[field] && (interval === void 0 || this.fields[field].interval_seconds === interval)) {
3074
3105
  this.logger.debug(`Streaming field ${field} already enabled @ ${this.fields[field]?.interval_seconds || "default"}s`);
3075
- return;
3106
+ return Promise.resolve();
3076
3107
  }
3077
3108
  const value = interval !== void 0 ? { interval_seconds: interval } : null;
3078
- this.updateFields({ [field]: value });
3109
+ return this.updateFields({ [field]: value });
3079
3110
  }
3080
3111
  /**
3081
3112
  * Helper to enable and listen for specific field signals
@@ -3084,8 +3115,8 @@ var TeslemetryVehicleStream = class extends EventEmitter {
3084
3115
  * @returns Off function to stop the listener
3085
3116
  */
3086
3117
  onSignal(field, callback) {
3087
- this.addField(field).catch((error) => {
3088
- this.logger.error(`Failed to add field ${field}:`, error);
3118
+ this.addField(field).catch(() => {
3119
+ this.logger.error(`Failed to add field ${field}`);
3089
3120
  });
3090
3121
  const data = this.root.sse.cache?.[this.vin]?.data?.[field];
3091
3122
  if (data !== void 0) callback(data);
@@ -3228,6 +3259,7 @@ var TeslemetryStream = class extends EventEmitter {
3228
3259
  else if ("credits" in event) this.emit("credits", event);
3229
3260
  else if ("vehicle_data" in event) this.emit("vehicle_data", event);
3230
3261
  else if ("config" in event) this.emit("config", event);
3262
+ this.emit("all", event);
3231
3263
  const vehicle = this.vehicles.get(event.vin);
3232
3264
  if (vehicle) {
3233
3265
  if ("state" in event) vehicle.emit("state", event);
@@ -5220,7 +5252,7 @@ const consoleLogger = {
5220
5252
 
5221
5253
  //#endregion
5222
5254
  //#region package.json
5223
- var version = "0.6.8";
5255
+ var version = "0.6.10";
5224
5256
 
5225
5257
  //#endregion
5226
5258
  //#region src/Teslemetry.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teslemetry/api",
3
- "version": "0.6.8",
3
+ "version": "0.6.10",
4
4
  "description": "API client for Teslemetry",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",