velocious 1.0.575 → 1.0.577
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 +46 -1
- package/build/background-jobs/main.js +13 -2
- package/build/background-jobs/scheduler.js +11 -7
- package/build/background-jobs/store.js +18 -13
- package/build/environment-handlers/node/cli/commands/test.js +2 -0
- package/build/environment-handlers/node/source-peer-package.js +172 -0
- package/build/routes/resolver.js +3 -50
- package/build/src/background-jobs/main.d.ts.map +1 -1
- package/build/src/background-jobs/main.js +13 -3
- package/build/src/background-jobs/scheduler.d.ts +2 -2
- package/build/src/background-jobs/scheduler.d.ts.map +1 -1
- package/build/src/background-jobs/scheduler.js +11 -8
- package/build/src/background-jobs/store.d.ts +5 -4
- package/build/src/background-jobs/store.d.ts.map +1 -1
- package/build/src/background-jobs/store.js +17 -12
- package/build/src/environment-handlers/node/cli/commands/test.d.ts.map +1 -1
- package/build/src/environment-handlers/node/cli/commands/test.js +3 -1
- package/build/src/environment-handlers/node/source-peer-package.d.ts +46 -0
- package/build/src/environment-handlers/node/source-peer-package.d.ts.map +1 -0
- package/build/src/environment-handlers/node/source-peer-package.js +148 -0
- package/build/src/routes/resolver.d.ts.map +1 -1
- package/build/src/routes/resolver.js +4 -45
- package/build/src/sync/sync-envelope-replay-service.d.ts.map +1 -1
- package/build/src/sync/sync-envelope-replay-service.js +9 -2
- package/build/sync/sync-envelope-replay-service.js +10 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -1
- package/scripts/run-tests.js +61 -20
- package/scripts/test-browser.js +6 -1
- package/src/background-jobs/main.js +13 -2
- package/src/background-jobs/scheduler.js +11 -7
- package/src/background-jobs/store.js +18 -13
- package/src/environment-handlers/node/cli/commands/test.js +2 -0
- package/src/environment-handlers/node/source-peer-package.js +172 -0
- package/src/routes/resolver.js +3 -50
- package/src/sync/sync-envelope-replay-service.js +10 -1
- package/build/deployment-api/controller.js +0 -437
- package/build/deployment-api/index.js +0 -210
- package/build/deployment-api/path-matcher.js +0 -45
- package/build/deployment-api/registry.js +0 -84
- package/build/deployment-api/run-store.js +0 -798
- package/build/deployment-api/sanitize.js +0 -114
- package/build/src/deployment-api/controller.d.ts +0 -117
- package/build/src/deployment-api/controller.d.ts.map +0 -1
- package/build/src/deployment-api/controller.js +0 -384
- package/build/src/deployment-api/index.d.ts +0 -46
- package/build/src/deployment-api/index.d.ts.map +0 -1
- package/build/src/deployment-api/index.js +0 -178
- package/build/src/deployment-api/path-matcher.d.ts +0 -31
- package/build/src/deployment-api/path-matcher.d.ts.map +0 -1
- package/build/src/deployment-api/path-matcher.js +0 -39
- package/build/src/deployment-api/registry.d.ts +0 -106
- package/build/src/deployment-api/registry.d.ts.map +0 -1
- package/build/src/deployment-api/registry.js +0 -74
- package/build/src/deployment-api/run-store.d.ts +0 -402
- package/build/src/deployment-api/run-store.d.ts.map +0 -1
- package/build/src/deployment-api/run-store.js +0 -711
- package/build/src/deployment-api/sanitize.d.ts +0 -27
- package/build/src/deployment-api/sanitize.d.ts.map +0 -1
- package/build/src/deployment-api/sanitize.js +0 -100
- package/src/deployment-api/controller.js +0 -437
- package/src/deployment-api/index.js +0 -210
- package/src/deployment-api/path-matcher.js +0 -45
- package/src/deployment-api/registry.js +0 -84
- package/src/deployment-api/run-store.js +0 -798
- package/src/deployment-api/sanitize.js +0 -114
|
@@ -1,384 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
import Controller from "../controller.js";
|
|
3
|
-
import DeploymentRunStore, { registerActiveDeploymentRun, unregisterActiveDeploymentRun } from "./run-store.js";
|
|
4
|
-
import { bearerToken, constantTimeEqual } from "../utils/bearer-token.js";
|
|
5
|
-
import { getDeploymentMount } from "./registry.js";
|
|
6
|
-
import { sanitizeAdapterValue, sanitizeErrorPayload } from "./sanitize.js";
|
|
7
|
-
const REVISION_PATTERN = /^[0-9a-f]{40}$/;
|
|
8
|
-
const MAX_IDEMPOTENCY_KEY_LENGTH = 255;
|
|
9
|
-
/**
|
|
10
|
-
* Resolves allowlisted stage options with own-property checks only, so
|
|
11
|
-
* request-controlled names like "__proto__" or "constructor" can never
|
|
12
|
-
* resolve inherited values. The normalized maps are also null-prototype, so
|
|
13
|
-
* this is defense in depth.
|
|
14
|
-
* @param {import("./registry.js").DeploymentMountOptions} options - Mount options.
|
|
15
|
-
* @param {string} project - Requested project identifier.
|
|
16
|
-
* @param {string} stage - Requested stage identifier.
|
|
17
|
-
* @returns {import("./registry.js").DeploymentStageOptions | undefined} - Stage options when allowlisted.
|
|
18
|
-
*/
|
|
19
|
-
function lookupStageOptions(options, project, stage) {
|
|
20
|
-
if (!Object.hasOwn(options.projects, project))
|
|
21
|
-
return undefined;
|
|
22
|
-
const stages = options.projects[project].stages;
|
|
23
|
-
if (!Object.hasOwn(stages, stage))
|
|
24
|
-
return undefined;
|
|
25
|
-
return stages[stage];
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Authenticated HTTP API for callable deployments. Mounted by
|
|
29
|
-
* {@link import("./index.js").default} as a route-resolver hook so it can ship
|
|
30
|
-
* inside the velocious package. Every action is gated by a bearer-token check
|
|
31
|
-
* against the configured access tokens; the API exposes only allowlisted
|
|
32
|
-
* project/stage pairs and full immutable revisions, and delegates all
|
|
33
|
-
* execution to the configured adapter. It never accepts commands, paths,
|
|
34
|
-
* arbitrary refs, environment variables, or raw log output.
|
|
35
|
-
*/
|
|
36
|
-
export default class VelociousDeploymentApiController extends Controller {
|
|
37
|
-
/**
|
|
38
|
-
* Runs mount options.
|
|
39
|
-
* @returns {import("./registry.js").DeploymentMountOptions} - Options for the mount that matched this request.
|
|
40
|
-
*/
|
|
41
|
-
_mountOptions() {
|
|
42
|
-
const at = /** @type {string} */ (this.params().velociousDeploymentMountAt);
|
|
43
|
-
const options = getDeploymentMount(this.getConfiguration(), at);
|
|
44
|
-
if (!options)
|
|
45
|
-
throw new Error(`No deployment API mount registered at ${at}`);
|
|
46
|
-
return options;
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Runs store.
|
|
50
|
-
* @returns {DeploymentRunStore} - Run store scoped to the mount's database.
|
|
51
|
-
*/
|
|
52
|
-
_store() {
|
|
53
|
-
if (!this._deploymentRunStore) {
|
|
54
|
-
this._deploymentRunStore = new DeploymentRunStore({
|
|
55
|
-
configuration: this.getConfiguration(),
|
|
56
|
-
databaseIdentifier: this._mountOptions().databaseIdentifier,
|
|
57
|
-
mountIdentifier: this._mountOptions().mountIdentifier,
|
|
58
|
-
staleRunTimeoutMs: this._mountOptions().staleRunTimeoutMs
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
return this._deploymentRunStore;
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Reports one internally consumed framework failure on both documented
|
|
65
|
-
* error channels so framework-specific and unified reporters see the same
|
|
66
|
-
* payload.
|
|
67
|
-
* @param {object} args - Options.
|
|
68
|
-
* @param {string} args.context - Deployment API failure context.
|
|
69
|
-
* @param {?} args.error - Consumed error.
|
|
70
|
-
* @returns {void} - No return value.
|
|
71
|
-
*/
|
|
72
|
-
_emitFrameworkError({ context, error }) {
|
|
73
|
-
const errorEvents = this.getConfiguration().getErrorEvents();
|
|
74
|
-
const payload = { context, error, request: this.getRequest() };
|
|
75
|
-
errorEvents.emit("framework-error", payload);
|
|
76
|
-
errorEvents.emit("all-error", { ...payload, errorType: "framework-error" });
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Authorizes the request with a constant-time bearer-token comparison and
|
|
80
|
-
* runs the action body only when authorized. Renders a 401 otherwise. The
|
|
81
|
-
* base controller has no before-action halting, so authorization is enforced
|
|
82
|
-
* here per action. Tokens are only accepted through the Authorization header
|
|
83
|
-
* — never through URLs — and are never rendered back.
|
|
84
|
-
* @param {() => Promise<void>} actionFn - Action body.
|
|
85
|
-
* @returns {Promise<void>} - Resolves when complete.
|
|
86
|
-
*/
|
|
87
|
-
async _respond(actionFn) {
|
|
88
|
-
const token = bearerToken(this.request());
|
|
89
|
-
let authorized = false;
|
|
90
|
-
if (token) {
|
|
91
|
-
for (const accessToken of this._mountOptions().accessTokens) {
|
|
92
|
-
if (constantTimeEqual(token, accessToken)) {
|
|
93
|
-
authorized = true;
|
|
94
|
-
break;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
if (!authorized) {
|
|
99
|
-
await this.render({ json: { error: "unauthorized" }, status: 401 });
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
await actionFn();
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Creates a deployment run for an allowlisted project/stage and a full
|
|
106
|
-
* immutable revision reachable from the approved release branch. Idempotent:
|
|
107
|
-
* a retried idempotency key reads the original run, a reused key with a
|
|
108
|
-
* different payload conflicts, and an active run for the same project/stage
|
|
109
|
-
* returns a bounded conflict.
|
|
110
|
-
* @returns {Promise<void>} - Resolves when complete.
|
|
111
|
-
*/
|
|
112
|
-
async create() {
|
|
113
|
-
await this._respond(async () => {
|
|
114
|
-
const params = this.params();
|
|
115
|
-
const revision = typeof params.revision === "string" ? params.revision : null;
|
|
116
|
-
const idempotencyKey = typeof params.idempotencyKey === "string" ? params.idempotencyKey : null;
|
|
117
|
-
const invalidFields = [];
|
|
118
|
-
if (!revision || !REVISION_PATTERN.test(revision))
|
|
119
|
-
invalidFields.push("revision");
|
|
120
|
-
if (!idempotencyKey || idempotencyKey.length === 0 || idempotencyKey.length > MAX_IDEMPOTENCY_KEY_LENGTH) {
|
|
121
|
-
invalidFields.push("idempotencyKey");
|
|
122
|
-
}
|
|
123
|
-
if (invalidFields.length > 0) {
|
|
124
|
-
await this.render({ json: { error: "invalid_params", fields: invalidFields }, status: 422 });
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
const options = this._mountOptions();
|
|
128
|
-
const project = typeof params.project === "string" ? params.project : "";
|
|
129
|
-
const stage = typeof params.stage === "string" ? params.stage : "";
|
|
130
|
-
const stageOptions = lookupStageOptions(options, project, stage);
|
|
131
|
-
if (!stageOptions) {
|
|
132
|
-
await this.render({ json: { error: "not_found" }, status: 404 });
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
const store = this._store();
|
|
136
|
-
const validRevision = /** @type {string} */ (revision);
|
|
137
|
-
const validIdempotencyKey = /** @type {string} */ (idempotencyKey);
|
|
138
|
-
// Retries read the original run before anything else — a replay must
|
|
139
|
-
// never re-validate or re-deploy.
|
|
140
|
-
const existingRun = await store.findRunByKey(validIdempotencyKey);
|
|
141
|
-
if (existingRun) {
|
|
142
|
-
await this._renderExistingRun({ existingRun, project, revision: validRevision, stage });
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
const reachable = await options.adapter.validateRevision({
|
|
146
|
-
configuration: this.getConfiguration(),
|
|
147
|
-
project,
|
|
148
|
-
releaseBranch: stageOptions.releaseBranch,
|
|
149
|
-
revision: validRevision,
|
|
150
|
-
stage
|
|
151
|
-
});
|
|
152
|
-
if (!reachable) {
|
|
153
|
-
await this.render({ json: { error: "revision_not_reachable" }, status: 422 });
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
const outcome = await store.createRunIfPossible({
|
|
157
|
-
idempotencyKey: validIdempotencyKey,
|
|
158
|
-
project,
|
|
159
|
-
revision: validRevision,
|
|
160
|
-
stage
|
|
161
|
-
});
|
|
162
|
-
if (outcome.outcome === "replay" || outcome.outcome === "conflict") {
|
|
163
|
-
const existingFromStore = outcome.run;
|
|
164
|
-
if (!existingFromStore)
|
|
165
|
-
throw new Error(`Deployment run store reported '${outcome.outcome}' without a run`);
|
|
166
|
-
await this._renderExistingRun({ existingRun: existingFromStore, project, revision: validRevision, stage });
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
if (outcome.outcome === "in_progress") {
|
|
170
|
-
const activeRun = outcome.run;
|
|
171
|
-
await this.render({ json: { error: "deployment_in_progress", runId: activeRun ? activeRun.id : undefined }, status: 409 });
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
if (outcome.outcome === "reconciliation_required") {
|
|
175
|
-
const blockedRun = outcome.run;
|
|
176
|
-
if (!blockedRun)
|
|
177
|
-
throw new Error("Deployment run store reported 'reconciliation_required' without a run");
|
|
178
|
-
await this.render({ json: { error: "deployment_reconciliation_required", runId: blockedRun.id }, status: 409 });
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
const run = outcome.run;
|
|
182
|
-
if (!run)
|
|
183
|
-
throw new Error("Deployment run store reported 'created' without a run");
|
|
184
|
-
await this._audit({ event: "run_requested", payload: { project, revision: validRevision, stage }, runId: run.id });
|
|
185
|
-
// Execution is deliberately not awaited: the deploy runs under the
|
|
186
|
-
// integration's own lock/build/health/rollback semantics and the caller
|
|
187
|
-
// reads progress back through the show action.
|
|
188
|
-
this._executeRun({ options, run }).catch((error) => {
|
|
189
|
-
this._emitFrameworkError({ context: "deployment-api-execute-run", error });
|
|
190
|
-
});
|
|
191
|
-
await this.render({ json: { run: this._serializeRun(run) }, status: 202 });
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Renders a previously created run for an idempotency-key hit: a replay when
|
|
196
|
-
* the payload matches, a bounded conflict when it doesn't.
|
|
197
|
-
* @param {object} args - Options.
|
|
198
|
-
* @param {import("./run-store.js").DeploymentRunRow} args.existingRun - The stored run.
|
|
199
|
-
* @param {string} args.project - Requested project.
|
|
200
|
-
* @param {string} args.revision - Requested revision.
|
|
201
|
-
* @param {string} args.stage - Requested stage.
|
|
202
|
-
* @returns {Promise<void>} - Resolves when complete.
|
|
203
|
-
*/
|
|
204
|
-
async _renderExistingRun({ existingRun, project, revision, stage }) {
|
|
205
|
-
const samePayload = existingRun.project === project && existingRun.stage === stage && existingRun.revision === revision;
|
|
206
|
-
if (!samePayload) {
|
|
207
|
-
await this.render({ json: { error: "idempotency_conflict", runId: existingRun.id }, status: 409 });
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
await this.render({ json: { replayed: true, run: this._serializeRun(existingRun) }, status: 200 });
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
|
-
* Returns the bounded state of a single run, enriched with the adapter's
|
|
214
|
-
* live status when the integration provides one.
|
|
215
|
-
* @returns {Promise<void>} - Resolves when complete.
|
|
216
|
-
*/
|
|
217
|
-
async show() {
|
|
218
|
-
await this._respond(async () => {
|
|
219
|
-
const run = await this._store().findRunById(/** @type {string} */ (this.params().id));
|
|
220
|
-
if (!run) {
|
|
221
|
-
await this.render({ json: { error: "not_found" }, status: 404 });
|
|
222
|
-
return;
|
|
223
|
-
}
|
|
224
|
-
const options = this._mountOptions();
|
|
225
|
-
/** @type {Record<string, ?>} */
|
|
226
|
-
const body = { run: this._serializeRun(run) };
|
|
227
|
-
if (options.adapter.readStatus) {
|
|
228
|
-
const liveStatus = await options.adapter.readStatus({
|
|
229
|
-
configuration: this.getConfiguration(),
|
|
230
|
-
project: run.project,
|
|
231
|
-
stage: run.stage
|
|
232
|
-
});
|
|
233
|
-
body.current = sanitizeAdapterValue(liveStatus, options.accessTokens) ?? null;
|
|
234
|
-
}
|
|
235
|
-
await this.render({ json: body, status: 200 });
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
/**
|
|
239
|
-
* Executes a created run asynchronously: registers it as active in this
|
|
240
|
-
* process, marks it running, heartbeats its ownership lease while the
|
|
241
|
-
* adapter deploys, and records the sanitized outcome. A deployment failure
|
|
242
|
-
* is an expected operational result — it is persisted with its sanitized
|
|
243
|
-
* recovery information instead of being raised, so it stays visible through
|
|
244
|
-
* readback and audit rather than crashing the worker.
|
|
245
|
-
* @param {object} args - Options.
|
|
246
|
-
* @param {import("./registry.js").DeploymentMountOptions} args.options - Mount options.
|
|
247
|
-
* @param {import("./run-store.js").DeploymentRunRow} args.run - The created run.
|
|
248
|
-
* @returns {Promise<void>} - Resolves when the outcome is recorded.
|
|
249
|
-
*/
|
|
250
|
-
async _executeRun({ options, run }) {
|
|
251
|
-
const store = this._store();
|
|
252
|
-
const secrets = options.accessTokens;
|
|
253
|
-
const stageOptions = lookupStageOptions(options, run.project, run.stage);
|
|
254
|
-
if (!stageOptions)
|
|
255
|
-
throw new Error(`Deployment run ${run.id} references non-allowlisted ${run.project}/${run.stage}`);
|
|
256
|
-
if (!run.ownerToken)
|
|
257
|
-
throw new Error(`Deployment run ${run.id} has no execution owner token`);
|
|
258
|
-
const ownerToken = run.ownerToken;
|
|
259
|
-
registerActiveDeploymentRun(run.id);
|
|
260
|
-
/** @type {ReturnType<typeof setInterval> | null} */
|
|
261
|
-
let heartbeatTimer = null;
|
|
262
|
-
try {
|
|
263
|
-
await store.markRunning({ id: run.id, startedAtMs: Date.now() });
|
|
264
|
-
// Renew the ownership lease while the deploy runs so reconciliation
|
|
265
|
-
// never reclaims this genuinely active run; unref'd so the timer alone
|
|
266
|
-
// keeps no process alive.
|
|
267
|
-
const heartbeatIntervalMs = Math.max(1000, Math.floor(options.staleRunTimeoutMs / 4));
|
|
268
|
-
heartbeatTimer = setInterval(() => {
|
|
269
|
-
store.heartbeat({ heartbeatAtMs: Date.now(), id: run.id }).catch((error) => {
|
|
270
|
-
this._emitFrameworkError({ context: "deployment-api-heartbeat", error });
|
|
271
|
-
});
|
|
272
|
-
}, heartbeatIntervalMs);
|
|
273
|
-
heartbeatTimer.unref();
|
|
274
|
-
await this._audit({ event: "run_started", payload: { project: run.project, revision: run.revision, stage: run.stage }, runId: run.id });
|
|
275
|
-
let report;
|
|
276
|
-
try {
|
|
277
|
-
report = await options.adapter.deploy({
|
|
278
|
-
configuration: this.getConfiguration(),
|
|
279
|
-
project: run.project,
|
|
280
|
-
releaseBranch: stageOptions.releaseBranch,
|
|
281
|
-
revision: run.revision,
|
|
282
|
-
runId: run.id,
|
|
283
|
-
stage: run.stage
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
catch (error) {
|
|
287
|
-
const errorPayload = sanitizeErrorPayload(error, secrets);
|
|
288
|
-
try {
|
|
289
|
-
await store.markFailed({ error: errorPayload, finishedAtMs: Date.now(), id: run.id, ownerToken });
|
|
290
|
-
await this._audit({
|
|
291
|
-
event: "run_failed",
|
|
292
|
-
payload: { message: errorPayload.message, project: run.project, revision: run.revision, stage: run.stage },
|
|
293
|
-
runId: run.id
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
catch (storeError) {
|
|
297
|
-
// Recording the failure itself failed — that is an unexpected bug
|
|
298
|
-
// and must surface to process-level error reporters.
|
|
299
|
-
this._emitFrameworkError({ context: "deployment-api-record-failure", error: storeError });
|
|
300
|
-
}
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
try {
|
|
304
|
-
const result = sanitizeAdapterValue(report ?? {}, secrets) ?? {};
|
|
305
|
-
await store.markSucceeded({ finishedAtMs: Date.now(), id: run.id, ownerToken, result });
|
|
306
|
-
await this._audit({ event: "run_succeeded", payload: { project: run.project, revision: run.revision, stage: run.stage }, runId: run.id });
|
|
307
|
-
}
|
|
308
|
-
catch (error) {
|
|
309
|
-
// The adapter already returned success. Surface the recording error,
|
|
310
|
-
// then fence the run in a durable non-retryable state rather than
|
|
311
|
-
// falsely recording an external success as a deployment failure.
|
|
312
|
-
this._emitFrameworkError({ context: "deployment-api-record-success", error });
|
|
313
|
-
const reconciliationError = {
|
|
314
|
-
message: "Deployment activation succeeded, but its result could not be persisted; operator reconciliation is required"
|
|
315
|
-
};
|
|
316
|
-
try {
|
|
317
|
-
await store.markReconciliationRequired({
|
|
318
|
-
error: reconciliationError,
|
|
319
|
-
finishedAtMs: Date.now(),
|
|
320
|
-
id: run.id,
|
|
321
|
-
ownerToken
|
|
322
|
-
});
|
|
323
|
-
await this._audit({
|
|
324
|
-
event: "run_reconciliation_required",
|
|
325
|
-
payload: { message: reconciliationError.message, project: run.project, revision: run.revision, stage: run.stage },
|
|
326
|
-
runId: run.id
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
catch (reconciliationErrorPersistenceError) {
|
|
330
|
-
this._emitFrameworkError({
|
|
331
|
-
context: "deployment-api-record-reconciliation-required",
|
|
332
|
-
error: reconciliationErrorPersistenceError
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
finally {
|
|
338
|
-
if (heartbeatTimer)
|
|
339
|
-
clearInterval(heartbeatTimer);
|
|
340
|
-
unregisterActiveDeploymentRun(run.id);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
/**
|
|
344
|
-
* Records a sanitized audit event. Audit persistence must never strand or
|
|
345
|
-
* suppress a deployment, so a failure here is reported on the
|
|
346
|
-
* framework-error and unified all-error channels (where process-level bug
|
|
347
|
-
* reporters capture it), and execution continues.
|
|
348
|
-
* @param {object} args - Options.
|
|
349
|
-
* @param {string} args.event - Event name.
|
|
350
|
-
* @param {Record<string, ?>} args.payload - Payload; sanitized and redacted before persistence.
|
|
351
|
-
* @param {string | null} args.runId - Owning run id.
|
|
352
|
-
* @returns {Promise<void>} - Resolves when recorded or reported.
|
|
353
|
-
*/
|
|
354
|
-
async _audit({ event, payload, runId }) {
|
|
355
|
-
const sanitized = sanitizeAdapterValue(payload, this._mountOptions().accessTokens) ?? {};
|
|
356
|
-
try {
|
|
357
|
-
await this._store().addAuditEvent({ event, payload: sanitized, runId });
|
|
358
|
-
}
|
|
359
|
-
catch (error) {
|
|
360
|
-
this._emitFrameworkError({ context: "deployment-api-audit", error });
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
/**
|
|
364
|
-
* Serializes a run for the API.
|
|
365
|
-
* @param {import("./run-store.js").DeploymentRunRow} run - Run row.
|
|
366
|
-
* @returns {Record<string, ?>} - Serialized run.
|
|
367
|
-
*/
|
|
368
|
-
_serializeRun(run) {
|
|
369
|
-
return {
|
|
370
|
-
error: run.error,
|
|
371
|
-
finishedAtMs: run.finishedAtMs,
|
|
372
|
-
id: run.id,
|
|
373
|
-
idempotencyKey: run.idempotencyKey,
|
|
374
|
-
project: run.project,
|
|
375
|
-
requestedAtMs: run.requestedAtMs,
|
|
376
|
-
result: run.result,
|
|
377
|
-
revision: run.revision,
|
|
378
|
-
stage: run.stage,
|
|
379
|
-
startedAtMs: run.startedAtMs,
|
|
380
|
-
status: run.status
|
|
381
|
-
};
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udHJvbGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9kZXBsb3ltZW50LWFwaS9jb250cm9sbGVyLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWixPQUFPLFVBQVUsTUFBTSxrQkFBa0IsQ0FBQTtBQUN6QyxPQUFPLGtCQUFrQixFQUFFLEVBQUMsMkJBQTJCLEVBQUUsNkJBQTZCLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQTtBQUM3RyxPQUFPLEVBQUMsV0FBVyxFQUFFLGlCQUFpQixFQUFDLE1BQU0sMEJBQTBCLENBQUE7QUFDdkUsT0FBTyxFQUFDLGtCQUFrQixFQUFDLE1BQU0sZUFBZSxDQUFBO0FBQ2hELE9BQU8sRUFBQyxvQkFBb0IsRUFBRSxvQkFBb0IsRUFBQyxNQUFNLGVBQWUsQ0FBQTtBQUV4RSxNQUFNLGdCQUFnQixHQUFHLGdCQUFnQixDQUFBO0FBQ3pDLE1BQU0sMEJBQTBCLEdBQUcsR0FBRyxDQUFBO0FBRXRDOzs7Ozs7Ozs7R0FTRztBQUNILFNBQVMsa0JBQWtCLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxLQUFLO0lBQ2pELElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUsT0FBTyxDQUFDO1FBQUUsT0FBTyxTQUFTLENBQUE7SUFFL0QsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxNQUFNLENBQUE7SUFFL0MsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLEtBQUssQ0FBQztRQUFFLE9BQU8sU0FBUyxDQUFBO0lBRW5ELE9BQU8sTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFBO0FBQ3RCLENBQUM7QUFFRDs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sQ0FBQyxPQUFPLE9BQU8sZ0NBQWlDLFNBQVEsVUFBVTtJQUN0RTs7O09BR0c7SUFDSCxhQUFhO1FBQ1gsTUFBTSxFQUFF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QUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixJQUFJLENBQUMsbUJBQW1CLENBQUMsRUFBQyxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsS0FBSyxFQUFDLENBQUMsQ0FBQTtRQUNwRSxDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxhQUFhLENBQUMsR0FBRztRQUNmLE9BQU87WUFDTCxLQUFLLEVBQUUsR0FBRyxDQUFDLEtBQUs7WUFDaEIsWUFBWSxFQUFFLEdBQUcsQ0FBQyxZQUFZO1lBQzlCLEVBQUUsRUFBRSxHQUFHLENBQUMsRUFBRTtZQUNWLGNBQWMsRUFBRSxHQUFHLENBQUMsY0FBYztZQUNsQyxPQUFPLEVBQUUsR0FBRyxDQUFDLE9BQU87WUFDcEIsYUFBYSxFQUFFLEdBQUcsQ0FBQyxhQUFhO1lBQ2hDLE1BQU0sRUFBRSxHQUFHLENBQUMsTUFBTTtZQUNsQixRQUFRLEVBQUUsR0FBRyxDQUFDLFFBQVE7WUFDdEIsS0FBSyxFQUFFLEdBQUcsQ0FBQyxLQUFLO1lBQ2hCLFdBQVcsRUFBRSxHQUFHLENBQUMsV0FBVztZQUM1QixNQUFNLEVBQUUsR0FBRyxDQUFDLE1BQU07U0FDbkIsQ0FBQTtJQUNILENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG5pbXBvcnQgQ29udHJvbGxlciBmcm9tIFwiLi4vY29udHJvbGxlci5qc1wiXG5pbXBvcnQgRGVwbG95bWVudFJ1blN0b3JlLCB7cmVnaXN0ZXJBY3RpdmVEZXBsb3ltZW50UnVuLCB1bnJlZ2lzdGVyQWN0aXZlRGVwbG95bWVudFJ1bn0gZnJvbSBcIi4vcnVuLXN0b3JlLmpzXCJcbmltcG9ydCB7YmVhcmVyVG9rZW4sIGNvbnN0YW50VGltZUVxdWFsfSBmcm9tIFwiLi4vdXRpbHMvYmVhcmVyLXRva2VuLmpzXCJcbmltcG9ydCB7Z2V0RGVwbG95bWVudE1vdW50fSBmcm9tIFwiLi9yZWdpc3RyeS5qc1wiXG5pbXBvcnQge3Nhbml0aXplQWRhcHRlclZhbHVlLCBzYW5pdGl6ZUVycm9yUGF5bG9hZH0gZnJvbSBcIi4vc2FuaXRpemUuanNcIlxuXG5jb25zdCBSRVZJU0lPTl9QQVRURVJOID0gL15bMC05YS1mXXs0MH0kL1xuY29uc3QgTUFYX0lERU1QT1RFTkNZX0tFWV9MRU5HVEggPSAyNTVcblxuLyoqXG4gKiBSZXNvbHZlcyBhbGxvd2xpc3RlZCBzdGFnZSBvcHRpb25zIHdpdGggb3duLXByb3BlcnR5IGNoZWNrcyBvbmx5LCBzb1xuICogcmVxdWVzdC1jb250cm9sbGVkIG5hbWVzIGxpa2UgXCJfX3Byb3RvX19cIiBvciBcImNvbnN0cnVjdG9yXCIgY2FuIG5ldmVyXG4gKiByZXNvbHZlIGluaGVyaXRlZCB2YWx1ZXMuIFRoZSBub3JtYWxpemVkIG1hcHMgYXJlIGFsc28gbnVsbC1wcm90b3R5cGUsIHNvXG4gKiB0aGlzIGlzIGRlZmVuc2UgaW4gZGVwdGguXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4vcmVnaXN0cnkuanNcIikuRGVwbG95bWVudE1vdW50T3B0aW9uc30gb3B0aW9ucyAtIE1vdW50IG9wdGlvbnMuXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvamVjdCAtIFJlcXVlc3RlZCBwcm9qZWN0IGlkZW50aWZpZXIuXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RhZ2UgLSBSZXF1ZXN0ZWQgc3RhZ2UgaWRlbnRpZmllci5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuL3JlZ2lzdHJ5LmpzXCIpLkRlcGxveW1lbnRTdGFnZU9wdGlvbnMgfCB1bmRlZmluZWR9IC0gU3RhZ2Ugb3B0aW9ucyB3aGVuIGFsbG93bGlzdGVkLlxuICovXG5mdW5jdGlvbiBsb29rdXBTdGFnZU9wdGlvbnMob3B0aW9ucywgcHJvamVjdCwgc3RhZ2UpIHtcbiAgaWYgKCFPYmplY3QuaGFzT3duKG9wdGlvbnMucHJvamVjdHMsIHByb2plY3QpKSByZXR1cm4gdW5kZWZpbmVkXG5cbiAgY29uc3Qgc3RhZ2VzID0gb3B0aW9ucy5wcm9qZWN0c1twcm9qZWN0XS5zdGFnZXNcblxuICBpZiAoIU9iamVjdC5oYXNPd24oc3RhZ2VzLCBzdGFnZSkpIHJldHVybiB1bmRlZmluZWRcblxuICByZXR1cm4gc3RhZ2VzW3N0YWdlXVxufVxuXG4vKipcbiAqIEF1dGhlbnRpY2F0ZWQgSFRUUCBBUEkgZm9yIGNhbGxhYmxlIGRlcGxveW1lbnRzLiBNb3VudGVkIGJ5XG4gKiB7QGxpbmsgaW1wb3J0KFwiLi9pbmRleC5qc1wiKS5kZWZhdWx0fSBhcyBhIHJvdXRlLXJlc29sdmVyIGhvb2sgc28gaXQgY2FuIHNoaXBcbiAqIGluc2lkZSB0aGUgdmVsb2Npb3VzIHBhY2thZ2UuIEV2ZXJ5IGFjdGlvbiBpcyBnYXRlZCBieSBhIGJlYXJlci10b2tlbiBjaGVja1xuICogYWdhaW5zdCB0aGUgY29uZmlndXJlZCBhY2Nlc3MgdG9rZW5zOyB0aGUgQVBJIGV4cG9zZXMgb25seSBhbGxvd2xpc3RlZFxuICogcHJvamVjdC9zdGFnZSBwYWlycyBhbmQgZnVsbCBpbW11dGFibGUgcmV2aXNpb25zLCBhbmQgZGVsZWdhdGVzIGFsbFxuICogZXhlY3V0aW9uIHRvIHRoZSBjb25maWd1cmVkIGFkYXB0ZXIuIEl0IG5ldmVyIGFjY2VwdHMgY29tbWFuZHMsIHBhdGhzLFxuICogYXJiaXRyYXJ5IHJlZnMsIGVudmlyb25tZW50IHZhcmlhYmxlcywgb3IgcmF3IGxvZyBvdXRwdXQuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFZlbG9jaW91c0RlcGxveW1lbnRBcGlDb250cm9sbGVyIGV4dGVuZHMgQ29udHJvbGxlciB7XG4gIC8qKlxuICAgKiBSdW5zIG1vdW50IG9wdGlvbnMuXG4gICAqIEByZXR1cm5zIHtpbXBvcnQoXCIuL3JlZ2lzdHJ5LmpzXCIpLkRlcGxveW1lbnRNb3VudE9wdGlvbnN9IC0gT3B0aW9ucyBmb3IgdGhlIG1vdW50IHRoYXQgbWF0Y2hlZCB0aGlzIHJlcXVlc3QuXG4gICAqL1xuICBfbW91bnRPcHRpb25zKCkge1xuICAgIGNvbnN0IGF0ID0gLyoqIEB0eXBlIHtzdHJpbmd9ICovICh0aGlzLnBhcmFtcygpLnZlbG9jaW91c0RlcGxveW1lbnRNb3VudEF0KVxuICAgIGNvbnN0IG9wdGlvbnMgPSBnZXREZXBsb3ltZW50TW91bnQodGhpcy5nZXRDb25maWd1cmF0aW9uKCksIGF0KVxuXG4gICAgaWYgKCFvcHRpb25zKSB0aHJvdyBuZXcgRXJyb3IoYE5vIGRlcGxveW1lbnQgQVBJIG1vdW50IHJlZ2lzdGVyZWQgYXQgJHthdH1gKVxuXG4gICAgcmV0dXJuIG9wdGlvbnNcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHN0b3JlLlxuICAgKiBAcmV0dXJucyB7RGVwbG95bWVudFJ1blN0b3JlfSAtIFJ1biBzdG9yZSBzY29wZWQgdG8gdGhlIG1vdW50J3MgZGF0YWJhc2UuXG4gICAqL1xuICBfc3RvcmUoKSB7XG4gICAgaWYgKCF0aGlzLl9kZXBsb3ltZW50UnVuU3RvcmUpIHtcbiAgICAgIHRoaXMuX2RlcGxveW1lbnRSdW5TdG9yZSA9IG5ldyBEZXBsb3ltZW50UnVuU3RvcmUoe1xuICAgICAgICBjb25maWd1cmF0aW9uOiB0aGlzLmdldENvbmZpZ3VyYXRpb24oKSxcbiAgICAgICAgZGF0YWJhc2VJZGVudGlmaWVyOiB0aGlzLl9tb3VudE9wdGlvbnMoKS5kYXRhYmFzZUlkZW50aWZpZXIsXG4gICAgICAgIG1vdW50SWRlbnRpZmllcjogdGhpcy5fbW91bnRPcHRpb25zKCkubW91bnRJZGVudGlmaWVyLFxuICAgICAgICBzdGFsZVJ1blRpbWVvdXRNczogdGhpcy5fbW91bnRPcHRpb25zKCkuc3RhbGVSdW5UaW1lb3V0TXNcbiAgICAgIH0pXG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuX2RlcGxveW1lbnRSdW5TdG9yZVxuICB9XG5cbiAgLyoqXG4gICAqIFJlcG9ydHMgb25lIGludGVybmFsbHkgY29uc3VtZWQgZnJhbWV3b3JrIGZhaWx1cmUgb24gYm90aCBkb2N1bWVudGVkXG4gICAqIGVycm9yIGNoYW5uZWxzIHNvIGZyYW1ld29yay1zcGVjaWZpYyBhbmQgdW5pZmllZCByZXBvcnRlcnMgc2VlIHRoZSBzYW1lXG4gICAqIHBheWxvYWQuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gT3B0aW9ucy5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGFyZ3MuY29udGV4dCAtIERlcGxveW1lbnQgQVBJIGZhaWx1cmUgY29udGV4dC5cbiAgICogQHBhcmFtIHs/fSBhcmdzLmVycm9yIC0gQ29uc3VtZWQgZXJyb3IuXG4gICAqIEByZXR1cm5zIHt2b2lkfSAtIE5vIHJldHVybiB2YWx1ZS5cbiAgICovXG4gIF9lbWl0RnJhbWV3b3JrRXJyb3Ioe2NvbnRleHQsIGVycm9yfSkge1xuICAgIGNvbnN0IGVycm9yRXZlbnRzID0gdGhpcy5nZXRDb25maWd1cmF0aW9uKCkuZ2V0RXJyb3JFdmVudHMoKVxuICAgIGNvbnN0IHBheWxvYWQgPSB7Y29udGV4dCwgZXJyb3IsIHJlcXVlc3Q6IHRoaXMuZ2V0UmVxdWVzdCgpfVxuXG4gICAgZXJyb3JFdmVudHMuZW1pdChcImZyYW1ld29yay1lcnJvclwiLCBwYXlsb2FkKVxuICAgIGVycm9yRXZlbnRzLmVtaXQoXCJhbGwtZXJyb3JcIiwgey4uLnBheWxvYWQsIGVycm9yVHlwZTogXCJmcmFtZXdvcmstZXJyb3JcIn0pXG4gIH1cblxuICAvKipcbiAgICogQXV0aG9yaXplcyB0aGUgcmVxdWVzdCB3aXRoIGEgY29uc3RhbnQtdGltZSBiZWFyZXItdG9rZW4gY29tcGFyaXNvbiBhbmRcbiAgICogcnVucyB0aGUgYWN0aW9uIGJvZHkgb25seSB3aGVuIGF1dGhvcml6ZWQuIFJlbmRlcnMgYSA0MDEgb3RoZXJ3aXNlLiBUaGVcbiAgICogYmFzZSBjb250cm9sbGVyIGhhcyBubyBiZWZvcmUtYWN0aW9uIGhhbHRpbmcsIHNvIGF1dGhvcml6YXRpb24gaXMgZW5mb3JjZWRcbiAgICogaGVyZSBwZXIgYWN0aW9uLiBUb2tlbnMgYXJlIG9ubHkgYWNjZXB0ZWQgdGhyb3VnaCB0aGUgQXV0aG9yaXphdGlvbiBoZWFkZXJcbiAgICog4oCUIG5ldmVyIHRocm91Z2ggVVJMcyDigJQgYW5kIGFyZSBuZXZlciByZW5kZXJlZCBiYWNrLlxuICAgKiBAcGFyYW0geygpID0+IFByb21pc2U8dm9pZD59IGFjdGlvbkZuIC0gQWN0aW9uIGJvZHkuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gY29tcGxldGUuXG4gICAqL1xuICBhc3luYyBfcmVzcG9uZChhY3Rpb25Gbikge1xuICAgIGNvbnN0IHRva2VuID0gYmVhcmVyVG9rZW4odGhpcy5yZXF1ZXN0KCkpXG4gICAgbGV0IGF1dGhvcml6ZWQgPSBmYWxzZVxuXG4gICAgaWYgKHRva2VuKSB7XG4gICAgICBmb3IgKGNvbnN0IGFjY2Vzc1Rva2VuIG9mIHRoaXMuX21vdW50T3B0aW9ucygpLmFjY2Vzc1Rva2Vucykge1xuICAgICAgICBpZiAoY29uc3RhbnRUaW1lRXF1YWwodG9rZW4sIGFjY2Vzc1Rva2VuKSkge1xuICAgICAgICAgIGF1dGhvcml6ZWQgPSB0cnVlXG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIGlmICghYXV0aG9yaXplZCkge1xuICAgICAgYXdhaXQgdGhpcy5yZW5kZXIoe2pzb246IHtlcnJvcjogXCJ1bmF1dGhvcml6ZWRcIn0sIHN0YXR1czogNDAxfSlcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIGF3YWl0IGFjdGlvbkZuKClcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgZGVwbG95bWVudCBydW4gZm9yIGFuIGFsbG93bGlzdGVkIHByb2plY3Qvc3RhZ2UgYW5kIGEgZnVsbFxuICAgKiBpbW11dGFibGUgcmV2aXNpb24gcmVhY2hhYmxlIGZyb20gdGhlIGFwcHJvdmVkIHJlbGVhc2UgYnJhbmNoLiBJZGVtcG90ZW50OlxuICAgKiBhIHJldHJpZWQgaWRlbXBvdGVuY3kga2V5IHJlYWRzIHRoZSBvcmlnaW5hbCBydW4sIGEgcmV1c2VkIGtleSB3aXRoIGFcbiAgICogZGlmZmVyZW50IHBheWxvYWQgY29uZmxpY3RzLCBhbmQgYW4gYWN0aXZlIHJ1biBmb3IgdGhlIHNhbWUgcHJvamVjdC9zdGFnZVxuICAgKiByZXR1cm5zIGEgYm91bmRlZCBjb25mbGljdC5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgd2hlbiBjb21wbGV0ZS5cbiAgICovXG4gIGFzeW5jIGNyZWF0ZSgpIHtcbiAgICBhd2FpdCB0aGlzLl9yZXNwb25kKGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHBhcmFtcyA9IHRoaXMucGFyYW1zKClcbiAgICAgIGNvbnN0IHJldmlzaW9uID0gdHlwZW9mIHBhcmFtcy5yZXZpc2lvbiA9PT0gXCJzdHJpbmdcIiA/IHBhcmFtcy5yZXZpc2lvbiA6IG51bGxcbiAgICAgIGNvbnN0IGlkZW1wb3RlbmN5S2V5ID0gdHlwZW9mIHBhcmFtcy5pZGVtcG90ZW5jeUtleSA9PT0gXCJzdHJpbmdcIiA/IHBhcmFtcy5pZGVtcG90ZW5jeUtleSA6IG51bGxcbiAgICAgIGNvbnN0IGludmFsaWRGaWVsZHMgPSBbXVxuXG4gICAgICBpZiAoIXJldmlzaW9uIHx8ICFSRVZJU0lPTl9QQVRURVJOLnRlc3QocmV2aXNpb24pKSBpbnZhbGlkRmllbGRzLnB1c2goXCJyZXZpc2lvblwiKVxuICAgICAgaWYgKCFpZGVtcG90ZW5jeUtleSB8fCBpZGVtcG90ZW5jeUtleS5sZW5ndGggPT09IDAgfHwgaWRlbXBvdGVuY3lLZXkubGVuZ3RoID4gTUFYX0lERU1QT1RFTkNZX0tFWV9MRU5HVEgpIHtcbiAgICAgICAgaW52YWxpZEZpZWxkcy5wdXNoKFwiaWRlbXBvdGVuY3lLZXlcIilcbiAgICAgIH1cblxuICAgICAgaWYgKGludmFsaWRGaWVsZHMubGVuZ3RoID4gMCkge1xuICAgICAgICBhd2FpdCB0aGlzLnJlbmRlcih7anNvbjoge2Vycm9yOiBcImludmFsaWRfcGFyYW1zXCIsIGZpZWxkczogaW52YWxpZEZpZWxkc30sIHN0YXR1czogNDIyfSlcbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG9wdGlvbnMgPSB0aGlzLl9tb3VudE9wdGlvbnMoKVxuICAgICAgY29uc3QgcHJvamVjdCA9IHR5cGVvZiBwYXJhbXMucHJvamVjdCA9PT0gXCJzdHJpbmdcIiA/IHBhcmFtcy5wcm9qZWN0IDogXCJcIlxuICAgICAgY29uc3Qgc3RhZ2UgPSB0eXBlb2YgcGFyYW1zLnN0YWdlID09PSBcInN0cmluZ1wiID8gcGFyYW1zLnN0YWdlIDogXCJcIlxuICAgICAgY29uc3Qgc3RhZ2VPcHRpb25zID0gbG9va3VwU3RhZ2VPcHRpb25zKG9wdGlvbnMsIHByb2plY3QsIHN0YWdlKVxuXG4gICAgICBpZiAoIXN0YWdlT3B0aW9ucykge1xuICAgICAgICBhd2FpdCB0aGlzLnJlbmRlcih7anNvbjoge2Vycm9yOiBcIm5vdF9mb3VuZFwifSwgc3RhdHVzOiA0MDR9KVxuICAgICAgICByZXR1cm5cbiAgICAgIH1cblxuICAgICAgY29uc3Qgc3RvcmUgPSB0aGlzLl9zdG9yZSgpXG4gICAgICBjb25zdCB2YWxpZFJldmlzaW9uID0gLyoqIEB0eXBlIHtzdHJpbmd9ICovIChyZXZpc2lvbilcbiAgICAgIGNvbnN0IHZhbGlkSWRlbXBvdGVuY3lLZXkgPSAvKiogQHR5cGUge3N0cmluZ30gKi8gKGlkZW1wb3RlbmN5S2V5KVxuXG4gICAgICAvLyBSZXRyaWVzIHJlYWQgdGhlIG9yaWdpbmFsIHJ1biBiZWZvcmUgYW55dGhpbmcgZWxzZSDigJQgYSByZXBsYXkgbXVzdFxuICAgICAgLy8gbmV2ZXIgcmUtdmFsaWRhdGUgb3IgcmUtZGVwbG95LlxuICAgICAgY29uc3QgZXhpc3RpbmdSdW4gPSBhd2FpdCBzdG9yZS5maW5kUnVuQnlLZXkodmFsaWRJZGVtcG90ZW5jeUtleSlcblxuICAgICAgaWYgKGV4aXN0aW5nUnVuKSB7XG4gICAgICAgIGF3YWl0IHRoaXMuX3JlbmRlckV4aXN0aW5nUnVuKHtleGlzdGluZ1J1biwgcHJvamVjdCwgcmV2aXNpb246IHZhbGlkUmV2aXNpb24sIHN0YWdlfSlcbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHJlYWNoYWJsZSA9IGF3YWl0IG9wdGlvbnMuYWRhcHRlci52YWxpZGF0ZVJldmlzaW9uKHtcbiAgICAgICAgY29uZmlndXJhdGlvbjogdGhpcy5nZXRDb25maWd1cmF0aW9uKCksXG4gICAgICAgIHByb2plY3QsXG4gICAgICAgIHJlbGVhc2VCcmFuY2g6IHN0YWdlT3B0aW9ucy5yZWxlYXNlQnJhbmNoLFxuICAgICAgICByZXZpc2lvbjogdmFsaWRSZXZpc2lvbixcbiAgICAgICAgc3RhZ2VcbiAgICAgIH0pXG5cbiAgICAgIGlmICghcmVhY2hhYmxlKSB7XG4gICAgICAgIGF3YWl0IHRoaXMucmVuZGVyKHtqc29uOiB7ZXJyb3I6IFwicmV2aXNpb25fbm90X3JlYWNoYWJsZVwifSwgc3RhdHVzOiA0MjJ9KVxuICAgICAgICByZXR1cm5cbiAgICAgIH1cblxuICAgICAgY29uc3Qgb3V0Y29tZSA9IGF3YWl0IHN0b3JlLmNyZWF0ZVJ1bklmUG9zc2libGUoe1xuICAgICAgICBpZGVtcG90ZW5jeUtleTogdmFsaWRJZGVtcG90ZW5jeUtleSxcbiAgICAgICAgcHJvamVjdCxcbiAgICAgICAgcmV2aXNpb246IHZhbGlkUmV2aXNpb24sXG4gICAgICAgIHN0YWdlXG4gICAgICB9KVxuXG4gICAgICBpZiAob3V0Y29tZS5vdXRjb21lID09PSBcInJlcGxheVwiIHx8IG91dGNvbWUub3V0Y29tZSA9PT0gXCJjb25mbGljdFwiKSB7XG4gICAgICAgIGNvbnN0IGV4aXN0aW5nRnJvbVN0b3JlID0gb3V0Y29tZS5ydW5cblxuICAgICAgICBpZiAoIWV4aXN0aW5nRnJvbVN0b3JlKSB0aHJvdyBuZXcgRXJyb3IoYERlcGxveW1lbnQgcnVuIHN0b3JlIHJlcG9ydGVkICcke291dGNvbWUub3V0Y29tZX0nIHdpdGhvdXQgYSBydW5gKVxuXG4gICAgICAgIGF3YWl0IHRoaXMuX3JlbmRlckV4aXN0aW5nUnVuKHtleGlzdGluZ1J1bjogZXhpc3RpbmdGcm9tU3RvcmUsIHByb2plY3QsIHJldmlzaW9uOiB2YWxpZFJldmlzaW9uLCBzdGFnZX0pXG4gICAgICAgIHJldHVyblxuICAgICAgfVxuXG4gICAgICBpZiAob3V0Y29tZS5vdXRjb21lID09PSBcImluX3Byb2dyZXNzXCIpIHtcbiAgICAgICAgY29uc3QgYWN0aXZlUnVuID0gb3V0Y29tZS5ydW5cblxuICAgICAgICBhd2FpdCB0aGlzLnJlbmRlcih7anNvbjoge2Vycm9yOiBcImRlcGxveW1lbnRfaW5fcHJvZ3Jlc3NcIiwgcnVuSWQ6IGFjdGl2ZVJ1biA/IGFjdGl2ZVJ1bi5pZCA6IHVuZGVmaW5lZH0sIHN0YXR1czogNDA5fSlcbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIGlmIChvdXRjb21lLm91dGNvbWUgPT09IFwicmVjb25jaWxpYXRpb25fcmVxdWlyZWRcIikge1xuICAgICAgICBjb25zdCBibG9ja2VkUnVuID0gb3V0Y29tZS5ydW5cblxuICAgICAgICBpZiAoIWJsb2NrZWRSdW4pIHRocm93IG5ldyBFcnJvcihcIkRlcGxveW1lbnQgcnVuIHN0b3JlIHJlcG9ydGVkICdyZWNvbmNpbGlhdGlvbl9yZXF1aXJlZCcgd2l0aG91dCBhIHJ1blwiKVxuXG4gICAgICAgIGF3YWl0IHRoaXMucmVuZGVyKHtqc29uOiB7ZXJyb3I6IFwiZGVwbG95bWVudF9yZWNvbmNpbGlhdGlvbl9yZXF1aXJlZFwiLCBydW5JZDogYmxvY2tlZFJ1bi5pZH0sIHN0YXR1czogNDA5fSlcbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHJ1biA9IG91dGNvbWUucnVuXG5cbiAgICAgIGlmICghcnVuKSB0aHJvdyBuZXcgRXJyb3IoXCJEZXBsb3ltZW50IHJ1biBzdG9yZSByZXBvcnRlZCAnY3JlYXRlZCcgd2l0aG91dCBhIHJ1blwiKVxuXG4gICAgICBhd2FpdCB0aGlzLl9hdWRpdCh7ZXZlbnQ6IFwicnVuX3JlcXVlc3RlZFwiLCBwYXlsb2FkOiB7cHJvamVjdCwgcmV2aXNpb246IHZhbGlkUmV2aXNpb24sIHN0YWdlfSwgcnVuSWQ6IHJ1bi5pZH0pXG5cbiAgICAgIC8vIEV4ZWN1dGlvbiBpcyBkZWxpYmVyYXRlbHkgbm90IGF3YWl0ZWQ6IHRoZSBkZXBsb3kgcnVucyB1bmRlciB0aGVcbiAgICAgIC8vIGludGVncmF0aW9uJ3Mgb3duIGxvY2svYnVpbGQvaGVhbHRoL3JvbGxiYWNrIHNlbWFudGljcyBhbmQgdGhlIGNhbGxlclxuICAgICAgLy8gcmVhZHMgcHJvZ3Jlc3MgYmFjayB0aHJvdWdoIHRoZSBzaG93IGFjdGlvbi5cbiAgICAgIHRoaXMuX2V4ZWN1dGVSdW4oe29wdGlvbnMsIHJ1bn0pLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgICB0aGlzLl9lbWl0RnJhbWV3b3JrRXJyb3Ioe2NvbnRleHQ6IFwiZGVwbG95bWVudC1hcGktZXhlY3V0ZS1ydW5cIiwgZXJyb3J9KVxuICAgICAgfSlcblxuICAgICAgYXdhaXQgdGhpcy5yZW5kZXIoe2pzb246IHtydW46IHRoaXMuX3NlcmlhbGl6ZVJ1bihydW4pfSwgc3RhdHVzOiAyMDJ9KVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogUmVuZGVycyBhIHByZXZpb3VzbHkgY3JlYXRlZCBydW4gZm9yIGFuIGlkZW1wb3RlbmN5LWtleSBoaXQ6IGEgcmVwbGF5IHdoZW5cbiAgICogdGhlIHBheWxvYWQgbWF0Y2hlcywgYSBib3VuZGVkIGNvbmZsaWN0IHdoZW4gaXQgZG9lc24ndC5cbiAgICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBPcHRpb25zLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4vcnVuLXN0b3JlLmpzXCIpLkRlcGxveW1lbnRSdW5Sb3d9IGFyZ3MuZXhpc3RpbmdSdW4gLSBUaGUgc3RvcmVkIHJ1bi5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGFyZ3MucHJvamVjdCAtIFJlcXVlc3RlZCBwcm9qZWN0LlxuICAgKiBAcGFyYW0ge3N0cmluZ30gYXJncy5yZXZpc2lvbiAtIFJlcXVlc3RlZCByZXZpc2lvbi5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGFyZ3Muc3RhZ2UgLSBSZXF1ZXN0ZWQgc3RhZ2UuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gY29tcGxldGUuXG4gICAqL1xuICBhc3luYyBfcmVuZGVyRXhpc3RpbmdSdW4oe2V4aXN0aW5nUnVuLCBwcm9qZWN0LCByZXZpc2lvbiwgc3RhZ2V9KSB7XG4gICAgY29uc3Qgc2FtZVBheWxvYWQgPSBleGlzdGluZ1J1bi5wcm9qZWN0ID09PSBwcm9qZWN0ICYmIGV4aXN0aW5nUnVuLnN0YWdlID09PSBzdGFnZSAmJiBleGlzdGluZ1J1bi5yZXZpc2lvbiA9PT0gcmV2aXNpb25cblxuICAgIGlmICghc2FtZVBheWxvYWQpIHtcbiAgICAgIGF3YWl0IHRoaXMucmVuZGVyKHtqc29uOiB7ZXJyb3I6IFwiaWRlbXBvdGVuY3lfY29uZmxpY3RcIiwgcnVuSWQ6IGV4aXN0aW5nUnVuLmlkfSwgc3RhdHVzOiA0MDl9KVxuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgYXdhaXQgdGhpcy5yZW5kZXIoe2pzb246IHtyZXBsYXllZDogdHJ1ZSwgcnVuOiB0aGlzLl9zZXJpYWxpemVSdW4oZXhpc3RpbmdSdW4pfSwgc3RhdHVzOiAyMDB9KVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGJvdW5kZWQgc3RhdGUgb2YgYSBzaW5nbGUgcnVuLCBlbnJpY2hlZCB3aXRoIHRoZSBhZGFwdGVyJ3NcbiAgICogbGl2ZSBzdGF0dXMgd2hlbiB0aGUgaW50ZWdyYXRpb24gcHJvdmlkZXMgb25lLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyB3aGVuIGNvbXBsZXRlLlxuICAgKi9cbiAgYXN5bmMgc2hvdygpIHtcbiAgICBhd2FpdCB0aGlzLl9yZXNwb25kKGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHJ1biA9IGF3YWl0IHRoaXMuX3N0b3JlKCkuZmluZFJ1bkJ5SWQoLyoqIEB0eXBlIHtzdHJpbmd9ICovICh0aGlzLnBhcmFtcygpLmlkKSlcblxuICAgICAgaWYgKCFydW4pIHtcbiAgICAgICAgYXdhaXQgdGhpcy5yZW5kZXIoe2pzb246IHtlcnJvcjogXCJub3RfZm91bmRcIn0sIHN0YXR1czogNDA0fSlcbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG9wdGlvbnMgPSB0aGlzLl9tb3VudE9wdGlvbnMoKVxuICAgICAgLyoqIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gKi9cbiAgICAgIGNvbnN0IGJvZHkgPSB7cnVuOiB0aGlzLl9zZXJpYWxpemVSdW4ocnVuKX1cblxuICAgICAgaWYgKG9wdGlvbnMuYWRhcHRlci5yZWFkU3RhdHVzKSB7XG4gICAgICAgIGNvbnN0IGxpdmVTdGF0dXMgPSBhd2FpdCBvcHRpb25zLmFkYXB0ZXIucmVhZFN0YXR1cyh7XG4gICAgICAgICAgY29uZmlndXJhdGlvbjogdGhpcy5nZXRDb25maWd1cmF0aW9uKCksXG4gICAgICAgICAgcHJvamVjdDogcnVuLnByb2plY3QsXG4gICAgICAgICAgc3RhZ2U6IHJ1bi5zdGFnZVxuICAgICAgICB9KVxuXG4gICAgICAgIGJvZHkuY3VycmVudCA9IHNhbml0aXplQWRhcHRlclZhbHVlKGxpdmVTdGF0dXMsIG9wdGlvbnMuYWNjZXNzVG9rZW5zKSA/PyBudWxsXG4gICAgICB9XG5cbiAgICAgIGF3YWl0IHRoaXMucmVuZGVyKHtqc29uOiBib2R5LCBzdGF0dXM6IDIwMH0pXG4gICAgfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBFeGVjdXRlcyBhIGNyZWF0ZWQgcnVuIGFzeW5jaHJvbm91c2x5OiByZWdpc3RlcnMgaXQgYXMgYWN0aXZlIGluIHRoaXNcbiAgICogcHJvY2VzcywgbWFya3MgaXQgcnVubmluZywgaGVhcnRiZWF0cyBpdHMgb3duZXJzaGlwIGxlYXNlIHdoaWxlIHRoZVxuICAgKiBhZGFwdGVyIGRlcGxveXMsIGFuZCByZWNvcmRzIHRoZSBzYW5pdGl6ZWQgb3V0Y29tZS4gQSBkZXBsb3ltZW50IGZhaWx1cmVcbiAgICogaXMgYW4gZXhwZWN0ZWQgb3BlcmF0aW9uYWwgcmVzdWx0IOKAlCBpdCBpcyBwZXJzaXN0ZWQgd2l0aCBpdHMgc2FuaXRpemVkXG4gICAqIHJlY292ZXJ5IGluZm9ybWF0aW9uIGluc3RlYWQgb2YgYmVpbmcgcmFpc2VkLCBzbyBpdCBzdGF5cyB2aXNpYmxlIHRocm91Z2hcbiAgICogcmVhZGJhY2sgYW5kIGF1ZGl0IHJhdGhlciB0aGFuIGNyYXNoaW5nIHRoZSB3b3JrZXIuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gT3B0aW9ucy5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuL3JlZ2lzdHJ5LmpzXCIpLkRlcGxveW1lbnRNb3VudE9wdGlvbnN9IGFyZ3Mub3B0aW9ucyAtIE1vdW50IG9wdGlvbnMuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi9ydW4tc3RvcmUuanNcIikuRGVwbG95bWVudFJ1blJvd30gYXJncy5ydW4gLSBUaGUgY3JlYXRlZCBydW4uXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gdGhlIG91dGNvbWUgaXMgcmVjb3JkZWQuXG4gICAqL1xuICBhc3luYyBfZXhlY3V0ZVJ1bih7b3B0aW9ucywgcnVufSkge1xuICAgIGNvbnN0IHN0b3JlID0gdGhpcy5fc3RvcmUoKVxuICAgIGNvbnN0IHNlY3JldHMgPSBvcHRpb25zLmFjY2Vzc1Rva2Vuc1xuICAgIGNvbnN0IHN0YWdlT3B0aW9ucyA9IGxvb2t1cFN0YWdlT3B0aW9ucyhvcHRpb25zLCBydW4ucHJvamVjdCwgcnVuLnN0YWdlKVxuXG4gICAgaWYgKCFzdGFnZU9wdGlvbnMpIHRocm93IG5ldyBFcnJvcihgRGVwbG95bWVudCBydW4gJHtydW4uaWR9IHJlZmVyZW5jZXMgbm9uLWFsbG93bGlzdGVkICR7cnVuLnByb2plY3R9LyR7cnVuLnN0YWdlfWApXG4gICAgaWYgKCFydW4ub3duZXJUb2tlbikgdGhyb3cgbmV3IEVycm9yKGBEZXBsb3ltZW50IHJ1biAke3J1bi5pZH0gaGFzIG5vIGV4ZWN1dGlvbiBvd25lciB0b2tlbmApXG5cbiAgICBjb25zdCBvd25lclRva2VuID0gcnVuLm93bmVyVG9rZW5cblxuICAgIHJlZ2lzdGVyQWN0aXZlRGVwbG95bWVudFJ1bihydW4uaWQpXG5cbiAgICAvKiogQHR5cGUge1JldHVyblR5cGU8dHlwZW9mIHNldEludGVydmFsPiB8IG51bGx9ICovXG4gICAgbGV0IGhlYXJ0YmVhdFRpbWVyID0gbnVsbFxuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHN0b3JlLm1hcmtSdW5uaW5nKHtpZDogcnVuLmlkLCBzdGFydGVkQXRNczogRGF0ZS5ub3coKX0pXG5cbiAgICAgIC8vIFJlbmV3IHRoZSBvd25lcnNoaXAgbGVhc2Ugd2hpbGUgdGhlIGRlcGxveSBydW5zIHNvIHJlY29uY2lsaWF0aW9uXG4gICAgICAvLyBuZXZlciByZWNsYWltcyB0aGlzIGdlbnVpbmVseSBhY3RpdmUgcnVuOyB1bnJlZidkIHNvIHRoZSB0aW1lciBhbG9uZVxuICAgICAgLy8ga2VlcHMgbm8gcHJvY2VzcyBhbGl2ZS5cbiAgICAgIGNvbnN0IGhlYXJ0YmVhdEludGVydmFsTXMgPSBNYXRoLm1heCgxMDAwLCBNYXRoLmZsb29yKG9wdGlvbnMuc3RhbGVSdW5UaW1lb3V0TXMgLyA0KSlcblxuICAgICAgaGVhcnRiZWF0VGltZXIgPSBzZXRJbnRlcnZhbCgoKSA9PiB7XG4gICAgICAgIHN0b3JlLmhlYXJ0YmVhdCh7aGVhcnRiZWF0QXRNczogRGF0ZS5ub3coKSwgaWQ6IHJ1bi5pZH0pLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgICAgIHRoaXMuX2VtaXRGcmFtZXdvcmtFcnJvcih7Y29udGV4dDogXCJkZXBsb3ltZW50LWFwaS1oZWFydGJlYXRcIiwgZXJyb3J9KVxuICAgICAgICB9KVxuICAgICAgfSwgaGVhcnRiZWF0SW50ZXJ2YWxNcylcbiAgICAgIGhlYXJ0YmVhdFRpbWVyLnVucmVmKClcblxuICAgICAgYXdhaXQgdGhpcy5fYXVkaXQoe2V2ZW50OiBcInJ1bl9zdGFydGVkXCIsIHBheWxvYWQ6IHtwcm9qZWN0OiBydW4ucHJvamVjdCwgcmV2aXNpb246IHJ1bi5yZXZpc2lvbiwgc3RhZ2U6IHJ1bi5zdGFnZX0sIHJ1bklkOiBydW4uaWR9KVxuXG4gICAgICBsZXQgcmVwb3J0XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIHJlcG9ydCA9IGF3YWl0IG9wdGlvbnMuYWRhcHRlci5kZXBsb3koe1xuICAgICAgICAgIGNvbmZpZ3VyYXRpb246IHRoaXMuZ2V0Q29uZmlndXJhdGlvbigpLFxuICAgICAgICAgIHByb2plY3Q6IHJ1bi5wcm9qZWN0LFxuICAgICAgICAgIHJlbGVhc2VCcmFuY2g6IHN0YWdlT3B0aW9ucy5yZWxlYXNlQnJhbmNoLFxuICAgICAgICAgIHJldmlzaW9uOiBydW4ucmV2aXNpb24sXG4gICAgICAgICAgcnVuSWQ6IHJ1bi5pZCxcbiAgICAgICAgICBzdGFnZTogcnVuLnN0YWdlXG4gICAgICAgIH0pXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zdCBlcnJvclBheWxvYWQgPSBzYW5pdGl6ZUVycm9yUGF5bG9hZChlcnJvciwgc2VjcmV0cylcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IHN0b3JlLm1hcmtGYWlsZWQoe2Vycm9yOiBlcnJvclBheWxvYWQsIGZpbmlzaGVkQXRNczogRGF0ZS5ub3coKSwgaWQ6IHJ1bi5pZCwgb3duZXJUb2tlbn0pXG4gICAgICAgICAgYXdhaXQgdGhpcy5fYXVkaXQoe1xuICAgICAgICAgICAgZXZlbnQ6IFwicnVuX2ZhaWxlZFwiLFxuICAgICAgICAgICAgcGF5bG9hZDoge21lc3NhZ2U6IGVycm9yUGF5bG9hZC5tZXNzYWdlLCBwcm9qZWN0OiBydW4ucHJvamVjdCwgcmV2aXNpb246IHJ1bi5yZXZpc2lvbiwgc3RhZ2U6IHJ1bi5zdGFnZX0sXG4gICAgICAgICAgICBydW5JZDogcnVuLmlkXG4gICAgICAgICAgfSlcbiAgICAgICAgfSBjYXRjaCAoc3RvcmVFcnJvcikge1xuICAgICAgICAgIC8vIFJlY29yZGluZyB0aGUgZmFpbHVyZSBpdHNlbGYgZmFpbGVkIOKAlCB0aGF0IGlzIGFuIHVuZXhwZWN0ZWQgYnVnXG4gICAgICAgICAgLy8gYW5kIG11c3Qgc3VyZmFjZSB0byBwcm9jZXNzLWxldmVsIGVycm9yIHJlcG9ydGVycy5cbiAgICAgICAgICB0aGlzLl9lbWl0RnJhbWV3b3JrRXJyb3Ioe2NvbnRleHQ6IFwiZGVwbG95bWVudC1hcGktcmVjb3JkLWZhaWx1cmVcIiwgZXJyb3I6IHN0b3JlRXJyb3J9KVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IHNhbml0aXplQWRhcHRlclZhbHVlKHJlcG9ydCA/PyB7fSwgc2VjcmV0cykgPz8ge31cblxuICAgICAgICBhd2FpdCBzdG9yZS5tYXJrU3VjY2VlZGVkKHtmaW5pc2hlZEF0TXM6IERhdGUubm93KCksIGlkOiBydW4uaWQsIG93bmVyVG9rZW4sIHJlc3VsdH0pXG4gICAgICAgIGF3YWl0IHRoaXMuX2F1ZGl0KHtldmVudDogXCJydW5fc3VjY2VlZGVkXCIsIHBheWxvYWQ6IHtwcm9qZWN0OiBydW4ucHJvamVjdCwgcmV2aXNpb246IHJ1bi5yZXZpc2lvbiwgc3RhZ2U6IHJ1bi5zdGFnZX0sIHJ1bklkOiBydW4uaWR9KVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgLy8gVGhlIGFkYXB0ZXIgYWxyZWFkeSByZXR1cm5lZCBzdWNjZXNzLiBTdXJmYWNlIHRoZSByZWNvcmRpbmcgZXJyb3IsXG4gICAgICAgIC8vIHRoZW4gZmVuY2UgdGhlIHJ1biBpbiBhIGR1cmFibGUgbm9uLXJldHJ5YWJsZSBzdGF0ZSByYXRoZXIgdGhhblxuICAgICAgICAvLyBmYWxzZWx5IHJlY29yZGluZyBhbiBleHRlcm5hbCBzdWNjZXNzIGFzIGEgZGVwbG95bWVudCBmYWlsdXJlLlxuICAgICAgICB0aGlzLl9lbWl0RnJhbWV3b3JrRXJyb3Ioe2NvbnRleHQ6IFwiZGVwbG95bWVudC1hcGktcmVjb3JkLXN1Y2Nlc3NcIiwgZXJyb3J9KVxuXG4gICAgICAgIGNvbnN0IHJlY29uY2lsaWF0aW9uRXJyb3IgPSB7XG4gICAgICAgICAgbWVzc2FnZTogXCJEZXBsb3ltZW50IGFjdGl2YXRpb24gc3VjY2VlZGVkLCBidXQgaXRzIHJlc3VsdCBjb3VsZCBub3QgYmUgcGVyc2lzdGVkOyBvcGVyYXRvciByZWNvbmNpbGlhdGlvbiBpcyByZXF1aXJlZFwiXG4gICAgICAgIH1cblxuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IHN0b3JlLm1hcmtSZWNvbmNpbGlhdGlvblJlcXVpcmVkKHtcbiAgICAgICAgICAgIGVycm9yOiByZWNvbmNpbGlhdGlvbkVycm9yLFxuICAgICAgICAgICAgZmluaXNoZWRBdE1zOiBEYXRlLm5vdygpLFxuICAgICAgICAgICAgaWQ6IHJ1bi5pZCxcbiAgICAgICAgICAgIG93bmVyVG9rZW5cbiAgICAgICAgICB9KVxuICAgICAgICAgIGF3YWl0IHRoaXMuX2F1ZGl0KHtcbiAgICAgICAgICAgIGV2ZW50OiBcInJ1bl9yZWNvbmNpbGlhdGlvbl9yZXF1aXJlZFwiLFxuICAgICAgICAgICAgcGF5bG9hZDoge21lc3NhZ2U6IHJlY29uY2lsaWF0aW9uRXJyb3IubWVzc2FnZSwgcHJvamVjdDogcnVuLnByb2plY3QsIHJldmlzaW9uOiBydW4ucmV2aXNpb24sIHN0YWdlOiBydW4uc3RhZ2V9LFxuICAgICAgICAgICAgcnVuSWQ6IHJ1bi5pZFxuICAgICAgICAgIH0pXG4gICAgICAgIH0gY2F0Y2ggKHJlY29uY2lsaWF0aW9uRXJyb3JQZXJzaXN0ZW5jZUVycm9yKSB7XG4gICAgICAgICAgdGhpcy5fZW1pdEZyYW1ld29ya0Vycm9yKHtcbiAgICAgICAgICAgIGNvbnRleHQ6IFwiZGVwbG95bWVudC1hcGktcmVjb3JkLXJlY29uY2lsaWF0aW9uLXJlcXVpcmVkXCIsXG4gICAgICAgICAgICBlcnJvcjogcmVjb25jaWxpYXRpb25FcnJvclBlcnNpc3RlbmNlRXJyb3JcbiAgICAgICAgICB9KVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIGlmIChoZWFydGJlYXRUaW1lcikgY2xlYXJJbnRlcnZhbChoZWFydGJlYXRUaW1lcilcbiAgICAgIHVucmVnaXN0ZXJBY3RpdmVEZXBsb3ltZW50UnVuKHJ1bi5pZClcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmVjb3JkcyBhIHNhbml0aXplZCBhdWRpdCBldmVudC4gQXVkaXQgcGVyc2lzdGVuY2UgbXVzdCBuZXZlciBzdHJhbmQgb3JcbiAgICogc3VwcHJlc3MgYSBkZXBsb3ltZW50LCBzbyBhIGZhaWx1cmUgaGVyZSBpcyByZXBvcnRlZCBvbiB0aGVcbiAgICogZnJhbWV3b3JrLWVycm9yIGFuZCB1bmlmaWVkIGFsbC1lcnJvciBjaGFubmVscyAod2hlcmUgcHJvY2Vzcy1sZXZlbCBidWdcbiAgICogcmVwb3J0ZXJzIGNhcHR1cmUgaXQpLCBhbmQgZXhlY3V0aW9uIGNvbnRpbnVlcy5cbiAgICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBPcHRpb25zLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gYXJncy5ldmVudCAtIEV2ZW50IG5hbWUuXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgPz59IGFyZ3MucGF5bG9hZCAtIFBheWxvYWQ7IHNhbml0aXplZCBhbmQgcmVkYWN0ZWQgYmVmb3JlIHBlcnNpc3RlbmNlLlxuICAgKiBAcGFyYW0ge3N0cmluZyB8IG51bGx9IGFyZ3MucnVuSWQgLSBPd25pbmcgcnVuIGlkLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyB3aGVuIHJlY29yZGVkIG9yIHJlcG9ydGVkLlxuICAgKi9cbiAgYXN5bmMgX2F1ZGl0KHtldmVudCwgcGF5bG9hZCwgcnVuSWR9KSB7XG4gICAgY29uc3Qgc2FuaXRpemVkID0gc2FuaXRpemVBZGFwdGVyVmFsdWUocGF5bG9hZCwgdGhpcy5fbW91bnRPcHRpb25zKCkuYWNjZXNzVG9rZW5zKSA/PyB7fVxuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMuX3N0b3JlKCkuYWRkQXVkaXRFdmVudCh7ZXZlbnQsIHBheWxvYWQ6IHNhbml0aXplZCwgcnVuSWR9KVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aGlzLl9lbWl0RnJhbWV3b3JrRXJyb3Ioe2NvbnRleHQ6IFwiZGVwbG95bWVudC1hcGktYXVkaXRcIiwgZXJyb3J9KVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTZXJpYWxpemVzIGEgcnVuIGZvciB0aGUgQVBJLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4vcnVuLXN0b3JlLmpzXCIpLkRlcGxveW1lbnRSdW5Sb3d9IHJ1biAtIFJ1biByb3cuXG4gICAqIEByZXR1cm5zIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gLSBTZXJpYWxpemVkIHJ1bi5cbiAgICovXG4gIF9zZXJpYWxpemVSdW4ocnVuKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGVycm9yOiBydW4uZXJyb3IsXG4gICAgICBmaW5pc2hlZEF0TXM6IHJ1bi5maW5pc2hlZEF0TXMsXG4gICAgICBpZDogcnVuLmlkLFxuICAgICAgaWRlbXBvdGVuY3lLZXk6IHJ1bi5pZGVtcG90ZW5jeUtleSxcbiAgICAgIHByb2plY3Q6IHJ1bi5wcm9qZWN0LFxuICAgICAgcmVxdWVzdGVkQXRNczogcnVuLnJlcXVlc3RlZEF0TXMsXG4gICAgICByZXN1bHQ6IHJ1bi5yZXN1bHQsXG4gICAgICByZXZpc2lvbjogcnVuLnJldmlzaW9uLFxuICAgICAgc3RhZ2U6IHJ1bi5zdGFnZSxcbiAgICAgIHN0YXJ0ZWRBdE1zOiBydW4uc3RhcnRlZEF0TXMsXG4gICAgICBzdGF0dXM6IHJ1bi5zdGF0dXNcbiAgICB9XG4gIH1cbn1cbiJdfQ==
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mountable authenticated deployment API. A narrowly configured consumer
|
|
3
|
-
* mounts it in its routes file and supplies an adapter owned by the deployment
|
|
4
|
-
* integration (e.g. Rampway) that performs the actual lock/build/release/
|
|
5
|
-
* health/rollback/cleanup work:
|
|
6
|
-
*
|
|
7
|
-
* ```js
|
|
8
|
-
* routes.draw((route) => {
|
|
9
|
-
* route.mount(VelociousDeploymentApi, {
|
|
10
|
-
* at: "/velocious/deployments",
|
|
11
|
-
* accessTokens: [secrets.deploymentApiToken],
|
|
12
|
-
* adapter: rampwayDeploymentAdapter,
|
|
13
|
-
* projects: {
|
|
14
|
-
* "my-app": {stages: {production: {releaseBranch: "master"}}}
|
|
15
|
-
* }
|
|
16
|
-
* })
|
|
17
|
-
* })
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
|
-
export default class VelociousDeploymentApi {
|
|
21
|
-
/**
|
|
22
|
-
* Registers the deployment API under `at`. Implemented as a route-resolver
|
|
23
|
-
* hook so the controller can live inside the velocious package rather than
|
|
24
|
-
* the host app's `src/routes` directory. Invoked by the routing layer for
|
|
25
|
-
* each `route.mount(...)` registration.
|
|
26
|
-
* @param {object} args - Options.
|
|
27
|
-
* @param {import("../configuration.js").default} args.configuration - Configuration instance.
|
|
28
|
-
* @param {string} args.at - Mount path prefix (e.g. "/velocious/deployments").
|
|
29
|
-
* @param {string[]} args.accessTokens - Accepted bearer tokens; requests authenticate with `Authorization: Bearer <token>` only.
|
|
30
|
-
* @param {import("./registry.js").DeploymentAdapter} args.adapter - Deployment integration adapter that owns execution.
|
|
31
|
-
* @param {Record<string, import("./registry.js").DeploymentProjectOptions>} args.projects - Allowlisted projects/stages with their approved release branches.
|
|
32
|
-
* @param {string} [args.databaseIdentifier] - Database identifier the run store reads from.
|
|
33
|
-
* @param {number} [args.staleRunTimeoutMs] - Lease timeout after which an active run without a heartbeat is reconciled according to its execution state; defaults to 60000.
|
|
34
|
-
* @returns {void} - No return value.
|
|
35
|
-
*/
|
|
36
|
-
static mountInto({ accessTokens, adapter, at, configuration, databaseIdentifier, projects, staleRunTimeoutMs }: {
|
|
37
|
-
configuration: import("../configuration.js").default;
|
|
38
|
-
at: string;
|
|
39
|
-
accessTokens: string[];
|
|
40
|
-
adapter: import("./registry.js").DeploymentAdapter;
|
|
41
|
-
projects: Record<string, import("./registry.js").DeploymentProjectOptions>;
|
|
42
|
-
databaseIdentifier?: string | undefined;
|
|
43
|
-
staleRunTimeoutMs?: number | undefined;
|
|
44
|
-
}): void;
|
|
45
|
-
}
|
|
46
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/deployment-api/index.js"],"names":[],"mappings":"AAkJA;;;;;;;;;;;;;;;;;;GAkBG;AACH;IACE;;;;;;;;;;;;;;OAcG;IACH,gHATG;QAAoD,aAAa,EAAzD,OAAO,qBAAqB,EAAE,OAAO;QACxB,EAAE,EAAf,MAAM;QACS,YAAY,EAA3B,MAAM,EAAE;QACwC,OAAO,EAAvD,OAAO,eAAe,EAAE,iBAAiB;QAC8B,QAAQ,EAA/E,MAAM,CAAC,MAAM,EAAE,OAAO,eAAe,EAAE,wBAAwB,CAAC;QAClD,kBAAkB;QAClB,iBAAiB;KACvC,GAAU,IAAI,CA6BhB;CACF"}
|