@podium/client 5.0.0-next.10 → 5.0.0-next.12
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 +14 -0
- package/lib/http.js +23 -0
- package/lib/resolver.content.js +185 -203
- package/lib/resolver.fallback.js +90 -100
- package/lib/resolver.js +5 -3
- package/lib/resolver.manifest.js +135 -142
- package/lib/resource.js +6 -13
- package/lib/response.js +5 -9
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [5.0.0-next.12](https://github.com/podium-lib/client/compare/v5.0.0-next.11...v5.0.0-next.12) (2022-09-20)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* replace request with undici for http requests ([31163db](https://github.com/podium-lib/client/commit/31163db538d87cb797135d7febcc6cc244eac17a))
|
|
7
|
+
|
|
8
|
+
# [5.0.0-next.11](https://github.com/podium-lib/client/compare/v5.0.0-next.10...v5.0.0-next.11) (2022-09-08)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* Fix inspect method on response object ([#294](https://github.com/podium-lib/client/issues/294)) ([94d1485](https://github.com/podium-lib/client/commit/94d14856ca2280888aa50e9cb7e7f782cd49666a))
|
|
14
|
+
|
|
1
15
|
# [5.0.0-next.10](https://github.com/podium-lib/client/compare/v5.0.0-next.9...v5.0.0-next.10) (2022-09-07)
|
|
2
16
|
|
|
3
17
|
|
package/lib/http.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Client } from 'undici';
|
|
2
|
+
|
|
3
|
+
export default class HTTP {
|
|
4
|
+
// #client;
|
|
5
|
+
|
|
6
|
+
// constructor() {
|
|
7
|
+
// // this.#client = { request };
|
|
8
|
+
// }
|
|
9
|
+
|
|
10
|
+
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
|
+
});
|
|
21
|
+
return { statusCode, headers, body };
|
|
22
|
+
}
|
|
23
|
+
}
|
package/lib/resolver.content.js
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
/* eslint-disable no-param-reassign */
|
|
2
|
-
|
|
3
2
|
import { pipeline } from 'stream';
|
|
4
3
|
import Metrics from '@metrics/client';
|
|
5
|
-
import request from 'request';
|
|
6
4
|
import abslog from 'abslog';
|
|
7
5
|
import * as putils from '@podium/utils';
|
|
8
6
|
import { Boom, badGateway } from '@hapi/boom';
|
|
9
|
-
|
|
10
7
|
import { join, dirname } from 'path';
|
|
11
8
|
import { fileURLToPath } from 'url';
|
|
12
9
|
import fs from 'fs';
|
|
13
10
|
import * as utils from './utils.js';
|
|
14
11
|
import Response from './response.js';
|
|
12
|
+
import HTTP from './http.js';
|
|
15
13
|
|
|
16
14
|
const currentDirectory = dirname(fileURLToPath(import.meta.url));
|
|
17
15
|
|
|
18
|
-
const pkgJson = fs.readFileSync(
|
|
16
|
+
const pkgJson = fs.readFileSync(
|
|
17
|
+
join(currentDirectory, '../package.json'),
|
|
18
|
+
'utf-8',
|
|
19
|
+
);
|
|
19
20
|
const pkg = JSON.parse(pkgJson);
|
|
20
21
|
|
|
21
22
|
const UA_STRING = `${pkg.name} ${pkg.version}`;
|
|
@@ -24,13 +25,11 @@ export default class PodletClientContentResolver {
|
|
|
24
25
|
#log;
|
|
25
26
|
#metrics;
|
|
26
27
|
#histogram;
|
|
27
|
-
#
|
|
28
|
-
#httpsAgent;
|
|
28
|
+
#http;
|
|
29
29
|
constructor(options = {}) {
|
|
30
|
+
this.#http = options.http || new HTTP();
|
|
30
31
|
const name = options.clientName;
|
|
31
32
|
this.#log = abslog(options.logger);
|
|
32
|
-
this.#httpAgent = options.httpAgent;
|
|
33
|
-
this.#httpsAgent = options.httpsAgent;
|
|
34
33
|
this.#metrics = new Metrics();
|
|
35
34
|
this.#histogram = this.#metrics.histogram({
|
|
36
35
|
name: 'podium_client_resolver_content_resolve',
|
|
@@ -43,7 +42,7 @@ export default class PodletClientContentResolver {
|
|
|
43
42
|
buckets: [0.001, 0.01, 0.1, 0.5, 1, 2, 10],
|
|
44
43
|
});
|
|
45
44
|
|
|
46
|
-
this.#metrics.on('error', error => {
|
|
45
|
+
this.#metrics.on('error', (error) => {
|
|
47
46
|
this.#log.error(
|
|
48
47
|
'Error emitted by metric stream in @podium/client module',
|
|
49
48
|
error,
|
|
@@ -55,207 +54,177 @@ export default class PodletClientContentResolver {
|
|
|
55
54
|
return this.#metrics;
|
|
56
55
|
}
|
|
57
56
|
|
|
58
|
-
resolve(outgoing) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
),
|
|
68
|
-
);
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
57
|
+
async resolve(outgoing) {
|
|
58
|
+
if (outgoing.kill && outgoing.throwable) {
|
|
59
|
+
this.#log.warn(
|
|
60
|
+
`recursion detected - failed to resolve fetching of podlet ${outgoing.recursions} times - throwing - resource: ${outgoing.name} - url: ${outgoing.manifestUri}`,
|
|
61
|
+
);
|
|
62
|
+
throw badGateway(
|
|
63
|
+
`Recursion detected - failed to resolve fetching of podlet ${outgoing.recursions} times`,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
71
66
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
67
|
+
if (outgoing.kill) {
|
|
68
|
+
this.#log.warn(
|
|
69
|
+
`recursion detected - failed to resolve fetching of podlet ${outgoing.recursions} times - serving fallback - resource: ${outgoing.name} - url: ${outgoing.manifestUri}`,
|
|
70
|
+
);
|
|
71
|
+
outgoing.success = true;
|
|
72
|
+
outgoing.pushFallback();
|
|
73
|
+
return outgoing;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (outgoing.status === 'empty' && outgoing.throwable) {
|
|
77
|
+
this.#log.warn(
|
|
78
|
+
`no manifest available - cannot read content - throwing - resource: ${outgoing.name} - url: ${outgoing.manifestUri}`,
|
|
79
|
+
);
|
|
80
|
+
throw badGateway(`No manifest available - Cannot read content`);
|
|
81
|
+
}
|
|
81
82
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
if (outgoing.status === 'empty') {
|
|
84
|
+
this.#log.warn(
|
|
85
|
+
`no manifest available - cannot read content - serving fallback - resource: ${outgoing.name} - url: ${outgoing.manifestUri}`,
|
|
86
|
+
);
|
|
87
|
+
outgoing.success = true;
|
|
88
|
+
outgoing.pushFallback();
|
|
89
|
+
return outgoing;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const headers = {
|
|
93
|
+
...outgoing.reqOptions.headers,
|
|
94
|
+
'User-Agent': UA_STRING,
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
putils.serializeContext(headers, outgoing.context, outgoing.name);
|
|
98
|
+
|
|
99
|
+
const uri = putils.uriBuilder(
|
|
100
|
+
outgoing.reqOptions.pathname,
|
|
101
|
+
outgoing.contentUri,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
const reqOptions = {
|
|
105
|
+
rejectUnauthorized: outgoing.rejectUnauthorized,
|
|
106
|
+
bodyTimeout: outgoing.timeout,
|
|
107
|
+
method: 'GET',
|
|
108
|
+
query: outgoing.reqOptions.query,
|
|
109
|
+
headers,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
if (outgoing.redirectable) {
|
|
113
|
+
reqOptions.follow = false;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const timer = this.#histogram.timer({
|
|
117
|
+
labels: {
|
|
118
|
+
podlet: outgoing.name,
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
this.#log.debug(
|
|
123
|
+
`start reading content from remote resource - manifest version is ${outgoing.manifest.version} - resource: ${outgoing.name} - url: ${outgoing.contentUri}`,
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
const {
|
|
128
|
+
statusCode,
|
|
129
|
+
headers: hdrs,
|
|
130
|
+
body,
|
|
131
|
+
} = await this.#http.request(uri, reqOptions);
|
|
132
|
+
|
|
133
|
+
// Remote responds but with an http error code
|
|
134
|
+
const resError = statusCode >= 400;
|
|
135
|
+
if (resError && outgoing.throwable) {
|
|
136
|
+
timer({
|
|
137
|
+
labels: {
|
|
138
|
+
status: 'failure',
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
this.#log.debug(
|
|
143
|
+
`remote resource responded with non 200 http status code for content - code: ${statusCode} - resource: ${outgoing.name} - url: ${outgoing.contentUri}`,
|
|
88
144
|
);
|
|
89
|
-
|
|
145
|
+
|
|
146
|
+
const errorMessage = `Could not read content. Resource responded with ${statusCode} on ${outgoing.contentUri}`;
|
|
147
|
+
|
|
148
|
+
const errorOptions = {
|
|
149
|
+
statusCode,
|
|
150
|
+
decorate: {
|
|
151
|
+
statusCode,
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
throw new Boom(errorMessage, errorOptions);
|
|
90
156
|
}
|
|
157
|
+
if (resError) {
|
|
158
|
+
timer({
|
|
159
|
+
labels: {
|
|
160
|
+
status: 'failure',
|
|
161
|
+
},
|
|
162
|
+
});
|
|
91
163
|
|
|
92
|
-
if (outgoing.status === 'empty') {
|
|
93
164
|
this.#log.warn(
|
|
94
|
-
`
|
|
165
|
+
`remote resource responded with non 200 http status code for content - code: ${statusCode} - resource: ${outgoing.name} - url: ${outgoing.contentUri}`,
|
|
95
166
|
);
|
|
96
167
|
outgoing.success = true;
|
|
97
168
|
outgoing.pushFallback();
|
|
98
|
-
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const headers = {
|
|
103
|
-
...outgoing.reqOptions.headers,
|
|
104
|
-
'User-Agent': UA_STRING,
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
putils.serializeContext(headers, outgoing.context, outgoing.name);
|
|
108
|
-
|
|
109
|
-
const reqOptions = {
|
|
110
|
-
rejectUnauthorized: outgoing.rejectUnauthorized,
|
|
111
|
-
timeout: outgoing.timeout,
|
|
112
|
-
method: 'GET',
|
|
113
|
-
agent: outgoing.contentUri.startsWith('https://')
|
|
114
|
-
? this.#httpsAgent
|
|
115
|
-
: this.#httpAgent,
|
|
116
|
-
uri: putils.uriBuilder(
|
|
117
|
-
outgoing.reqOptions.pathname,
|
|
118
|
-
outgoing.contentUri,
|
|
119
|
-
),
|
|
120
|
-
qs: outgoing.reqOptions.query,
|
|
121
|
-
headers,
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
if (outgoing.redirectable) {
|
|
125
|
-
reqOptions.followRedirect = false;
|
|
169
|
+
return outgoing;
|
|
126
170
|
}
|
|
127
171
|
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
},
|
|
132
|
-
});
|
|
172
|
+
const contentVersion = utils.isHeaderDefined(hdrs, 'podlet-version')
|
|
173
|
+
? hdrs['podlet-version']
|
|
174
|
+
: undefined;
|
|
133
175
|
|
|
134
176
|
this.#log.debug(
|
|
135
|
-
`
|
|
177
|
+
`got head response from remote resource for content - header version is ${hdrs['podlet-version']} - resource: ${outgoing.name} - url: ${outgoing.contentUri}`,
|
|
136
178
|
);
|
|
137
179
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
},
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
this.#log.debug(
|
|
151
|
-
`remote resource responded with non 200 http status code for content - code: ${response.statusCode} - resource: ${outgoing.name} - url: ${outgoing.contentUri}`,
|
|
152
|
-
);
|
|
153
|
-
|
|
154
|
-
const errorMessage = `Could not read content. Resource responded with ${response.statusCode} on ${outgoing.contentUri}`;
|
|
155
|
-
|
|
156
|
-
const errorOptions = {
|
|
157
|
-
statusCode: response.statusCode,
|
|
158
|
-
decorate: {
|
|
159
|
-
statusCode: response.statusCode,
|
|
160
|
-
},
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
reject(new Boom(errorMessage, errorOptions));
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
if (resError) {
|
|
167
|
-
timer({
|
|
168
|
-
labels: {
|
|
169
|
-
status: 'failure',
|
|
170
|
-
},
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
this.#log.warn(
|
|
174
|
-
`remote resource responded with non 200 http status code for content - code: ${response.statusCode} - resource: ${outgoing.name} - url: ${outgoing.contentUri}`,
|
|
175
|
-
);
|
|
176
|
-
outgoing.success = true;
|
|
177
|
-
outgoing.pushFallback();
|
|
178
|
-
resolve(outgoing);
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const contentVersion = utils.isHeaderDefined(
|
|
183
|
-
response.headers,
|
|
184
|
-
'podlet-version',
|
|
185
|
-
)
|
|
186
|
-
? response.headers['podlet-version']
|
|
187
|
-
: undefined;
|
|
180
|
+
if (
|
|
181
|
+
contentVersion !== outgoing.manifest.version &&
|
|
182
|
+
contentVersion !== undefined
|
|
183
|
+
) {
|
|
184
|
+
timer({
|
|
185
|
+
labels: {
|
|
186
|
+
status: 'success',
|
|
187
|
+
},
|
|
188
|
+
});
|
|
188
189
|
|
|
189
|
-
this.#log.
|
|
190
|
-
`
|
|
190
|
+
this.#log.info(
|
|
191
|
+
`podlet version number in header differs from cached version number - aborting request to remote resource for content - resource: ${outgoing.name} - url: ${outgoing.contentUri}`,
|
|
191
192
|
);
|
|
193
|
+
// TODO r.abort();
|
|
194
|
+
outgoing.status = 'stale';
|
|
195
|
+
return outgoing;
|
|
196
|
+
}
|
|
192
197
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
contentVersion !== undefined
|
|
196
|
-
) {
|
|
197
|
-
timer({
|
|
198
|
-
labels: {
|
|
199
|
-
status: 'success',
|
|
200
|
-
},
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
this.#log.info(
|
|
204
|
-
`podlet version number in header differs from cached version number - aborting request to remote resource for content - resource: ${outgoing.name} - url: ${outgoing.contentUri}`,
|
|
205
|
-
);
|
|
206
|
-
r.abort();
|
|
207
|
-
outgoing.status = 'stale';
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
outgoing.success = true;
|
|
212
|
-
outgoing.headers = response.headers;
|
|
213
|
-
|
|
214
|
-
if (outgoing.redirectable && response.statusCode >= 300) {
|
|
215
|
-
outgoing.redirect = {
|
|
216
|
-
statusCode: response.statusCode,
|
|
217
|
-
location: response.headers && response.headers.location,
|
|
218
|
-
};
|
|
219
|
-
}
|
|
198
|
+
outgoing.success = true;
|
|
199
|
+
outgoing.headers = hdrs;
|
|
220
200
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
redirect: outgoing.redirect,
|
|
228
|
-
}),
|
|
229
|
-
);
|
|
201
|
+
if (outgoing.redirectable && statusCode >= 300) {
|
|
202
|
+
outgoing.redirect = {
|
|
203
|
+
statusCode,
|
|
204
|
+
location: hdrs && hdrs.location,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
230
207
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
208
|
+
outgoing.emit(
|
|
209
|
+
'beforeStream',
|
|
210
|
+
new Response({
|
|
211
|
+
headers: outgoing.headers,
|
|
212
|
+
js: outgoing.manifest.js,
|
|
213
|
+
css: outgoing.manifest.css,
|
|
214
|
+
redirect: outgoing.redirect,
|
|
215
|
+
}),
|
|
216
|
+
);
|
|
237
217
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
timer({
|
|
242
|
-
labels: {
|
|
243
|
-
status: 'failure',
|
|
244
|
-
},
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
this.#log.warn(
|
|
248
|
-
`could not create network connection to remote resource when trying to request content - resource: ${outgoing.name} - url: ${outgoing.contentUri}`,
|
|
249
|
-
);
|
|
250
|
-
reject(
|
|
251
|
-
badGateway(
|
|
252
|
-
`Error reading content at ${outgoing.contentUri}`,
|
|
253
|
-
error,
|
|
254
|
-
),
|
|
255
|
-
);
|
|
256
|
-
return;
|
|
218
|
+
pipeline([body, outgoing], (err) => {
|
|
219
|
+
if (err) {
|
|
220
|
+
this.#log.warn('error while piping content stream', err);
|
|
257
221
|
}
|
|
222
|
+
});
|
|
223
|
+
} catch (error) {
|
|
224
|
+
if (error.isBoom) throw error;
|
|
258
225
|
|
|
226
|
+
// Network error
|
|
227
|
+
if (outgoing.throwable) {
|
|
259
228
|
timer({
|
|
260
229
|
labels: {
|
|
261
230
|
status: 'failure',
|
|
@@ -265,30 +234,43 @@ export default class PodletClientContentResolver {
|
|
|
265
234
|
this.#log.warn(
|
|
266
235
|
`could not create network connection to remote resource when trying to request content - resource: ${outgoing.name} - url: ${outgoing.contentUri}`,
|
|
267
236
|
);
|
|
237
|
+
throw badGateway(
|
|
238
|
+
`Error reading content at ${outgoing.contentUri}`,
|
|
239
|
+
error,
|
|
240
|
+
);
|
|
241
|
+
}
|
|
268
242
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
243
|
+
timer({
|
|
244
|
+
labels: {
|
|
245
|
+
status: 'failure',
|
|
246
|
+
},
|
|
273
247
|
});
|
|
274
248
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
status: 'success',
|
|
279
|
-
},
|
|
280
|
-
});
|
|
249
|
+
this.#log.warn(
|
|
250
|
+
`could not create network connection to remote resource when trying to request content - resource: ${outgoing.name} - url: ${outgoing.contentUri}`,
|
|
251
|
+
);
|
|
281
252
|
|
|
282
|
-
|
|
283
|
-
`successfully read content from remote resource - resource: ${outgoing.name} - url: ${outgoing.contentUri}`,
|
|
284
|
-
);
|
|
253
|
+
outgoing.success = true;
|
|
285
254
|
|
|
286
|
-
|
|
287
|
-
|
|
255
|
+
outgoing.pushFallback();
|
|
256
|
+
|
|
257
|
+
return outgoing;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
timer({
|
|
261
|
+
labels: {
|
|
262
|
+
status: 'success',
|
|
263
|
+
},
|
|
288
264
|
});
|
|
265
|
+
|
|
266
|
+
this.#log.debug(
|
|
267
|
+
`successfully read content from remote resource - resource: ${outgoing.name} - url: ${outgoing.contentUri}`,
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
return outgoing;
|
|
289
271
|
}
|
|
290
272
|
|
|
291
273
|
get [Symbol.toStringTag]() {
|
|
292
274
|
return 'PodletClientContentResolver';
|
|
293
275
|
}
|
|
294
|
-
}
|
|
276
|
+
}
|
package/lib/resolver.fallback.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
/* eslint-disable no-param-reassign */
|
|
2
2
|
|
|
3
|
-
import request from 'request';
|
|
4
3
|
import abslog from 'abslog';
|
|
5
4
|
import Metrics from '@metrics/client';
|
|
6
|
-
|
|
7
5
|
import { join, dirname } from 'path';
|
|
8
6
|
import { fileURLToPath } from 'url';
|
|
9
7
|
import fs from 'fs';
|
|
8
|
+
import HTTP from './http.js';
|
|
10
9
|
|
|
11
10
|
const currentDirectory = dirname(fileURLToPath(import.meta.url));
|
|
12
11
|
|
|
13
|
-
const pkgJson = fs.readFileSync(
|
|
12
|
+
const pkgJson = fs.readFileSync(
|
|
13
|
+
join(currentDirectory, '../package.json'),
|
|
14
|
+
'utf-8',
|
|
15
|
+
);
|
|
14
16
|
const pkg = JSON.parse(pkgJson);
|
|
15
17
|
|
|
16
18
|
const UA_STRING = `${pkg.name} ${pkg.version}`;
|
|
@@ -19,14 +21,12 @@ export default class PodletClientFallbackResolver {
|
|
|
19
21
|
#log;
|
|
20
22
|
#metrics;
|
|
21
23
|
#histogram;
|
|
22
|
-
#
|
|
23
|
-
#httpsAgent;
|
|
24
|
+
#http;
|
|
24
25
|
constructor(options = {}) {
|
|
26
|
+
this.#http = options.http || new HTTP();
|
|
25
27
|
const name = options.clientName;
|
|
26
28
|
this.#log = abslog(options.logger);
|
|
27
29
|
this.#metrics = new Metrics();
|
|
28
|
-
this.#httpAgent = options.httpAgent;
|
|
29
|
-
this.#httpsAgent = options.httpsAgent;
|
|
30
30
|
this.#histogram = this.#metrics.histogram({
|
|
31
31
|
name: 'podium_client_resolver_fallback_resolve',
|
|
32
32
|
description: 'Time taken for success/failure of fallback request',
|
|
@@ -38,7 +38,7 @@ export default class PodletClientFallbackResolver {
|
|
|
38
38
|
buckets: [0.001, 0.01, 0.1, 0.5, 1, 2, 10],
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
this.#metrics.on('error', error => {
|
|
41
|
+
this.#metrics.on('error', (error) => {
|
|
42
42
|
this.#log.error(
|
|
43
43
|
'Error emitted by metric stream in @podium/client module',
|
|
44
44
|
error,
|
|
@@ -50,113 +50,103 @@ export default class PodletClientFallbackResolver {
|
|
|
50
50
|
return this.#metrics;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
resolve(outgoing) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
async resolve(outgoing) {
|
|
54
|
+
if (outgoing.status === 'cached') {
|
|
55
|
+
return outgoing;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Manifest has no fallback, fetching of manifest likely failed.
|
|
59
|
+
// Its not possible to fetch anything
|
|
60
|
+
// Do not set fallback so we can serve any previous fallback we might have
|
|
61
|
+
if (outgoing.manifest.fallback === undefined) {
|
|
62
|
+
return outgoing;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// If manifest fallback is empty, there is no fallback content to fetch
|
|
66
|
+
// Set fallback to empty string
|
|
67
|
+
if (outgoing.manifest.fallback === '') {
|
|
68
|
+
this.#log.debug(
|
|
69
|
+
`no fallback defined in manifest - resource: ${outgoing.name}`,
|
|
70
|
+
);
|
|
71
|
+
outgoing.fallback = '';
|
|
72
|
+
return outgoing;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// The manifest fallback holds a URI, fetch its content
|
|
76
|
+
const headers = {
|
|
77
|
+
'User-Agent': UA_STRING,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const reqOptions = {
|
|
81
|
+
rejectUnauthorized: outgoing.rejectUnauthorized,
|
|
82
|
+
timeout: outgoing.timeout,
|
|
83
|
+
method: 'GET',
|
|
84
|
+
headers,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const timer = this.#histogram.timer({
|
|
88
|
+
labels: {
|
|
89
|
+
podlet: outgoing.name,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
59
92
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
93
|
+
try {
|
|
94
|
+
this.#log.debug(
|
|
95
|
+
`start reading fallback content from remote resource - resource: ${outgoing.name} - url: ${outgoing.fallbackUri}`,
|
|
96
|
+
);
|
|
97
|
+
const { statusCode, body } = await this.#http.request(
|
|
98
|
+
outgoing.fallbackUri,
|
|
99
|
+
reqOptions,
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
// Remote responds but with an http error code
|
|
103
|
+
const resError = statusCode !== 200;
|
|
104
|
+
if (resError) {
|
|
105
|
+
timer({
|
|
106
|
+
labels: {
|
|
107
|
+
status: 'failure',
|
|
108
|
+
},
|
|
109
|
+
});
|
|
67
110
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (outgoing.manifest.fallback === '') {
|
|
71
|
-
this.#log.debug(
|
|
72
|
-
`no fallback defined in manifest - resource: ${outgoing.name}`,
|
|
111
|
+
this.#log.warn(
|
|
112
|
+
`remote resource responded with non 200 http status code for fallback content - code: ${statusCode} - resource: ${outgoing.name} - url: ${outgoing.fallbackUri}`,
|
|
73
113
|
);
|
|
114
|
+
|
|
74
115
|
outgoing.fallback = '';
|
|
75
|
-
|
|
76
|
-
return;
|
|
116
|
+
return outgoing;
|
|
77
117
|
}
|
|
78
118
|
|
|
79
|
-
//
|
|
80
|
-
|
|
81
|
-
'User-Agent': UA_STRING,
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
const reqOptions = {
|
|
85
|
-
rejectUnauthorized: outgoing.rejectUnauthorized,
|
|
86
|
-
timeout: outgoing.timeout,
|
|
87
|
-
method: 'GET',
|
|
88
|
-
agent: outgoing.fallbackUri.startsWith('https://')
|
|
89
|
-
? this.#httpsAgent
|
|
90
|
-
: this.#httpAgent,
|
|
91
|
-
uri: outgoing.fallbackUri,
|
|
92
|
-
headers,
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
const timer = this.#histogram.timer({
|
|
119
|
+
// Response is OK. Store response body as fallback html for caching
|
|
120
|
+
timer({
|
|
96
121
|
labels: {
|
|
97
|
-
|
|
122
|
+
status: 'success',
|
|
98
123
|
},
|
|
99
124
|
});
|
|
100
125
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
`start reading fallback content from remote resource - resource: ${outgoing.name} - url: ${outgoing.fallbackUri}`,
|
|
104
|
-
);
|
|
126
|
+
// Set fallback to the fetched content
|
|
127
|
+
outgoing.fallback = await body.text();
|
|
105
128
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
outgoing.fallback = '';
|
|
119
|
-
resolve(outgoing);
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Remote responds but with an http error code
|
|
124
|
-
const resError = res.statusCode !== 200;
|
|
125
|
-
if (resError) {
|
|
126
|
-
timer({
|
|
127
|
-
labels: {
|
|
128
|
-
status: 'failure',
|
|
129
|
-
},
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
this.#log.warn(
|
|
133
|
-
`remote resource responded with non 200 http status code for fallback content - code: ${res.statusCode} - resource: ${outgoing.name} - url: ${outgoing.fallbackUri}`,
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
outgoing.fallback = '';
|
|
137
|
-
resolve(outgoing);
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Response is OK. Store response body as fallback html for caching
|
|
142
|
-
timer({
|
|
143
|
-
labels: {
|
|
144
|
-
status: 'success',
|
|
145
|
-
},
|
|
146
|
-
});
|
|
129
|
+
this.#log.debug(
|
|
130
|
+
`successfully read fallback from remote resource - resource: ${outgoing.name} - url: ${outgoing.fallbackUri}`,
|
|
131
|
+
);
|
|
132
|
+
return outgoing;
|
|
133
|
+
} catch (error) {
|
|
134
|
+
timer({
|
|
135
|
+
labels: {
|
|
136
|
+
status: 'failure',
|
|
137
|
+
},
|
|
138
|
+
});
|
|
147
139
|
|
|
148
|
-
|
|
149
|
-
outgoing.
|
|
140
|
+
this.#log.warn(
|
|
141
|
+
`could not create network connection to remote resource for fallback content - resource: ${outgoing.name} - url: ${outgoing.fallbackUri}`,
|
|
142
|
+
);
|
|
150
143
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
resolve(outgoing);
|
|
155
|
-
});
|
|
156
|
-
});
|
|
144
|
+
outgoing.fallback = '';
|
|
145
|
+
return outgoing;
|
|
146
|
+
}
|
|
157
147
|
}
|
|
158
148
|
|
|
159
149
|
get [Symbol.toStringTag]() {
|
|
160
150
|
return 'PodletClientFallbackResolver';
|
|
161
151
|
}
|
|
162
|
-
}
|
|
152
|
+
}
|
package/lib/resolver.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Metrics from '@metrics/client';
|
|
2
2
|
import abslog from 'abslog';
|
|
3
3
|
import assert from 'assert';
|
|
4
|
+
import HTTP from './http.js';
|
|
4
5
|
import Manifest from './resolver.manifest.js';
|
|
5
6
|
import Fallback from './resolver.fallback.js';
|
|
6
7
|
import Content from './resolver.content.js';
|
|
@@ -19,10 +20,11 @@ export default class PodletClientResolver {
|
|
|
19
20
|
);
|
|
20
21
|
|
|
21
22
|
const log = abslog(options.logger);
|
|
23
|
+
const http = new HTTP();
|
|
22
24
|
this.#cache = new Cache(registry, options);
|
|
23
|
-
this.#manifest = new Manifest(options);
|
|
24
|
-
this.#fallback = new Fallback(options);
|
|
25
|
-
this.#content = new Content(options);
|
|
25
|
+
this.#manifest = new Manifest({ ...options, http });
|
|
26
|
+
this.#fallback = new Fallback({ ...options, http });
|
|
27
|
+
this.#content = new Content({ ...options, http });
|
|
26
28
|
this.#metrics = new Metrics();
|
|
27
29
|
|
|
28
30
|
this.#metrics.on('error', error => {
|
package/lib/resolver.manifest.js
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
/* eslint-disable no-param-reassign */
|
|
2
2
|
|
|
3
3
|
import CachePolicy from 'http-cache-semantics';
|
|
4
|
-
import {manifest as validateManifest } from'@podium/schemas';
|
|
5
|
-
import request from 'request';
|
|
4
|
+
import { manifest as validateManifest } from '@podium/schemas';
|
|
6
5
|
import Metrics from '@metrics/client';
|
|
7
6
|
import abslog from 'abslog';
|
|
8
7
|
import * as utils from '@podium/utils';
|
|
9
|
-
|
|
10
8
|
import { join, dirname } from 'path';
|
|
11
9
|
import { fileURLToPath } from 'url';
|
|
12
10
|
import fs from 'fs';
|
|
11
|
+
import HTTP from './http.js';
|
|
13
12
|
|
|
14
13
|
const currentDirectory = dirname(fileURLToPath(import.meta.url));
|
|
15
14
|
|
|
16
|
-
const pkgJson = fs.readFileSync(
|
|
15
|
+
const pkgJson = fs.readFileSync(
|
|
16
|
+
join(currentDirectory, '../package.json'),
|
|
17
|
+
'utf-8',
|
|
18
|
+
);
|
|
17
19
|
const pkg = JSON.parse(pkgJson);
|
|
18
20
|
|
|
19
21
|
const UA_STRING = `${pkg.name} ${pkg.version}`;
|
|
@@ -21,15 +23,13 @@ const UA_STRING = `${pkg.name} ${pkg.version}`;
|
|
|
21
23
|
export default class PodletClientManifestResolver {
|
|
22
24
|
#log;
|
|
23
25
|
#metrics;
|
|
24
|
-
#httpAgent;
|
|
25
|
-
#httpsAgent;
|
|
26
26
|
#histogram;
|
|
27
|
+
#http;
|
|
27
28
|
constructor(options = {}) {
|
|
29
|
+
this.#http = options.http || new HTTP();
|
|
28
30
|
const name = options.clientName;
|
|
29
31
|
this.#log = abslog(options.logger);
|
|
30
32
|
this.#metrics = new Metrics();
|
|
31
|
-
this.#httpAgent = options.httpAgent;
|
|
32
|
-
this.#httpsAgent = options.httpsAgent;
|
|
33
33
|
this.#histogram = this.#metrics.histogram({
|
|
34
34
|
name: 'podium_client_resolver_manifest_resolve',
|
|
35
35
|
description: 'Time taken for success/failure of manifest request',
|
|
@@ -41,7 +41,7 @@ export default class PodletClientManifestResolver {
|
|
|
41
41
|
buckets: [0.001, 0.01, 0.1, 0.5, 1, 2, 10],
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
this.#metrics.on('error', error => {
|
|
44
|
+
this.#metrics.on('error', (error) => {
|
|
45
45
|
this.#log.error(
|
|
46
46
|
'Error emitted by metric stream in @podium/client module',
|
|
47
47
|
error,
|
|
@@ -53,161 +53,154 @@ export default class PodletClientManifestResolver {
|
|
|
53
53
|
return this.#metrics;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
resolve(outgoing) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
56
|
+
async resolve(outgoing) {
|
|
57
|
+
if (outgoing.status === 'cached') {
|
|
58
|
+
return outgoing;
|
|
59
|
+
}
|
|
62
60
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
const headers = {
|
|
62
|
+
'User-Agent': UA_STRING,
|
|
63
|
+
};
|
|
66
64
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
json: true,
|
|
75
|
-
uri: outgoing.manifestUri,
|
|
76
|
-
headers,
|
|
77
|
-
};
|
|
65
|
+
const reqOptions = {
|
|
66
|
+
rejectUnauthorized: outgoing.rejectUnauthorized,
|
|
67
|
+
timeout: outgoing.timeout,
|
|
68
|
+
method: 'GET',
|
|
69
|
+
json: true,
|
|
70
|
+
headers,
|
|
71
|
+
};
|
|
78
72
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
73
|
+
const timer = this.#histogram.timer({
|
|
74
|
+
labels: {
|
|
75
|
+
podlet: outgoing.name,
|
|
76
|
+
},
|
|
77
|
+
});
|
|
84
78
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
);
|
|
79
|
+
this.#log.debug(
|
|
80
|
+
`start reading manifest from remote resource - resource: ${outgoing.name} - url: ${outgoing.manifestUri}`,
|
|
81
|
+
);
|
|
89
82
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
);
|
|
101
|
-
resolve(outgoing);
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Remote responds but with an http error code
|
|
106
|
-
const resError = res.statusCode !== 200;
|
|
107
|
-
if (resError) {
|
|
108
|
-
timer({
|
|
109
|
-
labels: {
|
|
110
|
-
status: 'failure',
|
|
111
|
-
},
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
this.#log.warn(
|
|
115
|
-
`remote resource responded with non 200 http status code for manifest - code: ${res.statusCode} - resource: ${outgoing.name} - url: ${outgoing.manifestUri}`,
|
|
116
|
-
);
|
|
117
|
-
resolve(outgoing);
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const manifest = validateManifest(body);
|
|
122
|
-
|
|
123
|
-
// Manifest validation error
|
|
124
|
-
if (manifest.error) {
|
|
125
|
-
timer({
|
|
126
|
-
labels: {
|
|
127
|
-
status: 'failure',
|
|
128
|
-
},
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
this.#log.warn(
|
|
132
|
-
`could not parse manifest - resource: ${outgoing.name} - url: ${outgoing.manifestUri}`,
|
|
133
|
-
);
|
|
134
|
-
resolve(outgoing);
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Manifest is valid, calculate maxAge for caching and continue
|
|
83
|
+
try {
|
|
84
|
+
const {
|
|
85
|
+
statusCode,
|
|
86
|
+
headers: hdrs,
|
|
87
|
+
body,
|
|
88
|
+
} = await this.#http.request(outgoing.manifestUri, reqOptions);
|
|
89
|
+
|
|
90
|
+
// Remote responds but with an http error code
|
|
91
|
+
const resError = statusCode !== 200;
|
|
92
|
+
if (resError) {
|
|
139
93
|
timer({
|
|
140
94
|
labels: {
|
|
141
|
-
status: '
|
|
95
|
+
status: 'failure',
|
|
142
96
|
},
|
|
143
97
|
});
|
|
144
98
|
|
|
145
|
-
|
|
146
|
-
status:
|
|
147
|
-
headers: res.headers,
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
const cachePolicy = new CachePolicy(reqOptions, resValues, {
|
|
151
|
-
ignoreCargoCult: true,
|
|
152
|
-
});
|
|
153
|
-
const maxAge = cachePolicy.timeToLive();
|
|
154
|
-
if (maxAge !== 0) {
|
|
155
|
-
this.#log.debug(
|
|
156
|
-
`remote resource has cache header which yelds a max age of ${maxAge}ms, using this as cache ttl - resource: ${outgoing.name} - url: ${outgoing.manifestUri}`,
|
|
157
|
-
);
|
|
158
|
-
outgoing.maxAge = maxAge;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Build absolute content and fallback URIs
|
|
162
|
-
if (manifest.value.fallback !== '') {
|
|
163
|
-
manifest.value.fallback = utils.uriRelativeToAbsolute(
|
|
164
|
-
manifest.value.fallback,
|
|
165
|
-
outgoing.manifestUri,
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
manifest.value.content = utils.uriRelativeToAbsolute(
|
|
170
|
-
manifest.value.content,
|
|
171
|
-
outgoing.manifestUri,
|
|
99
|
+
this.#log.warn(
|
|
100
|
+
`remote resource responded with non 200 http status code for manifest - code: ${statusCode} - resource: ${outgoing.name} - url: ${outgoing.manifestUri}`,
|
|
172
101
|
);
|
|
102
|
+
return outgoing;
|
|
103
|
+
}
|
|
173
104
|
|
|
174
|
-
|
|
175
|
-
manifest.value.css = manifest.value.css.map(obj => {
|
|
176
|
-
obj.value = utils.uriRelativeToAbsolute(
|
|
177
|
-
obj.value,
|
|
178
|
-
outgoing.manifestUri,
|
|
179
|
-
);
|
|
180
|
-
return new utils.AssetCss(obj);
|
|
181
|
-
});
|
|
105
|
+
const manifest = validateManifest(await body.json());
|
|
182
106
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
107
|
+
// Manifest validation error
|
|
108
|
+
if (manifest.error) {
|
|
109
|
+
timer({
|
|
110
|
+
labels: {
|
|
111
|
+
status: 'failure',
|
|
112
|
+
},
|
|
189
113
|
});
|
|
190
114
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
);
|
|
197
|
-
});
|
|
115
|
+
this.#log.warn(
|
|
116
|
+
`could not parse manifest - resource: ${outgoing.name} - url: ${outgoing.manifestUri}`,
|
|
117
|
+
);
|
|
118
|
+
return outgoing;
|
|
119
|
+
}
|
|
198
120
|
|
|
199
|
-
|
|
200
|
-
|
|
121
|
+
// Manifest is valid, calculate maxAge for caching and continue
|
|
122
|
+
timer({
|
|
123
|
+
labels: {
|
|
124
|
+
status: 'success',
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const resValues = {
|
|
129
|
+
status: statusCode,
|
|
130
|
+
headers: hdrs,
|
|
131
|
+
};
|
|
201
132
|
|
|
133
|
+
const cachePolicy = new CachePolicy(reqOptions, resValues, {
|
|
134
|
+
ignoreCargoCult: true,
|
|
135
|
+
});
|
|
136
|
+
const maxAge = cachePolicy.timeToLive();
|
|
137
|
+
if (maxAge !== 0) {
|
|
202
138
|
this.#log.debug(
|
|
203
|
-
`
|
|
139
|
+
`remote resource has cache header which yelds a max age of ${maxAge}ms, using this as cache ttl - resource: ${outgoing.name} - url: ${outgoing.manifestUri}`,
|
|
140
|
+
);
|
|
141
|
+
outgoing.maxAge = maxAge;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Build absolute content and fallback URIs
|
|
145
|
+
if (manifest.value.fallback !== '') {
|
|
146
|
+
manifest.value.fallback = utils.uriRelativeToAbsolute(
|
|
147
|
+
manifest.value.fallback,
|
|
148
|
+
outgoing.manifestUri,
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
manifest.value.content = utils.uriRelativeToAbsolute(
|
|
153
|
+
manifest.value.content,
|
|
154
|
+
outgoing.manifestUri,
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
// Construct css and js objects with absolute URIs
|
|
158
|
+
manifest.value.css = manifest.value.css.map((obj) => {
|
|
159
|
+
obj.value = utils.uriRelativeToAbsolute(
|
|
160
|
+
obj.value,
|
|
161
|
+
outgoing.manifestUri,
|
|
204
162
|
);
|
|
205
|
-
|
|
163
|
+
return new utils.AssetCss(obj);
|
|
206
164
|
});
|
|
207
|
-
|
|
165
|
+
|
|
166
|
+
manifest.value.js = manifest.value.js.map((obj) => {
|
|
167
|
+
obj.value = utils.uriRelativeToAbsolute(
|
|
168
|
+
obj.value,
|
|
169
|
+
outgoing.manifestUri,
|
|
170
|
+
);
|
|
171
|
+
return new utils.AssetJs(obj);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Build absolute proxy URIs
|
|
175
|
+
Object.keys(manifest.value.proxy).forEach((key) => {
|
|
176
|
+
manifest.value.proxy[key] = utils.uriRelativeToAbsolute(
|
|
177
|
+
manifest.value.proxy[key],
|
|
178
|
+
outgoing.manifestUri,
|
|
179
|
+
);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
outgoing.manifest = manifest.value;
|
|
183
|
+
outgoing.status = 'fresh';
|
|
184
|
+
|
|
185
|
+
this.#log.debug(
|
|
186
|
+
`successfully read manifest from remote resource - resource: ${outgoing.name} - url: ${outgoing.manifestUri}`,
|
|
187
|
+
);
|
|
188
|
+
return outgoing;
|
|
189
|
+
} catch (error) {
|
|
190
|
+
timer({
|
|
191
|
+
labels: {
|
|
192
|
+
status: 'failure',
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
this.#log.warn(
|
|
197
|
+
`could not create network connection to remote manifest - resource: ${outgoing.name} - url: ${outgoing.manifestUri}`,
|
|
198
|
+
);
|
|
199
|
+
return outgoing;
|
|
200
|
+
}
|
|
208
201
|
}
|
|
209
202
|
|
|
210
203
|
get [Symbol.toStringTag]() {
|
|
211
204
|
return 'PodletClientManifestResolver';
|
|
212
205
|
}
|
|
213
|
-
}
|
|
206
|
+
}
|
package/lib/resource.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/* eslint-disable no-param-reassign */
|
|
2
2
|
|
|
3
3
|
import Metrics from '@metrics/client';
|
|
4
|
-
import stream from 'stream';
|
|
5
4
|
import abslog from 'abslog';
|
|
6
5
|
import assert from 'assert';
|
|
7
6
|
|
|
@@ -63,22 +62,16 @@ export default class PodiumClientResource {
|
|
|
63
62
|
|
|
64
63
|
this.#state.setInitializingState();
|
|
65
64
|
|
|
66
|
-
const chunks = [];
|
|
67
|
-
const to = new stream.Writable({
|
|
68
|
-
write: (chunk, encoding, next) => {
|
|
69
|
-
chunks.push(chunk);
|
|
70
|
-
next();
|
|
71
|
-
},
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
stream.pipeline([outgoing, to], () => {
|
|
75
|
-
// noop
|
|
76
|
-
});
|
|
77
|
-
|
|
78
65
|
const { manifest, headers, redirect } = await this.#resolver.resolve(
|
|
79
66
|
outgoing,
|
|
80
67
|
);
|
|
81
68
|
|
|
69
|
+
const chunks = [];
|
|
70
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
71
|
+
for await (const chunk of outgoing) {
|
|
72
|
+
chunks.push(chunk)
|
|
73
|
+
}
|
|
74
|
+
|
|
82
75
|
const content = !outgoing.redirect
|
|
83
76
|
? Buffer.concat(chunks).toString()
|
|
84
77
|
: '';
|
package/lib/response.js
CHANGED
|
@@ -60,15 +60,11 @@ export default class PodiumClientResponse {
|
|
|
60
60
|
|
|
61
61
|
[inspect]() {
|
|
62
62
|
return {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
async: this.async,
|
|
69
|
-
defer: this.defer,
|
|
70
|
-
type: this.type,
|
|
71
|
-
data: this.data,
|
|
63
|
+
redirect: this.redirect,
|
|
64
|
+
content: this.content,
|
|
65
|
+
headers: this.headers,
|
|
66
|
+
css: this.css,
|
|
67
|
+
js: this.js,
|
|
72
68
|
};
|
|
73
69
|
}
|
|
74
70
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@podium/client",
|
|
3
|
-
"version": "5.0.0-next.
|
|
3
|
+
"version": "5.0.0-next.12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"abslog": "2.4.0",
|
|
43
43
|
"http-cache-semantics": "^4.0.3",
|
|
44
44
|
"lodash.clonedeep": "^4.5.0",
|
|
45
|
-
"
|
|
46
|
-
"
|
|
45
|
+
"ttl-mem-cache": "4.1.0",
|
|
46
|
+
"undici": "^5.10.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@podium/test-utils": "2.5.2",
|