@friggframework/admin-scripts 2.0.0--canary.517.f04156f.0 → 2.0.0--canary.517.300ded3.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.
@@ -1,261 +0,0 @@
1
- /**
2
- * Dry-Run Repository Wrapper
3
- *
4
- * Wraps any repository to intercept write operations.
5
- * - READ operations pass through unchanged
6
- * - WRITE operations are logged but not executed
7
- *
8
- * Uses Proxy pattern for dynamic method interception
9
- */
10
-
11
- /**
12
- * Create a dry-run wrapper for any repository
13
- *
14
- * @param {Object} repository - The real repository to wrap
15
- * @param {Array} operationLog - Array to append logged operations
16
- * @param {string} modelName - Name of the model (for logging)
17
- * @returns {Proxy} Wrapped repository that logs write operations
18
- */
19
- function createDryRunWrapper(repository, operationLog, modelName) {
20
- return new Proxy(repository, {
21
- get(target, prop) {
22
- const value = target[prop];
23
-
24
- // Return non-function properties as-is
25
- if (typeof value !== 'function') {
26
- return value;
27
- }
28
-
29
- // Identify write operations by name pattern
30
- const writePatterns = /^(create|update|delete|upsert|append|remove|insert|save)/i;
31
- const isWrite = writePatterns.test(prop);
32
-
33
- // Pass through read operations
34
- if (!isWrite) {
35
- return value.bind(target);
36
- }
37
-
38
- // Wrap write operation
39
- return async (...args) => {
40
- // Log the operation that WOULD have been performed
41
- operationLog.push({
42
- operation: prop.toUpperCase(),
43
- model: modelName,
44
- method: prop,
45
- args: sanitizeArgs(args),
46
- timestamp: new Date().toISOString(),
47
- wouldExecute: `${modelName}.${prop}()`,
48
- });
49
-
50
- // For write operations, try to return existing data or mock data
51
- // This helps scripts continue executing without errors
52
-
53
- // For updates, try to return existing data
54
- if (prop.includes('update') || prop.includes('upsert')) {
55
- // Try to extract ID from first argument
56
- const possibleId = args[0];
57
- let existing = null;
58
-
59
- if (possibleId && typeof possibleId === 'string') {
60
- // Try to find existing record
61
- const findMethod = getFindMethod(target, prop);
62
- if (findMethod) {
63
- try {
64
- existing = await findMethod.call(target, possibleId);
65
- } catch (err) {
66
- // Ignore errors, continue to mock
67
- }
68
- }
69
- }
70
-
71
- // Return merged data
72
- if (existing) {
73
- // Merge update data with existing
74
- return { ...existing, ...args[1], _dryRun: true };
75
- }
76
-
77
- // No existing data, return mock
78
- if (args[1]) {
79
- return { id: possibleId, ...args[1], _dryRun: true };
80
- }
81
-
82
- return { id: possibleId, _dryRun: true };
83
- }
84
-
85
- // For creates, return mock object with the data
86
- if (prop.includes('create') || prop.includes('insert')) {
87
- const data = args[0] || {};
88
- return {
89
- id: `dry-run-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
90
- ...data,
91
- _dryRun: true,
92
- createdAt: new Date().toISOString(),
93
- };
94
- }
95
-
96
- // For deletes, return success indication
97
- if (prop.includes('delete') || prop.includes('remove')) {
98
- return { deletedCount: 1, _dryRun: true };
99
- }
100
-
101
- // Default: return mock success
102
- return { success: true, _dryRun: true };
103
- };
104
- },
105
- });
106
- }
107
-
108
- /**
109
- * Try to find a corresponding find method for an update operation
110
- * @param {Object} target - Repository target
111
- * @param {string} updateMethod - Update method name
112
- * @returns {Function|null} Find method or null
113
- */
114
- function getFindMethod(target, updateMethod) {
115
- // Common patterns: updateIntegration -> findIntegrationById
116
- const patterns = [
117
- () => {
118
- const match = updateMethod.match(/update(\w+)/i);
119
- return match ? `find${match[1]}ById` : null;
120
- },
121
- () => {
122
- const match = updateMethod.match(/update(\w+)/i);
123
- return match ? `get${match[1]}ById` : null;
124
- },
125
- () => 'findById',
126
- () => 'getById',
127
- ];
128
-
129
- for (const pattern of patterns) {
130
- const methodName = pattern();
131
- if (methodName && typeof target[methodName] === 'function') {
132
- return target[methodName];
133
- }
134
- }
135
-
136
- return null;
137
- }
138
-
139
- /**
140
- * Sanitize arguments for logging (remove sensitive data)
141
- * @param {Array} args - Function arguments
142
- * @returns {Array} Sanitized arguments
143
- */
144
- function sanitizeArgs(args) {
145
- return args.map((arg) => {
146
- if (arg === null || arg === undefined) {
147
- return arg;
148
- }
149
-
150
- if (typeof arg !== 'object') {
151
- return arg;
152
- }
153
-
154
- if (Array.isArray(arg)) {
155
- return arg.map((item) => sanitizeArgs([item])[0]);
156
- }
157
-
158
- // Sanitize object - remove sensitive fields
159
- const sanitized = {};
160
- for (const [key, value] of Object.entries(arg)) {
161
- const lowerKey = key.toLowerCase();
162
-
163
- // Skip sensitive fields
164
- if (
165
- lowerKey.includes('password') ||
166
- lowerKey.includes('token') ||
167
- lowerKey.includes('secret') ||
168
- lowerKey.includes('key') ||
169
- lowerKey.includes('auth')
170
- ) {
171
- sanitized[key] = '[REDACTED]';
172
- continue;
173
- }
174
-
175
- // Recursively sanitize nested objects
176
- if (typeof value === 'object' && value !== null) {
177
- sanitized[key] = sanitizeArgs([value])[0];
178
- } else {
179
- sanitized[key] = value;
180
- }
181
- }
182
-
183
- return sanitized;
184
- });
185
- }
186
-
187
- /**
188
- * Wrap AdminFriggCommands for dry-run mode
189
- *
190
- * @param {Object} realCommands - Real AdminFriggCommands instance
191
- * @param {Array} operationLog - Array to append logged operations
192
- * @returns {Object} Wrapped commands with dry-run repository wrappers
193
- */
194
- function wrapAdminFriggCommandsForDryRun(realCommands, operationLog) {
195
- return new Proxy(realCommands, {
196
- get(target, prop) {
197
- const value = target[prop];
198
-
199
- // Pass through non-functions
200
- if (typeof value !== 'function') {
201
- // For lazy-loaded repositories, wrap them
202
- if (prop.endsWith('Repository') && value && typeof value === 'object') {
203
- const modelName = prop.replace('Repository', '');
204
- return createDryRunWrapper(
205
- value,
206
- operationLog,
207
- modelName.charAt(0).toUpperCase() + modelName.slice(1)
208
- );
209
- }
210
- return value;
211
- }
212
-
213
- // Identify write operations on the commands themselves
214
- const writePatterns = /^(update|create|delete|append)/i;
215
- const isWrite = writePatterns.test(prop);
216
-
217
- if (!isWrite) {
218
- // Read operations pass through
219
- return value.bind(target);
220
- }
221
-
222
- // Wrap write operations
223
- return async (...args) => {
224
- operationLog.push({
225
- operation: prop.toUpperCase(),
226
- source: 'AdminFriggCommands',
227
- method: prop,
228
- args: sanitizeArgs(args),
229
- timestamp: new Date().toISOString(),
230
- });
231
-
232
- // For specific known methods, try to return sensible mocks
233
- if (prop === 'updateIntegrationConfig') {
234
- const [integrationId] = args;
235
- const existing = await target.findIntegrationById(integrationId);
236
- return existing;
237
- }
238
-
239
- if (prop === 'updateIntegrationStatus') {
240
- const [integrationId] = args;
241
- const existing = await target.findIntegrationById(integrationId);
242
- return existing;
243
- }
244
-
245
- if (prop === 'updateCredential') {
246
- const [credentialId, updates] = args;
247
- return { id: credentialId, ...updates, _dryRun: true };
248
- }
249
-
250
- // Default mock
251
- return { success: true, _dryRun: true };
252
- };
253
- },
254
- });
255
- }
256
-
257
- module.exports = {
258
- createDryRunWrapper,
259
- wrapAdminFriggCommandsForDryRun,
260
- sanitizeArgs,
261
- };