@hyve-sdk/js 2.1.1 → 2.2.0

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/index.d.mts CHANGED
@@ -72,6 +72,8 @@ interface Inventory {
72
72
  type GameDataValue = string | number | boolean | null | GameDataValue[] | {
73
73
  [key: string]: GameDataValue;
74
74
  };
75
+ /** Atomic operation type for persistent game data */
76
+ type GameDataOperation = 'set' | 'add' | 'subtract' | 'multiply' | 'divide' | 'modulo' | 'min' | 'max' | 'append';
75
77
  /** Single game data item with metadata */
76
78
  interface GameDataItem {
77
79
  key: string;
@@ -79,10 +81,27 @@ interface GameDataItem {
79
81
  created_at: string;
80
82
  updated_at: string;
81
83
  }
82
- /** Response from save operations */
84
+ /** Response from a single save operation */
83
85
  interface SaveGameDataResponse {
84
86
  success: boolean;
85
87
  message: string;
88
+ /** Resulting value after an atomic operation (only present when operation is used) */
89
+ result?: GameDataValue;
90
+ }
91
+ /** Per-item result in a batch save response */
92
+ interface BatchSaveResultItem {
93
+ key: string;
94
+ success: boolean;
95
+ /** Resulting value after an atomic operation */
96
+ result?: GameDataValue;
97
+ error?: string;
98
+ }
99
+ /** Response from a batch save operation */
100
+ interface BatchSaveGameDataResponse {
101
+ success: boolean;
102
+ message: string;
103
+ /** Per-item results (present when any item uses an operation) */
104
+ results?: BatchSaveResultItem[];
86
105
  }
87
106
  /** Response when getting a single game data entry */
88
107
  interface GetGameDataResponse {
@@ -101,6 +120,10 @@ interface DeleteGameDataResponse {
101
120
  interface GameDataBatchItem {
102
121
  key: string;
103
122
  value: GameDataValue;
123
+ /** Atomic operation to perform on the value */
124
+ operation?: GameDataOperation;
125
+ /** Dot-notation path targeting a nested field (e.g. "stats.score") */
126
+ path?: string;
104
127
  }
105
128
 
106
129
  /**
@@ -522,17 +545,19 @@ declare class HyveClient {
522
545
  * Save persistent game data
523
546
  * @param key Data key
524
547
  * @param value Data value (any JSON-serializable value)
548
+ * @param operation Optional atomic operation (e.g. 'add', 'max', 'append')
549
+ * @param path Optional dot-notation path to a nested field (e.g. 'stats.score')
525
550
  * @param storage Storage mode override ('cloud' or 'local')
526
551
  * @returns Promise resolving to save response
527
552
  */
528
- saveGameData(key: string, value: GameDataValue, storage?: 'cloud' | 'local'): Promise<SaveGameDataResponse>;
553
+ saveGameData(key: string, value: GameDataValue, operation?: GameDataOperation, path?: string, storage?: 'cloud' | 'local'): Promise<SaveGameDataResponse>;
529
554
  /**
530
555
  * Batch save persistent game data
531
- * @param items Array of key-value pairs to save
556
+ * @param items Array of items to save (each may include an optional operation and path)
532
557
  * @param storage Storage mode override ('cloud' or 'local')
533
- * @returns Promise resolving to save response
558
+ * @returns Promise resolving to batch save response with per-item results
534
559
  */
535
- batchSaveGameData(items: GameDataBatchItem[], storage?: 'cloud' | 'local'): Promise<SaveGameDataResponse>;
560
+ batchSaveGameData(items: GameDataBatchItem[], storage?: 'cloud' | 'local'): Promise<BatchSaveGameDataResponse>;
536
561
  /**
537
562
  * Get persistent game data
538
563
  * @param key Data key
@@ -794,8 +819,8 @@ declare class CrazyGamesService {
794
819
  * Storage adapter interface - supports cloud and local implementations
795
820
  */
796
821
  interface StorageAdapter {
797
- saveGameData(gameId: string, key: string, value: GameDataValue): Promise<SaveGameDataResponse>;
798
- batchSaveGameData(gameId: string, items: GameDataBatchItem[]): Promise<SaveGameDataResponse>;
822
+ saveGameData(gameId: string, key: string, value: GameDataValue, operation?: GameDataOperation, path?: string): Promise<SaveGameDataResponse>;
823
+ batchSaveGameData(gameId: string, items: GameDataBatchItem[]): Promise<BatchSaveGameDataResponse>;
799
824
  getGameData(gameId: string, key: string): Promise<GameDataItem | null>;
800
825
  getMultipleGameData(gameId: string, keys: string[]): Promise<GameDataItem[]>;
801
826
  deleteGameData(gameId: string, key: string): Promise<boolean>;
@@ -807,8 +832,8 @@ interface StorageAdapter {
807
832
  declare class CloudStorageAdapter implements StorageAdapter {
808
833
  private callApi;
809
834
  constructor(callApi: <T = any>(endpoint: string, options?: RequestInit) => Promise<T>);
810
- saveGameData(gameId: string, key: string, value: GameDataValue): Promise<SaveGameDataResponse>;
811
- batchSaveGameData(gameId: string, items: GameDataBatchItem[]): Promise<SaveGameDataResponse>;
835
+ saveGameData(gameId: string, key: string, value: GameDataValue, operation?: GameDataOperation, path?: string): Promise<SaveGameDataResponse>;
836
+ batchSaveGameData(gameId: string, items: GameDataBatchItem[]): Promise<BatchSaveGameDataResponse>;
812
837
  getGameData(gameId: string, key: string): Promise<GameDataItem | null>;
813
838
  getMultipleGameData(gameId: string, keys: string[]): Promise<GameDataItem[]>;
814
839
  deleteGameData(gameId: string, key: string): Promise<boolean>;
@@ -823,8 +848,8 @@ declare class LocalStorageAdapter implements StorageAdapter {
823
848
  private readonly storagePrefix;
824
849
  constructor(getUserId: () => string | null);
825
850
  private getStorageKey;
826
- saveGameData(gameId: string, key: string, value: GameDataValue): Promise<SaveGameDataResponse>;
827
- batchSaveGameData(gameId: string, items: GameDataBatchItem[]): Promise<SaveGameDataResponse>;
851
+ saveGameData(gameId: string, key: string, value: GameDataValue, _operation?: GameDataOperation, _path?: string): Promise<SaveGameDataResponse>;
852
+ batchSaveGameData(gameId: string, items: GameDataBatchItem[]): Promise<BatchSaveGameDataResponse>;
828
853
  getGameData(gameId: string, key: string): Promise<GameDataItem | null>;
829
854
  getMultipleGameData(gameId: string, keys: string[]): Promise<GameDataItem[]>;
830
855
  deleteGameData(gameId: string, key: string): Promise<boolean>;
@@ -1064,4 +1089,4 @@ declare class NativeBridge {
1064
1089
  */
1065
1090
  declare function generateUUID(): string;
1066
1091
 
1067
- export { type AdConfig, type AdResult, type AdType, AdsService, type BillingConfig, BillingPlatform, type BillingProduct, BillingService, CloudStorageAdapter, CrazyGamesService, type DeleteGameDataResponse, type GameDataBatchItem, type GameDataItem, type GameDataValue, type GetGameDataBatchResponse, type GetGameDataResponse, HyveClient, type HyveClientConfig, type Inventory, type InventoryItem, LocalStorageAdapter, Logger, NativeBridge, type NativeMessage, type NativeMessageHandler, NativeMessageType, PlaygamaService, type PurchaseResult, type SaveGameDataResponse, type StorageAdapter, type TelemetryAdditionalData, type TelemetryConfig, type TelemetryEvent, generateUUID, isDomainAllowed, logger, parseUrlParams };
1092
+ export { type AdConfig, type AdResult, type AdType, AdsService, type BatchSaveGameDataResponse, type BatchSaveResultItem, type BillingConfig, BillingPlatform, type BillingProduct, BillingService, CloudStorageAdapter, CrazyGamesService, type DeleteGameDataResponse, type GameDataBatchItem, type GameDataItem, type GameDataOperation, type GameDataValue, type GetGameDataBatchResponse, type GetGameDataResponse, HyveClient, type HyveClientConfig, type Inventory, type InventoryItem, LocalStorageAdapter, Logger, NativeBridge, type NativeMessage, type NativeMessageHandler, NativeMessageType, PlaygamaService, type PurchaseResult, type SaveGameDataResponse, type StorageAdapter, type TelemetryAdditionalData, type TelemetryConfig, type TelemetryEvent, generateUUID, isDomainAllowed, logger, parseUrlParams };
package/dist/index.d.ts CHANGED
@@ -72,6 +72,8 @@ interface Inventory {
72
72
  type GameDataValue = string | number | boolean | null | GameDataValue[] | {
73
73
  [key: string]: GameDataValue;
74
74
  };
75
+ /** Atomic operation type for persistent game data */
76
+ type GameDataOperation = 'set' | 'add' | 'subtract' | 'multiply' | 'divide' | 'modulo' | 'min' | 'max' | 'append';
75
77
  /** Single game data item with metadata */
76
78
  interface GameDataItem {
77
79
  key: string;
@@ -79,10 +81,27 @@ interface GameDataItem {
79
81
  created_at: string;
80
82
  updated_at: string;
81
83
  }
82
- /** Response from save operations */
84
+ /** Response from a single save operation */
83
85
  interface SaveGameDataResponse {
84
86
  success: boolean;
85
87
  message: string;
88
+ /** Resulting value after an atomic operation (only present when operation is used) */
89
+ result?: GameDataValue;
90
+ }
91
+ /** Per-item result in a batch save response */
92
+ interface BatchSaveResultItem {
93
+ key: string;
94
+ success: boolean;
95
+ /** Resulting value after an atomic operation */
96
+ result?: GameDataValue;
97
+ error?: string;
98
+ }
99
+ /** Response from a batch save operation */
100
+ interface BatchSaveGameDataResponse {
101
+ success: boolean;
102
+ message: string;
103
+ /** Per-item results (present when any item uses an operation) */
104
+ results?: BatchSaveResultItem[];
86
105
  }
87
106
  /** Response when getting a single game data entry */
88
107
  interface GetGameDataResponse {
@@ -101,6 +120,10 @@ interface DeleteGameDataResponse {
101
120
  interface GameDataBatchItem {
102
121
  key: string;
103
122
  value: GameDataValue;
123
+ /** Atomic operation to perform on the value */
124
+ operation?: GameDataOperation;
125
+ /** Dot-notation path targeting a nested field (e.g. "stats.score") */
126
+ path?: string;
104
127
  }
105
128
 
106
129
  /**
@@ -522,17 +545,19 @@ declare class HyveClient {
522
545
  * Save persistent game data
523
546
  * @param key Data key
524
547
  * @param value Data value (any JSON-serializable value)
548
+ * @param operation Optional atomic operation (e.g. 'add', 'max', 'append')
549
+ * @param path Optional dot-notation path to a nested field (e.g. 'stats.score')
525
550
  * @param storage Storage mode override ('cloud' or 'local')
526
551
  * @returns Promise resolving to save response
527
552
  */
528
- saveGameData(key: string, value: GameDataValue, storage?: 'cloud' | 'local'): Promise<SaveGameDataResponse>;
553
+ saveGameData(key: string, value: GameDataValue, operation?: GameDataOperation, path?: string, storage?: 'cloud' | 'local'): Promise<SaveGameDataResponse>;
529
554
  /**
530
555
  * Batch save persistent game data
531
- * @param items Array of key-value pairs to save
556
+ * @param items Array of items to save (each may include an optional operation and path)
532
557
  * @param storage Storage mode override ('cloud' or 'local')
533
- * @returns Promise resolving to save response
558
+ * @returns Promise resolving to batch save response with per-item results
534
559
  */
535
- batchSaveGameData(items: GameDataBatchItem[], storage?: 'cloud' | 'local'): Promise<SaveGameDataResponse>;
560
+ batchSaveGameData(items: GameDataBatchItem[], storage?: 'cloud' | 'local'): Promise<BatchSaveGameDataResponse>;
536
561
  /**
537
562
  * Get persistent game data
538
563
  * @param key Data key
@@ -794,8 +819,8 @@ declare class CrazyGamesService {
794
819
  * Storage adapter interface - supports cloud and local implementations
795
820
  */
796
821
  interface StorageAdapter {
797
- saveGameData(gameId: string, key: string, value: GameDataValue): Promise<SaveGameDataResponse>;
798
- batchSaveGameData(gameId: string, items: GameDataBatchItem[]): Promise<SaveGameDataResponse>;
822
+ saveGameData(gameId: string, key: string, value: GameDataValue, operation?: GameDataOperation, path?: string): Promise<SaveGameDataResponse>;
823
+ batchSaveGameData(gameId: string, items: GameDataBatchItem[]): Promise<BatchSaveGameDataResponse>;
799
824
  getGameData(gameId: string, key: string): Promise<GameDataItem | null>;
800
825
  getMultipleGameData(gameId: string, keys: string[]): Promise<GameDataItem[]>;
801
826
  deleteGameData(gameId: string, key: string): Promise<boolean>;
@@ -807,8 +832,8 @@ interface StorageAdapter {
807
832
  declare class CloudStorageAdapter implements StorageAdapter {
808
833
  private callApi;
809
834
  constructor(callApi: <T = any>(endpoint: string, options?: RequestInit) => Promise<T>);
810
- saveGameData(gameId: string, key: string, value: GameDataValue): Promise<SaveGameDataResponse>;
811
- batchSaveGameData(gameId: string, items: GameDataBatchItem[]): Promise<SaveGameDataResponse>;
835
+ saveGameData(gameId: string, key: string, value: GameDataValue, operation?: GameDataOperation, path?: string): Promise<SaveGameDataResponse>;
836
+ batchSaveGameData(gameId: string, items: GameDataBatchItem[]): Promise<BatchSaveGameDataResponse>;
812
837
  getGameData(gameId: string, key: string): Promise<GameDataItem | null>;
813
838
  getMultipleGameData(gameId: string, keys: string[]): Promise<GameDataItem[]>;
814
839
  deleteGameData(gameId: string, key: string): Promise<boolean>;
@@ -823,8 +848,8 @@ declare class LocalStorageAdapter implements StorageAdapter {
823
848
  private readonly storagePrefix;
824
849
  constructor(getUserId: () => string | null);
825
850
  private getStorageKey;
826
- saveGameData(gameId: string, key: string, value: GameDataValue): Promise<SaveGameDataResponse>;
827
- batchSaveGameData(gameId: string, items: GameDataBatchItem[]): Promise<SaveGameDataResponse>;
851
+ saveGameData(gameId: string, key: string, value: GameDataValue, _operation?: GameDataOperation, _path?: string): Promise<SaveGameDataResponse>;
852
+ batchSaveGameData(gameId: string, items: GameDataBatchItem[]): Promise<BatchSaveGameDataResponse>;
828
853
  getGameData(gameId: string, key: string): Promise<GameDataItem | null>;
829
854
  getMultipleGameData(gameId: string, keys: string[]): Promise<GameDataItem[]>;
830
855
  deleteGameData(gameId: string, key: string): Promise<boolean>;
@@ -1064,4 +1089,4 @@ declare class NativeBridge {
1064
1089
  */
1065
1090
  declare function generateUUID(): string;
1066
1091
 
1067
- export { type AdConfig, type AdResult, type AdType, AdsService, type BillingConfig, BillingPlatform, type BillingProduct, BillingService, CloudStorageAdapter, CrazyGamesService, type DeleteGameDataResponse, type GameDataBatchItem, type GameDataItem, type GameDataValue, type GetGameDataBatchResponse, type GetGameDataResponse, HyveClient, type HyveClientConfig, type Inventory, type InventoryItem, LocalStorageAdapter, Logger, NativeBridge, type NativeMessage, type NativeMessageHandler, NativeMessageType, PlaygamaService, type PurchaseResult, type SaveGameDataResponse, type StorageAdapter, type TelemetryAdditionalData, type TelemetryConfig, type TelemetryEvent, generateUUID, isDomainAllowed, logger, parseUrlParams };
1092
+ export { type AdConfig, type AdResult, type AdType, AdsService, type BatchSaveGameDataResponse, type BatchSaveResultItem, type BillingConfig, BillingPlatform, type BillingProduct, BillingService, CloudStorageAdapter, CrazyGamesService, type DeleteGameDataResponse, type GameDataBatchItem, type GameDataItem, type GameDataOperation, type GameDataValue, type GetGameDataBatchResponse, type GetGameDataResponse, HyveClient, type HyveClientConfig, type Inventory, type InventoryItem, LocalStorageAdapter, Logger, NativeBridge, type NativeMessage, type NativeMessageHandler, NativeMessageType, PlaygamaService, type PurchaseResult, type SaveGameDataResponse, type StorageAdapter, type TelemetryAdditionalData, type TelemetryConfig, type TelemetryEvent, generateUUID, isDomainAllowed, logger, parseUrlParams };
package/dist/index.js CHANGED
@@ -1433,13 +1433,19 @@ var CloudStorageAdapter = class {
1433
1433
  constructor(callApi) {
1434
1434
  this.callApi = callApi;
1435
1435
  }
1436
- async saveGameData(gameId, key, value) {
1436
+ async saveGameData(gameId, key, value, operation, path) {
1437
1437
  return this.callApi("/api/v1/persistent-game-data", {
1438
1438
  method: "POST",
1439
1439
  headers: {
1440
1440
  "Content-Type": "application/json"
1441
1441
  },
1442
- body: JSON.stringify({ game_id: gameId, key, value })
1442
+ body: JSON.stringify({
1443
+ game_id: gameId,
1444
+ key,
1445
+ value,
1446
+ ...operation !== void 0 && { operation },
1447
+ ...path !== void 0 && { path }
1448
+ })
1443
1449
  });
1444
1450
  }
1445
1451
  async batchSaveGameData(gameId, items) {
@@ -1509,7 +1515,7 @@ var LocalStorageAdapter = class {
1509
1515
  getStorageKey(gameId, key) {
1510
1516
  return `${this.storagePrefix}:${gameId}:${key}`;
1511
1517
  }
1512
- async saveGameData(gameId, key, value) {
1518
+ async saveGameData(gameId, key, value, _operation, _path) {
1513
1519
  try {
1514
1520
  const storageKey = this.getStorageKey(gameId, key);
1515
1521
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -1932,30 +1938,34 @@ var HyveClient = class {
1932
1938
  * Returns the current game ID or throws if not available.
1933
1939
  */
1934
1940
  requireGameId() {
1935
- const gameId = this.requireGameId();
1936
- return gameId;
1941
+ if (!this.gameId) {
1942
+ throw new Error("Game ID required. Ensure game-id URL parameter is set.");
1943
+ }
1944
+ return this.gameId;
1937
1945
  }
1938
1946
  /**
1939
1947
  * Save persistent game data
1940
1948
  * @param key Data key
1941
1949
  * @param value Data value (any JSON-serializable value)
1950
+ * @param operation Optional atomic operation (e.g. 'add', 'max', 'append')
1951
+ * @param path Optional dot-notation path to a nested field (e.g. 'stats.score')
1942
1952
  * @param storage Storage mode override ('cloud' or 'local')
1943
1953
  * @returns Promise resolving to save response
1944
1954
  */
1945
- async saveGameData(key, value, storage) {
1955
+ async saveGameData(key, value, operation, path, storage) {
1946
1956
  const gameId = this.requireGameId();
1947
1957
  const storageMode = storage || this.storageMode;
1948
1958
  logger.debug(`Saving game data to ${storageMode}: ${gameId}/${key}`);
1949
1959
  const adapter = this.getStorageAdapter(storage);
1950
- const response = await adapter.saveGameData(gameId, key, value);
1960
+ const response = await adapter.saveGameData(gameId, key, value, operation, path);
1951
1961
  logger.info(`Game data saved successfully to ${storageMode}: ${gameId}/${key}`);
1952
1962
  return response;
1953
1963
  }
1954
1964
  /**
1955
1965
  * Batch save persistent game data
1956
- * @param items Array of key-value pairs to save
1966
+ * @param items Array of items to save (each may include an optional operation and path)
1957
1967
  * @param storage Storage mode override ('cloud' or 'local')
1958
- * @returns Promise resolving to save response
1968
+ * @returns Promise resolving to batch save response with per-item results
1959
1969
  */
1960
1970
  async batchSaveGameData(items, storage) {
1961
1971
  const gameId = this.requireGameId();
package/dist/index.mjs CHANGED
@@ -1393,13 +1393,19 @@ var CloudStorageAdapter = class {
1393
1393
  constructor(callApi) {
1394
1394
  this.callApi = callApi;
1395
1395
  }
1396
- async saveGameData(gameId, key, value) {
1396
+ async saveGameData(gameId, key, value, operation, path) {
1397
1397
  return this.callApi("/api/v1/persistent-game-data", {
1398
1398
  method: "POST",
1399
1399
  headers: {
1400
1400
  "Content-Type": "application/json"
1401
1401
  },
1402
- body: JSON.stringify({ game_id: gameId, key, value })
1402
+ body: JSON.stringify({
1403
+ game_id: gameId,
1404
+ key,
1405
+ value,
1406
+ ...operation !== void 0 && { operation },
1407
+ ...path !== void 0 && { path }
1408
+ })
1403
1409
  });
1404
1410
  }
1405
1411
  async batchSaveGameData(gameId, items) {
@@ -1469,7 +1475,7 @@ var LocalStorageAdapter = class {
1469
1475
  getStorageKey(gameId, key) {
1470
1476
  return `${this.storagePrefix}:${gameId}:${key}`;
1471
1477
  }
1472
- async saveGameData(gameId, key, value) {
1478
+ async saveGameData(gameId, key, value, _operation, _path) {
1473
1479
  try {
1474
1480
  const storageKey = this.getStorageKey(gameId, key);
1475
1481
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -1892,30 +1898,34 @@ var HyveClient = class {
1892
1898
  * Returns the current game ID or throws if not available.
1893
1899
  */
1894
1900
  requireGameId() {
1895
- const gameId = this.requireGameId();
1896
- return gameId;
1901
+ if (!this.gameId) {
1902
+ throw new Error("Game ID required. Ensure game-id URL parameter is set.");
1903
+ }
1904
+ return this.gameId;
1897
1905
  }
1898
1906
  /**
1899
1907
  * Save persistent game data
1900
1908
  * @param key Data key
1901
1909
  * @param value Data value (any JSON-serializable value)
1910
+ * @param operation Optional atomic operation (e.g. 'add', 'max', 'append')
1911
+ * @param path Optional dot-notation path to a nested field (e.g. 'stats.score')
1902
1912
  * @param storage Storage mode override ('cloud' or 'local')
1903
1913
  * @returns Promise resolving to save response
1904
1914
  */
1905
- async saveGameData(key, value, storage) {
1915
+ async saveGameData(key, value, operation, path, storage) {
1906
1916
  const gameId = this.requireGameId();
1907
1917
  const storageMode = storage || this.storageMode;
1908
1918
  logger.debug(`Saving game data to ${storageMode}: ${gameId}/${key}`);
1909
1919
  const adapter = this.getStorageAdapter(storage);
1910
- const response = await adapter.saveGameData(gameId, key, value);
1920
+ const response = await adapter.saveGameData(gameId, key, value, operation, path);
1911
1921
  logger.info(`Game data saved successfully to ${storageMode}: ${gameId}/${key}`);
1912
1922
  return response;
1913
1923
  }
1914
1924
  /**
1915
1925
  * Batch save persistent game data
1916
- * @param items Array of key-value pairs to save
1926
+ * @param items Array of items to save (each may include an optional operation and path)
1917
1927
  * @param storage Storage mode override ('cloud' or 'local')
1918
- * @returns Promise resolving to save response
1928
+ * @returns Promise resolving to batch save response with per-item results
1919
1929
  */
1920
1930
  async batchSaveGameData(items, storage) {
1921
1931
  const gameId = this.requireGameId();
package/dist/react.d.mts CHANGED
@@ -41,6 +41,8 @@ interface Inventory {
41
41
  type GameDataValue = string | number | boolean | null | GameDataValue[] | {
42
42
  [key: string]: GameDataValue;
43
43
  };
44
+ /** Atomic operation type for persistent game data */
45
+ type GameDataOperation = 'set' | 'add' | 'subtract' | 'multiply' | 'divide' | 'modulo' | 'min' | 'max' | 'append';
44
46
  /** Single game data item with metadata */
45
47
  interface GameDataItem {
46
48
  key: string;
@@ -48,15 +50,36 @@ interface GameDataItem {
48
50
  created_at: string;
49
51
  updated_at: string;
50
52
  }
51
- /** Response from save operations */
53
+ /** Response from a single save operation */
52
54
  interface SaveGameDataResponse {
53
55
  success: boolean;
54
56
  message: string;
57
+ /** Resulting value after an atomic operation (only present when operation is used) */
58
+ result?: GameDataValue;
59
+ }
60
+ /** Per-item result in a batch save response */
61
+ interface BatchSaveResultItem {
62
+ key: string;
63
+ success: boolean;
64
+ /** Resulting value after an atomic operation */
65
+ result?: GameDataValue;
66
+ error?: string;
67
+ }
68
+ /** Response from a batch save operation */
69
+ interface BatchSaveGameDataResponse {
70
+ success: boolean;
71
+ message: string;
72
+ /** Per-item results (present when any item uses an operation) */
73
+ results?: BatchSaveResultItem[];
55
74
  }
56
75
  /** Batch item for saving multiple entries */
57
76
  interface GameDataBatchItem {
58
77
  key: string;
59
78
  value: GameDataValue;
79
+ /** Atomic operation to perform on the value */
80
+ operation?: GameDataOperation;
81
+ /** Dot-notation path targeting a nested field (e.g. "stats.score") */
82
+ path?: string;
60
83
  }
61
84
 
62
85
  /**
@@ -297,17 +320,19 @@ declare class HyveClient {
297
320
  * Save persistent game data
298
321
  * @param key Data key
299
322
  * @param value Data value (any JSON-serializable value)
323
+ * @param operation Optional atomic operation (e.g. 'add', 'max', 'append')
324
+ * @param path Optional dot-notation path to a nested field (e.g. 'stats.score')
300
325
  * @param storage Storage mode override ('cloud' or 'local')
301
326
  * @returns Promise resolving to save response
302
327
  */
303
- saveGameData(key: string, value: GameDataValue, storage?: 'cloud' | 'local'): Promise<SaveGameDataResponse>;
328
+ saveGameData(key: string, value: GameDataValue, operation?: GameDataOperation, path?: string, storage?: 'cloud' | 'local'): Promise<SaveGameDataResponse>;
304
329
  /**
305
330
  * Batch save persistent game data
306
- * @param items Array of key-value pairs to save
331
+ * @param items Array of items to save (each may include an optional operation and path)
307
332
  * @param storage Storage mode override ('cloud' or 'local')
308
- * @returns Promise resolving to save response
333
+ * @returns Promise resolving to batch save response with per-item results
309
334
  */
310
- batchSaveGameData(items: GameDataBatchItem[], storage?: 'cloud' | 'local'): Promise<SaveGameDataResponse>;
335
+ batchSaveGameData(items: GameDataBatchItem[], storage?: 'cloud' | 'local'): Promise<BatchSaveGameDataResponse>;
311
336
  /**
312
337
  * Get persistent game data
313
338
  * @param key Data key
package/dist/react.d.ts CHANGED
@@ -41,6 +41,8 @@ interface Inventory {
41
41
  type GameDataValue = string | number | boolean | null | GameDataValue[] | {
42
42
  [key: string]: GameDataValue;
43
43
  };
44
+ /** Atomic operation type for persistent game data */
45
+ type GameDataOperation = 'set' | 'add' | 'subtract' | 'multiply' | 'divide' | 'modulo' | 'min' | 'max' | 'append';
44
46
  /** Single game data item with metadata */
45
47
  interface GameDataItem {
46
48
  key: string;
@@ -48,15 +50,36 @@ interface GameDataItem {
48
50
  created_at: string;
49
51
  updated_at: string;
50
52
  }
51
- /** Response from save operations */
53
+ /** Response from a single save operation */
52
54
  interface SaveGameDataResponse {
53
55
  success: boolean;
54
56
  message: string;
57
+ /** Resulting value after an atomic operation (only present when operation is used) */
58
+ result?: GameDataValue;
59
+ }
60
+ /** Per-item result in a batch save response */
61
+ interface BatchSaveResultItem {
62
+ key: string;
63
+ success: boolean;
64
+ /** Resulting value after an atomic operation */
65
+ result?: GameDataValue;
66
+ error?: string;
67
+ }
68
+ /** Response from a batch save operation */
69
+ interface BatchSaveGameDataResponse {
70
+ success: boolean;
71
+ message: string;
72
+ /** Per-item results (present when any item uses an operation) */
73
+ results?: BatchSaveResultItem[];
55
74
  }
56
75
  /** Batch item for saving multiple entries */
57
76
  interface GameDataBatchItem {
58
77
  key: string;
59
78
  value: GameDataValue;
79
+ /** Atomic operation to perform on the value */
80
+ operation?: GameDataOperation;
81
+ /** Dot-notation path targeting a nested field (e.g. "stats.score") */
82
+ path?: string;
60
83
  }
61
84
 
62
85
  /**
@@ -297,17 +320,19 @@ declare class HyveClient {
297
320
  * Save persistent game data
298
321
  * @param key Data key
299
322
  * @param value Data value (any JSON-serializable value)
323
+ * @param operation Optional atomic operation (e.g. 'add', 'max', 'append')
324
+ * @param path Optional dot-notation path to a nested field (e.g. 'stats.score')
300
325
  * @param storage Storage mode override ('cloud' or 'local')
301
326
  * @returns Promise resolving to save response
302
327
  */
303
- saveGameData(key: string, value: GameDataValue, storage?: 'cloud' | 'local'): Promise<SaveGameDataResponse>;
328
+ saveGameData(key: string, value: GameDataValue, operation?: GameDataOperation, path?: string, storage?: 'cloud' | 'local'): Promise<SaveGameDataResponse>;
304
329
  /**
305
330
  * Batch save persistent game data
306
- * @param items Array of key-value pairs to save
331
+ * @param items Array of items to save (each may include an optional operation and path)
307
332
  * @param storage Storage mode override ('cloud' or 'local')
308
- * @returns Promise resolving to save response
333
+ * @returns Promise resolving to batch save response with per-item results
309
334
  */
310
- batchSaveGameData(items: GameDataBatchItem[], storage?: 'cloud' | 'local'): Promise<SaveGameDataResponse>;
335
+ batchSaveGameData(items: GameDataBatchItem[], storage?: 'cloud' | 'local'): Promise<BatchSaveGameDataResponse>;
311
336
  /**
312
337
  * Get persistent game data
313
338
  * @param key Data key
package/dist/react.js CHANGED
@@ -1384,13 +1384,19 @@ var CloudStorageAdapter = class {
1384
1384
  constructor(callApi) {
1385
1385
  this.callApi = callApi;
1386
1386
  }
1387
- async saveGameData(gameId, key, value) {
1387
+ async saveGameData(gameId, key, value, operation, path) {
1388
1388
  return this.callApi("/api/v1/persistent-game-data", {
1389
1389
  method: "POST",
1390
1390
  headers: {
1391
1391
  "Content-Type": "application/json"
1392
1392
  },
1393
- body: JSON.stringify({ game_id: gameId, key, value })
1393
+ body: JSON.stringify({
1394
+ game_id: gameId,
1395
+ key,
1396
+ value,
1397
+ ...operation !== void 0 && { operation },
1398
+ ...path !== void 0 && { path }
1399
+ })
1394
1400
  });
1395
1401
  }
1396
1402
  async batchSaveGameData(gameId, items) {
@@ -1460,7 +1466,7 @@ var LocalStorageAdapter = class {
1460
1466
  getStorageKey(gameId, key) {
1461
1467
  return `${this.storagePrefix}:${gameId}:${key}`;
1462
1468
  }
1463
- async saveGameData(gameId, key, value) {
1469
+ async saveGameData(gameId, key, value, _operation, _path) {
1464
1470
  try {
1465
1471
  const storageKey = this.getStorageKey(gameId, key);
1466
1472
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -1883,30 +1889,34 @@ var HyveClient = class {
1883
1889
  * Returns the current game ID or throws if not available.
1884
1890
  */
1885
1891
  requireGameId() {
1886
- const gameId = this.requireGameId();
1887
- return gameId;
1892
+ if (!this.gameId) {
1893
+ throw new Error("Game ID required. Ensure game-id URL parameter is set.");
1894
+ }
1895
+ return this.gameId;
1888
1896
  }
1889
1897
  /**
1890
1898
  * Save persistent game data
1891
1899
  * @param key Data key
1892
1900
  * @param value Data value (any JSON-serializable value)
1901
+ * @param operation Optional atomic operation (e.g. 'add', 'max', 'append')
1902
+ * @param path Optional dot-notation path to a nested field (e.g. 'stats.score')
1893
1903
  * @param storage Storage mode override ('cloud' or 'local')
1894
1904
  * @returns Promise resolving to save response
1895
1905
  */
1896
- async saveGameData(key, value, storage) {
1906
+ async saveGameData(key, value, operation, path, storage) {
1897
1907
  const gameId = this.requireGameId();
1898
1908
  const storageMode = storage || this.storageMode;
1899
1909
  logger.debug(`Saving game data to ${storageMode}: ${gameId}/${key}`);
1900
1910
  const adapter = this.getStorageAdapter(storage);
1901
- const response = await adapter.saveGameData(gameId, key, value);
1911
+ const response = await adapter.saveGameData(gameId, key, value, operation, path);
1902
1912
  logger.info(`Game data saved successfully to ${storageMode}: ${gameId}/${key}`);
1903
1913
  return response;
1904
1914
  }
1905
1915
  /**
1906
1916
  * Batch save persistent game data
1907
- * @param items Array of key-value pairs to save
1917
+ * @param items Array of items to save (each may include an optional operation and path)
1908
1918
  * @param storage Storage mode override ('cloud' or 'local')
1909
- * @returns Promise resolving to save response
1919
+ * @returns Promise resolving to batch save response with per-item results
1910
1920
  */
1911
1921
  async batchSaveGameData(items, storage) {
1912
1922
  const gameId = this.requireGameId();
package/dist/react.mjs CHANGED
@@ -1363,13 +1363,19 @@ var CloudStorageAdapter = class {
1363
1363
  constructor(callApi) {
1364
1364
  this.callApi = callApi;
1365
1365
  }
1366
- async saveGameData(gameId, key, value) {
1366
+ async saveGameData(gameId, key, value, operation, path) {
1367
1367
  return this.callApi("/api/v1/persistent-game-data", {
1368
1368
  method: "POST",
1369
1369
  headers: {
1370
1370
  "Content-Type": "application/json"
1371
1371
  },
1372
- body: JSON.stringify({ game_id: gameId, key, value })
1372
+ body: JSON.stringify({
1373
+ game_id: gameId,
1374
+ key,
1375
+ value,
1376
+ ...operation !== void 0 && { operation },
1377
+ ...path !== void 0 && { path }
1378
+ })
1373
1379
  });
1374
1380
  }
1375
1381
  async batchSaveGameData(gameId, items) {
@@ -1439,7 +1445,7 @@ var LocalStorageAdapter = class {
1439
1445
  getStorageKey(gameId, key) {
1440
1446
  return `${this.storagePrefix}:${gameId}:${key}`;
1441
1447
  }
1442
- async saveGameData(gameId, key, value) {
1448
+ async saveGameData(gameId, key, value, _operation, _path) {
1443
1449
  try {
1444
1450
  const storageKey = this.getStorageKey(gameId, key);
1445
1451
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -1862,30 +1868,34 @@ var HyveClient = class {
1862
1868
  * Returns the current game ID or throws if not available.
1863
1869
  */
1864
1870
  requireGameId() {
1865
- const gameId = this.requireGameId();
1866
- return gameId;
1871
+ if (!this.gameId) {
1872
+ throw new Error("Game ID required. Ensure game-id URL parameter is set.");
1873
+ }
1874
+ return this.gameId;
1867
1875
  }
1868
1876
  /**
1869
1877
  * Save persistent game data
1870
1878
  * @param key Data key
1871
1879
  * @param value Data value (any JSON-serializable value)
1880
+ * @param operation Optional atomic operation (e.g. 'add', 'max', 'append')
1881
+ * @param path Optional dot-notation path to a nested field (e.g. 'stats.score')
1872
1882
  * @param storage Storage mode override ('cloud' or 'local')
1873
1883
  * @returns Promise resolving to save response
1874
1884
  */
1875
- async saveGameData(key, value, storage) {
1885
+ async saveGameData(key, value, operation, path, storage) {
1876
1886
  const gameId = this.requireGameId();
1877
1887
  const storageMode = storage || this.storageMode;
1878
1888
  logger.debug(`Saving game data to ${storageMode}: ${gameId}/${key}`);
1879
1889
  const adapter = this.getStorageAdapter(storage);
1880
- const response = await adapter.saveGameData(gameId, key, value);
1890
+ const response = await adapter.saveGameData(gameId, key, value, operation, path);
1881
1891
  logger.info(`Game data saved successfully to ${storageMode}: ${gameId}/${key}`);
1882
1892
  return response;
1883
1893
  }
1884
1894
  /**
1885
1895
  * Batch save persistent game data
1886
- * @param items Array of key-value pairs to save
1896
+ * @param items Array of items to save (each may include an optional operation and path)
1887
1897
  * @param storage Storage mode override ('cloud' or 'local')
1888
- * @returns Promise resolving to save response
1898
+ * @returns Promise resolving to batch save response with per-item results
1889
1899
  */
1890
1900
  async batchSaveGameData(items, storage) {
1891
1901
  const gameId = this.requireGameId();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyve-sdk/js",
3
- "version": "2.1.1",
3
+ "version": "2.2.0",
4
4
  "description": "Hyve SDK - TypeScript wrapper for Hyve game server integration",
5
5
  "private": false,
6
6
  "publishConfig": {
@@ -27,6 +27,14 @@
27
27
  "README.md",
28
28
  "LICENSE"
29
29
  ],
30
+ "scripts": {
31
+ "lint": "eslint . --max-warnings 0",
32
+ "check-types": "tsc --noEmit",
33
+ "build": "tsup",
34
+ "prepublishOnly": "pnpm run build && pnpm run check-types",
35
+ "publish:npm": "pnpm publish --access public",
36
+ "publish:dry-run": "pnpm publish --dry-run --access public --no-git-checks"
37
+ },
30
38
  "keywords": [
31
39
  "hyve",
32
40
  "game",
@@ -63,19 +71,12 @@
63
71
  }
64
72
  },
65
73
  "devDependencies": {
74
+ "@repo/eslint-config": "workspace:*",
75
+ "@repo/typescript-config": "workspace:*",
66
76
  "@types/minimatch": "^5.1.2",
67
77
  "@types/react": "^18.3.28",
68
78
  "@types/uuid": "^10.0.0",
69
79
  "tsup": "^8.4.0",
70
- "typescript": "^5.3.3",
71
- "@repo/eslint-config": "0.0.0",
72
- "@repo/typescript-config": "0.0.0"
73
- },
74
- "scripts": {
75
- "lint": "eslint . --max-warnings 0",
76
- "check-types": "tsc --noEmit",
77
- "build": "tsup",
78
- "publish:npm": "pnpm publish --access public",
79
- "publish:dry-run": "pnpm publish --dry-run --access public --no-git-checks"
80
+ "typescript": "^5.3.3"
80
81
  }
81
- }
82
+ }