@resolveio/server-lib 22.3.154 → 22.3.156

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@resolveio/server-lib",
3
- "version": "22.3.154",
3
+ "version": "22.3.156",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "package": "./build_package.sh",
@@ -165,6 +165,61 @@ export interface ResolveIOAIManagerHotfixFirstReleasePolicy {
165
165
  forbiddenActions: string[];
166
166
  requiredEvidence: string[];
167
167
  }
168
+ export type ResolveIOAIManagerHotfixEvidenceStatus = 'missing' | 'incomplete' | 'passed' | 'blocked';
169
+ export interface ResolveIOAIManagerHotfixEvidenceTarget {
170
+ surface?: string;
171
+ host?: string;
172
+ path?: string;
173
+ artifactPath?: string;
174
+ bucket?: string;
175
+ distributionId?: string;
176
+ processName?: string;
177
+ configKey?: string;
178
+ cacheKey?: string;
179
+ seedKey?: string;
180
+ }
181
+ export interface ResolveIOAIManagerHotfixEvidence {
182
+ channel: ResolveIOAIManagerHotfixChannel;
183
+ status?: ResolveIOAIManagerHotfixEvidenceStatus | string;
184
+ target: ResolveIOAIManagerHotfixEvidenceTarget;
185
+ compiledArtifactPath?: string;
186
+ builtDistPath?: string;
187
+ remoteChecksumBefore?: string;
188
+ remoteChecksumAfter?: string;
189
+ remoteChecksum?: string;
190
+ restartEvidence?: string;
191
+ healthCheckStatus?: string;
192
+ selfTestStatus?: string;
193
+ releaseGateStatus?: string;
194
+ s3UploadResult?: string;
195
+ cloudfrontInvalidationId?: string;
196
+ publicProof?: string;
197
+ configChangeEvidence?: string;
198
+ seedDataEvidence?: string;
199
+ cacheInvalidationEvidence?: string;
200
+ serviceRestartEvidence?: string;
201
+ releaseArtifactFingerprint?: string;
202
+ lastReleaseArtifactFingerprint?: string;
203
+ forceDeployReason?: string;
204
+ hotfixCannotResolveReason?: string;
205
+ fullDeployRequested?: boolean;
206
+ recordedAt?: Date | string;
207
+ }
208
+ export interface ResolveIOAIManagerHotfixEvidenceValidation {
209
+ valid: boolean;
210
+ status: ResolveIOAIManagerHotfixEvidenceStatus;
211
+ channel: ResolveIOAIManagerHotfixChannel | '';
212
+ blockers: string[];
213
+ warnings: string[];
214
+ fullDeployAllowed: boolean;
215
+ fullDeployBlocked: boolean;
216
+ hotfixSatisfied: boolean;
217
+ requiredEvidence: string[];
218
+ successEvidence: string[];
219
+ normalized?: ResolveIOAIManagerHotfixEvidence;
220
+ policy?: ResolveIOAIManagerHotfixFirstReleasePolicy;
221
+ nextAction: 'record_hotfix_evidence' | 'rerun_release_gate' | 'request_force_deploy_reason' | 'allow_one_full_deploy' | 'park_manual';
222
+ }
168
223
  export interface ResolveIOAIManagerRecoveryActionPacket {
169
224
  actionId: string;
170
225
  checkpointId: string;
@@ -385,6 +440,10 @@ export interface ResolveIOAIManagerRecoveryReplayCase {
385
440
  fullDeployAllowed?: boolean;
386
441
  details?: Record<string, any>;
387
442
  }
443
+ export declare function normalizeResolveIOAIManagerHotfixEvidence(value: any, policy?: ResolveIOAIManagerHotfixFirstReleasePolicy): ResolveIOAIManagerHotfixEvidence | undefined;
444
+ export declare function validateResolveIOAIManagerHotfixEvidence(value: any, options?: {
445
+ policy?: ResolveIOAIManagerHotfixFirstReleasePolicy;
446
+ }): ResolveIOAIManagerHotfixEvidenceValidation;
388
447
  export declare function buildResolveIOAIManagerHotfixFirstReleasePolicy(input?: ResolveIOAIManagerHotfixFirstReleasePolicyInput): ResolveIOAIManagerHotfixFirstReleasePolicy;
389
448
  export declare function isResolveIOAIManagerSafeAutoDispatch(input: ResolveIOAIManagerAutoDispatchPolicyInput | ResolveIOAIManagerRecoveryActionDispatchAction | string | undefined): boolean;
390
449
  export declare function normalizeResolveIOAIManagerFailureClass(value: any): string;
@@ -47,6 +47,8 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
47
47
  return to.concat(ar || Array.prototype.slice.call(from));
48
48
  };
49
49
  Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.normalizeResolveIOAIManagerHotfixEvidence = normalizeResolveIOAIManagerHotfixEvidence;
51
+ exports.validateResolveIOAIManagerHotfixEvidence = validateResolveIOAIManagerHotfixEvidence;
50
52
  exports.buildResolveIOAIManagerHotfixFirstReleasePolicy = buildResolveIOAIManagerHotfixFirstReleasePolicy;
51
53
  exports.isResolveIOAIManagerSafeAutoDispatch = isResolveIOAIManagerSafeAutoDispatch;
52
54
  exports.normalizeResolveIOAIManagerFailureClass = normalizeResolveIOAIManagerFailureClass;
@@ -96,6 +98,240 @@ function cleanList(values, limit, max) {
96
98
  }
97
99
  return result;
98
100
  }
101
+ var HOTFIX_CHANNELS = new Set([
102
+ 'static_ui',
103
+ 'backend_js',
104
+ 'config',
105
+ 'seed_data',
106
+ 'cache_invalidation',
107
+ 'service_restart',
108
+ 'release_artifact',
109
+ 'force_deploy_review',
110
+ 'new_artifact_deploy',
111
+ 'artifact_build'
112
+ ]);
113
+ function cleanObject(value) {
114
+ return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
115
+ }
116
+ function normalizeHotfixChannel(value) {
117
+ var normalized = cleanText(value, 120).toLowerCase().replace(/[\s-]+/g, '_');
118
+ return HOTFIX_CHANNELS.has(normalized) ? normalized : '';
119
+ }
120
+ function normalizeHotfixStatus(value) {
121
+ var normalized = cleanText(value, 120).toLowerCase().replace(/[\s-]+/g, '_');
122
+ if (/^(pass|passed|success|succeeded|complete|completed|accepted)$/.test(normalized)) {
123
+ return 'passed';
124
+ }
125
+ if (/^(block|blocked|failed|fail|error|denied)$/.test(normalized)) {
126
+ return 'blocked';
127
+ }
128
+ if (/^(missing|none)$/.test(normalized)) {
129
+ return 'missing';
130
+ }
131
+ return 'incomplete';
132
+ }
133
+ function hotfixStatusPassed(value) {
134
+ return normalizeHotfixStatus(value) === 'passed';
135
+ }
136
+ function normalizeHotfixEvidenceTarget(value) {
137
+ var source = cleanObject(value);
138
+ return {
139
+ surface: cleanText(source.surface, 160),
140
+ host: cleanText(source.host || source.hostname || source.domain, 240),
141
+ path: cleanText(source.path || source.remotePath || source.remote_path, 500),
142
+ artifactPath: cleanText(source.artifactPath || source.artifact_path || source.localPath || source.local_path, 500),
143
+ bucket: cleanText(source.bucket || source.s3Bucket || source.s3_bucket, 240),
144
+ distributionId: cleanText(source.distributionId || source.distribution_id || source.cloudfrontDistributionId || source.cloudfront_distribution_id, 240),
145
+ processName: cleanText(source.processName || source.process_name || source.service || source.serviceName, 160),
146
+ configKey: cleanText(source.configKey || source.config_key || source.key, 240),
147
+ cacheKey: cleanText(source.cacheKey || source.cache_key, 240),
148
+ seedKey: cleanText(source.seedKey || source.seed_key || source.fixture, 240)
149
+ };
150
+ }
151
+ function normalizeResolveIOAIManagerHotfixEvidence(value, policy) {
152
+ var _a;
153
+ var source = cleanObject(value);
154
+ if (!Object.keys(source).length) {
155
+ return undefined;
156
+ }
157
+ var channel = normalizeHotfixChannel(source.channel || source.hotfixChannel || source.hotfix_channel || ((_a = policy === null || policy === void 0 ? void 0 : policy.hotfixPlan) === null || _a === void 0 ? void 0 : _a.recommendedChannel));
158
+ if (!channel) {
159
+ return undefined;
160
+ }
161
+ var target = normalizeHotfixEvidenceTarget(source.target || source);
162
+ return {
163
+ channel: channel,
164
+ status: normalizeHotfixStatus(source.status),
165
+ target: target,
166
+ compiledArtifactPath: cleanText(source.compiledArtifactPath || source.compiled_artifact_path || target.artifactPath, 500),
167
+ builtDistPath: cleanText(source.builtDistPath || source.built_dist_path || target.artifactPath, 500),
168
+ remoteChecksumBefore: cleanText(source.remoteChecksumBefore || source.remote_checksum_before || source.checksumBefore || source.checksum_before, 160),
169
+ remoteChecksumAfter: cleanText(source.remoteChecksumAfter || source.remote_checksum_after || source.checksumAfter || source.checksum_after, 160),
170
+ remoteChecksum: cleanText(source.remoteChecksum || source.remote_checksum || source.checksum, 160),
171
+ restartEvidence: cleanText(source.restartEvidence || source.restart_evidence, 1000),
172
+ healthCheckStatus: cleanText(source.healthCheckStatus || source.health_check_status || source.health, 160),
173
+ selfTestStatus: cleanText(source.selfTestStatus || source.self_test_status || source.selfTest || source.self_test, 160),
174
+ releaseGateStatus: cleanText(source.releaseGateStatus || source.release_gate_status || source.releaseGate || source.release_gate, 160),
175
+ s3UploadResult: cleanText(source.s3UploadResult || source.s3_upload_result || source.uploadResult || source.upload_result, 1000),
176
+ cloudfrontInvalidationId: cleanText(source.cloudfrontInvalidationId || source.cloudfront_invalidation_id || source.invalidationId || source.invalidation_id, 240),
177
+ publicProof: cleanText(source.publicProof || source.public_proof || source.publicUrl || source.public_url, 1000),
178
+ configChangeEvidence: cleanText(source.configChangeEvidence || source.config_change_evidence, 1000),
179
+ seedDataEvidence: cleanText(source.seedDataEvidence || source.seed_data_evidence, 1000),
180
+ cacheInvalidationEvidence: cleanText(source.cacheInvalidationEvidence || source.cache_invalidation_evidence, 1000),
181
+ serviceRestartEvidence: cleanText(source.serviceRestartEvidence || source.service_restart_evidence, 1000),
182
+ releaseArtifactFingerprint: cleanText(source.releaseArtifactFingerprint || source.release_artifact_fingerprint || source.artifactFingerprint || source.artifact_fingerprint, 240),
183
+ lastReleaseArtifactFingerprint: cleanText(source.lastReleaseArtifactFingerprint || source.last_release_artifact_fingerprint || source.lastArtifactFingerprint || source.last_artifact_fingerprint, 240),
184
+ forceDeployReason: cleanText(source.forceDeployReason || source.force_deploy_reason, 1000),
185
+ hotfixCannotResolveReason: cleanText(source.hotfixCannotResolveReason || source.hotfix_cannot_resolve_reason, 1000),
186
+ fullDeployRequested: source.fullDeployRequested === true || source.full_deploy_requested === true,
187
+ recordedAt: source.recordedAt || source.recorded_at
188
+ };
189
+ }
190
+ function matchingHotfixPlanStep(policy, channel) {
191
+ var _a;
192
+ return (((_a = policy === null || policy === void 0 ? void 0 : policy.hotfixPlan) === null || _a === void 0 ? void 0 : _a.steps) || []).find(function (step) { return step.channel === channel; });
193
+ }
194
+ function pushMissing(blockers, condition, message) {
195
+ if (!condition) {
196
+ blockers.push(message);
197
+ }
198
+ }
199
+ function validateResolveIOAIManagerHotfixEvidence(value, options) {
200
+ var _a, _b, _c, _d;
201
+ if (options === void 0) { options = {}; }
202
+ var normalized = normalizeResolveIOAIManagerHotfixEvidence(value, options.policy);
203
+ var policy = options.policy;
204
+ if (!normalized) {
205
+ return {
206
+ valid: false,
207
+ status: 'missing',
208
+ channel: '',
209
+ blockers: ['Hotfix evidence is missing or channel is unsupported.'],
210
+ warnings: [],
211
+ fullDeployAllowed: false,
212
+ fullDeployBlocked: true,
213
+ hotfixSatisfied: false,
214
+ requiredEvidence: ((_b = (_a = policy === null || policy === void 0 ? void 0 : policy.hotfixPlan) === null || _a === void 0 ? void 0 : _a.steps) === null || _b === void 0 ? void 0 : _b.flatMap(function (step) { return step.requiredEvidence; })) || [],
215
+ successEvidence: ((_d = (_c = policy === null || policy === void 0 ? void 0 : policy.hotfixPlan) === null || _c === void 0 ? void 0 : _c.steps) === null || _d === void 0 ? void 0 : _d.flatMap(function (step) { return step.successEvidence; })) || [],
216
+ policy: policy,
217
+ nextAction: 'record_hotfix_evidence'
218
+ };
219
+ }
220
+ var blockers = [];
221
+ var warnings = [];
222
+ var target = normalized.target || {};
223
+ var channel = normalized.channel;
224
+ var step = matchingHotfixPlanStep(policy, channel);
225
+ var requiredEvidence = (step === null || step === void 0 ? void 0 : step.requiredEvidence) || [];
226
+ var successEvidence = (step === null || step === void 0 ? void 0 : step.successEvidence) || [];
227
+ var policyAllowsFullDeploy = (policy === null || policy === void 0 ? void 0 : policy.fullDeployAllowed) === true;
228
+ var policyBlocksDuplicate = (policy === null || policy === void 0 ? void 0 : policy.duplicateDeployBlocked) === true || (policy === null || policy === void 0 ? void 0 : policy.duplicatePublishBlocked) === true;
229
+ if (normalized.fullDeployRequested && !policyAllowsFullDeploy && channel !== 'force_deploy_review' && channel !== 'new_artifact_deploy') {
230
+ blockers.push('Full deploy requested but hotfix-first policy does not allow a full deploy for this release state.');
231
+ }
232
+ if (normalized.fullDeployRequested && policyBlocksDuplicate && !normalized.forceDeployReason && channel !== 'force_deploy_review') {
233
+ blockers.push('Duplicate deploy/publish fingerprint requires force deploy/publish evidence before any full deploy.');
234
+ }
235
+ if (channel === 'backend_js') {
236
+ pushMissing(blockers, !!normalized.compiledArtifactPath, 'Backend JS hotfix requires compiledArtifactPath.');
237
+ pushMissing(blockers, !!target.host, 'Backend JS hotfix requires target.host.');
238
+ pushMissing(blockers, !!target.path, 'Backend JS hotfix requires target.path.');
239
+ pushMissing(blockers, !!(normalized.remoteChecksumAfter || normalized.remoteChecksum), 'Backend JS hotfix requires remote checksum after replacement.');
240
+ pushMissing(blockers, !!(normalized.restartEvidence || normalized.serviceRestartEvidence), 'Backend JS hotfix requires restart evidence.');
241
+ pushMissing(blockers, hotfixStatusPassed(normalized.healthCheckStatus), 'Backend JS hotfix requires passed healthCheckStatus.');
242
+ pushMissing(blockers, hotfixStatusPassed(normalized.selfTestStatus), 'Backend JS hotfix requires passed selfTestStatus.');
243
+ if (normalized.remoteChecksumBefore && normalized.remoteChecksumAfter && normalized.remoteChecksumBefore === normalized.remoteChecksumAfter) {
244
+ blockers.push('Backend JS hotfix checksum did not change; record force/no-op evidence or do not claim a hotfix.');
245
+ }
246
+ }
247
+ else if (channel === 'static_ui') {
248
+ pushMissing(blockers, !!normalized.builtDistPath, 'Static UI hotfix requires builtDistPath.');
249
+ pushMissing(blockers, !!target.bucket, 'Static UI hotfix requires target.bucket.');
250
+ pushMissing(blockers, !!target.distributionId, 'Static UI hotfix requires target.distributionId.');
251
+ pushMissing(blockers, !!normalized.s3UploadResult, 'Static UI hotfix requires s3UploadResult.');
252
+ pushMissing(blockers, !!normalized.cloudfrontInvalidationId, 'Static UI hotfix requires cloudfrontInvalidationId.');
253
+ pushMissing(blockers, !!normalized.publicProof, 'Static UI hotfix requires publicProof.');
254
+ }
255
+ else if (channel === 'config') {
256
+ pushMissing(blockers, !!target.configKey, 'Config hotfix requires target.configKey.');
257
+ pushMissing(blockers, !!normalized.configChangeEvidence, 'Config hotfix requires configChangeEvidence.');
258
+ pushMissing(blockers, hotfixStatusPassed(normalized.releaseGateStatus), 'Config hotfix requires passed releaseGateStatus.');
259
+ }
260
+ else if (channel === 'seed_data') {
261
+ pushMissing(blockers, !!target.seedKey, 'Seed-data hotfix requires target.seedKey.');
262
+ pushMissing(blockers, !!normalized.seedDataEvidence, 'Seed-data hotfix requires seedDataEvidence.');
263
+ pushMissing(blockers, hotfixStatusPassed(normalized.releaseGateStatus), 'Seed-data hotfix requires passed releaseGateStatus.');
264
+ }
265
+ else if (channel === 'cache_invalidation') {
266
+ pushMissing(blockers, !!target.cacheKey, 'Cache invalidation hotfix requires target.cacheKey.');
267
+ pushMissing(blockers, !!normalized.cacheInvalidationEvidence, 'Cache invalidation hotfix requires cacheInvalidationEvidence.');
268
+ pushMissing(blockers, hotfixStatusPassed(normalized.releaseGateStatus) || hotfixStatusPassed(normalized.healthCheckStatus), 'Cache invalidation hotfix requires passed releaseGateStatus or healthCheckStatus.');
269
+ }
270
+ else if (channel === 'service_restart') {
271
+ pushMissing(blockers, !!target.processName, 'Service restart hotfix requires target.processName.');
272
+ pushMissing(blockers, !!(normalized.serviceRestartEvidence || normalized.restartEvidence), 'Service restart hotfix requires restart evidence.');
273
+ pushMissing(blockers, hotfixStatusPassed(normalized.healthCheckStatus), 'Service restart hotfix requires passed healthCheckStatus.');
274
+ pushMissing(blockers, hotfixStatusPassed(normalized.selfTestStatus), 'Service restart hotfix requires passed selfTestStatus.');
275
+ }
276
+ else if (channel === 'release_artifact') {
277
+ pushMissing(blockers, !!normalized.releaseArtifactFingerprint, 'Release artifact hotfix requires releaseArtifactFingerprint.');
278
+ pushMissing(blockers, hotfixStatusPassed(normalized.releaseGateStatus), 'Release artifact hotfix requires passed releaseGateStatus.');
279
+ }
280
+ else if (channel === 'force_deploy_review') {
281
+ pushMissing(blockers, !!normalized.forceDeployReason, 'Force deploy review requires forceDeployReason.');
282
+ pushMissing(blockers, !!normalized.hotfixCannotResolveReason, 'Force deploy review requires hotfixCannotResolveReason.');
283
+ }
284
+ else if (channel === 'new_artifact_deploy') {
285
+ pushMissing(blockers, !!normalized.releaseArtifactFingerprint, 'New artifact deploy requires releaseArtifactFingerprint.');
286
+ pushMissing(blockers, !!normalized.lastReleaseArtifactFingerprint, 'New artifact deploy requires lastReleaseArtifactFingerprint.');
287
+ if (normalized.releaseArtifactFingerprint && normalized.lastReleaseArtifactFingerprint && normalized.releaseArtifactFingerprint === normalized.lastReleaseArtifactFingerprint) {
288
+ blockers.push('New artifact deploy requires a fingerprint different from the last deployed artifact.');
289
+ }
290
+ pushMissing(blockers, hotfixStatusPassed(normalized.releaseGateStatus), 'New artifact deploy requires passed releaseGateStatus.');
291
+ }
292
+ else if (channel === 'artifact_build') {
293
+ pushMissing(blockers, !!normalized.releaseArtifactFingerprint, 'Artifact build requires releaseArtifactFingerprint.');
294
+ if (normalized.fullDeployRequested) {
295
+ blockers.push('Artifact build evidence cannot request a full deploy in the same step.');
296
+ }
297
+ }
298
+ if (!step && policy) {
299
+ warnings.push("Hotfix channel ".concat(channel, " is not the recommended channel in the current release policy."));
300
+ }
301
+ var forceDeployReviewValid = channel === 'force_deploy_review' && blockers.length === 0;
302
+ var newArtifactDeployValid = channel === 'new_artifact_deploy' && blockers.length === 0;
303
+ var fullDeployAllowed = forceDeployReviewValid || newArtifactDeployValid || (policyAllowsFullDeploy && blockers.length === 0 && normalized.fullDeployRequested === true);
304
+ var hotfixSatisfied = blockers.length === 0 && !fullDeployAllowed;
305
+ var status = blockers.length
306
+ ? (normalizeHotfixStatus(normalized.status) === 'blocked' ? 'blocked' : 'incomplete')
307
+ : 'passed';
308
+ var fullDeployBlocked = !fullDeployAllowed && (normalized.fullDeployRequested === true || (policy === null || policy === void 0 ? void 0 : policy.fullDeployAllowed) !== true);
309
+ var nextAction = blockers.some(function (blocker) { return /force deploy/i.test(blocker); })
310
+ ? 'request_force_deploy_reason'
311
+ : fullDeployAllowed
312
+ ? 'allow_one_full_deploy'
313
+ : hotfixSatisfied
314
+ ? 'rerun_release_gate'
315
+ : blockers.length
316
+ ? 'record_hotfix_evidence'
317
+ : 'park_manual';
318
+ normalized.status = status;
319
+ return {
320
+ valid: blockers.length === 0,
321
+ status: status,
322
+ channel: channel,
323
+ blockers: blockers,
324
+ warnings: warnings,
325
+ fullDeployAllowed: fullDeployAllowed,
326
+ fullDeployBlocked: fullDeployBlocked,
327
+ hotfixSatisfied: hotfixSatisfied,
328
+ requiredEvidence: requiredEvidence,
329
+ successEvidence: successEvidence,
330
+ normalized: normalized,
331
+ policy: policy,
332
+ nextAction: nextAction
333
+ };
334
+ }
99
335
  function releaseStatusIsBlocked(value) {
100
336
  return /fail|error|blocked|missing|empty|not ready|not_ready|denied|invalid|timeout|stale/i.test(value);
101
337
  }