@podium/client 5.2.0-next.2 → 5.2.0-next.3
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 +1 -0
- package/lib/client.js +2 -0
- package/lib/http-outgoing.js +14 -0
- package/lib/resolver.content.js +7 -1
- package/lib/resolver.js +5 -1
- package/package.json +2 -2
- package/types/client.d.ts +2 -0
- package/types/http-outgoing.d.ts +1 -0
- package/types/resolver.content.d.ts +2 -0
- package/types/resolver.d.ts +2 -0
- package/types/utils.d.ts +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [5.2.0-next.3](https://github.com/podium-lib/client/compare/v5.2.0-next.2...v5.2.0-next.3) (2024-09-20)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* write early hints to browser ([42513a3](https://github.com/podium-lib/client/commit/42513a38f5304648f7b2fb915995c66dc1dd3594))
|
|
7
|
+
|
|
1
8
|
# [5.2.0-next.2](https://github.com/podium-lib/client/compare/v5.2.0-next.1...v5.2.0-next.2) (2024-09-16)
|
|
2
9
|
|
|
3
10
|
|
package/README.md
CHANGED
|
@@ -152,6 +152,7 @@ The following values can be provided:
|
|
|
152
152
|
- `throwable` - {Boolean} - Defines whether an error should be thrown if a failure occurs during the process of fetching a podium component. Defaults to `false` - Optional.
|
|
153
153
|
- `excludeBy` - {Object} - Lets you define a set of rules where a `fetch` call will not be resolved if it matches. - Optional.
|
|
154
154
|
- `includeBy` - {Object} - Inverse of `excludeBy`. Setting both at the same time will throw. - Optional.
|
|
155
|
+
- `earlyHints` - {boolean} - Can be used to disable early hints from being sent to the browser for this resource, see [HTTP Status 103 Early Hints](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/103).
|
|
155
156
|
|
|
156
157
|
##### `excludeBy` and `includeBy`
|
|
157
158
|
|
package/lib/client.js
CHANGED
|
@@ -62,6 +62,7 @@ const MAX_AGE = Infinity;
|
|
|
62
62
|
* @property {boolean} [redirectable=false] Set to `true` to allow podlet to respond with a redirect. You need to look for the redirect response from the podlet and return a redirect response to the browser yourself.
|
|
63
63
|
* @property {import('./resource.js').RequestFilterOptions} [excludeBy] Used by `fetch` to conditionally skip fetching the podlet content based on values on the request.
|
|
64
64
|
* @property {import('./resource.js').RequestFilterOptions} [includeBy] Used by `fetch` to conditionally skip fetching the podlet content based on values on the request.
|
|
65
|
+
* @property {boolean} [earlyHints=true]
|
|
65
66
|
*/
|
|
66
67
|
|
|
67
68
|
export default class PodiumClient extends EventEmitter {
|
|
@@ -212,6 +213,7 @@ export default class PodiumClient extends EventEmitter {
|
|
|
212
213
|
httpAgent: this.#options.httpAgent,
|
|
213
214
|
includeBy: this.#options.includeBy,
|
|
214
215
|
excludeBy: this.#options.excludeBy,
|
|
216
|
+
earlyHints: true,
|
|
215
217
|
...options,
|
|
216
218
|
};
|
|
217
219
|
|
package/lib/http-outgoing.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { PassThrough } from 'stream';
|
|
2
2
|
import assert from 'assert';
|
|
3
|
+
import { toPreloadAssetObjects } from './utils.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* @typedef {object} PodiumClientHttpOutgoingOptions
|
|
@@ -338,6 +339,19 @@ export default class PodletClientHttpOutgoing extends PassThrough {
|
|
|
338
339
|
this.#isFallback = true;
|
|
339
340
|
}
|
|
340
341
|
|
|
342
|
+
writeEarlyHints(cb = () => {}) {
|
|
343
|
+
if (this.#incoming.response.writeEarlyHints) {
|
|
344
|
+
const preloads = toPreloadAssetObjects([
|
|
345
|
+
...(this.js || []),
|
|
346
|
+
...(this.css || []),
|
|
347
|
+
]);
|
|
348
|
+
const link = preloads.map((preload) => preload.toHeader());
|
|
349
|
+
if (link.length) {
|
|
350
|
+
this.#incoming.response.writeEarlyHints({ link }, cb);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
341
355
|
get [Symbol.toStringTag]() {
|
|
342
356
|
return 'PodletClientHttpOutgoing';
|
|
343
357
|
}
|
package/lib/resolver.content.js
CHANGED
|
@@ -27,6 +27,7 @@ const UA_STRING = `${pkg.name} ${pkg.version}`;
|
|
|
27
27
|
* @property {string} clientName
|
|
28
28
|
* @property {import('./http.js').default} [http]
|
|
29
29
|
* @property {import('abslog').AbstractLoggerOptions} [logger]
|
|
30
|
+
* @property {boolean} [earlyHints]
|
|
30
31
|
*/
|
|
31
32
|
|
|
32
33
|
export default class PodletClientContentResolver {
|
|
@@ -34,6 +35,7 @@ export default class PodletClientContentResolver {
|
|
|
34
35
|
#metrics;
|
|
35
36
|
#histogram;
|
|
36
37
|
#http;
|
|
38
|
+
#earlyHints;
|
|
37
39
|
|
|
38
40
|
/**
|
|
39
41
|
* @constructor
|
|
@@ -44,6 +46,8 @@ export default class PodletClientContentResolver {
|
|
|
44
46
|
this.#http = options.http || new HTTP();
|
|
45
47
|
const name = options.clientName;
|
|
46
48
|
this.#log = abslog(options.logger);
|
|
49
|
+
this.#earlyHints =
|
|
50
|
+
typeof options.earlyHints === 'boolean' ? options.earlyHints : true;
|
|
47
51
|
this.#metrics = new Metrics();
|
|
48
52
|
this.#histogram = this.#metrics.histogram({
|
|
49
53
|
name: 'podium_client_resolver_content_resolve',
|
|
@@ -144,7 +148,7 @@ export default class PodletClientContentResolver {
|
|
|
144
148
|
method: 'GET',
|
|
145
149
|
query: outgoing.reqOptions.query,
|
|
146
150
|
headers,
|
|
147
|
-
onInfo({ statusCode, headers }) {
|
|
151
|
+
onInfo: ({ statusCode, headers }) => {
|
|
148
152
|
if (statusCode === 103 && !hintsReceived) {
|
|
149
153
|
const parsedAssetObjects = parseLinkHeaders(headers.link);
|
|
150
154
|
|
|
@@ -158,6 +162,8 @@ export default class PodletClientContentResolver {
|
|
|
158
162
|
outgoing.js = filterAssets('content', scriptObjects);
|
|
159
163
|
// set the content css asset objects
|
|
160
164
|
outgoing.css = filterAssets('content', styleObjects);
|
|
165
|
+
// write the early hints to the browser
|
|
166
|
+
if (this.#earlyHints) outgoing.writeEarlyHints();
|
|
161
167
|
|
|
162
168
|
hintsReceived = true;
|
|
163
169
|
}
|
package/lib/resolver.js
CHANGED
|
@@ -11,6 +11,7 @@ import Cache from './resolver.cache.js';
|
|
|
11
11
|
* @typedef {object} PodletClientResolverOptions
|
|
12
12
|
* @property {string} clientName
|
|
13
13
|
* @property {import('abslog').AbstractLoggerOptions} [logger]
|
|
14
|
+
* @property {boolean} [earlyHints]
|
|
14
15
|
*/
|
|
15
16
|
|
|
16
17
|
export default class PodletClientResolver {
|
|
@@ -41,7 +42,10 @@ export default class PodletClientResolver {
|
|
|
41
42
|
http,
|
|
42
43
|
});
|
|
43
44
|
this.#fallback = new Fallback({ ...options, http });
|
|
44
|
-
this.#content = new Content({
|
|
45
|
+
this.#content = new Content({
|
|
46
|
+
...options,
|
|
47
|
+
http,
|
|
48
|
+
});
|
|
45
49
|
this.#metrics = new Metrics();
|
|
46
50
|
|
|
47
51
|
this.#metrics.on('error', (error) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@podium/client",
|
|
3
|
-
"version": "5.2.0-next.
|
|
3
|
+
"version": "5.2.0-next.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"@hapi/boom": "10.0.1",
|
|
41
41
|
"@metrics/client": "2.5.3",
|
|
42
42
|
"@podium/schemas": "5.0.6",
|
|
43
|
-
"@podium/utils": "5.2.
|
|
43
|
+
"@podium/utils": "5.2.1",
|
|
44
44
|
"abslog": "2.4.4",
|
|
45
45
|
"http-cache-semantics": "^4.0.3",
|
|
46
46
|
"lodash.clonedeep": "^4.5.0",
|
package/types/client.d.ts
CHANGED
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
* @property {boolean} [redirectable=false] Set to `true` to allow podlet to respond with a redirect. You need to look for the redirect response from the podlet and return a redirect response to the browser yourself.
|
|
30
30
|
* @property {import('./resource.js').RequestFilterOptions} [excludeBy] Used by `fetch` to conditionally skip fetching the podlet content based on values on the request.
|
|
31
31
|
* @property {import('./resource.js').RequestFilterOptions} [includeBy] Used by `fetch` to conditionally skip fetching the podlet content based on values on the request.
|
|
32
|
+
* @property {boolean} [earlyHints=true]
|
|
32
33
|
*/
|
|
33
34
|
export default class PodiumClient extends EventEmitter<[never]> {
|
|
34
35
|
/**
|
|
@@ -115,6 +116,7 @@ export type RegisterOptions = {
|
|
|
115
116
|
* Used by `fetch` to conditionally skip fetching the podlet content based on values on the request.
|
|
116
117
|
*/
|
|
117
118
|
includeBy?: import('./resource.js').RequestFilterOptions;
|
|
119
|
+
earlyHints?: boolean;
|
|
118
120
|
};
|
|
119
121
|
import EventEmitter from 'events';
|
|
120
122
|
import Metrics from '@metrics/client';
|
package/types/http-outgoing.d.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* @property {string} clientName
|
|
4
4
|
* @property {import('./http.js').default} [http]
|
|
5
5
|
* @property {import('abslog').AbstractLoggerOptions} [logger]
|
|
6
|
+
* @property {boolean} [earlyHints]
|
|
6
7
|
*/
|
|
7
8
|
export default class PodletClientContentResolver {
|
|
8
9
|
/**
|
|
@@ -25,5 +26,6 @@ export type PodletClientContentResolverOptions = {
|
|
|
25
26
|
clientName: string;
|
|
26
27
|
http?: import('./http.js').default;
|
|
27
28
|
logger?: import('abslog').AbstractLoggerOptions;
|
|
29
|
+
earlyHints?: boolean;
|
|
28
30
|
};
|
|
29
31
|
import Metrics from '@metrics/client';
|
package/types/resolver.d.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* @typedef {object} PodletClientResolverOptions
|
|
3
3
|
* @property {string} clientName
|
|
4
4
|
* @property {import('abslog').AbstractLoggerOptions} [logger]
|
|
5
|
+
* @property {boolean} [earlyHints]
|
|
5
6
|
*/
|
|
6
7
|
export default class PodletClientResolver {
|
|
7
8
|
/**
|
|
@@ -31,5 +32,6 @@ export default class PodletClientResolver {
|
|
|
31
32
|
export type PodletClientResolverOptions = {
|
|
32
33
|
clientName: string;
|
|
33
34
|
logger?: import('abslog').AbstractLoggerOptions;
|
|
35
|
+
earlyHints?: boolean;
|
|
34
36
|
};
|
|
35
37
|
import Metrics from '@metrics/client';
|
package/types/utils.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export function isHeaderDefined(headers: object, header: string): boolean;
|
|
2
2
|
export function hasManifestChange(item: object): boolean;
|
|
3
3
|
export function validateIncoming(incoming?: object): boolean;
|
|
4
|
-
export function filterAssets<T extends
|
|
4
|
+
export function filterAssets<T extends AssetCss | AssetJs>(scope: "content" | "fallback" | "all", assets: T[]): T[];
|
|
5
5
|
export function parseLinkHeaders(headers: any): any[];
|
|
6
6
|
export function toPreloadAssetObjects(assetObjects: any): any;
|
|
7
|
-
import { AssetJs } from '@podium/utils';
|
|
8
7
|
import { AssetCss } from '@podium/utils';
|
|
8
|
+
import { AssetJs } from '@podium/utils';
|