@gqloom/core 0.8.4 → 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
@@ -596,9 +505,16 @@ function getStandardValue(result) {
596
505
 
597
506
  // src/resolver/resolver-chain-factory.ts
598
507
  var BaseChainFactory = class _BaseChainFactory {
508
+ /**
509
+ * Creates a new instance of the chain factory
510
+ * @param options - Configuration options for the factory
511
+ */
599
512
  constructor(options) {
600
513
  this.options = options;
601
514
  }
515
+ /**
516
+ * Returns the available methods for the chain factory
517
+ */
602
518
  static methods() {
603
519
  return {
604
520
  description: _BaseChainFactory.prototype.description,
@@ -606,15 +522,31 @@ var BaseChainFactory = class _BaseChainFactory {
606
522
  extensions: _BaseChainFactory.prototype.extensions
607
523
  };
608
524
  }
525
+ /**
526
+ * Sets the description for the field
527
+ * @param description - The description text
528
+ */
609
529
  description(description) {
610
530
  return this.clone({ description });
611
531
  }
532
+ /**
533
+ * Sets the deprecation reason for the field
534
+ * @param deprecationReason - The reason for deprecation
535
+ */
612
536
  deprecationReason(deprecationReason) {
613
537
  return this.clone({ deprecationReason });
614
538
  }
539
+ /**
540
+ * Sets custom extensions for the field
541
+ * @param extensions - Custom extensions to add
542
+ */
615
543
  extensions(extensions) {
616
544
  return this.clone({ extensions });
617
545
  }
546
+ /**
547
+ * Adds middleware functions to the field
548
+ * @param middlewares - Middleware functions to add
549
+ */
618
550
  use(...middlewares) {
619
551
  return this.clone({
620
552
  middlewares: [...this.options?.middlewares ?? [], ...middlewares]
@@ -622,6 +554,9 @@ var BaseChainFactory = class _BaseChainFactory {
622
554
  }
623
555
  };
624
556
  var FieldChainFactory = class _FieldChainFactory extends BaseChainFactory {
557
+ /**
558
+ * Returns the available methods for the field chain factory
559
+ */
625
560
  static methods() {
626
561
  return {
627
562
  ...BaseChainFactory.methods(),
@@ -631,15 +566,42 @@ var FieldChainFactory = class _FieldChainFactory extends BaseChainFactory {
631
566
  clone: _FieldChainFactory.prototype.clone
632
567
  };
633
568
  }
569
+ /**
570
+ * Creates a clone of the current factory with new options
571
+ * @param options - New options to apply to the clone
572
+ */
634
573
  clone(options) {
635
574
  return new _FieldChainFactory({ ...this.options, ...options });
636
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
+ */
637
581
  output(output) {
638
582
  return new _FieldChainFactory({ ...this.options, output });
639
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
+ */
640
589
  input(input) {
641
590
  return new _FieldChainFactory({ ...this.options, input });
642
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
+ */
643
605
  resolve(resolve) {
644
606
  if (!this.options?.output) throw new Error("Output is required");
645
607
  return createField(this.options.output, {
@@ -647,40 +609,47 @@ var FieldChainFactory = class _FieldChainFactory extends BaseChainFactory {
647
609
  resolve
648
610
  });
649
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
+ */
650
624
  load(resolve) {
651
625
  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
- );
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]);
679
644
  }
680
645
  });
681
646
  }
682
647
  };
683
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
+ */
684
653
  static methods() {
685
654
  return {
686
655
  ...BaseChainFactory.methods(),
@@ -690,15 +659,38 @@ var QueryChainFactory = class _QueryChainFactory extends BaseChainFactory {
690
659
  clone: _QueryChainFactory.prototype.clone
691
660
  };
692
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
+ */
693
667
  clone(options) {
694
668
  return new _QueryChainFactory({ ...this.options, ...options });
695
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
+ */
696
676
  output(output) {
697
677
  return new _QueryChainFactory({ ...this.options, output });
698
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
+ */
699
685
  input(input) {
700
686
  return new _QueryChainFactory({ ...this.options, input });
701
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
+ */
702
694
  resolve(resolve) {
703
695
  if (!this.options?.output) throw new Error("Output is required");
704
696
  return createQuery(this.options.output, {
@@ -708,6 +700,10 @@ var QueryChainFactory = class _QueryChainFactory extends BaseChainFactory {
708
700
  }
709
701
  };
710
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
+ */
711
707
  static methods() {
712
708
  return {
713
709
  ...BaseChainFactory.methods(),
@@ -717,15 +713,38 @@ var MutationChainFactory = class _MutationChainFactory extends BaseChainFactory
717
713
  clone: _MutationChainFactory.prototype.clone
718
714
  };
719
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
+ */
720
721
  clone(options) {
721
722
  return new _MutationChainFactory({ ...this.options, ...options });
722
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
+ */
723
730
  output(output) {
724
731
  return new _MutationChainFactory({ ...this.options, output });
725
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
+ */
726
739
  input(input) {
727
740
  return new _MutationChainFactory({ ...this.options, input });
728
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
+ */
729
748
  resolve(resolve) {
730
749
  if (!this.options?.output) throw new Error("Output is required");
731
750
  return createMutation(this.options.output, {
@@ -735,6 +754,10 @@ var MutationChainFactory = class _MutationChainFactory extends BaseChainFactory
735
754
  }
736
755
  };
737
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
+ */
738
761
  static methods() {
739
762
  return {
740
763
  ...BaseChainFactory.methods(),
@@ -744,15 +767,39 @@ var SubscriptionChainFactory = class _SubscriptionChainFactory extends BaseChain
744
767
  clone: _SubscriptionChainFactory.prototype.clone
745
768
  };
746
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
+ */
747
775
  clone(options) {
748
776
  return new _SubscriptionChainFactory({ ...this.options, ...options });
749
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
+ */
750
784
  output(output) {
751
785
  return new _SubscriptionChainFactory({ ...this.options, output });
752
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
+ */
753
793
  input(input) {
754
794
  return new _SubscriptionChainFactory({ ...this.options, input });
755
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
+ */
756
803
  subscribe(subscribe) {
757
804
  const options = this.options;
758
805
  const output = this.options?.output;
@@ -842,20 +889,13 @@ var createQuery = (output, resolveOrOptions) => {
842
889
  return new QueryChainFactory({ output });
843
890
  }
844
891
  const options = getOperationOptions(resolveOrOptions);
845
- const operation = "query";
846
892
  return meta({
847
893
  ...getFieldOptions(options),
848
894
  input: options.input,
849
895
  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
896
+ resolve: options.resolve,
897
+ middlewares: options.middlewares,
898
+ operation: "query"
859
899
  });
860
900
  };
861
901
  var query = Object.assign(
@@ -867,20 +907,13 @@ var createMutation = (output, resolveOrOptions) => {
867
907
  return new MutationChainFactory({ output });
868
908
  }
869
909
  const options = getOperationOptions(resolveOrOptions);
870
- const operation = "mutation";
871
910
  return meta({
872
911
  ...getFieldOptions(options),
873
912
  input: options.input,
874
913
  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
914
+ resolve: options.resolve,
915
+ middlewares: options.middlewares,
916
+ operation: "mutation"
884
917
  });
885
918
  };
886
919
  var mutation = Object.assign(
@@ -892,20 +925,16 @@ var createField = (output, resolveOrOptions) => {
892
925
  return new FieldChainFactory({ output });
893
926
  }
894
927
  const options = getOperationOptions(resolveOrOptions);
895
- const operation = "field";
896
928
  return meta({
897
- ...getFieldOptions(options),
929
+ ...getFieldOptions(options, {
930
+ [DERIVED_DEPENDENCIES]: options.dependencies
931
+ }),
898
932
  input: options.input,
933
+ dependencies: options.dependencies,
899
934
  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
935
+ resolve: options.resolve,
936
+ middlewares: options.middlewares,
937
+ operation: "field"
909
938
  });
910
939
  };
911
940
  var field = Object.assign(
@@ -919,72 +948,20 @@ function createSubscription(output, subscribeOrOptions) {
919
948
  return new SubscriptionChainFactory({ output });
920
949
  }
921
950
  const options = getSubscriptionOptions(subscribeOrOptions);
922
- const operation = "subscription";
923
951
  return meta({
924
952
  ...getFieldOptions(options),
925
953
  input: options.input,
926
954
  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
- },
955
+ subscribe: options.subscribe,
938
956
  resolve: options.resolve ?? defaultSubscriptionResolve,
939
- operation
957
+ middlewares: options.middlewares,
958
+ operation: "subscription"
940
959
  });
941
960
  }
942
961
  var subscription = Object.assign(
943
962
  createSubscription,
944
963
  SubscriptionChainFactory.methods()
945
964
  );
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
965
  var resolver = Object.assign(
989
966
  (operations, options) => new ChainResolver(operations, options),
990
967
  {
@@ -1004,6 +981,11 @@ var loom = {
1004
981
  };
1005
982
  var ChainResolver = class {
1006
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
+ */
1007
989
  constructor(fields, options) {
1008
990
  this.meta = {
1009
991
  [IS_RESOLVER]: true,
@@ -1011,38 +993,83 @@ var ChainResolver = class {
1011
993
  options
1012
994
  };
1013
995
  }
996
+ /**
997
+ * Gets the metadata for the resolver
998
+ */
1014
999
  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
- };
1000
+ return this.meta;
1027
1001
  }
1002
+ /**
1003
+ * Adds middleware functions to the resolver
1004
+ * @param middlewares - The middleware functions to add
1005
+ */
1028
1006
  use(...middlewares) {
1029
1007
  this.meta.options ??= {};
1030
1008
  this.meta.options.middlewares ??= [];
1031
1009
  this.meta.options.middlewares.push(...middlewares);
1032
1010
  return this;
1033
1011
  }
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
- });
1012
+ toExecutor(...middlewares) {
1013
+ const executor = mapValue(
1014
+ this["~meta"].fields,
1015
+ (field2) => this.toExecutorOperation(field2, middlewares) ?? mapValue.SKIP
1016
+ );
1041
1017
  return executor;
1042
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
+ }
1043
1064
  };
1044
1065
  var ObjectChainResolver = class extends ChainResolver {
1045
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
+ */
1046
1073
  constructor(parent, fields, options) {
1047
1074
  super(fields, options);
1048
1075
  this.meta = {
@@ -1052,9 +1079,16 @@ var ObjectChainResolver = class extends ChainResolver {
1052
1079
  options
1053
1080
  };
1054
1081
  }
1082
+ /**
1083
+ * Gets the metadata for the resolver
1084
+ */
1055
1085
  get "~meta"() {
1056
1086
  return super["~meta"];
1057
1087
  }
1088
+ /**
1089
+ * Sets custom extensions for the resolver
1090
+ * @param extensions - The extensions to add
1091
+ */
1058
1092
  extensions(extensions) {
1059
1093
  this.meta.options ??= {};
1060
1094
  this.meta.options.extensions ??= {};
@@ -1080,17 +1114,6 @@ import {
1080
1114
  resolveObjMapThunk
1081
1115
  } from "graphql";
1082
1116
 
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
1117
  // src/schema/input.ts
1095
1118
  import {
1096
1119
  GraphQLInputObjectType,
@@ -1195,7 +1218,11 @@ var LoomObjectType = class _LoomObjectType extends GraphQLObjectType {
1195
1218
  hiddenFields = /* @__PURE__ */ new Set();
1196
1219
  static AUTO_ALIASING = "__gqloom_auto_aliasing";
1197
1220
  weaverContext;
1198
- resolverOptions;
1221
+ globalOptions;
1222
+ /**
1223
+ * field name -> resolver
1224
+ */
1225
+ resolvers;
1199
1226
  constructor(objectOrGetter, options = {}) {
1200
1227
  const origin = typeof objectOrGetter === "function" ? objectOrGetter() : objectOrGetter;
1201
1228
  const config = (() => {
@@ -1208,8 +1235,9 @@ var LoomObjectType = class _LoomObjectType extends GraphQLObjectType {
1208
1235
  }
1209
1236
  })();
1210
1237
  super(config);
1211
- this.resolverOptions = options.resolverOptions;
1238
+ this.globalOptions = options.globalOptions;
1212
1239
  this.weaverContext = options.weaverContext ?? initWeaverContext();
1240
+ this.resolvers = /* @__PURE__ */ new Map();
1213
1241
  if (this.name !== _LoomObjectType.AUTO_ALIASING) {
1214
1242
  this.hasExplicitName = true;
1215
1243
  }
@@ -1236,12 +1264,13 @@ var LoomObjectType = class _LoomObjectType extends GraphQLObjectType {
1236
1264
  hideField(name) {
1237
1265
  this.hiddenFields.add(name);
1238
1266
  }
1239
- addField(name, resolver2) {
1267
+ addField(name, field2, resolver2) {
1240
1268
  const existing = this.extraFields.get(name);
1241
- if (existing && existing !== resolver2) {
1269
+ if (existing && existing !== field2) {
1242
1270
  throw new Error(`Field ${name} already exists in ${this.name}`);
1243
1271
  }
1244
- this.extraFields.set(name, resolver2);
1272
+ this.extraFields.set(name, field2);
1273
+ if (resolver2) this.resolvers.set(name, resolver2);
1245
1274
  }
1246
1275
  mergeExtensions(extensions) {
1247
1276
  this.extensions = deepMerge(this.extensions, extensions);
@@ -1276,58 +1305,140 @@ var LoomObjectType = class _LoomObjectType extends GraphQLObjectType {
1276
1305
  return record;
1277
1306
  }
1278
1307
  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)
1308
+ const outputType = this.getCacheType(
1309
+ getGraphQLType(field2["~meta"].output),
1310
+ fieldName
1310
1311
  );
1311
- 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
+ }
1312
1407
  }
1313
- provideForSubscribe(field2) {
1408
+ provideForSubscribe(field2, fieldName) {
1314
1409
  if (field2?.["~meta"]?.subscribe == null)
1315
1410
  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
- )
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
+ );
1324
1435
  };
1325
1436
  }
1326
1437
  getCacheType(gqlType, fieldName) {
1327
1438
  return getCacheType(gqlType, { ...this.options, fieldName, parent: this });
1328
1439
  }
1329
1440
  get options() {
1330
- const { resolverOptions, weaverContext: weaverContext2 } = this;
1441
+ const { globalOptions: resolverOptions, weaverContext: weaverContext2 } = this;
1331
1442
  return { resolverOptions, weaverContext: weaverContext2 };
1332
1443
  }
1333
1444
  };
@@ -1530,12 +1641,12 @@ var GraphQLSchemaLoom = class _GraphQLSchemaLoom {
1530
1641
  parentObject.hideField(name);
1531
1642
  } else if (field2["~meta"].operation === "field") {
1532
1643
  if (parentObject == null) return;
1533
- parentObject.addField(name, field2);
1644
+ parentObject.addField(name, field2, resolver2);
1534
1645
  } else {
1535
1646
  const operationObject = this.getOperationObject(
1536
1647
  field2["~meta"].operation
1537
1648
  );
1538
- operationObject.addField(name, field2);
1649
+ operationObject.addField(name, field2, resolver2);
1539
1650
  }
1540
1651
  });
1541
1652
  return this;
@@ -1567,7 +1678,7 @@ var GraphQLSchemaLoom = class _GraphQLSchemaLoom {
1567
1678
  }
1568
1679
  get fieldOptions() {
1569
1680
  const { resolverOptions, context } = this;
1570
- return { resolverOptions, weaverContext: context };
1681
+ return { globalOptions: resolverOptions, weaverContext: context };
1571
1682
  }
1572
1683
  static optionsFrom(...inputs) {
1573
1684
  const configs = /* @__PURE__ */ new Set();
@@ -1577,6 +1688,7 @@ var GraphQLSchemaLoom = class _GraphQLSchemaLoom {
1577
1688
  const weavers = /* @__PURE__ */ new Set();
1578
1689
  let context;
1579
1690
  for (const item of inputs) {
1691
+ if (item == null) continue;
1580
1692
  if (isSchemaVendorWeaver(item)) {
1581
1693
  weavers.add(item);
1582
1694
  } else if (typeof item === "function") {
@@ -1645,7 +1757,6 @@ function ensureInterfaceType(gqlType, interfaceConfig) {
1645
1757
  export {
1646
1758
  BaseChainFactory,
1647
1759
  ChainResolver,
1648
- ContextMemoization,
1649
1760
  EasyDataLoader,
1650
1761
  FieldChainFactory,
1651
1762
  FieldFactoryWithResolve,
@@ -1660,13 +1771,12 @@ export {
1660
1771
  symbols_exports as SYMBOLS,
1661
1772
  SubscriptionChainFactory,
1662
1773
  applyMiddlewares,
1774
+ assignContextMap,
1663
1775
  capitalize,
1664
1776
  collectName,
1665
1777
  collectNames,
1666
- compose,
1667
1778
  createField,
1668
1779
  createInputParser,
1669
- createMemoization,
1670
1780
  createMutation,
1671
1781
  createQuery,
1672
1782
  createSubscription,
@@ -1676,10 +1786,13 @@ export {
1676
1786
  ensureInputType,
1677
1787
  ensureInterfaceType,
1678
1788
  field,
1789
+ filterMiddlewares,
1679
1790
  getCacheType,
1680
1791
  getFieldOptions,
1681
1792
  getGraphQLType,
1793
+ getMemoizationMap,
1682
1794
  getOperationOptions,
1795
+ getResolvingFields,
1683
1796
  getStandardValue,
1684
1797
  getSubscriptionOptions,
1685
1798
  initWeaverContext,
@@ -1699,20 +1812,17 @@ export {
1699
1812
  nullableSilk,
1700
1813
  onlyMemoization,
1701
1814
  parseInputValue,
1815
+ parseResolvingFields,
1702
1816
  parseSilk,
1703
1817
  pascalCase,
1704
1818
  provideWeaverContext,
1705
1819
  query,
1706
1820
  resolver,
1707
- resolverPayloadStorage,
1708
1821
  screamingSnakeCase,
1709
1822
  silk,
1710
1823
  subscription,
1711
1824
  toObjMap,
1712
1825
  tryIn,
1713
- useContext,
1714
- useMemoizationMap,
1715
- useResolverPayload,
1716
1826
  weave,
1717
1827
  weaverContext
1718
1828
  };