@spottoai/types-package 1.0.2-beta.427 → 1.0.2-beta.429
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/dist/azure/dataProtection.d.ts +40 -0
- package/dist/azure/dataProtection.d.ts.map +1 -1
- package/dist/azure/metrics.d.ts +2 -27
- package/dist/azure/metrics.d.ts.map +1 -1
- package/dist/azure/payloads.d.ts +7 -7
- package/dist/azure/payloads.d.ts.map +1 -1
- package/dist/azure/payloads.js +22 -23
- package/dist/azure/payloads.js.map +1 -1
- package/dist/azure/reportEvidence.d.ts +7 -5
- package/dist/azure/reportEvidence.d.ts.map +1 -1
- package/dist/azure/reportEvidence.js.map +1 -1
- package/dist/azure/reportEvidenceValidation.d.ts.map +1 -1
- package/dist/azure/reportEvidenceValidation.js +5 -1
- package/dist/azure/reportEvidenceValidation.js.map +1 -1
- package/dist/azure/reportEvidenceValidationHelpers.d.ts +3 -16
- package/dist/azure/reportEvidenceValidationHelpers.d.ts.map +1 -1
- package/dist/azure/reportEvidenceValidationHelpers.js +79 -95
- package/dist/azure/reportEvidenceValidationHelpers.js.map +1 -1
- package/dist/azure/resilienceFacts.d.ts +100 -0
- package/dist/azure/resilienceFacts.d.ts.map +1 -0
- package/dist/azure/resilienceFacts.js +20 -0
- package/dist/azure/resilienceFacts.js.map +1 -0
- package/dist/azure/resilienceFactsValidation.d.ts +4 -0
- package/dist/azure/resilienceFactsValidation.d.ts.map +1 -0
- package/dist/azure/resilienceFactsValidation.js +70 -0
- package/dist/azure/resilienceFactsValidation.js.map +1 -0
- package/dist/azure/views.d.ts +7 -0
- package/dist/azure/views.d.ts.map +1 -1
- package/dist/azure/views.js.map +1 -1
- package/dist/common/boundedRows.d.ts +7 -0
- package/dist/common/boundedRows.d.ts.map +1 -0
- package/dist/{scheduler/scheduler.js → common/boundedRows.js} +1 -1
- package/dist/common/boundedRows.js.map +1 -0
- package/dist/common/metricStats.d.ts +29 -0
- package/dist/common/metricStats.d.ts.map +1 -0
- package/dist/{scheduler/bastionSchedule.js → common/metricStats.js} +1 -1
- package/dist/common/metricStats.js.map +1 -0
- package/dist/common/utilizationStories.d.ts +516 -0
- package/dist/common/utilizationStories.d.ts.map +1 -0
- package/dist/common/utilizationStories.js +21 -0
- package/dist/common/utilizationStories.js.map +1 -0
- package/dist/common/utilizationStoriesValidation.d.ts +48 -0
- package/dist/common/utilizationStoriesValidation.d.ts.map +1 -0
- package/dist/common/utilizationStoriesValidation.js +552 -0
- package/dist/common/utilizationStoriesValidation.js.map +1 -0
- package/dist/common/validationHelpers.d.ts +18 -0
- package/dist/common/validationHelpers.d.ts.map +1 -0
- package/dist/common/validationHelpers.js +36 -0
- package/dist/common/validationHelpers.js.map +1 -0
- package/dist/esm/azure/payloads.js +19 -20
- package/dist/esm/azure/reportEvidenceValidation.js +5 -1
- package/dist/esm/azure/reportEvidenceValidationHelpers.js +2 -18
- package/dist/esm/azure/resilienceFacts.js +16 -0
- package/dist/esm/azure/resilienceFactsValidation.js +64 -0
- package/dist/esm/common/utilizationStories.js +17 -0
- package/dist/esm/common/utilizationStoriesValidation.js +514 -0
- package/dist/esm/common/validationHelpers.js +18 -0
- package/dist/esm/index.js +4 -3
- package/dist/esm/scheduler/index.js +2 -1
- package/dist/esm/scheduler/resourceStrategyCapabilityValidation.js +4 -20
- package/dist/esm/scheduler/resourceStrategyContracts.js +4 -2
- package/dist/esm/scheduler/resourceStrategyScheduleValidation.js +109 -4
- package/dist/esm/scheduler/schedulerContracts.js +1 -0
- package/dist/esm/scheduler/schedulerValidation.js +363 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/scheduler/index.d.ts +2 -1
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +2 -1
- package/dist/scheduler/index.js.map +1 -1
- package/dist/scheduler/resourceStrategyCapabilityValidation.d.ts.map +1 -1
- package/dist/scheduler/resourceStrategyCapabilityValidation.js +4 -20
- package/dist/scheduler/resourceStrategyCapabilityValidation.js.map +1 -1
- package/dist/scheduler/resourceStrategyContracts.d.ts +26 -9
- package/dist/scheduler/resourceStrategyContracts.d.ts.map +1 -1
- package/dist/scheduler/resourceStrategyContracts.js +4 -2
- package/dist/scheduler/resourceStrategyContracts.js.map +1 -1
- package/dist/scheduler/resourceStrategyScheduleValidation.d.ts +3 -1
- package/dist/scheduler/resourceStrategyScheduleValidation.d.ts.map +1 -1
- package/dist/scheduler/resourceStrategyScheduleValidation.js +110 -4
- package/dist/scheduler/resourceStrategyScheduleValidation.js.map +1 -1
- package/dist/scheduler/schedulerContracts.d.ts +178 -0
- package/dist/scheduler/schedulerContracts.d.ts.map +1 -0
- package/dist/scheduler/schedulerContracts.js +3 -0
- package/dist/scheduler/schedulerContracts.js.map +1 -0
- package/dist/scheduler/schedulerValidation.d.ts +14 -0
- package/dist/scheduler/schedulerValidation.d.ts.map +1 -0
- package/dist/scheduler/schedulerValidation.js +378 -0
- package/dist/scheduler/schedulerValidation.js.map +1 -0
- package/package.json +5 -3
- package/dist/esm/scheduler/bastionScheduleProfile.js +0 -206
- package/dist/esm/scheduler/bastionScheduleValidation.js +0 -399
- package/dist/scheduler/bastionSchedule.d.ts +0 -113
- package/dist/scheduler/bastionSchedule.d.ts.map +0 -1
- package/dist/scheduler/bastionSchedule.js.map +0 -1
- package/dist/scheduler/bastionScheduleProfile.d.ts +0 -24
- package/dist/scheduler/bastionScheduleProfile.d.ts.map +0 -1
- package/dist/scheduler/bastionScheduleProfile.js +0 -210
- package/dist/scheduler/bastionScheduleProfile.js.map +0 -1
- package/dist/scheduler/bastionScheduleValidation.d.ts +0 -10
- package/dist/scheduler/bastionScheduleValidation.d.ts.map +0 -1
- package/dist/scheduler/bastionScheduleValidation.js +0 -410
- package/dist/scheduler/bastionScheduleValidation.js.map +0 -1
- package/dist/scheduler/scheduler.d.ts +0 -267
- package/dist/scheduler/scheduler.d.ts.map +0 -1
- package/dist/scheduler/scheduler.js.map +0 -1
- /package/dist/esm/{scheduler/bastionSchedule.js → common/boundedRows.js} +0 -0
- /package/dist/esm/{scheduler/scheduler.js → common/metricStats.js} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validationHelpers.d.ts","sourceRoot":"","sources":["../../src/common/validationHelpers.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEvD,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEjD,eAAO,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,UAAkF,CAAC;AACtI,eAAO,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAA8D,CAAC;AAClH,eAAO,MAAM,gBAAgB,GAAI,OAAO,OAAO,KAAG,OAAiD,CAAC;AACpG,eAAO,MAAM,cAAc,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAA6D,CAAC;AACvH,eAAO,MAAM,sBAAsB,GAAI,OAAO,OAAO,KAAG,OAAuD,CAAC;AAChH,eAAO,MAAM,iBAAiB,GAAI,OAAO,OAAO,KAAG,OAA4D,CAAC;AAChH,eAAO,MAAM,OAAO,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAAwE,CAAC;AAC3H,eAAO,MAAM,UAAU,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAA+D,CAAC;AACrH,eAAO,MAAM,aAAa,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAAM,EAAmD,CAAC;AAClH,eAAO,MAAM,aAAa,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAA2D,CAAC;AACzI,eAAO,MAAM,UAAU,GAAI,OAAO,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAG,MAAyE,CAAC;AACrI,eAAO,MAAM,kBAAkB,GAAI,OAAO,UAAU,EAAE,MAAM,SAAS,MAAM,EAAE,KAAG,OAA0D,CAAC;AAC3I,eAAO,MAAM,kBAAkB,GAAI,OAAO,UAAU,EAAE,MAAM,SAAS,MAAM,EAAE,KAAG,OAAgE,CAAC;AAEjJ,eAAO,MAAM,aAAa,GAAI,CAAC,EAAE,OAAO,OAAO,EAAE,OAAO,MAAM,EAAE,OAAO,CAAC,GAAG,EAAE,OAAO,KAAK,GAAG,IAAI,CAAC,KAAG,KAAK,IAAI,iBAAiB,CAAC,CAAC,CAG/H,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isBoundedRows = exports.hasOptionalNumbers = exports.hasOptionalStrings = exports.countTotal = exports.isCountRecord = exports.isStringArray = exports.isDateTime = exports.isCount = exports.isOptionalBoolean = exports.isOptionalFiniteNumber = exports.isFiniteNumber = exports.isOptionalString = exports.isString = exports.isRecord = void 0;
|
|
4
|
+
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
5
|
+
exports.isRecord = isRecord;
|
|
6
|
+
const isString = (value) => typeof value === 'string' && value.trim().length > 0;
|
|
7
|
+
exports.isString = isString;
|
|
8
|
+
const isOptionalString = (value) => value === undefined || (0, exports.isString)(value);
|
|
9
|
+
exports.isOptionalString = isOptionalString;
|
|
10
|
+
const isFiniteNumber = (value) => typeof value === 'number' && Number.isFinite(value);
|
|
11
|
+
exports.isFiniteNumber = isFiniteNumber;
|
|
12
|
+
const isOptionalFiniteNumber = (value) => value === undefined || (0, exports.isFiniteNumber)(value);
|
|
13
|
+
exports.isOptionalFiniteNumber = isOptionalFiniteNumber;
|
|
14
|
+
const isOptionalBoolean = (value) => value === undefined || typeof value === 'boolean';
|
|
15
|
+
exports.isOptionalBoolean = isOptionalBoolean;
|
|
16
|
+
const isCount = (value) => (0, exports.isFiniteNumber)(value) && Number.isInteger(value) && value >= 0;
|
|
17
|
+
exports.isCount = isCount;
|
|
18
|
+
const isDateTime = (value) => (0, exports.isString)(value) && Number.isFinite(Date.parse(value));
|
|
19
|
+
exports.isDateTime = isDateTime;
|
|
20
|
+
const isStringArray = (value) => Array.isArray(value) && value.every(exports.isString);
|
|
21
|
+
exports.isStringArray = isStringArray;
|
|
22
|
+
const isCountRecord = (value) => (0, exports.isRecord)(value) && Object.values(value).every(exports.isCount);
|
|
23
|
+
exports.isCountRecord = isCountRecord;
|
|
24
|
+
const countTotal = (value) => Object.values(value).reduce((total, count) => total + count, 0);
|
|
25
|
+
exports.countTotal = countTotal;
|
|
26
|
+
const hasOptionalStrings = (value, keys) => keys.every(key => (0, exports.isOptionalString)(value[key]));
|
|
27
|
+
exports.hasOptionalStrings = hasOptionalStrings;
|
|
28
|
+
const hasOptionalNumbers = (value, keys) => keys.every(key => (0, exports.isOptionalFiniteNumber)(value[key]));
|
|
29
|
+
exports.hasOptionalNumbers = hasOptionalNumbers;
|
|
30
|
+
const isBoundedRows = (value, limit, isRow) => {
|
|
31
|
+
if (!(0, exports.isRecord)(value) || !(0, exports.isCount)(value.totalCount) || !(0, exports.isCount)(value.omittedCount) || !Array.isArray(value.rows))
|
|
32
|
+
return false;
|
|
33
|
+
return value.rows.length <= limit && value.rows.every(isRow) && value.totalCount === value.rows.length + value.omittedCount;
|
|
34
|
+
};
|
|
35
|
+
exports.isBoundedRows = isBoundedRows;
|
|
36
|
+
//# sourceMappingURL=validationHelpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validationHelpers.js","sourceRoot":"","sources":["../../src/common/validationHelpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const
|
|
2
|
-
const
|
|
3
|
-
const
|
|
1
|
+
const SCHEDULER_TICK_PREFIX_V1 = 'scheduler:tick:';
|
|
2
|
+
const SCHEDULER_TICK_MAX_ID_LENGTH_V1 = 128;
|
|
3
|
+
const SCHEDULER_TICK_KEYS_V1 = [
|
|
4
4
|
'schemaVersion',
|
|
5
5
|
'entity',
|
|
6
6
|
'action',
|
|
@@ -19,34 +19,33 @@ const isCanonicalUtcTimestampMilliseconds = (value) => {
|
|
|
19
19
|
const parsed = Date.parse(value);
|
|
20
20
|
return Number.isFinite(parsed) && new Date(parsed).toISOString() === value;
|
|
21
21
|
};
|
|
22
|
-
const
|
|
22
|
+
const hasExactSchedulerTickKeysV1 = (value) => {
|
|
23
23
|
const keys = Object.keys(value);
|
|
24
|
-
return
|
|
25
|
-
RESOURCE_SCHEDULER_TICK_KEYS_V1.every(key => Object.prototype.hasOwnProperty.call(value, key)));
|
|
24
|
+
return keys.length === SCHEDULER_TICK_KEYS_V1.length && SCHEDULER_TICK_KEYS_V1.every(key => Object.prototype.hasOwnProperty.call(value, key));
|
|
26
25
|
};
|
|
27
|
-
const
|
|
26
|
+
const normalizeSchedulerTickInstantV1 = (scheduledAt) => {
|
|
28
27
|
if (typeof scheduledAt === 'string') {
|
|
29
28
|
if (!isCanonicalUtcTimestampMilliseconds(scheduledAt)) {
|
|
30
|
-
throw new TypeError('
|
|
29
|
+
throw new TypeError('Scheduler tick time must be a canonical UTC timestamp with milliseconds');
|
|
31
30
|
}
|
|
32
31
|
return scheduledAt;
|
|
33
32
|
}
|
|
34
33
|
const milliseconds = scheduledAt instanceof Date ? scheduledAt.getTime() : scheduledAt;
|
|
35
34
|
if (!Number.isFinite(milliseconds))
|
|
36
|
-
throw new TypeError('
|
|
35
|
+
throw new TypeError('Scheduler tick time must be finite');
|
|
37
36
|
const normalized = new Date(milliseconds).toISOString();
|
|
38
37
|
if (!isCanonicalUtcTimestampMilliseconds(normalized)) {
|
|
39
|
-
throw new TypeError('
|
|
38
|
+
throw new TypeError('Scheduler tick time must use a four-digit UTC year');
|
|
40
39
|
}
|
|
41
40
|
return normalized;
|
|
42
41
|
};
|
|
43
42
|
/** Creates the deterministic internal queue envelope for one cron occurrence. */
|
|
44
|
-
export const
|
|
45
|
-
const scheduledAtUtc =
|
|
46
|
-
const tickId = `${
|
|
43
|
+
export const createSchedulerTickRequestMessageV1 = (scheduledAt) => {
|
|
44
|
+
const scheduledAtUtc = normalizeSchedulerTickInstantV1(scheduledAt);
|
|
45
|
+
const tickId = `${SCHEDULER_TICK_PREFIX_V1}${scheduledAtUtc}`;
|
|
47
46
|
return {
|
|
48
47
|
schemaVersion: 1,
|
|
49
|
-
entity: '
|
|
48
|
+
entity: 'scheduler',
|
|
50
49
|
action: 'tick',
|
|
51
50
|
companyId: '*',
|
|
52
51
|
cloudAccountId: '*',
|
|
@@ -57,25 +56,25 @@ export const createResourceSchedulerTickRequestMessageV1 = (scheduledAt) => {
|
|
|
57
56
|
correlationId: tickId,
|
|
58
57
|
};
|
|
59
58
|
};
|
|
60
|
-
/** Exact validator for the internal
|
|
61
|
-
export const
|
|
59
|
+
/** Exact validator for the internal scheduler tick queue boundary. */
|
|
60
|
+
export const isSchedulerTickRequestMessageV1 = (value) => {
|
|
62
61
|
try {
|
|
63
62
|
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
64
63
|
return false;
|
|
65
64
|
const candidate = value;
|
|
66
|
-
if (!
|
|
65
|
+
if (!hasExactSchedulerTickKeysV1(candidate) || !isCanonicalUtcTimestampMilliseconds(candidate['scheduledAtUtc'])) {
|
|
67
66
|
return false;
|
|
68
67
|
}
|
|
69
|
-
const expectedTickId = `${
|
|
68
|
+
const expectedTickId = `${SCHEDULER_TICK_PREFIX_V1}${candidate['scheduledAtUtc']}`;
|
|
70
69
|
return (candidate['schemaVersion'] === 1 &&
|
|
71
|
-
candidate['entity'] === '
|
|
70
|
+
candidate['entity'] === 'scheduler' &&
|
|
72
71
|
candidate['action'] === 'tick' &&
|
|
73
72
|
candidate['companyId'] === '*' &&
|
|
74
73
|
candidate['cloudAccountId'] === '*' &&
|
|
75
74
|
candidate['tenantId'] === '*' &&
|
|
76
75
|
candidate['clientId'] === '*' &&
|
|
77
76
|
typeof candidate['tickId'] === 'string' &&
|
|
78
|
-
candidate['tickId'].length <=
|
|
77
|
+
candidate['tickId'].length <= SCHEDULER_TICK_MAX_ID_LENGTH_V1 &&
|
|
79
78
|
candidate['tickId'] === expectedTickId &&
|
|
80
79
|
candidate['correlationId'] === expectedTickId);
|
|
81
80
|
}
|
|
@@ -3,6 +3,7 @@ import { isReportDailySpend } from './reportDailySpendValidation.js';
|
|
|
3
3
|
import { isReportSavingsBasis, isReportSpendProjection } from './reportSpendValidation.js';
|
|
4
4
|
import { REPORT_EVIDENCE_LIMITS, } from './reportEvidence.js';
|
|
5
5
|
import { countTotal, hasOptionalNumbers, hasOptionalStrings, hasRequiredRecords, isBoundedRows, isCommitmentExpirySummary, isCostSummary, isCount, isCountRecord, isDateTime, isEvidenceReference, isFiniteNumber, isOptionalBoolean, isOptionalFiniteNumber, isOptionalString, isProjectionRows, isRecommendationSummary, isRecord, isResourceSummary, isRetirementSummary, isSourceFileStatus, isString, isStringArray, isTagCoverage, } from './reportEvidenceValidationHelpers.js';
|
|
6
|
+
import { isReportingStories, isStoryFingerprintRows } from '../common/utilizationStoriesValidation.js';
|
|
6
7
|
export const isReportSecureScoreEvidence = (value) => {
|
|
7
8
|
if (!isRecord(value) || !['available', 'unavailable', 'stale'].includes(value.status))
|
|
8
9
|
return false;
|
|
@@ -260,6 +261,8 @@ const isReportingProjection = (value) => {
|
|
|
260
261
|
return false;
|
|
261
262
|
if (value.spend !== undefined && !isReportSpendProjection(value.spend))
|
|
262
263
|
return false;
|
|
264
|
+
if (value.stories !== undefined && !isReportingStories(value.stories))
|
|
265
|
+
return false;
|
|
263
266
|
if (value.costChangePeriods !== undefined &&
|
|
264
267
|
(!isBoundedRows(value.costChangePeriods, REPORT_EVIDENCE_LIMITS.costChangePeriods, isCostChangePeriod) ||
|
|
265
268
|
new Set(value.costChangePeriods.rows.map(period => period.period)).size !== value.costChangePeriods.rows.length)) {
|
|
@@ -448,7 +451,8 @@ export const isSubscriptionReportHistory = (value) => {
|
|
|
448
451
|
!isDateTime(period.sourceGeneratedAt) ||
|
|
449
452
|
!isHistoryMetrics(period.metrics) ||
|
|
450
453
|
!isBoundedRows(period.recommendations, REPORT_EVIDENCE_LIMITS.historyRecommendations, isRecommendationFingerprint) ||
|
|
451
|
-
(period.comparisonIdentities !== undefined && !isHistoryComparisonIdentities(period.comparisonIdentities))
|
|
454
|
+
(period.comparisonIdentities !== undefined && !isHistoryComparisonIdentities(period.comparisonIdentities)) ||
|
|
455
|
+
(period.stories !== undefined && !isStoryFingerprintRows(period.stories))) {
|
|
452
456
|
return false;
|
|
453
457
|
}
|
|
454
458
|
if (period.recommendations.omittedCount === 0 &&
|
|
@@ -1,22 +1,6 @@
|
|
|
1
1
|
import { REPORT_EVIDENCE_LIMITS } from './reportEvidence.js';
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
export const isOptionalString = (value) => value === undefined || isString(value);
|
|
5
|
-
export const isFiniteNumber = (value) => typeof value === 'number' && Number.isFinite(value);
|
|
6
|
-
export const isOptionalFiniteNumber = (value) => value === undefined || isFiniteNumber(value);
|
|
7
|
-
export const isOptionalBoolean = (value) => value === undefined || typeof value === 'boolean';
|
|
8
|
-
export const isCount = (value) => isFiniteNumber(value) && Number.isInteger(value) && value >= 0;
|
|
9
|
-
export const isDateTime = (value) => isString(value) && Number.isFinite(Date.parse(value));
|
|
10
|
-
export const isStringArray = (value) => Array.isArray(value) && value.every(isString);
|
|
11
|
-
export const isCountRecord = (value) => isRecord(value) && Object.values(value).every(isCount);
|
|
12
|
-
export const countTotal = (value) => Object.values(value).reduce((total, count) => total + count, 0);
|
|
13
|
-
export const hasOptionalStrings = (value, keys) => keys.every(key => isOptionalString(value[key]));
|
|
14
|
-
export const hasOptionalNumbers = (value, keys) => keys.every(key => isOptionalFiniteNumber(value[key]));
|
|
15
|
-
export const isBoundedRows = (value, limit, isRow) => {
|
|
16
|
-
if (!isRecord(value) || !isCount(value.totalCount) || !isCount(value.omittedCount) || !Array.isArray(value.rows))
|
|
17
|
-
return false;
|
|
18
|
-
return value.rows.length <= limit && value.rows.every(isRow) && value.totalCount === value.rows.length + value.omittedCount;
|
|
19
|
-
};
|
|
2
|
+
import { isBoundedRows, isCount, isCountRecord, isFiniteNumber, isOptionalFiniteNumber, isOptionalString, isRecord, isString, isStringArray, hasOptionalNumbers, hasOptionalStrings, } from '../common/validationHelpers.js';
|
|
3
|
+
export { isRecord, isString, isOptionalString, isFiniteNumber, isOptionalFiniteNumber, isOptionalBoolean, isCount, isDateTime, isStringArray, isCountRecord, countTotal, hasOptionalStrings, hasOptionalNumbers, isBoundedRows, } from '../common/validationHelpers.js';
|
|
20
4
|
export const isProjectionRows = (value, limit = REPORT_EVIDENCE_LIMITS.detailRows) => isBoundedRows(value, limit, isRecord);
|
|
21
5
|
export const hasRequiredRecords = (value, keys) => keys.every(key => isRecord(value[key]));
|
|
22
6
|
export const isSourceFileStatus = (value) => isRecord(value) &&
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resilience facts: the small per-resource property reads the resilience story needs that no other collection
|
|
3
|
+
* carries — storage blob-service data-protection settings and lifecycle management, Azure SQL database backup
|
|
4
|
+
* retention and failover groups. Collected in the reliability component beside the data-protection posture and
|
|
5
|
+
* published as `azure-portal/subscriptions/{id}/resilience-facts.json`. Consumed by the cloud-engine
|
|
6
|
+
* `ProtectionProfileBuilder` (`data-protection:<selector>` capability sources) and available to the resilience story page.
|
|
7
|
+
*
|
|
8
|
+
* Spec: `Specs/reporting/utilization-stories-types-package.md` (parent: core `specs/reporting/utilization-stories.md`).
|
|
9
|
+
* Additive: consumers tolerate unknown fields. Field semantics: `undefined` = not read (the request failed, was not
|
|
10
|
+
* applicable or was skipped) and resolves to an `unknown` capability; `null` = read and absent/disabled. A failed
|
|
11
|
+
* read must never be presented as "disabled".
|
|
12
|
+
*/
|
|
13
|
+
export const RESILIENCE_FACTS_SCHEMA_VERSION = 1;
|
|
14
|
+
export const RESILIENCE_FACTS_SOURCE = 'AzureResilienceFacts';
|
|
15
|
+
export const RESILIENCE_FACTS_PORTAL_FILE = 'resilience-facts.json';
|
|
16
|
+
export const RESILIENCE_FACTS_RAW_FILE = 'data-protection/resilience-facts.json.gz';
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { isCount, isDateTime, isFiniteNumber, isRecord, isString, isStringArray } from '../common/validationHelpers.js';
|
|
2
|
+
import { RESILIENCE_FACTS_SCHEMA_VERSION, RESILIENCE_FACTS_SOURCE, } from './resilienceFacts.js';
|
|
3
|
+
const STATUSES = new Set(['collected', 'partial', 'failed', 'not-applicable']);
|
|
4
|
+
const isNullableBoolean = (value) => value === null || typeof value === 'boolean';
|
|
5
|
+
const isNullableNumber = (value) => value === null || isFiniteNumber(value);
|
|
6
|
+
const isOptionalNullableNumber = (value) => value === undefined || isNullableNumber(value);
|
|
7
|
+
const isOptionalNullableString = (value) => value === undefined || value === null || isString(value);
|
|
8
|
+
const isRetention = (value) => value === undefined || value === null || (isRecord(value) && typeof value.enabled === 'boolean' && isOptionalNullableNumber(value.days));
|
|
9
|
+
const isOptionalNullableBoolean = (value) => value === undefined || isNullableBoolean(value);
|
|
10
|
+
const isStorageFacts = (value) => isRecord(value) &&
|
|
11
|
+
isRetention(value.blobSoftDelete) &&
|
|
12
|
+
isRetention(value.containerSoftDelete) &&
|
|
13
|
+
isOptionalNullableBoolean(value.versioning) &&
|
|
14
|
+
isRetention(value.changeFeed) &&
|
|
15
|
+
isRetention(value.pointInTimeRestore) &&
|
|
16
|
+
isOptionalNullableString(value.kind) &&
|
|
17
|
+
(value.managementPolicy === undefined ||
|
|
18
|
+
value.managementPolicy === null ||
|
|
19
|
+
(isRecord(value.managementPolicy) &&
|
|
20
|
+
typeof value.managementPolicy.present === 'boolean' &&
|
|
21
|
+
(value.managementPolicy.ruleCount === undefined || isCount(value.managementPolicy.ruleCount))));
|
|
22
|
+
const isSqlFacts = (value) => isRecord(value) &&
|
|
23
|
+
isOptionalNullableNumber(value.shortTermRetentionDays) &&
|
|
24
|
+
isOptionalNullableNumber(value.diffBackupIntervalHours) &&
|
|
25
|
+
(value.longTermRetention === undefined ||
|
|
26
|
+
value.longTermRetention === null ||
|
|
27
|
+
(isRecord(value.longTermRetention) &&
|
|
28
|
+
typeof value.longTermRetention.enabled === 'boolean' &&
|
|
29
|
+
isOptionalNullableString(value.longTermRetention.weekly) &&
|
|
30
|
+
isOptionalNullableString(value.longTermRetention.monthly) &&
|
|
31
|
+
isOptionalNullableString(value.longTermRetention.yearly) &&
|
|
32
|
+
isOptionalNullableNumber(value.longTermRetention.weekOfYear))) &&
|
|
33
|
+
(value.failoverGroup === undefined ||
|
|
34
|
+
value.failoverGroup === null ||
|
|
35
|
+
(isRecord(value.failoverGroup) &&
|
|
36
|
+
isString(value.failoverGroup.id) &&
|
|
37
|
+
isString(value.failoverGroup.name) &&
|
|
38
|
+
isStringArray(value.failoverGroup.partnerServers) &&
|
|
39
|
+
isOptionalNullableString(value.failoverGroup.readWriteFailoverPolicy) &&
|
|
40
|
+
isOptionalNullableString(value.failoverGroup.role))) &&
|
|
41
|
+
isOptionalNullableString(value.backupStorageRedundancy);
|
|
42
|
+
export const isResilienceFactsItem = (value) => isRecord(value) &&
|
|
43
|
+
isString(value.resourceId) &&
|
|
44
|
+
isString(value.resourceType) &&
|
|
45
|
+
isString(value.status) &&
|
|
46
|
+
STATUSES.has(value.status) &&
|
|
47
|
+
isDateTime(value.observedAt) &&
|
|
48
|
+
isCount(value.requestCount) &&
|
|
49
|
+
(value.errors === undefined || isStringArray(value.errors)) &&
|
|
50
|
+
(value.storage === undefined || isStorageFacts(value.storage)) &&
|
|
51
|
+
(value.sql === undefined || isSqlFacts(value.sql));
|
|
52
|
+
export const isResilienceFactsProjection = (value) => isRecord(value) &&
|
|
53
|
+
value.schemaVersion === RESILIENCE_FACTS_SCHEMA_VERSION &&
|
|
54
|
+
value.source === RESILIENCE_FACTS_SOURCE &&
|
|
55
|
+
isString(value.subscriptionId) &&
|
|
56
|
+
(value.tenantId === undefined || isString(value.tenantId)) &&
|
|
57
|
+
isDateTime(value.generatedAt) &&
|
|
58
|
+
isRecord(value.summary) &&
|
|
59
|
+
(value.summary.notApplicable === undefined || isCount(value.summary.notApplicable)) &&
|
|
60
|
+
['storageAccounts', 'sqlDatabases', 'sqlServers', 'collected', 'partial', 'failed', 'requestCount'].every(key => isCount(value.summary[key])) &&
|
|
61
|
+
Array.isArray(value.items) &&
|
|
62
|
+
value.items.every(isResilienceFactsItem) &&
|
|
63
|
+
Array.isArray(value.issues) &&
|
|
64
|
+
value.issues.every(issue => isRecord(issue) && (issue.severity === 'warning' || issue.severity === 'error') && isString(issue.code) && isString(issue.message));
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const STORY_KEYS = [
|
|
2
|
+
'oversized-resources',
|
|
3
|
+
'right-sku',
|
|
4
|
+
'schedule-candidates',
|
|
5
|
+
'resilience-recovery',
|
|
6
|
+
'hybrid-benefit',
|
|
7
|
+
'commitments',
|
|
8
|
+
];
|
|
9
|
+
export const STORY_LIMITS = {
|
|
10
|
+
sectionRows: 1000,
|
|
11
|
+
sampleRows: 50,
|
|
12
|
+
windowDays: 30,
|
|
13
|
+
weeklyGridDays: 7,
|
|
14
|
+
weeklyGridHours: 24,
|
|
15
|
+
/** Story fingerprints retained per monthly history period (all stories together). */
|
|
16
|
+
historyFingerprints: 2000,
|
|
17
|
+
};
|