@geek-fun/serverlessinsight 0.6.7 → 0.6.9

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.
@@ -8,6 +8,7 @@ const common_1 = require("../../common");
8
8
  const certUtils_1 = require("../../common/certUtils");
9
9
  const logger_1 = require("../../common/logger");
10
10
  const lang_1 = require("../../lang");
11
+ const domainUtils_1 = require("../../common/domainUtils");
11
12
  const buildApigwGroupInstanceFromProvider = (info, stage) => {
12
13
  return {
13
14
  type: 'ALIYUN_APIGW_GROUP',
@@ -130,13 +131,7 @@ const createApigwResource = async (context, event, serviceName, roleArn, state)
130
131
  path: t.path,
131
132
  backend: t.backend,
132
133
  })),
133
- domain: event.domain
134
- ? {
135
- domainName: event.domain.domain_name,
136
- hasCertificate: !!(event.domain.certificate_body || event.domain.certificate_id),
137
- protocol: event.domain.protocol ?? null,
138
- }
139
- : null,
134
+ domain: (0, apigwTypes_1.extractEventDomainDefinition)(event.domain),
140
135
  },
141
136
  instances,
142
137
  lastUpdated: new Date().toISOString(),
@@ -170,13 +165,7 @@ const createApigwResource = async (context, event, serviceName, roleArn, state)
170
165
  path: t.path,
171
166
  backend: t.backend,
172
167
  })),
173
- domain: event.domain
174
- ? {
175
- domainName: event.domain.domain_name,
176
- hasCertificate: !!(event.domain.certificate_body || event.domain.certificate_id),
177
- protocol: event.domain.protocol ?? null,
178
- }
179
- : null,
168
+ domain: (0, apigwTypes_1.extractEventDomainDefinition)(event.domain),
180
169
  },
181
170
  instances,
182
171
  lastUpdated: new Date().toISOString(),
@@ -185,8 +174,22 @@ const createApigwResource = async (context, event, serviceName, roleArn, state)
185
174
  }
186
175
  if (event.domain) {
187
176
  try {
177
+ const primaryDomain = event.domain.domain_name;
178
+ const wwwBindApex = event.domain.www_bind_apex === true;
188
179
  const domainConfig = await buildDomainBindingConfig(event.domain, groupId, serviceName, event.key, context.stage, client);
189
180
  state = await client.apigw.bindCustomDomain(domainConfig, state, logicalId);
181
+ const wwwDomain = wwwBindApex ? (0, domainUtils_1.deriveWwwDomain)(primaryDomain) : null;
182
+ if (wwwDomain) {
183
+ logger_1.logger.info(lang_1.lang.__('APIGW_BINDING_DOMAIN', { domain: wwwDomain }));
184
+ const wwwDomainConfig = {
185
+ ...domainConfig,
186
+ domainName: wwwDomain,
187
+ certificateName: domainConfig.certificateName
188
+ ? `${domainConfig.certificateName}-www`
189
+ : undefined,
190
+ };
191
+ state = await client.apigw.bindCustomDomain(wwwDomainConfig, state, logicalId);
192
+ }
190
193
  }
191
194
  catch (error) {
192
195
  logger_1.logger.error(lang_1.lang.__('APIGW_DOMAIN_BINDING_FAILED', { error: String(error) }));
@@ -206,13 +209,7 @@ const createApigwResource = async (context, event, serviceName, roleArn, state)
206
209
  path: t.path,
207
210
  backend: t.backend,
208
211
  })),
209
- domain: event.domain
210
- ? {
211
- domainName: event.domain.domain_name,
212
- hasCertificate: !!(event.domain.certificate_body || event.domain.certificate_id),
213
- protocol: event.domain.protocol ?? null,
214
- }
215
- : null,
212
+ domain: (0, apigwTypes_1.extractEventDomainDefinition)(event.domain),
216
213
  },
217
214
  instances,
218
215
  lastUpdated: new Date().toISOString(),
@@ -301,8 +298,65 @@ const updateApigwResource = async (context, event, serviceName, roleArn, state)
301
298
  }
302
299
  }
303
300
  if (event.domain) {
301
+ const primaryDomain = event.domain.domain_name;
302
+ const wwwBindApex = event.domain.www_bind_apex === true;
303
+ const existingDomain = existingState.definition?.domain;
304
+ const previousWwwBindApex = existingDomain?.wwwBindApex === true;
305
+ const previousDomainName = existingDomain?.domainName;
304
306
  const domainConfig = await buildDomainBindingConfig(event.domain, groupId, serviceName, event.key, context.stage, client);
305
307
  state = await client.apigw.bindCustomDomain(domainConfig, state, logicalId);
308
+ const wwwDomain = wwwBindApex ? (0, domainUtils_1.deriveWwwDomain)(primaryDomain) : null;
309
+ if (wwwDomain) {
310
+ logger_1.logger.info(lang_1.lang.__('APIGW_BINDING_DOMAIN', { domain: wwwDomain }));
311
+ const wwwDomainConfig = {
312
+ ...domainConfig,
313
+ domainName: wwwDomain,
314
+ certificateName: domainConfig.certificateName
315
+ ? `${domainConfig.certificateName}-www`
316
+ : undefined,
317
+ };
318
+ state = await client.apigw.bindCustomDomain(wwwDomainConfig, state, logicalId);
319
+ }
320
+ if (previousWwwBindApex && previousDomainName) {
321
+ const previousWwwDomain = (0, domainUtils_1.deriveWwwDomain)(previousDomainName);
322
+ if (previousWwwDomain && previousWwwDomain !== wwwDomain) {
323
+ try {
324
+ await client.apigw.unbindCustomDomain(groupId, previousWwwDomain);
325
+ }
326
+ catch (error) {
327
+ logger_1.logger.warn(lang_1.lang.__('APIGW_WWW_DOMAIN_UNBIND_FAILED', {
328
+ domain: previousWwwDomain,
329
+ error: String(error),
330
+ }));
331
+ }
332
+ }
333
+ }
334
+ }
335
+ else {
336
+ const existingDomain = existingState.definition?.domain;
337
+ if (existingDomain?.domainName) {
338
+ const previousDomain = existingDomain.domainName;
339
+ try {
340
+ await client.apigw.unbindCustomDomain(groupId, previousDomain);
341
+ }
342
+ catch (error) {
343
+ logger_1.logger.warn(lang_1.lang.__('APIGW_DOMAIN_UNBIND_FAILED', { domain: previousDomain, error: String(error) }));
344
+ }
345
+ if (existingDomain.wwwBindApex === true) {
346
+ const previousWwwDomain = (0, domainUtils_1.deriveWwwDomain)(previousDomain);
347
+ if (previousWwwDomain) {
348
+ try {
349
+ await client.apigw.unbindCustomDomain(groupId, previousWwwDomain);
350
+ }
351
+ catch (error) {
352
+ logger_1.logger.warn(lang_1.lang.__('APIGW_WWW_DOMAIN_UNBIND_FAILED', {
353
+ domain: previousWwwDomain,
354
+ error: String(error),
355
+ }));
356
+ }
357
+ }
358
+ }
359
+ }
306
360
  }
307
361
  const groupDefinition = (0, apigwTypes_1.extractApigwGroupDefinition)(groupConfig);
308
362
  const resourceState = {
@@ -315,13 +369,7 @@ const updateApigwResource = async (context, event, serviceName, roleArn, state)
315
369
  path: t.path,
316
370
  backend: t.backend,
317
371
  })),
318
- domain: event.domain
319
- ? {
320
- domainName: event.domain.domain_name,
321
- hasCertificate: !!(event.domain.certificate_body || event.domain.certificate_id),
322
- protocol: event.domain.protocol ?? null,
323
- }
324
- : null,
372
+ domain: (0, apigwTypes_1.extractEventDomainDefinition)(event.domain),
325
373
  },
326
374
  instances,
327
375
  lastUpdated: new Date().toISOString(),
@@ -344,6 +392,30 @@ const deleteApigwResource = async (context, logicalId, state) => {
344
392
  }
345
393
  const groupId = groupInstance.id;
346
394
  state = await cleanupDnsRecords(context, logicalId, state);
395
+ const existingDomain = existingState.definition?.domain;
396
+ if (existingDomain?.domainName) {
397
+ const primaryDomain = existingDomain.domainName;
398
+ try {
399
+ await client.apigw.unbindCustomDomain(groupId, primaryDomain);
400
+ }
401
+ catch (error) {
402
+ logger_1.logger.warn(lang_1.lang.__('APIGW_DOMAIN_UNBIND_FAILED', { domain: primaryDomain, error: String(error) }));
403
+ }
404
+ if (existingDomain.wwwBindApex === true) {
405
+ const wwwDomain = (0, domainUtils_1.deriveWwwDomain)(primaryDomain);
406
+ if (wwwDomain) {
407
+ try {
408
+ await client.apigw.unbindCustomDomain(groupId, wwwDomain);
409
+ }
410
+ catch (error) {
411
+ logger_1.logger.warn(lang_1.lang.__('APIGW_WWW_DOMAIN_UNBIND_FAILED', {
412
+ domain: wwwDomain,
413
+ error: String(error),
414
+ }));
415
+ }
416
+ }
417
+ }
418
+ }
347
419
  const deployments = existingInstances.filter((i) => i.type === 'ALIYUN_APIGW_DEPLOYMENT');
348
420
  for (const deployment of deployments) {
349
421
  try {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.inferProtocolConfig = exports.extractApigwDeploymentDefinition = exports.extractApigwApiDefinition = exports.extractApigwGroupDefinition = exports.triggerToApigwApiConfig = exports.generateApiKey = exports.eventToApigwGroupConfig = void 0;
3
+ exports.extractEventDomainDefinition = exports.inferProtocolConfig = exports.extractApigwDeploymentDefinition = exports.extractApigwApiDefinition = exports.extractApigwGroupDefinition = exports.triggerToApigwApiConfig = exports.generateApiKey = exports.eventToApigwGroupConfig = void 0;
4
4
  const common_1 = require("../../common");
5
5
  const lang_1 = require("../../lang");
6
6
  /**
@@ -155,3 +155,17 @@ const inferProtocolConfig = (protocol) => {
155
155
  return { requestProtocol: protocol };
156
156
  };
157
157
  exports.inferProtocolConfig = inferProtocolConfig;
158
+ const extractEventDomainDefinition = (domain) => {
159
+ if (!domain) {
160
+ return null;
161
+ }
162
+ return {
163
+ domainName: domain.domain_name,
164
+ wwwBindApex: domain.www_bind_apex === true,
165
+ certificateId: domain.certificate_id ?? null,
166
+ certificateBody: domain.certificate_body ?? null,
167
+ certificatePrivateKey: domain.certificate_private_key ? '(managed)' : null,
168
+ protocol: domain.protocol ?? null,
169
+ };
170
+ };
171
+ exports.extractEventDomainDefinition = extractEventDomainDefinition;
@@ -4,6 +4,32 @@ exports.generateFunctionPlan = void 0;
4
4
  const common_1 = require("../../common");
5
5
  const aliyunClient_1 = require("../../common/aliyunClient");
6
6
  const fc3Types_1 = require("./fc3Types");
7
+ const lang_1 = require("../../lang");
8
+ const isSecurityGroupId = (value) => value.startsWith('sg-');
9
+ const resolveSecurityGroupId = async (context, securityGroupName, vpcId) => {
10
+ if (isSecurityGroupId(securityGroupName)) {
11
+ return securityGroupName;
12
+ }
13
+ const client = (0, aliyunClient_1.createAliyunClient)(context);
14
+ const sg = await client.ecs.getSecurityGroupByName(securityGroupName, vpcId);
15
+ if (!sg) {
16
+ throw new Error(lang_1.lang.__('SECURITY_GROUP_NOT_FOUND', { sgName: securityGroupName, vpcId: vpcId ?? 'default' }));
17
+ }
18
+ return sg.securityGroupId;
19
+ };
20
+ const resolveVpcConfigSecurityGroup = async (context, config) => {
21
+ if (!config.vpcConfig?.securityGroupId) {
22
+ return config;
23
+ }
24
+ const securityGroupId = await resolveSecurityGroupId(context, config.vpcConfig.securityGroupId, config.vpcConfig.vpcId);
25
+ return {
26
+ ...config,
27
+ vpcConfig: {
28
+ ...config.vpcConfig,
29
+ securityGroupId,
30
+ },
31
+ };
32
+ };
7
33
  const planFunctionDeletion = (logicalId, definition) => ({
8
34
  logicalId,
9
35
  action: 'delete',
@@ -22,7 +48,8 @@ const generateFunctionPlan = async (context, state, functions) => {
22
48
  const functionItems = await Promise.all(functions.map(async (fn) => {
23
49
  const logicalId = `functions.${fn.key}`;
24
50
  const currentState = (0, common_1.getResource)(state, logicalId);
25
- const config = (0, fc3Types_1.functionToFc3Config)(fn);
51
+ const rawConfig = (0, fc3Types_1.functionToFc3Config)(fn);
52
+ const config = await resolveVpcConfigSecurityGroup(context, rawConfig);
26
53
  const codePath = fn.code.path;
27
54
  const desiredCodeHash = (0, common_1.computeFileHash)(codePath);
28
55
  const desiredDefinition = (0, fc3Types_1.extractFc3Definition)(config, desiredCodeHash);
@@ -247,13 +247,13 @@ const createDependentResources = async (context, fn, serviceName, existingInstan
247
247
  const accessGroupName = `${fn.name}-${context.stage}-nas-access-${mountPath}`;
248
248
  logger_1.logger.info(lang_1.lang.__('CREATING_NAS_ACCESS_GROUP', { accessGroupName }));
249
249
  const accessGroup = await client.nas.createAccessGroup(accessGroupName);
250
+ logger_1.logger.info(lang_1.lang.__('CREATING_NAS_ACCESS_RULE', { accessGroupName }));
251
+ const accessRule = await client.nas.createAccessRule(accessGroupName, '10.0.0.0/8');
250
252
  instances.push({
251
253
  type: 'ALIYUN_NAS_ACCESS_GROUP',
252
254
  id: accessGroupName,
253
- attributes: { ...accessGroup },
255
+ attributes: { ...accessGroup, accessRules: [accessRule] },
254
256
  });
255
- logger_1.logger.info(lang_1.lang.__('CREATING_NAS_ACCESS_RULE', { accessGroupName }));
256
- await client.nas.createAccessRule(accessGroupName, '10.0.0.0/8');
257
257
  logger_1.logger.info(lang_1.lang.__('CREATING_NAS_FILE_SYSTEM', { name: fn.name }));
258
258
  const fileSystem = await client.nas.createFileSystem(nasItem.storage_class, fn.name);
259
259
  instances.push({
@@ -50,6 +50,23 @@ const functionToFc3Config = (fn) => {
50
50
  securityGroupId: fn.network.security_group.name,
51
51
  };
52
52
  }
53
+ if (fn.storage?.nas && fn.storage.nas.length > 0) {
54
+ config.nasConfig = {
55
+ userId: 10003,
56
+ groupId: 10003,
57
+ mountPoints: fn.storage.nas.map((nas) => ({
58
+ serverAddr: nas.storage_class,
59
+ mountDir: nas.mount_path,
60
+ enableTls: false,
61
+ })),
62
+ };
63
+ }
64
+ if (fn.log !== undefined) {
65
+ config.logConfig = {
66
+ enableRequestMetrics: fn.log,
67
+ enableInstanceMetrics: fn.log,
68
+ };
69
+ }
53
70
  return config;
54
71
  };
55
72
  exports.functionToFc3Config = functionToFc3Config;
@@ -65,6 +82,8 @@ const extractFc3Definition = (config, codeHash) => {
65
82
  vpcConfig: config.vpcConfig ?? null,
66
83
  gpuConfig: config.gpuConfig ?? null,
67
84
  customContainerConfig: config.customContainerConfig ?? null,
85
+ nasConfig: config.nasConfig ?? null,
86
+ logConfig: config.logConfig ?? null,
68
87
  codeHash,
69
88
  };
70
89
  };
@@ -12,6 +12,7 @@ const ossTypes_1 = require("./ossTypes");
12
12
  const logger_1 = require("../../common/logger");
13
13
  const lang_1 = require("../../lang");
14
14
  const node_path_1 = __importDefault(require("node:path"));
15
+ const domainUtils_1 = require("../../common/domainUtils");
15
16
  const buildOssInstanceFromProvider = (info, sid) => {
16
17
  return {
17
18
  type: types_1.ResourceTypeEnum.ALIYUN_OSS_BUCKET,
@@ -149,35 +150,59 @@ const createBucketResource = async (context, bucket, state) => {
149
150
  let cnameInfo;
150
151
  if (bucket.website?.domain) {
151
152
  const certificate = await resolveBucketDomainCertificate(bucket, client);
153
+ const primaryDomain = bucket.website.domain;
154
+ const wwwBindApex = bucket.website.www_bind_apex ?? false;
152
155
  logger_1.logger.info(lang_1.lang.__('BINDING_CUSTOM_DOMAIN_TO_BUCKET', {
153
- domain: bucket.website.domain,
156
+ domain: primaryDomain,
154
157
  bucketName: config.bucketName,
155
158
  }));
156
159
  if (certificate) {
157
160
  logger_1.logger.info(lang_1.lang.__('OSS_BUCKET_CERT_BINDING', {
158
- domain: bucket.website.domain,
161
+ domain: primaryDomain,
159
162
  bucketName: config.bucketName,
160
163
  }));
161
164
  }
162
- cnameInfo = await client.oss.bindCustomDomain(config.bucketName, bucket.website.domain, certificate);
165
+ cnameInfo = await client.oss.bindCustomDomain(config.bucketName, primaryDomain, certificate);
163
166
  if (cnameInfo) {
164
- const instanceId = cnameInfo.dnsRecordId ?? bucket.website.domain;
167
+ const instanceId = cnameInfo.dnsRecordId ?? primaryDomain;
165
168
  const dnsInstance = {
166
169
  sid: (0, common_1.buildSid)('aliyun', 'alidns', context.stage, instanceId),
167
170
  id: instanceId,
168
171
  type: types_1.ResourceTypeEnum.ALIYUN_OSS_DNS_CNAME,
169
- domain: bucket.website.domain,
172
+ domain: primaryDomain,
170
173
  cname: cnameInfo.cname,
171
174
  ...(cnameInfo.dnsRecordId ? { dnsRecordId: cnameInfo.dnsRecordId } : {}),
172
175
  ...(cnameInfo.txtRecordId ? { txtRecordId: cnameInfo.txtRecordId } : {}),
173
176
  };
174
177
  instances.push(dnsInstance);
175
- // Refresh bucket info to capture auto-added CORS rule
176
- bucketInfo = await client.oss.getBucket(config.bucketName);
177
- if (bucketInfo) {
178
- instances[0] = buildOssInstanceFromProvider(bucketInfo, sid);
178
+ }
179
+ const wwwDomain = wwwBindApex ? (0, domainUtils_1.deriveWwwDomain)(primaryDomain) : null;
180
+ if (wwwDomain) {
181
+ logger_1.logger.info(lang_1.lang.__('BINDING_CUSTOM_DOMAIN_TO_BUCKET', {
182
+ domain: wwwDomain,
183
+ bucketName: config.bucketName,
184
+ }));
185
+ const wwwCnameInfo = await client.oss.bindCustomDomain(config.bucketName, wwwDomain, certificate);
186
+ if (wwwCnameInfo) {
187
+ const wwwInstanceId = wwwCnameInfo.dnsRecordId ?? wwwDomain;
188
+ const wwwDnsInstance = {
189
+ sid: (0, common_1.buildSid)('aliyun', 'alidns', context.stage, wwwInstanceId),
190
+ id: wwwInstanceId,
191
+ type: types_1.ResourceTypeEnum.ALIYUN_OSS_DNS_CNAME,
192
+ domain: wwwDomain,
193
+ cname: wwwCnameInfo.cname,
194
+ isWwwVariant: true,
195
+ ...(wwwCnameInfo.dnsRecordId ? { dnsRecordId: wwwCnameInfo.dnsRecordId } : {}),
196
+ ...(wwwCnameInfo.txtRecordId ? { txtRecordId: wwwCnameInfo.txtRecordId } : {}),
197
+ };
198
+ instances.push(wwwDnsInstance);
179
199
  }
180
200
  }
201
+ // Refresh bucket info to capture auto-added CORS rule
202
+ bucketInfo = await client.oss.getBucket(config.bucketName);
203
+ if (bucketInfo) {
204
+ instances[0] = buildOssInstanceFromProvider(bucketInfo, sid);
205
+ }
181
206
  }
182
207
  // Upload static files if code path is specified
183
208
  if (bucket.website?.code) {
@@ -236,46 +261,78 @@ const updateBucketResource = async (context, bucket, state) => {
236
261
  const logicalId = `buckets.${bucket.key}`;
237
262
  const instances = [buildOssInstanceFromProvider(bucketInfo, sid)];
238
263
  const existingState = state.resources[logicalId];
239
- const existingDnsInstance = existingState?.instances?.find((i) => i.type === types_1.ResourceTypeEnum.ALIYUN_OSS_DNS_CNAME);
264
+ const existingDnsInstances = existingState?.instances?.filter((i) => i.type === types_1.ResourceTypeEnum.ALIYUN_OSS_DNS_CNAME);
265
+ const existingPrimaryDnsInstance = existingDnsInstances?.find((i) => !i.isWwwVariant);
266
+ const existingWwwDnsInstance = existingDnsInstances?.find((i) => i.isWwwVariant);
240
267
  let cnameInfo;
241
268
  if (bucket.website?.domain) {
242
- const domainChanged = existingDnsInstance?.domain !== bucket.website.domain;
243
- if (domainChanged && existingDnsInstance) {
244
- await client.oss.unbindCustomDomain(config.bucketName, existingDnsInstance.domain, existingDnsInstance.dnsRecordId, existingDnsInstance.txtRecordId);
269
+ const primaryDomain = bucket.website.domain;
270
+ const wwwBindApex = bucket.website.www_bind_apex ?? false;
271
+ const domainChanged = existingPrimaryDnsInstance?.domain !== primaryDomain;
272
+ if (domainChanged && existingDnsInstances) {
273
+ for (const instance of existingDnsInstances) {
274
+ await client.oss.unbindCustomDomain(config.bucketName, instance.domain, instance.dnsRecordId, instance.txtRecordId);
275
+ }
245
276
  }
246
277
  const certificate = await resolveBucketDomainCertificate(bucket, client);
247
278
  logger_1.logger.info(lang_1.lang.__('BINDING_CUSTOM_DOMAIN_TO_BUCKET', {
248
- domain: bucket.website.domain,
279
+ domain: primaryDomain,
249
280
  bucketName: config.bucketName,
250
281
  }));
251
282
  if (certificate) {
252
283
  logger_1.logger.info(lang_1.lang.__('OSS_BUCKET_CERT_BINDING', {
253
- domain: bucket.website.domain,
284
+ domain: primaryDomain,
254
285
  bucketName: config.bucketName,
255
286
  }));
256
287
  }
257
- cnameInfo = await client.oss.bindCustomDomain(config.bucketName, bucket.website.domain, certificate);
288
+ cnameInfo = await client.oss.bindCustomDomain(config.bucketName, primaryDomain, certificate);
258
289
  if (cnameInfo) {
259
- const instanceId = cnameInfo.dnsRecordId ?? bucket.website.domain;
290
+ const instanceId = cnameInfo.dnsRecordId ?? primaryDomain;
260
291
  const dnsInstance = {
261
292
  sid: (0, common_1.buildSid)('aliyun', 'alidns', context.stage, instanceId),
262
293
  id: instanceId,
263
294
  type: types_1.ResourceTypeEnum.ALIYUN_OSS_DNS_CNAME,
264
- domain: bucket.website.domain,
295
+ domain: primaryDomain,
265
296
  cname: cnameInfo.cname,
266
297
  ...(cnameInfo.dnsRecordId ? { dnsRecordId: cnameInfo.dnsRecordId } : {}),
267
298
  ...(cnameInfo.txtRecordId ? { txtRecordId: cnameInfo.txtRecordId } : {}),
268
299
  };
269
300
  instances.push(dnsInstance);
270
- // Refresh bucket info to capture auto-added CORS rule
271
- const refreshedInfo = await client.oss.getBucket(config.bucketName);
272
- if (refreshedInfo) {
273
- instances[0] = buildOssInstanceFromProvider(refreshedInfo, sid);
301
+ }
302
+ const wwwDomain = wwwBindApex ? (0, domainUtils_1.deriveWwwDomain)(primaryDomain) : null;
303
+ if (wwwDomain) {
304
+ logger_1.logger.info(lang_1.lang.__('BINDING_CUSTOM_DOMAIN_TO_BUCKET', {
305
+ domain: wwwDomain,
306
+ bucketName: config.bucketName,
307
+ }));
308
+ const wwwCnameInfo = await client.oss.bindCustomDomain(config.bucketName, wwwDomain, certificate);
309
+ if (wwwCnameInfo) {
310
+ const wwwInstanceId = wwwCnameInfo.dnsRecordId ?? wwwDomain;
311
+ const wwwDnsInstance = {
312
+ sid: (0, common_1.buildSid)('aliyun', 'alidns', context.stage, wwwInstanceId),
313
+ id: wwwInstanceId,
314
+ type: types_1.ResourceTypeEnum.ALIYUN_OSS_DNS_CNAME,
315
+ domain: wwwDomain,
316
+ cname: wwwCnameInfo.cname,
317
+ isWwwVariant: true,
318
+ ...(wwwCnameInfo.dnsRecordId ? { dnsRecordId: wwwCnameInfo.dnsRecordId } : {}),
319
+ ...(wwwCnameInfo.txtRecordId ? { txtRecordId: wwwCnameInfo.txtRecordId } : {}),
320
+ };
321
+ instances.push(wwwDnsInstance);
274
322
  }
275
323
  }
324
+ else if (existingWwwDnsInstance && !wwwBindApex) {
325
+ await client.oss.unbindCustomDomain(config.bucketName, existingWwwDnsInstance.domain, existingWwwDnsInstance.dnsRecordId, existingWwwDnsInstance.txtRecordId);
326
+ }
327
+ const refreshedInfo = await client.oss.getBucket(config.bucketName);
328
+ if (refreshedInfo) {
329
+ instances[0] = buildOssInstanceFromProvider(refreshedInfo, sid);
330
+ }
276
331
  }
277
- else if (existingDnsInstance) {
278
- await client.oss.unbindCustomDomain(config.bucketName, existingDnsInstance.domain, existingDnsInstance.dnsRecordId, existingDnsInstance.txtRecordId);
332
+ else if (existingDnsInstances) {
333
+ for (const instance of existingDnsInstances) {
334
+ await client.oss.unbindCustomDomain(config.bucketName, instance.domain, instance.dnsRecordId, instance.txtRecordId);
335
+ }
279
336
  }
280
337
  const resourceState = {
281
338
  mode: 'managed',
@@ -295,9 +352,11 @@ exports.updateBucketResource = updateBucketResource;
295
352
  const deleteBucketResource = async (context, bucketName, logicalId, state) => {
296
353
  const client = (0, aliyunClient_1.createAliyunClient)(context);
297
354
  const existingState = state.resources[logicalId];
298
- const dnsInstance = existingState?.instances?.find((i) => i.type === types_1.ResourceTypeEnum.ALIYUN_OSS_DNS_CNAME);
299
- if (dnsInstance) {
300
- await client.oss.unbindCustomDomain(bucketName, dnsInstance.domain, dnsInstance.dnsRecordId, dnsInstance.txtRecordId);
355
+ const dnsInstances = existingState?.instances?.filter((i) => i.type === types_1.ResourceTypeEnum.ALIYUN_OSS_DNS_CNAME);
356
+ if (dnsInstances) {
357
+ for (const dnsInstance of dnsInstances) {
358
+ await client.oss.unbindCustomDomain(bucketName, dnsInstance.domain, dnsInstance.dnsRecordId, dnsInstance.txtRecordId);
359
+ }
301
360
  }
302
361
  try {
303
362
  await client.oss.deleteBucket(bucketName);
@@ -30,6 +30,30 @@ const bucketToOssBucketConfig = (bucket) => {
30
30
  if (bucket.website?.domain) {
31
31
  config.domain = bucket.website.domain;
32
32
  }
33
+ if (bucket.website?.www_bind_apex !== undefined) {
34
+ config.wwwBindApex = bucket.website.www_bind_apex;
35
+ }
36
+ if (bucket.website?.domain_certificate_id) {
37
+ config.domainCertificateId = bucket.website.domain_certificate_id;
38
+ }
39
+ if (bucket.website?.domain_certificate_body) {
40
+ config.domainCertificateBody = bucket.website.domain_certificate_body;
41
+ }
42
+ if (bucket.website?.domain_certificate_private_key) {
43
+ config.domainCertificatePrivateKey = bucket.website.domain_certificate_private_key;
44
+ }
45
+ if (bucket.website?.domain_protocol) {
46
+ config.domainProtocol = bucket.website.domain_protocol;
47
+ }
48
+ if (bucket.versioning?.status) {
49
+ config.versioningStatus = bucket.versioning.status;
50
+ }
51
+ if (bucket.security?.sse_algorithm) {
52
+ config.sseAlgorithm = bucket.security.sse_algorithm;
53
+ }
54
+ if (bucket.security?.sse_kms_master_key_id) {
55
+ config.sseKmsMasterKeyId = bucket.security.sse_kms_master_key_id;
56
+ }
33
57
  return config;
34
58
  };
35
59
  exports.bucketToOssBucketConfig = bucketToOssBucketConfig;
@@ -45,6 +69,14 @@ const extractOssBucketDefinition = (config) => {
45
69
  : {},
46
70
  storageClass: config.storageClass ?? null,
47
71
  domain: config.domain ?? null,
72
+ wwwBindApex: config.wwwBindApex ?? false,
73
+ domainCertificateId: config.domainCertificateId ?? null,
74
+ domainCertificateBody: config.domainCertificateBody ?? null,
75
+ domainCertificatePrivateKey: config.domainCertificatePrivateKey ? '(managed)' : null,
76
+ domainProtocol: config.domainProtocol ?? null,
77
+ versioningStatus: config.versioningStatus ?? null,
78
+ sseAlgorithm: config.sseAlgorithm ?? null,
79
+ sseKmsMasterKeyId: config.sseKmsMasterKeyId ?? null,
48
80
  };
49
81
  };
50
82
  exports.extractOssBucketDefinition = extractOssBucketDefinition;
@@ -43,7 +43,12 @@ const tableToTableStoreConfig = (table) => {
43
43
  instanceName: table.collection,
44
44
  tableName: table.name,
45
45
  clusterType,
46
+ description: table.desc,
46
47
  primaryKey,
48
+ attributes: table.attributes.map((attr) => ({
49
+ name: attr.name,
50
+ type: attr.type,
51
+ })),
47
52
  network: table.network,
48
53
  };
49
54
  // Add reserved throughput if specified
@@ -55,6 +60,12 @@ const tableToTableStoreConfig = (table) => {
55
60
  },
56
61
  };
57
62
  }
63
+ if (table.throughput?.onDemand) {
64
+ config.onDemandThroughput = {
65
+ read: table.throughput.onDemand.read,
66
+ write: table.throughput.onDemand.write,
67
+ };
68
+ }
58
69
  // Default table options
59
70
  config.tableOptions = {
60
71
  timeToLive: -1, // -1 means never expire
@@ -68,8 +79,11 @@ const extractTableStoreDefinition = (config) => {
68
79
  instanceName: config.instanceName,
69
80
  tableName: config.tableName,
70
81
  clusterType: config.clusterType,
82
+ description: config.description ?? null,
71
83
  primaryKey: config.primaryKey,
84
+ attributes: config.attributes,
72
85
  reservedThroughput: config.reservedThroughput ?? null,
86
+ onDemandThroughput: config.onDemandThroughput ?? null,
73
87
  tableOptions: config.tableOptions ?? null,
74
88
  network: config.network ?? null,
75
89
  };