naystack 1.2.14 → 1.2.15

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
@@ -655,6 +655,9 @@ function QueryLibrary(queries) {
655
655
  descriptor
656
656
  );
657
657
  }
658
+ if (def.authorized) {
659
+ (0, import_type_graphql2.Authorized)()(GeneratedResolver, key);
660
+ }
658
661
  (0, import_type_graphql2.Ctx)()(GeneratedResolver.prototype, key, 0);
659
662
  if (def.input) {
660
663
  (0, import_type_graphql2.Arg)("input", () => def.input || String, def.inputOptions)(
@@ -651,6 +651,9 @@ function QueryLibrary(queries) {
651
651
  descriptor
652
652
  );
653
653
  }
654
+ if (def.authorized) {
655
+ Authorized()(GeneratedResolver, key);
656
+ }
654
657
  Ctx()(GeneratedResolver.prototype, key, 0);
655
658
  if (def.input) {
656
659
  Arg("input", () => def.input || String, def.inputOptions)(
@@ -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.15",
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",