@friggframework/devtools 2.0.0--canary.482.6216503.0 → 2.0.0--canary.482.fcb9803.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,66 +1,146 @@
1
1
  const path = require('path');
2
2
  const fs = require('fs-extra');
3
+ const crypto = require('crypto');
3
4
  const { composeServerlessDefinition } = require('./infrastructure-composer');
4
5
  const { findNearestBackendPackageJson } = require('@friggframework/core');
5
6
 
6
- // Memoization cache to prevent duplicate infrastructure composition
7
- // when serverless framework loads configuration multiple times
8
- let cachedInfrastructure = null;
9
- let isComposing = false;
7
+ // Filesystem-based cache to persist across osls require cache clears
8
+ const getCachePath = (backendDir) => {
9
+ return path.join(backendDir, '.frigg-infrastructure-cache.json');
10
+ };
11
+
12
+ const getLockPath = (backendDir) => {
13
+ return path.join(backendDir, '.frigg-infrastructure-lock');
14
+ };
15
+
16
+ // Check if process is still running
17
+ function isProcessRunning(pid) {
18
+ try {
19
+ process.kill(pid, 0);
20
+ return true;
21
+ } catch (error) {
22
+ return false;
23
+ }
24
+ }
10
25
 
11
26
  async function createFriggInfrastructure() {
12
- // Return cached infrastructure if already composed
13
- if (cachedInfrastructure) {
14
- console.log(' Using cached infrastructure definition (already composed)');
15
- return cachedInfrastructure;
27
+ const backendPath = findNearestBackendPackageJson();
28
+ if (!backendPath) {
29
+ throw new Error('Could not find backend package.json');
16
30
  }
17
31
 
18
- // Wait if another call is currently composing
19
- if (isComposing) {
20
- console.log('⏳ Infrastructure composition in progress - waiting...');
21
- // Poll every 100ms until composition completes
22
- while (isComposing) {
23
- await new Promise(resolve => setTimeout(resolve, 100));
24
- }
25
- // Return the newly cached infrastructure
26
- return cachedInfrastructure;
32
+ const backendDir = path.dirname(backendPath);
33
+ const backendFilePath = path.join(backendDir, 'index.js');
34
+ if (!fs.existsSync(backendFilePath)) {
35
+ throw new Error('Could not find index.js');
27
36
  }
28
37
 
29
- // Mark as composing to prevent concurrent composition
30
- isComposing = true;
38
+ const cachePath = getCachePath(backendDir);
39
+ const lockPath = getLockPath(backendDir);
31
40
 
32
- try {
33
- const backendPath = findNearestBackendPackageJson();
34
- if (!backendPath) {
35
- throw new Error('Could not find backend package.json');
41
+ // Check for cached infrastructure (filesystem-based for osls require cache clearing)
42
+ if (fs.existsSync(cachePath)) {
43
+ try {
44
+ const cached = JSON.parse(fs.readFileSync(cachePath, 'utf-8'));
45
+ // Verify cache is still valid (less than 60 seconds old)
46
+ if (Date.now() - cached.timestamp < 60000) {
47
+ console.log('✓ Using filesystem-cached infrastructure definition');
48
+ return cached.definition;
49
+ } else {
50
+ console.log('⚠️ Cache expired (> 60s), recomposing...');
51
+ fs.removeSync(cachePath);
52
+ }
53
+ } catch (error) {
54
+ console.log('⚠️ Invalid cache file, recomposing...', error.message);
55
+ fs.removeSync(cachePath);
36
56
  }
57
+ }
58
+
59
+ // Check for active composition process
60
+ if (fs.existsSync(lockPath)) {
61
+ const lockPid = parseInt(fs.readFileSync(lockPath, 'utf-8').trim(), 10);
62
+
63
+ if (isProcessRunning(lockPid)) {
64
+ console.log(`⏳ Another composition (PID ${lockPid}) in progress - waiting...`);
65
+
66
+ // Wait up to 30 seconds for the other process to complete
67
+ for (let i = 0; i < 30; i++) {
68
+ await new Promise(resolve => setTimeout(resolve, 1000));
37
69
 
38
- const backendDir = path.dirname(backendPath);
39
- const backendFilePath = path.join(backendDir, 'index.js');
40
- if (!fs.existsSync(backendFilePath)) {
41
- throw new Error('Could not find index.js');
70
+ // Check if cache was created by other process
71
+ if (fs.existsSync(cachePath)) {
72
+ try {
73
+ const cached = JSON.parse(fs.readFileSync(cachePath, 'utf-8'));
74
+ console.log('✓ Using infrastructure composed by concurrent process');
75
+ return cached.definition;
76
+ } catch (error) {
77
+ // Cache file corrupted, continue to compose ourselves
78
+ break;
79
+ }
80
+ }
81
+
82
+ // Check if process died
83
+ if (!isProcessRunning(lockPid)) {
84
+ console.log(`⚠ Composition process ${lockPid} terminated - cleaning up stale lock`);
85
+ fs.removeSync(lockPath);
86
+ break;
87
+ }
88
+ }
89
+ } else {
90
+ // Stale lock file
91
+ console.log(`⚠️ Stale lock file detected (PID ${lockPid} not running) - cleaning up`);
92
+ fs.removeSync(lockPath);
42
93
  }
94
+ }
95
+
96
+ // Create lock file with current process PID
97
+ try {
98
+ fs.writeFileSync(lockPath, process.pid.toString());
99
+ } catch (error) {
100
+ console.warn('⚠ Could not create lock file:', error.message);
101
+ }
43
102
 
103
+ try {
44
104
  const backend = require(backendFilePath);
45
105
  const appDefinition = backend.Definition;
46
106
 
47
- // const serverlessTemplate = require(path.resolve(
48
- // __dirname,
49
- // './serverless-template.js'
50
- // ));
51
107
  const definition = await composeServerlessDefinition(
52
108
  appDefinition,
53
109
  );
54
110
 
55
- // Cache the composed infrastructure
56
- cachedInfrastructure = {
57
- ...definition,
58
- };
111
+ // Write cache to filesystem (persists across osls require cache clears)
112
+ try {
113
+ fs.writeFileSync(cachePath, JSON.stringify({
114
+ timestamp: Date.now(),
115
+ definition
116
+ }));
117
+ console.log('✓ Infrastructure definition cached to filesystem');
118
+ } catch (error) {
119
+ console.warn('⚠ Could not write cache file:', error.message);
120
+ }
59
121
 
60
- return cachedInfrastructure;
122
+ return definition;
123
+ } catch (error) {
124
+ // Clean up partial cache on error
125
+ if (fs.existsSync(cachePath)) {
126
+ try {
127
+ fs.removeSync(cachePath);
128
+ } catch (cleanupError) {
129
+ console.warn('⚠ Could not clean failed cache:', cleanupError.message);
130
+ }
131
+ }
132
+
133
+ console.error('✗ Failed to compose infrastructure:', error.message);
134
+ throw error;
61
135
  } finally {
62
- // Always clear composing flag
63
- isComposing = false;
136
+ // Always remove lock file when done (success or failure)
137
+ if (fs.existsSync(lockPath)) {
138
+ try {
139
+ fs.removeSync(lockPath);
140
+ } catch (error) {
141
+ console.warn('⚠ Could not remove lock file:', error.message);
142
+ }
143
+ }
64
144
  }
65
145
  }
66
146
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@friggframework/devtools",
3
3
  "prettier": "@friggframework/prettier-config",
4
- "version": "2.0.0--canary.482.6216503.0",
4
+ "version": "2.0.0--canary.482.fcb9803.0",
5
5
  "dependencies": {
6
6
  "@aws-sdk/client-ec2": "^3.835.0",
7
7
  "@aws-sdk/client-kms": "^3.835.0",
@@ -12,8 +12,8 @@
12
12
  "@babel/eslint-parser": "^7.18.9",
13
13
  "@babel/parser": "^7.25.3",
14
14
  "@babel/traverse": "^7.25.3",
15
- "@friggframework/schemas": "2.0.0--canary.482.6216503.0",
16
- "@friggframework/test": "2.0.0--canary.482.6216503.0",
15
+ "@friggframework/schemas": "2.0.0--canary.482.fcb9803.0",
16
+ "@friggframework/test": "2.0.0--canary.482.fcb9803.0",
17
17
  "@hapi/boom": "^10.0.1",
18
18
  "@inquirer/prompts": "^5.3.8",
19
19
  "axios": "^1.7.2",
@@ -35,8 +35,8 @@
35
35
  "serverless-http": "^2.7.0"
36
36
  },
37
37
  "devDependencies": {
38
- "@friggframework/eslint-config": "2.0.0--canary.482.6216503.0",
39
- "@friggframework/prettier-config": "2.0.0--canary.482.6216503.0",
38
+ "@friggframework/eslint-config": "2.0.0--canary.482.fcb9803.0",
39
+ "@friggframework/prettier-config": "2.0.0--canary.482.fcb9803.0",
40
40
  "aws-sdk-client-mock": "^4.1.0",
41
41
  "aws-sdk-client-mock-jest": "^4.1.0",
42
42
  "jest": "^30.1.3",
@@ -68,5 +68,5 @@
68
68
  "publishConfig": {
69
69
  "access": "public"
70
70
  },
71
- "gitHead": "6216503a031bf84cdd718845e8116fb13cda1533"
71
+ "gitHead": "fcb98034ee94170352938e83dd718b0e93dbf6e3"
72
72
  }