@friggframework/devtools 2.0.0-next.7 → 2.0.0-next.71

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.
Files changed (240) hide show
  1. package/frigg-cli/README.md +1289 -0
  2. package/frigg-cli/__tests__/unit/commands/build.test.js +279 -0
  3. package/frigg-cli/__tests__/unit/commands/db-setup.test.js +649 -0
  4. package/frigg-cli/__tests__/unit/commands/deploy.test.js +320 -0
  5. package/frigg-cli/__tests__/unit/commands/doctor.test.js +309 -0
  6. package/frigg-cli/__tests__/unit/commands/install.test.js +400 -0
  7. package/frigg-cli/__tests__/unit/commands/ui.test.js +346 -0
  8. package/frigg-cli/__tests__/unit/dependencies.test.js +74 -0
  9. package/frigg-cli/__tests__/unit/utils/database-validator.test.js +397 -0
  10. package/frigg-cli/__tests__/unit/utils/error-messages.test.js +345 -0
  11. package/frigg-cli/__tests__/unit/version-detection.test.js +171 -0
  12. package/frigg-cli/__tests__/utils/mock-factory.js +270 -0
  13. package/frigg-cli/__tests__/utils/prisma-mock.js +194 -0
  14. package/frigg-cli/__tests__/utils/test-fixtures.js +463 -0
  15. package/frigg-cli/__tests__/utils/test-setup.js +287 -0
  16. package/frigg-cli/auth-command/CLAUDE.md +293 -0
  17. package/frigg-cli/auth-command/README.md +450 -0
  18. package/frigg-cli/auth-command/api-key-flow.js +153 -0
  19. package/frigg-cli/auth-command/auth-tester.js +344 -0
  20. package/frigg-cli/auth-command/credential-storage.js +182 -0
  21. package/frigg-cli/auth-command/index.js +256 -0
  22. package/frigg-cli/auth-command/json-schema-form.js +67 -0
  23. package/frigg-cli/auth-command/module-loader.js +172 -0
  24. package/frigg-cli/auth-command/oauth-callback-server.js +431 -0
  25. package/frigg-cli/auth-command/oauth-flow.js +195 -0
  26. package/frigg-cli/auth-command/utils/browser.js +30 -0
  27. package/frigg-cli/build-command/index.js +45 -12
  28. package/frigg-cli/db-setup-command/index.js +246 -0
  29. package/frigg-cli/deploy-command/SPEC-DEPLOY-DRY-RUN.md +981 -0
  30. package/frigg-cli/deploy-command/index.js +295 -23
  31. package/frigg-cli/doctor-command/index.js +335 -0
  32. package/frigg-cli/generate-command/__tests__/generate-command.test.js +301 -0
  33. package/frigg-cli/generate-command/azure-generator.js +43 -0
  34. package/frigg-cli/generate-command/gcp-generator.js +47 -0
  35. package/frigg-cli/generate-command/index.js +332 -0
  36. package/frigg-cli/generate-command/terraform-generator.js +555 -0
  37. package/frigg-cli/generate-iam-command.js +118 -0
  38. package/frigg-cli/index.js +174 -1
  39. package/frigg-cli/index.test.js +1 -4
  40. package/frigg-cli/init-command/backend-first-handler.js +756 -0
  41. package/frigg-cli/init-command/index.js +93 -0
  42. package/frigg-cli/init-command/template-handler.js +143 -0
  43. package/frigg-cli/install-command/index.js +1 -4
  44. package/frigg-cli/jest.config.js +124 -0
  45. package/frigg-cli/package.json +63 -0
  46. package/frigg-cli/repair-command/index.js +564 -0
  47. package/frigg-cli/start-command/index.js +118 -5
  48. package/frigg-cli/start-command/start-command.test.js +297 -0
  49. package/frigg-cli/test/init-command.test.js +180 -0
  50. package/frigg-cli/test/npm-registry.test.js +319 -0
  51. package/frigg-cli/ui-command/index.js +154 -0
  52. package/frigg-cli/utils/app-resolver.js +319 -0
  53. package/frigg-cli/utils/backend-path.js +16 -17
  54. package/frigg-cli/utils/database-validator.js +167 -0
  55. package/frigg-cli/utils/error-messages.js +329 -0
  56. package/frigg-cli/utils/npm-registry.js +167 -0
  57. package/frigg-cli/utils/process-manager.js +199 -0
  58. package/frigg-cli/utils/repo-detection.js +405 -0
  59. package/infrastructure/ARCHITECTURE.md +487 -0
  60. package/infrastructure/CLAUDE.md +481 -0
  61. package/infrastructure/HEALTH.md +468 -0
  62. package/infrastructure/README.md +522 -0
  63. package/infrastructure/__tests__/fixtures/mock-aws-resources.js +391 -0
  64. package/infrastructure/__tests__/helpers/test-utils.js +277 -0
  65. package/infrastructure/__tests__/postgres-config.test.js +914 -0
  66. package/infrastructure/__tests__/template-generation.test.js +687 -0
  67. package/infrastructure/create-frigg-infrastructure.js +129 -20
  68. package/infrastructure/docs/POSTGRES-CONFIGURATION.md +630 -0
  69. package/infrastructure/docs/PRE-DEPLOYMENT-HEALTH-CHECK-SPEC.md +1317 -0
  70. package/infrastructure/docs/WEBSOCKET-CONFIGURATION.md +105 -0
  71. package/infrastructure/docs/deployment-instructions.md +268 -0
  72. package/infrastructure/docs/generate-iam-command.md +278 -0
  73. package/infrastructure/docs/iam-policy-templates.md +193 -0
  74. package/infrastructure/domains/database/aurora-builder.js +809 -0
  75. package/infrastructure/domains/database/aurora-builder.test.js +950 -0
  76. package/infrastructure/domains/database/aurora-discovery.js +87 -0
  77. package/infrastructure/domains/database/aurora-discovery.test.js +188 -0
  78. package/infrastructure/domains/database/aurora-resolver.js +210 -0
  79. package/infrastructure/domains/database/aurora-resolver.test.js +347 -0
  80. package/infrastructure/domains/database/migration-builder.js +701 -0
  81. package/infrastructure/domains/database/migration-builder.test.js +321 -0
  82. package/infrastructure/domains/database/migration-resolver.js +163 -0
  83. package/infrastructure/domains/database/migration-resolver.test.js +337 -0
  84. package/infrastructure/domains/health/application/ports/IPropertyReconciler.js +164 -0
  85. package/infrastructure/domains/health/application/ports/IResourceDetector.js +129 -0
  86. package/infrastructure/domains/health/application/ports/IResourceImporter.js +142 -0
  87. package/infrastructure/domains/health/application/ports/IStackRepository.js +131 -0
  88. package/infrastructure/domains/health/application/ports/index.js +26 -0
  89. package/infrastructure/domains/health/application/use-cases/__tests__/execute-resource-import-use-case.test.js +679 -0
  90. package/infrastructure/domains/health/application/use-cases/__tests__/mismatch-analyzer-method-name.test.js +167 -0
  91. package/infrastructure/domains/health/application/use-cases/__tests__/repair-via-import-use-case.test.js +1130 -0
  92. package/infrastructure/domains/health/application/use-cases/execute-resource-import-use-case.js +221 -0
  93. package/infrastructure/domains/health/application/use-cases/reconcile-properties-use-case.js +152 -0
  94. package/infrastructure/domains/health/application/use-cases/reconcile-properties-use-case.test.js +343 -0
  95. package/infrastructure/domains/health/application/use-cases/repair-via-import-use-case.js +535 -0
  96. package/infrastructure/domains/health/application/use-cases/repair-via-import-use-case.test.js +376 -0
  97. package/infrastructure/domains/health/application/use-cases/run-health-check-use-case.js +213 -0
  98. package/infrastructure/domains/health/application/use-cases/run-health-check-use-case.test.js +441 -0
  99. package/infrastructure/domains/health/docs/ACME-DEV-DRIFT-ANALYSIS.md +267 -0
  100. package/infrastructure/domains/health/docs/BUILD-VS-DEPLOYED-TEMPLATE-ANALYSIS.md +324 -0
  101. package/infrastructure/domains/health/docs/ORPHAN-DETECTION-ANALYSIS.md +386 -0
  102. package/infrastructure/domains/health/docs/SPEC-CLEANUP-COMMAND.md +1419 -0
  103. package/infrastructure/domains/health/docs/TDD-IMPLEMENTATION-SUMMARY.md +391 -0
  104. package/infrastructure/domains/health/docs/TEMPLATE-COMPARISON-IMPLEMENTATION.md +551 -0
  105. package/infrastructure/domains/health/domain/entities/issue.js +299 -0
  106. package/infrastructure/domains/health/domain/entities/issue.test.js +528 -0
  107. package/infrastructure/domains/health/domain/entities/property-mismatch.js +108 -0
  108. package/infrastructure/domains/health/domain/entities/property-mismatch.test.js +275 -0
  109. package/infrastructure/domains/health/domain/entities/resource.js +159 -0
  110. package/infrastructure/domains/health/domain/entities/resource.test.js +432 -0
  111. package/infrastructure/domains/health/domain/entities/stack-health-report.js +306 -0
  112. package/infrastructure/domains/health/domain/entities/stack-health-report.test.js +601 -0
  113. package/infrastructure/domains/health/domain/services/__tests__/health-score-percentage-based.test.js +380 -0
  114. package/infrastructure/domains/health/domain/services/__tests__/import-progress-monitor.test.js +971 -0
  115. package/infrastructure/domains/health/domain/services/__tests__/import-template-generator.test.js +1150 -0
  116. package/infrastructure/domains/health/domain/services/__tests__/logical-id-mapper.test.js +672 -0
  117. package/infrastructure/domains/health/domain/services/__tests__/template-parser.test.js +496 -0
  118. package/infrastructure/domains/health/domain/services/__tests__/update-progress-monitor.test.js +419 -0
  119. package/infrastructure/domains/health/domain/services/health-score-calculator.js +248 -0
  120. package/infrastructure/domains/health/domain/services/health-score-calculator.test.js +504 -0
  121. package/infrastructure/domains/health/domain/services/import-progress-monitor.js +195 -0
  122. package/infrastructure/domains/health/domain/services/import-template-generator.js +435 -0
  123. package/infrastructure/domains/health/domain/services/logical-id-mapper.js +345 -0
  124. package/infrastructure/domains/health/domain/services/mismatch-analyzer.js +234 -0
  125. package/infrastructure/domains/health/domain/services/mismatch-analyzer.test.js +431 -0
  126. package/infrastructure/domains/health/domain/services/property-mutability-config.js +382 -0
  127. package/infrastructure/domains/health/domain/services/template-parser.js +245 -0
  128. package/infrastructure/domains/health/domain/services/update-progress-monitor.js +192 -0
  129. package/infrastructure/domains/health/domain/value-objects/health-score.js +138 -0
  130. package/infrastructure/domains/health/domain/value-objects/health-score.test.js +267 -0
  131. package/infrastructure/domains/health/domain/value-objects/property-mutability.js +161 -0
  132. package/infrastructure/domains/health/domain/value-objects/property-mutability.test.js +198 -0
  133. package/infrastructure/domains/health/domain/value-objects/resource-state.js +167 -0
  134. package/infrastructure/domains/health/domain/value-objects/resource-state.test.js +196 -0
  135. package/infrastructure/domains/health/domain/value-objects/stack-identifier.js +192 -0
  136. package/infrastructure/domains/health/domain/value-objects/stack-identifier.test.js +262 -0
  137. package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-cfn-tagged.test.js +312 -0
  138. package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-multi-stack.test.js +367 -0
  139. package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-relationship-analysis.test.js +432 -0
  140. package/infrastructure/domains/health/infrastructure/adapters/aws-property-reconciler.js +784 -0
  141. package/infrastructure/domains/health/infrastructure/adapters/aws-property-reconciler.test.js +1133 -0
  142. package/infrastructure/domains/health/infrastructure/adapters/aws-resource-detector.js +565 -0
  143. package/infrastructure/domains/health/infrastructure/adapters/aws-resource-detector.test.js +554 -0
  144. package/infrastructure/domains/health/infrastructure/adapters/aws-resource-importer.js +318 -0
  145. package/infrastructure/domains/health/infrastructure/adapters/aws-resource-importer.test.js +398 -0
  146. package/infrastructure/domains/health/infrastructure/adapters/aws-stack-repository.js +777 -0
  147. package/infrastructure/domains/health/infrastructure/adapters/aws-stack-repository.test.js +580 -0
  148. package/infrastructure/domains/integration/integration-builder.js +404 -0
  149. package/infrastructure/domains/integration/integration-builder.test.js +690 -0
  150. package/infrastructure/domains/integration/integration-resolver.js +170 -0
  151. package/infrastructure/domains/integration/integration-resolver.test.js +369 -0
  152. package/infrastructure/domains/integration/websocket-builder.js +69 -0
  153. package/infrastructure/domains/integration/websocket-builder.test.js +195 -0
  154. package/infrastructure/domains/networking/vpc-builder.js +2051 -0
  155. package/infrastructure/domains/networking/vpc-builder.test.js +1960 -0
  156. package/infrastructure/domains/networking/vpc-discovery.js +177 -0
  157. package/infrastructure/domains/networking/vpc-discovery.test.js +350 -0
  158. package/infrastructure/domains/networking/vpc-resolver.js +505 -0
  159. package/infrastructure/domains/networking/vpc-resolver.test.js +801 -0
  160. package/infrastructure/domains/parameters/ssm-builder.js +79 -0
  161. package/infrastructure/domains/parameters/ssm-builder.test.js +189 -0
  162. package/infrastructure/domains/parameters/ssm-discovery.js +84 -0
  163. package/infrastructure/domains/parameters/ssm-discovery.test.js +210 -0
  164. package/infrastructure/domains/scheduler/scheduler-builder.js +211 -0
  165. package/infrastructure/domains/security/iam-generator.js +816 -0
  166. package/infrastructure/domains/security/iam-generator.test.js +204 -0
  167. package/infrastructure/domains/security/kms-builder.js +415 -0
  168. package/infrastructure/domains/security/kms-builder.test.js +392 -0
  169. package/infrastructure/domains/security/kms-discovery.js +80 -0
  170. package/infrastructure/domains/security/kms-discovery.test.js +177 -0
  171. package/infrastructure/domains/security/kms-resolver.js +96 -0
  172. package/infrastructure/domains/security/kms-resolver.test.js +216 -0
  173. package/infrastructure/domains/security/templates/frigg-deployment-iam-stack.yaml +401 -0
  174. package/infrastructure/domains/security/templates/iam-policy-basic.json +218 -0
  175. package/infrastructure/domains/security/templates/iam-policy-full.json +288 -0
  176. package/infrastructure/domains/shared/base-builder.js +112 -0
  177. package/infrastructure/domains/shared/base-resolver.js +186 -0
  178. package/infrastructure/domains/shared/base-resolver.test.js +305 -0
  179. package/infrastructure/domains/shared/builder-orchestrator.js +212 -0
  180. package/infrastructure/domains/shared/builder-orchestrator.test.js +213 -0
  181. package/infrastructure/domains/shared/cloudformation-discovery-v2.js +334 -0
  182. package/infrastructure/domains/shared/cloudformation-discovery.js +672 -0
  183. package/infrastructure/domains/shared/cloudformation-discovery.test.js +985 -0
  184. package/infrastructure/domains/shared/environment-builder.js +119 -0
  185. package/infrastructure/domains/shared/environment-builder.test.js +247 -0
  186. package/infrastructure/domains/shared/providers/aws-provider-adapter.js +579 -0
  187. package/infrastructure/domains/shared/providers/aws-provider-adapter.test.js +416 -0
  188. package/infrastructure/domains/shared/providers/azure-provider-adapter.stub.js +93 -0
  189. package/infrastructure/domains/shared/providers/cloud-provider-adapter.js +136 -0
  190. package/infrastructure/domains/shared/providers/gcp-provider-adapter.stub.js +82 -0
  191. package/infrastructure/domains/shared/providers/provider-factory.js +108 -0
  192. package/infrastructure/domains/shared/providers/provider-factory.test.js +170 -0
  193. package/infrastructure/domains/shared/resource-discovery.enhanced.test.js +306 -0
  194. package/infrastructure/domains/shared/resource-discovery.js +233 -0
  195. package/infrastructure/domains/shared/resource-discovery.test.js +588 -0
  196. package/infrastructure/domains/shared/types/app-definition.js +205 -0
  197. package/infrastructure/domains/shared/types/discovery-result.js +106 -0
  198. package/infrastructure/domains/shared/types/discovery-result.test.js +258 -0
  199. package/infrastructure/domains/shared/types/index.js +46 -0
  200. package/infrastructure/domains/shared/types/resource-ownership.js +108 -0
  201. package/infrastructure/domains/shared/types/resource-ownership.test.js +101 -0
  202. package/infrastructure/domains/shared/utilities/base-definition-factory.js +408 -0
  203. package/infrastructure/domains/shared/utilities/base-definition-factory.js.bak +338 -0
  204. package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +291 -0
  205. package/infrastructure/domains/shared/utilities/handler-path-resolver.js +134 -0
  206. package/infrastructure/domains/shared/utilities/handler-path-resolver.test.js +268 -0
  207. package/infrastructure/domains/shared/utilities/prisma-layer-manager.js +159 -0
  208. package/infrastructure/domains/shared/utilities/prisma-layer-manager.test.js +444 -0
  209. package/infrastructure/domains/shared/validation/env-validator.js +78 -0
  210. package/infrastructure/domains/shared/validation/env-validator.test.js +173 -0
  211. package/infrastructure/domains/shared/validation/plugin-validator.js +187 -0
  212. package/infrastructure/domains/shared/validation/plugin-validator.test.js +323 -0
  213. package/infrastructure/esbuild.config.js +53 -0
  214. package/infrastructure/infrastructure-composer.js +119 -0
  215. package/infrastructure/infrastructure-composer.test.js +1895 -0
  216. package/infrastructure/integration.test.js +383 -0
  217. package/infrastructure/scripts/build-prisma-layer.js +701 -0
  218. package/infrastructure/scripts/build-prisma-layer.test.js +170 -0
  219. package/infrastructure/scripts/build-time-discovery.js +238 -0
  220. package/infrastructure/scripts/build-time-discovery.test.js +379 -0
  221. package/infrastructure/scripts/run-discovery.js +110 -0
  222. package/infrastructure/scripts/verify-prisma-layer.js +72 -0
  223. package/management-ui/README.md +203 -0
  224. package/package.json +44 -14
  225. package/test/index.js +2 -4
  226. package/test/mock-api.js +1 -3
  227. package/test/mock-integration.js +4 -14
  228. package/.eslintrc.json +0 -3
  229. package/CHANGELOG.md +0 -132
  230. package/infrastructure/app-handler-helpers.js +0 -57
  231. package/infrastructure/backend-utils.js +0 -87
  232. package/infrastructure/routers/auth.js +0 -26
  233. package/infrastructure/routers/integration-defined-routers.js +0 -42
  234. package/infrastructure/routers/middleware/loadUser.js +0 -15
  235. package/infrastructure/routers/middleware/requireLoggedInUser.js +0 -12
  236. package/infrastructure/routers/user.js +0 -41
  237. package/infrastructure/routers/websocket.js +0 -55
  238. package/infrastructure/serverless-template.js +0 -291
  239. package/infrastructure/workers/integration-defined-workers.js +0 -24
  240. package/test/auther-definition-tester.js +0 -125
@@ -0,0 +1,287 @@
1
+ /**
2
+ * Global test setup for Frigg CLI tests
3
+ * This file is executed before each test file
4
+ */
5
+
6
+ // Store original environment
7
+ const originalEnv = process.env;
8
+ const originalConsole = { ...console };
9
+ // Store original process methods (not entire object due to read-only properties)
10
+ const originalProcessExit = process.exit;
11
+ const originalProcessCwd = process.cwd;
12
+
13
+ // Mock console to prevent noisy output during tests
14
+ global.console = {
15
+ ...console,
16
+ log: jest.fn(),
17
+ info: jest.fn(),
18
+ warn: jest.fn(),
19
+ error: jest.fn(),
20
+ debug: jest.fn()
21
+ };
22
+
23
+ // Set up test environment variables
24
+ process.env = {
25
+ ...originalEnv,
26
+ NODE_ENV: 'test',
27
+ HOME: '/mock/home',
28
+ PATH: '/mock/path',
29
+ CI: 'true'
30
+ };
31
+
32
+ // Global setup before each test
33
+ beforeEach(() => {
34
+ // Clear all mocks
35
+ jest.clearAllMocks();
36
+
37
+ // Reset timers
38
+ jest.clearAllTimers();
39
+
40
+ // Reset modules
41
+ jest.resetModules();
42
+
43
+ // Mock process.exit to prevent actual exit
44
+ process.exit = jest.fn();
45
+
46
+ // Mock process.cwd to return predictable path
47
+ process.cwd = jest.fn().mockReturnValue('/mock/cwd');
48
+
49
+ // Reset console mocks
50
+ global.console.log.mockClear();
51
+ global.console.info.mockClear();
52
+ global.console.warn.mockClear();
53
+ global.console.error.mockClear();
54
+ global.console.debug.mockClear();
55
+ });
56
+
57
+ // Global cleanup after each test
58
+ afterEach(() => {
59
+ // Restore environment
60
+ process.env = { ...originalEnv };
61
+
62
+ // Restore process methods
63
+ process.exit = originalProcessExit;
64
+ process.cwd = originalProcessCwd;
65
+
66
+ // Clear any remaining timers
67
+ jest.clearAllTimers();
68
+
69
+ // Unmock all modules
70
+ jest.restoreAllMocks();
71
+ });
72
+
73
+ // Global teardown after all tests
74
+ afterAll(() => {
75
+ // Restore original environment completely
76
+ process.env = originalEnv;
77
+
78
+ // Restore original console
79
+ global.console = originalConsole;
80
+
81
+ // Restore original process methods
82
+ process.exit = originalProcessExit;
83
+ process.cwd = originalProcessCwd;
84
+ });
85
+
86
+ // Custom matchers for CLI testing
87
+ expect.extend({
88
+ toBeValidExitCode(received) {
89
+ const validCodes = [0, 1, 2];
90
+ const pass = validCodes.includes(received);
91
+
92
+ if (pass) {
93
+ return {
94
+ message: () => `expected ${received} not to be a valid exit code`,
95
+ pass: true
96
+ };
97
+ } else {
98
+ return {
99
+ message: () => `expected ${received} to be a valid exit code (0, 1, or 2)`,
100
+ pass: false
101
+ };
102
+ }
103
+ },
104
+
105
+ toHaveLoggedError(received, expected) {
106
+ const errorLogs = global.console.error.mock.calls;
107
+ const pass = errorLogs.some(call =>
108
+ call.some(arg =>
109
+ typeof arg === 'string' && arg.includes(expected)
110
+ )
111
+ );
112
+
113
+ if (pass) {
114
+ return {
115
+ message: () => `expected not to have logged error containing "${expected}"`,
116
+ pass: true
117
+ };
118
+ } else {
119
+ return {
120
+ message: () => `expected to have logged error containing "${expected}"`,
121
+ pass: false
122
+ };
123
+ }
124
+ },
125
+
126
+ toHaveLoggedInfo(received, expected) {
127
+ const infoLogs = global.console.info.mock.calls;
128
+ const pass = infoLogs.some(call =>
129
+ call.some(arg =>
130
+ typeof arg === 'string' && arg.includes(expected)
131
+ )
132
+ );
133
+
134
+ if (pass) {
135
+ return {
136
+ message: () => `expected not to have logged info containing "${expected}"`,
137
+ pass: true
138
+ };
139
+ } else {
140
+ return {
141
+ message: () => `expected to have logged info containing "${expected}"`,
142
+ pass: false
143
+ };
144
+ }
145
+ },
146
+
147
+ toBeWithinTimeLimit(received, limit) {
148
+ const pass = received <= limit;
149
+
150
+ if (pass) {
151
+ return {
152
+ message: () => `expected ${received}ms not to be within ${limit}ms`,
153
+ pass: true
154
+ };
155
+ } else {
156
+ return {
157
+ message: () => `expected ${received}ms to be within ${limit}ms`,
158
+ pass: false
159
+ };
160
+ }
161
+ }
162
+ });
163
+
164
+ // Helper functions available in all tests
165
+ global.TestHelpers = {
166
+ /**
167
+ * Create a temporary directory for tests
168
+ */
169
+ createTempDir() {
170
+ const fs = require('fs');
171
+ const path = require('path');
172
+ const os = require('os');
173
+
174
+ return fs.mkdtempSync(path.join(os.tmpdir(), 'frigg-cli-test-'));
175
+ },
176
+
177
+ /**
178
+ * Clean up temporary directory
179
+ */
180
+ cleanupTempDir(dirPath) {
181
+ const fs = require('fs');
182
+
183
+ if (fs.existsSync(dirPath)) {
184
+ fs.rmSync(dirPath, { recursive: true, force: true });
185
+ }
186
+ },
187
+
188
+ /**
189
+ * Create a mock package.json file
190
+ */
191
+ createMockPackageJson(overrides = {}) {
192
+ return JSON.stringify({
193
+ name: 'test-package',
194
+ version: '1.0.0',
195
+ main: 'index.js',
196
+ scripts: {
197
+ test: 'jest',
198
+ start: 'node index.js'
199
+ },
200
+ dependencies: {},
201
+ devDependencies: {},
202
+ ...overrides
203
+ }, null, 2);
204
+ },
205
+
206
+ /**
207
+ * Create a mock frigg.config.json file
208
+ */
209
+ createMockFriggConfig(overrides = {}) {
210
+ return JSON.stringify({
211
+ stage: 'dev',
212
+ region: 'us-east-1',
213
+ profile: 'default',
214
+ backend: {
215
+ runtime: 'nodejs18.x',
216
+ timeout: 30,
217
+ memory: 128
218
+ },
219
+ ...overrides
220
+ }, null, 2);
221
+ },
222
+
223
+ /**
224
+ * Wait for a specific amount of time
225
+ */
226
+ async delay(ms) {
227
+ return new Promise(resolve => setTimeout(resolve, ms));
228
+ },
229
+
230
+ /**
231
+ * Generate a random string for test data
232
+ */
233
+ randomString(length = 10) {
234
+ return Math.random().toString(36).substring(2, length + 2);
235
+ },
236
+
237
+ /**
238
+ * Simulate file system structure
239
+ */
240
+ mockFileSystem(structure) {
241
+ const fs = require('fs');
242
+
243
+ const originalExistsSync = fs.existsSync;
244
+ const originalReadFileSync = fs.readFileSync;
245
+ const originalWriteFileSync = fs.writeFileSync;
246
+
247
+ fs.existsSync = jest.fn((path) => {
248
+ return structure.hasOwnProperty(path);
249
+ });
250
+
251
+ fs.readFileSync = jest.fn((path) => {
252
+ if (structure.hasOwnProperty(path)) {
253
+ return structure[path];
254
+ }
255
+ throw new Error(`ENOENT: no such file or directory, open '${path}'`);
256
+ });
257
+
258
+ fs.writeFileSync = jest.fn((path, data) => {
259
+ structure[path] = data;
260
+ });
261
+
262
+ return {
263
+ restore() {
264
+ fs.existsSync = originalExistsSync;
265
+ fs.readFileSync = originalReadFileSync;
266
+ fs.writeFileSync = originalWriteFileSync;
267
+ }
268
+ };
269
+ }
270
+ };
271
+
272
+ // Global timeout for all tests
273
+ jest.setTimeout(30000);
274
+
275
+ // Suppress specific warnings during tests
276
+ // Note: console.warn is already mocked above, so we keep the mock
277
+ // and just suppress certain warnings in the implementation
278
+ const originalWarnMock = global.console.warn;
279
+ global.console.warn = jest.fn((...args) => {
280
+ // Suppress specific warnings that are expected during testing
281
+ const message = args.join(' ');
282
+ if (message.includes('ExperimentalWarning') ||
283
+ message.includes('DeprecationWarning')) {
284
+ return;
285
+ }
286
+ // Still track the call in the mock
287
+ });
@@ -0,0 +1,293 @@
1
+ # CLAUDE.md - Frigg Authenticator
2
+
3
+ This file provides guidance to Claude Code when working with the Frigg Authenticator tool.
4
+
5
+ ## Overview
6
+
7
+ The Frigg Authenticator is a CLI tool for testing API module authentication flows. It's part of `@friggframework/devtools` and enables developers to validate OAuth2 and API-Key authentication without deploying full Frigg infrastructure.
8
+
9
+ ## Directory Structure
10
+
11
+ ```
12
+ auth-command/
13
+ ├── index.js # Main CLI command handler (test, list, get, delete)
14
+ ├── module-loader.js # Dynamic module loading & validation
15
+ ├── credential-storage.js # .frigg-credentials.json persistence
16
+ ├── oauth-callback-server.js # Local HTTP server for OAuth callbacks
17
+ ├── oauth-flow.js # OAuth2 flow orchestration
18
+ ├── api-key-flow.js # API-Key authentication flow
19
+ ├── json-schema-form.js # Interactive JSON Schema form renderer (CLI prompts)
20
+ ├── auth-tester.js # Run testAuthRequest & sample API calls
21
+ ├── utils/
22
+ │ └── browser.js # Cross-platform browser opening
23
+ ├── README.md # User documentation
24
+ └── CLAUDE.md # This file - AI assistant guidance
25
+ ```
26
+
27
+ ## Key Files and Their Purpose
28
+
29
+ ### `index.js` - Command Handler
30
+ Main entry point that exports `authCommand` object with methods:
31
+ - `test(moduleName, options)` - Test authentication for a module
32
+ - `list(options)` - List saved credentials
33
+ - `get(moduleName, options)` - Retrieve credentials
34
+ - `delete(moduleName, options)` - Remove credentials
35
+
36
+ **When to modify:** Adding new subcommands or changing command behavior.
37
+
38
+ ### `module-loader.js` - Module Loading
39
+ Handles dynamic loading of API modules from various sources:
40
+ - Current directory (`.`)
41
+ - Relative/absolute paths (`./path/to/module`)
42
+ - Short names (`attio` → `@friggframework/api-module-attio`)
43
+ - Full package names (`@friggframework/api-module-attio`)
44
+
45
+ **Key functions:**
46
+ - `loadModule(moduleIdentifier)` - Load and return `{definition, Api, modulePath}`
47
+ - `validateModule(definition)` - Ensure module has required fields
48
+ - `getAuthType(Api)` - Detect auth type (oauth2 or apiKey)
49
+
50
+ **When to modify:** Supporting new module locations or validation rules.
51
+
52
+ ### `credential-storage.js` - Persistence
53
+ Manages `.frigg-credentials.json` file:
54
+ - Stores credentials per module
55
+ - Supports global (`~/.frigg-credentials.json`) and local storage
56
+ - Auto-adds to `.gitignore`
57
+
58
+ **Key class:** `CredentialStorage`
59
+ - `save(moduleName, credentials, authType)`
60
+ - `get(moduleName)`
61
+ - `list()`
62
+ - `delete(moduleName)`
63
+ - `deleteAll()`
64
+
65
+ **When to modify:** Changing storage format or location logic.
66
+
67
+ ### `oauth-callback-server.js` - OAuth Server
68
+ Local HTTP server that captures OAuth callbacks:
69
+ - Listens on configurable port (default: 3333)
70
+ - Handles `?code=` and `?error=` query params
71
+ - Returns success/error HTML pages
72
+ - Implements timeout handling
73
+
74
+ **Key class:** `OAuthCallbackServer`
75
+ - `start()` - Start the server
76
+ - `waitForCode()` - Promise that resolves with `{code, state}`
77
+ - `stop()` - Shutdown the server
78
+
79
+ **When to modify:** Changing callback behavior or HTML responses.
80
+
81
+ ### `oauth-flow.js` - OAuth2 Orchestration
82
+ Orchestrates the complete OAuth2 flow:
83
+ 1. Generate CSRF state token
84
+ 2. Create API instance with env params
85
+ 3. Get authorization URL
86
+ 4. Start callback server
87
+ 5. Open browser or print URL
88
+ 6. Wait for callback
89
+ 7. Verify state (CSRF protection)
90
+ 8. Exchange code for tokens via `getToken()`
91
+ 9. Fetch entity details via `getEntityDetails()`
92
+ 10. Return credentials object
93
+
94
+ **Key function:** `runOAuthFlow(definition, ApiClass, options)`
95
+
96
+ **When to modify:** Changing OAuth flow steps or adding features.
97
+
98
+ ### `api-key-flow.js` - API-Key Flow
99
+ Handles API-Key authentication:
100
+ 1. Check for `getAuthorizationRequirements` in module definition
101
+ 2. If no API key provided and `getAuthorizationRequirements` exists, render JSON Schema form
102
+ 3. Create API instance
103
+ 4. Set API key via `setApiKey()` or similar
104
+ 5. Fetch entity details
105
+ 6. Return credentials object
106
+
107
+ **Key function:** `runApiKeyFlow(definition, ApiClass, apiKey, options)`
108
+
109
+ **When to modify:** Supporting different API key mechanisms or form rendering.
110
+
111
+ ### `json-schema-form.js` - Interactive Form Renderer
112
+ Renders JSON Schema as interactive CLI prompts using `@inquirer/prompts`:
113
+ 1. Display form title from `jsonSchema.title`
114
+ 2. Iterate through `jsonSchema.properties`
115
+ 3. Show help text from `uiSchema[field]['ui:help']`
116
+ 4. Use password prompt for `ui:widget: 'password'` fields
117
+ 5. Validate required fields
118
+ 6. Return collected form data
119
+
120
+ **Key function:** `renderJsonSchemaForm(jsonSchema, uiSchema)`
121
+
122
+ **When to modify:** Adding new field types or UI schema options.
123
+
124
+ **Example output:**
125
+ ```
126
+ 📝 Quo API Authorization
127
+
128
+ (Your Quo API key)
129
+ API Key: ********************************
130
+ ```
131
+
132
+ ### `auth-tester.js` - Verification
133
+ Runs verification tests after authentication:
134
+ 1. Create fresh API instance with credentials
135
+ 2. Run `testAuthRequest` from module definition
136
+ 3. Try common sample API methods
137
+ 4. Verify credential properties are set
138
+
139
+ **Key function:** `runAuthTests(definition, ApiClass, credentials, options)`
140
+
141
+ **When to modify:** Adding verification steps or sample methods.
142
+
143
+ ### `utils/browser.js` - Browser Opening
144
+ Cross-platform browser opening utility:
145
+ - macOS: `open`
146
+ - Windows: `start`
147
+ - Linux: `xdg-open`
148
+
149
+ **Key function:** `openBrowser(url)`
150
+
151
+ ## Integration with Frigg CLI
152
+
153
+ The authenticator is registered in `frigg-cli/index.js`:
154
+
155
+ ```javascript
156
+ const { authCommand } = require('./auth-command');
157
+
158
+ const authProgram = program
159
+ .command('auth')
160
+ .description('Test API module authentication');
161
+
162
+ authProgram
163
+ .command('test <module>')
164
+ .action(authCommand.test);
165
+ // ... more subcommands
166
+ ```
167
+
168
+ ## Common Development Tasks
169
+
170
+ ### Adding a New Subcommand
171
+
172
+ 1. Add handler method in `auth-command/index.js`
173
+ 2. Register in `frigg-cli/index.js` under `authProgram`
174
+ 3. Update README.md with usage docs
175
+
176
+ ### Supporting a New Auth Type
177
+
178
+ 1. Create new flow file (e.g., `basic-auth-flow.js`)
179
+ 2. Update `getAuthType()` in `module-loader.js`
180
+ 3. Add case in `test()` handler in `index.js`
181
+
182
+ ### Changing Credential Format
183
+
184
+ 1. Update `save()` and `get()` in `credential-storage.js`
185
+ 2. Consider migration for existing credentials
186
+ 3. Update `_meta.version` for format versioning
187
+
188
+ ### Adding Verification Steps
189
+
190
+ 1. Modify `runAuthTests()` in `auth-tester.js`
191
+ 2. Add new sample methods to check
192
+ 3. Update verbose output
193
+
194
+ ## Testing
195
+
196
+ ### Manual Testing
197
+
198
+ ```bash
199
+ # Test with a real module
200
+ cd /path/to/api-module-attio
201
+ export ATTIO_CLIENT_ID=xxx
202
+ export ATTIO_CLIENT_SECRET=xxx
203
+ export ATTIO_SCOPE="read:objects"
204
+ export REDIRECT_URI="http://localhost:3333"
205
+ node /path/to/frigg-cli/index.js auth test . --verbose
206
+ ```
207
+
208
+ ### Unit Testing
209
+
210
+ Tests should be added to `frigg-cli/test/auth-command.test.js`:
211
+ - Test module loading with various paths
212
+ - Test credential storage operations
213
+ - Mock OAuth callback server responses
214
+ - Test error handling
215
+
216
+ ## Error Handling Patterns
217
+
218
+ ### User-Friendly Errors
219
+
220
+ ```javascript
221
+ throw new Error(
222
+ `Port ${port} is already in use.\n` +
223
+ `Try using a different port: frigg auth test <module> --port <different-port>`
224
+ );
225
+ ```
226
+
227
+ ### Validation Errors
228
+
229
+ ```javascript
230
+ const errors = [];
231
+ if (!definition.moduleName) {
232
+ errors.push('Missing required field: moduleName');
233
+ }
234
+ if (errors.length > 0) {
235
+ throw new Error(`Module validation failed:\n${errors.map(e => ` - ${e}`).join('\n')}`);
236
+ }
237
+ ```
238
+
239
+ ## Dependencies
240
+
241
+ External packages used:
242
+ - `chalk` - Terminal colors
243
+ - `commander` - CLI framework (via parent)
244
+ - `@inquirer/prompts` - Interactive CLI prompts (input, password)
245
+
246
+ Node.js built-ins:
247
+ - `http` - Callback server
248
+ - `url` - URL parsing
249
+ - `fs` - File system
250
+ - `path` - Path utilities
251
+ - `os` - OS info
252
+ - `crypto` - State token generation
253
+ - `child_process` - Browser opening
254
+ - `readline` - User confirmation
255
+
256
+ ## Security Considerations
257
+
258
+ 1. **State Parameter**: CSRF protection via random state token
259
+ 2. **Local Only**: Callback server only binds to localhost
260
+ 3. **No Credential Logging**: Sensitive values are masked in output
261
+ 4. **Gitignore Integration**: Auto-adds credentials file to .gitignore
262
+ 5. **Sanitization**: Client secrets removed from stored apiParams
263
+
264
+ ## Common Issues
265
+
266
+ ### Module Not Loading
267
+
268
+ Check:
269
+ - Module exports `{Definition}` or `{definition}`
270
+ - Definition has `API` class
271
+ - `require('dotenv').config()` is called in definition.js
272
+
273
+ ### OAuth Flow Failing
274
+
275
+ Check:
276
+ - Environment variables are set correctly
277
+ - Redirect URI matches callback server port
278
+ - OAuth credentials are valid
279
+ - Scopes are correct
280
+
281
+ ### Credentials Not Persisting
282
+
283
+ Check:
284
+ - Write permissions on target directory
285
+ - File isn't gitignored in a way that prevents reading
286
+ - Storage path detection is correct
287
+
288
+ ## Related Documentation
289
+
290
+ - [Frigg Framework CLAUDE.md](../../CLAUDE.md)
291
+ - [API Module Library](https://github.com/friggframework/api-module-library)
292
+ - [OAuth2Requester](../../../core/modules/requester/oauth-2.js)
293
+ - [ApiKeyRequester](../../../core/modules/requester/ApiKeyRequester.js)