Skip to content

Commit 40f1e62

Browse files
mrgrainevzzk
andauthored
feat: ESM plugins (#468)
Add examples and note for plugins written in ESM By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. --------- Co-authored-by: Evan Kuranishi <evzz@amazon.com> Co-authored-by: Evan K <113387406+evzzk@users.noreply.github.com>
1 parent 8568a83 commit 40f1e62

File tree

1 file changed

+176
-0
lines changed

1 file changed

+176
-0
lines changed

v2/guide/plugins.adoc

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ To create a CDK Toolkit plugin, you first create a Node.js module, authored in T
3535
[role="tablist"]
3636
TypeScript::
3737
+
38+
*CommonJS*:::
39+
+
3840
[source,typescript,subs="verbatim,attributes"]
3941
----
4042
// Example plugin structure
@@ -53,9 +55,32 @@ const plugin: Plugin = {
5355
5456
export = plugin;
5557
----
58+
+
59+
*ESM*:::
60+
+
61+
[source,typescript,subs="verbatim,attributes"]
62+
----
63+
// Example plugin structure
64+
import type { IPluginHost, Plugin } from '@aws-cdk/cli-plugin-contract';
65+
66+
const plugin: Plugin = {
67+
// Version of the plugin infrastructure (currently always '1')
68+
version: '1',
69+
70+
// Initialization function called when the plugin is loaded
71+
init(host: IPluginHost): void {
72+
// Register your plugin functionality with the host
73+
// For example, register a custom credential provider
74+
}
75+
};
76+
77+
export { plugin as 'module.exports' };
78+
----
5679
5780
JavaScript::
5881
+
82+
*CommonJS*:::
83+
+
5984
[source,javascript,subs="verbatim,attributes"]
6085
----
6186
const plugin = {
@@ -71,6 +96,34 @@ const plugin = {
7196
7297
module.exports = plugin;
7398
----
99+
+
100+
*ESM*:::
101+
+
102+
[source,javascript,subs="verbatim,attributes"]
103+
----
104+
const plugin = {
105+
// Version of the plugin infrastructure (currently always '1')
106+
version: '1',
107+
108+
// Initialization function called when the plugin is loaded
109+
init(host) {
110+
// Register your plugin functionality with the host
111+
// For example, register a custom credential provider
112+
}
113+
};
114+
115+
export { plugin as 'module.exports' };
116+
----
117+
====
118+
119+
[NOTE]
120+
====
121+
CDK Toolkit plugins are loaded as CommonJS modules. You can build your plugin as an ECMAScript module (ESM), but have to link:https://nodejs.org/api/modules.html#loading-ecmascript-modules-using-require[adhere to some constraints]:
122+
123+
--
124+
* The module cannot contain top-level `await`, or import any modules that contain top-level `await`.
125+
* The module must ensure compatibility by exporting the plugin object under the `module.exports` export name: `export { plugin as 'module.exports' }`.
126+
--
74127
====
75128

76129
[#plugins-load-cli]
@@ -177,6 +230,8 @@ To implement a custom credential provider, create a class that implements the re
177230
[role="tablist"]
178231
TypeScript::
179232
+
233+
*CommonJS*:::
234+
+
180235
[source,typescript,subs="verbatim,attributes"]
181236
----
182237
import type { CredentialProviderSource, ForReading, ForWriting, IPluginHost, Plugin, PluginProviderResult, SDKv3CompatibleCredentials } from '@aws-cdk/cli-plugin-contract';
@@ -233,9 +288,70 @@ const plugin: Plugin = {
233288
234289
export = plugin;
235290
----
291+
+
292+
*ESM*:::
293+
+
294+
[source,typescript,subs="verbatim,attributes"]
295+
----
296+
import type { CredentialProviderSource, ForReading, ForWriting, IPluginHost, Plugin, PluginProviderResult, SDKv3CompatibleCredentials } from '@aws-cdk/cli-plugin-contract';
297+
298+
class CustomCredentialProviderSource implements CredentialProviderSource {
299+
// Friendly name for the provider, used in error messages
300+
public readonly name: string = 'custom-credential-provider';
301+
302+
// Check if this provider is available on the current system
303+
public async isAvailable(): Promise<boolean> {
304+
// Return false if the plugin cannot be used
305+
// For example, if it depends on files not present on the host
306+
return true;
307+
}
308+
309+
// Check if this provider can provide credentials for a specific account
310+
public async canProvideCredentials(accountId: string): Promise<boolean> {
311+
// Return false if the plugin cannot provide credentials for this account
312+
// For example, if the account is not managed by this credential system
313+
return true;
314+
// You can use patterns to filter specific accounts
315+
// return accountId.startsWith('123456');
316+
}
317+
318+
// Get credentials for the specified account and access mode
319+
// Returns PluginProviderResult which can be one of:
320+
// - SDKv2CompatibleCredentials (AWS SDK v2 entered maintenance on Sept 8, 2024 and will reach end-of-life on Sept 8, 2025)
321+
// - SDKv3CompatibleCredentialProvider
322+
// - SDKv3CompatibleCredentials
323+
public async getProvider(accountId: string, mode: ForReading | ForWriting): Promise<PluginProviderResult> {
324+
// The access mode can be used to provide different credential sets
325+
const readOnly = mode === 0 satisfies ForReading;
326+
327+
// Create appropriate credentials based on your authentication mechanism
328+
const credentials: SDKv3CompatibleCredentials = {
329+
accessKeyId: 'AKIAIOSFODNN7EXAMPLE',
330+
secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
331+
// Add sessionToken if using temporary credentials
332+
// sessionToken: 'AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKwRcOIfrRh3c/LTo6UDdyJwOOvEVPvLXCrrrUtdnniCEXAMPLE/IvU1dYUg2RVAJBanLiHb4IgRmpRV3zrkuWJOgQs8IZZaIv2BXIa2R4Olgk',
333+
// expireTime: new Date(Date.now() + 3600 * 1000), // 1 hour from now
334+
};
335+
336+
return credentials;
337+
}
338+
}
339+
340+
const plugin: Plugin = {
341+
version: '1',
342+
init(host: IPluginHost): void {
343+
// Register the credential provider to the PluginHost.
344+
host.registerCredentialProviderSource(new CustomCredentialProviderSource());
345+
}
346+
};
347+
348+
export { plugin as 'module.exports' };
349+
----
236350
237351
JavaScript::
238352
+
353+
*CommonJS*:::
354+
+
239355
[source,javascript,subs="verbatim,attributes"]
240356
----
241357
// Implement the CredentialProviderSource interface
@@ -293,6 +409,66 @@ const plugin = {
293409
294410
module.exports = plugin;
295411
----
412+
+
413+
*ESM*:::
414+
+
415+
[source,javascript,subs="verbatim,attributes"]
416+
----
417+
// Implement the CredentialProviderSource interface
418+
class CustomCredentialProviderSource {
419+
constructor() {
420+
// Friendly name for the provider, used in error messages
421+
this.name = 'custom-credential-provider';
422+
}
423+
424+
// Check if this provider is available on the current system
425+
async isAvailable() {
426+
// Return false if the plugin cannot be used
427+
// For example, if it depends on files not present on the host
428+
return true;
429+
}
430+
431+
// Check if this provider can provide credentials for a specific account
432+
async canProvideCredentials(accountId) {
433+
// Return false if the plugin cannot provide credentials for this account
434+
// For example, if the account is not managed by this credential system
435+
return true;
436+
// You can use patterns to filter specific accounts
437+
// return accountId.startsWith('123456');
438+
}
439+
440+
// Get credentials for the specified account and access mode
441+
// Returns PluginProviderResult which can be one of:
442+
// - SDKv2CompatibleCredentials (AWS SDK v2 entered maintenance on Sept 8, 2024 and will reach end-of-life on Sept 8, 2025)
443+
// - SDKv3CompatibleCredentialProvider
444+
// - SDKv3CompatibleCredentials
445+
async getProvider(accountId, mode) {
446+
// The access mode can be used to provide different credential sets
447+
const readOnly = mode === 0; // 0 indicates ForReading; 1 indicates ForWriting
448+
449+
// Create appropriate credentials based on your authentication mechanism
450+
const credentials = {
451+
accessKeyId: 'ASIAIOSFODNN7EXAMPLE',
452+
secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
453+
// Add sessionToken if using temporary credentials
454+
// sessionToken: 'AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKwRcOIfrRh3c/LTo6UDdyJwOOvEVPvLXCrrrUtdnniCEXAMPLE/IvU1dYUg2RVAJBanLiHb4IgRmpRV3zrkuWJOgQs8IZZaIv2BXIa2R4Olgk',
455+
// expireTime: new Date(Date.now() + 3600 * 1000), // 1 hour from now
456+
};
457+
458+
return credentials;
459+
}
460+
}
461+
462+
const plugin = {
463+
version: '1',
464+
init(host) {
465+
// Register the credential provider to the PluginHost.
466+
host.registerCredentialProviderSource(new CustomCredentialProviderSource());
467+
}
468+
};
469+
470+
export { plugin as 'module.exports' };
471+
----
296472
====
297473

298474
[IMPORTANT]

0 commit comments

Comments
 (0)