@florianpat/lando-core 3.23.22 → 3.23.27-1florianPat.0
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 +23 -1
- package/app.js +2 -0
- package/builders/_lando.js +19 -6
- package/builders/lando-v4.js +3 -0
- package/config.yml +4 -4
- package/hooks/app-run-events.js +22 -0
- package/hooks/lando-setup-build-engine-darwin.js +3 -0
- package/hooks/lando-setup-build-engine-win32.js +2 -0
- package/hooks/lando-setup-build-engine-wsl.js +2 -0
- package/hooks/lando-setup-orchestrator.js +2 -2
- package/lib/daemon.js +1 -1
- package/lib/updates.js +9 -1
- package/netlify.toml +1 -0
- package/node_modules/undici/docs/docs/api/Dispatcher.md +51 -0
- package/node_modules/undici/index.js +2 -1
- package/node_modules/undici/lib/api/api-request.js +1 -1
- package/node_modules/undici/lib/core/connect.js +5 -0
- package/node_modules/undici/lib/dispatcher/client-h2.js +20 -6
- package/node_modules/undici/lib/handler/retry-handler.js +3 -3
- package/node_modules/undici/lib/interceptor/dns.js +375 -0
- package/node_modules/undici/lib/web/cache/cache.js +1 -0
- package/node_modules/undici/lib/web/cache/cachestorage.js +2 -0
- package/node_modules/undici/lib/web/eventsource/eventsource.js +2 -0
- package/node_modules/undici/lib/web/fetch/body.js +9 -1
- package/node_modules/undici/lib/web/fetch/formdata.js +2 -0
- package/node_modules/undici/lib/web/fetch/headers.js +2 -0
- package/node_modules/undici/lib/web/fetch/index.js +1 -1
- package/node_modules/undici/lib/web/fetch/request.js +1 -0
- package/node_modules/undici/lib/web/fetch/response.js +1 -0
- package/node_modules/undici/lib/web/fetch/webidl.js +2 -0
- package/node_modules/undici/lib/web/websocket/events.js +4 -0
- package/node_modules/undici/lib/web/websocket/websocket.js +2 -0
- package/node_modules/undici/package.json +1 -1
- package/node_modules/undici/types/interceptors.d.ts +14 -0
- package/node_modules/undici/types/retry-handler.d.ts +1 -1
- package/node_modules/undici/types/webidl.d.ts +6 -0
- package/package.json +6 -6
- package/release-aliases/3-EDGE +1 -1
- package/release-aliases/3-STABLE +1 -1
- package/scripts/install-docker-desktop.sh +1 -1
- package/scripts/install-docker-engine.sh +1 -1
- package/scripts/lando-entrypoint.sh +1 -1
- package/utils/get-compose-x.js +1 -1
- package/utils/get-config-defaults.js +5 -5
- package/utils/to-lando-container.js +16 -2
- package/checksums.txt +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
## {{ UNRELEASED_VERSION }} - [{{ UNRELEASED_DATE }}]({{ UNRELEASED_LINK }})
|
|
2
2
|
|
|
3
|
-
## v3.23.
|
|
3
|
+
## v3.23.27-1florianPat.0 - [February 17, 2025](https://github.com/florianPat/lando-core/releases/tag/v3.23.27-1florianPat.0)
|
|
4
|
+
|
|
5
|
+
## v3.23.26 - [January 24, 2025](https://github.com/lando/core/releases/tag/v3.23.26)
|
|
6
|
+
|
|
7
|
+
* Fixed bug where an app’s services were inadvertently reaped if the app’s path included a comma [#322](https://github.com/lando/core/issues/322)
|
|
8
|
+
|
|
9
|
+
## v3.23.25 - [January 18, 2025](https://github.com/lando/core/releases/tag/v3.23.25)
|
|
10
|
+
|
|
11
|
+
* Fixed bug causing `--accept-license` flag to not work when installing Docker Desktop on macOS
|
|
12
|
+
* Updated default Docker Desktop version to `4.37.1|2`
|
|
13
|
+
* Updated default Docker Engine version to `27.5.0`
|
|
14
|
+
* Updated default Docker Compose version to `2.31.0`
|
|
15
|
+
* Updated recommended Docker Desktop range to `>=4.37.0`
|
|
16
|
+
* Updated tested Docker Desktop range to `<=4.37`
|
|
17
|
+
* Updated tested Docker Compose range to `<=2.32`
|
|
18
|
+
|
|
19
|
+
## v3.23.24 - [January 14, 2025](https://github.com/lando/core/releases/tag/v3.23.24)
|
|
20
|
+
|
|
21
|
+
* Fixed bug causing service script moving to fail when receiving non-stringy inputs
|
|
22
|
+
|
|
23
|
+
## v3.23.23 - [January 14, 2025](https://github.com/lando/core/releases/tag/v3.23.23)
|
|
24
|
+
|
|
25
|
+
* Fixed bug causing service script loading collisions
|
|
4
26
|
|
|
5
27
|
## v3.23.22 - [December 17, 2024](https://github.com/lando/core/releases/tag/v3.23.22)
|
|
6
28
|
|
package/app.js
CHANGED
|
@@ -240,6 +240,8 @@ module.exports = async (app, lando) => {
|
|
|
240
240
|
BITNAMI_DEBUG: 'true',
|
|
241
241
|
},
|
|
242
242
|
labels: {
|
|
243
|
+
'io.lando.landofiles': app.configFiles.map(file => path.basename(file)).join(','),
|
|
244
|
+
'io.lando.root': app.root,
|
|
243
245
|
'io.lando.src': app.configFiles.join(','),
|
|
244
246
|
'io.lando.http-ports': '80,443',
|
|
245
247
|
},
|
package/builders/_lando.js
CHANGED
|
@@ -41,6 +41,7 @@ module.exports = {
|
|
|
41
41
|
refreshCerts = false,
|
|
42
42
|
remoteFiles = {},
|
|
43
43
|
scripts = [],
|
|
44
|
+
scriptsDir = false,
|
|
44
45
|
sport = '443',
|
|
45
46
|
ssl = false,
|
|
46
47
|
sslExpose = true,
|
|
@@ -68,16 +69,25 @@ module.exports = {
|
|
|
68
69
|
console.error(color.yellow(`${type} version ${version} is a legacy version! We recommend upgrading.`));
|
|
69
70
|
}
|
|
70
71
|
|
|
72
|
+
// normalize scripts dir if needed
|
|
73
|
+
if (typeof scriptsDir === 'string' && !path.isAbsolute(scriptsDir)) scriptsDir = path.resolve(root, scriptsDir);
|
|
74
|
+
|
|
75
|
+
// Get some basic locations
|
|
76
|
+
const globalScriptsDir = path.join(userConfRoot, 'scripts');
|
|
77
|
+
const serviceScriptsDir = path.join(userConfRoot, 'helpers', project, type, name);
|
|
78
|
+
const entrypointScript = path.join(globalScriptsDir, 'lando-entrypoint.sh');
|
|
79
|
+
const addCertsScript = path.join(globalScriptsDir, 'add-cert.sh');
|
|
80
|
+
const refreshCertsScript = path.join(globalScriptsDir, 'refresh-certs.sh');
|
|
81
|
+
|
|
71
82
|
// Move our config into the userconfroot if we have some
|
|
72
83
|
// NOTE: we need to do this because on macOS and Windows not all host files
|
|
73
84
|
// are shared into the docker vm
|
|
74
85
|
if (fs.existsSync(confSrc)) require('../utils/move-config')(confSrc, confDest);
|
|
75
86
|
|
|
76
|
-
//
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const refreshCertsScript = path.join(scriptsDir, 'refresh-certs.sh');
|
|
87
|
+
// ditto for service helpers
|
|
88
|
+
if (!require('../utils/is-disabled')(scriptsDir) && typeof scriptsDir === 'string' && fs.existsSync(scriptsDir)) {
|
|
89
|
+
require('../utils/move-config')(scriptsDir, serviceScriptsDir);
|
|
90
|
+
}
|
|
81
91
|
|
|
82
92
|
// Handle Environment
|
|
83
93
|
const environment = {
|
|
@@ -100,10 +110,13 @@ module.exports = {
|
|
|
100
110
|
// Handle volumes
|
|
101
111
|
const volumes = [
|
|
102
112
|
`${userConfRoot}:/lando:cached`,
|
|
103
|
-
`${
|
|
113
|
+
`${globalScriptsDir}:/helpers`,
|
|
104
114
|
`${entrypointScript}:/lando-entrypoint.sh`,
|
|
105
115
|
];
|
|
106
116
|
|
|
117
|
+
// add in service helpers if we have them
|
|
118
|
+
if (fs.existsSync(serviceScriptsDir)) volumes.push(`${serviceScriptsDir}:/etc/lando/service/helpers`);
|
|
119
|
+
|
|
107
120
|
// Handle ssl
|
|
108
121
|
if (ssl) {
|
|
109
122
|
// also expose the sport
|
package/builders/lando-v4.js
CHANGED
|
@@ -443,7 +443,10 @@ module.exports = {
|
|
|
443
443
|
const labels = merge({}, app.labels, {
|
|
444
444
|
'dev.lando.container': 'TRUE',
|
|
445
445
|
'dev.lando.id': lando.config.id,
|
|
446
|
+
'dev.lando.landofiles': app.configFiles.map(file => path.basename(file)).join(','),
|
|
447
|
+
'dev.lando.root': app.root,
|
|
446
448
|
'dev.lando.src': app.root,
|
|
449
|
+
'io.lando.http-ports': '80,443',
|
|
447
450
|
}, config.labels);
|
|
448
451
|
|
|
449
452
|
// add it all 2getha
|
package/config.yml
CHANGED
|
@@ -13,21 +13,21 @@ dockerSupportedVersions:
|
|
|
13
13
|
compose:
|
|
14
14
|
satisfies: "1.x.x || 2.x.x"
|
|
15
15
|
recommendUpdate: "<=2.24.6"
|
|
16
|
-
tested: "<=2.
|
|
16
|
+
tested: "<=2.32.99"
|
|
17
17
|
link:
|
|
18
18
|
linux: https://docs.docker.com/compose/install/#install-compose-on-linux-systems
|
|
19
19
|
darwin: https://docs.docker.com/desktop/install/mac-install/
|
|
20
20
|
win32: https://docs.docker.com/desktop/install/windows-install/
|
|
21
21
|
desktop:
|
|
22
22
|
satisfies: ">=4.0.0 <5"
|
|
23
|
-
tested: "<=4.
|
|
24
|
-
recommendUpdate: "<=4.
|
|
23
|
+
tested: "<=4.37.99"
|
|
24
|
+
recommendUpdate: "<=4.36"
|
|
25
25
|
link:
|
|
26
26
|
darwin: https://docs.docker.com/desktop/install/mac-install/
|
|
27
27
|
win32: https://docs.docker.com/desktop/install/windows-install/
|
|
28
28
|
wsl: https://docs.docker.com/desktop/install/windows-install/
|
|
29
29
|
engine:
|
|
30
30
|
satisfies: ">=18 <28"
|
|
31
|
-
tested: "<=27.
|
|
31
|
+
tested: "<=27.5.99"
|
|
32
32
|
link:
|
|
33
33
|
linux: https://docs.docker.com/engine/install/debian/#install-using-the-convenience-script
|
package/hooks/app-run-events.js
CHANGED
|
@@ -7,6 +7,28 @@ const formatters = require('../lib/formatters');
|
|
|
7
7
|
|
|
8
8
|
module.exports = async (app, lando, cmds, data, event) => {
|
|
9
9
|
const eventCommands = require('./../utils/parse-events-config')(cmds, app, data, lando);
|
|
10
|
+
// add perm sweeping to all v3 services
|
|
11
|
+
if (!_.isEmpty(eventCommands)) {
|
|
12
|
+
const permsweepers = _(eventCommands)
|
|
13
|
+
.filter(command => command.api === 3)
|
|
14
|
+
.map(command => ({id: command.id, services: _.get(command, 'opts.services', [])}))
|
|
15
|
+
.uniqBy('id')
|
|
16
|
+
.value();
|
|
17
|
+
lando.log.debug('added preemptive perm sweeping to evented v3 services %j', permsweepers.map(s => s.id));
|
|
18
|
+
_.forEach(permsweepers, ({id, services}) => {
|
|
19
|
+
eventCommands.unshift({
|
|
20
|
+
id,
|
|
21
|
+
cmd: '/helpers/user-perms.sh --silent',
|
|
22
|
+
compose: app.compose,
|
|
23
|
+
project: app.project,
|
|
24
|
+
opts: {
|
|
25
|
+
mode: 'attach',
|
|
26
|
+
user: 'root',
|
|
27
|
+
services,
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
}
|
|
10
32
|
const injectable = _.has(app, 'engine') ? app : lando;
|
|
11
33
|
|
|
12
34
|
const splitEventCommands = [];
|
|
@@ -7,7 +7,7 @@ const path = require('path');
|
|
|
7
7
|
/*
|
|
8
8
|
* Helper to get docker compose v2 download url
|
|
9
9
|
*/
|
|
10
|
-
const getComposeDownloadUrl = (version = '2.
|
|
10
|
+
const getComposeDownloadUrl = (version = '2.31.0') => {
|
|
11
11
|
const mv = version.split('.')[0] > 1 ? '2' : '1';
|
|
12
12
|
const arch = process.arch === 'arm64' ? 'aarch64' : 'x86_64';
|
|
13
13
|
const toggle = `${process.platform}-${mv}`;
|
|
@@ -31,7 +31,7 @@ const getComposeDownloadUrl = (version = '2.30.3') => {
|
|
|
31
31
|
/*
|
|
32
32
|
* Helper to get docker compose v2 download destination
|
|
33
33
|
*/
|
|
34
|
-
const getComposeDownloadDest = (base, version = '2.
|
|
34
|
+
const getComposeDownloadDest = (base, version = '2.31.0') => {
|
|
35
35
|
switch (process.platform) {
|
|
36
36
|
case 'linux':
|
|
37
37
|
case 'darwin':
|
package/lib/daemon.js
CHANGED
|
@@ -53,7 +53,7 @@ module.exports = class LandoDaemon {
|
|
|
53
53
|
log = new Log(),
|
|
54
54
|
context = 'node',
|
|
55
55
|
compose = require('../utils/get-compose-x')(),
|
|
56
|
-
orchestratorVersion = '2.
|
|
56
|
+
orchestratorVersion = '2.31.0',
|
|
57
57
|
userConfRoot = path.join(os.homedir(), '.lando'),
|
|
58
58
|
) {
|
|
59
59
|
this.cache = cache;
|
package/lib/updates.js
CHANGED
|
@@ -127,7 +127,15 @@ module.exports = class UpdateManager {
|
|
|
127
127
|
const {data, status, url} = await octokit.rest.repos.listReleases({owner: 'lando', repo: 'core'});
|
|
128
128
|
this.debug('retrieved cli information from %o [%o]', url, status);
|
|
129
129
|
|
|
130
|
-
const
|
|
130
|
+
const corePlugin = await this.plugins.find(plugin => plugin.core);
|
|
131
|
+
if (undefined === corePlugin) {
|
|
132
|
+
throw new Error('We should find a core!');
|
|
133
|
+
}
|
|
134
|
+
let newestCoreVersion = corePlugin.check4Update()?.update?.version ?? corePlugin.version;
|
|
135
|
+
if (undefined === newestCoreVersion) {
|
|
136
|
+
throw new Error('Could not obtain the next lando core version!');
|
|
137
|
+
}
|
|
138
|
+
newestCoreVersion = semver.clean(newestCoreVersion);
|
|
131
139
|
|
|
132
140
|
const versions = data
|
|
133
141
|
.map(release => ({...release, version: semver.clean(release.tag_name)}))
|
package/netlify.toml
CHANGED
|
@@ -986,6 +986,57 @@ client.dispatch(
|
|
|
986
986
|
);
|
|
987
987
|
```
|
|
988
988
|
|
|
989
|
+
##### `dns`
|
|
990
|
+
|
|
991
|
+
The `dns` interceptor enables you to cache DNS lookups for a given duration, per origin.
|
|
992
|
+
|
|
993
|
+
>It is well suited for scenarios where you want to cache DNS lookups to avoid the overhead of resolving the same domain multiple times
|
|
994
|
+
|
|
995
|
+
**Options**
|
|
996
|
+
- `maxTTL` - The maximum time-to-live (in milliseconds) of the DNS cache. It should be a positive integer. Default: `10000`.
|
|
997
|
+
- Set `0` to disable TTL.
|
|
998
|
+
- `maxItems` - The maximum number of items to cache. It should be a positive integer. Default: `Infinity`.
|
|
999
|
+
- `dualStack` - Whether to resolve both IPv4 and IPv6 addresses. Default: `true`.
|
|
1000
|
+
- It will also attempt a happy-eyeballs-like approach to connect to the available addresses in case of a connection failure.
|
|
1001
|
+
- `affinity` - Whether to use IPv4 or IPv6 addresses. Default: `4`.
|
|
1002
|
+
- It can be either `'4` or `6`.
|
|
1003
|
+
- It will only take effect if `dualStack` is `false`.
|
|
1004
|
+
- `lookup: (hostname: string, options: LookupOptions, callback: (err: NodeJS.ErrnoException | null, addresses: DNSInterceptorRecord[]) => void) => void` - Custom lookup function. Default: `dns.lookup`.
|
|
1005
|
+
- For more info see [dns.lookup](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback).
|
|
1006
|
+
- `pick: (origin: URL, records: DNSInterceptorRecords, affinity: 4 | 6) => DNSInterceptorRecord` - Custom pick function. Default: `RoundRobin`.
|
|
1007
|
+
- The function should return a single record from the records array.
|
|
1008
|
+
- By default a simplified version of Round Robin is used.
|
|
1009
|
+
- The `records` property can be mutated to store the state of the balancing algorithm.
|
|
1010
|
+
|
|
1011
|
+
> The `Dispatcher#options` also gets extended with the options `dns.affinity`, `dns.dualStack`, `dns.lookup` and `dns.pick` which can be used to configure the interceptor at a request-per-request basis.
|
|
1012
|
+
|
|
1013
|
+
|
|
1014
|
+
**DNSInterceptorRecord**
|
|
1015
|
+
It represents a DNS record.
|
|
1016
|
+
- `family` - (`number`) The IP family of the address. It can be either `4` or `6`.
|
|
1017
|
+
- `address` - (`string`) The IP address.
|
|
1018
|
+
|
|
1019
|
+
**DNSInterceptorOriginRecords**
|
|
1020
|
+
It represents a map of DNS IP addresses records for a single origin.
|
|
1021
|
+
- `4.ips` - (`DNSInterceptorRecord[] | null`) The IPv4 addresses.
|
|
1022
|
+
- `6.ips` - (`DNSInterceptorRecord[] | null`) The IPv6 addresses.
|
|
1023
|
+
|
|
1024
|
+
**Example - Basic DNS Interceptor**
|
|
1025
|
+
|
|
1026
|
+
```js
|
|
1027
|
+
const { Client, interceptors } = require("undici");
|
|
1028
|
+
const { dns } = interceptors;
|
|
1029
|
+
|
|
1030
|
+
const client = new Agent().compose([
|
|
1031
|
+
dns({ ...opts })
|
|
1032
|
+
])
|
|
1033
|
+
|
|
1034
|
+
const response = await client.request({
|
|
1035
|
+
origin: `http://localhost:3030`,
|
|
1036
|
+
...requestOpts
|
|
1037
|
+
})
|
|
1038
|
+
```
|
|
1039
|
+
|
|
989
1040
|
##### `Response Error Interceptor`
|
|
990
1041
|
|
|
991
1042
|
**Introduction**
|
|
@@ -41,7 +41,8 @@ module.exports.createRedirectInterceptor = createRedirectInterceptor
|
|
|
41
41
|
module.exports.interceptors = {
|
|
42
42
|
redirect: require('./lib/interceptor/redirect'),
|
|
43
43
|
retry: require('./lib/interceptor/retry'),
|
|
44
|
-
dump: require('./lib/interceptor/dump')
|
|
44
|
+
dump: require('./lib/interceptor/dump'),
|
|
45
|
+
dns: require('./lib/interceptor/dns')
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
module.exports.buildConnector = buildConnector
|
|
@@ -73,7 +73,7 @@ class RequestHandler extends AsyncResource {
|
|
|
73
73
|
this.removeAbortListener = util.addAbortListener(this.signal, () => {
|
|
74
74
|
this.reason = this.signal.reason ?? new RequestAbortedError()
|
|
75
75
|
if (this.res) {
|
|
76
|
-
util.destroy(this.res, this.reason)
|
|
76
|
+
util.destroy(this.res.on('error', util.nop), this.reason)
|
|
77
77
|
} else if (this.abort) {
|
|
78
78
|
this.abort(this.reason)
|
|
79
79
|
}
|
|
@@ -220,6 +220,11 @@ const setupConnectTimeout = process.platform === 'win32'
|
|
|
220
220
|
* @param {number} opts.port
|
|
221
221
|
*/
|
|
222
222
|
function onConnectTimeout (socket, opts) {
|
|
223
|
+
// The socket could be already garbage collected
|
|
224
|
+
if (socket == null) {
|
|
225
|
+
return
|
|
226
|
+
}
|
|
227
|
+
|
|
223
228
|
let message = 'Connect Timeout Error'
|
|
224
229
|
if (Array.isArray(socket.autoSelectFamilyAttemptedAddresses)) {
|
|
225
230
|
message += ` (attempted addresses: ${socket.autoSelectFamilyAttemptedAddresses.join(', ')},`
|
|
@@ -31,6 +31,8 @@ const {
|
|
|
31
31
|
|
|
32
32
|
const kOpenStreams = Symbol('open streams')
|
|
33
33
|
|
|
34
|
+
let extractBody
|
|
35
|
+
|
|
34
36
|
// Experimental
|
|
35
37
|
let h2ExperimentalWarned = false
|
|
36
38
|
|
|
@@ -240,11 +242,12 @@ function onHTTP2GoAway (code) {
|
|
|
240
242
|
util.destroy(this[kSocket], err)
|
|
241
243
|
|
|
242
244
|
// Fail head of pipeline.
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
245
|
+
if (client[kRunningIdx] < client[kQueue].length) {
|
|
246
|
+
const request = client[kQueue][client[kRunningIdx]]
|
|
247
|
+
client[kQueue][client[kRunningIdx]++] = null
|
|
248
|
+
util.errorRequest(client, request, err)
|
|
249
|
+
client[kPendingIdx] = client[kRunningIdx]
|
|
250
|
+
}
|
|
248
251
|
|
|
249
252
|
assert(client[kRunning] === 0)
|
|
250
253
|
|
|
@@ -260,7 +263,8 @@ function shouldSendContentLength (method) {
|
|
|
260
263
|
|
|
261
264
|
function writeH2 (client, request) {
|
|
262
265
|
const session = client[kHTTP2Session]
|
|
263
|
-
const {
|
|
266
|
+
const { method, path, host, upgrade, expectContinue, signal, headers: reqHeaders } = request
|
|
267
|
+
let { body } = request
|
|
264
268
|
|
|
265
269
|
if (upgrade) {
|
|
266
270
|
util.errorRequest(client, request, new Error('Upgrade not supported for H2'))
|
|
@@ -381,6 +385,16 @@ function writeH2 (client, request) {
|
|
|
381
385
|
|
|
382
386
|
let contentLength = util.bodyLength(body)
|
|
383
387
|
|
|
388
|
+
if (util.isFormDataLike(body)) {
|
|
389
|
+
extractBody ??= require('../web/fetch/body.js').extractBody
|
|
390
|
+
|
|
391
|
+
const [bodyStream, contentType] = extractBody(body)
|
|
392
|
+
headers['content-type'] = contentType
|
|
393
|
+
|
|
394
|
+
body = bodyStream.stream
|
|
395
|
+
contentLength = bodyStream.length
|
|
396
|
+
}
|
|
397
|
+
|
|
384
398
|
if (contentLength == null) {
|
|
385
399
|
contentLength = request.contentLength
|
|
386
400
|
}
|
|
@@ -229,7 +229,7 @@ class RetryHandler {
|
|
|
229
229
|
return false
|
|
230
230
|
}
|
|
231
231
|
|
|
232
|
-
const { start, size, end = size } = contentRange
|
|
232
|
+
const { start, size, end = size - 1 } = contentRange
|
|
233
233
|
|
|
234
234
|
assert(this.start === start, 'content-range mismatch')
|
|
235
235
|
assert(this.end == null || this.end === end, 'content-range mismatch')
|
|
@@ -252,7 +252,7 @@ class RetryHandler {
|
|
|
252
252
|
)
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
-
const { start, size, end = size } = range
|
|
255
|
+
const { start, size, end = size - 1 } = range
|
|
256
256
|
assert(
|
|
257
257
|
start != null && Number.isFinite(start),
|
|
258
258
|
'content-range mismatch'
|
|
@@ -266,7 +266,7 @@ class RetryHandler {
|
|
|
266
266
|
// We make our best to checkpoint the body for further range headers
|
|
267
267
|
if (this.end == null) {
|
|
268
268
|
const contentLength = headers['content-length']
|
|
269
|
-
this.end = contentLength != null ? Number(contentLength) : null
|
|
269
|
+
this.end = contentLength != null ? Number(contentLength) - 1 : null
|
|
270
270
|
}
|
|
271
271
|
|
|
272
272
|
assert(Number.isFinite(this.start))
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
const { isIP } = require('node:net')
|
|
3
|
+
const { lookup } = require('node:dns')
|
|
4
|
+
const DecoratorHandler = require('../handler/decorator-handler')
|
|
5
|
+
const { InvalidArgumentError, InformationalError } = require('../core/errors')
|
|
6
|
+
const maxInt = Math.pow(2, 31) - 1
|
|
7
|
+
|
|
8
|
+
class DNSInstance {
|
|
9
|
+
#maxTTL = 0
|
|
10
|
+
#maxItems = 0
|
|
11
|
+
#records = new Map()
|
|
12
|
+
dualStack = true
|
|
13
|
+
affinity = null
|
|
14
|
+
lookup = null
|
|
15
|
+
pick = null
|
|
16
|
+
|
|
17
|
+
constructor (opts) {
|
|
18
|
+
this.#maxTTL = opts.maxTTL
|
|
19
|
+
this.#maxItems = opts.maxItems
|
|
20
|
+
this.dualStack = opts.dualStack
|
|
21
|
+
this.affinity = opts.affinity
|
|
22
|
+
this.lookup = opts.lookup ?? this.#defaultLookup
|
|
23
|
+
this.pick = opts.pick ?? this.#defaultPick
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
get full () {
|
|
27
|
+
return this.#records.size === this.#maxItems
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
runLookup (origin, opts, cb) {
|
|
31
|
+
const ips = this.#records.get(origin.hostname)
|
|
32
|
+
|
|
33
|
+
// If full, we just return the origin
|
|
34
|
+
if (ips == null && this.full) {
|
|
35
|
+
cb(null, origin.origin)
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const newOpts = {
|
|
40
|
+
affinity: this.affinity,
|
|
41
|
+
dualStack: this.dualStack,
|
|
42
|
+
lookup: this.lookup,
|
|
43
|
+
pick: this.pick,
|
|
44
|
+
...opts.dns,
|
|
45
|
+
maxTTL: this.#maxTTL,
|
|
46
|
+
maxItems: this.#maxItems
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// If no IPs we lookup
|
|
50
|
+
if (ips == null) {
|
|
51
|
+
this.lookup(origin, newOpts, (err, addresses) => {
|
|
52
|
+
if (err || addresses == null || addresses.length === 0) {
|
|
53
|
+
cb(err ?? new InformationalError('No DNS entries found'))
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
this.setRecords(origin, addresses)
|
|
58
|
+
const records = this.#records.get(origin.hostname)
|
|
59
|
+
|
|
60
|
+
const ip = this.pick(
|
|
61
|
+
origin,
|
|
62
|
+
records,
|
|
63
|
+
newOpts.affinity
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
let port
|
|
67
|
+
if (typeof ip.port === 'number') {
|
|
68
|
+
port = `:${ip.port}`
|
|
69
|
+
} else if (origin.port !== '') {
|
|
70
|
+
port = `:${origin.port}`
|
|
71
|
+
} else {
|
|
72
|
+
port = ''
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
cb(
|
|
76
|
+
null,
|
|
77
|
+
`${origin.protocol}//${
|
|
78
|
+
ip.family === 6 ? `[${ip.address}]` : ip.address
|
|
79
|
+
}${port}`
|
|
80
|
+
)
|
|
81
|
+
})
|
|
82
|
+
} else {
|
|
83
|
+
// If there's IPs we pick
|
|
84
|
+
const ip = this.pick(
|
|
85
|
+
origin,
|
|
86
|
+
ips,
|
|
87
|
+
newOpts.affinity
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
// If no IPs we lookup - deleting old records
|
|
91
|
+
if (ip == null) {
|
|
92
|
+
this.#records.delete(origin.hostname)
|
|
93
|
+
this.runLookup(origin, opts, cb)
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let port
|
|
98
|
+
if (typeof ip.port === 'number') {
|
|
99
|
+
port = `:${ip.port}`
|
|
100
|
+
} else if (origin.port !== '') {
|
|
101
|
+
port = `:${origin.port}`
|
|
102
|
+
} else {
|
|
103
|
+
port = ''
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
cb(
|
|
107
|
+
null,
|
|
108
|
+
`${origin.protocol}//${
|
|
109
|
+
ip.family === 6 ? `[${ip.address}]` : ip.address
|
|
110
|
+
}${port}`
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
#defaultLookup (origin, opts, cb) {
|
|
116
|
+
lookup(
|
|
117
|
+
origin.hostname,
|
|
118
|
+
{
|
|
119
|
+
all: true,
|
|
120
|
+
family: this.dualStack === false ? this.affinity : 0,
|
|
121
|
+
order: 'ipv4first'
|
|
122
|
+
},
|
|
123
|
+
(err, addresses) => {
|
|
124
|
+
if (err) {
|
|
125
|
+
return cb(err)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const results = new Map()
|
|
129
|
+
|
|
130
|
+
for (const addr of addresses) {
|
|
131
|
+
// On linux we found duplicates, we attempt to remove them with
|
|
132
|
+
// the latest record
|
|
133
|
+
results.set(`${addr.address}:${addr.family}`, addr)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
cb(null, results.values())
|
|
137
|
+
}
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
#defaultPick (origin, hostnameRecords, affinity) {
|
|
142
|
+
let ip = null
|
|
143
|
+
const { records, offset } = hostnameRecords
|
|
144
|
+
|
|
145
|
+
let family
|
|
146
|
+
if (this.dualStack) {
|
|
147
|
+
if (affinity == null) {
|
|
148
|
+
// Balance between ip families
|
|
149
|
+
if (offset == null || offset === maxInt) {
|
|
150
|
+
hostnameRecords.offset = 0
|
|
151
|
+
affinity = 4
|
|
152
|
+
} else {
|
|
153
|
+
hostnameRecords.offset++
|
|
154
|
+
affinity = (hostnameRecords.offset & 1) === 1 ? 6 : 4
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (records[affinity] != null && records[affinity].ips.length > 0) {
|
|
159
|
+
family = records[affinity]
|
|
160
|
+
} else {
|
|
161
|
+
family = records[affinity === 4 ? 6 : 4]
|
|
162
|
+
}
|
|
163
|
+
} else {
|
|
164
|
+
family = records[affinity]
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// If no IPs we return null
|
|
168
|
+
if (family == null || family.ips.length === 0) {
|
|
169
|
+
return ip
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (family.offset == null || family.offset === maxInt) {
|
|
173
|
+
family.offset = 0
|
|
174
|
+
} else {
|
|
175
|
+
family.offset++
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const position = family.offset % family.ips.length
|
|
179
|
+
ip = family.ips[position] ?? null
|
|
180
|
+
|
|
181
|
+
if (ip == null) {
|
|
182
|
+
return ip
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (Date.now() - ip.timestamp > ip.ttl) { // record TTL is already in ms
|
|
186
|
+
// We delete expired records
|
|
187
|
+
// It is possible that they have different TTL, so we manage them individually
|
|
188
|
+
family.ips.splice(position, 1)
|
|
189
|
+
return this.pick(origin, hostnameRecords, affinity)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return ip
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
setRecords (origin, addresses) {
|
|
196
|
+
const timestamp = Date.now()
|
|
197
|
+
const records = { records: { 4: null, 6: null } }
|
|
198
|
+
for (const record of addresses) {
|
|
199
|
+
record.timestamp = timestamp
|
|
200
|
+
if (typeof record.ttl === 'number') {
|
|
201
|
+
// The record TTL is expected to be in ms
|
|
202
|
+
record.ttl = Math.min(record.ttl, this.#maxTTL)
|
|
203
|
+
} else {
|
|
204
|
+
record.ttl = this.#maxTTL
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const familyRecords = records.records[record.family] ?? { ips: [] }
|
|
208
|
+
|
|
209
|
+
familyRecords.ips.push(record)
|
|
210
|
+
records.records[record.family] = familyRecords
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
this.#records.set(origin.hostname, records)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
getHandler (meta, opts) {
|
|
217
|
+
return new DNSDispatchHandler(this, meta, opts)
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
class DNSDispatchHandler extends DecoratorHandler {
|
|
222
|
+
#state = null
|
|
223
|
+
#opts = null
|
|
224
|
+
#dispatch = null
|
|
225
|
+
#handler = null
|
|
226
|
+
#origin = null
|
|
227
|
+
|
|
228
|
+
constructor (state, { origin, handler, dispatch }, opts) {
|
|
229
|
+
super(handler)
|
|
230
|
+
this.#origin = origin
|
|
231
|
+
this.#handler = handler
|
|
232
|
+
this.#opts = { ...opts }
|
|
233
|
+
this.#state = state
|
|
234
|
+
this.#dispatch = dispatch
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
onError (err) {
|
|
238
|
+
switch (err.code) {
|
|
239
|
+
case 'ETIMEDOUT':
|
|
240
|
+
case 'ECONNREFUSED': {
|
|
241
|
+
if (this.#state.dualStack) {
|
|
242
|
+
// We delete the record and retry
|
|
243
|
+
this.#state.runLookup(this.#origin, this.#opts, (err, newOrigin) => {
|
|
244
|
+
if (err) {
|
|
245
|
+
return this.#handler.onError(err)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const dispatchOpts = {
|
|
249
|
+
...this.#opts,
|
|
250
|
+
origin: newOrigin
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
this.#dispatch(dispatchOpts, this)
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
// if dual-stack disabled, we error out
|
|
257
|
+
return
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
this.#handler.onError(err)
|
|
261
|
+
return
|
|
262
|
+
}
|
|
263
|
+
case 'ENOTFOUND':
|
|
264
|
+
this.#state.deleteRecord(this.#origin)
|
|
265
|
+
// eslint-disable-next-line no-fallthrough
|
|
266
|
+
default:
|
|
267
|
+
this.#handler.onError(err)
|
|
268
|
+
break
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
module.exports = interceptorOpts => {
|
|
274
|
+
if (
|
|
275
|
+
interceptorOpts?.maxTTL != null &&
|
|
276
|
+
(typeof interceptorOpts?.maxTTL !== 'number' || interceptorOpts?.maxTTL < 0)
|
|
277
|
+
) {
|
|
278
|
+
throw new InvalidArgumentError('Invalid maxTTL. Must be a positive number')
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (
|
|
282
|
+
interceptorOpts?.maxItems != null &&
|
|
283
|
+
(typeof interceptorOpts?.maxItems !== 'number' ||
|
|
284
|
+
interceptorOpts?.maxItems < 1)
|
|
285
|
+
) {
|
|
286
|
+
throw new InvalidArgumentError(
|
|
287
|
+
'Invalid maxItems. Must be a positive number and greater than zero'
|
|
288
|
+
)
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (
|
|
292
|
+
interceptorOpts?.affinity != null &&
|
|
293
|
+
interceptorOpts?.affinity !== 4 &&
|
|
294
|
+
interceptorOpts?.affinity !== 6
|
|
295
|
+
) {
|
|
296
|
+
throw new InvalidArgumentError('Invalid affinity. Must be either 4 or 6')
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (
|
|
300
|
+
interceptorOpts?.dualStack != null &&
|
|
301
|
+
typeof interceptorOpts?.dualStack !== 'boolean'
|
|
302
|
+
) {
|
|
303
|
+
throw new InvalidArgumentError('Invalid dualStack. Must be a boolean')
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (
|
|
307
|
+
interceptorOpts?.lookup != null &&
|
|
308
|
+
typeof interceptorOpts?.lookup !== 'function'
|
|
309
|
+
) {
|
|
310
|
+
throw new InvalidArgumentError('Invalid lookup. Must be a function')
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (
|
|
314
|
+
interceptorOpts?.pick != null &&
|
|
315
|
+
typeof interceptorOpts?.pick !== 'function'
|
|
316
|
+
) {
|
|
317
|
+
throw new InvalidArgumentError('Invalid pick. Must be a function')
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const dualStack = interceptorOpts?.dualStack ?? true
|
|
321
|
+
let affinity
|
|
322
|
+
if (dualStack) {
|
|
323
|
+
affinity = interceptorOpts?.affinity ?? null
|
|
324
|
+
} else {
|
|
325
|
+
affinity = interceptorOpts?.affinity ?? 4
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const opts = {
|
|
329
|
+
maxTTL: interceptorOpts?.maxTTL ?? 10e3, // Expressed in ms
|
|
330
|
+
lookup: interceptorOpts?.lookup ?? null,
|
|
331
|
+
pick: interceptorOpts?.pick ?? null,
|
|
332
|
+
dualStack,
|
|
333
|
+
affinity,
|
|
334
|
+
maxItems: interceptorOpts?.maxItems ?? Infinity
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const instance = new DNSInstance(opts)
|
|
338
|
+
|
|
339
|
+
return dispatch => {
|
|
340
|
+
return function dnsInterceptor (origDispatchOpts, handler) {
|
|
341
|
+
const origin =
|
|
342
|
+
origDispatchOpts.origin.constructor === URL
|
|
343
|
+
? origDispatchOpts.origin
|
|
344
|
+
: new URL(origDispatchOpts.origin)
|
|
345
|
+
|
|
346
|
+
if (isIP(origin.hostname) !== 0) {
|
|
347
|
+
return dispatch(origDispatchOpts, handler)
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
instance.runLookup(origin, origDispatchOpts, (err, newOrigin) => {
|
|
351
|
+
if (err) {
|
|
352
|
+
return handler.onError(err)
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
let dispatchOpts = null
|
|
356
|
+
dispatchOpts = {
|
|
357
|
+
...origDispatchOpts,
|
|
358
|
+
servername: origin.hostname, // For SNI on TLS
|
|
359
|
+
origin: newOrigin,
|
|
360
|
+
headers: {
|
|
361
|
+
host: origin.hostname,
|
|
362
|
+
...origDispatchOpts.headers
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
dispatch(
|
|
367
|
+
dispatchOpts,
|
|
368
|
+
instance.getHandler({ origin, dispatch, handler }, origDispatchOpts)
|
|
369
|
+
)
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
return true
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
@@ -20,6 +20,14 @@ const { isErrored, isDisturbed } = require('node:stream')
|
|
|
20
20
|
const { isArrayBuffer } = require('node:util/types')
|
|
21
21
|
const { serializeAMimeType } = require('./data-url')
|
|
22
22
|
const { multipartFormDataParser } = require('./formdata-parser')
|
|
23
|
+
let random
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const crypto = require('node:crypto')
|
|
27
|
+
random = (max) => crypto.randomInt(0, max)
|
|
28
|
+
} catch {
|
|
29
|
+
random = (max) => Math.floor(Math.random(max))
|
|
30
|
+
}
|
|
23
31
|
|
|
24
32
|
const textEncoder = new TextEncoder()
|
|
25
33
|
function noop () {}
|
|
@@ -113,7 +121,7 @@ function extractBody (object, keepalive = false) {
|
|
|
113
121
|
// Set source to a copy of the bytes held by object.
|
|
114
122
|
source = new Uint8Array(object.buffer.slice(object.byteOffset, object.byteOffset + object.byteLength))
|
|
115
123
|
} else if (util.isFormDataLike(object)) {
|
|
116
|
-
const boundary = `----formdata-undici-0${`${
|
|
124
|
+
const boundary = `----formdata-undici-0${`${random(1e11)}`.padStart(11, '0')}`
|
|
117
125
|
const prefix = `--${boundary}\r\nContent-Disposition: form-data`
|
|
118
126
|
|
|
119
127
|
/*! formdata-polyfill. MIT License. Jimmy Wärting <https://jimmy.warting.se/opensource> */
|
|
@@ -14,6 +14,8 @@ const File = globalThis.File ?? NativeFile
|
|
|
14
14
|
// https://xhr.spec.whatwg.org/#formdata
|
|
15
15
|
class FormData {
|
|
16
16
|
constructor (form) {
|
|
17
|
+
webidl.util.markAsUncloneable(this)
|
|
18
|
+
|
|
17
19
|
if (form !== undefined) {
|
|
18
20
|
throw webidl.errors.conversionFailed({
|
|
19
21
|
prefix: 'FormData constructor',
|
|
@@ -2137,7 +2137,7 @@ async function httpNetworkFetch (
|
|
|
2137
2137
|
|
|
2138
2138
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding
|
|
2139
2139
|
if (codings.length !== 0 && request.method !== 'HEAD' && request.method !== 'CONNECT' && !nullBodyStatus.includes(status) && !willFollow) {
|
|
2140
|
-
for (let i =
|
|
2140
|
+
for (let i = codings.length - 1; i >= 0; --i) {
|
|
2141
2141
|
const coding = codings[i]
|
|
2142
2142
|
// https://www.rfc-editor.org/rfc/rfc9112.html#section-7.2
|
|
2143
2143
|
if (coding === 'x-gzip' || coding === 'gzip') {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { types, inspect } = require('node:util')
|
|
4
|
+
const { markAsUncloneable } = require('node:worker_threads')
|
|
4
5
|
const { toUSVString } = require('../../core/util')
|
|
5
6
|
|
|
6
7
|
/** @type {import('../../../types/webidl').Webidl} */
|
|
@@ -86,6 +87,7 @@ webidl.util.Type = function (V) {
|
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
89
|
|
|
90
|
+
webidl.util.markAsUncloneable = markAsUncloneable || (() => {})
|
|
89
91
|
// https://webidl.spec.whatwg.org/#abstract-opdef-converttoint
|
|
90
92
|
webidl.util.ConvertToInt = function (V, bitLength, signedness, opts) {
|
|
91
93
|
let upperBound
|
|
@@ -14,6 +14,7 @@ class MessageEvent extends Event {
|
|
|
14
14
|
constructor (type, eventInitDict = {}) {
|
|
15
15
|
if (type === kConstruct) {
|
|
16
16
|
super(arguments[1], arguments[2])
|
|
17
|
+
webidl.util.markAsUncloneable(this)
|
|
17
18
|
return
|
|
18
19
|
}
|
|
19
20
|
|
|
@@ -26,6 +27,7 @@ class MessageEvent extends Event {
|
|
|
26
27
|
super(type, eventInitDict)
|
|
27
28
|
|
|
28
29
|
this.#eventInit = eventInitDict
|
|
30
|
+
webidl.util.markAsUncloneable(this)
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
get data () {
|
|
@@ -112,6 +114,7 @@ class CloseEvent extends Event {
|
|
|
112
114
|
super(type, eventInitDict)
|
|
113
115
|
|
|
114
116
|
this.#eventInit = eventInitDict
|
|
117
|
+
webidl.util.markAsUncloneable(this)
|
|
115
118
|
}
|
|
116
119
|
|
|
117
120
|
get wasClean () {
|
|
@@ -142,6 +145,7 @@ class ErrorEvent extends Event {
|
|
|
142
145
|
webidl.argumentLengthCheck(arguments, 1, prefix)
|
|
143
146
|
|
|
144
147
|
super(type, eventInitDict)
|
|
148
|
+
webidl.util.markAsUncloneable(this)
|
|
145
149
|
|
|
146
150
|
type = webidl.converters.DOMString(type, prefix, 'type')
|
|
147
151
|
eventInitDict = webidl.converters.ErrorEventInit(eventInitDict ?? {})
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { LookupOptions } from 'node:dns'
|
|
2
|
+
|
|
1
3
|
import Dispatcher from "./dispatcher";
|
|
2
4
|
import RetryHandler from "./retry-handler";
|
|
3
5
|
|
|
@@ -9,6 +11,18 @@ declare namespace Interceptors {
|
|
|
9
11
|
export type RedirectInterceptorOpts = { maxRedirections?: number }
|
|
10
12
|
export type ResponseErrorInterceptorOpts = { throwOnError: boolean }
|
|
11
13
|
|
|
14
|
+
// DNS interceptor
|
|
15
|
+
export type DNSInterceptorRecord = { address: string, ttl: number, family: 4 | 6 }
|
|
16
|
+
export type DNSInterceptorOriginRecords = { 4: { ips: DNSInterceptorRecord[] } | null, 6: { ips: DNSInterceptorRecord[] } | null }
|
|
17
|
+
export type DNSInterceptorOpts = {
|
|
18
|
+
maxTTL?: number
|
|
19
|
+
maxItems?: number
|
|
20
|
+
lookup?: (hostname: string, options: LookupOptions, callback: (err: NodeJS.ErrnoException | null, addresses: DNSInterceptorRecord[]) => void) => void
|
|
21
|
+
pick?: (origin: URL, records: DNSInterceptorOriginRecords, affinity: 4 | 6) => DNSInterceptorRecord
|
|
22
|
+
dualStack?: boolean
|
|
23
|
+
affinity?: 4 | 6
|
|
24
|
+
}
|
|
25
|
+
|
|
12
26
|
export function createRedirectInterceptor(opts: RedirectInterceptorOpts): Dispatcher.DispatcherComposeInterceptor
|
|
13
27
|
export function dump(opts?: DumpInterceptorOpts): Dispatcher.DispatcherComposeInterceptor
|
|
14
28
|
export function retry(opts?: RetryInterceptorOpts): Dispatcher.DispatcherComposeInterceptor
|
|
@@ -67,6 +67,12 @@ interface WebidlUtil {
|
|
|
67
67
|
* Stringifies {@param V}
|
|
68
68
|
*/
|
|
69
69
|
Stringify (V: any): string
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Mark a value as uncloneable for Node.js.
|
|
73
|
+
* This is only effective in some newer Node.js versions.
|
|
74
|
+
*/
|
|
75
|
+
markAsUncloneable (V: any): void
|
|
70
76
|
}
|
|
71
77
|
|
|
72
78
|
interface WebidlConverters {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@florianpat/lando-core",
|
|
3
3
|
"description": "The libraries that power all of Lando. Fork by flo for compose integration",
|
|
4
|
-
"version": "3.23.
|
|
4
|
+
"version": "3.23.27-1florianPat.0",
|
|
5
5
|
"author": "Florian Patruck @florianPat",
|
|
6
6
|
"license": "GPL-3.0",
|
|
7
7
|
"repository": "florianPat/lando-core",
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
"devDependencies": {
|
|
169
169
|
"@babel/eslint-parser": "^7.16.0",
|
|
170
170
|
"@lando/leia": "^1.0.0-beta.4",
|
|
171
|
-
"@lando/vitepress-theme-default-plus": "
|
|
171
|
+
"@lando/vitepress-theme-default-plus": "^1.1.1",
|
|
172
172
|
"@yao-pkg/pkg": "^5.16.1",
|
|
173
173
|
"chai": "^4.3.4",
|
|
174
174
|
"chai-as-promised": "^7.1.1",
|
|
@@ -247,9 +247,9 @@
|
|
|
247
247
|
"yargs-parser"
|
|
248
248
|
],
|
|
249
249
|
"dist": {
|
|
250
|
-
"integrity": "sha512-
|
|
251
|
-
"shasum": "
|
|
252
|
-
"filename": "florianpat-lando-core-3.23.
|
|
253
|
-
"unpackedSize":
|
|
250
|
+
"integrity": "sha512-EF8oq87DSgrav9p/64DkDyDuudJ/hW3soeFWiiuZzhjIIZ52UV98g6DGiIjVVyowcVtuAL6sAf/cidZkv7s+tQ==",
|
|
251
|
+
"shasum": "7fa58d190ddcacde2bb53ede9fffc5d92c0bb42c",
|
|
252
|
+
"filename": "florianpat-lando-core-3.23.27-1florianPat.0.tgz",
|
|
253
|
+
"unpackedSize": 60965868
|
|
254
254
|
}
|
|
255
255
|
}
|
package/release-aliases/3-EDGE
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
v3.24.0-beta.
|
|
1
|
+
v3.24.0-beta.12
|
package/release-aliases/3-STABLE
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
v3.23.
|
|
1
|
+
v3.23.26
|
|
@@ -59,7 +59,7 @@ debug "INSTALLER: $INSTALLER"
|
|
|
59
59
|
debug "USER: $USER"
|
|
60
60
|
|
|
61
61
|
# add accept license if set
|
|
62
|
-
if [ "${
|
|
62
|
+
if [ "${ACCEPT_LICENSE}" == 1 ]; then OPTS="$OPTS --accept-license"; fi
|
|
63
63
|
|
|
64
64
|
# run
|
|
65
65
|
hdiutil attach "$INSTALLER"
|
|
@@ -62,7 +62,7 @@ if [ -d "/scripts" ] && [ -z ${LANDO_NO_SCRIPTS+x} ]; then
|
|
|
62
62
|
|
|
63
63
|
# Keep this for backwards compat and fallback opts
|
|
64
64
|
chmod +x /scripts/* || true
|
|
65
|
-
find /scripts/ -type f -name "*.sh" -exec {} \;
|
|
65
|
+
find /scripts/ -type f \( -name "*.sh" -o ! -name "*.*" \) -exec {} \;
|
|
66
66
|
fi;
|
|
67
67
|
|
|
68
68
|
# Run any bash scripts that we've loaded into the mix for autorun unless we've
|
package/utils/get-compose-x.js
CHANGED
|
@@ -27,7 +27,7 @@ const getDockerBin = (bin, base, pathFallback = true) => {
|
|
|
27
27
|
}
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
-
module.exports = ({orchestratorVersion = '2.
|
|
30
|
+
module.exports = ({orchestratorVersion = '2.31.0', userConfRoot = os.tmpdir()} = {}) => {
|
|
31
31
|
const orchestratorBin = `docker-compose-v${orchestratorVersion}`;
|
|
32
32
|
switch (process.platform) {
|
|
33
33
|
case 'darwin':
|
|
@@ -8,20 +8,20 @@ const os = require('os');
|
|
|
8
8
|
const getBuildEngineVersion = (platform = process.landoPlatform ?? process.platform) => {
|
|
9
9
|
switch (platform) {
|
|
10
10
|
case 'darwin':
|
|
11
|
-
return '4.
|
|
11
|
+
return '4.37.2';
|
|
12
12
|
case 'linux':
|
|
13
|
-
return '27.
|
|
13
|
+
return '27.5.0';
|
|
14
14
|
case 'win32':
|
|
15
|
-
return '4.
|
|
15
|
+
return '4.37.1';
|
|
16
16
|
case 'wsl':
|
|
17
|
-
return '4.
|
|
17
|
+
return '4.37.1';
|
|
18
18
|
}
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
// Default config
|
|
22
22
|
const defaultConfig = options => ({
|
|
23
23
|
orchestratorSeparator: '_',
|
|
24
|
-
orchestratorVersion: '2.
|
|
24
|
+
orchestratorVersion: '2.31.0',
|
|
25
25
|
configSources: [],
|
|
26
26
|
coreBase: path.resolve(__dirname, '..'),
|
|
27
27
|
disablePlugins: [],
|
|
@@ -1,22 +1,36 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
module.exports = ({Labels, Id, Status}, separator = '_', src = []) => {
|
|
4
6
|
// Get name of docker container.
|
|
5
7
|
const app = Labels['com.docker.compose.project'];
|
|
6
8
|
const service = Labels['com.docker.compose.service'];
|
|
7
9
|
const num = Labels['com.docker.compose.container-number'];
|
|
8
10
|
const lando = Labels['io.lando.container'];
|
|
9
11
|
const special = Labels['io.lando.service-container'];
|
|
12
|
+
|
|
13
|
+
// if we have io.lando.root and io.lando.
|
|
14
|
+
if (Labels['io.lando.root'] && Labels['io.lando.landofiles']) {
|
|
15
|
+
src = Labels['io.lando.landofiles'].split(',').map(landofile => path.join(Labels['io.lando.root'], landofile));
|
|
16
|
+
|
|
17
|
+
// or legacy support for Labels['io.lando.src']
|
|
18
|
+
} else if (Labels['io.lando.src']) {
|
|
19
|
+
src = Labels['io.lando.src'].split(',');
|
|
20
|
+
|
|
21
|
+
// or its just unknown
|
|
22
|
+
} else src = 'unknown';
|
|
23
|
+
|
|
10
24
|
// Build generic container.
|
|
11
25
|
return {
|
|
12
26
|
id: Id,
|
|
13
27
|
service: service,
|
|
14
28
|
name: [app, service, num].join(separator),
|
|
15
29
|
app: (special !== 'TRUE') ? app : '_global_',
|
|
16
|
-
src: (Labels['io.lando.src']) ? Labels['io.lando.src'].split(',') : 'unknown',
|
|
17
30
|
kind: (special !== 'TRUE') ? 'app' : 'service',
|
|
18
31
|
lando: (lando === 'TRUE') ? true : false,
|
|
19
32
|
instance: Labels['io.lando.id'] || 'unknown',
|
|
20
33
|
status: Status,
|
|
34
|
+
src,
|
|
21
35
|
};
|
|
22
36
|
};
|
package/checksums.txt
DELETED
|
File without changes
|