@podium/client 5.1.0-beta.1 → 5.1.1

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.
@@ -1,4 +1,3 @@
1
- /* eslint-disable no-param-reassign */
2
1
  import { pipeline } from 'stream';
3
2
  import Metrics from '@metrics/client';
4
3
  import abslog from 'abslog';
@@ -21,11 +20,24 @@ const pkg = JSON.parse(pkgJson);
21
20
 
22
21
  const UA_STRING = `${pkg.name} ${pkg.version}`;
23
22
 
23
+ /**
24
+ * @typedef {object} PodletClientContentResolverOptions
25
+ * @property {string} clientName
26
+ * @property {import('./http.js').default} [http]
27
+ * @property {import('abslog').AbstractLoggerOptions} [logger]
28
+ */
29
+
24
30
  export default class PodletClientContentResolver {
25
31
  #log;
26
32
  #metrics;
27
33
  #histogram;
28
34
  #http;
35
+
36
+ /**
37
+ * @constructor
38
+ * @param {PodletClientContentResolverOptions} options
39
+ */
40
+ // @ts-expect-error Deliberate default empty options for better error messages
29
41
  constructor(options = {}) {
30
42
  this.#http = options.http || new HTTP();
31
43
  const name = options.clientName;
@@ -54,6 +66,12 @@ export default class PodletClientContentResolver {
54
66
  return this.#metrics;
55
67
  }
56
68
 
69
+ /**
70
+ * Resolves/fetches the podlet's content.
71
+ *
72
+ * @param {import('./http-outgoing.js').default} outgoing
73
+ * @returns {Promise<import('./http-outgoing.js').default>}
74
+ */
57
75
  async resolve(outgoing) {
58
76
  if (outgoing.kill && outgoing.throwable) {
59
77
  this.#log.warn(
@@ -71,12 +89,12 @@ export default class PodletClientContentResolver {
71
89
  outgoing.success = true;
72
90
  outgoing.pushFallback();
73
91
  outgoing.emit(
74
- 'beforeStream',
75
- new Response({
76
- js: utils.filterAssets("fallback", outgoing.manifest.js),
77
- css: utils.filterAssets("fallback", outgoing.manifest.css),
78
- }),
79
- );
92
+ 'beforeStream',
93
+ new Response({
94
+ js: utils.filterAssets('fallback', outgoing.manifest.js),
95
+ css: utils.filterAssets('fallback', outgoing.manifest.css),
96
+ }),
97
+ );
80
98
  return outgoing;
81
99
  }
82
100
 
@@ -94,12 +112,12 @@ export default class PodletClientContentResolver {
94
112
  outgoing.success = true;
95
113
  outgoing.pushFallback();
96
114
  outgoing.emit(
97
- 'beforeStream',
98
- new Response({
99
- js: utils.filterAssets("fallback", outgoing.manifest.js),
100
- css: utils.filterAssets("fallback", outgoing.manifest.css),
101
- }),
102
- );
115
+ 'beforeStream',
116
+ new Response({
117
+ js: utils.filterAssets('fallback', outgoing.manifest.js),
118
+ css: utils.filterAssets('fallback', outgoing.manifest.css),
119
+ }),
120
+ );
103
121
  return outgoing;
104
122
  }
105
123
 
@@ -113,8 +131,9 @@ export default class PodletClientContentResolver {
113
131
  const uri = putils.uriBuilder(
114
132
  outgoing.reqOptions.pathname,
115
133
  outgoing.contentUri,
116
- )
134
+ );
117
135
 
136
+ /** @type {import('./http.js').PodiumHttpClientRequestOptions} */
118
137
  const reqOptions = {
119
138
  rejectUnauthorized: outgoing.rejectUnauthorized,
120
139
  bodyTimeout: outgoing.timeout,
@@ -183,11 +202,17 @@ export default class PodletClientContentResolver {
183
202
  outgoing.success = true;
184
203
  outgoing.pushFallback();
185
204
  outgoing.emit(
186
- 'beforeStream',
187
- new Response({
188
- js: utils.filterAssets("fallback", outgoing.manifest.js),
189
- css: utils.filterAssets("fallback", outgoing.manifest.css),
190
- }),
205
+ 'beforeStream',
206
+ new Response({
207
+ js: utils.filterAssets(
208
+ 'fallback',
209
+ outgoing.manifest.js,
210
+ ),
211
+ css: utils.filterAssets(
212
+ 'fallback',
213
+ outgoing.manifest.css,
214
+ ),
215
+ }),
191
216
  );
192
217
 
193
218
  // Body must be consumed; https://github.com/nodejs/undici/issues/583#issuecomment-855384858
@@ -227,6 +252,7 @@ export default class PodletClientContentResolver {
227
252
  if (outgoing.redirectable && statusCode >= 300) {
228
253
  outgoing.redirect = {
229
254
  statusCode,
255
+ // @ts-expect-error TODO: look into what happens if the podlet returns more than one location header
230
256
  location: hdrs && hdrs.location,
231
257
  };
232
258
  }
@@ -235,8 +261,8 @@ export default class PodletClientContentResolver {
235
261
  'beforeStream',
236
262
  new Response({
237
263
  headers: outgoing.headers,
238
- js: utils.filterAssets("content", outgoing.manifest.js),
239
- css: utils.filterAssets("content", outgoing.manifest.css),
264
+ js: utils.filterAssets('content', outgoing.manifest.js),
265
+ css: utils.filterAssets('content', outgoing.manifest.css),
240
266
  redirect: outgoing.redirect,
241
267
  }),
242
268
  );
@@ -260,10 +286,7 @@ export default class PodletClientContentResolver {
260
286
  this.#log.warn(
261
287
  `could not create network connection to remote resource when trying to request content - resource: ${outgoing.name} - url: ${uri}`,
262
288
  );
263
- throw badGateway(
264
- `Error reading content at ${uri}`,
265
- error,
266
- );
289
+ throw badGateway(`Error reading content at ${uri}`, error);
267
290
  }
268
291
 
269
292
  timer({
@@ -280,12 +303,12 @@ export default class PodletClientContentResolver {
280
303
 
281
304
  outgoing.pushFallback();
282
305
  outgoing.emit(
283
- 'beforeStream',
284
- new Response({
285
- js: utils.filterAssets("fallback", outgoing.manifest.js),
286
- css: utils.filterAssets("fallback", outgoing.manifest.css),
287
- }),
288
- );
306
+ 'beforeStream',
307
+ new Response({
308
+ js: utils.filterAssets('fallback', outgoing.manifest.js),
309
+ css: utils.filterAssets('fallback', outgoing.manifest.css),
310
+ }),
311
+ );
289
312
 
290
313
  return outgoing;
291
314
  }
@@ -1,5 +1,3 @@
1
- /* eslint-disable no-param-reassign */
2
-
3
1
  import abslog from 'abslog';
4
2
  import Metrics from '@metrics/client';
5
3
  import { join, dirname } from 'path';
@@ -17,11 +15,24 @@ const pkg = JSON.parse(pkgJson);
17
15
 
18
16
  const UA_STRING = `${pkg.name} ${pkg.version}`;
19
17
 
18
+ /**
19
+ * @typedef {object} PodletClientFallbackResolverOptions
20
+ * @property {string} clientName
21
+ * @property {import('./http.js').default} [http]
22
+ * @property {import('abslog').AbstractLoggerOptions} [logger]
23
+ */
24
+
20
25
  export default class PodletClientFallbackResolver {
21
26
  #log;
22
27
  #metrics;
23
28
  #histogram;
24
29
  #http;
30
+
31
+ /**
32
+ * @constructor
33
+ * @param {PodletClientFallbackResolverOptions} options
34
+ */
35
+ // @ts-expect-error Deliberate default empty options for better error messages
25
36
  constructor(options = {}) {
26
37
  this.#http = options.http || new HTTP();
27
38
  const name = options.clientName;
@@ -50,6 +61,12 @@ export default class PodletClientFallbackResolver {
50
61
  return this.#metrics;
51
62
  }
52
63
 
64
+ /**
65
+ * Resolves/fetches the podlet's fallback.
66
+ *
67
+ * @param {import('./http-outgoing.js').default} outgoing
68
+ * @returns {Promise<import('./http-outgoing.js').default>}
69
+ */
53
70
  async resolve(outgoing) {
54
71
  if (outgoing.status === 'cached') {
55
72
  return outgoing;
@@ -77,6 +94,7 @@ export default class PodletClientFallbackResolver {
77
94
  'User-Agent': UA_STRING,
78
95
  };
79
96
 
97
+ /** @type {import('./http.js').PodiumHttpClientRequestOptions} */
80
98
  const reqOptions = {
81
99
  rejectUnauthorized: outgoing.rejectUnauthorized,
82
100
  timeout: outgoing.timeout,
@@ -133,6 +151,7 @@ export default class PodletClientFallbackResolver {
133
151
  `successfully read fallback from remote resource - resource: ${outgoing.name} - url: ${outgoing.fallbackUri}`,
134
152
  );
135
153
  return outgoing;
154
+ // eslint-disable-next-line no-unused-vars
136
155
  } catch (error) {
137
156
  timer({
138
157
  labels: {
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({ ...options, http });
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
+ }
@@ -1,5 +1,3 @@
1
- /* eslint-disable no-param-reassign */
2
-
3
1
  import CachePolicy from 'http-cache-semantics';
4
2
  import { manifest as validateManifest } from '@podium/schemas';
5
3
  import Metrics from '@metrics/client';
@@ -20,11 +18,24 @@ const pkg = JSON.parse(pkgJson);
20
18
 
21
19
  const UA_STRING = `${pkg.name} ${pkg.version}`;
22
20
 
21
+ /**
22
+ * @typedef {object} PodletClientManifestResolverOptions
23
+ * @property {string} clientName
24
+ * @property {import('abslog').AbstractLoggerOptions} [logger]
25
+ * @property {import('./http.js').default} [http]
26
+ */
27
+
23
28
  export default class PodletClientManifestResolver {
24
29
  #log;
25
30
  #metrics;
26
31
  #histogram;
27
32
  #http;
33
+
34
+ /**
35
+ * @constructor
36
+ * @param {PodletClientManifestResolverOptions} options
37
+ */
38
+ // @ts-expect-error Deliberate default empty options for better error messages
28
39
  constructor(options = {}) {
29
40
  this.#http = options.http || new HTTP();
30
41
  const name = options.clientName;
@@ -53,6 +64,10 @@ export default class PodletClientManifestResolver {
53
64
  return this.#metrics;
54
65
  }
55
66
 
67
+ /**
68
+ * @param {import('./http-outgoing.js').default} outgoing
69
+ * @returns {Promise<import('./http-outgoing.js').default>}
70
+ */
56
71
  async resolve(outgoing) {
57
72
  if (outgoing.status === 'cached') {
58
73
  return outgoing;
@@ -62,6 +77,7 @@ export default class PodletClientManifestResolver {
62
77
  'User-Agent': UA_STRING,
63
78
  };
64
79
 
80
+ /** @type {import('./http.js').PodiumHttpClientRequestOptions} */
65
81
  const reqOptions = {
66
82
  rejectUnauthorized: outgoing.rejectUnauthorized,
67
83
  timeout: outgoing.timeout,
@@ -81,11 +97,11 @@ export default class PodletClientManifestResolver {
81
97
  );
82
98
 
83
99
  try {
84
- const {
85
- statusCode,
86
- headers: hdrs,
87
- body,
88
- } = await this.#http.request(outgoing.manifestUri, reqOptions);
100
+ const response = await this.#http.request(
101
+ outgoing.manifestUri,
102
+ reqOptions,
103
+ );
104
+ const { statusCode, headers: hdrs, body } = response;
89
105
 
90
106
  // Remote responds but with an http error code
91
107
  const resError = statusCode !== 200;
@@ -105,7 +121,11 @@ export default class PodletClientManifestResolver {
105
121
  return outgoing;
106
122
  }
107
123
 
108
- const manifest = validateManifest(await body.json());
124
+ const manifest = validateManifest(
125
+ /** @type {import("@podium/schemas").PodletManifestSchema} */ (
126
+ await body.json()
127
+ ),
128
+ );
109
129
 
110
130
  // Manifest validation error
111
131
  if (manifest.error) {
@@ -158,6 +178,7 @@ export default class PodletClientManifestResolver {
158
178
  );
159
179
 
160
180
  // Construct css and js objects with absolute URIs
181
+ // @ts-expect-error We assign here what will end up as PodletManifest as defined in http-outgoing.js
161
182
  manifest.value.css = manifest.value.css.map((obj) => {
162
183
  obj.value = utils.uriRelativeToAbsolute(
163
184
  obj.value,
@@ -166,6 +187,7 @@ export default class PodletClientManifestResolver {
166
187
  return new utils.AssetCss(obj);
167
188
  });
168
189
 
190
+ // @ts-expect-error We assign here what will end up as PodletManifest as defined in http-outgoing.js
169
191
  manifest.value.js = manifest.value.js.map((obj) => {
170
192
  obj.value = utils.uriRelativeToAbsolute(
171
193
  obj.value,
@@ -179,9 +201,9 @@ export default class PodletClientManifestResolver {
179
201
 
180
202
  If .proxy is and Array, the podlet are of version 6 or newer. The Array is then an
181
203
  Array of proxy Objects ({ name: 'foo', target: '/' }) which is the new structure
182
- wanted from version 6 and onwards so leave this structure untouched.
204
+ wanted from version 6 and onwards so leave this structure untouched.
183
205
 
184
- If .proxy is an Object, the podlet are of version 5 or older where the key of the
206
+ If .proxy is an Object, the podlet are of version 5 or older where the key of the
185
207
  Object is the key of the target. If so, convert the structure to the new structure
186
208
  consisting of an Array of proxy Objects.
187
209
 
@@ -191,12 +213,12 @@ export default class PodletClientManifestResolver {
191
213
  if (Array.isArray(manifest.value.proxy)) {
192
214
  // Build absolute proxy URIs
193
215
  manifest.value.proxy = manifest.value.proxy.map((item) => ({
194
- target: utils.uriRelativeToAbsolute(
195
- item.target,
196
- outgoing.manifestUri,
197
- ),
198
- name: item.name,
199
- }));
216
+ target: utils.uriRelativeToAbsolute(
217
+ item.target,
218
+ outgoing.manifestUri,
219
+ ),
220
+ name: item.name,
221
+ }));
200
222
  } else {
201
223
  const proxies = [];
202
224
  // Build absolute proxy URIs
@@ -216,6 +238,7 @@ export default class PodletClientManifestResolver {
216
238
  END: Proxy backwards compabillity check and handling
217
239
  */
218
240
 
241
+ // @ts-expect-error We map to AssetCss and AssetJs above
219
242
  outgoing.manifest = manifest.value;
220
243
  outgoing.status = 'fresh';
221
244
 
@@ -223,6 +246,7 @@ export default class PodletClientManifestResolver {
223
246
  `successfully read manifest from remote resource - resource: ${outgoing.name} - url: ${outgoing.manifestUri}`,
224
247
  );
225
248
  return outgoing;
249
+ // eslint-disable-next-line no-unused-vars
226
250
  } catch (error) {
227
251
  timer({
228
252
  labels: {
package/lib/resource.js CHANGED
@@ -1,5 +1,3 @@
1
- /* eslint-disable no-param-reassign */
2
-
3
1
  import Metrics from '@metrics/client';
4
2
  import abslog from 'abslog';
5
3
  import assert from 'assert';
@@ -11,11 +9,42 @@ import * as utils from './utils.js';
11
9
 
12
10
  const inspect = Symbol.for('nodejs.util.inspect.custom');
13
11
 
12
+ /**
13
+ * @typedef {object} RequestFilterOptions
14
+ * @property {string[]} [deviceType] List of values for the `x-podium-device-type` HTTP request header.
15
+ */
16
+
17
+ /**
18
+ * @typedef {object} PodiumClientResourceOptions
19
+ * @property {import('abslog').AbstractLoggerOptions} [logger]
20
+ * @property {string} clientName
21
+ * @property {string} name
22
+ * @property {string} uri To the podlet's `manifest.json`
23
+ * @property {number} timeout In milliseconds
24
+ * @property {number} maxAge
25
+ * @property {number} [retries]
26
+ * @property {boolean} [throwable]
27
+ * @property {boolean} [redirectable]
28
+ * @property {boolean} [rejectUnauthorized]
29
+ * @property {import('http').Agent} [httpAgent]
30
+ * @property {import('https').Agent} [httpsAgent]
31
+ * @property {RequestFilterOptions} [excludeBy] Used by `fetch` to conditionally skip fetching the podlet content based on values on the request.
32
+ * @property {RequestFilterOptions} [includeBy] Used by `fetch` to conditionally skip fetching the podlet content based on values on the request.
33
+ */
34
+
14
35
  export default class PodiumClientResource {
15
36
  #resolver;
16
37
  #options;
17
38
  #metrics;
18
39
  #state;
40
+
41
+ /**
42
+ * @constructor
43
+ * @param {import('ttl-mem-cache').default} registry
44
+ * @param {import('./state.js').default} state
45
+ * @param {PodiumClientResourceOptions} options
46
+ */
47
+ // @ts-expect-error Deliberate for better error messages
19
48
  constructor(registry, state, options = {}) {
20
49
  assert(
21
50
  registry,
@@ -56,7 +85,22 @@ export default class PodiumClientResource {
56
85
  return this.#options.uri;
57
86
  }
58
87
 
59
- async fetch(incoming = {}, reqOptions = {}) {
88
+ /**
89
+ * Fetch the podlet's content, or fallback if the podlet is unavailable.
90
+ * The podlet response includes references to its CSS and JS assets which should be included in the final HTML document.
91
+ *
92
+ * @param {import('@podium/utils').HttpIncoming} incoming Instance of HttpIncoming
93
+ * @param {import('./http-outgoing.js').PodiumClientResourceOptions} [reqOptions={}] Optional parameters to the HTTP request, such as query parameters or HTTP request headers.
94
+ * @returns {Promise<import('./response.js').default>}
95
+ *
96
+ * @example
97
+ * ```js
98
+ * const incoming = res.locals.podium; // Express server example
99
+ * const header = await headerPodlet.fetch(incoming);
100
+ * incoming.podlets = [header]; // Register the podlet's JS and CSS assets with the layout's HTML template
101
+ * ```
102
+ */
103
+ async fetch(incoming, reqOptions = {}) {
60
104
  if (!utils.validateIncoming(incoming))
61
105
  throw new TypeError(
62
106
  'you must pass an instance of "HttpIncoming" as the first argument to the .fetch() method',
@@ -67,21 +111,21 @@ export default class PodiumClientResource {
67
111
  /**
68
112
  * @type {string[] | undefined}
69
113
  */
70
- const exclucedDeviceTypes = this.#options.excludeBy.deviceType;
71
- if (Array.isArray(exclucedDeviceTypes)) {
114
+ const excludedDeviceTypes = this.#options.excludeBy.deviceType;
115
+ if (Array.isArray(excludedDeviceTypes)) {
72
116
  const deviceTypeHeader =
73
117
  incoming.request.headers['x-podium-device-type'];
74
118
 
75
- for (let i = 0; i < exclucedDeviceTypes.length; i += 1) {
119
+ for (let i = 0; i < excludedDeviceTypes.length; i += 1) {
76
120
  const shouldSkip =
77
- exclucedDeviceTypes[i] === deviceTypeHeader;
121
+ excludedDeviceTypes[i] === deviceTypeHeader;
78
122
  if (shouldSkip) {
79
123
  return new Response({
80
124
  headers: {},
81
125
  content: '',
82
126
  css: [],
83
127
  js: [],
84
- redirect: '',
128
+ redirect: null,
85
129
  });
86
130
  }
87
131
  }
@@ -107,7 +151,7 @@ export default class PodiumClientResource {
107
151
  content: '',
108
152
  css: [],
109
153
  js: [],
110
- redirect: '',
154
+ redirect: null,
111
155
  });
112
156
  }
113
157
  }
@@ -119,7 +163,7 @@ export default class PodiumClientResource {
119
163
  await this.#resolver.resolve(outgoing);
120
164
 
121
165
  const chunks = [];
122
- // eslint-disable-next-line no-restricted-syntax
166
+
123
167
  for await (const chunk of outgoing) {
124
168
  chunks.push(chunk);
125
169
  }
@@ -143,7 +187,14 @@ export default class PodiumClientResource {
143
187
  });
144
188
  }
145
189
 
146
- stream(incoming = {}, reqOptions = {}) {
190
+ /**
191
+ * Stream the podlet's content, or fallback if the podlet is unavailable.
192
+ *
193
+ * @param {import('@podium/utils').HttpIncoming} incoming
194
+ * @param {import('./http-outgoing.js').PodiumClientResourceOptions} [reqOptions={}]
195
+ * @returns {import('./http-outgoing.js').default}
196
+ */
197
+ stream(incoming, reqOptions = {}) {
147
198
  if (!utils.validateIncoming(incoming))
148
199
  throw new TypeError(
149
200
  'you must pass an instance of "HttpIncoming" as the first argument to the .stream() method',
@@ -154,7 +205,14 @@ export default class PodiumClientResource {
154
205
  return outgoing;
155
206
  }
156
207
 
157
- refresh(incoming = {}, reqOptions = {}) {
208
+ /**
209
+ * Refresh the podlet's manifest and fallback in the cache.
210
+ *
211
+ * @param {import('@podium/utils').HttpIncoming} [incoming]
212
+ * @param {import('./http-outgoing.js').PodiumClientResourceOptions} [reqOptions={}]
213
+ * @returns {Promise<boolean>} `true` if succesful
214
+ */
215
+ refresh(incoming, reqOptions = {}) {
158
216
  const outgoing = new HttpOutgoing(this.#options, reqOptions, incoming);
159
217
  this.#state.setInitializingState();
160
218
  return this.#resolver.refresh(outgoing).then((obj) => obj);
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 = {},
@@ -45,8 +59,8 @@ export default class PodiumClientResponse {
45
59
  redirect: this.redirect,
46
60
  content: this.content,
47
61
  headers: this.headers,
48
- css: this.css,
49
- js: this.js,
62
+ css: this.css.map((a) => a.toJSON()),
63
+ js: this.js.map((a) => a.toJSON()),
50
64
  };
51
65
  }
52
66
 
@@ -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
+ }