houdini 1.0.0-next.3 → 1.0.0-next.5
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/build/cmd-cjs/index.js +1254 -1062
- package/build/cmd-esm/index.js +1254 -1062
- package/build/codegen/generators/artifacts/selection.d.ts +3 -3
- package/build/codegen/generators/artifacts/utils.d.ts +0 -1
- package/build/codegen-cjs/index.js +847 -717
- package/build/codegen-esm/index.js +847 -717
- package/build/lib/config.d.ts +10 -90
- package/build/lib/deepMerge.d.ts +1 -0
- package/build/lib/graphql.d.ts +5 -2
- package/build/lib/index.d.ts +2 -0
- package/build/lib/pipeline.d.ts +1 -1
- package/build/lib/plugin.d.ts +2 -0
- package/build/lib/types.d.ts +250 -2
- package/build/lib-cjs/index.js +351 -162
- package/build/lib-esm/index.js +349 -162
- package/build/runtime/cache/cache.d.ts +23 -6
- package/build/runtime/cache/staleManager.d.ts +30 -0
- package/build/runtime/cache/subscription.d.ts +2 -1
- package/build/runtime/client/documentStore.d.ts +1 -1
- package/build/runtime/client/plugins/fetchParams.d.ts +1 -1
- package/build/runtime/client/plugins/subscription.d.ts +1 -2
- package/build/runtime/lib/config.d.ts +4 -0
- package/build/runtime/lib/index.d.ts +1 -0
- package/build/runtime/lib/key.d.ts +6 -0
- package/build/runtime/lib/types.d.ts +4 -5
- package/build/runtime/public/cache.d.ts +8 -1
- package/build/runtime/public/record.d.ts +11 -1
- package/build/runtime/public/tests/test.d.ts +9 -10
- package/build/runtime-cjs/cache/cache.d.ts +23 -6
- package/build/runtime-cjs/cache/cache.js +95 -21
- package/build/runtime-cjs/cache/gc.js +9 -0
- package/build/runtime-cjs/cache/lists.js +3 -3
- package/build/runtime-cjs/cache/staleManager.d.ts +30 -0
- package/build/runtime-cjs/cache/staleManager.js +95 -0
- package/build/runtime-cjs/cache/subscription.d.ts +2 -1
- package/build/runtime-cjs/cache/subscription.js +6 -3
- package/build/runtime-cjs/client/documentStore.d.ts +1 -1
- package/build/runtime-cjs/client/documentStore.js +1 -0
- package/build/runtime-cjs/client/plugins/cache.js +5 -3
- package/build/runtime-cjs/client/plugins/fetch.js +1 -0
- package/build/runtime-cjs/client/plugins/fetchParams.d.ts +1 -1
- package/build/runtime-cjs/client/plugins/fetchParams.js +6 -1
- package/build/runtime-cjs/client/plugins/query.js +1 -1
- package/build/runtime-cjs/client/plugins/subscription.d.ts +1 -2
- package/build/runtime-cjs/client/plugins/subscription.js +2 -0
- package/build/runtime-cjs/lib/config.d.ts +4 -0
- package/build/runtime-cjs/lib/index.d.ts +1 -0
- package/build/runtime-cjs/lib/index.js +1 -0
- package/build/runtime-cjs/lib/key.d.ts +6 -0
- package/build/runtime-cjs/lib/key.js +41 -0
- package/build/runtime-cjs/lib/types.d.ts +4 -5
- package/build/runtime-cjs/public/cache.d.ts +8 -1
- package/build/runtime-cjs/public/cache.js +3 -0
- package/build/runtime-cjs/public/record.d.ts +11 -1
- package/build/runtime-cjs/public/record.js +8 -1
- package/build/runtime-cjs/public/tests/test.d.ts +9 -10
- package/build/runtime-esm/cache/cache.d.ts +23 -6
- package/build/runtime-esm/cache/cache.js +96 -22
- package/build/runtime-esm/cache/gc.js +9 -0
- package/build/runtime-esm/cache/lists.js +3 -3
- package/build/runtime-esm/cache/staleManager.d.ts +30 -0
- package/build/runtime-esm/cache/staleManager.js +71 -0
- package/build/runtime-esm/cache/subscription.d.ts +2 -1
- package/build/runtime-esm/cache/subscription.js +6 -3
- package/build/runtime-esm/client/documentStore.d.ts +1 -1
- package/build/runtime-esm/client/documentStore.js +1 -0
- package/build/runtime-esm/client/plugins/cache.js +5 -3
- package/build/runtime-esm/client/plugins/fetch.js +1 -0
- package/build/runtime-esm/client/plugins/fetchParams.d.ts +1 -1
- package/build/runtime-esm/client/plugins/fetchParams.js +6 -1
- package/build/runtime-esm/client/plugins/query.js +1 -1
- package/build/runtime-esm/client/plugins/subscription.d.ts +1 -2
- package/build/runtime-esm/client/plugins/subscription.js +2 -0
- package/build/runtime-esm/lib/config.d.ts +4 -0
- package/build/runtime-esm/lib/index.d.ts +1 -0
- package/build/runtime-esm/lib/index.js +1 -0
- package/build/runtime-esm/lib/key.d.ts +6 -0
- package/build/runtime-esm/lib/key.js +17 -0
- package/build/runtime-esm/lib/types.d.ts +4 -5
- package/build/runtime-esm/public/cache.d.ts +8 -1
- package/build/runtime-esm/public/cache.js +3 -0
- package/build/runtime-esm/public/record.d.ts +11 -1
- package/build/runtime-esm/public/record.js +8 -1
- package/build/runtime-esm/public/tests/test.d.ts +9 -10
- package/build/test-cjs/index.js +930 -788
- package/build/test-esm/index.js +930 -788
- package/build/vite-cjs/index.js +1232 -1039
- package/build/vite-esm/index.js +1232 -1039
- package/package.json +3 -2
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var key_exports = {};
|
|
20
|
+
__export(key_exports, {
|
|
21
|
+
computeKey: () => computeKey
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(key_exports);
|
|
24
|
+
const computeKey = ({ field, args }) => {
|
|
25
|
+
const keys = Object.keys(args ?? {});
|
|
26
|
+
keys.sort();
|
|
27
|
+
return args && keys.length > 0 ? `${field}(${keys.map((key) => `${key}: ${stringifyObjectWithNoQuotesOnKeys(args[key])}`).join(", ")})` : field;
|
|
28
|
+
};
|
|
29
|
+
const stringifyObjectWithNoQuotesOnKeys = (obj_from_json) => {
|
|
30
|
+
if (Array.isArray(obj_from_json)) {
|
|
31
|
+
return `[${obj_from_json.map((obj) => `${stringifyObjectWithNoQuotesOnKeys(obj)}`).join(", ")}]`;
|
|
32
|
+
}
|
|
33
|
+
if (typeof obj_from_json !== "object" || obj_from_json instanceof Date || obj_from_json === null) {
|
|
34
|
+
return JSON.stringify(obj_from_json).replace(/"([^"]+)":/g, "$1: ");
|
|
35
|
+
}
|
|
36
|
+
return `{${Object.keys(obj_from_json).map((key) => `${key}: ${stringifyObjectWithNoQuotesOnKeys(obj_from_json[key])}`).join(", ")}}`;
|
|
37
|
+
};
|
|
38
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
39
|
+
0 && (module.exports = {
|
|
40
|
+
computeKey
|
|
41
|
+
});
|
|
@@ -71,7 +71,6 @@ export type BaseCompiledDocument = {
|
|
|
71
71
|
rootType: string;
|
|
72
72
|
input?: InputObject;
|
|
73
73
|
refetch?: {
|
|
74
|
-
update: RefetchUpdateMode;
|
|
75
74
|
path: string[];
|
|
76
75
|
method: 'cursor' | 'offset';
|
|
77
76
|
pageSize: number;
|
|
@@ -79,9 +78,9 @@ export type BaseCompiledDocument = {
|
|
|
79
78
|
embedded: boolean;
|
|
80
79
|
targetType: string;
|
|
81
80
|
paginated: boolean;
|
|
82
|
-
direction
|
|
81
|
+
direction: 'forward' | 'backward' | 'both';
|
|
83
82
|
};
|
|
84
|
-
|
|
83
|
+
plugin_data?: Record<string, any>;
|
|
85
84
|
};
|
|
86
85
|
export type HoudiniFetchContext = {
|
|
87
86
|
variables: () => {};
|
|
@@ -135,7 +134,7 @@ export type SubscriptionSelection = {
|
|
|
135
134
|
connection: boolean;
|
|
136
135
|
type: string;
|
|
137
136
|
};
|
|
138
|
-
|
|
137
|
+
updates?: string[];
|
|
139
138
|
filters?: {
|
|
140
139
|
[key: string]: {
|
|
141
140
|
kind: 'Boolean' | 'String' | 'Float' | 'Int' | 'Variable';
|
|
@@ -165,7 +164,6 @@ export type SubscriptionSpec = {
|
|
|
165
164
|
export type FetchQueryResult<_Data> = {
|
|
166
165
|
result: RequestPayload<_Data | null>;
|
|
167
166
|
source: DataSource | null;
|
|
168
|
-
partial: boolean;
|
|
169
167
|
};
|
|
170
168
|
export type QueryResult<_Data = GraphQLObject, _Input = Record<string, any>> = {
|
|
171
169
|
data: _Data | null;
|
|
@@ -174,6 +172,7 @@ export type QueryResult<_Data = GraphQLObject, _Input = Record<string, any>> = {
|
|
|
174
172
|
}[] | null;
|
|
175
173
|
fetching: boolean;
|
|
176
174
|
partial: boolean;
|
|
175
|
+
stale: boolean;
|
|
177
176
|
source: DataSource | null;
|
|
178
177
|
variables: _Input | null;
|
|
179
178
|
};
|
|
@@ -2,7 +2,7 @@ import type { Cache as _Cache } from '../cache/cache';
|
|
|
2
2
|
import { type QueryArtifact } from '../lib';
|
|
3
3
|
import { ListCollection } from './list';
|
|
4
4
|
import { Record } from './record';
|
|
5
|
-
import type { CacheTypeDef, IDFields, QueryInput, QueryList, QueryValue, TypeNames, ValidLists } from './types';
|
|
5
|
+
import type { ArgType, CacheTypeDef, IDFields, QueryInput, QueryList, QueryValue, TypeFieldNames, TypeNames, ValidLists } from './types';
|
|
6
6
|
export declare class Cache<Def extends CacheTypeDef> {
|
|
7
7
|
_internal_unstable: _Cache;
|
|
8
8
|
constructor(cache: _Cache);
|
|
@@ -29,4 +29,11 @@ export declare class Cache<Def extends CacheTypeDef> {
|
|
|
29
29
|
data: QueryValue<QueryList<Def>, _Query>;
|
|
30
30
|
variables?: QueryInput<QueryList<Def>, _Query>;
|
|
31
31
|
}): void;
|
|
32
|
+
/**
|
|
33
|
+
* Mark some elements of the cache stale.
|
|
34
|
+
*/
|
|
35
|
+
markStale<_Type extends TypeNames<Def>, _Field extends TypeFieldNames<Def, _Type>>(type?: _Type, options?: {
|
|
36
|
+
field?: _Field;
|
|
37
|
+
when?: ArgType<Def, _Type, _Field>;
|
|
38
|
+
}): void;
|
|
32
39
|
}
|
|
@@ -87,6 +87,9 @@ Please acknowledge this by setting acceptImperativeInstability to true in your c
|
|
|
87
87
|
});
|
|
88
88
|
return;
|
|
89
89
|
}
|
|
90
|
+
markStale(type, options = {}) {
|
|
91
|
+
return this._internal_unstable.markTypeStale(type, options);
|
|
92
|
+
}
|
|
90
93
|
}
|
|
91
94
|
// Annotate the CommonJS export names for ESM import in node:
|
|
92
95
|
0 && (module.exports = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { FragmentArtifact } from '../lib/types';
|
|
2
2
|
import type { Cache } from './cache';
|
|
3
|
-
import type { CacheTypeDef, FragmentList, FragmentValue, FragmentVariables, ValidTypes } from './types';
|
|
3
|
+
import type { ArgType, CacheTypeDef, FragmentList, FragmentValue, FragmentVariables, TypeFieldNames, ValidTypes } from './types';
|
|
4
4
|
export declare class Record<Def extends CacheTypeDef, Type extends ValidTypes<Def>> {
|
|
5
5
|
#private;
|
|
6
6
|
type: string;
|
|
@@ -26,6 +26,16 @@ export declare class Record<Def extends CacheTypeDef, Type extends ValidTypes<De
|
|
|
26
26
|
fragment: _Fragment;
|
|
27
27
|
data: FragmentValue<FragmentList<Def, Type>, _Fragment>;
|
|
28
28
|
variables?: FragmentVariables<FragmentList<Def, Type>, _Fragment>;
|
|
29
|
+
forceStale?: boolean;
|
|
29
30
|
}): void;
|
|
30
31
|
delete(): void;
|
|
32
|
+
/**
|
|
33
|
+
* Mark some elements of the record stale in the cache.
|
|
34
|
+
* @param field
|
|
35
|
+
* @param when
|
|
36
|
+
*/
|
|
37
|
+
markStale<Field extends TypeFieldNames<Def, Type>>({ field, when, }?: {
|
|
38
|
+
field?: Field;
|
|
39
|
+
when?: ArgType<Def, Type, Field>;
|
|
40
|
+
}): void;
|
|
31
41
|
}
|
|
@@ -70,12 +70,19 @@ class Record {
|
|
|
70
70
|
config: this.#cache.config,
|
|
71
71
|
artifact: args.fragment.artifact,
|
|
72
72
|
input: args.variables
|
|
73
|
-
}) ?? void 0
|
|
73
|
+
}) ?? void 0,
|
|
74
|
+
forceStale: args.forceStale
|
|
74
75
|
});
|
|
75
76
|
}
|
|
76
77
|
delete() {
|
|
77
78
|
this.#cache._internal_unstable.delete(this.#id);
|
|
78
79
|
}
|
|
80
|
+
markStale({
|
|
81
|
+
field,
|
|
82
|
+
when
|
|
83
|
+
} = {}) {
|
|
84
|
+
this.#cache._internal_unstable.markRecordStale(this.#id, { field, when });
|
|
85
|
+
}
|
|
79
86
|
}
|
|
80
87
|
// Annotate the CommonJS export names for ESM import in node:
|
|
81
88
|
0 && (module.exports = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type SubscriptionSelection, type FragmentArtifact, type QueryArtifact } from '../../lib';
|
|
2
2
|
import { Cache } from '../cache';
|
|
3
3
|
import type { Record } from '../record';
|
|
4
|
-
type
|
|
4
|
+
export type CacheTypeDefTest = {
|
|
5
5
|
types: {
|
|
6
6
|
__ROOT__: {
|
|
7
7
|
idFields: {};
|
|
@@ -16,23 +16,23 @@ type CacheTypeDef = {
|
|
|
16
16
|
args: never;
|
|
17
17
|
};
|
|
18
18
|
viewer: {
|
|
19
|
-
type: Record<
|
|
19
|
+
type: Record<CacheTypeDefTest, 'User'> | null;
|
|
20
20
|
args: never;
|
|
21
21
|
};
|
|
22
22
|
pets: {
|
|
23
|
-
type: (Record<
|
|
23
|
+
type: (Record<CacheTypeDefTest, 'Cat'> | Record<CacheTypeDefTest, 'User'>)[];
|
|
24
24
|
args: never;
|
|
25
25
|
};
|
|
26
26
|
listOfLists: {
|
|
27
|
-
type: ((Record<
|
|
27
|
+
type: ((Record<CacheTypeDefTest, 'Cat'> | Record<CacheTypeDefTest, 'User'> | null | (null | Record<CacheTypeDefTest, 'User'>)[])[] | Record<CacheTypeDefTest, 'Cat'> | Record<CacheTypeDefTest, 'User'> | null)[];
|
|
28
28
|
args: never;
|
|
29
29
|
};
|
|
30
30
|
users: {
|
|
31
|
-
type: Record<
|
|
31
|
+
type: Record<CacheTypeDefTest, 'User'>[] | null;
|
|
32
32
|
args: never;
|
|
33
33
|
};
|
|
34
34
|
pet: {
|
|
35
|
-
type: Record<
|
|
35
|
+
type: Record<CacheTypeDefTest, 'Cat'> | Record<CacheTypeDefTest, 'User'>;
|
|
36
36
|
args: never;
|
|
37
37
|
};
|
|
38
38
|
};
|
|
@@ -60,7 +60,7 @@ type CacheTypeDef = {
|
|
|
60
60
|
args: never;
|
|
61
61
|
};
|
|
62
62
|
parent: {
|
|
63
|
-
type: Record<
|
|
63
|
+
type: Record<CacheTypeDefTest, 'User'>;
|
|
64
64
|
args: never;
|
|
65
65
|
};
|
|
66
66
|
id: {
|
|
@@ -84,7 +84,7 @@ type CacheTypeDef = {
|
|
|
84
84
|
args: never;
|
|
85
85
|
};
|
|
86
86
|
parent: {
|
|
87
|
-
type: Record<
|
|
87
|
+
type: Record<CacheTypeDefTest, 'User'> | null;
|
|
88
88
|
args: never;
|
|
89
89
|
};
|
|
90
90
|
id: {
|
|
@@ -147,11 +147,10 @@ type CacheTypeDef = {
|
|
|
147
147
|
};
|
|
148
148
|
};
|
|
149
149
|
};
|
|
150
|
-
export declare const testCache: () => Cache<
|
|
150
|
+
export declare const testCache: () => Cache<CacheTypeDefTest>;
|
|
151
151
|
export declare const testFragment: (selection: SubscriptionSelection) => {
|
|
152
152
|
artifact: FragmentArtifact;
|
|
153
153
|
};
|
|
154
154
|
export declare const testQuery: (selection: SubscriptionSelection) => {
|
|
155
155
|
artifact: QueryArtifact;
|
|
156
156
|
};
|
|
157
|
-
export {};
|
|
@@ -4,9 +4,10 @@ import { GarbageCollector } from './gc';
|
|
|
4
4
|
import type { ListCollection } from './lists';
|
|
5
5
|
import { ListManager } from './lists';
|
|
6
6
|
import { SchemaManager } from './schema';
|
|
7
|
+
import { StaleManager } from './staleManager';
|
|
7
8
|
import type { Layer, LayerID } from './storage';
|
|
8
9
|
import { InMemoryStorage } from './storage';
|
|
9
|
-
import { type FieldSelection
|
|
10
|
+
import { InMemorySubscriptions, type FieldSelection } from './subscription';
|
|
10
11
|
export declare class Cache {
|
|
11
12
|
_internal_unstable: CacheInternal;
|
|
12
13
|
constructor(config?: ConfigFile);
|
|
@@ -18,19 +19,30 @@ export declare class Cache {
|
|
|
18
19
|
variables?: {};
|
|
19
20
|
parent?: string;
|
|
20
21
|
layer?: LayerID | null;
|
|
21
|
-
applyUpdates?:
|
|
22
|
+
applyUpdates?: string[];
|
|
22
23
|
notifySubscribers?: SubscriptionSpec[];
|
|
23
24
|
forceNotify?: boolean;
|
|
25
|
+
forceStale?: boolean;
|
|
24
26
|
}): SubscriptionSpec[];
|
|
25
27
|
read(...args: Parameters<CacheInternal['getSelection']>): {
|
|
26
28
|
data: GraphQLObject | null;
|
|
27
29
|
partial: boolean;
|
|
30
|
+
stale: boolean;
|
|
28
31
|
};
|
|
29
32
|
subscribe(spec: SubscriptionSpec, variables?: {}): void;
|
|
30
33
|
unsubscribe(spec: SubscriptionSpec, variables?: {}): void;
|
|
31
34
|
list(name: string, parentID?: string, allLists?: boolean): ListCollection;
|
|
32
35
|
delete(id: string): void;
|
|
33
36
|
setConfig(config: ConfigFile): void;
|
|
37
|
+
markTypeStale(type?: string, options?: {
|
|
38
|
+
field?: string;
|
|
39
|
+
when?: {};
|
|
40
|
+
}): void;
|
|
41
|
+
markRecordStale(id: string, options: {
|
|
42
|
+
field?: string;
|
|
43
|
+
when?: {};
|
|
44
|
+
}): void;
|
|
45
|
+
getFieldTime(id: string, field: string): number | null | undefined;
|
|
34
46
|
}
|
|
35
47
|
declare class CacheInternal {
|
|
36
48
|
private _disabled;
|
|
@@ -40,17 +52,19 @@ declare class CacheInternal {
|
|
|
40
52
|
lists: ListManager;
|
|
41
53
|
cache: Cache;
|
|
42
54
|
lifetimes: GarbageCollector;
|
|
55
|
+
staleManager: StaleManager;
|
|
43
56
|
schema: SchemaManager;
|
|
44
|
-
constructor({ storage, subscriptions, lists, cache, lifetimes, schema, }: {
|
|
57
|
+
constructor({ storage, subscriptions, lists, cache, lifetimes, staleManager, schema, }: {
|
|
45
58
|
storage: InMemoryStorage;
|
|
46
59
|
subscriptions: InMemorySubscriptions;
|
|
47
60
|
lists: ListManager;
|
|
48
61
|
cache: Cache;
|
|
49
62
|
lifetimes: GarbageCollector;
|
|
63
|
+
staleManager: StaleManager;
|
|
50
64
|
schema: SchemaManager;
|
|
51
65
|
});
|
|
52
66
|
setConfig(config: ConfigFile): void;
|
|
53
|
-
writeSelection({ data, selection, variables, parent, applyUpdates, layer, toNotify, forceNotify, }: {
|
|
67
|
+
writeSelection({ data, selection, variables, parent, applyUpdates, layer, toNotify, forceNotify, forceStale, }: {
|
|
54
68
|
data: {
|
|
55
69
|
[key: string]: GraphQLValue;
|
|
56
70
|
};
|
|
@@ -62,8 +76,9 @@ declare class CacheInternal {
|
|
|
62
76
|
root?: string;
|
|
63
77
|
layer: Layer;
|
|
64
78
|
toNotify?: FieldSelection[];
|
|
65
|
-
applyUpdates?:
|
|
79
|
+
applyUpdates?: string[];
|
|
66
80
|
forceNotify?: boolean;
|
|
81
|
+
forceStale?: boolean;
|
|
67
82
|
}): FieldSelection[];
|
|
68
83
|
getSelection({ selection, parent, variables, stepsFromConnection, }: {
|
|
69
84
|
selection: SubscriptionSelection;
|
|
@@ -73,6 +88,7 @@ declare class CacheInternal {
|
|
|
73
88
|
}): {
|
|
74
89
|
data: GraphQLObject | null;
|
|
75
90
|
partial: boolean;
|
|
91
|
+
stale: boolean;
|
|
76
92
|
hasData: boolean;
|
|
77
93
|
};
|
|
78
94
|
id(type: string, data: {} | null): string | null;
|
|
@@ -87,6 +103,7 @@ declare class CacheInternal {
|
|
|
87
103
|
}): {
|
|
88
104
|
data: LinkedList<GraphQLValue>;
|
|
89
105
|
partial: boolean;
|
|
106
|
+
stale: boolean;
|
|
90
107
|
hasData: boolean;
|
|
91
108
|
};
|
|
92
109
|
extractNestedListIDs({ value, abstract, recordID, key, linkedType, fields, variables, applyUpdates, specs, layer, forceNotify, }: {
|
|
@@ -97,7 +114,7 @@ declare class CacheInternal {
|
|
|
97
114
|
abstract: boolean;
|
|
98
115
|
variables: {};
|
|
99
116
|
specs: FieldSelection[];
|
|
100
|
-
applyUpdates
|
|
117
|
+
applyUpdates?: string[];
|
|
101
118
|
fields: SubscriptionSelection;
|
|
102
119
|
layer: Layer;
|
|
103
120
|
forceNotify?: boolean;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { computeKey } from "../lib";
|
|
2
|
+
import { computeID, defaultConfigValues, keyFieldsForType } from "../lib/config";
|
|
2
3
|
import { deepEquals } from "../lib/deepEquals";
|
|
3
4
|
import { getFieldsForType } from "../lib/selection";
|
|
4
5
|
import { GarbageCollector } from "./gc";
|
|
5
6
|
import { ListManager } from "./lists";
|
|
6
7
|
import { SchemaManager } from "./schema";
|
|
8
|
+
import { StaleManager } from "./staleManager";
|
|
7
9
|
import { InMemoryStorage } from "./storage";
|
|
8
10
|
import { evaluateKey, flattenList } from "./stuff";
|
|
9
11
|
import { InMemorySubscriptions } from "./subscription";
|
|
@@ -16,6 +18,7 @@ class Cache {
|
|
|
16
18
|
subscriptions: new InMemorySubscriptions(this),
|
|
17
19
|
lists: new ListManager(this, rootID),
|
|
18
20
|
lifetimes: new GarbageCollector(this),
|
|
21
|
+
staleManager: new StaleManager(this),
|
|
19
22
|
schema: new SchemaManager(this)
|
|
20
23
|
});
|
|
21
24
|
if (config) {
|
|
@@ -45,13 +48,14 @@ class Cache {
|
|
|
45
48
|
return subscribers;
|
|
46
49
|
}
|
|
47
50
|
read(...args) {
|
|
48
|
-
const { data, partial, hasData } = this._internal_unstable.getSelection(...args);
|
|
51
|
+
const { data, partial, stale, hasData } = this._internal_unstable.getSelection(...args);
|
|
49
52
|
if (!hasData) {
|
|
50
|
-
return { data: null, partial: false };
|
|
53
|
+
return { data: null, partial: false, stale: false };
|
|
51
54
|
}
|
|
52
55
|
return {
|
|
53
56
|
data,
|
|
54
|
-
partial
|
|
57
|
+
partial,
|
|
58
|
+
stale
|
|
55
59
|
};
|
|
56
60
|
}
|
|
57
61
|
subscribe(spec, variables = {}) {
|
|
@@ -87,6 +91,30 @@ class Cache {
|
|
|
87
91
|
setConfig(config) {
|
|
88
92
|
this._internal_unstable.setConfig(config);
|
|
89
93
|
}
|
|
94
|
+
markTypeStale(type, options = {}) {
|
|
95
|
+
if (!type) {
|
|
96
|
+
this._internal_unstable.staleManager.markAllStale();
|
|
97
|
+
} else if (!options.field) {
|
|
98
|
+
this._internal_unstable.staleManager.markTypeStale(type);
|
|
99
|
+
} else {
|
|
100
|
+
this._internal_unstable.staleManager.markTypeFieldStale(
|
|
101
|
+
type,
|
|
102
|
+
options.field,
|
|
103
|
+
options.when
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
markRecordStale(id, options) {
|
|
108
|
+
if (options.field) {
|
|
109
|
+
const key = computeKey({ field: options.field, args: options.when ?? {} });
|
|
110
|
+
this._internal_unstable.staleManager.markFieldStale(id, key);
|
|
111
|
+
} else {
|
|
112
|
+
this._internal_unstable.staleManager.markRecordStale(id);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
getFieldTime(id, field) {
|
|
116
|
+
return this._internal_unstable.staleManager.getFieldTime(id, field);
|
|
117
|
+
}
|
|
90
118
|
}
|
|
91
119
|
class CacheInternal {
|
|
92
120
|
_disabled = false;
|
|
@@ -102,6 +130,7 @@ class CacheInternal {
|
|
|
102
130
|
lists;
|
|
103
131
|
cache;
|
|
104
132
|
lifetimes;
|
|
133
|
+
staleManager;
|
|
105
134
|
schema;
|
|
106
135
|
constructor({
|
|
107
136
|
storage,
|
|
@@ -109,6 +138,7 @@ class CacheInternal {
|
|
|
109
138
|
lists,
|
|
110
139
|
cache,
|
|
111
140
|
lifetimes,
|
|
141
|
+
staleManager,
|
|
112
142
|
schema
|
|
113
143
|
}) {
|
|
114
144
|
this.storage = storage;
|
|
@@ -116,6 +146,7 @@ class CacheInternal {
|
|
|
116
146
|
this.lists = lists;
|
|
117
147
|
this.cache = cache;
|
|
118
148
|
this.lifetimes = lifetimes;
|
|
149
|
+
this.staleManager = staleManager;
|
|
119
150
|
this.schema = schema;
|
|
120
151
|
this._disabled = typeof globalThis.window === "undefined";
|
|
121
152
|
try {
|
|
@@ -133,10 +164,11 @@ class CacheInternal {
|
|
|
133
164
|
selection,
|
|
134
165
|
variables = {},
|
|
135
166
|
parent = rootID,
|
|
136
|
-
applyUpdates
|
|
167
|
+
applyUpdates,
|
|
137
168
|
layer,
|
|
138
169
|
toNotify = [],
|
|
139
|
-
forceNotify
|
|
170
|
+
forceNotify,
|
|
171
|
+
forceStale
|
|
140
172
|
}) {
|
|
141
173
|
if (this._disabled) {
|
|
142
174
|
return [];
|
|
@@ -154,7 +186,7 @@ class CacheInternal {
|
|
|
154
186
|
selection: fieldSelection,
|
|
155
187
|
operations,
|
|
156
188
|
abstract: isAbstract,
|
|
157
|
-
|
|
189
|
+
updates,
|
|
158
190
|
nullable
|
|
159
191
|
} = targetSelection[field];
|
|
160
192
|
const key = evaluateKey(keyRaw, variables);
|
|
@@ -171,16 +203,31 @@ class CacheInternal {
|
|
|
171
203
|
const displayLayer = layer.isDisplayLayer(displayLayers);
|
|
172
204
|
if (displayLayer) {
|
|
173
205
|
this.lifetimes.resetLifetime(parent, key);
|
|
206
|
+
if (forceStale) {
|
|
207
|
+
this.staleManager.markFieldStale(parent, key);
|
|
208
|
+
} else {
|
|
209
|
+
this.staleManager.setFieldTimeToNow(parent, key);
|
|
210
|
+
}
|
|
174
211
|
}
|
|
175
212
|
if (!fieldSelection) {
|
|
176
213
|
let newValue = value;
|
|
177
|
-
if (
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
214
|
+
if (updates && applyUpdates && Array.isArray(value)) {
|
|
215
|
+
for (const update of applyUpdates) {
|
|
216
|
+
if (!updates.includes(update)) {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
if (update === "append") {
|
|
220
|
+
newValue = (previousValue || []).concat(value);
|
|
221
|
+
} else if (update === "prepend") {
|
|
222
|
+
newValue = value.concat(previousValue || []);
|
|
223
|
+
}
|
|
182
224
|
}
|
|
183
225
|
}
|
|
226
|
+
if (updates && applyUpdates?.includes("prepend") && ["endCursor", "hasNextPage"].includes(key)) {
|
|
227
|
+
newValue = previousValue;
|
|
228
|
+
} else if (updates && applyUpdates?.includes("append") && ["startCursor", "hasPreviousPage"].includes(key)) {
|
|
229
|
+
newValue = previousValue;
|
|
230
|
+
}
|
|
184
231
|
const valueChanged = !deepEquals(newValue, previousValue);
|
|
185
232
|
if (displayLayer && (valueChanged || forceNotify)) {
|
|
186
233
|
toNotify.push(...currentSubscribers);
|
|
@@ -240,7 +287,7 @@ class CacheInternal {
|
|
|
240
287
|
}
|
|
241
288
|
} else if (Array.isArray(value) && (typeof previousValue === "undefined" || Array.isArray(previousValue))) {
|
|
242
289
|
let oldIDs = [...previousValue || []];
|
|
243
|
-
const emptyEdges = !
|
|
290
|
+
const emptyEdges = !updates ? [] : oldIDs.map((id) => {
|
|
244
291
|
if (!id) {
|
|
245
292
|
return "";
|
|
246
293
|
}
|
|
@@ -268,7 +315,7 @@ class CacheInternal {
|
|
|
268
315
|
layer,
|
|
269
316
|
forceNotify
|
|
270
317
|
});
|
|
271
|
-
if (applyUpdates &&
|
|
318
|
+
if (applyUpdates && updates) {
|
|
272
319
|
if (key === "edges") {
|
|
273
320
|
const newNodeIDs = [];
|
|
274
321
|
for (const id of newIDs) {
|
|
@@ -296,12 +343,17 @@ class CacheInternal {
|
|
|
296
343
|
return true;
|
|
297
344
|
});
|
|
298
345
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
346
|
+
for (const update of applyUpdates) {
|
|
347
|
+
if (update !== "replace" && !updates.includes(update)) {
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
if (update === "prepend") {
|
|
351
|
+
linkedIDs = newIDs.concat(oldIDs);
|
|
352
|
+
} else if (update === "append") {
|
|
353
|
+
linkedIDs = oldIDs.concat(newIDs);
|
|
354
|
+
} else if (update === "replace") {
|
|
355
|
+
linkedIDs = newIDs;
|
|
356
|
+
}
|
|
305
357
|
}
|
|
306
358
|
} else {
|
|
307
359
|
linkedIDs = nestedIDs;
|
|
@@ -387,12 +439,13 @@ class CacheInternal {
|
|
|
387
439
|
stepsFromConnection = null
|
|
388
440
|
}) {
|
|
389
441
|
if (parent === null) {
|
|
390
|
-
return { data: null, partial: false, hasData: true };
|
|
442
|
+
return { data: null, partial: false, stale: false, hasData: true };
|
|
391
443
|
}
|
|
392
444
|
const target = {};
|
|
393
445
|
let hasData = false;
|
|
394
446
|
let partial = false;
|
|
395
447
|
let cascadeNull = false;
|
|
448
|
+
let stale = false;
|
|
396
449
|
const typename = this.storage.get(parent, "__typename").value;
|
|
397
450
|
let targetSelection = getFieldsForType(selection, typename);
|
|
398
451
|
for (const [
|
|
@@ -401,6 +454,10 @@ class CacheInternal {
|
|
|
401
454
|
] of Object.entries(targetSelection)) {
|
|
402
455
|
const key = evaluateKey(keyRaw, variables);
|
|
403
456
|
const { value } = this.storage.get(parent, key);
|
|
457
|
+
const dt_field = this.staleManager.getFieldTime(parent, key);
|
|
458
|
+
if (dt_field === null) {
|
|
459
|
+
stale = true;
|
|
460
|
+
}
|
|
404
461
|
let nextStep = stepsFromConnection;
|
|
405
462
|
if (nextStep !== null) {
|
|
406
463
|
if (nextStep >= 2) {
|
|
@@ -440,6 +497,9 @@ class CacheInternal {
|
|
|
440
497
|
if (listValue.partial) {
|
|
441
498
|
partial = true;
|
|
442
499
|
}
|
|
500
|
+
if (listValue.stale) {
|
|
501
|
+
stale = true;
|
|
502
|
+
}
|
|
443
503
|
if (listValue.hasData || value.length === 0) {
|
|
444
504
|
hasData = true;
|
|
445
505
|
}
|
|
@@ -454,6 +514,9 @@ class CacheInternal {
|
|
|
454
514
|
if (objectFields.partial) {
|
|
455
515
|
partial = true;
|
|
456
516
|
}
|
|
517
|
+
if (objectFields.stale) {
|
|
518
|
+
stale = true;
|
|
519
|
+
}
|
|
457
520
|
if (objectFields.hasData) {
|
|
458
521
|
hasData = true;
|
|
459
522
|
}
|
|
@@ -465,6 +528,7 @@ class CacheInternal {
|
|
|
465
528
|
return {
|
|
466
529
|
data: cascadeNull ? null : target,
|
|
467
530
|
partial: hasData && partial,
|
|
531
|
+
stale: hasData && stale,
|
|
468
532
|
hasData
|
|
469
533
|
};
|
|
470
534
|
}
|
|
@@ -492,6 +556,7 @@ class CacheInternal {
|
|
|
492
556
|
}) {
|
|
493
557
|
const result = [];
|
|
494
558
|
let partialData = false;
|
|
559
|
+
let stale = false;
|
|
495
560
|
let hasValues = false;
|
|
496
561
|
for (const entry of linkedList) {
|
|
497
562
|
if (Array.isArray(entry)) {
|
|
@@ -511,7 +576,12 @@ class CacheInternal {
|
|
|
511
576
|
result.push(entry);
|
|
512
577
|
continue;
|
|
513
578
|
}
|
|
514
|
-
const {
|
|
579
|
+
const {
|
|
580
|
+
data,
|
|
581
|
+
partial,
|
|
582
|
+
stale: local_stale,
|
|
583
|
+
hasData
|
|
584
|
+
} = this.getSelection({
|
|
515
585
|
parent: entry,
|
|
516
586
|
selection: fields,
|
|
517
587
|
variables,
|
|
@@ -521,6 +591,9 @@ class CacheInternal {
|
|
|
521
591
|
if (partial) {
|
|
522
592
|
partialData = true;
|
|
523
593
|
}
|
|
594
|
+
if (local_stale) {
|
|
595
|
+
stale = true;
|
|
596
|
+
}
|
|
524
597
|
if (hasData) {
|
|
525
598
|
hasValues = true;
|
|
526
599
|
}
|
|
@@ -528,6 +601,7 @@ class CacheInternal {
|
|
|
528
601
|
return {
|
|
529
602
|
data: result,
|
|
530
603
|
partial: partialData,
|
|
604
|
+
stale,
|
|
531
605
|
hasData: hasValues
|
|
532
606
|
};
|
|
533
607
|
}
|
|
@@ -14,6 +14,8 @@ class GarbageCollector {
|
|
|
14
14
|
this.lifetimes.get(id).set(field, 0);
|
|
15
15
|
}
|
|
16
16
|
tick() {
|
|
17
|
+
const dt_tick = Date.now().valueOf();
|
|
18
|
+
const config_max_time = this.cache._internal_unstable.config.defaultLifetime;
|
|
17
19
|
for (const [id, fieldMap] of this.lifetimes.entries()) {
|
|
18
20
|
for (const [field, lifetime] of fieldMap.entries()) {
|
|
19
21
|
if (this.cache._internal_unstable.subscriptions.get(id, field).length > 0) {
|
|
@@ -27,6 +29,13 @@ class GarbageCollector {
|
|
|
27
29
|
if ([...fieldMap.keys()].length === 0) {
|
|
28
30
|
this.lifetimes.delete(id);
|
|
29
31
|
}
|
|
32
|
+
this.cache._internal_unstable.staleManager.delete(id, field);
|
|
33
|
+
}
|
|
34
|
+
if (config_max_time && config_max_time > 0) {
|
|
35
|
+
const dt_valueOf = this.cache.getFieldTime(id, field);
|
|
36
|
+
if (dt_valueOf && dt_tick - dt_valueOf > config_max_time) {
|
|
37
|
+
this.cache._internal_unstable.staleManager.markFieldStale(id, field);
|
|
38
|
+
}
|
|
30
39
|
}
|
|
31
40
|
}
|
|
32
41
|
}
|
|
@@ -151,7 +151,7 @@ class List {
|
|
|
151
151
|
edges: {
|
|
152
152
|
keyRaw: "edges",
|
|
153
153
|
type: "ConnectionEdge",
|
|
154
|
-
|
|
154
|
+
updates: ["append", "prepend"],
|
|
155
155
|
selection: {
|
|
156
156
|
fields: {
|
|
157
157
|
node: {
|
|
@@ -187,7 +187,7 @@ class List {
|
|
|
187
187
|
newEntries: {
|
|
188
188
|
keyRaw: this.key,
|
|
189
189
|
type: listType,
|
|
190
|
-
|
|
190
|
+
updates: ["append", "prepend"],
|
|
191
191
|
selection: {
|
|
192
192
|
...selection,
|
|
193
193
|
fields: {
|
|
@@ -210,7 +210,7 @@ class List {
|
|
|
210
210
|
data: insertData,
|
|
211
211
|
variables,
|
|
212
212
|
parent: this.recordID,
|
|
213
|
-
applyUpdates:
|
|
213
|
+
applyUpdates: [where === "first" ? "prepend" : "append"]
|
|
214
214
|
});
|
|
215
215
|
}
|
|
216
216
|
removeID(id, variables = {}) {
|