@webiny/api-graphql 0.0.0-unstable.0156a4c312
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +11 -0
- package/ResolverDecoration.d.ts +6 -0
- package/ResolverDecoration.js +23 -0
- package/ResolverDecoration.js.map +1 -0
- package/builtInTypes/AnyScalar.d.ts +2 -0
- package/builtInTypes/AnyScalar.js +11 -0
- package/builtInTypes/AnyScalar.js.map +1 -0
- package/builtInTypes/DateScalar.d.ts +2 -0
- package/builtInTypes/DateScalar.js +23 -0
- package/builtInTypes/DateScalar.js.map +1 -0
- package/builtInTypes/DateTimeScalar.d.ts +2 -0
- package/builtInTypes/DateTimeScalar.js +18 -0
- package/builtInTypes/DateTimeScalar.js.map +1 -0
- package/builtInTypes/DateTimeZScalar.d.ts +6 -0
- package/builtInTypes/DateTimeZScalar.js +32 -0
- package/builtInTypes/DateTimeZScalar.js.map +1 -0
- package/builtInTypes/IconScalar.d.ts +10 -0
- package/builtInTypes/IconScalar.js +65 -0
- package/builtInTypes/IconScalar.js.map +1 -0
- package/builtInTypes/JsonScalar.d.ts +1 -0
- package/builtInTypes/JsonScalar.js +5 -0
- package/builtInTypes/JsonScalar.js.map +1 -0
- package/builtInTypes/LongScalar.d.ts +2 -0
- package/builtInTypes/LongScalar.js +40 -0
- package/builtInTypes/LongScalar.js.map +1 -0
- package/builtInTypes/NumberScalar.d.ts +2 -0
- package/builtInTypes/NumberScalar.js +41 -0
- package/builtInTypes/NumberScalar.js.map +1 -0
- package/builtInTypes/RefInputScalar.d.ts +2 -0
- package/builtInTypes/RefInputScalar.js +53 -0
- package/builtInTypes/RefInputScalar.js.map +1 -0
- package/builtInTypes/TimeScalar.d.ts +2 -0
- package/builtInTypes/TimeScalar.js +40 -0
- package/builtInTypes/TimeScalar.js.map +1 -0
- package/builtInTypes/index.d.ts +10 -0
- package/builtInTypes/index.js +10 -0
- package/createRequestBody.d.ts +2 -0
- package/createRequestBody.js +28 -0
- package/createRequestBody.js.map +1 -0
- package/createResolverDecorator.d.ts +2 -0
- package/createResolverDecorator.js +4 -0
- package/createResolverDecorator.js.map +1 -0
- package/engine/GraphQLEngine.d.ts +23 -0
- package/engine/GraphQLEngine.js +81 -0
- package/engine/GraphQLEngine.js.map +1 -0
- package/engine/GraphQLEngineFeature.d.ts +4 -0
- package/engine/GraphQLEngineFeature.js +15 -0
- package/engine/GraphQLEngineFeature.js.map +1 -0
- package/engine/GraphQLRoute.d.ts +24 -0
- package/engine/GraphQLRoute.js +38 -0
- package/engine/GraphQLRoute.js.map +1 -0
- package/engine/GraphQLSchemaCacheFeature.d.ts +8 -0
- package/engine/GraphQLSchemaCacheFeature.js +11 -0
- package/engine/GraphQLSchemaCacheFeature.js.map +1 -0
- package/engine/GraphQLSchemaKeyVerificationFeature.d.ts +9 -0
- package/engine/GraphQLSchemaKeyVerificationFeature.js +11 -0
- package/engine/GraphQLSchemaKeyVerificationFeature.js.map +1 -0
- package/engine/MemoryGraphQLSchemaCache.d.ts +15 -0
- package/engine/MemoryGraphQLSchemaCache.js +32 -0
- package/engine/MemoryGraphQLSchemaCache.js.map +1 -0
- package/engine/MemoryGraphQLSchemaKeyVerification.d.ts +13 -0
- package/engine/MemoryGraphQLSchemaKeyVerification.js +23 -0
- package/engine/MemoryGraphQLSchemaKeyVerification.js.map +1 -0
- package/engine/abstractions.d.ts +36 -0
- package/engine/abstractions.js +7 -0
- package/engine/abstractions.js.map +1 -0
- package/engine/createSchemaCacheKey.d.ts +8 -0
- package/engine/createSchemaCacheKey.js +23 -0
- package/engine/createSchemaCacheKey.js.map +1 -0
- package/engine/index.d.ts +5 -0
- package/engine/index.js +5 -0
- package/errors.d.ts +4 -0
- package/errors.js +9 -0
- package/errors.js.map +1 -0
- package/exports/api/graphql.d.ts +3 -0
- package/exports/api/graphql.js +3 -0
- package/features/GraphQLSchemaBuilder/GraphQLSchemaBuilder.d.ts +17 -0
- package/features/GraphQLSchemaBuilder/GraphQLSchemaBuilder.js +72 -0
- package/features/GraphQLSchemaBuilder/GraphQLSchemaBuilder.js.map +1 -0
- package/features/GraphQLSchemaBuilder/GraphQLSchemaComposer.d.ts +16 -0
- package/features/GraphQLSchemaBuilder/GraphQLSchemaComposer.js +70 -0
- package/features/GraphQLSchemaBuilder/GraphQLSchemaComposer.js.map +1 -0
- package/features/GraphQLSchemaBuilder/abstractions.d.ts +44 -0
- package/features/GraphQLSchemaBuilder/abstractions.js +6 -0
- package/features/GraphQLSchemaBuilder/abstractions.js.map +1 -0
- package/features/GraphQLSchemaBuilder/feature.d.ts +4 -0
- package/features/GraphQLSchemaBuilder/feature.js +11 -0
- package/features/GraphQLSchemaBuilder/feature.js.map +1 -0
- package/graphql/abstractions.core.d.ts +17 -0
- package/graphql/abstractions.core.js +5 -0
- package/graphql/abstractions.core.js.map +1 -0
- package/graphql/abstractions.d.ts +2 -0
- package/graphql/abstractions.js +2 -0
- package/graphql/abstractions.public.d.ts +39 -0
- package/graphql/abstractions.public.js +5 -0
- package/graphql/abstractions.public.js.map +1 -0
- package/graphql/staticSchemaKey.d.ts +5 -0
- package/graphql/staticSchemaKey.js +4 -0
- package/graphql/staticSchemaKey.js.map +1 -0
- package/index.d.ts +12 -0
- package/index.js +14 -0
- package/index.js.map +1 -0
- package/package.json +49 -0
- package/plugins/GraphQLSchemaPlugin.d.ts +21 -0
- package/plugins/GraphQLSchemaPlugin.js +25 -0
- package/plugins/GraphQLSchemaPlugin.js.map +1 -0
- package/plugins/index.d.ts +1 -0
- package/plugins/index.js +1 -0
- package/processRequestBody.d.ts +4 -0
- package/processRequestBody.js +26 -0
- package/processRequestBody.js.map +1 -0
- package/responses.d.ts +51 -0
- package/responses.js +59 -0
- package/responses.js.map +1 -0
- package/types.d.ts +50 -0
- package/types.js +0 -0
- package/utils/index.d.ts +1 -0
- package/utils/index.js +1 -0
- package/utils/resolve.d.ts +21 -0
- package/utils/resolve.js +20 -0
- package/utils/resolve.js.map +1 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Container } from "@webiny/di";
|
|
2
|
+
import { GraphQLEngine as GraphQLEngineAbstraction } from "./abstractions.js";
|
|
3
|
+
import { GraphQLSchemaCache } from "./abstractions.js";
|
|
4
|
+
import type { IGraphQLSchemaComposer } from "../features/GraphQLSchemaBuilder/abstractions.js";
|
|
5
|
+
declare class GraphQLEngineImpl implements GraphQLEngineAbstraction.Interface {
|
|
6
|
+
private composer;
|
|
7
|
+
private container;
|
|
8
|
+
private schemaCache;
|
|
9
|
+
constructor(composer: IGraphQLSchemaComposer, container: Container, schemaCache: GraphQLSchemaCache.Interface | undefined);
|
|
10
|
+
execute(body: any): Promise<any>;
|
|
11
|
+
/**
|
|
12
|
+
* The same composer output always builds the same executable schema, so with a cache in the
|
|
13
|
+
* root container it's built once and reused. When every schema factory has a schema key, the key
|
|
14
|
+
* comes from those and the factories only run on a cache miss. Otherwise they run on every
|
|
15
|
+
* request, and the key comes from what they produced.
|
|
16
|
+
*/
|
|
17
|
+
private resolveSchema;
|
|
18
|
+
private executeOne;
|
|
19
|
+
}
|
|
20
|
+
export declare const GraphQLEngine: typeof GraphQLEngineImpl & {
|
|
21
|
+
__abstraction: import("@webiny/di").Abstraction<import("./abstractions.js").IGraphQLEngine>;
|
|
22
|
+
};
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { graphql } from "graphql";
|
|
2
|
+
import { makeExecutableSchema } from "@graphql-tools/schema";
|
|
3
|
+
import { mergeResolvers } from "@graphql-tools/merge";
|
|
4
|
+
import { RequestContainer } from "@webiny/event-handler-core";
|
|
5
|
+
import { GraphQLEngine, GraphQLSchemaCache } from "./abstractions.js";
|
|
6
|
+
import { createSchemaCacheKey } from "./createSchemaCacheKey.js";
|
|
7
|
+
import { GraphQLSchemaComposer } from "../features/GraphQLSchemaBuilder/abstractions.js";
|
|
8
|
+
import { ResolverDecoration } from "../ResolverDecoration.js";
|
|
9
|
+
import { createRequestBody } from "../createRequestBody.js";
|
|
10
|
+
const buildStaticSchema = (schemaConfig)=>{
|
|
11
|
+
const resolverDecoration = new ResolverDecoration();
|
|
12
|
+
if (schemaConfig.resolverDecorators) resolverDecoration.addDecorators(schemaConfig.resolverDecorators);
|
|
13
|
+
const typeDefs = `type Query\ntype Mutation\n${schemaConfig.typeDefs ?? ""}`;
|
|
14
|
+
const resolvers = mergeResolvers([
|
|
15
|
+
schemaConfig.resolvers ?? {}
|
|
16
|
+
]);
|
|
17
|
+
return makeExecutableSchema({
|
|
18
|
+
typeDefs,
|
|
19
|
+
resolvers: resolverDecoration.decorateResolvers(resolvers),
|
|
20
|
+
assumeValidSDL: true,
|
|
21
|
+
inheritResolversFromInterfaces: true,
|
|
22
|
+
updateResolversInPlace: true
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
const composeAndBuild = async (composer)=>{
|
|
26
|
+
const schemaConfig = await composer.build();
|
|
27
|
+
return buildStaticSchema(schemaConfig);
|
|
28
|
+
};
|
|
29
|
+
class GraphQLEngineImpl {
|
|
30
|
+
constructor(composer, container, schemaCache){
|
|
31
|
+
this.composer = composer;
|
|
32
|
+
this.container = container;
|
|
33
|
+
this.schemaCache = schemaCache;
|
|
34
|
+
}
|
|
35
|
+
async execute(body) {
|
|
36
|
+
const ctx = {
|
|
37
|
+
container: this.container
|
|
38
|
+
};
|
|
39
|
+
const schema = await this.resolveSchema();
|
|
40
|
+
const parsed = createRequestBody(body);
|
|
41
|
+
if (!Array.isArray(parsed)) return this.executeOne(parsed, schema, ctx);
|
|
42
|
+
const results = [];
|
|
43
|
+
for (const b of parsed)results.push(await this.executeOne(b, schema, ctx));
|
|
44
|
+
return results;
|
|
45
|
+
}
|
|
46
|
+
async resolveSchema() {
|
|
47
|
+
if (!this.schemaCache) return composeAndBuild(this.composer);
|
|
48
|
+
const factoriesKey = await this.composer.getSchemaKey();
|
|
49
|
+
if (factoriesKey) return this.schemaCache.getOrBuild(`factories:${factoriesKey}`, ()=>composeAndBuild(this.composer));
|
|
50
|
+
const schemaConfig = await this.composer.build();
|
|
51
|
+
const contentKey = createSchemaCacheKey(schemaConfig);
|
|
52
|
+
return this.schemaCache.getOrBuild(`content:${contentKey}`, async ()=>buildStaticSchema(schemaConfig));
|
|
53
|
+
}
|
|
54
|
+
async executeOne(body, schema, ctx) {
|
|
55
|
+
const { query, variables, operationName } = body;
|
|
56
|
+
return graphql({
|
|
57
|
+
schema,
|
|
58
|
+
source: query,
|
|
59
|
+
rootValue: {},
|
|
60
|
+
contextValue: ctx,
|
|
61
|
+
variableValues: variables ?? void 0,
|
|
62
|
+
operationName: operationName ?? void 0
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const GraphQLEngine_GraphQLEngine = GraphQLEngine.createImplementation({
|
|
67
|
+
implementation: GraphQLEngineImpl,
|
|
68
|
+
dependencies: [
|
|
69
|
+
GraphQLSchemaComposer,
|
|
70
|
+
RequestContainer,
|
|
71
|
+
[
|
|
72
|
+
GraphQLSchemaCache,
|
|
73
|
+
{
|
|
74
|
+
optional: true
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
]
|
|
78
|
+
});
|
|
79
|
+
export { GraphQLEngine_GraphQLEngine as GraphQLEngine };
|
|
80
|
+
|
|
81
|
+
//# sourceMappingURL=GraphQLEngine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine/GraphQLEngine.js","sources":["../../src/engine/GraphQLEngine.ts"],"sourcesContent":["import { graphql } from \"graphql\";\nimport { makeExecutableSchema } from \"@graphql-tools/schema\";\nimport { mergeResolvers } from \"@graphql-tools/merge\";\nimport { Container } from \"@webiny/di\";\nimport { RequestContainer } from \"@webiny/event-handler-core\";\nimport { GraphQLEngine as GraphQLEngineAbstraction } from \"./abstractions.js\";\nimport { GraphQLSchemaCache } from \"./abstractions.js\";\nimport { createSchemaCacheKey } from \"./createSchemaCacheKey.js\";\nimport { GraphQLSchemaComposer } from \"~/features/GraphQLSchemaBuilder/abstractions.js\";\nimport { ResolverDecoration } from \"~/ResolverDecoration.js\";\nimport { createRequestBody } from \"~/createRequestBody.js\";\nimport type { IGraphQLSchemaComposer } from \"~/features/GraphQLSchemaBuilder/abstractions.js\";\nimport type { IGraphQLSchema } from \"~/graphql/abstractions.public.js\";\nimport type { GraphQLRequestBody } from \"~/types.js\";\nimport type { GraphQLSchema } from \"graphql\";\n\nconst buildStaticSchema = (schemaConfig: IGraphQLSchema): GraphQLSchema => {\n const resolverDecoration = new ResolverDecoration();\n if (schemaConfig.resolverDecorators) {\n resolverDecoration.addDecorators(schemaConfig.resolverDecorators);\n }\n\n // Always provide base root types so that `extend type Query/Mutation` works without\n // requiring callers to define them. With assumeValidSDL:true, empty base types are\n // allowed at build time; graphql() then returns schema-validation errors at execution\n // time (e.g. \"Type Query must define one or more fields.\") when no fields are registered.\n const typeDefs = `type Query\\ntype Mutation\\n${schemaConfig.typeDefs ?? \"\"}`;\n const resolvers = mergeResolvers([schemaConfig.resolvers ?? {}]);\n\n return makeExecutableSchema({\n typeDefs,\n resolvers: resolverDecoration.decorateResolvers(resolvers),\n assumeValidSDL: true,\n inheritResolversFromInterfaces: true,\n // The schema built from typeDefs above is new and nothing else holds it, so resolvers go\n // onto it directly. Without this, graphql-tools rebuilds the whole schema to attach them,\n // which was about half of the schema build on a cold Lambda.\n updateResolversInPlace: true\n });\n};\n\nconst composeAndBuild = async (composer: IGraphQLSchemaComposer): Promise<GraphQLSchema> => {\n const schemaConfig = await composer.build();\n return buildStaticSchema(schemaConfig);\n};\n\nclass GraphQLEngineImpl implements GraphQLEngineAbstraction.Interface {\n constructor(\n private composer: IGraphQLSchemaComposer,\n private container: Container,\n private schemaCache: GraphQLSchemaCache.Interface | undefined\n ) {}\n\n async execute(body: any): Promise<any> {\n const ctx: Record<string, any> = { container: this.container };\n const schema = await this.resolveSchema();\n const parsed = createRequestBody(body);\n\n if (!Array.isArray(parsed)) {\n return this.executeOne(parsed, schema, ctx);\n }\n // Run sequentially so per-request state (e.g. ctx.debug.logs) is scoped per query.\n const results = [];\n for (const b of parsed) {\n results.push(await this.executeOne(b, schema, ctx));\n }\n return results;\n }\n\n /**\n * The same composer output always builds the same executable schema, so with a cache in the\n * root container it's built once and reused. When every schema factory has a schema key, the key\n * comes from those and the factories only run on a cache miss. Otherwise they run on every\n * request, and the key comes from what they produced.\n */\n private async resolveSchema(): Promise<GraphQLSchema> {\n if (!this.schemaCache) {\n return composeAndBuild(this.composer);\n }\n\n const factoriesKey = await this.composer.getSchemaKey();\n if (factoriesKey) {\n return this.schemaCache.getOrBuild(`factories:${factoriesKey}`, () => {\n return composeAndBuild(this.composer);\n });\n }\n\n const schemaConfig = await this.composer.build();\n const contentKey = createSchemaCacheKey(schemaConfig);\n return this.schemaCache.getOrBuild(`content:${contentKey}`, async () => {\n return buildStaticSchema(schemaConfig);\n });\n }\n\n private async executeOne(\n body: GraphQLRequestBody,\n schema: GraphQLSchema,\n ctx: Record<string, any>\n ): Promise<any> {\n const { query, variables, operationName } = body;\n\n return graphql({\n schema,\n source: query,\n rootValue: {},\n contextValue: ctx,\n variableValues: variables ?? undefined,\n operationName: operationName ?? undefined\n });\n }\n}\n\nexport const GraphQLEngine = GraphQLEngineAbstraction.createImplementation({\n implementation: GraphQLEngineImpl,\n dependencies: [\n GraphQLSchemaComposer,\n RequestContainer,\n [GraphQLSchemaCache, { optional: true }]\n ]\n});\n"],"names":["buildStaticSchema","schemaConfig","resolverDecoration","ResolverDecoration","typeDefs","resolvers","mergeResolvers","makeExecutableSchema","composeAndBuild","composer","GraphQLEngineImpl","container","schemaCache","body","ctx","schema","parsed","createRequestBody","Array","results","b","factoriesKey","contentKey","createSchemaCacheKey","query","variables","operationName","graphql","undefined","GraphQLEngine","GraphQLEngineAbstraction","GraphQLSchemaComposer","RequestContainer","GraphQLSchemaCache"],"mappings":";;;;;;;;;AAgBA,MAAMA,oBAAoB,CAACC;IACvB,MAAMC,qBAAqB,IAAIC;IAC/B,IAAIF,aAAa,kBAAkB,EAC/BC,mBAAmB,aAAa,CAACD,aAAa,kBAAkB;IAOpE,MAAMG,WAAW,CAAC,2BAA2B,EAAEH,aAAa,QAAQ,IAAI,IAAI;IAC5E,MAAMI,YAAYC,eAAe;QAACL,aAAa,SAAS,IAAI,CAAC;KAAE;IAE/D,OAAOM,qBAAqB;QACxBH;QACA,WAAWF,mBAAmB,iBAAiB,CAACG;QAChD,gBAAgB;QAChB,gCAAgC;QAIhC,wBAAwB;IAC5B;AACJ;AAEA,MAAMG,kBAAkB,OAAOC;IAC3B,MAAMR,eAAe,MAAMQ,SAAS,KAAK;IACzC,OAAOT,kBAAkBC;AAC7B;AAEA,MAAMS;IACF,YACYD,QAAgC,EAChCE,SAAoB,EACpBC,WAAqD,CAC/D;aAHUH,QAAQ,GAARA;aACAE,SAAS,GAATA;aACAC,WAAW,GAAXA;IACT;IAEH,MAAM,QAAQC,IAAS,EAAgB;QACnC,MAAMC,MAA2B;YAAE,WAAW,IAAI,CAAC,SAAS;QAAC;QAC7D,MAAMC,SAAS,MAAM,IAAI,CAAC,aAAa;QACvC,MAAMC,SAASC,kBAAkBJ;QAEjC,IAAI,CAACK,MAAM,OAAO,CAACF,SACf,OAAO,IAAI,CAAC,UAAU,CAACA,QAAQD,QAAQD;QAG3C,MAAMK,UAAU,EAAE;QAClB,KAAK,MAAMC,KAAKJ,OACZG,QAAQ,IAAI,CAAC,MAAM,IAAI,CAAC,UAAU,CAACC,GAAGL,QAAQD;QAElD,OAAOK;IACX;IAQA,MAAc,gBAAwC;QAClD,IAAI,CAAC,IAAI,CAAC,WAAW,EACjB,OAAOX,gBAAgB,IAAI,CAAC,QAAQ;QAGxC,MAAMa,eAAe,MAAM,IAAI,CAAC,QAAQ,CAAC,YAAY;QACrD,IAAIA,cACA,OAAO,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,UAAU,EAAEA,cAAc,EAAE,IACrDb,gBAAgB,IAAI,CAAC,QAAQ;QAI5C,MAAMP,eAAe,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK;QAC9C,MAAMqB,aAAaC,qBAAqBtB;QACxC,OAAO,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,QAAQ,EAAEqB,YAAY,EAAE,UACjDtB,kBAAkBC;IAEjC;IAEA,MAAc,WACVY,IAAwB,EACxBE,MAAqB,EACrBD,GAAwB,EACZ;QACZ,MAAM,EAAEU,KAAK,EAAEC,SAAS,EAAEC,aAAa,EAAE,GAAGb;QAE5C,OAAOc,QAAQ;YACXZ;YACA,QAAQS;YACR,WAAW,CAAC;YACZ,cAAcV;YACd,gBAAgBW,aAAaG;YAC7B,eAAeF,iBAAiBE;QACpC;IACJ;AACJ;AAEO,MAAMC,8BAAgBC,cAAAA,oBAA6C,CAAC;IACvE,gBAAgBpB;IAChB,cAAc;QACVqB;QACAC;QACA;YAACC;YAAoB;gBAAE,UAAU;YAAK;SAAE;KAC3C;AACL"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createFeature } from "@webiny/feature/api";
|
|
2
|
+
import { GraphQLSchemaComposerFeature } from "../features/GraphQLSchemaBuilder/feature.js";
|
|
3
|
+
import { GraphQLEngine } from "./GraphQLEngine.js";
|
|
4
|
+
import { GraphQLRouteDefinition } from "./GraphQLRoute.js";
|
|
5
|
+
const GraphQLEngineFeature = createFeature({
|
|
6
|
+
name: "GraphQLEngine",
|
|
7
|
+
register (container) {
|
|
8
|
+
GraphQLSchemaComposerFeature.register(container);
|
|
9
|
+
container.register(GraphQLEngine);
|
|
10
|
+
container.register(GraphQLRouteDefinition);
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
export { GraphQLEngineFeature };
|
|
14
|
+
|
|
15
|
+
//# sourceMappingURL=GraphQLEngineFeature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine/GraphQLEngineFeature.js","sources":["../../src/engine/GraphQLEngineFeature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\n\nimport { GraphQLSchemaComposerFeature } from \"~/features/GraphQLSchemaBuilder/feature.js\";\nimport { GraphQLEngine } from \"./GraphQLEngine.js\";\nimport { GraphQLRouteDefinition } from \"./GraphQLRoute.js\";\n\nexport const GraphQLEngineFeature = createFeature({\n name: \"GraphQLEngine\",\n register(container) {\n GraphQLSchemaComposerFeature.register(container);\n container.register(GraphQLEngine);\n container.register(GraphQLRouteDefinition);\n }\n});\n"],"names":["GraphQLEngineFeature","createFeature","container","GraphQLSchemaComposerFeature","GraphQLEngine","GraphQLRouteDefinition"],"mappings":";;;;AAMO,MAAMA,uBAAuBC,cAAc;IAC9C,MAAM;IACN,UAASC,SAAS;QACdC,6BAA6B,QAAQ,CAACD;QACtCA,UAAU,QAAQ,CAACE;QACnBF,UAAU,QAAQ,CAACG;IACvB;AACJ"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { HttpRouteDefinition, HttpRouteHandler } from "@webiny/event-handler-core";
|
|
2
|
+
import type { IHttpRequest, IHttpResponse } from "@webiny/event-handler-core";
|
|
3
|
+
import type { IGraphQLEngine } from "./abstractions.js";
|
|
4
|
+
declare class GraphQLRouteImpl implements HttpRouteHandler.Interface {
|
|
5
|
+
private engine;
|
|
6
|
+
constructor(engine: IGraphQLEngine);
|
|
7
|
+
handle(request: IHttpRequest): Promise<IHttpResponse>;
|
|
8
|
+
}
|
|
9
|
+
export declare const GraphQLRoute: typeof GraphQLRouteImpl & {
|
|
10
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/event-handler-core").IHttpRoute>;
|
|
11
|
+
};
|
|
12
|
+
declare class GraphQLRouteDefinitionImpl implements HttpRouteDefinition.Interface {
|
|
13
|
+
readonly name = "graphql";
|
|
14
|
+
readonly method = "POST";
|
|
15
|
+
readonly path = "/graphql";
|
|
16
|
+
readonly handler: typeof GraphQLRouteImpl & {
|
|
17
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/event-handler-core").IHttpRoute>;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/** What the router matches on. Zero dependencies, so building it costs nothing. */
|
|
21
|
+
export declare const GraphQLRouteDefinition: typeof GraphQLRouteDefinitionImpl & {
|
|
22
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/event-handler-core").IHttpRouteDefinition>;
|
|
23
|
+
};
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { HttpRouteDefinition, HttpRouteHandler } from "@webiny/event-handler-core";
|
|
2
|
+
import { GraphQLEngine } from "./abstractions.js";
|
|
3
|
+
class GraphQLRouteImpl {
|
|
4
|
+
constructor(engine){
|
|
5
|
+
this.engine = engine;
|
|
6
|
+
}
|
|
7
|
+
async handle(request) {
|
|
8
|
+
const result = await this.engine.execute(request.body);
|
|
9
|
+
return {
|
|
10
|
+
statusCode: 200,
|
|
11
|
+
headers: {
|
|
12
|
+
"Content-Type": "application/json"
|
|
13
|
+
},
|
|
14
|
+
body: result
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const GraphQLRoute = HttpRouteHandler.createImplementation({
|
|
19
|
+
implementation: GraphQLRouteImpl,
|
|
20
|
+
dependencies: [
|
|
21
|
+
GraphQLEngine
|
|
22
|
+
]
|
|
23
|
+
});
|
|
24
|
+
class GraphQLRouteDefinitionImpl {
|
|
25
|
+
constructor(){
|
|
26
|
+
this.name = "graphql";
|
|
27
|
+
this.method = "POST";
|
|
28
|
+
this.path = "/graphql";
|
|
29
|
+
this.handler = GraphQLRoute;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const GraphQLRouteDefinition = HttpRouteDefinition.createImplementation({
|
|
33
|
+
implementation: GraphQLRouteDefinitionImpl,
|
|
34
|
+
dependencies: []
|
|
35
|
+
});
|
|
36
|
+
export { GraphQLRoute, GraphQLRouteDefinition };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=GraphQLRoute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine/GraphQLRoute.js","sources":["../../src/engine/GraphQLRoute.ts"],"sourcesContent":["import { HttpRouteDefinition, HttpRouteHandler } from \"@webiny/event-handler-core\";\nimport { GraphQLEngine } from \"./abstractions.js\";\nimport type { IHttpRequest, IHttpResponse } from \"@webiny/event-handler-core\";\nimport type { IGraphQLEngine } from \"./abstractions.js\";\n\nclass GraphQLRouteImpl implements HttpRouteHandler.Interface {\n constructor(private engine: IGraphQLEngine) {}\n\n async handle(request: IHttpRequest): Promise<IHttpResponse> {\n const result = await this.engine.execute(request.body);\n return {\n statusCode: 200,\n headers: { \"Content-Type\": \"application/json\" },\n body: result\n };\n }\n}\n\nexport const GraphQLRoute = HttpRouteHandler.createImplementation({\n implementation: GraphQLRouteImpl,\n dependencies: [GraphQLEngine]\n});\n\nclass GraphQLRouteDefinitionImpl implements HttpRouteDefinition.Interface {\n readonly name = \"graphql\";\n readonly method = \"POST\";\n readonly path = \"/graphql\";\n readonly handler = GraphQLRoute;\n}\n\n/** What the router matches on. Zero dependencies, so building it costs nothing. */\nexport const GraphQLRouteDefinition = HttpRouteDefinition.createImplementation({\n implementation: GraphQLRouteDefinitionImpl,\n dependencies: []\n});\n"],"names":["GraphQLRouteImpl","engine","request","result","GraphQLRoute","HttpRouteHandler","GraphQLEngine","GraphQLRouteDefinitionImpl","GraphQLRouteDefinition","HttpRouteDefinition"],"mappings":";;AAKA,MAAMA;IACF,YAAoBC,MAAsB,CAAE;aAAxBA,MAAM,GAANA;IAAyB;IAE7C,MAAM,OAAOC,OAAqB,EAA0B;QACxD,MAAMC,SAAS,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAACD,QAAQ,IAAI;QACrD,OAAO;YACH,YAAY;YACZ,SAAS;gBAAE,gBAAgB;YAAmB;YAC9C,MAAMC;QACV;IACJ;AACJ;AAEO,MAAMC,eAAeC,iBAAiB,oBAAoB,CAAC;IAC9D,gBAAgBL;IAChB,cAAc;QAACM;KAAc;AACjC;AAEA,MAAMC;;aACO,IAAI,GAAG;aACP,MAAM,GAAG;aACT,IAAI,GAAG;aACP,OAAO,GAAGH;;AACvB;AAGO,MAAMI,yBAAyBC,oBAAoB,oBAAoB,CAAC;IAC3E,gBAAgBF;IAChB,cAAc,EAAE;AACpB"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Register in the ROOT container. The request container registers the GraphQL engine again on every
|
|
3
|
+
* request, so a cache registered there would start empty each time.
|
|
4
|
+
*/
|
|
5
|
+
export declare const GraphQLSchemaCacheFeature: {
|
|
6
|
+
name: string;
|
|
7
|
+
register(container: import("@webiny/di").Container): void;
|
|
8
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createFeature } from "@webiny/feature/api";
|
|
2
|
+
import { MemoryGraphQLSchemaCache } from "./MemoryGraphQLSchemaCache.js";
|
|
3
|
+
const GraphQLSchemaCacheFeature = createFeature({
|
|
4
|
+
name: "GraphQLSchemaCache",
|
|
5
|
+
register (container) {
|
|
6
|
+
container.register(MemoryGraphQLSchemaCache).inSingletonScope();
|
|
7
|
+
}
|
|
8
|
+
});
|
|
9
|
+
export { GraphQLSchemaCacheFeature };
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=GraphQLSchemaCacheFeature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine/GraphQLSchemaCacheFeature.js","sources":["../../src/engine/GraphQLSchemaCacheFeature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { MemoryGraphQLSchemaCache } from \"./MemoryGraphQLSchemaCache.js\";\n\n/**\n * Register in the ROOT container. The request container registers the GraphQL engine again on every\n * request, so a cache registered there would start empty each time.\n */\nexport const GraphQLSchemaCacheFeature = createFeature({\n name: \"GraphQLSchemaCache\",\n register(container) {\n container.register(MemoryGraphQLSchemaCache).inSingletonScope();\n }\n});\n"],"names":["GraphQLSchemaCacheFeature","createFeature","container","MemoryGraphQLSchemaCache"],"mappings":";;AAOO,MAAMA,4BAA4BC,cAAc;IACnD,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC,0BAA0B,gBAAgB;IACjE;AACJ"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Register in the ROOT container of test handlers, next to GraphQLSchemaCacheFeature. Every request
|
|
3
|
+
* then also runs each keyed factory on its own and checks its output against its schema key, so a
|
|
4
|
+
* factory whose key misses a dependency fails the tests instead of serving a stale schema.
|
|
5
|
+
*/
|
|
6
|
+
export declare const GraphQLSchemaKeyVerificationFeature: {
|
|
7
|
+
name: string;
|
|
8
|
+
register(container: import("@webiny/di").Container): void;
|
|
9
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createFeature } from "@webiny/feature/api";
|
|
2
|
+
import { MemoryGraphQLSchemaKeyVerification } from "./MemoryGraphQLSchemaKeyVerification.js";
|
|
3
|
+
const GraphQLSchemaKeyVerificationFeature = createFeature({
|
|
4
|
+
name: "GraphQLSchemaKeyVerification",
|
|
5
|
+
register (container) {
|
|
6
|
+
container.register(MemoryGraphQLSchemaKeyVerification).inSingletonScope();
|
|
7
|
+
}
|
|
8
|
+
});
|
|
9
|
+
export { GraphQLSchemaKeyVerificationFeature };
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=GraphQLSchemaKeyVerificationFeature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine/GraphQLSchemaKeyVerificationFeature.js","sources":["../../src/engine/GraphQLSchemaKeyVerificationFeature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { MemoryGraphQLSchemaKeyVerification } from \"./MemoryGraphQLSchemaKeyVerification.js\";\n\n/**\n * Register in the ROOT container of test handlers, next to GraphQLSchemaCacheFeature. Every request\n * then also runs each keyed factory on its own and checks its output against its schema key, so a\n * factory whose key misses a dependency fails the tests instead of serving a stale schema.\n */\nexport const GraphQLSchemaKeyVerificationFeature = createFeature({\n name: \"GraphQLSchemaKeyVerification\",\n register(container) {\n container.register(MemoryGraphQLSchemaKeyVerification).inSingletonScope();\n }\n});\n"],"names":["GraphQLSchemaKeyVerificationFeature","createFeature","container","MemoryGraphQLSchemaKeyVerification"],"mappings":";;AAQO,MAAMA,sCAAsCC,cAAc;IAC7D,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC,oCAAoC,gBAAgB;IAC3E;AACJ"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { GraphQLSchema } from "graphql";
|
|
2
|
+
import { GraphQLSchemaCache as Abstraction } from "./abstractions.js";
|
|
3
|
+
/**
|
|
4
|
+
* Keeps the most recently used schemas in memory, dropping the least recently used one once it holds
|
|
5
|
+
* `MAX_ENTRIES`. It stores the build itself, so concurrent requests for a missing key share one
|
|
6
|
+
* build, and a failed build is forgotten.
|
|
7
|
+
*/
|
|
8
|
+
declare class MemoryGraphQLSchemaCacheImpl implements Abstraction.Interface {
|
|
9
|
+
private readonly schemas;
|
|
10
|
+
getOrBuild(key: string, build: () => Promise<GraphQLSchema>): Promise<GraphQLSchema>;
|
|
11
|
+
}
|
|
12
|
+
export declare const MemoryGraphQLSchemaCache: typeof MemoryGraphQLSchemaCacheImpl & {
|
|
13
|
+
__abstraction: import("@webiny/di").Abstraction<import("./abstractions.js").IGraphQLSchemaCache>;
|
|
14
|
+
};
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { GraphQLSchemaCache } from "./abstractions.js";
|
|
2
|
+
const MAX_ENTRIES = 10;
|
|
3
|
+
class MemoryGraphQLSchemaCacheImpl {
|
|
4
|
+
getOrBuild(key, build) {
|
|
5
|
+
const cached = this.schemas.get(key);
|
|
6
|
+
if (cached) {
|
|
7
|
+
this.schemas.delete(key);
|
|
8
|
+
this.schemas.set(key, cached);
|
|
9
|
+
return cached;
|
|
10
|
+
}
|
|
11
|
+
const schema = build().catch((error)=>{
|
|
12
|
+
if (this.schemas.get(key) === schema) this.schemas.delete(key);
|
|
13
|
+
throw error;
|
|
14
|
+
});
|
|
15
|
+
this.schemas.set(key, schema);
|
|
16
|
+
if (this.schemas.size > MAX_ENTRIES) {
|
|
17
|
+
const oldestKey = this.schemas.keys().next().value;
|
|
18
|
+
this.schemas.delete(oldestKey);
|
|
19
|
+
}
|
|
20
|
+
return schema;
|
|
21
|
+
}
|
|
22
|
+
constructor(){
|
|
23
|
+
this.schemas = new Map();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const MemoryGraphQLSchemaCache = GraphQLSchemaCache.createImplementation({
|
|
27
|
+
implementation: MemoryGraphQLSchemaCacheImpl,
|
|
28
|
+
dependencies: []
|
|
29
|
+
});
|
|
30
|
+
export { MemoryGraphQLSchemaCache };
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=MemoryGraphQLSchemaCache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine/MemoryGraphQLSchemaCache.js","sources":["../../src/engine/MemoryGraphQLSchemaCache.ts"],"sourcesContent":["import type { GraphQLSchema } from \"graphql\";\nimport { GraphQLSchemaCache as Abstraction } from \"./abstractions.js\";\n\n/*\n * A built schema is several megabytes. Tenants with the same models produce the same key and share\n * one entry, so a handful of entries covers the usual case without letting a process that serves\n * many differently shaped tenants grow without bound.\n */\nconst MAX_ENTRIES = 10;\n\n/**\n * Keeps the most recently used schemas in memory, dropping the least recently used one once it holds\n * `MAX_ENTRIES`. It stores the build itself, so concurrent requests for a missing key share one\n * build, and a failed build is forgotten.\n */\nclass MemoryGraphQLSchemaCacheImpl implements Abstraction.Interface {\n private readonly schemas = new Map<string, Promise<GraphQLSchema>>();\n\n public getOrBuild(key: string, build: () => Promise<GraphQLSchema>): Promise<GraphQLSchema> {\n const cached = this.schemas.get(key);\n if (cached) {\n // Re-insert, so the map's insertion order doubles as the recently-used order.\n this.schemas.delete(key);\n this.schemas.set(key, cached);\n return cached;\n }\n\n const schema = build().catch(error => {\n if (this.schemas.get(key) === schema) {\n this.schemas.delete(key);\n }\n throw error;\n });\n this.schemas.set(key, schema);\n\n if (this.schemas.size > MAX_ENTRIES) {\n const oldestKey = this.schemas.keys().next().value as string;\n this.schemas.delete(oldestKey);\n }\n\n return schema;\n }\n}\n\nexport const MemoryGraphQLSchemaCache = Abstraction.createImplementation({\n implementation: MemoryGraphQLSchemaCacheImpl,\n dependencies: []\n});\n"],"names":["MAX_ENTRIES","MemoryGraphQLSchemaCacheImpl","key","build","cached","schema","error","oldestKey","Map","MemoryGraphQLSchemaCache","Abstraction"],"mappings":";AAQA,MAAMA,cAAc;AAOpB,MAAMC;IAGK,WAAWC,GAAW,EAAEC,KAAmC,EAA0B;QACxF,MAAMC,SAAS,IAAI,CAAC,OAAO,CAAC,GAAG,CAACF;QAChC,IAAIE,QAAQ;YAER,IAAI,CAAC,OAAO,CAAC,MAAM,CAACF;YACpB,IAAI,CAAC,OAAO,CAAC,GAAG,CAACA,KAAKE;YACtB,OAAOA;QACX;QAEA,MAAMC,SAASF,QAAQ,KAAK,CAACG,CAAAA;YACzB,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAACJ,SAASG,QAC1B,IAAI,CAAC,OAAO,CAAC,MAAM,CAACH;YAExB,MAAMI;QACV;QACA,IAAI,CAAC,OAAO,CAAC,GAAG,CAACJ,KAAKG;QAEtB,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,GAAGL,aAAa;YACjC,MAAMO,YAAY,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,GAAG,KAAK;YAClD,IAAI,CAAC,OAAO,CAAC,MAAM,CAACA;QACxB;QAEA,OAAOF;IACX;;aAzBiB,OAAO,GAAG,IAAIG;;AA0BnC;AAEO,MAAMC,2BAA2BC,mBAAAA,oBAAgC,CAAC;IACrE,gBAAgBT;IAChB,cAAc,EAAE;AACpB"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { GraphQLSchemaKeyVerification as Abstraction } from "./abstractions.js";
|
|
2
|
+
/**
|
|
3
|
+
* Remembers the output each factory produced under each schema key, and throws when the same factory
|
|
4
|
+
* produces something else under a key it used before.
|
|
5
|
+
*/
|
|
6
|
+
declare class MemoryGraphQLSchemaKeyVerificationImpl implements Abstraction.Interface {
|
|
7
|
+
private readonly outputs;
|
|
8
|
+
check(params: Abstraction.Check): void;
|
|
9
|
+
}
|
|
10
|
+
export declare const MemoryGraphQLSchemaKeyVerification: typeof MemoryGraphQLSchemaKeyVerificationImpl & {
|
|
11
|
+
__abstraction: import("@webiny/di").Abstraction<import("./abstractions.js").IGraphQLSchemaKeyVerification>;
|
|
12
|
+
};
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { GraphQLSchemaKeyVerification } from "./abstractions.js";
|
|
2
|
+
class MemoryGraphQLSchemaKeyVerificationImpl {
|
|
3
|
+
check(params) {
|
|
4
|
+
const { factory, key, output } = params;
|
|
5
|
+
const id = JSON.stringify([
|
|
6
|
+
factory,
|
|
7
|
+
key
|
|
8
|
+
]);
|
|
9
|
+
const previous = this.outputs.get(id);
|
|
10
|
+
if (void 0 === previous) return void this.outputs.set(id, output);
|
|
11
|
+
if (previous !== output) throw new Error(`GraphQL schema factory "${factory}" produced a different schema under the same schema key "${key}". Its getSchemaKey() is missing something its output depends on.`);
|
|
12
|
+
}
|
|
13
|
+
constructor(){
|
|
14
|
+
this.outputs = new Map();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const MemoryGraphQLSchemaKeyVerification = GraphQLSchemaKeyVerification.createImplementation({
|
|
18
|
+
implementation: MemoryGraphQLSchemaKeyVerificationImpl,
|
|
19
|
+
dependencies: []
|
|
20
|
+
});
|
|
21
|
+
export { MemoryGraphQLSchemaKeyVerification };
|
|
22
|
+
|
|
23
|
+
//# sourceMappingURL=MemoryGraphQLSchemaKeyVerification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine/MemoryGraphQLSchemaKeyVerification.js","sources":["../../src/engine/MemoryGraphQLSchemaKeyVerification.ts"],"sourcesContent":["import { GraphQLSchemaKeyVerification as Abstraction } from \"./abstractions.js\";\n\n/**\n * Remembers the output each factory produced under each schema key, and throws when the same factory\n * produces something else under a key it used before.\n */\nclass MemoryGraphQLSchemaKeyVerificationImpl implements Abstraction.Interface {\n private readonly outputs = new Map<string, string>();\n\n public check(params: Abstraction.Check): void {\n const { factory, key, output } = params;\n const id = JSON.stringify([factory, key]);\n const previous = this.outputs.get(id);\n\n if (previous === undefined) {\n this.outputs.set(id, output);\n return;\n }\n\n if (previous !== output) {\n throw new Error(\n `GraphQL schema factory \"${factory}\" produced a different schema under the same schema key \"${key}\". Its getSchemaKey() is missing something its output depends on.`\n );\n }\n }\n}\n\nexport const MemoryGraphQLSchemaKeyVerification = Abstraction.createImplementation({\n implementation: MemoryGraphQLSchemaKeyVerificationImpl,\n dependencies: []\n});\n"],"names":["MemoryGraphQLSchemaKeyVerificationImpl","params","factory","key","output","id","JSON","previous","undefined","Error","Map","MemoryGraphQLSchemaKeyVerification","Abstraction"],"mappings":";AAMA,MAAMA;IAGK,MAAMC,MAAyB,EAAQ;QAC1C,MAAM,EAAEC,OAAO,EAAEC,GAAG,EAAEC,MAAM,EAAE,GAAGH;QACjC,MAAMI,KAAKC,KAAK,SAAS,CAAC;YAACJ;YAASC;SAAI;QACxC,MAAMI,WAAW,IAAI,CAAC,OAAO,CAAC,GAAG,CAACF;QAElC,IAAIE,AAAaC,WAAbD,UAAwB,YACxB,IAAI,CAAC,OAAO,CAAC,GAAG,CAACF,IAAID;QAIzB,IAAIG,aAAaH,QACb,MAAM,IAAIK,MACN,CAAC,wBAAwB,EAAEP,QAAQ,yDAAyD,EAAEC,IAAI,iEAAiE,CAAC;IAGhL;;aAjBiB,OAAO,GAAG,IAAIO;;AAkBnC;AAEO,MAAMC,qCAAqCC,6BAAAA,oBAAgC,CAAC;IAC/E,gBAAgBZ;IAChB,cAAc,EAAE;AACpB"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { GraphQLSchema } from "graphql";
|
|
2
|
+
export interface IGraphQLEngine {
|
|
3
|
+
execute(body: any): Promise<any>;
|
|
4
|
+
}
|
|
5
|
+
export declare const GraphQLEngine: import("@webiny/di").Abstraction<IGraphQLEngine>;
|
|
6
|
+
export declare namespace GraphQLEngine {
|
|
7
|
+
type Interface = IGraphQLEngine;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* GraphQLSchemaCache - Keeps built executable schemas across requests, keyed by what they were built
|
|
11
|
+
* from. Register it in the root container, so it lives as long as the handler.
|
|
12
|
+
*/
|
|
13
|
+
export interface IGraphQLSchemaCache {
|
|
14
|
+
getOrBuild(key: string, build: () => Promise<GraphQLSchema>): Promise<GraphQLSchema>;
|
|
15
|
+
}
|
|
16
|
+
export declare const GraphQLSchemaCache: import("@webiny/di").Abstraction<IGraphQLSchemaCache>;
|
|
17
|
+
export declare namespace GraphQLSchemaCache {
|
|
18
|
+
type Interface = IGraphQLSchemaCache;
|
|
19
|
+
}
|
|
20
|
+
export interface IGraphQLSchemaKeyCheck {
|
|
21
|
+
factory: string;
|
|
22
|
+
key: string;
|
|
23
|
+
output: string;
|
|
24
|
+
}
|
|
25
|
+
export interface IGraphQLSchemaKeyVerification {
|
|
26
|
+
check(params: IGraphQLSchemaKeyCheck): void;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* GraphQLSchemaKeyVerification - Fails when a schema factory produces different output under the same
|
|
30
|
+
* schema key, which would serve a stale schema. Register it in the root container of test handlers.
|
|
31
|
+
*/
|
|
32
|
+
export declare const GraphQLSchemaKeyVerification: import("@webiny/di").Abstraction<IGraphQLSchemaKeyVerification>;
|
|
33
|
+
export declare namespace GraphQLSchemaKeyVerification {
|
|
34
|
+
type Interface = IGraphQLSchemaKeyVerification;
|
|
35
|
+
type Check = IGraphQLSchemaKeyCheck;
|
|
36
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createAbstraction } from "@webiny/feature/api";
|
|
2
|
+
const GraphQLEngine = createAbstraction("GraphQLEngine");
|
|
3
|
+
const GraphQLSchemaCache = createAbstraction("GraphQLSchemaCache");
|
|
4
|
+
const GraphQLSchemaKeyVerification = createAbstraction("GraphQLSchemaKeyVerification");
|
|
5
|
+
export { GraphQLEngine, GraphQLSchemaCache, GraphQLSchemaKeyVerification };
|
|
6
|
+
|
|
7
|
+
//# sourceMappingURL=abstractions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine/abstractions.js","sources":["../../src/engine/abstractions.ts"],"sourcesContent":["import type { GraphQLSchema } from \"graphql\";\nimport { createAbstraction } from \"@webiny/feature/api\";\n\nexport interface IGraphQLEngine {\n execute(body: any): Promise<any>;\n}\n\nexport const GraphQLEngine = createAbstraction<IGraphQLEngine>(\"GraphQLEngine\");\n\nexport namespace GraphQLEngine {\n export type Interface = IGraphQLEngine;\n}\n\n/**\n * GraphQLSchemaCache - Keeps built executable schemas across requests, keyed by what they were built\n * from. Register it in the root container, so it lives as long as the handler.\n */\nexport interface IGraphQLSchemaCache {\n getOrBuild(key: string, build: () => Promise<GraphQLSchema>): Promise<GraphQLSchema>;\n}\n\nexport const GraphQLSchemaCache = createAbstraction<IGraphQLSchemaCache>(\"GraphQLSchemaCache\");\n\nexport namespace GraphQLSchemaCache {\n export type Interface = IGraphQLSchemaCache;\n}\n\nexport interface IGraphQLSchemaKeyCheck {\n factory: string;\n key: string;\n output: string;\n}\n\nexport interface IGraphQLSchemaKeyVerification {\n check(params: IGraphQLSchemaKeyCheck): void;\n}\n\n/**\n * GraphQLSchemaKeyVerification - Fails when a schema factory produces different output under the same\n * schema key, which would serve a stale schema. Register it in the root container of test handlers.\n */\nexport const GraphQLSchemaKeyVerification = createAbstraction<IGraphQLSchemaKeyVerification>(\n \"GraphQLSchemaKeyVerification\"\n);\n\nexport namespace GraphQLSchemaKeyVerification {\n export type Interface = IGraphQLSchemaKeyVerification;\n export type Check = IGraphQLSchemaKeyCheck;\n}\n"],"names":["GraphQLEngine","createAbstraction","GraphQLSchemaCache","GraphQLSchemaKeyVerification"],"mappings":";AAOO,MAAMA,gBAAgBC,kBAAkC;AAcxD,MAAMC,qBAAqBD,kBAAuC;AAoBlE,MAAME,+BAA+BF,kBACxC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { IGraphQLSchema } from "../graphql/abstractions.public.js";
|
|
2
|
+
/**
|
|
3
|
+
* The key identifies what an executable schema is built from: the type definitions, which paths
|
|
4
|
+
* have a resolver, and how many decorators each path has. Resolver functions themselves can't be
|
|
5
|
+
* compared, but every one of them resolves its dependencies when it runs, so two requests that
|
|
6
|
+
* produce the same key produce schemas that behave the same.
|
|
7
|
+
*/
|
|
8
|
+
export declare const createSchemaCacheKey: (schema: IGraphQLSchema) => string;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
const collectResolverPaths = (resolvers, prefix, paths)=>{
|
|
3
|
+
for (const [key, value] of Object.entries(resolvers)){
|
|
4
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
5
|
+
if ("function" == typeof value) paths.push(path);
|
|
6
|
+
else if (value && "object" == typeof value) collectResolverPaths(value, path, paths);
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
const createSchemaCacheKey = (schema)=>{
|
|
10
|
+
const resolverPaths = [];
|
|
11
|
+
collectResolverPaths(schema.resolvers ?? {}, "", resolverPaths);
|
|
12
|
+
const decoratorPaths = Object.entries(schema.resolverDecorators ?? {}).map(([path, decorators])=>`${path}:${decorators.length}`);
|
|
13
|
+
const hash = createHash("sha1");
|
|
14
|
+
hash.update(String(schema.typeDefs ?? ""));
|
|
15
|
+
hash.update("\n#resolvers\n");
|
|
16
|
+
hash.update(resolverPaths.sort().join("\n"));
|
|
17
|
+
hash.update("\n#decorators\n");
|
|
18
|
+
hash.update(decoratorPaths.sort().join("\n"));
|
|
19
|
+
return hash.digest("hex");
|
|
20
|
+
};
|
|
21
|
+
export { createSchemaCacheKey };
|
|
22
|
+
|
|
23
|
+
//# sourceMappingURL=createSchemaCacheKey.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine/createSchemaCacheKey.js","sources":["../../src/engine/createSchemaCacheKey.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { IGraphQLSchema } from \"~/graphql/abstractions.public.js\";\n\nconst collectResolverPaths = (resolvers: Record<string, any>, prefix: string, paths: string[]) => {\n for (const [key, value] of Object.entries(resolvers)) {\n const path = prefix ? `${prefix}.${key}` : key;\n if (typeof value === \"function\") {\n paths.push(path);\n } else if (value && typeof value === \"object\") {\n collectResolverPaths(value, path, paths);\n }\n }\n};\n\n/**\n * The key identifies what an executable schema is built from: the type definitions, which paths\n * have a resolver, and how many decorators each path has. Resolver functions themselves can't be\n * compared, but every one of them resolves its dependencies when it runs, so two requests that\n * produce the same key produce schemas that behave the same.\n */\nexport const createSchemaCacheKey = (schema: IGraphQLSchema): string => {\n const resolverPaths: string[] = [];\n collectResolverPaths(schema.resolvers ?? {}, \"\", resolverPaths);\n\n const decoratorPaths = Object.entries(schema.resolverDecorators ?? {}).map(\n ([path, decorators]) => `${path}:${decorators.length}`\n );\n\n const hash = createHash(\"sha1\");\n hash.update(String(schema.typeDefs ?? \"\"));\n hash.update(\"\\n#resolvers\\n\");\n hash.update(resolverPaths.sort().join(\"\\n\"));\n hash.update(\"\\n#decorators\\n\");\n hash.update(decoratorPaths.sort().join(\"\\n\"));\n\n return hash.digest(\"hex\");\n};\n"],"names":["collectResolverPaths","resolvers","prefix","paths","key","value","Object","path","createSchemaCacheKey","schema","resolverPaths","decoratorPaths","decorators","hash","createHash","String"],"mappings":";AAGA,MAAMA,uBAAuB,CAACC,WAAgCC,QAAgBC;IAC1E,KAAK,MAAM,CAACC,KAAKC,MAAM,IAAIC,OAAO,OAAO,CAACL,WAAY;QAClD,MAAMM,OAAOL,SAAS,GAAGA,OAAO,CAAC,EAAEE,KAAK,GAAGA;QAC3C,IAAI,AAAiB,cAAjB,OAAOC,OACPF,MAAM,IAAI,CAACI;aACR,IAAIF,SAAS,AAAiB,YAAjB,OAAOA,OACvBL,qBAAqBK,OAAOE,MAAMJ;IAE1C;AACJ;AAQO,MAAMK,uBAAuB,CAACC;IACjC,MAAMC,gBAA0B,EAAE;IAClCV,qBAAqBS,OAAO,SAAS,IAAI,CAAC,GAAG,IAAIC;IAEjD,MAAMC,iBAAiBL,OAAO,OAAO,CAACG,OAAO,kBAAkB,IAAI,CAAC,GAAG,GAAG,CACtE,CAAC,CAACF,MAAMK,WAAW,GAAK,GAAGL,KAAK,CAAC,EAAEK,WAAW,MAAM,EAAE;IAG1D,MAAMC,OAAOC,WAAW;IACxBD,KAAK,MAAM,CAACE,OAAON,OAAO,QAAQ,IAAI;IACtCI,KAAK,MAAM,CAAC;IACZA,KAAK,MAAM,CAACH,cAAc,IAAI,GAAG,IAAI,CAAC;IACtCG,KAAK,MAAM,CAAC;IACZA,KAAK,MAAM,CAACF,eAAe,IAAI,GAAG,IAAI,CAAC;IAEvC,OAAOE,KAAK,MAAM,CAAC;AACvB"}
|
package/engine/index.js
ADDED
package/errors.d.ts
ADDED
package/errors.js
ADDED
package/errors.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sources":["../src/errors.ts"],"sourcesContent":["import WebinyError from \"@webiny/error\";\n\nexport class NotFoundError extends WebinyError {\n constructor(message = \"Not found.\") {\n super(message, \"NOT_FOUND\");\n }\n}\n"],"names":["NotFoundError","WebinyError","message"],"mappings":";AAEO,MAAMA,sBAAsBC;IAC/B,YAAYC,UAAU,YAAY,CAAE;QAChC,KAAK,CAACA,SAAS;IACnB;AACJ"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { GraphQLSchemaBuilder as Abstraction } from "./abstractions.js";
|
|
2
|
+
import type { IGraphQLSchema } from "../../graphql/abstractions.public.js";
|
|
3
|
+
import type { ResolverDecorator } from "../../types.js";
|
|
4
|
+
export declare class GraphQLSchemaBuilder implements Abstraction.Interface {
|
|
5
|
+
private readonly typeDefsArray;
|
|
6
|
+
private readonly resolvers;
|
|
7
|
+
private readonly resolverDecorators;
|
|
8
|
+
addTypeDefs(typeDefs: string): this;
|
|
9
|
+
addResolver<TArgs = any>(config: Abstraction.Config<TArgs>): this;
|
|
10
|
+
addLegacyResolvers(resolvers: Record<string, any>, prefix?: string): this;
|
|
11
|
+
/**
|
|
12
|
+
* @internal This method needs revisiting, to align with DI concepts.
|
|
13
|
+
*/
|
|
14
|
+
addResolverDecorator(path: string, decorator: ResolverDecorator): this;
|
|
15
|
+
build(): IGraphQLSchema;
|
|
16
|
+
private setResolverAtPath;
|
|
17
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
class GraphQLSchemaBuilder {
|
|
2
|
+
addTypeDefs(typeDefs) {
|
|
3
|
+
this.typeDefsArray.push(typeDefs);
|
|
4
|
+
return this;
|
|
5
|
+
}
|
|
6
|
+
addResolver(config) {
|
|
7
|
+
const { path, dependencies = [], resolver } = config;
|
|
8
|
+
const pathParts = path.split(".");
|
|
9
|
+
const graphqlResolver = (parent, args, context, info)=>{
|
|
10
|
+
const resolvedDeps = dependencies.map((dep)=>{
|
|
11
|
+
const [abstraction, options] = Array.isArray(dep) ? dep : [
|
|
12
|
+
dep,
|
|
13
|
+
void 0
|
|
14
|
+
];
|
|
15
|
+
return options?.multiple ? context.container.resolveAll(abstraction) : context.container.resolve(abstraction);
|
|
16
|
+
});
|
|
17
|
+
const actualResolver = resolver(...resolvedDeps);
|
|
18
|
+
return actualResolver({
|
|
19
|
+
parent,
|
|
20
|
+
args,
|
|
21
|
+
context,
|
|
22
|
+
info
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
this.setResolverAtPath(pathParts, graphqlResolver);
|
|
26
|
+
return this;
|
|
27
|
+
}
|
|
28
|
+
addLegacyResolvers(resolvers, prefix = "") {
|
|
29
|
+
for (const [key, value] of Object.entries(resolvers)){
|
|
30
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
31
|
+
if ("function" == typeof value) {
|
|
32
|
+
const fn = value;
|
|
33
|
+
this.addResolver({
|
|
34
|
+
path,
|
|
35
|
+
dependencies: [],
|
|
36
|
+
resolver: ()=>({ parent, args, context, info })=>fn(parent, args, context, info)
|
|
37
|
+
});
|
|
38
|
+
} else if ("object" == typeof value && null !== value) this.addLegacyResolvers(value, path);
|
|
39
|
+
}
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
addResolverDecorator(path, decorator) {
|
|
43
|
+
if (!this.resolverDecorators[path]) this.resolverDecorators[path] = [];
|
|
44
|
+
this.resolverDecorators[path].push(decorator);
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
build() {
|
|
48
|
+
return {
|
|
49
|
+
typeDefs: this.typeDefsArray.join("\n"),
|
|
50
|
+
resolvers: this.resolvers,
|
|
51
|
+
resolverDecorators: this.resolverDecorators
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
setResolverAtPath(pathParts, resolver) {
|
|
55
|
+
let current = this.resolvers;
|
|
56
|
+
for(let i = 0; i < pathParts.length - 1; i++){
|
|
57
|
+
const part = pathParts[i];
|
|
58
|
+
if (!current[part]) current[part] = {};
|
|
59
|
+
current = current[part];
|
|
60
|
+
}
|
|
61
|
+
const finalKey = pathParts[pathParts.length - 1];
|
|
62
|
+
current[finalKey] = resolver;
|
|
63
|
+
}
|
|
64
|
+
constructor(){
|
|
65
|
+
this.typeDefsArray = [];
|
|
66
|
+
this.resolvers = {};
|
|
67
|
+
this.resolverDecorators = {};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export { GraphQLSchemaBuilder };
|
|
71
|
+
|
|
72
|
+
//# sourceMappingURL=GraphQLSchemaBuilder.js.map
|