naystack 1.5.9 → 1.5.10
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 +646 -91
- package/dist/auth/constants.d.mts +4 -0
- package/dist/auth/constants.d.ts +4 -0
- package/dist/auth/email/client.d.mts +149 -0
- package/dist/auth/email/client.d.ts +149 -0
- package/dist/auth/email/index.cjs.js +2 -20
- package/dist/auth/email/index.d.mts +41 -1
- package/dist/auth/email/index.d.ts +41 -1
- package/dist/auth/email/index.esm.js +1 -17
- package/dist/auth/email/routes/delete.cjs.js +0 -1
- package/dist/auth/email/routes/delete.d.mts +5 -0
- package/dist/auth/email/routes/delete.d.ts +5 -0
- package/dist/auth/email/routes/delete.esm.js +0 -1
- package/dist/auth/email/routes/get.d.mts +5 -0
- package/dist/auth/email/routes/get.d.ts +5 -0
- package/dist/auth/email/routes/post.cjs.js +0 -1
- package/dist/auth/email/routes/post.d.mts +5 -0
- package/dist/auth/email/routes/post.d.ts +5 -0
- package/dist/auth/email/routes/post.esm.js +0 -1
- package/dist/auth/email/routes/put.cjs.js +0 -1
- package/dist/auth/email/routes/put.d.mts +5 -0
- package/dist/auth/email/routes/put.d.ts +5 -0
- package/dist/auth/email/routes/put.esm.js +0 -1
- package/dist/auth/email/token.d.mts +62 -0
- package/dist/auth/email/token.d.ts +62 -0
- package/dist/auth/email/types.d.mts +22 -0
- package/dist/auth/email/types.d.ts +22 -0
- package/dist/auth/email/utils.cjs.js +0 -18
- package/dist/auth/email/utils.d.mts +41 -3
- package/dist/auth/email/utils.d.ts +41 -3
- package/dist/auth/email/utils.esm.js +0 -16
- package/dist/auth/google/get.d.mts +5 -0
- package/dist/auth/google/get.d.ts +5 -0
- package/dist/auth/google/index.d.mts +39 -0
- package/dist/auth/google/index.d.ts +39 -0
- package/dist/auth/index.cjs.js +4 -22
- package/dist/auth/index.d.mts +1 -1
- package/dist/auth/index.d.ts +1 -1
- package/dist/auth/index.esm.js +3 -19
- package/dist/auth/instagram/client.d.mts +19 -0
- package/dist/auth/instagram/client.d.ts +19 -0
- package/dist/auth/instagram/index.d.mts +37 -0
- package/dist/auth/instagram/index.d.ts +37 -0
- package/dist/auth/instagram/route.d.mts +5 -0
- package/dist/auth/instagram/route.d.ts +5 -0
- package/dist/auth/instagram/utils.d.mts +13 -0
- package/dist/auth/instagram/utils.d.ts +13 -0
- package/dist/auth/types.d.mts +24 -0
- package/dist/auth/types.d.ts +24 -0
- package/dist/auth/utils/errors.d.mts +10 -0
- package/dist/auth/utils/errors.d.ts +10 -0
- package/dist/auth/utils/token.d.mts +20 -0
- package/dist/auth/utils/token.d.ts +20 -0
- package/dist/client/hooks.d.mts +59 -0
- package/dist/client/hooks.d.ts +59 -0
- package/dist/client/seo.d.mts +46 -0
- package/dist/client/seo.d.ts +46 -0
- package/dist/env.d.mts +61 -0
- package/dist/env.d.ts +61 -0
- package/dist/file/client.d.mts +53 -1
- package/dist/file/client.d.ts +53 -1
- package/dist/file/index.cjs.js +0 -1
- package/dist/file/index.esm.js +0 -1
- package/dist/file/put.cjs.js +0 -1
- package/dist/file/put.d.mts +11 -0
- package/dist/file/put.d.ts +11 -0
- package/dist/file/put.esm.js +0 -1
- package/dist/file/setup.cjs.js +0 -1
- package/dist/file/setup.d.mts +48 -0
- package/dist/file/setup.d.ts +48 -0
- package/dist/file/setup.esm.js +0 -1
- package/dist/file/utils.d.mts +41 -0
- package/dist/file/utils.d.ts +41 -0
- package/dist/graphql/client.d.mts +113 -0
- package/dist/graphql/client.d.ts +113 -0
- package/dist/graphql/errors.d.mts +26 -0
- package/dist/graphql/errors.d.ts +26 -0
- package/dist/graphql/index.cjs.js +2 -3
- package/dist/graphql/index.esm.js +2 -3
- package/dist/graphql/init.cjs.js +0 -1
- package/dist/graphql/init.d.mts +33 -0
- package/dist/graphql/init.d.ts +33 -0
- package/dist/graphql/init.esm.js +0 -1
- package/dist/graphql/server.d.mts +88 -0
- package/dist/graphql/server.d.ts +88 -0
- package/dist/graphql/types.d.mts +21 -0
- package/dist/graphql/types.d.ts +21 -0
- package/dist/graphql/utils.d.mts +217 -0
- package/dist/graphql/utils.d.ts +217 -0
- package/dist/index.d.mts +16 -0
- package/dist/index.d.ts +16 -0
- package/dist/socials/instagram/getters.d.mts +115 -0
- package/dist/socials/instagram/getters.d.ts +115 -0
- package/dist/socials/instagram/setters.d.mts +18 -0
- package/dist/socials/instagram/setters.d.ts +18 -0
- package/dist/socials/instagram/types.d.mts +46 -0
- package/dist/socials/instagram/types.d.ts +46 -0
- package/dist/socials/instagram/utils.d.mts +19 -0
- package/dist/socials/instagram/utils.d.ts +19 -0
- package/dist/socials/instagram/webhook.d.mts +31 -0
- package/dist/socials/instagram/webhook.d.ts +31 -0
- package/dist/socials/meta-webhook.d.mts +11 -0
- package/dist/socials/meta-webhook.d.ts +11 -0
- package/dist/socials/threads/getters.d.mts +57 -0
- package/dist/socials/threads/getters.d.ts +57 -0
- package/dist/socials/threads/setters.d.mts +59 -0
- package/dist/socials/threads/setters.d.ts +59 -0
- package/dist/socials/threads/types.d.mts +9 -0
- package/dist/socials/threads/types.d.ts +9 -0
- package/dist/socials/threads/utils.d.mts +19 -0
- package/dist/socials/threads/utils.d.ts +19 -0
- package/dist/socials/threads/webhook.d.mts +30 -0
- package/dist/socials/threads/webhook.d.ts +30 -0
- package/package.json +4 -2
package/dist/graphql/server.d.ts
CHANGED
|
@@ -2,12 +2,67 @@ import { OperationVariables } from '@apollo/client';
|
|
|
2
2
|
import { TypedDocumentNode } from '@graphql-typed-document-node/core';
|
|
3
3
|
import React__default, { FC } from 'react';
|
|
4
4
|
|
|
5
|
+
/** Component props type minus loading and data (inferred from Injector Component). */
|
|
5
6
|
type OmittedProps<Y> = Omit<Omit<Y, "loading">, "data">;
|
|
7
|
+
/** Props for Injector: either optional or required based on remaining Component props. */
|
|
6
8
|
type ComponentProps<Y> = OmittedProps<Y> extends Record<string, never> ? {
|
|
7
9
|
props?: object;
|
|
8
10
|
} : {
|
|
9
11
|
props: OmittedProps<Y>;
|
|
10
12
|
};
|
|
13
|
+
/**
|
|
14
|
+
* Server component that wraps a client component with server-fetched data using Suspense.
|
|
15
|
+
*
|
|
16
|
+
* While the `fetch` function is resolving, the `Component` is rendered with `loading={true}` (and no `data`).
|
|
17
|
+
* Once the fetch resolves, the `Component` re-renders with `loading={false}` and `data` set to the result.
|
|
18
|
+
*
|
|
19
|
+
* This is the primary way to inject server-side data into client components in naystack.
|
|
20
|
+
* Use `.authCall()` or `.call()` from your query definitions inside the `fetch` function.
|
|
21
|
+
*
|
|
22
|
+
* @param injectorProps - Configuration object.
|
|
23
|
+
* @param injectorProps.fetch - Async function that returns the data to pass to the component. Runs on the server.
|
|
24
|
+
* @param injectorProps.Component - React component that receives `{ data?: T; loading: boolean }` plus any extra props.
|
|
25
|
+
* @param injectorProps.props - Optional. Any additional props to pass to `Component`. Required if the Component has props other than `data` and `loading`.
|
|
26
|
+
* @returns A React element that suspends until `fetch()` completes, then renders `Component` with the data.
|
|
27
|
+
*
|
|
28
|
+
* @example Simple usage:
|
|
29
|
+
* ```tsx
|
|
30
|
+
* import { Injector } from "naystack/graphql/server";
|
|
31
|
+
* import getCurrentUser from "@/app/api/(graphql)/User/resolvers/get-current-user";
|
|
32
|
+
* import AuthChecker from "./components/auth-checker";
|
|
33
|
+
*
|
|
34
|
+
* export default async function Layout({ children }: { children: React.ReactNode }) {
|
|
35
|
+
* return (
|
|
36
|
+
* <div>
|
|
37
|
+
* {children}
|
|
38
|
+
* <Injector fetch={getCurrentUser.authCall} Component={AuthChecker} />
|
|
39
|
+
* </div>
|
|
40
|
+
* );
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @example Fetching multiple queries:
|
|
45
|
+
* ```tsx
|
|
46
|
+
* import { Injector } from "naystack/graphql/server";
|
|
47
|
+
* import getCurrentUser from "@/app/api/(graphql)/User/resolvers/get-current-user";
|
|
48
|
+
* import getChats from "@/app/api/(graphql)/Chat/resolvers/get-chats";
|
|
49
|
+
* import { ChatWindow } from "./components/chat-window";
|
|
50
|
+
*
|
|
51
|
+
* export default async function ChatPage() {
|
|
52
|
+
* return (
|
|
53
|
+
* <Injector
|
|
54
|
+
* fetch={async () => ({
|
|
55
|
+
* user: await getCurrentUser.authCall(),
|
|
56
|
+
* chats: await getChats.authCall(),
|
|
57
|
+
* })}
|
|
58
|
+
* Component={ChatWindow}
|
|
59
|
+
* />
|
|
60
|
+
* );
|
|
61
|
+
* }
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* @category GraphQL
|
|
65
|
+
*/
|
|
11
66
|
declare function Injector<T, Y>({ fetch, Component, props, }: {
|
|
12
67
|
fetch: () => Promise<T>;
|
|
13
68
|
Component: FC<{
|
|
@@ -15,6 +70,39 @@ declare function Injector<T, Y>({ fetch, Component, props, }: {
|
|
|
15
70
|
loading: boolean;
|
|
16
71
|
} & Y>;
|
|
17
72
|
} & ComponentProps<Y>): React__default.JSX.Element;
|
|
73
|
+
/**
|
|
74
|
+
* Runs a raw GraphQL query on the server using the registered Apollo client.
|
|
75
|
+
* Cookies are forwarded automatically so the backend can identify the user.
|
|
76
|
+
*
|
|
77
|
+
* Use this in Server Components, Server Actions, or route handlers when you need to
|
|
78
|
+
* run a query against the GraphQL endpoint (rather than calling a resolver directly with `.call()`/`.authCall()`).
|
|
79
|
+
*
|
|
80
|
+
* Supports Next.js ISR via `revalidate` and on-demand revalidation via `tags`.
|
|
81
|
+
*
|
|
82
|
+
* @param _query - A `TypedDocumentNode` (e.g. from codegen) defining the query and its result type.
|
|
83
|
+
* @param options - Optional query options.
|
|
84
|
+
* @param options.variables - Variables object for the query (must match the document's variable types).
|
|
85
|
+
* @param options.revalidate - Next.js revalidate in seconds; when set, enables caching with this TTL.
|
|
86
|
+
* @param options.tags - Next.js cache tags for on-demand revalidation.
|
|
87
|
+
* @param options.noCookie - If `true`, the request is sent without cookies (unauthenticated).
|
|
88
|
+
* @returns Promise resolving to the query result data (typed by the document).
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* import { query } from "naystack/graphql/server";
|
|
93
|
+
* import { GetUserDocument } from "@/generated/graphql";
|
|
94
|
+
*
|
|
95
|
+
* // In a Server Component:
|
|
96
|
+
* const data = await query(GetUserDocument, {
|
|
97
|
+
* variables: { id: userId },
|
|
98
|
+
* revalidate: 60, // Cache for 60s (Next.js ISR)
|
|
99
|
+
* tags: ["user"], // For on-demand revalidation
|
|
100
|
+
* });
|
|
101
|
+
* return <Profile user={data.user} />;
|
|
102
|
+
* ```
|
|
103
|
+
*
|
|
104
|
+
* @category GraphQL
|
|
105
|
+
*/
|
|
18
106
|
declare const query: <T, V extends OperationVariables>(_query: TypedDocumentNode<T, V>, options?: {
|
|
19
107
|
variables?: V;
|
|
20
108
|
revalidate?: number;
|
package/dist/graphql/types.d.mts
CHANGED
|
@@ -1,7 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request context passed to GraphQL resolvers. Built automatically from the request's
|
|
3
|
+
* `Authorization` header or refresh cookie by the built-in `getContext`.
|
|
4
|
+
*
|
|
5
|
+
* @property userId - Authenticated user id, or `null` if the request is unauthenticated.
|
|
6
|
+
* @property isRefreshID - `true` if the user was identified via the refresh cookie (not an access token).
|
|
7
|
+
* When `isRefreshID` is true, mutations are blocked by default (only queries are allowed via refresh cookie).
|
|
8
|
+
*
|
|
9
|
+
* @category GraphQL
|
|
10
|
+
*/
|
|
1
11
|
interface Context {
|
|
2
12
|
userId: number | null;
|
|
3
13
|
isRefreshID?: boolean;
|
|
4
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Context for resolvers that require authentication (`authorized: true`). The `userId` is guaranteed to be non-null.
|
|
17
|
+
*
|
|
18
|
+
* When you set `authorized: true` on a `query()` or `field()`, the resolver's `ctx` parameter is typed as `AuthorizedContext`
|
|
19
|
+
* instead of `Context`, so you can safely access `ctx.userId` without null checks.
|
|
20
|
+
*
|
|
21
|
+
* @property userId - Authenticated user id (guaranteed non-null).
|
|
22
|
+
* @property isRefreshID - `true` if identified via refresh cookie.
|
|
23
|
+
*
|
|
24
|
+
* @category GraphQL
|
|
25
|
+
*/
|
|
5
26
|
interface AuthorizedContext {
|
|
6
27
|
userId: number;
|
|
7
28
|
isRefreshID?: boolean;
|
package/dist/graphql/types.d.ts
CHANGED
|
@@ -1,7 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request context passed to GraphQL resolvers. Built automatically from the request's
|
|
3
|
+
* `Authorization` header or refresh cookie by the built-in `getContext`.
|
|
4
|
+
*
|
|
5
|
+
* @property userId - Authenticated user id, or `null` if the request is unauthenticated.
|
|
6
|
+
* @property isRefreshID - `true` if the user was identified via the refresh cookie (not an access token).
|
|
7
|
+
* When `isRefreshID` is true, mutations are blocked by default (only queries are allowed via refresh cookie).
|
|
8
|
+
*
|
|
9
|
+
* @category GraphQL
|
|
10
|
+
*/
|
|
1
11
|
interface Context {
|
|
2
12
|
userId: number | null;
|
|
3
13
|
isRefreshID?: boolean;
|
|
4
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Context for resolvers that require authentication (`authorized: true`). The `userId` is guaranteed to be non-null.
|
|
17
|
+
*
|
|
18
|
+
* When you set `authorized: true` on a `query()` or `field()`, the resolver's `ctx` parameter is typed as `AuthorizedContext`
|
|
19
|
+
* instead of `Context`, so you can safely access `ctx.userId` without null checks.
|
|
20
|
+
*
|
|
21
|
+
* @property userId - Authenticated user id (guaranteed non-null).
|
|
22
|
+
* @property isRefreshID - `true` if identified via refresh cookie.
|
|
23
|
+
*
|
|
24
|
+
* @category GraphQL
|
|
25
|
+
*/
|
|
5
26
|
interface AuthorizedContext {
|
|
6
27
|
userId: number;
|
|
7
28
|
isRefreshID?: boolean;
|
package/dist/graphql/utils.d.mts
CHANGED
|
@@ -2,20 +2,29 @@ import { GraphQLScalarType } from 'graphql';
|
|
|
2
2
|
import { ClassType, Query, Arg } from 'type-graphql';
|
|
3
3
|
import { AuthorizedContext, Context } from './types.mjs';
|
|
4
4
|
|
|
5
|
+
/** Options for @Query() / @Mutation() return type (e.g. nullable). */
|
|
5
6
|
type ReturnOptions = Parameters<typeof Query>[1];
|
|
7
|
+
/** Options for @Arg() (e.g. nullable). */
|
|
6
8
|
type ArgsOptions = Parameters<typeof Arg>[2];
|
|
9
|
+
/** Maps nullable keys to optional and normalizes null/undefined. */
|
|
7
10
|
type NormalizeNullUndefined<T> = {
|
|
8
11
|
[K in keyof T as null extends T[K] ? K : never]?: Exclude<T[K], undefined>;
|
|
9
12
|
} & {
|
|
10
13
|
[K in keyof T as null extends T[K] ? never : K]: undefined extends T[K] ? Exclude<T[K], undefined> | null : T[K];
|
|
11
14
|
};
|
|
15
|
+
/** Adds nullable option to Query/Arg options. */
|
|
12
16
|
type NullableOptions<T, X extends boolean> = T & {
|
|
13
17
|
nullable: X;
|
|
14
18
|
};
|
|
19
|
+
/** Resolves a GraphQL type (class, scalar, primitive) to TS type. */
|
|
15
20
|
type ParsedGQLType<T, MergeNullUndefined extends boolean> = T extends StringConstructor ? string : T extends NumberConstructor ? number : T extends BooleanConstructor ? boolean : T extends GraphQLScalarType<infer U> ? U : T extends ClassType<infer U> ? MergeNullUndefined extends true ? NormalizeNullUndefined<U> : U : T extends Record<infer K, string | number> ? T[K] : void;
|
|
21
|
+
/** Array-aware ParsedGQLType. */
|
|
16
22
|
type ParsedGQLTypeWithArray<T, MergeNullUndefined extends boolean> = T extends Array<infer U> ? ParsedGQLType<U, MergeNullUndefined>[] : ParsedGQLType<T, MergeNullUndefined>;
|
|
23
|
+
/** Adds null/undefined when nullable. */
|
|
17
24
|
type ParsedGQLTypeWithNullability<T, IsNullable extends boolean, MergeNullUndefined extends boolean> = IsNullable extends true ? ParsedGQLTypeWithArray<T, MergeNullUndefined> | null | undefined : ParsedGQLTypeWithArray<T, MergeNullUndefined>;
|
|
25
|
+
/** Allows resolver to return T or Promise<T>. */
|
|
18
26
|
type Promisify<T> = T | Promise<T>;
|
|
27
|
+
/** Base for query/field definition (output, input, options). */
|
|
19
28
|
interface BaseDefinition<T, U, IsAuth extends boolean = false, OutputNullable extends boolean = false, InputNullable extends boolean = false> {
|
|
20
29
|
output: T;
|
|
21
30
|
outputOptions?: NullableOptions<ReturnOptions, OutputNullable>;
|
|
@@ -23,26 +32,234 @@ interface BaseDefinition<T, U, IsAuth extends boolean = false, OutputNullable ex
|
|
|
23
32
|
inputOptions?: NullableOptions<ArgsOptions, InputNullable>;
|
|
24
33
|
authorized?: IsAuth;
|
|
25
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Full query/mutation definition returned by {@link query}. Contains the resolver function,
|
|
37
|
+
* plus `.call()` and `.authCall()` for direct server-side invocation.
|
|
38
|
+
*
|
|
39
|
+
* @category GraphQL
|
|
40
|
+
*/
|
|
26
41
|
interface QueryDefinition<T, U, IsAuth extends boolean = false, OutputNullable extends boolean = false, InputNullable extends boolean = false, R extends Promisify<ParsedGQLTypeWithNullability<T, OutputNullable, true>> = Promisify<ParsedGQLTypeWithNullability<T, OutputNullable, true>>> extends BaseDefinition<T, U, IsAuth, OutputNullable, InputNullable> {
|
|
27
42
|
fn: (ctx: IsAuth extends true ? AuthorizedContext : Context, data: ParsedGQLTypeWithNullability<U, InputNullable, false>) => R;
|
|
43
|
+
/** Calls the resolver server-side. For authorized queries, reads the refresh cookie; for non-authorized, passes null userId. */
|
|
28
44
|
call: (data: ParsedGQLTypeWithNullability<U, InputNullable, false>) => Promise<Awaited<R>>;
|
|
45
|
+
/** Calls the resolver server-side with authentication (always reads the refresh cookie). Use in Server Components. */
|
|
29
46
|
authCall: (data: ParsedGQLTypeWithNullability<U, InputNullable, false>) => Promise<Awaited<R>>;
|
|
30
47
|
mutation?: boolean;
|
|
31
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Defines a type-graphql query or mutation with typed input/output and optional auth.
|
|
51
|
+
* Use with {@link QueryLibrary} to build resolver classes for `initGraphQLServer`.
|
|
52
|
+
*
|
|
53
|
+
* Each query definition gets `.call(data)` and `.authCall(data)` methods for direct server-side invocation
|
|
54
|
+
* (e.g. in Server Components or other resolvers). Both are cached via React's `cache()`.
|
|
55
|
+
*
|
|
56
|
+
* @param fn - Resolver function: `(ctx, data) => result`.
|
|
57
|
+
* - `ctx` is `Context` (or `AuthorizedContext` when `authorized: true`) with `userId`.
|
|
58
|
+
* - `data` is the typed GraphQL input (or `void` if no input).
|
|
59
|
+
* @param options - Configuration for the query/mutation.
|
|
60
|
+
* @param options.output - The GraphQL return type (type-graphql `@ObjectType` class, `String`, `Boolean`, `Number`, etc.).
|
|
61
|
+
* @param options.input - Optional GraphQL input type (`@InputType` class or scalar) for the `input` argument.
|
|
62
|
+
* @param options.outputOptions - Optional. Set `{ nullable: true }` to allow null returns.
|
|
63
|
+
* @param options.inputOptions - Optional. Set `{ nullable: true }` to allow null input.
|
|
64
|
+
* @param options.authorized - If `true`, the resolver requires an authenticated user. `ctx` is typed as `AuthorizedContext` (non-null `userId`).
|
|
65
|
+
* @param options.mutation - If `true`, registers as a `@Mutation`; otherwise registers as a `@Query`.
|
|
66
|
+
* @returns A `QueryDefinition` with `.call(data)` and `.authCall(data)` for server-side invocation.
|
|
67
|
+
*
|
|
68
|
+
* @example Simple query (no input, nullable output):
|
|
69
|
+
* ```ts
|
|
70
|
+
* import { query } from "naystack/graphql";
|
|
71
|
+
*
|
|
72
|
+
* export default query(
|
|
73
|
+
* async (ctx) => {
|
|
74
|
+
* if (!ctx.userId) return null;
|
|
75
|
+
* const [user] = await db.select().from(UserTable).where(eq(UserTable.id, ctx.userId));
|
|
76
|
+
* return user || null;
|
|
77
|
+
* },
|
|
78
|
+
* { output: User, outputOptions: { nullable: true } },
|
|
79
|
+
* );
|
|
80
|
+
* ```
|
|
81
|
+
*
|
|
82
|
+
* @example Mutation with input and authorization:
|
|
83
|
+
* ```ts
|
|
84
|
+
* export default query(
|
|
85
|
+
* async (ctx, input: SubmitFeedbackInput) => {
|
|
86
|
+
* await db.insert(FeedbackTable).values({ userId: ctx.userId, score: input.score, text: input.text });
|
|
87
|
+
* return true;
|
|
88
|
+
* },
|
|
89
|
+
* { output: Boolean, input: SubmitFeedbackInput, authorized: true, mutation: true },
|
|
90
|
+
* );
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
93
|
+
* @example Server-side invocation in a Server Component:
|
|
94
|
+
* ```ts
|
|
95
|
+
* const user = await getCurrentUser.authCall(); // Reads refresh cookie for auth
|
|
96
|
+
* const planets = await getPlanets.call(); // No auth needed
|
|
97
|
+
* ```
|
|
98
|
+
*
|
|
99
|
+
* @category GraphQL
|
|
100
|
+
*/
|
|
32
101
|
declare function query<T, U, IsAuth extends boolean = false, OutputNullable extends boolean = false, InputNullable extends boolean = false, R extends Promisify<ParsedGQLTypeWithNullability<T, OutputNullable, true>> = Promisify<ParsedGQLTypeWithNullability<T, OutputNullable, true>>>(fn: (ctx: IsAuth extends true ? AuthorizedContext : Context, data: ParsedGQLTypeWithNullability<U, InputNullable, false>) => R, options: Omit<QueryDefinition<T, U, IsAuth, OutputNullable, InputNullable, R>, "fn" | "authCall" | "call">): QueryDefinition<T, U, IsAuth, OutputNullable, InputNullable, R>;
|
|
102
|
+
/**
|
|
103
|
+
* Full field resolver definition returned by {@link field}. Contains the resolver function,
|
|
104
|
+
* plus `.call()` and `.authCall()` for direct server-side invocation.
|
|
105
|
+
*
|
|
106
|
+
* @category GraphQL
|
|
107
|
+
*/
|
|
33
108
|
interface FieldResolverDefinition<T, U, Root, IsAuth extends boolean = false, OutputNullable extends boolean = false, InputNullable extends boolean = false, R extends Promisify<ParsedGQLTypeWithNullability<T, OutputNullable, true>> = Promisify<ParsedGQLTypeWithNullability<T, OutputNullable, true>>> extends BaseDefinition<T, U, IsAuth, OutputNullable, InputNullable> {
|
|
34
109
|
fn: (root: Root, ctx: IsAuth extends true ? AuthorizedContext : Context, data: ParsedGQLTypeWithNullability<U, InputNullable, false>) => R;
|
|
110
|
+
/** Calls the field resolver server-side. For authorized fields, reads the refresh cookie. */
|
|
35
111
|
call: (root: Root, data: ParsedGQLTypeWithNullability<U, InputNullable, false>) => Promise<Awaited<R>>;
|
|
112
|
+
/** Calls the field resolver server-side with authentication (always reads the refresh cookie). */
|
|
36
113
|
authCall: (root: Root, data: ParsedGQLTypeWithNullability<U, InputNullable, false>) => Promise<Awaited<R>>;
|
|
37
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* Defines a type-graphql field resolver with typed root, context, and input.
|
|
117
|
+
* Use with {@link FieldLibrary} to attach computed fields to a parent GraphQL type.
|
|
118
|
+
*
|
|
119
|
+
* Like `query()`, each field definition gets `.call(root, data)` and `.authCall(root, data)` for server-side invocation.
|
|
120
|
+
*
|
|
121
|
+
* @param fn - Resolver function: `(root, ctx, data) => result`.
|
|
122
|
+
* - `root` is the parent object (e.g. the `User` row from the database).
|
|
123
|
+
* - `ctx` is `Context` (or `AuthorizedContext` when `authorized: true`).
|
|
124
|
+
* - `data` is the optional typed input argument.
|
|
125
|
+
* @param options - Configuration (same as `query()` but without `mutation`).
|
|
126
|
+
* @returns A `FieldResolverDefinition` with `.call` and `.authCall` for server-side invocation.
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```ts
|
|
130
|
+
* import { field } from "naystack/graphql";
|
|
131
|
+
*
|
|
132
|
+
* // Resolve the "seller" field on a Property type
|
|
133
|
+
* const seller = field(
|
|
134
|
+
* async (property: PropertyDB) => {
|
|
135
|
+
* if (!property.sellerId) return null;
|
|
136
|
+
* const [seller] = await db.select().from(ContactTable).where(eq(ContactTable.id, property.sellerId));
|
|
137
|
+
* return seller || null;
|
|
138
|
+
* },
|
|
139
|
+
* { output: ContactGQL, outputOptions: { nullable: true } },
|
|
140
|
+
* );
|
|
141
|
+
* ```
|
|
142
|
+
*
|
|
143
|
+
* @example Inline in a FieldLibrary:
|
|
144
|
+
* ```ts
|
|
145
|
+
* const OrgFields = FieldLibrary<OrgDB>(OrgGQL, {
|
|
146
|
+
* access: field(
|
|
147
|
+
* async (root, ctx) => {
|
|
148
|
+
* if (!ctx.userId) return null;
|
|
149
|
+
* return checkOrgAccess(ctx.userId, root.id);
|
|
150
|
+
* },
|
|
151
|
+
* { output: AccessRole, outputOptions: { nullable: true } },
|
|
152
|
+
* ),
|
|
153
|
+
* });
|
|
154
|
+
* ```
|
|
155
|
+
*
|
|
156
|
+
* @category GraphQL
|
|
157
|
+
*/
|
|
38
158
|
declare function field<T, U, IsAuth extends boolean, Root, OutputNullable extends boolean = false, InputNullable extends boolean = false, R extends Promisify<ParsedGQLTypeWithNullability<T, OutputNullable, true>> = Promisify<ParsedGQLTypeWithNullability<T, OutputNullable, true>>>(fn: (root: Root, ctx: IsAuth extends true ? AuthorizedContext : Context, data: ParsedGQLTypeWithNullability<U, InputNullable, false>) => R, options: Omit<FieldResolverDefinition<T, U, Root, IsAuth, OutputNullable, InputNullable, R>, "fn" | "authCall" | "call">): FieldResolverDefinition<T, U, Root, IsAuth, OutputNullable, InputNullable, R>;
|
|
159
|
+
/**
|
|
160
|
+
* Builds a type-graphql `@Resolver` class from a map of query/mutation definitions created with {@link query}.
|
|
161
|
+
* Each key in the `queries` object becomes a Query or Mutation field on the GraphQL schema.
|
|
162
|
+
*
|
|
163
|
+
* Pass the returned class in the `resolvers` array of `initGraphQLServer`.
|
|
164
|
+
*
|
|
165
|
+
* @param queries - Object mapping GraphQL field names to `QueryDefinition`s (from `query()`).
|
|
166
|
+
* Each key becomes the field name in the schema. Mutations are determined by `{ mutation: true }` in the definition.
|
|
167
|
+
* @returns A `@Resolver` class suitable for `initGraphQLServer`.
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```ts
|
|
171
|
+
* import { QueryLibrary, query } from "naystack/graphql";
|
|
172
|
+
* import getCurrentUser from "./resolvers/get-current-user";
|
|
173
|
+
* import updateUser from "./resolvers/update-user";
|
|
174
|
+
* import onboardUser from "./resolvers/onboard-user";
|
|
175
|
+
*
|
|
176
|
+
* export const UserResolvers = QueryLibrary({
|
|
177
|
+
* getCurrentUser, // becomes Query.getCurrentUser
|
|
178
|
+
* updateUser, // becomes Mutation.updateUser (if mutation: true)
|
|
179
|
+
* onboardUser, // becomes Mutation.onboardUser (if mutation: true)
|
|
180
|
+
* });
|
|
181
|
+
* ```
|
|
182
|
+
*
|
|
183
|
+
* @category GraphQL
|
|
184
|
+
*/
|
|
39
185
|
declare function QueryLibrary<T extends Record<string, QueryDefinition<any, any, any, any, any, any>>>(queries: T): {
|
|
40
186
|
new (): {};
|
|
41
187
|
};
|
|
188
|
+
/**
|
|
189
|
+
* Builds a type-graphql `@Resolver(() => type)` class that resolves computed fields on a parent GraphQL type.
|
|
190
|
+
* Each key in the `queries` object becomes a `@FieldResolver` on that type.
|
|
191
|
+
*
|
|
192
|
+
* Pass the returned class in the `resolvers` array of `initGraphQLServer`.
|
|
193
|
+
*
|
|
194
|
+
* @typeParam X - The database/plain type of the parent object (e.g. `UserDB`).
|
|
195
|
+
* @param type - The parent GraphQL type class (e.g. `User`). Must be a `@ObjectType` class.
|
|
196
|
+
* @param queries - Object mapping field names to `FieldResolverDefinition`s (from `field()`).
|
|
197
|
+
* @returns A `@Resolver` class for the given type; pass it in `initGraphQLServer`'s resolvers array.
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```ts
|
|
201
|
+
* import { FieldLibrary, field } from "naystack/graphql";
|
|
202
|
+
* import { User } from "./types";
|
|
203
|
+
* import type { UserDB } from "./db";
|
|
204
|
+
* import organizations from "./resolvers/organizations-field";
|
|
205
|
+
*
|
|
206
|
+
* export const UserFieldResolvers = FieldLibrary<UserDB>(User, {
|
|
207
|
+
* organizations, // Resolves User.organizations from the UserDB row
|
|
208
|
+
* });
|
|
209
|
+
* ```
|
|
210
|
+
*
|
|
211
|
+
* @example With inline field definitions:
|
|
212
|
+
* ```ts
|
|
213
|
+
* export const OrgFieldResolvers = FieldLibrary<OrgDB>(OrgGQL, {
|
|
214
|
+
* access: field(
|
|
215
|
+
* async (root, ctx) => checkOrgAccess(ctx.userId, root.id),
|
|
216
|
+
* { output: AccessRole, outputOptions: { nullable: true } },
|
|
217
|
+
* ),
|
|
218
|
+
* });
|
|
219
|
+
* ```
|
|
220
|
+
*
|
|
221
|
+
* @category GraphQL
|
|
222
|
+
*/
|
|
42
223
|
declare function FieldLibrary<X extends object, T extends Record<string, FieldResolverDefinition<any, any, X, any, any, any, any>> = Record<string, FieldResolverDefinition<any, any, X, any, any, any, any>>>(type: ClassType, queries: T): {
|
|
43
224
|
new (): {};
|
|
44
225
|
};
|
|
226
|
+
/**
|
|
227
|
+
* Infers the TypeScript return type of a query definition's `.call()` method.
|
|
228
|
+
* Use this to type component props that receive query results, ensuring full type safety.
|
|
229
|
+
*
|
|
230
|
+
* @typeParam T - A `QueryDefinition` (the default export from a resolver file created with `query()`).
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* ```ts
|
|
234
|
+
* import type { QueryResponseType } from "naystack/graphql";
|
|
235
|
+
* import type getCurrentUser from "@/app/api/(graphql)/User/resolvers/get-current-user";
|
|
236
|
+
* import type getDeal from "@/app/api/(graphql)/Deal/queries/get-deal";
|
|
237
|
+
*
|
|
238
|
+
* interface Props {
|
|
239
|
+
* user: QueryResponseType<typeof getCurrentUser>;
|
|
240
|
+
* deal: QueryResponseType<typeof getDeal>;
|
|
241
|
+
* }
|
|
242
|
+
* ```
|
|
243
|
+
*
|
|
244
|
+
* @category GraphQL
|
|
245
|
+
*/
|
|
45
246
|
type QueryResponseType<T extends QueryDefinition<any, any, any, any, any, any>> = Awaited<ReturnType<T["call"]>>;
|
|
247
|
+
/**
|
|
248
|
+
* Infers the TypeScript return type of a field resolver definition's `.call()` method.
|
|
249
|
+
* Use this to type the resolved field value.
|
|
250
|
+
*
|
|
251
|
+
* @typeParam T - A `FieldResolverDefinition` (from `field()`).
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* ```ts
|
|
255
|
+
* import type { FieldResponseType } from "naystack/graphql";
|
|
256
|
+
* import type organizationsField from "./resolvers/organizations-field";
|
|
257
|
+
*
|
|
258
|
+
* type Orgs = FieldResponseType<typeof organizationsField>;
|
|
259
|
+
* ```
|
|
260
|
+
*
|
|
261
|
+
* @category GraphQL
|
|
262
|
+
*/
|
|
46
263
|
type FieldResponseType<T extends FieldResolverDefinition<any, any, any, any, any, any, any>> = Awaited<ReturnType<T["call"]>>;
|
|
47
264
|
|
|
48
265
|
export { FieldLibrary, type FieldResponseType, QueryLibrary, type QueryResponseType, field, query };
|