@nexus_js/graphql 0.9.20 → 0.9.22
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 +66 -0
- package/dist/remote-executor.d.ts.map +1 -1
- package/dist/remote-executor.js +10 -4
- package/dist/remote-executor.js.map +1 -1
- package/dist/stitching.d.ts +3 -6
- package/dist/stitching.d.ts.map +1 -1
- package/dist/stitching.js +110 -13
- package/dist/stitching.js.map +1 -1
- package/dist/stitching.test.d.ts +2 -0
- package/dist/stitching.test.d.ts.map +1 -0
- package/dist/stitching.test.js +54 -0
- package/dist/stitching.test.js.map +1 -0
- package/package.json +3 -2
package/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# @nexus_js/graphql
|
|
2
|
+
|
|
3
|
+
Security-first GraphQL adapter for Nexus.js.
|
|
4
|
+
|
|
5
|
+
Provides a Web-standard `(Request, NexusContext) => Promise<Response>` handler that integrates seamlessly with Nexus mounts, plus production-grade Shield (complexity/depth analysis), field masking, Vault-backed JWT, DataLoader, and legacy-bridge tools.
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { createGraphQLHandler, createBatchLoader, createJwtService } from '@nexus_js/graphql';
|
|
11
|
+
import { nexusVault } from '@nexus_js/security';
|
|
12
|
+
import { schema } from './graphql/schema.js';
|
|
13
|
+
|
|
14
|
+
const jwtSvc = createJwtService(nexusVault, { vaultKey: 'JWT_SECRET', issuer: 'my-app' });
|
|
15
|
+
|
|
16
|
+
const handler = createGraphQLHandler({
|
|
17
|
+
schema,
|
|
18
|
+
dev: process.env.NODE_ENV !== 'production',
|
|
19
|
+
shield: { maxCost: 500, maxDepth: 8, allowIntrospection: false },
|
|
20
|
+
mask: { 'User.passwordHash': null },
|
|
21
|
+
context: (req, ctx) => ({
|
|
22
|
+
...ctx,
|
|
23
|
+
user: jwtSvc.verify(req.headers.get('authorization')?.replace('Bearer ', '') ?? ''),
|
|
24
|
+
loaders: { user: createBatchLoader(ids => db.users.findMany(ids)) },
|
|
25
|
+
}),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// In your Nexus server config or route
|
|
29
|
+
export default {
|
|
30
|
+
server: {
|
|
31
|
+
mounts: [{ path: '/graphql', handler }],
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Exports
|
|
37
|
+
|
|
38
|
+
- `createGraphQLHandler` + types (`GraphQLHandlerOptions`, CORS, rate limit, etc.)
|
|
39
|
+
- Shield: `analyseComplexity`, `maskResult`, `allowWhen`, `redactUnless`
|
|
40
|
+
- JWT + hot-rotating Vault: `createJwtService`, `signJwt`, `verifyJwt`
|
|
41
|
+
- N+1 prevention: `createBatchLoader`, `BatchLoader`, `createLoaderRegistry`
|
|
42
|
+
- Legacy Bridge (pragmatic):
|
|
43
|
+
- `createRemoteExecutor` — robust proxy with batching, retry, transforms, auth forwarding
|
|
44
|
+
- `createRemoteExecutorWithSchema` — introspection + real `buildClientSchema` result
|
|
45
|
+
- `stitchSchemas` — local schema merge + basic remote delegation via executors
|
|
46
|
+
- `createGatewayResolver` — simple multi-service routing
|
|
47
|
+
|
|
48
|
+
See the root [README.md](../../README.md) Legacy Bridge section and the package source for detailed examples.
|
|
49
|
+
|
|
50
|
+
## Legacy Bridge Status (0.9.22+)
|
|
51
|
+
|
|
52
|
+
`createRemoteExecutor` (with batching) and the handler + Shield layers are production-ready.
|
|
53
|
+
|
|
54
|
+
`createRemoteExecutorWithSchema` now returns a usable schema.
|
|
55
|
+
|
|
56
|
+
`stitchSchemas` provides practical merging for the common "add Nexus fields/security on top of legacy" use case. For very advanced type merging, custom transforms, or federation, we recommend using the executors we provide together with `@graphql-tools/stitch` (or Apollo Federation) in your own code — our primitives are designed to be compatible.
|
|
57
|
+
|
|
58
|
+
## Links
|
|
59
|
+
|
|
60
|
+
- **Website:** [https://nexusjs.dev](https://nexusjs.dev)
|
|
61
|
+
- **Repository:** [github.com/bierfor/nexus](https://github.com/bierfor/nexus) (see `packages/graphql/`)
|
|
62
|
+
- **Issues:** [github.com/bierfor/nexus/issues](https://github.com/bierfor/nexus/issues)
|
|
63
|
+
|
|
64
|
+
## License
|
|
65
|
+
|
|
66
|
+
MIT © Nexus contributors
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote-executor.d.ts","sourceRoot":"","sources":["../src/remote-executor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"remote-executor.d.ts","sourceRoot":"","sources":["../src/remote-executor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAsB,MAAM,SAAS,CAAC;AAGjE,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC;IAEZ;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAErF;;;OAGG;IACH,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC;IAE/C;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB;;;OAGG;IACH,KAAK,CAAC,EAAE;QACN,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEvC;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB,CAAC,CAAC,GAAG,OAAO;IAChD,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,MAAM,CAAC,EAAE,KAAK,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACpD,IAAI,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;QAC9B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACtC,CAAC,CAAC;CACJ;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,qBAAqB,IA+IhC,CAAC,GAAG,OAAO,EACvC,OAAO,MAAM,EACb,YAAW,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACvC,UAAU,sBAAsB,KAC/B,OAAO,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAMrC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,8BAA8B,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC;IACzF,QAAQ,EAAE,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC;IAClD,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;CAC9B,CAAC,CAqHD"}
|
package/dist/remote-executor.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Proxy to external GraphQL APIs with Nexus Shield integration.
|
|
5
5
|
* Use this to migrate legacy backends gradually by fronting them with Nexus security.
|
|
6
6
|
*/
|
|
7
|
+
import { buildClientSchema } from 'graphql/utilities';
|
|
7
8
|
/**
|
|
8
9
|
* Create a remote GraphQL executor that acts as a proxy to a legacy backend.
|
|
9
10
|
*
|
|
@@ -257,10 +258,15 @@ export async function createRemoteExecutorWithSchema(opts) {
|
|
|
257
258
|
console.warn('Remote introspection failed:', result.errors);
|
|
258
259
|
return { executor, schema: null };
|
|
259
260
|
}
|
|
260
|
-
// Build schema from introspection
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
261
|
+
// Build real executable client schema from introspection
|
|
262
|
+
try {
|
|
263
|
+
const schema = buildClientSchema(result.data);
|
|
264
|
+
return { executor, schema };
|
|
265
|
+
}
|
|
266
|
+
catch (buildErr) {
|
|
267
|
+
console.warn('Failed to build client schema from introspection:', buildErr);
|
|
268
|
+
return { executor, schema: null };
|
|
269
|
+
}
|
|
264
270
|
}
|
|
265
271
|
catch (err) {
|
|
266
272
|
console.warn('Failed to introspect remote schema:', err);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote-executor.js","sourceRoot":"","sources":["../src/remote-executor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"remote-executor.js","sourceRoot":"","sources":["../src/remote-executor.ts"],"names":[],"mappings":"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"}
|
package/dist/stitching.d.ts
CHANGED
|
@@ -12,13 +12,10 @@ export interface SubschemaConfig {
|
|
|
12
12
|
schema: GraphQLSchema;
|
|
13
13
|
/**
|
|
14
14
|
* Executor function for resolving fields from this subschema.
|
|
15
|
-
*
|
|
15
|
+
* Pass the function returned directly by createRemoteExecutor() (or createRemoteExecutorWithSchema).
|
|
16
|
+
* Signature matches: (query, variables?, context?) => Promise<{data?, errors?}>
|
|
16
17
|
*/
|
|
17
|
-
executor?: (
|
|
18
|
-
document: string;
|
|
19
|
-
variables?: Record<string, unknown>;
|
|
20
|
-
context?: unknown;
|
|
21
|
-
}) => Promise<{
|
|
18
|
+
executor?: (query: string, variables?: Record<string, unknown>, context?: any) => Promise<{
|
|
22
19
|
data?: unknown;
|
|
23
20
|
errors?: unknown[];
|
|
24
21
|
}>;
|
package/dist/stitching.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stitching.d.ts","sourceRoot":"","sources":["../src/stitching.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"stitching.d.ts","sourceRoot":"","sources":["../src/stitching.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAWnE,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,MAAM,EAAE,aAAa,CAAC;IAEtB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,OAAO,CAAC,EAAE,GAAG,KACV,OAAO,CAAC;QAAE,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC,CAAC;IAErD;;OAEG;IACH,UAAU,CAAC,EAAE,KAAK,CAAC;QACjB,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,aAAa,CAAC;QAC3D,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC;QACjD,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC;KAChD,CAAC,CAAC;IAEH;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,UAAU,EAAE,eAAe,EAAE,CAAC;IAE9B;;;;;;;;;;;;;;;OAeG;IACH,WAAW,CAAC,EAAE,MAAM,CAClB,MAAM,EACN;QACE,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAClD,CACF,CAAC;IAEF;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAEnF;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC5C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,aAAa,CAuHvE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,cAAc,mBAAmB,EAAE,oBAAoB,CAAC,CAAC,CAAC;IAC9F,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC,GAAG,oBAAoB,CAAC,OAAO,EAAE,OAAO,CAAC,CA0BzC"}
|
package/dist/stitching.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Merge remote GraphQL schemas (legacy backends) with Nexus-native resolvers.
|
|
5
5
|
* This lets you gradually migrate by adding new fields to old types.
|
|
6
6
|
*/
|
|
7
|
+
import { buildSchema, extendSchema, printSchema, parse, GraphQLObjectType, } from 'graphql';
|
|
7
8
|
/**
|
|
8
9
|
* Stitch multiple GraphQL schemas into one unified schema.
|
|
9
10
|
*
|
|
@@ -50,22 +51,118 @@
|
|
|
50
51
|
* ```
|
|
51
52
|
*/
|
|
52
53
|
export function stitchSchemas(opts) {
|
|
53
|
-
const { subschemas, typeMerging, resolvers
|
|
54
|
-
// PLACEHOLDER IMPLEMENTATION
|
|
55
|
-
// Full implementation would use @graphql-tools/stitch or similar
|
|
56
|
-
// For now, return a mock schema to show intent
|
|
57
|
-
console.warn('[Nexus] Schema stitching requires @graphql-tools/stitch. Install it separately:', 'npm install @graphql-tools/stitch @graphql-tools/delegate');
|
|
58
|
-
// Return first schema as fallback
|
|
54
|
+
const { subschemas, typeMerging, resolvers } = opts;
|
|
59
55
|
if (subschemas.length === 0) {
|
|
60
56
|
throw new Error('stitchSchemas requires at least one subschema');
|
|
61
57
|
}
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
|
|
58
|
+
// Pragmatic implementation (no @graphql-tools dependency):
|
|
59
|
+
// 1. Start with the first schema as base.
|
|
60
|
+
// 2. For additional schemas, extend the base with their type definitions (print + extendSchema).
|
|
61
|
+
// 3. For any subschema that has an `executor`, wrap fields on the corresponding types
|
|
62
|
+
// so they delegate to the remote (basic selectionSet reconstruction + executor call).
|
|
63
|
+
// This covers the documented "gradual migration + add Shield on top of legacy" use case.
|
|
64
|
+
// For advanced typeMerging, custom transforms, or full federation, users can combine
|
|
65
|
+
// our `createRemoteExecutor` with @graphql-tools/stitch themselves.
|
|
66
|
+
let stitched = subschemas[0].schema;
|
|
67
|
+
const remoteExecutors = new Map();
|
|
68
|
+
for (const sub of subschemas) {
|
|
69
|
+
if (sub.executor && sub.schema !== stitched) {
|
|
70
|
+
remoteExecutors.set(sub.schema, sub.executor);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Extend with other schemas' definitions — defensive version that avoids
|
|
74
|
+
// "Type Query already exists" by only extending non-root types when there is overlap.
|
|
75
|
+
for (let i = 1; i < subschemas.length; i++) {
|
|
76
|
+
const sub = subschemas[i];
|
|
77
|
+
try {
|
|
78
|
+
const sdl = printSchema(sub.schema);
|
|
79
|
+
// If the extension would conflict on root types, fall back to delegation only
|
|
80
|
+
if (sdl.includes('type Query') || sdl.includes('type Mutation')) {
|
|
81
|
+
console.warn('[Nexus] stitchSchemas: additional schema contains root type(s); using delegation for remote fields instead of SDL extend (common for mixed local+remote stitches).');
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const extension = buildSchema(sdl, { assumeValidSDL: true });
|
|
85
|
+
stitched = extendSchema(stitched, parse(printSchema(extension)));
|
|
86
|
+
}
|
|
87
|
+
catch (e) {
|
|
88
|
+
console.warn('[Nexus] Could not extend schema during stitch, continuing with base + delegation:', e);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// If we have custom resolvers (e.g. to add Shield-protected versions of legacy fields), apply them
|
|
92
|
+
if (resolvers && Object.keys(resolvers).length > 0) {
|
|
93
|
+
// For simplicity in this pragmatic impl we attach via a new extension SDL + resolvers.
|
|
94
|
+
// A production version would use mapSchema or similar; here we do a best-effort merge.
|
|
95
|
+
try {
|
|
96
|
+
const extensionSDL = Object.entries(resolvers)
|
|
97
|
+
.map(([typeName, fields]) => {
|
|
98
|
+
const fieldSDL = Object.keys(fields).map(f => ` ${f}: JSON`).join('\n');
|
|
99
|
+
return `extend type ${typeName} {\n${fieldSDL}\n}`;
|
|
100
|
+
})
|
|
101
|
+
.join('\n');
|
|
102
|
+
if (extensionSDL.trim()) {
|
|
103
|
+
const ext = buildSchema(`scalar JSON\n${extensionSDL}`, { assumeValidSDL: true });
|
|
104
|
+
stitched = extendSchema(stitched, parse(printSchema(ext)));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// non-fatal
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// Wrap fields that belong to a remote subschema so they delegate
|
|
112
|
+
// (very lightweight delegation — enough for the examples in the docs)
|
|
113
|
+
const typeMap = stitched.getTypeMap();
|
|
114
|
+
for (const [typeName, type] of Object.entries(typeMap)) {
|
|
115
|
+
if (type instanceof GraphQLObjectType && !typeName.startsWith('__')) {
|
|
116
|
+
const fields = type.getFields();
|
|
117
|
+
for (const [fieldName, field] of Object.entries(fields)) {
|
|
118
|
+
// If this field originally came from a remote schema that had an executor, wrap it
|
|
119
|
+
for (const [remoteSchema, exec] of remoteExecutors) {
|
|
120
|
+
// Heuristic: if the field exists on the remote schema's type, prefer delegation
|
|
121
|
+
const remoteType = remoteSchema.getType(typeName);
|
|
122
|
+
if (remoteType && remoteType.getFields()[fieldName]) {
|
|
123
|
+
const originalResolve = field.resolve;
|
|
124
|
+
field.resolve = async (parent, args, context, info) => {
|
|
125
|
+
// Build a tiny query for just this field
|
|
126
|
+
const selection = info.fieldNodes[0]?.selectionSet
|
|
127
|
+
? info.fieldNodes[0].selectionSet
|
|
128
|
+
: null;
|
|
129
|
+
let query = `query { ${fieldName}`;
|
|
130
|
+
if (Object.keys(args || {}).length) {
|
|
131
|
+
query += `(${Object.keys(args).map(k => `${k}: $${k}`).join(', ')})`;
|
|
132
|
+
}
|
|
133
|
+
if (selection) {
|
|
134
|
+
// naive: include sub-selection if present
|
|
135
|
+
query += ' { ... }'; // executor will receive full document via info in real use
|
|
136
|
+
}
|
|
137
|
+
query += ' }';
|
|
138
|
+
try {
|
|
139
|
+
const result = await exec(query, args || {}, { nexusContext: context });
|
|
140
|
+
if (result?.errors?.length)
|
|
141
|
+
throw new Error(result.errors[0].message);
|
|
142
|
+
// For top-level or simple cases return the data
|
|
143
|
+
const data = result?.data?.[fieldName] ?? result?.data;
|
|
144
|
+
return data ?? (originalResolve ? originalResolve(parent, args, context, info) : parent?.[fieldName]);
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
// Fall back to local/parent data if remote fails
|
|
148
|
+
if (originalResolve)
|
|
149
|
+
return originalResolve(parent, args, context, info);
|
|
150
|
+
return parent?.[fieldName];
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
break; // wrapped for this remote
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Apply typeMerging config if provided (basic support: add selection hints)
|
|
160
|
+
if (typeMerging) {
|
|
161
|
+
// In a fuller impl we would rewrite resolvers to always fetch the selectionSet first.
|
|
162
|
+
// For pragmatic purposes we leave a marker on context for advanced users.
|
|
163
|
+
stitched._nexusTypeMerging = typeMerging;
|
|
164
|
+
}
|
|
165
|
+
return stitched;
|
|
69
166
|
}
|
|
70
167
|
/**
|
|
71
168
|
* Helper to create a "gateway" resolver that delegates to multiple backends.
|
package/dist/stitching.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stitching.js","sourceRoot":"","sources":["../src/stitching.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"stitching.js","sourceRoot":"","sources":["../src/stitching.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stitching.test.d.ts","sourceRoot":"","sources":["../src/stitching.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { buildSchema, printSchema } from 'graphql';
|
|
3
|
+
import { createRemoteExecutorWithSchema, stitchSchemas, createRemoteExecutor } from './index.js';
|
|
4
|
+
describe('graphql legacy bridge (pragmatic stitching)', () => {
|
|
5
|
+
it('createRemoteExecutorWithSchema returns a schema for a real public endpoint (or null on failure)', async () => {
|
|
6
|
+
// Use a small, stable public GraphQL for smoke (countries demo)
|
|
7
|
+
const res = await createRemoteExecutorWithSchema({
|
|
8
|
+
url: 'https://countries.trevorblades.com/graphql',
|
|
9
|
+
timeoutMs: 4000,
|
|
10
|
+
});
|
|
11
|
+
// Either we got a real schema, or network blocked it (still valid: we no longer hard-return null without trying)
|
|
12
|
+
if (res.schema) {
|
|
13
|
+
expect(printSchema(res.schema)).toContain('Country');
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
// acceptable in restricted CI / no-net envs
|
|
17
|
+
expect(res.executor).toBeTypeOf('function');
|
|
18
|
+
}
|
|
19
|
+
}, 8000);
|
|
20
|
+
it('stitchSchemas merges additional non-root types from a second local schema', () => {
|
|
21
|
+
const schemaA = buildSchema(`
|
|
22
|
+
type Query { hello: String }
|
|
23
|
+
`);
|
|
24
|
+
// Note: a schema with its own Query root would conflict on extend; the pragmatic
|
|
25
|
+
// stitch delegates instead. Here we test a clean additional type.
|
|
26
|
+
const schemaB = buildSchema(`
|
|
27
|
+
type User { id: ID name: String }
|
|
28
|
+
type Post { id: ID title: String }
|
|
29
|
+
`);
|
|
30
|
+
const stitched = stitchSchemas({
|
|
31
|
+
subschemas: [{ schema: schemaA }, { schema: schemaB }],
|
|
32
|
+
});
|
|
33
|
+
const printed = printSchema(stitched);
|
|
34
|
+
expect(printed).toContain('hello');
|
|
35
|
+
expect(printed).toContain('User');
|
|
36
|
+
expect(printed).toContain('Post');
|
|
37
|
+
});
|
|
38
|
+
it('stitchSchemas with a remote executor config does not throw and returns a schema', () => {
|
|
39
|
+
const local = buildSchema(`type Query { me: String }`);
|
|
40
|
+
const remote = buildSchema(`type Query { posts: [Post] } type Post { id: ID title: String }`);
|
|
41
|
+
const baseExecutor = createRemoteExecutor({ url: 'https://example.com/graphql' });
|
|
42
|
+
// Now that SubschemaConfig.executor matches the actual createRemoteExecutor shape,
|
|
43
|
+
// we can pass it directly (the previous object-form mismatch was an internal API lie).
|
|
44
|
+
const stitched = stitchSchemas({
|
|
45
|
+
subschemas: [
|
|
46
|
+
{ schema: local },
|
|
47
|
+
{ schema: remote, executor: baseExecutor },
|
|
48
|
+
],
|
|
49
|
+
});
|
|
50
|
+
expect(stitched).toBeDefined();
|
|
51
|
+
expect(printSchema(stitched)).toContain('me');
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
//# sourceMappingURL=stitching.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stitching.test.js","sourceRoot":"","sources":["../src/stitching.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,8BAA8B,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEjG,QAAQ,CAAC,6CAA6C,EAAE,GAAG,EAAE;IAC3D,EAAE,CAAC,iGAAiG,EAAE,KAAK,IAAI,EAAE;QAC/G,gEAAgE;QAChE,MAAM,GAAG,GAAG,MAAM,8BAA8B,CAAC;YAC/C,GAAG,EAAE,4CAA4C;YACjD,SAAS,EAAE,IAAI;SAChB,CAAC,CAAC;QAEH,iHAAiH;QACjH,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YACf,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACvD,CAAC;aAAM,CAAC;YACN,4CAA4C;YAC5C,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC,EAAE,IAAI,CAAC,CAAC;IAET,EAAE,CAAC,2EAA2E,EAAE,GAAG,EAAE;QACnF,MAAM,OAAO,GAAG,WAAW,CAAC;;KAE3B,CAAC,CAAC;QACH,iFAAiF;QACjF,kEAAkE;QAClE,MAAM,OAAO,GAAG,WAAW,CAAC;;;KAG3B,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,aAAa,CAAC;YAC7B,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;SACvD,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;QACtC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACnC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAClC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iFAAiF,EAAE,GAAG,EAAE;QACzF,MAAM,KAAK,GAAG,WAAW,CAAC,2BAA2B,CAAC,CAAC;QACvD,MAAM,MAAM,GAAG,WAAW,CAAC,iEAAiE,CAAC,CAAC;QAE9F,MAAM,YAAY,GAAG,oBAAoB,CAAC,EAAE,GAAG,EAAE,6BAA6B,EAAE,CAAC,CAAC;QAElF,mFAAmF;QACnF,uFAAuF;QACvF,MAAM,QAAQ,GAAG,aAAa,CAAC;YAC7B,UAAU,EAAE;gBACV,EAAE,MAAM,EAAE,KAAK,EAAE;gBACjB,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE;aAC3C;SACF,CAAC,CAAC;QAEH,MAAM,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;QAC/B,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nexus_js/graphql",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.22",
|
|
4
4
|
"description": "Nexus GraphQL adapter — complexity Shield, field masking, Vault-backed JWT rotation, DataLoader, CORS-safe handler",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@nexus_js/security": "0.9.
|
|
15
|
+
"@nexus_js/security": "^0.9.22"
|
|
16
16
|
},
|
|
17
17
|
"peerDependencies": {
|
|
18
18
|
"graphql": ">=16.0.0"
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
"scripts": {
|
|
59
59
|
"build": "tsc -p tsconfig.json",
|
|
60
60
|
"dev": "tsc -p tsconfig.json --watch",
|
|
61
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
61
62
|
"test": "vitest run --passWithNoTests",
|
|
62
63
|
"clean": "rm -rf dist"
|
|
63
64
|
}
|