@abtnode/core 1.17.4-beta-20251205-104405-28838df1 → 1.17.4-beta-20251206-081442-6f622450

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/lib/index.js CHANGED
@@ -325,6 +325,7 @@ function ABTNode(options) {
325
325
  getSitesFromSnapshot,
326
326
  getRoutingCrons,
327
327
  ensureWildcardCerts,
328
+ ensureServerlessCerts,
328
329
  getRouterProvider,
329
330
  addRoutingSite,
330
331
  deleteRoutingSite,
@@ -730,6 +731,7 @@ function ABTNode(options) {
730
731
  getSitesFromSnapshot,
731
732
  ensureDashboardRouting,
732
733
  ensureWildcardCerts,
734
+ ensureServerlessCerts,
733
735
 
734
736
  addDomainAlias,
735
737
  deleteDomainAlias,
@@ -25,9 +25,12 @@ const md5 = require('@abtnode/util/lib/md5');
25
25
  const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
26
26
  const getTmpDir = require('@abtnode/util/lib/get-tmp-directory');
27
27
  const downloadFile = require('@abtnode/util/lib/download-file');
28
+ const axios = require('@abtnode/util/lib/axios');
28
29
  const { getIpDnsDomainForBlocklet } = require('@abtnode/util/lib/get-domain-for-blocklet');
29
30
  const { forEachBlockletSync } = require('@blocklet/meta/lib/util');
30
31
  const { processLogByDate } = require('@abtnode/analytics');
32
+ const pRetry = require('p-retry');
33
+ const { buildLauncherUrl, buildRequestHeaders } = require('@abtnode/auth/lib/launcher');
31
34
  const {
32
35
  DOMAIN_FOR_DEFAULT_SITE,
33
36
  DOMAIN_FOR_IP_SITE_REGEXP,
@@ -52,6 +55,7 @@ const {
52
55
  EVENTS,
53
56
  DEFAULT_IP_DOMAIN,
54
57
  WELLKNOWN_BLACKLIST_PREFIX,
58
+ NODE_MODES,
55
59
  } = require('@abtnode/constant');
56
60
  const {
57
61
  BLOCKLET_DYNAMIC_PATH_PREFIX,
@@ -903,6 +907,133 @@ module.exports = function getRouterHelpers({
903
907
  ]);
904
908
  };
905
909
 
910
+ const ensureServerlessCerts = async () => {
911
+ const info = await nodeState.read();
912
+
913
+ if (info.mode !== NODE_MODES.SERVERLESS) {
914
+ logger.warn('ensureServerlessCerts: not in serverless mode', { mode: info.mode });
915
+ return;
916
+ }
917
+
918
+ const launcherUrl = process.env.ABT_NODE_BLOCKLET_LAUNCHER_URL || info.registerUrl;
919
+ const provisionToken = process.env.ABT_NODE_PROVISION_TOKEN;
920
+
921
+ if (!launcherUrl) {
922
+ logger.warn('ensureServerlessCerts: missing launcher URL');
923
+ return;
924
+ }
925
+
926
+ let authHeaders = {};
927
+ let authType = 'none';
928
+
929
+ const payload = {
930
+ did: info.did,
931
+ version: info.version,
932
+ };
933
+
934
+ if (provisionToken) {
935
+ authHeaders = { Authorization: `Bearer ${provisionToken}` };
936
+ authType = 'bearer';
937
+ } else if (info.sk) {
938
+ try {
939
+ authHeaders = await buildRequestHeaders(info.sk, payload);
940
+ authType = 'signature';
941
+ } catch (error) {
942
+ logger.error('ensureServerlessCerts: failed to create signature', { error });
943
+ return;
944
+ }
945
+ } else {
946
+ logger.warn('ensureServerlessCerts: no authentication method available');
947
+ return;
948
+ }
949
+
950
+ const fn = async () => {
951
+ const provisionUrl = await buildLauncherUrl(launcherUrl, '/api/serverless/provision');
952
+ const destFolder = getTmpDir(path.join(`serverless-cert-${Date.now()}`));
953
+
954
+ logger.info('download serverless certificate start', { provisionUrl, destFolder, authType });
955
+
956
+ try {
957
+ const filename = path.join(destFolder, 'certificate.tar.gz');
958
+ fs.ensureDirSync(destFolder);
959
+
960
+ const { data } = await axios({
961
+ method: 'post',
962
+ url: provisionUrl,
963
+ headers: authHeaders,
964
+ responseType: 'stream',
965
+ data: payload,
966
+ });
967
+
968
+ const fileStream = data.pipe(fs.createWriteStream(filename));
969
+ await new Promise((resolve, reject) => {
970
+ fileStream.on('finish', resolve);
971
+ fileStream.on('error', reject);
972
+ });
973
+
974
+ await decompressCertificates(filename, destFolder);
975
+
976
+ const certificateFilePath = path.join(destFolder, 'cert.pem');
977
+ const privateKeyFilePath = path.join(destFolder, 'privkey.pem');
978
+
979
+ if (!fs.existsSync(certificateFilePath)) {
980
+ throw new Error('serverless certificate invalid: cert.pem does not exist');
981
+ }
982
+
983
+ if (!fs.existsSync(privateKeyFilePath)) {
984
+ throw new Error('serverless certificate invalid: privkey.pem does not exist');
985
+ }
986
+
987
+ const certificate = fs.readFileSync(certificateFilePath).toString();
988
+ const privateKey = fs.readFileSync(privateKeyFilePath).toString();
989
+
990
+ const certInfo = getHttpsCertInfo(certificate);
991
+ const domain = certInfo.sans?.[0] || certInfo.domain;
992
+
993
+ if (!domain) {
994
+ throw new Error('serverless certificate invalid: no domain found');
995
+ }
996
+
997
+ await certManager.upsertByDomain({
998
+ domain,
999
+ privateKey,
1000
+ certificate,
1001
+ isProtected: false,
1002
+ });
1003
+
1004
+ logger.info('serverless certificate updated', { domain, authType });
1005
+ return domain;
1006
+ } catch (error) {
1007
+ logger.error('serverless certificate download failed', { error, authType });
1008
+ throw error;
1009
+ } finally {
1010
+ fs.removeSync(destFolder);
1011
+ logger.info('remove serverless certificate dest folder', { destFolder });
1012
+ }
1013
+ };
1014
+
1015
+ const delay = 10 * 1000;
1016
+ try {
1017
+ await pRetry(fn, {
1018
+ retries: 3,
1019
+ minTimeout: delay,
1020
+ maxTimeout: delay,
1021
+ onFailedAttempt: (error) => {
1022
+ logger.error('serverless certificate download retry', {
1023
+ error,
1024
+ attempt: error.attemptNumber,
1025
+ retriesLeft: error.retriesLeft,
1026
+ });
1027
+ if (error.response && error.response.status >= 400 && error.response.status < 500) {
1028
+ throw error;
1029
+ }
1030
+ },
1031
+ });
1032
+ } catch (error) {
1033
+ logger.error('serverless certificate update failed', { error, authType });
1034
+ }
1035
+ };
1036
+
906
1037
  const upsertSiteRule = async ({ site, rule }, context) => {
907
1038
  const findExistingRule = (prefix) => site.rules.find((r) => r.from.pathPrefix === normalizePathPrefix(prefix));
908
1039
 
@@ -2040,6 +2171,7 @@ module.exports = function getRouterHelpers({
2040
2171
  getSitesFromSnapshot,
2041
2172
  getCertificates,
2042
2173
  ensureWildcardCerts,
2174
+ ensureServerlessCerts,
2043
2175
  addWellknownSite,
2044
2176
  upsertSiteRule,
2045
2177
  getRouterProvider: (name) => providers[name],
@@ -2052,6 +2184,12 @@ module.exports = function getRouterHelpers({
2052
2184
  fn: () => updateDashboardCertificates(),
2053
2185
  options: { runOnInit: true },
2054
2186
  },
2187
+ {
2188
+ name: 'update-serverless-certificate',
2189
+ time: '0 10 */6 * * *', // refetch on 0:10, 6:10, etc. (offset from dashboard cert update)
2190
+ fn: () => ensureServerlessCerts(),
2191
+ options: { runOnInit: false },
2192
+ },
2055
2193
  {
2056
2194
  name: 'rotate-log-files',
2057
2195
  time: '1 0 0 * * *', // rotate at 00:00:01 every day
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.17.4-beta-20251205-104405-28838df1",
6
+ "version": "1.17.4-beta-20251206-081442-6f622450",
7
7
  "description": "",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -17,21 +17,21 @@
17
17
  "author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
18
18
  "license": "Apache-2.0",
19
19
  "dependencies": {
20
- "@abtnode/analytics": "1.17.4-beta-20251205-104405-28838df1",
21
- "@abtnode/auth": "1.17.4-beta-20251205-104405-28838df1",
22
- "@abtnode/certificate-manager": "1.17.4-beta-20251205-104405-28838df1",
23
- "@abtnode/constant": "1.17.4-beta-20251205-104405-28838df1",
24
- "@abtnode/cron": "1.17.4-beta-20251205-104405-28838df1",
25
- "@abtnode/db-cache": "1.17.4-beta-20251205-104405-28838df1",
26
- "@abtnode/docker-utils": "1.17.4-beta-20251205-104405-28838df1",
27
- "@abtnode/logger": "1.17.4-beta-20251205-104405-28838df1",
28
- "@abtnode/models": "1.17.4-beta-20251205-104405-28838df1",
29
- "@abtnode/queue": "1.17.4-beta-20251205-104405-28838df1",
30
- "@abtnode/rbac": "1.17.4-beta-20251205-104405-28838df1",
31
- "@abtnode/router-provider": "1.17.4-beta-20251205-104405-28838df1",
32
- "@abtnode/static-server": "1.17.4-beta-20251205-104405-28838df1",
33
- "@abtnode/timemachine": "1.17.4-beta-20251205-104405-28838df1",
34
- "@abtnode/util": "1.17.4-beta-20251205-104405-28838df1",
20
+ "@abtnode/analytics": "1.17.4-beta-20251206-081442-6f622450",
21
+ "@abtnode/auth": "1.17.4-beta-20251206-081442-6f622450",
22
+ "@abtnode/certificate-manager": "1.17.4-beta-20251206-081442-6f622450",
23
+ "@abtnode/constant": "1.17.4-beta-20251206-081442-6f622450",
24
+ "@abtnode/cron": "1.17.4-beta-20251206-081442-6f622450",
25
+ "@abtnode/db-cache": "1.17.4-beta-20251206-081442-6f622450",
26
+ "@abtnode/docker-utils": "1.17.4-beta-20251206-081442-6f622450",
27
+ "@abtnode/logger": "1.17.4-beta-20251206-081442-6f622450",
28
+ "@abtnode/models": "1.17.4-beta-20251206-081442-6f622450",
29
+ "@abtnode/queue": "1.17.4-beta-20251206-081442-6f622450",
30
+ "@abtnode/rbac": "1.17.4-beta-20251206-081442-6f622450",
31
+ "@abtnode/router-provider": "1.17.4-beta-20251206-081442-6f622450",
32
+ "@abtnode/static-server": "1.17.4-beta-20251206-081442-6f622450",
33
+ "@abtnode/timemachine": "1.17.4-beta-20251206-081442-6f622450",
34
+ "@abtnode/util": "1.17.4-beta-20251206-081442-6f622450",
35
35
  "@aigne/aigne-hub": "^0.10.10",
36
36
  "@arcblock/did": "^1.27.12",
37
37
  "@arcblock/did-connect-js": "^1.27.12",
@@ -43,15 +43,15 @@
43
43
  "@arcblock/pm2-events": "^0.0.5",
44
44
  "@arcblock/validator": "^1.27.12",
45
45
  "@arcblock/vc": "^1.27.12",
46
- "@blocklet/constant": "1.17.4-beta-20251205-104405-28838df1",
46
+ "@blocklet/constant": "1.17.4-beta-20251206-081442-6f622450",
47
47
  "@blocklet/did-space-js": "^1.2.6",
48
- "@blocklet/env": "1.17.4-beta-20251205-104405-28838df1",
48
+ "@blocklet/env": "1.17.4-beta-20251206-081442-6f622450",
49
49
  "@blocklet/error": "^0.3.3",
50
- "@blocklet/meta": "1.17.4-beta-20251205-104405-28838df1",
51
- "@blocklet/resolver": "1.17.4-beta-20251205-104405-28838df1",
52
- "@blocklet/sdk": "1.17.4-beta-20251205-104405-28838df1",
53
- "@blocklet/server-js": "1.17.4-beta-20251205-104405-28838df1",
54
- "@blocklet/store": "1.17.4-beta-20251205-104405-28838df1",
50
+ "@blocklet/meta": "1.17.4-beta-20251206-081442-6f622450",
51
+ "@blocklet/resolver": "1.17.4-beta-20251206-081442-6f622450",
52
+ "@blocklet/sdk": "1.17.4-beta-20251206-081442-6f622450",
53
+ "@blocklet/server-js": "1.17.4-beta-20251206-081442-6f622450",
54
+ "@blocklet/store": "1.17.4-beta-20251206-081442-6f622450",
55
55
  "@blocklet/theme": "^3.2.11",
56
56
  "@fidm/x509": "^1.2.1",
57
57
  "@ocap/mcrypto": "^1.27.12",
@@ -116,5 +116,5 @@
116
116
  "express": "^4.18.2",
117
117
  "unzipper": "^0.10.11"
118
118
  },
119
- "gitHead": "f8e18c8b32b19fd98de3d292a0036e628e59d474"
119
+ "gitHead": "37b0b1147d40a5cf787cba5d111a63a2b6259790"
120
120
  }