@opensaas/keystone-nextjs-auth 15.0.0 → 18.0.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.
@@ -13,10 +13,8 @@ async function findMatchingIdentity(identityField, identity, queryAPI) {
13
13
  const item = await queryAPI.findOne({
14
14
  where: {
15
15
  [identityField]: identity
16
- },
17
- resolveFields: false
18
- });
19
- console.log(item); // Identity failures with helpful errors
16
+ }
17
+ }); // Identity failures with helpful errors
20
18
 
21
19
  let code;
22
20
 
@@ -71,7 +69,7 @@ function NextAuthPage(props) {
71
69
  const list = query[listKey];
72
70
  const queryAPI = query[listKey];
73
71
  const protectIdentities = true;
74
- return NextAuth__default['default']({
72
+ return NextAuth__default["default"]({
75
73
  providers,
76
74
  callbacks: {
77
75
  async signIn(user, account, profile) {
@@ -128,13 +126,11 @@ function NextAuthPage(props) {
128
126
  }
129
127
  },
130
128
 
131
- async redirect(url, baseUrl) {
129
+ async redirect(url) {
132
130
  return url;
133
131
  },
134
132
 
135
133
  async session(session, token) {
136
- console.log('session:', session);
137
-
138
134
  const returnSession = _objectSpread(_objectSpread({}, session), {}, {
139
135
  data: token.data,
140
136
  subject: token.sub,
@@ -145,8 +141,7 @@ function NextAuthPage(props) {
145
141
  return returnSession;
146
142
  },
147
143
 
148
- async jwt(token, user, account, profile, isNewUser) {
149
- console.log('account:', account);
144
+ async jwt(token) {
150
145
  const identity = token.sub;
151
146
 
152
147
  if (!token.itemId) {
@@ -181,5 +176,5 @@ function NextAuthPage(props) {
181
176
  }
182
177
  const getNextAuthPage = props => () => NextAuthPage(_objectSpread({}, props));
183
178
 
184
- exports['default'] = NextAuthPage;
179
+ exports["default"] = NextAuthPage;
185
180
  exports.getNextAuthPage = getNextAuthPage;
@@ -5,10 +5,8 @@ async function findMatchingIdentity(identityField, identity, queryAPI) {
5
5
  const item = await queryAPI.findOne({
6
6
  where: {
7
7
  [identityField]: identity
8
- },
9
- resolveFields: false
10
- });
11
- console.log(item); // Identity failures with helpful errors
8
+ }
9
+ }); // Identity failures with helpful errors
12
10
 
13
11
  let code;
14
12
 
@@ -120,13 +118,11 @@ function NextAuthPage(props) {
120
118
  }
121
119
  },
122
120
 
123
- async redirect(url, baseUrl) {
121
+ async redirect(url) {
124
122
  return url;
125
123
  },
126
124
 
127
125
  async session(session, token) {
128
- console.log('session:', session);
129
-
130
126
  const returnSession = _objectSpread(_objectSpread({}, session), {}, {
131
127
  data: token.data,
132
128
  subject: token.sub,
@@ -137,8 +133,7 @@ function NextAuthPage(props) {
137
133
  return returnSession;
138
134
  },
139
135
 
140
- async jwt(token, user, account, profile, isNewUser) {
141
- console.log('account:', account);
136
+ async jwt(token) {
142
137
  const identity = token.sub;
143
138
 
144
139
  if (!token.itemId) {
@@ -1,57 +1,38 @@
1
- import type {
2
- GraphQLSchemaExtension,
3
- KeystoneContext,
4
- } from '@keystone-next/keystone/types';
1
+ import type { ItemRootValue } from '@keystone-next/keystone/types';
2
+ import { graphql } from '@keystone-next/keystone';
5
3
 
6
4
  import { AuthGqlNames } from '../types';
7
5
 
8
- export function getBaseAuthSchema<I extends string, S extends string>({
6
+ export function getBaseAuthSchema({
9
7
  listKey,
10
8
  gqlNames,
9
+ base,
11
10
  }: {
12
11
  listKey: string;
13
12
  gqlNames: AuthGqlNames;
14
- }): GraphQLSchemaExtension {
15
- return {
16
- typeDefs: `
17
- # Auth
18
- union AuthenticatedItem = ${listKey}
19
- type Query {
20
- authenticatedItem: AuthenticatedItem
21
- }
22
- `,
23
- resolvers: {
24
- Query: {
25
- async authenticatedItem(root, args, { session, query }: KeystoneContext) {
13
+ base: graphql.BaseSchemaMeta;
14
+ }) {
15
+ const extension = {
16
+ query: {
17
+ authenticatedItem: graphql.field({
18
+ type: graphql.union({
19
+ name: 'AuthenticatedItem',
20
+ types: [base.object(listKey) as graphql.ObjectType<ItemRootValue>],
21
+ resolveType: (root, context) => context.session?.listKey,
22
+ }),
23
+ resolve(root, args, { session, db }) {
26
24
  if (
27
25
  typeof session?.itemId === 'string' &&
28
26
  typeof session.listKey === 'string'
29
27
  ) {
30
- try {
31
- return query[session.listKey].findOne({
32
- where: { id: session.itemId },
33
- resolveFields: false,
34
- });
35
- } catch (e) {
36
- return null;
37
- }
28
+ return db[session.listKey].findOne({
29
+ where: { id: session.itemId },
30
+ });
38
31
  }
39
32
  return null;
40
33
  },
41
- },
42
- AuthenticatedItem: {
43
- __resolveType(rootVal: any, { session }: KeystoneContext) {
44
- return session?.listKey;
45
- },
46
- },
47
- // TODO: Is this the preferred approach for this?
48
- [gqlNames.ItemAuthenticationWithPasswordResult]: {
49
- __resolveType(rootVal: any) {
50
- return rootVal.sessionToken
51
- ? gqlNames.ItemAuthenticationWithPasswordSuccess
52
- : gqlNames.ItemAuthenticationWithPasswordFailure;
53
- },
54
- },
34
+ }),
55
35
  },
56
36
  };
37
+ return { extension };
57
38
  }
package/src/index.ts CHANGED
@@ -236,7 +236,7 @@ export function createAuth<GeneratedListTypes extends BaseGeneratedListTypes>({
236
236
  ...keystoneConfig.ui,
237
237
  publicPages: [...(keystoneConfig.ui.publicPages || []), ...publicPages],
238
238
  getAdditionalFiles: [
239
- ...(keystoneConfig.ui.getAdditionalFiles || []),
239
+ ...(keystoneConfig.ui?.getAdditionalFiles || []),
240
240
  getAdditionalFiles,
241
241
  ],
242
242
  pageMiddleware: async (args) =>
@@ -266,10 +266,11 @@ export function createAuth<GeneratedListTypes extends BaseGeneratedListTypes>({
266
266
  },
267
267
  };
268
268
  }
269
- let { session } = keystoneConfig;
270
- if (session && sessionData) {
271
- session = withItemData(session);
272
- }
269
+
270
+ if (!keystoneConfig.session)
271
+ throw new TypeError('Missing .session configuration');
272
+ const session = withItemData(keystoneConfig.session);
273
+
273
274
  const existingExtendGraphQLSchema = keystoneConfig.extendGraphqlSchema;
274
275
  return {
275
276
  ...keystoneConfig,
@@ -10,10 +10,7 @@ export async function findMatchingIdentity(
10
10
  > {
11
11
  const item = await queryAPI.findOne({
12
12
  where: { [identityField]: identity },
13
- resolveFields: false,
14
13
  });
15
- console.log(item);
16
-
17
14
  // Identity failures with helpful errors
18
15
  let code: AuthTokenRequestErrorCode | undefined;
19
16
  if (!item) {
@@ -94,11 +94,10 @@ export default function NextAuthPage(props: NextAuthPageProps) {
94
94
  return result.success;
95
95
  }
96
96
  },
97
- async redirect(url, baseUrl) {
97
+ async redirect(url) {
98
98
  return url;
99
99
  },
100
100
  async session(session: any, token: any) {
101
- console.log('session:', session);
102
101
  const returnSession = {
103
102
  ...session,
104
103
  data: token.data,
@@ -108,9 +107,7 @@ export default function NextAuthPage(props: NextAuthPageProps) {
108
107
  };
109
108
  return returnSession;
110
109
  },
111
- async jwt(token, user, account, profile, isNewUser) {
112
- console.log('account:', account);
113
-
110
+ async jwt(token) {
114
111
  const identity = token.sub;
115
112
  if (!token.itemId) {
116
113
  const result = await validateNextAuth(
package/src/schema.ts CHANGED
@@ -1,28 +1,43 @@
1
- import { mergeSchemas } from '@graphql-tools/merge';
2
1
  import { ExtendGraphqlSchema } from '@keystone-next/keystone/types';
3
2
 
3
+ import { assertInputObjectType, GraphQLString, GraphQLID } from 'graphql';
4
+ import { graphql } from '@keystone-next/keystone';
4
5
  import { AuthGqlNames } from './types';
5
6
  import { getBaseAuthSchema } from './gql/getBaseAuthSchema';
6
7
 
7
- export const getSchemaExtension =
8
- ({
9
- identityField,
10
- listKey,
11
- gqlNames,
12
- }: {
13
- identityField: string;
14
- listKey: string;
15
- gqlNames: AuthGqlNames;
16
- }): ExtendGraphqlSchema =>
17
- (schema) =>
18
- [
19
- getBaseAuthSchema({
20
- listKey,
21
- gqlNames,
22
- }),
23
- ]
24
- .filter((x) => x)
25
- .reduce(
26
- (s, extension) => mergeSchemas({ schemas: [s], ...extension }),
27
- schema
8
+ export const getSchemaExtension = ({
9
+ identityField,
10
+ listKey,
11
+ gqlNames,
12
+ }: {
13
+ identityField: string;
14
+ listKey: string;
15
+ gqlNames: AuthGqlNames;
16
+ }): ExtendGraphqlSchema =>
17
+ graphql.extend((base) => {
18
+ const uniqueWhereInputType = assertInputObjectType(
19
+ base.schema.getType(`${listKey}WhereUniqueInput`)
20
+ );
21
+ const identityFieldOnUniqueWhere =
22
+ uniqueWhereInputType.getFields()[identityField];
23
+ if (
24
+ identityFieldOnUniqueWhere?.type !== GraphQLString &&
25
+ identityFieldOnUniqueWhere?.type !== GraphQLID
26
+ ) {
27
+ throw new Error(
28
+ `createAuth was called with an identityField of ${identityField} on the list ${listKey} ` +
29
+ `but that field doesn't allow being searched uniquely with a String or ID. ` +
30
+ `You should likely add \`isIndexed: 'unique'\` ` +
31
+ `to the field at ${listKey}.${identityField}`
28
32
  );
33
+ }
34
+ const baseSchema = getBaseAuthSchema({
35
+ listKey,
36
+ gqlNames,
37
+ base,
38
+ });
39
+
40
+ return [baseSchema.extension].filter(
41
+ (x): x is Exclude<typeof x, undefined> => x !== undefined
42
+ );
43
+ });
@@ -3,13 +3,11 @@ import { AuthGqlNames } from '../types';
3
3
 
4
4
  const template = `
5
5
  import getNextAuthPage from '@opensaas/keystone-nextjs-auth/pages/NextAuthPage';
6
- import { nextAuthProviders as Providers } from '@opensaas/keystone-nextjs-auth';
7
6
  import { query } from '.keystone/api';
8
7
  import keystoneConfig from '../../../../../keystone';
9
8
 
10
9
  export default getNextAuthPage({
11
10
  identityField: '<%= identityField %>',
12
- mutationName: '<%= gqlNames.authenticateItemWithPassword %>',
13
11
  sessionData: '<%= sessionData %>',
14
12
  listKey: '<%= listKey %>',
15
13
  userMap: <%- JSON.stringify(userMap) %>,
@@ -27,10 +27,30 @@ module.exports = withPreconstruct({
27
27
  /@keystone-next\\/keystone(?!\\/___internal-do-not-use-will-break-in-patch\\/admin-ui\\/id-field-view|\\/fields\\/types\\/[^\\/]+\\/views)/,
28
28
  /.prisma\\/client/
29
29
  ];
30
+ // we need to set these to true so that when __dirname/__filename is used
31
+ // to resolve the location of field views, we will get a path that we can use
32
+ // rather than just the __dirname/__filename of the generated file.
33
+ // https://webpack.js.org/configuration/node/#node__filename
34
+ (_config$node = config.node) !== null && _config$node !== void 0 ? _config$node : config.node = {};
35
+ config.node.__dirname = true;
36
+ config.node.__filename = true;
30
37
  }
31
38
  return config;
32
39
  },
40
+ <% if (keystonePath) { %>
41
+ <% if (process.env.NODE_ENV != 'production') { %>
42
+ async rewrites() {
43
+ return [
44
+ {
45
+ source: '/api/__keystone_api_build',
46
+ destination: 'http://localhost:3000<%= keystonePath || '' %>/api/__keystone_api_build',
47
+ basePath: false
48
+ }
49
+ ];
50
+ },
51
+ <% }%>
33
52
  basePath: '<%= keystonePath || '' %>'
53
+ <% } %>
34
54
  });
35
55
  `;
36
56
  export const nextConfigTemplate = ({
package/src/types.ts CHANGED
@@ -44,17 +44,6 @@ export type AuthConfig<GeneratedListTypes extends BaseGeneratedListTypes> = {
44
44
  providers: NextAuthProviders;
45
45
  };
46
46
 
47
- export type InitFirstItemConfig<
48
- GeneratedListTypes extends BaseGeneratedListTypes
49
- > = {
50
- /** Array of fields to collect, e.g ['name', 'email', 'password'] */
51
- fields: GeneratedListTypes['fields'][];
52
- /** Suppresses the second screen where we ask people to subscribe and follow Keystone */
53
- skipKeystoneWelcome?: boolean;
54
- /** Extra input to add for the create mutation */
55
- itemData?: Partial<GeneratedListTypes['inputs']['create']>;
56
- };
57
-
58
47
  export type AuthTokenRequestErrorCode =
59
48
  | 'IDENTITY_NOT_FOUND'
60
49
  | 'MULTIPLE_IDENTITY_MATCHES';