
Product
Announcing Socket Certified Patches: One-Click Fixes for Vulnerable Dependencies
A safer, faster way to eliminate vulnerabilities without updating dependencies
@friggframework/core
Advanced tools
The @friggframework/core package is the foundational layer of the Frigg Framework, implementing a hexagonal architecture pattern for building scalable, maintainable enterprise integrations. It provides the essential building blocks, domain logic, and infrastructure components that power the entire Frigg ecosystem.
Frigg Core implements a hexagonal architecture (also known as ports and adapters) that separates business logic from external concerns:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Inbound Adapters β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β Express β β Lambda β β WebSocket β β
β β Routes β β Handlers β β Handlers β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Application Layer β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β Use Cases β β Services β β Coordinatorsβ β
β β (Business β β β β β β
β β Logic) β β β β β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Domain Layer β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β Integration β β Entities β β Value β β
β β Aggregates β β β β Objects β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Outbound Adapters β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β Database β β API Modules β β Event β β
β β Repositoriesβ β β β Publishers β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
npm install @friggframework/core
# or
yarn add @friggframework/core
@friggframework/core supports both MongoDB and PostgreSQL via Prisma ORM. Prisma is an optional peer dependency - you only need to install it if you're using database features that require migrations or schema generation.
When you need Prisma:
prisma migrate, prisma db push)dbMigrate)Installation:
# Install Prisma CLI and Client as dev dependencies
npm install --save-dev prisma @prisma/client
# Or with yarn
yarn add -D prisma @prisma/client
Generate Prisma Clients:
# From @friggframework/core directory
npm run prisma:generate:mongo # MongoDB only
npm run prisma:generate:postgres # PostgreSQL only
npm run prisma:generate # Both databases
Note: The published npm package includes pre-generated Prisma clients, so you don't need to install Prisma just to use @friggframework/core in production. Prisma is only required if you're actively developing migrations or running the migration Lambda function.
# Database
MONGO_URI=mongodb://localhost:27017/frigg
FRIGG_ENCRYPTION_KEY=your-256-bit-encryption-key
# AWS (Optional - for production deployments)
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
# Logging
DEBUG=frigg:*
LOG_LEVEL=info
/integrations)The heart of the framework - manages integration lifecycle and business logic.
Key Classes:
IntegrationBase - Base class for all integrationsIntegration - Domain aggregate using Proxy patternCreateIntegration, UpdateIntegration, DeleteIntegrationUsage:
const { IntegrationBase } = require('@friggframework/core');
class SlackHubSpotSync extends IntegrationBase {
static Definition = {
name: 'slack-hubspot-sync',
version: '2.1.0',
modules: {
slack: 'slack',
hubspot: 'hubspot'
}
};
async onCreate({ integrationId }) {
// Setup webhooks, initial sync, etc.
await this.slack.createWebhook(process.env.WEBHOOK_URL);
await this.hubspot.setupContactSync();
await super.onCreate({ integrationId });
}
}
/database)MongoDB integration with Mongoose ODM.
Key Components:
Usage:
const {
connectToDatabase,
IntegrationModel,
UserModel
} = require('@friggframework/core');
await connectToDatabase();
// Query integrations
const userIntegrations = await IntegrationModel.find({
userId: 'user-123',
status: 'ENABLED'
});
// Create user
const user = new UserModel({
email: 'user@example.com',
name: 'John Doe'
});
await user.save();
/encrypt)AES-256-GCM encryption for sensitive data.
Usage:
const { Encrypt, Cryptor } = require('@friggframework/core');
// Simple encryption
const encrypted = Encrypt.encrypt('sensitive-data');
const decrypted = Encrypt.decrypt(encrypted);
// Advanced encryption with custom key
const cryptor = new Cryptor(process.env.CUSTOM_KEY);
const secureData = cryptor.encrypt(JSON.stringify({
accessToken: 'oauth-token',
refreshToken: 'refresh-token'
}));
/errors)Standardized error types with proper HTTP status codes.
Usage:
const {
BaseError,
RequiredPropertyError,
FetchError
} = require('@friggframework/core');
// Custom business logic error
throw new RequiredPropertyError('userId is required');
// API communication error
throw new FetchError('Failed to fetch data from external API', {
statusCode: 404,
response: errorResponse
});
// Base error with custom properties
throw new BaseError('Integration failed', {
integrationId: 'int-123',
errorCode: 'SYNC_FAILED'
});
/logs)Structured logging with debug capabilities.
Usage:
const { debug, initDebugLog, flushDebugLog } = require('@friggframework/core');
// Initialize debug logging
initDebugLog('integration:slack');
// Log debug information
debug('Processing webhook payload', {
eventType: 'contact.created',
payload: webhookData
});
// Flush logs (useful in serverless environments)
await flushDebugLog();
/user)Comprehensive user authentication and authorization system supporting both individual and organizational users.
Key Classes:
User - Domain aggregate for user entitiesUserRepository - Data access for user operationsLoginUser, CreateIndividualUser, CreateOrganizationUser, GetUserFromBearerTokenUser Types:
Authentication Methods:
Usage:
const {
LoginUser,
CreateIndividualUser,
GetUserFromBearerToken,
UserRepository
} = require('@friggframework/core');
// Configure user behavior in app definition
const userConfig = {
usePassword: true,
primary: 'individual', // or 'organization'
individualUserRequired: true,
organizationUserRequired: false
};
const userRepository = new UserRepository({ userConfig });
// Create individual user
const createUser = new CreateIndividualUser({ userRepository, userConfig });
const user = await createUser.execute({
email: 'user@example.com',
username: 'john_doe',
password: 'secure_password',
appUserId: 'external_user_123' // Optional external reference
});
// Login user
const loginUser = new LoginUser({ userRepository, userConfig });
const authenticatedUser = await loginUser.execute({
username: 'john_doe',
password: 'secure_password'
});
// Token-based authentication
const getUserFromToken = new GetUserFromBearerToken({ userRepository, userConfig });
const user = await getUserFromToken.execute('Bearer eyJhbGciOiJIUzI1NiIs...');
// Access user properties
console.log('User ID:', user.getId());
console.log('Primary user:', user.getPrimaryUser());
console.log('Individual user:', user.getIndividualUser());
console.log('Organization user:', user.getOrganizationUser());
/lambda)AWS Lambda-specific utilities and helpers.
Usage:
const { TimeoutCatcher } = require('@friggframework/core');
exports.handler = async (event, context) => {
const timeoutCatcher = new TimeoutCatcher(context);
try {
// Long-running integration process
const result = await processIntegrationSync(event);
return { statusCode: 200, body: JSON.stringify(result) };
} catch (error) {
if (timeoutCatcher.isNearTimeout()) {
// Handle graceful shutdown
await saveProgressState(event);
return { statusCode: 202, body: 'Processing continues...' };
}
throw error;
}
};
Frigg Core provides a flexible user management system that supports various authentication patterns and user types. The system is designed around the concept of Individual Users (personal accounts) and Organization Users (business accounts), with configurable authentication methods.
User behavior is configured in the app definition, allowing you to customize authentication requirements:
// App Definition with User Configuration
const appDefinition = {
integrations: [HubSpotIntegration],
user: {
usePassword: true, // Enable password authentication
primary: 'individual', // Primary user type: 'individual' or 'organization'
organizationUserRequired: true, // Require organization user
individualUserRequired: true, // Require individual user
}
};
The User class provides a rich domain model with behavior:
const { User } = require('@friggframework/core');
// User instance methods
const user = new User(individualUser, organizationUser, usePassword, primary);
// Access methods
user.getId() // Get primary user ID
user.getPrimaryUser() // Get primary user based on config
user.getIndividualUser() // Get individual user
user.getOrganizationUser() // Get organization user
// Validation methods
user.isPasswordRequired() // Check if password is required
user.isPasswordValid(password) // Validate password
user.isIndividualUserRequired() // Check individual user requirement
user.isOrganizationUserRequired() // Check organization user requirement
// Configuration methods
user.setIndividualUser(individualUser)
user.setOrganizationUser(organizationUser)
The user system uses MongoDB with Mongoose for data persistence:
// Individual User Schema
{
email: String,
username: { type: String, unique: true },
hashword: String, // Encrypted password
appUserId: String, // External app reference
organizationUser: ObjectId // Reference to organization
}
// Organization User Schema
{
name: String,
appOrgId: String, // External organization reference
domain: String,
settings: Object
}
// Session Token Schema
{
user: ObjectId, // Reference to user
token: String, // Encrypted token
expires: Date,
created: Date
}
Each business operation is encapsulated in a use case class:
class UpdateIntegrationStatus {
constructor({ integrationRepository }) {
this.integrationRepository = integrationRepository;
}
async execute(integrationId, newStatus) {
// Business logic validation
if (!['ENABLED', 'DISABLED', 'ERROR'].includes(newStatus)) {
throw new Error('Invalid status');
}
// Domain operation
const integration = await this.integrationRepository.findById(integrationId);
if (!integration) {
throw new Error('Integration not found');
}
// Update and persist
integration.status = newStatus;
integration.updatedAt = new Date();
return await this.integrationRepository.save(integration);
}
}
Data access is abstracted through repositories:
class IntegrationRepository {
async findById(id) {
return await IntegrationModel.findById(id);
}
async findByUserId(userId) {
return await IntegrationModel.find({ userId, deletedAt: null });
}
async save(integration) {
return await integration.save();
}
async createIntegration(entities, userId, config) {
const integration = new IntegrationModel({
entitiesIds: entities,
userId,
config,
status: 'NEW',
createdAt: new Date()
});
return await integration.save();
}
}
Complex business objects with behavior:
const Integration = new Proxy(class {}, {
construct(target, args) {
const [params] = args;
const instance = new params.integrationClass(params);
// Attach domain properties
Object.assign(instance, {
id: params.id,
userId: params.userId,
entities: params.entities,
config: params.config,
status: params.status,
modules: params.modules
});
return instance;
}
});
Here's a complete, production-ready HubSpot integration that demonstrates advanced Frigg features:
const {
get,
IntegrationBase,
WebsocketConnection,
} = require('@friggframework/core');
const FriggConstants = require('../utils/constants');
const hubspot = require('@friggframework/api-module-hubspot');
const testRouter = require('../testRouter');
const extensions = require('../extensions');
class HubSpotIntegration extends IntegrationBase {
static Definition = {
name: 'hubspot',
version: '1.0.0',
supportedVersions: ['1.0.0'],
hasUserConfig: true,
display: {
label: 'HubSpot',
description: hubspot.Config.description,
category: 'Sales & CRM, Marketing',
detailsUrl: 'https://hubspot.com',
icon: hubspot.Config.logoUrl,
},
modules: {
hubspot: {
definition: hubspot.Definition,
},
},
// Express routes for webhook endpoints and custom APIs
routes: [
{
path: '/hubspot/webhooks',
method: 'POST',
event: 'HUBSPOT_WEBHOOK',
},
testRouter,
],
};
constructor() {
super();
// Define event handlers for various integration actions
this.events = {
// Webhook handler with real-time WebSocket broadcasting
HUBSPOT_WEBHOOK: {
handler: async ({ data, context }) => {
console.log('Received HubSpot webhook:', data);
// Broadcast to all connected WebSocket clients
const activeConnections = await WebsocketConnection.getActiveConnections();
const message = JSON.stringify({
type: 'HUBSPOT_WEBHOOK',
data,
});
activeConnections.forEach((connection) => {
connection.send(message);
});
},
},
// User action: Get sample data with formatted table output
[FriggConstants.defaultEvents.GET_SAMPLE_DATA]: {
type: FriggConstants.eventTypes.USER_ACTION,
handler: this.getSampleData,
title: 'Get Sample Data',
description: 'Get sample data from HubSpot and display in a formatted table',
userActionType: 'QUICK_ACTION',
},
// User action: List available objects
GET_OBJECT_LIST: {
type: FriggConstants.eventTypes.USER_ACTION,
handler: this.getObjectList,
title: 'Get Object List',
description: 'Get list of available HubSpot objects',
userActionType: 'DATA',
},
// User action: Create records with dynamic forms
CREATE_RECORD: {
type: FriggConstants.eventTypes.USER_ACTION,
handler: this.createRecord,
title: 'Create Record',
description: 'Create a new record in HubSpot',
userActionType: 'DATA',
},
};
// Extension system for modular functionality
this.extensions = {
hubspotWebhooks: {
extension: extensions.hubspotWebhooks,
handlers: {
WEBHOOK_EVENT: this.handleWebhookEvent,
},
},
};
}
// Business logic: Fetch and format sample data
async getSampleData({ objectName }) {
let res;
switch (objectName) {
case 'deals':
res = await this.hubspot.api.searchDeals({
properties: ['dealname,amount,closedate'],
});
break;
case 'contacts':
res = await this.hubspot.api.listContacts({
after: 0,
properties: 'firstname,lastname,email',
});
break;
case 'companies':
res = await this.hubspot.api.searchCompanies({
properties: ['name,website,email'],
limit: 100,
});
break;
default:
throw new Error(`Unsupported object type: ${objectName}`);
}
const portalId = this.hubspot.entity.externalId;
// Format data with HubSpot record links
const formatted = res.results.map((item) => {
const formattedItem = {
linkToRecord: `https://app.hubspot.com/contacts/${portalId}/${objectName}/${item.id}/`,
id: item.id,
};
// Clean and format properties
for (const [key, value] of Object.entries(item.properties)) {
if (value !== null && value !== undefined && value !== '') {
formattedItem[key] = value;
}
}
delete formattedItem.hs_object_id;
return formattedItem;
});
return { label: objectName, data: formatted };
}
// Return available HubSpot object types
async getObjectList() {
return [
{ key: 'deals', label: 'Deals' },
{ key: 'contacts', label: 'Contacts' },
{ key: 'companies', label: 'Companies' },
];
}
// Create records based on object type
async createRecord(args) {
let res;
const objectType = args.objectType;
delete args.objectType;
switch (objectType.toLowerCase()) {
case 'deal':
res = await this.hubspot.api.createDeal({ ...args });
break;
case 'company':
res = await this.hubspot.api.createCompany({ ...args });
break;
case 'contact':
res = await this.hubspot.api.createContact({ ...args });
break;
default:
throw new Error(`Unsupported object type: ${objectType}`);
}
return { data: res };
}
// Dynamic form generation based on action and context
async getActionOptions({ actionId, data }) {
switch (actionId) {
case 'CREATE_RECORD':
let jsonSchema = {
type: 'object',
properties: {
objectType: {
type: 'string',
title: 'Object Type',
},
},
required: [],
};
let uiSchema = {
type: 'HorizontalLayout',
elements: [
{
type: 'Control',
scope: '#/properties/objectType',
rule: { effect: 'HIDE', condition: {} },
},
],
};
// Generate form fields based on object type
switch (data.name.toLowerCase()) {
case 'deal':
jsonSchema.properties = {
...jsonSchema.properties,
dealname: { type: 'string', title: 'Deal Name' },
amount: { type: 'number', title: 'Amount' },
};
jsonSchema.required = ['dealname', 'amount'];
uiSchema.elements.push(
{ type: 'Control', scope: '#/properties/dealname' },
{ type: 'Control', scope: '#/properties/amount' }
);
break;
case 'company':
jsonSchema.properties = {
...jsonSchema.properties,
name: { type: 'string', title: 'Company Name' },
website: { type: 'string', title: 'Website URL' },
};
jsonSchema.required = ['name', 'website'];
uiSchema.elements.push(
{ type: 'Control', scope: '#/properties/name' },
{ type: 'Control', scope: '#/properties/website' }
);
break;
case 'contact':
jsonSchema.properties = {
...jsonSchema.properties,
firstname: { type: 'string', title: 'First Name' },
lastname: { type: 'string', title: 'Last Name' },
email: { type: 'string', title: 'Email Address' },
};
jsonSchema.required = ['firstname', 'lastname', 'email'];
uiSchema.elements.push(
{ type: 'Control', scope: '#/properties/firstname' },
{ type: 'Control', scope: '#/properties/lastname' },
{ type: 'Control', scope: '#/properties/email' }
);
break;
default:
throw new Error(`Unsupported object type: ${data.name}`);
}
return {
jsonSchema,
uiSchema,
data: { objectType: data.name },
};
}
return null;
}
async getConfigOptions() {
// Return configuration options for the integration
return {};
}
}
module.exports = HubSpotIntegration;
index.js
const HubSpotIntegration = require('./src/integrations/HubSpotIntegration');
const appDefinition = {
integrations: [
HubSpotIntegration,
],
user: {
usePassword: true,
primary: 'individual',
organizationUserRequired: true,
individualUserRequired: true,
}
}
module.exports = {
Definition: appDefinition,
}
This real-world example showcases:
π Webhook Integration: Real-time event processing with WebSocket broadcasting
π User Actions: Interactive data operations with dynamic form generation
π― API Module Integration: Direct use of @friggframework/api-module-hubspot
π Extension System: Modular functionality through extensions
π Dynamic Forms: JSON Schema-based form generation for different object types
π Deep Linking: Direct links to HubSpot records in formatted data
β‘ Real-time Updates: WebSocket connections for live data streaming
# Run all tests
npm test
# Run specific test file
npm test -- --testPathPattern="integration.test.js"
The core package uses a comprehensive testing approach:
// Example test structure
describe('CreateIntegration Use-Case', () => {
let integrationRepository;
let moduleFactory;
let useCase;
beforeEach(() => {
integrationRepository = new TestIntegrationRepository();
moduleFactory = new TestModuleFactory();
useCase = new CreateIntegration({
integrationRepository,
integrationClasses: [TestIntegration],
moduleFactory
});
});
describe('happy path', () => {
it('creates an integration and returns DTO', async () => {
const result = await useCase.execute(['entity-1'], 'user-1', { type: 'test' });
expect(result.id).toBeDefined();
expect(result.status).toBe('NEW');
});
});
describe('error cases', () => {
it('throws error for unknown integration type', async () => {
await expect(useCase.execute(['entity-1'], 'user-1', { type: 'unknown' }))
.rejects.toThrow('No integration class found for type: unknown');
});
});
});
The framework provides test doubles for external dependencies:
const { TestIntegrationRepository, TestModuleFactory } = require('@friggframework/core/test');
// Mock repository for testing
const testRepo = new TestIntegrationRepository();
testRepo.addMockIntegration({ id: 'test-123', userId: 'user-1' });
// Mock module factory
const testFactory = new TestModuleFactory();
testFactory.addMockModule('hubspot', mockHubSpotModule);
packages/core/
βββ integrations/ # Integration domain logic
β βββ use-cases/ # Business use cases
β βββ tests/ # Integration tests
β βββ integration-base.js # Base integration class
βββ modules/ # API module system
β βββ requester/ # HTTP clients
β βββ use-cases/ # Module management
βββ database/ # Data persistence
βββ encrypt/ # Encryption utilities
βββ errors/ # Error definitions
βββ logs/ # Logging system
βββ lambda/ # Serverless utilities
# Format code
npm run lint:fix
# Check linting
npm run lint
const {
// Integrations
IntegrationBase,
IntegrationModel,
CreateIntegration,
UpdateIntegration,
DeleteIntegration,
// Modules
OAuth2Requester,
ApiKeyRequester,
Credential,
Entity,
// Database
connectToDatabase,
mongoose,
UserModel,
// Utilities
Encrypt,
Cryptor,
BaseError,
debug,
TimeoutCatcher
} = require('@friggframework/core');
| Variable | Required | Description |
|---|---|---|
MONGO_URI | Yes | MongoDB connection string |
FRIGG_ENCRYPTION_KEY | Yes | 256-bit encryption key |
AWS_REGION | No | AWS region for services |
DEBUG | No | Debug logging pattern |
LOG_LEVEL | No | Logging level (debug, info, warn, error) |
This project is licensed under the MIT License - see the LICENSE.md file for details.
Built with β€οΈ by the Frigg Framework team.
FAQs
Unknown package
We found that @friggframework/core demonstrated a not healthy version release cadence and project activity because the last version was released a year ago.Β It has 3 open source maintainers collaborating on the project.
Did you know?

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.

Product
A safer, faster way to eliminate vulnerabilities without updating dependencies

Product
Reachability analysis for Ruby is now in beta, helping teams identify which vulnerabilities are truly exploitable in their applications.

Research
/Security News
Malicious npm packages use Adspect cloaking and fake CAPTCHAs to fingerprint visitors and redirect victims to crypto-themed scam sites.