@composurecdk/cloudformation 0.6.0 → 0.8.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/dist/commonjs/apply-builder-tags.d.ts +32 -0
- package/dist/commonjs/apply-builder-tags.d.ts.map +1 -0
- package/dist/commonjs/apply-builder-tags.js +69 -0
- package/dist/commonjs/apply-builder-tags.js.map +1 -0
- package/dist/commonjs/index.d.ts +8 -0
- package/dist/commonjs/index.d.ts.map +1 -0
- package/dist/commonjs/index.js +20 -0
- package/dist/commonjs/index.js.map +1 -0
- package/dist/commonjs/outputs.d.ts.map +1 -0
- package/dist/commonjs/outputs.js +77 -0
- package/dist/commonjs/outputs.js.map +1 -0
- package/dist/commonjs/package.json +3 -0
- package/dist/{stack-builder.d.ts → commonjs/stack-builder.d.ts} +14 -18
- package/dist/commonjs/stack-builder.d.ts.map +1 -0
- package/dist/commonjs/stack-builder.js +47 -0
- package/dist/commonjs/stack-builder.js.map +1 -0
- package/dist/commonjs/strategies.d.ts.map +1 -0
- package/dist/commonjs/strategies.js +80 -0
- package/dist/commonjs/strategies.js.map +1 -0
- package/dist/commonjs/tag-validator.d.ts +22 -0
- package/dist/commonjs/tag-validator.d.ts.map +1 -0
- package/dist/commonjs/tag-validator.js +67 -0
- package/dist/commonjs/tag-validator.js.map +1 -0
- package/dist/commonjs/tagged-builder.d.ts +112 -0
- package/dist/commonjs/tagged-builder.d.ts.map +1 -0
- package/dist/commonjs/tagged-builder.js +121 -0
- package/dist/commonjs/tagged-builder.js.map +1 -0
- package/dist/commonjs/tags.d.ts +91 -0
- package/dist/commonjs/tags.d.ts.map +1 -0
- package/dist/commonjs/tags.js +86 -0
- package/dist/commonjs/tags.js.map +1 -0
- package/dist/esm/apply-builder-tags.d.ts +32 -0
- package/dist/esm/apply-builder-tags.d.ts.map +1 -0
- package/dist/esm/apply-builder-tags.js +65 -0
- package/dist/esm/apply-builder-tags.js.map +1 -0
- package/dist/esm/index.d.ts +8 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +8 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/outputs.d.ts +84 -0
- package/dist/esm/outputs.d.ts.map +1 -0
- package/dist/esm/outputs.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/stack-builder.d.ts +79 -0
- package/dist/esm/stack-builder.d.ts.map +1 -0
- package/dist/{stack-builder.js → esm/stack-builder.js} +9 -19
- package/dist/esm/stack-builder.js.map +1 -0
- package/dist/esm/strategies.d.ts +70 -0
- package/dist/esm/strategies.d.ts.map +1 -0
- package/dist/esm/strategies.js.map +1 -0
- package/dist/esm/tag-validator.d.ts +22 -0
- package/dist/esm/tag-validator.d.ts.map +1 -0
- package/dist/esm/tag-validator.js +63 -0
- package/dist/esm/tag-validator.js.map +1 -0
- package/dist/esm/tagged-builder.d.ts +112 -0
- package/dist/esm/tagged-builder.d.ts.map +1 -0
- package/dist/esm/tagged-builder.js +117 -0
- package/dist/esm/tagged-builder.js.map +1 -0
- package/dist/esm/tags.d.ts +91 -0
- package/dist/esm/tags.d.ts.map +1 -0
- package/dist/esm/tags.js +83 -0
- package/dist/esm/tags.js.map +1 -0
- package/package.json +33 -15
- package/dist/index.d.ts +0 -4
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -4
- package/dist/index.js.map +0 -1
- package/dist/outputs.d.ts.map +0 -1
- package/dist/outputs.js.map +0 -1
- package/dist/stack-builder.d.ts.map +0 -1
- package/dist/stack-builder.js.map +0 -1
- package/dist/strategies.d.ts.map +0 -1
- package/dist/strategies.js.map +0 -1
- /package/dist/{outputs.d.ts → commonjs/outputs.d.ts} +0 -0
- /package/dist/{strategies.d.ts → commonjs/strategies.d.ts} +0 -0
- /package/dist/{outputs.js → esm/outputs.js} +0 -0
- /package/dist/{strategies.js → esm/strategies.js} +0 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type IConstruct } from "constructs";
|
|
2
|
+
/**
|
|
3
|
+
* Applies every accumulated tag to every {@link IConstruct} reachable in a
|
|
4
|
+
* builder result.
|
|
5
|
+
*
|
|
6
|
+
* Recursively descends through plain-object literals, tagging every
|
|
7
|
+
* `IConstruct` it finds. Stops at:
|
|
8
|
+
*
|
|
9
|
+
* - **Constructs** — tagged via `Tags.of(...).add(...)`. The CDK Aspect
|
|
10
|
+
* schedules tag application across the construct's subtree at
|
|
11
|
+
* synth-prepare time, so the walker does not recurse into the construct's
|
|
12
|
+
* internals.
|
|
13
|
+
* - **Class instances that aren't constructs** (e.g. `PolicyDocument`) —
|
|
14
|
+
* skipped. Plain-object detection requires `Object.prototype` as the
|
|
15
|
+
* prototype, so class instances are opaque to the walker.
|
|
16
|
+
* - **Arrays and primitives** — skipped.
|
|
17
|
+
*
|
|
18
|
+
* The contract this implements: every construct exposed in a builder's
|
|
19
|
+
* result type is a tag target. Wrapper shapes such as
|
|
20
|
+
* `Record<string, { construct: ..., metadata: ... }>` are unwrapped
|
|
21
|
+
* naturally — the walker descends through the plain-object value and tags
|
|
22
|
+
* the construct field. Authors do not need an opt-in marker; if a construct
|
|
23
|
+
* appears in the result, it is tagged.
|
|
24
|
+
*/
|
|
25
|
+
export declare function applyBuilderTags(result: object, tags: ReadonlyMap<string, string>): void;
|
|
26
|
+
/**
|
|
27
|
+
* Applies every entry of `tags` to `target` via `Tags.of(target).add(...)`.
|
|
28
|
+
* Accepts any iterable of `[key, value]` pairs so callers can pass `Map`,
|
|
29
|
+
* `Object.entries(record)`, or other compatible sources without copying.
|
|
30
|
+
*/
|
|
31
|
+
export declare function applyTagsToConstruct(target: IConstruct, tags: Iterable<[string, string]>): void;
|
|
32
|
+
//# sourceMappingURL=apply-builder-tags.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply-builder-tags.d.ts","sourceRoot":"","sources":["../../src/apply-builder-tags.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAMxD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAGxF;AAcD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,IAAI,CAK/F"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.applyBuilderTags = applyBuilderTags;
|
|
4
|
+
exports.applyTagsToConstruct = applyTagsToConstruct;
|
|
5
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
6
|
+
const constructs_1 = require("constructs");
|
|
7
|
+
function isConstruct(value) {
|
|
8
|
+
return value !== null && typeof value === "object" && constructs_1.Construct.isConstruct(value);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Applies every accumulated tag to every {@link IConstruct} reachable in a
|
|
12
|
+
* builder result.
|
|
13
|
+
*
|
|
14
|
+
* Recursively descends through plain-object literals, tagging every
|
|
15
|
+
* `IConstruct` it finds. Stops at:
|
|
16
|
+
*
|
|
17
|
+
* - **Constructs** — tagged via `Tags.of(...).add(...)`. The CDK Aspect
|
|
18
|
+
* schedules tag application across the construct's subtree at
|
|
19
|
+
* synth-prepare time, so the walker does not recurse into the construct's
|
|
20
|
+
* internals.
|
|
21
|
+
* - **Class instances that aren't constructs** (e.g. `PolicyDocument`) —
|
|
22
|
+
* skipped. Plain-object detection requires `Object.prototype` as the
|
|
23
|
+
* prototype, so class instances are opaque to the walker.
|
|
24
|
+
* - **Arrays and primitives** — skipped.
|
|
25
|
+
*
|
|
26
|
+
* The contract this implements: every construct exposed in a builder's
|
|
27
|
+
* result type is a tag target. Wrapper shapes such as
|
|
28
|
+
* `Record<string, { construct: ..., metadata: ... }>` are unwrapped
|
|
29
|
+
* naturally — the walker descends through the plain-object value and tags
|
|
30
|
+
* the construct field. Authors do not need an opt-in marker; if a construct
|
|
31
|
+
* appears in the result, it is tagged.
|
|
32
|
+
*/
|
|
33
|
+
function applyBuilderTags(result, tags) {
|
|
34
|
+
if (tags.size === 0)
|
|
35
|
+
return;
|
|
36
|
+
walkAndTag(result, tags);
|
|
37
|
+
}
|
|
38
|
+
function walkAndTag(value, tags) {
|
|
39
|
+
if (isConstruct(value)) {
|
|
40
|
+
applyTagsToConstruct(value, tags);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (isPlainObject(value)) {
|
|
44
|
+
for (const inner of Object.values(value)) {
|
|
45
|
+
walkAndTag(inner, tags);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Applies every entry of `tags` to `target` via `Tags.of(target).add(...)`.
|
|
51
|
+
* Accepts any iterable of `[key, value]` pairs so callers can pass `Map`,
|
|
52
|
+
* `Object.entries(record)`, or other compatible sources without copying.
|
|
53
|
+
*/
|
|
54
|
+
function applyTagsToConstruct(target, tags) {
|
|
55
|
+
const t = aws_cdk_lib_1.Tags.of(target);
|
|
56
|
+
for (const [key, value] of tags) {
|
|
57
|
+
t.add(key, value);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function isPlainObject(value) {
|
|
61
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
62
|
+
return false;
|
|
63
|
+
// Accept both `{...}` literals and `Object.create(null)` dictionaries — the
|
|
64
|
+
// latter is a common idiom for prototype-pollution-safe key/value maps and
|
|
65
|
+
// would otherwise be silently skipped here.
|
|
66
|
+
const proto = Object.getPrototypeOf(value);
|
|
67
|
+
return proto === null || proto === Object.prototype;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=apply-builder-tags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply-builder-tags.js","sourceRoot":"","sources":["../../src/apply-builder-tags.ts"],"names":[],"mappings":";;AA8BA,4CAGC;AAmBD,oDAKC;AAzDD,6CAAmC;AACnC,2CAAwD;AAExD,SAAS,WAAW,CAAC,KAAc;IACjC,OAAO,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,sBAAS,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;AACrF,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,SAAgB,gBAAgB,CAAC,MAAc,EAAE,IAAiC;IAChF,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO;IAC5B,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,UAAU,CAAC,KAAc,EAAE,IAAiC;IACnE,IAAI,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;QACvB,oBAAoB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAClC,OAAO;IACT,CAAC;IACD,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACzC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAgB,oBAAoB,CAAC,MAAkB,EAAE,IAAgC;IACvF,MAAM,CAAC,GAAG,kBAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;IAC1B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;QAChC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACpB,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACtF,4EAA4E;IAC5E,2EAA2E;IAC3E,4CAA4C;IAC5C,MAAM,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC,KAAK,CAAkB,CAAC;IAC5D,OAAO,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,MAAM,CAAC,SAAS,CAAC;AACtD,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { createStackBuilder, type IStackBuilder, type StackBuilderResult, } from "./stack-builder.js";
|
|
2
|
+
export { singleStack, groupedStacks } from "./strategies.js";
|
|
3
|
+
export { outputs, type OutputDefinition, type OutputDefinitions } from "./outputs.js";
|
|
4
|
+
export { taggedBuilder, type ITaggedBuilder, TAG_OVERRIDE_WARNING_NAME } from "./tagged-builder.js";
|
|
5
|
+
export { applyBuilderTags } from "./apply-builder-tags.js";
|
|
6
|
+
export { validateTag } from "./tag-validator.js";
|
|
7
|
+
export { tags, type TagDefinitions } from "./tags.js";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,KAAK,aAAa,EAClB,KAAK,kBAAkB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtF,OAAO,EAAE,aAAa,EAAE,KAAK,cAAc,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AACpG,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.tags = exports.validateTag = exports.applyBuilderTags = exports.TAG_OVERRIDE_WARNING_NAME = exports.taggedBuilder = exports.outputs = exports.groupedStacks = exports.singleStack = exports.createStackBuilder = void 0;
|
|
4
|
+
var stack_builder_js_1 = require("./stack-builder.js");
|
|
5
|
+
Object.defineProperty(exports, "createStackBuilder", { enumerable: true, get: function () { return stack_builder_js_1.createStackBuilder; } });
|
|
6
|
+
var strategies_js_1 = require("./strategies.js");
|
|
7
|
+
Object.defineProperty(exports, "singleStack", { enumerable: true, get: function () { return strategies_js_1.singleStack; } });
|
|
8
|
+
Object.defineProperty(exports, "groupedStacks", { enumerable: true, get: function () { return strategies_js_1.groupedStacks; } });
|
|
9
|
+
var outputs_js_1 = require("./outputs.js");
|
|
10
|
+
Object.defineProperty(exports, "outputs", { enumerable: true, get: function () { return outputs_js_1.outputs; } });
|
|
11
|
+
var tagged_builder_js_1 = require("./tagged-builder.js");
|
|
12
|
+
Object.defineProperty(exports, "taggedBuilder", { enumerable: true, get: function () { return tagged_builder_js_1.taggedBuilder; } });
|
|
13
|
+
Object.defineProperty(exports, "TAG_OVERRIDE_WARNING_NAME", { enumerable: true, get: function () { return tagged_builder_js_1.TAG_OVERRIDE_WARNING_NAME; } });
|
|
14
|
+
var apply_builder_tags_js_1 = require("./apply-builder-tags.js");
|
|
15
|
+
Object.defineProperty(exports, "applyBuilderTags", { enumerable: true, get: function () { return apply_builder_tags_js_1.applyBuilderTags; } });
|
|
16
|
+
var tag_validator_js_1 = require("./tag-validator.js");
|
|
17
|
+
Object.defineProperty(exports, "validateTag", { enumerable: true, get: function () { return tag_validator_js_1.validateTag; } });
|
|
18
|
+
var tags_js_1 = require("./tags.js");
|
|
19
|
+
Object.defineProperty(exports, "tags", { enumerable: true, get: function () { return tags_js_1.tags; } });
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,uDAI4B;AAH1B,sHAAA,kBAAkB,OAAA;AAIpB,iDAA6D;AAApD,4GAAA,WAAW,OAAA;AAAE,8GAAA,aAAa,OAAA;AACnC,2CAAsF;AAA7E,qGAAA,OAAO,OAAA;AAChB,yDAAoG;AAA3F,kHAAA,aAAa,OAAA;AAAuB,8HAAA,yBAAyB,OAAA;AACtE,iEAA2D;AAAlD,yHAAA,gBAAgB,OAAA;AACzB,uDAAiD;AAAxC,+GAAA,WAAW,OAAA;AACpB,qCAAsD;AAA7C,+FAAA,IAAI,OAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outputs.d.ts","sourceRoot":"","sources":["../../src/outputs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,UAAU,EAAW,MAAM,oBAAoB,CAAC;AAEnF;;;;;;;;GAQG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IACzD,uDAAuD;IACvD,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAE1B,mCAAmC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;;;;;OAUG;IACH,KAAK,CAAC,EAAE,UAAU,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC;CACzC;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;AAE/F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CA0BhG"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.outputs = outputs;
|
|
4
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
5
|
+
const core_1 = require("@composurecdk/core");
|
|
6
|
+
/**
|
|
7
|
+
* Returns an {@link AfterBuildHook} that creates CloudFormation stack outputs
|
|
8
|
+
* from the composed system's build results.
|
|
9
|
+
*
|
|
10
|
+
* Each output definition's `value` can be a concrete string or a {@link Ref}
|
|
11
|
+
* that is resolved against the build results. An optional `scope` routes
|
|
12
|
+
* individual outputs to specific stacks — either as a direct `IConstruct`
|
|
13
|
+
* or as a component key string (statically typed against the composed
|
|
14
|
+
* system's component keys).
|
|
15
|
+
*
|
|
16
|
+
* Intended for use with {@link ComposedSystem.afterBuild}.
|
|
17
|
+
*
|
|
18
|
+
* @param defs - A record of output definitions keyed by logical name.
|
|
19
|
+
* @returns An {@link AfterBuildHook} that creates `CfnOutput` constructs.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* import { compose, ref } from "@composurecdk/core";
|
|
24
|
+
* import { outputs } from "@composurecdk/cloudformation";
|
|
25
|
+
*
|
|
26
|
+
* compose(
|
|
27
|
+
* { site: createBucketBuilder(), cdn: createDistributionBuilder(), dns: createZoneBuilder() },
|
|
28
|
+
* { site: [], cdn: ["site"], dns: [] },
|
|
29
|
+
* )
|
|
30
|
+
* .withStacks({ site: siteStack, cdn: siteStack, dns: dnsStack })
|
|
31
|
+
* .afterBuild(outputs({
|
|
32
|
+
* DistributionUrl: {
|
|
33
|
+
* value: ref("cdn", (r: DistributionBuilderResult) =>
|
|
34
|
+
* `https://${r.distribution.distributionDomainName}`),
|
|
35
|
+
* scope: "cdn",
|
|
36
|
+
* },
|
|
37
|
+
* BucketName: {
|
|
38
|
+
* value: ref("site", (r: BucketBuilderResult) => r.bucket.bucketName),
|
|
39
|
+
* scope: siteStack,
|
|
40
|
+
* },
|
|
41
|
+
* NameServers: {
|
|
42
|
+
* value: ref("dns", (r: ZoneBuilderResult) =>
|
|
43
|
+
* Fn.join(",", r.zone.hostedZoneNameServers!)),
|
|
44
|
+
* scope: "dns",
|
|
45
|
+
* },
|
|
46
|
+
* }))
|
|
47
|
+
* .build(app, "StaticWebsite");
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
function outputs(defs) {
|
|
51
|
+
return (scope, _id, results, componentScopes) => {
|
|
52
|
+
const resultAsContext = results;
|
|
53
|
+
const scopesByKey = componentScopes;
|
|
54
|
+
for (const [name, def] of Object.entries(defs)) {
|
|
55
|
+
let target;
|
|
56
|
+
if (typeof def.scope === "string") {
|
|
57
|
+
const resolved = scopesByKey[def.scope];
|
|
58
|
+
if (resolved === undefined) {
|
|
59
|
+
throw new Error(`outputs(): "${name}" refers to unknown component "${def.scope}".`);
|
|
60
|
+
}
|
|
61
|
+
target = resolved;
|
|
62
|
+
}
|
|
63
|
+
else if (def.scope !== undefined) {
|
|
64
|
+
target = def.scope;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
target = scope;
|
|
68
|
+
}
|
|
69
|
+
new aws_cdk_lib_1.CfnOutput(target, name, {
|
|
70
|
+
value: (0, core_1.resolve)(def.value, resultAsContext),
|
|
71
|
+
...(def.description !== undefined ? { description: def.description } : {}),
|
|
72
|
+
...(def.exportName !== undefined ? { exportName: def.exportName } : {}),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=outputs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outputs.js","sourceRoot":"","sources":["../../src/outputs.ts"],"names":[],"mappings":";;AAyFA,0BA0BC;AAnHD,6CAAwC;AAExC,6CAAmF;AA2CnF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,SAAgB,OAAO,CAA4B,IAA0B;IAC3E,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE;QAC9C,MAAM,eAAe,GAAG,OAAiC,CAAC;QAC1D,MAAM,WAAW,GAAG,eAAyD,CAAC;QAE9E,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/C,IAAI,MAAkB,CAAC;YACvB,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAClC,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBACxC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;oBAC3B,MAAM,IAAI,KAAK,CAAC,eAAe,IAAI,kCAAkC,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC;gBACtF,CAAC;gBACD,MAAM,GAAG,QAAQ,CAAC;YACpB,CAAC;iBAAM,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;gBACnC,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC;YACrB,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,KAAK,CAAC;YACjB,CAAC;YAED,IAAI,uBAAS,CAAC,MAAM,EAAE,IAAI,EAAE;gBAC1B,KAAK,EAAE,IAAA,cAAO,EAAC,GAAG,CAAC,KAAK,EAAE,eAAe,CAAC;gBAC1C,GAAG,CAAC,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC1E,GAAG,CAAC,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACxE,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Stack, type StackProps } from "aws-cdk-lib";
|
|
2
2
|
import { type IConstruct } from "constructs";
|
|
3
|
-
import {
|
|
3
|
+
import { type Lifecycle } from "@composurecdk/core";
|
|
4
|
+
import { type ITaggedBuilder } from "./tagged-builder.js";
|
|
4
5
|
/**
|
|
5
6
|
* The build output of a {@link IStackBuilder}. Contains the CDK Stack
|
|
6
7
|
* created during {@link Lifecycle.build}.
|
|
@@ -22,30 +23,23 @@ export interface StackBuilderResult {
|
|
|
22
23
|
* builder to a strategy that may be invoked after further configuration of
|
|
23
24
|
* the original, pass `builder.copy()` to snapshot the current state.
|
|
24
25
|
*
|
|
26
|
+
* Tags accumulated via {@link ITaggedBuilder.tag | .tag()} or
|
|
27
|
+
* {@link ITaggedBuilder.tags | .tags()} are applied to the resulting Stack.
|
|
28
|
+
* CloudFormation propagates stack-level tags to every resource the stack
|
|
29
|
+
* contains, so a single `.tag()` call on a stack reaches everything inside.
|
|
30
|
+
*
|
|
25
31
|
* @example
|
|
26
32
|
* ```ts
|
|
27
33
|
* const { stack } = createStackBuilder()
|
|
28
34
|
* .description("Network infrastructure")
|
|
29
35
|
* .terminationProtection(true)
|
|
36
|
+
* .tag("Owner", "platform")
|
|
30
37
|
* .build(app, "NetworkStack");
|
|
31
38
|
* ```
|
|
32
39
|
*/
|
|
33
|
-
export type IStackBuilder =
|
|
34
|
-
/**
|
|
35
|
-
* Adds a tag to the Stack. Tags are applied to the Stack and propagate
|
|
36
|
-
* to all resources within it.
|
|
37
|
-
*
|
|
38
|
-
* @param key - The tag key.
|
|
39
|
-
* @param value - The tag value.
|
|
40
|
-
* @returns The builder for chaining.
|
|
41
|
-
*/
|
|
42
|
-
tag(key: string, value: string): IStackBuilder;
|
|
43
|
-
};
|
|
40
|
+
export type IStackBuilder = ITaggedBuilder<StackProps, StackBuilder>;
|
|
44
41
|
declare class StackBuilder implements Lifecycle<StackBuilderResult> {
|
|
45
|
-
#private;
|
|
46
42
|
props: Partial<StackProps>;
|
|
47
|
-
tag(key: string, value: string): this;
|
|
48
|
-
[COPY_STATE](next: StackBuilder): void;
|
|
49
43
|
build(scope: IConstruct, id: string): StackBuilderResult;
|
|
50
44
|
}
|
|
51
45
|
/**
|
|
@@ -53,9 +47,10 @@ declare class StackBuilder implements Lifecycle<StackBuilderResult> {
|
|
|
53
47
|
*
|
|
54
48
|
* This is the entry point for declarative stack configuration. The returned
|
|
55
49
|
* builder exposes every {@link StackProps} property as a fluent setter/getter,
|
|
56
|
-
*
|
|
57
|
-
* {@link Lifecycle}, so it composes
|
|
58
|
-
* {@link singleStack} or
|
|
50
|
+
* `.tag(key, value)` / `.tags({...})` for stack-level tagging, and `.copy()`
|
|
51
|
+
* for variant authoring. It implements {@link Lifecycle}, so it composes
|
|
52
|
+
* naturally and can be passed to {@link singleStack} or
|
|
53
|
+
* {@link groupedStacks}.
|
|
59
54
|
*
|
|
60
55
|
* @returns A fluent builder for a CloudFormation Stack.
|
|
61
56
|
*
|
|
@@ -65,6 +60,7 @@ declare class StackBuilder implements Lifecycle<StackBuilderResult> {
|
|
|
65
60
|
* const { stack } = createStackBuilder()
|
|
66
61
|
* .description("Service layer")
|
|
67
62
|
* .terminationProtection(true)
|
|
63
|
+
* .tag("Owner", "platform")
|
|
68
64
|
* .build(app, "ServiceStack");
|
|
69
65
|
*
|
|
70
66
|
* // Hand a configured builder to a strategy. Use `.copy()` to snapshot
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stack-builder.d.ts","sourceRoot":"","sources":["../../src/stack-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,KAAK,cAAc,EAAiB,MAAM,qBAAqB,CAAC;AAEzE;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,4CAA4C;IAC5C,KAAK,EAAE,KAAK,CAAC;CACd;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;AAErE,cAAM,YAAa,YAAW,SAAS,CAAC,kBAAkB,CAAC;IACzD,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,CAAM;IAEhC,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,GAAG,kBAAkB;CAGzD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,kBAAkB,IAAI,aAAa,CAElD"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createStackBuilder = createStackBuilder;
|
|
4
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
5
|
+
const tagged_builder_js_1 = require("./tagged-builder.js");
|
|
6
|
+
class StackBuilder {
|
|
7
|
+
props = {};
|
|
8
|
+
build(scope, id) {
|
|
9
|
+
return { stack: new aws_cdk_lib_1.Stack(scope, id, this.props) };
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Creates a new {@link IStackBuilder} for configuring a CloudFormation Stack.
|
|
14
|
+
*
|
|
15
|
+
* This is the entry point for declarative stack configuration. The returned
|
|
16
|
+
* builder exposes every {@link StackProps} property as a fluent setter/getter,
|
|
17
|
+
* `.tag(key, value)` / `.tags({...})` for stack-level tagging, and `.copy()`
|
|
18
|
+
* for variant authoring. It implements {@link Lifecycle}, so it composes
|
|
19
|
+
* naturally and can be passed to {@link singleStack} or
|
|
20
|
+
* {@link groupedStacks}.
|
|
21
|
+
*
|
|
22
|
+
* @returns A fluent builder for a CloudFormation Stack.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* // Build a stack directly
|
|
27
|
+
* const { stack } = createStackBuilder()
|
|
28
|
+
* .description("Service layer")
|
|
29
|
+
* .terminationProtection(true)
|
|
30
|
+
* .tag("Owner", "platform")
|
|
31
|
+
* .build(app, "ServiceStack");
|
|
32
|
+
*
|
|
33
|
+
* // Hand a configured builder to a strategy. Use `.copy()` to snapshot
|
|
34
|
+
* // when the original may be mutated further.
|
|
35
|
+
* const base = createStackBuilder()
|
|
36
|
+
* .terminationProtection(true)
|
|
37
|
+
* .tag("team", "platform");
|
|
38
|
+
*
|
|
39
|
+
* compose({ ... }, { ... })
|
|
40
|
+
* .withStackStrategy(singleStack(base.copy()))
|
|
41
|
+
* .build(app, "MySystem");
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
function createStackBuilder() {
|
|
45
|
+
return (0, tagged_builder_js_1.taggedBuilder)(StackBuilder);
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=stack-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stack-builder.js","sourceRoot":"","sources":["../../src/stack-builder.ts"],"names":[],"mappings":";;AAmFA,gDAEC;AArFD,6CAAqD;AAGrD,2DAAyE;AAwCzE,MAAM,YAAY;IAChB,KAAK,GAAwB,EAAE,CAAC;IAEhC,KAAK,CAAC,KAAiB,EAAE,EAAU;QACjC,OAAO,EAAE,KAAK,EAAE,IAAI,mBAAK,CAAC,KAAK,EAAE,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;IACrD,CAAC;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,SAAgB,kBAAkB;IAChC,OAAO,IAAA,iCAAa,EAA2B,YAAY,CAAC,CAAC;AAC/D,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strategies.d.ts","sourceRoot":"","sources":["../../src/strategies.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,SAAS,EACd,KAAK,aAAa,EAGnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAsB,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAEjF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,WAAW,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,kBAAkB,CAAC,GAAG,aAAa,CAGlF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM,EAC1C,OAAO,CAAC,EAAE,SAAS,CAAC,kBAAkB,CAAC,GACtC,aAAa,CAGf"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.singleStack = singleStack;
|
|
4
|
+
exports.groupedStacks = groupedStacks;
|
|
5
|
+
const core_1 = require("@composurecdk/core");
|
|
6
|
+
const stack_builder_js_1 = require("./stack-builder.js");
|
|
7
|
+
/**
|
|
8
|
+
* Creates a strategy that places all components in a single Stack.
|
|
9
|
+
*
|
|
10
|
+
* The Stack is created lazily on the first call to `resolve` and reused
|
|
11
|
+
* for all subsequent components. The supplied `builder` is invoked at that
|
|
12
|
+
* point as `builder.build(scope, id).stack`, so any tags applied via the
|
|
13
|
+
* builder's `.tag()` method land on the resulting Stack.
|
|
14
|
+
*
|
|
15
|
+
* The builder's `build()` is called lazily. If the original may be mutated
|
|
16
|
+
* after this call, pass `builder.copy()` to snapshot the configuration.
|
|
17
|
+
*
|
|
18
|
+
* @param builder - Optional builder for configuring the Stack. Defaults to
|
|
19
|
+
* a fresh {@link createStackBuilder} per call, producing a plain Stack
|
|
20
|
+
* with no extra configuration. For non-Stack scope types, use
|
|
21
|
+
* `singleStack` from `@composurecdk/core` directly with a `ScopeFactory`.
|
|
22
|
+
* @returns A {@link StackStrategy} that groups all components into one Stack.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* compose({ handler, api }, { handler: [], api: ["handler"] })
|
|
27
|
+
* .withStackStrategy(singleStack())
|
|
28
|
+
* .build(app, "MySystem");
|
|
29
|
+
*
|
|
30
|
+
* // With a configured builder:
|
|
31
|
+
* const base = createStackBuilder().tag("team", "platform");
|
|
32
|
+
* compose({ ... }, { ... })
|
|
33
|
+
* .withStackStrategy(singleStack(base.copy()))
|
|
34
|
+
* .build(app, "MySystem");
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
function singleStack(builder) {
|
|
38
|
+
const stackBuilder = builder ?? (0, stack_builder_js_1.createStackBuilder)();
|
|
39
|
+
return (0, core_1.singleStack)((scope, id) => stackBuilder.build(scope, id).stack);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Creates a strategy that groups components into named Stacks determined by
|
|
43
|
+
* a classifier function.
|
|
44
|
+
*
|
|
45
|
+
* Components that return the same group key share a Stack. Stacks are
|
|
46
|
+
* created lazily as new group keys are encountered. The supplied `builder`
|
|
47
|
+
* is invoked once per group as `builder.build(scope, id).stack` with
|
|
48
|
+
* `id = ${systemId}-${group}`, so any configured tags propagate to every
|
|
49
|
+
* Stack the strategy creates.
|
|
50
|
+
*
|
|
51
|
+
* The builder's `build()` is called lazily. If the original may be mutated
|
|
52
|
+
* after this call, pass `builder.copy()` to snapshot the configuration.
|
|
53
|
+
*
|
|
54
|
+
* @param classify - A function that maps a component key to a group name.
|
|
55
|
+
* @param builder - Optional builder for configuring each Stack. Defaults to
|
|
56
|
+
* a fresh {@link createStackBuilder} per call. For non-Stack scope types,
|
|
57
|
+
* use `groupedStacks` from `@composurecdk/core` directly with a
|
|
58
|
+
* `ScopeFactory`.
|
|
59
|
+
* @returns A {@link StackStrategy} that groups components by classifier output.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* compose({ handler, api, table }, { ... })
|
|
64
|
+
* .withStackStrategy(groupedStacks(key => key === "table" ? "persistence" : "service"))
|
|
65
|
+
* .build(app, "MySystem");
|
|
66
|
+
*
|
|
67
|
+
* // With a configured builder, snapshotted via .copy():
|
|
68
|
+
* const base = createStackBuilder().tag("team", "platform");
|
|
69
|
+
* compose({ ... }, { ... })
|
|
70
|
+
* .withStackStrategy(
|
|
71
|
+
* groupedStacks(key => key === "table" ? "persistence" : "service", base.copy()),
|
|
72
|
+
* )
|
|
73
|
+
* .build(app, "MySystem");
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
function groupedStacks(classify, builder) {
|
|
77
|
+
const stackBuilder = builder ?? (0, stack_builder_js_1.createStackBuilder)();
|
|
78
|
+
return (0, core_1.groupedStacks)(classify, (scope, id) => stackBuilder.build(scope, id).stack);
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=strategies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strategies.js","sourceRoot":"","sources":["../../src/strategies.ts"],"names":[],"mappings":";;AAsCA,kCAGC;AAqCD,sCAMC;AApFD,6CAK4B;AAC5B,yDAAiF;AAEjF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,SAAgB,WAAW,CAAC,OAAuC;IACjE,MAAM,YAAY,GAAG,OAAO,IAAI,IAAA,qCAAkB,GAAE,CAAC;IACrD,OAAO,IAAA,kBAAe,EAAC,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;AAC7E,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,SAAgB,aAAa,CAC3B,QAA0C,EAC1C,OAAuC;IAEvC,MAAM,YAAY,GAAG,OAAO,IAAI,IAAA,qCAAkB,GAAE,CAAC;IACrD,OAAO,IAAA,oBAAiB,EAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;AACzF,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates a single tag key/value pair against AWS tag constraints.
|
|
3
|
+
*
|
|
4
|
+
* Throws synchronously at the call site so authors see the failure where the
|
|
5
|
+
* bad value was written, not at deploy time. Validates:
|
|
6
|
+
*
|
|
7
|
+
* - `key` is non-empty and at most {@link KEY_MAX} characters.
|
|
8
|
+
* - `key` does not start with the reserved `aws:` prefix (case-insensitive).
|
|
9
|
+
* - `value` is at most {@link VALUE_MAX} characters.
|
|
10
|
+
* - both `key` and `value` use only the AWS-permitted character set.
|
|
11
|
+
*
|
|
12
|
+
* The regex matches Unicode letters, digits, and whitespace plus the
|
|
13
|
+
* documented punctuation set, so non-ASCII tags are accepted as AWS
|
|
14
|
+
* supports them.
|
|
15
|
+
*/
|
|
16
|
+
export declare function validateTag(key: string, value: string): void;
|
|
17
|
+
/**
|
|
18
|
+
* Validates every entry of a record via {@link validateTag}, throwing on the
|
|
19
|
+
* first invalid pair so the failure surfaces at the configuring call site.
|
|
20
|
+
*/
|
|
21
|
+
export declare function validateTagRecord(values: Record<string, string>): void;
|
|
22
|
+
//# sourceMappingURL=tag-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tag-validator.d.ts","sourceRoot":"","sources":["../../src/tag-validator.ts"],"names":[],"mappings":"AAkBA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CA2B5D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAItE"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateTag = validateTag;
|
|
4
|
+
exports.validateTagRecord = validateTagRecord;
|
|
5
|
+
/**
|
|
6
|
+
* AWS allows letters, digits, whitespace, and the symbols `_ . : / = + - @`
|
|
7
|
+
* in tag keys and values, with non-ASCII letters/digits permitted via
|
|
8
|
+
* Unicode classes. Empty values are permitted by AWS for `Value`, but
|
|
9
|
+
* empty `Key` is not. The character set is validated against this regex.
|
|
10
|
+
*
|
|
11
|
+
* `\p{Z}` matches the full Unicode separator class — slightly more
|
|
12
|
+
* permissive than AWS's documented "white space," but errors on the side
|
|
13
|
+
* of accepting input that the AWS API may yet reject at deploy time. The
|
|
14
|
+
* extra rejections happen later but are reported in the API response.
|
|
15
|
+
*
|
|
16
|
+
* @see https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html
|
|
17
|
+
*/
|
|
18
|
+
const TAG_CHAR_RE = /^[\p{L}\p{Z}\p{N}_.:/=+\-@]*$/u;
|
|
19
|
+
const KEY_MAX = 128;
|
|
20
|
+
const VALUE_MAX = 256;
|
|
21
|
+
/**
|
|
22
|
+
* Validates a single tag key/value pair against AWS tag constraints.
|
|
23
|
+
*
|
|
24
|
+
* Throws synchronously at the call site so authors see the failure where the
|
|
25
|
+
* bad value was written, not at deploy time. Validates:
|
|
26
|
+
*
|
|
27
|
+
* - `key` is non-empty and at most {@link KEY_MAX} characters.
|
|
28
|
+
* - `key` does not start with the reserved `aws:` prefix (case-insensitive).
|
|
29
|
+
* - `value` is at most {@link VALUE_MAX} characters.
|
|
30
|
+
* - both `key` and `value` use only the AWS-permitted character set.
|
|
31
|
+
*
|
|
32
|
+
* The regex matches Unicode letters, digits, and whitespace plus the
|
|
33
|
+
* documented punctuation set, so non-ASCII tags are accepted as AWS
|
|
34
|
+
* supports them.
|
|
35
|
+
*/
|
|
36
|
+
function validateTag(key, value) {
|
|
37
|
+
if (key.length === 0) {
|
|
38
|
+
throw new Error("Tag key must be non-empty.");
|
|
39
|
+
}
|
|
40
|
+
if (key.length > KEY_MAX) {
|
|
41
|
+
throw new Error(`Tag key "${key}" exceeds ${String(KEY_MAX)}-character limit.`);
|
|
42
|
+
}
|
|
43
|
+
if (key.toLowerCase().startsWith("aws:")) {
|
|
44
|
+
throw new Error(`Tag key "${key}" uses reserved "aws:" prefix; AWS rejects user tags with this prefix.`);
|
|
45
|
+
}
|
|
46
|
+
if (!TAG_CHAR_RE.test(key)) {
|
|
47
|
+
throw new Error(`Tag key "${key}" contains characters outside the AWS tag character set ` +
|
|
48
|
+
"(letters, digits, whitespace, and `_ . : / = + - @`).");
|
|
49
|
+
}
|
|
50
|
+
if (value.length > VALUE_MAX) {
|
|
51
|
+
throw new Error(`Tag value for key "${key}" exceeds ${String(VALUE_MAX)}-character limit.`);
|
|
52
|
+
}
|
|
53
|
+
if (!TAG_CHAR_RE.test(value)) {
|
|
54
|
+
throw new Error(`Tag value for key "${key}" contains characters outside the AWS tag character set ` +
|
|
55
|
+
"(letters, digits, whitespace, and `_ . : / = + - @`).");
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Validates every entry of a record via {@link validateTag}, throwing on the
|
|
60
|
+
* first invalid pair so the failure surfaces at the configuring call site.
|
|
61
|
+
*/
|
|
62
|
+
function validateTagRecord(values) {
|
|
63
|
+
for (const [key, value] of Object.entries(values)) {
|
|
64
|
+
validateTag(key, value);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=tag-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tag-validator.js","sourceRoot":"","sources":["../../src/tag-validator.ts"],"names":[],"mappings":";;AAiCA,kCA2BC;AAMD,8CAIC;AAtED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,GAAG,gCAAgC,CAAC;AAErD,MAAM,OAAO,GAAG,GAAG,CAAC;AACpB,MAAM,SAAS,GAAG,GAAG,CAAC;AAEtB;;;;;;;;;;;;;;GAcG;AACH,SAAgB,WAAW,CAAC,GAAW,EAAE,KAAa;IACpD,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,GAAG,OAAO,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,YAAY,GAAG,aAAa,MAAM,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAClF,CAAC;IACD,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CACb,YAAY,GAAG,wEAAwE,CACxF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CACb,YAAY,GAAG,0DAA0D;YACvE,uDAAuD,CAC1D,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,sBAAsB,GAAG,aAAa,MAAM,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;IAC9F,CAAC;IACD,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,sBAAsB,GAAG,0DAA0D;YACjF,uDAAuD,CAC1D,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAgB,iBAAiB,CAAC,MAA8B;IAC9D,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,WAAW,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC"}
|