@gqloom/core 0.2.0 → 0.2.2

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
@@ -1,24 +1,24 @@
1
- # GQLoom
1
+ ![GQLoom Logo](https://github.com/modevol-com/gqloom/blob/main/gqloom.svg?raw=true)
2
2
 
3
- English | [简体中文](./README.zh-CN.md)
3
+ # GQLoom
4
4
 
5
- GQLoom is a GraphQL weaver for TypeScript/JavaScript, using Zod, Yup, or Valibot to easily weave GraphQL schemas, providing the best development experience with complete type inference.
5
+ GQLoom is a GraphQL weaver for TypeScript/JavaScript that weaves GraphQL Schema using Valibot, Zod, or Yup, and supports sophisticated type inference to provide the best development experience.
6
6
 
7
- GQLoom is inspired by [tRPC](https://trpc.io/), [TypeGraphQL](https://typegraphql.com/), and [Pothos](https://pothos-graphql.dev/).
7
+ The design of GQLoom is inspired by [tRPC](https://trpc.io/), [TypeGraphQL](https://typegraphql.com/), [Pothos](https://pothos-graphql.dev/).
8
8
 
9
9
  ## Features
10
10
 
11
- - 📦 Use popular pattern libraries (Zod, Yup, Valibot) to build and validate GraphQL schemas.
12
- - 🔒 Complete type safety, discover potential issues during compilation.
13
- - 🧩 Classic middleware system: authentication, caching, logging, etc.
14
- - 🪄 Accessible Context and DataLoader everywhere.
15
- - 🔮 No code generation and experimental decorator features.
11
+ - 🚀 GraphQL: flexible and efficient, reducing redundant data transfers;
12
+ - 🔒 Robust type safety: enjoy smart hints during development and spot potential problems during editing;
13
+ - 🔋 Ready to go: middleware, contexts, subscriptions, federated graphs are ready to go;
14
+ - 🔮 No extra magic: no decorators, no metadata and reflection, no code generation, you just need JavaScript/TypeScript;
15
+ - 🧩 Familiar schema libraries: use the schema libraries you already know (Zod, Yup, Valibot) to build GraphQL Schema and validate inputs;
16
+ - 🧑‍💻 Develop happily: highly readable and semantic APIs designed to keep your code tidy;
16
17
 
17
- ## Hello, World!
18
+ ## Hello World
18
19
 
19
20
  ```ts
20
- import { weave } from "@gqloom/core"
21
- import { resolver, query } from "@gqloom/valibot"
21
+ import { resolver, query, weave } from "@gqloom/valibot"
22
22
  import * as v from "valibot"
23
23
 
24
24
  const HelloResolver = resolver({
@@ -27,3 +27,9 @@ const HelloResolver = resolver({
27
27
 
28
28
  export const schema = weave(HelloResolver)
29
29
  ```
30
+
31
+ Read [Introduction](https://gqloom.dev/guide/introduction.html) to learn more about GQLoom.
32
+
33
+ ## Getting Started
34
+
35
+ See [Getting Started](https://gqloom.dev/guide/getting-started.html) to learn how to use GQLoom.
package/dist/index.d.cts CHANGED
@@ -205,9 +205,13 @@ declare function getSubscriptionOptions(subscribeOrOptions: (() => any) | Subscr
205
205
  declare function getFieldOptions({ description, deprecationReason, extensions, }: GraphQLFieldOptions): GraphQLFieldOptions;
206
206
 
207
207
  interface MiddlewarePayload<TField extends GenericFieldOrOperation = FieldOrOperation<any, any, any, any>> {
208
+ /** The Output Silk of the field */
208
209
  outputSilk: InferSilkO<InferFieldOutput<TField>>;
210
+ /** The previous object, which for a field on the root Query type is often not used. */
209
211
  parent: TField extends FieldOrOperation<infer TParent, any, any, any> ? TParent extends undefined ? undefined : InferSilkO<NonNullable<TParent>> : never;
212
+ /** A function to parse the input of the field */
210
213
  parseInput: TField extends FieldOrOperation<any, any, infer TInput, any> ? CallableInputParser<TInput> : undefined;
214
+ /** The type of the field: `query`, `mutation`, `subscription` or `field` */
211
215
  type: FieldOrOperationType;
212
216
  }
213
217
  type Middleware<TField extends GenericFieldOrOperation = FieldOrOperation<any, any, any, any>> = (next: () => MayPromise<InferSilkO<InferFieldOutput<TField>>>, payload: MiddlewarePayload<TField>) => MayPromise<InferSilkO<InferFieldOutput<TField>>>;
@@ -223,7 +227,7 @@ interface ResolverPayload<TContext extends object = object, TField extends Field
223
227
  */
224
228
  readonly root: any;
225
229
  /**
226
- * The payload provided to the field in the GraphQL query.
230
+ * The arguments provided to the field in the GraphQL query.
227
231
  */
228
232
  readonly args: Record<string, any>;
229
233
  /**
@@ -231,7 +235,7 @@ interface ResolverPayload<TContext extends object = object, TField extends Field
231
235
  */
232
236
  readonly context: TContext;
233
237
  /**
234
- * The source object that contains the field in the parent type.
238
+ * A custom object each resolver can read from/write to.
235
239
  */
236
240
  readonly info: GraphQLResolveInfo;
237
241
  /**
@@ -557,7 +561,7 @@ declare function inputToArgs(input: InputSchema<GraphQLSilk>): GraphQLFieldConfi
557
561
  declare function ensureInputType(silkOrType: GraphQLType | GraphQLSilk): GraphQLInputType;
558
562
  declare function ensureInputObjectType(object: GraphQLObjectType | GraphQLInterfaceType | GraphQLInputObjectType): GraphQLInputObjectType;
559
563
 
560
- declare function ensureInterfaceType(gqlType: GraphQLOutputType, interfaceConfig?: GraphQLInterfaceTypeConfig<any, any>): GraphQLInterfaceType;
564
+ declare function ensureInterfaceType(gqlType: GraphQLOutputType, interfaceConfig?: Partial<GraphQLInterfaceTypeConfig<any, any>>): GraphQLInterfaceType;
561
565
 
562
566
  interface GQLoomExtensions {
563
567
  defaultValue?: any;
package/dist/index.d.ts CHANGED
@@ -205,9 +205,13 @@ declare function getSubscriptionOptions(subscribeOrOptions: (() => any) | Subscr
205
205
  declare function getFieldOptions({ description, deprecationReason, extensions, }: GraphQLFieldOptions): GraphQLFieldOptions;
206
206
 
207
207
  interface MiddlewarePayload<TField extends GenericFieldOrOperation = FieldOrOperation<any, any, any, any>> {
208
+ /** The Output Silk of the field */
208
209
  outputSilk: InferSilkO<InferFieldOutput<TField>>;
210
+ /** The previous object, which for a field on the root Query type is often not used. */
209
211
  parent: TField extends FieldOrOperation<infer TParent, any, any, any> ? TParent extends undefined ? undefined : InferSilkO<NonNullable<TParent>> : never;
212
+ /** A function to parse the input of the field */
210
213
  parseInput: TField extends FieldOrOperation<any, any, infer TInput, any> ? CallableInputParser<TInput> : undefined;
214
+ /** The type of the field: `query`, `mutation`, `subscription` or `field` */
211
215
  type: FieldOrOperationType;
212
216
  }
213
217
  type Middleware<TField extends GenericFieldOrOperation = FieldOrOperation<any, any, any, any>> = (next: () => MayPromise<InferSilkO<InferFieldOutput<TField>>>, payload: MiddlewarePayload<TField>) => MayPromise<InferSilkO<InferFieldOutput<TField>>>;
@@ -223,7 +227,7 @@ interface ResolverPayload<TContext extends object = object, TField extends Field
223
227
  */
224
228
  readonly root: any;
225
229
  /**
226
- * The payload provided to the field in the GraphQL query.
230
+ * The arguments provided to the field in the GraphQL query.
227
231
  */
228
232
  readonly args: Record<string, any>;
229
233
  /**
@@ -231,7 +235,7 @@ interface ResolverPayload<TContext extends object = object, TField extends Field
231
235
  */
232
236
  readonly context: TContext;
233
237
  /**
234
- * The source object that contains the field in the parent type.
238
+ * A custom object each resolver can read from/write to.
235
239
  */
236
240
  readonly info: GraphQLResolveInfo;
237
241
  /**
@@ -557,7 +561,7 @@ declare function inputToArgs(input: InputSchema<GraphQLSilk>): GraphQLFieldConfi
557
561
  declare function ensureInputType(silkOrType: GraphQLType | GraphQLSilk): GraphQLInputType;
558
562
  declare function ensureInputObjectType(object: GraphQLObjectType | GraphQLInterfaceType | GraphQLInputObjectType): GraphQLInputObjectType;
559
563
 
560
- declare function ensureInterfaceType(gqlType: GraphQLOutputType, interfaceConfig?: GraphQLInterfaceTypeConfig<any, any>): GraphQLInterfaceType;
564
+ declare function ensureInterfaceType(gqlType: GraphQLOutputType, interfaceConfig?: Partial<GraphQLInterfaceTypeConfig<any, any>>): GraphQLInterfaceType;
561
565
 
562
566
  interface GQLoomExtensions {
563
567
  defaultValue?: any;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gqloom/core",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Create GraphQL schema and resolvers with TypeScript.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -26,7 +26,15 @@
26
26
  "peerDependencies": {
27
27
  "graphql": ">= 16.8.0"
28
28
  },
29
- "keywords": [],
29
+ "keywords": [
30
+ "gqloom",
31
+ "graphql",
32
+ "schema",
33
+ "typescript",
34
+ "valibot",
35
+ "zod",
36
+ "yup"
37
+ ],
30
38
  "author": "xcfox",
31
39
  "license": "MIT",
32
40
  "publishConfig": {
package/README.zh-CN.md DELETED
@@ -1,267 +0,0 @@
1
- # [GQLoom](../../README.zh-CN.md)
2
-
3
- [English](./README.md) | 简体中文
4
-
5
- [GQLoom](../../README.zh-CN.md) 是一个用于 TypeScript/JavaScript 的 GraphQL 编织器,使用 Zod、Yup 或者 Valibot 来愉快地编织 GraphQL Schema, 支持完善的类型推断以提供最好的开发体验。
6
-
7
- ## 你好,世界!
8
-
9
- ```ts
10
- import { weave, loom, silk } from "@gqloom/core"
11
- import { GraphQLString } from "graphql"
12
-
13
- const HelloResolver = loom.resolver({
14
- hello: loom.query(silk(GraphQLString), () => "world"),
15
- })
16
-
17
- export const schema = weave(HelloResolver)
18
- ```
19
-
20
- # GQLoom Core
21
-
22
- GQLoom Core 是 GQLoom 的核心库,提供了 GQLoom 的基础功能。
23
-
24
- ## 概念
25
-
26
- GQLoom 意为 GraphQL 的织布机(Loom),其核心理念是从各式Schema 编织出 GraphQL Schema。
27
-
28
- ### 丝线|Silk
29
-
30
- 丝线是 GQLoom 的基础单位,它同时反应 GraphQL 类型和 TypeScript 类型。
31
- 我们可以通过 `silk` 函数创建丝线:
32
-
33
- ##### 简单的标量丝线
34
-
35
- ```ts
36
- import { silk } from "@gqloom/core"
37
- import { GraphQLString, GraphQLInt } from "graphql"
38
-
39
- const StringSilk = silk(GraphQLString)
40
- const IntSilk = silk(GraphQLInt)
41
- ```
42
-
43
- ##### 携带类型的对象丝线
44
-
45
- ```ts
46
- import { silk } from "@gqloom/core"
47
- import {
48
- GraphQLObjectType,
49
- GraphQLNonNull,
50
- GraphQLString,
51
- GraphQLInt,
52
- } from "graphql"
53
-
54
- interface ICat {
55
- name: string
56
- age: number
57
- }
58
-
59
- // 这里我们使用 `silk`的泛型参数将 Cat 的类型标记为 ICat
60
- export const Cat = silk<ICat>(
61
- new GraphQLObjectType({
62
- name: "Cat",
63
- fields: {
64
- name: { type: new GraphQLNonNull(GraphQLString) },
65
- age: { type: new GraphQLNonNull(GraphQLInt) },
66
- },
67
- })
68
- )
69
- ```
70
-
71
- 直接使用 [graphql.js](https://graphql.org/graphql-js/constructing-types/) 构造 GraphQL 类型可能导致冗长的代码,并且需要手动为丝线添加类型声明。
72
- 使用 Zod、Valibot 可以更轻松地创建丝线。
73
-
74
- ##### 使用 Zod 创建丝线
75
-
76
- ```ts
77
- import { zodSilk } from "@gqloom/zod"
78
- import { z } from "zod"
79
-
80
- const Cat = zodSilk(
81
- z.object({
82
- __typename: z.literal("Cat").nullish(), // 定义 GraphQL Object 的名称
83
- name: z.string(),
84
- age: z.number(),
85
- })
86
- )
87
- ```
88
-
89
- ##### 使用 Valibot 创建丝线
90
-
91
- ```ts
92
- import { valibotSilk } from "@gqloom/valibot"
93
- import * as v from "valibot"
94
-
95
- const Cat = valibotSilk(
96
- v.object({
97
- __typename: v.nullish(v.literal("Cat")), // 定义 GraphQL Object 的名称
98
- name: v.string(),
99
- age: v.number(),
100
- })
101
- )
102
- ```
103
-
104
- ### 解析器|Resolver
105
-
106
- 解析器是放置 GraphQL 操作(Query、Mutation、Subscription)的地方,GQLoom 会将各个解析器汇总编织成 GraphQL Schema。
107
-
108
- ```ts
109
- import { loom, silk } from "@gqloom/core"
110
- import { GraphQLString } from "graphql"
111
-
112
- const { resolver, query, mutation } = loom
113
-
114
- const HelloResolver = resolver({
115
- hello: query(silk(GraphQLString), () => "world"),
116
- bye: mutation(silk(GraphQLString), {
117
- description: "say bye",
118
- resolve: () => "see you later",
119
- }),
120
- })
121
- ```
122
-
123
- 解析器内可以存放多个操作。操作通过 `query`、`mutation`或`subscription` 函数创建,它们接受两个参数:
124
-
125
- - 1. 丝线:定义了操作返回值的类型;
126
- - 2. 解析函数以及更多配置:定义了操作的具体逻辑、输入类型及其他配置。
127
-
128
- #### 带输入的解析操作
129
-
130
- 为 GraphQL 操作添加输入类型,只需要在解析函数中添加一个 `input` 参数即可。
131
-
132
- ```ts
133
- import { loom, silk } from "@gqloom/core"
134
- import { GraphQLString } from "graphql"
135
-
136
- const { resolver, query } = loom
137
-
138
- const GreetingResolver = resolver({
139
- greet: query(silk(GraphQLString), {
140
- input: { name: silk(GraphQLString) },
141
- resolve: ({ name }) => `Hello, ${name}!`,
142
- }),
143
- })
144
- ```
145
-
146
- 在以上代码中,我们定义了一个 `greet` 操作,它接受一个 `name` 作为输入,然后我们可以在 `resolve` 函数中轻松获取到 `name` 的值。
147
-
148
- #### 为对象添加更多字段
149
-
150
- 我们可以使用 `field` 函数在解析器内为对象添加额外的字段。
151
-
152
- ```ts
153
- import { loom, silk } from "@gqloom/core"
154
- import { GraphQLInt } from "graphql"
155
- import { Cat } from "./schemas"
156
-
157
- const CatResolver = resolver.of(Cat, {
158
- cat: query(Cat, () => ({
159
- name: "Tom",
160
- birthday: "2020-01-01",
161
- })),
162
-
163
- // 我们可以在解析函数的第一个参数获取到 `Cat` 实例的值
164
- age: field(silk(GraphQLInt), (cat) => {
165
- return new Date().getFullYear() - new Date(cat.birthday).getFullYear()
166
- }),
167
-
168
- ageAt: field(silk(GraphQLInt), {
169
- input: { year: silk(GraphQLInt) },
170
- // 当字段包含输入时,我们可以在第二个参数中获取到输入的值
171
- resolve: (cat, { year }) => {
172
- return year - new Date(cat.birthday).getFullYear()
173
- },
174
- }),
175
-
176
- // 在对象之间建立关联
177
- friend: field(Cat, () => ({
178
- name: "Jerry",
179
- birthday: "2020-01-01",
180
- })),
181
- })
182
- ```
183
-
184
- ### 编织器|Weaver
185
-
186
- 使用 `weave` 函数将解析器编织成 GraphQL Schema。
187
- `weave` 能够接受解析器、丝线、中间件、各式配置作为输入,将在之后介绍。
188
-
189
- ```ts
190
- import { weave } from "@gqloom/core"
191
- import { HelloResolver } from "./resolvers"
192
-
193
- export const schema = weave(HelloResolver, GreetingResolver)
194
- ```
195
-
196
- ### 中间件|Middleware
197
-
198
- GQLoom 提供了洋葱式中间件机制,可以在解析器执行之前或之后执行逻辑。
199
-
200
- ##### 声明一个简单中间件
201
-
202
- ```ts
203
- import { Middleware } from "@gqloom/core"
204
-
205
- const simpleMiddleware: Middleware = async (next) => {
206
- console.log("Before resolve")
207
- const result = await next()
208
- console.log("After resolve")
209
- return result
210
- }
211
- ```
212
-
213
- ### 上下文|Context
214
-
215
- 使用 `useContext` 函数随处获取上下文。
216
-
217
- ##### 在解析器中
218
-
219
- ```ts
220
- import { loom, silk, useContext } from "@gqloom/core"
221
- import { GraphQLString } from "graphql"
222
-
223
- const { query, mutation } = loom
224
-
225
- const HelloResolver = resolver({
226
- hello: query(silk(GraphQLString), () => {
227
- const name = useContext().info.name
228
- return `Hello, ${name}!`
229
- }),
230
- })
231
- ```
232
-
233
- ##### 在中间件中
234
-
235
- ```ts
236
- import { Middleware, useContext } from "@gqloom/core"
237
-
238
- const simpleMiddleware: Middleware = async (next) => {
239
- const context = useContext()
240
- console.log(`Hello, ${context.info.name}!`)
241
- return next()
242
- }
243
- ```
244
-
245
- Context 的内容取决于你选择的适配器。
246
-
247
- #### 上下文记忆|Context Memoization
248
-
249
- 我们有时需要在上下文中设置一些内容,并且在同一个上下文的中间件或解析器中获取同样的值,例如当前访问用户、DataLoader。
250
- GQLoom 提供了上下文记忆来便捷地实现这一点。
251
-
252
- ```ts
253
- import { createMemoization, useContext } from "@gqloom/core"
254
-
255
- // 创建一个上下文记忆
256
- const useVisitor = createMemoization(async () => {
257
- const context = useContext()
258
- return await fetchVisitor(context.info.visitorId)
259
- })
260
-
261
- // 在中间件中使用上下文记忆
262
- const AllowAdmin: Middleware = async (next) => {
263
- const visitor = await useVisitor()
264
- if (visitor.role !== "admin") throw new Error("Forbidden")
265
- return next()
266
- }
267
- ```