e2sm 0.2.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,3 +9,38 @@ npx e2sm
9
9
  npx e2sm --dry-run
10
10
  npx e2sm --help
11
11
  ```
12
+
13
+ ## Configuration
14
+
15
+ You can create a `.e2smrc.json` file to set default options.
16
+
17
+ ```json
18
+ {
19
+ "$schema": "https://unpkg.com/e2sm/schema.json",
20
+ "template": true,
21
+ "application": "my-app",
22
+ "stage": "dev",
23
+ "profile": "my-profile",
24
+ "region": "ap-northeast-1",
25
+ "input": ".env.local"
26
+ }
27
+ ```
28
+
29
+ ### Config file locations
30
+
31
+ 1. `./.e2smrc.json` (project) - takes precedence
32
+ 2. `~/.e2smrc.json` (global)
33
+
34
+ Only the first found config is used (no merging).
35
+
36
+ ### Priority
37
+
38
+ CLI flags always take precedence over config file values.
39
+
40
+ ```bash
41
+ # Uses profile from config
42
+ npx e2sm
43
+
44
+ # Overrides config with "prod-profile"
45
+ npx e2sm -p prod-profile
46
+ ```
package/dist/index.mjs CHANGED
@@ -3013,7 +3013,7 @@ BUILT_IN_PREFIX.codePointAt(0);
3013
3013
 
3014
3014
  //#endregion
3015
3015
  //#region package.json
3016
- var version = "0.2.1";
3016
+ var version = "0.4.0";
3017
3017
 
3018
3018
  //#endregion
3019
3019
  //#region src/lib.ts
@@ -3041,6 +3041,25 @@ function validateUnknownFlags(tokens, args) {
3041
3041
  }
3042
3042
  return null;
3043
3043
  }
3044
+ /**
3045
+ * Determines if template mode is active.
3046
+ */
3047
+ function isTemplateMode(flags) {
3048
+ return Boolean(flags.template || flags.application || flags.stage);
3049
+ }
3050
+ /**
3051
+ * Validates that --name flag is not used with template mode flags.
3052
+ */
3053
+ function validateNameTemplateConflict(flags) {
3054
+ if (flags.name && isTemplateMode(flags)) {
3055
+ const conflicting = [];
3056
+ if (flags.template) conflicting.push("--template");
3057
+ if (flags.application) conflicting.push("--application");
3058
+ if (flags.stage) conflicting.push("--stage");
3059
+ return `Cannot use --name with ${conflicting.join(", ")}`;
3060
+ }
3061
+ return null;
3062
+ }
3044
3063
  function parseEnvContent(content) {
3045
3064
  const result = {};
3046
3065
  for (const line of content.split("\n")) {
@@ -3059,6 +3078,29 @@ function parseEnvContent(content) {
3059
3078
  }
3060
3079
  return result;
3061
3080
  }
3081
+ /**
3082
+ * Loads config from .e2smrc.json (project or global).
3083
+ * Returns empty object if no config found.
3084
+ */
3085
+ async function loadConfig() {
3086
+ const { homedir } = await import("node:os");
3087
+ const { join } = await import("node:path");
3088
+ const candidates = [join(process.cwd(), ".e2smrc.json"), join(homedir(), ".e2smrc.json")];
3089
+ for (const filePath of candidates) try {
3090
+ const file = Bun.file(filePath);
3091
+ if (await file.exists()) return await file.json();
3092
+ } catch {}
3093
+ return {};
3094
+ }
3095
+ /**
3096
+ * Merges CLI flags with config. CLI takes precedence.
3097
+ */
3098
+ function mergeWithConfig(cliValues, config) {
3099
+ return {
3100
+ ...config,
3101
+ ...Object.fromEntries(Object.entries(cliValues).filter(([, v$1]) => v$1 !== void 0))
3102
+ };
3103
+ }
3062
3104
 
3063
3105
  //#endregion
3064
3106
  //#region src/index.ts
@@ -3121,19 +3163,41 @@ const command = define({
3121
3163
  type: "string",
3122
3164
  short: "r",
3123
3165
  description: "AWS region to use (e.g., ap-northeast-1)"
3166
+ },
3167
+ template: {
3168
+ type: "boolean",
3169
+ short: "t",
3170
+ description: "Use template mode: generate secret name as $application/$stage"
3171
+ },
3172
+ application: {
3173
+ type: "string",
3174
+ short: "a",
3175
+ description: "Application name for template mode (implies --template)"
3176
+ },
3177
+ stage: {
3178
+ type: "string",
3179
+ short: "s",
3180
+ description: "Stage name for template mode (implies --template)"
3124
3181
  }
3125
3182
  },
3126
3183
  run: async (ctx) => {
3184
+ const config = await loadConfig();
3127
3185
  const unknownFlagError = validateUnknownFlags(ctx.tokens, ctx.args);
3128
3186
  if (unknownFlagError) {
3129
3187
  console.error(unknownFlagError);
3130
3188
  process.exit(1);
3131
3189
  }
3190
+ const conflictError = validateNameTemplateConflict(ctx.values);
3191
+ if (conflictError) {
3192
+ console.error(conflictError);
3193
+ process.exit(1);
3194
+ }
3195
+ const merged = mergeWithConfig(ctx.values, config);
3132
3196
  const isDryRun = ctx.values.dryRun;
3133
- const profile = ctx.values.profile;
3134
- const inputFlag = ctx.values.input;
3197
+ const profile = merged.profile;
3198
+ const inputFlag = merged.input;
3135
3199
  const nameFlag = ctx.values.name;
3136
- const region = ctx.values.region;
3200
+ const region = merged.region;
3137
3201
  Ie(`e2sm v${version} - env to AWS Secrets Manager`);
3138
3202
  let envFilePath;
3139
3203
  if (inputFlag) envFilePath = inputFlag;
@@ -3169,8 +3233,46 @@ const command = define({
3169
3233
  return;
3170
3234
  }
3171
3235
  let secretName;
3236
+ const templateFlag = merged.template;
3237
+ const applicationFlag = merged.application;
3238
+ const stageFlag = merged.stage;
3239
+ const useTemplateMode = isTemplateMode({
3240
+ template: templateFlag,
3241
+ application: applicationFlag,
3242
+ stage: stageFlag
3243
+ });
3172
3244
  if (nameFlag) secretName = nameFlag;
3173
- else {
3245
+ else if (useTemplateMode) {
3246
+ let application;
3247
+ let stage;
3248
+ if (applicationFlag) application = applicationFlag;
3249
+ else {
3250
+ const result = await he({
3251
+ message: "Enter the application name:",
3252
+ placeholder: "my-app",
3253
+ defaultValue: "my-app"
3254
+ });
3255
+ if (isCancel(result)) {
3256
+ xe("Operation cancelled");
3257
+ process.exit(0);
3258
+ }
3259
+ application = result;
3260
+ }
3261
+ if (stageFlag) stage = stageFlag;
3262
+ else {
3263
+ const result = await he({
3264
+ message: "Enter the stage name:",
3265
+ placeholder: "dev",
3266
+ defaultValue: "dev"
3267
+ });
3268
+ if (isCancel(result)) {
3269
+ xe("Operation cancelled");
3270
+ process.exit(0);
3271
+ }
3272
+ stage = result;
3273
+ }
3274
+ secretName = `${application}/${stage}`;
3275
+ } else {
3174
3276
  const result = await he({
3175
3277
  message: "Enter the secret name for AWS Secrets Manager:",
3176
3278
  placeholder: "my-app/default",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "e2sm",
3
- "version": "0.2.1",
3
+ "version": "0.4.0",
4
4
  "license": "MIT",
5
5
  "author": "mfyuu",
6
6
  "repository": {
@@ -11,7 +11,8 @@
11
11
  "e2sm": "dist/index.mjs"
12
12
  },
13
13
  "files": [
14
- "dist"
14
+ "dist",
15
+ "schema.json"
15
16
  ],
16
17
  "type": "module",
17
18
  "publishConfig": {
package/schema.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "e2sm configuration",
4
+ "type": "object",
5
+ "properties": {
6
+ "$schema": {
7
+ "type": "string"
8
+ },
9
+ "template": {
10
+ "type": "boolean",
11
+ "description": "Use template mode: generate secret name as $application/$stage"
12
+ },
13
+ "application": {
14
+ "type": "string",
15
+ "description": "Application name for template mode"
16
+ },
17
+ "stage": {
18
+ "type": "string",
19
+ "description": "Stage name for template mode"
20
+ },
21
+ "profile": {
22
+ "type": "string",
23
+ "description": "AWS profile to use"
24
+ },
25
+ "region": {
26
+ "type": "string",
27
+ "description": "AWS region to use"
28
+ },
29
+ "input": {
30
+ "type": "string",
31
+ "description": "Path to the .env file"
32
+ }
33
+ },
34
+ "additionalProperties": false
35
+ }