@nxara/olio-codegen 0.0.0-stage → 0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nxara contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,239 @@
1
- # Temporary Holding Version
1
+ # @nxara/olio-codegen
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Generate TypeScript types from GraphQL SDL.
4
+
5
+ `@nxara/olio-codegen` discovers modules from a directory layout, reads each module's GraphQL SDL, and emits a single strongly typed TypeScript file: schema types, per-module operation contracts, and the application type.
6
+
7
+ It is deliberately small - SDL in, types out. Schema composition belongs to `@nxara/olio-schema`, the runtime to `@nxara/olio`.
8
+
9
+ ## Install
10
+
11
+ ```sh
12
+ bun add @nxara/olio-codegen graphql@16
13
+ ```
14
+
15
+ `graphql` 16 is a peer dependency (not 17, which is about 4× slower on small queries).
16
+
17
+ ## Usage
18
+
19
+ There is no bundled CLI; drive codegen from a short script:
20
+
21
+ ```ts
22
+ import { codegen } from "@nxara/olio-codegen";
23
+
24
+ await codegen({
25
+ root: import.meta.dirname,
26
+ modules: "src/modules",
27
+ typeDefs: "**/typedefs/**/*.gql",
28
+ output: "src/generated.ts"
29
+ });
30
+ ```
31
+
32
+ Relative paths (`modules`, `output`, `schemaOutput`) resolve against `root`, which defaults to the working directory; pass `import.meta.dirname` so the script runs the same from any folder. `typeDefs` is the exception: it resolves inside each module. `codegenClient` takes `root` the same way, for `schema` (unless it's a URL), `documents` and `output`.
33
+
34
+ Both reject with a message that names the file and position. Uncaught, the runtime prints it with a stack; to print just the message:
35
+
36
+ ```ts
37
+ await codegen({ ... }).catch((error: Error) => {
38
+ console.error(error.message);
39
+ process.exitCode = 1;
40
+ });
41
+ ```
42
+
43
+ `modules` points to a directory whose **direct child directories** are modules. `typeDefs` is resolved relative to each module directory. `codegen` discovers modules, loads and parses their SDL, generates TypeScript, and writes the output (creating parent directories as needed).
44
+
45
+ SDL files are read exactly as `loadTypeDefs` in `@nxara/olio-tools` reads them (both go through `@nxara/olio-core/files`): `.graphql` / `.gql`, or `.ts` / `.js` files whose default export is SDL or a `DocumentNode`, so an app moving from untyped to typed keeps its SDL where it is (`typeDefs: "**/typedefs/**/*.{gql,ts}"`). Codegen imports `.ts` files, so run it with something that executes TypeScript (bun, tsx, or Node 23.6+).
46
+
47
+ ### Directives
48
+
49
+ Pass `directives` to apply `@nxara/olio-schema` transformations before generation:
50
+
51
+ ```ts
52
+ import { codegen } from "@nxara/olio-codegen";
53
+ import { copyDirective, implementsDirective } from "@nxara/olio-schema";
54
+
55
+ await codegen({
56
+ modules: "src/modules",
57
+ typeDefs: "**/typedefs/**/*.gql",
58
+ output: "src/generated.ts",
59
+ schemaOutput: "src/schema.graphql",
60
+ directives: [implementsDirective(), copyDirective()]
61
+ });
62
+ ```
63
+
64
+ Their names land in `Application` as `"~directives"`, and olio's types then require the same `directives` in `olio()`.
65
+
66
+ Set `schemaOutput` to write the final schema to a file, printed from the built schema: each type once with its extensions merged in, the directives applied, ready for schema registries, linters and diff tools. Omit it to generate only TypeScript. The schema is validated before anything is written, so an invalid one fails codegen rather than the server.
67
+
68
+ ## Client types
69
+
70
+ `codegenClient({ schema, documents, output })` generates the types for [`@nxara/olio-client`](../client), the way graphql-codegen does: `schema` is an SDL file (typically the `schemaOutput` file above) or the running server's URL, introspected (`headers` for one that needs a token); `documents` are the client's `.graphql` operations. The operations are checked against the schema first, with `file:line:column` errors. `watch: true` reruns when an operation (including a new file) or the schema file changes; a server URL isn't watched.
71
+
72
+ Subscriptions go over WebSocket unless marked `@sse` (`subscription Feed @sse { … }`); `@ws` says the default explicitly. The directive is the client's: codegen records it in the document and removes it from the query the server receives, and imports only the transports the operations use. `@ws` / `@sse` on a query or mutation, both on one subscription, or with arguments, is an error.
73
+
74
+ Per operation it emits the result type, the variables type and a typed document (`LoginMutation`, `LoginMutationVariables`, `LoginDocument`), plus `operations` for `createClient`. Types are what a client sees on the wire: enums by name, scalars through `ClientScalars`.
75
+
76
+ ```ts
77
+ import { codegenClient } from "@nxara/olio-codegen";
78
+
79
+ await codegenClient({
80
+ root: import.meta.dirname,
81
+ schema: "../server/src/schema.gql", // or "http://localhost:4000/graphql"
82
+ documents: "src/operations/*.graphql",
83
+ output: "src/generated.ts"
84
+ });
85
+ ```
86
+
87
+ ## Modules
88
+
89
+ Every direct child directory of `modules` is one module. The directory name is the module ID, and there are no nested modules:
90
+
91
+ ```
92
+ src/modules/
93
+ ├── auth/
94
+ │ ├── typedefs/auth.gql
95
+ │ └── query.ts
96
+ ├── user/
97
+ │ └── typedefs/user.gql
98
+ └── sales/
99
+ ├── typedefs/sales.gql
100
+ └── orders/
101
+ └── typedefs/orders.gql
102
+ ```
103
+
104
+ This yields modules `auth`, `user`, and `sales`. `typeDefs` resolves inside each module (`src/modules/auth/**/typedefs/**/*.gql`, and so on), so each module's files belong exclusively to that module.
105
+
106
+ A direct subfolder of a module in which `typeDefs` finds files of its own is a **feature** of that module: here `sales/orders`, with its own entry in `Application` (`"sales/orders"`). Features don't nest.
107
+
108
+ So the glob decides what is a feature, because codegen runs it inside each subfolder. `**/typedefs/**/*.gql` finds nothing inside `users/typedefs/` itself (there's no `typedefs/` in it), so that folder stays the module's own SDL. `**/*.gql` does find its files, so it makes `typedefs` a feature of every module (`"users/typedefs"`), and `users` ends up with no fields. Keep SDL in `typedefs/` folders and use `**/typedefs/**/*.gql`. The ID is used as-is as the module's key in `Application` (quoted when it is not a valid identifier).
109
+
110
+ ## Application
111
+
112
+ `Application` lists, per module, the types it declares fields on. Register it with `@nxara/olio`, which derives resolver signatures and middleware targets from it:
113
+
114
+ ```ts
115
+ export type Application = {
116
+ users: {
117
+ Query: {
118
+ type: Query;
119
+ fields: "user" | "users";
120
+ args: {
121
+ user: { id: string };
122
+ };
123
+ };
124
+ User: { type: User; fields: "__isTypeOf" | "id" | "name" };
125
+ };
126
+ posts: {
127
+ Post: { type: Post; fields: "__isTypeOf" | "id" };
128
+ User: { type: User; fields: "posts" }; // from `extend type User { posts: [Post!]! }`
129
+ };
130
+ };
131
+ ```
132
+
133
+ - **`type`** is the parent type. Resolvers receive it as `root` and return `type[field]`.
134
+ - **`fields`** are the fields the module owns. A module owns every field it declares, whether in a definition or an `extend`, on root and non-root types alike. The defining module also owns `__isTypeOf` (objects) or `__resolveType` (interfaces and unions, which also list their possible types as `resolveType`).
135
+ - **`args`** appears only for fields that take arguments.
136
+ - **Enums** appear as `{ type; fields: never; enum: "A" | "B" }`, listing the values the module declares (an `extend enum` belongs to the extending module).
137
+ - **Scalars** appear as `{ type; fields: never; scalar: true }` under the module that defines them, which supplies the implementation.
138
+ - **`bypass`** lists, per owned field, the keys its `@bypass` gives it (`bypass: { login: "audit" | "auth" }`). olio types middleware's `bypass` set from every key listed here.
139
+ - **`root`** marks a root type with its operation (`root: "query"`), so olio finds the roots whatever they're named. A hand-written `Application` needs it too.
140
+
141
+ Middleware targets aren't emitted: a module's targets are its owned fields, and the application's are the root fields.
142
+
143
+ ## Supported SDL
144
+
145
+ - Object types, interfaces, unions, enums, inputs, and scalars
146
+ - Lists and nullability (`String`, `[String!]!`, …), mapped exactly
147
+ - Type extensions (`extend type User { … }`)
148
+ - Root operation types, under the default names or your own (`schema { query: RootQuery }`)
149
+
150
+ A schema type can't be named `Application`, `Maybe`, `ResolveEnum`, `ResolveScalar` or `Scalars`, since the generated file declares those names itself.
151
+
152
+ ## Custom scalars
153
+
154
+ Every scalar goes through one exported table, `Scalars`, so fields read `Scalars["DateTime"]["output"]`. Built-in scalars default to their usual TypeScript types (`ID`/`String` → `string`, `Int`/`Float` → `number`, `Boolean` → `boolean`), and custom scalars default to `unknown`. Register or remap any of them by augmenting `CustomScalars`:
155
+
156
+ ```ts
157
+ declare module "@nxara/olio-codegen" {
158
+ interface CustomScalars {
159
+ DateTime: Date;
160
+ JSON: { input: string; output: unknown };
161
+ ID: string | ObjectId; // built-ins can be remapped too
162
+ }
163
+ }
164
+ ```
165
+
166
+ Use the table directly when you need a scalar's type: `Scalars["DateTime"]["input"]`.
167
+
168
+ Like every registration, it goes in a `.ts` file, or a `.d.ts` with an `import` or `export {}`.
169
+
170
+ ## Enums with internal values
171
+
172
+ Enums are their GraphQL names by default (`"ADMIN" | "GUEST"`). To store something else, such as a number or a lowercase string, register the internal type by augmenting `CustomEnums`:
173
+
174
+ ```ts
175
+ declare module "@nxara/olio-codegen" {
176
+ interface CustomEnums {
177
+ OrderStatus: "confirmed" | "cancelled";
178
+ }
179
+ }
180
+ ```
181
+
182
+ Every generated position then uses it: object fields, arguments, and inputs, since graphql converts enum inputs to internal values too. Supply the values at runtime through the owning module's `enums` option. Once `CustomEnums` registers an enum, olio's types require it there, with a value for every value the module declares:
183
+
184
+ ```ts
185
+ export const sales = module.sales({
186
+ typeDefs,
187
+ resolvers,
188
+ enums: { OrderStatus: { CONFIRMED: "confirmed", CANCELLED: "cancelled" } }
189
+ });
190
+ ```
191
+
192
+ To keep a map in its own file, write it with the typed builder: `export const OrderStatus = resolvers.sales.OrderStatus({ ... })`, then `enums: { OrderStatus }`, or load such files with `enums: await loadEnums(...)` from `@nxara/olio-tools` (unchecked, like `loadResolvers`).
193
+
194
+ ## Output
195
+
196
+ `codegen` writes a single TypeScript file to `output`. For:
197
+
198
+ ```graphql
199
+ type Query {
200
+ user: User
201
+ }
202
+ type User {
203
+ id: ID!
204
+ name: String
205
+ }
206
+ ```
207
+
208
+ the emitted `User` type is:
209
+
210
+ ```ts
211
+ export type User = {
212
+ __typename?: "User";
213
+ id: Scalars["ID"]["output"];
214
+ name: Maybe<Scalars["String"]["output"]>;
215
+ };
216
+ ```
217
+
218
+ The full output contains:
219
+
220
+ - the `Scalars` table
221
+ - enums as `const` objects plus union types
222
+ - object types (root types included), interfaces, inputs, and unions. Nullable inputs without a default are optional keys.
223
+ - the `Application` type
224
+
225
+ The header marks the file as generated:
226
+
227
+ ```ts
228
+ // Generated by @nxara/olio-codegen - do not edit.
229
+ ```
230
+
231
+ ## Relationship to @nxara/olio-schema
232
+
233
+ `@nxara/olio-schema` composes a schema into ordinary GraphQL; `@nxara/olio-codegen` then turns that GraphQL into TypeScript:
234
+
235
+ ```
236
+ SDL → @nxara/olio-schema → DocumentNode → @nxara/olio-codegen → TypeScript
237
+ ```
238
+
239
+ Codegen has no knowledge of `@implements` or `@copy` - it accepts `SchemaDirective[]` and passes the parsed document through the transformation pipeline.
@@ -0,0 +1,10 @@
1
+ import { type DocumentNode, type GraphQLSchema } from "graphql";
2
+ import { type CodegenModule, type GenerateOptions } from "./types.js";
3
+ export interface Compiled {
4
+ document: DocumentNode;
5
+ code: string;
6
+ schema: GraphQLSchema;
7
+ }
8
+ export declare function compile(modules: readonly CodegenModule[], options?: GenerateOptions): Compiled;
9
+ export declare function generate(modules: readonly CodegenModule[], options?: GenerateOptions): string;
10
+ //# sourceMappingURL=codegen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../src/codegen.ts"],"names":[],"mappings":"AACA,OAAO,EASL,KAAK,YAAY,EACjB,KAAK,aAAa,EACnB,MAAM,SAAS,CAAC;AAWjB,OAAO,EAIL,KAAK,aAAa,EAClB,KAAK,eAAe,EAErB,MAAM,YAAY,CAAC;AAYpB,MAAM,WAAW,QAAQ;IAEvB,QAAQ,EAAE,YAAY,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,aAAa,CAAC;CACvB;AA8CD,wBAAgB,OAAO,CACrB,OAAO,EAAE,SAAS,aAAa,EAAE,EACjC,OAAO,GAAE,eAAoB,GAC5B,QAAQ,CAyCV;AAED,wBAAgB,QAAQ,CACtB,OAAO,EAAE,SAAS,aAAa,EAAE,EACjC,OAAO,GAAE,eAAoB,GAC5B,MAAM,CAER"}
@@ -0,0 +1,77 @@
1
+ import { compose } from "@nxara/olio-schema";
2
+ import { isEnumType, isInputObjectType, isInterfaceType, isObjectType, isScalarType, isUnionType, parse, Source } from "graphql";
3
+ import { emitApplication } from "./emit-application.js";
4
+ import { emitEnum, emitInput, emitInterface, emitObject, emitUnion, region } from "./emit-type.js";
5
+ import { BUILTIN_SCALARS, HEADER, RESERVED_NAMES } from "./types.js";
6
+ const IMPORTS = 'import type { ResolveEnum, ResolveScalar } from "@nxara/olio-codegen";';
7
+ const UTILS = "type Maybe<T> = T | null;";
8
+ function toDocument(typeDef, name) {
9
+ return typeof typeDef === "string"
10
+ ? parse(new Source(typeDef, name))
11
+ : typeDef;
12
+ }
13
+ const FUNCTION_PROPS = new Set([
14
+ "apply",
15
+ "arguments",
16
+ "bind",
17
+ "call",
18
+ "caller",
19
+ "length",
20
+ "name",
21
+ "prototype",
22
+ "toString"
23
+ ]);
24
+ function assertFeatureNames(ownership) {
25
+ for (const id of ownership.keys()) {
26
+ const [module = "", feature] = id.split("/");
27
+ if (feature === undefined)
28
+ continue;
29
+ const clash = FUNCTION_PROPS.has(feature)
30
+ ? "a reserved name"
31
+ : ownership.get(module)?.has(feature)
32
+ ? `type "${feature}" in module "${module}"`
33
+ : undefined;
34
+ if (clash) {
35
+ throw new Error(`Feature folder "${id}" clashes with ${clash}; rename the folder`);
36
+ }
37
+ }
38
+ }
39
+ function assertSupported(schema) {
40
+ for (const name of Object.keys(schema.getTypeMap())) {
41
+ if (RESERVED_NAMES.has(name)) {
42
+ throw new Error(`Type name "${name}" is reserved by the generated file; rename it`);
43
+ }
44
+ }
45
+ }
46
+ export function compile(modules, options = {}) {
47
+ const { document, schema, ownership, roots, bypass } = compose(modules.map((m) => ({
48
+ id: m.id,
49
+ typeDefs: (Array.isArray(m.typeDefs) ? m.typeDefs : [m.typeDefs]).map((d) => toDocument(d, m.id))
50
+ })), options.directives);
51
+ assertSupported(schema);
52
+ assertFeatureNames(ownership);
53
+ const types = Object.values(schema.getTypeMap())
54
+ .filter((t) => !t.name.startsWith("__") && !BUILTIN_SCALARS.has(t.name))
55
+ .sort((a, b) => a.name.localeCompare(b.name));
56
+ const scalars = Object.values(schema.getTypeMap())
57
+ .filter(isScalarType)
58
+ .map((t) => ` ${t.name}: ResolveScalar<"${t.name}">;`)
59
+ .sort();
60
+ const parts = [
61
+ HEADER,
62
+ IMPORTS,
63
+ UTILS,
64
+ `/** Every scalar's TypeScript types. Remap one through \`CustomScalars\`. */\nexport type Scalars = {\n${scalars.join("\n")}\n};`,
65
+ region("Enums", types.filter(isEnumType).map(emitEnum)),
66
+ region("Types", types.filter(isObjectType).map(emitObject)),
67
+ region("Inputs", types.filter(isInputObjectType).map(emitInput)),
68
+ region("Unions", types.filter(isUnionType).map(emitUnion)),
69
+ region("Interfaces", types.filter(isInterfaceType).map(emitInterface)),
70
+ emitApplication(schema, ownership, roots, bypass, (options.directives ?? []).map((d) => d.name))
71
+ ];
72
+ return { document, code: `${parts.join("\n\n")}\n`, schema };
73
+ }
74
+ export function generate(modules, options = {}) {
75
+ return compile(modules, options).code;
76
+ }
77
+ //# sourceMappingURL=codegen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codegen.js","sourceRoot":"","sources":["../src/codegen.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { Bypass, Ownership, RootTypes } from "@nxara/olio-schema";
2
+ import { type GraphQLSchema } from "graphql";
3
+ export declare function emitApplication(schema: GraphQLSchema, ownership: Ownership, roots: RootTypes, bypass: Bypass, directives: readonly string[]): string;
4
+ //# sourceMappingURL=emit-application.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-application.d.ts","sourceRoot":"","sources":["../src/emit-application.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACvE,OAAO,EAKL,KAAK,aAAa,EACnB,MAAM,SAAS,CAAC;AAqEjB,wBAAgB,eAAe,CAC7B,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,SAAS,MAAM,EAAE,GAC5B,MAAM,CAqBR"}
@@ -0,0 +1,66 @@
1
+ import { isAbstractType, isEnumType, isObjectType, isScalarType } from "graphql";
2
+ import { inputMember } from "./type-map.js";
3
+ const IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
4
+ const moduleKey = (id) => IDENTIFIER.test(id) ? id : JSON.stringify(id);
5
+ const union = (names) => names.length ? names.map((n) => `"${n}"`).join(" | ") : "never";
6
+ function emitEntry(schema, operations, bypass, name, owned) {
7
+ const type = schema.getType(name);
8
+ const fields = [...owned].sort();
9
+ if (isEnumType(type)) {
10
+ return ` ${name}: { type: ${name}; fields: never; enum: ${union(fields)} };`;
11
+ }
12
+ if (isScalarType(type)) {
13
+ return ` ${name}: { type: Scalars["${name}"]["output"]; fields: never; scalar: true };`;
14
+ }
15
+ const members = [`type: ${name}`, `fields: ${union(fields)}`];
16
+ const operation = operations.get(name);
17
+ if (operation)
18
+ members.push(`root: "${operation}"`);
19
+ if (isAbstractType(type)) {
20
+ members.push(`resolveType: ${union(schema
21
+ .getPossibleTypes(type)
22
+ .map((t) => t.name)
23
+ .sort())}`);
24
+ }
25
+ const objectFields = isObjectType(type) ? type.getFields() : {};
26
+ const args = fields.flatMap((f) => {
27
+ const field = objectFields[f];
28
+ return field?.args.length
29
+ ? [` ${f}: { ${field.args.map(inputMember).join("; ")} };`]
30
+ : [];
31
+ });
32
+ const bypassed = fields.flatMap((f) => {
33
+ const keys = bypass.get(`${name}.${f}`);
34
+ return keys ? [` ${f}: ${union([...keys].sort())};`] : [];
35
+ });
36
+ const sections = [
37
+ ...(args.length ? [" args: {", ...args, " };"] : []),
38
+ ...(bypassed.length ? [" bypass: {", ...bypassed, " };"] : [])
39
+ ];
40
+ if (sections.length === 0)
41
+ return ` ${name}: { ${members.join("; ")} };`;
42
+ return [
43
+ ` ${name}: {`,
44
+ ...members.map((m) => ` ${m};`),
45
+ ...sections,
46
+ " };"
47
+ ].join("\n");
48
+ }
49
+ export function emitApplication(schema, ownership, roots, bypass, directives) {
50
+ const operations = new Map(Object.entries(roots).map(([operation, name]) => [name, operation]));
51
+ const modules = [...ownership]
52
+ .sort(([a], [b]) => a.localeCompare(b))
53
+ .map(([id, types]) => {
54
+ const entries = [...types]
55
+ .sort(([a], [b]) => a.localeCompare(b))
56
+ .map(([name, owned]) => emitEntry(schema, operations, bypass, name, owned));
57
+ return entries.length
58
+ ? ` ${moduleKey(id)}: {\n${entries.join("\n")}\n };`
59
+ : ` ${moduleKey(id)}: {};`;
60
+ });
61
+ const used = directives.length
62
+ ? [` "~directives": ${directives.map((d) => `"${d}"`).join(" | ")};`]
63
+ : [];
64
+ return `export type Application = {\n${[...used, ...modules].join("\n")}\n};`;
65
+ }
66
+ //# sourceMappingURL=emit-application.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-application.js","sourceRoot":"","sources":["../src/emit-application.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type DocumentNode, type GraphQLSchema } from "graphql";
2
+ export declare function emitClient(schema: GraphQLSchema, documents: readonly DocumentNode[]): string;
3
+ //# sourceMappingURL=emit-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-client.d.ts","sourceRoot":"","sources":["../src/emit-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAcL,KAAK,YAAY,EAUjB,KAAK,aAAa,EAGnB,MAAM,SAAS,CAAC;AAiUjB,wBAAgB,UAAU,CACxB,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,SAAS,YAAY,EAAE,GACjC,MAAM,CAmGR"}