@geek-fun/serverlessinsight 0.6.12 → 0.6.14
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/dist/package.json +1 -1
- package/dist/src/common/hashUtils.js +28 -7
- package/dist/src/stack/aliyunStack/fc3Planner.js +39 -5
- package/dist/src/stack/aliyunStack/fc3Resource.js +2 -0
- package/dist/src/stack/aliyunStack/ossPlanner.js +33 -7
- package/dist/src/stack/aliyunStack/ossResource.js +9 -3
- package/dist/src/stack/aliyunStack/ossTypes.js +2 -1
- package/package.json +1 -1
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geek-fun/serverlessinsight",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.14",
|
|
4
4
|
"description": "Full life cycle cross providers serverless application management for your fast-growing business.",
|
|
5
5
|
"homepage": "https://serverlessinsight.geekfun.club",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -3,20 +3,41 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.diffAttributes = exports.attributesEqual = exports.computeFileHash = void 0;
|
|
6
|
+
exports.diffAttributes = exports.attributesEqual = exports.computeDirectoryHash = exports.computeFileHash = void 0;
|
|
7
7
|
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
8
8
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
|
-
|
|
10
|
-
* Compute SHA-256 hash of a file.
|
|
11
|
-
* Used for tracking external artifacts like function code zip files.
|
|
12
|
-
* @param filePath - Path to the file to hash
|
|
13
|
-
* @returns Hex-encoded SHA-256 hash of the file contents
|
|
14
|
-
*/
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
15
10
|
const computeFileHash = (filePath) => {
|
|
16
11
|
const fileBuffer = node_fs_1.default.readFileSync(filePath);
|
|
17
12
|
return node_crypto_1.default.createHash('sha256').update(fileBuffer).digest('hex');
|
|
18
13
|
};
|
|
19
14
|
exports.computeFileHash = computeFileHash;
|
|
15
|
+
const computeDirectoryHash = (dirPath) => {
|
|
16
|
+
const files = [];
|
|
17
|
+
const collectFiles = (currentPath) => {
|
|
18
|
+
const entries = node_fs_1.default.readdirSync(currentPath, { withFileTypes: true });
|
|
19
|
+
for (const entry of entries) {
|
|
20
|
+
const fullPath = node_path_1.default.join(currentPath, entry.name);
|
|
21
|
+
if (entry.isDirectory()) {
|
|
22
|
+
collectFiles(fullPath);
|
|
23
|
+
}
|
|
24
|
+
else if (entry.isFile()) {
|
|
25
|
+
files.push(fullPath);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
collectFiles(dirPath);
|
|
30
|
+
files.sort();
|
|
31
|
+
const hash = node_crypto_1.default.createHash('sha256');
|
|
32
|
+
for (const file of files) {
|
|
33
|
+
const relativePath = node_path_1.default.relative(dirPath, file).split(node_path_1.default.sep).join('/');
|
|
34
|
+
hash.update(relativePath);
|
|
35
|
+
const content = node_fs_1.default.readFileSync(file);
|
|
36
|
+
hash.update(content);
|
|
37
|
+
}
|
|
38
|
+
return hash.digest('hex');
|
|
39
|
+
};
|
|
40
|
+
exports.computeDirectoryHash = computeDirectoryHash;
|
|
20
41
|
/**
|
|
21
42
|
* Deep equality comparison for two values.
|
|
22
43
|
* Handles primitives, objects, arrays, null, and undefined.
|
|
@@ -5,6 +5,32 @@ const common_1 = require("../../common");
|
|
|
5
5
|
const aliyunClient_1 = require("../../common/aliyunClient");
|
|
6
6
|
const fc3Types_1 = require("./fc3Types");
|
|
7
7
|
const lang_1 = require("../../lang");
|
|
8
|
+
/**
|
|
9
|
+
* Provider-managed logConfig fields that are set by the system after creation.
|
|
10
|
+
* These should not be compared when detecting changes.
|
|
11
|
+
*/
|
|
12
|
+
const PROVIDER_MANAGED_LOG_CONFIG_FIELDS = ['project', 'logstore', 'logBeginRule'];
|
|
13
|
+
/**
|
|
14
|
+
* Normalize definition for comparison by excluding provider-managed fields.
|
|
15
|
+
* This prevents false-positive change detection when the system populates
|
|
16
|
+
* fields like logConfig.project and logConfig.logstore after creation.
|
|
17
|
+
*/
|
|
18
|
+
const normalizeDefinitionForComparison = (definition) => {
|
|
19
|
+
const { logConfig, ...rest } = definition;
|
|
20
|
+
if (!logConfig || typeof logConfig !== 'object') {
|
|
21
|
+
return definition;
|
|
22
|
+
}
|
|
23
|
+
const normalizedLogConfig = {};
|
|
24
|
+
for (const [key, value] of Object.entries(logConfig)) {
|
|
25
|
+
if (!PROVIDER_MANAGED_LOG_CONFIG_FIELDS.includes(key)) {
|
|
26
|
+
normalizedLogConfig[key] = value;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
...rest,
|
|
31
|
+
logConfig: Object.keys(normalizedLogConfig).length > 0 ? normalizedLogConfig : null,
|
|
32
|
+
};
|
|
33
|
+
};
|
|
8
34
|
const isSecurityGroupId = (value) => value.startsWith('sg-');
|
|
9
35
|
const resolveSecurityGroupId = async (context, securityGroupName, vpcId) => {
|
|
10
36
|
if (isSecurityGroupId(securityGroupName)) {
|
|
@@ -34,7 +60,7 @@ const planFunctionDeletion = (logicalId, definition) => ({
|
|
|
34
60
|
logicalId,
|
|
35
61
|
action: 'delete',
|
|
36
62
|
resourceType: 'ALIYUN_FC3',
|
|
37
|
-
changes: { before: definition },
|
|
63
|
+
changes: { before: normalizeDefinitionForComparison(definition) },
|
|
38
64
|
});
|
|
39
65
|
const generateFunctionPlan = async (context, state, functions) => {
|
|
40
66
|
if (!functions || functions.length === 0) {
|
|
@@ -69,18 +95,23 @@ const generateFunctionPlan = async (context, state, functions) => {
|
|
|
69
95
|
logicalId,
|
|
70
96
|
action: 'create',
|
|
71
97
|
resourceType: 'ALIYUN_FC3',
|
|
72
|
-
changes: {
|
|
98
|
+
changes: {
|
|
99
|
+
before: normalizeDefinitionForComparison(currentState.definition),
|
|
100
|
+
after: normalizeDefinitionForComparison(desiredDefinition),
|
|
101
|
+
},
|
|
73
102
|
drifted: true,
|
|
74
103
|
};
|
|
75
104
|
}
|
|
76
105
|
const currentDefinition = currentState.definition || {};
|
|
77
|
-
const
|
|
106
|
+
const normalizedCurrent = normalizeDefinitionForComparison(currentDefinition);
|
|
107
|
+
const normalizedDesired = normalizeDefinitionForComparison(desiredDefinition);
|
|
108
|
+
const definitionChanged = !(0, common_1.attributesEqual)(normalizedCurrent, normalizedDesired);
|
|
78
109
|
if (definitionChanged) {
|
|
79
110
|
return {
|
|
80
111
|
logicalId,
|
|
81
112
|
action: 'update',
|
|
82
113
|
resourceType: 'ALIYUN_FC3',
|
|
83
|
-
changes: { before:
|
|
114
|
+
changes: { before: normalizedCurrent, after: normalizedDesired },
|
|
84
115
|
drifted: true,
|
|
85
116
|
};
|
|
86
117
|
}
|
|
@@ -91,7 +122,10 @@ const generateFunctionPlan = async (context, state, functions) => {
|
|
|
91
122
|
logicalId,
|
|
92
123
|
action: 'create',
|
|
93
124
|
resourceType: 'ALIYUN_FC3',
|
|
94
|
-
changes: {
|
|
125
|
+
changes: {
|
|
126
|
+
before: normalizeDefinitionForComparison(currentState.definition),
|
|
127
|
+
after: normalizeDefinitionForComparison(desiredDefinition),
|
|
128
|
+
},
|
|
95
129
|
};
|
|
96
130
|
}
|
|
97
131
|
}));
|
|
@@ -358,6 +358,7 @@ const createResource = async (context, fn, state) => {
|
|
|
358
358
|
project: dependentResources.logConfig.project,
|
|
359
359
|
logstore: dependentResources.logConfig.logstore,
|
|
360
360
|
enableRequestMetrics: true,
|
|
361
|
+
enableInstanceMetrics: true,
|
|
361
362
|
},
|
|
362
363
|
};
|
|
363
364
|
}
|
|
@@ -547,6 +548,7 @@ const updateResource = async (context, fn, state) => {
|
|
|
547
548
|
project: logConfig.project,
|
|
548
549
|
logstore: logConfig.logstore,
|
|
549
550
|
enableRequestMetrics: true,
|
|
551
|
+
enableInstanceMetrics: true,
|
|
550
552
|
},
|
|
551
553
|
};
|
|
552
554
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.generateBucketPlan = void 0;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
4
8
|
const aliyunClient_1 = require("../../common/aliyunClient");
|
|
5
9
|
const ossTypes_1 = require("./ossTypes");
|
|
6
10
|
const stateManager_1 = require("../../common/stateManager");
|
|
@@ -9,8 +13,12 @@ const planBucketDeletion = (logicalId, definition) => ({
|
|
|
9
13
|
logicalId,
|
|
10
14
|
action: 'delete',
|
|
11
15
|
resourceType: 'ALIYUN_OSS_BUCKET',
|
|
12
|
-
changes: { before: definition },
|
|
16
|
+
changes: { before: normalizeDefinitionForDisplay(definition) },
|
|
13
17
|
});
|
|
18
|
+
const normalizeDefinitionForDisplay = (definition) => {
|
|
19
|
+
const { domainBound: _domainBound, ...rest } = definition;
|
|
20
|
+
return rest;
|
|
21
|
+
};
|
|
14
22
|
const generateBucketPlan = async (context, state, buckets) => {
|
|
15
23
|
if (!buckets || buckets.length === 0) {
|
|
16
24
|
const allStates = (0, stateManager_1.getAllResources)(state);
|
|
@@ -24,7 +32,17 @@ const generateBucketPlan = async (context, state, buckets) => {
|
|
|
24
32
|
const logicalId = `buckets.${bucket.key}`;
|
|
25
33
|
const currentState = (0, stateManager_1.getResource)(state, logicalId);
|
|
26
34
|
const config = (0, ossTypes_1.bucketToOssBucketConfig)(bucket);
|
|
27
|
-
const
|
|
35
|
+
const websiteCodeHash = (() => {
|
|
36
|
+
if (!bucket.website?.code)
|
|
37
|
+
return undefined;
|
|
38
|
+
try {
|
|
39
|
+
return (0, hashUtils_1.computeDirectoryHash)(node_path_1.default.resolve(process.cwd(), bucket.website.code));
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
})();
|
|
45
|
+
const desiredDefinition = (0, ossTypes_1.extractOssBucketDefinition)(config, websiteCodeHash);
|
|
28
46
|
if (!currentState) {
|
|
29
47
|
return {
|
|
30
48
|
logicalId,
|
|
@@ -41,20 +59,25 @@ const generateBucketPlan = async (context, state, buckets) => {
|
|
|
41
59
|
logicalId,
|
|
42
60
|
action: 'create',
|
|
43
61
|
resourceType: 'ALIYUN_OSS_BUCKET',
|
|
44
|
-
changes: {
|
|
62
|
+
changes: {
|
|
63
|
+
before: normalizeDefinitionForDisplay(currentState.definition),
|
|
64
|
+
after: desiredDefinition,
|
|
65
|
+
},
|
|
45
66
|
drifted: true,
|
|
46
67
|
};
|
|
47
68
|
}
|
|
48
69
|
const currentDefinition = currentState.definition || {};
|
|
49
|
-
const
|
|
50
|
-
const
|
|
70
|
+
const normalizedCurrent = normalizeDefinitionForDisplay(currentDefinition);
|
|
71
|
+
const normalizedDesired = normalizeDefinitionForDisplay(desiredDefinition);
|
|
72
|
+
const { domainBound } = currentDefinition;
|
|
73
|
+
const definitionChanged = !(0, hashUtils_1.attributesEqual)(normalizedCurrent, normalizedDesired);
|
|
51
74
|
const domainBindingPending = domainBound === false;
|
|
52
75
|
if (definitionChanged || domainBindingPending) {
|
|
53
76
|
return {
|
|
54
77
|
logicalId,
|
|
55
78
|
action: 'update',
|
|
56
79
|
resourceType: 'ALIYUN_OSS_BUCKET',
|
|
57
|
-
changes: { before:
|
|
80
|
+
changes: { before: normalizedCurrent, after: normalizedDesired },
|
|
58
81
|
...(definitionChanged ? { drifted: true } : {}),
|
|
59
82
|
};
|
|
60
83
|
}
|
|
@@ -65,7 +88,10 @@ const generateBucketPlan = async (context, state, buckets) => {
|
|
|
65
88
|
logicalId,
|
|
66
89
|
action: 'create',
|
|
67
90
|
resourceType: 'ALIYUN_OSS_BUCKET',
|
|
68
|
-
changes: {
|
|
91
|
+
changes: {
|
|
92
|
+
before: normalizeDefinitionForDisplay(currentState.definition),
|
|
93
|
+
after: desiredDefinition,
|
|
94
|
+
},
|
|
69
95
|
};
|
|
70
96
|
}
|
|
71
97
|
}));
|
|
@@ -136,11 +136,14 @@ const createBucketResource = async (context, bucket, state) => {
|
|
|
136
136
|
const sid = (0, common_1.buildSid)('aliyun', 'oss', context.stage, config.bucketName);
|
|
137
137
|
const logicalId = `buckets.${bucket.key}`;
|
|
138
138
|
const instances = [buildOssInstanceFromProvider(bucketInfo, sid)];
|
|
139
|
+
const websiteCodeHash = bucket.website?.code
|
|
140
|
+
? (0, common_1.computeDirectoryHash)(node_path_1.default.resolve(process.cwd(), bucket.website.code))
|
|
141
|
+
: undefined;
|
|
139
142
|
const partialResourceState = {
|
|
140
143
|
mode: 'managed',
|
|
141
144
|
region: context.region,
|
|
142
145
|
definition: {
|
|
143
|
-
...(0, ossTypes_1.extractOssBucketDefinition)(config),
|
|
146
|
+
...(0, ossTypes_1.extractOssBucketDefinition)(config, websiteCodeHash),
|
|
144
147
|
...(bucket.website?.domain != null ? { domainBound: null } : {}),
|
|
145
148
|
},
|
|
146
149
|
instances,
|
|
@@ -224,7 +227,7 @@ const createBucketResource = async (context, bucket, state) => {
|
|
|
224
227
|
mode: 'managed',
|
|
225
228
|
region: context.region,
|
|
226
229
|
definition: {
|
|
227
|
-
...(0, ossTypes_1.extractOssBucketDefinition)(config),
|
|
230
|
+
...(0, ossTypes_1.extractOssBucketDefinition)(config, websiteCodeHash),
|
|
228
231
|
...(bucket.website?.domain != null
|
|
229
232
|
? { domainBound: cnameInfo?.bucketCnameBound ?? null }
|
|
230
233
|
: {}),
|
|
@@ -260,6 +263,9 @@ const updateBucketResource = async (context, bucket, state) => {
|
|
|
260
263
|
const sid = (0, common_1.buildSid)('aliyun', 'oss', context.stage, config.bucketName);
|
|
261
264
|
const logicalId = `buckets.${bucket.key}`;
|
|
262
265
|
const instances = [buildOssInstanceFromProvider(bucketInfo, sid)];
|
|
266
|
+
const websiteCodeHash = bucket.website?.code
|
|
267
|
+
? (0, common_1.computeDirectoryHash)(node_path_1.default.resolve(process.cwd(), bucket.website.code))
|
|
268
|
+
: undefined;
|
|
263
269
|
const existingState = state.resources[logicalId];
|
|
264
270
|
const existingDnsInstances = existingState?.instances?.filter((i) => i.type === types_1.ResourceTypeEnum.ALIYUN_OSS_DNS_CNAME);
|
|
265
271
|
const existingPrimaryDnsInstance = existingDnsInstances?.find((i) => !i.isWwwVariant);
|
|
@@ -338,7 +344,7 @@ const updateBucketResource = async (context, bucket, state) => {
|
|
|
338
344
|
mode: 'managed',
|
|
339
345
|
region: context.region,
|
|
340
346
|
definition: {
|
|
341
|
-
...(0, ossTypes_1.extractOssBucketDefinition)(config),
|
|
347
|
+
...(0, ossTypes_1.extractOssBucketDefinition)(config, websiteCodeHash),
|
|
342
348
|
...(bucket.website?.domain != null
|
|
343
349
|
? { domainBound: cnameInfo?.bucketCnameBound ?? null }
|
|
344
350
|
: {}),
|
|
@@ -57,7 +57,7 @@ const bucketToOssBucketConfig = (bucket) => {
|
|
|
57
57
|
return config;
|
|
58
58
|
};
|
|
59
59
|
exports.bucketToOssBucketConfig = bucketToOssBucketConfig;
|
|
60
|
-
const extractOssBucketDefinition = (config) => {
|
|
60
|
+
const extractOssBucketDefinition = (config, websiteCodeHash) => {
|
|
61
61
|
return {
|
|
62
62
|
bucketName: config.bucketName,
|
|
63
63
|
acl: config.acl ?? null,
|
|
@@ -67,6 +67,7 @@ const extractOssBucketDefinition = (config) => {
|
|
|
67
67
|
errorDocument: config.websiteConfig.errorDocument ?? null,
|
|
68
68
|
}
|
|
69
69
|
: {},
|
|
70
|
+
websiteCodeHash: websiteCodeHash ?? null,
|
|
70
71
|
storageClass: config.storageClass ?? null,
|
|
71
72
|
domain: config.domain ?? null,
|
|
72
73
|
wwwBindApex: config.wwwBindApex ?? false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geek-fun/serverlessinsight",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.14",
|
|
4
4
|
"description": "Full life cycle cross providers serverless application management for your fast-growing business.",
|
|
5
5
|
"homepage": "https://serverlessinsight.geekfun.club",
|
|
6
6
|
"main": "dist/src/index.js",
|