@azure-net/kit 3.1.0 → 3.9.2
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/README.md +2 -2
- package/dist/core/delivery/index.d.ts +1 -4
- package/dist/core/delivery/index.js +1 -4
- package/dist/core/delivery/injectableDependencies/AsyncHelpers.d.ts +28 -30
- package/dist/core/delivery/injectableDependencies/AsyncHelpers.js +80 -116
- package/dist/core/delivery/injectableDependencies/ErrorHandler.d.ts +3 -21
- package/dist/core/delivery/injectableDependencies/ErrorHandler.js +11 -42
- package/dist/core/delivery/schema/Schema.d.ts +8 -1
- package/dist/core/delivery/schema/Schema.js +12 -3
- package/dist/core/delivery.d.ts +5 -0
- package/dist/core/delivery.js +5 -0
- package/dist/core/errors.d.ts +4 -0
- package/dist/core/errors.js +4 -0
- package/dist/core/index.d.ts +7 -8
- package/dist/core/index.js +7 -8
- package/dist/core/infra/datasource/BaseDatasource.d.ts +11 -11
- package/dist/core/infra/datasource/BaseDatasource.js +4 -4
- package/dist/core/infra/httpService/HttpServiceInstance.d.ts +90 -0
- package/dist/core/infra/httpService/HttpServiceInstance.js +340 -0
- package/dist/core/infra/httpService/index.d.ts +1 -1
- package/dist/core/infra/httpService/index.js +1 -1
- package/dist/core/infra/query/QueryBuilder.d.ts +9 -21
- package/dist/core/infra/query/QueryBuilder.js +63 -50
- package/dist/core/infra/response/BaseResponse.js +3 -2
- package/dist/core/infra.d.ts +6 -0
- package/dist/core/infra.js +6 -0
- package/dist/core/shared/appError/AppError.d.ts +30 -0
- package/dist/core/shared/appError/AppError.js +66 -0
- package/dist/core/shared/appEventBus/EventBus.d.ts +1 -1
- package/dist/core/shared/appEventBus/EventBus.js +3 -3
- package/dist/core/shared/boundaryProvider/Provider.d.ts +2 -2
- package/dist/core/shared/boundaryProvider/Provider.js +16 -9
- package/dist/core/shared/classMirror/ClassMirror.d.ts +7 -2
- package/dist/core/shared/classMirror/ClassMirror.js +34 -15
- package/dist/core/shared/cookie/UniversalCookie.js +9 -11
- package/dist/core/shared/middleware/Middleware.js +12 -8
- package/dist/core/svelte/ActiveForm/ActiveForm.svelte.d.ts +10 -6
- package/dist/core/svelte/ActiveForm/ActiveForm.svelte.js +47 -41
- package/dist/core/svelte/AsyncSignal/AsyncSignal.svelte.d.ts +0 -1
- package/dist/core/svelte/AsyncSignal/AsyncSignal.svelte.js +21 -30
- package/dist/core/svelte/Query/Query.svelte.d.ts +11 -12
- package/dist/core/svelte/Query/Query.svelte.js +43 -55
- package/dist/core/ui/onClickOutside/OnClickOutside.js +1 -1
- package/dist/core/ui/scrollTo/index.js +2 -2
- package/dist/edges/context/index.d.ts +1 -1
- package/dist/edges/context/index.js +1 -1
- package/dist/edges/dev/index.d.ts +1 -1
- package/dist/edges/dev/index.js +1 -1
- package/dist/edges/index.d.ts +1 -1
- package/dist/edges/index.js +1 -1
- package/dist/edges/plugin/index.d.ts +1 -1
- package/dist/edges/plugin/index.js +1 -1
- package/dist/edges/server/index.d.ts +1 -1
- package/dist/edges/server/index.js +1 -1
- package/dist/edges/state/index.d.ts +1 -1
- package/dist/edges/state/index.js +1 -1
- package/dist/i18n/index.d.ts +1 -1
- package/dist/i18n/index.js +1 -1
- package/dist/tools/index.d.ts +2 -1
- package/dist/tools/index.js +2 -1
- package/package.json +45 -47
- package/dist/core/delivery/serverAction/CreateServerAction.d.ts +0 -15
- package/dist/core/delivery/serverAction/CreateServerAction.js +0 -22
- package/dist/core/delivery/serverAction/index.d.ts +0 -1
- package/dist/core/delivery/serverAction/index.js +0 -1
- package/dist/core/infra/httpService/HttpService.d.ts +0 -74
- package/dist/core/infra/httpService/HttpService.js +0 -164
- package/dist/core/shared/eventBus/EventBus.d.ts +0 -87
- package/dist/core/shared/eventBus/EventBus.js +0 -227
- package/dist/core/shared/eventBus/index.d.ts +0 -1
- package/dist/core/shared/eventBus/index.js +0 -1
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { RequestContext } from '../../../edges/context/index.js';
|
|
2
|
-
import {
|
|
2
|
+
import { BROWSER } from '@azure-net/tools/environment';
|
|
3
|
+
import { AzureNetKitInternalError } from '../appError/AppError.js';
|
|
3
4
|
const clientCache = new Map();
|
|
4
5
|
const factoriesCache = new WeakMap();
|
|
5
6
|
const providerProxyCache = new Map();
|
|
6
7
|
const clientBootFlags = new Map();
|
|
7
8
|
const getProviderCache = (providerName) => {
|
|
8
|
-
if (
|
|
9
|
+
if (BROWSER) {
|
|
9
10
|
if (!clientCache.has(providerName)) {
|
|
10
11
|
clientCache.set(providerName, new Map());
|
|
11
12
|
}
|
|
@@ -28,7 +29,7 @@ const getProviderCache = (providerName) => {
|
|
|
28
29
|
}
|
|
29
30
|
};
|
|
30
31
|
const getBootFlag = (providerName) => {
|
|
31
|
-
if (
|
|
32
|
+
if (BROWSER) {
|
|
32
33
|
return clientBootFlags.get(providerName) ?? false;
|
|
33
34
|
}
|
|
34
35
|
else {
|
|
@@ -41,7 +42,7 @@ const getBootFlag = (providerName) => {
|
|
|
41
42
|
}
|
|
42
43
|
};
|
|
43
44
|
const setBootFlag = (providerName, value) => {
|
|
44
|
-
if (
|
|
45
|
+
if (BROWSER) {
|
|
45
46
|
clientBootFlags.set(providerName, value);
|
|
46
47
|
}
|
|
47
48
|
else {
|
|
@@ -56,7 +57,7 @@ const setBootFlag = (providerName, value) => {
|
|
|
56
57
|
export const createBoundaryProvider = (name, settings) => {
|
|
57
58
|
const { dependsOn = {}, boot, register } = settings;
|
|
58
59
|
const providerFn = () => {
|
|
59
|
-
if (
|
|
60
|
+
if (BROWSER && providerProxyCache.has(name)) {
|
|
60
61
|
return providerProxyCache.get(name);
|
|
61
62
|
}
|
|
62
63
|
const cache = getProviderCache(name);
|
|
@@ -82,7 +83,7 @@ export const createBoundaryProvider = (name, settings) => {
|
|
|
82
83
|
});
|
|
83
84
|
}
|
|
84
85
|
factories = register(deps);
|
|
85
|
-
if (
|
|
86
|
+
if (BROWSER) {
|
|
86
87
|
factoriesCache.set(register, factories);
|
|
87
88
|
}
|
|
88
89
|
return factories;
|
|
@@ -94,10 +95,16 @@ export const createBoundaryProvider = (name, settings) => {
|
|
|
94
95
|
}
|
|
95
96
|
const factories = getFactories();
|
|
96
97
|
if (!(key in factories)) {
|
|
97
|
-
throw new
|
|
98
|
+
throw new AzureNetKitInternalError(`[BoundaryProvider] Service '${key}' not found in provider '${name}'`);
|
|
98
99
|
}
|
|
99
100
|
const factory = factories[key];
|
|
101
|
+
if (typeof factory !== 'function') {
|
|
102
|
+
throw new AzureNetKitInternalError('[BoundaryProvider] Factory must be a function');
|
|
103
|
+
}
|
|
100
104
|
const instance = factory();
|
|
105
|
+
if (instance && typeof instance?.then === 'function') {
|
|
106
|
+
throw new AzureNetKitInternalError(`[BoundaryProvider] Service '${key}' in provider '${name}' returned Promise.`);
|
|
107
|
+
}
|
|
101
108
|
cache.set(key, instance);
|
|
102
109
|
return instance;
|
|
103
110
|
},
|
|
@@ -114,7 +121,7 @@ export const createBoundaryProvider = (name, settings) => {
|
|
|
114
121
|
return [...new Set([...cachedKeys, ...factoryKeys])];
|
|
115
122
|
}
|
|
116
123
|
});
|
|
117
|
-
if (
|
|
124
|
+
if (BROWSER) {
|
|
118
125
|
providerProxyCache.set(name, providerProxy);
|
|
119
126
|
}
|
|
120
127
|
if (boot && !getBootFlag(name)) {
|
|
@@ -143,7 +150,7 @@ export function cleanupProvider(name) {
|
|
|
143
150
|
await Promise.all(promises);
|
|
144
151
|
cache.clear();
|
|
145
152
|
};
|
|
146
|
-
if (
|
|
153
|
+
if (BROWSER) {
|
|
147
154
|
const cache = clientCache.get(name);
|
|
148
155
|
if (cache) {
|
|
149
156
|
void cleanupCache(cache);
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
declare const MIRROR_TARGET: unique symbol;
|
|
2
|
+
declare const MIRROR_CACHE: unique symbol;
|
|
3
|
+
export declare class ClassMirror {
|
|
4
|
+
private [MIRROR_TARGET];
|
|
5
|
+
private [MIRROR_CACHE];
|
|
6
|
+
constructor(target: object);
|
|
3
7
|
}
|
|
8
|
+
export {};
|
|
@@ -1,19 +1,38 @@
|
|
|
1
|
+
const MIRROR_TARGET = Symbol('class-mirror-target');
|
|
2
|
+
const MIRROR_CACHE = Symbol('class-mirror-cache');
|
|
1
3
|
export class ClassMirror {
|
|
4
|
+
[MIRROR_TARGET];
|
|
5
|
+
[MIRROR_CACHE];
|
|
2
6
|
constructor(target) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
7
|
+
this[MIRROR_TARGET] = target;
|
|
8
|
+
this[MIRROR_CACHE] = new Map();
|
|
9
|
+
return new Proxy(this, {
|
|
10
|
+
get(proxyTarget, prop, receiver) {
|
|
11
|
+
if (Reflect.has(proxyTarget, prop)) {
|
|
12
|
+
return Reflect.get(proxyTarget, prop, receiver);
|
|
13
|
+
}
|
|
14
|
+
const mirrorTarget = proxyTarget[MIRROR_TARGET];
|
|
15
|
+
const mirroredValue = Reflect.get(mirrorTarget, prop, mirrorTarget);
|
|
16
|
+
if (typeof mirroredValue !== 'function') {
|
|
17
|
+
return mirroredValue;
|
|
18
|
+
}
|
|
19
|
+
const cache = proxyTarget[MIRROR_CACHE];
|
|
20
|
+
if (cache.has(prop)) {
|
|
21
|
+
return cache.get(prop);
|
|
22
|
+
}
|
|
23
|
+
const bound = mirroredValue.bind(mirrorTarget);
|
|
24
|
+
cache.set(prop, bound);
|
|
25
|
+
return bound;
|
|
26
|
+
},
|
|
27
|
+
has(proxyTarget, prop) {
|
|
28
|
+
return Reflect.has(proxyTarget, prop) || Reflect.has(proxyTarget[MIRROR_TARGET], prop);
|
|
29
|
+
},
|
|
30
|
+
ownKeys(proxyTarget) {
|
|
31
|
+
return [...new Set([...Reflect.ownKeys(proxyTarget), ...Reflect.ownKeys(proxyTarget[MIRROR_TARGET])])];
|
|
32
|
+
},
|
|
33
|
+
getOwnPropertyDescriptor(proxyTarget, prop) {
|
|
34
|
+
return Reflect.getOwnPropertyDescriptor(proxyTarget, prop) ?? Reflect.getOwnPropertyDescriptor(proxyTarget[MIRROR_TARGET], prop);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
18
37
|
}
|
|
19
38
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { Cookies
|
|
2
|
-
import {
|
|
1
|
+
import { Cookies } from '@azure-net/tools';
|
|
2
|
+
import { BROWSER } from '@azure-net/tools/environment';
|
|
3
|
+
import { RequestContext } from '@azure-net/edges/context';
|
|
3
4
|
/**
|
|
4
5
|
* Utility class for managing cookies in svelte ssr (browser and server).
|
|
5
6
|
* Supports setting, getting, deleting, checking, and clearing cookies.
|
|
@@ -17,11 +18,11 @@ export class UniversalCookie {
|
|
|
17
18
|
* @returns {void}
|
|
18
19
|
*/
|
|
19
20
|
static set(name, value, options) {
|
|
20
|
-
if (
|
|
21
|
+
if (BROWSER) {
|
|
21
22
|
Cookies.set(name, value, options);
|
|
22
23
|
return;
|
|
23
24
|
}
|
|
24
|
-
|
|
25
|
+
else {
|
|
25
26
|
const event = RequestContext.current().event;
|
|
26
27
|
if (event) {
|
|
27
28
|
const encodedKey = encodeURIComponent(name);
|
|
@@ -53,7 +54,6 @@ export class UniversalCookie {
|
|
|
53
54
|
return;
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
|
-
throw new Error('Could not detect current environment');
|
|
57
57
|
}
|
|
58
58
|
/**
|
|
59
59
|
* Retrieves the value of a cookie by key.
|
|
@@ -64,10 +64,10 @@ export class UniversalCookie {
|
|
|
64
64
|
* @returns {T | undefined} The cookie value, parsed as type T or null if not found.
|
|
65
65
|
*/
|
|
66
66
|
static get(name) {
|
|
67
|
-
if (
|
|
67
|
+
if (BROWSER) {
|
|
68
68
|
return Cookies.get(name) ?? undefined;
|
|
69
69
|
}
|
|
70
|
-
|
|
70
|
+
else {
|
|
71
71
|
const event = RequestContext.current().event;
|
|
72
72
|
if (event) {
|
|
73
73
|
const encodedKey = encodeURIComponent(name);
|
|
@@ -85,7 +85,6 @@ export class UniversalCookie {
|
|
|
85
85
|
}
|
|
86
86
|
return undefined;
|
|
87
87
|
}
|
|
88
|
-
return undefined;
|
|
89
88
|
}
|
|
90
89
|
/**
|
|
91
90
|
* Retrieves all cookies as a key-value record.
|
|
@@ -95,10 +94,10 @@ export class UniversalCookie {
|
|
|
95
94
|
* @returns {T | undefined} An object with all cookie keys and their values.
|
|
96
95
|
*/
|
|
97
96
|
static getAll() {
|
|
98
|
-
if (
|
|
97
|
+
if (BROWSER) {
|
|
99
98
|
return Cookies.getAll();
|
|
100
99
|
}
|
|
101
|
-
|
|
100
|
+
else {
|
|
102
101
|
const event = RequestContext.current().event;
|
|
103
102
|
const result = {};
|
|
104
103
|
if (event) {
|
|
@@ -114,7 +113,6 @@ export class UniversalCookie {
|
|
|
114
113
|
}
|
|
115
114
|
return result;
|
|
116
115
|
}
|
|
117
|
-
return undefined;
|
|
118
116
|
}
|
|
119
117
|
/**
|
|
120
118
|
* Checks if a cookie with the given key exists.
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { error, redirect } from '@sveltejs/kit';
|
|
2
|
-
import { RequestContext } from '
|
|
2
|
+
import { RequestContext } from '@azure-net/edges/context';
|
|
3
3
|
import { beforeNavigate, goto } from '$app/navigation';
|
|
4
4
|
import { page } from '$app/state';
|
|
5
|
-
import {
|
|
5
|
+
import { BROWSER } from '@azure-net/tools/environment';
|
|
6
6
|
import { UniversalCookie } from '../cookie/index.js';
|
|
7
7
|
export const createMiddlewareManager = (middlewares) => {
|
|
8
8
|
const universalRedirect = (location, status = 301, navigation) => {
|
|
9
|
-
if (
|
|
9
|
+
if (BROWSER) {
|
|
10
10
|
if (navigation) {
|
|
11
11
|
navigation?.cancel();
|
|
12
12
|
}
|
|
@@ -18,8 +18,8 @@ export const createMiddlewareManager = (middlewares) => {
|
|
|
18
18
|
};
|
|
19
19
|
const executeMiddlewares = async (navigation) => {
|
|
20
20
|
let event;
|
|
21
|
-
let from
|
|
22
|
-
if (
|
|
21
|
+
let from;
|
|
22
|
+
if (!BROWSER) {
|
|
23
23
|
event = RequestContext.current().event;
|
|
24
24
|
const referer = event?.request.headers.get('referer');
|
|
25
25
|
from = referer ? new URL(referer) : undefined;
|
|
@@ -27,7 +27,7 @@ export const createMiddlewareManager = (middlewares) => {
|
|
|
27
27
|
else {
|
|
28
28
|
from = navigation?.from?.url ?? undefined;
|
|
29
29
|
}
|
|
30
|
-
const to = (
|
|
30
|
+
const to = (BROWSER ? (navigation?.to?.url ?? page?.url) : event?.url);
|
|
31
31
|
for (const middleware of middlewares) {
|
|
32
32
|
let shouldContinue = false;
|
|
33
33
|
const next = (location, status = 301) => {
|
|
@@ -40,14 +40,14 @@ export const createMiddlewareManager = (middlewares) => {
|
|
|
40
40
|
event,
|
|
41
41
|
page,
|
|
42
42
|
cookies: UniversalCookie,
|
|
43
|
-
isServer:
|
|
43
|
+
isServer: !BROWSER,
|
|
44
44
|
to,
|
|
45
45
|
from,
|
|
46
46
|
error,
|
|
47
47
|
next
|
|
48
48
|
});
|
|
49
49
|
if (!shouldContinue) {
|
|
50
|
-
if (
|
|
50
|
+
if (BROWSER) {
|
|
51
51
|
navigation?.cancel();
|
|
52
52
|
if (from) {
|
|
53
53
|
void goto(from.pathname);
|
|
@@ -61,7 +61,11 @@ export const createMiddlewareManager = (middlewares) => {
|
|
|
61
61
|
}
|
|
62
62
|
};
|
|
63
63
|
const serverMiddleware = async () => await executeMiddlewares();
|
|
64
|
+
let clientRegistered = false;
|
|
64
65
|
const clientMiddleware = () => {
|
|
66
|
+
if (!BROWSER || clientRegistered)
|
|
67
|
+
return;
|
|
68
|
+
clientRegistered = true;
|
|
65
69
|
beforeNavigate(async (navigation) => {
|
|
66
70
|
await executeMiddlewares(navigation);
|
|
67
71
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { RequestErrors } from '../../delivery/schema/index.js';
|
|
2
|
-
import type { AsyncActionResponse } from '../../
|
|
3
|
-
type InitialData<FormData, Initial extends Partial<FormData>> =
|
|
2
|
+
import type { AsyncActionResponse } from '../../delivery/injectableDependencies/AsyncHelpers.js';
|
|
3
|
+
type InitialData<FormData, Initial extends Partial<FormData>> = () => Initial | Promise<Initial>;
|
|
4
4
|
type PathRequiredShape<T, P extends string> = P extends `${infer Head}.${infer Tail}` ? Head extends keyof T ? {
|
|
5
5
|
[K in Head]-?: PathRequiredShape<NonNullable<T[K]>, Tail>;
|
|
6
6
|
} : unknown : P extends keyof T ? {
|
|
@@ -8,19 +8,23 @@ type PathRequiredShape<T, P extends string> = P extends `${infer Head}.${infer T
|
|
|
8
8
|
} : unknown;
|
|
9
9
|
type UnionToIntersection<U> = (U extends unknown ? (arg: U) => void : never) extends (arg: infer I) => void ? I : never;
|
|
10
10
|
type RequiredByPaths<T, P extends string> = [P] extends [never] ? object : UnionToIntersection<PathRequiredShape<T, P>>;
|
|
11
|
+
type ResetBehaviors = 'clear' | 'initial' | 'reloadInitial' | 'default';
|
|
11
12
|
export interface FormConfig<FormData, Response, Initial extends Partial<FormData> = Partial<FormData>, RequiredPath extends string = never> {
|
|
12
13
|
initialData?: InitialData<FormData, Initial>;
|
|
13
14
|
required?: readonly RequiredPath[];
|
|
14
15
|
onSuccess?: (response: Response) => Promise<void> | void;
|
|
15
16
|
onError?: () => Promise<void> | void;
|
|
16
|
-
beforeSubmit?: (
|
|
17
|
-
|
|
17
|
+
beforeSubmit?: (actions: {
|
|
18
|
+
form: ActiveFormController<FormData, RequiredPath>;
|
|
19
|
+
abort: () => void;
|
|
20
|
+
}) => Promise<void> | void;
|
|
21
|
+
successBehavior?: ResetBehaviors;
|
|
18
22
|
}
|
|
19
23
|
export interface ActiveForm<FormData, Response, Custom, RequiredPath extends string = never> {
|
|
20
24
|
data: Partial<FormData> & RequiredByPaths<FormData, RequiredPath>;
|
|
21
25
|
errors: RequestErrors<FormData>;
|
|
22
26
|
submit: () => Promise<AsyncActionResponse<Response, FormData, Custom>>;
|
|
23
|
-
reset: (
|
|
27
|
+
reset: (behavior?: ResetBehaviors) => Promise<void>;
|
|
24
28
|
pending: boolean;
|
|
25
29
|
dirty: boolean;
|
|
26
30
|
ready: Promise<Partial<FormData>>;
|
|
@@ -28,7 +32,7 @@ export interface ActiveForm<FormData, Response, Custom, RequiredPath extends str
|
|
|
28
32
|
export interface ActiveFormController<FormData, RequiredPath extends string = never> {
|
|
29
33
|
data: Partial<FormData> & RequiredByPaths<FormData, RequiredPath>;
|
|
30
34
|
errors: RequestErrors<FormData>;
|
|
31
|
-
reset: (
|
|
35
|
+
reset: (behavior?: ResetBehaviors) => Promise<void>;
|
|
32
36
|
}
|
|
33
37
|
type ExtractResponse<T> = T extends AsyncActionResponse<infer R, unknown, unknown> ? R : never;
|
|
34
38
|
type ExtractFormData<T> = T extends AsyncActionResponse<unknown, infer D, unknown> ? D : never;
|
|
@@ -1,59 +1,55 @@
|
|
|
1
|
-
import { ObjectUtil } from 'azure-net
|
|
1
|
+
import { ObjectUtil } from '@azure-net/tools';
|
|
2
2
|
export const createActiveForm = (onSubmit, config) => {
|
|
3
3
|
const isPromise = (value) => {
|
|
4
4
|
return typeof value?.then === 'function';
|
|
5
5
|
};
|
|
6
|
-
|
|
7
|
-
const source = config?.initialData;
|
|
8
|
-
if (!source) {
|
|
9
|
-
return { sync: true, value: {} };
|
|
10
|
-
}
|
|
11
|
-
const result = typeof source === 'function' ? source() : source;
|
|
12
|
-
if (isPromise(result)) {
|
|
13
|
-
return { sync: false, promise: result };
|
|
14
|
-
}
|
|
15
|
-
return { sync: true, value: (result ?? {}) };
|
|
16
|
-
};
|
|
17
|
-
const initialSource = resolveInitialSource();
|
|
18
|
-
let initial = initialSource.sync ? initialSource.value : {};
|
|
6
|
+
let initial = {};
|
|
19
7
|
let formData = $state(ObjectUtil.deepClone(initial));
|
|
20
8
|
let formErrors = $state({});
|
|
21
9
|
let pending = $state(false);
|
|
22
|
-
const dirty = $derived(
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
10
|
+
const dirty = $derived(!ObjectUtil.equals(formData, initial));
|
|
11
|
+
const loadInitialData = async () => {
|
|
12
|
+
const source = config?.initialData;
|
|
13
|
+
if (!source) {
|
|
14
|
+
initial = {};
|
|
15
|
+
formData = ObjectUtil.deepClone(initial);
|
|
16
|
+
formErrors = {};
|
|
17
|
+
return initial;
|
|
29
18
|
}
|
|
19
|
+
const value = source();
|
|
20
|
+
const nextInitial = isPromise(value) ? await value : value;
|
|
21
|
+
initial = (nextInitial ?? {});
|
|
22
|
+
formData = ObjectUtil.deepClone(initial);
|
|
23
|
+
formErrors = {};
|
|
30
24
|
return initial;
|
|
31
|
-
}
|
|
25
|
+
};
|
|
26
|
+
const ready = loadInitialData();
|
|
32
27
|
const submit = async () => {
|
|
33
28
|
pending = true;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
await config.beforeSubmit(formApi, () => abort());
|
|
41
|
-
if (aborted) {
|
|
42
|
-
return {
|
|
43
|
-
success: false,
|
|
44
|
-
response: undefined
|
|
29
|
+
try {
|
|
30
|
+
if (config?.beforeSubmit) {
|
|
31
|
+
let aborted = false;
|
|
32
|
+
const abort = () => {
|
|
33
|
+
aborted = true;
|
|
34
|
+
pending = false;
|
|
45
35
|
};
|
|
36
|
+
await config.beforeSubmit({ form: formApi, abort: () => abort() });
|
|
37
|
+
if (aborted) {
|
|
38
|
+
return {
|
|
39
|
+
success: false,
|
|
40
|
+
response: undefined
|
|
41
|
+
};
|
|
42
|
+
}
|
|
46
43
|
}
|
|
47
|
-
}
|
|
48
|
-
try {
|
|
49
44
|
const result = await onSubmit($state.snapshot(formData));
|
|
50
|
-
if (result.error?.fields) {
|
|
51
|
-
formErrors = result.error.fields;
|
|
52
|
-
}
|
|
53
45
|
if (result.success) {
|
|
54
46
|
await config?.onSuccess?.(result.response);
|
|
47
|
+
await reset(config?.successBehavior ?? 'default');
|
|
55
48
|
}
|
|
56
49
|
else {
|
|
50
|
+
if (result.error?.validation) {
|
|
51
|
+
formErrors = result.error.validation;
|
|
52
|
+
}
|
|
57
53
|
await config?.onError?.();
|
|
58
54
|
}
|
|
59
55
|
return result;
|
|
@@ -62,8 +58,18 @@ export const createActiveForm = (onSubmit, config) => {
|
|
|
62
58
|
pending = false;
|
|
63
59
|
}
|
|
64
60
|
};
|
|
65
|
-
const reset = (
|
|
66
|
-
|
|
61
|
+
const reset = async (behavior = 'clear') => {
|
|
62
|
+
switch (behavior) {
|
|
63
|
+
case 'clear':
|
|
64
|
+
formData = {};
|
|
65
|
+
break;
|
|
66
|
+
case 'initial':
|
|
67
|
+
formData = ObjectUtil.deepClone(initial);
|
|
68
|
+
break;
|
|
69
|
+
case 'reloadInitial':
|
|
70
|
+
await loadInitialData();
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
67
73
|
formErrors = {};
|
|
68
74
|
};
|
|
69
75
|
const formApi = {
|
|
@@ -100,8 +106,8 @@ export const createActiveForm = (onSubmit, config) => {
|
|
|
100
106
|
get pending() {
|
|
101
107
|
return pending;
|
|
102
108
|
},
|
|
103
|
-
ready,
|
|
104
109
|
submit,
|
|
110
|
+
ready,
|
|
105
111
|
reset
|
|
106
112
|
};
|
|
107
113
|
};
|
|
@@ -3,7 +3,6 @@ export type AsyncSignalSource = 'auto' | 'manual' | 'global';
|
|
|
3
3
|
export interface AsyncSignalOptions<TData, TError = Error> {
|
|
4
4
|
server?: boolean;
|
|
5
5
|
immediate?: boolean;
|
|
6
|
-
watch?: (() => unknown)[];
|
|
7
6
|
initialData?: TData | (() => TData);
|
|
8
7
|
beforeSend?: (meta: {
|
|
9
8
|
initial: boolean;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { untrack } from 'svelte';
|
|
2
|
-
import {
|
|
2
|
+
import { BROWSER } from '@azure-net/tools/environment';
|
|
3
3
|
const createAsyncSignalManager = () => {
|
|
4
|
-
const instances =
|
|
4
|
+
const instances = BROWSER ? new Map() : undefined;
|
|
5
5
|
const generateUid = () => {
|
|
6
6
|
return Math.random().toString(36).substring(2, 9);
|
|
7
7
|
};
|
|
@@ -46,7 +46,7 @@ const createAsyncSignalManager = () => {
|
|
|
46
46
|
};
|
|
47
47
|
const asyncSignalManager = createAsyncSignalManager();
|
|
48
48
|
export const createAsyncSignal = (handler, options = {}) => {
|
|
49
|
-
const { server = false, immediate = true,
|
|
49
|
+
const { server = false, immediate = true, initialData = undefined, key } = options;
|
|
50
50
|
const resolvedInitialData = typeof initialData === 'function' ? initialData() : initialData;
|
|
51
51
|
let data = $state(resolvedInitialData);
|
|
52
52
|
let error = $state();
|
|
@@ -59,24 +59,29 @@ export const createAsyncSignal = (handler, options = {}) => {
|
|
|
59
59
|
const run = async (runId, source) => {
|
|
60
60
|
const initial = !started;
|
|
61
61
|
started = true;
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
const prevController = abortController;
|
|
63
|
+
if (prevController) {
|
|
64
|
+
prevController.abort();
|
|
64
65
|
}
|
|
65
|
-
|
|
66
|
+
const localController = new AbortController();
|
|
67
|
+
abortController = localController;
|
|
66
68
|
if (options.beforeSend) {
|
|
67
69
|
await options.beforeSend({ initial, source });
|
|
68
70
|
}
|
|
71
|
+
if (runId !== currentRunId || abortController !== localController || localController.signal.aborted) {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
69
74
|
status = 'pending';
|
|
70
75
|
error = undefined;
|
|
71
76
|
try {
|
|
72
|
-
const result = await handler(
|
|
73
|
-
if (abortController.signal.aborted) {
|
|
77
|
+
const result = await handler(localController.signal);
|
|
78
|
+
if (runId !== currentRunId || abortController !== localController || localController.signal.aborted) {
|
|
74
79
|
return undefined;
|
|
75
80
|
}
|
|
76
81
|
data = result;
|
|
77
82
|
status = 'success';
|
|
78
83
|
if (options.onSuccess) {
|
|
79
|
-
options.onSuccess(result);
|
|
84
|
+
await options.onSuccess(result);
|
|
80
85
|
}
|
|
81
86
|
return result;
|
|
82
87
|
}
|
|
@@ -84,10 +89,13 @@ export const createAsyncSignal = (handler, options = {}) => {
|
|
|
84
89
|
if (err instanceof Error && err.name === 'AbortError') {
|
|
85
90
|
return undefined;
|
|
86
91
|
}
|
|
92
|
+
if (runId !== currentRunId || abortController !== localController || localController.signal.aborted) {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
87
95
|
error = err;
|
|
88
96
|
status = 'error';
|
|
89
97
|
if (options.onError) {
|
|
90
|
-
options.onError(err);
|
|
98
|
+
await options.onError(err);
|
|
91
99
|
}
|
|
92
100
|
return undefined;
|
|
93
101
|
}
|
|
@@ -98,9 +106,6 @@ export const createAsyncSignal = (handler, options = {}) => {
|
|
|
98
106
|
}
|
|
99
107
|
};
|
|
100
108
|
const start = (source) => {
|
|
101
|
-
if (currentPromise) {
|
|
102
|
-
return currentPromise;
|
|
103
|
-
}
|
|
104
109
|
const runId = ++currentRunId;
|
|
105
110
|
const localPromise = run(runId, source);
|
|
106
111
|
currentPromise = localPromise;
|
|
@@ -113,7 +118,7 @@ export const createAsyncSignal = (handler, options = {}) => {
|
|
|
113
118
|
}
|
|
114
119
|
await start('manual');
|
|
115
120
|
};
|
|
116
|
-
if (
|
|
121
|
+
if (BROWSER) {
|
|
117
122
|
const signalKey = key ?? asyncSignalManager.generateKey();
|
|
118
123
|
const callback = (source) => start(source);
|
|
119
124
|
asyncSignalManager.register(signalKey, callback);
|
|
@@ -122,28 +127,14 @@ export const createAsyncSignal = (handler, options = {}) => {
|
|
|
122
127
|
asyncSignalManager.unregister(signalKey, callback);
|
|
123
128
|
};
|
|
124
129
|
});
|
|
125
|
-
if (watch.length > 0) {
|
|
126
|
-
let isFirst = true;
|
|
127
|
-
$effect(() => {
|
|
128
|
-
watch.forEach((dep) => dep());
|
|
129
|
-
if (isFirst && !immediate) {
|
|
130
|
-
isFirst = false;
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
if (!isFirst) {
|
|
134
|
-
void start('auto');
|
|
135
|
-
}
|
|
136
|
-
isFirst = false;
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
130
|
}
|
|
140
131
|
if (immediate) {
|
|
141
|
-
if (
|
|
132
|
+
if (!BROWSER && server) {
|
|
142
133
|
untrack(() => {
|
|
143
134
|
void start('auto');
|
|
144
135
|
});
|
|
145
136
|
}
|
|
146
|
-
else if (
|
|
137
|
+
else if (BROWSER) {
|
|
147
138
|
void start('auto');
|
|
148
139
|
}
|
|
149
140
|
}
|
|
@@ -1,20 +1,19 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
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;
|
|
9
|
+
}
|
|
4
10
|
export interface CreateQueryOptions<T extends Record<string, unknown>> {
|
|
5
|
-
|
|
6
|
-
signal?: QuerySignal;
|
|
7
|
-
excludeKeys?: (keyof T)[];
|
|
8
|
-
debounceMs?: number;
|
|
9
|
-
autoRefresh?: boolean;
|
|
11
|
+
onChange?: QueryOnChangeOptions<T>;
|
|
10
12
|
}
|
|
11
13
|
export interface QueryController<T extends Record<string, unknown>> {
|
|
12
14
|
data: T;
|
|
13
|
-
patch: (values: Partial<T>) => void;
|
|
14
|
-
set: <K extends keyof T>(key: K, value: T[K]) => void;
|
|
15
15
|
reset: () => void;
|
|
16
16
|
snapshot: () => T;
|
|
17
17
|
initial: () => T;
|
|
18
|
-
attachSignal: (signal?: QuerySignal) => void;
|
|
19
18
|
}
|
|
20
|
-
export declare const createQuery: <T extends Record<string, unknown>>(
|
|
19
|
+
export declare const createQuery: <T extends Record<string, unknown>>(initialValue: T, options?: CreateQueryOptions<T>) => QueryController<T>;
|