@spottoai/types-package 1.0.2-beta.420 → 1.0.2-beta.421

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +3 -0
  2. package/dist/accounts/azureSpSetup.d.ts +5 -0
  3. package/dist/accounts/azureSpSetup.d.ts.map +1 -1
  4. package/dist/accounts/azureSpSetup.js.map +1 -1
  5. package/dist/accounts/writePermissions.d.ts +5 -1
  6. package/dist/accounts/writePermissions.d.ts.map +1 -1
  7. package/dist/accounts/writePermissions.js +9 -0
  8. package/dist/accounts/writePermissions.js.map +1 -1
  9. package/dist/esm/accounts/writePermissions.js +9 -0
  10. package/dist/esm/scheduler/index.js +2 -3
  11. package/dist/esm/scheduler/resourceStrategy.js +2 -0
  12. package/dist/esm/scheduler/resourceStrategyCapabilityValidation.js +241 -0
  13. package/dist/esm/scheduler/resourceStrategyContracts.js +14 -0
  14. package/dist/esm/scheduler/resourceStrategyFinancialValidation.js +145 -0
  15. package/dist/esm/scheduler/resourceStrategyPermissionValidation.js +190 -0
  16. package/dist/esm/scheduler/resourceStrategyScheduleValidation.js +332 -0
  17. package/dist/esm/scheduler/resourceStrategyValidation.js +4 -0
  18. package/dist/esm/scheduler/resourceStrategyValidationShared.js +261 -0
  19. package/dist/esm/scheduler/weeklyAvailabilityFixtures.js +140 -0
  20. package/dist/scheduler/index.d.ts +2 -3
  21. package/dist/scheduler/index.d.ts.map +1 -1
  22. package/dist/scheduler/index.js +2 -3
  23. package/dist/scheduler/index.js.map +1 -1
  24. package/dist/scheduler/resourceStrategy.d.ts +3 -0
  25. package/dist/scheduler/resourceStrategy.d.ts.map +1 -0
  26. package/dist/scheduler/resourceStrategy.js +19 -0
  27. package/dist/scheduler/resourceStrategy.js.map +1 -0
  28. package/dist/scheduler/resourceStrategyCapabilityValidation.d.ts +4 -0
  29. package/dist/scheduler/resourceStrategyCapabilityValidation.d.ts.map +1 -0
  30. package/dist/scheduler/resourceStrategyCapabilityValidation.js +246 -0
  31. package/dist/scheduler/resourceStrategyCapabilityValidation.js.map +1 -0
  32. package/dist/scheduler/resourceStrategyContracts.d.ts +412 -0
  33. package/dist/scheduler/resourceStrategyContracts.d.ts.map +1 -0
  34. package/dist/scheduler/resourceStrategyContracts.js +18 -0
  35. package/dist/scheduler/resourceStrategyContracts.js.map +1 -0
  36. package/dist/scheduler/resourceStrategyFinancialValidation.d.ts +5 -0
  37. package/dist/scheduler/resourceStrategyFinancialValidation.d.ts.map +1 -0
  38. package/dist/scheduler/resourceStrategyFinancialValidation.js +151 -0
  39. package/dist/scheduler/resourceStrategyFinancialValidation.js.map +1 -0
  40. package/dist/scheduler/resourceStrategyPermissionValidation.d.ts +4 -0
  41. package/dist/scheduler/resourceStrategyPermissionValidation.d.ts.map +1 -0
  42. package/dist/scheduler/resourceStrategyPermissionValidation.js +195 -0
  43. package/dist/scheduler/resourceStrategyPermissionValidation.js.map +1 -0
  44. package/dist/scheduler/resourceStrategyScheduleValidation.d.ts +10 -0
  45. package/dist/scheduler/resourceStrategyScheduleValidation.d.ts.map +1 -0
  46. package/dist/scheduler/resourceStrategyScheduleValidation.js +343 -0
  47. package/dist/scheduler/resourceStrategyScheduleValidation.js.map +1 -0
  48. package/dist/scheduler/resourceStrategyValidation.d.ts +5 -0
  49. package/dist/scheduler/resourceStrategyValidation.d.ts.map +1 -0
  50. package/dist/scheduler/resourceStrategyValidation.js +21 -0
  51. package/dist/scheduler/resourceStrategyValidation.js.map +1 -0
  52. package/dist/scheduler/resourceStrategyValidationShared.d.ts +19 -0
  53. package/dist/scheduler/resourceStrategyValidationShared.d.ts.map +1 -0
  54. package/dist/scheduler/resourceStrategyValidationShared.js +281 -0
  55. package/dist/scheduler/resourceStrategyValidationShared.js.map +1 -0
  56. package/dist/scheduler/scheduler.d.ts +6 -159
  57. package/dist/scheduler/scheduler.d.ts.map +1 -1
  58. package/dist/scheduler/weeklyAvailabilityFixtures.d.ts +26 -0
  59. package/dist/scheduler/weeklyAvailabilityFixtures.d.ts.map +1 -0
  60. package/dist/scheduler/weeklyAvailabilityFixtures.js +144 -0
  61. package/dist/scheduler/weeklyAvailabilityFixtures.js.map +1 -0
  62. package/package.json +11 -3
  63. package/dist/esm/scheduler/bastionSchedule.js +0 -1
  64. package/dist/esm/scheduler/bastionScheduleProfile.js +0 -206
  65. package/dist/esm/scheduler/bastionScheduleValidation.js +0 -401
  66. package/dist/scheduler/bastionSchedule.d.ts +0 -113
  67. package/dist/scheduler/bastionSchedule.d.ts.map +0 -1
  68. package/dist/scheduler/bastionSchedule.js +0 -3
  69. package/dist/scheduler/bastionSchedule.js.map +0 -1
  70. package/dist/scheduler/bastionScheduleProfile.d.ts +0 -24
  71. package/dist/scheduler/bastionScheduleProfile.d.ts.map +0 -1
  72. package/dist/scheduler/bastionScheduleProfile.js +0 -210
  73. package/dist/scheduler/bastionScheduleProfile.js.map +0 -1
  74. package/dist/scheduler/bastionScheduleValidation.d.ts +0 -10
  75. package/dist/scheduler/bastionScheduleValidation.d.ts.map +0 -1
  76. package/dist/scheduler/bastionScheduleValidation.js +0 -412
  77. package/dist/scheduler/bastionScheduleValidation.js.map +0 -1
@@ -0,0 +1,190 @@
1
+ import { RESOURCE_STRATEGY_CONTRACT_LIMITS, } from './resourceStrategyContracts.js';
2
+ import { hasOnlyKeys, isBoundedString, isBoundedStringArray, isCapabilityRef, isIsoTimestamp, isRecord, isWithinJsonByteLimit, } from './resourceStrategyValidationShared.js';
3
+ export function isResourceSchedulePermissionManifestProjection(value) {
4
+ if (!isWithinJsonByteLimit(value, RESOURCE_STRATEGY_CONTRACT_LIMITS.publicDtoBytes) ||
5
+ !isRecord(value) ||
6
+ !hasOnlyKeys(value, [
7
+ 'schemaVersion',
8
+ 'provider',
9
+ 'version',
10
+ 'contentHash',
11
+ 'capabilityVersions',
12
+ 'orderedGrantGroupHashes',
13
+ 'grantGroups',
14
+ 'generatedAtUtc',
15
+ 'evidenceObservedAtUtc',
16
+ 'expiresAtUtc',
17
+ 'reviewStatus',
18
+ 'change',
19
+ ]) ||
20
+ value.schemaVersion !== 1 ||
21
+ !isBoundedString(value.provider, 100) ||
22
+ !isBoundedString(value.version, 200) ||
23
+ !isBoundedString(value.contentHash, 200) ||
24
+ !Array.isArray(value.capabilityVersions) ||
25
+ value.capabilityVersions.length === 0 ||
26
+ value.capabilityVersions.length > RESOURCE_STRATEGY_CONTRACT_LIMITS.metadataItems ||
27
+ !value.capabilityVersions.every(isCapabilityRef) ||
28
+ !Array.isArray(value.grantGroups) ||
29
+ value.grantGroups.length === 0 ||
30
+ value.grantGroups.length > RESOURCE_STRATEGY_CONTRACT_LIMITS.grantGroups ||
31
+ !Array.isArray(value.orderedGrantGroupHashes) ||
32
+ value.orderedGrantGroupHashes.length !== value.grantGroups.length ||
33
+ !isIsoTimestamp(value.generatedAtUtc) ||
34
+ !isIsoTimestamp(value.evidenceObservedAtUtc) ||
35
+ !(value.expiresAtUtc === null || isIsoTimestamp(value.expiresAtUtc)) ||
36
+ !['current', 'review-required', 'expired'].includes(String(value.reviewStatus)) ||
37
+ !isRecord(value.change) ||
38
+ !hasOnlyKeys(value.change, ['status', 'addedOperations', 'removedOperations']) ||
39
+ !['new', 'unchanged', 'expanding', 'narrowing', 'missing'].includes(String(value.change.status)) ||
40
+ !isPermissionChangeOperations(value.change.addedOperations) ||
41
+ !isPermissionChangeOperations(value.change.removedOperations) ||
42
+ Date.parse(value.evidenceObservedAtUtc) > Date.parse(value.generatedAtUtc) ||
43
+ (typeof value.expiresAtUtc === 'string' && Date.parse(value.expiresAtUtc) < Date.parse(value.generatedAtUtc)) ||
44
+ new Set(value.capabilityVersions.map(item => `${item.capabilityId}:${item.capabilityVersion}`)).size !== value.capabilityVersions.length) {
45
+ return false;
46
+ }
47
+ const change = value.change;
48
+ const addedKeys = new Set(change.addedOperations.map(permissionChangeOperationKey));
49
+ const removedKeys = new Set(change.removedOperations.map(permissionChangeOperationKey));
50
+ if (addedKeys.size !== change.addedOperations.length ||
51
+ removedKeys.size !== change.removedOperations.length ||
52
+ [...addedKeys].some(key => removedKeys.has(key))) {
53
+ return false;
54
+ }
55
+ if ((value.change.status === 'unchanged' && (change.addedOperations.length > 0 || change.removedOperations.length > 0)) ||
56
+ ((value.change.status === 'new' || value.change.status === 'missing') &&
57
+ (change.addedOperations.length === 0 || change.removedOperations.length > 0)) ||
58
+ (value.change.status === 'expanding' && change.addedOperations.length === 0) ||
59
+ (value.change.status === 'narrowing' && (change.addedOperations.length > 0 || change.removedOperations.length === 0))) {
60
+ return false;
61
+ }
62
+ const grantGroups = value.grantGroups;
63
+ const seenGroupHashes = new Set();
64
+ const validGrantGroups = grantGroups.every(group => {
65
+ if (!isRecord(group) ||
66
+ !hasOnlyKeys(group, [
67
+ 'groupHash',
68
+ 'provider',
69
+ 'providerScopeId',
70
+ 'exactAssignmentScope',
71
+ 'operationSetHash',
72
+ 'principalRef',
73
+ 'roleDefinitionRef',
74
+ 'roleName',
75
+ 'roleDefinitionScope',
76
+ 'roleAssignmentRef',
77
+ 'actions',
78
+ 'dataActions',
79
+ 'disclosureKeys',
80
+ ]) ||
81
+ !isBoundedString(group.groupHash, 200) ||
82
+ group.provider !== value.provider ||
83
+ !isBoundedString(group.providerScopeId, 300) ||
84
+ !isBoundedString(group.exactAssignmentScope, 2000) ||
85
+ !isBoundedString(group.operationSetHash, 200) ||
86
+ !isBoundedString(group.principalRef, 200) ||
87
+ !isBoundedString(group.roleDefinitionRef, 200) ||
88
+ !isBoundedString(group.roleName, 500) ||
89
+ !isBoundedString(group.roleDefinitionScope, 2000) ||
90
+ !isBoundedString(group.roleAssignmentRef, 200) ||
91
+ !isPermissionOperations(group.actions) ||
92
+ !isPermissionOperations(group.dataActions) ||
93
+ group.actions.length + group.dataActions.length === 0 ||
94
+ (group.disclosureKeys !== undefined && !isBoundedStringArray(group.disclosureKeys)) ||
95
+ seenGroupHashes.has(group.groupHash)) {
96
+ return false;
97
+ }
98
+ const actions = group.actions;
99
+ const dataActions = group.dataActions;
100
+ if (actions.some(action => dataActions.some(dataAction => dataAction.operation.toLowerCase() === action.operation.toLowerCase()))) {
101
+ return false;
102
+ }
103
+ seenGroupHashes.add(group.groupHash);
104
+ return true;
105
+ });
106
+ if (!validGrantGroups ||
107
+ !value.orderedGrantGroupHashes.every((hash, index) => isBoundedString(hash, 200) && isRecord(grantGroups[index]) && hash === grantGroups[index].groupHash)) {
108
+ return false;
109
+ }
110
+ const currentOperationKeys = new Set();
111
+ for (const group of grantGroups) {
112
+ if (!isRecord(group))
113
+ return false;
114
+ for (const operation of group.actions) {
115
+ currentOperationKeys.add(permissionChangeOperationKey({
116
+ groupHash: String(group.groupHash),
117
+ providerScopeId: String(group.providerScopeId),
118
+ exactAssignmentScope: String(group.exactAssignmentScope),
119
+ operationKind: 'action',
120
+ operation: operation.operation,
121
+ }));
122
+ }
123
+ for (const operation of group.dataActions) {
124
+ currentOperationKeys.add(permissionChangeOperationKey({
125
+ groupHash: String(group.groupHash),
126
+ providerScopeId: String(group.providerScopeId),
127
+ exactAssignmentScope: String(group.exactAssignmentScope),
128
+ operationKind: 'data-action',
129
+ operation: operation.operation,
130
+ }));
131
+ }
132
+ }
133
+ if ((value.change.status === 'new' || value.change.status === 'missing') &&
134
+ (addedKeys.size !== currentOperationKeys.size || [...currentOperationKeys].some(key => !addedKeys.has(key)))) {
135
+ return false;
136
+ }
137
+ return (change.addedOperations.every(operation => currentOperationKeys.has(permissionChangeOperationKey(operation))) &&
138
+ change.removedOperations.every(operation => !currentOperationKeys.has(permissionChangeOperationKey(operation))));
139
+ }
140
+ function permissionChangeOperationKey(value) {
141
+ return [value.groupHash, value.providerScopeId, value.exactAssignmentScope, value.operationKind, value.operation]
142
+ .map(item => item.toLowerCase())
143
+ .join('\u0000');
144
+ }
145
+ function isPermissionChangeOperations(value) {
146
+ return (Array.isArray(value) &&
147
+ value.length <= RESOURCE_STRATEGY_CONTRACT_LIMITS.permissionOperations &&
148
+ value.every(item => isRecord(item) &&
149
+ hasOnlyKeys(item, ['groupHash', 'providerScopeId', 'exactAssignmentScope', 'operationKind', 'operation']) &&
150
+ isBoundedString(item.groupHash, 200) &&
151
+ isBoundedString(item.providerScopeId, 300) &&
152
+ isBoundedString(item.exactAssignmentScope, 2000) &&
153
+ ['action', 'data-action'].includes(String(item.operationKind)) &&
154
+ isBoundedString(item.operation, 500) &&
155
+ !item.operation.includes('*')));
156
+ }
157
+ function isPermissionOperations(value) {
158
+ if (!Array.isArray(value) || value.length > RESOURCE_STRATEGY_CONTRACT_LIMITS.metadataItems)
159
+ return false;
160
+ const operations = new Set();
161
+ return value.every(item => {
162
+ if (!isRecord(item) ||
163
+ !hasOnlyKeys(item, ['operation', 'permissionSetRefs', 'reason', 'evidenceUrl']) ||
164
+ !isBoundedString(item.operation, 500) ||
165
+ item.operation.includes('*') ||
166
+ !Array.isArray(item.permissionSetRefs) ||
167
+ item.permissionSetRefs.length === 0 ||
168
+ !isBoundedStringArray(item.permissionSetRefs) ||
169
+ new Set(item.permissionSetRefs).size !== item.permissionSetRefs.length ||
170
+ !isBoundedString(item.reason, 2000) ||
171
+ !isBoundedString(item.evidenceUrl, 2000) ||
172
+ operations.has(item.operation.toLowerCase())) {
173
+ return false;
174
+ }
175
+ operations.add(item.operation.toLowerCase());
176
+ return true;
177
+ });
178
+ }
179
+ export function isResourceSchedulePermissionManifestConsent(value) {
180
+ return (isWithinJsonByteLimit(value, RESOURCE_STRATEGY_CONTRACT_LIMITS.publicDtoBytes) &&
181
+ isRecord(value) &&
182
+ hasOnlyKeys(value, ['version', 'contentHash', 'orderedGrantGroupHashes']) &&
183
+ isBoundedString(value.version, 200) &&
184
+ isBoundedString(value.contentHash, 200) &&
185
+ Array.isArray(value.orderedGrantGroupHashes) &&
186
+ value.orderedGrantGroupHashes.length > 0 &&
187
+ value.orderedGrantGroupHashes.length <= RESOURCE_STRATEGY_CONTRACT_LIMITS.grantGroups &&
188
+ value.orderedGrantGroupHashes.every(item => isBoundedString(item, 200)) &&
189
+ new Set(value.orderedGrantGroupHashes).size === value.orderedGrantGroupHashes.length);
190
+ }
@@ -0,0 +1,332 @@
1
+ import { RESOURCE_STRATEGY_CONTRACT_LIMITS, } from './resourceStrategyContracts.js';
2
+ import { containsForbiddenKey, hasOnlyKeys, isBoundedParameters, isBoundedString, isCapabilityRef, isDate, isIanaTimezone, isIsoTimestamp, isNonNegativeInteger, isOptionalBoundedString, isPositiveInteger, isRecord, isTime, isWithinJsonByteLimit, } from './resourceStrategyValidationShared.js';
3
+ function isWeeklyRule(value) {
4
+ return (isRecord(value) &&
5
+ hasOnlyKeys(value, ['ruleId', 'transition', 'daysOfWeek', 'desiredStateAtLocal', 'parameters']) &&
6
+ isBoundedString(value.ruleId, 200) &&
7
+ (value.transition === 'reduce' || value.transition === 'restore') &&
8
+ Array.isArray(value.daysOfWeek) &&
9
+ value.daysOfWeek.length > 0 &&
10
+ value.daysOfWeek.length <= RESOURCE_STRATEGY_CONTRACT_LIMITS.ruleDays &&
11
+ new Set(value.daysOfWeek).size === value.daysOfWeek.length &&
12
+ value.daysOfWeek.every(day => Number.isInteger(day) && day >= 0 && day <= 6) &&
13
+ isTime(value.desiredStateAtLocal) &&
14
+ (value.parameters === undefined || isBoundedParameters(value.parameters)));
15
+ }
16
+ export function isResourceStrategyWeeklyScheduleSuggestion(value) {
17
+ if (!isWithinJsonByteLimit(value, RESOURCE_STRATEGY_CONTRACT_LIMITS.publicDtoBytes) || !isRecord(value) || containsForbiddenKey(value))
18
+ return false;
19
+ if (!hasOnlyKeys(value, [
20
+ 'definitionType',
21
+ 'capability',
22
+ 'defaultParameters',
23
+ 'rules',
24
+ 'busyPolicy',
25
+ 'blackoutDatesLocal',
26
+ 'activeFromUtc',
27
+ 'activeUntilUtc',
28
+ 'acknowledgementVersion',
29
+ 'firstExecutionAcknowledgementVersion',
30
+ ]) ||
31
+ value.definitionType !== 'resource-strategy-weekly' ||
32
+ !isCapabilityRef(value.capability) ||
33
+ (value.defaultParameters !== undefined && !isBoundedParameters(value.defaultParameters)) ||
34
+ !Array.isArray(value.rules) ||
35
+ value.rules.length === 0 ||
36
+ value.rules.length > RESOURCE_STRATEGY_CONTRACT_LIMITS.rules ||
37
+ !value.rules.every(isWeeklyRule) ||
38
+ new Set(value.rules.map(rule => rule.ruleId)).size !== value.rules.length ||
39
+ !isOptionalBoundedString(value.acknowledgementVersion, 200) ||
40
+ !isOptionalBoundedString(value.firstExecutionAcknowledgementVersion, 200)) {
41
+ return false;
42
+ }
43
+ if (value.busyPolicy !== undefined) {
44
+ if (!isRecord(value.busyPolicy) ||
45
+ !hasOnlyKeys(value.busyPolicy, ['mode', 'maxDelayMinutes']) ||
46
+ !['skip', 'wait-until-deadline', 'force'].includes(String(value.busyPolicy.mode)) ||
47
+ (value.busyPolicy.maxDelayMinutes !== undefined && !isNonNegativeInteger(value.busyPolicy.maxDelayMinutes))) {
48
+ return false;
49
+ }
50
+ }
51
+ if (value.blackoutDatesLocal !== undefined &&
52
+ (!Array.isArray(value.blackoutDatesLocal) ||
53
+ value.blackoutDatesLocal.length > RESOURCE_STRATEGY_CONTRACT_LIMITS.metadataItems ||
54
+ !value.blackoutDatesLocal.every(isDate))) {
55
+ return false;
56
+ }
57
+ if (value.activeFromUtc !== undefined && !isIsoTimestamp(value.activeFromUtc))
58
+ return false;
59
+ if (value.activeUntilUtc !== undefined && !isIsoTimestamp(value.activeUntilUtc))
60
+ return false;
61
+ if (typeof value.activeFromUtc === 'string' &&
62
+ typeof value.activeUntilUtc === 'string' &&
63
+ Date.parse(value.activeFromUtc) > Date.parse(value.activeUntilUtc)) {
64
+ return false;
65
+ }
66
+ return true;
67
+ }
68
+ export function isResourceStrategyWeeklyScheduleWriteRequest(value) {
69
+ if (!isWithinJsonByteLimit(value, RESOURCE_STRATEGY_CONTRACT_LIMITS.publicDtoBytes) || !isRecord(value) || containsForbiddenKey(value))
70
+ return false;
71
+ if (!hasOnlyKeys(value, [
72
+ 'definitionType',
73
+ 'providerScopeId',
74
+ 'cloudAccountId',
75
+ 'resourceId',
76
+ 'capability',
77
+ 'name',
78
+ 'timezone',
79
+ 'defaultParameters',
80
+ 'rules',
81
+ 'busyPolicy',
82
+ 'blackoutDatesLocal',
83
+ 'activeFromUtc',
84
+ 'activeUntilUtc',
85
+ 'initialMode',
86
+ 'notificationPolicyId',
87
+ 'acknowledgementVersion',
88
+ 'firstExecutionAcknowledgementVersion',
89
+ 'notes',
90
+ ])) {
91
+ return false;
92
+ }
93
+ if (value.definitionType !== 'resource-strategy-weekly' ||
94
+ !isBoundedString(value.providerScopeId, 300) ||
95
+ !isBoundedString(value.cloudAccountId, 200) ||
96
+ !isBoundedString(value.resourceId, 2000) ||
97
+ !isCapabilityRef(value.capability) ||
98
+ !isBoundedString(value.name) ||
99
+ !isIanaTimezone(value.timezone) ||
100
+ (value.defaultParameters !== undefined && !isBoundedParameters(value.defaultParameters)) ||
101
+ !Array.isArray(value.rules) ||
102
+ value.rules.length === 0 ||
103
+ value.rules.length > RESOURCE_STRATEGY_CONTRACT_LIMITS.rules ||
104
+ !value.rules.every(isWeeklyRule) ||
105
+ new Set(value.rules.map(rule => rule.ruleId)).size !== value.rules.length ||
106
+ !['draft', 'dry-run', 'active'].includes(String(value.initialMode)) ||
107
+ !isBoundedString(value.notificationPolicyId, 200) ||
108
+ !isOptionalBoundedString(value.acknowledgementVersion, 200) ||
109
+ !isOptionalBoundedString(value.firstExecutionAcknowledgementVersion, 200) ||
110
+ !isOptionalBoundedString(value.notes)) {
111
+ return false;
112
+ }
113
+ if (value.busyPolicy !== undefined) {
114
+ if (!isRecord(value.busyPolicy) ||
115
+ !hasOnlyKeys(value.busyPolicy, ['mode', 'maxDelayMinutes']) ||
116
+ !['skip', 'wait-until-deadline', 'force'].includes(String(value.busyPolicy.mode)) ||
117
+ (value.busyPolicy.maxDelayMinutes !== undefined && !isNonNegativeInteger(value.busyPolicy.maxDelayMinutes))) {
118
+ return false;
119
+ }
120
+ }
121
+ if (value.blackoutDatesLocal !== undefined &&
122
+ (!Array.isArray(value.blackoutDatesLocal) ||
123
+ value.blackoutDatesLocal.length > RESOURCE_STRATEGY_CONTRACT_LIMITS.metadataItems ||
124
+ !value.blackoutDatesLocal.every(isDate))) {
125
+ return false;
126
+ }
127
+ if (value.activeFromUtc !== undefined && !isIsoTimestamp(value.activeFromUtc))
128
+ return false;
129
+ if (value.activeUntilUtc !== undefined && !isIsoTimestamp(value.activeUntilUtc))
130
+ return false;
131
+ if (typeof value.activeFromUtc === 'string' &&
132
+ typeof value.activeUntilUtc === 'string' &&
133
+ Date.parse(value.activeFromUtc) > Date.parse(value.activeUntilUtc)) {
134
+ return false;
135
+ }
136
+ return true;
137
+ }
138
+ export function isResourceStrategyWeeklyScheduleProjection(value) {
139
+ if (!isWithinJsonByteLimit(value, RESOURCE_STRATEGY_CONTRACT_LIMITS.publicDtoBytes) ||
140
+ !isRecord(value) ||
141
+ !hasOnlyKeys(value, [
142
+ 'scheduleId',
143
+ 'definitionRevision',
144
+ 'controlGeneration',
145
+ 'etag',
146
+ 'status',
147
+ 'definition',
148
+ 'permissionManifest',
149
+ 'createdAtUtc',
150
+ 'createdBy',
151
+ 'updatedAtUtc',
152
+ 'updatedBy',
153
+ 'acknowledgement',
154
+ 'firstExecutionAcknowledgement',
155
+ ])) {
156
+ return false;
157
+ }
158
+ const isAcknowledgement = (item) => isRecord(item) &&
159
+ hasOnlyKeys(item, ['version', 'acknowledgedAtUtc', 'acknowledgedBy']) &&
160
+ isBoundedString(item.version, 200) &&
161
+ isIsoTimestamp(item.acknowledgedAtUtc) &&
162
+ isBoundedString(item.acknowledgedBy, 200);
163
+ return (isBoundedString(value.scheduleId, 200) &&
164
+ isPositiveInteger(value.definitionRevision) &&
165
+ isPositiveInteger(value.controlGeneration) &&
166
+ isBoundedString(value.etag, 500) &&
167
+ ['draft', 'dry-run', 'active', 'paused', 'restore-only'].includes(String(value.status)) &&
168
+ isResourceStrategyWeeklyScheduleWriteRequest(value.definition) &&
169
+ isManifestRef(value.permissionManifest) &&
170
+ isIsoTimestamp(value.createdAtUtc) &&
171
+ isBoundedString(value.createdBy, 200) &&
172
+ isIsoTimestamp(value.updatedAtUtc) &&
173
+ isBoundedString(value.updatedBy, 200) &&
174
+ (value.acknowledgement === undefined || isAcknowledgement(value.acknowledgement)) &&
175
+ (value.firstExecutionAcknowledgement === undefined || isAcknowledgement(value.firstExecutionAcknowledgement)));
176
+ }
177
+ function isManifestRef(value) {
178
+ return (isRecord(value) &&
179
+ hasOnlyKeys(value, ['version', 'contentHash']) &&
180
+ isBoundedString(value.version, 200) &&
181
+ isBoundedString(value.contentHash, 200));
182
+ }
183
+ export function isScheduledResourceTransitionV1(value) {
184
+ return (isWithinJsonByteLimit(value, RESOURCE_STRATEGY_CONTRACT_LIMITS.publicDtoBytes) &&
185
+ isRecord(value) &&
186
+ !containsForbiddenKey(value.parameters) &&
187
+ hasOnlyKeys(value, [
188
+ 'schemaVersion',
189
+ 'companyId',
190
+ 'providerScopeId',
191
+ 'cloudAccountId',
192
+ 'resourceId',
193
+ 'scheduleId',
194
+ 'definitionRevision',
195
+ 'controlGeneration',
196
+ 'ruleId',
197
+ 'occurrenceKey',
198
+ 'scheduleRunId',
199
+ 'desiredStateAtUtc',
200
+ 'dispatchNotBeforeUtc',
201
+ 'reduceDeadlineUtc',
202
+ 'capability',
203
+ 'transition',
204
+ 'parameters',
205
+ 'permissionManifest',
206
+ 'correlationId',
207
+ ]) &&
208
+ value.schemaVersion === 1 &&
209
+ isBoundedString(value.companyId, 200) &&
210
+ isBoundedString(value.providerScopeId, 300) &&
211
+ isBoundedString(value.cloudAccountId, 200) &&
212
+ isBoundedString(value.resourceId, 2000) &&
213
+ isBoundedString(value.scheduleId, 200) &&
214
+ isPositiveInteger(value.definitionRevision) &&
215
+ isPositiveInteger(value.controlGeneration) &&
216
+ isBoundedString(value.ruleId, 200) &&
217
+ isBoundedString(value.occurrenceKey, 500) &&
218
+ isBoundedString(value.scheduleRunId, 200) &&
219
+ isIsoTimestamp(value.desiredStateAtUtc) &&
220
+ isIsoTimestamp(value.dispatchNotBeforeUtc) &&
221
+ (value.reduceDeadlineUtc === undefined || isIsoTimestamp(value.reduceDeadlineUtc)) &&
222
+ isCapabilityRef(value.capability) &&
223
+ (value.transition === 'reduce' || value.transition === 'restore') &&
224
+ isBoundedParameters(value.parameters) &&
225
+ isManifestRef(value.permissionManifest) &&
226
+ isBoundedString(value.correlationId, 200));
227
+ }
228
+ export function isResourceSchedulingExecutionProjection(value) {
229
+ if (!isWithinJsonByteLimit(value, RESOURCE_STRATEGY_CONTRACT_LIMITS.publicDtoBytes) ||
230
+ !isRecord(value) ||
231
+ !hasOnlyKeys(value, [
232
+ 'companyId',
233
+ 'resourceId',
234
+ 'scheduleId',
235
+ 'definitionRevision',
236
+ 'controlGeneration',
237
+ 'lifecycleState',
238
+ 'activeRecoveryCycleId',
239
+ 'restoreOwed',
240
+ 'lastRun',
241
+ 'allowedCommands',
242
+ 'updatedAtUtc',
243
+ ])) {
244
+ return false;
245
+ }
246
+ if (value.lastRun !== undefined) {
247
+ const lastRun = value.lastRun;
248
+ if (!isRecord(lastRun) ||
249
+ !hasOnlyKeys(lastRun, ['scheduleRunId', 'transition', 'phase', 'outcome', 'desiredStateAtUtc', 'updatedAtUtc', 'reasonCode']) ||
250
+ !isBoundedString(lastRun.scheduleRunId, 200) ||
251
+ !['reduce', 'restore'].includes(String(lastRun.transition)) ||
252
+ (lastRun.phase !== undefined &&
253
+ !['queued', 'leased', 'preflight', 'capturing-baseline', 'executing', 'polling', 'verifying'].includes(String(lastRun.phase))) ||
254
+ (lastRun.outcome !== undefined &&
255
+ !['succeeded', 'no-op', 'skipped', 'blocked', 'failed', 'superseded', 'expired'].includes(String(lastRun.outcome))) ||
256
+ !isIsoTimestamp(lastRun.desiredStateAtUtc) ||
257
+ !isIsoTimestamp(lastRun.updatedAtUtc) ||
258
+ !isOptionalBoundedString(lastRun.reasonCode, 200)) {
259
+ return false;
260
+ }
261
+ if ((lastRun.phase === undefined) === (lastRun.outcome === undefined))
262
+ return false;
263
+ }
264
+ return (isBoundedString(value.companyId, 200) &&
265
+ isBoundedString(value.resourceId, 2000) &&
266
+ isOptionalBoundedString(value.scheduleId, 200) &&
267
+ (value.definitionRevision === undefined || isPositiveInteger(value.definitionRevision)) &&
268
+ isPositiveInteger(value.controlGeneration) &&
269
+ ['unknown', 'normal', 'reducing', 'reduced', 'restoring', 'reduce-failed', 'restore-failed', 'drifted', 'target-missing', 'stranded'].includes(String(value.lifecycleState)) &&
270
+ isOptionalBoundedString(value.activeRecoveryCycleId, 200) &&
271
+ typeof value.restoreOwed === 'boolean' &&
272
+ Array.isArray(value.allowedCommands) &&
273
+ value.allowedCommands.length <= 4 &&
274
+ new Set(value.allowedCommands).size === value.allowedCommands.length &&
275
+ value.allowedCommands.every(command => ['pause', 'resume', 'restore-now', 'leave-current-state'].includes(String(command))) &&
276
+ isIsoTimestamp(value.updatedAtUtc));
277
+ }
278
+ function isResourceSchedulingExecutionHistoryItem(value) {
279
+ return (isRecord(value) &&
280
+ hasOnlyKeys(value, [
281
+ 'scheduleRunId',
282
+ 'resourceId',
283
+ 'transition',
284
+ 'desiredStateAtUtc',
285
+ 'claimedAtUtc',
286
+ 'completedAtUtc',
287
+ 'outcome',
288
+ 'reasonCode',
289
+ 'attemptCount',
290
+ ]) &&
291
+ isBoundedString(value.scheduleRunId, 200) &&
292
+ isBoundedString(value.resourceId, 2000) &&
293
+ (value.transition === 'reduce' || value.transition === 'restore') &&
294
+ isIsoTimestamp(value.desiredStateAtUtc) &&
295
+ isIsoTimestamp(value.claimedAtUtc) &&
296
+ (value.completedAtUtc === undefined || isIsoTimestamp(value.completedAtUtc)) &&
297
+ (value.outcome === undefined ||
298
+ ['succeeded', 'no-op', 'skipped', 'blocked', 'failed', 'superseded', 'expired'].includes(String(value.outcome))) &&
299
+ isOptionalBoundedString(value.reasonCode, 200) &&
300
+ isPositiveInteger(value.attemptCount) &&
301
+ ((value.completedAtUtc === undefined && value.outcome === undefined) || (value.completedAtUtc !== undefined && value.outcome !== undefined)));
302
+ }
303
+ export function isResourceSchedulingExecutionHistoryResponse(value) {
304
+ return (isWithinJsonByteLimit(value, RESOURCE_STRATEGY_CONTRACT_LIMITS.publicDtoBytes) &&
305
+ isRecord(value) &&
306
+ hasOnlyKeys(value, ['execution', 'runs']) &&
307
+ isResourceSchedulingExecutionProjection(value.execution) &&
308
+ Array.isArray(value.runs) &&
309
+ value.runs.length <= 100 &&
310
+ value.runs.every(isResourceSchedulingExecutionHistoryItem));
311
+ }
312
+ export function isResourceStrategyScheduleCommand(value) {
313
+ if (!isWithinJsonByteLimit(value, RESOURCE_STRATEGY_CONTRACT_LIMITS.publicDtoBytes) ||
314
+ !isRecord(value) ||
315
+ !hasOnlyKeys(value, ['command', 'idempotencyKey', 'acknowledgement']) ||
316
+ !isBoundedString(value.idempotencyKey, 200)) {
317
+ return false;
318
+ }
319
+ if (value.command === 'leave-current-state')
320
+ return isBoundedString(value.acknowledgement, 2000);
321
+ return ['pause', 'resume', 'restore-now'].includes(String(value.command)) && value.acknowledgement === undefined;
322
+ }
323
+ export function isResourceStrategyWeeklyScheduleListResponse(value) {
324
+ return (isWithinJsonByteLimit(value, RESOURCE_STRATEGY_CONTRACT_LIMITS.publicDtoBytes) &&
325
+ isRecord(value) &&
326
+ hasOnlyKeys(value, ['results', 'continuation']) &&
327
+ Array.isArray(value.results) &&
328
+ value.results.length <= RESOURCE_STRATEGY_CONTRACT_LIMITS.listResults &&
329
+ value.results.every(isResourceStrategyWeeklyScheduleProjection) &&
330
+ (value.continuation === undefined ||
331
+ (isRecord(value.continuation) && hasOnlyKeys(value.continuation, ['cursor']) && isBoundedString(value.continuation.cursor, 2000))));
332
+ }
@@ -0,0 +1,4 @@
1
+ export * from './resourceStrategyCapabilityValidation.js';
2
+ export * from './resourceStrategyFinancialValidation.js';
3
+ export * from './resourceStrategyPermissionValidation.js';
4
+ export * from './resourceStrategyScheduleValidation.js';