@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,87 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.executeApigwPlan = void 0;
4
+ const apigwResource_1 = require("./apigwResource");
5
+ const common_1 = require("../../common");
6
+ const stateManager_1 = require("../../common/stateManager");
7
+ const lang_1 = require("../../lang");
8
+ const executeSingleItem = async (context, item, eventsMap, serviceName, currentState) => {
9
+ switch (item.action) {
10
+ case 'noop':
11
+ common_1.logger.info(lang_1.lang.__('NO_CHANGESForResource', { logicalId: item.logicalId }));
12
+ return null;
13
+ case 'create': {
14
+ const event = eventsMap.get(item.logicalId);
15
+ if (!event) {
16
+ throw new Error(`Event not found for logical ID: ${item.logicalId}`);
17
+ }
18
+ common_1.logger.info(lang_1.lang.__('CREATING_RESOURCE', { resourceType: 'API Gateway resources', name: event.name }));
19
+ const newState = await (0, apigwResource_1.createApigwResource)(context, event, serviceName, currentState);
20
+ common_1.logger.info(lang_1.lang.__('RESOURCE_CREATED', { resourceType: 'API Gateway resources', name: event.name }));
21
+ return newState;
22
+ }
23
+ case 'update': {
24
+ const event = eventsMap.get(item.logicalId);
25
+ if (!event) {
26
+ throw new Error(`Event not found for logical ID: ${item.logicalId}`);
27
+ }
28
+ common_1.logger.info(lang_1.lang.__('UPDATING_RESOURCE', { resourceType: 'API Gateway resources', name: event.name }));
29
+ const newState = await (0, apigwResource_1.updateApigwResource)(context, event, serviceName, currentState);
30
+ common_1.logger.info(lang_1.lang.__('RESOURCE_UPDATED', { resourceType: 'API Gateway resources', name: event.name }));
31
+ return newState;
32
+ }
33
+ case 'delete': {
34
+ const state = (0, stateManager_1.getResource)(currentState, item.logicalId);
35
+ if (!state) {
36
+ common_1.logger.warn(lang_1.lang.__('STATE_NOT_FOUND_SKIPPING', { logicalId: item.logicalId }));
37
+ return null;
38
+ }
39
+ common_1.logger.info(lang_1.lang.__('DELETING_RESOURCE', {
40
+ resourceType: 'API Gateway resources',
41
+ name: item.logicalId,
42
+ }));
43
+ const newState = await (0, apigwResource_1.deleteApigwResource)(context, item.logicalId, currentState);
44
+ common_1.logger.info(lang_1.lang.__('RESOURCE_DELETED', {
45
+ resourceType: 'API Gateway resources',
46
+ name: item.logicalId,
47
+ }));
48
+ return newState;
49
+ }
50
+ default:
51
+ common_1.logger.warn(lang_1.lang.__('UNKNOWN_ACTION_FOR_RESOURCE', { action: item.action, logicalId: item.logicalId }));
52
+ return null;
53
+ }
54
+ };
55
+ const executeApigwPlan = async (context, plan, events, serviceName, initialState, onStateChange) => {
56
+ const eventsMap = new Map(events?.map((e) => [`events.${e.key}`, e]) ?? []);
57
+ const successfulItems = [];
58
+ let currentState = initialState;
59
+ for (const item of plan.items) {
60
+ try {
61
+ const newState = await executeSingleItem(context, item, eventsMap, serviceName, currentState);
62
+ if (newState !== null) {
63
+ currentState = newState;
64
+ successfulItems.push(item);
65
+ if (onStateChange) {
66
+ onStateChange(currentState);
67
+ common_1.logger.debug(lang_1.lang.__('STATE_PERSISTED_AFTER_OPERATION', {
68
+ action: item.action,
69
+ resourceId: item.logicalId,
70
+ }));
71
+ }
72
+ }
73
+ }
74
+ catch (error) {
75
+ return {
76
+ state: currentState,
77
+ partialFailure: {
78
+ failedItem: item,
79
+ error: error instanceof Error ? error : new Error(String(error)),
80
+ successfulItems,
81
+ },
82
+ };
83
+ }
84
+ }
85
+ return { state: currentState };
86
+ };
87
+ exports.executeApigwPlan = executeApigwPlan;
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateApigwPlan = void 0;
4
+ const volcengineClient_1 = require("../../common/volcengineClient");
5
+ const apigwTypes_1 = require("./apigwTypes");
6
+ const stateManager_1 = require("../../common/stateManager");
7
+ const hashUtils_1 = require("../../common/hashUtils");
8
+ const planEventDeletion = (logicalId, definition) => ({
9
+ logicalId,
10
+ action: 'delete',
11
+ resourceType: 'VOLCENGINE_APIGW',
12
+ changes: { before: definition },
13
+ });
14
+ const generateApigwPlan = async (context, state, events, serviceName) => {
15
+ if (!events || events.length === 0) {
16
+ const allStates = (0, stateManager_1.getAllResources)(state);
17
+ const items = Object.entries(allStates)
18
+ .filter(([logicalId]) => logicalId.startsWith('events.'))
19
+ .map(([logicalId, resourceState]) => planEventDeletion(logicalId, resourceState.definition));
20
+ return { items };
21
+ }
22
+ const desiredLogicalIds = new Set(events.map((e) => `events.${e.key}`));
23
+ const eventItems = await Promise.all(events.map(async (event) => {
24
+ const logicalId = `events.${event.key}`;
25
+ const currentState = (0, stateManager_1.getResource)(state, logicalId);
26
+ const groupConfig = (0, apigwTypes_1.eventToApigwGroupConfig)(event, serviceName, context.stage);
27
+ const groupDefinition = (0, apigwTypes_1.extractApigwGroupDefinition)(groupConfig);
28
+ const client = (0, volcengineClient_1.createVolcengineClient)(context);
29
+ const desiredDefinition = {
30
+ ...groupDefinition,
31
+ triggers: event.triggers.map((t) => ({
32
+ method: t.method,
33
+ path: t.path,
34
+ backend: t.backend,
35
+ })),
36
+ domain: (0, apigwTypes_1.extractEventDomainDefinition)(event.domain),
37
+ };
38
+ if (!currentState) {
39
+ try {
40
+ const remoteGateway = await client.apigw.findGatewayByName(groupConfig.groupName);
41
+ if (remoteGateway) {
42
+ return {
43
+ logicalId,
44
+ action: 'update',
45
+ resourceType: 'VOLCENGINE_APIGW',
46
+ changes: { after: desiredDefinition },
47
+ drifted: true,
48
+ };
49
+ }
50
+ }
51
+ catch {
52
+ // Ignore errors when checking remote
53
+ }
54
+ return {
55
+ logicalId,
56
+ action: 'create',
57
+ resourceType: 'VOLCENGINE_APIGW',
58
+ changes: { after: desiredDefinition },
59
+ };
60
+ }
61
+ try {
62
+ const groupInstance = currentState.instances.find((i) => i.type === 'VOLCENGINE_APIGW_GROUP');
63
+ if (groupInstance) {
64
+ const remoteGateway = await client.apigw.getGateway(groupInstance.id);
65
+ if (!remoteGateway) {
66
+ return {
67
+ logicalId,
68
+ action: 'create',
69
+ resourceType: 'VOLCENGINE_APIGW',
70
+ changes: { before: currentState.definition, after: desiredDefinition },
71
+ drifted: true,
72
+ };
73
+ }
74
+ }
75
+ const currentDefinition = currentState.definition || {};
76
+ const definitionChanged = !(0, hashUtils_1.attributesEqual)(currentDefinition, desiredDefinition);
77
+ if (definitionChanged) {
78
+ return {
79
+ logicalId,
80
+ action: 'update',
81
+ resourceType: 'VOLCENGINE_APIGW',
82
+ changes: { before: currentDefinition, after: desiredDefinition },
83
+ };
84
+ }
85
+ return { logicalId, action: 'noop', resourceType: 'VOLCENGINE_APIGW' };
86
+ }
87
+ catch {
88
+ return {
89
+ logicalId,
90
+ action: 'create',
91
+ resourceType: 'VOLCENGINE_APIGW',
92
+ changes: { before: currentState.definition, after: desiredDefinition },
93
+ };
94
+ }
95
+ }));
96
+ const allStates = (0, stateManager_1.getAllResources)(state);
97
+ const deletionItems = Object.entries(allStates)
98
+ .filter(([logicalId]) => {
99
+ if (!logicalId.startsWith('events.')) {
100
+ return false;
101
+ }
102
+ if (desiredLogicalIds.has(logicalId)) {
103
+ return false;
104
+ }
105
+ return true;
106
+ })
107
+ .map(([logicalId, resourceState]) => planEventDeletion(logicalId, resourceState.definition));
108
+ return { items: [...eventItems, ...deletionItems] };
109
+ };
110
+ exports.generateApigwPlan = generateApigwPlan;
@@ -0,0 +1,302 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deleteApigwResource = exports.updateApigwResource = exports.readApigwResourceByName = exports.readApigwResource = exports.createApigwResource = void 0;
4
+ const volcengineClient_1 = require("../../common/volcengineClient");
5
+ const apigwTypes_1 = require("./apigwTypes");
6
+ const stateManager_1 = require("../../common/stateManager");
7
+ const common_1 = require("../../common");
8
+ const logger_1 = require("../../common/logger");
9
+ const lang_1 = require("../../lang");
10
+ const buildApigwGroupInstanceFromProvider = (info, stage) => {
11
+ return {
12
+ type: 'VOLCENGINE_APIGW_GROUP',
13
+ sid: (0, common_1.buildSid)('volcengine', 'apigw', stage, info.gatewayId ?? ''),
14
+ id: info.gatewayId ?? '',
15
+ gatewayId: info.gatewayId ?? null,
16
+ gatewayName: info.gatewayName ?? null,
17
+ description: info.description ?? null,
18
+ protocol: info.protocol ?? null,
19
+ status: info.status ?? null,
20
+ createdTime: info.createdTime ?? null,
21
+ subDomain: info.subDomain ?? null,
22
+ };
23
+ };
24
+ const buildApigwApiInstanceFromProvider = (info, stage, gatewayId) => {
25
+ return {
26
+ type: 'VOLCENGINE_APIGW_API',
27
+ sid: (0, common_1.buildSid)('volcengine', 'apigw', stage, `${gatewayId}/${info.apiId}`),
28
+ id: info.apiId ?? '',
29
+ apiId: info.apiId ?? null,
30
+ apiName: info.apiName ?? null,
31
+ gatewayId: info.gatewayId ?? null,
32
+ method: info.method ?? null,
33
+ path: info.path ?? null,
34
+ description: info.description ?? null,
35
+ backendType: info.backendType ?? null,
36
+ backendFunctionName: info.backendFunctionName ?? null,
37
+ status: info.status ?? null,
38
+ createdTime: info.createdTime ?? null,
39
+ };
40
+ };
41
+ const buildApigwDeploymentInstance = (gatewayId, apiId, stageName, stage) => {
42
+ return {
43
+ type: 'VOLCENGINE_APIGW_DEPLOYMENT',
44
+ sid: (0, common_1.buildSid)('volcengine', 'apigw', stage, `${gatewayId}/${apiId}/${stageName}`),
45
+ id: `${gatewayId}/${apiId}/${stageName}`,
46
+ gatewayId,
47
+ apiId,
48
+ stageName,
49
+ };
50
+ };
51
+ const createApigwResource = async (context, event, serviceName, state) => {
52
+ const logicalId = `events.${event.key}`;
53
+ const client = (0, volcengineClient_1.createVolcengineClient)(context);
54
+ const groupConfig = (0, apigwTypes_1.eventToApigwGroupConfig)(event, serviceName, context.stage);
55
+ let gatewayId;
56
+ try {
57
+ const existingGateway = await client.apigw.findGatewayByName(groupConfig.groupName);
58
+ if (existingGateway?.gatewayId) {
59
+ logger_1.logger.info(lang_1.lang.__('APIGW_GROUP_FOUND_REUSING', { groupName: groupConfig.groupName }));
60
+ gatewayId = existingGateway.gatewayId;
61
+ }
62
+ else {
63
+ const gatewayInfo = await client.apigw.createGateway(groupConfig);
64
+ gatewayId = gatewayInfo.gatewayId;
65
+ }
66
+ }
67
+ catch (error) {
68
+ logger_1.logger.debug(`Could not find existing gateway, creating new: ${error}`);
69
+ const gatewayInfo = await client.apigw.createGateway(groupConfig);
70
+ gatewayId = gatewayInfo.gatewayId;
71
+ }
72
+ const gatewayInfo = await client.apigw.getGateway(gatewayId);
73
+ if (!gatewayInfo) {
74
+ throw new Error(`Failed to get API Gateway info after creation: ${gatewayId}`);
75
+ }
76
+ const instances = [
77
+ buildApigwGroupInstanceFromProvider(gatewayInfo, context.stage),
78
+ ];
79
+ const groupDefinition = (0, apigwTypes_1.extractApigwGroupDefinition)(groupConfig);
80
+ const partialResourceState = {
81
+ mode: 'managed',
82
+ region: context.region,
83
+ definition: {
84
+ ...groupDefinition,
85
+ triggers: event.triggers.map((t) => ({
86
+ method: t.method,
87
+ path: t.path,
88
+ backend: t.backend,
89
+ })),
90
+ domain: (0, apigwTypes_1.extractEventDomainDefinition)(event.domain),
91
+ },
92
+ instances,
93
+ lastUpdated: new Date().toISOString(),
94
+ };
95
+ state = (0, stateManager_1.setResource)(state, logicalId, partialResourceState);
96
+ for (const trigger of event.triggers) {
97
+ const apiConfig = (0, apigwTypes_1.triggerToApigwApiConfig)(event, trigger, gatewayId, serviceName, context.region, context.stage);
98
+ const apiId = await client.apigw.createApi(apiConfig);
99
+ const apiInfo = await client.apigw.getApi(gatewayId, apiId);
100
+ if (apiInfo) {
101
+ instances.push(buildApigwApiInstanceFromProvider(apiInfo, context.stage, gatewayId));
102
+ }
103
+ await client.apigw.deployApi(gatewayId, apiId);
104
+ instances.push(buildApigwDeploymentInstance(gatewayId, apiId, 'RELEASE', context.stage));
105
+ const updatedResourceState = {
106
+ mode: 'managed',
107
+ region: context.region,
108
+ definition: {
109
+ ...groupDefinition,
110
+ triggers: event.triggers.map((t) => ({
111
+ method: t.method,
112
+ path: t.path,
113
+ backend: t.backend,
114
+ })),
115
+ domain: (0, apigwTypes_1.extractEventDomainDefinition)(event.domain),
116
+ },
117
+ instances,
118
+ lastUpdated: new Date().toISOString(),
119
+ };
120
+ state = (0, stateManager_1.setResource)(state, logicalId, updatedResourceState);
121
+ }
122
+ if (event.domain) {
123
+ try {
124
+ const domainConfig = {
125
+ gatewayId,
126
+ domainName: event.domain.domain_name,
127
+ certificateId: event.domain.certificate_id,
128
+ };
129
+ await client.apigw.bindDomain(domainConfig);
130
+ }
131
+ catch (error) {
132
+ logger_1.logger.error(lang_1.lang.__('APIGW_DOMAIN_BINDING_FAILED', { error: String(error) }));
133
+ logger_1.logger.info(lang_1.lang.__('APIGW_GROUP_APIS_CREATED_DOMAIN_FAILED'));
134
+ logger_1.logger.info(lang_1.lang.__('APIGW_STATE_SAVED_RETRY'));
135
+ return state;
136
+ }
137
+ }
138
+ const finalResourceState = {
139
+ mode: 'managed',
140
+ region: context.region,
141
+ definition: {
142
+ ...groupDefinition,
143
+ triggers: event.triggers.map((t) => ({
144
+ method: t.method,
145
+ path: t.path,
146
+ backend: t.backend,
147
+ })),
148
+ domain: (0, apigwTypes_1.extractEventDomainDefinition)(event.domain),
149
+ },
150
+ instances,
151
+ lastUpdated: new Date().toISOString(),
152
+ };
153
+ return (0, stateManager_1.setResource)(state, logicalId, finalResourceState);
154
+ };
155
+ exports.createApigwResource = createApigwResource;
156
+ const readApigwResource = async (context, gatewayId) => {
157
+ const client = (0, volcengineClient_1.createVolcengineClient)(context);
158
+ return await client.apigw.getGateway(gatewayId);
159
+ };
160
+ exports.readApigwResource = readApigwResource;
161
+ const readApigwResourceByName = async (context, gatewayName) => {
162
+ const client = (0, volcengineClient_1.createVolcengineClient)(context);
163
+ return await client.apigw.findGatewayByName(gatewayName);
164
+ };
165
+ exports.readApigwResourceByName = readApigwResourceByName;
166
+ const updateApigwResource = async (context, event, serviceName, state) => {
167
+ const logicalId = `events.${event.key}`;
168
+ const existingState = (0, stateManager_1.getResource)(state, logicalId);
169
+ const client = (0, volcengineClient_1.createVolcengineClient)(context);
170
+ if (!existingState) {
171
+ return (0, exports.createApigwResource)(context, event, serviceName, state);
172
+ }
173
+ const existingInstances = existingState.instances;
174
+ const groupInstance = existingInstances.find((i) => i.type === 'VOLCENGINE_APIGW_GROUP');
175
+ if (!groupInstance) {
176
+ return (0, exports.createApigwResource)(context, event, serviceName, state);
177
+ }
178
+ const gatewayId = groupInstance.id;
179
+ const groupConfig = (0, apigwTypes_1.eventToApigwGroupConfig)(event, serviceName, context.stage);
180
+ await client.apigw.updateGateway(gatewayId, groupConfig);
181
+ const gatewayInfo = await client.apigw.getGateway(gatewayId);
182
+ if (!gatewayInfo) {
183
+ throw new Error(`Failed to get API Gateway info after update: ${gatewayId}`);
184
+ }
185
+ const instances = [
186
+ buildApigwGroupInstanceFromProvider(gatewayInfo, context.stage),
187
+ ];
188
+ const existingApis = existingInstances.filter((i) => i.type === 'VOLCENGINE_APIGW_API');
189
+ const neededApiKeys = new Set();
190
+ for (const trigger of event.triggers) {
191
+ const apiConfig = (0, apigwTypes_1.triggerToApigwApiConfig)(event, trigger, gatewayId, serviceName, context.region, context.stage);
192
+ const apiKey = (0, apigwTypes_1.generateApiKey)(trigger.method, trigger.path);
193
+ neededApiKeys.add(apiKey);
194
+ const existingApi = existingApis.find((a) => {
195
+ return a.id && a.apiName === apiConfig.apiName;
196
+ });
197
+ let apiId;
198
+ if (existingApi) {
199
+ apiId = existingApi.id;
200
+ await client.apigw.updateApi(apiId, apiConfig);
201
+ }
202
+ else {
203
+ apiId = await client.apigw.createApi(apiConfig);
204
+ }
205
+ const apiInfo = await client.apigw.getApi(gatewayId, apiId);
206
+ if (apiInfo) {
207
+ instances.push(buildApigwApiInstanceFromProvider(apiInfo, context.stage, gatewayId));
208
+ }
209
+ await client.apigw.deployApi(gatewayId, apiId);
210
+ instances.push(buildApigwDeploymentInstance(gatewayId, apiId, 'RELEASE', context.stage));
211
+ }
212
+ for (const existingApi of existingApis) {
213
+ const apiInfo = await client.apigw.getApi(gatewayId, existingApi.id);
214
+ if (apiInfo) {
215
+ const isNeeded = event.triggers.some((t) => {
216
+ const expectedName = (0, apigwTypes_1.triggerToApigwApiConfig)(event, t, gatewayId, serviceName, context.region, context.stage).apiName;
217
+ return apiInfo.apiName === expectedName;
218
+ });
219
+ if (!isNeeded) {
220
+ await client.apigw.deleteApi(gatewayId, existingApi.id);
221
+ }
222
+ }
223
+ }
224
+ if (event.domain) {
225
+ const domainConfig = {
226
+ gatewayId,
227
+ domainName: event.domain.domain_name,
228
+ certificateId: event.domain.certificate_id,
229
+ };
230
+ await client.apigw.bindDomain(domainConfig);
231
+ }
232
+ else {
233
+ const existingDomain = existingState.definition?.domain;
234
+ if (existingDomain?.domainName) {
235
+ const previousDomain = existingDomain.domainName;
236
+ try {
237
+ await client.apigw.unbindDomain(gatewayId, previousDomain);
238
+ }
239
+ catch (error) {
240
+ logger_1.logger.warn(lang_1.lang.__('APIGW_DOMAIN_UNBIND_FAILED', { domain: previousDomain, error: String(error) }));
241
+ }
242
+ }
243
+ }
244
+ const groupDefinition = (0, apigwTypes_1.extractApigwGroupDefinition)(groupConfig);
245
+ const resourceState = {
246
+ mode: 'managed',
247
+ region: context.region,
248
+ definition: {
249
+ ...groupDefinition,
250
+ triggers: event.triggers.map((t) => ({
251
+ method: t.method,
252
+ path: t.path,
253
+ backend: t.backend,
254
+ })),
255
+ domain: (0, apigwTypes_1.extractEventDomainDefinition)(event.domain),
256
+ },
257
+ instances,
258
+ lastUpdated: new Date().toISOString(),
259
+ };
260
+ return (0, stateManager_1.setResource)(state, logicalId, resourceState);
261
+ };
262
+ exports.updateApigwResource = updateApigwResource;
263
+ const deleteApigwResource = async (context, logicalId, state) => {
264
+ const existingState = (0, stateManager_1.getResource)(state, logicalId);
265
+ const client = (0, volcengineClient_1.createVolcengineClient)(context);
266
+ if (!existingState) {
267
+ return state;
268
+ }
269
+ const existingInstances = existingState.instances;
270
+ const groupInstance = existingInstances.find((i) => i.type === 'VOLCENGINE_APIGW_GROUP');
271
+ if (!groupInstance) {
272
+ return (0, stateManager_1.removeResource)(state, logicalId);
273
+ }
274
+ const gatewayId = groupInstance.id;
275
+ const existingDomain = existingState.definition?.domain;
276
+ if (existingDomain?.domainName) {
277
+ const primaryDomain = existingDomain.domainName;
278
+ try {
279
+ await client.apigw.unbindDomain(gatewayId, primaryDomain);
280
+ }
281
+ catch (error) {
282
+ logger_1.logger.warn(lang_1.lang.__('APIGW_DOMAIN_UNBIND_FAILED', { domain: primaryDomain, error: String(error) }));
283
+ }
284
+ }
285
+ const apis = existingInstances.filter((i) => i.type === 'VOLCENGINE_APIGW_API');
286
+ for (const api of apis) {
287
+ try {
288
+ await client.apigw.deleteApi(gatewayId, api.id);
289
+ }
290
+ catch {
291
+ // API might already be deleted
292
+ }
293
+ }
294
+ try {
295
+ await client.apigw.deleteGateway(gatewayId);
296
+ }
297
+ catch {
298
+ // Gateway might already be deleted
299
+ }
300
+ return (0, stateManager_1.removeResource)(state, logicalId);
301
+ };
302
+ exports.deleteApigwResource = deleteApigwResource;
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractEventDomainDefinition = exports.extractApigwApiDefinition = exports.extractApigwGroupDefinition = exports.triggerToApigwApiConfig = exports.generateApiKey = exports.eventToApigwGroupConfig = void 0;
4
+ const common_1 = require("../../common");
5
+ const lang_1 = require("../../lang");
6
+ /**
7
+ * Convert EventDomain to API Gateway group config
8
+ */
9
+ const eventToApigwGroupConfig = (event, serviceName, stage) => {
10
+ return {
11
+ groupName: `${serviceName}-${stage}-apigw`.replace(/_/g, '-'),
12
+ description: `API Gateway for ${serviceName}`,
13
+ protocol: event.domain?.protocol ?? 'HTTP',
14
+ };
15
+ };
16
+ exports.eventToApigwGroupConfig = eventToApigwGroupConfig;
17
+ /**
18
+ * Generate a unique API key from method and path
19
+ * Uses URL encoding to preserve path structure and avoid collisions
20
+ */
21
+ const generateApiKey = (method, path) => {
22
+ const sanitizedPath = path
23
+ .replace(/\//g, '__')
24
+ .replace(/[^a-zA-Z0-9_]/g, '_')
25
+ .replace(/^__/, '')
26
+ .replace(/__$/, '');
27
+ return `${method}_${sanitizedPath}`;
28
+ };
29
+ exports.generateApiKey = generateApiKey;
30
+ /**
31
+ * Resolves a function reference like ${functions.xxx} to the actual function name
32
+ */
33
+ const resolveFunctionReference = (backendRef) => {
34
+ const context = (0, common_1.getContext)();
35
+ if (!context.iac) {
36
+ common_1.logger.warn(lang_1.lang.__('CANNOT_RESOLVE_FUNCTION_REF', { backendRef }));
37
+ return backendRef;
38
+ }
39
+ const functionDef = (0, common_1.getIacDefinition)(context.iac, backendRef);
40
+ if (!functionDef || !(0, common_1.isFunctionDomain)(functionDef)) {
41
+ common_1.logger.warn(lang_1.lang.__('FUNCTION_REF_NOT_RESOLVED', { backendRef }));
42
+ return backendRef;
43
+ }
44
+ const functionName = functionDef.name;
45
+ common_1.logger.info(lang_1.lang.__('RESOLVED_FUNCTION_REF', { backendRef, functionName }));
46
+ return functionName;
47
+ };
48
+ /**
49
+ * Convert EventDomain trigger to API Gateway API config
50
+ */
51
+ const triggerToApigwApiConfig = (event, trigger, gatewayId, _serviceName, _region, stage) => {
52
+ const method = trigger.method;
53
+ const path = trigger.path;
54
+ const backend = trigger.backend;
55
+ const resolvedFunctionName = resolveFunctionReference(backend);
56
+ const apiKey = (0, exports.generateApiKey)(method, path);
57
+ return {
58
+ gatewayId,
59
+ apiName: `${event.name}-${stage}-api-${apiKey}`.replace(/_/g, '-'),
60
+ method,
61
+ path,
62
+ backendFunctionName: resolvedFunctionName,
63
+ backendType: 'veFaaS',
64
+ requestTimeout: 60,
65
+ };
66
+ };
67
+ exports.triggerToApigwApiConfig = triggerToApigwApiConfig;
68
+ /**
69
+ * Extract definition from API Gateway group config for state comparison
70
+ */
71
+ const extractApigwGroupDefinition = (config) => {
72
+ return {
73
+ groupName: config.groupName,
74
+ description: config.description ?? null,
75
+ protocol: config.protocol ?? null,
76
+ };
77
+ };
78
+ exports.extractApigwGroupDefinition = extractApigwGroupDefinition;
79
+ /**
80
+ * Extract definition from API Gateway API config for state comparison
81
+ */
82
+ const extractApigwApiDefinition = (config) => {
83
+ return {
84
+ apiName: config.apiName,
85
+ gatewayId: config.gatewayId,
86
+ method: config.method,
87
+ path: config.path,
88
+ backendFunctionName: config.backendFunctionName,
89
+ backendType: config.backendType,
90
+ };
91
+ };
92
+ exports.extractApigwApiDefinition = extractApigwApiDefinition;
93
+ const extractEventDomainDefinition = (domain) => {
94
+ if (!domain) {
95
+ return null;
96
+ }
97
+ return {
98
+ domainName: domain.domain_name,
99
+ wwwBindApex: domain.www_bind_apex === true,
100
+ certificateId: domain.certificate_id ?? null,
101
+ certificateBody: domain.certificate_body ?? null,
102
+ certificatePrivateKey: domain.certificate_private_key ? '(managed)' : null,
103
+ protocol: domain.protocol ?? null,
104
+ };
105
+ };
106
+ exports.extractEventDomainDefinition = extractEventDomainDefinition;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deployVolcengineStack = void 0;
4
+ const common_1 = require("../../common");
5
+ const lang_1 = require("../../lang");
6
+ const vefaasPlanner_1 = require("./vefaasPlanner");
7
+ const vefaasExecutor_1 = require("./vefaasExecutor");
8
+ const tosPlanner_1 = require("./tosPlanner");
9
+ const tosExecutor_1 = require("./tosExecutor");
10
+ const apigwPlanner_1 = require("./apigwPlanner");
11
+ const apigwExecutor_1 = require("./apigwExecutor");
12
+ const deployVolcengineStack = async (iac, backend) => {
13
+ const context = (0, common_1.getContext)();
14
+ common_1.logger.info(lang_1.lang.__('DEPLOYING_STACK'));
15
+ let state = await backend.loadState('volcengine', iac.app, iac.service, context.stage);
16
+ const onStateChange = (newState) => {
17
+ state = newState;
18
+ backend.saveState(state, iac.app, iac.service, context.stage);
19
+ };
20
+ common_1.logger.info(lang_1.lang.__('GENERATING_PLAN'));
21
+ const functionPlan = await (0, vefaasPlanner_1.generateFunctionPlan)(context, state, iac.functions);
22
+ const bucketPlan = await (0, tosPlanner_1.generateBucketPlan)(context, state, iac.buckets);
23
+ const apigwPlan = await (0, apigwPlanner_1.generateApigwPlan)(context, state, iac.events, iac.service);
24
+ const bucketResult = await (0, tosExecutor_1.executeBucketPlan)(context, bucketPlan, iac.buckets, state, onStateChange);
25
+ if (bucketResult.partialFailure) {
26
+ const error = bucketResult.partialFailure.error;
27
+ error.isPartialFailure = true;
28
+ common_1.logger.error(lang_1.lang.__('PARTIAL_DEPLOYMENT_FAILURE', {
29
+ resourceType: 'Bucket',
30
+ name: bucketResult.partialFailure.failedItem.logicalId,
31
+ }));
32
+ throw error;
33
+ }
34
+ state = bucketResult.state;
35
+ const functionResult = await (0, vefaasExecutor_1.executeFunctionPlan)(context, functionPlan, iac.functions, state, onStateChange);
36
+ if (functionResult.partialFailure) {
37
+ const error = functionResult.partialFailure.error;
38
+ error.isPartialFailure = true;
39
+ common_1.logger.error(lang_1.lang.__('PARTIAL_DEPLOYMENT_FAILURE', {
40
+ resourceType: 'Function',
41
+ name: functionResult.partialFailure.failedItem.logicalId,
42
+ }));
43
+ throw error;
44
+ }
45
+ state = functionResult.state;
46
+ const apigwResult = await (0, apigwExecutor_1.executeApigwPlan)(context, apigwPlan, iac.events, iac.service, state, onStateChange);
47
+ if (apigwResult.partialFailure) {
48
+ const error = apigwResult.partialFailure.error;
49
+ error.isPartialFailure = true;
50
+ common_1.logger.error(lang_1.lang.__('PARTIAL_DEPLOYMENT_FAILURE', {
51
+ resourceType: 'API Gateway',
52
+ name: apigwResult.partialFailure.failedItem.logicalId,
53
+ }));
54
+ throw error;
55
+ }
56
+ await backend.saveState(apigwResult.state, iac.app, iac.service, context.stage);
57
+ common_1.logger.info(lang_1.lang.__('STACK_DEPLOYED'));
58
+ };
59
+ exports.deployVolcengineStack = deployVolcengineStack;