@ttoss/graphql-api 0.7.5 → 0.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -674
- package/dist/cli.d.mts +2 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +120 -0
- package/dist/esm/chunk-NT3ZWSM6.js +8 -0
- package/dist/esm/cli.js +95 -0
- package/dist/esm/index.js +161 -0
- package/dist/esm/shield.js +4 -0
- package/dist/index.d.mts +16 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +211 -0
- package/dist/shield.d.mts +2 -0
- package/dist/shield.d.ts +2 -0
- package/dist/shield.js +29 -0
- package/package.json +5 -5
- package/src/buildSchema.ts +0 -51
- package/src/cli.ts +0 -126
- package/src/composeWithRelay/composeWithRelay.ts +0 -68
- package/src/composeWithRelay/index.ts +0 -6
- package/src/composeWithRelay/nodeFieldConfig.ts +0 -86
- package/src/composeWithRelay/nodeInterface.ts +0 -31
- package/src/index.ts +0 -8
- package/src/shield.ts +0 -14
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttoss/graphql-api",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.7",
|
|
4
4
|
"description": "A library for building GraphQL APIs using ttoss ecosystem.",
|
|
5
|
+
"license": "MIT",
|
|
5
6
|
"author": "ttoss",
|
|
6
7
|
"contributors": [
|
|
7
8
|
"Pedro Arantes <pedro@arantespp.com> (https://arantespp.com)"
|
|
@@ -27,8 +28,7 @@
|
|
|
27
28
|
"ttoss-graphql-api": "./bin/cli.js"
|
|
28
29
|
},
|
|
29
30
|
"files": [
|
|
30
|
-
"dist"
|
|
31
|
-
"src"
|
|
31
|
+
"dist"
|
|
32
32
|
],
|
|
33
33
|
"sideEffects": false,
|
|
34
34
|
"dependencies": {
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"ts-node": "^10.9.2",
|
|
43
43
|
"tsconfig-paths": "^4.2.0",
|
|
44
44
|
"yargs": "^17.7.2",
|
|
45
|
-
"@ttoss/ids": "^0.2.
|
|
45
|
+
"@ttoss/ids": "^0.2.13"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"graphql": "^16.6.0"
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"graphql": "^16.8.1",
|
|
53
53
|
"jest": "^29.7.0",
|
|
54
54
|
"tsup": "^8.3.0",
|
|
55
|
-
"@ttoss/config": "^1.
|
|
55
|
+
"@ttoss/config": "^1.34.1"
|
|
56
56
|
},
|
|
57
57
|
"keywords": [
|
|
58
58
|
"api",
|
package/src/buildSchema.ts
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { type GraphQLSchema } from 'graphql';
|
|
2
|
-
import {
|
|
3
|
-
type IMiddleware as Middleware,
|
|
4
|
-
type IMiddlewareGenerator as MiddlewareGenerator,
|
|
5
|
-
applyMiddleware,
|
|
6
|
-
} from 'graphql-middleware';
|
|
7
|
-
import { type SchemaComposer } from 'graphql-compose';
|
|
8
|
-
|
|
9
|
-
export type { Middleware, MiddlewareGenerator };
|
|
10
|
-
|
|
11
|
-
export type BuildSchemaInput<TContext = unknown> = {
|
|
12
|
-
schemaComposer: SchemaComposer<TContext>;
|
|
13
|
-
middlewares?: (
|
|
14
|
-
| Middleware
|
|
15
|
-
| MiddlewareGenerator<unknown, TContext, unknown>
|
|
16
|
-
)[];
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export const buildSchema = ({
|
|
20
|
-
schemaComposer,
|
|
21
|
-
middlewares,
|
|
22
|
-
}: BuildSchemaInput): GraphQLSchema => {
|
|
23
|
-
if (!schemaComposer) {
|
|
24
|
-
throw new Error('No schemaComposer provided');
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const schema = schemaComposer.buildSchema();
|
|
28
|
-
|
|
29
|
-
if (middlewares) {
|
|
30
|
-
return applyMiddleware(
|
|
31
|
-
schema,
|
|
32
|
-
...middlewares.map((middleware) => {
|
|
33
|
-
/**
|
|
34
|
-
* https://github.com/dimatill/graphql-middleware/issues/433#issuecomment-1170187160
|
|
35
|
-
*/
|
|
36
|
-
if (
|
|
37
|
-
(middleware as MiddlewareGenerator<unknown, unknown, unknown>)
|
|
38
|
-
.generate
|
|
39
|
-
) {
|
|
40
|
-
return (
|
|
41
|
-
middleware as MiddlewareGenerator<unknown, unknown, unknown>
|
|
42
|
-
).generate(schema);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return middleware;
|
|
46
|
-
})
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return schema;
|
|
51
|
-
};
|
package/src/cli.ts
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs';
|
|
2
|
-
import * as path from 'node:path';
|
|
3
|
-
import * as typescriptPlugin from '@graphql-codegen/typescript';
|
|
4
|
-
import { codegen } from '@graphql-codegen/core';
|
|
5
|
-
import { hideBin } from 'yargs/helpers';
|
|
6
|
-
import { parse } from 'graphql';
|
|
7
|
-
import { register } from 'ts-node';
|
|
8
|
-
import { register as registerTsPaths } from 'tsconfig-paths';
|
|
9
|
-
import log from 'npmlog';
|
|
10
|
-
import yargs from 'yargs';
|
|
11
|
-
|
|
12
|
-
const logPrefix = 'graphql-api';
|
|
13
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
14
|
-
const tsConfig = require(path.resolve(process.cwd(), 'tsconfig.json'));
|
|
15
|
-
let cleanup = () => {};
|
|
16
|
-
try {
|
|
17
|
-
const baseUrl = tsConfig?.compilerOptions?.baseUrl;
|
|
18
|
-
const paths = tsConfig?.compilerOptions?.paths;
|
|
19
|
-
if ((baseUrl && !paths) || (!baseUrl && paths)) {
|
|
20
|
-
throw new Error(
|
|
21
|
-
"tsconfig.json must have 'baseUrl' and 'paths' properties."
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
if (baseUrl && paths) {
|
|
25
|
-
cleanup = registerTsPaths({
|
|
26
|
-
baseUrl: tsConfig.compilerOptions.baseUrl,
|
|
27
|
-
paths: tsConfig.compilerOptions.paths,
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
} catch (error: unknown) {
|
|
31
|
-
error instanceof Error && log.error(logPrefix, error.message);
|
|
32
|
-
process.exit(1);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
register({
|
|
36
|
-
transpileOnly: true,
|
|
37
|
-
compilerOptions: {
|
|
38
|
-
module: 'NodeNext',
|
|
39
|
-
moduleResolution: 'NodeNext',
|
|
40
|
-
},
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
const buildSchema = async ({ directory }: { directory: string }) => {
|
|
44
|
-
log.info(logPrefix, 'Building schema...');
|
|
45
|
-
|
|
46
|
-
await fs.promises.mkdir('schema', { recursive: true });
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Create schema/types.ts if it doesn't exist. We need to do this because
|
|
50
|
-
* graphql-codegen will throw an error if the file doesn't exist and the
|
|
51
|
-
* code import the types from that file.
|
|
52
|
-
*/
|
|
53
|
-
try {
|
|
54
|
-
await fs.promises.access('schema/types.ts');
|
|
55
|
-
} catch {
|
|
56
|
-
await fs.promises.writeFile('schema/types.ts', '');
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
60
|
-
const { schemaComposer } = require(
|
|
61
|
-
path.resolve(process.cwd(), directory, 'schemaComposer.ts')
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
const sdl = schemaComposer.toSDL();
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* https://the-guild.dev/graphql/codegen/docs/advanced/programmatic-usage
|
|
68
|
-
*/
|
|
69
|
-
const codegenConfig = {
|
|
70
|
-
documents: [],
|
|
71
|
-
config: {
|
|
72
|
-
declarationKind: {
|
|
73
|
-
type: 'interface',
|
|
74
|
-
interface: 'interface',
|
|
75
|
-
},
|
|
76
|
-
namingConvention: 'keep',
|
|
77
|
-
},
|
|
78
|
-
filename: 'schema/types.ts',
|
|
79
|
-
schema: parse(sdl),
|
|
80
|
-
plugins: [
|
|
81
|
-
{
|
|
82
|
-
typescript: {},
|
|
83
|
-
},
|
|
84
|
-
],
|
|
85
|
-
pluginMap: {
|
|
86
|
-
typescript: typescriptPlugin,
|
|
87
|
-
},
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
await fs.promises.writeFile('schema/schema.graphql', sdl);
|
|
91
|
-
|
|
92
|
-
log.info(logPrefix, 'Generating types...');
|
|
93
|
-
|
|
94
|
-
const typesOutput = await codegen(codegenConfig);
|
|
95
|
-
|
|
96
|
-
const typesOutputIgnore = ['/* eslint-disable */'].join('\n');
|
|
97
|
-
|
|
98
|
-
await fs.promises.writeFile(
|
|
99
|
-
'schema/types.ts',
|
|
100
|
-
`${typesOutputIgnore}\n${typesOutput}`
|
|
101
|
-
);
|
|
102
|
-
cleanup();
|
|
103
|
-
log.info(logPrefix, 'Schema and types generated!');
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
yargs(hideBin(process.argv))
|
|
107
|
-
.command(
|
|
108
|
-
'build-schema',
|
|
109
|
-
'fetch the contents of the URL',
|
|
110
|
-
(yargs) => {
|
|
111
|
-
return yargs.options({
|
|
112
|
-
directory: {
|
|
113
|
-
alias: ['d'],
|
|
114
|
-
type: 'string',
|
|
115
|
-
describe: 'Schema composer directory relative to the project root',
|
|
116
|
-
default: 'src',
|
|
117
|
-
},
|
|
118
|
-
});
|
|
119
|
-
},
|
|
120
|
-
(argv) => {
|
|
121
|
-
return buildSchema(argv);
|
|
122
|
-
}
|
|
123
|
-
)
|
|
124
|
-
.demandCommand(1)
|
|
125
|
-
.strictOptions()
|
|
126
|
-
.parse();
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { ObjectTypeComposer } from 'graphql-compose';
|
|
3
|
-
import { getNodeFieldConfig } from './nodeFieldConfig';
|
|
4
|
-
import { getNodeInterface } from './nodeInterface';
|
|
5
|
-
import { toGlobalId } from '@ttoss/ids';
|
|
6
|
-
|
|
7
|
-
// all wrapped typeComposers with Relay, stored in this variable
|
|
8
|
-
// for futher type resolving via NodeInterface.resolveType method
|
|
9
|
-
export const TypeMapForRelayNode: any = {};
|
|
10
|
-
|
|
11
|
-
export const composeWithRelay = <TContext>(
|
|
12
|
-
tc: ObjectTypeComposer<any, TContext>
|
|
13
|
-
): ObjectTypeComposer<any, TContext> => {
|
|
14
|
-
if (!(tc instanceof ObjectTypeComposer)) {
|
|
15
|
-
throw new Error(
|
|
16
|
-
'You should provide ObjectTypeComposer instance to composeWithRelay method'
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const nodeInterface = getNodeInterface(tc.schemaComposer);
|
|
21
|
-
const nodeFieldConfig = getNodeFieldConfig(
|
|
22
|
-
TypeMapForRelayNode,
|
|
23
|
-
nodeInterface
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
if (tc.getTypeName() === 'Query' || tc.getTypeName() === 'RootQuery') {
|
|
27
|
-
tc.setField('node', nodeFieldConfig);
|
|
28
|
-
return tc;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (tc.getTypeName() === 'Mutation' || tc.getTypeName() === 'RootMutation') {
|
|
32
|
-
// just skip
|
|
33
|
-
return tc;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (!tc.hasRecordIdFn()) {
|
|
37
|
-
throw new Error(
|
|
38
|
-
`ObjectTypeComposer(${tc.getTypeName()}) should have recordIdFn. ` +
|
|
39
|
-
'This function returns ID from provided object.'
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const findById = tc.getResolver('findById');
|
|
44
|
-
if (!findById) {
|
|
45
|
-
throw new Error(
|
|
46
|
-
`ObjectTypeComposer(${tc.getTypeName()}) provided to composeWithRelay ` +
|
|
47
|
-
'should have findById resolver.'
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
TypeMapForRelayNode[tc.getTypeName()] = {
|
|
51
|
-
resolver: findById,
|
|
52
|
-
tc,
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
tc.addFields({
|
|
56
|
-
id: {
|
|
57
|
-
type: 'ID!',
|
|
58
|
-
description: 'The globally unique ID among all types',
|
|
59
|
-
resolve: (source) => {
|
|
60
|
-
return toGlobalId(tc.getTypeName(), tc.getRecordId(source).toString());
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
tc.addInterface(nodeInterface);
|
|
66
|
-
|
|
67
|
-
return tc;
|
|
68
|
-
};
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import {
|
|
3
|
-
type InterfaceTypeComposer,
|
|
4
|
-
type ObjectTypeComposerFieldConfigDefinition,
|
|
5
|
-
getProjectionFromAST,
|
|
6
|
-
} from 'graphql-compose';
|
|
7
|
-
import { fromGlobalId } from '@ttoss/ids';
|
|
8
|
-
import type { GraphQLResolveInfo } from 'graphql-compose/lib/graphql';
|
|
9
|
-
import type { ObjectTypeComposer, Resolver } from 'graphql-compose';
|
|
10
|
-
|
|
11
|
-
export type TypeMapForRelayNode<TSource, TContext> = {
|
|
12
|
-
[typeName: string]: {
|
|
13
|
-
resolver: Resolver<TSource, TContext>;
|
|
14
|
-
tc: ObjectTypeComposer<TSource, TContext>;
|
|
15
|
-
};
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
// this fieldConfig must be set to RootQuery.node field
|
|
19
|
-
export const getNodeFieldConfig = (
|
|
20
|
-
typeMapForRelayNode: TypeMapForRelayNode<any, any>,
|
|
21
|
-
nodeInterface: InterfaceTypeComposer<any, any>
|
|
22
|
-
): ObjectTypeComposerFieldConfigDefinition<any, any> => {
|
|
23
|
-
return {
|
|
24
|
-
description:
|
|
25
|
-
'Fetches an object that has globally unique ID among all types',
|
|
26
|
-
type: nodeInterface,
|
|
27
|
-
args: {
|
|
28
|
-
id: {
|
|
29
|
-
type: 'ID!',
|
|
30
|
-
description: 'The globally unique ID among all types',
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
// eslint-disable-next-line max-params
|
|
34
|
-
resolve: (
|
|
35
|
-
source: any,
|
|
36
|
-
args: { [argName: string]: any },
|
|
37
|
-
context: any,
|
|
38
|
-
info: GraphQLResolveInfo
|
|
39
|
-
) => {
|
|
40
|
-
if (!args.id || !(typeof args.id === 'string')) {
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
const { type } = fromGlobalId(args.id);
|
|
44
|
-
|
|
45
|
-
if (!typeMapForRelayNode[type]) {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
const { tc, resolver: findById } = typeMapForRelayNode[type];
|
|
49
|
-
if (findById && findById.resolve && tc) {
|
|
50
|
-
const graphqlType = tc.getType();
|
|
51
|
-
|
|
52
|
-
// set `returnType` for proper work of `getProjectionFromAST`
|
|
53
|
-
// it will correctly add required fields for `relation` to `projection`
|
|
54
|
-
let projection;
|
|
55
|
-
if (info) {
|
|
56
|
-
projection = getProjectionFromAST({
|
|
57
|
-
...info,
|
|
58
|
-
returnType: graphqlType,
|
|
59
|
-
});
|
|
60
|
-
} else {
|
|
61
|
-
projection = {};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// suppose that first argument is argument with id field
|
|
65
|
-
const idArgName = Object.keys(findById.args)[0];
|
|
66
|
-
return findById
|
|
67
|
-
.resolve({
|
|
68
|
-
source,
|
|
69
|
-
args: { [idArgName]: args.id }, // eg. mongoose has _id fieldname, so should map
|
|
70
|
-
context,
|
|
71
|
-
info,
|
|
72
|
-
projection,
|
|
73
|
-
})
|
|
74
|
-
.then((res: any) => {
|
|
75
|
-
if (!res) {
|
|
76
|
-
return res;
|
|
77
|
-
}
|
|
78
|
-
res.__nodeType = graphqlType;
|
|
79
|
-
return res;
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return null;
|
|
84
|
-
},
|
|
85
|
-
};
|
|
86
|
-
};
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { InterfaceTypeComposer, type SchemaComposer } from 'graphql-compose';
|
|
2
|
-
|
|
3
|
-
const NodeTC = InterfaceTypeComposer.createTemp({
|
|
4
|
-
name: 'Node',
|
|
5
|
-
description:
|
|
6
|
-
'An object, that can be fetched by the globally unique ID among all types.',
|
|
7
|
-
fields: {
|
|
8
|
-
id: {
|
|
9
|
-
type: 'ID!',
|
|
10
|
-
description: 'The globally unique ID among all types.',
|
|
11
|
-
},
|
|
12
|
-
},
|
|
13
|
-
resolveType: (payload: any) => {
|
|
14
|
-
// `payload.__nodeType` was added to payload via nodeFieldConfig.resolve
|
|
15
|
-
return payload.__nodeType.name ? payload.__nodeType.name : null;
|
|
16
|
-
},
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
export const NodeInterface = NodeTC.getType();
|
|
20
|
-
|
|
21
|
-
export const getNodeInterface = <TContext>(
|
|
22
|
-
sc: SchemaComposer<TContext>
|
|
23
|
-
): InterfaceTypeComposer<any, TContext> => {
|
|
24
|
-
if (sc.hasInstance('Node', InterfaceTypeComposer)) {
|
|
25
|
-
return sc.get('Node') as any;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
sc.set('Node', NodeTC);
|
|
29
|
-
|
|
30
|
-
return NodeTC;
|
|
31
|
-
};
|
package/src/index.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export { composeWithRelay } from './composeWithRelay';
|
|
2
|
-
export { default as composeWithConnection } from 'graphql-compose-connection';
|
|
3
|
-
export * from 'graphql-compose';
|
|
4
|
-
export {
|
|
5
|
-
buildSchema,
|
|
6
|
-
type BuildSchemaInput,
|
|
7
|
-
type Middleware,
|
|
8
|
-
} from './buildSchema';
|
package/src/shield.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export * from 'graphql-shield';
|
|
2
|
-
/**
|
|
3
|
-
* Export types from graphql-middleware to avoid "The inferred type of 'x'
|
|
4
|
-
* cannot be named without a reference to '.../graphql-middleware/index.d.ts(1,1)'.
|
|
5
|
-
* This is likely not portable. A type annotation is necessary."
|
|
6
|
-
*/
|
|
7
|
-
export type {
|
|
8
|
-
IMiddlewareGenerator,
|
|
9
|
-
IMiddleware,
|
|
10
|
-
IMiddlewareFieldMap,
|
|
11
|
-
IMiddlewareFunction,
|
|
12
|
-
IMiddlewareGeneratorConstructor,
|
|
13
|
-
IMiddlewareTypeMap,
|
|
14
|
-
} from 'graphql-middleware';
|