🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@memberjunction/global

Package Overview
Dependencies
Maintainers
9
Versions
437
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@memberjunction/global

MemberJunction: Global Object - Needed for ALL other MJ components

Source
npmnpm
Version
5.41.0
Version published
Weekly downloads
3.3K
-39.77%
Maintainers
9
Weekly downloads
 
Created
Source

@memberjunction/global

The foundational package for the entire MemberJunction ecosystem. @memberjunction/global provides the core infrastructure that every other MJ package depends on: a singleton coordination hub, a dynamic class factory with decorator-based registration, cross-environment global state management, and a collection of essential utilities for validation, diffing, caching, pattern matching, and more.

This package has zero MJ dependencies and sits at the very bottom of the dependency graph, making it safe to import from anywhere in the stack without circular dependency concerns.

Architecture Overview

graph TD
    subgraph MJGlobal["@memberjunction/global"]
        direction TB
        MJG["MJGlobal (Singleton Hub)"]
        CF["ClassFactory"]
        RC["@RegisterClass Decorator"]
        OC["ObjectCache"]
        BS["BaseSingleton<T>"]
        EV["Event System (RxJS)"]

        MJG --> CF
        MJG --> OC
        MJG --> EV
        RC --> CF
        MJG -.->|extends| BS
    end

    subgraph Utilities["Utility Modules"]
        direction TB
        DD["DeepDiffer"]
        JV["JSONValidator"]
        SE["SafeExpressionEvaluator"]
        SQ["SQLExpressionValidator"]
        CU["ClassUtils"]
        PU["PatternUtils"]
        WM["WarningManager"]
        EU["EncryptionUtils"]
        UT["String / JSON Utilities"]
    end

    Core["@memberjunction/core"] --> MJGlobal
    Entities["@memberjunction/core-entities"] --> MJGlobal
    Server["@memberjunction/server"] --> MJGlobal
    Angular["Angular packages"] --> MJGlobal

    style MJGlobal fill:#2d6a9f,stroke:#1a4971,color:#fff
    style Utilities fill:#7c5295,stroke:#563a6b,color:#fff
    style Core fill:#2d8659,stroke:#1a5c3a,color:#fff
    style Entities fill:#2d8659,stroke:#1a5c3a,color:#fff
    style Server fill:#2d8659,stroke:#1a5c3a,color:#fff
    style Angular fill:#2d8659,stroke:#1a5c3a,color:#fff

Installation

npm install @memberjunction/global

Core Concepts

MJGlobal -- The Singleton Hub

MJGlobal is the central coordination point for the MemberJunction runtime. It is a singleton (via BaseSingleton<T>) that provides access to the class factory, a global event bus, a property bag, and an in-memory object cache.

classDiagram
    class MJGlobal {
        +Instance : MJGlobal$
        +ClassFactory : ClassFactory
        +ObjectCache : ObjectCache
        +Properties : MJGlobalProperty[]
        +RegisterComponent(component)
        +RaiseEvent(event)
        +GetEventListener(withReplay?) : Observable~MJEvent~
        +Reset()
    }
    class ClassFactory {
        +Register(baseClass, subClass, key?, priority?)
        +CreateInstance~T~(baseClass, key?, ...params) : T
        +GetRegistration(baseClass, key?) : ClassRegistration
        +GetAllRegistrations(baseClass, key?) : ClassRegistration[]
        +GetRegistrationsByRootClass(rootClass, key?) : ClassRegistration[]
    }
    class ObjectCache {
        +Add~T~(key, object)
        +Find~T~(key) : T
        +Replace~T~(key, object)
        +Remove(key)
        +Clear()
    }
    MJGlobal --> ClassFactory
    MJGlobal --> ObjectCache

    style MJGlobal fill:#2d6a9f,stroke:#1a4971,color:#fff
    style ClassFactory fill:#2d8659,stroke:#1a5c3a,color:#fff
    style ObjectCache fill:#b8762f,stroke:#8a5722,color:#fff
import { MJGlobal } from '@memberjunction/global';

// Access the singleton
const g = MJGlobal.Instance;

// Use the class factory
const instance = g.ClassFactory.CreateInstance<MyBase>(MyBase, 'some-key');

// Use the object cache
g.ObjectCache.Add('config', { debug: true });
const config = g.ObjectCache.Find<{ debug: boolean }>('config');

// Use the global property bag
g.Properties.push({ key: 'appName', value: 'MyApp' });

Class Factory and @RegisterClass

The class factory is MemberJunction's dependency injection system. It allows any module to register a subclass for a given base class and key, so that later code can request an instance by base class and key and automatically receive the most specific (highest-priority) subclass.

flowchart LR
    A["@RegisterClass(BaseEntity, 'Users')"] -->|registers| CF["ClassFactory"]
    B["@RegisterClass(BaseEntity, 'Users', 10)"] -->|higher priority| CF
    CF -->|"CreateInstance(BaseEntity, 'Users')"| B
    CF -->|returns instance of| SUB["UserEntity (priority 10)"]

    style A fill:#64748b,stroke:#475569,color:#fff
    style B fill:#2d8659,stroke:#1a5c3a,color:#fff
    style CF fill:#2d6a9f,stroke:#1a4971,color:#fff
    style SUB fill:#b8762f,stroke:#8a5722,color:#fff

Decorator usage:

import { RegisterClass } from '@memberjunction/global';

// Register a subclass for a base class with a key
@RegisterClass(BaseFormComponent, 'Users')
export class UserFormComponent extends BaseFormComponent {
    // ...
}

// Priority controls which registration wins
@RegisterClass(BaseFormComponent, 'Users', 10)
export class CustomUserFormComponent extends UserFormComponent {
    // Wins over UserFormComponent because priority 10 > auto-assigned
}

Programmatic registration:

MJGlobal.Instance.ClassFactory.Register(
    BaseEntity,      // base class
    UserEntity,      // subclass
    'Users',         // key
    5                // priority (optional)
);

Instance creation:

const entity = MJGlobal.Instance.ClassFactory.CreateInstance<BaseEntity>(
    BaseEntity,
    'Users'
);
// Returns an instance of the highest-priority registered subclass for 'Users'

Structured registration: @RegisterClassEx + metadata

When a registration needs anything beyond (baseClass, key, priority) — toggling the rarely-used flags, or attaching metadata for runtime filtering — reach for @RegisterClassEx. It's the same registration under the hood, but accepts a typed options bag instead of trailing positional booleans:

import { RegisterClassEx } from '@memberjunction/global';

@RegisterClassEx(BaseFormPanel, {
    key: 'content-sources:tag-pipeline',
    skipNullKeyWarning: true,
    metadata: {
        entity: 'MJ: Content Sources',
        slot: 'after-fields',
        sortKey: 100,
    },
})
export class TagPipelinePanel extends BaseFormPanel { /* ... */ }

The metadata field is stored on the ClassRegistration and is purely a runtime aid for discovery — it has no effect on the priority / key lookup. Pair it with one of the discovery helpers below:

HelperUse when …
GetAllRegistrationsByMetadata(base, predicate)You have structured discriminators (entity, slot, sortKey, etc.) and want to filter on multiple fields. Recommended default.
GetAllRegistrationsByKeyPrefix(base, prefix)Registrations share a structured key prefix (e.g. "breed:..." / "<EntityName>:...") and you want everything below that prefix.
GetAllRegistrationsByKeyPattern(base, regex)More nuanced key matching than a prefix can express.
// Discover every panel that should appear in a given form's slot
const panels = MJGlobal.Instance.ClassFactory.GetAllRegistrationsByMetadata(
    BaseFormPanel,
    (m) => m?.entity === 'MJ: Content Sources' && m?.slot === 'after-fields',
);
// Sort by metadata.sortKey, then by Priority, then by registration order
panels.sort((a, b) => {
    const aSort = (a.Metadata?.sortKey as number) ?? 0;
    const bSort = (b.Metadata?.sortKey as number) ?? 0;
    return bSort !== aSort ? bSort - aSort : b.Priority - a.Priority;
});

@RegisterClass also accepts an optional sixth positional metadata arg for parity, but the options-bag form scales better past three arguments and reads better at call sites — prefer @RegisterClassEx for new code.

Event System

MJGlobal provides a publish/subscribe event bus built on RxJS. Events can be observed in real-time or with replay (a ReplaySubject buffering up to 100 events for 30 seconds).

import { MJGlobal, MJEventType } from '@memberjunction/global';

// Subscribe to events (with replay for late subscribers)
MJGlobal.Instance.GetEventListener(true).subscribe(event => {
    if (event.event === MJEventType.LoggedIn) {
        console.log('User logged in:', event.args);
    }
});

// Raise an event
MJGlobal.Instance.RaiseEvent({
    event: MJEventType.ComponentEvent,
    eventCode: 'data-loaded',
    args: { recordCount: 42 },
    component: myComponent
});

Built-in event types:

Event TypeDescription
ComponentRegisteredA component was registered with MJGlobal
ComponentUnregisteredA component was unregistered
ComponentEventGeneric component-level event
LoggedInUser authentication succeeded
LoggedOutUser logged out
LoginFailedAuthentication attempt failed
LogoutFailedLogout attempt failed
ManualResizeRequestRequest for UI components to recalculate layout
DisplaySimpleNotificationRequestRequest to show a notification to the user

BaseSingleton<T>

A generic abstract base class for implementing the singleton pattern. It uses the global object store (window in browsers, global in Node.js) to guarantee a single instance even when module code is duplicated across multiple bundle paths.

import { BaseSingleton } from '@memberjunction/global';

export class MyService extends BaseSingleton<MyService> {
    public static get Instance(): MyService {
        return super.getInstance<MyService>();
    }

    public DoWork(): void {
        // service logic
    }
}

// Usage
MyService.Instance.DoWork();

Utility Modules

DeepDiffer -- Object Comparison

Recursively compares two objects and produces a detailed, human-readable diff with change tracking.

import { DeepDiffer, DiffChangeType } from '@memberjunction/global';

const differ = new DeepDiffer({
    maxDepth: 10,
    treatNullAsUndefined: true,
    includeUnchanged: false
});

const result = differ.diff(
    { name: 'Alice', age: 30, tags: ['dev'] },
    { name: 'Alice', age: 31, tags: ['dev', 'lead'] }
);

console.log(result.summary);
// { added: 1, removed: 0, modified: 2, unchanged: 0, totalPaths: 3 }

console.log(result.formatted);
// === Deep Diff Summary ===
// Total changes: 3
//   Added: 1
//   Modified: 2
// ...

JSONValidator -- Template-Based Validation

A lightweight validator that checks objects against example templates using special field-name syntax for validation rules.

import { JSONValidator } from '@memberjunction/global';

const validator = new JSONValidator();

const template = {
    "name": "example",               // required
    "email?": "user@example.com",    // optional (? suffix)
    "config*": {},                   // required, any content (* suffix)
    "tags:[1+]": ["tag1"],           // array with 1+ items
    "count:number": 0,               // must be a number
    "title:string:!empty": ""        // must be a non-empty string
};

const result = validator.validate(myData, template);
if (!result.Success) {
    console.log(result.Errors);
}

Supported validation rules:

SyntaxMeaning
field?Field is optional
field*Required, accepts any content
field:stringMust be a string
field:numberMust be a number
field:booleanMust be a boolean
field:objectMust be a plain object
field:arrayMust be an array
field:!emptyMust not be empty
field:[N+]Array with at least N elements
field:[N-M]Array with N to M elements
field:[=N]Array with exactly N elements

SafeExpressionEvaluator

Evaluates boolean expressions against context objects securely, blocking injection patterns like eval(), require(), process., template literals, and more.

import { SafeExpressionEvaluator } from '@memberjunction/global';

const evaluator = new SafeExpressionEvaluator();

const result = evaluator.evaluate(
    "customer.tier == 'premium' && order.total > 1000",
    {
        customer: { tier: 'premium' },
        order: { total: 1500 }
    }
);

if (result.success) {
    console.log(result.value); // true
}

Supports comparisons (==, !=, <, >, <=, >=), logical operators (&&, ||, !), dot-notation property access, bracket-notation array access, and safe string/array methods (.includes(), .startsWith(), .some(), .every(), etc.).

SQLExpressionValidator

Validates user-provided SQL expressions and full queries against injection attacks. Provides context-aware validation (WHERE clauses, ORDER BY, aggregates, field references, full queries) with an allowlist of safe SQL functions.

Expression validation (WHERE clauses, aggregates, ORDER BY):

import { SQLExpressionValidator } from '@memberjunction/global';

const validator = SQLExpressionValidator.Instance;

// Validate a WHERE clause
const result = validator.validate("Status = 'Active' AND Total > 100", {
    context: 'where_clause'
});
// result.valid === true

// Unsafe input is rejected
const bad = validator.validate("Name = 'test'; 1=1", {
    context: 'where_clause'
});
// bad.valid === false

Full query validation (ad-hoc SELECT/WITH statements):

// Validate a complete SQL query — allows SELECT, JOINs, subqueries, set operations, comments
const result = validator.validateFullQuery('SELECT TOP 10 * FROM __mj.vwUsers WHERE IsActive = 1');
// result.valid === true

// Mutations and dangerous operations are blocked
const bad = validator.validateFullQuery("INSERT INTO Users (Name) VALUES ('hacked')");
// bad.valid === false, bad.trigger === 'INSERT'

The full_query context allows keywords that are legitimate in SELECT statements (EXISTS, ANY, ALL, UNION, INTERSECT, EXCEPT, IF) while still blocking all mutations (INSERT, UPDATE, DELETE, DROP, etc.), dangerous operations (EXEC, OPENROWSET, WAITFOR), and multi-statement injection (semicolons).

ClassUtils -- Reflection Helpers

Functions for introspecting class hierarchies at runtime.

import {
    GetSuperclass,
    GetRootClass,
    IsSubclassOf,
    IsRootClass,
    GetClassInheritance,
    GetFullClassHierarchy,
    GetClassName,
    IsClassConstructor
} from '@memberjunction/global';

const chain = GetClassInheritance(MyDerivedClass);
// [{ name: 'MyBaseClass', reference: ... }, { name: 'MyRootClass', reference: ... }]

const isChild = IsSubclassOf(ChildClass, ParentClass); // true
const root = GetRootClass(ChildClass); // returns the top-most user-defined class

PatternUtils -- Wildcard and Regex Matching

Converts wildcard patterns and regex strings to RegExp objects for flexible text matching.

import { parsePattern, matchesAnyPattern } from '@memberjunction/global';

const regex = parsePattern('*AIPrompt*');   // matches strings containing "AIPrompt"
const exact = parsePattern('Users');        // matches exactly "Users" (case-insensitive)
const re = parsePattern('/^sp_Create/i');   // parsed as a regex literal

const matches = matchesAnyPattern('AIPromptRuns', ['*Prompt*', '*Agent*']); // true

ObjectCache

A simple in-memory key-value cache with type-safe generic accessors. Keys are case-insensitive.

import { MJGlobal } from '@memberjunction/global';

const cache = MJGlobal.Instance.ObjectCache;

cache.Add('user-prefs', { theme: 'dark' });
const prefs = cache.Find<{ theme: string }>('User-Prefs'); // case-insensitive lookup
cache.Replace('user-prefs', { theme: 'light' });
cache.Remove('user-prefs');
cache.Clear();

WarningManager

A singleton warning system with session-level deduplication, debounced output, and tree-structured formatting. Tracks deprecation warnings, field-not-found warnings, and redundant load warnings.

import { WarningManager } from '@memberjunction/global';

const wm = WarningManager.Instance;

// Configure
wm.UpdateConfig({ DebounceMs: 5000, GroupWarnings: true });

// Record warnings (deduplicated and batched automatically)
wm.RecordEntityDeprecationWarning('User Preferences', 'BaseEntity::constructor');
wm.RecordFieldNotFoundWarning('Users', 'DeletedColumn', 'BaseEntity::SetMany');
wm.RecordRedundantLoadWarning('AI Models', ['DashboardEngine', 'AIEngine']);

// Force immediate output if needed
wm.FlushWarnings();

EncryptionUtils

Constants and utility functions for working with encrypted field values. Located in this foundational package so any package can detect encrypted values without depending on the full Encryption package.

import {
    IsValueEncrypted,
    IsEncryptedSentinel,
    ENCRYPTION_MARKER,
    ENCRYPTED_SENTINEL
} from '@memberjunction/global';

IsValueEncrypted('$ENC$keyId$AES-256-GCM$iv$ciphertext$authTag'); // true
IsValueEncrypted('[!ENCRYPTED$]');                                 // true (sentinel)
IsValueEncrypted('plain text');                                    // false
IsEncryptedSentinel('[!ENCRYPTED$]');                              // true

String and JSON Utilities

A collection of utility functions for common string and JSON operations.

FunctionDescription
CleanJSON(input)Extracts and formats JSON from various formats (double-escaped, markdown blocks, mixed content)
SafeJSONParse<T>(json, logErrors?)Parses JSON returning T or null without throwing
CleanAndParseJSON<T>(input, logErrors?)Combines CleanJSON and SafeJSONParse in one call
ParseJSONRecursive(obj, options?)Recursively parses nested JSON strings within objects
CleanJavaScript(code)Extracts JavaScript from markdown code blocks
CopyScalarsAndArrays<T>(input, resolveCircular?)Deep-copies scalar and array properties, optionally handling circular references
convertCamelCaseToHaveSpaces(s)"AIAgentRun" becomes "AI Agent Run"
stripWhitespace(s)Removes all whitespace from a string
generatePluralName(singular, options?)Handles irregular and regular English pluralization
getIrregularPlural(word)Looks up irregular plural forms
adjustCasing(word, options?)Capitalizes first letter, entire word, or leaves as-is
stripTrailingChars(s, chars, skipIfExact?)Removes trailing substring
replaceAllSpaces(s)Removes all space characters
compareStringsByLine(str1, str2, log?)Line-by-line diff with character-level detail
IsOnlyTimezoneShift(date1, date2)Detects if two dates differ only by a whole-hour timezone offset
InvokeManualResize(delay?, component?)Broadcasts a ManualResizeRequest event
uuidv4()Generates a v4 UUID
GetGlobalObjectStore()Returns window (browser) or global (Node.js) for cross-environment state

ValidationTypes

Standard validation result types used across the framework.

import { ValidationResult, ValidationErrorInfo, ValidationErrorType } from '@memberjunction/global';

const result = new ValidationResult();
result.Success = false;
result.Errors.push(
    new ValidationErrorInfo('fieldName', 'Value is required', null, ValidationErrorType.Failure)
);

Module Dependency Flow

flowchart TB
    subgraph MJGlobal["@memberjunction/global (this package)"]
        direction LR
        G["MJGlobal"]
        CF["ClassFactory"]
        RC["RegisterClass"]
        BS["BaseSingleton"]
        OC["ObjectCache"]
        U["Utilities"]
    end

    subgraph External["External Dependencies"]
        RX["rxjs"]
        LO["lodash"]
        UUID["uuid"]
    end

    G --> RX
    U --> LO
    U --> UUID

    subgraph Consumers["Consuming Packages (examples)"]
        direction LR
        MJC["@memberjunction/core"]
        MCE["@memberjunction/core-entities"]
        GQL["@memberjunction/graphql-dataprovider"]
        ENC["@memberjunction/encryption"]
    end

    Consumers --> MJGlobal

    style MJGlobal fill:#2d6a9f,stroke:#1a4971,color:#fff
    style External fill:#b8762f,stroke:#8a5722,color:#fff
    style Consumers fill:#2d8659,stroke:#1a5c3a,color:#fff

API Reference

MJGlobal

MemberTypeDescription
InstanceMJGlobal (static)Returns the singleton instance
ClassFactoryClassFactoryAccess the class registration and instantiation system
ObjectCacheObjectCacheIn-memory key-value cache
PropertiesMJGlobalProperty[]Global property bag for arbitrary key-value storage
RegisterComponent(component)voidRegister an IMJComponent
RaiseEvent(event)voidPublish an MJEvent to all listeners
GetEventListener(withReplay?)Observable<MJEvent>Subscribe to the event stream
Reset()voidReset all internal state (use with extreme caution)

ClassFactory

MethodReturnsDescription
Register(baseClass, subClass, key?, priority?, skipNullKeyWarning?, autoRegisterWithRootClass?)voidRegister a subclass for a base class and optional key
CreateInstance<T>(baseClass, key?, ...params)T | nullCreate an instance of the highest-priority registered subclass (sync)
CreateInstanceAsync<T>(baseClass, key?, ...params)Promise<T | null>Async version that triggers lazy loaders if registration not found
GetRegistration(baseClass, key?)ClassRegistration | nullGet the highest-priority registration (sync)
GetRegistrationAsync(baseClass, key?)Promise<ClassRegistration | null>Async version that triggers lazy loaders if registration not found
GetAllRegistrations(baseClass, key?)ClassRegistration[]Get all registrations for a base class and optional key
GetRegistrationsByRootClass(rootClass, key?)ClassRegistration[]Get registrations by root class in the hierarchy
RegisterLazyLoader(loader)voidRegister a callback (baseClassName, key) => Promise<boolean> called when a registration is not found. Multiple loaders can be registered and are called in order.

RegisterClass Decorator

function RegisterClass(
    baseClass: unknown,
    key?: string | null,
    priority?: number,
    skipNullKeyWarning?: boolean,
    autoRegisterWithRootClass?: boolean
): (constructor: Function) => void;

ObjectCache

MethodReturnsDescription
Add<T>(key, object)voidAdd entry; throws if key exists
Find<T>(key)T | nullCase-insensitive key lookup
Replace<T>(key, object)voidReplace or add entry
Remove(key)voidRemove entry by key
Clear()voidRemove all entries

DeepDiffer

MethodReturnsDescription
diff<T>(oldValue, newValue)DeepDiffResultGenerate a full diff between two values
updateConfig(config)voidUpdate configuration options

JSONValidator

MethodReturnsDescription
validate(data, template, path?)ValidationResultValidate data against a template
validateAgainstSchema(data, schemaJson)ValidationResultValidate against a JSON string schema
cleanValidationSyntax<T>(data)TStrip validation markers from keys

SafeExpressionEvaluator

MethodReturnsDescription
evaluate(expression, context, enableDiagnostics?)ExpressionEvaluationResultEvaluate a single boolean expression
evaluateMultiple(expressions, context)Record<string, ExpressionEvaluationResult>Evaluate multiple expressions

SQLExpressionValidator

MethodReturnsDescription
Instance (static)SQLExpressionValidatorSingleton accessor
validate(expression, options)SQLValidationResultValidate a SQL expression with context-specific rules
validateFullQuery(sql)SQLValidationResultValidate a full SELECT/WITH query (convenience for validate(sql, { context: 'full_query' }))

WarningManager

MethodReturnsDescription
Instance (static)WarningManagerSingleton accessor
UpdateConfig(config)voidUpdate warning configuration
GetConfig()Readonly<WarningConfig>Get current configuration
RecordEntityDeprecationWarning(entityName, callerName)booleanRecord an entity deprecation warning
RecordFieldDeprecationWarning(entityName, fieldName, callerName)booleanRecord a field deprecation warning
RecordFieldNotFoundWarning(entityName, fieldName, context)booleanRecord a field-not-found warning
RecordRedundantLoadWarning(entityName, engines)booleanRecord a redundant data loading warning
FlushWarnings()voidForce immediate output of all pending warnings
Reset()voidClear all tracking state

Dependencies

PackagePurpose
rxjsObservable-based event system (Subject, ReplaySubject)
lodashDeep comparison, type checking, object utilities
uuidUUID v4 generation
PackageRelationship
@memberjunction/coreBuilds on MJGlobal; adds Metadata, RunView, BaseEntity, and more
@memberjunction/core-entitiesGenerated entity subclasses registered via @RegisterClass
@memberjunction/encryptionFull encryption implementation; uses EncryptionUtils constants from this package
@memberjunction/serverServer-side runtime that depends on MJGlobal for class factory and events
@memberjunction/graphql-dataproviderClient-side data provider registered through the class factory

Build

# From the package directory
cd packages/MJGlobal
npm run build

The build step runs tsc followed by tsc-alias for path alias resolution.

FAQs

Package last updated on 16 Jun 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts