@azure-net/kit 5.4.0 → 6.0.0-next
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/delivery/index.d.ts +1 -1
- package/dist/delivery/index.js +1 -1
- package/dist/delivery/injectable-dependencies/AsyncHelpers.d.ts +1 -11
- package/dist/delivery/injectable-dependencies/AsyncHelpers.js +8 -34
- package/dist/delivery/injectable-dependencies/index.d.ts +0 -1
- package/dist/delivery/injectable-dependencies/index.js +0 -1
- package/dist/delivery/schema/Schema.d.ts +4 -4
- package/dist/delivery/schema/Schema.js +6 -6
- package/dist/delivery/schema/rules/Rules.js +14 -6
- package/dist/errors.d.ts +1 -2
- package/dist/errors.js +1 -2
- package/dist/infra/response/BaseResponse.d.ts +1 -1
- package/dist/infra/response/BaseResponse.js +1 -1
- package/dist/plugin/AzureNetPlugin.js +1 -1
- package/dist/shared/app/App.d.ts +17 -1
- package/dist/shared/app/App.js +79 -34
- package/dist/shared/app/index.d.ts +1 -1
- package/dist/shared/app/middleware/ClientMiddleware.d.ts +3 -3
- package/dist/shared/app/middleware/ClientMiddleware.js +4 -5
- package/dist/shared/app-error/AppError.d.ts +2 -0
- package/dist/shared/app-error/AppError.js +2 -1
- package/dist/shared/app-error/ErrorRuntime.d.ts +11 -0
- package/dist/shared/app-error/ErrorRuntime.js +57 -0
- package/dist/shared/app-error/index.d.ts +1 -0
- package/dist/shared/app-error/index.js +1 -0
- package/dist/shared/boundary-provider/Provider.js +24 -4
- package/dist/svelte/active-form/ActiveForm.svelte.d.ts +1 -1
- package/dist/svelte/active-form/ActiveForm.svelte.js +14 -4
- package/dist/svelte/async-signal/AsyncSignal.svelte.d.ts +12 -1
- package/dist/svelte/async-signal/AsyncSignal.svelte.js +158 -7
- package/dist/svelte/effect/Effect.svelte.d.ts +4 -0
- package/dist/svelte/effect/Effect.svelte.js +27 -0
- package/dist/svelte/effect/index.d.ts +1 -0
- package/dist/svelte/effect/index.js +1 -0
- package/dist/svelte/index.d.ts +3 -2
- package/dist/svelte/index.js +2 -1
- package/dist/svelte/query/Query.svelte.d.ts +14 -11
- package/dist/svelte/query/Query.svelte.js +78 -68
- package/dist/svelte/query/SearchParamsSync.d.ts +2 -0
- package/dist/svelte/query/SearchParamsSync.js +119 -0
- package/package.json +1 -1
- package/dist/delivery/injectable-dependencies/ErrorHandler.d.ts +0 -7
- package/dist/delivery/injectable-dependencies/ErrorHandler.js +0 -15
|
@@ -105,12 +105,18 @@ export const createBoundaryProvider = (name, settings) => {
|
|
|
105
105
|
return factories;
|
|
106
106
|
};
|
|
107
107
|
const providerProxy = new Proxy({}, {
|
|
108
|
-
get(
|
|
108
|
+
get(target, key, receiver) {
|
|
109
|
+
if (typeof key === 'symbol')
|
|
110
|
+
return Reflect.get(target, key, receiver);
|
|
109
111
|
if (cache.has(key)) {
|
|
110
112
|
return cache.get(key);
|
|
111
113
|
}
|
|
112
114
|
const factories = getFactories();
|
|
113
|
-
if (!(key
|
|
115
|
+
if (!Object.hasOwn(factories, key)) {
|
|
116
|
+
if (key === 'then' || key === 'toJSON')
|
|
117
|
+
return undefined;
|
|
118
|
+
if (Reflect.has(target, key))
|
|
119
|
+
return Reflect.get(target, key, receiver);
|
|
114
120
|
throw new AzureNetKitInternalError(`[BoundaryProvider] Service '${key}' not found in provider '${name}'`);
|
|
115
121
|
}
|
|
116
122
|
const factory = factories[key];
|
|
@@ -124,17 +130,31 @@ export const createBoundaryProvider = (name, settings) => {
|
|
|
124
130
|
cache.set(key, instance);
|
|
125
131
|
return instance;
|
|
126
132
|
},
|
|
127
|
-
has(
|
|
133
|
+
has(target, key) {
|
|
134
|
+
if (typeof key === 'symbol')
|
|
135
|
+
return Reflect.has(target, key);
|
|
128
136
|
if (cache.has(key))
|
|
129
137
|
return true;
|
|
130
138
|
const factories = getFactories();
|
|
131
|
-
return key
|
|
139
|
+
return Object.hasOwn(factories, key) || Reflect.has(target, key);
|
|
132
140
|
},
|
|
133
141
|
ownKeys() {
|
|
134
142
|
const factories = getFactories();
|
|
135
143
|
const cachedKeys = Array.from(cache.keys());
|
|
136
144
|
const factoryKeys = Object.keys(factories);
|
|
137
145
|
return [...new Set([...cachedKeys, ...factoryKeys])];
|
|
146
|
+
},
|
|
147
|
+
getOwnPropertyDescriptor(_, key) {
|
|
148
|
+
if (typeof key === 'symbol')
|
|
149
|
+
return undefined;
|
|
150
|
+
const factories = getFactories();
|
|
151
|
+
if (!cache.has(key) && !Object.hasOwn(factories, key))
|
|
152
|
+
return undefined;
|
|
153
|
+
return {
|
|
154
|
+
configurable: true,
|
|
155
|
+
enumerable: true,
|
|
156
|
+
get: () => providerProxy[key]
|
|
157
|
+
};
|
|
138
158
|
}
|
|
139
159
|
});
|
|
140
160
|
if (BROWSER) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { RequestErrors } from '../../delivery/schema/index.js';
|
|
2
2
|
import type { AsyncActionResponse } from '../../delivery/injectable-dependencies/AsyncHelpers.js';
|
|
3
|
-
import type
|
|
3
|
+
import { type AsyncSignalSvelte } from '../async-signal/AsyncSignal.svelte.js';
|
|
4
4
|
type MaybePromise<T> = T | Promise<T>;
|
|
5
5
|
type PathRequiredShape<T, P extends string> = P extends `${infer Head}.${infer Tail}` ? Head extends keyof T ? {
|
|
6
6
|
[K in Head]-?: PathRequiredShape<NonNullable<T[K]>, Tail>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { ObjectUtil } from '../../external/tools/index.js';
|
|
1
|
+
import { BROWSER, ObjectUtil } from '../../external/tools/index.js';
|
|
2
|
+
import { isAsyncSignalScheduledForClient } from '../async-signal/AsyncSignal.svelte.js';
|
|
2
3
|
import { cloneStateValue } from '../shared/cloneStateValue.js';
|
|
3
4
|
const NO_INITIAL_VALUES_ERROR = Symbol('no-initial-values-error');
|
|
4
5
|
const isPromiseLike = (value) => {
|
|
@@ -29,7 +30,7 @@ export const createActiveForm = (onSubmit, config) => {
|
|
|
29
30
|
$effect(() => {
|
|
30
31
|
for (const binding of signalBindings) {
|
|
31
32
|
const status = binding.signal.status;
|
|
32
|
-
const data = binding.signal.
|
|
33
|
+
const data = binding.signal.response;
|
|
33
34
|
const shouldUpdate = binding.active && status === 'success' && (binding.lastStatus !== 'success' || !Object.is(binding.lastData, data));
|
|
34
35
|
binding.lastStatus = status;
|
|
35
36
|
binding.lastData = data;
|
|
@@ -40,6 +41,7 @@ export const createActiveForm = (onSubmit, config) => {
|
|
|
40
41
|
const loadInitialValues = async () => {
|
|
41
42
|
const runId = ++initialLoadRunId;
|
|
42
43
|
const source = config?.initialValues;
|
|
44
|
+
let waitingForClientSignal = false;
|
|
43
45
|
initialValuesError = NO_INITIAL_VALUES_ERROR;
|
|
44
46
|
if (!source) {
|
|
45
47
|
bindingsBySignal?.clear();
|
|
@@ -67,7 +69,7 @@ export const createActiveForm = (onSubmit, config) => {
|
|
|
67
69
|
map: map,
|
|
68
70
|
active: false,
|
|
69
71
|
loadRunId: runId,
|
|
70
|
-
lastData: signal.
|
|
72
|
+
lastData: signal.response,
|
|
71
73
|
lastStatus: signal.status
|
|
72
74
|
};
|
|
73
75
|
bindings.set(untypedSignal, binding);
|
|
@@ -79,9 +81,13 @@ export const createActiveForm = (onSubmit, config) => {
|
|
|
79
81
|
}
|
|
80
82
|
signalBindings = [...bindings.values()];
|
|
81
83
|
}
|
|
84
|
+
if (!BROWSER && isAsyncSignalScheduledForClient(signal)) {
|
|
85
|
+
waitingForClientSignal = true;
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
82
88
|
if (signal.status === 'idle' || signal.status === 'pending')
|
|
83
89
|
await signal.ready;
|
|
84
|
-
const value = signal.
|
|
90
|
+
const value = signal.response;
|
|
85
91
|
if (binding && runId === initialLoadRunId && binding.loadRunId === runId) {
|
|
86
92
|
binding.active = true;
|
|
87
93
|
binding.lastData = value;
|
|
@@ -101,6 +107,10 @@ export const createActiveForm = (onSubmit, config) => {
|
|
|
101
107
|
}
|
|
102
108
|
if (runId !== initialLoadRunId)
|
|
103
109
|
return;
|
|
110
|
+
if (waitingForClientSignal) {
|
|
111
|
+
status = 'waitingForInitialValues';
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
104
114
|
if (bindingsBySignal) {
|
|
105
115
|
for (const [signal, binding] of bindingsBySignal) {
|
|
106
116
|
if (binding.loadRunId !== runId)
|
|
@@ -13,7 +13,7 @@ export interface AsyncSignalOptions<TData, TError = Error> {
|
|
|
13
13
|
key?: string;
|
|
14
14
|
}
|
|
15
15
|
export interface AsyncSignalSvelte<TData, TError = Error> {
|
|
16
|
-
|
|
16
|
+
response?: TData;
|
|
17
17
|
error?: TError;
|
|
18
18
|
status: AsyncStatus;
|
|
19
19
|
pending: boolean;
|
|
@@ -23,6 +23,17 @@ export interface AsyncSignalSvelte<TData, TError = Error> {
|
|
|
23
23
|
reset: () => void;
|
|
24
24
|
abort: () => void;
|
|
25
25
|
}
|
|
26
|
+
export interface AsyncSignalBatchOptions {
|
|
27
|
+
parallel?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface AsyncSignalBatchFactory {
|
|
30
|
+
<TData, TError = Error>(handler: (signal?: AbortSignal) => Promise<TData>, options?: Omit<AsyncSignalOptions<TData, TError>, 'immediate'>): AsyncSignalSvelte<TData, TError>;
|
|
31
|
+
}
|
|
32
|
+
export interface AsyncSignalBatch<TSignals extends readonly AsyncSignalSvelte<unknown, unknown>[]> {
|
|
33
|
+
execute: () => TSignals;
|
|
34
|
+
}
|
|
35
|
+
export declare const isAsyncSignalScheduledForClient: (signal: AsyncSignalSvelte<unknown, unknown>) => boolean;
|
|
26
36
|
export declare const createAsyncSignal: <TData, TError = Error>(handler: (signal?: AbortSignal) => Promise<TData>, options?: AsyncSignalOptions<TData, TError>) => AsyncSignalSvelte<TData, TError>;
|
|
37
|
+
export declare const createAsyncSignalBatch: <const TSignals extends readonly AsyncSignalSvelte<unknown, unknown>[]>(factory: (createSignal: AsyncSignalBatchFactory) => TSignals, options?: AsyncSignalBatchOptions) => AsyncSignalBatch<TSignals>;
|
|
27
38
|
export declare const refreshAsyncSignal: (key: string) => Promise<void>;
|
|
28
39
|
export declare const refreshAllAsyncSignals: () => Promise<void>;
|
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
import { untrack } from 'svelte';
|
|
2
2
|
import { BROWSER } from '../../external/tools/index.js';
|
|
3
|
+
const ASYNC_SIGNAL_BATCH_INTERNAL = Symbol('async-signal-batch-internal');
|
|
4
|
+
const ASYNC_SIGNAL_SCHEDULED_FOR_CLIENT = Symbol('async-signal-scheduled-for-client');
|
|
5
|
+
export const isAsyncSignalScheduledForClient = (signal) => {
|
|
6
|
+
return signal[ASYNC_SIGNAL_SCHEDULED_FOR_CLIENT]?.() ?? false;
|
|
7
|
+
};
|
|
8
|
+
const createDeferred = () => {
|
|
9
|
+
let resolve;
|
|
10
|
+
const promise = new Promise((promiseResolve) => {
|
|
11
|
+
resolve = promiseResolve;
|
|
12
|
+
});
|
|
13
|
+
return { promise, resolve };
|
|
14
|
+
};
|
|
15
|
+
const createResolvedPromise = (value) => {
|
|
16
|
+
return new Promise((resolve) => resolve(value));
|
|
17
|
+
};
|
|
3
18
|
const createAsyncSignalManager = () => {
|
|
4
19
|
const instances = BROWSER ? new Map() : undefined;
|
|
5
20
|
const generateUid = () => {
|
|
@@ -48,14 +63,36 @@ const asyncSignalManager = createAsyncSignalManager();
|
|
|
48
63
|
export const createAsyncSignal = (handler, options = {}) => {
|
|
49
64
|
const { server = false, immediate = true, initialData = undefined, key } = options;
|
|
50
65
|
const resolvedInitialData = typeof initialData === 'function' ? initialData() : initialData;
|
|
66
|
+
let scheduledForClient = immediate && !BROWSER && !server;
|
|
51
67
|
let data = $state(resolvedInitialData);
|
|
52
68
|
let error = $state();
|
|
53
|
-
let status = $state('idle');
|
|
69
|
+
let status = $state(scheduledForClient ? 'pending' : 'idle');
|
|
54
70
|
const pending = $derived(status === 'pending');
|
|
55
71
|
let abortController = null;
|
|
56
72
|
let currentPromise = null;
|
|
73
|
+
let readyPromise = createResolvedPromise(resolvedInitialData);
|
|
74
|
+
let resolveReady = null;
|
|
57
75
|
let currentRunId = 0;
|
|
58
76
|
let started = false;
|
|
77
|
+
let batchLocked = false;
|
|
78
|
+
let batchGate = null;
|
|
79
|
+
let batchSkipRequested = false;
|
|
80
|
+
const startReadyCycle = () => {
|
|
81
|
+
if (resolveReady)
|
|
82
|
+
return;
|
|
83
|
+
const deferred = createDeferred();
|
|
84
|
+
readyPromise = deferred.promise;
|
|
85
|
+
resolveReady = deferred.resolve;
|
|
86
|
+
};
|
|
87
|
+
const settleReadyCycle = () => {
|
|
88
|
+
const resolve = resolveReady;
|
|
89
|
+
if (!resolve) {
|
|
90
|
+
readyPromise = createResolvedPromise(data);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
resolveReady = null;
|
|
94
|
+
resolve(data);
|
|
95
|
+
};
|
|
59
96
|
const run = async (runId, source) => {
|
|
60
97
|
const initial = !started;
|
|
61
98
|
started = true;
|
|
@@ -108,16 +145,28 @@ export const createAsyncSignal = (handler, options = {}) => {
|
|
|
108
145
|
currentPromise = null;
|
|
109
146
|
if (abortController === localController)
|
|
110
147
|
abortController = null;
|
|
148
|
+
settleReadyCycle();
|
|
111
149
|
}
|
|
112
150
|
}
|
|
113
151
|
};
|
|
114
152
|
const start = (source) => {
|
|
153
|
+
scheduledForClient = false;
|
|
154
|
+
startReadyCycle();
|
|
115
155
|
const runId = ++currentRunId;
|
|
116
156
|
const localPromise = run(runId, source);
|
|
117
157
|
currentPromise = localPromise;
|
|
118
158
|
return localPromise;
|
|
119
159
|
};
|
|
160
|
+
const startWhenUnlocked = (source) => {
|
|
161
|
+
if (batchLocked)
|
|
162
|
+
return batchGate ?? readyPromise;
|
|
163
|
+
return start(source);
|
|
164
|
+
};
|
|
120
165
|
const execute = async () => {
|
|
166
|
+
if (batchLocked) {
|
|
167
|
+
await batchGate;
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
121
170
|
if (currentPromise) {
|
|
122
171
|
await currentPromise;
|
|
123
172
|
return;
|
|
@@ -125,11 +174,15 @@ export const createAsyncSignal = (handler, options = {}) => {
|
|
|
125
174
|
await start('manual');
|
|
126
175
|
};
|
|
127
176
|
const refresh = async () => {
|
|
177
|
+
if (batchLocked) {
|
|
178
|
+
await batchGate;
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
128
181
|
await start('manual');
|
|
129
182
|
};
|
|
130
183
|
if (BROWSER) {
|
|
131
184
|
const signalKey = key ?? asyncSignalManager.generateKey();
|
|
132
|
-
const callback = (source) =>
|
|
185
|
+
const callback = (source) => startWhenUnlocked(source);
|
|
133
186
|
asyncSignalManager.register(signalKey, callback);
|
|
134
187
|
$effect(() => {
|
|
135
188
|
return () => {
|
|
@@ -147,8 +200,8 @@ export const createAsyncSignal = (handler, options = {}) => {
|
|
|
147
200
|
void start('auto');
|
|
148
201
|
}
|
|
149
202
|
}
|
|
150
|
-
|
|
151
|
-
get
|
|
203
|
+
const asyncSignal = {
|
|
204
|
+
get response() {
|
|
152
205
|
return data;
|
|
153
206
|
},
|
|
154
207
|
get error() {
|
|
@@ -161,13 +214,16 @@ export const createAsyncSignal = (handler, options = {}) => {
|
|
|
161
214
|
return pending;
|
|
162
215
|
},
|
|
163
216
|
get ready() {
|
|
164
|
-
if (
|
|
165
|
-
return
|
|
166
|
-
return
|
|
217
|
+
if (batchLocked)
|
|
218
|
+
return (batchGate ?? readyPromise);
|
|
219
|
+
return readyPromise;
|
|
167
220
|
},
|
|
168
221
|
execute,
|
|
169
222
|
refresh,
|
|
170
223
|
reset: () => {
|
|
224
|
+
scheduledForClient = false;
|
|
225
|
+
if (batchLocked)
|
|
226
|
+
batchSkipRequested = true;
|
|
171
227
|
currentRunId += 1;
|
|
172
228
|
abortController?.abort();
|
|
173
229
|
abortController = null;
|
|
@@ -175,16 +231,111 @@ export const createAsyncSignal = (handler, options = {}) => {
|
|
|
175
231
|
data = undefined;
|
|
176
232
|
error = undefined;
|
|
177
233
|
status = 'idle';
|
|
234
|
+
settleReadyCycle();
|
|
178
235
|
},
|
|
179
236
|
abort: () => {
|
|
237
|
+
scheduledForClient = false;
|
|
238
|
+
if (batchLocked)
|
|
239
|
+
batchSkipRequested = true;
|
|
180
240
|
currentRunId += 1;
|
|
181
241
|
abortController?.abort();
|
|
182
242
|
abortController = null;
|
|
183
243
|
currentPromise = null;
|
|
184
244
|
error = undefined;
|
|
185
245
|
status = 'idle';
|
|
246
|
+
settleReadyCycle();
|
|
186
247
|
}
|
|
187
248
|
};
|
|
249
|
+
Object.defineProperty(asyncSignal, ASYNC_SIGNAL_SCHEDULED_FOR_CLIENT, {
|
|
250
|
+
value: () => scheduledForClient
|
|
251
|
+
});
|
|
252
|
+
Object.defineProperty(asyncSignal, ASYNC_SIGNAL_BATCH_INTERNAL, {
|
|
253
|
+
value: {
|
|
254
|
+
lock: (gate) => {
|
|
255
|
+
batchLocked = true;
|
|
256
|
+
batchGate = gate ?? null;
|
|
257
|
+
batchSkipRequested = false;
|
|
258
|
+
},
|
|
259
|
+
unlock: () => {
|
|
260
|
+
batchLocked = false;
|
|
261
|
+
batchGate = null;
|
|
262
|
+
},
|
|
263
|
+
start: (source) => {
|
|
264
|
+
if (batchSkipRequested)
|
|
265
|
+
return Promise.resolve(undefined);
|
|
266
|
+
return start(source);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
return asyncSignal;
|
|
271
|
+
};
|
|
272
|
+
export const createAsyncSignalBatch = (factory, options = {}) => {
|
|
273
|
+
const internals = new Map();
|
|
274
|
+
const createSignal = (handler, signalOptions = {}) => {
|
|
275
|
+
const signal = createAsyncSignal(handler, { ...signalOptions, immediate: false });
|
|
276
|
+
const internal = signal[ASYNC_SIGNAL_BATCH_INTERNAL];
|
|
277
|
+
internal.lock();
|
|
278
|
+
internals.set(signal, internal);
|
|
279
|
+
return signal;
|
|
280
|
+
};
|
|
281
|
+
const signals = factory(createSignal);
|
|
282
|
+
const uniqueSignals = new Set(signals);
|
|
283
|
+
if (uniqueSignals.size !== signals.length || signals.some((signal) => !internals.has(signal))) {
|
|
284
|
+
throw new Error('[AsyncSignalBatch] Factory must return each signal created by createSignal exactly once.');
|
|
285
|
+
}
|
|
286
|
+
if (internals.size !== signals.length) {
|
|
287
|
+
throw new Error('[AsyncSignalBatch] Factory must return every signal created by createSignal.');
|
|
288
|
+
}
|
|
289
|
+
let running = false;
|
|
290
|
+
const execute = () => {
|
|
291
|
+
if (running || signals.length === 0)
|
|
292
|
+
return signals;
|
|
293
|
+
running = true;
|
|
294
|
+
const gates = signals.map(() => createDeferred());
|
|
295
|
+
signals.forEach((signal, index) => {
|
|
296
|
+
internals.get(signal)?.lock(gates[index].promise);
|
|
297
|
+
});
|
|
298
|
+
queueMicrotask(() => {
|
|
299
|
+
if (options.parallel !== false) {
|
|
300
|
+
let remaining = signals.length;
|
|
301
|
+
signals.forEach((signal, index) => {
|
|
302
|
+
const internal = internals.get(signal);
|
|
303
|
+
void internal
|
|
304
|
+
.start('manual')
|
|
305
|
+
.catch(() => undefined)
|
|
306
|
+
.then((result) => {
|
|
307
|
+
gates[index].resolve(result);
|
|
308
|
+
internal.unlock();
|
|
309
|
+
remaining -= 1;
|
|
310
|
+
if (remaining === 0)
|
|
311
|
+
running = false;
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
void (async () => {
|
|
317
|
+
for (let index = 0; index < signals.length; index += 1) {
|
|
318
|
+
const signal = signals[index];
|
|
319
|
+
const internal = internals.get(signal);
|
|
320
|
+
const result = await internal.start('manual').catch(() => undefined);
|
|
321
|
+
gates[index].resolve(result);
|
|
322
|
+
internal.unlock();
|
|
323
|
+
if (signal.status !== 'success') {
|
|
324
|
+
for (let skippedIndex = index + 1; skippedIndex < signals.length; skippedIndex += 1) {
|
|
325
|
+
const skippedSignal = signals[skippedIndex];
|
|
326
|
+
gates[skippedIndex].resolve(undefined);
|
|
327
|
+
internals.get(skippedSignal)?.unlock();
|
|
328
|
+
}
|
|
329
|
+
break;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
})().finally(() => {
|
|
333
|
+
running = false;
|
|
334
|
+
});
|
|
335
|
+
});
|
|
336
|
+
return signals;
|
|
337
|
+
};
|
|
338
|
+
return { execute };
|
|
188
339
|
};
|
|
189
340
|
export const refreshAsyncSignal = async (key) => {
|
|
190
341
|
return await asyncSignalManager.refreshByKey(key);
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type EffectCleanup = () => void;
|
|
2
|
+
export type EffectCallback = () => EffectCleanup | Promise<unknown> | void;
|
|
3
|
+
export type EffectDependency<T = unknown> = () => T;
|
|
4
|
+
export declare const createEffect: (callback: EffectCallback, dependencies: readonly EffectDependency[]) => void;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { untrack } from 'svelte';
|
|
2
|
+
export const createEffect = (callback, dependencies) => {
|
|
3
|
+
let cleanup;
|
|
4
|
+
let initialized = false;
|
|
5
|
+
let previousValues = [];
|
|
6
|
+
$effect(() => {
|
|
7
|
+
const values = dependencies.map((dependency) => dependency());
|
|
8
|
+
const changed = !initialized || values.some((value, index) => !Object.is(value, previousValues[index]));
|
|
9
|
+
if (!changed)
|
|
10
|
+
return;
|
|
11
|
+
initialized = true;
|
|
12
|
+
previousValues = values;
|
|
13
|
+
untrack(() => {
|
|
14
|
+
cleanup?.();
|
|
15
|
+
cleanup = undefined;
|
|
16
|
+
const result = callback();
|
|
17
|
+
if (typeof result === 'function')
|
|
18
|
+
cleanup = result;
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
$effect(() => {
|
|
22
|
+
return () => {
|
|
23
|
+
untrack(() => cleanup?.());
|
|
24
|
+
cleanup = undefined;
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Effect.svelte.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Effect.svelte.js';
|
package/dist/svelte/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export { createAsyncSignal, refreshAsyncSignal, refreshAllAsyncSignals, type AsyncSignalOptions, type AsyncSignalSvelte, type AsyncStatus, type AsyncSignalSource } from './async-signal/AsyncSignal.svelte.js';
|
|
1
|
+
export { createAsyncSignal, createAsyncSignalBatch, refreshAsyncSignal, refreshAllAsyncSignals, type AsyncSignalBatch, type AsyncSignalBatchFactory, type AsyncSignalBatchOptions, type AsyncSignalOptions, type AsyncSignalSvelte, type AsyncStatus, type AsyncSignalSource } from './async-signal/AsyncSignal.svelte.js';
|
|
2
2
|
export { createActiveForm, type ActiveForm, type ActiveFormCallbackContext, type ActiveFormController, type ActiveFormResponse, type ActiveFormStatus, type FormConfig, type InitialValuesHelpers, type LinkPromise, type LinkSignal, type LinkSignalOptions, type ResetBehaviors } from './active-form/ActiveForm.svelte.js';
|
|
3
|
-
export {
|
|
3
|
+
export { createEffect, type EffectCallback, type EffectCleanup, type EffectDependency } from './effect/Effect.svelte.js';
|
|
4
|
+
export { createQuery, type CreateQueryOptions, type QueryController, type QueryPath, type QuerySearchParamsSync } from './query/Query.svelte.js';
|
package/dist/svelte/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export { createAsyncSignal, refreshAsyncSignal, refreshAllAsyncSignals } from './async-signal/AsyncSignal.svelte.js';
|
|
1
|
+
export { createAsyncSignal, createAsyncSignalBatch, refreshAsyncSignal, refreshAllAsyncSignals } from './async-signal/AsyncSignal.svelte.js';
|
|
2
2
|
export { createActiveForm } from './active-form/ActiveForm.svelte.js';
|
|
3
|
+
export { createEffect } from './effect/Effect.svelte.js';
|
|
3
4
|
export { createQuery } from './query/Query.svelte.js';
|
|
@@ -1,20 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { type EffectCallback } from '../effect/Effect.svelte.js';
|
|
2
|
+
type QueryPathDepth = readonly [unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown];
|
|
3
|
+
type QueryLeaf = bigint | boolean | Date | File | Blob | ((...args: never[]) => unknown) | Map<unknown, unknown> | null | number | readonly unknown[] | RegExp | Set<unknown> | string | symbol | undefined | URL | URLSearchParams;
|
|
4
|
+
export type QueryPath<T, Depth extends readonly unknown[] = QueryPathDepth> = Depth extends readonly [unknown, ...infer Rest] ? T extends QueryLeaf ? never : T extends object ? {
|
|
5
|
+
[K in Extract<keyof T, string>]: NonNullable<T[K]> extends QueryLeaf ? K : K | `${K}.${QueryPath<NonNullable<T[K]>, Rest>}`;
|
|
6
|
+
}[Extract<keyof T, string>] : never : never;
|
|
7
|
+
export interface QuerySearchParamsSync<T extends Record<string, unknown>> {
|
|
8
|
+
fromSearchParams?: (params: URLSearchParams, initial: Readonly<T>) => Partial<T>;
|
|
9
|
+
toSearchParams?: (data: Readonly<T>, initial: Readonly<T>) => URLSearchParams;
|
|
9
10
|
}
|
|
10
11
|
export interface CreateQueryOptions<T extends Record<string, unknown>> {
|
|
11
|
-
|
|
12
|
+
syncWithSearchParams?: boolean | QuerySearchParamsSync<T>;
|
|
12
13
|
}
|
|
13
14
|
export interface QueryController<T extends Record<string, unknown>> {
|
|
14
15
|
data: T;
|
|
15
16
|
patch: (value: Partial<T>) => void;
|
|
16
17
|
reset: () => void;
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
createSnapshot: () => T;
|
|
19
|
+
getInitial: () => T;
|
|
20
|
+
createEffect: (callback: EffectCallback, dependencies?: readonly QueryPath<T>[]) => void;
|
|
19
21
|
}
|
|
20
22
|
export declare const createQuery: <T extends Record<string, unknown>>(initialValue: T, options?: CreateQueryOptions<T>) => QueryController<T>;
|
|
23
|
+
export {};
|