@effect-gql/federation 0.1.0 → 1.1.0
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 +100 -0
- package/index.cjs +618 -0
- package/index.cjs.map +1 -0
- package/index.d.cts +577 -0
- package/index.d.ts +577 -0
- package/index.js +570 -0
- package/index.js.map +1 -0
- package/package.json +14 -27
- package/dist/directives.d.ts +0 -136
- package/dist/directives.d.ts.map +0 -1
- package/dist/directives.js +0 -171
- package/dist/directives.js.map +0 -1
- package/dist/entities.d.ts +0 -31
- package/dist/entities.d.ts.map +0 -1
- package/dist/entities.js +0 -76
- package/dist/entities.js.map +0 -1
- package/dist/federated-builder.d.ts +0 -182
- package/dist/federated-builder.d.ts.map +0 -1
- package/dist/federated-builder.js +0 -442
- package/dist/federated-builder.js.map +0 -1
- package/dist/index.d.ts +0 -7
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -40
- package/dist/index.js.map +0 -1
- package/dist/pipe-api.d.ts +0 -163
- package/dist/pipe-api.d.ts.map +0 -1
- package/dist/pipe-api.js +0 -127
- package/dist/pipe-api.js.map +0 -1
- package/dist/scalars.d.ts +0 -12
- package/dist/scalars.d.ts.map +0 -1
- package/dist/scalars.js +0 -59
- package/dist/scalars.js.map +0 -1
- package/dist/types.d.ts +0 -89
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -41
- package/dist/types.js.map +0 -1
- package/src/directives.ts +0 -170
- package/src/entities.ts +0 -90
- package/src/federated-builder.ts +0 -593
- package/src/index.ts +0 -47
- package/src/pipe-api.ts +0 -263
- package/src/scalars.ts +0 -59
- package/src/types.ts +0 -114
package/src/pipe-api.ts
DELETED
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
import { Effect } from "effect"
|
|
2
|
-
import * as S from "effect/Schema"
|
|
3
|
-
import type { DirectiveApplication } from "@effect-gql/core"
|
|
4
|
-
import { FederatedSchemaBuilder } from "./federated-builder"
|
|
5
|
-
import type { EntityRegistration } from "./types"
|
|
6
|
-
|
|
7
|
-
// ============================================================================
|
|
8
|
-
// Entity Registration
|
|
9
|
-
// ============================================================================
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Register an entity type with @key directive(s) and reference resolver.
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* ```typescript
|
|
16
|
-
* FederatedSchemaBuilder.empty.pipe(
|
|
17
|
-
* entity({
|
|
18
|
-
* name: "User",
|
|
19
|
-
* schema: UserSchema,
|
|
20
|
-
* keys: [key({ fields: "id" })],
|
|
21
|
-
* resolveReference: (ref) => UserService.findById(ref.id),
|
|
22
|
-
* }),
|
|
23
|
-
* )
|
|
24
|
-
* ```
|
|
25
|
-
*/
|
|
26
|
-
export const entity =
|
|
27
|
-
<A, R>(config: EntityRegistration<A, R>) =>
|
|
28
|
-
<R2>(builder: FederatedSchemaBuilder<R2>): FederatedSchemaBuilder<R | R2> =>
|
|
29
|
-
builder.entity(config)
|
|
30
|
-
|
|
31
|
-
// ============================================================================
|
|
32
|
-
// Query/Mutation/Subscription
|
|
33
|
-
// ============================================================================
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Add a query field
|
|
37
|
-
*/
|
|
38
|
-
export const query =
|
|
39
|
-
<A, E, R, Args = void>(
|
|
40
|
-
name: string,
|
|
41
|
-
config: {
|
|
42
|
-
type: S.Schema<A, any, any>
|
|
43
|
-
args?: S.Schema<Args, any, any>
|
|
44
|
-
description?: string
|
|
45
|
-
directives?: readonly DirectiveApplication[]
|
|
46
|
-
resolve: (args: Args) => Effect.Effect<A, E, R>
|
|
47
|
-
}
|
|
48
|
-
) =>
|
|
49
|
-
<R2>(builder: FederatedSchemaBuilder<R2>): FederatedSchemaBuilder<R | R2> =>
|
|
50
|
-
builder.query(name, config)
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Add a mutation field
|
|
54
|
-
*/
|
|
55
|
-
export const mutation =
|
|
56
|
-
<A, E, R, Args = void>(
|
|
57
|
-
name: string,
|
|
58
|
-
config: {
|
|
59
|
-
type: S.Schema<A, any, any>
|
|
60
|
-
args?: S.Schema<Args, any, any>
|
|
61
|
-
description?: string
|
|
62
|
-
directives?: readonly DirectiveApplication[]
|
|
63
|
-
resolve: (args: Args) => Effect.Effect<A, E, R>
|
|
64
|
-
}
|
|
65
|
-
) =>
|
|
66
|
-
<R2>(builder: FederatedSchemaBuilder<R2>): FederatedSchemaBuilder<R | R2> =>
|
|
67
|
-
builder.mutation(name, config)
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Add a subscription field
|
|
71
|
-
*/
|
|
72
|
-
export const subscription =
|
|
73
|
-
<A, E, R, Args = void>(
|
|
74
|
-
name: string,
|
|
75
|
-
config: {
|
|
76
|
-
type: S.Schema<A, any, any>
|
|
77
|
-
args?: S.Schema<Args, any, any>
|
|
78
|
-
description?: string
|
|
79
|
-
directives?: readonly DirectiveApplication[]
|
|
80
|
-
subscribe: (args: Args) => Effect.Effect<import("effect").Stream.Stream<A, E, R>, E, R>
|
|
81
|
-
resolve?: (value: A, args: Args) => Effect.Effect<A, E, R>
|
|
82
|
-
}
|
|
83
|
-
) =>
|
|
84
|
-
<R2>(builder: FederatedSchemaBuilder<R2>): FederatedSchemaBuilder<R | R2> =>
|
|
85
|
-
builder.subscription(name, config)
|
|
86
|
-
|
|
87
|
-
// ============================================================================
|
|
88
|
-
// Type Registration
|
|
89
|
-
// ============================================================================
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Register an object type (non-entity)
|
|
93
|
-
*/
|
|
94
|
-
export const objectType =
|
|
95
|
-
<A>(config: {
|
|
96
|
-
name?: string
|
|
97
|
-
schema: S.Schema<A, any, any>
|
|
98
|
-
implements?: readonly string[]
|
|
99
|
-
directives?: readonly DirectiveApplication[]
|
|
100
|
-
}) =>
|
|
101
|
-
<R>(builder: FederatedSchemaBuilder<R>): FederatedSchemaBuilder<R> =>
|
|
102
|
-
builder.objectType(config)
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Register an interface type
|
|
106
|
-
*/
|
|
107
|
-
export const interfaceType =
|
|
108
|
-
(config: {
|
|
109
|
-
name?: string
|
|
110
|
-
schema: S.Schema<any, any, any>
|
|
111
|
-
resolveType?: (value: any) => string
|
|
112
|
-
directives?: readonly DirectiveApplication[]
|
|
113
|
-
}) =>
|
|
114
|
-
<R>(builder: FederatedSchemaBuilder<R>): FederatedSchemaBuilder<R> =>
|
|
115
|
-
builder.interfaceType(config)
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Register an enum type
|
|
119
|
-
*/
|
|
120
|
-
export const enumType =
|
|
121
|
-
(config: {
|
|
122
|
-
name: string
|
|
123
|
-
values: readonly string[]
|
|
124
|
-
description?: string
|
|
125
|
-
directives?: readonly DirectiveApplication[]
|
|
126
|
-
}) =>
|
|
127
|
-
<R>(builder: FederatedSchemaBuilder<R>): FederatedSchemaBuilder<R> =>
|
|
128
|
-
builder.enumType(config)
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Register a union type
|
|
132
|
-
*/
|
|
133
|
-
export const unionType =
|
|
134
|
-
(config: {
|
|
135
|
-
name: string
|
|
136
|
-
types: readonly string[]
|
|
137
|
-
resolveType?: (value: any) => string
|
|
138
|
-
directives?: readonly DirectiveApplication[]
|
|
139
|
-
}) =>
|
|
140
|
-
<R>(builder: FederatedSchemaBuilder<R>): FederatedSchemaBuilder<R> =>
|
|
141
|
-
builder.unionType(config)
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Register an input type
|
|
145
|
-
*/
|
|
146
|
-
export const inputType =
|
|
147
|
-
(config: {
|
|
148
|
-
name?: string
|
|
149
|
-
schema: S.Schema<any, any, any>
|
|
150
|
-
description?: string
|
|
151
|
-
directives?: readonly DirectiveApplication[]
|
|
152
|
-
}) =>
|
|
153
|
-
<R>(builder: FederatedSchemaBuilder<R>): FederatedSchemaBuilder<R> =>
|
|
154
|
-
builder.inputType(config)
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Add a computed/relational field to an object type
|
|
158
|
-
*/
|
|
159
|
-
export const field =
|
|
160
|
-
<Parent, A, E, R, Args = void>(
|
|
161
|
-
typeName: string,
|
|
162
|
-
fieldName: string,
|
|
163
|
-
config: {
|
|
164
|
-
type: S.Schema<A, any, any>
|
|
165
|
-
args?: S.Schema<Args, any, any>
|
|
166
|
-
description?: string
|
|
167
|
-
directives?: readonly DirectiveApplication[]
|
|
168
|
-
resolve: (parent: Parent, args: Args) => Effect.Effect<A, E, R>
|
|
169
|
-
}
|
|
170
|
-
) =>
|
|
171
|
-
<R2>(builder: FederatedSchemaBuilder<R2>): FederatedSchemaBuilder<R | R2> =>
|
|
172
|
-
builder.field(typeName, fieldName, config)
|
|
173
|
-
|
|
174
|
-
// ============================================================================
|
|
175
|
-
// Field-Level Federation Directive Helpers
|
|
176
|
-
// ============================================================================
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Create a field configuration with @external directive
|
|
180
|
-
*/
|
|
181
|
-
export const externalField = <A>(config: {
|
|
182
|
-
type: S.Schema<A, any, any>
|
|
183
|
-
description?: string
|
|
184
|
-
}): {
|
|
185
|
-
type: S.Schema<A, any, any>
|
|
186
|
-
description?: string
|
|
187
|
-
directives: readonly DirectiveApplication[]
|
|
188
|
-
resolve: (parent: any) => Effect.Effect<A, never, never>
|
|
189
|
-
} => ({
|
|
190
|
-
type: config.type,
|
|
191
|
-
description: config.description,
|
|
192
|
-
directives: [{ name: "external" }],
|
|
193
|
-
resolve: (parent: any) => Effect.succeed(parent),
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Create a field configuration with @requires directive
|
|
198
|
-
*/
|
|
199
|
-
export const requiresField = <A, E, R, Parent = any>(config: {
|
|
200
|
-
type: S.Schema<A, any, any>
|
|
201
|
-
fields: string
|
|
202
|
-
description?: string
|
|
203
|
-
resolve: (parent: Parent) => Effect.Effect<A, E, R>
|
|
204
|
-
}): {
|
|
205
|
-
type: S.Schema<A, any, any>
|
|
206
|
-
description?: string
|
|
207
|
-
directives: readonly DirectiveApplication[]
|
|
208
|
-
resolve: (parent: Parent) => Effect.Effect<A, E, R>
|
|
209
|
-
} => ({
|
|
210
|
-
type: config.type,
|
|
211
|
-
description: config.description,
|
|
212
|
-
directives: [{ name: "requires", args: { fields: config.fields } }],
|
|
213
|
-
resolve: config.resolve,
|
|
214
|
-
})
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Create a field configuration with @provides directive
|
|
218
|
-
*/
|
|
219
|
-
export const providesField = <A, E, R, Parent = any>(config: {
|
|
220
|
-
type: S.Schema<A, any, any>
|
|
221
|
-
fields: string
|
|
222
|
-
description?: string
|
|
223
|
-
resolve: (parent: Parent) => Effect.Effect<A, E, R>
|
|
224
|
-
}): {
|
|
225
|
-
type: S.Schema<A, any, any>
|
|
226
|
-
description?: string
|
|
227
|
-
directives: readonly DirectiveApplication[]
|
|
228
|
-
resolve: (parent: Parent) => Effect.Effect<A, E, R>
|
|
229
|
-
} => ({
|
|
230
|
-
type: config.type,
|
|
231
|
-
description: config.description,
|
|
232
|
-
directives: [{ name: "provides", args: { fields: config.fields } }],
|
|
233
|
-
resolve: config.resolve,
|
|
234
|
-
})
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Create a field configuration with @override directive
|
|
238
|
-
*/
|
|
239
|
-
export const overrideField = <A, E, R, Parent = any>(config: {
|
|
240
|
-
type: S.Schema<A, any, any>
|
|
241
|
-
from: string
|
|
242
|
-
label?: string
|
|
243
|
-
description?: string
|
|
244
|
-
resolve: (parent: Parent) => Effect.Effect<A, E, R>
|
|
245
|
-
}): {
|
|
246
|
-
type: S.Schema<A, any, any>
|
|
247
|
-
description?: string
|
|
248
|
-
directives: readonly DirectiveApplication[]
|
|
249
|
-
resolve: (parent: Parent) => Effect.Effect<A, E, R>
|
|
250
|
-
} => ({
|
|
251
|
-
type: config.type,
|
|
252
|
-
description: config.description,
|
|
253
|
-
directives: [
|
|
254
|
-
{
|
|
255
|
-
name: "override",
|
|
256
|
-
args: {
|
|
257
|
-
from: config.from,
|
|
258
|
-
...(config.label !== undefined ? { label: config.label } : {}),
|
|
259
|
-
},
|
|
260
|
-
},
|
|
261
|
-
],
|
|
262
|
-
resolve: config.resolve,
|
|
263
|
-
})
|
package/src/scalars.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { GraphQLScalarType, Kind, type ValueNode } from "@effect-gql/core"
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Parse a literal value from the AST to a JavaScript value
|
|
5
|
-
*/
|
|
6
|
-
function parseLiteralToValue(ast: ValueNode): unknown {
|
|
7
|
-
switch (ast.kind) {
|
|
8
|
-
case Kind.STRING:
|
|
9
|
-
case Kind.BOOLEAN:
|
|
10
|
-
return ast.value
|
|
11
|
-
case Kind.INT:
|
|
12
|
-
return parseInt(ast.value, 10)
|
|
13
|
-
case Kind.FLOAT:
|
|
14
|
-
return parseFloat(ast.value)
|
|
15
|
-
case Kind.NULL:
|
|
16
|
-
return null
|
|
17
|
-
case Kind.LIST:
|
|
18
|
-
return ast.values.map(parseLiteralToValue)
|
|
19
|
-
case Kind.OBJECT: {
|
|
20
|
-
const obj: Record<string, unknown> = {}
|
|
21
|
-
for (const field of ast.fields) {
|
|
22
|
-
obj[field.name.value] = parseLiteralToValue(field.value)
|
|
23
|
-
}
|
|
24
|
-
return obj
|
|
25
|
-
}
|
|
26
|
-
default:
|
|
27
|
-
return undefined
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* The _Any scalar is used for entity representations in the _entities query.
|
|
33
|
-
* It accepts any JSON value representing an entity with __typename and key fields.
|
|
34
|
-
*/
|
|
35
|
-
export const AnyScalar = new GraphQLScalarType({
|
|
36
|
-
name: "_Any",
|
|
37
|
-
description:
|
|
38
|
-
"The _Any scalar is used to pass representations of entities from external services.",
|
|
39
|
-
serialize: (value) => value,
|
|
40
|
-
parseValue: (value) => value,
|
|
41
|
-
parseLiteral: parseLiteralToValue,
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* The _FieldSet scalar represents a selection of fields.
|
|
46
|
-
* It's used in directive arguments like @key(fields: "id") and @requires(fields: "weight").
|
|
47
|
-
*/
|
|
48
|
-
export const FieldSetScalar = new GraphQLScalarType({
|
|
49
|
-
name: "_FieldSet",
|
|
50
|
-
description: "A string representing a selection of fields.",
|
|
51
|
-
serialize: (value) => value,
|
|
52
|
-
parseValue: (value) => value,
|
|
53
|
-
parseLiteral: (ast) => {
|
|
54
|
-
if (ast.kind === Kind.STRING) {
|
|
55
|
-
return ast.value
|
|
56
|
-
}
|
|
57
|
-
return undefined
|
|
58
|
-
},
|
|
59
|
-
})
|
package/src/types.ts
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import { Effect } from "effect"
|
|
2
|
-
import * as S from "effect/Schema"
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Configuration for a @key directive
|
|
6
|
-
*/
|
|
7
|
-
export interface KeyDirective {
|
|
8
|
-
/** FieldSet selection string (e.g., "id" or "sku package") */
|
|
9
|
-
readonly fields: string
|
|
10
|
-
/** Whether this key can be used to resolve the entity. Default: true */
|
|
11
|
-
readonly resolvable?: boolean
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* All Federation 2.x directive types
|
|
16
|
-
*/
|
|
17
|
-
export type FederationDirective =
|
|
18
|
-
| { readonly _tag: "key"; readonly fields: string; readonly resolvable?: boolean }
|
|
19
|
-
| { readonly _tag: "external" }
|
|
20
|
-
| { readonly _tag: "requires"; readonly fields: string }
|
|
21
|
-
| { readonly _tag: "provides"; readonly fields: string }
|
|
22
|
-
| { readonly _tag: "shareable" }
|
|
23
|
-
| { readonly _tag: "inaccessible" }
|
|
24
|
-
| { readonly _tag: "override"; readonly from: string; readonly label?: string }
|
|
25
|
-
| { readonly _tag: "interfaceObject" }
|
|
26
|
-
| { readonly _tag: "tag"; readonly name: string }
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Entity representation sent to _entities query
|
|
30
|
-
* Contains __typename plus the key fields
|
|
31
|
-
*/
|
|
32
|
-
export interface EntityRepresentation {
|
|
33
|
-
readonly __typename: string
|
|
34
|
-
readonly [key: string]: unknown
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Configuration for registering an entity type
|
|
39
|
-
*/
|
|
40
|
-
export interface EntityRegistration<A, R = never> {
|
|
41
|
-
/** Type name */
|
|
42
|
-
readonly name: string
|
|
43
|
-
/** Effect Schema for the entity type */
|
|
44
|
-
readonly schema: S.Schema<A, any, any>
|
|
45
|
-
/** Key directive configurations (at least one required) */
|
|
46
|
-
readonly keys: readonly KeyDirective[]
|
|
47
|
-
/** Additional directives to apply to the type */
|
|
48
|
-
readonly directives?: readonly FederationDirective[]
|
|
49
|
-
/**
|
|
50
|
-
* Reference resolver - given key fields, return the full entity.
|
|
51
|
-
* The representation contains __typename plus all fields from any matching @key.
|
|
52
|
-
*/
|
|
53
|
-
readonly resolveReference: (
|
|
54
|
-
representation: Partial<A> & { __typename: string }
|
|
55
|
-
) => Effect.Effect<A | null, any, R>
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Configuration for the FederatedSchemaBuilder
|
|
60
|
-
*/
|
|
61
|
-
export interface FederatedSchemaConfig {
|
|
62
|
-
/** Federation specification version (default: "2.3") */
|
|
63
|
-
readonly version?: string
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Result of building a federated schema
|
|
68
|
-
*/
|
|
69
|
-
export interface FederatedSchemaResult {
|
|
70
|
-
/** The GraphQL schema with Federation queries */
|
|
71
|
-
readonly schema: import("graphql").GraphQLSchema
|
|
72
|
-
/** The Federation-compliant SDL with directive annotations */
|
|
73
|
-
readonly sdl: string
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Convert a FederationDirective to a DirectiveApplication
|
|
78
|
-
*/
|
|
79
|
-
export function toDirectiveApplication(
|
|
80
|
-
directive: FederationDirective
|
|
81
|
-
): import("@effect-gql/core").DirectiveApplication {
|
|
82
|
-
switch (directive._tag) {
|
|
83
|
-
case "key":
|
|
84
|
-
return {
|
|
85
|
-
name: "key",
|
|
86
|
-
args: {
|
|
87
|
-
fields: directive.fields,
|
|
88
|
-
...(directive.resolvable !== undefined ? { resolvable: directive.resolvable } : {}),
|
|
89
|
-
},
|
|
90
|
-
}
|
|
91
|
-
case "external":
|
|
92
|
-
return { name: "external" }
|
|
93
|
-
case "requires":
|
|
94
|
-
return { name: "requires", args: { fields: directive.fields } }
|
|
95
|
-
case "provides":
|
|
96
|
-
return { name: "provides", args: { fields: directive.fields } }
|
|
97
|
-
case "shareable":
|
|
98
|
-
return { name: "shareable" }
|
|
99
|
-
case "inaccessible":
|
|
100
|
-
return { name: "inaccessible" }
|
|
101
|
-
case "override":
|
|
102
|
-
return {
|
|
103
|
-
name: "override",
|
|
104
|
-
args: {
|
|
105
|
-
from: directive.from,
|
|
106
|
-
...(directive.label !== undefined ? { label: directive.label } : {}),
|
|
107
|
-
},
|
|
108
|
-
}
|
|
109
|
-
case "interfaceObject":
|
|
110
|
-
return { name: "interfaceObject" }
|
|
111
|
-
case "tag":
|
|
112
|
-
return { name: "tag", args: { name: directive.name } }
|
|
113
|
-
}
|
|
114
|
-
}
|