@abtnode/core 1.17.7-beta-20251227-001958-ea2ba3f5 → 1.17.7-beta-20251229-223813-e1e6c5e3

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 (39) hide show
  1. package/lib/blocklet/manager/disk.js +74 -32
  2. package/lib/blocklet/manager/ensure-blocklet-running.js +1 -1
  3. package/lib/blocklet/manager/helper/blue-green-start-blocklet.js +1 -1
  4. package/lib/blocklet/manager/helper/install-application-from-general.js +2 -3
  5. package/lib/blocklet/manager/helper/install-component-from-url.js +7 -4
  6. package/lib/blocklet/migration-dist/migration.cjs +5 -4
  7. package/lib/blocklet/passport/index.js +10 -3
  8. package/lib/blocklet/project/index.js +7 -2
  9. package/lib/blocklet/security/index.js +2 -2
  10. package/lib/cert.js +6 -3
  11. package/lib/event/index.js +98 -87
  12. package/lib/event/util.js +7 -13
  13. package/lib/index.js +15 -26
  14. package/lib/migrations/1.5.0-site.js +3 -7
  15. package/lib/migrations/1.5.15-site.js +3 -7
  16. package/lib/monitor/blocklet-runtime-monitor.js +37 -5
  17. package/lib/monitor/node-runtime-monitor.js +4 -4
  18. package/lib/router/helper.js +525 -452
  19. package/lib/router/index.js +280 -104
  20. package/lib/router/manager.js +14 -28
  21. package/lib/states/blocklet-child.js +93 -1
  22. package/lib/states/blocklet-extras.js +1 -1
  23. package/lib/states/blocklet.js +429 -197
  24. package/lib/states/node.js +0 -10
  25. package/lib/states/site.js +87 -4
  26. package/lib/team/manager.js +2 -21
  27. package/lib/util/blocklet.js +39 -19
  28. package/lib/util/get-accessible-external-node-ip.js +21 -6
  29. package/lib/util/index.js +3 -3
  30. package/lib/util/ip.js +15 -1
  31. package/lib/util/launcher.js +11 -11
  32. package/lib/util/ready.js +2 -9
  33. package/lib/util/reset-node.js +6 -5
  34. package/lib/validators/router.js +0 -3
  35. package/lib/webhook/sender/api/index.js +5 -0
  36. package/package.json +23 -25
  37. package/lib/migrations/1.0.36-snapshot.js +0 -10
  38. package/lib/migrations/1.1.9-snapshot.js +0 -7
  39. package/lib/states/routing-snapshot.js +0 -146
@@ -1,6 +1,6 @@
1
1
  const get = require('lodash/get');
2
2
  const uniq = require('lodash/uniq');
3
- const throttle = require('lodash/throttle');
3
+ const debounce = require('lodash/debounce');
4
4
  const pick = require('lodash/pick');
5
5
  const isEqual = require('lodash/isEqual');
6
6
  const cloneDeep = require('@abtnode/util/lib/deep-clone');
@@ -27,30 +27,16 @@ const IP = require('../util/ip');
27
27
 
28
28
  const isServiceFeDevelopment = process.env.ABT_NODE_SERVICE_FE_PORT;
29
29
 
30
- const mergeAllowedOrigins = (domain, allowedOrigins) => {
31
- const origins = Array.isArray(allowedOrigins) ? allowedOrigins : [domain];
32
- if (origins.includes(domain) === false) {
33
- origins.push(domain);
34
- }
35
-
36
- // skip site if domain is BLOCKLET_SITE_GROUP
37
- const res = origins.filter((x) => !x.endsWith(BLOCKLET_SITE_GROUP_SUFFIX));
38
-
39
- return res;
40
- };
41
-
42
30
  const expandSites = (sites = []) => {
43
31
  const result = [];
44
32
 
45
33
  sites.forEach((site) => {
46
- site.corsAllowedOrigins = mergeAllowedOrigins(site.domain, site.corsAllowedOrigins);
47
34
  (site.domainAliases || []).forEach((domainAlias) => {
48
35
  const domain = typeof domainAlias === 'object' ? domainAlias.value : domainAlias;
49
36
  const tmpSite = cloneDeep(site);
50
37
  delete tmpSite.domainAliases;
51
38
  tmpSite.serviceType = isBlockletSite(site.domain) ? 'blocklet' : 'daemon';
52
39
  tmpSite.domain = domain;
53
- tmpSite.corsAllowedOrigins = mergeAllowedOrigins(tmpSite.domain, site.corsAllowedOrigins);
54
40
  result.push(tmpSite);
55
41
  });
56
42
 
@@ -98,7 +84,7 @@ const getRoutingTable = ({ sites, nodeInfo }) => {
98
84
  const enableIpServer = nodeInfo.routing.enableIpServer ?? false;
99
85
 
100
86
  // eslint-disable-next-line no-use-before-define
101
- let routingTable = Router.formatSites(sites);
87
+ let routingTable = Router.formatSites(sites, nodeInfo);
102
88
  routingTable = expandSites(routingTable);
103
89
  routingTable = filterSites({ sites: routingTable, enableDefaultServer, enableIpServer });
104
90
 
@@ -119,28 +105,122 @@ class Router {
119
105
  /**
120
106
  * Router
121
107
  * @constructor
122
- * @param {object} routingProvider
108
+ * @param {object} options
109
+ * @param {object} options.provider - Router provider instance
110
+ * @param {function} options.getAllRoutingParams - Function to get all routing params (for full reload)
111
+ * @param {function} [options.getBlockletRoutingParams] - Function to get single blocklet's routing params (for lightweight updates)
112
+ * @param {function} [options.getSystemRoutingParams] - Function to get global/system routing params (for global-only updates)
123
113
  */
124
- constructor({ provider, getRoutingParams }) {
114
+ constructor({ provider, getAllRoutingParams, getBlockletRoutingParams, getSystemRoutingParams }) {
125
115
  if (!provider) {
126
116
  throw new Error('Must provide valid router when create new router');
127
117
  }
128
118
 
129
- if (typeof getRoutingParams !== 'function') {
130
- throw new Error('Must provide a valid getRoutingParams function when create new router');
119
+ if (typeof getAllRoutingParams !== 'function') {
120
+ throw new Error('Must provide a valid getAllRoutingParams function when create new router');
131
121
  }
132
122
 
133
123
  this.provider = provider;
134
- this.getRoutingParams = getRoutingParams;
124
+ this.getAllRoutingParams = getAllRoutingParams;
125
+ this.getBlockletRoutingParams = getBlockletRoutingParams; // Optional - for lightweight single blocklet updates
126
+ this.getSystemRoutingParams = getSystemRoutingParams; // Optional - for global-only updates (O(1))
135
127
  this.routingTable = [];
136
128
 
137
- this.throttledReload = throttle(() => this.reload(), 5000, { leading: true, trailing: true });
138
- this.throttledRestart = throttle(() => this.restart(), 5000, { leading: true, trailing: true });
129
+ // Batching for rapid changes
130
+ this.pendingChanges = {
131
+ global: false,
132
+ blocklets: new Set(),
133
+ blockletsRemoved: new Set(),
134
+ };
135
+ this._processingBatch = false;
136
+
137
+ // Debounced batch processor - waits 1000ms for more changes, max 5s
138
+ this.debouncedProcessBatch = debounce(() => this._processBatch(), 1000, { maxWait: 5000 });
139
139
  }
140
140
 
141
+ /**
142
+ * Update routing table by fetching params and calling provider.update()
143
+ * This is a convenience method that combines _getUpdateParams() and provider.update()
144
+ */
141
145
  async updateRoutingTable() {
142
- logger.info('update routing table');
146
+ logger.info('router: update routing table');
147
+
148
+ const params = await this._getUpdateParams();
149
+ if (!params) {
150
+ logger.error('router: failed to get update params in updateRoutingTable');
151
+ return;
152
+ }
153
+ logger.info('router: update routing table params ready');
154
+
155
+ await this.provider.update(params);
156
+ logger.info('router: update routing table complete');
157
+ }
158
+
159
+ async update() {
160
+ logger.info('router: update');
161
+ await this.updateRoutingTable();
162
+ await this.provider.reload();
163
+ logger.info('router: reload provider success');
164
+ }
165
+
166
+ async start() {
167
+ logger.info('router: start');
168
+ await this.updateRoutingTable();
169
+ return this.provider.start();
170
+ }
171
+
172
+ async restart() {
173
+ logger.info('router: restart');
174
+ await this.updateRoutingTable();
175
+ return this.provider.restart();
176
+ }
177
+
178
+ async reload() {
179
+ logger.info('router: reload');
180
+ await this.updateRoutingTable();
181
+ return this.provider.reload();
182
+ }
183
+
184
+ stop() {
185
+ logger.info('router: stop');
186
+ return this.provider.stop();
187
+ }
188
+
189
+ async validateConfig() {
190
+ logger.info('router: validateConfig');
191
+ await this.provider.validateConfig();
192
+ }
193
+
194
+ async rotateLogs() {
195
+ logger.info('router: rotate logs');
196
+ await this.provider.rotateLogs();
197
+ }
198
+
199
+ getLogFilesForToday() {
200
+ return this.provider.getLogFilesForToday();
201
+ }
202
+
203
+ getLogDir() {
204
+ return this.provider.getLogDir();
205
+ }
143
206
 
207
+ searchCache(pattern, group) {
208
+ return this.provider.searchCache(pattern, group);
209
+ }
210
+
211
+ clearCache(group) {
212
+ return this.provider.clearCache(group);
213
+ }
214
+
215
+ supportsModSecurity() {
216
+ return !!this.provider.capabilities?.modsecurity;
217
+ }
218
+
219
+ /**
220
+ * Get update parameters for the provider
221
+ * @returns {Promise<object>} Parameters for provider.update()
222
+ */
223
+ async _getUpdateParams(fn = 'getAllRoutingParams') {
144
224
  const {
145
225
  sites,
146
226
  certificates,
@@ -148,10 +228,11 @@ class Router {
148
228
  services = [],
149
229
  nodeInfo = {},
150
230
  wafDisabledBlocklets = [],
151
- } = (await this.getRoutingParams()) || {};
231
+ } = (await this[fn]()) || {};
232
+
152
233
  if (!Array.isArray(sites)) {
153
- logger.error('sites is not an array', { sites });
154
- return;
234
+ logger.error('router:_getUpdateParams: sites is not an array', { fn, sites });
235
+ return null;
155
236
  }
156
237
 
157
238
  this.routingTable = getRoutingTable({ sites, nodeInfo });
@@ -179,7 +260,6 @@ class Router {
179
260
  if (blockPolicy.enabled) {
180
261
  blockPolicy.blacklist = await expandBlacklist(blockPolicy.blacklist);
181
262
 
182
- // remove current internal ip from blacklist to avoid blocking self
183
263
  const result = await IP.get({ timeout: 2000 });
184
264
  if (result?.internal) {
185
265
  blockPolicy.blacklist = blockPolicy.blacklist.filter((x) => x !== result.internal);
@@ -188,10 +268,7 @@ class Router {
188
268
  blockPolicy.blacklist = blockPolicy.blacklist.filter((x) => x !== result.external);
189
269
  }
190
270
 
191
- // Append blocked ips from database
192
271
  const blockedIps = await getActiveBlacklist();
193
- logger.info('router auto blocked ips', blockedIps);
194
-
195
272
  blockPolicy.blacklist = uniq([...blockPolicy.blacklist, ...blockedIps]);
196
273
  }
197
274
 
@@ -209,15 +286,12 @@ class Router {
209
286
  outboundAnomalyScoreThreshold: 10,
210
287
  };
211
288
 
212
- logger.info('router: update routing table', {
213
- snapshotHash: nodeInfo?.routing?.snapshotHash,
214
- });
215
- await this.provider.update({
289
+ return {
216
290
  routingTable: this.routingTable,
217
291
  certificates,
218
292
  commonHeaders: headers,
219
293
  services,
220
- nodeInfo: pick(nodeInfo, ['name', 'version', 'port', 'mode', 'enableWelcomePage', 'routing']),
294
+ nodeInfo: pick(nodeInfo, ['did', 'name', 'version', 'port', 'mode', 'enableWelcomePage', 'routing']),
221
295
  requestLimit,
222
296
  blockPolicy,
223
297
  proxyPolicy,
@@ -226,87 +300,190 @@ class Router {
226
300
  wafDisabledBlocklets,
227
301
  enableDefaultServer: nodeInfo.routing.enableDefaultServer ?? false,
228
302
  enableIpServer: nodeInfo.routing.enableIpServer ?? false,
229
- });
230
- logger.info('router: update routing table success', {
231
- snapshotHash: nodeInfo?.routing?.snapshotHash,
232
- });
303
+ };
233
304
  }
234
305
 
235
- async update() {
236
- logger.info('router: update');
237
- await this.updateRoutingTable();
238
- await this.provider.reload();
239
- logger.info('router: reload provider success');
240
- }
306
+ /**
307
+ * Queue a change for batched processing
308
+ * @param {string} changeType - 'global', 'blocklet', or 'blocklet-remove'
309
+ * @param {string} [did] - The blocklet DID (for blocklet changes)
310
+ */
311
+ queueChange(changeType, did = undefined) {
312
+ if (changeType === 'global') {
313
+ this.pendingChanges.global = true;
314
+ } else if (changeType === 'blocklet' && did) {
315
+ this.pendingChanges.blocklets.add(did);
316
+ // If we're updating a blocklet, remove it from the remove list
317
+ this.pendingChanges.blockletsRemoved.delete(did);
318
+ } else if (changeType === 'blocklet-remove' && did) {
319
+ this.pendingChanges.blockletsRemoved.add(did);
320
+ // If we're removing a blocklet, remove it from the update list
321
+ this.pendingChanges.blocklets.delete(did);
322
+ }
241
323
 
242
- async start() {
243
- logger.info('router: start');
244
- await this.updateRoutingTable();
245
- return this.provider.start();
246
- }
324
+ logger.info('router: queued change', {
325
+ changeType,
326
+ did,
327
+ global: this.pendingChanges.global,
328
+ blockletCount: this.pendingChanges.blocklets.size,
329
+ removeCount: this.pendingChanges.blockletsRemoved.size,
330
+ });
247
331
 
248
- async restart() {
249
- logger.info('router: restart');
250
- await this.updateRoutingTable();
251
- return this.provider.restart();
332
+ this.debouncedProcessBatch();
252
333
  }
253
334
 
254
- async reload() {
255
- logger.info('router: reload');
256
- await this.updateRoutingTable();
257
- return this.provider.reload();
258
- }
335
+ /**
336
+ * Process batched changes with tiered approach:
337
+ * - Global-only changes: O(1) using getSystemRoutingParams
338
+ * - Blocklet changes: O(1) per blocklet using getBlockletRoutingParams
339
+ * - Global + blocklet changes: O(1) global + O(k) blocklets where k = number of changed blocklets
340
+ */
341
+ async _processBatch() {
342
+ if (this._processingBatch) {
343
+ logger.info('router: already processing batch, will retry');
344
+ this.debouncedProcessBatch();
345
+ return;
346
+ }
259
347
 
260
- stop() {
261
- logger.info('router: stop');
262
- return this.provider.stop();
263
- }
348
+ const { global: globalChanged, blocklets, blockletsRemoved } = this.pendingChanges;
349
+ const hasBlockletChanges = blocklets.size > 0 || blockletsRemoved.size > 0;
350
+ const hasChanges = globalChanged || hasBlockletChanges;
264
351
 
265
- async validateConfig() {
266
- logger.info('router: validateConfig');
267
- await this.provider.validateConfig();
268
- }
352
+ if (!hasChanges) {
353
+ logger.debug('router: no pending changes to process');
354
+ return;
355
+ }
269
356
 
270
- async rotateLogs() {
271
- logger.info('router: rotate logs');
272
- await this.provider.rotateLogs();
273
- }
357
+ this._processingBatch = true;
274
358
 
275
- getLogFilesForToday() {
276
- return this.provider.getLogFilesForToday();
277
- }
359
+ // Clear pending changes before processing
360
+ const blockletsToUpdate = [...blocklets];
361
+ const blockletsToRemove = [...blockletsRemoved];
362
+ this.pendingChanges = {
363
+ global: false,
364
+ blocklets: new Set(),
365
+ blockletsRemoved: new Set(),
366
+ };
278
367
 
279
- getLogDir() {
280
- return this.provider.getLogDir();
281
- }
368
+ logger.info('router: processing batched changes', {
369
+ globalChanged,
370
+ blockletsToUpdate: blockletsToUpdate.length,
371
+ blockletsToRemove: blockletsToRemove.length,
372
+ });
282
373
 
283
- searchCache(pattern, group) {
284
- return this.provider.searchCache(pattern, group);
285
- }
374
+ try {
375
+ let needsReload = false;
286
376
 
287
- clearCache(group) {
288
- return this.provider.clearCache(group);
289
- }
377
+ // Get global params once (O(1)) - needed for both global and blocklet updates
378
+ let globalParams = null;
379
+ if (typeof this.getSystemRoutingParams === 'function') {
380
+ globalParams = await this._getUpdateParams('getSystemRoutingParams');
381
+ }
290
382
 
291
- supportsModSecurity() {
292
- return !!this.provider.capabilities?.modsecurity;
293
- }
294
- }
383
+ // Case 1: Global changed with no blocklet changes - use lightweight global update
384
+ if (globalChanged) {
385
+ if (globalParams) {
386
+ // Use global params for system sites + services + policies
387
+ await this.provider.update({ ...globalParams, skipBlockletSites: true });
388
+ needsReload = true;
389
+ logger.info('router: batch processed global-only changes');
390
+ } else {
391
+ logger.error('router: global-only changes found, but globalParams is not available');
392
+ }
393
+ }
295
394
 
296
- Router.formatSites = (sites = []) => {
297
- const result = cloneDeep(sites);
395
+ // Case 2: Process blocklet updates (O(1) per blocklet)
396
+ if (blockletsToUpdate.length > 0 && typeof this.getBlockletRoutingParams === 'function') {
397
+ // eslint-disable-next-line no-restricted-syntax
398
+ for (const did of blockletsToUpdate) {
399
+ try {
400
+ // eslint-disable-next-line no-await-in-loop
401
+ const rawParams = await this.getBlockletRoutingParams(did);
402
+ if (rawParams && rawParams.sites && rawParams.sites.length > 0) {
403
+ const { sites, certificates, headers = {}, nodeInfo = {}, wafDisabledBlocklets = [] } = rawParams;
404
+ const blockletParams = {
405
+ routingTable: getRoutingTable({ sites, nodeInfo }),
406
+ certificates,
407
+ commonHeaders: headers,
408
+ nodeInfo: pick(nodeInfo, ['did', 'name', 'version', 'port', 'mode', 'enableWelcomePage', 'routing']),
409
+ wafDisabledBlocklets,
410
+ };
411
+
412
+ if (typeof this.provider.updateSingleBlocklet === 'function') {
413
+ // eslint-disable-next-line no-await-in-loop
414
+ await this.provider.updateSingleBlocklet(did, blockletParams);
415
+ logger.info('router: batch processed blocklet changes', { did });
416
+ needsReload = true;
417
+ }
418
+ }
419
+ } catch (error) {
420
+ logger.warn('router: failed to update blocklet in batch, skipping', { did, error: error.message });
421
+ }
422
+ }
423
+ }
424
+
425
+ // Case 4: Process blocklet removals
426
+ // eslint-disable-next-line no-restricted-syntax
427
+ for (const did of blockletsToRemove) {
428
+ if (typeof this.provider._removeBlockletConfig === 'function') {
429
+ // eslint-disable-next-line no-await-in-loop
430
+ await this.provider._removeBlockletConfig(did);
431
+ logger.info('router: batch processed blocklet removal', { did });
432
+ needsReload = true;
433
+ }
434
+ }
435
+
436
+ // Single reload for all changes
437
+ if (needsReload) {
438
+ const status = await this.provider.getStatus();
439
+ logger.info('router: batch needs reload', { status });
440
+ if (!status.running) {
441
+ await this.provider.start();
442
+ } else {
443
+ await this.provider.reload();
444
+ }
445
+ }
298
446
 
299
- // Add extra routing rules to make blocklets adaptive
300
- let daemonRule = null;
301
- for (let i = 0; i < result.length; i++) {
302
- daemonRule = result[i].rules.find((x) => x.to.type === ROUTING_RULE_TYPES.DAEMON);
303
- if (daemonRule) {
304
- break;
447
+ logger.info('router: batch processing complete', {
448
+ globalChanged,
449
+ blockletsUpdated: blockletsToUpdate.length,
450
+ blockletsRemoved: blockletsToRemove.length,
451
+ });
452
+ } catch (error) {
453
+ logger.error('router: batch processing failed', { error: error.message });
454
+ // Try full reload as fallback
455
+ try {
456
+ await this.reload();
457
+ } catch (reloadError) {
458
+ logger.error('router: fallback reload also failed', { error: reloadError.message });
459
+ }
460
+ } finally {
461
+ this._processingBatch = false;
305
462
  }
306
463
  }
307
- if (!daemonRule) {
308
- return result;
464
+
465
+ /**
466
+ * Full regeneration - O(N) complexity
467
+ * Use for startup, manual rebuild, or when complete regeneration is needed
468
+ * @param {Object} options
469
+ * @param {string} [options.message] - Log message describing the reason for regeneration
470
+ */
471
+ async regenerateAll({ message = '' } = {}) {
472
+ logger.info('router: full regeneration', { message });
473
+ const params = await this._getUpdateParams('getAllRoutingParams');
474
+ if (!params) {
475
+ logger.error('router: failed to get update params for full regeneration');
476
+ return;
477
+ }
478
+
479
+ await this.provider.update(params);
480
+ await this.provider.reload();
481
+ logger.info('router: full regeneration complete', { message });
309
482
  }
483
+ }
484
+
485
+ Router.formatSites = (sites = [], info) => {
486
+ const result = cloneDeep(sites);
310
487
 
311
488
  result.forEach((site) => {
312
489
  const rules = Array.isArray(site.rules) ? cloneDeep(site.rules) : [];
@@ -324,7 +501,7 @@ Router.formatSites = (sites = []) => {
324
501
  },
325
502
  to: {
326
503
  type: ROUTING_RULE_TYPES.DAEMON,
327
- port: daemonRule.to.port,
504
+ port: info.port,
328
505
  did: site.blockletDid,
329
506
  },
330
507
  });
@@ -334,7 +511,7 @@ Router.formatSites = (sites = []) => {
334
511
  site.rules.push({
335
512
  dynamic: true,
336
513
  from: { root: true, pathPrefix: '/', groupPathPrefix: '/', pathSuffix: '/favicon.ico' },
337
- to: { type: ROUTING_RULE_TYPES.SERVICE, port: process.env.ABT_NODE_SERVICE_PORT, did: site.blockletDid },
514
+ to: { type: ROUTING_RULE_TYPES.SERVICE, port: info.port, did: site.blockletDid },
338
515
  });
339
516
  }
340
517
 
@@ -362,7 +539,7 @@ Router.formatSites = (sites = []) => {
362
539
  },
363
540
  to: {
364
541
  type: ROUTING_RULE_TYPES.DAEMON,
365
- port: daemonRule.to.port,
542
+ port: info.port,
366
543
  did: rule.to.did,
367
544
  componentId: rule.to.componentId,
368
545
  pageGroup: rule.to.pageGroup,
@@ -374,7 +551,6 @@ Router.formatSites = (sites = []) => {
374
551
  if (isBlockletSite(site.domain) && Object.keys(grouped).length === 0) {
375
552
  grouped['/'] = {
376
553
  id: '',
377
- groupId: '',
378
554
  to: {
379
555
  did: site.blockletDid,
380
556
  componentId: site.blockletDid,
@@ -397,7 +573,7 @@ Router.formatSites = (sites = []) => {
397
573
  from: rootFrom,
398
574
  to: {
399
575
  type: ROUTING_RULE_TYPES.DAEMON,
400
- port: daemonRule.to.port,
576
+ port: info.port,
401
577
  pageGroup: rule.to.pageGroup,
402
578
  did: rule.to.did,
403
579
  },
@@ -411,7 +587,7 @@ Router.formatSites = (sites = []) => {
411
587
  pathPrefix: BLOCKLET_PROXY_PATH_PREFIX,
412
588
  },
413
589
  to: {
414
- port: daemonRule.to.port,
590
+ port: info.port,
415
591
  type: ROUTING_RULE_TYPES.DAEMON,
416
592
  target: BLOCKLET_PROXY_PATH_PREFIX,
417
593
  cacheGroup: !isServiceFeDevelopment && site.mode === BLOCKLET_MODES.PRODUCTION ? 'blockletProxy' : '',
@@ -23,12 +23,7 @@ const checkDomainMatch = require('@abtnode/util/lib/check-domain-match');
23
23
  const { isDidDomain, isCustomDomain } = require('@abtnode/util/lib/url-evaluation');
24
24
  const { isTopLevelDomain } = require('@abtnode/util/lib/domain');
25
25
  const { EVENTS, WELLKNOWN_PING_PREFIX } = require('@abtnode/constant');
26
- const {
27
- DOMAIN_FOR_IP_SITE,
28
- DOMAIN_FOR_DEFAULT_SITE,
29
- ROUTING_RULE_TYPES,
30
- DEFAULT_SERVICE_PATH,
31
- } = require('@abtnode/constant');
26
+ const { DOMAIN_FOR_IP_SITE, DOMAIN_FOR_DEFAULT_SITE, ROUTING_RULE_TYPES } = require('@abtnode/constant');
32
27
  const {
33
28
  BLOCKLET_BUNDLE_FOLDER,
34
29
  BLOCKLET_DYNAMIC_PATH_PREFIX,
@@ -59,15 +54,7 @@ const {
59
54
  const checkDNS = require('../util/check-dns');
60
55
 
61
56
  const checkPathPrefixInBlackList = (pathPrefix, extraBlackList = []) => {
62
- const blacklist = [
63
- 'static',
64
- 'build',
65
- 'dist',
66
- 'assets',
67
- '.service',
68
- BLOCKLET_BUNDLE_FOLDER,
69
- DEFAULT_SERVICE_PATH,
70
- ].concat(extraBlackList);
57
+ const blacklist = ['static', 'build', 'dist', 'assets', '.service', BLOCKLET_BUNDLE_FOLDER].concat(extraBlackList);
71
58
  const prefixBlacklist = ['_abtnode_'].concat(extraBlackList);
72
59
  if (blacklist.find((b) => normalizePathPrefix(pathPrefix) === normalizePathPrefix(b))) {
73
60
  throw new Error(`path prefix can't be one of these values: ${blacklist.join(', ')}`);
@@ -420,7 +407,7 @@ class RouterManager extends EventEmitter {
420
407
  }
421
408
 
422
409
  async addRoutingRule(
423
- { id, rule: tempRule, skipCheckDynamicBlacklist = false, formatPathPrefix = true },
410
+ { id, rule: tempRule, skipCheckDynamicBlacklist = false, formatPathPrefix = true, skipValidation = false },
424
411
  context = {}
425
412
  ) {
426
413
  const { rule } = await validateAddRule({ id, rule: tempRule }, context);
@@ -458,7 +445,9 @@ class RouterManager extends EventEmitter {
458
445
  }
459
446
 
460
447
  await this.validatePathPrefix(rule);
461
- await this.validateRouterConfig('addRoutingRule', { id, rule });
448
+ if (!skipValidation) {
449
+ await this.validateRouterConfig('addRoutingRule', { id, rule });
450
+ }
462
451
 
463
452
  // add child blocklet rules
464
453
  for (const x of await this.getRulesForMutation(rule)) {
@@ -482,7 +471,7 @@ class RouterManager extends EventEmitter {
482
471
  }
483
472
 
484
473
  async updateRoutingRule(
485
- { id, rule: tmpRule, skipProtectedRuleChecking = false, formatPathPrefix = true },
474
+ { id, rule: tmpRule, skipProtectedRuleChecking = false, formatPathPrefix = true, skipValidation = false },
486
475
  context = {}
487
476
  ) {
488
477
  const { rule } = await validateEditRule({ id, rule: tmpRule }, context);
@@ -518,13 +507,12 @@ class RouterManager extends EventEmitter {
518
507
  }
519
508
 
520
509
  await this.validatePathPrefix(rule);
521
- await this.validateRouterConfig('updateRoutingRule', { id, rule });
510
+ if (!skipValidation) {
511
+ await this.validateRouterConfig('updateRoutingRule', { id, rule });
512
+ }
522
513
 
523
514
  // update rules
524
- const newRules = [
525
- ...dbSite.rules.filter((x) => (x.groupId && x.groupId !== rule.id) || x.id !== rule.id), // 有些路由没有 rule.groupId
526
- ...(await this.getRulesForMutation(rule)),
527
- ];
515
+ const newRules = [...dbSite.rules.filter((x) => x.id !== rule.id), ...(await this.getRulesForMutation(rule))];
528
516
 
529
517
  const updateResult = await states.site.update({ id }, { $set: { rules: newRules } });
530
518
  logger.info('update result', { updateResult });
@@ -551,8 +539,8 @@ class RouterManager extends EventEmitter {
551
539
 
552
540
  // 只要有匹配到的查询条件,不管是否删除成功都不会返回 0,所以这里没用 update 的返回值
553
541
  const doc = await states.site.findOne({ id });
554
- if (doc.rules.some((x) => x.id === ruleId || x.groupId === ruleId)) {
555
- const newRules = doc.rules.filter((x) => x.id !== ruleId && x.groupId !== ruleId);
542
+ if (doc.rules.some((x) => x.id === ruleId)) {
543
+ const newRules = doc.rules.filter((x) => x.id !== ruleId);
556
544
  await states.site.update({ id }, { $set: { rules: newRules } });
557
545
  }
558
546
 
@@ -840,7 +828,7 @@ class RouterManager extends EventEmitter {
840
828
  });
841
829
  const tempRouter = new Router({
842
830
  provider,
843
- getRoutingParams: async () => ({
831
+ getAllRoutingParams: async () => ({
844
832
  sites: await ensureLatestInfo([site]),
845
833
  certificates,
846
834
  commonHeaders: get(info, 'routing.headers', {}),
@@ -865,7 +853,6 @@ class RouterManager extends EventEmitter {
865
853
  if (!rule.id) {
866
854
  rule.id = uuid.v4();
867
855
  }
868
- rule.groupId = rule.id;
869
856
  rule.from.pathPrefix = normalizePathPrefix(rule.from.pathPrefix);
870
857
  if (rule.to.type === ROUTING_RULE_TYPES.BLOCKLET) {
871
858
  // pathPrefix of root blocklet maybe changed to another prefix than '/', so use old groupPathPrefix first
@@ -937,7 +924,6 @@ class RouterManager extends EventEmitter {
937
924
  // if is root path, child rule become root rule
938
925
  const childRule = {
939
926
  id: occupied ? rawRule.id : uuid.v4(),
940
- groupId: rawRule.id,
941
927
  from: {
942
928
  pathPrefix: normalizePathPrefix(pathPrefix),
943
929
  groupPathPrefix: blockletPrefix,