@symbiotejs/symbiote 3.3.0 → 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 +34 -22
- package/node/index.js +1 -0
- package/package.json +8 -1
- package/scripts/update-exports.js +5 -2
- package/types/node/SSR.d.ts +7 -1
- package/types/node/SSR.d.ts.map +1 -1
- package/types/node/index.d.ts +2 -0
- package/types/node/index.d.ts.map +1 -0
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/node/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SSR } from './SSR.js';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@symbiotejs/symbiote",
|
|
4
|
-
"version": "3.3.
|
|
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",
|
|
@@ -36,6 +36,9 @@
|
|
|
36
36
|
"./utils": {
|
|
37
37
|
"default": "./utils/index.js"
|
|
38
38
|
},
|
|
39
|
+
"./node": {
|
|
40
|
+
"default": "./node/index.js"
|
|
41
|
+
},
|
|
39
42
|
"./core/AppRouter.js": {
|
|
40
43
|
"types": "./types/core/AppRouter.d.ts",
|
|
41
44
|
"default": "./core/AppRouter.js"
|
|
@@ -115,6 +118,10 @@
|
|
|
115
118
|
"./utils/setNestedProp.js": {
|
|
116
119
|
"types": "./types/utils/setNestedProp.d.ts",
|
|
117
120
|
"default": "./utils/setNestedProp.js"
|
|
121
|
+
},
|
|
122
|
+
"./node/SSR.js": {
|
|
123
|
+
"types": "./types/node/SSR.d.ts",
|
|
124
|
+
"default": "./node/SSR.js"
|
|
118
125
|
}
|
|
119
126
|
},
|
|
120
127
|
"publishConfig": {
|
|
@@ -10,7 +10,7 @@ import { existsSync } from 'fs';
|
|
|
10
10
|
import { join, extname, basename } from 'path';
|
|
11
11
|
|
|
12
12
|
const ROOT = new URL('..', import.meta.url).pathname;
|
|
13
|
-
const DIRS = ['core', 'utils'];
|
|
13
|
+
const DIRS = ['core', 'utils', 'node'];
|
|
14
14
|
|
|
15
15
|
async function getModules(dir) {
|
|
16
16
|
let fullDir = join(ROOT, dir);
|
|
@@ -29,12 +29,15 @@ async function run() {
|
|
|
29
29
|
'./utils': {
|
|
30
30
|
default: './utils/index.js',
|
|
31
31
|
},
|
|
32
|
+
'./node': {
|
|
33
|
+
default: './node/index.js',
|
|
34
|
+
},
|
|
32
35
|
};
|
|
33
36
|
|
|
34
37
|
for (let dir of DIRS) {
|
|
35
38
|
let modules = await getModules(dir);
|
|
36
39
|
for (let mod of modules) {
|
|
37
|
-
if (mod === './core/index.js' || mod === './utils/index.js') continue;
|
|
40
|
+
if (mod === './core/index.js' || mod === './utils/index.js' || mod === './node/index.js') continue;
|
|
38
41
|
let dtsPath = `./types/${dir}/${basename(mod, '.js')}.d.ts`;
|
|
39
42
|
if (!existsSync(join(ROOT, dtsPath))) continue;
|
|
40
43
|
exports[mod] = {
|
package/types/node/SSR.d.ts
CHANGED
|
@@ -4,12 +4,18 @@ export class SSR {
|
|
|
4
4
|
window: any;
|
|
5
5
|
}>;
|
|
6
6
|
static destroy(): void;
|
|
7
|
-
static processHtml(html: 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;
|
package/types/node/SSR.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SSR.d.ts","sourceRoot":"","sources":["../../node/SSR.js"],"names":[],"mappings":"
|
|
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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../node/index.js"],"names":[],"mappings":""}
|