Advanced Features
This guide covers advanced platform features that enable sophisticated widget functionality including OAuth authentication, state sharing between widgets, real-time WebSocket updates, feature flags for conditional rendering, remote module integration, and extension usage. These features allow you to build powerful, interactive widgets that leverage the full capabilities of the platform.
Table of Contents
- Adding OAuth Authentication
- Implementing State Sharing
- Integrating WebSocket Updates
- Adding Feature Flags
- Using Remote Modules
- Working with Extensions
Adding OAuth Authentication
Reference:
The platform provides OAuth authentication through the @invent/proxy-app-components package.
ProxyApp Component
Import:
import { ProxyApp } from "@invent/proxy-app-components";
The ProxyApp component wraps your widget and handles the complete OAuth authentication flow automatically.
Basic Usage
import React from "react";
import { ProxyApp } from "@invent/proxy-app-components";
import type { IWidgetProps } from "../types/widget-props";
const KpiTracker: React.FC<IWidgetProps> = ({
httpClient,
apiUrl,
...otherProps
}) => {
return (
<ProxyApp
httpClient={httpClient}
provider="kpiProvider"
authUrl={apiUrl}
instanceName="kpi-tracker"
>
<KpiTrackerContent {...otherProps} />
</ProxyApp>
);
};
const KpiTrackerContent: React.FC = () => {
// Widget content only renders when authenticated
return (
<div>
<h2>Authenticated KPI Tracker</h2>
{/* Your widget content */}
</div>
);
};
export default KpiTracker;
Advanced Usage with Hooks and Components
For more flexible authentication flows, the package exports additional hooks and components:
Available exports from @invent/proxy-app-components:
import {
ProxyApp, // Main wrapper component
ProxyAppMulti, // Multi-instance authentication
ProxyLogin, // Login UI component
useAuth, // Authentication hook
useAuthContext, // Access auth context
AuthProvider, // Auth context provider
AuthContext, // Auth context
useProviderLogo, // Provider logo hook
} from "@invent/proxy-app-components";
Example with hooks:
import React from "react";
import {
AuthProvider,
useAuth,
ProxyLogin,
} from "@invent/proxy-app-components";
import type { IWidgetProps } from "../types/widget-props";
const KpiTracker: React.FC<IWidgetProps> = ({ httpClient, apiUrl }) => {
return (
<AuthProvider>
<KpiTrackerWithAuth httpClient={httpClient} apiUrl={apiUrl} />
</AuthProvider>
);
};
const KpiTrackerWithAuth: React.FC = ({ httpClient, apiUrl }) => {
const {
isLoggedIn,
setIsLoggedIn,
config,
logout,
availableProviders,
error,
} = useAuth({
httpClient,
provider: "kpiProvider",
authUrl: apiUrl,
instanceName: "kpi-tracker",
});
if (!isLoggedIn) {
return (
<ProxyLogin
httpClient={httpClient}
setIsLoggedIn={setIsLoggedIn}
config={config}
error={error}
/>
);
}
return (
<div>
<h2>Authenticated KPI Tracker</h2>
<button onClick={logout}>Logout</button>
{/* Widget content */}
</div>
);
};
export default KpiTracker;
DAP API - Getting externalConfigurationId
const dapApiUrl = process.env.DAP_API_URL;
const entityType = "account";
const entityIdType = "accountId";
const entityId = searchParams.get("accountId");
const getEntityOrigins = async () => {
const response = await httpClient(`${dapApiUrl}/${entityType}/origins`, {
method: "get",
traceId: "kpi-tracker-origins",
params: {
queryParams: {
[entityIdType]: entityId,
},
},
});
return response;
};
interface Origin {
sourceCode: string;
originalAppId: string;
originalAppTitle: string;
originalAccountId: string;
externalConfigurationId: string; // Pass-through identifier
masterAccountIds: string[];
firmId: string;
}
YARP Proxy API - Making Authenticated Requests
const yarpProxyApiUrl = process.env.YARP_PROXY_API_URL;
const fetchEntityData = async (externalConfigurationId: string) => {
const response = await httpClient(
`${yarpProxyApiUrl}/third_party_endpoint/entities`,
{
method: "get",
traceId: "kpi-tracker-entity",
params: {
queryParams: {
entityId: externalConfigurationId,
},
},
}
);
return response;
};
Complete OAuth Flow
const fetchDataWithAuth = async () => {
try {
// Step 1: Get externalConfigurationId from DAP API
const originsResponse = await getEntityOrigins();
const externalConfigurationId =
originsResponse.data.externalConfigurationId;
// Step 2: Use externalConfigurationId to call third-party API via YARP
const entityData = await fetchEntityData(externalConfigurationId);
console.log("Entity data:", entityData);
return entityData;
} catch (error) {
console.error("Error fetching data:", error);
showNotification("error", "Failed to fetch data", { autoClose: 5000 });
}
};
Implementing State Sharing
Reference: Widget Specifications API
State Sharing Hooks
Three hooks are available for state sharing between widgets:
useShareValue: Set shared value
useSelectSharedValue: Read shared value
useDeleteSharedValue: Delete shared value
Creating a Selector
import { path } from "ramda";
import type { ISharedState } from "@invent/shared-types";
// Selector function
function kpiDataSelector(state: ISharedState) {
return path<IKpiData | undefined>(["kpiData"], state);
}
interface IKpiData {
revenue: number;
users: number;
conversion: number;
timestamp: number;
}