@pax8-cta/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +198 -0
- package/dist/auth/device-code-login.d.ts +40 -0
- package/dist/auth/device-code-login.d.ts.map +1 -0
- package/dist/auth/device-code-login.js +59 -0
- package/dist/auth/device-code-login.js.map +1 -0
- package/dist/auth/gdap-client.d.ts +81 -0
- package/dist/auth/gdap-client.d.ts.map +1 -0
- package/dist/auth/gdap-client.js +128 -0
- package/dist/auth/gdap-client.js.map +1 -0
- package/dist/auth/index.d.ts +19 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +19 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/token-manager.d.ts +54 -0
- package/dist/auth/token-manager.d.ts.map +1 -0
- package/dist/auth/token-manager.js +150 -0
- package/dist/auth/token-manager.js.map +1 -0
- package/dist/client.d.ts +27 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +27 -0
- package/dist/client.js.map +1 -0
- package/dist/config/client.d.ts +24 -0
- package/dist/config/client.d.ts.map +1 -0
- package/dist/config/client.js +18 -0
- package/dist/config/client.js.map +1 -0
- package/dist/config/index.d.ts +18 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +18 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +81 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +271 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +751 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +556 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/constants.d.ts +116 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +170 -0
- package/dist/constants.js.map +1 -0
- package/dist/dataverse/agent-resolver.d.ts +98 -0
- package/dist/dataverse/agent-resolver.d.ts.map +1 -0
- package/dist/dataverse/agent-resolver.js +185 -0
- package/dist/dataverse/agent-resolver.js.map +1 -0
- package/dist/dataverse/client.d.ts +104 -0
- package/dist/dataverse/client.d.ts.map +1 -0
- package/dist/dataverse/client.js +272 -0
- package/dist/dataverse/client.js.map +1 -0
- package/dist/dataverse/connection-refs.d.ts +115 -0
- package/dist/dataverse/connection-refs.d.ts.map +1 -0
- package/dist/dataverse/connection-refs.js +203 -0
- package/dist/dataverse/connection-refs.js.map +1 -0
- package/dist/dataverse/index.d.ts +20 -0
- package/dist/dataverse/index.d.ts.map +1 -0
- package/dist/dataverse/index.js +20 -0
- package/dist/dataverse/index.js.map +1 -0
- package/dist/dataverse/solution-ops.d.ts +100 -0
- package/dist/dataverse/solution-ops.d.ts.map +1 -0
- package/dist/dataverse/solution-ops.js +288 -0
- package/dist/dataverse/solution-ops.js.map +1 -0
- package/dist/errors.d.ts +171 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +178 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/mock/demo-data.d.ts +213 -0
- package/dist/mock/demo-data.d.ts.map +1 -0
- package/dist/mock/demo-data.js +1096 -0
- package/dist/mock/demo-data.js.map +1 -0
- package/dist/mock/demo-deployment-store.d.ts +77 -0
- package/dist/mock/demo-deployment-store.d.ts.map +1 -0
- package/dist/mock/demo-deployment-store.js +85 -0
- package/dist/mock/demo-deployment-store.js.map +1 -0
- package/dist/powerplatform/admin-client.d.ts +226 -0
- package/dist/powerplatform/admin-client.d.ts.map +1 -0
- package/dist/powerplatform/admin-client.js +315 -0
- package/dist/powerplatform/admin-client.js.map +1 -0
- package/dist/powerplatform/index.d.ts +18 -0
- package/dist/powerplatform/index.d.ts.map +1 -0
- package/dist/powerplatform/index.js +18 -0
- package/dist/powerplatform/index.js.map +1 -0
- package/dist/powerplatform/tenant-discovery.d.ts +100 -0
- package/dist/powerplatform/tenant-discovery.d.ts.map +1 -0
- package/dist/powerplatform/tenant-discovery.js +205 -0
- package/dist/powerplatform/tenant-discovery.js.map +1 -0
- package/dist/preconditions/check.d.ts +41 -0
- package/dist/preconditions/check.d.ts.map +1 -0
- package/dist/preconditions/check.js +173 -0
- package/dist/preconditions/check.js.map +1 -0
- package/dist/preconditions/index.d.ts +20 -0
- package/dist/preconditions/index.d.ts.map +1 -0
- package/dist/preconditions/index.js +20 -0
- package/dist/preconditions/index.js.map +1 -0
- package/dist/preconditions/loader.d.ts +33 -0
- package/dist/preconditions/loader.d.ts.map +1 -0
- package/dist/preconditions/loader.js +65 -0
- package/dist/preconditions/loader.js.map +1 -0
- package/dist/preconditions/schema.d.ts +103 -0
- package/dist/preconditions/schema.d.ts.map +1 -0
- package/dist/preconditions/schema.js +93 -0
- package/dist/preconditions/schema.js.map +1 -0
- package/dist/preconditions/types.d.ts +118 -0
- package/dist/preconditions/types.d.ts.map +1 -0
- package/dist/preconditions/types.js +17 -0
- package/dist/preconditions/types.js.map +1 -0
- package/dist/queue/index.d.ts +17 -0
- package/dist/queue/index.d.ts.map +1 -0
- package/dist/queue/index.js +17 -0
- package/dist/queue/index.js.map +1 -0
- package/dist/queue/memory-queue.d.ts +86 -0
- package/dist/queue/memory-queue.d.ts.map +1 -0
- package/dist/queue/memory-queue.js +221 -0
- package/dist/queue/memory-queue.js.map +1 -0
- package/dist/services/audit-log.d.ts +59 -0
- package/dist/services/audit-log.d.ts.map +1 -0
- package/dist/services/audit-log.js +193 -0
- package/dist/services/audit-log.js.map +1 -0
- package/dist/services/auth-error-parser.d.ts +36 -0
- package/dist/services/auth-error-parser.d.ts.map +1 -0
- package/dist/services/auth-error-parser.js +90 -0
- package/dist/services/auth-error-parser.js.map +1 -0
- package/dist/services/deployment-doctor.d.ts +109 -0
- package/dist/services/deployment-doctor.d.ts.map +1 -0
- package/dist/services/deployment-doctor.js +476 -0
- package/dist/services/deployment-doctor.js.map +1 -0
- package/dist/services/deployment-notifications.d.ts +41 -0
- package/dist/services/deployment-notifications.d.ts.map +1 -0
- package/dist/services/deployment-notifications.js +161 -0
- package/dist/services/deployment-notifications.js.map +1 -0
- package/dist/services/deployment-progress.d.ts +89 -0
- package/dist/services/deployment-progress.d.ts.map +1 -0
- package/dist/services/deployment-progress.js +244 -0
- package/dist/services/deployment-progress.js.map +1 -0
- package/dist/services/deployment-service.d.ts +97 -0
- package/dist/services/deployment-service.d.ts.map +1 -0
- package/dist/services/deployment-service.js +375 -0
- package/dist/services/deployment-service.js.map +1 -0
- package/dist/services/drift-analyzer.d.ts +86 -0
- package/dist/services/drift-analyzer.d.ts.map +1 -0
- package/dist/services/drift-analyzer.js +273 -0
- package/dist/services/drift-analyzer.js.map +1 -0
- package/dist/services/environment-setup.d.ts +97 -0
- package/dist/services/environment-setup.d.ts.map +1 -0
- package/dist/services/environment-setup.js +250 -0
- package/dist/services/environment-setup.js.map +1 -0
- package/dist/services/health-check.d.ts +168 -0
- package/dist/services/health-check.d.ts.map +1 -0
- package/dist/services/health-check.js +705 -0
- package/dist/services/health-check.js.map +1 -0
- package/dist/services/index.d.ts +39 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +39 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/logger.d.ts +139 -0
- package/dist/services/logger.d.ts.map +1 -0
- package/dist/services/logger.js +268 -0
- package/dist/services/logger.js.map +1 -0
- package/dist/services/notification-service.d.ts +55 -0
- package/dist/services/notification-service.d.ts.map +1 -0
- package/dist/services/notification-service.js +184 -0
- package/dist/services/notification-service.js.map +1 -0
- package/dist/services/risk-analyzer.d.ts +252 -0
- package/dist/services/risk-analyzer.d.ts.map +1 -0
- package/dist/services/risk-analyzer.js +866 -0
- package/dist/services/risk-analyzer.js.map +1 -0
- package/dist/services/rollback.d.ts +57 -0
- package/dist/services/rollback.d.ts.map +1 -0
- package/dist/services/rollback.js +270 -0
- package/dist/services/rollback.js.map +1 -0
- package/dist/services/scheduler.d.ts +80 -0
- package/dist/services/scheduler.d.ts.map +1 -0
- package/dist/services/scheduler.js +350 -0
- package/dist/services/scheduler.js.map +1 -0
- package/dist/services/secrets.d.ts +31 -0
- package/dist/services/secrets.d.ts.map +1 -0
- package/dist/services/secrets.js +206 -0
- package/dist/services/secrets.js.map +1 -0
- package/dist/services/settings-service.d.ts +132 -0
- package/dist/services/settings-service.d.ts.map +1 -0
- package/dist/services/settings-service.js +378 -0
- package/dist/services/settings-service.js.map +1 -0
- package/dist/services/solution-diff.d.ts +127 -0
- package/dist/services/solution-diff.d.ts.map +1 -0
- package/dist/services/solution-diff.js +260 -0
- package/dist/services/solution-diff.js.map +1 -0
- package/dist/services/solution-mode-detector.d.ts +35 -0
- package/dist/services/solution-mode-detector.d.ts.map +1 -0
- package/dist/services/solution-mode-detector.js +84 -0
- package/dist/services/solution-mode-detector.js.map +1 -0
- package/dist/services/tenant-resolver.d.ts +55 -0
- package/dist/services/tenant-resolver.d.ts.map +1 -0
- package/dist/services/tenant-resolver.js +126 -0
- package/dist/services/tenant-resolver.js.map +1 -0
- package/dist/services/unmanaged-customizations.d.ts +104 -0
- package/dist/services/unmanaged-customizations.d.ts.map +1 -0
- package/dist/services/unmanaged-customizations.js +521 -0
- package/dist/services/unmanaged-customizations.js.map +1 -0
- package/dist/services/url-templater.d.ts +184 -0
- package/dist/services/url-templater.d.ts.map +1 -0
- package/dist/services/url-templater.js +327 -0
- package/dist/services/url-templater.js.map +1 -0
- package/dist/services/version-checker.d.ts +108 -0
- package/dist/services/version-checker.d.ts.map +1 -0
- package/dist/services/version-checker.js +403 -0
- package/dist/services/version-checker.js.map +1 -0
- package/dist/services/waves.d.ts +90 -0
- package/dist/services/waves.d.ts.map +1 -0
- package/dist/services/waves.js +222 -0
- package/dist/services/waves.js.map +1 -0
- package/dist/services/webhook.d.ts +95 -0
- package/dist/services/webhook.d.ts.map +1 -0
- package/dist/services/webhook.js +244 -0
- package/dist/services/webhook.js.map +1 -0
- package/dist/utils/deployment-tools.d.ts +110 -0
- package/dist/utils/deployment-tools.d.ts.map +1 -0
- package/dist/utils/deployment-tools.js +121 -0
- package/dist/utils/deployment-tools.js.map +1 -0
- package/dist/utils/index.d.ts +17 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +18 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +49 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
export type UrlTemplateType = "sharepoint" | "dynamics_crm" | "onmicrosoft" | "custom";
|
|
2
|
+
export interface ZipFile {
|
|
3
|
+
dir: boolean;
|
|
4
|
+
async(type: "text"): Promise<string>;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Map of ZIP output type identifiers to their concrete TS types.
|
|
8
|
+
*
|
|
9
|
+
* Mirrors the shape of JSZip's `OutputByType` so that {@link ZipArchive.generateAsync}
|
|
10
|
+
* can return the correct concrete type based on the requested `type` option,
|
|
11
|
+
* instead of falling back to `any`.
|
|
12
|
+
*/
|
|
13
|
+
export interface ZipOutputByType {
|
|
14
|
+
nodebuffer: Buffer;
|
|
15
|
+
arraybuffer: ArrayBuffer;
|
|
16
|
+
blob: Blob;
|
|
17
|
+
uint8array: Uint8Array;
|
|
18
|
+
base64: string;
|
|
19
|
+
string: string;
|
|
20
|
+
}
|
|
21
|
+
export type ZipOutputType = keyof ZipOutputByType;
|
|
22
|
+
/**
|
|
23
|
+
* Options for generating a ZIP archive.
|
|
24
|
+
*
|
|
25
|
+
* The `type` field is a generic so that callers like `zip.generateAsync({ type: "nodebuffer" })`
|
|
26
|
+
* yield a `Promise<Buffer>` rather than `Promise<any>`.
|
|
27
|
+
*/
|
|
28
|
+
export interface ZipGenerateOptions<T extends ZipOutputType = ZipOutputType> {
|
|
29
|
+
type: T;
|
|
30
|
+
compression?: "STORE" | "DEFLATE";
|
|
31
|
+
compressionOptions?: {
|
|
32
|
+
level: number;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Generic ZIP archive interface (compatible with JSZip)
|
|
37
|
+
*/
|
|
38
|
+
export interface ZipArchive {
|
|
39
|
+
files: Record<string, ZipFile>;
|
|
40
|
+
file(path: string, content: string): void;
|
|
41
|
+
generateAsync<T extends ZipOutputType>(options: ZipGenerateOptions<T>): Promise<ZipOutputByType[T]>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Interface for loading ZIP files (compatible with JSZip)
|
|
45
|
+
*/
|
|
46
|
+
export interface ZipLoader {
|
|
47
|
+
loadAsync(data: Buffer | ArrayBuffer): Promise<ZipArchive>;
|
|
48
|
+
}
|
|
49
|
+
export interface DetectedUrl {
|
|
50
|
+
type: UrlTemplateType;
|
|
51
|
+
originalUrl: string;
|
|
52
|
+
extractedTenant: string;
|
|
53
|
+
templatePattern: string;
|
|
54
|
+
fileLocation: string;
|
|
55
|
+
}
|
|
56
|
+
export interface UrlTemplate {
|
|
57
|
+
id: string;
|
|
58
|
+
type: UrlTemplateType;
|
|
59
|
+
originalUrl: string;
|
|
60
|
+
templatePattern: string;
|
|
61
|
+
extractedTenant: string;
|
|
62
|
+
fileLocations: string[];
|
|
63
|
+
description?: string;
|
|
64
|
+
confirmed: boolean;
|
|
65
|
+
}
|
|
66
|
+
export interface AgentUrlTemplates {
|
|
67
|
+
sourceTenant: string;
|
|
68
|
+
templates: UrlTemplate[];
|
|
69
|
+
createdAt: string;
|
|
70
|
+
confirmedAt?: string;
|
|
71
|
+
}
|
|
72
|
+
export interface TenantUrlValues {
|
|
73
|
+
tenant: string;
|
|
74
|
+
sharepoint: string;
|
|
75
|
+
dynamicsCrm: string;
|
|
76
|
+
onmicrosoft: string;
|
|
77
|
+
region?: string;
|
|
78
|
+
}
|
|
79
|
+
export declare class UrlTemplater {
|
|
80
|
+
/**
|
|
81
|
+
* Scan a solution ZIP for tenant-specific URLs
|
|
82
|
+
*
|
|
83
|
+
* @param zip - A ZipArchive instance (JSZip or compatible)
|
|
84
|
+
* @returns Array of detected tenant-specific URLs with their locations
|
|
85
|
+
*/
|
|
86
|
+
scanSolution(zip: ZipArchive): Promise<DetectedUrl[]>;
|
|
87
|
+
/**
|
|
88
|
+
* Extract tenant-specific URLs from text content using pattern matching
|
|
89
|
+
*
|
|
90
|
+
* This function scans text content (typically from XML, JSON, or YAML files
|
|
91
|
+
* within a Power Platform solution) and identifies tenant-specific URLs that
|
|
92
|
+
* should be templated for multi-tenant deployment.
|
|
93
|
+
*
|
|
94
|
+
* **Supported URL patterns:**
|
|
95
|
+
* - SharePoint: `https://{tenant}.sharepoint.com/...`
|
|
96
|
+
* - Dynamics 365: `https://{tenant}.crm[N].dynamics.com/...`
|
|
97
|
+
* - Microsoft 365: `https://{tenant}.onmicrosoft.com/...`
|
|
98
|
+
*
|
|
99
|
+
* Each detected URL is converted to a template pattern where the tenant
|
|
100
|
+
* identifier is replaced with `{tenant}`, allowing the URL to be resolved
|
|
101
|
+
* to different values for each target tenant during deployment.
|
|
102
|
+
*
|
|
103
|
+
* @param content - The text content to scan for URLs
|
|
104
|
+
* @param fileLocation - Path of the file being scanned (for tracking purposes)
|
|
105
|
+
* @returns Array of detected URLs with their types, extracted tenants, and template patterns
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```ts
|
|
109
|
+
* const urls = templater.extractUrlsFromContent(
|
|
110
|
+
* '<SharePointUrl>https://contoso.sharepoint.com/sites/docs</SharePointUrl>',
|
|
111
|
+
* 'solution/connections.xml'
|
|
112
|
+
* );
|
|
113
|
+
* // Returns: [{
|
|
114
|
+
* // type: 'sharepoint',
|
|
115
|
+
* // originalUrl: 'https://contoso.sharepoint.com/sites/docs',
|
|
116
|
+
* // extractedTenant: 'contoso',
|
|
117
|
+
* // templatePattern: 'https://{tenant}.sharepoint.com/sites/docs',
|
|
118
|
+
* // fileLocation: 'solution/connections.xml'
|
|
119
|
+
* // }]
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
extractUrlsFromContent(content: string, fileLocation: string): DetectedUrl[];
|
|
123
|
+
/**
|
|
124
|
+
* Infer the source tenant from detected URLs (most common tenant identifier)
|
|
125
|
+
*/
|
|
126
|
+
inferSourceTenant(urls: DetectedUrl[]): string | null;
|
|
127
|
+
/**
|
|
128
|
+
* Generate URL templates from detected URLs
|
|
129
|
+
*/
|
|
130
|
+
generateTemplates(detectedUrls: DetectedUrl[]): UrlTemplate[];
|
|
131
|
+
/**
|
|
132
|
+
* Get a human-readable description for a URL type
|
|
133
|
+
*/
|
|
134
|
+
private getDescriptionForType;
|
|
135
|
+
/**
|
|
136
|
+
* Resolve a template pattern to an actual URL for a target tenant
|
|
137
|
+
*/
|
|
138
|
+
resolveTemplate(templatePattern: string, tenantUrls: TenantUrlValues): string;
|
|
139
|
+
/**
|
|
140
|
+
* Modify a Power Platform solution ZIP by replacing tenant-specific URLs
|
|
141
|
+
*
|
|
142
|
+
* This function takes a solution ZIP file and performs URL replacements
|
|
143
|
+
* in all text files (XML, JSON, YAML) within the archive. It's used during
|
|
144
|
+
* deployment to customize solutions for specific target tenants.
|
|
145
|
+
*
|
|
146
|
+
* **How it works:**
|
|
147
|
+
* 1. Loads the ZIP file into memory
|
|
148
|
+
* 2. Iterates through all files in the archive
|
|
149
|
+
* 3. For text files, performs string replacements for each URL mapping
|
|
150
|
+
* 4. Generates a new ZIP buffer with the modified content
|
|
151
|
+
*
|
|
152
|
+
* **Important notes:**
|
|
153
|
+
* - Binary files are skipped (images, compiled resources, etc.)
|
|
154
|
+
* - The original ZIP is not modified; a new buffer is returned
|
|
155
|
+
* - If no replacements are needed, the original buffer is returned unchanged
|
|
156
|
+
* - Requires a JSZip-compatible loader to be passed in
|
|
157
|
+
*
|
|
158
|
+
* @param zipBuffer - The original solution ZIP file as a Buffer
|
|
159
|
+
* @param replacements - Map of original URLs to resolved URLs
|
|
160
|
+
* @param zipLoader - JSZip-compatible loader for reading/writing ZIP files
|
|
161
|
+
* @returns New Buffer containing the modified solution ZIP
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```ts
|
|
165
|
+
* const JSZip = require('jszip');
|
|
166
|
+
* const replacements = new Map([
|
|
167
|
+
* ['https://contoso.sharepoint.com', 'https://fabrikam.sharepoint.com'],
|
|
168
|
+
* ['https://contoso.crm.dynamics.com', 'https://fabrikam.crm.dynamics.com'],
|
|
169
|
+
* ]);
|
|
170
|
+
* const modifiedZip = await templater.modifySolution(
|
|
171
|
+
* originalZipBuffer,
|
|
172
|
+
* replacements,
|
|
173
|
+
* new JSZip()
|
|
174
|
+
* );
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
modifySolution(zipBuffer: Buffer, replacements: Map<string, string>, zipLoader: ZipLoader): Promise<Buffer>;
|
|
178
|
+
/**
|
|
179
|
+
* Create a complete AgentUrlTemplates object from scanning results
|
|
180
|
+
*/
|
|
181
|
+
createAgentUrlTemplates(detectedUrls: DetectedUrl[]): AgentUrlTemplates | null;
|
|
182
|
+
}
|
|
183
|
+
export declare const urlTemplater: UrlTemplater;
|
|
184
|
+
//# sourceMappingURL=url-templater.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-templater.d.ts","sourceRoot":"","sources":["../../src/services/url-templater.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2024 Pax8, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import crypto from "node:crypto";
|
|
17
|
+
/**
|
|
18
|
+
* URL Templating Service
|
|
19
|
+
*
|
|
20
|
+
* Detects tenant-specific URLs in Power Platform solutions and converts them to templates.
|
|
21
|
+
* At deploy time, templates are resolved to target tenant values.
|
|
22
|
+
*/
|
|
23
|
+
import { coreLogger } from "./logger.js";
|
|
24
|
+
const logger = coreLogger;
|
|
25
|
+
const URL_PATTERNS = [
|
|
26
|
+
{
|
|
27
|
+
type: "sharepoint",
|
|
28
|
+
// Matches: https://tenant.sharepoint.com/sites/path or https://tenant.sharepoint.com
|
|
29
|
+
regex: /https?:\/\/([a-zA-Z0-9-]+)\.sharepoint\.com(\/[^\s"'<>]*)?/gi,
|
|
30
|
+
extractTenant: (match) => match[1],
|
|
31
|
+
generateTemplate: (url, _tenant) => url.replace(new RegExp(`https?://([a-zA-Z0-9-]+)\\.sharepoint\\.com`, "i"), "https://{tenant}.sharepoint.com"),
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
type: "dynamics_crm",
|
|
35
|
+
// Matches: https://tenant.crm.dynamics.com or https://tenant.crm4.dynamics.com
|
|
36
|
+
regex: /https?:\/\/([a-zA-Z0-9-]+)\.(crm[0-9]*)\.dynamics\.com(\/[^\s"'<>]*)?/gi,
|
|
37
|
+
extractTenant: (match) => match[1],
|
|
38
|
+
extractRegion: (match) => match[2],
|
|
39
|
+
generateTemplate: (url, _tenant, region) => url.replace(new RegExp(`https?://([a-zA-Z0-9-]+)\\.(crm[0-9]*)\\.dynamics\\.com`, "i"), `https://{tenant}.${region || "crm"}.dynamics.com`),
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
type: "onmicrosoft",
|
|
43
|
+
// Matches: https://tenant.onmicrosoft.com or tenant.onmicrosoft.com in email/UPN
|
|
44
|
+
regex: /https?:\/\/([a-zA-Z0-9-]+)\.onmicrosoft\.com(\/[^\s"'<>]*)?/gi,
|
|
45
|
+
extractTenant: (match) => match[1],
|
|
46
|
+
generateTemplate: (url, _tenant) => url.replace(new RegExp(`https?://([a-zA-Z0-9-]+)\\.onmicrosoft\\.com`, "i"), "https://{tenant}.onmicrosoft.com"),
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
// File extensions to scan for URLs
|
|
50
|
+
const TEXT_FILE_EXTENSIONS = [".xml", ".json", ".yaml", ".yml"];
|
|
51
|
+
const TEXT_FILE_PATTERNS = [/\/data$/i, /\.data$/i];
|
|
52
|
+
export class UrlTemplater {
|
|
53
|
+
/**
|
|
54
|
+
* Scan a solution ZIP for tenant-specific URLs
|
|
55
|
+
*
|
|
56
|
+
* @param zip - A ZipArchive instance (JSZip or compatible)
|
|
57
|
+
* @returns Array of detected tenant-specific URLs with their locations
|
|
58
|
+
*/
|
|
59
|
+
async scanSolution(zip) {
|
|
60
|
+
const detectedUrls = [];
|
|
61
|
+
const seenUrls = new Set();
|
|
62
|
+
for (const [path, zipEntry] of Object.entries(zip.files)) {
|
|
63
|
+
const entry = zipEntry;
|
|
64
|
+
if (entry.dir)
|
|
65
|
+
continue;
|
|
66
|
+
// Check if this is a text file we should scan
|
|
67
|
+
const isTextFile = TEXT_FILE_EXTENSIONS.some((ext) => path.toLowerCase().endsWith(ext)) ||
|
|
68
|
+
TEXT_FILE_PATTERNS.some((pattern) => pattern.test(path));
|
|
69
|
+
if (!isTextFile)
|
|
70
|
+
continue;
|
|
71
|
+
try {
|
|
72
|
+
const content = await entry.async("text");
|
|
73
|
+
const urlsInFile = this.extractUrlsFromContent(content, path);
|
|
74
|
+
for (const url of urlsInFile) {
|
|
75
|
+
// Dedupe by original URL
|
|
76
|
+
if (!seenUrls.has(url.originalUrl)) {
|
|
77
|
+
seenUrls.add(url.originalUrl);
|
|
78
|
+
detectedUrls.push(url);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
// Log at debug level - binary files will fail to parse as text and that's expected
|
|
84
|
+
logger.debug("Skipping file that cannot be read as text", {
|
|
85
|
+
path,
|
|
86
|
+
error: error instanceof Error ? error.message : String(error),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return detectedUrls;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Extract tenant-specific URLs from text content using pattern matching
|
|
94
|
+
*
|
|
95
|
+
* This function scans text content (typically from XML, JSON, or YAML files
|
|
96
|
+
* within a Power Platform solution) and identifies tenant-specific URLs that
|
|
97
|
+
* should be templated for multi-tenant deployment.
|
|
98
|
+
*
|
|
99
|
+
* **Supported URL patterns:**
|
|
100
|
+
* - SharePoint: `https://{tenant}.sharepoint.com/...`
|
|
101
|
+
* - Dynamics 365: `https://{tenant}.crm[N].dynamics.com/...`
|
|
102
|
+
* - Microsoft 365: `https://{tenant}.onmicrosoft.com/...`
|
|
103
|
+
*
|
|
104
|
+
* Each detected URL is converted to a template pattern where the tenant
|
|
105
|
+
* identifier is replaced with `{tenant}`, allowing the URL to be resolved
|
|
106
|
+
* to different values for each target tenant during deployment.
|
|
107
|
+
*
|
|
108
|
+
* @param content - The text content to scan for URLs
|
|
109
|
+
* @param fileLocation - Path of the file being scanned (for tracking purposes)
|
|
110
|
+
* @returns Array of detected URLs with their types, extracted tenants, and template patterns
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```ts
|
|
114
|
+
* const urls = templater.extractUrlsFromContent(
|
|
115
|
+
* '<SharePointUrl>https://contoso.sharepoint.com/sites/docs</SharePointUrl>',
|
|
116
|
+
* 'solution/connections.xml'
|
|
117
|
+
* );
|
|
118
|
+
* // Returns: [{
|
|
119
|
+
* // type: 'sharepoint',
|
|
120
|
+
* // originalUrl: 'https://contoso.sharepoint.com/sites/docs',
|
|
121
|
+
* // extractedTenant: 'contoso',
|
|
122
|
+
* // templatePattern: 'https://{tenant}.sharepoint.com/sites/docs',
|
|
123
|
+
* // fileLocation: 'solution/connections.xml'
|
|
124
|
+
* // }]
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
extractUrlsFromContent(content, fileLocation) {
|
|
128
|
+
const urls = [];
|
|
129
|
+
for (const pattern of URL_PATTERNS) {
|
|
130
|
+
// Reset regex lastIndex
|
|
131
|
+
pattern.regex.lastIndex = 0;
|
|
132
|
+
let match;
|
|
133
|
+
while ((match = pattern.regex.exec(content)) !== null) {
|
|
134
|
+
const originalUrl = match[0].replace(/[,;:'")\]}>]+$/, ""); // Clean trailing punctuation
|
|
135
|
+
const tenant = pattern.extractTenant(match);
|
|
136
|
+
const region = pattern.extractRegion?.(match);
|
|
137
|
+
urls.push({
|
|
138
|
+
type: pattern.type,
|
|
139
|
+
originalUrl,
|
|
140
|
+
extractedTenant: tenant,
|
|
141
|
+
templatePattern: pattern.generateTemplate(originalUrl, tenant, region),
|
|
142
|
+
fileLocation,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return urls;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Infer the source tenant from detected URLs (most common tenant identifier)
|
|
150
|
+
*/
|
|
151
|
+
inferSourceTenant(urls) {
|
|
152
|
+
if (urls.length === 0)
|
|
153
|
+
return null;
|
|
154
|
+
// Count occurrences of each tenant
|
|
155
|
+
const tenantCounts = new Map();
|
|
156
|
+
for (const url of urls) {
|
|
157
|
+
const count = tenantCounts.get(url.extractedTenant) || 0;
|
|
158
|
+
tenantCounts.set(url.extractedTenant, count + 1);
|
|
159
|
+
}
|
|
160
|
+
// Return most common tenant
|
|
161
|
+
let maxCount = 0;
|
|
162
|
+
let mostCommonTenant = null;
|
|
163
|
+
for (const [tenant, count] of tenantCounts) {
|
|
164
|
+
if (count > maxCount) {
|
|
165
|
+
maxCount = count;
|
|
166
|
+
mostCommonTenant = tenant;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return mostCommonTenant;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Generate URL templates from detected URLs
|
|
173
|
+
*/
|
|
174
|
+
generateTemplates(detectedUrls) {
|
|
175
|
+
// Group by original URL to combine file locations
|
|
176
|
+
const urlMap = new Map();
|
|
177
|
+
for (const url of detectedUrls) {
|
|
178
|
+
const existing = urlMap.get(url.originalUrl) || [];
|
|
179
|
+
existing.push(url);
|
|
180
|
+
urlMap.set(url.originalUrl, existing);
|
|
181
|
+
}
|
|
182
|
+
// Create templates
|
|
183
|
+
const templates = [];
|
|
184
|
+
for (const [originalUrl, urls] of urlMap) {
|
|
185
|
+
const first = urls[0];
|
|
186
|
+
templates.push({
|
|
187
|
+
id: crypto.randomUUID(),
|
|
188
|
+
type: first.type,
|
|
189
|
+
originalUrl,
|
|
190
|
+
templatePattern: first.templatePattern,
|
|
191
|
+
extractedTenant: first.extractedTenant,
|
|
192
|
+
fileLocations: urls.map((u) => u.fileLocation),
|
|
193
|
+
description: this.getDescriptionForType(first.type),
|
|
194
|
+
confirmed: false,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
return templates;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Get a human-readable description for a URL type
|
|
201
|
+
*/
|
|
202
|
+
getDescriptionForType(type) {
|
|
203
|
+
switch (type) {
|
|
204
|
+
case "sharepoint":
|
|
205
|
+
return "SharePoint site URL - will be updated per tenant";
|
|
206
|
+
case "dynamics_crm":
|
|
207
|
+
return "Dynamics 365 / Dataverse URL - will be updated per tenant";
|
|
208
|
+
case "onmicrosoft":
|
|
209
|
+
return "Microsoft 365 tenant domain - will be updated per tenant";
|
|
210
|
+
case "custom":
|
|
211
|
+
return "Custom URL pattern";
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Resolve a template pattern to an actual URL for a target tenant
|
|
216
|
+
*/
|
|
217
|
+
resolveTemplate(templatePattern, tenantUrls) {
|
|
218
|
+
let resolved = templatePattern;
|
|
219
|
+
// Replace {tenant} placeholder
|
|
220
|
+
resolved = resolved.replace(/\{tenant\}/g, tenantUrls.tenant);
|
|
221
|
+
// Replace full domain patterns if present
|
|
222
|
+
resolved = resolved.replace(/\{tenant\}\.sharepoint\.com/g, tenantUrls.sharepoint);
|
|
223
|
+
resolved = resolved.replace(/\{tenant\}\.(crm[0-9]*)\.dynamics\.com/g, tenantUrls.dynamicsCrm);
|
|
224
|
+
resolved = resolved.replace(/\{tenant\}\.onmicrosoft\.com/g, tenantUrls.onmicrosoft);
|
|
225
|
+
return resolved;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Modify a Power Platform solution ZIP by replacing tenant-specific URLs
|
|
229
|
+
*
|
|
230
|
+
* This function takes a solution ZIP file and performs URL replacements
|
|
231
|
+
* in all text files (XML, JSON, YAML) within the archive. It's used during
|
|
232
|
+
* deployment to customize solutions for specific target tenants.
|
|
233
|
+
*
|
|
234
|
+
* **How it works:**
|
|
235
|
+
* 1. Loads the ZIP file into memory
|
|
236
|
+
* 2. Iterates through all files in the archive
|
|
237
|
+
* 3. For text files, performs string replacements for each URL mapping
|
|
238
|
+
* 4. Generates a new ZIP buffer with the modified content
|
|
239
|
+
*
|
|
240
|
+
* **Important notes:**
|
|
241
|
+
* - Binary files are skipped (images, compiled resources, etc.)
|
|
242
|
+
* - The original ZIP is not modified; a new buffer is returned
|
|
243
|
+
* - If no replacements are needed, the original buffer is returned unchanged
|
|
244
|
+
* - Requires a JSZip-compatible loader to be passed in
|
|
245
|
+
*
|
|
246
|
+
* @param zipBuffer - The original solution ZIP file as a Buffer
|
|
247
|
+
* @param replacements - Map of original URLs to resolved URLs
|
|
248
|
+
* @param zipLoader - JSZip-compatible loader for reading/writing ZIP files
|
|
249
|
+
* @returns New Buffer containing the modified solution ZIP
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* ```ts
|
|
253
|
+
* const JSZip = require('jszip');
|
|
254
|
+
* const replacements = new Map([
|
|
255
|
+
* ['https://contoso.sharepoint.com', 'https://fabrikam.sharepoint.com'],
|
|
256
|
+
* ['https://contoso.crm.dynamics.com', 'https://fabrikam.crm.dynamics.com'],
|
|
257
|
+
* ]);
|
|
258
|
+
* const modifiedZip = await templater.modifySolution(
|
|
259
|
+
* originalZipBuffer,
|
|
260
|
+
* replacements,
|
|
261
|
+
* new JSZip()
|
|
262
|
+
* );
|
|
263
|
+
* ```
|
|
264
|
+
*/
|
|
265
|
+
async modifySolution(zipBuffer, replacements, zipLoader) {
|
|
266
|
+
if (replacements.size === 0) {
|
|
267
|
+
return zipBuffer;
|
|
268
|
+
}
|
|
269
|
+
const zip = await zipLoader.loadAsync(zipBuffer);
|
|
270
|
+
for (const [path, zipEntry] of Object.entries(zip.files)) {
|
|
271
|
+
const entry = zipEntry;
|
|
272
|
+
if (entry.dir)
|
|
273
|
+
continue;
|
|
274
|
+
// Check if this is a text file
|
|
275
|
+
const isTextFile = TEXT_FILE_EXTENSIONS.some((ext) => path.toLowerCase().endsWith(ext)) ||
|
|
276
|
+
TEXT_FILE_PATTERNS.some((pattern) => pattern.test(path));
|
|
277
|
+
if (!isTextFile)
|
|
278
|
+
continue;
|
|
279
|
+
try {
|
|
280
|
+
let content = await entry.async("text");
|
|
281
|
+
let modified = false;
|
|
282
|
+
// Apply all replacements
|
|
283
|
+
for (const [original, resolved] of replacements) {
|
|
284
|
+
if (content.includes(original)) {
|
|
285
|
+
content = content.split(original).join(resolved);
|
|
286
|
+
modified = true;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
if (modified) {
|
|
290
|
+
zip.file(path, content);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
catch (error) {
|
|
294
|
+
// Log at debug level - binary files will fail to process and that's expected
|
|
295
|
+
logger.debug("Skipping file that cannot be processed for URL replacement", {
|
|
296
|
+
path,
|
|
297
|
+
error: error instanceof Error ? error.message : String(error),
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// Generate modified ZIP
|
|
302
|
+
return await zip.generateAsync({
|
|
303
|
+
type: "nodebuffer",
|
|
304
|
+
compression: "DEFLATE",
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Create a complete AgentUrlTemplates object from scanning results
|
|
309
|
+
*/
|
|
310
|
+
createAgentUrlTemplates(detectedUrls) {
|
|
311
|
+
if (detectedUrls.length === 0) {
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
const sourceTenant = this.inferSourceTenant(detectedUrls);
|
|
315
|
+
if (!sourceTenant) {
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
318
|
+
return {
|
|
319
|
+
sourceTenant,
|
|
320
|
+
templates: this.generateTemplates(detectedUrls),
|
|
321
|
+
createdAt: new Date().toISOString(),
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
// Export singleton instance
|
|
326
|
+
export const urlTemplater = new UrlTemplater();
|
|
327
|
+
//# sourceMappingURL=url-templater.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-templater.js","sourceRoot":"","sources":["../../src/services/url-templater.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2024 Pax8, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import { TokenManager } from "../auth/token-manager.js";
|
|
17
|
+
import { TenantConfig } from "../config/schema.js";
|
|
18
|
+
export interface SolutionVersionInfo {
|
|
19
|
+
uniqueName: string;
|
|
20
|
+
friendlyName: string;
|
|
21
|
+
expectedVersion: string;
|
|
22
|
+
deployedVersion: string | null;
|
|
23
|
+
isManaged: boolean;
|
|
24
|
+
status: "current" | "outdated" | "ahead" | "not_deployed" | "unknown";
|
|
25
|
+
versionDrift: number;
|
|
26
|
+
}
|
|
27
|
+
export interface TenantVersionStatus {
|
|
28
|
+
tenantId: string;
|
|
29
|
+
tenantName: string;
|
|
30
|
+
environmentUrl: string;
|
|
31
|
+
solutions: SolutionVersionInfo[];
|
|
32
|
+
overallStatus: "current" | "outdated" | "mixed" | "unknown";
|
|
33
|
+
lastChecked: string;
|
|
34
|
+
error?: string;
|
|
35
|
+
}
|
|
36
|
+
export interface VersionDriftSummary {
|
|
37
|
+
totalTenants: number;
|
|
38
|
+
currentTenants: number;
|
|
39
|
+
outdatedTenants: number;
|
|
40
|
+
unknownTenants: number;
|
|
41
|
+
solutionSummary: {
|
|
42
|
+
uniqueName: string;
|
|
43
|
+
friendlyName: string;
|
|
44
|
+
expectedVersion: string;
|
|
45
|
+
tenantsAtVersion: number;
|
|
46
|
+
tenantsBehind: number;
|
|
47
|
+
tenantsNotDeployed: number;
|
|
48
|
+
}[];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Compare two version strings (e.g., "1.0.0.5" vs "1.0.0.4")
|
|
52
|
+
* Returns: negative if a < b, 0 if equal, positive if a > b
|
|
53
|
+
*/
|
|
54
|
+
export declare function compareVersions(a: string, b: string): number;
|
|
55
|
+
/**
|
|
56
|
+
* Version Checker class for checking solution versions across tenants
|
|
57
|
+
*/
|
|
58
|
+
export declare class VersionChecker {
|
|
59
|
+
private cache;
|
|
60
|
+
private readonly CACHE_DURATION_MS;
|
|
61
|
+
/**
|
|
62
|
+
* Check solution versions for a single tenant
|
|
63
|
+
*/
|
|
64
|
+
checkTenantVersions(tenant: TenantConfig, expectedSolutions: Array<{
|
|
65
|
+
uniqueName: string;
|
|
66
|
+
friendlyName: string;
|
|
67
|
+
version: string;
|
|
68
|
+
}>, tokenManager?: TokenManager, skipCache?: boolean): Promise<TenantVersionStatus>;
|
|
69
|
+
/**
|
|
70
|
+
* Check versions for multiple tenants
|
|
71
|
+
*/
|
|
72
|
+
checkMultipleTenants(tenants: TenantConfig[], expectedSolutions: Array<{
|
|
73
|
+
uniqueName: string;
|
|
74
|
+
friendlyName: string;
|
|
75
|
+
version: string;
|
|
76
|
+
}>, tokenManager?: TokenManager, skipCache?: boolean): Promise<TenantVersionStatus[]>;
|
|
77
|
+
/**
|
|
78
|
+
* Get a summary of version drift across all tenants
|
|
79
|
+
*/
|
|
80
|
+
getVersionDriftSummary(tenants: TenantConfig[], expectedSolutions: Array<{
|
|
81
|
+
uniqueName: string;
|
|
82
|
+
friendlyName: string;
|
|
83
|
+
version: string;
|
|
84
|
+
}>, tokenManager?: TokenManager): Promise<VersionDriftSummary>;
|
|
85
|
+
/**
|
|
86
|
+
* Clear cache for a tenant or all tenants
|
|
87
|
+
*/
|
|
88
|
+
clearCache(tenantId?: string): void;
|
|
89
|
+
private calculateOverallStatus;
|
|
90
|
+
private getDemoVersionStatus;
|
|
91
|
+
/**
|
|
92
|
+
* Compute the version-drift status by comparing the rightmost-changed
|
|
93
|
+
* version segment. Used for demo-mode classification so `versionDrift`
|
|
94
|
+
* reflects how many releases behind the deployed version is — which is
|
|
95
|
+
* what the risk analyzer's `versions_behind` factor keys off of.
|
|
96
|
+
*/
|
|
97
|
+
private diffPatchVersion;
|
|
98
|
+
}
|
|
99
|
+
export declare const versionChecker: VersionChecker;
|
|
100
|
+
/**
|
|
101
|
+
* Get demo version status for all tenants and solutions
|
|
102
|
+
*/
|
|
103
|
+
export declare function getDemoVersionDriftSummary(): VersionDriftSummary;
|
|
104
|
+
/**
|
|
105
|
+
* Get demo version status for a specific tenant
|
|
106
|
+
*/
|
|
107
|
+
export declare function getDemoTenantVersionStatus(tenantId: string): TenantVersionStatus | null;
|
|
108
|
+
//# sourceMappingURL=version-checker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-checker.d.ts","sourceRoot":"","sources":["../../src/services/version-checker.ts"],"names":[],"mappings":"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"}
|