@netsapiens/horizon-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +643 -0
- package/dist/index.cjs +486 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +861 -0
- package/dist/index.d.ts +861 -0
- package/dist/index.js +453 -0
- package/dist/index.js.map +1 -0
- package/package.json +56 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,861 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import loglevel from 'loglevel';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Public type contract for @netsapiens/horizon-sdk.
|
|
7
|
+
*
|
|
8
|
+
* This file defines the shape of the runtime context that Horizon passes to
|
|
9
|
+
* remote applications, plus the registration payloads remote apps emit back
|
|
10
|
+
* through the event bus.
|
|
11
|
+
*
|
|
12
|
+
* Horizon's host implementation imports these same types so the host and the
|
|
13
|
+
* SDK cannot drift out of sync.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* User information passed to remote apps. Additional fields may be present.
|
|
18
|
+
*/
|
|
19
|
+
interface HorizonUser {
|
|
20
|
+
displayName: string;
|
|
21
|
+
domain: string;
|
|
22
|
+
email?: string;
|
|
23
|
+
extension?: string;
|
|
24
|
+
scope?: string;
|
|
25
|
+
department?: string;
|
|
26
|
+
site?: string;
|
|
27
|
+
[key: string]: unknown;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Configuration for remote vendor authentication request
|
|
31
|
+
*/
|
|
32
|
+
interface RemoteAuthRequest {
|
|
33
|
+
/** Unique identifier for the vendor system */
|
|
34
|
+
vendorId: string;
|
|
35
|
+
/** Callback URL where vendor will receive authcode webhook */
|
|
36
|
+
callbackUrl: string;
|
|
37
|
+
/** Optional scopes/permissions requested from vendor */
|
|
38
|
+
scopes?: string[];
|
|
39
|
+
/** Optional metadata to pass to vendor */
|
|
40
|
+
metadata?: Record<string, unknown>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Response from remote authentication flow
|
|
44
|
+
*/
|
|
45
|
+
interface RemoteAuthResponse {
|
|
46
|
+
/** Unique identifier for the vendor system */
|
|
47
|
+
vendorId: string;
|
|
48
|
+
/** Access token or JWT from vendor */
|
|
49
|
+
accessToken: string;
|
|
50
|
+
/** Token type (Bearer, etc.) */
|
|
51
|
+
tokenType?: string;
|
|
52
|
+
/** Token expiration timestamp (Unix seconds) */
|
|
53
|
+
expiresAt?: number;
|
|
54
|
+
/** Refresh token if provided by vendor */
|
|
55
|
+
refreshToken?: string;
|
|
56
|
+
/** Additional vendor-specific data */
|
|
57
|
+
metadata?: Record<string, unknown>;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Error response from remote authentication
|
|
61
|
+
*/
|
|
62
|
+
interface RemoteAuthError {
|
|
63
|
+
vendorId: string;
|
|
64
|
+
error: string;
|
|
65
|
+
errorDescription?: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Options for remote auth request
|
|
69
|
+
*/
|
|
70
|
+
interface RemoteAuthOptions {
|
|
71
|
+
/** Timeout in milliseconds (default: 60000) */
|
|
72
|
+
timeout?: number;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Authentication interface with remote vendor authentication support.
|
|
76
|
+
* Remote apps use this to authenticate with third-party systems.
|
|
77
|
+
*/
|
|
78
|
+
interface HorizonAuth {
|
|
79
|
+
isAuthenticated: () => boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Request authentication with a remote vendor system.
|
|
82
|
+
* Returns a promise that resolves when vendor auth completes.
|
|
83
|
+
*
|
|
84
|
+
* @param request - Configuration for the auth request
|
|
85
|
+
* @param options - Optional timeout and retry configuration
|
|
86
|
+
* @returns Promise<RemoteAuthResponse>
|
|
87
|
+
* @throws RemoteAuthError if authentication fails
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* const response = await auth.requestRemoteAuth({
|
|
91
|
+
* vendorId: 'salesforce',
|
|
92
|
+
* callbackUrl: 'https://vendor.example.com/oauth/callback',
|
|
93
|
+
* scopes: ['read', 'write']
|
|
94
|
+
* });
|
|
95
|
+
* // Use response.accessToken for vendor API calls
|
|
96
|
+
*/
|
|
97
|
+
requestRemoteAuth: (request: RemoteAuthRequest, options?: RemoteAuthOptions) => Promise<RemoteAuthResponse>;
|
|
98
|
+
/**
|
|
99
|
+
* Get stored token for a vendor (if previously authenticated)
|
|
100
|
+
*/
|
|
101
|
+
getRemoteAuthToken: (vendorId: string) => RemoteAuthResponse | null;
|
|
102
|
+
/**
|
|
103
|
+
* Clear stored token for a vendor (logout)
|
|
104
|
+
*/
|
|
105
|
+
clearRemoteAuthToken: (vendorId: string) => void;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Authenticated client for NetSapiens v2 API calls. Routed through the host's
|
|
109
|
+
* audited proxy — remote apps never see credentials directly.
|
|
110
|
+
*/
|
|
111
|
+
interface HorizonApiClient {
|
|
112
|
+
get: <T = unknown>(path: string, params?: Record<string, unknown>) => Promise<T>;
|
|
113
|
+
post: <T = unknown>(path: string, data: unknown) => Promise<T>;
|
|
114
|
+
put: <T = unknown>(path: string, data: unknown) => Promise<T>;
|
|
115
|
+
delete: <T = unknown>(path: string) => Promise<T>;
|
|
116
|
+
getBaseUrl: () => string;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Pub/sub event bus used for everything that crosses the host/remote boundary:
|
|
120
|
+
* route registration, dynamic extension registration, theme changes, call
|
|
121
|
+
* events, and app-defined custom events.
|
|
122
|
+
*/
|
|
123
|
+
interface HorizonEventBus {
|
|
124
|
+
emit: (event: string, data?: unknown) => void;
|
|
125
|
+
on: (event: string, handler: (data: unknown) => void) => void;
|
|
126
|
+
off: (event: string, handler: (data: unknown) => void) => void;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Theme tokens for advanced styling. Remote apps usually consume these
|
|
130
|
+
* indirectly through `ui.styles`.
|
|
131
|
+
*/
|
|
132
|
+
interface ThemeTokens {
|
|
133
|
+
colors: Record<string, unknown>;
|
|
134
|
+
spacing: Record<string, string>;
|
|
135
|
+
typography: Record<string, unknown>;
|
|
136
|
+
borderRadius: Record<string, string>;
|
|
137
|
+
shadows: Record<string, string>;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* UI templates and primitives provided by the host. Remote apps render these
|
|
141
|
+
* components instead of bringing their own MUI/styling stack — that keeps the
|
|
142
|
+
* remote bundle small and ensures visual consistency with Horizon.
|
|
143
|
+
*/
|
|
144
|
+
interface HorizonUITemplates {
|
|
145
|
+
PageTemplate: React.ComponentType<unknown>;
|
|
146
|
+
PageTemplateWithExtensions: React.ComponentType<unknown>;
|
|
147
|
+
FormTemplate: React.ComponentType<unknown>;
|
|
148
|
+
SideTrayTemplate: React.ComponentType<unknown>;
|
|
149
|
+
DatagridTemplate: React.ComponentType<unknown>;
|
|
150
|
+
Icon: React.ComponentType<{
|
|
151
|
+
name: string;
|
|
152
|
+
size?: number | string;
|
|
153
|
+
color?: string;
|
|
154
|
+
}>;
|
|
155
|
+
SideTrayComponents: {
|
|
156
|
+
Section: React.ComponentType<{
|
|
157
|
+
title?: string;
|
|
158
|
+
children: React.ReactNode;
|
|
159
|
+
}>;
|
|
160
|
+
Field: React.ComponentType<{
|
|
161
|
+
label: string;
|
|
162
|
+
value?: React.ReactNode;
|
|
163
|
+
}>;
|
|
164
|
+
Input: React.ComponentType<{
|
|
165
|
+
label?: string;
|
|
166
|
+
placeholder?: string;
|
|
167
|
+
value?: string;
|
|
168
|
+
onChange?: (value: string) => void;
|
|
169
|
+
helperText?: string;
|
|
170
|
+
error?: boolean;
|
|
171
|
+
required?: boolean;
|
|
172
|
+
disabled?: boolean;
|
|
173
|
+
type?: string;
|
|
174
|
+
multiline?: boolean;
|
|
175
|
+
rows?: number;
|
|
176
|
+
}>;
|
|
177
|
+
Button: React.ComponentType<unknown>;
|
|
178
|
+
UserCard: React.ComponentType<{
|
|
179
|
+
avatarUrl?: string;
|
|
180
|
+
name: string;
|
|
181
|
+
subtitle?: string;
|
|
182
|
+
trailing?: React.ReactNode;
|
|
183
|
+
}>;
|
|
184
|
+
Divider: React.ComponentType;
|
|
185
|
+
};
|
|
186
|
+
PageComponents: Record<string, React.ComponentType<unknown>>;
|
|
187
|
+
}
|
|
188
|
+
interface HorizonUI {
|
|
189
|
+
templates: HorizonUITemplates;
|
|
190
|
+
theme?: ThemeTokens;
|
|
191
|
+
/** Pre-built semantic style objects derived from the active theme */
|
|
192
|
+
styles?: Record<string, unknown>;
|
|
193
|
+
/** Individual MUI-backed components for direct use */
|
|
194
|
+
Button?: React.ComponentType<unknown>;
|
|
195
|
+
/**
|
|
196
|
+
* Pre-themed IconButton. Takes the icon name as a string prop — children
|
|
197
|
+
* are intentionally not supported. Renders an Iconify icon inside an MUI
|
|
198
|
+
* IconButton with the host's Aurora theming applied.
|
|
199
|
+
*
|
|
200
|
+
* ```tsx
|
|
201
|
+
* <IconButton icon="mdi:account" aria-label="Account" />
|
|
202
|
+
* ```
|
|
203
|
+
*
|
|
204
|
+
* Do NOT use the MUI children pattern (`<IconButton><Icon ... /></IconButton>`) —
|
|
205
|
+
* it will render an empty button at 0×0 because children are dropped.
|
|
206
|
+
*/
|
|
207
|
+
IconButton?: React.ComponentType<{
|
|
208
|
+
icon: string;
|
|
209
|
+
iconSize?: number | string;
|
|
210
|
+
'aria-label'?: string;
|
|
211
|
+
color?: 'default' | 'inherit' | 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning';
|
|
212
|
+
disabled?: boolean;
|
|
213
|
+
edge?: 'start' | 'end' | false;
|
|
214
|
+
size?: 'small' | 'medium' | 'large';
|
|
215
|
+
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
|
|
216
|
+
sx?: Record<string, unknown>;
|
|
217
|
+
}>;
|
|
218
|
+
TextField?: React.ComponentType<unknown>;
|
|
219
|
+
Select?: React.ComponentType<unknown>;
|
|
220
|
+
Checkbox?: React.ComponentType<unknown>;
|
|
221
|
+
Radio?: React.ComponentType<unknown>;
|
|
222
|
+
RadioGroup?: React.ComponentType<unknown>;
|
|
223
|
+
Switch?: React.ComponentType<unknown>;
|
|
224
|
+
ToggleButton?: React.ComponentType<unknown>;
|
|
225
|
+
ToggleButtonGroup?: React.ComponentType<unknown>;
|
|
226
|
+
FormLabel?: React.ComponentType<unknown>;
|
|
227
|
+
Typography?: React.ComponentType<unknown>;
|
|
228
|
+
Chip?: React.ComponentType<unknown>;
|
|
229
|
+
Avatar?: React.ComponentType<unknown>;
|
|
230
|
+
Divider?: React.ComponentType<unknown>;
|
|
231
|
+
Tooltip?: React.ComponentType<unknown>;
|
|
232
|
+
Stack?: React.ComponentType<unknown>;
|
|
233
|
+
Paper?: React.ComponentType<unknown>;
|
|
234
|
+
/** General-purpose layout primitive with sx prop support. Use this instead of
|
|
235
|
+
* importing Box directly from @mui/material in a remote app. */
|
|
236
|
+
Box?: React.ComponentType<unknown>;
|
|
237
|
+
Alert?: React.ComponentType<unknown>;
|
|
238
|
+
Icon?: React.ComponentType<unknown>;
|
|
239
|
+
}
|
|
240
|
+
interface BreadcrumbItem {
|
|
241
|
+
label: string;
|
|
242
|
+
url?: string;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* The object passed to a remote app's exported `App` component as props.
|
|
246
|
+
* Construct this in the host (see HorizonAppsLoader) — never construct it
|
|
247
|
+
* inside a remote app.
|
|
248
|
+
*/
|
|
249
|
+
interface HorizonContext {
|
|
250
|
+
user: HorizonUser;
|
|
251
|
+
auth: HorizonAuth;
|
|
252
|
+
api: HorizonApiClient;
|
|
253
|
+
theme: 'light' | 'dark';
|
|
254
|
+
locale: string;
|
|
255
|
+
/**
|
|
256
|
+
* Host's i18next translation function. All host strings (common, telecom,
|
|
257
|
+
* admin, validation namespaces) are available immediately — no i18next
|
|
258
|
+
* dependency or install required in the remote app.
|
|
259
|
+
* Use via the `useLocale()` SDK hook rather than calling directly.
|
|
260
|
+
*/
|
|
261
|
+
t?: (key: string, options?: Record<string, unknown>) => string;
|
|
262
|
+
navigate: (path: string) => void;
|
|
263
|
+
eventBus: HorizonEventBus;
|
|
264
|
+
ui: HorizonUI;
|
|
265
|
+
breadcrumbs?: BreadcrumbItem[];
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Semantic placement for menu items.
|
|
269
|
+
* Allows positioning relative to existing items using anchor-based placement.
|
|
270
|
+
*/
|
|
271
|
+
interface SemanticPlacement {
|
|
272
|
+
/** Place immediately after this anchor */
|
|
273
|
+
after?: string;
|
|
274
|
+
/** Place immediately before this anchor */
|
|
275
|
+
before?: string;
|
|
276
|
+
/** Force to start of menu */
|
|
277
|
+
first?: boolean;
|
|
278
|
+
/** Force to end of menu */
|
|
279
|
+
last?: boolean;
|
|
280
|
+
}
|
|
281
|
+
interface RouteConfig {
|
|
282
|
+
/** Unique route identifier (recommend prefixing with appId) */
|
|
283
|
+
id: string;
|
|
284
|
+
/** App identifier — set automatically by RemoteAppSDK */
|
|
285
|
+
appId: string;
|
|
286
|
+
/** Parent path to attach under (e.g., '/apps', '/home/settings') */
|
|
287
|
+
parentPath: string;
|
|
288
|
+
/** Route segment (e.g., 'my-feature') */
|
|
289
|
+
path: string;
|
|
290
|
+
/** Navigation label */
|
|
291
|
+
label: string;
|
|
292
|
+
/** Component rendered when this route is active */
|
|
293
|
+
component: React.ComponentType<unknown>;
|
|
294
|
+
/** Iconify icon name (e.g., 'mdi:cog') */
|
|
295
|
+
icon?: string;
|
|
296
|
+
/**
|
|
297
|
+
* Semantic placement for positioning in menus (e.g., { after: 'contacts' }).
|
|
298
|
+
* Supports fuzzy matching with 0.8 similarity threshold.
|
|
299
|
+
* If not specified or anchor not found, item is placed at end of menu.
|
|
300
|
+
*/
|
|
301
|
+
placement?: SemanticPlacement;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Webpack Module Federation reference for `useRouteFromModule`.
|
|
305
|
+
*/
|
|
306
|
+
interface RemoteModuleConfig {
|
|
307
|
+
scope: string;
|
|
308
|
+
module: string;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Generic extension zones available throughout Horizon. Pages may also define
|
|
312
|
+
* custom string zone IDs — `ExtensionZone` accepts both.
|
|
313
|
+
*/
|
|
314
|
+
type ExtensionZoneId = 'page-header-actions' | 'page-header-secondary' | 'page-content-before' | 'page-content-after' | 'page-sidebar' | 'table-row-actions' | 'table-toolbar' | 'detail-panel-tabs' | 'detail-panel-actions' | 'inbound-call-content' | 'topbar-actions' | 'form-section-before' | 'form-section-after';
|
|
315
|
+
type ExtensionZone = ExtensionZoneId | (string & {});
|
|
316
|
+
/**
|
|
317
|
+
* Route pattern with wildcard (`*`) and named-parameter (`:param`) support.
|
|
318
|
+
* Example patterns: `/manage/call-logs`, `/manage/*\/call-logs`, `/manage/:domain/users`.
|
|
319
|
+
*/
|
|
320
|
+
interface RoutePattern {
|
|
321
|
+
pattern: string;
|
|
322
|
+
/** Require an exact match (default: prefix match) */
|
|
323
|
+
exact?: boolean;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Context passed to extension components when they render.
|
|
327
|
+
*/
|
|
328
|
+
interface ExtensionContext {
|
|
329
|
+
route: string;
|
|
330
|
+
params: Record<string, string>;
|
|
331
|
+
user: {
|
|
332
|
+
domain: string;
|
|
333
|
+
username: string;
|
|
334
|
+
scopes: string[];
|
|
335
|
+
};
|
|
336
|
+
pageContext?: unknown;
|
|
337
|
+
ui?: HorizonUI;
|
|
338
|
+
eventBus?: HorizonEventBus;
|
|
339
|
+
/** Current color scheme — reactive to host theme changes. */
|
|
340
|
+
theme: 'light' | 'dark';
|
|
341
|
+
/** Host's i18next translation function — all host strings available immediately. */
|
|
342
|
+
t?: (key: string, options?: Record<string, unknown>) => string;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Props passed to extension components.
|
|
346
|
+
*/
|
|
347
|
+
interface ExtensionComponentProps {
|
|
348
|
+
context: ExtensionContext;
|
|
349
|
+
zone: ExtensionZone;
|
|
350
|
+
/** Provided by modal/dialog hosts to allow extensions to dismiss themselves */
|
|
351
|
+
close?: () => void;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Payload accepted by `sdk.registerDynamicExtension`. `appId` is filled in by
|
|
355
|
+
* the SDK from the value passed to `createRemoteAppSDK`.
|
|
356
|
+
*/
|
|
357
|
+
interface DynamicExtensionConfig {
|
|
358
|
+
/** Unique extension ID (recommend prefixing with appId) */
|
|
359
|
+
id: string;
|
|
360
|
+
/** Target zone — generic or page-defined */
|
|
361
|
+
zone: ExtensionZone;
|
|
362
|
+
/** Routes this extension applies to */
|
|
363
|
+
routes: RoutePattern[];
|
|
364
|
+
/** Render order within a zone (higher = first) */
|
|
365
|
+
priority?: number;
|
|
366
|
+
/** Component rendered for each match */
|
|
367
|
+
component: React.ComponentType<ExtensionComponentProps>;
|
|
368
|
+
/** Permissions the user must have for this extension to render */
|
|
369
|
+
requiredPermissions?: string[];
|
|
370
|
+
/** Optional gate evaluated at render time */
|
|
371
|
+
condition?: (context: ExtensionContext) => boolean;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Dynamic table column definition. Mirrors a subset of MUI X DataGrid's column
|
|
375
|
+
* shape — kept as `Record<string, unknown>`-friendly so the SDK doesn't pull
|
|
376
|
+
* in MUI types.
|
|
377
|
+
*/
|
|
378
|
+
interface DynamicColumnDefinition {
|
|
379
|
+
field: string;
|
|
380
|
+
headerName: string;
|
|
381
|
+
width?: number;
|
|
382
|
+
minWidth?: number;
|
|
383
|
+
maxWidth?: number;
|
|
384
|
+
flex?: number;
|
|
385
|
+
sortable?: boolean;
|
|
386
|
+
filterable?: boolean;
|
|
387
|
+
hideable?: boolean;
|
|
388
|
+
resizable?: boolean;
|
|
389
|
+
type?: 'string' | 'number' | 'date' | 'dateTime' | 'boolean';
|
|
390
|
+
align?: 'left' | 'center' | 'right';
|
|
391
|
+
headerAlign?: 'left' | 'center' | 'right';
|
|
392
|
+
renderCell?: (params: {
|
|
393
|
+
row: Record<string, unknown>;
|
|
394
|
+
value?: unknown;
|
|
395
|
+
}) => React.ReactNode;
|
|
396
|
+
valueGetter?: (value: unknown, row: Record<string, unknown>) => unknown;
|
|
397
|
+
valueFormatter?: (value: unknown) => string;
|
|
398
|
+
initiallyVisible?: boolean;
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Payload accepted by `sdk.registerDynamicColumn`.
|
|
402
|
+
*/
|
|
403
|
+
interface DynamicColumnConfig {
|
|
404
|
+
id: string;
|
|
405
|
+
zone: string;
|
|
406
|
+
routes: RoutePattern[];
|
|
407
|
+
column: DynamicColumnDefinition;
|
|
408
|
+
priority?: number;
|
|
409
|
+
condition?: (context: ExtensionContext) => boolean;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Remote App SDK.
|
|
414
|
+
*
|
|
415
|
+
* Wraps Horizon's event bus with a typed, app-scoped API for registering routes
|
|
416
|
+
* and dynamic extensions. Tracks every registration so `cleanup()` can tear
|
|
417
|
+
* everything down on unmount — essential when a remote app is reloaded or its
|
|
418
|
+
* webpack module is replaced during HMR.
|
|
419
|
+
*/
|
|
420
|
+
|
|
421
|
+
declare class RemoteAppSDK {
|
|
422
|
+
private eventBus;
|
|
423
|
+
private appId;
|
|
424
|
+
private routes;
|
|
425
|
+
private dynamicExtensions;
|
|
426
|
+
private dynamicColumns;
|
|
427
|
+
constructor(eventBus: HorizonEventBus, appId: string);
|
|
428
|
+
registerRoute(config: Omit<RouteConfig, 'appId'>): Promise<void>;
|
|
429
|
+
unregisterRoute(routeId: string): void;
|
|
430
|
+
/**
|
|
431
|
+
* Convenience: load a component out of a federated module's webpack
|
|
432
|
+
* container and register it as a route in one step. Useful when the route
|
|
433
|
+
* component lives in a sibling exposed module rather than the entry App.
|
|
434
|
+
*/
|
|
435
|
+
registerRouteFromModule(routeConfig: Omit<RouteConfig, 'appId' | 'component'>, moduleConfig: RemoteModuleConfig): Promise<void>;
|
|
436
|
+
registerDynamicExtension(config: Omit<DynamicExtensionConfig, 'appId'>): void;
|
|
437
|
+
unregisterDynamicExtension(extensionId: string): void;
|
|
438
|
+
registerDynamicColumn(config: Omit<DynamicColumnConfig, 'appId'>): void;
|
|
439
|
+
unregisterDynamicColumn(columnId: string): void;
|
|
440
|
+
/**
|
|
441
|
+
* Unregister everything this SDK instance has registered. Call from your
|
|
442
|
+
* remote app's unmount/cleanup path — `useRemoteApp` does this for you.
|
|
443
|
+
*/
|
|
444
|
+
cleanup(): void;
|
|
445
|
+
getAppId(): string;
|
|
446
|
+
getRegisteredRoutes(): string[];
|
|
447
|
+
getRegisteredDynamicExtensions(): string[];
|
|
448
|
+
getRegisteredDynamicColumns(): string[];
|
|
449
|
+
}
|
|
450
|
+
/** Factory: equivalent to `new RemoteAppSDK(...)`. */
|
|
451
|
+
declare function createRemoteAppSDK(eventBus: HorizonEventBus, appId: string): RemoteAppSDK;
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Wrap your registered page components with this provider so they receive a
|
|
455
|
+
* reactive HorizonContext without any extra event-listener boilerplate.
|
|
456
|
+
*
|
|
457
|
+
* The component memoization pattern in App.tsx captures `horizonContext` once
|
|
458
|
+
* (to keep stable component identity), but `eventBus` is a singleton — the
|
|
459
|
+
* Provider subscribes to it and pushes theme updates to all descendant pages.
|
|
460
|
+
*
|
|
461
|
+
* @example
|
|
462
|
+
* // In App.tsx, inside useMemo with empty deps:
|
|
463
|
+
* return (
|
|
464
|
+
* <HorizonContextProvider context={horizonContext}>
|
|
465
|
+
* <MyPage />
|
|
466
|
+
* </HorizonContextProvider>
|
|
467
|
+
* );
|
|
468
|
+
*/
|
|
469
|
+
declare function HorizonContextProvider({ context, children, }: {
|
|
470
|
+
context: HorizonContext;
|
|
471
|
+
children: ReactNode;
|
|
472
|
+
}): React.FunctionComponentElement<React.ProviderProps<HorizonContext | null>>;
|
|
473
|
+
/**
|
|
474
|
+
* Read the live HorizonContext inside any page registered via the SDK.
|
|
475
|
+
* Returns a context that updates automatically when dark mode changes.
|
|
476
|
+
*
|
|
477
|
+
* Must be called inside a component rendered within `HorizonContextProvider`.
|
|
478
|
+
*
|
|
479
|
+
* @example
|
|
480
|
+
* export default function MyPage() {
|
|
481
|
+
* const { ui, theme, user, navigate } = useHorizonContext();
|
|
482
|
+
* const { PageTemplate, DatagridTemplate } = ui.templates;
|
|
483
|
+
* // `theme` is always 'light' | 'dark', reactive to system/user toggle
|
|
484
|
+
* }
|
|
485
|
+
*/
|
|
486
|
+
declare function useHorizonContext(): HorizonContext;
|
|
487
|
+
/**
|
|
488
|
+
* Returns the current color scheme, reactive to host theme changes.
|
|
489
|
+
*
|
|
490
|
+
* Works in **both** contexts with the same import — no manual event wiring:
|
|
491
|
+
*
|
|
492
|
+
* - **Page components** (inside `HorizonContextProvider`): reads directly from
|
|
493
|
+
* the provider's React context. No subscription overhead.
|
|
494
|
+
* - **Standalone extension components** (rendered by the host via
|
|
495
|
+
* `registerDynamicExtension`): falls back to `eventBus` subscription.
|
|
496
|
+
* Pass `context.eventBus` as the argument.
|
|
497
|
+
*
|
|
498
|
+
* @example
|
|
499
|
+
* // In a page component (HorizonContextProvider ancestor required)
|
|
500
|
+
* export default function MyPage() {
|
|
501
|
+
* const { theme } = useTheme();
|
|
502
|
+
* return <div style={{ color: theme === 'dark' ? '#fff' : '#000' }}>...</div>;
|
|
503
|
+
* }
|
|
504
|
+
*
|
|
505
|
+
* @example
|
|
506
|
+
* // In a standalone extension component
|
|
507
|
+
* export default function MyButton({ context }: ExtensionComponentProps) {
|
|
508
|
+
* const { theme } = useTheme(context.eventBus);
|
|
509
|
+
* const { Button } = context.ui ?? {};
|
|
510
|
+
* return <Button>{theme === 'dark' ? '🌙' : '☀️'} Export</Button>;
|
|
511
|
+
* }
|
|
512
|
+
*/
|
|
513
|
+
/**
|
|
514
|
+
* Returns the current color scheme, reactive to host theme changes.
|
|
515
|
+
*
|
|
516
|
+
* @param eventBus - Pass `context.eventBus` when called from a standalone
|
|
517
|
+
* extension component (outside a HorizonContextProvider).
|
|
518
|
+
* @param initialTheme - Pass `context.theme` when called from a standalone
|
|
519
|
+
* extension component so the hook initialises with the correct value on
|
|
520
|
+
* first render rather than defaulting to `'light'`.
|
|
521
|
+
*
|
|
522
|
+
* Inside a page component wrapped by `HorizonContextProvider`, both params
|
|
523
|
+
* can be omitted — the provider context is used automatically.
|
|
524
|
+
*/
|
|
525
|
+
declare function useTheme(eventBus?: HorizonContext['eventBus'], initialTheme?: 'light' | 'dark'): {
|
|
526
|
+
theme: 'light' | 'dark';
|
|
527
|
+
};
|
|
528
|
+
/**
|
|
529
|
+
* Returns the host's translation function and current locale.
|
|
530
|
+
*
|
|
531
|
+
* Because `i18next` is shared as a singleton, this hook reads directly from
|
|
532
|
+
* the host's already-initialized i18next instance — all host translations
|
|
533
|
+
* (common, telecom, admin, etc.) are immediately available with no extra
|
|
534
|
+
* fetch or setup required.
|
|
535
|
+
*
|
|
536
|
+
* Reactivity is handled internally by react-i18next: the returned `t` and
|
|
537
|
+
* `locale` update automatically when the user switches language.
|
|
538
|
+
*
|
|
539
|
+
* @param ns - Optional namespace(s). Defaults to `'common'` (the host
|
|
540
|
+
* namespace that contains all standard UI strings). Pass your app's own
|
|
541
|
+
* registered namespace to access remote-app-specific keys.
|
|
542
|
+
*
|
|
543
|
+
* @example
|
|
544
|
+
* // In a page component — access any host string
|
|
545
|
+
* export default function MyPage() {
|
|
546
|
+
* const { t, locale } = useLocale();
|
|
547
|
+
* return <Button>{t('SAVE')}</Button>;
|
|
548
|
+
* }
|
|
549
|
+
*
|
|
550
|
+
* @example
|
|
551
|
+
* // In an extension component — same API
|
|
552
|
+
* export function MyButton({ context }: ExtensionComponentProps) {
|
|
553
|
+
* const { t } = useLocale();
|
|
554
|
+
* const { Button } = context.ui ?? {};
|
|
555
|
+
* return <Button>{t('EXPORT')}</Button>;
|
|
556
|
+
* }
|
|
557
|
+
*/
|
|
558
|
+
/**
|
|
559
|
+
* Returns the host's `t` translation function and current locale string.
|
|
560
|
+
*
|
|
561
|
+
* The `t` function is the host's i18next instance — all 1,375+ host strings
|
|
562
|
+
* across the common, telecom, admin, and validation namespaces are immediately
|
|
563
|
+
* available. No i18next dependency, no package install, no init required in
|
|
564
|
+
* the remote app.
|
|
565
|
+
*
|
|
566
|
+
* Both `t` and `locale` update automatically when the user switches language.
|
|
567
|
+
*
|
|
568
|
+
* @example
|
|
569
|
+
* export default function MyPage() {
|
|
570
|
+
* const { t, locale } = useLocale();
|
|
571
|
+
* return <Button>{t('SAVE')}</Button>;
|
|
572
|
+
* }
|
|
573
|
+
*
|
|
574
|
+
* @example
|
|
575
|
+
* // In a standalone extension component
|
|
576
|
+
* export function MyButton({ context }: ExtensionComponentProps) {
|
|
577
|
+
* const { t } = useLocale();
|
|
578
|
+
* return <span>{t('EXPORT')}</span>;
|
|
579
|
+
* }
|
|
580
|
+
*/
|
|
581
|
+
declare function useLocale(): {
|
|
582
|
+
t: HorizonContext['t'];
|
|
583
|
+
locale: string;
|
|
584
|
+
};
|
|
585
|
+
/**
|
|
586
|
+
* Get an SDK instance bound to your app, plus a flat view of the Horizon
|
|
587
|
+
* context. Returned `sdk.cleanup()` is called automatically on unmount.
|
|
588
|
+
*
|
|
589
|
+
* @example
|
|
590
|
+
* export default function MyApp(horizonContext: HorizonContext) {
|
|
591
|
+
* const { sdk, user } = useRemoteApp(horizonContext, 'my-app');
|
|
592
|
+
*
|
|
593
|
+
* useEffect(() => {
|
|
594
|
+
* sdk.registerDynamicExtension({
|
|
595
|
+
* id: 'my-app.button',
|
|
596
|
+
* zone: 'page-header-actions',
|
|
597
|
+
* routes: [{ pattern: '/manage/*\/users' }],
|
|
598
|
+
* component: MyButton,
|
|
599
|
+
* });
|
|
600
|
+
* }, [sdk]);
|
|
601
|
+
*
|
|
602
|
+
* return <div>Hello {user.displayName}</div>;
|
|
603
|
+
* }
|
|
604
|
+
*/
|
|
605
|
+
declare function useRemoteApp(horizonContext: HorizonContext, appId: string): {
|
|
606
|
+
user: HorizonUser;
|
|
607
|
+
auth: HorizonAuth;
|
|
608
|
+
api: HorizonApiClient;
|
|
609
|
+
theme: "light" | "dark";
|
|
610
|
+
locale: string;
|
|
611
|
+
t?: (key: string, options?: Record<string, unknown>) => string;
|
|
612
|
+
navigate: (path: string) => void;
|
|
613
|
+
eventBus: HorizonEventBus;
|
|
614
|
+
ui: HorizonUI;
|
|
615
|
+
breadcrumbs?: BreadcrumbItem[];
|
|
616
|
+
sdk: RemoteAppSDK;
|
|
617
|
+
};
|
|
618
|
+
/**
|
|
619
|
+
* Register a route for the lifetime of the calling component.
|
|
620
|
+
*/
|
|
621
|
+
declare function useRoute(eventBus: HorizonContext['eventBus'], appId: string, config: Omit<RouteConfig, 'appId'>): RemoteAppSDK;
|
|
622
|
+
/**
|
|
623
|
+
* Register a route by pulling its component out of a federated module's
|
|
624
|
+
* webpack container.
|
|
625
|
+
*/
|
|
626
|
+
declare function useRouteFromModule(eventBus: HorizonContext['eventBus'], appId: string, routeConfig: Omit<RouteConfig, 'appId' | 'component'>, moduleConfig: RemoteModuleConfig): {
|
|
627
|
+
loading: boolean;
|
|
628
|
+
error: Error | null;
|
|
629
|
+
sdk: RemoteAppSDK;
|
|
630
|
+
};
|
|
631
|
+
/**
|
|
632
|
+
* Register a dynamic extension (pattern-based UI injection) for the lifetime
|
|
633
|
+
* of the calling component.
|
|
634
|
+
*/
|
|
635
|
+
declare function useDynamicExtension(eventBus: HorizonContext['eventBus'], appId: string, config: Omit<DynamicExtensionConfig, 'appId'>): RemoteAppSDK;
|
|
636
|
+
/**
|
|
637
|
+
* Register a dynamic table column for the lifetime of the calling component.
|
|
638
|
+
*/
|
|
639
|
+
declare function useDynamicColumn(eventBus: HorizonContext['eventBus'], appId: string, config: Omit<DynamicColumnConfig, 'appId'>): RemoteAppSDK;
|
|
640
|
+
|
|
641
|
+
/**
|
|
642
|
+
* Federation Error
|
|
643
|
+
* Structured error class with error codes for better error handling
|
|
644
|
+
*/
|
|
645
|
+
type HorizonSDKErrorCode = 'PERMISSION_DENIED' | 'RATE_LIMIT_EXCEEDED' | 'INVALID_MESSAGE' | 'SIGNATURE_VERIFICATION_FAILED' | 'API_ERROR' | 'NETWORK_ERROR' | 'INVALID_EXTENSION_POINT' | 'INVALID_CONFIGURATION' | 'APP_NOT_FOUND' | 'MODULE_LOAD_FAILED' | 'INITIALIZATION_FAILED' | 'UNKNOWN_ERROR';
|
|
646
|
+
interface HorizonSDKErrorOptions {
|
|
647
|
+
code: HorizonSDKErrorCode;
|
|
648
|
+
message: string;
|
|
649
|
+
details?: Record<string, unknown>;
|
|
650
|
+
cause?: Error;
|
|
651
|
+
statusCode?: number;
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* HorizonSDKError class
|
|
655
|
+
* Provides structured errors with error codes and additional context
|
|
656
|
+
*/
|
|
657
|
+
declare class HorizonSDKError extends Error {
|
|
658
|
+
readonly code: HorizonSDKErrorCode;
|
|
659
|
+
readonly details?: Record<string, unknown>;
|
|
660
|
+
readonly cause?: Error;
|
|
661
|
+
readonly statusCode?: number;
|
|
662
|
+
readonly timestamp: string;
|
|
663
|
+
constructor(options: HorizonSDKErrorOptions);
|
|
664
|
+
/**
|
|
665
|
+
* Check if error is a HorizonSDKError
|
|
666
|
+
*/
|
|
667
|
+
static isHorizonSDKError(error: unknown): error is HorizonSDKError;
|
|
668
|
+
/**
|
|
669
|
+
* Get user-friendly error message
|
|
670
|
+
*/
|
|
671
|
+
getUserMessage(): string;
|
|
672
|
+
/**
|
|
673
|
+
* Serialize error to JSON
|
|
674
|
+
*/
|
|
675
|
+
toJSON(): object;
|
|
676
|
+
/**
|
|
677
|
+
* Get formatted error message for logging
|
|
678
|
+
*/
|
|
679
|
+
toLogString(): string;
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* Helper function to create HorizonSDKError instances
|
|
683
|
+
*/
|
|
684
|
+
declare function createHorizonSDKError(code: HorizonSDKErrorCode, message: string, details?: Record<string, unknown>, cause?: Error): HorizonSDKError;
|
|
685
|
+
/**
|
|
686
|
+
* Permission Denied Error
|
|
687
|
+
*/
|
|
688
|
+
declare function permissionDeniedError(resource: string, details?: Record<string, unknown>): HorizonSDKError;
|
|
689
|
+
/**
|
|
690
|
+
* Rate Limit Exceeded Error
|
|
691
|
+
*/
|
|
692
|
+
declare function rateLimitError(resetTime: number, details?: Record<string, unknown>): HorizonSDKError;
|
|
693
|
+
/**
|
|
694
|
+
* API Error
|
|
695
|
+
*/
|
|
696
|
+
declare function apiError(message: string, statusCode: number, details?: Record<string, unknown>, cause?: Error): HorizonSDKError;
|
|
697
|
+
/**
|
|
698
|
+
* Invalid Extension Point Error
|
|
699
|
+
*/
|
|
700
|
+
declare function invalidExtensionPointError(pointId: string, validPoints: string[]): HorizonSDKError;
|
|
701
|
+
/**
|
|
702
|
+
* Signature Verification Failed Error
|
|
703
|
+
*/
|
|
704
|
+
declare function signatureVerificationError(reason: string): HorizonSDKError;
|
|
705
|
+
/**
|
|
706
|
+
* Module Load Failed Error
|
|
707
|
+
*/
|
|
708
|
+
declare function moduleLoadError(appId: string, url: string, cause?: Error): HorizonSDKError;
|
|
709
|
+
|
|
710
|
+
/**
|
|
711
|
+
* Logging utility using loglevel for Horizon SDK
|
|
712
|
+
* Consistent with netsapiens-monorepo logging pattern
|
|
713
|
+
*
|
|
714
|
+
* Usage:
|
|
715
|
+
* import { createLogger } from '../utils/logger';
|
|
716
|
+
* const log = createLogger('ModuleLoader');
|
|
717
|
+
* log.info('Loading module...');
|
|
718
|
+
* log.error('Failed to load:', error);
|
|
719
|
+
*/
|
|
720
|
+
|
|
721
|
+
/**
|
|
722
|
+
* Create a namespaced logger for a specific module
|
|
723
|
+
* Follows the monorepo pattern from @netsapiens/ns-sdk
|
|
724
|
+
*
|
|
725
|
+
* @example
|
|
726
|
+
* const log = createLogger('ModuleLoader');
|
|
727
|
+
* log.debug('Starting load...');
|
|
728
|
+
* log.info('Module loaded successfully');
|
|
729
|
+
* log.warn('Slow load detected');
|
|
730
|
+
* log.error('Load failed:', error);
|
|
731
|
+
*/
|
|
732
|
+
declare const createLogger: (namespace: string) => loglevel.Logger;
|
|
733
|
+
/**
|
|
734
|
+
* Default logger instance for the SDK
|
|
735
|
+
*/
|
|
736
|
+
declare const logger: loglevel.Logger;
|
|
737
|
+
/**
|
|
738
|
+
* Set log level at runtime
|
|
739
|
+
* Useful for debugging
|
|
740
|
+
*
|
|
741
|
+
* @example
|
|
742
|
+
* import { setLogLevel } from './utils/logger';
|
|
743
|
+
* setLogLevel('DEBUG'); // Enable all logs
|
|
744
|
+
* setLogLevel('WARN'); // Only warnings and errors
|
|
745
|
+
*/
|
|
746
|
+
declare const setLogLevel: (level: "TRACE" | "DEBUG" | "INFO" | "WARN" | "ERROR" | "SILENT") => void;
|
|
747
|
+
/**
|
|
748
|
+
* Get current log level
|
|
749
|
+
*/
|
|
750
|
+
declare const getLogLevel: () => 0 | 1 | 2 | 3 | 4 | 5;
|
|
751
|
+
declare global {
|
|
752
|
+
interface Window {
|
|
753
|
+
__horizonSDKLogger__: typeof logger;
|
|
754
|
+
__setHorizonSDKLogLevel__: typeof setLogLevel;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
/**
|
|
759
|
+
* Stable Anchor IDs for Extension Placement
|
|
760
|
+
*
|
|
761
|
+
* These anchor IDs are guaranteed to be stable and can be used by extensions
|
|
762
|
+
* to specify their menu placement using semantic anchors.
|
|
763
|
+
*
|
|
764
|
+
* @example
|
|
765
|
+
* ```typescript
|
|
766
|
+
* import { MANAGE_ANCHORS } from '@netsapiens/horizon-sdk';
|
|
767
|
+
*
|
|
768
|
+
* sdk.registerRoute({
|
|
769
|
+
* id: 'my-crm',
|
|
770
|
+
* parentPath: '/apps',
|
|
771
|
+
* path: 'crm',
|
|
772
|
+
* label: 'CRM',
|
|
773
|
+
* placement: { after: MANAGE_ANCHORS.contacts }
|
|
774
|
+
* });
|
|
775
|
+
* ```
|
|
776
|
+
*/
|
|
777
|
+
/**
|
|
778
|
+
* Manage Menu Anchors
|
|
779
|
+
* Available in both domain and no-domain contexts
|
|
780
|
+
*/
|
|
781
|
+
declare const MANAGE_ANCHORS: {
|
|
782
|
+
readonly dashboard: "manage-dashboard";
|
|
783
|
+
readonly users: "manage-users";
|
|
784
|
+
readonly contacts: "manage-contacts";
|
|
785
|
+
readonly devices: "manage-devices";
|
|
786
|
+
readonly phoneNumbers: "manage-phone-numbers";
|
|
787
|
+
readonly callLogs: "manage-call-logs";
|
|
788
|
+
readonly voicemail: "manage-voicemail";
|
|
789
|
+
readonly fax: "manage-fax";
|
|
790
|
+
readonly settings: "manage-settings";
|
|
791
|
+
};
|
|
792
|
+
/**
|
|
793
|
+
* Platform Menu Anchors
|
|
794
|
+
* Available to Admin, Super User, and Reseller scopes
|
|
795
|
+
*/
|
|
796
|
+
declare const PLATFORM_ANCHORS: {
|
|
797
|
+
readonly dashboard: "platform-dashboard";
|
|
798
|
+
readonly codeManagement: "platform-code-management";
|
|
799
|
+
readonly configManagement: "platform-config-management";
|
|
800
|
+
readonly sdkManagement: "platform-ui-sdk";
|
|
801
|
+
readonly branding: "platform-branding";
|
|
802
|
+
readonly recording: "platform-recording";
|
|
803
|
+
readonly logsAndDiagnostics: "platform-logs-and-diagnostics";
|
|
804
|
+
};
|
|
805
|
+
/**
|
|
806
|
+
* Apps Menu Anchors
|
|
807
|
+
* Extension apps typically register here
|
|
808
|
+
*/
|
|
809
|
+
declare const APPS_ANCHORS: {
|
|
810
|
+
readonly home: "apps-home";
|
|
811
|
+
};
|
|
812
|
+
/**
|
|
813
|
+
* My Account Menu Anchors
|
|
814
|
+
* User-specific settings and preferences
|
|
815
|
+
*/
|
|
816
|
+
declare const MY_ACCOUNT_ANCHORS: {
|
|
817
|
+
readonly profile: "my-account-profile";
|
|
818
|
+
readonly preferences: "my-account-preferences";
|
|
819
|
+
readonly security: "my-account-security";
|
|
820
|
+
};
|
|
821
|
+
/**
|
|
822
|
+
* All anchor constants in one object for convenience
|
|
823
|
+
*/
|
|
824
|
+
declare const ANCHORS: {
|
|
825
|
+
readonly manage: {
|
|
826
|
+
readonly dashboard: "manage-dashboard";
|
|
827
|
+
readonly users: "manage-users";
|
|
828
|
+
readonly contacts: "manage-contacts";
|
|
829
|
+
readonly devices: "manage-devices";
|
|
830
|
+
readonly phoneNumbers: "manage-phone-numbers";
|
|
831
|
+
readonly callLogs: "manage-call-logs";
|
|
832
|
+
readonly voicemail: "manage-voicemail";
|
|
833
|
+
readonly fax: "manage-fax";
|
|
834
|
+
readonly settings: "manage-settings";
|
|
835
|
+
};
|
|
836
|
+
readonly platform: {
|
|
837
|
+
readonly dashboard: "platform-dashboard";
|
|
838
|
+
readonly codeManagement: "platform-code-management";
|
|
839
|
+
readonly configManagement: "platform-config-management";
|
|
840
|
+
readonly sdkManagement: "platform-ui-sdk";
|
|
841
|
+
readonly branding: "platform-branding";
|
|
842
|
+
readonly recording: "platform-recording";
|
|
843
|
+
readonly logsAndDiagnostics: "platform-logs-and-diagnostics";
|
|
844
|
+
};
|
|
845
|
+
readonly apps: {
|
|
846
|
+
readonly home: "apps-home";
|
|
847
|
+
};
|
|
848
|
+
readonly myAccount: {
|
|
849
|
+
readonly profile: "my-account-profile";
|
|
850
|
+
readonly preferences: "my-account-preferences";
|
|
851
|
+
readonly security: "my-account-security";
|
|
852
|
+
};
|
|
853
|
+
};
|
|
854
|
+
/**
|
|
855
|
+
* Type-safe anchor ID union
|
|
856
|
+
*/
|
|
857
|
+
type AnchorId = (typeof MANAGE_ANCHORS)[keyof typeof MANAGE_ANCHORS] | (typeof PLATFORM_ANCHORS)[keyof typeof PLATFORM_ANCHORS] | (typeof APPS_ANCHORS)[keyof typeof APPS_ANCHORS] | (typeof MY_ACCOUNT_ANCHORS)[keyof typeof MY_ACCOUNT_ANCHORS];
|
|
858
|
+
|
|
859
|
+
declare const VERSION = "1.0.0";
|
|
860
|
+
|
|
861
|
+
export { ANCHORS, APPS_ANCHORS, type AnchorId, type BreadcrumbItem, type DynamicColumnConfig, type DynamicColumnDefinition, type DynamicExtensionConfig, type ExtensionComponentProps, type ExtensionContext, type ExtensionZone, type ExtensionZoneId, type HorizonApiClient, type HorizonAuth, type HorizonContext, HorizonContextProvider, type HorizonEventBus, HorizonSDKError, type HorizonSDKErrorCode, type HorizonSDKErrorOptions, type HorizonUI, type HorizonUITemplates, type HorizonUser, MANAGE_ANCHORS, MY_ACCOUNT_ANCHORS, PLATFORM_ANCHORS, RemoteAppSDK, type RemoteAuthError, type RemoteAuthOptions, type RemoteAuthRequest, type RemoteAuthResponse, type RemoteModuleConfig, type RouteConfig, type RoutePattern, type SemanticPlacement, type ThemeTokens, VERSION, apiError, createHorizonSDKError, createLogger, createRemoteAppSDK, getLogLevel, invalidExtensionPointError, moduleLoadError, permissionDeniedError, rateLimitError, setLogLevel, signatureVerificationError, useDynamicColumn, useDynamicExtension, useHorizonContext, useLocale, useRemoteApp, useRoute, useRouteFromModule, useTheme };
|