@lwrjs/shared-utils 0.17.2-alpha.2 → 0.17.2-alpha.21

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/build/cjs/env.cjs CHANGED
@@ -8,12 +8,22 @@ var __export = (target, all) => {
8
8
  // packages/@lwrjs/shared-utils/src/env.ts
9
9
  __markAsModule(exports);
10
10
  __export(exports, {
11
+ B3_PARENT_ID: () => B3_PARENT_ID,
12
+ B3_SAMPLED: () => B3_SAMPLED,
13
+ B3_SPAN_ID: () => B3_SPAN_ID,
14
+ B3_TRACE_ID: () => B3_TRACE_ID,
15
+ CORRELATION_ID: () => CORRELATION_ID,
16
+ MRT_REQUEST_CLASS: () => MRT_REQUEST_CLASS,
11
17
  REQUEST_DEPTH_HEADER: () => REQUEST_DEPTH_HEADER,
12
- REQUEST_DEPTH_KEY: () => REQUEST_DEPTH_KEY,
18
+ ROUTE_CORE_HEADER: () => ROUTE_CORE_HEADER,
19
+ TRUE_CLIENT_IP: () => TRUE_CLIENT_IP,
13
20
  buildEnvironmentContext: () => buildEnvironmentContext,
14
21
  getFeatureFlags: () => getFeatureFlags,
22
+ getTraceHeaders: () => getTraceHeaders,
15
23
  isLambdaEnv: () => isLambdaEnv,
24
+ isLocalAuthEnabled: () => isLocalAuthEnabled,
16
25
  isLocalDev: () => isLocalDev,
26
+ isLocalPreview: () => isLocalPreview,
17
27
  parseRequestDepth: () => parseRequestDepth
18
28
  });
19
29
  if (getFeatureFlags().REEVALUATE_MODULES && !getFeatureFlags().LEGACY_LOADER) {
@@ -27,6 +37,7 @@ function getFeatureFlags() {
27
37
  EXPERIMENTAL_UNVERSIONED_ALIASES: parseBooleanFlag("EXPERIMENTAL_UNVERSIONED_ALIASES"),
28
38
  LEGACY_LOADER: parseBooleanFlag("LEGACY_LOADER"),
29
39
  LWR_TRACING: parseTracingFlag(),
40
+ DISABLE_B3_TRACING: parseBooleanFlag("DISABLE_B3_TRACING"),
30
41
  MAX_VIEW_CACHE_TTL: parseStringFlag("MAX_VIEW_CACHE_TTL"),
31
42
  REEVALUATE_MODULES: parseBooleanFlag("REEVALUATE_MODULES"),
32
43
  SSR_COMPILER_ENABLED: parseBooleanFlag("SSR_COMPILER_ENABLED"),
@@ -52,6 +63,12 @@ function isLambdaEnv() {
52
63
  function isLocalDev() {
53
64
  return process.env.MRT_HMR === "true";
54
65
  }
66
+ function isLocalPreview() {
67
+ return process.env.LOCAL_PREVIEW_MODE === "true";
68
+ }
69
+ function isLocalAuthEnabled() {
70
+ return process.env.AUTH_TOKEN !== void 0;
71
+ }
55
72
  function buildEnvironmentContext(runtimeParams) {
56
73
  const basePath = runtimeParams.basePath;
57
74
  const locale = runtimeParams.locale;
@@ -64,11 +81,18 @@ function buildEnvironmentContext(runtimeParams) {
64
81
  uiBasePath
65
82
  };
66
83
  }
67
- var REQUEST_DEPTH_HEADER = "X-SFDC-Request-Depth";
68
- var REQUEST_DEPTH_KEY = REQUEST_DEPTH_HEADER.toLowerCase();
84
+ var TRUE_CLIENT_IP = "true-client-ip";
85
+ var CORRELATION_ID = "x-correlation-id";
86
+ var B3_TRACE_ID = "x-b3-traceid";
87
+ var B3_SPAN_ID = "x-b3-spandid";
88
+ var B3_PARENT_ID = "x-b3-parentid";
89
+ var B3_SAMPLED = "x-b3-sampled";
90
+ var MRT_REQUEST_CLASS = "x-mobify-request-class";
91
+ var ROUTE_CORE_HEADER = "x-sfdc-route-core";
92
+ var REQUEST_DEPTH_HEADER = "x-sfdc-request-depth";
69
93
  function parseRequestDepth(headers = {}, query = {}) {
70
94
  let maxDepth = 0;
71
- const value = headers && headers[REQUEST_DEPTH_KEY];
95
+ const value = headers && headers[REQUEST_DEPTH_HEADER];
72
96
  if (value) {
73
97
  if (Array.isArray(value)) {
74
98
  for (const depth of value) {
@@ -86,11 +110,29 @@ function parseRequestDepth(headers = {}, query = {}) {
86
110
  }
87
111
  }
88
112
  }
89
- if (query[REQUEST_DEPTH_KEY]) {
90
- const queryValue = parseInt(query[REQUEST_DEPTH_KEY], 10);
113
+ if (query[REQUEST_DEPTH_HEADER]) {
114
+ const queryValue = parseInt(query[REQUEST_DEPTH_HEADER], 10);
91
115
  if (!isNaN(queryValue) && queryValue > maxDepth) {
92
116
  maxDepth = queryValue;
93
117
  }
94
118
  }
95
119
  return maxDepth;
96
120
  }
121
+ function getTraceHeaders(runtimeParams, span) {
122
+ const headers = {};
123
+ if (runtimeParams.trueClientIP)
124
+ headers[TRUE_CLIENT_IP] = runtimeParams.trueClientIP;
125
+ if (runtimeParams.correlationID)
126
+ headers[CORRELATION_ID] = runtimeParams.correlationID;
127
+ if (!getFeatureFlags().DISABLE_B3_TRACING) {
128
+ if (span?.traceId) {
129
+ headers[B3_TRACE_ID] = span.traceId;
130
+ headers[B3_SAMPLED] = parseTracingFlag() ? "1" : "0";
131
+ }
132
+ if (span?.spanId)
133
+ headers[B3_SPAN_ID] = span.spanId;
134
+ if (span?.parentSpanId)
135
+ headers[B3_PARENT_ID] = span.parentSpanId;
136
+ }
137
+ return headers;
138
+ }
@@ -95,7 +95,7 @@ function explodeSpecifier(rawSpecifier) {
95
95
  const name = rawName ? [rawName, ...remaining].join("/") : rawNamespace;
96
96
  return {
97
97
  specifier: importee,
98
- namespace,
98
+ namespace: namespace || "",
99
99
  name,
100
100
  version: version ? normalizeVersionFromUri(version) : version
101
101
  };
@@ -27,7 +27,7 @@ __export(exports, {
27
27
  launch: () => launch
28
28
  });
29
29
  var import_os = __toModule(require("os"));
30
- async function launch(port, https) {
30
+ async function launch(port, https, path) {
31
31
  const {exec} = await Promise.resolve().then(() => __toModule(require("child_process")));
32
32
  let cmd = "open";
33
33
  if (process.platform == "win32") {
@@ -39,5 +39,9 @@ async function launch(port, https) {
39
39
  cmd = "xdg-open";
40
40
  }
41
41
  }
42
- exec(`${cmd} ${https ? "https" : "http"}://localhost:${port}`);
42
+ const finalPath = path ? path.startsWith("/") ? path : `/${path}` : "";
43
+ const protocol = https ? "https" : "http";
44
+ const url = `${protocol}://localhost:${port}${finalPath}/`;
45
+ exec(`${cmd} ${url}`);
46
+ return url;
43
47
  }
@@ -24,11 +24,14 @@ var __toModule = (module2) => {
24
24
  // packages/@lwrjs/shared-utils/src/serialize.ts
25
25
  __markAsModule(exports);
26
26
  __export(exports, {
27
+ addHeadMarkup: () => addHeadMarkup,
28
+ createHeadMarkup: () => createHeadMarkup,
27
29
  replaceStringFromLocation: () => replaceStringFromLocation,
28
30
  serializeModuleToJson: () => serializeModuleToJson,
29
31
  shortestTtl: () => shortestTtl
30
32
  });
31
33
  var import_ms = __toModule(require("ms"));
34
+ var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
32
35
  async function createJsonModule(moduleId, moduleRegistry, runtimeEnvironment, runtimeParams) {
33
36
  const {
34
37
  ownHash,
@@ -84,3 +87,52 @@ function shortestTtl(newTtl, oldTtl, maxTtl) {
84
87
  }
85
88
  return shortest;
86
89
  }
90
+ function createMetaTags(meta) {
91
+ return meta.reduce((metaStr, {name, content, httpEquiv}) => {
92
+ if (!name && !content && !httpEquiv)
93
+ return metaStr;
94
+ const nameStr = name ? ` name="${name}"` : "", httpEquivStr = httpEquiv ? ` http-equiv="${httpEquiv}"` : "", contentStr = content ? ` content="${content}"` : "";
95
+ return metaStr + `<meta${nameStr}${httpEquivStr}${contentStr}>
96
+ `;
97
+ }, "");
98
+ }
99
+ function createScriptTags(scripts) {
100
+ return scripts.reduce((scriptStr, {body}) => scriptStr + `<script type="application/ld+json">${body}</script>
101
+ `, "");
102
+ }
103
+ function createLinkTags(links) {
104
+ return links.reduce((linkStr, {href, rel, as, fetchpriority}) => {
105
+ const relStr = rel ? ` rel="${rel}"` : "", asStr = as ? ` as="${as}"` : "", fetchStr = fetchpriority ? ` fetchpriority="${fetchpriority}"` : "";
106
+ return linkStr + `<link href="${href}"${relStr}${asStr}${fetchStr}>
107
+ `;
108
+ }, "");
109
+ }
110
+ function createStyleTags(styles) {
111
+ return styles.reduce((styleStr, {body, id}) => {
112
+ const idStr = id ? ` id="${id}"` : "";
113
+ return styleStr + `<style type="text/css"${idStr}>${body}</style>
114
+ `;
115
+ }, "");
116
+ }
117
+ function createHeadMarkup(markup) {
118
+ let hasTitle = false;
119
+ return markup.reduce((str, {title, scripts = [], meta = [], links = [], styles = []} = {}) => {
120
+ if (title && !hasTitle) {
121
+ hasTitle = true;
122
+ str += `<title>${title}</title>
123
+ `;
124
+ }
125
+ return str + createMetaTags(meta) + createScriptTags(scripts) + createLinkTags(links) + createStyleTags(styles);
126
+ }, "");
127
+ }
128
+ function addHeadMarkup(markup, stringBuilder) {
129
+ const headMarkup = createHeadMarkup(markup);
130
+ if (headMarkup) {
131
+ const headIndex = stringBuilder.original.indexOf("</head>");
132
+ if (headIndex >= 0) {
133
+ stringBuilder.prependLeft(headIndex, headMarkup);
134
+ } else {
135
+ import_diagnostics.logger.error("Adding head markup failed. Could not find the </head> tag.");
136
+ }
137
+ }
138
+ }
@@ -33,7 +33,8 @@ __export(exports, {
33
33
  getViewUri: () => getViewUri,
34
34
  isModuleOrBundleUrl: () => isModuleOrBundleUrl,
35
35
  isURL: () => isURL,
36
- removeClientBootstrapConfigurationSuffix: () => removeClientBootstrapConfigurationSuffix
36
+ removeClientBootstrapConfigurationSuffix: () => removeClientBootstrapConfigurationSuffix,
37
+ toHostname: () => toHostname
37
38
  });
38
39
  var import_path_to_regexp = __toModule(require("path-to-regexp"));
39
40
  var import_path = __toModule(require("path"));
@@ -138,3 +139,6 @@ function crossEnvFileURL(url) {
138
139
  }
139
140
  return url;
140
141
  }
142
+ function toHostname(url) {
143
+ return url.replace(/^https?:\/\//, "").replace(/:(\d+)(?=[/.]|$)/, "");
144
+ }
package/build/es/env.d.ts CHANGED
@@ -12,11 +12,35 @@ export declare function isLambdaEnv(): boolean;
12
12
  * @returns true if running in localdev mode
13
13
  */
14
14
  export declare function isLocalDev(): boolean;
15
+ /**
16
+ * This function is used to determine if lwr is running in the context of local preview.
17
+ *
18
+ * @returns true if running in preview mode
19
+ */
20
+ export declare function isLocalPreview(): boolean;
21
+ /**
22
+ * This function is used to determine if lwr is running with an authenticated context locally
23
+ *
24
+ * @returns true if local dev/preview authentication is enabled
25
+ */
26
+ export declare function isLocalAuthEnabled(): boolean;
15
27
  /**
16
28
  * Create a serializable context for user-land exposed environment variables
17
29
  */
18
30
  export declare function buildEnvironmentContext(runtimeParams: RuntimeParams): EnvironmentContext;
19
- export declare const REQUEST_DEPTH_HEADER = "X-SFDC-Request-Depth";
20
- export declare const REQUEST_DEPTH_KEY: string;
31
+ export declare const TRUE_CLIENT_IP = "true-client-ip";
32
+ export declare const CORRELATION_ID = "x-correlation-id";
33
+ export declare const B3_TRACE_ID = "x-b3-traceid";
34
+ export declare const B3_SPAN_ID = "x-b3-spandid";
35
+ export declare const B3_PARENT_ID = "x-b3-parentid";
36
+ export declare const B3_SAMPLED = "x-b3-sampled";
37
+ export declare const MRT_REQUEST_CLASS = "x-mobify-request-class";
38
+ export declare const ROUTE_CORE_HEADER = "x-sfdc-route-core";
39
+ export declare const REQUEST_DEPTH_HEADER = "x-sfdc-request-depth";
21
40
  export declare function parseRequestDepth(headers?: Headers, query?: Record<string, string>): number;
41
+ export declare function getTraceHeaders(runtimeParams: RuntimeParams, span?: {
42
+ traceId: string;
43
+ spanId: string;
44
+ parentSpanId?: string;
45
+ }): HeadersInit;
22
46
  //# sourceMappingURL=env.d.ts.map
package/build/es/env.js CHANGED
@@ -14,6 +14,8 @@ export function getFeatureFlags() {
14
14
  LEGACY_LOADER: parseBooleanFlag('LEGACY_LOADER'),
15
15
  // Enable metrics log level 'off', 'default' or 'verbose'
16
16
  LWR_TRACING: parseTracingFlag(),
17
+ // Turn off distributed tracing (B3 headers, traceparent meta tag, MRT span exporting)
18
+ DISABLE_B3_TRACING: parseBooleanFlag('DISABLE_B3_TRACING'),
17
19
  // Max size of ViewDefinition time to live
18
20
  MAX_VIEW_CACHE_TTL: parseStringFlag('MAX_VIEW_CACHE_TTL'),
19
21
  // Forces SSR to re-evaluate modules for every page render. By default, modules are evaluated only once.
@@ -70,6 +72,22 @@ export function isLocalDev() {
70
72
  // TODO still need to formalize environment variable names
71
73
  return process.env.MRT_HMR === 'true';
72
74
  }
75
+ /**
76
+ * This function is used to determine if lwr is running in the context of local preview.
77
+ *
78
+ * @returns true if running in preview mode
79
+ */
80
+ export function isLocalPreview() {
81
+ return process.env.LOCAL_PREVIEW_MODE === 'true';
82
+ }
83
+ /**
84
+ * This function is used to determine if lwr is running with an authenticated context locally
85
+ *
86
+ * @returns true if local dev/preview authentication is enabled
87
+ */
88
+ export function isLocalAuthEnabled() {
89
+ return process.env.AUTH_TOKEN !== undefined;
90
+ }
73
91
  /**
74
92
  * Create a serializable context for user-land exposed environment variables
75
93
  */
@@ -89,11 +107,20 @@ export function buildEnvironmentContext(runtimeParams) {
89
107
  uiBasePath,
90
108
  };
91
109
  }
92
- export const REQUEST_DEPTH_HEADER = 'X-SFDC-Request-Depth';
93
- export const REQUEST_DEPTH_KEY = REQUEST_DEPTH_HEADER.toLowerCase();
110
+ // headers used by LWR-Node and LWR@MRT
111
+ export const TRUE_CLIENT_IP = 'true-client-ip'; // public IP of the original request source, eg: 13.123.12.3
112
+ export const CORRELATION_ID = 'x-correlation-id'; // shared correlation ID for the request
113
+ export const B3_TRACE_ID = 'x-b3-traceid'; // trace ID shared across service boundaries for a page request, set to inbound B3 header || lwr.handle.view trace ID
114
+ export const B3_SPAN_ID = 'x-b3-spandid'; // span ID for a trace
115
+ export const B3_PARENT_ID = 'x-b3-parentid'; // parent span ID for a trace
116
+ export const B3_SAMPLED = 'x-b3-sampled'; // "0" = tracing is off, "1" = tracing is on
117
+ export const MRT_REQUEST_CLASS = 'x-mobify-request-class'; // contains the site base path, eg: basePath=/mysite
118
+ export const ROUTE_CORE_HEADER = 'x-sfdc-route-core'; // helps route requests to Core efficiently, value: true
119
+ export const REQUEST_DEPTH_HEADER = 'x-sfdc-request-depth'; // tracks the request depth to prevent cycles to the LWR server, eg: 2
120
+ // standard headers: Forwarded (eg: host=dev.testing.com;proto=https), Host (eg: darrell.sandbox.my.site.com), Cookie (holds the SID for auth'ed requests)
94
121
  export function parseRequestDepth(headers = {}, query = {}) {
95
122
  let maxDepth = 0;
96
- const value = headers && headers[REQUEST_DEPTH_KEY];
123
+ const value = headers && headers[REQUEST_DEPTH_HEADER];
97
124
  if (value) {
98
125
  if (Array.isArray(value)) {
99
126
  for (const depth of value) {
@@ -112,12 +139,30 @@ export function parseRequestDepth(headers = {}, query = {}) {
112
139
  }
113
140
  }
114
141
  }
115
- if (query[REQUEST_DEPTH_KEY]) {
116
- const queryValue = parseInt(query[REQUEST_DEPTH_KEY], 10);
142
+ if (query[REQUEST_DEPTH_HEADER]) {
143
+ const queryValue = parseInt(query[REQUEST_DEPTH_HEADER], 10);
117
144
  if (!isNaN(queryValue) && queryValue > maxDepth) {
118
145
  maxDepth = queryValue;
119
146
  }
120
147
  }
121
148
  return maxDepth;
122
149
  }
150
+ export function getTraceHeaders(runtimeParams, span) {
151
+ const headers = {};
152
+ if (runtimeParams.trueClientIP)
153
+ headers[TRUE_CLIENT_IP] = runtimeParams.trueClientIP;
154
+ if (runtimeParams.correlationID)
155
+ headers[CORRELATION_ID] = runtimeParams.correlationID;
156
+ if (!getFeatureFlags().DISABLE_B3_TRACING) {
157
+ if (span?.traceId) {
158
+ headers[B3_TRACE_ID] = span.traceId;
159
+ headers[B3_SAMPLED] = parseTracingFlag() ? '1' : '0';
160
+ }
161
+ if (span?.spanId)
162
+ headers[B3_SPAN_ID] = span.spanId;
163
+ if (span?.parentSpanId)
164
+ headers[B3_PARENT_ID] = span.parentSpanId;
165
+ }
166
+ return headers;
167
+ }
123
168
  //# sourceMappingURL=env.js.map
@@ -43,6 +43,7 @@ export declare function prettyModuleUriSuffix(specifier: string): string;
43
43
  */
44
44
  interface PartialModuleId extends AbstractModuleId {
45
45
  name: string;
46
+ namespace: string;
46
47
  }
47
48
  export declare function explodeSpecifier(rawSpecifier: string): PartialModuleId;
48
49
  export declare function explodeSpecifiers(rawSpecifiers: string): PartialModuleId[];
@@ -55,7 +55,7 @@ export function explodeSpecifier(rawSpecifier) {
55
55
  // Return an abstract ModuleIdentifier
56
56
  return {
57
57
  specifier: importee,
58
- namespace,
58
+ namespace: namespace || '',
59
59
  name,
60
60
  version: version ? normalizeVersionFromUri(version) : version,
61
61
  };
@@ -4,5 +4,5 @@
4
4
  * @param port - the port number
5
5
  * @param https - if true, use https
6
6
  */
7
- export declare function launch(port: number, https?: boolean): Promise<void>;
7
+ export declare function launch(port: number, https?: boolean, path?: string): Promise<string>;
8
8
  //# sourceMappingURL=launch.d.ts.map
@@ -5,7 +5,7 @@ import { release } from 'os';
5
5
  * @param port - the port number
6
6
  * @param https - if true, use https
7
7
  */
8
- export async function launch(port, https) {
8
+ export async function launch(port, https, path) {
9
9
  const { exec } = await import('child_process');
10
10
  let cmd = 'open';
11
11
  if (process.platform == 'win32') {
@@ -19,6 +19,11 @@ export async function launch(port, https) {
19
19
  cmd = 'xdg-open';
20
20
  }
21
21
  }
22
- exec(`${cmd} ${https ? 'https' : 'http'}://localhost:${port}`);
22
+ // Ensure the path begins with '/' if provided
23
+ const finalPath = path ? (path.startsWith('/') ? path : `/${path}`) : '';
24
+ const protocol = https ? 'https' : 'http';
25
+ const url = `${protocol}://localhost:${port}${finalPath}/`;
26
+ exec(`${cmd} ${url}`);
27
+ return url;
23
28
  }
24
29
  //# sourceMappingURL=launch.js.map
@@ -1,4 +1,4 @@
1
- import type { LinkedModuleDefinition, ModuleJsonDefinition, ModuleRegistry, RuntimeParams } from '@lwrjs/types';
1
+ import type { HeadMarkup, LinkedModuleDefinition, LwrStringBuilder, ModuleJsonDefinition, ModuleRegistry, RuntimeParams } from '@lwrjs/types';
2
2
  /**
3
3
  * Take a Module Definition and return its JSON serialization
4
4
  *
@@ -26,4 +26,16 @@ export declare function replaceStringFromLocation(src: string, { startOffset, en
26
26
  * @returns - the shorter of the two TTLs IN SECONDS, undefined if both TTLs are missing
27
27
  */
28
28
  export declare function shortestTtl(newTtl?: string | number, oldTtl?: string | number, maxTtl?: string | number): number | undefined;
29
+ /**
30
+ * Serialize head markup metadata into an HTML string
31
+ * @param markup An array of markup metadata objects
32
+ * @returns A string of HTML generated from markup metadata
33
+ */
34
+ export declare function createHeadMarkup(markup: (HeadMarkup | undefined)[]): string;
35
+ /**
36
+ * Serialize HeadMarkup config into HTML, then add it to the <head> of a base doc
37
+ * @param markup An array of markup metadata objects
38
+ * @param stringBuilder The string builder for a base document
39
+ */
40
+ export declare function addHeadMarkup(markup: (HeadMarkup | undefined)[], stringBuilder: LwrStringBuilder): void;
29
41
  //# sourceMappingURL=serialize.d.ts.map
@@ -1,4 +1,5 @@
1
1
  import ms from 'ms';
2
+ import { logger } from '@lwrjs/diagnostics';
2
3
  // Given a Module Identifier, return a JSON entry
3
4
  async function createJsonModule(moduleId, moduleRegistry, runtimeEnvironment, runtimeParams) {
4
5
  const { ownHash, moduleEntry: { version }, } = await moduleRegistry.getModule(moduleId, runtimeParams);
@@ -67,4 +68,69 @@ export function shortestTtl(newTtl, oldTtl, maxTtl) {
67
68
  }
68
69
  return shortest;
69
70
  }
71
+ /** HEAD MARKUP UTILS */
72
+ function createMetaTags(meta) {
73
+ return meta.reduce((metaStr, { name, content, httpEquiv }) => {
74
+ if (!name && !content && !httpEquiv)
75
+ return metaStr; // do not create empty <meta> tags
76
+ const nameStr = name ? ` name="${name}"` : '', httpEquivStr = httpEquiv ? ` http-equiv="${httpEquiv}"` : '', contentStr = content ? ` content="${content}"` : '';
77
+ return metaStr + `<meta${nameStr}${httpEquivStr}${contentStr}>\n`;
78
+ }, '');
79
+ }
80
+ function createScriptTags(scripts) {
81
+ return scripts.reduce((scriptStr, { body }) => scriptStr + `<script type="application/ld+json">${body}</script>\n`, '');
82
+ }
83
+ function createLinkTags(links) {
84
+ return links.reduce((linkStr, { href, rel, as, fetchpriority }) => {
85
+ const relStr = rel ? ` rel="${rel}"` : '', asStr = as ? ` as="${as}"` : '', fetchStr = fetchpriority ? ` fetchpriority="${fetchpriority}"` : '';
86
+ return linkStr + `<link href="${href}"${relStr}${asStr}${fetchStr}>\n`;
87
+ }, '');
88
+ }
89
+ function createStyleTags(styles) {
90
+ return styles.reduce((styleStr, { body, id }) => {
91
+ const idStr = id ? ` id="${id}"` : '';
92
+ return styleStr + `<style type="text/css"${idStr}>${body}</style>\n`;
93
+ }, '');
94
+ }
95
+ /**
96
+ * Serialize head markup metadata into an HTML string
97
+ * @param markup An array of markup metadata objects
98
+ * @returns A string of HTML generated from markup metadata
99
+ */
100
+ export function createHeadMarkup(markup) {
101
+ // Loop through the <title>, <script>, <meta>, and <link> tag information
102
+ // Create an HTML string for each tag
103
+ let hasTitle = false;
104
+ return markup.reduce((str, { title, scripts = [], meta = [], links = [], styles = [] } = {}) => {
105
+ if (title && !hasTitle) {
106
+ // first <title> wins
107
+ hasTitle = true;
108
+ str += `<title>${title}</title>\n`;
109
+ }
110
+ return (str +
111
+ createMetaTags(meta) +
112
+ createScriptTags(scripts) +
113
+ createLinkTags(links) +
114
+ createStyleTags(styles));
115
+ }, '');
116
+ }
117
+ /**
118
+ * Serialize HeadMarkup config into HTML, then add it to the <head> of a base doc
119
+ * @param markup An array of markup metadata objects
120
+ * @param stringBuilder The string builder for a base document
121
+ */
122
+ export function addHeadMarkup(markup, stringBuilder) {
123
+ // Create HTML tags for each item in the SsrDataResponse.markup bag
124
+ const headMarkup = createHeadMarkup(markup);
125
+ if (headMarkup) {
126
+ // Add all the links to the <head> section of the base document
127
+ const headIndex = stringBuilder.original.indexOf('</head>');
128
+ if (headIndex >= 0) {
129
+ stringBuilder.prependLeft(headIndex, headMarkup);
130
+ }
131
+ else {
132
+ logger.error('Adding head markup failed. Could not find the </head> tag.');
133
+ }
134
+ }
135
+ }
70
136
  //# sourceMappingURL=serialize.js.map
@@ -38,4 +38,5 @@ export declare function getViewUri(routePath: string, basePath: string, locale:
38
38
  */
39
39
  export declare function isURL(uri: string): boolean;
40
40
  export declare function crossEnvFileURL(url: string): string;
41
+ export declare function toHostname(url: string): string;
41
42
  //# sourceMappingURL=urls.d.ts.map
package/build/es/urls.js CHANGED
@@ -139,4 +139,13 @@ export function crossEnvFileURL(url) {
139
139
  }
140
140
  return url;
141
141
  }
142
+ // Remove the protocol and port from a URL to create a hostname
143
+ // eg: url = https://developer.mozilla.org:4097/en-US/docs/Web/API/URL/hostname
144
+ // protocol = https
145
+ // port = 4097
146
+ // host = developer.mozilla.org:4097
147
+ // hostname = developer.mozilla.org
148
+ export function toHostname(url) {
149
+ return url.replace(/^https?:\/\//, '').replace(/:(\d+)(?=[/.]|$)/, '');
150
+ }
142
151
  //# sourceMappingURL=urls.js.map
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.17.2-alpha.2",
7
+ "version": "0.17.2-alpha.21",
8
8
  "homepage": "https://developer.salesforce.com/docs/platform/lwr/overview",
9
9
  "repository": {
10
10
  "type": "git",
@@ -37,7 +37,7 @@
37
37
  "build/**/*.d.ts"
38
38
  ],
39
39
  "dependencies": {
40
- "@lwrjs/diagnostics": "0.17.2-alpha.2",
40
+ "@lwrjs/diagnostics": "0.17.2-alpha.21",
41
41
  "es-module-lexer": "^1.5.4",
42
42
  "fast-json-stable-stringify": "^2.1.0",
43
43
  "magic-string": "^0.30.9",
@@ -50,13 +50,13 @@
50
50
  "slugify": "^1.4.5"
51
51
  },
52
52
  "devDependencies": {
53
- "@lwrjs/types": "0.17.2-alpha.2",
53
+ "@lwrjs/types": "0.17.2-alpha.21",
54
54
  "@types/mime-types": "2.1.4",
55
55
  "@types/path-to-regexp": "^1.7.0",
56
56
  "memfs": "^4.13.0"
57
57
  },
58
58
  "engines": {
59
- "node": ">=18.0.0"
59
+ "node": ">=20.0.0"
60
60
  },
61
- "gitHead": "739b237f5d7f2c1989142cb505a56cc763f21976"
61
+ "gitHead": "448ae2b681a4718241a29890f34e0ac13e35e6fd"
62
62
  }