@gqloom/core 0.8.4 → 0.9.1

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,23 @@ 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;
92
- }
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);
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
+ }, []);
98
69
  }
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);
70
+ function ensureArray(value) {
71
+ if (value != null && typeof value === "object" && Symbol.iterator in value) {
72
+ return Array.from(value);
119
73
  }
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
- });
74
+ return [value];
163
75
  }
164
76
 
165
77
  // src/utils/object.ts
@@ -596,9 +508,16 @@ function getStandardValue(result) {
596
508
 
597
509
  // src/resolver/resolver-chain-factory.ts
598
510
  var BaseChainFactory = class _BaseChainFactory {
511
+ /**
512
+ * Creates a new instance of the chain factory
513
+ * @param options - Configuration options for the factory
514
+ */
599
515
  constructor(options) {
600
516
  this.options = options;
601
517
  }
518
+ /**
519
+ * Returns the available methods for the chain factory
520
+ */
602
521
  static methods() {
603
522
  return {
604
523
  description: _BaseChainFactory.prototype.description,
@@ -606,15 +525,31 @@ var BaseChainFactory = class _BaseChainFactory {
606
525
  extensions: _BaseChainFactory.prototype.extensions
607
526
  };
608
527
  }
528
+ /**
529
+ * Sets the description for the field
530
+ * @param description - The description text
531
+ */
609
532
  description(description) {
610
533
  return this.clone({ description });
611
534
  }
535
+ /**
536
+ * Sets the deprecation reason for the field
537
+ * @param deprecationReason - The reason for deprecation
538
+ */
612
539
  deprecationReason(deprecationReason) {
613
540
  return this.clone({ deprecationReason });
614
541
  }
542
+ /**
543
+ * Sets custom extensions for the field
544
+ * @param extensions - Custom extensions to add
545
+ */
615
546
  extensions(extensions) {
616
547
  return this.clone({ extensions });
617
548
  }
549
+ /**
550
+ * Adds middleware functions to the field
551
+ * @param middlewares - Middleware functions to add
552
+ */
618
553
  use(...middlewares) {
619
554
  return this.clone({
620
555
  middlewares: [...this.options?.middlewares ?? [], ...middlewares]
@@ -622,6 +557,9 @@ var BaseChainFactory = class _BaseChainFactory {
622
557
  }
623
558
  };
624
559
  var FieldChainFactory = class _FieldChainFactory extends BaseChainFactory {
560
+ /**
561
+ * Returns the available methods for the field chain factory
562
+ */
625
563
  static methods() {
626
564
  return {
627
565
  ...BaseChainFactory.methods(),
@@ -631,15 +569,42 @@ var FieldChainFactory = class _FieldChainFactory extends BaseChainFactory {
631
569
  clone: _FieldChainFactory.prototype.clone
632
570
  };
633
571
  }
572
+ /**
573
+ * Creates a clone of the current factory with new options
574
+ * @param options - New options to apply to the clone
575
+ */
634
576
  clone(options) {
635
577
  return new _FieldChainFactory({ ...this.options, ...options });
636
578
  }
579
+ /**
580
+ * Sets the output type for the field
581
+ * @template TOutputNew - The new output type
582
+ * @param output - The output type definition
583
+ */
637
584
  output(output) {
638
585
  return new _FieldChainFactory({ ...this.options, output });
639
586
  }
587
+ /**
588
+ * Sets the input type for the field
589
+ * @template TInputNew - The new input type
590
+ * @param input - The input type definition
591
+ */
640
592
  input(input) {
641
593
  return new _FieldChainFactory({ ...this.options, input });
642
594
  }
595
+ /**
596
+ * Specifies the dependencies for the field
597
+ * @template TDependencies - The dependencies type
598
+ * @param dependencies - The dependencies to add
599
+ */
600
+ derivedFrom(...dependencies) {
601
+ return this.clone({ dependencies });
602
+ }
603
+ /**
604
+ * Sets the resolve function for the field
605
+ * @template TParent - The parent type
606
+ * @param resolve - The resolve function
607
+ */
643
608
  resolve(resolve) {
644
609
  if (!this.options?.output) throw new Error("Output is required");
645
610
  return createField(this.options.output, {
@@ -647,40 +612,47 @@ var FieldChainFactory = class _FieldChainFactory extends BaseChainFactory {
647
612
  resolve
648
613
  });
649
614
  }
615
+ /**
616
+ * Creates a field resolver that uses DataLoader for batch loading data.
617
+ * This method is particularly useful for optimizing performance when dealing with multiple data requests
618
+ * by batching them together and handling caching automatically.
619
+ *
620
+ * @template TParent - The parent type that extends GraphQLSilk
621
+ * @param resolve - A function that handles batch loading of data. The function receives:
622
+ * - When no input type is defined: An array of parent objects
623
+ * - When input type is defined: An array of tuples containing [parent, input]
624
+ * - An array of resolver payloads
625
+ * @returns A GraphQL field resolver that implements batch loading
626
+ */
650
627
  load(resolve) {
651
628
  if (!this.options?.output) throw new Error("Output is required");
652
- const useUnifiedParseInput = createMemoization(() => ({ current: void 0 }));
653
- const useUserLoader = createMemoization(
654
- () => new EasyDataLoader(
655
- async (parents) => resolve(
656
- parents,
657
- await useUnifiedParseInput().current?.getResult()
658
- )
659
- )
660
- );
661
- const operation = "field";
662
- return meta({
663
- ...getFieldOptions(this.options),
664
- operation,
665
- input: this.options.input,
666
- output: this.options.output,
667
- resolve: async (parent, inputValue, extraOptions) => {
668
- const unifiedParseInput = useUnifiedParseInput();
669
- unifiedParseInput.current ??= createInputParser(
670
- this.options?.input,
671
- inputValue
672
- );
673
- const parseInput = unifiedParseInput.current;
674
- return applyMiddlewares(
675
- compose(extraOptions?.middlewares, this.options?.middlewares),
676
- async () => useUserLoader().load(parent),
677
- { parseInput, parent, outputSilk: this.output, operation }
678
- );
629
+ const hasInput = typeof this.options.input !== "undefined";
630
+ const initLoader = () => new EasyDataLoader((args) => {
631
+ const parents = args.map(
632
+ ([parent, input]) => hasInput ? [parent, input] : parent
633
+ );
634
+ const payloads = args.map(([, , payload]) => payload);
635
+ return resolve(parents, payloads);
636
+ });
637
+ return createField(this.options.output, {
638
+ ...this.options,
639
+ resolve: (parent, input, payload) => {
640
+ const loader = (() => {
641
+ if (!payload) return initLoader();
642
+ const memoMap = getMemoizationMap(payload);
643
+ if (!memoMap.has(resolve)) memoMap.set(resolve, initLoader());
644
+ return memoMap.get(resolve);
645
+ })();
646
+ return loader.load([parent, input, payload]);
679
647
  }
680
648
  });
681
649
  }
682
650
  };
683
651
  var QueryChainFactory = class _QueryChainFactory extends BaseChainFactory {
652
+ /**
653
+ * Returns the available methods for the query chain factory
654
+ * @returns An object containing all available methods
655
+ */
684
656
  static methods() {
685
657
  return {
686
658
  ...BaseChainFactory.methods(),
@@ -690,15 +662,38 @@ var QueryChainFactory = class _QueryChainFactory extends BaseChainFactory {
690
662
  clone: _QueryChainFactory.prototype.clone
691
663
  };
692
664
  }
665
+ /**
666
+ * Creates a clone of the current factory with new options
667
+ * @param options - New options to apply to the clone
668
+ * @returns A new instance of QueryChainFactory with the updated options
669
+ */
693
670
  clone(options) {
694
671
  return new _QueryChainFactory({ ...this.options, ...options });
695
672
  }
673
+ /**
674
+ * Sets the output type for the query
675
+ * @template TOutputNew - The new output type
676
+ * @param output - The output type definition
677
+ * @returns A new QueryChainFactory instance with the updated output type
678
+ */
696
679
  output(output) {
697
680
  return new _QueryChainFactory({ ...this.options, output });
698
681
  }
682
+ /**
683
+ * Sets the input type for the query
684
+ * @template TInputNew - The new input type
685
+ * @param input - The input type definition
686
+ * @returns A new QueryChainFactory instance with the updated input type
687
+ */
699
688
  input(input) {
700
689
  return new _QueryChainFactory({ ...this.options, input });
701
690
  }
691
+ /**
692
+ * Sets the resolve function for the query
693
+ * @param resolve - The resolve function that processes the input and returns the output
694
+ * @returns A GraphQL query resolver
695
+ * @throws {Error} If output type is not set
696
+ */
702
697
  resolve(resolve) {
703
698
  if (!this.options?.output) throw new Error("Output is required");
704
699
  return createQuery(this.options.output, {
@@ -708,6 +703,10 @@ var QueryChainFactory = class _QueryChainFactory extends BaseChainFactory {
708
703
  }
709
704
  };
710
705
  var MutationChainFactory = class _MutationChainFactory extends BaseChainFactory {
706
+ /**
707
+ * Returns the available methods for the mutation chain factory
708
+ * @returns An object containing all available methods
709
+ */
711
710
  static methods() {
712
711
  return {
713
712
  ...BaseChainFactory.methods(),
@@ -717,15 +716,38 @@ var MutationChainFactory = class _MutationChainFactory extends BaseChainFactory
717
716
  clone: _MutationChainFactory.prototype.clone
718
717
  };
719
718
  }
719
+ /**
720
+ * Creates a clone of the current factory with new options
721
+ * @param options - New options to apply to the clone
722
+ * @returns A new instance of MutationChainFactory with the updated options
723
+ */
720
724
  clone(options) {
721
725
  return new _MutationChainFactory({ ...this.options, ...options });
722
726
  }
727
+ /**
728
+ * Sets the output type for the mutation
729
+ * @template TOutputNew - The new output type
730
+ * @param output - The output type definition
731
+ * @returns A new MutationChainFactory instance with the updated output type
732
+ */
723
733
  output(output) {
724
734
  return new _MutationChainFactory({ ...this.options, output });
725
735
  }
736
+ /**
737
+ * Sets the input type for the mutation
738
+ * @template TInputNew - The new input type
739
+ * @param input - The input type definition
740
+ * @returns A new MutationChainFactory instance with the updated input type
741
+ */
726
742
  input(input) {
727
743
  return new _MutationChainFactory({ ...this.options, input });
728
744
  }
745
+ /**
746
+ * Sets the resolve function for the mutation
747
+ * @param resolve - The resolve function that processes the input and returns the output
748
+ * @returns A GraphQL mutation resolver
749
+ * @throws {Error} If output type is not set
750
+ */
729
751
  resolve(resolve) {
730
752
  if (!this.options?.output) throw new Error("Output is required");
731
753
  return createMutation(this.options.output, {
@@ -735,6 +757,10 @@ var MutationChainFactory = class _MutationChainFactory extends BaseChainFactory
735
757
  }
736
758
  };
737
759
  var SubscriptionChainFactory = class _SubscriptionChainFactory extends BaseChainFactory {
760
+ /**
761
+ * Returns the available methods for the subscription chain factory
762
+ * @returns An object containing all available methods
763
+ */
738
764
  static methods() {
739
765
  return {
740
766
  ...BaseChainFactory.methods(),
@@ -744,15 +770,39 @@ var SubscriptionChainFactory = class _SubscriptionChainFactory extends BaseChain
744
770
  clone: _SubscriptionChainFactory.prototype.clone
745
771
  };
746
772
  }
773
+ /**
774
+ * Creates a clone of the current factory with new options
775
+ * @param options - New options to apply to the clone
776
+ * @returns A new instance of SubscriptionChainFactory with the updated options
777
+ */
747
778
  clone(options) {
748
779
  return new _SubscriptionChainFactory({ ...this.options, ...options });
749
780
  }
781
+ /**
782
+ * Sets the output type for the subscription
783
+ * @template TOutputNew - The new output type
784
+ * @param output - The output type definition
785
+ * @returns A new SubscriptionChainFactory instance with the updated output type
786
+ */
750
787
  output(output) {
751
788
  return new _SubscriptionChainFactory({ ...this.options, output });
752
789
  }
790
+ /**
791
+ * Sets the input type for the subscription
792
+ * @template TInputNew - The new input type
793
+ * @param input - The input type definition
794
+ * @returns A new SubscriptionChainFactory instance with the updated input type
795
+ */
753
796
  input(input) {
754
797
  return new _SubscriptionChainFactory({ ...this.options, input });
755
798
  }
799
+ /**
800
+ * Sets the subscribe function for the subscription
801
+ * @template TValue - The value type of the subscription
802
+ * @param subscribe - The subscribe function that returns an AsyncIterator
803
+ * @returns A subscription resolver that can be further configured with a resolve function
804
+ * @throws {Error} If output type is not set
805
+ */
756
806
  subscribe(subscribe) {
757
807
  const options = this.options;
758
808
  const output = this.options?.output;
@@ -842,20 +892,13 @@ var createQuery = (output, resolveOrOptions) => {
842
892
  return new QueryChainFactory({ output });
843
893
  }
844
894
  const options = getOperationOptions(resolveOrOptions);
845
- const operation = "query";
846
895
  return meta({
847
896
  ...getFieldOptions(options),
848
897
  input: options.input,
849
898
  output,
850
- resolve: (inputValue, extraOptions) => {
851
- const parseInput = createInputParser(options.input, inputValue);
852
- return applyMiddlewares(
853
- compose(extraOptions?.middlewares, options.middlewares),
854
- async () => options.resolve(getStandardValue(await parseInput())),
855
- { parseInput, parent: void 0, outputSilk: output, operation }
856
- );
857
- },
858
- operation
899
+ resolve: options.resolve,
900
+ middlewares: options.middlewares,
901
+ operation: "query"
859
902
  });
860
903
  };
861
904
  var query = Object.assign(
@@ -867,20 +910,13 @@ var createMutation = (output, resolveOrOptions) => {
867
910
  return new MutationChainFactory({ output });
868
911
  }
869
912
  const options = getOperationOptions(resolveOrOptions);
870
- const operation = "mutation";
871
913
  return meta({
872
914
  ...getFieldOptions(options),
873
915
  input: options.input,
874
916
  output,
875
- resolve: (inputValue, extraOptions) => {
876
- const parseInput = createInputParser(options.input, inputValue);
877
- return applyMiddlewares(
878
- compose(extraOptions?.middlewares, options.middlewares),
879
- async () => options.resolve(getStandardValue(await parseInput())),
880
- { parseInput, parent: void 0, outputSilk: output, operation }
881
- );
882
- },
883
- operation
917
+ resolve: options.resolve,
918
+ middlewares: options.middlewares,
919
+ operation: "mutation"
884
920
  });
885
921
  };
886
922
  var mutation = Object.assign(
@@ -892,20 +928,16 @@ var createField = (output, resolveOrOptions) => {
892
928
  return new FieldChainFactory({ output });
893
929
  }
894
930
  const options = getOperationOptions(resolveOrOptions);
895
- const operation = "field";
896
931
  return meta({
897
- ...getFieldOptions(options),
932
+ ...getFieldOptions(options, {
933
+ [DERIVED_DEPENDENCIES]: options.dependencies
934
+ }),
898
935
  input: options.input,
936
+ dependencies: options.dependencies,
899
937
  output,
900
- resolve: (parent, inputValue, extraOptions) => {
901
- const parseInput = createInputParser(options.input, inputValue);
902
- return applyMiddlewares(
903
- compose(extraOptions?.middlewares, options.middlewares),
904
- async () => options.resolve(parent, getStandardValue(await parseInput())),
905
- { parseInput, parent, outputSilk: output, operation }
906
- );
907
- },
908
- operation
938
+ resolve: options.resolve,
939
+ middlewares: options.middlewares,
940
+ operation: "field"
909
941
  });
910
942
  };
911
943
  var field = Object.assign(
@@ -919,72 +951,20 @@ function createSubscription(output, subscribeOrOptions) {
919
951
  return new SubscriptionChainFactory({ output });
920
952
  }
921
953
  const options = getSubscriptionOptions(subscribeOrOptions);
922
- const operation = "subscription";
923
954
  return meta({
924
955
  ...getFieldOptions(options),
925
956
  input: options.input,
926
957
  output,
927
- subscribe: (inputValue, extraOptions) => {
928
- const parseInput = createInputParser(options.input, inputValue);
929
- return applyMiddlewares(
930
- compose(
931
- extraOptions?.middlewares,
932
- options.middlewares
933
- ),
934
- async () => options.subscribe(getStandardValue(await parseInput())),
935
- { parseInput, parent: void 0, outputSilk: output, operation }
936
- );
937
- },
958
+ subscribe: options.subscribe,
938
959
  resolve: options.resolve ?? defaultSubscriptionResolve,
939
- operation
960
+ middlewares: options.middlewares,
961
+ operation: "subscription"
940
962
  });
941
963
  }
942
964
  var subscription = Object.assign(
943
965
  createSubscription,
944
966
  SubscriptionChainFactory.methods()
945
967
  );
946
- function extraOperationOptions(field2, options) {
947
- if (typeof field2 === "symbol") return field2;
948
- const composeMiddlewares = (extraOptions) => compose(extraOptions?.middlewares, options?.middlewares);
949
- switch (field2["~meta"].operation) {
950
- case "field":
951
- return {
952
- ...field2,
953
- "~meta": {
954
- ...field2["~meta"],
955
- resolve: (parent, input, extraOptions) => field2["~meta"].resolve(parent, input, {
956
- ...extraOptions,
957
- middlewares: composeMiddlewares(extraOptions)
958
- })
959
- }
960
- };
961
- case "subscription":
962
- return {
963
- ...field2,
964
- "~meta": {
965
- ...field2["~meta"],
966
- subscribe: (input, extraOptions) => field2["~meta"].subscribe(
967
- input,
968
- {
969
- ...extraOptions,
970
- middlewares: composeMiddlewares(extraOptions)
971
- }
972
- )
973
- }
974
- };
975
- default:
976
- return {
977
- ...field2,
978
- "~meta": {
979
- ...field2["~meta"],
980
- resolve: (input, extraOptions) => field2["~meta"].resolve(input, {
981
- ...extraOptions,
982
- middlewares: composeMiddlewares(extraOptions)
983
- })
984
- }
985
- };
986
- }
987
- }
988
968
  var resolver = Object.assign(
989
969
  (operations, options) => new ChainResolver(operations, options),
990
970
  {
@@ -1004,6 +984,11 @@ var loom = {
1004
984
  };
1005
985
  var ChainResolver = class {
1006
986
  meta;
987
+ /**
988
+ * Creates a new chain resolver
989
+ * @param fields - The fields or operations to resolve
990
+ * @param options - Optional resolver options
991
+ */
1007
992
  constructor(fields, options) {
1008
993
  this.meta = {
1009
994
  [IS_RESOLVER]: true,
@@ -1011,38 +996,83 @@ var ChainResolver = class {
1011
996
  options
1012
997
  };
1013
998
  }
999
+ /**
1000
+ * Gets the metadata for the resolver
1001
+ */
1014
1002
  get "~meta"() {
1015
- const fields = {};
1016
- Object.entries(this.meta.fields).forEach(([name, field2]) => {
1017
- if (field2 === FIELD_HIDDEN) {
1018
- fields[name] = field2;
1019
- } else {
1020
- fields[name] = extraOperationOptions(field2, this.meta.options);
1021
- }
1022
- });
1023
- return {
1024
- ...this.meta,
1025
- fields
1026
- };
1003
+ return this.meta;
1027
1004
  }
1005
+ /**
1006
+ * Adds middleware functions to the resolver
1007
+ * @param middlewares - The middleware functions to add
1008
+ */
1028
1009
  use(...middlewares) {
1029
1010
  this.meta.options ??= {};
1030
1011
  this.meta.options.middlewares ??= [];
1031
1012
  this.meta.options.middlewares.push(...middlewares);
1032
1013
  return this;
1033
1014
  }
1034
- toExecutor() {
1035
- const fields = this["~meta"].fields;
1036
- const executor = {};
1037
- Object.entries(fields).forEach(([name, field2]) => {
1038
- if (field2 === FIELD_HIDDEN) return;
1039
- executor[name] = field2["~meta"].resolve;
1040
- });
1015
+ toExecutor(...middlewares) {
1016
+ const executor = mapValue(
1017
+ this["~meta"].fields,
1018
+ (field2) => this.toExecutorOperation(field2, middlewares) ?? mapValue.SKIP
1019
+ );
1041
1020
  return executor;
1042
1021
  }
1022
+ toExecutorOperation(field2, executorMiddlewares) {
1023
+ if (field2 === FIELD_HIDDEN || field2["~meta"].operation === "subscription") {
1024
+ return void 0;
1025
+ }
1026
+ const operation = field2["~meta"].operation;
1027
+ const middlewares = filterMiddlewares(
1028
+ operation,
1029
+ executorMiddlewares,
1030
+ this.meta.options?.middlewares,
1031
+ field2["~meta"].middlewares
1032
+ );
1033
+ if (field2["~meta"].operation === "field") {
1034
+ const resolve = field2["~meta"].resolve;
1035
+ return (parent, args, payload) => {
1036
+ const parseInput = createInputParser(field2["~meta"].input, args);
1037
+ return applyMiddlewares(
1038
+ {
1039
+ outputSilk: field2["~meta"].output,
1040
+ parent,
1041
+ payload,
1042
+ parseInput,
1043
+ operation
1044
+ },
1045
+ async () => resolve(parent, await parseInput.getResult(), payload),
1046
+ middlewares
1047
+ );
1048
+ };
1049
+ } else {
1050
+ const resolve = field2["~meta"].resolve;
1051
+ return (args, payload) => {
1052
+ const parseInput = createInputParser(field2["~meta"].input, args);
1053
+ return applyMiddlewares(
1054
+ {
1055
+ outputSilk: field2["~meta"].output,
1056
+ parent: void 0,
1057
+ payload,
1058
+ parseInput,
1059
+ operation
1060
+ },
1061
+ async () => resolve(await parseInput.getResult(), payload),
1062
+ middlewares
1063
+ );
1064
+ };
1065
+ }
1066
+ }
1043
1067
  };
1044
1068
  var ObjectChainResolver = class extends ChainResolver {
1045
1069
  meta;
1070
+ /**
1071
+ * Creates a new object chain resolver
1072
+ * @param parent - The parent type definition
1073
+ * @param fields - The fields to resolve
1074
+ * @param options - Optional resolver options
1075
+ */
1046
1076
  constructor(parent, fields, options) {
1047
1077
  super(fields, options);
1048
1078
  this.meta = {
@@ -1052,9 +1082,16 @@ var ObjectChainResolver = class extends ChainResolver {
1052
1082
  options
1053
1083
  };
1054
1084
  }
1085
+ /**
1086
+ * Gets the metadata for the resolver
1087
+ */
1055
1088
  get "~meta"() {
1056
1089
  return super["~meta"];
1057
1090
  }
1091
+ /**
1092
+ * Sets custom extensions for the resolver
1093
+ * @param extensions - The extensions to add
1094
+ */
1058
1095
  extensions(extensions) {
1059
1096
  this.meta.options ??= {};
1060
1097
  this.meta.options.extensions ??= {};
@@ -1080,17 +1117,6 @@ import {
1080
1117
  resolveObjMapThunk
1081
1118
  } from "graphql";
1082
1119
 
1083
- // src/utils/async-iterator.ts
1084
- function bindAsyncIterator(storage, generator) {
1085
- const store = storage.getStore();
1086
- const next = generator.next;
1087
- Object.defineProperty(generator, "next", {
1088
- value: (...args) => storage.run(store, () => next.apply(generator, args)),
1089
- writable: false
1090
- });
1091
- return generator;
1092
- }
1093
-
1094
1120
  // src/schema/input.ts
1095
1121
  import {
1096
1122
  GraphQLInputObjectType,
@@ -1195,7 +1221,11 @@ var LoomObjectType = class _LoomObjectType extends GraphQLObjectType {
1195
1221
  hiddenFields = /* @__PURE__ */ new Set();
1196
1222
  static AUTO_ALIASING = "__gqloom_auto_aliasing";
1197
1223
  weaverContext;
1198
- resolverOptions;
1224
+ globalOptions;
1225
+ /**
1226
+ * field name -> resolver
1227
+ */
1228
+ resolvers;
1199
1229
  constructor(objectOrGetter, options = {}) {
1200
1230
  const origin = typeof objectOrGetter === "function" ? objectOrGetter() : objectOrGetter;
1201
1231
  const config = (() => {
@@ -1208,8 +1238,9 @@ var LoomObjectType = class _LoomObjectType extends GraphQLObjectType {
1208
1238
  }
1209
1239
  })();
1210
1240
  super(config);
1211
- this.resolverOptions = options.resolverOptions;
1241
+ this.globalOptions = options.globalOptions;
1212
1242
  this.weaverContext = options.weaverContext ?? initWeaverContext();
1243
+ this.resolvers = /* @__PURE__ */ new Map();
1213
1244
  if (this.name !== _LoomObjectType.AUTO_ALIASING) {
1214
1245
  this.hasExplicitName = true;
1215
1246
  }
@@ -1236,12 +1267,13 @@ var LoomObjectType = class _LoomObjectType extends GraphQLObjectType {
1236
1267
  hideField(name) {
1237
1268
  this.hiddenFields.add(name);
1238
1269
  }
1239
- addField(name, resolver2) {
1270
+ addField(name, field2, resolver2) {
1240
1271
  const existing = this.extraFields.get(name);
1241
- if (existing && existing !== resolver2) {
1272
+ if (existing && existing !== field2) {
1242
1273
  throw new Error(`Field ${name} already exists in ${this.name}`);
1243
1274
  }
1244
- this.extraFields.set(name, resolver2);
1275
+ this.extraFields.set(name, field2);
1276
+ if (resolver2) this.resolvers.set(name, resolver2);
1245
1277
  }
1246
1278
  mergeExtensions(extensions) {
1247
1279
  this.extensions = deepMerge(this.extensions, extensions);
@@ -1276,58 +1308,140 @@ var LoomObjectType = class _LoomObjectType extends GraphQLObjectType {
1276
1308
  return record;
1277
1309
  }
1278
1310
  toFieldConfig(field2, fieldName) {
1279
- try {
1280
- const outputType = this.getCacheType(
1281
- getGraphQLType(field2["~meta"].output),
1282
- fieldName
1283
- );
1284
- return {
1285
- ...extract(field2),
1286
- type: outputType,
1287
- args: inputToArgs(field2["~meta"].input, {
1288
- fieldName: fieldName ? parentName(this.name) + fieldName : void 0
1289
- }),
1290
- ...this.provideForResolve(field2),
1291
- ...this.provideForSubscribe(field2)
1292
- };
1293
- } catch (error) {
1294
- throw markErrorLocation(error);
1295
- }
1296
- }
1297
- provideForResolve(field2) {
1298
- if (field2?.["~meta"]?.resolve == null) return;
1299
- if (field2["~meta"].resolve === defaultSubscriptionResolve)
1300
- return { resolve: defaultSubscriptionResolve };
1301
- const resolve = field2["~meta"].operation === "field" ? (root, args, context, info) => resolverPayloadStorage.run(
1302
- { root, args, context, info, field: field2 },
1303
- () => field2["~meta"].resolve(root, args, this.resolverOptions)
1304
- ) : field2["~meta"].operation === "subscription" ? (root, args, context, info) => resolverPayloadStorage.run(
1305
- { root, args, context, info, field: field2 },
1306
- () => field2["~meta"].resolve(root, args)
1307
- ) : (root, args, context, info) => resolverPayloadStorage.run(
1308
- { root, args, context, info, field: field2 },
1309
- () => field2["~meta"].resolve(args, this.resolverOptions)
1311
+ const outputType = this.getCacheType(
1312
+ getGraphQLType(field2["~meta"].output),
1313
+ fieldName
1310
1314
  );
1311
- return { resolve };
1315
+ const resolve = this.provideForResolve(field2, fieldName);
1316
+ const subscribe = this.provideForSubscribe(field2, fieldName);
1317
+ return {
1318
+ ...extract(field2),
1319
+ type: outputType,
1320
+ args: inputToArgs(field2["~meta"].input, {
1321
+ fieldName: fieldName ? parentName(this.name) + fieldName : void 0
1322
+ }),
1323
+ resolve,
1324
+ ...subscribe ? { subscribe } : {}
1325
+ };
1326
+ }
1327
+ provideForResolve(field2, fieldName) {
1328
+ const resolverMiddlewares = this.resolvers.get(fieldName)?.["~meta"].options?.middlewares;
1329
+ switch (field2["~meta"].operation) {
1330
+ case "query":
1331
+ case "mutation": {
1332
+ const operation = field2["~meta"].operation;
1333
+ const middlewares = filterMiddlewares(
1334
+ operation,
1335
+ this.globalOptions?.middlewares,
1336
+ resolverMiddlewares,
1337
+ field2["~meta"].middlewares
1338
+ );
1339
+ return (root, args, context, info) => {
1340
+ const payload = { root, args, context, info, field: field2 };
1341
+ const parseInput = createInputParser(field2["~meta"].input, args);
1342
+ return applyMiddlewares(
1343
+ {
1344
+ operation,
1345
+ outputSilk: field2["~meta"].output,
1346
+ parent: void 0,
1347
+ parseInput,
1348
+ payload
1349
+ },
1350
+ async () => field2["~meta"].resolve(await parseInput.getResult(), payload),
1351
+ middlewares
1352
+ );
1353
+ };
1354
+ }
1355
+ case "field": {
1356
+ const middlewares = filterMiddlewares(
1357
+ "field",
1358
+ this.globalOptions?.middlewares,
1359
+ resolverMiddlewares,
1360
+ field2["~meta"].middlewares
1361
+ );
1362
+ return (root, args, context, info) => {
1363
+ const payload = { root, args, context, info, field: field2 };
1364
+ const parseInput = createInputParser(field2["~meta"].input, args);
1365
+ return applyMiddlewares(
1366
+ {
1367
+ operation: "field",
1368
+ outputSilk: field2["~meta"].output,
1369
+ parent: root,
1370
+ parseInput,
1371
+ payload
1372
+ },
1373
+ async () => field2["~meta"].resolve(
1374
+ root,
1375
+ await parseInput.getResult(),
1376
+ payload
1377
+ ),
1378
+ middlewares
1379
+ );
1380
+ };
1381
+ }
1382
+ case "subscription": {
1383
+ const middlewares = filterMiddlewares(
1384
+ "subscription.resolve",
1385
+ this.globalOptions?.middlewares,
1386
+ resolverMiddlewares,
1387
+ field2["~meta"].middlewares
1388
+ );
1389
+ return (root, args, context, info) => {
1390
+ const payload = { root, args, context, info, field: field2 };
1391
+ const parseInput = createInputParser(field2["~meta"].input, args);
1392
+ return applyMiddlewares(
1393
+ {
1394
+ operation: "subscription.resolve",
1395
+ outputSilk: field2["~meta"].output,
1396
+ parent: root,
1397
+ parseInput,
1398
+ payload
1399
+ },
1400
+ async () => field2["~meta"].resolve(
1401
+ root,
1402
+ await parseInput.getResult(),
1403
+ payload
1404
+ ),
1405
+ middlewares
1406
+ );
1407
+ };
1408
+ }
1409
+ }
1312
1410
  }
1313
- provideForSubscribe(field2) {
1411
+ provideForSubscribe(field2, fieldName) {
1314
1412
  if (field2?.["~meta"]?.subscribe == null)
1315
1413
  return;
1316
- return {
1317
- subscribe: (root, args, context, info) => resolverPayloadStorage.run(
1318
- { root, args, context, info, field: field2 },
1319
- async () => {
1320
- const generator = await field2["~meta"].subscribe?.(args, this.resolverOptions);
1321
- return bindAsyncIterator(resolverPayloadStorage, generator);
1322
- }
1323
- )
1414
+ const resolverMiddlewares = this.resolvers.get(fieldName)?.["~meta"].options?.middlewares;
1415
+ const middlewares = filterMiddlewares(
1416
+ "subscription.subscribe",
1417
+ this.globalOptions?.middlewares,
1418
+ resolverMiddlewares,
1419
+ field2["~meta"].middlewares
1420
+ );
1421
+ return (source, args, context, info) => {
1422
+ const payload = { root: source, args, context, info, field: field2 };
1423
+ const parseInput = createInputParser(field2["~meta"].input, args);
1424
+ return applyMiddlewares(
1425
+ {
1426
+ operation: "subscription.subscribe",
1427
+ outputSilk: field2["~meta"].output,
1428
+ parent: void 0,
1429
+ parseInput,
1430
+ payload
1431
+ },
1432
+ async () => field2["~meta"].subscribe(
1433
+ await parseInput.getResult(),
1434
+ payload
1435
+ ),
1436
+ middlewares
1437
+ );
1324
1438
  };
1325
1439
  }
1326
1440
  getCacheType(gqlType, fieldName) {
1327
1441
  return getCacheType(gqlType, { ...this.options, fieldName, parent: this });
1328
1442
  }
1329
1443
  get options() {
1330
- const { resolverOptions, weaverContext: weaverContext2 } = this;
1444
+ const { globalOptions: resolverOptions, weaverContext: weaverContext2 } = this;
1331
1445
  return { resolverOptions, weaverContext: weaverContext2 };
1332
1446
  }
1333
1447
  };
@@ -1459,8 +1573,11 @@ var GraphQLSchemaLoom = class _GraphQLSchemaLoom {
1459
1573
  this.resolverOptions.middlewares.push(...middlewares);
1460
1574
  return this;
1461
1575
  }
1462
- add(resolver2) {
1463
- provideWeaverContext(() => this.addResolver(resolver2), this.context);
1576
+ add(resolver2, modifyParent) {
1577
+ provideWeaverContext(
1578
+ () => this.addResolver(resolver2, modifyParent),
1579
+ this.context
1580
+ );
1464
1581
  return this;
1465
1582
  }
1466
1583
  addVendor(weaver) {
@@ -1503,10 +1620,10 @@ var GraphQLSchemaLoom = class _GraphQLSchemaLoom {
1503
1620
  });
1504
1621
  return schema;
1505
1622
  }
1506
- addResolver(resolver2) {
1623
+ addResolver(resolver2, modifyParent) {
1507
1624
  const resolverOptions = resolver2["~meta"].options;
1508
1625
  const parent = resolver2["~meta"].parent;
1509
- const parentObject = (() => {
1626
+ let parentObject = (() => {
1510
1627
  if (parent == null) return void 0;
1511
1628
  let gqlType = getGraphQLType(parent);
1512
1629
  if (isNonNullType3(gqlType)) gqlType = gqlType.ofType;
@@ -1524,18 +1641,20 @@ var GraphQLSchemaLoom = class _GraphQLSchemaLoom {
1524
1641
  })();
1525
1642
  if (resolverOptions?.extensions && parentObject)
1526
1643
  parentObject.mergeExtensions(resolverOptions.extensions);
1644
+ if (modifyParent != null && parentObject)
1645
+ parentObject = modifyParent(parentObject);
1527
1646
  Object.entries(resolver2["~meta"].fields).forEach(([name, field2]) => {
1528
1647
  if (field2 === FIELD_HIDDEN) {
1529
1648
  if (parentObject == null) return;
1530
1649
  parentObject.hideField(name);
1531
1650
  } else if (field2["~meta"].operation === "field") {
1532
1651
  if (parentObject == null) return;
1533
- parentObject.addField(name, field2);
1652
+ parentObject.addField(name, field2, resolver2);
1534
1653
  } else {
1535
1654
  const operationObject = this.getOperationObject(
1536
1655
  field2["~meta"].operation
1537
1656
  );
1538
- operationObject.addField(name, field2);
1657
+ operationObject.addField(name, field2, resolver2);
1539
1658
  }
1540
1659
  });
1541
1660
  return this;
@@ -1567,7 +1686,7 @@ var GraphQLSchemaLoom = class _GraphQLSchemaLoom {
1567
1686
  }
1568
1687
  get fieldOptions() {
1569
1688
  const { resolverOptions, context } = this;
1570
- return { resolverOptions, weaverContext: context };
1689
+ return { globalOptions: resolverOptions, weaverContext: context };
1571
1690
  }
1572
1691
  static optionsFrom(...inputs) {
1573
1692
  const configs = /* @__PURE__ */ new Set();
@@ -1577,6 +1696,7 @@ var GraphQLSchemaLoom = class _GraphQLSchemaLoom {
1577
1696
  const weavers = /* @__PURE__ */ new Set();
1578
1697
  let context;
1579
1698
  for (const item of inputs) {
1699
+ if (item == null) continue;
1580
1700
  if (isSchemaVendorWeaver(item)) {
1581
1701
  weavers.add(item);
1582
1702
  } else if (typeof item === "function") {
@@ -1645,7 +1765,6 @@ function ensureInterfaceType(gqlType, interfaceConfig) {
1645
1765
  export {
1646
1766
  BaseChainFactory,
1647
1767
  ChainResolver,
1648
- ContextMemoization,
1649
1768
  EasyDataLoader,
1650
1769
  FieldChainFactory,
1651
1770
  FieldFactoryWithResolve,
@@ -1660,13 +1779,12 @@ export {
1660
1779
  symbols_exports as SYMBOLS,
1661
1780
  SubscriptionChainFactory,
1662
1781
  applyMiddlewares,
1782
+ assignContextMap,
1663
1783
  capitalize,
1664
1784
  collectName,
1665
1785
  collectNames,
1666
- compose,
1667
1786
  createField,
1668
1787
  createInputParser,
1669
- createMemoization,
1670
1788
  createMutation,
1671
1789
  createQuery,
1672
1790
  createSubscription,
@@ -1676,10 +1794,13 @@ export {
1676
1794
  ensureInputType,
1677
1795
  ensureInterfaceType,
1678
1796
  field,
1797
+ filterMiddlewares,
1679
1798
  getCacheType,
1680
1799
  getFieldOptions,
1681
1800
  getGraphQLType,
1801
+ getMemoizationMap,
1682
1802
  getOperationOptions,
1803
+ getResolvingFields,
1683
1804
  getStandardValue,
1684
1805
  getSubscriptionOptions,
1685
1806
  initWeaverContext,
@@ -1699,20 +1820,17 @@ export {
1699
1820
  nullableSilk,
1700
1821
  onlyMemoization,
1701
1822
  parseInputValue,
1823
+ parseResolvingFields,
1702
1824
  parseSilk,
1703
1825
  pascalCase,
1704
1826
  provideWeaverContext,
1705
1827
  query,
1706
1828
  resolver,
1707
- resolverPayloadStorage,
1708
1829
  screamingSnakeCase,
1709
1830
  silk,
1710
1831
  subscription,
1711
1832
  toObjMap,
1712
1833
  tryIn,
1713
- useContext,
1714
- useMemoizationMap,
1715
- useResolverPayload,
1716
1834
  weave,
1717
1835
  weaverContext
1718
1836
  };