@lwrjs/view-registry 0.13.0-alpha.2 → 0.13.0-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.
@@ -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
  }
@@ -161,7 +161,8 @@ var LwrViewRegistry = class {
161
161
  freezeAssets,
162
162
  locale: runtimeParams?.locale,
163
163
  basePath: runtimeParams?.basePath,
164
- debug: runtimeEnvironment.debug
164
+ debug: runtimeEnvironment.debug,
165
+ nonceEnabled: (0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE
165
166
  });
166
167
  import_diagnostics.logger.debug(`[view-registry][hasViewDefinition] viewDefId=${viewDefId}`);
167
168
  const viewParamKey = viewParamCacheKey ? (0, import_shared_utils.getCacheKeyFromJson)(viewParamCacheKey) : (0, import_shared_utils.getCacheKeyFromJson)(viewParams);
@@ -182,7 +183,8 @@ var LwrViewRegistry = class {
182
183
  freezeAssets,
183
184
  locale: runtimeParams?.locale,
184
185
  basePath: runtimeParams?.basePath,
185
- debug: runtimeEnvironment.debug
186
+ debug: runtimeEnvironment.debug,
187
+ nonceEnabled: (0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE
186
188
  });
187
189
  import_diagnostics.logger.debug(`[view-registry][getViewDefinition] viewDefCacheKey=${viewDefCacheKey}`);
188
190
  const viewParamKey = viewParamCacheKey ? (0, import_shared_utils.getCacheKeyFromJson)(viewParamCacheKey) : (0, import_shared_utils.getCacheKeyFromJson)(viewParams);
@@ -194,6 +196,8 @@ var LwrViewRegistry = class {
194
196
  return viewDefinition2.viewDefinition;
195
197
  }
196
198
  }
199
+ const updatableViewParams = {...viewParams};
200
+ (0, import_utils.generateViewNonce)(updatableViewParams);
197
201
  const pendingViewDefCacheKey = viewDefCacheKey + viewParamKey;
198
202
  const viewDefinition = await this.pendingViewDefinitions.execute(pendingViewDefCacheKey, () => (0, import_instrumentation.getTracer)().trace({
199
203
  name: import_instrumentation.ViewSpan.RenderView,
@@ -201,10 +205,12 @@ var LwrViewRegistry = class {
201
205
  view: view.id,
202
206
  ssr: view.bootstrap?.ssr === true
203
207
  }
204
- }, () => this.renderView(view, viewParams, runtimeEnvironment, runtimeParams, renderOptions)));
208
+ }, () => this.renderView(view, updatableViewParams, runtimeEnvironment, runtimeParams, renderOptions)));
209
+ viewDefinition.nonce = (0, import_utils.getViewNonce)(updatableViewParams);
205
210
  if (cacheDisabled === false) {
206
211
  const route = this.globalConfig.routes.find((r) => r.id === view.id);
207
- const ttl = (0, import_shared_utils.shortestTtl)(viewDefinition.cache?.ttl, route?.cache?.ttl);
212
+ const maxTtl = process.env.MAX_VIEW_CACHE_TTL && parseInt(process.env.MAX_VIEW_CACHE_TTL, 10);
213
+ const ttl = (0, import_shared_utils.shortestTtl)(viewDefinition.cache?.ttl, route?.cache?.ttl, maxTtl);
208
214
  if (ttl !== 0) {
209
215
  this.viewDefinitions.set(viewDefCacheKey, {
210
216
  view,
@@ -227,7 +233,7 @@ var LwrViewRegistry = class {
227
233
  async renderView(view, viewParams, runtimeEnvironment, runtimeParams = {}, renderOptions) {
228
234
  const {id, contentTemplate, rootComponent, layoutTemplate} = view;
229
235
  const lwrResourcesId = `__LWR_RESOURCES__${Date.now()}`;
230
- const renderedContent = await this.render({id, contentTemplate, rootComponent}, {...viewParams, lwr_resources: lwrResourcesId}, runtimeParams, renderOptions);
236
+ const renderedContent = await this.render({id, contentTemplate, rootComponent}, {...viewParams, lwr_resources: lwrResourcesId}, runtimeParams, runtimeEnvironment, renderOptions);
231
237
  let normalizedRenderOptions = (0, import_utils.normalizeRenderOptions)(this.runtimeEnvironment, renderedContent.options, renderOptions);
232
238
  const layout = layoutTemplate || renderedContent.compiledView.layoutTemplate;
233
239
  if (!layout) {
@@ -247,7 +253,7 @@ var LwrViewRegistry = class {
247
253
  ...viewParams,
248
254
  body: renderedContent.renderedView,
249
255
  lwr_resources: lwrResourcesId
250
- }, runtimeParams);
256
+ }, runtimeParams, runtimeEnvironment);
251
257
  normalizedRenderOptions = (0, import_utils.normalizeRenderOptions)(this.runtimeEnvironment, renderedLayout.options, normalizedRenderOptions);
252
258
  const renderedViewDef = await this.link({
253
259
  ...renderedLayout,
@@ -285,7 +291,7 @@ var LwrViewRegistry = class {
285
291
  });
286
292
  return renderedViewDef;
287
293
  }
288
- async render(viewId, viewParams, runtimeParams, renderOptions) {
294
+ async render(viewId, viewParams, runtimeParams, runtimeEnvironment, renderOptions) {
289
295
  const globalContext = this.globalData;
290
296
  const {id, rootComponent, contentTemplate} = viewId;
291
297
  const compiledView = await this.getView({id, contentTemplate, rootComponent}, renderOptions?.skipCaching);
@@ -294,7 +300,7 @@ var LwrViewRegistry = class {
294
300
  ...globalContext,
295
301
  ...compiledView.properties,
296
302
  ...viewParams
297
- });
303
+ }, runtimeEnvironment);
298
304
  const normalizedResult = (0, import_utils.normalizeRenderedResult)(result);
299
305
  return {
300
306
  compiledView,
@@ -360,7 +366,8 @@ var LwrViewRegistry = class {
360
366
  renderedView: linkedAssetContent,
361
367
  immutable,
362
368
  viewRecord: {
363
- assetReferences: (0, import_utils.reduceSourceAssetReferences)(linkedMetadata.assetReferences)
369
+ assetReferences: (0, import_utils.reduceSourceAssetReferences)(linkedMetadata.assetReferences),
370
+ moduleResources: []
364
371
  },
365
372
  cache: {ttl: pageTtl}
366
373
  };
@@ -49,9 +49,8 @@ async function getHtmlResources(view, viewParams, resourceContext) {
49
49
  resourceRegistry,
50
50
  viewMetadata
51
51
  } = resourceContext;
52
- const {lwrVersion, format, hmrEnabled, bundle, debug, minify} = runtimeEnvironment;
52
+ const {format, hmrEnabled, bundle, debug, minify} = runtimeEnvironment;
53
53
  const {customElements, serverData, serverDebug} = viewMetadata;
54
- const version = lwrVersion;
55
54
  const isAMD = format === "amd";
56
55
  const {bundleConfig} = resourceContext;
57
56
  const {external = {}, exclude = []} = bundleConfig;
@@ -98,9 +97,12 @@ async function getHtmlResources(view, viewParams, resourceContext) {
98
97
  const viewPreloads = {
99
98
  uris: [],
100
99
  specifiers: [],
101
- groups: new Map()
100
+ groups: new Map(),
101
+ integrities: new Map()
102
102
  };
103
103
  const isSSR = view.bootstrap?.ssr;
104
+ const version = view.bootstrap?.lwrVersion;
105
+ const nonce = (0, import_utils.getViewNonce)(viewParams);
104
106
  let bootstrapModuleRef, versionedSpecifier = bootstrapSpecifier;
105
107
  const customElementsRecords = [];
106
108
  const flattenedElements = (0, import_utils2.flattenCustomElements)(customElements, isSSR);
@@ -125,6 +127,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
125
127
  if (!def.inline && !def.src) {
126
128
  throw Error(`Invalid Shim ${shimBundle}: ${JSON.stringify(def)}`);
127
129
  }
130
+ (0, import_utils.addExternalScriptNonce)(def, nonce);
128
131
  requiredResources.push(def);
129
132
  const errorShimDef = await resourceRegistry.getResource({specifier: "lwr-error-shim.js", version}, runtimeEnvironment, runtimeParams);
130
133
  if (!errorShimDef) {
@@ -133,6 +136,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
133
136
  if (!errorShimDef.inline && !errorShimDef.src) {
134
137
  throw Error(`Invalid Shim lwr-error-shim.js: ${JSON.stringify(errorShimDef)}`);
135
138
  }
139
+ (0, import_utils.addExternalScriptNonce)(errorShimDef, nonce);
136
140
  requiredResources.push(errorShimDef);
137
141
  }
138
142
  const bootstrapModuleGraph = await (0, import_shared_utils.getModuleGraphs)(bootstrapSpecifier, {includeUris: true, includeLinkedDefinitions: true, depth}, moduleRegistry, defRegistry, runtimeEnvironment, runtimeParams, visitedCache);
@@ -146,11 +150,13 @@ async function getHtmlResources(view, viewParams, resourceContext) {
146
150
  if (!uri) {
147
151
  throw Error(`Invalid Module Resource ${versionedSpecifier}`);
148
152
  }
149
- moduleResources.push((0, import_utils.getModuleResourceByUri)(uri, runtimeEnvironment, {isPreload: false, isSSR}));
153
+ const integrity = (0, import_utils2.getBundleIntegrity)(bootstrapModuleGraph, versionedSpecifier);
154
+ moduleResources.push((0, import_utils.getModuleResourceByUri)(uri, runtimeEnvironment, {integrity, isPreload: false, isSSR, nonce}));
150
155
  for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
151
156
  const uri2 = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
152
157
  if (uri2) {
153
- (0, import_preload_utils.setPreloadModulesMeta)(depSpecifier, uri2, groups, viewPreloads);
158
+ const integrity2 = (0, import_utils2.getBundleIntegrity)(bootstrapModuleGraph, depSpecifier);
159
+ (0, import_preload_utils.setPreloadModulesMeta)(depSpecifier, uri2, integrity2, groups, viewPreloads);
154
160
  }
155
161
  }
156
162
  if ((0, import_shared_utils.isBundler)(defRegistry)) {
@@ -187,12 +193,14 @@ async function getHtmlResources(view, viewParams, resourceContext) {
187
193
  if (!isSSR || (0, import_shared_utils.getHydrateDirective)(props)) {
188
194
  const specifier = graph.graphs[0].specifier;
189
195
  const uri = graph.uriMap[specifier];
190
- (0, import_preload_utils.setPreloadModulesMeta)(specifier, uri, groups, viewPreloads);
196
+ const integrity = (0, import_utils2.getBundleIntegrity)(graph, specifier);
197
+ (0, import_preload_utils.setPreloadModulesMeta)(specifier, uri, integrity, groups, viewPreloads);
191
198
  if (bundle) {
192
199
  for (const depSpecifier of graph.graphs[0].static) {
193
- const uri2 = getPreloadUri(depSpecifier, graph.uriMap);
194
- if (uri2) {
195
- (0, import_preload_utils.setPreloadModulesMeta)(depSpecifier, uri2, groups, viewPreloads);
200
+ const depUri = getPreloadUri(depSpecifier, graph.uriMap);
201
+ if (depUri) {
202
+ const integrity2 = (0, import_utils2.getBundleIntegrity)(graph, depSpecifier);
203
+ (0, import_preload_utils.setPreloadModulesMeta)(depSpecifier, depUri, integrity2, groups, viewPreloads);
196
204
  }
197
205
  }
198
206
  }
@@ -211,6 +219,13 @@ async function getHtmlResources(view, viewParams, resourceContext) {
211
219
  }
212
220
  }));
213
221
  if (viewContainsLiveElements) {
222
+ if ((0, import_shared_utils.isLocalDev)()) {
223
+ const localDevSpecifier = "lwr_local_dev/bootstrap";
224
+ rootComponents.push(localDevSpecifier);
225
+ const localDevMod = await (0, import_utils.getModuleResource)({specifier: localDevSpecifier, version: ""}, runtimeEnvironment, {}, moduleRegistry, runtimeParams);
226
+ if (localDevMod.src)
227
+ imports[localDevSpecifier] = localDevMod.src;
228
+ }
214
229
  configResources.unshift((0, import_utils2.getViewBootstrapConfigurationResource)({
215
230
  id: view.id,
216
231
  url: viewParams?.page?.url,
@@ -235,7 +250,13 @@ async function getHtmlResources(view, viewParams, resourceContext) {
235
250
  }
236
251
  const dedupedUris = [...new Set(viewPreloads.uris)];
237
252
  for (const preloadUri of dedupedUris) {
238
- moduleResources.push((0, import_utils.getModuleResourceByUri)(preloadUri, runtimeEnvironment, {isPreload: true, isSSR}));
253
+ const integrity = viewPreloads.integrities.get(preloadUri);
254
+ moduleResources.push((0, import_utils.getModuleResourceByUri)(preloadUri, runtimeEnvironment, {
255
+ integrity,
256
+ isPreload: true,
257
+ isSSR,
258
+ nonce
259
+ }));
239
260
  }
240
261
  const htmlResources = await Promise.all([...configResources, ...requiredResources, ...moduleResources].map(import_utils.generateHtmlTag));
241
262
  return {
@@ -243,6 +264,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
243
264
  viewRecord: {
244
265
  resources: requiredResources,
245
266
  customElements: customElementsRecords,
267
+ moduleResources,
246
268
  bootstrapModule: bootstrapModuleRef
247
269
  }
248
270
  };
@@ -29,7 +29,7 @@ __export(exports, {
29
29
  });
30
30
  var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
31
31
  var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
32
- function setPreloadModulesMeta(specifier, uri, groups, preloads) {
32
+ function setPreloadModulesMeta(specifier, uri, integrity, groups, preloads) {
33
33
  if (!uri) {
34
34
  throw (0, import_diagnostics.createSingleDiagnosticError)({
35
35
  description: import_diagnostics.descriptions.UNRESOLVABLE.PRELOAD_MODULE(specifier)
@@ -41,6 +41,7 @@ function setPreloadModulesMeta(specifier, uri, groups, preloads) {
41
41
  const preloadModulesSpecifiers = preloads.specifiers;
42
42
  const preloadBundleGroupsMap = preloads.groups;
43
43
  const preloadModulesURIs = preloads.uris;
44
+ const preloadModuleIntegrities = preloads.integrities;
44
45
  preloadModulesSpecifiers.push(specifier);
45
46
  const {specifier: unversionedSpecifier} = (0, import_shared_utils.explodeSpecifier)(specifier);
46
47
  const groupName = (0, import_shared_utils.getGroupName)(unversionedSpecifier, groups);
@@ -49,6 +50,7 @@ function setPreloadModulesMeta(specifier, uri, groups, preloads) {
49
50
  }
50
51
  preloadModulesURIs.push(uri);
51
52
  groupName && preloadBundleGroupsMap.set(groupName, true);
53
+ preloadModuleIntegrities.set(uri, integrity);
52
54
  }
53
55
  async function getPreloadModulesMeta(specifier, viewPreloads, bundleConfig, moduleRegistry, defRegistry, runtimeEnvironment, runtimeParams, pending) {
54
56
  const {exclude = [], external = {}, groups = {}} = bundleConfig;
@@ -72,9 +74,10 @@ async function getPreloadModulesMeta(specifier, viewPreloads, bundleConfig, modu
72
74
  });
73
75
  const uri = await defRegistry.resolveModuleUri(versionedModuleId, runtimeEnvironment, runtimeParams);
74
76
  const normalizedSpecifier = versionedModuleId.version === import_shared_utils.VERSION_NOT_PROVIDED ? specifier : versionedModuleSpecifier;
75
- setPreloadModulesMeta(normalizedSpecifier, uri, groups, viewPreloads);
77
+ const preloadModuleRecord = await defRegistry.getModuleBundle(versionedModuleId, runtimeEnvironment, runtimeParams);
78
+ const {integrity} = preloadModuleRecord;
79
+ setPreloadModulesMeta(normalizedSpecifier, uri, integrity, groups, viewPreloads);
76
80
  if (exclude.length || Object.keys(groups).length) {
77
- const preloadModuleRecord = await defRegistry.getModuleBundle(versionedModuleId, runtimeEnvironment, runtimeParams);
78
81
  const {imports} = preloadModuleRecord.bundleRecord;
79
82
  if (imports) {
80
83
  if (!pending) {
@@ -25,6 +25,7 @@ var __toModule = (module2) => {
25
25
  __markAsModule(exports);
26
26
  __export(exports, {
27
27
  flattenCustomElements: () => flattenCustomElements,
28
+ getBundleIntegrity: () => getBundleIntegrity,
28
29
  getViewBootstrapConfigurationResource: () => getViewBootstrapConfigurationResource,
29
30
  getViewHmrConfigurationResource: () => getViewHmrConfigurationResource
30
31
  });
@@ -72,6 +73,7 @@ function getViewBootstrapConfigurationResource(viewInfo, config, runtimeEnvironm
72
73
  type: CONTENT_TYPE,
73
74
  content: configString,
74
75
  inline: false,
76
+ integrity: (0, import_shared_utils.createIntegrityHash)(configString),
75
77
  src: url
76
78
  };
77
79
  } else {
@@ -129,3 +131,8 @@ function flattenCustomElements(arr, isSSR = false) {
129
131
  flatten(arr);
130
132
  return ret;
131
133
  }
134
+ function getBundleIntegrity(bootstrapModuleGraph, versionedSpecifier) {
135
+ const def = bootstrapModuleGraph.linkedDefinitions[versionedSpecifier];
136
+ const integrity = def?.integrity;
137
+ return integrity;
138
+ }
@@ -41,10 +41,9 @@ async function getHtmlResources(view, viewParams, resourceContext) {
41
41
  resourceRegistry,
42
42
  viewMetadata
43
43
  } = resourceContext;
44
- const {lwrVersion, format, hmrEnabled, bundle, debug, minify} = runtimeEnvironment;
44
+ const {format, hmrEnabled, bundle, debug, minify} = runtimeEnvironment;
45
45
  const {customElements, serverData, serverDebug} = viewMetadata;
46
46
  const defRegistry = bundle ? moduleBundler : moduleRegistry;
47
- const version = lwrVersion;
48
47
  const isAMD = format === "amd";
49
48
  const depth = isAMD ? {static: import_shared_utils.GraphDepth.ALL, dynamic: 1} : {static: import_shared_utils.GraphDepth.NONE, dynamic: 1};
50
49
  const {bundleConfig} = resourceContext;
@@ -87,9 +86,12 @@ async function getHtmlResources(view, viewParams, resourceContext) {
87
86
  const viewPreloads = {
88
87
  uris: [],
89
88
  specifiers: [],
90
- groups: new Map()
89
+ groups: new Map(),
90
+ integrities: new Map()
91
91
  };
92
92
  const isSSR = view.bootstrap?.ssr;
93
+ const version = view.bootstrap?.lwrVersion;
94
+ const nonce = (0, import_utils.getViewNonce)(viewParams);
93
95
  let bootstrapModuleRef, versionedSpecifier = bootstrapSpecifier;
94
96
  let importMetadata = {imports: {}};
95
97
  const customElementsRecords = [];
@@ -105,6 +107,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
105
107
  if (!def.inline && !def.src) {
106
108
  throw Error(`Invalid Shim ${shimBundle}: ${JSON.stringify(def)}`);
107
109
  }
110
+ (0, import_utils.addExternalScriptNonce)(def, nonce);
108
111
  requiredResources.push(def);
109
112
  const errorShimDef = await resourceRegistry.getResource({specifier: "lwr-error-shim.js", version}, runtimeEnvironment, runtimeParams);
110
113
  if (!errorShimDef) {
@@ -113,6 +116,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
113
116
  if (!errorShimDef.inline && !errorShimDef.src) {
114
117
  throw Error(`Invalid Shim lwr-error-shim.js: ${JSON.stringify(errorShimDef)}`);
115
118
  }
119
+ (0, import_utils.addExternalScriptNonce)(errorShimDef, nonce);
116
120
  requiredResources.push(errorShimDef);
117
121
  }
118
122
  const bootstrapModuleGraph = await (0, import_shared_utils.getModuleGraphs)(bootstrapSpecifier, {includeUris: true, includeLinkedDefinitions: true, depth}, moduleRegistry, defRegistry, runtimeEnvironment, runtimeParams, visitedCache);
@@ -126,11 +130,13 @@ async function getHtmlResources(view, viewParams, resourceContext) {
126
130
  if (!uri) {
127
131
  throw Error(`Invalid Module Resource ${versionedSpecifier}`);
128
132
  }
129
- moduleResources.push((0, import_utils.getModuleResourceByUri)(uri, runtimeEnvironment, {isPreload: false, isSSR}));
133
+ const integrity = (0, import_utils2.getBundleIntegrity)(bootstrapModuleGraph, versionedSpecifier);
134
+ moduleResources.push((0, import_utils.getModuleResourceByUri)(uri, runtimeEnvironment, {integrity, isPreload: false, isSSR, nonce}));
130
135
  for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
131
136
  const uri2 = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
132
137
  if (uri2) {
133
- (0, import_preload_utils.setPreloadModulesMeta)(depSpecifier, uri2, groups, viewPreloads);
138
+ const integrity2 = (0, import_utils2.getBundleIntegrity)(bootstrapModuleGraph, depSpecifier);
139
+ (0, import_preload_utils.setPreloadModulesMeta)(depSpecifier, uri2, integrity2, groups, viewPreloads);
134
140
  }
135
141
  }
136
142
  if ((0, import_shared_utils.isBundler)(defRegistry)) {
@@ -168,12 +174,14 @@ async function getHtmlResources(view, viewParams, resourceContext) {
168
174
  if (!isSSR || (0, import_shared_utils.getHydrateDirective)(props)) {
169
175
  const specifier = graph.graphs[0].specifier;
170
176
  const uri = graph.uriMap[specifier];
171
- (0, import_preload_utils.setPreloadModulesMeta)(specifier, uri, groups, viewPreloads);
177
+ const integrity = (0, import_utils2.getBundleIntegrity)(graph, specifier);
178
+ (0, import_preload_utils.setPreloadModulesMeta)(specifier, uri, integrity, groups, viewPreloads);
172
179
  if (bundle) {
173
180
  for (const depSpecifier of graph.graphs[0].static) {
174
- const uri2 = getPreloadUri(depSpecifier, graph.uriMap);
175
- if (uri2) {
176
- (0, import_preload_utils.setPreloadModulesMeta)(depSpecifier, uri2, groups, viewPreloads);
181
+ const depUri = getPreloadUri(depSpecifier, graph.uriMap);
182
+ if (depUri) {
183
+ const integrity2 = (0, import_utils2.getBundleIntegrity)(graph, depSpecifier);
184
+ (0, import_preload_utils.setPreloadModulesMeta)(depSpecifier, depUri, integrity2, groups, viewPreloads);
177
185
  }
178
186
  }
179
187
  }
@@ -215,7 +223,13 @@ async function getHtmlResources(view, viewParams, resourceContext) {
215
223
  }
216
224
  const dedupedUris = [...new Set(viewPreloads.uris)];
217
225
  for (const preloadUri of dedupedUris) {
218
- moduleResources.push((0, import_utils.getModuleResourceByUri)(preloadUri, runtimeEnvironment, {isPreload: true, isSSR}));
226
+ const integrity = viewPreloads.integrities.get(preloadUri);
227
+ moduleResources.push((0, import_utils.getModuleResourceByUri)(preloadUri, runtimeEnvironment, {
228
+ integrity,
229
+ isPreload: true,
230
+ isSSR,
231
+ nonce
232
+ }));
219
233
  }
220
234
  const htmlResources = await Promise.all([...configResources, ...requiredResources, ...moduleResources].map(import_utils.generateHtmlTag));
221
235
  const mapping = (0, import_shared_utils.getMappingUriPrefix)(runtimeEnvironment, runtimeParams);
@@ -231,6 +245,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
231
245
  customElements: customElementsRecords,
232
246
  endpoints,
233
247
  importMetadata,
248
+ moduleResources,
234
249
  bootstrapModule: bootstrapModuleRef
235
250
  }
236
251
  };
@@ -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,26 @@ __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, integrity) {
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
+ let cspHashAttr = "";
56
+ if ((0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE) {
57
+ if (integrity) {
58
+ cspHashAttr = ` integrity="${integrity}"`;
59
+ } else if (nonce) {
60
+ cspHashAttr = ` nonce="${nonce}"`;
61
+ }
62
+ }
63
+ return `<script type="${type}"${scriptLoadOrder}${cspHashAttr} src="${src}"></script>`;
52
64
  }
53
65
  function generateLinkPreloadTag({href, type}) {
54
66
  if (type === "module") {
@@ -57,19 +69,27 @@ function generateLinkPreloadTag({href, type}) {
57
69
  return `<link rel="preload" href="${href}" type="${type}" />`;
58
70
  }
59
71
  }
60
- function generateExternalTag({type, src = "", async, defer, isPreload}) {
72
+ function generateExternalTag({
73
+ type,
74
+ src = "",
75
+ async,
76
+ defer,
77
+ isPreload,
78
+ nonce,
79
+ integrity
80
+ }) {
61
81
  if (isPreload) {
62
82
  return generateLinkPreloadTag({href: src, type});
63
83
  } else if (type === "text/css") {
64
84
  return generateExternalStyle(src);
65
85
  } else {
66
- return generateExternalScript(type, src, async, defer);
86
+ return generateExternalScript(type, src, async, defer, nonce, integrity);
67
87
  }
68
88
  }
69
89
  async function generateInlineTag({specifier, type, content, stream, nonce}) {
70
90
  const typeStr = type === "text/css" ? "" : ` type="${type}"`;
71
91
  const tag = type === "text/css" ? "style" : "script";
72
- const nonceStr = nonce ? ` nonce="${nonce}"` : "";
92
+ const nonceStr = (0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE && nonce && nonce ? ` nonce="${nonce}"` : "";
73
93
  if (!content && !stream) {
74
94
  throw new Error(`Invalid inline Resource Definition: must have either "content" or "stream": "${specifier}"`);
75
95
  }
@@ -223,14 +243,16 @@ async function getModuleResource(moduleId, runtimeEnvironment, moduleResourceMet
223
243
  };
224
244
  }
225
245
  function getModuleResourceByUri(uri, runtimeEnvironment, moduleResourceMeta) {
226
- const {isSSR = false, isPreload = false} = moduleResourceMeta;
246
+ const {integrity, isSSR = false, isPreload = false, nonce} = moduleResourceMeta;
227
247
  const {format} = runtimeEnvironment;
228
248
  return {
229
249
  src: uri,
230
250
  type: format === "amd" ? "application/javascript" : "module",
231
251
  async: !isSSR && isPreload,
232
252
  defer: isSSR,
233
- isPreload: format !== "amd" && isPreload
253
+ isPreload: format !== "amd" && isPreload,
254
+ integrity,
255
+ nonce
234
256
  };
235
257
  }
236
258
  async function createJsonModule(specifier, moduleRegistry, environment, params) {
@@ -252,3 +274,21 @@ async function createJsonModule(specifier, moduleRegistry, environment, params)
252
274
  }
253
275
  };
254
276
  }
277
+ function getViewNonce(viewParams) {
278
+ return (0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE ? viewParams?.page?.nonce : void 0;
279
+ }
280
+ function generateViewNonce(viewParams) {
281
+ if ((0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE) {
282
+ const nonce = import_crypto.default.randomBytes(16).toString("base64");
283
+ if (!viewParams.page) {
284
+ viewParams.page = {nonce};
285
+ } else {
286
+ viewParams.page.nonce = nonce;
287
+ }
288
+ }
289
+ }
290
+ function addExternalScriptNonce(def, nonce) {
291
+ if (nonce && (0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE && !def.inline) {
292
+ def.nonce = nonce;
293
+ }
294
+ }
@@ -130,6 +130,8 @@ var LwrViewHandler = class {
130
130
  const paths = {rootDir, assets, contentDir, layoutsDir};
131
131
  const locale = runtimeParams.locale;
132
132
  const basePath = runtimeParams.basePath;
133
+ const assetBasePath = runtimeParams.assetBasePath;
134
+ const uiBasePath = runtimeParams.assetBasePath;
133
135
  const viewApi = this.getBoundApi(viewRequest, route, runtimeEnvironment, runtimeParams);
134
136
  const response = await (0, import_instrumentation.getTracer)().trace({
135
137
  name: import_instrumentation.ViewSpan.ExecuteRouteHandler,
@@ -139,7 +141,7 @@ var LwrViewHandler = class {
139
141
  }
140
142
  }, async () => {
141
143
  try {
142
- return await routeHandlerFn({...viewRequest, locale, basePath}, {route, viewApi, ...paths}, routeHandlerOptions);
144
+ return await routeHandlerFn({...viewRequest, locale, basePath, assetBasePath, uiBasePath}, {route, viewApi, ...paths}, routeHandlerOptions);
143
145
  } catch (err) {
144
146
  if (err instanceof import_diagnostics.DiagnosticsError) {
145
147
  throw err;
@@ -148,6 +150,9 @@ var LwrViewHandler = class {
148
150
  throw (0, import_diagnostics.createSingleDiagnosticError)({description: import_diagnostics.descriptions.APPLICATION.ROUTE_HANDLER_ERROR(route.id, message)}, import_diagnostics.LwrApplicationError);
149
151
  }
150
152
  });
153
+ if (response?.locale) {
154
+ runtimeParams.locale = response.locale;
155
+ }
151
156
  return response;
152
157
  }
153
158
  getBoundApi(viewRequest, route, runtimeEnvironment, runtimeParams) {
@@ -164,6 +169,9 @@ var LwrViewHandler = class {
164
169
  async getViewResponse(viewRequest, route, runtimeEnvironment, runtimeParams = {}, view, viewParams, renderOptions) {
165
170
  const {id, bootstrap} = route;
166
171
  const managedView = {...view, id, bootstrap};
172
+ if (view.locale) {
173
+ runtimeParams.locale = view.locale;
174
+ }
167
175
  const viewResponse = {
168
176
  view: managedView,
169
177
  viewParams,
package/build/es/index.js CHANGED
@@ -1,7 +1,8 @@
1
- import { InflightTasks, createStringBuilder, extractMetadataFromHtml, getCacheKeyFromJson, getSpecifier, normalizeResourcePath, shortestTtl, } from '@lwrjs/shared-utils';
1
+ import { InflightTasks, createStringBuilder, extractMetadataFromHtml, getCacheKeyFromJson, getFeatureFlags, 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
+ // TODO: investigate perf impact W-16056356
5
6
  import { LRUCache } from 'lru-cache';
6
7
  import { DiagnosticsError, LwrServerError, createSingleDiagnosticError, descriptions, logger, } from '@lwrjs/diagnostics';
7
8
  export { LwrViewHandler } from './view-handler.js';
@@ -37,7 +38,7 @@ export class LwrViewRegistry {
37
38
  }
38
39
  async onModuleDefinitionChange(moduleDefinition) {
39
40
  // TODO we will make this more robust in the future w/ full MRT HMR
40
- if (process.env.MRT_HMR === 'true') {
41
+ if (isLocalDev()) {
41
42
  this.viewDefinitions.clear();
42
43
  return;
43
44
  }
@@ -63,7 +64,7 @@ export class LwrViewRegistry {
63
64
  }
64
65
  async onViewSourceChange(compiledView) {
65
66
  // TODO we will make this more robust in the future w/ full MRT HMR
66
- if (process.env.MRT_HMR === 'true') {
67
+ if (isLocalDev()) {
67
68
  this.viewDefinitions.clear();
68
69
  return;
69
70
  }
@@ -150,9 +151,11 @@ export class LwrViewRegistry {
150
151
  locale: runtimeParams?.locale,
151
152
  basePath: runtimeParams?.basePath,
152
153
  debug: runtimeEnvironment.debug,
154
+ // Add a variable on if the nonce is enabled
155
+ nonceEnabled: getFeatureFlags().ENABLE_NONCE,
153
156
  });
154
157
  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
158
+ // viewParams is an unbounded object and can be very large (17MB/view for developer.salesforce.com). Allowing consumers
156
159
  // to provide a simple override avoids the excess memory / performance overhead of serializing & storing the viewParams
157
160
  // on every request, while still reusing our caching logic.
158
161
  const viewParamKey = viewParamCacheKey
@@ -177,6 +180,8 @@ export class LwrViewRegistry {
177
180
  locale: runtimeParams?.locale,
178
181
  basePath: runtimeParams?.basePath,
179
182
  debug: runtimeEnvironment.debug,
183
+ // Add a variable on if the nonce is enabled
184
+ nonceEnabled: getFeatureFlags().ENABLE_NONCE,
180
185
  });
181
186
  logger.debug(`[view-registry][getViewDefinition] viewDefCacheKey=${viewDefCacheKey}`);
182
187
  // viewParams is an unbounded object and can be very large (17MB/view for developer.salesforce.com). Allowing consumers
@@ -196,6 +201,9 @@ export class LwrViewRegistry {
196
201
  return viewDefinition.viewDefinition;
197
202
  }
198
203
  }
204
+ // If we missed cache generate a nonce in the page context (we do not want it part of the cache key)
205
+ const updatableViewParams = { ...viewParams };
206
+ generateViewNonce(updatableViewParams);
199
207
  const pendingViewDefCacheKey = viewDefCacheKey + viewParamKey;
200
208
  const viewDefinition = await this.pendingViewDefinitions.execute(pendingViewDefCacheKey, () => getTracer().trace({
201
209
  name: ViewSpan.RenderView,
@@ -203,10 +211,14 @@ export class LwrViewRegistry {
203
211
  view: view.id,
204
212
  ssr: view.bootstrap?.ssr === true,
205
213
  },
206
- }, () => this.renderView(view, viewParams, runtimeEnvironment, runtimeParams, renderOptions)));
214
+ }, () => this.renderView(view, updatableViewParams, runtimeEnvironment, runtimeParams, renderOptions)));
215
+ // Once the view is generated add the nonce to the response so it can be cached and then added to the headers
216
+ viewDefinition.nonce = getViewNonce(updatableViewParams);
207
217
  if (cacheDisabled === false) {
208
218
  const route = this.globalConfig.routes.find((r) => r.id === view.id);
209
- const ttl = shortestTtl(viewDefinition.cache?.ttl, route?.cache?.ttl);
219
+ // optionally set a max TTL on the view registry cache
220
+ const maxTtl = process.env.MAX_VIEW_CACHE_TTL && parseInt(process.env.MAX_VIEW_CACHE_TTL, 10);
221
+ const ttl = shortestTtl(viewDefinition.cache?.ttl, route?.cache?.ttl, maxTtl);
210
222
  if (ttl !== 0) {
211
223
  // cache view definition for the shortest ttl or until it is the least recently used when ttl is undefined
212
224
  this.viewDefinitions.set(viewDefCacheKey, {
@@ -233,7 +245,7 @@ export class LwrViewRegistry {
233
245
  async renderView(view, viewParams, runtimeEnvironment, runtimeParams = {}, renderOptions) {
234
246
  const { id, contentTemplate, rootComponent, layoutTemplate } = view;
235
247
  const lwrResourcesId = `__LWR_RESOURCES__${Date.now()}`;
236
- const renderedContent = await this.render({ id, contentTemplate, rootComponent }, { ...viewParams, lwr_resources: lwrResourcesId }, runtimeParams, renderOptions);
248
+ const renderedContent = await this.render({ id, contentTemplate, rootComponent }, { ...viewParams, lwr_resources: lwrResourcesId }, runtimeParams, runtimeEnvironment, renderOptions);
237
249
  // normalize the renderOptions provided by the CompiledView content with the request options.
238
250
  let normalizedRenderOptions = normalizeRenderOptions(this.runtimeEnvironment, renderedContent.options, renderOptions);
239
251
  const layout = layoutTemplate || renderedContent.compiledView.layoutTemplate;
@@ -257,7 +269,7 @@ export class LwrViewRegistry {
257
269
  ...viewParams,
258
270
  body: renderedContent.renderedView,
259
271
  lwr_resources: lwrResourcesId,
260
- }, runtimeParams);
272
+ }, runtimeParams, runtimeEnvironment);
261
273
  normalizedRenderOptions = normalizeRenderOptions(this.runtimeEnvironment, renderedLayout.options, normalizedRenderOptions);
262
274
  const renderedViewDef = await this.link({
263
275
  ...renderedLayout,
@@ -301,7 +313,7 @@ export class LwrViewRegistry {
301
313
  });
302
314
  return renderedViewDef;
303
315
  }
304
- async render(viewId, viewParams, runtimeParams, renderOptions) {
316
+ async render(viewId, viewParams, runtimeParams, runtimeEnvironment, renderOptions) {
305
317
  const globalContext = this.globalData;
306
318
  const { id, rootComponent, contentTemplate } = viewId;
307
319
  const compiledView = await this.getView({ id, contentTemplate, rootComponent }, renderOptions?.skipCaching);
@@ -320,7 +332,7 @@ export class LwrViewRegistry {
320
332
  ...globalContext,
321
333
  ...compiledView.properties,
322
334
  ...viewParams,
323
- });
335
+ }, runtimeEnvironment);
324
336
  const normalizedResult = normalizeRenderedResult(result);
325
337
  return {
326
338
  compiledView,
@@ -345,6 +357,7 @@ export class LwrViewRegistry {
345
357
  importer: importer || renderedView.compiledView.filePath,
346
358
  };
347
359
  const stringBuilder = createStringBuilder(renderedViewContent);
360
+ // Note: this is the TTL for the page NOT for the view registry cache
348
361
  let pageTtl = renderedView.cache.ttl;
349
362
  for (const viewTransformer of this.viewTransformers) {
350
363
  // eslint-disable-next-line no-await-in-loop
@@ -384,6 +397,7 @@ export class LwrViewRegistry {
384
397
  immutable,
385
398
  viewRecord: {
386
399
  assetReferences: reduceSourceAssetReferences(linkedMetadata.assetReferences),
400
+ moduleResources: [],
387
401
  },
388
402
  cache: { ttl: pageTtl },
389
403
  };
@@ -1,8 +1,8 @@
1
1
  import { logger } from '@lwrjs/diagnostics';
2
- import { kebabCaseToModuleSpecifier, getModuleGraphs, GraphDepth, getModuleUriPrefix, explodeSpecifier, isBundler, getHydrateDirective, isGroupie, isExternalSpecifier, } from '@lwrjs/shared-utils';
2
+ import { kebabCaseToModuleSpecifier, getModuleGraphs, GraphDepth, getModuleUriPrefix, explodeSpecifier, isBundler, getHydrateDirective, isGroupie, isExternalSpecifier, isLocalDev, } from '@lwrjs/shared-utils';
3
3
  import { AppResourceEnum, getAppSpecifier } from '@lwrjs/app-service/identity';
4
- import { generateHtmlTag, getModuleResourceByUri } from '../utils.js';
5
- import { flattenCustomElements, getViewBootstrapConfigurationResource, getViewHmrConfigurationResource, } from './utils.js';
4
+ import { addExternalScriptNonce, generateHtmlTag, getModuleResource, getModuleResourceByUri, getViewNonce, } from '../utils.js';
5
+ import { flattenCustomElements, getBundleIntegrity, getViewBootstrapConfigurationResource, getViewHmrConfigurationResource, } from './utils.js';
6
6
  import { setPreloadModulesMeta, getPreloadModulesMeta } from './preload-utils.js';
7
7
  function includeIdFactory(bundleConfig) {
8
8
  return (moduleRef) => {
@@ -17,9 +17,8 @@ function includeIdFactory(bundleConfig) {
17
17
  }
18
18
  export async function getHtmlResources(view, viewParams, resourceContext) {
19
19
  const { runtimeEnvironment, runtimeParams, moduleRegistry, moduleBundler, resourceRegistry, viewMetadata, } = resourceContext;
20
- const { lwrVersion, format, hmrEnabled, bundle, debug, minify } = runtimeEnvironment;
20
+ const { format, hmrEnabled, bundle, debug, minify } = runtimeEnvironment;
21
21
  const { customElements, serverData, serverDebug } = viewMetadata;
22
- const version = lwrVersion;
23
22
  const isAMD = format === 'amd';
24
23
  const { bundleConfig } = resourceContext;
25
24
  const { external = {}, exclude = [] } = bundleConfig;
@@ -89,9 +88,14 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
89
88
  uris: [],
90
89
  specifiers: [],
91
90
  groups: new Map(),
91
+ integrities: new Map(),
92
92
  };
93
93
  // Determine if server side rendering view modules
94
94
  const isSSR = view.bootstrap?.ssr;
95
+ // Determine the LWR client version
96
+ const version = view.bootstrap?.lwrVersion;
97
+ // Page level nonce for script tags
98
+ const nonce = getViewNonce(viewParams);
95
99
  // ABS module and custom element references
96
100
  let bootstrapModuleRef, versionedSpecifier = bootstrapSpecifier;
97
101
  const customElementsRecords = [];
@@ -107,7 +111,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
107
111
  let def = (await resourceRegistry.getResource({ specifier: shimBundle, version }, runtimeEnvironment, runtimeParams));
108
112
  if (!def) {
109
113
  // HACK: fallback to looking for the other shim.
110
- // TODO: remove this once we solve debug mode in MRT
114
+ // TODO: remove this once KJ fixes W-15953000
111
115
  let fallbackShimBundle;
112
116
  if (shimBundle === 'lwr-loader-shim-legacy.bundle.js') {
113
117
  fallbackShimBundle = 'lwr-loader-shim-legacy.bundle.min.js';
@@ -126,6 +130,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
126
130
  if (!def.inline && !def.src) {
127
131
  throw Error(`Invalid Shim ${shimBundle}: ${JSON.stringify(def)}`);
128
132
  }
133
+ addExternalScriptNonce(def, nonce);
129
134
  requiredResources.push(def);
130
135
  // Always inline the error shim script after the shim
131
136
  const errorShimDef = (await resourceRegistry.getResource({ specifier: 'lwr-error-shim.js', version }, runtimeEnvironment, runtimeParams));
@@ -136,6 +141,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
136
141
  if (!errorShimDef.inline && !errorShimDef.src) {
137
142
  throw Error(`Invalid Shim lwr-error-shim.js: ${JSON.stringify(errorShimDef)}`);
138
143
  }
144
+ addExternalScriptNonce(errorShimDef, nonce);
139
145
  requiredResources.push(errorShimDef);
140
146
  }
141
147
  // ------- Application Bootstrap module
@@ -155,12 +161,14 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
155
161
  if (!uri) {
156
162
  throw Error(`Invalid Module Resource ${versionedSpecifier}`);
157
163
  }
158
- moduleResources.push(getModuleResourceByUri(uri, runtimeEnvironment, { isPreload: false, isSSR }));
164
+ const integrity = getBundleIntegrity(bootstrapModuleGraph, versionedSpecifier);
165
+ moduleResources.push(getModuleResourceByUri(uri, runtimeEnvironment, { integrity, isPreload: false, isSSR, nonce }));
159
166
  // PRELOAD the bootstrap module static dependencies as preloaded script resources
160
167
  for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
161
168
  const uri = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
162
169
  if (uri) {
163
- setPreloadModulesMeta(depSpecifier, uri, groups, viewPreloads);
170
+ const integrity = getBundleIntegrity(bootstrapModuleGraph, depSpecifier);
171
+ setPreloadModulesMeta(depSpecifier, uri, integrity, groups, viewPreloads);
164
172
  }
165
173
  }
166
174
  // PRELOAD configured preloadModules as preloaded script resources
@@ -210,13 +218,15 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
210
218
  // PRELOAD the custom element module as a link resource
211
219
  const specifier = graph.graphs[0].specifier;
212
220
  const uri = graph.uriMap[specifier];
213
- setPreloadModulesMeta(specifier, uri, groups, viewPreloads);
221
+ const integrity = getBundleIntegrity(graph, specifier);
222
+ setPreloadModulesMeta(specifier, uri, integrity, groups, viewPreloads);
214
223
  // PRELOAD custom element static deps as link resources when bundling is ON
215
224
  if (bundle) {
216
225
  for (const depSpecifier of graph.graphs[0].static) {
217
- const uri = getPreloadUri(depSpecifier, graph.uriMap);
218
- if (uri) {
219
- setPreloadModulesMeta(depSpecifier, uri, groups, viewPreloads);
226
+ const depUri = getPreloadUri(depSpecifier, graph.uriMap);
227
+ if (depUri) {
228
+ const integrity = getBundleIntegrity(graph, depSpecifier);
229
+ setPreloadModulesMeta(depSpecifier, depUri, integrity, groups, viewPreloads);
220
230
  }
221
231
  }
222
232
  }
@@ -238,6 +248,14 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
238
248
  }
239
249
  }));
240
250
  if (viewContainsLiveElements) {
251
+ if (isLocalDev()) {
252
+ // ADD the client-side bootstrap module and mapping for local-dev
253
+ const localDevSpecifier = 'lwr_local_dev/bootstrap';
254
+ rootComponents.push(localDevSpecifier);
255
+ const localDevMod = await getModuleResource({ specifier: localDevSpecifier, version: '' }, runtimeEnvironment, {}, moduleRegistry, runtimeParams);
256
+ if (localDevMod.src)
257
+ imports[localDevSpecifier] = localDevMod.src;
258
+ }
241
259
  // ADD configuration of the bootstrapModule
242
260
  configResources.unshift(getViewBootstrapConfigurationResource({
243
261
  id: view.id,
@@ -265,7 +283,13 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
265
283
  const dedupedUris = [...new Set(viewPreloads.uris)];
266
284
  // PRELOAD script resources for preload module URIs after the bootstrap module
267
285
  for (const preloadUri of dedupedUris) {
268
- moduleResources.push(getModuleResourceByUri(preloadUri, runtimeEnvironment, { isPreload: true, isSSR }));
286
+ const integrity = viewPreloads.integrities.get(preloadUri);
287
+ moduleResources.push(getModuleResourceByUri(preloadUri, runtimeEnvironment, {
288
+ integrity,
289
+ isPreload: true,
290
+ isSSR,
291
+ nonce,
292
+ }));
269
293
  }
270
294
  // generate html partial
271
295
  const htmlResources = await Promise.all([...configResources, ...requiredResources, ...moduleResources].map(generateHtmlTag));
@@ -274,6 +298,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
274
298
  viewRecord: {
275
299
  resources: requiredResources,
276
300
  customElements: customElementsRecords,
301
+ moduleResources,
277
302
  bootstrapModule: bootstrapModuleRef,
278
303
  },
279
304
  };
@@ -3,11 +3,12 @@ export type ViewPreloads = {
3
3
  groups: Map<string, boolean>;
4
4
  uris: string[];
5
5
  specifiers: string[];
6
+ integrities: Map<string, string | undefined>;
6
7
  };
7
8
  /**
8
9
  * keeps track of preloadModules metadata
9
10
  */
10
- export declare function setPreloadModulesMeta(specifier: string, uri: string, groups: BundleGroups, preloads: ViewPreloads): void;
11
+ export declare function setPreloadModulesMeta(specifier: string, uri: string, integrity: string | undefined, groups: BundleGroups, preloads: ViewPreloads): void;
11
12
  /**
12
13
  * Recursively gets preloadModules metadata starting with a specifier
13
14
  * Note: don't call me unless you got bundles
@@ -3,7 +3,7 @@ import { explodeSpecifier, getGroupName, getVersionedModuleId, normalizeVersionT
3
3
  /**
4
4
  * keeps track of preloadModules metadata
5
5
  */
6
- export function setPreloadModulesMeta(specifier, uri, groups, preloads) {
6
+ export function setPreloadModulesMeta(specifier, uri, integrity, groups, preloads) {
7
7
  // Throw a very specific error if we get this back and the uri property is not set
8
8
  if (!uri) {
9
9
  throw createSingleDiagnosticError({
@@ -20,6 +20,7 @@ export function setPreloadModulesMeta(specifier, uri, groups, preloads) {
20
20
  const preloadModulesSpecifiers = preloads.specifiers;
21
21
  const preloadBundleGroupsMap = preloads.groups;
22
22
  const preloadModulesURIs = preloads.uris;
23
+ const preloadModuleIntegrities = preloads.integrities;
23
24
  preloadModulesSpecifiers.push(specifier);
24
25
  const { specifier: unversionedSpecifier } = explodeSpecifier(specifier);
25
26
  const groupName = getGroupName(unversionedSpecifier, groups);
@@ -29,6 +30,7 @@ export function setPreloadModulesMeta(specifier, uri, groups, preloads) {
29
30
  // With bundling groups, we only want to include one URI
30
31
  preloadModulesURIs.push(uri);
31
32
  groupName && preloadBundleGroupsMap.set(groupName, true);
33
+ preloadModuleIntegrities.set(uri, integrity);
32
34
  }
33
35
  /**
34
36
  * Recursively gets preloadModules metadata starting with a specifier
@@ -60,12 +62,13 @@ viewPreloads, bundleConfig, moduleRegistry, defRegistry, runtimeEnvironment, run
60
62
  const uri =
61
63
  // eslint-disable-next-line no-await-in-loop
62
64
  await defRegistry.resolveModuleUri(versionedModuleId, runtimeEnvironment, runtimeParams);
63
- // fallback to unversioned specifier if needed
65
+ // fallback to un-versioned specifier if needed
64
66
  const normalizedSpecifier = versionedModuleId.version === VERSION_NOT_PROVIDED ? specifier : versionedModuleSpecifier;
65
- setPreloadModulesMeta(normalizedSpecifier, uri, groups, viewPreloads);
67
+ // Will set the integrity after loading the record below
68
+ const preloadModuleRecord = await defRegistry.getModuleBundle(versionedModuleId, runtimeEnvironment, runtimeParams);
69
+ const { integrity } = preloadModuleRecord;
70
+ setPreloadModulesMeta(normalizedSpecifier, uri, integrity, groups, viewPreloads);
66
71
  if (exclude.length || Object.keys(groups).length) {
67
- // check if we need to also preload any excluded dependencies of this preload module
68
- const preloadModuleRecord = await defRegistry.getModuleBundle(versionedModuleId, runtimeEnvironment, runtimeParams);
69
72
  const { imports } = preloadModuleRecord.bundleRecord;
70
73
  if (imports) {
71
74
  if (!pending) {
@@ -1,5 +1,6 @@
1
- import type { ClientBootstrapConfig, RuntimeEnvironment, RuntimeParams, ResourceDefinition, RenderedViewMetadata, CustomElementReference, View, ViewInfo } from '@lwrjs/types';
1
+ import type { ClientBootstrapConfig, RuntimeEnvironment, RuntimeParams, ResourceDefinition, RenderedViewMetadata, CustomElementReference, View, ViewInfo, FlattenedModuleGraphs } from '@lwrjs/types';
2
2
  export declare function getViewBootstrapConfigurationResource(viewInfo: ViewInfo, config: ClientBootstrapConfig, runtimeEnvironment: RuntimeEnvironment, runtimeParams: RuntimeParams, debugMessage?: string): ResourceDefinition;
3
3
  export declare function getViewHmrConfigurationResource(view: View, viewMetadata: RenderedViewMetadata): ResourceDefinition;
4
4
  export declare function flattenCustomElements(arr: CustomElementReference[], isSSR?: boolean): CustomElementReference[];
5
+ export declare function getBundleIntegrity(bootstrapModuleGraph: FlattenedModuleGraphs, versionedSpecifier: string): string | undefined;
5
6
  //# sourceMappingURL=utils.d.ts.map
@@ -1,4 +1,4 @@
1
- import { buildEnvironmentContext, getMappingUriPrefix, getModuleUriPrefix, getClientBootstrapConfigurationUri, hashContent, } from '@lwrjs/shared-utils';
1
+ import { buildEnvironmentContext, getMappingUriPrefix, getModuleUriPrefix, getClientBootstrapConfigurationUri, hashContent, createIntegrityHash, } from '@lwrjs/shared-utils';
2
2
  const CONTENT_TYPE = 'application/javascript';
3
3
  export function getViewBootstrapConfigurationResource(viewInfo, config, runtimeEnvironment, runtimeParams, debugMessage) {
4
4
  const { compat, debug, hmrEnabled, apiVersion, format } = runtimeEnvironment;
@@ -49,6 +49,7 @@ export function getViewBootstrapConfigurationResource(viewInfo, config, runtimeE
49
49
  type: CONTENT_TYPE,
50
50
  content: configString,
51
51
  inline: false,
52
+ integrity: createIntegrityHash(configString),
52
53
  src: url,
53
54
  };
54
55
  }
@@ -111,4 +112,9 @@ export function flattenCustomElements(arr, isSSR = false) {
111
112
  flatten(arr);
112
113
  return ret;
113
114
  }
115
+ export function getBundleIntegrity(bootstrapModuleGraph, versionedSpecifier) {
116
+ const def = bootstrapModuleGraph.linkedDefinitions[versionedSpecifier];
117
+ const integrity = def?.integrity;
118
+ return integrity;
119
+ }
114
120
  //# sourceMappingURL=utils.js.map
@@ -1,15 +1,14 @@
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';
5
- import { flattenCustomElements, getViewBootstrapConfigurationResource, getViewHmrConfigurationResource, } from './utils.js';
4
+ import { addExternalScriptNonce, generateHtmlTag, getModuleResourceByUri, getViewNonce } from '../utils.js';
5
+ import { flattenCustomElements, getBundleIntegrity, getViewBootstrapConfigurationResource, getViewHmrConfigurationResource, } from './utils.js';
6
6
  import { setPreloadModulesMeta, getPreloadModulesMeta } from './preload-utils.js';
7
7
  export async function getHtmlResources(view, viewParams, resourceContext) {
8
8
  const { runtimeEnvironment, runtimeParams, moduleRegistry, moduleBundler, resourceRegistry, viewMetadata, } = resourceContext;
9
- const { lwrVersion, format, hmrEnabled, bundle, debug, minify } = runtimeEnvironment;
9
+ const { format, hmrEnabled, bundle, debug, minify } = runtimeEnvironment;
10
10
  const { customElements, serverData, serverDebug } = viewMetadata;
11
11
  const defRegistry = bundle ? moduleBundler : moduleRegistry;
12
- const version = lwrVersion;
13
12
  const isAMD = format === 'amd';
14
13
  const depth = isAMD
15
14
  ? { static: GraphDepth.ALL, dynamic: 1 }
@@ -72,9 +71,14 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
72
71
  uris: [],
73
72
  specifiers: [],
74
73
  groups: new Map(),
74
+ integrities: new Map(),
75
75
  };
76
76
  // Determine if server side rendering view modules
77
77
  const isSSR = view.bootstrap?.ssr;
78
+ // Determine the LWR client version
79
+ const version = view.bootstrap?.lwrVersion;
80
+ // Page level nonce for script tags
81
+ const nonce = getViewNonce(viewParams);
78
82
  // ABS module and custom element references
79
83
  let bootstrapModuleRef, versionedSpecifier = bootstrapSpecifier;
80
84
  let importMetadata = { imports: {} };
@@ -94,6 +98,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
94
98
  if (!def.inline && !def.src) {
95
99
  throw Error(`Invalid Shim ${shimBundle}: ${JSON.stringify(def)}`);
96
100
  }
101
+ addExternalScriptNonce(def, nonce);
97
102
  requiredResources.push(def);
98
103
  // Always inline the error shim script after the shim
99
104
  const errorShimDef = (await resourceRegistry.getResource({ specifier: 'lwr-error-shim.js', version }, runtimeEnvironment, runtimeParams));
@@ -104,6 +109,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
104
109
  if (!errorShimDef.inline && !errorShimDef.src) {
105
110
  throw Error(`Invalid Shim lwr-error-shim.js: ${JSON.stringify(errorShimDef)}`);
106
111
  }
112
+ addExternalScriptNonce(errorShimDef, nonce);
107
113
  requiredResources.push(errorShimDef);
108
114
  }
109
115
  // ------- Application Bootstrap module
@@ -122,12 +128,14 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
122
128
  if (!uri) {
123
129
  throw Error(`Invalid Module Resource ${versionedSpecifier}`);
124
130
  }
125
- moduleResources.push(getModuleResourceByUri(uri, runtimeEnvironment, { isPreload: false, isSSR }));
131
+ const integrity = getBundleIntegrity(bootstrapModuleGraph, versionedSpecifier);
132
+ moduleResources.push(getModuleResourceByUri(uri, runtimeEnvironment, { integrity, isPreload: false, isSSR, nonce }));
126
133
  // PRELOAD the bootstrap module static dependencies as preloaded script resources
127
134
  for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
128
135
  const uri = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
129
136
  if (uri) {
130
- setPreloadModulesMeta(depSpecifier, uri, groups, viewPreloads);
137
+ const integrity = getBundleIntegrity(bootstrapModuleGraph, depSpecifier);
138
+ setPreloadModulesMeta(depSpecifier, uri, integrity, groups, viewPreloads);
131
139
  }
132
140
  }
133
141
  // PRELOAD configured preloadModules as preloaded script resources
@@ -179,13 +187,15 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
179
187
  // PRELOAD the custom element module as a link resource
180
188
  const specifier = graph.graphs[0].specifier;
181
189
  const uri = graph.uriMap[specifier];
182
- setPreloadModulesMeta(specifier, uri, groups, viewPreloads);
190
+ const integrity = getBundleIntegrity(graph, specifier);
191
+ setPreloadModulesMeta(specifier, uri, integrity, groups, viewPreloads);
183
192
  // PRELOAD custom element static deps as link resources when bundling is ON
184
193
  if (bundle) {
185
194
  for (const depSpecifier of graph.graphs[0].static) {
186
- const uri = getPreloadUri(depSpecifier, graph.uriMap);
187
- if (uri) {
188
- setPreloadModulesMeta(depSpecifier, uri, groups, viewPreloads);
195
+ const depUri = getPreloadUri(depSpecifier, graph.uriMap);
196
+ if (depUri) {
197
+ const integrity = getBundleIntegrity(graph, depSpecifier);
198
+ setPreloadModulesMeta(depSpecifier, depUri, integrity, groups, viewPreloads);
189
199
  }
190
200
  }
191
201
  }
@@ -234,7 +244,13 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
234
244
  // PRELOAD script resources for preload module URIs after the bootstrap module
235
245
  const dedupedUris = [...new Set(viewPreloads.uris)];
236
246
  for (const preloadUri of dedupedUris) {
237
- moduleResources.push(getModuleResourceByUri(preloadUri, runtimeEnvironment, { isPreload: true, isSSR }));
247
+ const integrity = viewPreloads.integrities.get(preloadUri);
248
+ moduleResources.push(getModuleResourceByUri(preloadUri, runtimeEnvironment, {
249
+ integrity,
250
+ isPreload: true,
251
+ isSSR,
252
+ nonce,
253
+ }));
238
254
  }
239
255
  // generate html partial
240
256
  const htmlResources = await Promise.all([...configResources, ...requiredResources, ...moduleResources].map(generateHtmlTag));
@@ -251,6 +267,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
251
267
  customElements: customElementsRecords,
252
268
  endpoints,
253
269
  importMetadata,
270
+ moduleResources,
254
271
  bootstrapModule: bootstrapModuleRef,
255
272
  },
256
273
  };
@@ -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 | undefined;
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,12 @@
1
1
  import { basename, extname } from 'path';
2
- import { explodeSpecifier, getMappingUriPrefix, getSpecifier, getClientBootstrapConfigurationUri, mimeLookup, DEFAULT_TITLE, streamToString, } from '@lwrjs/shared-utils';
2
+ import { explodeSpecifier, getMappingUriPrefix, getSpecifier, getClientBootstrapConfigurationUri, mimeLookup, DEFAULT_TITLE, streamToString, getFeatureFlags, } 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, integrity) {
9
+ // add script loader order attribute
8
10
  let scriptLoadOrder = '';
9
11
  if (defer) {
10
12
  scriptLoadOrder = ' defer';
@@ -12,7 +14,19 @@ function generateExternalScript(type = 'application/javascript', src, async, def
12
14
  else if (async) {
13
15
  scriptLoadOrder = ' async';
14
16
  }
15
- return `<script type="${type}"${scriptLoadOrder} src="${src}"></script>`;
17
+ // add the right CSP header attribute
18
+ let cspHashAttr = '';
19
+ // For now use the ENABLE_NONCE to gate adding nonce or integrity
20
+ // W-15868505 is open to create a better config
21
+ if (getFeatureFlags().ENABLE_NONCE) {
22
+ if (integrity) {
23
+ cspHashAttr = ` integrity="${integrity}"`;
24
+ }
25
+ else if (nonce) {
26
+ cspHashAttr = ` nonce="${nonce}"`;
27
+ }
28
+ }
29
+ return `<script type="${type}"${scriptLoadOrder}${cspHashAttr} src="${src}"></script>`;
16
30
  }
17
31
  function generateLinkPreloadTag({ href, type }) {
18
32
  if (type === 'module') {
@@ -22,7 +36,7 @@ function generateLinkPreloadTag({ href, type }) {
22
36
  return `<link rel="preload" href="${href}" type="${type}" />`;
23
37
  }
24
38
  }
25
- function generateExternalTag({ type, src = '', async, defer, isPreload }) {
39
+ function generateExternalTag({ type, src = '', async, defer, isPreload, nonce, integrity, }) {
26
40
  if (isPreload) {
27
41
  return generateLinkPreloadTag({ href: src, type: type });
28
42
  }
@@ -30,13 +44,13 @@ function generateExternalTag({ type, src = '', async, defer, isPreload }) {
30
44
  return generateExternalStyle(src);
31
45
  }
32
46
  else {
33
- return generateExternalScript(type, src, async, defer);
47
+ return generateExternalScript(type, src, async, defer, nonce, integrity);
34
48
  }
35
49
  }
36
50
  async function generateInlineTag({ specifier, type, content, stream, nonce }) {
37
51
  const typeStr = type === 'text/css' ? '' : ` type="${type}"`;
38
52
  const tag = type === 'text/css' ? 'style' : 'script';
39
- const nonceStr = nonce ? ` nonce="${nonce}"` : '';
53
+ const nonceStr = getFeatureFlags().ENABLE_NONCE && nonce && nonce ? ` nonce="${nonce}"` : '';
40
54
  if (!content && !stream) {
41
55
  throw new Error(`Invalid inline Resource Definition: must have either "content" or "stream": "${specifier}"`);
42
56
  }
@@ -203,7 +217,7 @@ export async function getModuleResource(moduleId, runtimeEnvironment, moduleReso
203
217
  };
204
218
  }
205
219
  export function getModuleResourceByUri(uri, runtimeEnvironment, moduleResourceMeta) {
206
- const { isSSR = false, isPreload = false } = moduleResourceMeta;
220
+ const { integrity, isSSR = false, isPreload = false, nonce } = moduleResourceMeta;
207
221
  const { format } = runtimeEnvironment;
208
222
  return {
209
223
  src: uri,
@@ -213,6 +227,8 @@ export function getModuleResourceByUri(uri, runtimeEnvironment, moduleResourceMe
213
227
  // only use link preload for ESM for compat reasons.
214
228
  // AMD should use regular script tags for preloading
215
229
  isPreload: format !== 'amd' && isPreload,
230
+ integrity,
231
+ nonce,
216
232
  };
217
233
  }
218
234
  // Given a specifier and resource type, return the JSON serialized Module data
@@ -236,4 +252,34 @@ export async function createJsonModule(specifier, moduleRegistry, environment, p
236
252
  },
237
253
  };
238
254
  }
255
+ /**
256
+ * Get the nonce set on the page context of the view params
257
+ */
258
+ export function getViewNonce(viewParams) {
259
+ return getFeatureFlags().ENABLE_NONCE
260
+ ? viewParams?.page?.nonce
261
+ : undefined;
262
+ }
263
+ /**
264
+ * Generate a nonce in the page context of the view params
265
+ */
266
+ export function generateViewNonce(viewParams) {
267
+ if (getFeatureFlags().ENABLE_NONCE) {
268
+ const nonce = crypto.randomBytes(16).toString('base64');
269
+ if (!viewParams.page) {
270
+ viewParams.page = { nonce };
271
+ }
272
+ else {
273
+ viewParams.page.nonce = nonce;
274
+ }
275
+ }
276
+ }
277
+ /**
278
+ * Add a nonce to a script definition in view if it is external (not inline)
279
+ */
280
+ export function addExternalScriptNonce(def, nonce) {
281
+ if (nonce && getFeatureFlags().ENABLE_NONCE && !def.inline) {
282
+ def.nonce = nonce;
283
+ }
284
+ }
239
285
  //# sourceMappingURL=utils.js.map
@@ -146,6 +146,8 @@ export class LwrViewHandler {
146
146
  const paths = { rootDir, assets, contentDir, layoutsDir };
147
147
  const locale = runtimeParams.locale;
148
148
  const basePath = runtimeParams.basePath;
149
+ const assetBasePath = runtimeParams.assetBasePath;
150
+ const uiBasePath = runtimeParams.assetBasePath;
149
151
  const viewApi = this.getBoundApi(viewRequest, route, runtimeEnvironment, runtimeParams);
150
152
  const response = await getTracer().trace({
151
153
  name: ViewSpan.ExecuteRouteHandler,
@@ -155,7 +157,7 @@ export class LwrViewHandler {
155
157
  },
156
158
  }, async () => {
157
159
  try {
158
- return await routeHandlerFn({ ...viewRequest, locale, basePath }, { route: route, viewApi, ...paths }, routeHandlerOptions);
160
+ return await routeHandlerFn({ ...viewRequest, locale, basePath, assetBasePath, uiBasePath }, { route: route, viewApi, ...paths }, routeHandlerOptions);
159
161
  }
160
162
  catch (err) {
161
163
  if (err instanceof DiagnosticsError) {
@@ -165,6 +167,10 @@ export class LwrViewHandler {
165
167
  throw createSingleDiagnosticError({ description: descriptions.APPLICATION.ROUTE_HANDLER_ERROR(route.id, message) }, LwrApplicationError);
166
168
  }
167
169
  });
170
+ // if the locale was returned by the route handler update the runtime time params
171
+ if (response?.locale) {
172
+ runtimeParams.locale = response.locale;
173
+ }
168
174
  return response;
169
175
  }
170
176
  /*
@@ -191,6 +197,11 @@ export class LwrViewHandler {
191
197
  view, viewParams, renderOptions) {
192
198
  const { id, bootstrap } = route;
193
199
  const managedView = { ...view, id, bootstrap };
200
+ // If this is a localized view request (could have come from a route handler)
201
+ // Update the runtime params
202
+ if (view.locale) {
203
+ runtimeParams.locale = view.locale;
204
+ }
194
205
  const viewResponse = {
195
206
  view: managedView,
196
207
  viewParams,
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.13.0-alpha.2",
7
+ "version": "0.13.0-alpha.21",
8
8
  "homepage": "https://developer.salesforce.com/docs/platform/lwr/overview",
9
9
  "repository": {
10
10
  "type": "git",
@@ -29,18 +29,21 @@
29
29
  "build/**/*.cjs",
30
30
  "build/**/*.d.ts"
31
31
  ],
32
+ "scripts": {
33
+ "build": "tsc -b"
34
+ },
32
35
  "dependencies": {
33
- "@lwrjs/app-service": "0.13.0-alpha.2",
34
- "@lwrjs/diagnostics": "0.13.0-alpha.2",
35
- "@lwrjs/instrumentation": "0.13.0-alpha.2",
36
- "@lwrjs/shared-utils": "0.13.0-alpha.2",
37
- "lru-cache": "^10.2.0"
36
+ "@lwrjs/app-service": "0.13.0-alpha.21",
37
+ "@lwrjs/diagnostics": "0.13.0-alpha.21",
38
+ "@lwrjs/instrumentation": "0.13.0-alpha.21",
39
+ "@lwrjs/shared-utils": "0.13.0-alpha.21",
40
+ "lru-cache": "^10.2.2"
38
41
  },
39
42
  "devDependencies": {
40
- "@lwrjs/types": "0.13.0-alpha.2"
43
+ "@lwrjs/types": "0.13.0-alpha.21"
41
44
  },
42
45
  "engines": {
43
46
  "node": ">=18.0.0"
44
47
  },
45
- "gitHead": "3ae1051ef1eb282f9c1fb54f6aab44ab5ba48480"
48
+ "gitHead": "d272dcd07881fa469ee73bd28d2f30f99957e122"
46
49
  }