@uniformdev/redirect 19.61.1 → 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.js
CHANGED
|
@@ -5,9 +5,6 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __commonJS = (cb, mod) => function __require() {
|
|
9
|
-
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
-
};
|
|
11
8
|
var __export = (target, all) => {
|
|
12
9
|
for (var name in all)
|
|
13
10
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -30,300 +27,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
30
27
|
));
|
|
31
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
29
|
|
|
33
|
-
// ../../node_modules/.pnpm/dotenv@16.3.1/node_modules/dotenv/package.json
|
|
34
|
-
var require_package = __commonJS({
|
|
35
|
-
"../../node_modules/.pnpm/dotenv@16.3.1/node_modules/dotenv/package.json"(exports, module2) {
|
|
36
|
-
module2.exports = {
|
|
37
|
-
name: "dotenv",
|
|
38
|
-
version: "16.3.1",
|
|
39
|
-
description: "Loads environment variables from .env file",
|
|
40
|
-
main: "lib/main.js",
|
|
41
|
-
types: "lib/main.d.ts",
|
|
42
|
-
exports: {
|
|
43
|
-
".": {
|
|
44
|
-
types: "./lib/main.d.ts",
|
|
45
|
-
require: "./lib/main.js",
|
|
46
|
-
default: "./lib/main.js"
|
|
47
|
-
},
|
|
48
|
-
"./config": "./config.js",
|
|
49
|
-
"./config.js": "./config.js",
|
|
50
|
-
"./lib/env-options": "./lib/env-options.js",
|
|
51
|
-
"./lib/env-options.js": "./lib/env-options.js",
|
|
52
|
-
"./lib/cli-options": "./lib/cli-options.js",
|
|
53
|
-
"./lib/cli-options.js": "./lib/cli-options.js",
|
|
54
|
-
"./package.json": "./package.json"
|
|
55
|
-
},
|
|
56
|
-
scripts: {
|
|
57
|
-
"dts-check": "tsc --project tests/types/tsconfig.json",
|
|
58
|
-
lint: "standard",
|
|
59
|
-
"lint-readme": "standard-markdown",
|
|
60
|
-
pretest: "npm run lint && npm run dts-check",
|
|
61
|
-
test: "tap tests/*.js --100 -Rspec",
|
|
62
|
-
prerelease: "npm test",
|
|
63
|
-
release: "standard-version"
|
|
64
|
-
},
|
|
65
|
-
repository: {
|
|
66
|
-
type: "git",
|
|
67
|
-
url: "git://github.com/motdotla/dotenv.git"
|
|
68
|
-
},
|
|
69
|
-
funding: "https://github.com/motdotla/dotenv?sponsor=1",
|
|
70
|
-
keywords: [
|
|
71
|
-
"dotenv",
|
|
72
|
-
"env",
|
|
73
|
-
".env",
|
|
74
|
-
"environment",
|
|
75
|
-
"variables",
|
|
76
|
-
"config",
|
|
77
|
-
"settings"
|
|
78
|
-
],
|
|
79
|
-
readmeFilename: "README.md",
|
|
80
|
-
license: "BSD-2-Clause",
|
|
81
|
-
devDependencies: {
|
|
82
|
-
"@definitelytyped/dtslint": "^0.0.133",
|
|
83
|
-
"@types/node": "^18.11.3",
|
|
84
|
-
decache: "^4.6.1",
|
|
85
|
-
sinon: "^14.0.1",
|
|
86
|
-
standard: "^17.0.0",
|
|
87
|
-
"standard-markdown": "^7.1.0",
|
|
88
|
-
"standard-version": "^9.5.0",
|
|
89
|
-
tap: "^16.3.0",
|
|
90
|
-
tar: "^6.1.11",
|
|
91
|
-
typescript: "^4.8.4"
|
|
92
|
-
},
|
|
93
|
-
engines: {
|
|
94
|
-
node: ">=12"
|
|
95
|
-
},
|
|
96
|
-
browser: {
|
|
97
|
-
fs: false
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
// ../../node_modules/.pnpm/dotenv@16.3.1/node_modules/dotenv/lib/main.js
|
|
104
|
-
var require_main = __commonJS({
|
|
105
|
-
"../../node_modules/.pnpm/dotenv@16.3.1/node_modules/dotenv/lib/main.js"(exports, module2) {
|
|
106
|
-
"use strict";
|
|
107
|
-
var fs = require("fs");
|
|
108
|
-
var path = require("path");
|
|
109
|
-
var os = require("os");
|
|
110
|
-
var crypto = require("crypto");
|
|
111
|
-
var packageJson = require_package();
|
|
112
|
-
var version = packageJson.version;
|
|
113
|
-
var LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;
|
|
114
|
-
function parse(src) {
|
|
115
|
-
const obj = {};
|
|
116
|
-
let lines = src.toString();
|
|
117
|
-
lines = lines.replace(/\r\n?/mg, "\n");
|
|
118
|
-
let match;
|
|
119
|
-
while ((match = LINE.exec(lines)) != null) {
|
|
120
|
-
const key = match[1];
|
|
121
|
-
let value = match[2] || "";
|
|
122
|
-
value = value.trim();
|
|
123
|
-
const maybeQuote = value[0];
|
|
124
|
-
value = value.replace(/^(['"`])([\s\S]*)\1$/mg, "$2");
|
|
125
|
-
if (maybeQuote === '"') {
|
|
126
|
-
value = value.replace(/\\n/g, "\n");
|
|
127
|
-
value = value.replace(/\\r/g, "\r");
|
|
128
|
-
}
|
|
129
|
-
obj[key] = value;
|
|
130
|
-
}
|
|
131
|
-
return obj;
|
|
132
|
-
}
|
|
133
|
-
function _parseVault(options) {
|
|
134
|
-
const vaultPath = _vaultPath(options);
|
|
135
|
-
const result = DotenvModule.configDotenv({ path: vaultPath });
|
|
136
|
-
if (!result.parsed) {
|
|
137
|
-
throw new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`);
|
|
138
|
-
}
|
|
139
|
-
const keys = _dotenvKey(options).split(",");
|
|
140
|
-
const length = keys.length;
|
|
141
|
-
let decrypted;
|
|
142
|
-
for (let i = 0; i < length; i++) {
|
|
143
|
-
try {
|
|
144
|
-
const key = keys[i].trim();
|
|
145
|
-
const attrs = _instructions(result, key);
|
|
146
|
-
decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key);
|
|
147
|
-
break;
|
|
148
|
-
} catch (error) {
|
|
149
|
-
if (i + 1 >= length) {
|
|
150
|
-
throw error;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
return DotenvModule.parse(decrypted);
|
|
155
|
-
}
|
|
156
|
-
function _log(message) {
|
|
157
|
-
console.log(`[dotenv@${version}][INFO] ${message}`);
|
|
158
|
-
}
|
|
159
|
-
function _warn(message) {
|
|
160
|
-
console.log(`[dotenv@${version}][WARN] ${message}`);
|
|
161
|
-
}
|
|
162
|
-
function _debug(message) {
|
|
163
|
-
console.log(`[dotenv@${version}][DEBUG] ${message}`);
|
|
164
|
-
}
|
|
165
|
-
function _dotenvKey(options) {
|
|
166
|
-
if (options && options.DOTENV_KEY && options.DOTENV_KEY.length > 0) {
|
|
167
|
-
return options.DOTENV_KEY;
|
|
168
|
-
}
|
|
169
|
-
if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) {
|
|
170
|
-
return process.env.DOTENV_KEY;
|
|
171
|
-
}
|
|
172
|
-
return "";
|
|
173
|
-
}
|
|
174
|
-
function _instructions(result, dotenvKey) {
|
|
175
|
-
let uri;
|
|
176
|
-
try {
|
|
177
|
-
uri = new URL(dotenvKey);
|
|
178
|
-
} catch (error) {
|
|
179
|
-
if (error.code === "ERR_INVALID_URL") {
|
|
180
|
-
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");
|
|
181
|
-
}
|
|
182
|
-
throw error;
|
|
183
|
-
}
|
|
184
|
-
const key = uri.password;
|
|
185
|
-
if (!key) {
|
|
186
|
-
throw new Error("INVALID_DOTENV_KEY: Missing key part");
|
|
187
|
-
}
|
|
188
|
-
const environment = uri.searchParams.get("environment");
|
|
189
|
-
if (!environment) {
|
|
190
|
-
throw new Error("INVALID_DOTENV_KEY: Missing environment part");
|
|
191
|
-
}
|
|
192
|
-
const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`;
|
|
193
|
-
const ciphertext = result.parsed[environmentKey];
|
|
194
|
-
if (!ciphertext) {
|
|
195
|
-
throw new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`);
|
|
196
|
-
}
|
|
197
|
-
return { ciphertext, key };
|
|
198
|
-
}
|
|
199
|
-
function _vaultPath(options) {
|
|
200
|
-
let dotenvPath = path.resolve(process.cwd(), ".env");
|
|
201
|
-
if (options && options.path && options.path.length > 0) {
|
|
202
|
-
dotenvPath = options.path;
|
|
203
|
-
}
|
|
204
|
-
return dotenvPath.endsWith(".vault") ? dotenvPath : `${dotenvPath}.vault`;
|
|
205
|
-
}
|
|
206
|
-
function _resolveHome(envPath) {
|
|
207
|
-
return envPath[0] === "~" ? path.join(os.homedir(), envPath.slice(1)) : envPath;
|
|
208
|
-
}
|
|
209
|
-
function _configVault(options) {
|
|
210
|
-
_log("Loading env from encrypted .env.vault");
|
|
211
|
-
const parsed = DotenvModule._parseVault(options);
|
|
212
|
-
let processEnv = process.env;
|
|
213
|
-
if (options && options.processEnv != null) {
|
|
214
|
-
processEnv = options.processEnv;
|
|
215
|
-
}
|
|
216
|
-
DotenvModule.populate(processEnv, parsed, options);
|
|
217
|
-
return { parsed };
|
|
218
|
-
}
|
|
219
|
-
function configDotenv(options) {
|
|
220
|
-
let dotenvPath = path.resolve(process.cwd(), ".env");
|
|
221
|
-
let encoding = "utf8";
|
|
222
|
-
const debug = Boolean(options && options.debug);
|
|
223
|
-
if (options) {
|
|
224
|
-
if (options.path != null) {
|
|
225
|
-
dotenvPath = _resolveHome(options.path);
|
|
226
|
-
}
|
|
227
|
-
if (options.encoding != null) {
|
|
228
|
-
encoding = options.encoding;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
try {
|
|
232
|
-
const parsed = DotenvModule.parse(fs.readFileSync(dotenvPath, { encoding }));
|
|
233
|
-
let processEnv = process.env;
|
|
234
|
-
if (options && options.processEnv != null) {
|
|
235
|
-
processEnv = options.processEnv;
|
|
236
|
-
}
|
|
237
|
-
DotenvModule.populate(processEnv, parsed, options);
|
|
238
|
-
return { parsed };
|
|
239
|
-
} catch (e) {
|
|
240
|
-
if (debug) {
|
|
241
|
-
_debug(`Failed to load ${dotenvPath} ${e.message}`);
|
|
242
|
-
}
|
|
243
|
-
return { error: e };
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
function config(options) {
|
|
247
|
-
const vaultPath = _vaultPath(options);
|
|
248
|
-
if (_dotenvKey(options).length === 0) {
|
|
249
|
-
return DotenvModule.configDotenv(options);
|
|
250
|
-
}
|
|
251
|
-
if (!fs.existsSync(vaultPath)) {
|
|
252
|
-
_warn(`You set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}. Did you forget to build it?`);
|
|
253
|
-
return DotenvModule.configDotenv(options);
|
|
254
|
-
}
|
|
255
|
-
return DotenvModule._configVault(options);
|
|
256
|
-
}
|
|
257
|
-
function decrypt(encrypted, keyStr) {
|
|
258
|
-
const key = Buffer.from(keyStr.slice(-64), "hex");
|
|
259
|
-
let ciphertext = Buffer.from(encrypted, "base64");
|
|
260
|
-
const nonce = ciphertext.slice(0, 12);
|
|
261
|
-
const authTag = ciphertext.slice(-16);
|
|
262
|
-
ciphertext = ciphertext.slice(12, -16);
|
|
263
|
-
try {
|
|
264
|
-
const aesgcm = crypto.createDecipheriv("aes-256-gcm", key, nonce);
|
|
265
|
-
aesgcm.setAuthTag(authTag);
|
|
266
|
-
return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
|
|
267
|
-
} catch (error) {
|
|
268
|
-
const isRange = error instanceof RangeError;
|
|
269
|
-
const invalidKeyLength = error.message === "Invalid key length";
|
|
270
|
-
const decryptionFailed = error.message === "Unsupported state or unable to authenticate data";
|
|
271
|
-
if (isRange || invalidKeyLength) {
|
|
272
|
-
const msg = "INVALID_DOTENV_KEY: It must be 64 characters long (or more)";
|
|
273
|
-
throw new Error(msg);
|
|
274
|
-
} else if (decryptionFailed) {
|
|
275
|
-
const msg = "DECRYPTION_FAILED: Please check your DOTENV_KEY";
|
|
276
|
-
throw new Error(msg);
|
|
277
|
-
} else {
|
|
278
|
-
console.error("Error: ", error.code);
|
|
279
|
-
console.error("Error: ", error.message);
|
|
280
|
-
throw error;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
function populate(processEnv, parsed, options = {}) {
|
|
285
|
-
const debug = Boolean(options && options.debug);
|
|
286
|
-
const override = Boolean(options && options.override);
|
|
287
|
-
if (typeof parsed !== "object") {
|
|
288
|
-
throw new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");
|
|
289
|
-
}
|
|
290
|
-
for (const key of Object.keys(parsed)) {
|
|
291
|
-
if (Object.prototype.hasOwnProperty.call(processEnv, key)) {
|
|
292
|
-
if (override === true) {
|
|
293
|
-
processEnv[key] = parsed[key];
|
|
294
|
-
}
|
|
295
|
-
if (debug) {
|
|
296
|
-
if (override === true) {
|
|
297
|
-
_debug(`"${key}" is already defined and WAS overwritten`);
|
|
298
|
-
} else {
|
|
299
|
-
_debug(`"${key}" is already defined and was NOT overwritten`);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
} else {
|
|
303
|
-
processEnv[key] = parsed[key];
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
var DotenvModule = {
|
|
308
|
-
configDotenv,
|
|
309
|
-
_configVault,
|
|
310
|
-
_parseVault,
|
|
311
|
-
config,
|
|
312
|
-
decrypt,
|
|
313
|
-
parse,
|
|
314
|
-
populate
|
|
315
|
-
};
|
|
316
|
-
module2.exports.configDotenv = DotenvModule.configDotenv;
|
|
317
|
-
module2.exports._configVault = DotenvModule._configVault;
|
|
318
|
-
module2.exports._parseVault = DotenvModule._parseVault;
|
|
319
|
-
module2.exports.config = DotenvModule.config;
|
|
320
|
-
module2.exports.decrypt = DotenvModule.decrypt;
|
|
321
|
-
module2.exports.parse = DotenvModule.parse;
|
|
322
|
-
module2.exports.populate = DotenvModule.populate;
|
|
323
|
-
module2.exports = DotenvModule;
|
|
324
|
-
}
|
|
325
|
-
});
|
|
326
|
-
|
|
327
30
|
// src/index.ts
|
|
328
31
|
var src_exports = {};
|
|
329
32
|
__export(src_exports, {
|
|
@@ -334,6 +37,9 @@ __export(src_exports, {
|
|
|
334
37
|
RedirectFileConverter: () => RedirectFileConverter,
|
|
335
38
|
UncachedRedirectClient: () => UncachedRedirectClient,
|
|
336
39
|
WithMemoryCache: () => WithMemoryCache,
|
|
40
|
+
getSourceVariables: () => getSourceVariables,
|
|
41
|
+
getTargetVariableExpandedUrl: () => getTargetVariableExpandedUrl,
|
|
42
|
+
mergeQueryStrings: () => mergeQueryStrings,
|
|
337
43
|
processUrl: () => processUrl
|
|
338
44
|
});
|
|
339
45
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -600,22 +306,78 @@ var import_api = require("@uniformdev/context/api");
|
|
|
600
306
|
// src/util/url.ts
|
|
601
307
|
function processUrl(url) {
|
|
602
308
|
var _a, _b, _c, _d, _e, _f;
|
|
603
|
-
const matches = url.match(/^(https?:\/\/)?(([^:/?#]*)(?:(:[0-9]+))?)?([/]{0,1}[^?#]*)(\?[
|
|
309
|
+
const matches = url.match(/^(https?:\/\/)?(([^:/?#]*)(?:(:[0-9]+))?)?([/]{0,1}[^?#]*)(\?[^#?]*|)(#.*|)$/);
|
|
310
|
+
const protocol = (_a = matches == null ? void 0 : matches[1]) != null ? _a : "";
|
|
311
|
+
const domain = (_b = matches == null ? void 0 : matches[3]) != null ? _b : "";
|
|
312
|
+
const port = (_c = matches == null ? void 0 : matches[4]) != null ? _c : "";
|
|
313
|
+
const path = (_d = matches == null ? void 0 : matches[5].replace(/\/+$/g, "")) != null ? _d : "";
|
|
314
|
+
const query = (_e = matches == null ? void 0 : matches[6]) != null ? _e : "";
|
|
315
|
+
const fragment = (_f = matches == null ? void 0 : matches[7]) != null ? _f : "";
|
|
604
316
|
return {
|
|
605
|
-
url
|
|
606
|
-
protocol
|
|
607
|
-
domain
|
|
608
|
-
port
|
|
609
|
-
path
|
|
610
|
-
query
|
|
611
|
-
fragment
|
|
317
|
+
url: `${protocol}${domain}${port}${path}${query}${fragment}`,
|
|
318
|
+
protocol,
|
|
319
|
+
domain,
|
|
320
|
+
port,
|
|
321
|
+
path,
|
|
322
|
+
query,
|
|
323
|
+
fragment
|
|
612
324
|
};
|
|
613
325
|
}
|
|
614
326
|
|
|
327
|
+
// src/util/process.ts
|
|
328
|
+
function getTargetVariableExpandedUrl(url, redirectDefinition, isVariable) {
|
|
329
|
+
const processedTarget = processUrl(redirectDefinition.targetUrl);
|
|
330
|
+
const processedSource = processUrl(redirectDefinition.sourceUrl);
|
|
331
|
+
let finalUrlPath = processedTarget.path;
|
|
332
|
+
const processedUrl = processUrl(url);
|
|
333
|
+
const variables = getSourceVariables(processedUrl.path, processedSource.path, isVariable);
|
|
334
|
+
for (const variable in variables) {
|
|
335
|
+
finalUrlPath = finalUrlPath.replace(variable, variables[variable]);
|
|
336
|
+
}
|
|
337
|
+
let protocol = redirectDefinition.targetPreserveIncomingProtocol || processedTarget.protocol === "" ? processedUrl.protocol : processedTarget.protocol;
|
|
338
|
+
const domain = protocol !== "" ? redirectDefinition.targetPreserveIncomingDomain || processedTarget.domain === "" ? processedUrl.domain : processedTarget.domain : "";
|
|
339
|
+
if (domain === "" && protocol !== "") {
|
|
340
|
+
protocol = "";
|
|
341
|
+
}
|
|
342
|
+
const port = domain === "" ? "" : redirectDefinition.targetPreserveIncomingDomain || processedTarget.domain === "" ? processedUrl.port : processedTarget.port;
|
|
343
|
+
const query = redirectDefinition.sourceRetainQuerystring && redirectDefinition.targetMergeQuerystring ? mergeQueryStrings(processedUrl.query, processedTarget.query) : !redirectDefinition.targetMergeQuerystring && redirectDefinition.sourceRetainQuerystring ? processedUrl.query : processedTarget.query;
|
|
344
|
+
const fragment = redirectDefinition.sourceRetainQuerystring && redirectDefinition.targetMergeQuerystring ? mergeQueryStrings(processedUrl.fragment, processedTarget.fragment) : !redirectDefinition.targetMergeQuerystring && redirectDefinition.sourceRetainQuerystring ? processedUrl.fragment : processedTarget.fragment;
|
|
345
|
+
return `${protocol}${domain}${port}${finalUrlPath}${query}${fragment}`;
|
|
346
|
+
}
|
|
347
|
+
function getSourceVariables(path, source, isVariable = (pathSegment, isLast) => pathSegment.startsWith(":") || pathSegment === "*" && isLast) {
|
|
348
|
+
const variables = {};
|
|
349
|
+
const pathSegments = path.split("/");
|
|
350
|
+
const sourceSegments = source.split("/");
|
|
351
|
+
sourceSegments.forEach((sourceSegment, i) => {
|
|
352
|
+
if (pathSegments.length >= i && isVariable(sourceSegment, i === sourceSegments.length - 1)) {
|
|
353
|
+
variables[sourceSegment] = pathSegments[i];
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
return variables;
|
|
357
|
+
}
|
|
358
|
+
function mergeQueryStrings(qs1, qs2) {
|
|
359
|
+
let fragment = false;
|
|
360
|
+
if (qs1.startsWith("#")) {
|
|
361
|
+
fragment = true;
|
|
362
|
+
qs1 = qs1.substring(1);
|
|
363
|
+
}
|
|
364
|
+
if (qs2.startsWith("#")) {
|
|
365
|
+
fragment = true;
|
|
366
|
+
qs2 = qs2.substring(1);
|
|
367
|
+
}
|
|
368
|
+
const params1 = new URLSearchParams(qs1);
|
|
369
|
+
const params2 = new URLSearchParams(qs2);
|
|
370
|
+
const merged = new URLSearchParams([...params1, ...params2]).toString();
|
|
371
|
+
if (merged.length > 0)
|
|
372
|
+
return (fragment ? "#" : "?") + merged;
|
|
373
|
+
return "";
|
|
374
|
+
}
|
|
375
|
+
|
|
615
376
|
// src/redirectClient.ts
|
|
616
377
|
var _RedirectClient = class _RedirectClient extends import_api.ApiClient {
|
|
617
378
|
constructor(options) {
|
|
618
379
|
super(options);
|
|
380
|
+
// Get a single redirect by ID or project map id
|
|
619
381
|
this.getRedirect = async (options) => {
|
|
620
382
|
var _a;
|
|
621
383
|
const { projectId } = this.options;
|
|
@@ -623,12 +385,14 @@ var _RedirectClient = class _RedirectClient extends import_api.ApiClient {
|
|
|
623
385
|
const results = await this.apiClient(fetchUri);
|
|
624
386
|
return (_a = results.redirects) == null ? void 0 : _a[0];
|
|
625
387
|
};
|
|
388
|
+
// Get redirects by list of IDs, source URL, target URL, or search
|
|
626
389
|
this.getRedirects = async (options) => {
|
|
627
390
|
const { projectId } = this.options;
|
|
628
391
|
const fetchUri = this.createUrl("/api/v1/redirect", { ...options, projectId });
|
|
629
392
|
const results = await this.apiClient(fetchUri);
|
|
630
393
|
return results;
|
|
631
394
|
};
|
|
395
|
+
// Assemble a trie powered search structure, used to have instant resolution of redirects. Note, result set may be large.
|
|
632
396
|
this.getRedirectTrie = async (options) => {
|
|
633
397
|
var _a, _b;
|
|
634
398
|
const { projectId } = this.options;
|
|
@@ -710,7 +474,7 @@ var _RedirectClient = class _RedirectClient extends import_api.ApiClient {
|
|
|
710
474
|
return _RedirectClient.processDefinitionToResults(
|
|
711
475
|
processedUrl,
|
|
712
476
|
redirect,
|
|
713
|
-
|
|
477
|
+
getSourceVariables(
|
|
714
478
|
processedUrl.path,
|
|
715
479
|
processUrl((options == null ? void 0 : options.reverse) ? redirect.redirect.targetUrl : redirect.redirect.sourceUrl).path
|
|
716
480
|
),
|
|
@@ -720,6 +484,8 @@ var _RedirectClient = class _RedirectClient extends import_api.ApiClient {
|
|
|
720
484
|
const trie = await this.getRedirectTrie();
|
|
721
485
|
return (_b = _RedirectClient.processHops(sanitizedUrl, trie, true, options)) == null ? void 0 : _b[0];
|
|
722
486
|
};
|
|
487
|
+
// Caculate redirect matches based on an incoming URL with an option to use a trie storage structure to streamline future
|
|
488
|
+
// redirect resolutions. Note this may cause a large in memory load for large collections of redirect, off by default.
|
|
723
489
|
this.processUrlAllMatches = async (url, options, useTrie) => {
|
|
724
490
|
const sanitizedUrl = url.endsWith("/") ? url.replace(/\/+$/, "") : url;
|
|
725
491
|
if (!useTrie) {
|
|
@@ -731,7 +497,7 @@ var _RedirectClient = class _RedirectClient extends import_api.ApiClient {
|
|
|
731
497
|
return _RedirectClient.processDefinitionToResults(
|
|
732
498
|
processedUrl,
|
|
733
499
|
redirect,
|
|
734
|
-
|
|
500
|
+
getSourceVariables(
|
|
735
501
|
processedUrl.path,
|
|
736
502
|
processUrl((options == null ? void 0 : options.reverse) ? redirect.redirect.targetUrl : redirect.redirect.sourceUrl).path
|
|
737
503
|
),
|
|
@@ -752,6 +518,7 @@ var _RedirectClient = class _RedirectClient extends import_api.ApiClient {
|
|
|
752
518
|
}
|
|
753
519
|
}
|
|
754
520
|
}
|
|
521
|
+
// Get all redirects in Uniform 500 at a time.
|
|
755
522
|
async *getAllRedirects(orderBy = "updated_at desc") {
|
|
756
523
|
var _a, _b;
|
|
757
524
|
const { projectId } = this.options;
|
|
@@ -800,6 +567,8 @@ var _RedirectClient = class _RedirectClient extends import_api.ApiClient {
|
|
|
800
567
|
}
|
|
801
568
|
return await _RedirectClient.assemblingPromise;
|
|
802
569
|
}
|
|
570
|
+
// Find all redirects involved for the current URL, this is for the case where a redirect definition leads to
|
|
571
|
+
// another redirect. This also involves cycle busting error handling
|
|
803
572
|
static processHops(initialUrl, trie, bestMatch, options) {
|
|
804
573
|
const url = (options == null ? void 0 : options.reverse) ? initialUrl.replace(/\/:/, "/~~") : initialUrl;
|
|
805
574
|
const isCycle = (id, result) => {
|
|
@@ -868,7 +637,7 @@ var _RedirectClient = class _RedirectClient extends import_api.ApiClient {
|
|
|
868
637
|
const redirect = definition == null ? void 0 : definition.redirect;
|
|
869
638
|
if (redirect.sourceMustMatchDomain && processedUrl.domain !== processedResult.domain)
|
|
870
639
|
return void 0;
|
|
871
|
-
const finalUrl = (options == null ? void 0 : options.reverse) ? "n/a" :
|
|
640
|
+
const finalUrl = (options == null ? void 0 : options.reverse) ? "n/a" : getTargetVariableExpandedUrl(processedUrl.url, redirect);
|
|
872
641
|
return {
|
|
873
642
|
url: finalUrl,
|
|
874
643
|
definition,
|
|
@@ -894,56 +663,6 @@ var _RedirectClient = class _RedirectClient extends import_api.ApiClient {
|
|
|
894
663
|
}
|
|
895
664
|
return true;
|
|
896
665
|
}
|
|
897
|
-
static getTargetVariableExpandedUrl(url, redirectDefinition, isVariable) {
|
|
898
|
-
const processedTarget = processUrl(redirectDefinition.targetUrl);
|
|
899
|
-
const processedSource = processUrl(redirectDefinition.sourceUrl);
|
|
900
|
-
let finalUrlPath = processedTarget.path;
|
|
901
|
-
const processedUrl = processUrl(url);
|
|
902
|
-
const variables = this.getSourceVariables(processedUrl.path, processedSource.path, isVariable);
|
|
903
|
-
for (const variable in variables) {
|
|
904
|
-
finalUrlPath = finalUrlPath.replace(variable, variables[variable]);
|
|
905
|
-
}
|
|
906
|
-
let protocol = redirectDefinition.targetPreserveIncomingProtocol || processedTarget.protocol === "" ? processedUrl.protocol : processedTarget.protocol;
|
|
907
|
-
const domain = protocol !== "" ? redirectDefinition.targetPreserveIncomingDomain || processedTarget.domain === "" ? processedUrl.domain : processedTarget.domain : "";
|
|
908
|
-
if (domain === "" && protocol !== "") {
|
|
909
|
-
protocol = "";
|
|
910
|
-
}
|
|
911
|
-
const port = domain === "" ? "" : redirectDefinition.targetPreserveIncomingDomain || processedTarget.domain === "" ? processedUrl.port : processedTarget.port;
|
|
912
|
-
const query = redirectDefinition.sourceRetainQuerystring && redirectDefinition.targetMergeQuerystring ? this.mergeQueryStrings(processedUrl.query, processedTarget.query) : !redirectDefinition.targetMergeQuerystring && redirectDefinition.sourceRetainQuerystring ? processedUrl.query : processedTarget.query;
|
|
913
|
-
const fragment = redirectDefinition.sourceRetainQuerystring && redirectDefinition.targetMergeQuerystring ? this.mergeQueryStrings(processedUrl.fragment, processedTarget.fragment) : !redirectDefinition.targetMergeQuerystring && redirectDefinition.sourceRetainQuerystring ? processedUrl.fragment : processedTarget.fragment;
|
|
914
|
-
return `${protocol}${domain}${port}${finalUrlPath}${query}${fragment}`;
|
|
915
|
-
}
|
|
916
|
-
static mergeQueryStrings(qs1, qs2) {
|
|
917
|
-
let fragment = false;
|
|
918
|
-
if (qs1.startsWith("#")) {
|
|
919
|
-
fragment = true;
|
|
920
|
-
qs1 = qs1.substring(1);
|
|
921
|
-
}
|
|
922
|
-
if (qs2.startsWith("#")) {
|
|
923
|
-
fragment = true;
|
|
924
|
-
qs2 = qs2.substring(1);
|
|
925
|
-
}
|
|
926
|
-
const params1 = new URLSearchParams(qs1);
|
|
927
|
-
const params2 = new URLSearchParams(qs2);
|
|
928
|
-
const merged = new URLSearchParams([...params1, ...params2]).toString();
|
|
929
|
-
if (merged.length > 0)
|
|
930
|
-
return (fragment ? "#" : "?") + merged;
|
|
931
|
-
return "";
|
|
932
|
-
}
|
|
933
|
-
static getSourceVariables(path, source, isVariable = (pathSegment, isLast) => pathSegment.startsWith(":") || pathSegment === "*" && isLast) {
|
|
934
|
-
const variables = {};
|
|
935
|
-
const pathSegments = path.split("/");
|
|
936
|
-
const sourceSegments = source.split("/");
|
|
937
|
-
if (pathSegments.length !== sourceSegments.length && !source.endsWith("/*")) {
|
|
938
|
-
throw new Error("Path and source have different numbers of path segments, must be the same");
|
|
939
|
-
}
|
|
940
|
-
sourceSegments.forEach((sourceSegment, i) => {
|
|
941
|
-
if (isVariable(sourceSegment, i === sourceSegments.length - 1)) {
|
|
942
|
-
variables[sourceSegment] = pathSegments[i];
|
|
943
|
-
}
|
|
944
|
-
});
|
|
945
|
-
return variables;
|
|
946
|
-
}
|
|
947
666
|
};
|
|
948
667
|
_RedirectClient.processUrlBestMatch = async (url, trie, options) => {
|
|
949
668
|
var _a;
|
|
@@ -962,8 +681,6 @@ var UncachedRedirectClient = class extends RedirectClient {
|
|
|
962
681
|
|
|
963
682
|
// src/util/RedirectFileConverter.ts
|
|
964
683
|
var getDefaultClient = async () => {
|
|
965
|
-
const dotenv = await Promise.resolve().then(() => __toESM(require_main()));
|
|
966
|
-
dotenv.config();
|
|
967
684
|
return new RedirectClient({
|
|
968
685
|
apiKey: process.env.UNIFORM_API_KEY,
|
|
969
686
|
apiHost: process.env.UNIFORM_BASE_URL,
|
|
@@ -1041,5 +758,8 @@ async function RedirectFileConverter({
|
|
|
1041
758
|
RedirectFileConverter,
|
|
1042
759
|
UncachedRedirectClient,
|
|
1043
760
|
WithMemoryCache,
|
|
761
|
+
getSourceVariables,
|
|
762
|
+
getTargetVariableExpandedUrl,
|
|
763
|
+
mergeQueryStrings,
|
|
1044
764
|
processUrl
|
|
1045
765
|
});
|