velocious 1.0.571 → 1.0.573

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 (80) hide show
  1. package/README.md +2 -0
  2. package/build/background-jobs/web/authorization.js +2 -33
  3. package/build/background-jobs/web/path-matcher.js +5 -30
  4. package/build/database/drivers/base.js +17 -0
  5. package/build/database/drivers/mssql/index.js +30 -0
  6. package/build/database/record/index.js +22 -10
  7. package/build/deployment-api/controller.js +437 -0
  8. package/build/deployment-api/index.js +210 -0
  9. package/build/deployment-api/path-matcher.js +45 -0
  10. package/build/deployment-api/registry.js +84 -0
  11. package/build/deployment-api/run-store.js +798 -0
  12. package/build/deployment-api/sanitize.js +114 -0
  13. package/build/http-client/request.js +3 -1
  14. package/build/src/background-jobs/web/authorization.d.ts.map +1 -1
  15. package/build/src/background-jobs/web/authorization.js +3 -29
  16. package/build/src/background-jobs/web/path-matcher.d.ts +2 -12
  17. package/build/src/background-jobs/web/path-matcher.d.ts.map +1 -1
  18. package/build/src/background-jobs/web/path-matcher.js +5 -30
  19. package/build/src/database/drivers/base.d.ts +16 -0
  20. package/build/src/database/drivers/base.d.ts.map +1 -1
  21. package/build/src/database/drivers/base.js +16 -1
  22. package/build/src/database/drivers/mssql/index.d.ts.map +1 -1
  23. package/build/src/database/drivers/mssql/index.js +29 -1
  24. package/build/src/database/record/index.d.ts +3 -2
  25. package/build/src/database/record/index.d.ts.map +1 -1
  26. package/build/src/database/record/index.js +21 -10
  27. package/build/src/deployment-api/controller.d.ts +117 -0
  28. package/build/src/deployment-api/controller.d.ts.map +1 -0
  29. package/build/src/deployment-api/controller.js +384 -0
  30. package/build/src/deployment-api/index.d.ts +46 -0
  31. package/build/src/deployment-api/index.d.ts.map +1 -0
  32. package/build/src/deployment-api/index.js +178 -0
  33. package/build/src/deployment-api/path-matcher.d.ts +31 -0
  34. package/build/src/deployment-api/path-matcher.d.ts.map +1 -0
  35. package/build/src/deployment-api/path-matcher.js +39 -0
  36. package/build/src/deployment-api/registry.d.ts +106 -0
  37. package/build/src/deployment-api/registry.d.ts.map +1 -0
  38. package/build/src/deployment-api/registry.js +74 -0
  39. package/build/src/deployment-api/run-store.d.ts +402 -0
  40. package/build/src/deployment-api/run-store.d.ts.map +1 -0
  41. package/build/src/deployment-api/run-store.js +711 -0
  42. package/build/src/deployment-api/sanitize.d.ts +27 -0
  43. package/build/src/deployment-api/sanitize.d.ts.map +1 -0
  44. package/build/src/deployment-api/sanitize.js +100 -0
  45. package/build/src/http-client/request.d.ts.map +1 -1
  46. package/build/src/http-client/request.js +4 -2
  47. package/build/src/sync/signed-sync-envelope-replay-service.d.ts +154 -0
  48. package/build/src/sync/signed-sync-envelope-replay-service.d.ts.map +1 -0
  49. package/build/src/sync/signed-sync-envelope-replay-service.js +294 -0
  50. package/build/src/sync/sync-envelope-replay-service.d.ts +84 -15
  51. package/build/src/sync/sync-envelope-replay-service.d.ts.map +1 -1
  52. package/build/src/sync/sync-envelope-replay-service.js +98 -16
  53. package/build/src/utils/bearer-token.d.ts +15 -0
  54. package/build/src/utils/bearer-token.d.ts.map +1 -0
  55. package/build/src/utils/bearer-token.js +29 -0
  56. package/build/src/utils/mount-prefix.d.ts +21 -0
  57. package/build/src/utils/mount-prefix.d.ts.map +1 -0
  58. package/build/src/utils/mount-prefix.js +35 -0
  59. package/build/sync/signed-sync-envelope-replay-service.js +342 -0
  60. package/build/sync/sync-envelope-replay-service.js +110 -15
  61. package/build/tsconfig.tsbuildinfo +1 -1
  62. package/build/utils/bearer-token.js +34 -0
  63. package/build/utils/mount-prefix.js +36 -0
  64. package/package.json +2 -1
  65. package/src/background-jobs/web/authorization.js +2 -33
  66. package/src/background-jobs/web/path-matcher.js +5 -30
  67. package/src/database/drivers/base.js +17 -0
  68. package/src/database/drivers/mssql/index.js +30 -0
  69. package/src/database/record/index.js +22 -10
  70. package/src/deployment-api/controller.js +437 -0
  71. package/src/deployment-api/index.js +210 -0
  72. package/src/deployment-api/path-matcher.js +45 -0
  73. package/src/deployment-api/registry.js +84 -0
  74. package/src/deployment-api/run-store.js +798 -0
  75. package/src/deployment-api/sanitize.js +114 -0
  76. package/src/http-client/request.js +3 -1
  77. package/src/sync/signed-sync-envelope-replay-service.js +342 -0
  78. package/src/sync/sync-envelope-replay-service.js +110 -15
  79. package/src/utils/bearer-token.js +34 -0
  80. package/src/utils/mount-prefix.js +36 -0
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Authenticated HTTP API for callable deployments. Mounted by
3
+ * {@link import("./index.js").default} as a route-resolver hook so it can ship
4
+ * inside the velocious package. Every action is gated by a bearer-token check
5
+ * against the configured access tokens; the API exposes only allowlisted
6
+ * project/stage pairs and full immutable revisions, and delegates all
7
+ * execution to the configured adapter. It never accepts commands, paths,
8
+ * arbitrary refs, environment variables, or raw log output.
9
+ */
10
+ export default class VelociousDeploymentApiController extends Controller {
11
+ /**
12
+ * Runs mount options.
13
+ * @returns {import("./registry.js").DeploymentMountOptions} - Options for the mount that matched this request.
14
+ */
15
+ _mountOptions(): import("./registry.js").DeploymentMountOptions;
16
+ /**
17
+ * Runs store.
18
+ * @returns {DeploymentRunStore} - Run store scoped to the mount's database.
19
+ */
20
+ _store(): DeploymentRunStore;
21
+ _deploymentRunStore: DeploymentRunStore | undefined;
22
+ /**
23
+ * Reports one internally consumed framework failure on both documented
24
+ * error channels so framework-specific and unified reporters see the same
25
+ * payload.
26
+ * @param {object} args - Options.
27
+ * @param {string} args.context - Deployment API failure context.
28
+ * @param {?} args.error - Consumed error.
29
+ * @returns {void} - No return value.
30
+ */
31
+ _emitFrameworkError({ context, error }: {
32
+ context: string;
33
+ error: unknown;
34
+ }): void;
35
+ /**
36
+ * Authorizes the request with a constant-time bearer-token comparison and
37
+ * runs the action body only when authorized. Renders a 401 otherwise. The
38
+ * base controller has no before-action halting, so authorization is enforced
39
+ * here per action. Tokens are only accepted through the Authorization header
40
+ * — never through URLs — and are never rendered back.
41
+ * @param {() => Promise<void>} actionFn - Action body.
42
+ * @returns {Promise<void>} - Resolves when complete.
43
+ */
44
+ _respond(actionFn: () => Promise<void>): Promise<void>;
45
+ /**
46
+ * Creates a deployment run for an allowlisted project/stage and a full
47
+ * immutable revision reachable from the approved release branch. Idempotent:
48
+ * a retried idempotency key reads the original run, a reused key with a
49
+ * different payload conflicts, and an active run for the same project/stage
50
+ * returns a bounded conflict.
51
+ * @returns {Promise<void>} - Resolves when complete.
52
+ */
53
+ create(): Promise<void>;
54
+ /**
55
+ * Renders a previously created run for an idempotency-key hit: a replay when
56
+ * the payload matches, a bounded conflict when it doesn't.
57
+ * @param {object} args - Options.
58
+ * @param {import("./run-store.js").DeploymentRunRow} args.existingRun - The stored run.
59
+ * @param {string} args.project - Requested project.
60
+ * @param {string} args.revision - Requested revision.
61
+ * @param {string} args.stage - Requested stage.
62
+ * @returns {Promise<void>} - Resolves when complete.
63
+ */
64
+ _renderExistingRun({ existingRun, project, revision, stage }: {
65
+ existingRun: import("./run-store.js").DeploymentRunRow;
66
+ project: string;
67
+ revision: string;
68
+ stage: string;
69
+ }): Promise<void>;
70
+ /**
71
+ * Returns the bounded state of a single run, enriched with the adapter's
72
+ * live status when the integration provides one.
73
+ * @returns {Promise<void>} - Resolves when complete.
74
+ */
75
+ show(): Promise<void>;
76
+ /**
77
+ * Executes a created run asynchronously: registers it as active in this
78
+ * process, marks it running, heartbeats its ownership lease while the
79
+ * adapter deploys, and records the sanitized outcome. A deployment failure
80
+ * is an expected operational result — it is persisted with its sanitized
81
+ * recovery information instead of being raised, so it stays visible through
82
+ * readback and audit rather than crashing the worker.
83
+ * @param {object} args - Options.
84
+ * @param {import("./registry.js").DeploymentMountOptions} args.options - Mount options.
85
+ * @param {import("./run-store.js").DeploymentRunRow} args.run - The created run.
86
+ * @returns {Promise<void>} - Resolves when the outcome is recorded.
87
+ */
88
+ _executeRun({ options, run }: {
89
+ options: import("./registry.js").DeploymentMountOptions;
90
+ run: import("./run-store.js").DeploymentRunRow;
91
+ }): Promise<void>;
92
+ /**
93
+ * Records a sanitized audit event. Audit persistence must never strand or
94
+ * suppress a deployment, so a failure here is reported on the
95
+ * framework-error and unified all-error channels (where process-level bug
96
+ * reporters capture it), and execution continues.
97
+ * @param {object} args - Options.
98
+ * @param {string} args.event - Event name.
99
+ * @param {Record<string, ?>} args.payload - Payload; sanitized and redacted before persistence.
100
+ * @param {string | null} args.runId - Owning run id.
101
+ * @returns {Promise<void>} - Resolves when recorded or reported.
102
+ */
103
+ _audit({ event, payload, runId }: {
104
+ event: string;
105
+ payload: Record<string, unknown>;
106
+ runId: string | null;
107
+ }): Promise<void>;
108
+ /**
109
+ * Serializes a run for the API.
110
+ * @param {import("./run-store.js").DeploymentRunRow} run - Run row.
111
+ * @returns {Record<string, ?>} - Serialized run.
112
+ */
113
+ _serializeRun(run: import("./run-store.js").DeploymentRunRow): Record<string, unknown>;
114
+ }
115
+ import Controller from "../controller.js";
116
+ import DeploymentRunStore from "./run-store.js";
117
+ //# sourceMappingURL=controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../src/deployment-api/controller.js"],"names":[],"mappings":"AA+BA;;;;;;;;GAQG;AACH;IACE;;;OAGG;IACH,iBAFa,OAAO,eAAe,EAAE,sBAAsB,CAS1D;IAED;;;OAGG;IACH,UAFa,kBAAkB,CAa9B;IATG,oDAKE;IAMN;;;;;;;;OAQG;IACH,wCAJG;QAAqB,OAAO,EAApB,MAAM;QACE,KAAK,EAAb,OAAC;KACT,GAAU,IAAI,CAQhB;IAED;;;;;;;;OAQG;IACH,mBAHW,MAAM,OAAO,CAAC,IAAI,CAAC,GACjB,OAAO,CAAC,IAAI,CAAC,CAqBzB;IAED;;;;;;;OAOG;IACH,UAFa,OAAO,CAAC,IAAI,CAAC,CAsGzB;IAED;;;;;;;;;OASG;IACH,8DANG;QAAwD,WAAW,EAA3D,OAAO,gBAAgB,EAAE,gBAAgB;QAC5B,OAAO,EAApB,MAAM;QACO,QAAQ,EAArB,MAAM;QACO,KAAK,EAAlB,MAAM;KACd,GAAU,OAAO,CAAC,IAAI,CAAC,CAWzB;IAED;;;;OAIG;IACH,QAFa,OAAO,CAAC,IAAI,CAAC,CA2BzB;IAED;;;;;;;;;;;OAWG;IACH,8BAJG;QAA6D,OAAO,EAA5D,OAAO,eAAe,EAAE,sBAAsB;QACE,GAAG,EAAnD,OAAO,gBAAgB,EAAE,gBAAgB;KACjD,GAAU,OAAO,CAAC,IAAI,CAAC,CAsGzB;IAED;;;;;;;;;;OAUG;IACH,kCALG;QAAqB,KAAK,EAAlB,MAAM;QACkB,OAAO,EAA/B,MAAM,CAAC,MAAM,EAAE,OAAC,CAAC;QACG,KAAK,EAAzB,MAAM,GAAG,IAAI;KACrB,GAAU,OAAO,CAAC,IAAI,CAAC,CAUzB;IAED;;;;OAIG;IACH,mBAHW,OAAO,gBAAgB,EAAE,gBAAgB,GACvC,MAAM,CAAC,MAAM,EAAE,OAAC,CAAC,CAgB7B;CACF;uBAlbsB,kBAAkB;+BACoD,gBAAgB"}
@@ -0,0 +1,384 @@
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udHJvbGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9kZXBsb3ltZW50LWFwaS9jb250cm9sbGVyLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWixPQUFPLFVBQVUsTUFBTSxrQkFBa0IsQ0FBQTtBQUN6QyxPQUFPLGtCQUFrQixFQUFFLEVBQUMsMkJBQTJCLEVBQUUsNkJBQTZCLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQTtBQUM3RyxPQUFPLEVBQUMsV0FBVyxFQUFFLGlCQUFpQixFQUFDLE1BQU0sMEJBQTBCLENBQUE7QUFDdkUsT0FBTyxFQUFDLGtCQUFrQixFQUFDLE1BQU0sZUFBZSxDQUFBO0FBQ2hELE9BQU8sRUFBQyxvQkFBb0IsRUFBRSxvQkFBb0IsRUFBQyxNQUFNLGVBQWUsQ0FBQTtBQUV4RSxNQUFNLGdCQUFnQixHQUFHLGdCQUFnQixDQUFBO0FBQ3pDLE1BQU0sMEJBQTBCLEdBQUcsR0FBRyxDQUFBO0FBRXRDOzs7Ozs7Ozs7R0FTRztBQUNILFNBQVMsa0JBQWtCLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxLQUFLO0lBQ2pELElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUsT0FBTyxDQUFDO1FBQUUsT0FBTyxTQUFTLENBQUE7SUFFL0QsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxNQUFNLENBQUE7SUFFL0MsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLEtBQUssQ0FBQztRQUFFLE9BQU8sU0FBUyxDQUFBO0lBRW5ELE9BQU8sTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFBO0FBQ3RCLENBQUM7QUFFRDs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sQ0FBQyxPQUFPLE9BQU8sZ0NBQWlDLFNBQVEsVUFBVTtJQUN0RTs7O09BR0c7SUFDSCxhQUFhO1FBQ1gsTUFBTSxFQUFFLEdBQUcscUJBQXFCLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsMEJBQTBCLENBQUMsQ0FBQTtRQUMzRSxNQUFNLE9BQU8sR0FBRyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQTtRQUUvRCxJQUFJLENBQUMsT0FBTztZQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMseUNBQXlDLEVBQUUsRUFBRSxDQUFDLENBQUE7UUFFNUUsT0FBTyxPQUFPLENBQUE7SUFDaEIsQ0FBQztJQUVEOzs7T0FHRztJQUNILE1BQU07UUFDSixJQUFJLENBQUMsSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUM7WUFDOUIsSUFBSSxDQUFDLG1CQUFtQixHQUFHLElBQUksa0JBQWtCLENBQUM7Z0JBQ2hELGFBQWEsRUFBRSxJQUFJLENBQUMsZ0JBQWdCLEVBQUU7Z0JBQ3RDLGtCQUFrQixFQUFFLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQyxrQkFBa0I7Z0JBQzNELGVBQWUsRUFBRSxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUMsZUFBZTtnQkFDckQsaUJBQWlCLEVBQUUsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDLGlCQUFpQjthQUMxRCxDQUFDLENBQUE7UUFDSixDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUMsbUJBQW1CLENBQUE7SUFDakMsQ0FBQztJQUVEOzs7Ozs7OztPQVFHO0lBQ0gsbUJBQW1CLENBQUMsRUFBQyxPQUFPLEVBQUUsS0FBSyxFQUFDO1FBQ2xDLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDLGNBQWMsRUFBRSxDQUFBO1FBQzVELE1BQU0sT0FBTyxHQUFHLEVBQUMsT0FBTyxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsSUFBSSxDQUFDLFVBQVUsRUFBRSxFQUFDLENBQUE7UUFFNUQsV0FBVyxDQUFDLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxPQUFPLENBQUMsQ0FBQTtRQUM1QyxXQUFXLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxFQUFDLEdBQUcsT0FBTyxFQUFFLFNBQVMsRUFBRSxpQkFBaUIsRUFBQyxDQUFDLENBQUE7SUFDM0UsQ0FBQztJQUVEOzs7Ozs7OztPQVFHO0lBQ0gsS0FBSyxDQUFDLFFBQVEsQ0FBQyxRQUFRO1FBQ3JCLE1BQU0sS0FBSyxHQUFHLFdBQVcsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQTtRQUN6QyxJQUFJLFVBQVUsR0FBRyxLQUFLLENBQUE7UUFFdEIsSUFBSSxLQUFLLEVBQUUsQ0FBQztZQUNWLEtBQUssTUFBTSxXQUFXLElBQUksSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDLFlBQVksRUFBRSxDQUFDO2dCQUM1RCxJQUFJLGlCQUFpQixDQUFDLEtBQUssRUFBRSxXQUFXLENBQUMsRUFBRSxDQUFDO29CQUMxQyxVQUFVLEdBQUcsSUFBSSxDQUFBO29CQUNqQixNQUFLO2dCQUNQLENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztRQUVELElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztZQUNoQixNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBQyxJQUFJLEVBQUUsRUFBQyxLQUFLLEVBQUUsY0FBYyxFQUFDLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBQyxDQUFDLENBQUE7WUFDL0QsT0FBTTtRQUNSLENBQUM7UUFFRCxNQUFNLFFBQVEsRUFBRSxDQUFBO0lBQ2xCLENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0gsS0FBSyxDQUFDLE1BQU07UUFDVixNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxJQUFJLEVBQUU7WUFDN0IsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFBO1lBQzVCLE1BQU0sUUFBUSxHQUFHLE9BQU8sTUFBTSxDQUFDLFFBQVEsS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQTtZQUM3RSxNQUFNLGNBQWMsR0FBRyxPQUFPLE1BQU0sQ0FBQyxjQUFjLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUE7WUFDL0YsTUFBTSxhQUFhLEdBQUcsRUFBRSxDQUFBO1lBRXhCLElBQUksQ0FBQyxRQUFRLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDO2dCQUFFLGFBQWEsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUE7WUFDakYsSUFBSSxDQUFDLGNBQWMsSUFBSSxjQUFjLENBQUMsTUFBTSxLQUFLLENBQUMsSUFBSSxjQUFjLENBQUMsTUFBTSxHQUFHLDBCQUEwQixFQUFFLENBQUM7Z0JBQ3pHLGFBQWEsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsQ0FBQTtZQUN0QyxDQUFDO1lBRUQsSUFBSSxhQUFhLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUM3QixNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBQyxJQUFJLEVBQUUsRUFBQyxLQUFLLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxFQUFFLGFBQWEsRUFBQyxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUMsQ0FBQyxDQUFBO2dCQUN4RixPQUFNO1lBQ1IsQ0FBQztZQUVELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQTtZQUNwQyxNQUFNLE9BQU8sR0FBRyxPQUFPLE1BQU0sQ0FBQyxPQUFPLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUE7WUFDeEUsTUFBTSxLQUFLLEdBQUcsT0FBTyxNQUFNLENBQUMsS0FBSyxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFBO1lBQ2xFLE1BQU0sWUFBWSxHQUFHLGtCQUFrQixDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsS0FBSyxDQUFDLENBQUE7WUFFaEUsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO2dCQUNsQixNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBQyxJQUFJLEVBQUUsRUFBQyxLQUFLLEVBQUUsV0FBVyxFQUFDLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBQyxDQUFDLENBQUE7Z0JBQzVELE9BQU07WUFDUixDQUFDO1lBRUQsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFBO1lBQzNCLE1BQU0sYUFBYSxHQUFHLHFCQUFxQixDQUFDLENBQUMsUUFBUSxDQUFDLENBQUE7WUFDdEQsTUFBTSxtQkFBbUIsR0FBRyxxQkFBcUIsQ0FBQyxDQUFDLGNBQWMsQ0FBQyxDQUFBO1lBRWxFLHFFQUFxRTtZQUNyRSxrQ0FBa0M7WUFDbEMsTUFBTSxXQUFXLEdBQUcsTUFBTSxLQUFLLENBQUMsWUFBWSxDQUFDLG1CQUFtQixDQUFDLENBQUE7WUFFakUsSUFBSSxXQUFXLEVBQUUsQ0FBQztnQkFDaEIsTUFBTSxJQUFJLENBQUMsa0JBQWtCLENBQUMsRUFBQyxXQUFXLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxhQUFhLEVBQUUsS0FBSyxFQUFDLENBQUMsQ0FBQTtnQkFDckYsT0FBTTtZQUNSLENBQUM7WUFFRCxNQUFNLFNBQVMsR0FBRyxNQUFNLE9BQU8sQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUM7Z0JBQ3ZELGFBQWEsRUFBRSxJQUFJLENBQUMsZ0JBQWdCLEVBQUU7Z0JBQ3RDLE9BQU87Z0JBQ1AsYUFBYSxFQUFFLFlBQVksQ0FBQyxhQUFhO2dCQUN6QyxRQUFRLEVBQUUsYUFBYTtnQkFDdkIsS0FBSzthQUNOLENBQUMsQ0FBQTtZQUVGLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztnQkFDZixNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBQyxJQUFJLEVBQUUsRUFBQyxLQUFLLEVBQUUsd0JBQXdCLEVBQUMsRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFDLENBQUMsQ0FBQTtnQkFDekUsT0FBTTtZQUNSLENBQUM7WUFFRCxNQUFNLE9BQU8sR0FBRyxNQUFNLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQztnQkFDOUMsY0FBYyxFQUFFLG1CQUFtQjtnQkFDbkMsT0FBTztnQkFDUCxRQUFRLEVBQUUsYUFBYTtnQkFDdkIsS0FBSzthQUNOLENBQUMsQ0FBQTtZQUVGLElBQUksT0FBTyxDQUFDLE9BQU8sS0FBSyxRQUFRLElBQUksT0FBTyxDQUFDLE9BQU8sS0FBSyxVQUFVLEVBQUUsQ0FBQztnQkFDbkUsTUFBTSxpQkFBaUIsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFBO2dCQUVyQyxJQUFJLENBQUMsaUJBQWlCO29CQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsa0NBQWtDLE9BQU8sQ0FBQyxPQUFPLGlCQUFpQixDQUFDLENBQUE7Z0JBRTNHLE1BQU0sSUFBSSxDQUFDLGtCQUFrQixDQUFDLEVBQUMsV0FBVyxFQUFFLGlCQUFpQixFQUFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsYUFBYSxFQUFFLEtBQUssRUFBQyxDQUFDLENBQUE7Z0JBQ3hHLE9BQU07WUFDUixDQUFDO1lBRUQsSUFBSSxPQUFPLENBQUMsT0FBTyxLQUFLLGFBQWEsRUFBRSxDQUFDO2dCQUN0QyxNQUFNLFNBQVMsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFBO2dCQUU3QixNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBQyxJQUFJLEVBQUUsRUFBQyxLQUFLLEVBQUUsd0JBQXdCLEVBQUUsS0FBSyxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsU0FBUyxFQUFDLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBQyxDQUFDLENBQUE7Z0JBQ3RILE9BQU07WUFDUixDQUFDO1lBRUQsSUFBSSxPQUFPLENBQUMsT0FBTyxLQUFLLHlCQUF5QixFQUFFLENBQUM7Z0JBQ2xELE1BQU0sVUFBVSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUE7Z0JBRTlCLElBQUksQ0FBQyxVQUFVO29CQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsdUVBQXVFLENBQUMsQ0FBQTtnQkFFekcsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLEVBQUMsSUFBSSxFQUFFLEVBQUMsS0FBSyxFQUFFLG9DQUFvQyxFQUFFLEtBQUssRUFBRSxVQUFVLENBQUMsRUFBRSxFQUFDLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBQyxDQUFDLENBQUE7Z0JBQzNHLE9BQU07WUFDUixDQUFDO1lBRUQsTUFBTSxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQTtZQUV2QixJQUFJLENBQUMsR0FBRztnQkFBRSxNQUFNLElBQUksS0FBSyxDQUFDLHVEQUF1RCxDQUFDLENBQUE7WUFFbEYsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLEVBQUMsS0FBSyxFQUFFLGVBQWUsRUFBRSxPQUFPLEVBQUUsRUFBQyxPQUFPLEVBQUUsUUFBUSxFQUFFLGFBQWEsRUFBRSxLQUFLLEVBQUMsRUFBRSxLQUFLLEVBQUUsR0FBRyxDQUFDLEVBQUUsRUFBQyxDQUFDLENBQUE7WUFFOUcsbUVBQW1FO1lBQ25FLHdFQUF3RTtZQUN4RSwrQ0FBK0M7WUFDL0MsSUFBSSxDQUFDLFdBQVcsQ0FBQyxFQUFDLE9BQU8sRUFBRSxHQUFHLEVBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFO2dCQUMvQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsRUFBQyxPQUFPLEVBQUUsNEJBQTRCLEVBQUUsS0FBSyxFQUFDLENBQUMsQ0FBQTtZQUMxRSxDQUFDLENBQUMsQ0FBQTtZQUVGLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFDLElBQUksRUFBRSxFQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxFQUFDLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBQyxDQUFDLENBQUE7UUFDeEUsQ0FBQyxDQUFDLENBQUE7SUFDSixDQUFDO0lBRUQ7Ozs7Ozs7OztPQVNHO0lBQ0gsS0FBSyxDQUFDLGtCQUFrQixDQUFDLEVBQUMsV0FBVyxFQUFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFDO1FBQzlELE1BQU0sV0FBVyxHQUFHLFdBQVcsQ0FBQyxPQUFPLEtBQUssT0FBTyxJQUFJLFdBQVcsQ0FBQyxLQUFLLEtBQUssS0FBSyxJQUFJLFdBQVcsQ0FBQyxRQUFRLEtBQUssUUFBUSxDQUFBO1FBRXZILElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUNqQixNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBQyxJQUFJLEVBQUUsRUFBQyxLQUFLLEVBQUUsc0JBQXNCLEVBQUUsS0FBSyxFQUFFLFdBQVcsQ0FBQyxFQUFFLEVBQUMsRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFDLENBQUMsQ0FBQTtZQUM5RixPQUFNO1FBQ1IsQ0FBQztRQUVELE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFDLElBQUksRUFBRSxFQUFDLFFBQVEsRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLElBQUksQ0FBQyxhQUFhLENBQUMsV0FBVyxDQUFDLEVBQUMsRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFDLENBQUMsQ0FBQTtJQUNoRyxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILEtBQUssQ0FBQyxJQUFJO1FBQ1IsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssSUFBSSxFQUFFO1lBQzdCLE1BQU0sR0FBRyxHQUFHLE1BQU0sSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLFdBQVcsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFBO1lBRXJGLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztnQkFDVCxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBQyxJQUFJLEVBQUUsRUFBQyxLQUFLLEVBQUUsV0FBVyxFQUFDLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBQyxDQUFDLENBQUE7Z0JBQzVELE9BQU07WUFDUixDQUFDO1lBRUQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFBO1lBQ3BDLGdDQUFnQztZQUNoQyxNQUFNLElBQUksR0FBRyxFQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxFQUFDLENBQUE7WUFFM0MsSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLFVBQVUsRUFBRSxDQUFDO2dCQUMvQixNQUFNLFVBQVUsR0FBRyxNQUFNLE9BQU8sQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDO29CQUNsRCxhQUFhLEVBQUUsSUFBSSxDQUFDLGdCQUFnQixFQUFFO29CQUN0QyxPQUFPLEVBQUUsR0FBRyxDQUFDLE9BQU87b0JBQ3BCLEtBQUssRUFBRSxHQUFHLENBQUMsS0FBSztpQkFDakIsQ0FBQyxDQUFBO2dCQUVGLElBQUksQ0FBQyxPQUFPLEdBQUcsb0JBQW9CLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxZQUFZLENBQUMsSUFBSSxJQUFJLENBQUE7WUFDL0UsQ0FBQztZQUVELE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBQyxDQUFDLENBQUE7UUFDOUMsQ0FBQyxDQUFDLENBQUE7SUFDSixDQUFDO0lBRUQ7Ozs7Ozs7Ozs7O09BV0c7SUFDSCxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUMsT0FBTyxFQUFFLEdBQUcsRUFBQztRQUM5QixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUE7UUFDM0IsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLFlBQVksQ0FBQTtRQUNwQyxNQUFNLFlBQVksR0FBRyxrQkFBa0IsQ0FBQyxPQUFPLEVBQUUsR0FBRyxDQUFDLE9BQU8sRUFBRSxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUE7UUFFeEUsSUFBSSxDQUFDLFlBQVk7WUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLGtCQUFrQixHQUFHLENBQUMsRUFBRSwrQkFBK0IsR0FBRyxDQUFDLE9BQU8sSUFBSSxHQUFHLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQTtRQUNySCxJQUFJLENBQUMsR0FBRyxDQUFDLFVBQVU7WUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLGtCQUFrQixHQUFHLENBQUMsRUFBRSwrQkFBK0IsQ0FBQyxDQUFBO1FBRTdGLE1BQU0sVUFBVSxHQUFHLEdBQUcsQ0FBQyxVQUFVLENBQUE7UUFFakMsMkJBQTJCLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFBO1FBRW5DLG9EQUFvRDtRQUNwRCxJQUFJLGNBQWMsR0FBRyxJQUFJLENBQUE7UUFFekIsSUFBSSxDQUFDO1lBQ0gsTUFBTSxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUMsRUFBRSxFQUFFLEdBQUcsQ0FBQyxFQUFFLEVBQUUsV0FBVyxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUUsRUFBQyxDQUFDLENBQUE7WUFFOUQsb0VBQW9FO1lBQ3BFLHVFQUF1RTtZQUN2RSwwQkFBMEI7WUFDMUIsTUFBTSxtQkFBbUIsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFBO1lBRXJGLGNBQWMsR0FBRyxXQUFXLENBQUMsR0FBRyxFQUFFO2dCQUNoQyxLQUFLLENBQUMsU0FBUyxDQUFDLEVBQUMsYUFBYSxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUUsRUFBRSxFQUFFLEVBQUUsR0FBRyxDQUFDLEVBQUUsRUFBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUU7b0JBQ3ZFLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxFQUFDLE9BQU8sRUFBRSwwQkFBMEIsRUFBRSxLQUFLLEVBQUMsQ0FBQyxDQUFBO2dCQUN4RSxDQUFDLENBQUMsQ0FBQTtZQUNKLENBQUMsRUFBRSxtQkFBbUIsQ0FBQyxDQUFBO1lBQ3ZCLGNBQWMsQ0FBQyxLQUFLLEVBQUUsQ0FBQTtZQUV0QixNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBQyxLQUFLLEVBQUUsYUFBYSxFQUFFLE9BQU8sRUFBRSxFQUFDLE9BQU8sRUFBRSxHQUFHLENBQUMsT0FBTyxFQUFFLFFBQVEsRUFBRSxHQUFHLENBQUMsUUFBUSxFQUFFLEtBQUssRUFBRSxHQUFHLENBQUMsS0FBSyxFQUFDLEVBQUUsS0FBSyxFQUFFLEdBQUcsQ0FBQyxFQUFFLEVBQUMsQ0FBQyxDQUFBO1lBRW5JLElBQUksTUFBTSxDQUFBO1lBRVYsSUFBSSxDQUFDO2dCQUNILE1BQU0sR0FBRyxNQUFNLE9BQU8sQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDO29CQUNwQyxhQUFhLEVBQUUsSUFBSSxDQUFDLGdCQUFnQixFQUFFO29CQUN0QyxPQUFPLEVBQUUsR0FBRyxDQUFDLE9BQU87b0JBQ3BCLGFBQWEsRUFBRSxZQUFZLENBQUMsYUFBYTtvQkFDekMsUUFBUSxFQUFFLEdBQUcsQ0FBQyxRQUFRO29CQUN0QixLQUFLLEVBQUUsR0FBRyxDQUFDLEVBQUU7b0JBQ2IsS0FBSyxFQUFFLEdBQUcsQ0FBQyxLQUFLO2lCQUNqQixDQUFDLENBQUE7WUFDSixDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDZixNQUFNLFlBQVksR0FBRyxvQkFBb0IsQ0FBQyxLQUFLLEVBQUUsT0FBTyxDQUFDLENBQUE7Z0JBRXpELElBQUksQ0FBQztvQkFDSCxNQUFNLEtBQUssQ0FBQyxVQUFVLENBQUMsRUFBQyxLQUFLLEVBQUUsWUFBWSxFQUFFLFlBQVksRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFLEVBQUUsRUFBRSxFQUFFLEdBQUcsQ0FBQyxFQUFFLEVBQUUsVUFBVSxFQUFDLENBQUMsQ0FBQTtvQkFDL0YsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDO3dCQUNoQixLQUFLLEVBQUUsWUFBWTt3QkFDbkIsT0FBTyxFQUFFLEVBQUMsT0FBTyxFQUFFLFlBQVksQ0FBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLEdBQUcsQ0FBQyxPQUFPLEVBQUUsUUFBUSxFQUFFLEdBQUcsQ0FBQyxRQUFRLEVBQUUsS0FBSyxFQUFFLEdBQUcsQ0FBQyxLQUFLLEVBQUM7d0JBQ3hHLEtBQUssRUFBRSxHQUFHLENBQUMsRUFBRTtxQkFDZCxDQUFDLENBQUE7Z0JBQ0osQ0FBQztnQkFBQyxPQUFPLFVBQVUsRUFBRSxDQUFDO29CQUNwQixrRUFBa0U7b0JBQ2xFLHFEQUFxRDtvQkFDckQsSUFBSSxDQUFDLG1CQUFtQixDQUFDLEVBQUMsT0FBTyxFQUFFLCtCQUErQixFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUMsQ0FBQyxDQUFBO2dCQUN6RixDQUFDO2dCQUVELE9BQU07WUFDUixDQUFDO1lBRUQsSUFBSSxDQUFDO2dCQUNILE1BQU0sTUFBTSxHQUFHLG9CQUFvQixDQUFDLE1BQU0sSUFBSSxFQUFFLEVBQUUsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFBO2dCQUVoRSxNQUFNLEtBQUssQ0FBQyxhQUFhLENBQUMsRUFBQyxZQUFZLEVBQUUsSUFBSSxDQUFDLEdBQUcsRUFBRSxFQUFFLEVBQUUsRUFBRSxHQUFHLENBQUMsRUFBRSxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUMsQ0FBQyxDQUFBO2dCQUNyRixNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBQyxLQUFLLEVBQUUsZUFBZSxFQUFFLE9BQU8sRUFBRSxFQUFDLE9BQU8sRUFBRSxHQUFHLENBQUMsT0FBTyxFQUFFLFFBQVEsRUFBRSxHQUFHLENBQUMsUUFBUSxFQUFFLEtBQUssRUFBRSxHQUFHLENBQUMsS0FBSyxFQUFDLEVBQUUsS0FBSyxFQUFFLEdBQUcsQ0FBQyxFQUFFLEVBQUMsQ0FBQyxDQUFBO1lBQ3ZJLENBQUM7WUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO2dCQUNmLHFFQUFxRTtnQkFDckUsa0VBQWtFO2dCQUNsRSxpRUFBaUU7Z0JBQ2pFLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxFQUFDLE9BQU8sRUFBRSwrQkFBK0IsRUFBRSxLQUFLLEVBQUMsQ0FBQyxDQUFBO2dCQUUzRSxNQUFNLG1CQUFtQixHQUFHO29CQUMxQixPQUFPLEVBQUUsNkdBQTZHO2lCQUN2SCxDQUFBO2dCQUVELElBQUksQ0FBQztvQkFDSCxNQUFNLEtBQUssQ0FBQywwQkFBMEIsQ0FBQzt3QkFDckMsS0FBSyxFQUFFLG1CQUFtQjt3QkFDMUIsWUFBWSxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUU7d0JBQ3hCLEVBQUUsRUFBRSxHQUFHLENBQUMsRUFBRTt3QkFDVixVQUFVO3FCQUNYLENBQUMsQ0FBQTtvQkFDRixNQUFNLElBQUksQ0FBQyxNQUFNLENBQUM7d0JBQ2hCLEtBQUssRUFBRSw2QkFBNkI7d0JBQ3BDLE9BQU8sRUFBRSxFQUFDLE9BQU8sRUFBRSxtQkFBbUIsQ0FBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLEdBQUcsQ0FBQyxPQUFPLEVBQUUsUUFBUSxFQUFFLEdBQUcsQ0FBQyxRQUFRLEVBQUUsS0FBSyxFQUFFLEdBQUcsQ0FBQyxLQUFLLEVBQUM7d0JBQy9HLEtBQUssRUFBRSxHQUFHLENBQUMsRUFBRTtxQkFDZCxDQUFDLENBQUE7Z0JBQ0osQ0FBQztnQkFBQyxPQUFPLG1DQUFtQyxFQUFFLENBQUM7b0JBQzdDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQzt3QkFDdkIsT0FBTyxFQUFFLCtDQUErQzt3QkFDeEQsS0FBSyxFQUFFLG1DQUFtQztxQkFDM0MsQ0FBQyxDQUFBO2dCQUNKLENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztnQkFBUyxDQUFDO1lBQ1QsSUFBSSxjQUFjO2dCQUFFLGFBQWEsQ0FBQyxjQUFjLENBQUMsQ0FBQTtZQUNqRCw2QkFBNkIsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUE7UUFDdkMsQ0FBQztJQUNILENBQUM7SUFFRDs7Ozs7Ozs7OztPQVVHO0lBQ0gsS0FBSyxDQUFDLE1BQU0sQ0FBQyxFQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFDO1FBQ2xDLE1BQU0sU0FBUyxHQUFHLG9CQUFvQixDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxDQUFBO1FBRXhGLElBQUksQ0FBQztZQUNILE1BQU0sSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLGFBQWEsQ0FBQyxFQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBQyxDQUFDLENBQUE7UUFDdkUsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixJQUFJLENBQUMsbUJBQW1CLENBQUMsRUFBQyxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsS0FBSyxFQUFDLENBQUMsQ0FBQTtRQUNwRSxDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxhQUFhLENBQUMsR0FBRztRQUNmLE9BQU87WUFDTCxLQUFLLEVBQUUsR0FBRyxDQUFDLEtBQUs7WUFDaEIsWUFBWSxFQUFFLEdBQUcsQ0FBQyxZQUFZO1lBQzlCLEVBQUUsRUFBRSxHQUFHLENBQUMsRUFBRTtZQUNWLGNBQWMsRUFBRSxHQUFHLENBQUMsY0FBYztZQUNsQyxPQUFPLEVBQUUsR0FBRyxDQUFDLE9BQU87WUFDcEIsYUFBYSxFQUFFLEdBQUcsQ0FBQyxhQUFhO1lBQ2hDLE1BQU0sRUFBRSxHQUFHLENBQUMsTUFBTTtZQUNsQixRQUFRLEVBQUUsR0FBRyxDQUFDLFFBQVE7WUFDdEIsS0FBSyxFQUFFLEdBQUcsQ0FBQyxLQUFLO1lBQ2hCLFdBQVcsRUFBRSxHQUFHLENBQUMsV0FBVztZQUM1QixNQUFNLEVBQUUsR0FBRyxDQUFDLE1BQU07U0FDbkIsQ0FBQTtJQUNILENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG5pbXBvcnQgQ29udHJvbGxlciBmcm9tIFwiLi4vY29udHJvbGxlci5qc1wiXG5pbXBvcnQgRGVwbG95bWVudFJ1blN0b3JlLCB7cmVnaXN0ZXJBY3RpdmVEZXBsb3ltZW50UnVuLCB1bnJlZ2lzdGVyQWN0aXZlRGVwbG95bWVudFJ1bn0gZnJvbSBcIi4vcnVuLXN0b3JlLmpzXCJcbmltcG9ydCB7YmVhcmVyVG9rZW4sIGNvbnN0YW50VGltZUVxdWFsfSBmcm9tIFwiLi4vdXRpbHMvYmVhcmVyLXRva2VuLmpzXCJcbmltcG9ydCB7Z2V0RGVwbG95bWVudE1vdW50fSBmcm9tIFwiLi9yZWdpc3RyeS5qc1wiXG5pbXBvcnQge3Nhbml0aXplQWRhcHRlclZhbHVlLCBzYW5pdGl6ZUVycm9yUGF5bG9hZH0gZnJvbSBcIi4vc2FuaXRpemUuanNcIlxuXG5jb25zdCBSRVZJU0lPTl9QQVRURVJOID0gL15bMC05YS1mXXs0MH0kL1xuY29uc3QgTUFYX0lERU1QT1RFTkNZX0tFWV9MRU5HVEggPSAyNTVcblxuLyoqXG4gKiBSZXNvbHZlcyBhbGxvd2xpc3RlZCBzdGFnZSBvcHRpb25zIHdpdGggb3duLXByb3BlcnR5IGNoZWNrcyBvbmx5LCBzb1xuICogcmVxdWVzdC1jb250cm9sbGVkIG5hbWVzIGxpa2UgXCJfX3Byb3RvX19cIiBvciBcImNvbnN0cnVjdG9yXCIgY2FuIG5ldmVyXG4gKiByZXNvbHZlIGluaGVyaXRlZCB2YWx1ZXMuIFRoZSBub3JtYWxpemVkIG1hcHMgYXJlIGFsc28gbnVsbC1wcm90b3R5cGUsIHNvXG4gKiB0aGlzIGlzIGRlZmVuc2UgaW4gZGVwdGguXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4vcmVnaXN0cnkuanNcIikuRGVwbG95bWVudE1vdW50T3B0aW9uc30gb3B0aW9ucyAtIE1vdW50IG9wdGlvbnMuXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvamVjdCAtIFJlcXVlc3RlZCBwcm9qZWN0IGlkZW50aWZpZXIuXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RhZ2UgLSBSZXF1ZXN0ZWQgc3RhZ2UgaWRlbnRpZmllci5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuL3JlZ2lzdHJ5LmpzXCIpLkRlcGxveW1lbnRTdGFnZU9wdGlvbnMgfCB1bmRlZmluZWR9IC0gU3RhZ2Ugb3B0aW9ucyB3aGVuIGFsbG93bGlzdGVkLlxuICovXG5mdW5jdGlvbiBsb29rdXBTdGFnZU9wdGlvbnMob3B0aW9ucywgcHJvamVjdCwgc3RhZ2UpIHtcbiAgaWYgKCFPYmplY3QuaGFzT3duKG9wdGlvbnMucHJvamVjdHMsIHByb2plY3QpKSByZXR1cm4gdW5kZWZpbmVkXG5cbiAgY29uc3Qgc3RhZ2VzID0gb3B0aW9ucy5wcm9qZWN0c1twcm9qZWN0XS5zdGFnZXNcblxuICBpZiAoIU9iamVjdC5oYXNPd24oc3RhZ2VzLCBzdGFnZSkpIHJldHVybiB1bmRlZmluZWRcblxuICByZXR1cm4gc3RhZ2VzW3N0YWdlXVxufVxuXG4vKipcbiAqIEF1dGhlbnRpY2F0ZWQgSFRUUCBBUEkgZm9yIGNhbGxhYmxlIGRlcGxveW1lbnRzLiBNb3VudGVkIGJ5XG4gKiB7QGxpbmsgaW1wb3J0KFwiLi9pbmRleC5qc1wiKS5kZWZhdWx0fSBhcyBhIHJvdXRlLXJlc29sdmVyIGhvb2sgc28gaXQgY2FuIHNoaXBcbiAqIGluc2lkZSB0aGUgdmVsb2Npb3VzIHBhY2thZ2UuIEV2ZXJ5IGFjdGlvbiBpcyBnYXRlZCBieSBhIGJlYXJlci10b2tlbiBjaGVja1xuICogYWdhaW5zdCB0aGUgY29uZmlndXJlZCBhY2Nlc3MgdG9rZW5zOyB0aGUgQVBJIGV4cG9zZXMgb25seSBhbGxvd2xpc3RlZFxuICogcHJvamVjdC9zdGFnZSBwYWlycyBhbmQgZnVsbCBpbW11dGFibGUgcmV2aXNpb25zLCBhbmQgZGVsZWdhdGVzIGFsbFxuICogZXhlY3V0aW9uIHRvIHRoZSBjb25maWd1cmVkIGFkYXB0ZXIuIEl0IG5ldmVyIGFjY2VwdHMgY29tbWFuZHMsIHBhdGhzLFxuICogYXJiaXRyYXJ5IHJlZnMsIGVudmlyb25tZW50IHZhcmlhYmxlcywgb3IgcmF3IGxvZyBvdXRwdXQuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFZlbG9jaW91c0RlcGxveW1lbnRBcGlDb250cm9sbGVyIGV4dGVuZHMgQ29udHJvbGxlciB7XG4gIC8qKlxuICAgKiBSdW5zIG1vdW50IG9wdGlvbnMuXG4gICAqIEByZXR1cm5zIHtpbXBvcnQoXCIuL3JlZ2lzdHJ5LmpzXCIpLkRlcGxveW1lbnRNb3VudE9wdGlvbnN9IC0gT3B0aW9ucyBmb3IgdGhlIG1vdW50IHRoYXQgbWF0Y2hlZCB0aGlzIHJlcXVlc3QuXG4gICAqL1xuICBfbW91bnRPcHRpb25zKCkge1xuICAgIGNvbnN0IGF0ID0gLyoqIEB0eXBlIHtzdHJpbmd9ICovICh0aGlzLnBhcmFtcygpLnZlbG9jaW91c0RlcGxveW1lbnRNb3VudEF0KVxuICAgIGNvbnN0IG9wdGlvbnMgPSBnZXREZXBsb3ltZW50TW91bnQodGhpcy5nZXRDb25maWd1cmF0aW9uKCksIGF0KVxuXG4gICAgaWYgKCFvcHRpb25zKSB0aHJvdyBuZXcgRXJyb3IoYE5vIGRlcGxveW1lbnQgQVBJIG1vdW50IHJlZ2lzdGVyZWQgYXQgJHthdH1gKVxuXG4gICAgcmV0dXJuIG9wdGlvbnNcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHN0b3JlLlxuICAgKiBAcmV0dXJucyB7RGVwbG95bWVudFJ1blN0b3JlfSAtIFJ1biBzdG9yZSBzY29wZWQgdG8gdGhlIG1vdW50J3MgZGF0YWJhc2UuXG4gICAqL1xuICBfc3RvcmUoKSB7XG4gICAgaWYgKCF0aGlzLl9kZXBsb3ltZW50UnVuU3RvcmUpIHtcbiAgICAgIHRoaXMuX2RlcGxveW1lbnRSdW5TdG9yZSA9IG5ldyBEZXBsb3ltZW50UnVuU3RvcmUoe1xuICAgICAgICBjb25maWd1cmF0aW9uOiB0aGlzLmdldENvbmZpZ3VyYXRpb24oKSxcbiAgICAgICAgZGF0YWJhc2VJZGVudGlmaWVyOiB0aGlzLl9tb3VudE9wdGlvbnMoKS5kYXRhYmFzZUlkZW50aWZpZXIsXG4gICAgICAgIG1vdW50SWRlbnRpZmllcjogdGhpcy5fbW91bnRPcHRpb25zKCkubW91bnRJZGVudGlmaWVyLFxuICAgICAgICBzdGFsZVJ1blRpbWVvdXRNczogdGhpcy5fbW91bnRPcHRpb25zKCkuc3RhbGVSdW5UaW1lb3V0TXNcbiAgICAgIH0pXG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuX2RlcGxveW1lbnRSdW5TdG9yZVxuICB9XG5cbiAgLyoqXG4gICAqIFJlcG9ydHMgb25lIGludGVybmFsbHkgY29uc3VtZWQgZnJhbWV3b3JrIGZhaWx1cmUgb24gYm90aCBkb2N1bWVudGVkXG4gICAqIGVycm9yIGNoYW5uZWxzIHNvIGZyYW1ld29yay1zcGVjaWZpYyBhbmQgdW5pZmllZCByZXBvcnRlcnMgc2VlIHRoZSBzYW1lXG4gICAqIHBheWxvYWQuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gT3B0aW9ucy5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGFyZ3MuY29udGV4dCAtIERlcGxveW1lbnQgQVBJIGZhaWx1cmUgY29udGV4dC5cbiAgICogQHBhcmFtIHs/fSBhcmdzLmVycm9yIC0gQ29uc3VtZWQgZXJyb3IuXG4gICAqIEByZXR1cm5zIHt2b2lkfSAtIE5vIHJldHVybiB2YWx1ZS5cbiAgICovXG4gIF9lbWl0RnJhbWV3b3JrRXJyb3Ioe2NvbnRleHQsIGVycm9yfSkge1xuICAgIGNvbnN0IGVycm9yRXZlbnRzID0gdGhpcy5nZXRDb25maWd1cmF0aW9uKCkuZ2V0RXJyb3JFdmVudHMoKVxuICAgIGNvbnN0IHBheWxvYWQgPSB7Y29udGV4dCwgZXJyb3IsIHJlcXVlc3Q6IHRoaXMuZ2V0UmVxdWVzdCgpfVxuXG4gICAgZXJyb3JFdmVudHMuZW1pdChcImZyYW1ld29yay1lcnJvclwiLCBwYXlsb2FkKVxuICAgIGVycm9yRXZlbnRzLmVtaXQoXCJhbGwtZXJyb3JcIiwgey4uLnBheWxvYWQsIGVycm9yVHlwZTogXCJmcmFtZXdvcmstZXJyb3JcIn0pXG4gIH1cblxuICAvKipcbiAgICogQXV0aG9yaXplcyB0aGUgcmVxdWVzdCB3aXRoIGEgY29uc3RhbnQtdGltZSBiZWFyZXItdG9rZW4gY29tcGFyaXNvbiBhbmRcbiAgICogcnVucyB0aGUgYWN0aW9uIGJvZHkgb25seSB3aGVuIGF1dGhvcml6ZWQuIFJlbmRlcnMgYSA0MDEgb3RoZXJ3aXNlLiBUaGVcbiAgICogYmFzZSBjb250cm9sbGVyIGhhcyBubyBiZWZvcmUtYWN0aW9uIGhhbHRpbmcsIHNvIGF1dGhvcml6YXRpb24gaXMgZW5mb3JjZWRcbiAgICogaGVyZSBwZXIgYWN0aW9uLiBUb2tlbnMgYXJlIG9ubHkgYWNjZXB0ZWQgdGhyb3VnaCB0aGUgQXV0aG9yaXphdGlvbiBoZWFkZXJcbiAgICog4oCUIG5ldmVyIHRocm91Z2ggVVJMcyDigJQgYW5kIGFyZSBuZXZlciByZW5kZXJlZCBiYWNrLlxuICAgKiBAcGFyYW0geygpID0+IFByb21pc2U8dm9pZD59IGFjdGlvbkZuIC0gQWN0aW9uIGJvZHkuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gY29tcGxldGUuXG4gICAqL1xuICBhc3luYyBfcmVzcG9uZChhY3Rpb25Gbikge1xuICAgIGNvbnN0IHRva2VuID0gYmVhcmVyVG9rZW4odGhpcy5yZXF1ZXN0KCkpXG4gICAgbGV0IGF1dGhvcml6ZWQgPSBmYWxzZVxuXG4gICAgaWYgKHRva2VuKSB7XG4gICAgICBmb3IgKGNvbnN0IGFjY2Vzc1Rva2VuIG9mIHRoaXMuX21vdW50T3B0aW9ucygpLmFjY2Vzc1Rva2Vucykge1xuICAgICAgICBpZiAoY29uc3RhbnRUaW1lRXF1YWwodG9rZW4sIGFjY2Vzc1Rva2VuKSkge1xuICAgICAgICAgIGF1dGhvcml6ZWQgPSB0cnVlXG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIGlmICghYXV0aG9yaXplZCkge1xuICAgICAgYXdhaXQgdGhpcy5yZW5kZXIoe2pzb246IHtlcnJvcjogXCJ1bmF1dGhvcml6ZWRcIn0sIHN0YXR1czogNDAxfSlcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIGF3YWl0IGFjdGlvbkZuKClcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgZGVwbG95bWVudCBydW4gZm9yIGFuIGFsbG93bGlzdGVkIHByb2plY3Qvc3RhZ2UgYW5kIGEgZnVsbFxuICAgKiBpbW11dGFibGUgcmV2aXNpb24gcmVhY2hhYmxlIGZyb20gdGhlIGFwcHJvdmVkIHJlbGVhc2UgYnJhbmNoLiBJZGVtcG90ZW50OlxuICAgKiBhIHJldHJpZWQgaWRlbXBvdGVuY3kga2V5IHJlYWRzIHRoZSBvcmlnaW5hbCBydW4sIGEgcmV1c2VkIGtleSB3aXRoIGFcbiAgICogZGlmZmVyZW50IHBheWxvYWQgY29uZmxpY3RzLCBhbmQgYW4gYWN0aXZlIHJ1biBmb3IgdGhlIHNhbWUgcHJvamVjdC9zdGFnZVxuICAgKiByZXR1cm5zIGEgYm91bmRlZCBjb25mbGljdC5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgd2hlbiBjb21wbGV0ZS5cbiAgICovXG4gIGFzeW5jIGNyZWF0ZSgpIHtcbiAgICBhd2FpdCB0aGlzLl9yZXNwb25kKGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHBhcmFtcyA9IHRoaXMucGFyYW1zKClcbiAgICAgIGNvbnN0IHJldmlzaW9uID0gdHlwZW9mIHBhcmFtcy5yZXZpc2lvbiA9PT0gXCJzdHJpbmdcIiA/IHBhcmFtcy5yZXZpc2lvbiA6IG51bGxcbiAgICAgIGNvbnN0IGlkZW1wb3RlbmN5S2V5ID0gdHlwZW9mIHBhcmFtcy5pZGVtcG90ZW5jeUtleSA9PT0gXCJzdHJpbmdcIiA/IHBhcmFtcy5pZGVtcG90ZW5jeUtleSA6IG51bGxcbiAgICAgIGNvbnN0IGludmFsaWRGaWVsZHMgPSBbXVxuXG4gICAgICBpZiAoIXJldmlzaW9uIHx8ICFSRVZJU0lPTl9QQVRURVJOLnRlc3QocmV2aXNpb24pKSBpbnZhbGlkRmllbGRzLnB1c2goXCJyZXZpc2lvblwiKVxuICAgICAgaWYgKCFpZGVtcG90ZW5jeUtleSB8fCBpZGVtcG90ZW5jeUtleS5sZW5ndGggPT09IDAgfHwgaWRlbXBvdGVuY3lLZXkubGVuZ3RoID4gTUFYX0lERU1QT1RFTkNZX0tFWV9MRU5HVEgpIHtcbiAgICAgICAgaW52YWxpZEZpZWxkcy5wdXNoKFwiaWRlbXBvdGVuY3lLZXlcIilcbiAgICAgIH1cblxuICAgICAgaWYgKGludmFsaWRGaWVsZHMubGVuZ3RoID4gMCkge1xuICAgICAgICBhd2FpdCB0aGlzLnJlbmRlcih7anNvbjoge2Vycm9yOiBcImludmFsaWRfcGFyYW1zXCIsIGZpZWxkczogaW52YWxpZEZpZWxkc30sIHN0YXR1czogNDIyfSlcbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG9wdGlvbnMgPSB0aGlzLl9tb3VudE9wdGlvbnMoKVxuICAgICAgY29uc3QgcHJvamVjdCA9IHR5cGVvZiBwYXJhbXMucHJvamVjdCA9PT0gXCJzdHJpbmdcIiA/IHBhcmFtcy5wcm9qZWN0IDogXCJcIlxuICAgICAgY29uc3Qgc3RhZ2UgPSB0eXBlb2YgcGFyYW1zLnN0YWdlID09PSBcInN0cmluZ1wiID8gcGFyYW1zLnN0YWdlIDogXCJcIlxuICAgICAgY29uc3Qgc3RhZ2VPcHRpb25zID0gbG9va3VwU3RhZ2VPcHRpb25zKG9wdGlvbnMsIHByb2plY3QsIHN0YWdlKVxuXG4gICAgICBpZiAoIXN0YWdlT3B0aW9ucykge1xuICAgICAgICBhd2FpdCB0aGlzLnJlbmRlcih7anNvbjoge2Vycm9yOiBcIm5vdF9mb3VuZFwifSwgc3RhdHVzOiA0MDR9KVxuICAgICAgICByZXR1cm5cbiAgICAgIH1cblxuICAgICAgY29uc3Qgc3RvcmUgPSB0aGlzLl9zdG9yZSgpXG4gICAgICBjb25zdCB2YWxpZFJldmlzaW9uID0gLyoqIEB0eXBlIHtzdHJpbmd9ICovIChyZXZpc2lvbilcbiAgICAgIGNvbnN0IHZhbGlkSWRlbXBvdGVuY3lLZXkgPSAvKiogQHR5cGUge3N0cmluZ30gKi8gKGlkZW1wb3RlbmN5S2V5KVxuXG4gICAgICAvLyBSZXRyaWVzIHJlYWQgdGhlIG9yaWdpbmFsIHJ1biBiZWZvcmUgYW55dGhpbmcgZWxzZSDigJQgYSByZXBsYXkgbXVzdFxuICAgICAgLy8gbmV2ZXIgcmUtdmFsaWRhdGUgb3IgcmUtZGVwbG95LlxuICAgICAgY29uc3QgZXhpc3RpbmdSdW4gPSBhd2FpdCBzdG9yZS5maW5kUnVuQnlLZXkodmFsaWRJZGVtcG90ZW5jeUtleSlcblxuICAgICAgaWYgKGV4aXN0aW5nUnVuKSB7XG4gICAgICAgIGF3YWl0IHRoaXMuX3JlbmRlckV4aXN0aW5nUnVuKHtleGlzdGluZ1J1biwgcHJvamVjdCwgcmV2aXNpb246IHZhbGlkUmV2aXNpb24sIHN0YWdlfSlcbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHJlYWNoYWJsZSA9IGF3YWl0IG9wdGlvbnMuYWRhcHRlci52YWxpZGF0ZVJldmlzaW9uKHtcbiAgICAgICAgY29uZmlndXJhdGlvbjogdGhpcy5nZXRDb25maWd1cmF0aW9uKCksXG4gICAgICAgIHByb2plY3QsXG4gICAgICAgIHJlbGVhc2VCcmFuY2g6IHN0YWdlT3B0aW9ucy5yZWxlYXNlQnJhbmNoLFxuICAgICAgICByZXZpc2lvbjogdmFsaWRSZXZpc2lvbixcbiAgICAgICAgc3RhZ2VcbiAgICAgIH0pXG5cbiAgICAgIGlmICghcmVhY2hhYmxlKSB7XG4gICAgICAgIGF3YWl0IHRoaXMucmVuZGVyKHtqc29uOiB7ZXJyb3I6IFwicmV2aXNpb25fbm90X3JlYWNoYWJsZVwifSwgc3RhdHVzOiA0MjJ9KVxuICAgICAgICByZXR1cm5cbiAgICAgIH1cblxuICAgICAgY29uc3Qgb3V0Y29tZSA9IGF3YWl0IHN0b3JlLmNyZWF0ZVJ1bklmUG9zc2libGUoe1xuICAgICAgICBpZGVtcG90ZW5jeUtleTogdmFsaWRJZGVtcG90ZW5jeUtleSxcbiAgICAgICAgcHJvamVjdCxcbiAgICAgICAgcmV2aXNpb246IHZhbGlkUmV2aXNpb24sXG4gICAgICAgIHN0YWdlXG4gICAgICB9KVxuXG4gICAgICBpZiAob3V0Y29tZS5vdXRjb21lID09PSBcInJlcGxheVwiIHx8IG91dGNvbWUub3V0Y29tZSA9PT0gXCJjb25mbGljdFwiKSB7XG4gICAgICAgIGNvbnN0IGV4aXN0aW5nRnJvbVN0b3JlID0gb3V0Y29tZS5ydW5cblxuICAgICAgICBpZiAoIWV4aXN0aW5nRnJvbVN0b3JlKSB0aHJvdyBuZXcgRXJyb3IoYERlcGxveW1lbnQgcnVuIHN0b3JlIHJlcG9ydGVkICcke291dGNvbWUub3V0Y29tZX0nIHdpdGhvdXQgYSBydW5gKVxuXG4gICAgICAgIGF3YWl0IHRoaXMuX3JlbmRlckV4aXN0aW5nUnVuKHtleGlzdGluZ1J1bjogZXhpc3RpbmdGcm9tU3RvcmUsIHByb2plY3QsIHJldmlzaW9uOiB2YWxpZFJldmlzaW9uLCBzdGFnZX0pXG4gICAgICAgIHJldHVyblxuICAgICAgfVxuXG4gICAgICBpZiAob3V0Y29tZS5vdXRjb21lID09PSBcImluX3Byb2dyZXNzXCIpIHtcbiAgICAgICAgY29uc3QgYWN0aXZlUnVuID0gb3V0Y29tZS5ydW5cblxuICAgICAgICBhd2FpdCB0aGlzLnJlbmRlcih7anNvbjoge2Vycm9yOiBcImRlcGxveW1lbnRfaW5fcHJvZ3Jlc3NcIiwgcnVuSWQ6IGFjdGl2ZVJ1biA/IGFjdGl2ZVJ1bi5pZCA6IHVuZGVmaW5lZH0sIHN0YXR1czogNDA5fSlcbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIGlmIChvdXRjb21lLm91dGNvbWUgPT09IFwicmVjb25jaWxpYXRpb25fcmVxdWlyZWRcIikge1xuICAgICAgICBjb25zdCBibG9ja2VkUnVuID0gb3V0Y29tZS5ydW5cblxuICAgICAgICBpZiAoIWJsb2NrZWRSdW4pIHRocm93IG5ldyBFcnJvcihcIkRlcGxveW1lbnQgcnVuIHN0b3JlIHJlcG9ydGVkICdyZWNvbmNpbGlhdGlvbl9yZXF1aXJlZCcgd2l0aG91dCBhIHJ1blwiKVxuXG4gICAgICAgIGF3YWl0IHRoaXMucmVuZGVyKHtqc29uOiB7ZXJyb3I6IFwiZGVwbG95bWVudF9yZWNvbmNpbGlhdGlvbl9yZXF1aXJlZFwiLCBydW5JZDogYmxvY2tlZFJ1bi5pZH0sIHN0YXR1czogNDA5fSlcbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHJ1biA9IG91dGNvbWUucnVuXG5cbiAgICAgIGlmICghcnVuKSB0aHJvdyBuZXcgRXJyb3IoXCJEZXBsb3ltZW50IHJ1biBzdG9yZSByZXBvcnRlZCAnY3JlYXRlZCcgd2l0aG91dCBhIHJ1blwiKVxuXG4gICAgICBhd2FpdCB0aGlzLl9hdWRpdCh7ZXZlbnQ6IFwicnVuX3JlcXVlc3RlZFwiLCBwYXlsb2FkOiB7cHJvamVjdCwgcmV2aXNpb246IHZhbGlkUmV2aXNpb24sIHN0YWdlfSwgcnVuSWQ6IHJ1bi5pZH0pXG5cbiAgICAgIC8vIEV4ZWN1dGlvbiBpcyBkZWxpYmVyYXRlbHkgbm90IGF3YWl0ZWQ6IHRoZSBkZXBsb3kgcnVucyB1bmRlciB0aGVcbiAgICAgIC8vIGludGVncmF0aW9uJ3Mgb3duIGxvY2svYnVpbGQvaGVhbHRoL3JvbGxiYWNrIHNlbWFudGljcyBhbmQgdGhlIGNhbGxlclxuICAgICAgLy8gcmVhZHMgcHJvZ3Jlc3MgYmFjayB0aHJvdWdoIHRoZSBzaG93IGFjdGlvbi5cbiAgICAgIHRoaXMuX2V4ZWN1dGVSdW4oe29wdGlvbnMsIHJ1bn0pLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgICB0aGlzLl9lbWl0RnJhbWV3b3JrRXJyb3Ioe2NvbnRleHQ6IFwiZGVwbG95bWVudC1hcGktZXhlY3V0ZS1ydW5cIiwgZXJyb3J9KVxuICAgICAgfSlcblxuICAgICAgYXdhaXQgdGhpcy5yZW5kZXIoe2pzb246IHtydW46IHRoaXMuX3NlcmlhbGl6ZVJ1bihydW4pfSwgc3RhdHVzOiAyMDJ9KVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogUmVuZGVycyBhIHByZXZpb3VzbHkgY3JlYXRlZCBydW4gZm9yIGFuIGlkZW1wb3RlbmN5LWtleSBoaXQ6IGEgcmVwbGF5IHdoZW5cbiAgICogdGhlIHBheWxvYWQgbWF0Y2hlcywgYSBib3VuZGVkIGNvbmZsaWN0IHdoZW4gaXQgZG9lc24ndC5cbiAgICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBPcHRpb25zLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4vcnVuLXN0b3JlLmpzXCIpLkRlcGxveW1lbnRSdW5Sb3d9IGFyZ3MuZXhpc3RpbmdSdW4gLSBUaGUgc3RvcmVkIHJ1bi5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGFyZ3MucHJvamVjdCAtIFJlcXVlc3RlZCBwcm9qZWN0LlxuICAgKiBAcGFyYW0ge3N0cmluZ30gYXJncy5yZXZpc2lvbiAtIFJlcXVlc3RlZCByZXZpc2lvbi5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGFyZ3Muc3RhZ2UgLSBSZXF1ZXN0ZWQgc3RhZ2UuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gY29tcGxldGUuXG4gICAqL1xuICBhc3luYyBfcmVuZGVyRXhpc3RpbmdSdW4oe2V4aXN0aW5nUnVuLCBwcm9qZWN0LCByZXZpc2lvbiwgc3RhZ2V9KSB7XG4gICAgY29uc3Qgc2FtZVBheWxvYWQgPSBleGlzdGluZ1J1bi5wcm9qZWN0ID09PSBwcm9qZWN0ICYmIGV4aXN0aW5nUnVuLnN0YWdlID09PSBzdGFnZSAmJiBleGlzdGluZ1J1bi5yZXZpc2lvbiA9PT0gcmV2aXNpb25cblxuICAgIGlmICghc2FtZVBheWxvYWQpIHtcbiAgICAgIGF3YWl0IHRoaXMucmVuZGVyKHtqc29uOiB7ZXJyb3I6IFwiaWRlbXBvdGVuY3lfY29uZmxpY3RcIiwgcnVuSWQ6IGV4aXN0aW5nUnVuLmlkfSwgc3RhdHVzOiA0MDl9KVxuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgYXdhaXQgdGhpcy5yZW5kZXIoe2pzb246IHtyZXBsYXllZDogdHJ1ZSwgcnVuOiB0aGlzLl9zZXJpYWxpemVSdW4oZXhpc3RpbmdSdW4pfSwgc3RhdHVzOiAyMDB9KVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGJvdW5kZWQgc3RhdGUgb2YgYSBzaW5nbGUgcnVuLCBlbnJpY2hlZCB3aXRoIHRoZSBhZGFwdGVyJ3NcbiAgICogbGl2ZSBzdGF0dXMgd2hlbiB0aGUgaW50ZWdyYXRpb24gcHJvdmlkZXMgb25lLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyB3aGVuIGNvbXBsZXRlLlxuICAgKi9cbiAgYXN5bmMgc2hvdygpIHtcbiAgICBhd2FpdCB0aGlzLl9yZXNwb25kKGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHJ1biA9IGF3YWl0IHRoaXMuX3N0b3JlKCkuZmluZFJ1bkJ5SWQoLyoqIEB0eXBlIHtzdHJpbmd9ICovICh0aGlzLnBhcmFtcygpLmlkKSlcblxuICAgICAgaWYgKCFydW4pIHtcbiAgICAgICAgYXdhaXQgdGhpcy5yZW5kZXIoe2pzb246IHtlcnJvcjogXCJub3RfZm91bmRcIn0sIHN0YXR1czogNDA0fSlcbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG9wdGlvbnMgPSB0aGlzLl9tb3VudE9wdGlvbnMoKVxuICAgICAgLyoqIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gKi9cbiAgICAgIGNvbnN0IGJvZHkgPSB7cnVuOiB0aGlzLl9zZXJpYWxpemVSdW4ocnVuKX1cblxuICAgICAgaWYgKG9wdGlvbnMuYWRhcHRlci5yZWFkU3RhdHVzKSB7XG4gICAgICAgIGNvbnN0IGxpdmVTdGF0dXMgPSBhd2FpdCBvcHRpb25zLmFkYXB0ZXIucmVhZFN0YXR1cyh7XG4gICAgICAgICAgY29uZmlndXJhdGlvbjogdGhpcy5nZXRDb25maWd1cmF0aW9uKCksXG4gICAgICAgICAgcHJvamVjdDogcnVuLnByb2plY3QsXG4gICAgICAgICAgc3RhZ2U6IHJ1bi5zdGFnZVxuICAgICAgICB9KVxuXG4gICAgICAgIGJvZHkuY3VycmVudCA9IHNhbml0aXplQWRhcHRlclZhbHVlKGxpdmVTdGF0dXMsIG9wdGlvbnMuYWNjZXNzVG9rZW5zKSA/PyBudWxsXG4gICAgICB9XG5cbiAgICAgIGF3YWl0IHRoaXMucmVuZGVyKHtqc29uOiBib2R5LCBzdGF0dXM6IDIwMH0pXG4gICAgfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBFeGVjdXRlcyBhIGNyZWF0ZWQgcnVuIGFzeW5jaHJvbm91c2x5OiByZWdpc3RlcnMgaXQgYXMgYWN0aXZlIGluIHRoaXNcbiAgICogcHJvY2VzcywgbWFya3MgaXQgcnVubmluZywgaGVhcnRiZWF0cyBpdHMgb3duZXJzaGlwIGxlYXNlIHdoaWxlIHRoZVxuICAgKiBhZGFwdGVyIGRlcGxveXMsIGFuZCByZWNvcmRzIHRoZSBzYW5pdGl6ZWQgb3V0Y29tZS4gQSBkZXBsb3ltZW50IGZhaWx1cmVcbiAgICogaXMgYW4gZXhwZWN0ZWQgb3BlcmF0aW9uYWwgcmVzdWx0IOKAlCBpdCBpcyBwZXJzaXN0ZWQgd2l0aCBpdHMgc2FuaXRpemVkXG4gICAqIHJlY292ZXJ5IGluZm9ybWF0aW9uIGluc3RlYWQgb2YgYmVpbmcgcmFpc2VkLCBzbyBpdCBzdGF5cyB2aXNpYmxlIHRocm91Z2hcbiAgICogcmVhZGJhY2sgYW5kIGF1ZGl0IHJhdGhlciB0aGFuIGNyYXNoaW5nIHRoZSB3b3JrZXIuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gT3B0aW9ucy5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuL3JlZ2lzdHJ5LmpzXCIpLkRlcGxveW1lbnRNb3VudE9wdGlvbnN9IGFyZ3Mub3B0aW9ucyAtIE1vdW50IG9wdGlvbnMuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi9ydW4tc3RvcmUuanNcIikuRGVwbG95bWVudFJ1blJvd30gYXJncy5ydW4gLSBUaGUgY3JlYXRlZCBydW4uXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gdGhlIG91dGNvbWUgaXMgcmVjb3JkZWQuXG4gICAqL1xuICBhc3luYyBfZXhlY3V0ZVJ1bih7b3B0aW9ucywgcnVufSkge1xuICAgIGNvbnN0IHN0b3JlID0gdGhpcy5fc3RvcmUoKVxuICAgIGNvbnN0IHNlY3JldHMgPSBvcHRpb25zLmFjY2Vzc1Rva2Vuc1xuICAgIGNvbnN0IHN0YWdlT3B0aW9ucyA9IGxvb2t1cFN0YWdlT3B0aW9ucyhvcHRpb25zLCBydW4ucHJvamVjdCwgcnVuLnN0YWdlKVxuXG4gICAgaWYgKCFzdGFnZU9wdGlvbnMpIHRocm93IG5ldyBFcnJvcihgRGVwbG95bWVudCBydW4gJHtydW4uaWR9IHJlZmVyZW5jZXMgbm9uLWFsbG93bGlzdGVkICR7cnVuLnByb2plY3R9LyR7cnVuLnN0YWdlfWApXG4gICAgaWYgKCFydW4ub3duZXJUb2tlbikgdGhyb3cgbmV3IEVycm9yKGBEZXBsb3ltZW50IHJ1biAke3J1bi5pZH0gaGFzIG5vIGV4ZWN1dGlvbiBvd25lciB0b2tlbmApXG5cbiAgICBjb25zdCBvd25lclRva2VuID0gcnVuLm93bmVyVG9rZW5cblxuICAgIHJlZ2lzdGVyQWN0aXZlRGVwbG95bWVudFJ1bihydW4uaWQpXG5cbiAgICAvKiogQHR5cGUge1JldHVyblR5cGU8dHlwZW9mIHNldEludGVydmFsPiB8IG51bGx9ICovXG4gICAgbGV0IGhlYXJ0YmVhdFRpbWVyID0gbnVsbFxuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHN0b3JlLm1hcmtSdW5uaW5nKHtpZDogcnVuLmlkLCBzdGFydGVkQXRNczogRGF0ZS5ub3coKX0pXG5cbiAgICAgIC8vIFJlbmV3IHRoZSBvd25lcnNoaXAgbGVhc2Ugd2hpbGUgdGhlIGRlcGxveSBydW5zIHNvIHJlY29uY2lsaWF0aW9uXG4gICAgICAvLyBuZXZlciByZWNsYWltcyB0aGlzIGdlbnVpbmVseSBhY3RpdmUgcnVuOyB1bnJlZidkIHNvIHRoZSB0aW1lciBhbG9uZVxuICAgICAgLy8ga2VlcHMgbm8gcHJvY2VzcyBhbGl2ZS5cbiAgICAgIGNvbnN0IGhlYXJ0YmVhdEludGVydmFsTXMgPSBNYXRoLm1heCgxMDAwLCBNYXRoLmZsb29yKG9wdGlvbnMuc3RhbGVSdW5UaW1lb3V0TXMgLyA0KSlcblxuICAgICAgaGVhcnRiZWF0VGltZXIgPSBzZXRJbnRlcnZhbCgoKSA9PiB7XG4gICAgICAgIHN0b3JlLmhlYXJ0YmVhdCh7aGVhcnRiZWF0QXRNczogRGF0ZS5ub3coKSwgaWQ6IHJ1bi5pZH0pLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgICAgIHRoaXMuX2VtaXRGcmFtZXdvcmtFcnJvcih7Y29udGV4dDogXCJkZXBsb3ltZW50LWFwaS1oZWFydGJlYXRcIiwgZXJyb3J9KVxuICAgICAgICB9KVxuICAgICAgfSwgaGVhcnRiZWF0SW50ZXJ2YWxNcylcbiAgICAgIGhlYXJ0YmVhdFRpbWVyLnVucmVmKClcblxuICAgICAgYXdhaXQgdGhpcy5fYXVkaXQoe2V2ZW50OiBcInJ1bl9zdGFydGVkXCIsIHBheWxvYWQ6IHtwcm9qZWN0OiBydW4ucHJvamVjdCwgcmV2aXNpb246IHJ1bi5yZXZpc2lvbiwgc3RhZ2U6IHJ1bi5zdGFnZX0sIHJ1bklkOiBydW4uaWR9KVxuXG4gICAgICBsZXQgcmVwb3J0XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIHJlcG9ydCA9IGF3YWl0IG9wdGlvbnMuYWRhcHRlci5kZXBsb3koe1xuICAgICAgICAgIGNvbmZpZ3VyYXRpb246IHRoaXMuZ2V0Q29uZmlndXJhdGlvbigpLFxuICAgICAgICAgIHByb2plY3Q6IHJ1bi5wcm9qZWN0LFxuICAgICAgICAgIHJlbGVhc2VCcmFuY2g6IHN0YWdlT3B0aW9ucy5yZWxlYXNlQnJhbmNoLFxuICAgICAgICAgIHJldmlzaW9uOiBydW4ucmV2aXNpb24sXG4gICAgICAgICAgcnVuSWQ6IHJ1bi5pZCxcbiAgICAgICAgICBzdGFnZTogcnVuLnN0YWdlXG4gICAgICAgIH0pXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zdCBlcnJvclBheWxvYWQgPSBzYW5pdGl6ZUVycm9yUGF5bG9hZChlcnJvciwgc2VjcmV0cylcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IHN0b3JlLm1hcmtGYWlsZWQoe2Vycm9yOiBlcnJvclBheWxvYWQsIGZpbmlzaGVkQXRNczogRGF0ZS5ub3coKSwgaWQ6IHJ1bi5pZCwgb3duZXJUb2tlbn0pXG4gICAgICAgICAgYXdhaXQgdGhpcy5fYXVkaXQoe1xuICAgICAgICAgICAgZXZlbnQ6IFwicnVuX2ZhaWxlZFwiLFxuICAgICAgICAgICAgcGF5bG9hZDoge21lc3NhZ2U6IGVycm9yUGF5bG9hZC5tZXNzYWdlLCBwcm9qZWN0OiBydW4ucHJvamVjdCwgcmV2aXNpb246IHJ1bi5yZXZpc2lvbiwgc3RhZ2U6IHJ1bi5zdGFnZX0sXG4gICAgICAgICAgICBydW5JZDogcnVuLmlkXG4gICAgICAgICAgfSlcbiAgICAgICAgfSBjYXRjaCAoc3RvcmVFcnJvcikge1xuICAgICAgICAgIC8vIFJlY29yZGluZyB0aGUgZmFpbHVyZSBpdHNlbGYgZmFpbGVkIOKAlCB0aGF0IGlzIGFuIHVuZXhwZWN0ZWQgYnVnXG4gICAgICAgICAgLy8gYW5kIG11c3Qgc3VyZmFjZSB0byBwcm9jZXNzLWxldmVsIGVycm9yIHJlcG9ydGVycy5cbiAgICAgICAgICB0aGlzLl9lbWl0RnJhbWV3b3JrRXJyb3Ioe2NvbnRleHQ6IFwiZGVwbG95bWVudC1hcGktcmVjb3JkLWZhaWx1cmVcIiwgZXJyb3I6IHN0b3JlRXJyb3J9KVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IHNhbml0aXplQWRhcHRlclZhbHVlKHJlcG9ydCA/PyB7fSwgc2VjcmV0cykgPz8ge31cblxuICAgICAgICBhd2FpdCBzdG9yZS5tYXJrU3VjY2VlZGVkKHtmaW5pc2hlZEF0TXM6IERhdGUubm93KCksIGlkOiBydW4uaWQsIG93bmVyVG9rZW4sIHJlc3VsdH0pXG4gICAgICAgIGF3YWl0IHRoaXMuX2F1ZGl0KHtldmVudDogXCJydW5fc3VjY2VlZGVkXCIsIHBheWxvYWQ6IHtwcm9qZWN0OiBydW4ucHJvamVjdCwgcmV2aXNpb246IHJ1bi5yZXZpc2lvbiwgc3RhZ2U6IHJ1bi5zdGFnZX0sIHJ1bklkOiBydW4uaWR9KVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgLy8gVGhlIGFkYXB0ZXIgYWxyZWFkeSByZXR1cm5lZCBzdWNjZXNzLiBTdXJmYWNlIHRoZSByZWNvcmRpbmcgZXJyb3IsXG4gICAgICAgIC8vIHRoZW4gZmVuY2UgdGhlIHJ1biBpbiBhIGR1cmFibGUgbm9uLXJldHJ5YWJsZSBzdGF0ZSByYXRoZXIgdGhhblxuICAgICAgICAvLyBmYWxzZWx5IHJlY29yZGluZyBhbiBleHRlcm5hbCBzdWNjZXNzIGFzIGEgZGVwbG95bWVudCBmYWlsdXJlLlxuICAgICAgICB0aGlzLl9lbWl0RnJhbWV3b3JrRXJyb3Ioe2NvbnRleHQ6IFwiZGVwbG95bWVudC1hcGktcmVjb3JkLXN1Y2Nlc3NcIiwgZXJyb3J9KVxuXG4gICAgICAgIGNvbnN0IHJlY29uY2lsaWF0aW9uRXJyb3IgPSB7XG4gICAgICAgICAgbWVzc2FnZTogXCJEZXBsb3ltZW50IGFjdGl2YXRpb24gc3VjY2VlZGVkLCBidXQgaXRzIHJlc3VsdCBjb3VsZCBub3QgYmUgcGVyc2lzdGVkOyBvcGVyYXRvciByZWNvbmNpbGlhdGlvbiBpcyByZXF1aXJlZFwiXG4gICAgICAgIH1cblxuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IHN0b3JlLm1hcmtSZWNvbmNpbGlhdGlvblJlcXVpcmVkKHtcbiAgICAgICAgICAgIGVycm9yOiByZWNvbmNpbGlhdGlvbkVycm9yLFxuICAgICAgICAgICAgZmluaXNoZWRBdE1zOiBEYXRlLm5vdygpLFxuICAgICAgICAgICAgaWQ6IHJ1bi5pZCxcbiAgICAgICAgICAgIG93bmVyVG9rZW5cbiAgICAgICAgICB9KVxuICAgICAgICAgIGF3YWl0IHRoaXMuX2F1ZGl0KHtcbiAgICAgICAgICAgIGV2ZW50OiBcInJ1bl9yZWNvbmNpbGlhdGlvbl9yZXF1aXJlZFwiLFxuICAgICAgICAgICAgcGF5bG9hZDoge21lc3NhZ2U6IHJlY29uY2lsaWF0aW9uRXJyb3IubWVzc2FnZSwgcHJvamVjdDogcnVuLnByb2plY3QsIHJldmlzaW9uOiBydW4ucmV2aXNpb24sIHN0YWdlOiBydW4uc3RhZ2V9LFxuICAgICAgICAgICAgcnVuSWQ6IHJ1bi5pZFxuICAgICAgICAgIH0pXG4gICAgICAgIH0gY2F0Y2ggKHJlY29uY2lsaWF0aW9uRXJyb3JQZXJzaXN0ZW5jZUVycm9yKSB7XG4gICAgICAgICAgdGhpcy5fZW1pdEZyYW1ld29ya0Vycm9yKHtcbiAgICAgICAgICAgIGNvbnRleHQ6IFwiZGVwbG95bWVudC1hcGktcmVjb3JkLXJlY29uY2lsaWF0aW9uLXJlcXVpcmVkXCIsXG4gICAgICAgICAgICBlcnJvcjogcmVjb25jaWxpYXRpb25FcnJvclBlcnNpc3RlbmNlRXJyb3JcbiAgICAgICAgICB9KVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIGlmIChoZWFydGJlYXRUaW1lcikgY2xlYXJJbnRlcnZhbChoZWFydGJlYXRUaW1lcilcbiAgICAgIHVucmVnaXN0ZXJBY3RpdmVEZXBsb3ltZW50UnVuKHJ1bi5pZClcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmVjb3JkcyBhIHNhbml0aXplZCBhdWRpdCBldmVudC4gQXVkaXQgcGVyc2lzdGVuY2UgbXVzdCBuZXZlciBzdHJhbmQgb3JcbiAgICogc3VwcHJlc3MgYSBkZXBsb3ltZW50LCBzbyBhIGZhaWx1cmUgaGVyZSBpcyByZXBvcnRlZCBvbiB0aGVcbiAgICogZnJhbWV3b3JrLWVycm9yIGFuZCB1bmlmaWVkIGFsbC1lcnJvciBjaGFubmVscyAod2hlcmUgcHJvY2Vzcy1sZXZlbCBidWdcbiAgICogcmVwb3J0ZXJzIGNhcHR1cmUgaXQpLCBhbmQgZXhlY3V0aW9uIGNvbnRpbnVlcy5cbiAgICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBPcHRpb25zLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gYXJncy5ldmVudCAtIEV2ZW50IG5hbWUuXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgPz59IGFyZ3MucGF5bG9hZCAtIFBheWxvYWQ7IHNhbml0aXplZCBhbmQgcmVkYWN0ZWQgYmVmb3JlIHBlcnNpc3RlbmNlLlxuICAgKiBAcGFyYW0ge3N0cmluZyB8IG51bGx9IGFyZ3MucnVuSWQgLSBPd25pbmcgcnVuIGlkLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyB3aGVuIHJlY29yZGVkIG9yIHJlcG9ydGVkLlxuICAgKi9cbiAgYXN5bmMgX2F1ZGl0KHtldmVudCwgcGF5bG9hZCwgcnVuSWR9KSB7XG4gICAgY29uc3Qgc2FuaXRpemVkID0gc2FuaXRpemVBZGFwdGVyVmFsdWUocGF5bG9hZCwgdGhpcy5fbW91bnRPcHRpb25zKCkuYWNjZXNzVG9rZW5zKSA/PyB7fVxuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMuX3N0b3JlKCkuYWRkQXVkaXRFdmVudCh7ZXZlbnQsIHBheWxvYWQ6IHNhbml0aXplZCwgcnVuSWR9KVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aGlzLl9lbWl0RnJhbWV3b3JrRXJyb3Ioe2NvbnRleHQ6IFwiZGVwbG95bWVudC1hcGktYXVkaXRcIiwgZXJyb3J9KVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTZXJpYWxpemVzIGEgcnVuIGZvciB0aGUgQVBJLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4vcnVuLXN0b3JlLmpzXCIpLkRlcGxveW1lbnRSdW5Sb3d9IHJ1biAtIFJ1biByb3cuXG4gICAqIEByZXR1cm5zIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gLSBTZXJpYWxpemVkIHJ1bi5cbiAgICovXG4gIF9zZXJpYWxpemVSdW4ocnVuKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGVycm9yOiBydW4uZXJyb3IsXG4gICAgICBmaW5pc2hlZEF0TXM6IHJ1bi5maW5pc2hlZEF0TXMsXG4gICAgICBpZDogcnVuLmlkLFxuICAgICAgaWRlbXBvdGVuY3lLZXk6IHJ1bi5pZGVtcG90ZW5jeUtleSxcbiAgICAgIHByb2plY3Q6IHJ1bi5wcm9qZWN0LFxuICAgICAgcmVxdWVzdGVkQXRNczogcnVuLnJlcXVlc3RlZEF0TXMsXG4gICAgICByZXN1bHQ6IHJ1bi5yZXN1bHQsXG4gICAgICByZXZpc2lvbjogcnVuLnJldmlzaW9uLFxuICAgICAgc3RhZ2U6IHJ1bi5zdGFnZSxcbiAgICAgIHN0YXJ0ZWRBdE1zOiBydW4uc3RhcnRlZEF0TXMsXG4gICAgICBzdGF0dXM6IHJ1bi5zdGF0dXNcbiAgICB9XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,46 @@
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
@@ -0,0 +1 @@
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"}