@adobe/spacecat-shared-tokowaka-client 1.19.0 → 1.20.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 CHANGED
@@ -1,3 +1,15 @@
1
+ ## [@adobe/spacecat-shared-tokowaka-client-v1.20.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-tokowaka-client-v1.19.1...@adobe/spacecat-shared-tokowaka-client-v1.20.0) (2026-06-27)
2
+
3
+ ### Features
4
+
5
+ * **tokowaka-client:** add CloudFront Optimize-at-Edge control-plane ([#1722](https://github.com/adobe/spacecat-shared/issues/1722)) ([e465be0](https://github.com/adobe/spacecat-shared/commit/e465be0a21e61b13db8dd06dacbec7895cb91272))
6
+
7
+ ## [@adobe/spacecat-shared-tokowaka-client-v1.19.1](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-tokowaka-client-v1.19.0...@adobe/spacecat-shared-tokowaka-client-v1.19.1) (2026-06-21)
8
+
9
+ ### Bug Fixes
10
+
11
+ * apply stale config in IVE edge deployment flow ([#1691](https://github.com/adobe/spacecat-shared/issues/1691)) ([9f07a9c](https://github.com/adobe/spacecat-shared/commit/9f07a9ccc73140249aad16e9c9d0d7f5cededf59))
12
+
1
13
  ## [@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
14
 
3
15
  ### Features
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/spacecat-shared-tokowaka-client",
3
- "version": "1.19.0",
3
+ "version": "1.20.0",
4
4
  "description": "Tokowaka Client for SpaceCat - Edge optimization config management",
5
5
  "type": "module",
6
6
  "engines": {
@@ -36,7 +36,10 @@
36
36
  "dependencies": {
37
37
  "@adobe/spacecat-shared-utils": "1.81.1",
38
38
  "@aws-sdk/client-cloudfront": "3.1057.0",
39
+ "@aws-sdk/client-iam": "3.1057.0",
40
+ "@aws-sdk/client-lambda": "3.1057.0",
39
41
  "@aws-sdk/client-s3": "3.1057.0",
42
+ "@aws-sdk/client-sts": "3.1057.0",
40
43
  "hast-util-from-html": "2.0.3",
41
44
  "mdast-util-from-markdown": "2.0.3",
42
45
  "mdast-util-to-hast": "13.2.1",
@@ -0,0 +1,152 @@
1
+ /*
2
+ * Copyright 2026 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ /**
14
+ * Edge runtime code for the CloudFront "Optimize at Edge" onboarding, kept out of the
15
+ * orchestrator (index.js) so it stays readable. Both exports are plain JS-module
16
+ * strings (not sibling-file reads) so the helix-deploy bundle preserves them — see CLAUDE.md
17
+ * "Lambda Bundle Constraints".
18
+ */
19
+
20
+ /**
21
+ * Build the CloudFront Function (viewer-request) routing code. Ported verbatim from the standalone
22
+ * wizard's `buildFunctionCode` (server.mjs). It detects agentic bots on HTML pages and, for them,
23
+ * creates a request origin group that fails over from the Edge Optimize origin to the default
24
+ * origin.
25
+ *
26
+ * @param {string} defaultOriginId - the distribution's default-behavior target origin id.
27
+ * @param {string[]|null} [targetedPaths] - explicit paths to target, or null for "all HTML pages".
28
+ * @returns {string} the CloudFront Function source code.
29
+ */
30
+ export function buildCloudfrontFunctionCode(defaultOriginId, targetedPaths = null) {
31
+ const targetedPathsValue = targetedPaths === null ? 'null' : JSON.stringify(targetedPaths);
32
+ const defaultOriginIdValue = JSON.stringify(defaultOriginId);
33
+
34
+ return `import cf from 'cloudfront';
35
+
36
+ function handler(event) {
37
+ var request = event.request;
38
+ var headers = request.headers;
39
+
40
+ delete headers['x-edgeoptimize-api-key'];
41
+ delete headers['x-edgeoptimize-url'];
42
+ delete headers['x-edgeoptimize-config'];
43
+
44
+ var AGENTIC_BOTS = ['AdobeEdgeOptimize-AI', 'ChatGPT-User', 'GPTBot', 'OAI-SearchBot', 'PerplexityBot', 'Perplexity-User', 'ClaudeBot', 'Claude-User', 'Claude-SearchBot'];
45
+ var TARGETED_PATHS = ${targetedPathsValue};
46
+
47
+ var userAgent = headers['user-agent'] ? headers['user-agent'].value.toLowerCase() : '';
48
+ var isEdgeOptimizeRequest = headers['x-edgeoptimize-request'];
49
+
50
+ var path = request.uri;
51
+ var pattern = /(?:\\/[^./]+|\\.html|\\/)$/;
52
+ var isHtmlPage = pattern.test(path);
53
+
54
+ var isTargetedPath = TARGETED_PATHS === null
55
+ ? isHtmlPage
56
+ : isHtmlPage && TARGETED_PATHS.includes(path);
57
+
58
+ var isAgenticBot = AGENTIC_BOTS.some(function(bot) {
59
+ return userAgent.includes(bot.toLowerCase());
60
+ });
61
+
62
+ if (!isEdgeOptimizeRequest && isAgenticBot && isTargetedPath) {
63
+ request.headers['x-edgeoptimize-url'] = { value: request.uri };
64
+ request.headers['x-edgeoptimize-config'] = { value: "LLMCLIENT=true" };
65
+
66
+ console.log("Adding origin group for userAgent: " + userAgent);
67
+
68
+ cf.createRequestOriginGroup({
69
+ "originIds": [
70
+ { "originId": "EdgeOptimize_Origin" },
71
+ { "originId": ${defaultOriginIdValue} }
72
+ ],
73
+ "failoverCriteria": {
74
+ "statusCodes": [400, 403, 404, 416, 500, 502, 503, 504]
75
+ }
76
+ });
77
+
78
+ console.log("Routing to Edge Optimize origin for userAgent: " + userAgent);
79
+ return request;
80
+ }
81
+
82
+ console.log("Routing to Default origin for userAgent: " + userAgent);
83
+ return request;
84
+ }`;
85
+ }
86
+
87
+ /**
88
+ * Build the Lambda@Edge origin-request/response handler. Ported from the standalone wizard's
89
+ * templates/origin-request-response.js. Returned as an inline JS module string (not a sibling-file
90
+ * read) so the helix-deploy bundle preserves it — see CLAUDE.md "Lambda Bundle Constraints".
91
+ *
92
+ * The Edge Optimize origin domain is injected so the same handler works per environment
93
+ * (e.g. dev.edgeoptimize.net on dev, live.edgeoptimize.net on prod): the origin-request branch
94
+ * routes to the EO origin only when CloudFront's current origin matches this domain — otherwise it
95
+ * marks the request as a failover. It MUST be the same value used as the EO origin's DomainName.
96
+ *
97
+ * @param {string} eoOriginDomain - the Edge Optimize origin domain baked into the routing check.
98
+ * @returns {string} the Lambda@Edge function source code.
99
+ */
100
+ export function buildEdgeOptimizeLambdaCode(eoOriginDomain) {
101
+ const eoOriginDomainValue = JSON.stringify(eoOriginDomain);
102
+
103
+ return `function hasHeader(map, name) {
104
+ const h = map?.[name];
105
+ return Array.isArray(h) && h.length > 0 && (h[0].value || '').trim() !== '';
106
+ }
107
+
108
+ function setHeader(map, name, value) {
109
+ if (map) {
110
+ map[name.toLowerCase()] = [{ key: name, value: String(value) }];
111
+ }
112
+ }
113
+
114
+ export const handler = async (event) => {
115
+ const request = event?.Records?.[0]?.cf?.request;
116
+ const response = event?.Records?.[0]?.cf?.response;
117
+ const eventType = event.Records[0].cf.config.eventType;
118
+ const reqHeaders = request.headers || {};
119
+
120
+ if (eventType === 'origin-request') {
121
+ const originDomain = request.origin?.custom?.domainName;
122
+ const isEdgeOptimizeConfig = hasHeader(reqHeaders, 'x-edgeoptimize-config');
123
+ const isEdgeOptimizeRequest = hasHeader(reqHeaders, 'x-edgeoptimize-request');
124
+
125
+ if (isEdgeOptimizeConfig && !isEdgeOptimizeRequest) {
126
+ if (originDomain === ${eoOriginDomainValue}) {
127
+ console.log("Calling Edge Optimize Origin for agentic requests");
128
+ setHeader(request.headers, 'host', originDomain);
129
+ } else {
130
+ console.log("Calling Default Origin in case of failover for agentic requests");
131
+ setHeader(request.headers, 'x-edgeoptimize-request', 'fo');
132
+ }
133
+ }
134
+
135
+ return request;
136
+
137
+ } else if (eventType === 'origin-response') {
138
+ const resHeaders = response.headers || {};
139
+ const isEdgeOptimizeConfig = hasHeader(reqHeaders, 'x-edgeoptimize-config');
140
+ const isEdgeOptimizeRequestId = hasHeader(resHeaders, 'x-edgeoptimize-request-id');
141
+
142
+ if (isEdgeOptimizeConfig && !isEdgeOptimizeRequestId) {
143
+ setHeader(response.headers, 'x-edgeoptimize-fo', '1');
144
+ setHeader(response.headers, 'cache-control', 'no-store');
145
+ console.log('Failover Triggered for agentic requests');
146
+ }
147
+
148
+ return response;
149
+ }
150
+ };
151
+ `;
152
+ }