npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@omni-gate/frame-bridge

v0.3.2

Published

A TypeScript framework for parent-child window communication, providing comprehensive APIs for user management, permissions, JWT expiry management, and unified message broadcasting.

Readme

@omni-gate/frame-bridge

npm version

A TypeScript framework for parent-child window communication, providing comprehensive APIs for user management, permissions, JWT expiry management, and unified message broadcasting.

简体中文 | English

🚀 Features

  • Parent-Child Window Communication - Secure message bridge for iframe communication
  • Trusted Origin Validation - Configurable whitelist for security
  • Centralized Data Management - Parent window handles all API calls and caching
  • User Management - Get current user information
  • Permission Control - Application and module-level permission management
  • Data Dictionaries - Hierarchical data options with intelligent caching
  • Module Navigation - Cross-window module opening via message bridge
  • Multi-language Support - Internationalized error messages
  • Smart Caching - Multi-tier caching strategy for optimal performance
  • Heartbeat Mechanism - User activity monitoring and session management
  • JWT Expiry Management - Automatic JWT expiry detection with async callback support
  • Unified Logoff Broadcast - Automatically notify all child windows on user logout

📦 Installation

npm install @omni-gate/frame-bridge

🏗️ Architecture

This library provides two main classes:

  • OmniParentApi - For the parent window, handles all API requests and caching
  • OmniClientApi - For child windows (iframes), communicates with parent window
┌─────────────────────────────────────────────────────────────┐
│                      Parent Window                           │
│                                                              │
│  ┌─────────────────────────────────────────────────────┐   │
│  │              OmniParentApi                           │   │
│  │  • RestService (API access)                         │   │
│  │  • MessageBridgeManager                             │   │
│  │  • Centralized caching                              │   │
│  │  • Trusted origin validation                        │   │
│  └─────────────────────────────────────────────────────┘   │
│                          │                                  │
│                          ▼                                  │
│              Message Bridge (postMessage)                   │
│                          │                                  │
└──────────────────────────┼──────────────────────────────────┘
                           │
           ┌───────────────┼───────────────┐
           │               │               │
           ▼               ▼               ▼
    ┌──────────┐    ┌──────────┐    ┌──────────┐
    │ iframe 1 │    │ iframe 2 │    │ iframe 3 │
    │          │    │          │    │          │
    │OmniClient│    │OmniClient│    │OmniClient│
    │   Api    │    │   Api    │    │   Api    │
    └──────────┘    └──────────┘    └──────────┘

🏗️ Quick Start

Parent Window Setup

import { OmniParentApi, OmniFrameOptions } from '@omni-gate/frame-bridge';
import { MessageBridgeManager } from '@ticatec/iframe-message-bridge';
import RestService from '@ticatec/restful_service_api';

// Create REST service proxy
const serviceProxy = new RestService('https://api.example.com');

// Create message bridge manager
const bridgeManager = new MessageBridgeManager();

// Configure SDK options (optional)
const options: OmniFrameOptions = {
  jwtStorage: sessionStorage,        // JWT token storage location (default: sessionStorage)
  jwtStorageKey: 'omni-token',       // JWT token storage key (default: 'omni-token')
  isDebug: false,                    // Enable debug mode (default: false)
  jwtCheckInterval: 30 * 1000,       // JWT check interval in ms (default: 30000)
  jwtWarningTime: 5 * 60 * 1000      // JWT warning time in ms (default: 300000)
};

// Configure trusted origins (optional but recommended)
const trustedOrigins = [
  'https://trusted-app1.com',
  'https://trusted-app2.com',
  'http://localhost:3000'
];

// Initialize parent API
const parentApi = OmniParentApi.initialize(
  serviceProxy,
  bridgeManager,
  trustedOrigins,  // Optional: restrict to specific origins
  options          // Optional: SDK configuration
);

// Get instance
const api = OmniParentApi.getInstance();

Child Window (iframe) Setup

import OmniClientApi from '@omni-gate/frame-bridge';
import { MessageBridgeClient } from '@ticatec/iframe-message-bridge';

// Create message bridge client
const bridge = new MessageBridgeClient('https://parent-domain.com');

// Initialize client API (no need for RestService!)
OmniClientApi.initialize(bridge);

// Get instance
const api = OmniClientApi.getInstance();

📖 API Reference

OmniParentApi (Parent Window)

Initialization

initialize(serviceProxy, bridgeManager, trustedOrigins?)

Initialize the parent API instance.

const parentApi = OmniParentApi.initialize(
  serviceProxy,
  bridgeManager,
  ['https://trusted-app.com']  // Optional: trusted origins
);
getInstance()

Get the parent API instance.

const api = OmniParentApi.getInstance();

Default Message Handlers

All message handlers automatically validate the origin before processing.

onHeartbeat()

Handles heartbeat messages from child windows.

onGetToken(customHandler?)

Handles JWT token requests. Returns token from localStorage by default.

onGetMe(customHandler?)

Handles current user information requests.

onGetPermission(customHandler?)

Handles application permission requests.

onGetModulePermission(customHandler?)

Handles module permission requests.

onGetOptionsData(customHandler?)

Handles data dictionary requests.

onGetChildrenOptions(customHandler?)

Handles hierarchical data requests.

onGetErrorMessages(customHandler?)

Handles error message requests.

onGetSupportedLanguages(customHandler?)

Handles supported languages list requests.

onGetCurrentLanguage(customHandler?)

Handles current language requests.

Custom Handlers

registerHandler(eventName, handler, skipOriginValidation?)

Register a custom message handler.

parentApi.registerHandler('customEvent', (data, sourceWindow, sourceOrigin) => {
  console.log('Received from:', sourceOrigin);
  return { result: 'ok' };
});

// Skip origin validation (not recommended for security-sensitive operations)
parentApi.registerHandler('publicEvent', handler, true);
unregisterHandler(eventName)

Unregister a message handler.

parentApi.unregisterHandler('customEvent');

Broadcast Messages

broadcast(eventName, data, targetOrigin?)

Send a broadcast message to all child windows.

parentApi.broadcast('user-login-changed', { userId: 123, userName: 'Alice' });
broadcastThemeChanged(theme)

Broadcast theme change.

broadcastLogoff()

Broadcast user logoff message. When the parent window user logs out, call this method to notify all child windows.

// When user logs out
parentApi.broadcastLogoff();

Broadcast Handlers

onBroadcast(eventName, handler)

Register a broadcast message handler (parent window can also receive broadcasts).

parentApi.onBroadcast('theme-changed', (data) => {
  console.log('Theme changed to:', data.theme);
  applyTheme(data.theme);
});
offBroadcast(eventName)

Unregister a broadcast message handler.

parentApi.offBroadcast('theme-changed');

Cache Management

clearAllCache()

Clear all cached data from both localStorage and the configured JWT storage. This includes user info, permissions, dictionaries, error messages, and JWT tokens.

parentApi.clearAllCache();
clearUserData()

Clear user-specific data (user info and permissions) when the logged-in user changes.

// After login, check if user changed
const oldMe = await parentApi.getMe();
const newMe = await performLogin(username, password);
if (oldMe.id !== newMe.id) {
  // User changed, clear user data
  parentApi.clearUserData();
}
clearOptionsData()

Clear dictionary/options data when the tenant changes.

// Check if tenant changed
const oldMe = await parentApi.getMe();
const newMe = await getUserInfo();
if (oldMe.tenantId !== newMe.tenantId) {
  // Tenant changed, clear options data
  parentApi.clearOptionsData();
}

Utility Methods

getBridgeManager()

Get the underlying MessageBridgeManager instance.

clearAllHandlers()

Clear all handlers (both message and broadcast handlers).

destroy()

Clean up and destroy the instance.

OmniClientApi (Child Window)

Initialization

initialize(bridge)

Initialize the client API instance.

const clientApi = OmniClientApi.initialize(bridge);
getInstance()

Get the client API instance.

const api = OmniClientApi.getInstance();

User Management

getMe(): Promise<User>

Get current logged-in user information from parent window.

const user = await clientApi.getMe();
console.log('Current user:', user);

Response:

{
  "accountCode": "admin@saas",
  "name": "System Administrator",
  "tenant": "company-001",
  "branch": "main-branch"
}

Permission Management

getPermission(appCode: string): Promise<Permission>

Get application permissions from parent window.

const permissions = await clientApi.getPermission('saas-platform');
console.log('App permissions:', permissions);

Response:

{
  "user-management": {
    "maintain": true,
    "delete": true
  },
  "role-management": {
    "maintain": true,
    "assign": true
  }
}
getModulePermission(appCode: string, modCode: string): Promise<Permission>

Get specific module permissions.

const modulePerms = await clientApi.getModulePermission('saas-platform', 'user-management');
const canMaintain = modulePerms.maintain === true;

Data Dictionary Management

getOptionsData(dicNames: string | string[]): Promise<OptionsData>

Get dictionary data from parent window.

// Single dictionary
const genderOptions = await clientApi.getOptionsData('gender');

// Multiple dictionaries
const options = await clientApi.getOptionsData([
  'gender',
  'card-type',
  'nationality'
]);

console.log('Gender options:', options.gender);
getChildrenOptions(dic: string, code: string): Promise<Option[]>

Get child options for hierarchical data.

const regions = await clientApi.getChildrenOptions('region', '130100');
console.log('Sub-regions:', regions);

Error Message Management

getErrorMessages(appCode: string): Promise<ErrorMessages>

Get localized error messages. Language is determined by the X-language request header which is automatically set based on the language setting in localStorage.

const errors = await clientApi.getErrorMessages('saas-platform');
// Language is automatically determined by the X-language header

Language Handling:

  • Language is read from localStorage's language key
  • Sent to backend via X-language request header
  • Backend returns error messages in the corresponding language

Language Management

getSupportedLanguages(): Promise<Language[]>

Get the list of supported languages from parent window.

const languages = await clientApi.getSupportedLanguages();
console.log('Supported languages:', languages);
// Returns: ['en', 'zh-CN', 'ja', 'ko', ...]
getCurrentLanguage(): Promise<LanguageResponse>

Get the current language setting from parent window.

const response = await clientApi.getCurrentLanguage();
const currentLang = response.language;
console.log('Current language:', currentLang);
// Returns: { language: 'zh-CN' }

Token Management

getJwtToken(): Promise<string>

Get JWT token from parent window.

const token = await clientApi.getJwtToken();
console.log('JWT Token:', token);

Module Navigation

openModule(modHash: string, params: any): void

Open a module via message bridge communication.

clientApi.openModule('/#/plan/PlanHomePage', {
  patientId: '12345',
  planType: 'follow-up'
});

Broadcast Handlers

onBroadcast(eventName, handler)

Register a broadcast message handler to receive broadcasts from parent window.

clientApi.onBroadcast('theme-changed', (data) => {
  console.log('Theme changed to:', data.theme);
  applyTheme(data.theme);
});
onLogoff(handler)

Register a user logout event handler. When the parent window user logs out, the child window will be notified and call the registered handler.

clientApi.onLogoff((data) => {
  console.log('User logged out at:', data.timestamp);
  // Perform logout-related cleanup operations
  // For example: clear local data, redirect to login page, etc.
});
offBroadcast(eventName)

Unregister a broadcast message handler.

clientApi.offBroadcast('theme-changed');
offLogoff()

Unregister the user logout event handler.

clientApi.offLogoff();
clearBroadcastHandlers()

Clear all broadcast message handlers.

clientApi.clearBroadcastHandlers();

Utility Methods

destroy()

Clean up and destroy the instance.

clientApi.destroy();

🔧 Caching Strategy

| Data Type | Storage | TTL | Managed By | |-----------|---------|-----|------------| | User Info (me) | localStorage | Session | Parent Window | | Permissions | localStorage | 15 minutes | Parent Window | | Dictionary Data | localStorage | 60 minutes | Parent Window | | Error Messages | localStorage | 24 hours | Parent Window | | Supported Languages | localStorage | 24 hours | Parent Window | | Current Language | localStorage | Session | Parent Window | | JWT Token | Configurable* | Session | Parent/Child Window |

Note: JWT token storage is configurable via OmniFrameOptions.jqStorage (default: sessionStorage). All other caching is managed by the parent window using localStorage. Child windows request data without worrying about cache management.

🔒 Security Features

Trusted Origin Validation

The parent window can restrict which origins are allowed to communicate:

const trustedOrigins = [
  'https://app1.company.com',
  'https://app2.company.com'
];

const parentApi = OmniParentApi.initialize(
  serviceProxy,
  bridgeManager,
  trustedOrigins
);

When a request comes from an untrusted origin:

{
  "error": "Untrusted origin",
  "message": "Origin https://malicious-site.com is not in the trusted origins list"
}

Security Best Practices

  1. Always specify trusted origins in production environments
  2. Use HTTPS for all communication
  3. Validate data received from child windows
  4. Implement proper authentication in your REST service
  5. Use Content Security Policy headers

🎯 Heartbeat System

The client automatically:

  • Monitors user interactions (keyboard, mouse events)
  • Sends heartbeat signals every 10 seconds when active
  • Handles cross-window communication
  • Manages session lifecycle

🔐 JWT Expiry Management

The SDK provides comprehensive JWT expiry detection and management with support for both synchronous and asynchronous callbacks.

Configuration

JWT check configuration via OmniFrameOptions:

| Option | Default | Description | |--------|---------|-------------| | jwtCheckInterval | 30 seconds | JWT expiry check interval | | jwtWarningTime | 5 minutes | How early to warn before expiry | | jwtStorage | sessionStorage | Storage location for JWT token | | jwtStorageKey | 'omni-token' | Storage key for JWT token | | isDebug | false | Enable debug logging |

Parent Window - JWT Monitoring

The parent window's JWT manager is created at initialization and monitors token expiry automatically.

const parentApi = OmniParentApi.getInstance();

// Start JWT monitoring with callback
parentApi.startJwtMonitoring((data) => {
  if (data.expired) {
    // JWT has expired (e.g., after sleep/wakeup)
    console.log('JWT has expired, need to re-login');
    // Clean up local data, redirect to login page, etc.
  } else {
    // JWT is about to expire
    const minutesLeft = Math.floor(data.remainingTime! / 60000);
    console.log(`JWT will expire in ${minutesLeft} minutes`);
    // Try to refresh token here
  }
});

// Stop JWT monitoring
parentApi.stopJwtMonitoring();

Child Window - Cross-Origin JWT Management

In cross-origin scenarios, the child window can independently monitor its locally stored JWT token.

// Only needed in cross-origin iframes
clientApi.startJwtMonitoring(async (data) => {
  if (data.expired) {
    // Token expired, request new token from parent
    const newToken = await clientApi.refreshJwtToken();
    if (newToken) {
      await clientApi.updateJwtToken(newToken);
    } else {
      // Cannot get new token, redirect to login
      window.location.href = '/login';
    }
  } else if (data.remainingTime && data.remainingTime < 5 * 60 * 1000) {
    // Token expiring soon (less than 5 minutes)
    showWarning('Session will expire soon, please save your work');
  }
});

// Stop monitoring
clientApi.stopJwtMonitoring();

Async Callback Support

Supports asynchronous callback functions. The system won't trigger repeated warnings while the user is handling an async operation.

parentApi.startJwtMonitoring(async (data) => {
  if (!data.expired) {
    // Show confirmation dialog
    const shouldRefresh = await showConfirmDialog({
      title: 'Session Expiring',
      message: `Your session will expire in ${Math.floor(data.remainingTime! / 60000)} minutes. Refresh now?`
    });

    if (shouldRefresh) {
      await refreshToken();
    }
  }
});

Features

  1. Automatic Detection: Automatically checks JWT status at configured intervals
  2. Expiry Warning: Triggers callback before JWT expires (only once)
  3. Expired Handling: When JWT is expired, triggers callback and automatically broadcasts logoff (parent window)
  4. Async Support: Supports async callback functions, won't trigger repeated warnings during async operations
  5. Prevent Duplication: Uses state flags to prevent duplicate warnings, avoiding multiple dialogs
  6. Cross-Origin Support: Child windows can independently manage JWT in cross-origin scenarios

🛠️ Development

# Clean build directory
npm run clean

# Build the library
npm run build

# Watch mode for development
npm run dev

# Type checking
npm run typecheck

# Publish to npm
npm run publish:public

📄 TypeScript Support

Full TypeScript definitions included. The library exports:

import OmniClientApi, {
  OmniParentApi,
  Permissions,
  Constants,
  BaseRestServiceProxy
} from '@omni-gate/frame-bridge';

// Access constants
const { BRIDGE_MESSAGES, BROADCAST_MESSAGES } = Constants;

🌐 Internationalization (i18n)

The SDK provides built-in internationalization support for user-facing error messages through the i18nRes resource object.

Error Message Resources

Error messages in BaseRestServiceProxy use i18n resources for displaying localized messages to end users. The available error message keys are:

| Key | Default Message | Usage | |-----|----------------|-------| | UnknownErrorCode | "Unknown error code." | Shown when an error code is not found in the error table | | NetworkError | "An unknown network error occurred." | Shown for network-related errors | | NoErrorsTable | "The error information table is not loaded." | Shown when error messages are not loaded |

Error Message Display

When API errors occur, the BaseRestServiceProxy automatically:

  1. Retrieves the error code from the API response
  2. Looks up the corresponding error message from the loaded error table
  3. Falls back to i18n resource messages if the error code is not found
  4. Displays the formatted error message via Toast.show()

Example Error Display:

MY-APP-1001: User does not exist

Or if error code is not found:

MY-APP-9999: Unknown error code.

i18n Resources Location:

import i18nRes from '@omni-gate/frame-bridge/src/i18nRes/i18nRes';

Note: Only user-facing error messages (displayed via Toast.show()) use i18n. Developer console logs and inter-window communication messages remain in English for debugging purposes.

🔧 REST Service Proxy

BaseRestServiceProxy

Abstract base class for managing RestService instances with automatic JWT token injection, language support, and error handling.

Features:

  • Automatic JWT token injection from storage
  • Automatic language header injection
  • Unified error handling with internationalized error messages
  • Request interception for custom headers

Usage Example:

import { BaseRestServiceProxy } from '@omni-gate/frame-bridge';
import RestService from '@ticatec/restful_service_api';

// Create a custom service proxy by extending the base class
class MyAppServiceProxy extends BaseRestServiceProxy {
  protected getPrefix(): string {
    return 'MY-APP';
  }

  protected getAppCode(): string {
    return 'my-application';
  }

  protected async retrieveErrorMessage(): Promise<any> {
    // Load error messages for the application
    const appCode = this.getAppCode();
    const response = await fetch(`/error-messages/${appCode}`);
    return await response.json();
  }

  constructor() {
    super(
      (errorHandler, preInterceptor) => {
        return new RestService('https://api.example.com', errorHandler, preInterceptor);
      },
      {
        jwtStorage: sessionStorage,
        jwtStorageKey: 'omni-token'
      }
    );
    // Initialize to load error messages
    this.initialize();
  }
}

// Create proxy instance (error messages are loaded automatically)
const proxy = new MyAppServiceProxy();

// Use the RestService
const users = await proxy.service.get('/api/users');

Automatic Request Headers:

  • Authorization: Bearer <token> - JWT token from storage (if available)
  • x-language: <lang> - Language setting from storage (if available)

Abstract Methods (must be implemented):

  • getPrefix(): string - Returns error message prefix (e.g., 'MY-APP')
  • getAppCode(): string - Returns application code for loading error messages
  • retrieveErrorMessage(): Promise<any> - Loads error messages (called by initialize())

Important:

  • Call initialize() to load error messages before using service
  • Requires global Toast.show() method for error display
  • Requires JWT token and language to be stored in storage

🛠️ Utility Tools

omniFrameSdk

Utility functions for frame detection and origin checking.

isSameOrigin(): boolean

Check if the current window is in the same origin as the parent window. Returns true if:

  • The window is not in an iframe (window === window.top), OR
  • The window is in an iframe and has the same origin as the parent window

Returns false if the window is in a cross-origin iframe.

import omniFrameSdk from '@omni-gate/frame-bridge';

if (omniFrameSdk.isSameOrigin()) {
  // Safe to access parent window properties directly
  console.log(window.parent.location.href);
} else {
  // Need to use postMessage for cross-origin communication
  console.log('Cross-origin iframe detected');
}

Use Cases:

  • Determine if direct parent window access is safe
  • Choose between direct property access and postMessage communication
  • Implement security checks before accessing parent window

🤝 Dependencies

Peer Dependencies

  • @ticatec/iframe-message-bridge - Cross-window communication
  • @ticatec/restful_service_api - REST API client

Dev Dependencies

  • typescript - TypeScript compiler

📋 Requirements

  • TypeScript 5.0+
  • ES2017+ target environment
  • Browser with sessionStorage/localStorage support
  • Modern browser with postMessage support

📞 Support

For issues and questions, please refer to the OmniGate platform documentation or contact the development team.

📜 License

MIT