naystack 1.2.14 → 1.2.16

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 CHANGED
@@ -19,13 +19,15 @@ yarn add naystack
19
19
 
20
20
  Naystack provides the following modules, each accessible via its own import path:
21
21
 
22
- | Module | Import Path | Description |
23
- | ----------- | ------------------ | ----------------------------------------------- |
24
- | **Auth** | `naystack/auth` | Email, Google, and Instagram authentication |
25
- | **GraphQL** | `naystack/graphql` | GraphQL server initialization with type-graphql |
26
- | **Client** | `naystack/client` | Client-side hooks and utilities |
27
- | **File** | `naystack/file` | File upload to AWS S3 |
28
- | **Socials** | `naystack/socials` | Instagram and Threads API integration |
22
+ | Module | Import Path | Description |
23
+ | ----------- | -------------------------- | ------------------------------------------------------------------ |
24
+ | **Auth** | `naystack/auth` | Email, Google, and Instagram authentication (server-side routes) |
25
+ | **Auth UI** | `naystack/auth/email/client` | Client-side React hooks for login / signup / logout flows |
26
+ | **GraphQL** | `naystack/graphql` | GraphQL server initialization with type-graphql |
27
+ | **GQL App** | `naystack/graphql/client` / `naystack/graphql/server` | Apollo Client helpers for Next.js App Router (client + server) |
28
+ | **Client** | `naystack/client` | Generic client-side hooks and utilities |
29
+ | **File** | `naystack/file` | File upload to AWS S3 |
30
+ | **Socials** | `naystack/socials` | Instagram and Threads API integration |
29
31
 
30
32
  ---
31
33
 
@@ -39,11 +41,21 @@ import {
39
41
  } from "naystack/auth";
40
42
  ```
41
43
 
44
+ ### High-level Auth Flow in a Next.js App Router project
45
+
46
+ From a real-world setup (like `veas-web`), the pieces look like this:
47
+
48
+ - **Server-side auth routes** – created with `getEmailAuthRoutes` (and optionally Google / Instagram)
49
+ - **Server-side GraphQL context** – uses `getUserIdFromRequest` from the email auth routes
50
+ - **Client-side auth hooks** – created with `getEmailAuthUtils` and used in login/signup/logout forms
51
+
52
+ The sections below show each part in more detail.
53
+
42
54
  ### Email Authentication
43
55
 
44
56
  Setup email-based authentication with JWT tokens and optional Turnstile captcha verification.
45
57
 
46
- **Basic Example:**
58
+ **Next.js App Router Example (server routes):**
47
59
 
48
60
  ```typescript
49
61
  const emailAuth = getEmailAuthRoutes({
@@ -61,6 +73,101 @@ const emailAuth = getEmailAuthRoutes({
61
73
  export const { GET, POST, PUT, DELETE, getUserIdFromRequest } = emailAuth;
62
74
  ```
63
75
 
76
+ **Client-side hooks (login, signup, logout) – as used in `veas-web`:**
77
+
78
+ ```typescript
79
+ // app/(auth)/utils.ts
80
+ import { getEmailAuthUtils } from "naystack/auth/email/client";
81
+
82
+ // The argument is the URL where your email auth API lives
83
+ export const { useLogin, useLogout, useSignUp } =
84
+ getEmailAuthUtils("/api/email");
85
+ ```
86
+
87
+ ```typescript
88
+ // app/(auth)/login/components/form.tsx
89
+ "use client";
90
+ import React, { useState } from "react";
91
+ import { useLogin } from "@/app/(auth)/utils";
92
+ import { useRouter } from "next/navigation";
93
+
94
+ export default function LoginForm() {
95
+ const login = useLogin();
96
+ const router = useRouter();
97
+ const [email, setEmail] = useState("");
98
+ const [password, setPassword] = useState("");
99
+
100
+ return (
101
+ <form
102
+ onSubmit={async (e) => {
103
+ e.preventDefault();
104
+ const ok = await login({ email, password });
105
+ if (ok) router.push("/dashboard");
106
+ }}
107
+ >
108
+ {/* inputs + submit */}
109
+ </form>
110
+ );
111
+ }
112
+ ```
113
+
114
+ ```typescript
115
+ // app/(auth)/signup/components/form.tsx
116
+ "use client";
117
+ import React, { useState } from "react";
118
+ import { useSignUp } from "@/app/(auth)/utils";
119
+ import { useRouter } from "next/navigation";
120
+
121
+ export default function SignupForm() {
122
+ const signUp = useSignUp();
123
+ const router = useRouter();
124
+ const [email, setEmail] = useState("");
125
+ const [password, setPassword] = useState("");
126
+
127
+ return (
128
+ <form
129
+ onSubmit={async (e) => {
130
+ e.preventDefault();
131
+ const ok = await signUp({ email, password });
132
+ if (ok) router.push("/onboard");
133
+ }}
134
+ >
135
+ {/* inputs + submit */}
136
+ </form>
137
+ );
138
+ }
139
+ ```
140
+
141
+ ```typescript
142
+ // app/dashboard/components/logout-button.tsx
143
+ "use client";
144
+ import React, { useState } from "react";
145
+ import { useLogout } from "@/app/(auth)/utils";
146
+ import { useRouter } from "next/navigation";
147
+
148
+ export default function LogoutButton() {
149
+ const logout = useLogout();
150
+ const [loading, setLoading] = useState(false);
151
+ const router = useRouter();
152
+
153
+ const handleLogout = async () => {
154
+ setLoading(true);
155
+ try {
156
+ await logout();
157
+ router.push("/login");
158
+ } finally {
159
+ setLoading(false);
160
+ }
161
+ };
162
+
163
+ return (
164
+ <button onClick={handleLogout} disabled={loading}>
165
+ {loading ? "Logging out..." : "Logout"}
166
+ </button>
167
+ );
168
+ }
169
+ ```
170
+
64
171
  **Real-World Example with Drizzle ORM:**
65
172
 
66
173
  ```typescript
@@ -302,7 +409,7 @@ import {
302
409
  import type { Context, AuthorizedContext } from "naystack/graphql";
303
410
  ```
304
411
 
305
- ### Initialize GraphQL Server
412
+ ### Initialize GraphQL Server (Next.js App Router)
306
413
 
307
414
  **Basic Example:**
308
415
 
@@ -357,6 +464,17 @@ export const { GET, POST } = await initGraphQLServer({
357
464
  });
358
465
  ```
359
466
 
467
+ ### Real-world pattern from a full Next.js app (like `veas-web`)
468
+
469
+ In a typical app you will:
470
+
471
+ - Define **GraphQL resolvers** using `QueryLibrary` / `FieldLibrary`
472
+ - Initialize the GraphQL **API route** with `initGraphQLServer`
473
+ - Use **server-side helper** `getGraphQLQuery` to call GraphQL from RSC / server actions
474
+ - Use **client-side helper** `getApolloWrapper` and `useAuthMutation` for client components
475
+
476
+ The next sections show how these pieces fit together.
477
+
360
478
  #### Options
361
479
 
362
480
  | Option | Type | Required | Description |
@@ -483,6 +601,139 @@ const fields = {
483
601
  const UserFieldResolver = FieldLibrary(User, fields);
484
602
  ```
485
603
 
604
+ **How this looks in a real app (`veas-web`-style):**
605
+
606
+ ```typescript
607
+ // app/api/(graphql)/User/db.ts
608
+ import { pgTable, serial, text, timestamp, real } from "drizzle-orm/pg-core";
609
+
610
+ export const UserTable = pgTable("users", {
611
+ id: serial("id").primaryKey(),
612
+ email: text("email").notNull(),
613
+ password: text("password").notNull(),
614
+ name: text("name"),
615
+ dateOfBirth: timestamp("date_of_birth"),
616
+ placeOfBirthLat: real("place_of_birth_lat"),
617
+ placeOfBirthLong: real("place_of_birth_long"),
618
+ timezone: real("timezone"),
619
+ });
620
+
621
+ export type UserDB = typeof UserTable.$inferSelect;
622
+ ```
623
+
624
+ ```typescript
625
+ // app/api/(graphql)/User/types.ts
626
+ import { Field, ObjectType } from "type-graphql";
627
+
628
+ @ObjectType("User")
629
+ export class User {
630
+ @Field()
631
+ id: number;
632
+
633
+ @Field()
634
+ email: string;
635
+
636
+ @Field(() => String, { nullable: true })
637
+ name: string | null;
638
+
639
+ @Field(() => Date, { nullable: true })
640
+ dateOfBirth: Date | null;
641
+
642
+ @Field(() => Number, { nullable: true })
643
+ placeOfBirthLat: number | null;
644
+
645
+ @Field(() => Number, { nullable: true })
646
+ placeOfBirthLong: number | null;
647
+
648
+ @Field(() => Number, { nullable: true })
649
+ timezone: number | null;
650
+
651
+ @Field()
652
+ isOnboarded: boolean;
653
+ }
654
+ ```
655
+
656
+ ```typescript
657
+ // app/api/(graphql)/User/resolvers/is-onboarded.ts
658
+ import { field } from "naystack/graphql";
659
+ import type { UserDB } from "../db";
660
+
661
+ export default field(
662
+ async (user: UserDB) => {
663
+ return (
664
+ !!user.name &&
665
+ !!user.dateOfBirth &&
666
+ user.placeOfBirthLat !== null &&
667
+ user.placeOfBirthLong !== null &&
668
+ user.timezone !== null
669
+ );
670
+ },
671
+ { output: Boolean },
672
+ );
673
+ ```
674
+
675
+ ```typescript
676
+ // app/api/(graphql)/User/resolvers/get-current-user.ts
677
+ import { query } from "naystack/graphql";
678
+ import { db } from "@/app/api/lib/db";
679
+ import { UserTable } from "../db";
680
+ import { eq } from "drizzle-orm";
681
+ import { User } from "../types";
682
+
683
+ export default query(
684
+ async (ctx: { userId: number | null }) => {
685
+ if (!ctx.userId) return null;
686
+ const [user] = await db
687
+ .select()
688
+ .from(UserTable)
689
+ .where(eq(UserTable.id, ctx.userId));
690
+ return user || null;
691
+ },
692
+ {
693
+ output: User,
694
+ },
695
+ );
696
+ ```
697
+
698
+ ```typescript
699
+ // app/api/(graphql)/User/graphql.ts
700
+ import { QueryLibrary, FieldLibrary } from "naystack/graphql";
701
+ import getCurrentUser from "./resolvers/get-current-user";
702
+ import onboardUser from "./resolvers/onboard-user";
703
+ import isOnboarded from "./resolvers/is-onboarded";
704
+ import type { UserDB } from "./db";
705
+ import { User } from "./types";
706
+
707
+ export const UserResolvers = QueryLibrary({
708
+ getCurrentUser,
709
+ onboardUser,
710
+ });
711
+
712
+ export const UserFieldResolvers = FieldLibrary<UserDB>(User, {
713
+ isOnboarded,
714
+ });
715
+ ```
716
+
717
+ ```typescript
718
+ // app/api/(graphql)/route.ts
719
+ import { initGraphQLServer } from "naystack/graphql";
720
+ import { UserResolvers, UserFieldResolvers } from "./User/graphql";
721
+ import { getUserIdFromRequest } from "@/app/api/(auth)/email";
722
+
723
+ export const { GET, POST } = await initGraphQLServer({
724
+ resolvers: [UserResolvers, UserFieldResolvers],
725
+ context: async (req) => {
726
+ const res = getUserIdFromRequest(req);
727
+ if (!res) return { userId: null };
728
+ return {
729
+ userId: res.accessUserId ?? res.refreshUserID ?? null,
730
+ };
731
+ },
732
+ });
733
+ ```
734
+
735
+ This gives you a full GraphQL API route that uses Naystack’s auth, Drizzle models, and functional resolvers.
736
+
486
737
  **Real-World Example:**
487
738
 
488
739
  ```typescript
@@ -220,7 +220,14 @@ function getEmailAuthRoutes(options) {
220
220
  POST: getPostRoute(options),
221
221
  PUT: getPutRoute(options),
222
222
  DELETE: getDeleteRoute(options),
223
- getUserIdFromRequest: (req) => getUserContext(options.refreshKey, options.signingKey, req)
223
+ getContext: (req) => {
224
+ const ids = getUserContext(options.refreshKey, options.signingKey, req);
225
+ if (!ids) return { userId: null };
226
+ if (ids.refreshUserID) {
227
+ return { userId: ids.refreshUserID, isRefreshID: true };
228
+ }
229
+ return { userId: ids.accessUserId };
230
+ }
224
231
  };
225
232
  }
226
233
  // Annotate the CommonJS export names for ESM import in node:
@@ -14,10 +14,16 @@ declare function getEmailAuthRoutes(options: InitRoutesOptions): {
14
14
  accessToken: string | undefined;
15
15
  refreshToken: string | undefined;
16
16
  }>>;
17
- getUserIdFromRequest: (req: NextRequest) => {
18
- refreshUserID?: number;
19
- accessUserId?: number;
20
- } | null;
17
+ getContext: (req: NextRequest) => {
18
+ userId: null;
19
+ isRefreshID?: undefined;
20
+ } | {
21
+ userId: number;
22
+ isRefreshID: boolean;
23
+ } | {
24
+ userId: number | undefined;
25
+ isRefreshID?: undefined;
26
+ };
21
27
  };
22
28
 
23
29
  export { getEmailAuthRoutes };
@@ -14,10 +14,16 @@ declare function getEmailAuthRoutes(options: InitRoutesOptions): {
14
14
  accessToken: string | undefined;
15
15
  refreshToken: string | undefined;
16
16
  }>>;
17
- getUserIdFromRequest: (req: NextRequest) => {
18
- refreshUserID?: number;
19
- accessUserId?: number;
20
- } | null;
17
+ getContext: (req: NextRequest) => {
18
+ userId: null;
19
+ isRefreshID?: undefined;
20
+ } | {
21
+ userId: number;
22
+ isRefreshID: boolean;
23
+ } | {
24
+ userId: number | undefined;
25
+ isRefreshID?: undefined;
26
+ };
21
27
  };
22
28
 
23
29
  export { getEmailAuthRoutes };
@@ -194,7 +194,14 @@ function getEmailAuthRoutes(options) {
194
194
  POST: getPostRoute(options),
195
195
  PUT: getPutRoute(options),
196
196
  DELETE: getDeleteRoute(options),
197
- getUserIdFromRequest: (req) => getUserContext(options.refreshKey, options.signingKey, req)
197
+ getContext: (req) => {
198
+ const ids = getUserContext(options.refreshKey, options.signingKey, req);
199
+ if (!ids) return { userId: null };
200
+ if (ids.refreshUserID) {
201
+ return { userId: ids.refreshUserID, isRefreshID: true };
202
+ }
203
+ return { userId: ids.accessUserId };
204
+ }
198
205
  };
199
206
  }
200
207
  export {
@@ -234,7 +234,14 @@ function getEmailAuthRoutes(options) {
234
234
  POST: getPostRoute(options),
235
235
  PUT: getPutRoute(options),
236
236
  DELETE: getDeleteRoute(options),
237
- getUserIdFromRequest: (req) => getUserContext(options.refreshKey, options.signingKey, req)
237
+ getContext: (req) => {
238
+ const ids = getUserContext(options.refreshKey, options.signingKey, req);
239
+ if (!ids) return { userId: null };
240
+ if (ids.refreshUserID) {
241
+ return { userId: ids.refreshUserID, isRefreshID: true };
242
+ }
243
+ return { userId: ids.accessUserId };
244
+ }
238
245
  };
239
246
  }
240
247
 
@@ -206,7 +206,14 @@ function getEmailAuthRoutes(options) {
206
206
  POST: getPostRoute(options),
207
207
  PUT: getPutRoute(options),
208
208
  DELETE: getDeleteRoute(options),
209
- getUserIdFromRequest: (req) => getUserContext(options.refreshKey, options.signingKey, req)
209
+ getContext: (req) => {
210
+ const ids = getUserContext(options.refreshKey, options.signingKey, req);
211
+ if (!ids) return { userId: null };
212
+ if (ids.refreshUserID) {
213
+ return { userId: ids.refreshUserID, isRefreshID: true };
214
+ }
215
+ return { userId: ids.accessUserId };
216
+ }
210
217
  };
211
218
  }
212
219
 
@@ -579,11 +579,11 @@ async function initGraphQLServer({
579
579
  authChecker,
580
580
  resolvers,
581
581
  plugins,
582
- context
582
+ getContext
583
583
  }) {
584
584
  const { typeDefs, resolvers: builtResolvers } = await (0, import_type_graphql.buildTypeDefsAndResolvers)({
585
585
  validate: true,
586
- authChecker,
586
+ authChecker: authChecker || (({ context }) => !!context.userId),
587
587
  resolvers
588
588
  });
589
589
  const server = new import_server.ApolloServer({
@@ -593,10 +593,7 @@ async function initGraphQLServer({
593
593
  process.env.NODE_ENV === "production" ? (0, import_default.ApolloServerPluginLandingPageProductionDefault)() : (0, import_default.ApolloServerPluginLandingPageLocalDefault)(),
594
594
  {
595
595
  async requestDidStart({ request, contextValue }) {
596
- if (
597
- // eslint-disable-next-line
598
- contextValue.onlyQuery && !request.query?.startsWith("query")
599
- )
596
+ if (contextValue.isRefreshID && !request.query?.startsWith("query"))
600
597
  contextValue.userId = null;
601
598
  }
602
599
  },
@@ -606,12 +603,11 @@ async function initGraphQLServer({
606
603
  status400ForVariableCoercionErrors: true
607
604
  });
608
605
  const handler = (0, import_next.startServerAndCreateNextHandler)(server, {
609
- context
606
+ context: getContext
610
607
  });
611
608
  return {
612
609
  GET: (request) => handler(request),
613
- POST: (request) => handler(request),
614
- context
610
+ POST: (request) => handler(request)
615
611
  };
616
612
  }
617
613
 
@@ -655,6 +651,9 @@ function QueryLibrary(queries) {
655
651
  descriptor
656
652
  );
657
653
  }
654
+ if (def.authorized) {
655
+ (0, import_type_graphql2.Authorized)()(GeneratedResolver, key);
656
+ }
658
657
  (0, import_type_graphql2.Ctx)()(GeneratedResolver.prototype, key, 0);
659
658
  if (def.input) {
660
659
  (0, import_type_graphql2.Arg)("input", () => def.input || String, def.inputOptions)(
@@ -566,11 +566,11 @@ async function initGraphQLServer({
566
566
  authChecker,
567
567
  resolvers,
568
568
  plugins,
569
- context
569
+ getContext
570
570
  }) {
571
571
  const { typeDefs, resolvers: builtResolvers } = await buildTypeDefsAndResolvers({
572
572
  validate: true,
573
- authChecker,
573
+ authChecker: authChecker || (({ context }) => !!context.userId),
574
574
  resolvers
575
575
  });
576
576
  const server = new ApolloServer({
@@ -580,10 +580,7 @@ async function initGraphQLServer({
580
580
  process.env.NODE_ENV === "production" ? ApolloServerPluginLandingPageProductionDefault() : ApolloServerPluginLandingPageLocalDefault(),
581
581
  {
582
582
  async requestDidStart({ request, contextValue }) {
583
- if (
584
- // eslint-disable-next-line
585
- contextValue.onlyQuery && !request.query?.startsWith("query")
586
- )
583
+ if (contextValue.isRefreshID && !request.query?.startsWith("query"))
587
584
  contextValue.userId = null;
588
585
  }
589
586
  },
@@ -593,12 +590,11 @@ async function initGraphQLServer({
593
590
  status400ForVariableCoercionErrors: true
594
591
  });
595
592
  const handler = startServerAndCreateNextHandler(server, {
596
- context
593
+ context: getContext
597
594
  });
598
595
  return {
599
596
  GET: (request) => handler(request),
600
- POST: (request) => handler(request),
601
- context
597
+ POST: (request) => handler(request)
602
598
  };
603
599
  }
604
600
 
@@ -651,6 +647,9 @@ function QueryLibrary(queries) {
651
647
  descriptor
652
648
  );
653
649
  }
650
+ if (def.authorized) {
651
+ Authorized()(GeneratedResolver, key);
652
+ }
654
653
  Ctx()(GeneratedResolver.prototype, key, 0);
655
654
  if (def.input) {
656
655
  Arg("input", () => def.input || String, def.inputOptions)(
@@ -32,11 +32,11 @@ async function initGraphQLServer({
32
32
  authChecker,
33
33
  resolvers,
34
34
  plugins,
35
- context
35
+ getContext
36
36
  }) {
37
37
  const { typeDefs, resolvers: builtResolvers } = await (0, import_type_graphql.buildTypeDefsAndResolvers)({
38
38
  validate: true,
39
- authChecker,
39
+ authChecker: authChecker || (({ context }) => !!context.userId),
40
40
  resolvers
41
41
  });
42
42
  const server = new import_server.ApolloServer({
@@ -46,10 +46,7 @@ async function initGraphQLServer({
46
46
  process.env.NODE_ENV === "production" ? (0, import_default.ApolloServerPluginLandingPageProductionDefault)() : (0, import_default.ApolloServerPluginLandingPageLocalDefault)(),
47
47
  {
48
48
  async requestDidStart({ request, contextValue }) {
49
- if (
50
- // eslint-disable-next-line
51
- contextValue.onlyQuery && !request.query?.startsWith("query")
52
- )
49
+ if (contextValue.isRefreshID && !request.query?.startsWith("query"))
53
50
  contextValue.userId = null;
54
51
  }
55
52
  },
@@ -59,12 +56,11 @@ async function initGraphQLServer({
59
56
  status400ForVariableCoercionErrors: true
60
57
  });
61
58
  const handler = (0, import_next.startServerAndCreateNextHandler)(server, {
62
- context
59
+ context: getContext
63
60
  });
64
61
  return {
65
62
  GET: (request) => handler(request),
66
- POST: (request) => handler(request),
67
- context
63
+ POST: (request) => handler(request)
68
64
  };
69
65
  }
70
66
  // Annotate the CommonJS export names for ESM import in node:
@@ -2,15 +2,14 @@ import { ApolloServerPlugin } from '@apollo/server';
2
2
  import { NextRequest } from 'next/server';
3
3
  import { AuthChecker, NonEmptyArray } from 'type-graphql';
4
4
 
5
- declare function initGraphQLServer({ authChecker, resolvers, plugins, context, }: {
5
+ declare function initGraphQLServer({ authChecker, resolvers, plugins, getContext, }: {
6
6
  authChecker?: AuthChecker<any>;
7
7
  resolvers: NonEmptyArray<Function>;
8
8
  plugins?: ApolloServerPlugin[];
9
- context?: (req: NextRequest) => Promise<any>;
9
+ getContext?: (req: NextRequest) => Promise<any>;
10
10
  }): Promise<{
11
11
  GET: (request: NextRequest) => Promise<Response>;
12
12
  POST: (request: NextRequest) => Promise<Response>;
13
- context: ((req: NextRequest) => Promise<any>) | undefined;
14
13
  }>;
15
14
 
16
15
  export { initGraphQLServer };
@@ -2,15 +2,14 @@ import { ApolloServerPlugin } from '@apollo/server';
2
2
  import { NextRequest } from 'next/server';
3
3
  import { AuthChecker, NonEmptyArray } from 'type-graphql';
4
4
 
5
- declare function initGraphQLServer({ authChecker, resolvers, plugins, context, }: {
5
+ declare function initGraphQLServer({ authChecker, resolvers, plugins, getContext, }: {
6
6
  authChecker?: AuthChecker<any>;
7
7
  resolvers: NonEmptyArray<Function>;
8
8
  plugins?: ApolloServerPlugin[];
9
- context?: (req: NextRequest) => Promise<any>;
9
+ getContext?: (req: NextRequest) => Promise<any>;
10
10
  }): Promise<{
11
11
  GET: (request: NextRequest) => Promise<Response>;
12
12
  POST: (request: NextRequest) => Promise<Response>;
13
- context: ((req: NextRequest) => Promise<any>) | undefined;
14
13
  }>;
15
14
 
16
15
  export { initGraphQLServer };
@@ -13,11 +13,11 @@ async function initGraphQLServer({
13
13
  authChecker,
14
14
  resolvers,
15
15
  plugins,
16
- context
16
+ getContext
17
17
  }) {
18
18
  const { typeDefs, resolvers: builtResolvers } = await buildTypeDefsAndResolvers({
19
19
  validate: true,
20
- authChecker,
20
+ authChecker: authChecker || (({ context }) => !!context.userId),
21
21
  resolvers
22
22
  });
23
23
  const server = new ApolloServer({
@@ -27,10 +27,7 @@ async function initGraphQLServer({
27
27
  process.env.NODE_ENV === "production" ? ApolloServerPluginLandingPageProductionDefault() : ApolloServerPluginLandingPageLocalDefault(),
28
28
  {
29
29
  async requestDidStart({ request, contextValue }) {
30
- if (
31
- // eslint-disable-next-line
32
- contextValue.onlyQuery && !request.query?.startsWith("query")
33
- )
30
+ if (contextValue.isRefreshID && !request.query?.startsWith("query"))
34
31
  contextValue.userId = null;
35
32
  }
36
33
  },
@@ -40,12 +37,11 @@ async function initGraphQLServer({
40
37
  status400ForVariableCoercionErrors: true
41
38
  });
42
39
  const handler = startServerAndCreateNextHandler(server, {
43
- context
40
+ context: getContext
44
41
  });
45
42
  return {
46
43
  GET: (request) => handler(request),
47
- POST: (request) => handler(request),
48
- context
44
+ POST: (request) => handler(request)
49
45
  };
50
46
  }
51
47
  export {
@@ -21,10 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var server_exports = {};
22
22
  __export(server_exports, {
23
23
  Injector: () => Injector,
24
- PreloadQuery: () => PreloadQuery,
25
- getClient: () => getClient,
26
- getGraphQLQuery: () => getGraphQLQuery,
27
- query: () => query
24
+ getGraphQLQuery: () => getGraphQLQuery
28
25
  });
29
26
  module.exports = __toCommonJS(server_exports);
30
27
  var import_client = require("@apollo/client");
@@ -46,22 +43,8 @@ async function InjectorSuspensed({
46
43
  const data = await fetch();
47
44
  return /* @__PURE__ */ React.createElement(Component, { loading: false, ...props || {}, data });
48
45
  }
49
- var { getClient, query, PreloadQuery } = (0, import_client_integration_nextjs.registerApolloClient)(() => {
50
- return new import_client.ApolloClient({
51
- cache: new import_client.InMemoryCache(),
52
- link: new import_client.HttpLink({
53
- // this needs to be an absolute url, as relative urls cannot be used in SSR
54
- uri: "http://example.com/api/graphql",
55
- fetchOptions: {
56
- // you can pass additional options that should be passed to `fetch` here,
57
- // e.g. Next.js-related `fetch` options regarding caching and revalidation
58
- // see https://nextjs.org/docs/app/api-reference/functions/fetch#fetchurl-options
59
- }
60
- })
61
- });
62
- });
63
46
  var getGraphQLQuery = ({ uri }) => {
64
- const { query: query2 } = (0, import_client_integration_nextjs.registerApolloClient)(() => {
47
+ const { query } = (0, import_client_integration_nextjs.registerApolloClient)(() => {
65
48
  return new import_client.ApolloClient({
66
49
  cache: new import_client.InMemoryCache(),
67
50
  link: new import_client.HttpLink({
@@ -70,7 +53,7 @@ var getGraphQLQuery = ({ uri }) => {
70
53
  });
71
54
  });
72
55
  return async (_query, options) => {
73
- const res = await query2({
56
+ const res = await query({
74
57
  query: _query,
75
58
  variables: options?.variables,
76
59
  context: {
@@ -92,8 +75,5 @@ var getGraphQLQuery = ({ uri }) => {
92
75
  // Annotate the CommonJS export names for ESM import in node:
93
76
  0 && (module.exports = {
94
77
  Injector,
95
- PreloadQuery,
96
- getClient,
97
- getGraphQLQuery,
98
- query
78
+ getGraphQLQuery
99
79
  });
@@ -1,8 +1,6 @@
1
- import * as _apollo_client_integration_nextjs from '@apollo/client-integration-nextjs';
2
- import * as _apollo_client from '@apollo/client';
3
- import { ApolloClient, OperationVariables } from '@apollo/client';
4
1
  import * as React from 'react';
5
2
  import { FC } from 'react';
3
+ import { OperationVariables } from '@apollo/client';
6
4
  import { TypedDocumentNode } from '@graphql-typed-document-node/core';
7
5
 
8
6
  type OmittedProps<Y> = Omit<Omit<Y, "loading">, "data">;
@@ -18,9 +16,6 @@ declare function Injector<T, Y>({ fetch, Component, props, }: {
18
16
  loading: boolean;
19
17
  } & Y>;
20
18
  } & ComponentProps<Y>): React.JSX.Element;
21
- declare const getClient: () => ApolloClient<_apollo_client.NormalizedCacheObject>;
22
- declare const query: <T = any, TVariables extends OperationVariables = OperationVariables>(options: _apollo_client.QueryOptions<TVariables, T>) => Promise<_apollo_client.ApolloQueryResult<_apollo_client.MaybeMasked<T>>>;
23
- declare const PreloadQuery: _apollo_client_integration_nextjs.PreloadQueryComponent;
24
19
  declare const getGraphQLQuery: ({ uri }: {
25
20
  uri: string;
26
21
  }) => <T, V extends OperationVariables>(_query: TypedDocumentNode<T, V>, options?: {
@@ -30,4 +25,4 @@ declare const getGraphQLQuery: ({ uri }: {
30
25
  noCookie?: boolean;
31
26
  }) => Promise<T>;
32
27
 
33
- export { Injector, PreloadQuery, getClient, getGraphQLQuery, query };
28
+ export { Injector, getGraphQLQuery };
@@ -1,8 +1,6 @@
1
- import * as _apollo_client_integration_nextjs from '@apollo/client-integration-nextjs';
2
- import * as _apollo_client from '@apollo/client';
3
- import { ApolloClient, OperationVariables } from '@apollo/client';
4
1
  import * as React from 'react';
5
2
  import { FC } from 'react';
3
+ import { OperationVariables } from '@apollo/client';
6
4
  import { TypedDocumentNode } from '@graphql-typed-document-node/core';
7
5
 
8
6
  type OmittedProps<Y> = Omit<Omit<Y, "loading">, "data">;
@@ -18,9 +16,6 @@ declare function Injector<T, Y>({ fetch, Component, props, }: {
18
16
  loading: boolean;
19
17
  } & Y>;
20
18
  } & ComponentProps<Y>): React.JSX.Element;
21
- declare const getClient: () => ApolloClient<_apollo_client.NormalizedCacheObject>;
22
- declare const query: <T = any, TVariables extends OperationVariables = OperationVariables>(options: _apollo_client.QueryOptions<TVariables, T>) => Promise<_apollo_client.ApolloQueryResult<_apollo_client.MaybeMasked<T>>>;
23
- declare const PreloadQuery: _apollo_client_integration_nextjs.PreloadQueryComponent;
24
19
  declare const getGraphQLQuery: ({ uri }: {
25
20
  uri: string;
26
21
  }) => <T, V extends OperationVariables>(_query: TypedDocumentNode<T, V>, options?: {
@@ -30,4 +25,4 @@ declare const getGraphQLQuery: ({ uri }: {
30
25
  noCookie?: boolean;
31
26
  }) => Promise<T>;
32
27
 
33
- export { Injector, PreloadQuery, getClient, getGraphQLQuery, query };
28
+ export { Injector, getGraphQLQuery };
@@ -22,22 +22,8 @@ async function InjectorSuspensed({
22
22
  const data = await fetch();
23
23
  return /* @__PURE__ */ React.createElement(Component, { loading: false, ...props || {}, data });
24
24
  }
25
- var { getClient, query, PreloadQuery } = registerApolloClient(() => {
26
- return new ApolloClient({
27
- cache: new InMemoryCache(),
28
- link: new HttpLink({
29
- // this needs to be an absolute url, as relative urls cannot be used in SSR
30
- uri: "http://example.com/api/graphql",
31
- fetchOptions: {
32
- // you can pass additional options that should be passed to `fetch` here,
33
- // e.g. Next.js-related `fetch` options regarding caching and revalidation
34
- // see https://nextjs.org/docs/app/api-reference/functions/fetch#fetchurl-options
35
- }
36
- })
37
- });
38
- });
39
25
  var getGraphQLQuery = ({ uri }) => {
40
- const { query: query2 } = registerApolloClient(() => {
26
+ const { query } = registerApolloClient(() => {
41
27
  return new ApolloClient({
42
28
  cache: new InMemoryCache(),
43
29
  link: new HttpLink({
@@ -46,7 +32,7 @@ var getGraphQLQuery = ({ uri }) => {
46
32
  });
47
33
  });
48
34
  return async (_query, options) => {
49
- const res = await query2({
35
+ const res = await query({
50
36
  query: _query,
51
37
  variables: options?.variables,
52
38
  context: {
@@ -67,8 +53,5 @@ var getGraphQLQuery = ({ uri }) => {
67
53
  };
68
54
  export {
69
55
  Injector,
70
- PreloadQuery,
71
- getClient,
72
- getGraphQLQuery,
73
- query
56
+ getGraphQLQuery
74
57
  };
@@ -73,6 +73,9 @@ function QueryLibrary(queries) {
73
73
  descriptor
74
74
  );
75
75
  }
76
+ if (def.authorized) {
77
+ (0, import_type_graphql.Authorized)()(GeneratedResolver, key);
78
+ }
76
79
  (0, import_type_graphql.Ctx)()(GeneratedResolver.prototype, key, 0);
77
80
  if (def.input) {
78
81
  (0, import_type_graphql.Arg)("input", () => def.input || String, def.inputOptions)(
@@ -1,6 +1,6 @@
1
1
  import { GraphQLScalarType } from 'graphql';
2
2
  import { ClassType, Query, Arg } from 'type-graphql';
3
- import { Context } from './types.mjs';
3
+ import { AuthorizedContext, Context } from './types.mjs';
4
4
 
5
5
  type ReturnOptions = Parameters<typeof Query>[1];
6
6
  type ArgsOptions = Parameters<typeof Arg>[2];
@@ -9,26 +9,26 @@ type DeepPartial<T> = {
9
9
  [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
10
10
  };
11
11
  type OtherTypes<T> = GraphQLScalarType<T, T> | [GraphQLScalarType<T, T>] | NumberConstructor | [NumberConstructor] | StringConstructor | [StringConstructor] | BooleanConstructor | [BooleanConstructor];
12
- interface BaseDefinition<T extends Values, U extends Values> {
12
+ interface BaseDefinition<T extends Values, U extends Values, IsAuth extends boolean> {
13
13
  output: T extends object ? ClassType<DeepPartial<T>> | [ClassType<DeepPartial<T>>] : OtherTypes<T>;
14
14
  outputOptions?: ReturnOptions;
15
15
  input?: U extends object ? ClassType<U> | [ClassType<U>] : OtherTypes<U>;
16
16
  inputOptions?: ArgsOptions;
17
- authorized?: boolean;
17
+ authorized?: IsAuth;
18
18
  }
19
- interface QueryDefinition<T extends Values, U extends Values> extends BaseDefinition<T, U> {
20
- fn: (ctx: Context, data: U) => Promise<T | T[]> | T | T[];
19
+ interface QueryDefinition<T extends Values, U extends Values, IsAuth extends boolean> extends BaseDefinition<T, U, IsAuth> {
20
+ fn: (ctx: IsAuth extends true ? AuthorizedContext : Context, data: U) => Promise<T | T[]> | T | T[];
21
21
  mutation?: boolean;
22
22
  }
23
- interface FieldResolverDefinition<T extends Values, U extends Values, Root> extends BaseDefinition<T, U> {
24
- fn: (root: Root, ctx: Context, data: U) => Promise<T | T[]> | T | T[];
23
+ interface FieldResolverDefinition<T extends Values, U extends Values, IsAuth extends boolean, Root> extends BaseDefinition<T, U, IsAuth> {
24
+ fn: (root: Root, ctx: IsAuth extends true ? AuthorizedContext : Context, data: U) => Promise<T | T[]> | T | T[];
25
25
  }
26
- declare function query<T extends Values, U extends Values>(fn: QueryDefinition<T, U>["fn"], options: Omit<QueryDefinition<T, U>, "fn">): QueryDefinition<T, U>;
27
- declare function field<T extends Values, U extends Values, Root>(fn: FieldResolverDefinition<T, U, Root>["fn"], options: Omit<FieldResolverDefinition<T, U, Root>, "fn">): FieldResolverDefinition<T, U, Root>;
28
- declare function QueryLibrary<T extends Record<string, QueryDefinition<any, any>>>(queries: T): {
26
+ declare function query<T extends Values, U extends Values, IsAuth extends boolean>(fn: QueryDefinition<T, U, IsAuth>["fn"], options: Omit<QueryDefinition<T, U, IsAuth>, "fn">): QueryDefinition<T, U, IsAuth>;
27
+ declare function field<T extends Values, U extends Values, IsAuth extends boolean, Root>(fn: FieldResolverDefinition<T, U, IsAuth, Root>["fn"], options: Omit<FieldResolverDefinition<T, U, IsAuth, Root>, "fn">): FieldResolverDefinition<T, U, IsAuth, Root>;
28
+ declare function QueryLibrary<T extends Record<string, QueryDefinition<any, any, any>>>(queries: T): {
29
29
  new (): {};
30
30
  };
31
- declare function FieldLibrary<X extends object, T extends Record<string, FieldResolverDefinition<any, any, X>> = Record<string, FieldResolverDefinition<any, any, X>>>(type: ClassType, queries: T): {
31
+ declare function FieldLibrary<X extends object, T extends Record<string, FieldResolverDefinition<any, any, any, X>> = Record<string, FieldResolverDefinition<any, any, any, X>>>(type: ClassType, queries: T): {
32
32
  new (): {};
33
33
  };
34
34
 
@@ -1,6 +1,6 @@
1
1
  import { GraphQLScalarType } from 'graphql';
2
2
  import { ClassType, Query, Arg } from 'type-graphql';
3
- import { Context } from './types.js';
3
+ import { AuthorizedContext, Context } from './types.js';
4
4
 
5
5
  type ReturnOptions = Parameters<typeof Query>[1];
6
6
  type ArgsOptions = Parameters<typeof Arg>[2];
@@ -9,26 +9,26 @@ type DeepPartial<T> = {
9
9
  [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
10
10
  };
11
11
  type OtherTypes<T> = GraphQLScalarType<T, T> | [GraphQLScalarType<T, T>] | NumberConstructor | [NumberConstructor] | StringConstructor | [StringConstructor] | BooleanConstructor | [BooleanConstructor];
12
- interface BaseDefinition<T extends Values, U extends Values> {
12
+ interface BaseDefinition<T extends Values, U extends Values, IsAuth extends boolean> {
13
13
  output: T extends object ? ClassType<DeepPartial<T>> | [ClassType<DeepPartial<T>>] : OtherTypes<T>;
14
14
  outputOptions?: ReturnOptions;
15
15
  input?: U extends object ? ClassType<U> | [ClassType<U>] : OtherTypes<U>;
16
16
  inputOptions?: ArgsOptions;
17
- authorized?: boolean;
17
+ authorized?: IsAuth;
18
18
  }
19
- interface QueryDefinition<T extends Values, U extends Values> extends BaseDefinition<T, U> {
20
- fn: (ctx: Context, data: U) => Promise<T | T[]> | T | T[];
19
+ interface QueryDefinition<T extends Values, U extends Values, IsAuth extends boolean> extends BaseDefinition<T, U, IsAuth> {
20
+ fn: (ctx: IsAuth extends true ? AuthorizedContext : Context, data: U) => Promise<T | T[]> | T | T[];
21
21
  mutation?: boolean;
22
22
  }
23
- interface FieldResolverDefinition<T extends Values, U extends Values, Root> extends BaseDefinition<T, U> {
24
- fn: (root: Root, ctx: Context, data: U) => Promise<T | T[]> | T | T[];
23
+ interface FieldResolverDefinition<T extends Values, U extends Values, IsAuth extends boolean, Root> extends BaseDefinition<T, U, IsAuth> {
24
+ fn: (root: Root, ctx: IsAuth extends true ? AuthorizedContext : Context, data: U) => Promise<T | T[]> | T | T[];
25
25
  }
26
- declare function query<T extends Values, U extends Values>(fn: QueryDefinition<T, U>["fn"], options: Omit<QueryDefinition<T, U>, "fn">): QueryDefinition<T, U>;
27
- declare function field<T extends Values, U extends Values, Root>(fn: FieldResolverDefinition<T, U, Root>["fn"], options: Omit<FieldResolverDefinition<T, U, Root>, "fn">): FieldResolverDefinition<T, U, Root>;
28
- declare function QueryLibrary<T extends Record<string, QueryDefinition<any, any>>>(queries: T): {
26
+ declare function query<T extends Values, U extends Values, IsAuth extends boolean>(fn: QueryDefinition<T, U, IsAuth>["fn"], options: Omit<QueryDefinition<T, U, IsAuth>, "fn">): QueryDefinition<T, U, IsAuth>;
27
+ declare function field<T extends Values, U extends Values, IsAuth extends boolean, Root>(fn: FieldResolverDefinition<T, U, IsAuth, Root>["fn"], options: Omit<FieldResolverDefinition<T, U, IsAuth, Root>, "fn">): FieldResolverDefinition<T, U, IsAuth, Root>;
28
+ declare function QueryLibrary<T extends Record<string, QueryDefinition<any, any, any>>>(queries: T): {
29
29
  new (): {};
30
30
  };
31
- declare function FieldLibrary<X extends object, T extends Record<string, FieldResolverDefinition<any, any, X>> = Record<string, FieldResolverDefinition<any, any, X>>>(type: ClassType, queries: T): {
31
+ declare function FieldLibrary<X extends object, T extends Record<string, FieldResolverDefinition<any, any, any, X>> = Record<string, FieldResolverDefinition<any, any, any, X>>>(type: ClassType, queries: T): {
32
32
  new (): {};
33
33
  };
34
34
 
@@ -58,6 +58,9 @@ function QueryLibrary(queries) {
58
58
  descriptor
59
59
  );
60
60
  }
61
+ if (def.authorized) {
62
+ Authorized()(GeneratedResolver, key);
63
+ }
61
64
  Ctx()(GeneratedResolver.prototype, key, 0);
62
65
  if (def.input) {
63
66
  Arg("input", () => def.input || String, def.inputOptions)(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "naystack",
3
- "version": "1.2.14",
3
+ "version": "1.2.16",
4
4
  "description": "A stack built with Next + GraphQL + S3 + Auth",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.esm.js",