@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 +7 -0
- package/README.md +22 -0
- package/lib/http-outgoing.js +16 -0
- package/lib/resolver.content.js +32 -3
- package/lib/resource.js +4 -3
- package/lib/utils.js +31 -0
- package/package.json +3 -3
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
|
package/lib/http-outgoing.js
CHANGED
|
@@ -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;
|
package/lib/resolver.content.js
CHANGED
|
@@ -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.
|
|
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.
|
|
41
|
-
"@podium/utils": "4.
|
|
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",
|