navis.js 5.3.2 → 5.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +198 -5
- package/examples/graphql-demo.js +130 -0
- package/examples/graphql-demo.ts +158 -0
- package/package.json +1 -1
- package/src/graphql/graphql-server.js +362 -0
- package/src/graphql/resolver.js +200 -0
- package/src/graphql/schema.js +188 -0
- package/src/index.js +27 -0
- package/types/index.d.ts +130 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GraphQL Schema Utilities
|
|
3
|
+
* Lightweight schema definition helpers
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* GraphQL Schema Builder
|
|
8
|
+
*/
|
|
9
|
+
class GraphQLSchema {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.types = {};
|
|
12
|
+
this.queries = {};
|
|
13
|
+
this.mutations = {};
|
|
14
|
+
this.subscriptions = {};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Define a type
|
|
19
|
+
*/
|
|
20
|
+
type(name, definition) {
|
|
21
|
+
this.types[name] = definition;
|
|
22
|
+
return this;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Define a query
|
|
27
|
+
*/
|
|
28
|
+
query(name, definition) {
|
|
29
|
+
this.queries[name] = definition;
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Define a mutation
|
|
35
|
+
*/
|
|
36
|
+
mutation(name, definition) {
|
|
37
|
+
this.mutations[name] = definition;
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Build schema string (GraphQL SDL format)
|
|
43
|
+
*/
|
|
44
|
+
build() {
|
|
45
|
+
let schema = '';
|
|
46
|
+
|
|
47
|
+
// Build type definitions
|
|
48
|
+
Object.keys(this.types).forEach(name => {
|
|
49
|
+
schema += this._buildType(name, this.types[name]);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Build Query type
|
|
53
|
+
if (Object.keys(this.queries).length > 0) {
|
|
54
|
+
schema += '\ntype Query {\n';
|
|
55
|
+
Object.keys(this.queries).forEach(name => {
|
|
56
|
+
schema += ` ${name}${this._buildFieldDefinition(this.queries[name])}\n`;
|
|
57
|
+
});
|
|
58
|
+
schema += '}\n';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Build Mutation type
|
|
62
|
+
if (Object.keys(this.mutations).length > 0) {
|
|
63
|
+
schema += '\ntype Mutation {\n';
|
|
64
|
+
Object.keys(this.mutations).forEach(name => {
|
|
65
|
+
schema += ` ${name}${this._buildFieldDefinition(this.mutations[name])}\n`;
|
|
66
|
+
});
|
|
67
|
+
schema += '}\n';
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return schema;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Build type definition
|
|
75
|
+
* @private
|
|
76
|
+
*/
|
|
77
|
+
_buildType(name, definition) {
|
|
78
|
+
if (typeof definition === 'string') {
|
|
79
|
+
return `type ${name} ${definition}\n`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
let typeDef = `type ${name} {\n`;
|
|
83
|
+
if (typeof definition === 'object') {
|
|
84
|
+
Object.keys(definition).forEach(field => {
|
|
85
|
+
typeDef += ` ${field}: ${definition[field]}\n`;
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
typeDef += '}\n';
|
|
89
|
+
return typeDef;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Build field definition
|
|
94
|
+
* @private
|
|
95
|
+
*/
|
|
96
|
+
_buildFieldDefinition(definition) {
|
|
97
|
+
if (typeof definition === 'string') {
|
|
98
|
+
return `: ${definition}`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (typeof definition === 'object' && definition.type) {
|
|
102
|
+
let def = '(';
|
|
103
|
+
if (definition.args && Object.keys(definition.args).length > 0) {
|
|
104
|
+
const args = Object.keys(definition.args).map(arg => {
|
|
105
|
+
return `${arg}: ${definition.args[arg]}`;
|
|
106
|
+
}).join(', ');
|
|
107
|
+
def += args;
|
|
108
|
+
}
|
|
109
|
+
def += `): ${definition.type}`;
|
|
110
|
+
return def;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return ': String';
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Create schema builder
|
|
119
|
+
*/
|
|
120
|
+
function createSchema() {
|
|
121
|
+
return new GraphQLSchema();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Define GraphQL type
|
|
126
|
+
*/
|
|
127
|
+
function type(name, definition) {
|
|
128
|
+
const schema = new GraphQLSchema();
|
|
129
|
+
return schema.type(name, definition);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Common GraphQL scalar types
|
|
134
|
+
*/
|
|
135
|
+
const scalars = {
|
|
136
|
+
String: 'String',
|
|
137
|
+
Int: 'Int',
|
|
138
|
+
Float: 'Float',
|
|
139
|
+
Boolean: 'Boolean',
|
|
140
|
+
ID: 'ID',
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Common GraphQL type helpers
|
|
145
|
+
*/
|
|
146
|
+
const types = {
|
|
147
|
+
/**
|
|
148
|
+
* Create input type definition
|
|
149
|
+
*/
|
|
150
|
+
input(name, fields) {
|
|
151
|
+
let input = `input ${name} {\n`;
|
|
152
|
+
Object.keys(fields).forEach(field => {
|
|
153
|
+
input += ` ${field}: ${fields[field]}\n`;
|
|
154
|
+
});
|
|
155
|
+
input += '}';
|
|
156
|
+
return input;
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Create list type
|
|
161
|
+
*/
|
|
162
|
+
list(type) {
|
|
163
|
+
return `[${type}]`;
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Create non-null type
|
|
168
|
+
*/
|
|
169
|
+
required(type) {
|
|
170
|
+
return `${type}!`;
|
|
171
|
+
},
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Create list of non-null items
|
|
175
|
+
*/
|
|
176
|
+
requiredList(type) {
|
|
177
|
+
return `[${type}!]`;
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
module.exports = {
|
|
182
|
+
GraphQLSchema,
|
|
183
|
+
createSchema,
|
|
184
|
+
type,
|
|
185
|
+
scalars,
|
|
186
|
+
types,
|
|
187
|
+
};
|
|
188
|
+
|
package/src/index.js
CHANGED
|
@@ -68,6 +68,17 @@ const WebSocketServer = require('./websocket/websocket-server');
|
|
|
68
68
|
const { SSEServer, createSSEServer, sse } = require('./sse/server-sent-events');
|
|
69
69
|
const { DatabasePool, createPool } = require('./db/db-pool');
|
|
70
70
|
|
|
71
|
+
// v5.4: GraphQL Support
|
|
72
|
+
const { GraphQLServer, GraphQLError, createGraphQLServer, graphql } = require('./graphql/graphql-server');
|
|
73
|
+
const { GraphQLSchema, createSchema, type, scalars, types } = require('./graphql/schema');
|
|
74
|
+
const {
|
|
75
|
+
createResolver,
|
|
76
|
+
fieldResolver,
|
|
77
|
+
combineResolvers,
|
|
78
|
+
createAsyncResolver,
|
|
79
|
+
createBatchResolver,
|
|
80
|
+
} = require('./graphql/resolver');
|
|
81
|
+
|
|
71
82
|
module.exports = {
|
|
72
83
|
// Core
|
|
73
84
|
NavisApp,
|
|
@@ -151,6 +162,22 @@ module.exports = {
|
|
|
151
162
|
DatabasePool,
|
|
152
163
|
createPool,
|
|
153
164
|
|
|
165
|
+
// v5.4: GraphQL Support
|
|
166
|
+
GraphQLServer,
|
|
167
|
+
GraphQLError,
|
|
168
|
+
createGraphQLServer,
|
|
169
|
+
graphql,
|
|
170
|
+
GraphQLSchema,
|
|
171
|
+
createSchema,
|
|
172
|
+
type,
|
|
173
|
+
scalars,
|
|
174
|
+
types,
|
|
175
|
+
createResolver,
|
|
176
|
+
fieldResolver,
|
|
177
|
+
combineResolvers,
|
|
178
|
+
createAsyncResolver,
|
|
179
|
+
createBatchResolver,
|
|
180
|
+
|
|
154
181
|
// Utilities
|
|
155
182
|
response: {
|
|
156
183
|
success,
|
package/types/index.d.ts
CHANGED
|
@@ -656,6 +656,123 @@ export const DatabasePool: {
|
|
|
656
656
|
new (options?: DatabasePoolOptions): DatabasePool;
|
|
657
657
|
};
|
|
658
658
|
|
|
659
|
+
// ============================================
|
|
660
|
+
// GraphQL Types (v5.4)
|
|
661
|
+
// ============================================
|
|
662
|
+
|
|
663
|
+
export interface GraphQLRequest {
|
|
664
|
+
query: string;
|
|
665
|
+
variables?: Record<string, any>;
|
|
666
|
+
operationName?: string;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
export interface GraphQLResponse {
|
|
670
|
+
data?: any;
|
|
671
|
+
errors?: GraphQLError[];
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
export interface GraphQLError {
|
|
675
|
+
message: string;
|
|
676
|
+
code?: string;
|
|
677
|
+
extensions?: Record<string, any>;
|
|
678
|
+
locations?: Array<{ line: number; column: number }>;
|
|
679
|
+
path?: Array<string | number>;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
export interface GraphQLContext {
|
|
683
|
+
req: NavisRequest;
|
|
684
|
+
headers: Record<string, string>;
|
|
685
|
+
query: Record<string, string>;
|
|
686
|
+
params: Record<string, string>;
|
|
687
|
+
[key: string]: any;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
export type GraphQLResolver = (
|
|
691
|
+
variables: Record<string, any>,
|
|
692
|
+
context: GraphQLContext,
|
|
693
|
+
fields?: string[]
|
|
694
|
+
) => Promise<any> | any;
|
|
695
|
+
|
|
696
|
+
export interface GraphQLResolverOptions {
|
|
697
|
+
validate?: (variables: Record<string, any>) => Promise<{ valid: boolean; errors?: string[] }>;
|
|
698
|
+
authorize?: (context: GraphQLContext) => Promise<boolean>;
|
|
699
|
+
cache?: {
|
|
700
|
+
get: (key: string) => Promise<any>;
|
|
701
|
+
set: (key: string, value: any, ttl?: number) => Promise<void>;
|
|
702
|
+
key?: (variables: Record<string, any>, context: GraphQLContext) => string;
|
|
703
|
+
ttl?: number;
|
|
704
|
+
};
|
|
705
|
+
errorHandler?: (error: Error, variables: Record<string, any>, context: GraphQLContext) => Promise<any>;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
export interface GraphQLServerOptions {
|
|
709
|
+
schema?: any;
|
|
710
|
+
resolvers?: {
|
|
711
|
+
Query?: Record<string, GraphQLResolver | { resolve: GraphQLResolver }>;
|
|
712
|
+
Mutation?: Record<string, GraphQLResolver | { resolve: GraphQLResolver }>;
|
|
713
|
+
[key: string]: any;
|
|
714
|
+
};
|
|
715
|
+
context?: (req: NavisRequest) => Promise<Record<string, any>> | Record<string, any>;
|
|
716
|
+
formatError?: (error: Error) => GraphQLError;
|
|
717
|
+
introspection?: boolean;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
export interface GraphQLHandlerOptions {
|
|
721
|
+
path?: string;
|
|
722
|
+
method?: string;
|
|
723
|
+
enableGET?: boolean;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
export interface GraphQLSchema {
|
|
727
|
+
type(name: string, definition: any): GraphQLSchema;
|
|
728
|
+
query(name: string, definition: any): GraphQLSchema;
|
|
729
|
+
mutation(name: string, definition: any): GraphQLSchema;
|
|
730
|
+
build(): string;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
export interface GraphQLTypes {
|
|
734
|
+
input(name: string, fields: Record<string, string>): string;
|
|
735
|
+
list(type: string): string;
|
|
736
|
+
required(type: string): string;
|
|
737
|
+
requiredList(type: string): string;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
export interface GraphQLScalars {
|
|
741
|
+
String: string;
|
|
742
|
+
Int: string;
|
|
743
|
+
Float: string;
|
|
744
|
+
Boolean: string;
|
|
745
|
+
ID: string;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
export interface GraphQLAsyncResolverOptions {
|
|
749
|
+
maxRetries?: number;
|
|
750
|
+
retryDelay?: number;
|
|
751
|
+
retryCondition?: (error: Error) => boolean;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
export interface GraphQLBatchResolverOptions {
|
|
755
|
+
batchKey?: (variables: Record<string, any>) => string;
|
|
756
|
+
batchSize?: number;
|
|
757
|
+
waitTime?: number;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
export const GraphQLServer: {
|
|
761
|
+
new (options?: GraphQLServerOptions): GraphQLServer;
|
|
762
|
+
};
|
|
763
|
+
|
|
764
|
+
export interface GraphQLServer {
|
|
765
|
+
handler(options?: GraphQLHandlerOptions): Middleware;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
export const GraphQLSchema: {
|
|
769
|
+
new (): GraphQLSchema;
|
|
770
|
+
};
|
|
771
|
+
|
|
772
|
+
export const GraphQLError: {
|
|
773
|
+
new (message: string, code?: string, extensions?: Record<string, any>): Error;
|
|
774
|
+
};
|
|
775
|
+
|
|
659
776
|
// Functions
|
|
660
777
|
export function retry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
|
|
661
778
|
export function shouldRetryHttpStatus(statusCode: number): boolean;
|
|
@@ -686,6 +803,19 @@ export function gracefulShutdown(server: any, options?: GracefulShutdownOptions)
|
|
|
686
803
|
export function getPool(): ServiceClientPool;
|
|
687
804
|
export function createLazyInit(initFn: () => Promise<any>, options?: LazyInitOptions): LazyInit;
|
|
688
805
|
export function coldStartTracker(): Middleware;
|
|
806
|
+
export function createGraphQLServer(options?: GraphQLServerOptions): GraphQLServer;
|
|
807
|
+
export function graphql(options?: GraphQLServerOptions): Middleware;
|
|
808
|
+
export function createSchema(): GraphQLSchema;
|
|
809
|
+
export function type(name: string, definition: any): GraphQLSchema;
|
|
810
|
+
export function createResolver<T = any>(resolverFn: GraphQLResolver, options?: GraphQLResolverOptions): GraphQLResolver;
|
|
811
|
+
export function fieldResolver(fieldName: string, resolverFn: GraphQLResolver): Record<string, GraphQLResolver>;
|
|
812
|
+
export function combineResolvers(...resolvers: any[]): any;
|
|
813
|
+
export function createAsyncResolver(resolverFn: GraphQLResolver, options?: GraphQLAsyncResolverOptions): GraphQLResolver;
|
|
814
|
+
export function createBatchResolver(resolverFn: GraphQLResolver, options?: GraphQLBatchResolverOptions): GraphQLResolver;
|
|
815
|
+
|
|
816
|
+
// GraphQL Constants
|
|
817
|
+
export const scalars: GraphQLScalars;
|
|
818
|
+
export const types: GraphQLTypes;
|
|
689
819
|
|
|
690
820
|
// Error Classes
|
|
691
821
|
export class ValidationError extends Error {
|