@nxara/olio-http 0.1.1 → 0.1.2

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 CHANGED
@@ -1,224 +1,11 @@
1
1
  # @nxara/olio-http
2
2
 
3
- Serve an olio app over HTTP, on any framework: GraphQL over HTTP ([graphql-http](https://github.com/graphql/graphql-http), the reference implementation), with `context`, error masking and per-operation cleanup. Nothing more: subscriptions are yours to serve, with the libraries you choose (below).
3
+ Serve an olio app over HTTP, from any framework, on graphql-http: Fetch and Node adapters with `context`, error masking and per-operation cleanup.
4
4
 
5
5
  ```sh
6
6
  bun add @nxara/olio-http graphql@16
7
7
  ```
8
8
 
9
- `graphql` 16 is a peer dependency; graphql-http is its only third-party dependency.
9
+ **[Read the docs](https://olio.nxara.dev/reference/http/)**
10
10
 
11
- ## Adapters
12
-
13
- | Import | For |
14
- | --- | --- |
15
- | `@nxara/olio-http/fetch` | Anything that speaks the Fetch API: Hono, Elysia, Bun.serve, Deno, Cloudflare Workers, Next.js route handlers, SvelteKit, Remix |
16
- | `@nxara/olio-http/node` | Node's `IncomingMessage` / `ServerResponse`: `node:http`, Express, Connect, Koa (`ctx.req`, `ctx.res`), Fastify (`request.raw`, `reply.raw`) |
17
-
18
- Your `context` hook receives the framework's request: a Fetch `Request`, or a Node `IncomingMessage`. Once your app registers a `ctx` type (`interface Olio { ctx: … }`), the hook is required: without it graphql-http passes no context, and every resolver reading `ctx` would fail at runtime. So `fetchHandler(app)` is then a compile error (`Expected 2 arguments`), as is an options object without `context`.
19
-
20
- ```ts
21
- import { fetchHandler } from "@nxara/olio-http/fetch";
22
-
23
- const graphql = fetchHandler(app, {
24
- context: (request) => createContext(request.headers.get("authorization")),
25
- onOperationEnd: (ctx) => ctx.di.dispose()
26
- });
27
-
28
- hono.on(["GET", "POST"], "/graphql", (c) => graphql(c.req.raw)); // Hono
29
- Bun.serve({ fetch: graphql }); // Bun
30
- ```
31
-
32
- ```ts
33
- import { nodeHandler } from "@nxara/olio-http/node";
34
-
35
- const graphql = nodeHandler(app, {
36
- context: (req) => createContext(req.headers.authorization)
37
- });
38
- expressApp.all("/graphql", (req, res) => graphql(req, res)); // or: createServer(graphql)
39
- ```
40
-
41
- ## Subscriptions
42
-
43
- Not included, the way Apollo Server leaves them out: install and run the reference libraries yourself, at the versions you want, next to the HTTP handler.
44
-
45
- - [graphql-ws](https://github.com/enisdenjo/graphql-ws): subscriptions over WebSocket (`useServer` on a `ws` server, `makeHandler` on Bun).
46
- - [graphql-sse](https://github.com/enisdenjo/graphql-sse): subscriptions as server-sent events, on the same URL (route `Accept: text/event-stream` to its handler).
47
-
48
- Pass them `app.schema`; `errorMasker` hides their unexpected errors the way the HTTP handler does, and `validateOperation` applies its rules. Both, with a context (and DI scope) per subscription, disposed when it ends:
49
-
50
- ```ts
51
- import type { SubscriptionContext } from "@nxara/olio";
52
- import { errorMasker, validateOperation } from "@nxara/olio-http";
53
- import { createHandler } from "graphql-sse/lib/use/fetch";
54
- import { useServer } from "graphql-ws/use/ws";
55
-
56
- const mask = errorMasker<SubscriptionContext>();
57
-
58
- // graphql-sse: route requests with `Accept: text/event-stream` here, GET and
59
- // POST (what @nxara/olio-client sends; single-connection mode also needs PUT and DELETE).
60
- export const sseHandler = createHandler({
61
- schema: app.schema,
62
- context: (req) =>
63
- createContext(req.raw.headers.get("authorization")) as never,
64
- onSubscribe: (_req, params) => {
65
- const errors = validateOperation(app.schema, params, validationRules);
66
- return errors.length ? { data: null, errors: [...errors] } : undefined; // needs `data`
67
- },
68
- onNext: (ctx, _req, result) =>
69
- mask.result(result, ctx as unknown as SubscriptionContext),
70
- onComplete: (ctx) => (ctx as unknown as SubscriptionContext).di.dispose()
71
- });
72
-
73
- // graphql-ws, on a `ws` server: `context` runs once per subscription, so the
74
- // scope is per operation; keep it by connection and id to end it.
75
- const live = new WeakMap<object, Map<string, SubscriptionContext>>();
76
- useServer(
77
- {
78
- schema: app.schema,
79
- context: (ctx, id) => {
80
- // A browser can't set WebSocket headers: @nxara/olio-client sends them here.
81
- const headers = ctx.connectionParams?.headers as
82
- | Record<string, string>
83
- | undefined;
84
- const value = createContext(headers?.authorization);
85
- live.set(ctx, (live.get(ctx) ?? new Map()).set(id, value));
86
- return value as never;
87
- },
88
- onSubscribe: (_ctx, _id, payload) => {
89
- const errors = validateOperation(app.schema, payload, validationRules);
90
- return errors.length ? errors : undefined;
91
- },
92
- onNext: (ctx, id, _payload, _args, result) =>
93
- mask.result(result, live.get(ctx)?.get(id)),
94
- onError: (ctx, id, _payload, errors) =>
95
- errors.map((e) => mask.error(e, live.get(ctx)?.get(id)).toJSON()),
96
- // Also runs when the socket closes mid-subscription (see the note below).
97
- onComplete: async (ctx, id) => {
98
- const value = live.get(ctx)?.get(id);
99
- live.get(ctx)?.delete(id);
100
- await value?.di.dispose();
101
- }
102
- },
103
- new WebSocketServer({ server, path: "/graphql" })
104
- );
105
- ```
106
-
107
- When a socket closes, graphql-ws ends each live subscription and waits for it before `onComplete`. A resolver that's an `async *` waiting inside `for await` can only end at its next event, so until one arrives, nothing is cleaned up. Return the event source's own iterator instead (olio's README, [Subscriptions](../olio/README.md#subscriptions)).
108
-
109
- With `@hono/node-server`, `serve()` is typed to return HTTP/2 servers too: pass `server as Server` (from `node:http`) to `WebSocketServer`. [`apps/example-server/src/subscriptions.ts`](../../apps/example-server/src/subscriptions.ts) is all of this, running. For tests, `testClient` from `@nxara/olio-client/test` runs these same options and handler in memory, so export them (the example exports `wsOptions` and `sseHandler`).
110
-
111
- ## Refusing a bad token
112
-
113
- Don't throw from `context`. A throw there refuses the whole request before any field runs, so a client still holding an expired token can't even call `login` to get a new one. Build a context without a user instead, and refuse in middleware; public fields skip it with `@bypass` (olio's README, [Skipping middleware](../olio/README.md#skipping-middleware-bypass)):
114
-
115
- ```ts
116
- fetchHandler(app, {
117
- // An invalid or expired token gives `userId: undefined`, not an error.
118
- context: (request) => ({
119
- userId: verify(request.headers.get("authorization"))
120
- })
121
- });
122
-
123
- const requireAuth =
124
- (): MiddlewareFn =>
125
- ({ ctx, bypass }, next) => {
126
- if (!ctx.userId && !bypass.has("auth")) throw unauthenticated();
127
- return next();
128
- };
129
- ```
130
-
131
- It's also the only way that gives clients the same `UNAUTHENTICATED` result, at once, on every transport. Over subscriptions, a `context` that throws is a server error to both libraries: graphql-ws closes the socket with 4500 (the error's code is lost), graphql-sse's handler throws (your framework answers 500). Refusing the socket in graphql-ws's `onConnect` closes it with 4403, which graphql-ws's client retries by default ([@nxara/olio-client](../client/README.md#subscriptions)).
132
-
133
- ## Validation rules
134
-
135
- `validationRules` run with graphql's own, before any resolver: a cost or depth limit, say. They're added to graphql's rules, never in their place. Pass a list, or a function of the operation (`{ variables, operationName }`) for rules that need its variables, like [graphql-query-complexity](https://github.com/slicknode/graphql-query-complexity) pricing a page by its size:
136
-
137
- ```ts
138
- import {
139
- createComplexityRule,
140
- fieldExtensionsEstimator,
141
- simpleEstimator
142
- } from "graphql-query-complexity";
143
-
144
- fetchHandler(app, {
145
- context,
146
- validationRules: ({ variables }) => [
147
- createComplexityRule({
148
- maximumComplexity: 1000,
149
- variables,
150
- estimators: [
151
- fieldExtensionsEstimator(),
152
- simpleEstimator({ defaultComplexity: 1 })
153
- ]
154
- })
155
- ]
156
- });
157
- ```
158
-
159
- `fieldExtensionsEstimator` reads each field's `complexity` extension, which olio sets from the resolver's `{ resolve, extensions }`. An operation over the limit gets the rule's error, and nothing runs.
160
-
161
- Subscription servers take the same rules through `validateOperation(schema, operation, rules)` in their `onSubscribe`; it returns the errors (none when the operation is valid):
162
-
163
- ```ts
164
- import { validateOperation } from "@nxara/olio-http";
165
-
166
- // graphql-ws
167
- onSubscribe: (_ctx, _id, payload) => {
168
- const errors = validateOperation(app.schema, payload, validationRules);
169
- return errors.length ? errors : undefined;
170
- };
171
- // graphql-sse: a result needs `data` to be read as one
172
- onSubscribe: (_req, params) => {
173
- const errors = validateOperation(app.schema, params, validationRules);
174
- return errors.length ? { data: null, errors: [...errors] } : undefined;
175
- };
176
- ```
177
-
178
- ## Errors
179
-
180
- Only `GraphQLError`s reach clients. Anything else that's thrown, such as a failing database or a bug, is replaced by `"Unexpected error."` and passed to `onUnexpectedError` (default: `console.error`), so it isn't lost. That includes a `context` hook that throws: a `GraphQLError` from it (say, `BAD_REQUEST` for a malformed header) reaches the client as a normal GraphQL error with status 200; anything else is a 500 with "Unexpected error.". It refuses the whole request, so a bad token belongs in middleware instead ([Refusing a bad token](#refusing-a-bad-token)).
181
-
182
- ```ts
183
- throw new GraphQLError("Forbidden", { extensions: { code: "FORBIDDEN" } }); // the client sees this
184
- throw new Error("connection refused"); // the client sees "Unexpected error."
185
- ```
186
-
187
- `onUnexpectedError(error, { ctx, request })` gets what the error happened in, so logs can tie it to a request: `ctx` is the operation's context (`undefined` when the `context` hook itself failed), `request` the adapter's (a Fetch `Request`, or Node's `IncomingMessage`).
188
-
189
- ```ts
190
- fetchHandler(app, {
191
- context,
192
- onUnexpectedError: (error, { ctx, request }) =>
193
- log.error({ error, requestId: ctx?.requestId, url: request.url })
194
- });
195
- ```
196
-
197
- `errorMasker(options?)`, from `@nxara/olio-http`, is the same masking for your own subscription servers. It takes the handlers' `maskErrors` and `onUnexpectedError` (both optional), and gives the functions below. Each takes the operation's context as a last argument, which `onUnexpectedError` receives as `ctx` (`request` is `undefined` there); type it with `errorMasker<SubscriptionContext>()`:
198
-
199
- | | |
200
- | --- | --- |
201
- | `mask.result(result, ctx?)` | The result with its errors masked, any shape: graphql's `ExecutionResult`, or what graphql-sse's and graphql-ws's `onNext` hand you |
202
- | `mask.error(error, ctx?)` | One error, or any caught value: a `GraphQLError` passes (unless it wraps an unexpected error), anything else becomes "Unexpected error." and is reported |
203
- | `mask.report(error, ctx?)` | Sends an error to `onUnexpectedError` |
204
-
205
- ```ts
206
- import { errorMasker } from "@nxara/olio-http";
207
-
208
- const mask = errorMasker<SubscriptionContext>();
209
- createHandler({
210
- schema: app.schema,
211
- onNext: (ctx, _req, result) => mask.result(result, ctx)
212
- }); // graphql-sse
213
- ```
214
-
215
- ## Options
216
-
217
- | Option | Default | |
218
- | --- | --- | --- |
219
- | `context` | none | Builds `ctx` from the request. Required once the app registers a `ctx` type |
220
- | `validationRules` | none | Rules run with graphql's own before execution: a list, or `({ variables, operationName }) => rules`. See [Validation rules](#validation-rules) |
221
- | `onOperationEnd` | none | Called once per operation, after the response is built. Release per-operation resources here, e.g. `(ctx) => ctx.di.dispose()`. A failure in it goes to `onUnexpectedError` |
222
- | `maskErrors` | `true` | Hide errors that aren't `GraphQLError`s. Turn off only while developing |
223
- | `onUnexpectedError` | `console.error` of the error | `(error, { ctx, request }) => void`: receives each hidden error, with the context and request it happened in (`ctx` is `undefined` when the `context` hook failed) |
224
- | graphql-http's own | its defaults | `execute`, `parse`, `validate`, `getOperationAST`, `rootValue`, `formatError` (runs after masking) and `parseRequestParams` (e.g. persisted queries: map an id to its stored query) go to [graphql-http](https://github.com/graphql/graphql-http) as they are. Not `onSubscribe`: operation args returned from it would skip `context` and every validation rule |
11
+ Part of [olio](https://olio.nxara.dev): modular, type-safe GraphQL for TypeScript. MIT licensed.
package/dist/node.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import type { IncomingMessage, ServerResponse } from "node:http";
2
- import type { OperationContext } from "graphql-http";
3
- import { type HandlerOptions } from "graphql-http/lib/use/http";
2
+ import { type OperationContext } from "graphql-http";
3
+ import type { HandlerOptions } from "graphql-http/lib/use/http";
4
4
  import { type GraphQLHttpOptions, type OptionsArgs, type Servable } from "./core.js";
5
5
  type Passed = GraphQLHttpOptions<HandlerOptions<OperationContext>>;
6
- export declare function nodeHandler(app: Servable, ...[options]: OptionsArgs<IncomingMessage, Passed>): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
6
+ export declare function nodeHandler(app: Servable, ...[options]: OptionsArgs<IncomingMessage, Passed>): (req: IncomingMessage, res: ServerResponse, body?: unknown) => Promise<void>;
7
7
  export {};
8
8
  //# sourceMappingURL=node.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE/E,OAAO,EAML,KAAK,kBAAkB,EAEvB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACd,MAAM,WAAW,CAAC;AAEnB,KAAK,MAAM,GAAG,kBAAkB,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAGnE,wBAAgB,WAAW,CACzB,GAAG,EAAE,QAAQ,EACb,GAAG,CAAC,OAAoD,CAAC,EAAE,WAAW,CACpE,eAAe,EACf,MAAM,CACP,GACA,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CA4B9D"}
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGjE,OAAO,EAAiB,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,2BAA2B,CAAC;AAEhF,OAAO,EAML,KAAK,kBAAkB,EAEvB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACd,MAAM,WAAW,CAAC;AAEnB,KAAK,MAAM,GAAG,kBAAkB,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAiBnE,wBAAgB,WAAW,CACzB,GAAG,EAAE,QAAQ,EACb,GAAG,CAAC,OAAoD,CAAC,EAAE,WAAW,CACpE,eAAe,EACf,MAAM,CACP,GACA,CACD,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,IAAI,CAAC,EAAE,OAAO,KACX,OAAO,CAAC,IAAI,CAAC,CAqDjB"}
package/dist/node.js CHANGED
@@ -1,5 +1,12 @@
1
- import { createHandler } from "graphql-http/lib/use/http";
1
+ import { createHandler } from "graphql-http";
2
2
  import { contextFailure, masking, operationEnd, handlerRules } from "./core.js";
3
+ const readBody = (req) => new Promise((resolve, reject) => {
4
+ let body = "";
5
+ req.setEncoding("utf8");
6
+ req.on("data", (chunk) => (body += chunk));
7
+ req.on("end", () => resolve(body));
8
+ req.on("error", reject);
9
+ });
3
10
  export function nodeHandler(app, ...[options = {}]) {
4
11
  const mask = masking(options);
5
12
  const { context } = options;
@@ -23,8 +30,24 @@ export function nodeHandler(app, ...[options = {}]) {
23
30
  validationRules: handlerRules(options.validationRules),
24
31
  onOperation: (req, _args, result) => mask.result(result, { ctx: contexts.get(req.raw), request: req.raw })
25
32
  });
26
- return async (req, res) => {
27
- await http(req, res);
33
+ return async (req, res, body) => {
34
+ const parsed = typeof body === "function"
35
+ ? req.body
36
+ : (body ?? req.body);
37
+ if (parsed === undefined && req.readableEnded) {
38
+ mask.report(new Error("nodeHandler: the request body was already read, by a body parser? Pass the parsed body as the third argument: graphql(req, res, body)."), { ctx: undefined, request: req });
39
+ res.writeHead(500).end();
40
+ return;
41
+ }
42
+ const [payload, init] = await http({
43
+ url: req.url ?? "/",
44
+ method: req.method ?? "GET",
45
+ headers: req.headers,
46
+ body: parsed === undefined ? () => readBody(req) : parsed,
47
+ raw: req,
48
+ context: { res }
49
+ });
50
+ res.writeHead(init.status, init.statusText, init.headers).end(payload);
28
51
  await end(contexts.get(req), req);
29
52
  };
30
53
  }
package/dist/node.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAuB,MAAM,2BAA2B,CAAC;AAE/E,OAAO,EACL,cAAc,EACd,OAAO,EACP,YAAY,EACZ,YAAY,EAMb,MAAM,WAAW,CAAC;AAKnB,MAAM,UAAU,WAAW,CACzB,GAAa,EACb,GAAG,CAAC,OAAO,GAAG,EAA0C,CAGvD;IAED,MAAM,IAAI,GAAG,OAAO,CAA6B,OAAO,CAAC,CAAC;IAC1D,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAC5B,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IAEvD,MAAM,QAAQ,GAAG,IAAI,OAAO,EAA4B,CAAC;IACzD,MAAM,IAAI,GAAG,aAAa,CAAC;QACzB,GAAG,OAAO;QACV,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,OAAO,EAAE,OAAO;YACd,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;gBACZ,IAAI,CAAC;oBACH,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;oBACnC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;oBAC3B,OAAO,GAAY,CAAC;gBACtB,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,cAAc,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;gBAC9C,CAAC;YACH,CAAC;YACH,CAAC,CAAC,SAAS;QACb,eAAe,EAAE,YAAY,CAAC,OAAO,CAAC,eAAe,CAAC;QACtD,WAAW,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,CAClC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC;KACxE,CAAC,CAAC;IACH,OAAO,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QACxB,MAAM,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACrB,MAAM,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;IACpC,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAyB,MAAM,cAAc,CAAC;AAGpE,OAAO,EACL,cAAc,EACd,OAAO,EACP,YAAY,EACZ,YAAY,EAMb,MAAM,WAAW,CAAC;AAInB,MAAM,QAAQ,GAAG,CAAC,GAAoB,EAAmB,EAAE,CACzD,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IAC9B,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IACxB,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC;IACnD,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACnC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAC1B,CAAC,CAAC,CAAC;AAQL,MAAM,UAAU,WAAW,CACzB,GAAa,EACb,GAAG,CAAC,OAAO,GAAG,EAA0C,CAGvD;IAMD,MAAM,IAAI,GAAG,OAAO,CAA6B,OAAO,CAAC,CAAC;IAC1D,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAC5B,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IAEvD,MAAM,QAAQ,GAAG,IAAI,OAAO,EAA4B,CAAC;IACzD,MAAM,IAAI,GAAG,aAAa,CACxB;QACE,GAAG,OAAO;QACV,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,OAAO,EAAE,OAAO;YACd,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;gBACZ,IAAI,CAAC;oBACH,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;oBACnC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;oBAC3B,OAAO,GAAY,CAAC;gBACtB,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,cAAc,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;gBAC9C,CAAC;YACH,CAAC;YACH,CAAC,CAAC,SAAS;QACb,eAAe,EAAE,YAAY,CAAC,OAAO,CAAC,eAAe,CAAC;QACtD,WAAW,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,CAClC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC;KACxE,CACF,CAAC;IACF,OAAO,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAE9B,MAAM,MAAM,GACV,OAAO,IAAI,KAAK,UAAU;YACxB,CAAC,CAAE,GAA0B,CAAC,IAAI;YAClC,CAAC,CAAC,CAAC,IAAI,IAAK,GAA0B,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,MAAM,KAAK,SAAS,IAAI,GAAG,CAAC,aAAa,EAAE,CAAC;YAC9C,IAAI,CAAC,MAAM,CACT,IAAI,KAAK,CACP,wIAAwI,CACzI,EACD,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,CACjC,CAAC;YACF,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;YACzB,OAAO;QACT,CAAC;QACD,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC;YACjC,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG;YACnB,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,KAAK;YAC3B,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,IAAI,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,MAAgB;YACpE,GAAG,EAAE,GAAG;YACR,OAAO,EAAE,EAAE,GAAG,EAAE;SACjB,CAAC,CAAC;QACH,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACvE,MAAM,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;IACpC,CAAC,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxara/olio-http",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Serve an olio app over HTTP, on any framework: GraphQL over HTTP with context, error masking and per-operation cleanup.",
5
5
  "keywords": [
6
6
  "graphql",
@@ -42,11 +42,11 @@
42
42
  "check-types": "tsc -p tsconfig.test.json"
43
43
  },
44
44
  "dependencies": {
45
- "@nxara/olio-core": "0.1.1",
45
+ "@nxara/olio-core": "0.1.2",
46
46
  "graphql-http": "^1.23.1"
47
47
  },
48
48
  "devDependencies": {
49
- "@nxara/olio": "0.1.1",
49
+ "@nxara/olio": "0.1.2",
50
50
  "graphql": "^16.14.2"
51
51
  },
52
52
  "peerDependencies": {