codify-plugin-lib 1.0.115 → 1.0.117

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -13,4 +13,7 @@ export * from './utils/utils.js';
13
13
  export async function runPlugin(plugin) {
14
14
  const messageHandler = new MessageHandler(plugin);
15
15
  process.on('message', (message) => messageHandler.onMessage(message));
16
+ process.on('beforeExit', () => {
17
+ plugin.kill();
18
+ });
16
19
  }
@@ -27,7 +27,14 @@ export declare class Plan<T extends StringIndexedObject> {
27
27
  */
28
28
  get currentConfig(): T | null;
29
29
  get resourceId(): string;
30
- requiresChanges(): boolean;
30
+ static calculate<T extends StringIndexedObject>(params: {
31
+ desiredParameters: Partial<T> | null;
32
+ currentParametersArray: Partial<T>[] | null;
33
+ stateParameters: Partial<T> | null;
34
+ coreParameters: ResourceConfig;
35
+ settings: ParsedResourceSettings<T>;
36
+ statefulMode: boolean;
37
+ }): Plan<T>;
31
38
  /**
32
39
  * When multiples of the same resource are allowed, this matching function will match a given config with one of the
33
40
  * existing configs on the system. For example if there are multiple versions of Android Studios installed, we can use
@@ -43,14 +50,7 @@ export declare class Plan<T extends StringIndexedObject> {
43
50
  * @return string
44
51
  */
45
52
  getResourceType(): string;
46
- static calculate<T extends StringIndexedObject>(params: {
47
- desiredParameters: Partial<T> | null;
48
- currentParametersArray: Partial<T>[] | null;
49
- stateParameters: Partial<T> | null;
50
- coreParameters: ResourceConfig;
51
- settings: ParsedResourceSettings<T>;
52
- statefulMode: boolean;
53
- }): Plan<T>;
53
+ static fromResponse<T extends ResourceConfig>(data: ApplyRequestData['plan'], defaultValues?: Partial<Record<keyof T, unknown>>): Plan<T>;
54
54
  /**
55
55
  * Only keep relevant params for the plan. We don't want to change settings that were not already
56
56
  * defined.
@@ -60,7 +60,7 @@ export declare class Plan<T extends StringIndexedObject> {
60
60
  * or wants to set. If a parameter is not specified then it's not managed by Codify.
61
61
  */
62
62
  private static filterCurrentParams;
63
- static fromResponse<T extends ResourceConfig>(data: ApplyRequestData['plan'], defaultValues?: Partial<Record<keyof T, unknown>>): Plan<T>;
63
+ requiresChanges(): boolean;
64
64
  /**
65
65
  * Convert the plan to a JSON response object
66
66
  */
package/dist/plan/plan.js CHANGED
@@ -52,8 +52,37 @@ export class Plan {
52
52
  ? `${this.coreParameters.type}.${this.coreParameters.name}`
53
53
  : this.coreParameters.type;
54
54
  }
55
- requiresChanges() {
56
- return this.changeSet.operation !== ResourceOperation.NOOP;
55
+ static calculate(params) {
56
+ const { desiredParameters, currentParametersArray, stateParameters, coreParameters, settings, statefulMode } = params;
57
+ const currentParameters = Plan.matchCurrentParameters({
58
+ desiredParameters,
59
+ currentParametersArray,
60
+ stateParameters,
61
+ settings,
62
+ statefulMode
63
+ });
64
+ const filteredCurrentParameters = Plan.filterCurrentParams({
65
+ desiredParameters,
66
+ currentParameters,
67
+ stateParameters,
68
+ settings,
69
+ statefulMode
70
+ });
71
+ // Empty
72
+ if (!filteredCurrentParameters && !desiredParameters) {
73
+ return new Plan(uuidV4(), ChangeSet.empty(), coreParameters, statefulMode);
74
+ }
75
+ // CREATE
76
+ if (!filteredCurrentParameters && desiredParameters) {
77
+ return new Plan(uuidV4(), ChangeSet.create(desiredParameters), coreParameters, statefulMode);
78
+ }
79
+ // DESTROY
80
+ if (filteredCurrentParameters && !desiredParameters) {
81
+ return new Plan(uuidV4(), ChangeSet.destroy(filteredCurrentParameters), coreParameters, statefulMode);
82
+ }
83
+ // NO-OP, MODIFY or RE-CREATE
84
+ const changeSet = ChangeSet.calculateModification(desiredParameters, filteredCurrentParameters, settings.parameterSettings);
85
+ return new Plan(uuidV4(), changeSet, coreParameters, statefulMode);
57
86
  }
58
87
  /**
59
88
  * When multiples of the same resource are allowed, this matching function will match a given config with one of the
@@ -86,37 +115,59 @@ export class Plan {
86
115
  getResourceType() {
87
116
  return this.coreParameters.type;
88
117
  }
89
- static calculate(params) {
90
- const { desiredParameters, currentParametersArray, stateParameters, coreParameters, settings, statefulMode } = params;
91
- const currentParameters = Plan.matchCurrentParameters({
92
- desiredParameters,
93
- currentParametersArray,
94
- stateParameters,
95
- settings,
96
- statefulMode
97
- });
98
- const filteredCurrentParameters = Plan.filterCurrentParams({
99
- desiredParameters,
100
- currentParameters,
101
- stateParameters,
102
- settings,
103
- statefulMode
104
- });
105
- // Empty
106
- if (!filteredCurrentParameters && !desiredParameters) {
107
- return new Plan(uuidV4(), ChangeSet.empty(), coreParameters, statefulMode);
108
- }
109
- // CREATE
110
- if (!filteredCurrentParameters && desiredParameters) {
111
- return new Plan(uuidV4(), ChangeSet.create(desiredParameters), coreParameters, statefulMode);
118
+ // 2. Even if there was (maybe for testing reasons), the plan values should not be adjusted
119
+ static fromResponse(data, defaultValues) {
120
+ if (!data) {
121
+ throw new Error('Data is empty');
112
122
  }
113
- // DESTROY
114
- if (filteredCurrentParameters && !desiredParameters) {
115
- return new Plan(uuidV4(), ChangeSet.destroy(filteredCurrentParameters), coreParameters, statefulMode);
123
+ addDefaultValues();
124
+ return new Plan(uuidV4(), new ChangeSet(data.operation, data.parameters), {
125
+ type: data.resourceType,
126
+ name: data.resourceName,
127
+ }, data.statefulMode);
128
+ function addDefaultValues() {
129
+ Object.entries(defaultValues ?? {})
130
+ .forEach(([key, defaultValue]) => {
131
+ const configValueExists = data
132
+ .parameters
133
+ .some((p) => p.name === key);
134
+ // Only set default values if the value does not exist in the config
135
+ if (configValueExists) {
136
+ return;
137
+ }
138
+ switch (data.operation) {
139
+ case ResourceOperation.CREATE: {
140
+ data.parameters.push({
141
+ name: key,
142
+ operation: ParameterOperation.ADD,
143
+ previousValue: null,
144
+ newValue: defaultValue,
145
+ });
146
+ break;
147
+ }
148
+ case ResourceOperation.DESTROY: {
149
+ data.parameters.push({
150
+ name: key,
151
+ operation: ParameterOperation.REMOVE,
152
+ previousValue: defaultValue,
153
+ newValue: null,
154
+ });
155
+ break;
156
+ }
157
+ case ResourceOperation.MODIFY:
158
+ case ResourceOperation.RECREATE:
159
+ case ResourceOperation.NOOP: {
160
+ data.parameters.push({
161
+ name: key,
162
+ operation: ParameterOperation.NOOP,
163
+ previousValue: defaultValue,
164
+ newValue: defaultValue,
165
+ });
166
+ break;
167
+ }
168
+ }
169
+ });
116
170
  }
117
- // NO-OP, MODIFY or RE-CREATE
118
- const changeSet = ChangeSet.calculateModification(desiredParameters, filteredCurrentParameters, settings.parameterSettings);
119
- return new Plan(uuidV4(), changeSet, coreParameters, statefulMode);
120
171
  }
121
172
  /**
122
173
  * Only keep relevant params for the plan. We don't want to change settings that were not already
@@ -215,59 +266,8 @@ export class Plan {
215
266
  }
216
267
  // TODO: This needs to be revisited. I don't think this is valid anymore.
217
268
  // 1. For all scenarios, there shouldn't be an apply without a plan beforehand
218
- // 2. Even if there was (maybe for testing reasons), the plan values should not be adjusted
219
- static fromResponse(data, defaultValues) {
220
- if (!data) {
221
- throw new Error('Data is empty');
222
- }
223
- addDefaultValues();
224
- return new Plan(uuidV4(), new ChangeSet(data.operation, data.parameters), {
225
- type: data.resourceType,
226
- name: data.resourceName,
227
- }, data.statefulMode);
228
- function addDefaultValues() {
229
- Object.entries(defaultValues ?? {})
230
- .forEach(([key, defaultValue]) => {
231
- const configValueExists = data
232
- .parameters
233
- .some((p) => p.name === key);
234
- // Only set default values if the value does not exist in the config
235
- if (configValueExists) {
236
- return;
237
- }
238
- switch (data.operation) {
239
- case ResourceOperation.CREATE: {
240
- data.parameters.push({
241
- name: key,
242
- operation: ParameterOperation.ADD,
243
- previousValue: null,
244
- newValue: defaultValue,
245
- });
246
- break;
247
- }
248
- case ResourceOperation.DESTROY: {
249
- data.parameters.push({
250
- name: key,
251
- operation: ParameterOperation.REMOVE,
252
- previousValue: defaultValue,
253
- newValue: null,
254
- });
255
- break;
256
- }
257
- case ResourceOperation.MODIFY:
258
- case ResourceOperation.RECREATE:
259
- case ResourceOperation.NOOP: {
260
- data.parameters.push({
261
- name: key,
262
- operation: ParameterOperation.NOOP,
263
- previousValue: defaultValue,
264
- newValue: defaultValue,
265
- });
266
- break;
267
- }
268
- }
269
- });
270
- }
269
+ requiresChanges() {
270
+ return this.changeSet.operation !== ResourceOperation.NOOP;
271
271
  }
272
272
  /**
273
273
  * Convert the plan to a JSON response object
@@ -16,6 +16,7 @@ export declare class Plugin {
16
16
  validate(data: ValidateRequestData): Promise<ValidateResponseData>;
17
17
  plan(data: PlanRequestData): Promise<PlanResponseData>;
18
18
  apply(data: ApplyRequestData): Promise<void>;
19
+ kill(): Promise<void>;
19
20
  private resolvePlan;
20
21
  protected crossValidateResources(configs: ResourceConfig[]): Promise<void>;
21
22
  }
@@ -1,6 +1,7 @@
1
1
  import { ApplyValidationError } from '../common/errors.js';
2
2
  import { Plan } from '../plan/plan.js';
3
3
  import { BackgroundPty } from '../pty/background-pty.js';
4
+ import { getPty } from '../pty/index.js';
4
5
  import { ResourceController } from '../resource/resource-controller.js';
5
6
  import { ptyLocalStorage } from '../utils/pty-local-storage.js';
6
7
  export class Plugin {
@@ -97,11 +98,18 @@ export class Plugin {
97
98
  throw new Error('Malformed plan with resource that cannot be found');
98
99
  }
99
100
  await resource.apply(plan);
100
- const validationPlan = await ptyLocalStorage.run(new BackgroundPty(), async () => resource.plan(plan.desiredConfig, plan.currentConfig, plan.statefulMode));
101
+ const validationPlan = await ptyLocalStorage.run(new BackgroundPty(), async () => {
102
+ const result = await resource.plan(plan.desiredConfig, plan.currentConfig, plan.statefulMode);
103
+ await getPty().kill();
104
+ return result;
105
+ });
101
106
  if (validationPlan.requiresChanges()) {
102
107
  throw new ApplyValidationError(plan);
103
108
  }
104
109
  }
110
+ async kill() {
111
+ await this.planPty.kill();
112
+ }
105
113
  resolvePlan(data) {
106
114
  const { plan: planRequest, planId } = data;
107
115
  if (planId) {
@@ -94,7 +94,7 @@ export class BackgroundPty {
94
94
  this.basePty.onExit((status) => {
95
95
  resolve(status);
96
96
  });
97
- this.basePty.kill();
97
+ this.basePty.kill('SIGKILL');
98
98
  });
99
99
  }
100
100
  async initialize() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codify-plugin-lib",
3
- "version": "1.0.115",
3
+ "version": "1.0.117",
4
4
  "description": "Library plugin library",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -1,6 +1,5 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
  import { ApplyValidationError } from './errors.js';
3
- import { Plan } from '../plan/plan.js';
4
3
  import { testPlan } from '../utils/test-utils.test.js';
5
4
 
6
5
  describe('Test file for errors file', () => {
@@ -21,7 +20,7 @@ describe('Test file for errors file', () => {
21
20
  } catch (e) {
22
21
  console.error(e);
23
22
  expect(e.message).toMatch(
24
- `Failed to apply changes to resource: "homebrew.first". Additional changes are needed to complete apply.
23
+ `Failed to apply changes to resource: "homebrew.first". Additional changes are needed to complete apply.
25
24
  Changes remaining:
26
25
  {
27
26
  "operation": "destroy",
@@ -16,7 +16,7 @@ export class ApplyValidationError extends Error {
16
16
  private static prettyPrintPlan(plan: Plan<any>): string {
17
17
  const { operation, parameters } = plan.toResponse();
18
18
 
19
- const prettyParameters = parameters.map(({ name, operation, previousValue, newValue}) => ({
19
+ const prettyParameters = parameters.map(({ name, operation, previousValue, newValue }) => ({
20
20
  name,
21
21
  operation,
22
22
  currentValue: previousValue,
package/src/index.ts CHANGED
@@ -16,4 +16,8 @@ export * from './utils/utils.js'
16
16
  export async function runPlugin(plugin: Plugin) {
17
17
  const messageHandler = new MessageHandler(plugin);
18
18
  process.on('message', (message) => messageHandler.onMessage(message))
19
+
20
+ process.on('beforeExit', () => {
21
+ plugin.kill();
22
+ })
19
23
  }
package/src/plan/plan.ts CHANGED
@@ -70,65 +70,12 @@ export class Plan<T extends StringIndexedObject> {
70
70
  ...this.changeSet.currentParameters,
71
71
  }
72
72
  }
73
-
73
+
74
74
  get resourceId(): string {
75
75
  return this.coreParameters.name
76
76
  ? `${this.coreParameters.type}.${this.coreParameters.name}`
77
77
  : this.coreParameters.type;
78
78
  }
79
-
80
- requiresChanges(): boolean {
81
- return this.changeSet.operation !== ResourceOperation.NOOP;
82
- }
83
-
84
- /**
85
- * When multiples of the same resource are allowed, this matching function will match a given config with one of the
86
- * existing configs on the system. For example if there are multiple versions of Android Studios installed, we can use
87
- * the application name and location to match it to our desired configs name and location.
88
- *
89
- * @param params
90
- * @private
91
- */
92
- private static matchCurrentParameters<T extends StringIndexedObject>(params: {
93
- desiredParameters: Partial<T> | null,
94
- currentParametersArray: Partial<T>[] | null,
95
- stateParameters: Partial<T> | null,
96
- settings: ResourceSettings<T>,
97
- statefulMode: boolean,
98
- }): Partial<T> | null {
99
- const {
100
- desiredParameters,
101
- currentParametersArray,
102
- stateParameters,
103
- settings,
104
- statefulMode
105
- } = params;
106
-
107
- if (!settings.allowMultiple) {
108
- return currentParametersArray?.[0] ?? null;
109
- }
110
-
111
- if (!currentParametersArray) {
112
- return null;
113
- }
114
-
115
- if (statefulMode) {
116
- return stateParameters
117
- ? settings.allowMultiple.matcher(stateParameters, currentParametersArray)
118
- : null
119
- }
120
-
121
- return settings.allowMultiple.matcher(desiredParameters!, currentParametersArray);
122
- }
123
-
124
- /**
125
- * The type (id) of the resource
126
- *
127
- * @return string
128
- */
129
- getResourceType(): string {
130
- return this.coreParameters.type
131
- }
132
79
 
133
80
  static calculate<T extends StringIndexedObject>(params: {
134
81
  desiredParameters: Partial<T> | null,
@@ -208,6 +155,126 @@ export class Plan<T extends StringIndexedObject> {
208
155
  );
209
156
  }
210
157
 
158
+ /**
159
+ * When multiples of the same resource are allowed, this matching function will match a given config with one of the
160
+ * existing configs on the system. For example if there are multiple versions of Android Studios installed, we can use
161
+ * the application name and location to match it to our desired configs name and location.
162
+ *
163
+ * @param params
164
+ * @private
165
+ */
166
+ private static matchCurrentParameters<T extends StringIndexedObject>(params: {
167
+ desiredParameters: Partial<T> | null,
168
+ currentParametersArray: Partial<T>[] | null,
169
+ stateParameters: Partial<T> | null,
170
+ settings: ResourceSettings<T>,
171
+ statefulMode: boolean,
172
+ }): Partial<T> | null {
173
+ const {
174
+ desiredParameters,
175
+ currentParametersArray,
176
+ stateParameters,
177
+ settings,
178
+ statefulMode
179
+ } = params;
180
+
181
+ if (!settings.allowMultiple) {
182
+ return currentParametersArray?.[0] ?? null;
183
+ }
184
+
185
+ if (!currentParametersArray) {
186
+ return null;
187
+ }
188
+
189
+ if (statefulMode) {
190
+ return stateParameters
191
+ ? settings.allowMultiple.matcher(stateParameters, currentParametersArray)
192
+ : null
193
+ }
194
+
195
+ return settings.allowMultiple.matcher(desiredParameters!, currentParametersArray);
196
+ }
197
+
198
+ /**
199
+ * The type (id) of the resource
200
+ *
201
+ * @return string
202
+ */
203
+ getResourceType(): string {
204
+ return this.coreParameters.type
205
+ }
206
+
207
+ // 2. Even if there was (maybe for testing reasons), the plan values should not be adjusted
208
+ static fromResponse<T extends ResourceConfig>(data: ApplyRequestData['plan'], defaultValues?: Partial<Record<keyof T, unknown>>): Plan<T> {
209
+ if (!data) {
210
+ throw new Error('Data is empty');
211
+ }
212
+
213
+ addDefaultValues();
214
+
215
+ return new Plan(
216
+ uuidV4(),
217
+ new ChangeSet<T>(
218
+ data.operation,
219
+ data.parameters
220
+ ),
221
+ {
222
+ type: data.resourceType,
223
+ name: data.resourceName,
224
+ },
225
+ data.statefulMode
226
+ );
227
+
228
+ function addDefaultValues(): void {
229
+ Object.entries(defaultValues ?? {})
230
+ .forEach(([key, defaultValue]) => {
231
+ const configValueExists = data!
232
+ .parameters
233
+ .some((p) => p.name === key);
234
+
235
+ // Only set default values if the value does not exist in the config
236
+ if (configValueExists) {
237
+ return;
238
+ }
239
+
240
+ switch (data!.operation) {
241
+ case ResourceOperation.CREATE: {
242
+ data!.parameters.push({
243
+ name: key,
244
+ operation: ParameterOperation.ADD,
245
+ previousValue: null,
246
+ newValue: defaultValue,
247
+ });
248
+ break;
249
+ }
250
+
251
+ case ResourceOperation.DESTROY: {
252
+ data!.parameters.push({
253
+ name: key,
254
+ operation: ParameterOperation.REMOVE,
255
+ previousValue: defaultValue,
256
+ newValue: null,
257
+ });
258
+ break;
259
+ }
260
+
261
+ case ResourceOperation.MODIFY:
262
+ case ResourceOperation.RECREATE:
263
+ case ResourceOperation.NOOP: {
264
+ data!.parameters.push({
265
+ name: key,
266
+ operation: ParameterOperation.NOOP,
267
+ previousValue: defaultValue,
268
+ newValue: defaultValue,
269
+ });
270
+ break;
271
+ }
272
+ }
273
+ });
274
+ }
275
+
276
+ }
277
+
211
278
  /**
212
279
  * Only keep relevant params for the plan. We don't want to change settings that were not already
213
280
  * defined.
@@ -347,75 +414,9 @@ export class Plan<T extends StringIndexedObject> {
347
414
 
348
415
  // TODO: This needs to be revisited. I don't think this is valid anymore.
349
416
  // 1. For all scenarios, there shouldn't be an apply without a plan beforehand
350
- // 2. Even if there was (maybe for testing reasons), the plan values should not be adjusted
351
- static fromResponse<T extends ResourceConfig>(data: ApplyRequestData['plan'], defaultValues?: Partial<Record<keyof T, unknown>>): Plan<T> {
352
- if (!data) {
353
- throw new Error('Data is empty');
354
- }
355
-
356
- addDefaultValues();
357
-
358
- return new Plan(
359
- uuidV4(),
360
- new ChangeSet<T>(
361
- data.operation,
362
- data.parameters
363
- ),
364
- {
365
- type: data.resourceType,
366
- name: data.resourceName,
367
- },
368
- data.statefulMode
369
- );
370
-
371
- function addDefaultValues(): void {
372
- Object.entries(defaultValues ?? {})
373
- .forEach(([key, defaultValue]) => {
374
- const configValueExists = data!
375
- .parameters
376
- .some((p) => p.name === key);
377
-
378
- // Only set default values if the value does not exist in the config
379
- if (configValueExists) {
380
- return;
381
- }
382
-
383
- switch (data!.operation) {
384
- case ResourceOperation.CREATE: {
385
- data!.parameters.push({
386
- name: key,
387
- operation: ParameterOperation.ADD,
388
- previousValue: null,
389
- newValue: defaultValue,
390
- });
391
- break;
392
- }
393
-
394
- case ResourceOperation.DESTROY: {
395
- data!.parameters.push({
396
- name: key,
397
- operation: ParameterOperation.REMOVE,
398
- previousValue: defaultValue,
399
- newValue: null,
400
- });
401
- break;
402
- }
403
-
404
- case ResourceOperation.MODIFY:
405
- case ResourceOperation.RECREATE:
406
- case ResourceOperation.NOOP: {
407
- data!.parameters.push({
408
- name: key,
409
- operation: ParameterOperation.NOOP,
410
- previousValue: defaultValue,
411
- newValue: defaultValue,
412
- });
413
- break;
414
- }
415
- }
416
- });
417
- }
418
417
 
418
+ requiresChanges(): boolean {
419
+ return this.changeSet.operation !== ResourceOperation.NOOP;
419
420
  }
420
421
 
421
422
  /**
@@ -7,7 +7,6 @@ import { spy } from 'sinon';
7
7
  import { ResourceSettings } from '../resource/resource-settings.js';
8
8
  import { TestConfig } from '../utils/test-utils.test.js';
9
9
  import { ApplyValidationError } from '../common/errors.js';
10
- import { ResourceController } from '../resource/resource-controller.js';
11
10
  import { getPty } from '../pty/index.js';
12
11
 
13
12
  interface TestConfig extends StringIndexedObject {
@@ -42,7 +41,7 @@ class TestResource extends Resource<TestConfig> {
42
41
 
43
42
  describe('Plugin tests', () => {
44
43
  it('Can apply resource', async () => {
45
- const resource= spy(new class extends TestResource {
44
+ const resource = spy(new class extends TestResource {
46
45
  async refresh(): Promise<Partial<TestConfig> | null> {
47
46
  return {
48
47
  propA: 'abc',
@@ -16,6 +16,7 @@ import {
16
16
  import { ApplyValidationError } from '../common/errors.js';
17
17
  import { Plan } from '../plan/plan.js';
18
18
  import { BackgroundPty } from '../pty/background-pty.js';
19
+ import { getPty } from '../pty/index.js';
19
20
  import { Resource } from '../resource/resource.js';
20
21
  import { ResourceController } from '../resource/resource-controller.js';
21
22
  import { ptyLocalStorage } from '../utils/pty-local-storage.js';
@@ -127,7 +128,7 @@ export class Plugin {
127
128
  data.desired ?? null,
128
129
  data.state ?? null,
129
130
  data.isStateful
130
- ))
131
+ ))
131
132
 
132
133
  this.planStorage.set(plan.id, plan);
133
134
 
@@ -148,17 +149,26 @@ export class Plugin {
148
149
 
149
150
  await resource.apply(plan);
150
151
 
151
- const validationPlan = await ptyLocalStorage.run(new BackgroundPty(), async () => resource.plan(
152
- plan.desiredConfig,
153
- plan.currentConfig,
154
- plan.statefulMode
155
- ))
156
-
152
+ const validationPlan = await ptyLocalStorage.run(new BackgroundPty(), async () => {
153
+ const result = await resource.plan(
154
+ plan.desiredConfig,
155
+ plan.currentConfig,
156
+ plan.statefulMode
157
+ );
158
+
159
+ await getPty().kill();
160
+ return result;
161
+ })
162
+
157
163
  if (validationPlan.requiresChanges()) {
158
164
  throw new ApplyValidationError(plan);
159
165
  }
160
166
  }
161
167
 
168
+ async kill() {
169
+ await this.planPty.kill();
170
+ }
171
+
162
172
  private resolvePlan(data: ApplyRequestData): Plan<ResourceConfig> {
163
173
  const { plan: planRequest, planId } = data;
164
174
 
@@ -179,5 +189,4 @@ export class Plugin {
179
189
  }
180
190
 
181
191
  protected async crossValidateResources(configs: ResourceConfig[]): Promise<void> {}
182
-
183
192
  }
@@ -117,7 +117,7 @@ export class BackgroundPty implements IPty {
117
117
  resolve(status);
118
118
  })
119
119
 
120
- this.basePty.kill()
120
+ this.basePty.kill('SIGKILL')
121
121
  })
122
122
  }
123
123