@fluojs/graphql 1.0.0-beta.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/LICENSE +21 -0
- package/README.ko.md +158 -0
- package/README.md +158 -0
- package/dist/dataloader/dataloader.d.ts +127 -0
- package/dist/dataloader/dataloader.d.ts.map +1 -0
- package/dist/dataloader/dataloader.js +151 -0
- package/dist/dataloader.d.ts +2 -0
- package/dist/dataloader.d.ts.map +1 -0
- package/dist/dataloader.js +1 -0
- package/dist/decorators.d.ts +21 -0
- package/dist/decorators.d.ts.map +1 -0
- package/dist/decorators.js +111 -0
- package/dist/discovery.d.ts +4 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +142 -0
- package/dist/guardrails.d.ts +35 -0
- package/dist/guardrails.d.ts.map +1 -0
- package/dist/guardrails.js +162 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/internal-tokens.d.ts +7 -0
- package/dist/internal-tokens.d.ts.map +1 -0
- package/dist/internal-tokens.js +4 -0
- package/dist/metadata.d.ts +20 -0
- package/dist/metadata.d.ts.map +1 -0
- package/dist/metadata.js +120 -0
- package/dist/module.d.ts +22 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +33 -0
- package/dist/pipeline/input-pipeline.d.ts +34 -0
- package/dist/pipeline/input-pipeline.d.ts.map +1 -0
- package/dist/pipeline/input-pipeline.js +129 -0
- package/dist/schema/schema.d.ts +20 -0
- package/dist/schema/schema.d.ts.map +1 -0
- package/dist/schema/schema.js +278 -0
- package/dist/service.d.ts +58 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +602 -0
- package/dist/transport/transport.d.ts +5 -0
- package/dist/transport/transport.d.ts.map +1 -0
- package/dist/transport/transport.js +119 -0
- package/dist/types.d.ts +221 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +132 -0
- package/package.json +61 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
export function isGraphqlPath(path) {
|
|
2
|
+
return path === '/graphql' || path === '/graphql/';
|
|
3
|
+
}
|
|
4
|
+
function resolveAbsoluteRequestUrl(request) {
|
|
5
|
+
const hostHeader = request.headers.host;
|
|
6
|
+
const host = Array.isArray(hostHeader) ? hostHeader[0] : hostHeader;
|
|
7
|
+
const protoHeader = request.headers['x-forwarded-proto'];
|
|
8
|
+
const protoValue = Array.isArray(protoHeader) ? protoHeader[0] : protoHeader;
|
|
9
|
+
const proto = typeof protoValue === 'string' && protoValue.length > 0 ? protoValue : 'http';
|
|
10
|
+
const base = `${proto}://${host ?? 'localhost'}`;
|
|
11
|
+
return new URL(request.url || request.path || '/graphql', base).toString();
|
|
12
|
+
}
|
|
13
|
+
function createFetchHeaders(request) {
|
|
14
|
+
const headers = new Headers();
|
|
15
|
+
for (const [name, value] of Object.entries(request.headers)) {
|
|
16
|
+
if (value === undefined) {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
if (Array.isArray(value)) {
|
|
20
|
+
for (const item of value) {
|
|
21
|
+
headers.append(name, item);
|
|
22
|
+
}
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (typeof value === 'string') {
|
|
26
|
+
headers.set(name, value);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return headers;
|
|
30
|
+
}
|
|
31
|
+
function createFetchBody(request, headers) {
|
|
32
|
+
const method = request.method.toUpperCase();
|
|
33
|
+
if (method === 'GET' || method === 'HEAD') {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
if (request.rawBody) {
|
|
37
|
+
return Buffer.from(request.rawBody);
|
|
38
|
+
}
|
|
39
|
+
if (request.body === undefined) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
if (typeof request.body === 'string') {
|
|
43
|
+
return request.body;
|
|
44
|
+
}
|
|
45
|
+
if (request.body instanceof Uint8Array) {
|
|
46
|
+
return Buffer.from(request.body);
|
|
47
|
+
}
|
|
48
|
+
if (request.body instanceof ArrayBuffer) {
|
|
49
|
+
return Buffer.from(request.body);
|
|
50
|
+
}
|
|
51
|
+
if (!headers.has('content-type')) {
|
|
52
|
+
headers.set('content-type', 'application/json; charset=utf-8');
|
|
53
|
+
}
|
|
54
|
+
return JSON.stringify(request.body);
|
|
55
|
+
}
|
|
56
|
+
export function toFetchRequest(request) {
|
|
57
|
+
const headers = createFetchHeaders(request);
|
|
58
|
+
const body = createFetchBody(request, headers);
|
|
59
|
+
return new Request(resolveAbsoluteRequestUrl(request), {
|
|
60
|
+
body,
|
|
61
|
+
headers,
|
|
62
|
+
method: request.method,
|
|
63
|
+
signal: request.signal
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function readSetCookieValues(headers) {
|
|
67
|
+
const setCookieHeaders = headers;
|
|
68
|
+
if (typeof setCookieHeaders.getSetCookie === 'function') {
|
|
69
|
+
return setCookieHeaders.getSetCookie();
|
|
70
|
+
}
|
|
71
|
+
const values = [];
|
|
72
|
+
for (const [name, value] of headers.entries()) {
|
|
73
|
+
if (name.toLowerCase() === 'set-cookie') {
|
|
74
|
+
values.push(value);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return values;
|
|
78
|
+
}
|
|
79
|
+
export async function writeFetchResponse(fetchResponse, frameworkResponse) {
|
|
80
|
+
frameworkResponse.setStatus(fetchResponse.status);
|
|
81
|
+
const setCookieValues = readSetCookieValues(fetchResponse.headers);
|
|
82
|
+
for (const value of setCookieValues) {
|
|
83
|
+
frameworkResponse.setHeader('set-cookie', value);
|
|
84
|
+
}
|
|
85
|
+
for (const [name, value] of fetchResponse.headers.entries()) {
|
|
86
|
+
if (name.toLowerCase() === 'set-cookie') {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
frameworkResponse.setHeader(name, value);
|
|
90
|
+
}
|
|
91
|
+
const stream = frameworkResponse.stream;
|
|
92
|
+
if (fetchResponse.body && stream) {
|
|
93
|
+
frameworkResponse.committed = true;
|
|
94
|
+
stream.flush?.();
|
|
95
|
+
const reader = fetchResponse.body.getReader();
|
|
96
|
+
while (true) {
|
|
97
|
+
const {
|
|
98
|
+
done,
|
|
99
|
+
value
|
|
100
|
+
} = await reader.read();
|
|
101
|
+
if (done) {
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
if (stream.closed) {
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
const canContinue = stream.write(value);
|
|
108
|
+
if (!canContinue && !stream.closed) {
|
|
109
|
+
await stream.waitForDrain?.();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (!stream.closed) {
|
|
113
|
+
stream.close();
|
|
114
|
+
}
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const buffer = await fetchResponse.arrayBuffer();
|
|
118
|
+
await frameworkResponse.send(new Uint8Array(buffer));
|
|
119
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import type { MetadataPropertyKey, Token } from '@fluojs/core';
|
|
2
|
+
import type { Container } from '@fluojs/di';
|
|
3
|
+
import type { FrameworkRequest, Principal } from '@fluojs/http';
|
|
4
|
+
import type { GraphQLObjectType, GraphQLSchema, GraphQLUnionType } from 'graphql';
|
|
5
|
+
/**
|
|
6
|
+
* GraphQL context key that stores the per-operation DI container.
|
|
7
|
+
*
|
|
8
|
+
* Resolvers can use this symbol indirectly through framework helpers when they
|
|
9
|
+
* need request-scoped provider resolution inside one GraphQL operation.
|
|
10
|
+
*/
|
|
11
|
+
export declare const GRAPHQL_OPERATION_CONTAINER: unique symbol;
|
|
12
|
+
/**
|
|
13
|
+
* GraphQL context key that stores the per-operation DataLoader cache.
|
|
14
|
+
*
|
|
15
|
+
* `createDataLoader(...)` and related helpers use this cache so singleton
|
|
16
|
+
* resolvers still get loader isolation per GraphQL operation.
|
|
17
|
+
*/
|
|
18
|
+
export declare const GRAPHQL_REQUEST_SCOPED_LOADER_CACHE: unique symbol;
|
|
19
|
+
/**
|
|
20
|
+
* Minimal request information exposed to GraphQL context factories.
|
|
21
|
+
*/
|
|
22
|
+
export interface GraphqlRequestContext {
|
|
23
|
+
request: FrameworkRequest;
|
|
24
|
+
connectionParams?: Record<string, unknown>;
|
|
25
|
+
principal?: Principal;
|
|
26
|
+
socket?: unknown;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Mutable GraphQL execution context shared across resolvers for one operation.
|
|
30
|
+
*
|
|
31
|
+
* @remarks
|
|
32
|
+
* This context always includes the underlying Fluo request and may carry the
|
|
33
|
+
* operation DI container, request-scoped DataLoader cache, subscription socket,
|
|
34
|
+
* and user-defined values returned from `GraphqlModule.forRoot({ context })`.
|
|
35
|
+
*/
|
|
36
|
+
export interface GraphQLContext {
|
|
37
|
+
request: FrameworkRequest;
|
|
38
|
+
connectionParams?: Record<string, unknown>;
|
|
39
|
+
principal?: Principal;
|
|
40
|
+
[GRAPHQL_OPERATION_CONTAINER]?: Container;
|
|
41
|
+
[GRAPHQL_REQUEST_SCOPED_LOADER_CACHE]?: Map<string | symbol, unknown>;
|
|
42
|
+
[key: string]: unknown;
|
|
43
|
+
socket?: unknown;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Budget settings applied to the optional GraphQL websocket transport.
|
|
47
|
+
*/
|
|
48
|
+
export interface GraphqlWebSocketLimitsOptions {
|
|
49
|
+
/**
|
|
50
|
+
* Maximum number of concurrently connected websocket clients.
|
|
51
|
+
*
|
|
52
|
+
* Set to `false` through `subscriptions.websocket.limits = false` to opt out of
|
|
53
|
+
* the built-in connection budget entirely.
|
|
54
|
+
*/
|
|
55
|
+
maxConnections?: number;
|
|
56
|
+
/**
|
|
57
|
+
* Maximum websocket frame payload size accepted from one client, in bytes.
|
|
58
|
+
*/
|
|
59
|
+
maxPayloadBytes?: number;
|
|
60
|
+
/**
|
|
61
|
+
* Maximum number of active GraphQL operations allowed on one websocket connection.
|
|
62
|
+
*/
|
|
63
|
+
maxOperationsPerConnection?: number;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* WebSocket-specific subscription settings for `GraphqlModule`.
|
|
67
|
+
*/
|
|
68
|
+
export interface GraphqlWebSocketSubscriptionsOptions {
|
|
69
|
+
connectionInitWaitTimeoutMs?: number;
|
|
70
|
+
enabled?: boolean;
|
|
71
|
+
keepAliveMs?: number;
|
|
72
|
+
/**
|
|
73
|
+
* Configures built-in websocket hardening budgets for connection count,
|
|
74
|
+
* payload size, and concurrent operations.
|
|
75
|
+
*
|
|
76
|
+
* Pass `false` to disable these websocket-specific guardrails and preserve
|
|
77
|
+
* legacy unbounded transport behavior.
|
|
78
|
+
*/
|
|
79
|
+
limits?: GraphqlWebSocketLimitsOptions | false;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Subscription transport settings for the GraphQL runtime.
|
|
83
|
+
*/
|
|
84
|
+
export interface GraphqlSubscriptionsOptions {
|
|
85
|
+
websocket?: GraphqlWebSocketSubscriptionsOptions;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Per-request validation budgets enforced before GraphQL execution begins.
|
|
89
|
+
*/
|
|
90
|
+
export interface GraphqlRequestLimitsOptions {
|
|
91
|
+
maxComplexity?: number;
|
|
92
|
+
maxCost?: number;
|
|
93
|
+
maxDepth?: number;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Resolver-level metadata captured by `@Resolver(...)`.
|
|
97
|
+
*/
|
|
98
|
+
export interface ResolverMetadata {
|
|
99
|
+
typeName: string;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Supported GraphQL operation handler categories.
|
|
103
|
+
*/
|
|
104
|
+
export type ResolverHandlerType = 'query' | 'mutation' | 'subscription';
|
|
105
|
+
/**
|
|
106
|
+
* Scalar names supported by the code-first schema helpers.
|
|
107
|
+
*/
|
|
108
|
+
export type GraphqlScalarTypeName = 'string' | 'int' | 'float' | 'boolean' | 'id';
|
|
109
|
+
/**
|
|
110
|
+
* Wrapper used by `listOf(...)` to describe GraphQL list output or argument types.
|
|
111
|
+
*/
|
|
112
|
+
export interface GraphqlListTypeRef<TType> {
|
|
113
|
+
kind: 'list';
|
|
114
|
+
ofType: TType;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Wrap a scalar or root output type reference as a GraphQL list type.
|
|
118
|
+
*
|
|
119
|
+
* @typeParam TType Item type carried by the list wrapper.
|
|
120
|
+
* @param ofType Scalar or object type reference for each list entry.
|
|
121
|
+
* @returns A lightweight marker object understood by the GraphQL schema builder.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```ts
|
|
125
|
+
* @Query({ outputType: listOf('string') })
|
|
126
|
+
* listTags() {
|
|
127
|
+
* return ['framework', 'typescript'];
|
|
128
|
+
* }
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
export declare function listOf<TType>(ofType: TType): GraphqlListTypeRef<TType>;
|
|
132
|
+
/**
|
|
133
|
+
* Check whether a value is a `listOf(...)` wrapper understood by the schema builder.
|
|
134
|
+
*
|
|
135
|
+
* @param value Unknown value to inspect.
|
|
136
|
+
* @returns `true` when the value is a GraphQL list type wrapper.
|
|
137
|
+
*/
|
|
138
|
+
export declare function isGraphqlListTypeRef(value: unknown): value is GraphqlListTypeRef<unknown>;
|
|
139
|
+
/**
|
|
140
|
+
* Supported argument type references for resolver parameters.
|
|
141
|
+
*/
|
|
142
|
+
export type GraphqlArgType = GraphqlScalarTypeName | GraphqlListTypeRef<GraphqlScalarTypeName>;
|
|
143
|
+
/**
|
|
144
|
+
* Named output types allowed at the root query, mutation, and subscription level.
|
|
145
|
+
*/
|
|
146
|
+
export type GraphqlRootOutputNamedType = GraphqlScalarTypeName | GraphQLObjectType | GraphQLUnionType;
|
|
147
|
+
/**
|
|
148
|
+
* Root output type references accepted by resolver metadata.
|
|
149
|
+
*/
|
|
150
|
+
export type GraphqlRootOutputType = GraphqlRootOutputNamedType | GraphqlListTypeRef<GraphqlRootOutputNamedType>;
|
|
151
|
+
/**
|
|
152
|
+
* Operation-level metadata captured from `@Query(...)`, `@Mutation(...)`, and `@Subscription(...)`.
|
|
153
|
+
*/
|
|
154
|
+
export interface ResolverHandlerMetadata {
|
|
155
|
+
type: ResolverHandlerType;
|
|
156
|
+
fieldName?: string;
|
|
157
|
+
topics?: string | string[];
|
|
158
|
+
inputClass?: Function;
|
|
159
|
+
argTypes?: Record<string, GraphqlArgType>;
|
|
160
|
+
outputType?: GraphqlRootOutputType;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Describes how one method parameter maps to a named GraphQL argument.
|
|
164
|
+
*/
|
|
165
|
+
export interface ArgFieldMetadata {
|
|
166
|
+
argName: string;
|
|
167
|
+
fieldName: string;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Normalized resolver method descriptor used during schema discovery.
|
|
171
|
+
*/
|
|
172
|
+
export interface ResolverHandlerDescriptor {
|
|
173
|
+
type: ResolverHandlerType;
|
|
174
|
+
methodKey: MetadataPropertyKey;
|
|
175
|
+
methodName: string;
|
|
176
|
+
fieldName: string;
|
|
177
|
+
topics?: string | string[];
|
|
178
|
+
inputClass?: Function;
|
|
179
|
+
argFields: ArgFieldMetadata[];
|
|
180
|
+
argTypes?: Record<string, GraphqlArgType>;
|
|
181
|
+
outputType?: GraphqlRootOutputType;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Fully discovered resolver descriptor used by the GraphQL runtime.
|
|
185
|
+
*/
|
|
186
|
+
export interface ResolverDescriptor {
|
|
187
|
+
typeName: string;
|
|
188
|
+
handlers: ResolverHandlerDescriptor[];
|
|
189
|
+
token: Token;
|
|
190
|
+
targetName: string;
|
|
191
|
+
moduleName: string;
|
|
192
|
+
scope: 'singleton' | 'request' | 'transient';
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Public options for `GraphqlModule.forRoot(...)` and `forRootAsync(...)`.
|
|
196
|
+
*
|
|
197
|
+
* @remarks
|
|
198
|
+
* Keep README examples for end-to-end module wiring. Source hover docs here are
|
|
199
|
+
* meant to clarify how each option shapes the per-request execution pipeline.
|
|
200
|
+
*/
|
|
201
|
+
export interface GraphqlModuleOptions {
|
|
202
|
+
schema?: GraphQLSchema | string;
|
|
203
|
+
resolvers?: Function[];
|
|
204
|
+
context?: (ctx: GraphqlRequestContext) => Record<string, unknown>;
|
|
205
|
+
graphiql?: boolean;
|
|
206
|
+
/**
|
|
207
|
+
* Enables schema introspection queries.
|
|
208
|
+
*
|
|
209
|
+
* When omitted, introspection remains disabled unless `graphiql` is explicitly enabled.
|
|
210
|
+
*/
|
|
211
|
+
introspection?: boolean;
|
|
212
|
+
/**
|
|
213
|
+
* Configures built-in request budgets for document depth, field complexity, and aggregate query cost.
|
|
214
|
+
*
|
|
215
|
+
* Pass `false` to disable these guardrails and preserve legacy unbounded behavior.
|
|
216
|
+
*/
|
|
217
|
+
limits?: GraphqlRequestLimitsOptions | false;
|
|
218
|
+
plugins?: unknown[];
|
|
219
|
+
subscriptions?: GraphqlSubscriptionsOptions;
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAElF;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,eAAiD,CAAC;AAE1F;;;;;GAKG;AACH,eAAO,MAAM,mCAAmC,eAAyD,CAAC;AAE1G;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,gBAAgB,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3C,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,gBAAgB,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3C,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,CAAC,2BAA2B,CAAC,CAAC,EAAE,SAAS,CAAC;IAC1C,CAAC,mCAAmC,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC,CAAC;IACtE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,6BAA6B;IAC5C;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;OAEG;IACH,0BAA0B,CAAC,EAAE,MAAM,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,oCAAoC;IACnD,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,6BAA6B,GAAG,KAAK,CAAC;CAChD;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,SAAS,CAAC,EAAE,oCAAoC,CAAC;CAClD;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,UAAU,GAAG,cAAc,CAAC;AAExE;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,QAAQ,GAAG,KAAK,GAAG,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC;AAElF;;GAEG;AACH,MAAM,WAAW,kBAAkB,CAAC,KAAK;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,KAAK,CAAC;CACf;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAKtE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,kBAAkB,CAAC,OAAO,CAAC,CAOzF;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,qBAAqB,GAAG,kBAAkB,CAAC,qBAAqB,CAAC,CAAC;AAE/F;;GAEG;AACH,MAAM,MAAM,0BAA0B,GAAG,qBAAqB,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;AAEtG;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,0BAA0B,GAAG,kBAAkB,CAAC,0BAA0B,CAAC,CAAC;AAEhH;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,mBAAmB,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE,QAAQ,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC1C,UAAU,CAAC,EAAE,qBAAqB,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,mBAAmB,CAAC;IAC1B,SAAS,EAAE,mBAAmB,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE,QAAQ,CAAC;IACtB,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC1C,UAAU,CAAC,EAAE,qBAAqB,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,yBAAyB,EAAE,CAAC;IACtC,KAAK,EAAE,KAAK,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,WAAW,GAAG,SAAS,GAAG,WAAW,CAAC;CAC9C;AAED;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC;IAChC,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;OAIG;IACH,MAAM,CAAC,EAAE,2BAA2B,GAAG,KAAK,CAAC;IAC7C,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,aAAa,CAAC,EAAE,2BAA2B,CAAC;CAC7C"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GraphQL context key that stores the per-operation DI container.
|
|
3
|
+
*
|
|
4
|
+
* Resolvers can use this symbol indirectly through framework helpers when they
|
|
5
|
+
* need request-scoped provider resolution inside one GraphQL operation.
|
|
6
|
+
*/
|
|
7
|
+
export const GRAPHQL_OPERATION_CONTAINER = Symbol.for('fluo.graphql.operation.container');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* GraphQL context key that stores the per-operation DataLoader cache.
|
|
11
|
+
*
|
|
12
|
+
* `createDataLoader(...)` and related helpers use this cache so singleton
|
|
13
|
+
* resolvers still get loader isolation per GraphQL operation.
|
|
14
|
+
*/
|
|
15
|
+
export const GRAPHQL_REQUEST_SCOPED_LOADER_CACHE = Symbol.for('fluo.graphql.request_scoped_loader_cache');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Minimal request information exposed to GraphQL context factories.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Mutable GraphQL execution context shared across resolvers for one operation.
|
|
23
|
+
*
|
|
24
|
+
* @remarks
|
|
25
|
+
* This context always includes the underlying Fluo request and may carry the
|
|
26
|
+
* operation DI container, request-scoped DataLoader cache, subscription socket,
|
|
27
|
+
* and user-defined values returned from `GraphqlModule.forRoot({ context })`.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Budget settings applied to the optional GraphQL websocket transport.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* WebSocket-specific subscription settings for `GraphqlModule`.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Subscription transport settings for the GraphQL runtime.
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Per-request validation budgets enforced before GraphQL execution begins.
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Resolver-level metadata captured by `@Resolver(...)`.
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Supported GraphQL operation handler categories.
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Scalar names supported by the code-first schema helpers.
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Wrapper used by `listOf(...)` to describe GraphQL list output or argument types.
|
|
60
|
+
*/
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Wrap a scalar or root output type reference as a GraphQL list type.
|
|
64
|
+
*
|
|
65
|
+
* @typeParam TType Item type carried by the list wrapper.
|
|
66
|
+
* @param ofType Scalar or object type reference for each list entry.
|
|
67
|
+
* @returns A lightweight marker object understood by the GraphQL schema builder.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* @Query({ outputType: listOf('string') })
|
|
72
|
+
* listTags() {
|
|
73
|
+
* return ['framework', 'typescript'];
|
|
74
|
+
* }
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export function listOf(ofType) {
|
|
78
|
+
return {
|
|
79
|
+
kind: 'list',
|
|
80
|
+
ofType
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Check whether a value is a `listOf(...)` wrapper understood by the schema builder.
|
|
86
|
+
*
|
|
87
|
+
* @param value Unknown value to inspect.
|
|
88
|
+
* @returns `true` when the value is a GraphQL list type wrapper.
|
|
89
|
+
*/
|
|
90
|
+
export function isGraphqlListTypeRef(value) {
|
|
91
|
+
if (value === null || typeof value !== 'object') {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
const candidate = value;
|
|
95
|
+
return candidate.kind === 'list' && 'ofType' in candidate;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Supported argument type references for resolver parameters.
|
|
100
|
+
*/
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Named output types allowed at the root query, mutation, and subscription level.
|
|
104
|
+
*/
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Root output type references accepted by resolver metadata.
|
|
108
|
+
*/
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Operation-level metadata captured from `@Query(...)`, `@Mutation(...)`, and `@Subscription(...)`.
|
|
112
|
+
*/
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Describes how one method parameter maps to a named GraphQL argument.
|
|
116
|
+
*/
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Normalized resolver method descriptor used during schema discovery.
|
|
120
|
+
*/
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Fully discovered resolver descriptor used by the GraphQL runtime.
|
|
124
|
+
*/
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Public options for `GraphqlModule.forRoot(...)` and `forRootAsync(...)`.
|
|
128
|
+
*
|
|
129
|
+
* @remarks
|
|
130
|
+
* Keep README examples for end-to-end module wiring. Source hover docs here are
|
|
131
|
+
* meant to clarify how each option shapes the per-request execution pipeline.
|
|
132
|
+
*/
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fluojs/graphql",
|
|
3
|
+
"description": "Decorator-based GraphQL module, schema exposure, and execution pipeline for Fluo.",
|
|
4
|
+
"keywords": [
|
|
5
|
+
"fluo",
|
|
6
|
+
"graphql",
|
|
7
|
+
"resolver",
|
|
8
|
+
"schema",
|
|
9
|
+
"yoga",
|
|
10
|
+
"api"
|
|
11
|
+
],
|
|
12
|
+
"version": "1.0.0-beta.1",
|
|
13
|
+
"private": false,
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/fluojs/fluo.git",
|
|
18
|
+
"directory": "packages/graphql"
|
|
19
|
+
},
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=20.0.0"
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"type": "module",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"import": "./dist/index.js"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"main": "./dist/index.js",
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"files": [
|
|
36
|
+
"dist"
|
|
37
|
+
],
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"dataloader": "^2.2.3",
|
|
40
|
+
"graphql": "^16.13.1",
|
|
41
|
+
"graphql-ws": "^5.16.2",
|
|
42
|
+
"graphql-yoga": "^5.18.1",
|
|
43
|
+
"ws": "^8.18.3",
|
|
44
|
+
"@fluojs/core": "^1.0.0-beta.1",
|
|
45
|
+
"@fluojs/runtime": "^1.0.0-beta.1",
|
|
46
|
+
"@fluojs/di": "^1.0.0-beta.1",
|
|
47
|
+
"@fluojs/http": "^1.0.0-beta.1",
|
|
48
|
+
"@fluojs/validation": "^1.0.0-beta.1"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/ws": "^8.18.1",
|
|
52
|
+
"vitest": "^3.2.4"
|
|
53
|
+
},
|
|
54
|
+
"scripts": {
|
|
55
|
+
"prebuild": "node ../../tooling/scripts/clean-dist.mjs",
|
|
56
|
+
"build": "pnpm exec babel src --extensions .ts --ignore 'src/**/*.test.ts' --out-dir dist --config-file ../../tooling/babel/babel.config.cjs && pnpm exec tsc -p tsconfig.build.json",
|
|
57
|
+
"typecheck": "pnpm exec tsc -p tsconfig.json --noEmit",
|
|
58
|
+
"test": "pnpm exec vitest run -c vitest.config.ts",
|
|
59
|
+
"test:watch": "pnpm exec vitest -c vitest.config.ts"
|
|
60
|
+
}
|
|
61
|
+
}
|