@adobe/spacecat-shared-tokowaka-client 1.18.1 → 1.19.0
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/CHANGELOG.md +12 -0
- package/package.json +1 -1
- package/src/index.js +21 -15
- package/test/index.test.js +284 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## [@adobe/spacecat-shared-tokowaka-client-v1.19.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-tokowaka-client-v1.18.2...@adobe/spacecat-shared-tokowaka-client-v1.19.0) (2026-06-03)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* **tokowaka-client:** mark path-level suggestions as coveredByDomainWide on domain-wide deploy ([#1648](https://github.com/adobe/spacecat-shared/issues/1648)) ([9cc5992](https://github.com/adobe/spacecat-shared/commit/9cc5992bb98acf9da48a432fedfbec694d30fe23))
|
|
6
|
+
|
|
7
|
+
## [@adobe/spacecat-shared-tokowaka-client-v1.18.2](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-tokowaka-client-v1.18.1...@adobe/spacecat-shared-tokowaka-client-v1.18.2) (2026-06-02)
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **tokowaka-client:** use scraperConfig headers in edge optimize probe (LLMO-5280) ([#1647](https://github.com/adobe/spacecat-shared/issues/1647)) ([6be14a1](https://github.com/adobe/spacecat-shared/commit/6be14a153ea8d9de010880afaa1c3c9290a32f13))
|
|
12
|
+
|
|
1
13
|
## [@adobe/spacecat-shared-tokowaka-client-v1.18.1](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-tokowaka-client-v1.18.0...@adobe/spacecat-shared-tokowaka-client-v1.18.1) (2026-06-01)
|
|
2
14
|
|
|
3
15
|
### Bug Fixes
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1287,10 +1287,18 @@ class TokowakaClient {
|
|
|
1287
1287
|
return { edgeOptimizeEnabled: true };
|
|
1288
1288
|
}
|
|
1289
1289
|
|
|
1290
|
+
const defaultProbeHeaders = {
|
|
1291
|
+
// eslint-disable-next-line max-len
|
|
1292
|
+
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Tokowaka-AI Tokowaka/1.0 AdobeEdgeOptimize-AI AdobeEdgeOptimize/1.0',
|
|
1293
|
+
'fastly-debug': '1',
|
|
1294
|
+
};
|
|
1295
|
+
const customHeaders = currentConfig?.getScraperConfig?.()?.headers ?? {};
|
|
1296
|
+
const probeHeaders = { ...customHeaders, ...defaultProbeHeaders };
|
|
1297
|
+
|
|
1290
1298
|
const baseURL = getEffectiveBaseURL(site);
|
|
1291
1299
|
const targetUrl = new URL(path, baseURL).toString();
|
|
1292
1300
|
|
|
1293
|
-
this.log.info(`Checking edge optimize status for ${targetUrl}`);
|
|
1301
|
+
this.log.info(`[edge-optimize-status] Checking edge optimize status for ${targetUrl}`);
|
|
1294
1302
|
|
|
1295
1303
|
const maxRetries = 3;
|
|
1296
1304
|
let attempt = 0;
|
|
@@ -1300,25 +1308,21 @@ class TokowakaClient {
|
|
|
1300
1308
|
while (attempt <= maxRetries) {
|
|
1301
1309
|
try {
|
|
1302
1310
|
// eslint-disable-next-line max-len
|
|
1303
|
-
this.log.debug(`Attempt ${attempt + 1}/${maxRetries + 1}: Checking edge optimize status for ${targetUrl}`);
|
|
1311
|
+
this.log.debug(`[edge-optimize-status] Attempt ${attempt + 1}/${maxRetries + 1}: Checking edge optimize status for ${targetUrl}`);
|
|
1304
1312
|
|
|
1305
1313
|
// eslint-disable-next-line no-await-in-loop
|
|
1306
1314
|
const response = await tracingFetch(targetUrl, {
|
|
1307
1315
|
method: 'GET',
|
|
1308
|
-
headers:
|
|
1309
|
-
// eslint-disable-next-line max-len
|
|
1310
|
-
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Tokowaka-AI Tokowaka/1.0 AdobeEdgeOptimize-AI AdobeEdgeOptimize/1.0',
|
|
1311
|
-
'fastly-debug': '1',
|
|
1312
|
-
},
|
|
1316
|
+
headers: probeHeaders,
|
|
1313
1317
|
timeout: REQUEST_TIMEOUT_MS,
|
|
1314
1318
|
});
|
|
1315
1319
|
|
|
1316
|
-
this.log.
|
|
1320
|
+
this.log.info(`[edge-optimize-status] Response status: ${response.status} for ${targetUrl}`);
|
|
1317
1321
|
|
|
1318
1322
|
const edgeOptimizeEnabled = response.headers.get('x-tokowaka-request-id') !== null
|
|
1319
1323
|
|| response.headers.get('x-edgeoptimize-request-id') !== null;
|
|
1320
1324
|
|
|
1321
|
-
this.log.
|
|
1325
|
+
this.log.info(`[edge-optimize-status] Edge optimize headers found: ${edgeOptimizeEnabled} for ${targetUrl}`);
|
|
1322
1326
|
|
|
1323
1327
|
return {
|
|
1324
1328
|
edgeOptimizeEnabled,
|
|
@@ -1328,7 +1332,7 @@ class TokowakaClient {
|
|
|
1328
1332
|
|
|
1329
1333
|
if (isTimeout) {
|
|
1330
1334
|
// eslint-disable-next-line max-len
|
|
1331
|
-
this.log.warn(`Request timed out after ${REQUEST_TIMEOUT_MS}ms for ${targetUrl}, returning edgeOptimizeEnabled: false`);
|
|
1335
|
+
this.log.warn(`[edge-optimize-status] Request timed out after ${REQUEST_TIMEOUT_MS}ms for ${targetUrl}, returning edgeOptimizeEnabled: false`);
|
|
1332
1336
|
return { edgeOptimizeEnabled: false };
|
|
1333
1337
|
}
|
|
1334
1338
|
|
|
@@ -1336,7 +1340,7 @@ class TokowakaClient {
|
|
|
1336
1340
|
|
|
1337
1341
|
if (attempt > maxRetries) {
|
|
1338
1342
|
// All retries exhausted
|
|
1339
|
-
this.log.error(`Failed after ${maxRetries + 1} attempts: ${error.message}`);
|
|
1343
|
+
this.log.error(`[edge-optimize-status] Failed after ${maxRetries + 1} attempts: ${error.message} for ${targetUrl}`);
|
|
1340
1344
|
throw this.#createError(
|
|
1341
1345
|
`Failed to check edge optimize status: ${error.message}`,
|
|
1342
1346
|
HTTP_INTERNAL_SERVER_ERROR,
|
|
@@ -1346,7 +1350,7 @@ class TokowakaClient {
|
|
|
1346
1350
|
// Exponential backoff: 200ms, 400ms, 800ms
|
|
1347
1351
|
const delay = 100 * (2 ** attempt);
|
|
1348
1352
|
this.log.warn(
|
|
1349
|
-
`Attempt ${attempt} to fetch failed: ${error.message}. Retrying in ${delay}ms
|
|
1353
|
+
`[edge-optimize-status] Attempt ${attempt} to fetch failed: ${error.message}. Retrying in ${delay}ms... for ${targetUrl}`,
|
|
1350
1354
|
);
|
|
1351
1355
|
// eslint-disable-next-line no-await-in-loop
|
|
1352
1356
|
await new Promise((res) => {
|
|
@@ -1528,12 +1532,14 @@ class TokowakaClient {
|
|
|
1528
1532
|
if (!isEdgeDeployableSuggestionStatus(s.getStatus())) {
|
|
1529
1533
|
return false;
|
|
1530
1534
|
}
|
|
1531
|
-
if (isPatternSuggestion(s)) {
|
|
1532
|
-
return false;
|
|
1533
|
-
}
|
|
1534
1535
|
if (s.getData()?.edgeDeployed) {
|
|
1535
1536
|
return false;
|
|
1536
1537
|
}
|
|
1538
|
+
// Path-level pattern suggestions (not domain-wide) are fully covered by a
|
|
1539
|
+
// domain-wide deployment. Other pattern suggestions (including other DW ones) are not.
|
|
1540
|
+
if (isPatternSuggestion(s)) {
|
|
1541
|
+
return coverageField === 'coveredByDomainWide' && !s.getData()?.isDomainWide;
|
|
1542
|
+
}
|
|
1537
1543
|
const url = s.getData()?.url;
|
|
1538
1544
|
return url && matchers.some((match) => match(url));
|
|
1539
1545
|
});
|
package/test/index.test.js
CHANGED
|
@@ -3117,6 +3117,55 @@ describe('TokowakaClient', () => {
|
|
|
3117
3117
|
expect(coveredData).to.not.have.property('coveredByDomainWide');
|
|
3118
3118
|
});
|
|
3119
3119
|
|
|
3120
|
+
it('cleans up coveredByDomainWide on path-level suggestions when rolling back domain-wide', async () => {
|
|
3121
|
+
const prerenderOpportunity = { getId: () => 'opp-dw', getType: () => 'prerender' };
|
|
3122
|
+
const dwSuggestion = {
|
|
3123
|
+
getId: () => 'dw-1',
|
|
3124
|
+
getData: () => ({
|
|
3125
|
+
isDomainWide: true,
|
|
3126
|
+
allowedRegexPatterns: ['/*'],
|
|
3127
|
+
edgeDeployed: Date.now(),
|
|
3128
|
+
}),
|
|
3129
|
+
setData: sinon.stub(),
|
|
3130
|
+
setUpdatedBy: sinon.stub(),
|
|
3131
|
+
save: sinon.stub().resolves(),
|
|
3132
|
+
};
|
|
3133
|
+
const pathSuggestion = {
|
|
3134
|
+
getId: () => 'path-1',
|
|
3135
|
+
getData: () => ({
|
|
3136
|
+
allowedRegexPatterns: ['/products/*'],
|
|
3137
|
+
coveredByDomainWide: 'dw-1',
|
|
3138
|
+
}),
|
|
3139
|
+
setData: sinon.stub(),
|
|
3140
|
+
setUpdatedBy: sinon.stub(),
|
|
3141
|
+
save: sinon.stub().resolves(),
|
|
3142
|
+
};
|
|
3143
|
+
|
|
3144
|
+
sinon.stub(client, 'fetchMetaconfig').resolves({
|
|
3145
|
+
siteId: 'site-123',
|
|
3146
|
+
prerender: { allowList: ['/*'] },
|
|
3147
|
+
});
|
|
3148
|
+
sinon.stub(client, 'uploadMetaconfig').resolves();
|
|
3149
|
+
|
|
3150
|
+
const result = await client.rollbackSuggestions(
|
|
3151
|
+
mockSite,
|
|
3152
|
+
prerenderOpportunity,
|
|
3153
|
+
[dwSuggestion],
|
|
3154
|
+
{ allSuggestions: [dwSuggestion, pathSuggestion], updatedBy: 'test@example.com' },
|
|
3155
|
+
);
|
|
3156
|
+
|
|
3157
|
+
expect(result.succeededSuggestions).to.include(dwSuggestion);
|
|
3158
|
+
expect(pathSuggestion.setData.calledOnce).to.be.true;
|
|
3159
|
+
const pathData = pathSuggestion.setData.firstCall.args[0];
|
|
3160
|
+
expect(pathData).to.not.have.property('coveredByDomainWide');
|
|
3161
|
+
expect(pathData).to.have.property('allowedRegexPatterns');
|
|
3162
|
+
// Verify the cleaned-up path suggestion was actually persisted via saveMany
|
|
3163
|
+
expect(client.dataAccess.Suggestion.saveMany).to.have.been.calledWith(
|
|
3164
|
+
sinon.match((arr) => arr.includes(pathSuggestion)),
|
|
3165
|
+
sinon.match.any,
|
|
3166
|
+
);
|
|
3167
|
+
});
|
|
3168
|
+
|
|
3120
3169
|
it('cleans up covered suggestions (coveredByPattern) when rolling back a path-level pattern', async () => {
|
|
3121
3170
|
const prerenderOpportunity = { getId: () => 'opp-p', getType: () => 'prerender' };
|
|
3122
3171
|
const pathSuggestion = {
|
|
@@ -5035,6 +5084,165 @@ describe('TokowakaClient', () => {
|
|
|
5035
5084
|
expect(userAgent).to.include('Mozilla/5.0');
|
|
5036
5085
|
});
|
|
5037
5086
|
|
|
5087
|
+
it('should ignore custom User-Agent from scraperConfig — default takes priority', async () => {
|
|
5088
|
+
const customSite = {
|
|
5089
|
+
getId: () => 'site-id',
|
|
5090
|
+
getBaseURL: () => 'https://example.com',
|
|
5091
|
+
getConfig: () => ({
|
|
5092
|
+
getEdgeOptimizeConfig: () => undefined,
|
|
5093
|
+
getScraperConfig: () => ({ headers: { 'User-Agent': 'AllowListedBot/1.0' } }),
|
|
5094
|
+
}),
|
|
5095
|
+
getDeliveryType: () => 'aem_edge',
|
|
5096
|
+
};
|
|
5097
|
+
const mockResponse = {
|
|
5098
|
+
status: 200,
|
|
5099
|
+
headers: new Map(),
|
|
5100
|
+
};
|
|
5101
|
+
mockResponse.headers.get = () => null;
|
|
5102
|
+
|
|
5103
|
+
tracingFetchStub.resolves(mockResponse);
|
|
5104
|
+
|
|
5105
|
+
await esmockClient.checkEdgeOptimizeStatus(customSite, '/');
|
|
5106
|
+
|
|
5107
|
+
const fetchOptions = tracingFetchStub.firstCall.args[1];
|
|
5108
|
+
expect(fetchOptions.headers['User-Agent']).to.include('Tokowaka-AI');
|
|
5109
|
+
expect(fetchOptions.headers['User-Agent']).to.not.include('AllowListedBot/1.0');
|
|
5110
|
+
});
|
|
5111
|
+
|
|
5112
|
+
it('should add extra custom headers while defaults always win on collision', async () => {
|
|
5113
|
+
const customSite = {
|
|
5114
|
+
getId: () => 'site-id',
|
|
5115
|
+
getBaseURL: () => 'https://example.com',
|
|
5116
|
+
getConfig: () => ({
|
|
5117
|
+
getEdgeOptimizeConfig: () => undefined,
|
|
5118
|
+
getScraperConfig: () => ({ headers: { 'x-allowlist-token': 'secret123', 'fastly-debug': 'custom' } }),
|
|
5119
|
+
}),
|
|
5120
|
+
getDeliveryType: () => 'aem_edge',
|
|
5121
|
+
};
|
|
5122
|
+
const mockResponse = {
|
|
5123
|
+
status: 200,
|
|
5124
|
+
headers: new Map(),
|
|
5125
|
+
};
|
|
5126
|
+
mockResponse.headers.get = () => null;
|
|
5127
|
+
|
|
5128
|
+
tracingFetchStub.resolves(mockResponse);
|
|
5129
|
+
|
|
5130
|
+
await esmockClient.checkEdgeOptimizeStatus(customSite, '/');
|
|
5131
|
+
|
|
5132
|
+
const fetchOptions = tracingFetchStub.firstCall.args[1];
|
|
5133
|
+
expect(fetchOptions.headers['x-allowlist-token']).to.equal('secret123');
|
|
5134
|
+
expect(fetchOptions.headers['fastly-debug']).to.equal('1');
|
|
5135
|
+
expect(fetchOptions.headers['User-Agent']).to.include('Mozilla/5.0');
|
|
5136
|
+
});
|
|
5137
|
+
|
|
5138
|
+
it('should use default probe headers when scraperConfig has no headers', async () => {
|
|
5139
|
+
const noHeadersSite = {
|
|
5140
|
+
getId: () => 'site-id',
|
|
5141
|
+
getBaseURL: () => 'https://example.com',
|
|
5142
|
+
getConfig: () => ({
|
|
5143
|
+
getEdgeOptimizeConfig: () => undefined,
|
|
5144
|
+
getScraperConfig: () => ({}),
|
|
5145
|
+
}),
|
|
5146
|
+
getDeliveryType: () => 'aem_edge',
|
|
5147
|
+
};
|
|
5148
|
+
const mockResponse = {
|
|
5149
|
+
status: 200,
|
|
5150
|
+
headers: new Map(),
|
|
5151
|
+
};
|
|
5152
|
+
mockResponse.headers.get = () => null;
|
|
5153
|
+
|
|
5154
|
+
tracingFetchStub.resolves(mockResponse);
|
|
5155
|
+
|
|
5156
|
+
await esmockClient.checkEdgeOptimizeStatus(noHeadersSite, '/');
|
|
5157
|
+
|
|
5158
|
+
const fetchOptions = tracingFetchStub.firstCall.args[1];
|
|
5159
|
+
expect(fetchOptions.headers['User-Agent']).to.include('Tokowaka-AI');
|
|
5160
|
+
expect(fetchOptions.headers['fastly-debug']).to.equal('1');
|
|
5161
|
+
});
|
|
5162
|
+
|
|
5163
|
+
it('should use default probe headers when getScraperConfig is not present on config', async () => {
|
|
5164
|
+
const noScraperSite = {
|
|
5165
|
+
getId: () => 'site-id',
|
|
5166
|
+
getBaseURL: () => 'https://example.com',
|
|
5167
|
+
getConfig: () => ({ getEdgeOptimizeConfig: () => undefined }),
|
|
5168
|
+
getDeliveryType: () => 'aem_edge',
|
|
5169
|
+
};
|
|
5170
|
+
const mockResponse = {
|
|
5171
|
+
status: 200,
|
|
5172
|
+
headers: new Map(),
|
|
5173
|
+
};
|
|
5174
|
+
mockResponse.headers.get = () => null;
|
|
5175
|
+
|
|
5176
|
+
tracingFetchStub.resolves(mockResponse);
|
|
5177
|
+
|
|
5178
|
+
await esmockClient.checkEdgeOptimizeStatus(noScraperSite, '/');
|
|
5179
|
+
|
|
5180
|
+
const fetchOptions = tracingFetchStub.firstCall.args[1];
|
|
5181
|
+
expect(fetchOptions.headers['User-Agent']).to.include('AdobeEdgeOptimize-AI');
|
|
5182
|
+
expect(fetchOptions.headers['fastly-debug']).to.equal('1');
|
|
5183
|
+
});
|
|
5184
|
+
|
|
5185
|
+
it('should use default probe headers when getScraperConfig returns null', async () => {
|
|
5186
|
+
const nullScraperSite = {
|
|
5187
|
+
getId: () => 'site-id',
|
|
5188
|
+
getBaseURL: () => 'https://example.com',
|
|
5189
|
+
getConfig: () => ({
|
|
5190
|
+
getEdgeOptimizeConfig: () => undefined,
|
|
5191
|
+
getScraperConfig: () => null,
|
|
5192
|
+
}),
|
|
5193
|
+
getDeliveryType: () => 'aem_edge',
|
|
5194
|
+
};
|
|
5195
|
+
const mockResponse = { status: 200, headers: new Map() };
|
|
5196
|
+
mockResponse.headers.get = () => null;
|
|
5197
|
+
tracingFetchStub.resolves(mockResponse);
|
|
5198
|
+
|
|
5199
|
+
await esmockClient.checkEdgeOptimizeStatus(nullScraperSite, '/');
|
|
5200
|
+
|
|
5201
|
+
const fetchOptions = tracingFetchStub.firstCall.args[1];
|
|
5202
|
+
expect(fetchOptions.headers['User-Agent']).to.include('Tokowaka-AI');
|
|
5203
|
+
expect(fetchOptions.headers['fastly-debug']).to.equal('1');
|
|
5204
|
+
});
|
|
5205
|
+
|
|
5206
|
+
it('should use default probe headers when getConfig returns null', async () => {
|
|
5207
|
+
const nullConfigSite = {
|
|
5208
|
+
getId: () => 'site-id',
|
|
5209
|
+
getBaseURL: () => 'https://example.com',
|
|
5210
|
+
getConfig: () => null,
|
|
5211
|
+
getDeliveryType: () => 'aem_edge',
|
|
5212
|
+
};
|
|
5213
|
+
const mockResponse = { status: 200, headers: new Map() };
|
|
5214
|
+
mockResponse.headers.get = () => null;
|
|
5215
|
+
tracingFetchStub.resolves(mockResponse);
|
|
5216
|
+
|
|
5217
|
+
await esmockClient.checkEdgeOptimizeStatus(nullConfigSite, '/');
|
|
5218
|
+
|
|
5219
|
+
const fetchOptions = tracingFetchStub.firstCall.args[1];
|
|
5220
|
+
expect(fetchOptions.headers['User-Agent']).to.include('Tokowaka-AI');
|
|
5221
|
+
expect(fetchOptions.headers['fastly-debug']).to.equal('1');
|
|
5222
|
+
});
|
|
5223
|
+
|
|
5224
|
+
it('should use default probe headers when scraperConfig has an empty headers object', async () => {
|
|
5225
|
+
const emptyHeadersSite = {
|
|
5226
|
+
getId: () => 'site-id',
|
|
5227
|
+
getBaseURL: () => 'https://example.com',
|
|
5228
|
+
getConfig: () => ({
|
|
5229
|
+
getEdgeOptimizeConfig: () => undefined,
|
|
5230
|
+
getScraperConfig: () => ({ headers: {} }),
|
|
5231
|
+
}),
|
|
5232
|
+
getDeliveryType: () => 'aem_edge',
|
|
5233
|
+
};
|
|
5234
|
+
const mockResponse = { status: 200, headers: new Map() };
|
|
5235
|
+
mockResponse.headers.get = () => null;
|
|
5236
|
+
tracingFetchStub.resolves(mockResponse);
|
|
5237
|
+
|
|
5238
|
+
await esmockClient.checkEdgeOptimizeStatus(emptyHeadersSite, '/');
|
|
5239
|
+
|
|
5240
|
+
const fetchOptions = tracingFetchStub.firstCall.args[1];
|
|
5241
|
+
expect(fetchOptions.headers['User-Agent']).to.include('Tokowaka-AI');
|
|
5242
|
+
expect(fetchOptions.headers['fastly-debug']).to.equal('1');
|
|
5243
|
+
expect(Object.keys(fetchOptions.headers)).to.have.lengthOf(2);
|
|
5244
|
+
});
|
|
5245
|
+
|
|
5038
5246
|
it('should pass timeout option to tracingFetch', async () => {
|
|
5039
5247
|
const mockResponse = {
|
|
5040
5248
|
status: 200,
|
|
@@ -5168,7 +5376,7 @@ describe('TokowakaClient', () => {
|
|
|
5168
5376
|
await promise;
|
|
5169
5377
|
|
|
5170
5378
|
expect(log.warn).to.have.been.calledWith(
|
|
5171
|
-
sinon.match(
|
|
5379
|
+
sinon.match(/\[edge-optimize-status\] Attempt 1 to fetch failed.*Connection refused.*Retrying in 200ms/),
|
|
5172
5380
|
);
|
|
5173
5381
|
});
|
|
5174
5382
|
|
|
@@ -5182,9 +5390,38 @@ describe('TokowakaClient', () => {
|
|
|
5182
5390
|
expect(result).to.deep.equal({ edgeOptimizeEnabled: false });
|
|
5183
5391
|
expect(tracingFetchStub).to.have.been.calledOnce;
|
|
5184
5392
|
expect(log.warn).to.have.been.calledWith(
|
|
5185
|
-
sinon.match(
|
|
5393
|
+
sinon.match(/\[edge-optimize-status\] Request timed out after 5000ms for https:\/\/example.com\/, returning edgeOptimizeEnabled: false/),
|
|
5186
5394
|
);
|
|
5187
5395
|
});
|
|
5396
|
+
|
|
5397
|
+
it('should send the same custom headers on every retry attempt', async () => {
|
|
5398
|
+
const customSite = {
|
|
5399
|
+
getId: () => 'site-id',
|
|
5400
|
+
getBaseURL: () => 'https://example.com',
|
|
5401
|
+
getConfig: () => ({
|
|
5402
|
+
getEdgeOptimizeConfig: () => undefined,
|
|
5403
|
+
getScraperConfig: () => ({ headers: { 'x-allowlist-token': 'secret123' } }),
|
|
5404
|
+
}),
|
|
5405
|
+
getDeliveryType: () => 'aem_edge',
|
|
5406
|
+
};
|
|
5407
|
+
const mockResponse = { status: 200, headers: new Map() };
|
|
5408
|
+
mockResponse.headers.get = () => null;
|
|
5409
|
+
|
|
5410
|
+
tracingFetchStub.onFirstCall().rejects(new Error('Temporary failure'));
|
|
5411
|
+
tracingFetchStub.onSecondCall().resolves(mockResponse);
|
|
5412
|
+
|
|
5413
|
+
const promise = esmockClient.checkEdgeOptimizeStatus(customSite, '/');
|
|
5414
|
+
await clock.tickAsync(200);
|
|
5415
|
+
await promise;
|
|
5416
|
+
|
|
5417
|
+
expect(tracingFetchStub).to.have.been.calledTwice;
|
|
5418
|
+
const firstCallHeaders = tracingFetchStub.firstCall.args[1].headers;
|
|
5419
|
+
const secondCallHeaders = tracingFetchStub.secondCall.args[1].headers;
|
|
5420
|
+
expect(firstCallHeaders['x-allowlist-token']).to.equal('secret123');
|
|
5421
|
+
expect(secondCallHeaders['x-allowlist-token']).to.equal('secret123');
|
|
5422
|
+
expect(firstCallHeaders['User-Agent']).to.include('Tokowaka-AI');
|
|
5423
|
+
expect(secondCallHeaders['User-Agent']).to.include('Tokowaka-AI');
|
|
5424
|
+
});
|
|
5188
5425
|
});
|
|
5189
5426
|
|
|
5190
5427
|
describe('URL Construction', () => {
|
|
@@ -5721,6 +5958,51 @@ describe('TokowakaClient', () => {
|
|
|
5721
5958
|
expect(result.coveredSuggestions).to.not.include(dw2);
|
|
5722
5959
|
});
|
|
5723
5960
|
|
|
5961
|
+
it('should mark path-level pattern suggestions as coveredByDomainWide when domain-wide is deployed', async () => {
|
|
5962
|
+
const dw = makeSuggestion('dw1', {
|
|
5963
|
+
isDomainWide: true,
|
|
5964
|
+
allowedRegexPatterns: ['^https://example\\.com/.*'],
|
|
5965
|
+
});
|
|
5966
|
+
const pathLevel = makeSuggestion('path1', {
|
|
5967
|
+
allowedRegexPatterns: ['/products/*'],
|
|
5968
|
+
});
|
|
5969
|
+
|
|
5970
|
+
fetchMetaconfigStub.resolves({ siteId: 'site-123' });
|
|
5971
|
+
|
|
5972
|
+
const result = await client.deployToEdge({
|
|
5973
|
+
site: mockSite,
|
|
5974
|
+
opportunity: mockOpportunity,
|
|
5975
|
+
targetSuggestions: [dw],
|
|
5976
|
+
allSuggestions: [dw, pathLevel],
|
|
5977
|
+
});
|
|
5978
|
+
|
|
5979
|
+
expect(result.coveredSuggestions).to.include(pathLevel);
|
|
5980
|
+
expect(pathLevel.getData()).to.have.property('coveredByDomainWide', 'dw1');
|
|
5981
|
+
});
|
|
5982
|
+
|
|
5983
|
+
it('should not mark already-deployed path-level suggestions as coveredByDomainWide', async () => {
|
|
5984
|
+
const dw = makeSuggestion('dw1', {
|
|
5985
|
+
isDomainWide: true,
|
|
5986
|
+
allowedRegexPatterns: ['^https://example\\.com/.*'],
|
|
5987
|
+
});
|
|
5988
|
+
const pathLevel = makeSuggestion('path1', {
|
|
5989
|
+
allowedRegexPatterns: ['/products/*'],
|
|
5990
|
+
edgeDeployed: Date.now(),
|
|
5991
|
+
});
|
|
5992
|
+
|
|
5993
|
+
fetchMetaconfigStub.resolves({ siteId: 'site-123' });
|
|
5994
|
+
|
|
5995
|
+
const result = await client.deployToEdge({
|
|
5996
|
+
site: mockSite,
|
|
5997
|
+
opportunity: mockOpportunity,
|
|
5998
|
+
targetSuggestions: [dw],
|
|
5999
|
+
allSuggestions: [dw, pathLevel],
|
|
6000
|
+
});
|
|
6001
|
+
|
|
6002
|
+
expect(result.coveredSuggestions).to.not.include(pathLevel);
|
|
6003
|
+
expect(pathLevel.getData()).to.not.have.property('coveredByDomainWide');
|
|
6004
|
+
});
|
|
6005
|
+
|
|
5724
6006
|
it('should not mark non-NEW suggestions as covered', async () => {
|
|
5725
6007
|
const dw = makeSuggestion('dw1', {
|
|
5726
6008
|
isDomainWide: true,
|