@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.
- package/.gitattributes +1 -0
- package/README.md +108 -8
- package/README.zh-CN.md +52 -8
- package/dist/package.json +37 -35
- package/dist/src/commands/deploy.js +17 -7
- package/dist/src/commands/destroy.js +27 -4
- package/dist/src/commands/forceUnlock.js +61 -0
- package/dist/src/commands/index.js +86 -14
- package/dist/src/commands/local.js +10 -1
- package/dist/src/commands/plan.js +33 -0
- package/dist/src/commands/template.js +3 -1
- package/dist/src/commands/validate.js +2 -1
- package/dist/src/common/aliyunClient/apigwOperations.js +652 -0
- package/dist/src/common/aliyunClient/dnsOperations.js +90 -0
- package/dist/src/common/aliyunClient/ecsOperations.js +141 -0
- package/dist/src/common/aliyunClient/esOperations.js +219 -0
- package/dist/src/common/aliyunClient/fc3Operations.js +270 -0
- package/dist/src/common/aliyunClient/index.js +141 -0
- package/dist/src/common/aliyunClient/nasOperations.js +233 -0
- package/dist/src/common/aliyunClient/ossOperations.js +237 -0
- package/dist/src/common/aliyunClient/ramOperations.js +205 -0
- package/dist/src/common/aliyunClient/rdsOperations.js +206 -0
- package/dist/src/common/aliyunClient/slsOperations.js +218 -0
- package/dist/src/common/aliyunClient/tablestoreOperations.js +199 -0
- package/dist/src/common/aliyunClient/types.js +2 -0
- package/dist/src/common/constants.js +7 -1
- package/dist/src/common/context.js +32 -14
- package/dist/src/common/credentials.js +39 -0
- package/dist/src/common/dependencyGraph/graph.js +280 -0
- package/dist/src/common/dependencyGraph/index.js +18 -0
- package/dist/src/common/dependencyGraph/types.js +2 -0
- package/dist/src/common/fileUtils.js +16 -0
- package/dist/src/common/hashUtils.js +121 -0
- package/dist/src/common/iacHelper.js +25 -97
- package/dist/src/common/imsClient.js +4 -0
- package/dist/src/common/index.js +7 -2
- package/dist/src/common/lockManager.js +212 -0
- package/dist/src/common/logger.js +89 -6
- package/dist/src/common/providerEnum.js +2 -3
- package/dist/src/common/runtimeMapper.js +160 -0
- package/dist/src/common/scfClient.js +84 -0
- package/dist/src/common/stateManager.js +107 -0
- package/dist/src/common/tencentClient/cosOperations.js +287 -0
- package/dist/src/common/tencentClient/esOperations.js +156 -0
- package/dist/src/common/tencentClient/index.js +116 -0
- package/dist/src/common/tencentClient/scfOperations.js +141 -0
- package/dist/src/common/tencentClient/tdsqlcOperations.js +211 -0
- package/dist/src/common/tencentClient/types.js +17 -0
- package/dist/src/lang/en.js +254 -0
- package/dist/src/lang/index.js +28 -8
- package/dist/src/lang/zh-CN.js +229 -0
- package/dist/src/parser/bucketParser.js +25 -12
- package/dist/src/parser/databaseParser.js +14 -10
- package/dist/src/parser/functionParser.js +19 -6
- package/dist/src/parser/parseUtils.js +74 -0
- package/dist/src/parser/tableParser.js +19 -17
- package/dist/src/stack/aliyunStack/apigwExecutor.js +84 -0
- package/dist/src/stack/aliyunStack/apigwPlanner.js +118 -0
- package/dist/src/stack/aliyunStack/apigwResource.js +339 -0
- package/dist/src/stack/aliyunStack/apigwTypes.js +125 -0
- package/dist/src/stack/aliyunStack/databaseExecutor.js +112 -0
- package/dist/src/stack/aliyunStack/databasePlanner.js +128 -0
- package/dist/src/stack/aliyunStack/databaseResource.js +228 -0
- package/dist/src/stack/aliyunStack/deployer.js +133 -0
- package/dist/src/stack/aliyunStack/destroyer.js +114 -0
- package/dist/src/stack/aliyunStack/esServerlessTypes.js +141 -0
- package/dist/src/stack/aliyunStack/fc3Executor.js +91 -0
- package/dist/src/stack/aliyunStack/fc3Planner.js +77 -0
- package/dist/src/stack/aliyunStack/fc3Resource.js +511 -0
- package/dist/src/stack/aliyunStack/fc3Types.js +76 -0
- package/dist/src/stack/aliyunStack/index.js +40 -0
- package/dist/src/stack/aliyunStack/ossExecutor.js +91 -0
- package/dist/src/stack/aliyunStack/ossPlanner.js +76 -0
- package/dist/src/stack/aliyunStack/ossResource.js +196 -0
- package/dist/src/stack/aliyunStack/ossTypes.js +50 -0
- package/dist/src/stack/aliyunStack/planner.js +37 -0
- package/dist/src/stack/aliyunStack/rdsTypes.js +217 -0
- package/dist/src/stack/aliyunStack/tablestoreExecutor.js +92 -0
- package/dist/src/stack/aliyunStack/tablestorePlanner.js +94 -0
- package/dist/src/stack/aliyunStack/tablestoreResource.js +120 -0
- package/dist/src/stack/aliyunStack/tablestoreTypes.js +77 -0
- package/dist/src/stack/bucketTypes.js +17 -0
- package/dist/src/stack/deploy.js +24 -77
- package/dist/src/stack/localStack/bucket.js +11 -6
- package/dist/src/stack/localStack/event.js +10 -5
- package/dist/src/stack/localStack/function.js +13 -7
- package/dist/src/stack/localStack/functionRunner.js +1 -1
- package/dist/src/stack/localStack/localServer.js +7 -6
- package/dist/src/stack/scfStack/cosExecutor.js +91 -0
- package/dist/src/stack/scfStack/cosPlanner.js +76 -0
- package/dist/src/stack/scfStack/cosResource.js +126 -0
- package/dist/src/stack/scfStack/cosTypes.js +46 -0
- package/dist/src/stack/scfStack/deployer.js +91 -0
- package/dist/src/stack/scfStack/destroyer.js +88 -0
- package/dist/src/stack/scfStack/esServerlessExecutor.js +105 -0
- package/dist/src/stack/scfStack/esServerlessPlanner.js +86 -0
- package/dist/src/stack/scfStack/esServerlessResource.js +94 -0
- package/dist/src/stack/scfStack/esServerlessTypes.js +48 -0
- package/dist/src/stack/scfStack/index.js +35 -0
- package/dist/src/stack/scfStack/planner.js +91 -0
- package/dist/src/stack/scfStack/scfExecutor.js +91 -0
- package/dist/src/stack/scfStack/scfPlanner.js +78 -0
- package/dist/src/stack/scfStack/scfResource.js +216 -0
- package/dist/src/stack/scfStack/scfTypes.js +41 -0
- package/dist/src/stack/scfStack/tdsqlcExecutor.js +105 -0
- package/dist/src/stack/scfStack/tdsqlcPlanner.js +90 -0
- package/dist/src/stack/scfStack/tdsqlcResource.js +146 -0
- package/dist/src/stack/scfStack/tdsqlcTypes.js +59 -0
- package/dist/src/types/domains/lock.js +2 -0
- package/dist/src/types/domains/resolvable.js +2 -0
- package/dist/src/types/domains/state.js +19 -0
- package/dist/src/types/index.js +4 -0
- package/dist/src/validator/bucketSchema.js +4 -10
- package/dist/src/validator/databaseSchema.js +36 -36
- package/dist/src/validator/eventSchema.js +3 -2
- package/dist/src/validator/functionSchema.js +51 -46
- package/dist/src/validator/iacSchema.js +52 -3
- package/dist/src/validator/rootSchema.js +47 -1
- package/dist/src/validator/tableschema.js +9 -8
- package/dist/src/validator/templateRefSchema.js +23 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +37 -35
- package/samples/README_TENCENT_COS.md +486 -0
- package/samples/README_TENCENT_SCF.md +272 -0
- package/samples/aliyun-poc-api.yml +1 -1
- package/samples/aliyun-poc-bucket.yml +0 -1
- package/samples/aliyun-poc-domain.yml +0 -1
- package/samples/aliyun-poc-es.yml +14 -13
- package/samples/aliyun-poc-rds.yml +0 -2
- package/samples/aliyun-poc-table.yml +1 -3
- package/samples/tencent-poc-cos.yml +20 -0
- package/samples/tencent-poc-scf.yml +36 -0
- package/dist/src/commands/index.d.ts +0 -2
- package/dist/src/common/index.d.ts +0 -11
- package/dist/src/common/rosAssets.js +0 -178
- package/dist/src/common/rosClient.js +0 -198
- package/dist/src/index.d.ts +0 -1
- package/dist/src/lang/index.d.ts +0 -3
- package/dist/src/parser/index.d.ts +0 -3
- package/dist/src/stack/index.d.ts +0 -1
- package/dist/src/stack/localStack/index.d.ts +0 -5
- package/dist/src/stack/rfsStack/index.d.ts +0 -9
- package/dist/src/stack/rosStack/bootstrap.js +0 -187
- package/dist/src/stack/rosStack/bucket.js +0 -127
- package/dist/src/stack/rosStack/database.js +0 -313
- package/dist/src/stack/rosStack/event.js +0 -143
- package/dist/src/stack/rosStack/function.js +0 -259
- package/dist/src/stack/rosStack/index.d.ts +0 -7
- package/dist/src/stack/rosStack/index.js +0 -75
- package/dist/src/stack/rosStack/stage.js +0 -46
- package/dist/src/stack/rosStack/table.js +0 -95
- package/dist/src/stack/rosStack/tag.js +0 -11
- package/dist/src/stack/rosStack/vars.js +0 -49
- package/dist/src/types/index.d.ts +0 -55
- package/dist/src/types/localStack/index.d.ts +0 -81
- package/dist/src/validator/index.d.ts +0 -1
- package/layers/si-bootstrap-sdk/Dockerfile-aliyuncli +0 -12
- package/layers/si-bootstrap-sdk/README.md +0 -1
- package/layers/si-bootstrap-sdk/package-lock.json +0 -875
- package/layers/si-bootstrap-sdk/package.json +0 -33
|
@@ -0,0 +1,652 @@
|
|
|
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.createApigwOperations = void 0;
|
|
37
|
+
const cloudapi = __importStar(require("@alicloud/cloudapi20160714"));
|
|
38
|
+
const dnsOperations_1 = require("./dnsOperations");
|
|
39
|
+
const logger_1 = require("../logger");
|
|
40
|
+
const lang_1 = require("../../lang");
|
|
41
|
+
const stateManager_1 = require("../stateManager");
|
|
42
|
+
const removeUndefined = (obj) => {
|
|
43
|
+
return Object.fromEntries(Object.entries(obj).filter(([, value]) => value !== undefined));
|
|
44
|
+
};
|
|
45
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
46
|
+
const extractMainDomain = (domainName) => {
|
|
47
|
+
const parts = domainName.split('.');
|
|
48
|
+
if (parts.length <= 2) {
|
|
49
|
+
return domainName;
|
|
50
|
+
}
|
|
51
|
+
return parts.slice(-2).join('.');
|
|
52
|
+
};
|
|
53
|
+
const extractHostRecord = (fullDomain, mainDomain) => {
|
|
54
|
+
if (fullDomain === mainDomain) {
|
|
55
|
+
return '@'; // @ represents the root domain
|
|
56
|
+
}
|
|
57
|
+
const suffix = `.${mainDomain}`;
|
|
58
|
+
if (fullDomain.endsWith(suffix)) {
|
|
59
|
+
return fullDomain.slice(0, -suffix.length);
|
|
60
|
+
}
|
|
61
|
+
return fullDomain;
|
|
62
|
+
};
|
|
63
|
+
const createApigwOperations = (apigwClient, dnsClient, _context) => {
|
|
64
|
+
const dnsOps = (0, dnsOperations_1.createDnsOperations)(dnsClient);
|
|
65
|
+
const extractVerificationToken = (error, groupInfo) => {
|
|
66
|
+
try {
|
|
67
|
+
if (groupInfo?.subDomain) {
|
|
68
|
+
const match = groupInfo.subDomain.match(/^([a-f0-9]+)-[^.]+\.alicloudapi\.com$/);
|
|
69
|
+
if (match) {
|
|
70
|
+
return match[1];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const errorStr = String(error);
|
|
74
|
+
const cnameMatch = errorStr.match(/([a-f0-9]{32})-[^.]+\.alicloudapi\.com/);
|
|
75
|
+
if (cnameMatch) {
|
|
76
|
+
return cnameMatch[1];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// Ignore extraction errors
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
};
|
|
84
|
+
const pollDnsPropagation = async (mainDomain, verificationHost, verificationValue, shouldLoop = true) => {
|
|
85
|
+
const checkPropagation = async () => {
|
|
86
|
+
try {
|
|
87
|
+
const currentRecords = await dnsOps.describeDomainRecords(mainDomain, verificationHost);
|
|
88
|
+
return currentRecords.some((record) => record.rr === verificationHost &&
|
|
89
|
+
record.type === 'CNAME' &&
|
|
90
|
+
record.value === verificationValue &&
|
|
91
|
+
record.status === 'ENABLE');
|
|
92
|
+
}
|
|
93
|
+
catch (checkError) {
|
|
94
|
+
logger_1.logger.warn(lang_1.lang.__('APIGW_DNS_CHECK_FAILED', { attempt: '1', error: String(checkError) }));
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
if (!shouldLoop) {
|
|
99
|
+
logger_1.logger.info('Checking DNS record status...');
|
|
100
|
+
return await checkPropagation();
|
|
101
|
+
}
|
|
102
|
+
logger_1.logger.info(lang_1.lang.__('APIGW_DNS_PROPAGATION_WAITING'));
|
|
103
|
+
const maxAttempts = 10;
|
|
104
|
+
const delayMs = 60000; // 1 minute
|
|
105
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
106
|
+
logger_1.logger.info(lang_1.lang.__('APIGW_DNS_PROPAGATION_CHECK', {
|
|
107
|
+
attempt: String(attempt),
|
|
108
|
+
max: String(maxAttempts),
|
|
109
|
+
}));
|
|
110
|
+
await sleep(delayMs);
|
|
111
|
+
const propagated = await checkPropagation();
|
|
112
|
+
if (propagated) {
|
|
113
|
+
logger_1.logger.info(lang_1.lang.__('APIGW_DNS_VERIFIED', { minutes: String(attempt) }));
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
logger_1.logger.warn(lang_1.lang.__('APIGW_DNS_PROPAGATION_TIMEOUT'));
|
|
118
|
+
return false;
|
|
119
|
+
};
|
|
120
|
+
const addDomainVerificationRecord = async (domainName, verificationToken, groupSubdomain, region, state, eventLogicalId) => {
|
|
121
|
+
logger_1.logger.info(lang_1.lang.__('APIGW_DNS_ADDING_RECORD', { domain: domainName }));
|
|
122
|
+
const mainDomain = extractMainDomain(domainName);
|
|
123
|
+
const hostRecord = extractHostRecord(domainName, mainDomain);
|
|
124
|
+
// For CNAME verification: point the domain directly to the group subdomain
|
|
125
|
+
const verificationHost = domainName;
|
|
126
|
+
const verificationValue = groupSubdomain;
|
|
127
|
+
const dnsResourceId = `${eventLogicalId}.dns_verification`;
|
|
128
|
+
try {
|
|
129
|
+
// Check if DNS record is tracked in state
|
|
130
|
+
const existingDnsResource = (0, stateManager_1.getResource)(state, dnsResourceId);
|
|
131
|
+
const now = new Date();
|
|
132
|
+
const thirtyMinutesMs = 30 * 60 * 1000;
|
|
133
|
+
if (existingDnsResource) {
|
|
134
|
+
const createdAt = new Date(existingDnsResource.lastUpdated);
|
|
135
|
+
const ageMs = now.getTime() - createdAt.getTime();
|
|
136
|
+
if (ageMs < thirtyMinutesMs) {
|
|
137
|
+
// Created within 30 minutes - poll for propagation
|
|
138
|
+
logger_1.logger.info(lang_1.lang.__('APIGW_DNS_RECORD_EXISTS_POLLING', {
|
|
139
|
+
minutes: String(Math.floor(ageMs / 60000)),
|
|
140
|
+
}));
|
|
141
|
+
await pollDnsPropagation(mainDomain, hostRecord, verificationValue, true);
|
|
142
|
+
return state;
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
// Created more than 30 minutes ago - just check once
|
|
146
|
+
logger_1.logger.info(lang_1.lang.__('APIGW_DNS_RECORD_EXISTS_CHECKING', {
|
|
147
|
+
minutes: String(Math.floor(ageMs / 60000)),
|
|
148
|
+
}));
|
|
149
|
+
const propagated = await pollDnsPropagation(mainDomain, hostRecord, verificationValue, false);
|
|
150
|
+
if (propagated) {
|
|
151
|
+
logger_1.logger.info(lang_1.lang.__('APIGW_DNS_RECORD_ACTIVE'));
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
logger_1.logger.warn(lang_1.lang.__('APIGW_DNS_RECORD_MAY_NOT_PROPAGATED'));
|
|
155
|
+
}
|
|
156
|
+
return state;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Check if record already exists in DNS (but not tracked in state)
|
|
160
|
+
const existingRecords = await dnsOps.describeDomainRecords(mainDomain, hostRecord);
|
|
161
|
+
const recordExists = existingRecords.some((record) => record.rr === hostRecord && record.type === 'CNAME' && record.value === verificationValue);
|
|
162
|
+
if (!recordExists) {
|
|
163
|
+
// Add the verification record
|
|
164
|
+
const recordId = await dnsOps.addDomainRecord({
|
|
165
|
+
domainName: mainDomain,
|
|
166
|
+
rr: hostRecord,
|
|
167
|
+
type: 'CNAME',
|
|
168
|
+
value: verificationValue,
|
|
169
|
+
ttl: 600,
|
|
170
|
+
});
|
|
171
|
+
logger_1.logger.info(lang_1.lang.__('APIGW_DNS_RECORD_ADDED', {
|
|
172
|
+
record: verificationHost,
|
|
173
|
+
type: 'CNAME',
|
|
174
|
+
value: verificationValue,
|
|
175
|
+
}));
|
|
176
|
+
// Track DNS record in state
|
|
177
|
+
const dnsResourceState = {
|
|
178
|
+
mode: 'managed',
|
|
179
|
+
region,
|
|
180
|
+
definition: {
|
|
181
|
+
domainName,
|
|
182
|
+
mainDomain,
|
|
183
|
+
verificationHost,
|
|
184
|
+
verificationValue,
|
|
185
|
+
verificationToken,
|
|
186
|
+
groupSubdomain,
|
|
187
|
+
},
|
|
188
|
+
instances: [
|
|
189
|
+
{
|
|
190
|
+
arn: `arn:acs:alidns:${region}:dns-record/${recordId}`,
|
|
191
|
+
id: recordId,
|
|
192
|
+
type: 'CNAME',
|
|
193
|
+
status: 'PENDING',
|
|
194
|
+
},
|
|
195
|
+
],
|
|
196
|
+
lastUpdated: now.toISOString(),
|
|
197
|
+
};
|
|
198
|
+
state = (0, stateManager_1.setResource)(state, dnsResourceId, dnsResourceState);
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
logger_1.logger.info(lang_1.lang.__('APIGW_DNS_RECORD_ALREADY_EXISTS', { domain: domainName }));
|
|
202
|
+
// Track existing record in state
|
|
203
|
+
const dnsResourceState = {
|
|
204
|
+
mode: 'managed',
|
|
205
|
+
region,
|
|
206
|
+
definition: {
|
|
207
|
+
domainName,
|
|
208
|
+
mainDomain,
|
|
209
|
+
verificationHost,
|
|
210
|
+
verificationValue,
|
|
211
|
+
verificationToken,
|
|
212
|
+
groupSubdomain,
|
|
213
|
+
},
|
|
214
|
+
instances: [
|
|
215
|
+
{
|
|
216
|
+
arn: `arn:acs:alidns:${region}:dns-record/existing`,
|
|
217
|
+
id: 'existing',
|
|
218
|
+
type: 'CNAME',
|
|
219
|
+
status: 'EXISTING',
|
|
220
|
+
},
|
|
221
|
+
],
|
|
222
|
+
lastUpdated: now.toISOString(),
|
|
223
|
+
};
|
|
224
|
+
state = (0, stateManager_1.setResource)(state, dnsResourceId, dnsResourceState);
|
|
225
|
+
}
|
|
226
|
+
// Poll for DNS propagation
|
|
227
|
+
await pollDnsPropagation(mainDomain, hostRecord, verificationValue, true);
|
|
228
|
+
return state;
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
logger_1.logger.error(lang_1.lang.__('APIGW_DNS_VERIFICATION_FAILED', { domain: domainName, error: String(error) }));
|
|
232
|
+
throw error;
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
const logVerificationInstructions = (domainName, verificationToken, groupSubdomain) => {
|
|
236
|
+
const separator = '='.repeat(80);
|
|
237
|
+
logger_1.logger.error(`\n${separator}\n${lang_1.lang.__('APIGW_VERIFICATION_HEADER')}\n${separator}\n${lang_1.lang.__('APIGW_VERIFICATION_DOMAIN', { domain: domainName })}\n\n${lang_1.lang.__('APIGW_VERIFICATION_INSTRUCTIONS')}\n\n${lang_1.lang.__('APIGW_VERIFICATION_RECORD_NAME', { name: domainName })}\n${lang_1.lang.__('APIGW_VERIFICATION_RECORD_TYPE', { type: 'CNAME' })}\n${lang_1.lang.__('APIGW_VERIFICATION_RECORD_VALUE', { value: groupSubdomain })}`);
|
|
238
|
+
logger_1.logger.error(`\n${separator}\n${lang_1.lang.__('APIGW_VERIFICATION_NEXT_STEPS')}\n${lang_1.lang.__('APIGW_VERIFICATION_STEP1')}\n${lang_1.lang.__('APIGW_VERIFICATION_STEP2')}\n${separator}\n`);
|
|
239
|
+
};
|
|
240
|
+
return {
|
|
241
|
+
/**
|
|
242
|
+
* Create an API Gateway group
|
|
243
|
+
*/
|
|
244
|
+
createApiGroup: async (config) => {
|
|
245
|
+
const request = new cloudapi.CreateApiGroupRequest({
|
|
246
|
+
groupName: config.groupName,
|
|
247
|
+
description: config.description,
|
|
248
|
+
basePath: config.basePath,
|
|
249
|
+
instanceId: config.instanceId,
|
|
250
|
+
tag: config.tags?.map((t) => new cloudapi.CreateApiGroupRequestTag({ key: t.key, value: t.value })),
|
|
251
|
+
});
|
|
252
|
+
const response = await apigwClient.createApiGroup(request);
|
|
253
|
+
if (!response.body?.groupId) {
|
|
254
|
+
throw new Error('Failed to create API Gateway group: no groupId returned');
|
|
255
|
+
}
|
|
256
|
+
return response.body.groupId;
|
|
257
|
+
},
|
|
258
|
+
/**
|
|
259
|
+
* Get API Gateway group by group ID
|
|
260
|
+
*/
|
|
261
|
+
getApiGroup: async (groupId) => {
|
|
262
|
+
try {
|
|
263
|
+
const request = new cloudapi.DescribeApiGroupRequest({
|
|
264
|
+
groupId,
|
|
265
|
+
});
|
|
266
|
+
const response = await apigwClient.describeApiGroup(request);
|
|
267
|
+
if (!response.body) {
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
return {
|
|
271
|
+
groupId: response.body.groupId,
|
|
272
|
+
groupName: response.body.groupName,
|
|
273
|
+
description: response.body.description,
|
|
274
|
+
basePath: response.body.basePath,
|
|
275
|
+
subDomain: response.body.subDomain,
|
|
276
|
+
instanceId: response.body.instanceId,
|
|
277
|
+
instanceType: response.body.instanceType,
|
|
278
|
+
regionId: response.body.regionId,
|
|
279
|
+
status: response.body.status,
|
|
280
|
+
createdTime: response.body.createdTime,
|
|
281
|
+
modifiedTime: response.body.modifiedTime,
|
|
282
|
+
billingStatus: response.body.billingStatus,
|
|
283
|
+
illegalStatus: response.body.illegalStatus,
|
|
284
|
+
trafficLimit: response.body.trafficLimit,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
catch (error) {
|
|
288
|
+
if (error &&
|
|
289
|
+
typeof error === 'object' &&
|
|
290
|
+
'code' in error &&
|
|
291
|
+
(error.code === 'NotFoundApiGroup' || error.code === 'InvalidGroupId.NotFound')) {
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
throw error;
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
/**
|
|
298
|
+
* Find API Gateway group by name
|
|
299
|
+
*/
|
|
300
|
+
findApiGroupByName: async (groupName) => {
|
|
301
|
+
const request = new cloudapi.DescribeApiGroupsRequest({
|
|
302
|
+
groupName,
|
|
303
|
+
pageSize: 10,
|
|
304
|
+
pageNumber: 1,
|
|
305
|
+
});
|
|
306
|
+
const response = await apigwClient.describeApiGroups(request);
|
|
307
|
+
if (!response.body?.apiGroupAttributes?.apiGroupAttribute?.length) {
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
// Find exact match
|
|
311
|
+
const group = response.body.apiGroupAttributes.apiGroupAttribute.find((g) => g.groupName === groupName);
|
|
312
|
+
if (!group) {
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
return {
|
|
316
|
+
groupId: group.groupId,
|
|
317
|
+
groupName: group.groupName,
|
|
318
|
+
description: group.description,
|
|
319
|
+
basePath: group.basePath,
|
|
320
|
+
subDomain: group.subDomain,
|
|
321
|
+
instanceId: group.instanceId,
|
|
322
|
+
instanceType: group.instanceType,
|
|
323
|
+
regionId: group.regionId,
|
|
324
|
+
billingStatus: group.billingStatus,
|
|
325
|
+
illegalStatus: group.illegalStatus,
|
|
326
|
+
trafficLimit: group.trafficLimit,
|
|
327
|
+
};
|
|
328
|
+
},
|
|
329
|
+
/**
|
|
330
|
+
* Update API Gateway group
|
|
331
|
+
*/
|
|
332
|
+
updateApiGroup: async (groupId, config) => {
|
|
333
|
+
const request = new cloudapi.ModifyApiGroupRequest({
|
|
334
|
+
groupId,
|
|
335
|
+
groupName: config.groupName,
|
|
336
|
+
description: config.description,
|
|
337
|
+
basePath: config.basePath,
|
|
338
|
+
});
|
|
339
|
+
await apigwClient.modifyApiGroup(request);
|
|
340
|
+
},
|
|
341
|
+
/**
|
|
342
|
+
* Delete API Gateway group
|
|
343
|
+
*/
|
|
344
|
+
deleteApiGroup: async (groupId) => {
|
|
345
|
+
const request = new cloudapi.DeleteApiGroupRequest({
|
|
346
|
+
groupId,
|
|
347
|
+
});
|
|
348
|
+
await apigwClient.deleteApiGroup(request);
|
|
349
|
+
},
|
|
350
|
+
/**
|
|
351
|
+
* Create an API in API Gateway
|
|
352
|
+
*/
|
|
353
|
+
createApi: async (config) => {
|
|
354
|
+
const requestConfig = JSON.stringify(removeUndefined({
|
|
355
|
+
RequestProtocol: config.requestConfig.requestProtocol,
|
|
356
|
+
RequestHttpMethod: config.requestConfig.requestHttpMethod,
|
|
357
|
+
RequestPath: config.requestConfig.requestPath,
|
|
358
|
+
RequestMode: config.requestConfig.requestMode,
|
|
359
|
+
BodyFormat: config.requestConfig.bodyFormat,
|
|
360
|
+
}));
|
|
361
|
+
const serviceConfigObj = {
|
|
362
|
+
ServiceProtocol: config.serviceConfig.serviceProtocol,
|
|
363
|
+
ServiceAddress: config.serviceConfig.serviceAddress,
|
|
364
|
+
ServiceHttpMethod: config.serviceConfig.serviceHttpMethod,
|
|
365
|
+
ServicePath: config.serviceConfig.servicePath,
|
|
366
|
+
ServiceTimeout: config.serviceConfig.serviceTimeout || 10000,
|
|
367
|
+
MockResult: config.serviceConfig.mockResult,
|
|
368
|
+
};
|
|
369
|
+
if (config.serviceConfig.functionComputeConfig) {
|
|
370
|
+
serviceConfigObj.FunctionComputeConfig = removeUndefined({
|
|
371
|
+
FcRegionId: config.serviceConfig.functionComputeConfig.fcRegionId,
|
|
372
|
+
FunctionName: config.serviceConfig.functionComputeConfig.functionName,
|
|
373
|
+
RoleArn: config.serviceConfig.functionComputeConfig.roleArn,
|
|
374
|
+
FcVersion: config.serviceConfig.functionComputeConfig.fcVersion || '3.0',
|
|
375
|
+
Method: config.serviceConfig.functionComputeConfig.method,
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
if (config.serviceConfig.vpcConfig) {
|
|
379
|
+
serviceConfigObj.VpcConfig = {
|
|
380
|
+
VpcId: config.serviceConfig.vpcConfig.vpcId,
|
|
381
|
+
InstanceId: config.serviceConfig.vpcConfig.instanceId,
|
|
382
|
+
Port: config.serviceConfig.vpcConfig.port,
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
const serviceConfig = JSON.stringify(removeUndefined(serviceConfigObj));
|
|
386
|
+
const request = new cloudapi.CreateApiRequest({
|
|
387
|
+
groupId: config.groupId,
|
|
388
|
+
apiName: config.apiName,
|
|
389
|
+
description: config.description,
|
|
390
|
+
visibility: config.visibility,
|
|
391
|
+
authType: config.authType,
|
|
392
|
+
requestConfig,
|
|
393
|
+
serviceConfig,
|
|
394
|
+
resultType: config.resultType,
|
|
395
|
+
resultSample: config.resultSample,
|
|
396
|
+
failResultSample: config.failResultSample,
|
|
397
|
+
tag: config.tags?.map((t) => new cloudapi.CreateApiRequestTag({ key: t.key, value: t.value })),
|
|
398
|
+
});
|
|
399
|
+
const response = await apigwClient.createApi(request);
|
|
400
|
+
if (!response.body?.apiId) {
|
|
401
|
+
throw new Error('Failed to create API: no apiId returned');
|
|
402
|
+
}
|
|
403
|
+
return response.body.apiId;
|
|
404
|
+
},
|
|
405
|
+
/**
|
|
406
|
+
* Get API by API ID
|
|
407
|
+
*/
|
|
408
|
+
getApi: async (groupId, apiId) => {
|
|
409
|
+
try {
|
|
410
|
+
const request = new cloudapi.DescribeApiRequest({
|
|
411
|
+
groupId,
|
|
412
|
+
apiId,
|
|
413
|
+
});
|
|
414
|
+
const response = await apigwClient.describeApi(request);
|
|
415
|
+
if (!response.body) {
|
|
416
|
+
return null;
|
|
417
|
+
}
|
|
418
|
+
const body = response.body;
|
|
419
|
+
return {
|
|
420
|
+
apiId: body.apiId,
|
|
421
|
+
apiName: body.apiName,
|
|
422
|
+
groupId: body.groupId,
|
|
423
|
+
groupName: body.groupName,
|
|
424
|
+
description: body.description,
|
|
425
|
+
visibility: body.visibility,
|
|
426
|
+
authType: body.authType,
|
|
427
|
+
requestConfig: body.requestConfig
|
|
428
|
+
? {
|
|
429
|
+
requestProtocol: body.requestConfig.requestProtocol,
|
|
430
|
+
requestHttpMethod: body.requestConfig.requestHttpMethod,
|
|
431
|
+
requestPath: body.requestConfig.requestPath,
|
|
432
|
+
requestMode: body.requestConfig.requestMode,
|
|
433
|
+
bodyFormat: body.requestConfig.bodyFormat,
|
|
434
|
+
}
|
|
435
|
+
: undefined,
|
|
436
|
+
serviceConfig: body.serviceConfig
|
|
437
|
+
? {
|
|
438
|
+
serviceProtocol: body.serviceConfig.serviceProtocol,
|
|
439
|
+
serviceAddress: body.serviceConfig.serviceAddress,
|
|
440
|
+
serviceHttpMethod: body.serviceConfig.serviceHttpMethod,
|
|
441
|
+
servicePath: body.serviceConfig.servicePath,
|
|
442
|
+
serviceTimeout: body.serviceConfig.serviceTimeout,
|
|
443
|
+
functionComputeConfig: body.serviceConfig.functionComputeConfig
|
|
444
|
+
? {
|
|
445
|
+
fcRegionId: body.serviceConfig.functionComputeConfig.fcRegionId,
|
|
446
|
+
functionName: body.serviceConfig.functionComputeConfig.functionName,
|
|
447
|
+
roleArn: body.serviceConfig.functionComputeConfig.roleArn,
|
|
448
|
+
fcVersion: body.serviceConfig.functionComputeConfig.fcVersion,
|
|
449
|
+
method: body.serviceConfig.functionComputeConfig.method,
|
|
450
|
+
}
|
|
451
|
+
: undefined,
|
|
452
|
+
mockResult: body.serviceConfig.mockResult,
|
|
453
|
+
}
|
|
454
|
+
: undefined,
|
|
455
|
+
resultType: body.resultType,
|
|
456
|
+
resultSample: body.resultSample,
|
|
457
|
+
createdTime: body.createdTime,
|
|
458
|
+
modifiedTime: body.modifiedTime,
|
|
459
|
+
deployedInfos: body.deployedInfos?.deployedInfo?.map((info) => ({
|
|
460
|
+
stageName: info.stageName,
|
|
461
|
+
deployedStatus: info.deployedStatus,
|
|
462
|
+
effectiveVersion: info.effectiveVersion,
|
|
463
|
+
})),
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
catch (error) {
|
|
467
|
+
if (error &&
|
|
468
|
+
typeof error === 'object' &&
|
|
469
|
+
'code' in error &&
|
|
470
|
+
(error.code === 'NotFoundApi' || error.code === 'InvalidApiId.NotFound')) {
|
|
471
|
+
return null;
|
|
472
|
+
}
|
|
473
|
+
throw error;
|
|
474
|
+
}
|
|
475
|
+
},
|
|
476
|
+
/**
|
|
477
|
+
* Update API
|
|
478
|
+
*/
|
|
479
|
+
updateApi: async (apiId, config) => {
|
|
480
|
+
const requestConfig = JSON.stringify(removeUndefined({
|
|
481
|
+
RequestProtocol: config.requestConfig.requestProtocol,
|
|
482
|
+
RequestHttpMethod: config.requestConfig.requestHttpMethod,
|
|
483
|
+
RequestPath: config.requestConfig.requestPath,
|
|
484
|
+
RequestMode: config.requestConfig.requestMode,
|
|
485
|
+
BodyFormat: config.requestConfig.bodyFormat,
|
|
486
|
+
}));
|
|
487
|
+
const serviceConfigObj = {
|
|
488
|
+
ServiceProtocol: config.serviceConfig.serviceProtocol,
|
|
489
|
+
ServiceAddress: config.serviceConfig.serviceAddress,
|
|
490
|
+
ServiceHttpMethod: config.serviceConfig.serviceHttpMethod,
|
|
491
|
+
ServicePath: config.serviceConfig.servicePath,
|
|
492
|
+
ServiceTimeout: config.serviceConfig.serviceTimeout || 10000,
|
|
493
|
+
MockResult: config.serviceConfig.mockResult,
|
|
494
|
+
};
|
|
495
|
+
if (config.serviceConfig.functionComputeConfig) {
|
|
496
|
+
serviceConfigObj.FunctionComputeConfig = removeUndefined({
|
|
497
|
+
FcRegionId: config.serviceConfig.functionComputeConfig.fcRegionId,
|
|
498
|
+
FunctionName: config.serviceConfig.functionComputeConfig.functionName,
|
|
499
|
+
RoleArn: config.serviceConfig.functionComputeConfig.roleArn,
|
|
500
|
+
FcVersion: config.serviceConfig.functionComputeConfig.fcVersion || '3.0',
|
|
501
|
+
Method: config.serviceConfig.functionComputeConfig.method,
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
const serviceConfig = JSON.stringify(removeUndefined(serviceConfigObj));
|
|
505
|
+
const request = new cloudapi.ModifyApiRequest({
|
|
506
|
+
groupId: config.groupId,
|
|
507
|
+
apiId,
|
|
508
|
+
apiName: config.apiName,
|
|
509
|
+
description: config.description,
|
|
510
|
+
visibility: config.visibility,
|
|
511
|
+
authType: config.authType,
|
|
512
|
+
requestConfig,
|
|
513
|
+
serviceConfig,
|
|
514
|
+
resultType: config.resultType,
|
|
515
|
+
resultSample: config.resultSample,
|
|
516
|
+
failResultSample: config.failResultSample,
|
|
517
|
+
});
|
|
518
|
+
await apigwClient.modifyApi(request);
|
|
519
|
+
},
|
|
520
|
+
/**
|
|
521
|
+
* Delete API
|
|
522
|
+
*/
|
|
523
|
+
deleteApi: async (groupId, apiId) => {
|
|
524
|
+
const request = new cloudapi.DeleteApiRequest({
|
|
525
|
+
groupId,
|
|
526
|
+
apiId,
|
|
527
|
+
});
|
|
528
|
+
await apigwClient.deleteApi(request);
|
|
529
|
+
},
|
|
530
|
+
/**
|
|
531
|
+
* Deploy API to a stage
|
|
532
|
+
*/
|
|
533
|
+
deployApi: async (config) => {
|
|
534
|
+
const request = new cloudapi.DeployApiRequest({
|
|
535
|
+
groupId: config.groupId,
|
|
536
|
+
apiId: config.apiId,
|
|
537
|
+
stageName: config.stageName,
|
|
538
|
+
description: config.description,
|
|
539
|
+
});
|
|
540
|
+
await apigwClient.deployApi(request);
|
|
541
|
+
},
|
|
542
|
+
/**
|
|
543
|
+
* Abolish (undeploy) API from a stage
|
|
544
|
+
*/
|
|
545
|
+
abolishApi: async (groupId, apiId, stageName) => {
|
|
546
|
+
const request = new cloudapi.AbolishApiRequest({
|
|
547
|
+
groupId,
|
|
548
|
+
apiId,
|
|
549
|
+
stageName,
|
|
550
|
+
});
|
|
551
|
+
await apigwClient.abolishApi(request);
|
|
552
|
+
},
|
|
553
|
+
/**
|
|
554
|
+
* Bind custom domain to API group with automatic verification
|
|
555
|
+
*/
|
|
556
|
+
bindCustomDomain: async (config, state, eventLogicalId) => {
|
|
557
|
+
logger_1.logger.info(lang_1.lang.__('APIGW_BINDING_DOMAIN', { domain: config.domainName }));
|
|
558
|
+
// Get the API group info to extract verification token from subDomain
|
|
559
|
+
const groupInfo = await apigwClient.describeApiGroup(new cloudapi.DescribeApiGroupRequest({ groupId: config.groupId }));
|
|
560
|
+
const region = groupInfo.body?.regionId || _context.region;
|
|
561
|
+
// Try to bind the domain first
|
|
562
|
+
try {
|
|
563
|
+
const request = new cloudapi.SetDomainRequest({
|
|
564
|
+
groupId: config.groupId,
|
|
565
|
+
domainName: config.domainName,
|
|
566
|
+
bindStageName: config.bindStageName || 'RELEASE',
|
|
567
|
+
customDomainType: config.customDomainType,
|
|
568
|
+
isHttpRedirectToHttps: config.isHttpRedirectToHttps,
|
|
569
|
+
});
|
|
570
|
+
await apigwClient.setDomain(request);
|
|
571
|
+
// Set certificate if provided
|
|
572
|
+
if (config.certificateName && config.certificateBody && config.certificatePrivateKey) {
|
|
573
|
+
const certRequest = new cloudapi.SetDomainCertificateRequest({
|
|
574
|
+
groupId: config.groupId,
|
|
575
|
+
domainName: config.domainName,
|
|
576
|
+
certificateName: config.certificateName,
|
|
577
|
+
certificateBody: config.certificateBody,
|
|
578
|
+
certificatePrivateKey: config.certificatePrivateKey,
|
|
579
|
+
});
|
|
580
|
+
await apigwClient.setDomainCertificate(certRequest);
|
|
581
|
+
}
|
|
582
|
+
logger_1.logger.info(lang_1.lang.__('APIGW_DOMAIN_BOUND_SUCCESS', { domain: config.domainName }));
|
|
583
|
+
return state;
|
|
584
|
+
}
|
|
585
|
+
catch (error) {
|
|
586
|
+
const err = error;
|
|
587
|
+
// Check if it's a domain ownership verification error
|
|
588
|
+
if (err.code === 'SingleDomainOwnershipCheckFail' || err.message?.includes('ownership')) {
|
|
589
|
+
logger_1.logger.error(lang_1.lang.__('APIGW_DOMAIN_OWNERSHIP_FAILED', { domain: config.domainName }));
|
|
590
|
+
const verificationToken = extractVerificationToken(error, groupInfo.body);
|
|
591
|
+
if (verificationToken && groupInfo.body?.subDomain) {
|
|
592
|
+
logger_1.logger.info(lang_1.lang.__('APIGW_ATTEMPTING_AUTO_VERIFICATION', { token: verificationToken }));
|
|
593
|
+
try {
|
|
594
|
+
// Try to add DNS verification record automatically and update state
|
|
595
|
+
state = await addDomainVerificationRecord(config.domainName, verificationToken, groupInfo.body.subDomain, region, state, eventLogicalId);
|
|
596
|
+
// Retry domain binding after DNS verification
|
|
597
|
+
logger_1.logger.info(lang_1.lang.__('APIGW_RETRYING_DOMAIN_BINDING'));
|
|
598
|
+
const retryRequest = new cloudapi.SetDomainRequest({
|
|
599
|
+
groupId: config.groupId,
|
|
600
|
+
domainName: config.domainName,
|
|
601
|
+
bindStageName: config.bindStageName || 'RELEASE',
|
|
602
|
+
customDomainType: config.customDomainType,
|
|
603
|
+
isHttpRedirectToHttps: config.isHttpRedirectToHttps,
|
|
604
|
+
});
|
|
605
|
+
await apigwClient.setDomain(retryRequest);
|
|
606
|
+
// Set certificate if provided
|
|
607
|
+
if (config.certificateName &&
|
|
608
|
+
config.certificateBody &&
|
|
609
|
+
config.certificatePrivateKey) {
|
|
610
|
+
const certRequest = new cloudapi.SetDomainCertificateRequest({
|
|
611
|
+
groupId: config.groupId,
|
|
612
|
+
domainName: config.domainName,
|
|
613
|
+
certificateName: config.certificateName,
|
|
614
|
+
certificateBody: config.certificateBody,
|
|
615
|
+
certificatePrivateKey: config.certificatePrivateKey,
|
|
616
|
+
});
|
|
617
|
+
await apigwClient.setDomainCertificate(certRequest);
|
|
618
|
+
}
|
|
619
|
+
logger_1.logger.info(lang_1.lang.__('APIGW_DOMAIN_BOUND_AFTER_VERIFICATION', { domain: config.domainName }));
|
|
620
|
+
return state;
|
|
621
|
+
}
|
|
622
|
+
catch (retryError) {
|
|
623
|
+
logger_1.logger.error(lang_1.lang.__('APIGW_AUTO_VERIFICATION_FAILED', { error: String(retryError) }));
|
|
624
|
+
// Fall through to show manual instructions
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
// Show manual verification instructions
|
|
628
|
+
if (verificationToken && groupInfo.body?.subDomain) {
|
|
629
|
+
logVerificationInstructions(config.domainName, verificationToken, groupInfo.body.subDomain);
|
|
630
|
+
}
|
|
631
|
+
else {
|
|
632
|
+
logger_1.logger.error(lang_1.lang.__('APIGW_NO_VERIFICATION_TOKEN'));
|
|
633
|
+
logger_1.logger.error(lang_1.lang.__('APIGW_MANUAL_VERIFICATION_REQUIRED'));
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
// Re-throw the error to be handled by caller
|
|
637
|
+
throw error;
|
|
638
|
+
}
|
|
639
|
+
},
|
|
640
|
+
/**
|
|
641
|
+
* Unbind custom domain from API group
|
|
642
|
+
*/
|
|
643
|
+
unbindCustomDomain: async (groupId, domainName) => {
|
|
644
|
+
const request = new cloudapi.DeleteDomainRequest({
|
|
645
|
+
groupId,
|
|
646
|
+
domainName,
|
|
647
|
+
});
|
|
648
|
+
await apigwClient.deleteDomain(request);
|
|
649
|
+
},
|
|
650
|
+
};
|
|
651
|
+
};
|
|
652
|
+
exports.createApigwOperations = createApigwOperations;
|