@friggframework/core 2.0.0--canary.395.a6dcc5a.0 → 2.0.0--canary.395.de6bcdf.0

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.
@@ -0,0 +1,188 @@
1
+ const { Module } = require('./module');
2
+ const { ModuleFactory } = require('./module-factory');
3
+
4
+ // Mock OAuth2Requester base class
5
+ class MockOAuth2Api {
6
+ constructor(params) {
7
+ // Capture all params passed to API constructor
8
+ this.client_id = params.client_id;
9
+ this.client_secret = params.client_secret;
10
+ this.redirect_uri = params.redirect_uri;
11
+ this.scope = params.scope;
12
+ this.access_token = params.access_token;
13
+ this.refresh_token = params.refresh_token;
14
+ this.domain = params.domain;
15
+ this.delegate = params.delegate;
16
+ }
17
+
18
+ // Mock API methods
19
+ async listProjects() {
20
+ if (!this.access_token) {
21
+ throw new Error('No access token provided');
22
+ }
23
+ return { projects: ['project1', 'project2'] };
24
+ }
25
+
26
+ async getFolders() {
27
+ if (!this.access_token) {
28
+ throw new Error('No access token provided');
29
+ }
30
+ return { folders: ['folder1', 'folder2'] };
31
+ }
32
+
33
+ getAuthorizationRequirements() {
34
+ return { type: 'oauth2', url: 'https://example.com/oauth' };
35
+ }
36
+ }
37
+
38
+ MockOAuth2Api.requesterType = 'oauth2';
39
+
40
+ // Mock module definition
41
+ const mockModuleDefinition = {
42
+ moduleName: 'testmodule',
43
+ modelName: 'TestModule',
44
+ API: MockOAuth2Api,
45
+ requiredAuthMethods: {
46
+ getToken: async () => {},
47
+ getEntityDetails: async () => {},
48
+ getCredentialDetails: async () => {},
49
+ apiPropertiesToPersist: {
50
+ credential: ['access_token', 'refresh_token'],
51
+ entity: ['domain'],
52
+ },
53
+ testAuthRequest: async () => true,
54
+ },
55
+ env: {
56
+ client_id: 'test_client_id',
57
+ client_secret: 'test_client_secret',
58
+ redirect_uri: 'https://test.com/redirect',
59
+ scope: 'read write',
60
+ },
61
+ };
62
+
63
+ describe('Module Hydration', () => {
64
+ describe('Module API instantiation', () => {
65
+ it('should create API instance with merged env and credential params', () => {
66
+ const entity = {
67
+ id: 'entity-1',
68
+ moduleName: 'testmodule',
69
+ domain: 'test.domain.com',
70
+ credential: {
71
+ access_token: 'test_access_token',
72
+ refresh_token: 'test_refresh_token',
73
+ },
74
+ };
75
+
76
+ const module = new Module({
77
+ definition: mockModuleDefinition,
78
+ userId: 'user-1',
79
+ entity,
80
+ });
81
+
82
+ // Verify module properties
83
+ expect(module.name).toBe('testmodule');
84
+ expect(module.api).toBeDefined();
85
+
86
+ // Verify API was instantiated with correct params
87
+ expect(module.api.client_id).toBe('test_client_id');
88
+ expect(module.api.client_secret).toBe('test_client_secret');
89
+ expect(module.api.redirect_uri).toBe('https://test.com/redirect');
90
+ expect(module.api.scope).toBe('read write');
91
+ expect(module.api.access_token).toBe('test_access_token');
92
+ expect(module.api.refresh_token).toBe('test_refresh_token');
93
+ expect(module.api.domain).toBe('test.domain.com');
94
+ });
95
+
96
+ it('should allow API methods to be called with credentials', async () => {
97
+ const entity = {
98
+ id: 'entity-1',
99
+ moduleName: 'testmodule',
100
+ credential: {
101
+ access_token: 'valid_token',
102
+ refresh_token: 'valid_refresh_token',
103
+ },
104
+ };
105
+
106
+ const module = new Module({
107
+ definition: mockModuleDefinition,
108
+ userId: 'user-1',
109
+ entity,
110
+ });
111
+
112
+ // Test that API methods work with credentials
113
+ const projects = await module.api.listProjects();
114
+ expect(projects).toEqual({ projects: ['project1', 'project2'] });
115
+
116
+ const folders = await module.api.getFolders();
117
+ expect(folders).toEqual({ folders: ['folder1', 'folder2'] });
118
+ });
119
+
120
+ it('should handle missing credentials gracefully', () => {
121
+ const entity = {
122
+ id: 'entity-1',
123
+ moduleName: 'testmodule',
124
+ // No credential property
125
+ };
126
+
127
+ const module = new Module({
128
+ definition: mockModuleDefinition,
129
+ userId: 'user-1',
130
+ entity,
131
+ });
132
+
133
+ // API should still be created with env params only
134
+ expect(module.api).toBeDefined();
135
+ expect(module.api.client_id).toBe('test_client_id');
136
+ expect(module.api.access_token).toBeUndefined();
137
+ });
138
+ });
139
+
140
+ describe('ModuleFactory', () => {
141
+ it('should create module instance from entity and definition', async () => {
142
+ const entity = {
143
+ id: 'entity-1',
144
+ moduleName: 'testmodule',
145
+ userId: 'user-1',
146
+ credential: {
147
+ access_token: 'factory_token',
148
+ },
149
+ };
150
+
151
+ const moduleRepository = {
152
+ findEntityById: jest.fn().mockResolvedValue(entity),
153
+ };
154
+
155
+ const factory = new ModuleFactory({
156
+ moduleRepository,
157
+ moduleDefinitions: [mockModuleDefinition],
158
+ });
159
+
160
+ const module = await factory.getModuleInstance('entity-1', 'user-1');
161
+
162
+ expect(module).toBeDefined();
163
+ expect(module.api).toBeDefined();
164
+ expect(module.api.access_token).toBe('factory_token');
165
+ });
166
+
167
+ it('should throw error if module definition not found', async () => {
168
+ const entity = {
169
+ id: 'entity-1',
170
+ moduleName: 'unknownmodule',
171
+ userId: 'user-1',
172
+ };
173
+
174
+ const moduleRepository = {
175
+ findEntityById: jest.fn().mockResolvedValue(entity),
176
+ };
177
+
178
+ const factory = new ModuleFactory({
179
+ moduleRepository,
180
+ moduleDefinitions: [mockModuleDefinition],
181
+ });
182
+
183
+ await expect(
184
+ factory.getModuleInstance('entity-1', 'user-1')
185
+ ).rejects.toThrow('Module definition not found for module: unknownmodule');
186
+ });
187
+ });
188
+ });
@@ -57,6 +57,25 @@ class ModuleRepository {
57
57
  }));
58
58
  }
59
59
 
60
+ async findEntitiesByUserIdAndModuleName(userId, moduleName) {
61
+ const entitiesRecords = await Entity.find(
62
+ { user: userId, moduleName: moduleName },
63
+ '',
64
+ { lean: true }
65
+ ).populate('credential');
66
+
67
+ return entitiesRecords.map(e => ({
68
+ id: e._id.toString(),
69
+ accountId: e.accountId,
70
+ credential: e.credential,
71
+ userId: e.user.toString(),
72
+ name: e.name,
73
+ externalId: e.externalId,
74
+ type: e.__t,
75
+ moduleName: e.moduleName,
76
+ }));
77
+ }
78
+
60
79
  /**
61
80
  * Remove the credential reference from an Entity document without loading a full Mongoose instance.
62
81
  * Useful when a credential has been revoked/deleted (e.g. via Module.deauthorize).
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@friggframework/core",
3
3
  "prettier": "@friggframework/prettier-config",
4
- "version": "2.0.0--canary.395.a6dcc5a.0",
4
+ "version": "2.0.0--canary.395.de6bcdf.0",
5
5
  "dependencies": {
6
6
  "@hapi/boom": "^10.0.1",
7
7
  "aws-sdk": "^2.1200.0",
@@ -22,9 +22,9 @@
22
22
  "uuid": "^9.0.1"
23
23
  },
24
24
  "devDependencies": {
25
- "@friggframework/eslint-config": "2.0.0--canary.395.a6dcc5a.0",
26
- "@friggframework/prettier-config": "2.0.0--canary.395.a6dcc5a.0",
27
- "@friggframework/test": "2.0.0--canary.395.a6dcc5a.0",
25
+ "@friggframework/eslint-config": "2.0.0--canary.395.de6bcdf.0",
26
+ "@friggframework/prettier-config": "2.0.0--canary.395.de6bcdf.0",
27
+ "@friggframework/test": "2.0.0--canary.395.de6bcdf.0",
28
28
  "@types/lodash": "4.17.15",
29
29
  "@typescript-eslint/eslint-plugin": "^8.0.0",
30
30
  "chai": "^4.3.6",
@@ -56,5 +56,5 @@
56
56
  "publishConfig": {
57
57
  "access": "public"
58
58
  },
59
- "gitHead": "a6dcc5a70f9edea8eb3fbe00825a7db7305849b8"
59
+ "gitHead": "de6bcdff381ea1c101c455609f9d4cd379831432"
60
60
  }