@dbx-tools/appkit 0.9.154 → 0.9.158
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/index.ts +18 -13
- package/lib/index.d.ts +18 -13
- package/lib/index.js +19 -12
- package/lib/src/appkit.js +6 -6
- package/lib/src/brand-context.js +3 -3
- package/lib/src/cache-storage.d.ts +1 -1
- package/lib/src/cache-storage.js +6 -6
- package/lib/src/databricks.js +3 -3
- package/lib/src/files-cache.js +9 -9
- package/lib/src/identity.d.ts +0 -14
- package/lib/src/identity.js +9 -23
- package/lib/src/interceptor.js +3 -3
- package/lib/src/lakebase-resolver.d.ts +1 -1
- package/lib/src/lakebase-resolver.js +16 -17
- package/lib/src/migration.js +6 -6
- package/lib/src/openapi-tool.js +5 -5
- package/lib/src/plugin-execution.d.ts +2 -2
- package/lib/src/plugin-execution.js +4 -4
- package/lib/src/provision.d.ts +2 -2
- package/lib/src/provision.js +4 -4
- package/lib/src/request-tags.js +2 -2
- package/lib/src/telemetry.js +4 -4
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -178
- package/src/appkit.ts +5 -5
- package/src/brand-context.ts +2 -2
- package/src/cache-storage.ts +5 -5
- package/src/databricks.ts +2 -2
- package/src/files-cache.ts +8 -8
- package/src/identity.ts +16 -25
- package/src/interceptor.ts +2 -2
- package/src/lakebase-resolver.ts +27 -34
- package/src/migration.ts +11 -5
- package/src/openapi-tool.ts +4 -4
- package/src/plugin-execution.ts +4 -4
- package/src/provision.ts +4 -4
- package/src/request-tags.ts +1 -1
- package/src/telemetry.ts +3 -3
- package/lib/src/bundle.d.ts +0 -33
- package/lib/src/bundle.js +0 -38
- package/lib/src/pgaddress.d.ts +0 -20
- package/lib/src/pgaddress.js +0 -21
- package/src/bundle.ts +0 -57
- package/src/pgaddress.ts +0 -42
package/package.json
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@databricks/appkit": "0.81.0",
|
|
23
|
-
"@dbx-tools/projen": "^0.9.
|
|
23
|
+
"@dbx-tools/projen": "^0.9.158",
|
|
24
24
|
"@types/json-schema": "^7",
|
|
25
25
|
"@types/node": "^24.6.0",
|
|
26
26
|
"typescript": "^5.9.3",
|
|
@@ -31,13 +31,13 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@databricks/sdk-experimental": "^0.17.0",
|
|
34
|
-
"@dbx-tools/auth": "^0.9.
|
|
35
|
-
"@dbx-tools/cache": "^0.9.
|
|
36
|
-
"@dbx-tools/core": "^0.9.
|
|
37
|
-
"@dbx-tools/lakebase": "^0.9.
|
|
38
|
-
"@dbx-tools/postgres": "^0.9.
|
|
39
|
-
"@dbx-tools/shared-core": "^0.9.
|
|
40
|
-
"@dbx-tools/shared-fs": "^0.9.
|
|
34
|
+
"@dbx-tools/auth": "^0.9.158",
|
|
35
|
+
"@dbx-tools/cache": "^0.9.158",
|
|
36
|
+
"@dbx-tools/core": "^0.9.158",
|
|
37
|
+
"@dbx-tools/lakebase": "^0.9.158",
|
|
38
|
+
"@dbx-tools/postgres": "^0.9.158",
|
|
39
|
+
"@dbx-tools/shared-core": "^0.9.158",
|
|
40
|
+
"@dbx-tools/shared-fs": "^0.9.158",
|
|
41
41
|
"@opentelemetry/api": "1.9.1",
|
|
42
42
|
"@opentelemetry/sdk-trace-base": "2.8.0",
|
|
43
43
|
"zod": "4.3.6"
|
|
@@ -53,94 +53,10 @@
|
|
|
53
53
|
"types": "./lib/index.d.ts",
|
|
54
54
|
"default": "./lib/index.js"
|
|
55
55
|
},
|
|
56
|
-
"./appkit": {
|
|
57
|
-
"types": "./lib/src/appkit.d.ts",
|
|
58
|
-
"default": "./lib/src/appkit.js"
|
|
59
|
-
},
|
|
60
|
-
"./brand-context": {
|
|
61
|
-
"types": "./lib/src/brand-context.d.ts",
|
|
62
|
-
"default": "./lib/src/brand-context.js"
|
|
63
|
-
},
|
|
64
|
-
"./bundle": {
|
|
65
|
-
"types": "./lib/src/bundle.d.ts",
|
|
66
|
-
"default": "./lib/src/bundle.js"
|
|
67
|
-
},
|
|
68
|
-
"./cache-storage": {
|
|
69
|
-
"types": "./lib/src/cache-storage.d.ts",
|
|
70
|
-
"default": "./lib/src/cache-storage.js"
|
|
71
|
-
},
|
|
72
|
-
"./databricks": {
|
|
73
|
-
"types": "./lib/src/databricks.d.ts",
|
|
74
|
-
"default": "./lib/src/databricks.js"
|
|
75
|
-
},
|
|
76
|
-
"./files-cache": {
|
|
77
|
-
"types": "./lib/src/files-cache.d.ts",
|
|
78
|
-
"default": "./lib/src/files-cache.js"
|
|
79
|
-
},
|
|
80
|
-
"./identity": {
|
|
81
|
-
"types": "./lib/src/identity.d.ts",
|
|
82
|
-
"default": "./lib/src/identity.js"
|
|
83
|
-
},
|
|
84
|
-
"./interceptor": {
|
|
85
|
-
"types": "./lib/src/interceptor.d.ts",
|
|
86
|
-
"default": "./lib/src/interceptor.js"
|
|
87
|
-
},
|
|
88
|
-
"./lakebase-resolver": {
|
|
89
|
-
"types": "./lib/src/lakebase-resolver.d.ts",
|
|
90
|
-
"default": "./lib/src/lakebase-resolver.js"
|
|
91
|
-
},
|
|
92
|
-
"./migration": {
|
|
93
|
-
"types": "./lib/src/migration.d.ts",
|
|
94
|
-
"default": "./lib/src/migration.js"
|
|
95
|
-
},
|
|
96
|
-
"./openapi-tool": {
|
|
97
|
-
"types": "./lib/src/openapi-tool.d.ts",
|
|
98
|
-
"default": "./lib/src/openapi-tool.js"
|
|
99
|
-
},
|
|
100
|
-
"./pgaddress": {
|
|
101
|
-
"types": "./lib/src/pgaddress.d.ts",
|
|
102
|
-
"default": "./lib/src/pgaddress.js"
|
|
103
|
-
},
|
|
104
|
-
"./plugin-execution": {
|
|
105
|
-
"types": "./lib/src/plugin-execution.d.ts",
|
|
106
|
-
"default": "./lib/src/plugin-execution.js"
|
|
107
|
-
},
|
|
108
|
-
"./plugin-registry": {
|
|
109
|
-
"types": "./lib/src/plugin-registry.d.ts",
|
|
110
|
-
"default": "./lib/src/plugin-registry.js"
|
|
111
|
-
},
|
|
112
|
-
"./provision": {
|
|
113
|
-
"types": "./lib/src/provision.d.ts",
|
|
114
|
-
"default": "./lib/src/provision.js"
|
|
115
|
-
},
|
|
116
|
-
"./request-tags": {
|
|
117
|
-
"types": "./lib/src/request-tags.d.ts",
|
|
118
|
-
"default": "./lib/src/request-tags.js"
|
|
119
|
-
},
|
|
120
|
-
"./telemetry": {
|
|
121
|
-
"types": "./lib/src/telemetry.d.ts",
|
|
122
|
-
"default": "./lib/src/telemetry.js"
|
|
123
|
-
},
|
|
124
|
-
"./tool-operations": {
|
|
125
|
-
"types": "./lib/src/tool-operations.d.ts",
|
|
126
|
-
"default": "./lib/src/tool-operations.js"
|
|
127
|
-
},
|
|
128
|
-
"./tool-provider": {
|
|
129
|
-
"types": "./lib/src/tool-provider.d.ts",
|
|
130
|
-
"default": "./lib/src/tool-provider.js"
|
|
131
|
-
},
|
|
132
|
-
"./toolkit-entries": {
|
|
133
|
-
"types": "./lib/src/toolkit-entries.d.ts",
|
|
134
|
-
"default": "./lib/src/toolkit-entries.js"
|
|
135
|
-
},
|
|
136
|
-
"./*": {
|
|
137
|
-
"types": "./lib/src/*/index.d.ts",
|
|
138
|
-
"default": "./lib/src/*/index.js"
|
|
139
|
-
},
|
|
140
56
|
"./package.json": "./package.json"
|
|
141
57
|
}
|
|
142
58
|
},
|
|
143
|
-
"version": "0.9.
|
|
59
|
+
"version": "0.9.158",
|
|
144
60
|
"types": "./lib/index.d.ts",
|
|
145
61
|
"dbxToolsConfig": {
|
|
146
62
|
"tags": [
|
|
@@ -153,94 +69,10 @@
|
|
|
153
69
|
"types": "./lib/index.d.ts",
|
|
154
70
|
"default": "./lib/index.js"
|
|
155
71
|
},
|
|
156
|
-
"./appkit": {
|
|
157
|
-
"types": "./lib/src/appkit.d.ts",
|
|
158
|
-
"default": "./lib/src/appkit.js"
|
|
159
|
-
},
|
|
160
|
-
"./brand-context": {
|
|
161
|
-
"types": "./lib/src/brand-context.d.ts",
|
|
162
|
-
"default": "./lib/src/brand-context.js"
|
|
163
|
-
},
|
|
164
|
-
"./bundle": {
|
|
165
|
-
"types": "./lib/src/bundle.d.ts",
|
|
166
|
-
"default": "./lib/src/bundle.js"
|
|
167
|
-
},
|
|
168
|
-
"./cache-storage": {
|
|
169
|
-
"types": "./lib/src/cache-storage.d.ts",
|
|
170
|
-
"default": "./lib/src/cache-storage.js"
|
|
171
|
-
},
|
|
172
|
-
"./databricks": {
|
|
173
|
-
"types": "./lib/src/databricks.d.ts",
|
|
174
|
-
"default": "./lib/src/databricks.js"
|
|
175
|
-
},
|
|
176
|
-
"./files-cache": {
|
|
177
|
-
"types": "./lib/src/files-cache.d.ts",
|
|
178
|
-
"default": "./lib/src/files-cache.js"
|
|
179
|
-
},
|
|
180
|
-
"./identity": {
|
|
181
|
-
"types": "./lib/src/identity.d.ts",
|
|
182
|
-
"default": "./lib/src/identity.js"
|
|
183
|
-
},
|
|
184
|
-
"./interceptor": {
|
|
185
|
-
"types": "./lib/src/interceptor.d.ts",
|
|
186
|
-
"default": "./lib/src/interceptor.js"
|
|
187
|
-
},
|
|
188
|
-
"./lakebase-resolver": {
|
|
189
|
-
"types": "./lib/src/lakebase-resolver.d.ts",
|
|
190
|
-
"default": "./lib/src/lakebase-resolver.js"
|
|
191
|
-
},
|
|
192
|
-
"./migration": {
|
|
193
|
-
"types": "./lib/src/migration.d.ts",
|
|
194
|
-
"default": "./lib/src/migration.js"
|
|
195
|
-
},
|
|
196
|
-
"./openapi-tool": {
|
|
197
|
-
"types": "./lib/src/openapi-tool.d.ts",
|
|
198
|
-
"default": "./lib/src/openapi-tool.js"
|
|
199
|
-
},
|
|
200
|
-
"./pgaddress": {
|
|
201
|
-
"types": "./lib/src/pgaddress.d.ts",
|
|
202
|
-
"default": "./lib/src/pgaddress.js"
|
|
203
|
-
},
|
|
204
|
-
"./plugin-execution": {
|
|
205
|
-
"types": "./lib/src/plugin-execution.d.ts",
|
|
206
|
-
"default": "./lib/src/plugin-execution.js"
|
|
207
|
-
},
|
|
208
|
-
"./plugin-registry": {
|
|
209
|
-
"types": "./lib/src/plugin-registry.d.ts",
|
|
210
|
-
"default": "./lib/src/plugin-registry.js"
|
|
211
|
-
},
|
|
212
|
-
"./provision": {
|
|
213
|
-
"types": "./lib/src/provision.d.ts",
|
|
214
|
-
"default": "./lib/src/provision.js"
|
|
215
|
-
},
|
|
216
|
-
"./request-tags": {
|
|
217
|
-
"types": "./lib/src/request-tags.d.ts",
|
|
218
|
-
"default": "./lib/src/request-tags.js"
|
|
219
|
-
},
|
|
220
|
-
"./telemetry": {
|
|
221
|
-
"types": "./lib/src/telemetry.d.ts",
|
|
222
|
-
"default": "./lib/src/telemetry.js"
|
|
223
|
-
},
|
|
224
|
-
"./tool-operations": {
|
|
225
|
-
"types": "./lib/src/tool-operations.d.ts",
|
|
226
|
-
"default": "./lib/src/tool-operations.js"
|
|
227
|
-
},
|
|
228
|
-
"./tool-provider": {
|
|
229
|
-
"types": "./lib/src/tool-provider.d.ts",
|
|
230
|
-
"default": "./lib/src/tool-provider.js"
|
|
231
|
-
},
|
|
232
|
-
"./toolkit-entries": {
|
|
233
|
-
"types": "./lib/src/toolkit-entries.d.ts",
|
|
234
|
-
"default": "./lib/src/toolkit-entries.js"
|
|
235
|
-
},
|
|
236
|
-
"./*": {
|
|
237
|
-
"types": "./lib/src/*/index.d.ts",
|
|
238
|
-
"default": "./lib/src/*/index.js"
|
|
239
|
-
},
|
|
240
72
|
"./package.json": "./package.json"
|
|
241
73
|
},
|
|
242
74
|
"files": [
|
|
243
|
-
"index
|
|
75
|
+
"index*.ts",
|
|
244
76
|
"src",
|
|
245
77
|
"lib"
|
|
246
78
|
],
|
package/src/appkit.ts
CHANGED
|
@@ -35,8 +35,8 @@ import {
|
|
|
35
35
|
// AppKit's root barrel re-exports `PluginData` but not `PluginMap`; the package
|
|
36
36
|
// publishes this subpath for exactly that type.
|
|
37
37
|
import type { PluginMap } from "@databricks/appkit/dist/shared/src/plugin";
|
|
38
|
-
import {
|
|
39
|
-
import {
|
|
38
|
+
import { resolveProfile } from "@dbx-tools/auth";
|
|
39
|
+
import { log, tieAbortSignal } from "@dbx-tools/shared-core";
|
|
40
40
|
|
|
41
41
|
import { resolveAutoConfigurePolicy } from "./_auto-configure.ts";
|
|
42
42
|
import { loadBrandContext } from "./brand-context.ts";
|
|
@@ -167,8 +167,8 @@ export async function autoConfigure<T extends AppKitPlugins>(
|
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
const controller = new AbortController();
|
|
170
|
-
|
|
171
|
-
|
|
170
|
+
tieAbortSignal(controller, signal);
|
|
171
|
+
tieAbortSignal(controller, AbortSignal.timeout(AUTO_CONFIGURE_TIMEOUT_MS));
|
|
172
172
|
|
|
173
173
|
logger.debug("autoConfigure: resolve lakebase", {
|
|
174
174
|
provision: policy.provision,
|
|
@@ -229,7 +229,7 @@ async function autoConfigureLakebase(
|
|
|
229
229
|
|
|
230
230
|
function applyDefaultProfile(): string | undefined {
|
|
231
231
|
const configured = process.env.DATABRICKS_CONFIG_PROFILE?.trim();
|
|
232
|
-
const resolved =
|
|
232
|
+
const resolved = resolveProfile(configured ? { profile: configured } : {});
|
|
233
233
|
if (!resolved) {
|
|
234
234
|
delete process.env.DATABRICKS_CONFIG_PROFILE;
|
|
235
235
|
return undefined;
|
package/src/brand-context.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { brandFiles } from "@dbx-tools/core";
|
|
2
|
-
import {
|
|
2
|
+
import { type BrandContext, defaultBrandContext } from "@dbx-tools/shared-core";
|
|
3
3
|
|
|
4
|
-
let activeBrandContext: BrandContext =
|
|
4
|
+
let activeBrandContext: BrandContext = defaultBrandContext;
|
|
5
5
|
|
|
6
6
|
/** Load and activate the brand context found from the supplied directory. */
|
|
7
7
|
export async function loadBrandContext(cwd: string = process.cwd()): Promise<BrandContext> {
|
package/src/cache-storage.ts
CHANGED
|
@@ -24,9 +24,9 @@ import {
|
|
|
24
24
|
flushCache,
|
|
25
25
|
projectCache,
|
|
26
26
|
type CacheOptions,
|
|
27
|
-
} from "@dbx-tools/cache
|
|
27
|
+
} from "@dbx-tools/cache";
|
|
28
28
|
import { postgresConnectionOptions } from "@dbx-tools/postgres";
|
|
29
|
-
import {
|
|
29
|
+
import { log, toError, id } from "@dbx-tools/shared-core";
|
|
30
30
|
import { handleOwnershipMigrationError } from "./migration.ts";
|
|
31
31
|
|
|
32
32
|
const logger = log.logger("cache-storage");
|
|
@@ -217,7 +217,7 @@ export function loadPersistentStorage(): PersistentStorageConstructor | undefine
|
|
|
217
217
|
return loaded;
|
|
218
218
|
} catch (err) {
|
|
219
219
|
logger.debug("soft persistent cache skipped (PersistentStorage unavailable)", {
|
|
220
|
-
error:
|
|
220
|
+
error: toError(err),
|
|
221
221
|
});
|
|
222
222
|
persistentStorageCtor = undefined;
|
|
223
223
|
return undefined;
|
|
@@ -288,7 +288,7 @@ export function softenInitialize(
|
|
|
288
288
|
|
|
289
289
|
/** Verify the migrated cache table can serve the reads and writes AppKit needs. */
|
|
290
290
|
export async function probeStorage(storage: PersistentStorageBase): Promise<void> {
|
|
291
|
-
const key = `dbx-tools:cache-probe:${
|
|
291
|
+
const key = `dbx-tools:cache-probe:${id()}`;
|
|
292
292
|
try {
|
|
293
293
|
await storage.set(key, { value: key, expiry: Date.now() + 60_000 });
|
|
294
294
|
const result = await storage.get(key);
|
|
@@ -330,7 +330,7 @@ async function createPersistentStorage(
|
|
|
330
330
|
return storage;
|
|
331
331
|
} catch (err) {
|
|
332
332
|
logger.debug("soft persistent cache unavailable", {
|
|
333
|
-
error:
|
|
333
|
+
error: toError(err),
|
|
334
334
|
});
|
|
335
335
|
if (pool) {
|
|
336
336
|
await pool.end().catch(() => {});
|
package/src/databricks.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import type { CancellationToken } from "@databricks/sdk-experimental";
|
|
14
14
|
import { Context } from "@databricks/sdk-experimental";
|
|
15
|
-
import {
|
|
15
|
+
import { tieAbortSignal } from "@dbx-tools/shared-core";
|
|
16
16
|
|
|
17
17
|
/** Either an SDK `Context` or a WHATWG `AbortSignal`. */
|
|
18
18
|
export type ContextLike = Context | AbortSignal;
|
|
@@ -54,7 +54,7 @@ export function toContext(source: AbortController | ContextLike, input?: Context
|
|
|
54
54
|
return new Context({ cancellationToken: signalToCancellationToken(source) });
|
|
55
55
|
}
|
|
56
56
|
if (input instanceof AbortSignal) {
|
|
57
|
-
|
|
57
|
+
tieAbortSignal(source, input);
|
|
58
58
|
} else if (input instanceof Context) {
|
|
59
59
|
const token = input.cancellationToken;
|
|
60
60
|
if (token) tieCancellationToken(source, token);
|
package/src/files-cache.ts
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { Plugin, toPlugin, type BasePluginConfig, type PluginManifest } from "@databricks/appkit";
|
|
8
|
-
import { cacheKeys, closeCache, createCache, getOrSet } from "@dbx-tools/cache
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
8
|
+
import { cacheKeys, closeCache, createCache, getOrSet } from "@dbx-tools/cache";
|
|
9
|
+
import { log, toError, toStableKey } from "@dbx-tools/shared-core";
|
|
10
|
+
import { type CacheValue, type FileSystemCache, normalizeRoot } from "@dbx-tools/shared-fs";
|
|
11
11
|
|
|
12
12
|
const DEFAULT_TTL_MS = 60_000;
|
|
13
13
|
const DEFAULT_INVALIDATION_BATCH_MS = 25;
|
|
@@ -121,9 +121,9 @@ export class FilesCacheManager {
|
|
|
121
121
|
load: () => T | Promise<T>,
|
|
122
122
|
): Promise<T> {
|
|
123
123
|
const state = await this.resolveScopeState(input);
|
|
124
|
-
const paths = identity.paths.map((path) =>
|
|
124
|
+
const paths = identity.paths.map((path) => normalizeRoot(path));
|
|
125
125
|
if (paths.length === 0) throw new TypeError("Filesystem source paths must not be empty");
|
|
126
|
-
const sourceKey =
|
|
126
|
+
const sourceKey = toStableKey({ paths, key: identity.key });
|
|
127
127
|
let source = state.sources.get(sourceKey);
|
|
128
128
|
if (!source) {
|
|
129
129
|
source = Promise.resolve(load());
|
|
@@ -139,7 +139,7 @@ export class FilesCacheManager {
|
|
|
139
139
|
|
|
140
140
|
private async resolveScopeState(input: FilesCacheScope): Promise<ScopeState> {
|
|
141
141
|
const scope = resolveScope(input, this.config.ttlMs);
|
|
142
|
-
const scopeKey =
|
|
142
|
+
const scopeKey = toStableKey({
|
|
143
143
|
host: scope.host,
|
|
144
144
|
userKey: scope.userKey,
|
|
145
145
|
workspaceId: scope.workspaceId,
|
|
@@ -186,7 +186,7 @@ export class FilesCacheManager {
|
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
private group(scope: ResolvedFilesCacheScope): GroupState {
|
|
189
|
-
const key =
|
|
189
|
+
const key = toStableKey({
|
|
190
190
|
host: scope.host,
|
|
191
191
|
workspaceId: scope.workspaceId,
|
|
192
192
|
});
|
|
@@ -247,7 +247,7 @@ export class FilesCacheManager {
|
|
|
247
247
|
state.group.timer = undefined;
|
|
248
248
|
void this.flushInvalidations(state.group).catch((error) => {
|
|
249
249
|
logger.warn("filesystem cache invalidation batch failed", {
|
|
250
|
-
error:
|
|
250
|
+
error: toError(error),
|
|
251
251
|
});
|
|
252
252
|
});
|
|
253
253
|
}, this.config.invalidationBatchMs);
|
package/src/identity.ts
CHANGED
|
@@ -52,25 +52,16 @@
|
|
|
52
52
|
*/
|
|
53
53
|
|
|
54
54
|
import { ConfigurationError, Plugin } from "@databricks/appkit";
|
|
55
|
-
import {
|
|
56
|
-
import {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
* this wire contract exists once.
|
|
66
|
-
*/
|
|
67
|
-
export const ACCESS_TOKEN_HEADER = token.ACCESS_TOKEN_HEADER;
|
|
68
|
-
|
|
69
|
-
/** Header the Databricks Apps front door forwards the caller's user id on. */
|
|
70
|
-
export const USER_ID_HEADER = token.USER_ID_HEADER;
|
|
71
|
-
|
|
72
|
-
/** Header the Databricks Apps front door forwards the caller's email on. */
|
|
73
|
-
export const USER_EMAIL_HEADER = token.USER_EMAIL_HEADER;
|
|
55
|
+
import { string, ENV_ONLY } from "@dbx-tools/core";
|
|
56
|
+
import {
|
|
57
|
+
log,
|
|
58
|
+
toError,
|
|
59
|
+
isLevelEnabled,
|
|
60
|
+
trimToNull,
|
|
61
|
+
ACCESS_TOKEN_HEADER,
|
|
62
|
+
USER_ID_HEADER,
|
|
63
|
+
USER_EMAIL_HEADER,
|
|
64
|
+
} from "@dbx-tools/shared-core";
|
|
74
65
|
|
|
75
66
|
/** Identity a request's Databricks calls run as. See the module docs. */
|
|
76
67
|
export type IdentityMode = "user" | "service-principal" | "auto";
|
|
@@ -103,7 +94,7 @@ export function resolveIdentityMode(
|
|
|
103
94
|
envKeys: string | readonly string[],
|
|
104
95
|
field = "identity",
|
|
105
96
|
): IdentityMode {
|
|
106
|
-
const raw =
|
|
97
|
+
const raw = string(configured, envKeys, ENV_ONLY);
|
|
107
98
|
if (raw === undefined) return DEFAULT_IDENTITY_MODE;
|
|
108
99
|
const mode = raw.toLowerCase() as IdentityMode;
|
|
109
100
|
if (!IDENTITY_MODES.includes(mode)) {
|
|
@@ -123,17 +114,17 @@ export function resolveIdentityMode(
|
|
|
123
114
|
* the first Databricks call.
|
|
124
115
|
*/
|
|
125
116
|
export function requestAccessToken(req: HeaderBearing | undefined): string | undefined {
|
|
126
|
-
return
|
|
117
|
+
return trimToNull(req?.header(ACCESS_TOKEN_HEADER)) ?? undefined;
|
|
127
118
|
}
|
|
128
119
|
|
|
129
120
|
/** The forwarded user id on `req`, or `undefined`. */
|
|
130
121
|
export function requestUserId(req: HeaderBearing | undefined): string | undefined {
|
|
131
|
-
return
|
|
122
|
+
return trimToNull(req?.header(USER_ID_HEADER)) ?? undefined;
|
|
132
123
|
}
|
|
133
124
|
|
|
134
125
|
/** The forwarded user email on `req`, or `undefined`. */
|
|
135
126
|
export function requestUserEmail(req: HeaderBearing | undefined): string | undefined {
|
|
136
|
-
return
|
|
127
|
+
return trimToNull(req?.header(USER_EMAIL_HEADER)) ?? undefined;
|
|
137
128
|
}
|
|
138
129
|
|
|
139
130
|
/**
|
|
@@ -193,7 +184,7 @@ export function installAsUserDevelopmentPatch(): void {
|
|
|
193
184
|
);
|
|
194
185
|
};
|
|
195
186
|
} catch (error) {
|
|
196
|
-
logger.debug("asUser development patch skipped", { error:
|
|
187
|
+
logger.debug("asUser development patch skipped", { error: toError(error) });
|
|
197
188
|
}
|
|
198
189
|
}
|
|
199
190
|
|
|
@@ -212,7 +203,7 @@ function withAsUserSkipWarnSuppressed<T>(req: HeaderBearing, fn: () => T): T {
|
|
|
212
203
|
const warn = console.warn;
|
|
213
204
|
console.warn = (...args: unknown[]) => {
|
|
214
205
|
if (
|
|
215
|
-
!
|
|
206
|
+
!isLevelEnabled("debug") &&
|
|
216
207
|
args.some((value) => typeof value === "string" && value.includes(AS_USER_SKIP_WARN))
|
|
217
208
|
) {
|
|
218
209
|
return;
|
package/src/interceptor.ts
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
import { Plugin, toPlugin, type BasePluginConfig, type PluginManifest } from "@databricks/appkit";
|
|
23
|
-
import {
|
|
23
|
+
import { log, toError } from "@dbx-tools/shared-core";
|
|
24
24
|
import type { LakebaseConnection } from "./lakebase-resolver.ts";
|
|
25
25
|
|
|
26
26
|
const logger = log.logger("interceptor");
|
|
@@ -122,7 +122,7 @@ export function createInterceptorContext(env: ResolvedAppEnv): InterceptorRuntim
|
|
|
122
122
|
// never blocks its siblings.
|
|
123
123
|
logger.warn("lifecycle handler failed", {
|
|
124
124
|
event,
|
|
125
|
-
error:
|
|
125
|
+
error: toError(error),
|
|
126
126
|
});
|
|
127
127
|
}
|
|
128
128
|
}
|
package/src/lakebase-resolver.ts
CHANGED
|
@@ -43,18 +43,7 @@ import {
|
|
|
43
43
|
type LakebasePool,
|
|
44
44
|
ValidationError,
|
|
45
45
|
} from "@databricks/appkit";
|
|
46
|
-
import {
|
|
47
|
-
import {
|
|
48
|
-
asyncUtils,
|
|
49
|
-
errorUtils,
|
|
50
|
-
log,
|
|
51
|
-
object,
|
|
52
|
-
options as sharedOptions,
|
|
53
|
-
stringUtils,
|
|
54
|
-
} from "@dbx-tools/shared-core";
|
|
55
|
-
import { z } from "zod";
|
|
56
|
-
|
|
57
|
-
import { toContext } from "./databricks.ts";
|
|
46
|
+
import { projectUtils, resolveValue } from "@dbx-tools/core";
|
|
58
47
|
import {
|
|
59
48
|
parseAddress,
|
|
60
49
|
parseResourcePath,
|
|
@@ -62,7 +51,20 @@ import {
|
|
|
62
51
|
SSL_MODES,
|
|
63
52
|
type LakebaseConnectionInputs,
|
|
64
53
|
type SslMode,
|
|
65
|
-
} from "
|
|
54
|
+
} from "@dbx-tools/lakebase";
|
|
55
|
+
import {
|
|
56
|
+
log,
|
|
57
|
+
sleep,
|
|
58
|
+
toError,
|
|
59
|
+
isRecord,
|
|
60
|
+
tcpPortSchema,
|
|
61
|
+
databricksEnvironmentNames,
|
|
62
|
+
toSlugWithOptions,
|
|
63
|
+
MAX_TCP_PORT,
|
|
64
|
+
} from "@dbx-tools/shared-core";
|
|
65
|
+
import { z } from "zod";
|
|
66
|
+
|
|
67
|
+
import { toContext } from "./databricks.ts";
|
|
66
68
|
|
|
67
69
|
const logger = log.logger("lakebase-resolver");
|
|
68
70
|
const API_BASE = "/api/2.0/postgres";
|
|
@@ -238,7 +240,7 @@ const operationSchema = z.object({
|
|
|
238
240
|
type Operation = z.infer<typeof operationSchema>;
|
|
239
241
|
|
|
240
242
|
/** `PGPORT` must land inside the TCP port range. */
|
|
241
|
-
const portSchema =
|
|
243
|
+
const portSchema = tcpPortSchema;
|
|
242
244
|
|
|
243
245
|
/**
|
|
244
246
|
* Validate a `PGPORT`-shaped value. Returns `undefined` when unset, and throws
|
|
@@ -249,11 +251,7 @@ export function parsePort(value: string | number | undefined): number | undefine
|
|
|
249
251
|
if (value === undefined || value === "") return undefined;
|
|
250
252
|
const parsed = portSchema.safeParse(value);
|
|
251
253
|
if (!parsed.success) {
|
|
252
|
-
throw ValidationError.invalidValue(
|
|
253
|
-
"PGPORT",
|
|
254
|
-
value,
|
|
255
|
-
`a TCP port between 1 and ${configUtils.MAX_TCP_PORT}`,
|
|
256
|
-
);
|
|
254
|
+
throw ValidationError.invalidValue("PGPORT", value, `a TCP port between 1 and ${MAX_TCP_PORT}`);
|
|
257
255
|
}
|
|
258
256
|
return parsed.data;
|
|
259
257
|
}
|
|
@@ -289,7 +287,7 @@ export function nextPollDelay(attempt: number, baseMs: number): number {
|
|
|
289
287
|
* instead of finishing its backoff first.
|
|
290
288
|
*/
|
|
291
289
|
export function pollDelay(attempt: number, baseMs: number, signal?: AbortSignal): Promise<void> {
|
|
292
|
-
return
|
|
290
|
+
return sleep(nextPollDelay(attempt, baseMs), signal);
|
|
293
291
|
}
|
|
294
292
|
|
|
295
293
|
/**
|
|
@@ -309,14 +307,10 @@ export async function readLakebaseInputs(
|
|
|
309
307
|
): Promise<LakebaseResolverInputs> {
|
|
310
308
|
const configOptions = { bundleProfile: config?.bundleProfile };
|
|
311
309
|
const rawAddress =
|
|
312
|
-
config?.endpoint ??
|
|
313
|
-
configUtils.resolveValue(
|
|
314
|
-
sharedOptions.databricksEnvironmentNames.lakebaseEndpoint,
|
|
315
|
-
configOptions,
|
|
316
|
-
);
|
|
310
|
+
config?.endpoint ?? resolveValue(databricksEnvironmentNames.lakebaseEndpoint, configOptions);
|
|
317
311
|
const parsed = parseAddress(rawAddress);
|
|
318
|
-
const portEnv = parsePort(
|
|
319
|
-
const sslModeEnv = parseSslMode(
|
|
312
|
+
const portEnv = parsePort(resolveValue("PGPORT", configOptions));
|
|
313
|
+
const sslModeEnv = parseSslMode(resolveValue("PGSSLMODE", configOptions));
|
|
320
314
|
const configuredSslMode = parseSslMode(config?.sslMode);
|
|
321
315
|
const parsedSslMode = parseSslMode(parsed.sslMode);
|
|
322
316
|
return {
|
|
@@ -326,9 +320,8 @@ export async function readLakebaseInputs(
|
|
|
326
320
|
// bare hostnames set `host` instead and leave `endpoint` undefined
|
|
327
321
|
// until the REST resolver fills it in.
|
|
328
322
|
endpoint: parsed.endpoint,
|
|
329
|
-
database:
|
|
330
|
-
|
|
331
|
-
host: config?.host ?? configUtils.resolveValue("PGHOST", configOptions) ?? parsed.host,
|
|
323
|
+
database: config?.database ?? resolveValue("PGDATABASE", configOptions) ?? parsed.database,
|
|
324
|
+
host: config?.host ?? resolveValue("PGHOST", configOptions) ?? parsed.host,
|
|
332
325
|
port: config?.port ?? portEnv ?? parsed.port,
|
|
333
326
|
sslMode: configuredSslMode ?? sslModeEnv ?? parsedSslMode,
|
|
334
327
|
autoCreate: config?.autoCreate,
|
|
@@ -444,7 +437,7 @@ export async function resolveLakebaseConnection(
|
|
|
444
437
|
*/
|
|
445
438
|
export function applyLakebaseToEnv(resolved: LakebaseConnection): void {
|
|
446
439
|
if (resolved.endpoint) {
|
|
447
|
-
process.env[
|
|
440
|
+
process.env[databricksEnvironmentNames.lakebaseEndpoint] ??= resolved.endpoint;
|
|
448
441
|
}
|
|
449
442
|
if (resolved.host) process.env.PGHOST ??= resolved.host;
|
|
450
443
|
if (resolved.database) process.env.PGDATABASE ??= resolved.database;
|
|
@@ -721,7 +714,7 @@ async function pickOrCreateProject(
|
|
|
721
714
|
*/
|
|
722
715
|
async function defaultProjectId(): Promise<string> {
|
|
723
716
|
const name = projectUtils.name();
|
|
724
|
-
const slug =
|
|
717
|
+
const slug = toSlugWithOptions({ maxLength: PROJECT_ID_MAX_LEN }, name);
|
|
725
718
|
if (!slug || !/^[a-z]/.test(slug)) {
|
|
726
719
|
logger.warn("autopg: project name does not slugify to a Lakebase project id", { name });
|
|
727
720
|
throw ConfigurationError.invalidConnection(
|
|
@@ -799,9 +792,9 @@ function isAlreadyExistsError(error: unknown): boolean {
|
|
|
799
792
|
function operationFailed(opName: string, opError: unknown): ExecutionError {
|
|
800
793
|
logger.error("autopg: operation failed", {
|
|
801
794
|
operation: opName,
|
|
802
|
-
error:
|
|
795
|
+
error: toError(opError),
|
|
803
796
|
});
|
|
804
|
-
const code =
|
|
797
|
+
const code = isRecord(opError) ? (opError.code ?? opError.reason) : undefined;
|
|
805
798
|
return new ExecutionError(`Lakebase operation failed: ${opName}`, {
|
|
806
799
|
context: {
|
|
807
800
|
operation: opName,
|
package/src/migration.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
/** Shared classification and logging policy for soft database migrations. */
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
type Logger,
|
|
5
|
+
errorContext,
|
|
6
|
+
errorMessage,
|
|
7
|
+
toError,
|
|
8
|
+
isLevelEnabled,
|
|
9
|
+
} from "@dbx-tools/shared-core";
|
|
4
10
|
|
|
5
11
|
const loggedOwnershipErrors = new Set<string>();
|
|
6
12
|
|
|
@@ -15,7 +21,7 @@ export interface OwnershipMigrationErrorOptions {
|
|
|
15
21
|
|
|
16
22
|
/** Whether a migration failed because the current role does not own an object. */
|
|
17
23
|
export function isOwnershipMigrationError(cause: unknown): boolean {
|
|
18
|
-
return
|
|
24
|
+
return errorContext(cause).hasMessage("must be owner");
|
|
19
25
|
}
|
|
20
26
|
|
|
21
27
|
/**
|
|
@@ -27,12 +33,12 @@ export function handleOwnershipMigrationError(
|
|
|
27
33
|
options: OwnershipMigrationErrorOptions,
|
|
28
34
|
): boolean {
|
|
29
35
|
if (!isOwnershipMigrationError(cause)) return false;
|
|
30
|
-
const message =
|
|
36
|
+
const message = errorMessage(cause);
|
|
31
37
|
const key = `${options.scope}\0${message}`;
|
|
32
38
|
if (loggedOwnershipErrors.has(key)) return true;
|
|
33
39
|
loggedOwnershipErrors.add(key);
|
|
34
|
-
const error =
|
|
35
|
-
if (
|
|
40
|
+
const error = toError(cause);
|
|
41
|
+
if (isLevelEnabled("debug")) options.logger.error(options.event, { error });
|
|
36
42
|
else options.logger.warn(options.event, { error, ...options.context });
|
|
37
43
|
return true;
|
|
38
44
|
}
|