@ttoss/appsync-api 0.8.1 → 0.8.3

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-RWRQSJ4M.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-RWRQSJ4M.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.3",
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.3",
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.2",
127
+ "@types/aws-lambda": "^8.10.110",
128
+ carlin: "^1.23.4",
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
@@ -3,25 +3,25 @@ import { AppSyncResolverHandler as AppSyncResolverHandler$1 } from 'aws-lambda';
3
3
  export { AppSyncIdentityCognito } from 'aws-lambda';
4
4
  export { default as composeWithConnection } from 'graphql-compose-connection';
5
5
 
6
- interface Parameter {
6
+ type Parameter = {
7
7
  AllowedValues?: string[];
8
8
  Default?: string | number;
9
9
  Description?: string;
10
10
  Type: string;
11
11
  NoEcho?: boolean;
12
- }
12
+ };
13
13
  type Parameters = {
14
14
  [key: string]: Parameter;
15
15
  };
16
- interface Resource {
16
+ type Resource = {
17
17
  Type: string;
18
18
  DeletionPolicy?: 'Delete' | 'Retain';
19
19
  Description?: string;
20
20
  DependsOn?: string[] | string;
21
21
  Condition?: string;
22
22
  Properties: any;
23
- }
24
- interface IAMRoleResource extends Resource {
23
+ };
24
+ type IAMRoleResource = Resource & {
25
25
  Type: 'AWS::IAM::Role';
26
26
  Properties: {
27
27
  AssumeRolePolicyDocument: {
@@ -50,7 +50,7 @@ interface IAMRoleResource extends Resource {
50
50
  };
51
51
  }[];
52
52
  };
53
- }
53
+ };
54
54
  type Resources = {
55
55
  [key: string]: IAMRoleResource | Resource;
56
56
  };
@@ -66,6 +66,7 @@ type Outputs = {
66
66
  };
67
67
  type CloudFormationTemplate = {
68
68
  AWSTemplateFormatVersion: '2010-09-09';
69
+ Metadata?: any;
69
70
  Description?: string;
70
71
  Transform?: 'AWS::Serverless-2016-10-31';
71
72
  Mappings?: any;
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.1",
122
+ version: "0.8.3",
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.3",
156
156
  express: "^4.18.2",
157
157
  "graphql-compose-connection": "^8.2.1",
158
158
  "graphql-helix": "^1.13.0",
@@ -163,9 +163,9 @@ var package_default = {
163
163
  "graphql-compose": "^9.0.10"
164
164
  },
165
165
  devDependencies: {
166
- "@ttoss/config": "^1.28.1",
166
+ "@ttoss/config": "^1.28.2",
167
167
  "@types/aws-lambda": "^8.10.110",
168
- carlin: "^1.23.2",
168
+ carlin: "^1.23.4",
169
169
  graphql: "^16.6.0",
170
170
  "graphql-compose": "^9.0.10"
171
171
  },
@@ -204,23 +204,30 @@ var createApiTemplate = ({
204
204
  lambdaFunction,
205
205
  userPoolConfig
206
206
  }) => {
207
- const sdl = schemaComposer2.toSDL({
207
+ const sdlWithoutComments = schemaComposer2.toSDL({
208
208
  commentDescriptions: false,
209
209
  omitDescriptions: true,
210
210
  omitScalars: true
211
211
  });
212
+ const sdlWithComments = schemaComposer2.toSDL({
213
+ omitScalars: true
214
+ });
212
215
  import_graphql_compose.graphql.validateSchema(schemaComposer2.buildSchema());
213
216
  const resolveMethods = schemaComposer2.getResolveMethods();
214
- const resolveMethodsEntries = Object.entries(resolveMethods).flatMap(
215
- ([typeName, fieldResolvers]) => {
216
- return Object.entries(fieldResolvers).map(([fieldName]) => {
217
- return {
218
- fieldName,
219
- typeName
220
- };
221
- });
222
- }
223
- );
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);
224
231
  const getGraphQLComposeDependenciesLambdaLayers = () => {
225
232
  const { peerDependencies } = package_default;
226
233
  const lambdaLayerStackNames = Object.entries(peerDependencies).map(
@@ -238,6 +245,14 @@ var createApiTemplate = ({
238
245
  };
239
246
  const template = {
240
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
+ },
241
256
  Parameters: {
242
257
  Environment: {
243
258
  Default: "Staging",
@@ -271,7 +286,7 @@ var createApiTemplate = ({
271
286
  Type: "AWS::AppSync::GraphQLSchema",
272
287
  Properties: {
273
288
  ApiId: { "Fn::GetAtt": [AppSyncGraphQLApiLogicalId, "ApiId"] },
274
- Definition: sdl
289
+ Definition: sdlWithoutComments
275
290
  }
276
291
  },
277
292
  [AppSyncLambdaFunctionLogicalId]: {
@@ -405,7 +420,8 @@ var createAppSyncResolverHandler = ({
405
420
  return async (event, context) => {
406
421
  const { info, arguments: args, source } = event;
407
422
  const { parentTypeName, fieldName } = info;
408
- const resolver = schemaComposer2.getResolveMethods()[parentTypeName][fieldName];
423
+ const resolveMethods = schemaComposer2.getResolveMethods();
424
+ const resolver = resolveMethods[parentTypeName][fieldName];
409
425
  return resolver(
410
426
  source,
411
427
  args,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/appsync-api",
3
- "version": "0.8.1",
3
+ "version": "0.8.3",
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.3",
37
37
  "express": "^4.18.2",
38
38
  "graphql-compose-connection": "^8.2.1",
39
39
  "graphql-helix": "^1.13.0",
@@ -44,9 +44,9 @@
44
44
  "graphql-compose": "^9.0.10"
45
45
  },
46
46
  "devDependencies": {
47
- "@ttoss/config": "^1.28.1",
47
+ "@ttoss/config": "^1.28.2",
48
48
  "@types/aws-lambda": "^8.10.110",
49
- "carlin": "^1.23.2",
49
+ "carlin": "^1.23.4",
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": "128418716cbc6dd7d4a41a6925b455b7e4784f9f"
72
+ "gitHead": "8ba4361ab9cf6c0ab275ee771a371d4c2ba8cebe"
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,13 +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
+
4
5
  /**
5
6
  * Absolute path to avoid:
6
7
  * The inferred type of 'template' cannot be named without a reference to
7
8
  * '@ttoss/appsync-api/node_modules/@ttoss/cloudformation'. This is likely not
8
9
  * portable. A type annotation is necessary.ts(2742)
9
10
  */
10
- import type { CloudFormationTemplate } from '../../cloudformation/src';
11
+ import type { CloudFormationTemplate } from '../../cloudformation/src/';
11
12
 
12
13
  export const AppSyncGraphQLApiLogicalId = 'AppSyncGraphQLApi';
13
14
 
@@ -59,12 +60,16 @@ export const createApiTemplate = ({
59
60
  * It should be on top of the file, otherwise it will have empty Mutation
60
61
  * or Subscription if there are no resolvers for them.
61
62
  */
62
- const sdl = schemaComposer.toSDL({
63
+ const sdlWithoutComments = schemaComposer.toSDL({
63
64
  commentDescriptions: false,
64
65
  omitDescriptions: true,
65
66
  omitScalars: true,
66
67
  });
67
68
 
69
+ const sdlWithComments = schemaComposer.toSDL({
70
+ omitScalars: true,
71
+ });
72
+
68
73
  graphql.validateSchema(schemaComposer.buildSchema());
69
74
 
70
75
  /**
@@ -73,16 +78,24 @@ export const createApiTemplate = ({
73
78
  */
74
79
  const resolveMethods = schemaComposer.getResolveMethods();
75
80
 
76
- const resolveMethodsEntries = Object.entries(resolveMethods).flatMap(
77
- ([typeName, fieldResolvers]) => {
78
- 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
+
79
92
  return {
80
93
  fieldName,
81
94
  typeName,
82
95
  };
83
96
  });
84
- }
85
- );
97
+ })
98
+ .filter(Boolean) as Array<{ fieldName: string; typeName: string }>;
86
99
 
87
100
  const getGraphQLComposeDependenciesLambdaLayers = () => {
88
101
  const { peerDependencies } = packageJson;
@@ -104,6 +117,14 @@ export const createApiTemplate = ({
104
117
 
105
118
  const template: CloudFormationTemplate = {
106
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
+ },
107
128
  Parameters: {
108
129
  Environment: {
109
130
  Default: 'Staging',
@@ -137,7 +158,7 @@ export const createApiTemplate = ({
137
158
  Type: 'AWS::AppSync::GraphQLSchema',
138
159
  Properties: {
139
160
  ApiId: { 'Fn::GetAtt': [AppSyncGraphQLApiLogicalId, 'ApiId'] },
140
- Definition: sdl,
161
+ Definition: sdlWithoutComments,
141
162
  },
142
163
  },
143
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,364 +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.1",
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
- commentDescriptions: false,
169
- omitDescriptions: true,
170
- omitScalars: true
171
- });
172
- graphql.validateSchema(schemaComposer.buildSchema());
173
- const resolveMethods = schemaComposer.getResolveMethods();
174
- const resolveMethodsEntries = Object.entries(resolveMethods).flatMap(
175
- ([typeName, fieldResolvers]) => {
176
- return Object.entries(fieldResolvers).map(([fieldName]) => {
177
- return {
178
- fieldName,
179
- typeName
180
- };
181
- });
182
- }
183
- );
184
- const getGraphQLComposeDependenciesLambdaLayers = () => {
185
- const { peerDependencies } = package_default;
186
- const lambdaLayerStackNames = Object.entries(peerDependencies).map(
187
- ([dependencyName, dependencyVersion]) => {
188
- return getPackageLambdaLayerStackName(
189
- [dependencyName, dependencyVersion].join("@")
190
- );
191
- }
192
- );
193
- return lambdaLayerStackNames.map((lambdaLayerStackName) => {
194
- return {
195
- "Fn::ImportValue": lambdaLayerStackName
196
- };
197
- });
198
- };
199
- const template = {
200
- AWSTemplateFormatVersion: "2010-09-09",
201
- Parameters: {
202
- Environment: {
203
- Default: "Staging",
204
- Type: "String",
205
- AllowedValues: ["Staging", "Production"]
206
- },
207
- LambdaS3Bucket: {
208
- Type: "String"
209
- },
210
- LambdaS3Key: {
211
- Type: "String"
212
- },
213
- LambdaS3ObjectVersion: {
214
- Type: "String"
215
- }
216
- },
217
- Resources: {
218
- [AppSyncGraphQLApiLogicalId]: {
219
- Type: "AWS::AppSync::GraphQLApi",
220
- Properties: {
221
- AuthenticationType: authenticationType,
222
- Name: {
223
- "Fn::Join": [
224
- ":",
225
- [{ Ref: "AWS::StackName" }, AppSyncGraphQLApiLogicalId]
226
- ]
227
- }
228
- }
229
- },
230
- [AppSyncGraphQLSchemaLogicalId]: {
231
- Type: "AWS::AppSync::GraphQLSchema",
232
- Properties: {
233
- ApiId: { "Fn::GetAtt": [AppSyncGraphQLApiLogicalId, "ApiId"] },
234
- Definition: sdl
235
- }
236
- },
237
- [AppSyncLambdaFunctionLogicalId]: {
238
- Type: "AWS::Lambda::Function",
239
- Properties: {
240
- Code: {
241
- S3Bucket: { Ref: "LambdaS3Bucket" },
242
- S3Key: { Ref: "LambdaS3Key" },
243
- S3ObjectVersion: { Ref: "LambdaS3ObjectVersion" }
244
- },
245
- Handler: "index.handler",
246
- Layers: getGraphQLComposeDependenciesLambdaLayers(),
247
- MemorySize: 512,
248
- Role: lambdaFunction.roleArn,
249
- Runtime: "nodejs18.x",
250
- /**
251
- * https://docs.aws.amazon.com/general/latest/gr/appsync.html
252
- * Request execution time for mutations, queries, and subscriptions: 30 seconds
253
- */
254
- Timeout: 29
255
- }
256
- },
257
- [AppSyncLambdaFunctionAppSyncDataSourceLogicalId]: {
258
- Type: "AWS::AppSync::DataSource",
259
- Properties: {
260
- ApiId: { "Fn::GetAtt": [AppSyncGraphQLApiLogicalId, "ApiId"] },
261
- LambdaConfig: {
262
- LambdaFunctionArn: {
263
- "Fn::GetAtt": [AppSyncLambdaFunctionLogicalId, "Arn"]
264
- }
265
- },
266
- Name: "AppSyncLambdaFunctionAppSyncDataSource",
267
- ServiceRoleArn: dataSource.roleArn,
268
- Type: "AWS_LAMBDA"
269
- }
270
- }
271
- },
272
- Outputs: {
273
- AppSyncApiGraphQLUrl: {
274
- Export: {
275
- Name: {
276
- "Fn::Join": [
277
- ":",
278
- [{ Ref: "AWS::StackName" }, "AppSyncApiGraphQLUrl"]
279
- ]
280
- }
281
- },
282
- Value: {
283
- "Fn::GetAtt": [AppSyncGraphQLApiLogicalId, "GraphQLUrl"]
284
- }
285
- },
286
- AppSyncApiArn: {
287
- Export: {
288
- Name: {
289
- "Fn::Join": [":", [{ Ref: "AWS::StackName" }, "AppSyncApiArn"]]
290
- }
291
- },
292
- Value: {
293
- "Fn::GetAtt": [AppSyncGraphQLApiLogicalId, "Arn"]
294
- }
295
- }
296
- }
297
- };
298
- resolveMethodsEntries.forEach(({ fieldName, typeName }) => {
299
- template.Resources[`${fieldName}${typeName}AppSyncResolver`] = {
300
- Type: "AWS::AppSync::Resolver",
301
- DependsOn: AppSyncGraphQLSchemaLogicalId,
302
- Properties: {
303
- ApiId: { "Fn::GetAtt": [AppSyncGraphQLApiLogicalId, "ApiId"] },
304
- FieldName: fieldName,
305
- TypeName: typeName,
306
- DataSourceName: {
307
- "Fn::GetAtt": [
308
- AppSyncLambdaFunctionAppSyncDataSourceLogicalId,
309
- "Name"
310
- ]
311
- }
312
- }
313
- };
314
- });
315
- const apiKey = additionalAuthenticationProviders?.includes("API_KEY") || authenticationType === "API_KEY";
316
- const cognitoUserPoolAuth = additionalAuthenticationProviders?.includes("AMAZON_COGNITO_USER_POOLS") || authenticationType === "AMAZON_COGNITO_USER_POOLS";
317
- if (additionalAuthenticationProviders) {
318
- template.Resources[AppSyncGraphQLApiLogicalId].Properties.AdditionalAuthenticationProviders = additionalAuthenticationProviders?.map((provider) => {
319
- return {
320
- AuthenticationType: provider
321
- };
322
- });
323
- }
324
- if (apiKey) {
325
- template.Resources[AppSyncGraphQLApiKeyLogicalId] = {
326
- Type: "AWS::AppSync::ApiKey",
327
- Properties: {
328
- ApiId: { "Fn::GetAtt": [AppSyncGraphQLApiLogicalId, "ApiId"] }
329
- }
330
- };
331
- if (!template.Outputs) {
332
- template.Outputs = {};
333
- }
334
- template.Outputs[AppSyncGraphQLApiKeyLogicalId] = {
335
- Value: {
336
- "Fn::GetAtt": [AppSyncGraphQLApiKeyLogicalId, "ApiKey"]
337
- }
338
- };
339
- }
340
- if (cognitoUserPoolAuth) {
341
- if (!userPoolConfig) {
342
- throw new Error(
343
- "userPoolConfig is required when using AMAZON_COGNITO_USER_POOLS authentication."
344
- );
345
- }
346
- template.Resources[AppSyncGraphQLApiLogicalId].Properties.UserPoolConfig = {
347
- AppIdClientRegex: userPoolConfig.appIdClientRegex,
348
- AwsRegion: userPoolConfig.awsRegion,
349
- DefaultAction: userPoolConfig.defaultAction,
350
- UserPoolId: userPoolConfig.userPoolId
351
- };
352
- }
353
- if (lambdaFunction.environment?.variables) {
354
- template.Resources[AppSyncLambdaFunctionLogicalId].Properties.Environment = {
355
- Variables: lambdaFunction.environment.variables
356
- };
357
- }
358
- return template;
359
- };
360
-
361
- export {
362
- AppSyncGraphQLSchemaLogicalId,
363
- createApiTemplate
364
- };