@opensaas/keystone-nextjs-auth 20.5.0 → 21.1.1

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.
@@ -49,23 +49,42 @@ async function validateNextAuth(identityField, identity, protectIdentities, item
49
49
 
50
50
  function NextAuthPage(props) {
51
51
  const {
52
+ autoCreate,
53
+ cookies,
54
+ events,
55
+ identityField,
56
+ jwt,
57
+ listKey,
58
+ pages,
52
59
  providers,
53
60
  query,
54
- identityField,
61
+ resolver,
55
62
  sessionData,
56
- listKey,
57
- autoCreate,
58
- userMap,
59
- accountMap,
60
- profileMap,
61
63
  sessionSecret
62
- } = props;
64
+ } = props; // TODO: (v1.1). https://github.com/ijsto/keystone-6-oauth/projects/1#card-78602004
65
+
66
+ console.log('NextAuthPages... ', pages);
67
+
68
+ if (!query) {
69
+ console.error('NextAuthPage got no query.');
70
+ return null;
71
+ }
72
+
73
+ if (!providers || !providers.length) {
74
+ console.error('You need to provide at least one provider.');
75
+ return null;
76
+ }
77
+
63
78
  const list = query[listKey];
64
79
  const queryAPI = query[listKey];
65
80
  const protectIdentities = true;
66
81
  return NextAuth({
67
- secret: sessionSecret,
82
+ cookies,
68
83
  providers,
84
+ pages: pages || {},
85
+ events: events || {},
86
+ jwt: jwt || {},
87
+ secret: sessionSecret,
69
88
  callbacks: {
70
89
  async signIn({
71
90
  user,
@@ -82,28 +101,16 @@ function NextAuthPage(props) {
82
101
  identity = 0;
83
102
  }
84
103
 
85
- const result = await validateNextAuth(identityField, identity, protectIdentities, queryAPI);
86
- const data = {}; // eslint-disable-next-line no-restricted-syntax
87
-
88
- for (const key in userMap) {
89
- if (Object.prototype.hasOwnProperty.call(userMap, key)) {
90
- data[key] = user[userMap[key]];
91
- }
92
- } // eslint-disable-next-line no-restricted-syntax
93
-
104
+ const userInput = resolver ? await resolver({
105
+ user,
106
+ account,
107
+ profile
108
+ }) : {};
109
+ const result = await validateNextAuth(identityField, identity, protectIdentities, queryAPI); // ID
94
110
 
95
- for (const key in accountMap) {
96
- if (Object.prototype.hasOwnProperty.call(accountMap, key)) {
97
- data[key] = account[accountMap[key]];
98
- }
99
- } // eslint-disable-next-line no-restricted-syntax
100
-
101
-
102
- for (const key in profileMap) {
103
- if (Object.prototype.hasOwnProperty.call(profileMap, key)) {
104
- data[key] = profile[profileMap[key]];
105
- }
106
- }
111
+ const data = _objectSpread({
112
+ [identityField]: identity
113
+ }, userInput);
107
114
 
108
115
  if (!result.success) {
109
116
  if (!autoCreate) {
@@ -158,9 +165,7 @@ function NextAuthPage(props) {
158
165
  const result = await validateNextAuth(identityField, identity, protectIdentities, queryAPI);
159
166
 
160
167
  if (!result.success) {
161
- return {
162
- result: false
163
- };
168
+ return token;
164
169
  }
165
170
 
166
171
  token.itemId = result.item.id;
@@ -1,15 +1,11 @@
1
1
  import type { BaseItem } from '@keystone-6/core/types';
2
2
  import { graphql } from '@keystone-6/core';
3
3
 
4
- import { AuthGqlNames } from '../types';
5
-
6
4
  export function getBaseAuthSchema({
7
5
  listKey,
8
- gqlNames,
9
6
  base,
10
7
  }: {
11
8
  listKey: string;
12
- gqlNames: AuthGqlNames;
13
9
  base: graphql.BaseSchemaMeta;
14
10
  }) {
15
11
  const extension = {
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import url from 'url';
1
+ import url from "url";
2
2
  import {
3
3
  AdminFileToWrite,
4
4
  BaseListTypeInfo,
@@ -7,23 +7,19 @@ import {
7
7
  AdminUIConfig,
8
8
  SessionStrategy,
9
9
  BaseKeystoneTypeInfo,
10
- } from '@keystone-6/core/types';
11
- import { getSession } from 'next-auth/react';
12
- import { getToken } from 'next-auth/jwt';
13
- import * as cookie from 'cookie';
14
- import { Provider } from 'next-auth/providers';
15
- import { NextApiRequest } from 'next';
16
- import { nextConfigTemplate } from './templates/next-config';
10
+ } from "@keystone-6/core/types";
11
+ import { getSession } from "next-auth/react";
12
+ import { getToken } from "next-auth/jwt";
13
+ import { Provider } from "next-auth/providers";
14
+
15
+ import * as cookie from "cookie";
16
+
17
+ import { nextConfigTemplate } from "./templates/next-config";
17
18
  // import * as Path from 'path';
18
19
 
19
- import {
20
- AuthConfig,
21
- AuthGqlNames,
22
- KeystoneAuthConfig,
23
- NextAuthSession,
24
- } from './types';
25
- import { getSchemaExtension } from './schema';
26
- import { authTemplate } from './templates/auth';
20
+ import { AuthConfig, KeystoneOAuthConfig, NextAuthSession } from "./types";
21
+ import { getSchemaExtension } from "./schema";
22
+ import { authTemplate } from "./templates/auth";
27
23
 
28
24
  /**
29
25
  * createAuth function
@@ -31,35 +27,25 @@ import { authTemplate } from './templates/auth';
31
27
  * Generates config for Keystone to implement standard auth features.
32
28
  */
33
29
 
34
- export type { NextAuthProviders, KeystoneAuthConfig } from './types';
30
+ export type { NextAuthProviders, KeystoneOAuthConfig } from "./types";
35
31
  export function createAuth<GeneratedListTypes extends BaseListTypeInfo>({
36
- listKey,
37
- identityField,
38
- sessionData,
39
32
  autoCreate,
40
- userMap,
41
- accountMap,
42
- profileMap,
33
+ cookies,
34
+ identityField,
35
+ listKey,
43
36
  keystonePath,
37
+ pages,
38
+ resolver,
44
39
  providers,
40
+ sessionData,
45
41
  sessionSecret,
46
42
  }: AuthConfig<GeneratedListTypes>) {
47
43
  // The protectIdentities flag is currently under review to see whether it should be
48
44
  // part of the createAuth API (in which case its use cases need to be documented and tested)
49
45
  // or whether always being true is what we want, in which case we can refactor our code
50
46
  // to match this. -TL
51
- const gqlNames: AuthGqlNames = {
52
- // Core
53
- authenticateItemWithPassword: `authenticate${listKey}WithPassword`,
54
- ItemAuthenticationWithPasswordResult: `${listKey}AuthenticationWithPasswordResult`,
55
- ItemAuthenticationWithPasswordSuccess: `${listKey}AuthenticationWithPasswordSuccess`,
56
- ItemAuthenticationWithPasswordFailure: `${listKey}AuthenticationWithPasswordFailure`,
57
- // Initial data
58
- CreateInitialInput: `CreateInitial${listKey}Input`,
59
- createInitialItem: `createInitial${listKey}`,
60
- };
61
47
 
62
- const customPath = !keystonePath || keystonePath === '/' ? '' : keystonePath;
48
+ const customPath = !keystonePath || keystonePath === "/" ? "" : keystonePath;
63
49
  /**
64
50
  * pageMiddleware
65
51
  *
@@ -70,25 +56,34 @@ export function createAuth<GeneratedListTypes extends BaseListTypeInfo>({
70
56
  * - to the init page when initFirstItem is configured, and there are no user in the database
71
57
  * - to the signin page when no valid session is present
72
58
  */
73
- const pageMiddleware: AdminUIConfig<BaseKeystoneTypeInfo>['pageMiddleware'] =
59
+ const pageMiddleware: AdminUIConfig<BaseKeystoneTypeInfo>["pageMiddleware"] =
74
60
  async ({ context, isValidSession }) => {
75
61
  const { req, session } = context;
76
62
  const pathname = url.parse(req?.url!).pathname!;
77
- if (pathname === `${customPath}/api/__keystone_api_build`) {
78
- return;
79
- }
63
+
80
64
  if (isValidSession) {
81
65
  if (pathname === `${customPath}/api/auth/signin`) {
82
- return { kind: 'redirect', to: `${customPath}` };
66
+ return { kind: "redirect", to: `${customPath}` };
83
67
  }
84
- if (customPath !== '' && pathname === '/') {
85
- return { kind: 'redirect', to: `${customPath}` };
68
+ if (customPath !== "" && pathname === "/") {
69
+ return { kind: "redirect", to: `${customPath}` };
86
70
  }
87
71
  return;
88
72
  }
89
-
73
+ if (
74
+ pathname.includes("/_next/") ||
75
+ pathname.includes("/api/auth/") ||
76
+ pathname.includes(pages?.signIn) ||
77
+ pathname.includes(pages?.error) ||
78
+ pathname.includes(pages?.signOut)
79
+ ) {
80
+ return;
81
+ }
90
82
  if (!session && !pathname.includes(`${customPath}/api/auth/`)) {
91
- return { kind: 'redirect', to: `${customPath}/api/auth/signin` };
83
+ return {
84
+ kind: "redirect",
85
+ to: pages?.signIn || `${customPath}/api/auth/signin`,
86
+ };
92
87
  }
93
88
  };
94
89
 
@@ -103,23 +98,19 @@ export function createAuth<GeneratedListTypes extends BaseListTypeInfo>({
103
98
  const getAdditionalFiles = () => {
104
99
  const filesToWrite: AdminFileToWrite[] = [
105
100
  {
106
- mode: 'write',
107
- outputPath: 'pages/api/auth/[...nextauth].js',
101
+ mode: "write",
102
+ outputPath: "pages/api/auth/[...nextauth].js",
108
103
  src: authTemplate({
109
- gqlNames,
104
+ autoCreate,
110
105
  identityField,
111
- sessionData,
112
106
  listKey,
113
- autoCreate,
114
- userMap,
115
- accountMap,
116
- profileMap,
107
+ sessionData,
117
108
  sessionSecret,
118
109
  }),
119
110
  },
120
111
  {
121
- mode: 'write',
122
- outputPath: 'next.config.js',
112
+ mode: "write",
113
+ outputPath: "next.config.js",
123
114
  src: nextConfigTemplate({ keystonePath: customPath }),
124
115
  },
125
116
  ];
@@ -132,13 +123,17 @@ export function createAuth<GeneratedListTypes extends BaseListTypeInfo>({
132
123
  * Must be added to the ui.publicPages config
133
124
  */
134
125
  const publicPages = [
126
+ `${customPath}/api/__keystone_api_build`,
135
127
  `${customPath}/api/auth/csrf`,
136
128
  `${customPath}/api/auth/signin`,
137
129
  `${customPath}/api/auth/callback`,
138
130
  `${customPath}/api/auth/session`,
139
131
  `${customPath}/api/auth/providers`,
140
132
  `${customPath}/api/auth/signout`,
133
+ `${customPath}/api/auth/error`,
141
134
  ];
135
+ // TODO: Add Provider Types
136
+ // @ts-ignore
142
137
  function addPages(provider: Provider) {
143
138
  const name = provider.id;
144
139
  publicPages.push(`${customPath}/api/auth/signin/${name}`);
@@ -154,7 +149,6 @@ export function createAuth<GeneratedListTypes extends BaseListTypeInfo>({
154
149
  const extendGraphqlSchema = getSchemaExtension({
155
150
  identityField,
156
151
  listKey,
157
- gqlNames,
158
152
  });
159
153
 
160
154
  /**
@@ -169,13 +163,16 @@ export function createAuth<GeneratedListTypes extends BaseListTypeInfo>({
169
163
  throw new Error(msg);
170
164
  }
171
165
 
166
+ // TODO: Check if providers
167
+ // TODO: Check other required commands/data
168
+
172
169
  // TODO: Check for String-like typing for identityField? How?
173
170
  // TODO: Validate that the identifyField is unique.
174
171
  // TODO: If this field isn't required, what happens if I try to log in as `null`?
175
172
  const identityFieldConfig = listConfig.fields[identityField];
176
173
  if (identityFieldConfig === undefined) {
177
- const i = JSON.stringify(identityField);
178
- const msg = `A createAuth() invocation for the "${listKey}" list specifies ${i} as its identityField but no field with that key exists on the list.`;
174
+ const identityFieldName = JSON.stringify(identityField);
175
+ const msg = `A createAuth() invocation for the "${listKey}" list specifies ${identityFieldName} as its identityField but no field with that key exists on the list.`;
179
176
  throw new Error(msg);
180
177
  }
181
178
  };
@@ -194,18 +191,25 @@ export function createAuth<GeneratedListTypes extends BaseListTypeInfo>({
194
191
  const { get, start, ...sessionStrategy } = _sessionStrategy;
195
192
  return {
196
193
  ...sessionStrategy,
197
- start,
194
+ start: async ({ res }) => {
195
+ console.log("start");
196
+
197
+ const session = await start({ res });
198
+ return session;
199
+ },
198
200
  get: async ({ req }) => {
199
201
  const pathname = url.parse(req?.url!).pathname!;
200
- if (pathname.includes('/api/auth')) {
202
+ if (pathname.includes("/api/auth")) {
201
203
  return;
202
204
  }
203
- if (req.headers.authorization?.split(' ')[0] === 'Bearer') {
204
- const request = req as NextApiRequest;
205
- const token = await getToken({ req: request, secret: sessionSecret });
205
+ if (req.headers.authorization?.split(" ")[0] === "Bearer") {
206
+ const token = (await getToken({
207
+ req,
208
+ secret: sessionSecret,
209
+ })) as NextAuthSession;
206
210
 
207
211
  if (token?.data?.id) {
208
- return token as NextAuthSession;
212
+ return token;
209
213
  }
210
214
  }
211
215
  const nextSession: unknown = await getSession({ req });
@@ -216,18 +220,19 @@ export function createAuth<GeneratedListTypes extends BaseListTypeInfo>({
216
220
  },
217
221
  end: async ({ res, req }) => {
218
222
  const TOKEN_NAME =
219
- process.env.NODE_ENV === 'production'
220
- ? '__Secure-next-auth.session-token'
221
- : 'next-auth.session-token';
223
+ process.env.NODE_ENV === "production"
224
+ ? "__Secure-next-auth.session-token"
225
+ : "next-auth.session-token";
222
226
  res.setHeader(
223
- 'Set-Cookie',
224
- cookie.serialize(TOKEN_NAME, '', {
227
+ "Set-Cookie",
228
+ cookie.serialize(TOKEN_NAME, "", {
225
229
  maxAge: 0,
226
230
  expires: new Date(),
227
231
  httpOnly: true,
228
- secure: process.env.NODE_ENV === 'production',
229
- path: '/',
230
- sameSite: 'lax',
232
+ secure: process.env.NODE_ENV === "production",
233
+ path: "/",
234
+ sameSite: "lax",
235
+ // TODO: Update parse to URL
231
236
  domain: url.parse(req.url as string).hostname as string,
232
237
  })
233
238
  );
@@ -245,7 +250,7 @@ export function createAuth<GeneratedListTypes extends BaseListTypeInfo>({
245
250
  * It validates the auth config against the provided keystone config, and preserves existing
246
251
  * config by composing existing extendGraphqlSchema functions and ui config.
247
252
  */
248
- const withAuth = (keystoneConfig: KeystoneConfig): KeystoneAuthConfig => {
253
+ const withAuth = (keystoneConfig: KeystoneConfig): KeystoneOAuthConfig => {
249
254
  validateConfig(keystoneConfig);
250
255
  let { ui } = keystoneConfig;
251
256
  if (keystoneConfig.ui) {
@@ -261,47 +266,44 @@ export function createAuth<GeneratedListTypes extends BaseListTypeInfo>({
261
266
  keystoneConfig?.ui?.pageMiddleware?.(args),
262
267
  enableSessionItem: true,
263
268
  isAccessAllowed: async (context: KeystoneContext) => {
269
+ const { req } = context;
270
+ const pathname = url.parse(req?.url!).pathname!;
271
+
272
+ // Allow nextjs scripts and static files to be accessed without auth
273
+ if (pathname.includes("/_next/")) {
274
+ return true;
275
+ }
276
+
277
+ // Allow keystone to access /api/__keystone_api_build for hot reloading
264
278
  if (
265
- process.env.NODE_ENV !== 'production' &&
279
+ process.env.NODE_ENV !== "production" &&
266
280
  context.req?.url !== undefined &&
267
- new URL(context.req.url, 'http://example.com').pathname ===
281
+ new URL(context.req.url, "http://example.com").pathname ===
268
282
  `${customPath}/api/__keystone_api_build`
269
283
  ) {
270
284
  return true;
271
285
  }
272
- // Allow access to the adminMeta data from the /init path to correctly render that page
273
- // even if the user isn't logged in (which should always be the case if they're seeing /init)
274
- const headers = context.req?.headers;
275
- const host = headers
276
- ? headers['x-forwarded-host'] || headers.host
277
- : null;
278
- const thisUrl = headers?.referer
279
- ? new URL(headers.referer)
280
- : undefined;
281
- const accessingInitPage =
282
- thisUrl?.pathname === '/init' &&
283
- thisUrl?.host === host &&
284
- (await context.sudo().query[listKey].count({})) === 0;
285
- return (
286
- accessingInitPage ||
287
- (keystoneConfig.ui?.isAccessAllowed
288
- ? keystoneConfig.ui.isAccessAllowed(context)
289
- : context.session !== undefined)
290
- );
286
+
287
+ return keystoneConfig.ui?.isAccessAllowed
288
+ ? keystoneConfig.ui.isAccessAllowed(context)
289
+ : context.session !== undefined;
291
290
  },
292
291
  };
293
292
  }
294
293
 
295
294
  if (!keystoneConfig.session)
296
- throw new TypeError('Missing .session configuration');
295
+ throw new TypeError("Missing .session configuration");
297
296
  const session = withItemData(keystoneConfig.session);
298
297
 
299
298
  const existingExtendGraphQLSchema = keystoneConfig.extendGraphqlSchema;
300
299
  return {
301
300
  ...keystoneConfig,
302
301
  ui,
303
- session,
302
+ cookies,
304
303
  providers,
304
+ pages,
305
+ resolver,
306
+ session,
305
307
  lists: {
306
308
  ...keystoneConfig.lists,
307
309
  },
@@ -1,43 +1,74 @@
1
- import NextAuth from 'next-auth';
1
+ import NextAuth, {
2
+ CookiesOptions,
3
+ EventCallbacks,
4
+ PagesOptions,
5
+ } from 'next-auth';
2
6
  import type { KeystoneListsAPI } from '@keystone-6/core/types';
3
7
  import { Provider } from 'next-auth/providers';
8
+ import { JWTOptions } from 'next-auth/jwt';
4
9
  import { validateNextAuth } from '../lib/validateNextAuth';
5
10
 
6
- // Need to bring in correct props
7
- type NextAuthPageProps = {
11
+ // TODO: See if possible to merge with `type AuthConfig`
12
+ type CoreNextAuthPageProps = {
13
+ autoCreate: boolean;
14
+ cookies?: Partial<CookiesOptions>;
15
+ events?: Partial<EventCallbacks>;
8
16
  identityField: string;
9
- mutationName: string;
10
- providers: Provider[];
11
- query: KeystoneListsAPI<any>;
12
- sessionData: string;
17
+ jwt?: Partial<JWTOptions>;
13
18
  listKey: string;
14
- autoCreate: boolean;
15
- userMap: any;
16
- accountMap: any;
17
- profileMap: any;
19
+ pages?: Partial<PagesOptions>;
20
+ providers?: Provider[];
21
+ resolver?: Function | undefined;
22
+ sessionData: string | undefined;
18
23
  sessionSecret: string;
19
24
  };
20
25
 
26
+ type NextAuthGglProps = {
27
+ mutationName?: string;
28
+ query?: KeystoneListsAPI<any>;
29
+ };
30
+
31
+ export type NextAuthPageProps = CoreNextAuthPageProps & NextAuthGglProps;
32
+
21
33
  export default function NextAuthPage(props: NextAuthPageProps) {
22
34
  const {
35
+ autoCreate,
36
+ cookies,
37
+ events,
38
+ identityField,
39
+ jwt,
40
+ listKey,
41
+ pages,
23
42
  providers,
24
43
  query,
25
- identityField,
44
+ resolver,
26
45
  sessionData,
27
- listKey,
28
- autoCreate,
29
- userMap,
30
- accountMap,
31
- profileMap,
32
46
  sessionSecret,
33
47
  } = props;
48
+ // TODO: (v1.1). https://github.com/ijsto/keystone-6-oauth/projects/1#card-78602004
49
+ console.log('NextAuthPages... ', pages);
50
+
51
+ if (!query) {
52
+ console.error('NextAuthPage got no query.');
53
+ return null;
54
+ }
55
+
56
+ if (!providers || !providers.length) {
57
+ console.error('You need to provide at least one provider.');
58
+ return null;
59
+ }
60
+
34
61
  const list = query[listKey];
35
62
  const queryAPI = query[listKey];
36
63
  const protectIdentities = true;
37
64
 
38
65
  return NextAuth({
39
- secret: sessionSecret,
66
+ cookies,
40
67
  providers,
68
+ pages: pages || {},
69
+ events: events || {},
70
+ jwt: jwt || {},
71
+ secret: sessionSecret,
41
72
  callbacks: {
42
73
  async signIn({ user, account, profile }) {
43
74
  let identity;
@@ -48,31 +79,21 @@ export default function NextAuthPage(props: NextAuthPageProps) {
48
79
  } else {
49
80
  identity = 0;
50
81
  }
82
+ const userInput = resolver
83
+ ? await resolver({ user, account, profile })
84
+ : {};
85
+
51
86
  const result = await validateNextAuth(
52
87
  identityField,
53
88
  identity,
54
89
  protectIdentities,
55
90
  queryAPI
56
91
  );
57
- const data: any = {};
58
- // eslint-disable-next-line no-restricted-syntax
59
- for (const key in userMap) {
60
- if (Object.prototype.hasOwnProperty.call(userMap, key)) {
61
- data[key] = user[userMap[key]];
62
- }
63
- }
64
- // eslint-disable-next-line no-restricted-syntax
65
- for (const key in accountMap) {
66
- if (Object.prototype.hasOwnProperty.call(accountMap, key)) {
67
- data[key] = account[accountMap[key]];
68
- }
69
- }
70
- // eslint-disable-next-line no-restricted-syntax
71
- for (const key in profileMap) {
72
- if (Object.prototype.hasOwnProperty.call(profileMap, key)) {
73
- data[key] = profile[profileMap[key]];
74
- }
75
- }
92
+ // ID
93
+ const data: any = {
94
+ [identityField]: identity,
95
+ ...userInput,
96
+ };
76
97
 
77
98
  if (!result.success) {
78
99
  if (!autoCreate) {
@@ -125,7 +146,7 @@ export default function NextAuthPage(props: NextAuthPageProps) {
125
146
  );
126
147
 
127
148
  if (!result.success) {
128
- return { result: false };
149
+ return token;
129
150
  }
130
151
  token.itemId = result.item.id;
131
152
  }
package/src/schema.ts CHANGED
@@ -1,39 +1,17 @@
1
1
  import { ExtendGraphqlSchema } from '@keystone-6/core/types';
2
2
 
3
- import { assertInputObjectType, GraphQLString, GraphQLID } from 'graphql';
4
3
  import { graphql } from '@keystone-6/core';
5
- import { AuthGqlNames } from './types';
6
4
  import { getBaseAuthSchema } from './gql/getBaseAuthSchema';
7
5
 
8
6
  export const getSchemaExtension = ({
9
- identityField,
10
7
  listKey,
11
- gqlNames,
12
8
  }: {
13
9
  identityField: string;
14
10
  listKey: string;
15
- gqlNames: AuthGqlNames;
16
11
  }): ExtendGraphqlSchema =>
17
12
  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}`
32
- );
33
- }
34
13
  const baseSchema = getBaseAuthSchema({
35
14
  listKey,
36
- gqlNames,
37
15
  base,
38
16
  });
39
17