@optimizely/ocp-local-env 1.0.0-beta.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.
Files changed (244) hide show
  1. package/README.md +51 -0
  2. package/dist/package.json +112 -0
  3. package/dist/public/bundle.82dc5d29fffb9f205051.js +3 -0
  4. package/dist/public/bundle.82dc5d29fffb9f205051.js.LICENSE.txt +92 -0
  5. package/dist/public/bundle.82dc5d29fffb9f205051.js.map +1 -0
  6. package/dist/public/index.html +1 -0
  7. package/dist/src/cli.d.ts +2 -0
  8. package/dist/src/cli.js +115 -0
  9. package/dist/src/cli.js.map +1 -0
  10. package/dist/src/executor/DestinationExecutor.d.ts +19 -0
  11. package/dist/src/executor/DestinationExecutor.js +72 -0
  12. package/dist/src/executor/DestinationExecutor.js.map +1 -0
  13. package/dist/src/executor/FunctionExecutor.d.ts +67 -0
  14. package/dist/src/executor/FunctionExecutor.js +189 -0
  15. package/dist/src/executor/FunctionExecutor.js.map +1 -0
  16. package/dist/src/executor/JobExecutor.d.ts +79 -0
  17. package/dist/src/executor/JobExecutor.js +215 -0
  18. package/dist/src/executor/JobExecutor.js.map +1 -0
  19. package/dist/src/executor/LifecycleExecutor.d.ts +64 -0
  20. package/dist/src/executor/LifecycleExecutor.js +167 -0
  21. package/dist/src/executor/LifecycleExecutor.js.map +1 -0
  22. package/dist/src/executor/SourceExecutor.d.ts +32 -0
  23. package/dist/src/executor/SourceExecutor.js +163 -0
  24. package/dist/src/executor/SourceExecutor.js.map +1 -0
  25. package/dist/src/executor/watcher.d.ts +62 -0
  26. package/dist/src/executor/watcher.js +213 -0
  27. package/dist/src/executor/watcher.js.map +1 -0
  28. package/dist/src/functions/hello.d.ts +4 -0
  29. package/dist/src/functions/hello.js +8 -0
  30. package/dist/src/functions/hello.js.map +1 -0
  31. package/dist/src/index.d.ts +1 -0
  32. package/dist/src/index.js +9 -0
  33. package/dist/src/index.js.map +1 -0
  34. package/dist/src/jobs/dailyJob.d.ts +4 -0
  35. package/dist/src/jobs/dailyJob.js +8 -0
  36. package/dist/src/jobs/dailyJob.js.map +1 -0
  37. package/dist/src/local_engine/LocalFunctionApi.d.ts +17 -0
  38. package/dist/src/local_engine/LocalFunctionApi.js +54 -0
  39. package/dist/src/local_engine/LocalFunctionApi.js.map +1 -0
  40. package/dist/src/local_engine/LocalJobApi.d.ts +67 -0
  41. package/dist/src/local_engine/LocalJobApi.js +205 -0
  42. package/dist/src/local_engine/LocalJobApi.js.map +1 -0
  43. package/dist/src/local_engine/LocalNotifier.d.ts +9 -0
  44. package/dist/src/local_engine/LocalNotifier.js +26 -0
  45. package/dist/src/local_engine/LocalNotifier.js.map +1 -0
  46. package/dist/src/local_engine/local-engine-child-base.d.ts +110 -0
  47. package/dist/src/local_engine/local-engine-child-base.js +607 -0
  48. package/dist/src/local_engine/local-engine-child-base.js.map +1 -0
  49. package/dist/src/local_engine/local-engine-client.d.ts +161 -0
  50. package/dist/src/local_engine/local-engine-client.js +888 -0
  51. package/dist/src/local_engine/local-engine-client.js.map +1 -0
  52. package/dist/src/local_engine/local-engine-types.d.ts +245 -0
  53. package/dist/src/local_engine/local-engine-types.js +6 -0
  54. package/dist/src/local_engine/local-engine-types.js.map +1 -0
  55. package/dist/src/local_engine/local-engine-unified.d.ts +71 -0
  56. package/dist/src/local_engine/local-engine-unified.js +723 -0
  57. package/dist/src/local_engine/local-engine-unified.js.map +1 -0
  58. package/dist/src/local_engine/local-engine-utils.d.ts +68 -0
  59. package/dist/src/local_engine/local-engine-utils.js +219 -0
  60. package/dist/src/local_engine/local-engine-utils.js.map +1 -0
  61. package/dist/src/local_engine/localSDKConfig.d.ts +40 -0
  62. package/dist/src/local_engine/localSDKConfig.js +247 -0
  63. package/dist/src/local_engine/localSDKConfig.js.map +1 -0
  64. package/dist/src/local_engine/storage/BaseKVStoreWrapper.d.ts +37 -0
  65. package/dist/src/local_engine/storage/BaseKVStoreWrapper.js +110 -0
  66. package/dist/src/local_engine/storage/BaseKVStoreWrapper.js.map +1 -0
  67. package/dist/src/local_engine/storage/LocalConfigStore.d.ts +74 -0
  68. package/dist/src/local_engine/storage/LocalConfigStore.js +178 -0
  69. package/dist/src/local_engine/storage/LocalConfigStore.js.map +1 -0
  70. package/dist/src/local_engine/storage/LocalJobStore.d.ts +111 -0
  71. package/dist/src/local_engine/storage/LocalJobStore.js +249 -0
  72. package/dist/src/local_engine/storage/LocalJobStore.js.map +1 -0
  73. package/dist/src/local_engine/storage/LocalKVStore.d.ts +106 -0
  74. package/dist/src/local_engine/storage/LocalKVStore.js +1061 -0
  75. package/dist/src/local_engine/storage/LocalKVStore.js.map +1 -0
  76. package/dist/src/local_engine/storage/LocalNotificationStore.d.ts +28 -0
  77. package/dist/src/local_engine/storage/LocalNotificationStore.js +149 -0
  78. package/dist/src/local_engine/storage/LocalNotificationStore.js.map +1 -0
  79. package/dist/src/local_engine/storage/LocalSecretsStore.d.ts +115 -0
  80. package/dist/src/local_engine/storage/LocalSecretsStore.js +350 -0
  81. package/dist/src/local_engine/storage/LocalSecretsStore.js.map +1 -0
  82. package/dist/src/local_engine/storage/LocalSecretsStoreWrapper.d.ts +19 -0
  83. package/dist/src/local_engine/storage/LocalSecretsStoreWrapper.js +52 -0
  84. package/dist/src/local_engine/storage/LocalSecretsStoreWrapper.js.map +1 -0
  85. package/dist/src/local_engine/storage/LocalSettingsStore.d.ts +168 -0
  86. package/dist/src/local_engine/storage/LocalSettingsStore.js +509 -0
  87. package/dist/src/local_engine/storage/LocalSettingsStore.js.map +1 -0
  88. package/dist/src/local_engine/storage/LocalSettingsStoreWrapper.d.ts +15 -0
  89. package/dist/src/local_engine/storage/LocalSettingsStoreWrapper.js +28 -0
  90. package/dist/src/local_engine/storage/LocalSettingsStoreWrapper.js.map +1 -0
  91. package/dist/src/local_engine/storage/NumberSet.d.ts +21 -0
  92. package/dist/src/local_engine/storage/NumberSet.js +32 -0
  93. package/dist/src/local_engine/storage/NumberSet.js.map +1 -0
  94. package/dist/src/local_engine/storage/SourceDataStore.d.ts +23 -0
  95. package/dist/src/local_engine/storage/SourceDataStore.js +83 -0
  96. package/dist/src/local_engine/storage/SourceDataStore.js.map +1 -0
  97. package/dist/src/local_engine/storage/SourceJobExecutionStore.d.ts +25 -0
  98. package/dist/src/local_engine/storage/SourceJobExecutionStore.js +61 -0
  99. package/dist/src/local_engine/storage/SourceJobExecutionStore.js.map +1 -0
  100. package/dist/src/local_engine/storage/StringSet.d.ts +21 -0
  101. package/dist/src/local_engine/storage/StringSet.js +32 -0
  102. package/dist/src/local_engine/storage/StringSet.js.map +1 -0
  103. package/dist/src/local_engine/types.d.ts +53 -0
  104. package/dist/src/local_engine/types.js +6 -0
  105. package/dist/src/local_engine/types.js.map +1 -0
  106. package/dist/src/local_engine/utils.d.ts +33 -0
  107. package/dist/src/local_engine/utils.js +143 -0
  108. package/dist/src/local_engine/utils.js.map +1 -0
  109. package/dist/src/logging/LogManager.d.ts +246 -0
  110. package/dist/src/logging/LogManager.js +343 -0
  111. package/dist/src/logging/LogManager.js.map +1 -0
  112. package/dist/src/server/api/destinations.d.ts +7 -0
  113. package/dist/src/server/api/destinations.js +170 -0
  114. package/dist/src/server/api/destinations.js.map +1 -0
  115. package/dist/src/server/api/functions.d.ts +7 -0
  116. package/dist/src/server/api/functions.js +80 -0
  117. package/dist/src/server/api/functions.js.map +1 -0
  118. package/dist/src/server/api/jobs.d.ts +10 -0
  119. package/dist/src/server/api/jobs.js +244 -0
  120. package/dist/src/server/api/jobs.js.map +1 -0
  121. package/dist/src/server/api/settings.d.ts +6 -0
  122. package/dist/src/server/api/settings.js +116 -0
  123. package/dist/src/server/api/settings.js.map +1 -0
  124. package/dist/src/server/api/sources.d.ts +7 -0
  125. package/dist/src/server/api/sources.js +382 -0
  126. package/dist/src/server/api/sources.js.map +1 -0
  127. package/dist/src/server/api/stores.d.ts +2 -0
  128. package/dist/src/server/api/stores.js +341 -0
  129. package/dist/src/server/api/stores.js.map +1 -0
  130. package/dist/src/server/api/v1.d.ts +10 -0
  131. package/dist/src/server/api/v1.js +718 -0
  132. package/dist/src/server/api/v1.js.map +1 -0
  133. package/dist/src/server/api.d.ts +8 -0
  134. package/dist/src/server/api.js +217 -0
  135. package/dist/src/server/api.js.map +1 -0
  136. package/dist/src/server/app-discovery.d.ts +5 -0
  137. package/dist/src/server/app-discovery.js +113 -0
  138. package/dist/src/server/app-discovery.js.map +1 -0
  139. package/dist/src/server/config.d.ts +26 -0
  140. package/dist/src/server/config.js +112 -0
  141. package/dist/src/server/config.js.map +1 -0
  142. package/dist/src/server/mockDataGenerator.d.ts +1 -0
  143. package/dist/src/server/mockDataGenerator.js +154 -0
  144. package/dist/src/server/mockDataGenerator.js.map +1 -0
  145. package/dist/src/server/websocket.d.ts +0 -0
  146. package/dist/src/server/websocket.js +2 -0
  147. package/dist/src/server/websocket.js.map +1 -0
  148. package/dist/src/server.d.ts +2 -0
  149. package/dist/src/server.js +735 -0
  150. package/dist/src/server.js.map +1 -0
  151. package/dist/src/types/app.d.ts +154 -0
  152. package/dist/src/types/app.js +24 -0
  153. package/dist/src/types/app.js.map +1 -0
  154. package/dist/src/types/kvstore.d.ts +320 -0
  155. package/dist/src/types/kvstore.js +5 -0
  156. package/dist/src/types/kvstore.js.map +1 -0
  157. package/dist/src/ui/components/App.d.ts +6 -0
  158. package/dist/src/ui/components/App.js +432 -0
  159. package/dist/src/ui/components/App.js.map +1 -0
  160. package/dist/src/ui/components/DestinationBatchEditor.d.ts +7 -0
  161. package/dist/src/ui/components/DestinationBatchEditor.js +160 -0
  162. package/dist/src/ui/components/DestinationBatchEditor.js.map +1 -0
  163. package/dist/src/ui/components/DestinationSchemaViewer.d.ts +7 -0
  164. package/dist/src/ui/components/DestinationSchemaViewer.js +61 -0
  165. package/dist/src/ui/components/DestinationSchemaViewer.js.map +1 -0
  166. package/dist/src/ui/components/DestinationsView.d.ts +14 -0
  167. package/dist/src/ui/components/DestinationsView.js +68 -0
  168. package/dist/src/ui/components/DestinationsView.js.map +1 -0
  169. package/dist/src/ui/components/FunctionsView.d.ts +13 -0
  170. package/dist/src/ui/components/FunctionsView.js +288 -0
  171. package/dist/src/ui/components/FunctionsView.js.map +1 -0
  172. package/dist/src/ui/components/JobsView.d.ts +13 -0
  173. package/dist/src/ui/components/JobsView.js +320 -0
  174. package/dist/src/ui/components/JobsView.js.map +1 -0
  175. package/dist/src/ui/components/KVStoreViewer.d.ts +11 -0
  176. package/dist/src/ui/components/KVStoreViewer.js +168 -0
  177. package/dist/src/ui/components/KVStoreViewer.js.map +1 -0
  178. package/dist/src/ui/components/MetadataModal.d.ts +14 -0
  179. package/dist/src/ui/components/MetadataModal.js +28 -0
  180. package/dist/src/ui/components/MetadataModal.js.map +1 -0
  181. package/dist/src/ui/components/MetadataModal.test.d.ts +1 -0
  182. package/dist/src/ui/components/MetadataModal.test.js +143 -0
  183. package/dist/src/ui/components/MetadataModal.test.js.map +1 -0
  184. package/dist/src/ui/components/NotificationViewer.d.ts +16 -0
  185. package/dist/src/ui/components/NotificationViewer.js +69 -0
  186. package/dist/src/ui/components/NotificationViewer.js.map +1 -0
  187. package/dist/src/ui/components/SecretsStoreViewer.d.ts +11 -0
  188. package/dist/src/ui/components/SecretsStoreViewer.js +179 -0
  189. package/dist/src/ui/components/SecretsStoreViewer.js.map +1 -0
  190. package/dist/src/ui/components/SettingsStoreViewer.d.ts +24 -0
  191. package/dist/src/ui/components/SettingsStoreViewer.js +132 -0
  192. package/dist/src/ui/components/SettingsStoreViewer.js.map +1 -0
  193. package/dist/src/ui/components/SourceDataViewer.d.ts +8 -0
  194. package/dist/src/ui/components/SourceDataViewer.js +84 -0
  195. package/dist/src/ui/components/SourceDataViewer.js.map +1 -0
  196. package/dist/src/ui/components/SourceJobsSection.d.ts +8 -0
  197. package/dist/src/ui/components/SourceJobsSection.js +99 -0
  198. package/dist/src/ui/components/SourceJobsSection.js.map +1 -0
  199. package/dist/src/ui/components/SourceLifecycleSection.d.ts +7 -0
  200. package/dist/src/ui/components/SourceLifecycleSection.js +58 -0
  201. package/dist/src/ui/components/SourceLifecycleSection.js.map +1 -0
  202. package/dist/src/ui/components/SourceSchemaViewer.d.ts +7 -0
  203. package/dist/src/ui/components/SourceSchemaViewer.js +65 -0
  204. package/dist/src/ui/components/SourceSchemaViewer.js.map +1 -0
  205. package/dist/src/ui/components/SourceWebhookEditor.d.ts +8 -0
  206. package/dist/src/ui/components/SourceWebhookEditor.js +181 -0
  207. package/dist/src/ui/components/SourceWebhookEditor.js.map +1 -0
  208. package/dist/src/ui/components/SourcesView.d.ts +14 -0
  209. package/dist/src/ui/components/SourcesView.js +74 -0
  210. package/dist/src/ui/components/SourcesView.js.map +1 -0
  211. package/dist/src/ui/components/StoreViewer.d.ts +16 -0
  212. package/dist/src/ui/components/StoreViewer.js +86 -0
  213. package/dist/src/ui/components/StoreViewer.js.map +1 -0
  214. package/dist/src/ui/components/TabbedConsole.d.ts +17 -0
  215. package/dist/src/ui/components/TabbedConsole.js +163 -0
  216. package/dist/src/ui/components/TabbedConsole.js.map +1 -0
  217. package/dist/src/ui/components/common/DataTree.d.ts +15 -0
  218. package/dist/src/ui/components/common/DataTree.js +95 -0
  219. package/dist/src/ui/components/common/DataTree.js.map +1 -0
  220. package/dist/src/ui/components/common/EyeIcon.d.ts +11 -0
  221. package/dist/src/ui/components/common/EyeIcon.js +11 -0
  222. package/dist/src/ui/components/common/EyeIcon.js.map +1 -0
  223. package/dist/src/ui/hooks/useEntityNavigation.d.ts +72 -0
  224. package/dist/src/ui/hooks/useEntityNavigation.js +150 -0
  225. package/dist/src/ui/hooks/useEntityNavigation.js.map +1 -0
  226. package/dist/src/ui/hooks/useQueryParams.d.ts +6 -0
  227. package/dist/src/ui/hooks/useQueryParams.js +39 -0
  228. package/dist/src/ui/hooks/useQueryParams.js.map +1 -0
  229. package/dist/src/ui/index.d.ts +1 -0
  230. package/dist/src/ui/index.js +23 -0
  231. package/dist/src/ui/index.js.map +1 -0
  232. package/dist/src/ui/store/formStateSlice.d.ts +54 -0
  233. package/dist/src/ui/store/formStateSlice.js +94 -0
  234. package/dist/src/ui/store/formStateSlice.js.map +1 -0
  235. package/dist/src/ui/store/hooks.d.ts +6 -0
  236. package/dist/src/ui/store/hooks.js +8 -0
  237. package/dist/src/ui/store/hooks.js.map +1 -0
  238. package/dist/src/ui/store/index.d.ts +11 -0
  239. package/dist/src/ui/store/index.js +107 -0
  240. package/dist/src/ui/store/index.js.map +1 -0
  241. package/dist/src/utils/functionEndpoints.d.ts +24 -0
  242. package/dist/src/utils/functionEndpoints.js +45 -0
  243. package/dist/src/utils/functionEndpoints.js.map +1 -0
  244. package/package.json +112 -0
@@ -0,0 +1,1061 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.LocalKVStore = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const NumberSet_1 = require("./NumberSet");
10
+ const StringSet_1 = require("./StringSet");
11
+ const LogManager_1 = require("../../logging/LogManager");
12
+ /**
13
+ * Local implementation of KVStore that persists data to disk
14
+ * Follows the pattern of LocalSettingsStore with singleton per app directory
15
+ */
16
+ class LocalKVStore {
17
+ constructor(appRootDir, storeFileName = "kvstore.json") {
18
+ this.logManager = LogManager_1.LogManager.getInstance();
19
+ this.appRootDir = appRootDir;
20
+ this.storeFileName = storeFileName;
21
+ this.configDirPath = path_1.default.join(appRootDir, ".ocp-local");
22
+ this.kvStorePath = path_1.default.join(this.configDirPath, storeFileName);
23
+ // Initialize store file if it doesn't exist
24
+ this.ensureStoreFileExists();
25
+ }
26
+ /**
27
+ * Get or create a singleton instance for the given app directory
28
+ */
29
+ static getInstance(appRootDir, storeFileName) {
30
+ const normalizedPath = path_1.default.resolve(appRootDir);
31
+ const instanceKey = `${normalizedPath}:${storeFileName || "kvstore.json"}`;
32
+ if (!this.instances.has(instanceKey)) {
33
+ this.instances.set(instanceKey, new LocalKVStore(normalizedPath, storeFileName));
34
+ }
35
+ return this.instances.get(instanceKey);
36
+ }
37
+ /**
38
+ * Clear singleton instance for testing
39
+ */
40
+ static clearInstance(appRootDir, storeFileName) {
41
+ const normalizedPath = path_1.default.resolve(appRootDir);
42
+ const instanceKey = `${normalizedPath}:${storeFileName || "kvstore.json"}`;
43
+ this.instances.delete(instanceKey);
44
+ }
45
+ /**
46
+ * Clear all singleton instances for testing
47
+ */
48
+ static clearAllInstances() {
49
+ this.instances.clear();
50
+ }
51
+ /**
52
+ * Ensure store file exists with empty structure
53
+ */
54
+ ensureStoreFileExists() {
55
+ try {
56
+ // Ensure the .ocp-local directory exists
57
+ if (!fs_1.default.existsSync(this.configDirPath)) {
58
+ fs_1.default.mkdirSync(this.configDirPath, { recursive: true });
59
+ }
60
+ // Create empty store file if it doesn't exist
61
+ if (!fs_1.default.existsSync(this.kvStorePath)) {
62
+ this.saveDataToDisk({});
63
+ }
64
+ }
65
+ catch (error) {
66
+ this.logManager.warn(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'Failed to ensure KV store file exists', {
67
+ id: 'unknown',
68
+ store: 'LocalKVStore',
69
+ operation: 'set',
70
+ error
71
+ });
72
+ }
73
+ }
74
+ /**
75
+ * Load data from disk and clean up expired entries
76
+ */
77
+ loadDataFromDisk() {
78
+ try {
79
+ if (!fs_1.default.existsSync(this.kvStorePath)) {
80
+ return {};
81
+ }
82
+ const storeData = fs_1.default.readFileSync(this.kvStorePath, "utf-8");
83
+ const data = JSON.parse(storeData);
84
+ // Clean up expired entries
85
+ const now = Date.now();
86
+ const cleanedData = {};
87
+ for (const [key, item] of Object.entries(data)) {
88
+ if (!item.expiresAt || item.expiresAt > now) {
89
+ cleanedData[key] = item;
90
+ }
91
+ }
92
+ // Save cleaned data if any entries were removed
93
+ if (Object.keys(cleanedData).length !== Object.keys(data).length) {
94
+ this.saveDataToDisk(cleanedData);
95
+ }
96
+ return cleanedData;
97
+ }
98
+ catch (error) {
99
+ this.logManager.warn(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'Failed to load KV store from disk', {
100
+ id: 'unknown',
101
+ store: 'LocalKVStore',
102
+ operation: 'get',
103
+ error
104
+ });
105
+ return {};
106
+ }
107
+ }
108
+ /**
109
+ * Save data to disk atomically
110
+ */
111
+ saveDataToDisk(data) {
112
+ try {
113
+ // Ensure the .ocp-local directory exists
114
+ if (!fs_1.default.existsSync(this.configDirPath)) {
115
+ fs_1.default.mkdirSync(this.configDirPath, { recursive: true });
116
+ }
117
+ // Serialize data with custom handling for NumberSet and StringSet
118
+ const serializedData = JSON.stringify(data, (key, value) => {
119
+ if (value instanceof NumberSet_1.NumberSet) {
120
+ return { _type: "NumberSet", values: Array.from(value) };
121
+ }
122
+ if (value instanceof StringSet_1.StringSet) {
123
+ return { _type: "StringSet", values: Array.from(value) };
124
+ }
125
+ return value;
126
+ }, 2);
127
+ // Write to temp file first, then rename for atomicity
128
+ const tempPath = `${this.kvStorePath}.tmp`;
129
+ fs_1.default.writeFileSync(tempPath, serializedData, "utf-8");
130
+ fs_1.default.renameSync(tempPath, this.kvStorePath);
131
+ }
132
+ catch (error) {
133
+ this.logManager.error(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'Failed to save KV store to disk', {
134
+ id: 'unknown',
135
+ store: 'LocalKVStore',
136
+ operation: 'set',
137
+ error
138
+ });
139
+ throw error;
140
+ }
141
+ }
142
+ /**
143
+ * Deserialize data with custom handling for NumberSet and StringSet
144
+ */
145
+ deserializeValue(value) {
146
+ if (value && typeof value === "object" && value._type) {
147
+ switch (value._type) {
148
+ case "NumberSet":
149
+ return new NumberSet_1.NumberSet(value.values);
150
+ case "StringSet":
151
+ return new StringSet_1.StringSet(value.values);
152
+ }
153
+ }
154
+ if (Array.isArray(value)) {
155
+ return value.map((item) => this.deserializeValue(item));
156
+ }
157
+ if (value && typeof value === "object") {
158
+ const result = {};
159
+ for (const [k, v] of Object.entries(value)) {
160
+ result[k] = this.deserializeValue(v);
161
+ }
162
+ return result;
163
+ }
164
+ return value;
165
+ }
166
+ /**
167
+ * Get stored item with deserialization
168
+ */
169
+ getStoredItem(key) {
170
+ const data = this.loadDataFromDisk();
171
+ const item = data[key];
172
+ if (!item) {
173
+ return null;
174
+ }
175
+ // Deserialize the data
176
+ const deserializedData = this.deserializeValue(item.data);
177
+ return {
178
+ ...item,
179
+ data: deserializedData,
180
+ };
181
+ }
182
+ /**
183
+ * Store item with optional TTL
184
+ */
185
+ storeItem(key, data, options) {
186
+ const storeData = this.loadDataFromDisk();
187
+ const item = { data };
188
+ if (options?.ttl !== undefined) {
189
+ item.ttl = options.ttl;
190
+ item.expiresAt = Date.now() + options.ttl * 1000;
191
+ }
192
+ storeData[key] = item;
193
+ this.saveDataToDisk(storeData);
194
+ }
195
+ // ===================================================================================================================
196
+ // Basic Operations
197
+ // ===================================================================================================================
198
+ async get(key, fields) {
199
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'GET request', {
200
+ id: key || 'unknown',
201
+ store: 'LocalKVStore',
202
+ operation: 'get',
203
+ key
204
+ });
205
+ try {
206
+ const item = this.getStoredItem(key);
207
+ if (!item) {
208
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'GET result: empty', {
209
+ id: key || 'unknown',
210
+ store: 'LocalKVStore',
211
+ operation: 'get',
212
+ key
213
+ });
214
+ return {};
215
+ }
216
+ if (fields && fields.length > 0) {
217
+ // Return only requested fields
218
+ const filteredData = {};
219
+ fields.forEach((field) => {
220
+ if (item.data[field] !== undefined) {
221
+ filteredData[field] = item.data[field];
222
+ }
223
+ });
224
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'GET result: filtered', {
225
+ id: key || 'unknown',
226
+ store: 'LocalKVStore',
227
+ operation: 'get',
228
+ key
229
+ });
230
+ return filteredData;
231
+ }
232
+ else {
233
+ // Return all data
234
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'GET result: full', {
235
+ id: key || 'unknown',
236
+ store: 'LocalKVStore',
237
+ operation: 'get',
238
+ key
239
+ });
240
+ return item.data;
241
+ }
242
+ }
243
+ catch (error) {
244
+ this.logManager.error(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'GET failed', {
245
+ id: key || 'unknown',
246
+ store: 'LocalKVStore',
247
+ operation: 'get',
248
+ key,
249
+ error
250
+ });
251
+ return {};
252
+ }
253
+ }
254
+ async put(key, value, options) {
255
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'PUT request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
256
+ try {
257
+ // Get previous value
258
+ const previousItem = this.getStoredItem(key);
259
+ const previousValue = previousItem ? previousItem.data : {};
260
+ // Store new value
261
+ this.storeItem(key, value, options);
262
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'PUT completed', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
263
+ return previousValue;
264
+ }
265
+ catch (error) {
266
+ this.logManager.error(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'PUT failed', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key, error });
267
+ throw error;
268
+ }
269
+ }
270
+ async patch(key, valueOrUpdater, options) {
271
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'PATCH request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
272
+ try {
273
+ // Get current value
274
+ const currentItem = this.getStoredItem(key);
275
+ const currentValue = currentItem ? currentItem.data : {};
276
+ let newValue;
277
+ if (typeof valueOrUpdater === "function") {
278
+ // Updater function
279
+ const updater = valueOrUpdater;
280
+ try {
281
+ // Try with options first (KVPatchUpdaterWithOptions)
282
+ const currentOptions = { ttl: currentItem?.ttl };
283
+ newValue = updater(currentValue, currentOptions);
284
+ }
285
+ catch (error) {
286
+ // Fall back to regular PatchUpdater
287
+ newValue = updater(currentValue);
288
+ }
289
+ }
290
+ else {
291
+ // Value object - merge with current
292
+ newValue = { ...currentValue, ...valueOrUpdater };
293
+ }
294
+ // Store updated value
295
+ this.storeItem(key, newValue, options);
296
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'PATCH completed', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
297
+ return currentValue;
298
+ }
299
+ catch (error) {
300
+ this.logManager.error(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'PATCH failed', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key, error });
301
+ throw error;
302
+ }
303
+ }
304
+ async delete(key, fields) {
305
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'DELETE request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'delete', key });
306
+ try {
307
+ const storeData = this.loadDataFromDisk();
308
+ const item = storeData[key];
309
+ if (!item) {
310
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'DELETE result: not found', { id: key || 'unknown', store: 'LocalKVStore', operation: 'delete', key });
311
+ return {};
312
+ }
313
+ const deserializedData = this.deserializeValue(item.data);
314
+ if (!fields || fields.length === 0) {
315
+ // Delete entire object
316
+ delete storeData[key];
317
+ this.saveDataToDisk(storeData);
318
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'DELETE completed: deleted entire key', { id: key || 'unknown', store: 'LocalKVStore', operation: 'delete', key });
319
+ return deserializedData;
320
+ }
321
+ else {
322
+ // Delete specific fields
323
+ const deletedFields = {};
324
+ fields.forEach((field) => {
325
+ if (item.data[field] !== undefined) {
326
+ deletedFields[field] = item.data[field];
327
+ delete item.data[field];
328
+ }
329
+ });
330
+ this.saveDataToDisk(storeData);
331
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'DELETE completed: deleted fields', { id: key || 'unknown', store: 'LocalKVStore', operation: 'delete', key });
332
+ return this.deserializeValue(deletedFields);
333
+ }
334
+ }
335
+ catch (error) {
336
+ this.logManager.error(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'DELETE failed', { id: key || 'unknown', store: 'LocalKVStore', operation: 'delete', key, error });
337
+ throw error;
338
+ }
339
+ }
340
+ async exists(key) {
341
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'EXISTS request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'exists', key });
342
+ try {
343
+ const item = this.getStoredItem(key);
344
+ const exists = item !== null;
345
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'EXISTS result', { id: key || 'unknown', store: 'LocalKVStore', operation: 'exists', key });
346
+ return exists;
347
+ }
348
+ catch (error) {
349
+ this.logManager.error(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'EXISTS failed', { id: key || 'unknown', store: 'LocalKVStore', operation: 'exists', key, error });
350
+ return false;
351
+ }
352
+ }
353
+ // ===================================================================================================================
354
+ // Numeric Operations
355
+ // ===================================================================================================================
356
+ async increment(key, field, amount = 1, options) {
357
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'INCREMENT request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
358
+ return this.patch(key, (previous) => {
359
+ const currentValue = previous[field];
360
+ if (currentValue !== undefined && typeof currentValue !== "number") {
361
+ throw new Error(`Field "${field}" is not a number`);
362
+ }
363
+ const newValue = (currentValue || 0) + amount;
364
+ return {
365
+ ...previous,
366
+ [field]: newValue,
367
+ };
368
+ }, options).then(() => {
369
+ // Return the new value
370
+ return this.get(key, [field]).then((result) => result[field]);
371
+ });
372
+ }
373
+ async incrementMulti(key, fieldAmounts, options) {
374
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'INCREMENT_MULTI request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
375
+ return this.patch(key, (previous) => {
376
+ const updated = { ...previous };
377
+ for (const [field, amount] of Object.entries(fieldAmounts)) {
378
+ const currentValue = updated[field];
379
+ if (currentValue !== undefined && typeof currentValue !== "number") {
380
+ throw new Error(`Field "${field}" is not a number`);
381
+ }
382
+ updated[field] = (currentValue || 0) + amount;
383
+ }
384
+ return updated;
385
+ }, options).then(() => {
386
+ // Return the new values
387
+ return this.get(key, Object.keys(fieldAmounts)).then((result) => {
388
+ const newValues = {};
389
+ for (const field of Object.keys(fieldAmounts)) {
390
+ newValues[field] = result[field];
391
+ }
392
+ return newValues;
393
+ });
394
+ });
395
+ }
396
+ // ===================================================================================================================
397
+ // List Operations
398
+ // ===================================================================================================================
399
+ async shift(key, field) {
400
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'SHIFT request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
401
+ let shiftedElement = undefined;
402
+ await this.patch(key, (previous) => {
403
+ const currentValue = previous[field];
404
+ if (currentValue === undefined) {
405
+ return previous;
406
+ }
407
+ if (!Array.isArray(currentValue)) {
408
+ throw new Error(`Field "${field}" is not a list`);
409
+ }
410
+ if (currentValue.length === 0) {
411
+ return previous;
412
+ }
413
+ // Capture the first element before removing it
414
+ shiftedElement = currentValue[0];
415
+ // Remove first element
416
+ const updatedList = [...currentValue.slice(1)];
417
+ return {
418
+ ...previous,
419
+ [field]: updatedList,
420
+ };
421
+ });
422
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'SHIFT result', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
423
+ return shiftedElement;
424
+ }
425
+ async shiftMulti(key, fieldCounts) {
426
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'SHIFT_MULTI request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
427
+ const shiftedItems = {};
428
+ return this.patch(key, (previous) => {
429
+ const updated = { ...previous };
430
+ for (const [field, count] of Object.entries(fieldCounts)) {
431
+ const currentValue = updated[field];
432
+ if (currentValue === undefined) {
433
+ shiftedItems[field] = [];
434
+ continue;
435
+ }
436
+ if (!Array.isArray(currentValue)) {
437
+ throw new Error(`Field "${field}" is not a list`);
438
+ }
439
+ const actualCount = Math.min(count, currentValue.length);
440
+ shiftedItems[field] = currentValue.slice(0, actualCount);
441
+ updated[field] = currentValue.slice(actualCount);
442
+ }
443
+ return updated;
444
+ }).then(() => shiftedItems);
445
+ }
446
+ async unshift(key, field, value) {
447
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'UNSHIFT request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
448
+ await this.patch(key, (previous) => {
449
+ const currentValue = previous[field];
450
+ if (currentValue === undefined) {
451
+ // Create new list with the value
452
+ return {
453
+ ...previous,
454
+ [field]: [value],
455
+ };
456
+ }
457
+ if (!Array.isArray(currentValue)) {
458
+ throw new Error(`Field "${field}" is not a list`);
459
+ }
460
+ // Prepend to existing list
461
+ return {
462
+ ...previous,
463
+ [field]: [value, ...currentValue],
464
+ };
465
+ });
466
+ }
467
+ async unshiftMulti(key, fieldValues) {
468
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'UNSHIFT_MULTI request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
469
+ await this.patch(key, (previous) => {
470
+ const updated = { ...previous };
471
+ for (const [field, values] of Object.entries(fieldValues)) {
472
+ const currentValue = updated[field];
473
+ if (currentValue === undefined) {
474
+ // Create new list with the values
475
+ updated[field] = [...values];
476
+ }
477
+ else {
478
+ if (!Array.isArray(currentValue)) {
479
+ throw new Error(`Field "${field}" is not a list`);
480
+ }
481
+ // Prepend to existing list
482
+ updated[field] = [...values, ...currentValue];
483
+ }
484
+ }
485
+ return updated;
486
+ });
487
+ }
488
+ async peek(key, field) {
489
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'PEEK request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key });
490
+ try {
491
+ const item = this.getStoredItem(key);
492
+ if (!item) {
493
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'PEEK result: key not found', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key });
494
+ return undefined;
495
+ }
496
+ const fieldValue = item.data[field];
497
+ if (fieldValue === undefined) {
498
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'PEEK result: field not found', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key });
499
+ return undefined;
500
+ }
501
+ if (!Array.isArray(fieldValue)) {
502
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'PEEK result: not a list', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key });
503
+ return undefined;
504
+ }
505
+ if (fieldValue.length === 0) {
506
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'PEEK result: empty list', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key });
507
+ return undefined;
508
+ }
509
+ const firstElement = fieldValue[0];
510
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'PEEK result', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key });
511
+ return firstElement;
512
+ }
513
+ catch (error) {
514
+ this.logManager.error(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'PEEK failed', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key, error });
515
+ return undefined;
516
+ }
517
+ }
518
+ async peekMulti(key, fieldCounts) {
519
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'PEEK_MULTI request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key });
520
+ const result = {};
521
+ try {
522
+ const item = this.getStoredItem(key);
523
+ if (!item) {
524
+ // Return empty arrays for all fields
525
+ for (const field of Object.keys(fieldCounts)) {
526
+ result[field] = [];
527
+ }
528
+ return result;
529
+ }
530
+ for (const [field, count] of Object.entries(fieldCounts)) {
531
+ const fieldValue = item.data[field];
532
+ if (fieldValue === undefined || !Array.isArray(fieldValue)) {
533
+ result[field] = [];
534
+ continue;
535
+ }
536
+ const actualCount = Math.min(count, fieldValue.length);
537
+ result[field] = fieldValue.slice(0, actualCount);
538
+ }
539
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'PEEK_MULTI result', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key });
540
+ return result;
541
+ }
542
+ catch (error) {
543
+ this.logManager.error(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'PEEK_MULTI failed', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key, error });
544
+ // Return empty arrays for all fields on error
545
+ for (const field of Object.keys(fieldCounts)) {
546
+ result[field] = [];
547
+ }
548
+ return result;
549
+ }
550
+ }
551
+ async append(key, field, value) {
552
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'APPEND request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
553
+ await this.patch(key, (previous) => {
554
+ const currentValue = previous[field];
555
+ if (currentValue === undefined) {
556
+ // Create new list with the value
557
+ return {
558
+ ...previous,
559
+ [field]: [value],
560
+ };
561
+ }
562
+ if (!Array.isArray(currentValue)) {
563
+ throw new Error(`Field "${field}" is not a list`);
564
+ }
565
+ // Append to existing list
566
+ return {
567
+ ...previous,
568
+ [field]: [...currentValue, value],
569
+ };
570
+ });
571
+ }
572
+ async appendMulti(key, fieldValues) {
573
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'APPEND_MULTI request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
574
+ await this.patch(key, (previous) => {
575
+ const updated = { ...previous };
576
+ for (const [field, values] of Object.entries(fieldValues)) {
577
+ const currentValue = updated[field];
578
+ if (currentValue === undefined) {
579
+ // Create new list with the values
580
+ updated[field] = [...values];
581
+ }
582
+ else {
583
+ if (!Array.isArray(currentValue)) {
584
+ throw new Error(`Field "${field}" is not a list`);
585
+ }
586
+ // Append to existing list
587
+ updated[field] = [...currentValue, ...values];
588
+ }
589
+ }
590
+ return updated;
591
+ });
592
+ }
593
+ // ===================================================================================================================
594
+ // NumberSet Operations
595
+ // ===================================================================================================================
596
+ async addNumber(key, field, value) {
597
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'ADD_NUMBER request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
598
+ let wasAdded = false;
599
+ await this.patch(key, (previous) => {
600
+ const currentValue = previous[field];
601
+ if (currentValue === undefined) {
602
+ // Create new NumberSet with the value
603
+ const newSet = new NumberSet_1.NumberSet([value]);
604
+ wasAdded = true;
605
+ return {
606
+ ...previous,
607
+ [field]: newSet,
608
+ };
609
+ }
610
+ if (!(currentValue instanceof NumberSet_1.NumberSet)) {
611
+ throw new Error(`Field "${field}" is not a NumberSet`);
612
+ }
613
+ // Check if value already exists
614
+ wasAdded = !currentValue.has(value);
615
+ if (wasAdded) {
616
+ // Create new NumberSet with added value
617
+ const newSet = new NumberSet_1.NumberSet(currentValue);
618
+ newSet.add(value);
619
+ return {
620
+ ...previous,
621
+ [field]: newSet,
622
+ };
623
+ }
624
+ return previous;
625
+ });
626
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'ADD_NUMBER result', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
627
+ return wasAdded;
628
+ }
629
+ async addNumberMulti(key, fieldValues) {
630
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'ADD_NUMBER_MULTI request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
631
+ const addedValues = {};
632
+ await this.patch(key, (previous) => {
633
+ const updated = { ...previous };
634
+ for (const [field, values] of Object.entries(fieldValues)) {
635
+ const currentValue = updated[field];
636
+ const newlyAdded = new NumberSet_1.NumberSet();
637
+ if (currentValue === undefined) {
638
+ // Create new NumberSet with all values
639
+ const newSet = new NumberSet_1.NumberSet(values);
640
+ updated[field] = newSet;
641
+ addedValues[field] = new NumberSet_1.NumberSet(values);
642
+ }
643
+ else {
644
+ if (!(currentValue instanceof NumberSet_1.NumberSet)) {
645
+ throw new Error(`Field "${field}" is not a NumberSet`);
646
+ }
647
+ // Create new NumberSet and track newly added values
648
+ const newSet = new NumberSet_1.NumberSet(currentValue);
649
+ for (const value of values) {
650
+ if (!newSet.has(value)) {
651
+ newSet.add(value);
652
+ newlyAdded.add(value);
653
+ }
654
+ }
655
+ updated[field] = newSet;
656
+ addedValues[field] = newlyAdded;
657
+ }
658
+ }
659
+ return updated;
660
+ });
661
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'ADD_NUMBER_MULTI result', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
662
+ return addedValues;
663
+ }
664
+ async removeNumber(key, field, value) {
665
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'REMOVE_NUMBER request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
666
+ let wasRemoved = false;
667
+ await this.patch(key, (previous) => {
668
+ const currentValue = previous[field];
669
+ if (currentValue === undefined) {
670
+ return previous;
671
+ }
672
+ if (!(currentValue instanceof NumberSet_1.NumberSet)) {
673
+ throw new Error(`Field "${field}" is not a NumberSet`);
674
+ }
675
+ // Check if value exists
676
+ wasRemoved = currentValue.has(value);
677
+ if (wasRemoved) {
678
+ // Create new NumberSet with removed value
679
+ const newSet = new NumberSet_1.NumberSet(currentValue);
680
+ newSet.delete(value);
681
+ return {
682
+ ...previous,
683
+ [field]: newSet,
684
+ };
685
+ }
686
+ return previous;
687
+ });
688
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'REMOVE_NUMBER result', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
689
+ return wasRemoved;
690
+ }
691
+ async removeNumberMulti(key, fieldValues) {
692
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'REMOVE_NUMBER_MULTI request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
693
+ const removedValues = {};
694
+ await this.patch(key, (previous) => {
695
+ const updated = { ...previous };
696
+ for (const [field, values] of Object.entries(fieldValues)) {
697
+ const currentValue = updated[field];
698
+ const actuallyRemoved = new NumberSet_1.NumberSet();
699
+ if (currentValue === undefined) {
700
+ removedValues[field] = actuallyRemoved;
701
+ continue;
702
+ }
703
+ if (!(currentValue instanceof NumberSet_1.NumberSet)) {
704
+ throw new Error(`Field "${field}" is not a NumberSet`);
705
+ }
706
+ // Create new NumberSet and track removed values
707
+ const newSet = new NumberSet_1.NumberSet(currentValue);
708
+ for (const value of values) {
709
+ if (newSet.has(value)) {
710
+ newSet.delete(value);
711
+ actuallyRemoved.add(value);
712
+ }
713
+ }
714
+ updated[field] = newSet;
715
+ removedValues[field] = actuallyRemoved;
716
+ }
717
+ return updated;
718
+ });
719
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'REMOVE_NUMBER_MULTI result', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
720
+ return removedValues;
721
+ }
722
+ async hasNumber(key, field, value) {
723
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'HAS_NUMBER request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key });
724
+ try {
725
+ const item = this.getStoredItem(key);
726
+ if (!item) {
727
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'HAS_NUMBER result: key not found', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key });
728
+ return false;
729
+ }
730
+ const fieldValue = item.data[field];
731
+ if (fieldValue === undefined) {
732
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'HAS_NUMBER result: field not found', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key });
733
+ return false;
734
+ }
735
+ if (!(fieldValue instanceof NumberSet_1.NumberSet)) {
736
+ throw new Error(`Field "${field}" is not a NumberSet`);
737
+ }
738
+ const hasValue = fieldValue.has(value);
739
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'HAS_NUMBER result', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key });
740
+ return hasValue;
741
+ }
742
+ catch (error) {
743
+ this.logManager.error(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'HAS_NUMBER failed', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key, error });
744
+ throw error;
745
+ }
746
+ }
747
+ async hasNumberMulti(key, fieldValues) {
748
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'HAS_NUMBER_MULTI request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key });
749
+ const result = {};
750
+ try {
751
+ const item = this.getStoredItem(key);
752
+ if (!item) {
753
+ // Return empty NumberSets for all fields
754
+ for (const field of Object.keys(fieldValues)) {
755
+ result[field] = new NumberSet_1.NumberSet();
756
+ }
757
+ return result;
758
+ }
759
+ for (const [field, values] of Object.entries(fieldValues)) {
760
+ const fieldValue = item.data[field];
761
+ const existingValues = new NumberSet_1.NumberSet();
762
+ if (fieldValue === undefined) {
763
+ result[field] = existingValues;
764
+ continue;
765
+ }
766
+ if (!(fieldValue instanceof NumberSet_1.NumberSet)) {
767
+ throw new Error(`Field "${field}" is not a NumberSet`);
768
+ }
769
+ // Check which values exist
770
+ for (const value of values) {
771
+ if (fieldValue.has(value)) {
772
+ existingValues.add(value);
773
+ }
774
+ }
775
+ result[field] = existingValues;
776
+ }
777
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'HAS_NUMBER_MULTI result', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key });
778
+ return result;
779
+ }
780
+ catch (error) {
781
+ this.logManager.error(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'HAS_NUMBER_MULTI failed', {
782
+ id: key || 'unknown',
783
+ store: 'LocalKVStore',
784
+ operation: 'get',
785
+ key,
786
+ error
787
+ });
788
+ throw error;
789
+ }
790
+ }
791
+ // ===================================================================================================================
792
+ // StringSet Operations
793
+ // ===================================================================================================================
794
+ async addString(key, field, value) {
795
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'ADD_STRING request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
796
+ let wasAdded = false;
797
+ await this.patch(key, (previous) => {
798
+ const currentValue = previous[field];
799
+ if (currentValue === undefined) {
800
+ // Create new StringSet with the value
801
+ const newSet = new StringSet_1.StringSet([value]);
802
+ wasAdded = true;
803
+ return {
804
+ ...previous,
805
+ [field]: newSet,
806
+ };
807
+ }
808
+ if (!(currentValue instanceof StringSet_1.StringSet)) {
809
+ throw new Error(`Field "${field}" is not a StringSet`);
810
+ }
811
+ // Check if value already exists
812
+ wasAdded = !currentValue.has(value);
813
+ if (wasAdded) {
814
+ // Create new StringSet with added value
815
+ const newSet = new StringSet_1.StringSet(currentValue);
816
+ newSet.add(value);
817
+ return {
818
+ ...previous,
819
+ [field]: newSet,
820
+ };
821
+ }
822
+ return previous;
823
+ });
824
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'ADD_STRING result', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
825
+ return wasAdded;
826
+ }
827
+ async addStringMulti(key, fieldValues) {
828
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'ADD_STRING_MULTI request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
829
+ const addedValues = {};
830
+ await this.patch(key, (previous) => {
831
+ const updated = { ...previous };
832
+ for (const [field, values] of Object.entries(fieldValues)) {
833
+ const currentValue = updated[field];
834
+ const newlyAdded = new StringSet_1.StringSet();
835
+ if (currentValue === undefined) {
836
+ // Create new StringSet with all values
837
+ const newSet = new StringSet_1.StringSet(values);
838
+ updated[field] = newSet;
839
+ addedValues[field] = new StringSet_1.StringSet(values);
840
+ }
841
+ else {
842
+ if (!(currentValue instanceof StringSet_1.StringSet)) {
843
+ throw new Error(`Field "${field}" is not a StringSet`);
844
+ }
845
+ // Create new StringSet and track newly added values
846
+ const newSet = new StringSet_1.StringSet(currentValue);
847
+ for (const value of values) {
848
+ if (!newSet.has(value)) {
849
+ newSet.add(value);
850
+ newlyAdded.add(value);
851
+ }
852
+ }
853
+ updated[field] = newSet;
854
+ addedValues[field] = newlyAdded;
855
+ }
856
+ }
857
+ return updated;
858
+ });
859
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'ADD_STRING_MULTI result', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
860
+ return addedValues;
861
+ }
862
+ async removeString(key, field, value) {
863
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'REMOVE_STRING request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
864
+ let wasRemoved = false;
865
+ await this.patch(key, (previous) => {
866
+ const currentValue = previous[field];
867
+ if (currentValue === undefined) {
868
+ return previous;
869
+ }
870
+ if (!(currentValue instanceof StringSet_1.StringSet)) {
871
+ throw new Error(`Field "${field}" is not a StringSet`);
872
+ }
873
+ // Check if value exists
874
+ wasRemoved = currentValue.has(value);
875
+ if (wasRemoved) {
876
+ // Create new StringSet with removed value
877
+ const newSet = new StringSet_1.StringSet(currentValue);
878
+ newSet.delete(value);
879
+ return {
880
+ ...previous,
881
+ [field]: newSet,
882
+ };
883
+ }
884
+ return previous;
885
+ });
886
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'REMOVE_STRING result', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
887
+ return wasRemoved;
888
+ }
889
+ async removeStringMulti(key, fieldValues) {
890
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'REMOVE_STRING_MULTI request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
891
+ const removedValues = {};
892
+ await this.patch(key, (previous) => {
893
+ const updated = { ...previous };
894
+ for (const [field, values] of Object.entries(fieldValues)) {
895
+ const currentValue = updated[field];
896
+ const actuallyRemoved = new StringSet_1.StringSet();
897
+ if (currentValue === undefined) {
898
+ removedValues[field] = actuallyRemoved;
899
+ continue;
900
+ }
901
+ if (!(currentValue instanceof StringSet_1.StringSet)) {
902
+ throw new Error(`Field "${field}" is not a StringSet`);
903
+ }
904
+ // Create new StringSet and track removed values
905
+ const newSet = new StringSet_1.StringSet(currentValue);
906
+ for (const value of values) {
907
+ if (newSet.has(value)) {
908
+ newSet.delete(value);
909
+ actuallyRemoved.add(value);
910
+ }
911
+ }
912
+ updated[field] = newSet;
913
+ removedValues[field] = actuallyRemoved;
914
+ }
915
+ return updated;
916
+ });
917
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'REMOVE_STRING_MULTI result', { id: key || 'unknown', store: 'LocalKVStore', operation: 'set', key });
918
+ return removedValues;
919
+ }
920
+ async hasString(key, field, value) {
921
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'HAS_STRING request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key });
922
+ try {
923
+ const item = this.getStoredItem(key);
924
+ if (!item) {
925
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'HAS_STRING result: key not found', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key });
926
+ return false;
927
+ }
928
+ const fieldValue = item.data[field];
929
+ if (fieldValue === undefined) {
930
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'HAS_STRING result: field not found', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key });
931
+ return false;
932
+ }
933
+ if (!(fieldValue instanceof StringSet_1.StringSet)) {
934
+ throw new Error(`Field "${field}" is not a StringSet`);
935
+ }
936
+ const hasValue = fieldValue.has(value);
937
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'HAS_STRING result', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key });
938
+ return hasValue;
939
+ }
940
+ catch (error) {
941
+ this.logManager.error(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'HAS_STRING failed', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key, error });
942
+ throw error;
943
+ }
944
+ }
945
+ async hasStringMulti(key, fieldValues) {
946
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'HAS_STRING_MULTI request', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key });
947
+ const result = {};
948
+ try {
949
+ const item = this.getStoredItem(key);
950
+ if (!item) {
951
+ // Return empty StringSets for all fields
952
+ for (const field of Object.keys(fieldValues)) {
953
+ result[field] = new StringSet_1.StringSet();
954
+ }
955
+ return result;
956
+ }
957
+ for (const [field, values] of Object.entries(fieldValues)) {
958
+ const fieldValue = item.data[field];
959
+ const existingValues = new StringSet_1.StringSet();
960
+ if (fieldValue === undefined) {
961
+ result[field] = existingValues;
962
+ continue;
963
+ }
964
+ if (!(fieldValue instanceof StringSet_1.StringSet)) {
965
+ throw new Error(`Field "${field}" is not a StringSet`);
966
+ }
967
+ // Check which values exist
968
+ for (const value of values) {
969
+ if (fieldValue.has(value)) {
970
+ existingValues.add(value);
971
+ }
972
+ }
973
+ result[field] = existingValues;
974
+ }
975
+ this.logManager.debug(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'HAS_STRING_MULTI result', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key });
976
+ return result;
977
+ }
978
+ catch (error) {
979
+ this.logManager.error(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, 'HAS_STRING_MULTI failed', { id: key || 'unknown', store: 'LocalKVStore', operation: 'get', key, error });
980
+ throw error;
981
+ }
982
+ }
983
+ // ===================================================================================================================
984
+ // Helper Methods for API
985
+ // ===================================================================================================================
986
+ /**
987
+ * Get all stored data as a simple key-value object for the UI
988
+ */
989
+ getAllData() {
990
+ try {
991
+ const storeData = this.loadDataFromDisk();
992
+ const result = {};
993
+ for (const [key, item] of Object.entries(storeData)) {
994
+ result[key] = this.deserializeValue(item.data);
995
+ }
996
+ return result;
997
+ }
998
+ catch (error) {
999
+ this.logManager.warn(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, "Failed to get all KV data:", {
1000
+ id: 'all',
1001
+ store: 'LocalKVStore',
1002
+ operation: 'get',
1003
+ error
1004
+ });
1005
+ return {};
1006
+ }
1007
+ }
1008
+ /**
1009
+ * Set a simple key-value pair (for UI convenience)
1010
+ */
1011
+ async set(key, value) {
1012
+ await this.put(key, value);
1013
+ }
1014
+ /**
1015
+ * Get a simple value by key (for UI convenience)
1016
+ */
1017
+ async getValue(key) {
1018
+ const result = await this.get(key);
1019
+ return result.value;
1020
+ }
1021
+ /**
1022
+ * Delete a key entirely (for UI convenience)
1023
+ */
1024
+ async deleteKey(key) {
1025
+ const storeData = this.loadDataFromDisk();
1026
+ if (key in storeData) {
1027
+ delete storeData[key];
1028
+ this.saveDataToDisk(storeData);
1029
+ return true;
1030
+ }
1031
+ return false;
1032
+ }
1033
+ /**
1034
+ * Get all keys
1035
+ */
1036
+ getAllKeys() {
1037
+ try {
1038
+ const storeData = this.loadDataFromDisk();
1039
+ return Object.keys(storeData);
1040
+ }
1041
+ catch (error) {
1042
+ this.logManager.warn(LogManager_1.LogSource.System, LogManager_1.LogCategory.KVStore, "Failed to get all KV keys:", {
1043
+ id: 'all',
1044
+ store: 'LocalKVStore',
1045
+ operation: 'list',
1046
+ error
1047
+ });
1048
+ return [];
1049
+ }
1050
+ }
1051
+ /**
1052
+ * Get a shared instance for shared KV store (global across installations of the same app)
1053
+ */
1054
+ static getSharedInstance(appRootDir) {
1055
+ // Use the same app directory but with a different filename for shared storage
1056
+ return LocalKVStore.getInstance(appRootDir, "shared-kvstore.json");
1057
+ }
1058
+ }
1059
+ exports.LocalKVStore = LocalKVStore;
1060
+ LocalKVStore.instances = new Map();
1061
+ //# sourceMappingURL=LocalKVStore.js.map