containerify 3.0.0 → 3.0.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/lib/cli.js +5 -2
- package/lib/registry.d.ts +1 -2
- package/lib/registry.js +165 -163
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +1 -1
package/lib/cli.js
CHANGED
|
@@ -235,7 +235,7 @@ function run(options) {
|
|
|
235
235
|
const todir = yield (0, fileutil_1.ensureEmptyDir)(path.join(tmpdir, "to"));
|
|
236
236
|
const allowInsecure = options.allowInsecureRegistries ? types_1.InsecureRegistrySupport.YES : types_1.InsecureRegistrySupport.NO;
|
|
237
237
|
const fromRegistryUrl = (_a = options.fromRegistry) !== null && _a !== void 0 ? _a : registry_1.DEFAULT_DOCKER_REGISTRY;
|
|
238
|
-
const fromRegistry = (0, registry_1.createRegistry)(fromRegistryUrl,
|
|
238
|
+
const fromRegistry = yield (0, registry_1.createRegistry)(fromRegistryUrl, options.fromImage, allowInsecure, options.fromToken);
|
|
239
239
|
const originalManifest = yield fromRegistry.download(options.fromImage, fromdir, (0, utils_1.getPreferredPlatform)(options.platform), options.layerCacheFolder);
|
|
240
240
|
yield appLayerCreator_1.default.addLayers(tmpdir, fromdir, todir, options);
|
|
241
241
|
if (options.toDocker) {
|
|
@@ -250,7 +250,10 @@ function run(options) {
|
|
|
250
250
|
yield tarExporter_1.default.saveToTar(todir, tmpdir, options.toTar, [options.toImage], options);
|
|
251
251
|
}
|
|
252
252
|
if (options.toRegistry) {
|
|
253
|
-
|
|
253
|
+
if (!options.token && allowInsecure == types_1.InsecureRegistrySupport.NO) {
|
|
254
|
+
throw new Error("Need auth token to upload to " + options.toRegistry);
|
|
255
|
+
}
|
|
256
|
+
const toRegistry = yield (0, registry_1.createRegistry)(options.toRegistry, options.toImage, allowInsecure, options.toToken, options.optimisticToRegistryCheck);
|
|
254
257
|
yield toRegistry.upload(options.toImage, todir, options.doCrossMount, originalManifest, options.fromImage);
|
|
255
258
|
}
|
|
256
259
|
logger_1.default.debug("Deleting " + tmpdir + " ...");
|
package/lib/registry.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { InsecureRegistrySupport, Registry } from "./types";
|
|
2
|
-
export declare function
|
|
3
|
-
export declare function createRegistry(registryBaseUrl: string, auth: string, allowInsecure: InsecureRegistrySupport, optimisticToRegistryCheck?: boolean): Registry;
|
|
2
|
+
export declare function createRegistry(registryBaseUrl: string, imagePath: string, allowInsecure: InsecureRegistrySupport, auth?: string, optimisticToRegistryCheck?: boolean): Promise<Registry>;
|
|
4
3
|
export declare const DEFAULT_DOCKER_REGISTRY = "https://registry-1.docker.io/v2/";
|
|
5
4
|
export declare function parseFullImageUrl(imageStr: string): {
|
|
6
5
|
registry: string;
|
package/lib/registry.js
CHANGED
|
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.parseFullImageUrl = exports.DEFAULT_DOCKER_REGISTRY = exports.createRegistry =
|
|
12
|
+
exports.parseFullImageUrl = exports.DEFAULT_DOCKER_REGISTRY = exports.createRegistry = void 0;
|
|
13
13
|
const URL = require("url");
|
|
14
14
|
const fss = require("fs");
|
|
15
15
|
const fs_1 = require("fs");
|
|
@@ -140,7 +140,7 @@ function processToken(registryBaseUrl, allowInsecure, imagePath, token) {
|
|
|
140
140
|
return `Bearer ${resp.token}`;
|
|
141
141
|
}
|
|
142
142
|
if (!token)
|
|
143
|
-
|
|
143
|
+
return ""; //We allow to pull from tokenless registries
|
|
144
144
|
if (token.startsWith("Basic "))
|
|
145
145
|
return token;
|
|
146
146
|
if (token.startsWith("ghp_"))
|
|
@@ -148,181 +148,183 @@ function processToken(registryBaseUrl, allowInsecure, imagePath, token) {
|
|
|
148
148
|
return "Bearer " + token;
|
|
149
149
|
});
|
|
150
150
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
return
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
if (location
|
|
180
|
-
|
|
151
|
+
function createRegistry(registryBaseUrl, imagePath, allowInsecure, auth, optimisticToRegistryCheck = false) {
|
|
152
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
153
|
+
const token = yield processToken(registryBaseUrl, allowInsecure, imagePath, auth);
|
|
154
|
+
function exists(image, layer) {
|
|
155
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
156
|
+
const url = `${registryBaseUrl}${image.path}/blobs/${layer.digest}`;
|
|
157
|
+
return yield checkIfLayerExists(url, (0, httpRequest_1.buildHeaders)(layer.mediaType, token), allowInsecure, optimisticToRegistryCheck, 0);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
function uploadLayerContent(uploadUrl, layer, dir) {
|
|
161
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
162
|
+
logger_1.default.info(layer.digest);
|
|
163
|
+
const file = path.join(dir, (0, utils_1.getHash)(layer.digest) + (0, utils_1.getLayerTypeFileEnding)(layer));
|
|
164
|
+
yield uploadContent(uploadUrl, file, layer, allowInsecure, token);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
function getUploadUrl(image, mountParameters = undefined) {
|
|
168
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
169
|
+
return new Promise((resolve, reject) => {
|
|
170
|
+
const parameters = new URLSearchParams(mountParameters);
|
|
171
|
+
const url = `${registryBaseUrl}${image.path}/blobs/uploads/${parameters.size > 0 ? "?" + parameters : ""}`;
|
|
172
|
+
const options = URL.parse(url);
|
|
173
|
+
options.method = "POST";
|
|
174
|
+
options.headers = { authorization: auth };
|
|
175
|
+
(0, httpRequest_1.request)(options, allowInsecure, (res) => {
|
|
176
|
+
logger_1.default.debug("POST", `${url}`, res.statusCode);
|
|
177
|
+
if (res.statusCode == 202) {
|
|
178
|
+
const { location } = res.headers;
|
|
179
|
+
if (location) {
|
|
180
|
+
if (location.startsWith("http")) {
|
|
181
|
+
resolve({ uploadUrl: location });
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
const regURL = URL.parse(registryBaseUrl);
|
|
185
|
+
resolve({
|
|
186
|
+
uploadUrl: `${regURL.protocol}//${regURL.hostname}${regURL.port ? ":" + regURL.port : ""}${location}`,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
181
189
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
190
|
+
reject("Missing location for 202");
|
|
191
|
+
}
|
|
192
|
+
else if (mountParameters && res.statusCode == 201) {
|
|
193
|
+
const returnedDigest = res.headers["docker-content-digest"];
|
|
194
|
+
if (returnedDigest && returnedDigest != mountParameters.mount) {
|
|
195
|
+
reject(`ERROR: Layer mounted with wrong digest: Expected ${mountParameters.mount} but got ${returnedDigest}`);
|
|
187
196
|
}
|
|
197
|
+
resolve({ mountSuccess: true });
|
|
188
198
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
if (returnedDigest && returnedDigest != mountParameters.mount) {
|
|
194
|
-
reject(`ERROR: Layer mounted with wrong digest: Expected ${mountParameters.mount} but got ${returnedDigest}`);
|
|
199
|
+
else {
|
|
200
|
+
(0, httpRequest_1.waitForResponseEnd)(res, (data) => {
|
|
201
|
+
reject(`Error getting upload URL from ${url}. Got ${res.statusCode} ${res.statusMessage}:\n${data.toString()}`);
|
|
202
|
+
});
|
|
195
203
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
else {
|
|
199
|
-
(0, httpRequest_1.waitForResponseEnd)(res, (data) => {
|
|
200
|
-
reject(`Error getting upload URL from ${url}. Got ${res.statusCode} ${res.statusMessage}:\n${data.toString()}`);
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
}).end();
|
|
204
|
+
}).end();
|
|
205
|
+
});
|
|
204
206
|
});
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
207
|
+
}
|
|
208
|
+
function dlManifest(image, preferredPlatform, allowInsecure) {
|
|
209
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
210
|
+
// Accept both manifests and index/manifest lists
|
|
211
|
+
const res = yield (0, httpRequest_1.dlJson)(`${registryBaseUrl}${image.path}/manifests/${image.tag}`, (0, httpRequest_1.buildHeaders)(`${MIMETypes_1.OCI.index}, ${MIMETypes_1.OCI.manifest}, ${MIMETypes_1.DockerV2.index}, ${MIMETypes_1.DockerV2.manifest}`, token), allowInsecure);
|
|
212
|
+
// We've received an OCI Index or Docker Manifest List and need to find which manifest we want
|
|
213
|
+
if (res.mediaType === MIMETypes_1.OCI.index || res.mediaType === MIMETypes_1.DockerV2.index) {
|
|
214
|
+
const availableManifests = res.manifests;
|
|
215
|
+
const adequateManifest = pickManifest(availableManifests, preferredPlatform);
|
|
216
|
+
return dlManifest(Object.assign(Object.assign({}, image), { tag: adequateManifest.digest }), preferredPlatform, allowInsecure);
|
|
217
|
+
}
|
|
218
|
+
return res;
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
function pickManifest(manifests, preferredPlatform) {
|
|
222
|
+
const matchingArchitectures = new Set();
|
|
223
|
+
const matchingOSes = new Set();
|
|
224
|
+
// Find sets of matching architecture and os
|
|
225
|
+
for (const manifest of manifests) {
|
|
226
|
+
if (manifest.platform.architecture === preferredPlatform.architecture) {
|
|
227
|
+
matchingArchitectures.add(manifest);
|
|
228
|
+
}
|
|
229
|
+
if (manifest.platform.os === preferredPlatform.os) {
|
|
230
|
+
matchingOSes.add(manifest);
|
|
231
|
+
}
|
|
216
232
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
const matchingArchitectures = new Set();
|
|
222
|
-
const matchingOSes = new Set();
|
|
223
|
-
// Find sets of matching architecture and os
|
|
224
|
-
for (const manifest of manifests) {
|
|
225
|
-
if (manifest.platform.architecture === preferredPlatform.architecture) {
|
|
226
|
-
matchingArchitectures.add(manifest);
|
|
233
|
+
// If the intersection of matching architectures and OS is one we've found our optimal match
|
|
234
|
+
const intersection = new Set([...matchingArchitectures].filter((x) => matchingOSes.has(x)));
|
|
235
|
+
if (intersection.size == 1) {
|
|
236
|
+
return intersection.values().next().value;
|
|
227
237
|
}
|
|
228
|
-
|
|
229
|
-
|
|
238
|
+
// If we don't have a perfect match we give a warning and try the first matching architecture
|
|
239
|
+
if (matchingArchitectures.size >= 1) {
|
|
240
|
+
const matchingArch = matchingArchitectures.values().next().value;
|
|
241
|
+
logger_1.default.info(`[WARN] Preferred OS '${preferredPlatform.os}' not available.`);
|
|
242
|
+
logger_1.default.info("[WARN] Using closest available manifest:", JSON.stringify(matchingArch.platform));
|
|
243
|
+
return matchingArch;
|
|
230
244
|
}
|
|
245
|
+
// If there's no image matching the wanted architecture we bail
|
|
246
|
+
logger_1.default.error(`No image matching requested architecture: '${preferredPlatform.architecture}'`);
|
|
247
|
+
logger_1.default.error("Available platforms:", JSON.stringify(manifests.map((m) => m.platform)));
|
|
248
|
+
throw new Error("No image matching requested architecture");
|
|
231
249
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
250
|
+
function dlConfig(image, config, allowInsecure) {
|
|
251
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
252
|
+
return yield (0, httpRequest_1.dlJson)(`${registryBaseUrl}${image.path}/blobs/${config.digest}`, (0, httpRequest_1.buildHeaders)("*/*", token), allowInsecure);
|
|
253
|
+
});
|
|
236
254
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
255
|
+
function dlLayer(image, layer, folder, allowInsecure, cacheFolder) {
|
|
256
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
257
|
+
const file = (0, utils_1.getHash)(layer.digest) + (0, utils_1.getLayerTypeFileEnding)(layer);
|
|
258
|
+
yield dlToFile(`${registryBaseUrl}${image.path}/blobs/${layer.digest}`, path.join(folder, file), (0, httpRequest_1.buildHeaders)(layer.mediaType, token), allowInsecure, cacheFolder);
|
|
259
|
+
return file;
|
|
260
|
+
});
|
|
243
261
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
const layersForUpload = layerStatus.filter((l) => !l.exists);
|
|
271
|
-
logger_1.default.debug("Needs upload:", layersForUpload.map((l) => l.layer.digest));
|
|
272
|
-
logger_1.default.info("Uploading layers...");
|
|
273
|
-
yield Promise.all(layersForUpload.map((l) => __awaiter(this, void 0, void 0, function* () {
|
|
274
|
-
if (doCrossMount && originalManifest.layers.find((x) => x.digest == l.layer.digest)) {
|
|
275
|
-
const mount = yield getUploadUrl(image, { mount: l.layer.digest, from: originalRepository });
|
|
276
|
-
if ("mountSuccess" in mount) {
|
|
277
|
-
logger_1.default.info(`Cross mounted layer ${l.layer.digest} from '${originalRepository}'`);
|
|
278
|
-
return;
|
|
262
|
+
function upload(imageStr, folder, doCrossMount, originalManifest, originalRepository) {
|
|
263
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
264
|
+
const image = (0, utils_1.parseImage)(imageStr);
|
|
265
|
+
const manifestFile = path.join(folder, "manifest.json");
|
|
266
|
+
const manifest = (yield fse.readJson(manifestFile));
|
|
267
|
+
logger_1.default.info("Checking layer status...");
|
|
268
|
+
const layerStatus = yield Promise.all(manifest.layers.map((l) => __awaiter(this, void 0, void 0, function* () {
|
|
269
|
+
return { layer: l, exists: yield exists(image, l) };
|
|
270
|
+
})));
|
|
271
|
+
const layersForUpload = layerStatus.filter((l) => !l.exists);
|
|
272
|
+
logger_1.default.debug("Needs upload:", layersForUpload.map((l) => l.layer.digest));
|
|
273
|
+
logger_1.default.info("Uploading layers...");
|
|
274
|
+
yield Promise.all(layersForUpload.map((l) => __awaiter(this, void 0, void 0, function* () {
|
|
275
|
+
if (doCrossMount && originalManifest.layers.find((x) => x.digest == l.layer.digest)) {
|
|
276
|
+
const mount = yield getUploadUrl(image, { mount: l.layer.digest, from: originalRepository });
|
|
277
|
+
if ("mountSuccess" in mount) {
|
|
278
|
+
logger_1.default.info(`Cross mounted layer ${l.layer.digest} from '${originalRepository}'`);
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
yield uploadLayerContent(mount.uploadUrl, l.layer, folder);
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
const url = yield getUploadUrl(image);
|
|
285
|
+
if ("mountSuccess" in url)
|
|
286
|
+
throw new Error("Mounting not supported for this upload");
|
|
287
|
+
yield uploadLayerContent(url.uploadUrl, l.layer, folder);
|
|
279
288
|
}
|
|
280
|
-
|
|
289
|
+
})));
|
|
290
|
+
logger_1.default.info("Uploading config...");
|
|
291
|
+
const configUploadUrl = yield getUploadUrl(image);
|
|
292
|
+
if ("mountSuccess" in configUploadUrl)
|
|
293
|
+
throw new Error("Mounting not supported for config upload");
|
|
294
|
+
const configFile = path.join(folder, (0, utils_1.getHash)(manifest.config.digest) + ".json");
|
|
295
|
+
yield uploadContent(configUploadUrl.uploadUrl, configFile, manifest.config, allowInsecure, token);
|
|
296
|
+
logger_1.default.info("Uploading manifest...");
|
|
297
|
+
const manifestSize = yield fileutil.sizeOf(manifestFile);
|
|
298
|
+
yield uploadContent(`${registryBaseUrl}${image.path}/manifests/${image.tag}`, manifestFile, { mediaType: manifest.mediaType, size: manifestSize }, allowInsecure, token, manifest.mediaType);
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
function download(imageStr, folder, preferredPlatform, cacheFolder) {
|
|
302
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
303
|
+
const image = (0, utils_1.parseImage)(imageStr);
|
|
304
|
+
logger_1.default.info("Downloading manifest...");
|
|
305
|
+
const manifest = yield dlManifest(image, preferredPlatform, allowInsecure);
|
|
306
|
+
yield fs_1.promises.writeFile(path.join(folder, "manifest.json"), JSON.stringify(manifest));
|
|
307
|
+
logger_1.default.info("Downloading config...");
|
|
308
|
+
const config = yield dlConfig(image, manifest.config, allowInsecure);
|
|
309
|
+
if (config.architecture != preferredPlatform.architecture) {
|
|
310
|
+
logger_1.default.info(`[WARN] Image architecture (${config.architecture}) does not match preferred architecture (${preferredPlatform.architecture}).`);
|
|
281
311
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
if ("mountSuccess" in url)
|
|
285
|
-
throw new Error("Mounting not supported for this upload");
|
|
286
|
-
yield uploadLayerContent(url.uploadUrl, l.layer, folder);
|
|
312
|
+
if (config.os != preferredPlatform.os) {
|
|
313
|
+
logger_1.default.info(`[WARN] Image OS (${config.os}) does not match preferred OS (${preferredPlatform.os}).`);
|
|
287
314
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
302
|
-
const image = (0, utils_1.parseImage)(imageStr);
|
|
303
|
-
logger_1.default.info("Downloading manifest...");
|
|
304
|
-
const manifest = yield dlManifest(image, preferredPlatform, allowInsecure);
|
|
305
|
-
yield fs_1.promises.writeFile(path.join(folder, "manifest.json"), JSON.stringify(manifest));
|
|
306
|
-
logger_1.default.info("Downloading config...");
|
|
307
|
-
const config = yield dlConfig(image, manifest.config, allowInsecure);
|
|
308
|
-
if (config.architecture != preferredPlatform.architecture) {
|
|
309
|
-
logger_1.default.info(`[WARN] Image architecture (${config.architecture}) does not match preferred architecture (${preferredPlatform.architecture}).`);
|
|
310
|
-
}
|
|
311
|
-
if (config.os != preferredPlatform.os) {
|
|
312
|
-
logger_1.default.info(`[WARN] Image OS (${config.os}) does not match preferred OS (${preferredPlatform.os}).`);
|
|
313
|
-
}
|
|
314
|
-
yield fs_1.promises.writeFile(path.join(folder, "config.json"), JSON.stringify(config));
|
|
315
|
-
logger_1.default.info("Downloading layers...");
|
|
316
|
-
yield Promise.all(manifest.layers.map((layer) => dlLayer(image, layer, folder, allowInsecure, cacheFolder)));
|
|
317
|
-
logger_1.default.info("Image downloaded.");
|
|
318
|
-
return manifest;
|
|
319
|
-
});
|
|
320
|
-
}
|
|
321
|
-
return {
|
|
322
|
-
download: download,
|
|
323
|
-
upload: upload,
|
|
324
|
-
registryBaseUrl,
|
|
325
|
-
};
|
|
315
|
+
yield fs_1.promises.writeFile(path.join(folder, "config.json"), JSON.stringify(config));
|
|
316
|
+
logger_1.default.info("Downloading layers...");
|
|
317
|
+
yield Promise.all(manifest.layers.map((layer) => dlLayer(image, layer, folder, allowInsecure, cacheFolder)));
|
|
318
|
+
logger_1.default.info("Image downloaded.");
|
|
319
|
+
return manifest;
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
return {
|
|
323
|
+
download: download,
|
|
324
|
+
upload: upload,
|
|
325
|
+
registryBaseUrl,
|
|
326
|
+
};
|
|
327
|
+
});
|
|
326
328
|
}
|
|
327
329
|
exports.createRegistry = createRegistry;
|
|
328
330
|
exports.DEFAULT_DOCKER_REGISTRY = "https://registry-1.docker.io/v2/";
|
package/lib/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "3.0.
|
|
1
|
+
export declare const VERSION = "3.0.1";
|
package/lib/version.js
CHANGED