@geek-fun/serverlessinsight 0.3.4 → 0.4.1
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/README.md +209 -21
- package/README.zh-CN.md +232 -0
- package/dist/package.json +33 -33
- package/dist/src/commands/index.js +50 -12
- package/dist/src/commands/local.js +6 -3
- package/dist/src/commands/template.js +3 -1
- package/dist/src/common/constants.js +3 -1
- package/dist/src/common/context.js +56 -30
- package/dist/src/common/credentials.js +15 -0
- package/dist/src/common/iacHelper.js +39 -4
- package/dist/src/common/index.d.ts +2 -1
- package/dist/src/common/index.js +2 -1
- package/dist/src/common/logger.js +6 -0
- package/dist/src/common/requestHelper.js +16 -0
- package/dist/src/common/rosClient.js +3 -0
- package/dist/src/parser/eventParser.js +1 -1
- package/dist/src/parser/index.d.ts +2 -1
- package/dist/src/parser/index.js +32 -1
- package/dist/src/stack/localStack/aliyunFc.js +145 -0
- package/dist/src/stack/localStack/bucket.js +226 -0
- package/dist/src/stack/localStack/event.js +133 -26
- package/dist/src/stack/localStack/function.js +120 -0
- package/dist/src/stack/localStack/functionRunner.js +270 -0
- package/dist/src/stack/localStack/index.d.ts +4 -1
- package/dist/src/stack/localStack/index.js +14 -4
- package/dist/src/stack/localStack/localServer.js +111 -0
- package/dist/src/stack/localStack/utils.js +36 -0
- package/dist/src/stack/rosStack/bootstrap.js +1 -1
- package/dist/src/types/localStack/index.d.ts +81 -0
- package/dist/src/types/localStack/index.js +10 -0
- package/dist/src/validator/iacSchema.js +17 -2
- package/dist/src/validator/rootSchema.js +46 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/layers/si-bootstrap-sdk/README.md +63 -0
- package/layers/si-bootstrap-sdk/package-lock.json +39 -33
- package/layers/si-bootstrap-sdk/package.json +5 -5
- package/layers/si-bootstrap-sdk/support/operation-collection/README.md +47 -0
- package/layers/si-bootstrap-sdk/support/operation-collection/package-lock.json +298 -0
- package/layers/si-bootstrap-sdk/support/operation-collection/package.json +18 -0
- package/layers/si-bootstrap-sdk/support/operation-collection/publish.js +257 -0
- package/package.json +33 -33
- package/samples/aliyun-poc-es.yml +16 -12
- package/dist/src/common/domainHelper.js +0 -10
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/* eslint-disable @typescript-eslint/no-require-imports */
|
|
5
|
+
|
|
6
|
+
const FCOpen20210406 = require('@alicloud/fc-open20210406').default;
|
|
7
|
+
const OpenApi = require('@alicloud/openapi-client');
|
|
8
|
+
const Util = require('@alicloud/tea-util');
|
|
9
|
+
const Credential = require('@alicloud/credentials').default;
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
|
|
13
|
+
// Parse command line arguments
|
|
14
|
+
const args = process.argv.slice(2);
|
|
15
|
+
const options = {};
|
|
16
|
+
|
|
17
|
+
for (let i = 0; i < args.length; i++) {
|
|
18
|
+
const arg = args[i];
|
|
19
|
+
if (arg.startsWith('--')) {
|
|
20
|
+
const key = arg.slice(2);
|
|
21
|
+
const value = args[i + 1];
|
|
22
|
+
options[key] = value;
|
|
23
|
+
i++;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Configuration
|
|
28
|
+
const config = {
|
|
29
|
+
artifact: options.artifact || process.env.ARTIFACT_PATH,
|
|
30
|
+
layerName: options['layer-name'] || process.env.LAYER_NAME || 'si-bootstrap-sdk',
|
|
31
|
+
regions: (
|
|
32
|
+
options.regions ||
|
|
33
|
+
process.env.ALIYUN_REGIONS ||
|
|
34
|
+
'cn-beijing,cn-hangzhou,cn-chengdu,ap-southeast-1'
|
|
35
|
+
)
|
|
36
|
+
.split(',')
|
|
37
|
+
.map((r) => r.trim()),
|
|
38
|
+
runtimes: (
|
|
39
|
+
options.runtimes ||
|
|
40
|
+
process.env.ALIYUN_COMPATIBLE_RUNTIMES ||
|
|
41
|
+
'nodejs20,nodejs18,nodejs16'
|
|
42
|
+
)
|
|
43
|
+
.split(',')
|
|
44
|
+
.map((r) => r.trim()),
|
|
45
|
+
delay: parseInt(options.delay || process.env.API_DELAY || '2', 10) * 1000,
|
|
46
|
+
accountId: process.env.ALIYUN_ACCOUNT_ID || '1990893136649406',
|
|
47
|
+
accessKeyId: process.env.ALIYUN_ACCESS_KEY_ID || process.env.ALIBABA_CLOUD_ACCESS_KEY_ID,
|
|
48
|
+
accessKeySecret:
|
|
49
|
+
process.env.ALIYUN_ACCESS_KEY_SECRET || process.env.ALIBABA_CLOUD_ACCESS_KEY_SECRET,
|
|
50
|
+
securityToken: process.env.ALIYUN_SECURITY_TOKEN || process.env.ALIBABA_CLOUD_SECURITY_TOKEN,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// Validate
|
|
54
|
+
if (!config.artifact) {
|
|
55
|
+
console.error('Error: --artifact is required');
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const artifactPath = path.resolve(config.artifact);
|
|
60
|
+
if (!fs.existsSync(artifactPath)) {
|
|
61
|
+
console.error(`Error: Artifact not found: ${artifactPath}`);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Initialize credentials once and reuse for all clients
|
|
66
|
+
const credential = new Credential({
|
|
67
|
+
type: 'access_key',
|
|
68
|
+
accessKeyId: config.accessKeyId,
|
|
69
|
+
accessKeySecret: config.accessKeySecret,
|
|
70
|
+
securityToken: config.securityToken,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Helper to create FC client for a region
|
|
74
|
+
const createFCClient = (region) => {
|
|
75
|
+
const clientConfig = new OpenApi.Config({
|
|
76
|
+
credential: credential,
|
|
77
|
+
endpoint: `${config.accountId}.${region}.fc.aliyuncs.com`,
|
|
78
|
+
regionId: region,
|
|
79
|
+
readTimeout: 60000, // 60 seconds for large layer uploads
|
|
80
|
+
connectTimeout: 60000, // 60 seconds connection timeout
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
return new FCOpen20210406(clientConfig);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// Get latest layer version for a region
|
|
87
|
+
const getLatestLayerVersion = async (client, layerName, region) => {
|
|
88
|
+
try {
|
|
89
|
+
const runtime = new Util.RuntimeOptions({});
|
|
90
|
+
let allVersions = [];
|
|
91
|
+
let startVersion = undefined;
|
|
92
|
+
|
|
93
|
+
// Paginate through all layer versions
|
|
94
|
+
do {
|
|
95
|
+
const request = startVersion ? { startVersion } : {};
|
|
96
|
+
const response = await client.listLayerVersions(layerName, request, {}, runtime);
|
|
97
|
+
|
|
98
|
+
const versions = response.body.layers || [];
|
|
99
|
+
allVersions = allVersions.concat(versions);
|
|
100
|
+
|
|
101
|
+
startVersion = response.body.nextVersion;
|
|
102
|
+
} while (startVersion);
|
|
103
|
+
|
|
104
|
+
if (allVersions.length === 0) {
|
|
105
|
+
console.log(`Region ${region}: Layer not found, treating as version 0`);
|
|
106
|
+
return 0;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Find the maximum version number across all pages
|
|
110
|
+
const maxVersion = Math.max(...allVersions.map((v) => v.version || 0));
|
|
111
|
+
return maxVersion;
|
|
112
|
+
} catch (error) {
|
|
113
|
+
if (error.code === 'LayerNotFound' || error.statusCode === 404) {
|
|
114
|
+
console.log(`Region ${region}: Layer not found, treating as version 0`);
|
|
115
|
+
return 0;
|
|
116
|
+
}
|
|
117
|
+
console.error(`Region ${region}: Failed to get layer versions:`, error.message);
|
|
118
|
+
if (error.data && error.data['Recommend']) {
|
|
119
|
+
console.error(`Recommend: ${error.data['Recommend']}`);
|
|
120
|
+
}
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// Publish a layer version
|
|
126
|
+
const publishLayerVersion = async (client, layerName, base64Content, region) => {
|
|
127
|
+
try {
|
|
128
|
+
const request = {
|
|
129
|
+
compatibleRuntime: config.runtimes,
|
|
130
|
+
code: { zipFile: base64Content },
|
|
131
|
+
license: 'Apache-2.0',
|
|
132
|
+
description: 'Bootstrap SDK for ServerlessInsight',
|
|
133
|
+
};
|
|
134
|
+
const runtime = new Util.RuntimeOptions({
|
|
135
|
+
readTimeout: 60000, // 60 seconds for large layer uploads
|
|
136
|
+
connectTimeout: 10000, // 10 seconds connection timeout
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
await client.createLayerVersion(layerName, request, {}, runtime);
|
|
140
|
+
console.log(`Region ${region}: Layer version published successfully`);
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.error(`Region ${region}: Failed to publish layer version:`, error.message);
|
|
143
|
+
if (error.data && error.data['Recommend']) {
|
|
144
|
+
console.error(`Recommend: ${error.data['Recommend']}`);
|
|
145
|
+
}
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// Delay helper
|
|
151
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
152
|
+
|
|
153
|
+
// Main publish flow
|
|
154
|
+
const publish = async () => {
|
|
155
|
+
console.log('Starting layer publication');
|
|
156
|
+
console.log(`Layer: ${config.layerName}`);
|
|
157
|
+
console.log(`Regions: ${config.regions.join(', ')}`);
|
|
158
|
+
console.log(`Runtimes: ${config.runtimes.join(', ')}`);
|
|
159
|
+
|
|
160
|
+
// Read and encode artifact
|
|
161
|
+
console.log(`Reading artifact: ${artifactPath}`);
|
|
162
|
+
const zipContent = fs.readFileSync(artifactPath);
|
|
163
|
+
const base64Content = zipContent.toString('base64');
|
|
164
|
+
console.log(
|
|
165
|
+
`Artifact encoded (${zipContent.length} bytes -> ${base64Content.length} base64 chars)`,
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
// Step 1: Get current versions for all regions
|
|
169
|
+
console.log('\nStep 1: Checking current versions across regions...');
|
|
170
|
+
const currentVersions = new Map();
|
|
171
|
+
let maxVersion = 0;
|
|
172
|
+
|
|
173
|
+
for (const region of config.regions) {
|
|
174
|
+
const client = createFCClient(region);
|
|
175
|
+
const version = await getLatestLayerVersion(client, config.layerName, region);
|
|
176
|
+
currentVersions.set(region, version);
|
|
177
|
+
console.log(`Region ${region}: version ${version}`);
|
|
178
|
+
|
|
179
|
+
if (version > maxVersion) {
|
|
180
|
+
maxVersion = version;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
console.log(`\nMaximum version across all regions: ${maxVersion}`);
|
|
185
|
+
|
|
186
|
+
// Step 2: Publish to all regions and align versions
|
|
187
|
+
console.log('\nStep 2: Publishing and aligning versions...');
|
|
188
|
+
const targetVersion = maxVersion + 1;
|
|
189
|
+
|
|
190
|
+
for (const region of config.regions) {
|
|
191
|
+
const currentVersion = currentVersions.get(region) || 0;
|
|
192
|
+
const versionsToAdd = targetVersion - currentVersion;
|
|
193
|
+
|
|
194
|
+
console.log(`\nRegion ${region}: current=${currentVersion}, target=${targetVersion}`);
|
|
195
|
+
|
|
196
|
+
if (versionsToAdd === 0) {
|
|
197
|
+
console.log(`Region ${region}: Already at target version, skipping`);
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const client = createFCClient(region);
|
|
202
|
+
|
|
203
|
+
for (let i = 1; i <= versionsToAdd; i++) {
|
|
204
|
+
console.log(
|
|
205
|
+
`Publishing version ${currentVersion + i} to ${region} (attempt ${i}/${versionsToAdd})`,
|
|
206
|
+
);
|
|
207
|
+
await publishLayerVersion(client, config.layerName, base64Content, region);
|
|
208
|
+
|
|
209
|
+
if (i < versionsToAdd) {
|
|
210
|
+
await sleep(config.delay);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Step 3: Verify all regions are aligned
|
|
216
|
+
console.log('\nStep 3: Verifying version alignment...');
|
|
217
|
+
let finalVersion = 0;
|
|
218
|
+
const mismatches = [];
|
|
219
|
+
|
|
220
|
+
for (const region of config.regions) {
|
|
221
|
+
const client = createFCClient(region);
|
|
222
|
+
const version = await getLatestLayerVersion(client, config.layerName, region);
|
|
223
|
+
console.log(`Region ${region}: final version ${version}`);
|
|
224
|
+
|
|
225
|
+
if (finalVersion === 0) {
|
|
226
|
+
finalVersion = version;
|
|
227
|
+
} else if (version !== finalVersion) {
|
|
228
|
+
mismatches.push(`${region}:${version}`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (mismatches.length > 0) {
|
|
233
|
+
console.warn(
|
|
234
|
+
`Warning: Version mismatch detected! Mismatches: ${mismatches.join(', ')}, expected: ${finalVersion}`,
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
console.log(`\nAll regions published and aligned to version: ${finalVersion}`);
|
|
239
|
+
|
|
240
|
+
// Output for GitHub Actions
|
|
241
|
+
if (process.env.GITHUB_OUTPUT) {
|
|
242
|
+
fs.appendFileSync(process.env.GITHUB_OUTPUT, `LAYER_VERSION=${finalVersion}\n`);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return finalVersion;
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
// Run
|
|
249
|
+
publish()
|
|
250
|
+
.then((version) => {
|
|
251
|
+
console.log(`\nSuccess! Layer version: ${version}`);
|
|
252
|
+
process.exit(0);
|
|
253
|
+
})
|
|
254
|
+
.catch((error) => {
|
|
255
|
+
console.error('\nPublish failed:', error.message);
|
|
256
|
+
process.exit(1);
|
|
257
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geek-fun/serverlessinsight",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
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",
|
|
@@ -51,52 +51,52 @@
|
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@alicloud/ims20190815": "^2.3.2",
|
|
53
53
|
"@alicloud/openapi-client": "^0.4.15",
|
|
54
|
-
"@alicloud/ros-cdk-apigateway": "^1.
|
|
55
|
-
"@alicloud/ros-cdk-core": "^1.
|
|
56
|
-
"@alicloud/ros-cdk-dns": "^1.
|
|
57
|
-
"@alicloud/ros-cdk-ecs": "^1.
|
|
58
|
-
"@alicloud/ros-cdk-elasticsearchserverless": "^1.
|
|
59
|
-
"@alicloud/ros-cdk-fc3": "^1.
|
|
60
|
-
"@alicloud/ros-cdk-nas": "^1.
|
|
61
|
-
"@alicloud/ros-cdk-oss": "^1.
|
|
62
|
-
"@alicloud/ros-cdk-ossdeployment": "^1.
|
|
63
|
-
"@alicloud/ros-cdk-ots": "^1.
|
|
64
|
-
"@alicloud/ros-cdk-ram": "^1.
|
|
65
|
-
"@alicloud/ros-cdk-rds": "^1.
|
|
66
|
-
"@alicloud/ros-cdk-ros": "^1.
|
|
67
|
-
"@alicloud/ros-cdk-sls": "^1.
|
|
68
|
-
"@alicloud/ros-cdk-vpc": "^1.
|
|
54
|
+
"@alicloud/ros-cdk-apigateway": "^1.11.0",
|
|
55
|
+
"@alicloud/ros-cdk-core": "^1.11.0",
|
|
56
|
+
"@alicloud/ros-cdk-dns": "^1.11.0",
|
|
57
|
+
"@alicloud/ros-cdk-ecs": "^1.11.0",
|
|
58
|
+
"@alicloud/ros-cdk-elasticsearchserverless": "^1.11.0",
|
|
59
|
+
"@alicloud/ros-cdk-fc3": "^1.11.0",
|
|
60
|
+
"@alicloud/ros-cdk-nas": "^1.11.0",
|
|
61
|
+
"@alicloud/ros-cdk-oss": "^1.11.0",
|
|
62
|
+
"@alicloud/ros-cdk-ossdeployment": "^1.11.0",
|
|
63
|
+
"@alicloud/ros-cdk-ots": "^1.11.0",
|
|
64
|
+
"@alicloud/ros-cdk-ram": "^1.11.0",
|
|
65
|
+
"@alicloud/ros-cdk-rds": "^1.11.0",
|
|
66
|
+
"@alicloud/ros-cdk-ros": "^1.11.0",
|
|
67
|
+
"@alicloud/ros-cdk-sls": "^1.11.0",
|
|
68
|
+
"@alicloud/ros-cdk-vpc": "^1.11.0",
|
|
69
69
|
"@alicloud/ros20190910": "^3.6.0",
|
|
70
70
|
"ajv": "^8.17.1",
|
|
71
71
|
"ali-oss": "^6.23.0",
|
|
72
72
|
"chalk": "^5.6.2",
|
|
73
|
-
"commander": "^14.0.
|
|
73
|
+
"commander": "^14.0.2",
|
|
74
74
|
"i": "^0.3.7",
|
|
75
|
-
"i18n": "^0.15.
|
|
75
|
+
"i18n": "^0.15.3",
|
|
76
76
|
"jszip": "^3.10.1",
|
|
77
77
|
"lodash": "^4.17.21",
|
|
78
|
-
"npm": "^11.
|
|
79
|
-
"pino": "^
|
|
80
|
-
"pino-pretty": "^13.1.
|
|
81
|
-
"yaml": "^2.8.
|
|
78
|
+
"npm": "^11.7.0",
|
|
79
|
+
"pino": "^10.1.0",
|
|
80
|
+
"pino-pretty": "^13.1.3",
|
|
81
|
+
"yaml": "^2.8.2"
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
|
-
"@types/ali-oss": "^6.16.
|
|
84
|
+
"@types/ali-oss": "^6.16.13",
|
|
85
85
|
"@types/i18n": "^0.13.12",
|
|
86
86
|
"@types/jest": "^30.0.0",
|
|
87
|
-
"@types/lodash": "^4.17.
|
|
88
|
-
"@types/node": "^
|
|
89
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
90
|
-
"@typescript-eslint/parser": "^8.
|
|
91
|
-
"eslint": "^9.
|
|
87
|
+
"@types/lodash": "^4.17.21",
|
|
88
|
+
"@types/node": "^25.0.3",
|
|
89
|
+
"@typescript-eslint/eslint-plugin": "^8.50.0",
|
|
90
|
+
"@typescript-eslint/parser": "^8.50.0",
|
|
91
|
+
"eslint": "^9.39.2",
|
|
92
92
|
"eslint-config-prettier": "^10.1.8",
|
|
93
93
|
"eslint-plugin-prettier": "^5.5.4",
|
|
94
|
-
"globals": "^16.
|
|
94
|
+
"globals": "^16.5.0",
|
|
95
95
|
"husky": "^9.1.7",
|
|
96
|
-
"jest": "^30.0
|
|
97
|
-
"prettier": "^3.
|
|
98
|
-
"ts-jest": "^29.4.
|
|
96
|
+
"jest": "^30.2.0",
|
|
97
|
+
"prettier": "^3.7.4",
|
|
98
|
+
"ts-jest": "^29.4.6",
|
|
99
99
|
"ts-node": "^10.9.2",
|
|
100
|
-
"typescript": "^5.9.
|
|
100
|
+
"typescript": "^5.9.3"
|
|
101
101
|
}
|
|
102
102
|
}
|
|
@@ -11,20 +11,24 @@ tags:
|
|
|
11
11
|
owner: geek-fun
|
|
12
12
|
|
|
13
13
|
databases:
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
14
|
+
insight_poc_es:
|
|
15
|
+
name: insight-poc-es
|
|
16
|
+
type: ELASTICSEARCH_SERVERLESS
|
|
17
|
+
version: ES_SEARCH_7.10
|
|
18
|
+
cu:
|
|
19
|
+
min: 0
|
|
20
|
+
max: 2
|
|
21
|
+
storage:
|
|
22
|
+
min: 20
|
|
23
|
+
security:
|
|
24
|
+
basic_auth:
|
|
25
|
+
master_user: admin
|
|
26
|
+
password: 'U34I6InQ8elseTgqTWT2t2oFXpoqFg'
|
|
27
|
+
insight_poc_rds:
|
|
25
28
|
name: insight-poc-rds
|
|
26
29
|
type: RDS_PGSQL_SERVERLESS
|
|
27
30
|
version: PGSQL_16
|
|
28
31
|
security:
|
|
29
32
|
basic_auth:
|
|
30
|
-
|
|
33
|
+
master_user: admin
|
|
34
|
+
password: 'U34I6InQ8elseTgqTWT2t2oFXpoqFg'
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.splitDomain = void 0;
|
|
4
|
-
const splitDomain = (domain) => {
|
|
5
|
-
const parts = domain.split('.');
|
|
6
|
-
const rr = parts.length > 2 ? parts[0] : '@';
|
|
7
|
-
const domainName = parts.length > 2 ? parts.slice(1).join('.') : domain;
|
|
8
|
-
return { rr, domainName };
|
|
9
|
-
};
|
|
10
|
-
exports.splitDomain = splitDomain;
|