@ttoss/appsync-api 0.8.0 → 0.8.2

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/cli.js CHANGED
@@ -25,18 +25,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
25
25
 
26
26
  // src/cli.ts
27
27
  var fs = __toESM(require("fs"));
28
-
29
- // src/createApiTemplate.ts
30
- var import_graphql_compose = require("graphql-compose");
31
- var AppSyncGraphQLSchemaLogicalId = "AppSyncGraphQLSchema";
32
-
33
- // src/cli.ts
34
28
  var import_cloudformation = require("@ttoss/cloudformation");
35
29
  var import_minimist = __toESM(require("minimist"));
36
30
  var argv = (0, import_minimist.default)(process.argv.slice(2));
37
31
  if (argv._.includes("build-schema")) {
38
32
  const template = (0, import_cloudformation.findAndReadCloudFormationTemplate)({});
39
- const sdl = template.Resources[AppSyncGraphQLSchemaLogicalId].Properties.Definition;
33
+ const sdl = template.Metadata.Schema.Definition;
40
34
  fs.mkdirSync("schema", { recursive: true });
41
35
  fs.writeFileSync("schema/schema.graphql", sdl);
42
36
  }
package/dist/esm/cli.js CHANGED
@@ -1,7 +1,4 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- import {
3
- AppSyncGraphQLSchemaLogicalId
4
- } from "./chunk-Y27A2LBZ.js";
5
2
 
6
3
  // src/cli.ts
7
4
  import * as fs from "fs";
@@ -10,7 +7,7 @@ import minimist from "minimist";
10
7
  var argv = minimist(process.argv.slice(2));
11
8
  if (argv._.includes("build-schema")) {
12
9
  const template = findAndReadCloudFormationTemplate({});
13
- const sdl = template.Resources[AppSyncGraphQLSchemaLogicalId].Properties.Definition;
10
+ const sdl = template.Metadata.Schema.Definition;
14
11
  fs.mkdirSync("schema", { recursive: true });
15
12
  fs.writeFileSync("schema/schema.graphql", sdl);
16
13
  }
package/dist/esm/index.js CHANGED
@@ -1,7 +1,377 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- import {
3
- createApiTemplate
4
- } from "./chunk-Y27A2LBZ.js";
2
+
3
+ // src/createApiTemplate.ts
4
+ import { graphql } from "graphql-compose";
5
+
6
+ // ../../node_modules/tslib/tslib.es6.js
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)
12
+ if (Object.prototype.hasOwnProperty.call(s, p))
13
+ t[p] = s[p];
14
+ }
15
+ return t;
16
+ };
17
+ return __assign.apply(this, arguments);
18
+ };
19
+
20
+ // ../../node_modules/lower-case/dist.es2015/index.js
21
+ function lowerCase(str) {
22
+ return str.toLowerCase();
23
+ }
24
+
25
+ // ../../node_modules/no-case/dist.es2015/index.js
26
+ var DEFAULT_SPLIT_REGEXP = [/([a-z0-9])([A-Z])/g, /([A-Z])([A-Z][a-z])/g];
27
+ var DEFAULT_STRIP_REGEXP = /[^A-Z0-9]+/gi;
28
+ function noCase(input, options) {
29
+ if (options === void 0) {
30
+ options = {};
31
+ }
32
+ var _a = options.splitRegexp, splitRegexp = _a === void 0 ? DEFAULT_SPLIT_REGEXP : _a, _b = options.stripRegexp, stripRegexp = _b === void 0 ? DEFAULT_STRIP_REGEXP : _b, _c = options.transform, transform = _c === void 0 ? lowerCase : _c, _d = options.delimiter, delimiter = _d === void 0 ? " " : _d;
33
+ var result = replace(replace(input, splitRegexp, "$1\0$2"), stripRegexp, "\0");
34
+ var start = 0;
35
+ var end = result.length;
36
+ while (result.charAt(start) === "\0")
37
+ start++;
38
+ while (result.charAt(end - 1) === "\0")
39
+ end--;
40
+ return result.slice(start, end).split("\0").map(transform).join(delimiter);
41
+ }
42
+ function replace(input, re, value) {
43
+ if (re instanceof RegExp)
44
+ return input.replace(re, value);
45
+ return re.reduce(function(input2, re2) {
46
+ return input2.replace(re2, value);
47
+ }, input);
48
+ }
49
+
50
+ // ../../node_modules/pascal-case/dist.es2015/index.js
51
+ function pascalCaseTransform(input, index) {
52
+ var firstChar = input.charAt(0);
53
+ var lowerChars = input.substr(1).toLowerCase();
54
+ if (index > 0 && firstChar >= "0" && firstChar <= "9") {
55
+ return "_" + firstChar + lowerChars;
56
+ }
57
+ return "" + firstChar.toUpperCase() + lowerChars;
58
+ }
59
+ function pascalCase(input, options) {
60
+ if (options === void 0) {
61
+ options = {};
62
+ }
63
+ return noCase(input, __assign({ delimiter: "", transform: pascalCaseTransform }, options));
64
+ }
65
+
66
+ // ../carlin/src/deploy/lambdaLayer/getPackageLambdaLayerStackName.ts
67
+ var lambdaLayerStackNamePrefix = `LambdaLayer`;
68
+ var getPackageLambdaLayerStackName = (packageName) => {
69
+ const [scopedName, version] = packageName.split("@").filter((part) => {
70
+ return !!part;
71
+ });
72
+ return [
73
+ lambdaLayerStackNamePrefix,
74
+ pascalCase(scopedName),
75
+ version.replace(/[^0-9.]/g, "").replace(/\./g, "-")
76
+ ].join("-");
77
+ };
78
+
79
+ // package.json
80
+ var package_default = {
81
+ name: "@ttoss/appsync-api",
82
+ version: "0.8.2",
83
+ description: "A library for building GraphQL APIs for AWS AppSync.",
84
+ license: "UNLICENSED",
85
+ author: "ttoss",
86
+ contributors: [
87
+ "Pedro Arantes <pedro@arantespp.com> (https://arantespp.com)"
88
+ ],
89
+ exports: {
90
+ ".": {
91
+ import: "./dist/esm/index.js",
92
+ require: "./dist/index.js"
93
+ },
94
+ "./server": {
95
+ import: "./dist/esm/server.js",
96
+ require: "./dist/server.js"
97
+ }
98
+ },
99
+ main: "dist/index.js",
100
+ module: "dist/esm/index.js",
101
+ bin: {
102
+ "ttoss-appsync-api": "./bin/cli.js"
103
+ },
104
+ files: [
105
+ "dist",
106
+ "src"
107
+ ],
108
+ scripts: {
109
+ build: "tsup",
110
+ test: "jest"
111
+ },
112
+ sideEffects: false,
113
+ typings: "dist/index.d.ts",
114
+ dependencies: {
115
+ "@ttoss/cloudformation": "^0.5.2",
116
+ express: "^4.18.2",
117
+ "graphql-compose-connection": "^8.2.1",
118
+ "graphql-helix": "^1.13.0",
119
+ minimist: "^1.2.8"
120
+ },
121
+ peerDependencies: {
122
+ graphql: "^16.6.0",
123
+ "graphql-compose": "^9.0.10"
124
+ },
125
+ devDependencies: {
126
+ "@ttoss/config": "^1.28.1",
127
+ "@types/aws-lambda": "^8.10.110",
128
+ carlin: "^1.23.3",
129
+ graphql: "^16.6.0",
130
+ "graphql-compose": "^9.0.10"
131
+ },
132
+ keywords: [
133
+ "api",
134
+ "appsync",
135
+ "aws",
136
+ "graphql"
137
+ ],
138
+ publishConfig: {
139
+ access: "public"
140
+ },
141
+ typesVersions: {
142
+ "*": {
143
+ ".": [
144
+ "./dist/index.d.ts"
145
+ ],
146
+ server: [
147
+ "./dist/server.d.ts"
148
+ ]
149
+ }
150
+ }
151
+ };
152
+
153
+ // src/createApiTemplate.ts
154
+ var AppSyncGraphQLApiLogicalId = "AppSyncGraphQLApi";
155
+ var AppSyncGraphQLSchemaLogicalId = "AppSyncGraphQLSchema";
156
+ var AppSyncLambdaFunctionLogicalId = "AppSyncLambdaFunction";
157
+ var AppSyncLambdaFunctionAppSyncDataSourceLogicalId = "AppSyncLambdaFunctionAppSyncDataSource";
158
+ var AppSyncGraphQLApiKeyLogicalId = "AppSyncGraphQLApiKey";
159
+ var createApiTemplate = ({
160
+ additionalAuthenticationProviders,
161
+ authenticationType = "AMAZON_COGNITO_USER_POOLS",
162
+ schemaComposer: schemaComposer2,
163
+ dataSource,
164
+ lambdaFunction,
165
+ userPoolConfig
166
+ }) => {
167
+ const sdlWithoutComments = schemaComposer2.toSDL({
168
+ commentDescriptions: false,
169
+ omitDescriptions: true,
170
+ omitScalars: true
171
+ });
172
+ const sdlWithComments = schemaComposer2.toSDL({
173
+ omitScalars: true
174
+ });
175
+ graphql.validateSchema(schemaComposer2.buildSchema());
176
+ const resolveMethods = schemaComposer2.getResolveMethods();
177
+ const resolveMethodsEntries = Object.entries(resolveMethods).flatMap(([typeName, fieldResolvers]) => {
178
+ return Object.entries(fieldResolvers).map(([fieldName, resolver]) => {
179
+ if (typeof resolver !== "function") {
180
+ return void 0;
181
+ }
182
+ if (typeName.toLowerCase().includes("enum")) {
183
+ return void 0;
184
+ }
185
+ return {
186
+ fieldName,
187
+ typeName
188
+ };
189
+ });
190
+ }).filter(Boolean);
191
+ const getGraphQLComposeDependenciesLambdaLayers = () => {
192
+ const { peerDependencies } = package_default;
193
+ const lambdaLayerStackNames = Object.entries(peerDependencies).map(
194
+ ([dependencyName, dependencyVersion]) => {
195
+ return getPackageLambdaLayerStackName(
196
+ [dependencyName, dependencyVersion].join("@")
197
+ );
198
+ }
199
+ );
200
+ return lambdaLayerStackNames.map((lambdaLayerStackName) => {
201
+ return {
202
+ "Fn::ImportValue": lambdaLayerStackName
203
+ };
204
+ });
205
+ };
206
+ const template = {
207
+ AWSTemplateFormatVersion: "2010-09-09",
208
+ /**
209
+ * This is a workaround to use with build script.
210
+ */
211
+ Metadata: {
212
+ Schema: {
213
+ Definition: sdlWithComments
214
+ }
215
+ },
216
+ Parameters: {
217
+ Environment: {
218
+ Default: "Staging",
219
+ Type: "String",
220
+ AllowedValues: ["Staging", "Production"]
221
+ },
222
+ LambdaS3Bucket: {
223
+ Type: "String"
224
+ },
225
+ LambdaS3Key: {
226
+ Type: "String"
227
+ },
228
+ LambdaS3ObjectVersion: {
229
+ Type: "String"
230
+ }
231
+ },
232
+ Resources: {
233
+ [AppSyncGraphQLApiLogicalId]: {
234
+ Type: "AWS::AppSync::GraphQLApi",
235
+ Properties: {
236
+ AuthenticationType: authenticationType,
237
+ Name: {
238
+ "Fn::Join": [
239
+ ":",
240
+ [{ Ref: "AWS::StackName" }, AppSyncGraphQLApiLogicalId]
241
+ ]
242
+ }
243
+ }
244
+ },
245
+ [AppSyncGraphQLSchemaLogicalId]: {
246
+ Type: "AWS::AppSync::GraphQLSchema",
247
+ Properties: {
248
+ ApiId: { "Fn::GetAtt": [AppSyncGraphQLApiLogicalId, "ApiId"] },
249
+ Definition: sdlWithoutComments
250
+ }
251
+ },
252
+ [AppSyncLambdaFunctionLogicalId]: {
253
+ Type: "AWS::Lambda::Function",
254
+ Properties: {
255
+ Code: {
256
+ S3Bucket: { Ref: "LambdaS3Bucket" },
257
+ S3Key: { Ref: "LambdaS3Key" },
258
+ S3ObjectVersion: { Ref: "LambdaS3ObjectVersion" }
259
+ },
260
+ Handler: "index.handler",
261
+ Layers: getGraphQLComposeDependenciesLambdaLayers(),
262
+ MemorySize: 512,
263
+ Role: lambdaFunction.roleArn,
264
+ Runtime: "nodejs18.x",
265
+ /**
266
+ * https://docs.aws.amazon.com/general/latest/gr/appsync.html
267
+ * Request execution time for mutations, queries, and subscriptions: 30 seconds
268
+ */
269
+ Timeout: 29
270
+ }
271
+ },
272
+ [AppSyncLambdaFunctionAppSyncDataSourceLogicalId]: {
273
+ Type: "AWS::AppSync::DataSource",
274
+ Properties: {
275
+ ApiId: { "Fn::GetAtt": [AppSyncGraphQLApiLogicalId, "ApiId"] },
276
+ LambdaConfig: {
277
+ LambdaFunctionArn: {
278
+ "Fn::GetAtt": [AppSyncLambdaFunctionLogicalId, "Arn"]
279
+ }
280
+ },
281
+ Name: "AppSyncLambdaFunctionAppSyncDataSource",
282
+ ServiceRoleArn: dataSource.roleArn,
283
+ Type: "AWS_LAMBDA"
284
+ }
285
+ }
286
+ },
287
+ Outputs: {
288
+ AppSyncApiGraphQLUrl: {
289
+ Export: {
290
+ Name: {
291
+ "Fn::Join": [
292
+ ":",
293
+ [{ Ref: "AWS::StackName" }, "AppSyncApiGraphQLUrl"]
294
+ ]
295
+ }
296
+ },
297
+ Value: {
298
+ "Fn::GetAtt": [AppSyncGraphQLApiLogicalId, "GraphQLUrl"]
299
+ }
300
+ },
301
+ AppSyncApiArn: {
302
+ Export: {
303
+ Name: {
304
+ "Fn::Join": [":", [{ Ref: "AWS::StackName" }, "AppSyncApiArn"]]
305
+ }
306
+ },
307
+ Value: {
308
+ "Fn::GetAtt": [AppSyncGraphQLApiLogicalId, "Arn"]
309
+ }
310
+ }
311
+ }
312
+ };
313
+ resolveMethodsEntries.forEach(({ fieldName, typeName }) => {
314
+ template.Resources[`${fieldName}${typeName}AppSyncResolver`] = {
315
+ Type: "AWS::AppSync::Resolver",
316
+ DependsOn: AppSyncGraphQLSchemaLogicalId,
317
+ Properties: {
318
+ ApiId: { "Fn::GetAtt": [AppSyncGraphQLApiLogicalId, "ApiId"] },
319
+ FieldName: fieldName,
320
+ TypeName: typeName,
321
+ DataSourceName: {
322
+ "Fn::GetAtt": [
323
+ AppSyncLambdaFunctionAppSyncDataSourceLogicalId,
324
+ "Name"
325
+ ]
326
+ }
327
+ }
328
+ };
329
+ });
330
+ const apiKey = additionalAuthenticationProviders?.includes("API_KEY") || authenticationType === "API_KEY";
331
+ const cognitoUserPoolAuth = additionalAuthenticationProviders?.includes("AMAZON_COGNITO_USER_POOLS") || authenticationType === "AMAZON_COGNITO_USER_POOLS";
332
+ if (additionalAuthenticationProviders) {
333
+ template.Resources[AppSyncGraphQLApiLogicalId].Properties.AdditionalAuthenticationProviders = additionalAuthenticationProviders?.map((provider) => {
334
+ return {
335
+ AuthenticationType: provider
336
+ };
337
+ });
338
+ }
339
+ if (apiKey) {
340
+ template.Resources[AppSyncGraphQLApiKeyLogicalId] = {
341
+ Type: "AWS::AppSync::ApiKey",
342
+ Properties: {
343
+ ApiId: { "Fn::GetAtt": [AppSyncGraphQLApiLogicalId, "ApiId"] }
344
+ }
345
+ };
346
+ if (!template.Outputs) {
347
+ template.Outputs = {};
348
+ }
349
+ template.Outputs[AppSyncGraphQLApiKeyLogicalId] = {
350
+ Value: {
351
+ "Fn::GetAtt": [AppSyncGraphQLApiKeyLogicalId, "ApiKey"]
352
+ }
353
+ };
354
+ }
355
+ if (cognitoUserPoolAuth) {
356
+ if (!userPoolConfig) {
357
+ throw new Error(
358
+ "userPoolConfig is required when using AMAZON_COGNITO_USER_POOLS authentication."
359
+ );
360
+ }
361
+ template.Resources[AppSyncGraphQLApiLogicalId].Properties.UserPoolConfig = {
362
+ AppIdClientRegex: userPoolConfig.appIdClientRegex,
363
+ AwsRegion: userPoolConfig.awsRegion,
364
+ DefaultAction: userPoolConfig.defaultAction,
365
+ UserPoolId: userPoolConfig.userPoolId
366
+ };
367
+ }
368
+ if (lambdaFunction.environment?.variables) {
369
+ template.Resources[AppSyncLambdaFunctionLogicalId].Properties.Environment = {
370
+ Variables: lambdaFunction.environment.variables
371
+ };
372
+ }
373
+ return template;
374
+ };
5
375
 
6
376
  // src/createAppSyncResolverHandler.ts
7
377
  var createAppSyncResolverHandler = ({
@@ -10,7 +380,8 @@ var createAppSyncResolverHandler = ({
10
380
  return async (event, context) => {
11
381
  const { info, arguments: args, source } = event;
12
382
  const { parentTypeName, fieldName } = info;
13
- const resolver = schemaComposer2.getResolveMethods()[parentTypeName][fieldName];
383
+ const resolveMethods = schemaComposer2.getResolveMethods();
384
+ const resolver = resolveMethods[parentTypeName][fieldName];
14
385
  return resolver(
15
386
  source,
16
387
  args,
package/dist/index.d.ts CHANGED
@@ -1,9 +1,81 @@
1
1
  import { SchemaComposer, ObjectTypeComposer } from 'graphql-compose';
2
- import { CloudFormationTemplate } from '@ttoss/cloudformation';
3
2
  import { AppSyncResolverHandler as AppSyncResolverHandler$1 } from 'aws-lambda';
4
3
  export { AppSyncIdentityCognito } from 'aws-lambda';
5
4
  export { default as composeWithConnection } from 'graphql-compose-connection';
6
5
 
6
+ type Parameter = {
7
+ AllowedValues?: string[];
8
+ Default?: string | number;
9
+ Description?: string;
10
+ Type: string;
11
+ NoEcho?: boolean;
12
+ };
13
+ type Parameters = {
14
+ [key: string]: Parameter;
15
+ };
16
+ type Resource = {
17
+ Type: string;
18
+ DeletionPolicy?: 'Delete' | 'Retain';
19
+ Description?: string;
20
+ DependsOn?: string[] | string;
21
+ Condition?: string;
22
+ Properties: any;
23
+ };
24
+ type IAMRoleResource = Resource & {
25
+ Type: 'AWS::IAM::Role';
26
+ Properties: {
27
+ AssumeRolePolicyDocument: {
28
+ Version: '2012-10-17';
29
+ Statement: {
30
+ Effect: 'Allow' | 'Deny';
31
+ Action: string;
32
+ Principal: any;
33
+ }[];
34
+ };
35
+ ManagedPolicyArns?: string[];
36
+ Path?: string;
37
+ Policies?: {
38
+ PolicyName: string;
39
+ PolicyDocument: {
40
+ Version: '2012-10-17';
41
+ Statement: {
42
+ Effect: 'Allow' | 'Deny';
43
+ Action: string | string[];
44
+ Resource: string | string[] | {
45
+ [key: string]: string;
46
+ } | {
47
+ [key: string]: string;
48
+ }[];
49
+ }[];
50
+ };
51
+ }[];
52
+ };
53
+ };
54
+ type Resources = {
55
+ [key: string]: IAMRoleResource | Resource;
56
+ };
57
+ type Output = {
58
+ Description?: string;
59
+ Value: string | any;
60
+ Export?: {
61
+ Name: string | any;
62
+ };
63
+ };
64
+ type Outputs = {
65
+ [key: string]: Output;
66
+ };
67
+ type CloudFormationTemplate = {
68
+ AWSTemplateFormatVersion: '2010-09-09';
69
+ Metadata?: any;
70
+ Description?: string;
71
+ Transform?: 'AWS::Serverless-2016-10-31';
72
+ Mappings?: any;
73
+ Conditions?: any;
74
+ Parameters?: Parameters;
75
+ Resources: Resources;
76
+ Outputs?: Outputs;
77
+ };
78
+
7
79
  type StringOrImport = string | {
8
80
  'Fn::ImportValue': string;
9
81
  };
package/dist/index.js CHANGED
@@ -119,7 +119,7 @@ var getPackageLambdaLayerStackName = (packageName) => {
119
119
  // package.json
120
120
  var package_default = {
121
121
  name: "@ttoss/appsync-api",
122
- version: "0.8.0",
122
+ version: "0.8.2",
123
123
  description: "A library for building GraphQL APIs for AWS AppSync.",
124
124
  license: "UNLICENSED",
125
125
  author: "ttoss",
@@ -152,7 +152,7 @@ var package_default = {
152
152
  sideEffects: false,
153
153
  typings: "dist/index.d.ts",
154
154
  dependencies: {
155
- "@ttoss/cloudformation": "^0.5.1",
155
+ "@ttoss/cloudformation": "^0.5.2",
156
156
  express: "^4.18.2",
157
157
  "graphql-compose-connection": "^8.2.1",
158
158
  "graphql-helix": "^1.13.0",
@@ -165,7 +165,7 @@ var package_default = {
165
165
  devDependencies: {
166
166
  "@ttoss/config": "^1.28.1",
167
167
  "@types/aws-lambda": "^8.10.110",
168
- carlin: "^1.23.2",
168
+ carlin: "^1.23.3",
169
169
  graphql: "^16.6.0",
170
170
  "graphql-compose": "^9.0.10"
171
171
  },
@@ -204,19 +204,30 @@ var createApiTemplate = ({
204
204
  lambdaFunction,
205
205
  userPoolConfig
206
206
  }) => {
207
- const sdl = schemaComposer2.toSDL();
207
+ const sdlWithoutComments = schemaComposer2.toSDL({
208
+ commentDescriptions: false,
209
+ omitDescriptions: true,
210
+ omitScalars: true
211
+ });
212
+ const sdlWithComments = schemaComposer2.toSDL({
213
+ omitScalars: true
214
+ });
208
215
  import_graphql_compose.graphql.validateSchema(schemaComposer2.buildSchema());
209
216
  const resolveMethods = schemaComposer2.getResolveMethods();
210
- const resolveMethodsEntries = Object.entries(resolveMethods).flatMap(
211
- ([typeName, fieldResolvers]) => {
212
- return Object.entries(fieldResolvers).map(([fieldName]) => {
213
- return {
214
- fieldName,
215
- typeName
216
- };
217
- });
218
- }
219
- );
217
+ const resolveMethodsEntries = Object.entries(resolveMethods).flatMap(([typeName, fieldResolvers]) => {
218
+ return Object.entries(fieldResolvers).map(([fieldName, resolver]) => {
219
+ if (typeof resolver !== "function") {
220
+ return void 0;
221
+ }
222
+ if (typeName.toLowerCase().includes("enum")) {
223
+ return void 0;
224
+ }
225
+ return {
226
+ fieldName,
227
+ typeName
228
+ };
229
+ });
230
+ }).filter(Boolean);
220
231
  const getGraphQLComposeDependenciesLambdaLayers = () => {
221
232
  const { peerDependencies } = package_default;
222
233
  const lambdaLayerStackNames = Object.entries(peerDependencies).map(
@@ -234,6 +245,14 @@ var createApiTemplate = ({
234
245
  };
235
246
  const template = {
236
247
  AWSTemplateFormatVersion: "2010-09-09",
248
+ /**
249
+ * This is a workaround to use with build script.
250
+ */
251
+ Metadata: {
252
+ Schema: {
253
+ Definition: sdlWithComments
254
+ }
255
+ },
237
256
  Parameters: {
238
257
  Environment: {
239
258
  Default: "Staging",
@@ -267,7 +286,7 @@ var createApiTemplate = ({
267
286
  Type: "AWS::AppSync::GraphQLSchema",
268
287
  Properties: {
269
288
  ApiId: { "Fn::GetAtt": [AppSyncGraphQLApiLogicalId, "ApiId"] },
270
- Definition: sdl
289
+ Definition: sdlWithoutComments
271
290
  }
272
291
  },
273
292
  [AppSyncLambdaFunctionLogicalId]: {
@@ -401,7 +420,8 @@ var createAppSyncResolverHandler = ({
401
420
  return async (event, context) => {
402
421
  const { info, arguments: args, source } = event;
403
422
  const { parentTypeName, fieldName } = info;
404
- const resolver = schemaComposer2.getResolveMethods()[parentTypeName][fieldName];
423
+ const resolveMethods = schemaComposer2.getResolveMethods();
424
+ const resolver = resolveMethods[parentTypeName][fieldName];
405
425
  return resolver(
406
426
  source,
407
427
  args,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/appsync-api",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
4
4
  "description": "A library for building GraphQL APIs for AWS AppSync.",
5
5
  "license": "UNLICENSED",
6
6
  "author": "ttoss",
@@ -33,7 +33,7 @@
33
33
  "sideEffects": false,
34
34
  "typings": "dist/index.d.ts",
35
35
  "dependencies": {
36
- "@ttoss/cloudformation": "^0.5.1",
36
+ "@ttoss/cloudformation": "^0.5.2",
37
37
  "express": "^4.18.2",
38
38
  "graphql-compose-connection": "^8.2.1",
39
39
  "graphql-helix": "^1.13.0",
@@ -46,7 +46,7 @@
46
46
  "devDependencies": {
47
47
  "@ttoss/config": "^1.28.1",
48
48
  "@types/aws-lambda": "^8.10.110",
49
- "carlin": "^1.23.2",
49
+ "carlin": "^1.23.3",
50
50
  "graphql": "^16.6.0",
51
51
  "graphql-compose": "^9.0.10"
52
52
  },
@@ -69,5 +69,5 @@
69
69
  ]
70
70
  }
71
71
  },
72
- "gitHead": "84ebce1283e142519776d7045c484269d3dbabe4"
72
+ "gitHead": "01f9bfea6d10cb472b5bf024e3bbacb6fd7cd25c"
73
73
  }
package/src/cli.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import * as fs from 'fs';
2
- import { AppSyncGraphQLSchemaLogicalId } from './createApiTemplate';
3
2
  import { findAndReadCloudFormationTemplate } from '@ttoss/cloudformation';
4
3
  import minimist from 'minimist';
5
4
 
@@ -8,8 +7,7 @@ const argv = minimist(process.argv.slice(2));
8
7
  if (argv._.includes('build-schema')) {
9
8
  const template = findAndReadCloudFormationTemplate({});
10
9
 
11
- const sdl =
12
- template.Resources[AppSyncGraphQLSchemaLogicalId].Properties.Definition;
10
+ const sdl = template.Metadata.Schema.Definition;
13
11
 
14
12
  /**
15
13
  * Save to schema/schema.graphql. schema folder might not exist.
@@ -1,7 +1,14 @@
1
1
  import { type SchemaComposer, graphql } from 'graphql-compose';
2
2
  import { getPackageLambdaLayerStackName } from 'carlin/src/deploy/lambdaLayer/getPackageLambdaLayerStackName';
3
3
  import packageJson from '../package.json';
4
- import type { CloudFormationTemplate } from '@ttoss/cloudformation';
4
+
5
+ /**
6
+ * Absolute path to avoid:
7
+ * The inferred type of 'template' cannot be named without a reference to
8
+ * '@ttoss/appsync-api/node_modules/@ttoss/cloudformation'. This is likely not
9
+ * portable. A type annotation is necessary.ts(2742)
10
+ */
11
+ import type { CloudFormationTemplate } from '../../cloudformation/src/';
5
12
 
6
13
  export const AppSyncGraphQLApiLogicalId = 'AppSyncGraphQLApi';
7
14
 
@@ -53,7 +60,15 @@ export const createApiTemplate = ({
53
60
  * It should be on top of the file, otherwise it will have empty Mutation
54
61
  * or Subscription if there are no resolvers for them.
55
62
  */
56
- const sdl = schemaComposer.toSDL();
63
+ const sdlWithoutComments = schemaComposer.toSDL({
64
+ commentDescriptions: false,
65
+ omitDescriptions: true,
66
+ omitScalars: true,
67
+ });
68
+
69
+ const sdlWithComments = schemaComposer.toSDL({
70
+ omitScalars: true,
71
+ });
57
72
 
58
73
  graphql.validateSchema(schemaComposer.buildSchema());
59
74
 
@@ -63,16 +78,24 @@ export const createApiTemplate = ({
63
78
  */
64
79
  const resolveMethods = schemaComposer.getResolveMethods();
65
80
 
66
- const resolveMethodsEntries = Object.entries(resolveMethods).flatMap(
67
- ([typeName, fieldResolvers]) => {
68
- return Object.entries(fieldResolvers).map(([fieldName]) => {
81
+ const resolveMethodsEntries = Object.entries(resolveMethods)
82
+ .flatMap(([typeName, fieldResolvers]) => {
83
+ return Object.entries(fieldResolvers).map(([fieldName, resolver]) => {
84
+ if (typeof resolver !== 'function') {
85
+ return undefined;
86
+ }
87
+
88
+ if (typeName.toLowerCase().includes('enum')) {
89
+ return undefined;
90
+ }
91
+
69
92
  return {
70
93
  fieldName,
71
94
  typeName,
72
95
  };
73
96
  });
74
- }
75
- );
97
+ })
98
+ .filter(Boolean) as Array<{ fieldName: string; typeName: string }>;
76
99
 
77
100
  const getGraphQLComposeDependenciesLambdaLayers = () => {
78
101
  const { peerDependencies } = packageJson;
@@ -94,6 +117,14 @@ export const createApiTemplate = ({
94
117
 
95
118
  const template: CloudFormationTemplate = {
96
119
  AWSTemplateFormatVersion: '2010-09-09',
120
+ /**
121
+ * This is a workaround to use with build script.
122
+ */
123
+ Metadata: {
124
+ Schema: {
125
+ Definition: sdlWithComments,
126
+ },
127
+ },
97
128
  Parameters: {
98
129
  Environment: {
99
130
  Default: 'Staging',
@@ -127,7 +158,7 @@ export const createApiTemplate = ({
127
158
  Type: 'AWS::AppSync::GraphQLSchema',
128
159
  Properties: {
129
160
  ApiId: { 'Fn::GetAtt': [AppSyncGraphQLApiLogicalId, 'ApiId'] },
130
- Definition: sdl,
161
+ Definition: sdlWithoutComments,
131
162
  },
132
163
  },
133
164
  [AppSyncLambdaFunctionLogicalId]: {
@@ -15,9 +15,8 @@ export const createAppSyncResolverHandler = ({
15
15
  return async (event, context) => {
16
16
  const { info, arguments: args, source } = event;
17
17
  const { parentTypeName, fieldName } = info;
18
- const resolver = (
19
- schemaComposer.getResolveMethods()[parentTypeName] as any
20
- )[fieldName];
18
+ const resolveMethods = schemaComposer.getResolveMethods();
19
+ const resolver = (resolveMethods[parentTypeName] as any)[fieldName];
21
20
  return resolver(
22
21
  source,
23
22
  args,
@@ -1,360 +0,0 @@
1
- /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
-
3
- // src/createApiTemplate.ts
4
- import { graphql } from "graphql-compose";
5
-
6
- // ../../node_modules/tslib/tslib.es6.js
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)
12
- if (Object.prototype.hasOwnProperty.call(s, p))
13
- t[p] = s[p];
14
- }
15
- return t;
16
- };
17
- return __assign.apply(this, arguments);
18
- };
19
-
20
- // ../../node_modules/lower-case/dist.es2015/index.js
21
- function lowerCase(str) {
22
- return str.toLowerCase();
23
- }
24
-
25
- // ../../node_modules/no-case/dist.es2015/index.js
26
- var DEFAULT_SPLIT_REGEXP = [/([a-z0-9])([A-Z])/g, /([A-Z])([A-Z][a-z])/g];
27
- var DEFAULT_STRIP_REGEXP = /[^A-Z0-9]+/gi;
28
- function noCase(input, options) {
29
- if (options === void 0) {
30
- options = {};
31
- }
32
- var _a = options.splitRegexp, splitRegexp = _a === void 0 ? DEFAULT_SPLIT_REGEXP : _a, _b = options.stripRegexp, stripRegexp = _b === void 0 ? DEFAULT_STRIP_REGEXP : _b, _c = options.transform, transform = _c === void 0 ? lowerCase : _c, _d = options.delimiter, delimiter = _d === void 0 ? " " : _d;
33
- var result = replace(replace(input, splitRegexp, "$1\0$2"), stripRegexp, "\0");
34
- var start = 0;
35
- var end = result.length;
36
- while (result.charAt(start) === "\0")
37
- start++;
38
- while (result.charAt(end - 1) === "\0")
39
- end--;
40
- return result.slice(start, end).split("\0").map(transform).join(delimiter);
41
- }
42
- function replace(input, re, value) {
43
- if (re instanceof RegExp)
44
- return input.replace(re, value);
45
- return re.reduce(function(input2, re2) {
46
- return input2.replace(re2, value);
47
- }, input);
48
- }
49
-
50
- // ../../node_modules/pascal-case/dist.es2015/index.js
51
- function pascalCaseTransform(input, index) {
52
- var firstChar = input.charAt(0);
53
- var lowerChars = input.substr(1).toLowerCase();
54
- if (index > 0 && firstChar >= "0" && firstChar <= "9") {
55
- return "_" + firstChar + lowerChars;
56
- }
57
- return "" + firstChar.toUpperCase() + lowerChars;
58
- }
59
- function pascalCase(input, options) {
60
- if (options === void 0) {
61
- options = {};
62
- }
63
- return noCase(input, __assign({ delimiter: "", transform: pascalCaseTransform }, options));
64
- }
65
-
66
- // ../carlin/src/deploy/lambdaLayer/getPackageLambdaLayerStackName.ts
67
- var lambdaLayerStackNamePrefix = `LambdaLayer`;
68
- var getPackageLambdaLayerStackName = (packageName) => {
69
- const [scopedName, version] = packageName.split("@").filter((part) => {
70
- return !!part;
71
- });
72
- return [
73
- lambdaLayerStackNamePrefix,
74
- pascalCase(scopedName),
75
- version.replace(/[^0-9.]/g, "").replace(/\./g, "-")
76
- ].join("-");
77
- };
78
-
79
- // package.json
80
- var package_default = {
81
- name: "@ttoss/appsync-api",
82
- version: "0.8.0",
83
- description: "A library for building GraphQL APIs for AWS AppSync.",
84
- license: "UNLICENSED",
85
- author: "ttoss",
86
- contributors: [
87
- "Pedro Arantes <pedro@arantespp.com> (https://arantespp.com)"
88
- ],
89
- exports: {
90
- ".": {
91
- import: "./dist/esm/index.js",
92
- require: "./dist/index.js"
93
- },
94
- "./server": {
95
- import: "./dist/esm/server.js",
96
- require: "./dist/server.js"
97
- }
98
- },
99
- main: "dist/index.js",
100
- module: "dist/esm/index.js",
101
- bin: {
102
- "ttoss-appsync-api": "./bin/cli.js"
103
- },
104
- files: [
105
- "dist",
106
- "src"
107
- ],
108
- scripts: {
109
- build: "tsup",
110
- test: "jest"
111
- },
112
- sideEffects: false,
113
- typings: "dist/index.d.ts",
114
- dependencies: {
115
- "@ttoss/cloudformation": "^0.5.1",
116
- express: "^4.18.2",
117
- "graphql-compose-connection": "^8.2.1",
118
- "graphql-helix": "^1.13.0",
119
- minimist: "^1.2.8"
120
- },
121
- peerDependencies: {
122
- graphql: "^16.6.0",
123
- "graphql-compose": "^9.0.10"
124
- },
125
- devDependencies: {
126
- "@ttoss/config": "^1.28.1",
127
- "@types/aws-lambda": "^8.10.110",
128
- carlin: "^1.23.2",
129
- graphql: "^16.6.0",
130
- "graphql-compose": "^9.0.10"
131
- },
132
- keywords: [
133
- "api",
134
- "appsync",
135
- "aws",
136
- "graphql"
137
- ],
138
- publishConfig: {
139
- access: "public"
140
- },
141
- typesVersions: {
142
- "*": {
143
- ".": [
144
- "./dist/index.d.ts"
145
- ],
146
- server: [
147
- "./dist/server.d.ts"
148
- ]
149
- }
150
- }
151
- };
152
-
153
- // src/createApiTemplate.ts
154
- var AppSyncGraphQLApiLogicalId = "AppSyncGraphQLApi";
155
- var AppSyncGraphQLSchemaLogicalId = "AppSyncGraphQLSchema";
156
- var AppSyncLambdaFunctionLogicalId = "AppSyncLambdaFunction";
157
- var AppSyncLambdaFunctionAppSyncDataSourceLogicalId = "AppSyncLambdaFunctionAppSyncDataSource";
158
- var AppSyncGraphQLApiKeyLogicalId = "AppSyncGraphQLApiKey";
159
- var createApiTemplate = ({
160
- additionalAuthenticationProviders,
161
- authenticationType = "AMAZON_COGNITO_USER_POOLS",
162
- schemaComposer,
163
- dataSource,
164
- lambdaFunction,
165
- userPoolConfig
166
- }) => {
167
- const sdl = schemaComposer.toSDL();
168
- graphql.validateSchema(schemaComposer.buildSchema());
169
- const resolveMethods = schemaComposer.getResolveMethods();
170
- const resolveMethodsEntries = Object.entries(resolveMethods).flatMap(
171
- ([typeName, fieldResolvers]) => {
172
- return Object.entries(fieldResolvers).map(([fieldName]) => {
173
- return {
174
- fieldName,
175
- typeName
176
- };
177
- });
178
- }
179
- );
180
- const getGraphQLComposeDependenciesLambdaLayers = () => {
181
- const { peerDependencies } = package_default;
182
- const lambdaLayerStackNames = Object.entries(peerDependencies).map(
183
- ([dependencyName, dependencyVersion]) => {
184
- return getPackageLambdaLayerStackName(
185
- [dependencyName, dependencyVersion].join("@")
186
- );
187
- }
188
- );
189
- return lambdaLayerStackNames.map((lambdaLayerStackName) => {
190
- return {
191
- "Fn::ImportValue": lambdaLayerStackName
192
- };
193
- });
194
- };
195
- const template = {
196
- AWSTemplateFormatVersion: "2010-09-09",
197
- Parameters: {
198
- Environment: {
199
- Default: "Staging",
200
- Type: "String",
201
- AllowedValues: ["Staging", "Production"]
202
- },
203
- LambdaS3Bucket: {
204
- Type: "String"
205
- },
206
- LambdaS3Key: {
207
- Type: "String"
208
- },
209
- LambdaS3ObjectVersion: {
210
- Type: "String"
211
- }
212
- },
213
- Resources: {
214
- [AppSyncGraphQLApiLogicalId]: {
215
- Type: "AWS::AppSync::GraphQLApi",
216
- Properties: {
217
- AuthenticationType: authenticationType,
218
- Name: {
219
- "Fn::Join": [
220
- ":",
221
- [{ Ref: "AWS::StackName" }, AppSyncGraphQLApiLogicalId]
222
- ]
223
- }
224
- }
225
- },
226
- [AppSyncGraphQLSchemaLogicalId]: {
227
- Type: "AWS::AppSync::GraphQLSchema",
228
- Properties: {
229
- ApiId: { "Fn::GetAtt": [AppSyncGraphQLApiLogicalId, "ApiId"] },
230
- Definition: sdl
231
- }
232
- },
233
- [AppSyncLambdaFunctionLogicalId]: {
234
- Type: "AWS::Lambda::Function",
235
- Properties: {
236
- Code: {
237
- S3Bucket: { Ref: "LambdaS3Bucket" },
238
- S3Key: { Ref: "LambdaS3Key" },
239
- S3ObjectVersion: { Ref: "LambdaS3ObjectVersion" }
240
- },
241
- Handler: "index.handler",
242
- Layers: getGraphQLComposeDependenciesLambdaLayers(),
243
- MemorySize: 512,
244
- Role: lambdaFunction.roleArn,
245
- Runtime: "nodejs18.x",
246
- /**
247
- * https://docs.aws.amazon.com/general/latest/gr/appsync.html
248
- * Request execution time for mutations, queries, and subscriptions: 30 seconds
249
- */
250
- Timeout: 29
251
- }
252
- },
253
- [AppSyncLambdaFunctionAppSyncDataSourceLogicalId]: {
254
- Type: "AWS::AppSync::DataSource",
255
- Properties: {
256
- ApiId: { "Fn::GetAtt": [AppSyncGraphQLApiLogicalId, "ApiId"] },
257
- LambdaConfig: {
258
- LambdaFunctionArn: {
259
- "Fn::GetAtt": [AppSyncLambdaFunctionLogicalId, "Arn"]
260
- }
261
- },
262
- Name: "AppSyncLambdaFunctionAppSyncDataSource",
263
- ServiceRoleArn: dataSource.roleArn,
264
- Type: "AWS_LAMBDA"
265
- }
266
- }
267
- },
268
- Outputs: {
269
- AppSyncApiGraphQLUrl: {
270
- Export: {
271
- Name: {
272
- "Fn::Join": [
273
- ":",
274
- [{ Ref: "AWS::StackName" }, "AppSyncApiGraphQLUrl"]
275
- ]
276
- }
277
- },
278
- Value: {
279
- "Fn::GetAtt": [AppSyncGraphQLApiLogicalId, "GraphQLUrl"]
280
- }
281
- },
282
- AppSyncApiArn: {
283
- Export: {
284
- Name: {
285
- "Fn::Join": [":", [{ Ref: "AWS::StackName" }, "AppSyncApiArn"]]
286
- }
287
- },
288
- Value: {
289
- "Fn::GetAtt": [AppSyncGraphQLApiLogicalId, "Arn"]
290
- }
291
- }
292
- }
293
- };
294
- resolveMethodsEntries.forEach(({ fieldName, typeName }) => {
295
- template.Resources[`${fieldName}${typeName}AppSyncResolver`] = {
296
- Type: "AWS::AppSync::Resolver",
297
- DependsOn: AppSyncGraphQLSchemaLogicalId,
298
- Properties: {
299
- ApiId: { "Fn::GetAtt": [AppSyncGraphQLApiLogicalId, "ApiId"] },
300
- FieldName: fieldName,
301
- TypeName: typeName,
302
- DataSourceName: {
303
- "Fn::GetAtt": [
304
- AppSyncLambdaFunctionAppSyncDataSourceLogicalId,
305
- "Name"
306
- ]
307
- }
308
- }
309
- };
310
- });
311
- const apiKey = additionalAuthenticationProviders?.includes("API_KEY") || authenticationType === "API_KEY";
312
- const cognitoUserPoolAuth = additionalAuthenticationProviders?.includes("AMAZON_COGNITO_USER_POOLS") || authenticationType === "AMAZON_COGNITO_USER_POOLS";
313
- if (additionalAuthenticationProviders) {
314
- template.Resources[AppSyncGraphQLApiLogicalId].Properties.AdditionalAuthenticationProviders = additionalAuthenticationProviders?.map((provider) => {
315
- return {
316
- AuthenticationType: provider
317
- };
318
- });
319
- }
320
- if (apiKey) {
321
- template.Resources[AppSyncGraphQLApiKeyLogicalId] = {
322
- Type: "AWS::AppSync::ApiKey",
323
- Properties: {
324
- ApiId: { "Fn::GetAtt": [AppSyncGraphQLApiLogicalId, "ApiId"] }
325
- }
326
- };
327
- if (!template.Outputs) {
328
- template.Outputs = {};
329
- }
330
- template.Outputs[AppSyncGraphQLApiKeyLogicalId] = {
331
- Value: {
332
- "Fn::GetAtt": [AppSyncGraphQLApiKeyLogicalId, "ApiKey"]
333
- }
334
- };
335
- }
336
- if (cognitoUserPoolAuth) {
337
- if (!userPoolConfig) {
338
- throw new Error(
339
- "userPoolConfig is required when using AMAZON_COGNITO_USER_POOLS authentication."
340
- );
341
- }
342
- template.Resources[AppSyncGraphQLApiLogicalId].Properties.UserPoolConfig = {
343
- AppIdClientRegex: userPoolConfig.appIdClientRegex,
344
- AwsRegion: userPoolConfig.awsRegion,
345
- DefaultAction: userPoolConfig.defaultAction,
346
- UserPoolId: userPoolConfig.userPoolId
347
- };
348
- }
349
- if (lambdaFunction.environment?.variables) {
350
- template.Resources[AppSyncLambdaFunctionLogicalId].Properties.Environment = {
351
- Variables: lambdaFunction.environment.variables
352
- };
353
- }
354
- return template;
355
- };
356
-
357
- export {
358
- AppSyncGraphQLSchemaLogicalId,
359
- createApiTemplate
360
- };