This document describes the services provided by lin-pulsar-core.
Provides a singleton Axios instance shared across all modules.
| Function | Description |
|---|---|
setHttpClient |
Initializes the shared Axios instance (call once) |
getHttpClient |
Returns the shared Axios instance |
Initializes the shared Axios instance to be used by all modules. Should be called once during application bootstrapping.
import { setHttpClient } from '@linagora/lin-pulsar-core';| Parameter | Type | Description |
|---|---|---|
client |
AxiosInstance |
The Axios instance to be shared. |
No return value.
- Singleton: Only the first call sets the instance; subsequent calls log a warning and do not overwrite the instance.
- Required: Must be called before any call to
getHttpClient().
Retrieves the shared Axios instance initialized by setHttpClient.
import { getHttpClient } from '@linagora/lin-pulsar-core';None.
| Type | Description |
|---|---|
AxiosInstance |
The shared Axios instance. |
- Singleton: Always returns the same instance set by
setHttpClient. - Error Handling: Throws an error if called before initialization.
import { setHttpClient, getHttpClient } from '@linagora/lin-pulsar-core';
import axios from 'axios';
// Host application bootstrapping
const axiosInstance = axios.create({
baseURL: '/api',
timeout: 10000,
});
setHttpClient(axiosInstance);
// In any module
const http = getHttpClient();
http.get('/users').then((response) => {
// handle response
});import { getHttpClient } from '@linagora/lin-pulsar-core';
try {
const http = getHttpClient();
// Throws: [LinPulsar Core] HTTP client is not initialized. Call setHttpClient() first.
} catch (error) {
// Handle error
}import { setHttpClient } from '@linagora/lin-pulsar-core';
import axios from 'axios';
setHttpClient(axios.create());
// Second call logs a warning and does not overwrite the instance
setHttpClient(axios.create());
// Logs: [LinPulsar Core] HTTP client has already been initialized. Re-initialization is ignored.The functions are fully typed for use with Axios:
import type { AxiosInstance } from 'axios';
const http: AxiosInstance = getHttpClient();The HTTP Client Service ensures all modules share a single, consistent Axios instance for HTTP requests.
- ✅ Host calls
setHttpClient()once during boot - ✅ Modules use
getHttpClient()to access the same instance ⚠️ Warning logged if re-initialization is attempted- ❌ Error thrown if
getHttpClient()is called before initialization
Provides helpers wrapping Module Federation (enhanced runtime) functionalities and enforcing a consistent initialization and loading model across the application.
This service centralizes access to the Module Federation instance and exposes high-level helpers for loading federated Vue components.
| Function | Description |
|---|---|
setModuleFederation |
Registers the Module Federation instance from host |
getModuleFederation |
Returns the active Module Federation instance from host |
loadAsyncComponent |
Loads a remote Vue component from a Module Federation remote |
This library relies on a single Module Federation instance generated by Vite in the host during build, shared across all consumers.
The Module Federation instance from host is registered by linPulsarModuleFederation.init() (see Module Lifecycle), which passes getInstance() (from the @module-federation/enhanced/runtime library) to setModuleFederation(). All subsequent federation operations depend on this instance.
Failure to initialize the runtime before loading federated modules will result in a runtime error.
Registers the active Module Federation instance from host for the application.
This function is called by linPulsarModuleFederation.init(): a host using init() must not call it. Call it only when the remotes are not loaded through init(), with the instance returned by the getInstance method from the @module-federation/enhanced/runtime library.
Subsequent calls are ignored to prevent accidental re-initialization.
setModuleFederation(instance:ModuleFederation): void| Parameter | Type | Description |
|---|---|---|
instance |
ModuleFederation |
An initialized Module Federation instance |
- Registers the active Module Federation instance globally
- Ignores re-initialization attempts and logs a warning
- Required before calling
getModuleFederation()orloadAsyncComponent()
Returns the active Module Federation instance.
This accessor enforces correct initialization order.
getModuleFederation(): ModuleFederation;Errorif the runtime has not been initialized viasetModuleFederation()
Loads a remote Vue component from a Module Federation remote using the enhanced runtime.
This helper wraps:
- Vue’s
defineAsyncComponent - The Module Federation runtime’s
loadRemote()method
It provides a safe, declarative way to consume federated Vue components.
import { loadAsyncComponent } from '@linagora/lin-pulsar-core';| Parameter | Type | Description |
|---|---|---|
plugin |
string |
Remote module identifier in the format remoteName/modulePathExample: 'myRemote/MyComponent' |
Returns a Vue async component that can be:
- used in templates via
<component :is="..."> - rendered programmatically
- lazily resolved at runtime
-
Runtime dependency Requires the Module Federation instance to be retrieved via
getInstance()and registered withsetModuleFederation() -
Lazy loading The remote module is fetched only when the component is rendered
-
ESM compliance Expects the remote module to be an ESM namespace object exposing a
defaultexport -
Error handling Throws an error if:
- the remote module is
nullorundefined - the module does not expose a
defaultexport
- the remote module is
-
Type safety Expects the remote module to follow the
FederatedModule<T>contract
<template>
<component :is="remoteComponent" />
</template>
<script setup lang="ts">
import { loadAsyncComponent } from '@linagora/lin-pulsar-core';
import { ref } from 'vue';
import type { Component } from 'vue';
const remoteComponent = ref<Component | null>(null);
remoteComponent.value = loadAsyncComponent('myRemote/HeaderWidget');
</script><template>
<component
v-for="plugin in plugins"
:key="plugin"
:is="loadAsyncComponent(plugin)"
/>
</template>
<script setup lang="ts">
import { loadAsyncComponent } from '@linagora/lin-pulsar-core';
const plugins = ['remote1/ComponentA', 'remote2/ComponentB'];
</script>If the remote module cannot be loaded:
const component = loadAsyncComponent('invalidRemote/Component');
// Nothing is thrown here: once the component is mounted, the Module Federation runtime error is reported through Vue's error handling (`onErrorCaptured` / `app.config.errorHandler`)If the module doesn't export a default component:
// Remote module exports: export { MyComponent }
const component = loadAsyncComponent('myRemote/MyComponent');
// Nothing is thrown here: once the component is mounted, the loader rejects with "Failed to load component from myRemote/MyComponent", reported through Vue's error handling (`onErrorCaptured` / `app.config.errorHandler`)Solution: Ensure your remote module exports a default component:
<!-- ✅ Correct - remote module (.vue file) -->
<template>
<div>My Component</div>
</template>
<script setup lang="ts">
// Default export automatic with <script setup>
// Nothing special to do!
</script>Alternative with Options API:
<!-- ✅ Correct - remote module (.vue file) -->
<template>
<div>My Component</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'MyComponent',
// ...
});
</script>❌ Wrong - TypeScript/JavaScript file (not .vue):
// In a .ts file (not .vue)
// ❌ Named export only - doesn't work with loadAsyncComponent
export const MyComponent = defineComponent({
// ...
});
// ✅ Correct - default export
export default defineComponent({
name: 'MyComponent',
// ...
});The function expects remotes to follow this structure:
/**
* ESM namespace object returned when loading a remote component through
* Module Federation (for example via `loadRemote`).
*
* In a Vite + native ESM environment, federated modules are not auto-unwrapped:
* the effective export is exposed on the `default` property of the namespace.
*/
interface FederatedModule<Component> {
/**
* The default exported Vue component.
*/
default: Component;
}The returned component is fully typed as a Vue Component:
import type { Component } from 'vue';
const myComponent: Component = loadAsyncComponent('remote/Component');| Error Message | Cause |
|---|---|
Module Federation is not initialized |
setModuleFederation() was not called |
Failed to load component from <plugin> |
Missing or invalid default export |
- Module Federation runtime is explicitly managed
- Initialization is mandatory and centralized
loadAsyncComponentprovides a safe abstraction overloadRemote- All federated modules must export a default value
This design guarantees predictable behavior, testability, and runtime safety across all federated front-end modules.
The Entity Service provides a standardized CRUD abstraction for backend entity management. Each operation automatically resolves the correct backend endpoint using the module’s instanceId and its registered configuration.
This service builds on top of the HTTP Client Service and the Module Host Configuration Service.
| Function | Description |
|---|---|
saveEntity |
Creates a new entity on the backend |
updateEntity |
Updates an existing entity |
getEntities |
Retrieves a paginated list of entities |
getEntityById |
Retrieves a single entity by ID |
deleteEntityById |
Deletes a single entity by ID |
Creates and persists a new entity using the backend API associated with the module instance.
| Parameter | Type | Description |
|---|---|---|
instanceId |
string |
Identifier of the module instance |
record |
T |
Entity data to create |
| Type | Description |
|---|---|
Y |
The created entity returned by server |
- Automatically resolves the backend endpoint through
getModuleHostConfiguration - Issues a
POSTrequest with the entity payload - Returns the deserialized response body
const created = await saveEntity<UserInput, User>('users', newUser);Updates an existing entity in the backend.
| Parameter | Type | Description |
|---|---|---|
instanceId |
string |
Identifier of the module instance |
entityId |
string |
The ID of the entity to update |
record |
T |
New data to update the entity |
| Type | Description |
|---|---|
Y |
The updated entity returned by server |
Retrieves a paginated list of entities.
| Parameter | Type | Description |
|---|---|---|
instanceId |
string |
Identifier of the module instance |
filters |
QueryFilter |
Filters to apply to the search |
pagination |
Pagination |
Pagination parameters |
| Type | Description |
|---|---|
Page<T> |
A page object containing entity items |
Fetches a single entity by its unique identifier.
| Parameter | Type | Description |
|---|---|---|
instanceId |
string |
Identifier of the module instance |
entityId |
string |
ID of the entity to retrieve |
| Type | Description |
|---|---|
T |
The retrieved entity content |
Deletes a single entity by ID.
| Parameter | Type | Description |
|---|---|---|
instanceId |
string |
Identifier of the module instance |
entityId |
string |
ID of the entity to delete |
void
- Resolves endpoint from module configuration
- Performs a
DELETEHTTP request - Returns an empty Promise
// Create
await saveEntity('users', { name: 'Alice' });
// Update
await updateEntity('users', '42', { name: 'Alice Cooper' });
// Retrieve paginated list
const page = await getEntities<User>(
'users',
{ search: 'alice' },
{ page: 0, size: 20 }
);
// Retrieve by ID
const user = await getEntityById<User>('users', '42');
// Delete
await deleteEntityById('users', '42');This service provides a unified, module-aware way to manage backend CRUD operations while relying on shared configuration and HTTP client infrastructure.
Provides a singleton Pinia store instance shared across all modules, ensuring a unified state management context for the entire application.
| Function | Description |
|---|---|
setPiniaStore |
Initializes the shared Pinia store (call once) |
getPiniaStore |
Returns the shared Pinia store instance |
Initializes the shared Pinia store instance to be used by all modules. Should be called once during application bootstrapping by the host application.
import { setPiniaStore } from '@linagora/lin-pulsar-core';
import { createPinia } from 'pinia';
const pinia = createPinia();
setPiniaStore(pinia);| Parameter | Type | Description |
|---|---|---|
store |
Pinia |
The Pinia instance to be shared. |
No return value.
- Singleton: Only the first call sets the instance; subsequent calls log a warning and do not overwrite the instance.
- Required: Must be called before any call to
getPiniaStore().
- If called more than once, logs a warning:
[LinPulsar Core] Pinia store has already been initialized. Re-initialization is ignored.
Retrieves the shared Pinia store instance initialized by setPiniaStore.
import { getPiniaStore } from '@linagora/lin-pulsar-core';
const pinia = getPiniaStore();None.
| Type | Description |
|---|---|
Pinia |
The shared Pinia instance. |
- Singleton: Always returns the same instance set by
setPiniaStore. - Error Handling: Throws an error if called before initialization.
- If called before initialization, throws:
[LinPulsar Core] Pinia store is not initialized. Call setPiniaStore() first.
All Pinia stores defined in this library (such as useLinPulsarConfigurationStore and useLinPulsarZoneStore) internally use getPiniaStore() to ensure they are attached to the singleton Pinia instance created by the host application.
When defining a new store (either in the host or a module), you should follow the same architecture:
- Export a composable function (e.g.,
useMyStore) that calls your internal store definition with the Pinia instance returned bygetPiniaStore(). - Do not call
defineStoredirectly in the host/module—always use the exported composable to ensure the correct Pinia context.
// myStore.ts
import { defineStore } from 'pinia';
import { getPiniaStore } from '@linagora/lin-pulsar-core';
export const useMyStore = () => _useMyStore(getPiniaStore());
const _useMyStore = defineStore('myStore', {
// state, getters, actions...
});This ensures your store is always registered on the singleton Pinia instance shared across all modules.
import { setPiniaStore, getPiniaStore } from '@linagora/lin-pulsar-core';
import { createPinia } from 'pinia';
// Host application bootstrapping
const pinia = createPinia();
setPiniaStore(pinia);
// In any module
const store = getPiniaStore();import { useLinPulsarConfigurationStore } from '@linagora/lin-pulsar-core';
const configStore = useLinPulsarConfigurationStore();import { defineStore } from 'pinia';
import { getPiniaStore } from '@linagora/lin-pulsar-core';
export const useCustomStore = () => _useCustomStore(getPiniaStore());
const _useCustomStore = defineStore('customStore', {
// state, getters, actions...
});Then use it in your module:
import { useCustomStore } from './customStore';
const store = useCustomStore();The functions are fully typed for use with Pinia:
import type { Pinia } from 'pinia';
const pinia: Pinia = getPiniaStore();The Pinia Store Service ensures all modules share a single, consistent Pinia instance for state management.
- ✅ Host calls
setPiniaStore()once during boot - ✅ Modules use
getPiniaStore()to access the same instance - ✅ All stores must be defined using a composable that injects the singleton Pinia instance
⚠️ Warning logged if re-initialization is attempted- ❌ Error thrown if
getPiniaStore()is called before initialization
The Object Service provides utility helpers for manipulating plain JavaScript objects in a predictable and type-safe way. It is designed for JSON-like structures, configuration objects, and data transformation scenarios commonly encountered across modules.
This service focuses on immutability, deep operations, and safe object introspection.
| Function | Description |
|---|---|
merge |
Performs an immutable deep merge of two plain objects |
fromDot |
Expands dot-notation keys into a nested object structure |
getNestedValue |
Reads the value located at a dot-notation path inside an object |
setNestedValue |
Immutably sets the value located at a dot-notation path |
isObject |
Determines whether a value is a non-null plain object |
renameKeys |
Recursively renames keys of an object using a provided key modifier |
deepEqual |
Performs a deep equality check between two values |
deepEqualUnordered |
Performs a deep equality check ignoring array element order |
import {
merge,
fromDot,
getNestedValue,
setNestedValue,
isObject,
renameKeys,
deepEqual,
deepEqualUnordered,
} from '@linagora/lin-pulsar-core';- Immutable by default — input objects are never mutated
- Deep-safe — recursive handling of nested objects
- JSON-oriented — optimized for plain objects, not class instances
- Type-safe — relies on
unknownand explicit narrowing - Framework-agnostic — no external dependencies
Performs a deep merge of two plain objects.
Nested objects are merged recursively, while primitive values from the source overwrite those in the target.
merge<T extends PlainObject, S extends PlainObject>(
target: T,
source: S
): T & S;| Parameter | Type | Description |
|---|---|---|
target |
PlainObject |
The base object to merge into |
source |
PlainObject |
The object whose values override target |
| Type | Description |
|---|---|
T & S |
A new object containing the merged structure |
- Performs a recursive merge when both values are plain objects
- Overwrites primitive values from
targetwithsource - Does not mutate either input object
- Returns
sourceif either argument is not a plain object
const target = {
a: {
b: {
c: 'x',
d: 'y',
},
},
};
const source = {
a: {
d: 'z',
b: {
e: 'w',
},
},
};
const result = merge(target, source);
/*
{
a: {
b: {
c: 'x',
d: 'y',
e: 'w'
},
d: 'z'
}
}
*/Converts an object using dot-notation keys into a nested object structure.
Each segment separated by . represents a deeper level in the resulting object.
fromDot(obj: PlainObject): PlainObject;| Parameter | Type | Description |
|---|---|---|
obj |
PlainObject |
Object with dot-notation keys |
| Type | Description |
|---|---|
PlainObject |
A new object with nested structure |
- Splits keys using
.as a path delimiter - Creates nested objects as needed
- Overwrites non-object paths when expanding deeper levels
- Preserves immutability of the input object
fromDot({
'a.b.c': 'value',
'a.b.d': 'other',
'a.e': 'test',
});
/*
{
a: {
b: {
c: 'value',
d: 'other'
},
e: 'test'
}
}
*/Reads the value located at a dot-notation path inside an object.
getNestedValue(obj: PlainObject, path: string): unknown;| Parameter | Type | Description |
|---|---|---|
obj |
PlainObject |
The object to read from |
path |
string |
Dot-notation path of the value (e.g. 'a.b.c') |
| Type | Description |
|---|---|
unknown |
The value at the given path, or undefined if it cannot be found |
- Splits the path using
.as a delimiter - Traverses nested objects segment by segment
- Returns
undefinedwhen an intermediate value is missing or is not an object - Does not mutate the input object
getNestedValue({ a: { b: { c: 'x' } } }, 'a.b.c'); // 'x'
getNestedValue({ a: { b: 'x' } }, 'a.b.c'); // undefined
getNestedValue({ email: 'john@example.com' }, 'email'); // 'john@example.com'Immutably sets the value located at a dot-notation path inside an object.
setNestedValue(obj: PlainObject, path: string, value: unknown): PlainObject;| Parameter | Type | Description |
|---|---|---|
obj |
PlainObject |
The object to update |
path |
string |
Dot-notation path of the value (e.g. 'a.b.c') |
value |
unknown |
The value to set at the given path |
| Type | Description |
|---|---|
PlainObject |
A new object with the value set at the path |
- Splits the path using
.as a delimiter - Recreates only the objects along the path, preserving the rest of the structure
- Creates missing intermediate objects
- Replaces intermediate values that are not objects with objects
- Does not mutate the input object
setNestedValue({ a: { b: 'old', c: 'keep' } }, 'a.b', 'new');
// { a: { b: 'new', c: 'keep' } }
setNestedValue({}, 'a.b.c', 'x');
// { a: { b: { c: 'x' } } }Determines whether a value is a non-null plain object.
Arrays, null, and primitive values are explicitly excluded.
isObject(value: unknown): value is PlainObject;| Parameter | Type | Description |
|---|---|---|
value |
unknown |
Value to test |
| Type | Description |
|---|---|
boolean |
true if value is a plain object |
isObject({}); // true
isObject([]); // false
isObject(null); // false
isObject('text'); // falseRecursively renames the keys of a plain object using a provided key modifier function.
renameKeys(obj: object, keyModifier: (key: string) => string): object;| Parameter | Type | Description |
|---|---|---|
obj |
object |
The object whose keys will be renamed |
keyModifier |
(key: string) => string |
Function that receives a key and returns the new key |
| Type | Description |
|---|---|
object |
A new object with keys renamed recursively |
- Recursively traverses nested objects
- Applies
keyModifierto every key - Preserves arrays and primitive values as-is
- Returns non-object values unchanged
- Original object is not mutated
renameKeys({ first_name: 'Alice', address: { city_name: 'Paris' } }, (key) =>
key.toUpperCase()
);
// { FIRST_NAME: 'Alice', ADDRESS: { CITY_NAME: 'Paris' } }Performs a deep equality check between two values.
deepEqual(a: unknown, b: unknown): boolean;| Parameter | Type | Description |
|---|---|---|
a |
unknown |
First value to check |
b |
unknown |
Second value to check |
| Type | Description |
|---|---|
boolean |
true if values are deeply equal |
- Compares primitive values directly
- Recursively compares plain objects and arrays
- Returns
falseif types differ or structures mismatch
deepEqual({ a: 1, b: { c: 2 } }, { a: 1, b: { c: 2 } }); // true
deepEqual([1, 2, 3], [1, 2, 4]); // falsePerforms a deep equality check between two values, ignoring the order of array elements.
Useful for comparing sets of values where order is not significant (e.g. tags, roles, permissions).
deepEqualUnordered(a: unknown, b: unknown): boolean;| Parameter | Type | Description |
|---|---|---|
a |
unknown |
First value to check |
b |
unknown |
Second value to check |
| Type | Description |
|---|---|
boolean |
true if values are deeply equal ignoring array order |
- For arrays, checks that both contain the same elements regardless of order
- For plain objects, recursively compares properties (also ignoring array order at any nesting level)
- For primitives, delegates to
deepEqual
deepEqualUnordered([1, 2, 3], [3, 1, 2]); // true
deepEqualUnordered({ tags: ['b', 'a'] }, { tags: ['a', 'b'] }); // true
deepEqualUnordered([1, 2], [1, 2, 3]); // falsemergeenables safe, immutable deep merging of configuration objectsfromDotsimplifies transformation from flat, dot-based keys to nested objectsisObjectprovides a reliable runtime guard for plain object detectionrenameKeys— recursive key renamingdeepEqual— deep equality checks (order-sensitive for arrays)deepEqualUnordered— deep equality checks ignoring array element order
This service is intended as a foundational utility layer for configuration handling, data normalization, and object manipulation across the application.
Provides a singleton Nunjucks Environment instance shared across all modules, ensuring a unified template rendering context for the entire application.
| Function | Description |
|---|---|
setNunjucksEnv |
Initializes the shared Nunjucks environment (call once) |
getNunjucksEnv |
Returns the shared Nunjucks environment instance |
Initializes the shared Nunjucks Environment instance to be used by all modules. Should be called once during application bootstrapping by the host application.
import { setNunjucksEnv } from '@linagora/lin-pulsar-core';
import nunjucks from 'nunjucks';
const env = new nunjucks.Environment();
setNunjucksEnv(env);| Parameter | Type | Description |
|---|---|---|
env |
Environment |
The Nunjucks Environment instance to share. |
No return value.
- Singleton: Only the first call sets the instance; subsequent calls log a warning and do not overwrite the instance.
- Required: Must be called before any call to
getNunjucksEnv().
- If called more than once, logs a warning:
[LinPulsar Core] Nunjucks environment has already been initialized. Re-initialization is ignored.
Retrieves the shared Nunjucks Environment instance initialized by setNunjucksEnv.
import { getNunjucksEnv } from '@linagora/lin-pulsar-core';
const env = getNunjucksEnv();None.
| Type | Description |
|---|---|
Environment |
The shared Nunjucks Environment instance. |
- Singleton: Always returns the same instance set by
setNunjucksEnv. - Error Handling: Throws an error if called before initialization.
- If called before initialization, throws:
[LinPulsar Core] Nunjucks environment is not initialized. Call setNunjucksEnv() first.
import { setNunjucksEnv } from '@linagora/lin-pulsar-core';
import nunjucks from 'nunjucks';
// Host application bootstrapping
const env = new nunjucks.Environment();
setNunjucksEnv(env);import { getNunjucksEnv } from '@linagora/lin-pulsar-core';
const env = getNunjucksEnv();
const result = env.renderString('Hello {{ name }}!', { name: 'Alice' });
// result: "Hello Alice!"Filters specific to the host application can be added after initialization:
import { setNunjucksEnv, getNunjucksEnv } from '@linagora/lin-pulsar-core';
import nunjucks from 'nunjucks';
const env = new nunjucks.Environment();
env.addFilter('uppercase', (str: string) => str.toUpperCase());
setNunjucksEnv(env);import type { Environment } from 'nunjucks';
const env: Environment = getNunjucksEnv();- ✅ Host calls
setNunjucksEnv()once during boot - ✅ Modules use
getNunjucksEnv()to access the same instance ⚠️ Warning logged if re-initialization is attempted- ❌ Error thrown if
getNunjucksEnv()is called before initialization
Provides a singleton Dayjs instance shared across all modules.
| Function | Description |
|---|---|
setDayjsInstance |
Initializes the shared Dayjs instance (call once) |
getDayjsInstance |
Returns the shared Dayjs instance |
Initializes the shared Dayjs instance to be used by all modules. Should be called once during application bootstrapping, after loading all required Dayjs plugins (e.g. customParseFormat).
import { setDayjsInstance } from '@linagora/lin-pulsar-core';| Parameter | Type | Description |
|---|---|---|
instance |
typeof dayjs |
The Dayjs function to be shared. |
No return value.
- Singleton: Only the first call sets the instance; subsequent calls log a warning and do not overwrite the instance.
- Required: Must be called before any call to
getDayjsInstance()(or any composable that uses it, such asuseDayjs).
Retrieves the shared Dayjs instance initialized by setDayjsInstance.
import { getDayjsInstance } from '@linagora/lin-pulsar-core';None.
| Type | Description |
|---|---|
typeof dayjs |
The shared Dayjs instance. |
- Singleton: Always returns the same instance set by
setDayjsInstance. - Error Handling: Throws an error if called before initialization.
import { setDayjsInstance } from '@linagora/lin-pulsar-core';
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
// Load required plugins before registering the instance
dayjs.extend(customParseFormat);
// Host application bootstrapping
setDayjsInstance(dayjs);import { getDayjsInstance } from '@linagora/lin-pulsar-core';
try {
const dayjs = getDayjsInstance();
// Throws: [LinPulsar Core] Dayjs instance is not initialized. Call setDayjsInstance() first.
} catch (error) {
// Handle error
}import { setDayjsInstance } from '@linagora/lin-pulsar-core';
import dayjs from 'dayjs';
setDayjsInstance(dayjs);
// Second call logs a warning and does not overwrite the instance
setDayjsInstance(dayjs);
// Logs: [LinPulsar Core] Dayjs instance has already been initialized. Re-initialization is ignored.- ✅ Host calls
setDayjsInstance()once during boot, after extending dayjs with required plugins - ✅ Modules use
getDayjsInstance()(or composables such asuseDayjs) to access the same instance ⚠️ Warning logged if re-initialization is attempted- ❌ Error thrown if
getDayjsInstance()is called before initialization
Declares which components can be referenced by name by a zone entry, and resolves those names at render time.
Zone entries of type component carry a name rather than a component reference, which allows them to be declared from a module configuration file. This service is what turns such a name back into a component.
| Function | Description |
|---|---|
registerLocalComponent |
Makes a component available to zones under a given name |
registerLocalComponents |
Makes several components available to zones at once |
getLocalComponent |
Returns the value registered under a given name, if any |
resolveLocalComponent |
Resolves the component registered under a given name |
Makes a component available to zones under the given name.
Components are stored with markRaw, so they are kept out of the reactivity system. Registering a name that is already known overrides the previous component.
import { registerLocalComponent } from '@linagora/lin-pulsar-core';
import UserRolesCard from './components/UserRolesCard.vue';
registerLocalComponent('UserRolesCard', UserRolesCard);Makes several components available to zones at once, typically to declare the whole zone surface of an application in a single call during bootstrap.
import { registerLocalComponents } from '@linagora/lin-pulsar-core';
import { QBanner, QSeparator } from 'quasar';
registerLocalComponents({
QBanner,
QSeparator,
});Returns the value registered under the given name, or undefined when the name is unknown.
Unlike resolveLocalComponent, unknown names are not resolved against globally registered components and no warning is logged: the caller is expected to treat undefined as an error. This is what the module configuration loading uses to resolve component references (lifecycleRemote, routesRemote, i18nRemote, route components), where an unregistered name must fail loudly instead of falling back.
import { getLocalComponent } from '@linagora/lin-pulsar-core';
// Returns the registered value
getLocalComponent('UserRolesCard');
// Returns undefined
getLocalComponent('UnknownCard');Resolves the component registered under the given name.
Unknown names are not an error: a warning listing the registered names is logged, and the name is returned as-is so that Vue still attempts to resolve it against globally registered components.
import { resolveLocalComponent } from '@linagora/lin-pulsar-core';
// Returns the registered component
resolveLocalComponent('UserRolesCard');
// Logs a warning and returns 'UnknownCard'
resolveLocalComponent('UnknownCard');- ✅ Host declares its zone components once during boot, before any zone is rendered
- ✅ Zone entries and module configuration files reference those components by name
⚠️ Warning logged when resolving an unknown name, which falls back to global resolution- ❌ Never called manually by consumers:
LinPulsarZoneRendererresolves entries on its own
Fetches the entity and API endpoint configurations exposed by the backend, through the shared HTTP client.
| Function | Description | Endpoint |
|---|---|---|
getEntitiesConfiguration |
Returns the configuration of all entities | GET /metadata/entities |
getEntityConfiguration |
Returns the configuration of one entity | GET /metadata/entities/:entityId |
getApiEndpointsConfiguration |
Returns the configuration of all API endpoints | GET /metadata/routes |
The endpoints are relative to the base URL of the HTTP client shared with setHttpClient. The
results are typed with LinPulsarEntityConfiguration and
LinPulsarApiEndpointConfiguration. Components usually
read these configurations from useLinPulsarConfigurationStore, which calls this service.
import { getEntitiesConfiguration } from '@linagora/lin-pulsar-core';
const entities = await getEntitiesConfiguration();import { getEntityConfiguration } from '@linagora/lin-pulsar-core';
const accounts = await getEntityConfiguration('accounts');import { getApiEndpointsConfiguration } from '@linagora/lin-pulsar-core';
const endpoints = await getApiEndpointsConfiguration();Stores the host configuration (ModuleHostConfig) of each module instance, indexed by its instanceId.
| Function | Description |
|---|---|
registerModuleHostConfiguration |
Registers the configuration of a module instance |
getModuleHostConfiguration |
Returns the configuration of a module instance |
Registers a module host configuration. A configuration with the same instanceId is overwritten.
This is done by linPulsarModuleFederation.init() during the SETUP phase for every module configuration file, so it
only needs to be called manually for a module that is not loaded through init().
import { registerModuleHostConfiguration } from '@linagora/lin-pulsar-core';
registerModuleHostConfiguration(config);Returns the configuration registered for an instanceId, typed with the module-specific options. Throws an error when
no configuration is registered for it.
import { getModuleHostConfiguration } from '@linagora/lin-pulsar-core';
const config =
getModuleHostConfiguration<MyModuleOptions>('moduleAccountsPage');Exposes uiEventSubject, a shared RxJS Subject acting as the event bus for all UI events across the host and the
remotes. Each event carries a key identifying its kind and a free data payload:
export interface UiEvent {
key: string;
data: unknown;
}| Key | Payload | Emitted by | Documentation |
|---|---|---|---|
'notify' |
QNotifyCreateOptions |
useNotify |
Notifications |
Key passed to useDialog |
DialogEvent |
The code opening or closing the dialog | Dialogs |
import { uiEventSubject } from '@linagora/lin-pulsar-core';
uiEventSubject.subscribe((event) => {
if (event.key === 'notify') {
// ...
}
});The following shared services are documented with the composables that use them:
| Service | Functions | Documentation |
|---|---|---|
| i18n | setI18nInstance, getI18nInstance |
i18n |
| UI design | setUiDesign, getUiDesign |
UI design |