@mearie/core 0.4.0 → 0.5.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.cjs CHANGED
@@ -318,6 +318,12 @@ const RootFieldKey = "__root";
318
318
  * @internal
319
319
  */
320
320
  const FragmentRefKey = "__fragmentRef";
321
+ /**
322
+ * Special key used to carry merged variable context (fragment args + operation variables)
323
+ * on fragment references. Used by readFragment to resolve variable-dependent field keys.
324
+ * @internal
325
+ */
326
+ const FragmentVarsKey = "__fragmentVars";
321
327
 
322
328
  //#endregion
323
329
  //#region src/cache/utils.ts
@@ -391,6 +397,14 @@ const isFragmentRef = (value) => {
391
397
  return typeof value === "object" && value !== null && FragmentRefKey in value;
392
398
  };
393
399
  /**
400
+ * Extracts the merged variable context for a specific fragment from a fragment reference.
401
+ * Returns the merged variables (fragment args + operation variables) if present, or an empty object.
402
+ * @internal
403
+ */
404
+ const getFragmentVars = (fragmentRef, fragmentName) => {
405
+ return fragmentRef[FragmentVarsKey]?.[fragmentName] ?? {};
406
+ };
407
+ /**
394
408
  * Type guard to check if a value is an array of fragment references.
395
409
  * @internal
396
410
  * @param value - Value to check.
@@ -504,18 +518,17 @@ const makeFieldKeyFromArgs = (field, args) => {
504
518
 
505
519
  //#endregion
506
520
  //#region src/cache/normalize.ts
507
- const SKIP = Symbol();
508
521
  const normalize = (schemaMeta, selections, storage, data, variables, accessor) => {
509
522
  const normalizeField = (storageKey, selections, value) => {
510
523
  if (isNullish(value)) return value;
511
524
  if (Array.isArray(value)) return value.map((item) => normalizeField(storageKey, selections, item));
512
525
  const data = value;
513
526
  const typename = data.__typename;
514
- const entityMeta = schemaMeta.entities[typename];
527
+ let entityMeta = schemaMeta.entities[typename];
515
528
  if (entityMeta) {
516
529
  const keys = entityMeta.keyFields.map((field) => data[field]);
517
- if (!keys.every((k) => k !== void 0 && k !== null)) return SKIP;
518
- storageKey = makeEntityKey(typename, keys);
530
+ if (keys.every((k) => k !== void 0 && k !== null)) storageKey = makeEntityKey(typename, keys);
531
+ else entityMeta = void 0;
519
532
  }
520
533
  const fields = {};
521
534
  for (const selection of selections) if (selection.kind === "Field") {
@@ -523,13 +536,11 @@ const normalize = (schemaMeta, selections, storage, data, variables, accessor) =
523
536
  const fieldValue = data[selection.alias ?? selection.name];
524
537
  const oldValue = storageKey === null ? void 0 : storage[storageKey]?.[fieldKey];
525
538
  if (storageKey !== null && (!selection.selections || isNullish(oldValue) || isNullish(fieldValue))) accessor?.(storageKey, fieldKey, oldValue, fieldValue);
526
- const normalized = selection.selections ? normalizeField(null, selection.selections, fieldValue) : fieldValue;
527
- if (normalized === SKIP) continue;
528
- fields[fieldKey] = normalized;
539
+ fields[fieldKey] = selection.selections ? normalizeField(null, selection.selections, fieldValue) : fieldValue;
529
540
  if (storageKey !== null && selection.selections && !isNullish(oldValue) && !isNullish(fieldValue) && !isEntityLink(fields[fieldKey]) && !isEqual(oldValue, fields[fieldKey])) accessor?.(storageKey, fieldKey, oldValue, fields[fieldKey]);
530
541
  } else if (selection.kind === "FragmentSpread" || selection.kind === "InlineFragment" && selection.on === typename) {
531
542
  const inner = normalizeField(storageKey, selection.selections, value);
532
- if (inner !== SKIP && !isEntityLink(inner)) mergeFields(fields, inner);
543
+ if (!isEntityLink(inner)) mergeFields(fields, inner);
533
544
  }
534
545
  if (entityMeta && storageKey !== null) {
535
546
  const existing = storage[storageKey];
@@ -584,6 +595,17 @@ const denormalize = (selections, storage, value, variables, accessor) => {
584
595
  else fields[name] = value;
585
596
  } else if (selection.kind === "FragmentSpread") if (storageKey !== null && storageKey !== RootFieldKey) {
586
597
  fields[FragmentRefKey] = storageKey;
598
+ if (selection.args) {
599
+ const resolvedArgs = resolveArguments(selection.args, variables);
600
+ const mergedVars = {
601
+ ...variables,
602
+ ...resolvedArgs
603
+ };
604
+ fields[FragmentVarsKey] = {
605
+ ...fields[FragmentVarsKey],
606
+ [selection.name]: mergedVars
607
+ };
608
+ }
587
609
  if (accessor) denormalize(selection.selections, storage, { [EntityLinkKey]: storageKey }, variables, accessor);
588
610
  } else mergeFields(fields, denormalizeField(storageKey, selection.selections, value));
589
611
  else if (selection.kind === "InlineFragment" && selection.on === data[typenameFieldKey]) mergeFields(fields, denormalizeField(storageKey, selection.selections, value));
@@ -607,9 +629,74 @@ var Cache = class {
607
629
  #subscriptions = /* @__PURE__ */ new Map();
608
630
  #memo = /* @__PURE__ */ new Map();
609
631
  #stale = /* @__PURE__ */ new Set();
632
+ #optimisticKeys = [];
633
+ #optimisticLayers = /* @__PURE__ */ new Map();
634
+ #storageView = null;
610
635
  constructor(schemaMetadata) {
611
636
  this.#schemaMeta = schemaMetadata;
612
637
  }
638
+ #getStorageView() {
639
+ if (this.#optimisticKeys.length === 0) return this.#storage;
640
+ if (this.#storageView) return this.#storageView;
641
+ const merged = { ...this.#storage };
642
+ for (const storageKey of Object.keys(this.#storage)) merged[storageKey] = { ...this.#storage[storageKey] };
643
+ for (const key of this.#optimisticKeys) {
644
+ const layer = this.#optimisticLayers.get(key);
645
+ if (!layer) continue;
646
+ for (const storageKey of Object.keys(layer.storage)) merged[storageKey] = merged[storageKey] ? {
647
+ ...merged[storageKey],
648
+ ...layer.storage[storageKey]
649
+ } : { ...layer.storage[storageKey] };
650
+ }
651
+ this.#storageView = merged;
652
+ return merged;
653
+ }
654
+ /**
655
+ * Writes an optimistic response to a separate cache layer.
656
+ * The optimistic data is immediately visible in reads but does not affect the base storage.
657
+ * @internal
658
+ * @param key - Unique key identifying this optimistic mutation (typically the operation key).
659
+ * @param artifact - GraphQL document artifact.
660
+ * @param variables - Operation variables.
661
+ * @param data - The optimistic response data.
662
+ */
663
+ writeOptimistic(key, artifact, variables, data) {
664
+ const layerStorage = { [RootFieldKey]: {} };
665
+ const dependencies = /* @__PURE__ */ new Set();
666
+ normalize(this.#schemaMeta, artifact.selections, layerStorage, data, variables, (storageKey, fieldKey) => {
667
+ dependencies.add(makeDependencyKey(storageKey, fieldKey));
668
+ });
669
+ this.#optimisticKeys.push(key);
670
+ this.#optimisticLayers.set(key, {
671
+ storage: layerStorage,
672
+ dependencies
673
+ });
674
+ this.#storageView = null;
675
+ const subscriptions = /* @__PURE__ */ new Set();
676
+ for (const depKey of dependencies) {
677
+ const ss = this.#subscriptions.get(depKey);
678
+ if (ss) for (const s of ss) subscriptions.add(s);
679
+ }
680
+ for (const subscription of subscriptions) subscription.listener();
681
+ }
682
+ /**
683
+ * Removes an optimistic layer and notifies affected subscribers.
684
+ * @internal
685
+ * @param key - The key of the optimistic layer to remove.
686
+ */
687
+ removeOptimistic(key) {
688
+ const layer = this.#optimisticLayers.get(key);
689
+ if (!layer) return;
690
+ this.#optimisticLayers.delete(key);
691
+ this.#optimisticKeys = this.#optimisticKeys.filter((k) => k !== key);
692
+ this.#storageView = null;
693
+ const subscriptions = /* @__PURE__ */ new Set();
694
+ for (const depKey of layer.dependencies) {
695
+ const ss = this.#subscriptions.get(depKey);
696
+ if (ss) for (const s of ss) subscriptions.add(s);
697
+ }
698
+ for (const subscription of subscriptions) subscription.listener();
699
+ }
613
700
  /**
614
701
  * Writes a query result to the cache, normalizing entities.
615
702
  * @param artifact - GraphQL document artifact.
@@ -642,7 +729,8 @@ var Cache = class {
642
729
  */
643
730
  readQuery(artifact, variables) {
644
731
  let stale = false;
645
- const { data, partial } = denormalize(artifact.selections, this.#storage, this.#storage[RootFieldKey], variables, (storageKey, fieldKey) => {
732
+ const storage = this.#getStorageView();
733
+ const { data, partial } = denormalize(artifact.selections, storage, storage[RootFieldKey], variables, (storageKey, fieldKey) => {
646
734
  if (this.#stale.has(storageKey) || this.#stale.has(makeDependencyKey(storageKey, fieldKey))) stale = true;
647
735
  });
648
736
  if (partial) return {
@@ -667,7 +755,8 @@ var Cache = class {
667
755
  */
668
756
  subscribeQuery(artifact, variables, listener) {
669
757
  const dependencies = /* @__PURE__ */ new Set();
670
- denormalize(artifact.selections, this.#storage, this.#storage[RootFieldKey], variables, (storageKey, fieldKey) => {
758
+ const storageView = this.#getStorageView();
759
+ denormalize(artifact.selections, storageView, storageView[RootFieldKey], variables, (storageKey, fieldKey) => {
671
760
  const dependencyKey = makeDependencyKey(storageKey, fieldKey);
672
761
  dependencies.add(dependencyKey);
673
762
  });
@@ -682,19 +771,22 @@ var Cache = class {
682
771
  */
683
772
  readFragment(artifact, fragmentRef) {
684
773
  const entityKey = fragmentRef[FragmentRefKey];
685
- if (!this.#storage[entityKey]) return {
774
+ const fragmentVars = getFragmentVars(fragmentRef, artifact.name);
775
+ const storageView = this.#getStorageView();
776
+ if (!storageView[entityKey]) return {
686
777
  data: null,
687
778
  stale: false
688
779
  };
689
780
  let stale = false;
690
- const { data, partial } = denormalize(artifact.selections, this.#storage, { [EntityLinkKey]: entityKey }, {}, (storageKey, fieldKey) => {
781
+ const { data, partial } = denormalize(artifact.selections, storageView, { [EntityLinkKey]: entityKey }, fragmentVars, (storageKey, fieldKey) => {
691
782
  if (this.#stale.has(storageKey) || this.#stale.has(makeDependencyKey(storageKey, fieldKey))) stale = true;
692
783
  });
693
784
  if (partial) return {
694
785
  data: null,
695
786
  stale: false
696
787
  };
697
- const key = makeMemoKey("fragment", artifact.name, entityKey);
788
+ const argsId = Object.keys(fragmentVars).length > 0 ? entityKey + stringify(fragmentVars) : entityKey;
789
+ const key = makeMemoKey("fragment", artifact.name, argsId);
698
790
  const prev = this.#memo.get(key);
699
791
  const result = prev === void 0 ? data : replaceEqualDeep(prev, data);
700
792
  this.#memo.set(key, result);
@@ -705,8 +797,10 @@ var Cache = class {
705
797
  }
706
798
  subscribeFragment(artifact, fragmentRef, listener) {
707
799
  const entityKey = fragmentRef[FragmentRefKey];
800
+ const fragmentVars = getFragmentVars(fragmentRef, artifact.name);
708
801
  const dependencies = /* @__PURE__ */ new Set();
709
- denormalize(artifact.selections, this.#storage, { [EntityLinkKey]: entityKey }, {}, (storageKey, fieldKey) => {
802
+ const storageView = this.#getStorageView();
803
+ denormalize(artifact.selections, storageView, { [EntityLinkKey]: entityKey }, fragmentVars, (storageKey, fieldKey) => {
710
804
  const dependencyKey = makeDependencyKey(storageKey, fieldKey);
711
805
  dependencies.add(dependencyKey);
712
806
  });
@@ -736,9 +830,11 @@ var Cache = class {
736
830
  }
737
831
  subscribeFragments(artifact, fragmentRefs, listener) {
738
832
  const dependencies = /* @__PURE__ */ new Set();
833
+ const storageView = this.#getStorageView();
739
834
  for (const ref of fragmentRefs) {
740
835
  const entityKey = ref[FragmentRefKey];
741
- denormalize(artifact.selections, this.#storage, { [EntityLinkKey]: entityKey }, {}, (storageKey, fieldKey) => {
836
+ const fragmentVars = getFragmentVars(ref, artifact.name);
837
+ denormalize(artifact.selections, storageView, { [EntityLinkKey]: entityKey }, fragmentVars, (storageKey, fieldKey) => {
742
838
  dependencies.add(makeDependencyKey(storageKey, fieldKey));
743
839
  });
744
840
  }
@@ -819,6 +915,7 @@ var Cache = class {
819
915
  }
820
916
  /**
821
917
  * Extracts a serializable snapshot of the cache storage and structural sharing state.
918
+ * Optimistic layers are excluded because they represent transient in-flight state.
822
919
  */
823
920
  extract() {
824
921
  return {
@@ -836,6 +933,7 @@ var Cache = class {
836
933
  ...fields
837
934
  };
838
935
  for (const [key, value] of Object.entries(memo)) this.#memo.set(key, value);
936
+ this.#storageView = null;
839
937
  }
840
938
  /**
841
939
  * Clears all cache data.
@@ -845,6 +943,9 @@ var Cache = class {
845
943
  this.#subscriptions.clear();
846
944
  this.#memo.clear();
847
945
  this.#stale.clear();
946
+ this.#optimisticKeys = [];
947
+ this.#optimisticLayers.clear();
948
+ this.#storageView = null;
848
949
  }
849
950
  };
850
951
 
@@ -877,10 +978,10 @@ const cacheExchange = (options = {}) => {
877
978
  },
878
979
  io: (ops$) => {
879
980
  const fragment$ = require_make.pipe(ops$, require_make.filter((op) => op.variant === "request" && op.artifact.kind === "fragment"), require_make.mergeMap((op) => {
880
- const fragmentRef = op.metadata?.fragmentRef;
981
+ const fragmentRef = op.metadata?.fragment?.ref;
881
982
  if (!fragmentRef) return require_make.fromValue({
882
983
  operation: op,
883
- errors: [new ExchangeError("Fragment operation missing fragmentRef in metadata. This usually happens when the wrong fragment reference was passed.", { exchangeName: "cache" })]
984
+ errors: [new ExchangeError("Fragment operation missing fragment.ref in metadata. This usually happens when the wrong fragment reference was passed.", { exchangeName: "cache" })]
884
985
  });
885
986
  if (isFragmentRefArray(fragmentRef)) {
886
987
  const trigger = require_make.makeSubject();
@@ -912,7 +1013,9 @@ const cacheExchange = (options = {}) => {
912
1013
  errors: []
913
1014
  })));
914
1015
  }));
915
- const nonCache$ = require_make.pipe(ops$, require_make.filter((op) => op.variant === "request" && (op.artifact.kind === "mutation" || op.artifact.kind === "subscription" || op.artifact.kind === "query" && fetchPolicy === "network-only")));
1016
+ const nonCache$ = require_make.pipe(ops$, require_make.filter((op) => op.variant === "request" && (op.artifact.kind === "mutation" || op.artifact.kind === "subscription" || op.artifact.kind === "query" && fetchPolicy === "network-only")), require_make.tap((op) => {
1017
+ if (op.artifact.kind === "mutation" && op.metadata?.cache?.optimisticResponse) cache.writeOptimistic(op.key, op.artifact, op.variables, op.metadata.cache.optimisticResponse);
1018
+ }));
916
1019
  const query$ = require_make.pipe(ops$, require_make.filter((op) => op.variant === "request" && op.artifact.kind === "query" && fetchPolicy !== "network-only"), require_make.share());
917
1020
  const refetch$ = require_make.makeSubject();
918
1021
  return require_make.merge(fragment$, require_make.pipe(query$, require_make.mergeMap((op) => {
@@ -955,9 +1058,18 @@ const cacheExchange = (options = {}) => {
955
1058
  }), require_make.filter(() => fetchPolicy === "cache-only" || fetchPolicy === "cache-and-network" || fetchPolicy === "cache-first")), require_make.pipe(require_make.merge(nonCache$, require_make.pipe(query$, require_make.filter((op) => {
956
1059
  const { data } = cache.readQuery(op.artifact, op.variables);
957
1060
  return fetchPolicy === "cache-and-network" || data === null;
958
- })), require_make.pipe(ops$, require_make.filter((op) => op.variant === "teardown")), refetch$.source), forward, require_make.tap((result) => {
1061
+ })), require_make.pipe(ops$, require_make.filter((op) => op.variant === "teardown")), refetch$.source), forward, require_make.mergeMap((result) => {
1062
+ if (result.operation.variant === "request" && result.operation.artifact.kind === "mutation" && result.operation.metadata?.cache?.optimisticResponse) cache.removeOptimistic(result.operation.key);
959
1063
  if (result.operation.variant === "request" && result.data) cache.writeQuery(result.operation.artifact, result.operation.variables, result.data);
960
- }), require_make.filter((result) => result.operation.variant !== "request" || result.operation.artifact.kind !== "query" || fetchPolicy === "network-only" || !!(result.errors && result.errors.length > 0))));
1064
+ if (result.operation.variant !== "request" || result.operation.artifact.kind !== "query" || fetchPolicy === "network-only" || !!(result.errors && result.errors.length > 0)) return require_make.fromValue(result);
1065
+ const { data } = cache.readQuery(result.operation.artifact, result.operation.variables);
1066
+ if (data !== null) return empty();
1067
+ return require_make.fromValue({
1068
+ operation: result.operation,
1069
+ data: void 0,
1070
+ errors: [new ExchangeError("Cache failed to denormalize the network response. This is likely a bug in the cache normalizer.", { exchangeName: "cache" })]
1071
+ });
1072
+ })));
961
1073
  }
962
1074
  };
963
1075
  };
@@ -1009,10 +1121,10 @@ const fragmentExchange = () => {
1009
1121
  name: "fragment",
1010
1122
  io: (ops$) => {
1011
1123
  return require_make.merge(require_make.pipe(ops$, require_make.filter((op) => op.variant === "request" && op.artifact.kind === "fragment"), require_make.map((op) => {
1012
- const fragmentRef = op.metadata.fragmentRef;
1124
+ const fragmentRef = op.metadata.fragment?.ref;
1013
1125
  if (!fragmentRef) return {
1014
1126
  operation: op,
1015
- errors: [new ExchangeError("Fragment operation missing fragmentRef in metadata. This usually happens when the wrong fragment reference was passed.", { exchangeName: "fragment" })]
1127
+ errors: [new ExchangeError("Fragment operation missing fragment.ref in metadata. This usually happens when the wrong fragment reference was passed.", { exchangeName: "fragment" })]
1016
1128
  };
1017
1129
  return {
1018
1130
  operation: op,
@@ -1398,7 +1510,7 @@ var Client = class {
1398
1510
  key: this.createOperationKey(),
1399
1511
  metadata: {
1400
1512
  ...options?.metadata,
1401
- fragmentRef
1513
+ fragment: { ref: fragmentRef }
1402
1514
  },
1403
1515
  artifact,
1404
1516
  variables: {}
package/dist/index.d.cts CHANGED
@@ -68,8 +68,8 @@ type QueryOptions<T extends Artifact$1<'query'> = Artifact$1<'query'>> = {
68
68
  initialData?: DataOf$1<T>;
69
69
  metadata?: OperationMetadata;
70
70
  };
71
- type MutationOptions = {
72
- metadata?: OperationMetadata;
71
+ type MutationOptions<T extends Artifact$1<'mutation'> = Artifact$1<'mutation'>> = {
72
+ metadata?: OperationMetadata<T>;
73
73
  };
74
74
  type SubscriptionOptions = {
75
75
  metadata?: OperationMetadata;
@@ -93,14 +93,14 @@ declare class Client<TMeta extends SchemaMeta$1 = SchemaMeta$1> {
93
93
  get schema(): TMeta;
94
94
  get scalars(): ScalarsConfig<TMeta> | undefined;
95
95
  private createOperationKey;
96
- createOperation(artifact: Artifact$1, variables?: unknown, metadata?: OperationMetadata): Operation;
96
+ createOperation(artifact: Artifact$1, variables?: unknown, metadata?: Record<string, unknown>): Operation;
97
97
  executeOperation(operation: Operation): Source<OperationResult>;
98
98
  executeQuery<T extends Artifact$1<'query'>>(artifact: T, ...[variables, options]: VariablesOf$1<T> extends undefined ? [undefined?, QueryOptions<T>?] : [VariablesOf$1<T>, QueryOptions<T>?]): Source<OperationResult>;
99
- executeMutation<T extends Artifact$1<'mutation'>>(artifact: T, ...[variables, options]: VariablesOf$1<T> extends undefined ? [undefined?, MutationOptions?] : [VariablesOf$1<T>, MutationOptions?]): Source<OperationResult>;
99
+ executeMutation<T extends Artifact$1<'mutation'>>(artifact: T, ...[variables, options]: VariablesOf$1<T> extends undefined ? [undefined?, MutationOptions<T>?] : [VariablesOf$1<T>, MutationOptions<T>?]): Source<OperationResult>;
100
100
  executeSubscription<T extends Artifact$1<'subscription'>>(artifact: T, ...[variables, options]: VariablesOf$1<T> extends undefined ? [undefined?, SubscriptionOptions?] : [VariablesOf$1<T>, SubscriptionOptions?]): Source<OperationResult>;
101
101
  executeFragment<T extends Artifact$1<'fragment'>>(artifact: T, fragmentRef: FragmentRefs$1<T['name']> | FragmentRefs$1<T['name']>[], options?: FragmentOptions): Source<OperationResult>;
102
102
  query<T extends Artifact$1<'query'>>(artifact: T, ...[variables, options]: VariablesOf$1<T> extends undefined ? [undefined?, QueryOptions<T>?] : [VariablesOf$1<T>, QueryOptions<T>?]): Promise<DataOf$1<T>>;
103
- mutation<T extends Artifact$1<'mutation'>>(artifact: T, ...[variables, options]: VariablesOf$1<T> extends undefined ? [undefined?, MutationOptions?] : [VariablesOf$1<T>, MutationOptions?]): Promise<DataOf$1<T>>;
103
+ mutation<T extends Artifact$1<'mutation'>>(artifact: T, ...[variables, options]: VariablesOf$1<T> extends undefined ? [undefined?, MutationOptions<T>?] : [VariablesOf$1<T>, MutationOptions<T>?]): Promise<DataOf$1<T>>;
104
104
  /**
105
105
  * Returns the extension registered by a named exchange.
106
106
  * @param name - The exchange name.
@@ -115,9 +115,9 @@ declare class Client<TMeta extends SchemaMeta$1 = SchemaMeta$1> {
115
115
  declare const createClient: <T extends SchemaMeta$1>(config: ClientOptions<T>) => Client<T>;
116
116
  //#endregion
117
117
  //#region src/exchange.d.ts
118
- interface OperationMetadataMap {}
118
+ interface OperationMetadataMap<T extends Artifact$1 = Artifact$1> {}
119
119
  interface OperationResultMetadataMap {}
120
- type OperationMetadata = { [K in keyof OperationMetadataMap]?: OperationMetadataMap[K] } & Record<string, unknown>;
120
+ type OperationMetadata<T extends Artifact$1 = Artifact$1> = { [K in keyof OperationMetadataMap<T>]?: OperationMetadataMap<T>[K] } & Record<string, unknown>;
121
121
  type BaseOperation = {
122
122
  key: string;
123
123
  metadata: OperationMetadataMap & Record<string, unknown>;
@@ -248,6 +248,11 @@ declare module '@mearie/core' {
248
248
  interface ExchangeExtensionMap<TMeta extends SchemaMeta$1> {
249
249
  cache: CacheOperations<TMeta>;
250
250
  }
251
+ interface OperationMetadataMap<T extends Artifact$1> {
252
+ cache?: {
253
+ optimisticResponse?: T extends Artifact$1<'mutation'> ? DataOf$1<T> : never;
254
+ };
255
+ }
251
256
  interface OperationResultMetadataMap {
252
257
  cache?: {
253
258
  stale: boolean;
@@ -278,7 +283,9 @@ declare const retryExchange: (options?: RetryOptions) => Exchange;
278
283
  //#region src/exchanges/fragment.d.ts
279
284
  declare module '@mearie/core' {
280
285
  interface OperationMetadataMap {
281
- fragmentRef?: unknown;
286
+ fragment?: {
287
+ ref?: unknown;
288
+ };
282
289
  }
283
290
  }
284
291
  declare const fragmentExchange: () => Exchange;
package/dist/index.d.mts CHANGED
@@ -68,8 +68,8 @@ type QueryOptions<T extends Artifact$1<'query'> = Artifact$1<'query'>> = {
68
68
  initialData?: DataOf$1<T>;
69
69
  metadata?: OperationMetadata;
70
70
  };
71
- type MutationOptions = {
72
- metadata?: OperationMetadata;
71
+ type MutationOptions<T extends Artifact$1<'mutation'> = Artifact$1<'mutation'>> = {
72
+ metadata?: OperationMetadata<T>;
73
73
  };
74
74
  type SubscriptionOptions = {
75
75
  metadata?: OperationMetadata;
@@ -93,14 +93,14 @@ declare class Client<TMeta extends SchemaMeta$1 = SchemaMeta$1> {
93
93
  get schema(): TMeta;
94
94
  get scalars(): ScalarsConfig<TMeta> | undefined;
95
95
  private createOperationKey;
96
- createOperation(artifact: Artifact$1, variables?: unknown, metadata?: OperationMetadata): Operation;
96
+ createOperation(artifact: Artifact$1, variables?: unknown, metadata?: Record<string, unknown>): Operation;
97
97
  executeOperation(operation: Operation): Source<OperationResult>;
98
98
  executeQuery<T extends Artifact$1<'query'>>(artifact: T, ...[variables, options]: VariablesOf$1<T> extends undefined ? [undefined?, QueryOptions<T>?] : [VariablesOf$1<T>, QueryOptions<T>?]): Source<OperationResult>;
99
- executeMutation<T extends Artifact$1<'mutation'>>(artifact: T, ...[variables, options]: VariablesOf$1<T> extends undefined ? [undefined?, MutationOptions?] : [VariablesOf$1<T>, MutationOptions?]): Source<OperationResult>;
99
+ executeMutation<T extends Artifact$1<'mutation'>>(artifact: T, ...[variables, options]: VariablesOf$1<T> extends undefined ? [undefined?, MutationOptions<T>?] : [VariablesOf$1<T>, MutationOptions<T>?]): Source<OperationResult>;
100
100
  executeSubscription<T extends Artifact$1<'subscription'>>(artifact: T, ...[variables, options]: VariablesOf$1<T> extends undefined ? [undefined?, SubscriptionOptions?] : [VariablesOf$1<T>, SubscriptionOptions?]): Source<OperationResult>;
101
101
  executeFragment<T extends Artifact$1<'fragment'>>(artifact: T, fragmentRef: FragmentRefs$1<T['name']> | FragmentRefs$1<T['name']>[], options?: FragmentOptions): Source<OperationResult>;
102
102
  query<T extends Artifact$1<'query'>>(artifact: T, ...[variables, options]: VariablesOf$1<T> extends undefined ? [undefined?, QueryOptions<T>?] : [VariablesOf$1<T>, QueryOptions<T>?]): Promise<DataOf$1<T>>;
103
- mutation<T extends Artifact$1<'mutation'>>(artifact: T, ...[variables, options]: VariablesOf$1<T> extends undefined ? [undefined?, MutationOptions?] : [VariablesOf$1<T>, MutationOptions?]): Promise<DataOf$1<T>>;
103
+ mutation<T extends Artifact$1<'mutation'>>(artifact: T, ...[variables, options]: VariablesOf$1<T> extends undefined ? [undefined?, MutationOptions<T>?] : [VariablesOf$1<T>, MutationOptions<T>?]): Promise<DataOf$1<T>>;
104
104
  /**
105
105
  * Returns the extension registered by a named exchange.
106
106
  * @param name - The exchange name.
@@ -115,9 +115,9 @@ declare class Client<TMeta extends SchemaMeta$1 = SchemaMeta$1> {
115
115
  declare const createClient: <T extends SchemaMeta$1>(config: ClientOptions<T>) => Client<T>;
116
116
  //#endregion
117
117
  //#region src/exchange.d.ts
118
- interface OperationMetadataMap {}
118
+ interface OperationMetadataMap<T extends Artifact$1 = Artifact$1> {}
119
119
  interface OperationResultMetadataMap {}
120
- type OperationMetadata = { [K in keyof OperationMetadataMap]?: OperationMetadataMap[K] } & Record<string, unknown>;
120
+ type OperationMetadata<T extends Artifact$1 = Artifact$1> = { [K in keyof OperationMetadataMap<T>]?: OperationMetadataMap<T>[K] } & Record<string, unknown>;
121
121
  type BaseOperation = {
122
122
  key: string;
123
123
  metadata: OperationMetadataMap & Record<string, unknown>;
@@ -248,6 +248,11 @@ declare module '@mearie/core' {
248
248
  interface ExchangeExtensionMap<TMeta extends SchemaMeta$1> {
249
249
  cache: CacheOperations<TMeta>;
250
250
  }
251
+ interface OperationMetadataMap<T extends Artifact$1> {
252
+ cache?: {
253
+ optimisticResponse?: T extends Artifact$1<'mutation'> ? DataOf$1<T> : never;
254
+ };
255
+ }
251
256
  interface OperationResultMetadataMap {
252
257
  cache?: {
253
258
  stale: boolean;
@@ -278,7 +283,9 @@ declare const retryExchange: (options?: RetryOptions) => Exchange;
278
283
  //#region src/exchanges/fragment.d.ts
279
284
  declare module '@mearie/core' {
280
285
  interface OperationMetadataMap {
281
- fragmentRef?: unknown;
286
+ fragment?: {
287
+ ref?: unknown;
288
+ };
282
289
  }
283
290
  }
284
291
  declare const fragmentExchange: () => Exchange;
package/dist/index.mjs CHANGED
@@ -317,6 +317,12 @@ const RootFieldKey = "__root";
317
317
  * @internal
318
318
  */
319
319
  const FragmentRefKey = "__fragmentRef";
320
+ /**
321
+ * Special key used to carry merged variable context (fragment args + operation variables)
322
+ * on fragment references. Used by readFragment to resolve variable-dependent field keys.
323
+ * @internal
324
+ */
325
+ const FragmentVarsKey = "__fragmentVars";
320
326
 
321
327
  //#endregion
322
328
  //#region src/cache/utils.ts
@@ -390,6 +396,14 @@ const isFragmentRef = (value) => {
390
396
  return typeof value === "object" && value !== null && FragmentRefKey in value;
391
397
  };
392
398
  /**
399
+ * Extracts the merged variable context for a specific fragment from a fragment reference.
400
+ * Returns the merged variables (fragment args + operation variables) if present, or an empty object.
401
+ * @internal
402
+ */
403
+ const getFragmentVars = (fragmentRef, fragmentName) => {
404
+ return fragmentRef[FragmentVarsKey]?.[fragmentName] ?? {};
405
+ };
406
+ /**
393
407
  * Type guard to check if a value is an array of fragment references.
394
408
  * @internal
395
409
  * @param value - Value to check.
@@ -503,18 +517,17 @@ const makeFieldKeyFromArgs = (field, args) => {
503
517
 
504
518
  //#endregion
505
519
  //#region src/cache/normalize.ts
506
- const SKIP = Symbol();
507
520
  const normalize = (schemaMeta, selections, storage, data, variables, accessor) => {
508
521
  const normalizeField = (storageKey, selections, value) => {
509
522
  if (isNullish(value)) return value;
510
523
  if (Array.isArray(value)) return value.map((item) => normalizeField(storageKey, selections, item));
511
524
  const data = value;
512
525
  const typename = data.__typename;
513
- const entityMeta = schemaMeta.entities[typename];
526
+ let entityMeta = schemaMeta.entities[typename];
514
527
  if (entityMeta) {
515
528
  const keys = entityMeta.keyFields.map((field) => data[field]);
516
- if (!keys.every((k) => k !== void 0 && k !== null)) return SKIP;
517
- storageKey = makeEntityKey(typename, keys);
529
+ if (keys.every((k) => k !== void 0 && k !== null)) storageKey = makeEntityKey(typename, keys);
530
+ else entityMeta = void 0;
518
531
  }
519
532
  const fields = {};
520
533
  for (const selection of selections) if (selection.kind === "Field") {
@@ -522,13 +535,11 @@ const normalize = (schemaMeta, selections, storage, data, variables, accessor) =
522
535
  const fieldValue = data[selection.alias ?? selection.name];
523
536
  const oldValue = storageKey === null ? void 0 : storage[storageKey]?.[fieldKey];
524
537
  if (storageKey !== null && (!selection.selections || isNullish(oldValue) || isNullish(fieldValue))) accessor?.(storageKey, fieldKey, oldValue, fieldValue);
525
- const normalized = selection.selections ? normalizeField(null, selection.selections, fieldValue) : fieldValue;
526
- if (normalized === SKIP) continue;
527
- fields[fieldKey] = normalized;
538
+ fields[fieldKey] = selection.selections ? normalizeField(null, selection.selections, fieldValue) : fieldValue;
528
539
  if (storageKey !== null && selection.selections && !isNullish(oldValue) && !isNullish(fieldValue) && !isEntityLink(fields[fieldKey]) && !isEqual(oldValue, fields[fieldKey])) accessor?.(storageKey, fieldKey, oldValue, fields[fieldKey]);
529
540
  } else if (selection.kind === "FragmentSpread" || selection.kind === "InlineFragment" && selection.on === typename) {
530
541
  const inner = normalizeField(storageKey, selection.selections, value);
531
- if (inner !== SKIP && !isEntityLink(inner)) mergeFields(fields, inner);
542
+ if (!isEntityLink(inner)) mergeFields(fields, inner);
532
543
  }
533
544
  if (entityMeta && storageKey !== null) {
534
545
  const existing = storage[storageKey];
@@ -583,6 +594,17 @@ const denormalize = (selections, storage, value, variables, accessor) => {
583
594
  else fields[name] = value;
584
595
  } else if (selection.kind === "FragmentSpread") if (storageKey !== null && storageKey !== RootFieldKey) {
585
596
  fields[FragmentRefKey] = storageKey;
597
+ if (selection.args) {
598
+ const resolvedArgs = resolveArguments(selection.args, variables);
599
+ const mergedVars = {
600
+ ...variables,
601
+ ...resolvedArgs
602
+ };
603
+ fields[FragmentVarsKey] = {
604
+ ...fields[FragmentVarsKey],
605
+ [selection.name]: mergedVars
606
+ };
607
+ }
586
608
  if (accessor) denormalize(selection.selections, storage, { [EntityLinkKey]: storageKey }, variables, accessor);
587
609
  } else mergeFields(fields, denormalizeField(storageKey, selection.selections, value));
588
610
  else if (selection.kind === "InlineFragment" && selection.on === data[typenameFieldKey]) mergeFields(fields, denormalizeField(storageKey, selection.selections, value));
@@ -606,9 +628,74 @@ var Cache = class {
606
628
  #subscriptions = /* @__PURE__ */ new Map();
607
629
  #memo = /* @__PURE__ */ new Map();
608
630
  #stale = /* @__PURE__ */ new Set();
631
+ #optimisticKeys = [];
632
+ #optimisticLayers = /* @__PURE__ */ new Map();
633
+ #storageView = null;
609
634
  constructor(schemaMetadata) {
610
635
  this.#schemaMeta = schemaMetadata;
611
636
  }
637
+ #getStorageView() {
638
+ if (this.#optimisticKeys.length === 0) return this.#storage;
639
+ if (this.#storageView) return this.#storageView;
640
+ const merged = { ...this.#storage };
641
+ for (const storageKey of Object.keys(this.#storage)) merged[storageKey] = { ...this.#storage[storageKey] };
642
+ for (const key of this.#optimisticKeys) {
643
+ const layer = this.#optimisticLayers.get(key);
644
+ if (!layer) continue;
645
+ for (const storageKey of Object.keys(layer.storage)) merged[storageKey] = merged[storageKey] ? {
646
+ ...merged[storageKey],
647
+ ...layer.storage[storageKey]
648
+ } : { ...layer.storage[storageKey] };
649
+ }
650
+ this.#storageView = merged;
651
+ return merged;
652
+ }
653
+ /**
654
+ * Writes an optimistic response to a separate cache layer.
655
+ * The optimistic data is immediately visible in reads but does not affect the base storage.
656
+ * @internal
657
+ * @param key - Unique key identifying this optimistic mutation (typically the operation key).
658
+ * @param artifact - GraphQL document artifact.
659
+ * @param variables - Operation variables.
660
+ * @param data - The optimistic response data.
661
+ */
662
+ writeOptimistic(key, artifact, variables, data) {
663
+ const layerStorage = { [RootFieldKey]: {} };
664
+ const dependencies = /* @__PURE__ */ new Set();
665
+ normalize(this.#schemaMeta, artifact.selections, layerStorage, data, variables, (storageKey, fieldKey) => {
666
+ dependencies.add(makeDependencyKey(storageKey, fieldKey));
667
+ });
668
+ this.#optimisticKeys.push(key);
669
+ this.#optimisticLayers.set(key, {
670
+ storage: layerStorage,
671
+ dependencies
672
+ });
673
+ this.#storageView = null;
674
+ const subscriptions = /* @__PURE__ */ new Set();
675
+ for (const depKey of dependencies) {
676
+ const ss = this.#subscriptions.get(depKey);
677
+ if (ss) for (const s of ss) subscriptions.add(s);
678
+ }
679
+ for (const subscription of subscriptions) subscription.listener();
680
+ }
681
+ /**
682
+ * Removes an optimistic layer and notifies affected subscribers.
683
+ * @internal
684
+ * @param key - The key of the optimistic layer to remove.
685
+ */
686
+ removeOptimistic(key) {
687
+ const layer = this.#optimisticLayers.get(key);
688
+ if (!layer) return;
689
+ this.#optimisticLayers.delete(key);
690
+ this.#optimisticKeys = this.#optimisticKeys.filter((k) => k !== key);
691
+ this.#storageView = null;
692
+ const subscriptions = /* @__PURE__ */ new Set();
693
+ for (const depKey of layer.dependencies) {
694
+ const ss = this.#subscriptions.get(depKey);
695
+ if (ss) for (const s of ss) subscriptions.add(s);
696
+ }
697
+ for (const subscription of subscriptions) subscription.listener();
698
+ }
612
699
  /**
613
700
  * Writes a query result to the cache, normalizing entities.
614
701
  * @param artifact - GraphQL document artifact.
@@ -641,7 +728,8 @@ var Cache = class {
641
728
  */
642
729
  readQuery(artifact, variables) {
643
730
  let stale = false;
644
- const { data, partial } = denormalize(artifact.selections, this.#storage, this.#storage[RootFieldKey], variables, (storageKey, fieldKey) => {
731
+ const storage = this.#getStorageView();
732
+ const { data, partial } = denormalize(artifact.selections, storage, storage[RootFieldKey], variables, (storageKey, fieldKey) => {
645
733
  if (this.#stale.has(storageKey) || this.#stale.has(makeDependencyKey(storageKey, fieldKey))) stale = true;
646
734
  });
647
735
  if (partial) return {
@@ -666,7 +754,8 @@ var Cache = class {
666
754
  */
667
755
  subscribeQuery(artifact, variables, listener) {
668
756
  const dependencies = /* @__PURE__ */ new Set();
669
- denormalize(artifact.selections, this.#storage, this.#storage[RootFieldKey], variables, (storageKey, fieldKey) => {
757
+ const storageView = this.#getStorageView();
758
+ denormalize(artifact.selections, storageView, storageView[RootFieldKey], variables, (storageKey, fieldKey) => {
670
759
  const dependencyKey = makeDependencyKey(storageKey, fieldKey);
671
760
  dependencies.add(dependencyKey);
672
761
  });
@@ -681,19 +770,22 @@ var Cache = class {
681
770
  */
682
771
  readFragment(artifact, fragmentRef) {
683
772
  const entityKey = fragmentRef[FragmentRefKey];
684
- if (!this.#storage[entityKey]) return {
773
+ const fragmentVars = getFragmentVars(fragmentRef, artifact.name);
774
+ const storageView = this.#getStorageView();
775
+ if (!storageView[entityKey]) return {
685
776
  data: null,
686
777
  stale: false
687
778
  };
688
779
  let stale = false;
689
- const { data, partial } = denormalize(artifact.selections, this.#storage, { [EntityLinkKey]: entityKey }, {}, (storageKey, fieldKey) => {
780
+ const { data, partial } = denormalize(artifact.selections, storageView, { [EntityLinkKey]: entityKey }, fragmentVars, (storageKey, fieldKey) => {
690
781
  if (this.#stale.has(storageKey) || this.#stale.has(makeDependencyKey(storageKey, fieldKey))) stale = true;
691
782
  });
692
783
  if (partial) return {
693
784
  data: null,
694
785
  stale: false
695
786
  };
696
- const key = makeMemoKey("fragment", artifact.name, entityKey);
787
+ const argsId = Object.keys(fragmentVars).length > 0 ? entityKey + stringify(fragmentVars) : entityKey;
788
+ const key = makeMemoKey("fragment", artifact.name, argsId);
697
789
  const prev = this.#memo.get(key);
698
790
  const result = prev === void 0 ? data : replaceEqualDeep(prev, data);
699
791
  this.#memo.set(key, result);
@@ -704,8 +796,10 @@ var Cache = class {
704
796
  }
705
797
  subscribeFragment(artifact, fragmentRef, listener) {
706
798
  const entityKey = fragmentRef[FragmentRefKey];
799
+ const fragmentVars = getFragmentVars(fragmentRef, artifact.name);
707
800
  const dependencies = /* @__PURE__ */ new Set();
708
- denormalize(artifact.selections, this.#storage, { [EntityLinkKey]: entityKey }, {}, (storageKey, fieldKey) => {
801
+ const storageView = this.#getStorageView();
802
+ denormalize(artifact.selections, storageView, { [EntityLinkKey]: entityKey }, fragmentVars, (storageKey, fieldKey) => {
709
803
  const dependencyKey = makeDependencyKey(storageKey, fieldKey);
710
804
  dependencies.add(dependencyKey);
711
805
  });
@@ -735,9 +829,11 @@ var Cache = class {
735
829
  }
736
830
  subscribeFragments(artifact, fragmentRefs, listener) {
737
831
  const dependencies = /* @__PURE__ */ new Set();
832
+ const storageView = this.#getStorageView();
738
833
  for (const ref of fragmentRefs) {
739
834
  const entityKey = ref[FragmentRefKey];
740
- denormalize(artifact.selections, this.#storage, { [EntityLinkKey]: entityKey }, {}, (storageKey, fieldKey) => {
835
+ const fragmentVars = getFragmentVars(ref, artifact.name);
836
+ denormalize(artifact.selections, storageView, { [EntityLinkKey]: entityKey }, fragmentVars, (storageKey, fieldKey) => {
741
837
  dependencies.add(makeDependencyKey(storageKey, fieldKey));
742
838
  });
743
839
  }
@@ -818,6 +914,7 @@ var Cache = class {
818
914
  }
819
915
  /**
820
916
  * Extracts a serializable snapshot of the cache storage and structural sharing state.
917
+ * Optimistic layers are excluded because they represent transient in-flight state.
821
918
  */
822
919
  extract() {
823
920
  return {
@@ -835,6 +932,7 @@ var Cache = class {
835
932
  ...fields
836
933
  };
837
934
  for (const [key, value] of Object.entries(memo)) this.#memo.set(key, value);
935
+ this.#storageView = null;
838
936
  }
839
937
  /**
840
938
  * Clears all cache data.
@@ -844,6 +942,9 @@ var Cache = class {
844
942
  this.#subscriptions.clear();
845
943
  this.#memo.clear();
846
944
  this.#stale.clear();
945
+ this.#optimisticKeys = [];
946
+ this.#optimisticLayers.clear();
947
+ this.#storageView = null;
847
948
  }
848
949
  };
849
950
 
@@ -876,10 +977,10 @@ const cacheExchange = (options = {}) => {
876
977
  },
877
978
  io: (ops$) => {
878
979
  const fragment$ = pipe(ops$, filter((op) => op.variant === "request" && op.artifact.kind === "fragment"), mergeMap((op) => {
879
- const fragmentRef = op.metadata?.fragmentRef;
980
+ const fragmentRef = op.metadata?.fragment?.ref;
880
981
  if (!fragmentRef) return fromValue({
881
982
  operation: op,
882
- errors: [new ExchangeError("Fragment operation missing fragmentRef in metadata. This usually happens when the wrong fragment reference was passed.", { exchangeName: "cache" })]
983
+ errors: [new ExchangeError("Fragment operation missing fragment.ref in metadata. This usually happens when the wrong fragment reference was passed.", { exchangeName: "cache" })]
883
984
  });
884
985
  if (isFragmentRefArray(fragmentRef)) {
885
986
  const trigger = makeSubject();
@@ -911,7 +1012,9 @@ const cacheExchange = (options = {}) => {
911
1012
  errors: []
912
1013
  })));
913
1014
  }));
914
- const nonCache$ = pipe(ops$, filter((op) => op.variant === "request" && (op.artifact.kind === "mutation" || op.artifact.kind === "subscription" || op.artifact.kind === "query" && fetchPolicy === "network-only")));
1015
+ const nonCache$ = pipe(ops$, filter((op) => op.variant === "request" && (op.artifact.kind === "mutation" || op.artifact.kind === "subscription" || op.artifact.kind === "query" && fetchPolicy === "network-only")), tap((op) => {
1016
+ if (op.artifact.kind === "mutation" && op.metadata?.cache?.optimisticResponse) cache.writeOptimistic(op.key, op.artifact, op.variables, op.metadata.cache.optimisticResponse);
1017
+ }));
915
1018
  const query$ = pipe(ops$, filter((op) => op.variant === "request" && op.artifact.kind === "query" && fetchPolicy !== "network-only"), share());
916
1019
  const refetch$ = makeSubject();
917
1020
  return merge(fragment$, pipe(query$, mergeMap((op) => {
@@ -954,9 +1057,18 @@ const cacheExchange = (options = {}) => {
954
1057
  }), filter(() => fetchPolicy === "cache-only" || fetchPolicy === "cache-and-network" || fetchPolicy === "cache-first")), pipe(merge(nonCache$, pipe(query$, filter((op) => {
955
1058
  const { data } = cache.readQuery(op.artifact, op.variables);
956
1059
  return fetchPolicy === "cache-and-network" || data === null;
957
- })), pipe(ops$, filter((op) => op.variant === "teardown")), refetch$.source), forward, tap((result) => {
1060
+ })), pipe(ops$, filter((op) => op.variant === "teardown")), refetch$.source), forward, mergeMap((result) => {
1061
+ if (result.operation.variant === "request" && result.operation.artifact.kind === "mutation" && result.operation.metadata?.cache?.optimisticResponse) cache.removeOptimistic(result.operation.key);
958
1062
  if (result.operation.variant === "request" && result.data) cache.writeQuery(result.operation.artifact, result.operation.variables, result.data);
959
- }), filter((result) => result.operation.variant !== "request" || result.operation.artifact.kind !== "query" || fetchPolicy === "network-only" || !!(result.errors && result.errors.length > 0))));
1063
+ if (result.operation.variant !== "request" || result.operation.artifact.kind !== "query" || fetchPolicy === "network-only" || !!(result.errors && result.errors.length > 0)) return fromValue(result);
1064
+ const { data } = cache.readQuery(result.operation.artifact, result.operation.variables);
1065
+ if (data !== null) return empty();
1066
+ return fromValue({
1067
+ operation: result.operation,
1068
+ data: void 0,
1069
+ errors: [new ExchangeError("Cache failed to denormalize the network response. This is likely a bug in the cache normalizer.", { exchangeName: "cache" })]
1070
+ });
1071
+ })));
960
1072
  }
961
1073
  };
962
1074
  };
@@ -1008,10 +1120,10 @@ const fragmentExchange = () => {
1008
1120
  name: "fragment",
1009
1121
  io: (ops$) => {
1010
1122
  return merge(pipe(ops$, filter((op) => op.variant === "request" && op.artifact.kind === "fragment"), map((op) => {
1011
- const fragmentRef = op.metadata.fragmentRef;
1123
+ const fragmentRef = op.metadata.fragment?.ref;
1012
1124
  if (!fragmentRef) return {
1013
1125
  operation: op,
1014
- errors: [new ExchangeError("Fragment operation missing fragmentRef in metadata. This usually happens when the wrong fragment reference was passed.", { exchangeName: "fragment" })]
1126
+ errors: [new ExchangeError("Fragment operation missing fragment.ref in metadata. This usually happens when the wrong fragment reference was passed.", { exchangeName: "fragment" })]
1015
1127
  };
1016
1128
  return {
1017
1129
  operation: op,
@@ -1397,7 +1509,7 @@ var Client = class {
1397
1509
  key: this.createOperationKey(),
1398
1510
  metadata: {
1399
1511
  ...options?.metadata,
1400
- fragmentRef
1512
+ fragment: { ref: fragmentRef }
1401
1513
  },
1402
1514
  artifact,
1403
1515
  variables: {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mearie/core",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Type-safe, zero-overhead GraphQL client",
5
5
  "keywords": [
6
6
  "graphql",
@@ -62,7 +62,7 @@
62
62
  "README.md"
63
63
  ],
64
64
  "dependencies": {
65
- "@mearie/shared": "0.3.0"
65
+ "@mearie/shared": "0.4.0"
66
66
  },
67
67
  "devDependencies": {
68
68
  "tsdown": "^0.20.3",