@nxgt/janus-graphql 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +110 -24
- package/dist/connection/connection.d.ts +36 -0
- package/dist/connection/connection.d.ts.map +1 -0
- package/dist/connection/credential.d.ts +34 -0
- package/dist/connection/credential.d.ts.map +1 -0
- package/dist/connection/types.d.ts +57 -0
- package/dist/connection/types.d.ts.map +1 -0
- package/dist/context.d.ts +10 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/errors.d.ts +26 -3
- package/dist/errors.d.ts.map +1 -1
- package/dist/index.d.ts +10 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +173 -30
- package/dist/index.js.map +12 -7
- package/dist/options.d.ts +17 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/plugin.d.ts +16 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/renewal.d.ts +30 -0
- package/dist/renewal.d.ts.map +1 -0
- package/dist/report.d.ts +22 -0
- package/dist/report.d.ts.map +1 -0
- package/dist/types.d.ts +6 -2
- package/dist/types.d.ts.map +1 -1
- package/docs/README.md +4 -3
- package/docs/guide/context.md +34 -3
- package/docs/guide/errors.md +68 -4
- package/docs/guide/step-up.md +7 -3
- package/docs/guide/subscriptions.md +255 -0
- package/docs/roadmap.md +29 -8
- package/docs/troubleshooting.md +130 -9
- package/package.json +12 -3
package/README.md
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
[`@nxgt/janus`](https://www.npmjs.com/package/@nxgt/janus) in a GraphQL
|
|
4
4
|
server: the signed-in user on the context, authenticated only when a field
|
|
5
5
|
asks, fields and types guarded by `@authenticated`, `@fresh` and
|
|
6
|
-
`@permission`,
|
|
7
|
-
|
|
8
|
-
as 401, 403 or 404.
|
|
6
|
+
`@permission`, the
|
|
7
|
+
same guards on subscriptions over graphql-ws, and every error answered with
|
|
8
|
+
the status it deserves — an outage as 503, never as 401, 403 or 404.
|
|
9
9
|
|
|
10
10
|
An [envelop](https://the-guild.dev/graphql/envelop) plugin, so it runs in
|
|
11
11
|
[GraphQL Yoga](https://the-guild.dev/graphql/yoga-server) and any server built
|
|
@@ -52,7 +52,7 @@ bun add @nxgt/janus-graphql @nxgt/janus graphql @graphql-tools/utils @envelop/co
|
|
|
52
52
|
bun add -d typescript # 6
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
Every peer is required
|
|
55
|
+
Every peer is required but `graphql-ws`:
|
|
56
56
|
|
|
57
57
|
| Peer | Range | Why |
|
|
58
58
|
| --- | --- | --- |
|
|
@@ -61,11 +61,12 @@ Every peer is required:
|
|
|
61
61
|
| `@graphql-tools/utils` | `>=10.0.0 <13` | `mapSchema` and `getDirective`, which apply the directives |
|
|
62
62
|
| `@envelop/core` | `^5.0.0` | Types only — the `Plugin` `useJanus()` answers. Yoga already brings it |
|
|
63
63
|
| `typescript` | `^6.0.3` | As for `@nxgt/janus` |
|
|
64
|
+
| `graphql-ws` | `^6.0.0`, **optional** | Only for subscriptions over a WebSocket, with `janusConnection()`. Nothing here imports it. For `graphql` 17, a `graphql-ws` whose peer range includes it — 6.3.0 does |
|
|
64
65
|
|
|
65
66
|
The floors are tested, not claimed: the package's specs and its typecheck run
|
|
66
|
-
on `graphql` 16.9.0, `@graphql-tools/utils` 10.0.0
|
|
67
|
-
as well, together, with a single copy of `graphql`,
|
|
68
|
-
every CI run.
|
|
67
|
+
on `graphql` 16.9.0, `@graphql-tools/utils` 10.0.0, `@envelop/core` 5.0.0
|
|
68
|
+
and `graphql-ws` 6.0.0 as well, together, with a single copy of `graphql`,
|
|
69
|
+
in the Floors job, on every CI run.
|
|
69
70
|
|
|
70
71
|
Like `@nxgt/janus`, it expects `"moduleResolution": "bundler"`: the
|
|
71
72
|
declarations import without extensions, so `nodenext` is not supported.
|
|
@@ -78,7 +79,7 @@ that reads files — `node_modules/@nxgt/janus-graphql/graphql/janus.graphqls`.
|
|
|
78
79
|
|
|
79
80
|
| Export | What it is |
|
|
80
81
|
| --- | --- |
|
|
81
|
-
| `useJanus({ auth, access?, type?, clock?, loaders?, conditions? })` | The envelop plugin. Adds `ctx.janus` to every request's context, and applies the directives to every schema the server is given, once. `type` treats a user of any other type as anonymous. `clock` is what `@fresh` and `requireFresh()` read — the one given to `janus()`, when it is not the system's. `loaders` and `conditions` are what `@permission` needs beside `access` |
|
|
82
|
+
| `useJanus({ auth, access?, type?, clock?, loaders?, conditions? })` | The envelop plugin. Adds `ctx.janus` to every request's context, and applies the directives to every schema the server is given, once. `type` treats a user of any other type as anonymous. `clock` is what `@fresh` and `requireFresh()` read — the one given to `janus()`, when it is not the system's. `loaders` and `conditions` are what `@permission` needs beside `access`. Under Yoga, a session `authenticate` renewed is sent again as `Set-Cookie` on the response, to a request that presented it as the cookie |
|
|
82
83
|
| `ctx.janus.user()`, `ctx.janus.session()` | Who the request belongs to, and the session it presented — `null` for an anonymous request. `auth.authenticate(request)` runs the first time either is asked, once per request, and never when neither is |
|
|
83
84
|
| `ctx.janus.access` | The `permissions()` instance given to `useJanus()`. Absent from the type — and from the context — without one |
|
|
84
85
|
| `janusTypeDefs` | The SDL: `@authenticated`, `@fresh`, `@permission` and the `JanusPermissionDenial` enum — prefixed, so it never collides with a type of your schema. The same text as `graphql/janus.graphqls` |
|
|
@@ -91,11 +92,12 @@ that reads files — `node_modules/@nxgt/janus-graphql/graphql/janus.graphqls`.
|
|
|
91
92
|
| `requireUser(ctx, { type? })` | The signed-in user, narrowed to `type` — one or a non-empty list — or a denial: `UNAUTHENTICATED`, `FORBIDDEN` |
|
|
92
93
|
| `requireFresh(ctx, maxAge)` | The request's session, once it proved who it is less than `maxAge` ago — a duration with its unit, `'10m'`, never a bare number — or a denial: `UNAUTHENTICATED`, `STEP_UP_REQUIRED` |
|
|
93
94
|
| `can(ctx, permission, object, options?)` | `access.can` for the request's user, typed as `access.can` is. Anonymous answers `false`. Shares the request's checks with `@permission`: one question, one check per request |
|
|
94
|
-
| `
|
|
95
|
+
| `janusConnection({ auth, access?, type?, clock?, upgrade? })` | Subscriptions over graphql-ws: `onConnect` for its `useServer()`, which accepts a connection whose `connectionParams.authorization` — else whose upgrade request's headers or cookie — authenticates, as a user of `type` when given, and refuses any other `4403`; an outage rejects, closed `4500`. Each operation's `ctx.janus` then authenticates from that credential, so the directives hold unchanged. `context` builds `{ janus }` for a server without Yoga; `upgrade` reads the upgrade request where the transport's `extra` does not carry it — Bun |
|
|
96
|
+
| `janusMaskError({ report?, fallback? })` | Yoga's `maskedErrors.maskError`: a `JanusError` a resolver let through answered with its code and status; anything else to `fallback`. `report` is called once with every `JanusError` answered 5xx — a directive's and a helper's too — and cannot change the answer. `janusMaskError(fallback)`, the fallback alone, still works |
|
|
95
97
|
| `janusGraphQLError(error)` | A `JanusError` as the `GraphQLError` the client reads: its code, its status, and only what the client can act on |
|
|
96
98
|
| `denial(code, message?)` | A denial of your own: `UNAUTHENTICATED` 401, `FORBIDDEN` 403, `NOT_FOUND` 404. For a stale session, call `requireFresh()`, whose `STEP_UP_REQUIRED` is `@nxgt/janus`'s |
|
|
97
99
|
| `JanusContext<typeof auth, typeof access?, Type?>` | What `useJanus()` adds to the context, for your resolvers' `ctx` |
|
|
98
|
-
| `JanusOptions`, `JanusOnContext`, `JanusDirectivesOptions`, `Loaders`, `Conditions`, `LoadedObject`, `RequireUserOptions`, `Auth`, `UserOfAuth`, `DenialCode`, `MaskError` | The types of the arguments and answers above |
|
|
100
|
+
| `JanusOptions`, `JanusOnContext`, `JanusConnectionOptions`, `JanusConnection`, `ConnectionContext`, `JanusDirectivesOptions`, `Loaders`, `Conditions`, `LoadedObject`, `RequireUserOptions`, `Auth`, `UserOfAuth`, `DenialCode`, `MaskError`, `JanusMaskErrorOptions` | The types of the arguments and answers above |
|
|
99
101
|
|
|
100
102
|
## Directives
|
|
101
103
|
|
|
@@ -145,6 +147,46 @@ model does not declare, a malformed `id:`, an argument the field does not
|
|
|
145
147
|
take, a missing loader or condition, a `maxAge` not above zero — is a
|
|
146
148
|
`TypeError` at start-up naming the field. Detail: [the directives guide](docs/guide/directives.md).
|
|
147
149
|
|
|
150
|
+
## Subscriptions over graphql-ws
|
|
151
|
+
|
|
152
|
+
Yoga's recommended graphql-ws setup, with `onConnect` added:
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import { janusConnection } from '@nxgt/janus-graphql';
|
|
156
|
+
import { useServer } from 'graphql-ws/use/ws';
|
|
157
|
+
|
|
158
|
+
useServer(
|
|
159
|
+
{
|
|
160
|
+
onConnect: janusConnection({ auth }).onConnect, // no valid session: closed 4403
|
|
161
|
+
execute: (args: any) => args.rootValue.execute(args),
|
|
162
|
+
subscribe: (args: any) => args.rootValue.subscribe(args),
|
|
163
|
+
onSubscribe: async (ctx, _id, params) => {
|
|
164
|
+
const { schema, execute, subscribe, contextFactory, parse, validate } =
|
|
165
|
+
yoga.getEnveloped({ ...ctx, req: ctx.extra.request, socket: ctx.extra.socket, params });
|
|
166
|
+
const args = {
|
|
167
|
+
schema,
|
|
168
|
+
operationName: params.operationName,
|
|
169
|
+
document: parse(params.query),
|
|
170
|
+
variableValues: params.variables,
|
|
171
|
+
contextValue: await contextFactory(), // useJanus() finds the connection by ctx.extra
|
|
172
|
+
rootValue: { execute, subscribe },
|
|
173
|
+
};
|
|
174
|
+
const errors = validate(args.schema, args.document);
|
|
175
|
+
return errors.length ? errors : args;
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
wsServer,
|
|
179
|
+
);
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
A browser's session cookie travels on the upgrade request; any other client
|
|
183
|
+
sends `connectionParams: { authorization: 'Bearer <token>' }`, which is
|
|
184
|
+
read first. Each operation is authenticated again from that credential
|
|
185
|
+
when it subscribes: `@authenticated` and `@fresh` are checked then, and
|
|
186
|
+
`@permission` on every event. A session revoked mid-stream is refused at
|
|
187
|
+
the next subscribe, not at the next event. Detail, Bun, and a server
|
|
188
|
+
without Yoga: [the subscriptions guide](docs/guide/subscriptions.md).
|
|
189
|
+
|
|
148
190
|
## Errors
|
|
149
191
|
|
|
150
192
|
This package defines **no error class**. A denial is a `GraphQLError`, and
|
|
@@ -170,6 +212,25 @@ else — never `reason`, `login`, a hash prefix or a cause. The message is a
|
|
|
170
212
|
fixed one per status, never the core's: read `code`. Detail, and the status of a
|
|
171
213
|
response with several errors: [the errors guide](docs/guide/errors.md).
|
|
172
214
|
|
|
215
|
+
The message carries nothing of the store's, and a directive answers an
|
|
216
|
+
outage itself, before any resolver of yours could log it. `report` sees
|
|
217
|
+
every `JanusError` answered 5xx, once, whichever path it took:
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
import { maskError } from 'graphql-yoga';
|
|
221
|
+
|
|
222
|
+
createYoga({
|
|
223
|
+
schema,
|
|
224
|
+
plugins: [useJanus({ auth, access })],
|
|
225
|
+
maskedErrors: {
|
|
226
|
+
maskError: janusMaskError({
|
|
227
|
+
report: (error) => logger.error({ code: error.code, cause: error.cause }), // slot, operation: which call failed
|
|
228
|
+
fallback: maskError, // Yoga's own, for everything else
|
|
229
|
+
}),
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
```
|
|
233
|
+
|
|
173
234
|
## Traps
|
|
174
235
|
|
|
175
236
|
- **Without `janusMaskError()`, a `JanusError` from a resolver is Yoga's
|
|
@@ -187,10 +248,16 @@ response with several errors: [the errors guide](docs/guide/errors.md).
|
|
|
187
248
|
the highest `extensions.http.status` among the errors, so `{ open me }`
|
|
188
249
|
from an anonymous request is a 401 whose `data` still holds `open`. A client
|
|
189
250
|
reads `data` and `errors`, not only the status.
|
|
190
|
-
- **A renewed session is
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
251
|
+
- **A renewed session is sent back only on an HTTP response from Yoga.**
|
|
252
|
+
`useJanus()` sets it in Yoga's `onResponse`, which a server on envelop
|
|
253
|
+
alone never calls; and an operation over graphql-ws has no response at
|
|
254
|
+
all. There, `ctx.janus` still renews the session in the store, but the
|
|
255
|
+
browser keeps the cookie with its old expiry until the next renewal over
|
|
256
|
+
HTTP, a `renewAfter` later: a browser whose only traffic is the WebSocket
|
|
257
|
+
should renew through an HTTP route of yours.
|
|
258
|
+
- **An `auth` of your own needs `cookie` for the renewal.** A wrapper that
|
|
259
|
+
passes on only `authenticate` and `types` sends no renewed cookie; pass
|
|
260
|
+
`cookie: auth.cookie` along.
|
|
194
261
|
- **`useJanus({ type })` narrows the whole server.** A user of any other type
|
|
195
262
|
is anonymous everywhere, and a directive naming another type is refused
|
|
196
263
|
when the schema is built.
|
|
@@ -218,8 +285,19 @@ response with several errors: [the errors guide](docs/guide/errors.md).
|
|
|
218
285
|
on every one, and one denial denies the field; to answer only the items a
|
|
219
286
|
user may see, ask `access.list()` for their ids.
|
|
220
287
|
- **A context built without a request cannot authenticate.** `ctx.janus.user()`
|
|
221
|
-
rejects with a `TypeError` — a transport that is not HTTP,
|
|
222
|
-
|
|
288
|
+
rejects with a `TypeError` — a transport that is not HTTP, or a graphql-ws
|
|
289
|
+
operation whose connection no `janusConnection().onConnect` accepted, or
|
|
290
|
+
whose context was built without Yoga's `...ctx` spread, which carries
|
|
291
|
+
`ctx.extra`.
|
|
292
|
+
- **A session revoked while a socket is open keeps its running streams.**
|
|
293
|
+
An operation authenticates once, when it subscribes, and each event's
|
|
294
|
+
`@authenticated` reads that answer; the next subscribe, and a
|
|
295
|
+
reconnection, are refused. Close the
|
|
296
|
+
socket yourself to cut it at once. `@permission` sees a `revoke()` at the
|
|
297
|
+
next event.
|
|
298
|
+
- **Bun's graphql-ws `extra` holds no request.** Without
|
|
299
|
+
`janusConnection({ upgrade })`, a browser's cookie is never read there,
|
|
300
|
+
and only `connectionParams` authenticates.
|
|
223
301
|
- **`@fresh` reads seconds; `requireFresh()` a duration.** `@fresh(maxAge:
|
|
224
302
|
10)` is ten seconds, not ten minutes — write `600`. `requireFresh(ctx,
|
|
225
303
|
'10m')` takes the unit, and refuses a bare number, which `@nxgt/janus`
|
|
@@ -238,13 +316,13 @@ response with several errors: [the errors guide](docs/guide/errors.md).
|
|
|
238
316
|
|
|
239
317
|
## Documentation
|
|
240
318
|
|
|
241
|
-
- [Guides](docs/README.md) — the directives, the step-up over GraphQL, the context and the lazy user, errors as statuses, telemetry, and federation
|
|
319
|
+
- [Guides](docs/README.md) — the directives, the step-up over GraphQL, subscriptions over graphql-ws, the context and the lazy user, errors as statuses, telemetry, and federation
|
|
242
320
|
- [Troubleshooting](docs/troubleshooting.md) — by the message or status you see
|
|
243
321
|
- [Roadmap](docs/roadmap.md) — what is next, and what is not planned
|
|
244
322
|
|
|
245
323
|
## Type safety, counted
|
|
246
324
|
|
|
247
|
-
|
|
325
|
+
Thirty-seven plausible mistakes are refused by the compiler, each with a
|
|
248
326
|
`@ts-expect-error` case in `test/types/`:
|
|
249
327
|
|
|
250
328
|
- five in `context.ts`: reading the user or the session where either may be
|
|
@@ -257,10 +335,11 @@ Twenty-nine plausible mistakes are refused by the compiler, each with a
|
|
|
257
335
|
permission the object's type does not declare, an object type the model
|
|
258
336
|
does not, an object without a field a `fromField` reads, a condition reached
|
|
259
337
|
with no `ctx`, a `ctx` of the wrong shape, and a context with no `access`;
|
|
260
|
-
-
|
|
338
|
+
- seven in `plugin.ts`: `useJanus()` given a user type the instance does not
|
|
261
339
|
know, something that is not what `janus()` answered, the `permissions()`
|
|
262
|
-
instance as `auth`,
|
|
263
|
-
to a user type the instance does not know
|
|
340
|
+
instance as `auth`, `applyJanusDirectives()` without `auth` or narrowed
|
|
341
|
+
to a user type the instance does not know, and `janusMaskError()` given a
|
|
342
|
+
misspelled `report` or one reading what a `JanusError` does not carry;
|
|
264
343
|
- five in `wiring.ts`: `useJanus()`'s `loaders` for an object type the model
|
|
265
344
|
does not declare, a loader answering an object without a field a
|
|
266
345
|
`fromField` reads, `conditions` for a type no `when()` is reached on, a
|
|
@@ -268,9 +347,16 @@ Twenty-nine plausible mistakes are refused by the compiler, each with a
|
|
|
268
347
|
`access`;
|
|
269
348
|
- five in `fresh.ts`: `requireFresh()` given a bare number, a duration
|
|
270
349
|
written as prose, no `maxAge` at all, or the request instead of the
|
|
271
|
-
context, and `useJanus()` given a timestamp as its `clock
|
|
272
|
-
|
|
273
|
-
|
|
350
|
+
context, and `useJanus()` given a timestamp as its `clock`;
|
|
351
|
+
- six in `connection.ts`: `janusConnection()` given a user type the
|
|
352
|
+
instance does not know, the `permissions()` instance as `auth`, or a
|
|
353
|
+
timestamp as its `clock`; `ctx.janus.access` from a connection given no
|
|
354
|
+
`access`, a field of another user type once narrowed, and an `upgrade`
|
|
355
|
+
answering a token rather than a request.
|
|
356
|
+
|
|
357
|
+
`plugin.ts` also holds this README's quick start, and `connection.ts` the
|
|
358
|
+
graphql-ws wiring — Yoga's recipe, without Yoga, and Bun's `upgrade` —
|
|
359
|
+
against graphql-ws's own types; both must keep compiling.
|
|
274
360
|
|
|
275
361
|
## Licence
|
|
276
362
|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `janusConnection()`: authenticated subscriptions over graphql-ws.
|
|
3
|
+
*/
|
|
4
|
+
import type { Auth, UserOfAuth } from '../types';
|
|
5
|
+
import type { JanusConnection, JanusConnectionOptions } from './types';
|
|
6
|
+
/**
|
|
7
|
+
* The pieces of graphql-ws's `useServer()` that authenticate a WebSocket
|
|
8
|
+
* connection, for Yoga's recommended setup:
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* const connection = janusConnection({ auth });
|
|
12
|
+
* useServer({
|
|
13
|
+
* onConnect: connection.onConnect,
|
|
14
|
+
* execute: (args) => args.rootValue.execute(args),
|
|
15
|
+
* subscribe: (args) => args.rootValue.subscribe(args),
|
|
16
|
+
* onSubscribe: async (ctx, _id, params) => { … yoga.getEnveloped({ ...ctx, … }) … },
|
|
17
|
+
* }, wsServer);
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* `onConnect` reads the connection's credential — `connectionParams`'
|
|
21
|
+
* `authorization`, else the upgrade request's headers and cookie — and
|
|
22
|
+
* refuses it unless it authenticates, as a user of `type` when it is given.
|
|
23
|
+
* Each operation on the connection then gets a `ctx.janus` of its own from
|
|
24
|
+
* `useJanus()`, authenticated again from that credential when a field asks:
|
|
25
|
+
* `@authenticated`, `@fresh` and `@permission` hold as over HTTP, and a
|
|
26
|
+
* session revoked since the connection opened is refused at the next
|
|
27
|
+
* subscribe.
|
|
28
|
+
*
|
|
29
|
+
* A server without Yoga passes `context` too, and applies the directives
|
|
30
|
+
* with `applyJanusDirectives()`.
|
|
31
|
+
*/
|
|
32
|
+
export declare function janusConnection<A extends Auth<{
|
|
33
|
+
readonly type: string;
|
|
34
|
+
readonly id: string;
|
|
35
|
+
}>, P extends object | undefined = undefined, const T extends UserOfAuth<A>['type'] = UserOfAuth<A>['type']>(options: JanusConnectionOptions<A, P, T>): JanusConnection<A, P, T>;
|
|
36
|
+
//# sourceMappingURL=connection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/connection/connection.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,IAAI,EAAgB,UAAU,EAAE,MAAM,UAAU,CAAC;AAE/D,OAAO,KAAK,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAEvE;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,eAAe,CAC9B,CAAC,SAAS,IAAI,CAAC;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,EAC9D,CAAC,SAAS,MAAM,GAAG,SAAS,GAAG,SAAS,EACxC,KAAK,CAAC,CAAC,SAAS,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAC5D,OAAO,EAAE,sBAAsB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAqCpE"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The credential a graphql-ws connection presents, and the connections
|
|
3
|
+
* `janusConnection().onConnect` accepted: what each operation on one is
|
|
4
|
+
* authenticated from.
|
|
5
|
+
*/
|
|
6
|
+
import type { RequestLike } from '@nxgt/janus';
|
|
7
|
+
import type { ConnectionContext } from './types';
|
|
8
|
+
/** Where the upgrade request is, when the transport does not say `extra.request`. */
|
|
9
|
+
export type Upgrade = (ctx: ConnectionContext) => RequestLike | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* The connection's credential, as `auth.authenticate` reads one:
|
|
12
|
+
*
|
|
13
|
+
* 1. `connectionParams.authorization`, when it is a `Bearer` token — a
|
|
14
|
+
* non-browser client's `'Bearer <token>'`;
|
|
15
|
+
* 2. otherwise the upgrade request itself, read as any request is —
|
|
16
|
+
* `Authorization`, then `X-Session-Token`, then the session cookie a
|
|
17
|
+
* browser sends with it.
|
|
18
|
+
*
|
|
19
|
+
* **The first present wins, not the first valid one**, as in `@nxgt/janus`:
|
|
20
|
+
* a lapsed token in `connectionParams` beside a live cookie is refused. An
|
|
21
|
+
* `authorization` of another scheme (`Basic`) is not a session credential,
|
|
22
|
+
* as in `@nxgt/janus`, and does not count. `null` when there is nothing to
|
|
23
|
+
* read, or an `authorization` that is not a string — refused, as a
|
|
24
|
+
* client's mistake.
|
|
25
|
+
*/
|
|
26
|
+
export declare function credentialOf(ctx: ConnectionContext, upgrade: Upgrade | undefined): RequestLike | null;
|
|
27
|
+
/** Remembers `credential` as the one `ctx`'s connection presented. */
|
|
28
|
+
export declare function accept(ctx: ConnectionContext, credential: RequestLike): void;
|
|
29
|
+
/**
|
|
30
|
+
* The credential of the connection a context was built for, or `undefined`
|
|
31
|
+
* for one no `onConnect` accepted — and for every HTTP request.
|
|
32
|
+
*/
|
|
33
|
+
export declare function acceptedOf(context: unknown): RequestLike | undefined;
|
|
34
|
+
//# sourceMappingURL=credential.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credential.d.ts","sourceRoot":"","sources":["../../src/connection/credential.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEjD,qFAAqF;AACrF,MAAM,MAAM,OAAO,GAAG,CAAC,GAAG,EAAE,iBAAiB,KAAK,WAAW,GAAG,SAAS,CAAC;AAK1E;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAC3B,GAAG,EAAE,iBAAiB,EACtB,OAAO,EAAE,OAAO,GAAG,SAAS,GAC1B,WAAW,GAAG,IAAI,CAcpB;AAWD,sEAAsE;AACtE,wBAAgB,MAAM,CAAC,GAAG,EAAE,iBAAiB,EAAE,UAAU,EAAE,WAAW,QAQrE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,WAAW,GAAG,SAAS,CAIpE"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The public types of `janusConnection()`: what it takes, and the pieces
|
|
3
|
+
* it answers for graphql-ws's `useServer()`. Typed by their shape, so the
|
|
4
|
+
* package imports nothing from graphql-ws. Nothing here runs.
|
|
5
|
+
*/
|
|
6
|
+
import type { Clock, RequestLike } from '@nxgt/janus';
|
|
7
|
+
import type { JanusContext, UserOfAuth } from '../types';
|
|
8
|
+
/**
|
|
9
|
+
* The part of graphql-ws's `Context` read here: the `connectionParams` the
|
|
10
|
+
* client sent with `connection_init`, and the transport's `extra` —
|
|
11
|
+
* `{ socket, request }` for `graphql-ws/use/ws`.
|
|
12
|
+
*/
|
|
13
|
+
export interface ConnectionContext {
|
|
14
|
+
readonly connectionParams?: Readonly<Record<string, unknown>> | undefined;
|
|
15
|
+
readonly extra: unknown;
|
|
16
|
+
}
|
|
17
|
+
/** What `janusConnection()` takes. */
|
|
18
|
+
export interface JanusConnectionOptions<A, P, T extends string> {
|
|
19
|
+
/** What `janus()` answered. */
|
|
20
|
+
readonly auth: A;
|
|
21
|
+
/**
|
|
22
|
+
* What `permissions()` answered: `ctx.janus.access` in the context
|
|
23
|
+
* `context()` builds. `useJanus()`'s own when Yoga builds it.
|
|
24
|
+
*/
|
|
25
|
+
readonly access?: P;
|
|
26
|
+
/** Only a user of this type may connect; any other is refused. */
|
|
27
|
+
readonly type?: T;
|
|
28
|
+
/** The clock `@fresh` reads in the context `context()` builds. */
|
|
29
|
+
readonly clock?: Clock;
|
|
30
|
+
/**
|
|
31
|
+
* The upgrade request of a connection, for a transport whose `extra`
|
|
32
|
+
* does not carry it as `request` — Bun's is `{ socket }`:
|
|
33
|
+
* `upgrade: (ctx) => ctx.extra.socket.data.request`, with the request
|
|
34
|
+
* passed to `server.upgrade(req, { data: { request: req } })`.
|
|
35
|
+
*
|
|
36
|
+
* A method, so `ctx` may be annotated with the transport's own `extra`.
|
|
37
|
+
*/
|
|
38
|
+
upgrade?(ctx: ConnectionContext): RequestLike | undefined;
|
|
39
|
+
}
|
|
40
|
+
/** What `janusConnection()` answers: the pieces of graphql-ws's `useServer()`. */
|
|
41
|
+
export interface JanusConnection<A, P = undefined, T extends UserOfAuth<A>['type'] = UserOfAuth<A>['type']> {
|
|
42
|
+
/**
|
|
43
|
+
* `useServer({ onConnect })`: accepts a connection whose credential
|
|
44
|
+
* authenticates, and answers `false` for any other — graphql-ws closes
|
|
45
|
+
* it `4403: Forbidden`. An outage rejects, never `false`: the transport
|
|
46
|
+
* closes it `4500`, and the client does not retry it as a refusal.
|
|
47
|
+
*/
|
|
48
|
+
readonly onConnect: (ctx: ConnectionContext) => Promise<boolean>;
|
|
49
|
+
/**
|
|
50
|
+
* `useServer({ context })`, for a server without Yoga: `ctx.janus` for
|
|
51
|
+
* one operation, authenticated from the connection's credential. Yoga's
|
|
52
|
+
* recipe builds the context itself, and `useJanus()` finds the
|
|
53
|
+
* connection there: leave this out.
|
|
54
|
+
*/
|
|
55
|
+
readonly context: (ctx: ConnectionContext) => JanusContext<A, P, T>;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/connection/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEzD;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAC1E,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACxB;AAED,sCAAsC;AACtC,MAAM,WAAW,sBAAsB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,MAAM;IAC7D,+BAA+B;IAC/B,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACjB;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACpB,kEAAkE;IAClE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAClB,kEAAkE;IAClE,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;IACvB;;;;;;;OAOG;IACH,OAAO,CAAC,CAAC,GAAG,EAAE,iBAAiB,GAAG,WAAW,GAAG,SAAS,CAAC;CAC1D;AAED,kFAAkF;AAClF,MAAM,WAAW,eAAe,CAC/B,CAAC,EACD,CAAC,GAAG,SAAS,EACb,CAAC,SAAS,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAEvD;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACjE;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;CACpE"}
|
package/dist/context.d.ts
CHANGED
|
@@ -34,17 +34,26 @@ export interface ContextOptions {
|
|
|
34
34
|
} | undefined;
|
|
35
35
|
readonly type?: string | undefined;
|
|
36
36
|
readonly clock?: Clock | undefined;
|
|
37
|
+
/** The call the consumer wrote, named by the no-request `TypeError`. */
|
|
38
|
+
readonly caller?: string;
|
|
37
39
|
}
|
|
38
40
|
/**
|
|
39
41
|
* `ctx.janus` for one request. `authenticate` runs the first time `user()`
|
|
40
42
|
* or `session()` is asked, once, and its answer — or its failure — is the
|
|
41
43
|
* answer of both from then on.
|
|
42
44
|
*
|
|
43
|
-
* A context with no request — a transport that is not HTTP
|
|
45
|
+
* A context with no request — a transport that is not HTTP, or a graphql-ws
|
|
46
|
+
* connection no `janusConnection().onConnect` accepted — answers a
|
|
44
47
|
* `TypeError` from `user()`, not `null`: anonymous is an answer, and nothing
|
|
45
48
|
* here asked.
|
|
46
49
|
*/
|
|
47
50
|
export declare function createJanusContext(request: RequestLike | undefined, options: ContextOptions): Built;
|
|
51
|
+
/**
|
|
52
|
+
* What `authenticate` answered for `janus`'s request, or `undefined` when it
|
|
53
|
+
* never ran — nothing asked `user()` or `session()`, or the context was not
|
|
54
|
+
* built here. Never runs it.
|
|
55
|
+
*/
|
|
56
|
+
export declare function answerOf(janus: object): Promise<Authenticated<AnyUser> | null> | undefined;
|
|
48
57
|
/**
|
|
49
58
|
* The clock `@fresh` and `requireFresh()` read the time from: the one given
|
|
50
59
|
* to `useJanus({ clock })`, or the system's.
|
package/dist/context.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACN,KAAK,aAAa,EAClB,KAAK,KAAK,EACV,KAAK,WAAW,EAEhB,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,iFAAiF;AACjF,MAAM,MAAM,KAAK,GAAG,CACnB,OAAO,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,EAC9D,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,EACtD,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAE,KAChC,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB,qEAAqE;AACrE,KAAK,OAAO,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9D,KAAK,SAAS,GAAG;IAChB,YAAY,CACX,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAClC,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;CAC1C,CAAC;AAEF,KAAK,KAAK,GAAG,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACN,KAAK,aAAa,EAClB,KAAK,KAAK,EACV,KAAK,WAAW,EAEhB,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,iFAAiF;AACjF,MAAM,MAAM,KAAK,GAAG,CACnB,OAAO,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,EAC9D,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,EACtD,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAE,KAChC,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB,qEAAqE;AACrE,KAAK,OAAO,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9D,KAAK,SAAS,GAAG;IAChB,YAAY,CACX,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAClC,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;CAC1C,CAAC;AAEF,KAAK,KAAK,GAAG,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAuB9C,mEAAmE;AACnE,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS,CAAC;IACxD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;IACnC,wEAAwE;IACxE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,WAAW,GAAG,SAAS,EAChC,OAAO,EAAE,cAAc,GACrB,KAAK,CAqCP;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CACvB,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,SAAS,CAEpD;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,CAE5C;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,UAAQ,GAAG,KAAK,GAAG,IAAI,CAMlE;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,KAAK,CAQ3D"}
|
package/dist/errors.d.ts
CHANGED
|
@@ -26,6 +26,22 @@ export declare function janusGraphQLError(error: JanusError): GraphQLError;
|
|
|
26
26
|
export declare function rethrown(error: unknown): never;
|
|
27
27
|
/** Yoga's and envelop's `maskError` signature. */
|
|
28
28
|
export type MaskError = (error: unknown, message: string, isDev?: boolean) => Error;
|
|
29
|
+
/** What `janusMaskError()` takes. */
|
|
30
|
+
export interface JanusMaskErrorOptions {
|
|
31
|
+
/**
|
|
32
|
+
* Called once with every `JanusError` answered 5xx — `STORE_FAILED`,
|
|
33
|
+
* `UNSUPPORTED`, `PERMISSION_DEPTH` — whichever path it took: a
|
|
34
|
+
* directive, `requireUser()`, `can()`, or a resolver that let it through.
|
|
35
|
+
* Its `slot`, `operation`, `reason` and cause are for your logs; the
|
|
36
|
+
* response never carries them.
|
|
37
|
+
*
|
|
38
|
+
* **It cannot change the answer**: one that throws, or rejects, is a
|
|
39
|
+
* `process.emitWarning`, and the 503 is sent all the same.
|
|
40
|
+
*/
|
|
41
|
+
readonly report?: (error: JanusError) => unknown;
|
|
42
|
+
/** Every error that is not a `JanusError`; see `janusMaskError()`. */
|
|
43
|
+
readonly fallback?: MaskError;
|
|
44
|
+
}
|
|
29
45
|
/**
|
|
30
46
|
* Yoga's `maskedErrors.maskError`: a `JanusError` a resolver let through is
|
|
31
47
|
* answered with its code and status — `STORE_FAILED` as 503, never masked
|
|
@@ -33,12 +49,19 @@ export type MaskError = (error: unknown, message: string, isDev?: boolean) => Er
|
|
|
33
49
|
*
|
|
34
50
|
* Without a `fallback`, a `GraphQLError` is kept and anything else becomes
|
|
35
51
|
* `message`, with no detail. Pass Yoga's own `maskError` to keep its
|
|
36
|
-
* development-mode details
|
|
52
|
+
* development-mode details — as the options' `fallback`, or alone, as
|
|
53
|
+
* before `report` existed:
|
|
37
54
|
*
|
|
38
55
|
* ```ts
|
|
39
56
|
* import { createYoga, maskError } from 'graphql-yoga';
|
|
40
|
-
* createYoga({
|
|
57
|
+
* createYoga({
|
|
58
|
+
* schema,
|
|
59
|
+
* plugins,
|
|
60
|
+
* maskedErrors: {
|
|
61
|
+
* maskError: janusMaskError({ report: (error) => logger.error(error), fallback: maskError }),
|
|
62
|
+
* },
|
|
63
|
+
* });
|
|
41
64
|
* ```
|
|
42
65
|
*/
|
|
43
|
-
export declare function janusMaskError(
|
|
66
|
+
export declare function janusMaskError(options?: JanusMaskErrorOptions | MaskError): MaskError;
|
|
44
67
|
//# sourceMappingURL=errors.d.ts.map
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAmC,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAmC,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAGvC,mFAAmF;AACnF,MAAM,MAAM,UAAU,GAAG,iBAAiB,GAAG,WAAW,GAAG,WAAW,CAAC;AAEvE,2EAA2E;AAC3E,wBAAgB,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,YAAY,CAKvE;AAaD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,YAAY,CAQjE;AA4CD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAE9C;AAED,kDAAkD;AAClD,MAAM,MAAM,SAAS,GAAG,CACvB,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,OAAO,KACX,KAAK,CAAC;AAEX,qCAAqC;AACrC,MAAM,WAAW,qBAAqB;IACrC;;;;;;;;;OASG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC;IACjD,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,cAAc,CAC7B,OAAO,GAAE,qBAAqB,GAAG,SAAc,GAC7C,SAAS,CAqBX"}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,16 +9,23 @@
|
|
|
9
9
|
* - `applyJanusDirectives(schema, { auth })` — the schema transform alone;
|
|
10
10
|
* - `requireUser(ctx, { type? })`, `requireFresh(ctx, maxAge)` and
|
|
11
11
|
* `can(ctx, permission, object)` — the calls a resolver makes itself;
|
|
12
|
-
* - `janusMaskError(fallback?)` — Yoga's `maskError`: a
|
|
13
|
-
* code and status, `STORE_FAILED` as 503 and never as
|
|
12
|
+
* - `janusMaskError({ report?, fallback? })` — Yoga's `maskError`: a
|
|
13
|
+
* `JanusError` as its code and status, `STORE_FAILED` as 503 and never as
|
|
14
|
+
* 401 or 403, and every 5xx handed to `report`.
|
|
14
15
|
* - `janusGraphQLError(error)` — a `JanusError` as the `GraphQLError` the
|
|
15
16
|
* client reads, and `denial(code, message?)` — a denial of your own.
|
|
17
|
+
* - `janusConnection({ auth, access?, type?, clock?, upgrade? })` —
|
|
18
|
+
* subscriptions over graphql-ws: `onConnect` and `context` for its
|
|
19
|
+
* `useServer()`, a connection authenticated from its `connectionParams`
|
|
20
|
+
* or its upgrade request.
|
|
16
21
|
*
|
|
17
22
|
* It defines no error class: a denial is a `GraphQLError`, and what it lets
|
|
18
23
|
* through is `@nxgt/janus`'s own.
|
|
19
24
|
*/
|
|
25
|
+
export { janusConnection } from './connection/connection';
|
|
26
|
+
export type { ConnectionContext, JanusConnection, JanusConnectionOptions, } from './connection/types';
|
|
20
27
|
export { applyJanusDirectives, type JanusDirectivesOptions, } from './directives/apply';
|
|
21
|
-
export { type DenialCode, denial, janusGraphQLError, janusMaskError, type MaskError, } from './errors';
|
|
28
|
+
export { type DenialCode, denial, type JanusMaskErrorOptions, janusGraphQLError, janusMaskError, type MaskError, } from './errors';
|
|
22
29
|
export { requireFresh } from './fresh';
|
|
23
30
|
export { can, type RequireUserOptions, requireUser } from './helpers';
|
|
24
31
|
export { useJanus } from './plugin';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,YAAY,EACX,iBAAiB,EACjB,eAAe,EACf,sBAAsB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACN,oBAAoB,EACpB,KAAK,sBAAsB,GAC3B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACN,KAAK,UAAU,EACf,MAAM,EACN,KAAK,qBAAqB,EAC1B,iBAAiB,EACjB,cAAc,EACd,KAAK,SAAS,GACd,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,GAAG,EAAE,KAAK,kBAAkB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACtE,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,YAAY,EACX,IAAI,EACJ,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,UAAU,GACV,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC"}
|