@lwrjs/view-registry 0.13.0-alpha.0 → 0.13.0-alpha.10

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.
@@ -57,7 +57,7 @@ var LwrViewRegistry = class {
57
57
  observer.onAssetSourceChange(({payload}) => this.onAssetSourceChange(payload));
58
58
  }
59
59
  async onModuleDefinitionChange(moduleDefinition) {
60
- if (process.env.MRT_HMR === "true") {
60
+ if ((0, import_shared_utils.isLocalDev)()) {
61
61
  this.viewDefinitions.clear();
62
62
  return;
63
63
  }
@@ -80,7 +80,7 @@ var LwrViewRegistry = class {
80
80
  }
81
81
  }
82
82
  async onViewSourceChange(compiledView) {
83
- if (process.env.MRT_HMR === "true") {
83
+ if ((0, import_shared_utils.isLocalDev)()) {
84
84
  this.viewDefinitions.clear();
85
85
  return;
86
86
  }
@@ -194,6 +194,8 @@ var LwrViewRegistry = class {
194
194
  return viewDefinition2.viewDefinition;
195
195
  }
196
196
  }
197
+ const updatableViewParams = {...viewParams};
198
+ (0, import_utils.generateViewNonce)(updatableViewParams);
197
199
  const pendingViewDefCacheKey = viewDefCacheKey + viewParamKey;
198
200
  const viewDefinition = await this.pendingViewDefinitions.execute(pendingViewDefCacheKey, () => (0, import_instrumentation.getTracer)().trace({
199
201
  name: import_instrumentation.ViewSpan.RenderView,
@@ -201,7 +203,8 @@ var LwrViewRegistry = class {
201
203
  view: view.id,
202
204
  ssr: view.bootstrap?.ssr === true
203
205
  }
204
- }, () => this.renderView(view, viewParams, runtimeEnvironment, runtimeParams, renderOptions)));
206
+ }, () => this.renderView(view, updatableViewParams, runtimeEnvironment, runtimeParams, renderOptions)));
207
+ viewDefinition.nonce = (0, import_utils.getViewNonce)(updatableViewParams);
205
208
  if (cacheDisabled === false) {
206
209
  const route = this.globalConfig.routes.find((r) => r.id === view.id);
207
210
  const ttl = (0, import_shared_utils.shortestTtl)(viewDefinition.cache?.ttl, route?.cache?.ttl);
@@ -101,6 +101,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
101
101
  groups: new Map()
102
102
  };
103
103
  const isSSR = view.bootstrap?.ssr;
104
+ const nonce = (0, import_utils.getViewNonce)(viewParams);
104
105
  let bootstrapModuleRef, versionedSpecifier = bootstrapSpecifier;
105
106
  const customElementsRecords = [];
106
107
  const flattenedElements = (0, import_utils2.flattenCustomElements)(customElements, isSSR);
@@ -125,6 +126,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
125
126
  if (!def.inline && !def.src) {
126
127
  throw Error(`Invalid Shim ${shimBundle}: ${JSON.stringify(def)}`);
127
128
  }
129
+ (0, import_utils.addExternalScriptNonce)(def, nonce);
128
130
  requiredResources.push(def);
129
131
  const errorShimDef = await resourceRegistry.getResource({specifier: "lwr-error-shim.js", version}, runtimeEnvironment, runtimeParams);
130
132
  if (!errorShimDef) {
@@ -133,6 +135,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
133
135
  if (!errorShimDef.inline && !errorShimDef.src) {
134
136
  throw Error(`Invalid Shim lwr-error-shim.js: ${JSON.stringify(errorShimDef)}`);
135
137
  }
138
+ (0, import_utils.addExternalScriptNonce)(errorShimDef, nonce);
136
139
  requiredResources.push(errorShimDef);
137
140
  }
138
141
  const bootstrapModuleGraph = await (0, import_shared_utils.getModuleGraphs)(bootstrapSpecifier, {includeUris: true, includeLinkedDefinitions: true, depth}, moduleRegistry, defRegistry, runtimeEnvironment, runtimeParams, visitedCache);
@@ -146,7 +149,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
146
149
  if (!uri) {
147
150
  throw Error(`Invalid Module Resource ${versionedSpecifier}`);
148
151
  }
149
- moduleResources.push((0, import_utils.getModuleResourceByUri)(uri, runtimeEnvironment, {isPreload: false, isSSR}));
152
+ moduleResources.push((0, import_utils.getModuleResourceByUri)(uri, runtimeEnvironment, {isPreload: false, isSSR, nonce}));
150
153
  for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
151
154
  const uri2 = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
152
155
  if (uri2) {
@@ -235,7 +238,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
235
238
  }
236
239
  const dedupedUris = [...new Set(viewPreloads.uris)];
237
240
  for (const preloadUri of dedupedUris) {
238
- moduleResources.push((0, import_utils.getModuleResourceByUri)(preloadUri, runtimeEnvironment, {isPreload: true, isSSR}));
241
+ moduleResources.push((0, import_utils.getModuleResourceByUri)(preloadUri, runtimeEnvironment, {isPreload: true, isSSR, nonce}));
239
242
  }
240
243
  const htmlResources = await Promise.all([...configResources, ...requiredResources, ...moduleResources].map(import_utils.generateHtmlTag));
241
244
  return {
@@ -90,6 +90,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
90
90
  groups: new Map()
91
91
  };
92
92
  const isSSR = view.bootstrap?.ssr;
93
+ const nonce = (0, import_utils.getViewNonce)(viewParams);
93
94
  let bootstrapModuleRef, versionedSpecifier = bootstrapSpecifier;
94
95
  let importMetadata = {imports: {}};
95
96
  const customElementsRecords = [];
@@ -105,6 +106,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
105
106
  if (!def.inline && !def.src) {
106
107
  throw Error(`Invalid Shim ${shimBundle}: ${JSON.stringify(def)}`);
107
108
  }
109
+ (0, import_utils.addExternalScriptNonce)(def, nonce);
108
110
  requiredResources.push(def);
109
111
  const errorShimDef = await resourceRegistry.getResource({specifier: "lwr-error-shim.js", version}, runtimeEnvironment, runtimeParams);
110
112
  if (!errorShimDef) {
@@ -113,6 +115,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
113
115
  if (!errorShimDef.inline && !errorShimDef.src) {
114
116
  throw Error(`Invalid Shim lwr-error-shim.js: ${JSON.stringify(errorShimDef)}`);
115
117
  }
118
+ (0, import_utils.addExternalScriptNonce)(errorShimDef, nonce);
116
119
  requiredResources.push(errorShimDef);
117
120
  }
118
121
  const bootstrapModuleGraph = await (0, import_shared_utils.getModuleGraphs)(bootstrapSpecifier, {includeUris: true, includeLinkedDefinitions: true, depth}, moduleRegistry, defRegistry, runtimeEnvironment, runtimeParams, visitedCache);
@@ -126,7 +129,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
126
129
  if (!uri) {
127
130
  throw Error(`Invalid Module Resource ${versionedSpecifier}`);
128
131
  }
129
- moduleResources.push((0, import_utils.getModuleResourceByUri)(uri, runtimeEnvironment, {isPreload: false, isSSR}));
132
+ moduleResources.push((0, import_utils.getModuleResourceByUri)(uri, runtimeEnvironment, {isPreload: false, isSSR, nonce}));
130
133
  for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
131
134
  const uri2 = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
132
135
  if (uri2) {
@@ -215,7 +218,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
215
218
  }
216
219
  const dedupedUris = [...new Set(viewPreloads.uris)];
217
220
  for (const preloadUri of dedupedUris) {
218
- moduleResources.push((0, import_utils.getModuleResourceByUri)(preloadUri, runtimeEnvironment, {isPreload: true, isSSR}));
221
+ moduleResources.push((0, import_utils.getModuleResourceByUri)(preloadUri, runtimeEnvironment, {isPreload: true, isSSR, nonce}));
219
222
  }
220
223
  const htmlResources = await Promise.all([...configResources, ...requiredResources, ...moduleResources].map(import_utils.generateHtmlTag));
221
224
  const mapping = (0, import_shared_utils.getMappingUriPrefix)(runtimeEnvironment, runtimeParams);
@@ -24,11 +24,14 @@ var __toModule = (module2) => {
24
24
  // packages/@lwrjs/view-registry/src/utils.ts
25
25
  __markAsModule(exports);
26
26
  __export(exports, {
27
+ addExternalScriptNonce: () => addExternalScriptNonce,
27
28
  createJsonModule: () => createJsonModule,
28
29
  generateHtmlTag: () => generateHtmlTag,
29
30
  generatePageContext: () => generatePageContext,
31
+ generateViewNonce: () => generateViewNonce,
30
32
  getModuleResource: () => getModuleResource,
31
33
  getModuleResourceByUri: () => getModuleResourceByUri,
34
+ getViewNonce: () => getViewNonce,
32
35
  isViewResponse: () => isViewResponse,
33
36
  normalizeRenderOptions: () => normalizeRenderOptions,
34
37
  normalizeRenderedResult: () => normalizeRenderedResult,
@@ -38,17 +41,19 @@ __export(exports, {
38
41
  var import_path = __toModule(require("path"));
39
42
  var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
40
43
  var import_identity = __toModule(require("@lwrjs/app-service/identity"));
44
+ var import_crypto = __toModule(require("crypto"));
41
45
  function generateExternalStyle(src) {
42
46
  return `<link rel="stylesheet" href="${src}">`;
43
47
  }
44
- function generateExternalScript(type = "application/javascript", src, async, defer) {
48
+ function generateExternalScript(type = "application/javascript", src, async, defer, nonce) {
45
49
  let scriptLoadOrder = "";
46
50
  if (defer) {
47
51
  scriptLoadOrder = " defer";
48
52
  } else if (async) {
49
53
  scriptLoadOrder = " async";
50
54
  }
51
- return `<script type="${type}"${scriptLoadOrder} src="${src}"></script>`;
55
+ const nonceAttr = nonce ? ` nonce="${nonce}"` : "";
56
+ return `<script type="${type}"${scriptLoadOrder}${nonceAttr} src="${src}"></script>`;
52
57
  }
53
58
  function generateLinkPreloadTag({href, type}) {
54
59
  if (type === "module") {
@@ -57,13 +62,13 @@ function generateLinkPreloadTag({href, type}) {
57
62
  return `<link rel="preload" href="${href}" type="${type}" />`;
58
63
  }
59
64
  }
60
- function generateExternalTag({type, src = "", async, defer, isPreload}) {
65
+ function generateExternalTag({type, src = "", async, defer, isPreload, nonce}) {
61
66
  if (isPreload) {
62
67
  return generateLinkPreloadTag({href: src, type});
63
68
  } else if (type === "text/css") {
64
69
  return generateExternalStyle(src);
65
70
  } else {
66
- return generateExternalScript(type, src, async, defer);
71
+ return generateExternalScript(type, src, async, defer, nonce);
67
72
  }
68
73
  }
69
74
  async function generateInlineTag({specifier, type, content, stream, nonce}) {
@@ -223,14 +228,15 @@ async function getModuleResource(moduleId, runtimeEnvironment, moduleResourceMet
223
228
  };
224
229
  }
225
230
  function getModuleResourceByUri(uri, runtimeEnvironment, moduleResourceMeta) {
226
- const {isSSR = false, isPreload = false} = moduleResourceMeta;
231
+ const {isSSR = false, isPreload = false, nonce} = moduleResourceMeta;
227
232
  const {format} = runtimeEnvironment;
228
233
  return {
229
234
  src: uri,
230
235
  type: format === "amd" ? "application/javascript" : "module",
231
236
  async: !isSSR && isPreload,
232
237
  defer: isSSR,
233
- isPreload: format !== "amd" && isPreload
238
+ isPreload: format !== "amd" && isPreload,
239
+ nonce
234
240
  };
235
241
  }
236
242
  async function createJsonModule(specifier, moduleRegistry, environment, params) {
@@ -252,3 +258,19 @@ async function createJsonModule(specifier, moduleRegistry, environment, params)
252
258
  }
253
259
  };
254
260
  }
261
+ function getViewNonce(viewParams) {
262
+ return viewParams?.page?.nonce;
263
+ }
264
+ function generateViewNonce(viewParams) {
265
+ const nonce = import_crypto.default.randomBytes(16).toString("base64");
266
+ if (!viewParams.page) {
267
+ viewParams.page = {nonce};
268
+ } else {
269
+ viewParams.page.nonce = nonce;
270
+ }
271
+ }
272
+ function addExternalScriptNonce(def, nonce) {
273
+ if (!def.inline) {
274
+ def.nonce = nonce;
275
+ }
276
+ }
@@ -148,6 +148,9 @@ var LwrViewHandler = class {
148
148
  throw (0, import_diagnostics.createSingleDiagnosticError)({description: import_diagnostics.descriptions.APPLICATION.ROUTE_HANDLER_ERROR(route.id, message)}, import_diagnostics.LwrApplicationError);
149
149
  }
150
150
  });
151
+ if (response?.locale) {
152
+ runtimeParams.locale = response.locale;
153
+ }
151
154
  return response;
152
155
  }
153
156
  getBoundApi(viewRequest, route, runtimeEnvironment, runtimeParams) {
package/build/es/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import { InflightTasks, createStringBuilder, extractMetadataFromHtml, getCacheKeyFromJson, getSpecifier, normalizeResourcePath, shortestTtl, } from '@lwrjs/shared-utils';
1
+ import { InflightTasks, createStringBuilder, extractMetadataFromHtml, getCacheKeyFromJson, getSpecifier, isLocalDev, normalizeResourcePath, shortestTtl, } from '@lwrjs/shared-utils';
2
2
  import { getTracer, ViewSpan } from '@lwrjs/instrumentation';
3
- import { normalizeRenderOptions, normalizeRenderedResult, reduceSourceAssetReferences } from './utils.js';
3
+ import { generateViewNonce, getViewNonce, normalizeRenderOptions, normalizeRenderedResult, reduceSourceAssetReferences, } from './utils.js';
4
4
  import { linkLwrResources } from './linkers/link-lwr-resources.js';
5
5
  import { LRUCache } from 'lru-cache';
6
6
  import { DiagnosticsError, LwrServerError, createSingleDiagnosticError, descriptions, logger, } from '@lwrjs/diagnostics';
@@ -37,7 +37,7 @@ export class LwrViewRegistry {
37
37
  }
38
38
  async onModuleDefinitionChange(moduleDefinition) {
39
39
  // TODO we will make this more robust in the future w/ full MRT HMR
40
- if (process.env.MRT_HMR === 'true') {
40
+ if (isLocalDev()) {
41
41
  this.viewDefinitions.clear();
42
42
  return;
43
43
  }
@@ -63,7 +63,7 @@ export class LwrViewRegistry {
63
63
  }
64
64
  async onViewSourceChange(compiledView) {
65
65
  // TODO we will make this more robust in the future w/ full MRT HMR
66
- if (process.env.MRT_HMR === 'true') {
66
+ if (isLocalDev()) {
67
67
  this.viewDefinitions.clear();
68
68
  return;
69
69
  }
@@ -152,7 +152,7 @@ export class LwrViewRegistry {
152
152
  debug: runtimeEnvironment.debug,
153
153
  });
154
154
  logger.debug(`[view-registry][hasViewDefinition] viewDefId=${viewDefId}`);
155
- // viewParams is an unbounded object and can be very large (17MB/view for developer.salesforce.com). Allowing conusmers
155
+ // viewParams is an unbounded object and can be very large (17MB/view for developer.salesforce.com). Allowing consumers
156
156
  // to provide a simple override avoids the excess memory / performance overhead of serializing & storing the viewParams
157
157
  // on every request, while still reusing our caching logic.
158
158
  const viewParamKey = viewParamCacheKey
@@ -196,6 +196,9 @@ export class LwrViewRegistry {
196
196
  return viewDefinition.viewDefinition;
197
197
  }
198
198
  }
199
+ // If we missed cache generate a nonce in the page context (we do not want it part of the cache key)
200
+ const updatableViewParams = { ...viewParams };
201
+ generateViewNonce(updatableViewParams);
199
202
  const pendingViewDefCacheKey = viewDefCacheKey + viewParamKey;
200
203
  const viewDefinition = await this.pendingViewDefinitions.execute(pendingViewDefCacheKey, () => getTracer().trace({
201
204
  name: ViewSpan.RenderView,
@@ -203,7 +206,9 @@ export class LwrViewRegistry {
203
206
  view: view.id,
204
207
  ssr: view.bootstrap?.ssr === true,
205
208
  },
206
- }, () => this.renderView(view, viewParams, runtimeEnvironment, runtimeParams, renderOptions)));
209
+ }, () => this.renderView(view, updatableViewParams, runtimeEnvironment, runtimeParams, renderOptions)));
210
+ // Once the view is generated add the nonce to the response so it can be cached and then added to the headers
211
+ viewDefinition.nonce = getViewNonce(updatableViewParams);
207
212
  if (cacheDisabled === false) {
208
213
  const route = this.globalConfig.routes.find((r) => r.id === view.id);
209
214
  const ttl = shortestTtl(viewDefinition.cache?.ttl, route?.cache?.ttl);
@@ -1,7 +1,7 @@
1
1
  import { logger } from '@lwrjs/diagnostics';
2
2
  import { kebabCaseToModuleSpecifier, getModuleGraphs, GraphDepth, getModuleUriPrefix, explodeSpecifier, isBundler, getHydrateDirective, isGroupie, isExternalSpecifier, } from '@lwrjs/shared-utils';
3
3
  import { AppResourceEnum, getAppSpecifier } from '@lwrjs/app-service/identity';
4
- import { generateHtmlTag, getModuleResourceByUri } from '../utils.js';
4
+ import { addExternalScriptNonce, generateHtmlTag, getModuleResourceByUri, getViewNonce } from '../utils.js';
5
5
  import { flattenCustomElements, getViewBootstrapConfigurationResource, getViewHmrConfigurationResource, } from './utils.js';
6
6
  import { setPreloadModulesMeta, getPreloadModulesMeta } from './preload-utils.js';
7
7
  function includeIdFactory(bundleConfig) {
@@ -92,6 +92,8 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
92
92
  };
93
93
  // Determine if server side rendering view modules
94
94
  const isSSR = view.bootstrap?.ssr;
95
+ // Page level nonce for script tags
96
+ const nonce = getViewNonce(viewParams);
95
97
  // ABS module and custom element references
96
98
  let bootstrapModuleRef, versionedSpecifier = bootstrapSpecifier;
97
99
  const customElementsRecords = [];
@@ -126,6 +128,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
126
128
  if (!def.inline && !def.src) {
127
129
  throw Error(`Invalid Shim ${shimBundle}: ${JSON.stringify(def)}`);
128
130
  }
131
+ addExternalScriptNonce(def, nonce);
129
132
  requiredResources.push(def);
130
133
  // Always inline the error shim script after the shim
131
134
  const errorShimDef = (await resourceRegistry.getResource({ specifier: 'lwr-error-shim.js', version }, runtimeEnvironment, runtimeParams));
@@ -136,6 +139,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
136
139
  if (!errorShimDef.inline && !errorShimDef.src) {
137
140
  throw Error(`Invalid Shim lwr-error-shim.js: ${JSON.stringify(errorShimDef)}`);
138
141
  }
142
+ addExternalScriptNonce(errorShimDef, nonce);
139
143
  requiredResources.push(errorShimDef);
140
144
  }
141
145
  // ------- Application Bootstrap module
@@ -155,7 +159,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
155
159
  if (!uri) {
156
160
  throw Error(`Invalid Module Resource ${versionedSpecifier}`);
157
161
  }
158
- moduleResources.push(getModuleResourceByUri(uri, runtimeEnvironment, { isPreload: false, isSSR }));
162
+ moduleResources.push(getModuleResourceByUri(uri, runtimeEnvironment, { isPreload: false, isSSR, nonce }));
159
163
  // PRELOAD the bootstrap module static dependencies as preloaded script resources
160
164
  for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
161
165
  const uri = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
@@ -265,7 +269,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
265
269
  const dedupedUris = [...new Set(viewPreloads.uris)];
266
270
  // PRELOAD script resources for preload module URIs after the bootstrap module
267
271
  for (const preloadUri of dedupedUris) {
268
- moduleResources.push(getModuleResourceByUri(preloadUri, runtimeEnvironment, { isPreload: true, isSSR }));
272
+ moduleResources.push(getModuleResourceByUri(preloadUri, runtimeEnvironment, { isPreload: true, isSSR, nonce }));
269
273
  }
270
274
  // generate html partial
271
275
  const htmlResources = await Promise.all([...configResources, ...requiredResources, ...moduleResources].map(generateHtmlTag));
@@ -1,7 +1,7 @@
1
1
  import { logger } from '@lwrjs/diagnostics';
2
2
  import { kebabCaseToModuleSpecifier, toImportMetadata, getModuleGraphs, getMappingUriPrefix, GraphDepth, explodeSpecifier, isBundler, getHydrateDirective, isGroupie, } from '@lwrjs/shared-utils';
3
3
  import { AppResourceEnum, getAppSpecifier } from '@lwrjs/app-service/identity';
4
- import { generateHtmlTag, getModuleResourceByUri } from '../utils.js';
4
+ import { addExternalScriptNonce, generateHtmlTag, getModuleResourceByUri, getViewNonce } from '../utils.js';
5
5
  import { flattenCustomElements, getViewBootstrapConfigurationResource, getViewHmrConfigurationResource, } from './utils.js';
6
6
  import { setPreloadModulesMeta, getPreloadModulesMeta } from './preload-utils.js';
7
7
  export async function getHtmlResources(view, viewParams, resourceContext) {
@@ -75,6 +75,8 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
75
75
  };
76
76
  // Determine if server side rendering view modules
77
77
  const isSSR = view.bootstrap?.ssr;
78
+ // Page level nonce for script tags
79
+ const nonce = getViewNonce(viewParams);
78
80
  // ABS module and custom element references
79
81
  let bootstrapModuleRef, versionedSpecifier = bootstrapSpecifier;
80
82
  let importMetadata = { imports: {} };
@@ -94,6 +96,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
94
96
  if (!def.inline && !def.src) {
95
97
  throw Error(`Invalid Shim ${shimBundle}: ${JSON.stringify(def)}`);
96
98
  }
99
+ addExternalScriptNonce(def, nonce);
97
100
  requiredResources.push(def);
98
101
  // Always inline the error shim script after the shim
99
102
  const errorShimDef = (await resourceRegistry.getResource({ specifier: 'lwr-error-shim.js', version }, runtimeEnvironment, runtimeParams));
@@ -104,6 +107,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
104
107
  if (!errorShimDef.inline && !errorShimDef.src) {
105
108
  throw Error(`Invalid Shim lwr-error-shim.js: ${JSON.stringify(errorShimDef)}`);
106
109
  }
110
+ addExternalScriptNonce(errorShimDef, nonce);
107
111
  requiredResources.push(errorShimDef);
108
112
  }
109
113
  // ------- Application Bootstrap module
@@ -122,7 +126,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
122
126
  if (!uri) {
123
127
  throw Error(`Invalid Module Resource ${versionedSpecifier}`);
124
128
  }
125
- moduleResources.push(getModuleResourceByUri(uri, runtimeEnvironment, { isPreload: false, isSSR }));
129
+ moduleResources.push(getModuleResourceByUri(uri, runtimeEnvironment, { isPreload: false, isSSR, nonce }));
126
130
  // PRELOAD the bootstrap module static dependencies as preloaded script resources
127
131
  for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
128
132
  const uri = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
@@ -234,7 +238,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
234
238
  // PRELOAD script resources for preload module URIs after the bootstrap module
235
239
  const dedupedUris = [...new Set(viewPreloads.uris)];
236
240
  for (const preloadUri of dedupedUris) {
237
- moduleResources.push(getModuleResourceByUri(preloadUri, runtimeEnvironment, { isPreload: true, isSSR }));
241
+ moduleResources.push(getModuleResourceByUri(preloadUri, runtimeEnvironment, { isPreload: true, isSSR, nonce }));
238
242
  }
239
243
  // generate html partial
240
244
  const htmlResources = await Promise.all([...configResources, ...requiredResources, ...moduleResources].map(generateHtmlTag));
@@ -1,4 +1,4 @@
1
- import type { AssetReference, JsonCompatible, LinkedViewDefinition, LwrErrorRoute, LwrRoute, ModuleBundler, ModuleId, ModuleJson, ModuleRegistry, NormalizedRenderingResult, PublicModuleRegistry, RenderOptions, RenderedAssetReference, RenderingResult, ResourceDefinition, RouteHandlerViewResponse, RuntimeEnvironment, RuntimeParams, ViewModuleResourceContext, ViewPageContext, ViewRequest, ViewResponse } from '@lwrjs/types';
1
+ import type { AssetReference, JsonCompatible, LinkedViewDefinition, LwrErrorRoute, LwrRoute, ModuleBundler, ModuleId, ModuleJson, ModuleRegistry, NormalizedRenderingResult, PublicModuleRegistry, RenderOptions, RenderedAssetReference, RenderingResult, ResourceDefinition, RouteHandlerViewResponse, RuntimeEnvironment, RuntimeParams, ViewModuleResourceContext, ViewPageContext, ViewParams, ViewRequest, ViewResponse } from '@lwrjs/types';
2
2
  export type HTMLResource = Partial<ResourceDefinition>;
3
3
  export declare function generateHtmlTag(definition: HTMLResource): Promise<string>;
4
4
  export declare function normalizeRenderedResult({ renderedView, metadata, options, cache, }: RenderingResult): NormalizedRenderingResult;
@@ -10,4 +10,16 @@ export declare function toJsonFormat(viewRequest: ViewRequest, viewDefinition: L
10
10
  export declare function getModuleResource(moduleId: Pick<ModuleId, 'specifier' | 'version'>, runtimeEnvironment: RuntimeEnvironment, moduleResourceMeta: ViewModuleResourceContext, defRegistry: ModuleRegistry | ModuleBundler, runtimeParams: RuntimeParams): Promise<ResourceDefinition>;
11
11
  export declare function getModuleResourceByUri(uri: string, runtimeEnvironment: RuntimeEnvironment, moduleResourceMeta: ViewModuleResourceContext): ResourceDefinition;
12
12
  export declare function createJsonModule(specifier: string, moduleRegistry: PublicModuleRegistry, environment: RuntimeEnvironment, params: RuntimeParams): Promise<ModuleJson>;
13
+ /**
14
+ * Get the nonce set on the page context of the view params
15
+ */
16
+ export declare function getViewNonce(viewParams: ViewParams): string;
17
+ /**
18
+ * Generate a nonce in the page context of the view params
19
+ */
20
+ export declare function generateViewNonce(viewParams: ViewParams): void;
21
+ /**
22
+ * Add a nonce to a script definition in view if it is external (not inline)
23
+ */
24
+ export declare function addExternalScriptNonce(def: ResourceDefinition, nonce: string): void;
13
25
  //# sourceMappingURL=utils.d.ts.map
package/build/es/utils.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import { basename, extname } from 'path';
2
2
  import { explodeSpecifier, getMappingUriPrefix, getSpecifier, getClientBootstrapConfigurationUri, mimeLookup, DEFAULT_TITLE, streamToString, } from '@lwrjs/shared-utils';
3
3
  import { AppResourceEnum, getAppSpecifier, ResourceIdentityTypes, } from '@lwrjs/app-service/identity';
4
+ import crypto from 'crypto';
4
5
  function generateExternalStyle(src) {
5
6
  return `<link rel="stylesheet" href="${src}">`;
6
7
  }
7
- function generateExternalScript(type = 'application/javascript', src, async, defer) {
8
+ function generateExternalScript(type = 'application/javascript', src, async, defer, nonce) {
8
9
  let scriptLoadOrder = '';
9
10
  if (defer) {
10
11
  scriptLoadOrder = ' defer';
@@ -12,7 +13,8 @@ function generateExternalScript(type = 'application/javascript', src, async, def
12
13
  else if (async) {
13
14
  scriptLoadOrder = ' async';
14
15
  }
15
- return `<script type="${type}"${scriptLoadOrder} src="${src}"></script>`;
16
+ const nonceAttr = nonce ? ` nonce="${nonce}"` : '';
17
+ return `<script type="${type}"${scriptLoadOrder}${nonceAttr} src="${src}"></script>`;
16
18
  }
17
19
  function generateLinkPreloadTag({ href, type }) {
18
20
  if (type === 'module') {
@@ -22,7 +24,7 @@ function generateLinkPreloadTag({ href, type }) {
22
24
  return `<link rel="preload" href="${href}" type="${type}" />`;
23
25
  }
24
26
  }
25
- function generateExternalTag({ type, src = '', async, defer, isPreload }) {
27
+ function generateExternalTag({ type, src = '', async, defer, isPreload, nonce }) {
26
28
  if (isPreload) {
27
29
  return generateLinkPreloadTag({ href: src, type: type });
28
30
  }
@@ -30,7 +32,7 @@ function generateExternalTag({ type, src = '', async, defer, isPreload }) {
30
32
  return generateExternalStyle(src);
31
33
  }
32
34
  else {
33
- return generateExternalScript(type, src, async, defer);
35
+ return generateExternalScript(type, src, async, defer, nonce);
34
36
  }
35
37
  }
36
38
  async function generateInlineTag({ specifier, type, content, stream, nonce }) {
@@ -203,7 +205,7 @@ export async function getModuleResource(moduleId, runtimeEnvironment, moduleReso
203
205
  };
204
206
  }
205
207
  export function getModuleResourceByUri(uri, runtimeEnvironment, moduleResourceMeta) {
206
- const { isSSR = false, isPreload = false } = moduleResourceMeta;
208
+ const { isSSR = false, isPreload = false, nonce } = moduleResourceMeta;
207
209
  const { format } = runtimeEnvironment;
208
210
  return {
209
211
  src: uri,
@@ -213,6 +215,7 @@ export function getModuleResourceByUri(uri, runtimeEnvironment, moduleResourceMe
213
215
  // only use link preload for ESM for compat reasons.
214
216
  // AMD should use regular script tags for preloading
215
217
  isPreload: format !== 'amd' && isPreload,
218
+ nonce,
216
219
  };
217
220
  }
218
221
  // Given a specifier and resource type, return the JSON serialized Module data
@@ -236,4 +239,30 @@ export async function createJsonModule(specifier, moduleRegistry, environment, p
236
239
  },
237
240
  };
238
241
  }
242
+ /**
243
+ * Get the nonce set on the page context of the view params
244
+ */
245
+ export function getViewNonce(viewParams) {
246
+ return viewParams?.page?.nonce;
247
+ }
248
+ /**
249
+ * Generate a nonce in the page context of the view params
250
+ */
251
+ export function generateViewNonce(viewParams) {
252
+ const nonce = crypto.randomBytes(16).toString('base64');
253
+ if (!viewParams.page) {
254
+ viewParams.page = { nonce };
255
+ }
256
+ else {
257
+ viewParams.page.nonce = nonce;
258
+ }
259
+ }
260
+ /**
261
+ * Add a nonce to a script definition in view if it is external (not inline)
262
+ */
263
+ export function addExternalScriptNonce(def, nonce) {
264
+ if (!def.inline) {
265
+ def.nonce = nonce;
266
+ }
267
+ }
239
268
  //# sourceMappingURL=utils.js.map
@@ -165,6 +165,10 @@ export class LwrViewHandler {
165
165
  throw createSingleDiagnosticError({ description: descriptions.APPLICATION.ROUTE_HANDLER_ERROR(route.id, message) }, LwrApplicationError);
166
166
  }
167
167
  });
168
+ // if the locale was returned by the route handler update the runtime time params
169
+ if (response?.locale) {
170
+ runtimeParams.locale = response.locale;
171
+ }
168
172
  return response;
169
173
  }
170
174
  /*
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.13.0-alpha.0",
7
+ "version": "0.13.0-alpha.10",
8
8
  "homepage": "https://developer.salesforce.com/docs/platform/lwr/overview",
9
9
  "repository": {
10
10
  "type": "git",
@@ -30,17 +30,17 @@
30
30
  "build/**/*.d.ts"
31
31
  ],
32
32
  "dependencies": {
33
- "@lwrjs/app-service": "0.13.0-alpha.0",
34
- "@lwrjs/diagnostics": "0.13.0-alpha.0",
35
- "@lwrjs/instrumentation": "0.13.0-alpha.0",
36
- "@lwrjs/shared-utils": "0.13.0-alpha.0",
37
- "lru-cache": "^10.2.0"
33
+ "@lwrjs/app-service": "0.13.0-alpha.10",
34
+ "@lwrjs/diagnostics": "0.13.0-alpha.10",
35
+ "@lwrjs/instrumentation": "0.13.0-alpha.10",
36
+ "@lwrjs/shared-utils": "0.13.0-alpha.10",
37
+ "lru-cache": "^10.2.2"
38
38
  },
39
39
  "devDependencies": {
40
- "@lwrjs/types": "0.13.0-alpha.0"
40
+ "@lwrjs/types": "0.13.0-alpha.10"
41
41
  },
42
42
  "engines": {
43
43
  "node": ">=18.0.0"
44
44
  },
45
- "gitHead": "c5fe8db55c74513dbb0937d1b4568109715a13fb"
45
+ "gitHead": "53e2a825868b4c9b1662419b531c80be13afd779"
46
46
  }