codify-plugin-lib 1.0.87 → 1.0.89

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.
@@ -1,31 +1,36 @@
1
1
  import { Ajv } from 'ajv';
2
2
  import addFormats from 'ajv-formats';
3
- import { ApplyRequestDataSchema, ApplyResponseDataSchema, InitializeRequestDataSchema, InitializeResponseDataSchema, IpcMessageSchema, MessageStatus, PlanRequestDataSchema, PlanResponseDataSchema, ResourceSchema, ValidateRequestDataSchema, ValidateResponseDataSchema } from 'codify-schemas';
3
+ import { ApplyRequestDataSchema, ApplyResponseDataSchema, GetResourceInfoRequestDataSchema, GetResourceInfoResponseDataSchema, InitializeRequestDataSchema, InitializeResponseDataSchema, IpcMessageSchema, MessageStatus, PlanRequestDataSchema, PlanResponseDataSchema, ResourceSchema, ValidateRequestDataSchema, ValidateResponseDataSchema } from 'codify-schemas';
4
4
  import { SudoError } from '../errors.js';
5
5
  const SupportedRequests = {
6
- 'apply': {
7
- async handler(plugin, data) {
8
- await plugin.apply(data);
9
- return null;
10
- },
11
- requestValidator: ApplyRequestDataSchema,
12
- responseValidator: ApplyResponseDataSchema
13
- },
14
6
  'initialize': {
15
7
  handler: async (plugin) => plugin.initialize(),
16
8
  requestValidator: InitializeRequestDataSchema,
17
9
  responseValidator: InitializeResponseDataSchema
18
10
  },
11
+ 'validate': {
12
+ handler: async (plugin, data) => plugin.validate(data),
13
+ requestValidator: ValidateRequestDataSchema,
14
+ responseValidator: ValidateResponseDataSchema
15
+ },
16
+ 'getResourceInfo': {
17
+ handler: async (plugin, data) => plugin.getResourceInfo(data),
18
+ requestValidator: GetResourceInfoRequestDataSchema,
19
+ responseValidator: GetResourceInfoResponseDataSchema
20
+ },
19
21
  'plan': {
20
22
  handler: async (plugin, data) => plugin.plan(data),
21
23
  requestValidator: PlanRequestDataSchema,
22
24
  responseValidator: PlanResponseDataSchema
23
25
  },
24
- 'validate': {
25
- handler: async (plugin, data) => plugin.validate(data),
26
- requestValidator: ValidateRequestDataSchema,
27
- responseValidator: ValidateResponseDataSchema
28
- }
26
+ 'apply': {
27
+ async handler(plugin, data) {
28
+ await plugin.apply(data);
29
+ return null;
30
+ },
31
+ requestValidator: ApplyRequestDataSchema,
32
+ responseValidator: ApplyResponseDataSchema
33
+ },
29
34
  };
30
35
  export class MessageHandler {
31
36
  ajv;
@@ -1,4 +1,4 @@
1
- import { ApplyRequestData, InitializeResponseData, PlanRequestData, PlanResponseData, ResourceConfig, ValidateRequestData, ValidateResponseData } from 'codify-schemas';
1
+ import { ApplyRequestData, GetResourceInfoRequestData, GetResourceInfoResponseData, InitializeResponseData, PlanRequestData, PlanResponseData, ResourceConfig, ValidateRequestData, ValidateResponseData } from 'codify-schemas';
2
2
  import { Plan } from '../plan/plan.js';
3
3
  import { Resource } from '../resource/resource.js';
4
4
  import { ResourceController } from '../resource/resource-controller.js';
@@ -9,6 +9,7 @@ export declare class Plugin {
9
9
  constructor(name: string, resourceControllers: Map<string, ResourceController<ResourceConfig>>);
10
10
  static create(name: string, resources: Resource<any>[]): Plugin;
11
11
  initialize(): Promise<InitializeResponseData>;
12
+ getResourceInfo(data: GetResourceInfoRequestData): Promise<GetResourceInfoResponseData>;
12
13
  validate(data: ValidateRequestData): Promise<ValidateResponseData>;
13
14
  plan(data: PlanRequestData): Promise<PlanResponseData>;
14
15
  apply(data: ApplyRequestData): Promise<void>;
@@ -27,6 +27,18 @@ export class Plugin {
27
27
  }))
28
28
  };
29
29
  }
30
+ async getResourceInfo(data) {
31
+ if (!this.resourceControllers.has(data.type)) {
32
+ throw new Error(`Cannot get info for resource ${data.type}, resource doesn't exist`);
33
+ }
34
+ const resource = this.resourceControllers.get(data.type);
35
+ return {
36
+ plugin: this.name,
37
+ type: data.type,
38
+ dependencies: resource.dependencies,
39
+ schema: resource.settings.schema
40
+ };
41
+ }
30
42
  async validate(data) {
31
43
  const validationResults = [];
32
44
  for (const config of data.configs) {
@@ -76,6 +76,8 @@ export class ResourceController {
76
76
  this.validatePlanInputs(desiredConfig, stateConfig, statefulMode);
77
77
  this.addDefaultValues(desiredConfig);
78
78
  await this.applyTransformParameters(desiredConfig);
79
+ this.addDefaultValues(stateConfig);
80
+ await this.applyTransformParameters(stateConfig);
79
81
  // Parse data from the user supplied config
80
82
  const parsedConfig = new ConfigParser(desiredConfig, stateConfig, this.parsedSettings.statefulParameters);
81
83
  const { coreParameters, desiredParameters, stateParameters, allParameters, allNonStatefulParameters, allStatefulParameters, } = parsedConfig;
@@ -188,30 +190,30 @@ ${JSON.stringify(refresh, null, 2)}
188
190
  `);
189
191
  }
190
192
  }
191
- async applyTransformParameters(desired) {
192
- if (!desired) {
193
+ async applyTransformParameters(config) {
194
+ if (!config) {
193
195
  return;
194
196
  }
195
197
  for (const [key, inputTransformation] of Object.entries(this.parsedSettings.inputTransformations)) {
196
- if (desired[key] === undefined || !inputTransformation) {
198
+ if (config[key] === undefined || !inputTransformation) {
197
199
  continue;
198
200
  }
199
- desired[key] = await inputTransformation(desired[key]);
201
+ config[key] = await inputTransformation(config[key]);
200
202
  }
201
203
  if (this.settings.inputTransformation) {
202
- const { parameters, coreParameters } = splitUserConfig(desired);
204
+ const { parameters, coreParameters } = splitUserConfig(config);
203
205
  const transformed = await this.settings.inputTransformation(parameters);
204
- Object.keys(desired).forEach((k) => delete desired[k]);
205
- Object.assign(desired, transformed, coreParameters);
206
+ Object.keys(config).forEach((k) => delete config[k]);
207
+ Object.assign(config, transformed, coreParameters);
206
208
  }
207
209
  }
208
- addDefaultValues(desired) {
209
- if (!desired) {
210
+ addDefaultValues(config) {
211
+ if (!config) {
210
212
  return;
211
213
  }
212
214
  for (const [key, defaultValue] of Object.entries(this.parsedSettings.defaultValues)) {
213
- if (defaultValue !== undefined && (desired[key] === undefined || desired[key] === null)) {
214
- desired[key] = defaultValue;
215
+ if (defaultValue !== undefined && (config[key] === undefined || config[key] === null)) {
216
+ config[key] = defaultValue;
215
217
  }
216
218
  }
217
219
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codify-plugin-lib",
3
- "version": "1.0.87",
3
+ "version": "1.0.89",
4
4
  "description": "Library plugin library",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -14,7 +14,7 @@
14
14
  "dependencies": {
15
15
  "ajv": "^8.12.0",
16
16
  "ajv-formats": "^2.1.1",
17
- "codify-schemas": "1.0.45",
17
+ "codify-schemas": "1.0.47",
18
18
  "@npmcli/promise-spawn": "^7.0.1",
19
19
  "uuid": "^10.0.0"
20
20
  },
@@ -3,6 +3,8 @@ import addFormats from 'ajv-formats';
3
3
  import {
4
4
  ApplyRequestDataSchema,
5
5
  ApplyResponseDataSchema,
6
+ GetResourceInfoRequestDataSchema,
7
+ GetResourceInfoResponseDataSchema,
6
8
  InitializeRequestDataSchema,
7
9
  InitializeResponseDataSchema,
8
10
  IpcMessage,
@@ -19,29 +21,34 @@ import { SudoError } from '../errors.js';
19
21
  import { Plugin } from '../plugin/plugin.js';
20
22
 
21
23
  const SupportedRequests: Record<string, { handler: (plugin: Plugin, data: any) => Promise<unknown>; requestValidator: SchemaObject; responseValidator: SchemaObject }> = {
22
- 'apply': {
23
- async handler(plugin: Plugin, data: any) {
24
- await plugin.apply(data);
25
- return null;
26
- },
27
- requestValidator: ApplyRequestDataSchema,
28
- responseValidator: ApplyResponseDataSchema
29
- },
30
24
  'initialize': {
31
25
  handler: async (plugin: Plugin) => plugin.initialize(),
32
26
  requestValidator: InitializeRequestDataSchema,
33
27
  responseValidator: InitializeResponseDataSchema
34
28
  },
29
+ 'validate': {
30
+ handler: async (plugin: Plugin, data: any) => plugin.validate(data),
31
+ requestValidator: ValidateRequestDataSchema,
32
+ responseValidator: ValidateResponseDataSchema
33
+ },
34
+ 'getResourceInfo': {
35
+ handler: async (plugin: Plugin, data: any) => plugin.getResourceInfo(data),
36
+ requestValidator: GetResourceInfoRequestDataSchema,
37
+ responseValidator: GetResourceInfoResponseDataSchema
38
+ },
35
39
  'plan': {
36
40
  handler: async (plugin: Plugin, data: any) => plugin.plan(data),
37
41
  requestValidator: PlanRequestDataSchema,
38
42
  responseValidator: PlanResponseDataSchema
39
43
  },
40
- 'validate': {
41
- handler: async (plugin: Plugin, data: any) => plugin.validate(data),
42
- requestValidator: ValidateRequestDataSchema,
43
- responseValidator: ValidateResponseDataSchema
44
- }
44
+ 'apply': {
45
+ async handler(plugin: Plugin, data: any) {
46
+ await plugin.apply(data);
47
+ return null;
48
+ },
49
+ requestValidator: ApplyRequestDataSchema,
50
+ responseValidator: ApplyResponseDataSchema
51
+ },
45
52
  }
46
53
 
47
54
  export class MessageHandler {
@@ -1,5 +1,7 @@
1
1
  import {
2
2
  ApplyRequestData,
3
+ GetResourceInfoRequestData,
4
+ GetResourceInfoResponseData,
3
5
  InitializeResponseData,
4
6
  PlanRequestData,
5
7
  PlanResponseData,
@@ -47,6 +49,21 @@ export class Plugin {
47
49
  }
48
50
  }
49
51
 
52
+ async getResourceInfo(data: GetResourceInfoRequestData): Promise<GetResourceInfoResponseData> {
53
+ if (!this.resourceControllers.has(data.type)) {
54
+ throw new Error(`Cannot get info for resource ${data.type}, resource doesn't exist`);
55
+ }
56
+
57
+ const resource = this.resourceControllers.get(data.type)!;
58
+
59
+ return {
60
+ plugin: this.name,
61
+ type: data.type,
62
+ dependencies: resource.dependencies,
63
+ schema: resource.settings.schema as Record<string, unknown> | undefined
64
+ }
65
+ }
66
+
50
67
  async validate(data: ValidateRequestData): Promise<ValidateResponseData> {
51
68
  const validationResults = [];
52
69
  for (const config of data.configs) {
@@ -112,6 +112,9 @@ export class ResourceController<T extends StringIndexedObject> {
112
112
  this.addDefaultValues(desiredConfig);
113
113
  await this.applyTransformParameters(desiredConfig);
114
114
 
115
+ this.addDefaultValues(stateConfig);
116
+ await this.applyTransformParameters(stateConfig);
117
+
115
118
  // Parse data from the user supplied config
116
119
  const parsedConfig = new ConfigParser(desiredConfig, stateConfig, this.parsedSettings.statefulParameters)
117
120
  const {
@@ -258,36 +261,36 @@ ${JSON.stringify(refresh, null, 2)}
258
261
  }
259
262
  }
260
263
 
261
- private async applyTransformParameters(desired: Partial<T> & ResourceConfig | null): Promise<void> {
262
- if (!desired) {
264
+ private async applyTransformParameters(config: Partial<T> & ResourceConfig | null): Promise<void> {
265
+ if (!config) {
263
266
  return;
264
267
  }
265
268
 
266
269
  for (const [key, inputTransformation] of Object.entries(this.parsedSettings.inputTransformations)) {
267
- if (desired[key] === undefined || !inputTransformation) {
270
+ if (config[key] === undefined || !inputTransformation) {
268
271
  continue;
269
272
  }
270
273
 
271
- (desired as Record<string, unknown>)[key] = await inputTransformation(desired[key]);
274
+ (config as Record<string, unknown>)[key] = await inputTransformation(config[key]);
272
275
  }
273
276
 
274
277
  if (this.settings.inputTransformation) {
275
- const { parameters, coreParameters } = splitUserConfig(desired);
278
+ const { parameters, coreParameters } = splitUserConfig(config);
276
279
 
277
280
  const transformed = await this.settings.inputTransformation(parameters)
278
- Object.keys(desired).forEach((k) => delete desired[k])
279
- Object.assign(desired, transformed, coreParameters);
281
+ Object.keys(config).forEach((k) => delete config[k])
282
+ Object.assign(config, transformed, coreParameters);
280
283
  }
281
284
  }
282
285
 
283
- private addDefaultValues(desired: Partial<T> | null): void {
284
- if (!desired) {
286
+ private addDefaultValues(config: Partial<T> | null): void {
287
+ if (!config) {
285
288
  return;
286
289
  }
287
290
 
288
291
  for (const [key, defaultValue] of Object.entries(this.parsedSettings.defaultValues)) {
289
- if (defaultValue !== undefined && (desired[key] === undefined || desired[key] === null)) {
290
- (desired as Record<string, unknown>)[key] = defaultValue;
292
+ if (defaultValue !== undefined && (config[key] === undefined || config[key] === null)) {
293
+ (config as Record<string, unknown>)[key] = defaultValue;
291
294
  }
292
295
  }
293
296
  }
@@ -491,4 +491,37 @@ describe('Resource parameter tests', () => {
491
491
 
492
492
  expect(plan.changeSet.operation).to.eq(ResourceOperation.NOOP);
493
493
  })
494
+
495
+ it('Supports transform parameters for state parameters', async () => {
496
+ const resource = spy(new class extends TestResource {
497
+ getSettings(): ResourceSettings<TestConfig> {
498
+ return {
499
+ id: 'resourceType',
500
+ inputTransformation: (desired) => ({
501
+ propA: 'propA',
502
+ propB: 10,
503
+ })
504
+ }
505
+ }
506
+
507
+ async refresh(): Promise<Partial<TestConfig> | null> {
508
+ return {
509
+ propA: 'propA',
510
+ propB: 10,
511
+ }
512
+ }
513
+ });
514
+
515
+ const controller = new ResourceController(resource);
516
+ const plan = await controller.plan(null, { type: 'resourceType', propC: 'abc' } as any, true);
517
+
518
+ expect(resource.refresh.called).to.be.true;
519
+ expect(resource.refresh.getCall(0).firstArg['propA']).to.exist;
520
+ expect(resource.refresh.getCall(0).firstArg['propB']).to.exist;
521
+ expect(resource.refresh.getCall(0).firstArg['propC']).to.not.exist;
522
+
523
+ expect(plan.currentConfig?.propA).to.eq('propA');
524
+ expect(plan.currentConfig?.propB).to.eq(10);
525
+ expect(plan.currentConfig?.propC).to.be.undefined;
526
+ })
494
527
  })