@einlogic/mcp-fabric-api 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +241 -0
- package/build/auth/oauth-handler.d.ts +14 -0
- package/build/auth/oauth-handler.d.ts.map +1 -0
- package/build/auth/oauth-handler.js +32 -0
- package/build/auth/oauth-handler.js.map +1 -0
- package/build/auth/token-manager.d.ts +15 -0
- package/build/auth/token-manager.d.ts.map +1 -0
- package/build/auth/token-manager.js +61 -0
- package/build/auth/token-manager.js.map +1 -0
- package/build/client/fabric-client.d.ts +24 -0
- package/build/client/fabric-client.d.ts.map +1 -0
- package/build/client/fabric-client.js +91 -0
- package/build/client/fabric-client.js.map +1 -0
- package/build/client/powerbi-client.d.ts +15 -0
- package/build/client/powerbi-client.d.ts.map +1 -0
- package/build/client/powerbi-client.js +62 -0
- package/build/client/powerbi-client.js.map +1 -0
- package/build/core/errors.d.ts +14 -0
- package/build/core/errors.d.ts.map +1 -0
- package/build/core/errors.js +33 -0
- package/build/core/errors.js.map +1 -0
- package/build/core/job-scheduler.d.ts +7 -0
- package/build/core/job-scheduler.d.ts.map +1 -0
- package/build/core/job-scheduler.js +20 -0
- package/build/core/job-scheduler.js.map +1 -0
- package/build/core/lro.d.ts +9 -0
- package/build/core/lro.d.ts.map +1 -0
- package/build/core/lro.js +35 -0
- package/build/core/lro.js.map +1 -0
- package/build/core/pagination.d.ts +3 -0
- package/build/core/pagination.d.ts.map +1 -0
- package/build/core/pagination.js +27 -0
- package/build/core/pagination.js.map +1 -0
- package/build/core/types.d.ts +86 -0
- package/build/core/types.d.ts.map +1 -0
- package/build/core/types.js +2 -0
- package/build/core/types.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +85 -0
- package/build/index.js.map +1 -0
- package/build/server.d.ts +7 -0
- package/build/server.d.ts.map +1 -0
- package/build/server.js +42 -0
- package/build/server.js.map +1 -0
- package/build/tools/auth.d.ts +4 -0
- package/build/tools/auth.d.ts.map +1 -0
- package/build/tools/auth.js +119 -0
- package/build/tools/auth.js.map +1 -0
- package/build/tools/dataflow.d.ts +4 -0
- package/build/tools/dataflow.d.ts.map +1 -0
- package/build/tools/dataflow.js +100 -0
- package/build/tools/dataflow.js.map +1 -0
- package/build/tools/eventhouse.d.ts +4 -0
- package/build/tools/eventhouse.d.ts.map +1 -0
- package/build/tools/eventhouse.js +80 -0
- package/build/tools/eventhouse.js.map +1 -0
- package/build/tools/eventstream.d.ts +4 -0
- package/build/tools/eventstream.d.ts.map +1 -0
- package/build/tools/eventstream.js +135 -0
- package/build/tools/eventstream.js.map +1 -0
- package/build/tools/graphql-api.d.ts +5 -0
- package/build/tools/graphql-api.d.ts.map +1 -0
- package/build/tools/graphql-api.js +124 -0
- package/build/tools/graphql-api.js.map +1 -0
- package/build/tools/lakehouse.d.ts +4 -0
- package/build/tools/lakehouse.d.ts.map +1 -0
- package/build/tools/lakehouse.js +138 -0
- package/build/tools/lakehouse.js.map +1 -0
- package/build/tools/notebook.d.ts +4 -0
- package/build/tools/notebook.d.ts.map +1 -0
- package/build/tools/notebook.js +186 -0
- package/build/tools/notebook.js.map +1 -0
- package/build/tools/pipeline.d.ts +4 -0
- package/build/tools/pipeline.d.ts.map +1 -0
- package/build/tools/pipeline.js +214 -0
- package/build/tools/pipeline.js.map +1 -0
- package/build/tools/reflex.d.ts +4 -0
- package/build/tools/reflex.d.ts.map +1 -0
- package/build/tools/reflex.js +101 -0
- package/build/tools/reflex.js.map +1 -0
- package/build/tools/report.d.ts +5 -0
- package/build/tools/report.d.ts.map +1 -0
- package/build/tools/report.js +191 -0
- package/build/tools/report.js.map +1 -0
- package/build/tools/semantic-model.d.ts +5 -0
- package/build/tools/semantic-model.d.ts.map +1 -0
- package/build/tools/semantic-model.js +225 -0
- package/build/tools/semantic-model.js.map +1 -0
- package/build/tools/sql-endpoint.d.ts +4 -0
- package/build/tools/sql-endpoint.d.ts.map +1 -0
- package/build/tools/sql-endpoint.js +44 -0
- package/build/tools/sql-endpoint.js.map +1 -0
- package/build/tools/workspace.d.ts +4 -0
- package/build/tools/workspace.d.ts.map +1 -0
- package/build/tools/workspace.js +84 -0
- package/build/tools/workspace.js.map +1 -0
- package/build/utils/base64.d.ts +3 -0
- package/build/utils/base64.d.ts.map +1 -0
- package/build/utils/base64.js +7 -0
- package/build/utils/base64.js.map +1 -0
- package/build/utils/tmdl.d.ts +13 -0
- package/build/utils/tmdl.d.ts.map +1 -0
- package/build/utils/tmdl.js +21 -0
- package/build/utils/tmdl.js.map +1 -0
- package/package.json +35 -0
package/README.md
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# mcp-fabric-api
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server for the Microsoft Fabric REST APIs. Built for data engineers and data analysts who want to use AI assistants beyond Copilot — such as Claude, Claude Code, or any MCP-compatible client — to build and manage their Fabric components. Covers lakehouses, notebooks, pipelines, semantic models, reports, dataflows, eventhouses, and more.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Node.js 18+
|
|
8
|
+
- Azure CLI (`az login` for authentication)
|
|
9
|
+
- Access to a Microsoft Fabric workspace
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
Authenticate with Azure CLI:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
az login
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Run directly with npx (no install needed):
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx @einlogic/mcp-fabric-api
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Setup
|
|
26
|
+
|
|
27
|
+
### Claude Desktop
|
|
28
|
+
|
|
29
|
+
Add to your Claude Desktop config file:
|
|
30
|
+
|
|
31
|
+
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
32
|
+
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"mcpServers": {
|
|
37
|
+
"fabric": {
|
|
38
|
+
"command": "npx",
|
|
39
|
+
"args": ["-y", "@einlogic/mcp-fabric-api"]
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Claude Code CLI
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
claude mcp add fabric -- npx -y @einlogic/mcp-fabric-api
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
To verify it was added:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
claude mcp list
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### HTTP Mode (Remote)
|
|
58
|
+
|
|
59
|
+
For remote deployments, set environment variables:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
export TRANSPORT=http
|
|
63
|
+
export PORT=3000
|
|
64
|
+
export AZURE_CLIENT_ID=your-client-id
|
|
65
|
+
export AZURE_CLIENT_SECRET=your-client-secret
|
|
66
|
+
export AZURE_TENANT_ID=your-tenant-id
|
|
67
|
+
npx @einlogic/mcp-fabric-api
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The server exposes:
|
|
71
|
+
- `POST /mcp` — MCP endpoint (StreamableHTTP)
|
|
72
|
+
- `GET /mcp` — SSE stream for server notifications
|
|
73
|
+
- `DELETE /mcp` — Session cleanup
|
|
74
|
+
- `GET /.well-known/oauth-protected-resource` — OAuth metadata
|
|
75
|
+
|
|
76
|
+
## Development
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
git clone https://github.com/your-org/mcp-fabric-api.git
|
|
80
|
+
cd mcp-fabric-api
|
|
81
|
+
npm install
|
|
82
|
+
npm run build
|
|
83
|
+
npm start
|
|
84
|
+
npm run dev # Watch mode
|
|
85
|
+
npm run inspect # Launch MCP Inspector
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Tools
|
|
89
|
+
|
|
90
|
+
### Auth (4 tools)
|
|
91
|
+
| Tool | Description |
|
|
92
|
+
|------|-------------|
|
|
93
|
+
| `auth_get_current_account` | Show current Azure identity, tenant, and token expiry |
|
|
94
|
+
| `auth_list_available_accounts` | List subscriptions/tenants from local `az login` state (does not query Entra) |
|
|
95
|
+
| `auth_switch_tenant` | Switch to a different Azure tenant (with rollback on failure) |
|
|
96
|
+
| `auth_clear_token_cache` | Clear cached tokens to force re-acquisition |
|
|
97
|
+
|
|
98
|
+
### Workspace (6 tools)
|
|
99
|
+
| Tool | Description |
|
|
100
|
+
|------|-------------|
|
|
101
|
+
| `workspace_list` | List all accessible Fabric workspaces |
|
|
102
|
+
| `workspace_get` | Get details of a specific workspace |
|
|
103
|
+
| `workspace_create` | Create a new workspace |
|
|
104
|
+
| `workspace_update` | Update a workspace's name or description |
|
|
105
|
+
| `workspace_delete` | Delete a workspace |
|
|
106
|
+
| `workspace_list_items` | List all items in a workspace (with optional type filter) |
|
|
107
|
+
|
|
108
|
+
### Lakehouse (8 tools)
|
|
109
|
+
| Tool | Description |
|
|
110
|
+
|------|-------------|
|
|
111
|
+
| `lakehouse_list` | List all lakehouses in a workspace |
|
|
112
|
+
| `lakehouse_get` | Get lakehouse details (SQL endpoint, OneLake paths) |
|
|
113
|
+
| `lakehouse_create` | Create a new lakehouse (LRO) |
|
|
114
|
+
| `lakehouse_update` | Update lakehouse name or description |
|
|
115
|
+
| `lakehouse_delete` | Delete a lakehouse |
|
|
116
|
+
| `lakehouse_list_tables` | List all tables in a lakehouse |
|
|
117
|
+
| `lakehouse_load_table` | Load data into a table from OneLake (LRO) |
|
|
118
|
+
| `lakehouse_get_sql_endpoint` | Get SQL endpoint details |
|
|
119
|
+
|
|
120
|
+
### Notebook (10 tools)
|
|
121
|
+
| Tool | Description |
|
|
122
|
+
|------|-------------|
|
|
123
|
+
| `notebook_list` | List all notebooks in a workspace |
|
|
124
|
+
| `notebook_get` | Get notebook details |
|
|
125
|
+
| `notebook_create` | Create a new notebook (LRO) |
|
|
126
|
+
| `notebook_update` | Update notebook name or description |
|
|
127
|
+
| `notebook_delete` | Delete a notebook |
|
|
128
|
+
| `notebook_get_definition` | Get notebook content (decoded from base64) |
|
|
129
|
+
| `notebook_update_definition` | Update notebook content |
|
|
130
|
+
| `notebook_run` | Run a notebook on demand |
|
|
131
|
+
| `notebook_get_run_status` | Get notebook run status |
|
|
132
|
+
| `notebook_cancel_run` | Cancel a running notebook |
|
|
133
|
+
|
|
134
|
+
### Pipeline (13 tools)
|
|
135
|
+
| Tool | Description |
|
|
136
|
+
|------|-------------|
|
|
137
|
+
| `pipeline_list` | List all data pipelines |
|
|
138
|
+
| `pipeline_get` | Get pipeline details |
|
|
139
|
+
| `pipeline_create` | Create a new pipeline |
|
|
140
|
+
| `pipeline_update` | Update pipeline name or description |
|
|
141
|
+
| `pipeline_delete` | Delete a pipeline |
|
|
142
|
+
| `pipeline_run` | Run a pipeline on demand |
|
|
143
|
+
| `pipeline_get_run_status` | Get pipeline run status |
|
|
144
|
+
| `pipeline_cancel_run` | Cancel a running pipeline |
|
|
145
|
+
| `pipeline_list_runs` | List all run instances |
|
|
146
|
+
| `pipeline_list_schedules` | List pipeline schedules |
|
|
147
|
+
| `pipeline_create_schedule` | Create a pipeline schedule |
|
|
148
|
+
| `pipeline_update_schedule` | Update a pipeline schedule |
|
|
149
|
+
| `pipeline_delete_schedule` | Delete a pipeline schedule |
|
|
150
|
+
|
|
151
|
+
### Semantic Model (11 tools)
|
|
152
|
+
| Tool | Description |
|
|
153
|
+
|------|-------------|
|
|
154
|
+
| `semantic_model_list` | List all semantic models |
|
|
155
|
+
| `semantic_model_get` | Get semantic model details |
|
|
156
|
+
| `semantic_model_create` | Create a new semantic model (LRO) |
|
|
157
|
+
| `semantic_model_update` | Update semantic model name or description |
|
|
158
|
+
| `semantic_model_delete` | Delete a semantic model |
|
|
159
|
+
| `semantic_model_refresh` | Trigger a model refresh (Power BI API) |
|
|
160
|
+
| `semantic_model_execute_dax` | Execute a DAX query (Power BI API) |
|
|
161
|
+
| `semantic_model_get_definition` | Get model definition in TMSL/BIM JSON format (LRO) |
|
|
162
|
+
| `semantic_model_get_tmdl` | Get model definition in TMDL format (LRO) |
|
|
163
|
+
| `semantic_model_update_definition` | Update model definition from TMSL/BIM JSON (LRO) |
|
|
164
|
+
| `semantic_model_update_tmdl` | Update model definition from TMDL files (LRO) |
|
|
165
|
+
|
|
166
|
+
### Report (10 tools)
|
|
167
|
+
| Tool | Description |
|
|
168
|
+
|------|-------------|
|
|
169
|
+
| `report_list` | List all reports |
|
|
170
|
+
| `report_get` | Get report details |
|
|
171
|
+
| `report_create` | Create a new report (LRO) |
|
|
172
|
+
| `report_update` | Update report name or description |
|
|
173
|
+
| `report_delete` | Delete a report |
|
|
174
|
+
| `report_clone` | Clone a report (Power BI API) |
|
|
175
|
+
| `report_export` | Export report to file format (Power BI API) |
|
|
176
|
+
| `report_get_export_status` | Check report export status |
|
|
177
|
+
| `report_get_definition` | Get report definition in PBIR or PBIR-Legacy format (LRO) |
|
|
178
|
+
| `report_update_definition` | Update report definition from parts (LRO) |
|
|
179
|
+
|
|
180
|
+
### Dataflow Gen2 (7 tools)
|
|
181
|
+
| Tool | Description |
|
|
182
|
+
|------|-------------|
|
|
183
|
+
| `dataflow_list` | List all Dataflow Gen2 items |
|
|
184
|
+
| `dataflow_get` | Get dataflow details |
|
|
185
|
+
| `dataflow_create` | Create a new dataflow |
|
|
186
|
+
| `dataflow_update` | Update dataflow name or description |
|
|
187
|
+
| `dataflow_delete` | Delete a dataflow |
|
|
188
|
+
| `dataflow_refresh` | Trigger a dataflow refresh |
|
|
189
|
+
| `dataflow_get_refresh_status` | Get refresh job status |
|
|
190
|
+
|
|
191
|
+
### Eventhouse (5 tools)
|
|
192
|
+
| Tool | Description |
|
|
193
|
+
|------|-------------|
|
|
194
|
+
| `eventhouse_list` | List all eventhouses |
|
|
195
|
+
| `eventhouse_get` | Get eventhouse details |
|
|
196
|
+
| `eventhouse_create` | Create a new eventhouse (LRO) |
|
|
197
|
+
| `eventhouse_update` | Update eventhouse name or description |
|
|
198
|
+
| `eventhouse_delete` | Delete an eventhouse |
|
|
199
|
+
|
|
200
|
+
### Eventstream (7 tools)
|
|
201
|
+
| Tool | Description |
|
|
202
|
+
|------|-------------|
|
|
203
|
+
| `eventstream_list` | List all eventstreams |
|
|
204
|
+
| `eventstream_get` | Get eventstream details |
|
|
205
|
+
| `eventstream_create` | Create a new eventstream (LRO) |
|
|
206
|
+
| `eventstream_update` | Update eventstream name or description |
|
|
207
|
+
| `eventstream_delete` | Delete an eventstream |
|
|
208
|
+
| `eventstream_get_definition` | Get eventstream definition (decoded) |
|
|
209
|
+
| `eventstream_update_definition` | Update eventstream definition |
|
|
210
|
+
|
|
211
|
+
### Reflex / Activator (6 tools)
|
|
212
|
+
| Tool | Description |
|
|
213
|
+
|------|-------------|
|
|
214
|
+
| `reflex_list` | List all Reflex (Activator) items |
|
|
215
|
+
| `reflex_get` | Get reflex details |
|
|
216
|
+
| `reflex_create` | Create a new reflex |
|
|
217
|
+
| `reflex_update` | Update reflex name or description |
|
|
218
|
+
| `reflex_delete` | Delete a reflex |
|
|
219
|
+
| `reflex_get_definition` | Get reflex definition (decoded) |
|
|
220
|
+
|
|
221
|
+
### GraphQL API (7 tools)
|
|
222
|
+
| Tool | Description |
|
|
223
|
+
|------|-------------|
|
|
224
|
+
| `graphql_api_list` | List all GraphQL API items |
|
|
225
|
+
| `graphql_api_get` | Get GraphQL API details |
|
|
226
|
+
| `graphql_api_create` | Create a new GraphQL API |
|
|
227
|
+
| `graphql_api_update` | Update GraphQL API name or description |
|
|
228
|
+
| `graphql_api_delete` | Delete a GraphQL API |
|
|
229
|
+
| `graphql_api_get_definition` | Get GraphQL schema definition |
|
|
230
|
+
| `graphql_api_execute_query` | Execute a GraphQL query |
|
|
231
|
+
|
|
232
|
+
### SQL Endpoint (3 tools)
|
|
233
|
+
| Tool | Description |
|
|
234
|
+
|------|-------------|
|
|
235
|
+
| `sql_endpoint_list` | List all SQL endpoints |
|
|
236
|
+
| `sql_endpoint_get` | Get SQL endpoint details |
|
|
237
|
+
| `sql_endpoint_get_connection_string` | Get TDS connection string |
|
|
238
|
+
|
|
239
|
+
## License
|
|
240
|
+
|
|
241
|
+
AGPL-3.0
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type Request, type Response, type NextFunction } from "express";
|
|
2
|
+
export interface OAuthConfig {
|
|
3
|
+
clientId: string;
|
|
4
|
+
clientSecret: string;
|
|
5
|
+
tenantId: string;
|
|
6
|
+
}
|
|
7
|
+
export interface AuthenticatedRequest extends Request {
|
|
8
|
+
userToken?: string;
|
|
9
|
+
}
|
|
10
|
+
declare function getOAuthConfig(): OAuthConfig;
|
|
11
|
+
export declare function createOAuthMetadataHandler(config: OAuthConfig): (_req: Request, res: Response) => void;
|
|
12
|
+
export declare function createTokenValidationMiddleware(config: OAuthConfig): (req: AuthenticatedRequest, _res: Response, next: NextFunction) => Promise<void>;
|
|
13
|
+
export { getOAuthConfig };
|
|
14
|
+
//# sourceMappingURL=oauth-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-handler.d.ts","sourceRoot":"","sources":["../../src/auth/oauth-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AAEzE,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAqB,SAAQ,OAAO;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,iBAAS,cAAc,IAAI,WAAW,CAYrC;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,WAAW,IACpD,MAAM,OAAO,EAAE,KAAK,QAAQ,UAQrC;AAED,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,WAAW,IACnD,KAAK,oBAAoB,EAAE,MAAM,QAAQ,EAAE,MAAM,YAAY,mBAS5E;AAED,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
function getOAuthConfig() {
|
|
2
|
+
const clientId = process.env.AZURE_CLIENT_ID;
|
|
3
|
+
const clientSecret = process.env.AZURE_CLIENT_SECRET;
|
|
4
|
+
const tenantId = process.env.AZURE_TENANT_ID;
|
|
5
|
+
if (!clientId || !clientSecret || !tenantId) {
|
|
6
|
+
throw new Error("HTTP mode requires AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, and AZURE_TENANT_ID environment variables");
|
|
7
|
+
}
|
|
8
|
+
return { clientId, clientSecret, tenantId };
|
|
9
|
+
}
|
|
10
|
+
export function createOAuthMetadataHandler(config) {
|
|
11
|
+
return (_req, res) => {
|
|
12
|
+
res.json({
|
|
13
|
+
resource: process.env.AZURE_CLIENT_ID,
|
|
14
|
+
authorization_servers: [
|
|
15
|
+
`https://login.microsoftonline.com/${config.tenantId}/v2.0`
|
|
16
|
+
],
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function createTokenValidationMiddleware(config) {
|
|
21
|
+
return async (req, _res, next) => {
|
|
22
|
+
const authHeader = req.headers.authorization;
|
|
23
|
+
if (!authHeader?.startsWith("Bearer ")) {
|
|
24
|
+
next();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
req.userToken = authHeader.slice(7);
|
|
28
|
+
next();
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export { getOAuthConfig };
|
|
32
|
+
//# sourceMappingURL=oauth-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-handler.js","sourceRoot":"","sources":["../../src/auth/oauth-handler.ts"],"names":[],"mappings":"AAYA,SAAS,cAAc;IACrB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAC7C,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;IACrD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAE7C,IAAI,CAAC,QAAQ,IAAI,CAAC,YAAY,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CACb,oGAAoG,CACrG,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,MAAmB;IAC5D,OAAO,CAAC,IAAa,EAAE,GAAa,EAAE,EAAE;QACtC,GAAG,CAAC,IAAI,CAAC;YACP,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe;YACrC,qBAAqB,EAAE;gBACrB,qCAAqC,MAAM,CAAC,QAAQ,OAAO;aAC5D;SACF,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,+BAA+B,CAAC,MAAmB;IACjE,OAAO,KAAK,EAAE,GAAyB,EAAE,IAAc,EAAE,IAAkB,EAAE,EAAE;QAC7E,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC;QAC7C,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACvC,IAAI,EAAE,CAAC;YACP,OAAO;QACT,CAAC;QACD,GAAG,CAAC,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACpC,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type AccessToken } from "@azure/identity";
|
|
2
|
+
export declare class TokenManager {
|
|
3
|
+
private credential;
|
|
4
|
+
private cache;
|
|
5
|
+
private currentTenantId;
|
|
6
|
+
constructor(tenantId?: string);
|
|
7
|
+
switchTenant(tenantId?: string): void;
|
|
8
|
+
clearCache(): void;
|
|
9
|
+
getCurrentTenantId(): string | undefined;
|
|
10
|
+
getCachedToken(scope: "fabric" | "powerbi"): AccessToken | undefined;
|
|
11
|
+
getToken(scope: "fabric" | "powerbi"): Promise<string>;
|
|
12
|
+
getFabricToken(): Promise<string>;
|
|
13
|
+
getPowerBIToken(): Promise<string>;
|
|
14
|
+
}
|
|
15
|
+
//# 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":"AAAA,OAAO,EAA0B,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAM3E,qBAAa,YAAY;IACvB,OAAO,CAAC,UAAU,CAAyB;IAC3C,OAAO,CAAC,KAAK,CAAkC;IAC/C,OAAO,CAAC,eAAe,CAAqB;gBAEhC,QAAQ,CAAC,EAAE,MAAM;IAO7B,YAAY,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;IAQrC,UAAU,IAAI,IAAI;IAIlB,kBAAkB,IAAI,MAAM,GAAG,SAAS;IAIxC,cAAc,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS;IAK9D,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;IAwBtD,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAIjC,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC;CAGzC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { DefaultAzureCredential } from "@azure/identity";
|
|
2
|
+
const FABRIC_SCOPE = "https://api.fabric.microsoft.com/.default";
|
|
3
|
+
const POWERBI_SCOPE = "https://analysis.windows.net/powerbi/api/.default";
|
|
4
|
+
const REFRESH_BUFFER_MS = 5 * 60 * 1000; // 5 minutes
|
|
5
|
+
export class TokenManager {
|
|
6
|
+
credential;
|
|
7
|
+
cache = new Map();
|
|
8
|
+
currentTenantId;
|
|
9
|
+
constructor(tenantId) {
|
|
10
|
+
this.currentTenantId = tenantId;
|
|
11
|
+
this.credential = tenantId
|
|
12
|
+
? new DefaultAzureCredential({ tenantId })
|
|
13
|
+
: new DefaultAzureCredential();
|
|
14
|
+
}
|
|
15
|
+
switchTenant(tenantId) {
|
|
16
|
+
this.currentTenantId = tenantId;
|
|
17
|
+
this.credential = tenantId
|
|
18
|
+
? new DefaultAzureCredential({ tenantId })
|
|
19
|
+
: new DefaultAzureCredential();
|
|
20
|
+
this.cache.clear();
|
|
21
|
+
}
|
|
22
|
+
clearCache() {
|
|
23
|
+
this.cache.clear();
|
|
24
|
+
}
|
|
25
|
+
getCurrentTenantId() {
|
|
26
|
+
return this.currentTenantId;
|
|
27
|
+
}
|
|
28
|
+
getCachedToken(scope) {
|
|
29
|
+
const scopeUrl = scope === "fabric" ? FABRIC_SCOPE : POWERBI_SCOPE;
|
|
30
|
+
return this.cache.get(scopeUrl);
|
|
31
|
+
}
|
|
32
|
+
async getToken(scope) {
|
|
33
|
+
const scopeUrl = scope === "fabric" ? FABRIC_SCOPE : POWERBI_SCOPE;
|
|
34
|
+
const cached = this.cache.get(scopeUrl);
|
|
35
|
+
if (cached && cached.expiresOnTimestamp - Date.now() > REFRESH_BUFFER_MS) {
|
|
36
|
+
return cached.token;
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const token = await this.credential.getToken(scopeUrl);
|
|
40
|
+
if (!token) {
|
|
41
|
+
throw new Error(`Failed to acquire token for scope: ${scopeUrl}`);
|
|
42
|
+
}
|
|
43
|
+
this.cache.set(scopeUrl, token);
|
|
44
|
+
return token.token;
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
48
|
+
if (message.includes("az login") || message.includes("DefaultAzureCredential")) {
|
|
49
|
+
throw new Error(`Azure authentication failed. Run 'az login' first to authenticate.\nDetails: ${message}`);
|
|
50
|
+
}
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async getFabricToken() {
|
|
55
|
+
return this.getToken("fabric");
|
|
56
|
+
}
|
|
57
|
+
async getPowerBIToken() {
|
|
58
|
+
return this.getToken("powerbi");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=token-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-manager.js","sourceRoot":"","sources":["../../src/auth/token-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { TokenManager } from "../auth/token-manager.js";
|
|
2
|
+
export interface LroResult {
|
|
3
|
+
operationId: string;
|
|
4
|
+
location?: string;
|
|
5
|
+
retryAfter?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface FabricResponse<T = unknown> {
|
|
8
|
+
data: T;
|
|
9
|
+
lro?: LroResult;
|
|
10
|
+
status: number;
|
|
11
|
+
}
|
|
12
|
+
export declare class FabricClient {
|
|
13
|
+
private tokenManager;
|
|
14
|
+
constructor(tokenManager: TokenManager);
|
|
15
|
+
private getHeaders;
|
|
16
|
+
private extractLro;
|
|
17
|
+
private handleResponse;
|
|
18
|
+
get<T = unknown>(path: string): Promise<FabricResponse<T>>;
|
|
19
|
+
post<T = unknown>(path: string, body?: unknown): Promise<FabricResponse<T>>;
|
|
20
|
+
patch<T = unknown>(path: string, body: unknown): Promise<FabricResponse<T>>;
|
|
21
|
+
delete<T = unknown>(path: string): Promise<FabricResponse<T>>;
|
|
22
|
+
getFullUrl<T = unknown>(url: string): Promise<FabricResponse<T>>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=fabric-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fabric-client.d.ts","sourceRoot":"","sources":["../../src/client/fabric-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAKxD,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc,CAAC,CAAC,GAAG,OAAO;IACzC,IAAI,EAAE,CAAC,CAAC;IACR,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,YAAY;IACX,OAAO,CAAC,YAAY;gBAAZ,YAAY,EAAE,YAAY;YAEhC,UAAU;IAQxB,OAAO,CAAC,UAAU;YAcJ,cAAc;IAuCtB,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;IAM1D,IAAI,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;IAU3E,KAAK,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;IAU3E,MAAM,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;IAS7D,UAAU,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;CAKvE"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { FabricApiError } from "../core/errors.js";
|
|
2
|
+
const FABRIC_BASE_URL = "https://api.fabric.microsoft.com/v1";
|
|
3
|
+
export class FabricClient {
|
|
4
|
+
tokenManager;
|
|
5
|
+
constructor(tokenManager) {
|
|
6
|
+
this.tokenManager = tokenManager;
|
|
7
|
+
}
|
|
8
|
+
async getHeaders() {
|
|
9
|
+
const token = await this.tokenManager.getFabricToken();
|
|
10
|
+
return {
|
|
11
|
+
Authorization: `Bearer ${token}`,
|
|
12
|
+
"Content-Type": "application/json",
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
extractLro(response) {
|
|
16
|
+
if (response.status !== 202)
|
|
17
|
+
return undefined;
|
|
18
|
+
const operationId = response.headers.get("x-ms-operation-id") ??
|
|
19
|
+
response.headers.get("location")?.match(/operations\/([^/?]+)/)?.[1];
|
|
20
|
+
if (!operationId)
|
|
21
|
+
return undefined;
|
|
22
|
+
const retryAfter = response.headers.get("retry-after");
|
|
23
|
+
return {
|
|
24
|
+
operationId,
|
|
25
|
+
location: response.headers.get("location") ?? undefined,
|
|
26
|
+
retryAfter: retryAfter ? parseInt(retryAfter, 10) : undefined,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
async handleResponse(response) {
|
|
30
|
+
if (response.status === 429) {
|
|
31
|
+
const retryAfter = response.headers.get("retry-after");
|
|
32
|
+
const waitMs = retryAfter ? parseInt(retryAfter, 10) * 1000 : 30000;
|
|
33
|
+
throw new FabricApiError(`Rate limited. Retry after ${waitMs / 1000}s`, 429, "TooManyRequests");
|
|
34
|
+
}
|
|
35
|
+
const lro = this.extractLro(response);
|
|
36
|
+
if (response.status === 204 || response.headers.get("content-length") === "0") {
|
|
37
|
+
return { data: undefined, lro, status: response.status };
|
|
38
|
+
}
|
|
39
|
+
let body;
|
|
40
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
41
|
+
if (contentType.includes("application/json")) {
|
|
42
|
+
body = await response.json();
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
body = await response.text();
|
|
46
|
+
}
|
|
47
|
+
if (!response.ok && response.status !== 202) {
|
|
48
|
+
const err = body;
|
|
49
|
+
const errorBody = (err?.error ?? err);
|
|
50
|
+
throw new FabricApiError(errorBody?.message ?? response.statusText, response.status, errorBody?.errorCode ?? undefined, errorBody?.relatedResource ?? undefined);
|
|
51
|
+
}
|
|
52
|
+
return { data: body, lro, status: response.status };
|
|
53
|
+
}
|
|
54
|
+
async get(path) {
|
|
55
|
+
const headers = await this.getHeaders();
|
|
56
|
+
const response = await fetch(`${FABRIC_BASE_URL}${path}`, { headers });
|
|
57
|
+
return this.handleResponse(response);
|
|
58
|
+
}
|
|
59
|
+
async post(path, body) {
|
|
60
|
+
const headers = await this.getHeaders();
|
|
61
|
+
const response = await fetch(`${FABRIC_BASE_URL}${path}`, {
|
|
62
|
+
method: "POST",
|
|
63
|
+
headers,
|
|
64
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
65
|
+
});
|
|
66
|
+
return this.handleResponse(response);
|
|
67
|
+
}
|
|
68
|
+
async patch(path, body) {
|
|
69
|
+
const headers = await this.getHeaders();
|
|
70
|
+
const response = await fetch(`${FABRIC_BASE_URL}${path}`, {
|
|
71
|
+
method: "PATCH",
|
|
72
|
+
headers,
|
|
73
|
+
body: JSON.stringify(body),
|
|
74
|
+
});
|
|
75
|
+
return this.handleResponse(response);
|
|
76
|
+
}
|
|
77
|
+
async delete(path) {
|
|
78
|
+
const headers = await this.getHeaders();
|
|
79
|
+
const response = await fetch(`${FABRIC_BASE_URL}${path}`, {
|
|
80
|
+
method: "DELETE",
|
|
81
|
+
headers,
|
|
82
|
+
});
|
|
83
|
+
return this.handleResponse(response);
|
|
84
|
+
}
|
|
85
|
+
async getFullUrl(url) {
|
|
86
|
+
const headers = await this.getHeaders();
|
|
87
|
+
const response = await fetch(url, { headers });
|
|
88
|
+
return this.handleResponse(response);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=fabric-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fabric-client.js","sourceRoot":"","sources":["../../src/client/fabric-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { TokenManager } from "../auth/token-manager.js";
|
|
2
|
+
export interface PowerBIResponse<T = unknown> {
|
|
3
|
+
data: T;
|
|
4
|
+
status: number;
|
|
5
|
+
}
|
|
6
|
+
export declare class PowerBIClient {
|
|
7
|
+
private tokenManager;
|
|
8
|
+
constructor(tokenManager: TokenManager);
|
|
9
|
+
private getHeaders;
|
|
10
|
+
private handleResponse;
|
|
11
|
+
get<T = unknown>(path: string): Promise<PowerBIResponse<T>>;
|
|
12
|
+
post<T = unknown>(path: string, body?: unknown): Promise<PowerBIResponse<T>>;
|
|
13
|
+
delete<T = unknown>(path: string): Promise<PowerBIResponse<T>>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=powerbi-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"powerbi-client.d.ts","sourceRoot":"","sources":["../../src/client/powerbi-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAKxD,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,OAAO;IAC1C,IAAI,EAAE,CAAC,CAAC;IACR,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,aAAa;IACZ,OAAO,CAAC,YAAY;gBAAZ,YAAY,EAAE,YAAY;YAEhC,UAAU;YAQV,cAAc;IAoCtB,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAM3D,IAAI,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAU5E,MAAM,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;CAQrE"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { FabricApiError } from "../core/errors.js";
|
|
2
|
+
const POWERBI_BASE_URL = "https://api.powerbi.com/v1.0/myorg";
|
|
3
|
+
export class PowerBIClient {
|
|
4
|
+
tokenManager;
|
|
5
|
+
constructor(tokenManager) {
|
|
6
|
+
this.tokenManager = tokenManager;
|
|
7
|
+
}
|
|
8
|
+
async getHeaders() {
|
|
9
|
+
const token = await this.tokenManager.getPowerBIToken();
|
|
10
|
+
return {
|
|
11
|
+
Authorization: `Bearer ${token}`,
|
|
12
|
+
"Content-Type": "application/json",
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
async handleResponse(response) {
|
|
16
|
+
if (response.status === 429) {
|
|
17
|
+
const retryAfter = response.headers.get("retry-after");
|
|
18
|
+
const waitMs = retryAfter ? parseInt(retryAfter, 10) * 1000 : 30000;
|
|
19
|
+
throw new FabricApiError(`Rate limited. Retry after ${waitMs / 1000}s`, 429, "TooManyRequests");
|
|
20
|
+
}
|
|
21
|
+
if (response.status === 204 || response.headers.get("content-length") === "0") {
|
|
22
|
+
return { data: undefined, status: response.status };
|
|
23
|
+
}
|
|
24
|
+
let body;
|
|
25
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
26
|
+
if (contentType.includes("application/json")) {
|
|
27
|
+
body = await response.json();
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
body = await response.text();
|
|
31
|
+
}
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
const err = body;
|
|
34
|
+
const errorBody = (err?.error ?? err);
|
|
35
|
+
throw new FabricApiError(errorBody?.message ?? response.statusText, response.status, errorBody?.errorCode ?? undefined);
|
|
36
|
+
}
|
|
37
|
+
return { data: body, status: response.status };
|
|
38
|
+
}
|
|
39
|
+
async get(path) {
|
|
40
|
+
const headers = await this.getHeaders();
|
|
41
|
+
const response = await fetch(`${POWERBI_BASE_URL}${path}`, { headers });
|
|
42
|
+
return this.handleResponse(response);
|
|
43
|
+
}
|
|
44
|
+
async post(path, body) {
|
|
45
|
+
const headers = await this.getHeaders();
|
|
46
|
+
const response = await fetch(`${POWERBI_BASE_URL}${path}`, {
|
|
47
|
+
method: "POST",
|
|
48
|
+
headers,
|
|
49
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
50
|
+
});
|
|
51
|
+
return this.handleResponse(response);
|
|
52
|
+
}
|
|
53
|
+
async delete(path) {
|
|
54
|
+
const headers = await this.getHeaders();
|
|
55
|
+
const response = await fetch(`${POWERBI_BASE_URL}${path}`, {
|
|
56
|
+
method: "DELETE",
|
|
57
|
+
headers,
|
|
58
|
+
});
|
|
59
|
+
return this.handleResponse(response);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=powerbi-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"powerbi-client.js","sourceRoot":"","sources":["../../src/client/powerbi-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare class FabricApiError extends Error {
|
|
2
|
+
statusCode: number;
|
|
3
|
+
errorCode?: string | undefined;
|
|
4
|
+
relatedResource?: string | undefined;
|
|
5
|
+
constructor(message: string, statusCode: number, errorCode?: string | undefined, relatedResource?: string | undefined);
|
|
6
|
+
}
|
|
7
|
+
export declare function formatToolError(error: unknown): {
|
|
8
|
+
content: Array<{
|
|
9
|
+
type: "text";
|
|
10
|
+
text: string;
|
|
11
|
+
}>;
|
|
12
|
+
isError: true;
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,cAAe,SAAQ,KAAK;IAG9B,UAAU,EAAE,MAAM;IAClB,SAAS,CAAC,EAAE,MAAM;IAClB,eAAe,CAAC,EAAE,MAAM;gBAH/B,OAAO,EAAE,MAAM,EACR,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,YAAA,EAClB,eAAe,CAAC,EAAE,MAAM,YAAA;CAKlC;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,EAAE,IAAI,CAAA;CAAE,CAejH"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export class FabricApiError extends Error {
|
|
2
|
+
statusCode;
|
|
3
|
+
errorCode;
|
|
4
|
+
relatedResource;
|
|
5
|
+
constructor(message, statusCode, errorCode, relatedResource) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.statusCode = statusCode;
|
|
8
|
+
this.errorCode = errorCode;
|
|
9
|
+
this.relatedResource = relatedResource;
|
|
10
|
+
this.name = "FabricApiError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function formatToolError(error) {
|
|
14
|
+
let message;
|
|
15
|
+
if (error instanceof FabricApiError) {
|
|
16
|
+
message = `Fabric API Error (${error.statusCode}): ${error.message}`;
|
|
17
|
+
if (error.errorCode)
|
|
18
|
+
message += `\nError code: ${error.errorCode}`;
|
|
19
|
+
if (error.relatedResource)
|
|
20
|
+
message += `\nRelated resource: ${error.relatedResource}`;
|
|
21
|
+
}
|
|
22
|
+
else if (error instanceof Error) {
|
|
23
|
+
message = error.message;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
message = String(error);
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
content: [{ type: "text", text: message }],
|
|
30
|
+
isError: true,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,cAAe,SAAQ,KAAK;IAG9B;IACA;IACA;IAJT,YACE,OAAe,EACR,UAAkB,EAClB,SAAkB,EAClB,eAAwB;QAE/B,KAAK,CAAC,OAAO,CAAC,CAAC;QAJR,eAAU,GAAV,UAAU,CAAQ;QAClB,cAAS,GAAT,SAAS,CAAS;QAClB,oBAAe,GAAf,eAAe,CAAS;QAG/B,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,IAAI,OAAe,CAAC;IACpB,IAAI,KAAK,YAAY,cAAc,EAAE,CAAC;QACpC,OAAO,GAAG,qBAAqB,KAAK,CAAC,UAAU,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC;QACrE,IAAI,KAAK,CAAC,SAAS;YAAE,OAAO,IAAI,iBAAiB,KAAK,CAAC,SAAS,EAAE,CAAC;QACnE,IAAI,KAAK,CAAC,eAAe;YAAE,OAAO,IAAI,uBAAuB,KAAK,CAAC,eAAe,EAAE,CAAC;IACvF,CAAC;SAAM,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAClC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC1B,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAC1C,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC"}
|