@geek-fun/serverlessinsight 0.0.4 → 0.0.5

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geek-fun/serverlessinsight",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
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",
@@ -49,33 +49,34 @@
49
49
  "function"
50
50
  ],
51
51
  "dependencies": {
52
- "@alicloud/openapi-client": "^0.4.11",
53
- "@alicloud/ros-cdk-apigateway": "^1.2.0",
54
- "@alicloud/ros-cdk-core": "^1.2.0",
55
- "@alicloud/ros-cdk-fc": "^1.2.0",
56
- "@alicloud/ros-cdk-ram": "^1.2.0",
57
- "@alicloud/ros20190910": "^3.4.3",
52
+ "@alicloud/openapi-client": "^0.4.12",
53
+ "@alicloud/ros-cdk-apigateway": "^1.4.0",
54
+ "@alicloud/ros-cdk-core": "^1.4.0",
55
+ "@alicloud/ros-cdk-fc3": "^1.4.0",
56
+ "@alicloud/ros-cdk-ram": "^1.4.0",
57
+ "@alicloud/ros20190910": "^3.5.0",
58
58
  "ajv": "^8.17.1",
59
- "chalk": "^4.1.2",
60
- "commander": "^11.1.0",
59
+ "chalk": "^5.3.0",
60
+ "commander": "^12.1.0",
61
61
  "i18n": "^0.15.1",
62
- "pino": "^8.17.2",
62
+ "pino": "^9.4.0",
63
63
  "pino-pretty": "^11.2.2",
64
64
  "yaml": "^2.5.1"
65
65
  },
66
66
  "devDependencies": {
67
- "@types/i18n": "^0.13.10",
68
- "@types/jest": "^29.5.11",
69
- "@types/node": "^20.11.5",
70
- "@typescript-eslint/eslint-plugin": "^6.19.0",
71
- "@typescript-eslint/parser": "^6.19.0",
72
- "eslint": "^8.56.0",
67
+ "@types/i18n": "^0.13.12",
68
+ "@types/jest": "^29.5.13",
69
+ "@types/node": "^22.7.4",
70
+ "@typescript-eslint/eslint-plugin": "^8.8.0",
71
+ "@typescript-eslint/parser": "^8.8.0",
72
+ "eslint": "^8.57.1",
73
73
  "eslint-config-prettier": "^9.1.0",
74
- "eslint-plugin-prettier": "^5.1.3",
74
+ "eslint-plugin-prettier": "^5.2.1",
75
+ "globals": "^15.9.0",
75
76
  "husky": "^9.1.6",
76
77
  "jest": "^29.7.0",
77
- "prettier": "^3.2.4",
78
- "ts-jest": "^29.1.1",
78
+ "prettier": "^3.3.3",
79
+ "ts-jest": "^29.2.5",
79
80
  "ts-node": "^10.9.2",
80
81
  "typescript": "^5.6.2"
81
82
  }
@@ -31,6 +31,7 @@ const tea_util_1 = __importDefault(require("@alicloud/tea-util"));
31
31
  const ros20190910_1 = __importStar(require("@alicloud/ros20190910"));
32
32
  const openapi_client_1 = require("@alicloud/openapi-client");
33
33
  const logger_1 = require("./logger");
34
+ const lang_1 = require("../lang");
34
35
  const client = new ros20190910_1.default(new openapi_client_1.Config({
35
36
  accessKeyId: process.env.ALIYUN_ACCESS_KEY_ID,
36
37
  accessKeySecret: process.env.ALIYUN_ACCESS_KEY_SECRET,
@@ -44,31 +45,45 @@ const createStack = async (stackName, templateBody, context) => {
44
45
  }));
45
46
  const createStackRequest = new ros20190910_1.CreateStackRequest({
46
47
  regionId: context.region,
48
+ sync: true,
47
49
  stackName,
48
50
  templateBody: JSON.stringify(templateBody),
49
51
  parameters,
50
52
  tags: context.tags?.map((tag) => new ros20190910_1.CreateStackRequestTags(tag)),
51
53
  });
52
- console.log('createStackRequest:', createStackRequest);
53
54
  const response = await client.createStack(createStackRequest);
54
- console.log(`创建中,资源栈ID:${response.body?.stackId}`);
55
- return response.body?.stackId;
55
+ logger_1.logger.info(`创建中,资源栈ID:${response.body?.stackId}`);
56
+ // wait for stack create complete
57
+ return await getStackActionResult(response.body?.stackId || '', context.region);
56
58
  };
57
59
  const updateStack = async (stackId, templateBody, context) => {
58
60
  const parameters = context.parameters?.map((parameter) => new ros20190910_1.UpdateStackRequestParameters({
59
61
  parameterKey: tea_util_1.default.assertAsString(parameter.key),
60
62
  parameterValue: tea_util_1.default.assertAsString(parameter.key),
61
63
  }));
62
- const createStackRequest = new ros20190910_1.UpdateStackRequest({
64
+ const updateStackRequest = new ros20190910_1.UpdateStackRequest({
63
65
  regionId: context.region,
64
66
  stackId,
65
67
  templateBody: JSON.stringify(templateBody),
66
68
  parameters,
67
69
  tags: context.tags?.map((tag) => new ros20190910_1.CreateStackRequestTags(tag)),
68
70
  });
69
- const response = await client.updateStack(createStackRequest);
70
- console.log(`更新中,资源栈ID:${response.body?.stackId}`);
71
- return response.body?.stackId;
71
+ try {
72
+ const response = await client.updateStack(updateStackRequest);
73
+ logger_1.logger.info(`更新中,资源栈ID:${response.body?.stackId}`);
74
+ // wait for stack update complete
75
+ return await getStackActionResult(response.body?.stackId || '', context.region);
76
+ }
77
+ catch (err) {
78
+ const { Message: message, statusCode } = err?.data || {};
79
+ if (statusCode === 400 && message.includes('Update the completely same stack')) {
80
+ logger_1.logger.warn(`${lang_1.lang.__('UPDATE_COMPLETELY_SAME_STACK')}`);
81
+ return null;
82
+ }
83
+ else {
84
+ throw err;
85
+ }
86
+ }
72
87
  };
73
88
  const getStackByName = async (stackName, region) => {
74
89
  const result = await client.listStacks(new ros20190910_1.ListStacksRequest({
@@ -84,21 +99,67 @@ const getStackByName = async (stackName, region) => {
84
99
  return null;
85
100
  }
86
101
  };
102
+ const getStackActionResult = async (stackId, region) => {
103
+ return new Promise((resolve, reject) => {
104
+ const startTime = Date.now();
105
+ const interval = setInterval(async () => {
106
+ try {
107
+ const result = await client.getStack(new ros20190910_1.GetStackRequest({ regionId: region, stackId }));
108
+ const status = result.body?.status ?? '';
109
+ logger_1.logger.info(`stack status: ${status}`);
110
+ if ([
111
+ 'CREATE_COMPLETE',
112
+ 'UPDATE_COMPLETE',
113
+ 'DELETE_COMPLETE',
114
+ 'CHECK_COMPLETE',
115
+ 'IMPORT_CREATE_COMPLETE',
116
+ 'IMPORT_UPDATE_COMPLETE',
117
+ ].includes(status)) {
118
+ clearInterval(interval);
119
+ resolve(result.body);
120
+ }
121
+ else if ([
122
+ 'CREATE_ROLLBACK_FAILED',
123
+ 'CREATE_ROLLBACK_COMPLETE',
124
+ 'ROLLBACK_FAILED',
125
+ 'ROLLBACK_COMPLETE',
126
+ 'IMPORT_CREATE_ROLLBACK_FAILED',
127
+ 'IMPORT_CREATE_ROLLBACK_COMPLETE',
128
+ 'IMPORT_UPDATE_ROLLBACK_FAILED',
129
+ 'IMPORT_UPDATE_ROLLBACK_COMPLETE',
130
+ ].includes(status)) {
131
+ clearInterval(interval);
132
+ reject(new Error(`Stack operation failed with status: ${status}`));
133
+ }
134
+ else if (Date.now() - startTime > 3600000) {
135
+ // 1 hour in milliseconds
136
+ clearInterval(interval);
137
+ reject(new Error('Stack operation did not finish within 1 hour'));
138
+ }
139
+ }
140
+ catch (error) {
141
+ clearInterval(interval);
142
+ reject(error);
143
+ }
144
+ }, 5000); // 5 seconds interval
145
+ });
146
+ };
87
147
  const rosStackDeploy = async (stackName, templateBody, context) => {
88
148
  const stackInfo = await getStackByName(stackName, context.region);
89
149
  if (stackInfo) {
90
150
  const { Status: stackStatus } = stackInfo;
91
151
  if (stackStatus?.indexOf('IN_PROGRESS') >= 0) {
92
- logger_1.logger.error(`fail to update stack, because stack status is ${stackStatus}`);
93
152
  throw new Error(`fail to update stack, because stack status is ${stackStatus}`);
94
153
  }
95
154
  logger_1.logger.info(`Update stack: ${stackName} deploying... `);
96
- return await updateStack(stackInfo.stackId, templateBody, context);
155
+ const stack = await updateStack(stackInfo.stackId, templateBody, context);
156
+ logger_1.logger.info(`stackUpdate success! stackName:${stack?.stackName}, stackId:${stack?.stackId}`);
97
157
  }
98
158
  else {
99
159
  // create stack
100
160
  logger_1.logger.info(`Create stack: ${stackName} deploying... `);
101
- return await createStack(stackName, templateBody, context);
161
+ const stack = await createStack(stackName, templateBody, context);
162
+ logger_1.logger.info(`createStack success! stackName:${stack?.stackName}, stackId:${stack?.stackId}`);
102
163
  }
103
164
  };
104
165
  exports.rosStackDeploy = rosStackDeploy;
@@ -4,6 +4,12 @@ exports.lang = void 0;
4
4
  const i18n_1 = require("i18n");
5
5
  const lang = new i18n_1.I18n({
6
6
  locales: ['en', 'cn'],
7
- register: [{ hello: 'hello' }, { hello: '你好' }],
7
+ register: [
8
+ {
9
+ hello: 'hello',
10
+ UPDATE_COMPLETELY_SAME_STACK: 'The stack is completely the same, update SKIPPED',
11
+ },
12
+ { hello: '你好', UPDATE_COMPLETELY_SAME_STACK: '栈完全相同,更新跳过' },
13
+ ],
8
14
  });
9
15
  exports.lang = lang;
@@ -94,6 +94,21 @@ const schema = {
94
94
  required: ['method', 'path', 'backend'],
95
95
  },
96
96
  },
97
+ custom_domain: {
98
+ type: 'object',
99
+ properties: {
100
+ domain_name: { type: 'string' },
101
+ certificate_name: { type: 'string' },
102
+ certificate_body: { type: 'string' },
103
+ certificate_private_key: { type: 'string' },
104
+ },
105
+ required: [
106
+ 'domain_name',
107
+ 'certificate_name',
108
+ 'certificate_body',
109
+ 'certificate_private_key',
110
+ ],
111
+ },
97
112
  },
98
113
  required: ['name', 'type', 'triggers'],
99
114
  },
@@ -27,7 +27,7 @@ exports.IacStack = void 0;
27
27
  const ros = __importStar(require("@alicloud/ros-cdk-core"));
28
28
  const ros_cdk_core_1 = require("@alicloud/ros-cdk-core");
29
29
  const types_1 = require("../types");
30
- const fc = __importStar(require("@alicloud/ros-cdk-fc"));
30
+ const fc = __importStar(require("@alicloud/ros-cdk-fc3"));
31
31
  const ram = __importStar(require("@alicloud/ros-cdk-ram"));
32
32
  const agw = __importStar(require("@alicloud/ros-cdk-apigateway"));
33
33
  const common_1 = require("../common");
@@ -48,14 +48,9 @@ class IacStack extends ros.Stack {
48
48
  // Define Mappings
49
49
  new ros.RosMapping(this, 'stages', { mapping: (0, common_1.replaceVars)(iac.stages, context.stage) });
50
50
  new ros.RosInfo(this, ros.RosInfo.description, (0, common_1.replaceVars)(`${iac.service} stack`, context.stage));
51
- const service = new fc.RosService(this, (0, common_1.replaceVars)(`${iac.service}-service`, context.stage), {
52
- serviceName: (0, common_1.replaceVars)(`${iac.service}-service`, context.stage),
53
- tags: (0, common_1.replaceVars)(iac.tags, context.stage),
54
- }, true);
55
51
  iac.functions.forEach((fnc) => {
56
- const func = new fc.RosFunction(this, fnc.key, {
52
+ new fc.RosFunction(this, fnc.key, {
57
53
  functionName: (0, common_1.replaceVars)(fnc.name, context.stage),
58
- serviceName: (0, common_1.replaceVars)(service.serviceName, context.stage),
59
54
  handler: (0, common_1.replaceVars)(fnc.handler, context.stage),
60
55
  runtime: (0, common_1.replaceVars)(fnc.runtime, context.stage),
61
56
  memorySize: (0, common_1.replaceVars)(fnc.memory, context.stage),
@@ -65,7 +60,6 @@ class IacStack extends ros.Stack {
65
60
  zipFile: (0, common_1.resolveCode)(fnc.code),
66
61
  },
67
62
  }, true);
68
- func.addDependsOn(service);
69
63
  });
70
64
  const apiGateway = iac.events?.filter((event) => event.type === types_1.EventTypes.API_GATEWAY);
71
65
  if (apiGateway?.length) {
@@ -105,6 +99,18 @@ class IacStack extends ros.Stack {
105
99
  groupName: (0, common_1.replaceVars)(`${iac.service}_apigroup`, context.stage),
106
100
  tags: (0, common_1.replaceVars)(iac.tags, context.stage),
107
101
  }, true);
102
+ // new agw.RosCustomDomain(
103
+ // this,
104
+ // 'customDomain',
105
+ // {
106
+ // domainName: 'example.com',
107
+ // certificateName: 'example.com',
108
+ // certificateBody: 'example.com',
109
+ // certificatePrivateKey: 'example.com',
110
+ // groupId: apiGatewayGroup.attrGroupId,
111
+ // },
112
+ // true,
113
+ // );
108
114
  apiGateway.forEach((event) => {
109
115
  event.triggers.forEach((trigger) => {
110
116
  const key = `${trigger.method}_${trigger.path}`.toLowerCase().replace(/\//g, '_');
@@ -122,9 +128,9 @@ class IacStack extends ros.Stack {
122
128
  serviceProtocol: 'FunctionCompute',
123
129
  functionComputeConfig: {
124
130
  fcRegionId: context.region,
125
- serviceName: service.serviceName,
126
131
  functionName: trigger.backend,
127
132
  roleArn: gatewayAccessRole.attrArn,
133
+ fcVersion: '3.0',
128
134
  },
129
135
  },
130
136
  resultSample: 'ServerlessInsight resultSample',
@@ -5,10 +5,16 @@ const yaml_1 = require("yaml");
5
5
  const node_fs_1 = require("node:fs");
6
6
  const iacSchema_1 = require("./iacSchema");
7
7
  const mapToArr = (obj) => {
8
- return Object.entries(obj).map(([key, value]) => typeof value === 'string' ? { [key]: value } : { key, ...value });
8
+ if (!obj) {
9
+ return [];
10
+ }
11
+ return Object.entries(obj)?.map(([key, value]) => typeof value === 'string' ? { [key]: value } : { key, ...value });
9
12
  };
10
13
  const mapToKvArr = (obj) => {
11
- return Object.entries(obj).map(([key, value]) => ({ key, value }));
14
+ if (!obj) {
15
+ return [];
16
+ }
17
+ return Object.entries(obj)?.map(([key, value]) => ({ key, value }));
12
18
  };
13
19
  const validateExistence = (path) => {
14
20
  if (!(0, node_fs_1.existsSync)(path)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geek-fun/serverlessinsight",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
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",
@@ -49,33 +49,34 @@
49
49
  "function"
50
50
  ],
51
51
  "dependencies": {
52
- "@alicloud/openapi-client": "^0.4.11",
53
- "@alicloud/ros-cdk-apigateway": "^1.2.0",
54
- "@alicloud/ros-cdk-core": "^1.2.0",
55
- "@alicloud/ros-cdk-fc": "^1.2.0",
56
- "@alicloud/ros-cdk-ram": "^1.2.0",
57
- "@alicloud/ros20190910": "^3.4.3",
52
+ "@alicloud/openapi-client": "^0.4.12",
53
+ "@alicloud/ros-cdk-apigateway": "^1.4.0",
54
+ "@alicloud/ros-cdk-core": "^1.4.0",
55
+ "@alicloud/ros-cdk-fc3": "^1.4.0",
56
+ "@alicloud/ros-cdk-ram": "^1.4.0",
57
+ "@alicloud/ros20190910": "^3.5.0",
58
58
  "ajv": "^8.17.1",
59
- "chalk": "^4.1.2",
60
- "commander": "^11.1.0",
59
+ "chalk": "^5.3.0",
60
+ "commander": "^12.1.0",
61
61
  "i18n": "^0.15.1",
62
- "pino": "^8.17.2",
62
+ "pino": "^9.4.0",
63
63
  "pino-pretty": "^11.2.2",
64
64
  "yaml": "^2.5.1"
65
65
  },
66
66
  "devDependencies": {
67
- "@types/i18n": "^0.13.10",
68
- "@types/jest": "^29.5.11",
69
- "@types/node": "^20.11.5",
70
- "@typescript-eslint/eslint-plugin": "^6.19.0",
71
- "@typescript-eslint/parser": "^6.19.0",
72
- "eslint": "^8.56.0",
67
+ "@types/i18n": "^0.13.12",
68
+ "@types/jest": "^29.5.13",
69
+ "@types/node": "^22.7.4",
70
+ "@typescript-eslint/eslint-plugin": "^8.8.0",
71
+ "@typescript-eslint/parser": "^8.8.0",
72
+ "eslint": "^8.57.1",
73
73
  "eslint-config-prettier": "^9.1.0",
74
- "eslint-plugin-prettier": "^5.1.3",
74
+ "eslint-plugin-prettier": "^5.2.1",
75
+ "globals": "^15.9.0",
75
76
  "husky": "^9.1.6",
76
77
  "jest": "^29.7.0",
77
- "prettier": "^3.2.4",
78
- "ts-jest": "^29.1.1",
78
+ "prettier": "^3.3.3",
79
+ "ts-jest": "^29.2.5",
79
80
  "ts-node": "^10.9.2",
80
81
  "typescript": "^5.6.2"
81
82
  }