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

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 (69) hide show
  1. package/README.md +178 -2
  2. package/dist/delivery/index.d.ts +2 -1
  3. package/dist/delivery/index.js +2 -1
  4. package/dist/delivery/injectable-dependencies/AsyncHelpers.d.ts +2 -4
  5. package/dist/delivery/injectable-dependencies/AsyncHelpers.js +96 -102
  6. package/dist/delivery/presenter/RegisterProvider.d.ts +9 -0
  7. package/dist/delivery/presenter/RegisterProvider.js +51 -0
  8. package/dist/delivery.d.ts +0 -1
  9. package/dist/delivery.js +0 -1
  10. package/dist/i18n/Internal.d.ts +13 -0
  11. package/dist/i18n/Internal.js +10 -0
  12. package/dist/i18n/Translations.svelte.d.ts +20 -0
  13. package/dist/i18n/Translations.svelte.js +254 -0
  14. package/dist/i18n/Types.d.ts +30 -0
  15. package/dist/i18n/Types.js +1 -0
  16. package/dist/i18n/index.d.ts +2 -0
  17. package/dist/i18n/index.js +1 -0
  18. package/dist/infra/datasource/BaseDatasource.d.ts +19 -6
  19. package/dist/infra/datasource/BaseDatasource.js +4 -4
  20. package/dist/infra/http-service/HttpServiceInstance.d.ts +26 -16
  21. package/dist/infra/http-service/HttpServiceInstance.js +21 -13
  22. package/dist/infra/index.d.ts +2 -2
  23. package/dist/infra/index.js +2 -2
  24. package/dist/infra/query/QueryBuilder.d.ts +6 -1
  25. package/dist/infra/query/QueryBuilder.js +14 -12
  26. package/dist/plugin/AzureNetPlugin.d.ts +1 -4
  27. package/dist/plugin/AzureNetPlugin.js +16 -64
  28. package/dist/plugin/index.d.ts +1 -1
  29. package/dist/server/Context/Runtime.d.ts +2 -0
  30. package/dist/server/Context/Runtime.js +18 -0
  31. package/dist/server/Context/index.d.ts +1 -0
  32. package/dist/server/Context/index.js +1 -0
  33. package/dist/shared/app/App.d.ts +44 -69
  34. package/dist/shared/app/App.js +91 -102
  35. package/dist/shared/app/index.d.ts +2 -1
  36. package/dist/shared/app/middleware/ClientMiddleware.d.ts +2 -2
  37. package/dist/shared/app/middleware/ClientMiddleware.js +0 -1
  38. package/dist/shared/app/middleware/ServerMiddleware.d.ts +1 -1
  39. package/dist/shared/app/middleware/ServerMiddleware.js +1 -1
  40. package/dist/shared/app-error/ErrorRuntime.d.ts +1 -1
  41. package/dist/shared/app-error/ErrorRuntime.js +4 -3
  42. package/dist/shared/boundary-provider/Provider.d.ts +1 -1
  43. package/dist/shared/boundary-provider/Provider.js +44 -29
  44. package/dist/shared/cookie/UniversalCookie.js +1 -1
  45. package/dist/shared/index.d.ts +1 -3
  46. package/dist/shared/index.js +1 -3
  47. package/dist/shared/logger/index.js +1 -1
  48. package/dist/shared/request-context/Internal.d.ts +16 -0
  49. package/dist/shared/request-context/Internal.js +24 -0
  50. package/dist/svelte/index.d.ts +1 -0
  51. package/dist/svelte/index.js +1 -0
  52. package/dist/svelte/query/Query.svelte.js +4 -2
  53. package/package.json +30 -21
  54. package/dist/external/edges/Dev.d.ts +0 -1
  55. package/dist/external/edges/Dev.js +0 -1
  56. package/dist/external/edges/Edges.d.ts +0 -1
  57. package/dist/external/edges/Edges.js +0 -1
  58. package/dist/external/edges/ServerContext.d.ts +0 -1
  59. package/dist/external/edges/ServerContext.js +0 -1
  60. package/dist/external/edges/_edges.d.ts +0 -1
  61. package/dist/external/edges/_edges.js +0 -1
  62. package/dist/external/i18n/index.d.ts +0 -1
  63. package/dist/external/i18n/index.js +0 -1
  64. package/dist/shared/event-bus/EventBus.d.ts +0 -12
  65. package/dist/shared/event-bus/EventBus.js +0 -3
  66. package/dist/shared/event-bus/index.d.ts +0 -1
  67. package/dist/shared/event-bus/index.js +0 -1
  68. /package/dist/{shared → svelte}/redirect/index.d.ts +0 -0
  69. /package/dist/{shared → svelte}/redirect/index.js +0 -0
package/README.md CHANGED
@@ -2,6 +2,106 @@
2
2
 
3
3
  #### [docs](https://svelte.kit.azure-net.ru)
4
4
 
5
+ ## Version 6 integration
6
+
7
+ Configure `AzureNetPlugin()` from `@azure-net/kit/plugin` alongside SvelteKit in Vite,
8
+ then export `{ register }` from `createApp(...)` in `src/program.ts`.
9
+ Call `register()` synchronously during root layout initialization. `useClient` may
10
+ be asynchronous: the navigation subscription is installed synchronously, and
11
+ middleware supplied after an `await` applies only from that point onward. Handle
12
+ the returned Promise if client initialization can fail. Client middleware itself
13
+ must remain synchronous.
14
+
15
+ The plugin provides virtual hooks only. It does not create or rewrite page/layout
16
+ modules. Manual `hooks.server`, `hooks.client` and `hooks` files are forbidden.
17
+ Initial Edges SSR state is hydrated once; later navigation is client-owned.
18
+
19
+ `program.ts` is universal: a static server-only import does not become safe merely
20
+ because it is used inside `useServer`. Use an explicit build-time browser guard
21
+ with dynamic server imports when needed, and retain SvelteKit's build checks.
22
+
23
+ ### Application structure
24
+
25
+ ```text
26
+ src/app/
27
+ Contexts/{Orders,Identity,SharedKernel}/
28
+ Domain/{Entities,Ports,Enums}
29
+ Infrastructure/Repositories
30
+ Application/UseCases
31
+ Presentation/{Admin,Public,Shared}/
32
+ Ui/
33
+ Scopes/
34
+ Shell/
35
+ Platform/
36
+ Foundation/{Datasource,Response,Schema,DI}
37
+ Bootstrap/{Routes,Localization}
38
+ ```
39
+
40
+ Without workspaces, `Ui`, `Scopes` and `Shell` sit directly under `Presentation`.
41
+ Central DI lives in `Platform/Foundation/DI/ApplicationProvider.ts`. Contexts may
42
+ import `SharedKernel`, but not each other. Presentation scopes may compose any
43
+ contexts. Workspaces may import `Shared`, but not each other.
44
+
45
+ Boundary providers cache their proxy, registration and services per SSR request,
46
+ not globally. Browser instances are cached until cleanup. Factories and `boot`
47
+ are synchronous. `await cleanupProvider(name)` explicitly disposes instantiated
48
+ services and resets the cache; request completion does not invoke it automatically.
49
+
50
+ Install the CLI separately with `npm i -D @azure-net/cli`. Its commit-tools command
51
+ configures Prettier without installing commit packages. `azure-net commit` commits
52
+ staged changes; `azure-net push` checks, stages, commits and pushes. `--no-check`
53
+ skips checks. Review `.gitignore` before staging.
54
+
55
+ ## Class Presenters And Async Helpers
56
+
57
+ Import `createAsyncResource` and `createAsyncAction` directly from
58
+ `@azure-net/kit/delivery`. `createAsyncHelpers()` has been removed. The error hook
59
+ configured by `createApp().useAzureNetKitError` is still resolved per execution;
60
+ there is no per-presenter parser or shared server error state. A custom error
61
+ payload can be typed as the third generic: `createAsyncAction<Response, Request, CustomError>()`.
62
+
63
+ ```ts
64
+ import { RegisterProvider, createAsyncResource } from '@azure-net/kit/delivery';
65
+ import { ApplicationProvider } from '#platform/Foundation/DI';
66
+ import type { OrdersUseCases } from '#contexts/Orders/Application/UseCases/OrdersUseCases';
67
+
68
+ export class OrdersPresenter {
69
+ constructor(private readonly useCases: OrdersUseCases) {}
70
+
71
+ collection = () => createAsyncResource(() => this.useCases.collection());
72
+ }
73
+
74
+ export const useOrdersPresenter = RegisterProvider(() => {
75
+ const { Orders } = ApplicationProvider();
76
+ return new OrdersPresenter(Orders);
77
+ }, 'scoped');
78
+ ```
79
+
80
+ Call `useOrdersPresenter()` during component initialization, not at module scope.
81
+ The registration itself is safe at module scope and does not resolve dependencies.
82
+ Arrow fields remain callable after destructuring. `RegisterProvider` returns the
83
+ actual class instance, without a proxy or automatic method binding.
84
+ Classes using Svelte runes such as `$state` must be placed in a `.svelte.ts` module
85
+ (or declared inside a Svelte component), not a regular `.ts` file.
86
+
87
+ | Lifecycle | Server | Browser |
88
+ | ------------------------------------------ | ----------------------------------------- | ----------------------------- |
89
+ | `scoped` (default) | One instance per registration per request | New instance per call |
90
+ | `transient` (`trancient` is also accepted) | New instance per call | New instance per call |
91
+ | `singleton` | One instance per registration per request | One instance per registration |
92
+
93
+ Server caching requires `AzureNetPlugin` request context and fails
94
+ outside it. There is no process-wide server singleton. Request caches have weak
95
+ keys and do not retain completed requests. Registrations do not require names,
96
+ Svelte context, hydration, or state serialization. Factory callbacks must be
97
+ synchronous; recursive construction is rejected.
98
+
99
+ This API does not own effects, subscriptions, timers, or `dispose()`. Keep
100
+ component-owned effects in component-lived instances; a cached browser singleton
101
+ must not rely on effects owned by the first component that requested it. SSR
102
+ isolation does not serialize state to the browser and cannot protect mutable
103
+ module-level state captured by user factories.
104
+
5
105
  **@azure-net/kit** is a universal toolkit and library collection, developed as part of the **Azure-net** ecosystem. It is designed to speed up modern application development, reduce boilerplate code, and maintain a unified project architecture.
6
106
 
7
107
  ## ✨ What is it?
@@ -10,8 +110,8 @@
10
110
 
11
111
  ## 🚀 What's included?
12
112
 
13
- - **Built-in store** — flexible and SSR-friendly state management powered by [@azure-net/edges](https://github.com/Pixel1917/edge-s).
14
- - **Localization and translation** — ready-to-use i18n solution ([@azure-net/edges-translations](https://github.com/Pixel1917/edges-svelte-translations)) for multilingual applications.
113
+ - **Reactive state classes** — request-isolated server instances and browser singletons via `RegisterProvider`.
114
+ - **Localization and translation**: built-in rune-based i18n with request-scoped SSR instances. No edges or external translations dependency.
15
115
  - **Extensive utilities** — for working with text, objects, dates, and common tasks.
16
116
  - **Data validation** — handy rules and validators.
17
117
  - **Reusable base abstractions** — `Repositories`, `Services`, `Providers`, and `Datasources` for quick setup and reuse.
@@ -40,3 +140,79 @@ In this guide, you will find:
40
140
  ## 🚀 Get started
41
141
 
42
142
  Ready to dive in? Check out the [docs](https://svelte.kit.azure-net.ru) and start building your app faster and more reliably with **Azure-net**.
143
+
144
+ ## Initial state and `useBoot`
145
+
146
+ `AzureNetPlugin()` owns a kit-local AsyncLocalStorage scope. It does not depend on
147
+ edges, serialize stores, inject response scripts or create virtual route modules.
148
+ There are no edges store/presenter exports or devtools exports in this version.
149
+ `RequestContext.current()` exposes only `event` and `state`, is server-only, and
150
+ throws outside an active request. Internal DI/error/lifecycle caches are private.
151
+
152
+ Declare transferable state in `src/app.d.ts` (prefer optional fields for CSR):
153
+
154
+ ```ts
155
+ import type { IUser } from '#contexts/Identity/Domain';
156
+ declare global {
157
+ namespace App {
158
+ interface RequestContextState {
159
+ currentUser?: IUser | null;
160
+ }
161
+ }
162
+ }
163
+ export {};
164
+ ```
165
+
166
+ ```ts
167
+ import { createApp } from '@azure-net/kit';
168
+ import { RequestContext } from '@azure-net/kit/server-context';
169
+
170
+ export const { register } = createApp((app) =>
171
+ app
172
+ .useServer(async ({ event, resolve, useMiddlewares }) => {
173
+ await useMiddlewares([ServerAuth]);
174
+ await TranslationManager().preloadTranslation();
175
+ return resolve(event);
176
+ })
177
+ .useBoot(({ state }) => {
178
+ useCurrentUser().setUser(state.currentUser ?? null);
179
+ TranslationManager().syncFromState(state);
180
+ })
181
+ );
182
+ ```
183
+
184
+ In the root layout call `register()` before resolving presenters or state classes.
185
+ `useBoot` is synchronous and runs once per server request render and once per
186
+ browser app initialization, before client lifecycle callbacks. Await all server
187
+ state preparation before `resolve`. Do not mutate the transfer snapshot during
188
+ rendering. Client navigations and repeated register calls do not rehydrate state.
189
+ `useClientInit` runs earlier and must not depend on this snapshot. CSR without an
190
+ SSR snapshot receives `{}`; initialize defaults and fetch missing data explicitly.
191
+ Only publish safe DTOs, never tokens or the whole request/locals. Personalized HTML
192
+ must not be publicly cached. Classes, functions and services are not serialized.
193
+
194
+ Svelte currently requires async mode for `hydratable`:
195
+
196
+ ```ts
197
+ sveltekit({ compilerOptions: { experimental: { async: true } } });
198
+ ```
199
+
200
+ Keep the application's CSP correctly configured; Svelte manages the transfer
201
+ script and serialization. No custom HTML parser is used by the kit.
202
+
203
+ ## DI naming
204
+
205
+ `createBoundaryProvider` is replaced by `CreateServiceContainer` (no compatibility alias):
206
+
207
+ ```ts
208
+ const ApplicationProvider = CreateDiContainer('ApplicationProvider', {
209
+ register: () => ({ Users: () => new UsersUseCases(repository) })
210
+ });
211
+ const { Users } = ApplicationProvider();
212
+ ```
213
+
214
+ The accessor remains lazy, synchronous and request-scoped on SSR. `RegisterProvider`
215
+ registers an individual class factory; `singleton` means one browser instance but
216
+ one instance per request on the server, never a server process singleton.
217
+
218
+ Built-in i18n: see [I18N.md](./I18N.md). preloadTranslation() fills request state automatically; syncFromState(state) restores it synchronously in useBoot. No separate translation package, writable/derived stores or edges adapter is required.
@@ -1,3 +1,4 @@
1
- export { createAsyncHelpers, type AsyncHelperRetry, type AsyncResourceSettings, type AsyncActionResponse } from './injectable-dependencies/index.js';
1
+ export { createAsyncAction, createAsyncResource, type AsyncActionSettings, type AsyncHelperRetry, type AsyncResourceSettings, type AsyncActionResponse } from './injectable-dependencies/index.js';
2
+ export { RegisterProvider, type ProviderLifecycle } from './presenter/RegisterProvider.js';
2
3
  export { createSchemaFactory, schema, type Schema, type RequestErrors, type ISchemaError, type ValidationResult, type ValidationRuleResult, type ValidationParams, type ValidationMessage, type ValidationErrorsMap } from './schema/index.js';
3
4
  export { createRules, validationMessagesRu, validationMessagesI18n, validationMessagesEn, type ValidationRuleParams, type BaseValidationMessages } from './schema/rules/index.js';
@@ -1,3 +1,4 @@
1
- export { createAsyncHelpers } from './injectable-dependencies/index.js';
1
+ export { createAsyncAction, createAsyncResource } from './injectable-dependencies/index.js';
2
+ export { RegisterProvider } from './presenter/RegisterProvider.js';
2
3
  export { createSchemaFactory, schema } from './schema/index.js';
3
4
  export { createRules, validationMessagesRu, validationMessagesI18n, validationMessagesEn } from './schema/rules/index.js';
@@ -18,7 +18,5 @@ export interface AsyncActionSettings<Res = never, Req = never, ErrorResult = App
18
18
  export interface AsyncResourceSettings<Res = never, Req = never, ErrorResult = AppError<Error>> extends AsyncActionSettings<Res, Req, ErrorResult> {
19
19
  reject?: boolean;
20
20
  }
21
- export declare const createAsyncHelpers: <ErrorResult extends object>() => {
22
- createAsyncAction: <Res = never, Req = never>(action: Action<Res>, args?: AsyncActionSettings<Res, Req, ErrorResult>) => Promise<AsyncActionResponse<Res, Req, ErrorResult>>;
23
- createAsyncResource: <Res = never, Req_1 = never>(action: Action<Res>, args?: AsyncResourceSettings<Res, Req_1, ErrorResult>) => Promise<Res>;
24
- };
21
+ export declare const createAsyncAction: <Res = never, Req = never, ErrorResult extends object = Record<never, never>>(action: Action<Res>, args?: AsyncActionSettings<Res, Req, ErrorResult>) => Promise<AsyncActionResponse<Res, Req, ErrorResult>>;
22
+ export declare const createAsyncResource: <Res = never, Req = never, ErrorResult extends object = Record<never, never>>(action: Action<Res>, args?: AsyncResourceSettings<Res, Req, ErrorResult>) => Promise<Res>;
@@ -1,115 +1,109 @@
1
1
  import { AsyncHelperError } from '../../shared/app-error/AppError.js';
2
2
  import { resolveAzureNetKitError } from '../../shared/app-error/ErrorRuntime.js';
3
- export const createAsyncHelpers = () => {
4
- const normalizeError = (err) => (err instanceof Error ? err : new Error(String(err)));
5
- const prepareErrors = async (error, retry) => {
6
- let retryResult = undefined;
7
- const retryFunc = async () => {
8
- if (retry) {
9
- return await retry()
10
- .then((res) => {
11
- retryResult = res;
12
- return undefined;
13
- })
14
- .catch((err) => normalizeError(err));
15
- }
16
- };
17
- const parsedError = await resolveAzureNetKitError(normalizeError(error), {
18
- can: !!retry,
19
- call: retry ? () => retryFunc() : undefined
20
- });
21
- return { error: parsedError, retryResult };
22
- };
23
- const beforeSendResolver = async (settings) => {
24
- if (!settings?.beforeSend)
25
- return undefined;
26
- let abortReason;
27
- let aborted = false;
28
- await new Promise((resolve) => {
29
- let settled = false;
30
- const beforeSend = settings.beforeSend;
31
- const guardTimer = setTimeout(() => {
32
- settle(true);
33
- }, 30000);
34
- const settle = (isAbort, reason) => {
35
- if (settled)
36
- return;
37
- settled = true;
38
- clearTimeout(guardTimer);
39
- aborted = isAbort;
40
- abortReason = reason;
41
- resolve();
42
- };
43
- const next = () => settle(false);
44
- const abort = (reason) => settle(true, reason);
45
- try {
46
- const maybePromise = beforeSend({ next, abort });
47
- if (maybePromise && typeof maybePromise.then === 'function') {
48
- maybePromise.then(() => settle(false), (err) => settle(true, normalizeError(err)));
49
- return;
50
- }
51
- settle(false);
52
- }
53
- catch (err) {
54
- settle(true, normalizeError(err));
55
- }
56
- });
57
- if (!aborted)
58
- return undefined;
59
- const { error } = await prepareErrors(abortReason ?? new AsyncHelperError('Aborted in beforeSend'));
60
- return {
61
- success: false,
62
- error,
63
- response: undefined
64
- };
3
+ const normalizeError = (err) => (err instanceof Error ? err : new Error(String(err)));
4
+ const prepareErrors = async (error, retry) => {
5
+ let retryResult = undefined;
6
+ const retryFunc = async () => {
7
+ if (retry) {
8
+ return await retry()
9
+ .then((res) => {
10
+ retryResult = res;
11
+ return undefined;
12
+ })
13
+ .catch((err) => normalizeError(err));
14
+ }
65
15
  };
66
- const createAsyncAction = async (action, args) => {
67
- const beforeSendResult = await beforeSendResolver(args);
68
- if (beforeSendResult)
69
- return beforeSendResult;
70
- const executeAction = async () => {
71
- const response = await Promise.resolve(action());
72
- return { response, success: true };
73
- };
74
- const handleFailure = async (err, retry) => {
75
- const { error, retryResult } = await prepareErrors(normalizeError(err), retry);
76
- if (retryResult) {
77
- return completeSuccess(retryResult);
78
- }
79
- const result = { error, response: args?.fallbackResponse, success: false };
80
- try {
81
- await args?.onError?.(result);
82
- }
83
- catch (onErrorException) {
84
- throw await resolveAzureNetKitError(new AsyncHelperError('onError caught exception', { cause: normalizeError(onErrorException) }));
85
- }
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
- }
16
+ const parsedError = await resolveAzureNetKitError(normalizeError(error), {
17
+ can: !!retry,
18
+ call: retry ? () => retryFunc() : undefined
19
+ });
20
+ return { error: parsedError, retryResult };
21
+ };
22
+ const beforeSendResolver = async (settings) => {
23
+ if (!settings?.beforeSend)
24
+ return undefined;
25
+ let abortReason;
26
+ let aborted = false;
27
+ await new Promise((resolve) => {
28
+ let settled = false;
29
+ const beforeSend = settings.beforeSend;
30
+ const guardTimer = setTimeout(() => {
31
+ settle(true);
32
+ }, 30000);
33
+ const settle = (isAbort, reason) => {
34
+ if (settled)
35
+ return;
36
+ settled = true;
37
+ clearTimeout(guardTimer);
38
+ aborted = isAbort;
39
+ abortReason = reason;
40
+ resolve();
96
41
  };
42
+ const next = () => settle(false);
43
+ const abort = (reason) => settle(true, reason);
97
44
  try {
98
- return completeSuccess(await executeAction());
45
+ const maybePromise = beforeSend({ next, abort });
46
+ if (maybePromise && typeof maybePromise.then === 'function') {
47
+ maybePromise.then(() => settle(false), (err) => settle(true, normalizeError(err)));
48
+ return;
49
+ }
50
+ settle(false);
99
51
  }
100
52
  catch (err) {
101
- return handleFailure(err, executeAction);
53
+ settle(true, normalizeError(err));
102
54
  }
55
+ });
56
+ if (!aborted)
57
+ return undefined;
58
+ const { error } = await prepareErrors(abortReason ?? new AsyncHelperError('Aborted in beforeSend'));
59
+ return {
60
+ success: false,
61
+ error,
62
+ response: undefined
63
+ };
64
+ };
65
+ export const createAsyncAction = async (action, args) => {
66
+ const beforeSendResult = await beforeSendResolver(args);
67
+ if (beforeSendResult)
68
+ return beforeSendResult;
69
+ const executeAction = async () => {
70
+ const response = await Promise.resolve(action());
71
+ return { response, success: true };
103
72
  };
104
- const createAsyncResource = async (action, args) => {
105
- const result = await createAsyncAction(action, args);
106
- if (!result.success && args?.reject) {
107
- throw result.error;
73
+ const handleFailure = async (err, retry) => {
74
+ const { error, retryResult } = await prepareErrors(normalizeError(err), retry);
75
+ if (retryResult) {
76
+ return completeSuccess(retryResult);
77
+ }
78
+ const result = { error, response: args?.fallbackResponse, success: false };
79
+ try {
80
+ await args?.onError?.(result);
81
+ }
82
+ catch (onErrorException) {
83
+ throw await resolveAzureNetKitError(new AsyncHelperError('onError caught exception', { cause: normalizeError(onErrorException) }));
108
84
  }
109
- return result.response;
85
+ return result;
110
86
  };
111
- return {
112
- createAsyncAction,
113
- createAsyncResource
87
+ const completeSuccess = async (result) => {
88
+ try {
89
+ await args?.onSuccess?.(result);
90
+ return result;
91
+ }
92
+ catch (err) {
93
+ return handleFailure(err);
94
+ }
114
95
  };
96
+ try {
97
+ return completeSuccess(await executeAction());
98
+ }
99
+ catch (err) {
100
+ return handleFailure(err, executeAction);
101
+ }
102
+ };
103
+ export const createAsyncResource = async (action, args) => {
104
+ const result = await createAsyncAction(action, args);
105
+ if (!result.success && args?.reject) {
106
+ throw result.error;
107
+ }
108
+ return result.response;
115
109
  };
@@ -0,0 +1,9 @@
1
+ export type ProviderLifecycle = 'scoped' | 'transient' | 'singleton';
2
+ /**
3
+ * Registration is safe at module scope; the factory is called only by the returned accessor.
4
+ * scoped: per request on the server, per call in the browser.
5
+ * singleton: per request on the server, per registration in the browser.
6
+ * transient: a new instance on every call.
7
+ * No hydration, component context, effects or disposal are managed by this function.
8
+ */
9
+ export declare function RegisterProvider<T extends object>(factory: () => T extends PromiseLike<unknown> ? never : T, lifecycle?: ProviderLifecycle): () => T;
@@ -0,0 +1,51 @@
1
+ import { RequestContext } from '../../shared/request-context/Internal.js';
2
+ import { BROWSER } from '../../external/tools/index.js';
3
+ /**
4
+ * Registration is safe at module scope; the factory is called only by the returned accessor.
5
+ * scoped: per request on the server, per call in the browser.
6
+ * singleton: per request on the server, per registration in the browser.
7
+ * transient: a new instance on every call.
8
+ * No hydration, component context, effects or disposal are managed by this function.
9
+ */
10
+ export function RegisterProvider(factory, lifecycle = 'scoped') {
11
+ if (!['scoped', 'transient', 'singleton'].includes(lifecycle)) {
12
+ throw new TypeError(`[RegisterProvider] Unknown lifecycle: ${lifecycle}`);
13
+ }
14
+ const requests = new WeakMap();
15
+ let clientInstance;
16
+ let constructing = false;
17
+ const create = () => {
18
+ if (constructing)
19
+ throw new Error('[RegisterProvider] Circular presenter dependency.');
20
+ constructing = true;
21
+ try {
22
+ const instance = factory();
23
+ if (!instance || (typeof instance !== 'object' && typeof instance !== 'function')) {
24
+ throw new TypeError('[RegisterProvider] Factory must return an instance.');
25
+ }
26
+ if ('then' in instance && typeof instance.then === 'function') {
27
+ // Consume a rejected async factory without allowing an unhandled rejection.
28
+ void Promise.resolve(instance).catch(() => undefined);
29
+ throw new TypeError('[RegisterProvider] Factory must be synchronous.');
30
+ }
31
+ return instance;
32
+ }
33
+ finally {
34
+ constructing = false;
35
+ }
36
+ };
37
+ return () => {
38
+ if (lifecycle === 'transient')
39
+ return create();
40
+ if (BROWSER)
41
+ return lifecycle === 'singleton' ? (clientInstance ??= create()) : create();
42
+ // Weak keys do not retain finished requests or their presenter graphs.
43
+ const context = RequestContext.current();
44
+ let instance = requests.get(context);
45
+ if (!instance) {
46
+ instance = create();
47
+ requests.set(context, instance);
48
+ }
49
+ return instance;
50
+ };
51
+ }
@@ -1,2 +1 @@
1
- export * from './external/edges/Edges.js';
2
1
  export * from './delivery/index.js';
package/dist/delivery.js CHANGED
@@ -1,2 +1 @@
1
- export * from './external/edges/Edges.js';
2
1
  export * from './delivery/index.js';
@@ -0,0 +1,13 @@
1
+ export interface TranslationLifecycle {
2
+ preloadTranslation(): Promise<void>;
3
+ initializeClient(): Promise<void>;
4
+ syncFromState(state: App.RequestContextState): void;
5
+ transformHtml(html: string): string;
6
+ }
7
+ declare const translationManager: unique symbol;
8
+ export type TranslationManagerFactory = (() => object) & {
9
+ readonly [translationManager]: true;
10
+ };
11
+ export declare const bindTranslationLifecycle: (manager: object, lifecycle: TranslationLifecycle) => void;
12
+ export declare const getTranslationLifecycle: (manager: object) => TranslationLifecycle;
13
+ export {};
@@ -0,0 +1,10 @@
1
+ const lifecycles = new WeakMap();
2
+ export const bindTranslationLifecycle = (manager, lifecycle) => {
3
+ lifecycles.set(manager, lifecycle);
4
+ };
5
+ export const getTranslationLifecycle = (manager) => {
6
+ const lifecycle = lifecycles.get(manager);
7
+ if (!lifecycle)
8
+ throw new Error('[AzureNetKit:i18n] Expected a manager returned by createTranslations().');
9
+ return lifecycle;
10
+ };
@@ -0,0 +1,20 @@
1
+ import { type TranslationManagerFactory } from './Internal.js';
2
+ import type { Path, TranslationCookieOptions, MessageLoader, TranslationVariables } from './Types.js';
3
+ export declare const createTranslations: <const TMessages extends Record<string, MessageLoader>, const TInitLocale extends Extract<keyof TMessages, string>>(params: {
4
+ messages: TMessages;
5
+ initLang: TInitLocale;
6
+ cookieName?: string;
7
+ cookieOptions?: TranslationCookieOptions;
8
+ initLangFromAcceptLanguage?: boolean;
9
+ prefix?: string;
10
+ }) => (() => {
11
+ switchLocale: (requestedLocale: Extract<keyof TMessages, string>) => Promise<void>;
12
+ applyHtmlLocaleAttr: (html: string) => string;
13
+ subscribeLocaleChangeEvent: (listener: (locale: Extract<keyof TMessages, string>) => void) => (() => void);
14
+ t: (translation?: string | {
15
+ key: string | Path<Awaited<ReturnType<TMessages[TInitLocale]>>, "", []>;
16
+ vars?: TranslationVariables;
17
+ } | Path<Awaited<ReturnType<TMessages[TInitLocale]>>, "", []>, vars?: TranslationVariables) => string;
18
+ readonly locale: Extract<keyof TMessages, string>;
19
+ locales: Readonly<Record<Extract<keyof TMessages, string>, Extract<keyof TMessages, string>>>;
20
+ }) & TranslationManagerFactory;