@aws/nx-plugin 0.1.6 → 0.2.1
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/LICENSE-THIRD-PARTY +1554 -3241
- package/generators.json +1 -13
- package/package.json +14 -14
- package/src/cloudscape-website/app/README.md +84 -48
- package/src/cloudscape-website/app/__snapshots__/generator.spec.ts.snap +168 -233
- package/src/cloudscape-website/app/files/app/README.md.template +44 -0
- package/src/cloudscape-website/app/files/app/src/layouts/App/index.tsx.template +40 -43
- package/src/cloudscape-website/app/files/app/src/layouts/App/navitems.ts.template +3 -3
- package/src/cloudscape-website/app/files/app/src/layouts/Routes/index.tsx.template +4 -6
- package/src/cloudscape-website/app/files/app/src/main.tsx.template +7 -10
- package/src/cloudscape-website/app/files/app/src/pages/Home/index.tsx.template +0 -2
- package/src/cloudscape-website/app/files/common/constructs/src/app/static-websites/__websiteNameKebabCase__.ts.template +13 -0
- package/src/cloudscape-website/app/files/common/constructs/src/{__websiteNameKebabCase__ → core}/static-website.ts.template +79 -144
- package/src/cloudscape-website/app/generator.js +90 -74
- package/src/cloudscape-website/app/generator.js.map +1 -1
- package/src/cloudscape-website/app/schema.d.ts +3 -5
- package/src/cloudscape-website/app/schema.json +1 -24
- package/src/cloudscape-website/cognito-auth/README.md +53 -32
- package/src/cloudscape-website/cognito-auth/__snapshots__/generator.spec.ts.snap +162 -124
- package/src/cloudscape-website/cognito-auth/files/app/components/CognitoAuth/index.tsx.template +53 -39
- package/src/cloudscape-website/cognito-auth/files/common/constructs/src/core/user-identity.ts.template +168 -0
- package/src/cloudscape-website/cognito-auth/generator.js +130 -47
- package/src/cloudscape-website/cognito-auth/generator.js.map +1 -1
- package/src/cloudscape-website/cognito-auth/schema.d.ts +1 -0
- package/src/cloudscape-website/cognito-auth/schema.json +7 -1
- package/src/cloudscape-website/runtime-config/__snapshots__/generator.spec.ts.snap +20 -15
- package/src/cloudscape-website/runtime-config/files/app/components/RuntimeConfig/index.tsx.template +7 -10
- package/src/cloudscape-website/runtime-config/files/app/hooks/useRuntimeConfig.tsx.template +13 -0
- package/src/cloudscape-website/runtime-config/generator.js +4 -2
- package/src/cloudscape-website/runtime-config/generator.js.map +1 -1
- package/src/infra/app/README.md +71 -46
- package/src/infra/app/__snapshots__/generator.spec.ts.snap +184 -305
- package/src/infra/app/files/app/README.md.template +76 -0
- package/src/infra/app/files/app/src/main.ts.template +18 -0
- package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/aws-prototyping.guard +1282 -0
- package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/cfn-nag.guard +6839 -0
- package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/hipaa-security.guard +2807 -0
- package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/nist-csf.guard +2585 -0
- package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/pci-dss-3-2-1.guard +2236 -0
- package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/wa-reliability-pillar.guard +885 -0
- package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/wa-security-pillar.guard +2205 -0
- package/src/infra/app/files/common/constructs/src/core/cfn-guard.ts.template +63 -0
- package/src/infra/app/generator.js +36 -7
- package/src/infra/app/generator.js.map +1 -1
- package/src/infra/app/schema.d.ts +10 -1
- package/src/infra/app/schema.json +16 -8
- package/src/trpc/backend/README.md +102 -80
- package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +42 -19
- package/src/trpc/backend/files/backend/README.md.template +33 -0
- package/src/trpc/backend/files/common/constructs/src/app/trpc-apis/__apiNameKebabCase__.ts.template +18 -0
- package/src/trpc/backend/files/common/constructs/src/{__apiNameKebabCase__/index.ts.template → core/trpc-api.ts.template} +12 -16
- package/src/trpc/backend/files/schema/README.md.template +33 -0
- package/src/trpc/backend/generator.js +30 -44
- package/src/trpc/backend/generator.js.map +1 -1
- package/src/trpc/backend/schema.d.ts +3 -1
- package/src/trpc/backend/schema.json +8 -13
- package/src/trpc/react/README.md +46 -66
- package/src/trpc/react/__snapshots__/generator.spec.ts.snap +104 -65
- package/src/trpc/react/files/src/components/TrpcClients/IsolatedTrpcProvider.tsx.template +75 -0
- package/src/trpc/react/files/src/components/TrpcClients/TrpcApis.tsx.template +1 -0
- package/src/trpc/react/files/src/components/TrpcClients/TrpcClientProviders.tsx.template +10 -0
- package/src/trpc/react/files/src/components/TrpcClients/index.tsx.template +5 -0
- package/src/trpc/react/files/src/hooks/useSigV4.tsx.template +38 -0
- package/src/trpc/react/files/src/hooks/use__apiNameClassName__.tsx.template +3 -0
- package/src/trpc/react/generator.js +124 -25
- package/src/trpc/react/generator.js.map +1 -1
- package/src/trpc/react/schema.json +2 -2
- package/src/ts/lib/__snapshots__/generator.spec.ts.snap +47 -93
- package/src/ts/lib/eslint.d.ts +1 -2
- package/src/ts/lib/eslint.js +62 -21
- package/src/ts/lib/eslint.js.map +1 -1
- package/src/ts/lib/files/README.md.template +33 -0
- package/src/ts/lib/generator.js +44 -5
- package/src/ts/lib/generator.js.map +1 -1
- package/src/ts/lib/schema.d.ts +1 -4
- package/src/ts/lib/schema.json +2 -21
- package/src/ts/lib/ts-project-utils.js +3 -18
- package/src/ts/lib/ts-project-utils.js.map +1 -1
- package/src/ts/lib/vitest.js +12 -0
- package/src/ts/lib/vitest.js.map +1 -1
- package/src/utils/ast.d.ts +13 -0
- package/src/utils/ast.js +102 -0
- package/src/utils/ast.js.map +1 -0
- package/src/utils/files/common/constructs/src/app/index.ts.template +0 -0
- package/src/utils/files/common/constructs/src/{runtime-config → core}/runtime-config.ts.template +3 -5
- package/src/utils/files/common/constructs/src/index.ts.template +2 -1
- package/src/utils/files/common/readme/README.md.template +33 -0
- package/src/utils/files/common/types/src/runtime-config.ts.template +2 -13
- package/src/utils/format.d.ts +1 -1
- package/src/utils/format.js +2 -2
- package/src/utils/format.js.map +1 -1
- package/src/utils/names.d.ts +2 -0
- package/src/utils/names.js +27 -0
- package/src/utils/names.js.map +1 -0
- package/src/utils/npm-scope.js.map +1 -1
- package/src/utils/paths.js.map +1 -1
- package/src/utils/shared-constructs.js +37 -4
- package/src/utils/shared-constructs.js.map +1 -1
- package/src/utils/test.d.ts +2 -0
- package/src/utils/test.js +19 -0
- package/src/utils/test.js.map +1 -0
- package/src/utils/versions.d.ts +15 -9
- package/src/utils/versions.js +14 -8
- package/src/utils/versions.js.map +1 -1
- package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/cloudfront-web-acl.ts.template +0 -317
- package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/index.ts.template +0 -4
- package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/webacl_event_handler/index.ts.template +0 -301
- package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/index.ts.template +0 -4
- package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/user-identity.ts.template +0 -66
- package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/userpool-with-mfa.ts.template +0 -70
- package/src/gitlab/generator.d.ts +0 -8
- package/src/gitlab/generator.js +0 -16
- package/src/gitlab/generator.js.map +0 -1
- package/src/gitlab/schema.d.ts +0 -9
- package/src/gitlab/schema.json +0 -52
- package/src/infra/app/files/src/main.ts.template +0 -37
- package/src/trpc/react/files/src/components/TRPCClientProvider/index.tsx.template +0 -34
- package/src/trpc/react/files/src/hooks/useTrpc.tsx.template +0 -5
- package/src/ts/cjs-to-esm/generator.d.ts +0 -12
- package/src/ts/cjs-to-esm/generator.js +0 -189
- package/src/ts/cjs-to-esm/generator.js.map +0 -1
- package/src/ts/cjs-to-esm/schema.d.ts +0 -9
- package/src/ts/cjs-to-esm/schema.json +0 -28
- /package/src/infra/app/files/{cdk.json → app/cdk.json} +0 -0
- /package/src/infra/app/files/{src → app/src}/stacks/application-stack.ts.template +0 -0
- /package/src/utils/files/common/constructs/src/{runtime-config → core}/index.ts.template +0 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as url from 'url';
|
|
2
|
+
import { CfnGuardValidator as _CfnGuardValidator } from '@cdklabs/cdk-validator-cfnguard';
|
|
3
|
+
import { IConstruct } from 'constructs';
|
|
4
|
+
import { CfnResource } from 'aws-cdk-lib';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Suppresses a rule for a construct tree.
|
|
8
|
+
*
|
|
9
|
+
* @param construct The root construct to suppress the rule for.
|
|
10
|
+
* @param ruleName The name of the rule to suppress.
|
|
11
|
+
* @param predicate A predicate function that determines whether the rule should be suppressed for the given construct or any of its descendants.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* The following example suppresses the RULE_NAME for the given construct.
|
|
15
|
+
* suppressRule(construct, 'RULE_NAME')
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* The following example suppresses the RULE_NAME for the construct or any of its descendants if it is an instance of Bucket:
|
|
19
|
+
* suppressRule(construct, 'RULE_NAME', (construct) => construct instanceof Bucket)
|
|
20
|
+
*/
|
|
21
|
+
export const suppressRule = (
|
|
22
|
+
construct: IConstruct,
|
|
23
|
+
ruleName: string,
|
|
24
|
+
predicate?: (construct: IConstruct) => boolean,
|
|
25
|
+
) => {
|
|
26
|
+
const resources = (
|
|
27
|
+
predicate ? construct.node.findAll().filter(predicate) : [construct]
|
|
28
|
+
)
|
|
29
|
+
.map((resource) => resource.node.defaultChild)
|
|
30
|
+
.filter((resource) => CfnResource.isCfnResource(resource));
|
|
31
|
+
|
|
32
|
+
resources.forEach((resource) => {
|
|
33
|
+
const metadata = resource.getMetadata('guard') || {};
|
|
34
|
+
metadata['SuppressedRules'] = [
|
|
35
|
+
...(metadata['SuppressedRules'] ?? []),
|
|
36
|
+
ruleName,
|
|
37
|
+
];
|
|
38
|
+
resource.addMetadata('guard', metadata);
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export enum RuleSet {
|
|
43
|
+
AWS_PROTOTYPING = 'aws-prototyping.guard',
|
|
44
|
+
CFN_NAG = 'cfn-nag.guard',
|
|
45
|
+
HIPAA = 'hipaa-security.guard',
|
|
46
|
+
NIST_CSF = 'nist-csf.guard',
|
|
47
|
+
PCI_DSS_3_2_1 = 'pci-dss-3-2-1.guard',
|
|
48
|
+
WELL_ARCHITECTED_RELIABILITY = 'wa-reliability-pillar.guard',
|
|
49
|
+
WELL_ARCHITECTED_SECURITY = 'wa-security-pillar.guard',
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export class CfnGuardValidator extends _CfnGuardValidator {
|
|
53
|
+
constructor(guardRule: RuleSet) {
|
|
54
|
+
super({
|
|
55
|
+
controlTowerRulesEnabled: false,
|
|
56
|
+
rules: [
|
|
57
|
+
url.fileURLToPath(
|
|
58
|
+
new URL(`./cfn-guard-rules/${guardRule}`, import.meta.url),
|
|
59
|
+
),
|
|
60
|
+
],
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -9,11 +9,16 @@ const tslib_1 = require("tslib");
|
|
|
9
9
|
const devkit_1 = require("@nx/devkit");
|
|
10
10
|
const generator_1 = tslib_1.__importStar(require("../../ts/lib/generator"));
|
|
11
11
|
const versions_1 = require("../../utils/versions");
|
|
12
|
+
const npm_scope_1 = require("../../utils/npm-scope");
|
|
13
|
+
const shared_constructs_1 = require("../../utils/shared-constructs");
|
|
14
|
+
const ast_1 = require("../../utils/ast");
|
|
15
|
+
const path_1 = tslib_1.__importDefault(require("path"));
|
|
12
16
|
const format_1 = require("../../utils/format");
|
|
13
17
|
function infraGenerator(tree, schema) {
|
|
14
18
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
15
19
|
const lib = (0, generator_1.getTsLibDetails)(tree, schema);
|
|
16
|
-
|
|
20
|
+
yield (0, generator_1.default)(tree, schema);
|
|
21
|
+
yield (0, shared_constructs_1.sharedConstructsGenerator)(tree);
|
|
17
22
|
const synthDirFromRoot = `/dist/${lib.dir}/cdk.out`;
|
|
18
23
|
const synthDirFromProject = lib.dir
|
|
19
24
|
.split('/')
|
|
@@ -21,13 +26,28 @@ function infraGenerator(tree, schema) {
|
|
|
21
26
|
.join('/') + synthDirFromRoot;
|
|
22
27
|
const projectConfig = (0, devkit_1.readProjectConfiguration)(tree, lib.fullyQualifiedName);
|
|
23
28
|
const libraryRoot = projectConfig.root;
|
|
29
|
+
const npmScopePrefix = (0, npm_scope_1.getNpmScopePrefix)(tree);
|
|
30
|
+
const scopeAlias = (0, npm_scope_1.toScopeAlias)(npmScopePrefix);
|
|
31
|
+
const fullyQualifiedName = `${npmScopePrefix}${schema.name}`;
|
|
24
32
|
tree.delete((0, devkit_1.joinPathFragments)(libraryRoot, 'src'));
|
|
25
33
|
(0, devkit_1.generateFiles)(tree, // the virtual file system
|
|
26
|
-
(0, devkit_1.joinPathFragments)(__dirname, './files'), // path to the file templates
|
|
27
|
-
libraryRoot, Object.assign({ synthDir: synthDirFromProject }, schema))
|
|
34
|
+
(0, devkit_1.joinPathFragments)(__dirname, './files/app'), // path to the file templates
|
|
35
|
+
libraryRoot, Object.assign(Object.assign({ synthDir: synthDirFromProject, scopeAlias: scopeAlias, fullyQualifiedName, pkgMgrCmd: (0, devkit_1.getPackageManagerCommand)().exec }, schema), { ruleSet: schema.ruleSet.toUpperCase() }), {
|
|
36
|
+
overwriteStrategy: devkit_1.OverwriteStrategy.Overwrite,
|
|
37
|
+
});
|
|
38
|
+
(0, devkit_1.generateFiles)(tree, // the virtual file system
|
|
39
|
+
(0, devkit_1.joinPathFragments)(__dirname, 'files', shared_constructs_1.SHARED_CONSTRUCTS_DIR, 'src', 'core'), (0, devkit_1.joinPathFragments)(shared_constructs_1.PACKAGES_DIR, shared_constructs_1.SHARED_CONSTRUCTS_DIR, 'src', 'core'), Object.assign({ synthDir: synthDirFromProject, scopeAlias: (0, npm_scope_1.toScopeAlias)((0, npm_scope_1.getNpmScopePrefix)(tree)) }, schema), {
|
|
40
|
+
overwriteStrategy: devkit_1.OverwriteStrategy.KeepExisting,
|
|
41
|
+
});
|
|
28
42
|
(0, devkit_1.updateJson)(tree, `${libraryRoot}/project.json`, (config) => {
|
|
43
|
+
var _a;
|
|
29
44
|
config.projectType = 'application';
|
|
30
|
-
config.targets.build =
|
|
45
|
+
config.targets.build.dependsOn = [
|
|
46
|
+
...((_a = config.targets.build.dependsOn) !== null && _a !== void 0 ? _a : []),
|
|
47
|
+
'synth',
|
|
48
|
+
];
|
|
49
|
+
config.targets.compile.options.main = (0, devkit_1.joinPathFragments)(libraryRoot, 'src', 'main.ts');
|
|
50
|
+
config.targets.synth = {
|
|
31
51
|
cache: true,
|
|
32
52
|
executor: 'nx:run-commands',
|
|
33
53
|
outputs: [`{workspaceRoot}${synthDirFromRoot}`],
|
|
@@ -46,16 +66,25 @@ function infraGenerator(tree, schema) {
|
|
|
46
66
|
};
|
|
47
67
|
return config;
|
|
48
68
|
});
|
|
69
|
+
(0, ast_1.addStarExport)(tree, (0, devkit_1.joinPathFragments)(shared_constructs_1.PACKAGES_DIR, shared_constructs_1.SHARED_CONSTRUCTS_DIR, 'src', 'core', 'index.ts'), './cfn-guard.js');
|
|
49
70
|
(0, devkit_1.addDependenciesToPackageJson)(tree, (0, versions_1.withVersions)([
|
|
50
|
-
'@
|
|
71
|
+
'@cdklabs/cdk-validator-cfnguard',
|
|
51
72
|
'aws-cdk-lib',
|
|
52
73
|
'aws-cdk',
|
|
53
74
|
'esbuild',
|
|
54
75
|
'constructs',
|
|
55
76
|
'source-map-support',
|
|
56
77
|
]), (0, versions_1.withVersions)(['tsx']));
|
|
57
|
-
|
|
58
|
-
|
|
78
|
+
(0, devkit_1.updateJson)(tree, `${libraryRoot}/tsconfig.json`, (tsConfig) => (Object.assign(Object.assign({}, tsConfig), { references: [
|
|
79
|
+
...(tsConfig.references || []),
|
|
80
|
+
{
|
|
81
|
+
path: `${path_1.default.relative(libraryRoot, `${tree.root}/${shared_constructs_1.PACKAGES_DIR}`)}/${shared_constructs_1.SHARED_CONSTRUCTS_DIR}/tsconfig.json`,
|
|
82
|
+
},
|
|
83
|
+
] })));
|
|
84
|
+
yield (0, format_1.formatFilesInSubtree)(tree);
|
|
85
|
+
return () => {
|
|
86
|
+
(0, devkit_1.installPackagesTask)(tree);
|
|
87
|
+
};
|
|
59
88
|
});
|
|
60
89
|
}
|
|
61
90
|
exports.default = infraGenerator;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../../packages/nx-plugin/src/infra/app/generator.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../../packages/nx-plugin/src/infra/app/generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,16 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export interface InfraGeneratorSchema {
|
|
6
6
|
name: string;
|
|
7
|
+
ruleSet:
|
|
8
|
+
| 'aws_prototyping'
|
|
9
|
+
| 'cfn_nag'
|
|
10
|
+
| 'hipaa'
|
|
11
|
+
| 'nist_csf'
|
|
12
|
+
| 'pci_dss_3_2_1'
|
|
13
|
+
| 'well_architected_reliability'
|
|
14
|
+
| 'well_architected_security';
|
|
7
15
|
directory?: string;
|
|
8
|
-
unitTestRunner?: 'jest' | 'vitest' | 'none';
|
|
16
|
+
// unitTestRunner?: 'jest' | 'vitest' | 'none';
|
|
17
|
+
// linter?: Linter;
|
|
9
18
|
skipInstall?: boolean;
|
|
10
19
|
}
|
|
@@ -14,6 +14,22 @@
|
|
|
14
14
|
"x-prompt": "What name would you like to use for the application?",
|
|
15
15
|
"pattern": "^[a-zA-Z][^:]*$"
|
|
16
16
|
},
|
|
17
|
+
"ruleSet": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"enum": [
|
|
20
|
+
"aws_prototyping",
|
|
21
|
+
"cfn_nag",
|
|
22
|
+
"hipaa",
|
|
23
|
+
"nist_csf",
|
|
24
|
+
"pci_dss_3_2_1",
|
|
25
|
+
"well_architected_reliability",
|
|
26
|
+
"well_architected_security"
|
|
27
|
+
],
|
|
28
|
+
"x-priority": "important",
|
|
29
|
+
"x-prompt": "What rule set do you want to validate your AWS resources with?",
|
|
30
|
+
"description": "Rule set to validate your AWS resources with.",
|
|
31
|
+
"default": "aws_prototyping"
|
|
32
|
+
},
|
|
17
33
|
"directory": {
|
|
18
34
|
"description": "The directory of the new application.",
|
|
19
35
|
"type": "string",
|
|
@@ -21,14 +37,6 @@
|
|
|
21
37
|
"x-priority": "important",
|
|
22
38
|
"default": "packages",
|
|
23
39
|
"x-prompt": "What directory would you like to store your application in?"
|
|
24
|
-
},
|
|
25
|
-
"unitTestRunner": {
|
|
26
|
-
"type": "string",
|
|
27
|
-
"enum": ["jest", "vitest", "none"],
|
|
28
|
-
"x-priority": "important",
|
|
29
|
-
"x-prompt": "What unit test runner would you like to use?",
|
|
30
|
-
"description": "Test runner to use for unit tests.",
|
|
31
|
-
"default": "vitest"
|
|
32
40
|
}
|
|
33
41
|
},
|
|
34
42
|
"required": ["name"]
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# tRPC Backend Generator
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
|
+
|
|
4
5
|
This generator creates a new tRPC backend application with AWS CDK infrastructure setup. The generated backend uses AWS Lambda for serverless deployment and includes schema validation using Zod. The codebase is structured using ES Modules (ESM) for modern JavaScript module system compatibility. It sets up a complete type-safe API using tRPC with AWS Lambda integration, AWS X-Ray tracing, and AWS Lambda Powertools for observability.
|
|
5
6
|
|
|
6
7
|
## Usage
|
|
@@ -10,12 +11,14 @@ You can generate a new tRPC backend in two ways:
|
|
|
10
11
|
### 1. Using VSCode IDE
|
|
11
12
|
|
|
12
13
|
First, install the NX Console extension for VSCode:
|
|
14
|
+
|
|
13
15
|
1. Open VSCode
|
|
14
16
|
2. Go to Extensions (Ctrl+Shift+X / Cmd+Shift+X)
|
|
15
17
|
3. Search for "Nx Console"
|
|
16
18
|
4. Install [Nx Console](https://marketplace.visualstudio.com/items?itemName=nrwl.angular-console)
|
|
17
19
|
|
|
18
20
|
Then generate your API:
|
|
21
|
+
|
|
19
22
|
1. Open the NX Console in VSCode
|
|
20
23
|
2. Click on "Generate"
|
|
21
24
|
3. Search for "trpc#backend"
|
|
@@ -25,33 +28,35 @@ Then generate your API:
|
|
|
25
28
|
### 2. Using CLI
|
|
26
29
|
|
|
27
30
|
Generate the API:
|
|
31
|
+
|
|
28
32
|
```bash
|
|
29
|
-
nx g @aws/nx-plugin:trpc#backend my-api --
|
|
33
|
+
nx g @aws/nx-plugin:trpc#backend my-api --directory=apps/api
|
|
30
34
|
```
|
|
31
35
|
|
|
32
36
|
You can also perform a dry-run to see what files would be generated without actually creating them:
|
|
37
|
+
|
|
33
38
|
```bash
|
|
34
|
-
nx g @aws/nx-plugin:trpc#backend my-api --
|
|
39
|
+
nx g @aws/nx-plugin:trpc#backend my-api --directory=apps/api --dry-run
|
|
35
40
|
```
|
|
36
41
|
|
|
37
42
|
Both methods will create a new tRPC backend API in the specified directory with all the necessary configuration and infrastructure code.
|
|
38
43
|
|
|
39
44
|
## Input Parameters
|
|
40
45
|
|
|
41
|
-
| Parameter
|
|
42
|
-
|
|
43
|
-
| apiName
|
|
44
|
-
|
|
|
45
|
-
|
|
|
46
|
-
| unitTestRunner | string | "vitest" | Test runner for unit tests. Options: jest, vitest, none |
|
|
46
|
+
| Parameter | Type | Default | Description |
|
|
47
|
+
| -------------- | ------ | ---------- | ---------------------------------------------------------------------------- |
|
|
48
|
+
| apiName\* | string | - | The name of the API (required). Used to generate class names and file paths. |
|
|
49
|
+
| directory | string | "packages" | The directory to store the application in. |
|
|
50
|
+
| unitTestRunner | string | "vitest" | Test runner for unit tests. Options: jest, vitest, none |
|
|
47
51
|
|
|
48
|
-
|
|
52
|
+
\*Required parameter
|
|
49
53
|
|
|
50
54
|
## Expected Output
|
|
51
55
|
|
|
52
56
|
The generator creates three main components:
|
|
53
57
|
|
|
54
58
|
### 1. Backend API Code
|
|
59
|
+
|
|
55
60
|
```
|
|
56
61
|
<directory>/<api-name>/backend/
|
|
57
62
|
├── src/
|
|
@@ -65,6 +70,7 @@ The generator creates three main components:
|
|
|
65
70
|
```
|
|
66
71
|
|
|
67
72
|
### 2. Schema Code
|
|
73
|
+
|
|
68
74
|
```
|
|
69
75
|
<directory>/<api-name>/schema/
|
|
70
76
|
├── src/
|
|
@@ -74,17 +80,29 @@ The generator creates three main components:
|
|
|
74
80
|
```
|
|
75
81
|
|
|
76
82
|
### 3. Infrastructure Code
|
|
83
|
+
|
|
77
84
|
```
|
|
78
|
-
common/
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
│ └── index.ts
|
|
85
|
+
common/
|
|
86
|
+
| └── constructs/
|
|
87
|
+
| | └── src/
|
|
88
|
+
| │ ├── app/ # Infrastructure specific to this API
|
|
89
|
+
| │ │ └── index.ts
|
|
90
|
+
| │ │ └── trpc-apis
|
|
91
|
+
| │ │ └── index.ts
|
|
92
|
+
| │ │ └── <name>.ts # Application specific cdk construct i.e: MyApi
|
|
93
|
+
| │ ├── core/ # Infrastructure specific to this API
|
|
94
|
+
| │ │ └── index.ts
|
|
95
|
+
| │ │ └── trpc-api.ts # Generic Trpc API construct
|
|
96
|
+
| │ └── index.ts # Exports for all constructs
|
|
97
|
+
| └── types/
|
|
98
|
+
| └── src/
|
|
99
|
+
| └── runtime-config.ts # Updates IRuntimeConfig to add trpcApis
|
|
83
100
|
├── tsconfig.json # TypeScript configuration
|
|
84
101
|
└── project.json # Project configuration and build targets
|
|
85
102
|
```
|
|
86
103
|
|
|
87
104
|
Additionally, it:
|
|
105
|
+
|
|
88
106
|
1. Configures build settings for production deployment
|
|
89
107
|
2. Installs required dependencies:
|
|
90
108
|
- @trpc/server
|
|
@@ -107,13 +125,7 @@ The router is configured in `router.ts` with AWS Lambda integration:
|
|
|
107
125
|
```typescript
|
|
108
126
|
import { initTRPC } from '@trpc/server';
|
|
109
127
|
import { awsLambdaRequestHandler } from '@trpc/server/adapters/aws-lambda';
|
|
110
|
-
import {
|
|
111
|
-
createErrorPlugin,
|
|
112
|
-
createLoggerPlugin,
|
|
113
|
-
createMetricsPlugin,
|
|
114
|
-
createTracerPlugin,
|
|
115
|
-
IMiddlewareContext,
|
|
116
|
-
} from './middleware.js';
|
|
128
|
+
import { createErrorPlugin, createLoggerPlugin, createMetricsPlugin, createTracerPlugin, IMiddlewareContext } from './middleware.js';
|
|
117
129
|
|
|
118
130
|
// Initialize tRPC with context type
|
|
119
131
|
export type Context = IMiddlewareContext;
|
|
@@ -121,11 +133,7 @@ const t = initTRPC.context<Context>().create();
|
|
|
121
133
|
|
|
122
134
|
// Create base router and procedure which automatically instruments all middleware
|
|
123
135
|
export const router = t.router;
|
|
124
|
-
export const publicProcedure = t.procedure
|
|
125
|
-
.unstable_concat(createLoggerPlugin().loggerPlugin)
|
|
126
|
-
.unstable_concat(createTracerPlugin().tracerPlugin)
|
|
127
|
-
.unstable_concat(createMetricsPlugin().metricsPlugin)
|
|
128
|
-
.unstable_concat(createErrorPlugin().errorPlugin);
|
|
136
|
+
export const publicProcedure = t.procedure.unstable_concat(createLoggerPlugin().loggerPlugin).unstable_concat(createTracerPlugin().tracerPlugin).unstable_concat(createMetricsPlugin().metricsPlugin).unstable_concat(createErrorPlugin().errorPlugin);
|
|
129
137
|
|
|
130
138
|
// Define your procedures here
|
|
131
139
|
const appRouter = router({
|
|
@@ -137,7 +145,7 @@ const appRouter = router({
|
|
|
137
145
|
|
|
138
146
|
// Create Lambda handler
|
|
139
147
|
export const handler = awsLambdaRequestHandler({
|
|
140
|
-
router: appRouter
|
|
148
|
+
router: appRouter,
|
|
141
149
|
});
|
|
142
150
|
|
|
143
151
|
// Import this type in the frontend when setting up your integration
|
|
@@ -149,17 +157,20 @@ export type AppRouter = typeof appRouter;
|
|
|
149
157
|
The generator includes four powerful middleware plugins whcih are automatically instrumented:
|
|
150
158
|
|
|
151
159
|
1. **Logger Plugin**
|
|
160
|
+
|
|
152
161
|
- Automatically logs procedure execution
|
|
153
162
|
- Captures errors with detailed context
|
|
154
163
|
- Uses structured logging format
|
|
155
164
|
|
|
156
165
|
2. **Metrics Plugin**
|
|
166
|
+
|
|
157
167
|
- Captures cold start metrics
|
|
158
168
|
- Tracks request counts
|
|
159
169
|
- Records success/error metrics
|
|
160
170
|
- Automatically publishes metrics to CloudWatch
|
|
161
171
|
|
|
162
172
|
3. **Tracer Plugin**
|
|
173
|
+
|
|
163
174
|
- Integrates with AWS X-Ray
|
|
164
175
|
- Creates subsegments for each procedure
|
|
165
176
|
- Annotates cold starts
|
|
@@ -176,23 +187,21 @@ You can access the context in your procedures to utilize the observability tools
|
|
|
176
187
|
|
|
177
188
|
```typescript
|
|
178
189
|
const appRouter = router({
|
|
179
|
-
getData: publicProcedure
|
|
180
|
-
|
|
181
|
-
.
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
//
|
|
191
|
-
return
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
});
|
|
195
|
-
}),
|
|
190
|
+
getData: publicProcedure.input(z.string()).query(async (opts) => {
|
|
191
|
+
// Access logger
|
|
192
|
+
opts.ctx.logger.info('Processing getData request', {
|
|
193
|
+
input: opts.input,
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// Add custom metrics
|
|
197
|
+
opts.ctx.metrics.addMetric('getData.calls', MetricUnit.Count, 1);
|
|
198
|
+
|
|
199
|
+
// Use tracer for subsegments
|
|
200
|
+
return opts.ctx.tracer.captureMethod('getData.process', async () => {
|
|
201
|
+
// Your business logic here
|
|
202
|
+
return { data: 'result' };
|
|
203
|
+
});
|
|
204
|
+
}),
|
|
196
205
|
});
|
|
197
206
|
```
|
|
198
207
|
|
|
@@ -201,7 +210,7 @@ const appRouter = router({
|
|
|
201
210
|
```mermaid
|
|
202
211
|
graph TD
|
|
203
212
|
subgraph AWS Cloud
|
|
204
|
-
APIGW[API Gateway] --> Lambda[Lambda
|
|
213
|
+
APIGW[API Gateway] --> Lambda[Lambda Function]
|
|
205
214
|
Lambda --> XRay[X-Ray Tracing]
|
|
206
215
|
Lambda --> CW[CloudWatch Logs]
|
|
207
216
|
Lambda --> Metrics[CloudWatch Metrics]
|
|
@@ -209,12 +218,15 @@ graph TD
|
|
|
209
218
|
```
|
|
210
219
|
|
|
211
220
|
The infrastructure stack deploys:
|
|
221
|
+
|
|
212
222
|
1. **API Gateway**
|
|
223
|
+
|
|
213
224
|
- HTTP API endpoint
|
|
214
225
|
- Request validation
|
|
215
226
|
- CORS configuration
|
|
216
227
|
|
|
217
228
|
2. **Lambda Functions**
|
|
229
|
+
|
|
218
230
|
- Serverless compute
|
|
219
231
|
- Auto-scaling
|
|
220
232
|
- Pay-per-use pricing
|
|
@@ -225,7 +237,6 @@ The infrastructure stack deploys:
|
|
|
225
237
|
- CloudWatch Metrics via Lambda Powertools
|
|
226
238
|
- Structured logging with Lambda Powertools
|
|
227
239
|
|
|
228
|
-
|
|
229
240
|
## Using the Generated CDK Constructs
|
|
230
241
|
|
|
231
242
|
After generating your tRPC backend, you'll find a CDK construct in the `common/constructs` directory. Here's how to use it in your infrastructure:
|
|
@@ -242,10 +253,7 @@ export class MyStack extends Stack {
|
|
|
242
253
|
super(scope, id);
|
|
243
254
|
|
|
244
255
|
// Create the API with no authentication
|
|
245
|
-
const api = new MyApi(this, 'MyApi'
|
|
246
|
-
defaultAuthorizer: new HttpNoneAuthorizer(),
|
|
247
|
-
allowedOrigins: ['http://localhost:4200']
|
|
248
|
-
});
|
|
256
|
+
const api = new MyApi(this, 'MyApi');
|
|
249
257
|
}
|
|
250
258
|
}
|
|
251
259
|
```
|
|
@@ -255,7 +263,7 @@ export class MyStack extends Stack {
|
|
|
255
263
|
```typescript
|
|
256
264
|
import * as cdk from 'aws-cdk-lib';
|
|
257
265
|
import { Construct } from 'constructs';
|
|
258
|
-
import { UserIdentity, MyApi } from ':my-org/common-constructs'
|
|
266
|
+
import { UserIdentity, MyApi } from ':my-org/common-constructs';
|
|
259
267
|
import { HttpIamAuthorizer } from 'aws-cdk-lib/aws-apigatewayv2-authorizers';
|
|
260
268
|
|
|
261
269
|
export class ApplicationStack extends cdk.Stack {
|
|
@@ -263,9 +271,7 @@ export class ApplicationStack extends cdk.Stack {
|
|
|
263
271
|
super(scope, id, props);
|
|
264
272
|
|
|
265
273
|
const identity = new UserIdentity(this, 'UserIdentity');
|
|
266
|
-
const myapi = new MyApi(this, 'MyApi'
|
|
267
|
-
defaultAuthorizer: new HttpIamAuthorizer(),
|
|
268
|
-
});
|
|
274
|
+
const myapi = new MyApi(this, 'MyApi');
|
|
269
275
|
myapi.grantInvokeAccess(identity.identityPool.authenticatedRole);
|
|
270
276
|
}
|
|
271
277
|
}
|
|
@@ -282,15 +288,13 @@ export class MyStack extends Stack {
|
|
|
282
288
|
constructor(scope: App, id: string) {
|
|
283
289
|
super(scope, id);
|
|
284
290
|
|
|
285
|
-
const api = new MyApi(this, 'MyApi'
|
|
286
|
-
// ... configuration
|
|
287
|
-
});
|
|
291
|
+
const api = new MyApi(this, 'MyApi');
|
|
288
292
|
|
|
289
293
|
// Grant access to other roles if needed
|
|
290
294
|
const consumerRole = new Role(this, 'ConsumerRole', {
|
|
291
295
|
// ... role configuration
|
|
292
296
|
});
|
|
293
|
-
|
|
297
|
+
|
|
294
298
|
api.grantInvokeAccess(consumerRole);
|
|
295
299
|
}
|
|
296
300
|
}
|
|
@@ -298,6 +302,29 @@ export class MyStack extends Stack {
|
|
|
298
302
|
|
|
299
303
|
The API URL will be automatically registered in the RuntimeConfig system and can be accessed in your frontend application.
|
|
300
304
|
|
|
305
|
+
### Updating CORS configuration
|
|
306
|
+
|
|
307
|
+
To update the CORS configuration, you can do this directly by modifying the generated APi construct located in `common/constructs/src/app/trpc-apis`.
|
|
308
|
+
|
|
309
|
+
For example:
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
import { Construct } from 'constructs';
|
|
313
|
+
import * as url from 'url';
|
|
314
|
+
import { TrpcApi } from '../../core/trpc-api.js';
|
|
315
|
+
import { HttpIamAuthorizer } from 'aws-cdk-lib/aws-apigatewayv2-authorizers';
|
|
316
|
+
|
|
317
|
+
export class MyApi extends TrpcApi {
|
|
318
|
+
constructor(scope: Construct, id: string) {
|
|
319
|
+
super(scope, id, {
|
|
320
|
+
defaultAuthorizer: new HttpIamAuthorizer(),
|
|
321
|
+
handlerFilePath: url.fileURLToPath(new URL('../../../../../../packages/my-api/backend/src/lambdas/router.ts', import.meta.url)),
|
|
322
|
+
allowedOrigins: ['http://localhost:4200/'], // Allow CORS from local vite dev server
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
301
328
|
## Schema Code and Zod
|
|
302
329
|
|
|
303
330
|
The generator creates a separate schema package that uses [Zod](https://zod.dev), a TypeScript-first schema declaration and validation library. This package can be shared between your backend and frontend code to ensure type safety across your entire application.
|
|
@@ -305,6 +332,7 @@ The generator creates a separate schema package that uses [Zod](https://zod.dev)
|
|
|
305
332
|
### Introduction to Zod
|
|
306
333
|
|
|
307
334
|
Zod is a schema declaration and validation library designed specifically for TypeScript. It allows you to:
|
|
335
|
+
|
|
308
336
|
- Define schemas with a fluent API
|
|
309
337
|
- Automatically infer TypeScript types from schemas
|
|
310
338
|
- Validate data at runtime
|
|
@@ -368,17 +396,9 @@ export const CustomerSchema = z.object({
|
|
|
368
396
|
```typescript
|
|
369
397
|
import { z } from 'zod';
|
|
370
398
|
|
|
371
|
-
export const OrderStatusSchema = z.enum([
|
|
372
|
-
'pending',
|
|
373
|
-
'processing',
|
|
374
|
-
'shipped',
|
|
375
|
-
'delivered'
|
|
376
|
-
]);
|
|
399
|
+
export const OrderStatusSchema = z.enum(['pending', 'processing', 'shipped', 'delivered']);
|
|
377
400
|
|
|
378
|
-
export const PaymentMethodSchema = z.union([
|
|
379
|
-
z.object({ type: z.literal('credit_card'), cardNumber: z.string() }),
|
|
380
|
-
z.object({ type: z.literal('paypal'), email: z.string().email() }),
|
|
381
|
-
]);
|
|
401
|
+
export const PaymentMethodSchema = z.union([z.object({ type: z.literal('credit_card'), cardNumber: z.string() }), z.object({ type: z.literal('paypal'), email: z.string().email() })]);
|
|
382
402
|
|
|
383
403
|
export const OrderSchema = z.object({
|
|
384
404
|
id: z.string().uuid(),
|
|
@@ -428,12 +448,7 @@ Your schemas can be used directly in your tRPC procedures for input validation a
|
|
|
428
448
|
|
|
429
449
|
```typescript
|
|
430
450
|
import { router, publicProcedure } from './router';
|
|
431
|
-
import {
|
|
432
|
-
UserSchema,
|
|
433
|
-
CreateUserSchema,
|
|
434
|
-
UpdateUserSchema,
|
|
435
|
-
SearchParamsSchema
|
|
436
|
-
} from ':my-org/schema';
|
|
451
|
+
import { UserSchema, CreateUserSchema, UpdateUserSchema, SearchParamsSchema } from ':my-org/schema';
|
|
437
452
|
|
|
438
453
|
export const userRouter = router({
|
|
439
454
|
// Create user with input validation
|
|
@@ -457,10 +472,12 @@ export const userRouter = router({
|
|
|
457
472
|
|
|
458
473
|
// Update user with partial data
|
|
459
474
|
update: publicProcedure
|
|
460
|
-
.input(
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
475
|
+
.input(
|
|
476
|
+
z.object({
|
|
477
|
+
id: z.string().uuid(),
|
|
478
|
+
data: UpdateUserSchema,
|
|
479
|
+
})
|
|
480
|
+
)
|
|
464
481
|
.output(UserSchema)
|
|
465
482
|
.mutation(async (opts) => {
|
|
466
483
|
const { id, data } = opts.input;
|
|
@@ -474,6 +491,7 @@ export const userRouter = router({
|
|
|
474
491
|
1. **Keep Schemas Centralized**: Store all schemas in the schema package to ensure they're easily shared between frontend and backend.
|
|
475
492
|
|
|
476
493
|
2. **Use Type Inference**: Let TypeScript infer types from your schemas instead of maintaining separate type definitions:
|
|
494
|
+
|
|
477
495
|
```typescript
|
|
478
496
|
// Do this:
|
|
479
497
|
export const UserSchema = z.object({ ... });
|
|
@@ -485,6 +503,7 @@ export const userRouter = router({
|
|
|
485
503
|
```
|
|
486
504
|
|
|
487
505
|
3. **Compose Schemas**: Build complex schemas by composing simpler ones:
|
|
506
|
+
|
|
488
507
|
```typescript
|
|
489
508
|
const BaseUserSchema = z.object({
|
|
490
509
|
email: z.string().email(),
|
|
@@ -497,6 +516,7 @@ export const userRouter = router({
|
|
|
497
516
|
```
|
|
498
517
|
|
|
499
518
|
4. **Version Your Schemas**: When making breaking changes, consider versioning your schemas:
|
|
519
|
+
|
|
500
520
|
```typescript
|
|
501
521
|
export const UserSchemaV1 = z.object({ ... });
|
|
502
522
|
export const UserSchemaV2 = UserSchemaV1.extend({ ... });
|
|
@@ -505,7 +525,7 @@ export const userRouter = router({
|
|
|
505
525
|
5. **Document Your Schemas**: Add JSDoc comments to explain complex validation rules:
|
|
506
526
|
```typescript
|
|
507
527
|
export const ConfigSchema = z.object({
|
|
508
|
-
/**
|
|
528
|
+
/**
|
|
509
529
|
* API key must be in format: prefix_<32 chars>
|
|
510
530
|
* Example: myapp_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
|
|
511
531
|
*/
|
|
@@ -516,15 +536,18 @@ export const userRouter = router({
|
|
|
516
536
|
## Building the Application
|
|
517
537
|
|
|
518
538
|
To create a production build:
|
|
539
|
+
|
|
519
540
|
```bash
|
|
520
541
|
nx build @my-org/my-api
|
|
521
542
|
```
|
|
522
543
|
|
|
523
544
|
All built code is located in the `dist` folder at the root of your workspace. For example:
|
|
545
|
+
|
|
524
546
|
- Backend code: `dist/apps/api/my-api/backend`
|
|
525
547
|
- Schema code: `dist/apps/api/my-api/schema`
|
|
526
548
|
|
|
527
549
|
The production build:
|
|
550
|
+
|
|
528
551
|
- Bundles Lambda functions for optimal cold start performance
|
|
529
552
|
- Generates TypeScript declaration files
|
|
530
553
|
- Creates source maps for debugging
|
|
@@ -546,4 +569,3 @@ new NodejsFunction(this, 'MyApiHandler', {
|
|
|
546
569
|
```
|
|
547
570
|
|
|
548
571
|
This will ensure that whichever `@aws-sdk` version you have installed locally will be the one that is used in the Lambda.
|
|
549
|
-
|