awolve-myoffice-cli 1.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 (94) hide show
  1. package/README.md +205 -0
  2. package/dist/auth/cache-plugin.d.ts +20 -0
  3. package/dist/auth/cache-plugin.d.ts.map +1 -0
  4. package/dist/auth/cache-plugin.js +49 -0
  5. package/dist/auth/cache-plugin.js.map +1 -0
  6. package/dist/auth/config.d.ts +22 -0
  7. package/dist/auth/config.d.ts.map +1 -0
  8. package/dist/auth/config.js +64 -0
  9. package/dist/auth/config.js.map +1 -0
  10. package/dist/auth/device-code.d.ts +2 -0
  11. package/dist/auth/device-code.d.ts.map +1 -0
  12. package/dist/auth/device-code.js +38 -0
  13. package/dist/auth/device-code.js.map +1 -0
  14. package/dist/auth/index.d.ts +4 -0
  15. package/dist/auth/index.d.ts.map +1 -0
  16. package/dist/auth/index.js +4 -0
  17. package/dist/auth/index.js.map +1 -0
  18. package/dist/auth/login.d.ts +7 -0
  19. package/dist/auth/login.d.ts.map +1 -0
  20. package/dist/auth/login.js +22 -0
  21. package/dist/auth/login.js.map +1 -0
  22. package/dist/auth/token-manager.d.ts +4 -0
  23. package/dist/auth/token-manager.d.ts.map +1 -0
  24. package/dist/auth/token-manager.js +78 -0
  25. package/dist/auth/token-manager.js.map +1 -0
  26. package/dist/cli/formatter.d.ts +5 -0
  27. package/dist/cli/formatter.d.ts.map +1 -0
  28. package/dist/cli/formatter.js +317 -0
  29. package/dist/cli/formatter.js.map +1 -0
  30. package/dist/cli.d.ts +3 -0
  31. package/dist/cli.d.ts.map +1 -0
  32. package/dist/cli.js +802 -0
  33. package/dist/cli.js.map +1 -0
  34. package/dist/core/handler.d.ts +8 -0
  35. package/dist/core/handler.d.ts.map +1 -0
  36. package/dist/core/handler.js +289 -0
  37. package/dist/core/handler.js.map +1 -0
  38. package/dist/index.d.ts +3 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +819 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/tools/calendar.d.ts +124 -0
  43. package/dist/tools/calendar.d.ts.map +1 -0
  44. package/dist/tools/calendar.js +129 -0
  45. package/dist/tools/calendar.js.map +1 -0
  46. package/dist/tools/chats.d.ts +66 -0
  47. package/dist/tools/chats.d.ts.map +1 -0
  48. package/dist/tools/chats.js +102 -0
  49. package/dist/tools/chats.js.map +1 -0
  50. package/dist/tools/contacts.d.ts +119 -0
  51. package/dist/tools/contacts.d.ts.map +1 -0
  52. package/dist/tools/contacts.js +136 -0
  53. package/dist/tools/contacts.js.map +1 -0
  54. package/dist/tools/index.d.ts +10 -0
  55. package/dist/tools/index.d.ts.map +1 -0
  56. package/dist/tools/index.js +10 -0
  57. package/dist/tools/index.js.map +1 -0
  58. package/dist/tools/mail.d.ts +138 -0
  59. package/dist/tools/mail.d.ts.map +1 -0
  60. package/dist/tools/mail.js +187 -0
  61. package/dist/tools/mail.js.map +1 -0
  62. package/dist/tools/onedrive.d.ts +107 -0
  63. package/dist/tools/onedrive.d.ts.map +1 -0
  64. package/dist/tools/onedrive.js +136 -0
  65. package/dist/tools/onedrive.js.map +1 -0
  66. package/dist/tools/planner.d.ts +261 -0
  67. package/dist/tools/planner.d.ts.map +1 -0
  68. package/dist/tools/planner.js +401 -0
  69. package/dist/tools/planner.js.map +1 -0
  70. package/dist/tools/sharepoint.d.ts +138 -0
  71. package/dist/tools/sharepoint.d.ts.map +1 -0
  72. package/dist/tools/sharepoint.js +156 -0
  73. package/dist/tools/sharepoint.js.map +1 -0
  74. package/dist/tools/tasks.d.ts +107 -0
  75. package/dist/tools/tasks.d.ts.map +1 -0
  76. package/dist/tools/tasks.js +131 -0
  77. package/dist/tools/tasks.js.map +1 -0
  78. package/dist/tools/teams.d.ts +66 -0
  79. package/dist/tools/teams.d.ts.map +1 -0
  80. package/dist/tools/teams.js +69 -0
  81. package/dist/tools/teams.js.map +1 -0
  82. package/dist/utils/graph-client.d.ts +10 -0
  83. package/dist/utils/graph-client.d.ts.map +1 -0
  84. package/dist/utils/graph-client.js +49 -0
  85. package/dist/utils/graph-client.js.map +1 -0
  86. package/dist/utils/signature.d.ts +2 -0
  87. package/dist/utils/signature.d.ts.map +1 -0
  88. package/dist/utils/signature.js +17 -0
  89. package/dist/utils/signature.js.map +1 -0
  90. package/dist/utils/version.d.ts +2 -0
  91. package/dist/utils/version.d.ts.map +1 -0
  92. package/dist/utils/version.js +20 -0
  93. package/dist/utils/version.js.map +1 -0
  94. package/package.json +51 -0
package/README.md ADDED
@@ -0,0 +1,205 @@
1
+ # MyOffice MCP
2
+
3
+ A lightweight MCP (Model Context Protocol) server for personal Microsoft 365 access, designed for AI assistants like Claude Code.
4
+
5
+ Unlike admin-focused M365 tools, this uses **delegated authentication** - users authenticate as themselves and can only access their own data.
6
+
7
+ ## Features
8
+
9
+ - **Email** - List, read, search, send, delete
10
+ - **Calendar** - List, create, update, delete events (with Teams meetings)
11
+ - **Tasks** - Manage Microsoft To Do lists and tasks
12
+ - **OneDrive** - Browse, search, read files
13
+ - **Contacts** - List and search contacts
14
+
15
+ ## Prerequisites
16
+
17
+ - Node.js 18+
18
+ - An Azure AD app registration with delegated permissions (see setup below)
19
+ - Microsoft 365 account
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ git clone https://github.com/awolve/ops-myoffice.git
25
+ cd ops-myoffice
26
+ npm install
27
+ npm run build
28
+ ```
29
+
30
+ ## Azure AD App Registration
31
+
32
+ 1. Go to [Azure Portal](https://portal.azure.com) > Azure Active Directory > App registrations
33
+ 2. Click **New registration**
34
+ - Name: `Personal M365 MCP` (or your choice)
35
+ - Supported account types: **Accounts in any organizational directory** (for multi-tenant)
36
+ - Redirect URI: Leave blank (we use device code flow)
37
+ 3. After creation, note the **Application (client) ID**
38
+ 4. Go to **Authentication** > Advanced settings
39
+ - Enable **Allow public client flows** = Yes
40
+ 5. Go to **API permissions** > Add a permission > Microsoft Graph > Delegated permissions
41
+ - Add these permissions:
42
+ - `Mail.ReadWrite`
43
+ - `Mail.Send`
44
+ - `Calendars.ReadWrite`
45
+ - `Tasks.ReadWrite`
46
+ - `Files.ReadWrite`
47
+ - `Sites.Read.All`
48
+ - `Contacts.ReadWrite`
49
+ - `User.Read`
50
+ - `Team.ReadBasic.All`
51
+ - `Channel.ReadBasic.All`
52
+ - `ChannelMessage.Read.All`
53
+ - `ChannelMessage.Send`
54
+ - `Chat.Create`
55
+ - `Chat.ReadBasic`
56
+ - `Chat.Read`
57
+ - `ChatMessage.Send`
58
+ - `offline_access`
59
+ 6. Click **Grant admin consent** (optional - users can consent themselves)
60
+
61
+ ## Configuration
62
+
63
+ Set environment variables:
64
+
65
+ ```bash
66
+ export M365_CLIENT_ID="your-app-client-id"
67
+ export M365_TENANT_ID="common" # or your tenant ID for single-tenant
68
+ ```
69
+
70
+ Or create a `.env` file:
71
+
72
+ ```
73
+ M365_CLIENT_ID=your-app-client-id
74
+ M365_TENANT_ID=common
75
+ ```
76
+
77
+ ## First-Time Authentication
78
+
79
+ Run the login script to authenticate:
80
+
81
+ ```bash
82
+ npm run login
83
+ ```
84
+
85
+ You'll see:
86
+ ```
87
+ AUTHENTICATION REQUIRED
88
+ ========================================
89
+ To sign in, use a web browser to open the page
90
+ https://microsoft.com/devicelogin and enter the code XXXXXXXX
91
+ ========================================
92
+ ```
93
+
94
+ After signing in, your token is cached at `~/.config/myoffice-mcp/token.json`
95
+
96
+ ## Usage with Claude Code
97
+
98
+ Add to your Claude Code MCP settings:
99
+
100
+ ```json
101
+ {
102
+ "mcpServers": {
103
+ "myoffice-mcp": {
104
+ "command": "node",
105
+ "args": ["/path/to/ops-myoffice/dist/index.js"],
106
+ "env": {
107
+ "M365_CLIENT_ID": "your-client-id"
108
+ }
109
+ }
110
+ }
111
+ }
112
+ ```
113
+
114
+ ## Available Tools
115
+
116
+ ### Email
117
+ | Tool | Description |
118
+ |------|-------------|
119
+ | `mail_list` | List emails from a folder |
120
+ | `mail_read` | Read a specific email |
121
+ | `mail_search` | Search emails |
122
+ | `mail_send` | Send an email |
123
+ | `mail_delete` | Delete an email |
124
+
125
+ ### Calendar
126
+ | Tool | Description |
127
+ |------|-------------|
128
+ | `calendar_list` | List events in date range |
129
+ | `calendar_get` | Get event details |
130
+ | `calendar_create` | Create an event |
131
+ | `calendar_update` | Update an event |
132
+ | `calendar_delete` | Delete an event |
133
+
134
+ ### Tasks
135
+ | Tool | Description |
136
+ |------|-------------|
137
+ | `tasks_list_lists` | List all task lists |
138
+ | `tasks_list` | List tasks from a list |
139
+ | `tasks_create` | Create a task |
140
+ | `tasks_update` | Update a task |
141
+ | `tasks_complete` | Mark task complete |
142
+ | `tasks_delete` | Delete a task |
143
+
144
+ ### OneDrive
145
+ | Tool | Description |
146
+ |------|-------------|
147
+ | `onedrive_list` | List files/folders |
148
+ | `onedrive_get` | Get file metadata |
149
+ | `onedrive_search` | Search files |
150
+ | `onedrive_read` | Read text file content |
151
+ | `onedrive_create_folder` | Create a folder |
152
+
153
+ ### Contacts
154
+ | Tool | Description |
155
+ |------|-------------|
156
+ | `contacts_list` | List contacts |
157
+ | `contacts_search` | Search contacts |
158
+ | `contacts_get` | Get contact details |
159
+ | `contacts_create` | Create a new contact |
160
+ | `contacts_update` | Update an existing contact |
161
+
162
+ ### Teams
163
+ | Tool | Description |
164
+ |------|-------------|
165
+ | `teams_list` | List Teams you're a member of |
166
+ | `teams_channels` | List channels in a Team |
167
+ | `teams_channel_messages` | Read messages from a channel |
168
+ | `teams_channel_post` | Post a message to a channel |
169
+
170
+ ### Chats
171
+ | Tool | Description |
172
+ |------|-------------|
173
+ | `chats_list` | List 1:1 and group chats |
174
+ | `chats_messages` | Read messages from a chat |
175
+ | `chats_send` | Send a message in a chat |
176
+ | `chats_create` | Create a new 1:1 or group chat |
177
+
178
+ ### Auth
179
+ | Tool | Description |
180
+ |------|-------------|
181
+ | `auth_status` | Check auth status |
182
+
183
+ ## Security
184
+
185
+ - Uses delegated permissions only - users can only access their own data
186
+ - Tokens stored locally with restrictive permissions (0600)
187
+ - No client secrets required (public client)
188
+ - Destructive operations (send, delete) are clearly marked for AI confirmation
189
+
190
+ ## Development
191
+
192
+ ```bash
193
+ # Run in development mode
194
+ npm run dev
195
+
196
+ # Build
197
+ npm run build
198
+
199
+ # Run login flow
200
+ npm run login
201
+ ```
202
+
203
+ ## License
204
+
205
+ MIT
@@ -0,0 +1,20 @@
1
+ import { ICachePlugin, TokenCacheContext } from '@azure/msal-node';
2
+ /**
3
+ * MSAL Cache Plugin that persists the full token cache (including refresh tokens)
4
+ * to a file. This ensures tokens survive server restarts.
5
+ */
6
+ export declare class FileCachePlugin implements ICachePlugin {
7
+ private cachePath;
8
+ constructor(cachePath: string);
9
+ /**
10
+ * Called before MSAL accesses the cache.
11
+ * Load the cache from disk into MSAL's memory.
12
+ */
13
+ beforeCacheAccess(cacheContext: TokenCacheContext): Promise<void>;
14
+ /**
15
+ * Called after MSAL accesses the cache.
16
+ * If the cache changed, persist it to disk.
17
+ */
18
+ afterCacheAccess(cacheContext: TokenCacheContext): Promise<void>;
19
+ }
20
+ //# sourceMappingURL=cache-plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache-plugin.d.ts","sourceRoot":"","sources":["../../src/auth/cache-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAInE;;;GAGG;AACH,qBAAa,eAAgB,YAAW,YAAY;IAClD,OAAO,CAAC,SAAS,CAAS;gBAEd,SAAS,EAAE,MAAM;IAI7B;;;OAGG;IACG,iBAAiB,CAAC,YAAY,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAavE;;;OAGG;IACG,gBAAgB,CAAC,YAAY,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;CAcvE"}
@@ -0,0 +1,49 @@
1
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
2
+ import { dirname } from 'path';
3
+ /**
4
+ * MSAL Cache Plugin that persists the full token cache (including refresh tokens)
5
+ * to a file. This ensures tokens survive server restarts.
6
+ */
7
+ export class FileCachePlugin {
8
+ cachePath;
9
+ constructor(cachePath) {
10
+ this.cachePath = cachePath;
11
+ }
12
+ /**
13
+ * Called before MSAL accesses the cache.
14
+ * Load the cache from disk into MSAL's memory.
15
+ */
16
+ async beforeCacheAccess(cacheContext) {
17
+ try {
18
+ if (existsSync(this.cachePath)) {
19
+ const cacheData = readFileSync(this.cachePath, 'utf-8');
20
+ if (cacheData && cacheData.trim()) {
21
+ cacheContext.tokenCache.deserialize(cacheData);
22
+ }
23
+ }
24
+ }
25
+ catch (error) {
26
+ console.error('[Cache] Failed to load cache:', error instanceof Error ? error.message : error);
27
+ }
28
+ }
29
+ /**
30
+ * Called after MSAL accesses the cache.
31
+ * If the cache changed, persist it to disk.
32
+ */
33
+ async afterCacheAccess(cacheContext) {
34
+ if (cacheContext.cacheHasChanged) {
35
+ try {
36
+ const dir = dirname(this.cachePath);
37
+ if (!existsSync(dir)) {
38
+ mkdirSync(dir, { recursive: true });
39
+ }
40
+ const serialized = cacheContext.tokenCache.serialize();
41
+ writeFileSync(this.cachePath, serialized, { mode: 0o600 });
42
+ }
43
+ catch (error) {
44
+ console.error('[Cache] Failed to save cache:', error instanceof Error ? error.message : error);
45
+ }
46
+ }
47
+ }
48
+ }
49
+ //# sourceMappingURL=cache-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache-plugin.js","sourceRoot":"","sources":["../../src/auth/cache-plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B;;;GAGG;AACH,MAAM,OAAO,eAAe;IAClB,SAAS,CAAS;IAE1B,YAAY,SAAiB;QAC3B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,iBAAiB,CAAC,YAA+B;QACrD,IAAI,CAAC;YACH,IAAI,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC/B,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;gBACxD,IAAI,SAAS,IAAI,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;oBAClC,YAAY,CAAC,UAAU,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;gBACjD,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACjG,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,gBAAgB,CAAC,YAA+B;QACpD,IAAI,YAAY,CAAC,eAAe,EAAE,CAAC;YACjC,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBACpC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBACtC,CAAC;gBACD,MAAM,UAAU,GAAG,YAAY,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC;gBACvD,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YAC7D,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACjG,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,22 @@
1
+ export interface TokenCache {
2
+ accessToken: string;
3
+ refreshToken: string;
4
+ expiresAt: number;
5
+ account?: {
6
+ homeAccountId: string;
7
+ environment: string;
8
+ tenantId: string;
9
+ username: string;
10
+ };
11
+ }
12
+ export interface AuthConfig {
13
+ clientId: string;
14
+ tenantId: string;
15
+ scopes: string[];
16
+ }
17
+ export declare const DEFAULT_CONFIG: AuthConfig;
18
+ export declare const MSAL_CACHE_FILE: string;
19
+ export declare function getTokenCache(): TokenCache | null;
20
+ export declare function saveTokenCache(cache: TokenCache): void;
21
+ export declare function clearTokenCache(): void;
22
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/auth/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE;QACR,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAID,eAAO,MAAM,cAAc,EAAE,UA0B5B,CAAC;AAGF,eAAO,MAAM,eAAe,QAAgE,CAAC;AAE7F,wBAAgB,aAAa,IAAI,UAAU,GAAG,IAAI,CAUjD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAMtD;AAED,wBAAgB,eAAe,IAAI,IAAI,CAQtC"}
@@ -0,0 +1,64 @@
1
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
2
+ import { homedir } from 'os';
3
+ import { join, dirname } from 'path';
4
+ // Default Azure AD app for personal M365 access
5
+ // Users can override with their own app registration
6
+ export const DEFAULT_CONFIG = {
7
+ clientId: process.env.M365_CLIENT_ID || '',
8
+ tenantId: process.env.M365_TENANT_ID || 'common',
9
+ scopes: [
10
+ 'https://graph.microsoft.com/Mail.ReadWrite',
11
+ 'https://graph.microsoft.com/Mail.Send',
12
+ 'https://graph.microsoft.com/Calendars.ReadWrite',
13
+ 'https://graph.microsoft.com/Tasks.ReadWrite',
14
+ 'https://graph.microsoft.com/Files.ReadWrite',
15
+ 'https://graph.microsoft.com/Sites.Read.All',
16
+ 'https://graph.microsoft.com/Contacts.ReadWrite',
17
+ 'https://graph.microsoft.com/User.Read',
18
+ // Teams
19
+ 'https://graph.microsoft.com/Team.ReadBasic.All',
20
+ 'https://graph.microsoft.com/Channel.ReadBasic.All',
21
+ 'https://graph.microsoft.com/ChannelMessage.Read.All',
22
+ 'https://graph.microsoft.com/ChannelMessage.Send',
23
+ // Chats
24
+ 'https://graph.microsoft.com/Chat.Create',
25
+ 'https://graph.microsoft.com/Chat.ReadBasic',
26
+ 'https://graph.microsoft.com/Chat.Read',
27
+ 'https://graph.microsoft.com/ChatMessage.Send',
28
+ // Planner
29
+ 'https://graph.microsoft.com/Group.Read.All',
30
+ 'offline_access',
31
+ ],
32
+ };
33
+ const TOKEN_FILE = join(homedir(), '.config', 'myoffice-mcp', 'token.json');
34
+ export const MSAL_CACHE_FILE = join(homedir(), '.config', 'myoffice-mcp', 'msal-cache.json');
35
+ export function getTokenCache() {
36
+ try {
37
+ if (existsSync(TOKEN_FILE)) {
38
+ const data = readFileSync(TOKEN_FILE, 'utf-8');
39
+ return JSON.parse(data);
40
+ }
41
+ }
42
+ catch {
43
+ // Ignore errors, return null
44
+ }
45
+ return null;
46
+ }
47
+ export function saveTokenCache(cache) {
48
+ const dir = dirname(TOKEN_FILE);
49
+ if (!existsSync(dir)) {
50
+ mkdirSync(dir, { recursive: true });
51
+ }
52
+ writeFileSync(TOKEN_FILE, JSON.stringify(cache, null, 2), { mode: 0o600 });
53
+ }
54
+ export function clearTokenCache() {
55
+ try {
56
+ if (existsSync(TOKEN_FILE)) {
57
+ writeFileSync(TOKEN_FILE, '', { mode: 0o600 });
58
+ }
59
+ }
60
+ catch {
61
+ // Ignore errors
62
+ }
63
+ }
64
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/auth/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAoBrC,gDAAgD;AAChD,qDAAqD;AACrD,MAAM,CAAC,MAAM,cAAc,GAAe;IACxC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE;IAC1C,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,QAAQ;IAChD,MAAM,EAAE;QACN,4CAA4C;QAC5C,uCAAuC;QACvC,iDAAiD;QACjD,6CAA6C;QAC7C,6CAA6C;QAC7C,4CAA4C;QAC5C,gDAAgD;QAChD,uCAAuC;QACvC,QAAQ;QACR,gDAAgD;QAChD,mDAAmD;QACnD,qDAAqD;QACrD,iDAAiD;QACjD,QAAQ;QACR,yCAAyC;QACzC,4CAA4C;QAC5C,uCAAuC;QACvC,8CAA8C;QAC9C,UAAU;QACV,4CAA4C;QAC5C,gBAAgB;KACjB;CACF,CAAC;AAEF,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;AAC5E,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE,iBAAiB,CAAC,CAAC;AAE7F,MAAM,UAAU,aAAa;IAC3B,IAAI,CAAC;QACH,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAC/C,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,6BAA6B;IAC/B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAiB;IAC9C,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAChC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,CAAC;IACD,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAC7E,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC;QACH,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3B,aAAa,CAAC,UAAU,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,gBAAgB;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function authenticateWithDeviceCode(): Promise<void>;
2
+ //# sourceMappingURL=device-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-code.d.ts","sourceRoot":"","sources":["../../src/auth/device-code.ts"],"names":[],"mappings":"AAMA,wBAAsB,0BAA0B,IAAI,OAAO,CAAC,IAAI,CAAC,CAuChE"}
@@ -0,0 +1,38 @@
1
+ import { PublicClientApplication } from '@azure/msal-node';
2
+ import { DEFAULT_CONFIG, MSAL_CACHE_FILE } from './config.js';
3
+ import { FileCachePlugin } from './cache-plugin.js';
4
+ const cachePlugin = new FileCachePlugin(MSAL_CACHE_FILE);
5
+ export async function authenticateWithDeviceCode() {
6
+ if (!DEFAULT_CONFIG.clientId) {
7
+ throw new Error('M365_CLIENT_ID environment variable is required.\n' +
8
+ 'Create an Azure AD app registration with delegated permissions and set M365_CLIENT_ID.');
9
+ }
10
+ const pca = new PublicClientApplication({
11
+ auth: {
12
+ clientId: DEFAULT_CONFIG.clientId,
13
+ authority: `https://login.microsoftonline.com/${DEFAULT_CONFIG.tenantId}`,
14
+ },
15
+ cache: {
16
+ cachePlugin,
17
+ },
18
+ });
19
+ const deviceCodeRequest = {
20
+ scopes: DEFAULT_CONFIG.scopes,
21
+ deviceCodeCallback: (response) => {
22
+ console.log('\n' + '='.repeat(60));
23
+ console.log('AUTHENTICATION REQUIRED');
24
+ console.log('='.repeat(60));
25
+ console.log(`\n${response.message}\n`);
26
+ console.log('='.repeat(60) + '\n');
27
+ },
28
+ };
29
+ const result = await pca.acquireTokenByDeviceCode(deviceCodeRequest);
30
+ if (!result || !result.accessToken) {
31
+ throw new Error('Failed to acquire access token');
32
+ }
33
+ // The cache plugin automatically persists the tokens via afterCacheAccess
34
+ console.log(`\nAuthenticated as: ${result.account?.username}`);
35
+ console.log('Token cached at:', MSAL_CACHE_FILE);
36
+ console.log('Refresh token is now properly persisted.\n');
37
+ }
38
+ //# sourceMappingURL=device-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-code.js","sourceRoot":"","sources":["../../src/auth/device-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAqB,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,WAAW,GAAG,IAAI,eAAe,CAAC,eAAe,CAAC,CAAC;AAEzD,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,oDAAoD;YACpD,wFAAwF,CACzF,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,uBAAuB,CAAC;QACtC,IAAI,EAAE;YACJ,QAAQ,EAAE,cAAc,CAAC,QAAQ;YACjC,SAAS,EAAE,qCAAqC,cAAc,CAAC,QAAQ,EAAE;SAC1E;QACD,KAAK,EAAE;YACL,WAAW;SACZ;KACF,CAAC,CAAC;IAEH,MAAM,iBAAiB,GAAsB;QAC3C,MAAM,EAAE,cAAc,CAAC,MAAM;QAC7B,kBAAkB,EAAE,CAAC,QAAQ,EAAE,EAAE;YAC/B,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;YACnC,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;YACvC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;YACvC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QACrC,CAAC;KACF,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,wBAAwB,CAAC,iBAAiB,CAAC,CAAC;IAErE,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IAED,0EAA0E;IAC1E,OAAO,CAAC,GAAG,CAAC,uBAAuB,MAAM,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC/D,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,eAAe,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { getAccessToken, isAuthenticated, getCurrentUser } from './token-manager.js';
2
+ export { authenticateWithDeviceCode } from './device-code.js';
3
+ export { DEFAULT_CONFIG, clearTokenCache } from './config.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACrF,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { getAccessToken, isAuthenticated, getCurrentUser } from './token-manager.js';
2
+ export { authenticateWithDeviceCode } from './device-code.js';
3
+ export { DEFAULT_CONFIG, clearTokenCache } from './config.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACrF,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Standalone login script for initial authentication
4
+ * Run with: npm run login
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=login.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/auth/login.ts"],"names":[],"mappings":";AACA;;;GAGG"}
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Standalone login script for initial authentication
4
+ * Run with: npm run login
5
+ */
6
+ import { authenticateWithDeviceCode } from './device-code.js';
7
+ async function main() {
8
+ console.log('Personal M365 MCP - Authentication');
9
+ console.log('===================================\n');
10
+ try {
11
+ await authenticateWithDeviceCode();
12
+ console.log('Authentication successful!');
13
+ console.log('You can now use the M365 MCP with Claude Code.');
14
+ process.exit(0);
15
+ }
16
+ catch (error) {
17
+ console.error('Authentication failed:', error);
18
+ process.exit(1);
19
+ }
20
+ }
21
+ main();
22
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/auth/login.ts"],"names":[],"mappings":";AACA;;;GAGG;AAEH,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAE9D,KAAK,UAAU,IAAI;IACjB,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;IAErD,IAAI,CAAC;QACH,MAAM,0BAA0B,EAAE,CAAC;QACnC,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;QAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAC;QAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function getAccessToken(): Promise<string>;
2
+ export declare function isAuthenticated(): Promise<boolean>;
3
+ export declare function getCurrentUser(): Promise<string | null>;
4
+ //# sourceMappingURL=token-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-manager.d.ts","sourceRoot":"","sources":["../../src/auth/token-manager.ts"],"names":[],"mappings":"AA0BA,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CA4CtD;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,CAQxD;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAQ7D"}
@@ -0,0 +1,78 @@
1
+ import { PublicClientApplication } from '@azure/msal-node';
2
+ import { DEFAULT_CONFIG, MSAL_CACHE_FILE, getTokenCache } from './config.js';
3
+ import { FileCachePlugin } from './cache-plugin.js';
4
+ let msalInstance = null;
5
+ const cachePlugin = new FileCachePlugin(MSAL_CACHE_FILE);
6
+ function getMsalInstance() {
7
+ if (!msalInstance) {
8
+ if (!DEFAULT_CONFIG.clientId) {
9
+ throw new Error('M365_CLIENT_ID environment variable is required');
10
+ }
11
+ msalInstance = new PublicClientApplication({
12
+ auth: {
13
+ clientId: DEFAULT_CONFIG.clientId,
14
+ authority: `https://login.microsoftonline.com/${DEFAULT_CONFIG.tenantId}`,
15
+ },
16
+ cache: {
17
+ cachePlugin,
18
+ },
19
+ });
20
+ }
21
+ return msalInstance;
22
+ }
23
+ export async function getAccessToken() {
24
+ const pca = getMsalInstance();
25
+ // Get accounts from MSAL's persisted cache
26
+ const accounts = await pca.getTokenCache().getAllAccounts();
27
+ if (accounts.length === 0) {
28
+ // No accounts in MSAL cache - check legacy token.json for migration hint
29
+ const legacyCache = getTokenCache();
30
+ if (legacyCache?.account) {
31
+ console.error('[Auth] Found legacy token.json but no MSAL cache.');
32
+ console.error('[Auth] Please re-authenticate to migrate to new cache format.');
33
+ }
34
+ throw new Error('Not authenticated. Please run "npm run login" in the myoffice-mcp directory.');
35
+ }
36
+ // Use the first account (typically there's only one for personal use)
37
+ const account = accounts[0];
38
+ // Try silent token acquisition (MSAL handles refresh automatically)
39
+ console.error('[Auth] Acquiring token silently...');
40
+ try {
41
+ const silentRequest = {
42
+ scopes: DEFAULT_CONFIG.scopes,
43
+ account: account,
44
+ };
45
+ const result = await pca.acquireTokenSilent(silentRequest);
46
+ console.error('[Auth] Token acquired successfully');
47
+ return result.accessToken;
48
+ }
49
+ catch (error) {
50
+ // Silent refresh failed - log the actual error
51
+ const errorMessage = error instanceof Error ? error.message : String(error);
52
+ console.error('[Auth] Silent token acquisition FAILED:', errorMessage);
53
+ console.error('[Auth] Please re-authenticate by running: npm run login');
54
+ throw new Error(`Token acquisition failed: ${errorMessage}. ` +
55
+ `Please re-authenticate by running 'npm run login' in the myoffice-mcp directory.`);
56
+ }
57
+ }
58
+ export async function isAuthenticated() {
59
+ try {
60
+ const pca = getMsalInstance();
61
+ const accounts = await pca.getTokenCache().getAllAccounts();
62
+ return accounts.length > 0;
63
+ }
64
+ catch {
65
+ return false;
66
+ }
67
+ }
68
+ export async function getCurrentUser() {
69
+ try {
70
+ const pca = getMsalInstance();
71
+ const accounts = await pca.getTokenCache().getAllAccounts();
72
+ return accounts[0]?.username || null;
73
+ }
74
+ catch {
75
+ return null;
76
+ }
77
+ }
78
+ //# sourceMappingURL=token-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-manager.js","sourceRoot":"","sources":["../../src/auth/token-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAwD,MAAM,kBAAkB,CAAC;AACjH,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,IAAI,YAAY,GAAmC,IAAI,CAAC;AACxD,MAAM,WAAW,GAAG,IAAI,eAAe,CAAC,eAAe,CAAC,CAAC;AAEzD,SAAS,eAAe;IACtB,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACrE,CAAC;QAED,YAAY,GAAG,IAAI,uBAAuB,CAAC;YACzC,IAAI,EAAE;gBACJ,QAAQ,EAAE,cAAc,CAAC,QAAQ;gBACjC,SAAS,EAAE,qCAAqC,cAAc,CAAC,QAAQ,EAAE;aAC1E;YACD,KAAK,EAAE;gBACL,WAAW;aACZ;SACF,CAAC,CAAC;IACL,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAE9B,2CAA2C;IAC3C,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,aAAa,EAAE,CAAC,cAAc,EAAE,CAAC;IAE5D,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,yEAAyE;QACzE,MAAM,WAAW,GAAG,aAAa,EAAE,CAAC;QACpC,IAAI,WAAW,EAAE,OAAO,EAAE,CAAC;YACzB,OAAO,CAAC,KAAK,CAAC,mDAAmD,CAAC,CAAC;YACnE,OAAO,CAAC,KAAK,CAAC,+DAA+D,CAAC,CAAC;QACjF,CAAC;QACD,MAAM,IAAI,KAAK,CACb,8EAA8E,CAC/E,CAAC;IACJ,CAAC;IAED,sEAAsE;IACtE,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAE5B,oEAAoE;IACpE,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACpD,IAAI,CAAC;QACH,MAAM,aAAa,GAAsB;YACvC,MAAM,EAAE,cAAc,CAAC,MAAM;YAC7B,OAAO,EAAE,OAAO;SACjB,CAAC;QAEF,MAAM,MAAM,GAAyB,MAAM,GAAG,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC;QAEjF,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACpD,OAAO,MAAM,CAAC,WAAW,CAAC;IAC5B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,+CAA+C;QAC/C,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5E,OAAO,CAAC,KAAK,CAAC,yCAAyC,EAAE,YAAY,CAAC,CAAC;QACvE,OAAO,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;QAEzE,MAAM,IAAI,KAAK,CACb,6BAA6B,YAAY,IAAI;YAC7C,kFAAkF,CACnF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,aAAa,EAAE,CAAC,cAAc,EAAE,CAAC;QAC5D,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,aAAa,EAAE,CAAC,cAAc,EAAE,CAAC;QAC5D,OAAO,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,IAAI,IAAI,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Output formatter for CLI - provides human-readable output
3
+ */
4
+ export declare function formatOutput(data: unknown, toolName?: string): string;
5
+ //# sourceMappingURL=formatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../src/cli/formatter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAoWH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAsErE"}