@btravstack/graphql-server 0.0.0-stage → 0.21.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/LICENSE +21 -0
- package/README.md +17 -2
- package/dist/index.cjs +87 -0
- package/dist/index.d.cts +25 -0
- package/dist/index.d.mts +25 -0
- package/dist/index.mjs +86 -0
- package/package.json +74 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Benoit TRAVERS
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @btravstack/graphql-server
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A GraphQL Yoga answerer for the protocol-neutral
|
|
4
|
+
[`@btravstack/http-server`](../http-server) runtime. Supply any
|
|
5
|
+
`GraphQLSchema`; the package has required GraphQL and Yoga peers and no oRPC
|
|
6
|
+
server dependency. `graphql(defineAuth(), { schema })` contributes a
|
|
7
|
+
`HttpHandler` member. A request-scoped unit and the Node incoming request are
|
|
8
|
+
available to resolvers.
|
|
9
|
+
Pass `units` with `unit` to check each injected port against the module the
|
|
10
|
+
selected request kind actually forks. Pass the same `units` record to
|
|
11
|
+
`httpServer({ unit: units })` so the runtime can apply unit test overrides.
|
|
12
|
+
Yoga plugins and CORS policy are explicit
|
|
13
|
+
options; the wildcard CORS default and Yoga console logging are disabled.
|
|
14
|
+
Preflights use Yoga's CORS policy before authentication, and Yoga plugins are
|
|
15
|
+
disposed when the application stops.
|
|
16
|
+
|
|
17
|
+
See [Serve GraphQL](https://btravstack.github.io/btravstack/how-to/serve-graphql)
|
|
18
|
+
and the [separate GraphQL gateway](../../examples/order-graphql-api).
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let _btravstack_di = require("@btravstack/di");
|
|
3
|
+
let _btravstack_http_server_internal = require("@btravstack/http-server/internal");
|
|
4
|
+
let graphql_yoga = require("graphql-yoga");
|
|
5
|
+
let unthrown = require("unthrown");
|
|
6
|
+
//#region src/graphql.ts
|
|
7
|
+
const dispose = Symbol("graphql.dispose");
|
|
8
|
+
const graphql = (api, options) => {
|
|
9
|
+
const mount = options.prefix ?? "/graphql";
|
|
10
|
+
let end = mount.length;
|
|
11
|
+
while (end > 1 && mount.charCodeAt(end - 1) === 47) end--;
|
|
12
|
+
const prefix = mount.slice(0, end);
|
|
13
|
+
const requirements = options.requires;
|
|
14
|
+
const schemes = [...new Set(requirements?.flatMap((requirement) => Object.keys(requirement)) ?? [])];
|
|
15
|
+
const typed = _btravstack_di.Provider.member(_btravstack_http_server_internal.HttpHandler)({
|
|
16
|
+
inject: {
|
|
17
|
+
config: _btravstack_http_server_internal.HttpConfig,
|
|
18
|
+
units: _btravstack_http_server_internal.HttpUnit,
|
|
19
|
+
...(0, _btravstack_http_server_internal.schemeDeps)(schemes)
|
|
20
|
+
},
|
|
21
|
+
sync: (services) => {
|
|
22
|
+
const config = services.config;
|
|
23
|
+
const units = services.units;
|
|
24
|
+
if (options.units !== void 0) {
|
|
25
|
+
for (const kind of requirements === void 0 ? ["anonymous"] : schemes) if ((options.units[kind] ?? options.units["anonymous"]) !== (units[kind] ?? units["anonymous"])) throw new Error(`[graphql-server] unit kind ${JSON.stringify(kind)} differs from HttpUnit`);
|
|
26
|
+
}
|
|
27
|
+
const authenticators = (0, _btravstack_http_server_internal.schemeServices)(schemes, services);
|
|
28
|
+
const yoga = (0, graphql_yoga.createYoga)({
|
|
29
|
+
schema: options.schema,
|
|
30
|
+
graphqlEndpoint: prefix,
|
|
31
|
+
cors: options.cors ?? (config.corsOrigin === "" ? false : { origin: config.corsOrigin.split(",").map((origin) => origin.trim()) }),
|
|
32
|
+
plugins: [{ onRequest: ({ serverContext, fetchAPI, endResponse }) => {
|
|
33
|
+
if (serverContext.refusalStatus !== void 0) endResponse(new fetchAPI.Response(null, { status: serverContext.refusalStatus }));
|
|
34
|
+
} }, ...options.plugins ?? []],
|
|
35
|
+
logging: false,
|
|
36
|
+
graphiql: false,
|
|
37
|
+
landingPage: false,
|
|
38
|
+
multipart: false,
|
|
39
|
+
maxRequestBodySize: config.bodyLimit === 0 ? false : config.bodyLimit,
|
|
40
|
+
disposeOnProcessTerminate: false
|
|
41
|
+
});
|
|
42
|
+
return {
|
|
43
|
+
prefix,
|
|
44
|
+
handle: async (request, response, signal, host) => {
|
|
45
|
+
if (request.method === "OPTIONS" && request.headers["access-control-request-method"] !== void 0) {
|
|
46
|
+
await yoga.handle(request, response, {
|
|
47
|
+
principal: void 0,
|
|
48
|
+
incoming: request,
|
|
49
|
+
unit: {},
|
|
50
|
+
signal
|
|
51
|
+
});
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
let resolved;
|
|
55
|
+
if (requirements !== void 0) {
|
|
56
|
+
const result = await (0, _btravstack_http_server_internal.resolveScheme)(requirements, authenticators, request.headers).mapErrCases((matcher) => matcher.with(unthrown.P.tag("Unauthenticated"), () => 401).with(unthrown.P.tag("UnderScoped"), () => 403));
|
|
57
|
+
if (result.isDefect()) throw result.cause;
|
|
58
|
+
if (result.isErr()) {
|
|
59
|
+
await yoga.handle(request, response, {
|
|
60
|
+
principal: void 0,
|
|
61
|
+
incoming: request,
|
|
62
|
+
unit: {},
|
|
63
|
+
signal,
|
|
64
|
+
refusalStatus: result.error
|
|
65
|
+
});
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
resolved = result.value;
|
|
69
|
+
}
|
|
70
|
+
const forked = await (0, _btravstack_http_server_internal.forkUnit)(host, units, api.principals, resolved, options.unit ?? {});
|
|
71
|
+
if (forked.isDefect()) throw forked.cause;
|
|
72
|
+
await yoga.handle(request, response, {
|
|
73
|
+
principal: requirements === void 0 ? void 0 : (0, _btravstack_http_server_internal.principalOf)(requirements, resolved),
|
|
74
|
+
incoming: request,
|
|
75
|
+
unit: forked.get(),
|
|
76
|
+
signal
|
|
77
|
+
});
|
|
78
|
+
},
|
|
79
|
+
[dispose]: () => yoga.dispose()
|
|
80
|
+
};
|
|
81
|
+
},
|
|
82
|
+
onStop: (answerer) => answerer[dispose]()
|
|
83
|
+
});
|
|
84
|
+
return Object.assign(typed, { authenticators: api.providers });
|
|
85
|
+
};
|
|
86
|
+
//#endregion
|
|
87
|
+
exports.graphql = graphql;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { OneScheme, Requirements } from "@btravstack/contract";
|
|
2
|
+
import { AnyPort, Provider, Scope } from "@btravstack/di";
|
|
3
|
+
import { Authenticators, HttpAuth, HttpConfig, HttpHandler, HttpUnit, KindOf, Kinds, RequiresGate, SchemePortsOf, UnitFor, UnitsNeedsOf, UnitsOf } from "@btravstack/http-server/internal";
|
|
4
|
+
import { GraphQLSchema } from "graphql";
|
|
5
|
+
import { Plugin, YogaServerOptions } from "graphql-yoga";
|
|
6
|
+
//#region src/graphql.d.ts
|
|
7
|
+
type YogaCors = YogaServerOptions<Record<string, unknown>, Record<string, unknown>>["cors"];
|
|
8
|
+
type MissingUnitPorts<U extends Readonly<Record<string, AnyPort>>, Units, K extends string> = Exclude<keyof U, keyof UnitFor<U, Units, K>>;
|
|
9
|
+
type UnitGate<U extends Readonly<Record<string, AnyPort>>, Units, K extends string> = [MissingUnitPorts<U, Units, K>] extends [never] ? unknown : {
|
|
10
|
+
readonly "UNIT PORT MISSING — the selected kind does not export": MissingUnitPorts<U, Units, K>;
|
|
11
|
+
};
|
|
12
|
+
/** Serve a GraphQL schema as one answerer under the existing HTTP runtime. */
|
|
13
|
+
type GraphqlOptions<A extends Authenticators, Units extends UnitsOf<A>, R extends Requirements & { readonly [I in keyof R]: OneScheme<R[I]>; }, U extends Readonly<Record<string, AnyPort>>> = {
|
|
14
|
+
readonly schema: GraphQLSchema;
|
|
15
|
+
readonly prefix?: `/${string}`;
|
|
16
|
+
readonly cors?: YogaCors;
|
|
17
|
+
readonly plugins?: readonly Plugin[];
|
|
18
|
+
readonly units?: Units & { readonly [K in Exclude<keyof Units, Kinds<A>>]: never; };
|
|
19
|
+
readonly unit?: U & UnitGate<U, Units, KindOf<R>>;
|
|
20
|
+
readonly requires?: R & RequiresGate<R, { readonly [K in keyof A]: A[K]["scope"]; }>;
|
|
21
|
+
};
|
|
22
|
+
export declare const graphql: <A extends Authenticators, Units extends UnitsOf<A> = Record<never, never>, const R extends Requirements & { readonly [I in keyof R]: OneScheme<R[I]>; } = never, U extends Readonly<Record<string, AnyPort>> = Record<never, never>>(api: HttpAuth<A>, options: GraphqlOptions<A, Units, R, U>) => Provider<HttpHandler, never, HttpConfig | HttpUnit | Scope | SchemePortsOf<R> | UnitsNeedsOf<Units>> & {
|
|
23
|
+
authenticators: readonly import("@btravstack/http-server/internal").SchemeProviders<A>[];
|
|
24
|
+
};
|
|
25
|
+
//#endregion
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { AnyPort, Provider, Scope } from "@btravstack/di";
|
|
2
|
+
import { Authenticators, HttpAuth, HttpConfig, HttpHandler, HttpUnit, KindOf, Kinds, RequiresGate, SchemePortsOf, UnitFor, UnitsNeedsOf, UnitsOf } from "@btravstack/http-server/internal";
|
|
3
|
+
import { Plugin, YogaServerOptions } from "graphql-yoga";
|
|
4
|
+
import { OneScheme, Requirements } from "@btravstack/contract";
|
|
5
|
+
import { GraphQLSchema } from "graphql";
|
|
6
|
+
//#region src/graphql.d.ts
|
|
7
|
+
type YogaCors = YogaServerOptions<Record<string, unknown>, Record<string, unknown>>["cors"];
|
|
8
|
+
type MissingUnitPorts<U extends Readonly<Record<string, AnyPort>>, Units, K extends string> = Exclude<keyof U, keyof UnitFor<U, Units, K>>;
|
|
9
|
+
type UnitGate<U extends Readonly<Record<string, AnyPort>>, Units, K extends string> = [MissingUnitPorts<U, Units, K>] extends [never] ? unknown : {
|
|
10
|
+
readonly "UNIT PORT MISSING — the selected kind does not export": MissingUnitPorts<U, Units, K>;
|
|
11
|
+
};
|
|
12
|
+
/** Serve a GraphQL schema as one answerer under the existing HTTP runtime. */
|
|
13
|
+
type GraphqlOptions<A extends Authenticators, Units extends UnitsOf<A>, R extends Requirements & { readonly [I in keyof R]: OneScheme<R[I]>; }, U extends Readonly<Record<string, AnyPort>>> = {
|
|
14
|
+
readonly schema: GraphQLSchema;
|
|
15
|
+
readonly prefix?: `/${string}`;
|
|
16
|
+
readonly cors?: YogaCors;
|
|
17
|
+
readonly plugins?: readonly Plugin[];
|
|
18
|
+
readonly units?: Units & { readonly [K in Exclude<keyof Units, Kinds<A>>]: never; };
|
|
19
|
+
readonly unit?: U & UnitGate<U, Units, KindOf<R>>;
|
|
20
|
+
readonly requires?: R & RequiresGate<R, { readonly [K in keyof A]: A[K]["scope"]; }>;
|
|
21
|
+
};
|
|
22
|
+
export declare const graphql: <A extends Authenticators, Units extends UnitsOf<A> = Record<never, never>, const R extends Requirements & { readonly [I in keyof R]: OneScheme<R[I]>; } = never, U extends Readonly<Record<string, AnyPort>> = Record<never, never>>(api: HttpAuth<A>, options: GraphqlOptions<A, Units, R, U>) => Provider<HttpHandler, never, HttpConfig | HttpUnit | Scope | SchemePortsOf<R> | UnitsNeedsOf<Units>> & {
|
|
23
|
+
authenticators: readonly import("@btravstack/http-server/internal").SchemeProviders<A>[];
|
|
24
|
+
};
|
|
25
|
+
//#endregion
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Provider } from "@btravstack/di";
|
|
2
|
+
import { HttpConfig, HttpHandler, HttpUnit, forkUnit, principalOf, resolveScheme, schemeDeps, schemeServices } from "@btravstack/http-server/internal";
|
|
3
|
+
import { createYoga } from "graphql-yoga";
|
|
4
|
+
import { P } from "unthrown";
|
|
5
|
+
//#region src/graphql.ts
|
|
6
|
+
const dispose = Symbol("graphql.dispose");
|
|
7
|
+
const graphql = (api, options) => {
|
|
8
|
+
const mount = options.prefix ?? "/graphql";
|
|
9
|
+
let end = mount.length;
|
|
10
|
+
while (end > 1 && mount.charCodeAt(end - 1) === 47) end--;
|
|
11
|
+
const prefix = mount.slice(0, end);
|
|
12
|
+
const requirements = options.requires;
|
|
13
|
+
const schemes = [...new Set(requirements?.flatMap((requirement) => Object.keys(requirement)) ?? [])];
|
|
14
|
+
const typed = Provider.member(HttpHandler)({
|
|
15
|
+
inject: {
|
|
16
|
+
config: HttpConfig,
|
|
17
|
+
units: HttpUnit,
|
|
18
|
+
...schemeDeps(schemes)
|
|
19
|
+
},
|
|
20
|
+
sync: (services) => {
|
|
21
|
+
const config = services.config;
|
|
22
|
+
const units = services.units;
|
|
23
|
+
if (options.units !== void 0) {
|
|
24
|
+
for (const kind of requirements === void 0 ? ["anonymous"] : schemes) if ((options.units[kind] ?? options.units["anonymous"]) !== (units[kind] ?? units["anonymous"])) throw new Error(`[graphql-server] unit kind ${JSON.stringify(kind)} differs from HttpUnit`);
|
|
25
|
+
}
|
|
26
|
+
const authenticators = schemeServices(schemes, services);
|
|
27
|
+
const yoga = createYoga({
|
|
28
|
+
schema: options.schema,
|
|
29
|
+
graphqlEndpoint: prefix,
|
|
30
|
+
cors: options.cors ?? (config.corsOrigin === "" ? false : { origin: config.corsOrigin.split(",").map((origin) => origin.trim()) }),
|
|
31
|
+
plugins: [{ onRequest: ({ serverContext, fetchAPI, endResponse }) => {
|
|
32
|
+
if (serverContext.refusalStatus !== void 0) endResponse(new fetchAPI.Response(null, { status: serverContext.refusalStatus }));
|
|
33
|
+
} }, ...options.plugins ?? []],
|
|
34
|
+
logging: false,
|
|
35
|
+
graphiql: false,
|
|
36
|
+
landingPage: false,
|
|
37
|
+
multipart: false,
|
|
38
|
+
maxRequestBodySize: config.bodyLimit === 0 ? false : config.bodyLimit,
|
|
39
|
+
disposeOnProcessTerminate: false
|
|
40
|
+
});
|
|
41
|
+
return {
|
|
42
|
+
prefix,
|
|
43
|
+
handle: async (request, response, signal, host) => {
|
|
44
|
+
if (request.method === "OPTIONS" && request.headers["access-control-request-method"] !== void 0) {
|
|
45
|
+
await yoga.handle(request, response, {
|
|
46
|
+
principal: void 0,
|
|
47
|
+
incoming: request,
|
|
48
|
+
unit: {},
|
|
49
|
+
signal
|
|
50
|
+
});
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
let resolved;
|
|
54
|
+
if (requirements !== void 0) {
|
|
55
|
+
const result = await resolveScheme(requirements, authenticators, request.headers).mapErrCases((matcher) => matcher.with(P.tag("Unauthenticated"), () => 401).with(P.tag("UnderScoped"), () => 403));
|
|
56
|
+
if (result.isDefect()) throw result.cause;
|
|
57
|
+
if (result.isErr()) {
|
|
58
|
+
await yoga.handle(request, response, {
|
|
59
|
+
principal: void 0,
|
|
60
|
+
incoming: request,
|
|
61
|
+
unit: {},
|
|
62
|
+
signal,
|
|
63
|
+
refusalStatus: result.error
|
|
64
|
+
});
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
resolved = result.value;
|
|
68
|
+
}
|
|
69
|
+
const forked = await forkUnit(host, units, api.principals, resolved, options.unit ?? {});
|
|
70
|
+
if (forked.isDefect()) throw forked.cause;
|
|
71
|
+
await yoga.handle(request, response, {
|
|
72
|
+
principal: requirements === void 0 ? void 0 : principalOf(requirements, resolved),
|
|
73
|
+
incoming: request,
|
|
74
|
+
unit: forked.get(),
|
|
75
|
+
signal
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
[dispose]: () => yoga.dispose()
|
|
79
|
+
};
|
|
80
|
+
},
|
|
81
|
+
onStop: (answerer) => answerer[dispose]()
|
|
82
|
+
});
|
|
83
|
+
return Object.assign(typed, { authenticators: api.providers });
|
|
84
|
+
};
|
|
85
|
+
//#endregion
|
|
86
|
+
export { graphql };
|
package/package.json
CHANGED
|
@@ -1,6 +1,77 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@btravstack/graphql-server",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.21.0",
|
|
4
|
+
"description": "The GraphQL Yoga answerer for @btravstack/http-server",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"graphql",
|
|
7
|
+
"http",
|
|
8
|
+
"server",
|
|
9
|
+
"typescript"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://github.com/btravstack/btravstack#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/btravstack/btravstack/issues"
|
|
14
|
+
},
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"author": "Benoit TRAVERS <benoit.travers.fr@gmail.com>",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/btravstack/btravstack.git",
|
|
20
|
+
"directory": "packages/graphql-server"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"type": "module",
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"main": "./dist/index.cjs",
|
|
28
|
+
"module": "./dist/index.mjs",
|
|
29
|
+
"types": "./dist/index.d.cts",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"import": {
|
|
33
|
+
"types": "./dist/index.d.mts",
|
|
34
|
+
"default": "./dist/index.mjs"
|
|
35
|
+
},
|
|
36
|
+
"require": {
|
|
37
|
+
"types": "./dist/index.d.cts",
|
|
38
|
+
"default": "./dist/index.cjs"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"./package.json": "./package.json"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@btravstack/contract": "0.21.0",
|
|
45
|
+
"@btravstack/core": "0.21.0",
|
|
46
|
+
"@btravstack/di": "0.21.0",
|
|
47
|
+
"@btravstack/http-server": "0.21.0",
|
|
48
|
+
"@btravstack/tsconfig": "0.4.0",
|
|
49
|
+
"@types/node": "26.6.4",
|
|
50
|
+
"@unthrown/vitest": "5.12.0",
|
|
51
|
+
"@vitest/coverage-v8": "5.0.3",
|
|
52
|
+
"graphql": "17.0.2",
|
|
53
|
+
"graphql-yoga": "5.24.1",
|
|
54
|
+
"tsdown": "0.23.0",
|
|
55
|
+
"typescript": "7.0.2",
|
|
56
|
+
"typescript-consumer": "npm:typescript@5.9.3",
|
|
57
|
+
"unthrown": "5.12.0",
|
|
58
|
+
"vitest": "5.0.3"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"@btravstack/contract": "^0.21.0",
|
|
62
|
+
"@btravstack/di": "^0.21.0",
|
|
63
|
+
"@btravstack/http-server": "^0.21.0",
|
|
64
|
+
"graphql": "^16.0.0 || ^17.0.0",
|
|
65
|
+
"graphql-yoga": "^5.24.1",
|
|
66
|
+
"unthrown": "^5.7.0"
|
|
67
|
+
},
|
|
68
|
+
"engines": {
|
|
69
|
+
"node": ">=22.15"
|
|
70
|
+
},
|
|
71
|
+
"scripts": {
|
|
72
|
+
"build": "tsdown src/index.ts --format cjs,esm --dts --clean",
|
|
73
|
+
"dev": "tsdown src/index.ts --format cjs,esm --dts --watch",
|
|
74
|
+
"test": "vitest run --coverage",
|
|
75
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test-d.json && node ./node_modules/typescript-consumer/bin/tsc --noEmit -p tsconfig.test-d.json"
|
|
76
|
+
}
|
|
6
77
|
}
|