@podium/podlet 5.1.19 → 5.2.0-next.10

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/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ # [5.2.0-next.10](https://github.com/podium-lib/podlet/compare/v5.2.0-next.9...v5.2.0-next.10) (2024-11-06)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **deps:** update dependency @podium/proxy to v5.0.29 ([0bbc78b](https://github.com/podium-lib/podlet/commit/0bbc78b07a7f3059cb8f659a23c75896c1081b2f))
7
+
1
8
  ## [5.1.19](https://github.com/podium-lib/podlet/compare/v5.1.18...v5.1.19) (2024-11-04)
2
9
 
3
10
 
package/README.md CHANGED
@@ -79,20 +79,23 @@ const podlet = new Podlet(options);
79
79
 
80
80
  ### options
81
81
 
82
- | option | type | default | required |
83
- | ----------- | --------- | ---------------- | -------- |
84
- | name | `string` | | ✓ |
85
- | version | `string` | | ✓ |
86
- | pathname | `string` | | ✓ |
87
- | manifest | `string` | `/manifest.json` | |
88
- | content | `string` | `/` | |
89
- | fallback | `string` | | |
90
- | logger | `object` | | |
91
- | development | `boolean` | `false` | |
82
+ | option | type | default | required |
83
+ | ------------ | --------- | ---------------- | -------- |
84
+ | name | `string` | | ✓ |
85
+ | version | `string` | | ✓ |
86
+ | pathname | `string` | | ✓ |
87
+ | manifest | `string` | `/manifest.json` | |
88
+ | content | `string` | `/` | |
89
+ | fallback | `string` | | |
90
+ | logger | `object` | | |
91
+ | development | `boolean` | `false` | |
92
+ | useShadowDOM | `boolean` | `false` | |
92
93
 
93
94
  #### name
94
95
 
95
- The name the podlet identifies itself by. This value must be in camelCase.
96
+ The name the podlet identifies itself by. This value can contain upper and lower case letters, numbers, the - character and the \_ character. No spaces.
97
+ When shadow DOM is used, either via the `useShadowDOM` constructor option or via the `wrapWithShadowDOM` method, the name must comply with custom element naming rules.
98
+ See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/define#valid_custom_element_names) for more information.
96
99
 
97
100
  _Example:_
98
101
 
@@ -257,6 +260,53 @@ further details.
257
260
 
258
261
  Turns development mode on or off. See the section about development mode.
259
262
 
263
+ #### useShadowDOM
264
+
265
+ Turns declarative shadow DOM encapsulation on for the podlet. When enabled, the podlet content will be wrapped inside a declarative shadow DOM wrapper to isolate it from the rest of whichever
266
+ page it is being included on.
267
+
268
+ ```js
269
+ const podlet = new Podlet({ ..., useShadowDOM: true });
270
+ ```
271
+
272
+ Please note the following caveats when using this feature:
273
+
274
+ 1. You must name your podlet following custom element naming conventions as explained here: https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/define#valid_custom_element_names
275
+ 2. In order to style your content, you will need to include your CSS inside the shadow DOM wrapper. You can do this using one of the following 2 options:
276
+
277
+ You can include a `<style>` tag before your content
278
+
279
+ ```js
280
+ res.podiumSend(`
281
+ <style>
282
+ ...styles here...
283
+ </style>
284
+ <div>...content here...</div>
285
+ `);
286
+ ```
287
+
288
+ You can have your podlet CSS included for you by using the "shadow-dom" scope
289
+
290
+ ```js
291
+ podlet.css({ value: '/path/to/css', scope: 'shadow-dom' });
292
+ res.podiumSend(`
293
+ <div>...content here...</div>
294
+ `);
295
+ ```
296
+
297
+ For more fine grained control, you can use the `podlet.wrapWithShadowDOM` method directly
298
+
299
+ ```js
300
+ const podlet = new Podlet({ ..., useShadowDOM: false });
301
+ ```
302
+
303
+ ```js
304
+ const wrapped = podlet.wrapWithShadowDOM(`<div>...content here...</div>`);
305
+ res.podiumSend(`
306
+ ${wrapped}
307
+ `);
308
+ ```
309
+
260
310
  ## Podlet Instance
261
311
 
262
312
  The podlet instance has the following API:
@@ -551,6 +601,8 @@ Sets the pathname for a podlet's javascript assets.
551
601
  When a value is set it will be internally kept and used when the podlet
552
602
  instance is serialized into a manifest JSON string.
553
603
 
604
+ In addition, JS information will be serialized into a Link header and sent as an HTTP 103 early hint with content and fallback responses so that the layout client can get access to assets before the main podlet body. The layout can use this information to generate 103 early hints for the browser so that the browser can begin downloading asset files while still waiting for the podlet and layout bodys.
605
+
554
606
  ### options
555
607
 
556
608
  | option | type | default | required |
@@ -647,6 +699,8 @@ Sets the options for a podlet's CSS assets.
647
699
  When a value is set it will be internally kept and used when the podlet
648
700
  instance is serialized into a manifest JSON string.
649
701
 
702
+ In addition, CSS information will be serialized into a Link header and sent as an HTTP 103 early hint with content and fallback responses so that the layout client can get access to assets before the main podlet body. The layout can use this information to generate 103 early hints for the browser so that the browser can begin downloading asset files while still waiting for the podlet and layout bodys.
703
+
650
704
  ### options
651
705
 
652
706
  | option | type | default | required |
package/lib/podlet.js CHANGED
@@ -7,12 +7,18 @@ import {
7
7
  import * as schema from '@podium/schemas';
8
8
  import Metrics from '@metrics/client';
9
9
  import abslog from 'abslog';
10
+ // @ts-ignore
10
11
  import objobj from 'objobj';
11
12
  import * as utils from '@podium/utils';
12
13
  import Proxy from '@podium/proxy';
13
14
  import { join, dirname } from 'node:path';
14
15
  import { fileURLToPath } from 'node:url';
16
+ // @ts-ignore
15
17
  import fs from 'node:fs';
18
+ import assert from 'node:assert';
19
+
20
+ const customElementRegex =
21
+ /^(?!(annotation-xml|color-profile|font-face|font-face-src|font-face-uri|font-face-format|font-face-name|missing-glyph)$)[a-z][a-z0-9.-]*-[a-z0-9.-]*$/;
16
22
 
17
23
  const currentDirectory = dirname(fileURLToPath(import.meta.url));
18
24
  const pkgJson = fs.readFileSync(
@@ -25,19 +31,20 @@ const { template } = utils;
25
31
 
26
32
  /**
27
33
  * @typedef {Object} PodletOptions
28
- * @property {string} name - Podlet name
29
- * @property {string} version - Podlet version
30
- * @property {string} pathname - Podlet pathname
31
- * @property {string} [manifest="/manifest.json"] - Path where the podlet manifest file is served from.
32
- * @property {string} [content="/"] - Path where the podlet content HTML markup is served from.
33
- * @property {string} [fallback=""] - Path where the podlet fallback HTML markup is served from. By default there is no fallback. Set this to for instance `"/fallback"` to serve a cacheable version of the contents in case the podlet goes down.
34
- * @property {boolean} [development=false] - a boolean flag that, when true, enables additional development setup
35
- * @property {import('abslog').AbstractLoggerOptions} [logger] - a logger to use when provided. Can be the console object if console logging is desired but can also be any Log4j compatible logging object as well. Nothing is logged if no logger is provided.
34
+ * @property {string} name - (required) podlet name
35
+ * @property {string} version - (required) podlet version
36
+ * @property {string} pathname - (required) podlet pathname
37
+ * @property {string} [manifest="/manifest.json"] - path where the podlet manifest file is served from (default '/manifest.json')
38
+ * @property {string} [content="/"] - path where the podlet content HTML markup is served from (default '/')
39
+ * @property {string} [fallback=""] - path where the podlet fallback HTML markup is served from (default '/fallback')
40
+ * @property {boolean} [development=false] - a boolean flag that, when true, enables additional development setup (default false)
41
+ * @property {boolean} [useShadowDOM=false] - a boolean flag that, when true, enables the use of ShadowDOM (default false)
42
+ * @property {import("abslog").AbstractLoggerOptions} [logger] - a logger to use when provided. Can be the console object if console logging is desired but can also be any Log4j compatible logging object as well. Nothing is logged if no logger is provided. (default null)
36
43
  * @property {import("@podium/proxy").PodiumProxyOptions} [proxy] - options that can be provided to configure the @podium/proxy instance used by the podlet. See that module for details.
37
44
  *
38
45
  * @typedef {{ debug: 'true' | 'false', locale: string, deviceType: string, requestedBy: string, mountOrigin: string, mountPathname: string, publicPathname: string }} PodletContext
39
- * @typedef {{ as?: string | false | null, crossorigin?: string | null | boolean, disabled?: boolean | '' | null, hreflang?: string | false | null, title?: string | false | null, media?: string | false | null, rel?: string | false | null, type?: string | false | null, value: string | false | null, data?: Array<{ key: string; value: string }>, strategy?: "beforeInteractive" | "afterInteractive" | "lazy", scope?: "content" | "fallback" | "all", [key: string]: any }} AssetCssLike
40
- * @typedef {{ value: string | null, crossorigin?: string | null | boolean, type?: string | null | false, integrity?: string | null | false, referrerpolicy?: string | null | false, nomodule?: boolean | null | '', async?: boolean | null | '', defer?: boolean | null | '', data?: Array<{ key: string; value: string }>, strategy?: "beforeInteractive" | "afterInteractive" | "lazy", scope?: "content" | "fallback" | "all", [key: string]: any }} AssetJsLike
46
+ * @typedef {{ as?: string | false | null, crossorigin?: string | null | boolean, disabled?: boolean | '' | null, hreflang?: string | false | null, title?: string | false | null, media?: string | false | null, rel?: string | false | null, type?: string | false | null, value: string | false | null, strategy?: "beforeInteractive" | "afterInteractive" | "lazy" | "shadow-dom", scope?: "content" | "fallback" | "all", [key: string]: any }} AssetCssLike
47
+ * @typedef {{ value: string | null, crossorigin?: string | null | boolean, type?: string | null | false, integrity?: string | null | false, referrerpolicy?: string | null | false, nomodule?: boolean | null | '', async?: boolean | null | '', defer?: boolean | null | '', data?: {[key: string]: string} | Array<{ key: string; value: string }>, strategy?: "beforeInteractive" | "afterInteractive" | "lazy" | "shadow-dom", scope?: "content" | "fallback" | "all" | "shadow-dom", [key: string]: any }} AssetJsLike
41
48
  */
42
49
 
43
50
  export default class PodiumPodlet {
@@ -281,10 +288,26 @@ export default class PodiumPodlet {
281
288
  */
282
289
  metrics = new Metrics();
283
290
 
291
+ /**
292
+ * Boolean flag that, when true, enables the use of declarative ShadowDOM in the podlet.
293
+ */
294
+ #useShadowDOM = false;
295
+
284
296
  /**
285
297
  * Creates a new instance of a Podium podlet which can be used in conjunction with your framework of choice to build podlet server apps.
286
298
  * `name`, `version` and `pathname` constructor arguments are required. All other options are optional.
287
299
  *
300
+ * * `name` - podlet name (**required**)
301
+ * * `version` - podlet version (**required**)
302
+ * * `pathname` - podlet pathname (**required**)
303
+ * * `manifest` - path where the podlet manifest file is served from (**default** `'/manifest.json'`)
304
+ * * `content` - path where the podlet content HTML markup is served from (**default** `'/'`)
305
+ * * `fallback` - path where the podlet fallback HTML markup is served from (**default** `'/fallback'`)
306
+ * * `development` - a boolean flag that, when true, enables additional development setup (**default** `false`)
307
+ * * `useShadowDOM` - a boolean flag that, when true, enables the use of declarative ShadowDOM in the podlet (**default** `false`)
308
+ * * `logger` - a logger to use when provided. Can be the console object if console logging is desired but can also be any Log4j compatible logging object as well. Nothing is logged if no logger is provided. (**default** `null`)
309
+ * * `proxy` - options that can be provided to configure the @podium/proxy instance used by the podlet. See that module for details. (**default**: `{}`)
310
+ *
288
311
  * @see https://podium-lib.io/docs/api/podlet/#constructor
289
312
  * @see https://podium-lib.io/docs/podlet/getting_started
290
313
  *
@@ -305,6 +328,7 @@ export default class PodiumPodlet {
305
328
  logger = undefined,
306
329
  development = false,
307
330
  proxy = {},
331
+ useShadowDOM = false,
308
332
  }) {
309
333
  if (schema.name(name).error)
310
334
  throw new Error(
@@ -362,6 +386,7 @@ export default class PodiumPodlet {
362
386
  this.name,
363
387
  ),
364
388
  };
389
+ this.#useShadowDOM = useShadowDOM;
365
390
 
366
391
  // Skip a tick to ensure the metric stream has been consumed
367
392
  setImmediate(() => {
@@ -517,9 +542,9 @@ export default class PodiumPodlet {
517
542
  * Takes an AssetCss instance or an object with equivalent properties, converts it to an AssetCss instance if necessary and adds it to the
518
543
  * cssRoute array.
519
544
  * @param { AssetCss | AssetCssLike } options
520
- * @returns {void}
545
+ * @returns {AssetCss}
521
546
  */
522
- #addCssAsset(options) {
547
+ #cssAsset(options) {
523
548
  const clonedOptions = JSON.parse(JSON.stringify(options));
524
549
  clonedOptions.value = this.#sanitize(
525
550
  clonedOptions.value,
@@ -530,7 +555,7 @@ export default class PodiumPodlet {
530
555
  ...clonedOptions,
531
556
  pathname: this.#pathname,
532
557
  };
533
- this.cssRoute.push(new AssetCss(args));
558
+ return new AssetCss(args);
534
559
  }
535
560
 
536
561
  /**
@@ -555,20 +580,19 @@ export default class PodiumPodlet {
555
580
  css(options) {
556
581
  if (Array.isArray(options)) {
557
582
  for (const opts of options) {
558
- this.#addCssAsset(opts);
583
+ this.cssRoute.push(this.#cssAsset(opts));
559
584
  }
560
585
  return;
561
586
  }
562
- this.#addCssAsset(options);
587
+ this.cssRoute.push(this.#cssAsset(options));
563
588
  }
564
589
 
565
590
  /**
566
- * Takes an AssetJs instance or an object with equivalent properties, converts it to an AssetJs instance if necessary and adds it to the
567
- * jsRoute array.
591
+ * Takes an AssetJs instance or an object with equivalent properties, converts it to an AssetJs instance if necessary and returns it.
568
592
  * @param { AssetJs | AssetJsLike } options
569
- * @returns {void}
593
+ * @returns {AssetJs}
570
594
  */
571
- #addJsAsset(options) {
595
+ #jsAsset(options) {
572
596
  const clonedOptions = JSON.parse(JSON.stringify(options));
573
597
  clonedOptions.value = this.#sanitize(
574
598
  clonedOptions.value,
@@ -581,19 +605,31 @@ export default class PodiumPodlet {
581
605
  pathname: this.#pathname,
582
606
  };
583
607
 
584
- // Convert data attribute object structure to array of key value objects
585
- if (typeof args.data === 'object' && args.data !== null) {
586
- const data = [];
587
- Object.keys(args.data).forEach((key) => {
588
- data.push({
589
- value: args.data[key],
590
- key,
608
+ if (args.data) {
609
+ // validate that key value objects provided are compliant
610
+ if (Array.isArray(args.data)) {
611
+ for (const data of args.data) {
612
+ if (!data.key || !data.value) {
613
+ throw new TypeError(
614
+ `JS Asset data object "${JSON.stringify(data)}" must contain both a 'key' and a 'value' attribute.`,
615
+ );
616
+ }
617
+ }
618
+ }
619
+ // Convert data attribute object structure to array of key value objects
620
+ else if (typeof args.data === 'object') {
621
+ const data = [];
622
+ Object.keys(args.data).forEach((key) => {
623
+ data.push({
624
+ value: args.data[key],
625
+ key,
626
+ });
591
627
  });
592
- });
593
- args.data = data;
628
+ args.data = data;
629
+ }
594
630
  }
595
631
 
596
- this.jsRoute.push(new AssetJs(args));
632
+ return new AssetJs(args);
597
633
  }
598
634
 
599
635
  /**
@@ -618,11 +654,11 @@ export default class PodiumPodlet {
618
654
  js(options) {
619
655
  if (Array.isArray(options)) {
620
656
  for (const opts of options) {
621
- this.#addJsAsset(opts);
657
+ this.jsRoute.push(this.#jsAsset(opts));
622
658
  }
623
659
  return;
624
660
  }
625
- this.#addJsAsset(options);
661
+ this.jsRoute.push(this.#jsAsset(options));
626
662
  }
627
663
 
628
664
  /**
@@ -800,10 +836,50 @@ export default class PodiumPodlet {
800
836
  * @returns {string}
801
837
  */
802
838
  render(incoming, data, ...args) {
839
+ const markup = this.#useShadowDOM ? this.wrapWithShadowDOM(data) : data;
803
840
  if (!incoming.development) {
804
- return data;
841
+ return markup;
805
842
  }
806
- return this.#view(incoming, data, ...args);
843
+ return this.#view(incoming, markup, ...args);
844
+ }
845
+
846
+ /**
847
+ * Function that takes in the podlet content,wraps it in declarative shadow DOM and returns it.
848
+ * @param {string} data - the podlet content to wrap in declarative shadow DOM as an HTML markup string
849
+ *
850
+ * @example
851
+ * ```js
852
+ * const content = podlet.wrapWithShadowDOM('<div>content to render</div>');
853
+ * ```
854
+ */
855
+ wrapWithShadowDOM(data) {
856
+ assert.ok(
857
+ customElementRegex.test(this.name),
858
+ `When using the constructor argument "useShadowDOM" or the method podlet.wrapWithShadowDOM, podlet.name must conform to custom element naming conventions. The name "${this.name}" does not comply. See https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/define#valid_custom_element_names for more information.`,
859
+ );
860
+
861
+ const styles = this.cssRoute
862
+ .filter((css) => css.strategy === 'shadow-dom')
863
+ .map((css) => css.toHTML());
864
+
865
+ const scripts = this.jsRoute
866
+ .filter((js) => js.strategy === 'shadow-dom')
867
+ .map((js) => js.toHTML());
868
+
869
+ // Wrap the markup in DSD.
870
+ return `
871
+ <${this.name}>
872
+ <template shadowrootmode="open">
873
+ ${styles.join('\n')}
874
+ ${data}
875
+ ${scripts.join('\n')}
876
+ </template>
877
+ </${this.name}>
878
+ <script>(()=>{function e(d){HTMLTemplateElement.prototype.hasOwnProperty("shadowRootMode")||d.querySelectorAll("template[shadowrootmode]").forEach(o=>{let
879
+ n=o.getAttribute("shadowrootmode"),s=o.hasAttribute("shadowrootdelegatesfocus"),t=o.parentNode.attachShadow({mode:n,delegatesFocus:s});t.appendChild(o.content),o.remove(),e(t)})}var
880
+ r;(r=document.currentScript)!=null&&r.previousElementSibling&&e(document.currentScript.previousElementSibling);})();
881
+ </script>
882
+ `;
807
883
  }
808
884
 
809
885
  /**
@@ -865,8 +941,9 @@ export default class PodiumPodlet {
865
941
  );
866
942
  }
867
943
 
868
- // Determin if the request should be proxied and do if so
944
+ // Determine if the request should be proxied and do if so
869
945
  if (incoming.development && proxy) {
946
+ // @ts-ignore
870
947
  await this.httpProxy.process(incoming);
871
948
  }
872
949
 
@@ -903,6 +980,18 @@ export default class PodiumPodlet {
903
980
  // if this is a proxy request then no further work should be done.
904
981
  if (incoming.proxy) return;
905
982
 
983
+ const js = incoming.js.map(
984
+ // @ts-ignore
985
+ (asset) => asset.toHeader() + '; asset-type=script',
986
+ );
987
+
988
+ const css = incoming.css.map(
989
+ // @ts-ignore
990
+ (asset) => asset.toHeader() + '; asset-type=style',
991
+ );
992
+
993
+ res.header('Link', [...js, ...css].join(', '));
994
+
906
995
  // set "incoming" on res.locals.podium
907
996
  objobj.set('locals.podium', incoming, res);
908
997
 
@@ -910,8 +999,15 @@ export default class PodiumPodlet {
910
999
  res.header('podlet-version', this.version);
911
1000
  }
912
1001
 
913
- res.podiumSend = (data, ...args) =>
914
- res.send(this.render(incoming, data, ...args));
1002
+ res.sendHeaders = () => {
1003
+ res.write('');
1004
+ return res;
1005
+ };
1006
+
1007
+ res.podiumSend = (data, ...args) => {
1008
+ res.write(this.render(incoming, data, ...args));
1009
+ res.end();
1010
+ };
915
1011
 
916
1012
  next();
917
1013
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@podium/podlet",
3
- "version": "5.1.19",
3
+ "version": "5.2.0-next.10",
4
4
  "type": "module",
5
5
  "description": "Module for building page fragment servers in a micro frontend architecture.",
6
6
  "license": "MIT",
@@ -34,8 +34,8 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@metrics/client": "2.5.3",
37
+ "@podium/schemas": "5.1.0",
37
38
  "@podium/proxy": "5.0.29",
38
- "@podium/schemas": "5.0.6",
39
39
  "@podium/utils": "5.3.1",
40
40
  "abslog": "2.4.4",
41
41
  "ajv": "8.17.1",
@@ -55,6 +55,7 @@
55
55
  "prettier": "3.3.3",
56
56
  "semantic-release": "24.1.2",
57
57
  "tap": "18.8.0",
58
- "typescript": "5.5.4"
58
+ "typescript": "5.5.4",
59
+ "undici": "^6.19.7"
59
60
  }
60
61
  }
package/types/podlet.d.ts CHANGED
@@ -73,25 +73,37 @@ declare global {
73
73
 
74
74
  /**
75
75
  * @typedef {Object} PodletOptions
76
- * @property {string} name - Podlet name
77
- * @property {string} version - Podlet version
78
- * @property {string} pathname - Podlet pathname
79
- * @property {string} [manifest="/manifest.json"] - Path where the podlet manifest file is served from.
80
- * @property {string} [content="/"] - Path where the podlet content HTML markup is served from.
81
- * @property {string} [fallback=""] - Path where the podlet fallback HTML markup is served from. By default there is no fallback. Set this to for instance `"/fallback"` to serve a cacheable version of the contents in case the podlet goes down.
82
- * @property {boolean} [development=false] - a boolean flag that, when true, enables additional development setup
83
- * @property {import('abslog').AbstractLoggerOptions} [logger] - a logger to use when provided. Can be the console object if console logging is desired but can also be any Log4j compatible logging object as well. Nothing is logged if no logger is provided.
76
+ * @property {string} name - (required) podlet name
77
+ * @property {string} version - (required) podlet version
78
+ * @property {string} pathname - (required) podlet pathname
79
+ * @property {string} [manifest="/manifest.json"] - path where the podlet manifest file is served from (default '/manifest.json')
80
+ * @property {string} [content="/"] - path where the podlet content HTML markup is served from (default '/')
81
+ * @property {string} [fallback=""] - path where the podlet fallback HTML markup is served from (default '/fallback')
82
+ * @property {boolean} [development=false] - a boolean flag that, when true, enables additional development setup (default false)
83
+ * @property {boolean} [useShadowDOM=false] - a boolean flag that, when true, enables the use of ShadowDOM (default false)
84
+ * @property {import("abslog").AbstractLoggerOptions} [logger] - a logger to use when provided. Can be the console object if console logging is desired but can also be any Log4j compatible logging object as well. Nothing is logged if no logger is provided. (default null)
84
85
  * @property {import("@podium/proxy").PodiumProxyOptions} [proxy] - options that can be provided to configure the @podium/proxy instance used by the podlet. See that module for details.
85
86
  *
86
87
  * @typedef {{ debug: 'true' | 'false', locale: string, deviceType: string, requestedBy: string, mountOrigin: string, mountPathname: string, publicPathname: string }} PodletContext
87
- * @typedef {{ as?: string | false | null, crossorigin?: string | null | boolean, disabled?: boolean | '' | null, hreflang?: string | false | null, title?: string | false | null, media?: string | false | null, rel?: string | false | null, type?: string | false | null, value: string | false | null, data?: Array<{ key: string; value: string }>, strategy?: "beforeInteractive" | "afterInteractive" | "lazy", scope?: "content" | "fallback" | "all", [key: string]: any }} AssetCssLike
88
- * @typedef {{ value: string | null, crossorigin?: string | null | boolean, type?: string | null | false, integrity?: string | null | false, referrerpolicy?: string | null | false, nomodule?: boolean | null | '', async?: boolean | null | '', defer?: boolean | null | '', data?: Array<{ key: string; value: string }>, strategy?: "beforeInteractive" | "afterInteractive" | "lazy", scope?: "content" | "fallback" | "all", [key: string]: any }} AssetJsLike
88
+ * @typedef {{ as?: string | false | null, crossorigin?: string | null | boolean, disabled?: boolean | '' | null, hreflang?: string | false | null, title?: string | false | null, media?: string | false | null, rel?: string | false | null, type?: string | false | null, value: string | false | null, strategy?: "beforeInteractive" | "afterInteractive" | "lazy" | "shadow-dom", scope?: "content" | "fallback" | "all", [key: string]: any }} AssetCssLike
89
+ * @typedef {{ value: string | null, crossorigin?: string | null | boolean, type?: string | null | false, integrity?: string | null | false, referrerpolicy?: string | null | false, nomodule?: boolean | null | '', async?: boolean | null | '', defer?: boolean | null | '', data?: {[key: string]: string} | Array<{ key: string; value: string }>, strategy?: "beforeInteractive" | "afterInteractive" | "lazy" | "shadow-dom", scope?: "content" | "fallback" | "all" | "shadow-dom", [key: string]: any }} AssetJsLike
89
90
  */
90
91
  export default class PodiumPodlet {
91
92
  /**
92
93
  * Creates a new instance of a Podium podlet which can be used in conjunction with your framework of choice to build podlet server apps.
93
94
  * `name`, `version` and `pathname` constructor arguments are required. All other options are optional.
94
95
  *
96
+ * * `name` - podlet name (**required**)
97
+ * * `version` - podlet version (**required**)
98
+ * * `pathname` - podlet pathname (**required**)
99
+ * * `manifest` - path where the podlet manifest file is served from (**default** `'/manifest.json'`)
100
+ * * `content` - path where the podlet content HTML markup is served from (**default** `'/'`)
101
+ * * `fallback` - path where the podlet fallback HTML markup is served from (**default** `'/fallback'`)
102
+ * * `development` - a boolean flag that, when true, enables additional development setup (**default** `false`)
103
+ * * `useShadowDOM` - a boolean flag that, when true, enables the use of declarative ShadowDOM in the podlet (**default** `false`)
104
+ * * `logger` - a logger to use when provided. Can be the console object if console logging is desired but can also be any Log4j compatible logging object as well. Nothing is logged if no logger is provided. (**default** `null`)
105
+ * * `proxy` - options that can be provided to configure the @podium/proxy instance used by the podlet. See that module for details. (**default**: `{}`)
106
+ *
95
107
  * @see https://podium-lib.io/docs/api/podlet/#constructor
96
108
  * @see https://podium-lib.io/docs/podlet/getting_started
97
109
  *
@@ -102,7 +114,7 @@ export default class PodiumPodlet {
102
114
  * const podlet = new Podlet({ name: 'foo', version: '1.0.0', pathname: '/' });
103
115
  * ```
104
116
  */
105
- constructor({ name, version, pathname, manifest, fallback, content, logger, development, proxy, }: PodletOptions);
117
+ constructor({ name, version, pathname, manifest, fallback, content, logger, development, proxy, useShadowDOM, }: PodletOptions);
106
118
  /**
107
119
  * The name that the podlet identifies itself by. (set in the constructor) This is used internally for things like metrics but can also be used by a layout server.
108
120
  * This value must be in camelCase.
@@ -581,6 +593,16 @@ export default class PodiumPodlet {
581
593
  render<T extends {
582
594
  [key: string]: unknown;
583
595
  }>(incoming: HttpIncoming<T>, data: string, ...args: any[]): string;
596
+ /**
597
+ * Function that takes in the podlet content,wraps it in declarative shadow DOM and returns it.
598
+ * @param {string} data - the podlet content to wrap in declarative shadow DOM as an HTML markup string
599
+ *
600
+ * @example
601
+ * ```js
602
+ * const content = podlet.wrapWithShadowDOM('<div>content to render</div>');
603
+ * ```
604
+ */
605
+ wrapWithShadowDOM(data: string): string;
584
606
  /**
585
607
  * Method for processing an incoming HTTP request. This method is intended to be used to implement support for multiple HTTP frameworks and in most cases will not need to be used directly by podlet developers when creating podlet servers.
586
608
  *
@@ -620,35 +642,39 @@ export default class PodiumPodlet {
620
642
  }
621
643
  export type PodletOptions = {
622
644
  /**
623
- * - Podlet name
645
+ * - (required) podlet name
624
646
  */
625
647
  name: string;
626
648
  /**
627
- * - Podlet version
649
+ * - (required) podlet version
628
650
  */
629
651
  version: string;
630
652
  /**
631
- * - Podlet pathname
653
+ * - (required) podlet pathname
632
654
  */
633
655
  pathname: string;
634
656
  /**
635
- * - Path where the podlet manifest file is served from.
657
+ * - path where the podlet manifest file is served from (default '/manifest.json')
636
658
  */
637
659
  manifest?: string;
638
660
  /**
639
- * - Path where the podlet content HTML markup is served from.
661
+ * - path where the podlet content HTML markup is served from (default '/')
640
662
  */
641
663
  content?: string;
642
664
  /**
643
- * - Path where the podlet fallback HTML markup is served from. By default there is no fallback. Set this to for instance `"/fallback"` to serve a cacheable version of the contents in case the podlet goes down.
665
+ * - path where the podlet fallback HTML markup is served from (default '/fallback')
644
666
  */
645
667
  fallback?: string;
646
668
  /**
647
- * - a boolean flag that, when true, enables additional development setup
669
+ * - a boolean flag that, when true, enables additional development setup (default false)
648
670
  */
649
671
  development?: boolean;
650
672
  /**
651
- * - a logger to use when provided. Can be the console object if console logging is desired but can also be any Log4j compatible logging object as well. Nothing is logged if no logger is provided.
673
+ * - a boolean flag that, when true, enables the use of ShadowDOM (default false)
674
+ */
675
+ useShadowDOM?: boolean;
676
+ /**
677
+ * - a logger to use when provided. Can be the console object if console logging is desired but can also be any Log4j compatible logging object as well. Nothing is logged if no logger is provided. (default null)
652
678
  */
653
679
  logger?: import("abslog").AbstractLoggerOptions;
654
680
  /**
@@ -675,11 +701,7 @@ export type AssetCssLike = {
675
701
  rel?: string | false | null;
676
702
  type?: string | false | null;
677
703
  value: string | false | null;
678
- data?: Array<{
679
- key: string;
680
- value: string;
681
- }>;
682
- strategy?: "beforeInteractive" | "afterInteractive" | "lazy";
704
+ strategy?: "beforeInteractive" | "afterInteractive" | "lazy" | "shadow-dom";
683
705
  scope?: "content" | "fallback" | "all";
684
706
  [key: string]: any;
685
707
  };
@@ -692,12 +714,14 @@ export type AssetJsLike = {
692
714
  nomodule?: boolean | null | "";
693
715
  async?: boolean | null | "";
694
716
  defer?: boolean | null | "";
695
- data?: Array<{
717
+ data?: {
718
+ [key: string]: string;
719
+ } | Array<{
696
720
  key: string;
697
721
  value: string;
698
722
  }>;
699
- strategy?: "beforeInteractive" | "afterInteractive" | "lazy";
700
- scope?: "content" | "fallback" | "all";
723
+ strategy?: "beforeInteractive" | "afterInteractive" | "lazy" | "shadow-dom";
724
+ scope?: "content" | "fallback" | "all" | "shadow-dom";
701
725
  [key: string]: any;
702
726
  };
703
727
  import Proxy from '@podium/proxy';