@geek-fun/serverlessinsight 0.3.1 → 0.3.2

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 (35) hide show
  1. package/dist/package.json +40 -38
  2. package/dist/src/commands/deploy.js +1 -1
  3. package/dist/src/commands/destroy.js +1 -1
  4. package/dist/src/commands/index.js +22 -7
  5. package/dist/src/commands/local.js +35 -0
  6. package/dist/src/commands/template.js +2 -2
  7. package/dist/src/commands/validate.js +2 -2
  8. package/dist/src/common/constants.js +4 -2
  9. package/dist/src/common/context.js +12 -6
  10. package/dist/src/common/iacHelper.js +1 -1
  11. package/dist/src/common/rosAssets.js +1 -0
  12. package/dist/src/common/rosClient.js +1 -1
  13. package/dist/src/parser/index.js +2 -0
  14. package/dist/src/parser/tableParser.js +41 -0
  15. package/dist/src/stack/localStack/event.js +38 -0
  16. package/dist/src/stack/localStack/index.d.ts +2 -0
  17. package/dist/src/stack/localStack/index.js +23 -0
  18. package/dist/src/stack/rosStack/bootstrap.js +153 -5
  19. package/dist/src/stack/rosStack/bucket.js +1 -0
  20. package/dist/src/stack/rosStack/database.js +1 -2
  21. package/dist/src/stack/rosStack/function.js +1 -2
  22. package/dist/src/stack/rosStack/index.js +3 -0
  23. package/dist/src/stack/rosStack/table.js +95 -0
  24. package/dist/src/types/domains/table.js +16 -0
  25. package/dist/src/types/index.d.ts +5 -0
  26. package/dist/src/validator/iacSchema.js +2 -0
  27. package/dist/src/validator/rootSchema.js +3 -0
  28. package/dist/src/validator/tableschema.js +72 -0
  29. package/dist/tsconfig.tsbuildinfo +1 -1
  30. package/layers/si-bootstrap-sdk/Dockerfile-aliyuncli +12 -0
  31. package/layers/si-bootstrap-sdk/README.md +1 -0
  32. package/layers/si-bootstrap-sdk/package-lock.json +875 -0
  33. package/layers/si-bootstrap-sdk/package.json +33 -0
  34. package/package.json +40 -38
  35. package/samples/aliyun-poc-table.yml +48 -0
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geek-fun/serverlessinsight",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Full life cycle cross providers serverless application management for your fast-growing business.",
5
5
  "homepage": "https://serverlessinsight.geekfun.club",
6
6
  "main": "dist/src/index.js",
@@ -49,52 +49,54 @@
49
49
  "function"
50
50
  ],
51
51
  "dependencies": {
52
- "@alicloud/ims20190815": "^2.2.0",
53
- "@alicloud/openapi-client": "^0.4.14",
54
- "@alicloud/ros-cdk-apigateway": "^1.8.0",
55
- "@alicloud/ros-cdk-core": "^1.8.0",
56
- "@alicloud/ros-cdk-dns": "^1.8.0",
57
- "@alicloud/ros-cdk-ecs": "^1.8.0",
58
- "@alicloud/ros-cdk-elasticsearchserverless": "^1.8.0",
59
- "@alicloud/ros-cdk-fc3": "^1.8.0",
60
- "@alicloud/ros-cdk-nas": "^1.8.0",
61
- "@alicloud/ros-cdk-oss": "^1.8.0",
62
- "@alicloud/ros-cdk-ossdeployment": "^1.8.0",
63
- "@alicloud/ros-cdk-ram": "^1.8.0",
64
- "@alicloud/ros-cdk-rds": "^1.8.0",
65
- "@alicloud/ros-cdk-sls": "^1.8.0",
66
- "@alicloud/ros-cdk-vpc": "^1.8.0",
67
- "@alicloud/ros20190910": "^3.5.6",
52
+ "@alicloud/ims20190815": "^2.3.2",
53
+ "@alicloud/openapi-client": "^0.4.15",
54
+ "@alicloud/ros-cdk-apigateway": "^1.10.0",
55
+ "@alicloud/ros-cdk-core": "^1.10.0",
56
+ "@alicloud/ros-cdk-dns": "^1.10.0",
57
+ "@alicloud/ros-cdk-ecs": "^1.10.0",
58
+ "@alicloud/ros-cdk-elasticsearchserverless": "^1.10.0",
59
+ "@alicloud/ros-cdk-fc3": "^1.10.0",
60
+ "@alicloud/ros-cdk-nas": "^1.10.0",
61
+ "@alicloud/ros-cdk-oss": "^1.10.0",
62
+ "@alicloud/ros-cdk-ossdeployment": "^1.10.0",
63
+ "@alicloud/ros-cdk-ots": "^1.10.0",
64
+ "@alicloud/ros-cdk-ram": "^1.10.0",
65
+ "@alicloud/ros-cdk-rds": "^1.10.0",
66
+ "@alicloud/ros-cdk-ros": "^1.10.0",
67
+ "@alicloud/ros-cdk-sls": "^1.10.0",
68
+ "@alicloud/ros-cdk-vpc": "^1.10.0",
69
+ "@alicloud/ros20190910": "^3.6.0",
68
70
  "ajv": "^8.17.1",
69
- "ali-oss": "^6.22.0",
70
- "chalk": "^5.4.1",
71
- "commander": "^13.1.0",
71
+ "ali-oss": "^6.23.0",
72
+ "chalk": "^5.6.2",
73
+ "commander": "^14.0.1",
72
74
  "i": "^0.3.7",
73
- "i18n": "^0.15.1",
75
+ "i18n": "^0.15.2",
74
76
  "jszip": "^3.10.1",
75
77
  "lodash": "^4.17.21",
76
- "npm": "^11.2.0",
77
- "pino": "^9.6.0",
78
- "pino-pretty": "^13.0.0",
79
- "yaml": "^2.7.1"
78
+ "npm": "^11.5.2",
79
+ "pino": "^9.9.4",
80
+ "pino-pretty": "^13.1.1",
81
+ "yaml": "^2.8.1"
80
82
  },
81
83
  "devDependencies": {
82
84
  "@types/ali-oss": "^6.16.11",
83
85
  "@types/i18n": "^0.13.12",
84
- "@types/jest": "^29.5.14",
85
- "@types/lodash": "^4.17.16",
86
- "@types/node": "^22.14.0",
87
- "@typescript-eslint/eslint-plugin": "^8.29.0",
88
- "@typescript-eslint/parser": "^8.29.0",
89
- "eslint": "^9.24.0",
90
- "eslint-config-prettier": "^10.1.1",
91
- "eslint-plugin-prettier": "^5.2.6",
92
- "globals": "^16.0.0",
86
+ "@types/jest": "^30.0.0",
87
+ "@types/lodash": "^4.17.20",
88
+ "@types/node": "^24.3.0",
89
+ "@typescript-eslint/eslint-plugin": "^8.39.1",
90
+ "@typescript-eslint/parser": "^8.39.1",
91
+ "eslint": "^9.33.0",
92
+ "eslint-config-prettier": "^10.1.8",
93
+ "eslint-plugin-prettier": "^5.5.4",
94
+ "globals": "^16.3.0",
93
95
  "husky": "^9.1.7",
94
- "jest": "^29.7.0",
95
- "prettier": "^3.5.3",
96
- "ts-jest": "^29.3.1",
96
+ "jest": "^30.0.5",
97
+ "prettier": "^3.6.2",
98
+ "ts-jest": "^29.4.1",
97
99
  "ts-node": "^10.9.2",
98
- "typescript": "^5.8.3"
100
+ "typescript": "^5.9.2"
99
101
  }
100
102
  }
@@ -8,7 +8,7 @@ const deploy = async (stackName, options) => {
8
8
  common_1.logger.info('Validating yaml...');
9
9
  const iac = (0, parser_1.parseYaml)((0, common_1.getIacLocation)(options.location));
10
10
  common_1.logger.info('Yaml is valid! 🎉');
11
- (0, common_1.setContext)({ ...options, stackName, iacProvider: iac.provider });
11
+ await (0, common_1.setContext)({ ...options, stackName, iacProvider: iac.provider }, true);
12
12
  common_1.logger.info('Deploying stack...');
13
13
  await (0, stack_1.deployStack)(stackName, iac);
14
14
  common_1.logger.info('Stack deployed! 🎉');
@@ -5,7 +5,7 @@ const common_1 = require("../common");
5
5
  const parser_1 = require("../parser");
6
6
  const destroyStack = async (stackName, options) => {
7
7
  const iac = (0, parser_1.parseYaml)((0, common_1.getIacLocation)(options.location));
8
- (0, common_1.setContext)({ stackName, ...options, iacProvider: iac.provider });
8
+ await (0, common_1.setContext)({ stackName, ...options, iacProvider: iac.provider }, true);
9
9
  const context = (0, common_1.getContext)();
10
10
  common_1.logger.info(`Destroying stack: ${stackName}, provider: ${context.provider}, region: ${context.region}...`);
11
11
  await (0, common_1.rosStackDelete)(context);
@@ -7,16 +7,16 @@ const validate_1 = require("./validate");
7
7
  const deploy_1 = require("./deploy");
8
8
  const template_1 = require("./template");
9
9
  const destroy_1 = require("./destroy");
10
- const common_2 = require("../common");
10
+ const local_1 = require("./local");
11
11
  const program = new commander_1.Command();
12
12
  program.name('si').description('CLI for ServerlessInsight').version((0, common_1.getVersion)());
13
13
  program
14
14
  .command('show')
15
15
  .description('show string')
16
16
  .action(async (options) => {
17
- (0, common_1.setContext)({ ...options });
17
+ await (0, common_1.setContext)({ ...options });
18
18
  const context = (0, common_1.getContext)();
19
- const result = await (0, common_2.getIamInfo)(context);
19
+ const result = await (0, common_1.getIamInfo)(context);
20
20
  console.log('result:', JSON.stringify(result));
21
21
  });
22
22
  program
@@ -24,9 +24,9 @@ program
24
24
  .description('validate serverless Iac yaml')
25
25
  .option('-f, --file <path>', 'specify the yaml file')
26
26
  .option('-s, --stage <stage>', 'specify the stage')
27
- .action((stackName, { file, stage }) => {
27
+ .action(async (stackName, { file, stage }) => {
28
28
  common_1.logger.debug('log command info');
29
- (0, validate_1.validate)(stackName, { stage, location: file });
29
+ await (0, validate_1.validate)(stackName, { stage, location: file });
30
30
  });
31
31
  program
32
32
  .command('deploy <stackName>')
@@ -61,8 +61,8 @@ program
61
61
  .option('-f, --file <path>', 'specify the yaml file')
62
62
  .option('-s, --stage <stage>', 'specify the stage')
63
63
  .option('-t, --format <type>', 'output content type (JSON or YAML)', 'JSON')
64
- .action((stackName, { format, file, stage }) => {
65
- (0, template_1.template)(stackName, { format, location: file, stage });
64
+ .action(async (stackName, { format, file, stage }) => {
65
+ await (0, template_1.template)(stackName, { format, location: file, stage });
66
66
  });
67
67
  program
68
68
  .command('destroy <stackName>')
@@ -83,4 +83,19 @@ program
83
83
  securityToken,
84
84
  });
85
85
  });
86
+ program
87
+ .command('local <stackName>')
88
+ .description('run Serverless application locally for debugging')
89
+ .option('-s, --stage <stage>', 'specify the stage', 'default')
90
+ .option('-p, --port <port>', 'specify the port', '3000')
91
+ .option('-d, --debug', 'enable debug mode')
92
+ .option('-w, --watch', 'enable file watch', true)
93
+ .action(async (stackName, { stage, port, debug, watch }) => {
94
+ await (0, local_1.runLocal)(stackName, {
95
+ stage,
96
+ port: Number(port) || 3000,
97
+ debug: !!debug,
98
+ watch: typeof watch === 'boolean' ? watch : true,
99
+ });
100
+ });
86
101
  program.parse();
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runLocal = void 0;
4
+ const common_1 = require("../common");
5
+ const localStack_1 = require("../stack/localStack");
6
+ const runLocal = async (stackName, opts) => {
7
+ const { stage, port, debug, watch } = opts;
8
+ await (0, common_1.setContext)({ stage });
9
+ common_1.logger.info(`run-local starting: stack=${stackName} stage=${stage} port=${port} debug=${debug} watch=${watch}`);
10
+ await (0, localStack_1.startLocalStack)();
11
+ // if (watch) {
12
+ // const cwd = process.cwd();
13
+ // try {
14
+ // fs.watch(cwd, { recursive: true }, (eventType, filename) => {
15
+ // if (!filename) return;
16
+ // const filePath = path.join(cwd, filename);
17
+ // logger.info(`file change detected: ${eventType} ${filePath}`);
18
+ // });
19
+ // logger.info(`watching files under ${process.cwd()}`);
20
+ // } catch (err) {
21
+ // logger.warn(`file watch not available: ${String(err)}`);
22
+ // }
23
+ // }
24
+ //
25
+ // const shutdown = () => {
26
+ // logger.info('shutting down run-local server');
27
+ // server.close(() => process.exit(0));
28
+ // };
29
+ // process.on('SIGINT', shutdown);
30
+ // process.on('SIGTERM', shutdown);
31
+ //
32
+ // // return server for tests if needed
33
+ // return { server, port, stage, debug, watch };
34
+ };
35
+ exports.runLocal = runLocal;
@@ -9,9 +9,9 @@ const yaml_1 = __importDefault(require("yaml"));
9
9
  const deploy_1 = require("../stack/deploy");
10
10
  const common_1 = require("../common");
11
11
  const parser_1 = require("../parser");
12
- const template = (stackName, options) => {
12
+ const template = async (stackName, options) => {
13
13
  const iac = (0, parser_1.parseYaml)((0, common_1.getIacLocation)(options.location));
14
- (0, common_1.setContext)({ ...options, stackName, provider: iac.provider.name });
14
+ await (0, common_1.setContext)({ ...options, stackName, provider: iac.provider.name }, true);
15
15
  const { template } = (0, deploy_1.generateStackTemplate)(stackName, iac);
16
16
  if (typeof template === 'string') {
17
17
  common_1.logger.info(`\n${template}`);
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.validate = void 0;
4
4
  const common_1 = require("../common");
5
5
  const parser_1 = require("../parser");
6
- const validate = (stackName, options) => {
7
- (0, common_1.setContext)({ stackName, ...options });
6
+ const validate = async (stackName, options) => {
7
+ await (0, common_1.setContext)({ stackName, ...options });
8
8
  const context = (0, common_1.getContext)();
9
9
  (0, parser_1.parseYaml)(context.iacLocation);
10
10
  common_1.logger.info('Yaml is valid! 🎉');
@@ -1,5 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OSS_DEPLOYMENT_TIMEOUT = exports.CODE_ZIP_SIZE_LIMIT = void 0;
4
- exports.CODE_ZIP_SIZE_LIMIT = 15 * 1000 * 1000;
3
+ exports.SI_BOOTSTRAP_BUCKET_PREFIX = exports.SI_BOOTSTRAP_FC_PREFIX = exports.OSS_DEPLOYMENT_TIMEOUT = exports.CODE_ZIP_SIZE_LIMIT = void 0;
4
+ exports.CODE_ZIP_SIZE_LIMIT = 300 * 1000; // 300 KB ROS TemplateBody size limit 512 KB
5
5
  exports.OSS_DEPLOYMENT_TIMEOUT = 3000; // in seconds
6
+ exports.SI_BOOTSTRAP_FC_PREFIX = 'si-bootstrap-api';
7
+ exports.SI_BOOTSTRAP_BUCKET_PREFIX = 'si-bootstrap-artifacts';
@@ -7,6 +7,7 @@ exports.getContext = exports.setContext = exports.getIacLocation = void 0;
7
7
  const node_path_1 = __importDefault(require("node:path"));
8
8
  const providerEnum_1 = require("./providerEnum");
9
9
  const node_async_hooks_1 = require("node:async_hooks");
10
+ const imsClient_1 = require("./imsClient");
10
11
  const asyncLocalStorage = new node_async_hooks_1.AsyncLocalStorage();
11
12
  const getIacLocation = (location) => {
12
13
  const projectRoot = node_path_1.default.resolve(process.cwd());
@@ -18,16 +19,17 @@ const getIacLocation = (location) => {
18
19
  node_path_1.default.resolve(projectRoot, 'serverless-insight.yml');
19
20
  };
20
21
  exports.getIacLocation = getIacLocation;
21
- const setContext = (config) => {
22
+ const setContext = async (config, reaValToken = false) => {
23
+ const region = config.region ??
24
+ config.iacProvider?.region ??
25
+ process.env.ROS_REGION_ID ??
26
+ process.env.ALIYUN_REGION ??
27
+ 'cn-hangzhou';
22
28
  const context = {
23
29
  stage: config.stage ?? 'default',
24
30
  stackName: config.stackName ?? '',
25
31
  provider: (config.provider ?? config.iacProvider?.name ?? providerEnum_1.ProviderEnum.ALIYUN),
26
- region: config.region ??
27
- config.iacProvider?.region ??
28
- process.env.ROS_REGION_ID ??
29
- process.env.ALIYUN_REGION ??
30
- 'cn-hangzhou',
32
+ region,
31
33
  accessKeyId: config.accessKeyId ?? process.env.ALIYUN_ACCESS_KEY_ID,
32
34
  accessKeySecret: config.accessKeySecret ?? process.env.ALIYUN_ACCESS_KEY_SECRET,
33
35
  securityToken: config.securityToken ?? process.env.ALIYUN_SECURITY_TOKEN,
@@ -38,6 +40,10 @@ const setContext = (config) => {
38
40
  [stage]: Object.entries(parameters).map(([key, value]) => ({ key, value })),
39
41
  }), {}),
40
42
  };
43
+ if (reaValToken) {
44
+ const iamInfo = await (0, imsClient_1.getIamInfo)(context);
45
+ context.accountId = iamInfo?.accountId;
46
+ }
41
47
  asyncLocalStorage.enterWith(context);
42
48
  };
43
49
  exports.setContext = setContext;
@@ -127,7 +127,7 @@ const formatRosId = (id) => {
127
127
  // Convert to lowercase
128
128
  result = result.toLowerCase();
129
129
  // Replace special characters with underscores
130
- result = result.replace(/[/#,-]/g, '_');
130
+ result = result.replace(/[/*,/#,-]/g, '_');
131
131
  // Remove any number of underscores to single one
132
132
  result = result.replace(/_+/g, '_');
133
133
  // Remove leading underscores
@@ -139,6 +139,7 @@ const publishAssets = async (assets) => {
139
139
  accessKeyId: context.accessKeyId,
140
140
  accessKeySecret: context.accessKeySecret,
141
141
  bucket: bucketName,
142
+ timeout: 600000, // 10 minutes
142
143
  });
143
144
  await ensureBucketExits(bucketName, client);
144
145
  const headers = {
@@ -37,9 +37,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.rosStackDelete = exports.rosStackDeploy = void 0;
40
- const tea_util_1 = __importDefault(require("@alicloud/tea-util"));
41
40
  const ros20190910_1 = __importStar(require("@alicloud/ros20190910"));
42
41
  const openapi_client_1 = require("@alicloud/openapi-client");
42
+ const tea_util_1 = __importDefault(require("@alicloud/tea-util"));
43
43
  const logger_1 = require("./logger");
44
44
  const lang_1 = require("../lang");
45
45
  const context_1 = require("./context");
@@ -9,6 +9,7 @@ const tagParser_1 = require("./tagParser");
9
9
  const yaml_1 = require("yaml");
10
10
  const validator_1 = require("../validator");
11
11
  const bucketParser_1 = require("./bucketParser");
12
+ const tableParser_1 = require("./tableParser");
12
13
  const validateExistence = (path) => {
13
14
  if (!(0, node_fs_1.existsSync)(path)) {
14
15
  throw new Error(`File does not exist at path: ${path}`);
@@ -24,6 +25,7 @@ const transformYaml = (iacJson) => {
24
25
  functions: (0, functionParser_1.parseFunction)(iacJson.functions),
25
26
  events: (0, eventParser_1.parseEvent)(iacJson.events),
26
27
  databases: (0, databaseParser_1.parseDatabase)(iacJson.databases),
28
+ tables: (0, tableParser_1.parseTable)(iacJson.tables),
27
29
  tags: (0, tagParser_1.parseTag)(iacJson.tags),
28
30
  buckets: (0, bucketParser_1.parseBucket)(iacJson.buckets),
29
31
  };
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseTable = parseTable;
4
+ const lodash_1 = require("lodash");
5
+ function parseTable(tablesRaw) {
6
+ if ((0, lodash_1.isEmpty)(tablesRaw)) {
7
+ return undefined;
8
+ }
9
+ return Object.entries(tablesRaw)?.map(([key, table]) => {
10
+ const throughput = (0, lodash_1.omitBy)({
11
+ reserved: (0, lodash_1.omitBy)({
12
+ read: table.throughput?.reserved?.read,
13
+ write: table.throughput?.reserved?.write,
14
+ }, lodash_1.isNil),
15
+ onDemand: (0, lodash_1.omitBy)({
16
+ read: table.throughput?.on_demand?.read,
17
+ write: table.throughput?.on_demand?.write,
18
+ }, lodash_1.isNil),
19
+ }, lodash_1.isEmpty);
20
+ return {
21
+ key,
22
+ collection: table.collection,
23
+ name: table.name,
24
+ type: table.type,
25
+ desc: table.desc,
26
+ network: {
27
+ type: table.network?.type ?? 'PRIVATE',
28
+ ingressRules: table.network?.ingress_rules ?? [],
29
+ },
30
+ throughput: !(0, lodash_1.isEmpty)(throughput) ? throughput : undefined,
31
+ keySchema: table.key_schema?.map((keySchema) => ({
32
+ name: keySchema.name,
33
+ type: keySchema.type,
34
+ })) ?? [],
35
+ attributes: table.attributes?.map((attribute) => ({
36
+ name: attribute.name,
37
+ type: attribute.type,
38
+ })) ?? [],
39
+ };
40
+ });
41
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.startEvents = void 0;
7
+ const node_http_1 = __importDefault(require("node:http"));
8
+ const common_1 = require("../../common");
9
+ const types_1 = require("../../types");
10
+ const lodash_1 = require("lodash");
11
+ const startApiGatewayServer = (event) => {
12
+ const server = node_http_1.default.createServer((req, res) => {
13
+ const matchedTrigger = event.triggers.find((trigger) => trigger.method === req.method && trigger.path === req.url);
14
+ if (!matchedTrigger) {
15
+ res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
16
+ res.end('Not Found\n');
17
+ common_1.logger.warn(`API Gateway Event - ${req.method} ${req.url} -> Not Found`);
18
+ return;
19
+ }
20
+ res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
21
+ res.end(`Invoked backend: ${matchedTrigger.backend}\n`);
22
+ common_1.logger.info(`API Gateway Event - ${req.method} ${req.url} -> ${matchedTrigger.backend}`);
23
+ });
24
+ const port = 3000 + Math.floor(Math.random() * 1000);
25
+ server.listen(port, () => {
26
+ common_1.logger.info(`API Gateway "${event.name}" listening on http://localhost:${port}`);
27
+ });
28
+ };
29
+ const startEvents = (events) => {
30
+ const apiGateways = events?.filter((event) => event.type === types_1.EventTypes.API_GATEWAY);
31
+ if ((0, lodash_1.isEmpty)(apiGateways)) {
32
+ return;
33
+ }
34
+ apiGateways.forEach((gateway) => {
35
+ startApiGatewayServer(gateway);
36
+ });
37
+ };
38
+ exports.startEvents = startEvents;
@@ -0,0 +1,2 @@
1
+ export * from './event';
2
+ export declare const startLocalStack: () => Promise<void>;
@@ -0,0 +1,23 @@
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.startLocalStack = void 0;
18
+ __exportStar(require("./event"), exports);
19
+ const startLocalStack = async () => {
20
+ // Placeholder for starting local stack logic
21
+ console.log('Local stack started');
22
+ };
23
+ exports.startLocalStack = startLocalStack;
@@ -3,8 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.prepareBootstrapStack = void 0;
4
4
  const common_1 = require("../../common");
5
5
  const getBootstrapTemplate = async (context) => {
6
- const iamInfo = await (0, common_1.getIamInfo)(context);
7
- const stackName = `si-bootstrap-${iamInfo?.accountId}-${context.region}`;
6
+ const stackName = `si-bootstrap-${context.accountId}-${context.region}`;
8
7
  const template = {
9
8
  Description: 'ServerlessInsight Bootstrap Stack',
10
9
  Metadata: {
@@ -17,9 +16,7 @@ const getBootstrapTemplate = async (context) => {
17
16
  si_auto_artifacts_bucket: {
18
17
  Type: 'ALIYUN::OSS::Bucket',
19
18
  Properties: {
20
- BucketName: {
21
- 'Fn::Sub': 'si-bootstrap-artifacts-${ALIYUN::AccountId}-${ALIYUN::Region}',
22
- },
19
+ BucketName: `${common_1.SI_BOOTSTRAP_BUCKET_PREFIX}-${context.accountId}-${context.region}`,
23
20
  AccessControl: 'private',
24
21
  DeletionForce: false,
25
22
  EnableOssHdfsService: false,
@@ -29,6 +26,157 @@ const getBootstrapTemplate = async (context) => {
29
26
  },
30
27
  },
31
28
  },
29
+ si_auto_bootstrap_api_lambda: {
30
+ Type: 'ALIYUN::FC3::Function',
31
+ Properties: {
32
+ FunctionName: `${common_1.SI_BOOTSTRAP_FC_PREFIX}-${context.accountId}-${context.region}`,
33
+ Description: 'ServerlessInsight Bootstrap API',
34
+ Handler: 'index.handler',
35
+ Runtime: 'nodejs20',
36
+ Layers: [
37
+ `acs:fc:${context.region}:${context.accountId}:layers/si-bootstrap-sdk/versions/18`,
38
+ ],
39
+ Code: {
40
+ SourceCode: `
41
+ const { bootstrapHandler } = require('@geek-fun/si-bootstrap-sdk');
42
+
43
+ module.exports.handler = async (rawEvent, context) => {
44
+ // 处理 Buffer 类型的事件
45
+ const event = parseEvent(rawEvent);
46
+
47
+ const commonResponse = {
48
+ RequestId: event.requestId,
49
+ LogicalResourceId: event.logicalResourceId,
50
+ StackId: event.stackId
51
+ };
52
+
53
+ try {
54
+ // 处理业务逻辑
55
+ const result = await bootstrapHandler(event);
56
+
57
+ // 构建符合 ROS 要求的响应结构
58
+ const rosResponse = {
59
+ ...commonResponse,
60
+ Status: result.status,
61
+ Reason: result.reason,
62
+ PhysicalResourceId: result.physicalResourceId,
63
+ Data: result.data || {} // 业务数据
64
+ };
65
+
66
+ // 如果是删除操作,不需要返回数据
67
+ if (event.requestType === 'Delete') {
68
+ delete rosResponse.Data;
69
+ }
70
+
71
+ // 发送响应到 ROS 服务(如果提供了 ResponseURL)
72
+ if (event.responseURL) {
73
+ await sendResponse(event.responseURL, rosResponse);
74
+ }
75
+
76
+ // 返回成功响应
77
+ return {
78
+ statusCode: 200,
79
+ body: JSON.stringify({
80
+ message: 'Request processed successfully',
81
+ rosResponse
82
+ })
83
+ };
84
+ } catch (error) {
85
+ console.error('Error:', error);
86
+
87
+ // 构建错误响应
88
+ const errorResponse = {
89
+ ...commonResponse,
90
+ Status: 'FAILED',
91
+ Reason: error.message || 'Internal Server Error',
92
+ PhysicalResourceId: 'error-' + Date.now()
93
+ };
94
+
95
+ // 发送错误响应到 ROS 服务
96
+ if (event.responseURL) {
97
+ try {
98
+ await sendResponse(event.responseURL, errorResponse);
99
+ } catch (err) {
100
+ console.error('Failed to send error response:', err);
101
+ }
102
+ }
103
+
104
+ // 返回错误响应
105
+ return {
106
+ statusCode: 500,
107
+ body: JSON.stringify({
108
+ error: 'Internal Server Error',
109
+ details: error.message,
110
+ rosErrorResponse: errorResponse
111
+ })
112
+ };
113
+ }
114
+ };
115
+
116
+ // 使用原生 fetch API 发送响应
117
+ async function sendResponse(responseUrl, responseBody) {
118
+
119
+ try {
120
+ const body = JSON.stringify(responseBody);
121
+
122
+ const response = await fetch(responseUrl, {
123
+ method: 'POST',
124
+ headers: {
125
+ 'Content-Type': 'application/json',
126
+ 'Content-Length': Buffer.byteLength(body).toString(),
127
+ 'Date': new Date().toUTCString()
128
+ },
129
+ body: body
130
+ });
131
+
132
+ if (!response.ok) {
133
+ const errorText = await response.text();
134
+ throw new Error(\`Failed to send response. Status: \${response.status}, Body: \${errorText}\`);
135
+ }
136
+
137
+ console.log('Response sent successfully');
138
+ } catch (error) {
139
+ console.error('Error sending response:', error);
140
+ throw error;
141
+ }
142
+ }
143
+
144
+
145
+ const parseEvent = (rawEvent) => {
146
+ // 处理 Buffer 类型的事件
147
+ let event;
148
+ if (Buffer.isBuffer(rawEvent)) {
149
+ event = JSON.parse(rawEvent.toString('utf8'));
150
+ } else if (typeof rawEvent === 'string') {
151
+ event = JSON.parse(rawEvent);
152
+ } else {
153
+ event = rawEvent;
154
+ }
155
+
156
+ const { credentials, ...resourceProperties } = event.ResourceProperties
157
+ return {
158
+ stackId: event.StackId,
159
+ responseURL: event.ResponseURL,
160
+ resourceOwnerId: event.ResourceOwnerId,
161
+ callerId: event.CallerId,
162
+ resourceProperties,
163
+ eventType: event.ResourceType,
164
+ requestType: event.RequestType?.toUpperCase(),
165
+ resourceType: resourceProperties.resource,
166
+ regionId: event.RegionId,
167
+ stackName: event.StackName,
168
+ requestId: event.RequestId,
169
+ intranetResponseURL: event.IntranetResponseURL,
170
+ logicalResourceId: event.LogicalResourceId,
171
+ physicalResourceId: event.PhysicalResourceId,
172
+ credentials
173
+ };
174
+ };`,
175
+ },
176
+ MemorySize: 512,
177
+ Timeout: 900, // 15 minutes
178
+ },
179
+ },
32
180
  },
33
181
  };
34
182
  return { stackName, template };
@@ -81,6 +81,7 @@ const resolveBuckets = (scope, buckets, context) => {
81
81
  const ossBucket = new oss.Bucket(scope, bucket.key, {
82
82
  bucketName: (0, common_1.calcRefs)(bucket.name, context),
83
83
  accessControl: aclMap.get((0, common_1.calcRefs)(bucket.security?.acl, context) ?? ''),
84
+ blockPublicAccess: (0, common_1.calcRefs)(bucket.security?.acl, context) === types_1.BucketAccessEnum.PRIVATE,
84
85
  websiteConfigurationV2: bucket.website
85
86
  ? {
86
87
  indexDocument: {
@@ -223,8 +223,7 @@ const resolveDatabases = (scope, databases, context) => {
223
223
  ],
224
224
  },
225
225
  quotaInfo: {
226
- cu: db.cu.min,
227
- storage: db.storage.min,
226
+ minCu: db.cu.min,
228
227
  appType: category,
229
228
  },
230
229
  // network: [