@podium/client 4.5.35 → 4.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ # [4.6.0](https://github.com/podium-lib/client/compare/v4.5.35...v4.6.0) (2023-11-16)
2
+
3
+
4
+ ### Features
5
+
6
+ * use manifest asset scope field to filter assets ([fd83d64](https://github.com/podium-lib/client/commit/fd83d6486f9454f4fef2cdbcf3a05b86c81205c5))
7
+
1
8
  ## [4.5.35](https://github.com/podium-lib/client/compare/v4.5.34...v4.5.35) (2023-10-19)
2
9
 
3
10
 
package/README.md CHANGED
@@ -384,6 +384,8 @@ the content of the component. Before the stream starts flowing a `beforeStream`
384
384
  with a Response object, containing `headers`, `css` and `js` references is
385
385
  emitted.
386
386
 
387
+ **Note:** If the podlet is unavailable, the client will not receive `headers` and therefore will not set `headers` on the response.
388
+
387
389
  #### incoming (required)
388
390
 
389
391
  A HttpIncoming object. See https://github.com/podium-lib/utils/blob/master/lib/http-incoming.js
@@ -428,6 +430,26 @@ stream.once('beforeStream', (data) => {
428
430
  });
429
431
  ```
430
432
 
433
+ **Note:** If the podlet is unavailable, the client will not receive `headers` and therefore `data.headers` will be undefined.
434
+
435
+ ### Asset Scope
436
+
437
+ Both the .fetch() method and the .stream() method give you access to podlet asset objects and these CSS and JS asset objects will be filtered if the asset objects contain a `scope` property and that `scope` property matches the current response type (either content or fallback).
438
+
439
+ For example, if the podlet manifest contains a JavaScript asset definition of the form:
440
+ ```
441
+ {
442
+ js: [{ value: "https://assets.com/path/to/file.js", scope: "content" }],
443
+ }
444
+ ```
445
+ And the client performs a fetch like so:
446
+ ```js
447
+ const result = await component.fetch();
448
+ ```
449
+ Then, if the podlet successfully responds from its content route, the `result.js` property will contain the asset defined above. If, however, the podlet's content route errors and the client is forced to use the podlet's fallback content, then `result.js` property will be an empty array.
450
+
451
+ Possible `scope` values are `content`, `fallback` and `all`. For backwards compatibility reasons, when assets do not provide a `scope` property, they will always be included in both `content` and `fallback` responses.
452
+
431
453
  ## Controlling caching of the manifest
432
454
 
433
455
  The client has an internal cache where it keeps a cached version of the manifest
@@ -24,6 +24,7 @@ const _maxAge = Symbol('podium:httpoutgoing:maxage');
24
24
  const _status = Symbol('podium:httpoutgoing:status');
25
25
  const _name = Symbol('podium:httpoutgoing:name');
26
26
  const _uri = Symbol('podium:httpoutgoing:uri');
27
+ const _isfallback = Symbol('podium:httpoutgoing:isfallback');
27
28
 
28
29
  const PodletClientHttpOutgoing = class PodletClientHttpOutgoing extends PassThrough {
29
30
  constructor(
@@ -114,6 +115,9 @@ const PodletClientHttpOutgoing = class PodletClientHttpOutgoing extends PassThro
114
115
  // When redirectable is true, this object should be populated with redirect information
115
116
  // such that a user can perform manual redirection
116
117
  this[_redirect] = null;
118
+
119
+ // When isfallback is true, content fetch has failed and fallback will be served instead
120
+ this[_isfallback] = false;
117
121
  }
118
122
 
119
123
  get [Symbol.toStringTag]() {
@@ -240,9 +244,21 @@ const PodletClientHttpOutgoing = class PodletClientHttpOutgoing extends PassThro
240
244
  this[_redirectable] = value;
241
245
  }
242
246
 
247
+ /**
248
+ * Boolean getter that indicates whether the client is responding with a content or fallback payload.
249
+ * @example
250
+ * ```
251
+ * if (outgoing.isFallback) console.log("Fallback!");
252
+ * ```
253
+ */
254
+ get isFallback() {
255
+ return this[_isfallback];
256
+ }
257
+
243
258
  pushFallback() {
244
259
  this.push(this[_manifest]._fallback);
245
260
  this.push(null);
261
+ this[_isfallback] = true;
246
262
  }
247
263
  };
248
264
  module.exports = PodletClientHttpOutgoing;
@@ -81,6 +81,13 @@ module.exports = class PodletClientContentResolver {
81
81
  );
82
82
  outgoing.success = true;
83
83
  outgoing.pushFallback();
84
+ outgoing.emit(
85
+ 'beforeStream',
86
+ new Response({
87
+ js: utils.filterAssets("fallback", outgoing.manifest.js),
88
+ css: utils.filterAssets("fallback", outgoing.manifest.css),
89
+ }),
90
+ );
84
91
  resolve(outgoing);
85
92
  return;
86
93
  }
@@ -101,6 +108,13 @@ module.exports = class PodletClientContentResolver {
101
108
  );
102
109
  outgoing.success = true;
103
110
  outgoing.pushFallback();
111
+ outgoing.emit(
112
+ 'beforeStream',
113
+ new Response({
114
+ js: utils.filterAssets("fallback", outgoing.manifest.js),
115
+ css: utils.filterAssets("fallback", outgoing.manifest.css),
116
+ }),
117
+ );
104
118
  resolve(outgoing);
105
119
  return;
106
120
  }
@@ -181,6 +195,14 @@ module.exports = class PodletClientContentResolver {
181
195
  );
182
196
  outgoing.success = true;
183
197
  outgoing.pushFallback();
198
+ outgoing.emit(
199
+ 'beforeStream',
200
+ new Response({
201
+ headers: outgoing.headers,
202
+ js: utils.filterAssets("fallback", outgoing.manifest.js),
203
+ css: utils.filterAssets("fallback", outgoing.manifest.css),
204
+ }),
205
+ );
184
206
  resolve(outgoing);
185
207
  return;
186
208
  }
@@ -228,8 +250,8 @@ module.exports = class PodletClientContentResolver {
228
250
  'beforeStream',
229
251
  new Response({
230
252
  headers: outgoing.headers,
231
- js: outgoing.manifest.js,
232
- css: outgoing.manifest.css,
253
+ js: utils.filterAssets("content", outgoing.manifest.js),
254
+ css: utils.filterAssets("content", outgoing.manifest.css),
233
255
  redirect: outgoing.redirect,
234
256
  }),
235
257
  );
@@ -273,8 +295,15 @@ module.exports = class PodletClientContentResolver {
273
295
  );
274
296
 
275
297
  outgoing.success = true;
276
-
277
298
  outgoing.pushFallback();
299
+ outgoing.emit(
300
+ 'beforeStream',
301
+ new Response({
302
+ js: utils.filterAssets('fallback', outgoing.manifest.js),
303
+ css: utils.filterAssets('fallback', outgoing.manifest.css),
304
+ }),
305
+ );
306
+
278
307
  resolve(outgoing);
279
308
  });
280
309
 
package/lib/resource.js CHANGED
@@ -12,6 +12,7 @@ const util = require('util');
12
12
  const HttpOutgoing = require('./http-outgoing');
13
13
  const Response = require('./response');
14
14
  const Resolver = require('./resolver');
15
+ const utils = require('./utils');
15
16
 
16
17
  const _resolver = Symbol('podium:client:resource:resolver');
17
18
  const _options = Symbol('podium:client:resource:options');
@@ -74,7 +75,7 @@ const PodiumClientResource = class PodiumClientResource {
74
75
 
75
76
  stream.pipeline(outgoing, to);
76
77
 
77
- const { manifest, headers, redirect } = await this[_resolver].resolve(
78
+ const { manifest, headers, redirect, isFallback } = await this[_resolver].resolve(
78
79
  outgoing,
79
80
  );
80
81
 
@@ -85,8 +86,8 @@ const PodiumClientResource = class PodiumClientResource {
85
86
  return new Response({
86
87
  headers,
87
88
  content,
88
- css: manifest.css,
89
- js: manifest.js,
89
+ css: utils.filterAssets(isFallback ? "fallback" : "content", manifest.css),
90
+ js: utils.filterAssets(isFallback ? "fallback" : "content", manifest.js),
90
91
  redirect,
91
92
  });
92
93
  }
package/lib/utils.js CHANGED
@@ -71,3 +71,34 @@ module.exports.validateIncoming = (incoming = {}) => {
71
71
  inc.context = incoming;
72
72
  return inc;
73
73
  };
74
+
75
+ /**
76
+ * @typedef {import("@podium/utils").AssetCss | import("@podium/utils").AssetJs} Asset
77
+ */
78
+
79
+ /**
80
+ * Filter assets array based on scope.
81
+ * If scope property is not present, asset will be included (backwards compatibility)
82
+ * If scope property is set to "all", asset will be included.
83
+ * If scope is set to "content" and asset scope property is set to "fallback", asset will not be included
84
+ * If scope is set to "fallback" and asset scope property is set to "content", asset will not be included
85
+ * @param {"content" | "fallback" | "all"} scope
86
+ * @param {Asset[]} assets
87
+ * @returns {Asset[]}
88
+ *
89
+ * @example
90
+ * ```
91
+ * // plain objects work
92
+ * const assets = filterAssets("content", [{..., scope: "content"}, {..., scope: "fallback"}]);
93
+ * // as do AssetJs and AssetCSS objects
94
+ * const assets = filterAssets("content", [new AssetCss(), new AssetCss()]);
95
+ * ```
96
+ */
97
+ module.exports.filterAssets = (scope, assets) => {
98
+ // if undefined or null, passthrough
99
+ if (!assets) return assets;
100
+ // if a non array value is given, throw
101
+ if (!Array.isArray(assets)) throw new TypeError(`Asset definition must be of type array. Got ${typeof assets}`);
102
+ // filter the array of asset definitions to matchin scope or anything with all. Treat no scope the same as "all" for backwards compatibility.
103
+ return assets.filter(asset => !asset.scope || asset.scope === scope || asset.scope === "all");
104
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@podium/client",
3
- "version": "4.5.35",
3
+ "version": "4.6.0",
4
4
  "main": "lib/client.js",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -37,8 +37,8 @@
37
37
  "dependencies": {
38
38
  "@hapi/boom": "^9.0.0",
39
39
  "@metrics/client": "2.5.2",
40
- "@podium/schemas": "4.1.34",
41
- "@podium/utils": "4.4.41",
40
+ "@podium/schemas": "4.2.0",
41
+ "@podium/utils": "4.5.0",
42
42
  "abslog": "2.4.0",
43
43
  "http-cache-semantics": "^4.0.3",
44
44
  "lodash.clonedeep": "^4.5.0",