@leaven-graphql/nestjs 0.1.0 → 0.2.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.
@@ -1,9 +1,10 @@
1
1
  /**
2
2
  * @leaven-graphql/nestjs - Decorators
3
3
  *
4
- * Copyright 2026 Pegasus Heavy Industries LLC
4
+ * Copyright 2026 Joseph Quinn
5
5
  * Licensed under the Apache License, Version 2.0
6
6
  */
7
+ import { type ExecutionContext } from '@nestjs/common';
7
8
  /**
8
9
  * Metadata key for resolver complexity
9
10
  */
@@ -24,6 +25,12 @@ export declare const CACHE_KEY = "leaven:cache";
24
25
  * Metadata key for subscription filter
25
26
  */
26
27
  export declare const SUBSCRIPTION_FILTER_KEY = "leaven:subscription:filter";
28
+ /**
29
+ * Extractor backing the {@link Context} decorator.
30
+ *
31
+ * @internal Exported for testing only.
32
+ */
33
+ export declare function contextExtractor(data: string | undefined, ctx: ExecutionContext): unknown;
27
34
  /**
28
35
  * Inject the GraphQL context
29
36
  *
@@ -35,7 +42,13 @@ export declare const SUBSCRIPTION_FILTER_KEY = "leaven:subscription:filter";
35
42
  * }
36
43
  * ```
37
44
  */
38
- export declare const Context: (...dataOrPipes: (string | import("@nestjs/common").PipeTransform<any, any> | import("@nestjs/common").Type<import("@nestjs/common").PipeTransform<any, any>>)[]) => ParameterDecorator;
45
+ export declare const Context: (...dataOrPipes: (string | import("@nestjs/common").PipeTransform<any, any> | import("@nestjs/common").Type<import("@nestjs/common").PipeTransform<any, any>> | undefined)[]) => ParameterDecorator;
46
+ /**
47
+ * Extractor backing the {@link Info} decorator.
48
+ *
49
+ * @internal Exported for testing only.
50
+ */
51
+ export declare function infoExtractor(_data: unknown, ctx: ExecutionContext): unknown;
39
52
  /**
40
53
  * Inject the GraphQL info object
41
54
  *
@@ -48,6 +61,12 @@ export declare const Context: (...dataOrPipes: (string | import("@nestjs/common"
48
61
  * ```
49
62
  */
50
63
  export declare const Info: (...dataOrPipes: unknown[]) => ParameterDecorator;
64
+ /**
65
+ * Extractor backing the {@link Root} decorator.
66
+ *
67
+ * @internal Exported for testing only.
68
+ */
69
+ export declare function rootExtractor(_data: unknown, ctx: ExecutionContext): unknown;
51
70
  /**
52
71
  * Inject the root/parent value
53
72
  *
@@ -64,6 +83,12 @@ export declare const Root: (...dataOrPipes: unknown[]) => ParameterDecorator;
64
83
  * Alias for Root decorator
65
84
  */
66
85
  export declare const Parent: (...dataOrPipes: unknown[]) => ParameterDecorator;
86
+ /**
87
+ * Extractor backing the {@link Args} decorator.
88
+ *
89
+ * @internal Exported for testing only.
90
+ */
91
+ export declare function argsExtractor(data: string | undefined, ctx: ExecutionContext): unknown;
67
92
  /**
68
93
  * Inject resolver arguments
69
94
  *
@@ -75,7 +100,7 @@ export declare const Parent: (...dataOrPipes: unknown[]) => ParameterDecorator;
75
100
  * }
76
101
  * ```
77
102
  */
78
- export declare const Args: (...dataOrPipes: (string | import("@nestjs/common").PipeTransform<any, any> | import("@nestjs/common").Type<import("@nestjs/common").PipeTransform<any, any>>)[]) => ParameterDecorator;
103
+ export declare const Args: (...dataOrPipes: (string | import("@nestjs/common").PipeTransform<any, any> | import("@nestjs/common").Type<import("@nestjs/common").PipeTransform<any, any>> | undefined)[]) => ParameterDecorator;
79
104
  /**
80
105
  * Set complexity for a resolver
81
106
  *
@@ -104,6 +129,13 @@ export interface ComplexityEstimatorArgs {
104
129
  /**
105
130
  * Mark a field as deprecated
106
131
  *
132
+ * @remarks
133
+ * Records the reason under {@link DEPRECATED_KEY}. `SchemaBuilderService`
134
+ * reads it off the resolver functions passed via the `resolvers` option and
135
+ * sets the matching field's `deprecationReason`, so the field is marked
136
+ * `@deprecated` in the emitted schema. A pre-built `schema` is used as
137
+ * given, so annotate its fields there instead.
138
+ *
107
139
  * @example
108
140
  * ```typescript
109
141
  * @Query(() => String)
@@ -117,6 +149,13 @@ export declare function Deprecated(reason: string): MethodDecorator;
117
149
  /**
118
150
  * Add description to a field
119
151
  *
152
+ * @remarks
153
+ * Records the text under {@link DESCRIPTION_KEY}. `SchemaBuilderService`
154
+ * reads it off the resolver functions passed via the `resolvers` option and
155
+ * sets the matching field's description, so the text appears in the emitted
156
+ * schema and in introspection. A pre-built `schema` is used as given, so
157
+ * describe its fields there instead.
158
+ *
120
159
  * @example
121
160
  * ```typescript
122
161
  * @Query(() => User)
@@ -130,6 +169,11 @@ export declare function Description(text: string): MethodDecorator;
130
169
  /**
131
170
  * Enable caching for a resolver
132
171
  *
172
+ * @deprecated Has no effect; removal target 0.3.0. The hint is only applied by
173
+ * `CachingInterceptor`, which requires `info.cacheControl` — an Apollo Server
174
+ * construct that Leaven never attaches to `GraphQLResolveInfo`. The metadata is
175
+ * recorded under {@link CACHE_KEY} but nothing in the library reads it.
176
+ *
133
177
  * @example
134
178
  * ```typescript
135
179
  * @Query(() => Settings)
@@ -153,9 +197,50 @@ export interface CacheHintOptions {
153
197
  */
154
198
  scope?: 'PUBLIC' | 'PRIVATE';
155
199
  }
200
+ /**
201
+ * Yield only the source events a predicate accepts.
202
+ *
203
+ * Cancelling the returned iterator cancels the source, because `for await`
204
+ * calls `return()` on the source when the loop completes abruptly — including
205
+ * when the consumer cancels this generator. No extra teardown is performed:
206
+ * a second `return()` would both replace any in-flight error with a cleanup
207
+ * error and, for shared engines, release a topic subscription twice.
208
+ *
209
+ * A predicate that throws drops the offending event and is reported to
210
+ * `console.error` rather than tearing down the whole subscription.
211
+ *
212
+ * @internal Shared by {@link SubscriptionFilter} and the `filter` option of
213
+ * the `Subscription` decorator.
214
+ */
215
+ export declare function filterAsyncIterator<T>(source: AsyncIterable<T>, predicate: (payload: T) => boolean | Promise<boolean>): AsyncGenerator<T>;
216
+ /**
217
+ * Replace a method descriptor with one that filters the async iterable the
218
+ * original method produces.
219
+ *
220
+ * The wrapper is deliberately synchronous: when the original method returns
221
+ * an async iterable directly, so does the wrapper, so a direct caller can
222
+ * still write `for await (const x of resolver.messageAdded())`. Only when the
223
+ * original returns a promise does the wrapper return one.
224
+ *
225
+ * @internal Shared by {@link SubscriptionFilter} and the `filter` option of
226
+ * the `Subscription` decorator, so a correctness fix lands in one place.
227
+ */
228
+ export declare function wrapWithFilter(descriptor: PropertyDescriptor, filter: (payload: unknown, variables: unknown, context: unknown) => boolean | Promise<boolean>): void;
156
229
  /**
157
230
  * Add filter to subscription
158
231
  *
232
+ * Wraps the decorated method so the async iterator it returns yields only
233
+ * the events the predicate accepts. The predicate receives the published
234
+ * payload along with the resolver's arguments and context, and may be
235
+ * asynchronous. Rejected events are dropped without reaching the client.
236
+ *
237
+ * The wrapper preserves the original method's return kind: an async iterable
238
+ * stays an async iterable (so direct callers can `for await` it), and a
239
+ * promise stays a promise.
240
+ *
241
+ * The predicate is also recorded under {@link SUBSCRIPTION_FILTER_KEY} so a
242
+ * schema builder can inspect it.
243
+ *
159
244
  * @example
160
245
  * ```typescript
161
246
  * @Subscription(() => Comment)
@@ -190,6 +275,10 @@ export declare function Decorators(...decorators: MethodDecorator[]): MethodDeco
190
275
  /**
191
276
  * Create a custom context decorator
192
277
  *
278
+ * The underlying param decorator is built once per created decorator, not on
279
+ * every application, so applying the returned decorator at many call sites
280
+ * reuses a single factory.
281
+ *
193
282
  * @example
194
283
  * ```typescript
195
284
  * export const CurrentUser = createContextDecorator<User>('user');
@@ -1 +1 @@
1
- {"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH;;GAEG;AACH,eAAO,MAAM,cAAc,sBAAsB,CAAC;AAElD;;GAEG;AACH,eAAO,MAAM,cAAc,sBAAsB,CAAC;AAElD;;GAEG;AACH,eAAO,MAAM,eAAe,uBAAuB,CAAC;AAEpD;;GAEG;AACH,eAAO,MAAM,SAAS,iBAAiB,CAAC;AAExC;;GAEG;AACH,eAAO,MAAM,uBAAuB,+BAA+B,CAAC;AAEpE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,OAAO,yLAUnB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,IAAI,mDAKhB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,IAAI,mDAKhB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,MAAM,mDAAO,CAAC;AAE3B;;;;;;;;;;GAUG;AACH,eAAO,MAAM,IAAI,yLAWhB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,mBAAmB,GAAG,eAAe,CAE/E;AAED;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,EAAE,uBAAuB,KAAK,MAAM,CAAC;AAE/E;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,CAE1D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAEzD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAEpE;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,KAAK,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC9B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAC7F,eAAe,CAEjB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,UAAU,CAAC,GAAG,UAAU,EAAE,eAAe,EAAE,GAAG,eAAe,CAE5E;AAYD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,kBAAkB,CAM/E"}
1
+ {"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"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"}
package/dist/driver.d.ts CHANGED
@@ -1,18 +1,18 @@
1
1
  /**
2
2
  * @leaven-graphql/nestjs - Leaven Driver for NestJS GraphQL
3
3
  *
4
- * Copyright 2026 Pegasus Heavy Industries LLC
4
+ * Copyright 2026 Joseph Quinn
5
5
  * Licensed under the Apache License, Version 2.0
6
6
  */
7
7
  import { type OnModuleInit, type OnModuleDestroy } from '@nestjs/common';
8
- import type { GraphQLSchema, DocumentNode } from 'graphql';
8
+ import { type GraphQLSchema, type DocumentNode } from 'graphql';
9
9
  import { LeavenExecutor } from '@leaven-graphql/core';
10
10
  import type { LeavenModuleOptions, GqlContext, GraphQLFormattedError } from './types';
11
11
  /**
12
12
  * Request handler result
13
13
  */
14
- export interface HandlerResult {
15
- data?: Record<string, unknown> | null;
14
+ export interface HandlerResult<TData = Record<string, unknown>> {
15
+ data?: TData | null;
16
16
  errors?: readonly GraphQLFormattedError[];
17
17
  extensions?: Record<string, unknown>;
18
18
  }
@@ -26,6 +26,13 @@ export declare class LeavenDriver implements OnModuleInit, OnModuleDestroy {
26
26
  private executor;
27
27
  private schema;
28
28
  private readonly options;
29
+ /** Maximum number of memoized query analyses retained */
30
+ private static readonly MAX_ANALYSIS_ENTRIES;
31
+ /**
32
+ * LRU of {@link QueryAnalysis} keyed by query string and operation name.
33
+ * Cleared whenever the schema changes, since complexity is schema-dependent.
34
+ */
35
+ private readonly analysisCache;
29
36
  constructor(options: LeavenModuleOptions);
30
37
  /**
31
38
  * Initialize the driver with a schema
@@ -33,6 +40,11 @@ export declare class LeavenDriver implements OnModuleInit, OnModuleDestroy {
33
40
  onModuleInit(): Promise<void>;
34
41
  /**
35
42
  * Cleanup resources on module destroy
43
+ *
44
+ * `LeavenExecutor.clearCaches()` is genuinely asynchronous for a remote
45
+ * cache (Redis `FLUSH`), so it is awaited: dropping the promise would both
46
+ * leave the clear unfinished and turn a rejecting cache into an unhandled
47
+ * rejection during shutdown.
36
48
  */
37
49
  onModuleDestroy(): Promise<void>;
38
50
  /**
@@ -49,18 +61,61 @@ export declare class LeavenDriver implements OnModuleInit, OnModuleDestroy {
49
61
  getExecutor(): LeavenExecutor | null;
50
62
  /**
51
63
  * Initialize the Leaven executor
64
+ *
65
+ * Every option the executor understands is forwarded here. In particular
66
+ * `introspection` and `maxDepth` are *enforced by the executor* — the former
67
+ * by validating with `NoSchemaIntrospectionCustomRule`, the latter by
68
+ * rejecting over-deep documents at parse time — so omitting either would
69
+ * leave a documented option silently inert.
52
70
  */
53
71
  private initializeExecutor;
54
72
  /**
55
73
  * Execute a GraphQL request
74
+ *
75
+ * When `maxComplexity` or `maxDepth` is configured, the query is statically
76
+ * analyzed before execution and its complexity and depth are recorded on the
77
+ * provided context as `_queryComplexity` and `_queryDepth`, the keys read by
78
+ * `ComplexityGuard` and `DepthGuard`. With neither limit configured the
79
+ * analysis is skipped — see {@link attachQueryAnalysis}.
56
80
  */
57
81
  execute<TData = Record<string, unknown>>(query: string | DocumentNode, variables?: Record<string, unknown>, context?: GqlContext, operationName?: string): Promise<HandlerResult>;
82
+ /**
83
+ * Turn an error thrown out of the executor into a response error.
84
+ *
85
+ * Leaven errors keep their code, extensions, and message as-is. Unexpected
86
+ * errors are masked only in production — masking them in development would
87
+ * hide the real message from the developer — and
88
+ * `includeStacktraceInErrorResponses` suppresses masking outright, since a
89
+ * masked error carries no stack to include. A configured `formatError` gets
90
+ * the last word, exactly as it does for errors the executor reports itself.
91
+ */
92
+ private formatThrownError;
93
+ /**
94
+ * Start a GraphQL subscription.
95
+ *
96
+ * Resolves to an async iterator of results when the operation subscribes
97
+ * successfully, or to a {@link HandlerResult} carrying `errors` when the
98
+ * document fails to parse or validate. Callers must distinguish the two by
99
+ * testing for `Symbol.asyncIterator`. This method rejects only when the
100
+ * driver has no executor — every error raised while subscribing is reported
101
+ * through `errors`, and masked in production, exactly as in {@link execute}.
102
+ *
103
+ * As with {@link execute}, complexity and depth are recorded on the context
104
+ * — when a limit is configured — so the guards apply to subscriptions as
105
+ * well as queries.
106
+ */
107
+ subscribe<TData = Record<string, unknown>>(query: string | DocumentNode, variables?: Record<string, unknown>, context?: GqlContext, operationName?: string): Promise<AsyncIterableIterator<HandlerResult<TData>> | HandlerResult<TData>>;
58
108
  /**
59
109
  * Handle an HTTP request
60
110
  */
61
111
  handleRequest(request: Request, response: Response): Promise<HandlerResult>;
62
112
  /**
63
113
  * Parse the request body
114
+ *
115
+ * POST requests are dispatched on their content type: `application/json`
116
+ * bodies carry `{ query, variables, operationName }`, and
117
+ * `application/graphql` bodies (per the GraphQL-over-HTTP spec) carry the
118
+ * raw query string. Other methods read the operation from URL parameters.
64
119
  */
65
120
  private parseRequestBody;
66
121
  /**
@@ -68,15 +123,55 @@ export declare class LeavenDriver implements OnModuleInit, OnModuleDestroy {
68
123
  */
69
124
  private createContext;
70
125
  /**
71
- * Convert DocumentNode to string
72
- */
73
- private documentToString;
126
+ * Analyze the query and record its complexity and depth on the request
127
+ * context under the `_queryComplexity` / `_queryDepth` keys that
128
+ * `ComplexityGuard` and `DepthGuard` enforce.
129
+ *
130
+ * Analysis is **skipped entirely** unless `maxComplexity` or `maxDepth` is
131
+ * configured. It costs a full uncached `parse()` plus a full uncached
132
+ * complexity compilation on top of the executor's own (LRU-cached) parse and
133
+ * compile — roughly 2.6x the work of the request itself for a small query —
134
+ * and with no limit configured both guards receive the module's `Infinity`
135
+ * sentinel and have nothing to enforce.
136
+ *
137
+ * When a limit *is* configured, the result is memoized in a small LRU keyed
138
+ * by query text and operation name, so the surcharge is paid once per
139
+ * distinct document rather than once per request.
140
+ *
141
+ * A document that fails to parse is left to the executor, which reports the
142
+ * syntax error as a proper GraphQL error response — no limit can be
143
+ * meaningfully enforced on a document that never executes.
144
+ *
145
+ * Every other failure (a broken compiler, a missing schema, a depth
146
+ * traversal that throws) is an *analysis* failure: it is logged and both
147
+ * fields are set to `Infinity` so the guards fail closed. Leaving them unset
148
+ * would hand an attacker who finds one query shape that trips the analyzer
149
+ * an unlimited-complexity channel. Failures are never memoized.
150
+ */
151
+ private attachQueryAnalysis;
152
+ /**
153
+ * Store an analysis result, evicting the least recently used entry when the
154
+ * cache is full.
155
+ */
156
+ private memoizeAnalysis;
157
+ /**
158
+ * Record a fail-closed sentinel for both analysis fields and log the cause.
159
+ *
160
+ * `Infinity` exceeds every finite limit, so a configured `ComplexityGuard`
161
+ * or `DepthGuard` rejects the request rather than letting it through
162
+ * unmeasured.
163
+ */
164
+ private recordAnalysisFailure;
74
165
  /**
75
166
  * Check if playground should be enabled
76
167
  */
77
168
  isPlaygroundEnabled(): boolean;
78
169
  /**
79
170
  * Check if introspection should be enabled
171
+ *
172
+ * This is the value handed to the executor as `ExecutorConfig.introspection`,
173
+ * which installs `NoSchemaIntrospectionCustomRule` when it is `false`, so a
174
+ * caller may also use it to decide whether to serve a schema-browsing UI.
80
175
  */
81
176
  isIntrospectionEnabled(): boolean;
82
177
  /**
@@ -89,7 +184,11 @@ export declare class LeavenDriver implements OnModuleInit, OnModuleDestroy {
89
184
  getCacheStats(): ReturnType<LeavenExecutor['getCacheStats']> | null;
90
185
  /**
91
186
  * Clear all caches
187
+ *
188
+ * Awaited rather than fired and forgotten: `clearCaches` is asynchronous for
189
+ * a remote cache, so a floated promise would leave the clear unfinished and
190
+ * a rejecting cache unhandled.
92
191
  */
93
- clearCaches(): void;
192
+ clearCaches(): Promise<void>;
94
193
  }
95
194
  //# sourceMappingURL=driver.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../src/driver.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAc,KAAK,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACrF,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAuB,MAAM,sBAAsB,CAAC;AAC3E,OAAO,KAAK,EACV,mBAAmB,EACnB,UAAU,EACV,qBAAqB,EACtB,MAAM,SAAS,CAAC;AAEjB;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACtC,MAAM,CAAC,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED;;;;;GAKG;AACH,qBACa,YAAa,YAAW,YAAY,EAAE,eAAe;IAChE,OAAO,CAAC,QAAQ,CAA+B;IAC/C,OAAO,CAAC,MAAM,CAA8B;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;gBAElC,OAAO,EAAE,mBAAmB;IAIxC;;OAEG;IACU,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAO1C;;OAEG;IACU,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAO7C;;OAEG;IACI,SAAS,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI;IAK7C;;OAEG;IACI,SAAS,IAAI,aAAa,GAAG,IAAI;IAIxC;;OAEG;IACI,WAAW,IAAI,cAAc,GAAG,IAAI;IAI3C;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAe1B;;OAEG;IACU,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClD,KAAK,EAAE,MAAM,GAAG,YAAY,EAC5B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,OAAO,CAAC,EAAE,UAAU,EACpB,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,aAAa,CAAC;IA2DzB;;OAEG;IACU,aAAa,CACxB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,aAAa,CAAC;IAYzB;;OAEG;YACW,gBAAgB;IAiC9B;;OAEG;YACW,aAAa;IAiB3B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAMxB;;OAEG;IACI,mBAAmB,IAAI,OAAO;IAOrC;;OAEG;IACI,sBAAsB,IAAI,OAAO;IAOxC;;OAEG;IACI,OAAO,IAAI,MAAM;IAIxB;;OAEG;IACI,aAAa,IAAI,UAAU,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC,GAAG,IAAI;IAI1E;;OAEG;IACI,WAAW,IAAI,IAAI;CAG3B"}
1
+ {"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../src/driver.ts"],"names":[],"mappings":"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"}
@@ -4,12 +4,34 @@
4
4
  * Provides a helper class for accessing GraphQL-specific context in guards,
5
5
  * interceptors, and other NestJS constructs.
6
6
  *
7
- * Copyright 2026 Pegasus Heavy Industries LLC
7
+ * Copyright 2026 Joseph Quinn
8
8
  * Licensed under the Apache License, Version 2.0
9
9
  */
10
10
  import type { ExecutionContext, ArgumentsHost } from '@nestjs/common';
11
11
  import type { GraphQLResolveInfo } from 'graphql';
12
12
  import type { GqlContext } from './types';
13
+ /**
14
+ * Positional indices of the GraphQL resolver arguments as exposed by
15
+ * NestJS's `ExecutionContext.getArgs()` for GraphQL invocations:
16
+ * `[root, args, context, info]`.
17
+ *
18
+ * This is the single source of truth for the positional assumption shared by
19
+ * the execution-context helpers and the param decorators. Use these named
20
+ * indices instead of hard-coded numbers so a change in argument ordering only
21
+ * needs to be reflected in one place.
22
+ *
23
+ * @internal
24
+ */
25
+ export declare const GQL_RESOLVER_ARGS: {
26
+ /** The root/parent value — 1st resolver argument */
27
+ readonly ROOT: 0;
28
+ /** The resolver arguments object — 2nd resolver argument */
29
+ readonly ARGS: 1;
30
+ /** The GraphQL context object — 3rd resolver argument */
31
+ readonly CONTEXT: 2;
32
+ /** The `GraphQLResolveInfo` object — 4th resolver argument */
33
+ readonly INFO: 3;
34
+ };
13
35
  /**
14
36
  * GraphQL execution context helper
15
37
  *
@@ -120,11 +142,33 @@ export declare class GqlExecutionContext {
120
142
  */
121
143
  getVariables<T = Record<string, unknown>>(): T;
122
144
  /**
123
- * Get the path to the current field
145
+ * Get the field-name path to the current field
146
+ *
147
+ * List indices are omitted, so `users[3].email` yields
148
+ * `['users', 'email']` — the same value this method has always returned,
149
+ * which keeps `getPath().join('.')` stable as a metric label, log key, or
150
+ * cache key.
151
+ *
152
+ * @deprecated Use {@link getFullPath}, which preserves list indices and so
153
+ * identifies an individual element rather than a field position.
124
154
  */
125
155
  getPath(): string[];
156
+ /**
157
+ * Get the full path to the current field
158
+ *
159
+ * Every path segment is included: field names as strings and list indices
160
+ * as numbers, so `users[3].email` yields `['users', 3, 'email']` and list
161
+ * positions remain distinguishable from field names.
162
+ */
163
+ getFullPath(): Array<string | number>;
126
164
  /**
127
165
  * Get the requested fields (first level)
166
+ *
167
+ * Resolves fragment spreads (via `info.fragments`) and inline fragments,
168
+ * and merges the selections of every field node for the current field, so
169
+ * fields hidden behind `...SomeFragment` or `... on Type { ... }` are
170
+ * reported. Fragment cycles are tolerated. Returned names are the schema
171
+ * field names (not client aliases), deduplicated.
128
172
  */
129
173
  getSelectedFields(): string[];
130
174
  }
@@ -1 +1 @@
1
- {"version":3,"file":"execution-context.d.ts","sourceRoot":"","sources":["../src/execution-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,mBAAmB;IAGV,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFzC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAY;IAEjC,OAAO;IAIP;;OAEG;WACW,MAAM,CAAC,OAAO,EAAE,gBAAgB,GAAG,mBAAmB;IAIpE;;;;;OAKG;IACI,UAAU,CAAC,CAAC,GAAG,UAAU,KAAK,CAAC;IAItC;;;;;OAKG;IACI,OAAO,CAAC,CAAC,GAAG,OAAO,KAAK,CAAC;IAIhC;;;;;OAKG;IACI,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC;IAIhD;;;;;OAKG;IACI,OAAO,CAAC,CAAC,GAAG,kBAAkB,KAAK,CAAC;IAI3C;;OAEG;IACI,MAAM,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAKvD;;OAEG;IACI,kBAAkB,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAKnE;;OAEG;IACI,OAAO,IAAI,aAAa;IAI/B;;;OAGG;IACI,OAAO,IAAI,MAAM;IAIxB;;OAEG;IACI,SAAS,IAAI,OAAO;IAI3B;;OAEG;IACI,UAAU,IAAI,QAAQ,GAAG,SAAS;IAIzC;;OAEG;IACI,QAAQ,IAAI,QAAQ,GAAG,SAAS;IAIvC;;OAEG;IACI,YAAY,IAAI,MAAM,GAAG,SAAS;IAKzC;;OAEG;IACI,iBAAiB,IAAI,MAAM,GAAG,SAAS;IAK9C;;OAEG;IACI,iBAAiB,IAAI,MAAM,GAAG,SAAS;IAK9C;;OAEG;IACI,gBAAgB,IAAI,MAAM,GAAG,SAAS;IAK7C;;OAEG;IACI,gBAAgB,IAAI,OAAO,GAAG,UAAU,GAAG,cAAc,GAAG,SAAS;IAK5E;;OAEG;IACI,YAAY,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC;IAKrD;;OAEG;IACI,OAAO,IAAI,MAAM,EAAE;IAiB1B;;OAEG;IACI,iBAAiB,IAAI,MAAM,EAAE;CAQrC;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,GAAG,UAAU,EAAE,OAAO,EAAE,gBAAgB,GAAG,CAAC,CAE1E;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,gBAAgB,GAAG,CAAC,CAEpF;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,GAAG,kBAAkB,EAAE,OAAO,EAAE,gBAAgB,GAAG,CAAC,CAE/E;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,GAAG,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,CAAC,CAEpE"}
1
+ {"version":3,"file":"execution-context.d.ts","sourceRoot":"","sources":["../src/execution-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,KAAK,EAAE,kBAAkB,EAAoB,MAAM,SAAS,CAAC;AACpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iBAAiB;IAC5B,oDAAoD;;IAEpD,4DAA4D;;IAE5D,yDAAyD;;IAEzD,8DAA8D;;CAEtD,CAAC;AAEX;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,mBAAmB;IAGV,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFzC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAY;IAEjC,OAAO;IAIP;;OAEG;WACW,MAAM,CAAC,OAAO,EAAE,gBAAgB,GAAG,mBAAmB;IAIpE;;;;;OAKG;IACI,UAAU,CAAC,CAAC,GAAG,UAAU,KAAK,CAAC;IAItC;;;;;OAKG;IACI,OAAO,CAAC,CAAC,GAAG,OAAO,KAAK,CAAC;IAIhC;;;;;OAKG;IACI,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC;IAIhD;;;;;OAKG;IACI,OAAO,CAAC,CAAC,GAAG,kBAAkB,KAAK,CAAC;IAI3C;;OAEG;IACI,MAAM,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAKvD;;OAEG;IACI,kBAAkB,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAKnE;;OAEG;IACI,OAAO,IAAI,aAAa;IAI/B;;;OAGG;IACI,OAAO,IAAI,MAAM;IAIxB;;OAEG;IACI,SAAS,IAAI,OAAO;IAI3B;;OAEG;IACI,UAAU,IAAI,QAAQ,GAAG,SAAS;IAIzC;;OAEG;IACI,QAAQ,IAAI,QAAQ,GAAG,SAAS;IAIvC;;OAEG;IACI,YAAY,IAAI,MAAM,GAAG,SAAS;IAKzC;;OAEG;IACI,iBAAiB,IAAI,MAAM,GAAG,SAAS;IAK9C;;OAEG;IACI,iBAAiB,IAAI,MAAM,GAAG,SAAS;IAK9C;;OAEG;IACI,gBAAgB,IAAI,MAAM,GAAG,SAAS;IAK7C;;OAEG;IACI,gBAAgB,IAAI,OAAO,GAAG,UAAU,GAAG,cAAc,GAAG,SAAS;IAK5E;;OAEG;IACI,YAAY,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC;IAKrD;;;;;;;;;;OAUG;IACI,OAAO,IAAI,MAAM,EAAE;IAM1B;;;;;;OAMG;IACI,WAAW,IAAI,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;IAe5C;;;;;;;;OAQG;IACI,iBAAiB,IAAI,MAAM,EAAE;CA8BrC;AAoBD;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,GAAG,UAAU,EAAE,OAAO,EAAE,gBAAgB,GAAG,CAAC,CAE1E;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,gBAAgB,GAAG,CAAC,CAEpF;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,GAAG,kBAAkB,EAAE,OAAO,EAAE,gBAAgB,GAAG,CAAC,CAE/E;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,GAAG,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,CAAC,CAEpE"}
@@ -0,0 +1,180 @@
1
+ /**
2
+ * @leaven-graphql/nestjs - `@nestjs/graphql` driver backed by Leaven
3
+ *
4
+ * Copyright 2026 Joseph Quinn
5
+ * Licensed under the Apache License, Version 2.0
6
+ */
7
+ import { AbstractGraphQLDriver } from '@nestjs/graphql';
8
+ import type { GqlModuleOptions } from '@nestjs/graphql';
9
+ import type { GraphQLFormattedError } from 'graphql';
10
+ import { LeavenExecutor, type ExecutorConfig } from '@leaven-graphql/core';
11
+ /**
12
+ * Configuration for {@link LeavenGraphQLDriver}.
13
+ *
14
+ * Everything `@nestjs/graphql` understands is accepted unchanged — including
15
+ * `autoSchemaFile`, `typeDefs`, `path`, `context` and `useGlobalPrefix` — and
16
+ * the Leaven-specific options below are forwarded to the executor that serves
17
+ * the finished schema.
18
+ */
19
+ export interface LeavenDriverConfig extends GqlModuleOptions {
20
+ /** Document/validation cache configuration passed to the executor. */
21
+ cache?: ExecutorConfig['cache'];
22
+ /** Collect per-operation metrics and expose them under `extensions.metrics`. */
23
+ metrics?: boolean;
24
+ /**
25
+ * Maximum allowed query complexity. Enforced by the executor itself, which
26
+ * rejects an over-budget document before any resolver runs.
27
+ */
28
+ maxComplexity?: number;
29
+ /** Maximum allowed query depth. Enforced by the executor at parse time. */
30
+ maxDepth?: number;
31
+ /** Serve GraphiQL on `GET <path>`. Defaults to `false`. */
32
+ playground?: boolean;
33
+ /** WebSocket endpoint advertised to GraphiQL, when subscriptions are served. */
34
+ subscriptionEndpoint?: string;
35
+ /** Final transformation applied to every error in the response. */
36
+ formatError?: (error: GraphQLFormattedError) => GraphQLFormattedError;
37
+ /**
38
+ * Include stack traces in error responses. Setting this also disables
39
+ * production masking, since a masked error carries no stack to include.
40
+ */
41
+ includeStacktraceInErrorResponses?: boolean;
42
+ }
43
+ /**
44
+ * A `@nestjs/graphql` driver that executes with Leaven.
45
+ *
46
+ * ## Why this class is the bridge
47
+ *
48
+ * `GraphQLModule.onModuleInit` calls `generateSchema()` before `start()`.
49
+ * `generateSchema()` is inherited from {@link AbstractGraphQLDriver} and
50
+ * delegates to `GraphQLFactory`, which builds the schema from your
51
+ * `@Resolver()` classes with NestJS's `ExternalContextCreator` wrapped around
52
+ * every field resolver. That wrapper is what runs guards, interceptors, pipes,
53
+ * filters and parameter decorators. By the time `start()` receives
54
+ * `options.schema`, the NestJS execution pipeline is already baked into it —
55
+ * this driver only has to execute that schema and serve it over HTTP.
56
+ *
57
+ * This is the opposite of `LeavenModule.forRoot({ typeDefs, resolvers })`,
58
+ * where resolvers are plain functions invoked directly by graphql-js and the
59
+ * NestJS pipeline never runs.
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * @Module({
64
+ * imports: [
65
+ * GraphQLModule.forRoot<LeavenDriverConfig>({
66
+ * driver: LeavenGraphQLDriver,
67
+ * autoSchemaFile: true,
68
+ * playground: true,
69
+ * cache: { maxSize: 1000 },
70
+ * }),
71
+ * ],
72
+ * })
73
+ * export class AppModule {}
74
+ * ```
75
+ */
76
+ export declare class LeavenGraphQLDriver extends AbstractGraphQLDriver<LeavenDriverConfig> {
77
+ private executor;
78
+ private options;
79
+ /**
80
+ * Serve the schema `@nestjs/graphql` has already built.
81
+ *
82
+ * Registers a POST handler for GraphQL operations and, when `playground` is
83
+ * enabled, a GET handler rendering GraphiQL — both at the module's
84
+ * normalized path.
85
+ */
86
+ start(options: LeavenDriverConfig): Promise<void>;
87
+ /**
88
+ * Release the executor.
89
+ *
90
+ * `clearCaches()` is genuinely asynchronous for a remote cache (a Redis
91
+ * `FLUSH`), so it is awaited: dropping the promise would leave the clear
92
+ * unfinished and turn a rejecting cache into an unhandled rejection during
93
+ * shutdown.
94
+ */
95
+ stop(): Promise<void>;
96
+ /**
97
+ * The executor currently serving requests, or `null` before `start()` and
98
+ * after `stop()`.
99
+ */
100
+ getExecutor(): LeavenExecutor | null;
101
+ /**
102
+ * Execute one GraphQL operation and write the HTTP response.
103
+ */
104
+ private handleOperation;
105
+ /**
106
+ * Render GraphiQL.
107
+ */
108
+ private servePlayground;
109
+ /**
110
+ * Build the GraphQL context for one request.
111
+ *
112
+ * `req`/`res` are always present so guards and resolvers can reach the
113
+ * transport objects (this is what makes `ctx.req.user` work under Passport);
114
+ * a configured `context` factory or object is merged over them.
115
+ */
116
+ private buildContext;
117
+ /**
118
+ * Write a GraphQL response with the status the error-handling conventions
119
+ * require.
120
+ *
121
+ * A response carrying `data` is a spec-conformant partial success and stays
122
+ * 200 whatever the error codes say — anything else makes clients treat it as
123
+ * a network failure and discard data they were given. Only a total failure
124
+ * derives its status from the first error's `ErrorCode`, via the
125
+ * `ERROR_CODES` registry that `@leaven-graphql/http` uses.
126
+ */
127
+ private respond;
128
+ /**
129
+ * Guarantee an `ErrorCode`, apply production masking, then hand the result
130
+ * to a configured `formatError`.
131
+ *
132
+ * By this point {@link formatExecutionError} has already given every NestJS
133
+ * `HttpException` its `ErrorCode`; what is left here is the residue — a
134
+ * resolver that threw a plain `Error` — which must still be coded and, in
135
+ * production, masked.
136
+ *
137
+ * The executor reports errors as already-serialised `GraphQLFormattedError`s
138
+ * (`GraphQLError.toJSON()`), so `formatError` from `@leaven-graphql/errors`
139
+ * — whose input is an `Error`/`GraphQLError` — cannot be reused verbatim
140
+ * here; this reproduces its masking rule for the formatted shape. Errors
141
+ * *thrown* out of the executor do go through it, in
142
+ * {@link formatThrownError}.
143
+ */
144
+ private finalizeError;
145
+ /**
146
+ * Turn an error thrown out of the executor into a response error.
147
+ *
148
+ * Leaven errors keep their code, extensions and message. Unexpected errors
149
+ * are masked only in production — masking them in development would hide the
150
+ * real message from the developer — and `includeStacktraceInErrorResponses`
151
+ * suppresses masking outright, since a masked error carries no stack to
152
+ * include. This matches `LeavenDriver.execute`.
153
+ */
154
+ private formatThrownError;
155
+ /**
156
+ * Read the operation from the request.
157
+ *
158
+ * The adapter may hand over an already-parsed body, a raw string, or nothing
159
+ * at all when no body-parser is installed; the raw Fetch `Request` is the
160
+ * last resort.
161
+ */
162
+ private static readBody;
163
+ /**
164
+ * Serialize one execution error, translating a NestJS `HttpException` into
165
+ * the equivalent {@link ErrorCode}.
166
+ *
167
+ * Installed as the executor's `formatExecutionError` hook, which runs while
168
+ * the graphql-js `GraphQLError` is still intact — the only point at which
169
+ * `originalError` is still reachable. After `toJSON()` it is gone, and an
170
+ * `HttpException` (unlike a `LeavenError`) has no `extensions` of its own
171
+ * for graphql-js to adopt, so the error would otherwise reach the client as
172
+ * a bare `INTERNAL_ERROR` with a 500: a guard's `ForbiddenException` would be
173
+ * indistinguishable from a crash.
174
+ *
175
+ * `message`, `path` and `locations` are preserved exactly as serialized;
176
+ * only `extensions.code` is supplied.
177
+ */
178
+ private static formatExecutionError;
179
+ }
180
+ //# sourceMappingURL=graphql-driver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graphql-driver.d.ts","sourceRoot":"","sources":["../src/graphql-driver.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EAAgB,qBAAqB,EAAE,MAAM,SAAS,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AA8C3E;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAmB,SAAQ,gBAAgB;IAC1D,sEAAsE;IACtE,KAAK,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;IAChC,gFAAgF;IAChF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gFAAgF;IAChF,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,mEAAmE;IACnE,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,qBAAqB,CAAC;IACtE;;;OAGG;IACH,iCAAiC,CAAC,EAAE,OAAO,CAAC;CAC7C;AAoBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,qBAAa,mBAAoB,SAAQ,qBAAqB,CAAC,kBAAkB,CAAC;IAChF,OAAO,CAAC,QAAQ,CAA+B;IAC/C,OAAO,CAAC,OAAO,CAAmC;IAElD;;;;;;OAMG;IACU,KAAK,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAgC9D;;;;;;;OAOG;IACU,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAOlC;;;OAGG;IACI,WAAW,IAAI,cAAc,GAAG,IAAI;IAI3C;;OAEG;YACW,eAAe;IAsE7B;;OAEG;IACH,OAAO,CAAC,eAAe;IASvB;;;;;;OAMG;YACW,YAAY;IAqB1B;;;;;;;;;OASG;IACH,OAAO,CAAC,OAAO;IAiCf;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,aAAa;IA2BrB;;;;;;;;OAQG;IACH,OAAO,CAAC,iBAAiB;IAezB;;;;;;OAMG;mBACkB,QAAQ;IAmB7B;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,MAAM,CAAC,oBAAoB;CAoBpC"}