@lwrjs/view-registry 0.13.0-alpha.9 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -136,17 +136,15 @@ var LwrViewRegistry = class {
136
136
  }
137
137
  throw new Error(`No View provider was able to resolve a view for template: ${viewId.contentTemplate}`);
138
138
  }
139
- async getView(viewId, skipCaching = false) {
139
+ async getView(viewId) {
140
140
  const {contentTemplate, rootComponent} = viewId;
141
141
  const compiledViewCacheKey = (0, import_shared_utils.getCacheKeyFromJson)({contentTemplate, rootComponent});
142
142
  import_diagnostics.logger.debug(`[view-registry][getView] compiledViewCacheKey=${compiledViewCacheKey}`);
143
- if (!skipCaching && this.compiledViews.has(compiledViewCacheKey)) {
143
+ if (this.compiledViews.has(compiledViewCacheKey)) {
144
144
  return this.compiledViews.get(compiledViewCacheKey);
145
145
  }
146
146
  const compiledView = await this.delegateGetView(viewId);
147
- if (!skipCaching) {
148
- this.compiledViews.set(compiledViewCacheKey, compiledView);
149
- }
147
+ this.compiledViews.set(compiledViewCacheKey, compiledView);
150
148
  return compiledView;
151
149
  }
152
150
  hasViewDefinition(view, viewParams, runtimeEnvironment, runtimeParams, renderOptions) {
@@ -161,7 +159,8 @@ var LwrViewRegistry = class {
161
159
  freezeAssets,
162
160
  locale: runtimeParams?.locale,
163
161
  basePath: runtimeParams?.basePath,
164
- debug: runtimeEnvironment.debug
162
+ debug: runtimeEnvironment.debug,
163
+ nonceEnabled: (0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE
165
164
  });
166
165
  import_diagnostics.logger.debug(`[view-registry][hasViewDefinition] viewDefId=${viewDefId}`);
167
166
  const viewParamKey = viewParamCacheKey ? (0, import_shared_utils.getCacheKeyFromJson)(viewParamCacheKey) : (0, import_shared_utils.getCacheKeyFromJson)(viewParams);
@@ -176,19 +175,19 @@ var LwrViewRegistry = class {
176
175
  }
177
176
  async getViewDefinition(view, viewParams, runtimeEnvironment, runtimeParams, renderOptions) {
178
177
  try {
179
- const {skipCaching, freezeAssets, viewParamCacheKey} = (0, import_utils.normalizeRenderOptions)(this.runtimeEnvironment, renderOptions);
178
+ const {freezeAssets, viewParamCacheKey} = (0, import_utils.normalizeRenderOptions)(this.runtimeEnvironment, renderOptions);
180
179
  const viewDefCacheKey = (0, import_shared_utils.getCacheKeyFromJson)({
181
180
  ...view,
182
181
  freezeAssets,
183
182
  locale: runtimeParams?.locale,
184
183
  basePath: runtimeParams?.basePath,
185
- debug: runtimeEnvironment.debug
184
+ debug: runtimeEnvironment.debug,
185
+ nonceEnabled: (0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE
186
186
  });
187
187
  import_diagnostics.logger.debug(`[view-registry][getViewDefinition] viewDefCacheKey=${viewDefCacheKey}`);
188
188
  const viewParamKey = viewParamCacheKey ? (0, import_shared_utils.getCacheKeyFromJson)(viewParamCacheKey) : (0, import_shared_utils.getCacheKeyFromJson)(viewParams);
189
189
  import_diagnostics.logger.debug(`[view-registry][getViewDefinition] viewParamKey=${viewParamKey}`);
190
- const cacheDisabled = process.env.NOCACHE === "true" || skipCaching;
191
- if (cacheDisabled === false && this.viewDefinitions.has(viewDefCacheKey)) {
190
+ if (this.viewDefinitions.has(viewDefCacheKey)) {
192
191
  const viewDefinition2 = this.viewDefinitions.get(viewDefCacheKey);
193
192
  if (viewDefinition2 && viewDefinition2.paramKey === viewParamKey && viewDefinition2.viewDefinition.immutable) {
194
193
  return viewDefinition2.viewDefinition;
@@ -205,17 +204,16 @@ var LwrViewRegistry = class {
205
204
  }
206
205
  }, () => this.renderView(view, updatableViewParams, runtimeEnvironment, runtimeParams, renderOptions)));
207
206
  viewDefinition.nonce = (0, import_utils.getViewNonce)(updatableViewParams);
208
- if (cacheDisabled === false) {
209
- const route = this.globalConfig.routes.find((r) => r.id === view.id);
210
- const ttl = (0, import_shared_utils.shortestTtl)(viewDefinition.cache?.ttl, route?.cache?.ttl);
211
- if (ttl !== 0) {
212
- this.viewDefinitions.set(viewDefCacheKey, {
213
- view,
214
- viewDefinition,
215
- paramKey: viewParamKey
216
- }, {ttl: ttl ? ttl * 1e3 : void 0});
217
- }
218
- }
207
+ const route = this.globalConfig.routes.find((r) => r.id === view.id);
208
+ const maxViewCacheTtl = (0, import_shared_utils.getFeatureFlags)().MAX_VIEW_CACHE_TTL;
209
+ const maxTtl = maxViewCacheTtl && parseInt(maxViewCacheTtl, 10);
210
+ const leastTtl = (0, import_shared_utils.shortestTtl)(viewDefinition.cache?.ttl, route?.cache?.ttl, maxTtl);
211
+ const ttl = leastTtl !== void 0 ? leastTtl === 0 ? 10 : leastTtl * 1e3 : void 0;
212
+ this.viewDefinitions.set(viewDefCacheKey, {
213
+ view,
214
+ viewDefinition,
215
+ paramKey: viewParamKey
216
+ }, {ttl});
219
217
  return viewDefinition;
220
218
  } catch (err) {
221
219
  if (err instanceof import_diagnostics.DiagnosticsError) {
@@ -230,7 +228,7 @@ var LwrViewRegistry = class {
230
228
  async renderView(view, viewParams, runtimeEnvironment, runtimeParams = {}, renderOptions) {
231
229
  const {id, contentTemplate, rootComponent, layoutTemplate} = view;
232
230
  const lwrResourcesId = `__LWR_RESOURCES__${Date.now()}`;
233
- const renderedContent = await this.render({id, contentTemplate, rootComponent}, {...viewParams, lwr_resources: lwrResourcesId}, runtimeParams, renderOptions);
231
+ const renderedContent = await this.render({id, contentTemplate, rootComponent}, {...viewParams, lwr_resources: lwrResourcesId}, runtimeParams, runtimeEnvironment, renderOptions);
234
232
  let normalizedRenderOptions = (0, import_utils.normalizeRenderOptions)(this.runtimeEnvironment, renderedContent.options, renderOptions);
235
233
  const layout = layoutTemplate || renderedContent.compiledView.layoutTemplate;
236
234
  if (!layout) {
@@ -250,7 +248,7 @@ var LwrViewRegistry = class {
250
248
  ...viewParams,
251
249
  body: renderedContent.renderedView,
252
250
  lwr_resources: lwrResourcesId
253
- }, runtimeParams);
251
+ }, runtimeParams, runtimeEnvironment);
254
252
  normalizedRenderOptions = (0, import_utils.normalizeRenderOptions)(this.runtimeEnvironment, renderedLayout.options, normalizedRenderOptions);
255
253
  const renderedViewDef = await this.link({
256
254
  ...renderedLayout,
@@ -288,16 +286,16 @@ var LwrViewRegistry = class {
288
286
  });
289
287
  return renderedViewDef;
290
288
  }
291
- async render(viewId, viewParams, runtimeParams, renderOptions) {
289
+ async render(viewId, viewParams, runtimeParams, runtimeEnvironment, renderOptions) {
292
290
  const globalContext = this.globalData;
293
291
  const {id, rootComponent, contentTemplate} = viewId;
294
- const compiledView = await this.getView({id, contentTemplate, rootComponent}, renderOptions?.skipCaching);
292
+ const compiledView = await this.getView({id, contentTemplate, rootComponent});
295
293
  const result = await compiledView.render({
296
294
  ...runtimeParams,
297
295
  ...globalContext,
298
296
  ...compiledView.properties,
299
297
  ...viewParams
300
- });
298
+ }, runtimeEnvironment);
301
299
  const normalizedResult = (0, import_utils.normalizeRenderedResult)(result);
302
300
  return {
303
301
  compiledView,
@@ -363,7 +361,8 @@ var LwrViewRegistry = class {
363
361
  renderedView: linkedAssetContent,
364
362
  immutable,
365
363
  viewRecord: {
366
- assetReferences: (0, import_utils.reduceSourceAssetReferences)(linkedMetadata.assetReferences)
364
+ assetReferences: (0, import_utils.reduceSourceAssetReferences)(linkedMetadata.assetReferences),
365
+ moduleResources: []
367
366
  },
368
367
  cache: {ttl: pageTtl}
369
368
  };
@@ -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,11 @@ 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;
104
105
  const nonce = (0, import_utils.getViewNonce)(viewParams);
105
106
  let bootstrapModuleRef, versionedSpecifier = bootstrapSpecifier;
106
107
  const customElementsRecords = [];
@@ -128,7 +129,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
128
129
  }
129
130
  (0, import_utils.addExternalScriptNonce)(def, nonce);
130
131
  requiredResources.push(def);
131
- const errorShimDef = await resourceRegistry.getResource({specifier: "lwr-error-shim.js", version}, runtimeEnvironment, runtimeParams);
132
+ const errorShimDef = await resourceRegistry.getResource({specifier: "lwr-error-shim.js", version}, runtimeEnvironment, {...runtimeParams, ignoreDebug: true});
132
133
  if (!errorShimDef) {
133
134
  throw Error("Failed to find definition of resource: lwr-error-shim.js");
134
135
  }
@@ -149,11 +150,13 @@ async function getHtmlResources(view, viewParams, resourceContext) {
149
150
  if (!uri) {
150
151
  throw Error(`Invalid Module Resource ${versionedSpecifier}`);
151
152
  }
152
- moduleResources.push((0, import_utils.getModuleResourceByUri)(uri, runtimeEnvironment, {isPreload: false, isSSR, nonce}));
153
+ const integrity = (0, import_utils2.getBundleIntegrity)(bootstrapModuleGraph, versionedSpecifier);
154
+ moduleResources.push((0, import_utils.getModuleResourceByUri)(uri, runtimeEnvironment, {integrity, isPreload: false, isSSR, nonce}));
153
155
  for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
154
156
  const uri2 = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
155
157
  if (uri2) {
156
- (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);
157
160
  }
158
161
  }
159
162
  if ((0, import_shared_utils.isBundler)(defRegistry)) {
@@ -190,12 +193,14 @@ async function getHtmlResources(view, viewParams, resourceContext) {
190
193
  if (!isSSR || (0, import_shared_utils.getHydrateDirective)(props)) {
191
194
  const specifier = graph.graphs[0].specifier;
192
195
  const uri = graph.uriMap[specifier];
193
- (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);
194
198
  if (bundle) {
195
199
  for (const depSpecifier of graph.graphs[0].static) {
196
- const uri2 = getPreloadUri(depSpecifier, graph.uriMap);
197
- if (uri2) {
198
- (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);
199
204
  }
200
205
  }
201
206
  }
@@ -214,11 +219,19 @@ async function getHtmlResources(view, viewParams, resourceContext) {
214
219
  }
215
220
  }));
216
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
+ }
217
229
  configResources.unshift((0, import_utils2.getViewBootstrapConfigurationResource)({
218
230
  id: view.id,
219
231
  url: viewParams?.page?.url,
220
232
  configAsSrc: view.bootstrap?.configAsSrc || false,
221
- mixedMode: view.bootstrap?.mixedMode || false
233
+ mixedMode: view.bootstrap?.mixedMode || false,
234
+ nonce: viewParams?.page?.nonce
222
235
  }, {
223
236
  appId: appIdentity.appName,
224
237
  bootstrapModule: versionedSpecifier,
@@ -238,7 +251,13 @@ async function getHtmlResources(view, viewParams, resourceContext) {
238
251
  }
239
252
  const dedupedUris = [...new Set(viewPreloads.uris)];
240
253
  for (const preloadUri of dedupedUris) {
241
- moduleResources.push((0, import_utils.getModuleResourceByUri)(preloadUri, runtimeEnvironment, {isPreload: true, isSSR, nonce}));
254
+ const integrity = viewPreloads.integrities.get(preloadUri);
255
+ moduleResources.push((0, import_utils.getModuleResourceByUri)(preloadUri, runtimeEnvironment, {
256
+ integrity,
257
+ isPreload: true,
258
+ isSSR,
259
+ nonce
260
+ }));
242
261
  }
243
262
  const htmlResources = await Promise.all([...configResources, ...requiredResources, ...moduleResources].map(import_utils.generateHtmlTag));
244
263
  return {
@@ -246,6 +265,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
246
265
  viewRecord: {
247
266
  resources: requiredResources,
248
267
  customElements: customElementsRecords,
268
+ moduleResources,
249
269
  bootstrapModule: bootstrapModuleRef
250
270
  }
251
271
  };
@@ -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
+ nonce: viewInfo.nonce,
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,11 @@ 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;
93
94
  const nonce = (0, import_utils.getViewNonce)(viewParams);
94
95
  let bootstrapModuleRef, versionedSpecifier = bootstrapSpecifier;
95
96
  let importMetadata = {imports: {}};
@@ -108,7 +109,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
108
109
  }
109
110
  (0, import_utils.addExternalScriptNonce)(def, nonce);
110
111
  requiredResources.push(def);
111
- const errorShimDef = await resourceRegistry.getResource({specifier: "lwr-error-shim.js", version}, runtimeEnvironment, runtimeParams);
112
+ const errorShimDef = await resourceRegistry.getResource({specifier: "lwr-error-shim.js", version}, runtimeEnvironment, {...runtimeParams, ignoreDebug: true});
112
113
  if (!errorShimDef) {
113
114
  throw Error("Failed to find definition of resource: lwr-error-shim.js");
114
115
  }
@@ -129,11 +130,13 @@ async function getHtmlResources(view, viewParams, resourceContext) {
129
130
  if (!uri) {
130
131
  throw Error(`Invalid Module Resource ${versionedSpecifier}`);
131
132
  }
132
- moduleResources.push((0, import_utils.getModuleResourceByUri)(uri, runtimeEnvironment, {isPreload: false, isSSR, nonce}));
133
+ const integrity = (0, import_utils2.getBundleIntegrity)(bootstrapModuleGraph, versionedSpecifier);
134
+ moduleResources.push((0, import_utils.getModuleResourceByUri)(uri, runtimeEnvironment, {integrity, isPreload: false, isSSR, nonce}));
133
135
  for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
134
136
  const uri2 = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
135
137
  if (uri2) {
136
- (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);
137
140
  }
138
141
  }
139
142
  if ((0, import_shared_utils.isBundler)(defRegistry)) {
@@ -171,12 +174,14 @@ async function getHtmlResources(view, viewParams, resourceContext) {
171
174
  if (!isSSR || (0, import_shared_utils.getHydrateDirective)(props)) {
172
175
  const specifier = graph.graphs[0].specifier;
173
176
  const uri = graph.uriMap[specifier];
174
- (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);
175
179
  if (bundle) {
176
180
  for (const depSpecifier of graph.graphs[0].static) {
177
- const uri2 = getPreloadUri(depSpecifier, graph.uriMap);
178
- if (uri2) {
179
- (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);
180
185
  }
181
186
  }
182
187
  }
@@ -200,7 +205,8 @@ async function getHtmlResources(view, viewParams, resourceContext) {
200
205
  id: view.id,
201
206
  url: viewParams?.page?.url,
202
207
  configAsSrc: view.bootstrap?.configAsSrc || false,
203
- mixedMode: view.bootstrap?.mixedMode || false
208
+ mixedMode: view.bootstrap?.mixedMode || false,
209
+ nonce: viewParams?.page?.nonce
204
210
  }, {
205
211
  appId: appIdentity.appName,
206
212
  bootstrapModule: versionedSpecifier,
@@ -218,7 +224,13 @@ async function getHtmlResources(view, viewParams, resourceContext) {
218
224
  }
219
225
  const dedupedUris = [...new Set(viewPreloads.uris)];
220
226
  for (const preloadUri of dedupedUris) {
221
- moduleResources.push((0, import_utils.getModuleResourceByUri)(preloadUri, runtimeEnvironment, {isPreload: true, isSSR, nonce}));
227
+ const integrity = viewPreloads.integrities.get(preloadUri);
228
+ moduleResources.push((0, import_utils.getModuleResourceByUri)(preloadUri, runtimeEnvironment, {
229
+ integrity,
230
+ isPreload: true,
231
+ isSSR,
232
+ nonce
233
+ }));
222
234
  }
223
235
  const htmlResources = await Promise.all([...configResources, ...requiredResources, ...moduleResources].map(import_utils.generateHtmlTag));
224
236
  const mapping = (0, import_shared_utils.getMappingUriPrefix)(runtimeEnvironment, runtimeParams);
@@ -234,6 +246,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
234
246
  customElements: customElementsRecords,
235
247
  endpoints,
236
248
  importMetadata,
249
+ moduleResources,
237
250
  bootstrapModule: bootstrapModuleRef
238
251
  }
239
252
  };
@@ -45,15 +45,22 @@ var import_crypto = __toModule(require("crypto"));
45
45
  function generateExternalStyle(src) {
46
46
  return `<link rel="stylesheet" href="${src}">`;
47
47
  }
48
- function generateExternalScript(type = "application/javascript", src, async, defer, nonce) {
48
+ function generateExternalScript(type = "application/javascript", src, async, defer, nonce, integrity) {
49
49
  let scriptLoadOrder = "";
50
50
  if (defer) {
51
51
  scriptLoadOrder = " defer";
52
52
  } else if (async) {
53
53
  scriptLoadOrder = " async";
54
54
  }
55
- const nonceAttr = nonce ? ` nonce="${nonce}"` : "";
56
- return `<script type="${type}"${scriptLoadOrder}${nonceAttr} 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>`;
57
64
  }
58
65
  function generateLinkPreloadTag({href, type}) {
59
66
  if (type === "module") {
@@ -62,19 +69,27 @@ function generateLinkPreloadTag({href, type}) {
62
69
  return `<link rel="preload" href="${href}" type="${type}" />`;
63
70
  }
64
71
  }
65
- function generateExternalTag({type, src = "", async, defer, isPreload, nonce}) {
72
+ function generateExternalTag({
73
+ type,
74
+ src = "",
75
+ async,
76
+ defer,
77
+ isPreload,
78
+ nonce,
79
+ integrity
80
+ }) {
66
81
  if (isPreload) {
67
82
  return generateLinkPreloadTag({href: src, type});
68
83
  } else if (type === "text/css") {
69
84
  return generateExternalStyle(src);
70
85
  } else {
71
- return generateExternalScript(type, src, async, defer, nonce);
86
+ return generateExternalScript(type, src, async, defer, nonce, integrity);
72
87
  }
73
88
  }
74
89
  async function generateInlineTag({specifier, type, content, stream, nonce}) {
75
90
  const typeStr = type === "text/css" ? "" : ` type="${type}"`;
76
91
  const tag = type === "text/css" ? "style" : "script";
77
- const nonceStr = nonce ? ` nonce="${nonce}"` : "";
92
+ const nonceStr = (0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE && nonce && nonce ? ` nonce="${nonce}"` : "";
78
93
  if (!content && !stream) {
79
94
  throw new Error(`Invalid inline Resource Definition: must have either "content" or "stream": "${specifier}"`);
80
95
  }
@@ -122,7 +137,6 @@ function normalizeRenderOptions(runtimeEnvironment, overrideRenderOptions, baseR
122
137
  return {
123
138
  skipMetadataCollection: false,
124
139
  freezeAssets: runtimeEnvironment.immutableAssets,
125
- skipCaching: false,
126
140
  viewParamCacheKey: null,
127
141
  ...baseRenderOptions,
128
142
  ...overrideRenderOptions
@@ -228,7 +242,7 @@ async function getModuleResource(moduleId, runtimeEnvironment, moduleResourceMet
228
242
  };
229
243
  }
230
244
  function getModuleResourceByUri(uri, runtimeEnvironment, moduleResourceMeta) {
231
- const {isSSR = false, isPreload = false, nonce} = moduleResourceMeta;
245
+ const {integrity, isSSR = false, isPreload = false, nonce} = moduleResourceMeta;
232
246
  const {format} = runtimeEnvironment;
233
247
  return {
234
248
  src: uri,
@@ -236,6 +250,7 @@ function getModuleResourceByUri(uri, runtimeEnvironment, moduleResourceMeta) {
236
250
  async: !isSSR && isPreload,
237
251
  defer: isSSR,
238
252
  isPreload: format !== "amd" && isPreload,
253
+ integrity,
239
254
  nonce
240
255
  };
241
256
  }
@@ -259,18 +274,20 @@ async function createJsonModule(specifier, moduleRegistry, environment, params)
259
274
  };
260
275
  }
261
276
  function getViewNonce(viewParams) {
262
- return viewParams?.page?.nonce;
277
+ return (0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE ? viewParams?.page?.nonce : void 0;
263
278
  }
264
279
  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;
280
+ if ((0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE) {
281
+ const nonce = import_crypto.default.randomBytes(16).toString("base64");
282
+ if (!viewParams.page) {
283
+ viewParams.page = {nonce};
284
+ } else {
285
+ viewParams.page.nonce = nonce;
286
+ }
270
287
  }
271
288
  }
272
289
  function addExternalScriptNonce(def, nonce) {
273
- if (!def.inline) {
290
+ if (nonce && (0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE && !def.inline) {
274
291
  def.nonce = nonce;
275
292
  }
276
293
  }
@@ -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;
@@ -167,6 +169,9 @@ var LwrViewHandler = class {
167
169
  async getViewResponse(viewRequest, route, runtimeEnvironment, runtimeParams = {}, view, viewParams, renderOptions) {
168
170
  const {id, bootstrap} = route;
169
171
  const managedView = {...view, id, bootstrap};
172
+ if (view.locale) {
173
+ runtimeParams.locale = view.locale;
174
+ }
170
175
  const viewResponse = {
171
176
  view: managedView,
172
177
  viewParams,
@@ -42,7 +42,7 @@ export declare class LwrViewRegistry implements ViewRegistry {
42
42
  addViewTransformers(transformers: ViewTransformPlugin[]): void;
43
43
  initializeViewProviders(): Promise<void[]>;
44
44
  delegateGetView(viewId: ViewIdentity): Promise<CompiledView>;
45
- getView(viewId: ViewIdentity, skipCaching?: boolean): Promise<CompiledView>;
45
+ getView(viewId: ViewIdentity): Promise<CompiledView>;
46
46
  hasViewDefinition(view: View, viewParams: ViewParams, runtimeEnvironment: RuntimeEnvironment, runtimeParams?: RuntimeParams, renderOptions?: RenderOptions): boolean;
47
47
  getViewDefinition(view: View, viewParams: ViewParams, runtimeEnvironment: RuntimeEnvironment, runtimeParams?: RuntimeParams, renderOptions?: RenderOptions): Promise<LinkedViewDefinition>;
48
48
  private renderView;
package/build/es/index.js CHANGED
@@ -1,7 +1,8 @@
1
- import { InflightTasks, createStringBuilder, extractMetadataFromHtml, getCacheKeyFromJson, getSpecifier, isLocalDev, 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
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';
@@ -122,19 +123,16 @@ export class LwrViewRegistry {
122
123
  }
123
124
  throw new Error(`No View provider was able to resolve a view for template: ${viewId.contentTemplate}`);
124
125
  }
125
- async getView(viewId, skipCaching = false) {
126
+ async getView(viewId) {
126
127
  const { contentTemplate, rootComponent } = viewId;
127
128
  const compiledViewCacheKey = getCacheKeyFromJson({ contentTemplate, rootComponent });
128
129
  logger.debug(`[view-registry][getView] compiledViewCacheKey=${compiledViewCacheKey}`);
129
130
  // use cached compiledView if available
130
- if (!skipCaching && this.compiledViews.has(compiledViewCacheKey)) {
131
+ if (this.compiledViews.has(compiledViewCacheKey)) {
131
132
  return this.compiledViews.get(compiledViewCacheKey);
132
133
  }
133
134
  const compiledView = await this.delegateGetView(viewId);
134
- // cache the compiled view
135
- if (!skipCaching) {
136
- this.compiledViews.set(compiledViewCacheKey, compiledView);
137
- }
135
+ this.compiledViews.set(compiledViewCacheKey, compiledView);
138
136
  return compiledView;
139
137
  }
140
138
  hasViewDefinition(view, viewParams, runtimeEnvironment, runtimeParams, renderOptions) {
@@ -150,6 +148,8 @@ export class LwrViewRegistry {
150
148
  locale: runtimeParams?.locale,
151
149
  basePath: runtimeParams?.basePath,
152
150
  debug: runtimeEnvironment.debug,
151
+ // Add a variable on if the nonce is enabled
152
+ nonceEnabled: getFeatureFlags().ENABLE_NONCE,
153
153
  });
154
154
  logger.debug(`[view-registry][hasViewDefinition] viewDefId=${viewDefId}`);
155
155
  // viewParams is an unbounded object and can be very large (17MB/view for developer.salesforce.com). Allowing consumers
@@ -170,13 +170,15 @@ export class LwrViewRegistry {
170
170
  }
171
171
  async getViewDefinition(view, viewParams, runtimeEnvironment, runtimeParams, renderOptions) {
172
172
  try {
173
- const { skipCaching, freezeAssets, viewParamCacheKey } = normalizeRenderOptions(this.runtimeEnvironment, renderOptions);
173
+ const { freezeAssets, viewParamCacheKey } = normalizeRenderOptions(this.runtimeEnvironment, renderOptions);
174
174
  const viewDefCacheKey = getCacheKeyFromJson({
175
175
  ...view,
176
176
  freezeAssets,
177
177
  locale: runtimeParams?.locale,
178
178
  basePath: runtimeParams?.basePath,
179
179
  debug: runtimeEnvironment.debug,
180
+ // Add a variable on if the nonce is enabled
181
+ nonceEnabled: getFeatureFlags().ENABLE_NONCE,
180
182
  });
181
183
  logger.debug(`[view-registry][getViewDefinition] viewDefCacheKey=${viewDefCacheKey}`);
182
184
  // viewParams is an unbounded object and can be very large (17MB/view for developer.salesforce.com). Allowing consumers
@@ -186,9 +188,8 @@ export class LwrViewRegistry {
186
188
  ? getCacheKeyFromJson(viewParamCacheKey)
187
189
  : getCacheKeyFromJson(viewParams);
188
190
  logger.debug(`[view-registry][getViewDefinition] viewParamKey=${viewParamKey}`);
189
- const cacheDisabled = process.env.NOCACHE === 'true' || skipCaching;
190
191
  // important: cache key does not include the unbounded viewParams
191
- if (cacheDisabled === false && this.viewDefinitions.has(viewDefCacheKey)) {
192
+ if (this.viewDefinitions.has(viewDefCacheKey)) {
192
193
  const viewDefinition = this.viewDefinitions.get(viewDefCacheKey);
193
194
  if (viewDefinition &&
194
195
  viewDefinition.paramKey === viewParamKey &&
@@ -209,20 +210,19 @@ export class LwrViewRegistry {
209
210
  }, () => this.renderView(view, updatableViewParams, runtimeEnvironment, runtimeParams, renderOptions)));
210
211
  // Once the view is generated add the nonce to the response so it can be cached and then added to the headers
211
212
  viewDefinition.nonce = getViewNonce(updatableViewParams);
212
- if (cacheDisabled === false) {
213
- const route = this.globalConfig.routes.find((r) => r.id === view.id);
214
- const ttl = shortestTtl(viewDefinition.cache?.ttl, route?.cache?.ttl);
215
- if (ttl !== 0) {
216
- // cache view definition for the shortest ttl or until it is the least recently used when ttl is undefined
217
- this.viewDefinitions.set(viewDefCacheKey, {
218
- view,
219
- viewDefinition,
220
- paramKey: viewParamKey,
221
- },
222
- // s -> ms
223
- { ttl: ttl ? ttl * 1000 : undefined });
224
- }
225
- }
213
+ const route = this.globalConfig.routes.find((r) => r.id === view.id);
214
+ const maxViewCacheTtl = getFeatureFlags().MAX_VIEW_CACHE_TTL;
215
+ // optionally set a max TTL on the view registry cache
216
+ // use a very low TTL if the shortest is 0, to allow the view to be fetched > once during a single request
217
+ const maxTtl = maxViewCacheTtl && parseInt(maxViewCacheTtl, 10);
218
+ const leastTtl = shortestTtl(viewDefinition.cache?.ttl, route?.cache?.ttl, maxTtl);
219
+ const ttl = leastTtl !== undefined ? (leastTtl === 0 ? 10 : leastTtl * 1000) : undefined;
220
+ // cache view definition for the shortest ttl or until it is the least recently used when ttl is undefined
221
+ this.viewDefinitions.set(viewDefCacheKey, {
222
+ view,
223
+ viewDefinition,
224
+ paramKey: viewParamKey,
225
+ }, { ttl });
226
226
  return viewDefinition;
227
227
  }
228
228
  catch (err) {
@@ -238,7 +238,7 @@ export class LwrViewRegistry {
238
238
  async renderView(view, viewParams, runtimeEnvironment, runtimeParams = {}, renderOptions) {
239
239
  const { id, contentTemplate, rootComponent, layoutTemplate } = view;
240
240
  const lwrResourcesId = `__LWR_RESOURCES__${Date.now()}`;
241
- const renderedContent = await this.render({ id, contentTemplate, rootComponent }, { ...viewParams, lwr_resources: lwrResourcesId }, runtimeParams, renderOptions);
241
+ const renderedContent = await this.render({ id, contentTemplate, rootComponent }, { ...viewParams, lwr_resources: lwrResourcesId }, runtimeParams, runtimeEnvironment, renderOptions);
242
242
  // normalize the renderOptions provided by the CompiledView content with the request options.
243
243
  let normalizedRenderOptions = normalizeRenderOptions(this.runtimeEnvironment, renderedContent.options, renderOptions);
244
244
  const layout = layoutTemplate || renderedContent.compiledView.layoutTemplate;
@@ -262,7 +262,7 @@ export class LwrViewRegistry {
262
262
  ...viewParams,
263
263
  body: renderedContent.renderedView,
264
264
  lwr_resources: lwrResourcesId,
265
- }, runtimeParams);
265
+ }, runtimeParams, runtimeEnvironment);
266
266
  normalizedRenderOptions = normalizeRenderOptions(this.runtimeEnvironment, renderedLayout.options, normalizedRenderOptions);
267
267
  const renderedViewDef = await this.link({
268
268
  ...renderedLayout,
@@ -306,10 +306,10 @@ export class LwrViewRegistry {
306
306
  });
307
307
  return renderedViewDef;
308
308
  }
309
- async render(viewId, viewParams, runtimeParams, renderOptions) {
309
+ async render(viewId, viewParams, runtimeParams, runtimeEnvironment, renderOptions) {
310
310
  const globalContext = this.globalData;
311
311
  const { id, rootComponent, contentTemplate } = viewId;
312
- const compiledView = await this.getView({ id, contentTemplate, rootComponent }, renderOptions?.skipCaching);
312
+ const compiledView = await this.getView({ id, contentTemplate, rootComponent });
313
313
  // Get content/body of the view
314
314
  /*
315
315
  When rendering the compiled view, a collection variable properties can be passed to the render() to be rendered in
@@ -325,7 +325,7 @@ export class LwrViewRegistry {
325
325
  ...globalContext,
326
326
  ...compiledView.properties,
327
327
  ...viewParams,
328
- });
328
+ }, runtimeEnvironment);
329
329
  const normalizedResult = normalizeRenderedResult(result);
330
330
  return {
331
331
  compiledView,
@@ -350,6 +350,7 @@ export class LwrViewRegistry {
350
350
  importer: importer || renderedView.compiledView.filePath,
351
351
  };
352
352
  const stringBuilder = createStringBuilder(renderedViewContent);
353
+ // Note: this is the TTL for the page NOT for the view registry cache
353
354
  let pageTtl = renderedView.cache.ttl;
354
355
  for (const viewTransformer of this.viewTransformers) {
355
356
  // eslint-disable-next-line no-await-in-loop
@@ -389,6 +390,7 @@ export class LwrViewRegistry {
389
390
  immutable,
390
391
  viewRecord: {
391
392
  assetReferences: reduceSourceAssetReferences(linkedMetadata.assetReferences),
393
+ moduleResources: [],
392
394
  },
393
395
  cache: { ttl: pageTtl },
394
396
  };
@@ -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 { addExternalScriptNonce, generateHtmlTag, getModuleResourceByUri, getViewNonce } 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,12 @@ 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;
95
97
  // Page level nonce for script tags
96
98
  const nonce = getViewNonce(viewParams);
97
99
  // ABS module and custom element references
@@ -109,7 +111,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
109
111
  let def = (await resourceRegistry.getResource({ specifier: shimBundle, version }, runtimeEnvironment, runtimeParams));
110
112
  if (!def) {
111
113
  // HACK: fallback to looking for the other shim.
112
- // TODO: remove this once we solve debug mode in MRT
114
+ // TODO: remove this once KJ fixes W-15953000
113
115
  let fallbackShimBundle;
114
116
  if (shimBundle === 'lwr-loader-shim-legacy.bundle.js') {
115
117
  fallbackShimBundle = 'lwr-loader-shim-legacy.bundle.min.js';
@@ -131,7 +133,10 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
131
133
  addExternalScriptNonce(def, nonce);
132
134
  requiredResources.push(def);
133
135
  // Always inline the error shim script after the shim
134
- const errorShimDef = (await resourceRegistry.getResource({ specifier: 'lwr-error-shim.js', version }, runtimeEnvironment, runtimeParams));
136
+ const errorShimDef = (await resourceRegistry.getResource({ specifier: 'lwr-error-shim.js', version }, runtimeEnvironment,
137
+ // Hack there is only a prod version of the error shim so forcing ignore debug
138
+ // So we never check the debug metadata
139
+ { ...runtimeParams, ignoreDebug: true }));
135
140
  if (!errorShimDef) {
136
141
  throw Error('Failed to find definition of resource: lwr-error-shim.js');
137
142
  }
@@ -159,12 +164,14 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
159
164
  if (!uri) {
160
165
  throw Error(`Invalid Module Resource ${versionedSpecifier}`);
161
166
  }
162
- moduleResources.push(getModuleResourceByUri(uri, runtimeEnvironment, { isPreload: false, isSSR, nonce }));
167
+ const integrity = getBundleIntegrity(bootstrapModuleGraph, versionedSpecifier);
168
+ moduleResources.push(getModuleResourceByUri(uri, runtimeEnvironment, { integrity, isPreload: false, isSSR, nonce }));
163
169
  // PRELOAD the bootstrap module static dependencies as preloaded script resources
164
170
  for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
165
171
  const uri = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
166
172
  if (uri) {
167
- setPreloadModulesMeta(depSpecifier, uri, groups, viewPreloads);
173
+ const integrity = getBundleIntegrity(bootstrapModuleGraph, depSpecifier);
174
+ setPreloadModulesMeta(depSpecifier, uri, integrity, groups, viewPreloads);
168
175
  }
169
176
  }
170
177
  // PRELOAD configured preloadModules as preloaded script resources
@@ -214,13 +221,15 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
214
221
  // PRELOAD the custom element module as a link resource
215
222
  const specifier = graph.graphs[0].specifier;
216
223
  const uri = graph.uriMap[specifier];
217
- setPreloadModulesMeta(specifier, uri, groups, viewPreloads);
224
+ const integrity = getBundleIntegrity(graph, specifier);
225
+ setPreloadModulesMeta(specifier, uri, integrity, groups, viewPreloads);
218
226
  // PRELOAD custom element static deps as link resources when bundling is ON
219
227
  if (bundle) {
220
228
  for (const depSpecifier of graph.graphs[0].static) {
221
- const uri = getPreloadUri(depSpecifier, graph.uriMap);
222
- if (uri) {
223
- setPreloadModulesMeta(depSpecifier, uri, groups, viewPreloads);
229
+ const depUri = getPreloadUri(depSpecifier, graph.uriMap);
230
+ if (depUri) {
231
+ const integrity = getBundleIntegrity(graph, depSpecifier);
232
+ setPreloadModulesMeta(depSpecifier, depUri, integrity, groups, viewPreloads);
224
233
  }
225
234
  }
226
235
  }
@@ -242,12 +251,21 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
242
251
  }
243
252
  }));
244
253
  if (viewContainsLiveElements) {
254
+ if (isLocalDev()) {
255
+ // ADD the client-side bootstrap module and mapping for local-dev
256
+ const localDevSpecifier = 'lwr_local_dev/bootstrap';
257
+ rootComponents.push(localDevSpecifier);
258
+ const localDevMod = await getModuleResource({ specifier: localDevSpecifier, version: '' }, runtimeEnvironment, {}, moduleRegistry, runtimeParams);
259
+ if (localDevMod.src)
260
+ imports[localDevSpecifier] = localDevMod.src;
261
+ }
245
262
  // ADD configuration of the bootstrapModule
246
263
  configResources.unshift(getViewBootstrapConfigurationResource({
247
264
  id: view.id,
248
265
  url: viewParams?.page?.url,
249
266
  configAsSrc: view.bootstrap?.configAsSrc || false,
250
267
  mixedMode: view.bootstrap?.mixedMode || false,
268
+ nonce: viewParams?.page?.nonce,
251
269
  }, {
252
270
  appId: appIdentity.appName,
253
271
  bootstrapModule: versionedSpecifier,
@@ -269,7 +287,13 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
269
287
  const dedupedUris = [...new Set(viewPreloads.uris)];
270
288
  // PRELOAD script resources for preload module URIs after the bootstrap module
271
289
  for (const preloadUri of dedupedUris) {
272
- moduleResources.push(getModuleResourceByUri(preloadUri, runtimeEnvironment, { isPreload: true, isSSR, nonce }));
290
+ const integrity = viewPreloads.integrities.get(preloadUri);
291
+ moduleResources.push(getModuleResourceByUri(preloadUri, runtimeEnvironment, {
292
+ integrity,
293
+ isPreload: true,
294
+ isSSR,
295
+ nonce,
296
+ }));
273
297
  }
274
298
  // generate html partial
275
299
  const htmlResources = await Promise.all([...configResources, ...requiredResources, ...moduleResources].map(generateHtmlTag));
@@ -278,6 +302,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
278
302
  viewRecord: {
279
303
  resources: requiredResources,
280
304
  customElements: customElementsRecords,
305
+ moduleResources,
281
306
  bootstrapModule: bootstrapModuleRef,
282
307
  },
283
308
  };
@@ -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
@@ -49,6 +49,10 @@ export function getViewBootstrapConfigurationResource(viewInfo, config, runtimeE
49
49
  type: CONTENT_TYPE,
50
50
  content: configString,
51
51
  inline: false,
52
+ // TODO do not create an integrity for config as src. We modify this script
53
+ // for HMR and fingerprints
54
+ // integrity: createIntegrityHash(configString),
55
+ nonce: viewInfo.nonce,
52
56
  src: url,
53
57
  };
54
58
  }
@@ -111,4 +115,9 @@ export function flattenCustomElements(arr, isSSR = false) {
111
115
  flatten(arr);
112
116
  return ret;
113
117
  }
118
+ export function getBundleIntegrity(bootstrapModuleGraph, versionedSpecifier) {
119
+ const def = bootstrapModuleGraph.linkedDefinitions[versionedSpecifier];
120
+ const integrity = def?.integrity;
121
+ return integrity;
122
+ }
114
123
  //# sourceMappingURL=utils.js.map
@@ -2,14 +2,13 @@ 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
4
  import { addExternalScriptNonce, generateHtmlTag, getModuleResourceByUri, getViewNonce } from '../utils.js';
5
- import { flattenCustomElements, getViewBootstrapConfigurationResource, getViewHmrConfigurationResource, } 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,12 @@ 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;
78
80
  // Page level nonce for script tags
79
81
  const nonce = getViewNonce(viewParams);
80
82
  // ABS module and custom element references
@@ -99,7 +101,10 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
99
101
  addExternalScriptNonce(def, nonce);
100
102
  requiredResources.push(def);
101
103
  // Always inline the error shim script after the shim
102
- const errorShimDef = (await resourceRegistry.getResource({ specifier: 'lwr-error-shim.js', version }, runtimeEnvironment, runtimeParams));
104
+ const errorShimDef = (await resourceRegistry.getResource({ specifier: 'lwr-error-shim.js', version }, runtimeEnvironment,
105
+ // Hack there is only a prod version of the error shim so forcing ignore debug
106
+ // So we never check the debug metadata
107
+ { ...runtimeParams, ignoreDebug: true }));
103
108
  if (!errorShimDef) {
104
109
  throw Error('Failed to find definition of resource: lwr-error-shim.js');
105
110
  }
@@ -126,12 +131,14 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
126
131
  if (!uri) {
127
132
  throw Error(`Invalid Module Resource ${versionedSpecifier}`);
128
133
  }
129
- moduleResources.push(getModuleResourceByUri(uri, runtimeEnvironment, { isPreload: false, isSSR, nonce }));
134
+ const integrity = getBundleIntegrity(bootstrapModuleGraph, versionedSpecifier);
135
+ moduleResources.push(getModuleResourceByUri(uri, runtimeEnvironment, { integrity, isPreload: false, isSSR, nonce }));
130
136
  // PRELOAD the bootstrap module static dependencies as preloaded script resources
131
137
  for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
132
138
  const uri = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
133
139
  if (uri) {
134
- setPreloadModulesMeta(depSpecifier, uri, groups, viewPreloads);
140
+ const integrity = getBundleIntegrity(bootstrapModuleGraph, depSpecifier);
141
+ setPreloadModulesMeta(depSpecifier, uri, integrity, groups, viewPreloads);
135
142
  }
136
143
  }
137
144
  // PRELOAD configured preloadModules as preloaded script resources
@@ -183,13 +190,15 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
183
190
  // PRELOAD the custom element module as a link resource
184
191
  const specifier = graph.graphs[0].specifier;
185
192
  const uri = graph.uriMap[specifier];
186
- setPreloadModulesMeta(specifier, uri, groups, viewPreloads);
193
+ const integrity = getBundleIntegrity(graph, specifier);
194
+ setPreloadModulesMeta(specifier, uri, integrity, groups, viewPreloads);
187
195
  // PRELOAD custom element static deps as link resources when bundling is ON
188
196
  if (bundle) {
189
197
  for (const depSpecifier of graph.graphs[0].static) {
190
- const uri = getPreloadUri(depSpecifier, graph.uriMap);
191
- if (uri) {
192
- setPreloadModulesMeta(depSpecifier, uri, groups, viewPreloads);
198
+ const depUri = getPreloadUri(depSpecifier, graph.uriMap);
199
+ if (depUri) {
200
+ const integrity = getBundleIntegrity(graph, depSpecifier);
201
+ setPreloadModulesMeta(depSpecifier, depUri, integrity, groups, viewPreloads);
193
202
  }
194
203
  }
195
204
  }
@@ -219,6 +228,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
219
228
  url: viewParams?.page?.url,
220
229
  configAsSrc: view.bootstrap?.configAsSrc || false,
221
230
  mixedMode: view.bootstrap?.mixedMode || false,
231
+ nonce: viewParams?.page?.nonce,
222
232
  }, {
223
233
  appId: appIdentity.appName,
224
234
  bootstrapModule: versionedSpecifier,
@@ -238,7 +248,13 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
238
248
  // PRELOAD script resources for preload module URIs after the bootstrap module
239
249
  const dedupedUris = [...new Set(viewPreloads.uris)];
240
250
  for (const preloadUri of dedupedUris) {
241
- moduleResources.push(getModuleResourceByUri(preloadUri, runtimeEnvironment, { isPreload: true, isSSR, nonce }));
251
+ const integrity = viewPreloads.integrities.get(preloadUri);
252
+ moduleResources.push(getModuleResourceByUri(preloadUri, runtimeEnvironment, {
253
+ integrity,
254
+ isPreload: true,
255
+ isSSR,
256
+ nonce,
257
+ }));
242
258
  }
243
259
  // generate html partial
244
260
  const htmlResources = await Promise.all([...configResources, ...requiredResources, ...moduleResources].map(generateHtmlTag));
@@ -255,6 +271,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
255
271
  customElements: customElementsRecords,
256
272
  endpoints,
257
273
  importMetadata,
274
+ moduleResources,
258
275
  bootstrapModule: bootstrapModuleRef,
259
276
  },
260
277
  };
@@ -13,7 +13,7 @@ export declare function createJsonModule(specifier: string, moduleRegistry: Publ
13
13
  /**
14
14
  * Get the nonce set on the page context of the view params
15
15
  */
16
- export declare function getViewNonce(viewParams: ViewParams): string;
16
+ export declare function getViewNonce(viewParams: ViewParams): string | undefined;
17
17
  /**
18
18
  * Generate a nonce in the page context of the view params
19
19
  */
@@ -21,5 +21,5 @@ export declare function generateViewNonce(viewParams: ViewParams): void;
21
21
  /**
22
22
  * Add a nonce to a script definition in view if it is external (not inline)
23
23
  */
24
- export declare function addExternalScriptNonce(def: ResourceDefinition, nonce: string): void;
24
+ export declare function addExternalScriptNonce(def: ResourceDefinition, nonce?: string): void;
25
25
  //# sourceMappingURL=utils.d.ts.map
package/build/es/utils.js CHANGED
@@ -1,11 +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
4
  import crypto from 'crypto';
5
5
  function generateExternalStyle(src) {
6
6
  return `<link rel="stylesheet" href="${src}">`;
7
7
  }
8
- function generateExternalScript(type = 'application/javascript', src, async, defer, nonce) {
8
+ function generateExternalScript(type = 'application/javascript', src, async, defer, nonce, integrity) {
9
+ // add script loader order attribute
9
10
  let scriptLoadOrder = '';
10
11
  if (defer) {
11
12
  scriptLoadOrder = ' defer';
@@ -13,8 +14,19 @@ function generateExternalScript(type = 'application/javascript', src, async, def
13
14
  else if (async) {
14
15
  scriptLoadOrder = ' async';
15
16
  }
16
- const nonceAttr = nonce ? ` nonce="${nonce}"` : '';
17
- return `<script type="${type}"${scriptLoadOrder}${nonceAttr} 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>`;
18
30
  }
19
31
  function generateLinkPreloadTag({ href, type }) {
20
32
  if (type === 'module') {
@@ -24,7 +36,7 @@ function generateLinkPreloadTag({ href, type }) {
24
36
  return `<link rel="preload" href="${href}" type="${type}" />`;
25
37
  }
26
38
  }
27
- function generateExternalTag({ type, src = '', async, defer, isPreload, nonce }) {
39
+ function generateExternalTag({ type, src = '', async, defer, isPreload, nonce, integrity, }) {
28
40
  if (isPreload) {
29
41
  return generateLinkPreloadTag({ href: src, type: type });
30
42
  }
@@ -32,13 +44,13 @@ function generateExternalTag({ type, src = '', async, defer, isPreload, nonce })
32
44
  return generateExternalStyle(src);
33
45
  }
34
46
  else {
35
- return generateExternalScript(type, src, async, defer, nonce);
47
+ return generateExternalScript(type, src, async, defer, nonce, integrity);
36
48
  }
37
49
  }
38
50
  async function generateInlineTag({ specifier, type, content, stream, nonce }) {
39
51
  const typeStr = type === 'text/css' ? '' : ` type="${type}"`;
40
52
  const tag = type === 'text/css' ? 'style' : 'script';
41
- const nonceStr = nonce ? ` nonce="${nonce}"` : '';
53
+ const nonceStr = getFeatureFlags().ENABLE_NONCE && nonce && nonce ? ` nonce="${nonce}"` : '';
42
54
  if (!content && !stream) {
43
55
  throw new Error(`Invalid inline Resource Definition: must have either "content" or "stream": "${specifier}"`);
44
56
  }
@@ -83,7 +95,6 @@ export function normalizeRenderOptions(runtimeEnvironment, overrideRenderOptions
83
95
  // Default render options
84
96
  skipMetadataCollection: false,
85
97
  freezeAssets: runtimeEnvironment.immutableAssets,
86
- skipCaching: false,
87
98
  viewParamCacheKey: null,
88
99
  ...baseRenderOptions,
89
100
  ...overrideRenderOptions,
@@ -205,7 +216,7 @@ export async function getModuleResource(moduleId, runtimeEnvironment, moduleReso
205
216
  };
206
217
  }
207
218
  export function getModuleResourceByUri(uri, runtimeEnvironment, moduleResourceMeta) {
208
- const { isSSR = false, isPreload = false, nonce } = moduleResourceMeta;
219
+ const { integrity, isSSR = false, isPreload = false, nonce } = moduleResourceMeta;
209
220
  const { format } = runtimeEnvironment;
210
221
  return {
211
222
  src: uri,
@@ -215,6 +226,7 @@ export function getModuleResourceByUri(uri, runtimeEnvironment, moduleResourceMe
215
226
  // only use link preload for ESM for compat reasons.
216
227
  // AMD should use regular script tags for preloading
217
228
  isPreload: format !== 'amd' && isPreload,
229
+ integrity,
218
230
  nonce,
219
231
  };
220
232
  }
@@ -243,25 +255,29 @@ export async function createJsonModule(specifier, moduleRegistry, environment, p
243
255
  * Get the nonce set on the page context of the view params
244
256
  */
245
257
  export function getViewNonce(viewParams) {
246
- return viewParams?.page?.nonce;
258
+ return getFeatureFlags().ENABLE_NONCE
259
+ ? viewParams?.page?.nonce
260
+ : undefined;
247
261
  }
248
262
  /**
249
263
  * Generate a nonce in the page context of the view params
250
264
  */
251
265
  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;
266
+ if (getFeatureFlags().ENABLE_NONCE) {
267
+ const nonce = crypto.randomBytes(16).toString('base64');
268
+ if (!viewParams.page) {
269
+ viewParams.page = { nonce };
270
+ }
271
+ else {
272
+ viewParams.page.nonce = nonce;
273
+ }
258
274
  }
259
275
  }
260
276
  /**
261
277
  * Add a nonce to a script definition in view if it is external (not inline)
262
278
  */
263
279
  export function addExternalScriptNonce(def, nonce) {
264
- if (!def.inline) {
280
+ if (nonce && getFeatureFlags().ENABLE_NONCE && !def.inline) {
265
281
  def.nonce = nonce;
266
282
  }
267
283
  }
@@ -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) {
@@ -195,6 +197,11 @@ export class LwrViewHandler {
195
197
  view, viewParams, renderOptions) {
196
198
  const { id, bootstrap } = route;
197
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
+ }
198
205
  const viewResponse = {
199
206
  view: managedView,
200
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.9",
7
+ "version": "0.13.0",
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.9",
34
- "@lwrjs/diagnostics": "0.13.0-alpha.9",
35
- "@lwrjs/instrumentation": "0.13.0-alpha.9",
36
- "@lwrjs/shared-utils": "0.13.0-alpha.9",
37
- "lru-cache": "^10.2.2"
36
+ "@lwrjs/app-service": "0.13.0",
37
+ "@lwrjs/diagnostics": "0.13.0",
38
+ "@lwrjs/instrumentation": "0.13.0",
39
+ "@lwrjs/shared-utils": "0.13.0",
40
+ "lru-cache": "^10.4.3"
38
41
  },
39
42
  "devDependencies": {
40
- "@lwrjs/types": "0.13.0-alpha.9"
43
+ "@lwrjs/types": "0.13.0"
41
44
  },
42
45
  "engines": {
43
46
  "node": ">=18.0.0"
44
47
  },
45
- "gitHead": "a2a9e1dbf39a7b04c7a43433e004895b6f4c51a3"
48
+ "gitHead": "21dc6b8ffd2e633f36b46daf9e1563992c5143b9"
46
49
  }