@endge/core 1.2.13 → 2.0.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.
- package/dist/core.cjs +323 -295
- package/dist/core.js +30689 -26344
- package/dist/domain/entities/reflect/RAuthProfile.d.ts +3 -3
- package/dist/domain/entities/runtime/ComponentSFCEventBoundary.d.ts +2 -0
- package/dist/domain/entities/runtime/hosts/ComponentSFCRuntimeHost.d.ts +1 -1
- package/dist/domain/types/auth/auth-profile.types.d.ts +93 -28
- package/dist/domain/types/auth/auth-runtime.types.d.ts +0 -23
- package/dist/domain/types/component/sfc/ast.types.d.ts +2 -0
- package/dist/domain/types/component/sfc/intrinsic-events.types.d.ts +6 -0
- package/dist/domain/types/component/sfc/ir.types.d.ts +96 -1
- package/dist/domain/types/component/sfc/visual-projection.types.d.ts +130 -5
- package/dist/domain/types/configuration/configuration.type.d.ts +13 -7
- package/dist/domain/types/document/domain-export.type.d.ts +1 -0
- package/dist/domain/types/document/query.types.d.ts +1 -1
- package/dist/domain/types/document/workspace.types.d.ts +1 -3
- package/dist/domain/types/i18n.types.d.ts +2 -0
- package/dist/domain/types/kernel/bootstrap.types.d.ts +1 -1
- package/dist/domain/types/kernel/events.types.d.ts +0 -3
- package/dist/domain/types/runtime/action.types.d.ts +1 -0
- package/dist/domain/types/runtime/context-persistence.types.d.ts +1 -0
- package/dist/domain/types/source/source-engine.types.d.ts +26 -1
- package/dist/domain/types/source/stream-source.types.d.ts +2 -1
- package/dist/main.d.ts +4 -0
- package/dist/model/config/kernel.config.d.ts +0 -1
- package/dist/model/config/sfc-editing.config.d.ts +3 -0
- package/dist/model/config/ui-composition.config.d.ts +10 -10
- package/dist/model/kernel/endge.d.ts +0 -5
- package/dist/model/modules/context/endge-vars.d.ts +4 -2
- package/dist/model/modules/context/endge-workspace.d.ts +1 -3
- package/dist/model/modules/context/persistence/RuntimeStateController.d.ts +7 -4
- package/dist/model/modules/domain/endge-domain.d.ts +6 -0
- package/dist/model/modules/program/endge-source.d.ts +3 -1
- package/dist/model/modules/runtime/execution/computation/ComputationResourceRegistry.d.ts +2 -0
- package/dist/model/modules/security/auth/AuthInteractionRequiredError.d.ts +6 -0
- package/dist/model/modules/security/auth/AuthProfileRegistry.d.ts +4 -4
- package/dist/model/modules/security/auth/AuthRequestResolver.d.ts +6 -1
- package/dist/model/modules/security/auth/AuthSessionManager.d.ts +2 -6
- package/dist/model/modules/security/auth/adapters/BasicAuthAdapter.d.ts +10 -0
- package/dist/model/modules/security/auth/adapters/BearerAuthAdapter.d.ts +1 -1
- package/dist/model/modules/security/auth/adapters/OAuth2ClientCredentialsAuthAdapter.d.ts +8 -0
- package/dist/model/modules/security/auth/adapters/OAuth2PasswordAuthAdapter.d.ts +11 -0
- package/dist/model/modules/security/auth/adapters/OidcAuthAdapter.d.ts +8 -0
- package/dist/model/modules/security/endge-auth.d.ts +12 -2
- package/dist/model/services/auth/OidcBrowserSession_Service.d.ts +26 -0
- package/dist/model/services/compiler/component-sfc/component-sfc-compile.d.ts +3 -0
- package/dist/model/services/compiler/component-sfc/component-sfc-interactions.d.ts +12 -0
- package/dist/model/services/compiler/component-sfc/component-sfc-template.d.ts +3 -0
- package/dist/model/services/i18n/composition-i18n-catalog-projection.d.ts +19 -0
- package/dist/model/services/i18n/i18n-catalog.d.ts +3 -1
- package/dist/model/services/source-engine/component-sfc/component-sfc-table-source-patch.d.ts +2 -2
- package/dist/model/services/source-engine/composition-source-i18n-hints.d.ts +5 -0
- package/dist/model/services/source-engine/strategies/CompositionSourceLanguageStrategy.d.ts +1 -0
- package/dist/test/component-sfc-interactions.bench.d.ts +1 -0
- package/dist/test/component-sfc-interactions.test.d.ts +1 -0
- package/dist/test/security/auth-profile-serializer.test.d.ts +1 -0
- package/dist/test/security/auth-test-helpers.d.ts +0 -1
- package/dist/test/security/oidc-browser-session.test.d.ts +1 -0
- package/dist/test/tools/component-sfc-edit-trigger.test.d.ts +1 -0
- package/dist/tools/component-sfc-edit-trigger.d.ts +11 -0
- package/package.json +6 -4
- package/dist/model/modules/runtime/input/endge-sse.d.ts +0 -46
- package/dist/model/modules/security/auth/adapters/KeycloakAuthAdapter.d.ts +0 -25
- package/dist/model/services/auth/KeycloakAuthClient.d.ts +0 -21
|
@@ -70,6 +70,7 @@ export type EndgePortableWorkspace = Omit<EndgeWorkspaceExport, 'installedIntegr
|
|
|
70
70
|
export interface EndgeDomainBundle {
|
|
71
71
|
schemaVersion: number;
|
|
72
72
|
kind: 'workspace-snapshot';
|
|
73
|
+
domainVersion?: string;
|
|
73
74
|
workspace: EndgePortableWorkspace;
|
|
74
75
|
installedIntegrations: EndgeInstalledIntegrationExport[];
|
|
75
76
|
documents: EndgePortableDocuments;
|
|
@@ -2,7 +2,7 @@ export type RQueryAuthMode = 'none' | 'inherit' | 'profile';
|
|
|
2
2
|
export interface RQueryAuth {
|
|
3
3
|
mode: RQueryAuthMode;
|
|
4
4
|
/** Identity auth-profile для mode=profile. */
|
|
5
|
-
|
|
5
|
+
profile?: string;
|
|
6
6
|
/** Схема для заголовка (по умолчанию "Bearer"). */
|
|
7
7
|
scheme?: string;
|
|
8
8
|
/** Имя заголовка (по умолчанию "Authorization"). */
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import { EndgeConfiguration, EndgeLocaleDefinition,
|
|
1
|
+
import { EndgeConfiguration, EndgeLocaleDefinition, EndgeThemeDefinition, EndgeVariableDefinition } from '../configuration/configuration.type';
|
|
2
2
|
import { EntityManagement } from './entity-management.type';
|
|
3
3
|
export type EndgeWorkspaceLocale = EndgeLocaleDefinition;
|
|
4
4
|
export type EndgeDataMode = 'live' | 'mock';
|
|
5
5
|
export type EndgeWorkspaceLocaleLabelMode = keyof Pick<EndgeWorkspaceLocale, 'displayName' | 'shortLabel'>;
|
|
6
6
|
export type EndgeWorkspaceTheme = EndgeThemeDefinition;
|
|
7
|
-
export type EndgeWorkspaceSSEAuthMode = EndgeSSEAuthMode;
|
|
8
7
|
export type EndgeWorkspaceVar = EndgeVariableDefinition;
|
|
9
|
-
export type EndgeWorkspaceSSEConfig = EndgeSSEConfiguration;
|
|
10
8
|
export interface WorkspaceIntegrationReference {
|
|
11
9
|
integrationId: string | number;
|
|
12
10
|
integrationIdentity: string;
|
|
@@ -10,6 +10,8 @@ export interface I18nRuntimeCatalogEntry {
|
|
|
10
10
|
}
|
|
11
11
|
/** Накопленный translation catalog, доступный дочернему runtime. */
|
|
12
12
|
export type I18nRuntimeCatalog = Record<string, I18nRuntimeCatalogEntry>;
|
|
13
|
+
/** Authoring-only provenance: public alias -> locale -> message key -> document identity. */
|
|
14
|
+
export type I18nCatalogProvenance = Record<string, Record<string, Record<string, string>>>;
|
|
13
15
|
export interface I18nTranslateOptions {
|
|
14
16
|
locale?: string;
|
|
15
17
|
fallbackLocale?: string;
|
|
@@ -38,7 +38,7 @@ export interface EndgeBootContext {
|
|
|
38
38
|
vars: Record<string, unknown>;
|
|
39
39
|
/** Host-local UI policy; it does not mutate persisted Workspace configuration. */
|
|
40
40
|
ui?: EndgeUIBootOptions;
|
|
41
|
-
/** Host-owned
|
|
41
|
+
/** Host-owned browser session namespace. */
|
|
42
42
|
auth?: EndgeAuthBootOptions;
|
|
43
43
|
/**
|
|
44
44
|
* Для plain provider.
|
|
@@ -4,6 +4,7 @@ export type RuntimeActionSurface = string;
|
|
|
4
4
|
/** Stable identities of targetless Actions provided by Endge itself. */
|
|
5
5
|
export declare const BUILTIN_ACTION_IDS: {
|
|
6
6
|
readonly consoleLog: "built-in-console-log";
|
|
7
|
+
readonly testAlert: "built-in-test-alert";
|
|
7
8
|
readonly vocabAcquire: "built-in-vocabs-acquire";
|
|
8
9
|
readonly vocabRefresh: "built-in-vocabs-refresh";
|
|
9
10
|
readonly vocabInvalidate: "built-in-vocabs-invalidate";
|
|
@@ -21,6 +21,7 @@ export interface EndgePersistenceScope {
|
|
|
21
21
|
environmentId: string;
|
|
22
22
|
userId: string;
|
|
23
23
|
}
|
|
24
|
+
export type EndgePersistenceScopeResolver = () => EndgePersistenceScope;
|
|
24
25
|
export interface EndgeSessionIdentity {
|
|
25
26
|
userId?: string | null;
|
|
26
27
|
tenantId?: string | null;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { I18nCatalogProvenance, I18nRuntimeCatalog } from '../i18n.types';
|
|
1
2
|
/** Канонический тип source-документа, для которого выбирается source strategy. */
|
|
2
3
|
export type SourceKind = 'query' | 'data-view' | 'filter' | 'composition' | 'store' | 'stream' | 'update' | 'computation' | 'style' | 'type';
|
|
3
4
|
/** Тип нейтральной source completion без привязки к Monaco или другому editor API. */
|
|
@@ -23,6 +24,20 @@ export interface SourceLanguageContext {
|
|
|
23
24
|
}>;
|
|
24
25
|
/** Identity of the document that owns current source diagnostics. */
|
|
25
26
|
ownerIdentity?: string;
|
|
27
|
+
/** Effective translation catalogs for all current Project occurrences. */
|
|
28
|
+
i18n?: SourceLanguageI18nContext;
|
|
29
|
+
}
|
|
30
|
+
/** One statically projected Composition occurrence in the current Project. */
|
|
31
|
+
export interface SourceLanguageI18nOccurrence {
|
|
32
|
+
id: string;
|
|
33
|
+
catalogsByScope: Readonly<Record<string, I18nRuntimeCatalog>>;
|
|
34
|
+
provenanceByScope: Readonly<Record<string, I18nCatalogProvenance>>;
|
|
35
|
+
}
|
|
36
|
+
/** Translation input prepared by the application without mounting Runtime. */
|
|
37
|
+
export interface SourceLanguageI18nContext {
|
|
38
|
+
locale: string;
|
|
39
|
+
fallbackLocale: string;
|
|
40
|
+
occurrences: readonly SourceLanguageI18nOccurrence[];
|
|
26
41
|
}
|
|
27
42
|
/** Нейтральная completion item, которую editor adapter мапит в свой формат. */
|
|
28
43
|
export interface SourceLanguageCompletion {
|
|
@@ -38,7 +53,7 @@ export interface SourceLanguageCompletion {
|
|
|
38
53
|
documentation?: string;
|
|
39
54
|
}
|
|
40
55
|
/** Логический тип внешнего доменного документа, на который ссылается source. */
|
|
41
|
-
export type SourceDocumentReferenceTarget = 'auth-profile' | 'component' | 'composition' | 'computation' | 'converter' | 'data-view' | 'filter' | 'mock' | 'query' | 'store' | 'stream' | 'update' | 'style' | 'type' | 'vocabs';
|
|
56
|
+
export type SourceDocumentReferenceTarget = 'auth-profile' | 'component' | 'composition' | 'computation' | 'converter' | 'data-view' | 'filter' | 'i18n-bundles' | 'mock' | 'query' | 'store' | 'stream' | 'update' | 'style' | 'type' | 'vocabs';
|
|
42
57
|
/** Семантическая ссылка из source на внешний доменный документ. */
|
|
43
58
|
export interface SourceDocumentReference {
|
|
44
59
|
/** Логический тип цели; UI может уточнить concrete document type через domain. */
|
|
@@ -58,6 +73,14 @@ export interface SourceLanguageSemanticHighlight {
|
|
|
58
73
|
identity: string;
|
|
59
74
|
range: SourceDocumentReference['range'];
|
|
60
75
|
}
|
|
76
|
+
/** Renderer-neutral inline annotation shown after one source range. */
|
|
77
|
+
export interface SourceLanguageInlineHint {
|
|
78
|
+
kind: 'translation';
|
|
79
|
+
status: 'resolved' | 'ambiguous';
|
|
80
|
+
text: string;
|
|
81
|
+
tooltip?: string;
|
|
82
|
+
range: SourceDocumentReference['range'];
|
|
83
|
+
}
|
|
61
84
|
/** Результат validation source language strategy. */
|
|
62
85
|
export interface SourceLanguageValidationResult extends SourceEngineResult {
|
|
63
86
|
/** Diagnostics, найденные language strategy. */
|
|
@@ -185,4 +208,6 @@ export interface SourceLanguageStrategy {
|
|
|
185
208
|
resolveReference?: (context: SourceLanguageContext) => SourceDocumentReference | null;
|
|
186
209
|
/** Возвращает semantic highlights без привязки к конкретному editor adapter. */
|
|
187
210
|
semanticHighlights?: (context: SourceLanguageContext) => SourceLanguageSemanticHighlight[];
|
|
211
|
+
/** Возвращает inline annotations без привязки к конкретному editor adapter. */
|
|
212
|
+
inlineHints?: (context: SourceLanguageContext) => SourceLanguageInlineHint[];
|
|
188
213
|
}
|
|
@@ -3,7 +3,8 @@ export interface StreamSseTransportDescriptor {
|
|
|
3
3
|
kind: 'sse';
|
|
4
4
|
url: string;
|
|
5
5
|
withCredentials: boolean;
|
|
6
|
-
authMode: 'inherit' | 'none';
|
|
6
|
+
authMode: 'inherit' | 'profile' | 'none';
|
|
7
|
+
authProfileIdentity: string | null;
|
|
7
8
|
}
|
|
8
9
|
export type StreamTransportDescriptor = StreamSseTransportDescriptor;
|
|
9
10
|
export interface StreamEventDescriptor {
|
package/dist/main.d.ts
CHANGED
|
@@ -15,6 +15,8 @@ export * from './model/modules/runtime/execution/endge-query';
|
|
|
15
15
|
export * from './model/modules/runtime/execution/endge-computation';
|
|
16
16
|
export * from './model/modules/runtime/core/endge-runtime';
|
|
17
17
|
export * from './model/modules/security/endge-auth';
|
|
18
|
+
export * from './model/modules/security/auth/AuthInteractionRequiredError';
|
|
19
|
+
export * from './model/services/auth/OidcBrowserSession_Service';
|
|
18
20
|
export * from './model/modules/context/endge-i18n';
|
|
19
21
|
export * from './model/modules/context/endge-workspace';
|
|
20
22
|
export * from './model/modules/context/endge-vars';
|
|
@@ -163,6 +165,7 @@ export * from './domain/entities/action-flow/REndgeFlow';
|
|
|
163
165
|
export * from './tools/openapi-parser';
|
|
164
166
|
export * from './tools/graphql-parser';
|
|
165
167
|
export * from './tools/ScheduleUpdate-sse-generator';
|
|
168
|
+
export * from './tools/component-sfc-edit-trigger';
|
|
166
169
|
export * from './model/config/diagnostics.config';
|
|
167
170
|
export * from './model/adapters/diagnostics/ConsoleDiagnosticsAdapter';
|
|
168
171
|
export * from './model/adapters/diagnostics/DiagnosticsAdapterRegistry';
|
|
@@ -179,6 +182,7 @@ export * from './model/seed/converters/date/string-to-date';
|
|
|
179
182
|
export * from './model/seed/converters/date/weekdays-range';
|
|
180
183
|
export * from './model/services/document/DocumentDraftFactory';
|
|
181
184
|
export * from './model/services/configuration/endge-configuration';
|
|
185
|
+
export * from './model/services/i18n/composition-i18n-catalog-projection';
|
|
182
186
|
export * from './domain/entities/runtime/RuntimeHostBase';
|
|
183
187
|
export * from './domain/entities/runtime/RuntimeHostRegistry';
|
|
184
188
|
export * from './domain/entities/runtime/RuntimeAppScope';
|
|
@@ -7,7 +7,6 @@ export declare const ENDGE_COMPILER_SPAN_GROUPS: {
|
|
|
7
7
|
readonly ACTIONS: "actions";
|
|
8
8
|
readonly CONVERTERS: "converters";
|
|
9
9
|
readonly QUERIES: "queries";
|
|
10
|
-
readonly SSE: "sse";
|
|
11
10
|
readonly RAPH: "raph";
|
|
12
11
|
};
|
|
13
12
|
/** Runtime fallback limits для nested computation execution. */
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { EndgeSFCEditingConfiguration } from '../../domain/types/configuration/configuration.type';
|
|
2
|
+
/** Системные triggers завершения edit session до Workspace cascade. */
|
|
3
|
+
export declare const DEFAULT_ENDGE_SFC_EDITING_CONFIGURATION: Readonly<EndgeSFCEditingConfiguration>;
|
|
@@ -33,7 +33,7 @@ export declare const ENDGE_UI_DEFAULT_DEFINITIONS: ({
|
|
|
33
33
|
roles: {
|
|
34
34
|
role: string;
|
|
35
35
|
description: string;
|
|
36
|
-
supportedSurfaces: ("
|
|
36
|
+
supportedSurfaces: ("canvas" | "runtime" | "admin")[];
|
|
37
37
|
}[];
|
|
38
38
|
};
|
|
39
39
|
defaultLayout?: undefined;
|
|
@@ -78,7 +78,7 @@ export declare const ENDGE_UI_DEFAULT_DEFINITIONS: ({
|
|
|
78
78
|
roles: {
|
|
79
79
|
role: string;
|
|
80
80
|
description: string;
|
|
81
|
-
supportedSurfaces: ("
|
|
81
|
+
supportedSurfaces: ("canvas" | "runtime" | "admin")[];
|
|
82
82
|
defaultRendererRefs: {
|
|
83
83
|
admin: string;
|
|
84
84
|
runtime: string;
|
|
@@ -126,7 +126,7 @@ export declare const ENDGE_UI_DEFAULT_DEFINITIONS: ({
|
|
|
126
126
|
roles: {
|
|
127
127
|
role: string;
|
|
128
128
|
description: string;
|
|
129
|
-
supportedSurfaces: ("
|
|
129
|
+
supportedSurfaces: ("canvas" | "runtime" | "admin")[];
|
|
130
130
|
defaultRendererRefs: {
|
|
131
131
|
admin: string;
|
|
132
132
|
runtime: string;
|
|
@@ -174,7 +174,7 @@ export declare const ENDGE_UI_DEFAULT_DEFINITIONS: ({
|
|
|
174
174
|
roles: {
|
|
175
175
|
role: string;
|
|
176
176
|
description: string;
|
|
177
|
-
supportedSurfaces: ("
|
|
177
|
+
supportedSurfaces: ("canvas" | "runtime" | "admin")[];
|
|
178
178
|
defaultRendererRefs: {
|
|
179
179
|
admin: string;
|
|
180
180
|
runtime: string;
|
|
@@ -222,7 +222,7 @@ export declare const ENDGE_UI_DEFAULT_DEFINITIONS: ({
|
|
|
222
222
|
roles: {
|
|
223
223
|
role: string;
|
|
224
224
|
description: string;
|
|
225
|
-
supportedSurfaces: ("
|
|
225
|
+
supportedSurfaces: ("canvas" | "runtime" | "admin")[];
|
|
226
226
|
defaultRendererRefs: {
|
|
227
227
|
admin: string;
|
|
228
228
|
runtime: string;
|
|
@@ -270,7 +270,7 @@ export declare const ENDGE_UI_DEFAULT_DEFINITIONS: ({
|
|
|
270
270
|
roles: {
|
|
271
271
|
role: string;
|
|
272
272
|
description: string;
|
|
273
|
-
supportedSurfaces: ("
|
|
273
|
+
supportedSurfaces: ("canvas" | "runtime" | "admin")[];
|
|
274
274
|
defaultRendererRefs: {
|
|
275
275
|
admin: string;
|
|
276
276
|
runtime: string;
|
|
@@ -319,7 +319,7 @@ export declare const ENDGE_UI_DEFAULT_DEFINITIONS: ({
|
|
|
319
319
|
roles: ({
|
|
320
320
|
role: string;
|
|
321
321
|
description: string;
|
|
322
|
-
supportedSurfaces: ("
|
|
322
|
+
supportedSurfaces: ("canvas" | "runtime" | "admin")[];
|
|
323
323
|
defaultRendererRefs: {
|
|
324
324
|
admin: string;
|
|
325
325
|
runtime: string;
|
|
@@ -375,7 +375,7 @@ export declare const ENDGE_UI_DEFAULT_DEFINITIONS: ({
|
|
|
375
375
|
roles: {
|
|
376
376
|
role: string;
|
|
377
377
|
description: string;
|
|
378
|
-
supportedSurfaces: ("
|
|
378
|
+
supportedSurfaces: ("canvas" | "runtime" | "admin")[];
|
|
379
379
|
defaultRendererRefs: {
|
|
380
380
|
admin: string;
|
|
381
381
|
runtime: string;
|
|
@@ -423,7 +423,7 @@ export declare const ENDGE_UI_DEFAULT_DEFINITIONS: ({
|
|
|
423
423
|
roles: ({
|
|
424
424
|
role: string;
|
|
425
425
|
description: string;
|
|
426
|
-
supportedSurfaces: ("
|
|
426
|
+
supportedSurfaces: ("canvas" | "runtime" | "admin")[];
|
|
427
427
|
defaultRendererRefs: {
|
|
428
428
|
admin: string;
|
|
429
429
|
runtime: string;
|
|
@@ -481,7 +481,7 @@ export declare const ENDGE_UI_DEFAULT_DEFINITIONS: ({
|
|
|
481
481
|
roles: {
|
|
482
482
|
role: string;
|
|
483
483
|
description: string;
|
|
484
|
-
supportedSurfaces: ("
|
|
484
|
+
supportedSurfaces: ("canvas" | "runtime" | "admin")[];
|
|
485
485
|
defaultRendererRefs: {
|
|
486
486
|
admin: string;
|
|
487
487
|
runtime: string;
|
|
@@ -22,7 +22,6 @@ import { EndgeRuntime } from '../modules/runtime/core/endge-runtime';
|
|
|
22
22
|
import { EndgeRuntimeDebugger } from '../modules/diagnostics/endge-runtime-debugger';
|
|
23
23
|
import { EndgeDomainRepository } from '../modules/domain/endge-domain-repository';
|
|
24
24
|
import { EndgeSource } from '../modules/program/endge-source';
|
|
25
|
-
import { EndgeSSE } from '../modules/runtime/input/endge-sse';
|
|
26
25
|
import { EndgeStyles } from '../modules/ui/endge-styles';
|
|
27
26
|
import { EndgeUI } from '../modules/ui/endge-ui';
|
|
28
27
|
import { EndgeUpdates } from '../modules/runtime/core/endge-updates';
|
|
@@ -151,10 +150,6 @@ export declare class Endge extends EndgeFederation {
|
|
|
151
150
|
* Доступ к event bus модулю.
|
|
152
151
|
*/
|
|
153
152
|
static get events(): EndgeEvents;
|
|
154
|
-
/**
|
|
155
|
-
* Доступ к SSE-модулю.
|
|
156
|
-
*/
|
|
157
|
-
static get sse(): EndgeSSE;
|
|
158
153
|
/**
|
|
159
154
|
* Доступ к UI state модулю.
|
|
160
155
|
*/
|
|
@@ -50,8 +50,8 @@ export declare class WorkspaceVariables {
|
|
|
50
50
|
currentValue: string;
|
|
51
51
|
}>;
|
|
52
52
|
/**
|
|
53
|
-
* Резолвит
|
|
54
|
-
*
|
|
53
|
+
* Резолвит одиночные токены и интерполирует несколько переменных в строке,
|
|
54
|
+
* затем применяет optional coercion.
|
|
55
55
|
*/
|
|
56
56
|
resolve<T = string>(raw: unknown, options?: {
|
|
57
57
|
coerce?: (value: string | number | boolean | null | undefined) => T;
|
|
@@ -70,6 +70,8 @@ export declare class WorkspaceVariables {
|
|
|
70
70
|
* Приводит значение переменной к boolean.
|
|
71
71
|
*/
|
|
72
72
|
static toBoolean(v: unknown): boolean;
|
|
73
|
+
/** Интерполирует все корректные `{{ VAR }}` и legacy `{VAR}` токены в строке. */
|
|
74
|
+
private _interpolate;
|
|
73
75
|
/**
|
|
74
76
|
* Внутренний helper модуля: parse Var Token.
|
|
75
77
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EndgeBootContext } from '../../../domain/types/kernel/bootstrap.types';
|
|
2
|
-
import { EndgeDataMode, EndgeWorkspaceDefinition, EndgeWorkspaceLocale, EndgeWorkspaceLocaleLabelMode,
|
|
2
|
+
import { EndgeDataMode, EndgeWorkspaceDefinition, EndgeWorkspaceLocale, EndgeWorkspaceLocaleLabelMode, EndgeWorkspaceTheme, EndgeWorkspaceVar } from '../../../domain/types/document/workspace.types';
|
|
3
3
|
import { EndgeModule } from '../../../domain/entities/endge/EndgeModule';
|
|
4
4
|
import { WorkspaceVariables } from './endge-vars';
|
|
5
5
|
/**
|
|
@@ -53,8 +53,6 @@ export declare class EndgeWorkspace extends EndgeModule {
|
|
|
53
53
|
get vars(): EndgeWorkspaceVar[];
|
|
54
54
|
/** Explicit name for the persisted variable definitions. */
|
|
55
55
|
get variableDefinitions(): EndgeWorkspaceVar[];
|
|
56
|
-
/** Возвращает workspace SSE config. */
|
|
57
|
-
get sse(): EndgeWorkspaceSSEConfig | undefined;
|
|
58
56
|
/** Возвращает locale по умолчанию. */
|
|
59
57
|
get defaultLocale(): string;
|
|
60
58
|
/** Возвращает fallback locale. */
|
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
import { EndgePersistenceScope, EndgeStorageAdapter, RuntimeStateControllerLike } from '../../../../domain/types/runtime/context-persistence.types';
|
|
1
|
+
import { EndgePersistenceScope, EndgePersistenceScopeResolver, EndgeStorageAdapter, RuntimeStateControllerLike } from '../../../../domain/types/runtime/context-persistence.types';
|
|
2
2
|
export declare function buildRuntimeStateStorageKey(scope: EndgePersistenceScope, runtimeId: string): string;
|
|
3
3
|
export declare class RuntimeStateController implements RuntimeStateControllerLike {
|
|
4
4
|
readonly runtimeId: string;
|
|
5
5
|
readonly storageId: string;
|
|
6
|
-
readonly storageKey: string;
|
|
7
|
-
readonly scope: EndgePersistenceScope;
|
|
8
6
|
private readonly _adapter;
|
|
7
|
+
private readonly _resolveScope;
|
|
9
8
|
constructor(input: {
|
|
10
9
|
runtimeId: string;
|
|
11
10
|
storageId?: string;
|
|
12
|
-
scope: EndgePersistenceScope;
|
|
11
|
+
scope: EndgePersistenceScope | EndgePersistenceScopeResolver;
|
|
13
12
|
adapter: EndgeStorageAdapter;
|
|
14
13
|
});
|
|
14
|
+
/** Возвращает актуальный persistence scope, включая текущую session identity. */
|
|
15
|
+
get scope(): EndgePersistenceScope;
|
|
16
|
+
/** Строит storage key из актуального scope, чтобы переавторизация не сохраняла данные прежнему пользователю. */
|
|
17
|
+
get storageKey(): string;
|
|
15
18
|
get<T>(entityKey: string, section: string, fallback: T): T;
|
|
16
19
|
set<T>(entityKey: string, section: string, value: T): void;
|
|
17
20
|
remove(entityKey: string, section?: string): void;
|
|
@@ -33,7 +33,9 @@ import { RType } from '../../../domain/entities/reflect/RType';
|
|
|
33
33
|
import { RVocabs } from '../../../domain/entities/reflect/RVocabs';
|
|
34
34
|
import { RI18nBundle } from '../../../domain/entities/reflect/RI18nBundle';
|
|
35
35
|
import { ResolvedEntityIndex } from './resolved/resolved-entity-index';
|
|
36
|
+
/** Материализует только активные документы; tombstones остаются в repository server state. */
|
|
36
37
|
export declare function normalizeSnapshotDocuments(documents: readonly EndgeLiveDomainDocument[], folderIds: ReadonlyMap<string, string>): Record<string, unknown>[];
|
|
38
|
+
/** Материализует только активные папки; tombstones остаются в repository server state. */
|
|
37
39
|
export declare function normalizeSnapshotFolders(folders: readonly EndgeLiveDomainDocument[], folderIds: ReadonlyMap<string, string>): Record<string, unknown>[];
|
|
38
40
|
/**
|
|
39
41
|
* EndgeDomain – менеджер доменных данных.
|
|
@@ -156,6 +158,10 @@ export declare class EndgeDomain extends EndgeModule {
|
|
|
156
158
|
* Объединяет доменные данные из JSON.
|
|
157
159
|
*/
|
|
158
160
|
merge(json: any): void;
|
|
161
|
+
/** Заменяет сохранённую сущность, не меняя её позицию в коллекции домена. */
|
|
162
|
+
replacePersistedEntity(currentEntity: object, nextEntity: object): void;
|
|
163
|
+
private _entityIndexes;
|
|
164
|
+
private _replaceUpdateOwnerIndex;
|
|
159
165
|
/** Нормализует live workspace snapshot нового backend и объединяет его с доменом. */
|
|
160
166
|
mergeFromSnapshot(snapshot: EndgeLiveDomainSnapshot): void;
|
|
161
167
|
/** Нормализует immutable workspace bundle без создания фиктивного server-side state. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SourceEngineCompileResult, SourceEngineGenerateResult, SourceEngineStrategy, SourceLanguageCompletion, SourceLanguageContext, SourceLanguageSemanticHighlight, SourceDocumentReference, SourceLanguageStrategy, SourceLanguageValidationResult, SourceKind, SourceParseResult, SourcePatchResult, SourcePatchStrategy } from '../../../domain/types/source/source-engine.types';
|
|
1
|
+
import { SourceEngineCompileResult, SourceEngineGenerateResult, SourceEngineStrategy, SourceLanguageCompletion, SourceLanguageContext, SourceLanguageInlineHint, SourceLanguageSemanticHighlight, SourceDocumentReference, SourceLanguageStrategy, SourceLanguageValidationResult, SourceKind, SourceParseResult, SourcePatchResult, SourcePatchStrategy } from '../../../domain/types/source/source-engine.types';
|
|
2
2
|
import { EndgeModule } from '../../../domain/entities/endge/EndgeModule';
|
|
3
3
|
/** Модуль authoring-операций над source-документами Endge. */
|
|
4
4
|
export declare class EndgeSource extends EndgeModule {
|
|
@@ -45,6 +45,8 @@ export declare class EndgeSource extends EndgeModule {
|
|
|
45
45
|
referenceAt(sourceKind: SourceKind | string, context: SourceLanguageContext): SourceDocumentReference | null;
|
|
46
46
|
/** Возвращает renderer-neutral semantic highlights для source-документа. */
|
|
47
47
|
semanticHighlights(sourceKind: SourceKind | string, context: SourceLanguageContext): SourceLanguageSemanticHighlight[];
|
|
48
|
+
/** Возвращает renderer-neutral inline annotations для source-документа. */
|
|
49
|
+
inlineHints(sourceKind: SourceKind | string, context: SourceLanguageContext): SourceLanguageInlineHint[];
|
|
48
50
|
/** Регистрирует встроенные strategies ядра. */
|
|
49
51
|
private _registerDefaultStrategies;
|
|
50
52
|
/** Возвращает strategy или бросает явную ошибку для некорректного source-kind. */
|
|
@@ -4,6 +4,8 @@ import { ComputationResourceState } from './ComputationResource';
|
|
|
4
4
|
export declare class ComputationResourceRegistry {
|
|
5
5
|
private readonly resources;
|
|
6
6
|
private readonly disposers;
|
|
7
|
+
/** Resource inputs currently pulled by the active renderer pass. */
|
|
8
|
+
private readonly _updatingInputs;
|
|
7
9
|
getOrCreate(key: string, input: unknown, create: () => ComputationResourceState, onChange?: VoidFunction): ComputationResourceContract;
|
|
8
10
|
dispose(): void;
|
|
9
11
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Сигнал host-приложению, что продолжение требует пользовательского OIDC flow. */
|
|
2
|
+
export declare class AuthInteractionRequiredError extends Error {
|
|
3
|
+
readonly profileIdentity: string;
|
|
4
|
+
readonly code = "auth_interaction_required";
|
|
5
|
+
constructor(profileIdentity: string);
|
|
6
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { RAuthProfile } from '../../../../domain/entities/reflect/RAuthProfile';
|
|
2
|
-
import { AuthAdapterContext, AuthProfileSchema,
|
|
2
|
+
import { AuthAdapterContext, AuthProfileSchema, AuthProfileTestResult } from '../../../../domain/types/auth/auth-profile.types';
|
|
3
3
|
import { AuthAdapterRegistry } from './AuthAdapterRegistry';
|
|
4
4
|
interface AuthProfileRegistryDependencies {
|
|
5
5
|
listProfiles: () => RAuthProfile[];
|
|
6
6
|
getDefaultIdentity: () => string | null;
|
|
7
|
-
|
|
7
|
+
resolveValue: (value: unknown) => string;
|
|
8
8
|
getSignal: () => AbortSignal | undefined;
|
|
9
9
|
}
|
|
10
10
|
/** Читает persisted AuthProfile и проверяет adapter-specific contracts. */
|
|
@@ -21,11 +21,11 @@ export declare class AuthProfileRegistry {
|
|
|
21
21
|
/** Проверяет все не удалённые profiles текущего Domain. */
|
|
22
22
|
validateAll(): void;
|
|
23
23
|
/** Проверяет profile в изолированной session без записи token в storage. */
|
|
24
|
-
test(profile: AuthProfileSchema
|
|
24
|
+
test(profile: AuthProfileSchema): Promise<AuthProfileTestResult>;
|
|
25
25
|
/** Требует существующий активный profile. */
|
|
26
26
|
requireActive(profileOrIdentity: AuthProfileSchema | string): AuthProfileSchema;
|
|
27
27
|
/** Создаёт adapter context с opaque host credential resolver. */
|
|
28
|
-
createAdapterContext(profile: AuthProfileSchema
|
|
28
|
+
createAdapterContext(profile: AuthProfileSchema): AuthAdapterContext;
|
|
29
29
|
private _adapterContext;
|
|
30
30
|
private _validateCommon;
|
|
31
31
|
}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { AuthRequestPolicy, AuthResolvedSession, AuthResolveOptions } from '../../../../domain/types/auth/auth-profile.types';
|
|
2
2
|
import { AuthProfileRegistry } from './AuthProfileRegistry';
|
|
3
3
|
import { AuthSessionManager } from './AuthSessionManager';
|
|
4
|
+
import { AuthInteractionRequiredError } from './AuthInteractionRequiredError';
|
|
4
5
|
/** Разрешает auth policy запроса без изменения sessions других profiles. */
|
|
5
6
|
export declare class AuthRequestResolver {
|
|
6
7
|
private readonly _profiles;
|
|
7
8
|
private readonly _sessions;
|
|
8
|
-
|
|
9
|
+
private readonly _onInteractionRequired?;
|
|
10
|
+
constructor(_profiles: AuthProfileRegistry, _sessions: AuthSessionManager, _onInteractionRequired?: ((error: AuthInteractionRequiredError) => void) | undefined);
|
|
9
11
|
/** Возвращает transport-neutral credentials для none/inherit/profile policy. */
|
|
10
12
|
resolve(policy: AuthRequestPolicy, options?: AuthResolveOptions): Promise<AuthResolvedSession>;
|
|
13
|
+
/** Publishes the typed host signal before the request fails. */
|
|
14
|
+
private _throwInteractionRequired;
|
|
15
|
+
private _publishAndThrow;
|
|
11
16
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AuthEnsureOptions,
|
|
1
|
+
import { AuthEnsureOptions, AuthProfileSchema, AuthResolvedSession, AuthSessionSource, AuthTokenSet, EndgeAuthContext } from '../../../../domain/types/auth/auth-profile.types';
|
|
2
2
|
import { AuthAdapterRegistry } from './AuthAdapterRegistry';
|
|
3
3
|
import { AuthProfileRegistry } from './AuthProfileRegistry';
|
|
4
4
|
import { AuthSessionStore } from './AuthSessionStore';
|
|
@@ -33,11 +33,6 @@ export declare class AuthSessionManager {
|
|
|
33
33
|
configureDefault(profile: AuthProfileSchema | null): void;
|
|
34
34
|
/** Подключает host-owned session source и запрещает смешивание с persisted snapshot profile. */
|
|
35
35
|
connect(profileIdentity: string, source: AuthSessionSource): void;
|
|
36
|
-
/** Выполняет interactive login default runtime profile. */
|
|
37
|
-
login(credentials: AuthLoginCredentials): Promise<void>;
|
|
38
|
-
/** Входит в указанный Keycloak profile, не меняя default profile. */
|
|
39
|
-
loginWithProfile(profileIdentity: string, credentials: AuthLoginCredentials): Promise<void>;
|
|
40
|
-
private _loginWithProfile;
|
|
41
36
|
/** Гарантирует действующую session default runtime profile. */
|
|
42
37
|
ensureValid(options?: AuthEnsureOptions): Promise<boolean>;
|
|
43
38
|
/** Загружает userinfo для session default runtime profile. */
|
|
@@ -56,6 +51,7 @@ export declare class AuthSessionManager {
|
|
|
56
51
|
private _clearState;
|
|
57
52
|
private _defaultState;
|
|
58
53
|
private _isAccessTokenUsable;
|
|
54
|
+
private _isSessionUsable;
|
|
59
55
|
private _isAccessTokenFresh;
|
|
60
56
|
private _refreshSkewMs;
|
|
61
57
|
private _isRefreshExpired;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AuthAdapterContext, AuthProfileAdapter, AuthProfileSchema, AuthTokenSet } from '../../../../../domain/types/auth/auth-profile.types';
|
|
2
|
+
/** Материализует HTTP Basic header без token session. */
|
|
3
|
+
export declare class BasicAuthAdapter implements AuthProfileAdapter {
|
|
4
|
+
readonly id = "basic";
|
|
5
|
+
readonly label = "Basic";
|
|
6
|
+
/** Проверяет строгий Basic contract. */
|
|
7
|
+
validate(profile: AuthProfileSchema): void;
|
|
8
|
+
/** Разрешает credentials и возвращает готовый Authorization header. */
|
|
9
|
+
authenticate(context: AuthAdapterContext): Promise<AuthTokenSet>;
|
|
10
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AuthAdapterContext, AuthProfileAdapter, AuthProfileSchema, AuthTokenSet } from '../../../../../domain/types/auth/auth-profile.types';
|
|
2
|
-
/**
|
|
2
|
+
/** Материализует Bearer header из literal или Workspace variable. */
|
|
3
3
|
export declare class BearerAuthAdapter implements AuthProfileAdapter {
|
|
4
4
|
readonly id = "bearer";
|
|
5
5
|
readonly label = "Bearer token";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AuthAdapterContext, AuthProfileAdapter, AuthProfileSchema, AuthTokenSet } from '../../../../../domain/types/auth/auth-profile.types';
|
|
2
|
+
/** Выполняет OAuth2 Client Credentials grant. */
|
|
3
|
+
export declare class OAuth2ClientCredentialsAuthAdapter implements AuthProfileAdapter {
|
|
4
|
+
readonly id = "oauth2-client-credentials";
|
|
5
|
+
readonly label = "OAuth2 Client Credentials";
|
|
6
|
+
validate(profile: AuthProfileSchema): void;
|
|
7
|
+
authenticate(context: AuthAdapterContext): Promise<AuthTokenSet>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AuthAdapterContext, AuthProfileAdapter, AuthProfileSchema, AuthTokenSet } from '../../../../../domain/types/auth/auth-profile.types';
|
|
2
|
+
/** Выполняет OAuth2 Resource Owner Password grant для dev/test профилей. */
|
|
3
|
+
export declare class OAuth2PasswordAuthAdapter implements AuthProfileAdapter {
|
|
4
|
+
readonly id = "oauth2-password";
|
|
5
|
+
readonly label = "OAuth2 Password (dev/test)";
|
|
6
|
+
validate(profile: AuthProfileSchema): void;
|
|
7
|
+
authenticate(context: AuthAdapterContext): Promise<AuthTokenSet>;
|
|
8
|
+
refresh(context: AuthAdapterContext): Promise<AuthTokenSet>;
|
|
9
|
+
private _appendScopes;
|
|
10
|
+
private _requestToken;
|
|
11
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AuthAdapterContext, AuthProfileAdapter, AuthProfileSchema, AuthTokenSet } from '../../../../../domain/types/auth/auth-profile.types';
|
|
2
|
+
/** Валидирует общий OIDC profile; interactive flow запускает host через session source. */
|
|
3
|
+
export declare class OidcAuthAdapter implements AuthProfileAdapter {
|
|
4
|
+
readonly id = "oidc";
|
|
5
|
+
readonly label = "OIDC";
|
|
6
|
+
validate(profile: AuthProfileSchema): void;
|
|
7
|
+
authenticate(context: AuthAdapterContext): Promise<AuthTokenSet>;
|
|
8
|
+
}
|
|
@@ -1,29 +1,39 @@
|
|
|
1
1
|
import { EndgeBootContext } from '../../../domain/types/kernel/bootstrap.types';
|
|
2
|
+
import { AuthProfileSchema, OidcBrowserSessionOptions } from '../../../domain/types/auth/auth-profile.types';
|
|
2
3
|
import { EndgeModule } from '../../../domain/entities/endge/EndgeModule';
|
|
3
4
|
import { AuthAdapterRegistry } from './auth/AuthAdapterRegistry';
|
|
4
5
|
import { AuthProfileRegistry } from './auth/AuthProfileRegistry';
|
|
5
6
|
import { AuthRequestResolver } from './auth/AuthRequestResolver';
|
|
6
7
|
import { AuthSessionManager } from './auth/AuthSessionManager';
|
|
8
|
+
import { OidcBrowserSession_Service } from '../../services/auth/OidcBrowserSession_Service';
|
|
9
|
+
import { AuthInteractionRequiredError } from './auth/AuthInteractionRequiredError';
|
|
10
|
+
export type AuthInteractionRequiredListener = (error: AuthInteractionRequiredError) => void;
|
|
7
11
|
/** Единый lifecycle owner runtime auth profile sessions и request authentication. */
|
|
8
12
|
export declare class EndgeAuth extends EndgeModule {
|
|
9
13
|
readonly adapters: AuthAdapterRegistry;
|
|
10
14
|
readonly profiles: AuthProfileRegistry;
|
|
11
15
|
readonly session: AuthSessionManager;
|
|
12
16
|
readonly requests: AuthRequestResolver;
|
|
13
|
-
private _credentialResolver;
|
|
14
17
|
private _signal;
|
|
18
|
+
private _storageNamespace;
|
|
15
19
|
private _abortController;
|
|
16
20
|
private _detachHostAbort;
|
|
17
21
|
private _unregisterDiagnosticsContext;
|
|
18
22
|
private readonly _store;
|
|
23
|
+
private readonly _interactionRequiredListeners;
|
|
19
24
|
/** Собирает auth subsystem и регистрирует встроенные adapters один раз. */
|
|
20
25
|
constructor();
|
|
21
|
-
/**
|
|
26
|
+
/** Subscribes a host application to requests that require an interactive OIDC flow. */
|
|
27
|
+
onInteractionRequired(listener: AuthInteractionRequiredListener): () => void;
|
|
28
|
+
/** Подключает storage namespace и безопасные context providers. */
|
|
22
29
|
setup(ctx: EndgeBootContext): void;
|
|
23
30
|
/** Валидирует Domain profiles и восстанавливает session default runtime profile. */
|
|
24
31
|
build(): void;
|
|
25
32
|
/** Сбрасывает runtime state, не удаляя persisted browser session. */
|
|
26
33
|
reset(): void;
|
|
34
|
+
/** Создаёт OIDC browser source из resolved persisted profile. */
|
|
35
|
+
createOidcSessionSource(profileInput: AuthProfileSchema | string, options: Pick<OidcBrowserSessionOptions, 'redirectUri' | 'popupRedirectUri' | 'postLogoutRedirectUri' | 'flow'>): OidcBrowserSession_Service;
|
|
27
36
|
private _resolvePublicValue;
|
|
28
37
|
private _diagnosticsAttributes;
|
|
38
|
+
private _publishInteractionRequired;
|
|
29
39
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { AuthSessionSource, AuthSessionSourceResolveOptions, AuthTokenSet, OidcBrowserSessionOptions } from '../../../domain/types/auth/auth-profile.types';
|
|
2
|
+
/** Общий browser OIDC runtime для popup и redirect Authorization Code + PKCE flows. */
|
|
3
|
+
export declare class OidcBrowserSession_Service implements AuthSessionSource {
|
|
4
|
+
readonly options: OidcBrowserSessionOptions;
|
|
5
|
+
private readonly _userStore;
|
|
6
|
+
private readonly _manager;
|
|
7
|
+
constructor(options: OidcBrowserSessionOptions);
|
|
8
|
+
/** Возвращает сохранённого пользователя без запуска интерактивного flow. */
|
|
9
|
+
hasSession(): Promise<boolean>;
|
|
10
|
+
/** Открывает внешний OIDC login в popup и сохраняет полученную session. */
|
|
11
|
+
loginPopup(): Promise<AuthTokenSet>;
|
|
12
|
+
/** Завершает callback в отдельном popup без загрузки Domain. */
|
|
13
|
+
static completeStoredPopupCallback(url?: string): Promise<void>;
|
|
14
|
+
/** Перенаправляет текущую вкладку на внешний OIDC login. */
|
|
15
|
+
loginRedirect(): Promise<never>;
|
|
16
|
+
/** Завершает redirect callback и сохраняет session. */
|
|
17
|
+
completeRedirectCallback(url?: string): Promise<AuthTokenSet>;
|
|
18
|
+
/** Завершает popup callback; результат передаётся opener через oidc-client-ts. */
|
|
19
|
+
completePopupCallback(url?: string): Promise<void>;
|
|
20
|
+
/** Возвращает актуальную session, используя refresh token только при необходимости. */
|
|
21
|
+
resolveToken(options: AuthSessionSourceResolveOptions): Promise<AuthTokenSet | null>;
|
|
22
|
+
/** Возвращает claims и при наличии endpoint дополняет их OIDC userinfo. */
|
|
23
|
+
loadUserInfo(): Promise<Record<string, unknown> | null>;
|
|
24
|
+
/** Завершает provider session выбранным host flow и всегда удаляет local user. */
|
|
25
|
+
logout(): Promise<void>;
|
|
26
|
+
}
|