@uniformdev/redirect 19.62.0 → 19.62.1-alpha.127
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/LICENSE.txt +1 -1
- package/dist/index.d.mts +7 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.esm.js +77 -65
- package/dist/index.js +80 -360
- package/dist/index.mjs +77 -65
- package/package.json +3 -3
- package/dist/chunk-TLYAXJ7N.mjs +0 -16
- package/dist/main-4Y7KG46W.mjs +0 -298
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import "./chunk-TLYAXJ7N.mjs";
|
|
2
|
-
|
|
3
1
|
// src/cache/data/refresher.ts
|
|
4
2
|
var Refresher = class {
|
|
5
3
|
/**
|
|
@@ -262,22 +260,78 @@ import { ApiClient } from "@uniformdev/context/api";
|
|
|
262
260
|
// src/util/url.ts
|
|
263
261
|
function processUrl(url) {
|
|
264
262
|
var _a, _b, _c, _d, _e, _f;
|
|
265
|
-
const matches = url.match(/^(https?:\/\/)?(([^:/?#]*)(?:(:[0-9]+))?)?([/]{0,1}[^?#]*)(\?[
|
|
263
|
+
const matches = url.match(/^(https?:\/\/)?(([^:/?#]*)(?:(:[0-9]+))?)?([/]{0,1}[^?#]*)(\?[^#?]*|)(#.*|)$/);
|
|
264
|
+
const protocol = (_a = matches == null ? void 0 : matches[1]) != null ? _a : "";
|
|
265
|
+
const domain = (_b = matches == null ? void 0 : matches[3]) != null ? _b : "";
|
|
266
|
+
const port = (_c = matches == null ? void 0 : matches[4]) != null ? _c : "";
|
|
267
|
+
const path = (_d = matches == null ? void 0 : matches[5].replace(/\/+$/g, "")) != null ? _d : "";
|
|
268
|
+
const query = (_e = matches == null ? void 0 : matches[6]) != null ? _e : "";
|
|
269
|
+
const fragment = (_f = matches == null ? void 0 : matches[7]) != null ? _f : "";
|
|
266
270
|
return {
|
|
267
|
-
url
|
|
268
|
-
protocol
|
|
269
|
-
domain
|
|
270
|
-
port
|
|
271
|
-
path
|
|
272
|
-
query
|
|
273
|
-
fragment
|
|
271
|
+
url: `${protocol}${domain}${port}${path}${query}${fragment}`,
|
|
272
|
+
protocol,
|
|
273
|
+
domain,
|
|
274
|
+
port,
|
|
275
|
+
path,
|
|
276
|
+
query,
|
|
277
|
+
fragment
|
|
274
278
|
};
|
|
275
279
|
}
|
|
276
280
|
|
|
281
|
+
// src/util/process.ts
|
|
282
|
+
function getTargetVariableExpandedUrl(url, redirectDefinition, isVariable) {
|
|
283
|
+
const processedTarget = processUrl(redirectDefinition.targetUrl);
|
|
284
|
+
const processedSource = processUrl(redirectDefinition.sourceUrl);
|
|
285
|
+
let finalUrlPath = processedTarget.path;
|
|
286
|
+
const processedUrl = processUrl(url);
|
|
287
|
+
const variables = getSourceVariables(processedUrl.path, processedSource.path, isVariable);
|
|
288
|
+
for (const variable in variables) {
|
|
289
|
+
finalUrlPath = finalUrlPath.replace(variable, variables[variable]);
|
|
290
|
+
}
|
|
291
|
+
let protocol = redirectDefinition.targetPreserveIncomingProtocol || processedTarget.protocol === "" ? processedUrl.protocol : processedTarget.protocol;
|
|
292
|
+
const domain = protocol !== "" ? redirectDefinition.targetPreserveIncomingDomain || processedTarget.domain === "" ? processedUrl.domain : processedTarget.domain : "";
|
|
293
|
+
if (domain === "" && protocol !== "") {
|
|
294
|
+
protocol = "";
|
|
295
|
+
}
|
|
296
|
+
const port = domain === "" ? "" : redirectDefinition.targetPreserveIncomingDomain || processedTarget.domain === "" ? processedUrl.port : processedTarget.port;
|
|
297
|
+
const query = redirectDefinition.sourceRetainQuerystring && redirectDefinition.targetMergeQuerystring ? mergeQueryStrings(processedUrl.query, processedTarget.query) : !redirectDefinition.targetMergeQuerystring && redirectDefinition.sourceRetainQuerystring ? processedUrl.query : processedTarget.query;
|
|
298
|
+
const fragment = redirectDefinition.sourceRetainQuerystring && redirectDefinition.targetMergeQuerystring ? mergeQueryStrings(processedUrl.fragment, processedTarget.fragment) : !redirectDefinition.targetMergeQuerystring && redirectDefinition.sourceRetainQuerystring ? processedUrl.fragment : processedTarget.fragment;
|
|
299
|
+
return `${protocol}${domain}${port}${finalUrlPath}${query}${fragment}`;
|
|
300
|
+
}
|
|
301
|
+
function getSourceVariables(path, source, isVariable = (pathSegment, isLast) => pathSegment.startsWith(":") || pathSegment === "*" && isLast) {
|
|
302
|
+
const variables = {};
|
|
303
|
+
const pathSegments = path.split("/");
|
|
304
|
+
const sourceSegments = source.split("/");
|
|
305
|
+
sourceSegments.forEach((sourceSegment, i) => {
|
|
306
|
+
if (pathSegments.length >= i && isVariable(sourceSegment, i === sourceSegments.length - 1)) {
|
|
307
|
+
variables[sourceSegment] = pathSegments[i];
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
return variables;
|
|
311
|
+
}
|
|
312
|
+
function mergeQueryStrings(qs1, qs2) {
|
|
313
|
+
let fragment = false;
|
|
314
|
+
if (qs1.startsWith("#")) {
|
|
315
|
+
fragment = true;
|
|
316
|
+
qs1 = qs1.substring(1);
|
|
317
|
+
}
|
|
318
|
+
if (qs2.startsWith("#")) {
|
|
319
|
+
fragment = true;
|
|
320
|
+
qs2 = qs2.substring(1);
|
|
321
|
+
}
|
|
322
|
+
const params1 = new URLSearchParams(qs1);
|
|
323
|
+
const params2 = new URLSearchParams(qs2);
|
|
324
|
+
const merged = new URLSearchParams([...params1, ...params2]).toString();
|
|
325
|
+
if (merged.length > 0)
|
|
326
|
+
return (fragment ? "#" : "?") + merged;
|
|
327
|
+
return "";
|
|
328
|
+
}
|
|
329
|
+
|
|
277
330
|
// src/redirectClient.ts
|
|
278
331
|
var _RedirectClient = class _RedirectClient extends ApiClient {
|
|
279
332
|
constructor(options) {
|
|
280
333
|
super(options);
|
|
334
|
+
// Get a single redirect by ID or project map id
|
|
281
335
|
this.getRedirect = async (options) => {
|
|
282
336
|
var _a;
|
|
283
337
|
const { projectId } = this.options;
|
|
@@ -285,12 +339,14 @@ var _RedirectClient = class _RedirectClient extends ApiClient {
|
|
|
285
339
|
const results = await this.apiClient(fetchUri);
|
|
286
340
|
return (_a = results.redirects) == null ? void 0 : _a[0];
|
|
287
341
|
};
|
|
342
|
+
// Get redirects by list of IDs, source URL, target URL, or search
|
|
288
343
|
this.getRedirects = async (options) => {
|
|
289
344
|
const { projectId } = this.options;
|
|
290
345
|
const fetchUri = this.createUrl("/api/v1/redirect", { ...options, projectId });
|
|
291
346
|
const results = await this.apiClient(fetchUri);
|
|
292
347
|
return results;
|
|
293
348
|
};
|
|
349
|
+
// Assemble a trie powered search structure, used to have instant resolution of redirects. Note, result set may be large.
|
|
294
350
|
this.getRedirectTrie = async (options) => {
|
|
295
351
|
var _a, _b;
|
|
296
352
|
const { projectId } = this.options;
|
|
@@ -372,7 +428,7 @@ var _RedirectClient = class _RedirectClient extends ApiClient {
|
|
|
372
428
|
return _RedirectClient.processDefinitionToResults(
|
|
373
429
|
processedUrl,
|
|
374
430
|
redirect,
|
|
375
|
-
|
|
431
|
+
getSourceVariables(
|
|
376
432
|
processedUrl.path,
|
|
377
433
|
processUrl((options == null ? void 0 : options.reverse) ? redirect.redirect.targetUrl : redirect.redirect.sourceUrl).path
|
|
378
434
|
),
|
|
@@ -382,6 +438,8 @@ var _RedirectClient = class _RedirectClient extends ApiClient {
|
|
|
382
438
|
const trie = await this.getRedirectTrie();
|
|
383
439
|
return (_b = _RedirectClient.processHops(sanitizedUrl, trie, true, options)) == null ? void 0 : _b[0];
|
|
384
440
|
};
|
|
441
|
+
// Caculate redirect matches based on an incoming URL with an option to use a trie storage structure to streamline future
|
|
442
|
+
// redirect resolutions. Note this may cause a large in memory load for large collections of redirect, off by default.
|
|
385
443
|
this.processUrlAllMatches = async (url, options, useTrie) => {
|
|
386
444
|
const sanitizedUrl = url.endsWith("/") ? url.replace(/\/+$/, "") : url;
|
|
387
445
|
if (!useTrie) {
|
|
@@ -393,7 +451,7 @@ var _RedirectClient = class _RedirectClient extends ApiClient {
|
|
|
393
451
|
return _RedirectClient.processDefinitionToResults(
|
|
394
452
|
processedUrl,
|
|
395
453
|
redirect,
|
|
396
|
-
|
|
454
|
+
getSourceVariables(
|
|
397
455
|
processedUrl.path,
|
|
398
456
|
processUrl((options == null ? void 0 : options.reverse) ? redirect.redirect.targetUrl : redirect.redirect.sourceUrl).path
|
|
399
457
|
),
|
|
@@ -414,6 +472,7 @@ var _RedirectClient = class _RedirectClient extends ApiClient {
|
|
|
414
472
|
}
|
|
415
473
|
}
|
|
416
474
|
}
|
|
475
|
+
// Get all redirects in Uniform 500 at a time.
|
|
417
476
|
async *getAllRedirects(orderBy = "updated_at desc") {
|
|
418
477
|
var _a, _b;
|
|
419
478
|
const { projectId } = this.options;
|
|
@@ -462,6 +521,8 @@ var _RedirectClient = class _RedirectClient extends ApiClient {
|
|
|
462
521
|
}
|
|
463
522
|
return await _RedirectClient.assemblingPromise;
|
|
464
523
|
}
|
|
524
|
+
// Find all redirects involved for the current URL, this is for the case where a redirect definition leads to
|
|
525
|
+
// another redirect. This also involves cycle busting error handling
|
|
465
526
|
static processHops(initialUrl, trie, bestMatch, options) {
|
|
466
527
|
const url = (options == null ? void 0 : options.reverse) ? initialUrl.replace(/\/:/, "/~~") : initialUrl;
|
|
467
528
|
const isCycle = (id, result) => {
|
|
@@ -530,7 +591,7 @@ var _RedirectClient = class _RedirectClient extends ApiClient {
|
|
|
530
591
|
const redirect = definition == null ? void 0 : definition.redirect;
|
|
531
592
|
if (redirect.sourceMustMatchDomain && processedUrl.domain !== processedResult.domain)
|
|
532
593
|
return void 0;
|
|
533
|
-
const finalUrl = (options == null ? void 0 : options.reverse) ? "n/a" :
|
|
594
|
+
const finalUrl = (options == null ? void 0 : options.reverse) ? "n/a" : getTargetVariableExpandedUrl(processedUrl.url, redirect);
|
|
534
595
|
return {
|
|
535
596
|
url: finalUrl,
|
|
536
597
|
definition,
|
|
@@ -556,56 +617,6 @@ var _RedirectClient = class _RedirectClient extends ApiClient {
|
|
|
556
617
|
}
|
|
557
618
|
return true;
|
|
558
619
|
}
|
|
559
|
-
static getTargetVariableExpandedUrl(url, redirectDefinition, isVariable) {
|
|
560
|
-
const processedTarget = processUrl(redirectDefinition.targetUrl);
|
|
561
|
-
const processedSource = processUrl(redirectDefinition.sourceUrl);
|
|
562
|
-
let finalUrlPath = processedTarget.path;
|
|
563
|
-
const processedUrl = processUrl(url);
|
|
564
|
-
const variables = this.getSourceVariables(processedUrl.path, processedSource.path, isVariable);
|
|
565
|
-
for (const variable in variables) {
|
|
566
|
-
finalUrlPath = finalUrlPath.replace(variable, variables[variable]);
|
|
567
|
-
}
|
|
568
|
-
let protocol = redirectDefinition.targetPreserveIncomingProtocol || processedTarget.protocol === "" ? processedUrl.protocol : processedTarget.protocol;
|
|
569
|
-
const domain = protocol !== "" ? redirectDefinition.targetPreserveIncomingDomain || processedTarget.domain === "" ? processedUrl.domain : processedTarget.domain : "";
|
|
570
|
-
if (domain === "" && protocol !== "") {
|
|
571
|
-
protocol = "";
|
|
572
|
-
}
|
|
573
|
-
const port = domain === "" ? "" : redirectDefinition.targetPreserveIncomingDomain || processedTarget.domain === "" ? processedUrl.port : processedTarget.port;
|
|
574
|
-
const query = redirectDefinition.sourceRetainQuerystring && redirectDefinition.targetMergeQuerystring ? this.mergeQueryStrings(processedUrl.query, processedTarget.query) : !redirectDefinition.targetMergeQuerystring && redirectDefinition.sourceRetainQuerystring ? processedUrl.query : processedTarget.query;
|
|
575
|
-
const fragment = redirectDefinition.sourceRetainQuerystring && redirectDefinition.targetMergeQuerystring ? this.mergeQueryStrings(processedUrl.fragment, processedTarget.fragment) : !redirectDefinition.targetMergeQuerystring && redirectDefinition.sourceRetainQuerystring ? processedUrl.fragment : processedTarget.fragment;
|
|
576
|
-
return `${protocol}${domain}${port}${finalUrlPath}${query}${fragment}`;
|
|
577
|
-
}
|
|
578
|
-
static mergeQueryStrings(qs1, qs2) {
|
|
579
|
-
let fragment = false;
|
|
580
|
-
if (qs1.startsWith("#")) {
|
|
581
|
-
fragment = true;
|
|
582
|
-
qs1 = qs1.substring(1);
|
|
583
|
-
}
|
|
584
|
-
if (qs2.startsWith("#")) {
|
|
585
|
-
fragment = true;
|
|
586
|
-
qs2 = qs2.substring(1);
|
|
587
|
-
}
|
|
588
|
-
const params1 = new URLSearchParams(qs1);
|
|
589
|
-
const params2 = new URLSearchParams(qs2);
|
|
590
|
-
const merged = new URLSearchParams([...params1, ...params2]).toString();
|
|
591
|
-
if (merged.length > 0)
|
|
592
|
-
return (fragment ? "#" : "?") + merged;
|
|
593
|
-
return "";
|
|
594
|
-
}
|
|
595
|
-
static getSourceVariables(path, source, isVariable = (pathSegment, isLast) => pathSegment.startsWith(":") || pathSegment === "*" && isLast) {
|
|
596
|
-
const variables = {};
|
|
597
|
-
const pathSegments = path.split("/");
|
|
598
|
-
const sourceSegments = source.split("/");
|
|
599
|
-
if (pathSegments.length !== sourceSegments.length && !source.endsWith("/*")) {
|
|
600
|
-
throw new Error("Path and source have different numbers of path segments, must be the same");
|
|
601
|
-
}
|
|
602
|
-
sourceSegments.forEach((sourceSegment, i) => {
|
|
603
|
-
if (isVariable(sourceSegment, i === sourceSegments.length - 1)) {
|
|
604
|
-
variables[sourceSegment] = pathSegments[i];
|
|
605
|
-
}
|
|
606
|
-
});
|
|
607
|
-
return variables;
|
|
608
|
-
}
|
|
609
620
|
};
|
|
610
621
|
_RedirectClient.processUrlBestMatch = async (url, trie, options) => {
|
|
611
622
|
var _a;
|
|
@@ -624,8 +635,6 @@ var UncachedRedirectClient = class extends RedirectClient {
|
|
|
624
635
|
|
|
625
636
|
// src/util/RedirectFileConverter.ts
|
|
626
637
|
var getDefaultClient = async () => {
|
|
627
|
-
const dotenv = await import("./main-4Y7KG46W.mjs");
|
|
628
|
-
dotenv.config();
|
|
629
638
|
return new RedirectClient({
|
|
630
639
|
apiKey: process.env.UNIFORM_API_KEY,
|
|
631
640
|
apiHost: process.env.UNIFORM_BASE_URL,
|
|
@@ -702,5 +711,8 @@ export {
|
|
|
702
711
|
RedirectFileConverter,
|
|
703
712
|
UncachedRedirectClient,
|
|
704
713
|
WithMemoryCache,
|
|
714
|
+
getSourceVariables,
|
|
715
|
+
getTargetVariableExpandedUrl,
|
|
716
|
+
mergeQueryStrings,
|
|
705
717
|
processUrl
|
|
706
718
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniformdev/redirect",
|
|
3
|
-
"version": "19.62.
|
|
3
|
+
"version": "19.62.1-alpha.127+d49e5a0782",
|
|
4
4
|
"description": "Uniform redirect client",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -33,12 +33,12 @@
|
|
|
33
33
|
"/dist"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@uniformdev/context": "19.62.
|
|
36
|
+
"@uniformdev/context": "19.62.1-alpha.127+d49e5a0782",
|
|
37
37
|
"p-limit": "^3.1.0",
|
|
38
38
|
"rfdc": "^1.3.0"
|
|
39
39
|
},
|
|
40
40
|
"publishConfig": {
|
|
41
41
|
"access": "public"
|
|
42
42
|
},
|
|
43
|
-
"gitHead": "
|
|
43
|
+
"gitHead": "d49e5a07824d69e5df3a92ff10bc9acd88d0bc22"
|
|
44
44
|
}
|
package/dist/chunk-TLYAXJ7N.mjs
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
2
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
4
|
-
}) : x)(function(x) {
|
|
5
|
-
if (typeof require !== "undefined")
|
|
6
|
-
return require.apply(this, arguments);
|
|
7
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
8
|
-
});
|
|
9
|
-
var __commonJS = (cb, mod) => function __require2() {
|
|
10
|
-
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export {
|
|
14
|
-
__require,
|
|
15
|
-
__commonJS
|
|
16
|
-
};
|
package/dist/main-4Y7KG46W.mjs
DELETED
|
@@ -1,298 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
__commonJS,
|
|
3
|
-
__require
|
|
4
|
-
} from "./chunk-TLYAXJ7N.mjs";
|
|
5
|
-
|
|
6
|
-
// ../../node_modules/.pnpm/dotenv@16.3.1/node_modules/dotenv/package.json
|
|
7
|
-
var require_package = __commonJS({
|
|
8
|
-
"../../node_modules/.pnpm/dotenv@16.3.1/node_modules/dotenv/package.json"(exports, module) {
|
|
9
|
-
module.exports = {
|
|
10
|
-
name: "dotenv",
|
|
11
|
-
version: "16.3.1",
|
|
12
|
-
description: "Loads environment variables from .env file",
|
|
13
|
-
main: "lib/main.js",
|
|
14
|
-
types: "lib/main.d.ts",
|
|
15
|
-
exports: {
|
|
16
|
-
".": {
|
|
17
|
-
types: "./lib/main.d.ts",
|
|
18
|
-
require: "./lib/main.js",
|
|
19
|
-
default: "./lib/main.js"
|
|
20
|
-
},
|
|
21
|
-
"./config": "./config.js",
|
|
22
|
-
"./config.js": "./config.js",
|
|
23
|
-
"./lib/env-options": "./lib/env-options.js",
|
|
24
|
-
"./lib/env-options.js": "./lib/env-options.js",
|
|
25
|
-
"./lib/cli-options": "./lib/cli-options.js",
|
|
26
|
-
"./lib/cli-options.js": "./lib/cli-options.js",
|
|
27
|
-
"./package.json": "./package.json"
|
|
28
|
-
},
|
|
29
|
-
scripts: {
|
|
30
|
-
"dts-check": "tsc --project tests/types/tsconfig.json",
|
|
31
|
-
lint: "standard",
|
|
32
|
-
"lint-readme": "standard-markdown",
|
|
33
|
-
pretest: "npm run lint && npm run dts-check",
|
|
34
|
-
test: "tap tests/*.js --100 -Rspec",
|
|
35
|
-
prerelease: "npm test",
|
|
36
|
-
release: "standard-version"
|
|
37
|
-
},
|
|
38
|
-
repository: {
|
|
39
|
-
type: "git",
|
|
40
|
-
url: "git://github.com/motdotla/dotenv.git"
|
|
41
|
-
},
|
|
42
|
-
funding: "https://github.com/motdotla/dotenv?sponsor=1",
|
|
43
|
-
keywords: [
|
|
44
|
-
"dotenv",
|
|
45
|
-
"env",
|
|
46
|
-
".env",
|
|
47
|
-
"environment",
|
|
48
|
-
"variables",
|
|
49
|
-
"config",
|
|
50
|
-
"settings"
|
|
51
|
-
],
|
|
52
|
-
readmeFilename: "README.md",
|
|
53
|
-
license: "BSD-2-Clause",
|
|
54
|
-
devDependencies: {
|
|
55
|
-
"@definitelytyped/dtslint": "^0.0.133",
|
|
56
|
-
"@types/node": "^18.11.3",
|
|
57
|
-
decache: "^4.6.1",
|
|
58
|
-
sinon: "^14.0.1",
|
|
59
|
-
standard: "^17.0.0",
|
|
60
|
-
"standard-markdown": "^7.1.0",
|
|
61
|
-
"standard-version": "^9.5.0",
|
|
62
|
-
tap: "^16.3.0",
|
|
63
|
-
tar: "^6.1.11",
|
|
64
|
-
typescript: "^4.8.4"
|
|
65
|
-
},
|
|
66
|
-
engines: {
|
|
67
|
-
node: ">=12"
|
|
68
|
-
},
|
|
69
|
-
browser: {
|
|
70
|
-
fs: false
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
// ../../node_modules/.pnpm/dotenv@16.3.1/node_modules/dotenv/lib/main.js
|
|
77
|
-
var require_main = __commonJS({
|
|
78
|
-
"../../node_modules/.pnpm/dotenv@16.3.1/node_modules/dotenv/lib/main.js"(exports, module) {
|
|
79
|
-
var fs = __require("fs");
|
|
80
|
-
var path = __require("path");
|
|
81
|
-
var os = __require("os");
|
|
82
|
-
var crypto = __require("crypto");
|
|
83
|
-
var packageJson = require_package();
|
|
84
|
-
var version = packageJson.version;
|
|
85
|
-
var LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;
|
|
86
|
-
function parse(src) {
|
|
87
|
-
const obj = {};
|
|
88
|
-
let lines = src.toString();
|
|
89
|
-
lines = lines.replace(/\r\n?/mg, "\n");
|
|
90
|
-
let match;
|
|
91
|
-
while ((match = LINE.exec(lines)) != null) {
|
|
92
|
-
const key = match[1];
|
|
93
|
-
let value = match[2] || "";
|
|
94
|
-
value = value.trim();
|
|
95
|
-
const maybeQuote = value[0];
|
|
96
|
-
value = value.replace(/^(['"`])([\s\S]*)\1$/mg, "$2");
|
|
97
|
-
if (maybeQuote === '"') {
|
|
98
|
-
value = value.replace(/\\n/g, "\n");
|
|
99
|
-
value = value.replace(/\\r/g, "\r");
|
|
100
|
-
}
|
|
101
|
-
obj[key] = value;
|
|
102
|
-
}
|
|
103
|
-
return obj;
|
|
104
|
-
}
|
|
105
|
-
function _parseVault(options) {
|
|
106
|
-
const vaultPath = _vaultPath(options);
|
|
107
|
-
const result = DotenvModule.configDotenv({ path: vaultPath });
|
|
108
|
-
if (!result.parsed) {
|
|
109
|
-
throw new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`);
|
|
110
|
-
}
|
|
111
|
-
const keys = _dotenvKey(options).split(",");
|
|
112
|
-
const length = keys.length;
|
|
113
|
-
let decrypted;
|
|
114
|
-
for (let i = 0; i < length; i++) {
|
|
115
|
-
try {
|
|
116
|
-
const key = keys[i].trim();
|
|
117
|
-
const attrs = _instructions(result, key);
|
|
118
|
-
decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key);
|
|
119
|
-
break;
|
|
120
|
-
} catch (error) {
|
|
121
|
-
if (i + 1 >= length) {
|
|
122
|
-
throw error;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return DotenvModule.parse(decrypted);
|
|
127
|
-
}
|
|
128
|
-
function _log(message) {
|
|
129
|
-
console.log(`[dotenv@${version}][INFO] ${message}`);
|
|
130
|
-
}
|
|
131
|
-
function _warn(message) {
|
|
132
|
-
console.log(`[dotenv@${version}][WARN] ${message}`);
|
|
133
|
-
}
|
|
134
|
-
function _debug(message) {
|
|
135
|
-
console.log(`[dotenv@${version}][DEBUG] ${message}`);
|
|
136
|
-
}
|
|
137
|
-
function _dotenvKey(options) {
|
|
138
|
-
if (options && options.DOTENV_KEY && options.DOTENV_KEY.length > 0) {
|
|
139
|
-
return options.DOTENV_KEY;
|
|
140
|
-
}
|
|
141
|
-
if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) {
|
|
142
|
-
return process.env.DOTENV_KEY;
|
|
143
|
-
}
|
|
144
|
-
return "";
|
|
145
|
-
}
|
|
146
|
-
function _instructions(result, dotenvKey) {
|
|
147
|
-
let uri;
|
|
148
|
-
try {
|
|
149
|
-
uri = new URL(dotenvKey);
|
|
150
|
-
} catch (error) {
|
|
151
|
-
if (error.code === "ERR_INVALID_URL") {
|
|
152
|
-
throw new Error("INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenv.org/vault/.env.vault?environment=development");
|
|
153
|
-
}
|
|
154
|
-
throw error;
|
|
155
|
-
}
|
|
156
|
-
const key = uri.password;
|
|
157
|
-
if (!key) {
|
|
158
|
-
throw new Error("INVALID_DOTENV_KEY: Missing key part");
|
|
159
|
-
}
|
|
160
|
-
const environment = uri.searchParams.get("environment");
|
|
161
|
-
if (!environment) {
|
|
162
|
-
throw new Error("INVALID_DOTENV_KEY: Missing environment part");
|
|
163
|
-
}
|
|
164
|
-
const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`;
|
|
165
|
-
const ciphertext = result.parsed[environmentKey];
|
|
166
|
-
if (!ciphertext) {
|
|
167
|
-
throw new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`);
|
|
168
|
-
}
|
|
169
|
-
return { ciphertext, key };
|
|
170
|
-
}
|
|
171
|
-
function _vaultPath(options) {
|
|
172
|
-
let dotenvPath = path.resolve(process.cwd(), ".env");
|
|
173
|
-
if (options && options.path && options.path.length > 0) {
|
|
174
|
-
dotenvPath = options.path;
|
|
175
|
-
}
|
|
176
|
-
return dotenvPath.endsWith(".vault") ? dotenvPath : `${dotenvPath}.vault`;
|
|
177
|
-
}
|
|
178
|
-
function _resolveHome(envPath) {
|
|
179
|
-
return envPath[0] === "~" ? path.join(os.homedir(), envPath.slice(1)) : envPath;
|
|
180
|
-
}
|
|
181
|
-
function _configVault(options) {
|
|
182
|
-
_log("Loading env from encrypted .env.vault");
|
|
183
|
-
const parsed = DotenvModule._parseVault(options);
|
|
184
|
-
let processEnv = process.env;
|
|
185
|
-
if (options && options.processEnv != null) {
|
|
186
|
-
processEnv = options.processEnv;
|
|
187
|
-
}
|
|
188
|
-
DotenvModule.populate(processEnv, parsed, options);
|
|
189
|
-
return { parsed };
|
|
190
|
-
}
|
|
191
|
-
function configDotenv(options) {
|
|
192
|
-
let dotenvPath = path.resolve(process.cwd(), ".env");
|
|
193
|
-
let encoding = "utf8";
|
|
194
|
-
const debug = Boolean(options && options.debug);
|
|
195
|
-
if (options) {
|
|
196
|
-
if (options.path != null) {
|
|
197
|
-
dotenvPath = _resolveHome(options.path);
|
|
198
|
-
}
|
|
199
|
-
if (options.encoding != null) {
|
|
200
|
-
encoding = options.encoding;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
try {
|
|
204
|
-
const parsed = DotenvModule.parse(fs.readFileSync(dotenvPath, { encoding }));
|
|
205
|
-
let processEnv = process.env;
|
|
206
|
-
if (options && options.processEnv != null) {
|
|
207
|
-
processEnv = options.processEnv;
|
|
208
|
-
}
|
|
209
|
-
DotenvModule.populate(processEnv, parsed, options);
|
|
210
|
-
return { parsed };
|
|
211
|
-
} catch (e) {
|
|
212
|
-
if (debug) {
|
|
213
|
-
_debug(`Failed to load ${dotenvPath} ${e.message}`);
|
|
214
|
-
}
|
|
215
|
-
return { error: e };
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
function config(options) {
|
|
219
|
-
const vaultPath = _vaultPath(options);
|
|
220
|
-
if (_dotenvKey(options).length === 0) {
|
|
221
|
-
return DotenvModule.configDotenv(options);
|
|
222
|
-
}
|
|
223
|
-
if (!fs.existsSync(vaultPath)) {
|
|
224
|
-
_warn(`You set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}. Did you forget to build it?`);
|
|
225
|
-
return DotenvModule.configDotenv(options);
|
|
226
|
-
}
|
|
227
|
-
return DotenvModule._configVault(options);
|
|
228
|
-
}
|
|
229
|
-
function decrypt(encrypted, keyStr) {
|
|
230
|
-
const key = Buffer.from(keyStr.slice(-64), "hex");
|
|
231
|
-
let ciphertext = Buffer.from(encrypted, "base64");
|
|
232
|
-
const nonce = ciphertext.slice(0, 12);
|
|
233
|
-
const authTag = ciphertext.slice(-16);
|
|
234
|
-
ciphertext = ciphertext.slice(12, -16);
|
|
235
|
-
try {
|
|
236
|
-
const aesgcm = crypto.createDecipheriv("aes-256-gcm", key, nonce);
|
|
237
|
-
aesgcm.setAuthTag(authTag);
|
|
238
|
-
return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
|
|
239
|
-
} catch (error) {
|
|
240
|
-
const isRange = error instanceof RangeError;
|
|
241
|
-
const invalidKeyLength = error.message === "Invalid key length";
|
|
242
|
-
const decryptionFailed = error.message === "Unsupported state or unable to authenticate data";
|
|
243
|
-
if (isRange || invalidKeyLength) {
|
|
244
|
-
const msg = "INVALID_DOTENV_KEY: It must be 64 characters long (or more)";
|
|
245
|
-
throw new Error(msg);
|
|
246
|
-
} else if (decryptionFailed) {
|
|
247
|
-
const msg = "DECRYPTION_FAILED: Please check your DOTENV_KEY";
|
|
248
|
-
throw new Error(msg);
|
|
249
|
-
} else {
|
|
250
|
-
console.error("Error: ", error.code);
|
|
251
|
-
console.error("Error: ", error.message);
|
|
252
|
-
throw error;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
function populate(processEnv, parsed, options = {}) {
|
|
257
|
-
const debug = Boolean(options && options.debug);
|
|
258
|
-
const override = Boolean(options && options.override);
|
|
259
|
-
if (typeof parsed !== "object") {
|
|
260
|
-
throw new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");
|
|
261
|
-
}
|
|
262
|
-
for (const key of Object.keys(parsed)) {
|
|
263
|
-
if (Object.prototype.hasOwnProperty.call(processEnv, key)) {
|
|
264
|
-
if (override === true) {
|
|
265
|
-
processEnv[key] = parsed[key];
|
|
266
|
-
}
|
|
267
|
-
if (debug) {
|
|
268
|
-
if (override === true) {
|
|
269
|
-
_debug(`"${key}" is already defined and WAS overwritten`);
|
|
270
|
-
} else {
|
|
271
|
-
_debug(`"${key}" is already defined and was NOT overwritten`);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
} else {
|
|
275
|
-
processEnv[key] = parsed[key];
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
var DotenvModule = {
|
|
280
|
-
configDotenv,
|
|
281
|
-
_configVault,
|
|
282
|
-
_parseVault,
|
|
283
|
-
config,
|
|
284
|
-
decrypt,
|
|
285
|
-
parse,
|
|
286
|
-
populate
|
|
287
|
-
};
|
|
288
|
-
module.exports.configDotenv = DotenvModule.configDotenv;
|
|
289
|
-
module.exports._configVault = DotenvModule._configVault;
|
|
290
|
-
module.exports._parseVault = DotenvModule._parseVault;
|
|
291
|
-
module.exports.config = DotenvModule.config;
|
|
292
|
-
module.exports.decrypt = DotenvModule.decrypt;
|
|
293
|
-
module.exports.parse = DotenvModule.parse;
|
|
294
|
-
module.exports.populate = DotenvModule.populate;
|
|
295
|
-
module.exports = DotenvModule;
|
|
296
|
-
}
|
|
297
|
-
});
|
|
298
|
-
export default require_main();
|