@pagopa/dx-savemoney 0.3.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/dist/__tests__/finding.test.js +22 -0
- package/dist/__tests__/finding.test.js.map +1 -1
- package/dist/azure/__tests__/analyzer-tags.test.js +28 -1
- package/dist/azure/__tests__/analyzer-tags.test.js.map +1 -1
- package/dist/azure/__tests__/config.test.js +31 -1
- package/dist/azure/__tests__/config.test.js.map +1 -1
- package/dist/azure/__tests__/report.test.js +71 -0
- package/dist/azure/__tests__/report.test.js.map +1 -1
- package/dist/azure/analyzer.d.ts +8 -1
- package/dist/azure/analyzer.d.ts.map +1 -1
- package/dist/azure/analyzer.js +57 -41
- package/dist/azure/analyzer.js.map +1 -1
- package/dist/azure/analyzers/registry.d.ts.map +1 -1
- package/dist/azure/analyzers/registry.js +4 -4
- package/dist/azure/analyzers/registry.js.map +1 -1
- package/dist/azure/analyzers/types.d.ts +6 -0
- package/dist/azure/analyzers/types.d.ts.map +1 -1
- package/dist/azure/config.d.ts.map +1 -1
- package/dist/azure/config.js +1 -5
- package/dist/azure/config.js.map +1 -1
- package/dist/azure/pricing/__tests__/cache.test.d.ts +8 -0
- package/dist/azure/pricing/__tests__/cache.test.d.ts.map +1 -0
- package/dist/azure/pricing/__tests__/cache.test.js +56 -0
- package/dist/azure/pricing/__tests__/cache.test.js.map +1 -0
- package/dist/azure/pricing/__tests__/client.test.d.ts +9 -0
- package/dist/azure/pricing/__tests__/client.test.d.ts.map +1 -0
- package/dist/azure/pricing/__tests__/client.test.js +181 -0
- package/dist/azure/pricing/__tests__/client.test.js.map +1 -0
- package/dist/azure/pricing/__tests__/pricing-service.test.d.ts +6 -0
- package/dist/azure/pricing/__tests__/pricing-service.test.d.ts.map +1 -0
- package/dist/azure/pricing/__tests__/pricing-service.test.js +283 -0
- package/dist/azure/pricing/__tests__/pricing-service.test.js.map +1 -0
- package/dist/azure/pricing/cache.d.ts +45 -0
- package/dist/azure/pricing/cache.d.ts.map +1 -0
- package/dist/azure/pricing/cache.js +79 -0
- package/dist/azure/pricing/cache.js.map +1 -0
- package/dist/azure/pricing/client.d.ts +67 -0
- package/dist/azure/pricing/client.d.ts.map +1 -0
- package/dist/azure/pricing/client.js +96 -0
- package/dist/azure/pricing/client.js.map +1 -0
- package/dist/azure/pricing/index.d.ts +6 -0
- package/dist/azure/pricing/index.d.ts.map +1 -0
- package/dist/azure/pricing/index.js +6 -0
- package/dist/azure/pricing/index.js.map +1 -0
- package/dist/azure/pricing/pricing-service.d.ts +46 -0
- package/dist/azure/pricing/pricing-service.d.ts.map +1 -0
- package/dist/azure/pricing/pricing-service.js +84 -0
- package/dist/azure/pricing/pricing-service.js.map +1 -0
- package/dist/azure/pricing/resolvers/__tests__/app-service.test.d.ts +5 -0
- package/dist/azure/pricing/resolvers/__tests__/app-service.test.d.ts.map +1 -0
- package/dist/azure/pricing/resolvers/__tests__/app-service.test.js +137 -0
- package/dist/azure/pricing/resolvers/__tests__/app-service.test.js.map +1 -0
- package/dist/azure/pricing/resolvers/__tests__/disk.test.d.ts +5 -0
- package/dist/azure/pricing/resolvers/__tests__/disk.test.d.ts.map +1 -0
- package/dist/azure/pricing/resolvers/__tests__/disk.test.js +160 -0
- package/dist/azure/pricing/resolvers/__tests__/disk.test.js.map +1 -0
- package/dist/azure/pricing/resolvers/__tests__/public-ip.test.d.ts +5 -0
- package/dist/azure/pricing/resolvers/__tests__/public-ip.test.d.ts.map +1 -0
- package/dist/azure/pricing/resolvers/__tests__/public-ip.test.js +113 -0
- package/dist/azure/pricing/resolvers/__tests__/public-ip.test.js.map +1 -0
- package/dist/azure/pricing/resolvers/__tests__/vm.test.d.ts +9 -0
- package/dist/azure/pricing/resolvers/__tests__/vm.test.d.ts.map +1 -0
- package/dist/azure/pricing/resolvers/__tests__/vm.test.js +204 -0
- package/dist/azure/pricing/resolvers/__tests__/vm.test.js.map +1 -0
- package/dist/azure/pricing/resolvers/app-service.d.ts +27 -0
- package/dist/azure/pricing/resolvers/app-service.d.ts.map +1 -0
- package/dist/azure/pricing/resolvers/app-service.js +67 -0
- package/dist/azure/pricing/resolvers/app-service.js.map +1 -0
- package/dist/azure/pricing/resolvers/disk.d.ts +59 -0
- package/dist/azure/pricing/resolvers/disk.d.ts.map +1 -0
- package/dist/azure/pricing/resolvers/disk.js +140 -0
- package/dist/azure/pricing/resolvers/disk.js.map +1 -0
- package/dist/azure/pricing/resolvers/index.d.ts +12 -0
- package/dist/azure/pricing/resolvers/index.d.ts.map +1 -0
- package/dist/azure/pricing/resolvers/index.js +8 -0
- package/dist/azure/pricing/resolvers/index.js.map +1 -0
- package/dist/azure/pricing/resolvers/public-ip.d.ts +32 -0
- package/dist/azure/pricing/resolvers/public-ip.d.ts.map +1 -0
- package/dist/azure/pricing/resolvers/public-ip.js +56 -0
- package/dist/azure/pricing/resolvers/public-ip.js.map +1 -0
- package/dist/azure/pricing/resolvers/vm.d.ts +51 -0
- package/dist/azure/pricing/resolvers/vm.d.ts.map +1 -0
- package/dist/azure/pricing/resolvers/vm.js +89 -0
- package/dist/azure/pricing/resolvers/vm.js.map +1 -0
- package/dist/azure/pricing/schema.d.ts +88 -0
- package/dist/azure/pricing/schema.d.ts.map +1 -0
- package/dist/azure/pricing/schema.js +64 -0
- package/dist/azure/pricing/schema.js.map +1 -0
- package/dist/azure/pricing/test-cache-dir.d.ts +3 -0
- package/dist/azure/pricing/test-cache-dir.d.ts.map +1 -0
- package/dist/azure/pricing/test-cache-dir.js +17 -0
- package/dist/azure/pricing/test-cache-dir.js.map +1 -0
- package/dist/azure/report.d.ts.map +1 -1
- package/dist/azure/report.js +57 -18
- package/dist/azure/report.js.map +1 -1
- package/dist/azure/resources/__tests__/app-service.test.d.ts +5 -0
- package/dist/azure/resources/__tests__/app-service.test.d.ts.map +1 -0
- package/dist/azure/resources/__tests__/app-service.test.js +105 -0
- package/dist/azure/resources/__tests__/app-service.test.js.map +1 -0
- package/dist/azure/resources/app-service.d.ts +8 -3
- package/dist/azure/resources/app-service.d.ts.map +1 -1
- package/dist/azure/resources/app-service.js +35 -2
- package/dist/azure/resources/app-service.js.map +1 -1
- package/dist/azure/resources/disk.d.ts +3 -1
- package/dist/azure/resources/disk.d.ts.map +1 -1
- package/dist/azure/resources/disk.js +35 -3
- package/dist/azure/resources/disk.js.map +1 -1
- package/dist/azure/resources/public-ip.d.ts +3 -1
- package/dist/azure/resources/public-ip.d.ts.map +1 -1
- package/dist/azure/resources/public-ip.js +41 -3
- package/dist/azure/resources/public-ip.js.map +1 -1
- package/dist/azure/resources/vm.d.ts +4 -1
- package/dist/azure/resources/vm.d.ts.map +1 -1
- package/dist/azure/resources/vm.js +49 -6
- package/dist/azure/resources/vm.js.map +1 -1
- package/dist/azure/types.d.ts +18 -3
- package/dist/azure/types.d.ts.map +1 -1
- package/dist/finding.d.ts +3 -3
- package/dist/finding.d.ts.map +1 -1
- package/dist/finding.js +7 -0
- package/dist/finding.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/schema.d.ts +5 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +5 -3
- package/dist/schema.js.map +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/finding.test.ts +24 -0
- package/src/azure/__tests__/analyzer-tags.test.ts +36 -1
- package/src/azure/__tests__/config.test.ts +43 -1
- package/src/azure/__tests__/fixtures/full-override.yaml +2 -0
- package/src/azure/__tests__/report.test.ts +78 -0
- package/src/azure/analyzer.ts +70 -52
- package/src/azure/analyzers/registry.ts +8 -2
- package/src/azure/analyzers/types.ts +6 -0
- package/src/azure/config.ts +1 -5
- package/src/azure/pricing/__tests__/cache.test.ts +67 -0
- package/src/azure/pricing/__tests__/client.test.ts +212 -0
- package/src/azure/pricing/__tests__/fixtures/vm-b2s-westeurope.json +51 -0
- package/src/azure/pricing/__tests__/pricing-service.test.ts +315 -0
- package/src/azure/pricing/cache.ts +92 -0
- package/src/azure/pricing/client.ts +137 -0
- package/src/azure/pricing/index.ts +6 -0
- package/src/azure/pricing/pricing-service.ts +125 -0
- package/src/azure/pricing/resolvers/__tests__/app-service.test.ts +154 -0
- package/src/azure/pricing/resolvers/__tests__/disk.test.ts +189 -0
- package/src/azure/pricing/resolvers/__tests__/public-ip.test.ts +130 -0
- package/src/azure/pricing/resolvers/__tests__/vm.test.ts +232 -0
- package/src/azure/pricing/resolvers/app-service.ts +102 -0
- package/src/azure/pricing/resolvers/disk.ts +170 -0
- package/src/azure/pricing/resolvers/index.ts +31 -0
- package/src/azure/pricing/resolvers/public-ip.ts +87 -0
- package/src/azure/pricing/resolvers/vm.ts +125 -0
- package/src/azure/pricing/schema.ts +69 -0
- package/src/azure/pricing/test-cache-dir.ts +26 -0
- package/src/azure/report.ts +86 -21
- package/src/azure/resources/__tests__/app-service.test.ts +165 -0
- package/src/azure/resources/app-service.ts +65 -4
- package/src/azure/resources/disk.ts +46 -4
- package/src/azure/resources/public-ip.ts +61 -2
- package/src/azure/resources/vm.ts +89 -11
- package/src/azure/types.ts +19 -3
- package/src/finding.ts +10 -3
- package/src/index.ts +4 -3
- package/src/schema.ts +7 -3
- package/src/types.ts +12 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-ip.js","sourceRoot":"","sources":["../../../../src/azure/pricing/resolvers/public-ip.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAc9D;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,MAAqB,EACrB,KAA2B;IAE3B,6DAA6D;IAC7D,MAAM,MAAM,GAAG;QACb,kCAAkC;QAClC,qBAAqB,kBAAkB,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG;QAC/D,eAAe,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG;KACxC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAEhB,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IACvD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,GAAG,eAAe,CAAC;QAChD,QAAQ,EAAE,IAAI,CAAC,YAAY;KAC5B,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACrC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;AAC/D,CAAC;AAED,SAAS,gBAAgB,CACvB,KAAkB,EAClB,UAA8B;IAE9B,MAAM,eAAe,GAAG,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;IACvE,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAC7B,CAAC,EAAE,EAAE,EAAE,CACL,EAAE,CAAC,IAAI,KAAK,aAAa;QACzB,EAAE,CAAC,aAAa,KAAK,QAAQ;QAC7B,CAAC,EAAE,CAAC,SAAS,EAAE,WAAW,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,KAAK,CAAC;QAC7D,CAAC,EAAE,CAAC,SAAS,EAAE,WAAW,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,KAAK,CAAC,CACnE,CAAC;IACF,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9C,yDAAyD;IACzD,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,CACxC,EAAE,CAAC,SAAS,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAClD,CAAC;AACJ,CAAC;AAED,SAAS,MAAM,CAAC,KAAa;IAC3B,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolver: estimated monthly cost of an Azure Virtual Machine SKU.
|
|
3
|
+
*
|
|
4
|
+
* Uses the Azure Retail Prices API to look up the pay-as-you-go consumption
|
|
5
|
+
* price for the given `armSkuName` in the given region, then converts the
|
|
6
|
+
* hourly rate to a monthly figure assuming the conventional `730 hours`
|
|
7
|
+
* (365.25 * 24 / 12) for "always-on" workloads.
|
|
8
|
+
*
|
|
9
|
+
* The lookup is intentionally conservative:
|
|
10
|
+
* - It restricts results to `type === "Consumption"` (no Reservations,
|
|
11
|
+
* no Spot/Low Priority, no Savings Plans).
|
|
12
|
+
* - It defaults to the Linux variant (cheapest) when the resource OS is
|
|
13
|
+
* unknown, so the returned figure is a LOWER BOUND of the real cost.
|
|
14
|
+
* - It returns `undefined` whenever it cannot identify a single
|
|
15
|
+
* unambiguous price item, so callers can treat the savings estimate
|
|
16
|
+
* as best-effort.
|
|
17
|
+
*/
|
|
18
|
+
import type { Money } from "../../../finding.js";
|
|
19
|
+
import type { PricingClient } from "../client.js";
|
|
20
|
+
/**
|
|
21
|
+
* Conventional hours-per-month used across Azure cost calculators
|
|
22
|
+
* (365.25 days × 24 h / 12 months ≈ 730).
|
|
23
|
+
*/
|
|
24
|
+
export declare const HOURS_PER_MONTH = 730;
|
|
25
|
+
export type ResolveVmInput = {
|
|
26
|
+
/** ARM region name, e.g. `westeurope`. */
|
|
27
|
+
armRegionName: string;
|
|
28
|
+
/** ARM SKU name, e.g. `Standard_B2s`. */
|
|
29
|
+
armSkuName: string;
|
|
30
|
+
/** Optional OS hint. Defaults to `linux`. */
|
|
31
|
+
os?: VmOs;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Operating system hint used to disambiguate Windows vs. Linux meters.
|
|
35
|
+
* When unset (default) the cheapest Linux variant is picked.
|
|
36
|
+
*/
|
|
37
|
+
export type VmOs = "linux" | "windows";
|
|
38
|
+
/**
|
|
39
|
+
* Normalises a region string to the `armRegionName` format expected by
|
|
40
|
+
* the Retail Prices API (lowercase, no spaces). The Azure SDK sometimes
|
|
41
|
+
* returns the display name (`"West Europe"`) instead of the ARM name
|
|
42
|
+
* (`"westeurope"`); without this normalisation the OData filter would
|
|
43
|
+
* silently miss every entry.
|
|
44
|
+
*/
|
|
45
|
+
export declare function normalizeArmRegion(region: string): string;
|
|
46
|
+
/**
|
|
47
|
+
* Resolves the estimated monthly cost for a VM SKU. Returns `undefined`
|
|
48
|
+
* if no matching consumption meter can be found.
|
|
49
|
+
*/
|
|
50
|
+
export declare function resolveVmMonthlyPrice(client: PricingClient, input: ResolveVmInput): Promise<Money | undefined>;
|
|
51
|
+
//# sourceMappingURL=vm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vm.d.ts","sourceRoot":"","sources":["../../../../src/azure/pricing/resolvers/vm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAGlD;;;GAGG;AACH,eAAO,MAAM,eAAe,MAAM,CAAC;AAEnC,MAAM,MAAM,cAAc,GAAG;IAC3B,0CAA0C;IAC1C,aAAa,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,EAAE,CAAC,EAAE,IAAI,CAAC;CACX,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,IAAI,GAAG,OAAO,GAAG,SAAS,CAAC;AAEvC;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,aAAa,EACrB,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAiB5B"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolver: estimated monthly cost of an Azure Virtual Machine SKU.
|
|
3
|
+
*
|
|
4
|
+
* Uses the Azure Retail Prices API to look up the pay-as-you-go consumption
|
|
5
|
+
* price for the given `armSkuName` in the given region, then converts the
|
|
6
|
+
* hourly rate to a monthly figure assuming the conventional `730 hours`
|
|
7
|
+
* (365.25 * 24 / 12) for "always-on" workloads.
|
|
8
|
+
*
|
|
9
|
+
* The lookup is intentionally conservative:
|
|
10
|
+
* - It restricts results to `type === "Consumption"` (no Reservations,
|
|
11
|
+
* no Spot/Low Priority, no Savings Plans).
|
|
12
|
+
* - It defaults to the Linux variant (cheapest) when the resource OS is
|
|
13
|
+
* unknown, so the returned figure is a LOWER BOUND of the real cost.
|
|
14
|
+
* - It returns `undefined` whenever it cannot identify a single
|
|
15
|
+
* unambiguous price item, so callers can treat the savings estimate
|
|
16
|
+
* as best-effort.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Conventional hours-per-month used across Azure cost calculators
|
|
20
|
+
* (365.25 days × 24 h / 12 months ≈ 730).
|
|
21
|
+
*/
|
|
22
|
+
export const HOURS_PER_MONTH = 730;
|
|
23
|
+
/**
|
|
24
|
+
* Normalises a region string to the `armRegionName` format expected by
|
|
25
|
+
* the Retail Prices API (lowercase, no spaces). The Azure SDK sometimes
|
|
26
|
+
* returns the display name (`"West Europe"`) instead of the ARM name
|
|
27
|
+
* (`"westeurope"`); without this normalisation the OData filter would
|
|
28
|
+
* silently miss every entry.
|
|
29
|
+
*/
|
|
30
|
+
export function normalizeArmRegion(region) {
|
|
31
|
+
return region.toLowerCase().replace(/\s+/g, "");
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Resolves the estimated monthly cost for a VM SKU. Returns `undefined`
|
|
35
|
+
* if no matching consumption meter can be found.
|
|
36
|
+
*/
|
|
37
|
+
export async function resolveVmMonthlyPrice(client, input) {
|
|
38
|
+
const filter = [
|
|
39
|
+
"serviceName eq 'Virtual Machines'",
|
|
40
|
+
`armRegionName eq '${normalizeArmRegion(input.armRegionName)}'`,
|
|
41
|
+
`armSkuName eq '${input.armSkuName}'`,
|
|
42
|
+
].join(" and ");
|
|
43
|
+
const items = await client.query(filter);
|
|
44
|
+
const item = pickVmItem(items, input.os ?? "linux");
|
|
45
|
+
if (!item) {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
amount: round2(item.unitPrice * HOURS_PER_MONTH),
|
|
50
|
+
currency: item.currencyCode,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function isSpotOrLowPriority(item) {
|
|
54
|
+
const sku = item.skuName?.toLowerCase() ?? "";
|
|
55
|
+
const meter = item.meterName?.toLowerCase() ?? "";
|
|
56
|
+
return (sku.includes("spot") ||
|
|
57
|
+
sku.includes("low priority") ||
|
|
58
|
+
meter.includes("spot") ||
|
|
59
|
+
meter.includes("low priority"));
|
|
60
|
+
}
|
|
61
|
+
function matchesOs(item, os) {
|
|
62
|
+
const product = item.productName?.toLowerCase() ?? "";
|
|
63
|
+
const isWindowsItem = product.includes("windows");
|
|
64
|
+
return os === "windows" ? isWindowsItem : !isWindowsItem;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Picks the most appropriate Retail Prices entry for the given OS hint.
|
|
68
|
+
*
|
|
69
|
+
* Filters out:
|
|
70
|
+
* - non-Consumption entries (Reservations, Savings Plans, …)
|
|
71
|
+
* - Spot / Low Priority entries (variable pricing)
|
|
72
|
+
* - Windows entries when the hint is `linux` and vice versa
|
|
73
|
+
*
|
|
74
|
+
* Then prefers the entry with the lowest `unitPrice` to act as a
|
|
75
|
+
* conservative lower bound.
|
|
76
|
+
*/
|
|
77
|
+
function pickVmItem(items, os) {
|
|
78
|
+
const candidates = items.filter((it) => it.type === "Consumption" &&
|
|
79
|
+
it.unitOfMeasure === "1 Hour" &&
|
|
80
|
+
!isSpotOrLowPriority(it) &&
|
|
81
|
+
matchesOs(it, os));
|
|
82
|
+
if (candidates.length === 0)
|
|
83
|
+
return undefined;
|
|
84
|
+
return candidates.reduce((cheapest, it) => it.unitPrice < cheapest.unitPrice ? it : cheapest);
|
|
85
|
+
}
|
|
86
|
+
function round2(value) {
|
|
87
|
+
return Math.round(value * 100) / 100;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=vm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vm.js","sourceRoot":"","sources":["../../../../src/azure/pricing/resolvers/vm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,CAAC;AAiBnC;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,OAAO,MAAM,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAClD,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,MAAqB,EACrB,KAAqB;IAErB,MAAM,MAAM,GAAG;QACb,mCAAmC;QACnC,qBAAqB,kBAAkB,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG;QAC/D,kBAAkB,KAAK,CAAC,UAAU,GAAG;KACtC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAEhB,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,IAAI,OAAO,CAAC,CAAC;IACpD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,GAAG,eAAe,CAAC;QAChD,QAAQ,EAAE,IAAI,CAAC,YAAY;KAC5B,CAAC;AACJ,CAAC;AAED,SAAS,mBAAmB,CAAC,IAAe;IAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IAClD,OAAO,CACL,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;QACpB,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC;QAC5B,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;QACtB,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,CAC/B,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,IAAe,EAAE,EAAQ;IAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IACtD,MAAM,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAClD,OAAO,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;AAC3D,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,UAAU,CAAC,KAAkB,EAAE,EAAQ;IAC9C,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAC7B,CAAC,EAAE,EAAE,EAAE,CACL,EAAE,CAAC,IAAI,KAAK,aAAa;QACzB,EAAE,CAAC,aAAa,KAAK,QAAQ;QAC7B,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACxB,SAAS,CAAC,EAAE,EAAE,EAAE,CAAC,CACpB,CAAC;IACF,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9C,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,CACxC,EAAE,CAAC,SAAS,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAClD,CAAC;AACJ,CAAC;AAED,SAAS,MAAM,CAAC,KAAa;IAC3B,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod schemas for the Azure Retail Prices REST API.
|
|
3
|
+
*
|
|
4
|
+
* Endpoint: https://prices.azure.com/api/retail/prices
|
|
5
|
+
* Docs: https://learn.microsoft.com/rest/api/cost-management/retail-prices/azure-retail-prices
|
|
6
|
+
*
|
|
7
|
+
* The API returns a flat list of `Items` (one per meter) plus an optional
|
|
8
|
+
* `NextPageLink` for pagination. Extra fields returned by Azure are tolerated,
|
|
9
|
+
* but the fields used by pricing logic are validated with narrow shapes.
|
|
10
|
+
*/
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
/**
|
|
13
|
+
* A single priced meter returned by the Retail Prices API.
|
|
14
|
+
*
|
|
15
|
+
* Notable fields:
|
|
16
|
+
* - `unitPrice`: list price per `unitOfMeasure` (e.g. "1 Hour", "1 GB/Month")
|
|
17
|
+
* - `retailPrice`: typically equals `unitPrice` but kept distinct by Azure
|
|
18
|
+
* - `armSkuName`: ARM SKU identifier (e.g. "Standard_B2s") — present for
|
|
19
|
+
* VM/compute meters, absent for some services (Bandwidth, Support, …)
|
|
20
|
+
* - `reservationTerm`: present ONLY for Reservation meters; consumers that
|
|
21
|
+
* want on-demand pricing must filter by `type === "Consumption"`.
|
|
22
|
+
*/
|
|
23
|
+
export declare const PriceItemSchema: z.ZodObject<{
|
|
24
|
+
armRegionName: z.ZodOptional<z.ZodString>;
|
|
25
|
+
armSkuName: z.ZodOptional<z.ZodString>;
|
|
26
|
+
currencyCode: z.ZodString;
|
|
27
|
+
effectiveStartDate: z.ZodOptional<z.ZodString>;
|
|
28
|
+
isPrimaryMeterRegion: z.ZodOptional<z.ZodBoolean>;
|
|
29
|
+
location: z.ZodOptional<z.ZodString>;
|
|
30
|
+
meterId: z.ZodOptional<z.ZodString>;
|
|
31
|
+
meterName: z.ZodOptional<z.ZodString>;
|
|
32
|
+
productId: z.ZodOptional<z.ZodString>;
|
|
33
|
+
productName: z.ZodOptional<z.ZodString>;
|
|
34
|
+
reservationTerm: z.ZodOptional<z.ZodString>;
|
|
35
|
+
retailPrice: z.ZodNumber;
|
|
36
|
+
serviceFamily: z.ZodOptional<z.ZodString>;
|
|
37
|
+
serviceId: z.ZodOptional<z.ZodString>;
|
|
38
|
+
serviceName: z.ZodOptional<z.ZodString>;
|
|
39
|
+
skuId: z.ZodOptional<z.ZodString>;
|
|
40
|
+
skuName: z.ZodOptional<z.ZodString>;
|
|
41
|
+
tierMinimumUnits: z.ZodOptional<z.ZodNumber>;
|
|
42
|
+
type: z.ZodEnum<{
|
|
43
|
+
Consumption: "Consumption";
|
|
44
|
+
DevTestConsumption: "DevTestConsumption";
|
|
45
|
+
Reservation: "Reservation";
|
|
46
|
+
}>;
|
|
47
|
+
unitOfMeasure: z.ZodString;
|
|
48
|
+
unitPrice: z.ZodNumber;
|
|
49
|
+
}, z.core.$strip>;
|
|
50
|
+
export type PriceItem = z.infer<typeof PriceItemSchema>;
|
|
51
|
+
/**
|
|
52
|
+
* Top-level response envelope. `Count` reflects the number of items in the
|
|
53
|
+
* current page, not the grand total.
|
|
54
|
+
*/
|
|
55
|
+
export declare const PricingResponseSchema: z.ZodObject<{
|
|
56
|
+
BillingCurrency: z.ZodOptional<z.ZodString>;
|
|
57
|
+
Count: z.ZodOptional<z.ZodNumber>;
|
|
58
|
+
Items: z.ZodArray<z.ZodObject<{
|
|
59
|
+
armRegionName: z.ZodOptional<z.ZodString>;
|
|
60
|
+
armSkuName: z.ZodOptional<z.ZodString>;
|
|
61
|
+
currencyCode: z.ZodString;
|
|
62
|
+
effectiveStartDate: z.ZodOptional<z.ZodString>;
|
|
63
|
+
isPrimaryMeterRegion: z.ZodOptional<z.ZodBoolean>;
|
|
64
|
+
location: z.ZodOptional<z.ZodString>;
|
|
65
|
+
meterId: z.ZodOptional<z.ZodString>;
|
|
66
|
+
meterName: z.ZodOptional<z.ZodString>;
|
|
67
|
+
productId: z.ZodOptional<z.ZodString>;
|
|
68
|
+
productName: z.ZodOptional<z.ZodString>;
|
|
69
|
+
reservationTerm: z.ZodOptional<z.ZodString>;
|
|
70
|
+
retailPrice: z.ZodNumber;
|
|
71
|
+
serviceFamily: z.ZodOptional<z.ZodString>;
|
|
72
|
+
serviceId: z.ZodOptional<z.ZodString>;
|
|
73
|
+
serviceName: z.ZodOptional<z.ZodString>;
|
|
74
|
+
skuId: z.ZodOptional<z.ZodString>;
|
|
75
|
+
skuName: z.ZodOptional<z.ZodString>;
|
|
76
|
+
tierMinimumUnits: z.ZodOptional<z.ZodNumber>;
|
|
77
|
+
type: z.ZodEnum<{
|
|
78
|
+
Consumption: "Consumption";
|
|
79
|
+
DevTestConsumption: "DevTestConsumption";
|
|
80
|
+
Reservation: "Reservation";
|
|
81
|
+
}>;
|
|
82
|
+
unitOfMeasure: z.ZodString;
|
|
83
|
+
unitPrice: z.ZodNumber;
|
|
84
|
+
}, z.core.$strip>>;
|
|
85
|
+
NextPageLink: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
86
|
+
}, z.core.$strip>;
|
|
87
|
+
export type PricingResponse = z.infer<typeof PricingResponseSchema>;
|
|
88
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/azure/pricing/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAUxB;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuB1B,CAAC;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD;;;GAGG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAKhC,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod schemas for the Azure Retail Prices REST API.
|
|
3
|
+
*
|
|
4
|
+
* Endpoint: https://prices.azure.com/api/retail/prices
|
|
5
|
+
* Docs: https://learn.microsoft.com/rest/api/cost-management/retail-prices/azure-retail-prices
|
|
6
|
+
*
|
|
7
|
+
* The API returns a flat list of `Items` (one per meter) plus an optional
|
|
8
|
+
* `NextPageLink` for pagination. Extra fields returned by Azure are tolerated,
|
|
9
|
+
* but the fields used by pricing logic are validated with narrow shapes.
|
|
10
|
+
*/
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
const NonEmptyStringSchema = z.string().min(1);
|
|
13
|
+
const PriceTypeSchema = z.enum([
|
|
14
|
+
"Consumption",
|
|
15
|
+
"DevTestConsumption",
|
|
16
|
+
"Reservation",
|
|
17
|
+
]);
|
|
18
|
+
const PriceValueSchema = z.number().finite().nonnegative();
|
|
19
|
+
/**
|
|
20
|
+
* A single priced meter returned by the Retail Prices API.
|
|
21
|
+
*
|
|
22
|
+
* Notable fields:
|
|
23
|
+
* - `unitPrice`: list price per `unitOfMeasure` (e.g. "1 Hour", "1 GB/Month")
|
|
24
|
+
* - `retailPrice`: typically equals `unitPrice` but kept distinct by Azure
|
|
25
|
+
* - `armSkuName`: ARM SKU identifier (e.g. "Standard_B2s") — present for
|
|
26
|
+
* VM/compute meters, absent for some services (Bandwidth, Support, …)
|
|
27
|
+
* - `reservationTerm`: present ONLY for Reservation meters; consumers that
|
|
28
|
+
* want on-demand pricing must filter by `type === "Consumption"`.
|
|
29
|
+
*/
|
|
30
|
+
export const PriceItemSchema = z.object({
|
|
31
|
+
armRegionName: NonEmptyStringSchema.optional(),
|
|
32
|
+
armSkuName: NonEmptyStringSchema.optional(),
|
|
33
|
+
currencyCode: z.string().length(3),
|
|
34
|
+
effectiveStartDate: NonEmptyStringSchema.optional(),
|
|
35
|
+
isPrimaryMeterRegion: z.boolean().optional(),
|
|
36
|
+
location: NonEmptyStringSchema.optional(),
|
|
37
|
+
meterId: NonEmptyStringSchema.optional(),
|
|
38
|
+
meterName: NonEmptyStringSchema.optional(),
|
|
39
|
+
productId: NonEmptyStringSchema.optional(),
|
|
40
|
+
productName: NonEmptyStringSchema.optional(),
|
|
41
|
+
reservationTerm: NonEmptyStringSchema.optional(),
|
|
42
|
+
retailPrice: PriceValueSchema,
|
|
43
|
+
serviceFamily: NonEmptyStringSchema.optional(),
|
|
44
|
+
serviceId: NonEmptyStringSchema.optional(),
|
|
45
|
+
serviceName: NonEmptyStringSchema.optional(),
|
|
46
|
+
skuId: NonEmptyStringSchema.optional(),
|
|
47
|
+
skuName: NonEmptyStringSchema.optional(),
|
|
48
|
+
tierMinimumUnits: PriceValueSchema.optional(),
|
|
49
|
+
/** "Consumption" | "Reservation" | "DevTestConsumption". */
|
|
50
|
+
type: PriceTypeSchema,
|
|
51
|
+
unitOfMeasure: NonEmptyStringSchema,
|
|
52
|
+
unitPrice: PriceValueSchema,
|
|
53
|
+
});
|
|
54
|
+
/**
|
|
55
|
+
* Top-level response envelope. `Count` reflects the number of items in the
|
|
56
|
+
* current page, not the grand total.
|
|
57
|
+
*/
|
|
58
|
+
export const PricingResponseSchema = z.object({
|
|
59
|
+
BillingCurrency: z.string().length(3).optional(),
|
|
60
|
+
Count: z.number().int().nonnegative().optional(),
|
|
61
|
+
Items: z.array(PriceItemSchema),
|
|
62
|
+
NextPageLink: z.string().url().nullable().optional(),
|
|
63
|
+
});
|
|
64
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/azure/pricing/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC/C,MAAM,eAAe,GAAG,CAAC,CAAC,IAAI,CAAC;IAC7B,aAAa;IACb,oBAAoB;IACpB,aAAa;CACd,CAAC,CAAC;AACH,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,CAAC;AAE3D;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,aAAa,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IAC9C,UAAU,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IAC3C,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAClC,kBAAkB,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IACnD,oBAAoB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC5C,QAAQ,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IACzC,OAAO,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IACxC,SAAS,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IAC1C,SAAS,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IAC1C,WAAW,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IAC5C,eAAe,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IAChD,WAAW,EAAE,gBAAgB;IAC7B,aAAa,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IAC9C,SAAS,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IAC1C,WAAW,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IAC5C,KAAK,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IACtC,OAAO,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IACxC,gBAAgB,EAAE,gBAAgB,CAAC,QAAQ,EAAE;IAC7C,4DAA4D;IAC5D,IAAI,EAAE,eAAe;IACrB,aAAa,EAAE,oBAAoB;IACnC,SAAS,EAAE,gBAAgB;CAC5B,CAAC,CAAC;AAGH;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAChD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE;IAChD,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC;IAC/B,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;CACrD,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-cache-dir.d.ts","sourceRoot":"","sources":["../../../src/azure/pricing/test-cache-dir.ts"],"names":[],"mappings":"AAUA,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGtE;AAED,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAUnE"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { mkdir, mkdtemp, rm } from "node:fs/promises";
|
|
2
|
+
import { isAbsolute, join, relative } from "node:path";
|
|
3
|
+
const TEST_CACHE_PARENT = join(process.cwd(), "node_modules", ".cache", "dx-savemoney-tests");
|
|
4
|
+
export async function makeTestCacheDir(prefix) {
|
|
5
|
+
await mkdir(TEST_CACHE_PARENT, { recursive: true });
|
|
6
|
+
return mkdtemp(join(TEST_CACHE_PARENT, `${prefix}-`));
|
|
7
|
+
}
|
|
8
|
+
export async function removeTestCacheDir(dir) {
|
|
9
|
+
const relativePath = relative(TEST_CACHE_PARENT, dir);
|
|
10
|
+
if (relativePath === "" ||
|
|
11
|
+
relativePath.startsWith("..") ||
|
|
12
|
+
isAbsolute(relativePath)) {
|
|
13
|
+
throw new Error(`Refusing to remove non-test cache directory: ${dir}`);
|
|
14
|
+
}
|
|
15
|
+
await rm(dir, { force: true, recursive: true });
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=test-cache-dir.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-cache-dir.js","sourceRoot":"","sources":["../../../src/azure/pricing/test-cache-dir.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEvD,MAAM,iBAAiB,GAAG,IAAI,CAC5B,OAAO,CAAC,GAAG,EAAE,EACb,cAAc,EACd,QAAQ,EACR,oBAAoB,CACrB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAAc;IACnD,MAAM,KAAK,CAAC,iBAAiB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,OAAO,OAAO,CAAC,IAAI,CAAC,iBAAiB,EAAE,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,GAAW;IAClD,MAAM,YAAY,GAAG,QAAQ,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;IACtD,IACE,YAAY,KAAK,EAAE;QACnB,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC;QAC7B,UAAU,CAAC,YAAY,CAAC,EACxB,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,gDAAgD,GAAG,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAClD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/azure/report.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EACV,2BAA2B,EAE5B,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/azure/report.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EACV,2BAA2B,EAE5B,MAAM,YAAY,CAAC;AA+CpB;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,2BAA2B,EAAE,EACrC,MAAM,EAAE,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,iBAmDpD"}
|
package/dist/azure/report.js
CHANGED
|
@@ -90,6 +90,7 @@ export async function generateReport(report, format) {
|
|
|
90
90
|
*/
|
|
91
91
|
function computeSummary(report) {
|
|
92
92
|
const summary = {
|
|
93
|
+
costAtRiskByCurrency: new Map(),
|
|
93
94
|
counts: { high: 0, low: 0, medium: 0 },
|
|
94
95
|
savingsByCurrency: new Map(),
|
|
95
96
|
sourceCounts: {},
|
|
@@ -110,11 +111,18 @@ function computeSummary(report) {
|
|
|
110
111
|
summary.counts[line.severity]++;
|
|
111
112
|
summary.sourceCounts[line.source] =
|
|
112
113
|
(summary.sourceCounts[line.source] ?? 0) + 1;
|
|
113
|
-
if (line.savings) {
|
|
114
|
+
if (line.source === "advisor" && line.savings) {
|
|
114
115
|
summary.savingsByCurrency.set(line.savings.currency, (summary.savingsByCurrency.get(line.savings.currency) ?? 0) +
|
|
115
116
|
line.savings.amount);
|
|
116
117
|
}
|
|
117
118
|
}
|
|
119
|
+
// Per-resource cost: counted ONCE per resource (not per finding) so
|
|
120
|
+
// that a resource with N findings doesn't inflate the total by Nx.
|
|
121
|
+
const costAtRisk = entry.analysis.estimatedMonthlySavings;
|
|
122
|
+
if (costAtRisk) {
|
|
123
|
+
summary.costAtRiskByCurrency.set(costAtRisk.currency, (summary.costAtRiskByCurrency.get(costAtRisk.currency) ?? 0) +
|
|
124
|
+
costAtRisk.amount);
|
|
125
|
+
}
|
|
118
126
|
}
|
|
119
127
|
return summary;
|
|
120
128
|
}
|
|
@@ -137,45 +145,72 @@ function formatAmount(amount, currency) {
|
|
|
137
145
|
}
|
|
138
146
|
}
|
|
139
147
|
/**
|
|
140
|
-
* Renders an
|
|
141
|
-
* label that ships next to each lint line.
|
|
142
|
-
* the
|
|
148
|
+
* Renders an Advisor per-finding monthly saving as the short
|
|
149
|
+
* "(saving: € 12.50/mo)" label that ships next to each lint line.
|
|
150
|
+
* Returns an empty string when the finding doesn't carry an estimate.
|
|
151
|
+
*
|
|
152
|
+
* Only Advisor populates this today: Microsoft attaches an authoritative
|
|
153
|
+
* per-recommendation saving to each recommendation, so it aggregates
|
|
154
|
+
* cleanly. Custom analyzers do NOT propagate the resource's monthly
|
|
155
|
+
* bill down to each finding — see the per-resource "cost at risk"
|
|
156
|
+
* header rendered by `generateLintReport` instead.
|
|
143
157
|
*/
|
|
144
|
-
function
|
|
158
|
+
function formatPerFindingSavings(savings) {
|
|
145
159
|
if (!savings)
|
|
146
160
|
return "";
|
|
147
|
-
return `(${formatAmount(savings.amount, savings.currency)}/mo)`;
|
|
161
|
+
return `(saving: ${formatAmount(savings.amount, savings.currency)}/mo)`;
|
|
148
162
|
}
|
|
149
163
|
/**
|
|
150
164
|
* Renders a linter-style report to stdout, grouping findings by resource.
|
|
151
165
|
*
|
|
152
166
|
* When `Finding[]` is attached to a report (Phase 1+), each finding is
|
|
153
|
-
* rendered with its `source` badge (e.g. `[advisor]`) and
|
|
154
|
-
* monthly
|
|
155
|
-
* fall back to splitting `analysis.reason`
|
|
156
|
-
* backward compatible.
|
|
167
|
+
* rendered with its `source` badge (e.g. `[advisor]`) and its own
|
|
168
|
+
* estimated monthly saving (when populated by Advisor). For older
|
|
169
|
+
* payloads without `findings` we fall back to splitting `analysis.reason`
|
|
170
|
+
* like before so the format stays backward compatible.
|
|
171
|
+
*
|
|
172
|
+
* When a custom analyzer populated `analysis.estimatedMonthlySavings`,
|
|
173
|
+
* the value is printed ONCE per resource as a header annotation labelled
|
|
174
|
+
* "cost at risk" — it represents the monthly bill of the resource (an
|
|
175
|
+
* upper bound on what could be recovered by removing it), NOT the saving
|
|
176
|
+
* of any individual finding sentence.
|
|
157
177
|
*
|
|
158
178
|
* Example output:
|
|
159
179
|
*
|
|
160
|
-
* /subscriptions/.../virtualMachines/my-vm
|
|
161
|
-
* ✖ HIGH [advisor] Right-size your VM. (€ 12.50/mo)
|
|
180
|
+
* /subscriptions/.../virtualMachines/my-vm (cost at risk: € 29.94/mo)
|
|
162
181
|
* ✖ HIGH [custom] No tags found.
|
|
182
|
+
* ✖ HIGH [custom] VM is deallocated.
|
|
183
|
+
*
|
|
184
|
+
* /subscriptions/.../virtualMachines/other-vm
|
|
185
|
+
* ✖ HIGH [advisor] Right-size your VM. (saving: € 12.50/mo)
|
|
163
186
|
*
|
|
164
187
|
* Summary: 3 issues found (2 high, 0 medium, 1 low)
|
|
165
|
-
* Estimated monthly
|
|
188
|
+
* Estimated monthly cost at risk (custom): € 29.94
|
|
189
|
+
* Estimated monthly savings (advisor): € 12.50
|
|
166
190
|
*/
|
|
167
191
|
function generateLintReport(report) {
|
|
168
192
|
const summary = {
|
|
193
|
+
costAtRiskByCurrency: new Map(),
|
|
169
194
|
counts: { high: 0, low: 0, medium: 0 },
|
|
170
195
|
savingsByCurrency: new Map(),
|
|
171
196
|
sourceCounts: {},
|
|
172
197
|
};
|
|
173
198
|
for (const entry of report) {
|
|
174
199
|
const resourceId = entry.resource.id ?? `unknown/${entry.resource.name ?? "unknown"}`;
|
|
175
|
-
|
|
200
|
+
const costAtRisk = entry.analysis.estimatedMonthlySavings;
|
|
201
|
+
const header = costAtRisk
|
|
202
|
+
? `${BOLD}${resourceId}${RESET} ${GREEN}(cost at risk: ${formatAmount(costAtRisk.amount, costAtRisk.currency)}/mo)${RESET}`
|
|
203
|
+
: `${BOLD}${resourceId}${RESET}`;
|
|
204
|
+
console.log(header);
|
|
205
|
+
if (costAtRisk) {
|
|
206
|
+
summary.costAtRiskByCurrency.set(costAtRisk.currency, (summary.costAtRiskByCurrency.get(costAtRisk.currency) ?? 0) +
|
|
207
|
+
costAtRisk.amount);
|
|
208
|
+
}
|
|
176
209
|
const lines = entry.findings?.length
|
|
177
210
|
? entry.findings.map((f) => ({
|
|
178
|
-
extra:
|
|
211
|
+
extra: f.source === "advisor"
|
|
212
|
+
? formatPerFindingSavings(f.estimatedMonthlySavings)
|
|
213
|
+
: "",
|
|
179
214
|
severity: f.severity,
|
|
180
215
|
source: f.source,
|
|
181
216
|
text: f.reason,
|
|
@@ -199,7 +234,7 @@ function generateLintReport(report) {
|
|
|
199
234
|
}
|
|
200
235
|
if (entry.findings) {
|
|
201
236
|
for (const f of entry.findings) {
|
|
202
|
-
if (f.estimatedMonthlySavings) {
|
|
237
|
+
if (f.source === "advisor" && f.estimatedMonthlySavings) {
|
|
203
238
|
const { amount, currency } = f.estimatedMonthlySavings;
|
|
204
239
|
summary.savingsByCurrency.set(currency, (summary.savingsByCurrency.get(currency) ?? 0) + amount);
|
|
205
240
|
}
|
|
@@ -221,7 +256,7 @@ function generateLintReport(report) {
|
|
|
221
256
|
* out of scope for this tool.
|
|
222
257
|
*/
|
|
223
258
|
function printSummary(summary) {
|
|
224
|
-
const { counts, savingsByCurrency, sourceCounts } = summary;
|
|
259
|
+
const { costAtRiskByCurrency, counts, savingsByCurrency, sourceCounts } = summary;
|
|
225
260
|
const total = counts.high + counts.medium + counts.low;
|
|
226
261
|
const summaryLine = `${BOLD}Summary:${RESET} ${total} issue${total !== 1 ? "s" : ""} found` +
|
|
227
262
|
` ${RED}(${counts.high} high${RESET}` +
|
|
@@ -235,9 +270,13 @@ function printSummary(summary) {
|
|
|
235
270
|
if (sourceBreakdown) {
|
|
236
271
|
console.log(`${BOLD}Sources:${RESET} ${sourceBreakdown}`);
|
|
237
272
|
}
|
|
273
|
+
if (costAtRiskByCurrency.size > 0) {
|
|
274
|
+
const parts = [...costAtRiskByCurrency.entries()].map(([currency, amount]) => `${GREEN}${formatAmount(amount, currency)}${RESET}`);
|
|
275
|
+
console.log(`${BOLD}Estimated monthly cost at risk (custom):${RESET} ${parts.join(", ")}`);
|
|
276
|
+
}
|
|
238
277
|
if (savingsByCurrency.size > 0) {
|
|
239
278
|
const parts = [...savingsByCurrency.entries()].map(([currency, amount]) => `${GREEN}${formatAmount(amount, currency)}${RESET}`);
|
|
240
|
-
console.log(`${BOLD}Estimated monthly savings:${RESET} ${parts.join(", ")}`);
|
|
279
|
+
console.log(`${BOLD}Estimated monthly savings (advisor):${RESET} ${parts.join(", ")}`);
|
|
241
280
|
}
|
|
242
281
|
}
|
|
243
282
|
/**
|
package/dist/azure/report.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/azure/report.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,MAAM,YAAY,CAAC;AAQ/B,wEAAwE;AACxE,6EAA6E;AAC7E,MAAM,UAAU,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAU,CAAC;AAEhD,6FAA6F;AAC7F,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,KAAK,CAAC;AAC5C,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;AACpC,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;AACvC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;AACrC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;AACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;AACrC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;AACpC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;AACrC,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;AAEnC,MAAM,SAAS,GAAG;IAChB,IAAI,EAAE,GAAG,GAAG,IAAI,KAAK,EAAE;IACvB,GAAG,EAAE,GAAG,IAAI,IAAI,KAAK,EAAE;IACvB,MAAM,EAAE,GAAG,MAAM,IAAI,KAAK,EAAE;CACpB,CAAC;AAEX,MAAM,UAAU,GAAG;IACjB,IAAI,EAAE,GAAG;IACT,GAAG,EAAE,IAAI;IACT,MAAM,EAAE,MAAM;CACN,CAAC;
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/azure/report.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,MAAM,YAAY,CAAC;AAQ/B,wEAAwE;AACxE,6EAA6E;AAC7E,MAAM,UAAU,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAU,CAAC;AAEhD,6FAA6F;AAC7F,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,KAAK,CAAC;AAC5C,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;AACpC,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;AACvC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;AACrC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;AACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;AACrC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;AACpC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;AACrC,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;AAEnC,MAAM,SAAS,GAAG;IAChB,IAAI,EAAE,GAAG,GAAG,IAAI,KAAK,EAAE;IACvB,GAAG,EAAE,GAAG,IAAI,IAAI,KAAK,EAAE;IACvB,MAAM,EAAE,GAAG,MAAM,IAAI,KAAK,EAAE;CACpB,CAAC;AAEX,MAAM,UAAU,GAAG;IACjB,IAAI,EAAE,GAAG;IACT,GAAG,EAAE,IAAI;IACT,MAAM,EAAE,MAAM;CACN,CAAC;AAoBX;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAqC,EACrC,MAAmD;IAEnD,IAAI,MAAM,KAAK,eAAe,EAAE,CAAC;QAC/B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7C,OAAO;IACT,CAAC;IAED,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,MAAM,aAAa,GAA0B,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC9D,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ;YAC7B,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,IAAI,EAAE;YACnC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,IAAI,SAAS;YAClC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,MAAM;YACzB,aAAa,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC3C,cAAc,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,SAAS;YACzD,eAAe,EAAE,CAAC,CAAC,QAAQ,CAAC,eAAe;YAC3C,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,IAAI,SAAS;SACnC,CAAC,CAAC,CAAC;QACJ,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACtD,CAAC;SAAM,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QAC7B,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;SAAM,CAAC;QACN,MAAM,aAAa,GAA0B,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC9D,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ;YAC7B,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,IAAI,EAAE;YACnC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,IAAI,SAAS;YAClC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,MAAM;YACzB,aAAa,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC3C,cAAc,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,SAAS;YACzD,eAAe,EAAE,CAAC,CAAC,QAAQ,CAAC,eAAe;YAC3C,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,IAAI,SAAS;SACnC,CAAC,CAAC,CAAC;QACJ,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC;YACtB,SAAS,EAAE,CAAC,GAAG,UAAU,CAAC;YAC1B,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,QAAQ,CAAC;YAC1D,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;QACH,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC;gBACT,CAAC,CAAC,IAAI;gBACN,CAAC,CAAC,IAAI;gBACN,CAAC,CAAC,aAAa,IAAI,KAAK;gBACxB,CAAC,CAAC,QAAQ;gBACV,CAAC,CAAC,MAAM;aACT,CAAC,CAAC;QACL,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC9B,oEAAoE;QACpE,uEAAuE;QACvE,YAAY,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;IACvC,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,cAAc,CAAC,MAAqC;IAC3D,MAAM,OAAO,GAAY;QACvB,oBAAoB,EAAE,IAAI,GAAG,EAAE;QAC/B,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;QACtC,iBAAiB,EAAE,IAAI,GAAG,EAAE;QAC5B,YAAY,EAAE,EAAE;KACjB,CAAC;IACF,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,EAAE,MAAM;YAClC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACzB,OAAO,EAAE,CAAC,CAAC,uBAAuB;gBAClC,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,MAAM,EAAE,CAAC,CAAC,MAAM;aACjB,CAAC,CAAC;YACL,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;gBAC7C,OAAO,EAAE,SAAS;gBAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,QAAQ;gBACjC,MAAM,EAAE,QAAiB;aAC1B,CAAC,CAAC,CAAC;QACR,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAChC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC;gBAC/B,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YAC/C,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBAC9C,OAAO,CAAC,iBAAiB,CAAC,GAAG,CAC3B,IAAI,CAAC,OAAO,CAAC,QAAQ,EACrB,CAAC,OAAO,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;oBACzD,IAAI,CAAC,OAAO,CAAC,MAAM,CACtB,CAAC;YACJ,CAAC;QACH,CAAC;QACD,oEAAoE;QACpE,mEAAmE;QACnE,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ,CAAC,uBAAuB,CAAC;QAC1D,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,CAAC,oBAAoB,CAAC,GAAG,CAC9B,UAAU,CAAC,QAAQ,EACnB,CAAC,OAAO,CAAC,oBAAoB,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;gBAC1D,UAAU,CAAC,MAAM,CACpB,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,SAAS,YAAY,CAAC,MAAc,EAAE,QAAgB;IACpD,IAAI,CAAC;QACH,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE;YACpC,QAAQ;YACR,qBAAqB,EAAE,CAAC;YACxB,qBAAqB,EAAE,CAAC;YACxB,KAAK,EAAE,UAAU;SAClB,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACpB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,QAAQ,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5C,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,uBAAuB,CAAC,OAAe;IAC9C,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IACxB,OAAO,YAAY,YAAY,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;AAC1E,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,SAAS,kBAAkB,CAAC,MAAqC;IAC/D,MAAM,OAAO,GAAY;QACvB,oBAAoB,EAAE,IAAI,GAAG,EAAE;QAC/B,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;QACtC,iBAAiB,EAAE,IAAI,GAAG,EAAE;QAC5B,YAAY,EAAE,EAAE;KACjB,CAAC;IAEF,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,UAAU,GACd,KAAK,CAAC,QAAQ,CAAC,EAAE,IAAI,WAAW,KAAK,CAAC,QAAQ,CAAC,IAAI,IAAI,SAAS,EAAE,CAAC;QACrE,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ,CAAC,uBAAuB,CAAC;QAC1D,MAAM,MAAM,GAAG,UAAU;YACvB,CAAC,CAAC,GAAG,IAAI,GAAG,UAAU,GAAG,KAAK,KAAK,KAAK,kBAAkB,YAAY,CAAC,UAAU,CAAC,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,OAAO,KAAK,EAAE;YAC5H,CAAC,CAAC,GAAG,IAAI,GAAG,UAAU,GAAG,KAAK,EAAE,CAAC;QACnC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpB,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,CAAC,oBAAoB,CAAC,GAAG,CAC9B,UAAU,CAAC,QAAQ,EACnB,CAAC,OAAO,CAAC,oBAAoB,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;gBAC1D,UAAU,CAAC,MAAM,CACpB,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,EAAE,MAAM;YAClC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACzB,KAAK,EACH,CAAC,CAAC,MAAM,KAAK,SAAS;oBACpB,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,uBAAuB,CAAC;oBACpD,CAAC,CAAC,EAAE;gBACR,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,MAAM,EAAE,CAAC,CAAC,MAAM;gBAChB,IAAI,EAAE,CAAC,CAAC,MAAM;aACf,CAAC,CAAC;YACL,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBACjD,KAAK,EAAE,EAAE;gBACT,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,QAAQ;gBACjC,MAAM,EAAE,QAAiB;gBACzB,IAAI;aACL,CAAC,CAAC,CAAC;QAER,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACtC,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACxC,MAAM,KAAK,GAAG,GAAG,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC;YACzE,MAAM,WAAW,GAAG,GAAG,IAAI,IAAI,IAAI,CAAC,MAAM,IAAI,KAAK,EAAE,CAAC;YACtD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjE,OAAO,CAAC,GAAG,CACT,KAAK,IAAI,IAAI,KAAK,KAAK,WAAW,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI,GAAG,KAAK,GAAG,KAAK,EAAE,CACxE,CAAC;YACF,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAChC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC;gBAC/B,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACjD,CAAC;QAED,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACnB,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBAC/B,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,uBAAuB,EAAE,CAAC;oBACxD,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC,uBAAuB,CAAC;oBACvD,OAAO,CAAC,iBAAiB,CAAC,GAAG,CAC3B,QAAQ,EACR,CAAC,OAAO,CAAC,iBAAiB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,MAAM,CACxD,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,CAAC,GAAG,EAAE,CAAC;IAChB,CAAC;IAED,YAAY,CAAC,OAAO,CAAC,CAAC;AACxB,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,YAAY,CAAC,OAAgB;IACpC,MAAM,EAAE,oBAAoB,EAAE,MAAM,EAAE,iBAAiB,EAAE,YAAY,EAAE,GACrE,OAAO,CAAC;IACV,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC;IACvD,MAAM,WAAW,GACf,GAAG,IAAI,WAAW,KAAK,IAAI,KAAK,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,QAAQ;QACvE,KAAK,GAAG,IAAI,MAAM,CAAC,IAAI,QAAQ,KAAK,EAAE;QACtC,KAAK,MAAM,GAAG,MAAM,CAAC,MAAM,UAAU,KAAK,EAAE;QAC5C,KAAK,IAAI,GAAG,MAAM,CAAC,GAAG,OAAO,KAAK,GAAG,CAAC;IACxC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAEzB,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC;SACjD,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;SACtC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,MAAM,EAAE,CAAC;SACtC,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,WAAW,KAAK,IAAI,eAAe,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,IAAI,oBAAoB,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,CAAC,GAAG,oBAAoB,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CACnD,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CACrB,GAAG,KAAK,GAAG,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,KAAK,EAAE,CACtD,CAAC;QACF,OAAO,CAAC,GAAG,CACT,GAAG,IAAI,2CAA2C,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC9E,CAAC;IACJ,CAAC;IAED,IAAI,iBAAiB,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,CAAC,GAAG,iBAAiB,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAChD,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CACrB,GAAG,KAAK,GAAG,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,KAAK,EAAE,CACtD,CAAC;QACF,OAAO,CAAC,GAAG,CACT,GAAG,IAAI,uCAAuC,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC1E,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,YAAY,CAAC,MAAc;IAClC,OAAO,MAAM;SACV,KAAK,CAAC,OAAO,CAAC;SACd,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;SAC3B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-service.test.d.ts","sourceRoot":"","sources":["../../../../src/azure/resources/__tests__/app-service.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|