@gqloom/core 0.8.3 → 0.9.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/dist/index.js CHANGED
@@ -1,8 +1,17 @@
1
- var __defProp = Object.defineProperty;
2
- var __export = (target, all) => {
3
- for (var name in all)
4
- __defProp(target, name, { get: all[name], enumerable: true });
5
- };
1
+ import {
2
+ DERIVED_DEPENDENCIES,
3
+ FIELD_HIDDEN,
4
+ GET_GRAPHQL_TYPE,
5
+ IS_RESOLVER,
6
+ WEAVER_CONFIG,
7
+ assignContextMap,
8
+ getMemoizationMap,
9
+ getResolvingFields,
10
+ isOnlyMemoryPayload,
11
+ onlyMemoization,
12
+ parseResolvingFields,
13
+ symbols_exports
14
+ } from "./chunk-BQAPYNA7.js";
6
15
 
7
16
  // src/utils/args.ts
8
17
  function getOperationOptions(resolveOrOptions) {
@@ -17,20 +26,22 @@ function getSubscriptionOptions(subscribeOrOptions) {
17
26
  }
18
27
  return subscribeOrOptions;
19
28
  }
20
- function getFieldOptions({
21
- description,
22
- deprecationReason,
23
- extensions
24
- }) {
29
+ function getFieldOptions({ description, deprecationReason, extensions }, extraExtensions) {
25
30
  return {
26
31
  description,
27
32
  deprecationReason,
28
- extensions
33
+ extensions: extraExtensions ? { ...extensions, ...extraExtensions } : extensions
29
34
  };
30
35
  }
31
36
 
32
37
  // src/utils/middleware.ts
33
- function applyMiddlewares(middlewares, resolveFunction, options) {
38
+ var defaultOperations = [
39
+ "field",
40
+ "mutation",
41
+ "query",
42
+ "subscription.subscribe"
43
+ ];
44
+ function applyMiddlewares(options, resolveFunction, middlewares) {
34
45
  const next = (index) => {
35
46
  if (index >= middlewares.length) {
36
47
  return resolveFunction();
@@ -44,122 +55,20 @@ function applyMiddlewares(middlewares, resolveFunction, options) {
44
55
  };
45
56
  return next(0);
46
57
  }
47
- function compose(...lists) {
48
- const list = [];
49
- for (const item of lists) {
50
- if (item != null) {
51
- list.push(...item);
52
- }
53
- }
54
- return list;
55
- }
56
-
57
- // src/utils/context.ts
58
- import { AsyncLocalStorage } from "async_hooks";
59
-
60
- // src/utils/symbols.ts
61
- var symbols_exports = {};
62
- __export(symbols_exports, {
63
- CONTEXT_MEMORY_MAP_KEY: () => CONTEXT_MEMORY_MAP_KEY,
64
- FIELD_HIDDEN: () => FIELD_HIDDEN,
65
- GET_GRAPHQL_TYPE: () => GET_GRAPHQL_TYPE,
66
- IS_RESOLVER: () => IS_RESOLVER,
67
- RESOLVER_OPTIONS_KEY: () => RESOLVER_OPTIONS_KEY,
68
- WEAVER_CONFIG: () => WEAVER_CONFIG
69
- });
70
- var GET_GRAPHQL_TYPE = Symbol.for("gqloom.get_graphql_type");
71
- var WEAVER_CONFIG = Symbol.for("gqloom.weaver_config");
72
- var RESOLVER_OPTIONS_KEY = Symbol.for("gqloom.resolver-options");
73
- var IS_RESOLVER = Symbol.for("gqloom.is-resolver");
74
- var CONTEXT_MEMORY_MAP_KEY = Symbol.for("gqloom.context-memory");
75
- var FIELD_HIDDEN = Symbol.for("gqloom.field-hidden");
76
-
77
- // src/utils/context.ts
78
- function onlyMemoization() {
79
- return { memoization: /* @__PURE__ */ new WeakMap(), isMemoization: true };
80
- }
81
- function isOnlyMemoryPayload(payload) {
82
- return payload.isMemoization === true;
83
- }
84
- var resolverPayloadStorage = new AsyncLocalStorage();
85
- function useResolverPayload() {
86
- const payload = resolverPayloadStorage.getStore();
87
- if (payload === void 0 || isOnlyMemoryPayload(payload)) return;
88
- return payload;
89
- }
90
- function useContext() {
91
- return useResolverPayload()?.context;
58
+ function filterMiddlewares(operation, ...middlewareList) {
59
+ return middlewareList.reduce((acc, m) => {
60
+ if (!m) return acc;
61
+ acc.push(
62
+ ...ensureArray(m).filter((m2) => {
63
+ const ops = m2.operations ?? defaultOperations;
64
+ return ops.includes(operation);
65
+ })
66
+ );
67
+ return acc;
68
+ }, []);
92
69
  }
93
- function useMemoizationMap() {
94
- const payload = resolverPayloadStorage.getStore();
95
- if (payload == null) return;
96
- if (isOnlyMemoryPayload(payload)) return payload.memoization;
97
- return ContextMemoization.assignMemoizationMap(payload.context);
98
- }
99
- var ContextMemoization = class {
100
- constructor(getter, options = {}) {
101
- this.getter = getter;
102
- this.getter = getter;
103
- this.getMemoizationMap = options.getMemoizationMap ?? useMemoizationMap;
104
- this.key = options.key ?? this.getter;
105
- }
106
- getMemoizationMap;
107
- key;
108
- /**
109
- * Get the value in memoization or call the getter function
110
- * @returns the value of the getter function
111
- */
112
- get() {
113
- const map = this.getMemoizationMap();
114
- if (!map) return this.getter();
115
- if (!map.has(this.key)) {
116
- map.set(this.key, this.getter());
117
- }
118
- return map.get(this.key);
119
- }
120
- /**
121
- * Clear the memoization
122
- * @returns true if the memoization is cleared, undefined if the context is not found
123
- */
124
- clear() {
125
- const map = this.getMemoizationMap();
126
- if (!map) return;
127
- return map.delete(this.key);
128
- }
129
- /**
130
- * Check if the memoization exists
131
- * @returns true if the memoization exists, undefined if the context is not found
132
- */
133
- exists() {
134
- const map = this.getMemoizationMap();
135
- if (!map) return;
136
- return map.has(this.key);
137
- }
138
- /**
139
- * Set a new value to the memoization
140
- * @param value the new value to set
141
- * @returns the memoization map or undefined if the context is not found
142
- */
143
- set(value) {
144
- const map = this.getMemoizationMap();
145
- if (!map) return;
146
- return map.set(this.key, value);
147
- }
148
- static assignMemoizationMap(target) {
149
- target[CONTEXT_MEMORY_MAP_KEY] ??= /* @__PURE__ */ new WeakMap();
150
- return target[CONTEXT_MEMORY_MAP_KEY];
151
- }
152
- };
153
- function createMemoization(...args) {
154
- const memoization = new ContextMemoization(...args);
155
- const callable = () => memoization.get();
156
- return Object.assign(callable, {
157
- get: () => memoization.get(),
158
- set: (value) => memoization.set(value),
159
- clear: () => memoization.clear(),
160
- exists: () => memoization.exists(),
161
- getter: memoization.getter
162
- });
70
+ function ensureArray(value) {
71
+ return Array.isArray(value) ? value : [value];
163
72
  }
164
73
 
165
74
  // src/utils/object.ts
@@ -224,6 +133,9 @@ function pascalCase(str) {
224
133
  function capitalize(str) {
225
134
  return str.slice(0, 1).toUpperCase() + str.slice(1);
226
135
  }
136
+ function screamingSnakeCase(str) {
137
+ return str.replace(/([a-z])([A-Z])/g, "$1_$2").split(/[\s-_]+/).map((word) => word.toUpperCase()).join("_");
138
+ }
227
139
 
228
140
  // src/utils/error.ts
229
141
  function markErrorLocation(error, ...locations) {
@@ -593,9 +505,16 @@ function getStandardValue(result) {
593
505
 
594
506
  // src/resolver/resolver-chain-factory.ts
595
507
  var BaseChainFactory = class _BaseChainFactory {
508
+ /**
509
+ * Creates a new instance of the chain factory
510
+ * @param options - Configuration options for the factory
511
+ */
596
512
  constructor(options) {
597
513
  this.options = options;
598
514
  }
515
+ /**
516
+ * Returns the available methods for the chain factory
517
+ */
599
518
  static methods() {
600
519
  return {
601
520
  description: _BaseChainFactory.prototype.description,
@@ -603,15 +522,31 @@ var BaseChainFactory = class _BaseChainFactory {
603
522
  extensions: _BaseChainFactory.prototype.extensions
604
523
  };
605
524
  }
525
+ /**
526
+ * Sets the description for the field
527
+ * @param description - The description text
528
+ */
606
529
  description(description) {
607
530
  return this.clone({ description });
608
531
  }
532
+ /**
533
+ * Sets the deprecation reason for the field
534
+ * @param deprecationReason - The reason for deprecation
535
+ */
609
536
  deprecationReason(deprecationReason) {
610
537
  return this.clone({ deprecationReason });
611
538
  }
539
+ /**
540
+ * Sets custom extensions for the field
541
+ * @param extensions - Custom extensions to add
542
+ */
612
543
  extensions(extensions) {
613
544
  return this.clone({ extensions });
614
545
  }
546
+ /**
547
+ * Adds middleware functions to the field
548
+ * @param middlewares - Middleware functions to add
549
+ */
615
550
  use(...middlewares) {
616
551
  return this.clone({
617
552
  middlewares: [...this.options?.middlewares ?? [], ...middlewares]
@@ -619,6 +554,9 @@ var BaseChainFactory = class _BaseChainFactory {
619
554
  }
620
555
  };
621
556
  var FieldChainFactory = class _FieldChainFactory extends BaseChainFactory {
557
+ /**
558
+ * Returns the available methods for the field chain factory
559
+ */
622
560
  static methods() {
623
561
  return {
624
562
  ...BaseChainFactory.methods(),
@@ -628,15 +566,42 @@ var FieldChainFactory = class _FieldChainFactory extends BaseChainFactory {
628
566
  clone: _FieldChainFactory.prototype.clone
629
567
  };
630
568
  }
569
+ /**
570
+ * Creates a clone of the current factory with new options
571
+ * @param options - New options to apply to the clone
572
+ */
631
573
  clone(options) {
632
574
  return new _FieldChainFactory({ ...this.options, ...options });
633
575
  }
576
+ /**
577
+ * Sets the output type for the field
578
+ * @template TOutputNew - The new output type
579
+ * @param output - The output type definition
580
+ */
634
581
  output(output) {
635
582
  return new _FieldChainFactory({ ...this.options, output });
636
583
  }
584
+ /**
585
+ * Sets the input type for the field
586
+ * @template TInputNew - The new input type
587
+ * @param input - The input type definition
588
+ */
637
589
  input(input) {
638
590
  return new _FieldChainFactory({ ...this.options, input });
639
591
  }
592
+ /**
593
+ * Specifies the dependencies for the field
594
+ * @template TDependencies - The dependencies type
595
+ * @param dependencies - The dependencies to add
596
+ */
597
+ derivedFrom(...dependencies) {
598
+ return this.clone({ dependencies });
599
+ }
600
+ /**
601
+ * Sets the resolve function for the field
602
+ * @template TParent - The parent type
603
+ * @param resolve - The resolve function
604
+ */
640
605
  resolve(resolve) {
641
606
  if (!this.options?.output) throw new Error("Output is required");
642
607
  return createField(this.options.output, {
@@ -644,40 +609,47 @@ var FieldChainFactory = class _FieldChainFactory extends BaseChainFactory {
644
609
  resolve
645
610
  });
646
611
  }
612
+ /**
613
+ * Creates a field resolver that uses DataLoader for batch loading data.
614
+ * This method is particularly useful for optimizing performance when dealing with multiple data requests
615
+ * by batching them together and handling caching automatically.
616
+ *
617
+ * @template TParent - The parent type that extends GraphQLSilk
618
+ * @param resolve - A function that handles batch loading of data. The function receives:
619
+ * - When no input type is defined: An array of parent objects
620
+ * - When input type is defined: An array of tuples containing [parent, input]
621
+ * - An array of resolver payloads
622
+ * @returns A GraphQL field resolver that implements batch loading
623
+ */
647
624
  load(resolve) {
648
625
  if (!this.options?.output) throw new Error("Output is required");
649
- const useUnifiedParseInput = createMemoization(() => ({ current: void 0 }));
650
- const useUserLoader = createMemoization(
651
- () => new EasyDataLoader(
652
- async (parents) => resolve(
653
- parents,
654
- await useUnifiedParseInput().current?.getResult()
655
- )
656
- )
657
- );
658
- const operation = "field";
659
- return meta({
660
- ...getFieldOptions(this.options),
661
- operation,
662
- input: this.options.input,
663
- output: this.options.output,
664
- resolve: async (parent, inputValue, extraOptions) => {
665
- const unifiedParseInput = useUnifiedParseInput();
666
- unifiedParseInput.current ??= createInputParser(
667
- this.options?.input,
668
- inputValue
669
- );
670
- const parseInput = unifiedParseInput.current;
671
- return applyMiddlewares(
672
- compose(extraOptions?.middlewares, this.options?.middlewares),
673
- async () => useUserLoader().load(parent),
674
- { parseInput, parent, outputSilk: this.output, operation }
675
- );
626
+ const hasInput = typeof this.options.input !== "undefined";
627
+ const initLoader = () => new EasyDataLoader((args) => {
628
+ const parents = args.map(
629
+ ([parent, input]) => hasInput ? [parent, input] : parent
630
+ );
631
+ const payloads = args.map(([, , payload]) => payload);
632
+ return resolve(parents, payloads);
633
+ });
634
+ return createField(this.options.output, {
635
+ ...this.options,
636
+ resolve: (parent, input, payload) => {
637
+ const loader = (() => {
638
+ if (!payload) return initLoader();
639
+ const memoMap = getMemoizationMap(payload);
640
+ if (!memoMap.has(resolve)) memoMap.set(resolve, initLoader());
641
+ return memoMap.get(resolve);
642
+ })();
643
+ return loader.load([parent, input, payload]);
676
644
  }
677
645
  });
678
646
  }
679
647
  };
680
648
  var QueryChainFactory = class _QueryChainFactory extends BaseChainFactory {
649
+ /**
650
+ * Returns the available methods for the query chain factory
651
+ * @returns An object containing all available methods
652
+ */
681
653
  static methods() {
682
654
  return {
683
655
  ...BaseChainFactory.methods(),
@@ -687,15 +659,38 @@ var QueryChainFactory = class _QueryChainFactory extends BaseChainFactory {
687
659
  clone: _QueryChainFactory.prototype.clone
688
660
  };
689
661
  }
662
+ /**
663
+ * Creates a clone of the current factory with new options
664
+ * @param options - New options to apply to the clone
665
+ * @returns A new instance of QueryChainFactory with the updated options
666
+ */
690
667
  clone(options) {
691
668
  return new _QueryChainFactory({ ...this.options, ...options });
692
669
  }
670
+ /**
671
+ * Sets the output type for the query
672
+ * @template TOutputNew - The new output type
673
+ * @param output - The output type definition
674
+ * @returns A new QueryChainFactory instance with the updated output type
675
+ */
693
676
  output(output) {
694
677
  return new _QueryChainFactory({ ...this.options, output });
695
678
  }
679
+ /**
680
+ * Sets the input type for the query
681
+ * @template TInputNew - The new input type
682
+ * @param input - The input type definition
683
+ * @returns A new QueryChainFactory instance with the updated input type
684
+ */
696
685
  input(input) {
697
686
  return new _QueryChainFactory({ ...this.options, input });
698
687
  }
688
+ /**
689
+ * Sets the resolve function for the query
690
+ * @param resolve - The resolve function that processes the input and returns the output
691
+ * @returns A GraphQL query resolver
692
+ * @throws {Error} If output type is not set
693
+ */
699
694
  resolve(resolve) {
700
695
  if (!this.options?.output) throw new Error("Output is required");
701
696
  return createQuery(this.options.output, {
@@ -705,6 +700,10 @@ var QueryChainFactory = class _QueryChainFactory extends BaseChainFactory {
705
700
  }
706
701
  };
707
702
  var MutationChainFactory = class _MutationChainFactory extends BaseChainFactory {
703
+ /**
704
+ * Returns the available methods for the mutation chain factory
705
+ * @returns An object containing all available methods
706
+ */
708
707
  static methods() {
709
708
  return {
710
709
  ...BaseChainFactory.methods(),
@@ -714,15 +713,38 @@ var MutationChainFactory = class _MutationChainFactory extends BaseChainFactory
714
713
  clone: _MutationChainFactory.prototype.clone
715
714
  };
716
715
  }
716
+ /**
717
+ * Creates a clone of the current factory with new options
718
+ * @param options - New options to apply to the clone
719
+ * @returns A new instance of MutationChainFactory with the updated options
720
+ */
717
721
  clone(options) {
718
722
  return new _MutationChainFactory({ ...this.options, ...options });
719
723
  }
724
+ /**
725
+ * Sets the output type for the mutation
726
+ * @template TOutputNew - The new output type
727
+ * @param output - The output type definition
728
+ * @returns A new MutationChainFactory instance with the updated output type
729
+ */
720
730
  output(output) {
721
731
  return new _MutationChainFactory({ ...this.options, output });
722
732
  }
733
+ /**
734
+ * Sets the input type for the mutation
735
+ * @template TInputNew - The new input type
736
+ * @param input - The input type definition
737
+ * @returns A new MutationChainFactory instance with the updated input type
738
+ */
723
739
  input(input) {
724
740
  return new _MutationChainFactory({ ...this.options, input });
725
741
  }
742
+ /**
743
+ * Sets the resolve function for the mutation
744
+ * @param resolve - The resolve function that processes the input and returns the output
745
+ * @returns A GraphQL mutation resolver
746
+ * @throws {Error} If output type is not set
747
+ */
726
748
  resolve(resolve) {
727
749
  if (!this.options?.output) throw new Error("Output is required");
728
750
  return createMutation(this.options.output, {
@@ -732,6 +754,10 @@ var MutationChainFactory = class _MutationChainFactory extends BaseChainFactory
732
754
  }
733
755
  };
734
756
  var SubscriptionChainFactory = class _SubscriptionChainFactory extends BaseChainFactory {
757
+ /**
758
+ * Returns the available methods for the subscription chain factory
759
+ * @returns An object containing all available methods
760
+ */
735
761
  static methods() {
736
762
  return {
737
763
  ...BaseChainFactory.methods(),
@@ -741,15 +767,39 @@ var SubscriptionChainFactory = class _SubscriptionChainFactory extends BaseChain
741
767
  clone: _SubscriptionChainFactory.prototype.clone
742
768
  };
743
769
  }
770
+ /**
771
+ * Creates a clone of the current factory with new options
772
+ * @param options - New options to apply to the clone
773
+ * @returns A new instance of SubscriptionChainFactory with the updated options
774
+ */
744
775
  clone(options) {
745
776
  return new _SubscriptionChainFactory({ ...this.options, ...options });
746
777
  }
778
+ /**
779
+ * Sets the output type for the subscription
780
+ * @template TOutputNew - The new output type
781
+ * @param output - The output type definition
782
+ * @returns A new SubscriptionChainFactory instance with the updated output type
783
+ */
747
784
  output(output) {
748
785
  return new _SubscriptionChainFactory({ ...this.options, output });
749
786
  }
787
+ /**
788
+ * Sets the input type for the subscription
789
+ * @template TInputNew - The new input type
790
+ * @param input - The input type definition
791
+ * @returns A new SubscriptionChainFactory instance with the updated input type
792
+ */
750
793
  input(input) {
751
794
  return new _SubscriptionChainFactory({ ...this.options, input });
752
795
  }
796
+ /**
797
+ * Sets the subscribe function for the subscription
798
+ * @template TValue - The value type of the subscription
799
+ * @param subscribe - The subscribe function that returns an AsyncIterator
800
+ * @returns A subscription resolver that can be further configured with a resolve function
801
+ * @throws {Error} If output type is not set
802
+ */
753
803
  subscribe(subscribe) {
754
804
  const options = this.options;
755
805
  const output = this.options?.output;
@@ -839,20 +889,13 @@ var createQuery = (output, resolveOrOptions) => {
839
889
  return new QueryChainFactory({ output });
840
890
  }
841
891
  const options = getOperationOptions(resolveOrOptions);
842
- const operation = "query";
843
892
  return meta({
844
893
  ...getFieldOptions(options),
845
894
  input: options.input,
846
895
  output,
847
- resolve: (inputValue, extraOptions) => {
848
- const parseInput = createInputParser(options.input, inputValue);
849
- return applyMiddlewares(
850
- compose(extraOptions?.middlewares, options.middlewares),
851
- async () => options.resolve(getStandardValue(await parseInput())),
852
- { parseInput, parent: void 0, outputSilk: output, operation }
853
- );
854
- },
855
- operation
896
+ resolve: options.resolve,
897
+ middlewares: options.middlewares,
898
+ operation: "query"
856
899
  });
857
900
  };
858
901
  var query = Object.assign(
@@ -864,20 +907,13 @@ var createMutation = (output, resolveOrOptions) => {
864
907
  return new MutationChainFactory({ output });
865
908
  }
866
909
  const options = getOperationOptions(resolveOrOptions);
867
- const operation = "mutation";
868
910
  return meta({
869
911
  ...getFieldOptions(options),
870
912
  input: options.input,
871
913
  output,
872
- resolve: (inputValue, extraOptions) => {
873
- const parseInput = createInputParser(options.input, inputValue);
874
- return applyMiddlewares(
875
- compose(extraOptions?.middlewares, options.middlewares),
876
- async () => options.resolve(getStandardValue(await parseInput())),
877
- { parseInput, parent: void 0, outputSilk: output, operation }
878
- );
879
- },
880
- operation
914
+ resolve: options.resolve,
915
+ middlewares: options.middlewares,
916
+ operation: "mutation"
881
917
  });
882
918
  };
883
919
  var mutation = Object.assign(
@@ -889,20 +925,16 @@ var createField = (output, resolveOrOptions) => {
889
925
  return new FieldChainFactory({ output });
890
926
  }
891
927
  const options = getOperationOptions(resolveOrOptions);
892
- const operation = "field";
893
928
  return meta({
894
- ...getFieldOptions(options),
929
+ ...getFieldOptions(options, {
930
+ [DERIVED_DEPENDENCIES]: options.dependencies
931
+ }),
895
932
  input: options.input,
933
+ dependencies: options.dependencies,
896
934
  output,
897
- resolve: (parent, inputValue, extraOptions) => {
898
- const parseInput = createInputParser(options.input, inputValue);
899
- return applyMiddlewares(
900
- compose(extraOptions?.middlewares, options.middlewares),
901
- async () => options.resolve(parent, getStandardValue(await parseInput())),
902
- { parseInput, parent, outputSilk: output, operation }
903
- );
904
- },
905
- operation
935
+ resolve: options.resolve,
936
+ middlewares: options.middlewares,
937
+ operation: "field"
906
938
  });
907
939
  };
908
940
  var field = Object.assign(
@@ -916,72 +948,20 @@ function createSubscription(output, subscribeOrOptions) {
916
948
  return new SubscriptionChainFactory({ output });
917
949
  }
918
950
  const options = getSubscriptionOptions(subscribeOrOptions);
919
- const operation = "subscription";
920
951
  return meta({
921
952
  ...getFieldOptions(options),
922
953
  input: options.input,
923
954
  output,
924
- subscribe: (inputValue, extraOptions) => {
925
- const parseInput = createInputParser(options.input, inputValue);
926
- return applyMiddlewares(
927
- compose(
928
- extraOptions?.middlewares,
929
- options.middlewares
930
- ),
931
- async () => options.subscribe(getStandardValue(await parseInput())),
932
- { parseInput, parent: void 0, outputSilk: output, operation }
933
- );
934
- },
955
+ subscribe: options.subscribe,
935
956
  resolve: options.resolve ?? defaultSubscriptionResolve,
936
- operation
957
+ middlewares: options.middlewares,
958
+ operation: "subscription"
937
959
  });
938
960
  }
939
961
  var subscription = Object.assign(
940
962
  createSubscription,
941
963
  SubscriptionChainFactory.methods()
942
964
  );
943
- function extraOperationOptions(field2, options) {
944
- if (typeof field2 === "symbol") return field2;
945
- const composeMiddlewares = (extraOptions) => compose(extraOptions?.middlewares, options?.middlewares);
946
- switch (field2["~meta"].operation) {
947
- case "field":
948
- return {
949
- ...field2,
950
- "~meta": {
951
- ...field2["~meta"],
952
- resolve: (parent, input, extraOptions) => field2["~meta"].resolve(parent, input, {
953
- ...extraOptions,
954
- middlewares: composeMiddlewares(extraOptions)
955
- })
956
- }
957
- };
958
- case "subscription":
959
- return {
960
- ...field2,
961
- "~meta": {
962
- ...field2["~meta"],
963
- subscribe: (input, extraOptions) => field2["~meta"].subscribe(
964
- input,
965
- {
966
- ...extraOptions,
967
- middlewares: composeMiddlewares(extraOptions)
968
- }
969
- )
970
- }
971
- };
972
- default:
973
- return {
974
- ...field2,
975
- "~meta": {
976
- ...field2["~meta"],
977
- resolve: (input, extraOptions) => field2["~meta"].resolve(input, {
978
- ...extraOptions,
979
- middlewares: composeMiddlewares(extraOptions)
980
- })
981
- }
982
- };
983
- }
984
- }
985
965
  var resolver = Object.assign(
986
966
  (operations, options) => new ChainResolver(operations, options),
987
967
  {
@@ -1001,6 +981,11 @@ var loom = {
1001
981
  };
1002
982
  var ChainResolver = class {
1003
983
  meta;
984
+ /**
985
+ * Creates a new chain resolver
986
+ * @param fields - The fields or operations to resolve
987
+ * @param options - Optional resolver options
988
+ */
1004
989
  constructor(fields, options) {
1005
990
  this.meta = {
1006
991
  [IS_RESOLVER]: true,
@@ -1008,38 +993,83 @@ var ChainResolver = class {
1008
993
  options
1009
994
  };
1010
995
  }
996
+ /**
997
+ * Gets the metadata for the resolver
998
+ */
1011
999
  get "~meta"() {
1012
- const fields = {};
1013
- Object.entries(this.meta.fields).forEach(([name, field2]) => {
1014
- if (field2 === FIELD_HIDDEN) {
1015
- fields[name] = field2;
1016
- } else {
1017
- fields[name] = extraOperationOptions(field2, this.meta.options);
1018
- }
1019
- });
1020
- return {
1021
- ...this.meta,
1022
- fields
1023
- };
1000
+ return this.meta;
1024
1001
  }
1002
+ /**
1003
+ * Adds middleware functions to the resolver
1004
+ * @param middlewares - The middleware functions to add
1005
+ */
1025
1006
  use(...middlewares) {
1026
1007
  this.meta.options ??= {};
1027
1008
  this.meta.options.middlewares ??= [];
1028
1009
  this.meta.options.middlewares.push(...middlewares);
1029
1010
  return this;
1030
1011
  }
1031
- toExecutor() {
1032
- const fields = this["~meta"].fields;
1033
- const executor = {};
1034
- Object.entries(fields).forEach(([name, field2]) => {
1035
- if (field2 === FIELD_HIDDEN) return;
1036
- executor[name] = field2["~meta"].resolve;
1037
- });
1012
+ toExecutor(...middlewares) {
1013
+ const executor = mapValue(
1014
+ this["~meta"].fields,
1015
+ (field2) => this.toExecutorOperation(field2, middlewares) ?? mapValue.SKIP
1016
+ );
1038
1017
  return executor;
1039
1018
  }
1019
+ toExecutorOperation(field2, executorMiddlewares) {
1020
+ if (field2 === FIELD_HIDDEN || field2["~meta"].operation === "subscription") {
1021
+ return void 0;
1022
+ }
1023
+ const operation = field2["~meta"].operation;
1024
+ const middlewares = filterMiddlewares(
1025
+ operation,
1026
+ executorMiddlewares,
1027
+ this.meta.options?.middlewares,
1028
+ field2["~meta"].middlewares
1029
+ );
1030
+ if (field2["~meta"].operation === "field") {
1031
+ const resolve = field2["~meta"].resolve;
1032
+ return (parent, args, payload) => {
1033
+ const parseInput = createInputParser(field2["~meta"].input, args);
1034
+ return applyMiddlewares(
1035
+ {
1036
+ outputSilk: field2["~meta"].output,
1037
+ parent,
1038
+ payload,
1039
+ parseInput,
1040
+ operation
1041
+ },
1042
+ async () => resolve(parent, await parseInput.getResult(), payload),
1043
+ middlewares
1044
+ );
1045
+ };
1046
+ } else {
1047
+ const resolve = field2["~meta"].resolve;
1048
+ return (args, payload) => {
1049
+ const parseInput = createInputParser(field2["~meta"].input, args);
1050
+ return applyMiddlewares(
1051
+ {
1052
+ outputSilk: field2["~meta"].output,
1053
+ parent: void 0,
1054
+ payload,
1055
+ parseInput,
1056
+ operation
1057
+ },
1058
+ async () => resolve(await parseInput.getResult(), payload),
1059
+ middlewares
1060
+ );
1061
+ };
1062
+ }
1063
+ }
1040
1064
  };
1041
1065
  var ObjectChainResolver = class extends ChainResolver {
1042
1066
  meta;
1067
+ /**
1068
+ * Creates a new object chain resolver
1069
+ * @param parent - The parent type definition
1070
+ * @param fields - The fields to resolve
1071
+ * @param options - Optional resolver options
1072
+ */
1043
1073
  constructor(parent, fields, options) {
1044
1074
  super(fields, options);
1045
1075
  this.meta = {
@@ -1049,9 +1079,16 @@ var ObjectChainResolver = class extends ChainResolver {
1049
1079
  options
1050
1080
  };
1051
1081
  }
1082
+ /**
1083
+ * Gets the metadata for the resolver
1084
+ */
1052
1085
  get "~meta"() {
1053
1086
  return super["~meta"];
1054
1087
  }
1088
+ /**
1089
+ * Sets custom extensions for the resolver
1090
+ * @param extensions - The extensions to add
1091
+ */
1055
1092
  extensions(extensions) {
1056
1093
  this.meta.options ??= {};
1057
1094
  this.meta.options.extensions ??= {};
@@ -1077,17 +1114,6 @@ import {
1077
1114
  resolveObjMapThunk
1078
1115
  } from "graphql";
1079
1116
 
1080
- // src/utils/async-iterator.ts
1081
- function bindAsyncIterator(storage, generator) {
1082
- const store = storage.getStore();
1083
- const next = generator.next;
1084
- Object.defineProperty(generator, "next", {
1085
- value: (...args) => storage.run(store, () => next.apply(generator, args)),
1086
- writable: false
1087
- });
1088
- return generator;
1089
- }
1090
-
1091
1117
  // src/schema/input.ts
1092
1118
  import {
1093
1119
  GraphQLInputObjectType,
@@ -1192,7 +1218,11 @@ var LoomObjectType = class _LoomObjectType extends GraphQLObjectType {
1192
1218
  hiddenFields = /* @__PURE__ */ new Set();
1193
1219
  static AUTO_ALIASING = "__gqloom_auto_aliasing";
1194
1220
  weaverContext;
1195
- resolverOptions;
1221
+ globalOptions;
1222
+ /**
1223
+ * field name -> resolver
1224
+ */
1225
+ resolvers;
1196
1226
  constructor(objectOrGetter, options = {}) {
1197
1227
  const origin = typeof objectOrGetter === "function" ? objectOrGetter() : objectOrGetter;
1198
1228
  const config = (() => {
@@ -1205,8 +1235,9 @@ var LoomObjectType = class _LoomObjectType extends GraphQLObjectType {
1205
1235
  }
1206
1236
  })();
1207
1237
  super(config);
1208
- this.resolverOptions = options.resolverOptions;
1238
+ this.globalOptions = options.globalOptions;
1209
1239
  this.weaverContext = options.weaverContext ?? initWeaverContext();
1240
+ this.resolvers = /* @__PURE__ */ new Map();
1210
1241
  if (this.name !== _LoomObjectType.AUTO_ALIASING) {
1211
1242
  this.hasExplicitName = true;
1212
1243
  }
@@ -1233,12 +1264,13 @@ var LoomObjectType = class _LoomObjectType extends GraphQLObjectType {
1233
1264
  hideField(name) {
1234
1265
  this.hiddenFields.add(name);
1235
1266
  }
1236
- addField(name, resolver2) {
1267
+ addField(name, field2, resolver2) {
1237
1268
  const existing = this.extraFields.get(name);
1238
- if (existing && existing !== resolver2) {
1269
+ if (existing && existing !== field2) {
1239
1270
  throw new Error(`Field ${name} already exists in ${this.name}`);
1240
1271
  }
1241
- this.extraFields.set(name, resolver2);
1272
+ this.extraFields.set(name, field2);
1273
+ if (resolver2) this.resolvers.set(name, resolver2);
1242
1274
  }
1243
1275
  mergeExtensions(extensions) {
1244
1276
  this.extensions = deepMerge(this.extensions, extensions);
@@ -1273,58 +1305,140 @@ var LoomObjectType = class _LoomObjectType extends GraphQLObjectType {
1273
1305
  return record;
1274
1306
  }
1275
1307
  toFieldConfig(field2, fieldName) {
1276
- try {
1277
- const outputType = this.getCacheType(
1278
- getGraphQLType(field2["~meta"].output),
1279
- fieldName
1280
- );
1281
- return {
1282
- ...extract(field2),
1283
- type: outputType,
1284
- args: inputToArgs(field2["~meta"].input, {
1285
- fieldName: fieldName ? parentName(this.name) + fieldName : void 0
1286
- }),
1287
- ...this.provideForResolve(field2),
1288
- ...this.provideForSubscribe(field2)
1289
- };
1290
- } catch (error) {
1291
- throw markErrorLocation(error);
1292
- }
1293
- }
1294
- provideForResolve(field2) {
1295
- if (field2?.["~meta"]?.resolve == null) return;
1296
- if (field2["~meta"].resolve === defaultSubscriptionResolve)
1297
- return { resolve: defaultSubscriptionResolve };
1298
- const resolve = field2["~meta"].operation === "field" ? (root, args, context, info) => resolverPayloadStorage.run(
1299
- { root, args, context, info, field: field2 },
1300
- () => field2["~meta"].resolve(root, args, this.resolverOptions)
1301
- ) : field2["~meta"].operation === "subscription" ? (root, args, context, info) => resolverPayloadStorage.run(
1302
- { root, args, context, info, field: field2 },
1303
- () => field2["~meta"].resolve(root, args)
1304
- ) : (root, args, context, info) => resolverPayloadStorage.run(
1305
- { root, args, context, info, field: field2 },
1306
- () => field2["~meta"].resolve(args, this.resolverOptions)
1308
+ const outputType = this.getCacheType(
1309
+ getGraphQLType(field2["~meta"].output),
1310
+ fieldName
1307
1311
  );
1308
- return { resolve };
1312
+ const resolve = this.provideForResolve(field2, fieldName);
1313
+ const subscribe = this.provideForSubscribe(field2, fieldName);
1314
+ return {
1315
+ ...extract(field2),
1316
+ type: outputType,
1317
+ args: inputToArgs(field2["~meta"].input, {
1318
+ fieldName: fieldName ? parentName(this.name) + fieldName : void 0
1319
+ }),
1320
+ resolve,
1321
+ ...subscribe ? { subscribe } : {}
1322
+ };
1323
+ }
1324
+ provideForResolve(field2, fieldName) {
1325
+ const resolverMiddlewares = this.resolvers.get(fieldName)?.["~meta"].options?.middlewares;
1326
+ switch (field2["~meta"].operation) {
1327
+ case "query":
1328
+ case "mutation": {
1329
+ const operation = field2["~meta"].operation;
1330
+ const middlewares = filterMiddlewares(
1331
+ operation,
1332
+ this.globalOptions?.middlewares,
1333
+ resolverMiddlewares,
1334
+ field2["~meta"].middlewares
1335
+ );
1336
+ return (root, args, context, info) => {
1337
+ const payload = { root, args, context, info, field: field2 };
1338
+ const parseInput = createInputParser(field2["~meta"].input, args);
1339
+ return applyMiddlewares(
1340
+ {
1341
+ operation,
1342
+ outputSilk: field2["~meta"].output,
1343
+ parent: void 0,
1344
+ parseInput,
1345
+ payload
1346
+ },
1347
+ async () => field2["~meta"].resolve(await parseInput.getResult(), payload),
1348
+ middlewares
1349
+ );
1350
+ };
1351
+ }
1352
+ case "field": {
1353
+ const middlewares = filterMiddlewares(
1354
+ "field",
1355
+ this.globalOptions?.middlewares,
1356
+ resolverMiddlewares,
1357
+ field2["~meta"].middlewares
1358
+ );
1359
+ return (root, args, context, info) => {
1360
+ const payload = { root, args, context, info, field: field2 };
1361
+ const parseInput = createInputParser(field2["~meta"].input, args);
1362
+ return applyMiddlewares(
1363
+ {
1364
+ operation: "field",
1365
+ outputSilk: field2["~meta"].output,
1366
+ parent: root,
1367
+ parseInput,
1368
+ payload
1369
+ },
1370
+ async () => field2["~meta"].resolve(
1371
+ root,
1372
+ await parseInput.getResult(),
1373
+ payload
1374
+ ),
1375
+ middlewares
1376
+ );
1377
+ };
1378
+ }
1379
+ case "subscription": {
1380
+ const middlewares = filterMiddlewares(
1381
+ "subscription.resolve",
1382
+ this.globalOptions?.middlewares,
1383
+ resolverMiddlewares,
1384
+ field2["~meta"].middlewares
1385
+ );
1386
+ return (root, args, context, info) => {
1387
+ const payload = { root, args, context, info, field: field2 };
1388
+ const parseInput = createInputParser(field2["~meta"].input, args);
1389
+ return applyMiddlewares(
1390
+ {
1391
+ operation: "subscription.resolve",
1392
+ outputSilk: field2["~meta"].output,
1393
+ parent: root,
1394
+ parseInput,
1395
+ payload
1396
+ },
1397
+ async () => field2["~meta"].resolve(
1398
+ root,
1399
+ await parseInput.getResult(),
1400
+ payload
1401
+ ),
1402
+ middlewares
1403
+ );
1404
+ };
1405
+ }
1406
+ }
1309
1407
  }
1310
- provideForSubscribe(field2) {
1408
+ provideForSubscribe(field2, fieldName) {
1311
1409
  if (field2?.["~meta"]?.subscribe == null)
1312
1410
  return;
1313
- return {
1314
- subscribe: (root, args, context, info) => resolverPayloadStorage.run(
1315
- { root, args, context, info, field: field2 },
1316
- async () => {
1317
- const generator = await field2["~meta"].subscribe?.(args, this.resolverOptions);
1318
- return bindAsyncIterator(resolverPayloadStorage, generator);
1319
- }
1320
- )
1411
+ const resolverMiddlewares = this.resolvers.get(fieldName)?.["~meta"].options?.middlewares;
1412
+ const middlewares = filterMiddlewares(
1413
+ "subscription.subscribe",
1414
+ this.globalOptions?.middlewares,
1415
+ resolverMiddlewares,
1416
+ field2["~meta"].middlewares
1417
+ );
1418
+ return (source, args, context, info) => {
1419
+ const payload = { root: source, args, context, info, field: field2 };
1420
+ const parseInput = createInputParser(field2["~meta"].input, args);
1421
+ return applyMiddlewares(
1422
+ {
1423
+ operation: "subscription.subscribe",
1424
+ outputSilk: field2["~meta"].output,
1425
+ parent: void 0,
1426
+ parseInput,
1427
+ payload
1428
+ },
1429
+ async () => field2["~meta"].subscribe(
1430
+ await parseInput.getResult(),
1431
+ payload
1432
+ ),
1433
+ middlewares
1434
+ );
1321
1435
  };
1322
1436
  }
1323
1437
  getCacheType(gqlType, fieldName) {
1324
1438
  return getCacheType(gqlType, { ...this.options, fieldName, parent: this });
1325
1439
  }
1326
1440
  get options() {
1327
- const { resolverOptions, weaverContext: weaverContext2 } = this;
1441
+ const { globalOptions: resolverOptions, weaverContext: weaverContext2 } = this;
1328
1442
  return { resolverOptions, weaverContext: weaverContext2 };
1329
1443
  }
1330
1444
  };
@@ -1527,12 +1641,12 @@ var GraphQLSchemaLoom = class _GraphQLSchemaLoom {
1527
1641
  parentObject.hideField(name);
1528
1642
  } else if (field2["~meta"].operation === "field") {
1529
1643
  if (parentObject == null) return;
1530
- parentObject.addField(name, field2);
1644
+ parentObject.addField(name, field2, resolver2);
1531
1645
  } else {
1532
1646
  const operationObject = this.getOperationObject(
1533
1647
  field2["~meta"].operation
1534
1648
  );
1535
- operationObject.addField(name, field2);
1649
+ operationObject.addField(name, field2, resolver2);
1536
1650
  }
1537
1651
  });
1538
1652
  return this;
@@ -1564,7 +1678,7 @@ var GraphQLSchemaLoom = class _GraphQLSchemaLoom {
1564
1678
  }
1565
1679
  get fieldOptions() {
1566
1680
  const { resolverOptions, context } = this;
1567
- return { resolverOptions, weaverContext: context };
1681
+ return { globalOptions: resolverOptions, weaverContext: context };
1568
1682
  }
1569
1683
  static optionsFrom(...inputs) {
1570
1684
  const configs = /* @__PURE__ */ new Set();
@@ -1574,6 +1688,7 @@ var GraphQLSchemaLoom = class _GraphQLSchemaLoom {
1574
1688
  const weavers = /* @__PURE__ */ new Set();
1575
1689
  let context;
1576
1690
  for (const item of inputs) {
1691
+ if (item == null) continue;
1577
1692
  if (isSchemaVendorWeaver(item)) {
1578
1693
  weavers.add(item);
1579
1694
  } else if (typeof item === "function") {
@@ -1642,7 +1757,6 @@ function ensureInterfaceType(gqlType, interfaceConfig) {
1642
1757
  export {
1643
1758
  BaseChainFactory,
1644
1759
  ChainResolver,
1645
- ContextMemoization,
1646
1760
  EasyDataLoader,
1647
1761
  FieldChainFactory,
1648
1762
  FieldFactoryWithResolve,
@@ -1657,13 +1771,12 @@ export {
1657
1771
  symbols_exports as SYMBOLS,
1658
1772
  SubscriptionChainFactory,
1659
1773
  applyMiddlewares,
1774
+ assignContextMap,
1660
1775
  capitalize,
1661
1776
  collectName,
1662
1777
  collectNames,
1663
- compose,
1664
1778
  createField,
1665
1779
  createInputParser,
1666
- createMemoization,
1667
1780
  createMutation,
1668
1781
  createQuery,
1669
1782
  createSubscription,
@@ -1673,10 +1786,13 @@ export {
1673
1786
  ensureInputType,
1674
1787
  ensureInterfaceType,
1675
1788
  field,
1789
+ filterMiddlewares,
1676
1790
  getCacheType,
1677
1791
  getFieldOptions,
1678
1792
  getGraphQLType,
1793
+ getMemoizationMap,
1679
1794
  getOperationOptions,
1795
+ getResolvingFields,
1680
1796
  getStandardValue,
1681
1797
  getSubscriptionOptions,
1682
1798
  initWeaverContext,
@@ -1696,19 +1812,17 @@ export {
1696
1812
  nullableSilk,
1697
1813
  onlyMemoization,
1698
1814
  parseInputValue,
1815
+ parseResolvingFields,
1699
1816
  parseSilk,
1700
1817
  pascalCase,
1701
1818
  provideWeaverContext,
1702
1819
  query,
1703
1820
  resolver,
1704
- resolverPayloadStorage,
1821
+ screamingSnakeCase,
1705
1822
  silk,
1706
1823
  subscription,
1707
1824
  toObjMap,
1708
1825
  tryIn,
1709
- useContext,
1710
- useMemoizationMap,
1711
- useResolverPayload,
1712
1826
  weave,
1713
1827
  weaverContext
1714
1828
  };