@butlr/butlr-mcp-server 0.1.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.
Files changed (135) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +195 -0
  3. package/dist/cache/occupancy-cache.d.ts +72 -0
  4. package/dist/cache/occupancy-cache.d.ts.map +1 -0
  5. package/dist/cache/occupancy-cache.js +166 -0
  6. package/dist/cache/occupancy-cache.js.map +1 -0
  7. package/dist/cache/topology-cache.d.ts +36 -0
  8. package/dist/cache/topology-cache.d.ts.map +1 -0
  9. package/dist/cache/topology-cache.js +74 -0
  10. package/dist/cache/topology-cache.js.map +1 -0
  11. package/dist/clients/auth-client.d.ts +22 -0
  12. package/dist/clients/auth-client.d.ts.map +1 -0
  13. package/dist/clients/auth-client.js +82 -0
  14. package/dist/clients/auth-client.js.map +1 -0
  15. package/dist/clients/graphql-client.d.ts +6 -0
  16. package/dist/clients/graphql-client.d.ts.map +1 -0
  17. package/dist/clients/graphql-client.js +106 -0
  18. package/dist/clients/graphql-client.js.map +1 -0
  19. package/dist/clients/queries/topology.d.ts +36 -0
  20. package/dist/clients/queries/topology.d.ts.map +1 -0
  21. package/dist/clients/queries/topology.js +252 -0
  22. package/dist/clients/queries/topology.js.map +1 -0
  23. package/dist/clients/reporting-client.d.ts +191 -0
  24. package/dist/clients/reporting-client.d.ts.map +1 -0
  25. package/dist/clients/reporting-client.js +353 -0
  26. package/dist/clients/reporting-client.js.map +1 -0
  27. package/dist/clients/stats-client.d.ts +119 -0
  28. package/dist/clients/stats-client.d.ts.map +1 -0
  29. package/dist/clients/stats-client.js +238 -0
  30. package/dist/clients/stats-client.js.map +1 -0
  31. package/dist/clients/types.d.ts +215 -0
  32. package/dist/clients/types.d.ts.map +1 -0
  33. package/dist/clients/types.js +6 -0
  34. package/dist/clients/types.js.map +1 -0
  35. package/dist/constants.d.ts +3 -0
  36. package/dist/constants.d.ts.map +1 -0
  37. package/dist/constants.js +3 -0
  38. package/dist/constants.js.map +1 -0
  39. package/dist/errors/mcp-errors.d.ts +63 -0
  40. package/dist/errors/mcp-errors.d.ts.map +1 -0
  41. package/dist/errors/mcp-errors.js +144 -0
  42. package/dist/errors/mcp-errors.js.map +1 -0
  43. package/dist/index.d.ts +3 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +43 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/tools/butlr-available-rooms.d.ts +49 -0
  48. package/dist/tools/butlr-available-rooms.d.ts.map +1 -0
  49. package/dist/tools/butlr-available-rooms.js +492 -0
  50. package/dist/tools/butlr-available-rooms.js.map +1 -0
  51. package/dist/tools/butlr-fetch-entity-details.d.ts +42 -0
  52. package/dist/tools/butlr-fetch-entity-details.d.ts.map +1 -0
  53. package/dist/tools/butlr-fetch-entity-details.js +276 -0
  54. package/dist/tools/butlr-fetch-entity-details.js.map +1 -0
  55. package/dist/tools/butlr-get-asset-details.d.ts +51 -0
  56. package/dist/tools/butlr-get-asset-details.d.ts.map +1 -0
  57. package/dist/tools/butlr-get-asset-details.js +391 -0
  58. package/dist/tools/butlr-get-asset-details.js.map +1 -0
  59. package/dist/tools/butlr-get-current-occupancy.d.ts +21 -0
  60. package/dist/tools/butlr-get-current-occupancy.d.ts.map +1 -0
  61. package/dist/tools/butlr-get-current-occupancy.js +126 -0
  62. package/dist/tools/butlr-get-current-occupancy.js.map +1 -0
  63. package/dist/tools/butlr-get-occupancy-timeseries.d.ts +31 -0
  64. package/dist/tools/butlr-get-occupancy-timeseries.d.ts.map +1 -0
  65. package/dist/tools/butlr-get-occupancy-timeseries.js +145 -0
  66. package/dist/tools/butlr-get-occupancy-timeseries.js.map +1 -0
  67. package/dist/tools/butlr-hardware-snapshot.d.ts +55 -0
  68. package/dist/tools/butlr-hardware-snapshot.d.ts.map +1 -0
  69. package/dist/tools/butlr-hardware-snapshot.js +556 -0
  70. package/dist/tools/butlr-hardware-snapshot.js.map +1 -0
  71. package/dist/tools/butlr-list-topology.d.ts +27 -0
  72. package/dist/tools/butlr-list-topology.d.ts.map +1 -0
  73. package/dist/tools/butlr-list-topology.js +241 -0
  74. package/dist/tools/butlr-list-topology.js.map +1 -0
  75. package/dist/tools/butlr-search-assets.d.ts +53 -0
  76. package/dist/tools/butlr-search-assets.d.ts.map +1 -0
  77. package/dist/tools/butlr-search-assets.js +206 -0
  78. package/dist/tools/butlr-search-assets.js.map +1 -0
  79. package/dist/tools/butlr-space-busyness.d.ts +23 -0
  80. package/dist/tools/butlr-space-busyness.d.ts.map +1 -0
  81. package/dist/tools/butlr-space-busyness.js +304 -0
  82. package/dist/tools/butlr-space-busyness.js.map +1 -0
  83. package/dist/tools/butlr-traffic-flow.d.ts +39 -0
  84. package/dist/tools/butlr-traffic-flow.d.ts.map +1 -0
  85. package/dist/tools/butlr-traffic-flow.js +369 -0
  86. package/dist/tools/butlr-traffic-flow.js.map +1 -0
  87. package/dist/types/responses.d.ts +253 -0
  88. package/dist/types/responses.d.ts.map +1 -0
  89. package/dist/types/responses.js +8 -0
  90. package/dist/types/responses.js.map +1 -0
  91. package/dist/utils/asset-flattener.d.ts +50 -0
  92. package/dist/utils/asset-flattener.d.ts.map +1 -0
  93. package/dist/utils/asset-flattener.js +131 -0
  94. package/dist/utils/asset-flattener.js.map +1 -0
  95. package/dist/utils/asset-helpers.d.ts +8 -0
  96. package/dist/utils/asset-helpers.d.ts.map +1 -0
  97. package/dist/utils/asset-helpers.js +24 -0
  98. package/dist/utils/asset-helpers.js.map +1 -0
  99. package/dist/utils/field-validator.d.ts +29 -0
  100. package/dist/utils/field-validator.d.ts.map +1 -0
  101. package/dist/utils/field-validator.js +197 -0
  102. package/dist/utils/field-validator.js.map +1 -0
  103. package/dist/utils/fuzzy-match.d.ts +29 -0
  104. package/dist/utils/fuzzy-match.d.ts.map +1 -0
  105. package/dist/utils/fuzzy-match.js +70 -0
  106. package/dist/utils/fuzzy-match.js.map +1 -0
  107. package/dist/utils/graphql-helpers.d.ts +29 -0
  108. package/dist/utils/graphql-helpers.d.ts.map +1 -0
  109. package/dist/utils/graphql-helpers.js +43 -0
  110. package/dist/utils/graphql-helpers.js.map +1 -0
  111. package/dist/utils/natural-language.d.ts +73 -0
  112. package/dist/utils/natural-language.d.ts.map +1 -0
  113. package/dist/utils/natural-language.js +172 -0
  114. package/dist/utils/natural-language.js.map +1 -0
  115. package/dist/utils/occupancy-helpers.d.ts +63 -0
  116. package/dist/utils/occupancy-helpers.d.ts.map +1 -0
  117. package/dist/utils/occupancy-helpers.js +203 -0
  118. package/dist/utils/occupancy-helpers.js.map +1 -0
  119. package/dist/utils/path-builder.d.ts +10 -0
  120. package/dist/utils/path-builder.d.ts.map +1 -0
  121. package/dist/utils/path-builder.js +34 -0
  122. package/dist/utils/path-builder.js.map +1 -0
  123. package/dist/utils/time-range-validator.d.ts +13 -0
  124. package/dist/utils/time-range-validator.d.ts.map +1 -0
  125. package/dist/utils/time-range-validator.js +65 -0
  126. package/dist/utils/time-range-validator.js.map +1 -0
  127. package/dist/utils/timezone-helpers.d.ts +49 -0
  128. package/dist/utils/timezone-helpers.d.ts.map +1 -0
  129. package/dist/utils/timezone-helpers.js +209 -0
  130. package/dist/utils/timezone-helpers.js.map +1 -0
  131. package/dist/utils/tree-formatter.d.ts +23 -0
  132. package/dist/utils/tree-formatter.d.ts.map +1 -0
  133. package/dist/utils/tree-formatter.js +258 -0
  134. package/dist/utils/tree-formatter.js.map +1 -0
  135. package/package.json +93 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Butlr Technologies
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,195 @@
1
+ # Butlr MCP Server
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@butlr/butlr-mcp-server.svg)](https://www.npmjs.com/package/@butlr/butlr-mcp-server)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D20.0.0-brightgreen.svg)](https://nodejs.org/)
6
+
7
+ A [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server that connects AI assistants to [Butlr's](https://www.butlr.com) occupancy sensing platform. Query real-time space utilization, search facility assets, and analyze occupancy patterns through natural language.
8
+
9
+ ### What you can do
10
+
11
+ - **Find available spaces** — "Are there any free conference rooms right now with capacity for 8?"
12
+ - **Monitor occupancy** — "How busy is the cafe? Should I head there now?"
13
+ - **Analyze trends** — "Show me occupancy patterns for Floor 3 over the past week"
14
+ - **Search your portfolio** — "Find all rooms named 'huddle' across Building 2"
15
+ - **Check sensor health** — "Which sensors are offline or need battery replacement?"
16
+ - **Track foot traffic** — "How many people entered the main lobby today?"
17
+
18
+ ## Prerequisites
19
+
20
+ - [Node.js](https://nodejs.org/) 20 or higher
21
+ - An MCP-compatible client ([Claude Desktop](https://claude.ai/download), [Claude Code](https://docs.anthropic.com/en/docs/claude-code), [VS Code](https://code.visualstudio.com/), [Cursor](https://cursor.com/), etc.)
22
+ - Butlr API credentials (OAuth2 client ID, client secret, and organization ID) — see [Getting API Credentials](#getting-api-credentials)
23
+
24
+ ## Quick Start
25
+
26
+ <details open>
27
+ <summary><strong>Claude Desktop</strong></summary>
28
+
29
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
30
+
31
+ ```json
32
+ {
33
+ "mcpServers": {
34
+ "butlr": {
35
+ "command": "npx",
36
+ "args": ["-y", "@butlr/butlr-mcp-server@latest"],
37
+ "env": {
38
+ "BUTLR_CLIENT_ID": "your_client_id",
39
+ "BUTLR_CLIENT_SECRET": "your_client_secret",
40
+ "BUTLR_ORG_ID": "your_org_id"
41
+ }
42
+ }
43
+ }
44
+ }
45
+ ```
46
+
47
+ </details>
48
+
49
+ <details>
50
+ <summary><strong>Claude Code</strong></summary>
51
+
52
+ ```bash
53
+ claude mcp add butlr -- npx -y @butlr/butlr-mcp-server@latest
54
+ ```
55
+
56
+ Then set environment variables in your shell or `.env` file:
57
+
58
+ ```bash
59
+ export BUTLR_CLIENT_ID=your_client_id
60
+ export BUTLR_CLIENT_SECRET=your_client_secret
61
+ export BUTLR_ORG_ID=your_org_id
62
+ ```
63
+
64
+ </details>
65
+
66
+ <details>
67
+ <summary><strong>VS Code (Copilot)</strong></summary>
68
+
69
+ Add to `.vscode/mcp.json`:
70
+
71
+ ```json
72
+ {
73
+ "servers": {
74
+ "butlr": {
75
+ "type": "stdio",
76
+ "command": "npx",
77
+ "args": ["-y", "@butlr/butlr-mcp-server@latest"],
78
+ "env": {
79
+ "BUTLR_CLIENT_ID": "your_client_id",
80
+ "BUTLR_CLIENT_SECRET": "your_client_secret",
81
+ "BUTLR_ORG_ID": "your_org_id"
82
+ }
83
+ }
84
+ }
85
+ }
86
+ ```
87
+
88
+ </details>
89
+
90
+ <details>
91
+ <summary><strong>Cursor</strong></summary>
92
+
93
+ Add to `.cursor/mcp.json`:
94
+
95
+ ```json
96
+ {
97
+ "mcpServers": {
98
+ "butlr": {
99
+ "command": "npx",
100
+ "args": ["-y", "@butlr/butlr-mcp-server@latest"],
101
+ "env": {
102
+ "BUTLR_CLIENT_ID": "your_client_id",
103
+ "BUTLR_CLIENT_SECRET": "your_client_secret",
104
+ "BUTLR_ORG_ID": "your_org_id"
105
+ }
106
+ }
107
+ }
108
+ }
109
+ ```
110
+
111
+ </details>
112
+
113
+ <details>
114
+ <summary><strong>Other MCP clients</strong></summary>
115
+
116
+ For any MCP client that supports stdio transport, use this command:
117
+
118
+ ```
119
+ npx -y @butlr/butlr-mcp-server@latest
120
+ ```
121
+
122
+ Pass the required environment variables (`BUTLR_CLIENT_ID`, `BUTLR_CLIENT_SECRET`, `BUTLR_ORG_ID`) through your client's configuration.
123
+
124
+ </details>
125
+
126
+ ## Available Tools
127
+
128
+ | Tool | Description | Try asking... |
129
+ |------|-------------|---------------|
130
+ | `butlr_search_assets` | Search for assets (sites, buildings, floors, rooms, sensors) by name with fuzzy matching | "Find the main lobby" |
131
+ | `butlr_get_asset_details` | Get comprehensive details for specific assets by ID with batch support | "Show me details for Conference Room 401" |
132
+ | `butlr_hardware_snapshot` | Device health check: online/offline status and battery levels across your portfolio | "Which sensors need battery replacement?" |
133
+ | `butlr_available_rooms` | Find currently unoccupied rooms, filterable by capacity and tags | "Are there any free conference rooms right now?" |
134
+ | `butlr_space_busyness` | Current occupancy with qualitative labels (quiet/moderate/busy) and trend comparison | "How busy is the cafe right now?" |
135
+ | `butlr_traffic_flow` | Entry/exit counts with hourly breakdown for traffic-mode sensors | "How many people entered the lobby today?" |
136
+ | `butlr_list_topology` | Display org hierarchy tree with flexible depth control | "Show me all floors in Building 2" |
137
+ | `butlr_fetch_entity_details` | Retrieve specific fields for entities by ID (minimal token usage) | "What's the timezone for this site?" |
138
+ | `butlr_get_occupancy_timeseries` | Historical occupancy data with configurable time ranges | "Show occupancy trends for Floor 3 this week" |
139
+ | `butlr_get_current_occupancy` | Real-time occupancy snapshot (last 5 minutes median) | "How many people are on Floor 2 right now?" |
140
+
141
+ All tools are **read-only** — the server cannot modify any data in your Butlr account.
142
+
143
+ ## Configuration
144
+
145
+ | Variable | Required | Default | Description |
146
+ |----------|----------|---------|-------------|
147
+ | `BUTLR_CLIENT_ID` | **Yes** | - | OAuth2 client ID |
148
+ | `BUTLR_CLIENT_SECRET` | **Yes** | - | OAuth2 client secret |
149
+ | `BUTLR_ORG_ID` | **Yes** | - | Organization ID |
150
+ | `BUTLR_BASE_URL` | No | `https://api.butlr.io` | API base URL |
151
+ | `BUTLR_TIMEZONE` | No | `UTC` | Default timezone |
152
+ | `MCP_CACHE_TOPO_TTL` | No | `600` | Topology cache TTL (seconds) |
153
+ | `DEBUG` | No | - | Set to `butlr-mcp` for verbose logging |
154
+
155
+ ## Getting API Credentials
156
+
157
+ To use this MCP server, you need OAuth2 API credentials from Butlr:
158
+
159
+ 1. **Contact your Butlr account representative** or visit [butlr.com](https://www.butlr.com) to request API access
160
+ 2. You will receive a **Client ID**, **Client Secret**, and **Organization ID**
161
+ 3. These credentials provide read-only access scoped to your organization's data
162
+
163
+ ## Troubleshooting
164
+
165
+ **Authentication errors** — Verify your `BUTLR_CLIENT_ID`, `BUTLR_CLIENT_SECRET`, and `BUTLR_ORG_ID` are correct. Tokens are refreshed automatically.
166
+
167
+ **Rate limiting** — The server handles rate limits automatically with retry logic. If you see persistent rate limit errors, reduce the frequency of requests.
168
+
169
+ **No data returned** — Ensure your organization has active sensors deployed. Use `butlr_search_assets` to verify your org has discoverable assets.
170
+
171
+ **Debug logging** — Set `DEBUG=butlr-mcp` in your environment to see detailed request/response logs on stderr.
172
+
173
+ ## Development
174
+
175
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for full development workflow and standards.
176
+
177
+ ```bash
178
+ npm install # Install dependencies
179
+ npm run build # Build TypeScript
180
+ npm test # Run tests (442 tests)
181
+ npm run typecheck # Type checking
182
+ npm run lint # ESLint
183
+ npm run dev # Dev with hot-reload
184
+ npm run dev:debug # Dev with debug logging
185
+ ```
186
+
187
+ ## Security
188
+
189
+ - All tools enforce read-only API access
190
+ - Never commit credentials to version control
191
+ - See [SECURITY.md](SECURITY.md) for vulnerability disclosure
192
+
193
+ ## License
194
+
195
+ MIT - see [LICENSE](LICENSE)
@@ -0,0 +1,72 @@
1
+ import { LRUCache } from "lru-cache";
2
+ interface OccupancyCacheEntry {
3
+ occupancy: number;
4
+ timestamp: string;
5
+ asset_id: string;
6
+ asset_type: string;
7
+ }
8
+ /**
9
+ * LRU cache for current occupancy data with short TTL
10
+ * Reduces API calls for frequently accessed current occupancy queries
11
+ *
12
+ * Cache key format: occupancy:{asset_id}:{minute_bucket}
13
+ * Example: occupancy:room_123:202501131400 (truncated to minute)
14
+ */
15
+ export declare const occupancyCache: LRUCache<string, OccupancyCacheEntry, unknown>;
16
+ /**
17
+ * Generate cache key for occupancy queries
18
+ * Includes minute bucket to group queries within same minute
19
+ */
20
+ export declare function generateOccupancyCacheKey(assetId: string, timestamp?: Date): string;
21
+ /**
22
+ * Get cached occupancy data
23
+ */
24
+ export declare function getCachedOccupancy(assetId: string, timestamp?: Date): OccupancyCacheEntry | undefined;
25
+ /**
26
+ * Get cached occupancy for multiple assets
27
+ * Returns { hits: {}, misses: [] }
28
+ */
29
+ export declare function getBulkCachedOccupancy(assetIds: string[], timestamp?: Date): {
30
+ hits: Record<string, OccupancyCacheEntry>;
31
+ misses: string[];
32
+ };
33
+ /**
34
+ * Store occupancy data in cache
35
+ */
36
+ export declare function setCachedOccupancy(assetId: string, occupancy: number, assetType: string, timestamp?: Date): void;
37
+ /**
38
+ * Store multiple occupancy values
39
+ */
40
+ export declare function setBulkCachedOccupancy(entries: Array<{
41
+ assetId: string;
42
+ occupancy: number;
43
+ assetType: string;
44
+ timestamp?: Date;
45
+ }>): void;
46
+ /**
47
+ * Clear all cached occupancy data
48
+ */
49
+ export declare function clearOccupancyCache(): void;
50
+ /**
51
+ * Invalidate cache for specific asset
52
+ */
53
+ export declare function invalidateAssetOccupancy(assetId: string): void;
54
+ /**
55
+ * Get cache statistics
56
+ */
57
+ export declare function getOccupancyCacheStats(): {
58
+ size: number;
59
+ maxSize: number;
60
+ ttl: number;
61
+ utilizationPercent: number;
62
+ };
63
+ export declare function recordCacheHit(): void;
64
+ export declare function recordCacheMiss(): void;
65
+ export declare function getCacheHitRate(): {
66
+ hits: number;
67
+ misses: number;
68
+ hitRate: number;
69
+ };
70
+ export declare function resetCacheMetrics(): void;
71
+ export {};
72
+ //# sourceMappingURL=occupancy-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"occupancy-cache.d.ts","sourceRoot":"","sources":["../../src/cache/occupancy-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AASrC,UAAU,mBAAmB;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,gDAKzB,CAAC;AAEH;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,IAAI,GAAG,MAAM,CAanF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,IAAI,GACf,mBAAmB,GAAG,SAAS,CAkBjC;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAAE,EAClB,SAAS,CAAC,EAAE,IAAI,GACf;IACD,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAC1C,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAoBA;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,IAAI,GACf,IAAI,CAkBN;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,KAAK,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,IAAI,CAAC;CAClB,CAAC,GACD,IAAI,CAQN;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAM1C;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAa9D;AAED;;GAEG;AACH,wBAAgB,sBAAsB;;;;;EAOrC;AASD,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED,wBAAgB,eAAe,IAAI,IAAI,CAEtC;AAED,wBAAgB,eAAe,IAAI;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB,CAOA;AAED,wBAAgB,iBAAiB,IAAI,IAAI,CAGxC"}
@@ -0,0 +1,166 @@
1
+ import { LRUCache } from "lru-cache";
2
+ /**
3
+ * Occupancy cache configuration
4
+ * TTL: 60 seconds (fast-changing data)
5
+ */
6
+ const CACHE_TTL_SECONDS = parseInt(process.env.MCP_CACHE_OCCUPANCY_TTL || "60", 10) * 1000; // Convert to milliseconds
7
+ const MAX_CACHE_ENTRIES = 500; // More entries than topology (many rooms)
8
+ /**
9
+ * LRU cache for current occupancy data with short TTL
10
+ * Reduces API calls for frequently accessed current occupancy queries
11
+ *
12
+ * Cache key format: occupancy:{asset_id}:{minute_bucket}
13
+ * Example: occupancy:room_123:202501131400 (truncated to minute)
14
+ */
15
+ export const occupancyCache = new LRUCache({
16
+ max: MAX_CACHE_ENTRIES,
17
+ ttl: CACHE_TTL_SECONDS,
18
+ updateAgeOnGet: true, // Reset TTL on cache hit
19
+ updateAgeOnHas: false,
20
+ });
21
+ /**
22
+ * Generate cache key for occupancy queries
23
+ * Includes minute bucket to group queries within same minute
24
+ */
25
+ export function generateOccupancyCacheKey(assetId, timestamp) {
26
+ const now = timestamp || new Date();
27
+ // Truncate to minute (ignore seconds)
28
+ const minuteBucket = new Date(now);
29
+ minuteBucket.setSeconds(0, 0);
30
+ const bucketStr = minuteBucket
31
+ .toISOString()
32
+ .replace(/[-:T]/g, "") // Remove dashes, colons, and T
33
+ .substring(0, 12); // YYYYMMDDHHmm
34
+ return `occupancy:${assetId}:${bucketStr}`;
35
+ }
36
+ /**
37
+ * Get cached occupancy data
38
+ */
39
+ export function getCachedOccupancy(assetId, timestamp) {
40
+ const key = generateOccupancyCacheKey(assetId, timestamp);
41
+ const cached = occupancyCache.get(key);
42
+ // Track cache hit/miss metrics
43
+ if (cached) {
44
+ recordCacheHit();
45
+ if (process.env.DEBUG) {
46
+ console.error(`[occupancy-cache] Cache HIT for ${assetId}`);
47
+ }
48
+ }
49
+ else {
50
+ recordCacheMiss();
51
+ if (process.env.DEBUG) {
52
+ console.error(`[occupancy-cache] Cache MISS for ${assetId}`);
53
+ }
54
+ }
55
+ return cached;
56
+ }
57
+ /**
58
+ * Get cached occupancy for multiple assets
59
+ * Returns { hits: {}, misses: [] }
60
+ */
61
+ export function getBulkCachedOccupancy(assetIds, timestamp) {
62
+ const hits = {};
63
+ const misses = [];
64
+ for (const assetId of assetIds) {
65
+ const cached = getCachedOccupancy(assetId, timestamp);
66
+ if (cached) {
67
+ hits[assetId] = cached;
68
+ }
69
+ else {
70
+ misses.push(assetId);
71
+ }
72
+ }
73
+ if (process.env.DEBUG) {
74
+ console.error(`[occupancy-cache] Bulk query: ${Object.keys(hits).length} hits, ${misses.length} misses`);
75
+ }
76
+ return { hits, misses };
77
+ }
78
+ /**
79
+ * Store occupancy data in cache
80
+ */
81
+ export function setCachedOccupancy(assetId, occupancy, assetType, timestamp) {
82
+ const now = timestamp || new Date();
83
+ const key = generateOccupancyCacheKey(assetId, now);
84
+ const entry = {
85
+ occupancy,
86
+ timestamp: now.toISOString(),
87
+ asset_id: assetId,
88
+ asset_type: assetType,
89
+ };
90
+ occupancyCache.set(key, entry);
91
+ if (process.env.DEBUG) {
92
+ console.error(`[occupancy-cache] Cached occupancy for ${assetId}: ${occupancy} (TTL: ${CACHE_TTL_SECONDS / 1000}s)`);
93
+ }
94
+ }
95
+ /**
96
+ * Store multiple occupancy values
97
+ */
98
+ export function setBulkCachedOccupancy(entries) {
99
+ for (const entry of entries) {
100
+ setCachedOccupancy(entry.assetId, entry.occupancy, entry.assetType, entry.timestamp);
101
+ }
102
+ if (process.env.DEBUG) {
103
+ console.error(`[occupancy-cache] Bulk cached ${entries.length} occupancy values`);
104
+ }
105
+ }
106
+ /**
107
+ * Clear all cached occupancy data
108
+ */
109
+ export function clearOccupancyCache() {
110
+ occupancyCache.clear();
111
+ if (process.env.DEBUG) {
112
+ console.error("[occupancy-cache] Cache cleared");
113
+ }
114
+ }
115
+ /**
116
+ * Invalidate cache for specific asset
117
+ */
118
+ export function invalidateAssetOccupancy(assetId) {
119
+ // Delete all keys for this asset (all time buckets)
120
+ let deleted = 0;
121
+ for (const key of occupancyCache.keys()) {
122
+ if (key.startsWith(`occupancy:${assetId}:`)) {
123
+ occupancyCache.delete(key);
124
+ deleted++;
125
+ }
126
+ }
127
+ if (process.env.DEBUG && deleted > 0) {
128
+ console.error(`[occupancy-cache] Invalidated ${deleted} cache entries for ${assetId}`);
129
+ }
130
+ }
131
+ /**
132
+ * Get cache statistics
133
+ */
134
+ export function getOccupancyCacheStats() {
135
+ return {
136
+ size: occupancyCache.size,
137
+ maxSize: MAX_CACHE_ENTRIES,
138
+ ttl: CACHE_TTL_SECONDS / 1000, // Convert back to seconds for display
139
+ utilizationPercent: (occupancyCache.size / MAX_CACHE_ENTRIES) * 100,
140
+ };
141
+ }
142
+ /**
143
+ * Calculate cache hit rate over time
144
+ * (For monitoring/debugging)
145
+ */
146
+ let cacheHits = 0;
147
+ let cacheMisses = 0;
148
+ export function recordCacheHit() {
149
+ cacheHits++;
150
+ }
151
+ export function recordCacheMiss() {
152
+ cacheMisses++;
153
+ }
154
+ export function getCacheHitRate() {
155
+ const total = cacheHits + cacheMisses;
156
+ return {
157
+ hits: cacheHits,
158
+ misses: cacheMisses,
159
+ hitRate: total > 0 ? (cacheHits / total) * 100 : 0,
160
+ };
161
+ }
162
+ export function resetCacheMetrics() {
163
+ cacheHits = 0;
164
+ cacheMisses = 0;
165
+ }
166
+ //# sourceMappingURL=occupancy-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"occupancy-cache.js","sourceRoot":"","sources":["../../src/cache/occupancy-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC;;;GAGG;AACH,MAAM,iBAAiB,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,0BAA0B;AACtH,MAAM,iBAAiB,GAAG,GAAG,CAAC,CAAC,0CAA0C;AASzE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,QAAQ,CAA8B;IACtE,GAAG,EAAE,iBAAiB;IACtB,GAAG,EAAE,iBAAiB;IACtB,cAAc,EAAE,IAAI,EAAE,yBAAyB;IAC/C,cAAc,EAAE,KAAK;CACtB,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAAe,EAAE,SAAgB;IACzE,MAAM,GAAG,GAAG,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC;IAEpC,sCAAsC;IACtC,MAAM,YAAY,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;IACnC,YAAY,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAE9B,MAAM,SAAS,GAAG,YAAY;SAC3B,WAAW,EAAE;SACb,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,+BAA+B;SACrD,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe;IAEpC,OAAO,aAAa,OAAO,IAAI,SAAS,EAAE,CAAC;AAC7C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAe,EACf,SAAgB;IAEhB,MAAM,GAAG,GAAG,yBAAyB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAEvC,+BAA+B;IAC/B,IAAI,MAAM,EAAE,CAAC;QACX,cAAc,EAAE,CAAC;QACjB,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,mCAAmC,OAAO,EAAE,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;SAAM,CAAC;QACN,eAAe,EAAE,CAAC;QAClB,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,oCAAoC,OAAO,EAAE,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,QAAkB,EAClB,SAAgB;IAKhB,MAAM,IAAI,GAAwC,EAAE,CAAC;IACrD,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACtD,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;QACtB,OAAO,CAAC,KAAK,CACX,iCAAiC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,UAAU,MAAM,CAAC,MAAM,SAAS,CAC1F,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAe,EACf,SAAiB,EACjB,SAAiB,EACjB,SAAgB;IAEhB,MAAM,GAAG,GAAG,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC;IACpC,MAAM,GAAG,GAAG,yBAAyB,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAEpD,MAAM,KAAK,GAAwB;QACjC,SAAS;QACT,SAAS,EAAE,GAAG,CAAC,WAAW,EAAE;QAC5B,QAAQ,EAAE,OAAO;QACjB,UAAU,EAAE,SAAS;KACtB,CAAC;IAEF,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAE/B,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;QACtB,OAAO,CAAC,KAAK,CACX,0CAA0C,OAAO,KAAK,SAAS,UAAU,iBAAiB,GAAG,IAAI,IAAI,CACtG,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAKE;IAEF,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,kBAAkB,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IACvF,CAAC;IAED,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;QACtB,OAAO,CAAC,KAAK,CAAC,iCAAiC,OAAO,CAAC,MAAM,mBAAmB,CAAC,CAAC;IACpF,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB;IACjC,cAAc,CAAC,KAAK,EAAE,CAAC;IAEvB,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;QACtB,OAAO,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,wBAAwB,CAAC,OAAe;IACtD,oDAAoD;IACpD,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,MAAM,GAAG,IAAI,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC;QACxC,IAAI,GAAG,CAAC,UAAU,CAAC,aAAa,OAAO,GAAG,CAAC,EAAE,CAAC;YAC5C,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC3B,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QACrC,OAAO,CAAC,KAAK,CAAC,iCAAiC,OAAO,sBAAsB,OAAO,EAAE,CAAC,CAAC;IACzF,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO;QACL,IAAI,EAAE,cAAc,CAAC,IAAI;QACzB,OAAO,EAAE,iBAAiB;QAC1B,GAAG,EAAE,iBAAiB,GAAG,IAAI,EAAE,sCAAsC;QACrE,kBAAkB,EAAE,CAAC,cAAc,CAAC,IAAI,GAAG,iBAAiB,CAAC,GAAG,GAAG;KACpE,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,IAAI,SAAS,GAAG,CAAC,CAAC;AAClB,IAAI,WAAW,GAAG,CAAC,CAAC;AAEpB,MAAM,UAAU,cAAc;IAC5B,SAAS,EAAE,CAAC;AACd,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,WAAW,EAAE,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,eAAe;IAK7B,MAAM,KAAK,GAAG,SAAS,GAAG,WAAW,CAAC;IACtC,OAAO;QACL,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,WAAW;QACnB,OAAO,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;KACnD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,SAAS,GAAG,CAAC,CAAC;IACd,WAAW,GAAG,CAAC,CAAC;AAClB,CAAC"}
@@ -0,0 +1,36 @@
1
+ import { LRUCache } from "lru-cache";
2
+ interface CacheEntry {
3
+ data: Record<string, unknown>;
4
+ timestamp: string;
5
+ }
6
+ /**
7
+ * LRU cache for topology data with TTL
8
+ * Reduces API calls for frequently accessed topology structures
9
+ */
10
+ export declare const topologyCache: LRUCache<string, CacheEntry, unknown>;
11
+ /**
12
+ * Generate cache key for topology queries
13
+ */
14
+ export declare function generateTopologyCacheKey(orgId: string, includeDevices: boolean, includeZones: boolean, siteIds?: string[]): string;
15
+ /**
16
+ * Get cached topology data
17
+ */
18
+ export declare function getCachedTopology(key: string): CacheEntry | undefined;
19
+ /**
20
+ * Store topology data in cache
21
+ */
22
+ export declare function setCachedTopology(key: string, data: Record<string, unknown>): void;
23
+ /**
24
+ * Clear all cached topology data
25
+ */
26
+ export declare function clearTopologyCache(): void;
27
+ /**
28
+ * Get cache statistics
29
+ */
30
+ export declare function getCacheStats(): {
31
+ size: number;
32
+ maxSize: number;
33
+ ttl: number;
34
+ };
35
+ export {};
36
+ //# sourceMappingURL=topology-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topology-cache.d.ts","sourceRoot":"","sources":["../../src/cache/topology-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAQrC,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,uCAKxB,CAAC;AAEH;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,OAAO,EACvB,YAAY,EAAE,OAAO,EACrB,OAAO,CAAC,EAAE,MAAM,EAAE,GACjB,MAAM,CAWR;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAUrE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAalF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAMzC;AAED;;GAEG;AACH,wBAAgB,aAAa;;;;EAM5B"}
@@ -0,0 +1,74 @@
1
+ import { LRUCache } from "lru-cache";
2
+ /**
3
+ * Topology cache configuration
4
+ */
5
+ const CACHE_TTL_SECONDS = parseInt(process.env.MCP_CACHE_TOPO_TTL || "600", 10) * 1000; // Convert to milliseconds
6
+ const MAX_CACHE_ENTRIES = 100;
7
+ /**
8
+ * LRU cache for topology data with TTL
9
+ * Reduces API calls for frequently accessed topology structures
10
+ */
11
+ export const topologyCache = new LRUCache({
12
+ max: MAX_CACHE_ENTRIES,
13
+ ttl: CACHE_TTL_SECONDS,
14
+ updateAgeOnGet: true, // Reset TTL on cache hit
15
+ updateAgeOnHas: false,
16
+ });
17
+ /**
18
+ * Generate cache key for topology queries
19
+ */
20
+ export function generateTopologyCacheKey(orgId, includeDevices, includeZones, siteIds) {
21
+ const parts = ["topo", orgId];
22
+ if (siteIds && siteIds.length > 0) {
23
+ parts.push(`sites:${siteIds.sort().join(",")}`);
24
+ }
25
+ parts.push(`devices:${includeDevices}`);
26
+ parts.push(`zones:${includeZones}`);
27
+ return parts.join(":");
28
+ }
29
+ /**
30
+ * Get cached topology data
31
+ */
32
+ export function getCachedTopology(key) {
33
+ const cached = topologyCache.get(key);
34
+ if (cached && process.env.DEBUG) {
35
+ console.error(`[topology-cache] Cache HIT for key: ${key}`);
36
+ }
37
+ else if (process.env.DEBUG) {
38
+ console.error(`[topology-cache] Cache MISS for key: ${key}`);
39
+ }
40
+ return cached;
41
+ }
42
+ /**
43
+ * Store topology data in cache
44
+ */
45
+ export function setCachedTopology(key, data) {
46
+ const entry = {
47
+ data,
48
+ timestamp: new Date().toISOString(),
49
+ };
50
+ topologyCache.set(key, entry);
51
+ if (process.env.DEBUG) {
52
+ console.error(`[topology-cache] Cached data for key: ${key} (TTL: ${CACHE_TTL_SECONDS / 1000}s)`);
53
+ }
54
+ }
55
+ /**
56
+ * Clear all cached topology data
57
+ */
58
+ export function clearTopologyCache() {
59
+ topologyCache.clear();
60
+ if (process.env.DEBUG) {
61
+ console.error("[topology-cache] Cache cleared");
62
+ }
63
+ }
64
+ /**
65
+ * Get cache statistics
66
+ */
67
+ export function getCacheStats() {
68
+ return {
69
+ size: topologyCache.size,
70
+ maxSize: MAX_CACHE_ENTRIES,
71
+ ttl: CACHE_TTL_SECONDS / 1000, // Convert back to seconds for display
72
+ };
73
+ }
74
+ //# sourceMappingURL=topology-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topology-cache.js","sourceRoot":"","sources":["../../src/cache/topology-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC;;GAEG;AACH,MAAM,iBAAiB,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,KAAK,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,0BAA0B;AAClH,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAO9B;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,QAAQ,CAAqB;IAC5D,GAAG,EAAE,iBAAiB;IACtB,GAAG,EAAE,iBAAiB;IACtB,cAAc,EAAE,IAAI,EAAE,yBAAyB;IAC/C,cAAc,EAAE,KAAK;CACtB,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,UAAU,wBAAwB,CACtC,KAAa,EACb,cAAuB,EACvB,YAAqB,EACrB,OAAkB;IAElB,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAE9B,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,SAAS,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,WAAW,cAAc,EAAE,CAAC,CAAC;IACxC,KAAK,CAAC,IAAI,CAAC,SAAS,YAAY,EAAE,CAAC,CAAC;IAEpC,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAEtC,IAAI,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;QAChC,OAAO,CAAC,KAAK,CAAC,uCAAuC,GAAG,EAAE,CAAC,CAAC;IAC9D,CAAC;SAAM,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;QAC7B,OAAO,CAAC,KAAK,CAAC,wCAAwC,GAAG,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAW,EAAE,IAA6B;IAC1E,MAAM,KAAK,GAAe;QACxB,IAAI;QACJ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IAEF,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAE9B,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;QACtB,OAAO,CAAC,KAAK,CACX,yCAAyC,GAAG,UAAU,iBAAiB,GAAG,IAAI,IAAI,CACnF,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB;IAChC,aAAa,CAAC,KAAK,EAAE,CAAC;IAEtB,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;QACtB,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;IAClD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO;QACL,IAAI,EAAE,aAAa,CAAC,IAAI;QACxB,OAAO,EAAE,iBAAiB;QAC1B,GAAG,EAAE,iBAAiB,GAAG,IAAI,EAAE,sCAAsC;KACtE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Butlr Authentication Client
3
+ * Manages OAuth2 client credentials flow for API authentication
4
+ */
5
+ declare class ButlrAuthClient {
6
+ private token;
7
+ private tokenExpiry;
8
+ private readonly clientId;
9
+ private readonly clientSecret;
10
+ constructor();
11
+ /**
12
+ * Get a valid access token, fetching a new one if needed
13
+ */
14
+ getToken(): Promise<string>;
15
+ /**
16
+ * Clear cached token (useful for testing)
17
+ */
18
+ clearToken(): void;
19
+ }
20
+ export declare const authClient: ButlrAuthClient;
21
+ export {};
22
+ //# sourceMappingURL=auth-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-client.d.ts","sourceRoot":"","sources":["../../src/clients/auth-client.ts"],"names":[],"mappings":"AAaA;;;GAGG;AACH,cAAM,eAAe;IACnB,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;;IAOtC;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAgEjC;;OAEG;IACH,UAAU,IAAI,IAAI;CAInB;AAGD,eAAO,MAAM,UAAU,iBAAwB,CAAC"}