@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.
package/README.md CHANGED
@@ -150,18 +150,16 @@ The following values can be provided:
150
150
  - `retries` - {Number} - The number of times the client should retry to settle a version number conflict before terminating. See the section "[on retrying](#on-retrying)" for more information. Default: 4 - Optional.
151
151
  - `timeout` - {Number} - Defines how long, in milliseconds, a request should wait before the connection is terminated. Overrides the global default. Default: 1000 - Optional.
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
- - `resolveJs` - {Boolean} - Defines whether to resolve a relative JS uri for a component to be an absolute uri. Defaults to `false` - Optional.
154
- - `resolveCss` - {Boolean} - Defines whether to resolve a relative CSS uri for a component to be an absolute uri. Defaults to `false` - Optional.
155
153
  - `excludeBy` - {Object} - Lets you define a set of rules where a `fetch` call will not be resolved if it matches. - Optional.
156
- - `includeBy` - {Object} - Inverse of `excludeBy`. - Optional.
154
+ - `includeBy` - {Object} - Inverse of `excludeBy`. Setting both at the same time will throw. - Optional.
157
155
 
158
156
  ##### `excludeBy` and `includeBy`
159
157
 
160
- These options are used by `fetch` to conditionally skip fetching the podlet content based on values on the request. It's an alternative to conditionally fetching podlets in your request handler.
158
+ These options are used by `fetch` to conditionally skip fetching the podlet content based on values on the request. It's an alternative to conditionally fetching podlets in your request handler. Setting both at the same time will throw.
161
159
 
162
160
  Allowed options:
163
161
 
164
- - `deviceType` - {Array<String>} - List of values for the `x-podium-device-type` header. - Optional.
162
+ - `deviceType` - {Array<String>} - List of values for the `x-podium-device-type` header. - Optional.
165
163
 
166
164
  Example: exclude a header and footer in a hybrid web view.
167
165
 
@@ -173,7 +171,7 @@ const footer = client.register({
173
171
  uri: 'http://footer.site.com/manifest.json',
174
172
  name: 'footer',
175
173
  excludeBy: {
176
- deviceType: ["hybrid-ios", "hybrid-android"], // when footer.fetch(incoming) is called, if the incoming request has the header `x-podium-device-type: hybrid-ios`, `fetch` will return an empty response.
174
+ deviceType: ['hybrid-ios', 'hybrid-android'], // when footer.fetch(incoming) is called, if the incoming request has the header `x-podium-device-type: hybrid-ios`, `fetch` will return an empty response.
177
175
  },
178
176
  });
179
177
  ```
@@ -382,7 +380,7 @@ Response object containing the keys `content`, `headers`, `css` and `js`.
382
380
 
383
381
  #### incoming (required)
384
382
 
385
- A HttpIncoming object. See https://github.com/podium-lib/utils/blob/master/lib/http-incoming.js
383
+ A HttpIncoming object. See https://github.com/podium-lib/utils/blob/main/lib/http-incoming.js
386
384
 
387
385
  #### options (optional)
388
386
 
@@ -413,7 +411,7 @@ emitted.
413
411
 
414
412
  #### incoming (required)
415
413
 
416
- A HttpIncoming object. See https://github.com/podium-lib/utils/blob/master/lib/http-incoming.js
414
+ A HttpIncoming object. See https://github.com/podium-lib/utils/blob/main/lib/http-incoming.js
417
415
 
418
416
  #### options (optional)
419
417
 
@@ -462,15 +460,19 @@ stream.once('beforeStream', (data) => {
462
460
  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).
463
461
 
464
462
  For example, if the podlet manifest contains a JavaScript asset definition of the form:
463
+
465
464
  ```
466
465
  {
467
466
  js: [{ value: "https://assets.com/path/to/file.js", scope: "content" }],
468
467
  }
469
468
  ```
469
+
470
470
  And the client performs a fetch like so:
471
+
471
472
  ```js
472
473
  const result = await component.fetch();
473
474
  ```
475
+
474
476
  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.
475
477
 
476
478
  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.
package/lib/client.js CHANGED
@@ -1,16 +1,17 @@
1
1
  import EventEmitter from 'events';
2
- import {uriStrict as validateUriStrict, name as validateName } from'@podium/schemas';
2
+ import {
3
+ uriStrict as validateUriStrict,
4
+ name as validateName,
5
+ } from '@podium/schemas';
3
6
  import Metrics from '@metrics/client';
4
7
  import abslog from 'abslog';
5
8
  import Cache from 'ttl-mem-cache';
6
9
  import http from 'http';
7
10
  import https from 'https';
8
-
9
11
  import Resource from './resource.js';
10
12
  import State from './state.js';
11
13
 
12
14
  const inspect = Symbol.for('nodejs.util.inspect.custom');
13
-
14
15
  const HTTP_AGENT_OPTIONS = {
15
16
  keepAlive: true,
16
17
  maxSockets: 10,
@@ -18,24 +19,51 @@ const HTTP_AGENT_OPTIONS = {
18
19
  timeout: 60000,
19
20
  keepAliveMsecs: 30000,
20
21
  };
21
-
22
22
  const HTTPS_AGENT_OPTIONS = {
23
23
  ...HTTP_AGENT_OPTIONS,
24
24
  maxCachedSessions: 10,
25
25
  };
26
-
27
26
  const REJECT_UNAUTHORIZED = true;
28
-
29
27
  const HTTP_AGENT = new http.Agent(HTTP_AGENT_OPTIONS);
30
-
31
28
  const HTTPS_AGENT = new https.Agent(HTTPS_AGENT_OPTIONS);
32
-
33
29
  const RETRIES = 4;
34
-
35
30
  const TIMEOUT = 1000; // 1 seconds
36
-
37
31
  const MAX_AGE = Infinity;
38
32
 
33
+ /**
34
+ * @typedef {import('./resource.js').default} PodiumClientResource
35
+ * @typedef {import('./resource.js').PodiumClientResourceOptions} PodiumClientResourceOptions
36
+ * @typedef {import('./response.js').default} PodiumClientResponse
37
+ * @typedef {import('./http-outgoing.js').PodiumRedirect} PodiumRedirect
38
+ * @typedef {import('@podium/schemas').PodletManifestSchema} PodletManifest
39
+ */
40
+
41
+ /**
42
+ * @typedef {object} PodiumClientOptions
43
+ * @property {string} name
44
+ * @property {import('abslog').AbstractLoggerOptions} [logger]
45
+ * @property {number} [retries=4]
46
+ * @property {number} [timeout=1000] In milliseconds
47
+ * @property {number} [maxAge=Infinity]
48
+ * @property {boolean} [rejectUnauthorized=true]
49
+ * @property {number} [resolveThreshold]
50
+ * @property {number} [resolveMax]
51
+ * @property {import('http').Agent} [httpAgent]
52
+ * @property {import('https').Agent} [httpsAgent]
53
+ */
54
+
55
+ /**
56
+ * @typedef {object} RegisterOptions
57
+ * @property {string} name A unique name for the podlet
58
+ * @property {string} uri URL to the podlet's `manifest.json`
59
+ * @property {number} [retries=4] Number of retries before serving fallback
60
+ * @property {number} [timeout=1000] In milliseconds, the amount of time to wait before serving fallback.
61
+ * @property {boolean} [throwable=false] Set to `true` and surround `fetch` in `try/catch` to serve different content in case podlet is unavailable. Will not server fallback content.
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
+ * @property {import('./resource.js').RequestFilterOptions} [excludeBy] Used by `fetch` to conditionally skip fetching the podlet content based on values on the request.
64
+ * @property {import('./resource.js').RequestFilterOptions} [includeBy] Used by `fetch` to conditionally skip fetching the podlet content based on values on the request.
65
+ */
66
+
39
67
  export default class PodiumClient extends EventEmitter {
40
68
  #resources;
41
69
  #registry;
@@ -43,6 +71,12 @@ export default class PodiumClient extends EventEmitter {
43
71
  #histogram;
44
72
  #options;
45
73
  #state;
74
+
75
+ /**
76
+ * @constructor
77
+ * @param {PodiumClientOptions} options
78
+ */
79
+ // @ts-expect-error Deliberate default empty options for better error messages
46
80
  constructor(options = {}) {
47
81
  super();
48
82
  const log = abslog(options.logger);
@@ -71,7 +105,7 @@ export default class PodiumClient extends EventEmitter {
71
105
  resolveThreshold: options.resolveThreshold,
72
106
  resolveMax: options.resolveMax,
73
107
  });
74
- this.#state.on('state', state => {
108
+ this.#state.on('state', (state) => {
75
109
  this.emit('state', state);
76
110
  });
77
111
 
@@ -81,7 +115,7 @@ export default class PodiumClient extends EventEmitter {
81
115
  changefeed: true,
82
116
  ttl: options.maxAge,
83
117
  });
84
- this.#registry.on('error', error => {
118
+ this.#registry.on('error', (error) => {
85
119
  log.error(
86
120
  'Error emitted by the registry in @podium/client module',
87
121
  error,
@@ -93,7 +127,7 @@ export default class PodiumClient extends EventEmitter {
93
127
  });
94
128
 
95
129
  this.#metrics = new Metrics();
96
- this.#metrics.on('error', error => {
130
+ this.#metrics.on('error', (error) => {
97
131
  log.error(
98
132
  'Error emitted by metric stream in @podium/client module',
99
133
  error,
@@ -101,7 +135,7 @@ export default class PodiumClient extends EventEmitter {
101
135
  });
102
136
 
103
137
  this[Symbol.iterator] = () => ({
104
- items: Array.from(this.#resources).map(item => item[1]),
138
+ items: Array.from(this.#resources).map((item) => item[1]),
105
139
  next: function next() {
106
140
  return {
107
141
  done: this.items.length === 0,
@@ -130,7 +164,21 @@ export default class PodiumClient extends EventEmitter {
130
164
  return this.#state.status;
131
165
  }
132
166
 
133
- register(options = {}) {
167
+ /**
168
+ * Register a podlet so you can fetch its contents later with {@link PodiumClientResource.fetch}.
169
+ *
170
+ * @param {RegisterOptions} options
171
+ * @returns {PodiumClientResource}
172
+ *
173
+ * @example
174
+ * ```js
175
+ * const headerPodlet = layout.client.register({
176
+ * name: 'header',
177
+ * uri: 'http://header/manifest.json',
178
+ * });
179
+ * ```
180
+ */
181
+ register(options) {
134
182
  if (validateName(options.name).error)
135
183
  throw new Error(
136
184
  `The value, "${options.name}", for the required argument "name" on the .register() method is not defined or not valid.`,
@@ -147,6 +195,12 @@ export default class PodiumClient extends EventEmitter {
147
195
  );
148
196
  }
149
197
 
198
+ if (options.includeBy && options.excludeBy) {
199
+ throw new Error(
200
+ 'A podlet can only be registered with either includeBy or excludeBy, not both.',
201
+ );
202
+ }
203
+
150
204
  const resourceOptions = {
151
205
  rejectUnauthorized: this.#options.rejectUnauthorized,
152
206
  clientName: this.#options.name,
@@ -154,12 +208,13 @@ export default class PodiumClient extends EventEmitter {
154
208
  timeout: this.#options.timeout,
155
209
  logger: this.#options.logger,
156
210
  maxAge: this.#options.maxAge,
157
- includeBy: this.#options.includeBy,
158
- excludeBy: this.#options.excludeBy,
159
211
  httpsAgent: this.#options.httpsAgent,
160
212
  httpAgent: this.#options.httpAgent,
213
+ includeBy: this.#options.includeBy,
214
+ excludeBy: this.#options.excludeBy,
161
215
  ...options,
162
216
  };
217
+
163
218
  const resource = new Resource(
164
219
  this.#registry,
165
220
  this.#state,
@@ -187,12 +242,17 @@ export default class PodiumClient extends EventEmitter {
187
242
  return this.#registry.load(dump);
188
243
  }
189
244
 
245
+ /**
246
+ * Refreshes the cached podlet manifest for all {@link register}ed podlets.
247
+ */
190
248
  async refreshManifests() {
191
249
  const end = this.#histogram.timer();
192
250
 
193
251
  // Don't return this
194
252
  await Promise.all(
195
- Array.from(this.#resources).map(resource => resource[1].refresh()),
253
+ Array.from(this.#resources).map((resource) =>
254
+ resource[1].refresh(),
255
+ ),
196
256
  );
197
257
 
198
258
  end();
@@ -208,4 +268,4 @@ export default class PodiumClient extends EventEmitter {
208
268
  get [Symbol.toStringTag]() {
209
269
  return 'PodiumClient';
210
270
  }
211
- };
271
+ }
@@ -1,28 +1,84 @@
1
- /* eslint-disable no-underscore-dangle */
2
-
3
1
  import { PassThrough } from 'stream';
4
2
  import assert from 'assert';
5
3
 
4
+ /**
5
+ * @typedef {object} PodiumClientHttpOutgoingOptions
6
+ * @property {string} name
7
+ * @property {string} uri To the podlet's `manifest.json`
8
+ * @property {number} timeout In milliseconds
9
+ * @property {number} maxAge
10
+ * @property {number} [retries=4]
11
+ * @property {boolean} [throwable=false]
12
+ * @property {boolean} [redirectable=false]
13
+ * @property {boolean} [rejectUnauthorized=true]
14
+ * @property {import('http').Agent} [httpAgent]
15
+ * @property {import('https').Agent} [httpsAgent]
16
+ */
17
+
18
+ /**
19
+ * @typedef {object} PodiumClientResourceOptions
20
+ * @property {string} [pathname]
21
+ * @property {import('http').IncomingHttpHeaders} [headers]
22
+ * @property {object} [query]
23
+ */
24
+
25
+ /**
26
+ * @typedef {object} PodiumRedirect
27
+ * @property {number} statusCode;
28
+ * @property {string} location;
29
+ */
30
+
31
+ /**
32
+ * @typedef {object} PodletProxySchema
33
+ * @property {string} target
34
+ * @property {string} name
35
+ */
36
+
37
+ /**
38
+ * @typedef {object} PodletManifest Similar to the schema's manifest, but with instances of AssetCss and AssetJs from `@podium/utils` and default values.
39
+ * @property {string} name
40
+ * @property {string} version
41
+ * @property {string} content
42
+ * @property {string} fallback
43
+ * @property {Array<import('@podium/utils').AssetJs>} js
44
+ * @property {Array<import('@podium/utils').AssetCss>} css
45
+ * @property {Record<string, string> | Array<PodletProxySchema>} proxy
46
+ * @property {string} team
47
+ */
48
+
6
49
  export default class PodletClientHttpOutgoing extends PassThrough {
7
50
  #rejectUnauthorized;
8
51
  #killRecursions;
9
52
  #killThreshold;
10
53
  #redirectable;
11
54
  #reqOptions;
12
- #isFallback;
55
+ #isFallback = false;
13
56
  #throwable;
57
+ /** @type {PodletManifest} */
14
58
  #manifest;
15
59
  #incoming;
16
- #redirect;
60
+ /** @type {null | PodiumRedirect} */
61
+ #redirect = null;
17
62
  #timeout;
18
63
  #success;
19
64
  #headers;
20
65
  #maxAge;
66
+ /** @type {'empty' | 'fresh' | 'cached' | 'stale'} */
21
67
  #status;
22
68
  #name;
23
- #uri;
24
- constructor(
25
- {
69
+ #uri;
70
+
71
+ /**
72
+ * @constructor
73
+ * @param {PodiumClientHttpOutgoingOptions} options
74
+ * @param {PodiumClientResourceOptions} [reqOptions]
75
+ * @param {import('@podium/utils').HttpIncoming} [incoming]
76
+ */
77
+ // @ts-expect-error Deliberate default empty options for better error messages
78
+ constructor(options = {}, reqOptions, incoming) {
79
+ super();
80
+
81
+ const {
26
82
  rejectUnauthorized = true,
27
83
  throwable = false,
28
84
  redirectable = false,
@@ -31,11 +87,7 @@ export default class PodletClientHttpOutgoing extends PassThrough {
31
87
  maxAge,
32
88
  name = '',
33
89
  uri,
34
- } = {},
35
- reqOptions,
36
- incoming,
37
- ) {
38
- super();
90
+ } = options;
39
91
 
40
92
  assert(
41
93
  uri,
@@ -45,7 +97,6 @@ export default class PodletClientHttpOutgoing extends PassThrough {
45
97
  // If requests to https sites should reject on unsigned sertificates
46
98
  this.#rejectUnauthorized = rejectUnauthorized;
47
99
 
48
- // A HttpIncoming object
49
100
  this.#incoming = incoming;
50
101
 
51
102
  // Kill switch for breaking the recursive promise chain
@@ -67,6 +118,7 @@ export default class PodletClientHttpOutgoing extends PassThrough {
67
118
  // Manifest which is either retrieved from the registry or
68
119
  // remote podlet (in other words its not saved in registry yet)
69
120
  this.#manifest = {
121
+ // @ts-expect-error Internal property
70
122
  _fallback: '',
71
123
  };
72
124
 
@@ -82,14 +134,6 @@ export default class PodletClientHttpOutgoing extends PassThrough {
82
134
  // How long the manifest should be cached before refetched
83
135
  this.#maxAge = maxAge;
84
136
 
85
- // What status the manifest is in. This is used to tell what actions need to
86
- // be performed throughout the resolving process to complete a request.
87
- //
88
- // The different statuses can be:
89
- // "empty" - there is no manifest available - we are in process of fetching it
90
- // "fresh" - the manifest has been fetched but is not stored in cache yet
91
- // "cached" - the manifest was retrieved from cache
92
- // "stale" - the manifest is outdated, a new manifest needs to be fetched
93
137
  this.#status = 'empty';
94
138
 
95
139
  // Name of the resource (name given to client)
@@ -100,13 +144,6 @@ export default class PodletClientHttpOutgoing extends PassThrough {
100
144
 
101
145
  // Whether the user can handle redirects manually.
102
146
  this.#redirectable = redirectable;
103
-
104
- // When redirectable is true, this object should be populated with redirect information
105
- // such that a user can perform manual redirection
106
- this.#redirect = null;
107
-
108
- // When isfallback is true, content fetch has failed and fallback will be served instead
109
- this.#isFallback = false;
110
147
  }
111
148
 
112
149
  get rejectUnauthorized() {
@@ -130,10 +167,12 @@ export default class PodletClientHttpOutgoing extends PassThrough {
130
167
  }
131
168
 
132
169
  get fallback() {
170
+ // @ts-expect-error Internal property
133
171
  return this.#manifest._fallback;
134
172
  }
135
173
 
136
174
  set fallback(value) {
175
+ // @ts-expect-error Internal property
137
176
  this.#manifest._fallback = value;
138
177
  }
139
178
 
@@ -169,6 +208,16 @@ export default class PodletClientHttpOutgoing extends PassThrough {
169
208
  this.#maxAge = value;
170
209
  }
171
210
 
211
+ /**
212
+ * What status the manifest is in. This is used to tell what actions need to
213
+ * be performed throughout the resolving process to complete a request.
214
+ *
215
+ * The different statuses can be:
216
+ * - `"empty"` - there is no manifest available - we are in process of fetching it
217
+ * - `"fresh"` - the manifest has been fetched but is not stored in cache yet
218
+ * - `"cached"` - the manifest was retrieved from cache
219
+ * - `"stale"` - the manifest is outdated, a new manifest needs to be fetched
220
+ */
172
221
  get status() {
173
222
  return this.#status;
174
223
  }
@@ -193,18 +242,33 @@ export default class PodletClientHttpOutgoing extends PassThrough {
193
242
  return this.#manifest.content;
194
243
  }
195
244
 
245
+ /**
246
+ * Kill switch for breaking the recursive promise chain in case it is never able to completely resolve.
247
+ * This is true if the number of recursions matches the threshold.
248
+ */
196
249
  get kill() {
197
250
  return this.#killRecursions === this.#killThreshold;
198
251
  }
199
252
 
253
+ /**
254
+ * The number of recursions before the request should be {@link kill}ed
255
+ */
200
256
  get recursions() {
201
257
  return this.#killRecursions;
202
258
  }
203
259
 
260
+ /**
261
+ * Set the number of recursions before the request should be {@link kill}ed
262
+ */
204
263
  set recursions(value) {
205
264
  this.#killRecursions = value;
206
265
  }
207
266
 
267
+ /**
268
+ * When {@link redirectable} is `true` this is populated with redirect information so you can send a redirect response to the browser from your layout.
269
+ *
270
+ * @see https://podium-lib.io/docs/layout/handling_redirects
271
+ */
208
272
  get redirect() {
209
273
  return this.#redirect;
210
274
  }
@@ -213,6 +277,11 @@ export default class PodletClientHttpOutgoing extends PassThrough {
213
277
  this.#redirect = value;
214
278
  }
215
279
 
280
+ /**
281
+ * Whether the podlet can signal redirects to the layout.
282
+ *
283
+ * @see https://podium-lib.io/docs/layout/handling_redirects
284
+ */
216
285
  get redirectable() {
217
286
  return this.#redirectable;
218
287
  }
@@ -222,17 +291,22 @@ export default class PodletClientHttpOutgoing extends PassThrough {
222
291
  }
223
292
 
224
293
  /**
225
- * Boolean getter that indicates whether the client is responding with a content or fallback payload.
294
+ * True if the client has returned the podlet's fallback.
295
+ *
226
296
  * @example
227
- * ```
297
+ *
298
+ * ```js
228
299
  * if (outgoing.isFallback) console.log("Fallback!");
229
300
  * ```
301
+ *
302
+ * @see https://podium-lib.io/docs/podlet/fallbacks
230
303
  */
231
304
  get isFallback() {
232
- return this.#isFallback;
305
+ return this.#isFallback;
233
306
  }
234
307
 
235
308
  pushFallback() {
309
+ // @ts-expect-error Internal property
236
310
  this.push(this.#manifest._fallback);
237
311
  this.push(null);
238
312
  this.#isFallback = true;
@@ -241,4 +315,4 @@ export default class PodletClientHttpOutgoing extends PassThrough {
241
315
  get [Symbol.toStringTag]() {
242
316
  return 'PodletClientHttpOutgoing';
243
317
  }
244
- };
318
+ }
package/lib/http.js CHANGED
@@ -1,23 +1,28 @@
1
- import { Client } from 'undici';
1
+ import { request } from 'undici';
2
2
 
3
- export default class HTTP {
4
- // #client;
5
-
6
- // constructor() {
7
- // // this.#client = { request };
8
- // }
3
+ /**
4
+ * @typedef {object} PodiumHttpClientRequestOptions
5
+ * @property {'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'CONNECT' | 'OPTIONS' | 'TRACE' | 'PATCH'} method
6
+ * @property {boolean} [json]
7
+ * @property {boolean} [rejectUnauthorized]
8
+ * @property {boolean} [follow]
9
+ * @property {number} [timeout]
10
+ * @property {number} [bodyTimeout]
11
+ * @property {object} [query]
12
+ * @property {import('http').IncomingHttpHeaders} [headers]
13
+ */
9
14
 
15
+ export default class HTTP {
16
+ /**
17
+ * @param {string} url
18
+ * @param {PodiumHttpClientRequestOptions} options
19
+ * @returns {Promise<Pick<import('undici').Dispatcher.ResponseData, 'statusCode' | 'headers' | 'body'>>}
20
+ */
10
21
  async request(url, options) {
11
- const u = new URL(url);
12
- const client = new Client(u.origin, {
13
- ...options,
14
- connect: { rejectUnauthorized: options.rejectUnauthorized },
15
- });
16
-
17
- const { statusCode, headers, body } = await client.request({
18
- ...options,
19
- path: u.pathname,
20
- });
22
+ const { statusCode, headers, body } = await request(
23
+ new URL(url),
24
+ options,
25
+ );
21
26
  return { statusCode, headers, body };
22
27
  }
23
28
  }
@@ -1,13 +1,21 @@
1
- /* eslint-disable no-plusplus */
2
- /* eslint-disable no-param-reassign */
3
-
4
1
  import clonedeep from 'lodash.clonedeep';
5
2
  import abslog from 'abslog';
6
3
  import assert from 'assert';
7
4
 
5
+ /**
6
+ * @typedef {object} PodletClientCacheResolverOptions
7
+ * @property {import('abslog').AbstractLoggerOptions} [logger]
8
+ */
9
+
8
10
  export default class PodletClientCacheResolver {
9
11
  #registry;
10
12
  #log;
13
+
14
+ /**
15
+ * @constructor
16
+ * @param {import('ttl-mem-cache').default} registry
17
+ * @param {PodletClientCacheResolverOptions} options
18
+ */
11
19
  constructor(registry, options = {}) {
12
20
  assert(
13
21
  registry,
@@ -17,8 +25,14 @@ export default class PodletClientCacheResolver {
17
25
  this.#log = abslog(options.logger);
18
26
  }
19
27
 
28
+ /**
29
+ * Loads the podlet's manifest from cache if not stale
30
+ *
31
+ * @param {import('./http-outgoing.js').default} outgoing
32
+ * @returns {Promise<import('./http-outgoing.js').default>}
33
+ */
20
34
  load(outgoing) {
21
- return new Promise(resolve => {
35
+ return new Promise((resolve) => {
22
36
  if (outgoing.status !== 'stale') {
23
37
  const cached = this.#registry.get(outgoing.name);
24
38
  if (cached) {
@@ -33,8 +47,14 @@ export default class PodletClientCacheResolver {
33
47
  });
34
48
  }
35
49
 
50
+ /**
51
+ * Saves the podlet's manifest to the cache
52
+ *
53
+ * @param {import('./http-outgoing.js').default} outgoing
54
+ * @returns {Promise<import('./http-outgoing.js').default>}
55
+ */
36
56
  save(outgoing) {
37
- return new Promise(resolve => {
57
+ return new Promise((resolve) => {
38
58
  if (outgoing.status === 'fresh') {
39
59
  this.#registry.set(
40
60
  outgoing.name,
@@ -55,4 +75,4 @@ export default class PodletClientCacheResolver {
55
75
  get [Symbol.toStringTag]() {
56
76
  return 'PodletClientCacheResolver';
57
77
  }
58
- };
78
+ }