@lwrjs/view-registry 0.13.0-alpha.14 → 0.13.0-alpha.16

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.
@@ -232,7 +232,7 @@ var LwrViewRegistry = class {
232
232
  async renderView(view, viewParams, runtimeEnvironment, runtimeParams = {}, renderOptions) {
233
233
  const {id, contentTemplate, rootComponent, layoutTemplate} = view;
234
234
  const lwrResourcesId = `__LWR_RESOURCES__${Date.now()}`;
235
- const renderedContent = await this.render({id, contentTemplate, rootComponent}, {...viewParams, lwr_resources: lwrResourcesId}, runtimeParams, renderOptions);
235
+ const renderedContent = await this.render({id, contentTemplate, rootComponent}, {...viewParams, lwr_resources: lwrResourcesId}, runtimeParams, runtimeEnvironment, renderOptions);
236
236
  let normalizedRenderOptions = (0, import_utils.normalizeRenderOptions)(this.runtimeEnvironment, renderedContent.options, renderOptions);
237
237
  const layout = layoutTemplate || renderedContent.compiledView.layoutTemplate;
238
238
  if (!layout) {
@@ -252,7 +252,7 @@ var LwrViewRegistry = class {
252
252
  ...viewParams,
253
253
  body: renderedContent.renderedView,
254
254
  lwr_resources: lwrResourcesId
255
- }, runtimeParams);
255
+ }, runtimeParams, runtimeEnvironment);
256
256
  normalizedRenderOptions = (0, import_utils.normalizeRenderOptions)(this.runtimeEnvironment, renderedLayout.options, normalizedRenderOptions);
257
257
  const renderedViewDef = await this.link({
258
258
  ...renderedLayout,
@@ -290,7 +290,7 @@ var LwrViewRegistry = class {
290
290
  });
291
291
  return renderedViewDef;
292
292
  }
293
- async render(viewId, viewParams, runtimeParams, renderOptions) {
293
+ async render(viewId, viewParams, runtimeParams, runtimeEnvironment, renderOptions) {
294
294
  const globalContext = this.globalData;
295
295
  const {id, rootComponent, contentTemplate} = viewId;
296
296
  const compiledView = await this.getView({id, contentTemplate, rootComponent}, renderOptions?.skipCaching);
@@ -299,7 +299,7 @@ var LwrViewRegistry = class {
299
299
  ...globalContext,
300
300
  ...compiledView.properties,
301
301
  ...viewParams
302
- });
302
+ }, runtimeEnvironment);
303
303
  const normalizedResult = (0, import_utils.normalizeRenderedResult)(result);
304
304
  return {
305
305
  compiledView,
@@ -365,7 +365,8 @@ var LwrViewRegistry = class {
365
365
  renderedView: linkedAssetContent,
366
366
  immutable,
367
367
  viewRecord: {
368
- assetReferences: (0, import_utils.reduceSourceAssetReferences)(linkedMetadata.assetReferences)
368
+ assetReferences: (0, import_utils.reduceSourceAssetReferences)(linkedMetadata.assetReferences),
369
+ moduleResources: []
369
370
  },
370
371
  cache: {ttl: pageTtl}
371
372
  };
@@ -97,7 +97,8 @@ async function getHtmlResources(view, viewParams, resourceContext) {
97
97
  const viewPreloads = {
98
98
  uris: [],
99
99
  specifiers: [],
100
- groups: new Map()
100
+ groups: new Map(),
101
+ integrities: new Map()
101
102
  };
102
103
  const isSSR = view.bootstrap?.ssr;
103
104
  const version = view.bootstrap?.lwrVersion;
@@ -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
  }
@@ -238,7 +243,13 @@ async function getHtmlResources(view, viewParams, resourceContext) {
238
243
  }
239
244
  const dedupedUris = [...new Set(viewPreloads.uris)];
240
245
  for (const preloadUri of dedupedUris) {
241
- moduleResources.push((0, import_utils.getModuleResourceByUri)(preloadUri, runtimeEnvironment, {isPreload: true, isSSR, nonce}));
246
+ const integrity = viewPreloads.integrities.get(preloadUri);
247
+ moduleResources.push((0, import_utils.getModuleResourceByUri)(preloadUri, runtimeEnvironment, {
248
+ integrity,
249
+ isPreload: true,
250
+ isSSR,
251
+ nonce
252
+ }));
242
253
  }
243
254
  const htmlResources = await Promise.all([...configResources, ...requiredResources, ...moduleResources].map(import_utils.generateHtmlTag));
244
255
  return {
@@ -246,6 +257,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
246
257
  viewRecord: {
247
258
  resources: requiredResources,
248
259
  customElements: customElementsRecords,
260
+ moduleResources,
249
261
  bootstrapModule: bootstrapModuleRef
250
262
  }
251
263
  };
@@ -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
+ }
@@ -86,7 +86,8 @@ async function getHtmlResources(view, viewParams, resourceContext) {
86
86
  const viewPreloads = {
87
87
  uris: [],
88
88
  specifiers: [],
89
- groups: new Map()
89
+ groups: new Map(),
90
+ integrities: new Map()
90
91
  };
91
92
  const isSSR = view.bootstrap?.ssr;
92
93
  const version = view.bootstrap?.lwrVersion;
@@ -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
  }
@@ -218,7 +223,13 @@ async function getHtmlResources(view, viewParams, resourceContext) {
218
223
  }
219
224
  const dedupedUris = [...new Set(viewPreloads.uris)];
220
225
  for (const preloadUri of dedupedUris) {
221
- moduleResources.push((0, import_utils.getModuleResourceByUri)(preloadUri, runtimeEnvironment, {isPreload: true, isSSR, nonce}));
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
+ }));
222
233
  }
223
234
  const htmlResources = await Promise.all([...configResources, ...requiredResources, ...moduleResources].map(import_utils.generateHtmlTag));
224
235
  const mapping = (0, import_shared_utils.getMappingUriPrefix)(runtimeEnvironment, runtimeParams);
@@ -234,6 +245,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
234
245
  customElements: customElementsRecords,
235
246
  endpoints,
236
247
  importMetadata,
248
+ moduleResources,
237
249
  bootstrapModule: bootstrapModuleRef
238
250
  }
239
251
  };
@@ -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 = (0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE && 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,13 +69,21 @@ 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}) {
@@ -228,7 +243,7 @@ async function getModuleResource(moduleId, runtimeEnvironment, moduleResourceMet
228
243
  };
229
244
  }
230
245
  function getModuleResourceByUri(uri, runtimeEnvironment, moduleResourceMeta) {
231
- const {isSSR = false, isPreload = false, nonce} = moduleResourceMeta;
246
+ const {integrity, isSSR = false, isPreload = false, nonce} = moduleResourceMeta;
232
247
  const {format} = runtimeEnvironment;
233
248
  return {
234
249
  src: uri,
@@ -236,6 +251,7 @@ function getModuleResourceByUri(uri, runtimeEnvironment, moduleResourceMeta) {
236
251
  async: !isSSR && isPreload,
237
252
  defer: isSSR,
238
253
  isPreload: format !== "amd" && isPreload,
254
+ integrity,
239
255
  nonce
240
256
  };
241
257
  }
package/build/es/index.js CHANGED
@@ -242,7 +242,7 @@ export class LwrViewRegistry {
242
242
  async renderView(view, viewParams, runtimeEnvironment, runtimeParams = {}, renderOptions) {
243
243
  const { id, contentTemplate, rootComponent, layoutTemplate } = view;
244
244
  const lwrResourcesId = `__LWR_RESOURCES__${Date.now()}`;
245
- const renderedContent = await this.render({ id, contentTemplate, rootComponent }, { ...viewParams, lwr_resources: lwrResourcesId }, runtimeParams, renderOptions);
245
+ const renderedContent = await this.render({ id, contentTemplate, rootComponent }, { ...viewParams, lwr_resources: lwrResourcesId }, runtimeParams, runtimeEnvironment, renderOptions);
246
246
  // normalize the renderOptions provided by the CompiledView content with the request options.
247
247
  let normalizedRenderOptions = normalizeRenderOptions(this.runtimeEnvironment, renderedContent.options, renderOptions);
248
248
  const layout = layoutTemplate || renderedContent.compiledView.layoutTemplate;
@@ -266,7 +266,7 @@ export class LwrViewRegistry {
266
266
  ...viewParams,
267
267
  body: renderedContent.renderedView,
268
268
  lwr_resources: lwrResourcesId,
269
- }, runtimeParams);
269
+ }, runtimeParams, runtimeEnvironment);
270
270
  normalizedRenderOptions = normalizeRenderOptions(this.runtimeEnvironment, renderedLayout.options, normalizedRenderOptions);
271
271
  const renderedViewDef = await this.link({
272
272
  ...renderedLayout,
@@ -310,7 +310,7 @@ export class LwrViewRegistry {
310
310
  });
311
311
  return renderedViewDef;
312
312
  }
313
- async render(viewId, viewParams, runtimeParams, renderOptions) {
313
+ async render(viewId, viewParams, runtimeParams, runtimeEnvironment, renderOptions) {
314
314
  const globalContext = this.globalData;
315
315
  const { id, rootComponent, contentTemplate } = viewId;
316
316
  const compiledView = await this.getView({ id, contentTemplate, rootComponent }, renderOptions?.skipCaching);
@@ -329,7 +329,7 @@ export class LwrViewRegistry {
329
329
  ...globalContext,
330
330
  ...compiledView.properties,
331
331
  ...viewParams,
332
- });
332
+ }, runtimeEnvironment);
333
333
  const normalizedResult = normalizeRenderedResult(result);
334
334
  return {
335
335
  compiledView,
@@ -393,6 +393,7 @@ export class LwrViewRegistry {
393
393
  immutable,
394
394
  viewRecord: {
395
395
  assetReferences: reduceSourceAssetReferences(linkedMetadata.assetReferences),
396
+ moduleResources: [],
396
397
  },
397
398
  cache: { ttl: pageTtl },
398
399
  };
@@ -2,7 +2,7 @@ import { logger } from '@lwrjs/diagnostics';
2
2
  import { kebabCaseToModuleSpecifier, getModuleGraphs, GraphDepth, getModuleUriPrefix, explodeSpecifier, isBundler, getHydrateDirective, isGroupie, isExternalSpecifier, } from '@lwrjs/shared-utils';
3
3
  import { AppResourceEnum, getAppSpecifier } from '@lwrjs/app-service/identity';
4
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
  function includeIdFactory(bundleConfig) {
8
8
  return (moduleRef) => {
@@ -88,6 +88,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
88
88
  uris: [],
89
89
  specifiers: [],
90
90
  groups: new Map(),
91
+ integrities: new Map(),
91
92
  };
92
93
  // Determine if server side rendering view modules
93
94
  const isSSR = view.bootstrap?.ssr;
@@ -160,12 +161,14 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
160
161
  if (!uri) {
161
162
  throw Error(`Invalid Module Resource ${versionedSpecifier}`);
162
163
  }
163
- moduleResources.push(getModuleResourceByUri(uri, runtimeEnvironment, { isPreload: false, isSSR, nonce }));
164
+ const integrity = getBundleIntegrity(bootstrapModuleGraph, versionedSpecifier);
165
+ moduleResources.push(getModuleResourceByUri(uri, runtimeEnvironment, { integrity, isPreload: false, isSSR, nonce }));
164
166
  // PRELOAD the bootstrap module static dependencies as preloaded script resources
165
167
  for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
166
168
  const uri = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
167
169
  if (uri) {
168
- setPreloadModulesMeta(depSpecifier, uri, groups, viewPreloads);
170
+ const integrity = getBundleIntegrity(bootstrapModuleGraph, depSpecifier);
171
+ setPreloadModulesMeta(depSpecifier, uri, integrity, groups, viewPreloads);
169
172
  }
170
173
  }
171
174
  // PRELOAD configured preloadModules as preloaded script resources
@@ -215,13 +218,15 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
215
218
  // PRELOAD the custom element module as a link resource
216
219
  const specifier = graph.graphs[0].specifier;
217
220
  const uri = graph.uriMap[specifier];
218
- setPreloadModulesMeta(specifier, uri, groups, viewPreloads);
221
+ const integrity = getBundleIntegrity(graph, specifier);
222
+ setPreloadModulesMeta(specifier, uri, integrity, groups, viewPreloads);
219
223
  // PRELOAD custom element static deps as link resources when bundling is ON
220
224
  if (bundle) {
221
225
  for (const depSpecifier of graph.graphs[0].static) {
222
- const uri = getPreloadUri(depSpecifier, graph.uriMap);
223
- if (uri) {
224
- 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);
225
230
  }
226
231
  }
227
232
  }
@@ -270,7 +275,13 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
270
275
  const dedupedUris = [...new Set(viewPreloads.uris)];
271
276
  // PRELOAD script resources for preload module URIs after the bootstrap module
272
277
  for (const preloadUri of dedupedUris) {
273
- moduleResources.push(getModuleResourceByUri(preloadUri, runtimeEnvironment, { isPreload: true, isSSR, nonce }));
278
+ const integrity = viewPreloads.integrities.get(preloadUri);
279
+ moduleResources.push(getModuleResourceByUri(preloadUri, runtimeEnvironment, {
280
+ integrity,
281
+ isPreload: true,
282
+ isSSR,
283
+ nonce,
284
+ }));
274
285
  }
275
286
  // generate html partial
276
287
  const htmlResources = await Promise.all([...configResources, ...requiredResources, ...moduleResources].map(generateHtmlTag));
@@ -279,6 +290,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
279
290
  viewRecord: {
280
291
  resources: requiredResources,
281
292
  customElements: customElementsRecords,
293
+ moduleResources,
282
294
  bootstrapModule: bootstrapModuleRef,
283
295
  },
284
296
  };
@@ -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
@@ -2,7 +2,7 @@ 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;
@@ -71,6 +71,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
71
71
  uris: [],
72
72
  specifiers: [],
73
73
  groups: new Map(),
74
+ integrities: new Map(),
74
75
  };
75
76
  // Determine if server side rendering view modules
76
77
  const isSSR = view.bootstrap?.ssr;
@@ -127,12 +128,14 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
127
128
  if (!uri) {
128
129
  throw Error(`Invalid Module Resource ${versionedSpecifier}`);
129
130
  }
130
- moduleResources.push(getModuleResourceByUri(uri, runtimeEnvironment, { isPreload: false, isSSR, nonce }));
131
+ const integrity = getBundleIntegrity(bootstrapModuleGraph, versionedSpecifier);
132
+ moduleResources.push(getModuleResourceByUri(uri, runtimeEnvironment, { integrity, isPreload: false, isSSR, nonce }));
131
133
  // PRELOAD the bootstrap module static dependencies as preloaded script resources
132
134
  for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
133
135
  const uri = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
134
136
  if (uri) {
135
- setPreloadModulesMeta(depSpecifier, uri, groups, viewPreloads);
137
+ const integrity = getBundleIntegrity(bootstrapModuleGraph, depSpecifier);
138
+ setPreloadModulesMeta(depSpecifier, uri, integrity, groups, viewPreloads);
136
139
  }
137
140
  }
138
141
  // PRELOAD configured preloadModules as preloaded script resources
@@ -184,13 +187,15 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
184
187
  // PRELOAD the custom element module as a link resource
185
188
  const specifier = graph.graphs[0].specifier;
186
189
  const uri = graph.uriMap[specifier];
187
- setPreloadModulesMeta(specifier, uri, groups, viewPreloads);
190
+ const integrity = getBundleIntegrity(graph, specifier);
191
+ setPreloadModulesMeta(specifier, uri, integrity, groups, viewPreloads);
188
192
  // PRELOAD custom element static deps as link resources when bundling is ON
189
193
  if (bundle) {
190
194
  for (const depSpecifier of graph.graphs[0].static) {
191
- const uri = getPreloadUri(depSpecifier, graph.uriMap);
192
- if (uri) {
193
- 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);
194
199
  }
195
200
  }
196
201
  }
@@ -239,7 +244,13 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
239
244
  // PRELOAD script resources for preload module URIs after the bootstrap module
240
245
  const dedupedUris = [...new Set(viewPreloads.uris)];
241
246
  for (const preloadUri of dedupedUris) {
242
- moduleResources.push(getModuleResourceByUri(preloadUri, runtimeEnvironment, { isPreload: true, isSSR, nonce }));
247
+ const integrity = viewPreloads.integrities.get(preloadUri);
248
+ moduleResources.push(getModuleResourceByUri(preloadUri, runtimeEnvironment, {
249
+ integrity,
250
+ isPreload: true,
251
+ isSSR,
252
+ nonce,
253
+ }));
243
254
  }
244
255
  // generate html partial
245
256
  const htmlResources = await Promise.all([...configResources, ...requiredResources, ...moduleResources].map(generateHtmlTag));
@@ -256,6 +267,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
256
267
  customElements: customElementsRecords,
257
268
  endpoints,
258
269
  importMetadata,
270
+ moduleResources,
259
271
  bootstrapModule: bootstrapModuleRef,
260
272
  },
261
273
  };
package/build/es/utils.js CHANGED
@@ -5,7 +5,8 @@ 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 = getFeatureFlags().ENABLE_NONCE && 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,7 +44,7 @@ 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 }) {
@@ -205,7 +217,7 @@ export async function getModuleResource(moduleId, runtimeEnvironment, moduleReso
205
217
  };
206
218
  }
207
219
  export function getModuleResourceByUri(uri, runtimeEnvironment, moduleResourceMeta) {
208
- const { isSSR = false, isPreload = false, nonce } = moduleResourceMeta;
220
+ const { integrity, isSSR = false, isPreload = false, nonce } = moduleResourceMeta;
209
221
  const { format } = runtimeEnvironment;
210
222
  return {
211
223
  src: uri,
@@ -215,6 +227,7 @@ export function getModuleResourceByUri(uri, runtimeEnvironment, moduleResourceMe
215
227
  // only use link preload for ESM for compat reasons.
216
228
  // AMD should use regular script tags for preloading
217
229
  isPreload: format !== 'amd' && isPreload,
230
+ integrity,
218
231
  nonce,
219
232
  };
220
233
  }
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.13.0-alpha.14",
7
+ "version": "0.13.0-alpha.16",
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.14",
34
- "@lwrjs/diagnostics": "0.13.0-alpha.14",
35
- "@lwrjs/instrumentation": "0.13.0-alpha.14",
36
- "@lwrjs/shared-utils": "0.13.0-alpha.14",
36
+ "@lwrjs/app-service": "0.13.0-alpha.16",
37
+ "@lwrjs/diagnostics": "0.13.0-alpha.16",
38
+ "@lwrjs/instrumentation": "0.13.0-alpha.16",
39
+ "@lwrjs/shared-utils": "0.13.0-alpha.16",
37
40
  "lru-cache": "^10.2.2"
38
41
  },
39
42
  "devDependencies": {
40
- "@lwrjs/types": "0.13.0-alpha.14"
43
+ "@lwrjs/types": "0.13.0-alpha.16"
41
44
  },
42
45
  "engines": {
43
46
  "node": ">=18.0.0"
44
47
  },
45
- "gitHead": "7276973cd522d9117256026fbd35ca12a9032304"
48
+ "gitHead": "5aabb958d70a4a962b207da21e852d7a801d7d44"
46
49
  }