@sitecore-jss/sitecore-jss 0.1.0-beta.2
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/LICENSE.txt +202 -0
- package/README.md +7 -0
- package/dist/cjs/cache-client.js +54 -0
- package/dist/cjs/constants.js +12 -0
- package/dist/cjs/debug.js +43 -0
- package/dist/cjs/graphql/app-root-query.js +73 -0
- package/dist/cjs/graphql/graphql-edge-proxy.js +12 -0
- package/dist/cjs/graphql/index.js +11 -0
- package/dist/cjs/graphql/search-service.js +60 -0
- package/dist/cjs/graphql-request-client.js +106 -0
- package/dist/cjs/i18n/dictionary-service.js +45 -0
- package/dist/cjs/i18n/graphql-dictionary-service.js +125 -0
- package/dist/cjs/i18n/index.js +7 -0
- package/dist/cjs/index.js +36 -0
- package/dist/cjs/layout/content-styles.js +73 -0
- package/dist/cjs/layout/graphql-layout-service.js +84 -0
- package/dist/cjs/layout/index.js +18 -0
- package/dist/cjs/layout/layout-service.js +9 -0
- package/dist/cjs/layout/models.js +27 -0
- package/dist/cjs/layout/themes.js +79 -0
- package/dist/cjs/layout/utils.js +44 -0
- package/dist/cjs/media/index.js +24 -0
- package/dist/cjs/media/media-api.js +128 -0
- package/dist/cjs/models.js +2 -0
- package/dist/cjs/native-fetcher.js +183 -0
- package/dist/cjs/personalize/graphql-personalize-service.js +114 -0
- package/dist/cjs/personalize/index.js +12 -0
- package/dist/cjs/personalize/layout-personalizer.js +75 -0
- package/dist/cjs/personalize/utils.js +92 -0
- package/dist/cjs/site/graphql-error-pages-service.js +86 -0
- package/dist/cjs/site/graphql-redirects-service.js +103 -0
- package/dist/cjs/site/graphql-robots-service.js +81 -0
- package/dist/cjs/site/graphql-siteinfo-service.js +128 -0
- package/dist/cjs/site/graphql-sitemap-service.js +91 -0
- package/dist/cjs/site/index.js +22 -0
- package/dist/cjs/site/site-resolver.js +79 -0
- package/dist/cjs/site/utils.js +43 -0
- package/dist/cjs/utils/edit-frame.js +138 -0
- package/dist/cjs/utils/editing.js +122 -0
- package/dist/cjs/utils/env.js +26 -0
- package/dist/cjs/utils/index.js +25 -0
- package/dist/cjs/utils/is-server.js +10 -0
- package/dist/cjs/utils/timeout-promise.js +31 -0
- package/dist/cjs/utils/utils.js +70 -0
- package/dist/esm/cache-client.js +50 -0
- package/dist/esm/constants.js +9 -0
- package/dist/esm/debug.js +36 -0
- package/dist/esm/graphql/app-root-query.js +69 -0
- package/dist/esm/graphql/graphql-edge-proxy.js +8 -0
- package/dist/esm/graphql/index.js +4 -0
- package/dist/esm/graphql/search-service.js +56 -0
- package/dist/esm/graphql-request-client.js +99 -0
- package/dist/esm/i18n/dictionary-service.js +41 -0
- package/dist/esm/i18n/graphql-dictionary-service.js +118 -0
- package/dist/esm/i18n/index.js +2 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/layout/content-styles.js +65 -0
- package/dist/esm/layout/graphql-layout-service.js +77 -0
- package/dist/esm/layout/index.js +6 -0
- package/dist/esm/layout/layout-service.js +5 -0
- package/dist/esm/layout/models.js +24 -0
- package/dist/esm/layout/themes.js +74 -0
- package/dist/esm/layout/utils.js +39 -0
- package/dist/esm/media/index.js +2 -0
- package/dist/esm/media/media-api.js +117 -0
- package/dist/esm/models.js +1 -0
- package/dist/esm/native-fetcher.js +176 -0
- package/dist/esm/personalize/graphql-personalize-service.js +107 -0
- package/dist/esm/personalize/index.js +3 -0
- package/dist/esm/personalize/layout-personalizer.js +69 -0
- package/dist/esm/personalize/utils.js +85 -0
- package/dist/esm/site/graphql-error-pages-service.js +79 -0
- package/dist/esm/site/graphql-redirects-service.js +96 -0
- package/dist/esm/site/graphql-robots-service.js +74 -0
- package/dist/esm/site/graphql-siteinfo-service.js +121 -0
- package/dist/esm/site/graphql-sitemap-service.js +84 -0
- package/dist/esm/site/index.js +7 -0
- package/dist/esm/site/site-resolver.js +75 -0
- package/dist/esm/site/utils.js +37 -0
- package/dist/esm/utils/edit-frame.js +133 -0
- package/dist/esm/utils/editing.js +111 -0
- package/dist/esm/utils/env.js +22 -0
- package/dist/esm/utils/index.js +5 -0
- package/dist/esm/utils/is-server.js +8 -0
- package/dist/esm/utils/timeout-promise.js +28 -0
- package/dist/esm/utils/utils.js +61 -0
- package/graphql.d.ts +1 -0
- package/graphql.js +1 -0
- package/i18n.d.ts +1 -0
- package/i18n.js +1 -0
- package/layout.d.ts +1 -0
- package/layout.js +1 -0
- package/media.d.ts +1 -0
- package/media.js +1 -0
- package/package.json +71 -0
- package/personalize.d.ts +1 -0
- package/personalize.js +1 -0
- package/site.d.ts +1 -0
- package/site.js +1 -0
- package/types/cache-client.d.ts +64 -0
- package/types/constants.d.ts +6 -0
- package/types/debug.d.ts +26 -0
- package/types/graphql/app-root-query.d.ts +32 -0
- package/types/graphql/graphql-edge-proxy.d.ts +7 -0
- package/types/graphql/index.d.ts +4 -0
- package/types/graphql/search-service.d.ts +92 -0
- package/types/graphql-request-client.d.ts +88 -0
- package/types/i18n/dictionary-service.d.ts +56 -0
- package/types/i18n/graphql-dictionary-service.d.ts +65 -0
- package/types/i18n/index.d.ts +2 -0
- package/types/index.d.ts +6 -0
- package/types/layout/content-styles.d.ts +18 -0
- package/types/layout/graphql-layout-service.d.ts +59 -0
- package/types/layout/index.d.ts +6 -0
- package/types/layout/layout-service.d.ts +20 -0
- package/types/layout/models.d.ts +140 -0
- package/types/layout/themes.d.ts +11 -0
- package/types/layout/utils.d.ts +17 -0
- package/types/media/index.d.ts +2 -0
- package/types/media/media-api.d.ts +69 -0
- package/types/models.d.ts +6 -0
- package/types/native-fetcher.d.ts +92 -0
- package/types/personalize/graphql-personalize-service.d.ts +77 -0
- package/types/personalize/index.d.ts +3 -0
- package/types/personalize/layout-personalizer.d.ts +25 -0
- package/types/personalize/utils.d.ts +53 -0
- package/types/site/graphql-error-pages-service.d.ts +55 -0
- package/types/site/graphql-redirects-service.d.ts +66 -0
- package/types/site/graphql-robots-service.d.ts +47 -0
- package/types/site/graphql-siteinfo-service.d.ts +69 -0
- package/types/site/graphql-sitemap-service.d.ts +53 -0
- package/types/site/index.d.ts +7 -0
- package/types/site/site-resolver.d.ts +27 -0
- package/types/site/utils.d.ts +24 -0
- package/types/utils/edit-frame.d.ts +76 -0
- package/types/utils/editing.d.ts +58 -0
- package/types/utils/env.d.ts +7 -0
- package/types/utils/index.d.ts +5 -0
- package/types/utils/is-server.d.ts +6 -0
- package/types/utils/timeout-promise.d.ts +18 -0
- package/types/utils/utils.d.ts +18 -0
- package/utils.d.ts +1 -0
- package/utils.js +1 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.handleEditorAnchors = exports.resetEditorChromes = exports.isEditorActive = exports.HorizonEditor = exports.ChromeRediscoveryGlobalFunctionName = exports.ExperienceEditor = void 0;
|
|
7
|
+
const is_server_1 = __importDefault(require("./is-server"));
|
|
8
|
+
/**
|
|
9
|
+
* Static utility class for Sitecore Experience Editor
|
|
10
|
+
*/
|
|
11
|
+
class ExperienceEditor {
|
|
12
|
+
/**
|
|
13
|
+
* Determines whether the current execution context is within a Experience Editor.
|
|
14
|
+
* Experience Editor environment can be identified only in the browser
|
|
15
|
+
* @returns true if executing within a Experience Editor
|
|
16
|
+
*/
|
|
17
|
+
static isActive() {
|
|
18
|
+
if (is_server_1.default()) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
// eslint-disable-next-line
|
|
22
|
+
const sc = window.Sitecore;
|
|
23
|
+
return Boolean(sc && sc.PageModes && sc.PageModes.ChromeManager);
|
|
24
|
+
}
|
|
25
|
+
static resetChromes() {
|
|
26
|
+
if (is_server_1.default()) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
window.Sitecore.PageModes.ChromeManager.resetChromes();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.ExperienceEditor = ExperienceEditor;
|
|
33
|
+
/**
|
|
34
|
+
* Copy of chrome rediscovery contract from Horizon (chrome-rediscovery.contract.ts)
|
|
35
|
+
*/
|
|
36
|
+
exports.ChromeRediscoveryGlobalFunctionName = {
|
|
37
|
+
name: 'Sitecore.Horizon.ResetChromes',
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Static utility class for Sitecore Horizon Editor
|
|
41
|
+
*/
|
|
42
|
+
class HorizonEditor {
|
|
43
|
+
/**
|
|
44
|
+
* Determines whether the current execution context is within a Horizon Editor.
|
|
45
|
+
* Horizon Editor environment can be identified only in the browser
|
|
46
|
+
* @returns true if executing within a Horizon Editor
|
|
47
|
+
*/
|
|
48
|
+
static isActive() {
|
|
49
|
+
if (is_server_1.default()) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
// Horizon will add "sc_horizon=editor" query string parameter for the editor and "sc_horizon=simulator" for the preview
|
|
53
|
+
return window.location.search.indexOf('sc_horizon=editor') > -1;
|
|
54
|
+
}
|
|
55
|
+
static resetChromes() {
|
|
56
|
+
if (is_server_1.default()) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
// Reset chromes in Horizon
|
|
60
|
+
window[exports.ChromeRediscoveryGlobalFunctionName.name] &&
|
|
61
|
+
window[exports.ChromeRediscoveryGlobalFunctionName.name]();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
exports.HorizonEditor = HorizonEditor;
|
|
65
|
+
/**
|
|
66
|
+
* Determines whether the current execution context is within a Sitecore editor.
|
|
67
|
+
* Sitecore Editor environment can be identified only in the browser
|
|
68
|
+
* @returns true if executing within a Sitecore editor
|
|
69
|
+
*/
|
|
70
|
+
const isEditorActive = () => {
|
|
71
|
+
return ExperienceEditor.isActive() || HorizonEditor.isActive();
|
|
72
|
+
};
|
|
73
|
+
exports.isEditorActive = isEditorActive;
|
|
74
|
+
/**
|
|
75
|
+
* Resets Sitecore editor "chromes"
|
|
76
|
+
*/
|
|
77
|
+
const resetEditorChromes = () => {
|
|
78
|
+
if (ExperienceEditor.isActive()) {
|
|
79
|
+
ExperienceEditor.resetChromes();
|
|
80
|
+
}
|
|
81
|
+
else if (HorizonEditor.isActive()) {
|
|
82
|
+
HorizonEditor.resetChromes();
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
exports.resetEditorChromes = resetEditorChromes;
|
|
86
|
+
/**
|
|
87
|
+
* @description in Experience Editor, anchor tags
|
|
88
|
+
* with both onclick and href attributes will use the href, blocking the onclick from firing.
|
|
89
|
+
* This function makes it so the anchor tags function as intended in the sample when using Experience Editor
|
|
90
|
+
*
|
|
91
|
+
* The Mutation Observer API is used to observe changes to the body, then select all elements with href="#" and an onclick,
|
|
92
|
+
* and replaces the # value with javascript:void(0); which prevents the anchor tag from blocking the onclick event handler.
|
|
93
|
+
* @see Mutation Observer API: https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver/MutationObserver
|
|
94
|
+
*/
|
|
95
|
+
const handleEditorAnchors = () => {
|
|
96
|
+
// The sample gives the href attribute priority over the onclick attribute if both are present, so we must replace
|
|
97
|
+
// the href attribute to avoid overriding the onclick in Experience Editor
|
|
98
|
+
if (!window || !ExperienceEditor.isActive()) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const targetNode = document.querySelector('body');
|
|
102
|
+
const callback = (mutationList) => {
|
|
103
|
+
mutationList.forEach((mutation) => {
|
|
104
|
+
const btns = document.querySelectorAll('.scChromeDropDown > a[href="#"], .scChromeDropDown > a[href="#!"], a[onclick]');
|
|
105
|
+
if (mutation.type === 'childList') {
|
|
106
|
+
btns.forEach((link) => {
|
|
107
|
+
link.href = 'javascript:void(0);';
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return;
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
const observer = new MutationObserver(callback);
|
|
114
|
+
const observerOptions = {
|
|
115
|
+
childList: true,
|
|
116
|
+
subtree: true,
|
|
117
|
+
};
|
|
118
|
+
if (targetNode) {
|
|
119
|
+
observer.observe(targetNode, observerOptions);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
exports.handleEditorAnchors = handleEditorAnchors;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.tryParseEnvValue = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Method to parse JSON-formatted environment variables
|
|
6
|
+
* @param {string} envValue - can be undefined when providing values via process.env
|
|
7
|
+
* @param {T} defaultValue - default value
|
|
8
|
+
* @returns {T | string} parsed value
|
|
9
|
+
*/
|
|
10
|
+
const tryParseEnvValue = (envValue, defaultValue) => {
|
|
11
|
+
if (!envValue) {
|
|
12
|
+
return defaultValue;
|
|
13
|
+
}
|
|
14
|
+
if (envValue.startsWith('{') && envValue.endsWith('}')) {
|
|
15
|
+
try {
|
|
16
|
+
return JSON.parse(envValue);
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
console.warn('Parsing of env variable failed');
|
|
20
|
+
console.warn(`Attempted to parse ${envValue}`);
|
|
21
|
+
return defaultValue;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return defaultValue;
|
|
25
|
+
};
|
|
26
|
+
exports.tryParseEnvValue = tryParseEnvValue;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.mapButtonToCommand = exports.DefaultEditFrameButtonIds = exports.DefaultEditFrameButtons = exports.DefaultEditFrameButton = exports.handleEditorAnchors = exports.resetEditorChromes = exports.isEditorActive = exports.HorizonEditor = exports.ExperienceEditor = exports.tryParseEnvValue = exports.isTimeoutError = exports.isAbsoluteUrl = exports.resolveUrl = exports.isServer = void 0;
|
|
7
|
+
var is_server_1 = require("./is-server");
|
|
8
|
+
Object.defineProperty(exports, "isServer", { enumerable: true, get: function () { return __importDefault(is_server_1).default; } });
|
|
9
|
+
var utils_1 = require("./utils");
|
|
10
|
+
Object.defineProperty(exports, "resolveUrl", { enumerable: true, get: function () { return utils_1.resolveUrl; } });
|
|
11
|
+
Object.defineProperty(exports, "isAbsoluteUrl", { enumerable: true, get: function () { return utils_1.isAbsoluteUrl; } });
|
|
12
|
+
Object.defineProperty(exports, "isTimeoutError", { enumerable: true, get: function () { return utils_1.isTimeoutError; } });
|
|
13
|
+
var env_1 = require("./env");
|
|
14
|
+
Object.defineProperty(exports, "tryParseEnvValue", { enumerable: true, get: function () { return env_1.tryParseEnvValue; } });
|
|
15
|
+
var editing_1 = require("./editing");
|
|
16
|
+
Object.defineProperty(exports, "ExperienceEditor", { enumerable: true, get: function () { return editing_1.ExperienceEditor; } });
|
|
17
|
+
Object.defineProperty(exports, "HorizonEditor", { enumerable: true, get: function () { return editing_1.HorizonEditor; } });
|
|
18
|
+
Object.defineProperty(exports, "isEditorActive", { enumerable: true, get: function () { return editing_1.isEditorActive; } });
|
|
19
|
+
Object.defineProperty(exports, "resetEditorChromes", { enumerable: true, get: function () { return editing_1.resetEditorChromes; } });
|
|
20
|
+
Object.defineProperty(exports, "handleEditorAnchors", { enumerable: true, get: function () { return editing_1.handleEditorAnchors; } });
|
|
21
|
+
var edit_frame_1 = require("./edit-frame");
|
|
22
|
+
Object.defineProperty(exports, "DefaultEditFrameButton", { enumerable: true, get: function () { return edit_frame_1.DefaultEditFrameButton; } });
|
|
23
|
+
Object.defineProperty(exports, "DefaultEditFrameButtons", { enumerable: true, get: function () { return edit_frame_1.DefaultEditFrameButtons; } });
|
|
24
|
+
Object.defineProperty(exports, "DefaultEditFrameButtonIds", { enumerable: true, get: function () { return edit_frame_1.DefaultEditFrameButtonIds; } });
|
|
25
|
+
Object.defineProperty(exports, "mapButtonToCommand", { enumerable: true, get: function () { return edit_frame_1.mapButtonToCommand; } });
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* Determines whether the current execution context is server-side
|
|
5
|
+
* @returns true if executing server-side
|
|
6
|
+
*/
|
|
7
|
+
function isServer() {
|
|
8
|
+
return !(typeof window !== 'undefined' && window.document);
|
|
9
|
+
}
|
|
10
|
+
exports.default = isServer;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* A helper to assign timeouts to fetch or other promises
|
|
5
|
+
* Useful in nextjs middleware until fetch.signal is fully supported by Vercel edge functions
|
|
6
|
+
*/
|
|
7
|
+
class TimeoutPromise {
|
|
8
|
+
constructor(timeout) {
|
|
9
|
+
this.timeout = timeout;
|
|
10
|
+
this.timeoutId = undefined;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Creates a timeout promise
|
|
14
|
+
*/
|
|
15
|
+
get start() {
|
|
16
|
+
return new Promise((_, reject) => {
|
|
17
|
+
this.timeoutId = setTimeout(() => {
|
|
18
|
+
const abortError = new Error(`Request timed out, timeout of ${this.timeout}ms is exceeded`);
|
|
19
|
+
abortError.name = 'AbortError';
|
|
20
|
+
reject(abortError);
|
|
21
|
+
}, this.timeout);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Clears the timeout from timeout promise
|
|
26
|
+
*/
|
|
27
|
+
clear() {
|
|
28
|
+
this.timeoutId && clearTimeout(this.timeoutId);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.default = TimeoutPromise;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.isTimeoutError = exports.isAbsoluteUrl = exports.resolveUrl = void 0;
|
|
7
|
+
const is_server_1 = __importDefault(require("./is-server"));
|
|
8
|
+
/**
|
|
9
|
+
* note: encodeURIComponent is available via browser (window) or natively in node.js
|
|
10
|
+
* if you use another js engine for server-side rendering you may not have native encodeURIComponent
|
|
11
|
+
* and would then need to install a package for that functionality
|
|
12
|
+
* @param {ParsedUrlQueryInput} params query string parameters
|
|
13
|
+
* @returns {string} query string
|
|
14
|
+
*/
|
|
15
|
+
function getQueryString(params) {
|
|
16
|
+
return Object.keys(params)
|
|
17
|
+
.map((k) => `${encodeURIComponent(k)}=${encodeURIComponent(String(params[k]))}`)
|
|
18
|
+
.join('&');
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Resolves a base URL that may contain query string parameters and an additional set of query
|
|
22
|
+
* string parameters into a unified string representation.
|
|
23
|
+
* @param {string} urlBase the base URL that may contain query string parameters
|
|
24
|
+
* @param {ParsedUrlQueryInput} params query string parameters
|
|
25
|
+
* @returns a URL string
|
|
26
|
+
* @throws {RangeError} if the provided url is an empty string
|
|
27
|
+
*/
|
|
28
|
+
function resolveUrl(urlBase, params = {}) {
|
|
29
|
+
if (!urlBase) {
|
|
30
|
+
throw new RangeError('url must be a non-empty string');
|
|
31
|
+
}
|
|
32
|
+
// This is a better way to work with URLs since it handles different user input
|
|
33
|
+
// edge cases. This works in Node and all browser except IE11.
|
|
34
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/URL
|
|
35
|
+
// TODO: Verify our browser support requirements.
|
|
36
|
+
if (is_server_1.default()) {
|
|
37
|
+
const url = new URL(urlBase);
|
|
38
|
+
for (const key in params) {
|
|
39
|
+
if ({}.hasOwnProperty.call(params, key)) {
|
|
40
|
+
url.searchParams.append(key, String(params[key]));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const result = url.toString();
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
const qs = getQueryString(params);
|
|
47
|
+
const result = urlBase.indexOf('?') !== -1 ? `${urlBase}&${qs}` : `${urlBase}?${qs}`;
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
exports.resolveUrl = resolveUrl;
|
|
51
|
+
const isAbsoluteUrl = (url) => {
|
|
52
|
+
if (!url) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
if (typeof url !== 'string') {
|
|
56
|
+
throw new TypeError('Expected a string');
|
|
57
|
+
}
|
|
58
|
+
return /^[a-z][a-z0-9+.-]*:/.test(url);
|
|
59
|
+
};
|
|
60
|
+
exports.isAbsoluteUrl = isAbsoluteUrl;
|
|
61
|
+
/**
|
|
62
|
+
* Indicates whether the error is a timeout error
|
|
63
|
+
* @param {unknown} error error
|
|
64
|
+
* @returns {boolean} is timeout error
|
|
65
|
+
*/
|
|
66
|
+
const isTimeoutError = (error) => {
|
|
67
|
+
var _a;
|
|
68
|
+
return ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 408 || error.name === 'AbortError';
|
|
69
|
+
};
|
|
70
|
+
exports.isTimeoutError = isTimeoutError;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Cache } from 'memory-cache';
|
|
2
|
+
/**
|
|
3
|
+
* Default cache configuration
|
|
4
|
+
*/
|
|
5
|
+
const DEFAULTS = Object.freeze({
|
|
6
|
+
cacheTimeout: 60,
|
|
7
|
+
cacheEnabled: true,
|
|
8
|
+
});
|
|
9
|
+
/**
|
|
10
|
+
* A cache client that uses the 'memory-cache' library (https://github.com/ptarjan/node-cache).
|
|
11
|
+
* This class is meant to be extended or used as a mixin; it's not meant to be used directly.
|
|
12
|
+
* @template T The type of data being cached.
|
|
13
|
+
* @mixin
|
|
14
|
+
*/
|
|
15
|
+
export class MemoryCacheClient {
|
|
16
|
+
/**
|
|
17
|
+
* Initializes a new instance of @see MemoryCacheClient using the provided @see CacheOptions
|
|
18
|
+
* @param {CacheOptions} options Configuration options
|
|
19
|
+
*/
|
|
20
|
+
constructor(options) {
|
|
21
|
+
var _a;
|
|
22
|
+
this.options = options;
|
|
23
|
+
this.cache = new Cache();
|
|
24
|
+
this.options.cacheTimeout = ((_a = this.options.cacheTimeout) !== null && _a !== void 0 ? _a : DEFAULTS.cacheTimeout) * 1000;
|
|
25
|
+
if (this.options.cacheEnabled === undefined) {
|
|
26
|
+
this.options.cacheEnabled = DEFAULTS.cacheEnabled;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Retrieves a value from the cache.
|
|
31
|
+
* @template T The type of data being cached.
|
|
32
|
+
* @param {string} key The cache key.
|
|
33
|
+
* @returns The cache value as {T}, or null if the specified key is not found in the cache.
|
|
34
|
+
*/
|
|
35
|
+
getCacheValue(key) {
|
|
36
|
+
return this.options.cacheEnabled ? this.cache.get(key) : null;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Adds a value to the cache for the specified cache key.
|
|
40
|
+
* @template T The type of data being cached.
|
|
41
|
+
* @param {string} key The cache key.
|
|
42
|
+
* @param {T} value The value to cache.
|
|
43
|
+
* @returns The value added to the cache.
|
|
44
|
+
*/
|
|
45
|
+
setCacheValue(key, value) {
|
|
46
|
+
return this.options.cacheEnabled
|
|
47
|
+
? this.cache.put(key, value, this.options.cacheTimeout)
|
|
48
|
+
: value;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export var SitecoreTemplateId;
|
|
2
|
+
(function (SitecoreTemplateId) {
|
|
3
|
+
// /sitecore/templates/Foundation/JavaScript Services/App
|
|
4
|
+
SitecoreTemplateId["JssApp"] = "061cba1554744b918a0617903b102b82";
|
|
5
|
+
// /sitecore/templates/System/Dictionary/Dictionary entry
|
|
6
|
+
SitecoreTemplateId["DictionaryEntry"] = "6d1cd89719364a3aa511289a94c2a7b1";
|
|
7
|
+
})(SitecoreTemplateId || (SitecoreTemplateId = {}));
|
|
8
|
+
export const siteNameError = 'The siteName cannot be empty';
|
|
9
|
+
export const SITECORE_EDGE_URL_DEFAULT = 'https://edge-platform.sitecorecloud.io';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
var _a;
|
|
2
|
+
import debug from 'debug';
|
|
3
|
+
import isServer from './utils/is-server';
|
|
4
|
+
const rootNamespace = 'sitecore-jss';
|
|
5
|
+
// On server/node side, allow switching from the built-in
|
|
6
|
+
// `%o` (pretty-print single line) and `%O` (pretty-print multiple line)
|
|
7
|
+
// with a `DEBUG_MULTILINE` environment variable.
|
|
8
|
+
if (isServer() &&
|
|
9
|
+
((_a = process === null || process === void 0 ? void 0 : process.env) === null || _a === void 0 ? void 0 : _a.DEBUG_MULTILINE) === 'true' &&
|
|
10
|
+
debug.formatters.o &&
|
|
11
|
+
debug.formatters.O) {
|
|
12
|
+
debug.formatters.o = debug.formatters.O;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Enable debug logging dynamically
|
|
16
|
+
* @param {string} namespaces space-separated list of namespaces to enable
|
|
17
|
+
*/
|
|
18
|
+
export const enableDebug = (namespaces) => debug.enable(namespaces);
|
|
19
|
+
/**
|
|
20
|
+
* Default Sitecore JSS 'debug' module debuggers. Uses namespace prefix 'sitecore-jss:'.
|
|
21
|
+
* See {@link https://www.npmjs.com/package/debug} for details.
|
|
22
|
+
*/
|
|
23
|
+
export default {
|
|
24
|
+
common: debug(`${rootNamespace}:common`),
|
|
25
|
+
http: debug(`${rootNamespace}:http`),
|
|
26
|
+
layout: debug(`${rootNamespace}:layout`),
|
|
27
|
+
dictionary: debug(`${rootNamespace}:dictionary`),
|
|
28
|
+
editing: debug(`${rootNamespace}:editing`),
|
|
29
|
+
sitemap: debug(`${rootNamespace}:sitemap`),
|
|
30
|
+
multisite: debug(`${rootNamespace}:multisite`),
|
|
31
|
+
robots: debug(`${rootNamespace}:robots`),
|
|
32
|
+
redirects: debug(`${rootNamespace}:redirects`),
|
|
33
|
+
personalize: debug(`${rootNamespace}:personalize`),
|
|
34
|
+
errorpages: debug(`${rootNamespace}:errorpages`),
|
|
35
|
+
revalidate: debug(`${rootNamespace}:revalidate`),
|
|
36
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { SitecoreTemplateId } from '../constants';
|
|
11
|
+
/** @private */
|
|
12
|
+
export const siteNameError = 'The site name must be a non-empty string';
|
|
13
|
+
/** @private */
|
|
14
|
+
export const languageError = 'The language must be a non-empty string';
|
|
15
|
+
/*
|
|
16
|
+
* GraphQL query that returns the ID of the root item of the specified site and language
|
|
17
|
+
*/
|
|
18
|
+
const appRootQuery = /* GraphQL */ `
|
|
19
|
+
query AppRootQuery($jssAppTemplateId: String!, $siteName: String!, $language: String!) {
|
|
20
|
+
layout(site: $siteName, routePath: "/", language: $language) {
|
|
21
|
+
homePage: item {
|
|
22
|
+
rootItem: ancestors(includeTemplateIDs: [$jssAppTemplateId]) {
|
|
23
|
+
id
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
`;
|
|
29
|
+
/**
|
|
30
|
+
* Gets the ID of the JSS App root item for the specified site and language.
|
|
31
|
+
* @param {GraphQLClient} client that fetches data from a GraphQL endpoint.
|
|
32
|
+
* @param {string} siteName the name of the Sitecore site.
|
|
33
|
+
* @param {string} language the item language version.
|
|
34
|
+
* @param {string} [jssAppTemplateId] optional template ID of the app root item. If not
|
|
35
|
+
* specified, the ID of the "/sitecore/templates/Foundation/JavaScript Services/App"
|
|
36
|
+
* item is used.
|
|
37
|
+
* @returns the root item ID of the JSS App in Sitecore. Returns null if the app root item is not found.
|
|
38
|
+
* @throws {RangeError} if a valid site name value is not provided.
|
|
39
|
+
* @throws {RangeError} if a valid language value is not provided.
|
|
40
|
+
* @summary This function intentionally avoids throwing an error if a root item is not found,
|
|
41
|
+
* leaving that decision up to implementations.
|
|
42
|
+
*/
|
|
43
|
+
export function getAppRootId(client, siteName, language, jssAppTemplateId) {
|
|
44
|
+
var _a, _b, _c, _d, _e, _f;
|
|
45
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
46
|
+
if (!siteName) {
|
|
47
|
+
throw new RangeError(siteNameError);
|
|
48
|
+
}
|
|
49
|
+
if (!language) {
|
|
50
|
+
throw new RangeError(languageError);
|
|
51
|
+
}
|
|
52
|
+
let fetchResponse = yield client.request(appRootQuery, {
|
|
53
|
+
jssAppTemplateId: jssAppTemplateId || SitecoreTemplateId.JssApp,
|
|
54
|
+
siteName,
|
|
55
|
+
language,
|
|
56
|
+
});
|
|
57
|
+
if (!((_c = (_b = (_a = fetchResponse === null || fetchResponse === void 0 ? void 0 : fetchResponse.layout) === null || _a === void 0 ? void 0 : _a.homePage) === null || _b === void 0 ? void 0 : _b.rootItem) === null || _c === void 0 ? void 0 : _c.length) && language !== 'en') {
|
|
58
|
+
fetchResponse = yield client.request(appRootQuery, {
|
|
59
|
+
jssAppTemplateId: jssAppTemplateId || SitecoreTemplateId.JssApp,
|
|
60
|
+
siteName,
|
|
61
|
+
language: 'en',
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
if (!((_f = (_e = (_d = fetchResponse === null || fetchResponse === void 0 ? void 0 : fetchResponse.layout) === null || _d === void 0 ? void 0 : _d.homePage) === null || _e === void 0 ? void 0 : _e.rootItem) === null || _f === void 0 ? void 0 : _f.length)) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
return fetchResponse.layout.homePage.rootItem[0].id;
|
|
68
|
+
});
|
|
69
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { SITECORE_EDGE_URL_DEFAULT } from '../constants';
|
|
2
|
+
/**
|
|
3
|
+
* Generates a URL for accessing Sitecore Edge Platform Content using the provided endpoint and context ID.
|
|
4
|
+
* @param {string} sitecoreEdgeContextId - The unique context id.
|
|
5
|
+
* @param {string} [sitecoreEdgeUrl] - The base endpoint URL for the Edge Platform. Default is https://edge-platform.sitecorecloud.io
|
|
6
|
+
* @returns {string} The complete URL for accessing content through the Edge Platform.
|
|
7
|
+
*/
|
|
8
|
+
export const getEdgeProxyContentUrl = (sitecoreEdgeContextId, sitecoreEdgeUrl = SITECORE_EDGE_URL_DEFAULT) => `${sitecoreEdgeUrl}/v1/content/api/graphql/v1?sitecoreContextId=${sitecoreEdgeContextId}`;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Provides functionality for performing GraphQL 'search' operations, including handling pagination.
|
|
12
|
+
* This class is meant to be extended or used as a mixin; it's not meant to be used directly.
|
|
13
|
+
* @template T The type of objects being requested.
|
|
14
|
+
* @mixin
|
|
15
|
+
*/
|
|
16
|
+
export class SearchQueryService {
|
|
17
|
+
/**
|
|
18
|
+
* Creates an instance of search query service.
|
|
19
|
+
* @param {GraphQLClient} client that fetches data from a GraphQL endpoint.
|
|
20
|
+
*/
|
|
21
|
+
constructor(client) {
|
|
22
|
+
this.client = client;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 1. Validates mandatory search query arguments
|
|
26
|
+
* 2. Executes search query with pagination
|
|
27
|
+
* 3. Aggregates pagination results into a single result-set.
|
|
28
|
+
* @template T The type of objects being requested.
|
|
29
|
+
* @param {string | DocumentNode} query the search query.
|
|
30
|
+
* @param {SearchQueryVariables} args search query arguments.
|
|
31
|
+
* @returns {T[]} array of result objects.
|
|
32
|
+
* @throws {RangeError} if a valid root item ID is not provided.
|
|
33
|
+
* @throws {RangeError} if the provided language(s) is(are) not valid.
|
|
34
|
+
*/
|
|
35
|
+
fetch(query, args) {
|
|
36
|
+
var _a;
|
|
37
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
38
|
+
if (!args.rootItemId) {
|
|
39
|
+
throw new RangeError('"rootItemId" and "language" must be non-empty strings');
|
|
40
|
+
}
|
|
41
|
+
if (!args.language) {
|
|
42
|
+
throw new RangeError('"rootItemId" and "language" must be non-empty strings');
|
|
43
|
+
}
|
|
44
|
+
let results = [];
|
|
45
|
+
let hasNext = true;
|
|
46
|
+
let after = '';
|
|
47
|
+
while (hasNext) {
|
|
48
|
+
const fetchResponse = yield this.client.request(query, Object.assign(Object.assign({}, args), { after }));
|
|
49
|
+
results = results.concat((_a = fetchResponse === null || fetchResponse === void 0 ? void 0 : fetchResponse.search) === null || _a === void 0 ? void 0 : _a.results);
|
|
50
|
+
hasNext = fetchResponse.search.pageInfo.hasNext;
|
|
51
|
+
after = fetchResponse.search.pageInfo.endCursor;
|
|
52
|
+
}
|
|
53
|
+
return results;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { GraphQLClient as Client } from 'graphql-request';
|
|
11
|
+
import parse from 'url-parse';
|
|
12
|
+
import debuggers from './debug';
|
|
13
|
+
import TimeoutPromise from './utils/timeout-promise';
|
|
14
|
+
/**
|
|
15
|
+
* A GraphQL client for Sitecore APIs that uses the 'graphql-request' library.
|
|
16
|
+
* https://github.com/prisma-labs/graphql-request
|
|
17
|
+
*/
|
|
18
|
+
export class GraphQLRequestClient {
|
|
19
|
+
/**
|
|
20
|
+
* Provides ability to execute graphql query using given `endpoint`
|
|
21
|
+
* @param {string} endpoint The Graphql endpoint
|
|
22
|
+
* @param {GraphQLRequestClientConfig} [clientConfig] GraphQL request client configuration.
|
|
23
|
+
*/
|
|
24
|
+
constructor(endpoint, clientConfig = {}) {
|
|
25
|
+
this.endpoint = endpoint;
|
|
26
|
+
this.headers = {};
|
|
27
|
+
if (clientConfig.apiKey) {
|
|
28
|
+
this.headers.sc_apikey = clientConfig.apiKey;
|
|
29
|
+
}
|
|
30
|
+
if (!endpoint || !parse(endpoint).hostname) {
|
|
31
|
+
throw new Error(`Invalid GraphQL endpoint '${endpoint}'. Verify that 'layoutServiceHost' property in 'scjssconfig.json' file or appropriate environment variable is set`);
|
|
32
|
+
}
|
|
33
|
+
this.timeout = clientConfig.timeout;
|
|
34
|
+
this.retries = clientConfig.retries || 0;
|
|
35
|
+
this.client = new Client(endpoint, {
|
|
36
|
+
headers: this.headers,
|
|
37
|
+
fetch: clientConfig.fetch,
|
|
38
|
+
});
|
|
39
|
+
this.debug = clientConfig.debugger || debuggers.http;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Factory method for creating a GraphQLRequestClientFactory.
|
|
43
|
+
* @param {Object} config - client configuration options.
|
|
44
|
+
* @param {string} config.endpoint - endpoint
|
|
45
|
+
* @param {string} [config.apiKey] - apikey
|
|
46
|
+
*/
|
|
47
|
+
static createClientFactory({ endpoint, apiKey, }) {
|
|
48
|
+
return (config = {}) => new GraphQLRequestClient(endpoint, Object.assign(Object.assign({}, config), { apiKey }));
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Execute graphql request
|
|
52
|
+
* @param {string | DocumentNode} query graphql query
|
|
53
|
+
* @param {Object} variables graphql variables
|
|
54
|
+
*/
|
|
55
|
+
request(query, variables) {
|
|
56
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
57
|
+
let retriesLeft = this.retries;
|
|
58
|
+
const retryer = () => __awaiter(this, void 0, void 0, function* () {
|
|
59
|
+
// Note we don't have access to raw request/response with graphql-request
|
|
60
|
+
// but we should log whatever we have.
|
|
61
|
+
this.debug('request: %o', {
|
|
62
|
+
url: this.endpoint,
|
|
63
|
+
headers: this.headers,
|
|
64
|
+
query,
|
|
65
|
+
variables,
|
|
66
|
+
});
|
|
67
|
+
const startTimestamp = Date.now();
|
|
68
|
+
const fetchWithOptionalTimeout = [this.client.request(query, variables)];
|
|
69
|
+
if (this.timeout) {
|
|
70
|
+
this.abortTimeout = new TimeoutPromise(this.timeout);
|
|
71
|
+
fetchWithOptionalTimeout.push(this.abortTimeout.start);
|
|
72
|
+
}
|
|
73
|
+
return Promise.race(fetchWithOptionalTimeout).then((data) => {
|
|
74
|
+
var _a;
|
|
75
|
+
(_a = this.abortTimeout) === null || _a === void 0 ? void 0 : _a.clear();
|
|
76
|
+
this.debug('response in %dms: %o', Date.now() - startTimestamp, data);
|
|
77
|
+
return Promise.resolve(data);
|
|
78
|
+
}, (error) => {
|
|
79
|
+
var _a, _b, _c, _d;
|
|
80
|
+
(_a = this.abortTimeout) === null || _a === void 0 ? void 0 : _a.clear();
|
|
81
|
+
this.debug('response error: %o', error.response || error.message || error);
|
|
82
|
+
if (((_b = error.response) === null || _b === void 0 ? void 0 : _b.status) === 429 && retriesLeft > 0) {
|
|
83
|
+
const rawHeaders = (_d = (_c = error) === null || _c === void 0 ? void 0 : _c.response) === null || _d === void 0 ? void 0 : _d.headers;
|
|
84
|
+
const delaySeconds = rawHeaders && rawHeaders.get('Retry-After')
|
|
85
|
+
? Number.parseInt(rawHeaders.get('Retry-After'), 10)
|
|
86
|
+
: 1;
|
|
87
|
+
this.debug('Error: Rate limit reached for GraphQL endpoint. Retrying in %ds. Retries left: %d', delaySeconds, retriesLeft);
|
|
88
|
+
retriesLeft--;
|
|
89
|
+
return new Promise((resolve) => setTimeout(resolve, delaySeconds * 1000)).then(retryer);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
return Promise.reject(error);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
return retryer();
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|