@common-stack/generate-plugin 5.0.4-alpha.9 → 5.0.5-alpha.0
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/CHANGELOG.md +48 -0
- package/README.md +42 -0
- package/generators.json +5 -0
- package/lib/generators/add-backend/files/CHANGELOG.md +196 -0
- package/lib/generators/add-backend/files/Dockerfile +30 -0
- package/lib/generators/add-backend/files/LICENSE +661 -0
- package/lib/generators/add-backend/files/README.md +133 -0
- package/lib/generators/add-backend/files/__tests__/test.ts.template +95 -0
- package/lib/generators/add-backend/files/babel.config.js +45 -0
- package/lib/generators/add-backend/files/build.config.js +14 -0
- package/lib/generators/add-backend/files/build.config.mjs +27 -0
- package/lib/generators/add-backend/files/generated-schema.graphql +235 -0
- package/lib/generators/add-backend/files/jest.config.js +27 -0
- package/lib/generators/add-backend/files/knexfile.js +63 -0
- package/lib/generators/add-backend/files/package.json +162 -0
- package/lib/generators/add-backend/files/src/api/remote-config.ts.template +11 -0
- package/lib/generators/add-backend/files/src/api/resolver.ts.template +15 -0
- package/lib/generators/add-backend/files/src/api/root-schema.graphqls +96 -0
- package/lib/generators/add-backend/files/src/api/scalar.ts.template +16 -0
- package/lib/generators/add-backend/files/src/api/schema-builder.ts.template +189 -0
- package/lib/generators/add-backend/files/src/api/utils.ts.template +44 -0
- package/lib/generators/add-backend/files/src/config/env-config.ts.template +34 -0
- package/lib/generators/add-backend/files/src/config/index.ts.template +1 -0
- package/lib/generators/add-backend/files/src/config/moleculer.config.ts.template +228 -0
- package/lib/generators/add-backend/files/src/connectors/connection-broker.ts.template +80 -0
- package/lib/generators/add-backend/files/src/connectors/graphql-pubsub-connector.ts.template +43 -0
- package/lib/generators/add-backend/files/src/connectors/mongo-connector.ts.template +78 -0
- package/lib/generators/add-backend/files/src/connectors/nats-connector.ts.template +82 -0
- package/lib/generators/add-backend/files/src/connectors/redis-connector.ts.template +73 -0
- package/lib/generators/add-backend/files/src/env.ts.template +5 -0
- package/lib/generators/add-backend/files/src/express-app.ts.template +67 -0
- package/lib/generators/add-backend/files/src/index.ts.template +56 -0
- package/lib/generators/add-backend/files/src/interfaces/index.ts.template +1 -0
- package/lib/generators/add-backend/files/src/interfaces/module-interface.ts.template +16 -0
- package/lib/generators/add-backend/files/src/main.spec.ts.template +129 -0
- package/lib/generators/add-backend/files/src/middleware/__tests__/cors.test.ts.template +12 -0
- package/lib/generators/add-backend/files/src/middleware/cors.ts.template +31 -0
- package/lib/generators/add-backend/files/src/middleware/error.ts.template +63 -0
- package/lib/generators/add-backend/files/src/middleware/moleculer-inter-namespace.ts.template +60 -0
- package/lib/generators/add-backend/files/src/middleware/persistedQuery.ts.template +40 -0
- package/lib/generators/add-backend/files/src/middleware/sentry.ts.template +9 -0
- package/lib/generators/add-backend/files/src/middleware/services.ts.template +16 -0
- package/lib/generators/add-backend/files/src/middleware/tracer.ts.template +24 -0
- package/lib/generators/add-backend/files/src/modules/auth/schema/auth-schema.graphql +25 -0
- package/lib/generators/add-backend/files/src/modules/index.ts.template +17 -0
- package/lib/generators/add-backend/files/src/modules/module.ts.template +78 -0
- package/lib/generators/add-backend/files/src/server-setup/graphql-server.ts.template +185 -0
- package/lib/generators/add-backend/files/src/server-setup/graphql-subscription-server.ts.template +113 -0
- package/lib/generators/add-backend/files/src/server-setup/graphql-ws.ts.template +158 -0
- package/lib/generators/add-backend/files/src/server-setup/mongodb-migration-update.ts.template +47 -0
- package/lib/generators/add-backend/files/src/server-setup/utils.ts.template +43 -0
- package/lib/generators/add-backend/files/src/server-setup/websocket-multipath-update.ts.template +88 -0
- package/lib/generators/add-backend/files/src/service.ts.template +36 -0
- package/lib/generators/add-backend/files/src/stack-server.ts.template +277 -0
- package/lib/generators/add-backend/files/src/utils/migrations.ts.template +32 -0
- package/lib/generators/add-backend/files/tsconfig.base.json +30 -0
- package/lib/generators/add-backend/files/tsconfig.json +19 -0
- package/lib/generators/add-backend/files/uploads/3986781.ppt +0 -0
- package/lib/generators/add-backend/files/webpack.config.js +186 -0
- package/lib/generators/add-backend/files/webpack.config.mjs +209 -0
- package/lib/generators/add-backend/generator.cjs +20 -0
- package/lib/generators/add-backend/generator.cjs.map +1 -0
- package/lib/generators/add-backend/generator.d.ts +4 -0
- package/lib/generators/add-backend/generator.mjs +20 -0
- package/lib/generators/add-backend/generator.mjs.map +1 -0
- package/lib/generators/add-backend/generator.spec.d.ts +1 -0
- package/lib/generators/add-backend/schema.json +17 -0
- package/lib/generators/add-frontend/generator.cjs +3 -12
- package/lib/generators/add-frontend/generator.cjs.map +1 -1
- package/lib/generators/add-frontend/generator.mjs +2 -11
- package/lib/generators/add-frontend/generator.mjs.map +1 -1
- package/lib/generators/add-frontend/templates/package.json +23 -24
- package/lib/index.cjs +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.mjs +1 -1
- package/lib/utils/index.cjs +8 -0
- package/lib/utils/index.cjs.map +1 -0
- package/lib/utils/index.d.ts +1 -0
- package/lib/utils/index.mjs +8 -0
- package/lib/utils/index.mjs.map +1 -0
- package/package.json +2 -2
- package/rollup.config.mjs +6 -4
- package/src/generators/add-backend/generator.spec.ts +20 -0
- package/src/generators/add-backend/generator.ts +30 -0
- package/src/generators/add-backend/schema.d.ts +4 -0
- package/src/generators/add-backend/schema.json +17 -0
- package/src/generators/add-frontend/generator.ts +2 -12
- package/src/index.ts +1 -1
- package/src/utils/index.ts +10 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "adminide-stack-backend-server",
|
|
3
|
+
"version": "3.1.1-alpha.5",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "Starter kit for apollo server using webpack and typescript",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"apollo",
|
|
8
|
+
"apollo-server",
|
|
9
|
+
"backend",
|
|
10
|
+
"express",
|
|
11
|
+
"graphiql",
|
|
12
|
+
"graphql",
|
|
13
|
+
"typescript",
|
|
14
|
+
"webpack"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://github.com/cdmbase/fullstack-pro#readme",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/cdmbase/fullstack-pro/issues"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/cdmbase/fullstack-pro.git"
|
|
23
|
+
},
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"author": "CDMBase LLC",
|
|
26
|
+
"main": "dist/index.js",
|
|
27
|
+
"typings": "dist/main.d.ts",
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "cross-env NODE_ENV=production webpack --config webpack.config.js",
|
|
30
|
+
"build:clean": "rimraf dist .awcache",
|
|
31
|
+
"build:dev": "cross-env NODE_ENV=development ENV_FILE=../../config/development/dev.env webpack --config webpack.config.js",
|
|
32
|
+
"db:migrate": "knex -- migrate:latest --cwd . --knexfile ./knexfile.js",
|
|
33
|
+
"db:migrate:rollback": "knex -- migrate:rollback --cwd . --knexfile ./knexfile.js",
|
|
34
|
+
"db:seed": "yarn db:migrate && knex -- seed:run --cwd . --knexfile ./knexfile.js",
|
|
35
|
+
"docker:build": "yarn build && docker build . -t $npm_package_name:$npm_package_version",
|
|
36
|
+
"docker:build:debug": "yarn build:debug && docker build . -t $npm_package_name:$npm_package_version",
|
|
37
|
+
"docker:run": "docker run --env-file ../../config/staging/docker-staging.env -p 8080:8080 -it $npm_package_name:$npm_package_version",
|
|
38
|
+
"docker:run:debug": "cross-env NODE_ENV=development docker run --env-file ../../config/staging/docker-staging.env -p 8080:8080 -it $npm_package_name:$npm_package_version",
|
|
39
|
+
"proddb:migrate": "NODE_ENV=production yarn db:migrate",
|
|
40
|
+
"proddb:migrate:rollback": "NODE_ENV=production yarn db:migrate:rollback",
|
|
41
|
+
"proddb:seed": "NODE_ENV=production yarn db:seed",
|
|
42
|
+
"prepublish": "yarn build:clean",
|
|
43
|
+
"stagedb:migrate": "cross-env ENV_FILE=../../config/test/test.env NODE_ENV=test yarn db:migrate",
|
|
44
|
+
"stagedb:migrate:rollback": "cross-env ENV_FILE=../../config/test/test.env NODE_ENV=test yarn db:migrate:rollback",
|
|
45
|
+
"stagedb:seed": "cross-env ENV_FILE=../../config/test/test.env NODE_ENV=test yarn db:seed",
|
|
46
|
+
"start": "cross-env NODE_ENV=production tsx dist/index.js",
|
|
47
|
+
"start:dev": "cross-env NODE_ENV=development ENV_FILE=../../config/development/dev.env tsx watch dist/index.js",
|
|
48
|
+
"start:staging": "cross-env NODE_ENV=staging ENV_FILE=../../config/staging/staging.env tsx dist/index.js",
|
|
49
|
+
"start:test": "cross-env NODE_ENV=test ENV_FILE=../../config/test/test.env tsx dist/index.js",
|
|
50
|
+
"test": "jest",
|
|
51
|
+
"test:notify": "yarn test:watch -- --notify",
|
|
52
|
+
"test:watch": "npm test -- --watch",
|
|
53
|
+
"preupver": "npm test",
|
|
54
|
+
"upver": "standard-version",
|
|
55
|
+
"watch": "cross-env NODE_ENV=development ENV_FILE=../../config/development/dev.env yarn build:dev && yarn start:dev",
|
|
56
|
+
"watch:staging": "cross-env NODE_ENV=test ENV_FILE=../../config/staging/staging.env yarn build && yarn start:stage",
|
|
57
|
+
"watch:test": "cross-env NODE_ENV=test ENV_FILE=../../config/test/test.env yarn build:test && yarn start:test",
|
|
58
|
+
"zen:watch": "zen watch -x"
|
|
59
|
+
},
|
|
60
|
+
"resolutions": {
|
|
61
|
+
"apollo-upload-client": "^16.0.0",
|
|
62
|
+
"extract-files": "^10.0.0",
|
|
63
|
+
"html-to-text": "^8.0.0"
|
|
64
|
+
},
|
|
65
|
+
"dependencies": {
|
|
66
|
+
"@adminide-stack/account-api-server": "7.2.6-alpha.13",
|
|
67
|
+
"@adminide-stack/billing-api-server": "7.2.6-alpha.13",
|
|
68
|
+
"@adminide-stack/core": "7.2.6-alpha.13",
|
|
69
|
+
"@adminide-stack/extension-module-server": "7.2.6-alpha.13",
|
|
70
|
+
"@adminide-stack/git-api-server": "7.2.6-alpha.13",
|
|
71
|
+
"@adminide-stack/integration-api-server": "7.2.6-alpha.13",
|
|
72
|
+
"@adminide-stack/marketplace-module-server": "7.2.6-alpha.13",
|
|
73
|
+
"@adminide-stack/platform-server": "7.2.6-alpha.13",
|
|
74
|
+
"@adminide-stack/project-mgmt-server": "7.2.6-alpha.13",
|
|
75
|
+
"@adminide-stack/registry-api-server": "7.2.6-alpha.13",
|
|
76
|
+
"@adminide-stack/user-auth0-server": "7.2.6-alpha.13",
|
|
77
|
+
"@apollo/client": "^3.9.0",
|
|
78
|
+
"@apollo/utils.keyvadapter": "3.1.0",
|
|
79
|
+
"@babel/runtime": "^7.20.1",
|
|
80
|
+
"@casl/ability": "^4.1.5",
|
|
81
|
+
"@cdm-logger/client": "9.0.3",
|
|
82
|
+
"@cdm-logger/server": "^9.0.3",
|
|
83
|
+
"@cdmbase/graphql-type-uri": "^3.0.0",
|
|
84
|
+
"@common-stack/cache-api-server": "0.0.1",
|
|
85
|
+
"@common-stack/client-core": "0.0.1",
|
|
86
|
+
"@common-stack/core": "0.0.1",
|
|
87
|
+
"@common-stack/server-core": "0.0.1",
|
|
88
|
+
"@common-stack/store-mongo": "0.0.1",
|
|
89
|
+
"@container-stack/core": "5.1.2",
|
|
90
|
+
"@container-stack/mailing-api": "5.1.2",
|
|
91
|
+
"@container-stack/notification-api-core": "5.1.2",
|
|
92
|
+
"@container-stack/notification-api-server": "5.1.2",
|
|
93
|
+
"@container-stack/territory": "5.1.2",
|
|
94
|
+
"@graphql-tools/links": "^8.3.21",
|
|
95
|
+
"@graphql-tools/schema": "^8.3.14",
|
|
96
|
+
"@graphql-tools/stitch": "^8.7.29",
|
|
97
|
+
"@graphql-tools/utils": "^8.0.0",
|
|
98
|
+
"@graphql-tools/wrap": "^8.4.20",
|
|
99
|
+
"@keyv/redis": "2.8.4",
|
|
100
|
+
"@remix-run/node": "^2.8.1",
|
|
101
|
+
"@sentry/node": "~7.24.2",
|
|
102
|
+
"apollo-datasource": "^3.3.1",
|
|
103
|
+
"apollo-datasource-rest": "^3.3.1",
|
|
104
|
+
"apollo-errors": "^1.9.0",
|
|
105
|
+
"apollo-server-cache-memcached": "^3.3.1",
|
|
106
|
+
"apollo-server-cache-redis": "^3.3.1",
|
|
107
|
+
"apollo-server-caching": "^3.3.0",
|
|
108
|
+
"apollo-server-core": "^3.11.1",
|
|
109
|
+
"apollo-server-errors": "^3.3.1",
|
|
110
|
+
"apollo-server-express": "^3.11.1",
|
|
111
|
+
"apollo-server-plugin-response-cache": "^3.8.1",
|
|
112
|
+
"app-root-path": "^3.0.0",
|
|
113
|
+
"body-parser": "^1.19.0",
|
|
114
|
+
"cors": "^2.8.5",
|
|
115
|
+
"dataloader": "^2.0.0",
|
|
116
|
+
"dotenv": "^8.2.0",
|
|
117
|
+
"dotenv-esm": "^16.0.3-4",
|
|
118
|
+
"envalid": "~7.2.2",
|
|
119
|
+
"esm": "^3.2.25",
|
|
120
|
+
"express": "^4.17.1",
|
|
121
|
+
"graphql": "^15.0.0",
|
|
122
|
+
"graphql-bigint": "^1.0.0",
|
|
123
|
+
"graphql-iso-date": "^3.6.1",
|
|
124
|
+
"graphql-middleware": "^6.1.33",
|
|
125
|
+
"graphql-nats-subscriptions": "^1.5.0",
|
|
126
|
+
"graphql-playground-middleware-express": "^1.7.3",
|
|
127
|
+
"graphql-shield": "^7.3.5",
|
|
128
|
+
"graphql-subscriptions": "^2.0.0",
|
|
129
|
+
"graphql-tools": "^8.0.0",
|
|
130
|
+
"graphql-type-json": "^0.3.1",
|
|
131
|
+
"graphql-ws": "^5.11.2",
|
|
132
|
+
"inversify": "^6.0.2",
|
|
133
|
+
"ioredis": "^5.4.1",
|
|
134
|
+
"isomorphic-fetch": "^2.2.1",
|
|
135
|
+
"lodash": "^4.17.15",
|
|
136
|
+
"moleculer": "^0.14.2",
|
|
137
|
+
"moleculer-zipkin": "0.2.2",
|
|
138
|
+
"mongoose": "^6.3.3",
|
|
139
|
+
"mongoose-execution-time": "^1.1.0",
|
|
140
|
+
"morgan": "^1.9.1",
|
|
141
|
+
"nats": "^1.3.2",
|
|
142
|
+
"react": "18.2.0",
|
|
143
|
+
"reflect-metadata": "^0.1.13",
|
|
144
|
+
"rxjs": "^6.5.3",
|
|
145
|
+
"rxjs-compat": "^6.5.3",
|
|
146
|
+
"subscriptions-transport-ws": "^0.11.0",
|
|
147
|
+
"universal-cookie-express": "^4.0.1",
|
|
148
|
+
"ws": "^8.11.0"
|
|
149
|
+
},
|
|
150
|
+
"devDependencies": {
|
|
151
|
+
"cross-env": "^7.0.3",
|
|
152
|
+
"pm2": "^5.2.2",
|
|
153
|
+
"rimraf": "^3.0.2",
|
|
154
|
+
"tsx": "^4.7.0"
|
|
155
|
+
},
|
|
156
|
+
"engines": {
|
|
157
|
+
"vscode": "^1.52.1"
|
|
158
|
+
},
|
|
159
|
+
"typescript": {
|
|
160
|
+
"definition": "dist/main.d.ts"
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import GraphQLJSON, { GraphQLJSONObject } from 'graphql-type-json';
|
|
2
|
+
import { GraphQLDate, GraphQLTime, GraphQLDateTime } from 'graphql-iso-date';
|
|
3
|
+
import { GraphQLAnyObject } from './scalar';
|
|
4
|
+
import GraphQLURI from '@cdmbase/graphql-type-uri';
|
|
5
|
+
|
|
6
|
+
export const resolvers = {
|
|
7
|
+
AnyObject: GraphQLAnyObject,
|
|
8
|
+
Date: GraphQLDate,
|
|
9
|
+
Time: GraphQLTime,
|
|
10
|
+
URI: GraphQLURI('URI'),
|
|
11
|
+
URIInput: GraphQLURI('URIInput'),
|
|
12
|
+
DateTime: GraphQLDateTime,
|
|
13
|
+
JSON: GraphQLJSON,
|
|
14
|
+
JSONObject: GraphQLJSONObject,
|
|
15
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
scalar AnyObject
|
|
2
|
+
scalar Date
|
|
3
|
+
scalar Time
|
|
4
|
+
scalar DateTime
|
|
5
|
+
scalar URI
|
|
6
|
+
scalar URIInput
|
|
7
|
+
scalar Observable
|
|
8
|
+
|
|
9
|
+
scalar JSON
|
|
10
|
+
scalar JSONObject
|
|
11
|
+
|
|
12
|
+
directive @cacheControl(maxAge: Int, scope: CacheControlScope) on FIELD_DEFINITION | OBJECT | INTERFACE
|
|
13
|
+
enum CacheControlScope {
|
|
14
|
+
PUBLIC
|
|
15
|
+
PRIVATE
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
An object with an ID.
|
|
20
|
+
"""
|
|
21
|
+
interface Node {
|
|
22
|
+
"""
|
|
23
|
+
The ID of the node.
|
|
24
|
+
"""
|
|
25
|
+
id: ID!
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
# Pagination information. See https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo.
|
|
29
|
+
type PageInfo {
|
|
30
|
+
# Whether there is a next page of nodes in the connection.
|
|
31
|
+
hasNextPage: Boolean!
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
"""
|
|
35
|
+
Represents a null return value.
|
|
36
|
+
"""
|
|
37
|
+
type EmptyResponse {
|
|
38
|
+
# A dummy null value.
|
|
39
|
+
alwaysNil: String
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type FieldError {
|
|
43
|
+
field: String!
|
|
44
|
+
message: String!
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
input Sort{
|
|
48
|
+
key: String!,
|
|
49
|
+
value: SortEnum!,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
enum SortEnum{
|
|
53
|
+
ASC,
|
|
54
|
+
DESC
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
type Query {
|
|
58
|
+
"""
|
|
59
|
+
Looks up a node by ID.
|
|
60
|
+
"""
|
|
61
|
+
node(id: ID!): Node
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
type Mutation {
|
|
65
|
+
dummy: Int
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
type Subscription {
|
|
69
|
+
dummy: Int
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
type AdminIdeSettings {
|
|
73
|
+
dummy: Int
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
""" All Moleculer Topic names are extended from this."""
|
|
77
|
+
enum MoleculerServiceName {
|
|
78
|
+
dummy
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
interface IResourceUtilizationSettings {
|
|
82
|
+
subTopic: String
|
|
83
|
+
adminApiNamespace: String
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
type GeoLocation {
|
|
88
|
+
coordinates: [Float]
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
schema {
|
|
92
|
+
query: Query
|
|
93
|
+
mutation: Mutation
|
|
94
|
+
subscription: Subscription
|
|
95
|
+
}
|
|
96
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// add any scalar types
|
|
2
|
+
import { GraphQLError, GraphQLScalarType, Kind } from 'graphql';
|
|
3
|
+
|
|
4
|
+
// https://stackoverflow.com/questions/41557536/custom-map-keys-in-graphql-response
|
|
5
|
+
export const GraphQLAnyObject = new GraphQLScalarType({
|
|
6
|
+
name: 'AnyObject',
|
|
7
|
+
description: 'Any JSON object. This type bypasses type checking.',
|
|
8
|
+
serialize: (value) => value,
|
|
9
|
+
parseValue: (value) => value,
|
|
10
|
+
parseLiteral: (ast) => {
|
|
11
|
+
if (ast.kind !== Kind.OBJECT) {
|
|
12
|
+
throw new GraphQLError(`Query error: Can only parse object but got a: ${ast.kind}`, [ast]);
|
|
13
|
+
}
|
|
14
|
+
return ast.fields;
|
|
15
|
+
},
|
|
16
|
+
});
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/* eslint-disable class-methods-use-this */
|
|
2
|
+
/* eslint-disable no-useless-constructor */
|
|
3
|
+
/* eslint-disable import/no-extraneous-dependencies */
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import { GraphQLSchema, OperationDefinitionNode } from 'graphql';
|
|
6
|
+
import { stitchSchemas } from '@graphql-tools/stitch';
|
|
7
|
+
import { makeExecutableSchema } from '@graphql-tools/schema';
|
|
8
|
+
import { linkToExecutor } from '@graphql-tools/links';
|
|
9
|
+
import { introspectSchema, wrapSchema } from '@graphql-tools/wrap';
|
|
10
|
+
// import { transformSchema } from '@graphql-tools/delegate';
|
|
11
|
+
import * as ws from 'ws';
|
|
12
|
+
import { getMainDefinition } from '@apollo/client/utilities';
|
|
13
|
+
import { WebSocketLink } from '@apollo/client/link/ws';
|
|
14
|
+
import { split } from '@apollo/client/index.js';
|
|
15
|
+
import { IGraphqlShieldRules, logger } from '@common-stack/server-core';
|
|
16
|
+
import { HttpLink } from '@apollo/client/link/http';
|
|
17
|
+
import * as fetch from 'isomorphic-fetch';
|
|
18
|
+
import { CdmLogger } from '@cdm-logger/core';
|
|
19
|
+
import { shield } from 'graphql-shield';
|
|
20
|
+
import { applyMiddleware } from 'graphql-middleware';
|
|
21
|
+
import { remoteSchemaDetails } from './remote-config';
|
|
22
|
+
import rootSchemaDef from './root-schema.graphqls';
|
|
23
|
+
import { resolvers as rootResolver } from './resolver';
|
|
24
|
+
import { attachDirectiveResolvers } from './utils';
|
|
25
|
+
|
|
26
|
+
interface IGraphqlOptions {
|
|
27
|
+
schema: string | string[];
|
|
28
|
+
resolvers: any;
|
|
29
|
+
directives: any[];
|
|
30
|
+
directiveResolvers: { [key: string]: any };
|
|
31
|
+
middlewares: any[];
|
|
32
|
+
rules?: IGraphqlShieldRules;
|
|
33
|
+
logger: CdmLogger.ILogger;
|
|
34
|
+
}
|
|
35
|
+
export class GatewaySchemaBuilder {
|
|
36
|
+
constructor(private options: IGraphqlOptions) {}
|
|
37
|
+
|
|
38
|
+
public async build(): Promise<GraphQLSchema> {
|
|
39
|
+
let gatewaySchema;
|
|
40
|
+
let ownSchema;
|
|
41
|
+
try {
|
|
42
|
+
ownSchema = this.createOwnSchema();
|
|
43
|
+
const remoteSchema = await this.load();
|
|
44
|
+
// techSchema = this.patchSchema(techSchema, 'TechService');
|
|
45
|
+
|
|
46
|
+
gatewaySchema = stitchSchemas({
|
|
47
|
+
subschemas: [ownSchema],
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Apply middleware to the schema
|
|
51
|
+
if (this.options.middlewares && this.options.middlewares.length > 0) {
|
|
52
|
+
gatewaySchema = applyMiddleware(
|
|
53
|
+
gatewaySchema,
|
|
54
|
+
...this.options.middlewares,
|
|
55
|
+
shield(this.options.rules || {}, {
|
|
56
|
+
allowExternalErrors: true,
|
|
57
|
+
}),
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
// TODO after updating graphql-tools to v8
|
|
61
|
+
// addErrorLoggingToSchema(schema, { log: (e) => logger.error(e as Error) });
|
|
62
|
+
} catch (err) {
|
|
63
|
+
logger.error('[Graphql Schema Errors] when building schema:', err.message);
|
|
64
|
+
gatewaySchema = ownSchema;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return gatewaySchema;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private async load() {
|
|
71
|
+
const schemas = [];
|
|
72
|
+
// eslint-disable-next-line no-plusplus
|
|
73
|
+
for (let i = 0; i < remoteSchemaDetails.length; i++) {
|
|
74
|
+
// eslint-disable-next-line no-await-in-loop
|
|
75
|
+
const schema = await this.loadRemoteSchema(remoteSchemaDetails[i]);
|
|
76
|
+
schemas.push(schema);
|
|
77
|
+
}
|
|
78
|
+
return schemas;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private async createRemoteSchema(service: string, iteration?: number): Promise<GraphQLSchema> {
|
|
82
|
+
logger.info('Fetch service [%s] iteration [%s]', service, iteration);
|
|
83
|
+
const services = remoteSchemaDetails;
|
|
84
|
+
if (!services.length) {
|
|
85
|
+
console.warn(`Service ${services} is undefined`);
|
|
86
|
+
if (iteration && iteration > 2) {
|
|
87
|
+
return Promise.reject(`tried upto ${iteration} attempts, now failing...`);
|
|
88
|
+
}
|
|
89
|
+
return new Promise<GraphQLSchema>((resolve, reject) => {
|
|
90
|
+
const timeout = iteration ? 1000 * iteration : 1000;
|
|
91
|
+
logger.info('Wait for service startup %s', timeout);
|
|
92
|
+
setTimeout(() => {
|
|
93
|
+
this.createRemoteSchema(service, iteration ? iteration + 1 : 1)
|
|
94
|
+
.then(resolve)
|
|
95
|
+
.catch(reject);
|
|
96
|
+
}, timeout);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
// instead need to loop it
|
|
100
|
+
// https://github.com/j-colter/graphql-gateway/blob/9c64d90a74727d2002d10b06f47e1f4a316070fc/src/schema.js#L50
|
|
101
|
+
const url = services[0].uri;
|
|
102
|
+
logger.info('fetch service [%s]', url);
|
|
103
|
+
// 1. Create apollo Link that's connected to the underlying GraphQL API
|
|
104
|
+
const link = new HttpLink({ uri: url, fetch });
|
|
105
|
+
const executor: any = linkToExecutor(link);
|
|
106
|
+
// 2. Retrieve schema definition of the underlying GraphQL API
|
|
107
|
+
const remoteSchema = await introspectSchema(link as any);
|
|
108
|
+
|
|
109
|
+
// 3. Create the executable schema based on schema definition and Apollo Link
|
|
110
|
+
return wrapSchema({
|
|
111
|
+
schema: remoteSchema,
|
|
112
|
+
executor,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private async loadRemoteSchema({ uri, wsUri }) {
|
|
117
|
+
try {
|
|
118
|
+
const httpLink = new HttpLink({ uri, fetch });
|
|
119
|
+
let link = null;
|
|
120
|
+
|
|
121
|
+
if (wsUri) {
|
|
122
|
+
const wsLink = new WebSocketLink({
|
|
123
|
+
uri: wsUri,
|
|
124
|
+
options: {
|
|
125
|
+
reconnect: true,
|
|
126
|
+
},
|
|
127
|
+
webSocketImpl: ws,
|
|
128
|
+
});
|
|
129
|
+
link = split(
|
|
130
|
+
// split based on operatino type
|
|
131
|
+
({ query }) => {
|
|
132
|
+
const { kind, operation } = getMainDefinition(query) as OperationDefinitionNode;
|
|
133
|
+
return kind === 'OperationDefinition' && operation === 'subscription';
|
|
134
|
+
},
|
|
135
|
+
wsLink,
|
|
136
|
+
httpLink,
|
|
137
|
+
);
|
|
138
|
+
} else {
|
|
139
|
+
link = httpLink;
|
|
140
|
+
}
|
|
141
|
+
const executor: any = linkToExecutor(link);
|
|
142
|
+
const remoteSchema = await introspectSchema(link);
|
|
143
|
+
const executableSchema = wrapSchema({
|
|
144
|
+
schema: remoteSchema,
|
|
145
|
+
executor,
|
|
146
|
+
});
|
|
147
|
+
return executableSchema;
|
|
148
|
+
} catch (err) {
|
|
149
|
+
this.options.logger.error('fetching schema error: ', err);
|
|
150
|
+
return {};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// disabled after updating to apollo-client to v3 and graphql-tools to v8
|
|
155
|
+
// private patchSchema(schema: GraphQLSchema, systemName: string) {
|
|
156
|
+
// return transformSchema(schema, [
|
|
157
|
+
// new RenameTypes((name: string) => (name === 'StatusInfo' ? `${systemName}StatusInfo` : undefined)),
|
|
158
|
+
// new RenameRootFields((_operation: string, name: string) =>
|
|
159
|
+
// name === 'status'
|
|
160
|
+
// ? `${systemName.substring(0, 1).toLowerCase()}${systemName.substring(1)}Status`
|
|
161
|
+
// : name,
|
|
162
|
+
// ),
|
|
163
|
+
// ]);
|
|
164
|
+
// }
|
|
165
|
+
|
|
166
|
+
private createOwnSchema(): GraphQLSchema {
|
|
167
|
+
const typeDefs = [rootSchemaDef, this.options.schema].join('\n');
|
|
168
|
+
if (__DEV__) {
|
|
169
|
+
import('../modules/module').then(({ ExternalModules }) => {
|
|
170
|
+
const externalSchema = ExternalModules?.schemas || ``;
|
|
171
|
+
const writeData = `${externalSchema}`;
|
|
172
|
+
fs.writeFileSync('./generated-schema.graphql', writeData);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
let mergedSchema = makeExecutableSchema({
|
|
176
|
+
resolvers: [rootResolver, this.options.resolvers],
|
|
177
|
+
typeDefs,
|
|
178
|
+
resolverValidationOptions: {
|
|
179
|
+
requireResolversForResolveType: 'warn',
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
// mergedSchema = this.options.directives.reduce((curSchema,transform) => transform(curSchema), mergedSchema);
|
|
183
|
+
if (this.options.directiveResolvers && Object.keys(this.options.directiveResolvers).length !== 0) {
|
|
184
|
+
this.options.logger.warn('directiveResolvers deprecated replaced with directives');
|
|
185
|
+
mergedSchema = attachDirectiveResolvers(mergedSchema, this.options.directiveResolvers);
|
|
186
|
+
}
|
|
187
|
+
return mergedSchema;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { defaultFieldResolver, GraphQLSchema } from 'graphql';
|
|
2
|
+
import { mapSchema, MapperKind, getDirectives } from '@graphql-tools/utils';
|
|
3
|
+
|
|
4
|
+
export function attachDirectiveResolvers(
|
|
5
|
+
schema: GraphQLSchema,
|
|
6
|
+
directiveResolvers: {[key: string]: Function},
|
|
7
|
+
): GraphQLSchema {
|
|
8
|
+
// ... argument validation ...
|
|
9
|
+
|
|
10
|
+
return mapSchema(schema, {
|
|
11
|
+
[MapperKind.OBJECT_FIELD]: (fieldConfig) => {
|
|
12
|
+
const newFieldConfig = { ...fieldConfig };
|
|
13
|
+
|
|
14
|
+
const directives = getDirectives(schema, fieldConfig);
|
|
15
|
+
for (const directive of directives) {
|
|
16
|
+
const directiveName = directive.name;
|
|
17
|
+
if (directiveResolvers[directiveName]) {
|
|
18
|
+
const resolver = directiveResolvers[directiveName];
|
|
19
|
+
const originalResolver =
|
|
20
|
+
newFieldConfig.resolve != null ? newFieldConfig.resolve : defaultFieldResolver;
|
|
21
|
+
const directiveArgs = directive.args;
|
|
22
|
+
newFieldConfig.resolve = (source, originalArgs, context, info) => {
|
|
23
|
+
return resolver(
|
|
24
|
+
() =>
|
|
25
|
+
new Promise((resolve, reject) => {
|
|
26
|
+
const result = originalResolver(source, originalArgs, context, info);
|
|
27
|
+
if (result instanceof Error) {
|
|
28
|
+
reject(result);
|
|
29
|
+
}
|
|
30
|
+
resolve(result);
|
|
31
|
+
}),
|
|
32
|
+
source,
|
|
33
|
+
directiveArgs,
|
|
34
|
+
context,
|
|
35
|
+
info,
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return newFieldConfig;
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/// <reference path='../../../../typings/index.d.ts' />
|
|
2
|
+
import { str, bool, num, json, cleanEnv } from 'envalid';
|
|
3
|
+
|
|
4
|
+
export const config = cleanEnv(process.env, {
|
|
5
|
+
NODE_ENV: str({ default: 'production', choices: ['production', 'staging', 'development', 'test'] }),
|
|
6
|
+
NATS_URL: str({ devDefault: 'nats://localhost:4222/' }),
|
|
7
|
+
NATS_USER: str({ devDefault: 'test' }),
|
|
8
|
+
NATS_PW: str({ devDefault: 'test' }),
|
|
9
|
+
MONGO_URL: str({ devDefault: 'mongodb://localhost:27017/sample-stack' }),
|
|
10
|
+
MONGO_OPTIONS: str({ default: '{}' }),
|
|
11
|
+
LOG_LEVEL: str({ default: 'info', devDefault: 'trace', choices: ['info', 'debug', 'trace'] }),
|
|
12
|
+
REDIS_CLUSTER_URL: json({
|
|
13
|
+
devDefault: '[{"port":6379,"host":"localhost"}]',
|
|
14
|
+
example: '[{"port":6379,"host":"localhost"}]',
|
|
15
|
+
}),
|
|
16
|
+
REDIS_URL: str({ devDefault: 'localhost' }),
|
|
17
|
+
REDIS_CLUSTER_ENABLED: bool({ devDefault: false }),
|
|
18
|
+
REDIS_SENTINEL_ENABLED: bool({ devDefault: true }),
|
|
19
|
+
HEMERA_LOG_LEVEL: str({
|
|
20
|
+
default: 'info',
|
|
21
|
+
devDefault: 'info',
|
|
22
|
+
choices: ['fatal', 'error', 'warn', 'info', 'debug', 'trace'],
|
|
23
|
+
}),
|
|
24
|
+
BACKEND_URL: str({ devDefault: __BACKEND_URL__ }),
|
|
25
|
+
GRAPHQL_URL: str({ devDefault: __GRAPHQL_URL__ }),
|
|
26
|
+
CLIENT_URL: str({ devDefault: __BACKEND_URL__ }),
|
|
27
|
+
CONNECTION_ID: str({ devDefault: 'CONNECTION_ID' }),
|
|
28
|
+
MAILGUN_KEY: str(),
|
|
29
|
+
MAILGUN_DOMAIN: str(),
|
|
30
|
+
NAMESPACE: str({ default: 'default' }),
|
|
31
|
+
ACTIVITY_NAMESPACE: str({ devDefault: 'default' }),
|
|
32
|
+
API_NAMESPACE: str({ devDefault: 'default' }),
|
|
33
|
+
ADMIN_API_NAMESPACE: str({ devDefault: 'default' }),
|
|
34
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './env-config';
|