@dbx-tools/shared-core 0.6.46 → 0.6.49
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/README.md +77 -2
- package/index.ts +7 -0
- package/lib/index.d.ts +7 -0
- package/lib/index.js +5 -1
- package/lib/src/env.d.ts +80 -0
- package/lib/src/env.js +114 -0
- package/lib/src/execution.d.ts +34 -0
- package/lib/src/execution.js +42 -0
- package/lib/src/object.d.ts +19 -2
- package/lib/src/object.js +22 -3
- package/lib/src/pattern.d.ts +67 -0
- package/lib/src/pattern.js +129 -0
- package/lib/src/token.d.ts +14 -0
- package/lib/src/token.js +16 -2
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/env.ts +133 -0
- package/src/execution.ts +71 -0
- package/src/object.ts +25 -2
- package/src/pattern.ts +148 -0
- package/src/token.ts +18 -1
package/lib/src/token.js
CHANGED
|
@@ -12,6 +12,20 @@ import { isLevelEnabled, logger } from "./log.js";
|
|
|
12
12
|
const BEARER_PREFIX_REGEX = /^bearer\s+/i;
|
|
13
13
|
const SPLIT_REGEX = /\s+|\s*,\s*/;
|
|
14
14
|
const log = logger("shared/token");
|
|
15
|
+
/**
|
|
16
|
+
* Header the Databricks Apps front door forwards the caller's OAuth (OBO) token
|
|
17
|
+
* on - the default source for every helper here.
|
|
18
|
+
*
|
|
19
|
+
* Exported because it is a wire contract several packages branch on, not just a
|
|
20
|
+
* default argument: `@dbx-tools/appkit`'s `identity` module decides whether a
|
|
21
|
+
* request can use OBO auth at all by its presence, and `@dbx-tools/cli-tunnel`
|
|
22
|
+
* must know the name to strip inbound copies of it. One spelling, one place.
|
|
23
|
+
*/
|
|
24
|
+
export const ACCESS_TOKEN_HEADER = "x-forwarded-access-token";
|
|
25
|
+
/** Header the front door forwards the caller's user id on. */
|
|
26
|
+
export const USER_ID_HEADER = "x-forwarded-user";
|
|
27
|
+
/** Header the front door forwards the caller's email on. */
|
|
28
|
+
export const USER_EMAIL_HEADER = "x-forwarded-email";
|
|
15
29
|
/**
|
|
16
30
|
* Decode a JWT segment (base64url with standard base64 padding), or
|
|
17
31
|
* `undefined` when the segment is not valid base64.
|
|
@@ -34,7 +48,7 @@ function decodeJwtSegment(segment) {
|
|
|
34
48
|
* When `input` is header-like, walks every value for `headerName` (default
|
|
35
49
|
* `x-forwarded-access-token`) and merges claim keys left-to-right.
|
|
36
50
|
*/
|
|
37
|
-
export function getAccessTokenPayload(input, headerName =
|
|
51
|
+
export function getAccessTokenPayload(input, headerName = ACCESS_TOKEN_HEADER) {
|
|
38
52
|
let accessTokenPayload;
|
|
39
53
|
if (!(typeof input === "string")) {
|
|
40
54
|
if (headerName) {
|
|
@@ -123,4 +137,4 @@ function* iterateClaims(input, distinct = true) {
|
|
|
123
137
|
}
|
|
124
138
|
yield* visit(input);
|
|
125
139
|
}
|
|
126
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9rZW4uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdG9rZW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7R0FPRztBQUVILE9BQU8sRUFBRSxrQkFBa0IsRUFBbUIsTUFBTSxXQUFXLENBQUM7QUFDaEUsT0FBTyxLQUFLLElBQUksTUFBTSxXQUFXLENBQUM7QUFDbEMsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFFbEQsTUFBTSxtQkFBbUIsR0FBRyxhQUFhLENBQUM7QUFDMUMsTUFBTSxXQUFXLEdBQUcsYUFBYSxDQUFDO0FBQ2xDLE1BQU0sR0FBRyxHQUFHLE1BQU0sQ0FBQyxjQUFjLENBQUMsQ0FBQztBQUVuQzs7O0dBR0c7QUFDSCxTQUFTLGdCQUFnQixDQUFDLE9BQWU7SUFDdkMsTUFBTSxVQUFVLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsR0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxHQUFHLENBQUMsQ0FBQztJQUNqRSxNQUFNLE1BQU0sR0FBRyxVQUFVLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUMxRSxJQUFJLENBQUM7UUFDSCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDNUIsTUFBTSxLQUFLLEdBQUcsVUFBVSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNoRSxPQUFPLElBQUksV0FBVyxFQUFFLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3pDLENBQUM7SUFBQyxNQUFNLENBQUM7UUFDUCxPQUFPLFNBQVMs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LENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVELEtBQUssQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUN0QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBKV1QgYWNjZXNzLXRva2VuIGhlbHBlcnMgZm9yIERhdGFicmlja3MgQXBwcy5cbiAqXG4gKiBQYXJzZXMgYmVhcmVyIHRva2VucyBhbmQgYHgtZm9yd2FyZGVkLWFjY2Vzcy10b2tlbmAgcGF5bG9hZHMgdG8gcmVhZFxuICogT0F1dGggc2NvcGVzIGFuZCBvdGhlciBjbGFpbXMgZnJvbSBpbmNvbWluZyBIVFRQIHJlcXVlc3RzLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBmb3JFYWNoSGVhZGVyVmFsdWUsIHR5cGUgSGVhZGVyTGlrZSB9IGZyb20gXCIuL2h0dHAudHNcIjtcbmltcG9ydCAqIGFzIGpzb24gZnJvbSBcIi4vanNvbi50c1wiO1xuaW1wb3J0IHsgaXNMZXZlbEVuYWJsZWQsIGxvZ2dlciB9IGZyb20gXCIuL2xvZy50c1wiO1xuXG5jb25zdCBCRUFSRVJfUFJFRklYX1JFR0VYID0gL15iZWFyZXJcXHMrL2k7XG5jb25zdCBTUExJVF9SRUdFWCA9IC9cXHMrfFxccyosXFxzKi87XG5jb25zdCBsb2cgPSBsb2dnZXIoXCJzaGFyZWQvdG9rZW5cIik7XG5cbi8qKlxuICogRGVjb2RlIGEgSldUIHNlZ21lbnQgKGJhc2U2NHVybCB3aXRoIHN0YW5kYXJkIGJhc2U2NCBwYWRkaW5nKSwgb3JcbiAqIGB1bmRlZmluZWRgIHdoZW4gdGhlIHNlZ21lbnQgaXMgbm90IHZhbGlkIGJhc2U2NC5cbiAqL1xuZnVuY3Rpb24gZGVjb2RlSnd0U2VnbWVudChzZWdtZW50OiBzdHJpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBjb25zdCBub3JtYWxpemVkID0gc2VnbWVudC5yZXBsYWNlKC8tL2csIFwiK1wiKS5yZXBsYWNlKC9fL2csIFwiL1wiKTtcbiAgY29uc3QgcGFkZGVkID0gbm9ybWFsaXplZCArIFwiPVwiLnJlcGVhdCgoNCAtIChub3JtYWxpemVkLmxlbmd0aCAlIDQpKSAlIDQpO1xuICB0cnkge1xuICAgIGNvbnN0IGJpbmFyeSA9IGF0b2IocGFkZGVkKTtcbiAgICBjb25zdCBieXRlcyA9IFVpbnQ4QXJyYXkuZnJvbShiaW5hcnksIChjaCkgPT4gY2guY2hhckNvZGVBdCgwKSk7XG4gICAgcmV0dXJuIG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShieXRlcyk7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cblxuLyoqXG4gKiBEZWNvZGUgdGhlIEpXVCBwYXlsb2FkIGZyb20gYSBiZWFyZXIgdG9rZW4gc3RyaW5nIG9yIHJlcXVlc3QgaGVhZGVycy5cbiAqXG4gKiBXaGVuIGBpbnB1dGAgaXMgaGVhZGVyLWxpa2UsIHdhbGtzIGV2ZXJ5IHZhbHVlIGZvciBgaGVhZGVyTmFtZWAgKGRlZmF1bHRcbiAqIGB4LWZvcndhcmRlZC1hY2Nlc3MtdG9rZW5gKSBhbmQgbWVyZ2VzIGNsYWltIGtleXMgbGVmdC10by1yaWdodC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldEFjY2Vzc1Rva2VuUGF5bG9hZChcbiAgaW5wdXQ6IEhlYWRlckxpa2UgfCBzdHJpbmcsXG4gIGhlYWRlck5hbWU6IHN0cmluZyB8IHVuZGVmaW5lZCA9IFwieC1mb3J3YXJkZWQtYWNjZXNzLXRva2VuXCIsXG4pOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB7XG4gIGxldCBhY2Nlc3NUb2tlblBheWxvYWQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgdW5kZWZpbmVkO1xuICBpZiAoISh0eXBlb2YgaW5wdXQgPT09IFwic3RyaW5nXCIpKSB7XG4gICAgaWYgKGhlYWRlck5hbWUpIHtcbiAgICAgIGZvckVhY2hIZWFkZXJWYWx1ZShpbnB1dCwgaGVhZGVyTmFtZSwgKHZhbHVlOiBzdHJpbmcpID0+IHtcbiAgICAgICAgZm9yIChjb25zdCBbcGF5bG9hZEtleSwgcGF5bG9hZFZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhnZXRBY2Nlc3NUb2tlblBheWxvYWQodmFsdWUpKSkge1xuICAgICAgICAgIGlmICghYWNjZXNzVG9rZW5QYXlsb2FkIHx8ICEocGF5bG9hZEtleSBpbiBhY2Nlc3NUb2tlblBheWxvYWQpKSB7XG4gICAgICAgICAgICBpZiAoIWFjY2Vzc1Rva2VuUGF5bG9hZCkgYWNjZXNzVG9rZW5QYXlsb2FkID0ge307XG4gICAgICAgICAgICBhY2Nlc3NUb2tlblBheWxvYWRbcGF5bG9hZEtleV0gPSBwYXlsb2FkVmFsdWU7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgaW5wdXQgPSBpbnB1dC50cmltKCk7XG4gICAgaWYgKGlucHV0KSB7XG4gICAgICBjb25zdCBtYXRjaCA9IEJFQVJFUl9QUkVGSVhfUkVHRVguZXhlYyhpbnB1dCk7XG4gICAgICBpZiAobWF0Y2gpIHtcbiAgICAgICAgY29uc3QgZW5kSW5kZXggPSBtYXRjaC5pbmRleCArIG1hdGNoWzBdLmxlbmd0aDtcbiAgICAgICAgaW5wdXQgPSBpbnB1dC5zbGljZShlbmRJbmRleCk7XG4gICAgICB9XG4gICAgICBjb25zdCBwYXJ0cyA9IGlucHV0LnNwbGl0KFwiLlwiLCA0KTtcbiAgICAgIGlmIChwYXJ0cy5sZW5ndGggPT09IDIgfHwgcGFydHMubGVuZ3RoID09PSAzKSB7XG4gICAgICAgIC8vIEEgbWFsZm9ybWVkIHNlZ21lbnQgeWllbGRzIHVuZGVmaW5lZDsgZmFsbCB0aHJvdWdoIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgYWNjZXNzVG9rZW5QYXlsb2FkID0ganNvbi5wYXJzZVJlY29yZChkZWNvZGVKd3RTZWdtZW50KHBhcnRzWzFdISkpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICBpZiAoIWFjY2Vzc1Rva2VuUGF5bG9hZCkgYWNjZXNzVG9rZW5QYXlsb2FkID0ge307XG4gIGxvZy5kZWJ1ZyhcImdldEFjY2Vzc1Rva2VuUGF5bG9hZFwiLCB7IGFjY2Vzc1Rva2VuUGF5bG9hZCB9KTtcbiAgcmV0dXJuIGFjY2Vzc1Rva2VuUGF5bG9hZDtcbn1cblxuLyoqXG4gKiBPQXV0aCBzY29wZXMgZnJvbSB0aGUgYWNjZXNzLXRva2VuIEpXVCBvbiBgaW5wdXRgLlxuICpcbiAqIERlZmF1bHRzIHRvIHRoZSBgeC1mb3J3YXJkZWQtYWNjZXNzLXRva2VuYCBoZWFkZXIsIHdoaWNoIERhdGFicmlja3MgQXBwc1xuICogZm9yd2FyZCBmcm9tIHRoZSBicm93c2VyIHNlc3Npb24uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRBY2Nlc3NUb2tlblNjb3BlcyhcbiAgaW5wdXQ6IEhlYWRlckxpa2UgfCBzdHJpbmcsXG4gIGhlYWRlck5hbWU/OiBzdHJpbmcsXG4pOiBJdGVyYWJsZTxzdHJpbmc+IHtcbiAgY29uc3QgcGF5bG9hZCA9IGdldEFjY2Vzc1Rva2VuUGF5bG9hZChpbnB1dCwgaGVhZGVyTmFtZSk7XG4gIGxldCBhY2Nlc3NUb2tlblNjb3BlczogSXRlcmFibGU8c3RyaW5nPiA9IGl0ZXJhdGVDbGFpbXMocGF5bG9hZC5zY29wZSk7XG4gIGlmIChpc0xldmVsRW5hYmxlZChcImRlYnVnXCIpKSB7XG4gICAgYWNjZXNzVG9rZW5TY29wZXMgPSBBcnJheS5mcm9tKGFjY2Vzc1Rva2VuU2NvcGVzKTtcbiAgICBsb2cuZGVidWcoXCJnZXRBY2Nlc3NUb2tlblNjb3Blc1wiLCB7IGFjY2Vzc1Rva2VuU2NvcGVzIH0pO1xuICB9XG4gIHJldHVybiBhY2Nlc3NUb2tlblNjb3Blcztcbn1cblxuLyoqXG4gKiBSZXR1cm4gdHJ1ZSB3aGVuIGBzY29wZXNgIGNvbnRhaW5zIGFueSB2YWx1ZSBmcm9tIGBhbGxvd2VkYC5cbiAqXG4gKiBBY2NlcHRzIHRoZSByYXcge0BsaW5rIE1BU1RSQV9TQ09QRVNfS0VZfSBhcnJheSBzdGFtcGVkIG9uXG4gKiBgUmVxdWVzdENvbnRleHRgIGFzIHdlbGwgYXMgaXRlcmFibGVzIGZyb20ge0BsaW5rIGdldEFjY2Vzc1Rva2VuU2NvcGVzfS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGluY2x1ZGVzQWNjZXNzVG9rZW5TY29wZShzY29wZXM6IHVua25vd24sIGFsbG93ZWQ6IHJlYWRvbmx5IHN0cmluZ1tdKTogYm9vbGVhbiB7XG4gIGlmIChhbGxvd2VkLmxlbmd0aCkge1xuICAgIGZvciAoY29uc3Qgc2NvcGUgb2YgaXRlcmF0ZUNsYWltcyhzY29wZXMpKSB7XG4gICAgICBpZiAoYWxsb3dlZC5pbmNsdWRlcyhzY29wZSkpIHtcbiAgICAgICAgbG9nLmRlYnVnKFwiaW5jbHVkZXNBY2Nlc3NUb2tlblNjb3BlXCIsIHsgc2NvcGUsIGFsbG93ZWQgfSk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICByZXR1cm4gZmFsc2U7XG59XG5cbi8qKiBTcGxpdCBhIEpXVCBgc2NvcGVgIGNsYWltIHN0cmluZyBvciBhcnJheSBpbnRvIGluZGl2aWR1YWwgc2NvcGUgdG9rZW5zLiAqL1xuZnVuY3Rpb24qIGl0ZXJhdGVDbGFpbXMoaW5wdXQ6IHVua25vd24sIGRpc3RpbmN0ID0gdHJ1ZSk6IEl0ZXJhYmxlPHN0cmluZz4ge1xuICBjb25zdCBzZWVuID0gZGlzdGluY3QgPyBuZXcgU2V0PHN0cmluZz4oKSA6IHVuZGVmaW5lZDtcblxuICBmdW5jdGlvbiogdmlzaXQodmFsdWU6IHVua25vd24pOiBJdGVyYWJsZTxzdHJpbmc+IHtcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSBcInN0cmluZ1wiKSB7XG4gICAgICBmb3IgKGNvbnN0IGNsYWltIG9mIHZhbHVlLnNwbGl0KFNQTElUX1JFR0VYKSkge1xuICAgICAgICBjb25zdCB0b2tlbiA9IGNsYWltLnRyaW0oKTtcbiAgICAgICAgaWYgKCF0b2tlbiB8fCBzZWVuPy5oYXModG9rZW4pKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgc2Vlbj8uYWRkKHRva2VuKTtcbiAgICAgICAgeWllbGQgdG9rZW47XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkge1xuICAgICAgZm9yIChjb25zdCBpdGVtIG9mIHZhbHVlKSB7XG4gICAgICAgIHlpZWxkKiB2aXNpdChpdGVtKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICB5aWVsZCogdmlzaXQoaW5wdXQpO1xufVxuIl19
|
|
140
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9rZW4uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdG9rZW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7R0FPRztBQUVILE9BQU8sRUFBRSxrQkFBa0IsRUFBbUIsTUFBTSxXQUFXLENBQUM7QUFDaEUsT0FBTyxLQUFLLElBQUksTUFBTSxXQUFXLENBQUM7QUFDbEMsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFFbEQsTUFBTSxtQkFBbUIsR0FBRyxhQUFhLENBQUM7QUFDMUMsTUFBTSxXQUFXLEdBQUcsYUFBYSxDQUFDO0FBQ2xDLE1BQU0sR0FBRyxHQUFHLE1BQU0sQ0FBQyxjQUFjLENBQUMsQ0FBQztBQUVuQzs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sQ0FBQyxNQUFNLG1CQUFtQixHQUFHLDBCQUEwQixDQUFDO0FBRTlELDhEQUE4RDtBQUM5RCxNQUFNLENBQUMsTUFBTSxjQUFjLEdBQUcsa0JBQWtCLENBQUM7QUFFakQsNERBQTREO0FBQzVELE1BQU0sQ0FBQyxNQUFNLGlCQUFpQixHQUFHLG1CQUFtQixDQUFDO0FBRXJEOzs7R0FHRztBQUNILFNBQVMsZ0JBQWdCLENBQUMsT0FBZTtJQUN2QyxNQUFNLFVBQVUsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxHQUFHLENBQUMsQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDO0lBQ2pFLE1BQU0sTUFBTSxHQUFHLFVBQVUsR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQzFFLElBQUksQ0FBQztRQUNILE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUM1QixNQUFNLEtBQUssR0FBRyxVQUFVLENBQUMsSUFBSSxD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QU0sS0FBSyxDQUFDO1lBQ2QsQ0FBQztRQUNILENBQUM7YUFBTSxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUNoQyxLQUFLLE1BQU0sSUFBSSxJQUFJLEtBQUssRUFBRSxDQUFDO2dCQUN6QixLQUFLLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDckIsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBRUQsS0FBSyxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBQ3RCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEpXVCBhY2Nlc3MtdG9rZW4gaGVscGVycyBmb3IgRGF0YWJyaWNrcyBBcHBzLlxuICpcbiAqIFBhcnNlcyBiZWFyZXIgdG9rZW5zIGFuZCBgeC1mb3J3YXJkZWQtYWNjZXNzLXRva2VuYCBwYXlsb2FkcyB0byByZWFkXG4gKiBPQXV0aCBzY29wZXMgYW5kIG90aGVyIGNsYWltcyBmcm9tIGluY29taW5nIEhUVFAgcmVxdWVzdHMuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IGZvckVhY2hIZWFkZXJWYWx1ZSwgdHlwZSBIZWFkZXJMaWtlIH0gZnJvbSBcIi4vaHR0cC50c1wiO1xuaW1wb3J0ICogYXMganNvbiBmcm9tIFwiLi9qc29uLnRzXCI7XG5pbXBvcnQgeyBpc0xldmVsRW5hYmxlZCwgbG9nZ2VyIH0gZnJvbSBcIi4vbG9nLnRzXCI7XG5cbmNvbnN0IEJFQVJFUl9QUkVGSVhfUkVHRVggPSAvXmJlYXJlclxccysvaTtcbmNvbnN0IFNQTElUX1JFR0VYID0gL1xccyt8XFxzKixcXHMqLztcbmNvbnN0IGxvZyA9IGxvZ2dlcihcInNoYXJlZC90b2tlblwiKTtcblxuLyoqXG4gKiBIZWFkZXIgdGhlIERhdGFicmlja3MgQXBwcyBmcm9udCBkb29yIGZvcndhcmRzIHRoZSBjYWxsZXIncyBPQXV0aCAoT0JPKSB0b2tlblxuICogb24gLSB0aGUgZGVmYXVsdCBzb3VyY2UgZm9yIGV2ZXJ5IGhlbHBlciBoZXJlLlxuICpcbiAqIEV4cG9ydGVkIGJlY2F1c2UgaXQgaXMgYSB3aXJlIGNvbnRyYWN0IHNldmVyYWwgcGFja2FnZXMgYnJhbmNoIG9uLCBub3QganVzdCBhXG4gKiBkZWZhdWx0IGFyZ3VtZW50OiBgQGRieC10b29scy9hcHBraXRgJ3MgYGlkZW50aXR5YCBtb2R1bGUgZGVjaWRlcyB3aGV0aGVyIGFcbiAqIHJlcXVlc3QgY2FuIHVzZSBPQk8gYXV0aCBhdCBhbGwgYnkgaXRzIHByZXNlbmNlLCBhbmQgYEBkYngtdG9vbHMvY2xpLXR1bm5lbGBcbiAqIG11c3Qga25vdyB0aGUgbmFtZSB0byBzdHJpcCBpbmJvdW5kIGNvcGllcyBvZiBpdC4gT25lIHNwZWxsaW5nLCBvbmUgcGxhY2UuXG4gKi9cbmV4cG9ydCBjb25zdCBBQ0NFU1NfVE9LRU5fSEVBREVSID0gXCJ4LWZvcndhcmRlZC1hY2Nlc3MtdG9rZW5cIjtcblxuLyoqIEhlYWRlciB0aGUgZnJvbnQgZG9vciBmb3J3YXJkcyB0aGUgY2FsbGVyJ3MgdXNlciBpZCBvbi4gKi9cbmV4cG9ydCBjb25zdCBVU0VSX0lEX0hFQURFUiA9IFwieC1mb3J3YXJkZWQtdXNlclwiO1xuXG4vKiogSGVhZGVyIHRoZSBmcm9udCBkb29yIGZvcndhcmRzIHRoZSBjYWxsZXIncyBlbWFpbCBvbi4gKi9cbmV4cG9ydCBjb25zdCBVU0VSX0VNQUlMX0hFQURFUiA9IFwieC1mb3J3YXJkZWQtZW1haWxcIjtcblxuLyoqXG4gKiBEZWNvZGUgYSBKV1Qgc2VnbWVudCAoYmFzZTY0dXJsIHdpdGggc3RhbmRhcmQgYmFzZTY0IHBhZGRpbmcpLCBvclxuICogYHVuZGVmaW5lZGAgd2hlbiB0aGUgc2VnbWVudCBpcyBub3QgdmFsaWQgYmFzZTY0LlxuICovXG5mdW5jdGlvbiBkZWNvZGVKd3RTZWdtZW50KHNlZ21lbnQ6IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IG5vcm1hbGl6ZWQgPSBzZWdtZW50LnJlcGxhY2UoLy0vZywgXCIrXCIpLnJlcGxhY2UoL18vZywgXCIvXCIpO1xuICBjb25zdCBwYWRkZWQgPSBub3JtYWxpemVkICsgXCI9XCIucmVwZWF0KCg0IC0gKG5vcm1hbGl6ZWQubGVuZ3RoICUgNCkpICUgNCk7XG4gIHRyeSB7XG4gICAgY29uc3QgYmluYXJ5ID0gYXRvYihwYWRkZWQpO1xuICAgIGNvbnN0IGJ5dGVzID0gVWludDhBcnJheS5mcm9tKGJpbmFyeSwgKGNoKSA9PiBjaC5jaGFyQ29kZUF0KDApKTtcbiAgICByZXR1cm4gbmV3IFRleHREZWNvZGVyKCkuZGVjb2RlKGJ5dGVzKTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufVxuXG4vKipcbiAqIERlY29kZSB0aGUgSldUIHBheWxvYWQgZnJvbSBhIGJlYXJlciB0b2tlbiBzdHJpbmcgb3IgcmVxdWVzdCBoZWFkZXJzLlxuICpcbiAqIFdoZW4gYGlucHV0YCBpcyBoZWFkZXItbGlrZSwgd2Fsa3MgZXZlcnkgdmFsdWUgZm9yIGBoZWFkZXJOYW1lYCAoZGVmYXVsdFxuICogYHgtZm9yd2FyZGVkLWFjY2Vzcy10b2tlbmApIGFuZCBtZXJnZXMgY2xhaW0ga2V5cyBsZWZ0LXRvLXJpZ2h0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0QWNjZXNzVG9rZW5QYXlsb2FkKFxuICBpbnB1dDogSGVhZGVyTGlrZSB8IHN0cmluZyxcbiAgaGVhZGVyTmFtZTogc3RyaW5nIHwgdW5kZWZpbmVkID0gQUNDRVNTX1RPS0VOX0hFQURFUixcbik6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgbGV0IGFjY2Vzc1Rva2VuUGF5bG9hZDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCB1bmRlZmluZWQ7XG4gIGlmICghKHR5cGVvZiBpbnB1dCA9PT0gXCJzdHJpbmdcIikpIHtcbiAgICBpZiAoaGVhZGVyTmFtZSkge1xuICAgICAgZm9yRWFjaEhlYWRlclZhbHVlKGlucHV0LCBoZWFkZXJOYW1lLCAodmFsdWU6IHN0cmluZykgPT4ge1xuICAgICAgICBmb3IgKGNvbnN0IFtwYXlsb2FkS2V5LCBwYXlsb2FkVmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKGdldEFjY2Vzc1Rva2VuUGF5bG9hZCh2YWx1ZSkpKSB7XG4gICAgICAgICAgaWYgKCFhY2Nlc3NUb2tlblBheWxvYWQgfHwgIShwYXlsb2FkS2V5IGluIGFjY2Vzc1Rva2VuUGF5bG9hZCkpIHtcbiAgICAgICAgICAgIGlmICghYWNjZXNzVG9rZW5QYXlsb2FkKSBhY2Nlc3NUb2tlblBheWxvYWQgPSB7fTtcbiAgICAgICAgICAgIGFjY2Vzc1Rva2VuUGF5bG9hZFtwYXlsb2FkS2V5XSA9IHBheWxvYWRWYWx1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICBpbnB1dCA9IGlucHV0LnRyaW0oKTtcbiAgICBpZiAoaW5wdXQpIHtcbiAgICAgIGNvbnN0IG1hdGNoID0gQkVBUkVSX1BSRUZJWF9SRUdFWC5leGVjKGlucHV0KTtcbiAgICAgIGlmIChtYXRjaCkge1xuICAgICAgICBjb25zdCBlbmRJbmRleCA9IG1hdGNoLmluZGV4ICsgbWF0Y2hbMF0ubGVuZ3RoO1xuICAgICAgICBpbnB1dCA9IGlucHV0LnNsaWNlKGVuZEluZGV4KTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHBhcnRzID0gaW5wdXQuc3BsaXQoXCIuXCIsIDQpO1xuICAgICAgaWYgKHBhcnRzLmxlbmd0aCA9PT0gMiB8fCBwYXJ0cy5sZW5ndGggPT09IDMpIHtcbiAgICAgICAgLy8gQSBtYWxmb3JtZWQgc2VnbWVudCB5aWVsZHMgdW5kZWZpbmVkOyBmYWxsIHRocm91Z2ggdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICBhY2Nlc3NUb2tlblBheWxvYWQgPSBqc29uLnBhcnNlUmVjb3JkKGRlY29kZUp3dFNlZ21lbnQocGFydHNbMV0hKSk7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIGlmICghYWNjZXNzVG9rZW5QYXlsb2FkKSBhY2Nlc3NUb2tlblBheWxvYWQgPSB7fTtcbiAgbG9nLmRlYnVnKFwiZ2V0QWNjZXNzVG9rZW5QYXlsb2FkXCIsIHsgYWNjZXNzVG9rZW5QYXlsb2FkIH0pO1xuICByZXR1cm4gYWNjZXNzVG9rZW5QYXlsb2FkO1xufVxuXG4vKipcbiAqIE9BdXRoIHNjb3BlcyBmcm9tIHRoZSBhY2Nlc3MtdG9rZW4gSldUIG9uIGBpbnB1dGAuXG4gKlxuICogRGVmYXVsdHMgdG8gdGhlIGB4LWZvcndhcmRlZC1hY2Nlc3MtdG9rZW5gIGhlYWRlciwgd2hpY2ggRGF0YWJyaWNrcyBBcHBzXG4gKiBmb3J3YXJkIGZyb20gdGhlIGJyb3dzZXIgc2Vzc2lvbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldEFjY2Vzc1Rva2VuU2NvcGVzKFxuICBpbnB1dDogSGVhZGVyTGlrZSB8IHN0cmluZyxcbiAgaGVhZGVyTmFtZT86IHN0cmluZyxcbik6IEl0ZXJhYmxlPHN0cmluZz4ge1xuICBjb25zdCBwYXlsb2FkID0gZ2V0QWNjZXNzVG9rZW5QYXlsb2FkKGlucHV0LCBoZWFkZXJOYW1lKTtcbiAgbGV0IGFjY2Vzc1Rva2VuU2NvcGVzOiBJdGVyYWJsZTxzdHJpbmc+ID0gaXRlcmF0ZUNsYWltcyhwYXlsb2FkLnNjb3BlKTtcbiAgaWYgKGlzTGV2ZWxFbmFibGVkKFwiZGVidWdcIikpIHtcbiAgICBhY2Nlc3NUb2tlblNjb3BlcyA9IEFycmF5LmZyb20oYWNjZXNzVG9rZW5TY29wZXMpO1xuICAgIGxvZy5kZWJ1ZyhcImdldEFjY2Vzc1Rva2VuU2NvcGVzXCIsIHsgYWNjZXNzVG9rZW5TY29wZXMgfSk7XG4gIH1cbiAgcmV0dXJuIGFjY2Vzc1Rva2VuU2NvcGVzO1xufVxuXG4vKipcbiAqIFJldHVybiB0cnVlIHdoZW4gYHNjb3Blc2AgY29udGFpbnMgYW55IHZhbHVlIGZyb20gYGFsbG93ZWRgLlxuICpcbiAqIEFjY2VwdHMgdGhlIHJhdyB7QGxpbmsgTUFTVFJBX1NDT1BFU19LRVl9IGFycmF5IHN0YW1wZWQgb25cbiAqIGBSZXF1ZXN0Q29udGV4dGAgYXMgd2VsbCBhcyBpdGVyYWJsZXMgZnJvbSB7QGxpbmsgZ2V0QWNjZXNzVG9rZW5TY29wZXN9LlxuICovXG5leHBvcnQgZnVuY3Rpb24gaW5jbHVkZXNBY2Nlc3NUb2tlblNjb3BlKHNjb3BlczogdW5rbm93biwgYWxsb3dlZDogcmVhZG9ubHkgc3RyaW5nW10pOiBib29sZWFuIHtcbiAgaWYgKGFsbG93ZWQubGVuZ3RoKSB7XG4gICAgZm9yIChjb25zdCBzY29wZSBvZiBpdGVyYXRlQ2xhaW1zKHNjb3BlcykpIHtcbiAgICAgIGlmIChhbGxvd2VkLmluY2x1ZGVzKHNjb3BlKSkge1xuICAgICAgICBsb2cuZGVidWcoXCJpbmNsdWRlc0FjY2Vzc1Rva2VuU2NvcGVcIiwgeyBzY29wZSwgYWxsb3dlZCB9KTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHJldHVybiBmYWxzZTtcbn1cblxuLyoqIFNwbGl0IGEgSldUIGBzY29wZWAgY2xhaW0gc3RyaW5nIG9yIGFycmF5IGludG8gaW5kaXZpZHVhbCBzY29wZSB0b2tlbnMuICovXG5mdW5jdGlvbiogaXRlcmF0ZUNsYWltcyhpbnB1dDogdW5rbm93biwgZGlzdGluY3QgPSB0cnVlKTogSXRlcmFibGU8c3RyaW5nPiB7XG4gIGNvbnN0IHNlZW4gPSBkaXN0aW5jdCA/IG5ldyBTZXQ8c3RyaW5nPigpIDogdW5kZWZpbmVkO1xuXG4gIGZ1bmN0aW9uKiB2aXNpdCh2YWx1ZTogdW5rbm93bik6IEl0ZXJhYmxlPHN0cmluZz4ge1xuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIGZvciAoY29uc3QgY2xhaW0gb2YgdmFsdWUuc3BsaXQoU1BMSVRfUkVHRVgpKSB7XG4gICAgICAgIGNvbnN0IHRva2VuID0gY2xhaW0udHJpbSgpO1xuICAgICAgICBpZiAoIXRva2VuIHx8IHNlZW4/Lmhhcyh0b2tlbikpIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICBzZWVuPy5hZGQodG9rZW4pO1xuICAgICAgICB5aWVsZCB0b2tlbjtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKEFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICBmb3IgKGNvbnN0IGl0ZW0gb2YgdmFsdWUpIHtcbiAgICAgICAgeWllbGQqIHZpc2l0KGl0ZW0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHlpZWxkKiB2aXNpdChpbnB1dCk7XG59XG4iXX0=
|
package/lib/tsconfig.tsbuildinfo
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/async.ts","../src/brand.ts","../src/error.ts","../src/function.ts","../src/hash.ts","../src/http.ts","../src/json.ts","../src/log.ts","../src/net.ts","../src/object.ts","../src/predicate.ts","../src/string.ts","../src/token.ts","../index.ts"],"version":"5.9.3"}
|
|
1
|
+
{"root":["../src/async.ts","../src/brand.ts","../src/env.ts","../src/error.ts","../src/execution.ts","../src/function.ts","../src/hash.ts","../src/http.ts","../src/json.ts","../src/log.ts","../src/net.ts","../src/object.ts","../src/pattern.ts","../src/predicate.ts","../src/string.ts","../src/token.ts","../index.ts"],"version":"5.9.3"}
|
package/package.json
CHANGED
package/src/env.ts
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading configuration out of the environment.
|
|
3
|
+
*
|
|
4
|
+
* Every plugin config in this repo resolves the same way: take the typed
|
|
5
|
+
* config value when the caller set one, else fall back to one or more
|
|
6
|
+
* environment variables, else a default. Written by hand that becomes a
|
|
7
|
+
* `config.x ?? Number(process.env.X)` chain per field, and each package grew
|
|
8
|
+
* its own `fromEnv` / `resolvePositiveInt` helper with slightly different
|
|
9
|
+
* coercion rules. These are those helpers, once.
|
|
10
|
+
*
|
|
11
|
+
* Browser-safe: `process` is reached through `globalThis` and guarded, so this
|
|
12
|
+
* module needs no Node types and is inert in a browser (every lookup misses and
|
|
13
|
+
* the caller's fallback applies).
|
|
14
|
+
*
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { toBoolean } from "./object.ts";
|
|
19
|
+
import { parseList, trimToNull } from "./string.ts";
|
|
20
|
+
|
|
21
|
+
/** `process`-shaped view off `globalThis`, so no node types are needed. */
|
|
22
|
+
interface ProcessLike {
|
|
23
|
+
env?: Record<string, string | undefined>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** One env var name, or several tried in order. */
|
|
27
|
+
export type EnvKey = string | readonly string[];
|
|
28
|
+
|
|
29
|
+
/** The ambient environment, or `{}` off-process (a browser). */
|
|
30
|
+
function environment(): Record<string, string | undefined> {
|
|
31
|
+
return (globalThis as { process?: ProcessLike }).process?.env ?? {};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* First non-empty value among `keys`, trimmed, else `null`.
|
|
36
|
+
*
|
|
37
|
+
* Several names for one setting is the norm (a package-specific variable plus
|
|
38
|
+
* the Databricks-standard one), so `keys` is order-sensitive: earlier names win.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* env.text(["TEAMS_APP_ID", "MICROSOFT_APP_ID"]);
|
|
42
|
+
*/
|
|
43
|
+
export function text(keys: EnvKey): string | null {
|
|
44
|
+
const env = environment();
|
|
45
|
+
for (const key of typeof keys === "string" ? [keys] : keys) {
|
|
46
|
+
const value = trimToNull(env[key]);
|
|
47
|
+
if (value !== null) return value;
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Resolve a string setting: `configured` when set and non-empty, else the first
|
|
54
|
+
* non-empty variable among `keys`, else `null`.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* env.string(config.host, "SMTP_HOST");
|
|
58
|
+
*/
|
|
59
|
+
export function string(configured: unknown, keys: EnvKey): string | null {
|
|
60
|
+
return trimToNull(configured) ?? text(keys);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Resolve a boolean setting through {@link toBoolean}, so the loose spellings an
|
|
65
|
+
* env var actually carries (`1`, `on`, `yes`, ...) are accepted. Returns
|
|
66
|
+
* `undefined` when neither source is interpretable, letting the caller pick a
|
|
67
|
+
* default with `??`.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* env.boolean(config.fuzzy, "WEB_SEARCH_FUZZY") ?? true;
|
|
71
|
+
*/
|
|
72
|
+
export function boolean(configured: unknown, keys: EnvKey): boolean | undefined {
|
|
73
|
+
return toBoolean(configured) ?? toBoolean(text(keys));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Resolve a positive-number setting that may be fractional (a score threshold,
|
|
78
|
+
* a ratio): `configured` when it is a finite number greater than zero, else the
|
|
79
|
+
* first variable among `keys` that parses that way, else `fallback`.
|
|
80
|
+
*
|
|
81
|
+
* {@link positiveInt} is the right choice for a count; this one keeps the
|
|
82
|
+
* fraction, so a `0.4` threshold does not floor to `0`.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* env.positiveNumber(config.fuzzyThreshold, "SEARCH_FUZZY_THRESHOLD", 0.4);
|
|
86
|
+
*/
|
|
87
|
+
export function positiveNumber(configured: unknown, keys: EnvKey, fallback: number): number {
|
|
88
|
+
return toPositiveNumber(configured) ?? toPositiveNumber(text(keys)) ?? fallback;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Resolve a positive-integer setting (a port, timeout, page size, or cap):
|
|
93
|
+
* `configured` when it is a finite number greater than zero, else the first
|
|
94
|
+
* variable among `keys` that parses that way, else `fallback`. Floored, so a
|
|
95
|
+
* fractional value can't leak into a count.
|
|
96
|
+
*
|
|
97
|
+
* A non-numeric or non-positive value is treated as absent rather than fatal -
|
|
98
|
+
* these are ceilings and timeouts where a sane default beats a boot failure.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* env.positiveInt(config.timeoutMs, "SEARCH_TIMEOUT_MS", 30_000);
|
|
102
|
+
*/
|
|
103
|
+
export function positiveInt(configured: unknown, keys: EnvKey, fallback: number): number {
|
|
104
|
+
return toPositiveInt(configured) ?? toPositiveInt(text(keys)) ?? fallback;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function toPositiveNumber(value: unknown): number | undefined {
|
|
108
|
+
if (value === null || value === undefined || value === "") return undefined;
|
|
109
|
+
const parsed = Number(value);
|
|
110
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function toPositiveInt(value: unknown): number | undefined {
|
|
114
|
+
const parsed = toPositiveNumber(value);
|
|
115
|
+
return parsed === undefined ? undefined : Math.floor(parsed);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Resolve a list setting through {@link parseList}, so an array from typed
|
|
120
|
+
* config and a `"a, b c"` env string normalize identically. Returns `[]` when
|
|
121
|
+
* neither source has entries.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* env.list(config.modelFallbacks, "WEB_SEARCH_MODEL_FALLBACKS");
|
|
125
|
+
*/
|
|
126
|
+
export function list(
|
|
127
|
+
configured: string | readonly string[] | undefined | null,
|
|
128
|
+
keys: EnvKey,
|
|
129
|
+
transform?: (entry: string) => string,
|
|
130
|
+
): string[] {
|
|
131
|
+
const fromConfig = parseList(configured, transform);
|
|
132
|
+
return fromConfig.length > 0 ? fromConfig : parseList(text(keys), transform);
|
|
133
|
+
}
|
package/src/execution.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/** Generic helpers for AppKit-style intercepted execution. */
|
|
2
|
+
import * as async from "./async.ts";
|
|
3
|
+
import * as error from "./error.ts";
|
|
4
|
+
import * as object from "./object.ts";
|
|
5
|
+
|
|
6
|
+
/** Success/failure shape returned by an interceptor-backed executor. */
|
|
7
|
+
export type ExecutionResult<T> =
|
|
8
|
+
{ ok: true; data: T } | { ok: false; status: number; message: string };
|
|
9
|
+
|
|
10
|
+
/** Function signature shared by AppKit plugin executors. */
|
|
11
|
+
export type Executor<Settings> = <T>(
|
|
12
|
+
fn: (signal?: AbortSignal) => Promise<T>,
|
|
13
|
+
settings: Settings,
|
|
14
|
+
) => Promise<ExecutionResult<T>>;
|
|
15
|
+
|
|
16
|
+
/** Failure details supplied when an intercepted operation cannot complete. */
|
|
17
|
+
export interface ExecutionFailure {
|
|
18
|
+
operation: string;
|
|
19
|
+
status: number;
|
|
20
|
+
message: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Options for running and unwrapping one intercepted operation. */
|
|
24
|
+
export interface RunOptions<T, Settings> {
|
|
25
|
+
operation: string;
|
|
26
|
+
settings: Settings;
|
|
27
|
+
execute: Executor<Settings>;
|
|
28
|
+
fn: (signal?: AbortSignal) => Promise<T>;
|
|
29
|
+
signal?: AbortSignal;
|
|
30
|
+
canceled: () => Error;
|
|
31
|
+
failed: (failure: ExecutionFailure) => Error;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function errorStatus(value: unknown): number {
|
|
35
|
+
if (!object.isRecord(value)) return 500;
|
|
36
|
+
const status = value.statusCode;
|
|
37
|
+
return typeof status === "number" && Number.isFinite(status) ? status : 500;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Build the executor used before a plugin installs its interceptor chain.
|
|
42
|
+
* Errors are mapped onto the same result shape as AppKit's `Plugin.execute()`.
|
|
43
|
+
*/
|
|
44
|
+
export function directExecutor<Settings>(): Executor<Settings> {
|
|
45
|
+
return async (fn) => {
|
|
46
|
+
try {
|
|
47
|
+
return { ok: true, data: await fn() };
|
|
48
|
+
} catch (cause) {
|
|
49
|
+
return {
|
|
50
|
+
ok: false,
|
|
51
|
+
status: errorStatus(cause),
|
|
52
|
+
message: error.errorMessage(cause),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Run an operation through an executor, merge cancellation, and unwrap its result. */
|
|
59
|
+
export async function run<T, Settings>(options: RunOptions<T, Settings>): Promise<T> {
|
|
60
|
+
const result = await options.execute(
|
|
61
|
+
(executeSignal) => options.fn(async.combineAbortSignals(executeSignal, options.signal)),
|
|
62
|
+
options.settings,
|
|
63
|
+
);
|
|
64
|
+
if (result.ok) return result.data;
|
|
65
|
+
if (options.signal?.aborted) throw options.canceled();
|
|
66
|
+
throw options.failed({
|
|
67
|
+
operation: options.operation,
|
|
68
|
+
status: result.status,
|
|
69
|
+
message: result.message,
|
|
70
|
+
});
|
|
71
|
+
}
|
package/src/object.ts
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Value guards / coercions / shape types: {@link isRecord} narrows parsed JSON
|
|
5
5
|
* to a record, {@link toBoolean} coerces loose truthy/falsy values, {@link
|
|
6
|
-
*
|
|
7
|
-
* describe object
|
|
6
|
+
* optional} spreads a field only when it is present, {@link deepEqual} compares
|
|
7
|
+
* structurally, and {@link NameLike}/{@link NonFunctionKeys} describe object
|
|
8
|
+
* shapes.
|
|
8
9
|
*
|
|
9
10
|
* Iterable helpers: {@link generator} flattens mixed arguments; {@link sequence}
|
|
10
11
|
* wraps source(s) in a lazy, `Array`-compatible {@link Sequence}. Every
|
|
@@ -812,6 +813,28 @@ export function isRecord(value: unknown): value is Record<string, unknown> {
|
|
|
812
813
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
813
814
|
}
|
|
814
815
|
|
|
816
|
+
/**
|
|
817
|
+
* `{ [key]: value }` when `value` is present, otherwise `undefined` - so an
|
|
818
|
+
* absent optional field stays ABSENT when spread, rather than becoming an
|
|
819
|
+
* explicit `undefined` that `exactOptionalPropertyTypes` rejects.
|
|
820
|
+
*
|
|
821
|
+
* Spelling that inline costs a repeated, double-evaluated ternary per field
|
|
822
|
+
* (`...(v ? { key: v } : {})`), which is how config resolvers end up computing
|
|
823
|
+
* the same value twice.
|
|
824
|
+
*
|
|
825
|
+
* @example
|
|
826
|
+
* return {
|
|
827
|
+
* ...optional("appId", env.text("MICROSOFT_APP_ID")),
|
|
828
|
+
* ...optional("endpoint", config.endpoint),
|
|
829
|
+
* };
|
|
830
|
+
*/
|
|
831
|
+
export function optional<K extends string, V>(
|
|
832
|
+
key: K,
|
|
833
|
+
value: V | null | undefined,
|
|
834
|
+
): Record<K, V> | undefined {
|
|
835
|
+
return value === null || value === undefined ? undefined : ({ [key]: value } as Record<K, V>);
|
|
836
|
+
}
|
|
837
|
+
|
|
815
838
|
/**
|
|
816
839
|
* Coerce a loose boolean-ish value to a real `boolean`, or `undefined`
|
|
817
840
|
* when it can't be interpreted. Recognizes `true`/`t`/`on`/`1`/`yes`/`y`
|
package/src/pattern.ts
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Literal / glob / regex string matching, compiled to a composable
|
|
3
|
+
* {@link Predicate}.
|
|
4
|
+
*
|
|
5
|
+
* A configurable allow-list is the same shape everywhere in this repo: a list of
|
|
6
|
+
* patterns from a config field or an env var, where an operator reasonably
|
|
7
|
+
* expects to write a plain value, a `*` wildcard, or - when neither is enough -
|
|
8
|
+
* a real regex. Each consumer used to grow its own `globToRegExp` +
|
|
9
|
+
* `/pattern/flags` parser; this is that parser, once.
|
|
10
|
+
*
|
|
11
|
+
* Three shapes are recognized per entry, tried in order:
|
|
12
|
+
*
|
|
13
|
+
* - **regex** - wrapped in slashes (`/^x-mastra-/`, with optional trailing
|
|
14
|
+
* flags). Compiled as written. An invalid regex never matches: it is skipped
|
|
15
|
+
* with a warning rather than throwing, so one bad entry cannot take a process
|
|
16
|
+
* down at startup.
|
|
17
|
+
* - **glob** - contains `*` or `?` (`x-mastra-*`). Shell-style, anchored at both
|
|
18
|
+
* ends: `*` matches any run of characters, `?` exactly one.
|
|
19
|
+
* - **literal** - anything else. Whole-string equality.
|
|
20
|
+
*
|
|
21
|
+
* Matching is case-INSENSITIVE by default, which is what the callers want (HTTP
|
|
22
|
+
* header names and email addresses are both case-insensitive); pass
|
|
23
|
+
* `caseSensitive` to opt out. An empty pattern list matches NOTHING, so a
|
|
24
|
+
* caller that treats "no patterns" as "permit everything" must special-case it
|
|
25
|
+
* rather than relying on the matcher.
|
|
26
|
+
*
|
|
27
|
+
* Browser-safe: hand-compiled to `RegExp` with no glob dependency, so this stays
|
|
28
|
+
* usable from a client bundle. Node code that needs path-aware globbing
|
|
29
|
+
* (`/` as a segment boundary, `**`) wants `@dbx-tools/path`'s `toPathMatcher`
|
|
30
|
+
* instead - that one is `minimatch`-backed and understands path semantics.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* const allowed = toPatternMatcher(["x-mastra-*", "/^x-trace-/"]);
|
|
34
|
+
* allowed("x-mastra-thread-id"); // true
|
|
35
|
+
* allowed("x-forwarded-user"); // false
|
|
36
|
+
*
|
|
37
|
+
* @module
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
import { logger } from "./log.ts";
|
|
41
|
+
import * as predicate from "./predicate.ts";
|
|
42
|
+
import { parseList } from "./string.ts";
|
|
43
|
+
|
|
44
|
+
const log = logger("shared/pattern");
|
|
45
|
+
|
|
46
|
+
/** Options for {@link toPattern} / {@link toPatternMatcher}. */
|
|
47
|
+
export interface PatternOptions {
|
|
48
|
+
/** Match case-sensitively. Default `false` (case-insensitive). */
|
|
49
|
+
caseSensitive?: boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Escape a string for literal use inside a `RegExp`. */
|
|
53
|
+
export function escapeRegExp(value: string): string {
|
|
54
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** True when `pattern` is a `/.../flags` regex literal. */
|
|
58
|
+
function isRegexLiteral(pattern: string): boolean {
|
|
59
|
+
return pattern.length > 1 && pattern.startsWith("/") && /\/[a-z]*$/i.test(pattern);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** True when `pattern` contains a glob wildcard. */
|
|
63
|
+
function isGlob(pattern: string): boolean {
|
|
64
|
+
return pattern.includes("*") || pattern.includes("?");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Compile a `/pattern/flags` literal, or `undefined` when it is malformed or
|
|
69
|
+
* the body is not a valid regex.
|
|
70
|
+
*/
|
|
71
|
+
function compileRegexLiteral(pattern: string, caseSensitive: boolean): RegExp | undefined {
|
|
72
|
+
const parsed = /^\/(.+)\/([a-z]*)$/is.exec(pattern);
|
|
73
|
+
if (!parsed) return undefined;
|
|
74
|
+
const body = parsed[1]!;
|
|
75
|
+
const flags = parsed[2]!;
|
|
76
|
+
try {
|
|
77
|
+
return new RegExp(body, caseSensitive || flags.includes("i") ? flags : `${flags}i`);
|
|
78
|
+
} catch (error) {
|
|
79
|
+
log.warn("ignoring invalid regex pattern", { pattern, error });
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Compile a shell-style glob (`*`, `?`) into an anchored `RegExp`. Every other
|
|
86
|
+
* character is escaped, so a glob can safely contain regex metacharacters
|
|
87
|
+
* (`x-app.*` matches a literal dot followed by anything).
|
|
88
|
+
*/
|
|
89
|
+
function compileGlob(pattern: string, caseSensitive: boolean): RegExp {
|
|
90
|
+
const body = pattern
|
|
91
|
+
.split(/([*?])/)
|
|
92
|
+
.map((part) => (part === "*" ? ".*" : part === "?" ? "." : escapeRegExp(part)))
|
|
93
|
+
.join("");
|
|
94
|
+
return new RegExp(`^${body}$`, caseSensitive ? "" : "i");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Compile ONE pattern into a predicate, or `undefined` when the entry is empty
|
|
99
|
+
* or an unparseable regex literal.
|
|
100
|
+
*
|
|
101
|
+
* Callers that want a whole list should use {@link toPatternMatcher}; this is
|
|
102
|
+
* exported for the case where a consumer applies its own semantics to some
|
|
103
|
+
* shapes and only wants the glob/regex handling (the email gate's bare-domain
|
|
104
|
+
* shortcut, for one).
|
|
105
|
+
*/
|
|
106
|
+
export function toPattern(
|
|
107
|
+
pattern: string,
|
|
108
|
+
options: PatternOptions = {},
|
|
109
|
+
): predicate.Predicate<string> | undefined {
|
|
110
|
+
const trimmed = pattern.trim();
|
|
111
|
+
if (!trimmed) return undefined;
|
|
112
|
+
const caseSensitive = options.caseSensitive ?? false;
|
|
113
|
+
|
|
114
|
+
if (isRegexLiteral(trimmed)) {
|
|
115
|
+
const compiled = compileRegexLiteral(trimmed, caseSensitive);
|
|
116
|
+
return compiled && predicate.create<string>((value) => compiled.test(value));
|
|
117
|
+
}
|
|
118
|
+
if (isGlob(trimmed)) {
|
|
119
|
+
const compiled = compileGlob(trimmed, caseSensitive);
|
|
120
|
+
return predicate.create<string>((value) => compiled.test(value));
|
|
121
|
+
}
|
|
122
|
+
// Literal: whole-string equality.
|
|
123
|
+
const expected = caseSensitive ? trimmed : trimmed.toLowerCase();
|
|
124
|
+
return predicate.create<string>((value) =>
|
|
125
|
+
caseSensitive ? value === expected : value.toLowerCase() === expected,
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Compile patterns into a single OR'd {@link Predicate}. Accepts the raw config
|
|
131
|
+
* shapes {@link parseList} does - an array, or one comma/whitespace-separated
|
|
132
|
+
* string - so a field and its env var need no separate handling.
|
|
133
|
+
*
|
|
134
|
+
* With no usable patterns the result always returns `false`.
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* const forwardable = toPatternMatcher(process.env.TUNNEL_FORWARD_HEADERS);
|
|
138
|
+
*/
|
|
139
|
+
export function toPatternMatcher(
|
|
140
|
+
patterns: string | readonly string[] | undefined | null,
|
|
141
|
+
options: PatternOptions = {},
|
|
142
|
+
): predicate.Predicate<string> {
|
|
143
|
+
const compiled = parseList(patterns)
|
|
144
|
+
.map((pattern) => toPattern(pattern, options))
|
|
145
|
+
.filter((value): value is predicate.Predicate<string> => value !== undefined);
|
|
146
|
+
if (compiled.length === 0) return predicate.create<string>(() => false);
|
|
147
|
+
return compiled.slice(1).reduce((acc, next) => acc.or(next), compiled[0]!);
|
|
148
|
+
}
|
package/src/token.ts
CHANGED
|
@@ -15,6 +15,23 @@ const BEARER_PREFIX_REGEX = /^bearer\s+/i;
|
|
|
15
15
|
const SPLIT_REGEX = /\s+|\s*,\s*/;
|
|
16
16
|
const log = logger("shared/token");
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Header the Databricks Apps front door forwards the caller's OAuth (OBO) token
|
|
20
|
+
* on - the default source for every helper here.
|
|
21
|
+
*
|
|
22
|
+
* Exported because it is a wire contract several packages branch on, not just a
|
|
23
|
+
* default argument: `@dbx-tools/appkit`'s `identity` module decides whether a
|
|
24
|
+
* request can use OBO auth at all by its presence, and `@dbx-tools/cli-tunnel`
|
|
25
|
+
* must know the name to strip inbound copies of it. One spelling, one place.
|
|
26
|
+
*/
|
|
27
|
+
export const ACCESS_TOKEN_HEADER = "x-forwarded-access-token";
|
|
28
|
+
|
|
29
|
+
/** Header the front door forwards the caller's user id on. */
|
|
30
|
+
export const USER_ID_HEADER = "x-forwarded-user";
|
|
31
|
+
|
|
32
|
+
/** Header the front door forwards the caller's email on. */
|
|
33
|
+
export const USER_EMAIL_HEADER = "x-forwarded-email";
|
|
34
|
+
|
|
18
35
|
/**
|
|
19
36
|
* Decode a JWT segment (base64url with standard base64 padding), or
|
|
20
37
|
* `undefined` when the segment is not valid base64.
|
|
@@ -39,7 +56,7 @@ function decodeJwtSegment(segment: string): string | undefined {
|
|
|
39
56
|
*/
|
|
40
57
|
export function getAccessTokenPayload(
|
|
41
58
|
input: HeaderLike | string,
|
|
42
|
-
headerName: string | undefined =
|
|
59
|
+
headerName: string | undefined = ACCESS_TOKEN_HEADER,
|
|
43
60
|
): Record<string, unknown> {
|
|
44
61
|
let accessTokenPayload: Record<string, unknown> | undefined;
|
|
45
62
|
if (!(typeof input === "string")) {
|