@dbx-tools/appkit 0.3.43 → 0.4.0

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.
@@ -0,0 +1,120 @@
1
+ /**
2
+ * `createApp` wrapper: runs dbx-tools auto-configuration, then delegates to
3
+ * AppKit's own `createApp` with the exact same arguments.
4
+ *
5
+ * Drop it in as a one-for-one replacement for `@databricks/appkit`'s
6
+ * `createApp` - same parameters, same return type, full plugin-export inference
7
+ * preserved:
8
+ *
9
+ * ```ts
10
+ * import { createApp } from "@dbx-tools/appkit";
11
+ * import { lakebase, server } from "@databricks/appkit";
12
+ *
13
+ * await createApp.createApp({ plugins: [server(), lakebase()] });
14
+ * ```
15
+ *
16
+ * Auto-configuration runs BEFORE delegating so plugins see a fully populated
17
+ * `process.env` during their synchronous `setup()`. Lakebase Postgres runs when
18
+ * a `lakebase` plugin is present, or when {@link AutoConfigureMode} is set
19
+ * explicitly on the config object.
20
+ *
21
+ * @module
22
+ */
23
+ import { createApp as appkitCreateApp, getUsernameWithApiLookup } from "@databricks/appkit";
24
+ import { async, log } from "@dbx-tools/shared-core";
25
+ import { applyLakebaseToEnv, resolveLakebaseConnection, } from "./lakebase-resolver.js";
26
+ import { provisionCacheSchema } from "./provision.js";
27
+ const logger = log.logger("create-app");
28
+ const LAKEBASE_PLUGIN = "lakebase";
29
+ const DEFAULT_AUTO_CONFIGURE = "provision";
30
+ /**
31
+ * Upper bound on boot-time auto-configuration. It runs as the service principal
32
+ * before any plugin is constructed, so it sits outside AppKit's interceptor
33
+ * chain and inherits no timeout, retry, or telemetry from it. The budget covers
34
+ * the resolver's own worst case (create a project, then wait for its endpoint)
35
+ * plus the cache-schema grants.
36
+ */
37
+ const AUTO_CONFIGURE_TIMEOUT_MS = 11 * 60_000;
38
+ function usesPlugin(config, name) {
39
+ return Boolean(config?.plugins?.some((entry) => entry.name === name));
40
+ }
41
+ /**
42
+ * Run enabled auto-configuration steps without calling AppKit's `createApp`.
43
+ *
44
+ * Lakebase Postgres resolves when {@link CreateAppConfig.autoConfigure} is set
45
+ * explicitly or a `lakebase` plugin is listed in `config.plugins`. `signal`
46
+ * cancels the resolution; it is combined with an internal boot timeout either
47
+ * way.
48
+ *
49
+ * @example
50
+ * import { createApp } from "@dbx-tools/appkit";
51
+ *
52
+ * // Populate PGHOST / PGDATABASE / LAKEBASE_ENDPOINT without booting AppKit.
53
+ * await createApp.autoConfigure({ autoConfigure: "env" });
54
+ */
55
+ export async function autoConfigure(config, signal) {
56
+ const mode = config?.autoConfigure ?? DEFAULT_AUTO_CONFIGURE;
57
+ const explicit = config?.autoConfigure !== undefined;
58
+ const lakebasePluginPresent = usesPlugin(config, LAKEBASE_PLUGIN);
59
+ if (mode === false || !(explicit || lakebasePluginPresent)) {
60
+ logger.info("ready", {
61
+ autoConfigure: mode,
62
+ lakebasePluginPresent,
63
+ provisioned: false,
64
+ skippedReason: mode === false ? "disabled" : "no lakebase plugin",
65
+ });
66
+ return;
67
+ }
68
+ const controller = new AbortController();
69
+ async.tieAbortSignal(controller, signal);
70
+ async.tieAbortSignal(controller, AbortSignal.timeout(AUTO_CONFIGURE_TIMEOUT_MS));
71
+ const provision = mode === "provision";
72
+ await autoConfigureLakebase(provision, controller.signal);
73
+ logger.info("ready", { autoConfigure: mode, lakebasePluginPresent, provisioned: provision });
74
+ }
75
+ /**
76
+ * Resolve Lakebase Postgres connection info, write the resolved values to
77
+ * `process.env`, and return the record. Used by {@link autoConfigure}; call
78
+ * {@link resolveLakebaseConnection} and {@link applyLakebaseToEnv} directly when
79
+ * finer control is needed.
80
+ */
81
+ async function autoConfigureLakebase(provision, signal) {
82
+ const resolved = await resolveLakebaseConnection(undefined, signal);
83
+ applyLakebaseToEnv(resolved);
84
+ const user = await getUsernameWithApiLookup({});
85
+ if (user)
86
+ process.env.PGUSER ??= user;
87
+ logger.info("env updated", { ...redactLakebaseConnection(resolved), user });
88
+ if (provision) {
89
+ await provisionCacheSchema(user, logger);
90
+ }
91
+ return resolved;
92
+ }
93
+ function redactLakebaseConnection(resolved) {
94
+ return {
95
+ project: resolved.project,
96
+ branch: resolved.branch,
97
+ endpoint: resolved.endpoint,
98
+ database: resolved.database,
99
+ host: resolved.host,
100
+ port: resolved.port,
101
+ sslMode: resolved.sslMode,
102
+ };
103
+ }
104
+ /**
105
+ * Auto-configuring drop-in for AppKit's `createApp`: same config, same typed
106
+ * plugin-export map, with {@link autoConfigure} run first.
107
+ *
108
+ * @example
109
+ * import { createApp } from "@dbx-tools/appkit";
110
+ * import { lakebase, server } from "@databricks/appkit";
111
+ *
112
+ * const app = await createApp.createApp({ plugins: [server(), lakebase()] });
113
+ */
114
+ export async function createApp(config) {
115
+ await autoConfigure(config);
116
+ const appConfig = { ...config };
117
+ delete appConfig.autoConfigure;
118
+ return appkitCreateApp(appConfig);
119
+ }
120
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlLWFwcC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jcmVhdGUtYXBwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FxQkc7QUFFSCxPQUFPLEVBQUUsU0FBUyxJQUFJLGVBQWUsRUFBRSx3QkFBd0IsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBSTVGLE9BQU8sRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFcEQsT0FBTyxFQUNMLGtCQUFrQixFQUNsQix5QkFBeUIsR0FFMUIsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QixPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxhQUFhLENBQUM7QUE2Qm5ELE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUM7QUFFeEMsTUFBTSxlQUFlLEdBQUcsVUFBVSxDQUFDO0FBQ25DLE1BQU0sc0JBQXNCLEdBQXNCLFdBQVcsQ0FBQztBQUU5RDs7Ozs7O0dBTUc7QUFDSCxNQUFNLHlCQUF5QixHQUFHLEVBQUUsR0FBRyxNQUFNLENBQUM7QUFFOUMsU0FBUyxVQUFVLENBQ2pCLE1BQXNDLEVBQ3RDLElBQVk7SUFFWixPQUFPLE9BQU8sQ0FBQyxNQUFNLEVBQUUsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDO0FBQ3hFLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7OztHQWFHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxhQUFhLENBQ2pDLE1BQTJCLEVBQzNCLE1BQW9CO0lBRXBCLE1BQU0sSUFBSSxHQUFHLE1BQU0sRUFBRSxhQUFhLElBQUksc0JBQXNCLENBQUM7SUFDN0QsTUFBTSxRQUFRLEdBQUcsTUFBTSxFQUFFLGFBQWEsS0FBSyxTQUFTLENBQUM7SUFDckQsTUFBTSxxQkFBcUIsR0FBRyxVQUFVLENBQUMsTUFBTSxFQUFFLGVBQWUsQ0FBQyxDQUFDO0lBQ2xFLElBQUksSUFBSSxLQUFLLEtBQUssSUFBSSxDQUFDLENBQUMsUUFBUSxJQUFJLHFCQUFxQixDQUFDLEVBQUUsQ0FBQztRQUMzRCxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRTtZQUNuQixhQUFhLEVBQUUsSUFBSTtZQUNuQixxQkFBcUI7WUFDckIsV0FBVyxFQUFFLEtBQUs7WUFDbEIsYUFBYSxFQUFFLElBQUksS0FBSyxLQUFLLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsb0JBQW9CO1NBQ2xFLENBQUMsQ0FBQztRQUNILE9BQU87SUFDVCxDQUFDO0lBRUQsTUFBTSxVQUFVLEdBQUcsSUFBSSxlQUFlLEVBQUUsQ0FBQztJQUN6QyxLQUFLLENBQUMsY0FBYyxDQUFDLFVBQVUsRUFBRSxNQUFNLENBQUMsQ0FBQztJQUN6QyxLQUFLLENBQUMsY0FBYyxDQUFDLFVBQVUsRUFBRSxXQUFXLENBQUMsT0FBTyxDQUFDLHlCQUF5QixDQUFDLENBQUMsQ0FBQztJQUVqRixNQUFNLFNBQVMsR0FBRyxJQUFJLEtBQUssV0FBVyxDQUFDO0lBQ3ZDLE1BQU0scUJBQXFCLENBQUMsU0FBUyxFQUFFLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUMxRCxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxFQUFFLGFBQWEsRUFBRSxJQUFJLEVBQUUscUJBQXFCLEVBQUUsV0FBVyxFQUFFLFNBQVMsRUFBRSxDQUFDLENBQUM7QUFDL0YsQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsS0FBSyxVQUFVLHFCQUFxQixDQUNsQyxTQUFrQixFQUNsQixNQUFtQjtJQUVuQixNQUFNLFFBQVEsR0FBRyxNQUFNLHlCQUF5QixDQUFDLFNBQVMsRUFBRSxNQUFNLENBQUMsQ0FBQztJQUNwRSxrQkFBa0IsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUM3QixNQUFNLElBQUksR0FBRyxNQUFNLHdCQUF3QixDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ2hELElBQUksSUFBSTtRQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxLQUFLLElBQUksQ0FBQztJQUN0QyxNQUFNLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRSxFQUFFLEdBQUcsd0JBQXdCLENBQUMsUUFBUSxDQUFDLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUM1RSxJQUFJLFNBQVMsRUFBRSxDQUFDO1FBQ2QsTUFBTSxvQkFBb0IsQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDM0MsQ0FBQztJQUNELE9BQU8sUUFBUSxDQUFDO0FBQ2xCLENBQUM7QUFFRCxTQUFTLHdCQUF3QixDQUFDLFFBQTRCO0lBQzVELE9BQU87UUFDTCxPQUFPLEVBQUUsUUFBUSxDQUFDLE9BQU87UUFDekIsTUFBTSxFQUFFLFFBQVEsQ0FBQyxNQUFNO1FBQ3ZCLFFBQVEsRUFBRSxRQUFRLENBQUMsUUFBUTtRQUMzQixRQUFRLEVBQUUsUUFBUSxDQUFDLFFBQVE7UUFDM0IsSUFBSSxFQUFFLFFBQVEsQ0FBQyxJQUFJO1FBQ25CLElBQUksRUFBRSxRQUFRLENBQUMsSUFBSTtRQUNuQixPQUFPLEVBQUUsUUFBUSxDQUFDLE9BQU87S0FDMUIsQ0FBQztBQUNKLENBQUM7QUFFRDs7Ozs7Ozs7O0dBU0c7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLFNBQVMsQ0FDN0IsTUFBMkI7SUFFM0IsTUFBTSxhQUFhLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDNUIsTUFBTSxTQUFTLEdBQUcsRUFBRSxHQUFHLE1BQU0sRUFBRSxDQUFDO0lBQ2hDLE9BQU8sU0FBUyxDQUFDLGFBQWEsQ0FBQztJQUMvQixPQUFPLGVBQWUsQ0FBSSxTQUFTLENBQUMsQ0FBQztBQUN2QyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBgY3JlYXRlQXBwYCB3cmFwcGVyOiBydW5zIGRieC10b29scyBhdXRvLWNvbmZpZ3VyYXRpb24sIHRoZW4gZGVsZWdhdGVzIHRvXG4gKiBBcHBLaXQncyBvd24gYGNyZWF0ZUFwcGAgd2l0aCB0aGUgZXhhY3Qgc2FtZSBhcmd1bWVudHMuXG4gKlxuICogRHJvcCBpdCBpbiBhcyBhIG9uZS1mb3Itb25lIHJlcGxhY2VtZW50IGZvciBgQGRhdGFicmlja3MvYXBwa2l0YCdzXG4gKiBgY3JlYXRlQXBwYCAtIHNhbWUgcGFyYW1ldGVycywgc2FtZSByZXR1cm4gdHlwZSwgZnVsbCBwbHVnaW4tZXhwb3J0IGluZmVyZW5jZVxuICogcHJlc2VydmVkOlxuICpcbiAqIGBgYHRzXG4gKiBpbXBvcnQgeyBjcmVhdGVBcHAgfSBmcm9tIFwiQGRieC10b29scy9hcHBraXRcIjtcbiAqIGltcG9ydCB7IGxha2ViYXNlLCBzZXJ2ZXIgfSBmcm9tIFwiQGRhdGFicmlja3MvYXBwa2l0XCI7XG4gKlxuICogYXdhaXQgY3JlYXRlQXBwLmNyZWF0ZUFwcCh7IHBsdWdpbnM6IFtzZXJ2ZXIoKSwgbGFrZWJhc2UoKV0gfSk7XG4gKiBgYGBcbiAqXG4gKiBBdXRvLWNvbmZpZ3VyYXRpb24gcnVucyBCRUZPUkUgZGVsZWdhdGluZyBzbyBwbHVnaW5zIHNlZSBhIGZ1bGx5IHBvcHVsYXRlZFxuICogYHByb2Nlc3MuZW52YCBkdXJpbmcgdGhlaXIgc3luY2hyb25vdXMgYHNldHVwKClgLiBMYWtlYmFzZSBQb3N0Z3JlcyBydW5zIHdoZW5cbiAqIGEgYGxha2ViYXNlYCBwbHVnaW4gaXMgcHJlc2VudCwgb3Igd2hlbiB7QGxpbmsgQXV0b0NvbmZpZ3VyZU1vZGV9IGlzIHNldFxuICogZXhwbGljaXRseSBvbiB0aGUgY29uZmlnIG9iamVjdC5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgY3JlYXRlQXBwIGFzIGFwcGtpdENyZWF0ZUFwcCwgZ2V0VXNlcm5hbWVXaXRoQXBpTG9va3VwIH0gZnJvbSBcIkBkYXRhYnJpY2tzL2FwcGtpdFwiO1xuLy8gQXBwS2l0J3Mgcm9vdCBiYXJyZWwgcmUtZXhwb3J0cyBgUGx1Z2luRGF0YWAgYnV0IG5vdCBgUGx1Z2luTWFwYDsgdGhlIHBhY2thZ2Vcbi8vIHB1Ymxpc2hlcyB0aGlzIHN1YnBhdGggZm9yIGV4YWN0bHkgdGhhdCB0eXBlLlxuaW1wb3J0IHR5cGUgeyBQbHVnaW5NYXAgfSBmcm9tIFwiQGRhdGFicmlja3MvYXBwa2l0L2Rpc3Qvc2hhcmVkL3NyYy9wbHVnaW5cIjtcbmltcG9ydCB7IGFzeW5jLCBsb2cgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuXG5pbXBvcnQge1xuICBhcHBseUxha2ViYXNlVG9FbnYsXG4gIHJlc29sdmVMYWtlYmFzZUNvbm5lY3Rpb24sXG4gIHR5cGUgTGFrZWJhc2VDb25uZWN0aW9uLFxufSBmcm9tIFwiLi9sYWtlYmFzZS1yZXNvbHZlclwiO1xuaW1wb3J0IHsgcHJvdmlzaW9uQ2FjaGVTY2hlbWEgfSBmcm9tIFwiLi9wcm92aXNpb25cIjtcblxudHlwZSBBcHBLaXRDcmVhdGVBcHBDb25maWcgPSBOb25OdWxsYWJsZTxQYXJhbWV0ZXJzPHR5cGVvZiBhcHBraXRDcmVhdGVBcHA+WzBdPjtcbnR5cGUgQXBwS2l0UGx1Z2lucyA9IE5vbk51bGxhYmxlPEFwcEtpdENyZWF0ZUFwcENvbmZpZ1tcInBsdWdpbnNcIl0+O1xuXG4vKipcbiAqIFdoYXQgYXV0by1jb25maWd1cmF0aW9uIGRvZXMgYmVmb3JlIEFwcEtpdCBib290cy5cbiAqXG4gKiAtIGBcInByb3Zpc2lvblwiYDogcmVzb2x2ZSB0aGUgTGFrZWJhc2UgY29ubmVjdGlvbiBpbnRvIGBwcm9jZXNzLmVudmAsIHRoZW5cbiAqICAgZ3JhbnQgdGhlIEFwcEtpdCBjYWNoZSBzY2hlbWEgdG8gdGhlIGNvbm5lY3Rpbmcgcm9sZS5cbiAqIC0gYFwiZW52XCJgOiByZXNvbHZlIHRoZSBMYWtlYmFzZSBjb25uZWN0aW9uIGludG8gYHByb2Nlc3MuZW52YCBvbmx5LlxuICpcbiAqIE9taXQgaXQgdG8gZ2V0IGBcInByb3Zpc2lvblwiYCBnYXRlZCBvbiBhIGBsYWtlYmFzZWAgcGx1Z2luIGJlaW5nIHJlZ2lzdGVyZWQ7XG4gKiBzZXQgaXQgZXhwbGljaXRseSB0byBydW4gcmVnYXJkbGVzcyBvZiB0aGUgcGx1Z2luIGxpc3QsIG9yIHBhc3MgYGZhbHNlYCB0b1xuICogc2tpcCBhdXRvLWNvbmZpZ3VyYXRpb24gZW50aXJlbHkuXG4gKi9cbmV4cG9ydCB0eXBlIEF1dG9Db25maWd1cmVNb2RlID0gXCJlbnZcIiB8IFwicHJvdmlzaW9uXCI7XG5cbi8qKiBBcHBLaXQncyBgY3JlYXRlQXBwYCBjb25maWcgcGx1cyB0aGUgZGJ4LXRvb2xzIGF1dG8tY29uZmlndXJhdGlvbiBzd2l0Y2guICovXG5leHBvcnQgdHlwZSBDcmVhdGVBcHBDb25maWc8VCBleHRlbmRzIEFwcEtpdFBsdWdpbnMgPSBBcHBLaXRQbHVnaW5zPiA9IE9taXQ8XG4gIEFwcEtpdENyZWF0ZUFwcENvbmZpZyxcbiAgXCJwbHVnaW5zXCIgfCBcIm9uUGx1Z2luc1JlYWR5XCJcbj4gJiB7XG4gIHBsdWdpbnM/OiBUO1xuICBvblBsdWdpbnNSZWFkeT86IChhcHBraXQ6IFBsdWdpbk1hcDxUPikgPT4gdm9pZCB8IFByb21pc2U8dm9pZD47XG4gIC8qKiBBdXRvLWNvbmZpZ3VyYXRpb24gdG8gcnVuIGJlZm9yZSBBcHBLaXQgYm9vdHMuIERlZmF1bHRzIHRvIGBcInByb3Zpc2lvblwiYC4gKi9cbiAgYXV0b0NvbmZpZ3VyZT86IEF1dG9Db25maWd1cmVNb2RlIHwgZmFsc2U7XG59O1xuXG5jb25zdCBsb2dnZXIgPSBsb2cubG9nZ2VyKFwiY3JlYXRlLWFwcFwiKTtcblxuY29uc3QgTEFLRUJBU0VfUExVR0lOID0gXCJsYWtlYmFzZVwiO1xuY29uc3QgREVGQVVMVF9BVVRPX0NPTkZJR1VSRTogQXV0b0NvbmZpZ3VyZU1vZGUgPSBcInByb3Zpc2lvblwiO1xuXG4vKipcbiAqIFVwcGVyIGJvdW5kIG9uIGJvb3QtdGltZSBhdXRvLWNvbmZpZ3VyYXRpb24uIEl0IHJ1bnMgYXMgdGhlIHNlcnZpY2UgcHJpbmNpcGFsXG4gKiBiZWZvcmUgYW55IHBsdWdpbiBpcyBjb25zdHJ1Y3RlZCwgc28gaXQgc2l0cyBvdXRzaWRlIEFwcEtpdCdzIGludGVyY2VwdG9yXG4gKiBjaGFpbiBhbmQgaW5oZXJpdHMgbm8gdGltZW91dCwgcmV0cnksIG9yIHRlbGVtZXRyeSBmcm9tIGl0LiBUaGUgYnVkZ2V0IGNvdmVyc1xuICogdGhlIHJlc29sdmVyJ3Mgb3duIHdvcnN0IGNhc2UgKGNyZWF0ZSBhIHByb2plY3QsIHRoZW4gd2FpdCBmb3IgaXRzIGVuZHBvaW50KVxuICogcGx1cyB0aGUgY2FjaGUtc2NoZW1hIGdyYW50cy5cbiAqL1xuY29uc3QgQVVUT19DT05GSUdVUkVfVElNRU9VVF9NUyA9IDExICogNjBfMDAwO1xuXG5mdW5jdGlvbiB1c2VzUGx1Z2luPFQgZXh0ZW5kcyBBcHBLaXRQbHVnaW5zPihcbiAgY29uZmlnOiBDcmVhdGVBcHBDb25maWc8VD4gfCB1bmRlZmluZWQsXG4gIG5hbWU6IHN0cmluZyxcbik6IGJvb2xlYW4ge1xuICByZXR1cm4gQm9vbGVhbihjb25maWc/LnBsdWdpbnM/LnNvbWUoKGVudHJ5KSA9PiBlbnRyeS5uYW1lID09PSBuYW1lKSk7XG59XG5cbi8qKlxuICogUnVuIGVuYWJsZWQgYXV0by1jb25maWd1cmF0aW9uIHN0ZXBzIHdpdGhvdXQgY2FsbGluZyBBcHBLaXQncyBgY3JlYXRlQXBwYC5cbiAqXG4gKiBMYWtlYmFzZSBQb3N0Z3JlcyByZXNvbHZlcyB3aGVuIHtAbGluayBDcmVhdGVBcHBDb25maWcuYXV0b0NvbmZpZ3VyZX0gaXMgc2V0XG4gKiBleHBsaWNpdGx5IG9yIGEgYGxha2ViYXNlYCBwbHVnaW4gaXMgbGlzdGVkIGluIGBjb25maWcucGx1Z2luc2AuIGBzaWduYWxgXG4gKiBjYW5jZWxzIHRoZSByZXNvbHV0aW9uOyBpdCBpcyBjb21iaW5lZCB3aXRoIGFuIGludGVybmFsIGJvb3QgdGltZW91dCBlaXRoZXJcbiAqIHdheS5cbiAqXG4gKiBAZXhhbXBsZVxuICogaW1wb3J0IHsgY3JlYXRlQXBwIH0gZnJvbSBcIkBkYngtdG9vbHMvYXBwa2l0XCI7XG4gKlxuICogLy8gUG9wdWxhdGUgUEdIT1NUIC8gUEdEQVRBQkFTRSAvIExBS0VCQVNFX0VORFBPSU5UIHdpdGhvdXQgYm9vdGluZyBBcHBLaXQuXG4gKiBhd2FpdCBjcmVhdGVBcHAuYXV0b0NvbmZpZ3VyZSh7IGF1dG9Db25maWd1cmU6IFwiZW52XCIgfSk7XG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBhdXRvQ29uZmlndXJlPFQgZXh0ZW5kcyBBcHBLaXRQbHVnaW5zPihcbiAgY29uZmlnPzogQ3JlYXRlQXBwQ29uZmlnPFQ+LFxuICBzaWduYWw/OiBBYm9ydFNpZ25hbCxcbik6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBtb2RlID0gY29uZmlnPy5hdXRvQ29uZmlndXJlID8/IERFRkFVTFRfQVVUT19DT05GSUdVUkU7XG4gIGNvbnN0IGV4cGxpY2l0ID0gY29uZmlnPy5hdXRvQ29uZmlndXJlICE9PSB1bmRlZmluZWQ7XG4gIGNvbnN0IGxha2ViYXNlUGx1Z2luUHJlc2VudCA9IHVzZXNQbHVnaW4oY29uZmlnLCBMQUtFQkFTRV9QTFVHSU4pO1xuICBpZiAobW9kZSA9PT0gZmFsc2UgfHwgIShleHBsaWNpdCB8fCBsYWtlYmFzZVBsdWdpblByZXNlbnQpKSB7XG4gICAgbG9nZ2VyLmluZm8oXCJyZWFkeVwiLCB7XG4gICAgICBhdXRvQ29uZmlndXJlOiBtb2RlLFxuICAgICAgbGFrZWJhc2VQbHVnaW5QcmVzZW50LFxuICAgICAgcHJvdmlzaW9uZWQ6IGZhbHNlLFxuICAgICAgc2tpcHBlZFJlYXNvbjogbW9kZSA9PT0gZmFsc2UgPyBcImRpc2FibGVkXCIgOiBcIm5vIGxha2ViYXNlIHBsdWdpblwiLFxuICAgIH0pO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IGNvbnRyb2xsZXIgPSBuZXcgQWJvcnRDb250cm9sbGVyKCk7XG4gIGFzeW5jLnRpZUFib3J0U2lnbmFsKGNvbnRyb2xsZXIsIHNpZ25hbCk7XG4gIGFzeW5jLnRpZUFib3J0U2lnbmFsKGNvbnRyb2xsZXIsIEFib3J0U2lnbmFsLnRpbWVvdXQoQVVUT19DT05GSUdVUkVfVElNRU9VVF9NUykpO1xuXG4gIGNvbnN0IHByb3Zpc2lvbiA9IG1vZGUgPT09IFwicHJvdmlzaW9uXCI7XG4gIGF3YWl0IGF1dG9Db25maWd1cmVMYWtlYmFzZShwcm92aXNpb24sIGNvbnRyb2xsZXIuc2lnbmFsKTtcbiAgbG9nZ2VyLmluZm8oXCJyZWFkeVwiLCB7IGF1dG9Db25maWd1cmU6IG1vZGUsIGxha2ViYXNlUGx1Z2luUHJlc2VudCwgcHJvdmlzaW9uZWQ6IHByb3Zpc2lvbiB9KTtcbn1cblxuLyoqXG4gKiBSZXNvbHZlIExha2ViYXNlIFBvc3RncmVzIGNvbm5lY3Rpb24gaW5mbywgd3JpdGUgdGhlIHJlc29sdmVkIHZhbHVlcyB0b1xuICogYHByb2Nlc3MuZW52YCwgYW5kIHJldHVybiB0aGUgcmVjb3JkLiBVc2VkIGJ5IHtAbGluayBhdXRvQ29uZmlndXJlfTsgY2FsbFxuICoge0BsaW5rIHJlc29sdmVMYWtlYmFzZUNvbm5lY3Rpb259IGFuZCB7QGxpbmsgYXBwbHlMYWtlYmFzZVRvRW52fSBkaXJlY3RseSB3aGVuXG4gKiBmaW5lciBjb250cm9sIGlzIG5lZWRlZC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gYXV0b0NvbmZpZ3VyZUxha2ViYXNlKFxuICBwcm92aXNpb246IGJvb2xlYW4sXG4gIHNpZ25hbDogQWJvcnRTaWduYWwsXG4pOiBQcm9taXNlPExha2ViYXNlQ29ubmVjdGlvbj4ge1xuICBjb25zdCByZXNvbHZlZCA9IGF3YWl0IHJlc29sdmVMYWtlYmFzZUNvbm5lY3Rpb24odW5kZWZpbmVkLCBzaWduYWwpO1xuICBhcHBseUxha2ViYXNlVG9FbnYocmVzb2x2ZWQpO1xuICBjb25zdCB1c2VyID0gYXdhaXQgZ2V0VXNlcm5hbWVXaXRoQXBpTG9va3VwKHt9KTtcbiAgaWYgKHVzZXIpIHByb2Nlc3MuZW52LlBHVVNFUiA/Pz0gdXNlcjtcbiAgbG9nZ2VyLmluZm8oXCJlbnYgdXBkYXRlZFwiLCB7IC4uLnJlZGFjdExha2ViYXNlQ29ubmVjdGlvbihyZXNvbHZlZCksIHVzZXIgfSk7XG4gIGlmIChwcm92aXNpb24pIHtcbiAgICBhd2FpdCBwcm92aXNpb25DYWNoZVNjaGVtYSh1c2VyLCBsb2dnZXIpO1xuICB9XG4gIHJldHVybiByZXNvbHZlZDtcbn1cblxuZnVuY3Rpb24gcmVkYWN0TGFrZWJhc2VDb25uZWN0aW9uKHJlc29sdmVkOiBMYWtlYmFzZUNvbm5lY3Rpb24pOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB7XG4gIHJldHVybiB7XG4gICAgcHJvamVjdDogcmVzb2x2ZWQucHJvamVjdCxcbiAgICBicmFuY2g6IHJlc29sdmVkLmJyYW5jaCxcbiAgICBlbmRwb2ludDogcmVzb2x2ZWQuZW5kcG9pbnQsXG4gICAgZGF0YWJhc2U6IHJlc29sdmVkLmRhdGFiYXNlLFxuICAgIGhvc3Q6IHJlc29sdmVkLmhvc3QsXG4gICAgcG9ydDogcmVzb2x2ZWQucG9ydCxcbiAgICBzc2xNb2RlOiByZXNvbHZlZC5zc2xNb2RlLFxuICB9O1xufVxuXG4vKipcbiAqIEF1dG8tY29uZmlndXJpbmcgZHJvcC1pbiBmb3IgQXBwS2l0J3MgYGNyZWF0ZUFwcGA6IHNhbWUgY29uZmlnLCBzYW1lIHR5cGVkXG4gKiBwbHVnaW4tZXhwb3J0IG1hcCwgd2l0aCB7QGxpbmsgYXV0b0NvbmZpZ3VyZX0gcnVuIGZpcnN0LlxuICpcbiAqIEBleGFtcGxlXG4gKiBpbXBvcnQgeyBjcmVhdGVBcHAgfSBmcm9tIFwiQGRieC10b29scy9hcHBraXRcIjtcbiAqIGltcG9ydCB7IGxha2ViYXNlLCBzZXJ2ZXIgfSBmcm9tIFwiQGRhdGFicmlja3MvYXBwa2l0XCI7XG4gKlxuICogY29uc3QgYXBwID0gYXdhaXQgY3JlYXRlQXBwLmNyZWF0ZUFwcCh7IHBsdWdpbnM6IFtzZXJ2ZXIoKSwgbGFrZWJhc2UoKV0gfSk7XG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVBcHA8VCBleHRlbmRzIEFwcEtpdFBsdWdpbnM+KFxuICBjb25maWc/OiBDcmVhdGVBcHBDb25maWc8VD4sXG4pOiBQcm9taXNlPFBsdWdpbk1hcDxUPj4ge1xuICBhd2FpdCBhdXRvQ29uZmlndXJlKGNvbmZpZyk7XG4gIGNvbnN0IGFwcENvbmZpZyA9IHsgLi4uY29uZmlnIH07XG4gIGRlbGV0ZSBhcHBDb25maWcuYXV0b0NvbmZpZ3VyZTtcbiAgcmV0dXJuIGFwcGtpdENyZWF0ZUFwcDxUPihhcHBDb25maWcpO1xufVxuIl19
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Generic Databricks SDK glue (no AppKit): adapt WHATWG cancellation
3
+ * (`AbortSignal` / `AbortController`) into the SDK's `Context` /
4
+ * `CancellationToken` shapes so a single `AbortController` can drive every
5
+ * in-flight SDK call, plus Databricks runtime-environment detection.
6
+ *
7
+ * Server-only: leans on the Databricks SDK `Context`. Lives in node-appkit so
8
+ * the browser-safe shared-core stays SDK-free.
9
+ *
10
+ * @module
11
+ */
12
+ import { Context } from "@databricks/sdk-experimental";
13
+ /** Highest valid TCP port number. */
14
+ export declare const MAX_TCP_PORT = 65535;
15
+ /**
16
+ * Detect the Databricks App runtime from environment shape: requires a
17
+ * non-empty `DATABRICKS_APP_NAME`, a `DATABRICKS_HOST` that parses as an
18
+ * `http`/`https` URL, and a `DATABRICKS_APP_PORT` that is a valid TCP port.
19
+ * Reads `process.env` when no `env` is passed.
20
+ *
21
+ * @example
22
+ * import { databricks } from "@dbx-tools/appkit";
23
+ *
24
+ * // Skip bundle / app.yaml discovery when the app is already deployed.
25
+ * const local = !databricks.isAppEnv();
26
+ */
27
+ export declare function isAppEnv(env?: Record<string, string | undefined>): boolean;
28
+ /** Either an SDK `Context` or a WHATWG `AbortSignal`. */
29
+ export type ContextLike = Context | AbortSignal;
30
+ /**
31
+ * Wrap a `Context` (returned as-is) or `AbortSignal` (adapted) as an SDK `Context`.
32
+ *
33
+ * @example
34
+ * import { databricks } from "@dbx-tools/appkit";
35
+ * import { getWorkspaceClient } from "@databricks/appkit";
36
+ *
37
+ * await getWorkspaceClient({}).apiClient.request(
38
+ * { path: "/api/2.0/serving-endpoints", method: "GET", headers: new Headers(), raw: false },
39
+ * databricks.toContext(request.signal),
40
+ * );
41
+ */
42
+ export declare function toContext(input: ContextLike): Context;
43
+ /**
44
+ * Derive an SDK `Context` from `controller.signal`, optionally tying `input`
45
+ * into the controller so the controller becomes the single cancellation
46
+ * source for downstream SDK calls:
47
+ *
48
+ * - `AbortSignal`: aborting it propagates into `controller` (and from there
49
+ * into every SDK call you pass the returned context to).
50
+ * - `Context`: its `cancellationToken` is tied into `controller`, and its
51
+ * other fields (`logger`, `opName`, `rootClassName`, `rootFnName`, `opId`)
52
+ * are preserved in the returned `Context`. The returned context's
53
+ * `cancellationToken` is replaced with one backed by `controller.signal`.
54
+ *
55
+ * The tie is one-way (parent -> child): aborting `controller` directly does
56
+ * NOT cancel `input`. So a request-level cancel (your loop's `try/finally {
57
+ * controller.abort() }`) won't tear down a caller-supplied AbortSignal it
58
+ * didn't own.
59
+ */
60
+ export declare function toContext(controller: AbortController, input?: ContextLike): Context;
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Generic Databricks SDK glue (no AppKit): adapt WHATWG cancellation
3
+ * (`AbortSignal` / `AbortController`) into the SDK's `Context` /
4
+ * `CancellationToken` shapes so a single `AbortController` can drive every
5
+ * in-flight SDK call, plus Databricks runtime-environment detection.
6
+ *
7
+ * Server-only: leans on the Databricks SDK `Context`. Lives in node-appkit so
8
+ * the browser-safe shared-core stays SDK-free.
9
+ *
10
+ * @module
11
+ */
12
+ import { Context } from "@databricks/sdk-experimental";
13
+ import { async, log } from "@dbx-tools/shared-core";
14
+ const logger = log.logger("databricks");
15
+ /** Highest valid TCP port number. */
16
+ export const MAX_TCP_PORT = 65_535;
17
+ /**
18
+ * Detect the Databricks App runtime from environment shape: requires a
19
+ * non-empty `DATABRICKS_APP_NAME`, a `DATABRICKS_HOST` that parses as an
20
+ * `http`/`https` URL, and a `DATABRICKS_APP_PORT` that is a valid TCP port.
21
+ * Reads `process.env` when no `env` is passed.
22
+ *
23
+ * @example
24
+ * import { databricks } from "@dbx-tools/appkit";
25
+ *
26
+ * // Skip bundle / app.yaml discovery when the app is already deployed.
27
+ * const local = !databricks.isAppEnv();
28
+ */
29
+ export function isAppEnv(env = process.env) {
30
+ const appName = env.DATABRICKS_APP_NAME?.trim();
31
+ const host = env.DATABRICKS_HOST?.trim();
32
+ const port = env.DATABRICKS_APP_PORT?.trim();
33
+ if (!appName || !host || !port) {
34
+ return false;
35
+ }
36
+ try {
37
+ const url = new URL(host);
38
+ if (!["http:", "https:"].includes(url.protocol)) {
39
+ logger.debug("app env rejected: host is not an http(s) URL");
40
+ return false;
41
+ }
42
+ }
43
+ catch {
44
+ logger.debug("app env rejected: host is not a URL");
45
+ return false;
46
+ }
47
+ const portNumber = Number(port);
48
+ if (!Number.isInteger(portNumber) || portNumber < 1 || portNumber > MAX_TCP_PORT) {
49
+ logger.debug("app env rejected: DATABRICKS_APP_PORT is not a TCP port");
50
+ return false;
51
+ }
52
+ return true;
53
+ }
54
+ export function toContext(source, input) {
55
+ if (!(source instanceof AbortController)) {
56
+ if (source instanceof Context)
57
+ return source;
58
+ return new Context({ cancellationToken: signalToCancellationToken(source) });
59
+ }
60
+ if (input instanceof AbortSignal) {
61
+ async.tieAbortSignal(source, input);
62
+ }
63
+ else if (input instanceof Context) {
64
+ const token = input.cancellationToken;
65
+ if (token)
66
+ tieCancellationToken(source, token);
67
+ const merged = input.copy();
68
+ merged.setItems({ cancellationToken: signalToCancellationToken(source.signal) });
69
+ return merged;
70
+ }
71
+ return new Context({ cancellationToken: signalToCancellationToken(source.signal) });
72
+ }
73
+ /**
74
+ * Adapt a WHATWG `AbortSignal` to the Databricks SDK's `CancellationToken`
75
+ * interface. The SDK's `api-client.ts` internally creates an `AbortController`
76
+ * and wires `cancellationToken.onCancellationRequested` to it, so this adapter
77
+ * is the one-line bridge from "platform-standard cancellation" to "the SDK
78
+ * aborts the fetch on your behalf".
79
+ */
80
+ function signalToCancellationToken(signal) {
81
+ return {
82
+ get isCancellationRequested() {
83
+ return signal.aborted;
84
+ },
85
+ onCancellationRequested(cb) {
86
+ if (signal.aborted) {
87
+ cb(signal.reason);
88
+ return;
89
+ }
90
+ signal.addEventListener("abort", () => cb(signal.reason), { once: true });
91
+ },
92
+ };
93
+ }
94
+ /**
95
+ * Tie the SDK's `CancellationToken` interface back into an `AbortController`.
96
+ * Mirrors `async.tieAbortSignal` but for the SDK's cancellation shape, used
97
+ * when a caller hands us a pre-built `Context` whose token we want to fold into
98
+ * our own controller.
99
+ */
100
+ function tieCancellationToken(controller, token) {
101
+ if (token.isCancellationRequested) {
102
+ controller.abort();
103
+ return;
104
+ }
105
+ token.onCancellationRequested((reason) => controller.abort(reason));
106
+ }
107
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YWJyaWNrcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kYXRhYnJpY2tzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7O0dBVUc7QUFHSCxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDdkQsT0FBTyxFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUVwRCxNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLFlBQVksQ0FBQyxDQUFDO0FBRXhDLHFDQUFxQztBQUNyQyxNQUFNLENBQUMsTUFBTSxZQUFZLEdBQUcsTUFBTSxDQUFDO0FBRW5DOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsTUFBTSxVQUFVLFFBQVEsQ0FBQyxNQUEwQyxPQUFPLENBQUMsR0FBRztJQUM1RSxNQUFNLE9BQU8sR0FBRyxHQUFHLENBQUMsbUJBQW1CLEVBQUUsSUFBSSxFQUFFLENBQUM7SUFDaEQsTUFBTSxJQUFJLEdBQUcsR0FBRyxDQUFDLGVBQWUsRUFBRSxJQUFJLEVBQUUsQ0FBQztJQUN6QyxNQUFNLElBQUksR0FBRyxHQUFHLENBQUMsbUJBQW1CLEVBQUUsSUFBSSxFQUFFLENBQUM7SUFFN0MsSUFBSSxDQUFDLE9BQU8sSUFBSSxDQUFDLElBQUksSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQy9CLE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVELElBQUksQ0FBQztRQUNILE1BQU0sR0FBRyxHQUFHLElBQUksR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzFCLElBQUksQ0FBQyxDQUFDLE9BQU8sRUFBRSxRQUFRLENBQUMsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7WUFDaEQsTUFBTSxDQUFDLEtBQUssQ0FBQyw4Q0FBOEMsQ0FBQyxDQUFDO1lBQzdELE9BQU8sS0FBSyxDQUFDO1FBQ2YsQ0FBQztJQUNILENBQUM7SUFBQyxNQUFNLENBQUM7UUFDUCxNQUFNLENBQUMsS0FBSyxDQUFDLHFDQUFxQyxDQUFDLENBQUM7UUFDcEQsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBRUQsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2hDLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLFVBQVUsQ0FBQyxJQUFJLFVBQVUsR0FBRyxDQUFDLElBQUksVUFBVSxHQUFHLFlBQVksRUFBRSxDQUFDO1FBQ2pGLE1BQU0sQ0FBQyxLQUFLLENBQUMseURBQXlELENBQUMsQ0FBQztRQUN4RSxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCxPQUFPLElBQUksQ0FBQztBQUNkLENBQUM7QUFvQ0QsTUFBTSxVQUFVLFNBQVMsQ0FBQyxNQUFxQyxFQUFFLEtBQW1CO0lBQ2xGLElBQUksQ0FBQyxDQUFDLE1BQU0sWUFBWSxlQUFlLENBQUMsRUFBRSxDQUFDO1FBQ3pDLElBQUksTUFBTSxZQUFZLE9BQU87WUFBRSxPQUFPLE1BQU0sQ0FBQztRQUM3QyxPQUFPLElBQUksT0FBTyxDQUFDLEVBQUUsaUJBQWlCLEVBQUUseUJBQXlCLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQy9FLENBQUM7SUFDRCxJQUFJLEtBQUssWUFBWSxXQUFXLEVBQUUsQ0FBQztRQUNqQyxLQUFLLENBQUMsY0FBYyxDQUFDLE1BQU0sRUFBRSxLQUFLLENBQUMsQ0FBQztJQUN0QyxDQUFDO1NBQU0sSUFBSSxLQUFLLFlBQVksT0FBTyxFQUFFLENBQUM7UUFDcEMsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLGlCQUFpQixDQUFDO1FBQ3RDLElBQUksS0FBSztZQUFFLG9CQUFvQixDQUFDLE1BQU0sRUFBRSxLQUFLLENBQUMsQ0FBQztRQUMvQyxNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDNUIsTUFBTSxDQUFDLFFBQVEsQ0FBQyxFQUFFLGlCQUFpQixFQUFFLHlCQUF5QixDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDakYsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUNELE9BQU8sSUFBSSxPQUFPLENBQUMsRUFBRSxpQkFBaUIsRUFBRSx5QkFBeUIsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0FBQ3RGLENBQUM7QUFFRDs7Ozs7O0dBTUc7QUFDSCxTQUFTLHlCQUF5QixDQUFDLE1BQW1CO0lBQ3BELE9BQU87UUFDTCxJQUFJLHVCQUF1QjtZQUN6QixPQUFPLE1BQU0sQ0FBQyxPQUFPLENBQUM7UUFDeEIsQ0FBQztRQUNELHVCQUF1QixDQUFDLEVBQUU7WUFDeEIsSUFBSSxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQ25CLEVBQUUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQ2xCLE9BQU87WUFDVCxDQUFDO1lBQ0QsTUFBTSxDQUFDLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7UUFDNUUsQ0FBQztLQUNGLENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxTQUFTLG9CQUFvQixDQUFDLFVBQTJCLEVBQUUsS0FBd0I7SUFDakYsSUFBSSxLQUFLLENBQUMsdUJBQXVCLEVBQUUsQ0FBQztRQUNsQyxVQUFVLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDbkIsT0FBTztJQUNULENBQUM7SUFDRCxLQUFLLENBQUMsdUJBQXVCLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztBQUN0RSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBHZW5lcmljIERhdGFicmlja3MgU0RLIGdsdWUgKG5vIEFwcEtpdCk6IGFkYXB0IFdIQVRXRyBjYW5jZWxsYXRpb25cbiAqIChgQWJvcnRTaWduYWxgIC8gYEFib3J0Q29udHJvbGxlcmApIGludG8gdGhlIFNESydzIGBDb250ZXh0YCAvXG4gKiBgQ2FuY2VsbGF0aW9uVG9rZW5gIHNoYXBlcyBzbyBhIHNpbmdsZSBgQWJvcnRDb250cm9sbGVyYCBjYW4gZHJpdmUgZXZlcnlcbiAqIGluLWZsaWdodCBTREsgY2FsbCwgcGx1cyBEYXRhYnJpY2tzIHJ1bnRpbWUtZW52aXJvbm1lbnQgZGV0ZWN0aW9uLlxuICpcbiAqIFNlcnZlci1vbmx5OiBsZWFucyBvbiB0aGUgRGF0YWJyaWNrcyBTREsgYENvbnRleHRgLiBMaXZlcyBpbiBub2RlLWFwcGtpdCBzb1xuICogdGhlIGJyb3dzZXItc2FmZSBzaGFyZWQtY29yZSBzdGF5cyBTREstZnJlZS5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHR5cGUgeyBDYW5jZWxsYXRpb25Ub2tlbiB9IGZyb20gXCJAZGF0YWJyaWNrcy9zZGstZXhwZXJpbWVudGFsXCI7XG5pbXBvcnQgeyBDb250ZXh0IH0gZnJvbSBcIkBkYXRhYnJpY2tzL3Nkay1leHBlcmltZW50YWxcIjtcbmltcG9ydCB7IGFzeW5jLCBsb2cgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuXG5jb25zdCBsb2dnZXIgPSBsb2cubG9nZ2VyKFwiZGF0YWJyaWNrc1wiKTtcblxuLyoqIEhpZ2hlc3QgdmFsaWQgVENQIHBvcnQgbnVtYmVyLiAqL1xuZXhwb3J0IGNvbnN0IE1BWF9UQ1BfUE9SVCA9IDY1XzUzNTtcblxuLyoqXG4gKiBEZXRlY3QgdGhlIERhdGFicmlja3MgQXBwIHJ1bnRpbWUgZnJvbSBlbnZpcm9ubWVudCBzaGFwZTogcmVxdWlyZXMgYVxuICogbm9uLWVtcHR5IGBEQVRBQlJJQ0tTX0FQUF9OQU1FYCwgYSBgREFUQUJSSUNLU19IT1NUYCB0aGF0IHBhcnNlcyBhcyBhblxuICogYGh0dHBgL2BodHRwc2AgVVJMLCBhbmQgYSBgREFUQUJSSUNLU19BUFBfUE9SVGAgdGhhdCBpcyBhIHZhbGlkIFRDUCBwb3J0LlxuICogUmVhZHMgYHByb2Nlc3MuZW52YCB3aGVuIG5vIGBlbnZgIGlzIHBhc3NlZC5cbiAqXG4gKiBAZXhhbXBsZVxuICogaW1wb3J0IHsgZGF0YWJyaWNrcyB9IGZyb20gXCJAZGJ4LXRvb2xzL2FwcGtpdFwiO1xuICpcbiAqIC8vIFNraXAgYnVuZGxlIC8gYXBwLnlhbWwgZGlzY292ZXJ5IHdoZW4gdGhlIGFwcCBpcyBhbHJlYWR5IGRlcGxveWVkLlxuICogY29uc3QgbG9jYWwgPSAhZGF0YWJyaWNrcy5pc0FwcEVudigpO1xuICovXG5leHBvcnQgZnVuY3Rpb24gaXNBcHBFbnYoZW52OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCB1bmRlZmluZWQ+ID0gcHJvY2Vzcy5lbnYpOiBib29sZWFuIHtcbiAgY29uc3QgYXBwTmFtZSA9IGVudi5EQVRBQlJJQ0tTX0FQUF9OQU1FPy50cmltKCk7XG4gIGNvbnN0IGhvc3QgPSBlbnYuREFUQUJSSUNLU19IT1NUPy50cmltKCk7XG4gIGNvbnN0IHBvcnQgPSBlbnYuREFUQUJSSUNLU19BUFBfUE9SVD8udHJpbSgpO1xuXG4gIGlmICghYXBwTmFtZSB8fCAhaG9zdCB8fCAhcG9ydCkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIHRyeSB7XG4gICAgY29uc3QgdXJsID0gbmV3IFVSTChob3N0KTtcbiAgICBpZiAoIVtcImh0dHA6XCIsIFwiaHR0cHM6XCJdLmluY2x1ZGVzKHVybC5wcm90b2NvbCkpIHtcbiAgICAgIGxvZ2dlci5kZWJ1ZyhcImFwcCBlbnYgcmVqZWN0ZWQ6IGhvc3QgaXMgbm90IGFuIGh0dHAocykgVVJMXCIpO1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfSBjYXRjaCB7XG4gICAgbG9nZ2VyLmRlYnVnKFwiYXBwIGVudiByZWplY3RlZDogaG9zdCBpcyBub3QgYSBVUkxcIik7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgY29uc3QgcG9ydE51bWJlciA9IE51bWJlcihwb3J0KTtcbiAgaWYgKCFOdW1iZXIuaXNJbnRlZ2VyKHBvcnROdW1iZXIpIHx8IHBvcnROdW1iZXIgPCAxIHx8IHBvcnROdW1iZXIgPiBNQVhfVENQX1BPUlQpIHtcbiAgICBsb2dnZXIuZGVidWcoXCJhcHAgZW52IHJlamVjdGVkOiBEQVRBQlJJQ0tTX0FQUF9QT1JUIGlzIG5vdCBhIFRDUCBwb3J0XCIpO1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIHJldHVybiB0cnVlO1xufVxuXG4vKiogRWl0aGVyIGFuIFNESyBgQ29udGV4dGAgb3IgYSBXSEFUV0cgYEFib3J0U2lnbmFsYC4gKi9cbmV4cG9ydCB0eXBlIENvbnRleHRMaWtlID0gQ29udGV4dCB8IEFib3J0U2lnbmFsO1xuXG4vKipcbiAqIFdyYXAgYSBgQ29udGV4dGAgKHJldHVybmVkIGFzLWlzKSBvciBgQWJvcnRTaWduYWxgIChhZGFwdGVkKSBhcyBhbiBTREsgYENvbnRleHRgLlxuICpcbiAqIEBleGFtcGxlXG4gKiBpbXBvcnQgeyBkYXRhYnJpY2tzIH0gZnJvbSBcIkBkYngtdG9vbHMvYXBwa2l0XCI7XG4gKiBpbXBvcnQgeyBnZXRXb3Jrc3BhY2VDbGllbnQgfSBmcm9tIFwiQGRhdGFicmlja3MvYXBwa2l0XCI7XG4gKlxuICogYXdhaXQgZ2V0V29ya3NwYWNlQ2xpZW50KHt9KS5hcGlDbGllbnQucmVxdWVzdChcbiAqICAgeyBwYXRoOiBcIi9hcGkvMi4wL3NlcnZpbmctZW5kcG9pbnRzXCIsIG1ldGhvZDogXCJHRVRcIiwgaGVhZGVyczogbmV3IEhlYWRlcnMoKSwgcmF3OiBmYWxzZSB9LFxuICogICBkYXRhYnJpY2tzLnRvQ29udGV4dChyZXF1ZXN0LnNpZ25hbCksXG4gKiApO1xuICovXG5leHBvcnQgZnVuY3Rpb24gdG9Db250ZXh0KGlucHV0OiBDb250ZXh0TGlrZSk6IENvbnRleHQ7XG4vKipcbiAqIERlcml2ZSBhbiBTREsgYENvbnRleHRgIGZyb20gYGNvbnRyb2xsZXIuc2lnbmFsYCwgb3B0aW9uYWxseSB0eWluZyBgaW5wdXRgXG4gKiBpbnRvIHRoZSBjb250cm9sbGVyIHNvIHRoZSBjb250cm9sbGVyIGJlY29tZXMgdGhlIHNpbmdsZSBjYW5jZWxsYXRpb25cbiAqIHNvdXJjZSBmb3IgZG93bnN0cmVhbSBTREsgY2FsbHM6XG4gKlxuICogICAtIGBBYm9ydFNpZ25hbGA6IGFib3J0aW5nIGl0IHByb3BhZ2F0ZXMgaW50byBgY29udHJvbGxlcmAgKGFuZCBmcm9tIHRoZXJlXG4gKiAgICAgaW50byBldmVyeSBTREsgY2FsbCB5b3UgcGFzcyB0aGUgcmV0dXJuZWQgY29udGV4dCB0bykuXG4gKiAgIC0gYENvbnRleHRgOiBpdHMgYGNhbmNlbGxhdGlvblRva2VuYCBpcyB0aWVkIGludG8gYGNvbnRyb2xsZXJgLCBhbmQgaXRzXG4gKiAgICAgb3RoZXIgZmllbGRzIChgbG9nZ2VyYCwgYG9wTmFtZWAsIGByb290Q2xhc3NOYW1lYCwgYHJvb3RGbk5hbWVgLCBgb3BJZGApXG4gKiAgICAgYXJlIHByZXNlcnZlZCBpbiB0aGUgcmV0dXJuZWQgYENvbnRleHRgLiBUaGUgcmV0dXJuZWQgY29udGV4dCdzXG4gKiAgICAgYGNhbmNlbGxhdGlvblRva2VuYCBpcyByZXBsYWNlZCB3aXRoIG9uZSBiYWNrZWQgYnkgYGNvbnRyb2xsZXIuc2lnbmFsYC5cbiAqXG4gKiBUaGUgdGllIGlzIG9uZS13YXkgKHBhcmVudCAtPiBjaGlsZCk6IGFib3J0aW5nIGBjb250cm9sbGVyYCBkaXJlY3RseSBkb2VzXG4gKiBOT1QgY2FuY2VsIGBpbnB1dGAuIFNvIGEgcmVxdWVzdC1sZXZlbCBjYW5jZWwgKHlvdXIgbG9vcCdzIGB0cnkvZmluYWxseSB7XG4gKiBjb250cm9sbGVyLmFib3J0KCkgfWApIHdvbid0IHRlYXIgZG93biBhIGNhbGxlci1zdXBwbGllZCBBYm9ydFNpZ25hbCBpdFxuICogZGlkbid0IG93bi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRvQ29udGV4dChjb250cm9sbGVyOiBBYm9ydENvbnRyb2xsZXIsIGlucHV0PzogQ29udGV4dExpa2UpOiBDb250ZXh0O1xuZXhwb3J0IGZ1bmN0aW9uIHRvQ29udGV4dChzb3VyY2U6IEFib3J0Q29udHJvbGxlciB8IENvbnRleHRMaWtlLCBpbnB1dD86IENvbnRleHRMaWtlKTogQ29udGV4dCB7XG4gIGlmICghKHNvdXJjZSBpbnN0YW5jZW9mIEFib3J0Q29udHJvbGxlcikpIHtcbiAgICBpZiAoc291cmNlIGluc3RhbmNlb2YgQ29udGV4dCkgcmV0dXJuIHNvdXJjZTtcbiAgICByZXR1cm4gbmV3IENvbnRleHQoeyBjYW5jZWxsYXRpb25Ub2tlbjogc2lnbmFsVG9DYW5jZWxsYXRpb25Ub2tlbihzb3VyY2UpIH0pO1xuICB9XG4gIGlmIChpbnB1dCBpbnN0YW5jZW9mIEFib3J0U2lnbmFsKSB7XG4gICAgYXN5bmMudGllQWJvcnRTaWduYWwoc291cmNlLCBpbnB1dCk7XG4gIH0gZWxzZSBpZiAoaW5wdXQgaW5zdGFuY2VvZiBDb250ZXh0KSB7XG4gICAgY29uc3QgdG9rZW4gPSBpbnB1dC5jYW5jZWxsYXRpb25Ub2tlbjtcbiAgICBpZiAodG9rZW4pIHRpZUNhbmNlbGxhdGlvblRva2VuKHNvdXJjZSwgdG9rZW4pO1xuICAgIGNvbnN0IG1lcmdlZCA9IGlucHV0LmNvcHkoKTtcbiAgICBtZXJnZWQuc2V0SXRlbXMoeyBjYW5jZWxsYXRpb25Ub2tlbjogc2lnbmFsVG9DYW5jZWxsYXRpb25Ub2tlbihzb3VyY2Uuc2lnbmFsKSB9KTtcbiAgICByZXR1cm4gbWVyZ2VkO1xuICB9XG4gIHJldHVybiBuZXcgQ29udGV4dCh7IGNhbmNlbGxhdGlvblRva2VuOiBzaWduYWxUb0NhbmNlbGxhdGlvblRva2VuKHNvdXJjZS5zaWduYWwpIH0pO1xufVxuXG4vKipcbiAqIEFkYXB0IGEgV0hBVFdHIGBBYm9ydFNpZ25hbGAgdG8gdGhlIERhdGFicmlja3MgU0RLJ3MgYENhbmNlbGxhdGlvblRva2VuYFxuICogaW50ZXJmYWNlLiBUaGUgU0RLJ3MgYGFwaS1jbGllbnQudHNgIGludGVybmFsbHkgY3JlYXRlcyBhbiBgQWJvcnRDb250cm9sbGVyYFxuICogYW5kIHdpcmVzIGBjYW5jZWxsYXRpb25Ub2tlbi5vbkNhbmNlbGxhdGlvblJlcXVlc3RlZGAgdG8gaXQsIHNvIHRoaXMgYWRhcHRlclxuICogaXMgdGhlIG9uZS1saW5lIGJyaWRnZSBmcm9tIFwicGxhdGZvcm0tc3RhbmRhcmQgY2FuY2VsbGF0aW9uXCIgdG8gXCJ0aGUgU0RLXG4gKiBhYm9ydHMgdGhlIGZldGNoIG9uIHlvdXIgYmVoYWxmXCIuXG4gKi9cbmZ1bmN0aW9uIHNpZ25hbFRvQ2FuY2VsbGF0aW9uVG9rZW4oc2lnbmFsOiBBYm9ydFNpZ25hbCk6IENhbmNlbGxhdGlvblRva2VuIHtcbiAgcmV0dXJuIHtcbiAgICBnZXQgaXNDYW5jZWxsYXRpb25SZXF1ZXN0ZWQoKSB7XG4gICAgICByZXR1cm4gc2lnbmFsLmFib3J0ZWQ7XG4gICAgfSxcbiAgICBvbkNhbmNlbGxhdGlvblJlcXVlc3RlZChjYikge1xuICAgICAgaWYgKHNpZ25hbC5hYm9ydGVkKSB7XG4gICAgICAgIGNiKHNpZ25hbC5yZWFzb24pO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBzaWduYWwuYWRkRXZlbnRMaXN0ZW5lcihcImFib3J0XCIsICgpID0+IGNiKHNpZ25hbC5yZWFzb24pLCB7IG9uY2U6IHRydWUgfSk7XG4gICAgfSxcbiAgfTtcbn1cblxuLyoqXG4gKiBUaWUgdGhlIFNESydzIGBDYW5jZWxsYXRpb25Ub2tlbmAgaW50ZXJmYWNlIGJhY2sgaW50byBhbiBgQWJvcnRDb250cm9sbGVyYC5cbiAqIE1pcnJvcnMgYGFzeW5jLnRpZUFib3J0U2lnbmFsYCBidXQgZm9yIHRoZSBTREsncyBjYW5jZWxsYXRpb24gc2hhcGUsIHVzZWRcbiAqIHdoZW4gYSBjYWxsZXIgaGFuZHMgdXMgYSBwcmUtYnVpbHQgYENvbnRleHRgIHdob3NlIHRva2VuIHdlIHdhbnQgdG8gZm9sZCBpbnRvXG4gKiBvdXIgb3duIGNvbnRyb2xsZXIuXG4gKi9cbmZ1bmN0aW9uIHRpZUNhbmNlbGxhdGlvblRva2VuKGNvbnRyb2xsZXI6IEFib3J0Q29udHJvbGxlciwgdG9rZW46IENhbmNlbGxhdGlvblRva2VuKTogdm9pZCB7XG4gIGlmICh0b2tlbi5pc0NhbmNlbGxhdGlvblJlcXVlc3RlZCkge1xuICAgIGNvbnRyb2xsZXIuYWJvcnQoKTtcbiAgICByZXR1cm47XG4gIH1cbiAgdG9rZW4ub25DYW5jZWxsYXRpb25SZXF1ZXN0ZWQoKHJlYXNvbikgPT4gY29udHJvbGxlci5hYm9ydChyZWFzb24pKTtcbn1cbiJdfQ==
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Lakebase Postgres connection resolver.
3
+ *
4
+ * Reads the same env vars the `lakebase` plugin consumes (`PGHOST`,
5
+ * `PGDATABASE`, `PGPORT`, `PGSSLMODE`, `LAKEBASE_ENDPOINT`) and fills in
6
+ * whichever pieces are missing using the Lakebase Autoscaling REST API
7
+ * under `/api/2.0/postgres/` via the Databricks workspace client.
8
+ *
9
+ * `LAKEBASE_ENDPOINT` (and `config.endpoint`) accept anything
10
+ * {@link parseAddress} understands - canonical resource paths, Postgres
11
+ * URIs, bare hostnames, or bare project ids. The resolver layers
12
+ * whatever pieces fall out of parsing under explicit config / env
13
+ * values, then fills the remaining gaps via the API:
14
+ *
15
+ * 1. Reverse-lookup: when a host is known but no resource path is,
16
+ * scan projects -> branches -> endpoints for a matching
17
+ * `status.hosts.host` and recover the owning project/branch/endpoint.
18
+ * 2. Pick: when a project is known but child resources aren't, prefer
19
+ * the server-side default (`status.default`, `ENDPOINT_TYPE_READ_WRITE`,
20
+ * `databricks_postgres`) and fall back to "the only one" when a
21
+ * listing returns a single result.
22
+ * 3. Auto-create: when no projects exist at all, create one whose
23
+ * id defaults to `project.name()` slugified (override
24
+ * with `config.autoCreate: "my-id"` or disable with
25
+ * `config.autoCreate: false`). The create call is idempotent - an
26
+ * `ALREADY_EXISTS` response from a concurrent boot is treated as
27
+ * success. Then poll the default endpoint until it reports
28
+ * `current_state` `READY` or `IDLE`.
29
+ *
30
+ * {@link applyLakebaseToEnv} writes the resolved values back to
31
+ * `process.env` so the downstream `lakebase` plugin picks them up.
32
+ *
33
+ * @see https://docs.databricks.com/api/workspace/postgres
34
+ *
35
+ * @module
36
+ */
37
+ import { type LakebaseConnectionInputs, type SslMode } from "./pgaddress.js";
38
+ /**
39
+ * User-supplied Lakebase inputs (config or env) before any API resolution.
40
+ * Extends {@link LakebaseConnectionInputs} with resolver-only options.
41
+ * {@link resolveLakebaseConnection} fills gaps from the Lakebase API when
42
+ * it has enough context (typically a `project`).
43
+ */
44
+ export interface LakebaseResolverInputs extends LakebaseConnectionInputs {
45
+ /**
46
+ * What to do when no project exists in the workspace at all.
47
+ * - `undefined` (default): derive a project id from
48
+ * {@link project.name} (the host repo's `package.json`
49
+ * name) slugified to Lakebase id constraints, then create it.
50
+ * - `string`: create a new project with this exact id.
51
+ * - `false`: skip creation and throw with a clear error message.
52
+ */
53
+ autoCreate?: string | false;
54
+ }
55
+ /** Fully-resolved Lakebase Postgres connection. */
56
+ export interface LakebaseConnection extends LakebaseConnectionInputs {
57
+ port: number;
58
+ sslMode: SslMode;
59
+ }
60
+ /**
61
+ * Validate a `PGPORT`-shaped value. Returns `undefined` when unset, and throws
62
+ * a {@link ValidationError} naming `PGPORT` for anything that is not a TCP
63
+ * port, so a typo cannot reach the connection record as `NaN`.
64
+ */
65
+ export declare function parsePort(value: string | number | undefined): number | undefined;
66
+ /**
67
+ * Validate a `PGSSLMODE`-shaped value. Returns `undefined` when unset, and
68
+ * throws a {@link ValidationError} naming `PGSSLMODE` for an unsupported mode
69
+ * rather than handing `pg` a value it will reject at connect time.
70
+ */
71
+ export declare function parseSslMode(value: string | undefined): SslMode | undefined;
72
+ /**
73
+ * Delay before the next poll attempt: exponential backoff capped at
74
+ * {@link POLL_MAX_DELAY_MS}, plus jitter so several apps booting against the
75
+ * same workspace do not retry in lockstep.
76
+ */
77
+ export declare function nextPollDelay(attempt: number, baseMs: number): number;
78
+ /**
79
+ * Wait out {@link nextPollDelay} before the next attempt. Rejects with the
80
+ * signal's reason when the caller cancels mid-wait, so a poll loop unwinds
81
+ * instead of finishing its backoff first.
82
+ */
83
+ export declare function pollDelay(attempt: number, baseMs: number, signal?: AbortSignal): Promise<void>;
84
+ /**
85
+ * Pull resolver inputs from `process.env`, parse the address blob, and
86
+ * layer explicit config on top with this precedence:
87
+ *
88
+ * `config.<field>` > `config.resolveConfigValue` (`env`, then bundle
89
+ * validate JSON) > whatever {@link parseAddress} recovered from the
90
+ * `endpoint` / `LAKEBASE_ENDPOINT` blob.
91
+ *
92
+ * Set `config.endpoint` (or `LAKEBASE_ENDPOINT`) to any input
93
+ * {@link parseAddress} understands: canonical resource paths, Postgres
94
+ * URIs, bare hostnames, or bare project ids.
95
+ */
96
+ export declare function readLakebaseInputs(config?: LakebaseResolverInputs): Promise<LakebaseResolverInputs>;
97
+ /**
98
+ * Resolve a fully-populated Postgres connection record from config + env.
99
+ *
100
+ * Returns immediately without network traffic when env already supplies
101
+ * `endpoint`, `host`, and `database`. Otherwise issues REST calls and
102
+ * may auto-create a project (see module docstring).
103
+ *
104
+ * `signal` cancels every REST call and inter-poll sleep.
105
+ *
106
+ * @example
107
+ * import { lakebaseResolver } from "@dbx-tools/appkit";
108
+ *
109
+ * const resolved = await lakebaseResolver.resolveLakebaseConnection(
110
+ * { autoCreate: false },
111
+ * AbortSignal.timeout(60_000),
112
+ * );
113
+ * lakebaseResolver.applyLakebaseToEnv(resolved);
114
+ */
115
+ export declare function resolveLakebaseConnection(config?: LakebaseResolverInputs, signal?: AbortSignal): Promise<LakebaseConnection>;
116
+ /**
117
+ * Write resolved values back to `process.env` so the `lakebase` plugin
118
+ * (which reads env directly) picks them up during its own `setup()`.
119
+ * Existing env values are preserved; only missing keys are filled in,
120
+ * which keeps explicit overrides authoritative.
121
+ */
122
+ export declare function applyLakebaseToEnv(resolved: LakebaseConnection): void;