@ttoss/appsync-api 0.17.12 → 0.18.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/README.md +35 -0
- package/dist/esm/index.js +55 -139
- package/dist/index.d.mts +8 -2
- package/dist/index.d.ts +8 -2
- package/dist/index.js +55 -139
- package/package.json +2 -2
- package/src/createApiTemplate.ts +81 -25
package/README.md
CHANGED
|
@@ -98,3 +98,38 @@ export const handler = createAppSyncResolverHandler({
|
|
|
98
98
|
middlewares: [permissions],
|
|
99
99
|
});
|
|
100
100
|
```
|
|
101
|
+
|
|
102
|
+
### Custom domain name
|
|
103
|
+
|
|
104
|
+
You can add a custom domain name to your API using the `customDomain` option.
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
import { createApiTemplate } from '@ttoss/appsync-api';
|
|
108
|
+
|
|
109
|
+
export const handler = createApiTemplate({
|
|
110
|
+
schemaComposer,
|
|
111
|
+
customDomain: {
|
|
112
|
+
domainName: 'api.example.com', // required
|
|
113
|
+
certificateArn: {
|
|
114
|
+
'Fn::ImportValue': 'AppSyncDomainCertificateArn',
|
|
115
|
+
}, // required
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
If your domain is on Route53, you can use the option `customDomain.hostedZoneName` to create the required DNS records.
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
import { createApiTemplate } from '@ttoss/appsync-api';
|
|
124
|
+
|
|
125
|
+
export const template = createApiTemplate({
|
|
126
|
+
schemaComposer,
|
|
127
|
+
customDomain: {
|
|
128
|
+
domainName: 'api.example.com', // required
|
|
129
|
+
certificateArn: {
|
|
130
|
+
'Fn::ImportValue': 'AppSyncDomainCertificateArn',
|
|
131
|
+
}, // required
|
|
132
|
+
hostedZoneName: 'example.com.', // optional
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
```
|
package/dist/esm/index.js
CHANGED
|
@@ -2,128 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
// src/createApiTemplate.ts
|
|
4
4
|
import { graphql } from "@ttoss/graphql-api";
|
|
5
|
-
|
|
6
|
-
// ../../node_modules/.pnpm/tslib@2.6.2/node_modules/tslib/tslib.es6.mjs
|
|
7
|
-
var __assign = function () {
|
|
8
|
-
__assign = Object.assign || function __assign2(t) {
|
|
9
|
-
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
10
|
-
s = arguments[i];
|
|
11
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
|
|
12
|
-
}
|
|
13
|
-
return t;
|
|
14
|
-
};
|
|
15
|
-
return __assign.apply(this, arguments);
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
// ../../node_modules/.pnpm/lower-case@2.0.2/node_modules/lower-case/dist.es2015/index.js
|
|
19
|
-
function lowerCase(str) {
|
|
20
|
-
return str.toLowerCase();
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// ../../node_modules/.pnpm/no-case@3.0.4/node_modules/no-case/dist.es2015/index.js
|
|
24
|
-
var DEFAULT_SPLIT_REGEXP = [/([a-z0-9])([A-Z])/g, /([A-Z])([A-Z][a-z])/g];
|
|
25
|
-
var DEFAULT_STRIP_REGEXP = /[^A-Z0-9]+/gi;
|
|
26
|
-
function noCase(input, options) {
|
|
27
|
-
if (options === void 0) {
|
|
28
|
-
options = {};
|
|
29
|
-
}
|
|
30
|
-
var _a = options.splitRegexp,
|
|
31
|
-
splitRegexp = _a === void 0 ? DEFAULT_SPLIT_REGEXP : _a,
|
|
32
|
-
_b = options.stripRegexp,
|
|
33
|
-
stripRegexp = _b === void 0 ? DEFAULT_STRIP_REGEXP : _b,
|
|
34
|
-
_c = options.transform,
|
|
35
|
-
transform = _c === void 0 ? lowerCase : _c,
|
|
36
|
-
_d = options.delimiter,
|
|
37
|
-
delimiter = _d === void 0 ? " " : _d;
|
|
38
|
-
var result = replace(replace(input, splitRegexp, "$1\0$2"), stripRegexp, "\0");
|
|
39
|
-
var start = 0;
|
|
40
|
-
var end = result.length;
|
|
41
|
-
while (result.charAt(start) === "\0") start++;
|
|
42
|
-
while (result.charAt(end - 1) === "\0") end--;
|
|
43
|
-
return result.slice(start, end).split("\0").map(transform).join(delimiter);
|
|
44
|
-
}
|
|
45
|
-
function replace(input, re, value) {
|
|
46
|
-
if (re instanceof RegExp) return input.replace(re, value);
|
|
47
|
-
return re.reduce(function (input2, re2) {
|
|
48
|
-
return input2.replace(re2, value);
|
|
49
|
-
}, input);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// ../../node_modules/.pnpm/pascal-case@3.1.2/node_modules/pascal-case/dist.es2015/index.js
|
|
53
|
-
function pascalCaseTransform(input, index) {
|
|
54
|
-
var firstChar = input.charAt(0);
|
|
55
|
-
var lowerChars = input.substr(1).toLowerCase();
|
|
56
|
-
if (index > 0 && firstChar >= "0" && firstChar <= "9") {
|
|
57
|
-
return "_" + firstChar + lowerChars;
|
|
58
|
-
}
|
|
59
|
-
return "" + firstChar.toUpperCase() + lowerChars;
|
|
60
|
-
}
|
|
61
|
-
function pascalCase(input, options) {
|
|
62
|
-
if (options === void 0) {
|
|
63
|
-
options = {};
|
|
64
|
-
}
|
|
65
|
-
return noCase(input, __assign({
|
|
66
|
-
delimiter: "",
|
|
67
|
-
transform: pascalCaseTransform
|
|
68
|
-
}, options));
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// ../carlin/src/deploy/lambdaLayer/getPackageLambdaLayerStackName.ts
|
|
72
|
-
var lambdaLayerStackNamePrefix = `LambdaLayer`;
|
|
73
|
-
var getPackageLambdaLayerStackName = packageName => {
|
|
74
|
-
const [scopedName, version] = packageName.split("@").filter(part => {
|
|
75
|
-
return !!part;
|
|
76
|
-
});
|
|
77
|
-
return [lambdaLayerStackNamePrefix, pascalCase(scopedName), version.replace(/[^0-9.]/g, "").replace(/\./g, "-")].join("-");
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
// package.json
|
|
81
|
-
var package_default = {
|
|
82
|
-
name: "@ttoss/appsync-api",
|
|
83
|
-
version: "0.17.12",
|
|
84
|
-
description: "A library for building GraphQL APIs for AWS AppSync.",
|
|
85
|
-
author: "ttoss",
|
|
86
|
-
contributors: ["Pedro Arantes <pedro@arantespp.com> (https://arantespp.com)"],
|
|
87
|
-
repository: {
|
|
88
|
-
type: "git",
|
|
89
|
-
url: "https://github.com/ttoss/ttoss.git",
|
|
90
|
-
directory: "packages/appsync-api"
|
|
91
|
-
},
|
|
92
|
-
main: "dist/index.js",
|
|
93
|
-
module: "dist/esm/index.js",
|
|
94
|
-
files: ["dist", "src"],
|
|
95
|
-
scripts: {
|
|
96
|
-
build: "tsup",
|
|
97
|
-
test: "jest"
|
|
98
|
-
},
|
|
99
|
-
sideEffects: false,
|
|
100
|
-
typings: "dist/index.d.ts",
|
|
101
|
-
dependencies: {
|
|
102
|
-
"@ttoss/cloudformation": "workspace:^"
|
|
103
|
-
},
|
|
104
|
-
peerDependencies: {
|
|
105
|
-
"@ttoss/graphql-api": "workspace:^",
|
|
106
|
-
graphql: "^16.6.0"
|
|
107
|
-
},
|
|
108
|
-
devDependencies: {
|
|
109
|
-
"@ttoss/config": "workspace:^",
|
|
110
|
-
"@ttoss/graphql-api": "workspace:^",
|
|
111
|
-
"@ttoss/relay-amplify": "workspace:^",
|
|
112
|
-
"@types/aws-lambda": "^8.10.130",
|
|
113
|
-
carlin: "workspace:^",
|
|
114
|
-
graphql: "^16.8.1",
|
|
115
|
-
"graphql-shield": "^7.6.5",
|
|
116
|
-
jest: "^29.7.0",
|
|
117
|
-
tsup: "^8.0.1"
|
|
118
|
-
},
|
|
119
|
-
keywords: ["api", "appsync", "aws", "graphql"],
|
|
120
|
-
publishConfig: {
|
|
121
|
-
access: "public",
|
|
122
|
-
provenance: true
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
// src/createApiTemplate.ts
|
|
127
5
|
var AppSyncGraphQLApiLogicalId = "AppSyncGraphQLApi";
|
|
128
6
|
var AppSyncGraphQLSchemaLogicalId = "AppSyncGraphQLSchema";
|
|
129
7
|
var AppSyncLambdaFunctionLogicalId = "AppSyncLambdaFunction";
|
|
@@ -135,7 +13,8 @@ var createApiTemplate = ({
|
|
|
135
13
|
schemaComposer,
|
|
136
14
|
dataSource,
|
|
137
15
|
lambdaFunction,
|
|
138
|
-
userPoolConfig
|
|
16
|
+
userPoolConfig,
|
|
17
|
+
customDomain
|
|
139
18
|
}) => {
|
|
140
19
|
const sdlWithoutComments = schemaComposer.toSDL({
|
|
141
20
|
commentDescriptions: false,
|
|
@@ -158,21 +37,6 @@ var createApiTemplate = ({
|
|
|
158
37
|
};
|
|
159
38
|
});
|
|
160
39
|
}).filter(Boolean);
|
|
161
|
-
const getPeerDependenciesLambdaLayers = () => {
|
|
162
|
-
const {
|
|
163
|
-
peerDependencies
|
|
164
|
-
} = package_default;
|
|
165
|
-
const lambdaLayerStackNames = Object.entries(peerDependencies).filter(([dependencyName]) => {
|
|
166
|
-
return ["graphql"].includes(dependencyName);
|
|
167
|
-
}).map(([dependencyName, dependencyVersion]) => {
|
|
168
|
-
return getPackageLambdaLayerStackName([dependencyName, dependencyVersion].join("@"));
|
|
169
|
-
});
|
|
170
|
-
return lambdaLayerStackNames.map(lambdaLayerStackName => {
|
|
171
|
-
return {
|
|
172
|
-
"Fn::ImportValue": lambdaLayerStackName
|
|
173
|
-
};
|
|
174
|
-
});
|
|
175
|
-
};
|
|
176
40
|
const template = {
|
|
177
41
|
AWSTemplateFormatVersion: "2010-09-09",
|
|
178
42
|
Parameters: {
|
|
@@ -228,7 +92,7 @@ var createApiTemplate = ({
|
|
|
228
92
|
}
|
|
229
93
|
},
|
|
230
94
|
Handler: "index.handler",
|
|
231
|
-
Layers:
|
|
95
|
+
Layers: lambdaFunction.layers,
|
|
232
96
|
MemorySize: 512,
|
|
233
97
|
Role: lambdaFunction.roleArn,
|
|
234
98
|
Runtime: "nodejs20.x",
|
|
@@ -345,6 +209,58 @@ var createApiTemplate = ({
|
|
|
345
209
|
Variables: lambdaFunction.environment.variables
|
|
346
210
|
};
|
|
347
211
|
}
|
|
212
|
+
if (customDomain) {
|
|
213
|
+
const AppSyncDomainNameLogicalId = "AppSyncDomainName";
|
|
214
|
+
template.Resources[AppSyncDomainNameLogicalId] = {
|
|
215
|
+
Type: "AWS::AppSync::DomainName",
|
|
216
|
+
Properties: {
|
|
217
|
+
CertificateArn: customDomain.certificateArn,
|
|
218
|
+
Description: "Custom domain for AppSync API",
|
|
219
|
+
DomainName: customDomain.domainName
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
if (customDomain.hostedZoneName) {
|
|
223
|
+
const hostedZoneName = customDomain.hostedZoneName.endsWith(".") ? customDomain.hostedZoneName : `${customDomain.hostedZoneName}.`;
|
|
224
|
+
template.Resources.AppSyncDomainNameRoute53RecordSet = {
|
|
225
|
+
Type: "AWS::Route53::RecordSet",
|
|
226
|
+
Properties: {
|
|
227
|
+
HostedZoneName: hostedZoneName,
|
|
228
|
+
Name: customDomain.domainName,
|
|
229
|
+
ResourceRecords: [{
|
|
230
|
+
"Fn::GetAtt": [AppSyncDomainNameLogicalId, "AppSyncDomainName"]
|
|
231
|
+
}],
|
|
232
|
+
TTL: "900",
|
|
233
|
+
Type: "CNAME"
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
template.Resources.AppSyncDomainNameApiAssociation = {
|
|
238
|
+
Type: "AWS::AppSync::DomainNameApiAssociation",
|
|
239
|
+
Properties: {
|
|
240
|
+
ApiId: {
|
|
241
|
+
"Fn::GetAtt": [AppSyncGraphQLApiLogicalId, "ApiId"]
|
|
242
|
+
},
|
|
243
|
+
DomainName: {
|
|
244
|
+
"Fn::GetAtt": [AppSyncDomainNameLogicalId, "DomainName"]
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
if (!template.Outputs) {
|
|
249
|
+
template.Outputs = {};
|
|
250
|
+
}
|
|
251
|
+
template.Outputs.DomainName = {
|
|
252
|
+
Description: "Custom domain name for AppSync API",
|
|
253
|
+
Value: {
|
|
254
|
+
"Fn::GetAtt": [AppSyncDomainNameLogicalId, "DomainName"]
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
template.Outputs.CloudFrontDomainName = {
|
|
258
|
+
Description: "CloudFront domain name for AppSync API",
|
|
259
|
+
Value: {
|
|
260
|
+
"Fn::GetAtt": [AppSyncDomainNameLogicalId, "AppSyncDomainName"]
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
}
|
|
348
264
|
return template;
|
|
349
265
|
};
|
|
350
266
|
|
package/dist/index.d.mts
CHANGED
|
@@ -87,10 +87,14 @@ type StringOrImport = string | {
|
|
|
87
87
|
* https://docs.aws.amazon.com/appsync/latest/devguide/security-authz.html
|
|
88
88
|
*/
|
|
89
89
|
type AuthenticationType = 'API_KEY' | 'AWS_LAMBDA' | 'AWS_IAM' | 'OPENID_CONNECT' | 'AMAZON_COGNITO_USER_POOLS';
|
|
90
|
-
declare const createApiTemplate: ({ additionalAuthenticationProviders, authenticationType, schemaComposer, dataSource, lambdaFunction, userPoolConfig, }: {
|
|
90
|
+
declare const createApiTemplate: ({ additionalAuthenticationProviders, authenticationType, schemaComposer, dataSource, lambdaFunction, userPoolConfig, customDomain, }: {
|
|
91
91
|
additionalAuthenticationProviders?: AuthenticationType[] | undefined;
|
|
92
92
|
authenticationType?: AuthenticationType | undefined;
|
|
93
|
-
|
|
93
|
+
customDomain?: {
|
|
94
|
+
domainName: string;
|
|
95
|
+
certificateArn: string;
|
|
96
|
+
hostedZoneName?: string | undefined;
|
|
97
|
+
} | undefined;
|
|
94
98
|
dataSource: {
|
|
95
99
|
roleArn: StringOrImport;
|
|
96
100
|
};
|
|
@@ -98,8 +102,10 @@ declare const createApiTemplate: ({ additionalAuthenticationProviders, authentic
|
|
|
98
102
|
environment?: {
|
|
99
103
|
variables: Record<string, string>;
|
|
100
104
|
};
|
|
105
|
+
layers?: any;
|
|
101
106
|
roleArn: StringOrImport;
|
|
102
107
|
};
|
|
108
|
+
schemaComposer: SchemaComposer<any>;
|
|
103
109
|
userPoolConfig?: {
|
|
104
110
|
appIdClientRegex: StringOrImport;
|
|
105
111
|
awsRegion: StringOrImport;
|
package/dist/index.d.ts
CHANGED
|
@@ -87,10 +87,14 @@ type StringOrImport = string | {
|
|
|
87
87
|
* https://docs.aws.amazon.com/appsync/latest/devguide/security-authz.html
|
|
88
88
|
*/
|
|
89
89
|
type AuthenticationType = 'API_KEY' | 'AWS_LAMBDA' | 'AWS_IAM' | 'OPENID_CONNECT' | 'AMAZON_COGNITO_USER_POOLS';
|
|
90
|
-
declare const createApiTemplate: ({ additionalAuthenticationProviders, authenticationType, schemaComposer, dataSource, lambdaFunction, userPoolConfig, }: {
|
|
90
|
+
declare const createApiTemplate: ({ additionalAuthenticationProviders, authenticationType, schemaComposer, dataSource, lambdaFunction, userPoolConfig, customDomain, }: {
|
|
91
91
|
additionalAuthenticationProviders?: AuthenticationType[] | undefined;
|
|
92
92
|
authenticationType?: AuthenticationType | undefined;
|
|
93
|
-
|
|
93
|
+
customDomain?: {
|
|
94
|
+
domainName: string;
|
|
95
|
+
certificateArn: string;
|
|
96
|
+
hostedZoneName?: string | undefined;
|
|
97
|
+
} | undefined;
|
|
94
98
|
dataSource: {
|
|
95
99
|
roleArn: StringOrImport;
|
|
96
100
|
};
|
|
@@ -98,8 +102,10 @@ declare const createApiTemplate: ({ additionalAuthenticationProviders, authentic
|
|
|
98
102
|
environment?: {
|
|
99
103
|
variables: Record<string, string>;
|
|
100
104
|
};
|
|
105
|
+
layers?: any;
|
|
101
106
|
roleArn: StringOrImport;
|
|
102
107
|
};
|
|
108
|
+
schemaComposer: SchemaComposer<any>;
|
|
103
109
|
userPoolConfig?: {
|
|
104
110
|
appIdClientRegex: StringOrImport;
|
|
105
111
|
awsRegion: StringOrImport;
|
package/dist/index.js
CHANGED
|
@@ -34,128 +34,6 @@ module.exports = __toCommonJS(src_exports);
|
|
|
34
34
|
|
|
35
35
|
// src/createApiTemplate.ts
|
|
36
36
|
var import_graphql_api = require("@ttoss/graphql-api");
|
|
37
|
-
|
|
38
|
-
// ../../node_modules/.pnpm/tslib@2.6.2/node_modules/tslib/tslib.es6.mjs
|
|
39
|
-
var __assign = function () {
|
|
40
|
-
__assign = Object.assign || function __assign2(t) {
|
|
41
|
-
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
42
|
-
s = arguments[i];
|
|
43
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
|
|
44
|
-
}
|
|
45
|
-
return t;
|
|
46
|
-
};
|
|
47
|
-
return __assign.apply(this, arguments);
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
// ../../node_modules/.pnpm/lower-case@2.0.2/node_modules/lower-case/dist.es2015/index.js
|
|
51
|
-
function lowerCase(str) {
|
|
52
|
-
return str.toLowerCase();
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// ../../node_modules/.pnpm/no-case@3.0.4/node_modules/no-case/dist.es2015/index.js
|
|
56
|
-
var DEFAULT_SPLIT_REGEXP = [/([a-z0-9])([A-Z])/g, /([A-Z])([A-Z][a-z])/g];
|
|
57
|
-
var DEFAULT_STRIP_REGEXP = /[^A-Z0-9]+/gi;
|
|
58
|
-
function noCase(input, options) {
|
|
59
|
-
if (options === void 0) {
|
|
60
|
-
options = {};
|
|
61
|
-
}
|
|
62
|
-
var _a = options.splitRegexp,
|
|
63
|
-
splitRegexp = _a === void 0 ? DEFAULT_SPLIT_REGEXP : _a,
|
|
64
|
-
_b = options.stripRegexp,
|
|
65
|
-
stripRegexp = _b === void 0 ? DEFAULT_STRIP_REGEXP : _b,
|
|
66
|
-
_c = options.transform,
|
|
67
|
-
transform = _c === void 0 ? lowerCase : _c,
|
|
68
|
-
_d = options.delimiter,
|
|
69
|
-
delimiter = _d === void 0 ? " " : _d;
|
|
70
|
-
var result = replace(replace(input, splitRegexp, "$1\0$2"), stripRegexp, "\0");
|
|
71
|
-
var start = 0;
|
|
72
|
-
var end = result.length;
|
|
73
|
-
while (result.charAt(start) === "\0") start++;
|
|
74
|
-
while (result.charAt(end - 1) === "\0") end--;
|
|
75
|
-
return result.slice(start, end).split("\0").map(transform).join(delimiter);
|
|
76
|
-
}
|
|
77
|
-
function replace(input, re, value) {
|
|
78
|
-
if (re instanceof RegExp) return input.replace(re, value);
|
|
79
|
-
return re.reduce(function (input2, re2) {
|
|
80
|
-
return input2.replace(re2, value);
|
|
81
|
-
}, input);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// ../../node_modules/.pnpm/pascal-case@3.1.2/node_modules/pascal-case/dist.es2015/index.js
|
|
85
|
-
function pascalCaseTransform(input, index) {
|
|
86
|
-
var firstChar = input.charAt(0);
|
|
87
|
-
var lowerChars = input.substr(1).toLowerCase();
|
|
88
|
-
if (index > 0 && firstChar >= "0" && firstChar <= "9") {
|
|
89
|
-
return "_" + firstChar + lowerChars;
|
|
90
|
-
}
|
|
91
|
-
return "" + firstChar.toUpperCase() + lowerChars;
|
|
92
|
-
}
|
|
93
|
-
function pascalCase(input, options) {
|
|
94
|
-
if (options === void 0) {
|
|
95
|
-
options = {};
|
|
96
|
-
}
|
|
97
|
-
return noCase(input, __assign({
|
|
98
|
-
delimiter: "",
|
|
99
|
-
transform: pascalCaseTransform
|
|
100
|
-
}, options));
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// ../carlin/src/deploy/lambdaLayer/getPackageLambdaLayerStackName.ts
|
|
104
|
-
var lambdaLayerStackNamePrefix = `LambdaLayer`;
|
|
105
|
-
var getPackageLambdaLayerStackName = packageName => {
|
|
106
|
-
const [scopedName, version] = packageName.split("@").filter(part => {
|
|
107
|
-
return !!part;
|
|
108
|
-
});
|
|
109
|
-
return [lambdaLayerStackNamePrefix, pascalCase(scopedName), version.replace(/[^0-9.]/g, "").replace(/\./g, "-")].join("-");
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
// package.json
|
|
113
|
-
var package_default = {
|
|
114
|
-
name: "@ttoss/appsync-api",
|
|
115
|
-
version: "0.17.12",
|
|
116
|
-
description: "A library for building GraphQL APIs for AWS AppSync.",
|
|
117
|
-
author: "ttoss",
|
|
118
|
-
contributors: ["Pedro Arantes <pedro@arantespp.com> (https://arantespp.com)"],
|
|
119
|
-
repository: {
|
|
120
|
-
type: "git",
|
|
121
|
-
url: "https://github.com/ttoss/ttoss.git",
|
|
122
|
-
directory: "packages/appsync-api"
|
|
123
|
-
},
|
|
124
|
-
main: "dist/index.js",
|
|
125
|
-
module: "dist/esm/index.js",
|
|
126
|
-
files: ["dist", "src"],
|
|
127
|
-
scripts: {
|
|
128
|
-
build: "tsup",
|
|
129
|
-
test: "jest"
|
|
130
|
-
},
|
|
131
|
-
sideEffects: false,
|
|
132
|
-
typings: "dist/index.d.ts",
|
|
133
|
-
dependencies: {
|
|
134
|
-
"@ttoss/cloudformation": "workspace:^"
|
|
135
|
-
},
|
|
136
|
-
peerDependencies: {
|
|
137
|
-
"@ttoss/graphql-api": "workspace:^",
|
|
138
|
-
graphql: "^16.6.0"
|
|
139
|
-
},
|
|
140
|
-
devDependencies: {
|
|
141
|
-
"@ttoss/config": "workspace:^",
|
|
142
|
-
"@ttoss/graphql-api": "workspace:^",
|
|
143
|
-
"@ttoss/relay-amplify": "workspace:^",
|
|
144
|
-
"@types/aws-lambda": "^8.10.130",
|
|
145
|
-
carlin: "workspace:^",
|
|
146
|
-
graphql: "^16.8.1",
|
|
147
|
-
"graphql-shield": "^7.6.5",
|
|
148
|
-
jest: "^29.7.0",
|
|
149
|
-
tsup: "^8.0.1"
|
|
150
|
-
},
|
|
151
|
-
keywords: ["api", "appsync", "aws", "graphql"],
|
|
152
|
-
publishConfig: {
|
|
153
|
-
access: "public",
|
|
154
|
-
provenance: true
|
|
155
|
-
}
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
// src/createApiTemplate.ts
|
|
159
37
|
var AppSyncGraphQLApiLogicalId = "AppSyncGraphQLApi";
|
|
160
38
|
var AppSyncGraphQLSchemaLogicalId = "AppSyncGraphQLSchema";
|
|
161
39
|
var AppSyncLambdaFunctionLogicalId = "AppSyncLambdaFunction";
|
|
@@ -167,7 +45,8 @@ var createApiTemplate = ({
|
|
|
167
45
|
schemaComposer,
|
|
168
46
|
dataSource,
|
|
169
47
|
lambdaFunction,
|
|
170
|
-
userPoolConfig
|
|
48
|
+
userPoolConfig,
|
|
49
|
+
customDomain
|
|
171
50
|
}) => {
|
|
172
51
|
const sdlWithoutComments = schemaComposer.toSDL({
|
|
173
52
|
commentDescriptions: false,
|
|
@@ -190,21 +69,6 @@ var createApiTemplate = ({
|
|
|
190
69
|
};
|
|
191
70
|
});
|
|
192
71
|
}).filter(Boolean);
|
|
193
|
-
const getPeerDependenciesLambdaLayers = () => {
|
|
194
|
-
const {
|
|
195
|
-
peerDependencies
|
|
196
|
-
} = package_default;
|
|
197
|
-
const lambdaLayerStackNames = Object.entries(peerDependencies).filter(([dependencyName]) => {
|
|
198
|
-
return ["graphql"].includes(dependencyName);
|
|
199
|
-
}).map(([dependencyName, dependencyVersion]) => {
|
|
200
|
-
return getPackageLambdaLayerStackName([dependencyName, dependencyVersion].join("@"));
|
|
201
|
-
});
|
|
202
|
-
return lambdaLayerStackNames.map(lambdaLayerStackName => {
|
|
203
|
-
return {
|
|
204
|
-
"Fn::ImportValue": lambdaLayerStackName
|
|
205
|
-
};
|
|
206
|
-
});
|
|
207
|
-
};
|
|
208
72
|
const template = {
|
|
209
73
|
AWSTemplateFormatVersion: "2010-09-09",
|
|
210
74
|
Parameters: {
|
|
@@ -260,7 +124,7 @@ var createApiTemplate = ({
|
|
|
260
124
|
}
|
|
261
125
|
},
|
|
262
126
|
Handler: "index.handler",
|
|
263
|
-
Layers:
|
|
127
|
+
Layers: lambdaFunction.layers,
|
|
264
128
|
MemorySize: 512,
|
|
265
129
|
Role: lambdaFunction.roleArn,
|
|
266
130
|
Runtime: "nodejs20.x",
|
|
@@ -377,6 +241,58 @@ var createApiTemplate = ({
|
|
|
377
241
|
Variables: lambdaFunction.environment.variables
|
|
378
242
|
};
|
|
379
243
|
}
|
|
244
|
+
if (customDomain) {
|
|
245
|
+
const AppSyncDomainNameLogicalId = "AppSyncDomainName";
|
|
246
|
+
template.Resources[AppSyncDomainNameLogicalId] = {
|
|
247
|
+
Type: "AWS::AppSync::DomainName",
|
|
248
|
+
Properties: {
|
|
249
|
+
CertificateArn: customDomain.certificateArn,
|
|
250
|
+
Description: "Custom domain for AppSync API",
|
|
251
|
+
DomainName: customDomain.domainName
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
if (customDomain.hostedZoneName) {
|
|
255
|
+
const hostedZoneName = customDomain.hostedZoneName.endsWith(".") ? customDomain.hostedZoneName : `${customDomain.hostedZoneName}.`;
|
|
256
|
+
template.Resources.AppSyncDomainNameRoute53RecordSet = {
|
|
257
|
+
Type: "AWS::Route53::RecordSet",
|
|
258
|
+
Properties: {
|
|
259
|
+
HostedZoneName: hostedZoneName,
|
|
260
|
+
Name: customDomain.domainName,
|
|
261
|
+
ResourceRecords: [{
|
|
262
|
+
"Fn::GetAtt": [AppSyncDomainNameLogicalId, "AppSyncDomainName"]
|
|
263
|
+
}],
|
|
264
|
+
TTL: "900",
|
|
265
|
+
Type: "CNAME"
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
template.Resources.AppSyncDomainNameApiAssociation = {
|
|
270
|
+
Type: "AWS::AppSync::DomainNameApiAssociation",
|
|
271
|
+
Properties: {
|
|
272
|
+
ApiId: {
|
|
273
|
+
"Fn::GetAtt": [AppSyncGraphQLApiLogicalId, "ApiId"]
|
|
274
|
+
},
|
|
275
|
+
DomainName: {
|
|
276
|
+
"Fn::GetAtt": [AppSyncDomainNameLogicalId, "DomainName"]
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
if (!template.Outputs) {
|
|
281
|
+
template.Outputs = {};
|
|
282
|
+
}
|
|
283
|
+
template.Outputs.DomainName = {
|
|
284
|
+
Description: "Custom domain name for AppSync API",
|
|
285
|
+
Value: {
|
|
286
|
+
"Fn::GetAtt": [AppSyncDomainNameLogicalId, "DomainName"]
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
template.Outputs.CloudFrontDomainName = {
|
|
290
|
+
Description: "CloudFront domain name for AppSync API",
|
|
291
|
+
Value: {
|
|
292
|
+
"Fn::GetAtt": [AppSyncDomainNameLogicalId, "AppSyncDomainName"]
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
}
|
|
380
296
|
return template;
|
|
381
297
|
};
|
|
382
298
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttoss/appsync-api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.1",
|
|
4
4
|
"description": "A library for building GraphQL APIs for AWS AppSync.",
|
|
5
5
|
"author": "ttoss",
|
|
6
6
|
"contributors": [
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"@ttoss/config": "^1.31.4",
|
|
36
36
|
"@ttoss/graphql-api": "^0.5.0",
|
|
37
37
|
"@ttoss/relay-amplify": "^0.5.4",
|
|
38
|
-
"carlin": "^1.31.
|
|
38
|
+
"carlin": "^1.31.9"
|
|
39
39
|
},
|
|
40
40
|
"keywords": [
|
|
41
41
|
"api",
|
package/src/createApiTemplate.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { type SchemaComposer, graphql } from '@ttoss/graphql-api';
|
|
2
|
-
import { getPackageLambdaLayerStackName } from 'carlin/src/deploy/lambdaLayer/getPackageLambdaLayerStackName';
|
|
3
|
-
import packageJson from '../package.json';
|
|
4
2
|
|
|
5
3
|
/**
|
|
6
4
|
* Absolute path to avoid:
|
|
@@ -44,11 +42,15 @@ export const createApiTemplate = ({
|
|
|
44
42
|
dataSource,
|
|
45
43
|
lambdaFunction,
|
|
46
44
|
userPoolConfig,
|
|
45
|
+
customDomain,
|
|
47
46
|
}: {
|
|
48
47
|
additionalAuthenticationProviders?: AuthenticationType[];
|
|
49
48
|
authenticationType?: AuthenticationType;
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
customDomain?: {
|
|
50
|
+
domainName: string;
|
|
51
|
+
certificateArn: string;
|
|
52
|
+
hostedZoneName?: string;
|
|
53
|
+
};
|
|
52
54
|
dataSource: {
|
|
53
55
|
roleArn: StringOrImport;
|
|
54
56
|
};
|
|
@@ -56,8 +58,12 @@ export const createApiTemplate = ({
|
|
|
56
58
|
environment?: {
|
|
57
59
|
variables: Record<string, string>;
|
|
58
60
|
};
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
62
|
+
layers?: any;
|
|
59
63
|
roleArn: StringOrImport;
|
|
60
64
|
};
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
66
|
+
schemaComposer: SchemaComposer<any>;
|
|
61
67
|
userPoolConfig?: {
|
|
62
68
|
appIdClientRegex: StringOrImport;
|
|
63
69
|
awsRegion: StringOrImport;
|
|
@@ -102,26 +108,6 @@ export const createApiTemplate = ({
|
|
|
102
108
|
})
|
|
103
109
|
.filter(Boolean) as Array<{ fieldName: string; typeName: string }>;
|
|
104
110
|
|
|
105
|
-
const getPeerDependenciesLambdaLayers = () => {
|
|
106
|
-
const { peerDependencies } = packageJson;
|
|
107
|
-
|
|
108
|
-
const lambdaLayerStackNames = Object.entries(peerDependencies)
|
|
109
|
-
.filter(([dependencyName]) => {
|
|
110
|
-
return ['graphql'].includes(dependencyName);
|
|
111
|
-
})
|
|
112
|
-
.map(([dependencyName, dependencyVersion]) => {
|
|
113
|
-
return getPackageLambdaLayerStackName(
|
|
114
|
-
[dependencyName, dependencyVersion].join('@')
|
|
115
|
-
);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
return lambdaLayerStackNames.map((lambdaLayerStackName) => {
|
|
119
|
-
return {
|
|
120
|
-
'Fn::ImportValue': lambdaLayerStackName,
|
|
121
|
-
};
|
|
122
|
-
});
|
|
123
|
-
};
|
|
124
|
-
|
|
125
111
|
const template: CloudFormationTemplate = {
|
|
126
112
|
AWSTemplateFormatVersion: '2010-09-09',
|
|
127
113
|
Parameters: {
|
|
@@ -169,7 +155,7 @@ export const createApiTemplate = ({
|
|
|
169
155
|
S3ObjectVersion: { Ref: 'LambdaS3ObjectVersion' },
|
|
170
156
|
},
|
|
171
157
|
Handler: 'index.handler',
|
|
172
|
-
Layers:
|
|
158
|
+
Layers: lambdaFunction.layers,
|
|
173
159
|
MemorySize: 512,
|
|
174
160
|
Role: lambdaFunction.roleArn,
|
|
175
161
|
Runtime: 'nodejs20.x',
|
|
@@ -300,5 +286,75 @@ export const createApiTemplate = ({
|
|
|
300
286
|
};
|
|
301
287
|
}
|
|
302
288
|
|
|
289
|
+
if (customDomain) {
|
|
290
|
+
const AppSyncDomainNameLogicalId = 'AppSyncDomainName';
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appsync-domainname.html
|
|
294
|
+
*/
|
|
295
|
+
template.Resources[AppSyncDomainNameLogicalId] = {
|
|
296
|
+
Type: 'AWS::AppSync::DomainName',
|
|
297
|
+
Properties: {
|
|
298
|
+
CertificateArn: customDomain.certificateArn,
|
|
299
|
+
Description: 'Custom domain for AppSync API',
|
|
300
|
+
DomainName: customDomain.domainName,
|
|
301
|
+
},
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
if (customDomain.hostedZoneName) {
|
|
305
|
+
const hostedZoneName = customDomain.hostedZoneName.endsWith('.')
|
|
306
|
+
? customDomain.hostedZoneName
|
|
307
|
+
: `${customDomain.hostedZoneName}.`;
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53-recordset.html
|
|
311
|
+
*/
|
|
312
|
+
template.Resources.AppSyncDomainNameRoute53RecordSet = {
|
|
313
|
+
Type: 'AWS::Route53::RecordSet',
|
|
314
|
+
Properties: {
|
|
315
|
+
HostedZoneName: hostedZoneName,
|
|
316
|
+
Name: customDomain.domainName,
|
|
317
|
+
ResourceRecords: [
|
|
318
|
+
{
|
|
319
|
+
'Fn::GetAtt': [AppSyncDomainNameLogicalId, 'AppSyncDomainName'],
|
|
320
|
+
},
|
|
321
|
+
],
|
|
322
|
+
TTL: '900',
|
|
323
|
+
Type: 'CNAME',
|
|
324
|
+
},
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
template.Resources.AppSyncDomainNameApiAssociation = {
|
|
329
|
+
Type: 'AWS::AppSync::DomainNameApiAssociation',
|
|
330
|
+
Properties: {
|
|
331
|
+
ApiId: {
|
|
332
|
+
'Fn::GetAtt': [AppSyncGraphQLApiLogicalId, 'ApiId'],
|
|
333
|
+
},
|
|
334
|
+
DomainName: {
|
|
335
|
+
'Fn::GetAtt': [AppSyncDomainNameLogicalId, 'DomainName'],
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
if (!template.Outputs) {
|
|
341
|
+
template.Outputs = {};
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
template.Outputs.DomainName = {
|
|
345
|
+
Description: 'Custom domain name for AppSync API',
|
|
346
|
+
Value: {
|
|
347
|
+
'Fn::GetAtt': [AppSyncDomainNameLogicalId, 'DomainName'],
|
|
348
|
+
},
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
template.Outputs.CloudFrontDomainName = {
|
|
352
|
+
Description: 'CloudFront domain name for AppSync API',
|
|
353
|
+
Value: {
|
|
354
|
+
'Fn::GetAtt': [AppSyncDomainNameLogicalId, 'AppSyncDomainName'],
|
|
355
|
+
},
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
|
|
303
359
|
return template;
|
|
304
360
|
};
|