@geek-fun/serverlessinsight 0.6.15 → 0.7.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 (44) hide show
  1. package/AGENTS.md +405 -10
  2. package/README.md +1 -0
  3. package/dist/package.json +8 -2
  4. package/dist/src/commands/deploy.js +4 -0
  5. package/dist/src/commands/destroy.js +4 -0
  6. package/dist/src/common/credentials.js +12 -0
  7. package/dist/src/common/providerEnum.js +1 -0
  8. package/dist/src/common/runtimeMapper.js +24 -3
  9. package/dist/src/common/volcengineClient/apigwOperations.js +271 -0
  10. package/dist/src/common/volcengineClient/iamOperations.js +349 -0
  11. package/dist/src/common/volcengineClient/index.js +99 -0
  12. package/dist/src/common/volcengineClient/tlsOperations.js +256 -0
  13. package/dist/src/common/volcengineClient/tosOperations.js +440 -0
  14. package/dist/src/common/volcengineClient/types.js +26 -0
  15. package/dist/src/common/volcengineClient/vefaasOperations.js +386 -0
  16. package/dist/src/lang/en.js +120 -0
  17. package/dist/src/lang/zh-CN.js +119 -0
  18. package/dist/src/stack/deploy.js +4 -0
  19. package/dist/src/stack/volcengineStack/apigwExecutor.js +87 -0
  20. package/dist/src/stack/volcengineStack/apigwPlanner.js +110 -0
  21. package/dist/src/stack/volcengineStack/apigwResource.js +302 -0
  22. package/dist/src/stack/volcengineStack/apigwTypes.js +106 -0
  23. package/dist/src/stack/volcengineStack/deployer.js +59 -0
  24. package/dist/src/stack/volcengineStack/destroyer.js +72 -0
  25. package/dist/src/stack/volcengineStack/index.js +44 -0
  26. package/dist/src/stack/volcengineStack/planner.js +27 -0
  27. package/dist/src/stack/volcengineStack/tosExecutor.js +106 -0
  28. package/dist/src/stack/volcengineStack/tosPlanner.js +96 -0
  29. package/dist/src/stack/volcengineStack/tosResource.js +103 -0
  30. package/dist/src/stack/volcengineStack/tosTypes.js +65 -0
  31. package/dist/src/stack/volcengineStack/vefaasExecutor.js +102 -0
  32. package/dist/src/stack/volcengineStack/vefaasPlanner.js +84 -0
  33. package/dist/src/stack/volcengineStack/vefaasResource.js +513 -0
  34. package/dist/src/stack/volcengineStack/vefaasTypes.js +75 -0
  35. package/dist/src/types/domains/state.js +3 -0
  36. package/dist/src/validator/functionSchema.js +13 -0
  37. package/dist/src/validator/rootSchema.js +1 -1
  38. package/dist/tsconfig.tsbuildinfo +1 -1
  39. package/package.json +8 -2
  40. package/samples/volcengine-poc-advanced.yml +59 -0
  41. package/samples/volcengine-poc-api.yml +31 -0
  42. package/samples/volcengine-poc-bucket.yml +17 -0
  43. package/samples/volcengine-poc-function.yml +19 -0
  44. package/samples/volcengine-poc-vpc.yml +34 -0
@@ -0,0 +1,386 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.createVefaasOperations = void 0;
37
+ const openapi_1 = require("@volcengine/openapi");
38
+ const logger_1 = require("../../common/logger");
39
+ const lang_1 = require("../../lang");
40
+ const fs = __importStar(require("node:fs"));
41
+ const MAX_ZIP_SIZE_MB = 50;
42
+ const MAX_ZIP_SIZE_BYTES = MAX_ZIP_SIZE_MB * 1024 * 1024;
43
+ const MAX_TOS_SIZE_MB = 500;
44
+ const MAX_TOS_SIZE_BYTES = MAX_TOS_SIZE_MB * 1024 * 1024;
45
+ const buildEnvVariables = (envs) => {
46
+ if (!envs)
47
+ return undefined;
48
+ return Object.entries(envs).map(([key, value]) => ({ key, value }));
49
+ };
50
+ const parseEnvVariables = (envs) => {
51
+ if (!envs || envs.length === 0)
52
+ return undefined;
53
+ return envs.reduce((acc, { key, value }) => {
54
+ acc[key] = value;
55
+ return acc;
56
+ }, {});
57
+ };
58
+ const validateCodePackage = async (codePath) => {
59
+ const stats = await fs.promises.stat(codePath);
60
+ const sizeMB = (stats.size / 1024 / 1024).toFixed(2);
61
+ if (stats.size > MAX_TOS_SIZE_BYTES) {
62
+ throw new Error(lang_1.lang.__('CODE_PACKAGE_TOO_LARGE', {
63
+ size: sizeMB,
64
+ maxZip: MAX_ZIP_SIZE_MB.toString(),
65
+ maxTos: MAX_TOS_SIZE_MB.toString(),
66
+ }));
67
+ }
68
+ if (stats.size > MAX_ZIP_SIZE_BYTES) {
69
+ logger_1.logger.info(lang_1.lang.__('CODE_PACKAGE_EXCEEDS_ZIP_LIMIT', {
70
+ size: sizeMB,
71
+ limit: MAX_ZIP_SIZE_MB.toString(),
72
+ strategy: 'TOS',
73
+ }));
74
+ }
75
+ try {
76
+ const zipContent = await fs.promises.readFile(codePath);
77
+ await Promise.resolve().then(() => __importStar(require('jszip'))).then(async (JSZip) => {
78
+ const zip = await JSZip.loadAsync(zipContent);
79
+ const fileCount = Object.keys(zip.files).length;
80
+ if (fileCount === 0) {
81
+ throw new Error(lang_1.lang.__('CODE_PACKAGE_EMPTY'));
82
+ }
83
+ const hasHandler = Object.keys(zip.files).some((f) => f.endsWith('.js') || f.endsWith('.py') || f.endsWith('.go') || f.endsWith('handler'));
84
+ if (!hasHandler) {
85
+ logger_1.logger.warn(lang_1.lang.__('CODE_PACKAGE_MAY_MISS_HANDLER'));
86
+ }
87
+ });
88
+ }
89
+ catch (error) {
90
+ if (error instanceof Error && error.message.includes('Empty')) {
91
+ throw error;
92
+ }
93
+ const errorMessage = error instanceof Error ? error.message : String(error);
94
+ // eslint-disable-next-line preserve-caught-error
95
+ throw new Error(`${lang_1.lang.__('CODE_PACKAGE_INVALID_ZIP', { error: errorMessage })} (Original: ${errorMessage})`);
96
+ }
97
+ return { size: stats.size, sizeMB };
98
+ };
99
+ const uploadCodeToTos = async (tosClient, bucketName, codePath, functionName) => {
100
+ const codeContent = await fs.promises.readFile(codePath);
101
+ const timestamp = Date.now();
102
+ const key = `function-codes/${functionName}/${timestamp}/code.zip`;
103
+ logger_1.logger.info(lang_1.lang.__('UPLOADING_CODE_TO_TOS', { bucket: bucketName, key }));
104
+ await tosClient.fetchOpenAPI({
105
+ Action: 'PutObject',
106
+ Version: '2018-08-01',
107
+ method: 'PUT',
108
+ headers: {
109
+ 'content-type': 'application/zip',
110
+ 'content-length': codeContent.length.toString(),
111
+ },
112
+ data: codeContent,
113
+ query: {
114
+ bucket: bucketName,
115
+ key: key,
116
+ },
117
+ });
118
+ logger_1.logger.info(lang_1.lang.__('CODE_UPLOADED_TO_TOS', {
119
+ bucket: bucketName,
120
+ key,
121
+ size: (codeContent.length / 1024 / 1024).toFixed(2),
122
+ }));
123
+ return { bucket: bucketName, key };
124
+ };
125
+ const createVefaasOperations = (client) => {
126
+ const tosClient = new openapi_1.Service({
127
+ serviceName: 'tos',
128
+ defaultVersion: '2018-08-01',
129
+ protocol: 'https',
130
+ host: 'tos-cn-beijing.volces.com',
131
+ accessKeyId: client.accessKeyId,
132
+ secretKey: client.secretKey,
133
+ region: client.region,
134
+ });
135
+ return {
136
+ createFunction: async (config, codePath) => {
137
+ const { size, sizeMB } = await validateCodePackage(codePath);
138
+ let codeSource;
139
+ if (size <= MAX_ZIP_SIZE_BYTES) {
140
+ const codeContent = await fs.promises.readFile(codePath);
141
+ const codeBase64 = codeContent.toString('base64');
142
+ logger_1.logger.info(lang_1.lang.__('DEPLOYING_FUNCTION_WITH_ZIP', {
143
+ functionName: config.functionName,
144
+ size: sizeMB,
145
+ }));
146
+ codeSource = {
147
+ SourceType: 'zip',
148
+ Source: codeBase64,
149
+ };
150
+ }
151
+ else {
152
+ const tosBucket = `vefaas-codes-${client.region || 'cn-beijing'}`;
153
+ const { bucket, key } = await uploadCodeToTos(tosClient, tosBucket, codePath, config.functionName);
154
+ logger_1.logger.info(lang_1.lang.__('DEPLOYING_FUNCTION_WITH_TOS', {
155
+ functionName: config.functionName,
156
+ size: sizeMB,
157
+ bucket,
158
+ key,
159
+ }));
160
+ codeSource = {
161
+ SourceType: 'tos',
162
+ TosBucket: bucket,
163
+ TosKey: key,
164
+ };
165
+ }
166
+ const params = {
167
+ FunctionName: config.functionName,
168
+ Runtime: config.runtime,
169
+ Handler: config.handler,
170
+ MemoryMb: config.memoryMb,
171
+ RequestTimeout: config.requestTimeout,
172
+ ...(config.description && { Description: config.description }),
173
+ ...(config.environmentVariables && {
174
+ Envs: buildEnvVariables(config.environmentVariables),
175
+ }),
176
+ ...(config.role && { Role: config.role }),
177
+ ...codeSource,
178
+ ...(config.vpcConfig && {
179
+ VpcConfig: {
180
+ EnableVpc: true,
181
+ VpcId: config.vpcConfig.vpcId,
182
+ SubnetIds: config.vpcConfig.subnetIds,
183
+ SecurityGroupIds: config.vpcConfig.securityGroupIds,
184
+ },
185
+ }),
186
+ ...(config.tosMountConfig && {
187
+ TosMountConfig: {
188
+ EnableTos: true,
189
+ MountPoints: [
190
+ {
191
+ BucketName: config.tosMountConfig.bucketName,
192
+ LocalMountPath: config.tosMountConfig.mountPath,
193
+ },
194
+ ],
195
+ },
196
+ }),
197
+ ...(config.logConfig && {
198
+ LogConfig: {
199
+ EnableLog: true,
200
+ ProjectName: config.logConfig.project,
201
+ TopicName: config.logConfig.topic,
202
+ },
203
+ }),
204
+ };
205
+ await client.fetchOpenAPI({
206
+ Action: 'CreateFunction',
207
+ Version: '2024-06-06',
208
+ method: 'POST',
209
+ headers: { 'content-type': 'application/json' },
210
+ data: params,
211
+ });
212
+ logger_1.logger.info(lang_1.lang.__('FUNCTION_CREATED', { functionName: config.functionName }));
213
+ },
214
+ getFunction: async (functionName) => {
215
+ try {
216
+ const response = await client.fetchOpenAPI({
217
+ Action: 'GetFunction',
218
+ Version: '2024-06-06',
219
+ method: 'POST',
220
+ headers: { 'content-type': 'application/json' },
221
+ data: { FunctionName: functionName },
222
+ });
223
+ const data = (response.Result || {});
224
+ return {
225
+ functionId: data.FunctionId,
226
+ functionName: data.FunctionName,
227
+ runtime: data.Runtime,
228
+ handler: data.Handler,
229
+ memoryMb: data.MemoryMb,
230
+ requestTimeout: data.RequestTimeout,
231
+ description: data.Description,
232
+ environmentVariables: parseEnvVariables(data.Envs),
233
+ status: data.Status,
234
+ createdTime: data.CreationTime,
235
+ lastModifiedTime: data.LastUpdateTime,
236
+ role: data.Role,
237
+ vpcConfig: data.VpcConfig
238
+ ? {
239
+ vpcId: data.VpcConfig.VpcId,
240
+ subnetIds: data.VpcConfig.SubnetIds,
241
+ securityGroupIds: data.VpcConfig.SecurityGroupIds,
242
+ }
243
+ : undefined,
244
+ logConfig: data.LogConfig
245
+ ? {
246
+ project: data.LogConfig.ProjectName,
247
+ topic: data.LogConfig.TopicName,
248
+ }
249
+ : undefined,
250
+ };
251
+ }
252
+ catch (error) {
253
+ if (error && typeof error === 'object' && 'code' in error) {
254
+ if (error.code === 'ResourceNotFound' || error.code === 'FunctionNotFound') {
255
+ return null;
256
+ }
257
+ }
258
+ throw error;
259
+ }
260
+ },
261
+ updateFunctionConfiguration: async (config) => {
262
+ const params = {
263
+ FunctionName: config.functionName,
264
+ Handler: config.handler,
265
+ Runtime: config.runtime,
266
+ MemoryMb: config.memoryMb,
267
+ RequestTimeout: config.requestTimeout,
268
+ ...(config.description !== undefined && { Description: config.description }),
269
+ ...(config.environmentVariables && {
270
+ Envs: buildEnvVariables(config.environmentVariables),
271
+ }),
272
+ ...(config.role && { Role: config.role }),
273
+ ...(config.vpcConfig && {
274
+ VpcConfig: {
275
+ EnableVpc: true,
276
+ VpcId: config.vpcConfig.vpcId,
277
+ SubnetIds: config.vpcConfig.subnetIds,
278
+ SecurityGroupIds: config.vpcConfig.securityGroupIds,
279
+ },
280
+ }),
281
+ ...(config.tosMountConfig && {
282
+ TosMountConfig: {
283
+ EnableTos: true,
284
+ MountPoints: [
285
+ {
286
+ BucketName: config.tosMountConfig.bucketName,
287
+ LocalMountPath: config.tosMountConfig.mountPath,
288
+ },
289
+ ],
290
+ },
291
+ }),
292
+ ...(config.logConfig && {
293
+ LogConfig: {
294
+ EnableLog: true,
295
+ ProjectName: config.logConfig.project,
296
+ TopicName: config.logConfig.topic,
297
+ },
298
+ }),
299
+ };
300
+ await client.fetchOpenAPI({
301
+ Action: 'UpdateFunction',
302
+ Version: '2024-06-06',
303
+ method: 'POST',
304
+ headers: { 'content-type': 'application/json' },
305
+ data: params,
306
+ });
307
+ logger_1.logger.info(lang_1.lang.__('FUNCTION_CONFIGURATION_UPDATED', { functionName: config.functionName }));
308
+ },
309
+ updateFunctionCode: async (functionName, codePath) => {
310
+ const { size, sizeMB } = await validateCodePackage(codePath);
311
+ let codeSource;
312
+ if (size <= MAX_ZIP_SIZE_BYTES) {
313
+ const codeContent = await fs.promises.readFile(codePath);
314
+ const codeBase64 = codeContent.toString('base64');
315
+ logger_1.logger.info(lang_1.lang.__('UPDATING_FUNCTION_CODE_WITH_ZIP', {
316
+ functionName,
317
+ size: sizeMB,
318
+ }));
319
+ codeSource = {
320
+ SourceType: 'zip',
321
+ Source: codeBase64,
322
+ };
323
+ }
324
+ else {
325
+ const tosBucket = `vefaas-codes-${client.region || 'cn-beijing'}`;
326
+ const { bucket, key } = await uploadCodeToTos(tosClient, tosBucket, codePath, functionName);
327
+ logger_1.logger.info(lang_1.lang.__('UPDATING_FUNCTION_CODE_WITH_TOS', {
328
+ functionName,
329
+ size: sizeMB,
330
+ bucket,
331
+ key,
332
+ }));
333
+ codeSource = {
334
+ SourceType: 'tos',
335
+ TosBucket: bucket,
336
+ TosKey: key,
337
+ };
338
+ }
339
+ await client.fetchOpenAPI({
340
+ Action: 'UpdateFunction',
341
+ Version: '2024-06-06',
342
+ method: 'POST',
343
+ headers: { 'content-type': 'application/json' },
344
+ data: {
345
+ FunctionName: functionName,
346
+ ...codeSource,
347
+ },
348
+ });
349
+ logger_1.logger.info(lang_1.lang.__('FUNCTION_CODE_UPDATED', { functionName }));
350
+ },
351
+ deleteFunction: async (functionName) => {
352
+ await client.fetchOpenAPI({
353
+ Action: 'DeleteFunction',
354
+ Version: '2024-06-06',
355
+ method: 'POST',
356
+ headers: { 'content-type': 'application/json' },
357
+ data: { FunctionName: functionName },
358
+ });
359
+ logger_1.logger.info(lang_1.lang.__('FUNCTION_DELETED', { functionName }));
360
+ },
361
+ listFunctions: async () => {
362
+ const response = await client.fetchOpenAPI({
363
+ Action: 'ListFunctions',
364
+ Version: '2024-06-06',
365
+ method: 'POST',
366
+ headers: { 'content-type': 'application/json' },
367
+ data: {},
368
+ });
369
+ const result = (response.Result || {});
370
+ const functions = (result.Functions || []);
371
+ return functions.map((fn) => ({
372
+ functionId: fn.FunctionId,
373
+ functionName: fn.FunctionName,
374
+ runtime: fn.Runtime,
375
+ handler: fn.Handler,
376
+ memoryMb: fn.MemoryMb,
377
+ requestTimeout: fn.RequestTimeout,
378
+ description: fn.Description,
379
+ status: fn.Status,
380
+ createdTime: fn.CreationTime,
381
+ lastModifiedTime: fn.LastUpdateTime,
382
+ }));
383
+ },
384
+ };
385
+ };
386
+ exports.createVefaasOperations = createVefaasOperations;
@@ -522,4 +522,124 @@ exports.en = {
522
522
  RETRY_ATTEMPT_FAILED: '{{operation}} attempt {{attempt}}/{{max}} failed: {{error}}. Retrying...',
523
523
  RETRY_ALL_ATTEMPTS_FAILED: '{{operation}} failed after {{max}} attempts: {{error}}',
524
524
  RETRY_UNEXPECTED_FAILURE: '{{operation}} failed unexpectedly',
525
+ // Rate Limit messages
526
+ RATE_LIMIT_CREATING: 'Creating traffic control policy: {{policyName}}',
527
+ RATE_LIMIT_CREATED: 'Traffic control policy created: {{policyName}} (ID: {{policyId}})',
528
+ RATE_LIMIT_UPDATING: 'Updating traffic control policy: {{policyName}}',
529
+ RATE_LIMIT_UPDATED: 'Traffic control policy updated: {{policyName}}',
530
+ RATE_LIMIT_DELETING: 'Deleting traffic control policy: {{policyId}}',
531
+ RATE_LIMIT_DELETED: 'Traffic control policy deleted: {{policyId}}',
532
+ RATE_LIMIT_BINDING: 'Binding traffic control {{policyId}} to APIs in group {{groupId}}',
533
+ RATE_LIMIT_BOUND: 'Traffic control {{policyId}} bound to {{apiCount}} API(s)',
534
+ RATE_LIMIT_UNBINDING: 'Unbinding traffic control from APIs in group {{groupId}}',
535
+ RATE_LIMIT_UNBOUND: 'Traffic control unbound from APIs in group {{groupId}}',
536
+ RATE_LIMIT_NOT_FOUND: 'Traffic control policy not found: {{policyId}}',
537
+ RATE_LIMIT_CREATE_FAILED: 'Failed to create traffic control policy: {{error}}',
538
+ RATE_LIMIT_UPDATE_FAILED: 'Failed to update traffic control policy: {{error}}',
539
+ RATE_LIMIT_DELETE_FAILED: 'Failed to delete traffic control policy: {{error}}',
540
+ RATE_LIMIT_BIND_FAILED: 'Failed to bind traffic control to APIs: {{error}}',
541
+ RATE_LIMIT_UNBIND_FAILED: 'Failed to unbind traffic control from APIs: {{error}}',
542
+ RATE_LIMIT_CONFIG_INVALID: 'Invalid rate_limit configuration: must specify either qps or scopes',
543
+ RATE_LIMIT_SCOPE_INVALID: 'Rate limit scope "{{scope}}" is not supported by provider "{{provider}}"',
544
+ RATE_LIMIT_LIMITBY_REQUIRES_NAME: 'Rate limit limit_by type "{{type}}" requires a "name" parameter',
545
+ RATE_LIMIT_SKIPPED_WARNING: 'Rate limit creation failed but API deployment succeeded. You can retry by running deploy again.',
546
+ // Volcengine provider messages
547
+ PROVIDER_VOLCENGINE: 'Volcengine',
548
+ VOLCENGINE_DEPLOYING_STACK: 'Deploying stack to Volcengine...',
549
+ VOLCENGINE_CREATING_FUNCTION: 'Creating Volcengine function {{functionName}}',
550
+ VOLCENGINE_UPDATING_FUNCTION: 'Updating Volcengine function {{functionName}}',
551
+ VOLCENGINE_DELETING_FUNCTION: 'Deleting Volcengine function {{functionName}}',
552
+ VOLCENGINE_FUNCTION_NOT_FOUND: 'Volcengine function {{functionName}} not found',
553
+ VOLCENGINE_FUNCTION_READY: 'Volcengine function {{functionName}} is ready',
554
+ VOLCENGINE_CREATING_BUCKET: 'Creating Volcengine TOS bucket {{bucketName}}',
555
+ VOLCENGINE_DELETING_BUCKET: 'Deleting Volcengine TOS bucket {{bucketName}}',
556
+ VOLCENGINE_BUCKET_NOT_FOUND: 'Volcengine TOS bucket {{bucketName}} not found',
557
+ VOLCENGINE_CREATING_ROLE: 'Creating Volcengine IAM role {{roleName}}',
558
+ VOLCENGINE_DELETING_ROLE: 'Deleting Volcengine IAM role {{roleName}}',
559
+ VOLCENGINE_ROLE_NOT_FOUND: 'Volcengine IAM role {{roleName}} not found',
560
+ VOLCENGINE_CREATING_APIGW: 'Creating Volcengine API Gateway {{gatewayName}}',
561
+ VOLCENGINE_DELETING_APIGW: 'Deleting Volcengine API Gateway {{gatewayName}}',
562
+ VOLCENGINE_APIGW_NOT_FOUND: 'Volcengine API Gateway {{gatewayName}} not found',
563
+ // Additional Volcengine-specific messages
564
+ RESOURCE_STATE_NOT_FOUND: 'Resource state not found for logical ID: {{logicalId}}',
565
+ RESOURCE_INSTANCE_NOT_FOUND: 'Resource instance not found for logical ID: {{logicalId}}',
566
+ UPDATING_RESOURCE_WITH_NO_CHANGES: 'No changes detected for {{resourceType}}: {{name}}',
567
+ // Code deployment messages
568
+ CODE_PACKAGE_TOO_LARGE: 'Code package size ({{size}} MB) exceeds maximum limit. Max ZIP: {{maxZip}} MB, Max TOS: {{maxTos}} MB',
569
+ CODE_PACKAGE_EXCEEDS_ZIP_LIMIT: 'Code package ({{size}} MB) exceeds ZIP limit ({{limit}} MB), using TOS upload strategy',
570
+ CODE_PACKAGE_EMPTY: 'Code package is empty',
571
+ CODE_PACKAGE_MAY_MISS_HANDLER: 'Code package may not contain a handler file',
572
+ CODE_PACKAGE_INVALID_ZIP: 'Invalid ZIP package: {{error}}',
573
+ DEPLOYING_FUNCTION_WITH_ZIP: 'Deploying function {{functionName}} with ZIP package ({{size}} MB)',
574
+ DEPLOYING_FUNCTION_WITH_TOS: 'Deploying function {{functionName}} with TOS ({{size}} MB) to {{bucket}}/{{key}}',
575
+ UPLOADING_CODE_TO_TOS: 'Uploading code to TOS: {{bucket}}/{{key}}',
576
+ CODE_UPLOADED_TO_TOS: 'Code uploaded to TOS: {{bucket}}/{{key}} ({{size}} MB)',
577
+ FUNCTION_CREATED: 'Function {{functionName}} created successfully',
578
+ FUNCTION_CONFIGURATION_UPDATED: 'Function {{functionName}} configuration updated',
579
+ UPDATING_FUNCTION_CODE_WITH_ZIP: 'Updating function {{functionName}} code with ZIP package ({{size}} MB)',
580
+ UPDATING_FUNCTION_CODE_WITH_TOS: 'Updating function {{functionName}} code with TOS ({{size}} MB) to {{bucket}}/{{key}}',
581
+ FUNCTION_CODE_UPDATED: 'Function {{functionName}} code updated',
582
+ FUNCTION_DELETED: 'Function {{functionName}} deleted',
583
+ // TOS Object Storage messages
584
+ TOS_BUCKET_CREATED: 'TOS bucket {{bucketName}} created successfully',
585
+ TOS_BUCKET_DELETED: 'TOS bucket {{bucketName}} deleted successfully',
586
+ TOS_BUCKET_ACL_UPDATED: 'TOS bucket {{bucketName}} ACL updated to {{acl}}',
587
+ TOS_BUCKET_WEBSITE_CONFIGURED: 'TOS bucket {{bucketName}} website configured',
588
+ TOS_BUCKET_WEBSITE_UPDATED: 'TOS bucket {{bucketName}} website configuration updated',
589
+ TOS_BUCKET_NOT_FOUND: 'TOS bucket {{bucketName}} not found',
590
+ TOS_BUCKET_TRACKED_CAN_RETRY: 'Bucket is tracked in state, you can retry deployment to upload files',
591
+ TOS_BUCKET_FILE_UPLOAD_FAILED_STATE_SAVED: 'Failed to upload files to bucket, but bucket was created and saved to state: {{error}}',
592
+ TOS_OBJECT_UPLOADED: 'Uploaded object {{key}} to bucket {{bucket}}',
593
+ TOS_FILES_UPLOADED: 'Uploaded files from {{path}} to bucket {{bucket}}',
594
+ VOLCENGINE_TOS_CLIENT_NOT_INITIALIZED: 'TOS client not initialized. Check your credentials.',
595
+ VOLCENGINE_BUCKET_DELETE_FAILED: 'Failed to delete bucket {{bucketName}}: {{error}}',
596
+ VOLCENGINE_FUNCTION_DELETE_FAILED: 'Failed to delete function {{functionName}}: {{error}}',
597
+ VOLCENGINE_APIGW_CLIENT_NOT_INITIALIZED: 'API Gateway client not initialized. Check your credentials.',
598
+ VOLCENGINE_APIGW_DELETE_FAILED: 'Failed to delete API Gateway {{logicalId}}: {{error}}',
599
+ // Volcengine IAM messages
600
+ IAM_ROLE_CREATED: 'IAM role {{roleName}} created successfully',
601
+ IAM_ROLE_DELETED: 'IAM role {{roleName}} deleted successfully',
602
+ IAM_ROLE_ALREADY_EXISTS: 'IAM role "{{roleName}}" already exists in cloud (state drift detected). ' +
603
+ 'Updating trust policy and reusing existing role.',
604
+ IAM_ROLE_NOT_FOUND_IN_CLOUD: 'IAM role "{{roleName}}" does not exist in the cloud provider. ' +
605
+ 'The role may have been deleted manually. ' +
606
+ 'To fix: remove the role from state and redeploy.',
607
+ IAM_ROLE_DRIFT_RECOVERY_FAILED: 'Failed to recover from IAM role state drift for "{{roleName}}": {{error}}. ' +
608
+ 'The role existed in the cloud but recovery operations failed. ' +
609
+ 'To fix: manually verify the role in the cloud console, remove it from state, and redeploy.',
610
+ IAM_ROLE_TRUST_POLICY_UPDATED: 'IAM role {{roleName}} trust policy updated',
611
+ IAM_POLICY_ALREADY_EXISTS: 'IAM policy {{policyName}} already exists, reusing',
612
+ IAM_POLICY_ALREADY_ATTACHED: 'IAM policy {{policyName}} already attached to role {{roleName}}',
613
+ IAM_POLICY_ATTACHED: 'IAM policy {{policyName}} attached to role {{roleName}}',
614
+ IAM_POLICY_DETACHED: 'IAM policy {{policyName}} detached from role {{roleName}}',
615
+ IAM_ROLE_INSTANCE_NOT_FOUND: 'IAM role instance not found in state for {{roleName}}',
616
+ IAM_ROLE_TRN_MISSING: 'IAM role TRN is missing and accountId is not available to construct it for {{roleName}}. ' +
617
+ 'Ensure the IAM role was created successfully and accountId is configured.',
618
+ CREATING_IAM_ROLE: 'Creating IAM role: {{roleName}}',
619
+ DELETING_IAM_ROLE: 'Deleting IAM role: {{id}}',
620
+ IAM_POLICY_DETACH_FAILED: 'Failed to detach IAM policy {{policyName}} from role {{roleName}}: {{error}}',
621
+ // Volcengine TLS (Log Service) messages
622
+ TLS_PROJECT_CREATED: 'TLS project {{projectName}} created successfully',
623
+ TLS_PROJECT_DELETED: 'TLS project {{projectName}} deleted successfully',
624
+ TLS_PROJECT_NOT_FOUND: 'TLS project {{projectName}} not found',
625
+ TLS_PROJECT_TIMEOUT: 'Timeout waiting for TLS project {{projectName}} to be ready',
626
+ TLS_TOPIC_CREATED: 'TLS topic {{topicName}} created successfully',
627
+ TLS_TOPIC_DELETED: 'TLS topic {{topicName}} deleted successfully',
628
+ TLS_TOPIC_NOT_FOUND: 'TLS topic {{topicName}} not found',
629
+ TLS_TOPIC_TIMEOUT: 'Timeout waiting for TLS topic {{topicName}} to be ready',
630
+ TLS_INDEX_CREATED: 'TLS index for topic {{topicName}} created successfully',
631
+ TLS_INDEX_DELETED: 'TLS index for topic {{topicName}} deleted successfully',
632
+ TLS_PROJECT_FAILED: 'TLS project {{projectName}} failed to create',
633
+ TLS_TOPIC_FAILED: 'TLS topic {{topicName}} failed to create',
634
+ CREATING_TLS_PROJECT: 'Creating TLS project: {{projectName}}',
635
+ CREATING_TLS_TOPIC: 'Creating TLS topic: {{topicName}}',
636
+ CREATING_TLS_INDEX: 'Creating TLS index for topic: {{topicName}}',
637
+ DELETING_TLS_PROJECT: 'Deleting TLS project: {{id}}',
638
+ DELETING_TLS_TOPIC: 'Deleting TLS topic: {{id}}',
639
+ DELETING_TLS_INDEX: 'Deleting TLS index: {{id}}',
640
+ WAITING_FOR_TLS_RESOURCES: 'Waiting for TLS resources to be ready: {{projectName}}/{{topicName}}',
641
+ // Volcengine veFaaS dependent resources
642
+ VEFAAS_DEPENDENT_RESOURCES_TRACKED: 'Dependent resources (TLS, IAM) are tracked in state',
643
+ VEFAAS_CAN_RETRY_DEPLOYMENT: 'You can retry deployment - the system will reuse existing dependent resources',
644
+ VEFAAS_FUNCTION_EXISTS_RECOVERY: 'Function {{functionName}} already exists in provider (tainted recovery), skipping create and refreshing state',
525
645
  };
@@ -517,4 +517,123 @@ exports.zhCN = {
517
517
  RETRY_ATTEMPT_FAILED: '{{operation}} 第 {{attempt}}/{{max}} 次尝试失败:{{error}}。正在重试...',
518
518
  RETRY_ALL_ATTEMPTS_FAILED: '{{operation}} 在 {{max}} 次尝试后失败:{{error}}',
519
519
  RETRY_UNEXPECTED_FAILURE: '{{operation}} 意外失败',
520
+ // 流量限制消息
521
+ RATE_LIMIT_CREATING: '正在创建流量控制策略:{{policyName}}',
522
+ RATE_LIMIT_CREATED: '流量控制策略已创建:{{policyName}}(ID: {{policyId}})',
523
+ RATE_LIMIT_UPDATING: '正在更新流量控制策略:{{policyName}}',
524
+ RATE_LIMIT_UPDATED: '流量控制策略已更新:{{policyName}}',
525
+ RATE_LIMIT_DELETING: '正在删除流量控制策略:{{policyId}}',
526
+ RATE_LIMIT_DELETED: '流量控制策略已删除:{{policyId}}',
527
+ RATE_LIMIT_BINDING: '正在将流量控制 {{policyId}} 绑定到分组 {{groupId}} 的 API',
528
+ RATE_LIMIT_BOUND: '流量控制 {{policyId}} 已绑定到 {{apiCount}} 个 API',
529
+ RATE_LIMIT_UNBINDING: '正在解除分组 {{groupId}} 中 API 的流量控制绑定',
530
+ RATE_LIMIT_UNBOUND: '已解除分组 {{groupId}} 中 API 的流量控制绑定',
531
+ RATE_LIMIT_NOT_FOUND: '未找到流量控制策略:{{policyId}}',
532
+ RATE_LIMIT_CREATE_FAILED: '创建流量控制策略失败:{{error}}',
533
+ RATE_LIMIT_UPDATE_FAILED: '更新流量控制策略失败:{{error}}',
534
+ RATE_LIMIT_DELETE_FAILED: '删除流量控制策略失败:{{error}}',
535
+ RATE_LIMIT_BIND_FAILED: '绑定流量控制到 API 失败:{{error}}',
536
+ RATE_LIMIT_UNBIND_FAILED: '解除流量控制绑定失败:{{error}}',
537
+ RATE_LIMIT_CONFIG_INVALID: '无效的 rate_limit 配置:必须指定 qps 或 scopes',
538
+ RATE_LIMIT_SCOPE_INVALID: '流量限制范围 "{{scope}}" 不被提供商 "{{provider}}" 支持',
539
+ RATE_LIMIT_LIMITBY_REQUIRES_NAME: '流量限制 limit_by 类型 "{{type}}" 需要指定 "name" 参数',
540
+ RATE_LIMIT_SKIPPED_WARNING: '流量控制创建失败但 API 部署成功。您可以重新运行 deploy 重试。',
541
+ // Volcengine provider messages
542
+ PROVIDER_VOLCENGINE: '火山引擎',
543
+ VOLCENGINE_DEPLOYING_STACK: '正在部署资源栈到火山引擎...',
544
+ VOLCENGINE_CREATING_FUNCTION: '正在创建火山引擎函数 {{functionName}}',
545
+ VOLCENGINE_UPDATING_FUNCTION: '正在更新火山引擎函数 {{functionName}}',
546
+ VOLCENGINE_DELETING_FUNCTION: '正在删除火山引擎函数 {{functionName}}',
547
+ VOLCENGINE_FUNCTION_NOT_FOUND: '火山引擎函数 {{functionName}} 未找到',
548
+ VOLCENGINE_FUNCTION_READY: '火山引擎函数 {{functionName}} 已就绪',
549
+ VOLCENGINE_CREATING_BUCKET: '正在创建火山引擎 TOS 存储桶 {{bucketName}}',
550
+ VOLCENGINE_DELETING_BUCKET: '正在删除火山引擎 TOS 存储桶 {{bucketName}}',
551
+ VOLCENGINE_BUCKET_NOT_FOUND: '火山引擎 TOS 存储桶 {{bucketName}} 未找到',
552
+ VOLCENGINE_CREATING_ROLE: '正在创建火山引擎 IAM 角色 {{roleName}}',
553
+ VOLCENGINE_DELETING_ROLE: '正在删除火山引擎 IAM 角色 {{roleName}}',
554
+ VOLCENGINE_ROLE_NOT_FOUND: '火山引擎 IAM 角色 {{roleName}} 未找到',
555
+ VOLCENGINE_CREATING_APIGW: '正在创建火山引擎 API 网关 {{gatewayName}}',
556
+ VOLCENGINE_DELETING_APIGW: '正在删除火山引擎 API 网关 {{gatewayName}}',
557
+ VOLCENGINE_APIGW_NOT_FOUND: '火山引擎 API 网关 {{gatewayName}} 未找到',
558
+ // Additional Volcengine-specific messages
559
+ RESOURCE_STATE_NOT_FOUND: '未找到逻辑 ID 为 {{logicalId}} 的资源状态',
560
+ RESOURCE_INSTANCE_NOT_FOUND: '未找到逻辑 ID 为 {{logicalId}} 的资源实例',
561
+ UPDATING_RESOURCE_WITH_NO_CHANGES: '未检测到 {{resourceType}}: {{name}} 的变更',
562
+ // Code deployment messages
563
+ CODE_PACKAGE_TOO_LARGE: '代码包大小 ({{size}} MB) 超过最大限制。ZIP 最大:{{maxZip}} MB, TOS 最大:{{maxTos}} MB',
564
+ CODE_PACKAGE_EXCEEDS_ZIP_LIMIT: '代码包 ({{size}} MB) 超过 ZIP 限制 ({{limit}} MB),使用 TOS 上传策略',
565
+ CODE_PACKAGE_EMPTY: '代码包为空',
566
+ CODE_PACKAGE_MAY_MISS_HANDLER: '代码包可能不包含处理函数文件',
567
+ CODE_PACKAGE_INVALID_ZIP: '无效的 ZIP 包:{{error}}',
568
+ DEPLOYING_FUNCTION_WITH_ZIP: '正在部署函数 {{functionName}},使用 ZIP 包 ({{size}} MB)',
569
+ DEPLOYING_FUNCTION_WITH_TOS: '正在部署函数 {{functionName}},使用 TOS ({{size}} MB) 到 {{bucket}}/{{key}}',
570
+ UPLOADING_CODE_TO_TOS: '正在上传代码到 TOS: {{bucket}}/{{key}}',
571
+ CODE_UPLOADED_TO_TOS: '代码已上传到 TOS: {{bucket}}/{{key}} ({{size}} MB)',
572
+ FUNCTION_CREATED: '函数 {{functionName}} 创建成功',
573
+ FUNCTION_CONFIGURATION_UPDATED: '函数 {{functionName}} 配置已更新',
574
+ UPDATING_FUNCTION_CODE_WITH_ZIP: '正在更新函数 {{functionName}} 代码,使用 ZIP 包 ({{size}} MB)',
575
+ UPDATING_FUNCTION_CODE_WITH_TOS: '正在更新函数 {{functionName}} 代码,使用 TOS ({{size}} MB) 到 {{bucket}}/{{key}}',
576
+ FUNCTION_CODE_UPDATED: '函数 {{functionName}} 代码已更新',
577
+ FUNCTION_DELETED: '函数 {{functionName}} 已删除',
578
+ // TOS Object Storage messages
579
+ TOS_BUCKET_CREATED: 'TOS 存储桶 {{bucketName}} 创建成功',
580
+ TOS_BUCKET_DELETED: 'TOS 存储桶 {{bucketName}} 删除成功',
581
+ TOS_BUCKET_ACL_UPDATED: 'TOS 存储桶 {{bucketName}} ACL 已更新为 {{acl}}',
582
+ TOS_BUCKET_WEBSITE_CONFIGURED: 'TOS 存储桶 {{bucketName}} 静态网站已配置',
583
+ TOS_BUCKET_WEBSITE_UPDATED: 'TOS 存储桶 {{bucketName}} 静态网站配置已更新',
584
+ TOS_BUCKET_NOT_FOUND: 'TOS 存储桶 {{bucketName}} 未找到',
585
+ TOS_BUCKET_TRACKED_CAN_RETRY: '存储桶已在状态中跟踪,您可以重试部署以上传文件',
586
+ TOS_BUCKET_FILE_UPLOAD_FAILED_STATE_SAVED: '上传文件到存储桶失败,但存储桶已创建并保存到状态:{{error}}',
587
+ TOS_OBJECT_UPLOADED: '已上传对象 {{key}} 到存储桶 {{bucket}}',
588
+ TOS_FILES_UPLOADED: '已从 {{path}} 上传文件到存储桶 {{bucket}}',
589
+ VOLCENGINE_TOS_CLIENT_NOT_INITIALIZED: 'TOS 客户端未初始化。请检查您的凭证。',
590
+ VOLCENGINE_BUCKET_DELETE_FAILED: '删除存储桶 {{bucketName}} 失败:{{error}}',
591
+ VOLCENGINE_FUNCTION_DELETE_FAILED: '删除函数 {{functionName}} 失败:{{error}}',
592
+ VOLCENGINE_APIGW_CLIENT_NOT_INITIALIZED: 'API 网关客户端未初始化。请检查您的凭证。',
593
+ VOLCENGINE_APIGW_DELETE_FAILED: '删除 API 网关 {{logicalId}} 失败:{{error}}',
594
+ // Volcengine IAM messages
595
+ IAM_ROLE_CREATED: 'IAM 角色 {{roleName}} 创建成功',
596
+ IAM_ROLE_DELETED: 'IAM 角色 {{roleName}} 删除成功',
597
+ IAM_ROLE_ALREADY_EXISTS: 'IAM 角色 "{{roleName}}" 在云端已存在(检测到状态漂移)。' + '正在更新信任策略并复用现有角色。',
598
+ IAM_ROLE_NOT_FOUND_IN_CLOUD: '云提供商中不存在 IAM 角色 "{{roleName}}"。' +
599
+ '该角色可能已被手动删除。' +
600
+ '修复方法:从状态中移除该角色并重新部署。',
601
+ IAM_ROLE_DRIFT_RECOVERY_FAILED: 'IAM 角色 "{{roleName}}" 状态漂移恢复失败:{{error}}。' +
602
+ '角色在云端存在但恢复操作失败。' +
603
+ '修复方法:在云控制台手动确认角色状态,从状态中移除该角色并重新部署。',
604
+ IAM_ROLE_TRUST_POLICY_UPDATED: 'IAM 角色 {{roleName}} 信任策略已更新',
605
+ IAM_POLICY_ALREADY_EXISTS: 'IAM 策略 {{policyName}} 已存在,复用现有策略',
606
+ IAM_POLICY_ALREADY_ATTACHED: 'IAM 策略 {{policyName}} 已附加到角色 {{roleName}}',
607
+ IAM_POLICY_ATTACHED: 'IAM 策略 {{policyName}} 已附加到角色 {{roleName}}',
608
+ IAM_POLICY_DETACHED: 'IAM 策略 {{policyName}} 已从角色 {{roleName}} 分离',
609
+ IAM_ROLE_INSTANCE_NOT_FOUND: 'IAM 角色实例在状态中未找到:{{roleName}}',
610
+ IAM_ROLE_TRN_MISSING: 'IAM 角色 TRN 缺失且无法获取 accountId 来构造 {{roleName}} 的 TRN。' +
611
+ '请确保 IAM 角色创建成功且 accountId 已配置。',
612
+ CREATING_IAM_ROLE: '正在创建 IAM 角色:{{roleName}}',
613
+ DELETING_IAM_ROLE: '正在删除 IAM 角色:{{id}}',
614
+ IAM_POLICY_DETACH_FAILED: '从角色 {{roleName}} 解除 IAM 策略 {{policyName}} 失败:{{error}}',
615
+ // Volcengine TLS (Log Service) messages
616
+ TLS_PROJECT_CREATED: 'TLS 项目 {{projectName}} 创建成功',
617
+ TLS_PROJECT_DELETED: 'TLS 项目 {{projectName}} 删除成功',
618
+ TLS_PROJECT_NOT_FOUND: 'TLS 项目 {{projectName}} 未找到',
619
+ TLS_PROJECT_TIMEOUT: '等待 TLS 项目 {{projectName}} 就绪超时',
620
+ TLS_TOPIC_CREATED: 'TLS 主题 {{topicName}} 创建成功',
621
+ TLS_TOPIC_DELETED: 'TLS 主题 {{topicName}} 删除成功',
622
+ TLS_TOPIC_NOT_FOUND: 'TLS 主题 {{topicName}} 未找到',
623
+ TLS_TOPIC_TIMEOUT: '等待 TLS 主题 {{topicName}} 就绪超时',
624
+ TLS_INDEX_CREATED: 'TLS 主题 {{topicName}} 索引创建成功',
625
+ TLS_INDEX_DELETED: 'TLS 主题 {{topicName}} 索引删除成功',
626
+ TLS_PROJECT_FAILED: 'TLS 项目 {{projectName}} 创建失败',
627
+ TLS_TOPIC_FAILED: 'TLS 主题 {{topicName}} 创建失败',
628
+ CREATING_TLS_PROJECT: '正在创建 TLS 项目:{{projectName}}',
629
+ CREATING_TLS_TOPIC: '正在创建 TLS 主题:{{topicName}}',
630
+ CREATING_TLS_INDEX: '正在为 TLS 主题创建索引:{{topicName}}',
631
+ DELETING_TLS_PROJECT: '正在删除 TLS 项目:{{id}}',
632
+ DELETING_TLS_TOPIC: '正在删除 TLS 主题:{{id}}',
633
+ DELETING_TLS_INDEX: '正在删除 TLS 索引:{{id}}',
634
+ WAITING_FOR_TLS_RESOURCES: '等待 TLS 资源就绪:{{projectName}}/{{topicName}}',
635
+ // Volcengine veFaaS dependent resources
636
+ VEFAAS_DEPENDENT_RESOURCES_TRACKED: '依赖资源(TLS、IAM)已在状态中跟踪',
637
+ VEFAAS_CAN_RETRY_DEPLOYMENT: '您可以重试部署 - 系统将复用现有的依赖资源',
638
+ VEFAAS_FUNCTION_EXISTS_RECOVERY: '函数 {{functionName}} 在提供商中已存在(状态恢复中),跳过创建并刷新状态',
520
639
  };
@@ -4,6 +4,7 @@ exports.deployStack = void 0;
4
4
  const common_1 = require("../common");
5
5
  const scfStack_1 = require("./scfStack");
6
6
  const aliyunStack_1 = require("./aliyunStack");
7
+ const volcengineStack_1 = require("./volcengineStack");
7
8
  const deployHuawei = async () => {
8
9
  throw new Error('Huawei deployment is not yet implemented. ' +
9
10
  'The provider currently generates HCL templates but does not deploy them. ' +
@@ -19,5 +20,8 @@ const deployStack = async (iac, backend) => {
19
20
  else if (iac.provider.name === common_1.ProviderEnum.HUAWEI) {
20
21
  await deployHuawei();
21
22
  }
23
+ else if (iac.provider.name === common_1.ProviderEnum.VOLCENGINE) {
24
+ await (0, volcengineStack_1.deployVolcengineStack)(iac, backend);
25
+ }
22
26
  };
23
27
  exports.deployStack = deployStack;