diff --git a/.changeset/goodbye-busted-session.md b/.changeset/goodbye-busted-session.md index 929de598389..33d33ea1077 100644 --- a/.changeset/goodbye-busted-session.md +++ b/.changeset/goodbye-busted-session.md @@ -2,4 +2,4 @@ '@keystone-6/core': major --- -Removes `createContext`, `createRequestContext` - replace any relevant usage with `.sudo`, `.withSession` or `withRequest` +Removes `createContext`, `createRequestContext` - replace any relevant usage with `context.sudo()`, `context.withSession()` or `context.withRequest()` diff --git a/docs/pages/docs/config/config.md b/docs/pages/docs/config/config.md index 14cd8e1ab90..f73973c712a 100644 --- a/docs/pages/docs/config/config.md +++ b/docs/pages/docs/config/config.md @@ -221,8 +221,8 @@ export default config({ maxFileSize: 200 * 1024 * 1024, healthCheck: true, {% if $nextRelease %} - extendExpressApp: (app, context) => { /* ... */ }, - extendHttpServer: (httpServer, context, graphQLSchema) => { /* ... */ }, + extendExpressApp: (app, commonContext) => { /* ... */ }, + extendHttpServer: (httpServer, commonContext, graphQLSchema) => { /* ... */ }, {% else /%} extendExpressApp: (app, createContext) => { /* ... */ }, extendHttpServer: (httpServer, createContext, graphQLSchema) => { /* ... */ }, @@ -276,7 +276,7 @@ The function is passed two arguments: {% if $nextRelease %} - `context`: A Keystone Context {% else /%} -- `async createContext(req, res)`: A function you can call to create a Keystone Context for the request +- `async createRequestContext(req, res)`: A function you can call to create a Keystone Context for the request {% /if %} For example, you could add your own request logging middleware: @@ -314,17 +314,17 @@ You could also use it to add custom REST endpoints to your server, by creating a export default config({ server: { {% if $nextRelease %} - extendExpressApp: (app, _context) => { + extendExpressApp: (app, commonContext) => { app.get('/api/users', async (req, res) => { - const context = _context.withRequest(req, res); + const context = commonContext.withRequest(req, res); const users = await context.query.User.findMany(); res.json(users); }); }, {% else /%} - extendExpressApp: (app, createContext) => { + extendExpressApp: (app, createRequestContext) => { app.get('/api/users', async (req, res) => { - const context = await createContext(req, res); + const context = await createRequestContext(req, res); const users = await context.query.User.findMany(); res.json(users); }); @@ -338,7 +338,7 @@ The created context will be bound to the request, including the current visitor' _ProTip!_: `extendExpressApp` can be `async` -## extendHttpServer +### extendHttpServer This lets you interact with the node [http.Server](https://nodejs.org/api/http.html#class-httpserver) that Keystone uses. @@ -361,7 +361,7 @@ import { useServer as wsUseServer } from 'graphql-ws/lib/use/ws'; export default config({ server: { {% if $nextRelease %} - extendHttpServer: (httpServer, context, graphqlSchema) => { + extendHttpServer: (httpServer, commonContext, graphqlSchema) => { const wss = new WebSocketServer({ server: httpServer, path: '/api/graphql', @@ -394,18 +394,11 @@ import type { SessionStrategy } from '@keystone-6/core/types'; The `session` config option allows you to configure session management of your Keystone system. It has a TypeScript type of `SessionStrategy`. -{% if $nextRelease %} -In general you will use `SessionStrategy` objects from the `@keystone-6/auth/session` package, rather than writing this yourself. -{% else /%} In general you will use `SessionStrategy` objects from the `@keystone-6/core/session` package, rather than writing this yourself. -{% /if %} + ```typescript -{% if $nextRelease %} -import { statelessSessions } from '@keystone-6/auth/session'; -{% else /%} import { statelessSessions } from '@keystone-6/core/session'; -{% /if %} export default config({ session: statelessSessions({ /* ... */ }), diff --git a/docs/pages/docs/config/session.md b/docs/pages/docs/config/session.md index 620c14c59ce..072fb2e7351 100644 --- a/docs/pages/docs/config/session.md +++ b/docs/pages/docs/config/session.md @@ -105,14 +105,25 @@ Interface: ## Session context -If you configure your Keystone session with session management then the [`KeystoneContext`](../context/overview) type will include three session related properties. +If you configure your Keystone session with session management then the [`KeystoneContext`](../context/overview) type will include the following session related properties. +{% if $nextRelease %} +- `session`: An object representing the session data. The value will depend on the value passed into `context.sessionStrategy.start()`. +- `sessionStrategy`: an object that, when using `statelessSessions` or `storedSessions` from `@keystone-6/core/session` includes the following functions: + - `get({context})`: a function that returns a `session` object based on `context` - this needs to be a `context` with a valid `req` (using `context.withRequest`). This function is called by Keystone to get the value of `context.session` + - `start({context, data})`: a function that, given a valid `context.res` starts a new session containing what is passed into `data`. + - `end({context})`: a function that, given a valid `context.res` ends a session. + +The `start` and `end` functions will be used by [authentication mutations](./auth) to start and end authenticated sessions. +These mutations will set the value of `session` to include the values `{ listKey, itemId }`. +{% else /%} - `session`: An object representing the session data. The value will depend on the value passed into `context.startSession()`. - `startSession`: A function `data => {...}` which will start a new session using the provided `data` value. - `endSession`: A function `() => {...}` which will end the current session. The `startSession` and `endSession` functions will be used by [authentication mutations](./auth) to start and end authenticated sessions. These mutations will set the value of `session` to include the values `{ listKey, itemId }`. +{% /if %} ## Related resources diff --git a/docs/pages/docs/context/overview.md b/docs/pages/docs/context/overview.md index 0f10d09be55..8606fd92c73 100644 --- a/docs/pages/docs/context/overview.md +++ b/docs/pages/docs/context/overview.md @@ -16,29 +16,37 @@ import type { Context } from '.keystone/types'; context = { // HTTP request object req, +{% if $nextRelease %} + res, +{% /if %} // Query API query, // Internal DB object API - db + db, // GraphQL helpers graphql: { schema, run, raw, - }; + }, // Session API session, + {% if $nextRelease %} + sessionStrategy + {% else /%} startSession, endSession, + {% /if %} // New context creators sudo, exitSudo, withSession, + withRequest, // Database access prisma, @@ -57,8 +65,10 @@ context = { ### HTTP request object -`req`: The [IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage) object from the HTTP request which called the GraphQL API. - +`req`: The [IncomingMessage](https://nodejs.org/api/http.html#class-httpincomingmessage) object from the HTTP request. +{% if $nextRelease %} +`res`: The [ServerResonse](https://nodejs.org/api/http.html#class-httpserverresponse) object for HTTP request. +{% /if %} ### Query API `query`: The [Query API](./query), which can be used to perform CRUD operations against your GraphQL API and return a queried value. @@ -93,18 +103,22 @@ See the [session API](../config/session#session-context) for more details. `session`: The current session data object. +{% if $nextRelease %} +`sessionStrategy`: an object containing functions(`get`, `start` and `end`) that manipulate a session. See the [session API](../config/session#session-context) for more details. +{% else /%} `startSession`: An internal helper function used by authentication mutations to start a session on a successful login. This should not be called directly. `endSession`: An internal helper function used by authentication mutations to end a session on logout. This should not be called directly. +{% /if %} ### New context creators When using the `context.query`, `context.graphql.run`, and `context.graphql.raw` APIs, access control and session information is passed through to these calls from the `context` object. The following functions will create a new `Context` object with this behaviour modified. -`sudo()`: A function which returns a new `Context` object with all access control disabled and all filters enabled for subsequent API calls. +`sudo()`: A function which returns a new elevated `Context` object with all access control disabled and all filters enabled for subsequent API calls. -`exitSudo()`: A function which returns a new `Context` object with all access control re-enabled for subsequent API calls. +`withRequest(req, res)`: A function which returns a new user `Context` object with a session and access control based on the `req` given. `withSession(newSession)`: A function which returns a new `Context` object with the `.session` object replaced with `newSession`. diff --git a/examples/extend-graphql-subscriptions/websocket.ts b/examples/extend-graphql-subscriptions/websocket.ts index 5a9c493e2cf..c6aaf4035b5 100644 --- a/examples/extend-graphql-subscriptions/websocket.ts +++ b/examples/extend-graphql-subscriptions/websocket.ts @@ -19,7 +19,7 @@ globalThis.graphqlSubscriptionPubSub = pubSub; export const extendHttpServer = ( httpServer: http.Server, - _context: Context, + commonContext: Context, graphqlSchema: KeystoneGraphQLAPI['schema'] ): void => { // Setup WebSocket server using 'ws' @@ -34,7 +34,7 @@ export const extendHttpServer = ( schema: graphqlSchema, // run these onSubscribe functions as needed or remove them if you don't need them onSubscribe: async (ctx: any, msg) => { - const context = await _context.withRequest(ctx.extra.request); + const context = await commonContext.withRequest(ctx.extra.request); // Return the execution args for this subscription passing through the Keystone Context return { schema: graphqlSchema, diff --git a/examples/rest-api/keystone.ts b/examples/rest-api/keystone.ts index ef6b29ad6ba..c4cbe6bdba3 100644 --- a/examples/rest-api/keystone.ts +++ b/examples/rest-api/keystone.ts @@ -31,9 +31,9 @@ export default config({ - Adds a GET handler for tasks, which will query for tasks in the Keystone schema and return the results as JSON */ - extendExpressApp: (app, context) => { + extendExpressApp: (app, commonContext) => { app.use('/rest', async (req, res, next) => { - (req as any).context = await context.withRequest(req, res); + (req as any).context = await commonContext.withRequest(req, res); next(); });