@dbx-tools/shared-core 0.6.48 → 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 CHANGED
@@ -261,6 +261,36 @@ const internal = cidr ? net.ipInCidr("10.1.2.3", cidr) : false;
261
261
  `net.pathMatch()` compares path prefixes on segment boundaries. IP/CIDR helpers
262
262
  parse IPv4 and IPv6 into a shared bigint comparison model.
263
263
 
264
+ ## Allow-List Patterns
265
+
266
+ ```ts
267
+ // One matcher from a config array OR a delimited env string.
268
+ const forwardable = pattern.toPatternMatcher(["x-mastra-*", "/^x-trace-/", "x-tenant"]);
269
+
270
+ forwardable("x-mastra-model"); // true (glob)
271
+ forwardable("x-trace-parent"); // true (regex literal)
272
+ forwardable("x-tenant"); // true (literal, whole-string)
273
+ forwardable("x-forwarded-user"); // false
274
+ ```
275
+
276
+ Every configurable allow-list in this repo takes the same three shapes, so the
277
+ compilation lives here once: a `/regex/` literal (with optional flags), a
278
+ shell-style glob (`*`, `?`, anchored at both ends, all other characters escaped),
279
+ or a literal compared whole-string. Matching is case-insensitive by default -
280
+ what HTTP header names and email addresses both want - and `caseSensitive` opts
281
+ out.
282
+
283
+ An invalid regex is skipped with a warning instead of throwing, so one bad
284
+ config entry cannot stop a process from starting. No usable patterns yields a
285
+ matcher that always returns `false`; a caller that reads "no patterns" as "permit
286
+ everything" must say so itself. The result is a `predicate`, so it composes with
287
+ `.and()` / `.or()` / `.negate()`.
288
+
289
+ Reach for [`@dbx-tools/path`](../../node/path)'s `toPathMatcher` instead when
290
+ matching a filesystem path or URL path, where `/` is a segment boundary and `**`
291
+ is meaningful - that one is `minimatch`-backed. This module is deliberately
292
+ dependency-free so it stays usable in a browser bundle.
293
+
264
294
  ## Token Claims
265
295
 
266
296
  ```ts
@@ -312,6 +342,8 @@ without paying formatting cost when disabled.
312
342
  - `env` - config-over-environment resolution: strings, booleans, positive
313
343
  numbers/integers, and lists, with env-name fallback chains.
314
344
  - `predicate` - composable boolean/type predicates.
345
+ - `pattern` - literal / glob / `/regex/` allow-list matching compiled to a
346
+ predicate.
315
347
  - `http` - header iteration, cookie parsing, and fetch error creation.
316
348
  - `execution` - direct executor fallback, cancellation merging, and result unwrapping.
317
349
  - `net` - URL building, email parsing, path matching, IP/CIDR helpers.
package/index.ts CHANGED
@@ -14,6 +14,7 @@ export * as json from "./src/json.ts";
14
14
  export * as log from "./src/log.ts";
15
15
  export * as net from "./src/net.ts";
16
16
  export * as object from "./src/object.ts";
17
+ export * as pattern from "./src/pattern.ts";
17
18
  export * as predicate from "./src/predicate.ts";
18
19
  export * as string from "./src/string.ts";
19
20
  export * as token from "./src/token.ts";
@@ -28,5 +29,7 @@ export type { HeaderLike } from "./src/http.ts";
28
29
  export type { LogLevel, Logger } from "./src/log.ts";
29
30
  export type { UrlLike, IpVersion, ParsedIp, Cidr, UrlBuilder, ParseEmailsOptions } from "./src/net.ts";
30
31
  export type { Sequence, Container, Collection, OneOrMany, NameLike, NonFunctionKeys, DeepEqualComparator } from "./src/object.ts";
32
+ export type { PatternOptions } from "./src/pattern.ts";
31
33
  export type { PredicateFunction, TypePredicateFunction, PredicateInput, Predicate } from "./src/predicate.ts";
32
34
  export type { TokenizeOptions, KeyOptions, IdentifierOptions, Description } from "./src/string.ts";
35
+ export { ACCESS_TOKEN_HEADER, USER_ID_HEADER, USER_EMAIL_HEADER } from "./src/token.ts";
package/lib/index.d.ts CHANGED
@@ -10,6 +10,7 @@ export * as json from "./src/json.ts";
10
10
  export * as log from "./src/log.ts";
11
11
  export * as net from "./src/net.ts";
12
12
  export * as object from "./src/object.ts";
13
+ export * as pattern from "./src/pattern.ts";
13
14
  export * as predicate from "./src/predicate.ts";
14
15
  export * as string from "./src/string.ts";
15
16
  export * as token from "./src/token.ts";
@@ -24,5 +25,7 @@ export type { HeaderLike } from "./src/http.ts";
24
25
  export type { LogLevel, Logger } from "./src/log.ts";
25
26
  export type { UrlLike, IpVersion, ParsedIp, Cidr, UrlBuilder, ParseEmailsOptions } from "./src/net.ts";
26
27
  export type { Sequence, Container, Collection, OneOrMany, NameLike, NonFunctionKeys, DeepEqualComparator } from "./src/object.ts";
28
+ export type { PatternOptions } from "./src/pattern.ts";
27
29
  export type { PredicateFunction, TypePredicateFunction, PredicateInput, Predicate } from "./src/predicate.ts";
28
30
  export type { TokenizeOptions, KeyOptions, IdentifierOptions, Description } from "./src/string.ts";
31
+ export { ACCESS_TOKEN_HEADER, USER_ID_HEADER, USER_EMAIL_HEADER } from "./src/token.ts";
package/lib/index.js CHANGED
@@ -13,8 +13,10 @@ export * as json from "./src/json.js";
13
13
  export * as log from "./src/log.js";
14
14
  export * as net from "./src/net.js";
15
15
  export * as object from "./src/object.js";
16
+ export * as pattern from "./src/pattern.js";
16
17
  export * as predicate from "./src/predicate.js";
17
18
  export * as string from "./src/string.js";
18
19
  export * as token from "./src/token.js";
19
20
  export { DEFAULT_BRAND_ASSETS, BrandAssetSetSchema, BrandColorsSchema, BrandVoiceSchema, BrandContextSchema, defaultBrandContext } from "./src/brand.js";
20
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwyQ0FBMkM7QUFDM0MsbURBQW1EO0FBQ25ELHdFQUF3RTtBQUV4RSxPQUFPLEtBQUssS0FBSyxNQUFNLGdCQUFnQixDQUFDO0FBQ3hDLE9BQU8sS0FBSyxLQUFLLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEMsT0FBTyxLQUFLLEdBQUcsTUFBTSxjQUFjLENBQUM7QUFDcEMsT0FBTyxLQUFLLEtBQUssTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QyxPQUFPLEtBQUssU0FBUyxNQUFNLG9CQUFvQixDQUFDO0FBQ2hELE9BQU8sS0FBSyxjQUFjLE1BQU0sbUJBQW1CLENBQUM7QUFDcEQsT0FBTyxLQUFLLElBQUksTUFBTSxlQUFlLENBQUM7QUFDdEMsT0FBTyxLQUFLLElBQUksTUFBTSxlQUFlLENBQUM7QUFDdEMsT0FBTyxLQUFLLElBQUksTUFBTSxlQUFlLENBQUM7QUFDdEMsT0FBTyxLQUFLLEdBQUcsTUFBTSxjQUFjLENBQUM7QUFDcEMsT0FBTyxLQUFLLEdBQUcsTUFBTSxjQUFjLENBQUM7QUFDcEMsT0FBTyxLQUFLLE1BQU0sTUFBTSxpQkFBaUIsQ0FBQztBQUMxQyxPQUFPLEtBQUssU0FBUyxNQUFNLG9CQUFvQixDQUFDO0FBQ2hELE9BQU8sS0FBSyxNQUFNLE1BQU0saUJBQWlCLENBQUM7QUFDMUMsT0FBTyxLQUFLLEtBQUssTUFBTSxnQkFBZ0IsQ0FBQztBQUV4QyxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsbUJBQW1CLEVBQUUsaUJBQWlCLEVBQUUsZ0JBQWdCLEVBQUUsa0JBQWtCLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIEdFTkVSQVRFRCBieSBwcm9qZW4gd2F0Y2ggLSBETyBOT1QgRURJVC5cbi8vIFJlZ2VuZXJhdGVkIGZyb20gdGhlIGV4cG9ydGluZyBtb2R1bGVzIGluIC4vc3JjLlxuLy8gSGFuZCBlZGl0cyBhcmUgb3ZlcndyaXR0ZW4gb24gdGhlIG5leHQgd2F0Y2g7IHRoaXMgZmlsZSBpcyByZWFkLW9ubHkuXG5cbmV4cG9ydCAqIGFzIGFzeW5jIGZyb20gXCIuL3NyYy9hc3luYy50c1wiO1xuZXhwb3J0ICogYXMgYnJhbmQgZnJvbSBcIi4vc3JjL2JyYW5kLnRzXCI7XG5leHBvcnQgKiBhcyBlbnYgZnJvbSBcIi4vc3JjL2Vudi50c1wiO1xuZXhwb3J0ICogYXMgZXJyb3IgZnJvbSBcIi4vc3JjL2Vycm9yLnRzXCI7XG5leHBvcnQgKiBhcyBleGVjdXRpb24gZnJvbSBcIi4vc3JjL2V4ZWN1dGlvbi50c1wiO1xuZXhwb3J0ICogYXMgZnVuY3Rpb25Nb2R1bGUgZnJvbSBcIi4vc3JjL2Z1bmN0aW9uLnRzXCI7XG5leHBvcnQgKiBhcyBoYXNoIGZyb20gXCIuL3NyYy9oYXNoLnRzXCI7XG5leHBvcnQgKiBhcyBodHRwIGZyb20gXCIuL3NyYy9odHRwLnRzXCI7XG5leHBvcnQgKiBhcyBqc29uIGZyb20gXCIuL3NyYy9qc29uLnRzXCI7XG5leHBvcnQgKiBhcyBsb2cgZnJvbSBcIi4vc3JjL2xvZy50c1wiO1xuZXhwb3J0ICogYXMgbmV0IGZyb20gXCIuL3NyYy9uZXQudHNcIjtcbmV4cG9ydCAqIGFzIG9iamVjdCBmcm9tIFwiLi9zcmMvb2JqZWN0LnRzXCI7XG5leHBvcnQgKiBhcyBwcmVkaWNhdGUgZnJvbSBcIi4vc3JjL3ByZWRpY2F0ZS50c1wiO1xuZXhwb3J0ICogYXMgc3RyaW5nIGZyb20gXCIuL3NyYy9zdHJpbmcudHNcIjtcbmV4cG9ydCAqIGFzIHRva2VuIGZyb20gXCIuL3NyYy90b2tlbi50c1wiO1xuZXhwb3J0IHR5cGUgeyBQb2xsQ29udGV4dCwgUG9sbFByb2R1Y2VyLCBQb2xsT3B0aW9ucyB9IGZyb20gXCIuL3NyYy9hc3luYy50c1wiO1xuZXhwb3J0IHsgREVGQVVMVF9CUkFORF9BU1NFVFMsIEJyYW5kQXNzZXRTZXRTY2hlbWEsIEJyYW5kQ29sb3JzU2NoZW1hLCBCcmFuZFZvaWNlU2NoZW1hLCBCcmFuZENvbnRleHRTY2hlbWEsIGRlZmF1bHRCcmFuZENvbnRleHQgfSBmcm9tIFwiLi9zcmMvYnJhbmQudHNcIjtcbmV4cG9ydCB0eXBlIHsgQnJhbmRDb250ZXh0LCBCcmFuZENvbnRleHRJbnB1dCwgQnJhbmRBc3NldFNldCB9IGZyb20gXCIuL3NyYy9icmFuZC50c1wiO1xuZXhwb3J0IHR5cGUgeyBFbnZLZXkgfSBmcm9tIFwiLi9zcmMvZW52LnRzXCI7XG5leHBvcnQgdHlwZSB7IEVycm9yQ29udGV4dCB9IGZyb20gXCIuL3NyYy9lcnJvci50c1wiO1xuZXhwb3J0IHR5cGUgeyBFeGVjdXRpb25SZXN1bHQsIEV4ZWN1dG9yLCBFeGVjdXRpb25GYWlsdXJlLCBSdW5PcHRpb25zIH0gZnJvbSBcIi4vc3JjL2V4ZWN1dGlvbi50c1wiO1xuZXhwb3J0IHR5cGUgeyBNZW1vaXplT3B0aW9ucyB9IGZyb20gXCIuL3NyYy9mdW5jdGlvbi50c1wiO1xuZXhwb3J0IHR5cGUgeyBIZWFkZXJMaWtlIH0gZnJvbSBcIi4vc3JjL2h0dHAudHNcIjtcbmV4cG9ydCB0eXBlIHsgTG9nTGV2ZWwsIExvZ2dlciB9IGZyb20gXCIuL3NyYy9sb2cudHNcIjtcbmV4cG9ydCB0eXBlIHsgVXJsTGlrZSwgSXBWZXJzaW9uLCBQYXJzZWRJcCwgQ2lkciwgVXJsQnVpbGRlciwgUGFyc2VFbWFpbHNPcHRpb25zIH0gZnJvbSBcIi4vc3JjL25ldC50c1wiO1xuZXhwb3J0IHR5cGUgeyBTZXF1ZW5jZSwgQ29udGFpbmVyLCBDb2xsZWN0aW9uLCBPbmVPck1hbnksIE5hbWVMaWtlLCBOb25GdW5jdGlvbktleXMsIERlZXBFcXVhbENvbXBhcmF0b3IgfSBmcm9tIFwiLi9zcmMvb2JqZWN0LnRzXCI7XG5leHBvcnQgdHlwZSB7IFByZWRpY2F0ZUZ1bmN0aW9uLCBUeXBlUHJlZGljYXRlRnVuY3Rpb24sIFByZWRpY2F0ZUlucHV0LCBQcmVkaWNhdGUgfSBmcm9tIFwiLi9zcmMvcHJlZGljYXRlLnRzXCI7XG5leHBvcnQgdHlwZSB7IFRva2VuaXplT3B0aW9ucywgS2V5T3B0aW9ucywgSWRlbnRpZmllck9wdGlvbnMsIERlc2NyaXB0aW9uIH0gZnJvbSBcIi4vc3JjL3N0cmluZy50c1wiO1xuIl19
21
+ export { ACCESS_TOKEN_HEADER, USER_ID_HEADER, USER_EMAIL_HEADER } from "./src/token.js";
22
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwyQ0FBMkM7QUFDM0MsbURBQW1EO0FBQ25ELHdFQUF3RTtBQUV4RSxPQUFPLEtBQUssS0FBSyxNQUFNLGdCQUFnQixDQUFDO0FBQ3hDLE9BQU8sS0FBSyxLQUFLLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEMsT0FBTyxLQUFLLEdBQUcsTUFBTSxjQUFjLENBQUM7QUFDcEMsT0FBTyxLQUFLLEtBQUssTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QyxPQUFPLEtBQUssU0FBUyxNQUFNLG9CQUFvQixDQUFDO0FBQ2hELE9BQU8sS0FBSyxjQUFjLE1BQU0sbUJBQW1CLENBQUM7QUFDcEQsT0FBTyxLQUFLLElBQUksTUFBTSxlQUFlLENBQUM7QUFDdEMsT0FBTyxLQUFLLElBQUksTUFBTSxlQUFlLENBQUM7QUFDdEMsT0FBTyxLQUFLLElBQUksTUFBTSxlQUFlLENBQUM7QUFDdEMsT0FBTyxLQUFLLEdBQUcsTUFBTSxjQUFjLENBQUM7QUFDcEMsT0FBTyxLQUFLLEdBQUcsTUFBTSxjQUFjLENBQUM7QUFDcEMsT0FBTyxLQUFLLE1BQU0sTUFBTSxpQkFBaUIsQ0FBQztBQUMxQyxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBQzVDLE9BQU8sS0FBSyxTQUFTLE1BQU0sb0JBQW9CLENBQUM7QUFDaEQsT0FBTyxLQUFLLE1BQU0sTUFBTSxpQkFBaUIsQ0FBQztBQUMxQyxPQUFPLEtBQUssS0FBSyxNQUFNLGdCQUFnQixDQUFDO0FBRXhDLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxtQkFBbUIsRUFBRSxpQkFBaUIsRUFBRSxnQkFBZ0IsRUFBRSxrQkFBa0IsRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBYXpKLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxjQUFjLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIEdFTkVSQVRFRCBieSBwcm9qZW4gd2F0Y2ggLSBETyBOT1QgRURJVC5cbi8vIFJlZ2VuZXJhdGVkIGZyb20gdGhlIGV4cG9ydGluZyBtb2R1bGVzIGluIC4vc3JjLlxuLy8gSGFuZCBlZGl0cyBhcmUgb3ZlcndyaXR0ZW4gb24gdGhlIG5leHQgd2F0Y2g7IHRoaXMgZmlsZSBpcyByZWFkLW9ubHkuXG5cbmV4cG9ydCAqIGFzIGFzeW5jIGZyb20gXCIuL3NyYy9hc3luYy50c1wiO1xuZXhwb3J0ICogYXMgYnJhbmQgZnJvbSBcIi4vc3JjL2JyYW5kLnRzXCI7XG5leHBvcnQgKiBhcyBlbnYgZnJvbSBcIi4vc3JjL2Vudi50c1wiO1xuZXhwb3J0ICogYXMgZXJyb3IgZnJvbSBcIi4vc3JjL2Vycm9yLnRzXCI7XG5leHBvcnQgKiBhcyBleGVjdXRpb24gZnJvbSBcIi4vc3JjL2V4ZWN1dGlvbi50c1wiO1xuZXhwb3J0ICogYXMgZnVuY3Rpb25Nb2R1bGUgZnJvbSBcIi4vc3JjL2Z1bmN0aW9uLnRzXCI7XG5leHBvcnQgKiBhcyBoYXNoIGZyb20gXCIuL3NyYy9oYXNoLnRzXCI7XG5leHBvcnQgKiBhcyBodHRwIGZyb20gXCIuL3NyYy9odHRwLnRzXCI7XG5leHBvcnQgKiBhcyBqc29uIGZyb20gXCIuL3NyYy9qc29uLnRzXCI7XG5leHBvcnQgKiBhcyBsb2cgZnJvbSBcIi4vc3JjL2xvZy50c1wiO1xuZXhwb3J0ICogYXMgbmV0IGZyb20gXCIuL3NyYy9uZXQudHNcIjtcbmV4cG9ydCAqIGFzIG9iamVjdCBmcm9tIFwiLi9zcmMvb2JqZWN0LnRzXCI7XG5leHBvcnQgKiBhcyBwYXR0ZXJuIGZyb20gXCIuL3NyYy9wYXR0ZXJuLnRzXCI7XG5leHBvcnQgKiBhcyBwcmVkaWNhdGUgZnJvbSBcIi4vc3JjL3ByZWRpY2F0ZS50c1wiO1xuZXhwb3J0ICogYXMgc3RyaW5nIGZyb20gXCIuL3NyYy9zdHJpbmcudHNcIjtcbmV4cG9ydCAqIGFzIHRva2VuIGZyb20gXCIuL3NyYy90b2tlbi50c1wiO1xuZXhwb3J0IHR5cGUgeyBQb2xsQ29udGV4dCwgUG9sbFByb2R1Y2VyLCBQb2xsT3B0aW9ucyB9IGZyb20gXCIuL3NyYy9hc3luYy50c1wiO1xuZXhwb3J0IHsgREVGQVVMVF9CUkFORF9BU1NFVFMsIEJyYW5kQXNzZXRTZXRTY2hlbWEsIEJyYW5kQ29sb3JzU2NoZW1hLCBCcmFuZFZvaWNlU2NoZW1hLCBCcmFuZENvbnRleHRTY2hlbWEsIGRlZmF1bHRCcmFuZENvbnRleHQgfSBmcm9tIFwiLi9zcmMvYnJhbmQudHNcIjtcbmV4cG9ydCB0eXBlIHsgQnJhbmRDb250ZXh0LCBCcmFuZENvbnRleHRJbnB1dCwgQnJhbmRBc3NldFNldCB9IGZyb20gXCIuL3NyYy9icmFuZC50c1wiO1xuZXhwb3J0IHR5cGUgeyBFbnZLZXkgfSBmcm9tIFwiLi9zcmMvZW52LnRzXCI7XG5leHBvcnQgdHlwZSB7IEVycm9yQ29udGV4dCB9IGZyb20gXCIuL3NyYy9lcnJvci50c1wiO1xuZXhwb3J0IHR5cGUgeyBFeGVjdXRpb25SZXN1bHQsIEV4ZWN1dG9yLCBFeGVjdXRpb25GYWlsdXJlLCBSdW5PcHRpb25zIH0gZnJvbSBcIi4vc3JjL2V4ZWN1dGlvbi50c1wiO1xuZXhwb3J0IHR5cGUgeyBNZW1vaXplT3B0aW9ucyB9IGZyb20gXCIuL3NyYy9mdW5jdGlvbi50c1wiO1xuZXhwb3J0IHR5cGUgeyBIZWFkZXJMaWtlIH0gZnJvbSBcIi4vc3JjL2h0dHAudHNcIjtcbmV4cG9ydCB0eXBlIHsgTG9nTGV2ZWwsIExvZ2dlciB9IGZyb20gXCIuL3NyYy9sb2cudHNcIjtcbmV4cG9ydCB0eXBlIHsgVXJsTGlrZSwgSXBWZXJzaW9uLCBQYXJzZWRJcCwgQ2lkciwgVXJsQnVpbGRlciwgUGFyc2VFbWFpbHNPcHRpb25zIH0gZnJvbSBcIi4vc3JjL25ldC50c1wiO1xuZXhwb3J0IHR5cGUgeyBTZXF1ZW5jZSwgQ29udGFpbmVyLCBDb2xsZWN0aW9uLCBPbmVPck1hbnksIE5hbWVMaWtlLCBOb25GdW5jdGlvbktleXMsIERlZXBFcXVhbENvbXBhcmF0b3IgfSBmcm9tIFwiLi9zcmMvb2JqZWN0LnRzXCI7XG5leHBvcnQgdHlwZSB7IFBhdHRlcm5PcHRpb25zIH0gZnJvbSBcIi4vc3JjL3BhdHRlcm4udHNcIjtcbmV4cG9ydCB0eXBlIHsgUHJlZGljYXRlRnVuY3Rpb24sIFR5cGVQcmVkaWNhdGVGdW5jdGlvbiwgUHJlZGljYXRlSW5wdXQsIFByZWRpY2F0ZSB9IGZyb20gXCIuL3NyYy9wcmVkaWNhdGUudHNcIjtcbmV4cG9ydCB0eXBlIHsgVG9rZW5pemVPcHRpb25zLCBLZXlPcHRpb25zLCBJZGVudGlmaWVyT3B0aW9ucywgRGVzY3JpcHRpb24gfSBmcm9tIFwiLi9zcmMvc3RyaW5nLnRzXCI7XG5leHBvcnQgeyBBQ0NFU1NfVE9LRU5fSEVBREVSLCBVU0VSX0lEX0hFQURFUiwgVVNFUl9FTUFJTF9IRUFERVIgfSBmcm9tIFwiLi9zcmMvdG9rZW4udHNcIjtcbiJdfQ==
@@ -0,0 +1,67 @@
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
+ import * as predicate from "./predicate.ts";
40
+ /** Options for {@link toPattern} / {@link toPatternMatcher}. */
41
+ export interface PatternOptions {
42
+ /** Match case-sensitively. Default `false` (case-insensitive). */
43
+ caseSensitive?: boolean;
44
+ }
45
+ /** Escape a string for literal use inside a `RegExp`. */
46
+ export declare function escapeRegExp(value: string): string;
47
+ /**
48
+ * Compile ONE pattern into a predicate, or `undefined` when the entry is empty
49
+ * or an unparseable regex literal.
50
+ *
51
+ * Callers that want a whole list should use {@link toPatternMatcher}; this is
52
+ * exported for the case where a consumer applies its own semantics to some
53
+ * shapes and only wants the glob/regex handling (the email gate's bare-domain
54
+ * shortcut, for one).
55
+ */
56
+ export declare function toPattern(pattern: string, options?: PatternOptions): predicate.Predicate<string> | undefined;
57
+ /**
58
+ * Compile patterns into a single OR'd {@link Predicate}. Accepts the raw config
59
+ * shapes {@link parseList} does - an array, or one comma/whitespace-separated
60
+ * string - so a field and its env var need no separate handling.
61
+ *
62
+ * With no usable patterns the result always returns `false`.
63
+ *
64
+ * @example
65
+ * const forwardable = toPatternMatcher(process.env.TUNNEL_FORWARD_HEADERS);
66
+ */
67
+ export declare function toPatternMatcher(patterns: string | readonly string[] | undefined | null, options?: PatternOptions): predicate.Predicate<string>;
@@ -0,0 +1,129 @@
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
+ import { logger } from "./log.js";
40
+ import * as predicate from "./predicate.js";
41
+ import { parseList } from "./string.js";
42
+ const log = logger("shared/pattern");
43
+ /** Escape a string for literal use inside a `RegExp`. */
44
+ export function escapeRegExp(value) {
45
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
46
+ }
47
+ /** True when `pattern` is a `/.../flags` regex literal. */
48
+ function isRegexLiteral(pattern) {
49
+ return pattern.length > 1 && pattern.startsWith("/") && /\/[a-z]*$/i.test(pattern);
50
+ }
51
+ /** True when `pattern` contains a glob wildcard. */
52
+ function isGlob(pattern) {
53
+ return pattern.includes("*") || pattern.includes("?");
54
+ }
55
+ /**
56
+ * Compile a `/pattern/flags` literal, or `undefined` when it is malformed or
57
+ * the body is not a valid regex.
58
+ */
59
+ function compileRegexLiteral(pattern, caseSensitive) {
60
+ const parsed = /^\/(.+)\/([a-z]*)$/is.exec(pattern);
61
+ if (!parsed)
62
+ return undefined;
63
+ const body = parsed[1];
64
+ const flags = parsed[2];
65
+ try {
66
+ return new RegExp(body, caseSensitive || flags.includes("i") ? flags : `${flags}i`);
67
+ }
68
+ catch (error) {
69
+ log.warn("ignoring invalid regex pattern", { pattern, error });
70
+ return undefined;
71
+ }
72
+ }
73
+ /**
74
+ * Compile a shell-style glob (`*`, `?`) into an anchored `RegExp`. Every other
75
+ * character is escaped, so a glob can safely contain regex metacharacters
76
+ * (`x-app.*` matches a literal dot followed by anything).
77
+ */
78
+ function compileGlob(pattern, caseSensitive) {
79
+ const body = pattern
80
+ .split(/([*?])/)
81
+ .map((part) => (part === "*" ? ".*" : part === "?" ? "." : escapeRegExp(part)))
82
+ .join("");
83
+ return new RegExp(`^${body}$`, caseSensitive ? "" : "i");
84
+ }
85
+ /**
86
+ * Compile ONE pattern into a predicate, or `undefined` when the entry is empty
87
+ * or an unparseable regex literal.
88
+ *
89
+ * Callers that want a whole list should use {@link toPatternMatcher}; this is
90
+ * exported for the case where a consumer applies its own semantics to some
91
+ * shapes and only wants the glob/regex handling (the email gate's bare-domain
92
+ * shortcut, for one).
93
+ */
94
+ export function toPattern(pattern, options = {}) {
95
+ const trimmed = pattern.trim();
96
+ if (!trimmed)
97
+ return undefined;
98
+ const caseSensitive = options.caseSensitive ?? false;
99
+ if (isRegexLiteral(trimmed)) {
100
+ const compiled = compileRegexLiteral(trimmed, caseSensitive);
101
+ return compiled && predicate.create((value) => compiled.test(value));
102
+ }
103
+ if (isGlob(trimmed)) {
104
+ const compiled = compileGlob(trimmed, caseSensitive);
105
+ return predicate.create((value) => compiled.test(value));
106
+ }
107
+ // Literal: whole-string equality.
108
+ const expected = caseSensitive ? trimmed : trimmed.toLowerCase();
109
+ return predicate.create((value) => caseSensitive ? value === expected : value.toLowerCase() === expected);
110
+ }
111
+ /**
112
+ * Compile patterns into a single OR'd {@link Predicate}. Accepts the raw config
113
+ * shapes {@link parseList} does - an array, or one comma/whitespace-separated
114
+ * string - so a field and its env var need no separate handling.
115
+ *
116
+ * With no usable patterns the result always returns `false`.
117
+ *
118
+ * @example
119
+ * const forwardable = toPatternMatcher(process.env.TUNNEL_FORWARD_HEADERS);
120
+ */
121
+ export function toPatternMatcher(patterns, options = {}) {
122
+ const compiled = parseList(patterns)
123
+ .map((pattern) => toPattern(pattern, options))
124
+ .filter((value) => value !== undefined);
125
+ if (compiled.length === 0)
126
+ return predicate.create(() => false);
127
+ return compiled.slice(1).reduce((acc, next) => acc.or(next), compiled[0]);
128
+ }
129
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGF0dGVybi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wYXR0ZXJuLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBcUNHO0FBRUgsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUNsQyxPQUFPLEtBQUssU0FBUyxNQUFNLGdCQUFnQixDQUFDO0FBQzVDLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFeEMsTUFBTSxHQUFHLEdBQUcsTUFBTSxDQUFDLGdCQUFnQixDQUFDLENBQUM7QUFRckMseURBQXlEO0FBQ3pELE1BQU0sVUFBVSxZQUFZLENBQUMsS0FBYTtJQUN4QyxPQUFPLEtBQUssQ0FBQyxPQUFPLENBQUMscUJBQXFCLEVBQUUsTUFBTSxDQUFDLENBQUM7QUFDdEQsQ0FBQztBQUVELDJEQUEyRDtBQUMzRCxTQUFTLGNBQWMsQ0FBQyxPQUFlO0lBQ3JDLE9BQU8sT0FBTyxDQUFDLE1BQU0sR0FBRyxDQUFDLElBQUksT0FBTyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsSUFBSSxZQUFZLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0FBQ3JGLENBQUM7QUFFRCxvREFBb0Q7QUFDcEQsU0FBUyxNQUFNLENBQUMsT0FBZTtJQUM3QixPQUFPLE9BQU8sQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLElBQUksT0FBTyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUN4RCxDQUFDO0FBRUQ7OztHQUdHO0FBQ0gsU0FBUyxtQkFBbUIsQ0FBQyxPQUFlLEVBQUUsYUFBc0I7SUFDbEUsTUFBTSxNQUFNLEdBQUcsc0JBQXNCLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3BELElBQUksQ0FBQyxNQUFNO1FBQUUsT0FBTyxTQUFTLENBQUM7SUFDOUIsTUFBTSxJQUFJLEdBQUcsTUFBTSxD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RSxFQUFFLENBQUMsU0FBUyxDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQztTQUM3QyxNQUFNLENBQUMsQ0FBQyxLQUFLLEVBQXdDLEVBQUUsQ0FBQyxLQUFLLEtBQUssU0FBUyxDQUFDLENBQUM7SUFDaEYsSUFBSSxRQUFRLENBQUMsTUFBTSxLQUFLLENBQUM7UUFBRSxPQUFPLFNBQVMsQ0FBQyxNQUFNLENBQVMsR0FBRyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDeEUsT0FBTyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsRUFBRSxJQUFJLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBRSxDQUFDLENBQUM7QUFDN0UsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogTGl0ZXJhbCAvIGdsb2IgLyByZWdleCBzdHJpbmcgbWF0Y2hpbmcsIGNvbXBpbGVkIHRvIGEgY29tcG9zYWJsZVxuICoge0BsaW5rIFByZWRpY2F0ZX0uXG4gKlxuICogQSBjb25maWd1cmFibGUgYWxsb3ctbGlzdCBpcyB0aGUgc2FtZSBzaGFwZSBldmVyeXdoZXJlIGluIHRoaXMgcmVwbzogYSBsaXN0IG9mXG4gKiBwYXR0ZXJucyBmcm9tIGEgY29uZmlnIGZpZWxkIG9yIGFuIGVudiB2YXIsIHdoZXJlIGFuIG9wZXJhdG9yIHJlYXNvbmFibHlcbiAqIGV4cGVjdHMgdG8gd3JpdGUgYSBwbGFpbiB2YWx1ZSwgYSBgKmAgd2lsZGNhcmQsIG9yIC0gd2hlbiBuZWl0aGVyIGlzIGVub3VnaCAtXG4gKiBhIHJlYWwgcmVnZXguIEVhY2ggY29uc3VtZXIgdXNlZCB0byBncm93IGl0cyBvd24gYGdsb2JUb1JlZ0V4cGAgK1xuICogYC9wYXR0ZXJuL2ZsYWdzYCBwYXJzZXI7IHRoaXMgaXMgdGhhdCBwYXJzZXIsIG9uY2UuXG4gKlxuICogVGhyZWUgc2hhcGVzIGFyZSByZWNvZ25pemVkIHBlciBlbnRyeSwgdHJpZWQgaW4gb3JkZXI6XG4gKlxuICogLSAqKnJlZ2V4KiogLSB3cmFwcGVkIGluIHNsYXNoZXMgKGAvXngtbWFzdHJhLS9gLCB3aXRoIG9wdGlvbmFsIHRyYWlsaW5nXG4gKiAgIGZsYWdzKS4gQ29tcGlsZWQgYXMgd3JpdHRlbi4gQW4gaW52YWxpZCByZWdleCBuZXZlciBtYXRjaGVzOiBpdCBpcyBza2lwcGVkXG4gKiAgIHdpdGggYSB3YXJuaW5nIHJhdGhlciB0aGFuIHRocm93aW5nLCBzbyBvbmUgYmFkIGVudHJ5IGNhbm5vdCB0YWtlIGEgcHJvY2Vzc1xuICogICBkb3duIGF0IHN0YXJ0dXAuXG4gKiAtICoqZ2xvYioqIC0gY29udGFpbnMgYCpgIG9yIGA/YCAoYHgtbWFzdHJhLSpgKS4gU2hlbGwtc3R5bGUsIGFuY2hvcmVkIGF0IGJvdGhcbiAqICAgZW5kczogYCpgIG1hdGNoZXMgYW55IHJ1biBvZiBjaGFyYWN0ZXJzLCBgP2AgZXhhY3RseSBvbmUuXG4gKiAtICoqbGl0ZXJhbCoqIC0gYW55dGhpbmcgZWxzZS4gV2hvbGUtc3RyaW5nIGVxdWFsaXR5LlxuICpcbiAqIE1hdGNoaW5nIGlzIGNhc2UtSU5TRU5TSVRJVkUgYnkgZGVmYXVsdCwgd2hpY2ggaXMgd2hhdCB0aGUgY2FsbGVycyB3YW50IChIVFRQXG4gKiBoZWFkZXIgbmFtZXMgYW5kIGVtYWlsIGFkZHJlc3NlcyBhcmUgYm90aCBjYXNlLWluc2Vuc2l0aXZlKTsgcGFzc1xuICogYGNhc2VTZW5zaXRpdmVgIHRvIG9wdCBvdXQuIEFuIGVtcHR5IHBhdHRlcm4gbGlzdCBtYXRjaGVzIE5PVEhJTkcsIHNvIGFcbiAqIGNhbGxlciB0aGF0IHRyZWF0cyBcIm5vIHBhdHRlcm5zXCIgYXMgXCJwZXJtaXQgZXZlcnl0aGluZ1wiIG11c3Qgc3BlY2lhbC1jYXNlIGl0XG4gKiByYXRoZXIgdGhhbiByZWx5aW5nIG9uIHRoZSBtYXRjaGVyLlxuICpcbiAqIEJyb3dzZXItc2FmZTogaGFuZC1jb21waWxlZCB0byBgUmVnRXhwYCB3aXRoIG5vIGdsb2IgZGVwZW5kZW5jeSwgc28gdGhpcyBzdGF5c1xuICogdXNhYmxlIGZyb20gYSBjbGllbnQgYnVuZGxlLiBOb2RlIGNvZGUgdGhhdCBuZWVkcyBwYXRoLWF3YXJlIGdsb2JiaW5nXG4gKiAoYC9gIGFzIGEgc2VnbWVudCBib3VuZGFyeSwgYCoqYCkgd2FudHMgYEBkYngtdG9vbHMvcGF0aGAncyBgdG9QYXRoTWF0Y2hlcmBcbiAqIGluc3RlYWQgLSB0aGF0IG9uZSBpcyBgbWluaW1hdGNoYC1iYWNrZWQgYW5kIHVuZGVyc3RhbmRzIHBhdGggc2VtYW50aWNzLlxuICpcbiAqIEBleGFtcGxlXG4gKiBjb25zdCBhbGxvd2VkID0gdG9QYXR0ZXJuTWF0Y2hlcihbXCJ4LW1hc3RyYS0qXCIsIFwiL154LXRyYWNlLS9cIl0pO1xuICogYWxsb3dlZChcIngtbWFzdHJhLXRocmVhZC1pZFwiKTsgLy8gdHJ1ZVxuICogYWxsb3dlZChcIngtZm9yd2FyZGVkLXVzZXJcIik7ICAgLy8gZmFsc2VcbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSBcIi4vbG9nLnRzXCI7XG5pbXBvcnQgKiBhcyBwcmVkaWNhdGUgZnJvbSBcIi4vcHJlZGljYXRlLnRzXCI7XG5pbXBvcnQgeyBwYXJzZUxpc3QgfSBmcm9tIFwiLi9zdHJpbmcudHNcIjtcblxuY29uc3QgbG9nID0gbG9nZ2VyKFwic2hhcmVkL3BhdHRlcm5cIik7XG5cbi8qKiBPcHRpb25zIGZvciB7QGxpbmsgdG9QYXR0ZXJufSAvIHtAbGluayB0b1BhdHRlcm5NYXRjaGVyfS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUGF0dGVybk9wdGlvbnMge1xuICAvKiogTWF0Y2ggY2FzZS1zZW5zaXRpdmVseS4gRGVmYXVsdCBgZmFsc2VgIChjYXNlLWluc2Vuc2l0aXZlKS4gKi9cbiAgY2FzZVNlbnNpdGl2ZT86IGJvb2xlYW47XG59XG5cbi8qKiBFc2NhcGUgYSBzdHJpbmcgZm9yIGxpdGVyYWwgdXNlIGluc2lkZSBhIGBSZWdFeHBgLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGVzY2FwZVJlZ0V4cCh2YWx1ZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIHZhbHVlLnJlcGxhY2UoL1suKis/XiR7fSgpfFtcXF1cXFxcXS9nLCBcIlxcXFwkJlwiKTtcbn1cblxuLyoqIFRydWUgd2hlbiBgcGF0dGVybmAgaXMgYSBgLy4uLi9mbGFnc2AgcmVnZXggbGl0ZXJhbC4gKi9cbmZ1bmN0aW9uIGlzUmVnZXhMaXRlcmFsKHBhdHRlcm46IHN0cmluZyk6IGJvb2xlYW4ge1xuICByZXR1cm4gcGF0dGVybi5sZW5ndGggPiAxICYmIHBhdHRlcm4uc3RhcnRzV2l0aChcIi9cIikgJiYgL1xcL1thLXpdKiQvaS50ZXN0KHBhdHRlcm4pO1xufVxuXG4vKiogVHJ1ZSB3aGVuIGBwYXR0ZXJuYCBjb250YWlucyBhIGdsb2Igd2lsZGNhcmQuICovXG5mdW5jdGlvbiBpc0dsb2IocGF0dGVybjogc3RyaW5nKTogYm9vbGVhbiB7XG4gIHJldHVybiBwYXR0ZXJuLmluY2x1ZGVzKFwiKlwiKSB8fCBwYXR0ZXJuLmluY2x1ZGVzKFwiP1wiKTtcbn1cblxuLyoqXG4gKiBDb21waWxlIGEgYC9wYXR0ZXJuL2ZsYWdzYCBsaXRlcmFsLCBvciBgdW5kZWZpbmVkYCB3aGVuIGl0IGlzIG1hbGZvcm1lZCBvclxuICogdGhlIGJvZHkgaXMgbm90IGEgdmFsaWQgcmVnZXguXG4gKi9cbmZ1bmN0aW9uIGNvbXBpbGVSZWdleExpdGVyYWwocGF0dGVybjogc3RyaW5nLCBjYXNlU2Vuc2l0aXZlOiBib29sZWFuKTogUmVnRXhwIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgcGFyc2VkID0gL15cXC8oLispXFwvKFthLXpdKikkL2lzLmV4ZWMocGF0dGVybik7XG4gIGlmICghcGFyc2VkKSByZXR1cm4gdW5kZWZpbmVkO1xuICBjb25zdCBib2R5ID0gcGFyc2VkWzFdITtcbiAgY29uc3QgZmxhZ3MgPSBwYXJzZWRbMl0hO1xuICB0cnkge1xuICAgIHJldHVybiBuZXcgUmVnRXhwKGJvZHksIGNhc2VTZW5zaXRpdmUgfHwgZmxhZ3MuaW5jbHVkZXMoXCJpXCIpID8gZmxhZ3MgOiBgJHtmbGFnc31pYCk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgbG9nLndhcm4oXCJpZ25vcmluZyBpbnZhbGlkIHJlZ2V4IHBhdHRlcm5cIiwgeyBwYXR0ZXJuLCBlcnJvciB9KTtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG59XG5cbi8qKlxuICogQ29tcGlsZSBhIHNoZWxsLXN0eWxlIGdsb2IgKGAqYCwgYD9gKSBpbnRvIGFuIGFuY2hvcmVkIGBSZWdFeHBgLiBFdmVyeSBvdGhlclxuICogY2hhcmFjdGVyIGlzIGVzY2FwZWQsIHNvIGEgZ2xvYiBjYW4gc2FmZWx5IGNvbnRhaW4gcmVnZXggbWV0YWNoYXJhY3RlcnNcbiAqIChgeC1hcHAuKmAgbWF0Y2hlcyBhIGxpdGVyYWwgZG90IGZvbGxvd2VkIGJ5IGFueXRoaW5nKS5cbiAqL1xuZnVuY3Rpb24gY29tcGlsZUdsb2IocGF0dGVybjogc3RyaW5nLCBjYXNlU2Vuc2l0aXZlOiBib29sZWFuKTogUmVnRXhwIHtcbiAgY29uc3QgYm9keSA9IHBhdHRlcm5cbiAgICAuc3BsaXQoLyhbKj9dKS8pXG4gICAgLm1hcCgocGFydCkgPT4gKHBhcnQgPT09IFwiKlwiID8gXCIuKlwiIDogcGFydCA9PT0gXCI/XCIgPyBcIi5cIiA6IGVzY2FwZVJlZ0V4cChwYXJ0KSkpXG4gICAgLmpvaW4oXCJcIik7XG4gIHJldHVybiBuZXcgUmVnRXhwKGBeJHtib2R5fSRgLCBjYXNlU2Vuc2l0aXZlID8gXCJcIiA6IFwiaVwiKTtcbn1cblxuLyoqXG4gKiBDb21waWxlIE9ORSBwYXR0ZXJuIGludG8gYSBwcmVkaWNhdGUsIG9yIGB1bmRlZmluZWRgIHdoZW4gdGhlIGVudHJ5IGlzIGVtcHR5XG4gKiBvciBhbiB1bnBhcnNlYWJsZSByZWdleCBsaXRlcmFsLlxuICpcbiAqIENhbGxlcnMgdGhhdCB3YW50IGEgd2hvbGUgbGlzdCBzaG91bGQgdXNlIHtAbGluayB0b1BhdHRlcm5NYXRjaGVyfTsgdGhpcyBpc1xuICogZXhwb3J0ZWQgZm9yIHRoZSBjYXNlIHdoZXJlIGEgY29uc3VtZXIgYXBwbGllcyBpdHMgb3duIHNlbWFudGljcyB0byBzb21lXG4gKiBzaGFwZXMgYW5kIG9ubHkgd2FudHMgdGhlIGdsb2IvcmVnZXggaGFuZGxpbmcgKHRoZSBlbWFpbCBnYXRlJ3MgYmFyZS1kb21haW5cbiAqIHNob3J0Y3V0LCBmb3Igb25lKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRvUGF0dGVybihcbiAgcGF0dGVybjogc3RyaW5nLFxuICBvcHRpb25zOiBQYXR0ZXJuT3B0aW9ucyA9IHt9LFxuKTogcHJlZGljYXRlLlByZWRpY2F0ZTxzdHJpbmc+IHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgdHJpbW1lZCA9IHBhdHRlcm4udHJpbSgpO1xuICBpZiAoIXRyaW1tZWQpIHJldHVybiB1bmRlZmluZWQ7XG4gIGNvbnN0IGNhc2VTZW5zaXRpdmUgPSBvcHRpb25zLmNhc2VTZW5zaXRpdmUgPz8gZmFsc2U7XG5cbiAgaWYgKGlzUmVnZXhMaXRlcmFsKHRyaW1tZWQpKSB7XG4gICAgY29uc3QgY29tcGlsZWQgPSBjb21waWxlUmVnZXhMaXRlcmFsKHRyaW1tZWQsIGNhc2VTZW5zaXRpdmUpO1xuICAgIHJldHVybiBjb21waWxlZCAmJiBwcmVkaWNhdGUuY3JlYXRlPHN0cmluZz4oKHZhbHVlKSA9PiBjb21waWxlZC50ZXN0KHZhbHVlKSk7XG4gIH1cbiAgaWYgKGlzR2xvYih0cmltbWVkKSkge1xuICAgIGNvbnN0IGNvbXBpbGVkID0gY29tcGlsZUdsb2IodHJpbW1lZCwgY2FzZVNlbnNpdGl2ZSk7XG4gICAgcmV0dXJuIHByZWRpY2F0ZS5jcmVhdGU8c3RyaW5nPigodmFsdWUpID0+IGNvbXBpbGVkLnRlc3QodmFsdWUpKTtcbiAgfVxuICAvLyBMaXRlcmFsOiB3aG9sZS1zdHJpbmcgZXF1YWxpdHkuXG4gIGNvbnN0IGV4cGVjdGVkID0gY2FzZVNlbnNpdGl2ZSA/IHRyaW1tZWQgOiB0cmltbWVkLnRvTG93ZXJDYXNlKCk7XG4gIHJldHVybiBwcmVkaWNhdGUuY3JlYXRlPHN0cmluZz4oKHZhbHVlKSA9PlxuICAgIGNhc2VTZW5zaXRpdmUgPyB2YWx1ZSA9PT0gZXhwZWN0ZWQgOiB2YWx1ZS50b0xvd2VyQ2FzZSgpID09PSBleHBlY3RlZCxcbiAgKTtcbn1cblxuLyoqXG4gKiBDb21waWxlIHBhdHRlcm5zIGludG8gYSBzaW5nbGUgT1InZCB7QGxpbmsgUHJlZGljYXRlfS4gQWNjZXB0cyB0aGUgcmF3IGNvbmZpZ1xuICogc2hhcGVzIHtAbGluayBwYXJzZUxpc3R9IGRvZXMgLSBhbiBhcnJheSwgb3Igb25lIGNvbW1hL3doaXRlc3BhY2Utc2VwYXJhdGVkXG4gKiBzdHJpbmcgLSBzbyBhIGZpZWxkIGFuZCBpdHMgZW52IHZhciBuZWVkIG5vIHNlcGFyYXRlIGhhbmRsaW5nLlxuICpcbiAqIFdpdGggbm8gdXNhYmxlIHBhdHRlcm5zIHRoZSByZXN1bHQgYWx3YXlzIHJldHVybnMgYGZhbHNlYC5cbiAqXG4gKiBAZXhhbXBsZVxuICogY29uc3QgZm9yd2FyZGFibGUgPSB0b1BhdHRlcm5NYXRjaGVyKHByb2Nlc3MuZW52LlRVTk5FTF9GT1JXQVJEX0hFQURFUlMpO1xuICovXG5leHBvcnQgZnVuY3Rpb24gdG9QYXR0ZXJuTWF0Y2hlcihcbiAgcGF0dGVybnM6IHN0cmluZyB8IHJlYWRvbmx5IHN0cmluZ1tdIHwgdW5kZWZpbmVkIHwgbnVsbCxcbiAgb3B0aW9uczogUGF0dGVybk9wdGlvbnMgPSB7fSxcbik6IHByZWRpY2F0ZS5QcmVkaWNhdGU8c3RyaW5nPiB7XG4gIGNvbnN0IGNvbXBpbGVkID0gcGFyc2VMaXN0KHBhdHRlcm5zKVxuICAgIC5tYXAoKHBhdHRlcm4pID0+IHRvUGF0dGVybihwYXR0ZXJuLCBvcHRpb25zKSlcbiAgICAuZmlsdGVyKCh2YWx1ZSk6IHZhbHVlIGlzIHByZWRpY2F0ZS5QcmVkaWNhdGU8c3RyaW5nPiA9PiB2YWx1ZSAhPT0gdW5kZWZpbmVkKTtcbiAgaWYgKGNvbXBpbGVkLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHByZWRpY2F0ZS5jcmVhdGU8c3RyaW5nPigoKSA9PiBmYWxzZSk7XG4gIHJldHVybiBjb21waWxlZC5zbGljZSgxKS5yZWR1Y2UoKGFjYywgbmV4dCkgPT4gYWNjLm9yKG5leHQpLCBjb21waWxlZFswXSEpO1xufVxuIl19
@@ -7,6 +7,20 @@
7
7
  * @module
8
8
  */
9
9
  import { type HeaderLike } from "./http.ts";
10
+ /**
11
+ * Header the Databricks Apps front door forwards the caller's OAuth (OBO) token
12
+ * on - the default source for every helper here.
13
+ *
14
+ * Exported because it is a wire contract several packages branch on, not just a
15
+ * default argument: `@dbx-tools/appkit`'s `identity` module decides whether a
16
+ * request can use OBO auth at all by its presence, and `@dbx-tools/cli-tunnel`
17
+ * must know the name to strip inbound copies of it. One spelling, one place.
18
+ */
19
+ export declare const ACCESS_TOKEN_HEADER = "x-forwarded-access-token";
20
+ /** Header the front door forwards the caller's user id on. */
21
+ export declare const USER_ID_HEADER = "x-forwarded-user";
22
+ /** Header the front door forwards the caller's email on. */
23
+ export declare const USER_EMAIL_HEADER = "x-forwarded-email";
10
24
  /**
11
25
  * Decode the JWT payload from a bearer token string or request headers.
12
26
  *
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 = "x-forwarded-access-token") {
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=
@@ -1 +1 @@
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/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
@@ -43,7 +43,7 @@
43
43
  "./package.json": "./package.json"
44
44
  }
45
45
  },
46
- "version": "0.6.48",
46
+ "version": "0.6.49",
47
47
  "types": "./lib/index.d.ts",
48
48
  "type": "module",
49
49
  "exports": {
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 = "x-forwarded-access-token",
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")) {