ag-common 0.0.899 → 0.0.901
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,28 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
Resource: {
|
|
5
|
-
node: {
|
|
6
|
-
scope: unknown;
|
|
7
|
-
};
|
|
8
|
-
};
|
|
9
|
-
};
|
|
10
|
-
};
|
|
11
|
-
}
|
|
12
|
-
/** ensure that dynamo tables in stack dont exceed passed in provisioned limits */
|
|
13
|
-
export declare const enforceDynamoProvisionCap: ({ tables, readsMax, writesMax, mustEqual, }: {
|
|
14
|
-
tables: DynamoTableConstruct[];
|
|
15
|
-
/**
|
|
16
|
-
* default 25
|
|
17
|
-
*/
|
|
1
|
+
import { aws_dynamodb as dynamodb } from "aws-cdk-lib";
|
|
2
|
+
export interface EnforceDynamoProvisionCapOptions {
|
|
3
|
+
tables: dynamodb.Table[];
|
|
18
4
|
readsMax?: number;
|
|
19
|
-
/**
|
|
20
|
-
* default 25
|
|
21
|
-
*/
|
|
22
5
|
writesMax?: number;
|
|
23
|
-
/**
|
|
24
|
-
* default false. if true, will throw if cap isnt met. will still throw if exceeds.
|
|
25
|
-
*/
|
|
26
6
|
mustEqual?: boolean;
|
|
27
|
-
}
|
|
28
|
-
|
|
7
|
+
}
|
|
8
|
+
/** Ensure the supplied DynamoDB tables do not exceed the provisioned capacity limits. */
|
|
9
|
+
export declare const enforceDynamoProvisionCap: ({ tables, readsMax, writesMax, mustEqual, }: EnforceDynamoProvisionCapOptions) => void;
|
|
@@ -1,32 +1,123 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.enforceDynamoProvisionCap = void 0;
|
|
4
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
4
5
|
const log_1 = require("../../common/helpers/log");
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
const ZERO_CAPACITY = {
|
|
7
|
+
reads: 0,
|
|
8
|
+
writes: 0,
|
|
9
|
+
};
|
|
10
|
+
const isResolvable = (value) => "resolve" in value && typeof value.resolve === "function";
|
|
11
|
+
const isRecord = (value) => typeof value === "object" && value !== null;
|
|
12
|
+
const isUnknownArray = (value) => Array.isArray(value);
|
|
13
|
+
const getResolvedCapacity = ({ value, label }) => {
|
|
14
|
+
if (aws_cdk_lib_1.Token.isUnresolved(value)) {
|
|
15
|
+
throw new Error(`Cannot enforce DynamoDB provision cap with unresolved ${label}`);
|
|
16
|
+
}
|
|
17
|
+
return value;
|
|
18
|
+
};
|
|
19
|
+
const getProvisionedThroughput = ({ throughput, label, }) => {
|
|
20
|
+
if (!throughput) {
|
|
21
|
+
return ZERO_CAPACITY;
|
|
22
|
+
}
|
|
23
|
+
if (isResolvable(throughput)) {
|
|
24
|
+
throw new Error(`Cannot enforce DynamoDB provision cap with unresolved ${label}`);
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
reads: getResolvedCapacity({
|
|
28
|
+
value: throughput.readCapacityUnits,
|
|
29
|
+
label: `${label} read capacity`,
|
|
30
|
+
}),
|
|
31
|
+
writes: getResolvedCapacity({
|
|
32
|
+
value: throughput.writeCapacityUnits,
|
|
33
|
+
label: `${label} write capacity`,
|
|
34
|
+
}),
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
const getResolvedIndexThroughput = ({ throughput, label, }) => {
|
|
38
|
+
if (throughput === undefined) {
|
|
39
|
+
return ZERO_CAPACITY;
|
|
40
|
+
}
|
|
41
|
+
if (!isRecord(throughput) || isResolvable(throughput)) {
|
|
42
|
+
throw new Error(`Cannot enforce DynamoDB provision cap with unresolved ${label}`);
|
|
43
|
+
}
|
|
44
|
+
const reads = throughput.readCapacityUnits;
|
|
45
|
+
const writes = throughput.writeCapacityUnits;
|
|
46
|
+
if (typeof reads !== "number" || aws_cdk_lib_1.Token.isUnresolved(reads)) {
|
|
47
|
+
throw new Error(`Cannot enforce DynamoDB provision cap with unresolved ${label} read capacity`);
|
|
48
|
+
}
|
|
49
|
+
if (typeof writes !== "number" || aws_cdk_lib_1.Token.isUnresolved(writes)) {
|
|
50
|
+
throw new Error(`Cannot enforce DynamoDB provision cap with unresolved ${label} write capacity`);
|
|
51
|
+
}
|
|
52
|
+
return { reads, writes };
|
|
53
|
+
};
|
|
54
|
+
const getTableResource = (table) => {
|
|
55
|
+
const resource = table.node.defaultChild;
|
|
56
|
+
if (!(resource instanceof aws_cdk_lib_1.aws_dynamodb.CfnTable)) {
|
|
57
|
+
throw new Error(`Unable to inspect DynamoDB table resource: ${table.node.path}`);
|
|
58
|
+
}
|
|
59
|
+
return resource;
|
|
60
|
+
};
|
|
61
|
+
const getGlobalSecondaryIndexCapacity = (table) => {
|
|
62
|
+
const indexes = table.globalSecondaryIndexes;
|
|
63
|
+
if (!indexes) {
|
|
64
|
+
return ZERO_CAPACITY;
|
|
65
|
+
}
|
|
66
|
+
const resolvedIndexes = isResolvable(indexes)
|
|
67
|
+
? aws_cdk_lib_1.Stack.of(table).resolve(indexes)
|
|
68
|
+
: indexes;
|
|
69
|
+
if (resolvedIndexes === undefined) {
|
|
70
|
+
return ZERO_CAPACITY;
|
|
71
|
+
}
|
|
72
|
+
if (!isUnknownArray(resolvedIndexes)) {
|
|
73
|
+
throw new Error(`Cannot enforce DynamoDB provision cap with unresolved indexes for ${table.node.path}`);
|
|
74
|
+
}
|
|
75
|
+
return resolvedIndexes.reduce((total, index, indexPosition) => {
|
|
76
|
+
if (!isRecord(index) || isResolvable(index)) {
|
|
77
|
+
throw new Error(`Cannot enforce DynamoDB provision cap with unresolved index ${indexPosition} for ${table.node.path}`);
|
|
78
|
+
}
|
|
79
|
+
const capacity = getResolvedIndexThroughput({
|
|
80
|
+
throughput: index.provisionedThroughput,
|
|
81
|
+
label: `${table.node.path} index ${indexPosition}`,
|
|
82
|
+
});
|
|
83
|
+
return {
|
|
84
|
+
reads: total.reads + capacity.reads,
|
|
85
|
+
writes: total.writes + capacity.writes,
|
|
86
|
+
};
|
|
87
|
+
}, { ...ZERO_CAPACITY });
|
|
88
|
+
};
|
|
89
|
+
const getTableCapacity = (table) => {
|
|
90
|
+
const resource = getTableResource(table);
|
|
91
|
+
const tableCapacity = getProvisionedThroughput({
|
|
92
|
+
throughput: resource.provisionedThroughput,
|
|
93
|
+
label: resource.node.path,
|
|
94
|
+
});
|
|
95
|
+
const indexCapacity = getGlobalSecondaryIndexCapacity(resource);
|
|
96
|
+
return {
|
|
97
|
+
reads: tableCapacity.reads + indexCapacity.reads,
|
|
98
|
+
writes: tableCapacity.writes + indexCapacity.writes,
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
/** Ensure the supplied DynamoDB tables do not exceed the provisioned capacity limits. */
|
|
14
102
|
const enforceDynamoProvisionCap = ({ tables, readsMax = 25, writesMax = 25, mustEqual = false, }) => {
|
|
15
103
|
if (tables.length === 0) {
|
|
16
104
|
(0, log_1.warn)("error in dynamo FT enforce");
|
|
17
105
|
return;
|
|
18
106
|
}
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
107
|
+
const capacity = tables.reduce((total, table) => {
|
|
108
|
+
const tableCapacity = getTableCapacity(table);
|
|
109
|
+
return {
|
|
110
|
+
reads: total.reads + tableCapacity.reads,
|
|
111
|
+
writes: total.writes + tableCapacity.writes,
|
|
112
|
+
};
|
|
113
|
+
}, { ...ZERO_CAPACITY });
|
|
114
|
+
(0, log_1.warn)(`dynamo table provisioned reads:${capacity.reads}/${readsMax}`);
|
|
115
|
+
(0, log_1.warn)(`dynamo table provisioned writes:${capacity.writes}/${writesMax}`);
|
|
116
|
+
if (capacity.reads > readsMax || capacity.writes > writesMax) {
|
|
26
117
|
throw new Error("exceeded dynamo provision cap");
|
|
27
118
|
}
|
|
28
|
-
if (mustEqual && (reads !== readsMax || writes !== writesMax)) {
|
|
29
|
-
throw new Error(
|
|
119
|
+
if (mustEqual && (capacity.reads !== readsMax || capacity.writes !== writesMax)) {
|
|
120
|
+
throw new Error("dynamo provision cap not met");
|
|
30
121
|
}
|
|
31
122
|
};
|
|
32
123
|
exports.enforceDynamoProvisionCap = enforceDynamoProvisionCap;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ag-common",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.901",
|
|
4
4
|
"license": "ISC",
|
|
5
5
|
"author": "admin@gec.dev",
|
|
6
6
|
"repository": {
|
|
@@ -39,7 +39,6 @@
|
|
|
39
39
|
"@radix-ui/react-scroll-area": "^1.2.18",
|
|
40
40
|
"@radix-ui/react-select": "^2.3.7",
|
|
41
41
|
"@radix-ui/react-switch": "^1.3.7",
|
|
42
|
-
"aws-cdk-lib": "^2.262.1",
|
|
43
42
|
"buffer": "^6.0.3",
|
|
44
43
|
"class-variance-authority": "^0.7.1",
|
|
45
44
|
"clsx": "^2.1.1",
|
|
@@ -61,8 +60,10 @@
|
|
|
61
60
|
"@types/node": "^26.1.1",
|
|
62
61
|
"@types/react": "^19.2.17",
|
|
63
62
|
"@types/react-dom": "^19.2.3",
|
|
63
|
+
"aws-cdk-lib": "^2.265.0",
|
|
64
|
+
"constructs": "^10.8.1",
|
|
64
65
|
"cross-env": "^10.1.0",
|
|
65
|
-
"eslint-config-e7npm": "0.1.
|
|
66
|
+
"eslint-config-e7npm": "0.1.56",
|
|
66
67
|
"globstar": "^1.0.0",
|
|
67
68
|
"jiti": "^2.7.0",
|
|
68
69
|
"oxfmt": "^0.60.0",
|
|
@@ -73,6 +74,10 @@
|
|
|
73
74
|
"tsx": "^4.23.12",
|
|
74
75
|
"typescript": "^7.0.2"
|
|
75
76
|
},
|
|
77
|
+
"peerDependencies": {
|
|
78
|
+
"aws-cdk-lib": "^2.262.1",
|
|
79
|
+
"constructs": "^10.0.0"
|
|
80
|
+
},
|
|
76
81
|
"scripts": {
|
|
77
82
|
"preinstall": "npx only-allow pnpm",
|
|
78
83
|
"format": "e7-oxfmt --config .oxfmtrc.json --disable-nested-config .",
|
|
@@ -81,6 +86,6 @@
|
|
|
81
86
|
"build": "rimraf dist && tsc -p tsconfig.build.json",
|
|
82
87
|
"start": "cross-env BROWSER=none cross-env storybook dev -p 6006",
|
|
83
88
|
"build-storybook": "storybook build -o docs --quiet",
|
|
84
|
-
"test": "globstar -- node --import tsx --test \"src/**/*.test.ts\""
|
|
89
|
+
"test": "globstar -- node --import tsx --test \"src/tests/**/*.test.ts\""
|
|
85
90
|
}
|
|
86
91
|
}
|