@nxgt/janus-graphql 0.2.0 → 0.3.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 +75 -15
- 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 +4 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +83 -17
- package/dist/index.js.map +9 -6
- package/dist/options.d.ts +17 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/plugin.d.ts +4 -0
- package/dist/plugin.d.ts.map +1 -1
- package/docs/README.md +2 -1
- package/docs/guide/context.md +4 -1
- package/docs/guide/step-up.md +7 -3
- package/docs/guide/subscriptions.md +251 -0
- package/docs/roadmap.md +18 -4
- package/docs/troubleshooting.md +92 -9
- package/package.json +10 -1
package/dist/index.js.map
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/
|
|
3
|
+
"sources": ["../src/context.ts", "../src/memo.ts", "../src/options.ts", "../src/connection/credential.ts", "../src/connection/connection.ts", "../src/directives/apply.ts", "../src/errors.ts", "../src/fresh.ts", "../src/directives/permission/path.ts", "../src/directives/permission/enforce.ts", "../src/directives/guard.ts", "../src/directives/read.ts", "../src/directives/words.ts", "../src/directives/permission/model.ts", "../src/directives/permission/validate.ts", "../src/directives/validate.ts", "../src/helpers.ts", "../src/plugin.ts", "../src/sdl.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n *
|
|
6
|
-
"/**\n * `ctx.janus`, built once per request by `useJanus()`: a lazy\n * authentication, and the per-request check `can()` and the directives ask\n * through.\n */\n\nimport {\n\ttype Authenticated,\n\ttype Clock,\n\ttype RequestLike,\n\tsystemClock,\n} from '@nxgt/janus';\nimport { memoized } from './memo';\nimport type { JanusOnContext } from './types';\n\n/** One check, as `access.can` answers it — loose: the typing is the caller's. */\nexport type Check = (\n\tsubject: { readonly type: string; readonly id: string } | null,\n\tpermission: string,\n\tobject: { readonly type: string; readonly id: string },\n\toptions?: { readonly ctx?: unknown },\n) => Promise<boolean>;\n\n/** A user as this module reads one: the part every user type has. */\ntype AnyUser = { readonly type: string; readonly id: string };\n\ntype LooseAuth = {\n\tauthenticate(\n\t\trequest: RequestLike,\n\t\toptions?: { readonly type?: string },\n\t): Promise<Authenticated<AnyUser> | null>;\n};\n\ntype Built = JanusOnContext<AnyUser, unknown>;\n\n/**\n * The check of each context this module built. A `WeakMap` rather than a\n * property, so the context's own surface stays `user`, `session` and\n * `access`; it is the one place a request's checks pass through, and so the\n * one place a per-request memo of their answers goes.\n */\nconst checks = new WeakMap<object, { memo: Check; fresh: Check }>();\n\n/** The clock of each context this module built with one: what `@fresh` reads. */\nconst clocks = new WeakMap<object, Clock>();\n\n/** What `createJanusContext` reads from `useJanus()`'s options. */\nexport interface ContextOptions {\n\treadonly auth: LooseAuth;\n\treadonly access?: { readonly can: unknown } | undefined;\n\treadonly type?: string | undefined;\n\treadonly clock?: Clock | undefined;\n}\n\n/**\n * `ctx.janus` for one request. `authenticate` runs the first time `user()`\n * or `session()` is asked, once, and its answer — or its failure — is the\n * answer of both from then on.\n *\n * A context with no request — a transport that is not HTTP — answers a\n * `TypeError` from `user()`, not `null`: anonymous is an answer, and nothing\n * here asked.\n */\nexport function createJanusContext(\n\trequest: RequestLike | undefined,\n\toptions: ContextOptions,\n): Built {\n\tconst { auth, access, type, clock } = options;\n\tlet answer: Promise<Authenticated<AnyUser> | null>;\n\tlet asked = false;\n\tconst authenticated = () => {\n\t\tif (!asked) {\n\t\t\tasked = true;\n\t\t\tanswer =\n\t\t\t\trequest === undefined\n\t\t\t\t\t? Promise.reject(\n\t\t\t\t\t\t\tnew TypeError(\n\t\t\t\t\t\t\t\t'useJanus(): the GraphQL context has no request to authenticate — build the context from an HTTP request',\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t)\n\t\t\t\t\t: auth.authenticate(\n\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t\ttype === undefined ? undefined : { type },\n\t\t\t\t\t\t);\n\t\t}\n\t\treturn answer;\n\t};\n\n\tconst janus = Object.freeze({\n\t\tuser: () => authenticated().then((current) => current?.user ?? null),\n\t\tsession: () => authenticated().then((current) => current?.session ?? null),\n\t\t...(access === undefined ? {} : { access }),\n\t});\n\tif (access !== undefined) {\n\t\tconst can = access.can as Check;\n\t\tchecks.set(janus, {\n\t\t\tmemo: memoized(access),\n\t\t\tfresh: (...args) => can.apply(access, args),\n\t\t});\n\t}\n\tif (clock !== undefined) clocks.set(janus, clock);\n\treturn janus as Built;\n}\n\n/**\n * The clock `@fresh` and `requireFresh()` read the time from: the one given\n * to `useJanus({ clock })`, or the system's.\n */\nexport function clockOf(janus: object): Clock {\n\treturn clocks.get(janus) ?? systemClock;\n}\n\n/**\n * The check `ctx.janus` answers through: the one its context was built\n * with — `access.can`, memoized for the request (`memo.ts`) — or\n * `access.can` itself for a context built by hand. `null` when it has no\n * `access` at all.\n *\n * `fresh` skips the memo: a subscription is one request whose checks run\n * again on every event, and must see a `revoke()` made since it started.\n */\nexport function checkOf(janus: object, fresh = false): Check | null {\n\tconst built = checks.get(janus);\n\tif (built !== undefined) return fresh ? built.fresh : built.memo;\n\tconst access = (janus as { readonly access?: { readonly can?: unknown } })\n\t\t.access;\n\treturn typeof access?.can === 'function' ? (access.can as Check) : null;\n}\n\n/**\n * `ctx.janus`, or a wiring `TypeError` naming `caller` when nothing put it\n * there: `useJanus()` is missing from the plugins.\n */\nexport function janusOf(ctx: unknown, caller: string): Built {\n\tconst janus = (ctx as { readonly janus?: Built } | null)?.janus;\n\tif (janus === undefined || typeof janus.user !== 'function') {\n\t\tthrow new TypeError(\n\t\t\t`${caller}: ctx.janus is not set — add useJanus({ auth }) to the plugins`,\n\t\t);\n\t}\n\treturn janus;\n}\n",
|
|
5
|
+
"/**\n * `ctx.janus`, built once per request by `useJanus()`: a lazy\n * authentication, and the per-request check `can()` and the directives ask\n * through.\n */\n\nimport {\n\ttype Authenticated,\n\ttype Clock,\n\ttype RequestLike,\n\tsystemClock,\n} from '@nxgt/janus';\nimport { memoized } from './memo';\nimport type { JanusOnContext } from './types';\n\n/** One check, as `access.can` answers it — loose: the typing is the caller's. */\nexport type Check = (\n\tsubject: { readonly type: string; readonly id: string } | null,\n\tpermission: string,\n\tobject: { readonly type: string; readonly id: string },\n\toptions?: { readonly ctx?: unknown },\n) => Promise<boolean>;\n\n/** A user as this module reads one: the part every user type has. */\ntype AnyUser = { readonly type: string; readonly id: string };\n\ntype LooseAuth = {\n\tauthenticate(\n\t\trequest: RequestLike,\n\t\toptions?: { readonly type?: string },\n\t): Promise<Authenticated<AnyUser> | null>;\n};\n\ntype Built = JanusOnContext<AnyUser, unknown>;\n\n/**\n * The check of each context this module built. A `WeakMap` rather than a\n * property, so the context's own surface stays `user`, `session` and\n * `access`; it is the one place a request's checks pass through, and so the\n * one place a per-request memo of their answers goes.\n */\nconst checks = new WeakMap<object, { memo: Check; fresh: Check }>();\n\n/** The clock of each context this module built with one: what `@fresh` reads. */\nconst clocks = new WeakMap<object, Clock>();\n\n/** What `createJanusContext` reads from `useJanus()`'s options. */\nexport interface ContextOptions {\n\treadonly auth: LooseAuth;\n\treadonly access?: { readonly can: unknown } | undefined;\n\treadonly type?: string | undefined;\n\treadonly clock?: Clock | undefined;\n\t/** The call the consumer wrote, named by the no-request `TypeError`. */\n\treadonly caller?: string;\n}\n\n/**\n * `ctx.janus` for one request. `authenticate` runs the first time `user()`\n * or `session()` is asked, once, and its answer — or its failure — is the\n * answer of both from then on.\n *\n * A context with no request — a transport that is not HTTP, or a graphql-ws\n * connection no `janusConnection().onConnect` accepted — answers a\n * `TypeError` from `user()`, not `null`: anonymous is an answer, and nothing\n * here asked.\n */\nexport function createJanusContext(\n\trequest: RequestLike | undefined,\n\toptions: ContextOptions,\n): Built {\n\tconst { auth, access, type, clock, caller = 'useJanus()' } = options;\n\tlet answer: Promise<Authenticated<AnyUser> | null>;\n\tlet asked = false;\n\tconst authenticated = () => {\n\t\tif (!asked) {\n\t\t\tasked = true;\n\t\t\tanswer =\n\t\t\t\trequest === undefined\n\t\t\t\t\t? Promise.reject(\n\t\t\t\t\t\t\tnew TypeError(\n\t\t\t\t\t\t\t\t`${caller}: the GraphQL context has no request to authenticate — build the context from an HTTP request, or accept a graphql-ws connection with janusConnection().onConnect`,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t)\n\t\t\t\t\t: auth.authenticate(\n\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t\ttype === undefined ? undefined : { type },\n\t\t\t\t\t\t);\n\t\t}\n\t\treturn answer;\n\t};\n\n\tconst janus = Object.freeze({\n\t\tuser: () => authenticated().then((current) => current?.user ?? null),\n\t\tsession: () => authenticated().then((current) => current?.session ?? null),\n\t\t...(access === undefined ? {} : { access }),\n\t});\n\tif (access !== undefined) {\n\t\tconst can = access.can as Check;\n\t\tchecks.set(janus, {\n\t\t\tmemo: memoized(access),\n\t\t\tfresh: (...args) => can.apply(access, args),\n\t\t});\n\t}\n\tif (clock !== undefined) clocks.set(janus, clock);\n\treturn janus as Built;\n}\n\n/**\n * The clock `@fresh` and `requireFresh()` read the time from: the one given\n * to `useJanus({ clock })`, or the system's.\n */\nexport function clockOf(janus: object): Clock {\n\treturn clocks.get(janus) ?? systemClock;\n}\n\n/**\n * The check `ctx.janus` answers through: the one its context was built\n * with — `access.can`, memoized for the request (`memo.ts`) — or\n * `access.can` itself for a context built by hand. `null` when it has no\n * `access` at all.\n *\n * `fresh` skips the memo: a subscription is one request whose checks run\n * again on every event, and must see a `revoke()` made since it started.\n */\nexport function checkOf(janus: object, fresh = false): Check | null {\n\tconst built = checks.get(janus);\n\tif (built !== undefined) return fresh ? built.fresh : built.memo;\n\tconst access = (janus as { readonly access?: { readonly can?: unknown } })\n\t\t.access;\n\treturn typeof access?.can === 'function' ? (access.can as Check) : null;\n}\n\n/**\n * `ctx.janus`, or a wiring `TypeError` naming `caller` when nothing put it\n * there: `useJanus()` is missing from the plugins.\n */\nexport function janusOf(ctx: unknown, caller: string): Built {\n\tconst janus = (ctx as { readonly janus?: Built } | null)?.janus;\n\tif (janus === undefined || typeof janus.user !== 'function') {\n\t\tthrow new TypeError(\n\t\t\t`${caller}: ctx.janus is not set — add useJanus({ auth }) to the plugins`,\n\t\t);\n\t}\n\treturn janus;\n}\n",
|
|
7
6
|
"/**\n * The per-request memo of permission checks: the same question asked twice\n * in one request — by two fields, by a directive and a resolver's `can()`,\n * or by two fields at once — is one call to `access.can`.\n */\n\nimport type { Check } from './context';\n\ntype Ref = {\n\treadonly type: string;\n\treadonly id: string;\n\treadonly relation?: unknown;\n};\n\n/**\n * What no id in a key may hold: the notation reads `@` and `#` as its own,\n * so a key built from such an id could be another question's. `can()`\n * refuses or denies such an id anyway; it is asked, not remembered.\n */\nconst NOTATION = /[@#]/;\n\n/**\n * The key of one question, in the notation — `record:r1#view@staff:u1` —\n * or `null` when it is not remembered: an anonymous subject, which `can()`\n * answers `false` with no store call; a condition's `ctx`, which the key\n * does not hold; an id the notation could read two ways.\n */\nfunction keyOf(\n\tsubject: Ref | null,\n\tpermission: string,\n\tobject: Ref,\n\toptions: { readonly ctx?: unknown } | undefined,\n): string | null {\n\tif (subject === null || options?.ctx !== undefined) return null;\n\tif (NOTATION.test(object.id) || NOTATION.test(subject.id)) return null;\n\tconst set =\n\t\ttypeof subject.relation === 'string' ? `#${subject.relation}` : '';\n\treturn `${object.type}:${object.id}#${permission}@${subject.type}:${subject.id}${set}`;\n}\n\n/**\n * `access.can` for one request, remembered: a question asked again answers\n * the first answer's promise, so two asked at once share one call. A\n * failure is not remembered — an outage is no answer, and the next question\n * asks again.\n */\nexport function memoized(access: { readonly can: unknown }): Check {\n\tconst can = access.can as Check;\n\tconst answers = new Map<string, Promise<boolean>>();\n\tconst ask: Check = async (subject, permission, object, options) =>\n\t\tcan.call(access, subject, permission, object, options);\n\treturn (subject, permission, object, options) => {\n\t\tconst key = keyOf(subject, permission, object, options);\n\t\tif (key === null) return ask(subject, permission, object, options);\n\t\tconst known = answers.get(key);\n\t\tif (known !== undefined) return known;\n\t\tconst answer = ask(subject, permission, object, options);\n\t\tanswers.set(key, answer);\n\t\tanswer.then(undefined, () => answers.delete(key));\n\t\treturn answer;\n\t};\n}\n",
|
|
7
|
+
"/**\n * The wiring checks `useJanus()` and `janusConnection()` share: what each\n * refuses at start-up, with a `TypeError` naming the call that was written.\n */\n\n/** What both calls take and check before anything runs. */\nexport interface Wiring {\n\treadonly auth: unknown;\n\treadonly access?: unknown;\n\treadonly clock?: unknown;\n}\n\n/**\n * Refuses an `auth` that is not what `janus()` answered, an `access` that\n * is not what `permissions()` answered, and a `clock` that is not a\n * `Clock` — each a `TypeError` naming `caller`.\n */\nexport function checkWiring(caller: string, { auth, access, clock }: Wiring) {\n\tif (\n\t\ttypeof (auth as { readonly authenticate?: unknown } | null)\n\t\t\t?.authenticate !== 'function'\n\t) {\n\t\tthrow new TypeError(\n\t\t\t`${caller}: auth is not what janus() answered — pass { auth }`,\n\t\t);\n\t}\n\tif (\n\t\taccess !== undefined &&\n\t\ttypeof (access as { readonly can?: unknown } | null)?.can !== 'function'\n\t) {\n\t\tthrow new TypeError(\n\t\t\t`${caller}: access is not what permissions() answered — pass { auth, access }`,\n\t\t);\n\t}\n\tif (\n\t\tclock !== undefined &&\n\t\ttypeof (clock as { readonly now?: unknown } | null)?.now !== 'function'\n\t) {\n\t\tthrow new TypeError(\n\t\t\t`${caller}: clock is not a Clock — pass the clock given to janus(), or leave it out for the system clock`,\n\t\t);\n\t}\n}\n",
|
|
8
|
+
"/**\n * The credential a graphql-ws connection presents, and the connections\n * `janusConnection().onConnect` accepted: what each operation on one is\n * authenticated from.\n */\n\nimport type { RequestLike } from '@nxgt/janus';\nimport type { ConnectionContext } from './types';\n\n/** Where the upgrade request is, when the transport does not say `extra.request`. */\nexport type Upgrade = (ctx: ConnectionContext) => RequestLike | undefined;\n\n/** The scheme `@nxgt/janus` reads a session token from — any case, as it does. */\nconst BEARER = /^\\s*bearer(?:\\s|$)/i;\n\n/**\n * The connection's credential, as `auth.authenticate` reads one:\n *\n * 1. `connectionParams.authorization`, when it is a `Bearer` token — a\n * non-browser client's `'Bearer <token>'`;\n * 2. otherwise the upgrade request itself, read as any request is —\n * `Authorization`, then `X-Session-Token`, then the session cookie a\n * browser sends with it.\n *\n * **The first present wins, not the first valid one**, as in `@nxgt/janus`:\n * a lapsed token in `connectionParams` beside a live cookie is refused. An\n * `authorization` of another scheme (`Basic`) is not a session credential,\n * as in `@nxgt/janus`, and does not count. `null` when there is nothing to\n * read, or an `authorization` that is not a string — refused, as a\n * client's mistake.\n */\nexport function credentialOf(\n\tctx: ConnectionContext,\n\tupgrade: Upgrade | undefined,\n): RequestLike | null {\n\tconst params = ctx.connectionParams;\n\tif (params !== undefined && Object.hasOwn(params, 'authorization')) {\n\t\tconst { authorization } = params;\n\t\tif (typeof authorization !== 'string') return null;\n\t\t// A record, not `Headers`, which would throw on a value no header may\n\t\t// hold: a client's mistake is a refusal, never a 4500.\n\t\tif (BEARER.test(authorization)) return { authorization };\n\t}\n\tconst request =\n\t\tupgrade === undefined\n\t\t\t? (ctx.extra as { readonly request?: RequestLike } | null)?.request\n\t\t\t: upgrade(ctx);\n\treturn request ?? null;\n}\n\n/**\n * The credential of each connection `onConnect` accepted, by its `extra`:\n * the one object graphql-ws hands every callback of a connection, and that\n * Yoga's recipe spreads into the context it builds. A `WeakMap`, so a\n * closed connection takes its entry with it, and nothing a request carries\n * can name one.\n */\nconst accepted = new WeakMap<object, RequestLike>();\n\n/** Remembers `credential` as the one `ctx`'s connection presented. */\nexport function accept(ctx: ConnectionContext, credential: RequestLike) {\n\tconst { extra } = ctx;\n\tif (typeof extra !== 'object' || extra === null) {\n\t\tthrow new TypeError(\n\t\t\t\"janusConnection(): the connection's extra is not an object — pass the context graphql-ws gave onConnect\",\n\t\t);\n\t}\n\taccepted.set(extra, credential);\n}\n\n/**\n * The credential of the connection a context was built for, or `undefined`\n * for one no `onConnect` accepted — and for every HTTP request.\n */\nexport function acceptedOf(context: unknown): RequestLike | undefined {\n\tconst extra = (context as { readonly extra?: unknown } | null)?.extra;\n\tif (typeof extra !== 'object' || extra === null) return undefined;\n\treturn accepted.get(extra);\n}\n",
|
|
9
|
+
"/**\n * `janusConnection()`: authenticated subscriptions over graphql-ws.\n */\n\nimport { createJanusContext } from '../context';\nimport { checkWiring } from '../options';\nimport type { Auth, JanusContext, UserOfAuth } from '../types';\nimport { accept, acceptedOf, credentialOf } from './credential';\nimport type { JanusConnection, JanusConnectionOptions } from './types';\n\n/**\n * The pieces of graphql-ws's `useServer()` that authenticate a WebSocket\n * connection, for Yoga's recommended setup:\n *\n * ```ts\n * const connection = janusConnection({ auth });\n * useServer({\n * onConnect: connection.onConnect,\n * execute: (args) => args.rootValue.execute(args),\n * subscribe: (args) => args.rootValue.subscribe(args),\n * onSubscribe: async (ctx, _id, params) => { … yoga.getEnveloped({ ...ctx, … }) … },\n * }, wsServer);\n * ```\n *\n * `onConnect` reads the connection's credential — `connectionParams`'\n * `authorization`, else the upgrade request's headers and cookie — and\n * refuses it unless it authenticates, as a user of `type` when it is given.\n * Each operation on the connection then gets a `ctx.janus` of its own from\n * `useJanus()`, authenticated again from that credential when a field asks:\n * `@authenticated`, `@fresh` and `@permission` hold as over HTTP, and a\n * session revoked since the connection opened is refused at the next\n * subscribe.\n *\n * A server without Yoga passes `context` too, and applies the directives\n * with `applyJanusDirectives()`.\n */\nexport function janusConnection<\n\tA extends Auth<{ readonly type: string; readonly id: string }>,\n\tP extends object | undefined = undefined,\n\tconst T extends UserOfAuth<A>['type'] = UserOfAuth<A>['type'],\n>(options: JanusConnectionOptions<A, P, T>): JanusConnection<A, P, T> {\n\tconst { auth, access, type, clock } = options;\n\tcheckWiring('janusConnection()', { auth, access, clock });\n\tif (options.upgrade !== undefined && typeof options.upgrade !== 'function') {\n\t\tthrow new TypeError(\n\t\t\t'janusConnection(): upgrade is not a function — pass (ctx) => the upgrade request, or leave it out to read ctx.extra.request',\n\t\t);\n\t}\n\tconst upgrade = options.upgrade?.bind(options);\n\tconst wiring = {\n\t\tauth,\n\t\taccess: access as { readonly can: unknown } | undefined,\n\t\ttype,\n\t\tclock,\n\t\tcaller: 'janusConnection().context',\n\t};\n\n\treturn {\n\t\tonConnect: async (ctx) => {\n\t\t\tconst credential = credentialOf(ctx, upgrade);\n\t\t\tif (credential === null) return false;\n\t\t\t// An outage rejects here, and graphql-ws closes the socket 4500:\n\t\t\t// never `false`, which a client reads as a refusal.\n\t\t\tconst current = await auth.authenticate(\n\t\t\t\tcredential,\n\t\t\t\ttype === undefined ? undefined : { type },\n\t\t\t);\n\t\t\tif (current === null) return false;\n\t\t\taccept(ctx, credential);\n\t\t\treturn true;\n\t\t},\n\t\t// The one cast at the boundary: the context is built loose, typed here.\n\t\tcontext: (ctx) =>\n\t\t\t({\n\t\t\t\tjanus: createJanusContext(acceptedOf(ctx), wiring),\n\t\t\t}) as unknown as JanusContext<A, P, T>,\n\t};\n}\n",
|
|
10
|
+
"/**\n * The schema transform: every object field a directive guards gets its\n * resolver wrapped, once, when the schema is built.\n */\n\nimport { MapperKind, mapSchema } from '@graphql-tools/utils';\nimport { defaultFieldResolver, type GraphQLSchema } from 'graphql';\nimport { guarded } from './guard';\nimport { readField } from './read';\nimport { type Known, requirementOf } from './validate';\nimport { list, PREFIX } from './words';\n\ntype Entries = {\n\treadonly [type: string]: ((...args: never[]) => unknown) | undefined;\n};\n\n/** What `applyJanusDirectives()` takes. */\nexport interface JanusDirectivesOptions<T extends string = string> {\n\t/** What `janus()` answered: its `types` are the names `type:` may take. */\n\treadonly auth: { readonly types: readonly T[] };\n\t/** `useJanus({ type })`'s: the one user type the schema's users can have. */\n\treadonly type?: NoInfer<T>;\n\t/** What `permissions()` answered: its model is what `@permission` may name. Required once a schema uses it. */\n\treadonly access?: { readonly model: unknown } | undefined;\n\t/** `useJanus({ loaders })`'s. */\n\treadonly loaders?: Entries | undefined;\n\t/** `useJanus({ conditions })`'s. */\n\treadonly conditions?: Entries | undefined;\n}\n\n/**\n * The schema with every field guarded by `@authenticated`, `@fresh` or\n * `@permission` — on the field, on its type, or on an interface the type\n * implements — wrapped so its resolver runs only for a signed-in user, of\n * one of the types `type:` names when it names some, on a session that\n * proved who it is less than `maxAge` seconds ago, holding every permission\n * asked. Every directive that applies must hold.\n *\n * `useJanus()` calls it on every schema it is given. Call it yourself to\n * check a schema without a server: the guards it installs read `ctx.janus`,\n * which only `useJanus()` builds.\n *\n * **Refuses when the schema is built**, with a `TypeError` naming the\n * field: a user type `auth` does not know, a `type: []`, restrictions no\n * user type meets together, a `@fresh` whose `maxAge` is not above zero;\n * for `@permission`, an object type or a permission the model does not\n * declare, a malformed `id:`, an argument the field does not take, and a\n * loader or a condition's `ctx` it needs and was not given.\n */\nexport function applyJanusDirectives<const T extends string>(\n\tschema: GraphQLSchema,\n\toptions: JanusDirectivesOptions<T>,\n): GraphQLSchema {\n\tconst known = knownOf(options);\n\treturn mapSchema(schema, {\n\t\t[MapperKind.OBJECT_FIELD]: (field, fieldName, typeName) => {\n\t\t\tconst requirement = requirementOf(\n\t\t\t\t{\n\t\t\t\t\tname: `${typeName}.${fieldName}`,\n\t\t\t\t\targs: Object.keys(field.args ?? {}),\n\t\t\t\t},\n\t\t\t\treadField(schema, field, fieldName, typeName),\n\t\t\t\tknown,\n\t\t\t\toptions,\n\t\t\t);\n\t\t\tif (requirement === null) return field;\n\t\t\tconst resolve = field.resolve ?? defaultFieldResolver;\n\t\t\tif (field.subscribe === undefined) {\n\t\t\t\treturn { ...field, resolve: guarded(resolve, requirement) };\n\t\t\t}\n\t\t\t// A subscription's freshness is checked when it subscribes: its\n\t\t\t// events keep coming past maxAge, as its session keeps standing.\n\t\t\tconst onEvent = { ...requirement, maxAgeMs: null };\n\t\t\treturn {\n\t\t\t\t...field,\n\t\t\t\tsubscribe: guarded(field.subscribe, requirement),\n\t\t\t\tresolve: guarded(resolve, onEvent),\n\t\t\t};\n\t\t},\n\t});\n}\n\n/** The user types a directive may name — `type` alone when it is given, and one of `auth.types`. */\nfunction knownOf({ auth, type }: JanusDirectivesOptions): Known {\n\tif (type === undefined) return { types: auth.types };\n\tif (!auth.types.includes(type)) {\n\t\tthrow new TypeError(\n\t\t\t`${PREFIX}: type '${type}' is not a user type of auth — it knows ${list(auth.types)}`,\n\t\t);\n\t}\n\treturn { types: [type] };\n}\n",
|
|
8
11
|
"/**\n * Every refusal as a `GraphQLError` whose `extensions` carry a `code` and the\n * HTTP status Yoga answers with: `{ code, http: { status } }`. This package\n * defines no error class of its own — a denial is a `GraphQLError`, and what\n * `@nxgt/janus` throws stays its own until `janusMaskError()` reads it.\n */\n\nimport { JanusError, type JanusErrorStatus, statusOf } from '@nxgt/janus';\nimport { GraphQLError } from 'graphql';\n\n/** What a guard answers without asking `@nxgt/janus`: no user, or not this one. */\nexport type DenialCode = 'UNAUTHENTICATED' | 'FORBIDDEN' | 'NOT_FOUND';\n\n/** A denial: `UNAUTHENTICATED` 401, `FORBIDDEN` 403 or `NOT_FOUND` 404. */\nexport function denial(code: DenialCode, message?: string): GraphQLError {\n\tconst [status, fallback] = denialOf(code);\n\treturn new GraphQLError(message ?? fallback, {\n\t\textensions: { code, http: { status } },\n\t});\n}\n\nfunction denialOf(code: DenialCode): readonly [number, string] {\n\tswitch (code) {\n\t\tcase 'UNAUTHENTICATED':\n\t\t\treturn [401, 'Not signed in'];\n\t\tcase 'FORBIDDEN':\n\t\t\treturn [403, 'Forbidden'];\n\t\tcase 'NOT_FOUND':\n\t\t\treturn [404, 'Not found'];\n\t}\n}\n\n/**\n * A `JanusError` as the client may read it: its code and status, and only\n * what the client can act on — `issues`, `minLength`, `attemptsLeft`. Never\n * `reason`, `login`, `slot` or a cause: those are for your logs.\n *\n * `STORE_FAILED` is `SERVICE_UNAVAILABLE` 503 — **an outage is never a\n * denial** — and no message of the core's reaches the client.\n */\nexport function janusGraphQLError(error: JanusError): GraphQLError {\n\tconst status = statusOf(error.code);\n\tconst code =\n\t\terror.code === 'STORE_FAILED' ? 'SERVICE_UNAVAILABLE' : error.code;\n\treturn new GraphQLError(messageOf(status), {\n\t\toriginalError: error,\n\t\textensions: { code, http: { status }, ...actionable(error) },\n\t});\n}\n\n/**\n * A fixed message per status: the core's own message names a hash prefix or\n * a version, which are for your logs. The client reads `extensions.code`.\n */\nfunction messageOf(status: JanusErrorStatus): string {\n\tswitch (status) {\n\t\tcase 400:\n\t\t\treturn 'Invalid request';\n\t\tcase 401:\n\t\t\treturn 'Invalid credentials';\n\t\tcase 403:\n\t\t\treturn 'Forbidden';\n\t\tcase 404:\n\t\t\treturn 'Not found';\n\t\tcase 409:\n\t\t\treturn 'Conflict';\n\t\tcase 503:\n\t\t\treturn 'The service is unavailable, retry later';\n\t\tcase 500:\n\t\tcase 501:\n\t\t\treturn 'Internal server error';\n\t}\n}\n\n/** The fields of a refusal a client can act on, as `@nxgt/janus-hono`'s `bodyOf`. */\nfunction actionable(error: JanusError): Record<string, unknown> {\n\tswitch (error.code) {\n\t\tcase 'USER_INVALID':\n\t\t\treturn { issues: error.issues ?? [] };\n\t\tcase 'PASSWORD_TOO_SHORT':\n\t\t\treturn error.minLength === undefined\n\t\t\t\t? {}\n\t\t\t\t: { minLength: error.minLength };\n\t\tcase 'CODE_INVALID':\n\t\t\treturn error.attemptsLeft === undefined\n\t\t\t\t? {}\n\t\t\t\t: { attemptsLeft: error.attemptsLeft };\n\t\tdefault:\n\t\t\treturn {};\n\t}\n}\n\n/**\n * A rejection handler: a `JanusError` becomes its `GraphQLError`, anything\n * else goes on as it is. `.then(undefined, rethrown)`.\n */\nexport function rethrown(error: unknown): never {\n\tthrow error instanceof JanusError ? janusGraphQLError(error) : error;\n}\n\n/** Yoga's and envelop's `maskError` signature. */\nexport type MaskError = (\n\terror: unknown,\n\tmessage: string,\n\tisDev?: boolean,\n) => Error;\n\n/**\n * Yoga's `maskedErrors.maskError`: a `JanusError` a resolver let through is\n * answered with its code and status — `STORE_FAILED` as 503, never masked\n * into a 500 and never a denial — and every other error goes to `fallback`.\n *\n * Without a `fallback`, a `GraphQLError` is kept and anything else becomes\n * `message`, with no detail. Pass Yoga's own `maskError` to keep its\n * development-mode details:\n *\n * ```ts\n * import { createYoga, maskError } from 'graphql-yoga';\n * createYoga({ schema, plugins, maskedErrors: { maskError: janusMaskError(maskError) } });\n * ```\n */\nexport function janusMaskError(fallback: MaskError = masked): MaskError {\n\treturn (error, message, isDev) => {\n\t\tconst original =\n\t\t\terror instanceof GraphQLError ? error.originalError : error;\n\t\tif (original instanceof JanusError) {\n\t\t\tconst answer = janusGraphQLError(original);\n\t\t\treturn error instanceof GraphQLError\n\t\t\t\t? new GraphQLError(answer.message, {\n\t\t\t\t\t\tnodes: error.nodes ?? null,\n\t\t\t\t\t\tpath: error.path ?? null,\n\t\t\t\t\t\toriginalError: original,\n\t\t\t\t\t\textensions: answer.extensions,\n\t\t\t\t\t})\n\t\t\t\t: answer;\n\t\t}\n\t\treturn fallback(error, message, isDev);\n\t};\n}\n\n/** The default `fallback`: a `GraphQLError` of our own kept, anything else `message`. */\nfunction masked(error: unknown, message: string): Error {\n\tif (error instanceof GraphQLError) {\n\t\tconst original = error.originalError;\n\t\tif (original === undefined || original instanceof GraphQLError) {\n\t\t\treturn error;\n\t\t}\n\t\treturn new GraphQLError(message, {\n\t\t\tnodes: error.nodes ?? null,\n\t\t\tpath: error.path ?? null,\n\t\t\textensions: { code: 'INTERNAL_SERVER_ERROR' },\n\t\t});\n\t}\n\treturn new GraphQLError(message, {\n\t\textensions: { code: 'INTERNAL_SERVER_ERROR' },\n\t});\n}\n",
|
|
9
12
|
"/**\n * Freshness: whether the request's session proved who it is recently enough\n * — the check `@fresh` runs before a field, and `requireFresh()` in a\n * resolver. Both are `@nxgt/janus`'s `assertFresh`, on the clock given to\n * `useJanus({ clock })`.\n */\n\nimport {\n\tassertFresh,\n\ttype Duration,\n\tparseDuration,\n\ttype Session,\n} from '@nxgt/janus';\nimport { clockOf, janusOf } from './context';\nimport { denial, rethrown } from './errors';\n\n/**\n * The request's session, once it proved who it is less than `maxAgeMs` ago\n * — or a denial: `UNAUTHENTICATED` 401 for an anonymous request,\n * `STEP_UP_REQUIRED` 403 for an older session. A store that cannot answer is\n * `SERVICE_UNAVAILABLE` 503, never either of them.\n */\nexport async function freshSession(\n\tjanus: { session(): Promise<Session | null> },\n\tmaxAgeMs: number,\n): Promise<Session> {\n\tconst session = await janus.session().then(undefined, rethrown);\n\tif (session === null) throw denial('UNAUTHENTICATED');\n\ttry {\n\t\tassertFresh(session, maxAgeMs, clockOf(janus));\n\t} catch (error) {\n\t\trethrown(error);\n\t}\n\treturn session;\n}\n\n/**\n * The request's session, once it proved who it is less than `maxAge` ago —\n * signed in, or confirmed since by `auth.stepUp.confirm` — or a denial:\n * `UNAUTHENTICATED` 401 for an anonymous request, `STEP_UP_REQUIRED` 403 for\n * an older session, which tells the client to ask for a step-up.\n *\n * ```ts\n * await requireFresh(ctx, '10m'); // before changing the e-mail\n * ```\n *\n * `maxAge` is a duration with its unit — `'10m'`, `'600s'` — never a bare\n * number, which `@nxgt/janus` reads as milliseconds where `@fresh` reads\n * seconds: a `TypeError`, as any other malformed duration.\n */\nexport async function requireFresh(\n\tctx: {\n\t\treadonly janus: {\n\t\t\tuser(): Promise<unknown>;\n\t\t\tsession(): Promise<Session | null>;\n\t\t};\n\t},\n\tmaxAge: Exclude<Duration, number>,\n): Promise<Session> {\n\tif (typeof maxAge !== 'string') {\n\t\tthrow new TypeError(\n\t\t\t\"requireFresh(): maxAge is a duration with its unit, such as '10m' — a bare number would be milliseconds, where @fresh reads seconds\",\n\t\t);\n\t}\n\tconst maxAgeMs = parseDuration(maxAge, 'requireFresh(): maxAge');\n\treturn freshSession(janusOf(ctx, 'requireFresh()'), maxAgeMs);\n}\n",
|
|
10
13
|
"/**\n * `@permission`'s `id:` — `args.<path>` or `parent.<path>` — parsed when the\n * schema is built, and read from a request's arguments or parent value when a\n * field is resolved.\n */\n\n/** A parsed `id:`. */\nexport interface IdPath {\n\t/** As written: `args.id`, `parent.wardId`, `args.input.ids`. */\n\treadonly text: string;\n\treadonly root: 'args' | 'parent';\n\t/** The names after the root, at least one. */\n\treadonly segments: readonly string[];\n}\n\nconst NAME = /^[_A-Za-z][_0-9A-Za-z]*$/;\n\n/** `text` parsed, or `null` when it is not `args.<name>…` or `parent.<name>…`. */\nexport function parsePath(text: string): IdPath | null {\n\tconst [root, ...segments] = text.split('.');\n\tif (root !== 'args' && root !== 'parent') return null;\n\tif (segments.length === 0 || !segments.every((name) => NAME.test(name))) {\n\t\treturn null;\n\t}\n\treturn { text, root, segments };\n}\n\n/** One object a check is about: its id, and the value that holds it when that value is the object. */\nexport interface Target {\n\treadonly id: string;\n\t/** The value the id was read from, when `id` is its `id` field under `parent`. */\n\treadonly holder: object | null;\n}\n\n/**\n * The objects `path` names in this request: one, or one per element where a\n * step reads a list. `null` when a step reads nothing, or an id is not a\n * string or an integer: the request resolved no object id. An empty list\n * under `parent` is `null` too — the object's data names nothing to check,\n * and its fields are not open to everyone for it; under `args` it is the\n * client asking for nothing, and there is nothing to refuse.\n */\nexport function targetsOf(\n\tpath: IdPath,\n\tparent: unknown,\n\targs: unknown,\n): readonly Target[] | null {\n\tconst containers = walk(\n\t\t[path.root === 'args' ? args : parent],\n\t\tpath.segments.slice(0, -1),\n\t);\n\tif (containers === null) return null;\n\tconst last = path.segments[path.segments.length - 1] as string;\n\tconst held = path.root === 'parent' && last === 'id';\n\tconst targets: Target[] = [];\n\tfor (const container of containers) {\n\t\tfor (const value of spread((container as Record<string, unknown>)[last])) {\n\t\t\tconst id = idOf(value);\n\t\t\tif (id === null) return null;\n\t\t\ttargets.push({ id, holder: held ? (container as object) : null });\n\t\t}\n\t}\n\treturn path.root === 'parent' && targets.length === 0 ? null : targets;\n}\n\n/** The values `segments` reach from `values`, a list read as its elements. */\nfunction walk(\n\tvalues: readonly unknown[],\n\tsegments: readonly string[],\n): readonly unknown[] | null {\n\tlet current = values;\n\tfor (const segment of segments) {\n\t\tconst next: unknown[] = [];\n\t\tfor (const value of current) {\n\t\t\tif (typeof value !== 'object' || value === null) return null;\n\t\t\tnext.push(...spread((value as Record<string, unknown>)[segment]));\n\t\t}\n\t\tcurrent = next;\n\t}\n\treturn current.every((value) => typeof value === 'object' && value !== null)\n\t\t? current\n\t\t: null;\n}\n\nfunction spread(value: unknown): readonly unknown[] {\n\treturn Array.isArray(value) ? value.flat(Number.POSITIVE_INFINITY) : [value];\n}\n\n/** An `ID` as graphql-js coerces one: a string, or an integer serialised. */\nfunction idOf(value: unknown): string | null {\n\tif (typeof value === 'string') return value;\n\tif (typeof value === 'number' && Number.isSafeInteger(value)) {\n\t\treturn String(value);\n\t}\n\treturn null;\n}\n",
|
|
@@ -16,10 +19,10 @@
|
|
|
16
19
|
"/**\n * One `@permission`, checked against the model and the field when the schema\n * is built, and turned into what the guard asks at request time. Everything\n * no request could pass is a `TypeError` naming the field.\n */\n\nimport type { PermissionUse } from '../read';\nimport { list, on, PREFIX } from '../words';\nimport {\n\tfieldsOf,\n\ttype ModelLike,\n\tmodelOf,\n\tnamesOf,\n\treachesCondition,\n} from './model';\nimport { type IdPath, parsePath } from './path';\n\n/** `useJanus({ loaders })`'s entry: the object of a type, by id, or `null`. */\nexport type Loader = (id: string, ctx: unknown) => unknown;\n/** `useJanus({ conditions })`'s entry: the `ctx` a type's conditions test. */\nexport type Condition = (object: unknown, ctx: unknown) => unknown;\n\n/** What `@permission` reads from `useJanus()`'s options. */\nexport interface PermissionWiring {\n\treadonly access?: unknown;\n\treadonly loaders?: { readonly [type: string]: unknown } | undefined;\n\treadonly conditions?: { readonly [type: string]: unknown } | undefined;\n}\n\n/** One `@permission`, as the guard asks it. */\nexport interface PermissionCheck {\n\t/** `@permission on Record (read by Record.title)`, for the messages. */\n\treadonly label: string;\n\treadonly name: string;\n\treadonly type: string;\n\treadonly onDeny: 'NOT_FOUND' | 'FORBIDDEN';\n\treadonly path: IdPath;\n\t/** Loads an object named by id alone; `null` passes `{ type, id }`. */\n\treadonly load: Loader | null;\n\t/** Answers the check's `ctx`; `null` when no condition is reachable. */\n\treadonly condition: Condition | null;\n}\n\n/** The field a directive is read for: `Type.field`, and the arguments it takes. */\nexport interface FieldShape {\n\treadonly name: string;\n\treadonly args: readonly string[];\n}\n\n/** `use`, checked, or a `TypeError` naming the field. */\nexport function permissionCheckOf(\n\tuse: PermissionUse,\n\tfield: FieldShape,\n\twiring: PermissionWiring,\n): PermissionCheck {\n\tconst label = `@permission on ${on(use.where, field.name)}`;\n\tconst refuse = (why: string) => new TypeError(`${PREFIX}: ${label} ${why}`);\n\tconst model = modelOf(wiring.access);\n\tif (model === null) {\n\t\tthrow refuse(\n\t\t\t'needs the permissions() instance — pass useJanus({ auth, access }), with access what permissions() answered',\n\t\t);\n\t}\n\tcheckNames(model, use, refuse);\n\tconst text = use.id ?? (use.onType ? 'parent.id' : 'args.id');\n\tconst path = parsePath(text);\n\tif (path === null) {\n\t\tthrow refuse(\n\t\t\t`reads its id from '${text}', which is not args.<name> or parent.<name>`,\n\t\t);\n\t}\n\tconst [first] = path.segments;\n\tif (path.root === 'args' && !field.args.includes(first as string)) {\n\t\tthrow refuse(\n\t\t\t`reads ${path.root}.${first}, and ${field.name} takes no argument ${first}${\n\t\t\t\tuse.id === null && use.onType === false\n\t\t\t\t\t? ' — name the id with id: \"parent.<field>\" or id: \"args.<name>\"'\n\t\t\t\t\t: ''\n\t\t\t}`,\n\t\t);\n\t}\n\treturn {\n\t\tlabel,\n\t\tname: use.name,\n\t\ttype: use.type,\n\t\tonDeny: use.onDeny,\n\t\tpath,\n\t\tload: loaderOf(model, use.type, path, wiring, refuse),\n\t\tcondition: conditionOf(model, use, wiring, refuse),\n\t};\n}\n\ntype Refuse = (why: string) => TypeError;\n\nfunction checkNames(model: ModelLike, use: PermissionUse, refuse: Refuse) {\n\tif (!model.types.includes(use.type)) {\n\t\tthrow refuse(\n\t\t\t`names the object type '${use.type}', which is not one of ${list(model.types)}`,\n\t\t);\n\t}\n\tconst names = namesOf(model, use.type);\n\tif (!names.includes(use.name)) {\n\t\tthrow refuse(\n\t\t\t`asks '${use.name}', which ${use.type} does not declare — it declares ${list(names)}`,\n\t\t);\n\t}\n}\n\n/** The loader a check needs: its type's, required when the object is named by id alone and reads its own fields. */\nfunction loaderOf(\n\tmodel: ModelLike,\n\ttype: string,\n\tpath: IdPath,\n\twiring: PermissionWiring,\n\trefuse: Refuse,\n): Loader | null {\n\tconst load = wiring.loaders?.[type];\n\tif (load !== undefined && typeof load !== 'function') {\n\t\tthrow refuse(`finds loaders.${type}, which is not a function`);\n\t}\n\tconst held = path.root === 'parent' && path.segments.at(-1) === 'id';\n\tif (held) return null;\n\tif (load !== undefined) return load as Loader;\n\tconst fields = fieldsOf(model, type);\n\tif (fields.length > 0) {\n\t\tthrow refuse(\n\t\t\t`reads the ${type}'s id from ${path.text}, and ${type} reads ${list(fields)} of the object itself (fromField) — pass useJanus({ loaders: { ${type}: (id, ctx) => … } })`,\n\t\t);\n\t}\n\treturn null;\n}\n\n/** The type's `conditions` entry, required when the permission reaches a `when`. */\nfunction conditionOf(\n\tmodel: ModelLike,\n\tuse: PermissionUse,\n\twiring: PermissionWiring,\n\trefuse: Refuse,\n): Condition | null {\n\tif (!reachesCondition(model, use.type, use.name)) return null;\n\tconst condition = wiring.conditions?.[use.type];\n\tif (typeof condition !== 'function') {\n\t\tthrow refuse(\n\t\t\t`asks '${use.name}' of ${use.type}, which reaches a when() — pass useJanus({ conditions: { ${use.type}: (object, ctx) => … } })`,\n\t\t);\n\t}\n\treturn condition as Condition;\n}\n",
|
|
17
20
|
"/**\n * Decides, when the schema is built, what the directives on one field add up\n * to — and refuses with a `TypeError` what no request could ever pass: a user\n * type `auth` does not know, a `type: []`, restrictions that exclude each\n * other, a `@fresh` whose `maxAge` is not above zero, or a `@permission` the\n * model, the field or the wiring cannot answer (`permission/validate.ts`).\n */\n\nimport {\n\ttype FieldShape,\n\ttype PermissionCheck,\n\ttype PermissionWiring,\n\tpermissionCheckOf,\n} from './permission/validate';\nimport type { AuthenticatedUse, FieldDirectives, FreshUse } from './read';\nimport { list, on, PREFIX } from './words';\n\n/** What a field requires before its resolver runs. */\nexport interface Requirement {\n\t/** `Type.field`, for the messages. */\n\treadonly where: string;\n\t/** The directive a missing `ctx.janus` is reported against. */\n\treadonly label: string;\n\t/**\n\t * The user types allowed, every `type:` intersected; `null` when none\n\t * narrows it: any signed-in user.\n\t */\n\treadonly types: ReadonlySet<string> | null;\n\t/**\n\t * How long ago, in milliseconds, the session may have proved who it is at\n\t * most — the smallest `@fresh` that applies; `null` when none does.\n\t */\n\treadonly maxAgeMs: number | null;\n\t/** The permissions asked after that, in order: every one must hold. */\n\treadonly permissions: readonly PermissionCheck[];\n}\n\n/** The user types a schema may name: `auth.types`, or the one `useJanus({ type })` keeps. */\nexport interface Known {\n\treadonly types: readonly string[];\n}\n\n/**\n * The requirement of one field, or `null` when nothing guards it. Throws a\n * `TypeError` naming the field for a directive no request could pass.\n */\nexport function requirementOf(\n\tfield: FieldShape,\n\tdirectives: FieldDirectives,\n\tknown: Known,\n\twiring: PermissionWiring,\n): Requirement | null {\n\tconst { authenticated, fresh, permission } = directives;\n\tconst [name, first] = firstOf(directives);\n\tif (first === undefined) return null;\n\treturn {\n\t\twhere: field.name,\n\t\tlabel: `${name} on ${on(first.where, field.name)}`,\n\t\ttypes: typesOf(field.name, authenticated, known),\n\t\tmaxAgeMs: maxAgeOf(field.name, fresh),\n\t\tpermissions: permission.map((use) => permissionCheckOf(use, field, wiring)),\n\t};\n}\n\n/** Every `type:` intersected, or `null` when none names any. */\nfunction typesOf(\n\tfield: string,\n\tuses: readonly AuthenticatedUse[],\n\tknown: Known,\n): ReadonlySet<string> | null {\n\tlet types: Set<string> | null = null;\n\tfor (const { where, types: named } of uses) {\n\t\tif (named === null) continue;\n\t\tif (named.length === 0) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`${PREFIX}: @authenticated on ${on(where, field)} names no user type — leave type: out to admit any signed-in user`,\n\t\t\t);\n\t\t}\n\t\tfor (const name of named) {\n\t\t\tif (!known.types.includes(name)) {\n\t\t\t\tthrow new TypeError(\n\t\t\t\t\t`${PREFIX}: @authenticated on ${on(where, field)} names the user type '${name}', which is not one of ${list(known.types)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\ttypes =\n\t\t\ttypes === null\n\t\t\t\t? new Set(named)\n\t\t\t\t: new Set(named.filter((name) => types?.has(name)));\n\t}\n\tif (types !== null && types.size === 0) {\n\t\tthrow new TypeError(\n\t\t\t`${PREFIX}: the @authenticated on ${field} and on its type or interfaces admit no user type in common`,\n\t\t);\n\t}\n\treturn types;\n}\n\n/** The directive a missing `ctx.janus` is reported against: the first checked. */\nfunction firstOf({\n\tauthenticated,\n\tfresh,\n\tpermission,\n}: FieldDirectives): readonly [string, { readonly where: string } | undefined] {\n\tif (authenticated.length > 0) return ['@authenticated', authenticated[0]];\n\tif (fresh.length > 0) return ['@fresh', fresh[0]];\n\treturn ['@permission', permission[0]];\n}\n\n/** The smallest `maxAge`, in milliseconds, or `null` when no `@fresh` applies. */\nfunction maxAgeOf(field: string, uses: readonly FreshUse[]): number | null {\n\tlet seconds: number | null = null;\n\tfor (const { where, maxAge } of uses) {\n\t\tif (!Number.isSafeInteger(maxAge) || maxAge <= 0) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`${PREFIX}: @fresh on ${on(where, field)} asks maxAge: ${maxAge} — write a number of seconds above zero, such as maxAge: 600 for ten minutes`,\n\t\t\t);\n\t\t}\n\t\tseconds = seconds === null ? maxAge : Math.min(seconds, maxAge);\n\t}\n\treturn seconds === null ? null : seconds * 1000;\n}\n",
|
|
18
21
|
"/**\n * The two calls a resolver makes itself: `requireUser` where a directive\n * would not do, and `can` for a check the schema cannot express.\n */\n\nimport type {\n\tCheckArgs,\n\tCheckableOf,\n\tModelConfig,\n\tObjectRef,\n\tObjectTypeOf,\n\tPermissions,\n} from '@nxgt/janus/permissions';\nimport { checkOf, janusOf } from './context';\nimport { denial, rethrown } from './errors';\n\n/** What `requireUser()` takes. */\nexport interface RequireUserOptions<T extends string> {\n\t/**\n\t * Only a user of this type, or of one of these — never an empty list,\n\t * which no user could pass: any other is `FORBIDDEN`.\n\t */\n\treadonly type?: T | readonly [T, ...T[]];\n}\n\n/**\n * The signed-in user, narrowed to `type` when it is given — or a denial:\n * `UNAUTHENTICATED` 401 for an anonymous request, `FORBIDDEN` 403 for a user\n * of another type. A store that cannot answer is `SERVICE_UNAVAILABLE` 503,\n * never either of them.\n *\n * ```ts\n * const staff = await requireUser(ctx, { type: 'staff' });\n * staff.username; // typed: a staff member\n * ```\n */\nexport async function requireUser<\n\tU extends { readonly type: string },\n\tconst T extends U['type'] = U['type'],\n>(\n\tctx: { readonly janus: { user(): Promise<U | null> } },\n\toptions: RequireUserOptions<T> = {},\n): Promise<Extract<U, { readonly type: T }>> {\n\tconst { type } = options;\n\tconst allowed: readonly string[] | undefined =\n\t\ttypeof type === 'string' ? [type] : type;\n\tif (allowed?.length === 0) {\n\t\tthrow new TypeError(\n\t\t\t'requireUser(): type is an empty list, which no user could pass — name at least one user type, or leave type out',\n\t\t);\n\t}\n\tconst user = await janusOf(ctx, 'requireUser()')\n\t\t.user()\n\t\t.then(undefined, rethrown);\n\tif (user === null) throw denial('UNAUTHENTICATED');\n\tif (allowed !== undefined && !allowed.includes(user.type)) {\n\t\tthrow denial('FORBIDDEN');\n\t}\n\treturn user as unknown as Extract<U, { readonly type: T }>;\n}\n\n/**\n * Whether the request's user holds `permission` on `object`, typed as\n * `access.can` is: the permission must be one the object's type declares,\n * the object must carry every field its `fromField`s read, and `{ ctx }` is\n * required exactly when a condition is reachable. Anonymous answers `false`.\n *\n * **A failure throws**: a store that cannot answer is `SERVICE_UNAVAILABLE`\n * 503, never `false`.\n *\n * ```ts\n * if (!(await can(ctx, 'edit', { type: 'record', ...record }))) return null;\n * ```\n */\nexport async function can<\n\tC extends ModelConfig,\n\tconst T extends ObjectTypeOf<C>,\n\tconst P extends CheckableOf<C, T>,\n>(\n\tctx: {\n\t\treadonly janus: {\n\t\t\tuser(): Promise<{ readonly type: string; readonly id: string } | null>;\n\t\t\treadonly access: Pick<Permissions<C>, 'can'>;\n\t\t};\n\t},\n\tpermission: P,\n\tobject: ObjectRef<C, T>,\n\t...options: CheckArgs<C, T, P>\n): Promise<boolean> {\n\tconst janus = janusOf(ctx, 'can()');\n\tconst check = checkOf(janus);\n\tif (check === null) {\n\t\tthrow new TypeError(\n\t\t\t'can(): ctx.janus.access is not set — pass { access } to useJanus()',\n\t\t);\n\t}\n\tconst subject = await janus.user().then(undefined, rethrown);\n\treturn check(subject, permission, object, options[0]).then(\n\t\tundefined,\n\t\trethrown,\n\t);\n}\n",
|
|
19
|
-
"/**\n * `useJanus()`, the envelop plugin — for Yoga, or any server built on\n * envelop.\n */\n\nimport type { Plugin } from '@envelop/core';\nimport type { RequestLike } from '@nxgt/janus';\nimport type { GraphQLSchema } from 'graphql';\nimport { createJanusContext } from './context';\nimport { applyJanusDirectives } from './directives/apply';\nimport type { Auth, JanusContext, JanusOptions, UserOfAuth } from './types';\n\n/**\n * The plugin that wires `@nxgt/janus` into a GraphQL server:\n *\n * - every request's context gets `ctx.janus` — `user()` and `session()`,\n * authenticated lazily and once, and `access` when it is given;\n * - every schema the server is given has its directives applied, once, by\n * `applyJanusDirectives()`.\n *\n * ```ts\n * createYoga({\n * schema: createSchema({ typeDefs: [janusTypeDefs, typeDefs], resolvers }),\n * plugins: [useJanus({ auth, access })],\n * maskedErrors: { maskError: janusMaskError() },\n * });\n * ```\n *\n * `type` treats a user of any other type as anonymous, as\n * `auth.authenticate(request, { type })` does. `clock` is what `@fresh` and\n * `requireFresh()` read the time from — the one given to `janus()`.\n * `loaders` and `conditions` are what `@permission` needs beside `access`:\n * the objects it checks by id, and the `ctx` of the conditions it reaches.\n */\nexport function useJanus<\n\tA extends Auth<{ readonly type: string; readonly id: string }>,\n\tP extends object | undefined = undefined,\n\tconst T extends UserOfAuth<A>['type'] = UserOfAuth<A>['type'],\n>(options: JanusOptions<A, P, T>): Plugin<JanusContext<A, P, T>> {\n\tconst { auth, access, type, clock, loaders, conditions } = options;\n\
|
|
22
|
+
"/**\n * `useJanus()`, the envelop plugin — for Yoga, or any server built on\n * envelop.\n */\n\nimport type { Plugin } from '@envelop/core';\nimport type { RequestLike } from '@nxgt/janus';\nimport type { GraphQLSchema } from 'graphql';\nimport { acceptedOf } from './connection/credential';\nimport { createJanusContext } from './context';\nimport { applyJanusDirectives } from './directives/apply';\nimport { checkWiring } from './options';\nimport type { Auth, JanusContext, JanusOptions, UserOfAuth } from './types';\n\n/**\n * The plugin that wires `@nxgt/janus` into a GraphQL server:\n *\n * - every request's context gets `ctx.janus` — `user()` and `session()`,\n * authenticated lazily and once, and `access` when it is given;\n * - every schema the server is given has its directives applied, once, by\n * `applyJanusDirectives()`.\n *\n * ```ts\n * createYoga({\n * schema: createSchema({ typeDefs: [janusTypeDefs, typeDefs], resolvers }),\n * plugins: [useJanus({ auth, access })],\n * maskedErrors: { maskError: janusMaskError() },\n * });\n * ```\n *\n * `type` treats a user of any other type as anonymous, as\n * `auth.authenticate(request, { type })` does. `clock` is what `@fresh` and\n * `requireFresh()` read the time from — the one given to `janus()`.\n * `loaders` and `conditions` are what `@permission` needs beside `access`:\n * the objects it checks by id, and the `ctx` of the conditions it reaches.\n *\n * An operation over graphql-ws has no request: its `ctx.janus`\n * authenticates the credential its connection presented, once\n * `janusConnection().onConnect` accepted it.\n */\nexport function useJanus<\n\tA extends Auth<{ readonly type: string; readonly id: string }>,\n\tP extends object | undefined = undefined,\n\tconst T extends UserOfAuth<A>['type'] = UserOfAuth<A>['type'],\n>(options: JanusOptions<A, P, T>): Plugin<JanusContext<A, P, T>> {\n\tconst { auth, access, type, clock, loaders, conditions } = options;\n\tcheckWiring('useJanus()', { auth, access, clock });\n\tconst applied = new WeakSet<GraphQLSchema>();\n\n\treturn {\n\t\tonContextBuilding: ({ context, extendContext }) => {\n\t\t\tconst { request } = context as { readonly request?: RequestLike };\n\t\t\tconst janus = createJanusContext(request ?? acceptedOf(context), {\n\t\t\t\tauth,\n\t\t\t\taccess: access as { readonly can: unknown } | undefined,\n\t\t\t\ttype,\n\t\t\t\tclock,\n\t\t\t});\n\t\t\textendContext({ janus } as unknown as Partial<JanusContext<A, P, T>>);\n\t\t},\n\t\t// `replaceSchema` calls this hook again with the schema it was given:\n\t\t// the one it made is remembered, or it would transform it for ever.\n\t\tonSchemaChange: ({ schema, replaceSchema }) => {\n\t\t\tif (applied.has(schema)) return;\n\t\t\tconst next = applyJanusDirectives(schema, {\n\t\t\t\tauth,\n\t\t\t\t...(type === undefined ? {} : { type }),\n\t\t\t\taccess: access as { readonly model: unknown } | undefined,\n\t\t\t\tloaders,\n\t\t\t\tconditions,\n\t\t\t});\n\t\t\tapplied.add(next);\n\t\t\treplaceSchema(next);\n\t\t},\n\t};\n}\n",
|
|
20
23
|
"/**\n * The directives and the enum this package reads, as SDL: put it beside your\n * own type definitions. The same text ships as `graphql/janus.graphqls`, for\n * a code generator or an editor that reads files — `sdl.spec.ts` holds that\n * the two are identical.\n *\n * ```ts\n * createSchema({ typeDefs: [janusTypeDefs, typeDefs], resolvers });\n * ```\n */\nexport const janusTypeDefs: string = `\"\"\"\nOnly a signed-in user reaches this field, or every field of this type or\ninterface. With \\`type\\`, only a user of one of these user types: any other is\nanswered FORBIDDEN.\n\"\"\"\ndirective @authenticated(\n\ttype: [String!]\n) on OBJECT | INTERFACE | FIELD_DEFINITION\n\n\"\"\"\nOnly a session that proved who it is less than \\`maxAge\\` seconds ago reaches\nthis field, or every field of this type or interface: signed in, or confirmed\nsince by a step-up. Anonymous is answered UNAUTHENTICATED, an older session\nSTEP_UP_REQUIRED. Where several apply, the smallest \\`maxAge\\` holds.\n\"\"\"\ndirective @fresh(maxAge: Int!) on OBJECT | INTERFACE | FIELD_DEFINITION\n\n\"\"\"\nWhat a denied \\`@permission\\` answers.\n\"\"\"\nenum JanusPermissionDenial {\n\t\"\"\"\n\t404: the object is not told to exist. The default.\n\t\"\"\"\n\tNOT_FOUND\n\t\"\"\"\n\t403: the object exists, and this user may not do this to it.\n\t\"\"\"\n\tFORBIDDEN\n}\n\n\"\"\"\nOnly a user holding permission \\`name\\` on the object of \\`type\\` whose id \\`id\\`\nreads reaches this field, or every field of this type or interface. \\`id\\` is\n\\`args.<path>\\` or \\`parent.<path>\\`: \\`args.id\\` on a field and \\`parent.id\\` on a\ntype or an interface when absent. A list of ids requires the permission on\nevery one. Repeated, every one must hold, in the order written.\n\"\"\"\ndirective @permission(\n\tname: String!\n\ttype: String!\n\tid: String\n\tonDeny: JanusPermissionDenial! = NOT_FOUND\n) repeatable on OBJECT | INTERFACE | FIELD_DEFINITION\n`;\n"
|
|
21
24
|
],
|
|
22
|
-
"mappings": "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",
|
|
23
|
-
"debugId": "
|
|
25
|
+
"mappings": ";AAMA;AAAA;AAAA;;;ACaA,IAAM,WAAW;AAQjB,SAAS,KAAK,CACb,SACA,YACA,QACA,SACgB;AAAA,EAChB,IAAI,YAAY,QAAQ,SAAS,QAAQ;AAAA,IAAW,OAAO;AAAA,EAC3D,IAAI,SAAS,KAAK,OAAO,EAAE,KAAK,SAAS,KAAK,QAAQ,EAAE;AAAA,IAAG,OAAO;AAAA,EAClE,MAAM,MACL,OAAO,QAAQ,aAAa,WAAW,IAAI,QAAQ,aAAa;AAAA,EACjE,OAAO,GAAG,OAAO,QAAQ,OAAO,MAAM,cAAc,QAAQ,QAAQ,QAAQ,KAAK;AAAA;AAS3E,SAAS,QAAQ,CAAC,QAA0C;AAAA,EAClE,MAAM,MAAM,OAAO;AAAA,EACnB,MAAM,UAAU,IAAI;AAAA,EACpB,MAAM,MAAa,OAAO,SAAS,YAAY,QAAQ,YACtD,IAAI,KAAK,QAAQ,SAAS,YAAY,QAAQ,OAAO;AAAA,EACtD,OAAO,CAAC,SAAS,YAAY,QAAQ,YAAY;AAAA,IAChD,MAAM,MAAM,MAAM,SAAS,YAAY,QAAQ,OAAO;AAAA,IACtD,IAAI,QAAQ;AAAA,MAAM,OAAO,IAAI,SAAS,YAAY,QAAQ,OAAO;AAAA,IACjE,MAAM,QAAQ,QAAQ,IAAI,GAAG;AAAA,IAC7B,IAAI,UAAU;AAAA,MAAW,OAAO;AAAA,IAChC,MAAM,SAAS,IAAI,SAAS,YAAY,QAAQ,OAAO;AAAA,IACvD,QAAQ,IAAI,KAAK,MAAM;AAAA,IACvB,OAAO,KAAK,WAAW,MAAM,QAAQ,OAAO,GAAG,CAAC;AAAA,IAChD,OAAO;AAAA;AAAA;;;ADlBT,IAAM,SAAS,IAAI;AAGnB,IAAM,SAAS,IAAI;AAsBZ,SAAS,kBAAkB,CACjC,SACA,SACQ;AAAA,EACR,QAAQ,MAAM,QAAQ,MAAM,OAAO,SAAS,iBAAiB;AAAA,EAC7D,IAAI;AAAA,EACJ,IAAI,QAAQ;AAAA,EACZ,MAAM,gBAAgB,MAAM;AAAA,IAC3B,IAAI,CAAC,OAAO;AAAA,MACX,QAAQ;AAAA,MACR,SACC,YAAY,YACT,QAAQ,OACR,IAAI,UACH,GAAG,yKACJ,CACD,IACC,KAAK,aACL,SACA,SAAS,YAAY,YAAY,EAAE,KAAK,CACzC;AAAA,IACJ;AAAA,IACA,OAAO;AAAA;AAAA,EAGR,MAAM,QAAQ,OAAO,OAAO;AAAA,IAC3B,MAAM,MAAM,cAAc,EAAE,KAAK,CAAC,YAAY,SAAS,QAAQ,IAAI;AAAA,IACnE,SAAS,MAAM,cAAc,EAAE,KAAK,CAAC,YAAY,SAAS,WAAW,IAAI;AAAA,OACrE,WAAW,YAAY,CAAC,IAAI,EAAE,OAAO;AAAA,EAC1C,CAAC;AAAA,EACD,IAAI,WAAW,WAAW;AAAA,IACzB,MAAM,MAAM,OAAO;AAAA,IACnB,OAAO,IAAI,OAAO;AAAA,MACjB,MAAM,SAAS,MAAM;AAAA,MACrB,OAAO,IAAI,SAAS,IAAI,MAAM,QAAQ,IAAI;AAAA,IAC3C,CAAC;AAAA,EACF;AAAA,EACA,IAAI,UAAU;AAAA,IAAW,OAAO,IAAI,OAAO,KAAK;AAAA,EAChD,OAAO;AAAA;AAOD,SAAS,OAAO,CAAC,OAAsB;AAAA,EAC7C,OAAO,OAAO,IAAI,KAAK,KAAK;AAAA;AAYtB,SAAS,OAAO,CAAC,OAAe,QAAQ,OAAqB;AAAA,EACnE,MAAM,QAAQ,OAAO,IAAI,KAAK;AAAA,EAC9B,IAAI,UAAU;AAAA,IAAW,OAAO,QAAQ,MAAM,QAAQ,MAAM;AAAA,EAC5D,MAAM,SAAU,MACd;AAAA,EACF,OAAO,OAAO,QAAQ,QAAQ,aAAc,OAAO,MAAgB;AAAA;AAO7D,SAAS,OAAO,CAAC,KAAc,QAAuB;AAAA,EAC5D,MAAM,QAAS,KAA2C;AAAA,EAC1D,IAAI,UAAU,aAAa,OAAO,MAAM,SAAS,YAAY;AAAA,IAC5D,MAAM,IAAI,UACT,GAAG,sEACJ;AAAA,EACD;AAAA,EACA,OAAO;AAAA;;;AE9HD,SAAS,WAAW,CAAC,UAAkB,MAAM,QAAQ,SAAiB;AAAA,EAC5E,IACC,OAAQ,MACL,iBAAiB,YACnB;AAAA,IACD,MAAM,IAAI,UACT,GAAG,2DACJ;AAAA,EACD;AAAA,EACA,IACC,WAAW,aACX,OAAQ,QAA8C,QAAQ,YAC7D;AAAA,IACD,MAAM,IAAI,UACT,GAAG,2EACJ;AAAA,EACD;AAAA,EACA,IACC,UAAU,aACV,OAAQ,OAA6C,QAAQ,YAC5D;AAAA,IACD,MAAM,IAAI,UACT,GAAG,sGACJ;AAAA,EACD;AAAA;;;AC5BD,IAAM,SAAS;AAkBR,SAAS,YAAY,CAC3B,KACA,SACqB;AAAA,EACrB,MAAM,SAAS,IAAI;AAAA,EACnB,IAAI,WAAW,aAAa,OAAO,OAAO,QAAQ,eAAe,GAAG;AAAA,IACnE,QAAQ,kBAAkB;AAAA,IAC1B,IAAI,OAAO,kBAAkB;AAAA,MAAU,OAAO;AAAA,IAG9C,IAAI,OAAO,KAAK,aAAa;AAAA,MAAG,OAAO,EAAE,cAAc;AAAA,EACxD;AAAA,EACA,MAAM,UACL,YAAY,YACR,IAAI,OAAqD,UAC1D,QAAQ,GAAG;AAAA,EACf,OAAO,WAAW;AAAA;AAUnB,IAAM,WAAW,IAAI;AAGd,SAAS,MAAM,CAAC,KAAwB,YAAyB;AAAA,EACvE,QAAQ,UAAU;AAAA,EAClB,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAAA,IAChD,MAAM,IAAI,UACT,yGACD;AAAA,EACD;AAAA,EACA,SAAS,IAAI,OAAO,UAAU;AAAA;AAOxB,SAAS,UAAU,CAAC,SAA2C;AAAA,EACrE,MAAM,QAAS,SAAiD;AAAA,EAChE,IAAI,OAAO,UAAU,YAAY,UAAU;AAAA,IAAM;AAAA,EACjD,OAAO,SAAS,IAAI,KAAK;AAAA;;;ACzCnB,SAAS,eAIf,CAAC,SAAoE;AAAA,EACrE,QAAQ,MAAM,QAAQ,MAAM,UAAU;AAAA,EACtC,YAAY,qBAAqB,EAAE,MAAM,QAAQ,MAAM,CAAC;AAAA,EACxD,IAAI,QAAQ,YAAY,aAAa,OAAO,QAAQ,YAAY,YAAY;AAAA,IAC3E,MAAM,IAAI,UACT,6HACD;AAAA,EACD;AAAA,EACA,MAAM,UAAU,QAAQ,SAAS,KAAK,OAAO;AAAA,EAC7C,MAAM,SAAS;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,EACT;AAAA,EAEA,OAAO;AAAA,IACN,WAAW,OAAO,QAAQ;AAAA,MACzB,MAAM,aAAa,aAAa,KAAK,OAAO;AAAA,MAC5C,IAAI,eAAe;AAAA,QAAM,OAAO;AAAA,MAGhC,MAAM,UAAU,MAAM,KAAK,aAC1B,YACA,SAAS,YAAY,YAAY,EAAE,KAAK,CACzC;AAAA,MACA,IAAI,YAAY;AAAA,QAAM,OAAO;AAAA,MAC7B,OAAO,KAAK,UAAU;AAAA,MACtB,OAAO;AAAA;AAAA,IAGR,SAAS,CAAC,SACR;AAAA,MACA,OAAO,mBAAmB,WAAW,GAAG,GAAG,MAAM;AAAA,IAClD;AAAA,EACF;AAAA;;ACvED;AACA;;;ACCA;AACA;AAMO,SAAS,MAAM,CAAC,MAAkB,SAAgC;AAAA,EACxE,OAAO,QAAQ,YAAY,SAAS,IAAI;AAAA,EACxC,OAAO,IAAI,aAAa,WAAW,UAAU;AAAA,IAC5C,YAAY,EAAE,MAAM,MAAM,EAAE,OAAO,EAAE;AAAA,EACtC,CAAC;AAAA;AAGF,SAAS,QAAQ,CAAC,MAA6C;AAAA,EAC9D,QAAQ;AAAA,SACF;AAAA,MACJ,OAAO,CAAC,KAAK,eAAe;AAAA,SACxB;AAAA,MACJ,OAAO,CAAC,KAAK,WAAW;AAAA,SACpB;AAAA,MACJ,OAAO,CAAC,KAAK,WAAW;AAAA;AAAA;AAYpB,SAAS,iBAAiB,CAAC,OAAiC;AAAA,EAClE,MAAM,SAAS,SAAS,MAAM,IAAI;AAAA,EAClC,MAAM,OACL,MAAM,SAAS,iBAAiB,wBAAwB,MAAM;AAAA,EAC/D,OAAO,IAAI,aAAa,UAAU,MAAM,GAAG;AAAA,IAC1C,eAAe;AAAA,IACf,YAAY,EAAE,MAAM,MAAM,EAAE,OAAO,MAAM,WAAW,KAAK,EAAE;AAAA,EAC5D,CAAC;AAAA;AAOF,SAAS,SAAS,CAAC,QAAkC;AAAA,EACpD,QAAQ;AAAA,SACF;AAAA,MACJ,OAAO;AAAA,SACH;AAAA,MACJ,OAAO;AAAA,SACH;AAAA,MACJ,OAAO;AAAA,SACH;AAAA,MACJ,OAAO;AAAA,SACH;AAAA,MACJ,OAAO;AAAA,SACH;AAAA,MACJ,OAAO;AAAA,SACH;AAAA,SACA;AAAA,MACJ,OAAO;AAAA;AAAA;AAKV,SAAS,UAAU,CAAC,OAA4C;AAAA,EAC/D,QAAQ,MAAM;AAAA,SACR;AAAA,MACJ,OAAO,EAAE,QAAQ,MAAM,UAAU,CAAC,EAAE;AAAA,SAChC;AAAA,MACJ,OAAO,MAAM,cAAc,YACxB,CAAC,IACD,EAAE,WAAW,MAAM,UAAU;AAAA,SAC5B;AAAA,MACJ,OAAO,MAAM,iBAAiB,YAC3B,CAAC,IACD,EAAE,cAAc,MAAM,aAAa;AAAA;AAAA,MAEtC,OAAO,CAAC;AAAA;AAAA;AAQJ,SAAS,QAAQ,CAAC,OAAuB;AAAA,EAC/C,MAAM,iBAAiB,aAAa,kBAAkB,KAAK,IAAI;AAAA;AAwBzD,SAAS,cAAc,CAAC,WAAsB,QAAmB;AAAA,EACvE,OAAO,CAAC,OAAO,SAAS,UAAU;AAAA,IACjC,MAAM,WACL,iBAAiB,eAAe,MAAM,gBAAgB;AAAA,IACvD,IAAI,oBAAoB,YAAY;AAAA,MACnC,MAAM,SAAS,kBAAkB,QAAQ;AAAA,MACzC,OAAO,iBAAiB,eACrB,IAAI,aAAa,OAAO,SAAS;AAAA,QACjC,OAAO,MAAM,SAAS;AAAA,QACtB,MAAM,MAAM,QAAQ;AAAA,QACpB,eAAe;AAAA,QACf,YAAY,OAAO;AAAA,MACpB,CAAC,IACA;AAAA,IACJ;AAAA,IACA,OAAO,SAAS,OAAO,SAAS,KAAK;AAAA;AAAA;AAKvC,SAAS,MAAM,CAAC,OAAgB,SAAwB;AAAA,EACvD,IAAI,iBAAiB,cAAc;AAAA,IAClC,MAAM,WAAW,MAAM;AAAA,IACvB,IAAI,aAAa,aAAa,oBAAoB,cAAc;AAAA,MAC/D,OAAO;AAAA,IACR;AAAA,IACA,OAAO,IAAI,aAAa,SAAS;AAAA,MAChC,OAAO,MAAM,SAAS;AAAA,MACtB,MAAM,MAAM,QAAQ;AAAA,MACpB,YAAY,EAAE,MAAM,wBAAwB;AAAA,IAC7C,CAAC;AAAA,EACF;AAAA,EACA,OAAO,IAAI,aAAa,SAAS;AAAA,IAChC,YAAY,EAAE,MAAM,wBAAwB;AAAA,EAC7C,CAAC;AAAA;;;ACpJF;AAAA;AAAA;AAAA;AAeA,eAAsB,YAAY,CACjC,OACA,UACmB;AAAA,EACnB,MAAM,UAAU,MAAM,MAAM,QAAQ,EAAE,KAAK,WAAW,QAAQ;AAAA,EAC9D,IAAI,YAAY;AAAA,IAAM,MAAM,OAAO,iBAAiB;AAAA,EACpD,IAAI;AAAA,IACH,YAAY,SAAS,UAAU,QAAQ,KAAK,CAAC;AAAA,IAC5C,OAAO,OAAO;AAAA,IACf,SAAS,KAAK;AAAA;AAAA,EAEf,OAAO;AAAA;AAiBR,eAAsB,YAAY,CACjC,KAMA,QACmB;AAAA,EACnB,IAAI,OAAO,WAAW,UAAU;AAAA,IAC/B,MAAM,IAAI,UACT,qIACD;AAAA,EACD;AAAA,EACA,MAAM,WAAW,cAAc,QAAQ,wBAAwB;AAAA,EAC/D,OAAO,aAAa,QAAQ,KAAK,gBAAgB,GAAG,QAAQ;AAAA;;;AClD7D,IAAM,OAAO;AAGN,SAAS,SAAS,CAAC,MAA6B;AAAA,EACtD,OAAO,SAAS,YAAY,KAAK,MAAM,GAAG;AAAA,EAC1C,IAAI,SAAS,UAAU,SAAS;AAAA,IAAU,OAAO;AAAA,EACjD,IAAI,SAAS,WAAW,KAAK,CAAC,SAAS,MAAM,CAAC,SAAS,KAAK,KAAK,IAAI,CAAC,GAAG;AAAA,IACxE,OAAO;AAAA,EACR;AAAA,EACA,OAAO,EAAE,MAAM,MAAM,SAAS;AAAA;AAkBxB,SAAS,SAAS,CACxB,MACA,QACA,MAC2B;AAAA,EAC3B,MAAM,aAAa,KAClB,CAAC,KAAK,SAAS,SAAS,OAAO,MAAM,GACrC,KAAK,SAAS,MAAM,GAAG,EAAE,CAC1B;AAAA,EACA,IAAI,eAAe;AAAA,IAAM,OAAO;AAAA,EAChC,MAAM,OAAO,KAAK,SAAS,KAAK,SAAS,SAAS;AAAA,EAClD,MAAM,OAAO,KAAK,SAAS,YAAY,SAAS;AAAA,EAChD,MAAM,UAAoB,CAAC;AAAA,EAC3B,WAAW,aAAa,YAAY;AAAA,IACnC,WAAW,SAAS,OAAQ,UAAsC,KAAK,GAAG;AAAA,MACzE,MAAM,KAAK,KAAK,KAAK;AAAA,MACrB,IAAI,OAAO;AAAA,QAAM,OAAO;AAAA,MACxB,QAAQ,KAAK,EAAE,IAAI,QAAQ,OAAQ,YAAuB,KAAK,CAAC;AAAA,IACjE;AAAA,EACD;AAAA,EACA,OAAO,KAAK,SAAS,YAAY,QAAQ,WAAW,IAAI,OAAO;AAAA;AAIhE,SAAS,IAAI,CACZ,QACA,UAC4B;AAAA,EAC5B,IAAI,UAAU;AAAA,EACd,WAAW,WAAW,UAAU;AAAA,IAC/B,MAAM,OAAkB,CAAC;AAAA,IACzB,WAAW,SAAS,SAAS;AAAA,MAC5B,IAAI,OAAO,UAAU,YAAY,UAAU;AAAA,QAAM,OAAO;AAAA,MACxD,KAAK,KAAK,GAAG,OAAQ,MAAkC,QAAQ,CAAC;AAAA,IACjE;AAAA,IACA,UAAU;AAAA,EACX;AAAA,EACA,OAAO,QAAQ,MAAM,CAAC,UAAU,OAAO,UAAU,YAAY,UAAU,IAAI,IACxE,UACA;AAAA;AAGJ,SAAS,MAAM,CAAC,OAAoC;AAAA,EACnD,OAAO,MAAM,QAAQ,KAAK,IAAI,MAAM,KAAK,OAAO,iBAAiB,IAAI,CAAC,KAAK;AAAA;AAI5E,SAAS,IAAI,CAAC,OAA+B;AAAA,EAC5C,IAAI,OAAO,UAAU;AAAA,IAAU,OAAO;AAAA,EACtC,IAAI,OAAO,UAAU,YAAY,OAAO,cAAc,KAAK,GAAG;AAAA,IAC7D,OAAO,OAAO,KAAK;AAAA,EACpB;AAAA,EACA,OAAO;AAAA;;;ACrER,eAAsB,iBAAiB,CACtC,YACA,QACgB;AAAA,EAChB,MAAM,UAAU,UAAU,WAAW,MAAM,OAAO,QAAQ,OAAO,IAAI;AAAA,EACrE,IAAI,YAAY,MAAM;AAAA,IACrB,SAAS,UAAU;AAAA,IACnB,MAAM,OAAO,WAAW;AAAA,EACzB;AAAA,EACA,MAAM,UAAU,MAAM,QAAQ,IAC7B,QAAQ,IAAI,CAAC,WAAW,SAAS,YAAY,QAAQ,OAAO,GAAG,CAAC,CACjE,EAAE,KAAK,WAAW,QAAQ;AAAA,EAC1B,MAAM,QAAQ,QAAQ,OACrB,CAAC,WAAiC,WAAW,IAC9C;AAAA,EACA,IAAI,MAAM,SAAS,QAAQ;AAAA,IAAQ,MAAM,OAAO,WAAW;AAAA,EAC3D,MAAM,UAAU,MAAM,QAAQ,IAC7B,MAAM,IAAI,CAAC,WAAW,IAAI,YAAY,QAAQ,MAAM,CAAC,CACtD,EAAE,KAAK,WAAW,QAAQ;AAAA,EAC1B,IAAI,QAAQ,SAAS,KAAK;AAAA,IAAG,MAAM,OAAO,WAAW,MAAM;AAAA;AAG5D,eAAe,GAAG,CACjB,YACA,UACE,OAAO,MAAM,OACI;AAAA,EACnB,MAAM,UACL,WAAW,cAAc,OACtB,YACA,EAAE,KAAK,MAAM,WAAW,UAAU,QAAQ,GAAG,EAAE;AAAA,EACnD,OAAO,MAAM,MAAM,WAAW,MAAM,QAAQ,OAAO;AAAA;AASpD,IAAM,aAAa;AAQnB,IAAM,aAAa,CAAC,OACnB,CAAC,WAAW,KAAK,EAAE,KAAK,CAAC,GAAG,SAAS,MAAQ,KAAK,GAAG,aAAa;AAOnE,eAAe,QAAQ,CACtB,cACE,IAAI,UACN,KAC6B;AAAA,EAC7B,QAAQ,MAAM,SAAS;AAAA,EACvB,IAAI,CAAC,WAAW,EAAE;AAAA,IAAG,OAAO;AAAA,EAC5B,IAAI,WAAW;AAAA,IAAM,OAAO,KAAK,QAAQ,MAAM,EAAE;AAAA,EACjD,IAAI,SAAS;AAAA,IAAM,OAAO,EAAE,MAAM,GAAG;AAAA,EACrC,MAAM,SAAS,MAAM,KAAK,IAAI,GAAG;AAAA,EACjC,IAAI,WAAW;AAAA,IAAM,OAAO;AAAA,EAC5B,IAAI,OAAO,WAAW,UAAU;AAAA,IAC/B,MAAM,IAAI,UACT,GAAG,WAAW,kBAAkB,iBAAiB,OAAO,wDACzD;AAAA,EACD;AAAA,EACA,OAAO,KAAK,QAAQ,MAAM,EAAE;AAAA;AAa7B,SAAS,IAAI,CAAC,QAAgB,MAAc,IAAwB;AAAA,EACnE,OAAO,IAAI,MAAM,OAAO,OAAO,IAAI,GAAa;AAAA,IAC/C,KAAK,CAAC,GAAG,QACR,QAAQ,SAAS,OAAO,QAAQ,OAAO,KAAK,QAAQ,IAAI,QAAQ,GAAG;AAAA,IACpE,KAAK,CAAC,GAAG,QAAQ,QAAQ,UAAU,QAAQ,IAAI,QAAQ,GAAG;AAAA,EAC3D,CAAC;AAAA;AAGF,IAAM,SAAS,IAAI;AAGnB,SAAS,QAAQ,CAAC,YAAmC;AAAA,EACpD,IAAI,OAAO,IAAI,UAAU;AAAA,IAAG;AAAA,EAC5B,OAAO,IAAI,UAAU;AAAA,EACrB,QAAQ,YACP,GAAG,WAAW,oCAAoC,WAAW,KAAK,6BAClE,EAAE,MAAM,6BAA6B,CACtC;AAAA;;;ACtGD,eAAsB,OAAO,CAC5B,eACE,QAAQ,MAAM,KAAK,SACL;AAAA,EAChB,MAAM,QAAQ,QAAQ,KAAK,YAAY,KAAK;AAAA,EAC5C,MAAM,OAAO,MAAM,MAAM,KAAK,EAAE,KAAK,WAAW,QAAQ;AAAA,EACxD,IAAI,SAAS;AAAA,IAAM,MAAM,OAAO,iBAAiB;AAAA,EACjD,IAAI,YAAY,UAAU,QAAQ,CAAC,YAAY,MAAM,IAAI,KAAK,IAAI,GAAG;AAAA,IACpE,MAAM,OAAO,WAAW;AAAA,EACzB;AAAA,EACA,IAAI,YAAY,aAAa,MAAM;AAAA,IAClC,MAAM,aAAa,OAAO,YAAY,QAAQ;AAAA,EAC/C;AAAA,EACA,OAAO,SAAS,YAAY;AAAA,EAC5B,IAAI,UAAU;AAAA,IAAW;AAAA,EACzB,MAAM,QAAQ,QAAQ,OAAO,KAAK;AAAA,EAClC,IAAI,UAAU,MAAM;AAAA,IACnB,MAAM,IAAI,UACT,GAAG,MAAM,oEACV;AAAA,EACD;AAAA,EAGA,WAAW,cAAc,YAAY,aAAa;AAAA,IACjD,MAAM,kBAAkB,YAAY,EAAE,OAAO,MAAM,QAAQ,MAAM,IAAI,CAAC;AAAA,EACvE;AAAA;AAIM,SAAS,OAAgB,CAC/B,SACA,aACgC;AAAA,EAChC,OAAO,OAAO,QAAQ,MAAM,KAAK,SAAS;AAAA,IACzC,MAAM,QAAQ,aAAa;AAAA,MAC1B,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA,OAAO,KAAK,UAAU,cAAc;AAAA,IACrC,CAAC;AAAA,IACD,OAAO,QAAQ,QAAQ,MAAM,KAAK,IAAI;AAAA;AAAA;;;AC1DxC;AA0DA,SAAS,SAAS,CACjB,QACA,OACA,WACA,UACY;AAAA,EACZ,MAAM,OAAO,OAAO,QAAQ,QAAQ;AAAA,EACpC,MAAM,QAAQ,KAAK,cAAc;AAAA,EACjC,MAAM,SAAoB,CAAC;AAAA,EAC3B,WAAW,QAAQ,OAAO;AAAA,IACzB,MAAM,MAAM,KAAK,UAAU,EAAE;AAAA,IAC7B,IAAI,QAAQ,WAAW;AAAA,MACtB,OAAO,KAAK;AAAA,QACX,OAAO,GAAG,KAAK,QAAQ;AAAA,QACvB,QAAQ;AAAA,QACR,MAAM;AAAA,MACP,CAAC;AAAA,IACF;AAAA,EACD;AAAA,EACA,OAAO;AAAA,IACN,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,OAAO,KAAK,MAAM,QAAQ,MAAM,MAAM,KAAK,EAAE;AAAA,IACvE,EAAE,OAAO,UAAU,QAAQ,MAAM,MAAM,KAAK;AAAA,IAC5C,GAAG;AAAA,IACH,EAAE,OAAO,GAAG,YAAY,aAAa,QAAQ,OAAO,MAAM,MAAM;AAAA,EACjE;AAAA;AAIM,SAAS,SAAS,CACxB,QACA,OACA,WACA,UACkB;AAAA,EAClB,MAAM,gBAAoC,CAAC;AAAA,EAC3C,MAAM,QAAoB,CAAC;AAAA,EAC3B,MAAM,aAA8B,CAAC;AAAA,EACrC,aAAa,OAAO,QAAQ,UAAU,UACrC,QACA,OACA,WACA,QACD,GAAG;AAAA,IACF,WAAW,QAAQ,aAAa,QAAQ,MAAM,eAAe,KAAK,CAAC,GAAG;AAAA,MACrE,MAAM,QAAQ,KAAK;AAAA,MACnB,cAAc,KAAK,EAAE,OAAO,OAAO,SAAS,KAAK,CAAC;AAAA,IACnD;AAAA,IACA,WAAW,QAAQ,aAAa,QAAQ,MAAM,OAAO,KAAK,CAAC,GAAG;AAAA,MAC7D,MAAM,KAAK,EAAE,OAAO,QAAQ,KAAK,OAAiB,CAAC;AAAA,IACpD;AAAA,IACA,WAAW,QAAQ,aAAa,QAAQ,MAAM,YAAY,KAAK,CAAC,GAAG;AAAA,MAClE,WAAW,KAAK;AAAA,QACf;AAAA,QACA;AAAA,QACA,MAAM,KAAK;AAAA,QACX,MAAM,KAAK;AAAA,QACX,IAAK,KAAK,MAAoC;AAAA,QAC9C,QAAQ,KAAK,WAAW,cAAc,cAAc;AAAA,MACrD,CAAC;AAAA,IACF;AAAA,EACD;AAAA,EACA,OAAO,EAAE,eAAe,OAAO,WAAW;AAAA;;;AC5HpC,IAAM,SAAS;AAGf,SAAS,EAAE,CAAC,OAAe,OAAuB;AAAA,EACxD,OAAO,UAAU,QAAQ,QAAQ,GAAG,kBAAkB;AAAA;AAIhD,SAAS,IAAI,CAAC,OAAkC;AAAA,EACtD,OAAO,MAAM,IAAI,CAAC,SAAS,IAAI,OAAO,EAAE,KAAK,IAAI;AAAA;;;ACU3C,SAAS,OAAO,CAAC,QAAmC;AAAA,EAC1D,MAAM,QAAS,QACZ;AAAA,EACH,IAAI,CAAC,MAAM,QAAQ,OAAO,KAAK,KAAK,MAAM,YAAY,UAAU,WAAW;AAAA,IAC1E,OAAO;AAAA,EACR;AAAA,EACA,OAAO;AAAA;AAID,SAAS,OAAO,CAAC,OAAkB,MAAiC;AAAA,EAC1E,MAAM,MAAM,MAAM,WAAW,MAAM;AAAA,EACnC,OAAO;AAAA,IACN,GAAG,OAAO,KAAK,KAAK,WAAW,CAAC,CAAC;AAAA,IACjC,GAAG,OAAO,KAAK,KAAK,WAAW,CAAC,CAAC;AAAA,EAClC;AAAA;AASD,SAAS,WAAW,CAAC,OAAwC;AAAA,EAC5D,OAAQ,OAA8C,SAAS;AAAA;AAIzD,SAAS,QAAQ,CAAC,OAAkB,MAAiC;AAAA,EAC3E,MAAM,UAAU,MAAM,WAAW,MAAM,OAAO,WAAW,CAAC;AAAA,EAC1D,OAAO,OAAO,OAAO,OAAO,EAC1B,OAAO,WAAW,EAClB,IAAI,CAAC,QAAQ,IAAI,KAAK;AAAA;AAQlB,SAAS,gBAAgB,CAC/B,OACA,MACA,MACA,OAAoB,IAAI,KACd;AAAA,EACV,MAAM,MAAM,GAAG,QAAQ;AAAA,EACvB,IAAI,KAAK,IAAI,GAAG;AAAA,IAAG,OAAO;AAAA,EAC1B,KAAK,IAAI,GAAG;AAAA,EACZ,MAAM,MAAM,MAAM,WAAW,MAAM;AAAA,EACnC,WAAW,QAAQ,KAAK,UAAU,SAAS,CAAC,GAAG;AAAA,IAC9C,IAAI,OAAO,SAAS;AAAA,MAAU,OAAO;AAAA,IACrC,OAAO,UAAU,UAAU,KAAK,MAAM,IAAI;AAAA,IAC1C,IAAI,WAAW,WAAW;AAAA,MACzB,IAAI,iBAAiB,OAAO,MAAM,MAAM,IAAI;AAAA,QAAG,OAAO;AAAA,MACtD;AAAA,IACD;AAAA,IACA,WAAW,QAAQ,aAAa,KAAK,UAAU,SAAmB,GAAG;AAAA,MACpE,IAAI,iBAAiB,OAAO,MAAM,QAAQ,IAAI;AAAA,QAAG,OAAO;AAAA,IACzD;AAAA,EACD;AAAA,EACA,OAAO;AAAA;AAIR,SAAS,YAAY,CAAC,UAAsC;AAAA,EAC3D,IAAI,YAAY,QAAQ,GAAG;AAAA,IAC1B,OAAO,CAAC,SAAS,OAAO;AAAA,EACzB;AAAA,EACA,IAAI,CAAC,MAAM,QAAQ,QAAQ;AAAA,IAAG,OAAO,CAAC;AAAA,EACtC,OAAO,SACL,OAAO,CAAC,WAA6B,OAAO,WAAW,QAAQ,EAC/D,IAAI,CAAC,WAAW,OAAO,MAAM,GAAG,EAAE,EAAY;AAAA;;;AC5C1C,SAAS,iBAAiB,CAChC,KACA,OACA,QACkB;AAAA,EAClB,MAAM,QAAQ,kBAAkB,GAAG,IAAI,OAAO,MAAM,IAAI;AAAA,EACxD,MAAM,SAAS,CAAC,QAAgB,IAAI,UAAU,GAAG,WAAW,SAAS,KAAK;AAAA,EAC1E,MAAM,QAAQ,QAAQ,OAAO,MAAM;AAAA,EACnC,IAAI,UAAU,MAAM;AAAA,IACnB,MAAM,OACL,6GACD;AAAA,EACD;AAAA,EACA,WAAW,OAAO,KAAK,MAAM;AAAA,EAC7B,MAAM,OAAO,IAAI,OAAO,IAAI,SAAS,cAAc;AAAA,EACnD,MAAM,OAAO,UAAU,IAAI;AAAA,EAC3B,IAAI,SAAS,MAAM;AAAA,IAClB,MAAM,OACL,sBAAsB,kDACvB;AAAA,EACD;AAAA,EACA,OAAO,SAAS,KAAK;AAAA,EACrB,IAAI,KAAK,SAAS,UAAU,CAAC,MAAM,KAAK,SAAS,KAAe,GAAG;AAAA,IAClE,MAAM,OACL,SAAS,KAAK,QAAQ,cAAc,MAAM,0BAA0B,QACnE,IAAI,OAAO,QAAQ,IAAI,WAAW,QAC/B,kEACA,IAEL;AAAA,EACD;AAAA,EACA,OAAO;AAAA,IACN;AAAA,IACA,MAAM,IAAI;AAAA,IACV,MAAM,IAAI;AAAA,IACV,QAAQ,IAAI;AAAA,IACZ;AAAA,IACA,MAAM,SAAS,OAAO,IAAI,MAAM,MAAM,QAAQ,MAAM;AAAA,IACpD,WAAW,YAAY,OAAO,KAAK,QAAQ,MAAM;AAAA,EAClD;AAAA;AAKD,SAAS,UAAU,CAAC,OAAkB,KAAoB,QAAgB;AAAA,EACzE,IAAI,CAAC,MAAM,MAAM,SAAS,IAAI,IAAI,GAAG;AAAA,IACpC,MAAM,OACL,0BAA0B,IAAI,8BAA8B,KAAK,MAAM,KAAK,GAC7E;AAAA,EACD;AAAA,EACA,MAAM,QAAQ,QAAQ,OAAO,IAAI,IAAI;AAAA,EACrC,IAAI,CAAC,MAAM,SAAS,IAAI,IAAI,GAAG;AAAA,IAC9B,MAAM,OACL,SAAS,IAAI,gBAAgB,IAAI,uCAAuC,KAAK,KAAK,GACnF;AAAA,EACD;AAAA;AAID,SAAS,QAAQ,CAChB,OACA,MACA,MACA,QACA,QACgB;AAAA,EAChB,MAAM,OAAO,OAAO,UAAU;AAAA,EAC9B,IAAI,SAAS,aAAa,OAAO,SAAS,YAAY;AAAA,IACrD,MAAM,OAAO,iBAAiB,+BAA+B;AAAA,EAC9D;AAAA,EACA,MAAM,OAAO,KAAK,SAAS,YAAY,KAAK,SAAS,GAAG,EAAE,MAAM;AAAA,EAChE,IAAI;AAAA,IAAM,OAAO;AAAA,EACjB,IAAI,SAAS;AAAA,IAAW,OAAO;AAAA,EAC/B,MAAM,SAAS,SAAS,OAAO,IAAI;AAAA,EACnC,IAAI,OAAO,SAAS,GAAG;AAAA,IACtB,MAAM,OACL,aAAa,kBAAkB,KAAK,aAAa,cAAc,KAAK,MAAM,mEAAmE,2BAC9I;AAAA,EACD;AAAA,EACA,OAAO;AAAA;AAIR,SAAS,WAAW,CACnB,OACA,KACA,QACA,QACmB;AAAA,EACnB,IAAI,CAAC,iBAAiB,OAAO,IAAI,MAAM,IAAI,IAAI;AAAA,IAAG,OAAO;AAAA,EACzD,MAAM,YAAY,OAAO,aAAa,IAAI;AAAA,EAC1C,IAAI,OAAO,cAAc,YAAY;AAAA,IACpC,MAAM,OACL,SAAS,IAAI,YAAY,IAAI,gEAAgE,IAAI,+BAClG;AAAA,EACD;AAAA,EACA,OAAO;AAAA;;;ACpGD,SAAS,aAAa,CAC5B,OACA,YACA,OACA,QACqB;AAAA,EACrB,QAAQ,eAAe,OAAO,eAAe;AAAA,EAC7C,OAAO,MAAM,SAAS,QAAQ,UAAU;AAAA,EACxC,IAAI,UAAU;AAAA,IAAW,OAAO;AAAA,EAChC,OAAO;AAAA,IACN,OAAO,MAAM;AAAA,IACb,OAAO,GAAG,WAAW,GAAG,MAAM,OAAO,MAAM,IAAI;AAAA,IAC/C,OAAO,QAAQ,MAAM,MAAM,eAAe,KAAK;AAAA,IAC/C,UAAU,SAAS,MAAM,MAAM,KAAK;AAAA,IACpC,aAAa,WAAW,IAAI,CAAC,QAAQ,kBAAkB,KAAK,OAAO,MAAM,CAAC;AAAA,EAC3E;AAAA;AAID,SAAS,OAAO,CACf,OACA,MACA,OAC6B;AAAA,EAC7B,IAAI,QAA4B;AAAA,EAChC,aAAa,OAAO,OAAO,WAAW,MAAM;AAAA,IAC3C,IAAI,UAAU;AAAA,MAAM;AAAA,IACpB,IAAI,MAAM,WAAW,GAAG;AAAA,MACvB,MAAM,IAAI,UACT,GAAG,6BAA6B,GAAG,OAAO,KAAK,oEAChD;AAAA,IACD;AAAA,IACA,WAAW,QAAQ,OAAO;AAAA,MACzB,IAAI,CAAC,MAAM,MAAM,SAAS,IAAI,GAAG;AAAA,QAChC,MAAM,IAAI,UACT,GAAG,6BAA6B,GAAG,OAAO,KAAK,0BAA0B,8BAA8B,KAAK,MAAM,KAAK,GACxH;AAAA,MACD;AAAA,IACD;AAAA,IACA,QACC,UAAU,OACP,IAAI,IAAI,KAAK,IACb,IAAI,IAAI,MAAM,OAAO,CAAC,SAAS,OAAO,IAAI,IAAI,CAAC,CAAC;AAAA,EACrD;AAAA,EACA,IAAI,UAAU,QAAQ,MAAM,SAAS,GAAG;AAAA,IACvC,MAAM,IAAI,UACT,GAAG,iCAAiC,kEACrC;AAAA,EACD;AAAA,EACA,OAAO;AAAA;AAIR,SAAS,OAAO;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,GAC8E;AAAA,EAC9E,IAAI,cAAc,SAAS;AAAA,IAAG,OAAO,CAAC,kBAAkB,cAAc,EAAE;AAAA,EACxE,IAAI,MAAM,SAAS;AAAA,IAAG,OAAO,CAAC,UAAU,MAAM,EAAE;AAAA,EAChD,OAAO,CAAC,eAAe,WAAW,EAAE;AAAA;AAIrC,SAAS,QAAQ,CAAC,OAAe,MAA0C;AAAA,EAC1E,IAAI,UAAyB;AAAA,EAC7B,aAAa,OAAO,YAAY,MAAM;AAAA,IACrC,IAAI,CAAC,OAAO,cAAc,MAAM,KAAK,UAAU,GAAG;AAAA,MACjD,MAAM,IAAI,UACT,GAAG,qBAAqB,GAAG,OAAO,KAAK,kBAAkB,oFAC1D;AAAA,IACD;AAAA,IACA,UAAU,YAAY,OAAO,SAAS,KAAK,IAAI,SAAS,MAAM;AAAA,EAC/D;AAAA,EACA,OAAO,YAAY,OAAO,OAAO,UAAU;AAAA;;;AVvErC,SAAS,oBAA4C,CAC3D,QACA,SACgB;AAAA,EAChB,MAAM,QAAQ,QAAQ,OAAO;AAAA,EAC7B,OAAO,UAAU,QAAQ;AAAA,KACvB,WAAW,eAAe,CAAC,OAAO,WAAW,aAAa;AAAA,MAC1D,MAAM,cAAc,cACnB;AAAA,QACC,MAAM,GAAG,YAAY;AAAA,QACrB,MAAM,OAAO,KAAK,MAAM,QAAQ,CAAC,CAAC;AAAA,MACnC,GACA,UAAU,QAAQ,OAAO,WAAW,QAAQ,GAC5C,OACA,OACD;AAAA,MACA,IAAI,gBAAgB;AAAA,QAAM,OAAO;AAAA,MACjC,MAAM,UAAU,MAAM,WAAW;AAAA,MACjC,IAAI,MAAM,cAAc,WAAW;AAAA,QAClC,OAAO,KAAK,OAAO,SAAS,QAAQ,SAAS,WAAW,EAAE;AAAA,MAC3D;AAAA,MAGA,MAAM,UAAU,KAAK,aAAa,UAAU,KAAK;AAAA,MACjD,OAAO;AAAA,WACH;AAAA,QACH,WAAW,QAAQ,MAAM,WAAW,WAAW;AAAA,QAC/C,SAAS,QAAQ,SAAS,OAAO;AAAA,MAClC;AAAA;AAAA,EAEF,CAAC;AAAA;AAIF,SAAS,OAAO,GAAG,MAAM,QAAuC;AAAA,EAC/D,IAAI,SAAS;AAAA,IAAW,OAAO,EAAE,OAAO,KAAK,MAAM;AAAA,EACnD,IAAI,CAAC,KAAK,MAAM,SAAS,IAAI,GAAG;AAAA,IAC/B,MAAM,IAAI,UACT,GAAG,iBAAiB,+CAA+C,KAAK,KAAK,KAAK,GACnF;AAAA,EACD;AAAA,EACA,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE;AAAA;;AWtDxB,eAAsB,WAGrB,CACA,KACA,UAAiC,CAAC,GACU;AAAA,EAC5C,QAAQ,SAAS;AAAA,EACjB,MAAM,UACL,OAAO,SAAS,WAAW,CAAC,IAAI,IAAI;AAAA,EACrC,IAAI,SAAS,WAAW,GAAG;AAAA,IAC1B,MAAM,IAAI,UACT,iHACD;AAAA,EACD;AAAA,EACA,MAAM,OAAO,MAAM,QAAQ,KAAK,eAAe,EAC7C,KAAK,EACL,KAAK,WAAW,QAAQ;AAAA,EAC1B,IAAI,SAAS;AAAA,IAAM,MAAM,OAAO,iBAAiB;AAAA,EACjD,IAAI,YAAY,aAAa,CAAC,QAAQ,SAAS,KAAK,IAAI,GAAG;AAAA,IAC1D,MAAM,OAAO,WAAW;AAAA,EACzB;AAAA,EACA,OAAO;AAAA;AAgBR,eAAsB,GAIrB,CACA,KAMA,YACA,WACG,SACgB;AAAA,EACnB,MAAM,QAAQ,QAAQ,KAAK,OAAO;AAAA,EAClC,MAAM,QAAQ,QAAQ,KAAK;AAAA,EAC3B,IAAI,UAAU,MAAM;AAAA,IACnB,MAAM,IAAI,UACT,oEACD;AAAA,EACD;AAAA,EACA,MAAM,UAAU,MAAM,MAAM,KAAK,EAAE,KAAK,WAAW,QAAQ;AAAA,EAC3D,OAAO,MAAM,SAAS,YAAY,QAAQ,QAAQ,EAAE,EAAE,KACrD,WACA,QACD;AAAA;;AC5DM,SAAS,QAIf,CAAC,SAA+D;AAAA,EAChE,QAAQ,MAAM,QAAQ,MAAM,OAAO,SAAS,eAAe;AAAA,EAC3D,YAAY,cAAc,EAAE,MAAM,QAAQ,MAAM,CAAC;AAAA,EACjD,MAAM,UAAU,IAAI;AAAA,EAEpB,OAAO;AAAA,IACN,mBAAmB,GAAG,SAAS,oBAAoB;AAAA,MAClD,QAAQ,YAAY;AAAA,MACpB,MAAM,QAAQ,mBAAmB,WAAW,WAAW,OAAO,GAAG;AAAA,QAChE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACD,CAAC;AAAA,MACD,cAAc,EAAE,MAAM,CAA8C;AAAA;AAAA,IAIrE,gBAAgB,GAAG,QAAQ,oBAAoB;AAAA,MAC9C,IAAI,QAAQ,IAAI,MAAM;AAAA,QAAG;AAAA,MACzB,MAAM,OAAO,qBAAqB,QAAQ;AAAA,QACzC;AAAA,WACI,SAAS,YAAY,CAAC,IAAI,EAAE,KAAK;AAAA,QACrC;AAAA,QACA;AAAA,QACA;AAAA,MACD,CAAC;AAAA,MACD,QAAQ,IAAI,IAAI;AAAA,MAChB,cAAc,IAAI;AAAA;AAAA,EAEpB;AAAA;;AChEM,IAAM,gBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
|
|
26
|
+
"debugId": "C6BF0BFA8BF13A9C64756E2164756E21",
|
|
24
27
|
"names": []
|
|
25
28
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wiring checks `useJanus()` and `janusConnection()` share: what each
|
|
3
|
+
* refuses at start-up, with a `TypeError` naming the call that was written.
|
|
4
|
+
*/
|
|
5
|
+
/** What both calls take and check before anything runs. */
|
|
6
|
+
export interface Wiring {
|
|
7
|
+
readonly auth: unknown;
|
|
8
|
+
readonly access?: unknown;
|
|
9
|
+
readonly clock?: unknown;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Refuses an `auth` that is not what `janus()` answered, an `access` that
|
|
13
|
+
* is not what `permissions()` answered, and a `clock` that is not a
|
|
14
|
+
* `Clock` — each a `TypeError` naming `caller`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function checkWiring(caller: string, { auth, access, clock }: Wiring): void;
|
|
17
|
+
//# sourceMappingURL=options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,2DAA2D;AAC3D,MAAM,WAAW,MAAM;IACtB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,MAAM,QAyB1E"}
|
package/dist/plugin.d.ts
CHANGED
|
@@ -25,6 +25,10 @@ import type { Auth, JanusContext, JanusOptions, UserOfAuth } from './types';
|
|
|
25
25
|
* `requireFresh()` read the time from — the one given to `janus()`.
|
|
26
26
|
* `loaders` and `conditions` are what `@permission` needs beside `access`:
|
|
27
27
|
* the objects it checks by id, and the `ctx` of the conditions it reaches.
|
|
28
|
+
*
|
|
29
|
+
* An operation over graphql-ws has no request: its `ctx.janus`
|
|
30
|
+
* authenticates the credential its connection presented, once
|
|
31
|
+
* `janusConnection().onConnect` accepted it.
|
|
28
32
|
*/
|
|
29
33
|
export declare function useJanus<A extends Auth<{
|
|
30
34
|
readonly type: string;
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAO5C,OAAO,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE5E;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,QAAQ,CACvB,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,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CA+B/D"}
|
package/docs/README.md
CHANGED
|
@@ -7,12 +7,13 @@ give the detail.
|
|
|
7
7
|
| --- | --- |
|
|
8
8
|
| [Directives](guide/directives.md) | You are guarding fields, types or interfaces with `@authenticated`, `@fresh` or `@permission`: where the id is read, loaders and conditions, lists, the order, the denials, one check per question, and what is refused at start-up |
|
|
9
9
|
| [The step-up over GraphQL](guide/step-up.md) | A mutation must run only on a session that proved who it is recently: `@fresh`, `STEP_UP_REQUIRED`, `stepUp.request` and `confirm` as mutations, `requireFresh()`, subscriptions, and testing with a clock |
|
|
10
|
+
| [Subscriptions over graphql-ws](guide/subscriptions.md) | You serve subscriptions over a WebSocket: `janusConnection()`, the cookie or `connectionParams`, the close codes, a session revoked mid-stream, Bun, and a server without Yoga |
|
|
10
11
|
| [The context](guide/context.md) | You are reading the user in a resolver, narrowing it to a user type, or checking a permission or freshness yourself with `requireUser()`, `requireFresh()` and `can()` |
|
|
11
12
|
| [Errors](guide/errors.md) | You want to know what a client receives for a denial or an outage, what the status of the response is, and how `janusMaskError()` fits Yoga's masking |
|
|
12
13
|
| [Telemetry](guide/telemetry.md) | You want a span per authentication and per permission check, with `@nxgt/janus-telemetry` |
|
|
13
14
|
| [Federation](guide/federation.md) | The server is a subgraph: where the directives are checked, what the router must forward, and `@composeDirective` |
|
|
14
15
|
| [Troubleshooting](troubleshooting.md) | A query answers something you did not expect, the server refuses to start, or the compiler refuses a resolver |
|
|
15
|
-
| [Roadmap](roadmap.md) | You want to know what is coming —
|
|
16
|
+
| [Roadmap](roadmap.md) | You want to know what is coming — the renewed session cookie — and what is deliberately not planned |
|
|
16
17
|
|
|
17
18
|
The words — user, user type, session, subject, permission, failure, denial —
|
|
18
19
|
are [`@nxgt/janus`'s vocabulary](https://github.com/softistx/nxgt-janus/blob/develop/packages/janus/docs/guide/vocabulary.md),
|
package/docs/guide/context.md
CHANGED
|
@@ -22,7 +22,10 @@ export const yoga = createYoga({
|
|
|
22
22
|
`useJanus()` does two things, and nothing else:
|
|
23
23
|
|
|
24
24
|
- **Every request's context gets `ctx.janus`**, built from `context.request`,
|
|
25
|
-
the `Request` Yoga puts there
|
|
25
|
+
the `Request` Yoga puts there — or, for an operation over graphql-ws,
|
|
26
|
+
from the credential of the connection `janusConnection().onConnect`
|
|
27
|
+
accepted, found through `ctx.extra`
|
|
28
|
+
([subscriptions over graphql-ws](subscriptions.md)).
|
|
26
29
|
- **Every schema the server is given has its directives applied**, once, by
|
|
27
30
|
`applyJanusDirectives()`. A schema set later — a gateway reloading its
|
|
28
31
|
supergraph — is applied too. The schema it made is remembered, so envelop
|
package/docs/guide/step-up.md
CHANGED
|
@@ -140,11 +140,15 @@ seconds.
|
|
|
140
140
|
|
|
141
141
|
**A `@fresh` on the subscription field is checked when it subscribes.** A
|
|
142
142
|
stale session is refused before the stream starts; a fresh one keeps
|
|
143
|
-
receiving events past `maxAge`, as it keeps its session. `@
|
|
144
|
-
|
|
145
|
-
|
|
143
|
+
receiving events past `maxAge`, as it keeps its session. `@permission` on
|
|
144
|
+
the field is asked again on every event; `@authenticated` reads the
|
|
145
|
+
operation's one authentication, made when it subscribed; its `@fresh` is
|
|
146
|
+
not asked again. To end a stream when the session is no longer fresh, close
|
|
146
147
|
it from the server.
|
|
147
148
|
|
|
149
|
+
Over a WebSocket, the same holds once `janusConnection()` authenticates
|
|
150
|
+
the connection: [subscriptions over graphql-ws](subscriptions.md).
|
|
151
|
+
|
|
148
152
|
**A `@fresh` on the payload's type, or on one of its fields, is checked on
|
|
149
153
|
every event**, as any field is: those fields resolve anew for each event,
|
|
150
154
|
and once the session is past `maxAge` they answer `STEP_UP_REQUIRED` while
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# Subscriptions over graphql-ws
|
|
2
|
+
|
|
3
|
+
A subscription over server-sent events is an HTTP request like any other:
|
|
4
|
+
`useJanus()` authenticates it from its headers, and nothing more is needed.
|
|
5
|
+
Over a WebSocket, every operation travels over one socket, opened once:
|
|
6
|
+
`janusConnection()` authenticates that socket, with
|
|
7
|
+
[graphql-ws](https://github.com/enisdenjo/graphql-ws), the library Yoga
|
|
8
|
+
recommends, so the directives hold on it unchanged.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
`graphql-ws` is an **optional** peer: install it only when you serve
|
|
13
|
+
subscriptions over a WebSocket.
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
bun add graphql-ws ws
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Its range, `^6.0.0`, and the `graphql` 17 note are in the
|
|
20
|
+
[README's Install](../../README.md#install).
|
|
21
|
+
|
|
22
|
+
## Wiring, with Yoga
|
|
23
|
+
|
|
24
|
+
This is Yoga's recommended graphql-ws setup, with one line added:
|
|
25
|
+
`onConnect`.
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { createServer } from 'node:http';
|
|
29
|
+
import { janusConnection, janusMaskError, janusTypeDefs, useJanus } from '@nxgt/janus-graphql';
|
|
30
|
+
import { useServer } from 'graphql-ws/use/ws';
|
|
31
|
+
import { createSchema, createYoga } from 'graphql-yoga';
|
|
32
|
+
import { WebSocketServer } from 'ws';
|
|
33
|
+
import { access } from './access'; // what permissions() answered
|
|
34
|
+
import { auth } from './auth'; // what janus() answered
|
|
35
|
+
|
|
36
|
+
const yoga = createYoga({
|
|
37
|
+
schema: createSchema({ typeDefs: [janusTypeDefs, typeDefs], resolvers }),
|
|
38
|
+
plugins: [useJanus({ auth, access })],
|
|
39
|
+
maskedErrors: { maskError: janusMaskError() },
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const server = createServer(yoga);
|
|
43
|
+
const wsServer = new WebSocketServer({ server, path: yoga.graphqlEndpoint });
|
|
44
|
+
|
|
45
|
+
useServer(
|
|
46
|
+
{
|
|
47
|
+
onConnect: janusConnection({ auth }).onConnect, // refuses a connection with no valid session
|
|
48
|
+
execute: (args: any) => args.rootValue.execute(args),
|
|
49
|
+
subscribe: (args: any) => args.rootValue.subscribe(args),
|
|
50
|
+
onSubscribe: async (ctx, _id, params) => {
|
|
51
|
+
const { schema, execute, subscribe, contextFactory, parse, validate } = yoga.getEnveloped({
|
|
52
|
+
...ctx, // carries ctx.extra, where useJanus() finds the connection
|
|
53
|
+
req: ctx.extra.request,
|
|
54
|
+
socket: ctx.extra.socket,
|
|
55
|
+
params,
|
|
56
|
+
});
|
|
57
|
+
const args = {
|
|
58
|
+
schema,
|
|
59
|
+
operationName: params.operationName,
|
|
60
|
+
document: parse(params.query),
|
|
61
|
+
variableValues: params.variables,
|
|
62
|
+
contextValue: await contextFactory(),
|
|
63
|
+
rootValue: { execute, subscribe },
|
|
64
|
+
};
|
|
65
|
+
const errors = validate(args.schema, args.document);
|
|
66
|
+
if (errors.length) return errors;
|
|
67
|
+
return args;
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
wsServer,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
server.listen(4000);
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`useJanus()` needs nothing new. When it builds the context of an operation
|
|
77
|
+
with no `request`, it looks for the connection the operation came from —
|
|
78
|
+
by `ctx.extra`, which the `...ctx` spread carries — and authenticates the
|
|
79
|
+
credential that connection presented. **Keep the spread**: a context built
|
|
80
|
+
without `ctx.extra` has no connection to find, and its first guarded field
|
|
81
|
+
throws [`the GraphQL context has no request to authenticate`](../troubleshooting.md#typeerror--the-graphql-context-has-no-request-to-authenticate).
|
|
82
|
+
|
|
83
|
+
## How the session travels
|
|
84
|
+
|
|
85
|
+
`onConnect` reads one credential per connection, in this order:
|
|
86
|
+
|
|
87
|
+
1. **`connectionParams.authorization`** — for a client that is not a
|
|
88
|
+
browser, or a browser that holds a bearer token:
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
import { createClient } from 'graphql-ws';
|
|
92
|
+
|
|
93
|
+
const client = createClient({
|
|
94
|
+
url: 'wss://api.example.com/graphql',
|
|
95
|
+
connectionParams: async () => ({ authorization: `Bearer ${await tokens.current()}` }),
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The key is `authorization`, lower-case, and its value a string — the
|
|
100
|
+
same `Bearer <token>` an HTTP request sends. A value that is not a
|
|
101
|
+
string refuses the connection; a string of another scheme (`Basic …`)
|
|
102
|
+
is not a session credential, as in `@nxgt/janus`, and the upgrade
|
|
103
|
+
request is read instead.
|
|
104
|
+
|
|
105
|
+
2. **The upgrade request**, read as `auth.authenticate` reads any request:
|
|
106
|
+
`Authorization: Bearer`, then `X-Session-Token`, then the session
|
|
107
|
+
cookie. A browser sends its cookies with the upgrade, so a signed-in
|
|
108
|
+
browser needs no `connectionParams` at all — provided the WebSocket goes
|
|
109
|
+
to the origin that set the cookie, or to one its `SameSite` admits.
|
|
110
|
+
|
|
111
|
+
**The first credential present wins, not the first valid one**, as in
|
|
112
|
+
`@nxgt/janus`: a lapsed token in `connectionParams` beside a live cookie is
|
|
113
|
+
refused, rather than rescued in silence. Fix the client's token.
|
|
114
|
+
|
|
115
|
+
`type` restricts who may connect:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
janusConnection({ auth, type: 'staff' }); // a patient's session is refused
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## What a client sees
|
|
122
|
+
|
|
123
|
+
| What happened | The client sees |
|
|
124
|
+
| --- | --- |
|
|
125
|
+
| No credential, an unknown or lapsed one, a user gone, inactive or of another `type`, an `authorization` that is not a string | The socket closed **`4403: Forbidden`**, before any operation — graphql-ws's own close for an `onConnect` that answers `false` |
|
|
126
|
+
| The sessions store could not answer at connect | The socket closed **`4500`**, by `graphql-ws/use/ws`, which also logs the error — **never `4403`** |
|
|
127
|
+
| Accepted | `connection_ack`, then operations as over HTTP |
|
|
128
|
+
|
|
129
|
+
graphql-ws's client treats `4403` as retryable — a `connectionParams`
|
|
130
|
+
function asked again can present a fresh token — and `4500` as fatal. Set
|
|
131
|
+
`retryAttempts` and `shouldRetry` on the client to change that. (`4401` is
|
|
132
|
+
the protocol's answer to an operation sent before the acknowledgement;
|
|
133
|
+
`onConnect` cannot choose it.)
|
|
134
|
+
|
|
135
|
+
## Each operation
|
|
136
|
+
|
|
137
|
+
Each operation on an accepted connection gets **a `ctx.janus` of its own**,
|
|
138
|
+
built by `useJanus()` as for an HTTP request, and authenticated again from
|
|
139
|
+
the connection's credential the first time a field asks — once per
|
|
140
|
+
operation, never per event:
|
|
141
|
+
|
|
142
|
+
- `@authenticated` and `@fresh` on a subscription field are checked **when
|
|
143
|
+
it subscribes**. A denial answers the operation with its `GraphQLError` —
|
|
144
|
+
`UNAUTHENTICATED`, `FORBIDDEN`, `STEP_UP_REQUIRED` — and the source stream
|
|
145
|
+
never starts; the connection stays open.
|
|
146
|
+
- `@permission` on a subscription field is asked **again on every event**,
|
|
147
|
+
bypassing the request's memo, so a `revoke()` stops the stream at its
|
|
148
|
+
next event with `NOT_FOUND` (or `FORBIDDEN`).
|
|
149
|
+
- A directive on the payload's type or its fields is checked on every
|
|
150
|
+
event, as any field.
|
|
151
|
+
- An outage at subscribe, or on an event, answers `SERVICE_UNAVAILABLE` —
|
|
152
|
+
never a denial.
|
|
153
|
+
|
|
154
|
+
## A session revoked while connected
|
|
155
|
+
|
|
156
|
+
`auth.signOut` or `signOutEverywhere` while a socket is open:
|
|
157
|
+
|
|
158
|
+
- **the stream already running keeps its events coming.** Its user was
|
|
159
|
+
authenticated once, when it subscribed, and each event's
|
|
160
|
+
`@authenticated` reads that answer — authenticating on every event would
|
|
161
|
+
cost a sessions-store read per event per subscriber;
|
|
162
|
+
- **the next operation on the same connection is refused**
|
|
163
|
+
`UNAUTHENTICATED`, since it authenticates again;
|
|
164
|
+
- **a reconnection is refused `4403`**.
|
|
165
|
+
|
|
166
|
+
To cut a revoked session's streams at once, close its sockets yourself.
|
|
167
|
+
graphql-ws hands every callback the transport's socket as
|
|
168
|
+
`ctx.extra.socket`: a server that keeps its open sockets by user can close
|
|
169
|
+
them with `4403` when it revokes, and a client that reconnects is then
|
|
170
|
+
refused.
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
const connection = janusConnection({ auth });
|
|
174
|
+
|
|
175
|
+
useServer({
|
|
176
|
+
onConnect: async (ctx) => {
|
|
177
|
+
const accepted = await connection.onConnect(ctx);
|
|
178
|
+
if (accepted) track(ctx.extra.socket, ctx); // your own bookkeeping, keyed as you revoke
|
|
179
|
+
return accepted;
|
|
180
|
+
},
|
|
181
|
+
onClose: (ctx) => untrack(ctx.extra.socket),
|
|
182
|
+
// … Yoga's recipe …
|
|
183
|
+
}, wsServer);
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
A permission revoked while connected needs none of this: `@permission` sees
|
|
187
|
+
it at the next event.
|
|
188
|
+
|
|
189
|
+
## Without Yoga
|
|
190
|
+
|
|
191
|
+
A server that runs graphql-ws alone passes `context` as well, and applies
|
|
192
|
+
the directives itself:
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
import { applyJanusDirectives, janusConnection } from '@nxgt/janus-graphql';
|
|
196
|
+
import { useServer } from 'graphql-ws/use/ws';
|
|
197
|
+
import { WebSocketServer } from 'ws';
|
|
198
|
+
import { schema } from './schema'; // your executable schema, with janusTypeDefs
|
|
199
|
+
|
|
200
|
+
const wsServer = new WebSocketServer({ port: 4000, path: '/graphql' });
|
|
201
|
+
const connection = janusConnection({ auth, access, clock }); // clock: the one given to janus()
|
|
202
|
+
|
|
203
|
+
useServer(
|
|
204
|
+
{
|
|
205
|
+
schema: applyJanusDirectives(schema, { auth, access }),
|
|
206
|
+
onConnect: connection.onConnect,
|
|
207
|
+
context: connection.context, // { janus } for each operation
|
|
208
|
+
},
|
|
209
|
+
wsServer,
|
|
210
|
+
);
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
With Yoga, leave `context` out: Yoga's recipe builds the context itself,
|
|
214
|
+
and `useJanus()`'s `access` and `clock` are the ones that apply.
|
|
215
|
+
|
|
216
|
+
## On Bun, or another transport
|
|
217
|
+
|
|
218
|
+
`onConnect` reads the upgrade request from `ctx.extra.request`, where
|
|
219
|
+
`graphql-ws/use/ws` and `graphql-ws/use/@fastify/websocket` put it.
|
|
220
|
+
`graphql-ws/use/bun`'s `extra` is `{ socket }` alone: pass the request as
|
|
221
|
+
the socket's `data` when you upgrade, and tell `janusConnection` where it is.
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
import type { ServerWebSocket } from 'bun';
|
|
225
|
+
import { makeHandler } from 'graphql-ws/use/bun';
|
|
226
|
+
|
|
227
|
+
type Upgraded = ServerWebSocket<{ readonly request: Request }>;
|
|
228
|
+
|
|
229
|
+
const connection = janusConnection({
|
|
230
|
+
auth,
|
|
231
|
+
upgrade: (ctx: { readonly extra: { readonly socket: Upgraded } }) => ctx.extra.socket.data.request,
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
Bun.serve({
|
|
235
|
+
fetch: (request, server) =>
|
|
236
|
+
server.upgrade(request, { data: { request } }) ? undefined : yoga.fetch(request, server),
|
|
237
|
+
websocket: makeHandler({ onConnect: connection.onConnect, /* … Yoga's recipe … */ }),
|
|
238
|
+
});
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Without `upgrade` on Bun, only `connectionParams` authenticates: a browser's
|
|
242
|
+
cookie is never read.
|
|
243
|
+
|
|
244
|
+
## What is not covered
|
|
245
|
+
|
|
246
|
+
- **An anonymous connection.** `onConnect` refuses every connection it
|
|
247
|
+
cannot authenticate; serve anonymous clients over server-sent events. An
|
|
248
|
+
operation on a connection no `onConnect` accepted has no credential: its
|
|
249
|
+
first guarded field, or `ctx.janus.user()`, throws a `TypeError`, a 500.
|
|
250
|
+
- **The renewed session cookie.** A WebSocket has no response to set one
|
|
251
|
+
on: renew through your HTTP routes.
|