@friggframework/core 2.0.0-next.41 → 2.0.0-next.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +693 -0
- package/README.md +931 -50
- package/application/commands/README.md +421 -0
- package/application/commands/credential-commands.js +224 -0
- package/application/commands/entity-commands.js +315 -0
- package/application/commands/integration-commands.js +160 -0
- package/application/commands/integration-commands.test.js +123 -0
- package/application/commands/user-commands.js +213 -0
- package/application/index.js +69 -0
- package/core/CLAUDE.md +690 -0
- package/core/create-handler.js +0 -6
- package/credential/repositories/credential-repository-factory.js +47 -0
- package/credential/repositories/credential-repository-interface.js +98 -0
- package/credential/repositories/credential-repository-mongo.js +301 -0
- package/credential/repositories/credential-repository-postgres.js +307 -0
- package/credential/repositories/credential-repository.js +307 -0
- package/credential/use-cases/get-credential-for-user.js +21 -0
- package/credential/use-cases/update-authentication-status.js +15 -0
- package/database/config.js +117 -0
- package/database/encryption/README.md +683 -0
- package/database/encryption/encryption-integration.test.js +553 -0
- package/database/encryption/encryption-schema-registry.js +141 -0
- package/database/encryption/encryption-schema-registry.test.js +392 -0
- package/database/encryption/field-encryption-service.js +226 -0
- package/database/encryption/field-encryption-service.test.js +525 -0
- package/database/encryption/logger.js +79 -0
- package/database/encryption/mongo-decryption-fix-verification.test.js +348 -0
- package/database/encryption/postgres-decryption-fix-verification.test.js +371 -0
- package/database/encryption/postgres-relation-decryption.test.js +245 -0
- package/database/encryption/prisma-encryption-extension.js +222 -0
- package/database/encryption/prisma-encryption-extension.test.js +439 -0
- package/database/index.js +25 -12
- package/database/models/readme.md +1 -0
- package/database/prisma.js +162 -0
- package/database/repositories/health-check-repository-factory.js +38 -0
- package/database/repositories/health-check-repository-interface.js +86 -0
- package/database/repositories/health-check-repository-mongodb.js +72 -0
- package/database/repositories/health-check-repository-postgres.js +75 -0
- package/database/repositories/health-check-repository.js +108 -0
- package/database/use-cases/check-database-health-use-case.js +34 -0
- package/database/use-cases/check-encryption-health-use-case.js +82 -0
- package/database/use-cases/test-encryption-use-case.js +252 -0
- package/encrypt/Cryptor.js +20 -152
- package/encrypt/index.js +1 -2
- package/encrypt/test-encrypt.js +0 -2
- package/handlers/app-definition-loader.js +38 -0
- package/handlers/app-handler-helpers.js +0 -3
- package/handlers/auth-flow.integration.test.js +147 -0
- package/handlers/backend-utils.js +25 -45
- package/handlers/integration-event-dispatcher.js +54 -0
- package/handlers/integration-event-dispatcher.test.js +141 -0
- package/handlers/routers/HEALTHCHECK.md +103 -1
- package/handlers/routers/auth.js +3 -14
- package/handlers/routers/health.js +63 -424
- package/handlers/routers/health.test.js +7 -0
- package/handlers/routers/integration-defined-routers.js +8 -5
- package/handlers/routers/user.js +27 -5
- package/handlers/routers/websocket.js +5 -3
- package/handlers/use-cases/check-external-apis-health-use-case.js +81 -0
- package/handlers/use-cases/check-integrations-health-use-case.js +32 -0
- package/handlers/workers/integration-defined-workers.js +6 -3
- package/index.js +45 -22
- package/integrations/index.js +12 -10
- package/integrations/integration-base.js +224 -53
- package/integrations/integration-router.js +386 -178
- package/integrations/options.js +1 -1
- package/integrations/repositories/integration-mapping-repository-factory.js +50 -0
- package/integrations/repositories/integration-mapping-repository-interface.js +106 -0
- package/integrations/repositories/integration-mapping-repository-mongo.js +161 -0
- package/integrations/repositories/integration-mapping-repository-postgres.js +227 -0
- package/integrations/repositories/integration-mapping-repository.js +156 -0
- package/integrations/repositories/integration-repository-factory.js +44 -0
- package/integrations/repositories/integration-repository-interface.js +115 -0
- package/integrations/repositories/integration-repository-mongo.js +271 -0
- package/integrations/repositories/integration-repository-postgres.js +319 -0
- package/integrations/tests/doubles/dummy-integration-class.js +90 -0
- package/integrations/tests/doubles/test-integration-repository.js +99 -0
- package/integrations/tests/use-cases/create-integration.test.js +131 -0
- package/integrations/tests/use-cases/delete-integration-for-user.test.js +150 -0
- package/integrations/tests/use-cases/find-integration-context-by-external-entity-id.test.js +92 -0
- package/integrations/tests/use-cases/get-integration-for-user.test.js +150 -0
- package/integrations/tests/use-cases/get-integration-instance.test.js +176 -0
- package/integrations/tests/use-cases/get-integrations-for-user.test.js +176 -0
- package/integrations/tests/use-cases/get-possible-integrations.test.js +188 -0
- package/integrations/tests/use-cases/update-integration-messages.test.js +142 -0
- package/integrations/tests/use-cases/update-integration-status.test.js +103 -0
- package/integrations/tests/use-cases/update-integration.test.js +141 -0
- package/integrations/use-cases/create-integration.js +83 -0
- package/integrations/use-cases/delete-integration-for-user.js +73 -0
- package/integrations/use-cases/find-integration-context-by-external-entity-id.js +72 -0
- package/integrations/use-cases/get-integration-for-user.js +78 -0
- package/integrations/use-cases/get-integration-instance-by-definition.js +67 -0
- package/integrations/use-cases/get-integration-instance.js +83 -0
- package/integrations/use-cases/get-integrations-for-user.js +87 -0
- package/integrations/use-cases/get-possible-integrations.js +27 -0
- package/integrations/use-cases/index.js +11 -0
- package/integrations/use-cases/load-integration-context-full.test.js +329 -0
- package/integrations/use-cases/load-integration-context.js +71 -0
- package/integrations/use-cases/load-integration-context.test.js +114 -0
- package/integrations/use-cases/update-integration-messages.js +44 -0
- package/integrations/use-cases/update-integration-status.js +32 -0
- package/integrations/use-cases/update-integration.js +93 -0
- package/integrations/utils/map-integration-dto.js +36 -0
- package/jest-global-setup-noop.js +3 -0
- package/jest-global-teardown-noop.js +3 -0
- package/{module-plugin → modules}/entity.js +1 -0
- package/{module-plugin → modules}/index.js +0 -8
- package/modules/module-factory.js +56 -0
- package/modules/module-hydration.test.js +205 -0
- package/modules/module.js +221 -0
- package/modules/repositories/module-repository-factory.js +33 -0
- package/modules/repositories/module-repository-interface.js +129 -0
- package/modules/repositories/module-repository-mongo.js +386 -0
- package/modules/repositories/module-repository-postgres.js +437 -0
- package/modules/repositories/module-repository.js +327 -0
- package/{module-plugin → modules}/test/mock-api/api.js +8 -3
- package/{module-plugin → modules}/test/mock-api/definition.js +12 -8
- package/modules/tests/doubles/test-module-factory.js +16 -0
- package/modules/tests/doubles/test-module-repository.js +39 -0
- package/modules/use-cases/get-entities-for-user.js +32 -0
- package/modules/use-cases/get-entity-options-by-id.js +59 -0
- package/modules/use-cases/get-entity-options-by-type.js +34 -0
- package/modules/use-cases/get-module-instance-from-type.js +31 -0
- package/modules/use-cases/get-module.js +56 -0
- package/modules/use-cases/process-authorization-callback.js +122 -0
- package/modules/use-cases/refresh-entity-options.js +59 -0
- package/modules/use-cases/test-module-auth.js +55 -0
- package/modules/utils/map-module-dto.js +18 -0
- package/package.json +14 -6
- package/prisma-mongodb/schema.prisma +318 -0
- package/prisma-postgresql/migrations/20250930193005_init/migration.sql +315 -0
- package/prisma-postgresql/migrations/20251006135218_init/migration.sql +9 -0
- package/prisma-postgresql/migrations/20251010000000_remove_unused_entity_reference_map/migration.sql +3 -0
- package/prisma-postgresql/migrations/migration_lock.toml +3 -0
- package/prisma-postgresql/schema.prisma +300 -0
- package/syncs/manager.js +468 -443
- package/syncs/repositories/sync-repository-factory.js +38 -0
- package/syncs/repositories/sync-repository-interface.js +109 -0
- package/syncs/repositories/sync-repository-mongo.js +239 -0
- package/syncs/repositories/sync-repository-postgres.js +319 -0
- package/syncs/sync.js +0 -1
- package/token/repositories/token-repository-factory.js +33 -0
- package/token/repositories/token-repository-interface.js +131 -0
- package/token/repositories/token-repository-mongo.js +212 -0
- package/token/repositories/token-repository-postgres.js +257 -0
- package/token/repositories/token-repository.js +219 -0
- package/types/integrations/index.d.ts +2 -6
- package/types/module-plugin/index.d.ts +5 -57
- package/types/syncs/index.d.ts +0 -2
- package/user/repositories/user-repository-factory.js +46 -0
- package/user/repositories/user-repository-interface.js +198 -0
- package/user/repositories/user-repository-mongo.js +250 -0
- package/user/repositories/user-repository-postgres.js +311 -0
- package/user/tests/doubles/test-user-repository.js +72 -0
- package/user/tests/use-cases/create-individual-user.test.js +24 -0
- package/user/tests/use-cases/create-organization-user.test.js +28 -0
- package/user/tests/use-cases/create-token-for-user-id.test.js +19 -0
- package/user/tests/use-cases/get-user-from-bearer-token.test.js +64 -0
- package/user/tests/use-cases/login-user.test.js +140 -0
- package/user/use-cases/create-individual-user.js +61 -0
- package/user/use-cases/create-organization-user.js +47 -0
- package/user/use-cases/create-token-for-user-id.js +30 -0
- package/user/use-cases/get-user-from-bearer-token.js +77 -0
- package/user/use-cases/login-user.js +122 -0
- package/user/user.js +77 -0
- package/websocket/repositories/websocket-connection-repository-factory.js +37 -0
- package/websocket/repositories/websocket-connection-repository-interface.js +106 -0
- package/websocket/repositories/websocket-connection-repository-mongo.js +155 -0
- package/websocket/repositories/websocket-connection-repository-postgres.js +195 -0
- package/websocket/repositories/websocket-connection-repository.js +160 -0
- package/database/models/State.js +0 -9
- package/database/models/Token.js +0 -70
- package/database/mongo.js +0 -171
- package/encrypt/Cryptor.test.js +0 -32
- package/encrypt/encrypt.js +0 -104
- package/encrypt/encrypt.test.js +0 -1069
- package/handlers/routers/middleware/loadUser.js +0 -15
- package/handlers/routers/middleware/requireLoggedInUser.js +0 -12
- package/integrations/create-frigg-backend.js +0 -31
- package/integrations/integration-factory.js +0 -251
- package/integrations/integration-mapping.js +0 -43
- package/integrations/integration-model.js +0 -46
- package/integrations/integration-user.js +0 -144
- package/integrations/test/integration-base.test.js +0 -144
- package/module-plugin/auther.js +0 -393
- package/module-plugin/credential.js +0 -22
- package/module-plugin/entity-manager.js +0 -70
- package/module-plugin/manager.js +0 -169
- package/module-plugin/module-factory.js +0 -61
- package/module-plugin/test/auther.test.js +0 -97
- /package/{module-plugin → modules}/ModuleConstants.js +0 -0
- /package/{module-plugin → modules}/requester/api-key.js +0 -0
- /package/{module-plugin → modules}/requester/basic.js +0 -0
- /package/{module-plugin → modules}/requester/oauth-2.js +0 -0
- /package/{module-plugin → modules}/requester/requester.js +0 -0
- /package/{module-plugin → modules}/requester/requester.test.js +0 -0
- /package/{module-plugin → modules}/test/mock-api/mocks/hubspot.js +0 -0
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,693 @@
|
|
|
1
|
+
# CLAUDE.md - Frigg Framework Core Package
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code when working with the Frigg Framework's core package (`@friggframework/core`).
|
|
4
|
+
|
|
5
|
+
## Critical Context (Read First)
|
|
6
|
+
|
|
7
|
+
- **Package Purpose**: Core framework functionality for building enterprise serverless integrations
|
|
8
|
+
- **Main Architecture**: Hexagonal/DDD architecture with clear separation of adapters, use cases, and repositories
|
|
9
|
+
- **Key Technologies**: Node.js, Express, AWS Lambda, MongoDB/PostgreSQL (Prisma), AWS KMS encryption
|
|
10
|
+
- **Core Value**: Provides building blocks for integration developers - they extend IntegrationBase and use framework services
|
|
11
|
+
- **Security Model**: Field-level encryption, OAuth2 flows, signature validation, VPC deployment
|
|
12
|
+
- **DO NOT**: Bypass architectural layers, skip encryption for sensitive data, expose internal errors to users
|
|
13
|
+
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
16
|
+
1. [Package Overview](#package-overview)
|
|
17
|
+
2. [Architecture Principles](#architecture-principles)
|
|
18
|
+
3. [Essential Commands](#essential-commands)
|
|
19
|
+
4. [Directory Structure](#directory-structure)
|
|
20
|
+
5. [Core Components](#core-components)
|
|
21
|
+
6. [Development Workflow](#development-workflow)
|
|
22
|
+
7. [Testing Strategy](#testing-strategy)
|
|
23
|
+
8. [Anti-Patterns](#anti-patterns)
|
|
24
|
+
|
|
25
|
+
## Package Overview
|
|
26
|
+
|
|
27
|
+
`@friggframework/core` is the foundational package of the Frigg Framework, providing:
|
|
28
|
+
|
|
29
|
+
- **IntegrationBase**: Base class all integrations extend
|
|
30
|
+
- **Database Layer**: Multi-database support (MongoDB, PostgreSQL) with Prisma ORM
|
|
31
|
+
- **Encryption**: Transparent field-level encryption with AWS KMS or AES
|
|
32
|
+
- **User Management**: Individual and organizational user support
|
|
33
|
+
- **Module System**: API module loading and credential management
|
|
34
|
+
- **Lambda Runtime**: Handler factory, worker base class, timeout management
|
|
35
|
+
- **Error Handling**: Standardized error types with proper HTTP status codes
|
|
36
|
+
- **Event System**: Integration lifecycle events and user actions
|
|
37
|
+
|
|
38
|
+
## Architecture Principles
|
|
39
|
+
|
|
40
|
+
### Hexagonal Architecture (Ports and Adapters)
|
|
41
|
+
|
|
42
|
+
The core package strictly follows hexagonal architecture:
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
┌─────────────────────────────────────────────────────────┐
|
|
46
|
+
│ Adapters (Inbound) │
|
|
47
|
+
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
|
48
|
+
│ │ HTTP/REST │ │ Lambda │ │ SQS Workers │ │
|
|
49
|
+
│ │ (handlers/) │ │ (core/) │ │ (queues/) │ │
|
|
50
|
+
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
|
|
51
|
+
└─────────┼─────────────────┼─────────────────┼───────────┘
|
|
52
|
+
│ │ │
|
|
53
|
+
┌─────────▼─────────────────▼─────────────────▼───────────┐
|
|
54
|
+
│ Application Layer (Use Cases) │
|
|
55
|
+
│ ┌────────────────────────────────────────────────┐ │
|
|
56
|
+
│ │ CreateIntegration, UpdateIntegration, │ │
|
|
57
|
+
│ │ LoginUser, ProcessAttachmentJob, etc. │ │
|
|
58
|
+
│ └────────────────────┬───────────────────────────┘ │
|
|
59
|
+
└───────────────────────┼─────────────────────────────────┘
|
|
60
|
+
│ calls
|
|
61
|
+
┌───────────────────────▼─────────────────────────────────┐
|
|
62
|
+
│ Domain Layer (Entities) │
|
|
63
|
+
│ ┌────────────────────────────────────────────────┐ │
|
|
64
|
+
│ │ IntegrationBase, User, Credential, Entity │ │
|
|
65
|
+
│ └────────────────────┬───────────────────────────┘ │
|
|
66
|
+
└───────────────────────┼─────────────────────────────────┘
|
|
67
|
+
│ persisted by
|
|
68
|
+
┌───────────────────────▼─────────────────────────────────┐
|
|
69
|
+
│ Infrastructure Layer (Repositories) │
|
|
70
|
+
│ ┌────────────────────────────────────────────────┐ │
|
|
71
|
+
│ │ IntegrationRepository, UserRepository, │ │
|
|
72
|
+
│ │ CredentialRepository, ModuleRepository │ │
|
|
73
|
+
│ └────────────────────┬───────────────────────────┘ │
|
|
74
|
+
└───────────────────────┼─────────────────────────────────┘
|
|
75
|
+
│ accesses
|
|
76
|
+
┌───────────────────────▼─────────────────────────────────┐
|
|
77
|
+
│ External Systems │
|
|
78
|
+
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
|
79
|
+
│ │ MongoDB │ │ Postgres │ │ AWS KMS │ │
|
|
80
|
+
│ └──────────┘ └──────────┘ └──────────┘ │
|
|
81
|
+
└─────────────────────────────────────────────────────────┘
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Golden Rules
|
|
85
|
+
|
|
86
|
+
1. **Handlers NEVER call repositories directly** - Always go through use cases
|
|
87
|
+
2. **Use cases contain business logic** - Not repositories or handlers
|
|
88
|
+
3. **Repositories are pure data access** - No business logic or orchestration
|
|
89
|
+
4. **Domain entities have behavior** - Not just data bags
|
|
90
|
+
5. **Encryption is transparent** - Application code works with plain data
|
|
91
|
+
|
|
92
|
+
## Essential Commands
|
|
93
|
+
|
|
94
|
+
### Development
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# Install dependencies
|
|
98
|
+
npm install
|
|
99
|
+
|
|
100
|
+
# Generate Prisma clients (both MongoDB and PostgreSQL)
|
|
101
|
+
npm run prisma:generate
|
|
102
|
+
|
|
103
|
+
# Format and lint code
|
|
104
|
+
npm run lint:fix
|
|
105
|
+
|
|
106
|
+
# Run tests
|
|
107
|
+
npm test
|
|
108
|
+
|
|
109
|
+
# Run specific test file
|
|
110
|
+
npm test -- path/to/test.test.js
|
|
111
|
+
|
|
112
|
+
# Run tests for specific pattern
|
|
113
|
+
npm test -- --testPathPattern="encryption"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Prisma Database Operations
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
# Generate clients
|
|
120
|
+
npm run prisma:generate:mongo # MongoDB only
|
|
121
|
+
npm run prisma:generate:postgres # PostgreSQL only
|
|
122
|
+
npm run prisma:generate # Both databases
|
|
123
|
+
|
|
124
|
+
# Database migrations
|
|
125
|
+
npm run prisma:push:mongo # Push MongoDB schema
|
|
126
|
+
npm run prisma:migrate:postgres # Run PostgreSQL migrations
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Testing
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# All tests
|
|
133
|
+
npm test
|
|
134
|
+
|
|
135
|
+
# Specific test categories
|
|
136
|
+
npm test -- database/encryption/ # Encryption tests
|
|
137
|
+
npm test -- integrations/ # Integration tests
|
|
138
|
+
npm test -- handlers/ # Handler tests
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Directory Structure
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
packages/core/
|
|
145
|
+
├── application/ # Application-level commands and initialization
|
|
146
|
+
│ └── commands/ # Command pattern implementations
|
|
147
|
+
├── assertions/ # Validation and assertion utilities
|
|
148
|
+
├── associations/ # Entity association management
|
|
149
|
+
├── core/ # Runtime system (Lambda, Workers, Delegates)
|
|
150
|
+
│ └── CLAUDE.md # Detailed core runtime documentation
|
|
151
|
+
├── credential/ # Credential management
|
|
152
|
+
│ ├── repositories/ # Credential data access
|
|
153
|
+
│ └── use-cases/ # Credential business logic
|
|
154
|
+
├── database/ # Database layer and encryption
|
|
155
|
+
│ ├── encryption/ # Field-level encryption system
|
|
156
|
+
│ │ └── README.md # Comprehensive encryption documentation
|
|
157
|
+
│ ├── models/ # Mongoose models
|
|
158
|
+
│ ├── repositories/ # Database repositories
|
|
159
|
+
│ └── use-cases/ # Database health and management
|
|
160
|
+
├── encrypt/ # Cryptor adapter for AWS KMS and AES
|
|
161
|
+
├── errors/ # Error type definitions
|
|
162
|
+
├── handlers/ # HTTP/Lambda request handlers
|
|
163
|
+
│ └── routers/ # Express routers
|
|
164
|
+
├── integrations/ # Integration domain and lifecycle
|
|
165
|
+
│ ├── integration-base.js # Base class for all integrations
|
|
166
|
+
│ ├── repositories/ # Integration data access
|
|
167
|
+
│ ├── tests/ # Integration tests
|
|
168
|
+
│ └── use-cases/ # Integration business logic
|
|
169
|
+
├── lambda/ # AWS Lambda utilities
|
|
170
|
+
├── logs/ # Logging system
|
|
171
|
+
├── modules/ # API module system
|
|
172
|
+
│ ├── requester/ # HTTP client implementations
|
|
173
|
+
│ └── repositories/ # Module data access
|
|
174
|
+
├── prisma-mongodb/ # MongoDB Prisma schema
|
|
175
|
+
├── prisma-postgresql/ # PostgreSQL Prisma schema
|
|
176
|
+
├── queues/ # SQS job queue management
|
|
177
|
+
├── syncs/ # Data synchronization
|
|
178
|
+
├── token/ # Token management
|
|
179
|
+
│ └── repositories/ # Token data access
|
|
180
|
+
├── types/ # TypeScript type definitions
|
|
181
|
+
├── user/ # User management
|
|
182
|
+
│ ├── repositories/ # User data access
|
|
183
|
+
│ └── use-cases/ # User business logic
|
|
184
|
+
├── utils/ # Utility functions
|
|
185
|
+
├── websocket/ # WebSocket connection management
|
|
186
|
+
│ └── repositories/ # WebSocket data access
|
|
187
|
+
├── index.js # Main export file
|
|
188
|
+
├── package.json # Package configuration
|
|
189
|
+
└── README.md # Package documentation
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Core Components
|
|
193
|
+
|
|
194
|
+
### 1. Integration System (`/integrations`)
|
|
195
|
+
|
|
196
|
+
**Purpose**: Foundation for building integrations between external systems.
|
|
197
|
+
|
|
198
|
+
**Key Files**:
|
|
199
|
+
- `integration-base.js` - Base class all integrations extend
|
|
200
|
+
- `integration.js` - Integration domain aggregate using Proxy pattern
|
|
201
|
+
- `options.js` - Integration configuration and options
|
|
202
|
+
|
|
203
|
+
**Use Cases**:
|
|
204
|
+
- `create-integration.js` - Create new integration instance
|
|
205
|
+
- `update-integration.js` - Update integration configuration
|
|
206
|
+
- `delete-integration-for-user.js` - Remove integration
|
|
207
|
+
- `get-integration-instance.js` - Load integration with modules
|
|
208
|
+
- `load-integration-context.js` - Full integration context loading
|
|
209
|
+
|
|
210
|
+
**Repositories**:
|
|
211
|
+
- `integration-repository-factory.js` - Creates database-specific repositories
|
|
212
|
+
- `integration-repository-mongo.js` - MongoDB implementation
|
|
213
|
+
- `integration-repository-postgres.js` - PostgreSQL implementation
|
|
214
|
+
- `integration-mapping-repository-*.js` - Mapping data persistence
|
|
215
|
+
|
|
216
|
+
**Integration developers extend IntegrationBase**:
|
|
217
|
+
|
|
218
|
+
```javascript
|
|
219
|
+
const { IntegrationBase } = require('@friggframework/core');
|
|
220
|
+
|
|
221
|
+
class MyIntegration extends IntegrationBase {
|
|
222
|
+
static Definition = {
|
|
223
|
+
name: 'my-integration',
|
|
224
|
+
version: '1.0.0',
|
|
225
|
+
modules: {
|
|
226
|
+
serviceA: 'service-a',
|
|
227
|
+
serviceB: 'service-b'
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
async onCreate({ integrationId }) {
|
|
232
|
+
// Setup logic
|
|
233
|
+
await super.onCreate({ integrationId });
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### 2. Database Layer (`/database`)
|
|
239
|
+
|
|
240
|
+
**Purpose**: Multi-database support with transparent encryption.
|
|
241
|
+
|
|
242
|
+
**Key Components**:
|
|
243
|
+
- `prisma.js` - Prisma client initialization with encryption extension
|
|
244
|
+
- `mongo.js` - Mongoose connection management (legacy)
|
|
245
|
+
- `models/` - Mongoose model definitions
|
|
246
|
+
|
|
247
|
+
**Encryption System** (`/database/encryption`):
|
|
248
|
+
- **Transparent encryption**: Application code never sees encrypted data
|
|
249
|
+
- **Database-agnostic**: Works with MongoDB and PostgreSQL
|
|
250
|
+
- **AWS KMS or AES**: Production KMS, development AES
|
|
251
|
+
- **Configurable**: Via environment variables and app definition
|
|
252
|
+
|
|
253
|
+
**See**: `database/encryption/README.md` for comprehensive documentation
|
|
254
|
+
|
|
255
|
+
**Repositories**:
|
|
256
|
+
- `health-check-repository.js` - Database health monitoring
|
|
257
|
+
- `token-repository.js` - Authentication tokens
|
|
258
|
+
- `websocket-connection-repository.js` - WebSocket connections
|
|
259
|
+
|
|
260
|
+
**Use Cases**:
|
|
261
|
+
- `check-database-health-use-case.js` - Database health checks
|
|
262
|
+
- `test-encryption-use-case.js` - Encryption verification
|
|
263
|
+
|
|
264
|
+
### 3. User Management (`/user`)
|
|
265
|
+
|
|
266
|
+
**Purpose**: Individual and organizational user authentication.
|
|
267
|
+
|
|
268
|
+
**User Types**:
|
|
269
|
+
- **Individual Users**: Personal accounts with email/password
|
|
270
|
+
- **Organization Users**: Business accounts with organization-level access
|
|
271
|
+
- **Hybrid**: Support both simultaneously
|
|
272
|
+
|
|
273
|
+
**Authentication Methods**:
|
|
274
|
+
- Password-based (bcrypt hashed)
|
|
275
|
+
- Token-based (Bearer tokens)
|
|
276
|
+
- App-based (external app user IDs)
|
|
277
|
+
|
|
278
|
+
**Use Cases**:
|
|
279
|
+
- `login-user.js` - User authentication
|
|
280
|
+
- `create-individual-user.js` - Create personal account
|
|
281
|
+
- `create-organization-user.js` - Create business account
|
|
282
|
+
- `get-user-from-bearer-token.js` - Token authentication
|
|
283
|
+
|
|
284
|
+
**Repositories**:
|
|
285
|
+
- `user-repository-factory.js` - Creates database-specific repositories
|
|
286
|
+
- `user-repository-mongo.js` - MongoDB implementation
|
|
287
|
+
- `user-repository-postgres.js` - PostgreSQL implementation
|
|
288
|
+
|
|
289
|
+
**Configuration** (in app definition):
|
|
290
|
+
|
|
291
|
+
```javascript
|
|
292
|
+
{
|
|
293
|
+
user: {
|
|
294
|
+
usePassword: true, // Enable password auth
|
|
295
|
+
primary: 'individual', // Primary user type
|
|
296
|
+
individualUserRequired: true, // Require individual user
|
|
297
|
+
organizationUserRequired: false // Optional org user
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### 4. Module System (`/modules`)
|
|
303
|
+
|
|
304
|
+
**Purpose**: API module loading, credential management, and HTTP clients.
|
|
305
|
+
|
|
306
|
+
**Key Classes**:
|
|
307
|
+
- `Credential` - API credentials domain entity
|
|
308
|
+
- `Entity` - External service entity (account, workspace, etc.)
|
|
309
|
+
- `Requester` - Base HTTP client class
|
|
310
|
+
- `OAuth2Requester` - OAuth 2.0 flow implementation
|
|
311
|
+
- `ApiKeyRequester` - API key authentication
|
|
312
|
+
- `BasicAuthRequester` - Basic authentication
|
|
313
|
+
|
|
314
|
+
**Module Factory**:
|
|
315
|
+
- `ModuleFactory` - Creates and configures API module instances
|
|
316
|
+
- Handles credential injection
|
|
317
|
+
- Manages module lifecycle
|
|
318
|
+
|
|
319
|
+
**Repositories**:
|
|
320
|
+
- `module-repository.js` - Module data access
|
|
321
|
+
- `credential-repository.js` - Credential persistence (encrypted)
|
|
322
|
+
|
|
323
|
+
### 5. Core Runtime System (`/core`)
|
|
324
|
+
|
|
325
|
+
**Purpose**: Lambda-optimized runtime with handlers, workers, and delegates.
|
|
326
|
+
|
|
327
|
+
**See**: `core/CLAUDE.md` for comprehensive documentation
|
|
328
|
+
|
|
329
|
+
**Key Components**:
|
|
330
|
+
- `create-handler.js` - Lambda handler factory
|
|
331
|
+
- `Worker.js` - SQS job processing base class
|
|
332
|
+
- `Delegate.js` - Observer/delegation pattern
|
|
333
|
+
- `load-installed-modules.js` - Dynamic module loading
|
|
334
|
+
|
|
335
|
+
**Handler Pattern**:
|
|
336
|
+
|
|
337
|
+
```javascript
|
|
338
|
+
const { createHandler } = require('@friggframework/core');
|
|
339
|
+
|
|
340
|
+
const handler = createHandler({
|
|
341
|
+
eventName: 'MyIntegration',
|
|
342
|
+
isUserFacingResponse: true, // Sanitize errors
|
|
343
|
+
shouldUseDatabase: true, // Connect to DB
|
|
344
|
+
method: async (event, context) => {
|
|
345
|
+
// Your logic here
|
|
346
|
+
return { statusCode: 200, body: 'Success' };
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
**Worker Pattern**:
|
|
352
|
+
|
|
353
|
+
```javascript
|
|
354
|
+
const { Worker } = require('@friggframework/core');
|
|
355
|
+
|
|
356
|
+
class MyWorker extends Worker {
|
|
357
|
+
_validateParams(params) {
|
|
358
|
+
this._verifyParamExists(params, 'requiredField');
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
async _run(params, context) {
|
|
362
|
+
// Process SQS message
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### 6. Encryption System (`/encrypt`)
|
|
368
|
+
|
|
369
|
+
**Purpose**: Cryptor adapter for AWS KMS and AES encryption.
|
|
370
|
+
|
|
371
|
+
**Key Class**: `Cryptor.js`
|
|
372
|
+
- Envelope encryption pattern
|
|
373
|
+
- AWS KMS integration
|
|
374
|
+
- AES-256-GCM fallback
|
|
375
|
+
- Key rotation support
|
|
376
|
+
|
|
377
|
+
**Usage**:
|
|
378
|
+
|
|
379
|
+
```javascript
|
|
380
|
+
const { Cryptor } = require('@friggframework/core');
|
|
381
|
+
|
|
382
|
+
const cryptor = new Cryptor({
|
|
383
|
+
shouldUseAws: process.env.KMS_KEY_ARN ? true : false
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
const encrypted = await cryptor.encrypt('sensitive-data');
|
|
387
|
+
const decrypted = await cryptor.decrypt(encrypted);
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### 7. Handlers & Routers (`/handlers`)
|
|
391
|
+
|
|
392
|
+
**Purpose**: HTTP/Lambda request handling and routing.
|
|
393
|
+
|
|
394
|
+
**Key Routers**:
|
|
395
|
+
- `integration-router.js` - Integration CRUD operations
|
|
396
|
+
- `auth.js` - Authentication endpoints
|
|
397
|
+
- `health.js` - Health check endpoints with encryption verification
|
|
398
|
+
|
|
399
|
+
**Handler Types**:
|
|
400
|
+
- **User-facing**: Sanitize errors, friendly responses
|
|
401
|
+
- **Server-to-server**: Full error details for debugging
|
|
402
|
+
- **Background workers**: SQS message processing
|
|
403
|
+
|
|
404
|
+
**Event Dispatcher**:
|
|
405
|
+
- `integration-event-dispatcher.js` - Routes events to integration handlers
|
|
406
|
+
- Supports lifecycle events and user actions
|
|
407
|
+
|
|
408
|
+
### 8. Error Handling (`/errors`)
|
|
409
|
+
|
|
410
|
+
**Purpose**: Standardized error types with proper HTTP semantics.
|
|
411
|
+
|
|
412
|
+
**Error Types**:
|
|
413
|
+
- `BaseError` - Base error class
|
|
414
|
+
- `FetchError` - HTTP request failures
|
|
415
|
+
- `HaltError` - Stop processing without retry
|
|
416
|
+
- `RequiredPropertyError` - Missing required parameters
|
|
417
|
+
- `ParameterTypeError` - Invalid parameter type
|
|
418
|
+
|
|
419
|
+
**Usage**:
|
|
420
|
+
|
|
421
|
+
```javascript
|
|
422
|
+
const { RequiredPropertyError } = require('@friggframework/core');
|
|
423
|
+
|
|
424
|
+
if (!userId) {
|
|
425
|
+
throw new RequiredPropertyError('userId is required');
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### 9. Logging System (`/logs`)
|
|
430
|
+
|
|
431
|
+
**Purpose**: Structured logging with debug capabilities.
|
|
432
|
+
|
|
433
|
+
**Functions**:
|
|
434
|
+
- `debug(message, data)` - Debug logging
|
|
435
|
+
- `initDebugLog(eventName, event)` - Initialize debug context
|
|
436
|
+
- `flushDebugLog(error)` - Flush logs on error
|
|
437
|
+
|
|
438
|
+
**Usage**:
|
|
439
|
+
|
|
440
|
+
```javascript
|
|
441
|
+
const { debug, initDebugLog, flushDebugLog } = require('@friggframework/core');
|
|
442
|
+
|
|
443
|
+
initDebugLog('MyIntegration', event);
|
|
444
|
+
debug('Processing request', { userId, action });
|
|
445
|
+
// ... your code ...
|
|
446
|
+
flushDebugLog(); // On error
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### 10. Lambda Utilities (`/lambda`)
|
|
450
|
+
|
|
451
|
+
**Purpose**: AWS Lambda-specific utilities.
|
|
452
|
+
|
|
453
|
+
**Key Classes**:
|
|
454
|
+
- `TimeoutCatcher` - Detect approaching Lambda timeout
|
|
455
|
+
- Graceful shutdown handling
|
|
456
|
+
|
|
457
|
+
**Usage**:
|
|
458
|
+
|
|
459
|
+
```javascript
|
|
460
|
+
const { TimeoutCatcher } = require('@friggframework/core');
|
|
461
|
+
|
|
462
|
+
exports.handler = async (event, context) => {
|
|
463
|
+
const timeoutCatcher = new TimeoutCatcher(context);
|
|
464
|
+
|
|
465
|
+
if (timeoutCatcher.isNearTimeout()) {
|
|
466
|
+
// Save state and exit gracefully
|
|
467
|
+
}
|
|
468
|
+
};
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
## Development Workflow
|
|
472
|
+
|
|
473
|
+
### Adding a New Use Case
|
|
474
|
+
|
|
475
|
+
1. **Create use case file** in appropriate `use-cases/` directory:
|
|
476
|
+
|
|
477
|
+
```javascript
|
|
478
|
+
// integrations/use-cases/my-new-use-case.js
|
|
479
|
+
class MyNewUseCase {
|
|
480
|
+
constructor({ integrationRepository, userRepository }) {
|
|
481
|
+
this.integrationRepo = integrationRepository;
|
|
482
|
+
this.userRepo = userRepository;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
async execute(userId, integrationId) {
|
|
486
|
+
// Business logic here
|
|
487
|
+
const user = await this.userRepo.findById(userId);
|
|
488
|
+
const integration = await this.integrationRepo.findById(integrationId);
|
|
489
|
+
|
|
490
|
+
// Validate, orchestrate, coordinate
|
|
491
|
+
// Return result
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
module.exports = { MyNewUseCase };
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
2. **Add tests** in corresponding `tests/` directory
|
|
499
|
+
3. **Export** from parent index.js if needed
|
|
500
|
+
4. **Use in handler** - handlers call use cases, not repositories
|
|
501
|
+
|
|
502
|
+
### Adding Encrypted Fields
|
|
503
|
+
|
|
504
|
+
**For custom models** (integration developers):
|
|
505
|
+
|
|
506
|
+
In `backend/index.js`:
|
|
507
|
+
|
|
508
|
+
```javascript
|
|
509
|
+
const appDefinition = {
|
|
510
|
+
encryption: {
|
|
511
|
+
schema: {
|
|
512
|
+
MyCustomModel: {
|
|
513
|
+
fields: ['secretData', 'data.apiKey']
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
};
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
**For core models** (framework developers):
|
|
521
|
+
|
|
522
|
+
Edit `database/encryption/encryption-schema-registry.js`:
|
|
523
|
+
|
|
524
|
+
```javascript
|
|
525
|
+
const ENCRYPTION_SCHEMA = {
|
|
526
|
+
MyModel: {
|
|
527
|
+
fields: ['sensitiveField']
|
|
528
|
+
}
|
|
529
|
+
};
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
### Database Migrations
|
|
533
|
+
|
|
534
|
+
**MongoDB** (Prisma push):
|
|
535
|
+
|
|
536
|
+
```bash
|
|
537
|
+
npm run prisma:push:mongo
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
**PostgreSQL** (Prisma migrate):
|
|
541
|
+
|
|
542
|
+
```bash
|
|
543
|
+
npm run prisma:migrate:postgres
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
### Integration Development
|
|
547
|
+
|
|
548
|
+
1. **Extend IntegrationBase** in your app
|
|
549
|
+
2. **Define static Definition** with name, version, modules
|
|
550
|
+
3. **Implement lifecycle methods**: `onCreate`, `onUpdate`, `onDelete`
|
|
551
|
+
4. **Add event handlers** for webhooks and user actions
|
|
552
|
+
5. **Use framework services**: repositories, encryption, logging
|
|
553
|
+
|
|
554
|
+
## Testing Strategy
|
|
555
|
+
|
|
556
|
+
### Test Categories
|
|
557
|
+
|
|
558
|
+
1. **Unit Tests**: Use cases with mocked repositories
|
|
559
|
+
2. **Integration Tests**: Full flow with real dependencies
|
|
560
|
+
3. **Repository Tests**: Database operations
|
|
561
|
+
4. **Handler Tests**: HTTP/Lambda response testing
|
|
562
|
+
|
|
563
|
+
### Test Structure
|
|
564
|
+
|
|
565
|
+
```javascript
|
|
566
|
+
describe('MyUseCase', () => {
|
|
567
|
+
let useCase;
|
|
568
|
+
let mockRepository;
|
|
569
|
+
|
|
570
|
+
beforeEach(() => {
|
|
571
|
+
mockRepository = {
|
|
572
|
+
findById: jest.fn(),
|
|
573
|
+
save: jest.fn()
|
|
574
|
+
};
|
|
575
|
+
useCase = new MyUseCase({ repository: mockRepository });
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
it('executes successfully', async () => {
|
|
579
|
+
mockRepository.findById.mockResolvedValue({ id: '123' });
|
|
580
|
+
|
|
581
|
+
const result = await useCase.execute('123');
|
|
582
|
+
|
|
583
|
+
expect(result).toBeDefined();
|
|
584
|
+
expect(mockRepository.findById).toHaveBeenCalledWith('123');
|
|
585
|
+
});
|
|
586
|
+
});
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
### Running Tests
|
|
590
|
+
|
|
591
|
+
```bash
|
|
592
|
+
# All tests
|
|
593
|
+
npm test
|
|
594
|
+
|
|
595
|
+
# Specific file
|
|
596
|
+
npm test -- path/to/test.test.js
|
|
597
|
+
|
|
598
|
+
# Pattern matching
|
|
599
|
+
npm test -- --testPathPattern="encryption"
|
|
600
|
+
|
|
601
|
+
# With coverage
|
|
602
|
+
npm test -- --coverage
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
### Test Doubles
|
|
606
|
+
|
|
607
|
+
Use test doubles from `@friggframework/test` package for consistent mocking.
|
|
608
|
+
|
|
609
|
+
## Anti-Patterns
|
|
610
|
+
|
|
611
|
+
### Architecture Anti-Patterns
|
|
612
|
+
|
|
613
|
+
❌ **Don't call repositories from handlers** - Always use use cases
|
|
614
|
+
❌ **Don't put business logic in repositories** - Repositories are pure data access
|
|
615
|
+
❌ **Don't put HTTP concerns in use cases** - Use cases are protocol-agnostic
|
|
616
|
+
❌ **Don't bypass encryption** - Sensitive data must be encrypted
|
|
617
|
+
❌ **Don't expose internal errors to users** - Use `isUserFacingResponse: true`
|
|
618
|
+
❌ **Don't skip connection pooling** - Set `callbackWaitsForEmptyEventLoop = false`
|
|
619
|
+
|
|
620
|
+
### Development Anti-Patterns
|
|
621
|
+
|
|
622
|
+
❌ **Don't modify node_modules** - Extend through proper patterns
|
|
623
|
+
❌ **Don't hardcode credentials** - Use environment variables
|
|
624
|
+
❌ **Don't skip tests** - Maintain test coverage
|
|
625
|
+
❌ **Don't commit secrets** - Use .gitignore and AWS Secrets Manager
|
|
626
|
+
❌ **Don't ignore linting errors** - Run `npm run lint:fix`
|
|
627
|
+
|
|
628
|
+
### Integration Development Anti-Patterns
|
|
629
|
+
|
|
630
|
+
❌ **Don't bypass IntegrationBase** - Always extend the base class
|
|
631
|
+
❌ **Don't ignore lifecycle methods** - Implement onCreate, onUpdate, onDelete
|
|
632
|
+
❌ **Don't skip signature validation** - Validate all webhooks
|
|
633
|
+
❌ **Don't sync operations in handlers** - Use background workers for long tasks
|
|
634
|
+
❌ **Don't ignore errors** - Proper error handling and logging
|
|
635
|
+
|
|
636
|
+
## Environment Variables
|
|
637
|
+
|
|
638
|
+
### Required
|
|
639
|
+
|
|
640
|
+
- `AWS_REGION` - AWS region for services
|
|
641
|
+
- `DATABASE_URL` - Database connection string (auto-set)
|
|
642
|
+
- `DB_TYPE` - Database type: 'mongodb' or 'postgresql'
|
|
643
|
+
|
|
644
|
+
### Encryption
|
|
645
|
+
|
|
646
|
+
- `KMS_KEY_ARN` - AWS KMS key ARN (production)
|
|
647
|
+
- `AES_KEY_ID` - AES key ID (development)
|
|
648
|
+
- `AES_KEY` - AES encryption key (development)
|
|
649
|
+
- `STAGE` - Environment stage (dev, test, local bypass encryption)
|
|
650
|
+
|
|
651
|
+
### Optional
|
|
652
|
+
|
|
653
|
+
- `SECRET_ARN` - AWS Secrets Manager ARN for auto-injection
|
|
654
|
+
- `DEBUG` - Debug logging pattern
|
|
655
|
+
- `LOG_LEVEL` - Logging level (debug, info, warn, error)
|
|
656
|
+
|
|
657
|
+
## Version Information
|
|
658
|
+
|
|
659
|
+
- **Current Version**: 2.0.0-next.0 (pre-release)
|
|
660
|
+
- **Node.js**: >=18 required
|
|
661
|
+
- **Dependencies**: See package.json for full list
|
|
662
|
+
|
|
663
|
+
## Support and Documentation
|
|
664
|
+
|
|
665
|
+
- **Main Framework CLAUDE.md**: See root Frigg CLAUDE.md for framework-wide guidance
|
|
666
|
+
- **Core Runtime**: See `core/CLAUDE.md` for Lambda/Worker patterns
|
|
667
|
+
- **Encryption**: See `database/encryption/README.md` for encryption details
|
|
668
|
+
- **Package README**: See `README.md` for API reference
|
|
669
|
+
|
|
670
|
+
## Recent Important Changes
|
|
671
|
+
|
|
672
|
+
### Field-Level Encryption JSON Object Support
|
|
673
|
+
|
|
674
|
+
**Date**: 2025-01-06
|
|
675
|
+
|
|
676
|
+
**Problem**: The `FieldEncryptionService` was converting objects to the string `"[object Object]"` before encrypting, corrupting JSON fields like `IntegrationMapping.mapping`.
|
|
677
|
+
|
|
678
|
+
**Solution**: Added `_serializeForEncryption()` and `_deserializeAfterDecryption()` methods:
|
|
679
|
+
- Objects are now JSON.stringify'd before encryption
|
|
680
|
+
- Decrypted strings are JSON.parse'd back to objects
|
|
681
|
+
- Plain strings work as before
|
|
682
|
+
|
|
683
|
+
**Files Changed**:
|
|
684
|
+
- `database/encryption/field-encryption-service.js`
|
|
685
|
+
- `database/encryption/field-encryption-service.test.js`
|
|
686
|
+
|
|
687
|
+
**Test Coverage**: All 40 tests pass, including new object encryption test.
|
|
688
|
+
|
|
689
|
+
**Impact**: `IntegrationMapping.mapping` and other JSON fields now correctly round-trip through encryption.
|
|
690
|
+
|
|
691
|
+
---
|
|
692
|
+
|
|
693
|
+
**Built with ❤️ by the Frigg Framework team**
|