@dbx-tools/shared-core 0.9.43 → 0.9.46
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 +3 -2
- package/lib/index.d.ts +3 -2
- package/lib/index.js +3 -2
- package/lib/src/bindings.d.ts +10 -0
- package/lib/src/bindings.js +15 -0
- package/lib/src/log.d.ts +2 -0
- package/lib/src/log.js +2 -2
- package/lib/src/options.d.ts +39 -8
- package/lib/src/options.js +127 -79
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -2
- package/src/bindings.ts +17 -0
- package/src/log.ts +1 -1
- package/src/options.ts +230 -83
package/src/options.ts
CHANGED
|
@@ -71,60 +71,55 @@ export const normalizedUrlSchema = z
|
|
|
71
71
|
|
|
72
72
|
const databricksText = (description: string) =>
|
|
73
73
|
z.string().trim().min(1).optional().describe(description);
|
|
74
|
+
const databricksOptionMeta = (env: string, flag = true) => ({
|
|
75
|
+
env,
|
|
76
|
+
flag,
|
|
77
|
+
helpDefault: false,
|
|
78
|
+
});
|
|
74
79
|
|
|
75
80
|
export const DatabricksOptionsSchema = z
|
|
76
81
|
.object({
|
|
77
|
-
profile: databricksText("Databricks CLI profile.").meta(
|
|
78
|
-
|
|
79
|
-
|
|
82
|
+
profile: databricksText("Databricks CLI profile.").meta(
|
|
83
|
+
databricksOptionMeta(databricksEnvironmentNames.profile),
|
|
84
|
+
),
|
|
80
85
|
host: normalizedUrlSchema
|
|
81
86
|
.optional()
|
|
82
87
|
.describe("Databricks host.")
|
|
83
|
-
.meta(
|
|
84
|
-
accountId: databricksText("Databricks account ID.").meta(
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
flag: false,
|
|
119
|
-
}),
|
|
120
|
-
appPort: tcpPortSchema.optional().describe("Databricks App port.").meta({
|
|
121
|
-
env: databricksEnvironmentNames.appPort,
|
|
122
|
-
flag: false,
|
|
123
|
-
}),
|
|
124
|
-
lakebaseEndpoint: databricksText("Lakebase endpoint.").meta({
|
|
125
|
-
env: databricksEnvironmentNames.lakebaseEndpoint,
|
|
126
|
-
flag: false,
|
|
127
|
-
}),
|
|
88
|
+
.meta(databricksOptionMeta(databricksEnvironmentNames.host, false)),
|
|
89
|
+
accountId: databricksText("Databricks account ID.").meta(
|
|
90
|
+
databricksOptionMeta(databricksEnvironmentNames.accountId, false),
|
|
91
|
+
),
|
|
92
|
+
workspaceId: databricksText("Databricks workspace ID.").meta(
|
|
93
|
+
databricksOptionMeta(databricksEnvironmentNames.workspaceId, false),
|
|
94
|
+
),
|
|
95
|
+
configFile: databricksText("Databricks CLI config file.").meta(
|
|
96
|
+
databricksOptionMeta(databricksEnvironmentNames.configFile, false),
|
|
97
|
+
),
|
|
98
|
+
clientId: databricksText("Databricks OAuth client ID.").meta(
|
|
99
|
+
databricksOptionMeta(databricksEnvironmentNames.clientId, false),
|
|
100
|
+
),
|
|
101
|
+
clientSecret: databricksText("Databricks OAuth client secret.").meta(
|
|
102
|
+
databricksOptionMeta(databricksEnvironmentNames.clientSecret, false),
|
|
103
|
+
),
|
|
104
|
+
accessToken: databricksText("Databricks access token.").meta(
|
|
105
|
+
databricksOptionMeta(databricksEnvironmentNames.accessToken, false),
|
|
106
|
+
),
|
|
107
|
+
groupId: databricksText("Databricks group ID.").meta(
|
|
108
|
+
databricksOptionMeta(databricksEnvironmentNames.groupId, false),
|
|
109
|
+
),
|
|
110
|
+
authType: databricksText("Databricks authentication type.").meta(
|
|
111
|
+
databricksOptionMeta(databricksEnvironmentNames.authType, false),
|
|
112
|
+
),
|
|
113
|
+
appName: databricksText("Databricks App name.").meta(
|
|
114
|
+
databricksOptionMeta(databricksEnvironmentNames.appName, false),
|
|
115
|
+
),
|
|
116
|
+
appPort: tcpPortSchema
|
|
117
|
+
.optional()
|
|
118
|
+
.describe("Databricks App port.")
|
|
119
|
+
.meta(databricksOptionMeta(databricksEnvironmentNames.appPort, false)),
|
|
120
|
+
lakebaseEndpoint: databricksText("Lakebase endpoint.").meta(
|
|
121
|
+
databricksOptionMeta(databricksEnvironmentNames.lakebaseEndpoint, false),
|
|
122
|
+
),
|
|
128
123
|
})
|
|
129
124
|
.strict()
|
|
130
125
|
.describe("Common Databricks CLI, SDK, Apps, and Lakebase options.");
|
|
@@ -134,6 +129,11 @@ export type DatabricksOptions = z.input<typeof DatabricksOptionsSchema>;
|
|
|
134
129
|
/** Key format emitted by {@link serializeOpts}. */
|
|
135
130
|
export type OptionSerializationFormat = "flag" | "env";
|
|
136
131
|
|
|
132
|
+
/** Namespace every option field while retaining its owning Zod field schemas. */
|
|
133
|
+
export type NamespacedOptionShape<T extends z.ZodRawShape, Prefix extends string> = {
|
|
134
|
+
[Key in keyof T as Key extends string ? `${Prefix}${Capitalize<Key>}` : never]: T[Key];
|
|
135
|
+
};
|
|
136
|
+
|
|
137
137
|
interface OptionProperty {
|
|
138
138
|
readonly key: string;
|
|
139
139
|
readonly type?: string;
|
|
@@ -147,6 +147,56 @@ export function serializeOpts<T extends z.ZodRawShape>(
|
|
|
147
147
|
values: z.input<z.ZodObject<T>>,
|
|
148
148
|
format: OptionSerializationFormat,
|
|
149
149
|
): string {
|
|
150
|
+
return JSON.stringify(serializedOpts(schema, values, format), null, 2);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Serialize complete parsed options as a process environment map. */
|
|
154
|
+
export function serializeOptsEnvironment<T extends z.ZodRawShape>(
|
|
155
|
+
schema: z.ZodObject<T>,
|
|
156
|
+
values: z.input<z.ZodObject<T>>,
|
|
157
|
+
): Readonly<Record<string, string>> {
|
|
158
|
+
return Object.fromEntries(
|
|
159
|
+
Object.entries(serializedOpts(schema, values, "env")).map(([key, value]) => [
|
|
160
|
+
key,
|
|
161
|
+
environmentOptionValue(value),
|
|
162
|
+
]),
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Namespace a reusable option schema so composed CLI flags render as `--<namespace>-<field>`. */
|
|
167
|
+
export function namespaceOpts<T extends z.ZodRawShape, Prefix extends string>(
|
|
168
|
+
schema: z.ZodObject<T>,
|
|
169
|
+
prefix: Prefix,
|
|
170
|
+
): z.ZodObject<NamespacedOptionShape<T, Prefix>> {
|
|
171
|
+
const shape = Object.fromEntries(
|
|
172
|
+
Object.entries(schema.shape).map(([key, field]) => [namespacedOptionKey(prefix, key), field]),
|
|
173
|
+
);
|
|
174
|
+
return z.object(shape).strict() as z.ZodObject<NamespacedOptionShape<T, Prefix>>;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** Parse namespaced option values back through their owning schema. */
|
|
178
|
+
export function unnamespaceOpts<T extends z.ZodRawShape>(
|
|
179
|
+
schema: z.ZodObject<T>,
|
|
180
|
+
values: object,
|
|
181
|
+
prefix: string,
|
|
182
|
+
): z.output<z.ZodObject<T>> {
|
|
183
|
+
const source = values as Readonly<Record<string, unknown>>;
|
|
184
|
+
return schema.parse(
|
|
185
|
+
Object.fromEntries(
|
|
186
|
+
Object.keys(schema.shape).map((key) => [key, source[namespacedOptionKey(prefix, key)]]),
|
|
187
|
+
),
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function namespacedOptionKey(prefix: string, key: string): string {
|
|
192
|
+
return `${prefix}${key.charAt(0).toUpperCase()}${key.slice(1)}`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function serializedOpts<T extends z.ZodRawShape>(
|
|
196
|
+
schema: z.ZodObject<T>,
|
|
197
|
+
values: z.input<z.ZodObject<T>>,
|
|
198
|
+
format: OptionSerializationFormat,
|
|
199
|
+
): Readonly<Record<string, unknown>> {
|
|
150
200
|
const parsed = schema.parse(values) as Readonly<Record<string, unknown>>;
|
|
151
201
|
const entries = optionProperties(schema).flatMap((property) => {
|
|
152
202
|
if (format === "flag" && property.flag === false) return [];
|
|
@@ -158,7 +208,7 @@ export function serializeOpts<T extends z.ZodRawShape>(
|
|
|
158
208
|
const value = parsed[property.key];
|
|
159
209
|
return value === undefined ? [] : [[key, serializedOptionValue(value)] as const];
|
|
160
210
|
});
|
|
161
|
-
return
|
|
211
|
+
return Object.fromEntries(entries);
|
|
162
212
|
}
|
|
163
213
|
|
|
164
214
|
const optionalText = (description: string, env: string) =>
|
|
@@ -192,67 +242,153 @@ export function parseOpts<T extends z.ZodRawShape>(
|
|
|
192
242
|
) as Partial<z.output<z.ZodObject<T>>>;
|
|
193
243
|
}
|
|
194
244
|
|
|
195
|
-
/**
|
|
196
|
-
export
|
|
245
|
+
/** Supported listener transport schemes. */
|
|
246
|
+
export type ListenScheme = "tcp" | "unix";
|
|
247
|
+
|
|
248
|
+
/** TCP listener returned by {@link listenAddressSchema}. */
|
|
249
|
+
export interface TcpListenAddress {
|
|
250
|
+
readonly scheme: "tcp";
|
|
197
251
|
readonly host: string;
|
|
198
252
|
readonly port: number;
|
|
199
253
|
}
|
|
200
254
|
|
|
255
|
+
/** Unix-domain listener returned by {@link listenAddressSchema}. */
|
|
256
|
+
export interface UnixListenAddress {
|
|
257
|
+
readonly scheme: "unix";
|
|
258
|
+
readonly path: string;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/** Transport-aware listener address. */
|
|
262
|
+
export type ListenAddress = TcpListenAddress | UnixListenAddress;
|
|
263
|
+
|
|
201
264
|
/** Defaults and validation policy for {@link listenAddressSchema}. */
|
|
202
265
|
export interface ListenAddressOptions {
|
|
203
266
|
readonly port: number;
|
|
204
267
|
readonly host?: string;
|
|
205
268
|
readonly loopback?: boolean;
|
|
269
|
+
readonly scheme?: ListenScheme;
|
|
270
|
+
readonly schemes?: readonly ListenScheme[];
|
|
271
|
+
readonly withDefault?: boolean;
|
|
206
272
|
}
|
|
207
273
|
|
|
208
|
-
/**
|
|
209
|
-
export
|
|
210
|
-
|
|
274
|
+
/** Raw listener input accepted before transport-aware normalization. */
|
|
275
|
+
export type ListenAddressInput = ListenAddress | string | number | undefined;
|
|
276
|
+
|
|
277
|
+
export function listenAddressSchema(
|
|
278
|
+
options: ListenAddressOptions & {
|
|
279
|
+
readonly schemes: readonly ["tcp", "unix"];
|
|
280
|
+
readonly withDefault: false;
|
|
281
|
+
},
|
|
282
|
+
): z.ZodType<ListenAddress, unknown>;
|
|
283
|
+
|
|
284
|
+
export function listenAddressSchema(
|
|
285
|
+
options: ListenAddressOptions & { readonly schemes: readonly ["tcp", "unix"] },
|
|
286
|
+
): z.ZodDefault<z.ZodType<ListenAddress, unknown>>;
|
|
287
|
+
|
|
288
|
+
export function listenAddressSchema(
|
|
289
|
+
options: ListenAddressOptions & { readonly withDefault: false },
|
|
290
|
+
): z.ZodType<TcpListenAddress, unknown>;
|
|
291
|
+
|
|
292
|
+
export function listenAddressSchema(
|
|
293
|
+
options: ListenAddressOptions,
|
|
294
|
+
): z.ZodDefault<z.ZodType<TcpListenAddress, unknown>>;
|
|
295
|
+
|
|
296
|
+
/** Build a transport-aware listener schema. Bare addresses use the configured default scheme. */
|
|
297
|
+
export function listenAddressSchema(
|
|
298
|
+
options: ListenAddressOptions,
|
|
299
|
+
): z.ZodType<ListenAddress, unknown> | z.ZodDefault<z.ZodType<ListenAddress, unknown>> {
|
|
300
|
+
const defaults: TcpListenAddress = {
|
|
301
|
+
scheme: "tcp",
|
|
211
302
|
host: options.host ?? "localhost",
|
|
212
303
|
port: options.port,
|
|
213
304
|
};
|
|
214
|
-
|
|
305
|
+
const allowed = new Set<ListenScheme>(options.schemes ?? ["tcp"]);
|
|
306
|
+
const schema = z
|
|
215
307
|
.preprocess(
|
|
216
|
-
(value) => parseListenAddress(value, defaults),
|
|
217
|
-
z
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
308
|
+
(value) => parseListenAddress(value, defaults, options.scheme ?? "tcp"),
|
|
309
|
+
z.discriminatedUnion("scheme", [
|
|
310
|
+
z
|
|
311
|
+
.object({
|
|
312
|
+
scheme: z.literal("tcp"),
|
|
313
|
+
host: z.string().trim().toLowerCase().min(1).default(defaults.host),
|
|
314
|
+
port: tcpPortOrZeroSchema.default(defaults.port),
|
|
315
|
+
})
|
|
316
|
+
.strict(),
|
|
317
|
+
z
|
|
318
|
+
.object({
|
|
319
|
+
scheme: z.literal("unix"),
|
|
320
|
+
path: z.string().trim().min(1),
|
|
321
|
+
})
|
|
322
|
+
.strict(),
|
|
323
|
+
]),
|
|
227
324
|
)
|
|
228
|
-
.
|
|
229
|
-
.
|
|
325
|
+
.refine((address) => allowed.has(address.scheme), "Listener scheme is not allowed.")
|
|
326
|
+
.refine(
|
|
327
|
+
(address) => address.scheme !== "tcp" || !options.loopback || isLoopbackHost(address.host),
|
|
328
|
+
"Listener host must be loopback.",
|
|
329
|
+
)
|
|
330
|
+
.describe("TCP or Unix-domain listener address.") as z.ZodType<ListenAddress, unknown>;
|
|
331
|
+
return options.withDefault === false ? schema : schema.default(defaults);
|
|
230
332
|
}
|
|
231
333
|
|
|
232
|
-
/** Render a listener address as `
|
|
334
|
+
/** Render a listener address as a `tcp://` or `unix://` URL. */
|
|
233
335
|
export function formatListenAddress(address: ListenAddress): string {
|
|
336
|
+
if (address.scheme === "unix") {
|
|
337
|
+
return `unix://${address.path.startsWith("/") ? "" : "/"}${address.path}`;
|
|
338
|
+
}
|
|
234
339
|
const host = address.host.includes(":") ? `[${address.host}]` : address.host;
|
|
235
|
-
return
|
|
340
|
+
return `tcp://${host}:${address.port}`;
|
|
236
341
|
}
|
|
237
342
|
|
|
238
|
-
function parseListenAddress(
|
|
239
|
-
|
|
343
|
+
function parseListenAddress(
|
|
344
|
+
value: unknown,
|
|
345
|
+
defaults: TcpListenAddress,
|
|
346
|
+
defaultScheme: ListenScheme,
|
|
347
|
+
): unknown {
|
|
348
|
+
if (isRecord(value) && value.scheme === undefined) {
|
|
349
|
+
if (typeof value.host === "string" && value.port !== undefined) {
|
|
350
|
+
return { ...value, scheme: "tcp" };
|
|
351
|
+
}
|
|
352
|
+
if (typeof value.path === "string") {
|
|
353
|
+
return { ...value, scheme: "unix" };
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
if (typeof value === "number") {
|
|
357
|
+
return defaultScheme === "tcp"
|
|
358
|
+
? { scheme: "tcp", host: defaults.host, port: value }
|
|
359
|
+
: { scheme: "unix", path: String(value) };
|
|
360
|
+
}
|
|
240
361
|
if (typeof value !== "string") return value;
|
|
241
362
|
const text = value.trim();
|
|
242
|
-
if (
|
|
243
|
-
|
|
244
|
-
|
|
363
|
+
if (text.startsWith("unix://")) {
|
|
364
|
+
const path = text.slice("unix://".length);
|
|
365
|
+
return { scheme: "unix", path: path.startsWith("/") ? path : `/${path}` };
|
|
366
|
+
}
|
|
367
|
+
const tcp = text.startsWith("tcp://") ? text.slice("tcp://".length) : text;
|
|
368
|
+
if (defaultScheme === "unix" && !text.startsWith("tcp://")) {
|
|
369
|
+
return { scheme: "unix", path: text };
|
|
370
|
+
}
|
|
371
|
+
if (/^\d+$/.test(tcp)) return { scheme: "tcp", host: defaults.host, port: tcp };
|
|
372
|
+
if (/^:\d+$/.test(tcp)) {
|
|
373
|
+
return { scheme: "tcp", host: defaults.host, port: tcp.slice(1) };
|
|
374
|
+
}
|
|
375
|
+
const bracketed = tcp.match(/^\[([^\]]+)\](?::(\d+))?$/);
|
|
245
376
|
if (bracketed) {
|
|
246
|
-
return {
|
|
377
|
+
return {
|
|
378
|
+
scheme: "tcp",
|
|
379
|
+
host: bracketed[1],
|
|
380
|
+
port: bracketed[2] ?? defaults.port,
|
|
381
|
+
};
|
|
247
382
|
}
|
|
248
|
-
const separator =
|
|
249
|
-
if (separator > 0 && !
|
|
383
|
+
const separator = tcp.lastIndexOf(":");
|
|
384
|
+
if (separator > 0 && !tcp.slice(0, separator).includes(":")) {
|
|
250
385
|
return {
|
|
251
|
-
|
|
252
|
-
|
|
386
|
+
scheme: "tcp",
|
|
387
|
+
host: tcp.slice(0, separator),
|
|
388
|
+
port: tcp.slice(separator + 1),
|
|
253
389
|
};
|
|
254
390
|
}
|
|
255
|
-
return { host:
|
|
391
|
+
return { scheme: "tcp", host: tcp || defaults.host, port: defaults.port };
|
|
256
392
|
}
|
|
257
393
|
|
|
258
394
|
function optionProperties(schema: z.ZodObject<z.ZodRawShape>): OptionProperty[] {
|
|
@@ -275,12 +411,23 @@ function optionProperties(schema: z.ZodObject<z.ZodRawShape>): OptionProperty[]
|
|
|
275
411
|
}
|
|
276
412
|
|
|
277
413
|
function serializedOptionValue(value: unknown): unknown {
|
|
278
|
-
if (isRecord(value) &&
|
|
279
|
-
|
|
414
|
+
if (isRecord(value) && value.scheme === "tcp") {
|
|
415
|
+
if (typeof value.host === "string" && typeof value.port === "number") {
|
|
416
|
+
return formatListenAddress({ scheme: "tcp", host: value.host, port: value.port });
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
if (isRecord(value) && value.scheme === "unix" && typeof value.path === "string") {
|
|
420
|
+
return formatListenAddress({ scheme: "unix", path: value.path });
|
|
280
421
|
}
|
|
281
422
|
return value;
|
|
282
423
|
}
|
|
283
424
|
|
|
425
|
+
function environmentOptionValue(value: unknown): string {
|
|
426
|
+
if (Array.isArray(value)) return value.map(String).join(",");
|
|
427
|
+
if (typeof value === "object" && value !== null) return JSON.stringify(value);
|
|
428
|
+
return String(value);
|
|
429
|
+
}
|
|
430
|
+
|
|
284
431
|
function optionValues<T extends z.ZodRawShape>(
|
|
285
432
|
schema: z.ZodObject<T>,
|
|
286
433
|
values: OptionValueMap,
|