@dbx-tools/core 0.6.82 → 0.6.86

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
@@ -1,7 +1,7 @@
1
1
  # @dbx-tools/core
2
2
 
3
- Node-only core helpers for binary installation, process execution, and project
4
- discovery.
3
+ Node-only core helpers for layered configuration, binary installation, process
4
+ execution, locking, and project discovery.
5
5
 
6
6
  Import this package when code needs `node:child_process`, `node:fs`, or
7
7
  `node:path`. Browser-safe utilities live in
@@ -16,8 +16,12 @@ Key features:
16
16
  - Workspace/project root discovery from package-manager files, git metadata, and
17
17
  the current working directory.
18
18
  - Safe filesystem stat and project naming helpers for CLIs and projen synth.
19
+ - Layered config from process env, environment-specific `.env` files, and
20
+ Databricks bundle App config or variables.
19
21
  - YAML/JSON brand-context discovery and loading with shared Zod validation.
20
22
  - Idempotent executable downloads with zip/tar extraction and atomic installs.
23
+ - Cross-process file locks with a Bun `flock(2)` fast path and a portable,
24
+ stale-reclaiming lock-directory fallback.
21
25
  - Keyed mutual exclusion across the main thread and its worker threads.
22
26
 
23
27
  ## Install A Binary
@@ -73,6 +77,48 @@ files. Missing files return the complete dbx tools default context; malformed
73
77
  files fail validation. Use `loadBrandContextFile(path)` for an explicit file and
74
78
  `resolveBrandAssetPath(path, asset)` for relative asset references.
75
79
 
80
+ ## Resolve Configuration
81
+
82
+ ```ts
83
+ import { config } from "@dbx-tools/core";
84
+
85
+ const publicDomain = config.string(undefined, "PUBLIC_DOMAIN", {
86
+ prefix: "TUNNEL",
87
+ });
88
+ const timeoutMs = config.positiveInt(undefined, "TIMEOUT_MS", 30_000, {
89
+ prefix: "SEARCH",
90
+ });
91
+ ```
92
+
93
+ Resolution is lazy and follows process env, `.env`, then Databricks bundle
94
+ configuration. The default `DBX_TOOLS` scope and an optional capability prefix
95
+ produce names such as `DBX_TOOLS_TUNNEL_PUBLIC_DOMAIN`, then
96
+ `TUNNEL_PUBLIC_DOMAIN`, then `PUBLIC_DOMAIN`. `.env.production` and `.env.prod`
97
+ are checked before `.env` when `NODE_ENV=production`; development uses
98
+ `.env.development` and `.env.dev`.
99
+
100
+ Bundle lookup runs `databricks bundle validate --output json` only after earlier
101
+ sources miss. It reads literal values from the single App's `config.env` first,
102
+ then root bundle variables, accepts usable partial JSON from a failed validation,
103
+ and caches each dotenv file or validated bundle once per resolved working-
104
+ directory context. Bundle cache entries also include the Databricks profile.
105
+ Deployed Apps skip dotenv and bundle lookup after `isDatabricksAppEnv()`
106
+ recognizes the required App name, HTTP(S) host, and valid port. Set
107
+ `DBX_TOOLS_DATABRICKS_APP_ENV=true` or `false` to force that result; unrecognized
108
+ values leave automatic detection in place.
109
+
110
+ `DBX_TOOLS_CONFIG_DOTENV` and `DBX_TOOLS_CONFIG_BUNDLE` independently force
111
+ those file sources on or off. A recognized boolean takes precedence over App
112
+ runtime detection, so `true` can enable a local source inside an App and `false`
113
+ can suppress it during local development. Absent or unrecognized values keep
114
+ the default: read files outside an App and skip them inside one. Bundle reads
115
+ also default off when `NODE_ENV=production`; set
116
+ `DBX_TOOLS_CONFIG_BUNDLE=true` to opt into bundle validation there.
117
+
118
+ Use `config.string()`, `boolean()`, `positiveNumber()`, `positiveInt()`, and
119
+ `list()` to normalize typed options and text-based configuration through one
120
+ rule. `config.ENV_ONLY` disables file fallbacks for exact environment reads.
121
+
76
122
  ## Run Commands
77
123
 
78
124
  ```ts
@@ -166,6 +212,28 @@ deployment, use
166
212
  [`@dbx-tools/postgres`](../postgres)'s `withAdvisoryLock`, which puts the arbiter
167
213
  in PostgreSQL where every replica can see it.
168
214
 
215
+ ## Serialize Work Across Processes
216
+
217
+ ```ts
218
+ import { fileLock } from "@dbx-tools/core";
219
+
220
+ await fileLock.withFileLock(["cache", name], async () => {
221
+ if (!(await exists(name))) await build(name);
222
+ });
223
+ ```
224
+
225
+ `withFileLock()` serializes processes on the same machine or shared filesystem.
226
+ Under Bun on Unix it prefers a kernel `flock(2)` lock, which the OS releases if
227
+ the process dies. Plain Node, Windows, and systems without the FFI path use
228
+ atomic lock-directory creation with a heartbeat and stale-lock reclamation.
229
+ Callers can select the lock directory, restrict the backend cascade, observe the
230
+ chosen backend, or set a wait timeout. Lock keys use the same stable structured
231
+ identity as process and Postgres advisory locks.
232
+
233
+ Use `processLock.withProcessLock()` when only threads in one process compete,
234
+ `fileLock.withFileLock()` when local processes compete, and Postgres advisory
235
+ locks when multiple app replicas need one arbiter.
236
+
169
237
  ## Discover Project Roots
170
238
 
171
239
  ```ts
@@ -188,6 +256,11 @@ basename. `project.stat()` returns `undefined` instead of throwing.
188
256
  - `project` - root discovery, project naming, git-remote parsing, and safe
189
257
  filesystem stat.
190
258
  - `brand` - YAML/JSON discovery, parsing, validation, and asset path resolution.
259
+ - `config` - scoped environment, dotenv, and validated Databricks bundle lookup,
260
+ including runtime detection and typed coercion helpers.
261
+ - `file` - best-effort filesystem stat.
262
+ - `fileLock` - cascading cross-process locks using `flock` or portable lock
263
+ directories.
191
264
  - `processLock` - keyed mutual exclusion across the main thread and its workers,
192
265
  with worker wiring (`processLockWorkerOptions`, `attachProcessLock`,
193
266
  `processLockAttached`).
package/index.ts CHANGED
@@ -4,6 +4,7 @@
4
4
 
5
5
  export * as bin from "./src/bin.ts";
6
6
  export * as brand from "./src/brand.ts";
7
+ export * as config from "./src/config.ts";
7
8
  export * as exec from "./src/exec.ts";
8
9
  export * as file from "./src/file.ts";
9
10
  export * as fileLock from "./src/file-lock.ts";
@@ -12,6 +13,8 @@ export * as project from "./src/project.ts";
12
13
  export type { BinContext, BinSelectionContext, BinSelector, BinVersionOutput, BinVersionParser, BinOptions, BinUrl } from "./src/bin.ts";
13
14
  export { BrandContextSchema, defaultBrandContext, parseBrandContext, brandContextJsonSchema, brandContextPrompt } from "./src/brand.ts";
14
15
  export type { BrandContext, BrandContextInput } from "./src/brand.ts";
16
+ export { MAX_TCP_PORT, DATABRICKS_APP_ENV_KEY, CONFIG_DOTENV_KEY, CONFIG_BUNDLE_KEY, ENV_ONLY, bundleValue, bundleResourceSchema, bundleEnvEntrySchema, bundleAppSchema } from "./src/config.ts";
17
+ export type { ConfigKey, ConfigSource, ConfigOptions, ConfigFile } from "./src/config.ts";
15
18
  export { COMMAND_NOT_FOUND_EXIT_CODE } from "./src/exec.ts";
16
19
  export type { ExecStdio, LineHandler, StdioOption, ExecResult, ChildProcessResult, ExecOptions, SyncExecStdio, SyncExecOptions, SpawnArgs } from "./src/exec.ts";
17
20
  export type { FileLockBackend, FileLockAcquisition, FileLockOptions } from "./src/file-lock.ts";
package/lib/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * as bin from "./src/bin.ts";
2
2
  export * as brand from "./src/brand.ts";
3
+ export * as config from "./src/config.ts";
3
4
  export * as exec from "./src/exec.ts";
4
5
  export * as file from "./src/file.ts";
5
6
  export * as fileLock from "./src/file-lock.ts";
@@ -8,6 +9,8 @@ export * as project from "./src/project.ts";
8
9
  export type { BinContext, BinSelectionContext, BinSelector, BinVersionOutput, BinVersionParser, BinOptions, BinUrl } from "./src/bin.ts";
9
10
  export { BrandContextSchema, defaultBrandContext, parseBrandContext, brandContextJsonSchema, brandContextPrompt } from "./src/brand.ts";
10
11
  export type { BrandContext, BrandContextInput } from "./src/brand.ts";
12
+ export { MAX_TCP_PORT, DATABRICKS_APP_ENV_KEY, CONFIG_DOTENV_KEY, CONFIG_BUNDLE_KEY, ENV_ONLY, bundleValue, bundleResourceSchema, bundleEnvEntrySchema, bundleAppSchema } from "./src/config.ts";
13
+ export type { ConfigKey, ConfigSource, ConfigOptions, ConfigFile } from "./src/config.ts";
11
14
  export { COMMAND_NOT_FOUND_EXIT_CODE } from "./src/exec.ts";
12
15
  export type { ExecStdio, LineHandler, StdioOption, ExecResult, ChildProcessResult, ExecOptions, SyncExecStdio, SyncExecOptions, SpawnArgs } from "./src/exec.ts";
13
16
  export type { FileLockBackend, FileLockAcquisition, FileLockOptions } from "./src/file-lock.ts";
package/lib/index.js CHANGED
@@ -3,11 +3,13 @@
3
3
  // Hand edits are overwritten on the next watch; this file is read-only.
4
4
  export * as bin from "./src/bin.js";
5
5
  export * as brand from "./src/brand.js";
6
+ export * as config from "./src/config.js";
6
7
  export * as exec from "./src/exec.js";
7
8
  export * as file from "./src/file.js";
8
9
  export * as fileLock from "./src/file-lock.js";
9
10
  export * as processLock from "./src/process-lock.js";
10
11
  export * as project from "./src/project.js";
11
12
  export { BrandContextSchema, defaultBrandContext, parseBrandContext, brandContextJsonSchema, brandContextPrompt } from "./src/brand.js";
13
+ export { MAX_TCP_PORT, DATABRICKS_APP_ENV_KEY, CONFIG_DOTENV_KEY, CONFIG_BUNDLE_KEY, ENV_ONLY, bundleValue, bundleResourceSchema, bundleEnvEntrySchema, bundleAppSchema } from "./src/config.js";
12
14
  export { COMMAND_NOT_FOUND_EXIT_CODE } from "./src/exec.js";
13
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwyQ0FBMkM7QUFDM0MsbURBQW1EO0FBQ25ELHdFQUF3RTtBQUV4RSxPQUFPLEtBQUssR0FBRyxNQUFNLGNBQWMsQ0FBQztBQUNwQyxPQUFPLEtBQUssS0FBSyxNQUFNLGdCQUFnQixDQUFDO0FBQ3hDLE9BQU8sS0FBSyxJQUFJLE1BQU0sZUFBZSxDQUFDO0FBQ3RDLE9BQU8sS0FBSyxJQUFJLE1BQU0sZUFBZSxDQUFDO0FBQ3RDLE9BQU8sS0FBSyxRQUFRLE1BQU0sb0JBQW9CLENBQUM7QUFDL0MsT0FBTyxLQUFLLFdBQVcsTUFBTSx1QkFBdUIsQ0FBQztBQUNyRCxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBRTVDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxtQkFBbUIsRUFBRSxpQkFBaUIsRUFBRSxzQkFBc0IsRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRXhJLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLGVBQWUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIEdFTkVSQVRFRCBieSBwcm9qZW4gd2F0Y2ggLSBETyBOT1QgRURJVC5cbi8vIFJlZ2VuZXJhdGVkIGZyb20gdGhlIGV4cG9ydGluZyBtb2R1bGVzIGluIC4vc3JjLlxuLy8gSGFuZCBlZGl0cyBhcmUgb3ZlcndyaXR0ZW4gb24gdGhlIG5leHQgd2F0Y2g7IHRoaXMgZmlsZSBpcyByZWFkLW9ubHkuXG5cbmV4cG9ydCAqIGFzIGJpbiBmcm9tIFwiLi9zcmMvYmluLnRzXCI7XG5leHBvcnQgKiBhcyBicmFuZCBmcm9tIFwiLi9zcmMvYnJhbmQudHNcIjtcbmV4cG9ydCAqIGFzIGV4ZWMgZnJvbSBcIi4vc3JjL2V4ZWMudHNcIjtcbmV4cG9ydCAqIGFzIGZpbGUgZnJvbSBcIi4vc3JjL2ZpbGUudHNcIjtcbmV4cG9ydCAqIGFzIGZpbGVMb2NrIGZyb20gXCIuL3NyYy9maWxlLWxvY2sudHNcIjtcbmV4cG9ydCAqIGFzIHByb2Nlc3NMb2NrIGZyb20gXCIuL3NyYy9wcm9jZXNzLWxvY2sudHNcIjtcbmV4cG9ydCAqIGFzIHByb2plY3QgZnJvbSBcIi4vc3JjL3Byb2plY3QudHNcIjtcbmV4cG9ydCB0eXBlIHsgQmluQ29udGV4dCwgQmluU2VsZWN0aW9uQ29udGV4dCwgQmluU2VsZWN0b3IsIEJpblZlcnNpb25PdXRwdXQsIEJpblZlcnNpb25QYXJzZXIsIEJpbk9wdGlvbnMsIEJpblVybCB9IGZyb20gXCIuL3NyYy9iaW4udHNcIjtcbmV4cG9ydCB7IEJyYW5kQ29udGV4dFNjaGVtYSwgZGVmYXVsdEJyYW5kQ29udGV4dCwgcGFyc2VCcmFuZENvbnRleHQsIGJyYW5kQ29udGV4dEpzb25TY2hlbWEsIGJyYW5kQ29udGV4dFByb21wdCB9IGZyb20gXCIuL3NyYy9icmFuZC50c1wiO1xuZXhwb3J0IHR5cGUgeyBCcmFuZENvbnRleHQsIEJyYW5kQ29udGV4dElucHV0IH0gZnJvbSBcIi4vc3JjL2JyYW5kLnRzXCI7XG5leHBvcnQgeyBDT01NQU5EX05PVF9GT1VORF9FWElUX0NPREUgfSBmcm9tIFwiLi9zcmMvZXhlYy50c1wiO1xuZXhwb3J0IHR5cGUgeyBFeGVjU3RkaW8sIExpbmVIYW5kbGVyLCBTdGRpb09wdGlvbiwgRXhlY1Jlc3VsdCwgQ2hpbGRQcm9jZXNzUmVzdWx0LCBFeGVjT3B0aW9ucywgU3luY0V4ZWNTdGRpbywgU3luY0V4ZWNPcHRpb25zLCBTcGF3bkFyZ3MgfSBmcm9tIFwiLi9zcmMvZXhlYy50c1wiO1xuZXhwb3J0IHR5cGUgeyBGaWxlTG9ja0JhY2tlbmQsIEZpbGVMb2NrQWNxdWlzaXRpb24sIEZpbGVMb2NrT3B0aW9ucyB9IGZyb20gXCIuL3NyYy9maWxlLWxvY2sudHNcIjtcbmV4cG9ydCB0eXBlIHsgUHJvamVjdENvbnRleHQgfSBmcm9tIFwiLi9zcmMvcHJvamVjdC50c1wiO1xuIl19
15
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwyQ0FBMkM7QUFDM0MsbURBQW1EO0FBQ25ELHdFQUF3RTtBQUV4RSxPQUFPLEtBQUssR0FBRyxNQUFNLGNBQWMsQ0FBQztBQUNwQyxPQUFPLEtBQUssS0FBSyxNQUFNLGdCQUFnQixDQUFDO0FBQ3hDLE9BQU8sS0FBSyxNQUFNLE1BQU0saUJBQWlCLENBQUM7QUFDMUMsT0FBTyxLQUFLLElBQUksTUFBTSxlQUFlLENBQUM7QUFDdEMsT0FBTyxLQUFLLElBQUksTUFBTSxlQUFlLENBQUM7QUFDdEMsT0FBTyxLQUFLLFFBQVEsTUFBTSxvQkFBb0IsQ0FBQztBQUMvQyxPQUFPLEtBQUssV0FBVyxNQUFNLHVCQUF1QixDQUFDO0FBQ3JELE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFFNUMsT0FBTyxFQUFFLGtCQUFrQixFQUFFLG1CQUFtQixFQUFFLGlCQUFpQixFQUFFLHNCQUFzQixFQUFFLGtCQUFrQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFeEksT0FBTyxFQUFFLFlBQVksRUFBRSxzQkFBc0IsRUFBRSxpQkFBaUIsRUFBRSxpQkFBaUIsRUFBRSxRQUFRLEVBQUUsV0FBVyxFQUFFLG9CQUFvQixFQUFFLG9CQUFvQixFQUFFLGVBQWUsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRWpNLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLGVBQWUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIEdFTkVSQVRFRCBieSBwcm9qZW4gd2F0Y2ggLSBETyBOT1QgRURJVC5cbi8vIFJlZ2VuZXJhdGVkIGZyb20gdGhlIGV4cG9ydGluZyBtb2R1bGVzIGluIC4vc3JjLlxuLy8gSGFuZCBlZGl0cyBhcmUgb3ZlcndyaXR0ZW4gb24gdGhlIG5leHQgd2F0Y2g7IHRoaXMgZmlsZSBpcyByZWFkLW9ubHkuXG5cbmV4cG9ydCAqIGFzIGJpbiBmcm9tIFwiLi9zcmMvYmluLnRzXCI7XG5leHBvcnQgKiBhcyBicmFuZCBmcm9tIFwiLi9zcmMvYnJhbmQudHNcIjtcbmV4cG9ydCAqIGFzIGNvbmZpZyBmcm9tIFwiLi9zcmMvY29uZmlnLnRzXCI7XG5leHBvcnQgKiBhcyBleGVjIGZyb20gXCIuL3NyYy9leGVjLnRzXCI7XG5leHBvcnQgKiBhcyBmaWxlIGZyb20gXCIuL3NyYy9maWxlLnRzXCI7XG5leHBvcnQgKiBhcyBmaWxlTG9jayBmcm9tIFwiLi9zcmMvZmlsZS1sb2NrLnRzXCI7XG5leHBvcnQgKiBhcyBwcm9jZXNzTG9jayBmcm9tIFwiLi9zcmMvcHJvY2Vzcy1sb2NrLnRzXCI7XG5leHBvcnQgKiBhcyBwcm9qZWN0IGZyb20gXCIuL3NyYy9wcm9qZWN0LnRzXCI7XG5leHBvcnQgdHlwZSB7IEJpbkNvbnRleHQsIEJpblNlbGVjdGlvbkNvbnRleHQsIEJpblNlbGVjdG9yLCBCaW5WZXJzaW9uT3V0cHV0LCBCaW5WZXJzaW9uUGFyc2VyLCBCaW5PcHRpb25zLCBCaW5VcmwgfSBmcm9tIFwiLi9zcmMvYmluLnRzXCI7XG5leHBvcnQgeyBCcmFuZENvbnRleHRTY2hlbWEsIGRlZmF1bHRCcmFuZENvbnRleHQsIHBhcnNlQnJhbmRDb250ZXh0LCBicmFuZENvbnRleHRKc29uU2NoZW1hLCBicmFuZENvbnRleHRQcm9tcHQgfSBmcm9tIFwiLi9zcmMvYnJhbmQudHNcIjtcbmV4cG9ydCB0eXBlIHsgQnJhbmRDb250ZXh0LCBCcmFuZENvbnRleHRJbnB1dCB9IGZyb20gXCIuL3NyYy9icmFuZC50c1wiO1xuZXhwb3J0IHsgTUFYX1RDUF9QT1JULCBEQVRBQlJJQ0tTX0FQUF9FTlZfS0VZLCBDT05GSUdfRE9URU5WX0tFWSwgQ09ORklHX0JVTkRMRV9LRVksIEVOVl9PTkxZLCBidW5kbGVWYWx1ZSwgYnVuZGxlUmVzb3VyY2VTY2hlbWEsIGJ1bmRsZUVudkVudHJ5U2NoZW1hLCBidW5kbGVBcHBTY2hlbWEgfSBmcm9tIFwiLi9zcmMvY29uZmlnLnRzXCI7XG5leHBvcnQgdHlwZSB7IENvbmZpZ0tleSwgQ29uZmlnU291cmNlLCBDb25maWdPcHRpb25zLCBDb25maWdGaWxlIH0gZnJvbSBcIi4vc3JjL2NvbmZpZy50c1wiO1xuZXhwb3J0IHsgQ09NTUFORF9OT1RfRk9VTkRfRVhJVF9DT0RFIH0gZnJvbSBcIi4vc3JjL2V4ZWMudHNcIjtcbmV4cG9ydCB0eXBlIHsgRXhlY1N0ZGlvLCBMaW5lSGFuZGxlciwgU3RkaW9PcHRpb24sIEV4ZWNSZXN1bHQsIENoaWxkUHJvY2Vzc1Jlc3VsdCwgRXhlY09wdGlvbnMsIFN5bmNFeGVjU3RkaW8sIFN5bmNFeGVjT3B0aW9ucywgU3Bhd25BcmdzIH0gZnJvbSBcIi4vc3JjL2V4ZWMudHNcIjtcbmV4cG9ydCB0eXBlIHsgRmlsZUxvY2tCYWNrZW5kLCBGaWxlTG9ja0FjcXVpc2l0aW9uLCBGaWxlTG9ja09wdGlvbnMgfSBmcm9tIFwiLi9zcmMvZmlsZS1sb2NrLnRzXCI7XG5leHBvcnQgdHlwZSB7IFByb2plY3RDb250ZXh0IH0gZnJvbSBcIi4vc3JjL3Byb2plY3QudHNcIjtcbiJdfQ==
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Layered configuration lookup: environment, `.env`, Databricks bundle.
3
+ *
4
+ * Every package resolves settings the same way: take the caller's value, else
5
+ * an environment variable, else a default. Local development adds two fallback
6
+ * locations: `.env` files and `resources.apps.<app>.config.env` or root
7
+ * `variables` in `databricks.yml`.
8
+ *
9
+ * Two things make it cheap to call from a hot path:
10
+ *
11
+ * - {@link values} is LAZY (an `object.Sequence`), so `databricks bundle
12
+ * validate` is only spawned when the environment and `.env` both missed.
13
+ * - the parsed `.env` and bundle are cached through {@link context.cached}, so
14
+ * the spawn happens once per working directory and a `cwd` change misses
15
+ * rather than returning another project's config.
16
+ *
17
+ * Inside a deployed Databricks App both file sources are skipped by default
18
+ * ({@link isDatabricksAppEnv}): the platform has already turned them into real
19
+ * environment variables, there is no bundle to validate, and the `databricks`
20
+ * CLI is not on the image. Boolean environment overrides can force either file
21
+ * source on or off when a tool needs different behavior.
22
+ *
23
+ * Node-only (`child_process`, `fs`, `process`).
24
+ *
25
+ * @module
26
+ */
27
+ import { z } from "zod";
28
+ export type ConfigKey = string | readonly string[];
29
+ /** Where a value may come from, consulted in the order given. */
30
+ export type ConfigSource = "env" | "dotenv" | "bundle";
31
+ export interface ConfigOptions {
32
+ /**
33
+ * Outermost namespaces tried before each key. Defaults to `DBX_TOOLS`.
34
+ */
35
+ scope?: string | readonly string[];
36
+ /** Capability namespaces inserted after the scope and before each key. */
37
+ prefix?: string | readonly string[];
38
+ /** Directory to resolve `.env` and the bundle from. Default: `process.cwd()`. */
39
+ cwd?: string;
40
+ /** Sources in precedence order. Default: `env`, `dotenv`, `bundle`. */
41
+ sources?: ConfigSource | readonly ConfigSource[];
42
+ }
43
+ /** A config file found on disk, with its parsed contents. */
44
+ export interface ConfigFile {
45
+ path: string;
46
+ data: Record<string, unknown>;
47
+ }
48
+ /** Highest valid TCP port number. */
49
+ export declare const MAX_TCP_PORT = 65535;
50
+ /** Boolean environment override for {@link isDatabricksAppEnv}. */
51
+ export declare const DATABRICKS_APP_ENV_KEY = "DBX_TOOLS_DATABRICKS_APP_ENV";
52
+ /** Boolean environment override for project `.env` reads. */
53
+ export declare const CONFIG_DOTENV_KEY = "DBX_TOOLS_CONFIG_DOTENV";
54
+ /** Boolean environment override for Databricks bundle reads. */
55
+ export declare const CONFIG_BUNDLE_KEY = "DBX_TOOLS_CONFIG_BUNDLE";
56
+ /** Exact process-environment lookup for callers that do not read local config files. */
57
+ export declare const ENV_ONLY: {
58
+ scope: readonly [];
59
+ sources: "env";
60
+ };
61
+ export declare const bundleValue: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
62
+ /**
63
+ * The GENERIC shape of a bundle resource: a name, and whatever else the resource
64
+ * type carries. Deliberately unopinionated and `passthrough()` - the concrete
65
+ * resource kinds (`sql_warehouse`, `genie_space`, `postgres`, ...) are
66
+ * Databricks-App concepts that belong to the package that resolves them, so
67
+ * node-appkit `.extend()`s this rather than this module knowing about them.
68
+ */
69
+ export declare const bundleResourceSchema: z.ZodObject<{
70
+ name: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
71
+ }, z.core.$loose>;
72
+ export declare const bundleEnvEntrySchema: z.ZodObject<{
73
+ name: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
74
+ value: z.ZodOptional<z.ZodString>;
75
+ value_from: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
76
+ }, z.core.$strip>;
77
+ export declare const bundleAppSchema: z.ZodObject<{
78
+ name: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
79
+ source_code_path: z.ZodOptional<z.ZodString>;
80
+ config: z.ZodOptional<z.ZodObject<{
81
+ env: z.ZodOptional<z.ZodArray<z.ZodObject<{
82
+ name: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
83
+ value: z.ZodOptional<z.ZodString>;
84
+ value_from: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
85
+ }, z.core.$strip>>>;
86
+ }, z.core.$strip>>;
87
+ resources: z.ZodOptional<z.ZodArray<z.ZodObject<{
88
+ name: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
89
+ }, z.core.$loose>>>;
90
+ }, z.core.$strip>;
91
+ /**
92
+ * Detect a Databricks App runtime from its required name, host, and port.
93
+ *
94
+ * `DBX_TOOLS_DATABRICKS_APP_ENV` takes precedence when it contains a recognized
95
+ * boolean value. This lets local tools emulate the deployed runtime (`true`) or
96
+ * lets unusual deployed processes retain local config lookup (`false`). An
97
+ * absent or unrecognized override falls back to structural detection.
98
+ */
99
+ export declare function isDatabricksAppEnv(source?: Record<string, string | undefined>): boolean;
100
+ /**
101
+ * The first value that resolves for `input`, or `undefined`.
102
+ *
103
+ * @example
104
+ * const domain = config.text(["TUNNEL_PUBLIC_DOMAIN", "PUBLIC_DOMAIN"]);
105
+ */
106
+ export declare function text(input: ConfigKey, options?: ConfigOptions): string | undefined;
107
+ /**
108
+ * The PRIMARY (fully-scoped) name for `input` - what to print in a log line or an
109
+ * error, so the message names the variable a reader should set. Do not index
110
+ * `keys(...)[0]` for this if `input` may be a bare string.
111
+ *
112
+ * @example
113
+ * logger.warn(`${config.name(JWT_SECRET_ENV)} is not set`);
114
+ */
115
+ export declare function name(input: ConfigKey, options?: Pick<ConfigOptions, "scope" | "prefix">): string;
116
+ /**
117
+ * Resolve a string: `configured` when non-empty, else {@link text}, else `undefined`.
118
+ *
119
+ * The coercion rules are deliberately loose (`on` / `yes` / `1` are all
120
+ * `true`) because values may come from a file a human typed.
121
+ *
122
+ * @example
123
+ * config.string(options.host, "SMTP_HOST");
124
+ */
125
+ export declare function string(configured: unknown, input: ConfigKey, options?: ConfigOptions): string | undefined;
126
+ /**
127
+ * Resolve a boolean through `object.toBoolean`. `undefined` when neither source
128
+ * is interpretable, so the caller picks a default with `??`.
129
+ */
130
+ export declare function boolean(configured: unknown, input: ConfigKey, options?: ConfigOptions): boolean | undefined;
131
+ /**
132
+ * Resolve a positive number that may be fractional (a score threshold, a ratio).
133
+ * Use {@link positiveInt} for a count, port, or timeout.
134
+ */
135
+ export declare function positiveNumber(configured: unknown, input: ConfigKey, fallback: number, options?: ConfigOptions): number;
136
+ /**
137
+ * Resolve a positive integer (a port, a timeout, a page size), floored. A
138
+ * non-numeric or non-positive value is treated as ABSENT rather than fatal -
139
+ * these are ceilings where a sane default beats a boot failure.
140
+ */
141
+ export declare function positiveInt(configured: unknown, input: ConfigKey, fallback: number, options?: ConfigOptions): number;
142
+ /**
143
+ * Resolve a list through `string.parseList`, so an array from typed config and a
144
+ * `"a, b c"` string normalize identically. `[]` when neither source has entries.
145
+ */
146
+ export declare function list(configured: string | readonly string[] | undefined | null, input: ConfigKey, transform?: (entry: string) => string, options?: ConfigOptions): string[];
147
+ /**
148
+ * The Databricks bundle output for `cwd` - `databricks bundle validate --output
149
+ * json` run from the directory holding `databricks.yml`, with the config file's
150
+ * path. A non-zero validation may still return partial JSON with usable
151
+ * variables. `undefined` when bundle reads are disabled, there is no bundle, or
152
+ * the CLI produces no JSON.
153
+ *
154
+ * Cached once per resolved working-directory context and
155
+ * `DATABRICKS_CONFIG_PROFILE` through {@link context.cached}, so repeated
156
+ * lookups do not rerun validation and changing either cannot return another
157
+ * context's bundle.
158
+ */
159
+ export declare function bundleFile(cwd?: string | null): ConfigFile | undefined;