serverless-plugin-env-stage-config 1.4.1 → 2.0.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 +5 -4
- package/dist/index.d.mts +42 -0
- package/dist/index.mjs +78 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +37 -16
- package/index.js +0 -54
package/README.md
CHANGED
|
@@ -3,17 +3,18 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/serverless-plugin-env-stage-config)
|
|
4
4
|
[](https://github.com/xojs/xo)
|
|
5
5
|
|
|
6
|
-
This [
|
|
6
|
+
This plugin for [**osls**](https://github.com/oss-serverless/osls) (Open Source ServerLeSs) lets you define environment variable configuration files for stages.
|
|
7
7
|
It exposes a new variable resolver (`$esc`) that automatically picks the correct value based on the selected stage.
|
|
8
8
|
For development stages (`local`, `dev`, `development`), the variables will default to the system’s environment variables.
|
|
9
9
|
|
|
10
|
-
> [!
|
|
11
|
-
> This plugin
|
|
10
|
+
> [!IMPORTANT]
|
|
11
|
+
> This plugin targets [**osls**](https://github.com/oss-serverless/osls) — the community-maintained fork of Serverless Framework v3, published as [`osls`](https://www.npmjs.com/package/osls) on npm. The `$esc` resolver relies on the v3 configuration-variables-sources API.
|
|
12
12
|
|
|
13
13
|
## CI
|
|
14
14
|
|
|
15
15
|
[](https://github.com/bizon/serverless-plugin-env-stage-config/actions/workflows/tests.yml)
|
|
16
16
|
[](https://github.com/bizon/serverless-plugin-env-stage-config/actions/workflows/release.yml)
|
|
17
|
+
[](https://codecov.io/github/bizon/serverless-plugin-env-stage-config)
|
|
17
18
|
|
|
18
19
|
## Installation
|
|
19
20
|
|
|
@@ -94,7 +95,7 @@ MIT
|
|
|
94
95
|
|
|
95
96
|
## Miscellaneous
|
|
96
97
|
|
|
97
|
-
```
|
|
98
|
+
```text
|
|
98
99
|
╚⊙ ⊙╝
|
|
99
100
|
╚═(███)═╝
|
|
100
101
|
╚═(███)═╝
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//#region src/index.d.ts
|
|
2
|
+
interface ServerlessOptions {
|
|
3
|
+
stage?: string;
|
|
4
|
+
}
|
|
5
|
+
interface Serverless {
|
|
6
|
+
serviceDir: string;
|
|
7
|
+
service: {
|
|
8
|
+
provider: {
|
|
9
|
+
stage: string;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
cli: {
|
|
13
|
+
log(message: string, entity?: string, options?: {
|
|
14
|
+
color?: string;
|
|
15
|
+
}): void;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
interface ConfigVariableSource {
|
|
19
|
+
address: string;
|
|
20
|
+
}
|
|
21
|
+
declare class EnvironmentStageConfigServerlessPlugin {
|
|
22
|
+
serverless: Serverless;
|
|
23
|
+
options: ServerlessOptions;
|
|
24
|
+
stage: string;
|
|
25
|
+
stageVariables: Record<string, unknown> | undefined;
|
|
26
|
+
configurationVariablesSources: {
|
|
27
|
+
esc: {
|
|
28
|
+
resolve: (source: ConfigVariableSource) => Promise<{
|
|
29
|
+
value: unknown;
|
|
30
|
+
}>;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
constructor(serverless: Serverless, options: ServerlessOptions);
|
|
34
|
+
resolveConfigVariable({
|
|
35
|
+
address
|
|
36
|
+
}: ConfigVariableSource): Promise<{
|
|
37
|
+
value: unknown;
|
|
38
|
+
}>;
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
export { EnvironmentStageConfigServerlessPlugin as default };
|
|
42
|
+
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import yaml from "js-yaml";
|
|
4
|
+
//#region src/cloudformation-schema.ts
|
|
5
|
+
const functionNames = [
|
|
6
|
+
"And",
|
|
7
|
+
"Base64",
|
|
8
|
+
"Cidr",
|
|
9
|
+
"Condition",
|
|
10
|
+
"Equals",
|
|
11
|
+
"FindInMap",
|
|
12
|
+
"GetAtt",
|
|
13
|
+
"GetAZs",
|
|
14
|
+
"If",
|
|
15
|
+
"ImportValue",
|
|
16
|
+
"Join",
|
|
17
|
+
"Not",
|
|
18
|
+
"Or",
|
|
19
|
+
"Ref",
|
|
20
|
+
"Select",
|
|
21
|
+
"Split",
|
|
22
|
+
"Sub"
|
|
23
|
+
];
|
|
24
|
+
const kinds = [
|
|
25
|
+
"mapping",
|
|
26
|
+
"scalar",
|
|
27
|
+
"sequence"
|
|
28
|
+
];
|
|
29
|
+
const yamlType = (name, kind) => {
|
|
30
|
+
const functionName = name === "Ref" || name === "Condition" ? name : `Fn::${name}`;
|
|
31
|
+
return new yaml.Type(`!${name}`, {
|
|
32
|
+
kind,
|
|
33
|
+
construct(data) {
|
|
34
|
+
if (name === "GetAtt" && typeof data === "string") {
|
|
35
|
+
const [first, ...tail] = data.split(".");
|
|
36
|
+
return { [functionName]: [first, tail.join(".")] };
|
|
37
|
+
}
|
|
38
|
+
return { [functionName]: data };
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
const types = functionNames.flatMap((functionName) => kinds.map((kind) => yamlType(functionName, kind)));
|
|
43
|
+
const cloudformationSchema = yaml.DEFAULT_SCHEMA.extend(types);
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/index.ts
|
|
46
|
+
const developmentStages = /* @__PURE__ */ new Set([
|
|
47
|
+
"local",
|
|
48
|
+
"development",
|
|
49
|
+
"dev"
|
|
50
|
+
]);
|
|
51
|
+
var EnvironmentStageConfigServerlessPlugin = class {
|
|
52
|
+
serverless;
|
|
53
|
+
options;
|
|
54
|
+
stage;
|
|
55
|
+
stageVariables;
|
|
56
|
+
configurationVariablesSources;
|
|
57
|
+
constructor(serverless, options) {
|
|
58
|
+
this.serverless = serverless;
|
|
59
|
+
this.options = options;
|
|
60
|
+
this.stage = options.stage ?? serverless.service.provider.stage;
|
|
61
|
+
this.configurationVariablesSources = { esc: { resolve: this.resolveConfigVariable.bind(this) } };
|
|
62
|
+
if (!developmentStages.has(this.stage)) {
|
|
63
|
+
const stageConfigYaml = readFileSync(path.join(this.serverless.serviceDir, `serverless.env.${this.stage}.yml`), "utf8");
|
|
64
|
+
this.stageVariables = yaml.load(stageConfigYaml, { schema: cloudformationSchema });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async resolveConfigVariable({ address }) {
|
|
68
|
+
if (this.stageVariables) {
|
|
69
|
+
if (Object.hasOwn(this.stageVariables, address)) return { value: this.stageVariables[address] };
|
|
70
|
+
this.serverless.cli.log(`env-stage-config: WARNING: the ${address} variable is not defined in serverless.env.${this.stage}.yml, defaulting to \${env:${address}, null}.`, void 0, { color: "orange" });
|
|
71
|
+
}
|
|
72
|
+
return { value: `\${env:${address}, null}` };
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
//#endregion
|
|
76
|
+
export { EnvironmentStageConfigServerlessPlugin as default };
|
|
77
|
+
|
|
78
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/cloudformation-schema.ts","../src/index.ts"],"sourcesContent":["// Ported from Serverless Framework's @serverless/utils (MIT), which osls also\n// vendors internally. See https://github.com/oss-serverless/osls/issues/147\n\nimport yaml from 'js-yaml'\n\n// CloudFormation intrinsic functions that can appear as YAML tags (e.g. `!Ref`,\n// `!GetAtt`, `!Sub`) in serverless.env.<stage>.yml files.\nconst functionNames = [\n 'And',\n 'Base64',\n 'Cidr',\n 'Condition',\n 'Equals',\n 'FindInMap',\n 'GetAtt',\n 'GetAZs',\n 'If',\n 'ImportValue',\n 'Join',\n 'Not',\n 'Or',\n 'Ref',\n 'Select',\n 'Split',\n 'Sub',\n]\n\ntype YamlKind = 'mapping' | 'scalar' | 'sequence'\n\nconst kinds: YamlKind[] = ['mapping', 'scalar', 'sequence']\n\nconst yamlType = (name: string, kind: YamlKind) => {\n const functionName = name === 'Ref' || name === 'Condition' ? name : `Fn::${name}`\n return new yaml.Type(`!${name}`, {\n kind,\n construct(data: unknown) {\n // Special GetAtt dot syntax: `!GetAtt Resource.Attribute`\n if (name === 'GetAtt' && typeof data === 'string') {\n const [first, ...tail] = data.split('.')\n return {[functionName]: [first, tail.join('.')]}\n }\n\n return {[functionName]: data}\n },\n })\n}\n\nconst types = functionNames.flatMap((functionName) =>\n kinds.map((kind) => yamlType(functionName, kind)),\n)\n\nexport const cloudformationSchema = yaml.DEFAULT_SCHEMA.extend(types)\n","import {readFileSync} from 'node:fs'\nimport path from 'node:path'\n\nimport yaml from 'js-yaml'\n\nimport {cloudformationSchema} from './cloudformation-schema.js'\n\nconst developmentStages = new Set(['local', 'development', 'dev'])\n\ninterface ServerlessOptions {\n stage?: string\n}\n\ninterface Serverless {\n serviceDir: string\n service: {\n provider: {\n stage: string\n }\n }\n cli: {\n log(message: string, entity?: string, options?: {color?: string}): void\n }\n}\n\ninterface ConfigVariableSource {\n address: string\n}\n\nexport default class EnvironmentStageConfigServerlessPlugin {\n serverless: Serverless\n options: ServerlessOptions\n stage: string\n stageVariables: Record<string, unknown> | undefined\n configurationVariablesSources: {\n esc: {\n resolve: (source: ConfigVariableSource) => Promise<{value: unknown}>\n }\n }\n\n constructor(serverless: Serverless, options: ServerlessOptions) {\n this.serverless = serverless\n this.options = options\n this.stage = options.stage ?? serverless.service.provider.stage\n\n this.configurationVariablesSources = {\n esc: {\n resolve: this.resolveConfigVariable.bind(this),\n },\n }\n\n if (!developmentStages.has(this.stage)) {\n const stageConfigYaml = readFileSync(\n path.join(this.serverless.serviceDir, `serverless.env.${this.stage}.yml`),\n 'utf8',\n )\n\n // YAML load returns `unknown`; a stage config file is always a mapping.\n this.stageVariables = yaml.load(stageConfigYaml, {\n schema: cloudformationSchema,\n }) as Record<string, unknown>\n }\n }\n\n async resolveConfigVariable({address}: ConfigVariableSource) {\n if (this.stageVariables) {\n if (Object.hasOwn(this.stageVariables, address)) {\n return {\n value: this.stageVariables[address],\n }\n }\n\n this.serverless.cli.log(\n `env-stage-config: WARNING: the ${address} variable is not defined in serverless.env.${this.stage}.yml, defaulting to \\${env:${address}, null}.`,\n undefined,\n {color: 'orange'},\n )\n }\n\n return {\n value: `\\${env:${address}, null}`,\n }\n }\n}\n"],"mappings":";;;;AAOA,MAAM,gBAAgB;CACpB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAIA,MAAM,QAAoB;CAAC;CAAW;CAAU;AAAU;AAE1D,MAAM,YAAY,MAAc,SAAmB;CACjD,MAAM,eAAe,SAAS,SAAS,SAAS,cAAc,OAAO,OAAO;CAC5E,OAAO,IAAI,KAAK,KAAK,IAAI,QAAQ;EAC/B;EACA,UAAU,MAAe;GAEvB,IAAI,SAAS,YAAY,OAAO,SAAS,UAAU;IACjD,MAAM,CAAC,OAAO,GAAG,QAAQ,KAAK,MAAM,GAAG;IACvC,OAAO,GAAE,eAAe,CAAC,OAAO,KAAK,KAAK,GAAG,CAAC,EAAC;GACjD;GAEA,OAAO,GAAE,eAAe,KAAI;EAC9B;CACF,CAAC;AACH;AAEA,MAAM,QAAQ,cAAc,SAAS,iBACnC,MAAM,KAAK,SAAS,SAAS,cAAc,IAAI,CAAC,CAClD;AAEA,MAAa,uBAAuB,KAAK,eAAe,OAAO,KAAK;;;AC5CpE,MAAM,oCAAoB,IAAI,IAAI;CAAC;CAAS;CAAe;AAAK,CAAC;AAsBjE,IAAqB,yCAArB,MAA4D;CAC1D;CACA;CACA;CACA;CACA;CAMA,YAAY,YAAwB,SAA4B;EAC9D,KAAK,aAAa;EAClB,KAAK,UAAU;EACf,KAAK,QAAQ,QAAQ,SAAS,WAAW,QAAQ,SAAS;EAE1D,KAAK,gCAAgC,EACnC,KAAK,EACH,SAAS,KAAK,sBAAsB,KAAK,IAAI,EAC/C,EACF;EAEA,IAAI,CAAC,kBAAkB,IAAI,KAAK,KAAK,GAAG;GACtC,MAAM,kBAAkB,aACtB,KAAK,KAAK,KAAK,WAAW,YAAY,kBAAkB,KAAK,MAAM,KAAK,GACxE,MACF;GAGA,KAAK,iBAAiB,KAAK,KAAK,iBAAiB,EAC/C,QAAQ,qBACV,CAAC;EACH;CACF;CAEA,MAAM,sBAAsB,EAAC,WAAgC;EAC3D,IAAI,KAAK,gBAAgB;GACvB,IAAI,OAAO,OAAO,KAAK,gBAAgB,OAAO,GAC5C,OAAO,EACL,OAAO,KAAK,eAAe,SAC7B;GAGF,KAAK,WAAW,IAAI,IAClB,kCAAkC,QAAQ,6CAA6C,KAAK,MAAM,6BAA6B,QAAQ,WACvI,KAAA,GACA,EAAC,OAAO,SAAQ,CAClB;EACF;EAEA,OAAO,EACL,OAAO,UAAU,QAAQ,SAC3B;CACF;AACF"}
|
package/package.json
CHANGED
|
@@ -1,39 +1,60 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "serverless-plugin-env-stage-config",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "osls (Serverless Framework v3) plugin to define environment variable files for stages",
|
|
4
5
|
"author": "Bertrand Marron <bertrand.marron@gmail.com>",
|
|
5
|
-
"
|
|
6
|
+
"repository": "https://github.com/bizon/serverless-plugin-env-stage-config",
|
|
6
7
|
"type": "module",
|
|
7
|
-
"
|
|
8
|
+
"sideEffects": false,
|
|
9
|
+
"source": "./src/index.ts",
|
|
10
|
+
"module": "./dist/index.mjs",
|
|
11
|
+
"types": "./dist/index.d.mts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.mts",
|
|
15
|
+
"default": "./dist/index.mjs"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
8
18
|
"files": [
|
|
9
|
-
"
|
|
19
|
+
"dist"
|
|
10
20
|
],
|
|
11
21
|
"engines": {
|
|
12
22
|
"node": ">=24"
|
|
13
23
|
},
|
|
14
|
-
"repository": "https://github.com/bizon/serverless-plugin-env-stage-config",
|
|
15
24
|
"license": "MIT",
|
|
16
25
|
"keywords": [
|
|
26
|
+
"osls",
|
|
17
27
|
"serverless",
|
|
18
28
|
"serverless-plugin"
|
|
19
29
|
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"test": "NODE_OPTIONS=--experimental-vm-modules jest",
|
|
32
|
+
"check:ts": "tsc --noEmit",
|
|
33
|
+
"build": "tsdown",
|
|
34
|
+
"dev": "tsdown --watch"
|
|
35
|
+
},
|
|
20
36
|
"dependencies": {
|
|
21
|
-
"
|
|
22
|
-
"js-yaml": "^4.1.1"
|
|
37
|
+
"js-yaml": "^4.1.0"
|
|
23
38
|
},
|
|
24
39
|
"devDependencies": {
|
|
25
40
|
"@bizon/semantic-release-config": "^3.1.0",
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
41
|
+
"@jest/globals": "^30.4.1",
|
|
42
|
+
"@swc/core": "^1.15.40",
|
|
43
|
+
"@swc/jest": "^0.2.39",
|
|
44
|
+
"@tsconfig/node24": "^24.0.4",
|
|
45
|
+
"@types/js-yaml": "^4.0.9",
|
|
46
|
+
"@types/node": "^24.12.4",
|
|
47
|
+
"eslint-config-xo-bizon": "^4.4.0",
|
|
48
|
+
"jest": "^30.4.2",
|
|
49
|
+
"jest-junit": "^17.0.0",
|
|
50
|
+
"semantic-release": "^25.0.5",
|
|
51
|
+
"ts-node": "^10.9.2",
|
|
52
|
+
"tsdown": "^0.22.3",
|
|
53
|
+
"typescript": "^6.0.3",
|
|
54
|
+
"xo": "^3.0.2"
|
|
34
55
|
},
|
|
35
56
|
"release": {
|
|
36
57
|
"extends": "@bizon/semantic-release-config"
|
|
37
58
|
},
|
|
38
|
-
"packageManager": "pnpm@10.
|
|
59
|
+
"packageManager": "pnpm@11.10.0+sha512.0b7f8b98060031904c017e3a41eb187a16d40eeb829b95c4f8cb03681761fc4ab53dd219115b9b447f4dce1a05a214764461e7d3703392a9f32f9511ce8c86c8"
|
|
39
60
|
}
|
package/index.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import {readFileSync} from 'node:fs'
|
|
2
|
-
import path from 'node:path'
|
|
3
|
-
|
|
4
|
-
import cloudformationSchema from '@serverless/utils/cloudformation-schema.js'
|
|
5
|
-
import yaml from 'js-yaml'
|
|
6
|
-
|
|
7
|
-
const developmentStages = new Set([
|
|
8
|
-
'local',
|
|
9
|
-
'development',
|
|
10
|
-
'dev',
|
|
11
|
-
])
|
|
12
|
-
|
|
13
|
-
export default class EnvironmentStageConfigServerlessPlugin {
|
|
14
|
-
constructor(serverless, options) {
|
|
15
|
-
this.serverless = serverless
|
|
16
|
-
this.options = options
|
|
17
|
-
this.stage = options.stage ?? serverless.service.provider.stage
|
|
18
|
-
|
|
19
|
-
this.configurationVariablesSources = {
|
|
20
|
-
esc: {
|
|
21
|
-
resolve: this.resolveConfigVariable.bind(this),
|
|
22
|
-
},
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (!developmentStages.has(this.stage)) {
|
|
26
|
-
const stageConfigYaml = readFileSync(path.join(this.serverless.serviceDir, `serverless.env.${this.stage}.yml`))
|
|
27
|
-
|
|
28
|
-
this.stageVariables = yaml.load(stageConfigYaml, {
|
|
29
|
-
schema: cloudformationSchema,
|
|
30
|
-
})
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async resolveConfigVariable({address}) {
|
|
35
|
-
if (this.stageVariables) {
|
|
36
|
-
if (address in this.stageVariables) {
|
|
37
|
-
return {
|
|
38
|
-
value: this.stageVariables[address],
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
this.serverless.cli.log(
|
|
43
|
-
`env-stage-config: WARNING: the ${address} variable is not defined in serverless.env.${this.stage}.yml, defaulting to \${env:${address}, null}.`,
|
|
44
|
-
null,
|
|
45
|
-
{color: 'orange'},
|
|
46
|
-
)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
value: `\${env:${address}, null}`,
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|