@podium/client 5.0.20 → 5.0.22
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 +15 -0
- package/lib/client.js +68 -17
- package/lib/http-outgoing.js +106 -30
- package/lib/http.js +21 -1
- package/lib/resolver.cache.js +26 -3
- package/lib/resolver.content.js +54 -30
- package/lib/resolver.fallback.js +20 -0
- package/lib/resolver.js +40 -11
- package/lib/resolver.manifest.js +39 -14
- package/lib/resource.js +78 -14
- package/lib/response.js +15 -1
- package/lib/state.js +14 -1
- package/lib/utils.js +25 -27
- package/package.json +10 -8
- package/types/client.d.ts +110 -0
- package/types/http-outgoing.d.ts +177 -0
- package/types/http.d.ts +29 -0
- package/types/resolver.cache.d.ts +31 -0
- package/types/resolver.content.d.ts +29 -0
- package/types/resolver.d.ts +35 -0
- package/types/resolver.fallback.d.ts +29 -0
- package/types/resolver.manifest.d.ts +27 -0
- package/types/resource.d.ts +89 -0
- package/types/response.d.ts +47 -0
- package/types/state.d.ts +33 -0
- package/types/utils.d.ts +4 -0
- package/client.d.ts +0 -140
- package/dist/package.json +0 -3
package/lib/resolver.fallback.js
CHANGED
|
@@ -17,11 +17,24 @@ const pkg = JSON.parse(pkgJson);
|
|
|
17
17
|
|
|
18
18
|
const UA_STRING = `${pkg.name} ${pkg.version}`;
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* @typedef {object} PodletClientFallbackResolverOptions
|
|
22
|
+
* @property {string} clientName
|
|
23
|
+
* @property {import('./http.js').default} [http]
|
|
24
|
+
* @property {import('abslog').AbstractLoggerOptions} [logger]
|
|
25
|
+
*/
|
|
26
|
+
|
|
20
27
|
export default class PodletClientFallbackResolver {
|
|
21
28
|
#log;
|
|
22
29
|
#metrics;
|
|
23
30
|
#histogram;
|
|
24
31
|
#http;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @constructor
|
|
35
|
+
* @param {PodletClientFallbackResolverOptions} options
|
|
36
|
+
*/
|
|
37
|
+
// @ts-expect-error Deliberate default empty options for better error messages
|
|
25
38
|
constructor(options = {}) {
|
|
26
39
|
this.#http = options.http || new HTTP();
|
|
27
40
|
const name = options.clientName;
|
|
@@ -50,6 +63,12 @@ export default class PodletClientFallbackResolver {
|
|
|
50
63
|
return this.#metrics;
|
|
51
64
|
}
|
|
52
65
|
|
|
66
|
+
/**
|
|
67
|
+
* Resolves/fetches the podlet's fallback.
|
|
68
|
+
*
|
|
69
|
+
* @param {import('./http-outgoing.js').default} outgoing
|
|
70
|
+
* @returns {Promise<import('./http-outgoing.js').default>}
|
|
71
|
+
*/
|
|
53
72
|
async resolve(outgoing) {
|
|
54
73
|
if (outgoing.status === 'cached') {
|
|
55
74
|
return outgoing;
|
|
@@ -77,6 +96,7 @@ export default class PodletClientFallbackResolver {
|
|
|
77
96
|
'User-Agent': UA_STRING,
|
|
78
97
|
};
|
|
79
98
|
|
|
99
|
+
/** @type {import('./http.js').PodiumHttpClientRequestOptions} */
|
|
80
100
|
const reqOptions = {
|
|
81
101
|
rejectUnauthorized: outgoing.rejectUnauthorized,
|
|
82
102
|
timeout: outgoing.timeout,
|
package/lib/resolver.js
CHANGED
|
@@ -7,12 +7,25 @@ import Fallback from './resolver.fallback.js';
|
|
|
7
7
|
import Content from './resolver.content.js';
|
|
8
8
|
import Cache from './resolver.cache.js';
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {object} PodletClientResolverOptions
|
|
12
|
+
* @property {string} clientName
|
|
13
|
+
* @property {import('abslog').AbstractLoggerOptions} [logger]
|
|
14
|
+
*/
|
|
15
|
+
|
|
10
16
|
export default class PodletClientResolver {
|
|
11
17
|
#cache;
|
|
12
18
|
#manifest;
|
|
13
19
|
#fallback;
|
|
14
20
|
#content;
|
|
15
21
|
#metrics;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @constructor
|
|
25
|
+
* @param {import('ttl-mem-cache').default} registry
|
|
26
|
+
* @param {PodletClientResolverOptions} options
|
|
27
|
+
*/
|
|
28
|
+
// @ts-expect-error Deliberate default empty options for better error messages
|
|
16
29
|
constructor(registry, options = {}) {
|
|
17
30
|
assert(
|
|
18
31
|
registry,
|
|
@@ -22,12 +35,16 @@ export default class PodletClientResolver {
|
|
|
22
35
|
const log = abslog(options.logger);
|
|
23
36
|
const http = new HTTP();
|
|
24
37
|
this.#cache = new Cache(registry, options);
|
|
25
|
-
this.#manifest = new Manifest({
|
|
38
|
+
this.#manifest = new Manifest({
|
|
39
|
+
clientName: options.clientName,
|
|
40
|
+
logger: options.logger,
|
|
41
|
+
http,
|
|
42
|
+
});
|
|
26
43
|
this.#fallback = new Fallback({ ...options, http });
|
|
27
44
|
this.#content = new Content({ ...options, http });
|
|
28
45
|
this.#metrics = new Metrics();
|
|
29
46
|
|
|
30
|
-
this.#metrics.on('error', error => {
|
|
47
|
+
this.#metrics.on('error', (error) => {
|
|
31
48
|
log.error(
|
|
32
49
|
'Error emitted by metric stream in @podium/client module',
|
|
33
50
|
error,
|
|
@@ -43,14 +60,20 @@ export default class PodletClientResolver {
|
|
|
43
60
|
return this.#metrics;
|
|
44
61
|
}
|
|
45
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Resolve the podlet's manifest, fallback and content
|
|
65
|
+
*
|
|
66
|
+
* @param {import('./http-outgoing.js').default} outgoing
|
|
67
|
+
* @returns {Promise<import('./http-outgoing.js').default>}
|
|
68
|
+
*/
|
|
46
69
|
resolve(outgoing) {
|
|
47
70
|
return this.#cache
|
|
48
71
|
.load(outgoing)
|
|
49
|
-
.then(obj => this.#manifest.resolve(obj))
|
|
50
|
-
.then(obj => this.#fallback.resolve(obj))
|
|
51
|
-
.then(obj => this.#content.resolve(obj))
|
|
52
|
-
.then(obj => this.#cache.save(obj))
|
|
53
|
-
.then(obj => {
|
|
72
|
+
.then((obj) => this.#manifest.resolve(obj))
|
|
73
|
+
.then((obj) => this.#fallback.resolve(obj))
|
|
74
|
+
.then((obj) => this.#content.resolve(obj))
|
|
75
|
+
.then((obj) => this.#cache.save(obj))
|
|
76
|
+
.then((obj) => {
|
|
54
77
|
if (obj.success) {
|
|
55
78
|
return obj;
|
|
56
79
|
}
|
|
@@ -58,15 +81,21 @@ export default class PodletClientResolver {
|
|
|
58
81
|
});
|
|
59
82
|
}
|
|
60
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Refresh the podlet's cached manifest and fallback
|
|
86
|
+
*
|
|
87
|
+
* @param {import('./http-outgoing.js').default} outgoing
|
|
88
|
+
* @returns {Promise<boolean>} `true` if successful
|
|
89
|
+
*/
|
|
61
90
|
refresh(outgoing) {
|
|
62
91
|
return this.#manifest
|
|
63
92
|
.resolve(outgoing)
|
|
64
|
-
.then(obj => this.#fallback.resolve(obj))
|
|
65
|
-
.then(obj => this.#cache.save(obj))
|
|
66
|
-
.then(obj => !!obj.manifest.name);
|
|
93
|
+
.then((obj) => this.#fallback.resolve(obj))
|
|
94
|
+
.then((obj) => this.#cache.save(obj))
|
|
95
|
+
.then((obj) => !!obj.manifest.name);
|
|
67
96
|
}
|
|
68
97
|
|
|
69
98
|
get [Symbol.toStringTag]() {
|
|
70
99
|
return 'PodletClientResolver';
|
|
71
100
|
}
|
|
72
|
-
}
|
|
101
|
+
}
|
package/lib/resolver.manifest.js
CHANGED
|
@@ -20,11 +20,24 @@ const pkg = JSON.parse(pkgJson);
|
|
|
20
20
|
|
|
21
21
|
const UA_STRING = `${pkg.name} ${pkg.version}`;
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @typedef {object} PodletClientManifestResolverOptions
|
|
25
|
+
* @property {string} clientName
|
|
26
|
+
* @property {import('abslog').AbstractLoggerOptions} [logger]
|
|
27
|
+
* @property {import('./http.js').default} [http]
|
|
28
|
+
*/
|
|
29
|
+
|
|
23
30
|
export default class PodletClientManifestResolver {
|
|
24
31
|
#log;
|
|
25
32
|
#metrics;
|
|
26
33
|
#histogram;
|
|
27
34
|
#http;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @constructor
|
|
38
|
+
* @param {PodletClientManifestResolverOptions} options
|
|
39
|
+
*/
|
|
40
|
+
// @ts-expect-error Deliberate default empty options for better error messages
|
|
28
41
|
constructor(options = {}) {
|
|
29
42
|
this.#http = options.http || new HTTP();
|
|
30
43
|
const name = options.clientName;
|
|
@@ -53,6 +66,10 @@ export default class PodletClientManifestResolver {
|
|
|
53
66
|
return this.#metrics;
|
|
54
67
|
}
|
|
55
68
|
|
|
69
|
+
/**
|
|
70
|
+
* @param {import('./http-outgoing.js').default} outgoing
|
|
71
|
+
* @returns {Promise<import('./http-outgoing.js').default>}
|
|
72
|
+
*/
|
|
56
73
|
async resolve(outgoing) {
|
|
57
74
|
if (outgoing.status === 'cached') {
|
|
58
75
|
return outgoing;
|
|
@@ -62,6 +79,7 @@ export default class PodletClientManifestResolver {
|
|
|
62
79
|
'User-Agent': UA_STRING,
|
|
63
80
|
};
|
|
64
81
|
|
|
82
|
+
/** @type {import('./http.js').PodiumHttpClientRequestOptions} */
|
|
65
83
|
const reqOptions = {
|
|
66
84
|
rejectUnauthorized: outgoing.rejectUnauthorized,
|
|
67
85
|
timeout: outgoing.timeout,
|
|
@@ -81,11 +99,11 @@ export default class PodletClientManifestResolver {
|
|
|
81
99
|
);
|
|
82
100
|
|
|
83
101
|
try {
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
102
|
+
const response = await this.#http.request(
|
|
103
|
+
outgoing.manifestUri,
|
|
104
|
+
reqOptions,
|
|
105
|
+
);
|
|
106
|
+
const { statusCode, headers: hdrs, body } = response;
|
|
89
107
|
|
|
90
108
|
// Remote responds but with an http error code
|
|
91
109
|
const resError = statusCode !== 200;
|
|
@@ -105,7 +123,11 @@ export default class PodletClientManifestResolver {
|
|
|
105
123
|
return outgoing;
|
|
106
124
|
}
|
|
107
125
|
|
|
108
|
-
const manifest = validateManifest(
|
|
126
|
+
const manifest = validateManifest(
|
|
127
|
+
/** @type {import("@podium/schemas").PodletManifestSchema} */ (
|
|
128
|
+
await body.json()
|
|
129
|
+
),
|
|
130
|
+
);
|
|
109
131
|
|
|
110
132
|
// Manifest validation error
|
|
111
133
|
if (manifest.error) {
|
|
@@ -158,6 +180,7 @@ export default class PodletClientManifestResolver {
|
|
|
158
180
|
);
|
|
159
181
|
|
|
160
182
|
// Construct css and js objects with absolute URIs
|
|
183
|
+
// @ts-expect-error We assign here what will end up as PodletManifest as defined in http-outgoing.js
|
|
161
184
|
manifest.value.css = manifest.value.css.map((obj) => {
|
|
162
185
|
obj.value = utils.uriRelativeToAbsolute(
|
|
163
186
|
obj.value,
|
|
@@ -166,6 +189,7 @@ export default class PodletClientManifestResolver {
|
|
|
166
189
|
return new utils.AssetCss(obj);
|
|
167
190
|
});
|
|
168
191
|
|
|
192
|
+
// @ts-expect-error We assign here what will end up as PodletManifest as defined in http-outgoing.js
|
|
169
193
|
manifest.value.js = manifest.value.js.map((obj) => {
|
|
170
194
|
obj.value = utils.uriRelativeToAbsolute(
|
|
171
195
|
obj.value,
|
|
@@ -179,9 +203,9 @@ export default class PodletClientManifestResolver {
|
|
|
179
203
|
|
|
180
204
|
If .proxy is and Array, the podlet are of version 6 or newer. The Array is then an
|
|
181
205
|
Array of proxy Objects ({ name: 'foo', target: '/' }) which is the new structure
|
|
182
|
-
wanted from version 6 and onwards so leave this structure untouched.
|
|
206
|
+
wanted from version 6 and onwards so leave this structure untouched.
|
|
183
207
|
|
|
184
|
-
If .proxy is an Object, the podlet are of version 5 or older where the key of the
|
|
208
|
+
If .proxy is an Object, the podlet are of version 5 or older where the key of the
|
|
185
209
|
Object is the key of the target. If so, convert the structure to the new structure
|
|
186
210
|
consisting of an Array of proxy Objects.
|
|
187
211
|
|
|
@@ -191,12 +215,12 @@ export default class PodletClientManifestResolver {
|
|
|
191
215
|
if (Array.isArray(manifest.value.proxy)) {
|
|
192
216
|
// Build absolute proxy URIs
|
|
193
217
|
manifest.value.proxy = manifest.value.proxy.map((item) => ({
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
218
|
+
target: utils.uriRelativeToAbsolute(
|
|
219
|
+
item.target,
|
|
220
|
+
outgoing.manifestUri,
|
|
221
|
+
),
|
|
222
|
+
name: item.name,
|
|
223
|
+
}));
|
|
200
224
|
} else {
|
|
201
225
|
const proxies = [];
|
|
202
226
|
// Build absolute proxy URIs
|
|
@@ -216,6 +240,7 @@ export default class PodletClientManifestResolver {
|
|
|
216
240
|
END: Proxy backwards compabillity check and handling
|
|
217
241
|
*/
|
|
218
242
|
|
|
243
|
+
// @ts-expect-error We map to AssetCss and AssetJs above
|
|
219
244
|
outgoing.manifest = manifest.value;
|
|
220
245
|
outgoing.status = 'fresh';
|
|
221
246
|
|
package/lib/resource.js
CHANGED
|
@@ -11,11 +11,35 @@ import * as utils from './utils.js';
|
|
|
11
11
|
|
|
12
12
|
const inspect = Symbol.for('nodejs.util.inspect.custom');
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {object} PodiumClientResourceOptions
|
|
16
|
+
* @property {import('abslog').AbstractLoggerOptions} [logger]
|
|
17
|
+
* @property {string} clientName
|
|
18
|
+
* @property {string} name
|
|
19
|
+
* @property {string} uri To the podlet's `manifest.json`
|
|
20
|
+
* @property {number} timeout In milliseconds
|
|
21
|
+
* @property {number} maxAge
|
|
22
|
+
* @property {number} [retries]
|
|
23
|
+
* @property {boolean} [throwable]
|
|
24
|
+
* @property {boolean} [redirectable]
|
|
25
|
+
* @property {boolean} [rejectUnauthorized]
|
|
26
|
+
* @property {import('http').Agent} [httpAgent]
|
|
27
|
+
* @property {import('https').Agent} [httpsAgent]
|
|
28
|
+
*/
|
|
29
|
+
|
|
14
30
|
export default class PodiumClientResource {
|
|
15
31
|
#resolver;
|
|
16
32
|
#options;
|
|
17
33
|
#metrics;
|
|
18
34
|
#state;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @constructor
|
|
38
|
+
* @param {import('ttl-mem-cache').default} registry
|
|
39
|
+
* @param {import('./state.js').default} state
|
|
40
|
+
* @param {PodiumClientResourceOptions} options
|
|
41
|
+
*/
|
|
42
|
+
// @ts-expect-error Deliberate for better error messages
|
|
19
43
|
constructor(registry, state, options = {}) {
|
|
20
44
|
assert(
|
|
21
45
|
registry,
|
|
@@ -34,7 +58,7 @@ export default class PodiumClientResource {
|
|
|
34
58
|
this.#metrics = new Metrics();
|
|
35
59
|
this.#state = state;
|
|
36
60
|
|
|
37
|
-
this.#metrics.on('error', error => {
|
|
61
|
+
this.#metrics.on('error', (error) => {
|
|
38
62
|
log.error(
|
|
39
63
|
'Error emitted by metric stream in @podium/client module',
|
|
40
64
|
error,
|
|
@@ -56,20 +80,37 @@ export default class PodiumClientResource {
|
|
|
56
80
|
return this.#options.uri;
|
|
57
81
|
}
|
|
58
82
|
|
|
59
|
-
|
|
60
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Fetch the podlet's content, or fallback if the podlet is unavailable.
|
|
85
|
+
* The podlet response includes references to its CSS and JS assets which should be included in the final HTML document.
|
|
86
|
+
*
|
|
87
|
+
* @param {import('@podium/utils').HttpIncoming} incoming Instance of HttpIncoming
|
|
88
|
+
* @param {import('./http-outgoing.js').PodiumClientResourceOptions} [reqOptions={}] Optional parameters to the HTTP request, such as query parameters or HTTP request headers.
|
|
89
|
+
* @returns {Promise<import('./response.js').default>}
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```js
|
|
93
|
+
* const incoming = res.locals.podium; // Express server example
|
|
94
|
+
* const header = await headerPodlet.fetch(incoming);
|
|
95
|
+
* incoming.podlets = [header]; // Register the podlet's JS and CSS assets with the layout's HTML template
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
async fetch(incoming, reqOptions = {}) {
|
|
99
|
+
if (!utils.validateIncoming(incoming))
|
|
100
|
+
throw new TypeError(
|
|
101
|
+
'you must pass an instance of "HttpIncoming" as the first argument to the .fetch() method',
|
|
102
|
+
);
|
|
61
103
|
const outgoing = new HttpOutgoing(this.#options, reqOptions, incoming);
|
|
62
104
|
|
|
63
105
|
this.#state.setInitializingState();
|
|
64
106
|
|
|
65
|
-
const { manifest, headers, redirect, isFallback } =
|
|
66
|
-
outgoing
|
|
67
|
-
);
|
|
107
|
+
const { manifest, headers, redirect, isFallback } =
|
|
108
|
+
await this.#resolver.resolve(outgoing);
|
|
68
109
|
|
|
69
110
|
const chunks = [];
|
|
70
111
|
// eslint-disable-next-line no-restricted-syntax
|
|
71
112
|
for await (const chunk of outgoing) {
|
|
72
|
-
chunks.push(chunk)
|
|
113
|
+
chunks.push(chunk);
|
|
73
114
|
}
|
|
74
115
|
|
|
75
116
|
const content = !outgoing.redirect
|
|
@@ -79,24 +120,47 @@ export default class PodiumClientResource {
|
|
|
79
120
|
return new Response({
|
|
80
121
|
headers,
|
|
81
122
|
content,
|
|
82
|
-
css: utils.filterAssets(
|
|
83
|
-
|
|
123
|
+
css: utils.filterAssets(
|
|
124
|
+
isFallback ? 'fallback' : 'content',
|
|
125
|
+
manifest.css,
|
|
126
|
+
),
|
|
127
|
+
js: utils.filterAssets(
|
|
128
|
+
isFallback ? 'fallback' : 'content',
|
|
129
|
+
manifest.js,
|
|
130
|
+
),
|
|
84
131
|
redirect,
|
|
85
132
|
});
|
|
86
133
|
}
|
|
87
134
|
|
|
88
|
-
|
|
89
|
-
|
|
135
|
+
/**
|
|
136
|
+
* Stream the podlet's content, or fallback if the podlet is unavailable.
|
|
137
|
+
*
|
|
138
|
+
* @param {import('@podium/utils').HttpIncoming} incoming
|
|
139
|
+
* @param {import('./http-outgoing.js').PodiumClientResourceOptions} [reqOptions={}]
|
|
140
|
+
* @returns {import('./http-outgoing.js').default}
|
|
141
|
+
*/
|
|
142
|
+
stream(incoming, reqOptions = {}) {
|
|
143
|
+
if (!utils.validateIncoming(incoming))
|
|
144
|
+
throw new TypeError(
|
|
145
|
+
'you must pass an instance of "HttpIncoming" as the first argument to the .stream() method',
|
|
146
|
+
);
|
|
90
147
|
const outgoing = new HttpOutgoing(this.#options, reqOptions, incoming);
|
|
91
148
|
this.#state.setInitializingState();
|
|
92
149
|
this.#resolver.resolve(outgoing);
|
|
93
150
|
return outgoing;
|
|
94
151
|
}
|
|
95
152
|
|
|
96
|
-
|
|
153
|
+
/**
|
|
154
|
+
* Refresh the podlet's manifest and fallback in the cache.
|
|
155
|
+
*
|
|
156
|
+
* @param {import('@podium/utils').HttpIncoming} [incoming]
|
|
157
|
+
* @param {import('./http-outgoing.js').PodiumClientResourceOptions} [reqOptions={}]
|
|
158
|
+
* @returns {Promise<boolean>} `true` if succesful
|
|
159
|
+
*/
|
|
160
|
+
refresh(incoming, reqOptions = {}) {
|
|
97
161
|
const outgoing = new HttpOutgoing(this.#options, reqOptions, incoming);
|
|
98
162
|
this.#state.setInitializingState();
|
|
99
|
-
return this.#resolver.refresh(outgoing).then(obj => obj);
|
|
163
|
+
return this.#resolver.refresh(outgoing).then((obj) => obj);
|
|
100
164
|
}
|
|
101
165
|
|
|
102
166
|
[inspect]() {
|
|
@@ -110,4 +174,4 @@ export default class PodiumClientResource {
|
|
|
110
174
|
get [Symbol.toStringTag]() {
|
|
111
175
|
return 'PodiumClientResource';
|
|
112
176
|
}
|
|
113
|
-
}
|
|
177
|
+
}
|
package/lib/response.js
CHANGED
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
const inspect = Symbol.for('nodejs.util.inspect.custom');
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {object} PodiumClientResponseOptions
|
|
5
|
+
* @property {string} [content]
|
|
6
|
+
* @property {object} [headers]
|
|
7
|
+
* @property {Array<import('@podium/utils').AssetJs>} [js]
|
|
8
|
+
* @property {Array<import('@podium/utils').AssetCss>} [css]
|
|
9
|
+
* @property {import('./http-outgoing.js').PodiumRedirect | null} [redirect]
|
|
10
|
+
*/
|
|
11
|
+
|
|
3
12
|
export default class PodiumClientResponse {
|
|
4
13
|
#redirect;
|
|
5
14
|
#content;
|
|
6
15
|
#headers;
|
|
7
16
|
#css;
|
|
8
17
|
#js;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @constructor
|
|
21
|
+
* @param {PodiumClientResponseOptions} options
|
|
22
|
+
*/
|
|
9
23
|
constructor({
|
|
10
24
|
content = '',
|
|
11
25
|
headers = {},
|
|
@@ -71,4 +85,4 @@ export default class PodiumClientResponse {
|
|
|
71
85
|
get [Symbol.toStringTag]() {
|
|
72
86
|
return 'PodiumClientResponse';
|
|
73
87
|
}
|
|
74
|
-
}
|
|
88
|
+
}
|
package/lib/state.js
CHANGED
|
@@ -2,12 +2,25 @@ import EventEmitter from 'events';
|
|
|
2
2
|
|
|
3
3
|
const inspect = Symbol.for('nodejs.util.inspect.custom');
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {object} PodiumClientStateOptions
|
|
7
|
+
* @property {number} [resolveThreshold=10000]
|
|
8
|
+
* @property {number} [resolveMax=240000]
|
|
9
|
+
*/
|
|
10
|
+
|
|
5
11
|
export default class PodiumClientState extends EventEmitter {
|
|
12
|
+
/** @type {NodeJS.Timeout | undefined} */
|
|
6
13
|
#thresholdTimer;
|
|
7
14
|
#threshold;
|
|
15
|
+
/** @type {NodeJS.Timeout | undefined} */
|
|
8
16
|
#maxTimer;
|
|
17
|
+
/** @type {"instantiated" | "stable" | "initializing" | "unhealthy" | "unstable"} */
|
|
9
18
|
#state;
|
|
10
19
|
#max;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @param {PodiumClientStateOptions} [options]
|
|
23
|
+
*/
|
|
11
24
|
constructor({
|
|
12
25
|
resolveThreshold = 10 * 1000,
|
|
13
26
|
resolveMax = 4 * 60 * 1000,
|
|
@@ -113,4 +126,4 @@ export default class PodiumClientState extends EventEmitter {
|
|
|
113
126
|
get [Symbol.toStringTag]() {
|
|
114
127
|
return 'PodiumClientState';
|
|
115
128
|
}
|
|
116
|
-
}
|
|
129
|
+
}
|
package/lib/utils.js
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Checks if a header
|
|
3
|
-
* Will return true if the header exist and
|
|
4
|
-
*
|
|
2
|
+
* Checks if a header object has a header.
|
|
3
|
+
* Will return true if the header exist and is not an empty
|
|
4
|
+
* string or a string of whitespace.
|
|
5
5
|
*
|
|
6
|
-
* @param {
|
|
7
|
-
* @param {
|
|
8
|
-
*
|
|
9
|
-
* @returns {Boolean}
|
|
6
|
+
* @param {object} headers
|
|
7
|
+
* @param {string} header
|
|
8
|
+
* @returns {boolean}
|
|
10
9
|
*/
|
|
11
|
-
|
|
12
10
|
export const isHeaderDefined = (headers, header) => {
|
|
13
11
|
if (headers[header] === undefined || headers[header].trim() === '') {
|
|
14
12
|
return false;
|
|
@@ -21,31 +19,24 @@ export const isHeaderDefined = (headers, header) => {
|
|
|
21
19
|
* the changelog event object emitted from the internal
|
|
22
20
|
* cache registry.
|
|
23
21
|
*
|
|
24
|
-
* @param {
|
|
25
|
-
*
|
|
26
|
-
* @returns {Boolean}
|
|
22
|
+
* @param {object} item A changelog event object
|
|
23
|
+
* @returns {boolean}
|
|
27
24
|
*/
|
|
28
|
-
|
|
29
|
-
export const hasManifestChange = item => {
|
|
25
|
+
export const hasManifestChange = (item) => {
|
|
30
26
|
const oldVersion = item.oldVal ? item.oldVal.version : '';
|
|
31
27
|
const newVersion = item.newVal ? item.newVal.version : '';
|
|
32
28
|
return oldVersion !== newVersion;
|
|
33
29
|
};
|
|
34
30
|
|
|
35
|
-
|
|
36
31
|
/**
|
|
37
|
-
* Check if a value is a HttpIncoming object or not. If not, it
|
|
32
|
+
* Check if a value is a Podium HttpIncoming object or not. If not, it
|
|
38
33
|
* assume the incoming value is a context
|
|
39
34
|
*
|
|
40
|
-
* @param {
|
|
41
|
-
*
|
|
42
|
-
* @returns {HttpIncoming}
|
|
43
|
-
*/
|
|
44
|
-
export const validateIncoming = (incoming = {}) => (Object.prototype.toString.call(incoming) === '[object PodiumHttpIncoming]');
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* @typedef {import("@podium/utils").AssetCss | import("@podium/utils").AssetJs} Asset
|
|
35
|
+
* @param {object} incoming
|
|
36
|
+
* @returns {boolean}
|
|
48
37
|
*/
|
|
38
|
+
export const validateIncoming = (incoming = {}) =>
|
|
39
|
+
Object.prototype.toString.call(incoming) === '[object PodiumHttpIncoming]';
|
|
49
40
|
|
|
50
41
|
/**
|
|
51
42
|
* Filter assets array based on scope.
|
|
@@ -53,9 +44,10 @@ export const validateIncoming = (incoming = {}) => (Object.prototype.toString.ca
|
|
|
53
44
|
* If scope property is set to "all", asset will be included.
|
|
54
45
|
* If scope is set to "content" and asset scope property is set to "fallback", asset will not be included
|
|
55
46
|
* If scope is set to "fallback" and asset scope property is set to "content", asset will not be included
|
|
47
|
+
* @template {import("@podium/utils").AssetCss | import("@podium/utils").AssetJs} T[]
|
|
56
48
|
* @param {"content" | "fallback" | "all"} scope
|
|
57
|
-
* @param {
|
|
58
|
-
* @returns {
|
|
49
|
+
* @param {T[]} assets
|
|
50
|
+
* @returns {T[]}
|
|
59
51
|
*
|
|
60
52
|
* @example
|
|
61
53
|
* ```
|
|
@@ -69,7 +61,13 @@ export const filterAssets = (scope, assets) => {
|
|
|
69
61
|
// if undefined or null, passthrough
|
|
70
62
|
if (!assets) return assets;
|
|
71
63
|
// if a non array value is given, throw
|
|
72
|
-
if (!Array.isArray(assets))
|
|
64
|
+
if (!Array.isArray(assets))
|
|
65
|
+
throw new TypeError(
|
|
66
|
+
`Asset definition must be of type array. Got ${typeof assets}`,
|
|
67
|
+
);
|
|
73
68
|
// filter the array of asset definitions to matchin scope or anything with all. Treat no scope the same as "all" for backwards compatibility.
|
|
74
|
-
return assets.filter(
|
|
69
|
+
return assets.filter(
|
|
70
|
+
(asset) =>
|
|
71
|
+
!asset.scope || asset.scope === scope || asset.scope === 'all',
|
|
72
|
+
);
|
|
75
73
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@podium/client",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.22",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -21,18 +21,18 @@
|
|
|
21
21
|
"files": [
|
|
22
22
|
"package.json",
|
|
23
23
|
"CHANGELOG.md",
|
|
24
|
-
"client.d.ts",
|
|
25
24
|
"README.md",
|
|
26
25
|
"LICENSE",
|
|
27
|
-
"
|
|
28
|
-
"
|
|
26
|
+
"lib",
|
|
27
|
+
"types"
|
|
29
28
|
],
|
|
30
29
|
"main": "./lib/client.js",
|
|
31
|
-
"types": "client.d.ts",
|
|
30
|
+
"types": "./types/client.d.ts",
|
|
32
31
|
"scripts": {
|
|
33
32
|
"lint": "eslint .",
|
|
34
33
|
"lint:fix": "eslint --fix .",
|
|
35
|
-
"test": "tap --disable-coverage --allow-empty-coverage"
|
|
34
|
+
"test": "tap tests/*.js --disable-coverage --allow-empty-coverage && tsc --project tsconfig.test.json",
|
|
35
|
+
"types": "tsc --declaration --emitDeclarationOnly"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@hapi/boom": "10.0.1",
|
|
@@ -46,14 +46,15 @@
|
|
|
46
46
|
"undici": "6.16.1"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
+
"@babel/eslint-parser": "7.24.5",
|
|
49
50
|
"@podium/test-utils": "2.5.2",
|
|
50
51
|
"@semantic-release/changelog": "6.0.3",
|
|
51
52
|
"@semantic-release/git": "10.0.1",
|
|
52
|
-
"@babel/eslint-parser": "7.24.5",
|
|
53
53
|
"@semantic-release/github": "10.0.3",
|
|
54
54
|
"@semantic-release/npm": "12.0.0",
|
|
55
55
|
"@semantic-release/release-notes-generator": "13.0.0",
|
|
56
56
|
"@sinonjs/fake-timers": "11.2.2",
|
|
57
|
+
"@types/readable-stream": "4.0.14",
|
|
57
58
|
"benchmark": "2.1.4",
|
|
58
59
|
"eslint": "8.57.0",
|
|
59
60
|
"eslint-config-airbnb-base": "15.0.0",
|
|
@@ -66,6 +67,7 @@
|
|
|
66
67
|
"is-stream": "4.0.1",
|
|
67
68
|
"prettier": "3.2.5",
|
|
68
69
|
"semantic-release": "23.0.8",
|
|
69
|
-
"tap": "18.7.2"
|
|
70
|
+
"tap": "18.7.2",
|
|
71
|
+
"typescript": "5.4.5"
|
|
70
72
|
}
|
|
71
73
|
}
|