@sabrish/power-platform-solution-blueprint 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/CHANGELOG.md +166 -0
  2. package/LICENSE +21 -0
  3. package/README.md +331 -0
  4. package/dist/assets/BusinessProcessFlowDiscovery-BSDgBoIA.js +2 -0
  5. package/dist/assets/BusinessProcessFlowDiscovery-BSDgBoIA.js.map +1 -0
  6. package/dist/assets/ColumnSecurityDiscovery-B3yVn0LZ.js +2 -0
  7. package/dist/assets/ColumnSecurityDiscovery-B3yVn0LZ.js.map +1 -0
  8. package/dist/assets/ConnectionReferenceDiscovery-DFTQuo-S.js +2 -0
  9. package/dist/assets/ConnectionReferenceDiscovery-DFTQuo-S.js.map +1 -0
  10. package/dist/assets/CustomAPIDiscovery-BiQS_ENt.js +2 -0
  11. package/dist/assets/CustomAPIDiscovery-BiQS_ENt.js.map +1 -0
  12. package/dist/assets/CustomConnectorDiscovery-TvNjElP3.js +2 -0
  13. package/dist/assets/CustomConnectorDiscovery-TvNjElP3.js.map +1 -0
  14. package/dist/assets/EnvironmentVariableDiscovery-DG_tXCcQ.js +2 -0
  15. package/dist/assets/EnvironmentVariableDiscovery-DG_tXCcQ.js.map +1 -0
  16. package/dist/assets/GlobalChoiceDiscovery-nivz9yGs.js +2 -0
  17. package/dist/assets/GlobalChoiceDiscovery-nivz9yGs.js.map +1 -0
  18. package/dist/assets/HtmlReporter-Cu9NwA6b.js +1894 -0
  19. package/dist/assets/HtmlReporter-Cu9NwA6b.js.map +1 -0
  20. package/dist/assets/JsonReporter-BqDJorX-.js +2 -0
  21. package/dist/assets/JsonReporter-BqDJorX-.js.map +1 -0
  22. package/dist/assets/MarkdownReporter-B1FEpc6-.js +53 -0
  23. package/dist/assets/MarkdownReporter-B1FEpc6-.js.map +1 -0
  24. package/dist/assets/ZipPackager-B4xx8LbF.js +3 -0
  25. package/dist/assets/ZipPackager-B4xx8LbF.js.map +1 -0
  26. package/dist/assets/_baseUniq-Nm59UrQz.js +2 -0
  27. package/dist/assets/_baseUniq-Nm59UrQz.js.map +1 -0
  28. package/dist/assets/arc-BVr5R-xB.js +2 -0
  29. package/dist/assets/arc-BVr5R-xB.js.map +1 -0
  30. package/dist/assets/architectureDiagram-VXUJARFQ-C-olLUHb.js +37 -0
  31. package/dist/assets/architectureDiagram-VXUJARFQ-C-olLUHb.js.map +1 -0
  32. package/dist/assets/blockDiagram-VD42YOAC-B4incSX8.js +123 -0
  33. package/dist/assets/blockDiagram-VD42YOAC-B4incSX8.js.map +1 -0
  34. package/dist/assets/c4Diagram-YG6GDRKO-BJxhcb17.js +11 -0
  35. package/dist/assets/c4Diagram-YG6GDRKO-BJxhcb17.js.map +1 -0
  36. package/dist/assets/channel-CjhOgOS9.js +2 -0
  37. package/dist/assets/channel-CjhOgOS9.js.map +1 -0
  38. package/dist/assets/chunk-4BX2VUAB-BIe6iK-b.js +2 -0
  39. package/dist/assets/chunk-4BX2VUAB-BIe6iK-b.js.map +1 -0
  40. package/dist/assets/chunk-55IACEB6-CA6P5Ey6.js +2 -0
  41. package/dist/assets/chunk-55IACEB6-CA6P5Ey6.js.map +1 -0
  42. package/dist/assets/chunk-B4BG7PRW-licIQLj-.js +166 -0
  43. package/dist/assets/chunk-B4BG7PRW-licIQLj-.js.map +1 -0
  44. package/dist/assets/chunk-DI55MBZ5-CxFpzZDS.js +221 -0
  45. package/dist/assets/chunk-DI55MBZ5-CxFpzZDS.js.map +1 -0
  46. package/dist/assets/chunk-FMBD7UC4-VjnBPAq9.js +16 -0
  47. package/dist/assets/chunk-FMBD7UC4-VjnBPAq9.js.map +1 -0
  48. package/dist/assets/chunk-QN33PNHL-BcMwEixv.js +2 -0
  49. package/dist/assets/chunk-QN33PNHL-BcMwEixv.js.map +1 -0
  50. package/dist/assets/chunk-QZHKN3VN-6eOG0UZ6.js +2 -0
  51. package/dist/assets/chunk-QZHKN3VN-6eOG0UZ6.js.map +1 -0
  52. package/dist/assets/chunk-TZMSLE5B-B38vDpWG.js +2 -0
  53. package/dist/assets/chunk-TZMSLE5B-B38vDpWG.js.map +1 -0
  54. package/dist/assets/classDiagram-2ON5EDUG-CEjpoRuI.js +2 -0
  55. package/dist/assets/classDiagram-2ON5EDUG-CEjpoRuI.js.map +1 -0
  56. package/dist/assets/classDiagram-v2-WZHVMYZB-CEjpoRuI.js +2 -0
  57. package/dist/assets/classDiagram-v2-WZHVMYZB-CEjpoRuI.js.map +1 -0
  58. package/dist/assets/clone-FgHYDKfb.js +2 -0
  59. package/dist/assets/clone-FgHYDKfb.js.map +1 -0
  60. package/dist/assets/cose-bilkent-S5V4N54A-BFz6nI_Q.js +2 -0
  61. package/dist/assets/cose-bilkent-S5V4N54A-BFz6nI_Q.js.map +1 -0
  62. package/dist/assets/cytoscape.esm-CyJtwmzi.js +332 -0
  63. package/dist/assets/cytoscape.esm-CyJtwmzi.js.map +1 -0
  64. package/dist/assets/dagre-6UL2VRFP-B9xCTGce.js +5 -0
  65. package/dist/assets/dagre-6UL2VRFP-B9xCTGce.js.map +1 -0
  66. package/dist/assets/defaultLocale-DX6XiGOO.js +2 -0
  67. package/dist/assets/defaultLocale-DX6XiGOO.js.map +1 -0
  68. package/dist/assets/diagram-PSM6KHXK-BG-mPBdn.js +25 -0
  69. package/dist/assets/diagram-PSM6KHXK-BG-mPBdn.js.map +1 -0
  70. package/dist/assets/diagram-QEK2KX5R-BAd41szY.js +44 -0
  71. package/dist/assets/diagram-QEK2KX5R-BAd41szY.js.map +1 -0
  72. package/dist/assets/diagram-S2PKOQOG-Qhy7nrMX.js +25 -0
  73. package/dist/assets/diagram-S2PKOQOG-Qhy7nrMX.js.map +1 -0
  74. package/dist/assets/erDiagram-Q2GNP2WA-HJD-sygr.js +61 -0
  75. package/dist/assets/erDiagram-Q2GNP2WA-HJD-sygr.js.map +1 -0
  76. package/dist/assets/flowDiagram-NV44I4VS-DcFzPV5l.js +163 -0
  77. package/dist/assets/flowDiagram-NV44I4VS-DcFzPV5l.js.map +1 -0
  78. package/dist/assets/ganttDiagram-JELNMOA3-5hzmn_YM.js +268 -0
  79. package/dist/assets/ganttDiagram-JELNMOA3-5hzmn_YM.js.map +1 -0
  80. package/dist/assets/gitGraphDiagram-NY62KEGX-BJoaRoQP.js +66 -0
  81. package/dist/assets/gitGraphDiagram-NY62KEGX-BJoaRoQP.js.map +1 -0
  82. package/dist/assets/graph-iTkoc_Qp.js +2 -0
  83. package/dist/assets/graph-iTkoc_Qp.js.map +1 -0
  84. package/dist/assets/index-C0N3Q-wf.js +404 -0
  85. package/dist/assets/index-C0N3Q-wf.js.map +1 -0
  86. package/dist/assets/index-Dau71uup.css +1 -0
  87. package/dist/assets/infoDiagram-WHAUD3N6-Dm-9Locf.js +3 -0
  88. package/dist/assets/infoDiagram-WHAUD3N6-Dm-9Locf.js.map +1 -0
  89. package/dist/assets/init-Gi6I4Gst.js +2 -0
  90. package/dist/assets/init-Gi6I4Gst.js.map +1 -0
  91. package/dist/assets/journeyDiagram-XKPGCS4Q-Cn4q49x5.js +140 -0
  92. package/dist/assets/journeyDiagram-XKPGCS4Q-Cn4q49x5.js.map +1 -0
  93. package/dist/assets/kanban-definition-3W4ZIXB7-lUx8-faE.js +90 -0
  94. package/dist/assets/kanban-definition-3W4ZIXB7-lUx8-faE.js.map +1 -0
  95. package/dist/assets/katex-CBSAILhF.js +262 -0
  96. package/dist/assets/katex-CBSAILhF.js.map +1 -0
  97. package/dist/assets/layout-BNMvCxLN.js +2 -0
  98. package/dist/assets/layout-BNMvCxLN.js.map +1 -0
  99. package/dist/assets/linear-OqJg3PPm.js +2 -0
  100. package/dist/assets/linear-OqJg3PPm.js.map +1 -0
  101. package/dist/assets/min-N_DZlU1c.js +2 -0
  102. package/dist/assets/min-N_DZlU1c.js.map +1 -0
  103. package/dist/assets/mindmap-definition-VGOIOE7T-C43AGCOz.js +69 -0
  104. package/dist/assets/mindmap-definition-VGOIOE7T-C43AGCOz.js.map +1 -0
  105. package/dist/assets/ordinal-Cboi1Yqb.js +2 -0
  106. package/dist/assets/ordinal-Cboi1Yqb.js.map +1 -0
  107. package/dist/assets/pieDiagram-ADFJNKIX-COl1BPcc.js +31 -0
  108. package/dist/assets/pieDiagram-ADFJNKIX-COl1BPcc.js.map +1 -0
  109. package/dist/assets/quadrantDiagram-AYHSOK5B-C-fSINkS.js +8 -0
  110. package/dist/assets/quadrantDiagram-AYHSOK5B-C-fSINkS.js.map +1 -0
  111. package/dist/assets/requirementDiagram-UZGBJVZJ-DSag9Z4m.js +65 -0
  112. package/dist/assets/requirementDiagram-UZGBJVZJ-DSag9Z4m.js.map +1 -0
  113. package/dist/assets/sankeyDiagram-TZEHDZUN-JyvYJ7BV.js +11 -0
  114. package/dist/assets/sankeyDiagram-TZEHDZUN-JyvYJ7BV.js.map +1 -0
  115. package/dist/assets/sequenceDiagram-WL72ISMW-GkUPZQOc.js +146 -0
  116. package/dist/assets/sequenceDiagram-WL72ISMW-GkUPZQOc.js.map +1 -0
  117. package/dist/assets/stateDiagram-FKZM4ZOC-DiJHFrza.js +2 -0
  118. package/dist/assets/stateDiagram-FKZM4ZOC-DiJHFrza.js.map +1 -0
  119. package/dist/assets/stateDiagram-v2-4FDKWEC3-BgdSYitm.js +2 -0
  120. package/dist/assets/stateDiagram-v2-4FDKWEC3-BgdSYitm.js.map +1 -0
  121. package/dist/assets/timeline-definition-IT6M3QCI-BIeoFfU5.js +62 -0
  122. package/dist/assets/timeline-definition-IT6M3QCI-BIeoFfU5.js.map +1 -0
  123. package/dist/assets/treemap-KMMF4GRG-BDDqLxLB.js +129 -0
  124. package/dist/assets/treemap-KMMF4GRG-BDDqLxLB.js.map +1 -0
  125. package/dist/assets/xychartDiagram-PRI3JC2R-CUzWjNyv.js +8 -0
  126. package/dist/assets/xychartDiagram-PRI3JC2R-CUzWjNyv.js.map +1 -0
  127. package/dist/index.html +13 -0
  128. package/index.html +12 -0
  129. package/package.json +74 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,166 @@
1
+ # Changelog
2
+
3
+ All notable changes to Power Platform Solution Blueprint will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.5.1] - 2026-02-10
9
+
10
+ ### Changed
11
+
12
+ **Repository Structure**
13
+ - Restructured repository from monorepo to flat structure to comply with PPTB tool development standards
14
+ - Moved `packages/pptb-tool/*` to root directory for proper PPTB Desktop integration
15
+ - Moved `packages/core/src/*` to `src/core/` maintaining logical separation
16
+ - Updated all 47 source files with corrected import paths (replaced workspace references with relative paths)
17
+ - Consolidated package.json files (removed workspace configuration)
18
+ - Preserved documentation and screenshots during restructure
19
+
20
+ **API Integration**
21
+ - Integrated official `@pptb/types` package (v1.0.19) from npm registry
22
+ - Updated all code to use `window.dataverseAPI` global (official PPTB Desktop API structure)
23
+ - Removed custom type definitions in favor of official types
24
+ - Updated `PptbDataverseClient` to accept `DataverseAPI.API` directly instead of nested structure
25
+ - Updated all components to use `await window.toolboxAPI.getToolContext()` (async method)
26
+
27
+ **Documentation**
28
+ - Updated `docs/API_SECURITY.md` to reflect official @pptb/types integration
29
+ - Clarified API connection mechanism and authentication flow
30
+
31
+ ### Fixed
32
+
33
+ **Export Consistency**
34
+ - Fixed ERD exports to generate single comprehensive diagram instead of 3 diagrams
35
+ - HTML exports now show 1 ERD matching the in-tool UI behavior
36
+ - Markdown exports now use only the first (comprehensive) ERD diagram
37
+ - Eliminated redundant publisher-specific diagrams in exported documentation
38
+
39
+ **PPTB Desktop Compatibility**
40
+ - Added `base: './'` to `vite.config.ts` to fix dynamic import path resolution
41
+ - Resolved "Failed to fetch dynamically imported module" error with custom `pptb-webview://` protocol
42
+ - All asset paths now use relative paths compatible with PPTB Desktop's webview environment
43
+
44
+ ### Added
45
+
46
+ **User Interface**
47
+ - Added author attribution to footer ("by SAB" with link to GitHub profile)
48
+ - Enhanced footer with GitHub repository link and Open icon
49
+
50
+ ### Technical Notes
51
+
52
+ **Breaking Changes**
53
+ - Repository structure changed from monorepo to flat layout
54
+ - Import paths changed from workspace references (`@ppsb/core`) to relative paths (`./core` or `../core`)
55
+ - API initialization requires awaiting `getToolContext()` instead of synchronous access
56
+ - `PptbDataverseClient` constructor signature changed to accept `DataverseAPI.API`
57
+
58
+ **Migration Guide**
59
+ - If extending this codebase, use relative imports instead of workspace package references
60
+ - Use `window.dataverseAPI` for Dataverse operations instead of `window.toolboxAPI.dataverse`
61
+ - Always await `window.toolboxAPI.getToolContext()` for tool context access
62
+
63
+ **Dependencies**
64
+ - Added `@pptb/types@^1.0.19` as devDependency (official PPTB Desktop type definitions)
65
+ - Maintained all existing runtime dependencies (React, Fluent UI, Mermaid, JSZip)
66
+
67
+ [0.5.1]: https://github.com/sabrish/power-platform-solution-blueprint/releases/tag/v0.5.1
68
+ ## [0.5.0] - 2026-02-08
69
+
70
+ ### Added
71
+
72
+ **Discovery & Documentation**
73
+ - Complete entity schema discovery (fields, relationships, keys, alternate keys)
74
+ - Plugin discovery with full registration details and execution order analysis
75
+ - Power Automate flow discovery with trigger analysis and external call detection
76
+ - Business rule discovery and parsing (client-side and server-side)
77
+ - Classic workflow discovery with migration recommendations and risk assessment
78
+ - Business Process Flow documentation with stage and step details
79
+ - JavaScript web resource analysis with external call detection and deprecated API warnings (Xrm.Page)
80
+ - Custom API documentation with complete parameter specifications
81
+ - Environment variable discovery and value tracking (critical for ALM)
82
+ - Connection reference discovery with premium connector detection
83
+ - Global choice (shared option set) documentation
84
+ - Security role discovery with entity permissions and special permissions matrices
85
+ - Field security profile discovery
86
+ - Attribute masking rule discovery
87
+ - Column security profile discovery
88
+
89
+ **Analysis & Visualization**
90
+ - Entity Relationship Diagram (ERD) generation using Mermaid with publisher color-coding
91
+ - Execution pipeline visualization showing client → sync → async automation flow per entity
92
+ - Cross-entity automation mapping to identify automation that affects multiple entities
93
+ - External dependency detection and risk analysis (categorized as Trusted/Known/Unknown)
94
+ - Solution distribution analysis showing component breakdown across solutions
95
+ - Entity complexity scoring based on field count, automation density, and relationships
96
+ - Performance risk identification (synchronous plugins with external calls, execution chains)
97
+ - Deprecated API detection (classic workflows, Xrm.Page usage in JavaScript)
98
+
99
+ **Export Formats**
100
+ - Markdown export with complete file structure ready for Azure DevOps Wiki
101
+ - JSON export for programmatic use, baseline storage, and CI/CD integration
102
+ - HTML single-page export with interactive navigation, search, and accordion sections
103
+ - ZIP packaging bundling all formats with organized directory structure
104
+
105
+ **User Interface**
106
+ - Smart scope selection (by publisher, solution, or all entities)
107
+ - Multi-select dropdowns with live filtering and selected item management
108
+ - Real-time progress tracking during generation with phase indicators
109
+ - Interactive results dashboard with tabs and expandable sections
110
+ - ERD view with zoom/pan and entity quick links
111
+ - Entity detail view with complete schema, automation, and execution pipeline
112
+ - Security roles view with interactive accordion and permission matrices
113
+ - Export dialog with format selection and download management
114
+ - Comprehensive error handling with user-friendly messages and retry options
115
+ - Accessibility compliance (WCAG AA standards)
116
+ - Loading states with spinners and progress indicators
117
+ - Responsive design (desktop optimized, mobile functional)
118
+
119
+ **Technical Infrastructure**
120
+ - Monorepo structure with `@ppsb/core` (pure TypeScript) and `@ppsb/pptb-tool` (React UI)
121
+ - PPTB Desktop integration via `window.toolboxAPI`
122
+ - TypeScript 5.x with strict mode and comprehensive type definitions
123
+ - React 18 with Vite 5 for fast development and optimized builds
124
+ - Fluent UI v9 component library (Microsoft Design System)
125
+ - Mermaid diagram rendering for ERD and execution pipelines
126
+ - JSZip for multi-file export packages
127
+ - Performance optimizations (batched queries, in-memory filtering, lazy rendering)
128
+ - Error handling and retry logic for Dataverse API calls
129
+
130
+ ### Development Notes
131
+ - Developed with significant AI collaboration:
132
+ - **ChatGPT (OpenAI)**: Initial brainstorming, concept validation, feature ideation
133
+ - **Claude (Anthropic)**: Detailed architecture design, comprehensive implementation via Claude Code
134
+ - Built on modern web technologies: TypeScript 5.x, React 18, Fluent UI v9, Vite 5
135
+ - Clean architecture with core business logic separated from UI concerns
136
+ - Extensible design for future enhancements and custom analyzers
137
+
138
+ ### Known Limitations
139
+ - **Canvas Apps**: Metadata only (description, connection references) due to API limitations
140
+ - **Custom Pages**: Metadata only (no component-level analysis available)
141
+ - **Power Pages**: Only included if deployed to Dataverse (site settings, web files)
142
+ - **Customer Insights - Journeys**: Not included in v0.5 (planned for future version)
143
+ - **Baseline Comparison**: Planned for v0.6 (compare current state against saved JSON baseline)
144
+ - **CLI Tool**: Planned for v0.6 (command-line interface for automation)
145
+ - **CI/CD Integration**: Planned for v0.6 (GitHub Actions, Azure DevOps tasks)
146
+ - **Plugin Code Analysis**: Not available (requires source code access, most plugins are compiled DLLs)
147
+ - **Custom Connector Details**: Metadata only (OpenAPI spec not accessible via Dataverse API)
148
+ - **Large Environments**: May take 10-20 minutes for environments with 500+ entities and complex automation
149
+
150
+ ### Performance Considerations
151
+ - **Query Optimization**: Batched queries reduce API calls from thousands to hundreds
152
+ - **GUID Normalization**: Proper GUID handling prevents silent failures in OData filters
153
+ - **Selective $select**: Only requests needed fields to minimize payload size
154
+ - **Strategic $expand**: Fetches related data when always needed to reduce round-trips
155
+ - **In-Memory Filtering**: Client-side filtering when server-side options are limited
156
+ - **Lazy Rendering**: Large tables and diagrams render only when viewed
157
+ - **Progress Tracking**: Real-time feedback during long-running operations
158
+
159
+ ### Security & Privacy
160
+ - **No Data Storage**: PPSB never stores your Dataverse data on external servers
161
+ - **Local Processing**: All analysis happens client-side in your browser
162
+ - **Export Control**: You control where exported files are saved
163
+ - **Connection Security**: Uses PPTB Desktop's existing authenticated connection
164
+ - **No Telemetry**: No usage data collected or transmitted
165
+
166
+ [0.5.0]: https://github.com/sabrish/power-platform-solution-blueprint/releases/tag/v0.5.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SAB
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,331 @@
1
+ # Power Platform Solution Blueprint (PPSB)
2
+
3
+ > Complete architectural blueprints for your Power Platform solutions.
4
+
5
+ ![Version](https://img.shields.io/badge/version-0.5.1-blue)
6
+ ![Status](https://img.shields.io/badge/status-initial%20release-green)
7
+
8
+ Generate comprehensive technical documentation for Dataverse and Power Platform solutions with automated discovery, analysis, and export capabilities.
9
+
10
+ ---
11
+
12
+ ## 🎯 What is PPSB?
13
+
14
+ **PPSB** is an automated documentation tool that generates complete architectural blueprints for Power Platform solutions. It discovers, analyzes, and documents your entire Dataverse environment—from entity schemas to automation pipelines—saving architects and developers hundreds of hours of manual documentation work.
15
+
16
+ The tool generates **comprehensive blueprints** including Entity Relationship Diagrams (ERD), complete entity documentation with automation execution pipelines, cross-entity automation mapping, external dependency analysis, and solution distribution breakdowns. All exports are production-ready: Markdown files ready for Azure DevOps Wiki, JSON for programmatic analysis, and self-contained HTML for stakeholder sharing.
17
+
18
+ PPSB benefits **solution architects** (system documentation), **developers** (onboarding and reference), **governance teams** (compliance and dependency tracking), and **consultants** (assessment and migration planning). Primary use cases include technical documentation generation, governance and compliance auditing, performance analysis, and migration planning.
19
+
20
+ ---
21
+
22
+ ## ✨ Key Features
23
+
24
+ <details>
25
+ <summary><b>📋 Discovery & Documentation</b> (click to expand)</summary>
26
+
27
+ - **Entities**: Complete schema (fields, relationships, keys, alternate keys)
28
+ - **Plugins**: Full registration details with execution order analysis
29
+ - **Power Automate Flows**: Trigger analysis, connection references, external calls
30
+ - **Business Rules**: Client-side and server-side with condition parsing
31
+ - **Classic Workflows**: Documentation with migration recommendations and risk assessment
32
+ - **Business Process Flows**: Stage and step documentation
33
+ - **JavaScript Web Resources**: Code analysis with external call detection and deprecated API warnings
34
+ - **Custom APIs**: Complete parameter documentation and privilege requirements
35
+ - **Environment Variables**: Value tracking critical for ALM
36
+ - **Connection References**: Premium connector detection for licensing
37
+ - **Global Choices**: Shared option sets with usage tracking
38
+ - **Security**: Roles, field security profiles, attribute masking, column security
39
+
40
+ </details>
41
+
42
+ <details>
43
+ <summary><b>📊 Analysis & Visualization</b> (click to expand)</summary>
44
+
45
+ - **Entity Relationship Diagram (ERD)**: Mermaid diagram with publisher color-coding and relationship types
46
+ - **Execution Pipeline**: Visual representation of client → sync → async automation flow per entity
47
+ - **Cross-Entity Automation**: Map automation that creates/updates records across entity boundaries
48
+ - **External Dependencies**: Detect and risk-assess all external API calls (flows, plugins, web resources)
49
+ - **Solution Distribution**: Component breakdown across solutions with dependency mapping
50
+ - **Entity Complexity**: Scoring based on field count, automation density, and relationship complexity
51
+ - **Performance Risks**: Identify synchronous plugins with external calls, long execution chains
52
+
53
+ </details>
54
+
55
+ <details>
56
+ <summary><b>💾 Export Formats</b> (click to expand)</summary>
57
+
58
+ - **Markdown**: Complete file structure ready for Azure DevOps Wiki upload
59
+ - **JSON**: Full data export for programmatic use, baselines, and CI/CD pipelines
60
+ - **HTML**: Single-page interactive document with navigation, search, and accordion sections
61
+ - **ZIP**: All formats bundled together with organized directory structure
62
+
63
+ </details>
64
+
65
+ <details>
66
+ <summary><b>🔍 Smart Scope Selection</b> (click to expand)</summary>
67
+
68
+ - **By Publisher**: Select one or more publishers to document all their solutions
69
+ - **By Solution**: Choose specific solutions regardless of publisher
70
+ - **By Entity**: Document all entities (with optional system entity inclusion)
71
+ - **Filtering**: Multi-select with live filtering and selected item management
72
+
73
+ </details>
74
+
75
+ ---
76
+
77
+ ## 🚀 Quick Start
78
+
79
+ 1. **Install**: Add PPSB to your PPTB Desktop tools directory
80
+ 2. **Launch**: Open PPSB from PPTB Desktop with an active Dataverse connection
81
+ 3. **Select Scope**: Choose publisher(s), solution(s), or all entities
82
+ 4. **Generate**: Click "Generate Blueprint" and wait for discovery and analysis
83
+ 5. **Review**: Explore the interactive results with ERD, entity details, and automation analysis
84
+ 6. **Export**: Download as Markdown, JSON, HTML, or ZIP bundle
85
+ 7. **Use**: Upload Markdown to Azure DevOps Wiki or share HTML with stakeholders
86
+
87
+ 📖 **[Detailed User Guide](docs/user-guide.md)** |
88
+ 📊 **[Example Output Structure](docs/examples/example-output-structure.md)** |
89
+ 🏗️ **[Architecture Documentation](docs/architecture.md)**
90
+
91
+ ---
92
+
93
+ ## 📸 Screenshots
94
+
95
+ ### Scope Selection
96
+ Choose what to document - by publisher or solution with multi-select filtering.
97
+
98
+ ![Scope Selection](docs/screenshots/PPSB-1-What%20to%20document-selector.png)
99
+
100
+ ### Confirmation Screen
101
+ Review your selection before generating the blueprint.
102
+
103
+ ![Generator Confirmation](docs/screenshots/PPSB-2-Generator-Confirmation.png)
104
+
105
+ ### Results Dashboard
106
+ Interactive dashboard with summary metrics, ERD visualization, and component browser.
107
+
108
+ ![Dashboard](docs/screenshots/PPSB-3-Dashboard.png)
109
+
110
+ ### Component Details
111
+ Browse and explore all discovered components with expandable details and inline documentation.
112
+
113
+ ![Component Details](docs/screenshots/PPSB-4-Component-Details.png)
114
+
115
+ ### Solution Distribution Analysis
116
+ Analyze component distribution across solutions with dependency mapping and shared component detection.
117
+
118
+ ![Solution Distribution Analysis](docs/screenshots/PPSB-5-Solution%20Distrubution%20Analysis.png)
119
+
120
+ ### External Dependencies Analysis
121
+ Identify and assess all external API calls across flows, plugins, and web resources with risk scoring.
122
+
123
+ ![External Dependencies Analysis](docs/screenshots/PPSB-6-External%20Dependencies%20Analysis.png)
124
+
125
+ ### Export Options
126
+ Choose your export format - Markdown, JSON, HTML, or ZIP bundle.
127
+
128
+ ![Export Options](docs/screenshots/PPSB-6-Export%20Options.png)
129
+
130
+ ### HTML Export
131
+ Self-contained, interactive HTML documentation ready to share with stakeholders.
132
+
133
+ ![HTML Export Example 1](docs/screenshots/PPSB-7-Export%20html.png)
134
+
135
+ ![HTML Export Example 2](docs/screenshots/PPSB-8-Export%20html.png)
136
+
137
+ ---
138
+
139
+ ## 💡 Use Cases
140
+
141
+ ### Architecture Documentation
142
+ - **Onboarding**: Generate complete system docs for new team members joining projects
143
+ - **Proposals**: Create technical specifications and architecture diagrams for client proposals
144
+ - **Handover**: Provide comprehensive documentation during project transitions
145
+
146
+ ### Governance & Compliance
147
+ - **External Dependencies**: Identify all external API calls for security review and approval
148
+ - **Premium Connectors**: Track premium connector usage for accurate licensing compliance
149
+ - **Environment Variables**: Monitor configuration management and ALM readiness
150
+ - **Security Audit**: Document all security roles, field security, and data masking rules
151
+
152
+ ### Performance Analysis
153
+ - **Bottleneck Detection**: Find synchronous plugins with external calls blocking transactions
154
+ - **Execution Chains**: Identify complex automation sequences that may cause performance issues
155
+ - **Optimization Planning**: Prioritize refactoring based on complexity scores and risk levels
156
+
157
+ ### Migration Planning
158
+ - **Classic Workflow Assessment**: Identify all workflows requiring migration to cloud flows
159
+ - **Complexity Analysis**: Get detailed migration recommendations with step-by-step guidance
160
+ - **Dependency Mapping**: Understand cross-entity automation before migration
161
+
162
+ 📖 **[More Use Cases in User Guide](docs/user-guide.md#common-use-cases)**
163
+
164
+ ---
165
+
166
+ ## 🔧 Technical Stack
167
+
168
+ - **Language**: TypeScript 5.x (strict mode)
169
+ - **UI Framework**: React 18 + Vite 5
170
+ - **Component Library**: Fluent UI v9 (Microsoft Design System)
171
+ - **Diagrams**: Mermaid (ERD and execution pipelines)
172
+ - **Export**: JSZip (multi-file packages)
173
+ - **Architecture**: Flat structure with separated core logic (`src/core/`) and React UI (`src/components/`)
174
+
175
+ 🏗️ **[Architecture Details](docs/architecture.md)** |
176
+ 🛣️ **[Roadmap](docs/roadmap.md)**
177
+
178
+ ---
179
+
180
+ ## 🚦 Installation
181
+
182
+ ### For PPTB Desktop Users
183
+
184
+ 1. Available in the PPTB Marketplace
185
+
186
+ ### For Development
187
+
188
+ ```bash
189
+ # Clone repository
190
+ git clone https://github.com/sabrish/power-platform-solution-blueprint.git
191
+ cd power-platform-solution-blueprint
192
+
193
+ # Install dependencies
194
+ pnpm install
195
+
196
+ # Run development server
197
+ pnpm dev
198
+
199
+ # Build for production
200
+ pnpm build
201
+
202
+ # Type check
203
+ pnpm typecheck
204
+ ```
205
+
206
+ **Development Requirements:**
207
+ - Node.js 18+ and pnpm 8+
208
+ - PPTB Desktop for testing (connects to Dataverse)
209
+ - Windows, macOS, or Linux
210
+
211
+ ---
212
+
213
+ ## 📚 Documentation
214
+
215
+ Comprehensive documentation for all aspects of PPSB:
216
+
217
+ - **[User Guide](docs/user-guide.md)** - Complete usage instructions from scope selection to export
218
+ - **[Architecture](docs/architecture.md)** - Technical design, component structure, and extension points
219
+ - **[API Security](docs/API_SECURITY.md)** - Complete API reference, security considerations, and data access documentation
220
+ - **[Roadmap](docs/roadmap.md)** - Future versions (baseline comparison, CLI, CI/CD integration)
221
+ - **[Examples](docs/examples/)** - Sample outputs and documentation structure
222
+ - [Output Structure](docs/examples/example-output-structure.md)
223
+ - [Sample ERD](docs/examples/sample-erd.md)
224
+ - [Sample Entity Documentation](docs/examples/sample-entity-doc.md)
225
+ - **[Changelog](CHANGELOG.md)** - Version history and release notes
226
+
227
+ ---
228
+
229
+ ## 🙏 Credits & Acknowledgments
230
+
231
+ ### Development Team
232
+ - **Primary Developer**: [SAB](https://github.com/sabrish)
233
+
234
+ ### AI Collaboration
235
+
236
+ This project was developed with significant AI assistance:
237
+
238
+ - **ChatGPT (OpenAI)**: Initial brainstorming, concept validation, feature ideation, and requirements exploration. Helped refine the vision for what PPSB should be and validated technical approaches.
239
+
240
+ - **Claude (Anthropic)**: Detailed architecture design, comprehensive implementation planning, and hands-on code development via **Claude Code**. Provided deep technical expertise for TypeScript/React implementation, Dataverse API integration, performance optimization strategies, and accessibility compliance.
241
+
242
+ The combination of AI tools accelerated development while maintaining high code quality and architectural consistency. ChatGPT helped explore possibilities and refine the product vision, while Claude provided meticulous technical implementation with thousands of lines of production-ready code.
243
+
244
+ **AI Development Approach:**
245
+ - Architecture designed through iterative collaboration with Claude
246
+ - Implementation executed via Claude Code (AI-assisted coding)
247
+ - Code reviews and optimization suggestions from both AI assistants
248
+ - Documentation structure and content refined with AI input
249
+
250
+ ### Technology
251
+
252
+ - **PPTB Desktop** - [Power Platform Toolbox](https://www.powerplatformtoolbox.com/) (platform for PPSB deployment)
253
+ - **Microsoft Dataverse** - Data platform and APIs
254
+ - **Fluent UI** - Microsoft's design system and React components
255
+ - **Mermaid** - Diagram rendering engine for ERD and pipeline visualizations
256
+ - **TypeScript** - Language and type system
257
+ - **React** - UI framework
258
+ - **Vite** - Build tool and development server
259
+
260
+ ### Open Source Libraries
261
+
262
+ - JSZip (ZIP file generation)
263
+ - React Router (navigation)
264
+ - Various TypeScript utilities and type definitions
265
+
266
+ ### Community
267
+
268
+ Thanks to the Power Platform community for inspiration, feedback, and the collective knowledge that shaped PPSB's feature set and use cases.
269
+
270
+ ---
271
+
272
+ ## 🛣️ Roadmap Highlights
273
+
274
+ PPSB is under active development with exciting features planned:
275
+
276
+ **Baseline Comparison & Automation**
277
+ - Baseline comparison (load previous JSON and detect changes)
278
+ - Change detection with risk assessment
279
+ - Command-line interface (CLI) for automation
280
+ - CI/CD integration (GitHub Actions, Azure DevOps)
281
+
282
+ **Enhanced Analysis**
283
+ - Impact analysis ("What breaks if I delete this?")
284
+ - Unused component detection
285
+ - Business process mining
286
+ - Custom analysis rules
287
+
288
+ **Extended Platform Support**
289
+ - Canvas Apps (enhanced with screen analysis)
290
+ - Power Pages (forms, lists, Liquid templates)
291
+ - Customer Insights & Marketing (journeys, segments, email templates)
292
+ - Additional component types (30+ new types)
293
+
294
+ **Enterprise Features**
295
+ - Performance benchmarking
296
+ - Multi-environment comparison
297
+ - Multi-tenant support
298
+ - Advanced visualizations and AI-powered insights
299
+
300
+ 📖 **[Full Roadmap](docs/roadmap.md)**
301
+
302
+ ---
303
+
304
+ ## 📄 License
305
+
306
+ [MIT License](LICENSE)
307
+
308
+ Copyright © 2026 SAB. All rights reserved.
309
+
310
+ ---
311
+
312
+ ## 💬 Support
313
+
314
+ - **Issues**: [GitHub Issues](https://github.com/sabrish/power-platform-solution-blueprint/issues) - Report bugs or request features
315
+ - **Discussions**: [GitHub Discussions](https://github.com/sabrish/power-platform-solution-blueprint/discussions) - Ask questions and share ideas
316
+ - **Documentation**: [docs/](docs/) - Comprehensive guides and examples
317
+
318
+ ---
319
+
320
+ ## 🌟 Quick Links
321
+
322
+ - [Installation](#installation)
323
+ - [User Guide](docs/user-guide.md)
324
+ - [Architecture](docs/architecture.md)
325
+ - [Roadmap](docs/roadmap.md)
326
+ - [Changelog](CHANGELOG.md)
327
+ - [Examples](docs/examples/)
328
+
329
+ ---
330
+
331
+ **Made with ❤️ for the Power Platform community**
@@ -0,0 +1,2 @@
1
+ var g=Object.defineProperty;var p=(a,e,t)=>e in a?g(a,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[e]=t;var m=(a,e,t)=>p(a,typeof e!="symbol"?e+"":e,t);class f{constructor(e,t){m(this,"client");m(this,"onProgress");this.client=e,this.onProgress=t}async getBusinessProcessFlowsByIds(e){if(e.length===0)return[];try{const n=[];for(let s=0;s<e.length;s+=20){const c=`(${e.slice(s,s+20).map(l=>`workflowid eq ${l.replace(/[{}]/g,"")}`).join(" or ")}) and category eq 4`,i=await this.client.query("workflows",{select:["workflowid","name","description","category","uniquename","primaryentity","statecode","xaml","ismanaged","createdon","modifiedon","_ownerid_value"],filter:c,orderBy:["primaryentity asc","name asc"]});n.push(...i.value),this.onProgress&&this.onProgress(n.length,e.length)}return n.map(s=>this.mapToBusinessProcessFlow(s))}catch(t){throw new Error(`Failed to retrieve Business Process Flows: ${t instanceof Error?t.message:"Unknown error"}`)}}mapToBusinessProcessFlow(e){const t=this.parseXaml(e.xaml);return{id:e.workflowid,name:e.name,description:e.description,primaryEntity:e.primaryentity,primaryEntityDisplayName:e["_primaryentity_value@OData.Community.Display.V1.FormattedValue"]||null,state:this.getStateName(e.statecode),stateCode:e.statecode,isManaged:e.ismanaged,uniqueName:e.uniquename,xaml:e.xaml,definition:t,owner:e["_ownerid_value@OData.Community.Display.V1.FormattedValue"]||"Unknown",ownerId:e._ownerid_value||"",modifiedBy:e["_modifiedby_value@OData.Community.Display.V1.FormattedValue"]||"Unknown",modifiedOn:e.modifiedon,createdOn:e.createdon}}parseXaml(e){const t=[];try{const n=/<mxswa:Stage[^>]*EntityName="([^"]+)"[^>]*StageName="([^"]+)"[^>]*StageId="([^"]+)"[^>]*>/gi;let s,u=0;for(;(s=n.exec(e))!==null;){const o=s[1],d=s[2],y=s[3];t.push({id:y,name:d,entity:o,order:u++,steps:[]})}const r=[...new Set(t.map(o=>o.entity))],c=/<mxswa:Step[^>]*>/gi,i=e.match(c),l=i?i.length:0;return{stages:t,entities:r,totalSteps:l,crossEntityFlow:r.length>1}}catch(n){return{stages:[],entities:[],totalSteps:0,crossEntityFlow:!1,parseError:n instanceof Error?n.message:"Failed to parse XAML"}}}getStateName(e){switch(e){case 0:return"Draft";case 1:return"Active";default:return"Draft"}}}export{f as BusinessProcessFlowDiscovery};
2
+ //# sourceMappingURL=BusinessProcessFlowDiscovery-BSDgBoIA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BusinessProcessFlowDiscovery-BSDgBoIA.js","sources":["../../src/core/discovery/BusinessProcessFlowDiscovery.ts"],"sourcesContent":["import type { IDataverseClient } from '../dataverse/IDataverseClient.js';\nimport type { BusinessProcessFlow } from '../types/businessProcessFlow.js';\n\n/**\n * Raw BPF data from Dataverse\n */\ninterface RawBusinessProcessFlow {\n workflowid: string;\n name: string;\n description: string | null;\n category: number; // Must be 4 for BPFs\n uniquename: string;\n primaryentity: string;\n statecode: number;\n xaml: string;\n ismanaged: boolean;\n createdon: string;\n modifiedon: string;\n _ownerid_value?: string;\n '_ownerid_value@OData.Community.Display.V1.FormattedValue'?: string;\n '_modifiedby_value@OData.Community.Display.V1.FormattedValue'?: string;\n '_primaryentity_value@OData.Community.Display.V1.FormattedValue'?: string;\n}\n\n/**\n * Discovers Business Process Flows (category=4)\n */\nexport class BusinessProcessFlowDiscovery {\n private readonly client: IDataverseClient;\n private onProgress?: (current: number, total: number) => void;\n\n constructor(client: IDataverseClient, onProgress?: (current: number, total: number) => void) {\n this.client = client;\n this.onProgress = onProgress;\n }\n\n /**\n * Get BPFs by their IDs\n * @param workflowIds Array of workflow IDs\n * @returns Array of Business Process Flows\n */\n async getBusinessProcessFlowsByIds(workflowIds: string[]): Promise<BusinessProcessFlow[]> {\n if (workflowIds.length === 0) {\n return [];\n }\n\n try {\n const batchSize = 20;\n const allResults: RawBusinessProcessFlow[] = [];\n\n for (let i = 0; i < workflowIds.length; i += batchSize) {\n const batch = workflowIds.slice(i, i + batchSize);\n const filterClauses = batch.map((id) => {\n const cleanGuid = id.replace(/[{}]/g, '');\n return `workflowid eq ${cleanGuid}`;\n });\n const filter = `(${filterClauses.join(' or ')}) and category eq 4`;\n\n const result = await this.client.query<RawBusinessProcessFlow>('workflows', {\n select: [\n 'workflowid',\n 'name',\n 'description',\n 'category',\n 'uniquename',\n 'primaryentity',\n 'statecode',\n 'xaml',\n 'ismanaged',\n 'createdon',\n 'modifiedon',\n '_ownerid_value',\n ],\n filter,\n orderBy: ['primaryentity asc', 'name asc'],\n });\n\n allResults.push(...result.value);\n\n // Report progress after each batch\n if (this.onProgress) {\n this.onProgress(allResults.length, workflowIds.length);\n }\n }\n\n // Map to BusinessProcessFlow objects\n return allResults.map((raw) => this.mapToBusinessProcessFlow(raw));\n } catch (error) {\n throw new Error(\n `Failed to retrieve Business Process Flows: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n }\n\n /**\n * Map raw data to BusinessProcessFlow\n */\n private mapToBusinessProcessFlow(raw: RawBusinessProcessFlow): BusinessProcessFlow {\n const definition = this.parseXaml(raw.xaml);\n\n return {\n id: raw.workflowid,\n name: raw.name,\n description: raw.description,\n primaryEntity: raw.primaryentity,\n primaryEntityDisplayName:\n raw['_primaryentity_value@OData.Community.Display.V1.FormattedValue'] || null,\n state: this.getStateName(raw.statecode),\n stateCode: raw.statecode,\n isManaged: raw.ismanaged,\n uniqueName: raw.uniquename,\n xaml: raw.xaml,\n definition,\n owner: raw['_ownerid_value@OData.Community.Display.V1.FormattedValue'] || 'Unknown',\n ownerId: raw._ownerid_value || '',\n modifiedBy: raw['_modifiedby_value@OData.Community.Display.V1.FormattedValue'] || 'Unknown',\n modifiedOn: raw.modifiedon,\n createdOn: raw.createdon,\n };\n }\n\n /**\n * Parse XAML to extract BPF definition\n */\n private parseXaml(xaml: string): {\n stages: Array<{\n id: string;\n name: string;\n entity: string;\n order: number;\n steps: Array<{\n id: string;\n name: string;\n fieldName: string;\n required: boolean;\n order: number;\n }>;\n }>;\n entities: string[];\n totalSteps: number;\n crossEntityFlow: boolean;\n parseError?: string;\n } {\n const stages: Array<{\n id: string;\n name: string;\n entity: string;\n order: number;\n steps: Array<{\n id: string;\n name: string;\n fieldName: string;\n required: boolean;\n order: number;\n }>;\n }> = [];\n\n try {\n // Extract stage information from XAML\n // Pattern: <mxswa:Stage ... EntityName=\"entityname\" StageName=\"stagename\" ...>\n const stageRegex =\n /<mxswa:Stage[^>]*EntityName=\"([^\"]+)\"[^>]*StageName=\"([^\"]+)\"[^>]*StageId=\"([^\"]+)\"[^>]*>/gi;\n let stageMatch;\n let order = 0;\n\n while ((stageMatch = stageRegex.exec(xaml)) !== null) {\n const entity = stageMatch[1];\n const name = stageMatch[2];\n const id = stageMatch[3];\n\n stages.push({\n id,\n name,\n entity,\n order: order++,\n steps: [], // Would need more complex parsing to extract steps\n });\n }\n\n // Extract unique entities\n const entities = [...new Set(stages.map((s) => s.entity))];\n\n // Calculate total steps (would need to parse step elements)\n const stepRegex = /<mxswa:Step[^>]*>/gi;\n const stepMatches = xaml.match(stepRegex);\n const totalSteps = stepMatches ? stepMatches.length : 0;\n\n return {\n stages,\n entities,\n totalSteps,\n crossEntityFlow: entities.length > 1,\n };\n } catch (error) {\n return {\n stages: [],\n entities: [],\n totalSteps: 0,\n crossEntityFlow: false,\n parseError: error instanceof Error ? error.message : 'Failed to parse XAML',\n };\n }\n }\n\n /**\n * Get state name\n */\n private getStateName(statecode: number): 'Draft' | 'Active' {\n switch (statecode) {\n case 0:\n return 'Draft';\n case 1:\n return 'Active';\n default:\n return 'Draft';\n }\n }\n}\n"],"names":["BusinessProcessFlowDiscovery","client","onProgress","__publicField","workflowIds","allResults","i","filter","id","result","raw","error","definition","xaml","stages","stageRegex","stageMatch","order","entity","name","entities","s","stepRegex","stepMatches","totalSteps","statecode"],"mappings":"oKA2BO,MAAMA,CAA6B,CAIxC,YAAYC,EAA0BC,EAAuD,CAH5EC,EAAA,eACTA,EAAA,mBAGN,KAAK,OAASF,EACd,KAAK,WAAaC,CACpB,CAOA,MAAM,6BAA6BE,EAAuD,CACxF,GAAIA,EAAY,SAAW,EACzB,MAAO,CAAA,EAGT,GAAI,CAEF,MAAMC,EAAuC,CAAA,EAE7C,QAASC,EAAI,EAAGA,EAAIF,EAAY,OAAQE,GAAK,GAAW,CAMtD,MAAMC,EAAS,IALDH,EAAY,MAAME,EAAGA,EAAI,EAAS,EACpB,IAAKE,GAExB,iBADWA,EAAG,QAAQ,QAAS,EAAE,CACP,EAClC,EACgC,KAAK,MAAM,CAAC,sBAEvCC,EAAS,MAAM,KAAK,OAAO,MAA8B,YAAa,CAC1E,OAAQ,CACN,aACA,OACA,cACA,WACA,aACA,gBACA,YACA,OACA,YACA,YACA,aACA,gBAAA,EAEF,OAAAF,EACA,QAAS,CAAC,oBAAqB,UAAU,CAAA,CAC1C,EAEDF,EAAW,KAAK,GAAGI,EAAO,KAAK,EAG3B,KAAK,YACP,KAAK,WAAWJ,EAAW,OAAQD,EAAY,MAAM,CAEzD,CAGA,OAAOC,EAAW,IAAKK,GAAQ,KAAK,yBAAyBA,CAAG,CAAC,CACnE,OAASC,EAAO,CACd,MAAM,IAAI,MACR,8CAA8CA,aAAiB,MAAQA,EAAM,QAAU,eAAe,EAAA,CAE1G,CACF,CAKQ,yBAAyBD,EAAkD,CACjF,MAAME,EAAa,KAAK,UAAUF,EAAI,IAAI,EAE1C,MAAO,CACL,GAAIA,EAAI,WACR,KAAMA,EAAI,KACV,YAAaA,EAAI,YACjB,cAAeA,EAAI,cACnB,yBACEA,EAAI,gEAAgE,GAAK,KAC3E,MAAO,KAAK,aAAaA,EAAI,SAAS,EACtC,UAAWA,EAAI,UACf,UAAWA,EAAI,UACf,WAAYA,EAAI,WAChB,KAAMA,EAAI,KACV,WAAAE,EACA,MAAOF,EAAI,0DAA0D,GAAK,UAC1E,QAASA,EAAI,gBAAkB,GAC/B,WAAYA,EAAI,6DAA6D,GAAK,UAClF,WAAYA,EAAI,WAChB,UAAWA,EAAI,SAAA,CAEnB,CAKQ,UAAUG,EAkBhB,CACA,MAAMC,EAYD,CAAA,EAEL,GAAI,CAGF,MAAMC,EACJ,8FACF,IAAIC,EACAC,EAAQ,EAEZ,MAAQD,EAAaD,EAAW,KAAKF,CAAI,KAAO,MAAM,CACpD,MAAMK,EAASF,EAAW,CAAC,EACrBG,EAAOH,EAAW,CAAC,EACnBR,EAAKQ,EAAW,CAAC,EAEvBF,EAAO,KAAK,CACV,GAAAN,EACA,KAAAW,EACA,OAAAD,EACA,MAAOD,IACP,MAAO,CAAA,CAAC,CACT,CACH,CAGA,MAAMG,EAAW,CAAC,GAAG,IAAI,IAAIN,EAAO,IAAKO,GAAMA,EAAE,MAAM,CAAC,CAAC,EAGnDC,EAAY,sBACZC,EAAcV,EAAK,MAAMS,CAAS,EAClCE,EAAaD,EAAcA,EAAY,OAAS,EAEtD,MAAO,CACL,OAAAT,EACA,SAAAM,EACA,WAAAI,EACA,gBAAiBJ,EAAS,OAAS,CAAA,CAEvC,OAAST,EAAO,CACd,MAAO,CACL,OAAQ,CAAA,EACR,SAAU,CAAA,EACV,WAAY,EACZ,gBAAiB,GACjB,WAAYA,aAAiB,MAAQA,EAAM,QAAU,sBAAA,CAEzD,CACF,CAKQ,aAAac,EAAuC,CAC1D,OAAQA,EAAA,CACN,IAAK,GACH,MAAO,QACT,IAAK,GACH,MAAO,SACT,QACE,MAAO,OAAA,CAEb,CACF"}
@@ -0,0 +1,2 @@
1
+ class r{constructor(e){this.client=e}async getAttributeMaskingRules(){return(await this.client.query("attributemaskingrules",{select:["attributemaskingruleid","entitylogicalname","attributelogicalname","maskingtype","maskingformat","description","ismanaged"],orderBy:["entitylogicalname","attributelogicalname"]})).value}async getColumnSecurityProfiles(){return(await this.client.query("columnsecurityprofiles",{select:["columnsecurityprofileid","name","description","ismanaged","organizationid"],orderBy:["name"]})).value}async getColumnPermissions(e){const t=e.replace(/[{}]/g,"");return(await this.client.query("columnpermissions",{select:["columnpermissionid","columnsecurityprofileid","entitylogicalname","attributelogicalname","cancreate","canread","canupdate"],filter:`columnsecurityprofileid eq ${t}`,orderBy:["entitylogicalname","attributelogicalname"]})).value}getMaskingTypeDisplayName(e){switch(e){case 1:return"Full";case 2:return"Partial";case 3:return"Email";case 4:return"Custom";default:return"Unknown"}}}export{r as ColumnSecurityDiscovery};
2
+ //# sourceMappingURL=ColumnSecurityDiscovery-B3yVn0LZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ColumnSecurityDiscovery-B3yVn0LZ.js","sources":["../../src/core/discovery/ColumnSecurityDiscovery.ts"],"sourcesContent":["import type { IDataverseClient } from '../dataverse/IDataverseClient.js';\n\n/**\n * Attribute Masking Rule\n */\nexport interface AttributeMaskingRule {\n attributemaskingruleid: string;\n name?: string; // Optional - may not exist in all Dataverse versions\n entitylogicalname: string;\n attributelogicalname: string;\n maskingtype: number; // 1 = Full, 2 = Partial, 3 = Email, 4 = Custom\n maskingformat?: string;\n description?: string;\n ismanaged: boolean;\n}\n\n/**\n * Column Level Security Profile (Security Masking Rule)\n */\nexport interface ColumnSecurityProfile {\n columnsecurityprofileid: string;\n name: string;\n description?: string;\n ismanaged: boolean;\n organizationid: string;\n}\n\n/**\n * Column Permission (which columns this profile can access)\n */\nexport interface ColumnPermission {\n columnpermissionid: string;\n columnsecurityprofileid: string;\n entitylogicalname: string;\n attributelogicalname: string;\n cancreate: boolean;\n canread: boolean;\n canupdate: boolean;\n}\n\n/**\n * Discovery class for column-level security components\n */\nexport class ColumnSecurityDiscovery {\n constructor(\n private client: IDataverseClient\n ) {}\n\n /**\n * Get all attribute masking rules\n */\n async getAttributeMaskingRules(): Promise<AttributeMaskingRule[]> {\n const result = await this.client.query<AttributeMaskingRule>('attributemaskingrules', {\n select: [\n 'attributemaskingruleid',\n 'entitylogicalname',\n 'attributelogicalname',\n 'maskingtype',\n 'maskingformat',\n 'description',\n 'ismanaged',\n ],\n orderBy: ['entitylogicalname', 'attributelogicalname'],\n });\n\n return result.value;\n }\n\n /**\n * Get column security profiles (security masking rules)\n */\n async getColumnSecurityProfiles(): Promise<ColumnSecurityProfile[]> {\n const result = await this.client.query<ColumnSecurityProfile>('columnsecurityprofiles', {\n select: [\n 'columnsecurityprofileid',\n 'name',\n 'description',\n 'ismanaged',\n 'organizationid',\n ],\n orderBy: ['name'],\n });\n\n return result.value;\n }\n\n /**\n * Get column permissions for a specific profile\n */\n async getColumnPermissions(profileId: string): Promise<ColumnPermission[]> {\n const cleanId = profileId.replace(/[{}]/g, '');\n\n const result = await this.client.query<ColumnPermission>('columnpermissions', {\n select: [\n 'columnpermissionid',\n 'columnsecurityprofileid',\n 'entitylogicalname',\n 'attributelogicalname',\n 'cancreate',\n 'canread',\n 'canupdate',\n ],\n filter: `columnsecurityprofileid eq ${cleanId}`,\n orderBy: ['entitylogicalname', 'attributelogicalname'],\n });\n\n return result.value;\n }\n\n /**\n * Get masking type display name\n */\n getMaskingTypeDisplayName(maskingType: number): string {\n switch (maskingType) {\n case 1:\n return 'Full';\n case 2:\n return 'Partial';\n case 3:\n return 'Email';\n case 4:\n return 'Custom';\n default:\n return 'Unknown';\n }\n }\n}\n"],"names":["ColumnSecurityDiscovery","client","profileId","cleanId","maskingType"],"mappings":"AA2CO,MAAMA,CAAwB,CACnC,YACUC,EACR,CADQ,KAAA,OAAAA,CACP,CAKH,MAAM,0BAA4D,CAchE,OAbe,MAAM,KAAK,OAAO,MAA4B,wBAAyB,CACpF,OAAQ,CACN,yBACA,oBACA,uBACA,cACA,gBACA,cACA,WAAA,EAEF,QAAS,CAAC,oBAAqB,sBAAsB,CAAA,CACtD,GAEa,KAChB,CAKA,MAAM,2BAA8D,CAYlE,OAXe,MAAM,KAAK,OAAO,MAA6B,yBAA0B,CACtF,OAAQ,CACN,0BACA,OACA,cACA,YACA,gBAAA,EAEF,QAAS,CAAC,MAAM,CAAA,CACjB,GAEa,KAChB,CAKA,MAAM,qBAAqBC,EAAgD,CACzE,MAAMC,EAAUD,EAAU,QAAQ,QAAS,EAAE,EAgB7C,OAde,MAAM,KAAK,OAAO,MAAwB,oBAAqB,CAC5E,OAAQ,CACN,qBACA,0BACA,oBACA,uBACA,YACA,UACA,WAAA,EAEF,OAAQ,8BAA8BC,CAAO,GAC7C,QAAS,CAAC,oBAAqB,sBAAsB,CAAA,CACtD,GAEa,KAChB,CAKA,0BAA0BC,EAA6B,CACrD,OAAQA,EAAA,CACN,IAAK,GACH,MAAO,OACT,IAAK,GACH,MAAO,UACT,IAAK,GACH,MAAO,QACT,IAAK,GACH,MAAO,SACT,QACE,MAAO,SAAA,CAEb,CACF"}
@@ -0,0 +1,2 @@
1
+ var l=Object.defineProperty;var d=(o,e,n)=>e in o?l(o,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):o[e]=n;var i=(o,e,n)=>d(o,typeof e!="symbol"?e+"":e,n);class h{constructor(e,n){i(this,"client");i(this,"onProgress");this.client=e,this.onProgress=n}async getConnectionReferencesByIds(e){if(e.length===0)return[];try{const c=[];for(let t=0;t<e.length;t+=20){const r=e.slice(t,t+20).map(a=>`connectionreferenceid eq ${a.replace(/[{}]/g,"")}`).join(" or "),s=await this.client.query("connectionreferences",{select:["connectionreferenceid","connectionreferencelogicalname","connectionreferencedisplayname","description","connectionid","connectorid","ismanaged","iscustomizable","statecode","statuscode","createdon","modifiedon","_ownerid_value"],filter:r,orderBy:["connectionreferencelogicalname asc"]});c.push(...s.value),this.onProgress&&this.onProgress(c.length,e.length)}return c.map(t=>this.mapToConnectionReference(t))}catch(n){throw new Error(`Failed to retrieve Connection References: ${n instanceof Error?n.message:"Unknown error"}`)}}mapToConnectionReference(e){var n;return{id:e.connectionreferenceid,name:e.connectionreferencelogicalname,displayName:e.connectionreferencedisplayname||e.connectionreferencelogicalname,description:e.description,connectionId:e.connectionid,connectorId:e.connectorid,connectorDisplayName:e.connectorid?this.getConnectorDisplayName(e.connectorid):null,isManaged:e.ismanaged,isCustomizable:((n=e.iscustomizable)==null?void 0:n.Value)??!0,statecode:e.statecode,statuscode:e.statuscode,owner:e["_ownerid_value@OData.Community.Display.V1.FormattedValue"]||"Unknown",ownerId:e._ownerid_value||"",modifiedBy:e["_modifiedby_value@OData.Community.Display.V1.FormattedValue"]||"Unknown",modifiedOn:e.modifiedon,createdOn:e.createdon}}getConnectorDisplayName(e){const n=e.match(/\/apis\/([^/]+)/);return n?n[1]:e}}export{h as ConnectionReferenceDiscovery};
2
+ //# sourceMappingURL=ConnectionReferenceDiscovery-DFTQuo-S.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConnectionReferenceDiscovery-DFTQuo-S.js","sources":["../../src/core/discovery/ConnectionReferenceDiscovery.ts"],"sourcesContent":["import type { IDataverseClient } from '../dataverse/IDataverseClient.js';\nimport type { ConnectionReference } from '../types/connectionReference.js';\n\ninterface RawConnectionReference {\n connectionreferenceid: string;\n connectionreferencelogicalname: string;\n connectionreferencedisplayname: string | null;\n description: string | null;\n connectionid: string | null;\n connectorid: string | null;\n ismanaged: boolean;\n iscustomizable: { Value: boolean };\n statecode: number;\n statuscode: number;\n createdon: string;\n modifiedon: string;\n _ownerid_value?: string;\n '_ownerid_value@OData.Community.Display.V1.FormattedValue'?: string;\n '_modifiedby_value@OData.Community.Display.V1.FormattedValue'?: string;\n}\n\nexport class ConnectionReferenceDiscovery {\n private readonly client: IDataverseClient;\n private onProgress?: (current: number, total: number) => void;\n\n constructor(client: IDataverseClient, onProgress?: (current: number, total: number) => void) {\n this.client = client;\n this.onProgress = onProgress;\n }\n\n async getConnectionReferencesByIds(ids: string[]): Promise<ConnectionReference[]> {\n if (ids.length === 0) return [];\n\n try {\n const batchSize = 20;\n const allResults: RawConnectionReference[] = [];\n\n for (let i = 0; i < ids.length; i += batchSize) {\n const batch = ids.slice(i, i + batchSize);\n const filterClauses = batch.map(id => `connectionreferenceid eq ${id.replace(/[{}]/g, '')}`);\n const filter = filterClauses.join(' or ');\n\n const result = await this.client.query<RawConnectionReference>('connectionreferences', {\n select: ['connectionreferenceid', 'connectionreferencelogicalname', 'connectionreferencedisplayname',\n 'description', 'connectionid', 'connectorid', 'ismanaged', 'iscustomizable',\n 'statecode', 'statuscode', 'createdon', 'modifiedon', '_ownerid_value'],\n filter,\n orderBy: ['connectionreferencelogicalname asc'],\n });\n\n allResults.push(...result.value);\n\n // Report progress after each batch\n if (this.onProgress) {\n this.onProgress(allResults.length, ids.length);\n }\n }\n\n return allResults.map(raw => this.mapToConnectionReference(raw));\n } catch (error) {\n throw new Error(`Failed to retrieve Connection References: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n }\n\n private mapToConnectionReference(raw: RawConnectionReference): ConnectionReference {\n return {\n id: raw.connectionreferenceid,\n name: raw.connectionreferencelogicalname,\n displayName: raw.connectionreferencedisplayname || raw.connectionreferencelogicalname,\n description: raw.description,\n connectionId: raw.connectionid,\n connectorId: raw.connectorid,\n connectorDisplayName: raw.connectorid ? this.getConnectorDisplayName(raw.connectorid) : null,\n isManaged: raw.ismanaged,\n isCustomizable: raw.iscustomizable?.Value ?? true,\n statecode: raw.statecode,\n statuscode: raw.statuscode,\n owner: raw['_ownerid_value@OData.Community.Display.V1.FormattedValue'] || 'Unknown',\n ownerId: raw._ownerid_value || '',\n modifiedBy: raw['_modifiedby_value@OData.Community.Display.V1.FormattedValue'] || 'Unknown',\n modifiedOn: raw.modifiedon,\n createdOn: raw.createdon,\n };\n }\n\n private getConnectorDisplayName(connectorId: string): string {\n // Extract connector name from connector ID (format: /providers/Microsoft.PowerApps/apis/{name})\n const match = connectorId.match(/\\/apis\\/([^/]+)/);\n return match ? match[1] : connectorId;\n }\n}\n"],"names":["ConnectionReferenceDiscovery","client","onProgress","__publicField","ids","allResults","i","filter","id","result","raw","error","_a","connectorId","match"],"mappings":"oKAqBO,MAAMA,CAA6B,CAIxC,YAAYC,EAA0BC,EAAuD,CAH5EC,EAAA,eACTA,EAAA,mBAGN,KAAK,OAASF,EACd,KAAK,WAAaC,CACpB,CAEA,MAAM,6BAA6BE,EAA+C,CAChF,GAAIA,EAAI,SAAW,EAAG,MAAO,CAAA,EAE7B,GAAI,CAEF,MAAMC,EAAuC,CAAA,EAE7C,QAASC,EAAI,EAAGA,EAAIF,EAAI,OAAQE,GAAK,GAAW,CAG9C,MAAMC,EAFQH,EAAI,MAAME,EAAGA,EAAI,EAAS,EACZ,IAAIE,GAAM,4BAA4BA,EAAG,QAAQ,QAAS,EAAE,CAAC,EAAE,EAC9D,KAAK,MAAM,EAElCC,EAAS,MAAM,KAAK,OAAO,MAA8B,uBAAwB,CACrF,OAAQ,CAAC,wBAAyB,iCAAkC,iCAClE,cAAe,eAAgB,cAAe,YAAa,iBAC3D,YAAa,aAAc,YAAa,aAAc,gBAAA,EACxD,OAAAF,EACA,QAAS,CAAC,oCAAoC,CAAA,CAC/C,EAEDF,EAAW,KAAK,GAAGI,EAAO,KAAK,EAG3B,KAAK,YACP,KAAK,WAAWJ,EAAW,OAAQD,EAAI,MAAM,CAEjD,CAEA,OAAOC,EAAW,IAAIK,GAAO,KAAK,yBAAyBA,CAAG,CAAC,CACjE,OAASC,EAAO,CACd,MAAM,IAAI,MAAM,6CAA6CA,aAAiB,MAAQA,EAAM,QAAU,eAAe,EAAE,CACzH,CACF,CAEQ,yBAAyBD,EAAkD,CA3C9E,IAAAE,EA4CH,MAAO,CACL,GAAIF,EAAI,sBACR,KAAMA,EAAI,+BACV,YAAaA,EAAI,gCAAkCA,EAAI,+BACvD,YAAaA,EAAI,YACjB,aAAcA,EAAI,aAClB,YAAaA,EAAI,YACjB,qBAAsBA,EAAI,YAAc,KAAK,wBAAwBA,EAAI,WAAW,EAAI,KACxF,UAAWA,EAAI,UACf,iBAAgBE,EAAAF,EAAI,iBAAJ,YAAAE,EAAoB,QAAS,GAC7C,UAAWF,EAAI,UACf,WAAYA,EAAI,WAChB,MAAOA,EAAI,0DAA0D,GAAK,UAC1E,QAASA,EAAI,gBAAkB,GAC/B,WAAYA,EAAI,6DAA6D,GAAK,UAClF,WAAYA,EAAI,WAChB,UAAWA,EAAI,SAAA,CAEnB,CAEQ,wBAAwBG,EAA6B,CAE3D,MAAMC,EAAQD,EAAY,MAAM,iBAAiB,EACjD,OAAOC,EAAQA,EAAM,CAAC,EAAID,CAC5B,CACF"}
@@ -0,0 +1,2 @@
1
+ var m=Object.defineProperty;var d=(r,e,t)=>e in r?m(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t;var s=(r,e,t)=>d(r,typeof e!="symbol"?e+"":e,t);class h{constructor(e,t){s(this,"client");s(this,"onProgress");this.client=e,this.onProgress=t}async getCustomAPIsByIds(e){if(e.length===0)return[];try{const i=[];for(let n=0;n<e.length;n+=20){const c=e.slice(n,n+20).map(p=>`customapiid eq ${p.replace(/[{}]/g,"")}`).join(" or "),l=await this.client.query("customapis",{select:["customapiid","uniquename","displayname","description","bindingtype","boundentitylogicalname","isfunction","isprivate","ismanaged","allowedcustomprocessingsteptype","executeprivilegename","createdon","modifiedon","_ownerid_value"],filter:c,orderBy:["uniquename asc"]});i.push(...l.value),this.onProgress&&this.onProgress(i.length,e.length)}const a=[];for(const n of i){const[o,u]=await Promise.all([this.getRequestParameters(n.customapiid),this.getResponseProperties(n.customapiid)]);a.push(this.mapToCustomAPI(n,o,u))}return a}catch(t){throw new Error(`Failed to retrieve Custom APIs: ${t instanceof Error?t.message:"Unknown error"}`)}}async getRequestParameters(e){try{return(await this.client.query("customapirequestparameters",{select:["customapirequestparameterid","uniquename","displayname","description","type","isoptional","logicalentityname"],filter:`_customapiid_value eq ${e.replace(/[{}]/g,"")}`,orderBy:["uniquename asc"]})).value.map(i=>this.mapToParameter(i,!0))}catch{return[]}}async getResponseProperties(e){try{return(await this.client.query("customapiresponseproperties",{select:["customapiresponsepropertyid","uniquename","displayname","description","type","isoptional","logicalentityname"],filter:`_customapiid_value eq ${e.replace(/[{}]/g,"")}`,orderBy:["uniquename asc"]})).value.map(i=>this.mapToParameter(i,!1))}catch{return[]}}mapToCustomAPI(e,t,i){return{id:e.customapiid,uniqueName:e.uniquename,displayName:e.displayname||e.uniquename,description:e.description,bindingType:this.getBindingType(e.bindingtype),boundEntityLogicalName:e.boundentitylogicalname,isFunction:e.isfunction,isPrivate:e.isprivate,isManaged:e.ismanaged,allowedCustomProcessingStepType:this.getAllowedStepType(e.allowedcustomprocessingsteptype),executionPrivilege:this.getExecutionPrivilege(e.executeprivilegename),requestParameters:t,responseProperties:i,owner:e["_ownerid_value@OData.Community.Display.V1.FormattedValue"]||"Unknown",ownerId:e._ownerid_value||"",modifiedBy:e["_modifiedby_value@OData.Community.Display.V1.FormattedValue"]||"Unknown",modifiedOn:e.modifiedon,createdOn:e.createdon}}mapToParameter(e,t){return{id:(t?e.customapirequestparameterid:e.customapiresponsepropertyid)||"",uniqueName:e.uniquename,displayName:e.displayname||e.uniquename,description:e.description,type:this.getParameterType(e.type),typeName:this.getParameterTypeName(e.type),isOptional:e.isoptional,logicalEntityName:e.logicalentityname}}getBindingType(e){switch(e){case 0:return"Global";case 1:return"Entity";case 2:return"EntityCollection";default:return"Global"}}getAllowedStepType(e){switch(e){case 0:return"None";case 1:return"AsyncOnly";case 2:return"SyncAndAsync";default:return"None"}}getExecutionPrivilege(e){return e?e.includes("Basic")?"Basic":e.includes("Local")?"Local":e.includes("Deep")?"Deep":e.includes("Global")?"Global":"None":"None"}getParameterType(e){switch(e){case 0:return"Boolean";case 1:return"DateTime";case 2:return"Decimal";case 3:return"Entity";case 4:return"EntityCollection";case 5:return"EntityReference";case 6:return"Float";case 7:return"Integer";case 8:return"Money";case 9:return"Picklist";case 10:return"String";case 11:return"StringArray";case 12:return"Guid";default:return"String"}}getParameterTypeName(e){return this.getParameterType(e)}}export{h as CustomAPIDiscovery};
2
+ //# sourceMappingURL=CustomAPIDiscovery-BiQS_ENt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CustomAPIDiscovery-BiQS_ENt.js","sources":["../../src/core/discovery/CustomAPIDiscovery.ts"],"sourcesContent":["import type { IDataverseClient } from '../dataverse/IDataverseClient.js';\nimport type { CustomAPI, CustomAPIParameter } from '../types/customApi.js';\n\n/**\n * Raw Custom API data from Dataverse\n */\ninterface RawCustomAPI {\n customapiid: string;\n uniquename: string;\n displayname: string | null;\n description: string | null;\n bindingtype: number;\n boundentitylogicalname: string | null;\n isfunction: boolean;\n isprivate: boolean;\n ismanaged: boolean;\n allowedcustomprocessingsteptype: number;\n executeprivilegename: string | null;\n createdon: string;\n modifiedon: string;\n _ownerid_value?: string;\n '_ownerid_value@OData.Community.Display.V1.FormattedValue'?: string;\n '_modifiedby_value@OData.Community.Display.V1.FormattedValue'?: string;\n}\n\n/**\n * Raw Custom API parameter data\n */\ninterface RawCustomAPIParameter {\n customapirequestparameterid?: string;\n customapiresponsepropertyid?: string;\n uniquename: string;\n displayname: string | null;\n description: string | null;\n type: number;\n isoptional: boolean;\n logicalentityname: string | null;\n}\n\n/**\n * Discovers Custom APIs\n */\nexport class CustomAPIDiscovery {\n private readonly client: IDataverseClient;\n private onProgress?: (current: number, total: number) => void;\n\n constructor(client: IDataverseClient, onProgress?: (current: number, total: number) => void) {\n this.client = client;\n this.onProgress = onProgress;\n }\n\n /**\n * Get all Custom APIs in the solution\n * @param customApiIds Array of custom API IDs from solution components\n * @returns Array of Custom APIs with parameters\n */\n async getCustomAPIsByIds(customApiIds: string[]): Promise<CustomAPI[]> {\n if (customApiIds.length === 0) {\n return [];\n }\n\n try {\n const batchSize = 20;\n const allResults: RawCustomAPI[] = [];\n\n for (let i = 0; i < customApiIds.length; i += batchSize) {\n const batch = customApiIds.slice(i, i + batchSize);\n const filterClauses = batch.map((id) => {\n const cleanGuid = id.replace(/[{}]/g, '');\n return `customapiid eq ${cleanGuid}`;\n });\n const filter = filterClauses.join(' or ');\n\n const result = await this.client.query<RawCustomAPI>('customapis', {\n select: [\n 'customapiid',\n 'uniquename',\n 'displayname',\n 'description',\n 'bindingtype',\n 'boundentitylogicalname',\n 'isfunction',\n 'isprivate',\n 'ismanaged',\n 'allowedcustomprocessingsteptype',\n 'executeprivilegename',\n 'createdon',\n 'modifiedon',\n '_ownerid_value',\n ],\n filter,\n orderBy: ['uniquename asc'],\n });\n\n allResults.push(...result.value);\n\n // Report progress after each batch\n if (this.onProgress) {\n this.onProgress(allResults.length, customApiIds.length);\n }\n }\n\n // For each Custom API, fetch its request parameters and response properties\n const customAPIs: CustomAPI[] = [];\n for (const rawApi of allResults) {\n const [requestParams, responseProps] = await Promise.all([\n this.getRequestParameters(rawApi.customapiid),\n this.getResponseProperties(rawApi.customapiid),\n ]);\n\n customAPIs.push(this.mapToCustomAPI(rawApi, requestParams, responseProps));\n }\n\n return customAPIs;\n } catch (error) {\n throw new Error(\n `Failed to retrieve Custom APIs: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n }\n\n /**\n * Get request parameters for a Custom API\n */\n private async getRequestParameters(customApiId: string): Promise<CustomAPIParameter[]> {\n try {\n const result = await this.client.query<RawCustomAPIParameter>(\n 'customapirequestparameters',\n {\n select: [\n 'customapirequestparameterid',\n 'uniquename',\n 'displayname',\n 'description',\n 'type',\n 'isoptional',\n 'logicalentityname',\n ],\n filter: `_customapiid_value eq ${customApiId.replace(/[{}]/g, '')}`,\n orderBy: ['uniquename asc'],\n }\n );\n\n return result.value.map((raw) => this.mapToParameter(raw, true));\n } catch (error) {\n return [];\n }\n }\n\n /**\n * Get response properties for a Custom API\n */\n private async getResponseProperties(customApiId: string): Promise<CustomAPIParameter[]> {\n try {\n const result = await this.client.query<RawCustomAPIParameter>(\n 'customapiresponseproperties',\n {\n select: [\n 'customapiresponsepropertyid',\n 'uniquename',\n 'displayname',\n 'description',\n 'type',\n 'isoptional',\n 'logicalentityname',\n ],\n filter: `_customapiid_value eq ${customApiId.replace(/[{}]/g, '')}`,\n orderBy: ['uniquename asc'],\n }\n );\n\n return result.value.map((raw) => this.mapToParameter(raw, false));\n } catch (error) {\n return [];\n }\n }\n\n /**\n * Map raw data to CustomAPI\n */\n private mapToCustomAPI(\n raw: RawCustomAPI,\n requestParameters: CustomAPIParameter[],\n responseProperties: CustomAPIParameter[]\n ): CustomAPI {\n return {\n id: raw.customapiid,\n uniqueName: raw.uniquename,\n displayName: raw.displayname || raw.uniquename,\n description: raw.description,\n bindingType: this.getBindingType(raw.bindingtype),\n boundEntityLogicalName: raw.boundentitylogicalname,\n isFunction: raw.isfunction,\n isPrivate: raw.isprivate,\n isManaged: raw.ismanaged,\n allowedCustomProcessingStepType: this.getAllowedStepType(\n raw.allowedcustomprocessingsteptype\n ),\n executionPrivilege: this.getExecutionPrivilege(raw.executeprivilegename),\n requestParameters,\n responseProperties,\n owner: raw['_ownerid_value@OData.Community.Display.V1.FormattedValue'] || 'Unknown',\n ownerId: raw._ownerid_value || '',\n modifiedBy: raw['_modifiedby_value@OData.Community.Display.V1.FormattedValue'] || 'Unknown',\n modifiedOn: raw.modifiedon,\n createdOn: raw.createdon,\n };\n }\n\n /**\n * Map raw parameter to CustomAPIParameter\n */\n private mapToParameter(raw: RawCustomAPIParameter, isRequest: boolean): CustomAPIParameter {\n return {\n id: (isRequest ? raw.customapirequestparameterid : raw.customapiresponsepropertyid) || '',\n uniqueName: raw.uniquename,\n displayName: raw.displayname || raw.uniquename,\n description: raw.description,\n type: this.getParameterType(raw.type),\n typeName: this.getParameterTypeName(raw.type),\n isOptional: raw.isoptional,\n logicalEntityName: raw.logicalentityname,\n };\n }\n\n /**\n * Get binding type name\n */\n private getBindingType(bindingType: number): 'Global' | 'Entity' | 'EntityCollection' {\n switch (bindingType) {\n case 0:\n return 'Global';\n case 1:\n return 'Entity';\n case 2:\n return 'EntityCollection';\n default:\n return 'Global';\n }\n }\n\n /**\n * Get allowed custom processing step type\n */\n private getAllowedStepType(type: number): 'None' | 'AsyncOnly' | 'SyncAndAsync' {\n switch (type) {\n case 0:\n return 'None';\n case 1:\n return 'AsyncOnly';\n case 2:\n return 'SyncAndAsync';\n default:\n return 'None';\n }\n }\n\n /**\n * Get execution privilege\n */\n private getExecutionPrivilege(\n privilegeName: string | null\n ): 'None' | 'Basic' | 'Local' | 'Deep' | 'Global' {\n if (!privilegeName) return 'None';\n\n // Privilege names typically end with prvRead{EntityName}, prvWrite{EntityName}, etc.\n if (privilegeName.includes('Basic')) return 'Basic';\n if (privilegeName.includes('Local')) return 'Local';\n if (privilegeName.includes('Deep')) return 'Deep';\n if (privilegeName.includes('Global')) return 'Global';\n\n return 'None';\n }\n\n /**\n * Get parameter type\n */\n private getParameterType(type: number):\n | 'Boolean'\n | 'DateTime'\n | 'Decimal'\n | 'Entity'\n | 'EntityCollection'\n | 'EntityReference'\n | 'Float'\n | 'Integer'\n | 'Money'\n | 'Picklist'\n | 'String'\n | 'StringArray'\n | 'Guid' {\n switch (type) {\n case 0:\n return 'Boolean';\n case 1:\n return 'DateTime';\n case 2:\n return 'Decimal';\n case 3:\n return 'Entity';\n case 4:\n return 'EntityCollection';\n case 5:\n return 'EntityReference';\n case 6:\n return 'Float';\n case 7:\n return 'Integer';\n case 8:\n return 'Money';\n case 9:\n return 'Picklist';\n case 10:\n return 'String';\n case 11:\n return 'StringArray';\n case 12:\n return 'Guid';\n default:\n return 'String';\n }\n }\n\n /**\n * Get parameter type name\n */\n private getParameterTypeName(type: number): string {\n const typeMap = this.getParameterType(type);\n return typeMap;\n }\n}\n"],"names":["CustomAPIDiscovery","client","onProgress","__publicField","customApiIds","allResults","i","filter","id","result","customAPIs","rawApi","requestParams","responseProps","error","customApiId","raw","requestParameters","responseProperties","isRequest","bindingType","type","privilegeName"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ var m=Object.defineProperty;var d=(o,e,t)=>e in o?m(o,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[e]=t;var r=(o,e,t)=>d(o,typeof e!="symbol"?e+"":e,t);class y{constructor(e,t){r(this,"client");r(this,"onProgress");this.client=e,this.onProgress=t}async getConnectorsByIds(e){if(e.length===0)return[];try{const s=[];for(let i=0;i<e.length;i+=20){const p=e.slice(i,i+20).map(a=>`connectorid eq ${a.startsWith("{")?a:`{${a}}`}`).join(" or "),l=await this.client.query("connectors",{select:["connectorid","name","displayname","description","connectortype","iconuri","ismanaged","iscustomizable","capabilities","connectionparameters","ownerid","modifiedon","modifiedby","policytemplateinstances","openapidefinition"],filter:p});s.push(...l.value),this.onProgress&&this.onProgress(s.length,e.length)}return s.map(i=>this.mapToCustomConnector(i))}catch{return[]}}mapToCustomConnector(e){var c;const t=[];if(e.capabilities)try{const n=JSON.parse(e.capabilities);Array.isArray(n)?t.push(...n):typeof n=="object"&&t.push(...Object.keys(n))}catch{}const s=[];if(e.connectionparameters)try{const n=JSON.parse(e.connectionparameters);typeof n=="object"&&s.push(...Object.keys(n))}catch{}const i={0:"NotSpecified",1:"Custom",2:"Certified",3:"Shared"};return{id:e.connectorid,name:e.name,displayName:e.displayname||e.name,description:e.description,connectorType:i[e.connectortype||1]||"Custom",iconUri:e.iconuri,isManaged:e.ismanaged||!1,isCustomizable:((c=e.iscustomizable)==null?void 0:c.Value)??!0,capabilities:t,connectionParameters:s,owner:e.ownerid||"Unknown",modifiedOn:e.modifiedon||new Date().toISOString(),modifiedBy:e.modifiedby||"Unknown",policy:e.policytemplateinstances,apiDefinition:e.openapidefinition}}}export{y as CustomConnectorDiscovery};
2
+ //# sourceMappingURL=CustomConnectorDiscovery-TvNjElP3.js.map