@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/README.md
CHANGED
|
@@ -10,6 +10,7 @@ namespaces so call sites stay explicit:
|
|
|
10
10
|
import {
|
|
11
11
|
async,
|
|
12
12
|
brand,
|
|
13
|
+
env,
|
|
13
14
|
error,
|
|
14
15
|
hash,
|
|
15
16
|
http,
|
|
@@ -155,6 +156,38 @@ field off parsed JSON. `parseList()` normalizes a config value that may arrive a
|
|
|
155
156
|
an array or as one comma/whitespace-separated env string, de-duplicating as it
|
|
156
157
|
goes.
|
|
157
158
|
|
|
159
|
+
## Configuration From The Environment
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
const config = {
|
|
163
|
+
host: env.string(options.host, "SMTP_HOST"),
|
|
164
|
+
// Several names for one setting; earlier names win.
|
|
165
|
+
appId: env.string(options.appId, ["TEAMS_APP_ID", "MICROSOFT_APP_ID"]),
|
|
166
|
+
timeoutMs: env.positiveInt(options.timeoutMs, "SEARCH_TIMEOUT_MS", 30_000),
|
|
167
|
+
threshold: env.positiveNumber(options.threshold, "FUZZY_THRESHOLD", 0.4),
|
|
168
|
+
fuzzy: env.boolean(options.fuzzy, "SEARCH_FUZZY") ?? true,
|
|
169
|
+
fallbacks: env.list(options.fallbacks, "MODEL_FALLBACKS"),
|
|
170
|
+
};
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Every plugin resolves config the same way - the caller's typed value, else one or
|
|
174
|
+
more environment variables, else a default - and hand-writing that chain per
|
|
175
|
+
field is how `config.x ?? Number(process.env.X)` bugs get in. `positiveInt()`
|
|
176
|
+
floors, so a count cannot go fractional; `positiveNumber()` keeps the fraction
|
|
177
|
+
for a threshold or ratio. `boolean()` goes through `object.toBoolean()`, so the
|
|
178
|
+
loose spellings an env var actually carries (`1`, `on`, `yes`) are accepted, and
|
|
179
|
+
returns `undefined` when neither source is interpretable so `??` picks the
|
|
180
|
+
default. A name that is SET but unusable is not skipped for a later name in the
|
|
181
|
+
chain - ignoring what a deployment explicitly configured hides the mistake.
|
|
182
|
+
|
|
183
|
+
Browser-safe: `process` is reached through `globalThis` and guarded, so every
|
|
184
|
+
lookup simply misses off-process and the caller's fallback applies.
|
|
185
|
+
|
|
186
|
+
Pair it with `object.optional()` when a resolved value is an optional field -
|
|
187
|
+
`...object.optional("endpoint", env.string(...))` keeps an absent field ABSENT
|
|
188
|
+
rather than setting it to an explicit `undefined`, which
|
|
189
|
+
`exactOptionalPropertyTypes` rejects.
|
|
190
|
+
|
|
158
191
|
## Objects And Predicates
|
|
159
192
|
|
|
160
193
|
```ts
|
|
@@ -208,6 +241,13 @@ http.forEachHeaderValue(req, "authorization", (value) => {
|
|
|
208
241
|
records, and plain `{ headers }` objects. `http.createFetchError()` turns a
|
|
209
242
|
failed `Response` into an error with response text attached.
|
|
210
243
|
|
|
244
|
+
## Intercepted Execution
|
|
245
|
+
|
|
246
|
+
`execution.directExecutor()` gives plugin-backed tools a no-plugin fallback with
|
|
247
|
+
the same success/failure shape as AppKit's executor. `execution.run()` merges the
|
|
248
|
+
plugin timeout signal with the caller's cancellation signal and centralizes
|
|
249
|
+
result unwrapping without imposing an AppKit dependency on shared code.
|
|
250
|
+
|
|
211
251
|
## Network Strings, Email, And CIDR
|
|
212
252
|
|
|
213
253
|
```ts
|
|
@@ -221,6 +261,36 @@ const internal = cidr ? net.ipInCidr("10.1.2.3", cidr) : false;
|
|
|
221
261
|
`net.pathMatch()` compares path prefixes on segment boundaries. IP/CIDR helpers
|
|
222
262
|
parse IPv4 and IPv6 into a shared bigint comparison model.
|
|
223
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
|
+
|
|
224
294
|
## Token Claims
|
|
225
295
|
|
|
226
296
|
```ts
|
|
@@ -267,10 +337,15 @@ without paying formatting cost when disabled.
|
|
|
267
337
|
- `json` - non-throwing `parse()` and record-narrowing `parseRecord()`.
|
|
268
338
|
- `string` - tokenization, slugs, identifiers, human labels, string coercion,
|
|
269
339
|
config lists, descriptions, pluralization, and HTML escaping.
|
|
270
|
-
- `object` - record checks, boolean coercion,
|
|
271
|
-
lazy sequence transforms + collection helpers.
|
|
340
|
+
- `object` - record checks, boolean coercion, present-only field spreading, deep
|
|
341
|
+
equality, shape types, and lazy sequence transforms + collection helpers.
|
|
342
|
+
- `env` - config-over-environment resolution: strings, booleans, positive
|
|
343
|
+
numbers/integers, and lists, with env-name fallback chains.
|
|
272
344
|
- `predicate` - composable boolean/type predicates.
|
|
345
|
+
- `pattern` - literal / glob / `/regex/` allow-list matching compiled to a
|
|
346
|
+
predicate.
|
|
273
347
|
- `http` - header iteration, cookie parsing, and fetch error creation.
|
|
348
|
+
- `execution` - direct executor fallback, cancellation merging, and result unwrapping.
|
|
274
349
|
- `net` - URL building, email parsing, path matching, IP/CIDR helpers.
|
|
275
350
|
- `token` - JWT payload and scope readers.
|
|
276
351
|
- `functionModule` - memoization.
|
package/index.ts
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
export * as async from "./src/async.ts";
|
|
6
6
|
export * as brand from "./src/brand.ts";
|
|
7
|
+
export * as env from "./src/env.ts";
|
|
7
8
|
export * as error from "./src/error.ts";
|
|
9
|
+
export * as execution from "./src/execution.ts";
|
|
8
10
|
export * as functionModule from "./src/function.ts";
|
|
9
11
|
export * as hash from "./src/hash.ts";
|
|
10
12
|
export * as http from "./src/http.ts";
|
|
@@ -12,17 +14,22 @@ export * as json from "./src/json.ts";
|
|
|
12
14
|
export * as log from "./src/log.ts";
|
|
13
15
|
export * as net from "./src/net.ts";
|
|
14
16
|
export * as object from "./src/object.ts";
|
|
17
|
+
export * as pattern from "./src/pattern.ts";
|
|
15
18
|
export * as predicate from "./src/predicate.ts";
|
|
16
19
|
export * as string from "./src/string.ts";
|
|
17
20
|
export * as token from "./src/token.ts";
|
|
18
21
|
export type { PollContext, PollProducer, PollOptions } from "./src/async.ts";
|
|
19
22
|
export { DEFAULT_BRAND_ASSETS, BrandAssetSetSchema, BrandColorsSchema, BrandVoiceSchema, BrandContextSchema, defaultBrandContext } from "./src/brand.ts";
|
|
20
23
|
export type { BrandContext, BrandContextInput, BrandAssetSet } from "./src/brand.ts";
|
|
24
|
+
export type { EnvKey } from "./src/env.ts";
|
|
21
25
|
export type { ErrorContext } from "./src/error.ts";
|
|
26
|
+
export type { ExecutionResult, Executor, ExecutionFailure, RunOptions } from "./src/execution.ts";
|
|
22
27
|
export type { MemoizeOptions } from "./src/function.ts";
|
|
23
28
|
export type { HeaderLike } from "./src/http.ts";
|
|
24
29
|
export type { LogLevel, Logger } from "./src/log.ts";
|
|
25
30
|
export type { UrlLike, IpVersion, ParsedIp, Cidr, UrlBuilder, ParseEmailsOptions } from "./src/net.ts";
|
|
26
31
|
export type { Sequence, Container, Collection, OneOrMany, NameLike, NonFunctionKeys, DeepEqualComparator } from "./src/object.ts";
|
|
32
|
+
export type { PatternOptions } from "./src/pattern.ts";
|
|
27
33
|
export type { PredicateFunction, TypePredicateFunction, PredicateInput, Predicate } from "./src/predicate.ts";
|
|
28
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
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export * as async from "./src/async.ts";
|
|
2
2
|
export * as brand from "./src/brand.ts";
|
|
3
|
+
export * as env from "./src/env.ts";
|
|
3
4
|
export * as error from "./src/error.ts";
|
|
5
|
+
export * as execution from "./src/execution.ts";
|
|
4
6
|
export * as functionModule from "./src/function.ts";
|
|
5
7
|
export * as hash from "./src/hash.ts";
|
|
6
8
|
export * as http from "./src/http.ts";
|
|
@@ -8,17 +10,22 @@ export * as json from "./src/json.ts";
|
|
|
8
10
|
export * as log from "./src/log.ts";
|
|
9
11
|
export * as net from "./src/net.ts";
|
|
10
12
|
export * as object from "./src/object.ts";
|
|
13
|
+
export * as pattern from "./src/pattern.ts";
|
|
11
14
|
export * as predicate from "./src/predicate.ts";
|
|
12
15
|
export * as string from "./src/string.ts";
|
|
13
16
|
export * as token from "./src/token.ts";
|
|
14
17
|
export type { PollContext, PollProducer, PollOptions } from "./src/async.ts";
|
|
15
18
|
export { DEFAULT_BRAND_ASSETS, BrandAssetSetSchema, BrandColorsSchema, BrandVoiceSchema, BrandContextSchema, defaultBrandContext } from "./src/brand.ts";
|
|
16
19
|
export type { BrandContext, BrandContextInput, BrandAssetSet } from "./src/brand.ts";
|
|
20
|
+
export type { EnvKey } from "./src/env.ts";
|
|
17
21
|
export type { ErrorContext } from "./src/error.ts";
|
|
22
|
+
export type { ExecutionResult, Executor, ExecutionFailure, RunOptions } from "./src/execution.ts";
|
|
18
23
|
export type { MemoizeOptions } from "./src/function.ts";
|
|
19
24
|
export type { HeaderLike } from "./src/http.ts";
|
|
20
25
|
export type { LogLevel, Logger } from "./src/log.ts";
|
|
21
26
|
export type { UrlLike, IpVersion, ParsedIp, Cidr, UrlBuilder, ParseEmailsOptions } from "./src/net.ts";
|
|
22
27
|
export type { Sequence, Container, Collection, OneOrMany, NameLike, NonFunctionKeys, DeepEqualComparator } from "./src/object.ts";
|
|
28
|
+
export type { PatternOptions } from "./src/pattern.ts";
|
|
23
29
|
export type { PredicateFunction, TypePredicateFunction, PredicateInput, Predicate } from "./src/predicate.ts";
|
|
24
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
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
// Hand edits are overwritten on the next watch; this file is read-only.
|
|
4
4
|
export * as async from "./src/async.js";
|
|
5
5
|
export * as brand from "./src/brand.js";
|
|
6
|
+
export * as env from "./src/env.js";
|
|
6
7
|
export * as error from "./src/error.js";
|
|
8
|
+
export * as execution from "./src/execution.js";
|
|
7
9
|
export * as functionModule from "./src/function.js";
|
|
8
10
|
export * as hash from "./src/hash.js";
|
|
9
11
|
export * as http from "./src/http.js";
|
|
@@ -11,8 +13,10 @@ export * as json from "./src/json.js";
|
|
|
11
13
|
export * as log from "./src/log.js";
|
|
12
14
|
export * as net from "./src/net.js";
|
|
13
15
|
export * as object from "./src/object.js";
|
|
16
|
+
export * as pattern from "./src/pattern.js";
|
|
14
17
|
export * as predicate from "./src/predicate.js";
|
|
15
18
|
export * as string from "./src/string.js";
|
|
16
19
|
export * as token from "./src/token.js";
|
|
17
20
|
export { DEFAULT_BRAND_ASSETS, BrandAssetSetSchema, BrandColorsSchema, BrandVoiceSchema, BrandContextSchema, defaultBrandContext } from "./src/brand.js";
|
|
18
|
-
|
|
21
|
+
export { ACCESS_TOKEN_HEADER, USER_ID_HEADER, USER_EMAIL_HEADER } from "./src/token.js";
|
|
22
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwyQ0FBMkM7QUFDM0MsbURBQW1EO0FBQ25ELHdFQUF3RTtBQUV4RSxPQUFPLEtBQUssS0FBSyxNQUFNLGdCQUFnQixDQUFDO0FBQ3hDLE9BQU8sS0FBSyxLQUFLLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEMsT0FBTyxLQUFLLEdBQUcsTUFBTSxjQUFjLENBQUM7QUFDcEMsT0FBTyxLQUFLLEtBQUssTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QyxPQUFPLEtBQUssU0FBUyxNQUFNLG9CQUFvQixDQUFDO0FBQ2hELE9BQU8sS0FBSyxjQUFjLE1BQU0sbUJBQW1CLENBQUM7QUFDcEQsT0FBTyxLQUFLLElBQUksTUFBTSxlQUFlLENBQUM7QUFDdEMsT0FBTyxLQUFLLElBQUksTUFBTSxlQUFlLENBQUM7QUFDdEMsT0FBTyxLQUFLLElBQUksTUFBTSxlQUFlLENBQUM7QUFDdEMsT0FBTyxLQUFLLEdBQUcsTUFBTSxjQUFjLENBQUM7QUFDcEMsT0FBTyxLQUFLLEdBQUcsTUFBTSxjQUFjLENBQUM7QUFDcEMsT0FBTyxLQUFLLE1BQU0sTUFBTSxpQkFBaUIsQ0FBQztBQUMxQyxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBQzVDLE9BQU8sS0FBSyxTQUFTLE1BQU0sb0JBQW9CLENBQUM7QUFDaEQsT0FBTyxLQUFLLE1BQU0sTUFBTSxpQkFBaUIsQ0FBQztBQUMxQyxPQUFPLEtBQUssS0FBSyxNQUFNLGdCQUFnQixDQUFDO0FBRXhDLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxtQkFBbUIsRUFBRSxpQkFBaUIsRUFBRSxnQkFBZ0IsRUFBRSxrQkFBa0IsRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBYXpKLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxjQUFjLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIEdFTkVSQVRFRCBieSBwcm9qZW4gd2F0Y2ggLSBETyBOT1QgRURJVC5cbi8vIFJlZ2VuZXJhdGVkIGZyb20gdGhlIGV4cG9ydGluZyBtb2R1bGVzIGluIC4vc3JjLlxuLy8gSGFuZCBlZGl0cyBhcmUgb3ZlcndyaXR0ZW4gb24gdGhlIG5leHQgd2F0Y2g7IHRoaXMgZmlsZSBpcyByZWFkLW9ubHkuXG5cbmV4cG9ydCAqIGFzIGFzeW5jIGZyb20gXCIuL3NyYy9hc3luYy50c1wiO1xuZXhwb3J0ICogYXMgYnJhbmQgZnJvbSBcIi4vc3JjL2JyYW5kLnRzXCI7XG5leHBvcnQgKiBhcyBlbnYgZnJvbSBcIi4vc3JjL2Vudi50c1wiO1xuZXhwb3J0ICogYXMgZXJyb3IgZnJvbSBcIi4vc3JjL2Vycm9yLnRzXCI7XG5leHBvcnQgKiBhcyBleGVjdXRpb24gZnJvbSBcIi4vc3JjL2V4ZWN1dGlvbi50c1wiO1xuZXhwb3J0ICogYXMgZnVuY3Rpb25Nb2R1bGUgZnJvbSBcIi4vc3JjL2Z1bmN0aW9uLnRzXCI7XG5leHBvcnQgKiBhcyBoYXNoIGZyb20gXCIuL3NyYy9oYXNoLnRzXCI7XG5leHBvcnQgKiBhcyBodHRwIGZyb20gXCIuL3NyYy9odHRwLnRzXCI7XG5leHBvcnQgKiBhcyBqc29uIGZyb20gXCIuL3NyYy9qc29uLnRzXCI7XG5leHBvcnQgKiBhcyBsb2cgZnJvbSBcIi4vc3JjL2xvZy50c1wiO1xuZXhwb3J0ICogYXMgbmV0IGZyb20gXCIuL3NyYy9uZXQudHNcIjtcbmV4cG9ydCAqIGFzIG9iamVjdCBmcm9tIFwiLi9zcmMvb2JqZWN0LnRzXCI7XG5leHBvcnQgKiBhcyBwYXR0ZXJuIGZyb20gXCIuL3NyYy9wYXR0ZXJuLnRzXCI7XG5leHBvcnQgKiBhcyBwcmVkaWNhdGUgZnJvbSBcIi4vc3JjL3ByZWRpY2F0ZS50c1wiO1xuZXhwb3J0ICogYXMgc3RyaW5nIGZyb20gXCIuL3NyYy9zdHJpbmcudHNcIjtcbmV4cG9ydCAqIGFzIHRva2VuIGZyb20gXCIuL3NyYy90b2tlbi50c1wiO1xuZXhwb3J0IHR5cGUgeyBQb2xsQ29udGV4dCwgUG9sbFByb2R1Y2VyLCBQb2xsT3B0aW9ucyB9IGZyb20gXCIuL3NyYy9hc3luYy50c1wiO1xuZXhwb3J0IHsgREVGQVVMVF9CUkFORF9BU1NFVFMsIEJyYW5kQXNzZXRTZXRTY2hlbWEsIEJyYW5kQ29sb3JzU2NoZW1hLCBCcmFuZFZvaWNlU2NoZW1hLCBCcmFuZENvbnRleHRTY2hlbWEsIGRlZmF1bHRCcmFuZENvbnRleHQgfSBmcm9tIFwiLi9zcmMvYnJhbmQudHNcIjtcbmV4cG9ydCB0eXBlIHsgQnJhbmRDb250ZXh0LCBCcmFuZENvbnRleHRJbnB1dCwgQnJhbmRBc3NldFNldCB9IGZyb20gXCIuL3NyYy9icmFuZC50c1wiO1xuZXhwb3J0IHR5cGUgeyBFbnZLZXkgfSBmcm9tIFwiLi9zcmMvZW52LnRzXCI7XG5leHBvcnQgdHlwZSB7IEVycm9yQ29udGV4dCB9IGZyb20gXCIuL3NyYy9lcnJvci50c1wiO1xuZXhwb3J0IHR5cGUgeyBFeGVjdXRpb25SZXN1bHQsIEV4ZWN1dG9yLCBFeGVjdXRpb25GYWlsdXJlLCBSdW5PcHRpb25zIH0gZnJvbSBcIi4vc3JjL2V4ZWN1dGlvbi50c1wiO1xuZXhwb3J0IHR5cGUgeyBNZW1vaXplT3B0aW9ucyB9IGZyb20gXCIuL3NyYy9mdW5jdGlvbi50c1wiO1xuZXhwb3J0IHR5cGUgeyBIZWFkZXJMaWtlIH0gZnJvbSBcIi4vc3JjL2h0dHAudHNcIjtcbmV4cG9ydCB0eXBlIHsgTG9nTGV2ZWwsIExvZ2dlciB9IGZyb20gXCIuL3NyYy9sb2cudHNcIjtcbmV4cG9ydCB0eXBlIHsgVXJsTGlrZSwgSXBWZXJzaW9uLCBQYXJzZWRJcCwgQ2lkciwgVXJsQnVpbGRlciwgUGFyc2VFbWFpbHNPcHRpb25zIH0gZnJvbSBcIi4vc3JjL25ldC50c1wiO1xuZXhwb3J0IHR5cGUgeyBTZXF1ZW5jZSwgQ29udGFpbmVyLCBDb2xsZWN0aW9uLCBPbmVPck1hbnksIE5hbWVMaWtlLCBOb25GdW5jdGlvbktleXMsIERlZXBFcXVhbENvbXBhcmF0b3IgfSBmcm9tIFwiLi9zcmMvb2JqZWN0LnRzXCI7XG5leHBvcnQgdHlwZSB7IFBhdHRlcm5PcHRpb25zIH0gZnJvbSBcIi4vc3JjL3BhdHRlcm4udHNcIjtcbmV4cG9ydCB0eXBlIHsgUHJlZGljYXRlRnVuY3Rpb24sIFR5cGVQcmVkaWNhdGVGdW5jdGlvbiwgUHJlZGljYXRlSW5wdXQsIFByZWRpY2F0ZSB9IGZyb20gXCIuL3NyYy9wcmVkaWNhdGUudHNcIjtcbmV4cG9ydCB0eXBlIHsgVG9rZW5pemVPcHRpb25zLCBLZXlPcHRpb25zLCBJZGVudGlmaWVyT3B0aW9ucywgRGVzY3JpcHRpb24gfSBmcm9tIFwiLi9zcmMvc3RyaW5nLnRzXCI7XG5leHBvcnQgeyBBQ0NFU1NfVE9LRU5fSEVBREVSLCBVU0VSX0lEX0hFQURFUiwgVVNFUl9FTUFJTF9IRUFERVIgfSBmcm9tIFwiLi9zcmMvdG9rZW4udHNcIjtcbiJdfQ==
|
package/lib/src/env.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
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
|
+
/** One env var name, or several tried in order. */
|
|
18
|
+
export type EnvKey = string | readonly string[];
|
|
19
|
+
/**
|
|
20
|
+
* First non-empty value among `keys`, trimmed, else `null`.
|
|
21
|
+
*
|
|
22
|
+
* Several names for one setting is the norm (a package-specific variable plus
|
|
23
|
+
* the Databricks-standard one), so `keys` is order-sensitive: earlier names win.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* env.text(["TEAMS_APP_ID", "MICROSOFT_APP_ID"]);
|
|
27
|
+
*/
|
|
28
|
+
export declare function text(keys: EnvKey): string | null;
|
|
29
|
+
/**
|
|
30
|
+
* Resolve a string setting: `configured` when set and non-empty, else the first
|
|
31
|
+
* non-empty variable among `keys`, else `null`.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* env.string(config.host, "SMTP_HOST");
|
|
35
|
+
*/
|
|
36
|
+
export declare function string(configured: unknown, keys: EnvKey): string | null;
|
|
37
|
+
/**
|
|
38
|
+
* Resolve a boolean setting through {@link toBoolean}, so the loose spellings an
|
|
39
|
+
* env var actually carries (`1`, `on`, `yes`, ...) are accepted. Returns
|
|
40
|
+
* `undefined` when neither source is interpretable, letting the caller pick a
|
|
41
|
+
* default with `??`.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* env.boolean(config.fuzzy, "WEB_SEARCH_FUZZY") ?? true;
|
|
45
|
+
*/
|
|
46
|
+
export declare function boolean(configured: unknown, keys: EnvKey): boolean | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Resolve a positive-number setting that may be fractional (a score threshold,
|
|
49
|
+
* a ratio): `configured` when it is a finite number greater than zero, else the
|
|
50
|
+
* first variable among `keys` that parses that way, else `fallback`.
|
|
51
|
+
*
|
|
52
|
+
* {@link positiveInt} is the right choice for a count; this one keeps the
|
|
53
|
+
* fraction, so a `0.4` threshold does not floor to `0`.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* env.positiveNumber(config.fuzzyThreshold, "SEARCH_FUZZY_THRESHOLD", 0.4);
|
|
57
|
+
*/
|
|
58
|
+
export declare function positiveNumber(configured: unknown, keys: EnvKey, fallback: number): number;
|
|
59
|
+
/**
|
|
60
|
+
* Resolve a positive-integer setting (a port, timeout, page size, or cap):
|
|
61
|
+
* `configured` when it is a finite number greater than zero, else the first
|
|
62
|
+
* variable among `keys` that parses that way, else `fallback`. Floored, so a
|
|
63
|
+
* fractional value can't leak into a count.
|
|
64
|
+
*
|
|
65
|
+
* A non-numeric or non-positive value is treated as absent rather than fatal -
|
|
66
|
+
* these are ceilings and timeouts where a sane default beats a boot failure.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* env.positiveInt(config.timeoutMs, "SEARCH_TIMEOUT_MS", 30_000);
|
|
70
|
+
*/
|
|
71
|
+
export declare function positiveInt(configured: unknown, keys: EnvKey, fallback: number): number;
|
|
72
|
+
/**
|
|
73
|
+
* Resolve a list setting through {@link parseList}, so an array from typed
|
|
74
|
+
* config and a `"a, b c"` env string normalize identically. Returns `[]` when
|
|
75
|
+
* neither source has entries.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* env.list(config.modelFallbacks, "WEB_SEARCH_MODEL_FALLBACKS");
|
|
79
|
+
*/
|
|
80
|
+
export declare function list(configured: string | readonly string[] | undefined | null, keys: EnvKey, transform?: (entry: string) => string): string[];
|
package/lib/src/env.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
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
|
+
import { toBoolean } from "./object.js";
|
|
18
|
+
import { parseList, trimToNull } from "./string.js";
|
|
19
|
+
/** The ambient environment, or `{}` off-process (a browser). */
|
|
20
|
+
function environment() {
|
|
21
|
+
return globalThis.process?.env ?? {};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* First non-empty value among `keys`, trimmed, else `null`.
|
|
25
|
+
*
|
|
26
|
+
* Several names for one setting is the norm (a package-specific variable plus
|
|
27
|
+
* the Databricks-standard one), so `keys` is order-sensitive: earlier names win.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* env.text(["TEAMS_APP_ID", "MICROSOFT_APP_ID"]);
|
|
31
|
+
*/
|
|
32
|
+
export function text(keys) {
|
|
33
|
+
const env = environment();
|
|
34
|
+
for (const key of typeof keys === "string" ? [keys] : keys) {
|
|
35
|
+
const value = trimToNull(env[key]);
|
|
36
|
+
if (value !== null)
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Resolve a string setting: `configured` when set and non-empty, else the first
|
|
43
|
+
* non-empty variable among `keys`, else `null`.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* env.string(config.host, "SMTP_HOST");
|
|
47
|
+
*/
|
|
48
|
+
export function string(configured, keys) {
|
|
49
|
+
return trimToNull(configured) ?? text(keys);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Resolve a boolean setting through {@link toBoolean}, so the loose spellings an
|
|
53
|
+
* env var actually carries (`1`, `on`, `yes`, ...) are accepted. Returns
|
|
54
|
+
* `undefined` when neither source is interpretable, letting the caller pick a
|
|
55
|
+
* default with `??`.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* env.boolean(config.fuzzy, "WEB_SEARCH_FUZZY") ?? true;
|
|
59
|
+
*/
|
|
60
|
+
export function boolean(configured, keys) {
|
|
61
|
+
return toBoolean(configured) ?? toBoolean(text(keys));
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Resolve a positive-number setting that may be fractional (a score threshold,
|
|
65
|
+
* a ratio): `configured` when it is a finite number greater than zero, else the
|
|
66
|
+
* first variable among `keys` that parses that way, else `fallback`.
|
|
67
|
+
*
|
|
68
|
+
* {@link positiveInt} is the right choice for a count; this one keeps the
|
|
69
|
+
* fraction, so a `0.4` threshold does not floor to `0`.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* env.positiveNumber(config.fuzzyThreshold, "SEARCH_FUZZY_THRESHOLD", 0.4);
|
|
73
|
+
*/
|
|
74
|
+
export function positiveNumber(configured, keys, fallback) {
|
|
75
|
+
return toPositiveNumber(configured) ?? toPositiveNumber(text(keys)) ?? fallback;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Resolve a positive-integer setting (a port, timeout, page size, or cap):
|
|
79
|
+
* `configured` when it is a finite number greater than zero, else the first
|
|
80
|
+
* variable among `keys` that parses that way, else `fallback`. Floored, so a
|
|
81
|
+
* fractional value can't leak into a count.
|
|
82
|
+
*
|
|
83
|
+
* A non-numeric or non-positive value is treated as absent rather than fatal -
|
|
84
|
+
* these are ceilings and timeouts where a sane default beats a boot failure.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* env.positiveInt(config.timeoutMs, "SEARCH_TIMEOUT_MS", 30_000);
|
|
88
|
+
*/
|
|
89
|
+
export function positiveInt(configured, keys, fallback) {
|
|
90
|
+
return toPositiveInt(configured) ?? toPositiveInt(text(keys)) ?? fallback;
|
|
91
|
+
}
|
|
92
|
+
function toPositiveNumber(value) {
|
|
93
|
+
if (value === null || value === undefined || value === "")
|
|
94
|
+
return undefined;
|
|
95
|
+
const parsed = Number(value);
|
|
96
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
|
|
97
|
+
}
|
|
98
|
+
function toPositiveInt(value) {
|
|
99
|
+
const parsed = toPositiveNumber(value);
|
|
100
|
+
return parsed === undefined ? undefined : Math.floor(parsed);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Resolve a list setting through {@link parseList}, so an array from typed
|
|
104
|
+
* config and a `"a, b c"` env string normalize identically. Returns `[]` when
|
|
105
|
+
* neither source has entries.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* env.list(config.modelFallbacks, "WEB_SEARCH_MODEL_FALLBACKS");
|
|
109
|
+
*/
|
|
110
|
+
export function list(configured, keys, transform) {
|
|
111
|
+
const fromConfig = parseList(configured, transform);
|
|
112
|
+
return fromConfig.length > 0 ? fromConfig : parseList(text(keys), transform);
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW52LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2Vudi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7O0dBZUc7QUFFSCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBVXBELGdFQUFnRTtBQUNoRSxTQUFTLFdBQVc7SUFDbEIsT0FBUSxVQUF3QyxDQUFDLE9BQU8sRUFBRSxHQUFHLElBQUksRUFBRSxDQUFDO0FBQ3RFLENBQUM7QUFFRDs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sVUFBVSxJQUFJLENBQUMsSUFBWTtJQUMvQixNQUFNLEdBQUcsR0FBRyxXQUFXLEVBQUUsQ0FBQztJQUMxQixLQUFLLE1BQU0sR0FBRyxJQUFJLE9BQU8sSUFBSSxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDM0QsTUFBTSxLQUFLLEdBQUcsVUFBVSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ25DLElBQUksS0FBSyxLQUFLLElBQUk7WUFBRSxPQUFPLEtBQUssQ0FBQztJQUNuQyxDQUFDO0lBQ0QsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxVQUFVLE1BQU0sQ0FBQyxVQUFtQixFQUFFLElBQVk7SUFDdEQsT0FBTyxVQUFVLENBQUMsVUFBVSxDQUFDLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQzlDLENBQUM7QUFFRDs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sVUFBVSxPQUFPLENBQUMsVUFBbUIsRUFBRSxJQUFZO0lBQ3ZELE9BQU8sU0FBUyxDQUFDLFVBQVUsQ0FBQyxJQUFJLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztBQUN4RCxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7R0FVRztBQUNILE1BQU0sVUFBVSxjQUFjLENBQUMsVUFBbUIsRUFBRSxJQUFZLEVBQUUsUUFBZ0I7SUFDaEYsT0FBTyxnQkFBZ0IsQ0FBQyxVQUFVLENBQUMsSUFBSSxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxRQUFRLENBQUM7QUFDbEYsQ0FBQztBQUVEOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsTUFBTSxVQUFVLFdBQVcsQ0FBQyxVQUFtQixFQUFFLElBQVksRUFBRSxRQUFnQjtJQUM3RSxPQUFPLGFBQWEsQ0FBQyxVQUFVLENBQUMsSUFBSSxhQUFhLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksUUFBUSxDQUFDO0FBQzVFLENBQUM7QUFFRCxTQUFTLGdCQUFnQixDQUFDLEtBQWM7SUFDdEMsSUFBSSxLQUFLLEtBQUssSUFBSSxJQUFJLEtBQUssS0FBSyxTQUFTLElBQUksS0FBSyxLQUFLLEVBQUU7UUFBRSxPQUFPLFNBQVMsQ0FBQztJQUM1RSxNQUFNLE1BQU0sR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDN0IsT0FBTyxNQUFNLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxJQUFJLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0FBQ3BFLENBQUM7QUFFRCxTQUFTLGFBQWEsQ0FBQyxLQUFjO0lBQ25DLE1BQU0sTUFBTSxHQUFHLGdCQUFnQixDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3ZDLE9BQU8sTUFBTSxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0FBQy9ELENBQUM7QUFFRDs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxVQUFVLElBQUksQ0FDbEIsVUFBeUQsRUFDekQsSUFBWSxFQUNaLFNBQXFDO0lBRXJDLE1BQU0sVUFBVSxHQUFHLFNBQVMsQ0FBQyxVQUFVLEVBQUUsU0FBUyxDQUFDLENBQUM7SUFDcEQsT0FBTyxVQUFVLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLFNBQVMsQ0FBQyxDQUFDO0FBQy9FLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFJlYWRpbmcgY29uZmlndXJhdGlvbiBvdXQgb2YgdGhlIGVudmlyb25tZW50LlxuICpcbiAqIEV2ZXJ5IHBsdWdpbiBjb25maWcgaW4gdGhpcyByZXBvIHJlc29sdmVzIHRoZSBzYW1lIHdheTogdGFrZSB0aGUgdHlwZWRcbiAqIGNvbmZpZyB2YWx1ZSB3aGVuIHRoZSBjYWxsZXIgc2V0IG9uZSwgZWxzZSBmYWxsIGJhY2sgdG8gb25lIG9yIG1vcmVcbiAqIGVudmlyb25tZW50IHZhcmlhYmxlcywgZWxzZSBhIGRlZmF1bHQuIFdyaXR0ZW4gYnkgaGFuZCB0aGF0IGJlY29tZXMgYVxuICogYGNvbmZpZy54ID8/IE51bWJlcihwcm9jZXNzLmVudi5YKWAgY2hhaW4gcGVyIGZpZWxkLCBhbmQgZWFjaCBwYWNrYWdlIGdyZXdcbiAqIGl0cyBvd24gYGZyb21FbnZgIC8gYHJlc29sdmVQb3NpdGl2ZUludGAgaGVscGVyIHdpdGggc2xpZ2h0bHkgZGlmZmVyZW50XG4gKiBjb2VyY2lvbiBydWxlcy4gVGhlc2UgYXJlIHRob3NlIGhlbHBlcnMsIG9uY2UuXG4gKlxuICogQnJvd3Nlci1zYWZlOiBgcHJvY2Vzc2AgaXMgcmVhY2hlZCB0aHJvdWdoIGBnbG9iYWxUaGlzYCBhbmQgZ3VhcmRlZCwgc28gdGhpc1xuICogbW9kdWxlIG5lZWRzIG5vIE5vZGUgdHlwZXMgYW5kIGlzIGluZXJ0IGluIGEgYnJvd3NlciAoZXZlcnkgbG9va3VwIG1pc3NlcyBhbmRcbiAqIHRoZSBjYWxsZXIncyBmYWxsYmFjayBhcHBsaWVzKS5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgdG9Cb29sZWFuIH0gZnJvbSBcIi4vb2JqZWN0LnRzXCI7XG5pbXBvcnQgeyBwYXJzZUxpc3QsIHRyaW1Ub051bGwgfSBmcm9tIFwiLi9zdHJpbmcudHNcIjtcblxuLyoqIGBwcm9jZXNzYC1zaGFwZWQgdmlldyBvZmYgYGdsb2JhbFRoaXNgLCBzbyBubyBub2RlIHR5cGVzIGFyZSBuZWVkZWQuICovXG5pbnRlcmZhY2UgUHJvY2Vzc0xpa2Uge1xuICBlbnY/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCB1bmRlZmluZWQ+O1xufVxuXG4vKiogT25lIGVudiB2YXIgbmFtZSwgb3Igc2V2ZXJhbCB0cmllZCBpbiBvcmRlci4gKi9cbmV4cG9ydCB0eXBlIEVudktleSA9IHN0cmluZyB8IHJlYWRvbmx5IHN0cmluZ1tdO1xuXG4vKiogVGhlIGFtYmllbnQgZW52aXJvbm1lbnQsIG9yIGB7fWAgb2ZmLXByb2Nlc3MgKGEgYnJvd3NlcikuICovXG5mdW5jdGlvbiBlbnZpcm9ubWVudCgpOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCB1bmRlZmluZWQ+IHtcbiAgcmV0dXJuIChnbG9iYWxUaGlzIGFzIHsgcHJvY2Vzcz86IFByb2Nlc3NMaWtlIH0pLnByb2Nlc3M/LmVudiA/PyB7fTtcbn1cblxuLyoqXG4gKiBGaXJzdCBub24tZW1wdHkgdmFsdWUgYW1vbmcgYGtleXNgLCB0cmltbWVkLCBlbHNlIGBudWxsYC5cbiAqXG4gKiBTZXZlcmFsIG5hbWVzIGZvciBvbmUgc2V0dGluZyBpcyB0aGUgbm9ybSAoYSBwYWNrYWdlLXNwZWNpZmljIHZhcmlhYmxlIHBsdXNcbiAqIHRoZSBEYXRhYnJpY2tzLXN0YW5kYXJkIG9uZSksIHNvIGBrZXlzYCBpcyBvcmRlci1zZW5zaXRpdmU6IGVhcmxpZXIgbmFtZXMgd2luLlxuICpcbiAqIEBleGFtcGxlXG4gKiBlbnYudGV4dChbXCJURUFNU19BUFBfSURcIiwgXCJNSUNST1NPRlRfQVBQX0lEXCJdKTtcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRleHQoa2V5czogRW52S2V5KTogc3RyaW5nIHwgbnVsbCB7XG4gIGNvbnN0IGVudiA9IGVudmlyb25tZW50KCk7XG4gIGZvciAoY29uc3Qga2V5IG9mIHR5cGVvZiBrZXlzID09PSBcInN0cmluZ1wiID8gW2tleXNdIDoga2V5cykge1xuICAgIGNvbnN0IHZhbHVlID0gdHJpbVRvTnVsbChlbnZba2V5XSk7XG4gICAgaWYgKHZhbHVlICE9PSBudWxsKSByZXR1cm4gdmFsdWU7XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59XG5cbi8qKlxuICogUmVzb2x2ZSBhIHN0cmluZyBzZXR0aW5nOiBgY29uZmlndXJlZGAgd2hlbiBzZXQgYW5kIG5vbi1lbXB0eSwgZWxzZSB0aGUgZmlyc3RcbiAqIG5vbi1lbXB0eSB2YXJpYWJsZSBhbW9uZyBga2V5c2AsIGVsc2UgYG51bGxgLlxuICpcbiAqIEBleGFtcGxlXG4gKiBlbnYuc3RyaW5nKGNvbmZpZy5ob3N0LCBcIlNNVFBfSE9TVFwiKTtcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHN0cmluZyhjb25maWd1cmVkOiB1bmtub3duLCBrZXlzOiBFbnZLZXkpOiBzdHJpbmcgfCBudWxsIHtcbiAgcmV0dXJuIHRyaW1Ub051bGwoY29uZmlndXJlZCkgPz8gdGV4dChrZXlzKTtcbn1cblxuLyoqXG4gKiBSZXNvbHZlIGEgYm9vbGVhbiBzZXR0aW5nIHRocm91Z2gge0BsaW5rIHRvQm9vbGVhbn0sIHNvIHRoZSBsb29zZSBzcGVsbGluZ3MgYW5cbiAqIGVudiB2YXIgYWN0dWFsbHkgY2FycmllcyAoYDFgLCBgb25gLCBgeWVzYCwgLi4uKSBhcmUgYWNjZXB0ZWQuIFJldHVybnNcbiAqIGB1bmRlZmluZWRgIHdoZW4gbmVpdGhlciBzb3VyY2UgaXMgaW50ZXJwcmV0YWJsZSwgbGV0dGluZyB0aGUgY2FsbGVyIHBpY2sgYVxuICogZGVmYXVsdCB3aXRoIGA/P2AuXG4gKlxuICogQGV4YW1wbGVcbiAqIGVudi5ib29sZWFuKGNvbmZpZy5mdXp6eSwgXCJXRUJfU0VBUkNIX0ZVWlpZXCIpID8/IHRydWU7XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBib29sZWFuKGNvbmZpZ3VyZWQ6IHVua25vd24sIGtleXM6IEVudktleSk6IGJvb2xlYW4gfCB1bmRlZmluZWQge1xuICByZXR1cm4gdG9Cb29sZWFuKGNvbmZpZ3VyZWQpID8/IHRvQm9vbGVhbih0ZXh0KGtleXMpKTtcbn1cblxuLyoqXG4gKiBSZXNvbHZlIGEgcG9zaXRpdmUtbnVtYmVyIHNldHRpbmcgdGhhdCBtYXkgYmUgZnJhY3Rpb25hbCAoYSBzY29yZSB0aHJlc2hvbGQsXG4gKiBhIHJhdGlvKTogYGNvbmZpZ3VyZWRgIHdoZW4gaXQgaXMgYSBmaW5pdGUgbnVtYmVyIGdyZWF0ZXIgdGhhbiB6ZXJvLCBlbHNlIHRoZVxuICogZmlyc3QgdmFyaWFibGUgYW1vbmcgYGtleXNgIHRoYXQgcGFyc2VzIHRoYXQgd2F5LCBlbHNlIGBmYWxsYmFja2AuXG4gKlxuICoge0BsaW5rIHBvc2l0aXZlSW50fSBpcyB0aGUgcmlnaHQgY2hvaWNlIGZvciBhIGNvdW50OyB0aGlzIG9uZSBrZWVwcyB0aGVcbiAqIGZyYWN0aW9uLCBzbyBhIGAwLjRgIHRocmVzaG9sZCBkb2VzIG5vdCBmbG9vciB0byBgMGAuXG4gKlxuICogQGV4YW1wbGVcbiAqIGVudi5wb3NpdGl2ZU51bWJlcihjb25maWcuZnV6enlUaHJlc2hvbGQsIFwiU0VBUkNIX0ZVWlpZX1RIUkVTSE9MRFwiLCAwLjQpO1xuICovXG5leHBvcnQgZnVuY3Rpb24gcG9zaXRpdmVOdW1iZXIoY29uZmlndXJlZDogdW5rbm93biwga2V5czogRW52S2V5LCBmYWxsYmFjazogbnVtYmVyKTogbnVtYmVyIHtcbiAgcmV0dXJuIHRvUG9zaXRpdmVOdW1iZXIoY29uZmlndXJlZCkgPz8gdG9Qb3NpdGl2ZU51bWJlcih0ZXh0KGtleXMpKSA/PyBmYWxsYmFjaztcbn1cblxuLyoqXG4gKiBSZXNvbHZlIGEgcG9zaXRpdmUtaW50ZWdlciBzZXR0aW5nIChhIHBvcnQsIHRpbWVvdXQsIHBhZ2Ugc2l6ZSwgb3IgY2FwKTpcbiAqIGBjb25maWd1cmVkYCB3aGVuIGl0IGlzIGEgZmluaXRlIG51bWJlciBncmVhdGVyIHRoYW4gemVybywgZWxzZSB0aGUgZmlyc3RcbiAqIHZhcmlhYmxlIGFtb25nIGBrZXlzYCB0aGF0IHBhcnNlcyB0aGF0IHdheSwgZWxzZSBgZmFsbGJhY2tgLiBGbG9vcmVkLCBzbyBhXG4gKiBmcmFjdGlvbmFsIHZhbHVlIGNhbid0IGxlYWsgaW50byBhIGNvdW50LlxuICpcbiAqIEEgbm9uLW51bWVyaWMgb3Igbm9uLXBvc2l0aXZlIHZhbHVlIGlzIHRyZWF0ZWQgYXMgYWJzZW50IHJhdGhlciB0aGFuIGZhdGFsIC1cbiAqIHRoZXNlIGFyZSBjZWlsaW5ncyBhbmQgdGltZW91dHMgd2hlcmUgYSBzYW5lIGRlZmF1bHQgYmVhdHMgYSBib290IGZhaWx1cmUuXG4gKlxuICogQGV4YW1wbGVcbiAqIGVudi5wb3NpdGl2ZUludChjb25maWcudGltZW91dE1zLCBcIlNFQVJDSF9USU1FT1VUX01TXCIsIDMwXzAwMCk7XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwb3NpdGl2ZUludChjb25maWd1cmVkOiB1bmtub3duLCBrZXlzOiBFbnZLZXksIGZhbGxiYWNrOiBudW1iZXIpOiBudW1iZXIge1xuICByZXR1cm4gdG9Qb3NpdGl2ZUludChjb25maWd1cmVkKSA/PyB0b1Bvc2l0aXZlSW50KHRleHQoa2V5cykpID8/IGZhbGxiYWNrO1xufVxuXG5mdW5jdGlvbiB0b1Bvc2l0aXZlTnVtYmVyKHZhbHVlOiB1bmtub3duKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgaWYgKHZhbHVlID09PSBudWxsIHx8IHZhbHVlID09PSB1bmRlZmluZWQgfHwgdmFsdWUgPT09IFwiXCIpIHJldHVybiB1bmRlZmluZWQ7XG4gIGNvbnN0IHBhcnNlZCA9IE51bWJlcih2YWx1ZSk7XG4gIHJldHVybiBOdW1iZXIuaXNGaW5pdGUocGFyc2VkKSAmJiBwYXJzZWQgPiAwID8gcGFyc2VkIDogdW5kZWZpbmVkO1xufVxuXG5mdW5jdGlvbiB0b1Bvc2l0aXZlSW50KHZhbHVlOiB1bmtub3duKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgcGFyc2VkID0gdG9Qb3NpdGl2ZU51bWJlcih2YWx1ZSk7XG4gIHJldHVybiBwYXJzZWQgPT09IHVuZGVmaW5lZCA/IHVuZGVmaW5lZCA6IE1hdGguZmxvb3IocGFyc2VkKTtcbn1cblxuLyoqXG4gKiBSZXNvbHZlIGEgbGlzdCBzZXR0aW5nIHRocm91Z2gge0BsaW5rIHBhcnNlTGlzdH0sIHNvIGFuIGFycmF5IGZyb20gdHlwZWRcbiAqIGNvbmZpZyBhbmQgYSBgXCJhLCBiIGNcImAgZW52IHN0cmluZyBub3JtYWxpemUgaWRlbnRpY2FsbHkuIFJldHVybnMgYFtdYCB3aGVuXG4gKiBuZWl0aGVyIHNvdXJjZSBoYXMgZW50cmllcy5cbiAqXG4gKiBAZXhhbXBsZVxuICogZW52Lmxpc3QoY29uZmlnLm1vZGVsRmFsbGJhY2tzLCBcIldFQl9TRUFSQ0hfTU9ERUxfRkFMTEJBQ0tTXCIpO1xuICovXG5leHBvcnQgZnVuY3Rpb24gbGlzdChcbiAgY29uZmlndXJlZDogc3RyaW5nIHwgcmVhZG9ubHkgc3RyaW5nW10gfCB1bmRlZmluZWQgfCBudWxsLFxuICBrZXlzOiBFbnZLZXksXG4gIHRyYW5zZm9ybT86IChlbnRyeTogc3RyaW5nKSA9PiBzdHJpbmcsXG4pOiBzdHJpbmdbXSB7XG4gIGNvbnN0IGZyb21Db25maWcgPSBwYXJzZUxpc3QoY29uZmlndXJlZCwgdHJhbnNmb3JtKTtcbiAgcmV0dXJuIGZyb21Db25maWcubGVuZ3RoID4gMCA/IGZyb21Db25maWcgOiBwYXJzZUxpc3QodGV4dChrZXlzKSwgdHJhbnNmb3JtKTtcbn1cbiJdfQ==
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** Success/failure shape returned by an interceptor-backed executor. */
|
|
2
|
+
export type ExecutionResult<T> = {
|
|
3
|
+
ok: true;
|
|
4
|
+
data: T;
|
|
5
|
+
} | {
|
|
6
|
+
ok: false;
|
|
7
|
+
status: number;
|
|
8
|
+
message: string;
|
|
9
|
+
};
|
|
10
|
+
/** Function signature shared by AppKit plugin executors. */
|
|
11
|
+
export type Executor<Settings> = <T>(fn: (signal?: AbortSignal) => Promise<T>, settings: Settings) => Promise<ExecutionResult<T>>;
|
|
12
|
+
/** Failure details supplied when an intercepted operation cannot complete. */
|
|
13
|
+
export interface ExecutionFailure {
|
|
14
|
+
operation: string;
|
|
15
|
+
status: number;
|
|
16
|
+
message: string;
|
|
17
|
+
}
|
|
18
|
+
/** Options for running and unwrapping one intercepted operation. */
|
|
19
|
+
export interface RunOptions<T, Settings> {
|
|
20
|
+
operation: string;
|
|
21
|
+
settings: Settings;
|
|
22
|
+
execute: Executor<Settings>;
|
|
23
|
+
fn: (signal?: AbortSignal) => Promise<T>;
|
|
24
|
+
signal?: AbortSignal;
|
|
25
|
+
canceled: () => Error;
|
|
26
|
+
failed: (failure: ExecutionFailure) => Error;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Build the executor used before a plugin installs its interceptor chain.
|
|
30
|
+
* Errors are mapped onto the same result shape as AppKit's `Plugin.execute()`.
|
|
31
|
+
*/
|
|
32
|
+
export declare function directExecutor<Settings>(): Executor<Settings>;
|
|
33
|
+
/** Run an operation through an executor, merge cancellation, and unwrap its result. */
|
|
34
|
+
export declare function run<T, Settings>(options: RunOptions<T, Settings>): Promise<T>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** Generic helpers for AppKit-style intercepted execution. */
|
|
2
|
+
import * as async from "./async.js";
|
|
3
|
+
import * as error from "./error.js";
|
|
4
|
+
import * as object from "./object.js";
|
|
5
|
+
function errorStatus(value) {
|
|
6
|
+
if (!object.isRecord(value))
|
|
7
|
+
return 500;
|
|
8
|
+
const status = value.statusCode;
|
|
9
|
+
return typeof status === "number" && Number.isFinite(status) ? status : 500;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Build the executor used before a plugin installs its interceptor chain.
|
|
13
|
+
* Errors are mapped onto the same result shape as AppKit's `Plugin.execute()`.
|
|
14
|
+
*/
|
|
15
|
+
export function directExecutor() {
|
|
16
|
+
return async (fn) => {
|
|
17
|
+
try {
|
|
18
|
+
return { ok: true, data: await fn() };
|
|
19
|
+
}
|
|
20
|
+
catch (cause) {
|
|
21
|
+
return {
|
|
22
|
+
ok: false,
|
|
23
|
+
status: errorStatus(cause),
|
|
24
|
+
message: error.errorMessage(cause),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** Run an operation through an executor, merge cancellation, and unwrap its result. */
|
|
30
|
+
export async function run(options) {
|
|
31
|
+
const result = await options.execute((executeSignal) => options.fn(async.combineAbortSignals(executeSignal, options.signal)), options.settings);
|
|
32
|
+
if (result.ok)
|
|
33
|
+
return result.data;
|
|
34
|
+
if (options.signal?.aborted)
|
|
35
|
+
throw options.canceled();
|
|
36
|
+
throw options.failed({
|
|
37
|
+
operation: options.operation,
|
|
38
|
+
status: result.status,
|
|
39
|
+
message: result.message,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhlY3V0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2V4ZWN1dGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSw4REFBOEQ7QUFDOUQsT0FBTyxLQUFLLEtBQUssTUFBTSxZQUFZLENBQUM7QUFDcEMsT0FBTyxLQUFLLEtBQUssTUFBTSxZQUFZLENBQUM7QUFDcEMsT0FBTyxLQUFLLE1BQU0sTUFBTSxhQUFhLENBQUM7QUE4QnRDLFNBQVMsV0FBVyxDQUFDLEtBQWM7SUFDakMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDO1FBQUUsT0FBTyxHQUFHLENBQUM7SUFDeEMsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLFVBQVUsQ0FBQztJQUNoQyxPQUFPLE9BQU8sTUFBTSxLQUFLLFFBQVEsSUFBSSxNQUFNLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQztBQUM5RSxDQUFDO0FBRUQ7OztHQUdHO0FBQ0gsTUFBTSxVQUFVLGNBQWM7SUFDNUIsT0FBTyxLQUFLLEVBQUUsRUFBRSxFQUFFLEVBQUU7UUFDbEIsSUFBSSxDQUFDO1lBQ0gsT0FBTyxFQUFFLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxFQUFFLEVBQUUsQ0FBQztRQUN4QyxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE9BQU87Z0JBQ0wsRUFBRSxFQUFFLEtBQUs7Z0JBQ1QsTUFBTSxFQUFFLFdBQVcsQ0FBQyxLQUFLLENBQUM7Z0JBQzFCLE9BQU8sRUFBRSxLQUFLLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQzthQUNuQyxDQUFDO1FBQ0osQ0FBQztJQUNILENBQUMsQ0FBQztBQUNKLENBQUM7QUFFRCx1RkFBdUY7QUFDdkYsTUFBTSxDQUFDLEtBQUssVUFBVSxHQUFHLENBQWMsT0FBZ0M7SUFDckUsTUFBTSxNQUFNLEdBQUcsTUFBTSxPQUFPLENBQUMsT0FBTyxDQUNsQyxDQUFDLGFBQWEsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsbUJBQW1CLENBQUMsYUFBYSxFQUFFLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUN2RixPQUFPLENBQUMsUUFBUSxDQUNqQixDQUFDO0lBQ0YsSUFBSSxNQUFNLENBQUMsRUFBRTtRQUFFLE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQztJQUNsQyxJQUFJLE9BQU8sQ0FBQyxNQUFNLEVBQUUsT0FBTztRQUFFLE1BQU0sT0FBTyxDQUFDLFFBQVEsRUFBRSxDQUFDO0lBQ3RELE1BQU0sT0FBTyxDQUFDLE1BQU0sQ0FBQztRQUNuQixTQUFTLEVBQUUsT0FBTyxDQUFDLFNBQVM7UUFDNUIsTUFBTSxFQUFFLE1BQU0sQ0FBQyxNQUFNO1FBQ3JCLE9BQU8sRUFBRSxNQUFNLENBQUMsT0FBTztLQUN4QixDQUFDLENBQUM7QUFDTCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqIEdlbmVyaWMgaGVscGVycyBmb3IgQXBwS2l0LXN0eWxlIGludGVyY2VwdGVkIGV4ZWN1dGlvbi4gKi9cbmltcG9ydCAqIGFzIGFzeW5jIGZyb20gXCIuL2FzeW5jLnRzXCI7XG5pbXBvcnQgKiBhcyBlcnJvciBmcm9tIFwiLi9lcnJvci50c1wiO1xuaW1wb3J0ICogYXMgb2JqZWN0IGZyb20gXCIuL29iamVjdC50c1wiO1xuXG4vKiogU3VjY2Vzcy9mYWlsdXJlIHNoYXBlIHJldHVybmVkIGJ5IGFuIGludGVyY2VwdG9yLWJhY2tlZCBleGVjdXRvci4gKi9cbmV4cG9ydCB0eXBlIEV4ZWN1dGlvblJlc3VsdDxUPiA9XG4gIHsgb2s6IHRydWU7IGRhdGE6IFQgfSB8IHsgb2s6IGZhbHNlOyBzdGF0dXM6IG51bWJlcjsgbWVzc2FnZTogc3RyaW5nIH07XG5cbi8qKiBGdW5jdGlvbiBzaWduYXR1cmUgc2hhcmVkIGJ5IEFwcEtpdCBwbHVnaW4gZXhlY3V0b3JzLiAqL1xuZXhwb3J0IHR5cGUgRXhlY3V0b3I8U2V0dGluZ3M+ID0gPFQ+KFxuICBmbjogKHNpZ25hbD86IEFib3J0U2lnbmFsKSA9PiBQcm9taXNlPFQ+LFxuICBzZXR0aW5nczogU2V0dGluZ3MsXG4pID0+IFByb21pc2U8RXhlY3V0aW9uUmVzdWx0PFQ+PjtcblxuLyoqIEZhaWx1cmUgZGV0YWlscyBzdXBwbGllZCB3aGVuIGFuIGludGVyY2VwdGVkIG9wZXJhdGlvbiBjYW5ub3QgY29tcGxldGUuICovXG5leHBvcnQgaW50ZXJmYWNlIEV4ZWN1dGlvbkZhaWx1cmUge1xuICBvcGVyYXRpb246IHN0cmluZztcbiAgc3RhdHVzOiBudW1iZXI7XG4gIG1lc3NhZ2U6IHN0cmluZztcbn1cblxuLyoqIE9wdGlvbnMgZm9yIHJ1bm5pbmcgYW5kIHVud3JhcHBpbmcgb25lIGludGVyY2VwdGVkIG9wZXJhdGlvbi4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUnVuT3B0aW9uczxULCBTZXR0aW5ncz4ge1xuICBvcGVyYXRpb246IHN0cmluZztcbiAgc2V0dGluZ3M6IFNldHRpbmdzO1xuICBleGVjdXRlOiBFeGVjdXRvcjxTZXR0aW5ncz47XG4gIGZuOiAoc2lnbmFsPzogQWJvcnRTaWduYWwpID0+IFByb21pc2U8VD47XG4gIHNpZ25hbD86IEFib3J0U2lnbmFsO1xuICBjYW5jZWxlZDogKCkgPT4gRXJyb3I7XG4gIGZhaWxlZDogKGZhaWx1cmU6IEV4ZWN1dGlvbkZhaWx1cmUpID0+IEVycm9yO1xufVxuXG5mdW5jdGlvbiBlcnJvclN0YXR1cyh2YWx1ZTogdW5rbm93bik6IG51bWJlciB7XG4gIGlmICghb2JqZWN0LmlzUmVjb3JkKHZhbHVlKSkgcmV0dXJuIDUwMDtcbiAgY29uc3Qgc3RhdHVzID0gdmFsdWUuc3RhdHVzQ29kZTtcbiAgcmV0dXJuIHR5cGVvZiBzdGF0dXMgPT09IFwibnVtYmVyXCIgJiYgTnVtYmVyLmlzRmluaXRlKHN0YXR1cykgPyBzdGF0dXMgOiA1MDA7XG59XG5cbi8qKlxuICogQnVpbGQgdGhlIGV4ZWN1dG9yIHVzZWQgYmVmb3JlIGEgcGx1Z2luIGluc3RhbGxzIGl0cyBpbnRlcmNlcHRvciBjaGFpbi5cbiAqIEVycm9ycyBhcmUgbWFwcGVkIG9udG8gdGhlIHNhbWUgcmVzdWx0IHNoYXBlIGFzIEFwcEtpdCdzIGBQbHVnaW4uZXhlY3V0ZSgpYC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRpcmVjdEV4ZWN1dG9yPFNldHRpbmdzPigpOiBFeGVjdXRvcjxTZXR0aW5ncz4ge1xuICByZXR1cm4gYXN5bmMgKGZuKSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiB7IG9rOiB0cnVlLCBkYXRhOiBhd2FpdCBmbigpIH07XG4gICAgfSBjYXRjaCAoY2F1c2UpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIG9rOiBmYWxzZSxcbiAgICAgICAgc3RhdHVzOiBlcnJvclN0YXR1cyhjYXVzZSksXG4gICAgICAgIG1lc3NhZ2U6IGVycm9yLmVycm9yTWVzc2FnZShjYXVzZSksXG4gICAgICB9O1xuICAgIH1cbiAgfTtcbn1cblxuLyoqIFJ1biBhbiBvcGVyYXRpb24gdGhyb3VnaCBhbiBleGVjdXRvciwgbWVyZ2UgY2FuY2VsbGF0aW9uLCBhbmQgdW53cmFwIGl0cyByZXN1bHQuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuPFQsIFNldHRpbmdzPihvcHRpb25zOiBSdW5PcHRpb25zPFQsIFNldHRpbmdzPik6IFByb21pc2U8VD4ge1xuICBjb25zdCByZXN1bHQgPSBhd2FpdCBvcHRpb25zLmV4ZWN1dGUoXG4gICAgKGV4ZWN1dGVTaWduYWwpID0+IG9wdGlvbnMuZm4oYXN5bmMuY29tYmluZUFib3J0U2lnbmFscyhleGVjdXRlU2lnbmFsLCBvcHRpb25zLnNpZ25hbCkpLFxuICAgIG9wdGlvbnMuc2V0dGluZ3MsXG4gICk7XG4gIGlmIChyZXN1bHQub2spIHJldHVybiByZXN1bHQuZGF0YTtcbiAgaWYgKG9wdGlvbnMuc2lnbmFsPy5hYm9ydGVkKSB0aHJvdyBvcHRpb25zLmNhbmNlbGVkKCk7XG4gIHRocm93IG9wdGlvbnMuZmFpbGVkKHtcbiAgICBvcGVyYXRpb246IG9wdGlvbnMub3BlcmF0aW9uLFxuICAgIHN0YXR1czogcmVzdWx0LnN0YXR1cyxcbiAgICBtZXNzYWdlOiByZXN1bHQubWVzc2FnZSxcbiAgfSk7XG59XG4iXX0=
|
package/lib/src/object.d.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
|
|
@@ -349,6 +350,22 @@ export type NonFunctionKeys<T> = {
|
|
|
349
350
|
* if (isRecord(parsed)) parsed.foo = 1;
|
|
350
351
|
*/
|
|
351
352
|
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
353
|
+
/**
|
|
354
|
+
* `{ [key]: value }` when `value` is present, otherwise `undefined` - so an
|
|
355
|
+
* absent optional field stays ABSENT when spread, rather than becoming an
|
|
356
|
+
* explicit `undefined` that `exactOptionalPropertyTypes` rejects.
|
|
357
|
+
*
|
|
358
|
+
* Spelling that inline costs a repeated, double-evaluated ternary per field
|
|
359
|
+
* (`...(v ? { key: v } : {})`), which is how config resolvers end up computing
|
|
360
|
+
* the same value twice.
|
|
361
|
+
*
|
|
362
|
+
* @example
|
|
363
|
+
* return {
|
|
364
|
+
* ...optional("appId", env.text("MICROSOFT_APP_ID")),
|
|
365
|
+
* ...optional("endpoint", config.endpoint),
|
|
366
|
+
* };
|
|
367
|
+
*/
|
|
368
|
+
export declare function optional<K extends string, V>(key: K, value: V | null | undefined): Record<K, V> | undefined;
|
|
352
369
|
/**
|
|
353
370
|
* Coerce a loose boolean-ish value to a real `boolean`, or `undefined`
|
|
354
371
|
* when it can't be interpreted. Recognizes `true`/`t`/`on`/`1`/`yes`/`y`
|