@symbiotejs/symbiote 3.3.1 → 3.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/node/SSR.js CHANGED
@@ -66,14 +66,16 @@ function resolveTextTokens(text, node) {
66
66
  * Serialize a custom element to HTML with DSD and rootStyles support.
67
67
  * @param {HTMLElement} el
68
68
  * @param {Set<Function>} emittedStyles - track which constructors already emitted rootStyles
69
+ * @param {string} [nonce] - CSP nonce for inline style tags
69
70
  * @returns {string}
70
71
  */
71
- function serializeElement(el, emittedStyles) {
72
+ function serializeElement(el, emittedStyles, nonce) {
72
73
  let tagName = el.localName;
73
74
  let attrsStr = serializeAttrs(el);
74
75
  let ctor = /** @type {any} */ (el).constructor;
75
76
 
76
77
  let innerContent = '';
78
+ let nonceAttr = nonce ? ` nonce="${nonce}"` : '';
77
79
 
78
80
  // Light DOM rootStyles — inject <style> (once per constructor):
79
81
  if (ctor.rootStyleSheets && !emittedStyles.has(ctor)) {
@@ -81,7 +83,7 @@ function serializeElement(el, emittedStyles) {
81
83
  for (let sheet of ctor.rootStyleSheets) {
82
84
  let cssText = extractCSS(sheet);
83
85
  if (cssText) {
84
- innerContent += `<style>${cssText}</style>`;
86
+ innerContent += `<style${nonceAttr}>${cssText}</style>`;
85
87
  }
86
88
  }
87
89
  }
@@ -95,19 +97,19 @@ function serializeElement(el, emittedStyles) {
95
97
  for (let sheet of ctor.shadowStyleSheets) {
96
98
  let cssText = extractCSS(sheet);
97
99
  if (cssText) {
98
- shadowHTML += `<style>${cssText}</style>`;
100
+ shadowHTML += `<style${nonceAttr}>${cssText}</style>`;
99
101
  }
100
102
  }
101
103
  }
102
104
  for (let child of el.shadowRoot.childNodes) {
103
- shadowHTML += serializeNode(child, shadowEmitted);
105
+ shadowHTML += serializeNode(child, shadowEmitted, nonce);
104
106
  }
105
107
  innerContent += `<template shadowrootmode="open">${shadowHTML}</template>`;
106
108
  }
107
109
 
108
110
  // Light DOM content:
109
111
  for (let child of el.childNodes) {
110
- innerContent += serializeNode(child, emittedStyles);
112
+ innerContent += serializeNode(child, emittedStyles, nonce);
111
113
  }
112
114
 
113
115
  return `<${tagName}${attrsStr}>${innerContent}</${tagName}>`;
@@ -132,12 +134,13 @@ function serializeAttrs(el) {
132
134
  * Serialize a DOM node to HTML string.
133
135
  * @param {Node} node
134
136
  * @param {Set<Function>} emittedStyles
137
+ * @param {string} [nonce] - CSP nonce for inline style tags
135
138
  * @returns {string}
136
139
  */
137
- function serializeNode(node, emittedStyles) {
140
+ function serializeNode(node, emittedStyles, nonce) {
138
141
  // Custom element — recurse:
139
142
  if (node.nodeType === 1 && /** @type {Element} */ (node).localName?.includes('-')) {
140
- return serializeElement(/** @type {HTMLElement} */ (node), emittedStyles);
143
+ return serializeElement(/** @type {HTMLElement} */ (node), emittedStyles, nonce);
141
144
  }
142
145
  // Regular element:
143
146
  if (node.nodeType === 1) {
@@ -145,7 +148,7 @@ function serializeNode(node, emittedStyles) {
145
148
  let attrsStr = serializeAttrs(el);
146
149
  let childHTML = '';
147
150
  for (let child of el.childNodes) {
148
- childHTML += serializeNode(child, emittedStyles);
151
+ childHTML += serializeNode(child, emittedStyles, nonce);
149
152
  }
150
153
  return `<${el.localName}${attrsStr}>${childHTML}</${el.localName}>`;
151
154
  }
@@ -164,13 +167,16 @@ function serializeNode(node, emittedStyles) {
164
167
  * Stream-serialize an element, yielding chunks.
165
168
  * @param {HTMLElement} el
166
169
  * @param {Set<Function>} emittedStyles
170
+ * @param {string} [nonce] - CSP nonce for inline style tags
167
171
  * @returns {AsyncGenerator<string>}
168
172
  */
169
- async function* streamElement(el, emittedStyles) {
173
+ async function* streamElement(el, emittedStyles, nonce) {
170
174
  let tagName = el.localName;
171
175
  let attrsStr = serializeAttrs(el);
172
176
  let ctor = /** @type {any} */ (el).constructor;
173
177
 
178
+ let nonceAttr = nonce ? ` nonce="${nonce}"` : '';
179
+
174
180
  yield `<${tagName}${attrsStr}>`;
175
181
 
176
182
  // Light DOM rootStyles (once per constructor):
@@ -179,7 +185,7 @@ async function* streamElement(el, emittedStyles) {
179
185
  for (let sheet of ctor.rootStyleSheets) {
180
186
  let cssText = extractCSS(sheet);
181
187
  if (cssText) {
182
- yield `<style>${cssText}</style>`;
188
+ yield `<style${nonceAttr}>${cssText}</style>`;
183
189
  }
184
190
  }
185
191
  }
@@ -193,19 +199,19 @@ async function* streamElement(el, emittedStyles) {
193
199
  for (let sheet of ctor.shadowStyleSheets) {
194
200
  let cssText = extractCSS(sheet);
195
201
  if (cssText) {
196
- yield `<style>${cssText}</style>`;
202
+ yield `<style${nonceAttr}>${cssText}</style>`;
197
203
  }
198
204
  }
199
205
  }
200
206
  for (let child of el.shadowRoot.childNodes) {
201
- yield* streamNode(child, shadowEmitted);
207
+ yield* streamNode(child, shadowEmitted, nonce);
202
208
  }
203
209
  yield '</template>';
204
210
  }
205
211
 
206
212
  // Light DOM content:
207
213
  for (let child of el.childNodes) {
208
- yield* streamNode(child, emittedStyles);
214
+ yield* streamNode(child, emittedStyles, nonce);
209
215
  }
210
216
 
211
217
  yield `</${tagName}>`;
@@ -215,11 +221,12 @@ async function* streamElement(el, emittedStyles) {
215
221
  * Stream-serialize a DOM node.
216
222
  * @param {Node} node
217
223
  * @param {Set<Function>} emittedStyles
224
+ * @param {string} [nonce] - CSP nonce for inline style tags
218
225
  * @returns {AsyncGenerator<string>}
219
226
  */
220
- async function* streamNode(node, emittedStyles) {
227
+ async function* streamNode(node, emittedStyles, nonce) {
221
228
  if (node.nodeType === 1 && /** @type {Element} */ (node).localName?.includes('-')) {
222
- yield* streamElement(/** @type {HTMLElement} */ (node), emittedStyles);
229
+ yield* streamElement(/** @type {HTMLElement} */ (node), emittedStyles, nonce);
223
230
  return;
224
231
  }
225
232
  if (node.nodeType === 1) {
@@ -228,7 +235,7 @@ async function* streamNode(node, emittedStyles) {
228
235
  if (el.childNodes.length) {
229
236
  yield `<${el.localName}${attrsStr}>`;
230
237
  for (let child of el.childNodes) {
231
- yield* streamNode(child, emittedStyles);
238
+ yield* streamNode(child, emittedStyles, nonce);
232
239
  }
233
240
  yield `</${el.localName}>`;
234
241
  } else {
@@ -348,15 +355,18 @@ export class SSR {
348
355
  * Initializes and destroys the SSR environment automatically.
349
356
  *
350
357
  * @param {string} html - Any HTML string containing custom element tags
358
+ * @param {{ nonce?: string }} [options] - SSR options
351
359
  * @returns {Promise<string>} Processed HTML with rendered components
352
360
  *
353
361
  * @example
354
362
  * ```js
355
363
  * await import('./my-components.js');
356
364
  * let result = await SSR.processHtml('<div><my-header></my-header><main>content</main></div>');
365
+ * // With CSP nonce:
366
+ * let safe = await SSR.processHtml('<my-app></my-app>', { nonce: 'abc123' });
357
367
  * ```
358
368
  */
359
- static async processHtml(html) {
369
+ static async processHtml(html, options = {}) {
360
370
  let autoInited = !SSR.#doc;
361
371
  if (autoInited) {
362
372
  await SSR.init();
@@ -365,7 +375,7 @@ export class SSR {
365
375
  let emittedStyles = new Set();
366
376
  let result = '';
367
377
  for (let child of SSR.#doc.body.childNodes) {
368
- result += serializeNode(child, emittedStyles);
378
+ result += serializeNode(child, emittedStyles, options.nonce);
369
379
  }
370
380
  SSR.#doc.body.innerHTML = '';
371
381
  if (autoInited) {
@@ -380,9 +390,10 @@ export class SSR {
380
390
  *
381
391
  * @param {string} tagName - Custom element tag name
382
392
  * @param {Object<string, string>} [attrs] - Attributes to set on the element
393
+ * @param {{ nonce?: string }} [options] - SSR options
383
394
  * @returns {string}
384
395
  */
385
- static renderToString(tagName, attrs = {}) {
396
+ static renderToString(tagName, attrs = {}, options = {}) {
386
397
  if (!SSR.#doc) {
387
398
  throw new Error('[Symbiote SSR] Call SSR.init() before renderToString()');
388
399
  }
@@ -391,7 +402,7 @@ export class SSR {
391
402
  el.setAttribute(key, String(val));
392
403
  }
393
404
  SSR.#doc.body.appendChild(el);
394
- let html = serializeElement(el, new Set());
405
+ let html = serializeElement(el, new Set(), options.nonce);
395
406
  el.remove();
396
407
  return html;
397
408
  }
@@ -402,9 +413,10 @@ export class SSR {
402
413
  *
403
414
  * @param {string} tagName - Custom element tag name
404
415
  * @param {Object<string, string>} [attrs] - Attributes to set on the element
416
+ * @param {{ nonce?: string }} [options] - SSR options
405
417
  * @returns {AsyncGenerator<string>}
406
418
  */
407
- static async *renderToStream(tagName, attrs = {}) {
419
+ static async *renderToStream(tagName, attrs = {}, options = {}) {
408
420
  if (!SSR.#doc) {
409
421
  throw new Error('[Symbiote SSR] Call SSR.init() before renderToStream()');
410
422
  }
@@ -413,7 +425,7 @@ export class SSR {
413
425
  el.setAttribute(key, String(val));
414
426
  }
415
427
  SSR.#doc.body.appendChild(el);
416
- yield* streamElement(el, new Set());
428
+ yield* streamElement(el, new Set(), options.nonce);
417
429
  el.remove();
418
430
  }
419
431
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@symbiotejs/symbiote",
4
- "version": "3.3.1",
4
+ "version": "3.3.2",
5
5
  "description": "Symbiote.js - zero-dependency close-to-platform frontend library to build super-powered web components",
6
6
  "author": "team@rnd-pro.com",
7
7
  "license": "MIT",
@@ -4,12 +4,18 @@ export class SSR {
4
4
  window: any;
5
5
  }>;
6
6
  static destroy(): void;
7
- static processHtml(html: string): Promise<string>;
7
+ static processHtml(html: string, options?: {
8
+ nonce?: string;
9
+ }): Promise<string>;
8
10
  static renderToString(tagName: string, attrs?: {
9
11
  [x: string]: string;
12
+ }, options?: {
13
+ nonce?: string;
10
14
  }): string;
11
15
  static renderToStream(tagName: string, attrs?: {
12
16
  [x: string]: string;
17
+ }, options?: {
18
+ nonce?: string;
13
19
  }): AsyncGenerator<string>;
14
20
  }
15
21
  export default SSR;
@@ -1 +1 @@
1
- {"version":3,"file":"SSR.d.ts","sourceRoot":"","sources":["../../node/SSR.js"],"names":[],"mappings":"AAuPA;IAEE,8BAAmB;IACnB,8BAAmB;IAMnB;;;OAkEC;IAMD,uBAeC;IAeD,yBATW,MAAM,GACJ,OAAO,CAAC,MAAM,CAAC,CAwB3B;IAUD,+BAJW,MAAM;;QAEJ,MAAM,CAclB;IAUD,+BAJW,MAAM;;QAEJ,cAAc,CAAC,MAAM,CAAC,CAalC;CACF"}
1
+ {"version":3,"file":"SSR.d.ts","sourceRoot":"","sources":["../../node/SSR.js"],"names":[],"mappings":"AA8PA;IAEE,8BAAmB;IACnB,8BAAmB;IAMnB;;;OAkEC;IAMD,uBAeC;IAkBD,yBAZW,MAAM,YACN;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAChB,OAAO,CAAC,MAAM,CAAC,CA0B3B;IAWD,+BALW,MAAM;;iBAEN;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAChB,MAAM,CAclB;IAWD,+BALW,MAAM;;iBAEN;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAChB,cAAc,CAAC,MAAM,CAAC,CAalC;CACF"}