@azure-net/kit 5.5.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 +2 -1
- package/dist/svelte/async-signal/AsyncSignal.svelte.js +48 -14
- package/package.json +1 -1
- package/dist/delivery/injectable-dependencies/ErrorHandler.d.ts +0 -7
- package/dist/delivery/injectable-dependencies/ErrorHandler.js +0 -15
package/dist/delivery/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { createAsyncHelpers,
|
|
1
|
+
export { createAsyncHelpers, type AsyncHelperRetry, type AsyncResourceSettings, type AsyncActionResponse } from './injectable-dependencies/index.js';
|
|
2
2
|
export { createSchemaFactory, schema, type Schema, type RequestErrors, type ISchemaError, type ValidationResult, type ValidationRuleResult, type ValidationParams, type ValidationMessage, type ValidationErrorsMap } from './schema/index.js';
|
|
3
3
|
export { createRules, validationMessagesRu, validationMessagesI18n, validationMessagesEn, type ValidationRuleParams, type BaseValidationMessages } from './schema/rules/index.js';
|
package/dist/delivery/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { createAsyncHelpers
|
|
1
|
+
export { createAsyncHelpers } from './injectable-dependencies/index.js';
|
|
2
2
|
export { createSchemaFactory, schema } from './schema/index.js';
|
|
3
3
|
export { createRules, validationMessagesRu, validationMessagesI18n, validationMessagesEn } from './schema/rules/index.js';
|
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
import { createErrorHandler } from './ErrorHandler.js';
|
|
2
1
|
import { type AppError, type IAppError } from '../../shared/app-error/AppError.js';
|
|
2
|
+
export type { AsyncHelperRetry } from '../../shared/app-error/ErrorRuntime.js';
|
|
3
3
|
export interface AsyncActionResponse<T, D = never, ErrorResult = Record<never, never>> {
|
|
4
4
|
success: boolean;
|
|
5
5
|
response: T;
|
|
6
6
|
error?: IAppError<D> & ErrorResult;
|
|
7
7
|
}
|
|
8
|
-
export interface AsyncHelperRetry {
|
|
9
|
-
can: boolean;
|
|
10
|
-
call?: () => Promise<Error | void>;
|
|
11
|
-
}
|
|
12
8
|
type Action<Res> = () => Promise<Res>;
|
|
13
|
-
type ErrorParser<ErrorResult extends object> = ReturnType<typeof createErrorHandler<ErrorResult>>;
|
|
14
9
|
export interface AsyncActionSettings<Res = never, Req = never, ErrorResult = AppError<Error>> {
|
|
15
10
|
beforeSend?: (actions: {
|
|
16
11
|
next: () => void;
|
|
@@ -23,12 +18,7 @@ export interface AsyncActionSettings<Res = never, Req = never, ErrorResult = App
|
|
|
23
18
|
export interface AsyncResourceSettings<Res = never, Req = never, ErrorResult = AppError<Error>> extends AsyncActionSettings<Res, Req, ErrorResult> {
|
|
24
19
|
reject?: boolean;
|
|
25
20
|
}
|
|
26
|
-
export declare class AsyncHelperError extends Error {
|
|
27
|
-
}
|
|
28
21
|
export declare const createAsyncHelpers: <ErrorResult extends object>() => {
|
|
29
22
|
createAsyncAction: <Res = never, Req = never>(action: Action<Res>, args?: AsyncActionSettings<Res, Req, ErrorResult>) => Promise<AsyncActionResponse<Res, Req, ErrorResult>>;
|
|
30
23
|
createAsyncResource: <Res = never, Req_1 = never>(action: Action<Res>, args?: AsyncResourceSettings<Res, Req_1, ErrorResult>) => Promise<Res>;
|
|
31
|
-
errorParser: <T = unknown>(error: Error, asyncHelperRetry?: AsyncHelperRetry) => Promise<IAppError<T> & ErrorResult>;
|
|
32
|
-
useHandler: (parser: ErrorParser<ErrorResult>) => void;
|
|
33
24
|
};
|
|
34
|
-
export {};
|
|
@@ -1,33 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {} from '../../shared/app-error/
|
|
3
|
-
import { BROWSER } from '../../external/tools/index.js';
|
|
4
|
-
import { RequestContext } from '../../external/edges/ServerContext.js';
|
|
5
|
-
export class AsyncHelperError extends Error {
|
|
6
|
-
}
|
|
1
|
+
import { AsyncHelperError } from '../../shared/app-error/AppError.js';
|
|
2
|
+
import { resolveAzureNetKitError } from '../../shared/app-error/ErrorRuntime.js';
|
|
7
3
|
export const createAsyncHelpers = () => {
|
|
8
|
-
const defaultErrorParser = createErrorHandler();
|
|
9
|
-
const handlerContextKey = Symbol('azureNetAsyncHelperErrorParser');
|
|
10
|
-
let clientErrorParser;
|
|
11
|
-
const getErrorParser = () => {
|
|
12
|
-
if (BROWSER)
|
|
13
|
-
return clientErrorParser ?? defaultErrorParser;
|
|
14
|
-
try {
|
|
15
|
-
const data = RequestContext.current().data;
|
|
16
|
-
return data[handlerContextKey] ?? defaultErrorParser;
|
|
17
|
-
}
|
|
18
|
-
catch {
|
|
19
|
-
return defaultErrorParser;
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
const errorParser = async (error, asyncHelperRetry) => await getErrorParser()(error, asyncHelperRetry);
|
|
23
|
-
const useHandler = (parser) => {
|
|
24
|
-
if (BROWSER) {
|
|
25
|
-
clientErrorParser = parser;
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
const data = RequestContext.current().data;
|
|
29
|
-
data[handlerContextKey] = parser;
|
|
30
|
-
};
|
|
31
4
|
const normalizeError = (err) => (err instanceof Error ? err : new Error(String(err)));
|
|
32
5
|
const prepareErrors = async (error, retry) => {
|
|
33
6
|
let retryResult = undefined;
|
|
@@ -41,7 +14,10 @@ export const createAsyncHelpers = () => {
|
|
|
41
14
|
.catch((err) => normalizeError(err));
|
|
42
15
|
}
|
|
43
16
|
};
|
|
44
|
-
const parsedError = await
|
|
17
|
+
const parsedError = await resolveAzureNetKitError(normalizeError(error), {
|
|
18
|
+
can: !!retry,
|
|
19
|
+
call: retry ? () => retryFunc() : undefined
|
|
20
|
+
});
|
|
45
21
|
return { error: parsedError, retryResult };
|
|
46
22
|
};
|
|
47
23
|
const beforeSendResolver = async (settings) => {
|
|
@@ -110,7 +86,7 @@ export const createAsyncHelpers = () => {
|
|
|
110
86
|
await args?.onError?.(result);
|
|
111
87
|
}
|
|
112
88
|
catch (err) {
|
|
113
|
-
throw await
|
|
89
|
+
throw await resolveAzureNetKitError(new AsyncHelperError('onError caught exception', { cause: normalizeError(err) }));
|
|
114
90
|
}
|
|
115
91
|
return result;
|
|
116
92
|
}
|
|
@@ -124,8 +100,6 @@ export const createAsyncHelpers = () => {
|
|
|
124
100
|
};
|
|
125
101
|
return {
|
|
126
102
|
createAsyncAction,
|
|
127
|
-
createAsyncResource
|
|
128
|
-
errorParser,
|
|
129
|
-
useHandler
|
|
103
|
+
createAsyncResource
|
|
130
104
|
};
|
|
131
105
|
};
|
|
@@ -47,13 +47,13 @@ interface SchemaBuilder<SchemaData, Rules = unknown, TransformResult = SchemaDat
|
|
|
47
47
|
create(): Schema<SchemaData, TransformResult, CustomMethods>;
|
|
48
48
|
}
|
|
49
49
|
interface SchemaInstance<TransformResult, SchemaData> {
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
toJson(params?: TransformationParams<SchemaData>): TransformResult;
|
|
51
|
+
toFormData(params?: TransformationParams<SchemaData>): FormData;
|
|
52
52
|
validated(): {
|
|
53
53
|
valid: boolean;
|
|
54
54
|
errors: RequestErrors<SchemaData>;
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
toJson(): TransformResult;
|
|
56
|
+
toFormData(): FormData;
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
59
|
export type Schema<SchemaData, TransformResult, CustomMethods> = CustomMethods & {
|
|
@@ -109,18 +109,18 @@ class SchemaBuilderImpl {
|
|
|
109
109
|
return {
|
|
110
110
|
valid: _isValid,
|
|
111
111
|
errors: _errors,
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
toJson: () => toJson({ validate: false }),
|
|
113
|
+
toFormData: () => toFormData({ validate: false })
|
|
114
114
|
};
|
|
115
115
|
};
|
|
116
|
-
const
|
|
116
|
+
const toJson = (params = {}) => {
|
|
117
117
|
const { validate = true, onValidationError } = params;
|
|
118
118
|
if (validate && !validated({ onValidationError }).valid) {
|
|
119
119
|
throw new SchemaFail(_errors);
|
|
120
120
|
}
|
|
121
121
|
return transform(_preparedData);
|
|
122
122
|
};
|
|
123
|
-
const
|
|
123
|
+
const toFormData = (params = {}) => {
|
|
124
124
|
const { validate = true, onValidationError } = params;
|
|
125
125
|
if (validate && !validated({ onValidationError }).valid) {
|
|
126
126
|
throw new SchemaFail(_errors);
|
|
@@ -128,8 +128,8 @@ class SchemaBuilderImpl {
|
|
|
128
128
|
return FormDataUtil.fromObject(transform(_preparedData));
|
|
129
129
|
};
|
|
130
130
|
return {
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
toJson,
|
|
132
|
+
toFormData,
|
|
133
133
|
validated
|
|
134
134
|
};
|
|
135
135
|
}
|
|
@@ -10,6 +10,9 @@ export const createRules = (validationMessages) => {
|
|
|
10
10
|
const checkVal = (val) => {
|
|
11
11
|
return val !== undefined && val !== null;
|
|
12
12
|
};
|
|
13
|
+
const isNumericInput = (val) => {
|
|
14
|
+
return typeof val === 'number' || (typeof val === 'string' && val.trim().length > 0);
|
|
15
|
+
};
|
|
13
16
|
/**
|
|
14
17
|
* Checks a value against a regular expression.
|
|
15
18
|
*/
|
|
@@ -137,8 +140,10 @@ export const createRules = (validationMessages) => {
|
|
|
137
140
|
const { message, range } = { ...params, message: { ...validationMessages.number, ...params?.message } };
|
|
138
141
|
return ({ val }) => {
|
|
139
142
|
if (checkVal(val)) {
|
|
143
|
+
if (!isNumericInput(val))
|
|
144
|
+
return message.base();
|
|
140
145
|
const numberVal = Number(val);
|
|
141
|
-
if (!Number.isInteger(numberVal)
|
|
146
|
+
if (!Number.isInteger(numberVal)) {
|
|
142
147
|
return message.base();
|
|
143
148
|
}
|
|
144
149
|
switch (true) {
|
|
@@ -163,12 +168,15 @@ export const createRules = (validationMessages) => {
|
|
|
163
168
|
const { message, maxDigitsAfterDot, range } = { ...params, message: { ...validationMessages.finite, ...params?.message } };
|
|
164
169
|
return ({ val }) => {
|
|
165
170
|
if (checkVal(val)) {
|
|
171
|
+
if (!isNumericInput(val))
|
|
172
|
+
return message.base();
|
|
173
|
+
const normalizedValue = typeof val === 'string' ? val.trim() : String(val);
|
|
166
174
|
const numVal = Number(val);
|
|
167
|
-
if (!Number.isFinite(numVal) ||
|
|
175
|
+
if (!Number.isFinite(numVal) || normalizedValue.startsWith('.')) {
|
|
168
176
|
return message.base();
|
|
169
177
|
}
|
|
170
178
|
if (typeof maxDigitsAfterDot === 'number') {
|
|
171
|
-
const digitsAfterDot =
|
|
179
|
+
const digitsAfterDot = normalizedValue.split('.')[1]?.length ?? 0;
|
|
172
180
|
if (digitsAfterDot > maxDigitsAfterDot) {
|
|
173
181
|
return message.maxDigitsAfterDot(maxDigitsAfterDot);
|
|
174
182
|
}
|
|
@@ -213,9 +221,9 @@ export const createRules = (validationMessages) => {
|
|
|
213
221
|
if (checkVal(val)) {
|
|
214
222
|
if (!Array.isArray(val))
|
|
215
223
|
return message.base();
|
|
216
|
-
if (length.min && val.length < length.min)
|
|
224
|
+
if (length.min !== undefined && val.length < length.min)
|
|
217
225
|
return message.min(length.min);
|
|
218
|
-
if (length.max && val.length > length.max)
|
|
226
|
+
if (length.max !== undefined && val.length > length.max)
|
|
219
227
|
return message.max(length.max);
|
|
220
228
|
if (schema) {
|
|
221
229
|
const nestedErrors = [];
|
|
@@ -359,7 +367,7 @@ export const createRules = (validationMessages) => {
|
|
|
359
367
|
const normalizedBlockedDomains = blockedDomains?.map(normalizeDomain).filter(Boolean);
|
|
360
368
|
const emailRegExp =
|
|
361
369
|
// eslint-disable-next-line no-control-regex
|
|
362
|
-
/^(?:[A-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[A-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|[\x01-\x09\x0B\x0C\x0E-\x7F])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9]{2,}(?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21-\x5A\x53-\x7F]|\\[\x01-\x09\x0B\x0C\x0E-\x7F])+)])$/i;
|
|
370
|
+
/^(?:[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|[\x01-\x09\x0B\x0C\x0E-\x7F])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9]{2,}(?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21-\x5A\x53-\x7F]|\\[\x01-\x09\x0B\x0C\x0E-\x7F])+)])$/i;
|
|
363
371
|
return ({ val }) => {
|
|
364
372
|
if (!checkVal(val))
|
|
365
373
|
return undefined;
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export { AppError, ErrorTypes, AzureNetKitInternalError, type IAppError } from './shared/app-error/AppError.js';
|
|
1
|
+
export { AppError, AsyncHelperError, ErrorTypes, AzureNetKitInternalError, type IAppError } from './shared/app-error/AppError.js';
|
|
2
2
|
export { HttpServiceError } from './infra/http-service/HttpServiceInstance.js';
|
|
3
|
-
export { AsyncHelperError } from './delivery/injectable-dependencies/AsyncHelpers.js';
|
|
4
3
|
export { SchemaFail } from './delivery/schema/Schema.js';
|
package/dist/errors.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export { AppError, ErrorTypes, AzureNetKitInternalError } from './shared/app-error/AppError.js';
|
|
1
|
+
export { AppError, AsyncHelperError, ErrorTypes, AzureNetKitInternalError } from './shared/app-error/AppError.js';
|
|
2
2
|
export { HttpServiceError } from './infra/http-service/HttpServiceInstance.js';
|
|
3
|
-
export { AsyncHelperError } from './delivery/injectable-dependencies/AsyncHelpers.js';
|
|
4
3
|
export { SchemaFail } from './delivery/schema/Schema.js';
|
|
@@ -19,7 +19,7 @@ export declare class ResponseBuilder<TData = unknown, TMeta = object, TWrapper =
|
|
|
19
19
|
mapCollectionUsing<TResource>(ResourceClass: new (data: ArrayElement<TData>) => {
|
|
20
20
|
toPlainObject(): TResource;
|
|
21
21
|
}): Omit<this, keyof ResponseBuilder<unknown, unknown, unknown>> & ResponseBuilder<TResource[], TMeta, TWrapper>;
|
|
22
|
-
|
|
22
|
+
extractKey<TPath extends DeepKeys<TData>>(path: TPath): Omit<this, keyof ResponseBuilder<unknown, unknown, unknown>> & ResponseBuilder<DeepValue<TData, TPath>, TMeta, TWrapper>;
|
|
23
23
|
addMeta<TNewMeta extends Record<string, unknown>>(metaData: TNewMeta | ((current: TMeta & TNewMeta) => TMeta & TNewMeta)): Omit<this, keyof ResponseBuilder<unknown, unknown, unknown>> & ResponseBuilder<TData, TMeta & TNewMeta, TWrapper>;
|
|
24
24
|
getData(): TData;
|
|
25
25
|
get(): {
|
|
@@ -52,7 +52,7 @@ export const handle = edgesHandle(async ({ serialize, edgesEvent, resolve }) =>
|
|
|
52
52
|
resolve(event, {
|
|
53
53
|
...options,
|
|
54
54
|
transformPageChunk: async (chunk) => {
|
|
55
|
-
const html = options?.transformPageChunk ? await options.transformPageChunk(chunk) : chunk.html;
|
|
55
|
+
const html = (options?.transformPageChunk ? await options.transformPageChunk(chunk) : undefined) ?? chunk.html;
|
|
56
56
|
return serialize(html);
|
|
57
57
|
}
|
|
58
58
|
})
|
package/dist/shared/app/App.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { type ContextData } from '../../external/edges/ServerContext.js';
|
|
2
|
+
import { AppError, type IAppError } from '../app-error/AppError.js';
|
|
3
|
+
import { type AsyncHelperRetry } from '../app-error/ErrorRuntime.js';
|
|
4
|
+
import { AppEvents } from '../event-bus/EventBus.js';
|
|
2
5
|
import { type IServerMiddleware } from './middleware/ServerMiddleware.js';
|
|
3
6
|
import type { Handle, HandleClientError, HandleFetch, HandleServerError, HandleValidationError, RequestEvent, Reroute, ServerInit, Transport } from '@sveltejs/kit';
|
|
4
7
|
import { type IClientMiddleware } from './middleware/ClientMiddleware.js';
|
|
@@ -11,7 +14,7 @@ type AppDependencyFactories<TApp> = Record<string, AppDependencyFactory<TApp>>;
|
|
|
11
14
|
type ResolvedDependencies<T> = {
|
|
12
15
|
[K in keyof T]: T[K] extends (...args: never[]) => infer TReturn ? TReturn : never;
|
|
13
16
|
};
|
|
14
|
-
type BuilderFlags = Partial<Record<'use' | 'useClient' | 'useClientInit' | 'useClientError' | 'useServerInit' | 'useServer' | 'useServerError' | 'useServerFetch' | 'useServerValidationError' | 'useReroute' | 'useTransport', true>>;
|
|
17
|
+
type BuilderFlags = Partial<Record<'use' | 'useClient' | 'useClientInit' | 'useClientError' | 'useServerInit' | 'useServer' | 'useServerError' | 'useServerFetch' | 'useServerValidationError' | 'useAzureNetKitError' | 'useReroute' | 'useTransport', true>>;
|
|
15
18
|
type WithFlag<TFlags extends BuilderFlags, TKey extends keyof BuilderFlags> = TFlags & Record<TKey, true>;
|
|
16
19
|
type BuilderDependencies<TBuilder> = TBuilder extends {
|
|
17
20
|
readonly __types__?: infer TDependencies;
|
|
@@ -63,6 +66,16 @@ export type AppServerValidationErrorContext<TDependencies extends Record<string,
|
|
|
63
66
|
Container: AppContainer<TDependencies>;
|
|
64
67
|
requestContext: ContextData;
|
|
65
68
|
};
|
|
69
|
+
export interface AppAzureNetKitErrorContext<TDependencies extends Record<string, unknown>> {
|
|
70
|
+
Container: AppContainer<TDependencies>;
|
|
71
|
+
AppEvents: typeof AppEvents;
|
|
72
|
+
error: AppError;
|
|
73
|
+
retry: AsyncHelperRetry;
|
|
74
|
+
isClient: boolean;
|
|
75
|
+
isServer: boolean;
|
|
76
|
+
requestContext?: ContextData;
|
|
77
|
+
event?: RequestEvent;
|
|
78
|
+
}
|
|
66
79
|
export type AppUniversalLifecycleCallback<TDependencies extends Record<string, unknown>> = (context: AppUniversalLifecycleContext<TDependencies>) => MaybePromise<void>;
|
|
67
80
|
export type AppClientLifecycleCallback<TDependencies extends Record<string, unknown>> = (context: AppClientLifecycleContext<TDependencies>) => MaybePromise<void>;
|
|
68
81
|
export type AppClientInitLifecycleCallback<TDependencies extends Record<string, unknown>> = (context: AppClientInitLifecycleContext<TDependencies>) => MaybePromise<void>;
|
|
@@ -72,6 +85,7 @@ export type AppServerLifecycleCallback<TDependencies extends Record<string, unkn
|
|
|
72
85
|
export type AppServerErrorCallback<TDependencies extends Record<string, unknown>> = (context: AppServerErrorContext<TDependencies>) => ReturnType<HandleServerError>;
|
|
73
86
|
export type AppServerFetchCallback<TDependencies extends Record<string, unknown>> = (context: AppServerFetchContext<TDependencies>) => ReturnType<HandleFetch>;
|
|
74
87
|
export type AppServerValidationErrorCallback<TDependencies extends Record<string, unknown>> = (context: AppServerValidationErrorContext<TDependencies>) => ReturnType<HandleValidationError>;
|
|
88
|
+
export type AppAzureNetKitErrorCallback<TDependencies extends Record<string, unknown>> = (context: AppAzureNetKitErrorContext<TDependencies>) => MaybePromise<IAppError & object>;
|
|
75
89
|
export type AppRerouteCallback = Reroute;
|
|
76
90
|
export type CreateAppBuilder<TDependencies extends Record<string, unknown>, TFlags extends BuilderFlags = object> = {
|
|
77
91
|
readonly __types__?: TDependencies;
|
|
@@ -94,6 +108,8 @@ export type CreateAppBuilder<TDependencies extends Record<string, unknown>, TFla
|
|
|
94
108
|
useServerFetch(callback: AppServerFetchCallback<TDependencies>): CreateAppBuilder<TDependencies, WithFlag<TFlags, 'useServerFetch'>>;
|
|
95
109
|
}> & OnceMethod<TFlags, 'useServerValidationError', {
|
|
96
110
|
useServerValidationError(callback: AppServerValidationErrorCallback<TDependencies>): CreateAppBuilder<TDependencies, WithFlag<TFlags, 'useServerValidationError'>>;
|
|
111
|
+
}> & OnceMethod<TFlags, 'useAzureNetKitError', {
|
|
112
|
+
useAzureNetKitError(callback: AppAzureNetKitErrorCallback<TDependencies>): CreateAppBuilder<TDependencies, WithFlag<TFlags, 'useAzureNetKitError'>>;
|
|
97
113
|
}> & OnceMethod<TFlags, 'useReroute', {
|
|
98
114
|
useReroute(callback: AppRerouteCallback): CreateAppBuilder<TDependencies, WithFlag<TFlags, 'useReroute'>>;
|
|
99
115
|
}> & OnceMethod<TFlags, 'useTransport', {
|
package/dist/shared/app/App.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { BROWSER } from '../../external/tools/index.js';
|
|
2
2
|
import { RequestContext } from '../../external/edges/ServerContext.js';
|
|
3
3
|
import { createBoundaryProvider } from '../boundary-provider/Provider.js';
|
|
4
|
-
import { AzureNetKitInternalError } from '../app-error/AppError.js';
|
|
4
|
+
import { AppError, AzureNetKitInternalError } from '../app-error/AppError.js';
|
|
5
|
+
import { bindAzureNetKitErrorResolver } from '../app-error/ErrorRuntime.js';
|
|
6
|
+
import { AppEvents } from '../event-bus/EventBus.js';
|
|
5
7
|
import { executeServerMiddlewares } from './middleware/ServerMiddleware.js';
|
|
6
8
|
import { beforeNavigate } from '$app/navigation';
|
|
7
9
|
import { executeClientMiddlewares } from './middleware/ClientMiddleware.js';
|
|
@@ -87,6 +89,10 @@ const createBuilder = (dependencies, callbacks) => {
|
|
|
87
89
|
setCallback(callbacks, 'useServerValidationError', callback);
|
|
88
90
|
return builder;
|
|
89
91
|
},
|
|
92
|
+
useAzureNetKitError(callback) {
|
|
93
|
+
setCallback(callbacks, 'useAzureNetKitError', callback);
|
|
94
|
+
return builder;
|
|
95
|
+
},
|
|
90
96
|
useReroute(callback) {
|
|
91
97
|
setCallback(callbacks, 'useReroute', callback);
|
|
92
98
|
return builder;
|
|
@@ -142,9 +148,28 @@ export const createApp = (callback, name = DEFAULT_APP_NAME) => {
|
|
|
142
148
|
};
|
|
143
149
|
}
|
|
144
150
|
});
|
|
151
|
+
const errorResolver = callbacks.useAzureNetKitError
|
|
152
|
+
? (error, retry) => {
|
|
153
|
+
const requestContext = BROWSER ? undefined : getRequestContext();
|
|
154
|
+
return callbacks.useAzureNetKitError({
|
|
155
|
+
Container,
|
|
156
|
+
AppEvents,
|
|
157
|
+
error,
|
|
158
|
+
retry,
|
|
159
|
+
isClient: BROWSER,
|
|
160
|
+
isServer: !BROWSER,
|
|
161
|
+
requestContext,
|
|
162
|
+
event: requestContext?.event
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
: undefined;
|
|
166
|
+
const bindErrorResolver = (requestContext) => {
|
|
167
|
+
bindAzureNetKitErrorResolver(errorResolver, requestContext);
|
|
168
|
+
};
|
|
145
169
|
const runClient = (kind) => {
|
|
146
170
|
if (!BROWSER)
|
|
147
171
|
return undefined;
|
|
172
|
+
bindErrorResolver();
|
|
148
173
|
const flags = getLifecycleFlags(appKey);
|
|
149
174
|
if (flags[kind])
|
|
150
175
|
return undefined;
|
|
@@ -172,8 +197,8 @@ export const createApp = (callback, name = DEFAULT_APP_NAME) => {
|
|
|
172
197
|
if (clientInitialized)
|
|
173
198
|
return;
|
|
174
199
|
clientInitialized = true;
|
|
175
|
-
beforeNavigate(
|
|
176
|
-
|
|
200
|
+
beforeNavigate((navigation) => {
|
|
201
|
+
executeClientMiddlewares(internalMiddlewares, navigation);
|
|
177
202
|
});
|
|
178
203
|
};
|
|
179
204
|
if (clientResult && typeof clientResult.then === 'function') {
|
|
@@ -190,19 +215,33 @@ export const createApp = (callback, name = DEFAULT_APP_NAME) => {
|
|
|
190
215
|
const runServerError = ({ error, event, status, message }) => {
|
|
191
216
|
if (BROWSER)
|
|
192
217
|
return undefined;
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
218
|
+
const requestContext = getServerRequestContext();
|
|
219
|
+
bindErrorResolver(requestContext);
|
|
220
|
+
try {
|
|
221
|
+
const result = callbacks.useServerError?.({
|
|
222
|
+
Container,
|
|
223
|
+
requestContext,
|
|
224
|
+
error,
|
|
225
|
+
event,
|
|
226
|
+
status,
|
|
227
|
+
message,
|
|
228
|
+
useLogger
|
|
229
|
+
});
|
|
230
|
+
if (result && typeof result.then === 'function') {
|
|
231
|
+
return Promise.resolve(result).finally(() => bindAzureNetKitErrorResolver(undefined, requestContext));
|
|
232
|
+
}
|
|
233
|
+
bindAzureNetKitErrorResolver(undefined, requestContext);
|
|
234
|
+
return result;
|
|
235
|
+
}
|
|
236
|
+
catch (error) {
|
|
237
|
+
bindAzureNetKitErrorResolver(undefined, requestContext);
|
|
238
|
+
throw error;
|
|
239
|
+
}
|
|
202
240
|
};
|
|
203
241
|
const runClientError = ({ error, event, status, message }) => {
|
|
204
242
|
if (!BROWSER)
|
|
205
243
|
return undefined;
|
|
244
|
+
bindErrorResolver();
|
|
206
245
|
return callbacks.useClientError?.({
|
|
207
246
|
Container,
|
|
208
247
|
error,
|
|
@@ -234,30 +273,36 @@ export const createApp = (callback, name = DEFAULT_APP_NAME) => {
|
|
|
234
273
|
const reroute = (input) => callbacks.useReroute?.(input);
|
|
235
274
|
const handle = async ({ event, resolve }) => {
|
|
236
275
|
const requestContext = getServerRequestContext();
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
flags
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
276
|
+
bindErrorResolver(requestContext);
|
|
277
|
+
try {
|
|
278
|
+
const flags = getLifecycleFlags(appKey, requestContext);
|
|
279
|
+
if (!flags.server) {
|
|
280
|
+
flags.server = true;
|
|
281
|
+
const universalResult = callbacks.use?.({
|
|
282
|
+
Container,
|
|
283
|
+
isClient: false,
|
|
284
|
+
isServer: true,
|
|
285
|
+
requestContext,
|
|
286
|
+
event
|
|
287
|
+
});
|
|
288
|
+
if (universalResult && typeof universalResult.then === 'function') {
|
|
289
|
+
await universalResult;
|
|
290
|
+
}
|
|
291
|
+
const serverResult = await callbacks.useServer?.({
|
|
292
|
+
Container,
|
|
293
|
+
requestContext,
|
|
294
|
+
event,
|
|
295
|
+
resolve,
|
|
296
|
+
useMiddlewares: executeServerMiddlewares
|
|
297
|
+
});
|
|
298
|
+
if (serverResult)
|
|
299
|
+
return serverResult;
|
|
249
300
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
resolve,
|
|
255
|
-
useMiddlewares: executeServerMiddlewares
|
|
256
|
-
});
|
|
257
|
-
if (serverResult)
|
|
258
|
-
return serverResult;
|
|
301
|
+
return await resolve(event);
|
|
302
|
+
}
|
|
303
|
+
finally {
|
|
304
|
+
bindAzureNetKitErrorResolver(undefined, requestContext);
|
|
259
305
|
}
|
|
260
|
-
return resolve(event);
|
|
261
306
|
};
|
|
262
307
|
const register = Object.assign(() => runClient('client'), {
|
|
263
308
|
clientInit: () => runClient('clientInit'),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { createApp, type AppClientErrorCallback, type AppClientErrorContext, type AppClientInitLifecycleCallback, type AppClientInitLifecycleContext, type AppClientLifecycleCallback, type AppClientLifecycleContext, type AppContainer, type AppRegistrar, type AppServerErrorCallback, type AppServerErrorContext, type AppServerFetchCallback, type AppServerFetchContext, type AppServerInitLifecycleCallback, type AppServerInitLifecycleContext, type AppServerLifecycleCallback, type AppServerLifecycleContext, type AppServerValidationErrorCallback, type AppServerValidationErrorContext, type AppRerouteCallback, type AppUniversalLifecycleCallback, type AppUniversalLifecycleContext, type CreateAppInstance } from './App.js';
|
|
1
|
+
export { createApp, type AppAzureNetKitErrorCallback, type AppAzureNetKitErrorContext, type AppClientErrorCallback, type AppClientErrorContext, type AppClientInitLifecycleCallback, type AppClientInitLifecycleContext, type AppClientLifecycleCallback, type AppClientLifecycleContext, type AppContainer, type AppRegistrar, type AppServerErrorCallback, type AppServerErrorContext, type AppServerFetchCallback, type AppServerFetchContext, type AppServerInitLifecycleCallback, type AppServerInitLifecycleContext, type AppServerLifecycleCallback, type AppServerLifecycleContext, type AppServerValidationErrorCallback, type AppServerValidationErrorContext, type AppRerouteCallback, type AppUniversalLifecycleCallback, type AppUniversalLifecycleContext, type CreateAppInstance } from './App.js';
|
|
2
2
|
export type { IClientMiddleware } from './middleware/ClientMiddleware.js';
|
|
3
3
|
export type { IServerMiddleware } from './middleware/ServerMiddleware.js';
|
|
4
4
|
export type { EnsureRoute, EnsureRouteSource, EnsureRouteTarget } from './middleware/Shared.js';
|
|
@@ -4,7 +4,7 @@ import type { RedirectStatus } from '../../redirect/index.js';
|
|
|
4
4
|
export type IClientMiddleware = (middlewareData: {
|
|
5
5
|
to: URL;
|
|
6
6
|
from?: URL;
|
|
7
|
-
next: (location?: string | URL, status?: RedirectStatus) =>
|
|
7
|
+
next: (location?: string | URL, status?: RedirectStatus) => undefined;
|
|
8
8
|
ensureRoute: EnsureRoute;
|
|
9
|
-
}) =>
|
|
10
|
-
export declare const executeClientMiddlewares: (middlewares: IClientMiddleware[], navigation?: BeforeNavigate) =>
|
|
9
|
+
}) => undefined;
|
|
10
|
+
export declare const executeClientMiddlewares: (middlewares: IClientMiddleware[], navigation?: BeforeNavigate) => void;
|
|
@@ -2,7 +2,7 @@ import {} from '@sveltejs/kit';
|
|
|
2
2
|
import { ensureRoute } from './Shared.js';
|
|
3
3
|
import { page } from '$app/state';
|
|
4
4
|
import { goto } from '$app/navigation';
|
|
5
|
-
export const executeClientMiddlewares =
|
|
5
|
+
export const executeClientMiddlewares = (middlewares, navigation) => {
|
|
6
6
|
const from = navigation?.from?.url ?? undefined;
|
|
7
7
|
const to = navigation?.to?.url ?? page?.url;
|
|
8
8
|
for (const middleware of middlewares) {
|
|
@@ -11,18 +11,17 @@ export const executeClientMiddlewares = async (middlewares, navigation) => {
|
|
|
11
11
|
const next = (location) => {
|
|
12
12
|
shouldContinue = true;
|
|
13
13
|
redirectTo = location;
|
|
14
|
+
return undefined;
|
|
14
15
|
};
|
|
15
|
-
|
|
16
|
+
middleware({
|
|
16
17
|
to,
|
|
17
18
|
from,
|
|
18
19
|
next,
|
|
19
20
|
ensureRoute
|
|
20
21
|
});
|
|
21
|
-
if (result && typeof result.then === 'function')
|
|
22
|
-
await result;
|
|
23
22
|
if (redirectTo) {
|
|
24
23
|
navigation?.cancel();
|
|
25
|
-
|
|
24
|
+
void goto(redirectTo);
|
|
26
25
|
return;
|
|
27
26
|
}
|
|
28
27
|
if (!shouldContinue) {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { HttpServiceError } from '../../infra/http-service/HttpServiceInstance.js';
|
|
2
2
|
import { type RequestErrors } from '../../delivery/schema/Schema.js';
|
|
3
|
+
export declare class AsyncHelperError extends Error {
|
|
4
|
+
}
|
|
3
5
|
export declare enum ErrorTypes {
|
|
4
6
|
Http = "Http",
|
|
5
7
|
Schema = "Schema",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { HttpErrorTypes, HttpServiceError } from '../../infra/http-service/HttpServiceInstance.js';
|
|
2
2
|
import { SchemaFail } from '../../delivery/schema/Schema.js';
|
|
3
|
-
|
|
3
|
+
export class AsyncHelperError extends Error {
|
|
4
|
+
}
|
|
4
5
|
export var ErrorTypes;
|
|
5
6
|
(function (ErrorTypes) {
|
|
6
7
|
ErrorTypes["Http"] = "Http";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ContextData } from '../../external/edges/ServerContext.js';
|
|
2
|
+
import { AppError, type IAppError } from './AppError.js';
|
|
3
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
4
|
+
export interface AsyncHelperRetry {
|
|
5
|
+
can: boolean;
|
|
6
|
+
call?: () => Promise<Error | void>;
|
|
7
|
+
}
|
|
8
|
+
export type AzureNetKitErrorResolver = (error: AppError, retry: AsyncHelperRetry) => MaybePromise<IAppError & object>;
|
|
9
|
+
export declare const bindAzureNetKitErrorResolver: (resolver?: AzureNetKitErrorResolver, requestContext?: ContextData) => void;
|
|
10
|
+
export declare const resolveAzureNetKitError: <Validation = unknown, CustomData extends object = Record<never, never>>(error: unknown, retry?: AsyncHelperRetry) => Promise<IAppError<Validation> & CustomData>;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { BROWSER } from '../../external/tools/index.js';
|
|
2
|
+
import { RequestContext } from '../../external/edges/ServerContext.js';
|
|
3
|
+
import { AppError, AzureNetKitInternalError } from './AppError.js';
|
|
4
|
+
const SERVER_BINDING_KEY = Symbol('azureNetKitErrorResolver');
|
|
5
|
+
let clientBinding;
|
|
6
|
+
const createBinding = (resolver) => ({ resolver });
|
|
7
|
+
const getServerData = (requestContext) => {
|
|
8
|
+
if (requestContext)
|
|
9
|
+
return requestContext.data;
|
|
10
|
+
try {
|
|
11
|
+
return RequestContext.current().data;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
export const bindAzureNetKitErrorResolver = (resolver, requestContext) => {
|
|
18
|
+
if (BROWSER) {
|
|
19
|
+
clientBinding = resolver ? createBinding(resolver) : undefined;
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const data = getServerData(requestContext);
|
|
23
|
+
if (!data)
|
|
24
|
+
return;
|
|
25
|
+
if (resolver) {
|
|
26
|
+
data[SERVER_BINDING_KEY] = createBinding(resolver);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
delete data[SERVER_BINDING_KEY];
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
const getBinding = () => {
|
|
33
|
+
if (BROWSER)
|
|
34
|
+
return clientBinding;
|
|
35
|
+
return getServerData()?.[SERVER_BINDING_KEY];
|
|
36
|
+
};
|
|
37
|
+
const normalizeError = (error) => (error instanceof Error ? error : new Error(String(error)));
|
|
38
|
+
export const resolveAzureNetKitError = async (error, retry = { can: false }) => {
|
|
39
|
+
const normalizedError = normalizeError(error);
|
|
40
|
+
const appError = normalizedError instanceof AppError ? normalizedError : new AppError(normalizedError);
|
|
41
|
+
const binding = getBinding();
|
|
42
|
+
if (!binding || binding.activeErrors?.has(normalizedError)) {
|
|
43
|
+
return appError.toPlainObject();
|
|
44
|
+
}
|
|
45
|
+
const activeErrors = (binding.activeErrors ??= new WeakSet());
|
|
46
|
+
activeErrors.add(normalizedError);
|
|
47
|
+
try {
|
|
48
|
+
const result = await binding.resolver(appError, retry);
|
|
49
|
+
if (!result?.appErrorConvert) {
|
|
50
|
+
throw new AzureNetKitInternalError("[createApp] 'useAzureNetKitError' must return the result of AppError.toPlainObject().");
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
activeErrors.delete(normalizedError);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
@@ -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;
|
|
@@ -32,6 +32,7 @@ export interface AsyncSignalBatchFactory {
|
|
|
32
32
|
export interface AsyncSignalBatch<TSignals extends readonly AsyncSignalSvelte<unknown, unknown>[]> {
|
|
33
33
|
execute: () => TSignals;
|
|
34
34
|
}
|
|
35
|
+
export declare const isAsyncSignalScheduledForClient: (signal: AsyncSignalSvelte<unknown, unknown>) => boolean;
|
|
35
36
|
export declare const createAsyncSignal: <TData, TError = Error>(handler: (signal?: AbortSignal) => Promise<TData>, options?: AsyncSignalOptions<TData, TError>) => AsyncSignalSvelte<TData, TError>;
|
|
36
37
|
export declare const createAsyncSignalBatch: <const TSignals extends readonly AsyncSignalSvelte<unknown, unknown>[]>(factory: (createSignal: AsyncSignalBatchFactory) => TSignals, options?: AsyncSignalBatchOptions) => AsyncSignalBatch<TSignals>;
|
|
37
38
|
export declare const refreshAsyncSignal: (key: string) => Promise<void>;
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import { untrack } from 'svelte';
|
|
2
2
|
import { BROWSER } from '../../external/tools/index.js';
|
|
3
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
|
+
};
|
|
4
18
|
const createAsyncSignalManager = () => {
|
|
5
19
|
const instances = BROWSER ? new Map() : undefined;
|
|
6
20
|
const generateUid = () => {
|
|
@@ -49,17 +63,36 @@ const asyncSignalManager = createAsyncSignalManager();
|
|
|
49
63
|
export const createAsyncSignal = (handler, options = {}) => {
|
|
50
64
|
const { server = false, immediate = true, initialData = undefined, key } = options;
|
|
51
65
|
const resolvedInitialData = typeof initialData === 'function' ? initialData() : initialData;
|
|
66
|
+
let scheduledForClient = immediate && !BROWSER && !server;
|
|
52
67
|
let data = $state(resolvedInitialData);
|
|
53
68
|
let error = $state();
|
|
54
|
-
let status = $state('idle');
|
|
69
|
+
let status = $state(scheduledForClient ? 'pending' : 'idle');
|
|
55
70
|
const pending = $derived(status === 'pending');
|
|
56
71
|
let abortController = null;
|
|
57
72
|
let currentPromise = null;
|
|
73
|
+
let readyPromise = createResolvedPromise(resolvedInitialData);
|
|
74
|
+
let resolveReady = null;
|
|
58
75
|
let currentRunId = 0;
|
|
59
76
|
let started = false;
|
|
60
77
|
let batchLocked = false;
|
|
61
78
|
let batchGate = null;
|
|
62
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
|
+
};
|
|
63
96
|
const run = async (runId, source) => {
|
|
64
97
|
const initial = !started;
|
|
65
98
|
started = true;
|
|
@@ -112,10 +145,13 @@ export const createAsyncSignal = (handler, options = {}) => {
|
|
|
112
145
|
currentPromise = null;
|
|
113
146
|
if (abortController === localController)
|
|
114
147
|
abortController = null;
|
|
148
|
+
settleReadyCycle();
|
|
115
149
|
}
|
|
116
150
|
}
|
|
117
151
|
};
|
|
118
152
|
const start = (source) => {
|
|
153
|
+
scheduledForClient = false;
|
|
154
|
+
startReadyCycle();
|
|
119
155
|
const runId = ++currentRunId;
|
|
120
156
|
const localPromise = run(runId, source);
|
|
121
157
|
currentPromise = localPromise;
|
|
@@ -123,7 +159,7 @@ export const createAsyncSignal = (handler, options = {}) => {
|
|
|
123
159
|
};
|
|
124
160
|
const startWhenUnlocked = (source) => {
|
|
125
161
|
if (batchLocked)
|
|
126
|
-
return batchGate ??
|
|
162
|
+
return batchGate ?? readyPromise;
|
|
127
163
|
return start(source);
|
|
128
164
|
};
|
|
129
165
|
const execute = async () => {
|
|
@@ -165,7 +201,7 @@ export const createAsyncSignal = (handler, options = {}) => {
|
|
|
165
201
|
}
|
|
166
202
|
}
|
|
167
203
|
const asyncSignal = {
|
|
168
|
-
get
|
|
204
|
+
get response() {
|
|
169
205
|
return data;
|
|
170
206
|
},
|
|
171
207
|
get error() {
|
|
@@ -179,14 +215,13 @@ export const createAsyncSignal = (handler, options = {}) => {
|
|
|
179
215
|
},
|
|
180
216
|
get ready() {
|
|
181
217
|
if (batchLocked)
|
|
182
|
-
return (batchGate ??
|
|
183
|
-
|
|
184
|
-
return currentPromise;
|
|
185
|
-
return start('auto');
|
|
218
|
+
return (batchGate ?? readyPromise);
|
|
219
|
+
return readyPromise;
|
|
186
220
|
},
|
|
187
221
|
execute,
|
|
188
222
|
refresh,
|
|
189
223
|
reset: () => {
|
|
224
|
+
scheduledForClient = false;
|
|
190
225
|
if (batchLocked)
|
|
191
226
|
batchSkipRequested = true;
|
|
192
227
|
currentRunId += 1;
|
|
@@ -196,8 +231,10 @@ export const createAsyncSignal = (handler, options = {}) => {
|
|
|
196
231
|
data = undefined;
|
|
197
232
|
error = undefined;
|
|
198
233
|
status = 'idle';
|
|
234
|
+
settleReadyCycle();
|
|
199
235
|
},
|
|
200
236
|
abort: () => {
|
|
237
|
+
scheduledForClient = false;
|
|
201
238
|
if (batchLocked)
|
|
202
239
|
batchSkipRequested = true;
|
|
203
240
|
currentRunId += 1;
|
|
@@ -206,8 +243,12 @@ export const createAsyncSignal = (handler, options = {}) => {
|
|
|
206
243
|
currentPromise = null;
|
|
207
244
|
error = undefined;
|
|
208
245
|
status = 'idle';
|
|
246
|
+
settleReadyCycle();
|
|
209
247
|
}
|
|
210
248
|
};
|
|
249
|
+
Object.defineProperty(asyncSignal, ASYNC_SIGNAL_SCHEDULED_FOR_CLIENT, {
|
|
250
|
+
value: () => scheduledForClient
|
|
251
|
+
});
|
|
211
252
|
Object.defineProperty(asyncSignal, ASYNC_SIGNAL_BATCH_INTERNAL, {
|
|
212
253
|
value: {
|
|
213
254
|
lock: (gate) => {
|
|
@@ -228,13 +269,6 @@ export const createAsyncSignal = (handler, options = {}) => {
|
|
|
228
269
|
});
|
|
229
270
|
return asyncSignal;
|
|
230
271
|
};
|
|
231
|
-
const createDeferred = () => {
|
|
232
|
-
let resolve;
|
|
233
|
-
const promise = new Promise((promiseResolve) => {
|
|
234
|
-
resolve = promiseResolve;
|
|
235
|
-
});
|
|
236
|
-
return { promise, resolve };
|
|
237
|
-
};
|
|
238
272
|
export const createAsyncSignalBatch = (factory, options = {}) => {
|
|
239
273
|
const internals = new Map();
|
|
240
274
|
const createSignal = (handler, signalOptions = {}) => {
|
package/package.json
CHANGED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { AppError, type IAppError } from '../../shared/app-error/AppError.js';
|
|
2
|
-
import { AppEvents } from '../../shared/event-bus/EventBus.js';
|
|
3
|
-
import type { AsyncHelperRetry } from './AsyncHelpers.js';
|
|
4
|
-
export type ErrorHandlerContext = {
|
|
5
|
-
AppEvents: typeof AppEvents;
|
|
6
|
-
};
|
|
7
|
-
export declare const createErrorHandler: <CustomData extends object>(handle?: <T = unknown>(error: AppError<T>, asyncHelperRetry: AsyncHelperRetry, context: ErrorHandlerContext) => Promise<IAppError<T> & CustomData>) => <T = unknown>(error: Error, asyncHelperRetry?: AsyncHelperRetry) => Promise<IAppError<T> & CustomData>;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { AppError } from '../../shared/app-error/AppError.js';
|
|
2
|
-
import { AppEvents } from '../../shared/event-bus/EventBus.js';
|
|
3
|
-
export const createErrorHandler = (handle) => {
|
|
4
|
-
return async (error, asyncHelperRetry) => {
|
|
5
|
-
const appError = new AppError(error);
|
|
6
|
-
if (handle) {
|
|
7
|
-
const handled = await handle(appError, asyncHelperRetry ?? { can: false }, { AppEvents });
|
|
8
|
-
if (handled?.appErrorConvert) {
|
|
9
|
-
return handled;
|
|
10
|
-
}
|
|
11
|
-
throw new Error('Method "handle" must return result of "toPlainObject" method in AppError');
|
|
12
|
-
}
|
|
13
|
-
return appError.toPlainObject();
|
|
14
|
-
};
|
|
15
|
-
};
|