@effect-gql/core 0.1.0 → 1.0.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/README.md +100 -0
- package/builder/index.cjs +1431 -0
- package/builder/index.cjs.map +1 -0
- package/builder/index.d.cts +259 -0
- package/{dist/builder/pipe-api.d.ts → builder/index.d.ts} +49 -21
- package/builder/index.js +1390 -0
- package/builder/index.js.map +1 -0
- package/index.cjs +3419 -0
- package/index.cjs.map +1 -0
- package/index.d.cts +523 -0
- package/index.d.ts +523 -0
- package/index.js +3242 -0
- package/index.js.map +1 -0
- package/package.json +19 -28
- package/schema-builder-Cvdq7Kz_.d.cts +963 -0
- package/schema-builder-Cvdq7Kz_.d.ts +963 -0
- package/server/index.cjs +1555 -0
- package/server/index.cjs.map +1 -0
- package/server/index.d.cts +680 -0
- package/server/index.d.ts +680 -0
- package/server/index.js +1524 -0
- package/server/index.js.map +1 -0
- package/dist/analyzer-extension.d.ts +0 -105
- package/dist/analyzer-extension.d.ts.map +0 -1
- package/dist/analyzer-extension.js +0 -137
- package/dist/analyzer-extension.js.map +0 -1
- package/dist/builder/execute.d.ts +0 -26
- package/dist/builder/execute.d.ts.map +0 -1
- package/dist/builder/execute.js +0 -104
- package/dist/builder/execute.js.map +0 -1
- package/dist/builder/field-builders.d.ts +0 -30
- package/dist/builder/field-builders.d.ts.map +0 -1
- package/dist/builder/field-builders.js +0 -200
- package/dist/builder/field-builders.js.map +0 -1
- package/dist/builder/index.d.ts +0 -7
- package/dist/builder/index.d.ts.map +0 -1
- package/dist/builder/index.js +0 -31
- package/dist/builder/index.js.map +0 -1
- package/dist/builder/pipe-api.d.ts.map +0 -1
- package/dist/builder/pipe-api.js +0 -151
- package/dist/builder/pipe-api.js.map +0 -1
- package/dist/builder/schema-builder.d.ts +0 -301
- package/dist/builder/schema-builder.d.ts.map +0 -1
- package/dist/builder/schema-builder.js +0 -566
- package/dist/builder/schema-builder.js.map +0 -1
- package/dist/builder/type-registry.d.ts +0 -80
- package/dist/builder/type-registry.d.ts.map +0 -1
- package/dist/builder/type-registry.js +0 -505
- package/dist/builder/type-registry.js.map +0 -1
- package/dist/builder/types.d.ts +0 -283
- package/dist/builder/types.d.ts.map +0 -1
- package/dist/builder/types.js +0 -3
- package/dist/builder/types.js.map +0 -1
- package/dist/cli/generate-schema.d.ts +0 -29
- package/dist/cli/generate-schema.d.ts.map +0 -1
- package/dist/cli/generate-schema.js +0 -233
- package/dist/cli/generate-schema.js.map +0 -1
- package/dist/cli/index.d.ts +0 -19
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/index.js +0 -24
- package/dist/cli/index.js.map +0 -1
- package/dist/context.d.ts +0 -18
- package/dist/context.d.ts.map +0 -1
- package/dist/context.js +0 -11
- package/dist/context.js.map +0 -1
- package/dist/error.d.ts +0 -45
- package/dist/error.d.ts.map +0 -1
- package/dist/error.js +0 -29
- package/dist/error.js.map +0 -1
- package/dist/extensions.d.ts +0 -130
- package/dist/extensions.d.ts.map +0 -1
- package/dist/extensions.js +0 -78
- package/dist/extensions.js.map +0 -1
- package/dist/index.d.ts +0 -12
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -47
- package/dist/index.js.map +0 -1
- package/dist/loader.d.ts +0 -169
- package/dist/loader.d.ts.map +0 -1
- package/dist/loader.js +0 -237
- package/dist/loader.js.map +0 -1
- package/dist/resolver-context.d.ts +0 -154
- package/dist/resolver-context.d.ts.map +0 -1
- package/dist/resolver-context.js +0 -184
- package/dist/resolver-context.js.map +0 -1
- package/dist/schema-mapping.d.ts +0 -30
- package/dist/schema-mapping.d.ts.map +0 -1
- package/dist/schema-mapping.js +0 -280
- package/dist/schema-mapping.js.map +0 -1
- package/dist/server/cache-control.d.ts +0 -96
- package/dist/server/cache-control.d.ts.map +0 -1
- package/dist/server/cache-control.js +0 -308
- package/dist/server/cache-control.js.map +0 -1
- package/dist/server/complexity.d.ts +0 -165
- package/dist/server/complexity.d.ts.map +0 -1
- package/dist/server/complexity.js +0 -433
- package/dist/server/complexity.js.map +0 -1
- package/dist/server/config.d.ts +0 -66
- package/dist/server/config.d.ts.map +0 -1
- package/dist/server/config.js +0 -104
- package/dist/server/config.js.map +0 -1
- package/dist/server/graphiql.d.ts +0 -5
- package/dist/server/graphiql.d.ts.map +0 -1
- package/dist/server/graphiql.js +0 -43
- package/dist/server/graphiql.js.map +0 -1
- package/dist/server/index.d.ts +0 -18
- package/dist/server/index.d.ts.map +0 -1
- package/dist/server/index.js +0 -48
- package/dist/server/index.js.map +0 -1
- package/dist/server/router.d.ts +0 -79
- package/dist/server/router.d.ts.map +0 -1
- package/dist/server/router.js +0 -232
- package/dist/server/router.js.map +0 -1
- package/dist/server/schema-builder-extensions.d.ts +0 -42
- package/dist/server/schema-builder-extensions.d.ts.map +0 -1
- package/dist/server/schema-builder-extensions.js +0 -48
- package/dist/server/schema-builder-extensions.js.map +0 -1
- package/dist/server/sse-adapter.d.ts +0 -64
- package/dist/server/sse-adapter.d.ts.map +0 -1
- package/dist/server/sse-adapter.js +0 -227
- package/dist/server/sse-adapter.js.map +0 -1
- package/dist/server/sse-types.d.ts +0 -192
- package/dist/server/sse-types.d.ts.map +0 -1
- package/dist/server/sse-types.js +0 -63
- package/dist/server/sse-types.js.map +0 -1
- package/dist/server/ws-adapter.d.ts +0 -39
- package/dist/server/ws-adapter.d.ts.map +0 -1
- package/dist/server/ws-adapter.js +0 -247
- package/dist/server/ws-adapter.js.map +0 -1
- package/dist/server/ws-types.d.ts +0 -169
- package/dist/server/ws-types.d.ts.map +0 -1
- package/dist/server/ws-types.js +0 -11
- package/dist/server/ws-types.js.map +0 -1
- package/dist/server/ws-utils.d.ts +0 -42
- package/dist/server/ws-utils.d.ts.map +0 -1
- package/dist/server/ws-utils.js +0 -99
- package/dist/server/ws-utils.js.map +0 -1
- package/src/analyzer-extension.ts +0 -254
- package/src/builder/execute.ts +0 -153
- package/src/builder/field-builders.ts +0 -322
- package/src/builder/index.ts +0 -48
- package/src/builder/pipe-api.ts +0 -312
- package/src/builder/schema-builder.ts +0 -970
- package/src/builder/type-registry.ts +0 -670
- package/src/builder/types.ts +0 -305
- package/src/context.ts +0 -23
- package/src/error.ts +0 -32
- package/src/extensions.ts +0 -240
- package/src/index.ts +0 -32
- package/src/loader.ts +0 -363
- package/src/resolver-context.ts +0 -253
- package/src/schema-mapping.ts +0 -307
- package/src/server/cache-control.ts +0 -590
- package/src/server/complexity.ts +0 -774
- package/src/server/config.ts +0 -174
- package/src/server/graphiql.ts +0 -38
- package/src/server/index.ts +0 -96
- package/src/server/router.ts +0 -432
- package/src/server/schema-builder-extensions.ts +0 -51
- package/src/server/sse-adapter.ts +0 -327
- package/src/server/sse-types.ts +0 -234
- package/src/server/ws-adapter.ts +0 -355
- package/src/server/ws-types.ts +0 -192
- package/src/server/ws-utils.ts +0 -136
|
@@ -0,0 +1,963 @@
|
|
|
1
|
+
import * as effect from 'effect';
|
|
2
|
+
import { Effect, Config, Stream, Runtime, Context, Pipeable } from 'effect';
|
|
3
|
+
import * as S from 'effect/Schema';
|
|
4
|
+
import * as graphql from 'graphql';
|
|
5
|
+
import { DocumentNode, OperationDefinitionNode, GraphQLSchema, DirectiveLocation, GraphQLResolveInfo, GraphQLError, ExecutionResult } from 'graphql';
|
|
6
|
+
import * as effect_Cause from 'effect/Cause';
|
|
7
|
+
import * as effect_Types from 'effect/Types';
|
|
8
|
+
|
|
9
|
+
declare const ComplexityLimitExceededError_base: new <A extends Record<string, any> = {}>(args: effect_Types.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => effect_Cause.YieldableError & {
|
|
10
|
+
readonly _tag: "ComplexityLimitExceededError";
|
|
11
|
+
} & Readonly<A>;
|
|
12
|
+
/**
|
|
13
|
+
* Error thrown when query complexity exceeds configured limits
|
|
14
|
+
*/
|
|
15
|
+
declare class ComplexityLimitExceededError extends ComplexityLimitExceededError_base<{
|
|
16
|
+
readonly message: string;
|
|
17
|
+
readonly limit: number;
|
|
18
|
+
readonly actual: number;
|
|
19
|
+
readonly limitType: "depth" | "complexity" | "aliases" | "fields";
|
|
20
|
+
}> {
|
|
21
|
+
}
|
|
22
|
+
declare const ComplexityAnalysisError_base: new <A extends Record<string, any> = {}>(args: effect_Types.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => effect_Cause.YieldableError & {
|
|
23
|
+
readonly _tag: "ComplexityAnalysisError";
|
|
24
|
+
} & Readonly<A>;
|
|
25
|
+
/**
|
|
26
|
+
* Error thrown when complexity analysis fails
|
|
27
|
+
*/
|
|
28
|
+
declare class ComplexityAnalysisError extends ComplexityAnalysisError_base<{
|
|
29
|
+
readonly message: string;
|
|
30
|
+
readonly cause?: unknown;
|
|
31
|
+
}> {
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Result of complexity analysis for a GraphQL operation
|
|
35
|
+
*/
|
|
36
|
+
interface ComplexityResult {
|
|
37
|
+
/** Maximum depth of the query */
|
|
38
|
+
readonly depth: number;
|
|
39
|
+
/** Total complexity score */
|
|
40
|
+
readonly complexity: number;
|
|
41
|
+
/** Number of field selections (including nested) */
|
|
42
|
+
readonly fieldCount: number;
|
|
43
|
+
/** Number of aliased fields */
|
|
44
|
+
readonly aliasCount: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Information provided to complexity calculators
|
|
48
|
+
*/
|
|
49
|
+
interface ComplexityAnalysisInfo {
|
|
50
|
+
/** Parsed GraphQL document */
|
|
51
|
+
readonly document: DocumentNode;
|
|
52
|
+
/** The operation being executed */
|
|
53
|
+
readonly operation: OperationDefinitionNode;
|
|
54
|
+
/** Variables provided with the query */
|
|
55
|
+
readonly variables?: Record<string, unknown>;
|
|
56
|
+
/** The GraphQL schema */
|
|
57
|
+
readonly schema: GraphQLSchema;
|
|
58
|
+
/** Field complexity definitions from the builder */
|
|
59
|
+
readonly fieldComplexities: FieldComplexityMap;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Information provided when complexity limit is exceeded
|
|
63
|
+
*/
|
|
64
|
+
interface ComplexityExceededInfo {
|
|
65
|
+
/** The computed complexity result */
|
|
66
|
+
readonly result: ComplexityResult;
|
|
67
|
+
/** Which limit was exceeded */
|
|
68
|
+
readonly exceededLimit: "depth" | "complexity" | "aliases" | "fields";
|
|
69
|
+
/** The limit value */
|
|
70
|
+
readonly limit: number;
|
|
71
|
+
/** The actual value */
|
|
72
|
+
readonly actual: number;
|
|
73
|
+
/** The query that exceeded limits */
|
|
74
|
+
readonly query: string;
|
|
75
|
+
/** Operation name if provided */
|
|
76
|
+
readonly operationName?: string;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Complexity value for a field - can be static or dynamic based on arguments
|
|
80
|
+
*/
|
|
81
|
+
type FieldComplexity = number | ((args: Record<string, unknown>) => number);
|
|
82
|
+
/**
|
|
83
|
+
* Map of type.field -> complexity
|
|
84
|
+
*/
|
|
85
|
+
type FieldComplexityMap = Map<string, FieldComplexity>;
|
|
86
|
+
/**
|
|
87
|
+
* Custom complexity calculator function.
|
|
88
|
+
* Must be self-contained (no service requirements).
|
|
89
|
+
*/
|
|
90
|
+
type ComplexityCalculator = (info: ComplexityAnalysisInfo) => Effect.Effect<ComplexityResult, ComplexityAnalysisError, never>;
|
|
91
|
+
/**
|
|
92
|
+
* Configuration for query complexity limiting
|
|
93
|
+
*/
|
|
94
|
+
interface ComplexityConfig {
|
|
95
|
+
/**
|
|
96
|
+
* Maximum allowed query depth.
|
|
97
|
+
* Depth is the deepest nesting level in the query.
|
|
98
|
+
* @example
|
|
99
|
+
* // Depth 3:
|
|
100
|
+
* // { user { posts { comments { text } } } }
|
|
101
|
+
*/
|
|
102
|
+
readonly maxDepth?: number;
|
|
103
|
+
/**
|
|
104
|
+
* Maximum allowed total complexity score.
|
|
105
|
+
* Complexity is calculated by summing field costs.
|
|
106
|
+
*/
|
|
107
|
+
readonly maxComplexity?: number;
|
|
108
|
+
/**
|
|
109
|
+
* Maximum number of field aliases allowed.
|
|
110
|
+
* Prevents response explosion attacks via aliases.
|
|
111
|
+
*/
|
|
112
|
+
readonly maxAliases?: number;
|
|
113
|
+
/**
|
|
114
|
+
* Maximum total number of fields in the query.
|
|
115
|
+
* Includes all nested field selections.
|
|
116
|
+
*/
|
|
117
|
+
readonly maxFields?: number;
|
|
118
|
+
/**
|
|
119
|
+
* Default complexity cost for fields without explicit costs.
|
|
120
|
+
* @default 1
|
|
121
|
+
*/
|
|
122
|
+
readonly defaultFieldComplexity?: number;
|
|
123
|
+
/**
|
|
124
|
+
* Custom complexity calculator.
|
|
125
|
+
* If provided, this is used instead of the default calculator.
|
|
126
|
+
* Can be used to implement custom cost algorithms.
|
|
127
|
+
*/
|
|
128
|
+
readonly calculator?: ComplexityCalculator;
|
|
129
|
+
/**
|
|
130
|
+
* Hook called when a limit is exceeded.
|
|
131
|
+
* Useful for logging, metrics, or custom handling.
|
|
132
|
+
* This is called BEFORE the error is thrown.
|
|
133
|
+
* Must be self-contained (no service requirements).
|
|
134
|
+
*/
|
|
135
|
+
readonly onExceeded?: (info: ComplexityExceededInfo) => Effect.Effect<void, never, never>;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Default complexity calculator that walks the AST and computes:
|
|
139
|
+
* - depth: Maximum nesting level
|
|
140
|
+
* - complexity: Sum of field costs
|
|
141
|
+
* - fieldCount: Total number of field selections
|
|
142
|
+
* - aliasCount: Number of aliased fields
|
|
143
|
+
*/
|
|
144
|
+
declare const defaultComplexityCalculator: (defaultCost?: number) => ComplexityCalculator;
|
|
145
|
+
/**
|
|
146
|
+
* Validate query complexity against configured limits.
|
|
147
|
+
* Returns the complexity result if within limits, or fails with ComplexityLimitExceededError.
|
|
148
|
+
*/
|
|
149
|
+
declare const validateComplexity: (query: string, operationName: string | undefined, variables: Record<string, unknown> | undefined, schema: GraphQLSchema, fieldComplexities: FieldComplexityMap, config: ComplexityConfig) => Effect.Effect<ComplexityResult, ComplexityLimitExceededError | ComplexityAnalysisError, never>;
|
|
150
|
+
/**
|
|
151
|
+
* Effect Config for loading complexity configuration from environment variables.
|
|
152
|
+
*
|
|
153
|
+
* Environment variables:
|
|
154
|
+
* - GRAPHQL_MAX_DEPTH: Maximum query depth
|
|
155
|
+
* - GRAPHQL_MAX_COMPLEXITY: Maximum complexity score
|
|
156
|
+
* - GRAPHQL_MAX_ALIASES: Maximum number of aliases
|
|
157
|
+
* - GRAPHQL_MAX_FIELDS: Maximum number of fields
|
|
158
|
+
* - GRAPHQL_DEFAULT_FIELD_COMPLEXITY: Default field complexity (default: 1)
|
|
159
|
+
*/
|
|
160
|
+
declare const ComplexityConfigFromEnv: Config.Config<ComplexityConfig>;
|
|
161
|
+
/**
|
|
162
|
+
* A simple depth-only calculator that only tracks query depth.
|
|
163
|
+
* Use this when you only care about depth limiting and want fast validation.
|
|
164
|
+
*/
|
|
165
|
+
declare const depthOnlyCalculator: ComplexityCalculator;
|
|
166
|
+
/**
|
|
167
|
+
* Combine multiple calculators - returns the maximum values from all calculators.
|
|
168
|
+
*/
|
|
169
|
+
declare const combineCalculators: (...calculators: ComplexityCalculator[]) => ComplexityCalculator;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Cache control scope determines whether a cached response can be shared.
|
|
173
|
+
* - PUBLIC: Response can be cached by CDNs and shared across users
|
|
174
|
+
* - PRIVATE: Response is user-specific and should only be cached in browsers
|
|
175
|
+
*/
|
|
176
|
+
type CacheControlScope = "PUBLIC" | "PRIVATE";
|
|
177
|
+
/**
|
|
178
|
+
* Cache control hint for a type or field.
|
|
179
|
+
* Used to compute the overall cache policy for a GraphQL response.
|
|
180
|
+
*/
|
|
181
|
+
interface CacheHint {
|
|
182
|
+
/**
|
|
183
|
+
* Maximum age in seconds that this field's value can be cached.
|
|
184
|
+
* The response's maxAge will be the minimum of all field maxAges.
|
|
185
|
+
*/
|
|
186
|
+
readonly maxAge?: number;
|
|
187
|
+
/**
|
|
188
|
+
* Whether the cached value is user-specific (PRIVATE) or shared (PUBLIC).
|
|
189
|
+
* If any field is PRIVATE, the entire response is PRIVATE.
|
|
190
|
+
*/
|
|
191
|
+
readonly scope?: CacheControlScope;
|
|
192
|
+
/**
|
|
193
|
+
* When true, this field inherits its maxAge from the parent field
|
|
194
|
+
* instead of using the default (which is 0 for root fields).
|
|
195
|
+
* Cannot be used together with maxAge.
|
|
196
|
+
*/
|
|
197
|
+
readonly inheritMaxAge?: boolean;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Configuration for a query or mutation field
|
|
201
|
+
*/
|
|
202
|
+
interface FieldRegistration<Args = any, A = any, E = any, R = any> {
|
|
203
|
+
type: S.Schema<A, any, any>;
|
|
204
|
+
args?: S.Schema<Args, any, any>;
|
|
205
|
+
description?: string;
|
|
206
|
+
directives?: readonly DirectiveApplication[];
|
|
207
|
+
/**
|
|
208
|
+
* Complexity cost of this field.
|
|
209
|
+
* Can be a static number or a function that receives the resolved arguments.
|
|
210
|
+
* Used for query complexity limiting.
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* // Static cost
|
|
214
|
+
* complexity: 5
|
|
215
|
+
*
|
|
216
|
+
* // Dynamic cost based on pagination
|
|
217
|
+
* complexity: (args) => args.limit * 2
|
|
218
|
+
*/
|
|
219
|
+
complexity?: FieldComplexity;
|
|
220
|
+
/**
|
|
221
|
+
* Cache control hint for this field.
|
|
222
|
+
* Used to compute HTTP Cache-Control headers for the response.
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* // Cache for 1 hour
|
|
226
|
+
* cacheControl: { maxAge: 3600 }
|
|
227
|
+
*
|
|
228
|
+
* // User-specific data, don't cache in CDN
|
|
229
|
+
* cacheControl: { maxAge: 60, scope: "PRIVATE" }
|
|
230
|
+
*/
|
|
231
|
+
cacheControl?: CacheHint;
|
|
232
|
+
resolve: (args: Args) => Effect.Effect<A, E, R>;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Configuration for an object type
|
|
236
|
+
*/
|
|
237
|
+
interface TypeRegistration {
|
|
238
|
+
name: string;
|
|
239
|
+
schema: S.Schema<any, any, any>;
|
|
240
|
+
implements?: readonly string[];
|
|
241
|
+
directives?: readonly DirectiveApplication[];
|
|
242
|
+
/**
|
|
243
|
+
* Default cache control hint for all fields returning this type.
|
|
244
|
+
* Can be overridden by field-level cacheControl.
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* // All User fields cacheable for 1 hour by default
|
|
248
|
+
* cacheControl: { maxAge: 3600 }
|
|
249
|
+
*/
|
|
250
|
+
cacheControl?: CacheHint;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Configuration for an interface type
|
|
254
|
+
*/
|
|
255
|
+
interface InterfaceRegistration {
|
|
256
|
+
name: string;
|
|
257
|
+
schema: S.Schema<any, any, any>;
|
|
258
|
+
resolveType: (value: any) => string;
|
|
259
|
+
directives?: readonly DirectiveApplication[];
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Configuration for an enum type
|
|
263
|
+
*/
|
|
264
|
+
interface EnumRegistration {
|
|
265
|
+
name: string;
|
|
266
|
+
values: readonly string[];
|
|
267
|
+
description?: string;
|
|
268
|
+
directives?: readonly DirectiveApplication[];
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Configuration for a union type
|
|
272
|
+
*/
|
|
273
|
+
interface UnionRegistration {
|
|
274
|
+
name: string;
|
|
275
|
+
types: readonly string[];
|
|
276
|
+
resolveType: (value: any) => string;
|
|
277
|
+
directives?: readonly DirectiveApplication[];
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Configuration for an input type
|
|
281
|
+
*/
|
|
282
|
+
interface InputTypeRegistration {
|
|
283
|
+
name: string;
|
|
284
|
+
schema: S.Schema<any, any, any>;
|
|
285
|
+
description?: string;
|
|
286
|
+
directives?: readonly DirectiveApplication[];
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* A reference to a directive applied to a type, field, or argument
|
|
290
|
+
*/
|
|
291
|
+
interface DirectiveApplication {
|
|
292
|
+
readonly name: string;
|
|
293
|
+
readonly args?: Record<string, unknown>;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Configuration for a directive definition
|
|
297
|
+
*/
|
|
298
|
+
interface DirectiveRegistration<Args = any, R = never> {
|
|
299
|
+
name: string;
|
|
300
|
+
description?: string;
|
|
301
|
+
locations: readonly DirectiveLocation[];
|
|
302
|
+
args?: S.Schema<Args, any, any>;
|
|
303
|
+
/**
|
|
304
|
+
* For executable directives - transforms the resolver Effect.
|
|
305
|
+
* Called with directive args, returns an Effect transformer.
|
|
306
|
+
*/
|
|
307
|
+
apply?: (args: Args) => <A, E, R2>(effect: Effect.Effect<A, E, R2>) => Effect.Effect<A, E, R | R2>;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Context passed to middleware apply functions
|
|
311
|
+
* Contains the resolver's parent value, arguments, and GraphQL resolve info
|
|
312
|
+
*/
|
|
313
|
+
interface MiddlewareContext<Parent = any, Args = any> {
|
|
314
|
+
readonly parent: Parent;
|
|
315
|
+
readonly args: Args;
|
|
316
|
+
readonly info: GraphQLResolveInfo;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Configuration for middleware registration
|
|
320
|
+
*
|
|
321
|
+
* Middleware wraps all resolvers (or those matching a pattern) and executes
|
|
322
|
+
* in an "onion" model - first registered middleware is the outermost layer.
|
|
323
|
+
*
|
|
324
|
+
* Unlike directives which are applied per-field explicitly, middleware is
|
|
325
|
+
* applied globally or via pattern matching.
|
|
326
|
+
*
|
|
327
|
+
* @example
|
|
328
|
+
* ```typescript
|
|
329
|
+
* // Logging middleware - applies to all fields
|
|
330
|
+
* middleware({
|
|
331
|
+
* name: "logging",
|
|
332
|
+
* apply: (effect, ctx) => Effect.gen(function*() {
|
|
333
|
+
* yield* Effect.logInfo(`Resolving ${ctx.info.fieldName}`)
|
|
334
|
+
* return yield* effect
|
|
335
|
+
* })
|
|
336
|
+
* })
|
|
337
|
+
*
|
|
338
|
+
* // Admin-only middleware - pattern matched
|
|
339
|
+
* middleware({
|
|
340
|
+
* name: "adminOnly",
|
|
341
|
+
* match: (info) => info.fieldName.startsWith("admin"),
|
|
342
|
+
* apply: (effect) => Effect.gen(function*() {
|
|
343
|
+
* const auth = yield* AuthService
|
|
344
|
+
* yield* auth.requireAdmin()
|
|
345
|
+
* return yield* effect
|
|
346
|
+
* })
|
|
347
|
+
* })
|
|
348
|
+
* ```
|
|
349
|
+
*/
|
|
350
|
+
interface MiddlewareRegistration<R = never> {
|
|
351
|
+
readonly name: string;
|
|
352
|
+
readonly description?: string;
|
|
353
|
+
/**
|
|
354
|
+
* Optional predicate to filter which fields this middleware applies to.
|
|
355
|
+
* If undefined, middleware applies to all fields.
|
|
356
|
+
* Receives the GraphQL resolve info for the field being resolved.
|
|
357
|
+
*/
|
|
358
|
+
readonly match?: (info: GraphQLResolveInfo) => boolean;
|
|
359
|
+
/**
|
|
360
|
+
* Transform the resolver Effect.
|
|
361
|
+
* Receives the resolver effect and full context (parent, args, info).
|
|
362
|
+
* Returns the transformed effect.
|
|
363
|
+
*
|
|
364
|
+
* Middleware executes in "onion" order - first registered is outermost.
|
|
365
|
+
*/
|
|
366
|
+
readonly apply: <A, E, R2>(effect: Effect.Effect<A, E, R2>, context: MiddlewareContext) => Effect.Effect<A, E, R | R2>;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Configuration for a subscription field
|
|
370
|
+
* Returns a Stream that yields values over time
|
|
371
|
+
*/
|
|
372
|
+
interface SubscriptionFieldRegistration<Args = any, A = any, E = any, R = any> {
|
|
373
|
+
type: S.Schema<A, any, any>;
|
|
374
|
+
args?: S.Schema<Args, any, any>;
|
|
375
|
+
description?: string;
|
|
376
|
+
directives?: readonly DirectiveApplication[];
|
|
377
|
+
/**
|
|
378
|
+
* Complexity cost of this subscription.
|
|
379
|
+
* Can be a static number or a function that receives the resolved arguments.
|
|
380
|
+
* Used for query complexity limiting.
|
|
381
|
+
*/
|
|
382
|
+
complexity?: FieldComplexity;
|
|
383
|
+
/**
|
|
384
|
+
* Cache control hint for this subscription.
|
|
385
|
+
* Note: Subscriptions are real-time and typically not cached,
|
|
386
|
+
* but this can be used for initial data hints.
|
|
387
|
+
*/
|
|
388
|
+
cacheControl?: CacheHint;
|
|
389
|
+
/**
|
|
390
|
+
* Subscribe function returns an Effect that produces a Stream.
|
|
391
|
+
* The Stream yields values that are passed to the resolve function.
|
|
392
|
+
*/
|
|
393
|
+
subscribe: (args: Args) => Effect.Effect<Stream.Stream<A, E, R>, E, R>;
|
|
394
|
+
/**
|
|
395
|
+
* Optional resolve function to transform each yielded value.
|
|
396
|
+
* If not provided, yields values directly.
|
|
397
|
+
*/
|
|
398
|
+
resolve?: (value: A, args: Args) => Effect.Effect<A, E, R>;
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Configuration for a field on an object type
|
|
402
|
+
*/
|
|
403
|
+
interface ObjectFieldRegistration<Parent = any, Args = any, A = any, E = any, R = any> {
|
|
404
|
+
type: S.Schema<A, any, any>;
|
|
405
|
+
args?: S.Schema<Args, any, any>;
|
|
406
|
+
description?: string;
|
|
407
|
+
directives?: readonly DirectiveApplication[];
|
|
408
|
+
/**
|
|
409
|
+
* Complexity cost of this field.
|
|
410
|
+
* Can be a static number or a function that receives the resolved arguments.
|
|
411
|
+
* Used for query complexity limiting.
|
|
412
|
+
*
|
|
413
|
+
* @example
|
|
414
|
+
* // Relation field with pagination
|
|
415
|
+
* complexity: (args) => (args.limit ?? 10) * 2
|
|
416
|
+
*/
|
|
417
|
+
complexity?: FieldComplexity;
|
|
418
|
+
/**
|
|
419
|
+
* Cache control hint for this field.
|
|
420
|
+
* Used to compute HTTP Cache-Control headers for the response.
|
|
421
|
+
*
|
|
422
|
+
* @example
|
|
423
|
+
* // Expensive computation, cache for 5 minutes
|
|
424
|
+
* cacheControl: { maxAge: 300 }
|
|
425
|
+
*
|
|
426
|
+
* // Inherit cache policy from parent type
|
|
427
|
+
* cacheControl: { inheritMaxAge: true }
|
|
428
|
+
*/
|
|
429
|
+
cacheControl?: CacheHint;
|
|
430
|
+
resolve: (parent: Parent, args: Args) => Effect.Effect<A, E, R>;
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* GraphQL context that contains the Effect runtime
|
|
434
|
+
*/
|
|
435
|
+
interface GraphQLEffectContext<R> {
|
|
436
|
+
runtime: Runtime.Runtime<R>;
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Type registries used during schema building
|
|
440
|
+
*/
|
|
441
|
+
interface TypeRegistries {
|
|
442
|
+
types: Map<string, graphql.GraphQLObjectType>;
|
|
443
|
+
interfaces: Map<string, graphql.GraphQLInterfaceType>;
|
|
444
|
+
enums: Map<string, graphql.GraphQLEnumType>;
|
|
445
|
+
unions: Map<string, graphql.GraphQLUnionType>;
|
|
446
|
+
inputs: Map<string, graphql.GraphQLInputObjectType>;
|
|
447
|
+
directives: Map<string, graphql.GraphQLDirective>;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Execution arguments passed to onExecuteStart hook
|
|
452
|
+
*/
|
|
453
|
+
interface ExecutionArgs {
|
|
454
|
+
readonly source: string;
|
|
455
|
+
readonly document: DocumentNode;
|
|
456
|
+
readonly variableValues?: Record<string, unknown>;
|
|
457
|
+
readonly operationName?: string;
|
|
458
|
+
/** The GraphQL schema being executed against */
|
|
459
|
+
readonly schema: GraphQLSchema;
|
|
460
|
+
/** Field complexity definitions from the schema builder */
|
|
461
|
+
readonly fieldComplexities: FieldComplexityMap;
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Configuration for a GraphQL extension
|
|
465
|
+
*
|
|
466
|
+
* Extensions provide lifecycle hooks that run at each phase of request processing,
|
|
467
|
+
* and can contribute data to the response's `extensions` field.
|
|
468
|
+
*
|
|
469
|
+
* @example
|
|
470
|
+
* ```typescript
|
|
471
|
+
* // Tracing extension
|
|
472
|
+
* extension({
|
|
473
|
+
* name: "tracing",
|
|
474
|
+
* onExecuteStart: () => Effect.gen(function*() {
|
|
475
|
+
* const ext = yield* ExtensionsService
|
|
476
|
+
* yield* ext.set("tracing", { startTime: Date.now() })
|
|
477
|
+
* }),
|
|
478
|
+
* onExecuteEnd: () => Effect.gen(function*() {
|
|
479
|
+
* const ext = yield* ExtensionsService
|
|
480
|
+
* yield* ext.merge("tracing", { endTime: Date.now() })
|
|
481
|
+
* }),
|
|
482
|
+
* })
|
|
483
|
+
* ```
|
|
484
|
+
*/
|
|
485
|
+
interface GraphQLExtension<R = never> {
|
|
486
|
+
readonly name: string;
|
|
487
|
+
readonly description?: string;
|
|
488
|
+
/**
|
|
489
|
+
* Called after the query source is parsed into a DocumentNode.
|
|
490
|
+
* Useful for query analysis, caching parsed documents, etc.
|
|
491
|
+
*/
|
|
492
|
+
readonly onParse?: (source: string, document: DocumentNode) => Effect.Effect<void, never, R>;
|
|
493
|
+
/**
|
|
494
|
+
* Called after validation completes.
|
|
495
|
+
* Receives the document and any validation errors.
|
|
496
|
+
* Useful for complexity analysis, query whitelisting, etc.
|
|
497
|
+
*/
|
|
498
|
+
readonly onValidate?: (document: DocumentNode, errors: readonly GraphQLError[]) => Effect.Effect<void, never, R>;
|
|
499
|
+
/**
|
|
500
|
+
* Called before execution begins.
|
|
501
|
+
* Receives the full execution arguments.
|
|
502
|
+
* Useful for setting up tracing, logging, etc.
|
|
503
|
+
*/
|
|
504
|
+
readonly onExecuteStart?: (args: ExecutionArgs) => Effect.Effect<void, never, R>;
|
|
505
|
+
/**
|
|
506
|
+
* Called after execution completes.
|
|
507
|
+
* Receives the execution result (including data and errors).
|
|
508
|
+
* Useful for recording metrics, finalizing traces, etc.
|
|
509
|
+
*/
|
|
510
|
+
readonly onExecuteEnd?: (result: ExecutionResult) => Effect.Effect<void, never, R>;
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Service for accumulating extension data during request processing.
|
|
514
|
+
*
|
|
515
|
+
* This service is automatically provided for each request and allows
|
|
516
|
+
* extensions, middleware, and resolvers to contribute to the response
|
|
517
|
+
* extensions field.
|
|
518
|
+
*
|
|
519
|
+
* @example
|
|
520
|
+
* ```typescript
|
|
521
|
+
* Effect.gen(function*() {
|
|
522
|
+
* const ext = yield* ExtensionsService
|
|
523
|
+
*
|
|
524
|
+
* // Set a value (overwrites existing)
|
|
525
|
+
* yield* ext.set("complexity", { score: 42 })
|
|
526
|
+
*
|
|
527
|
+
* // Merge into existing value
|
|
528
|
+
* yield* ext.merge("tracing", { endTime: Date.now() })
|
|
529
|
+
*
|
|
530
|
+
* // Get all accumulated extensions
|
|
531
|
+
* const all = yield* ext.get()
|
|
532
|
+
* })
|
|
533
|
+
* ```
|
|
534
|
+
*/
|
|
535
|
+
interface ExtensionsService {
|
|
536
|
+
/**
|
|
537
|
+
* Set a key-value pair in the extensions.
|
|
538
|
+
* Overwrites any existing value for this key.
|
|
539
|
+
*/
|
|
540
|
+
readonly set: (key: string, value: unknown) => Effect.Effect<void>;
|
|
541
|
+
/**
|
|
542
|
+
* Deep merge an object into an existing key's value.
|
|
543
|
+
* If the key doesn't exist, sets the value.
|
|
544
|
+
* If the existing value is not an object, overwrites it.
|
|
545
|
+
*/
|
|
546
|
+
readonly merge: (key: string, value: Record<string, unknown>) => Effect.Effect<void>;
|
|
547
|
+
/**
|
|
548
|
+
* Get all accumulated extensions as a record.
|
|
549
|
+
*/
|
|
550
|
+
readonly get: () => Effect.Effect<Record<string, unknown>>;
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Tag for the ExtensionsService
|
|
554
|
+
*/
|
|
555
|
+
declare const ExtensionsService: Context.Tag<ExtensionsService, ExtensionsService>;
|
|
556
|
+
/**
|
|
557
|
+
* Create a new ExtensionsService backed by a Ref
|
|
558
|
+
*/
|
|
559
|
+
declare const makeExtensionsService: () => Effect.Effect<ExtensionsService, never, never>;
|
|
560
|
+
/**
|
|
561
|
+
* Run all onParse hooks for registered extensions
|
|
562
|
+
*/
|
|
563
|
+
declare const runParseHooks: <R>(extensions: readonly GraphQLExtension<R>[], source: string, document: DocumentNode) => Effect.Effect<void, never, R>;
|
|
564
|
+
/**
|
|
565
|
+
* Run all onValidate hooks for registered extensions
|
|
566
|
+
*/
|
|
567
|
+
declare const runValidateHooks: <R>(extensions: readonly GraphQLExtension<R>[], document: DocumentNode, errors: readonly GraphQLError[]) => Effect.Effect<void, never, R>;
|
|
568
|
+
/**
|
|
569
|
+
* Run all onExecuteStart hooks for registered extensions
|
|
570
|
+
*/
|
|
571
|
+
declare const runExecuteStartHooks: <R>(extensions: readonly GraphQLExtension<R>[], args: ExecutionArgs) => Effect.Effect<void, never, R>;
|
|
572
|
+
/**
|
|
573
|
+
* Run all onExecuteEnd hooks for registered extensions
|
|
574
|
+
*/
|
|
575
|
+
declare const runExecuteEndHooks: <R>(extensions: readonly GraphQLExtension<R>[], result: ExecutionResult) => Effect.Effect<void, never, R>;
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* Map of type.field -> cache hint, or type -> cache hint for type-level hints
|
|
579
|
+
*/
|
|
580
|
+
type CacheHintMap = Map<string, CacheHint>;
|
|
581
|
+
/**
|
|
582
|
+
* Computed cache policy for a GraphQL response
|
|
583
|
+
*/
|
|
584
|
+
interface CachePolicy {
|
|
585
|
+
/**
|
|
586
|
+
* Maximum age in seconds the response can be cached.
|
|
587
|
+
* This is the minimum maxAge of all resolved fields.
|
|
588
|
+
* If 0, the response should not be cached.
|
|
589
|
+
*/
|
|
590
|
+
readonly maxAge: number;
|
|
591
|
+
/**
|
|
592
|
+
* Cache scope - PUBLIC means CDN-cacheable, PRIVATE means browser-only.
|
|
593
|
+
* If any field is PRIVATE, the entire response is PRIVATE.
|
|
594
|
+
*/
|
|
595
|
+
readonly scope: CacheControlScope;
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Configuration for cache control
|
|
599
|
+
*/
|
|
600
|
+
interface CacheControlConfig {
|
|
601
|
+
/**
|
|
602
|
+
* Enable cache control header calculation.
|
|
603
|
+
* @default true
|
|
604
|
+
*/
|
|
605
|
+
readonly enabled?: boolean;
|
|
606
|
+
/**
|
|
607
|
+
* Default maxAge for root fields (Query, Mutation).
|
|
608
|
+
* @default 0 (no caching)
|
|
609
|
+
*/
|
|
610
|
+
readonly defaultMaxAge?: number;
|
|
611
|
+
/**
|
|
612
|
+
* Default scope for fields without explicit scope.
|
|
613
|
+
* @default "PUBLIC"
|
|
614
|
+
*/
|
|
615
|
+
readonly defaultScope?: CacheControlScope;
|
|
616
|
+
/**
|
|
617
|
+
* Whether to set HTTP Cache-Control headers on responses.
|
|
618
|
+
* @default true
|
|
619
|
+
*/
|
|
620
|
+
readonly calculateHttpHeaders?: boolean;
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Information provided to cache policy calculation
|
|
624
|
+
*/
|
|
625
|
+
interface CachePolicyAnalysisInfo {
|
|
626
|
+
/** Parsed GraphQL document */
|
|
627
|
+
readonly document: DocumentNode;
|
|
628
|
+
/** The operation being executed */
|
|
629
|
+
readonly operation: OperationDefinitionNode;
|
|
630
|
+
/** The GraphQL schema */
|
|
631
|
+
readonly schema: GraphQLSchema;
|
|
632
|
+
/** Cache hints from the builder (type.field -> hint or type -> hint) */
|
|
633
|
+
readonly cacheHints: CacheHintMap;
|
|
634
|
+
/** Configuration options */
|
|
635
|
+
readonly config: CacheControlConfig;
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Compute the cache policy for a GraphQL response based on the fields resolved.
|
|
639
|
+
*
|
|
640
|
+
* The policy is computed by walking the selection set and aggregating hints:
|
|
641
|
+
* - maxAge: Use the minimum maxAge of all resolved fields
|
|
642
|
+
* - scope: If any field is PRIVATE, the entire response is PRIVATE
|
|
643
|
+
*
|
|
644
|
+
* Default behaviors (matching Apollo):
|
|
645
|
+
* - Root fields default to maxAge: 0 (unless configured otherwise)
|
|
646
|
+
* - Object-returning fields default to maxAge: 0
|
|
647
|
+
* - Scalar fields inherit their parent's maxAge
|
|
648
|
+
* - Fields with inheritMaxAge: true inherit from parent
|
|
649
|
+
*/
|
|
650
|
+
declare const computeCachePolicy: (info: CachePolicyAnalysisInfo) => Effect.Effect<CachePolicy, never, never>;
|
|
651
|
+
/**
|
|
652
|
+
* Compute cache policy from a query string
|
|
653
|
+
*/
|
|
654
|
+
declare const computeCachePolicyFromQuery: (query: string, operationName: string | undefined, schema: GraphQLSchema, cacheHints: CacheHintMap, config?: CacheControlConfig) => Effect.Effect<CachePolicy, Error, never>;
|
|
655
|
+
/**
|
|
656
|
+
* Convert a cache policy to an HTTP Cache-Control header value
|
|
657
|
+
*/
|
|
658
|
+
declare const toCacheControlHeader: (policy: CachePolicy) => string;
|
|
659
|
+
/**
|
|
660
|
+
* Effect Config for loading cache control configuration from environment variables.
|
|
661
|
+
*
|
|
662
|
+
* Environment variables:
|
|
663
|
+
* - GRAPHQL_CACHE_CONTROL_ENABLED: Enable cache control (default: true)
|
|
664
|
+
* - GRAPHQL_CACHE_CONTROL_DEFAULT_MAX_AGE: Default maxAge for root fields (default: 0)
|
|
665
|
+
* - GRAPHQL_CACHE_CONTROL_DEFAULT_SCOPE: Default scope (PUBLIC or PRIVATE, default: PUBLIC)
|
|
666
|
+
* - GRAPHQL_CACHE_CONTROL_HTTP_HEADERS: Set HTTP headers (default: true)
|
|
667
|
+
*/
|
|
668
|
+
declare const CacheControlConfigFromEnv: Config.Config<CacheControlConfig>;
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* GraphQL Schema Builder with type-safe service requirements (Layer-per-Request Pattern)
|
|
672
|
+
*
|
|
673
|
+
* The type parameter R accumulates all service requirements from resolvers.
|
|
674
|
+
* Unlike the runtime-in-context approach, this pattern builds the schema without
|
|
675
|
+
* executing any Effects. At request time, you provide a Layer with all required services.
|
|
676
|
+
*/
|
|
677
|
+
declare class GraphQLSchemaBuilder<R = never> implements Pipeable.Pipeable {
|
|
678
|
+
private readonly state;
|
|
679
|
+
private constructor();
|
|
680
|
+
/**
|
|
681
|
+
* Pipeable interface implementation - enables fluent .pipe() syntax
|
|
682
|
+
*/
|
|
683
|
+
pipe<A>(this: A): A;
|
|
684
|
+
pipe<A, B>(this: A, ab: (a: A) => B): B;
|
|
685
|
+
pipe<A, B, C>(this: A, ab: (a: A) => B, bc: (b: B) => C): C;
|
|
686
|
+
pipe<A, B, C, D>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D): D;
|
|
687
|
+
pipe<A, B, C, D, E>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E): E;
|
|
688
|
+
pipe<A, B, C, D, E, F>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F): F;
|
|
689
|
+
pipe<A, B, C, D, E, F, G>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G): G;
|
|
690
|
+
pipe<A, B, C, D, E, F, G, H>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H): H;
|
|
691
|
+
pipe<A, B, C, D, E, F, G, H, I>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I): I;
|
|
692
|
+
/**
|
|
693
|
+
* Create an empty schema builder
|
|
694
|
+
*/
|
|
695
|
+
static readonly empty: GraphQLSchemaBuilder<never>;
|
|
696
|
+
/**
|
|
697
|
+
* Create a new builder with updated state
|
|
698
|
+
*/
|
|
699
|
+
private with;
|
|
700
|
+
/**
|
|
701
|
+
* Add a query field
|
|
702
|
+
*/
|
|
703
|
+
query<A, E, R2, Args = void>(name: string, config: {
|
|
704
|
+
type: S.Schema<A, any, any>;
|
|
705
|
+
args?: S.Schema<Args, any, any>;
|
|
706
|
+
description?: string;
|
|
707
|
+
directives?: readonly DirectiveApplication[];
|
|
708
|
+
/**
|
|
709
|
+
* Complexity cost of this field for query complexity limiting.
|
|
710
|
+
* Can be a static number or a function that receives the resolved arguments.
|
|
711
|
+
*/
|
|
712
|
+
complexity?: FieldComplexity;
|
|
713
|
+
/**
|
|
714
|
+
* Cache control hint for this field.
|
|
715
|
+
* Used to compute HTTP Cache-Control headers for the response.
|
|
716
|
+
*/
|
|
717
|
+
cacheControl?: CacheHint;
|
|
718
|
+
resolve: (args: Args) => Effect.Effect<A, E, R2>;
|
|
719
|
+
}): GraphQLSchemaBuilder<R | R2>;
|
|
720
|
+
/**
|
|
721
|
+
* Add a mutation field
|
|
722
|
+
*/
|
|
723
|
+
mutation<A, E, R2, Args = void>(name: string, config: {
|
|
724
|
+
type: S.Schema<A, any, any>;
|
|
725
|
+
args?: S.Schema<Args, any, any>;
|
|
726
|
+
description?: string;
|
|
727
|
+
directives?: readonly DirectiveApplication[];
|
|
728
|
+
/**
|
|
729
|
+
* Complexity cost of this field for query complexity limiting.
|
|
730
|
+
* Can be a static number or a function that receives the resolved arguments.
|
|
731
|
+
*/
|
|
732
|
+
complexity?: FieldComplexity;
|
|
733
|
+
resolve: (args: Args) => Effect.Effect<A, E, R2>;
|
|
734
|
+
}): GraphQLSchemaBuilder<R | R2>;
|
|
735
|
+
/**
|
|
736
|
+
* Add a subscription field
|
|
737
|
+
*
|
|
738
|
+
* Subscriptions return a Stream that yields values over time.
|
|
739
|
+
* The subscribe function returns an Effect that produces a Stream.
|
|
740
|
+
*
|
|
741
|
+
* @example
|
|
742
|
+
* ```typescript
|
|
743
|
+
* builder.subscription("userCreated", {
|
|
744
|
+
* type: User,
|
|
745
|
+
* subscribe: Effect.gen(function*() {
|
|
746
|
+
* const pubsub = yield* PubSubService
|
|
747
|
+
* return pubsub.subscribe("USER_CREATED")
|
|
748
|
+
* }),
|
|
749
|
+
* })
|
|
750
|
+
* ```
|
|
751
|
+
*/
|
|
752
|
+
subscription<A, E, R2, Args = void>(name: string, config: {
|
|
753
|
+
type: S.Schema<A, any, any>;
|
|
754
|
+
args?: S.Schema<Args, any, any>;
|
|
755
|
+
description?: string;
|
|
756
|
+
directives?: readonly DirectiveApplication[];
|
|
757
|
+
/**
|
|
758
|
+
* Complexity cost of this subscription for query complexity limiting.
|
|
759
|
+
* Can be a static number or a function that receives the resolved arguments.
|
|
760
|
+
*/
|
|
761
|
+
complexity?: FieldComplexity;
|
|
762
|
+
/**
|
|
763
|
+
* Cache control hint for this subscription.
|
|
764
|
+
* Note: Subscriptions are typically not cached, but this can be used for initial response hints.
|
|
765
|
+
*/
|
|
766
|
+
cacheControl?: CacheHint;
|
|
767
|
+
subscribe: (args: Args) => Effect.Effect<effect.Stream.Stream<A, E, R2>, E, R2>;
|
|
768
|
+
resolve?: (value: A, args: Args) => Effect.Effect<A, E, R2>;
|
|
769
|
+
}): GraphQLSchemaBuilder<R | R2>;
|
|
770
|
+
/**
|
|
771
|
+
* Register an object type from a schema
|
|
772
|
+
*/
|
|
773
|
+
objectType<A, R2 = never>(config: {
|
|
774
|
+
name?: string;
|
|
775
|
+
schema: S.Schema<A, any, any>;
|
|
776
|
+
implements?: readonly string[];
|
|
777
|
+
directives?: readonly DirectiveApplication[];
|
|
778
|
+
/**
|
|
779
|
+
* Default cache control hint for all fields returning this type.
|
|
780
|
+
* Can be overridden by field-level cacheControl.
|
|
781
|
+
*/
|
|
782
|
+
cacheControl?: CacheHint;
|
|
783
|
+
fields?: Record<string, {
|
|
784
|
+
type: S.Schema<any, any, any>;
|
|
785
|
+
args?: S.Schema<any, any, any>;
|
|
786
|
+
description?: string;
|
|
787
|
+
directives?: readonly DirectiveApplication[];
|
|
788
|
+
/**
|
|
789
|
+
* Complexity cost of this field for query complexity limiting.
|
|
790
|
+
*/
|
|
791
|
+
complexity?: FieldComplexity;
|
|
792
|
+
/**
|
|
793
|
+
* Cache control hint for this field.
|
|
794
|
+
*/
|
|
795
|
+
cacheControl?: CacheHint;
|
|
796
|
+
resolve: (parent: A, args: any) => Effect.Effect<any, any, any>;
|
|
797
|
+
}>;
|
|
798
|
+
}): GraphQLSchemaBuilder<R | R2>;
|
|
799
|
+
/**
|
|
800
|
+
* Register an interface type from a schema
|
|
801
|
+
*/
|
|
802
|
+
interfaceType(config: {
|
|
803
|
+
name?: string;
|
|
804
|
+
schema: S.Schema<any, any, any>;
|
|
805
|
+
resolveType?: (value: any) => string;
|
|
806
|
+
directives?: readonly DirectiveApplication[];
|
|
807
|
+
}): GraphQLSchemaBuilder<R>;
|
|
808
|
+
/**
|
|
809
|
+
* Register an enum type
|
|
810
|
+
*/
|
|
811
|
+
enumType(config: {
|
|
812
|
+
name: string;
|
|
813
|
+
values: readonly string[];
|
|
814
|
+
description?: string;
|
|
815
|
+
directives?: readonly DirectiveApplication[];
|
|
816
|
+
}): GraphQLSchemaBuilder<R>;
|
|
817
|
+
/**
|
|
818
|
+
* Register a union type
|
|
819
|
+
*/
|
|
820
|
+
unionType(config: {
|
|
821
|
+
name: string;
|
|
822
|
+
types: readonly string[];
|
|
823
|
+
resolveType?: (value: any) => string;
|
|
824
|
+
directives?: readonly DirectiveApplication[];
|
|
825
|
+
}): GraphQLSchemaBuilder<R>;
|
|
826
|
+
/**
|
|
827
|
+
* Register an input type
|
|
828
|
+
*/
|
|
829
|
+
inputType(config: {
|
|
830
|
+
name?: string;
|
|
831
|
+
schema: S.Schema<any, any, any>;
|
|
832
|
+
description?: string;
|
|
833
|
+
directives?: readonly DirectiveApplication[];
|
|
834
|
+
}): GraphQLSchemaBuilder<R>;
|
|
835
|
+
/**
|
|
836
|
+
* Register a directive
|
|
837
|
+
*/
|
|
838
|
+
directive<Args = void, R2 = never>(config: {
|
|
839
|
+
name: string;
|
|
840
|
+
description?: string;
|
|
841
|
+
locations: readonly DirectiveLocation[];
|
|
842
|
+
args?: S.Schema<Args, any, any>;
|
|
843
|
+
apply?: (args: Args) => <A, E, R3>(effect: Effect.Effect<A, E, R3>) => Effect.Effect<A, E, R2 | R3>;
|
|
844
|
+
}): GraphQLSchemaBuilder<R | R2>;
|
|
845
|
+
/**
|
|
846
|
+
* Register a middleware
|
|
847
|
+
*
|
|
848
|
+
* Middleware wraps all resolvers (or those matching a pattern) and executes
|
|
849
|
+
* in an "onion" model - first registered middleware is the outermost layer.
|
|
850
|
+
*
|
|
851
|
+
* @param config.name - Middleware name (for debugging/logging)
|
|
852
|
+
* @param config.description - Optional description
|
|
853
|
+
* @param config.match - Optional predicate to filter which fields this applies to
|
|
854
|
+
* @param config.apply - Function that transforms the resolver Effect
|
|
855
|
+
*
|
|
856
|
+
* @example
|
|
857
|
+
* ```typescript
|
|
858
|
+
* builder.middleware({
|
|
859
|
+
* name: "logging",
|
|
860
|
+
* apply: (effect, ctx) => Effect.gen(function*() {
|
|
861
|
+
* yield* Effect.logInfo(`Resolving ${ctx.info.fieldName}`)
|
|
862
|
+
* const start = Date.now()
|
|
863
|
+
* const result = yield* effect
|
|
864
|
+
* yield* Effect.logInfo(`Resolved in ${Date.now() - start}ms`)
|
|
865
|
+
* return result
|
|
866
|
+
* })
|
|
867
|
+
* })
|
|
868
|
+
* ```
|
|
869
|
+
*/
|
|
870
|
+
middleware<R2 = never>(config: {
|
|
871
|
+
name: string;
|
|
872
|
+
description?: string;
|
|
873
|
+
match?: (info: GraphQLResolveInfo) => boolean;
|
|
874
|
+
apply: <A, E, R3>(effect: Effect.Effect<A, E, R3>, context: MiddlewareContext) => Effect.Effect<A, E, R2 | R3>;
|
|
875
|
+
}): GraphQLSchemaBuilder<R | R2>;
|
|
876
|
+
/**
|
|
877
|
+
* Register an extension
|
|
878
|
+
*
|
|
879
|
+
* Extensions provide lifecycle hooks that run at each phase of request processing
|
|
880
|
+
* (parse, validate, execute) and can contribute data to the response's extensions field.
|
|
881
|
+
*
|
|
882
|
+
* @param config.name - Extension name (for debugging/logging)
|
|
883
|
+
* @param config.description - Optional description
|
|
884
|
+
* @param config.onParse - Called after query parsing
|
|
885
|
+
* @param config.onValidate - Called after validation
|
|
886
|
+
* @param config.onExecuteStart - Called before execution begins
|
|
887
|
+
* @param config.onExecuteEnd - Called after execution completes
|
|
888
|
+
*
|
|
889
|
+
* @example
|
|
890
|
+
* ```typescript
|
|
891
|
+
* builder.extension({
|
|
892
|
+
* name: "tracing",
|
|
893
|
+
* onExecuteStart: () => Effect.gen(function*() {
|
|
894
|
+
* const ext = yield* ExtensionsService
|
|
895
|
+
* yield* ext.set("tracing", { startTime: Date.now() })
|
|
896
|
+
* }),
|
|
897
|
+
* onExecuteEnd: () => Effect.gen(function*() {
|
|
898
|
+
* const ext = yield* ExtensionsService
|
|
899
|
+
* yield* ext.merge("tracing", { endTime: Date.now() })
|
|
900
|
+
* }),
|
|
901
|
+
* })
|
|
902
|
+
* ```
|
|
903
|
+
*/
|
|
904
|
+
extension<R2 = never>(config: {
|
|
905
|
+
name: string;
|
|
906
|
+
description?: string;
|
|
907
|
+
onParse?: (source: string, document: DocumentNode) => Effect.Effect<void, never, R2>;
|
|
908
|
+
onValidate?: (document: DocumentNode, errors: readonly GraphQLError[]) => Effect.Effect<void, never, R2>;
|
|
909
|
+
onExecuteStart?: (args: ExecutionArgs) => Effect.Effect<void, never, R2>;
|
|
910
|
+
onExecuteEnd?: (result: ExecutionResult) => Effect.Effect<void, never, R2>;
|
|
911
|
+
}): GraphQLSchemaBuilder<R | R2>;
|
|
912
|
+
/**
|
|
913
|
+
* Get the registered extensions for use by the execution layer
|
|
914
|
+
*/
|
|
915
|
+
getExtensions(): readonly GraphQLExtension<any>[];
|
|
916
|
+
/**
|
|
917
|
+
* Add a computed/relational field to an object type
|
|
918
|
+
*/
|
|
919
|
+
field<Parent, A, E, R2, Args = void>(typeName: string, fieldName: string, config: {
|
|
920
|
+
type: S.Schema<A, any, any>;
|
|
921
|
+
args?: S.Schema<Args, any, any>;
|
|
922
|
+
description?: string;
|
|
923
|
+
directives?: readonly DirectiveApplication[];
|
|
924
|
+
/**
|
|
925
|
+
* Complexity cost of this field for query complexity limiting.
|
|
926
|
+
* Can be a static number or a function that receives the resolved arguments.
|
|
927
|
+
*/
|
|
928
|
+
complexity?: FieldComplexity;
|
|
929
|
+
/**
|
|
930
|
+
* Cache control hint for this field.
|
|
931
|
+
* Used to compute HTTP Cache-Control headers for the response.
|
|
932
|
+
*/
|
|
933
|
+
cacheControl?: CacheHint;
|
|
934
|
+
resolve: (parent: Parent, args: Args) => Effect.Effect<A, E, R2>;
|
|
935
|
+
}): GraphQLSchemaBuilder<R | R2>;
|
|
936
|
+
/**
|
|
937
|
+
* Get the field complexity map for use in complexity validation.
|
|
938
|
+
* Maps "TypeName.fieldName" to the complexity value or function.
|
|
939
|
+
*/
|
|
940
|
+
getFieldComplexities(): FieldComplexityMap;
|
|
941
|
+
/**
|
|
942
|
+
* Get the cache hint map for use in cache control calculation.
|
|
943
|
+
* Maps "TypeName.fieldName" to the cache hint for field-level hints,
|
|
944
|
+
* or "TypeName" to the cache hint for type-level hints.
|
|
945
|
+
*/
|
|
946
|
+
getCacheHints(): CacheHintMap;
|
|
947
|
+
/**
|
|
948
|
+
* Build the GraphQL schema (no services required)
|
|
949
|
+
*/
|
|
950
|
+
buildSchema(): GraphQLSchema;
|
|
951
|
+
private buildDirectiveRegistry;
|
|
952
|
+
private buildEnumRegistry;
|
|
953
|
+
private buildInputRegistry;
|
|
954
|
+
private buildInterfaceRegistry;
|
|
955
|
+
private buildTypeAndUnionRegistries;
|
|
956
|
+
private createFieldBuilderContext;
|
|
957
|
+
private buildQueryFields;
|
|
958
|
+
private buildMutationFields;
|
|
959
|
+
private buildSubscriptionFields;
|
|
960
|
+
private assembleSchema;
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
export { computeCachePolicy as A, computeCachePolicyFromQuery as B, type CacheHint as C, type DirectiveApplication as D, ExtensionsService as E, type FieldComplexityMap as F, type GraphQLExtension as G, toCacheControlHeader as H, type InterfaceRegistration as I, CacheControlConfigFromEnv as J, type ExecutionArgs as K, makeExtensionsService as L, type MiddlewareContext as M, runParseHooks as N, type ObjectFieldRegistration as O, runValidateHooks as P, runExecuteStartHooks as Q, runExecuteEndHooks as R, type SubscriptionFieldRegistration as S, type TypeRegistration as T, type UnionRegistration as U, type FieldRegistration as a, type EnumRegistration as b, type InputTypeRegistration as c, type DirectiveRegistration as d, type MiddlewareRegistration as e, type GraphQLEffectContext as f, type TypeRegistries as g, type CacheControlScope as h, GraphQLSchemaBuilder as i, type ComplexityConfig as j, type ComplexityResult as k, type ComplexityAnalysisInfo as l, type ComplexityExceededInfo as m, type ComplexityCalculator as n, type FieldComplexity as o, ComplexityLimitExceededError as p, ComplexityAnalysisError as q, defaultComplexityCalculator as r, depthOnlyCalculator as s, combineCalculators as t, ComplexityConfigFromEnv as u, validateComplexity as v, type CacheHintMap as w, type CachePolicy as x, type CacheControlConfig as y, type CachePolicyAnalysisInfo as z };
|