dax-optimizer-sdk 0.1.0 → 0.2.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/README.md CHANGED
@@ -1,112 +1,130 @@
1
1
  # dax-optimizer-sdk
2
2
 
3
- Programmatic DAX Optimizer analysis for Power BI and Analysis Services models. Exports a model to VPAX format, uploads it to the [DAX Optimizer](https://daxoptimizer.com) service, and returns structured performance analysis results — all from a single function call.
3
+ Programmatic DAX Optimizer analysis for Power BI, Fabric, and Analysis Services models. Exports a model to VPAX format, uploads it to the [DAX Optimizer](https://daxoptimizer.com) service, and returns structured performance analysis results — all from a single function call.
4
4
 
5
5
  ## Prerequisites
6
6
 
7
- Three CLI tools must be installed on the machine before using this library. If any are missing, the library throws a `PrerequisiteError` with the exact install command.
8
-
9
7
  | Tool | Purpose | Install |
10
8
  |------|---------|---------|
11
- | **.NET 6.0+** | Runtime for the DAX Optimizer CLI | [Download](https://dotnet.microsoft.com/download) |
12
- | **DAX Optimizer CLI 1.4.7+** | Uploads VPAX and runs analysis | `dotnet tool install --global Dax.Optimizer.CLI` |
13
- | **DAX Studio** | Exports models to VPAX format (`dscmd.exe`) | [Download](https://daxstudio.org/download/) or `choco install daxstudio` |
9
+ | **.NET 8.0+** | Runtime for vpax-bridge and DAX Optimizer CLI | [Download](https://dotnet.microsoft.com/download) |
10
+ | **DAX Optimizer CLI** | Uploads VPAX and runs analysis | `dotnet tool install --global Dax.Optimizer.CLI` |
11
+
12
+ vpax-bridge (bundled) is built automatically on `npm install` via `dotnet build`.
14
13
 
15
14
  You also need a [DAX Optimizer account](https://daxoptimizer.com) with a workspace ID.
16
15
 
17
16
  ## Authentication
18
17
 
19
- Three auth modes are supported. Pass an `auth` object to choose:
18
+ ### DAX Optimizer auth (for analysis upload)
19
+
20
+ Three modes — pass an `auth` object:
20
21
 
21
- ### PAT (Personal Access Token)
22
- Non-interactive. For CI/CD and automation. Requires Enterprise license.
23
22
  ```ts
23
+ // PAT (CI/CD, automation — requires Enterprise license)
24
24
  auth: { method: 'pat', username: 'group:automation', token: process.env.TOKEN! }
25
+
26
+ // Interactive (opens browser, credentials cached by CLI)
27
+ auth: { method: 'interactive' }
28
+
29
+ // Group (opens browser, switches to group account)
30
+ auth: { method: 'group', username: 'my-team' }
25
31
  ```
26
32
 
27
- ### Interactive (Individual)
28
- Opens a browser for sign-in. Credentials are cached locally by the CLI — subsequent runs skip the browser.
33
+ ### Fabric auth (for VPAX export from cloud models)
34
+
35
+ For Fabric / Power BI Service models, add `interactive: true` to open a browser for Azure AD sign-in:
36
+
29
37
  ```ts
30
- auth: { method: 'interactive' }
38
+ interactive: true
31
39
  ```
32
40
 
33
- ### Group
34
- Opens a browser, then switches to a shared group account. Cached like interactive.
41
+ Or pass a pre-acquired token:
42
+
35
43
  ```ts
36
- auth: { method: 'group', username: 'my-team' }
44
+ accessToken: '<bearer-token>'
37
45
  ```
38
46
 
39
- Use `isInteractive(auth)` to check if a mode may open a browser (useful for showing a "waiting for login" UI). Use `logout()` to clear cached credentials.
47
+ Not needed for local Power BI Desktop models.
40
48
 
41
49
  ## Quick start
42
50
 
51
+ ### Local Power BI Desktop
52
+
43
53
  ```ts
44
54
  import { analyzeDaxModel } from 'dax-optimizer-sdk'
45
55
 
46
56
  const result = await analyzeDaxModel({
47
- // Authentication
48
57
  auth: { method: 'pat', username: 'group:automation', token: process.env.TOKEN! },
49
-
50
- // Connection to your Power BI Desktop / Analysis Services instance
51
58
  server: 'localhost:65072',
52
59
  databaseId: 'f97515be-bbb7-434b-83fc-b2599bf8a754',
53
-
54
- // DAX Optimizer target
55
60
  workspaceId: process.env.WORKSPACE_ID!,
56
61
  modelName: 'My Model',
57
- modelCreate: true, // create if it doesn't exist yet
58
- contractId: '...', // required when modelCreate is true
62
+ modelCreate: true,
63
+ contractId: '...',
59
64
  })
65
+ ```
66
+
67
+ ### Fabric / Power BI Service
60
68
 
61
- console.log(`Version: ${result.version}`)
62
- console.log(`Messages: ${result.messages.length}`)
63
- console.log(`Rules triggered: ${result.rules.length}`)
64
- console.log(`Measures analyzed: ${result.objectAnalyses.length}`)
69
+ ```ts
70
+ const result = await analyzeDaxModel({
71
+ auth: { method: 'pat', username: 'group:automation', token: process.env.TOKEN! },
72
+ server: 'powerbi://api.powerbi.com/v1.0/myorg/My Workspace',
73
+ databaseId: 'My Dataset',
74
+ interactive: true, // opens browser for Azure AD sign-in
75
+ workspaceId: process.env.WORKSPACE_ID!,
76
+ modelName: 'My Dataset',
77
+ modelCreate: true,
78
+ contractId: '...',
79
+ })
65
80
  ```
66
81
 
67
82
  ## Where do `server` and `databaseId` come from?
68
83
 
69
- This library does **not** include Power BI model discovery. The caller is responsible for providing the Analysis Services connection details. Common approaches:
84
+ This library does **not** include Power BI model discovery. The caller provides the connection details:
70
85
 
71
- - **Power BI MCP Server** — use `connection_operations` `ListLocalInstances` to discover running PBI Desktop instances, then `Connect` and `database_operations` → `List` to get the database ID.
72
- - **Manual** — find the port in `%LOCALAPPDATA%\Microsoft\Power BI Desktop\AnalysisServicesWorkspaces\*\Data\msmdsrv.port.txt`.
86
+ - **Local PBI Desktop** — use Power BI MCP `ListLocalInstances` + `Connect` + `database_operations List`
87
+ - **Fabric** — use the XMLA endpoint URL: `powerbi://api.powerbi.com/v1.0/myorg/<workspace>` and the dataset name as `databaseId`
73
88
 
74
89
  ## API
75
90
 
76
91
  ### `analyzeDaxModel(options): Promise<DaxOptimizerResult>`
77
92
 
78
- End-to-end analysis: checks prerequisites, exports VPAX, runs analysis, returns results, cleans up temp files.
93
+ End-to-end: preflight check VPAX export analysis results cleanup.
79
94
 
80
95
  ### `checkPrerequisites(): PreflightResult`
81
96
 
82
- Returns `{ dotnet: boolean, daxoptimizer: boolean, dscmd: boolean }` without throwing.
97
+ Returns `{ dotnet, daxoptimizer, vpaxBridge }` booleans.
83
98
 
84
99
  ### `exportVpax(options): Promise<string>`
85
100
 
86
- Exports a model to VPAX format. Returns the path to the `.vpax` file.
101
+ Exports a model to VPAX. Supports local, Fabric (interactive), and Fabric (token).
87
102
 
88
103
  ### `runAnalysis(options): Promise<DaxOptimizerResult>`
89
104
 
90
- Runs analysis on an existing VPAX file. Use this if you already have a `.vpax` and want to skip the export step.
105
+ Analyzes an existing VPAX file.
91
106
 
92
107
  ### `logout(): Promise<void>`
93
108
 
94
- Clears cached browser credentials from the DAX Optimizer CLI.
109
+ Clears cached DAX Optimizer CLI credentials.
95
110
 
96
111
  ### `isInteractive(auth): boolean`
97
112
 
98
- Returns `true` if the auth mode may open a browser (`interactive` or `group`).
113
+ Returns `true` if the DAX Optimizer auth mode may open a browser.
99
114
 
100
115
  ## Error handling
101
116
 
102
117
  | Error class | When |
103
118
  |-------------|------|
104
- | `AuthError` | Invalid auth configuration or login/logout failure |
105
- | `PrerequisiteError` | A required CLI tool is missing (includes install command) |
106
- | `VpaxExportError` | `dscmd.exe` failed to export the model |
107
- | `AnalysisError` | `daxoptimizer` CLI failed or results couldn't be parsed |
119
+ | `AuthError` | Invalid auth config or login/logout failure |
120
+ | `PrerequisiteError` | Missing tool (includes install command) |
121
+ | `VpaxExportError` | VPAX export failed |
122
+ | `AnalysisError` | DAX Optimizer CLI failed or results couldn't be parsed |
123
+
124
+ ## Known limitations
108
125
 
109
- All error classes include `stdout` / `stderr` from the failed process where available.
126
+ - **Direct Lake models** (compat level 1604) are not yet supported by DAX Optimizer
127
+ - **TMDL/PBIP offline** export produces a VPAX without data statistics, which DAX Optimizer rejects
110
128
 
111
129
  ## License
112
130
 
package/dist/index.d.ts CHANGED
@@ -2,14 +2,14 @@ import { DaxOptimizerOptions, DaxOptimizerResult } from './types.js';
2
2
  /**
3
3
  * End-to-end DAX Optimizer analysis.
4
4
  *
5
- * 1. Validates prerequisites (dscmd, daxoptimizer, dotnet).
5
+ * 1. Validates prerequisites (vpax-bridge, daxoptimizer, dotnet).
6
6
  * 2. Exports the model to a temporary VPAX file.
7
7
  * 3. Uploads VPAX to DAX Optimizer and waits for results.
8
8
  * 4. Cleans up temp files and returns the parsed result.
9
9
  */
10
10
  export declare function analyzeDaxModel(options: DaxOptimizerOptions): Promise<DaxOptimizerResult>;
11
11
  export { checkPrerequisites } from './preflight.js';
12
- export { exportVpax, findDscmd } from './vpax-export.js';
12
+ export { exportVpax, findVpaxBridge, buildConnectionString } from './vpax-export.js';
13
13
  export { runAnalysis } from './analyze.js';
14
14
  export { logout, isInteractive, buildAuthArgs } from './auth.js';
15
15
  export * from './types.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAwBA,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAEnB,MAAM,YAAY,CAAA;AAKnB;;;;;;;GAOG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAoC/F;AAGD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAChE,cAAc,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AA6BA,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAEnB,MAAM,YAAY,CAAA;AAKnB;;;;;;;GAOG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAwC/F;AAGD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AACpF,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAChE,cAAc,YAAY,CAAA"}
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@
5
5
  // Usage:
6
6
  // import { analyzeDaxModel, checkPrerequisites, logout } from 'dax-optimizer-sdk'
7
7
  //
8
- // // PAT auth (CI/CD)
8
+ // // Local PBI Desktop
9
9
  // const result = await analyzeDaxModel({
10
10
  // auth: { method: 'pat', username: 'group:automation', token: '...' },
11
11
  // server: 'localhost:65072',
@@ -14,11 +14,16 @@
14
14
  // modelName: 'My Model',
15
15
  // })
16
16
  //
17
- // // Interactive auth (local dev)
18
- // const result2 = await analyzeDaxModel({
19
- // auth: { method: 'interactive' },
20
- // ...
17
+ // // Fabric with interactive browser login
18
+ // const result = await analyzeDaxModel({
19
+ // auth: { method: 'pat', username: '...', token: '...' },
20
+ // server: 'powerbi://api.powerbi.com/v1.0/myorg/MyWorkspace',
21
+ // databaseId: 'My Dataset',
22
+ // interactive: true,
23
+ // workspaceId: '...',
24
+ // modelName: 'My Model',
21
25
  // })
26
+ //
22
27
  // ---------------------------------------------------------------------------
23
28
  import { unlinkSync } from 'node:fs';
24
29
  import { PrerequisiteError, } from './types.js';
@@ -28,7 +33,7 @@ import { runAnalysis } from './analyze.js';
28
33
  /**
29
34
  * End-to-end DAX Optimizer analysis.
30
35
  *
31
- * 1. Validates prerequisites (dscmd, daxoptimizer, dotnet).
36
+ * 1. Validates prerequisites (vpax-bridge, daxoptimizer, dotnet).
32
37
  * 2. Exports the model to a temporary VPAX file.
33
38
  * 3. Uploads VPAX to DAX Optimizer and waits for results.
34
39
  * 4. Cleans up temp files and returns the parsed result.
@@ -41,8 +46,8 @@ export async function analyzeDaxModel(options) {
41
46
  missing.push('dotnet 6.0+');
42
47
  if (!pre.daxoptimizer)
43
48
  missing.push('daxoptimizer CLI (dotnet tool install --global Dax.Optimizer.CLI)');
44
- if (!pre.dscmd)
45
- missing.push('dscmd.exe (DAX Studio)');
49
+ if (!pre.vpaxBridge)
50
+ missing.push('vpax-bridge (run "dotnet build" in tools/vpax-bridge)');
46
51
  if (missing.length)
47
52
  throw new PrerequisiteError(missing);
48
53
  // ── 2. Export VPAX ────────────────────────────────────────────────────
@@ -50,6 +55,10 @@ export async function analyzeDaxModel(options) {
50
55
  databaseId: options.databaseId,
51
56
  server: options.server,
52
57
  connectionString: options.connectionString,
58
+ interactive: options.interactive,
59
+ accessToken: options.accessToken,
60
+ clientId: options.clientId,
61
+ tenantId: options.tenantId,
53
62
  });
54
63
  // ── 3. Run analysis ───────────────────────────────────────────────────
55
64
  try {
@@ -77,7 +86,7 @@ export async function analyzeDaxModel(options) {
77
86
  }
78
87
  // Re-export everything so callers can import from a single entry point
79
88
  export { checkPrerequisites } from './preflight.js';
80
- export { exportVpax, findDscmd } from './vpax-export.js';
89
+ export { exportVpax, findVpaxBridge, buildConnectionString } from './vpax-export.js';
81
90
  export { runAnalysis } from './analyze.js';
82
91
  export { logout, isInteractive, buildAuthArgs } from './auth.js';
83
92
  export * from './types.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,6BAA6B;AAC7B,8EAA8E;AAC9E,EAAE;AACF,SAAS;AACT,oFAAoF;AACpF,EAAE;AACF,wBAAwB;AACxB,2CAA2C;AAC3C,2EAA2E;AAC3E,iCAAiC;AACjC,yBAAyB;AACzB,0BAA0B;AAC1B,6BAA6B;AAC7B,OAAO;AACP,EAAE;AACF,oCAAoC;AACpC,4CAA4C;AAC5C,uCAAuC;AACvC,UAAU;AACV,OAAO;AACP,8EAA8E;AAE9E,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAGL,iBAAiB,GAClB,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE1C;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAA4B;IAChE,yEAAyE;IACzE,MAAM,GAAG,GAAG,kBAAkB,EAAE,CAAA;IAChC,MAAM,OAAO,GAAa,EAAE,CAAA;IAC5B,IAAI,CAAC,GAAG,CAAC,MAAM;QAAQ,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;IAClD,IAAI,CAAC,GAAG,CAAC,YAAY;QAAE,OAAO,CAAC,IAAI,CAAC,mEAAmE,CAAC,CAAA;IACxG,IAAI,CAAC,GAAG,CAAC,KAAK;QAAS,OAAO,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAA;IAC7D,IAAI,OAAO,CAAC,MAAM;QAAE,MAAM,IAAI,iBAAiB,CAAC,OAAO,CAAC,CAAA;IAExD,yEAAyE;IACzE,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC;QAChC,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;KAC3C,CAAC,CAAA;IAEF,yEAAyE;IACzE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC;YAC/B,QAAQ;YACR,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,YAAY;YACtC,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,UAAU;YAClD,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,YAAY,EAAE,OAAO,CAAC,YAAY;SACnC,CAAC,CAAA;QAEF,OAAO,MAAM,CAAA;IACf,CAAC;YAAS,CAAC;QACT,uEAAuE;QACvE,IAAI,CAAC;YAAC,UAAU,CAAC,QAAQ,CAAC,CAAA;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED,uEAAuE;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAChE,cAAc,YAAY,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,10 @@
1
1
  import { PreflightResult } from './types.js';
2
2
  /**
3
- * Check whether all required CLI tools are available.
3
+ * Check whether all required tools are available.
4
4
  *
5
5
  * - `dotnet` 6.0+
6
6
  * - `daxoptimizer` (Dax.Optimizer.CLI .NET global tool)
7
- * - `dscmd.exe` (DAX Studio CLI)
7
+ * - `vpax-bridge` (bundled .NET tool for VPAX export)
8
8
  */
9
9
  export declare function checkPrerequisites(): PreflightResult;
10
10
  //# sourceMappingURL=preflight.d.ts.map
package/dist/preflight.js CHANGED
@@ -2,7 +2,7 @@
2
2
  // DAX Optimizer – prerequisite checks
3
3
  // ---------------------------------------------------------------------------
4
4
  import { execFileSync } from 'node:child_process';
5
- import { findDscmd } from './vpax-export.js';
5
+ import { findVpaxBridge } from './vpax-export.js';
6
6
  function commandExists(cmd, args = ['--version']) {
7
7
  try {
8
8
  execFileSync(cmd, args, { encoding: 'utf-8', timeout: 10_000, stdio: 'pipe' });
@@ -23,17 +23,17 @@ function checkDotnet() {
23
23
  }
24
24
  }
25
25
  /**
26
- * Check whether all required CLI tools are available.
26
+ * Check whether all required tools are available.
27
27
  *
28
28
  * - `dotnet` 6.0+
29
29
  * - `daxoptimizer` (Dax.Optimizer.CLI .NET global tool)
30
- * - `dscmd.exe` (DAX Studio CLI)
30
+ * - `vpax-bridge` (bundled .NET tool for VPAX export)
31
31
  */
32
32
  export function checkPrerequisites() {
33
33
  return {
34
34
  dotnet: checkDotnet(),
35
35
  daxoptimizer: commandExists('daxoptimizer'),
36
- dscmd: findDscmd() !== null,
36
+ vpaxBridge: findVpaxBridge() !== null,
37
37
  };
38
38
  }
39
39
  //# sourceMappingURL=preflight.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"preflight.js","sourceRoot":"","sources":["../preflight.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,sCAAsC;AACtC,8EAA8E;AAE9E,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAE5C,SAAS,aAAa,CAAC,GAAW,EAAE,OAAiB,CAAC,WAAW,CAAC;IAChE,IAAI,CAAC;QACH,YAAY,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;QAC9E,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED,SAAS,WAAW;IAClB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;QACxG,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;QACpD,OAAO,KAAK,IAAI,CAAC,CAAA;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO;QACL,MAAM,EAAE,WAAW,EAAE;QACrB,YAAY,EAAE,aAAa,CAAC,cAAc,CAAC;QAC3C,KAAK,EAAE,SAAS,EAAE,KAAK,IAAI;KAC5B,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"preflight.js","sourceRoot":"","sources":["../preflight.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,sCAAsC;AACtC,8EAA8E;AAE9E,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEjD,SAAS,aAAa,CAAC,GAAW,EAAE,OAAiB,CAAC,WAAW,CAAC;IAChE,IAAI,CAAC;QACH,YAAY,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;QAC9E,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED,SAAS,WAAW;IAClB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;QACxG,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;QACpD,OAAO,KAAK,IAAI,CAAC,CAAA;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO;QACL,MAAM,EAAE,WAAW,EAAE;QACrB,YAAY,EAAE,aAAa,CAAC,cAAc,CAAC;QAC3C,UAAU,EAAE,cAAc,EAAE,KAAK,IAAI;KACtC,CAAA;AACH,CAAC"}
package/dist/types.d.ts CHANGED
@@ -52,12 +52,29 @@ export interface DaxOptimizerOptions {
52
52
  failOnIssues?: boolean;
53
53
  /** Optional: full MSOLAP connection string (overrides server + databaseId) */
54
54
  connectionString?: string;
55
+ /** Open browser for Azure AD sign-in (for Fabric/cloud models) */
56
+ interactive?: boolean;
57
+ /** Pre-acquired bearer token for Fabric/cloud XMLA endpoint */
58
+ accessToken?: string;
59
+ /** Azure AD app client ID for interactive auth (default: well-known AS tools ID) */
60
+ clientId?: string;
61
+ /** Azure AD tenant ID for interactive auth (default: 'common') */
62
+ tenantId?: string;
55
63
  }
56
64
  /** Subset of options needed just for VPAX export. */
57
65
  export interface VpaxExportOptions {
58
66
  databaseId: string;
59
67
  server: string;
68
+ /** Full MSOLAP connection string (overrides server + databaseId) */
60
69
  connectionString?: string;
70
+ /** Open browser for Azure AD sign-in (for Fabric/cloud models) */
71
+ interactive?: boolean;
72
+ /** Pre-acquired bearer token for Fabric/cloud XMLA endpoint */
73
+ accessToken?: string;
74
+ /** Azure AD app client ID for interactive auth (default: well-known AS tools ID) */
75
+ clientId?: string;
76
+ /** Azure AD tenant ID for interactive auth (default: 'common') */
77
+ tenantId?: string;
61
78
  outputPath?: string;
62
79
  }
63
80
  /** Subset of options needed for the `daxoptimizer analyze` step. */
@@ -76,7 +93,7 @@ export interface AnalyzeOptions {
76
93
  export interface PreflightResult {
77
94
  dotnet: boolean;
78
95
  daxoptimizer: boolean;
79
- dscmd: boolean;
96
+ vpaxBridge: boolean;
80
97
  }
81
98
  export interface DaxOptimizerMessage {
82
99
  category: number;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"AAIA,kDAAkD;AAClD,MAAM,MAAM,kBAAkB,GAAG,eAAe,GAAG,QAAQ,GAAG,YAAY,CAAA;AAI1E,0FAA0F;AAC1F,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,KAAK,CAAA;IACb,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAA;IAChB,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAA;CACd;AAED,0FAA0F;AAC1F,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,aAAa,CAAA;CACtB;AAED,4EAA4E;AAC5E,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,OAAO,CAAA;IACf,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,eAAe,GAAG,SAAS,CAAA;AAIpE,2EAA2E;AAC3E,MAAM,WAAW,mBAAmB;IAClC,+DAA+D;IAC/D,MAAM,EAAE,MAAM,CAAA;IACd,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAA;IAClB,gCAAgC;IAChC,IAAI,EAAE,gBAAgB,CAAA;IACtB,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAA;IACnB,+CAA+C;IAC/C,MAAM,CAAC,EAAE,kBAAkB,CAAA;IAC3B,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gEAAgE;IAChE,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,wDAAwD;IACxD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qDAAqD;IACrD,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,8EAA8E;IAC9E,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,kEAAkE;IAClE,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,qDAAqD;AACrD,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,oEAAoE;IACpE,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,kEAAkE;IAClE,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,oEAAoE;AACpE,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,gBAAgB,CAAA;IACtB,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,kBAAkB,CAAA;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;AAID,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,OAAO,CAAA;IACf,YAAY,EAAE,OAAO,CAAA;IACrB,UAAU,EAAE,OAAO,CAAA;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,aAAa,EAAE,gBAAgB,EAAE,CAAA;CAClC;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,qBAAqB,EAAE,MAAM,CAAA;IAC7B,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAC5D;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,eAAe,EAAE,cAAc,EAAE,CAAA;CAClC;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,GAAG,EAAE,MAAM,CAAA;IACX,cAAc,EAAE,MAAM,CAAA;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,iBAAiB,EAAE,MAAM,CAAA;IACzB,oBAAoB,EAAE,MAAM,CAAA;IAC5B,6BAA6B,EAAE,MAAM,CAAA;IACrC,oBAAoB,EAAE,MAAM,CAAA;IAC5B,sBAAsB,EAAE,MAAM,CAAA;IAC9B,mBAAmB,EAAE,MAAM,CAAA;IAC3B,qBAAqB,EAAE,MAAM,CAAA;IAC7B,mBAAmB,EAAE,MAAM,CAAA;IAC3B,mBAAmB,EAAE,kBAAkB,EAAE,CAAA;IACzC,kBAAkB,EAAE,gBAAgB,EAAE,CAAA;IACtC,YAAY,EAAE,OAAO,EAAE,CAAA;IACvB,UAAU,EAAE,OAAO,CAAA;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,mBAAmB,EAAE,CAAA;IAC/B,KAAK,EAAE,gBAAgB,EAAE,CAAA;IACzB,cAAc,EAAE,cAAc,EAAE,CAAA;CACjC;AAID,qBAAa,iBAAkB,SAAQ,KAAK;IACvB,OAAO,EAAE,MAAM,EAAE;gBAAjB,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM;CAIvD;AAED,qBAAa,SAAU,SAAQ,KAAK;gBACtB,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,eAAgB,SAAQ,KAAK;IACJ,MAAM,CAAC,EAAE,MAAM;IAAS,MAAM,CAAC,EAAE,MAAM;gBAA/D,OAAO,EAAE,MAAM,EAAS,MAAM,CAAC,EAAE,MAAM,YAAA,EAAS,MAAM,CAAC,EAAE,MAAM,YAAA;CAI5E;AAED,qBAAa,aAAc,SAAQ,KAAK;IACF,QAAQ,CAAC,EAAE,MAAM;IAAS,MAAM,CAAC,EAAE,MAAM;IAAS,MAAM,CAAC,EAAE,MAAM;gBAAzF,OAAO,EAAE,MAAM,EAAS,QAAQ,CAAC,EAAE,MAAM,YAAA,EAAS,MAAM,CAAC,EAAE,MAAM,YAAA,EAAS,MAAM,CAAC,EAAE,MAAM,YAAA;CAItG"}
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,+BAA+B;AAC/B,8EAA8E;AA4K9E,+EAA+E;AAE/E,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACvB;IAAnB,YAAmB,OAAiB,EAAE,OAAgB;QACpD,KAAK,CAAC,OAAO,IAAI,0BAA0B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAD/C,YAAO,GAAP,OAAO,CAAU;QAElC,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAA;IACjC,CAAC;CACF;AAED,MAAM,OAAO,SAAU,SAAQ,KAAK;IAClC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,WAAW,CAAA;IACzB,CAAC;CACF;AAED,MAAM,OAAO,eAAgB,SAAQ,KAAK;IACJ;IAAwB;IAA5D,YAAY,OAAe,EAAS,MAAe,EAAS,MAAe;QACzE,KAAK,CAAC,OAAO,CAAC,CAAA;QADoB,WAAM,GAAN,MAAM,CAAS;QAAS,WAAM,GAAN,MAAM,CAAS;QAEzE,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAA;IAC/B,CAAC;CACF;AAED,MAAM,OAAO,aAAc,SAAQ,KAAK;IACF;IAA0B;IAAwB;IAAtF,YAAY,OAAe,EAAS,QAAiB,EAAS,MAAe,EAAS,MAAe;QACnG,KAAK,CAAC,OAAO,CAAC,CAAA;QADoB,aAAQ,GAAR,QAAQ,CAAS;QAAS,WAAM,GAAN,MAAM,CAAS;QAAS,WAAM,GAAN,MAAM,CAAS;QAEnG,IAAI,CAAC,IAAI,GAAG,eAAe,CAAA;IAC7B,CAAC;CACF"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,+BAA+B;AAC/B,8EAA8E;AA6L9E,+EAA+E;AAE/E,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACvB;IAAnB,YAAmB,OAAiB,EAAE,OAAgB;QACpD,KAAK,CAAC,OAAO,IAAI,0BAA0B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAD/C,YAAO,GAAP,OAAO,CAAU;QAElC,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAA;IACjC,CAAC;CACF;AAED,MAAM,OAAO,SAAU,SAAQ,KAAK;IAClC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,WAAW,CAAA;IACzB,CAAC;CACF;AAED,MAAM,OAAO,eAAgB,SAAQ,KAAK;IACJ;IAAwB;IAA5D,YAAY,OAAe,EAAS,MAAe,EAAS,MAAe;QACzE,KAAK,CAAC,OAAO,CAAC,CAAA;QADoB,WAAM,GAAN,MAAM,CAAS;QAAS,WAAM,GAAN,MAAM,CAAS;QAEzE,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAA;IAC/B,CAAC;CACF;AAED,MAAM,OAAO,aAAc,SAAQ,KAAK;IACF;IAA0B;IAAwB;IAAtF,YAAY,OAAe,EAAS,QAAiB,EAAS,MAAe,EAAS,MAAe;QACnG,KAAK,CAAC,OAAO,CAAC,CAAA;QADoB,aAAQ,GAAR,QAAQ,CAAS;QAAS,WAAM,GAAN,MAAM,CAAS;QAAS,WAAM,GAAN,MAAM,CAAS;QAEnG,IAAI,CAAC,IAAI,GAAG,eAAe,CAAA;IAC7B,CAAC;CACF"}
@@ -1,11 +1,20 @@
1
1
  import { VpaxExportOptions } from './types.js';
2
- /** Locate dscmd.exe on PATH or at well-known install locations. */
3
- export declare function findDscmd(): string | null;
4
2
  /**
5
- * Export a Power BI / Analysis Services model to VPAX format.
3
+ * Locate the vpax-bridge executable.
4
+ * Checks the built output relative to this module's location.
5
+ */
6
+ export declare function findVpaxBridge(): string | null;
7
+ /**
8
+ * Build an MSOLAP connection string from export options.
9
+ */
10
+ export declare function buildConnectionString(options: VpaxExportOptions): string;
11
+ /**
12
+ * Export a Power BI / Analysis Services / Fabric model to VPAX format.
6
13
  *
7
- * Runs: `dscmd.exe vpax <outputPath> -s <server> -d <databaseId>`
8
- * or: `dscmd.exe vpax <outputPath> -c <connectionString>`
14
+ * Uses vpax-bridge which supports:
15
+ * - Local PBI Desktop (no auth)
16
+ * - Fabric with interactive browser login (`interactive: true`)
17
+ * - Fabric with pre-acquired token (`accessToken: '...'`)
9
18
  *
10
19
  * @returns Absolute path to the exported .vpax file.
11
20
  */
@@ -1 +1 @@
1
- {"version":3,"file":"vpax-export.d.ts","sourceRoot":"","sources":["../vpax-export.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,iBAAiB,EAAmB,MAAM,YAAY,CAAA;AAM/D,mEAAmE;AACnE,wBAAgB,SAAS,IAAI,MAAM,GAAG,IAAI,CAYzC;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CA8CtE"}
1
+ {"version":3,"file":"vpax-export.d.ts","sourceRoot":"","sources":["../vpax-export.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,iBAAiB,EAAmB,MAAM,YAAY,CAAA;AAI/D;;;GAGG;AACH,wBAAgB,cAAc,IAAI,MAAM,GAAG,IAAI,CAqB9C;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAKxE;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoDtE"}
@@ -1,61 +1,87 @@
1
1
  // ---------------------------------------------------------------------------
2
- // DAX Optimizer – VPAX export via DAX Studio CLI (dscmd.exe)
2
+ // DAX Optimizer – VPAX export via vpax-bridge (.NET wrapper around SQLBI libs)
3
3
  // ---------------------------------------------------------------------------
4
4
  import { execFile, execFileSync } from 'node:child_process';
5
5
  import { existsSync, mkdirSync, statSync } from 'node:fs';
6
6
  import { tmpdir } from 'node:os';
7
7
  import { dirname, join } from 'node:path';
8
+ import { fileURLToPath } from 'node:url';
8
9
  import { VpaxExportError } from './types.js';
9
- const KNOWN_DSCMD_PATHS = [
10
- 'C:\\Program Files\\DAX Studio\\dscmd.exe',
11
- ];
12
- /** Locate dscmd.exe on PATH or at well-known install locations. */
13
- export function findDscmd() {
14
- // Check PATH via `where` on Windows
10
+ const __dirname = dirname(fileURLToPath(import.meta.url));
11
+ /**
12
+ * Locate the vpax-bridge executable.
13
+ * Checks the built output relative to this module's location.
14
+ */
15
+ export function findVpaxBridge() {
16
+ // When running from source (lib/dax-optimizer/): tools/vpax-bridge/bin/...
17
+ // When running from dist (lib/dax-optimizer/dist/): ../tools/vpax-bridge/bin/...
18
+ const candidates = [
19
+ join(__dirname, '..', 'tools', 'vpax-bridge', 'bin', 'Debug', 'net8.0', 'vpax-bridge.exe'),
20
+ join(__dirname, 'tools', 'vpax-bridge', 'bin', 'Debug', 'net8.0', 'vpax-bridge.exe'),
21
+ join(__dirname, '..', 'tools', 'vpax-bridge', 'bin', 'Release', 'net8.0', 'vpax-bridge.exe'),
22
+ ];
23
+ for (const p of candidates) {
24
+ if (existsSync(p))
25
+ return p;
26
+ }
27
+ // Also check PATH
15
28
  try {
16
- const result = execFileSync('where', ['dscmd.exe'], { encoding: 'utf-8', timeout: 5_000 });
29
+ const result = execFileSync('where', ['vpax-bridge'], { encoding: 'utf-8', timeout: 5_000 });
17
30
  const first = result.trim().split(/\r?\n/)[0];
18
31
  if (first && existsSync(first))
19
32
  return first;
20
33
  }
21
34
  catch { /* not on PATH */ }
22
- for (const p of KNOWN_DSCMD_PATHS) {
23
- if (existsSync(p))
24
- return p;
25
- }
26
35
  return null;
27
36
  }
28
37
  /**
29
- * Export a Power BI / Analysis Services model to VPAX format.
38
+ * Build an MSOLAP connection string from export options.
39
+ */
40
+ export function buildConnectionString(options) {
41
+ if (options.connectionString) {
42
+ return options.connectionString;
43
+ }
44
+ return `Provider=MSOLAP;Data Source=${options.server};Initial Catalog=${options.databaseId}`;
45
+ }
46
+ /**
47
+ * Export a Power BI / Analysis Services / Fabric model to VPAX format.
30
48
  *
31
- * Runs: `dscmd.exe vpax <outputPath> -s <server> -d <databaseId>`
32
- * or: `dscmd.exe vpax <outputPath> -c <connectionString>`
49
+ * Uses vpax-bridge which supports:
50
+ * - Local PBI Desktop (no auth)
51
+ * - Fabric with interactive browser login (`interactive: true`)
52
+ * - Fabric with pre-acquired token (`accessToken: '...'`)
33
53
  *
34
54
  * @returns Absolute path to the exported .vpax file.
35
55
  */
36
56
  export function exportVpax(options) {
37
- const { databaseId, server, connectionString } = options;
57
+ const { databaseId } = options;
38
58
  const outputPath = options.outputPath ?? join(tmpdir(), `${databaseId}.vpax`);
39
- const dscmd = findDscmd();
40
- if (!dscmd) {
41
- throw new VpaxExportError('dscmd.exe not found. Install DAX Studio from https://daxstudio.org/download/ or add it to PATH.');
59
+ const bridge = findVpaxBridge();
60
+ if (!bridge) {
61
+ throw new VpaxExportError('vpax-bridge not found. Run "dotnet build" in the tools/vpax-bridge directory.');
42
62
  }
43
63
  // Ensure output directory exists
44
64
  const dir = dirname(outputPath);
45
65
  if (!existsSync(dir))
46
66
  mkdirSync(dir, { recursive: true });
47
- // Build command arguments
48
- const args = ['vpax', outputPath];
49
- if (connectionString) {
50
- args.push('-c', connectionString);
67
+ const connStr = buildConnectionString(options);
68
+ const args = ['export', outputPath, connStr, '--overwrite'];
69
+ if (options.interactive) {
70
+ args.push('--interactive');
71
+ if (options.clientId)
72
+ args.push('--client-id', options.clientId);
73
+ if (options.tenantId)
74
+ args.push('--tenant-id', options.tenantId);
51
75
  }
52
- else {
53
- args.push('-s', server, '-d', databaseId);
76
+ else if (options.accessToken) {
77
+ args.push('--access-token', options.accessToken);
54
78
  }
79
+ // Interactive auth needs more time for browser login
80
+ const timeoutMs = options.interactive ? 300_000 : 120_000;
55
81
  return new Promise((resolve, reject) => {
56
- execFile(dscmd, args, { timeout: 120_000 }, (error, stdout, stderr) => {
82
+ execFile(bridge, args, { timeout: timeoutMs }, (error, stdout, stderr) => {
57
83
  if (error) {
58
- return reject(new VpaxExportError(`VPAX export failed: ${error.message}`, stdout, stderr));
84
+ return reject(new VpaxExportError(`VPAX export failed: ${(stderr || error.message).trim()}`, stdout, stderr));
59
85
  }
60
86
  if (!existsSync(outputPath)) {
61
87
  return reject(new VpaxExportError('VPAX export completed but output file was not created.', stdout, stderr));
@@ -1 +1 @@
1
- {"version":3,"file":"vpax-export.js","sourceRoot":"","sources":["../vpax-export.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"vpax-export.js","sourceRoot":"","sources":["../vpax-export.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dax-optimizer-sdk",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Programmatic DAX Optimizer analysis for Power BI and Analysis Services models",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -13,11 +13,15 @@
13
13
  },
14
14
  "files": [
15
15
  "dist/",
16
+ "tools/vpax-bridge/Program.cs",
17
+ "tools/vpax-bridge/VpaxBridge.csproj",
16
18
  "README.md",
17
19
  "LICENSE"
18
20
  ],
19
21
  "scripts": {
20
22
  "build": "tsc",
23
+ "build:bridge": "dotnet build tools/vpax-bridge -c Debug",
24
+ "postinstall": "dotnet build tools/vpax-bridge -c Debug -v quiet",
21
25
  "prepublishOnly": "npm run build",
22
26
  "preflight": "node dist/preflight.js"
23
27
  },
@@ -0,0 +1,225 @@
1
+ // vpax-bridge — VPAX export with interactive auth and TMDL support
2
+ //
3
+ // Usage:
4
+ // vpax-bridge export <output.vpax> <connection-string> [options]
5
+ // vpax-bridge export-tmdl <output.vpax> <tmdl-folder> [--overwrite]
6
+ //
7
+ // Options:
8
+ // --access-token <token> Use a pre-acquired bearer token
9
+ // --interactive Open browser for Azure AD sign-in (like DAX Studio)
10
+ // --client-id <id> Azure AD app client ID (default: well-known AS tools ID)
11
+ // --tenant-id <id> Azure AD tenant ID (default: common)
12
+ // --overwrite Overwrite existing output file
13
+ //
14
+ // Examples:
15
+ // # Local PBI Desktop (no auth needed)
16
+ // vpax-bridge export model.vpax "Provider=MSOLAP;Data Source=localhost:65072;Initial Catalog=mydb"
17
+ //
18
+ // # Fabric with interactive browser login
19
+ // vpax-bridge export model.vpax "Data Source=powerbi://api.powerbi.com/v1.0/myorg/Workspace;Initial Catalog=Dataset" --interactive
20
+ //
21
+ // # Fabric with pre-acquired token
22
+ // vpax-bridge export model.vpax "Data Source=powerbi://...;Initial Catalog=..." --access-token eyJ0...
23
+ //
24
+ // # From TMDL/PBIP folder (offline, no server needed)
25
+ // vpax-bridge export-tmdl model.vpax "C:\path\to\MyModel.SemanticModel"
26
+
27
+ using System;
28
+ using System.IO;
29
+ using System.Linq;
30
+ using System.Threading.Tasks;
31
+ using Dax.Model.Extractor;
32
+ using Dax.Vpax.Tools;
33
+ using Microsoft.AnalysisServices;
34
+ using Microsoft.Identity.Client;
35
+ using Tom = Microsoft.AnalysisServices.Tabular;
36
+
37
+ class Program
38
+ {
39
+ // Default client ID: well-known AS tools ID (same as DAX Studio)
40
+ private const string DefaultClientId = "a672d62c-fc7b-4e81-a576-e60dc46e951d";
41
+ private const string DefaultTenantId = "common";
42
+ private const string PowerBIScope = "https://analysis.windows.net/powerbi/api/.default";
43
+
44
+ static async Task<int> Main(string[] args)
45
+ {
46
+ if (args.Length < 3)
47
+ {
48
+ PrintUsage();
49
+ return 1;
50
+ }
51
+
52
+ var command = args[0];
53
+ var outputPath = args[1];
54
+ bool overwrite = args.Contains("--overwrite");
55
+
56
+ if (File.Exists(outputPath) && !overwrite)
57
+ {
58
+ Console.Error.WriteLine($"Output file already exists: {outputPath}. Use --overwrite to replace.");
59
+ return 1;
60
+ }
61
+
62
+ try
63
+ {
64
+ return command switch
65
+ {
66
+ "export" => await ExportFromServer(outputPath, args),
67
+ "export-tmdl" => ExportFromTmdl(outputPath, args[2]),
68
+ _ => PrintUsage()
69
+ };
70
+ }
71
+ catch (Exception ex)
72
+ {
73
+ Console.Error.WriteLine();
74
+ Console.Error.WriteLine($"Error: {ex.Message}");
75
+ if (ex.InnerException != null)
76
+ Console.Error.WriteLine($"Inner: {ex.InnerException.Message}");
77
+ return 1;
78
+ }
79
+ }
80
+
81
+ static int PrintUsage()
82
+ {
83
+ Console.Error.WriteLine("vpax-bridge — VPAX export with auth support");
84
+ Console.Error.WriteLine();
85
+ Console.Error.WriteLine("Usage:");
86
+ Console.Error.WriteLine(" vpax-bridge export <output.vpax> <connection-string> [--interactive] [--access-token <token>] [--overwrite]");
87
+ Console.Error.WriteLine(" vpax-bridge export-tmdl <output.vpax> <tmdl-folder> [--overwrite]");
88
+ return 1;
89
+ }
90
+
91
+ /// <summary>Acquire an access token via interactive browser sign-in.</summary>
92
+ static async Task<string> AcquireTokenInteractive(string clientId = null, string tenantId = null)
93
+ {
94
+ var effectiveClientId = clientId ?? DefaultClientId;
95
+ var effectiveTenantId = tenantId ?? DefaultTenantId;
96
+
97
+ Console.Error.WriteLine($"Opening browser for Azure AD sign-in (client: {effectiveClientId}, tenant: {effectiveTenantId})...");
98
+
99
+ var app = PublicClientApplicationBuilder
100
+ .Create(effectiveClientId)
101
+ .WithAuthority($"https://login.microsoftonline.com/{effectiveTenantId}")
102
+ .WithDefaultRedirectUri()
103
+ .Build();
104
+
105
+ var result = await app.AcquireTokenInteractive(new[] { PowerBIScope })
106
+ .WithPrompt(Prompt.SelectAccount)
107
+ .ExecuteAsync();
108
+
109
+ Console.Error.WriteLine($"Authenticated as: {result.Account.Username}");
110
+ return result.AccessToken;
111
+ }
112
+
113
+ /// <summary>Export VPAX from a live server connection.</summary>
114
+ static async Task<int> ExportFromServer(string outputPath, string[] args)
115
+ {
116
+ var connectionString = args[2];
117
+ string accessToken = null;
118
+ string clientId = null;
119
+ string tenantId = null;
120
+ bool interactive = false;
121
+
122
+ for (int i = 3; i < args.Length; i++)
123
+ {
124
+ if (args[i] == "--access-token" && i + 1 < args.Length)
125
+ accessToken = args[++i];
126
+ else if (args[i] == "--interactive")
127
+ interactive = true;
128
+ else if (args[i] == "--client-id" && i + 1 < args.Length)
129
+ clientId = args[++i];
130
+ else if (args[i] == "--tenant-id" && i + 1 < args.Length)
131
+ tenantId = args[++i];
132
+ }
133
+
134
+ // Acquire token interactively if requested
135
+ if (interactive && string.IsNullOrEmpty(accessToken))
136
+ {
137
+ accessToken = await AcquireTokenInteractive(clientId, tenantId);
138
+ }
139
+
140
+ Console.Error.Write("Extracting VPAX metadata...");
141
+
142
+ Dax.Metadata.Model daxModel;
143
+
144
+ Tom.Database database;
145
+
146
+ if (!string.IsNullOrEmpty(accessToken))
147
+ {
148
+ var asAccessToken = new AccessToken(accessToken, DateTimeOffset.UtcNow.AddHours(1));
149
+
150
+ // Connect with token, then extract with stats
151
+ database = TomExtractor.GetDatabase(connectionString, asAccessToken,
152
+ onTokenExpired: (expired) => asAccessToken);
153
+
154
+ daxModel = TomExtractor.GetDaxModel(
155
+ connectionString: connectionString,
156
+ applicationName: "vpax-bridge",
157
+ applicationVersion: "1.0.0",
158
+ readStatisticsFromData: true,
159
+ sampleRows: 0,
160
+ analyzeDirectQuery: false,
161
+ statsColumnBatchSize: 50,
162
+ accessToken: asAccessToken,
163
+ onTokenExpired: (expired) => asAccessToken
164
+ );
165
+ }
166
+ else
167
+ {
168
+ // No token — local PBI Desktop
169
+ database = TomExtractor.GetDatabase(connectionString);
170
+
171
+ daxModel = TomExtractor.GetDaxModel(
172
+ connectionString: connectionString,
173
+ applicationName: "vpax-bridge",
174
+ applicationVersion: "1.0.0",
175
+ readStatisticsFromData: true,
176
+ sampleRows: 0,
177
+ analyzeDirectQuery: false,
178
+ statsColumnBatchSize: 50
179
+ );
180
+ }
181
+
182
+ return WriteVpax(outputPath, daxModel, database);
183
+ }
184
+
185
+ /// <summary>Export VPAX from a local TMDL folder (offline, no server needed).</summary>
186
+ static int ExportFromTmdl(string outputPath, string tmdlFolder)
187
+ {
188
+ Console.Error.Write("Loading TMDL model...");
189
+
190
+ var folder = tmdlFolder;
191
+ if (!File.Exists(Path.Combine(folder, "database.tmdl")))
192
+ {
193
+ var defFolder = Path.Combine(folder, "definition");
194
+ if (File.Exists(Path.Combine(defFolder, "database.tmdl")))
195
+ folder = defFolder;
196
+ else
197
+ throw new FileNotFoundException(
198
+ $"database.tmdl not found in '{tmdlFolder}' or '{defFolder}'. " +
199
+ "Point to the folder containing database.tmdl or the .SemanticModel folder.");
200
+ }
201
+
202
+ var database = Tom.TmdlSerializer.DeserializeDatabaseFromFolder(folder);
203
+ Console.Error.Write($"loaded '{database.Name ?? "Model"}' ({database.Model.Tables.Count} tables)...");
204
+
205
+ var daxModel = TomExtractor.GetDaxModel(database.Model, "vpax-bridge", "1.0.0");
206
+
207
+ return WriteVpax(outputPath, daxModel);
208
+ }
209
+
210
+ static int WriteVpax(string outputPath, Dax.Metadata.Model daxModel, Tom.Database database = null)
211
+ {
212
+ Console.Error.Write("done. Exporting VPAX file...");
213
+
214
+ var dir = Path.GetDirectoryName(Path.GetFullPath(outputPath));
215
+ if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir))
216
+ Directory.CreateDirectory(dir);
217
+
218
+ var vpaModel = new Dax.ViewVpaExport.Model(daxModel);
219
+ VpaxTools.ExportVpax(outputPath, daxModel, vpaModel, database);
220
+
221
+ Console.Error.WriteLine("done.");
222
+ Console.WriteLine(outputPath);
223
+ return 0;
224
+ }
225
+ }
@@ -0,0 +1,14 @@
1
+ <Project Sdk="Microsoft.NET.Sdk">
2
+ <PropertyGroup>
3
+ <OutputType>Exe</OutputType>
4
+ <TargetFramework>net8.0</TargetFramework>
5
+ <AssemblyName>vpax-bridge</AssemblyName>
6
+ <RootNamespace>VpaxBridge</RootNamespace>
7
+ </PropertyGroup>
8
+ <ItemGroup>
9
+ <PackageReference Include="Dax.Model.Extractor" Version="1.12.0" />
10
+ <PackageReference Include="Dax.Vpax" Version="1.12.0" />
11
+ <PackageReference Include="Dax.ViewVpaExport" Version="1.12.0" />
12
+ <PackageReference Include="Microsoft.Identity.Client" Version="4.65.0" />
13
+ </ItemGroup>
14
+ </Project>