zova-module-a-model 5.1.37 → 5.1.39
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/.metadata/index.d.ts +7 -7
- package/dist/.metadata/index.d.ts.map +1 -1
- package/dist/.metadata/this.d.ts +1 -1
- package/dist/bean/bean.model/bean.model.cookie.d.ts +2 -2
- package/dist/bean/bean.model/bean.model.first.d.ts +1 -1
- package/dist/bean/bean.model/bean.model.last.d.ts +3 -3
- package/dist/bean/bean.model/bean.model.local.d.ts +1 -1
- package/dist/bean/bean.model/bean.model.persister.d.ts +15 -6
- package/dist/bean/bean.model/bean.model.persister.d.ts.map +1 -1
- package/dist/bean/bean.model/bean.model.query.d.ts +2 -2
- package/dist/bean/bean.model/bean.model.query.d.ts.map +1 -1
- package/dist/bean/bean.model/bean.model.useMutation.d.ts +2 -2
- package/dist/bean/bean.model/bean.model.useQuery.d.ts +3 -3
- package/dist/bean/bean.model/bean.model.useQuery.d.ts.map +1 -1
- package/dist/bean/bean.model/bean.model.useState.d.ts +3 -3
- package/dist/bean/bean.model/bean.model.useState.d.ts.map +1 -1
- package/dist/bean/bean.model/bean.model.useStateGeneral.d.ts +3 -3
- package/dist/bean/bean.modelBase.d.ts +1 -1
- package/dist/common/cookieWrapper.d.ts +1 -1
- package/dist/config/config.d.ts +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +501 -68
- package/dist/index.js.map +1 -1
- package/dist/lib/index.d.ts +3 -2
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/model.d.ts +1 -1
- package/dist/lib/modelPersistence.d.ts +39 -0
- package/dist/lib/modelPersistence.d.ts.map +1 -0
- package/dist/lib/persistenceQueue.d.ts +14 -0
- package/dist/lib/persistenceQueue.d.ts.map +1 -0
- package/dist/lib/queryRefetch.d.ts +1 -1
- package/dist/lib/utils.d.ts +1 -1
- package/dist/monkey.d.ts.map +1 -1
- package/dist/service/storage.d.ts +15 -0
- package/dist/service/storage.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/query.d.ts +2 -0
- package/dist/types/query.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/.metadata/index.ts +7 -7
- package/src/.metadata/this.ts +1 -1
- package/src/bean/bean.model/bean.model.cookie.ts +2 -2
- package/src/bean/bean.model/bean.model.first.ts +1 -1
- package/src/bean/bean.model/bean.model.last.ts +4 -4
- package/src/bean/bean.model/bean.model.local.ts +1 -1
- package/src/bean/bean.model/bean.model.persister.ts +336 -92
- package/src/bean/bean.model/bean.model.query.ts +13 -8
- package/src/bean/bean.model/bean.model.useMutation.ts +2 -2
- package/src/bean/bean.model/bean.model.useQuery.ts +8 -6
- package/src/bean/bean.model/bean.model.useState.ts +20 -4
- package/src/bean/bean.model/bean.model.useStateGeneral.ts +4 -4
- package/src/bean/bean.modelBase.ts +1 -1
- package/src/common/cookieWrapper.ts +3 -3
- package/src/config/config.ts +1 -1
- package/src/index.ts +3 -3
- package/src/lib/index.ts +3 -2
- package/src/lib/model.ts +1 -1
- package/src/lib/modelPersistence.ts +204 -0
- package/src/lib/persistenceQueue.ts +50 -0
- package/src/lib/queryRefetch.ts +1 -1
- package/src/lib/utils.ts +1 -1
- package/src/monkey.ts +6 -1
- package/src/service/storage.ts +47 -2
- package/src/types/index.ts +2 -2
- package/src/types/query.ts +3 -0
|
@@ -3,11 +3,11 @@ import type { DefaultError, QueryClient, QueryKey, UseQueryOptions } from '@tans
|
|
|
3
3
|
import type {
|
|
4
4
|
DefinedInitialQueryOptions,
|
|
5
5
|
UndefinedInitialQueryOptions,
|
|
6
|
-
} from '../../common/types.
|
|
7
|
-
import type { ModelUseQueryDefinedReturnType, ModelUseQueryReturnType } from '../../types/query.
|
|
8
|
-
import type { StateType } from '../../types/query.
|
|
6
|
+
} from '../../common/types.ts';
|
|
7
|
+
import type { ModelUseQueryDefinedReturnType, ModelUseQueryReturnType } from '../../types/query.ts';
|
|
8
|
+
import type { StateType } from '../../types/query.ts';
|
|
9
9
|
|
|
10
|
-
import { BeanModelUseState } from './bean.model.useState.
|
|
10
|
+
import { BeanModelUseState } from './bean.model.useState.ts';
|
|
11
11
|
|
|
12
12
|
export class BeanModelUseStateGeneral extends BeanModelUseState {
|
|
13
13
|
$useState<
|
|
@@ -3,10 +3,10 @@ import type { CookieOptions } from 'zova';
|
|
|
3
3
|
|
|
4
4
|
import { BeanSimple } from 'zova';
|
|
5
5
|
|
|
6
|
-
import type { QueryMetaPersister } from '../types/index.
|
|
6
|
+
import type { QueryMetaPersister } from '../types/index.ts';
|
|
7
7
|
|
|
8
|
-
import { __ThisModule__ } from '../.metadata/this.
|
|
9
|
-
import { resolveMaxAgeTime } from '../types/index.
|
|
8
|
+
import { __ThisModule__ } from '../.metadata/this.ts';
|
|
9
|
+
import { resolveMaxAgeTime } from '../types/index.ts';
|
|
10
10
|
|
|
11
11
|
export class CookieWrapper extends BeanSimple {
|
|
12
12
|
options: QueryMetaPersister;
|
package/src/config/config.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { CookieOptions, ZovaSys } from 'zova';
|
|
|
3
3
|
|
|
4
4
|
import { defaultShouldDehydrateQuery } from '@tanstack/vue-query';
|
|
5
5
|
|
|
6
|
-
import type { MaxAgeTime, StaleTimeFunction } from '../types/index.
|
|
6
|
+
import type { MaxAgeTime, StaleTimeFunction } from '../types/index.ts';
|
|
7
7
|
|
|
8
8
|
const defaultOptions: DefaultOptions = {
|
|
9
9
|
queries: {
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export * from './.metadata/index.
|
|
2
|
-
export * from './lib/index.
|
|
3
|
-
export * from './types/index.
|
|
1
|
+
export * from './.metadata/index.ts';
|
|
2
|
+
export * from './lib/index.ts';
|
|
3
|
+
export * from './types/index.ts';
|
package/src/lib/index.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export * from './model.
|
|
2
|
-
export * from './
|
|
1
|
+
export * from './model.ts';
|
|
2
|
+
export * from './modelPersistence.ts';
|
|
3
|
+
export * from './utils.ts';
|
package/src/lib/model.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createBeanDecorator } from 'zova';
|
|
2
2
|
|
|
3
|
-
import type { IDecoratorModelOptions } from '../types/model.
|
|
3
|
+
import type { IDecoratorModelOptions } from '../types/model.ts';
|
|
4
4
|
|
|
5
5
|
export function Model<T extends IDecoratorModelOptions>(options?: T): ClassDecorator {
|
|
6
6
|
return createBeanDecorator('model', 'ctx', true, options);
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import type { Query, QueryClient, QueryOptions } from '@tanstack/query-core';
|
|
2
|
+
|
|
3
|
+
import { notifyManager } from '@tanstack/query-core';
|
|
4
|
+
import { markRaw, shallowRef } from 'vue';
|
|
5
|
+
|
|
6
|
+
export type ModelPersistenceScope = readonly [string | null, string | null, string | null];
|
|
7
|
+
export interface ModelPersistenceValues {
|
|
8
|
+
instanceId?: string | number | null;
|
|
9
|
+
siteId?: string | number | null;
|
|
10
|
+
userId?: string | number | null;
|
|
11
|
+
}
|
|
12
|
+
export interface ModelPersistenceToken {
|
|
13
|
+
readonly scope: ModelPersistenceScope;
|
|
14
|
+
readonly epoch: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const normalize = (value: string | number | null | undefined) =>
|
|
18
|
+
value == null ? null : String(value);
|
|
19
|
+
|
|
20
|
+
export function getModelPersistenceStorageKey(
|
|
21
|
+
appName: string,
|
|
22
|
+
scope: ModelPersistenceScope,
|
|
23
|
+
logicalKey: string,
|
|
24
|
+
): string {
|
|
25
|
+
return JSON.stringify(['zova-model-db', 1, appName, scope, logicalKey]);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function isModelPersistenceDb(options?: unknown): boolean {
|
|
29
|
+
if (options === false) return false;
|
|
30
|
+
const persister =
|
|
31
|
+
options && typeof options === 'object' ? (options as { storage?: string; sync?: boolean }) : {};
|
|
32
|
+
return (persister.storage ?? (persister.sync ? 'local' : 'db')) === 'db';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function emptyQueryState() {
|
|
36
|
+
return {
|
|
37
|
+
data: undefined,
|
|
38
|
+
dataUpdateCount: 0,
|
|
39
|
+
dataUpdatedAt: 0,
|
|
40
|
+
error: null,
|
|
41
|
+
errorUpdateCount: 0,
|
|
42
|
+
errorUpdatedAt: 0,
|
|
43
|
+
fetchFailureCount: 0,
|
|
44
|
+
fetchFailureReason: null,
|
|
45
|
+
fetchMeta: null,
|
|
46
|
+
isInvalidated: false,
|
|
47
|
+
status: 'pending' as const,
|
|
48
|
+
fetchStatus: 'idle' as const,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** App-owned identity; independent of the module providing the current Passport. */
|
|
53
|
+
export class ModelPersistenceContext {
|
|
54
|
+
private _epoch = 0;
|
|
55
|
+
private _version = shallowRef(0);
|
|
56
|
+
private _scope: ModelPersistenceScope;
|
|
57
|
+
private _registered = false;
|
|
58
|
+
private _hydrated = new Set<Query>();
|
|
59
|
+
private _listeners = new Set<(token: ModelPersistenceToken) => void>();
|
|
60
|
+
|
|
61
|
+
constructor(
|
|
62
|
+
private _queryClient: QueryClient,
|
|
63
|
+
siteId?: string | number | null,
|
|
64
|
+
) {
|
|
65
|
+
// IoC owners can be reactive; do not let Vue unwrap this class's private refs
|
|
66
|
+
// or proxy TanStack Query instances retained for hydration adoption.
|
|
67
|
+
markRaw(this);
|
|
68
|
+
this._scope = Object.freeze([null, normalize(siteId), null]);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
get epoch(): number {
|
|
72
|
+
void this._version.value;
|
|
73
|
+
return this._epoch;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
capture(): ModelPersistenceToken {
|
|
77
|
+
return Object.freeze({ scope: this._scope, epoch: this.epoch });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
current(token: ModelPersistenceToken): boolean {
|
|
81
|
+
return token.epoch === this.epoch && token.scope === this._scope;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
markHydrated(queries: Query[]) {
|
|
85
|
+
if (!this._registered) {
|
|
86
|
+
for (const query of queries) this._hydrated.add(query);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
touch(query?: Query): void {
|
|
91
|
+
// A transferred Query that has since participated in DB work belongs to the
|
|
92
|
+
// actual invocation scope, not the one-time hydration adoption baseline.
|
|
93
|
+
if (query) this._hydrated.delete(query);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
subscribe(listener: (token: ModelPersistenceToken) => void): () => void {
|
|
97
|
+
this._listeners.add(listener);
|
|
98
|
+
return () => this._listeners.delete(listener);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
update(
|
|
102
|
+
values: ModelPersistenceValues,
|
|
103
|
+
options: { initial?: boolean; refetchActive?: boolean } = {},
|
|
104
|
+
): void {
|
|
105
|
+
const scope: ModelPersistenceScope = Object.freeze([
|
|
106
|
+
normalize(values.instanceId),
|
|
107
|
+
normalize(values.siteId),
|
|
108
|
+
normalize(values.userId),
|
|
109
|
+
]);
|
|
110
|
+
const adopt = !this._registered && options.initial === true;
|
|
111
|
+
this._registered = true;
|
|
112
|
+
if (scope.every((value, index) => value === this._scope[index])) {
|
|
113
|
+
this._hydrated.clear();
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const affected = this._queryClient
|
|
117
|
+
.getQueryCache()
|
|
118
|
+
.getAll()
|
|
119
|
+
.filter(
|
|
120
|
+
query =>
|
|
121
|
+
isModelPersistenceDb(query.meta?.persister) && !(adopt && this._hydrated.has(query)),
|
|
122
|
+
);
|
|
123
|
+
this._scope = scope;
|
|
124
|
+
this._hydrated.clear();
|
|
125
|
+
this._invalidate(affected);
|
|
126
|
+
// Outgoing relogin/logout still resets immediately, but must not refetch
|
|
127
|
+
// protected queries after their authentication has been removed.
|
|
128
|
+
if (options.refetchActive === false) return;
|
|
129
|
+
const token = this.capture();
|
|
130
|
+
// The identity owner installs authentication before publishing this transition.
|
|
131
|
+
// Defer refetch until all synchronous reset/listener work has finished.
|
|
132
|
+
void Promise.resolve().then(() => {
|
|
133
|
+
if (this.current(token)) {
|
|
134
|
+
return this._queryClient.refetchQueries({
|
|
135
|
+
type: 'active',
|
|
136
|
+
predicate: query => affected.includes(query),
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
clear(): void {
|
|
143
|
+
this._hydrated.clear();
|
|
144
|
+
this._invalidate(this._queryClient.getQueryCache().getAll());
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
private _invalidate(queries: Query[]): void {
|
|
148
|
+
this._epoch++;
|
|
149
|
+
// Cancel every retryer before resetting any query. Silent + non-reverting avoids
|
|
150
|
+
// the old fetch's asynchronous cancellation handler publishing an error/reset.
|
|
151
|
+
for (const query of queries) void query.cancel({ silent: true, revert: false });
|
|
152
|
+
notifyManager.batch(() => {
|
|
153
|
+
for (const query of queries) {
|
|
154
|
+
query.setOptions({
|
|
155
|
+
...query.options,
|
|
156
|
+
initialData: undefined,
|
|
157
|
+
initialDataUpdatedAt: undefined,
|
|
158
|
+
});
|
|
159
|
+
for (const observer of query.observers) {
|
|
160
|
+
observer.setOptions({
|
|
161
|
+
...observer.options,
|
|
162
|
+
initialData: undefined,
|
|
163
|
+
initialDataUpdatedAt: undefined,
|
|
164
|
+
placeholderData: undefined,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
query.setState(emptyQueryState());
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
this._version.value++;
|
|
171
|
+
const token = this.capture();
|
|
172
|
+
for (const listener of this._listeners) listener(token);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** Keep later observer option reapplication from reinstalling an old identity. */
|
|
176
|
+
guardOptions<T extends QueryOptions>(options: T): T {
|
|
177
|
+
if (!isModelPersistenceDb(options.meta?.persister)) return options;
|
|
178
|
+
const token = this.capture();
|
|
179
|
+
const initialData = options.initialData;
|
|
180
|
+
const initialDataUpdatedAt = options.initialDataUpdatedAt;
|
|
181
|
+
const placeholderData = (options as T & { placeholderData?: unknown }).placeholderData;
|
|
182
|
+
return {
|
|
183
|
+
...options,
|
|
184
|
+
initialData: () =>
|
|
185
|
+
this.current(token)
|
|
186
|
+
? typeof initialData === 'function'
|
|
187
|
+
? initialData()
|
|
188
|
+
: initialData
|
|
189
|
+
: undefined,
|
|
190
|
+
initialDataUpdatedAt: () =>
|
|
191
|
+
this.current(token)
|
|
192
|
+
? typeof initialDataUpdatedAt === 'function'
|
|
193
|
+
? initialDataUpdatedAt()
|
|
194
|
+
: initialDataUpdatedAt
|
|
195
|
+
: undefined,
|
|
196
|
+
placeholderData: (...args: unknown[]) =>
|
|
197
|
+
this.current(token)
|
|
198
|
+
? typeof placeholderData === 'function'
|
|
199
|
+
? placeholderData(...args)
|
|
200
|
+
: placeholderData
|
|
201
|
+
: undefined,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export class PersistenceQueue {
|
|
2
|
+
private _tail: Promise<unknown> = Promise.resolve();
|
|
3
|
+
private _sequence = 0;
|
|
4
|
+
private _failure?: { sequence: number; error: unknown };
|
|
5
|
+
private _generation = 0;
|
|
6
|
+
private _keyGenerations = new Map<string, number>();
|
|
7
|
+
|
|
8
|
+
generation(key: string): string {
|
|
9
|
+
return `${this._generation}:${this._keyGenerations.get(key) ?? 0}`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
invalidate(key: string) {
|
|
13
|
+
this._keyGenerations.set(key, (this._keyGenerations.get(key) ?? 0) + 1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
invalidateAll() {
|
|
17
|
+
this._generation++;
|
|
18
|
+
this._keyGenerations.clear();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
enqueue<T>(operation: () => T | PromiseLike<T>): Promise<T> {
|
|
22
|
+
const sequence = ++this._sequence;
|
|
23
|
+
const result = this._tail.then(operation);
|
|
24
|
+
this._tail = result.catch(error => {
|
|
25
|
+
this._failure ??= { sequence, error };
|
|
26
|
+
});
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async flush(): Promise<void> {
|
|
31
|
+
const sequence = this._sequence;
|
|
32
|
+
await this._tail;
|
|
33
|
+
if (this._failure && this._failure.sequence <= sequence) {
|
|
34
|
+
const { error } = this._failure;
|
|
35
|
+
this._failure = undefined;
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const queues = new WeakMap<object, PersistenceQueue>();
|
|
42
|
+
|
|
43
|
+
export function getPersistenceQueue(storage: object): PersistenceQueue {
|
|
44
|
+
let queue = queues.get(storage);
|
|
45
|
+
if (!queue) {
|
|
46
|
+
queue = new PersistenceQueue();
|
|
47
|
+
queues.set(storage, queue);
|
|
48
|
+
}
|
|
49
|
+
return queue;
|
|
50
|
+
}
|
package/src/lib/queryRefetch.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Query, RefetchOptions } from '@tanstack/query-core';
|
|
2
2
|
|
|
3
|
-
import type { QueryRefetchOptions } from '../types/query.
|
|
3
|
+
import type { QueryRefetchOptions } from '../types/query.ts';
|
|
4
4
|
|
|
5
5
|
type QueryRefetch<TResult> = (options?: RefetchOptions) => Promise<TResult>;
|
|
6
6
|
type QueryRefetchWithFetchOptions<TResult> = (
|
package/src/lib/utils.ts
CHANGED
package/src/monkey.ts
CHANGED
|
@@ -11,7 +11,7 @@ import { useQueryClient } from '@tanstack/vue-query';
|
|
|
11
11
|
import { markRaw } from 'vue';
|
|
12
12
|
import { BeanSimple } from 'zova';
|
|
13
13
|
|
|
14
|
-
import { ServiceStorage } from './service/storage.
|
|
14
|
+
import { ServiceStorage } from './service/storage.ts';
|
|
15
15
|
|
|
16
16
|
export class Monkey
|
|
17
17
|
extends BeanSimple
|
|
@@ -47,6 +47,11 @@ export class Monkey
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
async beanInit(bean: BeanContainer, beanInstance: BeanBase) {
|
|
50
|
+
bean.defineProperty(beanInstance, '$modelPersistence', {
|
|
51
|
+
enumerable: false,
|
|
52
|
+
configurable: true,
|
|
53
|
+
get: () => this._storage,
|
|
54
|
+
});
|
|
50
55
|
bean.defineProperty(beanInstance, '$queryClient', {
|
|
51
56
|
enumerable: false,
|
|
52
57
|
configurable: true,
|
package/src/service/storage.ts
CHANGED
|
@@ -1,12 +1,49 @@
|
|
|
1
|
-
import type { VueQueryPluginOptions } from '@tanstack/vue-query';
|
|
1
|
+
import type { Query, VueQueryPluginOptions } from '@tanstack/vue-query';
|
|
2
2
|
|
|
3
3
|
import { dehydrate, hydrate, QueryCache, QueryClient, VueQueryPlugin } from '@tanstack/vue-query';
|
|
4
4
|
import { BeanBase, deepExtend } from 'zova';
|
|
5
5
|
import { Service } from 'zova-module-a-bean';
|
|
6
6
|
|
|
7
|
+
import type { ModelPersistenceToken, ModelPersistenceValues } from '../lib/modelPersistence.ts';
|
|
8
|
+
|
|
9
|
+
import { ModelPersistenceContext } from '../lib/modelPersistence.ts';
|
|
10
|
+
|
|
7
11
|
@Service()
|
|
8
12
|
export class ServiceStorage extends BeanBase {
|
|
9
13
|
private _queryClient: QueryClient;
|
|
14
|
+
private _persistence: ModelPersistenceContext;
|
|
15
|
+
|
|
16
|
+
get epoch() {
|
|
17
|
+
return this._persistence.epoch;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
capture() {
|
|
21
|
+
return this._persistence.capture();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
current(token: ModelPersistenceToken) {
|
|
25
|
+
return this._persistence.current(token);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
update(values: ModelPersistenceValues, options?: { initial?: boolean; refetchActive?: boolean }) {
|
|
29
|
+
this._persistence.update(values, options);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
subscribe(listener: (token: ModelPersistenceToken) => void) {
|
|
33
|
+
return this._persistence.subscribe(listener);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
clear() {
|
|
37
|
+
this._persistence.clear();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
touch(query?: Query) {
|
|
41
|
+
this._persistence.touch(query);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
guardOptions<T extends Parameters<ModelPersistenceContext['guardOptions']>[0]>(options: T): T {
|
|
45
|
+
return this._persistence.guardOptions(options);
|
|
46
|
+
}
|
|
10
47
|
|
|
11
48
|
async moduleLoaded() {
|
|
12
49
|
// options
|
|
@@ -22,6 +59,7 @@ export class ServiceStorage extends BeanBase {
|
|
|
22
59
|
defaultOptions: options,
|
|
23
60
|
queryCache,
|
|
24
61
|
}));
|
|
62
|
+
this._persistence = new ModelPersistenceContext(queryClient, this.sys.env.SITE_ID);
|
|
25
63
|
// use plugin
|
|
26
64
|
const vueQueryPluginOptions: VueQueryPluginOptions = { queryClient };
|
|
27
65
|
this.app.vue.use(VueQueryPlugin, vueQueryPluginOptions);
|
|
@@ -43,7 +81,14 @@ export class ServiceStorage extends BeanBase {
|
|
|
43
81
|
}
|
|
44
82
|
// client
|
|
45
83
|
if (process.env.CLIENT && this.ctx.meta.$ssr.isRuntimeSsrPreHydration) {
|
|
46
|
-
|
|
84
|
+
const state = this.ctx.meta.$ssr.stateDefer.query;
|
|
85
|
+
hydrate(this._queryClient, state);
|
|
86
|
+
this._persistence.markHydrated(
|
|
87
|
+
(state?.queries ?? []).flatMap(item => {
|
|
88
|
+
const query = this._queryClient.getQueryCache().get(item.queryHash);
|
|
89
|
+
return query ? [query] : [];
|
|
90
|
+
}),
|
|
91
|
+
);
|
|
47
92
|
}
|
|
48
93
|
}
|
|
49
94
|
}
|
package/src/types/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './model.
|
|
2
|
-
export * from './query.
|
|
1
|
+
export * from './model.ts';
|
|
2
|
+
export * from './query.ts';
|
package/src/types/query.ts
CHANGED
|
@@ -12,11 +12,14 @@ import type {
|
|
|
12
12
|
} from '@tanstack/vue-query';
|
|
13
13
|
import type { DebuggerOptions, UnwrapNestedRefs } from 'vue';
|
|
14
14
|
|
|
15
|
+
import type { ServiceStorage } from '../service/storage.ts';
|
|
16
|
+
|
|
15
17
|
import 'zova';
|
|
16
18
|
|
|
17
19
|
declare module 'zova' {
|
|
18
20
|
export interface BeanBase {
|
|
19
21
|
$queryClient: ReturnType<typeof useQueryClient>;
|
|
22
|
+
$modelPersistence: ServiceStorage;
|
|
20
23
|
}
|
|
21
24
|
}
|
|
22
25
|
|