@nxgt/shared-graphql 1.0.1 → 1.1.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/dist/index.js.map CHANGED
@@ -13,9 +13,9 @@
13
13
  "import { html } from 'hono/html';\n\nexport type RenderSandboxOptions = {\n\tport?: number;\n\tgraphqlEndpoint?: string;\n\tprotocol?: string;\n\thostname?: string;\n\ttitle?: string;\n};\n\nexport const renderSandbox = ({\n\tport = 8080,\n\thostname = 'localhost',\n\tgraphqlEndpoint = 'graphql',\n\tprotocol = 'http',\n\ttitle = 'Sandbox Explorer',\n}: RenderSandboxOptions) => html`\n<title>${title}</title>\n<div id=\"sandbox\" style=\"position:absolute;top:0;right:0;bottom:0;left:0\"></div>\n<script src=\"https://embeddable-sandbox.cdn.apollographql.com/_latest/embeddable-sandbox.umd.production.min.js\"></script>\n<script>\n new window.EmbeddedSandbox({\n target: \"#sandbox\",\n // Pass through your server href if you are embedding on an endpoint.\n // Otherwise, you can pass whatever endpoint you want Sandbox to start up with here.\n initialEndpoint: \"${protocol}://${hostname}:${port}/${graphqlEndpoint}\",\n handleRequest: (endpointUrl, options) => {\n return fetch(endpointUrl, {\n ...options,\n headers: {\n ...options.headers\n },\n })\n },\n hideCookieToggle: true,\n });\n // advanced options: https://www.apollographql.com/docs/studio/explorer/sandbox#embedding-sandbox\n</script>\n\n`;\n",
14
14
  "import { join } from 'node:path';\nimport { buildSubgraphSchema as buildSubgraphSchemaBase } from '@apollo/subgraph';\nimport { loadFilesSync } from '@graphql-tools/load-files';\nimport { mergeTypeDefs } from '@graphql-tools/merge';\nimport { pruneSchema } from '@graphql-tools/utils';\nimport { printSchema } from 'graphql';\n\nexport const SHARED_SCHEMA_PATH = join(__dirname, './**/*.graphqls');\n\nexport function loadTypeDefs(...paths: string[]) {\n\tconst typeDefs = mergeTypeDefs([\n\t\t...paths.flatMap((path) =>\n\t\t\tloadFilesSync(path, {\n\t\t\t\trecursive: true,\n\t\t\t}),\n\t\t),\n\t]);\n\n\treturn typeDefs;\n}\n\nexport function buildSubgraphSchema(\n\tmodulesOrSdl: Parameters<typeof buildSubgraphSchemaBase>[0],\n) {\n\treturn pruneSchema(buildSubgraphSchemaBase(modulesOrSdl), {\n\t\tskipUnusedTypesPruning: false,\n\t});\n}\n\n/**\n * Utility function to generate a GraphQL schema file from the provided type definitions.\n * @param output - The path where the generated schema file should be saved.\n * @param paths - An array of glob patterns to locate the GraphQL type definition files.\n */\nexport async function generateSchema(output: string, ...paths: string[]) {\n\tawait Bun.write(\n\t\toutput,\n\t\tprintSchema(buildSubgraphSchema(loadTypeDefs(...paths))),\n\t);\n}\n",
15
15
  "import { createServer } from 'node:http';\nimport type { ServerOptions } from 'graphql-ws';\nimport { useServer } from 'graphql-ws/use/ws';\nimport type { YogaServerInstance } from 'graphql-yoga';\nimport { WebSocketServer } from 'ws';\n\nexport function setupYogaWebSocketServer<\n\tServerContext extends {},\n\tUserContext extends {},\n>({\n\tyoga,\n\tcontext,\n}: {\n\tyoga: YogaServerInstance<ServerContext, UserContext>;\n\tcontext?: ServerOptions['context'];\n}) {\n\tconst httpServer = createServer(yoga);\n\tconst wsServer = new WebSocketServer({\n\t\tserver: httpServer,\n\t\tpath: yoga.graphqlEndpoint,\n\t});\n\n\t// biome-ignore lint/correctness/useHookAtTopLevel: Not react related\n\tuseServer(\n\t\t{\n\t\t\texecute: (args: any) => args.rootValue.execute(args),\n\t\t\tsubscribe: (args: any) => args.rootValue.subscribe(args),\n\t\t\tonSubscribe: async (ctx, _id, params) => {\n\t\t\t\tconst { schema, execute, subscribe, contextFactory, parse, validate } =\n\t\t\t\t\tyoga.getEnveloped({\n\t\t\t\t\t\t...ctx,\n\t\t\t\t\t\treq: ctx.extra.request,\n\t\t\t\t\t\tsocket: ctx.extra.socket,\n\t\t\t\t\t\tparams,\n\t\t\t\t\t});\n\n\t\t\t\tconst args = {\n\t\t\t\t\tschema,\n\t\t\t\t\toperationName: params.operationName,\n\t\t\t\t\tdocument: parse(params.query),\n\t\t\t\t\tvariableValues: params.variables,\n\t\t\t\t\tcontextValue: await contextFactory(),\n\t\t\t\t\trootValue: {\n\t\t\t\t\t\texecute,\n\t\t\t\t\t\tsubscribe,\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\t\t\tconst errors = validate(args.schema, args.document);\n\t\t\t\tif (errors.length) return errors;\n\t\t\t\treturn args;\n\t\t\t},\n\t\t\tcontext,\n\t\t},\n\t\twsServer,\n\t);\n\n\tconst startServer = (port: number) =>\n\t\tnew Promise<void>((resolve) => httpServer.listen({ port }, resolve));\n\treturn { yoga, httpServer, startServer };\n}\n",
16
- "import type { Principal } from '@nxgt/shared';\nimport type { Context } from 'graphql-ws';\nimport type { createAuthClient } from 'stx-sdk/auth';\n\ntype AuthClient = ReturnType<typeof createAuthClient>;\n\nexport interface ResolvedWsUser {\n\tuser: Principal | undefined;\n\ttoken: string | undefined;\n}\n\n/**\n * Resolves the authenticated Principal for a `graphql-ws` connection - the\n * WS-transport equivalent of the HTTP-path `useAuth()`/`useGenericAuth()`\n * plugins. There is no gateway hop for WS connections, so each app performs\n * the OAuth introspection call itself using its own `auth` client.\n *\n * Reads the bearer token off `connectionParams.authorization` /\n * `connectionParams.Authorization` (both casings are used by existing\n * clients), strips the `Bearer ` prefix, and introspects it. Returns\n * `user: undefined` for a missing, invalid, or inactive token - callers\n * pass `user ?? null` into their own `services()` factory, exactly as the\n * HTTP-path plugins already do.\n */\nexport async function resolveWsUser(\n\tconnectionParams: Context['connectionParams'],\n\tauthClient: AuthClient,\n): Promise<ResolvedWsUser> {\n\tconst rawToken =\n\t\t(connectionParams?.authorization as string | undefined) ??\n\t\t(connectionParams?.Authorization as string | undefined);\n\tconst token = rawToken?.replace('Bearer ', '');\n\n\tconst { data } = token\n\t\t? await authClient.POST('/oauth/introspect', { body: { token } })\n\t\t: { data: null };\n\n\tconst user = data?.active\n\t\t? ({ ...(data as any), name: (data as any).sub } as Principal)\n\t\t: undefined;\n\n\treturn { user, token };\n}\n",
16
+ "import type { TokenPrincipal } from '@nxgt/shared';\nimport type { Context } from 'graphql-ws';\nimport type { createAuthClient } from 'stx-sdk/auth';\n\ntype AuthClient = ReturnType<typeof createAuthClient>;\n\nexport interface ResolvedWsUser {\n\tuser: TokenPrincipal | undefined;\n\ttoken: string | undefined;\n}\n\n/**\n * Resolves the authenticated TokenPrincipal for a `graphql-ws` connection - the\n * WS-transport equivalent of the HTTP-path `useAuth()`/`useGenericAuth()`\n * plugins. There is no gateway hop for WS connections, so each app performs\n * the OAuth introspection call itself using its own `auth` client.\n *\n * Reads the bearer token off `connectionParams.authorization` /\n * `connectionParams.Authorization` (both casings are used by existing\n * clients), strips the `Bearer ` prefix, and introspects it. Returns\n * `user: undefined` for a missing, invalid, or inactive token - callers\n * pass `user ?? null` into their own `services()` factory, exactly as the\n * HTTP-path plugins already do.\n */\nexport async function resolveWsUser(\n\tconnectionParams: Context['connectionParams'],\n\tauthClient: AuthClient,\n): Promise<ResolvedWsUser> {\n\tconst rawToken =\n\t\t(connectionParams?.authorization as string | undefined) ??\n\t\t(connectionParams?.Authorization as string | undefined);\n\tconst token = rawToken?.replace('Bearer ', '');\n\n\tconst { data } = token\n\t\t? await authClient.POST('/oauth/introspect', { body: { token } })\n\t\t: { data: null };\n\n\tconst user = data?.active\n\t\t? ({ ...(data as any), name: (data as any).sub } as TokenPrincipal)\n\t\t: undefined;\n\n\treturn { user, token };\n}\n",
17
17
  "import type { Plugin } from 'graphql-yoga';\nimport type { GraphQLBaseContext } from '../types';\n\nexport function useAuth(): Plugin<GraphQLBaseContext> {\n\treturn {\n\t\tonContextBuilding: async ({ context, extendContext }) => {\n\t\t\textendContext({\n\t\t\t\tuser: context.params.extensions?.user,\n\t\t\t\ttoken: context.params.extensions?.token,\n\t\t\t});\n\t\t},\n\t};\n}\n",
18
- "import type { ApolloServerPlugin } from '@apollo/server';\nimport type { Principal } from '@nxgt/shared';\nimport { logger } from '@nxgt/shared-logging';\n\nexport const extractJwtPlugin = {\n\tasync requestDidStart({ request, contextValue }) {\n\t\tlogger.info(\n\t\t\t`[${request.extensions?.subgraphName}] Extracting JWT from request extensions: ${request.extensions?.payload?.sub}`,\n\t\t\trequest.extensions,\n\t\t);\n\t\tcontextValue.jwt = {\n\t\t\tpayload: request.extensions?.payload,\n\t\t};\n\t},\n} satisfies ApolloServerPlugin<{\n\tjwt?: { payload: Principal };\n}>;\n",
18
+ "import type { ApolloServerPlugin } from '@apollo/server';\nimport type { TokenPrincipal } from '@nxgt/shared';\nimport { logger } from '@nxgt/shared-logging';\n\nexport const extractJwtPlugin = {\n\tasync requestDidStart({ request, contextValue }) {\n\t\tlogger.info(\n\t\t\t`[${request.extensions?.subgraphName}] Extracting JWT from request extensions: ${request.extensions?.payload?.sub}`,\n\t\t\trequest.extensions,\n\t\t);\n\t\tcontextValue.jwt = {\n\t\t\tpayload: request.extensions?.payload,\n\t\t};\n\t},\n} satisfies ApolloServerPlugin<{\n\tjwt?: { payload: TokenPrincipal };\n}>;\n",
19
19
  "import type { TokenPrincipal } from '@nxgt/shared';\nimport { GraphQLError } from 'graphql';\nimport type { Plugin } from 'graphql-yoga';\nimport {\n\tbearerOf,\n\ttype Ory,\n\ttype OryPrincipal,\n\tOryUnavailable,\n} from 'stx-sdk/ory';\nimport type { GraphQLBaseContext } from '../types';\n\n/**\n * What `useOryAuth()` adds to the context, next to `user` and `token`: the\n * Ory principal itself, or `null` when the request carried no honoured\n * credential. `user.sub === ory.subject` by construction; read `ory` when the\n * value is going to Keto, so the code says what it is.\n */\nexport type OryContext = {\n\tory?: OryPrincipal | null;\n};\n\n/**\n * The repo-wide TokenPrincipal an Ory principal becomes.\n *\n * `sub` and `uid` are both the Ory subject — a Kratos identity id for a\n * session or a person's token, the client id for a `client_credentials`\n * token — so every service that reads `this.principal?.sub` (or `.uid`) keeps\n * working unchanged. `authorities` is EMPTY on purpose: Keto answers per\n * object, and an empty list is what keeps `@policy` / `useGenericAuth`'s\n * policy extraction from granting anything by accident.\n */\nexport function toPrincipal(ory: OryPrincipal): TokenPrincipal {\n\tconst email = ory.identity?.email;\n\treturn {\n\t\tsub: ory.subject,\n\t\tuid: ory.subject,\n\t\tname: email ?? ory.clientId ?? ory.subject,\n\t\tusername: email,\n\t\tclientId: ory.clientId,\n\t\tscope: ory.scopes.join(' ') || undefined,\n\t\ttokenType: ory.kind,\n\t\texp: ory.expiresAt ? Math.floor(ory.expiresAt.getTime() / 1000) : undefined,\n\t\tauthorities: [],\n\t\troles: [],\n\t};\n}\n\n/**\n * A 503 the client can read as one — a real `GraphQLError` so Yoga's masking\n * leaves it alone, `extensions.http.status` so the transport says 503 too.\n * Never a denial: `stx-sdk/ory` throws `OryUnavailable` only when Kratos,\n * Hydra or Keto could not answer, and that must not read as \"not signed in\".\n */\nexport function oryUnavailableError(error: OryUnavailable): GraphQLError {\n\treturn new GraphQLError(`ory: ${error.service} is unavailable`, {\n\t\textensions: {\n\t\t\tcode: 'SERVICE_UNAVAILABLE',\n\t\t\thttp: { status: 503 },\n\t\t\tdebugMessage: error.message,\n\t\t},\n\t});\n}\n\n/**\n * The one introspection code path — `Bearer` first, then `X-Session-Token`,\n * then the Kratos cookie; the first credential present decides. Exported so\n * a REST route mounted beside the GraphQL endpoint (content-hub-api's\n * webhook shape) authenticates through the same function instead of a\n * second call.\n */\nexport async function resolveOryPrincipal(\n\tory: Ory,\n\theaders: Headers,\n): Promise<OryContext & { user?: TokenPrincipal; token?: string }> {\n\tlet principal: OryPrincipal | null;\n\ttry {\n\t\tprincipal = await ory.resolve(headers);\n\t} catch (error) {\n\t\tif (error instanceof OryUnavailable) throw oryUnavailableError(error);\n\t\tthrow error;\n\t}\n\n\treturn {\n\t\tory: principal,\n\t\tuser: principal ? toPrincipal(principal) : undefined,\n\t\ttoken: bearerOf(headers) ?? undefined,\n\t};\n}\n\n/**\n * `useAuth()` for an Ory-native API: resolves the caller through Kratos\n * (session cookie, session token) or Hydra (Bearer, introspected) and puts\n * `user`, `token` and `ory` on the context. Wire it exactly where the\n * standalone APIs wire `useAuth()`, ahead of `useGenericAuth` — which then\n * enforces `@authenticated` from `context.user` unchanged.\n *\n * The `Ory` instance comes from the app's `createOry()` — one per process —\n * and is the same one the services use for `isAllowed`.\n */\nexport function useOryAuth(ory: Ory): Plugin<GraphQLBaseContext & OryContext> {\n\treturn {\n\t\tonContextBuilding: async ({ context, extendContext }) => {\n\t\t\textendContext(await resolveOryPrincipal(ory, context.request.headers));\n\t\t},\n\t};\n}\n",
20
20
  "import { GraphQLScalarType, Kind } from 'graphql';\n\nexport const ANY_SCALAR = {\n\tAny: new GraphQLScalarType<any, any>({\n\t\tname: 'Any',\n\t\tdescription: 'Generic scalar to represent any type',\n\t\tserialize(value) {\n\t\t\treturn value;\n\t\t},\n\t\tparseValue(value: any) {\n\t\t\treturn value;\n\t\t},\n\t\tparseLiteral(ast, variables) {\n\t\t\tswitch (ast.kind) {\n\t\t\t\tcase Kind.STRING:\n\t\t\t\tcase Kind.BOOLEAN:\n\t\t\t\t\treturn ast.value;\n\t\t\t\tcase Kind.INT:\n\t\t\t\tcase Kind.FLOAT:\n\t\t\t\t\treturn parseFloat(ast.value);\n\t\t\t\tcase Kind.OBJECT:\n\t\t\t\t\treturn Object.fromEntries(\n\t\t\t\t\t\tast.fields.map((field) => [field.name, field.value]),\n\t\t\t\t\t);\n\t\t\t\tcase Kind.LIST:\n\t\t\t\t\treturn ast.values.map((n) => this?.parseLiteral?.(n, variables));\n\t\t\t\tcase Kind.NULL:\n\t\t\t\t\treturn null;\n\t\t\t\tcase Kind.VARIABLE: {\n\t\t\t\t\tconst name = ast.name.value;\n\t\t\t\t\treturn variables ? variables[name] : undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}),\n};\n",
21
21
  "import type { GraphQLScalarType } from 'graphql';\nimport {\n\tAccountNumberResolver,\n\tBigIntResolver,\n\tCountryCodeResolver,\n\tCountryNameResolver,\n\tCuidResolver,\n\tCurrencyResolver,\n\tDateResolver,\n\tDateTimeISOResolver,\n\tDurationResolver,\n\tEmailAddressResolver,\n\tGeoJSONResolver,\n\tGUIDResolver,\n\tHexadecimalResolver,\n\tHexColorCodeResolver,\n\tHSLAResolver,\n\tHSLResolver,\n\tIBANResolver,\n\tIPResolver,\n\tIPv4Resolver,\n\tIPv6Resolver,\n\tISBNResolver,\n\tJSONObjectResolver,\n\tJSONResolver,\n\tJWTResolver,\n\tLatitudeResolver,\n\tLocaleResolver,\n\tLongitudeResolver,\n\tLongResolver,\n\tMACResolver,\n\tNegativeFloatResolver,\n\tNegativeIntResolver,\n\tNonEmptyStringResolver,\n\tNonNegativeFloatResolver,\n\tNonNegativeIntResolver,\n\tNonPositiveFloatResolver,\n\tNonPositiveIntResolver,\n\tObjectIDResolver,\n\tPhoneNumberResolver,\n\tPortResolver,\n\tPositiveFloatResolver,\n\tPositiveIntResolver,\n\tPostalCodeResolver,\n\tRGBAResolver,\n\tRGBResolver,\n\tSESSNResolver,\n\tTimeResolver,\n\tTimestampResolver,\n\tURLResolver,\n\tUSCurrencyResolver,\n\tUtcOffsetResolver,\n\tUUIDResolver,\n\tVoidResolver,\n} from 'graphql-scalars';\nimport { createScalarFrom } from './utils';\n\nexport const CUSTOM_SCALARS: Record<string, GraphQLScalarType> = {\n\tAccountNumber: createScalarFrom(AccountNumberResolver, {\n\t\terrorMessage: 'validation.errors.invalid-account-number',\n\t}),\n\tBigInt: createScalarFrom(BigIntResolver, {\n\t\terrorMessage: 'validation.errors.invalid-big-int',\n\t}),\n\tCountryCode: createScalarFrom(CountryCodeResolver, {\n\t\terrorMessage: 'validation.errors.invalid-country-code',\n\t}),\n\tCountryName: createScalarFrom(CountryNameResolver, {\n\t\terrorMessage: 'validation.errors.invalid-country-name',\n\t}),\n\tCuid: createScalarFrom(CuidResolver, {\n\t\terrorMessage: 'validation.errors.invalid-cuid',\n\t}),\n\tCurrencyCode: createScalarFrom(CurrencyResolver, {\n\t\tname: 'CurrencyCode',\n\t\terrorMessage: 'validation.errors.invalid-currency',\n\t}),\n\tDate: createScalarFrom(DateResolver, {\n\t\terrorMessage: 'validation.errors.invalid-date',\n\t}),\n\tDateTime: createScalarFrom(DateTimeISOResolver, {\n\t\tname: 'DateTime',\n\t\terrorMessage: 'validation.errors.invalid-date-time',\n\t}),\n\tDuration: createScalarFrom(DurationResolver, {\n\t\terrorMessage: 'validation.errors.invalid-duration',\n\t}),\n\tEmailAddress: createScalarFrom(EmailAddressResolver, {\n\t\terrorMessage: 'validation.errors.invalid-email-address',\n\t}),\n\tGeoJSON: createScalarFrom(GeoJSONResolver, {\n\t\terrorMessage: 'validation.errors.invalid-geo-json',\n\t}),\n\tGUID: createScalarFrom(GUIDResolver, {\n\t\terrorMessage: 'validation.errors.invalid-guid',\n\t}),\n\tHexColorCode: createScalarFrom(HexColorCodeResolver, {\n\t\terrorMessage: 'validation.errors.invalid-hex-color-code',\n\t}),\n\tHexadecimal: createScalarFrom(HexadecimalResolver, {\n\t\terrorMessage: 'validation.errors.invalid-hexadecimal',\n\t}),\n\tHSL: createScalarFrom(HSLResolver, {\n\t\terrorMessage: 'validation.errors.invalid-hsl',\n\t}),\n\tHSLA: createScalarFrom(HSLAResolver, {\n\t\terrorMessage: 'validation.errors.invalid-hsla',\n\t}),\n\tIBAN: createScalarFrom(IBANResolver, {\n\t\terrorMessage: 'validation.errors.invalid-iban',\n\t}),\n\tIP: createScalarFrom(IPResolver, {\n\t\terrorMessage: 'validation.errors.invalid-ip',\n\t}),\n\tIPv4: createScalarFrom(IPv4Resolver, {\n\t\terrorMessage: 'validation.errors.invalid-ipv4',\n\t}),\n\tIPv6: createScalarFrom(IPv6Resolver, {\n\t\terrorMessage: 'validation.errors.invalid-ipv6',\n\t}),\n\tISBN: createScalarFrom(ISBNResolver, {\n\t\terrorMessage: 'validation.errors.invalid-isbn',\n\t}),\n\tJSON: createScalarFrom(JSONResolver, {\n\t\terrorMessage: 'validation.errors.invalid-json',\n\t}),\n\tJSONObject: createScalarFrom(JSONObjectResolver, {\n\t\terrorMessage: 'validation.errors.invalid-json-object',\n\t}),\n\tJWT: createScalarFrom(JWTResolver, {\n\t\terrorMessage: 'validation.errors.invalid-jwt',\n\t}),\n\tLatitude: createScalarFrom(LatitudeResolver, {\n\t\terrorMessage: 'validation.errors.invalid-latitude',\n\t}),\n\tLocale: createScalarFrom(LocaleResolver, {\n\t\terrorMessage: 'validation.errors.invalid-locale',\n\t}),\n\tLongitude: createScalarFrom(LongitudeResolver, {\n\t\terrorMessage: 'validation.errors.invalid-longitude',\n\t}),\n\tLong: createScalarFrom(LongResolver, {\n\t\terrorMessage: 'validation.errors.invalid-long',\n\t}),\n\tMAC: createScalarFrom(MACResolver, {\n\t\terrorMessage: 'validation.errors.invalid-mac',\n\t}),\n\tNegativeFloat: createScalarFrom(NegativeFloatResolver, {\n\t\terrorMessage: 'validation.errors.invalid-negative-float',\n\t}),\n\tNegativeInt: createScalarFrom(NegativeIntResolver, {\n\t\terrorMessage: 'validation.errors.invalid-negative-int',\n\t}),\n\tNonEmptyString: createScalarFrom(NonEmptyStringResolver, {\n\t\terrorMessage: 'validation.errors.invalid-non-empty-string',\n\t}),\n\tNonNegativeFloat: createScalarFrom(NonNegativeFloatResolver, {\n\t\terrorMessage: 'validation.errors.invalid-non-negative-float',\n\t}),\n\tNonNegativeInt: createScalarFrom(NonNegativeIntResolver, {\n\t\terrorMessage: 'validation.errors.invalid-non-negative-int',\n\t}),\n\tNonPositiveFloat: createScalarFrom(NonPositiveFloatResolver, {\n\t\terrorMessage: 'validation.errors.invalid-non-positive-float',\n\t}),\n\tNonPositiveInt: createScalarFrom(NonPositiveIntResolver, {\n\t\terrorMessage: 'validation.errors.invalid-non-positive-int',\n\t}),\n\tObjectID: createScalarFrom(ObjectIDResolver, {\n\t\terrorMessage: 'validation.errors.invalid-object-id',\n\t}),\n\tPhoneNumber: createScalarFrom(PhoneNumberResolver, {\n\t\terrorMessage: 'validation.errors.invalid-phone-number',\n\t}),\n\tPort: createScalarFrom(PortResolver, {\n\t\terrorMessage: 'validation.errors.invalid-port',\n\t}),\n\tPositiveFloat: createScalarFrom(PositiveFloatResolver, {\n\t\terrorMessage: 'validation.errors.invalid-positive-float',\n\t}),\n\tPositiveInt: createScalarFrom(PositiveIntResolver, {\n\t\terrorMessage: 'validation.errors.invalid-positive-int',\n\t}),\n\tPostalCode: createScalarFrom(PostalCodeResolver, {\n\t\terrorMessage: 'validation.errors.invalid-postal-code',\n\t}),\n\tRGB: createScalarFrom(RGBResolver, {\n\t\terrorMessage: 'validation.errors.invalid-rgb',\n\t}),\n\tRGBA: createScalarFrom(RGBAResolver, {\n\t\terrorMessage: 'validation.errors.invalid-rgba',\n\t}),\n\tSESSN: createScalarFrom(SESSNResolver, {\n\t\terrorMessage: 'validation.errors.invalid-sessn',\n\t}),\n\tTime: createScalarFrom(TimeResolver, {\n\t\terrorMessage: 'validation.errors.invalid-time',\n\t}),\n\tTimestamp: createScalarFrom(TimestampResolver, {\n\t\terrorMessage: 'validation.errors.invalid-timestamp',\n\t}),\n\tURL: createScalarFrom(URLResolver, {\n\t\terrorMessage: 'validation.errors.invalid-url',\n\t}),\n\tUSCurrency: createScalarFrom(USCurrencyResolver, {\n\t\terrorMessage: 'validation.errors.invalid-us-currency',\n\t}),\n\tUTCOffset: createScalarFrom(UtcOffsetResolver, {\n\t\terrorMessage: 'validation.errors.invalid-utc-offset',\n\t}),\n\tUUID: createScalarFrom(UUIDResolver, {\n\t\terrorMessage: 'validation.errors.invalid-uuid',\n\t}),\n\tVoid: createScalarFrom(VoidResolver, {\n\t\terrorMessage: 'validation.errors.invalid-void',\n\t}),\n};\n",
@@ -1,8 +1,8 @@
1
- import type { Principal } from '@nxgt/shared';
1
+ import type { TokenPrincipal } from '@nxgt/shared';
2
2
  export declare const extractJwtPlugin: {
3
3
  requestDidStart({ request, contextValue }: import("@apollo/server").GraphQLRequestContext<{
4
4
  jwt?: {
5
- payload: Principal;
5
+ payload: TokenPrincipal;
6
6
  };
7
7
  }>): Promise<void>;
8
8
  };
@@ -1 +1 @@
1
- {"version":3,"file":"extract-jwt.d.ts","sourceRoot":"","sources":["../../src/plugins/extract-jwt.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAG9C,eAAO,MAAM,gBAAgB;;cAWtB;YAAE,OAAO,EAAE,SAAS,CAAA;SAAE;;CAC3B,CAAC"}
1
+ {"version":3,"file":"extract-jwt.d.ts","sourceRoot":"","sources":["../../src/plugins/extract-jwt.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAGnD,eAAO,MAAM,gBAAgB;;cAWtB;YAAE,OAAO,EAAE,cAAc,CAAA;SAAE;;CAChC,CAAC"}
@@ -1,14 +1,22 @@
1
- import type { Principal } from '@nxgt/shared';
1
+ import type { TokenPrincipal } from '@nxgt/shared';
2
+ /**
3
+ * `TokenPrincipal`, not `Principal`. This package is nxgt-federation's alone —
4
+ * sellix-monorepo has no GraphQL — and what its server puts in the context is
5
+ * a decoded JWT: `sub`, `uid`, `scope`. `Principal` is the gateway-header
6
+ * shape, and the two survived the merge under different names precisely
7
+ * because they are different models of the caller. See the duplication table
8
+ * in AGENTS.md.
9
+ */
2
10
  import type { YogaInitialContext } from 'graphql-yoga';
3
11
  export interface GraphQLBaseContext extends YogaInitialContext {
4
- user?: Principal;
12
+ user?: TokenPrincipal;
5
13
  token?: string;
6
14
  }
7
15
  export type ServerContext = {
8
16
  request: Request;
9
17
  };
10
18
  export type PrincipalContext = {
11
- user?: Principal;
19
+ user?: TokenPrincipal;
12
20
  token?: string;
13
21
  };
14
22
  //# sourceMappingURL=context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/types/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEvD,MAAM,WAAW,kBAAmB,SAAQ,kBAAkB;IAC7D,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,aAAa,GAAG;IAC3B,OAAO,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC9B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf,CAAC"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/types/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEvD,MAAM,WAAW,kBAAmB,SAAQ,kBAAkB;IAC7D,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,aAAa,GAAG;IAC3B,OAAO,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC9B,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf,CAAC"}
@@ -1,13 +1,13 @@
1
- import type { Principal } from '@nxgt/shared';
1
+ import type { TokenPrincipal } from '@nxgt/shared';
2
2
  import type { Context } from 'graphql-ws';
3
3
  import type { createAuthClient } from 'stx-sdk/auth';
4
4
  type AuthClient = ReturnType<typeof createAuthClient>;
5
5
  export interface ResolvedWsUser {
6
- user: Principal | undefined;
6
+ user: TokenPrincipal | undefined;
7
7
  token: string | undefined;
8
8
  }
9
9
  /**
10
- * Resolves the authenticated Principal for a `graphql-ws` connection - the
10
+ * Resolves the authenticated TokenPrincipal for a `graphql-ws` connection - the
11
11
  * WS-transport equivalent of the HTTP-path `useAuth()`/`useGenericAuth()`
12
12
  * plugins. There is no gateway hop for WS connections, so each app performs
13
13
  * the OAuth introspection call itself using its own `auth` client.
@@ -1 +1 @@
1
- {"version":3,"file":"ws-context.d.ts","sourceRoot":"","sources":["../../src/utils/ws-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,SAAS,GAAG,SAAS,CAAC;IAC5B,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CAClC,gBAAgB,EAAE,OAAO,CAAC,kBAAkB,CAAC,EAC7C,UAAU,EAAE,UAAU,GACpB,OAAO,CAAC,cAAc,CAAC,CAezB"}
1
+ {"version":3,"file":"ws-context.d.ts","sourceRoot":"","sources":["../../src/utils/ws-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,cAAc,GAAG,SAAS,CAAC;IACjC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CAClC,gBAAgB,EAAE,OAAO,CAAC,kBAAkB,CAAC,EAC7C,UAAU,EAAE,UAAU,GACpB,OAAO,CAAC,cAAc,CAAC,CAezB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxgt/shared-graphql",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "license": "UNLICENSED",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",