@geek-fun/serverlessinsight 0.4.0 → 0.5.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.
Files changed (160) hide show
  1. package/.gitattributes +1 -0
  2. package/README.md +108 -8
  3. package/README.zh-CN.md +52 -8
  4. package/dist/package.json +37 -35
  5. package/dist/src/commands/deploy.js +17 -7
  6. package/dist/src/commands/destroy.js +27 -4
  7. package/dist/src/commands/forceUnlock.js +61 -0
  8. package/dist/src/commands/index.js +86 -14
  9. package/dist/src/commands/local.js +10 -1
  10. package/dist/src/commands/plan.js +33 -0
  11. package/dist/src/commands/template.js +3 -1
  12. package/dist/src/commands/validate.js +2 -1
  13. package/dist/src/common/aliyunClient/apigwOperations.js +652 -0
  14. package/dist/src/common/aliyunClient/dnsOperations.js +90 -0
  15. package/dist/src/common/aliyunClient/ecsOperations.js +141 -0
  16. package/dist/src/common/aliyunClient/esOperations.js +219 -0
  17. package/dist/src/common/aliyunClient/fc3Operations.js +270 -0
  18. package/dist/src/common/aliyunClient/index.js +141 -0
  19. package/dist/src/common/aliyunClient/nasOperations.js +233 -0
  20. package/dist/src/common/aliyunClient/ossOperations.js +237 -0
  21. package/dist/src/common/aliyunClient/ramOperations.js +205 -0
  22. package/dist/src/common/aliyunClient/rdsOperations.js +206 -0
  23. package/dist/src/common/aliyunClient/slsOperations.js +218 -0
  24. package/dist/src/common/aliyunClient/tablestoreOperations.js +199 -0
  25. package/dist/src/common/aliyunClient/types.js +2 -0
  26. package/dist/src/common/constants.js +7 -1
  27. package/dist/src/common/context.js +32 -14
  28. package/dist/src/common/credentials.js +39 -0
  29. package/dist/src/common/dependencyGraph/graph.js +280 -0
  30. package/dist/src/common/dependencyGraph/index.js +18 -0
  31. package/dist/src/common/dependencyGraph/types.js +2 -0
  32. package/dist/src/common/fileUtils.js +16 -0
  33. package/dist/src/common/hashUtils.js +121 -0
  34. package/dist/src/common/iacHelper.js +25 -97
  35. package/dist/src/common/imsClient.js +4 -0
  36. package/dist/src/common/index.js +7 -2
  37. package/dist/src/common/lockManager.js +212 -0
  38. package/dist/src/common/logger.js +89 -6
  39. package/dist/src/common/providerEnum.js +2 -3
  40. package/dist/src/common/runtimeMapper.js +160 -0
  41. package/dist/src/common/scfClient.js +84 -0
  42. package/dist/src/common/stateManager.js +107 -0
  43. package/dist/src/common/tencentClient/cosOperations.js +287 -0
  44. package/dist/src/common/tencentClient/esOperations.js +156 -0
  45. package/dist/src/common/tencentClient/index.js +116 -0
  46. package/dist/src/common/tencentClient/scfOperations.js +141 -0
  47. package/dist/src/common/tencentClient/tdsqlcOperations.js +211 -0
  48. package/dist/src/common/tencentClient/types.js +17 -0
  49. package/dist/src/lang/en.js +254 -0
  50. package/dist/src/lang/index.js +28 -8
  51. package/dist/src/lang/zh-CN.js +229 -0
  52. package/dist/src/parser/bucketParser.js +25 -12
  53. package/dist/src/parser/databaseParser.js +14 -10
  54. package/dist/src/parser/functionParser.js +19 -6
  55. package/dist/src/parser/parseUtils.js +74 -0
  56. package/dist/src/parser/tableParser.js +19 -17
  57. package/dist/src/stack/aliyunStack/apigwExecutor.js +84 -0
  58. package/dist/src/stack/aliyunStack/apigwPlanner.js +118 -0
  59. package/dist/src/stack/aliyunStack/apigwResource.js +339 -0
  60. package/dist/src/stack/aliyunStack/apigwTypes.js +125 -0
  61. package/dist/src/stack/aliyunStack/databaseExecutor.js +112 -0
  62. package/dist/src/stack/aliyunStack/databasePlanner.js +128 -0
  63. package/dist/src/stack/aliyunStack/databaseResource.js +228 -0
  64. package/dist/src/stack/aliyunStack/deployer.js +133 -0
  65. package/dist/src/stack/aliyunStack/destroyer.js +114 -0
  66. package/dist/src/stack/aliyunStack/esServerlessTypes.js +141 -0
  67. package/dist/src/stack/aliyunStack/fc3Executor.js +91 -0
  68. package/dist/src/stack/aliyunStack/fc3Planner.js +77 -0
  69. package/dist/src/stack/aliyunStack/fc3Resource.js +511 -0
  70. package/dist/src/stack/aliyunStack/fc3Types.js +76 -0
  71. package/dist/src/stack/aliyunStack/index.js +40 -0
  72. package/dist/src/stack/aliyunStack/ossExecutor.js +91 -0
  73. package/dist/src/stack/aliyunStack/ossPlanner.js +76 -0
  74. package/dist/src/stack/aliyunStack/ossResource.js +196 -0
  75. package/dist/src/stack/aliyunStack/ossTypes.js +50 -0
  76. package/dist/src/stack/aliyunStack/planner.js +37 -0
  77. package/dist/src/stack/aliyunStack/rdsTypes.js +217 -0
  78. package/dist/src/stack/aliyunStack/tablestoreExecutor.js +92 -0
  79. package/dist/src/stack/aliyunStack/tablestorePlanner.js +94 -0
  80. package/dist/src/stack/aliyunStack/tablestoreResource.js +120 -0
  81. package/dist/src/stack/aliyunStack/tablestoreTypes.js +77 -0
  82. package/dist/src/stack/bucketTypes.js +17 -0
  83. package/dist/src/stack/deploy.js +24 -77
  84. package/dist/src/stack/localStack/bucket.js +11 -6
  85. package/dist/src/stack/localStack/event.js +10 -5
  86. package/dist/src/stack/localStack/function.js +13 -7
  87. package/dist/src/stack/localStack/functionRunner.js +1 -1
  88. package/dist/src/stack/localStack/localServer.js +7 -6
  89. package/dist/src/stack/scfStack/cosExecutor.js +91 -0
  90. package/dist/src/stack/scfStack/cosPlanner.js +76 -0
  91. package/dist/src/stack/scfStack/cosResource.js +126 -0
  92. package/dist/src/stack/scfStack/cosTypes.js +46 -0
  93. package/dist/src/stack/scfStack/deployer.js +91 -0
  94. package/dist/src/stack/scfStack/destroyer.js +88 -0
  95. package/dist/src/stack/scfStack/esServerlessExecutor.js +105 -0
  96. package/dist/src/stack/scfStack/esServerlessPlanner.js +86 -0
  97. package/dist/src/stack/scfStack/esServerlessResource.js +94 -0
  98. package/dist/src/stack/scfStack/esServerlessTypes.js +48 -0
  99. package/dist/src/stack/scfStack/index.js +35 -0
  100. package/dist/src/stack/scfStack/planner.js +91 -0
  101. package/dist/src/stack/scfStack/scfExecutor.js +91 -0
  102. package/dist/src/stack/scfStack/scfPlanner.js +78 -0
  103. package/dist/src/stack/scfStack/scfResource.js +216 -0
  104. package/dist/src/stack/scfStack/scfTypes.js +41 -0
  105. package/dist/src/stack/scfStack/tdsqlcExecutor.js +105 -0
  106. package/dist/src/stack/scfStack/tdsqlcPlanner.js +90 -0
  107. package/dist/src/stack/scfStack/tdsqlcResource.js +146 -0
  108. package/dist/src/stack/scfStack/tdsqlcTypes.js +59 -0
  109. package/dist/src/types/domains/lock.js +2 -0
  110. package/dist/src/types/domains/resolvable.js +2 -0
  111. package/dist/src/types/domains/state.js +19 -0
  112. package/dist/src/types/index.js +4 -0
  113. package/dist/src/validator/bucketSchema.js +4 -10
  114. package/dist/src/validator/databaseSchema.js +36 -36
  115. package/dist/src/validator/eventSchema.js +3 -2
  116. package/dist/src/validator/functionSchema.js +51 -46
  117. package/dist/src/validator/iacSchema.js +52 -3
  118. package/dist/src/validator/rootSchema.js +47 -1
  119. package/dist/src/validator/tableschema.js +9 -8
  120. package/dist/src/validator/templateRefSchema.js +23 -0
  121. package/dist/tsconfig.tsbuildinfo +1 -1
  122. package/package.json +37 -35
  123. package/samples/README_TENCENT_COS.md +486 -0
  124. package/samples/README_TENCENT_SCF.md +272 -0
  125. package/samples/aliyun-poc-api.yml +1 -1
  126. package/samples/aliyun-poc-bucket.yml +0 -1
  127. package/samples/aliyun-poc-domain.yml +0 -1
  128. package/samples/aliyun-poc-es.yml +14 -13
  129. package/samples/aliyun-poc-rds.yml +0 -2
  130. package/samples/aliyun-poc-table.yml +1 -3
  131. package/samples/tencent-poc-cos.yml +20 -0
  132. package/samples/tencent-poc-scf.yml +36 -0
  133. package/dist/src/commands/index.d.ts +0 -2
  134. package/dist/src/common/index.d.ts +0 -11
  135. package/dist/src/common/rosAssets.js +0 -178
  136. package/dist/src/common/rosClient.js +0 -198
  137. package/dist/src/index.d.ts +0 -1
  138. package/dist/src/lang/index.d.ts +0 -3
  139. package/dist/src/parser/index.d.ts +0 -3
  140. package/dist/src/stack/index.d.ts +0 -1
  141. package/dist/src/stack/localStack/index.d.ts +0 -5
  142. package/dist/src/stack/rfsStack/index.d.ts +0 -9
  143. package/dist/src/stack/rosStack/bootstrap.js +0 -187
  144. package/dist/src/stack/rosStack/bucket.js +0 -127
  145. package/dist/src/stack/rosStack/database.js +0 -313
  146. package/dist/src/stack/rosStack/event.js +0 -143
  147. package/dist/src/stack/rosStack/function.js +0 -259
  148. package/dist/src/stack/rosStack/index.d.ts +0 -7
  149. package/dist/src/stack/rosStack/index.js +0 -75
  150. package/dist/src/stack/rosStack/stage.js +0 -46
  151. package/dist/src/stack/rosStack/table.js +0 -95
  152. package/dist/src/stack/rosStack/tag.js +0 -11
  153. package/dist/src/stack/rosStack/vars.js +0 -49
  154. package/dist/src/types/index.d.ts +0 -55
  155. package/dist/src/types/localStack/index.d.ts +0 -81
  156. package/dist/src/validator/index.d.ts +0 -1
  157. package/layers/si-bootstrap-sdk/Dockerfile-aliyuncli +0 -12
  158. package/layers/si-bootstrap-sdk/README.md +0 -1
  159. package/layers/si-bootstrap-sdk/package-lock.json +0 -875
  160. package/layers/si-bootstrap-sdk/package.json +0 -33
@@ -10,8 +10,12 @@ const node_path_1 = __importDefault(require("node:path"));
10
10
  const node_fs_1 = __importDefault(require("node:fs"));
11
11
  const aliyunFc_1 = require("./aliyunFc");
12
12
  const utils_1 = require("./utils");
13
+ const lang_1 = require("../../lang");
13
14
  const functionsHandler = async (req, parsed, iac) => {
14
- common_1.logger.info(`Function request received by local server -> ${req.method} ${parsed.identifier ?? '/'} `);
15
+ common_1.logger.info(lang_1.lang.__('FUNCTION_REQUEST_RECEIVED', {
16
+ method: req.method || '',
17
+ identifier: parsed.identifier ?? '/',
18
+ }));
15
19
  const fcDef = iac.functions?.find((fn) => fn.key === parsed.identifier);
16
20
  if (!fcDef) {
17
21
  return {
@@ -44,7 +48,7 @@ const functionsHandler = async (req, parsed, iac) => {
44
48
  functionKey: fcDef.key,
45
49
  handler: fcDef.code.handler,
46
50
  servicePath: '',
47
- timeout: fcDef.timeout * 1000,
51
+ timeout: (fcDef.timeout ?? 3) * 1000,
48
52
  };
49
53
  // Check if provider is Aliyun to use Aliyun FC format
50
54
  const isAliyun = iac.provider.name === common_1.ProviderEnum.ALIYUN;
@@ -57,7 +61,7 @@ const functionsHandler = async (req, parsed, iac) => {
57
61
  const { event: aliyunEvent } = await (0, aliyunFc_1.transformToAliyunEvent)(req, parsed.url, parsed.query);
58
62
  event = aliyunEvent;
59
63
  // Use serializable context for worker thread (logger will be added inside worker)
60
- fcContext = (0, aliyunFc_1.createAliyunContextSerializable)(iac, fcDef.name, fcDef.code.handler, fcDef.memory, fcDef.timeout, requestId);
64
+ fcContext = (0, aliyunFc_1.createAliyunContextSerializable)(iac, fcDef.name, fcDef.code.handler, fcDef.memory ?? 128, fcDef.timeout ?? 3, requestId);
61
65
  env = {
62
66
  ...fcDef.environment,
63
67
  };
@@ -83,10 +87,12 @@ const functionsHandler = async (req, parsed, iac) => {
83
87
  awsRequestId: Math.random().toString(36).substring(2, 15),
84
88
  };
85
89
  }
86
- common_1.logger.debug(`Invoking worker with event type: ${isAliyun ? 'Buffer' : 'Object'} and context`);
87
- common_1.logger.debug(`Worker codeDir: ${codeDir}, handler: ${funOptions.handler}`);
90
+ common_1.logger.debug(lang_1.lang.__('INVOKING_WORKER_WITH_EVENT_TYPE', {
91
+ eventType: isAliyun ? 'Buffer' : 'Object',
92
+ }));
93
+ common_1.logger.debug(lang_1.lang.__('WORKER_CODE_DIR', { codeDir, handler: funOptions.handler }));
88
94
  const result = await (0, functionRunner_1.invokeFunction)(funOptions, env, event, fcContext);
89
- common_1.logger.info(`Function execution result: ${JSON.stringify(result)}`);
95
+ common_1.logger.info(lang_1.lang.__('FUNCTION_EXECUTION_RESULT', { result: JSON.stringify(result) }));
90
96
  // For Aliyun, transform FC response to HTTP response if needed
91
97
  if (isAliyun && result) {
92
98
  const transformed = (0, aliyunFc_1.transformFCResponse)(result);
@@ -102,7 +108,7 @@ const functionsHandler = async (req, parsed, iac) => {
102
108
  };
103
109
  }
104
110
  catch (error) {
105
- common_1.logger.error(`Function execution error: ${error}`);
111
+ common_1.logger.error(lang_1.lang.__('FUNCTION_EXECUTION_ERROR', { error: String(error) }));
106
112
  return {
107
113
  statusCode: 500,
108
114
  body: {
@@ -169,7 +169,7 @@ const resolveWorkerPath = () => {
169
169
  return localPath;
170
170
  }
171
171
  // Fallback to dist directory
172
- const distPath = __dirname.replace(/src\/stack\/localStack$/, 'dist/src/stack/localStack');
172
+ const distPath = __dirname.replace((0, node_path_1.join)('src', 'stack', 'localStack'), (0, node_path_1.join)('dist', 'src', 'stack', 'localStack'));
173
173
  return (0, node_path_1.join)(distPath, 'functionRunner.js');
174
174
  };
175
175
  const createWorker = (funOptions, env) => {
@@ -7,6 +7,7 @@ exports.stopLocal = exports.servLocal = void 0;
7
7
  const localStack_1 = require("../../types/localStack");
8
8
  const common_1 = require("../../common");
9
9
  const node_http_1 = __importDefault(require("node:http"));
10
+ const lang_1 = require("../../lang");
10
11
  let localServer;
11
12
  const cleanPathSegments = (pathname) => pathname
12
13
  .split('/')
@@ -43,7 +44,7 @@ const parseRequest = (req) => {
43
44
  };
44
45
  const servLocal = async (handlers, iac) => {
45
46
  if (localServer) {
46
- common_1.logger.info(`localServer already running on http://localhost:${common_1.SI_LOCALSTACK_SERVER_PORT}`);
47
+ common_1.logger.info(lang_1.lang.__('LOCAL_SERVER_ALREADY_RUNNING', { port: String(common_1.SI_LOCALSTACK_SERVER_PORT) }));
47
48
  return;
48
49
  }
49
50
  localServer = node_http_1.default.createServer(async (req, res) => {
@@ -76,13 +77,13 @@ const servLocal = async (handlers, iac) => {
76
77
  }
77
78
  }
78
79
  catch (err) {
79
- common_1.logger.error({ err }, 'Local gateway error');
80
+ common_1.logger.error({ err }, lang_1.lang.__('LOCAL_GATEWAY_ERROR'));
80
81
  respondJson(res, 500, { error: 'Local gateway failure' });
81
82
  }
82
83
  });
83
84
  await new Promise((resolve, reject) => {
84
85
  localServer.listen(common_1.SI_LOCALSTACK_SERVER_PORT, '0.0.0.0', () => {
85
- common_1.logger.info(`Local Server listening on http://localhost:${common_1.SI_LOCALSTACK_SERVER_PORT}`);
86
+ common_1.logger.info(lang_1.lang.__('LOCAL_SERVER_LISTENING', { port: String(common_1.SI_LOCALSTACK_SERVER_PORT) }));
86
87
  resolve();
87
88
  });
88
89
  localServer.once('error', reject);
@@ -91,18 +92,18 @@ const servLocal = async (handlers, iac) => {
91
92
  exports.servLocal = servLocal;
92
93
  const stopLocal = async () => {
93
94
  if (!localServer) {
94
- common_1.logger.info('localServer is not running');
95
+ common_1.logger.info(lang_1.lang.__('LOCAL_SERVER_NOT_RUNNING'));
95
96
  return;
96
97
  }
97
98
  await new Promise((resolve, reject) => {
98
99
  localServer.close((err) => {
99
100
  if (err) {
100
- common_1.logger.error({ err }, 'Error stopping localServer');
101
+ common_1.logger.error({ err }, lang_1.lang.__('ERROR_STOPPING_LOCAL_SERVER'));
101
102
  reject(err);
102
103
  }
103
104
  else {
104
105
  localServer = undefined;
105
- common_1.logger.info('localServer stopped');
106
+ common_1.logger.info(lang_1.lang.__('LOCAL_SERVER_STOPPED'));
106
107
  resolve();
107
108
  }
108
109
  });
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.executeBucketPlan = void 0;
4
+ const cosResource_1 = require("./cosResource");
5
+ const common_1 = require("../../common");
6
+ const stateManager_1 = require("../../common/stateManager");
7
+ const lang_1 = require("../../lang");
8
+ const executeCreateAction = async (context, bucket, currentState) => {
9
+ common_1.logger.info(`Creating bucket: ${bucket.name}`);
10
+ const newState = await (0, cosResource_1.createBucketResource)(context, bucket, currentState);
11
+ common_1.logger.info(`Successfully created bucket: ${bucket.name}`);
12
+ return newState;
13
+ };
14
+ const executeUpdateAction = async (context, bucket, currentState) => {
15
+ common_1.logger.info(`Updating bucket: ${bucket.name}`);
16
+ const newState = await (0, cosResource_1.updateBucketResource)(context, bucket, currentState);
17
+ common_1.logger.info(`Successfully updated bucket: ${bucket.name}`);
18
+ return newState;
19
+ };
20
+ const executeDeleteAction = async (context, bucketName, region, logicalId, currentState) => {
21
+ common_1.logger.info(`Deleting bucket: ${bucketName}`);
22
+ const newState = await (0, cosResource_1.deleteBucketResource)(context, bucketName, region, logicalId, currentState);
23
+ common_1.logger.info(`Successfully deleted bucket: ${bucketName}`);
24
+ return newState;
25
+ };
26
+ const executeSingleItem = async (context, item, bucketsMap, currentState) => {
27
+ switch (item.action) {
28
+ case 'noop':
29
+ common_1.logger.info(`No changes for ${item.logicalId}`);
30
+ return null;
31
+ case 'create': {
32
+ const bucket = bucketsMap.get(item.logicalId);
33
+ if (!bucket) {
34
+ throw new Error(`Bucket not found for logical ID: ${item.logicalId}`);
35
+ }
36
+ return executeCreateAction(context, bucket, currentState);
37
+ }
38
+ case 'update': {
39
+ const bucket = bucketsMap.get(item.logicalId);
40
+ if (!bucket) {
41
+ throw new Error(`Bucket not found for logical ID: ${item.logicalId}`);
42
+ }
43
+ return executeUpdateAction(context, bucket, currentState);
44
+ }
45
+ case 'delete': {
46
+ const state = (0, stateManager_1.getResource)(currentState, item.logicalId);
47
+ if (!state) {
48
+ common_1.logger.warn(`State not found for ${item.logicalId}, skipping deletion`);
49
+ return null;
50
+ }
51
+ const bucketName = state.definition.bucket;
52
+ return executeDeleteAction(context, bucketName, state.region, item.logicalId, currentState);
53
+ }
54
+ default:
55
+ common_1.logger.warn(`Unknown action: ${item.action} for ${item.logicalId}`);
56
+ return null;
57
+ }
58
+ };
59
+ const executeBucketPlan = async (context, plan, buckets, initialState, onStateChange) => {
60
+ const bucketsMap = new Map(buckets?.map((bucket) => [`buckets.${bucket.key}`, bucket]) ?? []);
61
+ const successfulItems = [];
62
+ let currentState = initialState;
63
+ for (const item of plan.items) {
64
+ try {
65
+ const newState = await executeSingleItem(context, item, bucketsMap, currentState);
66
+ if (newState !== null) {
67
+ currentState = newState;
68
+ successfulItems.push(item);
69
+ if (onStateChange) {
70
+ onStateChange(currentState);
71
+ common_1.logger.debug(lang_1.lang.__('STATE_PERSISTED_AFTER_OPERATION', {
72
+ action: item.action,
73
+ resourceId: item.logicalId,
74
+ }));
75
+ }
76
+ }
77
+ }
78
+ catch (error) {
79
+ return {
80
+ state: currentState,
81
+ partialFailure: {
82
+ failedItem: item,
83
+ error: error instanceof Error ? error : new Error(String(error)),
84
+ successfulItems,
85
+ },
86
+ };
87
+ }
88
+ }
89
+ return { state: currentState };
90
+ };
91
+ exports.executeBucketPlan = executeBucketPlan;
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateBucketPlan = void 0;
4
+ const tencentClient_1 = require("../../common/tencentClient");
5
+ const cosTypes_1 = require("./cosTypes");
6
+ const stateManager_1 = require("../../common/stateManager");
7
+ const hashUtils_1 = require("../../common/hashUtils");
8
+ const planBucketDeletion = (logicalId, definition) => ({
9
+ logicalId,
10
+ action: 'delete',
11
+ resourceType: 'COS_BUCKET',
12
+ changes: { before: definition },
13
+ });
14
+ const generateBucketPlan = async (context, state, buckets) => {
15
+ if (!buckets || buckets.length === 0) {
16
+ const allStates = (0, stateManager_1.getAllResources)(state);
17
+ const items = Object.entries(allStates)
18
+ .filter(([logicalId]) => logicalId.startsWith('buckets.'))
19
+ .map(([logicalId, resourceState]) => planBucketDeletion(logicalId, resourceState.definition));
20
+ return { items };
21
+ }
22
+ const desiredLogicalIds = new Set(buckets.map((bucket) => `buckets.${bucket.key}`));
23
+ const bucketItems = await Promise.all(buckets.map(async (bucket) => {
24
+ const logicalId = `buckets.${bucket.key}`;
25
+ const currentState = (0, stateManager_1.getResource)(state, logicalId);
26
+ const config = (0, cosTypes_1.bucketToCosBucketConfig)(bucket, context.region);
27
+ const desiredDefinition = (0, cosTypes_1.extractCosBucketDefinition)(config);
28
+ if (!currentState) {
29
+ return {
30
+ logicalId,
31
+ action: 'create',
32
+ resourceType: 'COS_BUCKET',
33
+ changes: { after: desiredDefinition },
34
+ };
35
+ }
36
+ try {
37
+ const client = (0, tencentClient_1.createTencentClient)(context);
38
+ const remoteBucket = await client.cos.getBucket(bucket.name, context.region);
39
+ if (!remoteBucket) {
40
+ return {
41
+ logicalId,
42
+ action: 'create',
43
+ resourceType: 'COS_BUCKET',
44
+ changes: { before: currentState.definition, after: desiredDefinition },
45
+ drifted: true,
46
+ };
47
+ }
48
+ const currentDefinition = currentState.definition || {};
49
+ const definitionChanged = !(0, hashUtils_1.attributesEqual)(currentDefinition, desiredDefinition);
50
+ if (definitionChanged) {
51
+ return {
52
+ logicalId,
53
+ action: 'update',
54
+ resourceType: 'COS_BUCKET',
55
+ changes: { before: currentDefinition, after: desiredDefinition },
56
+ drifted: true,
57
+ };
58
+ }
59
+ return { logicalId, action: 'noop', resourceType: 'COS_BUCKET' };
60
+ }
61
+ catch {
62
+ return {
63
+ logicalId,
64
+ action: 'create',
65
+ resourceType: 'COS_BUCKET',
66
+ changes: { before: currentState.definition, after: desiredDefinition },
67
+ };
68
+ }
69
+ }));
70
+ const allStates = (0, stateManager_1.getAllResources)(state);
71
+ const deletionItems = Object.entries(allStates)
72
+ .filter(([logicalId]) => logicalId.startsWith('buckets.') && !desiredLogicalIds.has(logicalId))
73
+ .map(([logicalId, resourceState]) => planBucketDeletion(logicalId, resourceState.definition));
74
+ return { items: [...bucketItems, ...deletionItems] };
75
+ };
76
+ exports.generateBucketPlan = generateBucketPlan;
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deleteBucketResource = exports.updateBucketResource = exports.readBucketResource = exports.createBucketResource = void 0;
4
+ const tencentClient_1 = require("../../common/tencentClient");
5
+ const cosTypes_1 = require("./cosTypes");
6
+ const stateManager_1 = require("../../common/stateManager");
7
+ const buildCosInstanceFromProvider = (info, arn) => {
8
+ return {
9
+ arn,
10
+ id: info.Name,
11
+ bucket: info.Name,
12
+ location: info.Location,
13
+ creationDate: info.CreationDate ?? null,
14
+ acl: info.ACL ?? null,
15
+ websiteConfiguration: info.WebsiteConfiguration
16
+ ? {
17
+ indexDocument: info.WebsiteConfiguration.IndexDocument?.Suffix ?? null,
18
+ errorDocument: info.WebsiteConfiguration.ErrorDocument?.Key ?? null,
19
+ }
20
+ : {},
21
+ accessControlPolicy: info.AccessControlPolicy
22
+ ? {
23
+ owner: info.AccessControlPolicy.owner
24
+ ? {
25
+ id: info.AccessControlPolicy.owner.id ?? null,
26
+ displayName: info.AccessControlPolicy.owner.displayName ?? null,
27
+ }
28
+ : {},
29
+ grants: info.AccessControlPolicy.grants?.map((g) => ({
30
+ grantee: g.grantee
31
+ ? {
32
+ type: g.grantee.type ?? null,
33
+ uri: g.grantee.uri ?? null,
34
+ id: g.grantee.id ?? null,
35
+ displayName: g.grantee.displayName ?? null,
36
+ }
37
+ : {},
38
+ permission: g.permission ?? null,
39
+ })) ?? [],
40
+ }
41
+ : {},
42
+ corsConfiguration: info.CorsConfiguration?.map((r) => ({
43
+ id: r.id ?? null,
44
+ allowedOrigins: r.allowedOrigins ?? [],
45
+ allowedMethods: r.allowedMethods ?? [],
46
+ allowedHeaders: r.allowedHeaders ?? [],
47
+ exposeHeaders: r.exposeHeaders ?? [],
48
+ maxAgeSeconds: r.maxAgeSeconds ?? null,
49
+ })) ?? [],
50
+ versioningConfiguration: info.VersioningConfiguration
51
+ ? {
52
+ status: info.VersioningConfiguration.status ?? null,
53
+ }
54
+ : {},
55
+ taggingConfiguration: info.TaggingConfiguration
56
+ ? {
57
+ tags: info.TaggingConfiguration.tags?.map((t) => ({
58
+ key: t.key ?? null,
59
+ value: t.value ?? null,
60
+ })) ?? [],
61
+ }
62
+ : {},
63
+ };
64
+ };
65
+ const createBucketResource = async (context, bucket, state) => {
66
+ const config = (0, cosTypes_1.bucketToCosBucketConfig)(bucket, context.region);
67
+ const client = (0, tencentClient_1.createTencentClient)(context);
68
+ await client.cos.createBucket(config);
69
+ // Refresh state from provider to get all attributes
70
+ const bucketInfo = await client.cos.getBucket(bucket.name, context.region);
71
+ if (!bucketInfo) {
72
+ throw new Error(`Failed to refresh state for bucket: ${bucket.name}`);
73
+ }
74
+ const definition = (0, cosTypes_1.extractCosBucketDefinition)(config);
75
+ const arn = `arn:tencent:cos:${context.region}::bucket:${bucket.name}`;
76
+ const resourceState = {
77
+ mode: 'managed',
78
+ region: context.region,
79
+ definition,
80
+ instances: [buildCosInstanceFromProvider(bucketInfo, arn)],
81
+ lastUpdated: new Date().toISOString(),
82
+ };
83
+ const logicalId = `buckets.${bucket.key}`;
84
+ return (0, stateManager_1.setResource)(state, logicalId, resourceState);
85
+ };
86
+ exports.createBucketResource = createBucketResource;
87
+ const readBucketResource = async (context, bucketName, region) => {
88
+ const client = (0, tencentClient_1.createTencentClient)(context);
89
+ return await client.cos.getBucket(bucketName, region);
90
+ };
91
+ exports.readBucketResource = readBucketResource;
92
+ const updateBucketResource = async (context, bucket, state) => {
93
+ const config = (0, cosTypes_1.bucketToCosBucketConfig)(bucket, context.region);
94
+ const client = (0, tencentClient_1.createTencentClient)(context);
95
+ // Update ACL if specified
96
+ if (config.ACL) {
97
+ await client.cos.updateBucketAcl(bucket.name, context.region, config.ACL);
98
+ }
99
+ // Update website configuration if specified
100
+ if (config.WebsiteConfiguration) {
101
+ await client.cos.updateBucketWebsite(bucket.name, context.region, config.WebsiteConfiguration);
102
+ }
103
+ // Refresh state from provider to get all attributes
104
+ const bucketInfo = await client.cos.getBucket(bucket.name, context.region);
105
+ if (!bucketInfo) {
106
+ throw new Error(`Failed to refresh state for bucket: ${bucket.name}`);
107
+ }
108
+ const definition = (0, cosTypes_1.extractCosBucketDefinition)(config);
109
+ const arn = `arn:tencent:cos:${context.region}::bucket:${bucket.name}`;
110
+ const resourceState = {
111
+ mode: 'managed',
112
+ region: context.region,
113
+ definition,
114
+ instances: [buildCosInstanceFromProvider(bucketInfo, arn)],
115
+ lastUpdated: new Date().toISOString(),
116
+ };
117
+ const logicalId = `buckets.${bucket.key}`;
118
+ return (0, stateManager_1.setResource)(state, logicalId, resourceState);
119
+ };
120
+ exports.updateBucketResource = updateBucketResource;
121
+ const deleteBucketResource = async (context, bucketName, region, logicalId, state) => {
122
+ const client = (0, tencentClient_1.createTencentClient)(context);
123
+ await client.cos.deleteBucket(bucketName, region);
124
+ return (0, stateManager_1.removeResource)(state, logicalId);
125
+ };
126
+ exports.deleteBucketResource = deleteBucketResource;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractCosBucketDefinition = exports.bucketToCosBucketConfig = void 0;
4
+ const bucketToCosBucketConfig = (bucket, region) => {
5
+ const config = {
6
+ Bucket: bucket.name,
7
+ Region: region,
8
+ };
9
+ if (bucket.security?.acl) {
10
+ const aclMap = {
11
+ PRIVATE: 'private',
12
+ PUBLIC_READ: 'public-read',
13
+ PUBLIC_READ_WRITE: 'public-read-write',
14
+ };
15
+ config.ACL = aclMap[bucket.security.acl];
16
+ }
17
+ if (bucket.website) {
18
+ config.WebsiteConfiguration = {
19
+ IndexDocument: {
20
+ Suffix: bucket.website.index,
21
+ },
22
+ };
23
+ // Only add ErrorDocument if error_page is defined
24
+ if (bucket.website.error_page) {
25
+ config.WebsiteConfiguration.ErrorDocument = {
26
+ Key: bucket.website.error_page,
27
+ };
28
+ }
29
+ }
30
+ return config;
31
+ };
32
+ exports.bucketToCosBucketConfig = bucketToCosBucketConfig;
33
+ const extractCosBucketDefinition = (config) => {
34
+ return {
35
+ bucket: config.Bucket,
36
+ region: config.Region,
37
+ acl: config.ACL ?? null,
38
+ websiteConfiguration: config.WebsiteConfiguration
39
+ ? {
40
+ indexDocument: config.WebsiteConfiguration.IndexDocument.Suffix,
41
+ errorDocument: config.WebsiteConfiguration.ErrorDocument?.Key ?? null,
42
+ }
43
+ : {},
44
+ };
45
+ };
46
+ exports.extractCosBucketDefinition = extractCosBucketDefinition;
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deployTencentStack = void 0;
4
+ const common_1 = require("../../common");
5
+ const lang_1 = require("../../lang");
6
+ const scfPlanner_1 = require("./scfPlanner");
7
+ const scfExecutor_1 = require("./scfExecutor");
8
+ const cosPlanner_1 = require("./cosPlanner");
9
+ const cosExecutor_1 = require("./cosExecutor");
10
+ const tdsqlcPlanner_1 = require("./tdsqlcPlanner");
11
+ const tdsqlcExecutor_1 = require("./tdsqlcExecutor");
12
+ const esServerlessPlanner_1 = require("./esServerlessPlanner");
13
+ const esServerlessExecutor_1 = require("./esServerlessExecutor");
14
+ const createSaveStateFn = (baseDir) => (state) => {
15
+ (0, common_1.saveState)(state, baseDir);
16
+ };
17
+ const handlePartialFailure = (failure) => {
18
+ const error = failure.error;
19
+ error.isPartialFailure = true;
20
+ common_1.logger.error(`${lang_1.lang.__('FAILED_TO_EXECUTE_ACTION', {
21
+ action: failure.failedItem.action,
22
+ logicalId: failure.failedItem.logicalId,
23
+ error: error.message,
24
+ })}\n\n${lang_1.lang.__('PARTIAL_DEPLOYMENT_FAILURE', {
25
+ successCount: String(failure.successfulItems.length),
26
+ failedResource: failure.failedItem.logicalId,
27
+ })}\n${lang_1.lang.__('PARTIAL_FAILURE_STATE_SAVED')}\n${lang_1.lang.__('PARTIAL_FAILURE_NEXT_STEPS')}`);
28
+ throw error;
29
+ };
30
+ const collectSuccessfulItems = (results) => results.flatMap((result) => result.partialFailure?.successfulItems ?? []);
31
+ const deployTencentStack = async (iac) => {
32
+ const context = (0, common_1.getContext)();
33
+ const baseDir = process.cwd();
34
+ common_1.logger.info(lang_1.lang.__('DEPLOYING_STACK_PUBLISHING_ASSETS'));
35
+ let state = (0, common_1.loadState)(iac.provider.name, baseDir);
36
+ const onStateChange = createSaveStateFn(baseDir);
37
+ common_1.logger.info(lang_1.lang.__('GENERATING_PLAN'));
38
+ const functionPlan = await (0, scfPlanner_1.generateFunctionPlan)(context, state, iac.functions);
39
+ const bucketPlan = await (0, cosPlanner_1.generateBucketPlan)(context, state, iac.buckets);
40
+ const databasePlan = await (0, tdsqlcPlanner_1.generateDatabasePlan)(context, state, iac.databases);
41
+ const esPlan = await (0, esServerlessPlanner_1.generateEsPlan)(context, state, iac.databases);
42
+ const combinedPlan = {
43
+ items: [...functionPlan.items, ...bucketPlan.items, ...databasePlan.items, ...esPlan.items],
44
+ };
45
+ common_1.logger.info(`${lang_1.lang.__('PLAN_GENERATED')}: ${combinedPlan.items.length} ${lang_1.lang.__('ACTIONS')}`);
46
+ combinedPlan.items.forEach((item) => {
47
+ common_1.logger.info(` - ${item.action.toUpperCase()}: ${item.logicalId} (${item.resourceType})`);
48
+ });
49
+ common_1.logger.info(lang_1.lang.__('EXECUTING_PLAN'));
50
+ const functionResult = await (0, scfExecutor_1.executeFunctionPlan)(context, functionPlan, iac.functions, state, onStateChange);
51
+ state = functionResult.state;
52
+ if (functionResult.partialFailure) {
53
+ handlePartialFailure(functionResult.partialFailure);
54
+ }
55
+ const bucketResult = await (0, cosExecutor_1.executeBucketPlan)(context, bucketPlan, iac.buckets, state, onStateChange);
56
+ state = bucketResult.state;
57
+ if (bucketResult.partialFailure) {
58
+ handlePartialFailure({
59
+ ...bucketResult.partialFailure,
60
+ successfulItems: [
61
+ ...collectSuccessfulItems([functionResult]),
62
+ ...bucketResult.partialFailure.successfulItems,
63
+ ],
64
+ });
65
+ }
66
+ const databaseResult = await (0, tdsqlcExecutor_1.executeDatabasePlan)(context, databasePlan, iac.databases, state, onStateChange);
67
+ state = databaseResult.state;
68
+ if (databaseResult.partialFailure) {
69
+ handlePartialFailure({
70
+ ...databaseResult.partialFailure,
71
+ successfulItems: [
72
+ ...collectSuccessfulItems([functionResult, bucketResult]),
73
+ ...databaseResult.partialFailure.successfulItems,
74
+ ],
75
+ });
76
+ }
77
+ const esResult = await (0, esServerlessExecutor_1.executeEsPlan)(context, esPlan, iac.databases, state, onStateChange);
78
+ state = esResult.state;
79
+ if (esResult.partialFailure) {
80
+ handlePartialFailure({
81
+ ...esResult.partialFailure,
82
+ successfulItems: [
83
+ ...collectSuccessfulItems([functionResult, bucketResult, databaseResult]),
84
+ ...esResult.partialFailure.successfulItems,
85
+ ],
86
+ });
87
+ }
88
+ (0, common_1.saveState)(state, baseDir);
89
+ common_1.logger.info(lang_1.lang.__('STACK_DEPLOYED'));
90
+ };
91
+ exports.deployTencentStack = deployTencentStack;
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.destroyTencentStack = void 0;
4
+ const common_1 = require("../../common");
5
+ const lang_1 = require("../../lang");
6
+ const scfPlanner_1 = require("./scfPlanner");
7
+ const scfExecutor_1 = require("./scfExecutor");
8
+ const cosPlanner_1 = require("./cosPlanner");
9
+ const cosExecutor_1 = require("./cosExecutor");
10
+ const tdsqlcPlanner_1 = require("./tdsqlcPlanner");
11
+ const tdsqlcExecutor_1 = require("./tdsqlcExecutor");
12
+ const esServerlessPlanner_1 = require("./esServerlessPlanner");
13
+ const esServerlessExecutor_1 = require("./esServerlessExecutor");
14
+ const createSaveStateFn = (baseDir) => (state) => {
15
+ (0, common_1.saveState)(state, baseDir);
16
+ };
17
+ const handlePartialFailure = (failure) => {
18
+ const error = failure.error;
19
+ error.isPartialFailure = true;
20
+ common_1.logger.error(`${lang_1.lang.__('FAILED_TO_EXECUTE_ACTION', {
21
+ action: failure.failedItem.action,
22
+ logicalId: failure.failedItem.logicalId,
23
+ error: error.message,
24
+ })}\n\n${lang_1.lang.__('PARTIAL_DEPLOYMENT_FAILURE', {
25
+ successCount: String(failure.successfulItems.length),
26
+ failedResource: failure.failedItem.logicalId,
27
+ })}\n${lang_1.lang.__('PARTIAL_FAILURE_STATE_SAVED')}\n${lang_1.lang.__('PARTIAL_FAILURE_NEXT_STEPS')}`);
28
+ throw failure.error;
29
+ };
30
+ const collectSuccessfulItems = (results) => results.flatMap((result) => result.partialFailure?.successfulItems ?? []);
31
+ const destroyTencentStack = async () => {
32
+ const context = (0, common_1.getContext)();
33
+ const baseDir = process.cwd();
34
+ const providerName = common_1.ProviderEnum.TENCENT;
35
+ let state = (0, common_1.loadState)(providerName, baseDir);
36
+ const onStateChange = createSaveStateFn(baseDir);
37
+ const functionPlan = await (0, scfPlanner_1.generateFunctionPlan)(context, state, undefined);
38
+ const bucketPlan = await (0, cosPlanner_1.generateBucketPlan)(context, state, undefined);
39
+ const databasePlan = await (0, tdsqlcPlanner_1.generateDatabasePlan)(context, state, undefined);
40
+ const esPlan = await (0, esServerlessPlanner_1.generateEsPlan)(context, state, undefined);
41
+ const combinedPlan = {
42
+ items: [...functionPlan.items, ...bucketPlan.items, ...databasePlan.items, ...esPlan.items],
43
+ };
44
+ common_1.logger.info(`${lang_1.lang.__('PLAN_GENERATED')}: ${combinedPlan.items.length} ${lang_1.lang.__('ACTIONS')}`);
45
+ combinedPlan.items.forEach((item) => {
46
+ common_1.logger.info(` - ${item.action.toUpperCase()}: ${item.logicalId} (${item.resourceType})`);
47
+ });
48
+ const functionResult = await (0, scfExecutor_1.executeFunctionPlan)(context, functionPlan, undefined, state, onStateChange);
49
+ state = functionResult.state;
50
+ if (functionResult.partialFailure) {
51
+ handlePartialFailure(functionResult.partialFailure);
52
+ }
53
+ const bucketResult = await (0, cosExecutor_1.executeBucketPlan)(context, bucketPlan, undefined, state, onStateChange);
54
+ state = bucketResult.state;
55
+ if (bucketResult.partialFailure) {
56
+ handlePartialFailure({
57
+ ...bucketResult.partialFailure,
58
+ successfulItems: [
59
+ ...collectSuccessfulItems([functionResult]),
60
+ ...bucketResult.partialFailure.successfulItems,
61
+ ],
62
+ });
63
+ }
64
+ const databaseResult = await (0, tdsqlcExecutor_1.executeDatabasePlan)(context, databasePlan, undefined, state, onStateChange);
65
+ state = databaseResult.state;
66
+ if (databaseResult.partialFailure) {
67
+ handlePartialFailure({
68
+ ...databaseResult.partialFailure,
69
+ successfulItems: [
70
+ ...collectSuccessfulItems([functionResult, bucketResult]),
71
+ ...databaseResult.partialFailure.successfulItems,
72
+ ],
73
+ });
74
+ }
75
+ const esResult = await (0, esServerlessExecutor_1.executeEsPlan)(context, esPlan, undefined, state, onStateChange);
76
+ state = esResult.state;
77
+ if (esResult.partialFailure) {
78
+ handlePartialFailure({
79
+ ...esResult.partialFailure,
80
+ successfulItems: [
81
+ ...collectSuccessfulItems([functionResult, bucketResult, databaseResult]),
82
+ ...esResult.partialFailure.successfulItems,
83
+ ],
84
+ });
85
+ }
86
+ (0, common_1.saveState)(state, baseDir);
87
+ };
88
+ exports.destroyTencentStack = destroyTencentStack;