@effect-gql/core 0.1.0 → 1.1.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 +1446 -0
- package/builder/index.cjs.map +1 -0
- package/builder/index.d.cts +260 -0
- package/{dist/builder/pipe-api.d.ts → builder/index.d.ts} +50 -21
- package/builder/index.js +1405 -0
- package/builder/index.js.map +1 -0
- package/index.cjs +3469 -0
- package/index.cjs.map +1 -0
- package/index.d.cts +529 -0
- package/index.d.ts +529 -0
- package/index.js +3292 -0
- package/index.js.map +1 -0
- package/package.json +19 -28
- package/schema-builder-DKvkzU_M.d.cts +965 -0
- package/schema-builder-DKvkzU_M.d.ts +965 -0
- package/server/index.cjs +1579 -0
- package/server/index.cjs.map +1 -0
- package/server/index.d.cts +682 -0
- package/server/index.d.ts +682 -0
- package/server/index.js +1548 -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
package/server/index.cjs
ADDED
|
@@ -0,0 +1,1579 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var effect = require('effect');
|
|
4
|
+
var platform = require('@effect/platform');
|
|
5
|
+
var graphql = require('graphql');
|
|
6
|
+
var graphqlWs = require('graphql-ws');
|
|
7
|
+
|
|
8
|
+
// src/server/config.ts
|
|
9
|
+
var defaultConfig = {
|
|
10
|
+
path: "/graphql",
|
|
11
|
+
graphiql: false,
|
|
12
|
+
complexity: void 0,
|
|
13
|
+
introspection: true,
|
|
14
|
+
cacheControl: void 0
|
|
15
|
+
};
|
|
16
|
+
var normalizeConfig = (input = {}) => {
|
|
17
|
+
const path = input.path ?? defaultConfig.path;
|
|
18
|
+
let graphiql = false;
|
|
19
|
+
if (input.graphiql === true) {
|
|
20
|
+
graphiql = { path: "/graphiql", endpoint: path };
|
|
21
|
+
} else if (input.graphiql && typeof input.graphiql === "object") {
|
|
22
|
+
graphiql = {
|
|
23
|
+
path: input.graphiql.path ?? "/graphiql",
|
|
24
|
+
endpoint: input.graphiql.endpoint ?? path
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
path,
|
|
29
|
+
graphiql,
|
|
30
|
+
complexity: input.complexity,
|
|
31
|
+
introspection: input.introspection ?? true,
|
|
32
|
+
cacheControl: input.cacheControl
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
var GraphQLRouterConfigFromEnv = effect.Config.all({
|
|
36
|
+
path: effect.Config.string("GRAPHQL_PATH").pipe(effect.Config.withDefault("/graphql")),
|
|
37
|
+
introspection: effect.Config.boolean("GRAPHQL_INTROSPECTION").pipe(effect.Config.withDefault(true)),
|
|
38
|
+
graphiqlEnabled: effect.Config.boolean("GRAPHIQL_ENABLED").pipe(effect.Config.withDefault(false)),
|
|
39
|
+
graphiqlPath: effect.Config.string("GRAPHIQL_PATH").pipe(effect.Config.withDefault("/graphiql")),
|
|
40
|
+
graphiqlEndpoint: effect.Config.string("GRAPHIQL_ENDPOINT").pipe(effect.Config.option),
|
|
41
|
+
maxDepth: effect.Config.number("GRAPHQL_MAX_DEPTH").pipe(effect.Config.option),
|
|
42
|
+
maxComplexity: effect.Config.number("GRAPHQL_MAX_COMPLEXITY").pipe(effect.Config.option),
|
|
43
|
+
maxAliases: effect.Config.number("GRAPHQL_MAX_ALIASES").pipe(effect.Config.option),
|
|
44
|
+
maxFields: effect.Config.number("GRAPHQL_MAX_FIELDS").pipe(effect.Config.option),
|
|
45
|
+
defaultFieldComplexity: effect.Config.number("GRAPHQL_DEFAULT_FIELD_COMPLEXITY").pipe(
|
|
46
|
+
effect.Config.withDefault(1)
|
|
47
|
+
),
|
|
48
|
+
cacheControlEnabled: effect.Config.boolean("GRAPHQL_CACHE_CONTROL_ENABLED").pipe(
|
|
49
|
+
effect.Config.withDefault(false)
|
|
50
|
+
),
|
|
51
|
+
cacheControlDefaultMaxAge: effect.Config.number("GRAPHQL_CACHE_CONTROL_DEFAULT_MAX_AGE").pipe(
|
|
52
|
+
effect.Config.withDefault(0)
|
|
53
|
+
),
|
|
54
|
+
cacheControlDefaultScope: effect.Config.string("GRAPHQL_CACHE_CONTROL_DEFAULT_SCOPE").pipe(
|
|
55
|
+
effect.Config.withDefault("PUBLIC")
|
|
56
|
+
)
|
|
57
|
+
}).pipe(
|
|
58
|
+
effect.Config.map(
|
|
59
|
+
({
|
|
60
|
+
path,
|
|
61
|
+
introspection,
|
|
62
|
+
graphiqlEnabled,
|
|
63
|
+
graphiqlPath,
|
|
64
|
+
graphiqlEndpoint,
|
|
65
|
+
maxDepth,
|
|
66
|
+
maxComplexity,
|
|
67
|
+
maxAliases,
|
|
68
|
+
maxFields,
|
|
69
|
+
defaultFieldComplexity,
|
|
70
|
+
cacheControlEnabled,
|
|
71
|
+
cacheControlDefaultMaxAge,
|
|
72
|
+
cacheControlDefaultScope
|
|
73
|
+
}) => {
|
|
74
|
+
const hasComplexity = effect.Option.isSome(maxDepth) || effect.Option.isSome(maxComplexity) || effect.Option.isSome(maxAliases) || effect.Option.isSome(maxFields);
|
|
75
|
+
return {
|
|
76
|
+
path,
|
|
77
|
+
introspection,
|
|
78
|
+
graphiql: graphiqlEnabled ? {
|
|
79
|
+
path: graphiqlPath,
|
|
80
|
+
endpoint: effect.Option.isSome(graphiqlEndpoint) ? graphiqlEndpoint.value : path
|
|
81
|
+
} : false,
|
|
82
|
+
complexity: hasComplexity ? {
|
|
83
|
+
maxDepth: effect.Option.getOrUndefined(maxDepth),
|
|
84
|
+
maxComplexity: effect.Option.getOrUndefined(maxComplexity),
|
|
85
|
+
maxAliases: effect.Option.getOrUndefined(maxAliases),
|
|
86
|
+
maxFields: effect.Option.getOrUndefined(maxFields),
|
|
87
|
+
defaultFieldComplexity
|
|
88
|
+
} : void 0,
|
|
89
|
+
cacheControl: cacheControlEnabled ? {
|
|
90
|
+
enabled: true,
|
|
91
|
+
defaultMaxAge: cacheControlDefaultMaxAge,
|
|
92
|
+
defaultScope: cacheControlDefaultScope === "PRIVATE" ? "PRIVATE" : "PUBLIC",
|
|
93
|
+
calculateHttpHeaders: true
|
|
94
|
+
} : void 0
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
)
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
// src/server/graphiql.ts
|
|
101
|
+
var graphiqlHtml = (endpoint, subscriptionEndpoint) => `<!DOCTYPE html>
|
|
102
|
+
<html lang="en">
|
|
103
|
+
<head>
|
|
104
|
+
<meta charset="utf-8" />
|
|
105
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
106
|
+
<title>GraphiQL</title>
|
|
107
|
+
<link
|
|
108
|
+
rel="stylesheet"
|
|
109
|
+
href="https://unpkg.com/graphiql@3/graphiql.min.css"
|
|
110
|
+
/>
|
|
111
|
+
</head>
|
|
112
|
+
<body style="margin: 0; overflow: hidden;">
|
|
113
|
+
<div id="graphiql" style="height: 100vh;"></div>
|
|
114
|
+
<script
|
|
115
|
+
crossorigin
|
|
116
|
+
src="https://unpkg.com/react@18/umd/react.production.min.js"
|
|
117
|
+
></script>
|
|
118
|
+
<script
|
|
119
|
+
crossorigin
|
|
120
|
+
src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"
|
|
121
|
+
></script>
|
|
122
|
+
<script
|
|
123
|
+
crossorigin
|
|
124
|
+
src="https://unpkg.com/graphiql@3/graphiql.min.js"
|
|
125
|
+
></script>
|
|
126
|
+
<script>
|
|
127
|
+
const fetcher = GraphiQL.createFetcher({
|
|
128
|
+
url: ${JSON.stringify(endpoint)},
|
|
129
|
+
subscriptionUrl: ${JSON.stringify(subscriptionEndpoint ?? endpoint)},
|
|
130
|
+
});
|
|
131
|
+
ReactDOM.createRoot(document.getElementById('graphiql')).render(
|
|
132
|
+
React.createElement(GraphiQL, { fetcher })
|
|
133
|
+
);
|
|
134
|
+
</script>
|
|
135
|
+
</body>
|
|
136
|
+
</html>`;
|
|
137
|
+
var ComplexityLimitExceededError = class extends effect.Data.TaggedError("ComplexityLimitExceededError") {
|
|
138
|
+
};
|
|
139
|
+
var ComplexityAnalysisError = class extends effect.Data.TaggedError("ComplexityAnalysisError") {
|
|
140
|
+
};
|
|
141
|
+
var defaultComplexityCalculator = (defaultCost = 1) => {
|
|
142
|
+
return (info) => effect.Effect.try({
|
|
143
|
+
try: () => {
|
|
144
|
+
const fragments = /* @__PURE__ */ new Map();
|
|
145
|
+
for (const definition of info.document.definitions) {
|
|
146
|
+
if (definition.kind === graphql.Kind.FRAGMENT_DEFINITION) {
|
|
147
|
+
fragments.set(definition.name.value, definition);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const rootType = getRootType(info.schema, info.operation.operation);
|
|
151
|
+
if (!rootType) {
|
|
152
|
+
throw new Error(`No root type found for operation: ${info.operation.operation}`);
|
|
153
|
+
}
|
|
154
|
+
const result = analyzeSelectionSet(
|
|
155
|
+
info.operation.selectionSet,
|
|
156
|
+
rootType,
|
|
157
|
+
info.schema,
|
|
158
|
+
fragments,
|
|
159
|
+
info.fieldComplexities,
|
|
160
|
+
info.variables ?? {},
|
|
161
|
+
defaultCost,
|
|
162
|
+
1,
|
|
163
|
+
// Starting depth
|
|
164
|
+
/* @__PURE__ */ new Set()
|
|
165
|
+
// Visited fragments to prevent infinite loops
|
|
166
|
+
);
|
|
167
|
+
return result;
|
|
168
|
+
},
|
|
169
|
+
catch: (error) => new ComplexityAnalysisError({
|
|
170
|
+
message: `Failed to analyze query complexity: ${error}`,
|
|
171
|
+
cause: error
|
|
172
|
+
})
|
|
173
|
+
});
|
|
174
|
+
};
|
|
175
|
+
function getRootType(schema, operation) {
|
|
176
|
+
switch (operation) {
|
|
177
|
+
case "query":
|
|
178
|
+
return schema.getQueryType() ?? null;
|
|
179
|
+
case "mutation":
|
|
180
|
+
return schema.getMutationType() ?? null;
|
|
181
|
+
case "subscription":
|
|
182
|
+
return schema.getSubscriptionType() ?? null;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function getNamedType(type) {
|
|
186
|
+
if (type instanceof graphql.GraphQLNonNull || type instanceof graphql.GraphQLList) {
|
|
187
|
+
return getNamedType(type.ofType);
|
|
188
|
+
}
|
|
189
|
+
if (type instanceof graphql.GraphQLObjectType) {
|
|
190
|
+
return type;
|
|
191
|
+
}
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
function accumulateResult(acc, result) {
|
|
195
|
+
acc.maxDepth = Math.max(acc.maxDepth, result.depth);
|
|
196
|
+
acc.complexity += result.complexity;
|
|
197
|
+
acc.fieldCount += result.fieldCount;
|
|
198
|
+
acc.aliasCount += result.aliasCount;
|
|
199
|
+
}
|
|
200
|
+
function analyzeSelectionSet(selectionSet, parentType, schema, fragments, fieldComplexities, variables, defaultCost, currentDepth, visitedFragments) {
|
|
201
|
+
const ctx = { schema, fragments, fieldComplexities, variables, defaultCost };
|
|
202
|
+
const acc = { maxDepth: currentDepth, complexity: 0, fieldCount: 0, aliasCount: 0 };
|
|
203
|
+
for (const selection of selectionSet.selections) {
|
|
204
|
+
const result = analyzeSelection(selection, parentType, ctx, currentDepth, visitedFragments);
|
|
205
|
+
accumulateResult(acc, result);
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
depth: acc.maxDepth,
|
|
209
|
+
complexity: acc.complexity,
|
|
210
|
+
fieldCount: acc.fieldCount,
|
|
211
|
+
aliasCount: acc.aliasCount
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
function analyzeSelection(selection, parentType, ctx, currentDepth, visitedFragments) {
|
|
215
|
+
switch (selection.kind) {
|
|
216
|
+
case graphql.Kind.FIELD:
|
|
217
|
+
return analyzeField(selection, parentType, ctx, currentDepth, visitedFragments);
|
|
218
|
+
case graphql.Kind.FRAGMENT_SPREAD:
|
|
219
|
+
return analyzeFragmentSpread(selection, ctx, currentDepth, visitedFragments);
|
|
220
|
+
case graphql.Kind.INLINE_FRAGMENT:
|
|
221
|
+
return analyzeInlineFragment(selection, parentType, ctx, currentDepth, visitedFragments);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function analyzeField(field, parentType, ctx, currentDepth, visitedFragments) {
|
|
225
|
+
const fieldName = field.name.value;
|
|
226
|
+
const aliasCount = field.alias ? 1 : 0;
|
|
227
|
+
if (fieldName.startsWith("__")) {
|
|
228
|
+
return { depth: currentDepth, complexity: 0, fieldCount: 1, aliasCount };
|
|
229
|
+
}
|
|
230
|
+
const schemaField = parentType.getFields()[fieldName];
|
|
231
|
+
if (!schemaField) {
|
|
232
|
+
return { depth: currentDepth, complexity: ctx.defaultCost, fieldCount: 1, aliasCount };
|
|
233
|
+
}
|
|
234
|
+
const args = resolveFieldArguments(field, ctx.variables);
|
|
235
|
+
const complexityKey = `${parentType.name}.${fieldName}`;
|
|
236
|
+
const fieldComplexity = ctx.fieldComplexities.get(complexityKey);
|
|
237
|
+
const cost = fieldComplexity !== void 0 ? typeof fieldComplexity === "function" ? fieldComplexity(args) : fieldComplexity : ctx.defaultCost;
|
|
238
|
+
if (field.selectionSet) {
|
|
239
|
+
const fieldType = getNamedType(schemaField.type);
|
|
240
|
+
if (fieldType) {
|
|
241
|
+
const nestedResult = analyzeSelectionSet(
|
|
242
|
+
field.selectionSet,
|
|
243
|
+
fieldType,
|
|
244
|
+
ctx.schema,
|
|
245
|
+
ctx.fragments,
|
|
246
|
+
ctx.fieldComplexities,
|
|
247
|
+
ctx.variables,
|
|
248
|
+
ctx.defaultCost,
|
|
249
|
+
currentDepth + 1,
|
|
250
|
+
visitedFragments
|
|
251
|
+
);
|
|
252
|
+
return {
|
|
253
|
+
depth: nestedResult.depth,
|
|
254
|
+
complexity: cost + nestedResult.complexity,
|
|
255
|
+
fieldCount: 1 + nestedResult.fieldCount,
|
|
256
|
+
aliasCount: aliasCount + nestedResult.aliasCount
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return { depth: currentDepth, complexity: cost, fieldCount: 1, aliasCount };
|
|
261
|
+
}
|
|
262
|
+
function analyzeFragmentSpread(spread, ctx, currentDepth, visitedFragments) {
|
|
263
|
+
const fragmentName = spread.name.value;
|
|
264
|
+
if (visitedFragments.has(fragmentName)) {
|
|
265
|
+
return { depth: currentDepth, complexity: 0, fieldCount: 0, aliasCount: 0 };
|
|
266
|
+
}
|
|
267
|
+
const fragment = ctx.fragments.get(fragmentName);
|
|
268
|
+
if (!fragment) {
|
|
269
|
+
return { depth: currentDepth, complexity: 0, fieldCount: 0, aliasCount: 0 };
|
|
270
|
+
}
|
|
271
|
+
const fragmentType = ctx.schema.getType(fragment.typeCondition.name.value);
|
|
272
|
+
if (!(fragmentType instanceof graphql.GraphQLObjectType)) {
|
|
273
|
+
return { depth: currentDepth, complexity: 0, fieldCount: 0, aliasCount: 0 };
|
|
274
|
+
}
|
|
275
|
+
const newVisited = new Set(visitedFragments);
|
|
276
|
+
newVisited.add(fragmentName);
|
|
277
|
+
return analyzeSelectionSet(
|
|
278
|
+
fragment.selectionSet,
|
|
279
|
+
fragmentType,
|
|
280
|
+
ctx.schema,
|
|
281
|
+
ctx.fragments,
|
|
282
|
+
ctx.fieldComplexities,
|
|
283
|
+
ctx.variables,
|
|
284
|
+
ctx.defaultCost,
|
|
285
|
+
currentDepth,
|
|
286
|
+
newVisited
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
function analyzeInlineFragment(fragment, parentType, ctx, currentDepth, visitedFragments) {
|
|
290
|
+
let targetType = parentType;
|
|
291
|
+
if (fragment.typeCondition) {
|
|
292
|
+
const conditionType = ctx.schema.getType(fragment.typeCondition.name.value);
|
|
293
|
+
if (conditionType instanceof graphql.GraphQLObjectType) {
|
|
294
|
+
targetType = conditionType;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return analyzeSelectionSet(
|
|
298
|
+
fragment.selectionSet,
|
|
299
|
+
targetType,
|
|
300
|
+
ctx.schema,
|
|
301
|
+
ctx.fragments,
|
|
302
|
+
ctx.fieldComplexities,
|
|
303
|
+
ctx.variables,
|
|
304
|
+
ctx.defaultCost,
|
|
305
|
+
currentDepth,
|
|
306
|
+
visitedFragments
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
function resolveFieldArguments(field, variables) {
|
|
310
|
+
const args = {};
|
|
311
|
+
if (!field.arguments) {
|
|
312
|
+
return args;
|
|
313
|
+
}
|
|
314
|
+
for (const arg of field.arguments) {
|
|
315
|
+
const value = arg.value;
|
|
316
|
+
switch (value.kind) {
|
|
317
|
+
case graphql.Kind.VARIABLE:
|
|
318
|
+
args[arg.name.value] = variables[value.name.value];
|
|
319
|
+
break;
|
|
320
|
+
case graphql.Kind.INT:
|
|
321
|
+
args[arg.name.value] = parseInt(value.value, 10);
|
|
322
|
+
break;
|
|
323
|
+
case graphql.Kind.FLOAT:
|
|
324
|
+
args[arg.name.value] = parseFloat(value.value);
|
|
325
|
+
break;
|
|
326
|
+
case graphql.Kind.STRING:
|
|
327
|
+
args[arg.name.value] = value.value;
|
|
328
|
+
break;
|
|
329
|
+
case graphql.Kind.BOOLEAN:
|
|
330
|
+
args[arg.name.value] = value.value;
|
|
331
|
+
break;
|
|
332
|
+
case graphql.Kind.NULL:
|
|
333
|
+
args[arg.name.value] = null;
|
|
334
|
+
break;
|
|
335
|
+
case graphql.Kind.ENUM:
|
|
336
|
+
args[arg.name.value] = value.value;
|
|
337
|
+
break;
|
|
338
|
+
case graphql.Kind.LIST:
|
|
339
|
+
args[arg.name.value] = [];
|
|
340
|
+
break;
|
|
341
|
+
case graphql.Kind.OBJECT:
|
|
342
|
+
args[arg.name.value] = {};
|
|
343
|
+
break;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return args;
|
|
347
|
+
}
|
|
348
|
+
var validateComplexity = (query, operationName, variables, schema, fieldComplexities, config) => effect.Effect.gen(function* () {
|
|
349
|
+
const document = yield* effect.Effect.try({
|
|
350
|
+
try: () => graphql.parse(query),
|
|
351
|
+
catch: (error) => new ComplexityAnalysisError({
|
|
352
|
+
message: `Failed to parse query: ${error}`,
|
|
353
|
+
cause: error
|
|
354
|
+
})
|
|
355
|
+
});
|
|
356
|
+
const operation = yield* effect.Effect.try({
|
|
357
|
+
try: () => {
|
|
358
|
+
const operations = document.definitions.filter(
|
|
359
|
+
(d) => d.kind === graphql.Kind.OPERATION_DEFINITION
|
|
360
|
+
);
|
|
361
|
+
if (operations.length === 0) {
|
|
362
|
+
throw new Error("No operation found in query");
|
|
363
|
+
}
|
|
364
|
+
if (operationName) {
|
|
365
|
+
const op = operations.find((o) => o.name?.value === operationName);
|
|
366
|
+
if (!op) {
|
|
367
|
+
throw new Error(`Operation "${operationName}" not found`);
|
|
368
|
+
}
|
|
369
|
+
return op;
|
|
370
|
+
}
|
|
371
|
+
if (operations.length > 1) {
|
|
372
|
+
throw new Error("Multiple operations found - operationName required");
|
|
373
|
+
}
|
|
374
|
+
return operations[0];
|
|
375
|
+
},
|
|
376
|
+
catch: (error) => new ComplexityAnalysisError({
|
|
377
|
+
message: String(error),
|
|
378
|
+
cause: error
|
|
379
|
+
})
|
|
380
|
+
});
|
|
381
|
+
const calculator = config.calculator ?? defaultComplexityCalculator(config.defaultFieldComplexity ?? 1);
|
|
382
|
+
const result = yield* calculator({
|
|
383
|
+
document,
|
|
384
|
+
operation,
|
|
385
|
+
variables,
|
|
386
|
+
schema,
|
|
387
|
+
fieldComplexities
|
|
388
|
+
});
|
|
389
|
+
const checkLimit = (limitType, limit, actual) => effect.Effect.gen(function* () {
|
|
390
|
+
if (limit !== void 0 && actual > limit) {
|
|
391
|
+
const exceededInfo = {
|
|
392
|
+
result,
|
|
393
|
+
exceededLimit: limitType,
|
|
394
|
+
limit,
|
|
395
|
+
actual,
|
|
396
|
+
query,
|
|
397
|
+
operationName
|
|
398
|
+
};
|
|
399
|
+
if (config.onExceeded) {
|
|
400
|
+
yield* config.onExceeded(exceededInfo);
|
|
401
|
+
}
|
|
402
|
+
yield* effect.Effect.fail(
|
|
403
|
+
new ComplexityLimitExceededError({
|
|
404
|
+
message: `Query ${limitType} of ${actual} exceeds maximum allowed ${limitType} of ${limit}`,
|
|
405
|
+
limit,
|
|
406
|
+
actual,
|
|
407
|
+
limitType
|
|
408
|
+
})
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
yield* checkLimit("depth", config.maxDepth, result.depth);
|
|
413
|
+
yield* checkLimit("complexity", config.maxComplexity, result.complexity);
|
|
414
|
+
yield* checkLimit("aliases", config.maxAliases, result.aliasCount);
|
|
415
|
+
yield* checkLimit("fields", config.maxFields, result.fieldCount);
|
|
416
|
+
return result;
|
|
417
|
+
});
|
|
418
|
+
var ComplexityConfigFromEnv = effect.Config.all({
|
|
419
|
+
maxDepth: effect.Config.number("GRAPHQL_MAX_DEPTH").pipe(effect.Config.option),
|
|
420
|
+
maxComplexity: effect.Config.number("GRAPHQL_MAX_COMPLEXITY").pipe(effect.Config.option),
|
|
421
|
+
maxAliases: effect.Config.number("GRAPHQL_MAX_ALIASES").pipe(effect.Config.option),
|
|
422
|
+
maxFields: effect.Config.number("GRAPHQL_MAX_FIELDS").pipe(effect.Config.option),
|
|
423
|
+
defaultFieldComplexity: effect.Config.number("GRAPHQL_DEFAULT_FIELD_COMPLEXITY").pipe(
|
|
424
|
+
effect.Config.withDefault(1)
|
|
425
|
+
)
|
|
426
|
+
}).pipe(
|
|
427
|
+
effect.Config.map(({ maxDepth, maxComplexity, maxAliases, maxFields, defaultFieldComplexity }) => ({
|
|
428
|
+
maxDepth: effect.Option.getOrUndefined(maxDepth),
|
|
429
|
+
maxComplexity: effect.Option.getOrUndefined(maxComplexity),
|
|
430
|
+
maxAliases: effect.Option.getOrUndefined(maxAliases),
|
|
431
|
+
maxFields: effect.Option.getOrUndefined(maxFields),
|
|
432
|
+
defaultFieldComplexity
|
|
433
|
+
}))
|
|
434
|
+
);
|
|
435
|
+
var depthOnlyCalculator = (info) => effect.Effect.try({
|
|
436
|
+
try: () => {
|
|
437
|
+
const fragments = /* @__PURE__ */ new Map();
|
|
438
|
+
for (const definition of info.document.definitions) {
|
|
439
|
+
if (definition.kind === graphql.Kind.FRAGMENT_DEFINITION) {
|
|
440
|
+
fragments.set(definition.name.value, definition);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
const depth = calculateMaxDepth(info.operation.selectionSet, fragments, 1, /* @__PURE__ */ new Set());
|
|
444
|
+
return {
|
|
445
|
+
depth,
|
|
446
|
+
complexity: 0,
|
|
447
|
+
fieldCount: 0,
|
|
448
|
+
aliasCount: 0
|
|
449
|
+
};
|
|
450
|
+
},
|
|
451
|
+
catch: (error) => new ComplexityAnalysisError({
|
|
452
|
+
message: `Failed to analyze query depth: ${error}`,
|
|
453
|
+
cause: error
|
|
454
|
+
})
|
|
455
|
+
});
|
|
456
|
+
function calculateMaxDepth(selectionSet, fragments, currentDepth, visitedFragments) {
|
|
457
|
+
let maxDepth = currentDepth;
|
|
458
|
+
for (const selection of selectionSet.selections) {
|
|
459
|
+
switch (selection.kind) {
|
|
460
|
+
case graphql.Kind.FIELD:
|
|
461
|
+
if (selection.selectionSet) {
|
|
462
|
+
const nestedDepth = calculateMaxDepth(
|
|
463
|
+
selection.selectionSet,
|
|
464
|
+
fragments,
|
|
465
|
+
currentDepth + 1,
|
|
466
|
+
visitedFragments
|
|
467
|
+
);
|
|
468
|
+
maxDepth = Math.max(maxDepth, nestedDepth);
|
|
469
|
+
}
|
|
470
|
+
break;
|
|
471
|
+
case graphql.Kind.FRAGMENT_SPREAD: {
|
|
472
|
+
const fragmentName = selection.name.value;
|
|
473
|
+
if (!visitedFragments.has(fragmentName)) {
|
|
474
|
+
const fragment = fragments.get(fragmentName);
|
|
475
|
+
if (fragment) {
|
|
476
|
+
const newVisited = new Set(visitedFragments);
|
|
477
|
+
newVisited.add(fragmentName);
|
|
478
|
+
const fragmentDepth = calculateMaxDepth(
|
|
479
|
+
fragment.selectionSet,
|
|
480
|
+
fragments,
|
|
481
|
+
currentDepth,
|
|
482
|
+
newVisited
|
|
483
|
+
);
|
|
484
|
+
maxDepth = Math.max(maxDepth, fragmentDepth);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
break;
|
|
488
|
+
}
|
|
489
|
+
case graphql.Kind.INLINE_FRAGMENT: {
|
|
490
|
+
const inlineDepth = calculateMaxDepth(
|
|
491
|
+
selection.selectionSet,
|
|
492
|
+
fragments,
|
|
493
|
+
currentDepth,
|
|
494
|
+
visitedFragments
|
|
495
|
+
);
|
|
496
|
+
maxDepth = Math.max(maxDepth, inlineDepth);
|
|
497
|
+
break;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return maxDepth;
|
|
502
|
+
}
|
|
503
|
+
var combineCalculators = (...calculators) => {
|
|
504
|
+
return (info) => effect.Effect.gen(function* () {
|
|
505
|
+
let maxDepth = 0;
|
|
506
|
+
let maxComplexity = 0;
|
|
507
|
+
let maxFieldCount = 0;
|
|
508
|
+
let maxAliasCount = 0;
|
|
509
|
+
for (const calculator of calculators) {
|
|
510
|
+
const result = yield* calculator(info);
|
|
511
|
+
maxDepth = Math.max(maxDepth, result.depth);
|
|
512
|
+
maxComplexity = Math.max(maxComplexity, result.complexity);
|
|
513
|
+
maxFieldCount = Math.max(maxFieldCount, result.fieldCount);
|
|
514
|
+
maxAliasCount = Math.max(maxAliasCount, result.aliasCount);
|
|
515
|
+
}
|
|
516
|
+
return {
|
|
517
|
+
depth: maxDepth,
|
|
518
|
+
complexity: maxComplexity,
|
|
519
|
+
fieldCount: maxFieldCount,
|
|
520
|
+
aliasCount: maxAliasCount
|
|
521
|
+
};
|
|
522
|
+
});
|
|
523
|
+
};
|
|
524
|
+
var computeCachePolicy = (info) => effect.Effect.sync(() => {
|
|
525
|
+
const fragments = /* @__PURE__ */ new Map();
|
|
526
|
+
for (const definition of info.document.definitions) {
|
|
527
|
+
if (definition.kind === graphql.Kind.FRAGMENT_DEFINITION) {
|
|
528
|
+
fragments.set(definition.name.value, definition);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
const rootType = getRootType2(info.schema, info.operation.operation);
|
|
532
|
+
if (!rootType) {
|
|
533
|
+
return { maxAge: 0, scope: "PUBLIC" };
|
|
534
|
+
}
|
|
535
|
+
const defaultMaxAge = info.config.defaultMaxAge ?? 0;
|
|
536
|
+
const defaultScope = info.config.defaultScope ?? "PUBLIC";
|
|
537
|
+
const result = analyzeSelectionSet2(
|
|
538
|
+
info.operation.selectionSet,
|
|
539
|
+
rootType,
|
|
540
|
+
info.schema,
|
|
541
|
+
fragments,
|
|
542
|
+
info.cacheHints,
|
|
543
|
+
defaultMaxAge,
|
|
544
|
+
defaultScope,
|
|
545
|
+
void 0,
|
|
546
|
+
// No parent maxAge for root
|
|
547
|
+
/* @__PURE__ */ new Set()
|
|
548
|
+
);
|
|
549
|
+
return result;
|
|
550
|
+
});
|
|
551
|
+
var computeCachePolicyFromQuery = (query, operationName, schema, cacheHints, config = {}) => effect.Effect.gen(function* () {
|
|
552
|
+
const document = yield* effect.Effect.try({
|
|
553
|
+
try: () => graphql.parse(query),
|
|
554
|
+
catch: (error) => new Error(`Failed to parse query: ${error}`)
|
|
555
|
+
});
|
|
556
|
+
const operation = yield* effect.Effect.try({
|
|
557
|
+
try: () => {
|
|
558
|
+
const operations = document.definitions.filter(
|
|
559
|
+
(d) => d.kind === graphql.Kind.OPERATION_DEFINITION
|
|
560
|
+
);
|
|
561
|
+
if (operations.length === 0) {
|
|
562
|
+
throw new Error("No operation found in query");
|
|
563
|
+
}
|
|
564
|
+
if (operationName) {
|
|
565
|
+
const op = operations.find((o) => o.name?.value === operationName);
|
|
566
|
+
if (!op) {
|
|
567
|
+
throw new Error(`Operation "${operationName}" not found`);
|
|
568
|
+
}
|
|
569
|
+
return op;
|
|
570
|
+
}
|
|
571
|
+
if (operations.length > 1) {
|
|
572
|
+
throw new Error("Multiple operations found - operationName required");
|
|
573
|
+
}
|
|
574
|
+
return operations[0];
|
|
575
|
+
},
|
|
576
|
+
catch: (error) => error
|
|
577
|
+
});
|
|
578
|
+
return yield* computeCachePolicy({
|
|
579
|
+
document,
|
|
580
|
+
operation,
|
|
581
|
+
schema,
|
|
582
|
+
cacheHints,
|
|
583
|
+
config
|
|
584
|
+
});
|
|
585
|
+
});
|
|
586
|
+
var toCacheControlHeader = (policy) => {
|
|
587
|
+
if (policy.maxAge === 0) {
|
|
588
|
+
return "no-store";
|
|
589
|
+
}
|
|
590
|
+
const directives = [];
|
|
591
|
+
directives.push(policy.scope === "PRIVATE" ? "private" : "public");
|
|
592
|
+
directives.push(`max-age=${policy.maxAge}`);
|
|
593
|
+
return directives.join(", ");
|
|
594
|
+
};
|
|
595
|
+
function getRootType2(schema, operation) {
|
|
596
|
+
switch (operation) {
|
|
597
|
+
case "query":
|
|
598
|
+
return schema.getQueryType() ?? null;
|
|
599
|
+
case "mutation":
|
|
600
|
+
return schema.getMutationType() ?? null;
|
|
601
|
+
case "subscription":
|
|
602
|
+
return schema.getSubscriptionType() ?? null;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
function getNamedType2(type) {
|
|
606
|
+
if (type instanceof graphql.GraphQLNonNull || type instanceof graphql.GraphQLList) {
|
|
607
|
+
return getNamedType2(type.ofType);
|
|
608
|
+
}
|
|
609
|
+
if (type instanceof graphql.GraphQLObjectType || type instanceof graphql.GraphQLScalarType || type instanceof graphql.GraphQLEnumType) {
|
|
610
|
+
return type;
|
|
611
|
+
}
|
|
612
|
+
return null;
|
|
613
|
+
}
|
|
614
|
+
function isLeafType(type) {
|
|
615
|
+
const namedType = getNamedType2(type);
|
|
616
|
+
return namedType instanceof graphql.GraphQLScalarType || namedType instanceof graphql.GraphQLEnumType;
|
|
617
|
+
}
|
|
618
|
+
function aggregatePolicy(acc, policy) {
|
|
619
|
+
if (acc.minMaxAge === void 0) {
|
|
620
|
+
acc.minMaxAge = policy.maxAge;
|
|
621
|
+
} else {
|
|
622
|
+
acc.minMaxAge = Math.min(acc.minMaxAge, policy.maxAge);
|
|
623
|
+
}
|
|
624
|
+
if (policy.scope === "PRIVATE") {
|
|
625
|
+
acc.hasPrivate = true;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
function analyzeFragmentSpread2(fragmentName, ctx, parentMaxAge, visitedFragments) {
|
|
629
|
+
if (visitedFragments.has(fragmentName)) {
|
|
630
|
+
return void 0;
|
|
631
|
+
}
|
|
632
|
+
const fragment = ctx.fragments.get(fragmentName);
|
|
633
|
+
if (!fragment) {
|
|
634
|
+
return void 0;
|
|
635
|
+
}
|
|
636
|
+
const fragmentType = ctx.schema.getType(fragment.typeCondition.name.value);
|
|
637
|
+
if (!(fragmentType instanceof graphql.GraphQLObjectType)) {
|
|
638
|
+
return void 0;
|
|
639
|
+
}
|
|
640
|
+
const newVisited = new Set(visitedFragments);
|
|
641
|
+
newVisited.add(fragmentName);
|
|
642
|
+
return analyzeSelectionSet2(fragment.selectionSet, fragmentType, ctx, parentMaxAge, newVisited);
|
|
643
|
+
}
|
|
644
|
+
function analyzeInlineFragment2(selection, parentType, ctx, parentMaxAge, visitedFragments) {
|
|
645
|
+
let targetType = parentType;
|
|
646
|
+
if (selection.typeCondition) {
|
|
647
|
+
const conditionType = ctx.schema.getType(selection.typeCondition.name.value);
|
|
648
|
+
if (conditionType instanceof graphql.GraphQLObjectType) {
|
|
649
|
+
targetType = conditionType;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
return analyzeSelectionSet2(
|
|
653
|
+
selection.selectionSet,
|
|
654
|
+
targetType,
|
|
655
|
+
ctx,
|
|
656
|
+
parentMaxAge,
|
|
657
|
+
visitedFragments
|
|
658
|
+
);
|
|
659
|
+
}
|
|
660
|
+
function lookupEffectiveCacheHint(parentTypeName, fieldName, returnType, cacheHints) {
|
|
661
|
+
const fieldKey = `${parentTypeName}.${fieldName}`;
|
|
662
|
+
const fieldHint = cacheHints.get(fieldKey);
|
|
663
|
+
if (fieldHint) return fieldHint;
|
|
664
|
+
const namedType = getNamedType2(returnType);
|
|
665
|
+
return namedType ? cacheHints.get(namedType.name) : void 0;
|
|
666
|
+
}
|
|
667
|
+
function computeFieldMaxAge(hint, fieldType, parentMaxAge, defaultMaxAge) {
|
|
668
|
+
if (hint) {
|
|
669
|
+
if (hint.inheritMaxAge && parentMaxAge !== void 0) {
|
|
670
|
+
return parentMaxAge;
|
|
671
|
+
}
|
|
672
|
+
if (hint.maxAge !== void 0) {
|
|
673
|
+
return hint.maxAge;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
if (isLeafType(fieldType) && parentMaxAge !== void 0) {
|
|
677
|
+
return parentMaxAge;
|
|
678
|
+
}
|
|
679
|
+
return defaultMaxAge;
|
|
680
|
+
}
|
|
681
|
+
function analyzeSelectionSet2(selectionSet, parentType, schemaOrCtx, fragmentsOrParentMaxAge, cacheHintsOrVisited, defaultMaxAge, defaultScope, parentMaxAge, visitedFragments) {
|
|
682
|
+
let ctx;
|
|
683
|
+
let actualParentMaxAge;
|
|
684
|
+
let actualVisitedFragments;
|
|
685
|
+
if (schemaOrCtx instanceof graphql.GraphQLSchema) {
|
|
686
|
+
ctx = {
|
|
687
|
+
schema: schemaOrCtx,
|
|
688
|
+
fragments: fragmentsOrParentMaxAge,
|
|
689
|
+
cacheHints: cacheHintsOrVisited,
|
|
690
|
+
defaultMaxAge,
|
|
691
|
+
defaultScope
|
|
692
|
+
};
|
|
693
|
+
actualParentMaxAge = parentMaxAge;
|
|
694
|
+
actualVisitedFragments = visitedFragments;
|
|
695
|
+
} else {
|
|
696
|
+
ctx = schemaOrCtx;
|
|
697
|
+
actualParentMaxAge = fragmentsOrParentMaxAge;
|
|
698
|
+
actualVisitedFragments = cacheHintsOrVisited;
|
|
699
|
+
}
|
|
700
|
+
const acc = { minMaxAge: void 0, hasPrivate: false };
|
|
701
|
+
for (const selection of selectionSet.selections) {
|
|
702
|
+
let fieldPolicy;
|
|
703
|
+
switch (selection.kind) {
|
|
704
|
+
case graphql.Kind.FIELD:
|
|
705
|
+
fieldPolicy = analyzeField2(
|
|
706
|
+
selection,
|
|
707
|
+
parentType,
|
|
708
|
+
ctx,
|
|
709
|
+
actualParentMaxAge,
|
|
710
|
+
actualVisitedFragments
|
|
711
|
+
);
|
|
712
|
+
break;
|
|
713
|
+
case graphql.Kind.FRAGMENT_SPREAD:
|
|
714
|
+
fieldPolicy = analyzeFragmentSpread2(
|
|
715
|
+
selection.name.value,
|
|
716
|
+
ctx,
|
|
717
|
+
actualParentMaxAge,
|
|
718
|
+
actualVisitedFragments
|
|
719
|
+
);
|
|
720
|
+
break;
|
|
721
|
+
case graphql.Kind.INLINE_FRAGMENT:
|
|
722
|
+
fieldPolicy = analyzeInlineFragment2(
|
|
723
|
+
selection,
|
|
724
|
+
parentType,
|
|
725
|
+
ctx,
|
|
726
|
+
actualParentMaxAge,
|
|
727
|
+
actualVisitedFragments
|
|
728
|
+
);
|
|
729
|
+
break;
|
|
730
|
+
}
|
|
731
|
+
if (fieldPolicy) {
|
|
732
|
+
aggregatePolicy(acc, fieldPolicy);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
return {
|
|
736
|
+
maxAge: acc.minMaxAge ?? ctx.defaultMaxAge,
|
|
737
|
+
scope: acc.hasPrivate ? "PRIVATE" : ctx.defaultScope
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
function analyzeField2(field, parentType, ctx, parentMaxAge, visitedFragments) {
|
|
741
|
+
const fieldName = field.name.value;
|
|
742
|
+
if (fieldName.startsWith("__")) {
|
|
743
|
+
return { maxAge: Infinity, scope: "PUBLIC" };
|
|
744
|
+
}
|
|
745
|
+
const schemaField = parentType.getFields()[fieldName];
|
|
746
|
+
if (!schemaField) {
|
|
747
|
+
return { maxAge: ctx.defaultMaxAge, scope: ctx.defaultScope };
|
|
748
|
+
}
|
|
749
|
+
const effectiveHint = lookupEffectiveCacheHint(
|
|
750
|
+
parentType.name,
|
|
751
|
+
fieldName,
|
|
752
|
+
schemaField.type,
|
|
753
|
+
ctx.cacheHints
|
|
754
|
+
);
|
|
755
|
+
const fieldMaxAge = computeFieldMaxAge(
|
|
756
|
+
effectiveHint,
|
|
757
|
+
schemaField.type,
|
|
758
|
+
parentMaxAge,
|
|
759
|
+
ctx.defaultMaxAge
|
|
760
|
+
);
|
|
761
|
+
const fieldScope = effectiveHint?.scope ?? ctx.defaultScope;
|
|
762
|
+
const namedType = getNamedType2(schemaField.type);
|
|
763
|
+
if (field.selectionSet && namedType instanceof graphql.GraphQLObjectType) {
|
|
764
|
+
const nestedPolicy = analyzeSelectionSet2(
|
|
765
|
+
field.selectionSet,
|
|
766
|
+
namedType,
|
|
767
|
+
ctx,
|
|
768
|
+
fieldMaxAge,
|
|
769
|
+
visitedFragments
|
|
770
|
+
);
|
|
771
|
+
return {
|
|
772
|
+
maxAge: Math.min(fieldMaxAge, nestedPolicy.maxAge),
|
|
773
|
+
scope: fieldScope === "PRIVATE" || nestedPolicy.scope === "PRIVATE" ? "PRIVATE" : "PUBLIC"
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
return { maxAge: fieldMaxAge, scope: fieldScope };
|
|
777
|
+
}
|
|
778
|
+
var CacheControlConfigFromEnv = effect.Config.all({
|
|
779
|
+
enabled: effect.Config.boolean("GRAPHQL_CACHE_CONTROL_ENABLED").pipe(effect.Config.withDefault(true)),
|
|
780
|
+
defaultMaxAge: effect.Config.number("GRAPHQL_CACHE_CONTROL_DEFAULT_MAX_AGE").pipe(effect.Config.withDefault(0)),
|
|
781
|
+
defaultScope: effect.Config.string("GRAPHQL_CACHE_CONTROL_DEFAULT_SCOPE").pipe(
|
|
782
|
+
effect.Config.withDefault("PUBLIC"),
|
|
783
|
+
effect.Config.map((s) => s === "PRIVATE" ? "PRIVATE" : "PUBLIC")
|
|
784
|
+
),
|
|
785
|
+
calculateHttpHeaders: effect.Config.boolean("GRAPHQL_CACHE_CONTROL_HTTP_HEADERS").pipe(
|
|
786
|
+
effect.Config.withDefault(true)
|
|
787
|
+
)
|
|
788
|
+
});
|
|
789
|
+
var ExtensionsService = effect.Context.GenericTag(
|
|
790
|
+
"@effect-gql/ExtensionsService"
|
|
791
|
+
);
|
|
792
|
+
function deepMerge(target, source) {
|
|
793
|
+
const result = { ...target };
|
|
794
|
+
for (const key of Object.keys(source)) {
|
|
795
|
+
const sourceValue = source[key];
|
|
796
|
+
const targetValue = result[key];
|
|
797
|
+
if (typeof sourceValue === "object" && sourceValue !== null && !Array.isArray(sourceValue) && typeof targetValue === "object" && targetValue !== null && !Array.isArray(targetValue)) {
|
|
798
|
+
result[key] = deepMerge(
|
|
799
|
+
targetValue,
|
|
800
|
+
sourceValue
|
|
801
|
+
);
|
|
802
|
+
} else {
|
|
803
|
+
result[key] = sourceValue;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
return result;
|
|
807
|
+
}
|
|
808
|
+
var makeExtensionsService = () => effect.Effect.gen(function* () {
|
|
809
|
+
const ref = yield* effect.Ref.make({});
|
|
810
|
+
return ExtensionsService.of({
|
|
811
|
+
set: (key, value) => effect.Ref.update(ref, (current) => ({ ...current, [key]: value })),
|
|
812
|
+
merge: (key, value) => effect.Ref.update(ref, (current) => {
|
|
813
|
+
const existing = current[key];
|
|
814
|
+
if (typeof existing === "object" && existing !== null && !Array.isArray(existing)) {
|
|
815
|
+
return {
|
|
816
|
+
...current,
|
|
817
|
+
[key]: deepMerge(existing, value)
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
return { ...current, [key]: value };
|
|
821
|
+
}),
|
|
822
|
+
get: () => effect.Ref.get(ref)
|
|
823
|
+
});
|
|
824
|
+
});
|
|
825
|
+
var runExtensionHooks = (extensions, hookName, getHookEffect) => effect.Effect.forEach(
|
|
826
|
+
extensions.filter((ext) => ext[hookName] !== void 0),
|
|
827
|
+
(ext) => getHookEffect(ext).pipe(
|
|
828
|
+
effect.Effect.catchAllCause(
|
|
829
|
+
(cause) => effect.Effect.logWarning(`Extension "${ext.name}" ${String(hookName)} hook failed`, cause)
|
|
830
|
+
)
|
|
831
|
+
),
|
|
832
|
+
{ discard: true }
|
|
833
|
+
);
|
|
834
|
+
var runParseHooks = (extensions, source, document) => runExtensionHooks(extensions, "onParse", (ext) => ext.onParse(source, document));
|
|
835
|
+
var runValidateHooks = (extensions, document, errors) => runExtensionHooks(extensions, "onValidate", (ext) => ext.onValidate(document, errors));
|
|
836
|
+
var runExecuteStartHooks = (extensions, args) => runExtensionHooks(extensions, "onExecuteStart", (ext) => ext.onExecuteStart(args));
|
|
837
|
+
var runExecuteEndHooks = (extensions, result) => runExtensionHooks(extensions, "onExecuteEnd", (ext) => ext.onExecuteEnd(result));
|
|
838
|
+
|
|
839
|
+
// src/server/router.ts
|
|
840
|
+
var defaultErrorHandler = (cause) => (process.env.NODE_ENV !== "production" ? effect.Effect.logError("GraphQL error", cause) : effect.Effect.void).pipe(
|
|
841
|
+
effect.Effect.andThen(
|
|
842
|
+
platform.HttpServerResponse.json(
|
|
843
|
+
{
|
|
844
|
+
errors: [
|
|
845
|
+
{
|
|
846
|
+
message: "An error occurred processing your request"
|
|
847
|
+
}
|
|
848
|
+
]
|
|
849
|
+
},
|
|
850
|
+
{ status: 500 }
|
|
851
|
+
).pipe(effect.Effect.orDie)
|
|
852
|
+
)
|
|
853
|
+
);
|
|
854
|
+
var GraphQLRequestBodySchema = effect.Schema.Struct({
|
|
855
|
+
query: effect.Schema.String,
|
|
856
|
+
variables: effect.Schema.optionalWith(effect.Schema.Record({ key: effect.Schema.String, value: effect.Schema.Unknown }), {
|
|
857
|
+
as: "Option"
|
|
858
|
+
}),
|
|
859
|
+
operationName: effect.Schema.optionalWith(effect.Schema.String, { as: "Option" })
|
|
860
|
+
});
|
|
861
|
+
var decodeRequestBody = platform.HttpIncomingMessage.schemaBodyJson(GraphQLRequestBodySchema);
|
|
862
|
+
var parseGraphQLQuery = (query, extensionsService) => {
|
|
863
|
+
try {
|
|
864
|
+
const document = graphql.parse(query);
|
|
865
|
+
return effect.Effect.succeed({ ok: true, document });
|
|
866
|
+
} catch (parseError) {
|
|
867
|
+
return extensionsService.get().pipe(
|
|
868
|
+
effect.Effect.flatMap(
|
|
869
|
+
(extensionData) => platform.HttpServerResponse.json({
|
|
870
|
+
errors: [{ message: String(parseError) }],
|
|
871
|
+
extensions: Object.keys(extensionData).length > 0 ? extensionData : void 0
|
|
872
|
+
}).pipe(
|
|
873
|
+
effect.Effect.orDie,
|
|
874
|
+
effect.Effect.map((response) => ({ ok: false, response }))
|
|
875
|
+
)
|
|
876
|
+
)
|
|
877
|
+
);
|
|
878
|
+
}
|
|
879
|
+
};
|
|
880
|
+
var runComplexityValidation = (body, schema, fieldComplexities, complexityConfig) => {
|
|
881
|
+
if (!complexityConfig) {
|
|
882
|
+
return effect.Effect.void;
|
|
883
|
+
}
|
|
884
|
+
return validateComplexity(
|
|
885
|
+
body.query,
|
|
886
|
+
body.operationName,
|
|
887
|
+
body.variables,
|
|
888
|
+
schema,
|
|
889
|
+
fieldComplexities,
|
|
890
|
+
complexityConfig
|
|
891
|
+
).pipe(
|
|
892
|
+
effect.Effect.catchTag("ComplexityLimitExceededError", (error) => effect.Effect.fail(error)),
|
|
893
|
+
effect.Effect.catchTag(
|
|
894
|
+
"ComplexityAnalysisError",
|
|
895
|
+
(error) => effect.Effect.logWarning("Complexity analysis failed", error)
|
|
896
|
+
)
|
|
897
|
+
);
|
|
898
|
+
};
|
|
899
|
+
var isPromiseLike = (value) => value !== null && typeof value === "object" && "then" in value && typeof value.then === "function";
|
|
900
|
+
var executeGraphQLQuery = (schema, document, variables, operationName, runtime) => {
|
|
901
|
+
const tryExecute = effect.Effect.try({
|
|
902
|
+
try: () => graphql.execute({
|
|
903
|
+
schema,
|
|
904
|
+
document,
|
|
905
|
+
variableValues: variables,
|
|
906
|
+
operationName,
|
|
907
|
+
contextValue: { runtime }
|
|
908
|
+
}),
|
|
909
|
+
catch: (error) => new Error(String(error))
|
|
910
|
+
});
|
|
911
|
+
return tryExecute.pipe(
|
|
912
|
+
effect.Effect.flatMap((executeResult) => {
|
|
913
|
+
if (isPromiseLike(executeResult)) {
|
|
914
|
+
return effect.Effect.promise(() => executeResult);
|
|
915
|
+
}
|
|
916
|
+
return effect.Effect.succeed(executeResult);
|
|
917
|
+
})
|
|
918
|
+
);
|
|
919
|
+
};
|
|
920
|
+
var computeCacheControlHeader = (document, operationName, schema, cacheHints, cacheControlConfig) => {
|
|
921
|
+
if (cacheControlConfig?.enabled === false || cacheControlConfig?.calculateHttpHeaders === false) {
|
|
922
|
+
return effect.Effect.succeed(void 0);
|
|
923
|
+
}
|
|
924
|
+
const operations = document.definitions.filter(
|
|
925
|
+
(d) => d.kind === graphql.Kind.OPERATION_DEFINITION
|
|
926
|
+
);
|
|
927
|
+
const operation = operationName ? operations.find((o) => o.name?.value === operationName) : operations[0];
|
|
928
|
+
if (!operation || operation.operation === "mutation") {
|
|
929
|
+
return effect.Effect.succeed(void 0);
|
|
930
|
+
}
|
|
931
|
+
return computeCachePolicy({
|
|
932
|
+
document,
|
|
933
|
+
operation,
|
|
934
|
+
schema,
|
|
935
|
+
cacheHints,
|
|
936
|
+
config: cacheControlConfig ?? {}
|
|
937
|
+
}).pipe(effect.Effect.map(toCacheControlHeader));
|
|
938
|
+
};
|
|
939
|
+
var buildGraphQLResponse = (result, extensionData, cacheControlHeader) => {
|
|
940
|
+
const finalResult = Object.keys(extensionData).length > 0 ? {
|
|
941
|
+
...result,
|
|
942
|
+
extensions: {
|
|
943
|
+
...result.extensions,
|
|
944
|
+
...extensionData
|
|
945
|
+
}
|
|
946
|
+
} : result;
|
|
947
|
+
const responseHeaders = cacheControlHeader ? { "cache-control": cacheControlHeader } : void 0;
|
|
948
|
+
return platform.HttpServerResponse.json(finalResult, { headers: responseHeaders }).pipe(effect.Effect.orDie);
|
|
949
|
+
};
|
|
950
|
+
var handleComplexityError = (error) => platform.HttpServerResponse.json(
|
|
951
|
+
{
|
|
952
|
+
errors: [
|
|
953
|
+
{
|
|
954
|
+
message: error.message,
|
|
955
|
+
extensions: {
|
|
956
|
+
code: "COMPLEXITY_LIMIT_EXCEEDED",
|
|
957
|
+
limitType: error.limitType,
|
|
958
|
+
limit: error.limit,
|
|
959
|
+
actual: error.actual
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
]
|
|
963
|
+
},
|
|
964
|
+
{ status: 400 }
|
|
965
|
+
).pipe(effect.Effect.orDie);
|
|
966
|
+
var makeGraphQLRouter = (schema, layer, options = {}) => {
|
|
967
|
+
const resolvedConfig = normalizeConfig(options);
|
|
968
|
+
const fieldComplexities = options.fieldComplexities ?? /* @__PURE__ */ new Map();
|
|
969
|
+
const cacheHints = options.cacheHints ?? /* @__PURE__ */ new Map();
|
|
970
|
+
const extensions = options.extensions ?? [];
|
|
971
|
+
const errorHandler = options.errorHandler ?? defaultErrorHandler;
|
|
972
|
+
const graphqlHandler = effect.Effect.gen(function* () {
|
|
973
|
+
const extensionsService = yield* makeExtensionsService();
|
|
974
|
+
const runtime = yield* effect.Effect.runtime();
|
|
975
|
+
const request = yield* platform.HttpServerRequest.HttpServerRequest;
|
|
976
|
+
const parsedBody = yield* decodeRequestBody(request);
|
|
977
|
+
const body = {
|
|
978
|
+
query: parsedBody.query,
|
|
979
|
+
variables: parsedBody.variables._tag === "Some" ? parsedBody.variables.value : void 0,
|
|
980
|
+
operationName: parsedBody.operationName._tag === "Some" ? parsedBody.operationName.value : void 0
|
|
981
|
+
};
|
|
982
|
+
const parseResult = yield* parseGraphQLQuery(body.query, extensionsService);
|
|
983
|
+
if (!parseResult.ok) {
|
|
984
|
+
return parseResult.response;
|
|
985
|
+
}
|
|
986
|
+
const document = parseResult.document;
|
|
987
|
+
yield* runParseHooks(extensions, body.query, document).pipe(
|
|
988
|
+
effect.Effect.provideService(ExtensionsService, extensionsService)
|
|
989
|
+
);
|
|
990
|
+
const validationRules = resolvedConfig.introspection ? void 0 : graphql.specifiedRules.concat(graphql.NoSchemaIntrospectionCustomRule);
|
|
991
|
+
const validationErrors = graphql.validate(schema, document, validationRules);
|
|
992
|
+
yield* runValidateHooks(extensions, document, validationErrors).pipe(
|
|
993
|
+
effect.Effect.provideService(ExtensionsService, extensionsService)
|
|
994
|
+
);
|
|
995
|
+
if (validationErrors.length > 0) {
|
|
996
|
+
const extensionData2 = yield* extensionsService.get();
|
|
997
|
+
return yield* platform.HttpServerResponse.json(
|
|
998
|
+
{
|
|
999
|
+
errors: validationErrors.map((e) => ({
|
|
1000
|
+
message: e.message,
|
|
1001
|
+
locations: e.locations,
|
|
1002
|
+
path: e.path
|
|
1003
|
+
})),
|
|
1004
|
+
extensions: Object.keys(extensionData2).length > 0 ? extensionData2 : void 0
|
|
1005
|
+
},
|
|
1006
|
+
{ status: 400 }
|
|
1007
|
+
);
|
|
1008
|
+
}
|
|
1009
|
+
yield* runComplexityValidation(body, schema, fieldComplexities, resolvedConfig.complexity);
|
|
1010
|
+
yield* runExecuteStartHooks(extensions, {
|
|
1011
|
+
source: body.query,
|
|
1012
|
+
document,
|
|
1013
|
+
variableValues: body.variables,
|
|
1014
|
+
operationName: body.operationName,
|
|
1015
|
+
schema,
|
|
1016
|
+
fieldComplexities
|
|
1017
|
+
}).pipe(effect.Effect.provideService(ExtensionsService, extensionsService));
|
|
1018
|
+
const result = yield* executeGraphQLQuery(
|
|
1019
|
+
schema,
|
|
1020
|
+
document,
|
|
1021
|
+
body.variables,
|
|
1022
|
+
body.operationName,
|
|
1023
|
+
runtime
|
|
1024
|
+
);
|
|
1025
|
+
yield* runExecuteEndHooks(extensions, result).pipe(
|
|
1026
|
+
effect.Effect.provideService(ExtensionsService, extensionsService)
|
|
1027
|
+
);
|
|
1028
|
+
const extensionData = yield* extensionsService.get();
|
|
1029
|
+
const cacheControlHeader = yield* computeCacheControlHeader(
|
|
1030
|
+
document,
|
|
1031
|
+
body.operationName,
|
|
1032
|
+
schema,
|
|
1033
|
+
cacheHints,
|
|
1034
|
+
resolvedConfig.cacheControl
|
|
1035
|
+
);
|
|
1036
|
+
return yield* buildGraphQLResponse(result, extensionData, cacheControlHeader);
|
|
1037
|
+
}).pipe(
|
|
1038
|
+
effect.Effect.provide(layer),
|
|
1039
|
+
effect.Effect.catchAll((error) => {
|
|
1040
|
+
if (error instanceof ComplexityLimitExceededError) {
|
|
1041
|
+
return handleComplexityError(error);
|
|
1042
|
+
}
|
|
1043
|
+
return effect.Effect.fail(error);
|
|
1044
|
+
}),
|
|
1045
|
+
effect.Effect.catchAllCause(errorHandler)
|
|
1046
|
+
);
|
|
1047
|
+
let router = platform.HttpRouter.empty.pipe(
|
|
1048
|
+
platform.HttpRouter.post(resolvedConfig.path, graphqlHandler)
|
|
1049
|
+
);
|
|
1050
|
+
if (resolvedConfig.graphiql) {
|
|
1051
|
+
const { path, endpoint, subscriptionEndpoint } = resolvedConfig.graphiql;
|
|
1052
|
+
router = router.pipe(
|
|
1053
|
+
platform.HttpRouter.get(
|
|
1054
|
+
path,
|
|
1055
|
+
platform.HttpServerResponse.html(graphiqlHtml(endpoint, subscriptionEndpoint))
|
|
1056
|
+
)
|
|
1057
|
+
);
|
|
1058
|
+
}
|
|
1059
|
+
return router;
|
|
1060
|
+
};
|
|
1061
|
+
|
|
1062
|
+
// src/server/schema-builder-extensions.ts
|
|
1063
|
+
var toRouter = (builder, layer, options) => {
|
|
1064
|
+
const schema = builder.buildSchema();
|
|
1065
|
+
const fieldComplexities = builder.getFieldComplexities();
|
|
1066
|
+
const cacheHints = builder.getCacheHints();
|
|
1067
|
+
return makeGraphQLRouter(schema, layer, { ...options, fieldComplexities, cacheHints });
|
|
1068
|
+
};
|
|
1069
|
+
var WebSocketError = class extends effect.Data.TaggedError("WebSocketError") {
|
|
1070
|
+
};
|
|
1071
|
+
var createConnectionContext = (extra) => ({
|
|
1072
|
+
runtime: extra.runtime,
|
|
1073
|
+
connectionParams: extra.connectionParams,
|
|
1074
|
+
socket: extra.socket
|
|
1075
|
+
});
|
|
1076
|
+
var makeOnConnectHandler = (options) => {
|
|
1077
|
+
if (!options?.onConnect) return void 0;
|
|
1078
|
+
return async (ctx) => {
|
|
1079
|
+
const extra = ctx.extra;
|
|
1080
|
+
try {
|
|
1081
|
+
const result = await effect.Runtime.runPromise(extra.runtime)(
|
|
1082
|
+
options.onConnect(ctx.connectionParams ?? {})
|
|
1083
|
+
);
|
|
1084
|
+
if (typeof result === "object" && result !== null) {
|
|
1085
|
+
Object.assign(extra.connectionParams, result);
|
|
1086
|
+
}
|
|
1087
|
+
return result !== false;
|
|
1088
|
+
} catch {
|
|
1089
|
+
return false;
|
|
1090
|
+
}
|
|
1091
|
+
};
|
|
1092
|
+
};
|
|
1093
|
+
var makeOnDisconnectHandler = (options) => {
|
|
1094
|
+
if (!options?.onDisconnect) return void 0;
|
|
1095
|
+
return async (ctx) => {
|
|
1096
|
+
const extra = ctx.extra;
|
|
1097
|
+
await effect.Runtime.runPromise(extra.runtime)(
|
|
1098
|
+
options.onDisconnect(createConnectionContext(extra))
|
|
1099
|
+
).catch(() => {
|
|
1100
|
+
});
|
|
1101
|
+
};
|
|
1102
|
+
};
|
|
1103
|
+
var makeOnSubscribeHandler = (options, schema, complexityConfig, fieldComplexities) => {
|
|
1104
|
+
return async (ctx, id, payload) => {
|
|
1105
|
+
const extra = ctx.extra;
|
|
1106
|
+
const connectionCtx = createConnectionContext(extra);
|
|
1107
|
+
if (complexityConfig) {
|
|
1108
|
+
const validationEffect = validateComplexity(
|
|
1109
|
+
payload.query,
|
|
1110
|
+
payload.operationName ?? void 0,
|
|
1111
|
+
payload.variables ?? void 0,
|
|
1112
|
+
schema,
|
|
1113
|
+
fieldComplexities,
|
|
1114
|
+
complexityConfig
|
|
1115
|
+
).pipe(
|
|
1116
|
+
effect.Effect.catchAll((error) => {
|
|
1117
|
+
if (error._tag === "ComplexityLimitExceededError") {
|
|
1118
|
+
throw new graphql.GraphQLError(error.message, {
|
|
1119
|
+
extensions: {
|
|
1120
|
+
code: "COMPLEXITY_LIMIT_EXCEEDED",
|
|
1121
|
+
limitType: error.limitType,
|
|
1122
|
+
limit: error.limit,
|
|
1123
|
+
actual: error.actual
|
|
1124
|
+
}
|
|
1125
|
+
});
|
|
1126
|
+
}
|
|
1127
|
+
return effect.Effect.logWarning("Complexity analysis failed for subscription", error);
|
|
1128
|
+
})
|
|
1129
|
+
);
|
|
1130
|
+
await effect.Effect.runPromise(validationEffect);
|
|
1131
|
+
}
|
|
1132
|
+
if (options?.onSubscribe) {
|
|
1133
|
+
await effect.Runtime.runPromise(extra.runtime)(
|
|
1134
|
+
options.onSubscribe(connectionCtx, {
|
|
1135
|
+
id,
|
|
1136
|
+
payload: {
|
|
1137
|
+
query: payload.query,
|
|
1138
|
+
variables: payload.variables ?? void 0,
|
|
1139
|
+
operationName: payload.operationName ?? void 0,
|
|
1140
|
+
extensions: payload.extensions ?? void 0
|
|
1141
|
+
}
|
|
1142
|
+
})
|
|
1143
|
+
);
|
|
1144
|
+
}
|
|
1145
|
+
};
|
|
1146
|
+
};
|
|
1147
|
+
var makeOnCompleteHandler = (options) => {
|
|
1148
|
+
if (!options?.onComplete) return void 0;
|
|
1149
|
+
return async (ctx, id, _payload) => {
|
|
1150
|
+
const extra = ctx.extra;
|
|
1151
|
+
await effect.Runtime.runPromise(extra.runtime)(
|
|
1152
|
+
options.onComplete(createConnectionContext(extra), { id })
|
|
1153
|
+
).catch(() => {
|
|
1154
|
+
});
|
|
1155
|
+
};
|
|
1156
|
+
};
|
|
1157
|
+
var makeOnErrorHandler = (options) => {
|
|
1158
|
+
if (!options?.onError) return void 0;
|
|
1159
|
+
return async (ctx, _id, _payload, errors) => {
|
|
1160
|
+
const extra = ctx.extra;
|
|
1161
|
+
await effect.Runtime.runPromise(extra.runtime)(
|
|
1162
|
+
options.onError(createConnectionContext(extra), errors)
|
|
1163
|
+
).catch(() => {
|
|
1164
|
+
});
|
|
1165
|
+
};
|
|
1166
|
+
};
|
|
1167
|
+
var createGraphqlWsSocketAdapter = (socket, runtime) => {
|
|
1168
|
+
let messageCallback = null;
|
|
1169
|
+
return {
|
|
1170
|
+
adapter: {
|
|
1171
|
+
protocol: socket.protocol,
|
|
1172
|
+
send: (data) => effect.Runtime.runPromise(runtime)(
|
|
1173
|
+
socket.send(data).pipe(effect.Effect.catchAll((error) => effect.Effect.logError("WebSocket send error", error)))
|
|
1174
|
+
),
|
|
1175
|
+
close: (code, reason) => {
|
|
1176
|
+
effect.Runtime.runPromise(runtime)(socket.close(code, reason)).catch(() => {
|
|
1177
|
+
});
|
|
1178
|
+
},
|
|
1179
|
+
onMessage: (cb) => {
|
|
1180
|
+
messageCallback = cb;
|
|
1181
|
+
},
|
|
1182
|
+
onPong: (_payload) => {
|
|
1183
|
+
}
|
|
1184
|
+
},
|
|
1185
|
+
dispatchMessage: async (message) => {
|
|
1186
|
+
if (messageCallback) {
|
|
1187
|
+
await messageCallback(message);
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
};
|
|
1191
|
+
};
|
|
1192
|
+
var runConnectionLifecycle = (socket, wsServer, extra) => effect.Effect.gen(function* () {
|
|
1193
|
+
const messageQueue = yield* effect.Queue.unbounded();
|
|
1194
|
+
const closedDeferred = yield* effect.Deferred.make();
|
|
1195
|
+
const messageFiber = yield* effect.Effect.fork(
|
|
1196
|
+
effect.Stream.runForEach(socket.messages, (msg) => effect.Queue.offer(messageQueue, msg)).pipe(
|
|
1197
|
+
effect.Effect.catchAll((error) => effect.Deferred.fail(closedDeferred, error))
|
|
1198
|
+
)
|
|
1199
|
+
);
|
|
1200
|
+
const closeFiber = yield* effect.Effect.fork(
|
|
1201
|
+
socket.closed.pipe(
|
|
1202
|
+
effect.Effect.tap((event) => effect.Deferred.succeed(closedDeferred, event)),
|
|
1203
|
+
effect.Effect.catchAll((error) => effect.Deferred.fail(closedDeferred, error))
|
|
1204
|
+
)
|
|
1205
|
+
);
|
|
1206
|
+
const { adapter, dispatchMessage } = createGraphqlWsSocketAdapter(socket, extra.runtime);
|
|
1207
|
+
const closedHandler = wsServer.opened(adapter, extra);
|
|
1208
|
+
const processMessagesFiber = yield* effect.Effect.fork(
|
|
1209
|
+
effect.Effect.gen(function* () {
|
|
1210
|
+
while (true) {
|
|
1211
|
+
const message = yield* effect.Queue.take(messageQueue);
|
|
1212
|
+
yield* effect.Effect.tryPromise({
|
|
1213
|
+
try: () => dispatchMessage(message),
|
|
1214
|
+
catch: (error) => error
|
|
1215
|
+
}).pipe(effect.Effect.catchAll(() => effect.Effect.void));
|
|
1216
|
+
}
|
|
1217
|
+
})
|
|
1218
|
+
);
|
|
1219
|
+
yield* effect.Deferred.await(closedDeferred).pipe(
|
|
1220
|
+
effect.Effect.catchAll(() => effect.Effect.succeed({ code: 1e3, reason: "Error" }))
|
|
1221
|
+
);
|
|
1222
|
+
closedHandler(1e3, "Connection closed");
|
|
1223
|
+
yield* effect.Fiber.interrupt(messageFiber);
|
|
1224
|
+
yield* effect.Fiber.interrupt(closeFiber);
|
|
1225
|
+
yield* effect.Fiber.interrupt(processMessagesFiber);
|
|
1226
|
+
yield* effect.Queue.shutdown(messageQueue);
|
|
1227
|
+
}).pipe(
|
|
1228
|
+
effect.Effect.catchAllCause(() => effect.Effect.void),
|
|
1229
|
+
effect.Effect.scoped
|
|
1230
|
+
);
|
|
1231
|
+
var makeGraphQLWSHandler = (schema, layer, options) => {
|
|
1232
|
+
const complexityConfig = options?.complexity;
|
|
1233
|
+
const fieldComplexities = options?.fieldComplexities ?? /* @__PURE__ */ new Map();
|
|
1234
|
+
const serverOptions = {
|
|
1235
|
+
schema,
|
|
1236
|
+
context: async (ctx) => {
|
|
1237
|
+
const extra = ctx.extra;
|
|
1238
|
+
return {
|
|
1239
|
+
runtime: extra.runtime,
|
|
1240
|
+
...extra.connectionParams
|
|
1241
|
+
};
|
|
1242
|
+
},
|
|
1243
|
+
subscribe: async (args) => graphql.subscribe(args),
|
|
1244
|
+
onConnect: makeOnConnectHandler(options),
|
|
1245
|
+
onDisconnect: makeOnDisconnectHandler(options),
|
|
1246
|
+
onSubscribe: makeOnSubscribeHandler(options, schema, complexityConfig, fieldComplexities),
|
|
1247
|
+
onComplete: makeOnCompleteHandler(options),
|
|
1248
|
+
onError: makeOnErrorHandler(options)
|
|
1249
|
+
};
|
|
1250
|
+
const wsServer = graphqlWs.makeServer(serverOptions);
|
|
1251
|
+
return (socket) => effect.Effect.gen(function* () {
|
|
1252
|
+
const runtime = yield* effect.Effect.provide(effect.Effect.runtime(), layer);
|
|
1253
|
+
const extra = {
|
|
1254
|
+
socket,
|
|
1255
|
+
runtime,
|
|
1256
|
+
connectionParams: {}
|
|
1257
|
+
};
|
|
1258
|
+
yield* runConnectionLifecycle(socket, wsServer, extra);
|
|
1259
|
+
}).pipe(
|
|
1260
|
+
effect.Effect.catchAllCause(() => effect.Effect.void),
|
|
1261
|
+
effect.Effect.scoped
|
|
1262
|
+
);
|
|
1263
|
+
};
|
|
1264
|
+
var WS_CLOSED = 3;
|
|
1265
|
+
var toEffectWebSocketFromWs = (ws) => {
|
|
1266
|
+
const messagesEffect = effect.Effect.gen(function* () {
|
|
1267
|
+
const queue = yield* effect.Queue.unbounded();
|
|
1268
|
+
const closed = yield* effect.Deferred.make();
|
|
1269
|
+
ws.on("message", (data) => {
|
|
1270
|
+
const message = data.toString();
|
|
1271
|
+
effect.Effect.runPromise(effect.Queue.offer(queue, message)).catch(() => {
|
|
1272
|
+
});
|
|
1273
|
+
});
|
|
1274
|
+
ws.on("error", (error) => {
|
|
1275
|
+
effect.Effect.runPromise(effect.Deferred.fail(closed, new WebSocketError({ cause: error }))).catch(() => {
|
|
1276
|
+
});
|
|
1277
|
+
});
|
|
1278
|
+
ws.on("close", (code, reason) => {
|
|
1279
|
+
effect.Effect.runPromise(
|
|
1280
|
+
effect.Queue.shutdown(queue).pipe(
|
|
1281
|
+
effect.Effect.andThen(effect.Deferred.succeed(closed, { code, reason: reason.toString() }))
|
|
1282
|
+
)
|
|
1283
|
+
).catch(() => {
|
|
1284
|
+
});
|
|
1285
|
+
});
|
|
1286
|
+
return { queue, closed };
|
|
1287
|
+
});
|
|
1288
|
+
const messages = effect.Stream.unwrap(
|
|
1289
|
+
messagesEffect.pipe(
|
|
1290
|
+
effect.Effect.map(({ queue }) => effect.Stream.fromQueue(queue).pipe(effect.Stream.catchAll(() => effect.Stream.empty)))
|
|
1291
|
+
)
|
|
1292
|
+
);
|
|
1293
|
+
return {
|
|
1294
|
+
protocol: ws.protocol || "graphql-transport-ws",
|
|
1295
|
+
send: (data) => effect.Effect.async((resume) => {
|
|
1296
|
+
ws.send(data, (error) => {
|
|
1297
|
+
if (error) {
|
|
1298
|
+
resume(effect.Effect.fail(new WebSocketError({ cause: error })));
|
|
1299
|
+
} else {
|
|
1300
|
+
resume(effect.Effect.succeed(void 0));
|
|
1301
|
+
}
|
|
1302
|
+
});
|
|
1303
|
+
}),
|
|
1304
|
+
close: (code, reason) => effect.Effect.sync(() => {
|
|
1305
|
+
ws.close(code ?? 1e3, reason ?? "");
|
|
1306
|
+
}),
|
|
1307
|
+
messages,
|
|
1308
|
+
closed: effect.Effect.async((resume) => {
|
|
1309
|
+
if (ws.readyState === WS_CLOSED) {
|
|
1310
|
+
resume(effect.Effect.succeed({ code: 1e3, reason: "" }));
|
|
1311
|
+
return;
|
|
1312
|
+
}
|
|
1313
|
+
const onClose = (code, reason) => {
|
|
1314
|
+
cleanup();
|
|
1315
|
+
resume(effect.Effect.succeed({ code, reason: reason.toString() }));
|
|
1316
|
+
};
|
|
1317
|
+
const onError = (error) => {
|
|
1318
|
+
cleanup();
|
|
1319
|
+
resume(effect.Effect.fail(new WebSocketError({ cause: error })));
|
|
1320
|
+
};
|
|
1321
|
+
const cleanup = () => {
|
|
1322
|
+
ws.removeListener("close", onClose);
|
|
1323
|
+
ws.removeListener("error", onError);
|
|
1324
|
+
};
|
|
1325
|
+
ws.on("close", onClose);
|
|
1326
|
+
ws.on("error", onError);
|
|
1327
|
+
return effect.Effect.sync(cleanup);
|
|
1328
|
+
})
|
|
1329
|
+
};
|
|
1330
|
+
};
|
|
1331
|
+
var SSE_HEADERS = {
|
|
1332
|
+
"Content-Type": "text/event-stream",
|
|
1333
|
+
"Cache-Control": "no-cache",
|
|
1334
|
+
Connection: "keep-alive",
|
|
1335
|
+
"X-Accel-Buffering": "no"
|
|
1336
|
+
// Disable nginx buffering
|
|
1337
|
+
};
|
|
1338
|
+
var SSEError = class extends effect.Data.TaggedError("SSEError") {
|
|
1339
|
+
};
|
|
1340
|
+
var formatNextEvent = (result) => ({
|
|
1341
|
+
event: "next",
|
|
1342
|
+
data: JSON.stringify(result)
|
|
1343
|
+
});
|
|
1344
|
+
var formatErrorEvent = (errors) => ({
|
|
1345
|
+
event: "error",
|
|
1346
|
+
data: JSON.stringify({ errors })
|
|
1347
|
+
});
|
|
1348
|
+
var formatCompleteEvent = () => ({
|
|
1349
|
+
event: "complete",
|
|
1350
|
+
data: ""
|
|
1351
|
+
});
|
|
1352
|
+
var formatSSEMessage = (event) => {
|
|
1353
|
+
const lines = [`event: ${event.event}`];
|
|
1354
|
+
if (event.data) {
|
|
1355
|
+
lines.push(`data: ${event.data}`);
|
|
1356
|
+
}
|
|
1357
|
+
lines.push("", "");
|
|
1358
|
+
return lines.join("\n");
|
|
1359
|
+
};
|
|
1360
|
+
var makeSSESubscriptionStream = (schema, layer, request, headers, options) => {
|
|
1361
|
+
const complexityConfig = options?.complexity;
|
|
1362
|
+
const fieldComplexities = options?.fieldComplexities ?? /* @__PURE__ */ new Map();
|
|
1363
|
+
return effect.Stream.unwrap(
|
|
1364
|
+
effect.Effect.gen(function* () {
|
|
1365
|
+
const runtime = yield* effect.Effect.provide(effect.Effect.runtime(), layer);
|
|
1366
|
+
let connectionContext = {};
|
|
1367
|
+
if (options?.onConnect) {
|
|
1368
|
+
try {
|
|
1369
|
+
connectionContext = yield* effect.Effect.provide(options.onConnect(request, headers), layer);
|
|
1370
|
+
} catch {
|
|
1371
|
+
return effect.Stream.make(
|
|
1372
|
+
formatErrorEvent([
|
|
1373
|
+
new graphql.GraphQLError("Subscription connection rejected", {
|
|
1374
|
+
extensions: { code: "CONNECTION_REJECTED" }
|
|
1375
|
+
})
|
|
1376
|
+
]),
|
|
1377
|
+
formatCompleteEvent()
|
|
1378
|
+
);
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
let document;
|
|
1382
|
+
try {
|
|
1383
|
+
document = graphql.parse(request.query);
|
|
1384
|
+
} catch (syntaxError) {
|
|
1385
|
+
return effect.Stream.make(formatErrorEvent([syntaxError]), formatCompleteEvent());
|
|
1386
|
+
}
|
|
1387
|
+
const validationErrors = graphql.validate(schema, document);
|
|
1388
|
+
if (validationErrors.length > 0) {
|
|
1389
|
+
return effect.Stream.make(formatErrorEvent(validationErrors), formatCompleteEvent());
|
|
1390
|
+
}
|
|
1391
|
+
const operations = document.definitions.filter(
|
|
1392
|
+
(d) => d.kind === graphql.Kind.OPERATION_DEFINITION
|
|
1393
|
+
);
|
|
1394
|
+
const operation = request.operationName ? operations.find((o) => o.name?.value === request.operationName) : operations[0];
|
|
1395
|
+
if (!operation) {
|
|
1396
|
+
return effect.Stream.make(
|
|
1397
|
+
formatErrorEvent([new graphql.GraphQLError("No operation found in query")]),
|
|
1398
|
+
formatCompleteEvent()
|
|
1399
|
+
);
|
|
1400
|
+
}
|
|
1401
|
+
if (operation.operation !== "subscription") {
|
|
1402
|
+
return effect.Stream.make(
|
|
1403
|
+
formatErrorEvent([
|
|
1404
|
+
new graphql.GraphQLError(
|
|
1405
|
+
`SSE endpoint only supports subscriptions, received: ${operation.operation}`,
|
|
1406
|
+
{ extensions: { code: "OPERATION_NOT_SUPPORTED" } }
|
|
1407
|
+
)
|
|
1408
|
+
]),
|
|
1409
|
+
formatCompleteEvent()
|
|
1410
|
+
);
|
|
1411
|
+
}
|
|
1412
|
+
if (complexityConfig) {
|
|
1413
|
+
const complexityResult = yield* validateComplexity(
|
|
1414
|
+
request.query,
|
|
1415
|
+
request.operationName,
|
|
1416
|
+
request.variables,
|
|
1417
|
+
schema,
|
|
1418
|
+
fieldComplexities,
|
|
1419
|
+
complexityConfig
|
|
1420
|
+
).pipe(
|
|
1421
|
+
effect.Effect.map(() => null),
|
|
1422
|
+
effect.Effect.catchAll((error) => {
|
|
1423
|
+
if (error._tag === "ComplexityLimitExceededError") {
|
|
1424
|
+
return effect.Effect.succeed(
|
|
1425
|
+
new graphql.GraphQLError(error.message, {
|
|
1426
|
+
extensions: {
|
|
1427
|
+
code: "COMPLEXITY_LIMIT_EXCEEDED",
|
|
1428
|
+
limitType: error.limitType,
|
|
1429
|
+
limit: error.limit,
|
|
1430
|
+
actual: error.actual
|
|
1431
|
+
}
|
|
1432
|
+
})
|
|
1433
|
+
);
|
|
1434
|
+
}
|
|
1435
|
+
return effect.Effect.logWarning("Complexity analysis failed for SSE subscription", error).pipe(
|
|
1436
|
+
effect.Effect.map(() => null)
|
|
1437
|
+
);
|
|
1438
|
+
})
|
|
1439
|
+
);
|
|
1440
|
+
if (complexityResult) {
|
|
1441
|
+
return effect.Stream.make(formatErrorEvent([complexityResult]), formatCompleteEvent());
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
const ctx = {
|
|
1445
|
+
runtime,
|
|
1446
|
+
request,
|
|
1447
|
+
connectionContext
|
|
1448
|
+
};
|
|
1449
|
+
if (options?.onSubscribe) {
|
|
1450
|
+
yield* effect.Effect.provide(options.onSubscribe(ctx), layer).pipe(
|
|
1451
|
+
effect.Effect.catchAll(() => effect.Effect.void)
|
|
1452
|
+
);
|
|
1453
|
+
}
|
|
1454
|
+
const graphqlContext = {
|
|
1455
|
+
runtime,
|
|
1456
|
+
...connectionContext
|
|
1457
|
+
};
|
|
1458
|
+
const subscriptionResult = yield* effect.Effect.tryPromise({
|
|
1459
|
+
try: () => graphql.subscribe({
|
|
1460
|
+
schema,
|
|
1461
|
+
document,
|
|
1462
|
+
variableValues: request.variables,
|
|
1463
|
+
operationName: request.operationName ?? void 0,
|
|
1464
|
+
contextValue: graphqlContext
|
|
1465
|
+
}),
|
|
1466
|
+
catch: (error) => new SSEError({ cause: error })
|
|
1467
|
+
});
|
|
1468
|
+
if (!isAsyncIterable(subscriptionResult)) {
|
|
1469
|
+
const result = subscriptionResult;
|
|
1470
|
+
if (result.errors) {
|
|
1471
|
+
return effect.Stream.make(formatErrorEvent(result.errors), formatCompleteEvent());
|
|
1472
|
+
}
|
|
1473
|
+
return effect.Stream.make(formatNextEvent(result), formatCompleteEvent());
|
|
1474
|
+
}
|
|
1475
|
+
const asyncIterator = subscriptionResult[Symbol.asyncIterator]();
|
|
1476
|
+
const eventStream = effect.Stream.async((emit) => {
|
|
1477
|
+
let done = false;
|
|
1478
|
+
const iterate = async () => {
|
|
1479
|
+
try {
|
|
1480
|
+
while (!done) {
|
|
1481
|
+
const result = await asyncIterator.next();
|
|
1482
|
+
if (result.done) {
|
|
1483
|
+
emit.end();
|
|
1484
|
+
break;
|
|
1485
|
+
}
|
|
1486
|
+
emit.single(formatNextEvent(result.value));
|
|
1487
|
+
}
|
|
1488
|
+
} catch (error) {
|
|
1489
|
+
if (!done) {
|
|
1490
|
+
emit.single(
|
|
1491
|
+
formatErrorEvent([
|
|
1492
|
+
error instanceof graphql.GraphQLError ? error : new graphql.GraphQLError(
|
|
1493
|
+
error instanceof Error ? error.message : "Subscription error",
|
|
1494
|
+
{ extensions: { code: "SUBSCRIPTION_ERROR" } }
|
|
1495
|
+
)
|
|
1496
|
+
])
|
|
1497
|
+
);
|
|
1498
|
+
emit.end();
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
};
|
|
1502
|
+
iterate();
|
|
1503
|
+
return effect.Effect.sync(() => {
|
|
1504
|
+
done = true;
|
|
1505
|
+
asyncIterator.return?.();
|
|
1506
|
+
});
|
|
1507
|
+
});
|
|
1508
|
+
return eventStream.pipe(
|
|
1509
|
+
effect.Stream.onDone(
|
|
1510
|
+
() => effect.Effect.gen(function* () {
|
|
1511
|
+
yield* effect.Effect.sync(() => {
|
|
1512
|
+
});
|
|
1513
|
+
}).pipe(effect.Effect.asVoid)
|
|
1514
|
+
),
|
|
1515
|
+
effect.Stream.concat(effect.Stream.make(formatCompleteEvent())),
|
|
1516
|
+
effect.Stream.onDone(() => {
|
|
1517
|
+
if (options?.onComplete) {
|
|
1518
|
+
return effect.Effect.provide(options.onComplete(ctx), layer).pipe(
|
|
1519
|
+
effect.Effect.catchAll(() => effect.Effect.void)
|
|
1520
|
+
);
|
|
1521
|
+
}
|
|
1522
|
+
return effect.Effect.void;
|
|
1523
|
+
})
|
|
1524
|
+
);
|
|
1525
|
+
}).pipe(
|
|
1526
|
+
effect.Effect.catchAll(
|
|
1527
|
+
(error) => effect.Effect.succeed(
|
|
1528
|
+
effect.Stream.make(
|
|
1529
|
+
formatErrorEvent([
|
|
1530
|
+
new graphql.GraphQLError(error instanceof Error ? error.message : "Internal error", {
|
|
1531
|
+
extensions: { code: "INTERNAL_ERROR" }
|
|
1532
|
+
})
|
|
1533
|
+
]),
|
|
1534
|
+
formatCompleteEvent()
|
|
1535
|
+
)
|
|
1536
|
+
)
|
|
1537
|
+
)
|
|
1538
|
+
)
|
|
1539
|
+
);
|
|
1540
|
+
};
|
|
1541
|
+
var makeGraphQLSSEHandler = (schema, layer, options) => {
|
|
1542
|
+
return (request, headers) => makeSSESubscriptionStream(schema, layer, request, headers, options);
|
|
1543
|
+
};
|
|
1544
|
+
function isAsyncIterable(value) {
|
|
1545
|
+
return typeof value === "object" && value !== null && Symbol.asyncIterator in value;
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
exports.CacheControlConfigFromEnv = CacheControlConfigFromEnv;
|
|
1549
|
+
exports.ComplexityAnalysisError = ComplexityAnalysisError;
|
|
1550
|
+
exports.ComplexityConfigFromEnv = ComplexityConfigFromEnv;
|
|
1551
|
+
exports.ComplexityLimitExceededError = ComplexityLimitExceededError;
|
|
1552
|
+
exports.GraphQLRouterConfigFromEnv = GraphQLRouterConfigFromEnv;
|
|
1553
|
+
exports.SSEError = SSEError;
|
|
1554
|
+
exports.SSE_HEADERS = SSE_HEADERS;
|
|
1555
|
+
exports.WS_CLOSED = WS_CLOSED;
|
|
1556
|
+
exports.WebSocketError = WebSocketError;
|
|
1557
|
+
exports.combineCalculators = combineCalculators;
|
|
1558
|
+
exports.computeCachePolicy = computeCachePolicy;
|
|
1559
|
+
exports.computeCachePolicyFromQuery = computeCachePolicyFromQuery;
|
|
1560
|
+
exports.defaultComplexityCalculator = defaultComplexityCalculator;
|
|
1561
|
+
exports.defaultConfig = defaultConfig;
|
|
1562
|
+
exports.defaultErrorHandler = defaultErrorHandler;
|
|
1563
|
+
exports.depthOnlyCalculator = depthOnlyCalculator;
|
|
1564
|
+
exports.formatCompleteEvent = formatCompleteEvent;
|
|
1565
|
+
exports.formatErrorEvent = formatErrorEvent;
|
|
1566
|
+
exports.formatNextEvent = formatNextEvent;
|
|
1567
|
+
exports.formatSSEMessage = formatSSEMessage;
|
|
1568
|
+
exports.graphiqlHtml = graphiqlHtml;
|
|
1569
|
+
exports.makeGraphQLRouter = makeGraphQLRouter;
|
|
1570
|
+
exports.makeGraphQLSSEHandler = makeGraphQLSSEHandler;
|
|
1571
|
+
exports.makeGraphQLWSHandler = makeGraphQLWSHandler;
|
|
1572
|
+
exports.makeSSESubscriptionStream = makeSSESubscriptionStream;
|
|
1573
|
+
exports.normalizeConfig = normalizeConfig;
|
|
1574
|
+
exports.toCacheControlHeader = toCacheControlHeader;
|
|
1575
|
+
exports.toEffectWebSocketFromWs = toEffectWebSocketFromWs;
|
|
1576
|
+
exports.toRouter = toRouter;
|
|
1577
|
+
exports.validateComplexity = validateComplexity;
|
|
1578
|
+
//# sourceMappingURL=index.cjs.map
|
|
1579
|
+
//# sourceMappingURL=index.cjs.map
|