@coffeerunhobby/mcp-ha-connect 2.2.1 → 2.3.1

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 (281) hide show
  1. package/.env.example +1 -1
  2. package/README.md +11 -2
  3. package/dist/omadaClient/client.d.ts +6 -1
  4. package/dist/omadaClient/client.js +12 -1
  5. package/dist/omadaClient/client.js.map +1 -1
  6. package/dist/omadaClient/diagnose.d.ts +68 -0
  7. package/dist/omadaClient/diagnose.js +164 -0
  8. package/dist/omadaClient/diagnose.js.map +1 -0
  9. package/dist/omadaClient/index.d.ts +6 -0
  10. package/dist/omadaClient/index.js +15 -0
  11. package/dist/omadaClient/index.js.map +1 -1
  12. package/dist/omadaClient/macGroups.d.ts +58 -0
  13. package/dist/omadaClient/macGroups.js +124 -0
  14. package/dist/omadaClient/macGroups.js.map +1 -0
  15. package/dist/tools/infra/actions.d.ts +1 -1
  16. package/dist/tools/infra/actions.js +1 -1
  17. package/dist/tools/omada/index.js +6 -0
  18. package/dist/tools/omada/index.js.map +1 -1
  19. package/dist/tools/omada/macGroups.d.ts +19 -0
  20. package/dist/tools/omada/macGroups.js +77 -0
  21. package/dist/tools/omada/macGroups.js.map +1 -0
  22. package/dist/tools/omada/namespace.js +8 -0
  23. package/dist/tools/omada/namespace.js.map +1 -1
  24. package/dist/version.d.ts +1 -1
  25. package/dist/version.js +1 -1
  26. package/package.json +5 -1
  27. package/.codex/review-rules.md +0 -16
  28. package/.dockerignore +0 -8
  29. package/.gitattributes +0 -30
  30. package/.github/workflows/ci.yml +0 -193
  31. package/AGENTS.md +0 -389
  32. package/Dockerfile +0 -50
  33. package/docker-compose.yml +0 -23
  34. package/docs/CHANGELOG.md +0 -341
  35. package/docs/COVERAGE.md +0 -219
  36. package/docs/QUICK_START.md +0 -240
  37. package/eslint.config.js +0 -33
  38. package/n8n/ai-agent-safety-monitor.json +0 -355
  39. package/openapi.json +0 -1259
  40. package/scripts/check-version-sync.mjs +0 -69
  41. package/scripts/generate-jwt.ts +0 -121
  42. package/src/config.ts +0 -440
  43. package/src/haClient/automations.ts +0 -261
  44. package/src/haClient/calendars.ts +0 -94
  45. package/src/haClient/config.ts +0 -52
  46. package/src/haClient/devices.ts +0 -653
  47. package/src/haClient/entities.ts +0 -128
  48. package/src/haClient/events.ts +0 -689
  49. package/src/haClient/history.ts +0 -73
  50. package/src/haClient/index.ts +0 -336
  51. package/src/haClient/request.ts +0 -142
  52. package/src/haClient/services.ts +0 -45
  53. package/src/haClient/states.ts +0 -60
  54. package/src/haClient/updates.ts +0 -58
  55. package/src/haClient/wsCommand.ts +0 -44
  56. package/src/index.ts +0 -164
  57. package/src/localAI/index.ts +0 -88
  58. package/src/localAI/prompts.ts +0 -50
  59. package/src/localAI/providers/base.ts +0 -120
  60. package/src/localAI/providers/ollama.ts +0 -78
  61. package/src/localAI/providers/openai.ts +0 -86
  62. package/src/localAI/types.ts +0 -67
  63. package/src/omadaClient/auth.ts +0 -178
  64. package/src/omadaClient/client.ts +0 -337
  65. package/src/omadaClient/device.ts +0 -118
  66. package/src/omadaClient/index.ts +0 -310
  67. package/src/omadaClient/network.ts +0 -284
  68. package/src/omadaClient/request.ts +0 -365
  69. package/src/omadaClient/security.ts +0 -51
  70. package/src/omadaClient/site.ts +0 -344
  71. package/src/ownerQuestions/service.ts +0 -536
  72. package/src/permissions/index.ts +0 -143
  73. package/src/resources/index.ts +0 -213
  74. package/src/server/auth.ts +0 -175
  75. package/src/server/chatFace.ts +0 -789
  76. package/src/server/chatSlice.ts +0 -57
  77. package/src/server/common.ts +0 -170
  78. package/src/server/eventSubscription.ts +0 -343
  79. package/src/server/http.ts +0 -626
  80. package/src/server/instructions.ts +0 -97
  81. package/src/server/rateLimiter.ts +0 -227
  82. package/src/server/stdio.ts +0 -41
  83. package/src/server/stream.ts +0 -205
  84. package/src/tools/ai/analyzeSensors.ts +0 -33
  85. package/src/tools/ai/index.ts +0 -20
  86. package/src/tools/common.ts +0 -442
  87. package/src/tools/homeassistant/askOwner.ts +0 -133
  88. package/src/tools/homeassistant/automationControls.ts +0 -66
  89. package/src/tools/homeassistant/calendar.ts +0 -97
  90. package/src/tools/homeassistant/callService.ts +0 -25
  91. package/src/tools/homeassistant/controlClimate.ts +0 -68
  92. package/src/tools/homeassistant/controlCover.ts +0 -48
  93. package/src/tools/homeassistant/controlFan.ts +0 -44
  94. package/src/tools/homeassistant/controlLight.ts +0 -38
  95. package/src/tools/homeassistant/controlMediaPlayer.ts +0 -50
  96. package/src/tools/homeassistant/createAutomation.ts +0 -35
  97. package/src/tools/homeassistant/deleteAutomation.ts +0 -24
  98. package/src/tools/homeassistant/entityAction.ts +0 -35
  99. package/src/tools/homeassistant/entityGuard.ts +0 -28
  100. package/src/tools/homeassistant/getAllSensors.ts +0 -46
  101. package/src/tools/homeassistant/getAutomationTrace.ts +0 -30
  102. package/src/tools/homeassistant/getDomainSummary.ts +0 -29
  103. package/src/tools/homeassistant/getEntitiesByDomain.ts +0 -56
  104. package/src/tools/homeassistant/getHistory.ts +0 -24
  105. package/src/tools/homeassistant/getState.ts +0 -24
  106. package/src/tools/homeassistant/getStates.ts +0 -46
  107. package/src/tools/homeassistant/getVersion.ts +0 -21
  108. package/src/tools/homeassistant/index.ts +0 -121
  109. package/src/tools/homeassistant/listAutomations.ts +0 -35
  110. package/src/tools/homeassistant/listEntities.ts +0 -44
  111. package/src/tools/homeassistant/listPersons.ts +0 -46
  112. package/src/tools/homeassistant/sceneAndScript.ts +0 -53
  113. package/src/tools/homeassistant/searchEntities.ts +0 -58
  114. package/src/tools/homeassistant/sendNotification.ts +0 -179
  115. package/src/tools/homeassistant/systemTools.ts +0 -52
  116. package/src/tools/homeassistant/triggerAutomation.ts +0 -24
  117. package/src/tools/index.ts +0 -78
  118. package/src/tools/infra/actions.ts +0 -95
  119. package/src/tools/infra/index.ts +0 -138
  120. package/src/tools/omada/blockClient.ts +0 -28
  121. package/src/tools/omada/cyclePoePort.ts +0 -32
  122. package/src/tools/omada/deleteClient.ts +0 -27
  123. package/src/tools/omada/disableClientRateLimit.ts +0 -23
  124. package/src/tools/omada/getClient.ts +0 -14
  125. package/src/tools/omada/getDevice.ts +0 -14
  126. package/src/tools/omada/getFirewallSetting.ts +0 -14
  127. package/src/tools/omada/getInternetInfo.ts +0 -14
  128. package/src/tools/omada/getLanNetworkList.ts +0 -14
  129. package/src/tools/omada/getLanProfileList.ts +0 -14
  130. package/src/tools/omada/getPortForwardingStatus.ts +0 -26
  131. package/src/tools/omada/getRateLimitProfiles.ts +0 -14
  132. package/src/tools/omada/getSiteNtpStatus.ts +0 -14
  133. package/src/tools/omada/getSsidDetail.ts +0 -22
  134. package/src/tools/omada/getSsidList.ts +0 -21
  135. package/src/tools/omada/getSwitchStackDetail.ts +0 -14
  136. package/src/tools/omada/getThreatList.ts +0 -42
  137. package/src/tools/omada/getWlanGroupList.ts +0 -14
  138. package/src/tools/omada/graph.ts +0 -187
  139. package/src/tools/omada/index.ts +0 -153
  140. package/src/tools/omada/listBlockedClients.ts +0 -17
  141. package/src/tools/omada/listClients.ts +0 -14
  142. package/src/tools/omada/listClientsActivity.ts +0 -25
  143. package/src/tools/omada/listClientsPastConnections.ts +0 -44
  144. package/src/tools/omada/listDevices.ts +0 -14
  145. package/src/tools/omada/listDevicesStats.ts +0 -41
  146. package/src/tools/omada/listMostActiveClients.ts +0 -14
  147. package/src/tools/omada/listSites.ts +0 -18
  148. package/src/tools/omada/namespace.ts +0 -1164
  149. package/src/tools/omada/searchDevices.ts +0 -20
  150. package/src/tools/omada/setClientRateLimit.ts +0 -26
  151. package/src/tools/omada/setClientRateLimitProfile.ts +0 -25
  152. package/src/tools/omada/setSiteNtpServers.ts +0 -36
  153. package/src/tools/omada/setSsidEnabled.ts +0 -38
  154. package/src/tools/omada/unblockClient.ts +0 -26
  155. package/src/tools/types.ts +0 -11
  156. package/src/tools/utils/pagination-schema.ts +0 -27
  157. package/src/types/ai/index.ts +0 -11
  158. package/src/types/ai/types.ts +0 -67
  159. package/src/types/homeassistant/automations.ts +0 -43
  160. package/src/types/homeassistant/calendars.ts +0 -26
  161. package/src/types/homeassistant/config.ts +0 -14
  162. package/src/types/homeassistant/entities.ts +0 -14
  163. package/src/types/homeassistant/errors.ts +0 -33
  164. package/src/types/homeassistant/haConfig.ts +0 -7
  165. package/src/types/homeassistant/history.ts +0 -13
  166. package/src/types/homeassistant/index.ts +0 -46
  167. package/src/types/homeassistant/request.ts +0 -6
  168. package/src/types/homeassistant/serviceCall.ts +0 -18
  169. package/src/types/homeassistant/states.ts +0 -58
  170. package/src/types/homeassistant/updates.ts +0 -28
  171. package/src/types/index.ts +0 -12
  172. package/src/types/omada/activeClientInfo.ts +0 -17
  173. package/src/types/omada/clientActivity.ts +0 -32
  174. package/src/types/omada/clientBlockStatus.ts +0 -11
  175. package/src/types/omada/clientPastConnection.ts +0 -82
  176. package/src/types/omada/index.ts +0 -14
  177. package/src/types/omada/omadaApiResponse.ts +0 -5
  178. package/src/types/omada/omadaClientInfo.ts +0 -11
  179. package/src/types/omada/omadaDeviceInfo.ts +0 -11
  180. package/src/types/omada/omadaDeviceStats.ts +0 -31
  181. package/src/types/omada/omadaSiteSummary.ts +0 -5
  182. package/src/types/omada/oswStackDetail.ts +0 -11
  183. package/src/types/omada/paginatedResult.ts +0 -6
  184. package/src/types/omada/rateLimitProfile.ts +0 -58
  185. package/src/types/omada/threatInfo.ts +0 -38
  186. package/src/types/omada/tokenResult.ts +0 -6
  187. package/src/types.ts +0 -2
  188. package/src/utils/config-validations.ts +0 -68
  189. package/src/utils/jwt.ts +0 -112
  190. package/src/utils/logger.ts +0 -121
  191. package/src/utils/plainText.ts +0 -48
  192. package/src/utils/redact.ts +0 -59
  193. package/src/utils/sanitizeError.ts +0 -18
  194. package/src/utils/tlsDispatcher.ts +0 -69
  195. package/src/version.ts +0 -5
  196. package/tests/bdd/automation-creation.spec.ts +0 -214
  197. package/tests/bdd/automation-management.spec.ts +0 -267
  198. package/tests/bdd/calendar.spec.ts +0 -190
  199. package/tests/bdd/configuration.spec.ts +0 -283
  200. package/tests/bdd/device-control.spec.ts +0 -344
  201. package/tests/bdd/entity-listing.spec.ts +0 -208
  202. package/tests/bdd/entity-search.spec.ts +0 -183
  203. package/tests/bdd/history-retrieval.spec.ts +0 -195
  204. package/tests/bdd/notifications.spec.ts +0 -238
  205. package/tests/bdd/service-calls.spec.ts +0 -144
  206. package/tests/bdd/state-retrieval.spec.ts +0 -204
  207. package/tests/bench/hotpaths.bench.ts +0 -68
  208. package/tests/config.test.ts +0 -355
  209. package/tests/features/automation-creation.feature +0 -36
  210. package/tests/features/automation-management.feature +0 -54
  211. package/tests/features/calendar.feature +0 -37
  212. package/tests/features/configuration.feature +0 -70
  213. package/tests/features/device-control.feature +0 -100
  214. package/tests/features/entity-listing.feature +0 -51
  215. package/tests/features/entity-search.feature +0 -44
  216. package/tests/features/history-retrieval.feature +0 -38
  217. package/tests/features/notifications.feature +0 -37
  218. package/tests/features/service-calls.feature +0 -35
  219. package/tests/features/state-retrieval.feature +0 -37
  220. package/tests/fixtures/openapi-default-slice.json +0 -290
  221. package/tests/haClient/automationTrace.test.ts +0 -59
  222. package/tests/haClient/automations.test.ts +0 -149
  223. package/tests/haClient/config.test.ts +0 -117
  224. package/tests/haClient/entities.test.ts +0 -188
  225. package/tests/haClient/events.test.ts +0 -455
  226. package/tests/haClient/eventsTls.test.ts +0 -52
  227. package/tests/haClient/history.test.ts +0 -228
  228. package/tests/haClient/index.test.ts +0 -243
  229. package/tests/haClient/request.test.ts +0 -217
  230. package/tests/haClient/services.test.ts +0 -120
  231. package/tests/haClient/states.test.ts +0 -119
  232. package/tests/haClient/updates.test.ts +0 -193
  233. package/tests/index.test.ts +0 -160
  234. package/tests/integration/homeassistant.test.ts +0 -144
  235. package/tests/integration/omada.test.ts +0 -167
  236. package/tests/integration/server.test.ts +0 -151
  237. package/tests/localAI/index.test.ts +0 -177
  238. package/tests/localAI/ollama.test.ts +0 -187
  239. package/tests/localAI/openai.test.ts +0 -257
  240. package/tests/omadaClient/actions.test.ts +0 -161
  241. package/tests/omadaClient/clientBlocks.test.ts +0 -170
  242. package/tests/omadaClient/ntp.test.ts +0 -381
  243. package/tests/omadaClient/site.test.ts +0 -37
  244. package/tests/ownerQuestions/service.test.ts +0 -499
  245. package/tests/ownerQuestions/tools.test.ts +0 -186
  246. package/tests/permissions/index.test.ts +0 -217
  247. package/tests/resources/index.test.ts +0 -288
  248. package/tests/scripts/generateJwt.test.ts +0 -44
  249. package/tests/security/accessControl.test.ts +0 -223
  250. package/tests/security/authentication.test.ts +0 -117
  251. package/tests/security/configuration.test.ts +0 -170
  252. package/tests/security/cryptoTransport.test.ts +0 -172
  253. package/tests/security/dependencies.test.ts +0 -152
  254. package/tests/security/injection.test.ts +0 -117
  255. package/tests/security/insecureDesign.test.ts +0 -121
  256. package/tests/security/logging.test.ts +0 -131
  257. package/tests/security/resourceConsumption.test.ts +0 -142
  258. package/tests/server/auth.test.ts +0 -249
  259. package/tests/server/chatFace.test.ts +0 -320
  260. package/tests/server/common.test.ts +0 -84
  261. package/tests/server/http.test.ts +0 -561
  262. package/tests/server/instructions.test.ts +0 -152
  263. package/tests/server/memoizeJsonSchema.test.ts +0 -71
  264. package/tests/server/stdio.test.ts +0 -99
  265. package/tests/server/stream.test.ts +0 -285
  266. package/tests/server/toolVisibility.http.test.ts +0 -111
  267. package/tests/server/toolVisibility.test.ts +0 -129
  268. package/tests/tools/ai/analyzeSensors.test.ts +0 -227
  269. package/tests/tools/common.test.ts +0 -123
  270. package/tests/tools/homeassistant/handlers.test.ts +0 -872
  271. package/tests/tools/infra/invokeAction.test.ts +0 -280
  272. package/tests/tools/omada/graph.test.ts +0 -385
  273. package/tests/tools/omada/handlers.test.ts +0 -897
  274. package/tests/tools/omada/namespace.test.ts +0 -483
  275. package/tests/tools/registry.test.ts +0 -168
  276. package/tests/utils/config-validations.test.ts +0 -352
  277. package/tests/utils/jwt.test.ts +0 -115
  278. package/tests/utils/logger.test.ts +0 -327
  279. package/tests/utils/redact.test.ts +0 -105
  280. package/tsconfig.json +0 -24
  281. package/vitest.config.ts +0 -38
@@ -1,327 +0,0 @@
1
- /**
2
- * Logger tests
3
- */
4
-
5
- import { describe, it, expect, beforeEach, vi } from 'vitest';
6
- import { initLogger, setLevel, logger } from '../../src/utils/logger.js';
7
- import type { LogLevel, LogFormat } from '../../src/utils/logger.js';
8
-
9
- describe('Logger', () => {
10
- beforeEach(() => {
11
- // Reset to default configuration
12
- initLogger('info', 'plain', false);
13
- });
14
-
15
- describe('initLogger', () => {
16
- it('should initialize with default level and format', () => {
17
- initLogger('info', 'plain', false);
18
-
19
- // Logger should be initialized without errors
20
- expect(logger).toBeDefined();
21
- expect(logger.info).toBeDefined();
22
- expect(logger.debug).toBeDefined();
23
- expect(logger.warn).toBeDefined();
24
- expect(logger.error).toBeDefined();
25
- });
26
-
27
- it('should support all log levels', () => {
28
- const levels: LogLevel[] = ['debug', 'info', 'warn', 'error', 'silent'];
29
-
30
- for (const level of levels) {
31
- expect(() => initLogger(level, 'plain', false)).not.toThrow();
32
- }
33
- });
34
-
35
- it('should support all log formats', () => {
36
- const formats: LogFormat[] = ['plain', 'json', 'gcp-json'];
37
-
38
- for (const format of formats) {
39
- expect(() => initLogger('info', format, false)).not.toThrow();
40
- }
41
- });
42
-
43
- it('should configure stderr output when useStderr is true', () => {
44
- expect(() => initLogger('info', 'plain', true)).not.toThrow();
45
-
46
- // Logger should be configured to use stderr
47
- });
48
-
49
- it('should configure stdout output when useStderr is false', () => {
50
- expect(() => initLogger('info', 'plain', false)).not.toThrow();
51
-
52
- // Logger should be configured to use stdout
53
- });
54
- });
55
-
56
- describe('setLevel', () => {
57
- it('should change log level dynamically', () => {
58
- initLogger('info', 'plain', false);
59
-
60
- expect(() => setLevel('debug')).not.toThrow();
61
- expect(() => setLevel('warn')).not.toThrow();
62
- expect(() => setLevel('error')).not.toThrow();
63
- });
64
-
65
- it('should accept all valid log levels', () => {
66
- const levels: LogLevel[] = ['debug', 'info', 'warn', 'error', 'silent'];
67
-
68
- for (const level of levels) {
69
- expect(() => setLevel(level)).not.toThrow();
70
- }
71
- });
72
- });
73
-
74
- describe('Log methods', () => {
75
- it('should have debug method', () => {
76
- expect(typeof logger.debug).toBe('function');
77
- expect(() => logger.debug('Test debug message')).not.toThrow();
78
- });
79
-
80
- it('should have info method', () => {
81
- expect(typeof logger.info).toBe('function');
82
- expect(() => logger.info('Test info message')).not.toThrow();
83
- });
84
-
85
- it('should have warn method', () => {
86
- expect(typeof logger.warn).toBe('function');
87
- expect(() => logger.warn('Test warn message')).not.toThrow();
88
- });
89
-
90
- it('should have error method', () => {
91
- expect(typeof logger.error).toBe('function');
92
- expect(() => logger.error('Test error message')).not.toThrow();
93
- });
94
- });
95
-
96
- describe('Log with metadata', () => {
97
- it('should log with metadata object', () => {
98
- const metadata = {
99
- userId: 'user-123',
100
- requestId: 'req-456',
101
- duration: 123,
102
- };
103
-
104
- expect(() => logger.info('Test message', metadata)).not.toThrow();
105
- });
106
-
107
- it('should handle Error objects in metadata', () => {
108
- const error = new Error('Test error');
109
- const metadata = {
110
- error,
111
- context: 'test',
112
- };
113
-
114
- expect(() => logger.error('Error occurred', metadata)).not.toThrow();
115
- });
116
-
117
- it('should handle nested objects in metadata', () => {
118
- const metadata = {
119
- config: {
120
- baseUrl: 'http://example.com',
121
- timeout: 30000,
122
- },
123
- user: {
124
- id: 'user-123',
125
- name: 'Test User',
126
- },
127
- };
128
-
129
- expect(() => logger.info('Complex metadata', metadata)).not.toThrow();
130
- });
131
-
132
- it('should handle arrays in metadata', () => {
133
- const metadata = {
134
- entities: ['light.living_room', 'sensor.temperature'],
135
- tags: ['home', 'automation'],
136
- };
137
-
138
- expect(() => logger.info('Array metadata', metadata)).not.toThrow();
139
- });
140
-
141
- it('should handle empty metadata', () => {
142
- expect(() => logger.info('No metadata')).not.toThrow();
143
- expect(() => logger.info('Empty metadata', {})).not.toThrow();
144
- });
145
- });
146
-
147
- describe('Log formats', () => {
148
- it('should format plain logs with uppercase level', () => {
149
- initLogger('info', 'plain', false);
150
-
151
- // Plain format should use { level: 'INFO' }
152
- expect(() => logger.info('Plain format test')).not.toThrow();
153
- });
154
-
155
- it('should format JSON logs with standard structure', () => {
156
- initLogger('info', 'json', false);
157
-
158
- // JSON format should use standard pino JSON
159
- expect(() => logger.info('JSON format test')).not.toThrow();
160
- });
161
-
162
- it('should format GCP JSON logs with severity field', () => {
163
- initLogger('info', 'gcp-json', false);
164
-
165
- // GCP format should use { severity: 'INFO' }
166
- expect(() => logger.info('GCP format test')).not.toThrow();
167
- });
168
- });
169
-
170
- describe('Severity mapping for GCP format', () => {
171
- it('should map debug to DEBUG', () => {
172
- const levelToSeverity = {
173
- debug: 'DEBUG',
174
- info: 'INFO',
175
- warn: 'WARNING',
176
- error: 'ERROR',
177
- };
178
-
179
- expect(levelToSeverity.debug).toBe('DEBUG');
180
- });
181
-
182
- it('should map info to INFO', () => {
183
- const levelToSeverity = {
184
- debug: 'DEBUG',
185
- info: 'INFO',
186
- warn: 'WARNING',
187
- error: 'ERROR',
188
- };
189
-
190
- expect(levelToSeverity.info).toBe('INFO');
191
- });
192
-
193
- it('should map warn to WARNING', () => {
194
- const levelToSeverity = {
195
- debug: 'DEBUG',
196
- info: 'INFO',
197
- warn: 'WARNING',
198
- error: 'ERROR',
199
- };
200
-
201
- expect(levelToSeverity.warn).toBe('WARNING');
202
- });
203
-
204
- it('should map error to ERROR', () => {
205
- const levelToSeverity = {
206
- debug: 'DEBUG',
207
- info: 'INFO',
208
- warn: 'WARNING',
209
- error: 'ERROR',
210
- };
211
-
212
- expect(levelToSeverity.error).toBe('ERROR');
213
- });
214
- });
215
-
216
- describe('Error metadata normalization', () => {
217
- it('should normalize Error to object with message and stack', () => {
218
- const error = new Error('Test error');
219
- const normalized = {
220
- message: error.message,
221
- stack: error.stack,
222
- };
223
-
224
- expect(normalized.message).toBe('Test error');
225
- expect(normalized.stack).toBeDefined();
226
- });
227
-
228
- it('should preserve non-Error values', () => {
229
- const metadata = {
230
- string: 'test',
231
- number: 123,
232
- boolean: true,
233
- null: null,
234
- array: [1, 2, 3],
235
- object: { key: 'value' },
236
- };
237
-
238
- expect(metadata.string).toBe('test');
239
- expect(metadata.number).toBe(123);
240
- expect(metadata.boolean).toBe(true);
241
- expect(metadata.null).toBeNull();
242
- expect(metadata.array).toEqual([1, 2, 3]);
243
- expect(metadata.object).toEqual({ key: 'value' });
244
- });
245
- });
246
-
247
- describe('Timestamp format', () => {
248
- it('should use ISO time format', () => {
249
- // Pino stdTimeFunctions.isoTime produces ISO 8601 timestamps
250
- const now = new Date();
251
- const isoTime = now.toISOString();
252
-
253
- expect(isoTime).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/);
254
- });
255
- });
256
-
257
- describe('Message key', () => {
258
- it('should use "message" as the message key', () => {
259
- const logEntry = {
260
- level: 'INFO',
261
- time: '2026-01-08T12:00:00.000Z',
262
- message: 'Test message',
263
- };
264
-
265
- expect(logEntry.message).toBe('Test message');
266
- expect('message' in logEntry).toBe(true);
267
- });
268
- });
269
-
270
- describe('Base fields', () => {
271
- it('should not include base fields like hostname and pid', () => {
272
- // baseConfig.base = undefined disables these fields
273
- const logEntry = {
274
- level: 'INFO',
275
- time: '2026-01-08T12:00:00.000Z',
276
- message: 'Test message',
277
- };
278
-
279
- expect('hostname' in logEntry).toBe(false);
280
- expect('pid' in logEntry).toBe(false);
281
- expect('name' in logEntry).toBe(false);
282
- });
283
- });
284
-
285
- describe('Stdio mode behavior', () => {
286
- it('should log to stderr in stdio mode to avoid MCP protocol interference', () => {
287
- const useStderr = true;
288
-
289
- initLogger('info', 'plain', useStderr);
290
-
291
- // Logger should be configured for stderr
292
- expect(() => logger.info('Stdio mode test')).not.toThrow();
293
- });
294
-
295
- it('should log to stdout in HTTP mode', () => {
296
- const useStderr = false;
297
-
298
- initLogger('info', 'plain', useStderr);
299
-
300
- // Logger should be configured for stdout
301
- expect(() => logger.info('HTTP mode test')).not.toThrow();
302
- });
303
- });
304
-
305
- describe('Environment variable initialization', () => {
306
- it('should use MCP_SERVER_LOG_LEVEL from environment by default', () => {
307
- // The default instance reads from process.env.MCP_SERVER_LOG_LEVEL
308
- const defaultLevel = (process.env.MCP_SERVER_LOG_LEVEL as LogLevel | undefined) ?? 'info';
309
-
310
- expect(['debug', 'info', 'warn', 'error', 'silent']).toContain(defaultLevel);
311
- });
312
- });
313
-
314
- describe('Multiple logger instances', () => {
315
- it('should replace previous instance when reinitializing', () => {
316
- initLogger('info', 'plain', false);
317
- const firstInit = { ...logger };
318
-
319
- initLogger('debug', 'json', true);
320
- const secondInit = { ...logger };
321
-
322
- // Second initialization should replace the first
323
- expect(firstInit).toBeDefined();
324
- expect(secondInit).toBeDefined();
325
- });
326
- });
327
- });
@@ -1,105 +0,0 @@
1
- /**
2
- * Secrets returned by Home Assistant / Omada never reach a tool response.
3
- */
4
-
5
- import { describe, it, expect, vi } from 'vitest';
6
- import type { McpServer } from '@modelcontextprotocol/server';
7
-
8
- import { redactSecrets, REDACTED } from '../../src/utils/redact.js';
9
- import { toToolResult } from '../../src/tools/common.js';
10
- import { registerOmadaGraphTools } from '../../src/tools/omada/graph.js';
11
- import type { OmadaClient } from '../../src/omadaClient/index.js';
12
-
13
- /** Shape of an Omada SSID detail (GET .../wlans/{wlanId}/ssids/{ssidId}). */
14
- const ssidDetail = {
15
- ssidId: 'node-s55',
16
- name: 'node-s55',
17
- security: 3,
18
- hidePwd: true,
19
- pskSetting: { versionPsk: 2, encryptionPsk: 3, gikRekeyPskEnable: false, securityKey: 'HouseWifiPassw0rd!' },
20
- macFilterEnable: false,
21
- };
22
-
23
- describe('redactSecrets', () => {
24
- it('redacts the Wi-Fi password but keeps flags and numbers with similar names', () => {
25
- const out = redactSecrets(ssidDetail);
26
-
27
- expect(out.pskSetting.securityKey).toBe(REDACTED);
28
- expect(out.pskSetting.versionPsk).toBe(2);
29
- expect(out.pskSetting.encryptionPsk).toBe(3);
30
- expect(out.hidePwd).toBe(true);
31
- expect(out.name).toBe('node-s55');
32
- expect(JSON.stringify(out)).not.toContain('HouseWifiPassw0rd!');
33
- });
34
-
35
- it.each([
36
- ['RADIUS profile', { authServer: [{ ip: '192.168.0.2', port: 1812, secret: 'radius-s3cret' }], accountingServerPwd: 'acct-pw', coaPassword: 'coa-pw', radiusPwd: 'rp' }],
37
- ['PPSK profile', { name: 'kids', ppsk: [{ name: 'tablet', password: 'ppsk-key-1', vlanId: 20 }] }],
38
- ['VPN', { preSharedKey: 'ipsec-psk', presharedKey: 'wg-psk', privateKey: 'wg-private', publicKey: 'wg-public' }],
39
- ['SNMP', { snmpV1V2CEnable: true, communityString: 'snmp-community' }],
40
- ['portal and hotspot', { password: 'portal-pw', authCode: 'auth-code-123', simpleKey: 'sk', md5Key: 'mk' }],
41
- ['SSID variants', { psk: 'override-psk', ssidPassword: 'ssid-pw', bridgeSsidPassword: 'bridge-pw', overrideSsidPassword: 'ov-pw' }],
42
- ['VRRP and certificates', { key: 'vrrp-key', keyPassword: 'ks-pw', trustPassword: 'trust-pw' }],
43
- ['webhooks and tokens', { shardedSecret: 'hook-secret', authToken: 'twilio-token', accessToken: 'at', token: 'user-token' }],
44
- ])('redacts every secret in a %s', (_name, input) => {
45
- const text = JSON.stringify(redactSecrets(input));
46
-
47
- for (const secret of ['radius-s3cret', 'acct-pw', 'coa-pw', 'ppsk-key-1', 'ipsec-psk', 'wg-psk', 'wg-private', 'snmp-community', 'portal-pw', 'auth-code-123', 'override-psk', 'ssid-pw', 'bridge-pw', 'ov-pw', 'vrrp-key', 'ks-pw', 'trust-pw', 'hook-secret', 'twilio-token', 'user-token']) {
48
- expect(text).not.toContain(secret);
49
- }
50
- });
51
-
52
- it('keeps public, non-secret values (public keys, ids, names)', () => {
53
- const out = redactSecrets({ publicKey: 'wg-public', keyId: 'k1', searchKey: 'abc', ppskProfileId: 'p1' });
54
- expect(out).toEqual({ publicKey: 'wg-public', keyId: 'k1', searchKey: 'abc', ppskProfileId: 'p1' });
55
- });
56
-
57
- it('masks tokens inside URLs (Home Assistant camera image)', () => {
58
- const out = redactSecrets({
59
- entity_picture: '/api/camera_proxy/camera.door?token=0123456789abcdef&width=640',
60
- attributes: { access_token: 'cam-token' },
61
- });
62
- expect(out.entity_picture).toBe(`/api/camera_proxy/camera.door?token=${REDACTED}&width=640`);
63
- expect(out.attributes.access_token).toBe(REDACTED);
64
- });
65
-
66
- it('leaves empty secrets empty, so "is it set?" stays answerable', () => {
67
- expect(redactSecrets({ password: '', securityKey: 'x' })).toEqual({ password: '', securityKey: REDACTED });
68
- });
69
-
70
- it('does not modify its input', () => {
71
- const input = structuredClone(ssidDetail);
72
- redactSecrets(input);
73
- expect(input).toEqual(ssidDetail);
74
- });
75
-
76
- it('handles arrays, nulls and plain strings', () => {
77
- expect(redactSecrets([{ password: 'p' }, null, 3])).toEqual([{ password: REDACTED }, null, 3]);
78
- expect(redactSecrets('see /x?token=abc')).toBe(`see /x?token=${REDACTED}`);
79
- expect(redactSecrets(null)).toBeNull();
80
- });
81
- });
82
-
83
- describe('tool responses are redacted', () => {
84
- it('toToolResult never carries a secret', () => {
85
- const result = toToolResult(ssidDetail);
86
- expect(result.content[0].text).not.toContain('HouseWifiPassw0rd!');
87
- expect(result.content[0].text).toContain(REDACTED);
88
- });
89
-
90
- it('omada_read /wifi/ssids (SSID detail) does not return the Wi-Fi password', async () => {
91
- const handlers = new Map<string, (args: unknown, extra: unknown) => Promise<{ content: { text: string }[] }>>();
92
- const server = { registerTool: vi.fn((name, _c, h) => handlers.set(name, h)) } as unknown as McpServer;
93
- const client = { getSsidDetail: vi.fn().mockResolvedValue(ssidDetail), getSsidList: vi.fn() } as unknown as OmadaClient;
94
- registerOmadaGraphTools(server, client);
95
-
96
- const result = await handlers.get('omada_read')!(
97
- { path: '/wifi/ssids', params: { wlanId: 'w1', ssidId: 'node-s55' } },
98
- { sessionId: 's', http: { authInfo: { extra: { permissions: 0xff } } } }
99
- );
100
-
101
- expect(client.getSsidDetail).toHaveBeenCalled();
102
- expect(result.content[0].text).not.toContain('HouseWifiPassw0rd!');
103
- expect(JSON.parse(result.content[0].text).pskSetting.securityKey).toBe(REDACTED);
104
- });
105
- });
package/tsconfig.json DELETED
@@ -1,24 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2023",
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
- "outDir": "dist",
7
- "rootDir": "src",
8
- "resolveJsonModule": true,
9
- "esModuleInterop": true,
10
- "forceConsistentCasingInFileNames": true,
11
- "strict": true,
12
- "skipLibCheck": true,
13
- "declaration": true,
14
- "sourceMap": true,
15
- "noUnusedLocals": true,
16
- "noUnusedParameters": true,
17
- "noImplicitReturns": true,
18
- "noFallthroughCasesInSwitch": true,
19
- "allowUnusedLabels": false,
20
- "allowUnreachableCode": false
21
- },
22
- "include": ["src"],
23
- "exclude": ["node_modules", "dist", "tests", "example"]
24
- }
package/vitest.config.ts DELETED
@@ -1,38 +0,0 @@
1
- import { defineConfig } from 'vitest/config';
2
-
3
- export default defineConfig({
4
- test: {
5
- globals: true,
6
- environment: 'node',
7
- reporters: ['default'],
8
- exclude: [
9
- '**/node_modules/**',
10
- '**/dist/**',
11
- '**/example/**',
12
- ],
13
- coverage: {
14
- provider: 'v8',
15
- reporter: ['text', 'json', 'html'],
16
- exclude: [
17
- 'node_modules/',
18
- 'dist/',
19
- 'example/',
20
- 'tests/',
21
- '**/*.test.ts',
22
- '**/*.config.ts',
23
- ],
24
- // Regression FLOOR, not an aspiration. Set just below the measured numbers
25
- // (stmts 68.7 / branch 58.3 / funcs 75.4 / lines 69.3 as of v1.4.0) so the
26
- // gate catches a DROP in coverage without forcing busywork tests today.
27
- // Global (not per-file) by design — per-file 90% gates punish trivial files
28
- // and breed assertion-free stubs. Ratchet these UP as real coverage grows;
29
- // never lower them to make a red build pass.
30
- thresholds: {
31
- statements: 68,
32
- branches: 57,
33
- functions: 74,
34
- lines: 68,
35
- },
36
- },
37
- },
38
- });