@azure-net/kit 5.5.0 → 6.0.0-next.1

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 (35) 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 +29 -45
  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 +7 -7
  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/http-service/HttpServiceInstance.js +8 -4
  13. package/dist/infra/response/BaseResponse.d.ts +1 -1
  14. package/dist/infra/response/BaseResponse.js +1 -1
  15. package/dist/plugin/AzureNetPlugin.js +1 -1
  16. package/dist/shared/app/App.d.ts +17 -1
  17. package/dist/shared/app/App.js +79 -34
  18. package/dist/shared/app/index.d.ts +1 -1
  19. package/dist/shared/app/middleware/ClientMiddleware.d.ts +3 -3
  20. package/dist/shared/app/middleware/ClientMiddleware.js +4 -5
  21. package/dist/shared/app-error/AppError.d.ts +2 -0
  22. package/dist/shared/app-error/AppError.js +2 -1
  23. package/dist/shared/app-error/ErrorRuntime.d.ts +11 -0
  24. package/dist/shared/app-error/ErrorRuntime.js +57 -0
  25. package/dist/shared/app-error/index.d.ts +1 -0
  26. package/dist/shared/app-error/index.js +1 -0
  27. package/dist/shared/boundary-provider/Provider.d.ts +1 -1
  28. package/dist/shared/boundary-provider/Provider.js +35 -14
  29. package/dist/svelte/active-form/ActiveForm.svelte.d.ts +1 -1
  30. package/dist/svelte/active-form/ActiveForm.svelte.js +14 -4
  31. package/dist/svelte/async-signal/AsyncSignal.svelte.d.ts +2 -1
  32. package/dist/svelte/async-signal/AsyncSignal.svelte.js +48 -14
  33. package/package.json +1 -1
  34. package/dist/delivery/injectable-dependencies/ErrorHandler.d.ts +0 -7
  35. package/dist/delivery/injectable-dependencies/ErrorHandler.js +0 -15
@@ -1,3 +1,3 @@
1
- export { createAsyncHelpers, createErrorHandler, type AsyncHelperRetry, type AsyncResourceSettings, type AsyncActionResponse } from './injectable-dependencies/index.js';
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';
@@ -1,3 +1,3 @@
1
- export { createAsyncHelpers, createErrorHandler } from './injectable-dependencies/index.js';
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 { createErrorHandler } from './ErrorHandler.js';
2
- import {} from '../../shared/app-error/AppError.js';
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 errorParser(normalizeError(error), { can: !!retry, call: retry ? () => retryFunc() : undefined });
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) => {
@@ -91,28 +67,38 @@ export const createAsyncHelpers = () => {
91
67
  const beforeSendResult = await beforeSendResolver(args);
92
68
  if (beforeSendResult)
93
69
  return beforeSendResult;
94
- const req = async () => {
70
+ const executeAction = async () => {
95
71
  const response = await Promise.resolve(action());
96
- const result = { response, success: true };
97
- await args?.onSuccess?.(result);
98
- return result;
72
+ return { response, success: true };
99
73
  };
100
- try {
101
- return await req();
102
- }
103
- catch (err) {
104
- const { error, retryResult } = await prepareErrors(normalizeError(err), async () => await req());
74
+ const handleFailure = async (err, retry) => {
75
+ const { error, retryResult } = await prepareErrors(normalizeError(err), retry);
105
76
  if (retryResult) {
106
- return retryResult;
77
+ return completeSuccess(retryResult);
107
78
  }
108
79
  const result = { error, response: args?.fallbackResponse, success: false };
109
80
  try {
110
81
  await args?.onError?.(result);
111
82
  }
112
- catch (err) {
113
- throw await errorParser(new AsyncHelperError('onError caught exception', { cause: normalizeError(err) }));
83
+ catch (onErrorException) {
84
+ throw await resolveAzureNetKitError(new AsyncHelperError('onError caught exception', { cause: normalizeError(onErrorException) }));
114
85
  }
115
86
  return result;
87
+ };
88
+ const completeSuccess = async (result) => {
89
+ try {
90
+ await args?.onSuccess?.(result);
91
+ return result;
92
+ }
93
+ catch (err) {
94
+ return handleFailure(err);
95
+ }
96
+ };
97
+ try {
98
+ return completeSuccess(await executeAction());
99
+ }
100
+ catch (err) {
101
+ return handleFailure(err, executeAction);
116
102
  }
117
103
  };
118
104
  const createAsyncResource = async (action, args) => {
@@ -124,8 +110,6 @@ export const createAsyncHelpers = () => {
124
110
  };
125
111
  return {
126
112
  createAsyncAction,
127
- createAsyncResource,
128
- errorParser,
129
- useHandler
113
+ createAsyncResource
130
114
  };
131
115
  };
@@ -1,2 +1 @@
1
1
  export * from './AsyncHelpers.js';
2
- export * from './ErrorHandler.js';
@@ -1,2 +1 @@
1
1
  export * from './AsyncHelpers.js';
2
- export * from './ErrorHandler.js';
@@ -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
- json(params?: TransformationParams<SchemaData>): TransformResult;
51
- formData(params?: TransformationParams<SchemaData>): FormData;
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
- json(): TransformResult;
56
- formData(): FormData;
55
+ toJson(): TransformResult;
56
+ toFormData(): FormData;
57
57
  };
58
58
  }
59
59
  export type Schema<SchemaData, TransformResult, CustomMethods> = CustomMethods & {
@@ -76,7 +76,7 @@ class SchemaBuilderImpl {
76
76
  const _preparedData = prepare(data);
77
77
  let _errors = {};
78
78
  let _isValid = true;
79
- if (typeof _preparedData !== 'object') {
79
+ if (_preparedData === null || typeof _preparedData !== 'object') {
80
80
  throw new AzureNetKitInternalError('[Schema] Data in "from" method can be only valid object or formData.');
81
81
  }
82
82
  const validated = (params) => {
@@ -109,18 +109,18 @@ class SchemaBuilderImpl {
109
109
  return {
110
110
  valid: _isValid,
111
111
  errors: _errors,
112
- json: () => json({ validate: false }),
113
- formData: () => formData({ validate: false })
112
+ toJson: () => toJson({ validate: false }),
113
+ toFormData: () => toFormData({ validate: false })
114
114
  };
115
115
  };
116
- const json = (params = {}) => {
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 formData = (params = {}) => {
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
- json,
132
- formData,
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) || Number.isNaN(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) || String(val)[0] === '.') {
175
+ if (!Number.isFinite(numVal) || normalizedValue.startsWith('.')) {
168
176
  return message.base();
169
177
  }
170
178
  if (typeof maxDigitsAfterDot === 'number') {
171
- const digitsAfterDot = val.toString().split('.')[1]?.length ?? 0;
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';
@@ -162,10 +162,14 @@ const parseBodyByFormat = async (response, format) => {
162
162
  return (await response.arrayBuffer());
163
163
  case 'body':
164
164
  return response.body;
165
- case 'json':
166
- return (await response.json());
167
- default:
168
- return (await response.json());
165
+ case 'json': {
166
+ const text = await response.text();
167
+ return (text.trim() ? JSON.parse(text) : undefined);
168
+ }
169
+ default: {
170
+ const text = await response.text();
171
+ return (text.trim() ? JSON.parse(text) : undefined);
172
+ }
169
173
  }
170
174
  };
171
175
  const withTimeout = (signal, timeout) => {
@@ -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
- extract<TPath extends DeepKeys<TData>>(path: TPath): Omit<this, keyof ResponseBuilder<unknown, unknown, unknown>> & ResponseBuilder<DeepValue<TData, TPath>, TMeta, TWrapper>;
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(): {
@@ -33,7 +33,7 @@ export class ResponseBuilder {
33
33
  };
34
34
  return newResponse;
35
35
  }
36
- extract(path) {
36
+ extractKey(path) {
37
37
  const keys = path.split('.');
38
38
  let result = this.state.data;
39
39
  for (const key of keys) {
@@ -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
  })
@@ -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', {
@@ -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(async (navigation) => {
176
- await executeClientMiddlewares(internalMiddlewares, navigation);
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
- return callbacks.useServerError?.({
194
- Container,
195
- requestContext: getServerRequestContext(),
196
- error,
197
- event,
198
- status,
199
- message,
200
- useLogger
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
- const flags = getLifecycleFlags(appKey, requestContext);
238
- if (!flags.server) {
239
- flags.server = true;
240
- const universalResult = callbacks.use?.({
241
- Container,
242
- isClient: false,
243
- isServer: true,
244
- requestContext,
245
- event
246
- });
247
- if (universalResult && typeof universalResult.then === 'function') {
248
- await universalResult;
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
- const serverResult = await callbacks.useServer?.({
251
- Container,
252
- requestContext,
253
- event,
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) => void;
7
+ next: (location?: string | URL, status?: RedirectStatus) => undefined;
8
8
  ensureRoute: EnsureRoute;
9
- }) => Promise<void> | void;
10
- export declare const executeClientMiddlewares: (middlewares: IClientMiddleware[], navigation?: BeforeNavigate) => Promise<void>;
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 = async (middlewares, navigation) => {
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
- const result = middleware({
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
- await goto(redirectTo);
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
- import { AsyncHelperError } from '../../delivery/injectable-dependencies/AsyncHelpers.js';
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
+ };
@@ -1 +1,2 @@
1
1
  export * from './AppError.js';
2
+ export * from './ErrorRuntime.js';
@@ -1 +1,2 @@
1
1
  export * from './AppError.js';
2
+ export * from './ErrorRuntime.js';
@@ -13,7 +13,7 @@ type ProviderFactory<T extends ServiceMap, D extends Record<string, ProviderWith
13
13
  }) => T;
14
14
  export interface ProviderSettings<T extends ServiceMap, D extends Record<string, ProviderWithType<ServiceMap>>> {
15
15
  dependsOn?: D;
16
- boot?: (services: ResolvedServices<T>) => void | Promise<void>;
16
+ boot?: (services: ResolvedServices<T>) => undefined;
17
17
  register: ProviderFactory<T, D>;
18
18
  }
19
19
  export declare const createBoundaryProvider: <T extends ServiceMap, D extends Record<string, ProviderWithType<ServiceMap>>>(name: string, settings: ProviderSettings<T, D>) => ProviderWithType<T>;
@@ -14,17 +14,17 @@ const getProviderCache = (providerName) => {
14
14
  }
15
15
  else {
16
16
  const context = RequestContext.current();
17
- if (!context.data.providers) {
18
- context.data.providers = new Map();
17
+ if (!context.data.azureNetKitBoundaryProviders) {
18
+ context.data.azureNetKitBoundaryProviders = new Map();
19
19
  }
20
- const providers = context.data.providers;
20
+ const providers = context.data.azureNetKitBoundaryProviders;
21
21
  if (!providers.has(providerName)) {
22
22
  providers.set(providerName, new Map());
23
23
  }
24
- if (!context.data.providersToCleanup) {
25
- context.data.providersToCleanup = new Set();
24
+ if (!context.data.azureNetKitBoundaryProvidersToCleanup) {
25
+ context.data.azureNetKitBoundaryProvidersToCleanup = new Set();
26
26
  }
27
- context.data.providersToCleanup.add(providerName);
27
+ context.data.azureNetKitBoundaryProvidersToCleanup.add(providerName);
28
28
  return providers.get(providerName);
29
29
  }
30
30
  };
@@ -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,29 +130,44 @@ 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) {
141
161
  providerProxyCache.set(name, providerProxy);
142
162
  }
143
163
  if (boot && !getBootFlag(name)) {
144
- setBootFlag(name, true);
145
164
  getFactories();
146
165
  const bootResult = boot(providerProxy);
147
- if (bootResult instanceof Promise) {
148
- bootResult.catch((err) => console.error(`Error in boot for provider '${name}':`, err));
166
+ if (bootResult && typeof bootResult.then === 'function') {
167
+ void Promise.resolve(bootResult).catch(() => undefined);
168
+ throw new AzureNetKitInternalError(`[BoundaryProvider] Boot for provider '${name}' must be synchronous.`);
149
169
  }
170
+ setBootFlag(name, true);
150
171
  }
151
172
  return providerProxy;
152
173
  };
@@ -179,7 +200,7 @@ export async function cleanupProvider(name) {
179
200
  }
180
201
  else {
181
202
  const context = RequestContext.current();
182
- const providers = context.data.providers;
203
+ const providers = context.data.azureNetKitBoundaryProviders;
183
204
  if (providers?.has(name)) {
184
205
  const cache = providers.get(name);
185
206
  providers.delete(name);
@@ -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;
@@ -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 ?? Promise.resolve(data);
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 data() {
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 ?? Promise.resolve(data));
183
- if (currentPromise)
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-net/kit",
3
- "version": "5.5.0",
3
+ "version": "6.0.0-next.1",
4
4
  "license": "MIT",
5
5
  "author": "Pixel1917",
6
6
  "description": "Universal toolkit and library collection, developed as part of the Azure-net ecosystem",
@@ -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
- };