@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.
Files changed (43) hide show
  1. package/dist/delivery/index.d.ts +1 -1
  2. package/dist/delivery/index.js +1 -1
  3. package/dist/delivery/injectable-dependencies/AsyncHelpers.d.ts +1 -11
  4. package/dist/delivery/injectable-dependencies/AsyncHelpers.js +8 -34
  5. package/dist/delivery/injectable-dependencies/index.d.ts +0 -1
  6. package/dist/delivery/injectable-dependencies/index.js +0 -1
  7. package/dist/delivery/schema/Schema.d.ts +4 -4
  8. package/dist/delivery/schema/Schema.js +6 -6
  9. package/dist/delivery/schema/rules/Rules.js +14 -6
  10. package/dist/errors.d.ts +1 -2
  11. package/dist/errors.js +1 -2
  12. package/dist/infra/response/BaseResponse.d.ts +1 -1
  13. package/dist/infra/response/BaseResponse.js +1 -1
  14. package/dist/plugin/AzureNetPlugin.js +1 -1
  15. package/dist/shared/app/App.d.ts +17 -1
  16. package/dist/shared/app/App.js +79 -34
  17. package/dist/shared/app/index.d.ts +1 -1
  18. package/dist/shared/app/middleware/ClientMiddleware.d.ts +3 -3
  19. package/dist/shared/app/middleware/ClientMiddleware.js +4 -5
  20. package/dist/shared/app-error/AppError.d.ts +2 -0
  21. package/dist/shared/app-error/AppError.js +2 -1
  22. package/dist/shared/app-error/ErrorRuntime.d.ts +11 -0
  23. package/dist/shared/app-error/ErrorRuntime.js +57 -0
  24. package/dist/shared/app-error/index.d.ts +1 -0
  25. package/dist/shared/app-error/index.js +1 -0
  26. package/dist/shared/boundary-provider/Provider.js +24 -4
  27. package/dist/svelte/active-form/ActiveForm.svelte.d.ts +1 -1
  28. package/dist/svelte/active-form/ActiveForm.svelte.js +14 -4
  29. package/dist/svelte/async-signal/AsyncSignal.svelte.d.ts +12 -1
  30. package/dist/svelte/async-signal/AsyncSignal.svelte.js +158 -7
  31. package/dist/svelte/effect/Effect.svelte.d.ts +4 -0
  32. package/dist/svelte/effect/Effect.svelte.js +27 -0
  33. package/dist/svelte/effect/index.d.ts +1 -0
  34. package/dist/svelte/effect/index.js +1 -0
  35. package/dist/svelte/index.d.ts +3 -2
  36. package/dist/svelte/index.js +2 -1
  37. package/dist/svelte/query/Query.svelte.d.ts +14 -11
  38. package/dist/svelte/query/Query.svelte.js +78 -68
  39. package/dist/svelte/query/SearchParamsSync.d.ts +2 -0
  40. package/dist/svelte/query/SearchParamsSync.js +119 -0
  41. package/package.json +1 -1
  42. package/dist/delivery/injectable-dependencies/ErrorHandler.d.ts +0 -7
  43. package/dist/delivery/injectable-dependencies/ErrorHandler.js +0 -15
@@ -1 +1,2 @@
1
1
  export * from './AppError.js';
2
+ export * from './ErrorRuntime.js';
@@ -105,12 +105,18 @@ export const createBoundaryProvider = (name, settings) => {
105
105
  return factories;
106
106
  };
107
107
  const providerProxy = new Proxy({}, {
108
- get(_, key) {
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 in factories)) {
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(_, key) {
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 in factories;
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 { AsyncSignalSvelte } from '../async-signal/AsyncSignal.svelte.js';
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.data;
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.data,
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.data;
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
- data?: TData;
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) => start(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
- return {
151
- get data() {
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 (currentPromise)
165
- return currentPromise;
166
- return start('auto');
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';
@@ -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 { createQuery, type QueryController, type CreateQueryOptions } from './query/Query.svelte.js';
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';
@@ -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
- export interface QueryOnChangeContext<T extends Record<string, unknown>> {
2
- snapshot: T;
3
- changedKeys: (keyof T)[];
4
- signal: AbortSignal;
5
- }
6
- export interface QueryOnChangeOptions<T extends Record<string, unknown>> {
7
- include: (keyof T)[];
8
- handler: (ctx: QueryOnChangeContext<T>) => Promise<void> | void;
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
- onChange?: QueryOnChangeOptions<T>;
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
- snapshot: () => T;
18
- initial: () => T;
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 {};