@dbx-tools/cli 0.9.58 → 0.9.61

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.
Files changed (90) hide show
  1. package/README.md +594 -57
  2. package/bin/dbx-genie.ts +13 -0
  3. package/bin/dbx-graphiti.ts +5 -0
  4. package/bin/dbx-lakebase-proxy.ts +4 -0
  5. package/bin/dbx-model-gateway.ts +5 -0
  6. package/index.ts +47 -1
  7. package/lib/bin/dbx-genie.d.ts +2 -0
  8. package/lib/bin/dbx-genie.js +10 -0
  9. package/lib/bin/dbx-graphiti.d.ts +2 -0
  10. package/lib/bin/dbx-graphiti.js +4 -0
  11. package/lib/bin/dbx-lakebase-proxy.d.ts +2 -0
  12. package/lib/bin/dbx-lakebase-proxy.js +4 -0
  13. package/lib/bin/dbx-model-gateway.d.ts +2 -0
  14. package/lib/bin/dbx-model-gateway.js +4 -0
  15. package/lib/index.d.ts +47 -1
  16. package/lib/index.js +34 -2
  17. package/lib/src/appkit/cli.d.ts +24 -0
  18. package/lib/src/appkit/cli.js +54 -0
  19. package/lib/src/appkit/env-export.d.ts +40 -0
  20. package/lib/src/appkit/env-export.js +99 -0
  21. package/lib/src/auth/cli.d.ts +20 -0
  22. package/lib/src/auth/cli.js +129 -0
  23. package/lib/src/auth/options.d.ts +45 -0
  24. package/lib/src/auth/options.js +68 -0
  25. package/lib/src/cli.d.ts +2 -0
  26. package/lib/src/cli.js +19 -9
  27. package/lib/src/genie-code/cli.d.ts +19 -0
  28. package/lib/src/genie-code/cli.js +36 -0
  29. package/lib/src/genie-code/config.d.ts +38 -0
  30. package/lib/src/genie-code/config.js +111 -0
  31. package/lib/src/genie-code/install.d.ts +21 -0
  32. package/lib/src/genie-code/install.js +69 -0
  33. package/lib/src/genie-code/options.d.ts +7 -0
  34. package/lib/src/genie-code/options.js +7 -0
  35. package/lib/src/genie-code/runner.d.ts +21 -0
  36. package/lib/src/genie-code/runner.js +90 -0
  37. package/lib/src/genie-code/runtime.d.ts +48 -0
  38. package/lib/src/genie-code/runtime.js +162 -0
  39. package/lib/src/graphiti/cli.d.ts +18 -0
  40. package/lib/src/graphiti/cli.js +43 -0
  41. package/lib/src/graphiti/options.d.ts +10 -0
  42. package/lib/src/graphiti/options.js +10 -0
  43. package/lib/src/lakebase-proxy/cancellation.d.ts +22 -0
  44. package/lib/src/lakebase-proxy/cancellation.js +100 -0
  45. package/lib/src/lakebase-proxy/cli.d.ts +13 -0
  46. package/lib/src/lakebase-proxy/cli.js +54 -0
  47. package/lib/src/lakebase-proxy/options.d.ts +23 -0
  48. package/lib/src/lakebase-proxy/options.js +41 -0
  49. package/lib/src/lakebase-proxy/protocol.d.ts +37 -0
  50. package/lib/src/lakebase-proxy/protocol.js +124 -0
  51. package/lib/src/lakebase-proxy/proxy.d.ts +22 -0
  52. package/lib/src/lakebase-proxy/proxy.js +200 -0
  53. package/lib/src/model-gateway/cli.d.ts +19 -0
  54. package/lib/src/model-gateway/cli.js +63 -0
  55. package/lib/src/model-gateway/server.d.ts +16 -0
  56. package/lib/src/model-gateway/server.js +83 -0
  57. package/lib/src/tunnel/app.d.ts +20 -0
  58. package/lib/src/tunnel/app.js +52 -0
  59. package/lib/src/tunnel/cli.d.ts +27 -0
  60. package/lib/src/tunnel/cli.js +190 -0
  61. package/lib/src/tunnel/options.d.ts +72 -0
  62. package/lib/src/tunnel/options.js +138 -0
  63. package/lib/src/tunnel/proxy.d.ts +51 -0
  64. package/lib/src/tunnel/proxy.js +143 -0
  65. package/lib/tsconfig.tsbuildinfo +1 -1
  66. package/package.json +146 -9
  67. package/src/appkit/cli.ts +72 -0
  68. package/src/appkit/env-export.ts +124 -0
  69. package/src/auth/cli.ts +175 -0
  70. package/src/auth/options.ts +83 -0
  71. package/src/cli.ts +35 -8
  72. package/src/genie-code/cli.ts +58 -0
  73. package/src/genie-code/config.ts +161 -0
  74. package/src/genie-code/install.ts +103 -0
  75. package/src/genie-code/options.ts +14 -0
  76. package/src/genie-code/runner.ts +106 -0
  77. package/src/genie-code/runtime.ts +212 -0
  78. package/src/graphiti/cli.ts +75 -0
  79. package/src/graphiti/options.ts +20 -0
  80. package/src/lakebase-proxy/cancellation.ts +116 -0
  81. package/src/lakebase-proxy/cli.ts +80 -0
  82. package/src/lakebase-proxy/options.ts +56 -0
  83. package/src/lakebase-proxy/protocol.ts +170 -0
  84. package/src/lakebase-proxy/proxy.ts +256 -0
  85. package/src/model-gateway/cli.ts +93 -0
  86. package/src/model-gateway/server.ts +94 -0
  87. package/src/tunnel/app.ts +58 -0
  88. package/src/tunnel/cli.ts +218 -0
  89. package/src/tunnel/options.ts +169 -0
  90. package/src/tunnel/proxy.ts +194 -0
@@ -0,0 +1,200 @@
1
+ /** Pure Node PostgreSQL wire proxy for Databricks Lakebase. */
2
+ import { createServer } from "node:net";
3
+ import { LakebaseClient, requireAddress } from "@dbx-tools/lakebase";
4
+ import { postgresConnectionOptions } from "@dbx-tools/postgres";
5
+ import { log, stringUtils } from "@dbx-tools/shared-core";
6
+ import { Client } from "pg";
7
+ import { CancellationRegistry } from "./cancellation.js";
8
+ import { resolveLakebaseProxyOptions, } from "./options.js";
9
+ import { fatalError, PostgresProtocolError, readInitialMessage, startupComplete, upstreamStartupParameters, } from "./protocol.js";
10
+ const logger = log.logger("lakebase-proxy");
11
+ /** Loopback PostgreSQL wire proxy backed by Databricks Lakebase credentials. */
12
+ export class LakebaseProxy {
13
+ client;
14
+ options;
15
+ cancellations = new CancellationRegistry();
16
+ server;
17
+ statsTimer;
18
+ opened = 0;
19
+ closed = 0;
20
+ failed = 0;
21
+ active = 0;
22
+ constructor(options = {}) {
23
+ this.options = resolveLakebaseProxyOptions(options);
24
+ this.client = new LakebaseClient({ profile: this.options.profile });
25
+ }
26
+ async listen() {
27
+ if (this.server)
28
+ throw new Error("Lakebase proxy is already listening");
29
+ const host = this.options.listen.host;
30
+ const server = createServer((socket) => void this.handle(socket));
31
+ this.server = server;
32
+ this.statsTimer = setInterval(() => this.reportStats(), 60_000);
33
+ this.statsTimer.unref();
34
+ await new Promise((resolve, reject) => {
35
+ server.once("error", reject);
36
+ server.listen(this.options.listen.port, host, () => {
37
+ server.off("error", reject);
38
+ resolve();
39
+ });
40
+ });
41
+ const address = server.address();
42
+ if (!address || typeof address === "string") {
43
+ throw new Error("Lakebase listener has no address");
44
+ }
45
+ logger.info("Lakebase proxy listening", { host: address.address, port: address.port });
46
+ return { host: address.address, port: address.port };
47
+ }
48
+ async close() {
49
+ const server = this.server;
50
+ this.server = undefined;
51
+ if (this.statsTimer)
52
+ clearInterval(this.statsTimer);
53
+ this.statsTimer = undefined;
54
+ if (!server)
55
+ return;
56
+ await new Promise((resolve, reject) => server.close((error) => (error ? reject(error) : resolve())));
57
+ }
58
+ async handle(local) {
59
+ const started = Date.now();
60
+ let upstream;
61
+ let cancellation;
62
+ this.opened += 1;
63
+ this.active += 1;
64
+ try {
65
+ local.setNoDelay(true);
66
+ const initial = await readInitialMessage(local, this.options.startupTimeoutSeconds * 1000);
67
+ if (initial.kind === "cancel") {
68
+ await this.cancellations.forward(initial);
69
+ local.end();
70
+ return;
71
+ }
72
+ const startup = initial;
73
+ const targetText = startup.parameters.database;
74
+ if (!targetText)
75
+ throw new ProxyFailure("startup database is required", "3D000");
76
+ let target;
77
+ try {
78
+ target = requireAddress(targetText);
79
+ }
80
+ catch (error) {
81
+ throw new ProxyFailure(message(error), "3D000");
82
+ }
83
+ const startupUser = stringUtils.trimToUndefined(startup.parameters.user);
84
+ let resolved;
85
+ try {
86
+ resolved = await this.client.resolve(target, startupUser);
87
+ }
88
+ catch (error) {
89
+ throw new ProxyFailure(message(error), "3D000");
90
+ }
91
+ let password;
92
+ try {
93
+ password = await this.client.generateDatabaseCredential(resolved.endpoint, startupUser);
94
+ }
95
+ catch (error) {
96
+ throw new ProxyFailure(message(error), "28000");
97
+ }
98
+ let connected;
99
+ try {
100
+ connected = await connectUpstream(resolved, password, postgresConnectionOptions(startup.parameters, this.options.postgresRole));
101
+ }
102
+ catch (error) {
103
+ throw new ProxyFailure(message(error), "08001");
104
+ }
105
+ upstream = connected.socket;
106
+ cancellation = this.cancellations.register({
107
+ host: resolved.host,
108
+ port: resolved.port,
109
+ processId: connected.processId,
110
+ secretKey: connected.secretKey,
111
+ });
112
+ local.write(startupComplete(connected.parameters, cancellation.processId, cancellation.secretKey, connected.transactionStatus));
113
+ local.pipe(upstream).pipe(local);
114
+ await Promise.race([closed(local), closed(upstream)]);
115
+ logger.debug("Lakebase connection closed", {
116
+ durationMs: Date.now() - started,
117
+ project: resolved.project,
118
+ branch: resolved.branch,
119
+ endpoint: resolved.endpoint,
120
+ });
121
+ }
122
+ catch (error) {
123
+ this.failed += 1;
124
+ const failure = error instanceof ProxyFailure
125
+ ? error
126
+ : error instanceof PostgresProtocolError
127
+ ? new ProxyFailure(error.message, "08P01")
128
+ : new ProxyFailure(message(error));
129
+ logger.warn("Lakebase connection failed", {
130
+ durationMs: Date.now() - started,
131
+ error: failure.message,
132
+ });
133
+ if (!local.destroyed)
134
+ local.end(fatalError(failure.message, failure.sqlstate));
135
+ }
136
+ finally {
137
+ if (cancellation)
138
+ this.cancellations.remove(cancellation);
139
+ upstream?.destroy();
140
+ local.destroy();
141
+ this.closed += 1;
142
+ this.active -= 1;
143
+ }
144
+ }
145
+ reportStats() {
146
+ logger.info("Lakebase proxy connections", {
147
+ opened: this.opened,
148
+ closed: this.closed,
149
+ failed: this.failed,
150
+ active: this.active,
151
+ });
152
+ }
153
+ }
154
+ async function connectUpstream(resolved, password, startup) {
155
+ const client = new Client({
156
+ host: resolved.host,
157
+ port: resolved.port,
158
+ database: resolved.database,
159
+ user: resolved.user,
160
+ password,
161
+ ssl: { rejectUnauthorized: true, servername: resolved.host },
162
+ application_name: startup.application_name,
163
+ connectionTimeoutMillis: 30_000,
164
+ });
165
+ const parameters = new Map();
166
+ client.getStartupConf = () => upstreamStartupParameters(startup, resolved.user, resolved.database);
167
+ client.on("error", (error) => {
168
+ logger.debug("Lakebase upstream client closed", { error: error.message });
169
+ });
170
+ client.connection.on("parameterStatus", (message) => {
171
+ parameters.set(message.parameterName, message.parameterValue);
172
+ });
173
+ await client.connect();
174
+ const socket = client.connection.stream;
175
+ socket.removeAllListeners("data");
176
+ return {
177
+ socket,
178
+ parameters,
179
+ processId: client.processID,
180
+ secretKey: client.secretKey,
181
+ transactionStatus: client._txStatus ?? "I",
182
+ };
183
+ }
184
+ function closed(socket) {
185
+ return new Promise((resolve, reject) => {
186
+ socket.once("close", () => resolve());
187
+ socket.once("error", reject);
188
+ });
189
+ }
190
+ function message(error) {
191
+ return error instanceof Error ? error.message : String(error);
192
+ }
193
+ class ProxyFailure extends Error {
194
+ sqlstate;
195
+ constructor(message, sqlstate = "08001") {
196
+ super(message);
197
+ this.sqlstate = sqlstate;
198
+ }
199
+ }
200
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJveHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGFrZWJhc2UtcHJveHkvcHJveHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0RBQStEO0FBRS9ELE9BQU8sRUFBRSxZQUFZLEVBQTRCLE1BQU0sVUFBVSxDQUFDO0FBRWxFLE9BQU8sRUFBRSxjQUFjLEVBQUUsY0FBYyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDckUsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDaEUsT0FBTyxFQUFFLEdBQUcsRUFBRSxXQUFXLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUMxRCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBRTVCLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ3pELE9BQU8sRUFDTCwyQkFBMkIsR0FHNUIsTUFBTSxjQUFjLENBQUM7QUFDdEIsT0FBTyxFQUNMLFVBQVUsRUFDVixxQkFBcUIsRUFDckIsa0JBQWtCLEVBQ2xCLGVBQWUsRUFDZix5QkFBeUIsR0FFMUIsTUFBTSxlQUFlLENBQUM7QUFFdkIsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0FBb0I1QyxnRkFBZ0Y7QUFDaEYsTUFBTSxPQUFPLGFBQWE7SUFDUCxNQUFNLENBQWlCO0lBQ3ZCLE9BQU8sQ0FBK0I7SUFDdEMsYUFBYSxHQUFHLElBQUksb0JBQW9CLEVBQUUsQ0FBQztJQUNwRCxNQUFNLENBQVU7SUFDaEIsVUFBVSxDQUFrQztJQUM1QyxNQUFNLEdBQUcsQ0FBQyxDQUFDO0lBQ1gsTUFBTSxHQUFHLENBQUMsQ0FBQztJQUNYLE1BQU0sR0FBRyxDQUFDLENBQUM7SUFDWCxNQUFNLEdBQUcsQ0FBQyxDQUFDO0lBRW5CLFlBQVksVUFBZ0MsRUFBRTtRQUM1QyxJQUFJLENBQUMsT0FBTyxHQUFHLDJCQUEyQixD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QUFPLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDL0IsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsU0FBUyxPQUFPLENBQUMsS0FBYztJQUM3QixPQUFPLEtBQUssWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUNoRSxDQUFDO0FBRUQsTUFBTSxZQUFhLFNBQVEsS0FBSztJQUduQjtJQUZYLFlBQ0UsT0FBZSxFQUNOLFdBQVcsT0FBTztRQUUzQixLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFGTixhQUFRLEdBQVIsUUFBUSxDQUFVO0lBRzdCLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKiBQdXJlIE5vZGUgUG9zdGdyZVNRTCB3aXJlIHByb3h5IGZvciBEYXRhYnJpY2tzIExha2ViYXNlLiAqL1xuXG5pbXBvcnQgeyBjcmVhdGVTZXJ2ZXIsIHR5cGUgU2VydmVyLCB0eXBlIFNvY2tldCB9IGZyb20gXCJub2RlOm5ldFwiO1xuaW1wb3J0IHR5cGUgeyBEdXBsZXggfSBmcm9tIFwibm9kZTpzdHJlYW1cIjtcbmltcG9ydCB7IExha2ViYXNlQ2xpZW50LCByZXF1aXJlQWRkcmVzcyB9IGZyb20gXCJAZGJ4LXRvb2xzL2xha2ViYXNlXCI7XG5pbXBvcnQgeyBwb3N0Z3Jlc0Nvbm5lY3Rpb25PcHRpb25zIH0gZnJvbSBcIkBkYngtdG9vbHMvcG9zdGdyZXNcIjtcbmltcG9ydCB7IGxvZywgc3RyaW5nVXRpbHMgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHsgQ2xpZW50IH0gZnJvbSBcInBnXCI7XG5cbmltcG9ydCB7IENhbmNlbGxhdGlvblJlZ2lzdHJ5IH0gZnJvbSBcIi4vY2FuY2VsbGF0aW9uLnRzXCI7XG5pbXBvcnQge1xuICByZXNvbHZlTGFrZWJhc2VQcm94eU9wdGlvbnMsXG4gIHR5cGUgTGFrZWJhc2VQcm94eU9wdGlvbnMsXG4gIHR5cGUgUmVzb2x2ZWRMYWtlYmFzZVByb3h5T3B0aW9ucyxcbn0gZnJvbSBcIi4vb3B0aW9ucy50c1wiO1xuaW1wb3J0IHtcbiAgZmF0YWxFcnJvcixcbiAgUG9zdGdyZXNQcm90b2NvbEVycm9yLFxuICByZWFkSW5pdGlhbE1lc3NhZ2UsXG4gIHN0YXJ0dXBDb21wbGV0ZSxcbiAgdXBzdHJlYW1TdGFydHVwUGFyYW1ldGVycyxcbiAgdHlwZSBDYW5jZWxNZXNzYWdlLFxufSBmcm9tIFwiLi9wcm90b2NvbC50c1wiO1xuXG5jb25zdCBsb2dnZXIgPSBsb2cubG9nZ2VyKFwibGFrZWJhc2UtcHJveHlcIik7XG5cbmludGVyZmFjZSBQZ0Nvbm5lY3Rpb25JbnRlcm5hbHMge1xuICBzdHJlYW06IER1cGxleDtcbiAgb24oZXZlbnQ6IFwicGFyYW1ldGVyU3RhdHVzXCIsIGxpc3RlbmVyOiAobWVzc2FnZTogUGFyYW1ldGVyU3RhdHVzKSA9PiB2b2lkKTogdm9pZDtcbn1cblxudHlwZSBQZ0NsaWVudEludGVybmFscyA9IENsaWVudCAmIHtcbiAgY29ubmVjdGlvbjogQ2xpZW50W1wiY29ubmVjdGlvblwiXSAmIFBnQ29ubmVjdGlvbkludGVybmFscztcbiAgcHJvY2Vzc0lEOiBudW1iZXI7XG4gIHNlY3JldEtleTogbnVtYmVyO1xuICBfdHhTdGF0dXM/OiBzdHJpbmc7XG4gIGdldFN0YXJ0dXBDb25mKCk6IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG59O1xuXG5pbnRlcmZhY2UgUGFyYW1ldGVyU3RhdHVzIHtcbiAgcGFyYW1ldGVyTmFtZTogc3RyaW5nO1xuICBwYXJhbWV0ZXJWYWx1ZTogc3RyaW5nO1xufVxuXG4vKiogTG9vcGJhY2sgUG9zdGdyZVNRTCB3aXJlIHByb3h5IGJhY2tlZCBieSBEYXRhYnJpY2tzIExha2ViYXNlIGNyZWRlbnRpYWxzLiAqL1xuZXhwb3J0IGNsYXNzIExha2ViYXNlUHJveHkge1xuICBwcml2YXRlIHJlYWRvbmx5IGNsaWVudDogTGFrZWJhc2VDbGllbnQ7XG4gIHByaXZhdGUgcmVhZG9ubHkgb3B0aW9uczogUmVzb2x2ZWRMYWtlYmFzZVByb3h5T3B0aW9ucztcbiAgcHJpdmF0ZSByZWFkb25seSBjYW5jZWxsYXRpb25zID0gbmV3IENhbmNlbGxhdGlvblJlZ2lzdHJ5KCk7XG4gIHByaXZhdGUgc2VydmVyPzogU2VydmVyO1xuICBwcml2YXRlIHN0YXRzVGltZXI/OiBSZXR1cm5UeXBlPHR5cGVvZiBzZXRJbnRlcnZhbD47XG4gIHByaXZhdGUgb3BlbmVkID0gMDtcbiAgcHJpdmF0ZSBjbG9zZWQgPSAwO1xuICBwcml2YXRlIGZhaWxlZCA9IDA7XG4gIHByaXZhdGUgYWN0aXZlID0gMDtcblxuICBjb25zdHJ1Y3RvcihvcHRpb25zOiBMYWtlYmFzZVByb3h5T3B0aW9ucyA9IHt9KSB7XG4gICAgdGhpcy5vcHRpb25zID0gcmVzb2x2ZUxha2ViYXNlUHJveHlPcHRpb25zKG9wdGlvbnMpO1xuICAgIHRoaXMuY2xpZW50ID0gbmV3IExha2ViYXNlQ2xpZW50KHsgcHJvZmlsZTogdGhpcy5vcHRpb25zLnByb2ZpbGUgfSk7XG4gIH1cblxuICBhc3luYyBsaXN0ZW4oKTogUHJvbWlzZTx7IGhvc3Q6IHN0cmluZzsgcG9ydDogbnVtYmVyIH0+IHtcbiAgICBpZiAodGhpcy5zZXJ2ZXIpIHRocm93IG5ldyBFcnJvcihcIkxha2ViYXNlIHByb3h5IGlzIGFscmVhZHkgbGlzdGVuaW5nXCIpO1xuICAgIGNvbnN0IGhvc3QgPSB0aGlzLm9wdGlvbnMubGlzdGVuLmhvc3Q7XG4gICAgY29uc3Qgc2VydmVyID0gY3JlYXRlU2VydmVyKChzb2NrZXQpID0+IHZvaWQgdGhpcy5oYW5kbGUoc29ja2V0KSk7XG4gICAgdGhpcy5zZXJ2ZXIgPSBzZXJ2ZXI7XG4gICAgdGhpcy5zdGF0c1RpbWVyID0gc2V0SW50ZXJ2YWwoKCkgPT4gdGhpcy5yZXBvcnRTdGF0cygpLCA2MF8wMDApO1xuICAgIHRoaXMuc3RhdHNUaW1lci51bnJlZigpO1xuICAgIGF3YWl0IG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIHNlcnZlci5vbmNlKFwiZXJyb3JcIiwgcmVqZWN0KTtcbiAgICAgIHNlcnZlci5saXN0ZW4odGhpcy5vcHRpb25zLmxpc3Rlbi5wb3J0LCBob3N0LCAoKSA9PiB7XG4gICAgICAgIHNlcnZlci5vZmYoXCJlcnJvclwiLCByZWplY3QpO1xuICAgICAgICByZXNvbHZlKCk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBjb25zdCBhZGRyZXNzID0gc2VydmVyLmFkZHJlc3MoKTtcbiAgICBpZiAoIWFkZHJlc3MgfHwgdHlwZW9mIGFkZHJlc3MgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkxha2ViYXNlIGxpc3RlbmVyIGhhcyBubyBhZGRyZXNzXCIpO1xuICAgIH1cbiAgICBsb2dnZXIuaW5mbyhcIkxha2ViYXNlIHByb3h5IGxpc3RlbmluZ1wiLCB7IGhvc3Q6IGFkZHJlc3MuYWRkcmVzcywgcG9ydDogYWRkcmVzcy5wb3J0IH0pO1xuICAgIHJldHVybiB7IGhvc3Q6IGFkZHJlc3MuYWRkcmVzcywgcG9ydDogYWRkcmVzcy5wb3J0IH07XG4gIH1cblxuICBhc3luYyBjbG9zZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBzZXJ2ZXIgPSB0aGlzLnNlcnZlcjtcbiAgICB0aGlzLnNlcnZlciA9IHVuZGVmaW5lZDtcbiAgICBpZiAodGhpcy5zdGF0c1RpbWVyKSBjbGVhckludGVydmFsKHRoaXMuc3RhdHNUaW1lcik7XG4gICAgdGhpcy5zdGF0c1RpbWVyID0gdW5kZWZpbmVkO1xuICAgIGlmICghc2VydmVyKSByZXR1cm47XG4gICAgYXdhaXQgbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUsIHJlamVjdCkgPT5cbiAgICAgIHNlcnZlci5jbG9zZSgoZXJyb3IpID0+IChlcnJvciA/IHJlamVjdChlcnJvcikgOiByZXNvbHZlKCkpKSxcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBoYW5kbGUobG9jYWw6IFNvY2tldCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHN0YXJ0ZWQgPSBEYXRlLm5vdygpO1xuICAgIGxldCB1cHN0cmVhbTogRHVwbGV4IHwgdW5kZWZpbmVkO1xuICAgIGxldCBjYW5jZWxsYXRpb246IENhbmNlbE1lc3NhZ2UgfCB1bmRlZmluZWQ7XG4gICAgdGhpcy5vcGVuZWQgKz0gMTtcbiAgICB0aGlzLmFjdGl2ZSArPSAxO1xuICAgIHRyeSB7XG4gICAgICBsb2NhbC5zZXROb0RlbGF5KHRydWUpO1xuICAgICAgY29uc3QgaW5pdGlhbCA9IGF3YWl0IHJlYWRJbml0aWFsTWVzc2FnZShsb2NhbCwgdGhpcy5vcHRpb25zLnN0YXJ0dXBUaW1lb3V0U2Vjb25kcyAqIDEwMDApO1xuICAgICAgaWYgKGluaXRpYWwua2luZCA9PT0gXCJjYW5jZWxcIikge1xuICAgICAgICBhd2FpdCB0aGlzLmNhbmNlbGxhdGlvbnMuZm9yd2FyZChpbml0aWFsKTtcbiAgICAgICAgbG9jYWwuZW5kKCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHN0YXJ0dXAgPSBpbml0aWFsO1xuICAgICAgY29uc3QgdGFyZ2V0VGV4dCA9IHN0YXJ0dXAucGFyYW1ldGVycy5kYXRhYmFzZTtcbiAgICAgIGlmICghdGFyZ2V0VGV4dCkgdGhyb3cgbmV3IFByb3h5RmFpbHVyZShcInN0YXJ0dXAgZGF0YWJhc2UgaXMgcmVxdWlyZWRcIiwgXCIzRDAwMFwiKTtcbiAgICAgIGxldCB0YXJnZXQ7XG4gICAgICB0cnkge1xuICAgICAgICB0YXJnZXQgPSByZXF1aXJlQWRkcmVzcyh0YXJnZXRUZXh0KTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIHRocm93IG5ldyBQcm94eUZhaWx1cmUobWVzc2FnZShlcnJvciksIFwiM0QwMDBcIik7XG4gICAgICB9XG4gICAgICBjb25zdCBzdGFydHVwVXNlciA9IHN0cmluZ1V0aWxzLnRyaW1Ub1VuZGVmaW5lZChzdGFydHVwLnBhcmFtZXRlcnMudXNlcik7XG4gICAgICBsZXQgcmVzb2x2ZWQ7XG4gICAgICB0cnkge1xuICAgICAgICByZXNvbHZlZCA9IGF3YWl0IHRoaXMuY2xpZW50LnJlc29sdmUodGFyZ2V0LCBzdGFydHVwVXNlcik7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICB0aHJvdyBuZXcgUHJveHlGYWlsdXJlKG1lc3NhZ2UoZXJyb3IpLCBcIjNEMDAwXCIpO1xuICAgICAgfVxuICAgICAgbGV0IHBhc3N3b3JkO1xuICAgICAgdHJ5IHtcbiAgICAgICAgcGFzc3dvcmQgPSBhd2FpdCB0aGlzLmNsaWVudC5nZW5lcmF0ZURhdGFiYXNlQ3JlZGVudGlhbChyZXNvbHZlZC5lbmRwb2ludCwgc3RhcnR1cFVzZXIpO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgdGhyb3cgbmV3IFByb3h5RmFpbHVyZShtZXNzYWdlKGVycm9yKSwgXCIyODAwMFwiKTtcbiAgICAgIH1cbiAgICAgIGxldCBjb25uZWN0ZWQ7XG4gICAgICB0cnkge1xuICAgICAgICBjb25uZWN0ZWQgPSBhd2FpdCBjb25uZWN0VXBzdHJlYW0oXG4gICAgICAgICAgcmVzb2x2ZWQsXG4gICAgICAgICAgcGFzc3dvcmQsXG4gICAgICAgICAgcG9zdGdyZXNDb25uZWN0aW9uT3B0aW9ucyhzdGFydHVwLnBhcmFtZXRlcnMsIHRoaXMub3B0aW9ucy5wb3N0Z3Jlc1JvbGUpLFxuICAgICAgICApO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgdGhyb3cgbmV3IFByb3h5RmFpbHVyZShtZXNzYWdlKGVycm9yKSwgXCIwODAwMVwiKTtcbiAgICAgIH1cbiAgICAgIHVwc3RyZWFtID0gY29ubmVjdGVkLnNvY2tldDtcbiAgICAgIGNhbmNlbGxhdGlvbiA9IHRoaXMuY2FuY2VsbGF0aW9ucy5yZWdpc3Rlcih7XG4gICAgICAgIGhvc3Q6IHJlc29sdmVkLmhvc3QsXG4gICAgICAgIHBvcnQ6IHJlc29sdmVkLnBvcnQsXG4gICAgICAgIHByb2Nlc3NJZDogY29ubmVjdGVkLnByb2Nlc3NJZCxcbiAgICAgICAgc2VjcmV0S2V5OiBjb25uZWN0ZWQuc2VjcmV0S2V5LFxuICAgICAgfSk7XG4gICAgICBsb2NhbC53cml0ZShcbiAgICAgICAgc3RhcnR1cENvbXBsZXRlKFxuICAgICAgICAgIGNvbm5lY3RlZC5wYXJhbWV0ZXJzLFxuICAgICAgICAgIGNhbmNlbGxhdGlvbi5wcm9jZXNzSWQsXG4gICAgICAgICAgY2FuY2VsbGF0aW9uLnNlY3JldEtleSxcbiAgICAgICAgICBjb25uZWN0ZWQudHJhbnNhY3Rpb25TdGF0dXMsXG4gICAgICAgICksXG4gICAgICApO1xuICAgICAgbG9jYWwucGlwZSh1cHN0cmVhbSkucGlwZShsb2NhbCk7XG4gICAgICBhd2FpdCBQcm9taXNlLnJhY2UoW2Nsb3NlZChsb2NhbCksIGNsb3NlZCh1cHN0cmVhbSldKTtcbiAgICAgIGxvZ2dlci5kZWJ1ZyhcIkxha2ViYXNlIGNvbm5lY3Rpb24gY2xvc2VkXCIsIHtcbiAgICAgICAgZHVyYXRpb25NczogRGF0ZS5ub3coKSAtIHN0YXJ0ZWQsXG4gICAgICAgIHByb2plY3Q6IHJlc29sdmVkLnByb2plY3QsXG4gICAgICAgIGJyYW5jaDogcmVzb2x2ZWQuYnJhbmNoLFxuICAgICAgICBlbmRwb2ludDogcmVzb2x2ZWQuZW5kcG9pbnQsXG4gICAgICB9KTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhpcy5mYWlsZWQgKz0gMTtcbiAgICAgIGNvbnN0IGZhaWx1cmUgPVxuICAgICAgICBlcnJvciBpbnN0YW5jZW9mIFByb3h5RmFpbHVyZVxuICAgICAgICAgID8gZXJyb3JcbiAgICAgICAgICA6IGVycm9yIGluc3RhbmNlb2YgUG9zdGdyZXNQcm90b2NvbEVycm9yXG4gICAgICAgICAgICA/IG5ldyBQcm94eUZhaWx1cmUoZXJyb3IubWVzc2FnZSwgXCIwOFAwMVwiKVxuICAgICAgICAgICAgOiBuZXcgUHJveHlGYWlsdXJlKG1lc3NhZ2UoZXJyb3IpKTtcbiAgICAgIGxvZ2dlci53YXJuKFwiTGFrZWJhc2UgY29ubmVjdGlvbiBmYWlsZWRcIiwge1xuICAgICAgICBkdXJhdGlvbk1zOiBEYXRlLm5vdygpIC0gc3RhcnRlZCxcbiAgICAgICAgZXJyb3I6IGZhaWx1cmUubWVzc2FnZSxcbiAgICAgIH0pO1xuICAgICAgaWYgKCFsb2NhbC5kZXN0cm95ZWQpIGxvY2FsLmVuZChmYXRhbEVycm9yKGZhaWx1cmUubWVzc2FnZSwgZmFpbHVyZS5zcWxzdGF0ZSkpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBpZiAoY2FuY2VsbGF0aW9uKSB0aGlzLmNhbmNlbGxhdGlvbnMucmVtb3ZlKGNhbmNlbGxhdGlvbik7XG4gICAgICB1cHN0cmVhbT8uZGVzdHJveSgpO1xuICAgICAgbG9jYWwuZGVzdHJveSgpO1xuICAgICAgdGhpcy5jbG9zZWQgKz0gMTtcbiAgICAgIHRoaXMuYWN0aXZlIC09IDE7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSByZXBvcnRTdGF0cygpOiB2b2lkIHtcbiAgICBsb2dnZXIuaW5mbyhcIkxha2ViYXNlIHByb3h5IGNvbm5lY3Rpb25zXCIsIHtcbiAgICAgIG9wZW5lZDogdGhpcy5vcGVuZWQsXG4gICAgICBjbG9zZWQ6IHRoaXMuY2xvc2VkLFxuICAgICAgZmFpbGVkOiB0aGlzLmZhaWxlZCxcbiAgICAgIGFjdGl2ZTogdGhpcy5hY3RpdmUsXG4gICAgfSk7XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gY29ubmVjdFVwc3RyZWFtKFxuICByZXNvbHZlZDogQXdhaXRlZDxSZXR1cm5UeXBlPExha2ViYXNlQ2xpZW50W1wicmVzb2x2ZVwiXT4+LFxuICBwYXNzd29yZDogc3RyaW5nLFxuICBzdGFydHVwOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+LFxuKTogUHJvbWlzZTx7XG4gIHNvY2tldDogRHVwbGV4O1xuICBwYXJhbWV0ZXJzOiBNYXA8c3RyaW5nLCBzdHJpbmc+O1xuICBwcm9jZXNzSWQ6IG51bWJlcjtcbiAgc2VjcmV0S2V5OiBudW1iZXI7XG4gIHRyYW5zYWN0aW9uU3RhdHVzOiBzdHJpbmc7XG59PiB7XG4gIGNvbnN0IGNsaWVudCA9IG5ldyBDbGllbnQoe1xuICAgIGhvc3Q6IHJlc29sdmVkLmhvc3QsXG4gICAgcG9ydDogcmVzb2x2ZWQucG9ydCxcbiAgICBkYXRhYmFzZTogcmVzb2x2ZWQuZGF0YWJhc2UsXG4gICAgdXNlcjogcmVzb2x2ZWQudXNlcixcbiAgICBwYXNzd29yZCxcbiAgICBzc2w6IHsgcmVqZWN0VW5hdXRob3JpemVkOiB0cnVlLCBzZXJ2ZXJuYW1lOiByZXNvbHZlZC5ob3N0IH0sXG4gICAgYXBwbGljYXRpb25fbmFtZTogc3RhcnR1cC5hcHBsaWNhdGlvbl9uYW1lLFxuICAgIGNvbm5lY3Rpb25UaW1lb3V0TWlsbGlzOiAzMF8wMDAsXG4gIH0pIGFzIHVua25vd24gYXMgUGdDbGllbnRJbnRlcm5hbHM7XG4gIGNvbnN0IHBhcmFtZXRlcnMgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nPigpO1xuICBjbGllbnQuZ2V0U3RhcnR1cENvbmYgPSAoKSA9PlxuICAgIHVwc3RyZWFtU3RhcnR1cFBhcmFtZXRlcnMoc3RhcnR1cCwgcmVzb2x2ZWQudXNlciwgcmVzb2x2ZWQuZGF0YWJhc2UpO1xuICBjbGllbnQub24oXCJlcnJvclwiLCAoZXJyb3IpID0+IHtcbiAgICBsb2dnZXIuZGVidWcoXCJMYWtlYmFzZSB1cHN0cmVhbSBjbGllbnQgY2xvc2VkXCIsIHsgZXJyb3I6IGVycm9yLm1lc3NhZ2UgfSk7XG4gIH0pO1xuICBjbGllbnQuY29ubmVjdGlvbi5vbihcInBhcmFtZXRlclN0YXR1c1wiLCAobWVzc2FnZSkgPT4ge1xuICAgIHBhcmFtZXRlcnMuc2V0KG1lc3NhZ2UucGFyYW1ldGVyTmFtZSwgbWVzc2FnZS5wYXJhbWV0ZXJWYWx1ZSk7XG4gIH0pO1xuICBhd2FpdCBjbGllbnQuY29ubmVjdCgpO1xuICBjb25zdCBzb2NrZXQgPSBjbGllbnQuY29ubmVjdGlvbi5zdHJlYW07XG4gIHNvY2tldC5yZW1vdmVBbGxMaXN0ZW5lcnMoXCJkYXRhXCIpO1xuICByZXR1cm4ge1xuICAgIHNvY2tldCxcbiAgICBwYXJhbWV0ZXJzLFxuICAgIHByb2Nlc3NJZDogY2xpZW50LnByb2Nlc3NJRCxcbiAgICBzZWNyZXRLZXk6IGNsaWVudC5zZWNyZXRLZXksXG4gICAgdHJhbnNhY3Rpb25TdGF0dXM6IGNsaWVudC5fdHhTdGF0dXMgPz8gXCJJXCIsXG4gIH07XG59XG5cbmZ1bmN0aW9uIGNsb3NlZChzb2NrZXQ6IER1cGxleCk6IFByb21pc2U8dm9pZD4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIHNvY2tldC5vbmNlKFwiY2xvc2VcIiwgKCkgPT4gcmVzb2x2ZSgpKTtcbiAgICBzb2NrZXQub25jZShcImVycm9yXCIsIHJlamVjdCk7XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBtZXNzYWdlKGVycm9yOiB1bmtub3duKTogc3RyaW5nIHtcbiAgcmV0dXJuIGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKTtcbn1cblxuY2xhc3MgUHJveHlGYWlsdXJlIGV4dGVuZHMgRXJyb3Ige1xuICBjb25zdHJ1Y3RvcihcbiAgICBtZXNzYWdlOiBzdHJpbmcsXG4gICAgcmVhZG9ubHkgc3Fsc3RhdGUgPSBcIjA4MDAxXCIsXG4gICkge1xuICAgIHN1cGVyKG1lc3NhZ2UpO1xuICB9XG59XG4iXX0=
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Foreground `dbx model-gateway` command.
3
+ *
4
+ * @module
5
+ */
6
+ import { type CliServiceCliDependencies } from "@dbx-tools/cli-service/cli";
7
+ import { type CliServiceDefinition } from "@dbx-tools/cli-service/definition";
8
+ import { type ModelGatewayOptions } from "@dbx-tools/shared-model-gateway/options";
9
+ import { Command } from "commander";
10
+ /** Injectable foreground gateway boundary for CLI tests. */
11
+ export interface ModelGatewayCliDependencies {
12
+ start(options: ModelGatewayOptions): Promise<void>;
13
+ /** Optional service CLI boundary for tests and embedding. */
14
+ readonly service?: CliServiceCliDependencies;
15
+ }
16
+ /** Build the tray-only model-gateway service definition. */
17
+ export declare function modelGatewayServiceDefinition(options?: ModelGatewayOptions): CliServiceDefinition;
18
+ /** Build foreground and service model-gateway commands without starting a server. */
19
+ export declare function buildProgram(name?: string, dependencies?: ModelGatewayCliDependencies): Command;
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Foreground `dbx model-gateway` command.
3
+ *
4
+ * @module
5
+ */
6
+ import { addArgs, parseArgs, serializeArgs } from "@dbx-tools/cli-args";
7
+ import { buildServiceCommand } from "@dbx-tools/cli-service/cli";
8
+ import { defineService } from "@dbx-tools/cli-service/definition";
9
+ import { ModelGatewayCliOptionsSchema, resolveModelGatewayCliOptions, } from "@dbx-tools/shared-model-gateway/options";
10
+ import { Command } from "commander";
11
+ import { startModelGateway } from "./server.js";
12
+ import { PACKAGE_VERSION } from "../../index.js";
13
+ const DEFAULT_DEPENDENCIES = {
14
+ start: startModelGateway,
15
+ };
16
+ /** Build the tray-only model-gateway service definition. */
17
+ export function modelGatewayServiceDefinition(options = {}) {
18
+ const { runtimeInfo: _, bearerToken: _bearerToken, ...resolved } = resolveModelGatewayCliOptions(options);
19
+ const host = urlHost(resolved.listen.host);
20
+ return defineService(import.meta.url, {
21
+ id: "dbx-tools.cli-model-gateway",
22
+ name: "dbx model gateway",
23
+ command: {
24
+ binName: "dbx-model-gateway",
25
+ arguments: serializeArgs(resolved),
26
+ },
27
+ menu: [
28
+ {
29
+ type: "url",
30
+ label: "Models",
31
+ url: `http://${host}:${resolved.listen.port}/v1/models`,
32
+ },
33
+ ],
34
+ });
35
+ }
36
+ /** Build foreground and service model-gateway commands without starting a server. */
37
+ export function buildProgram(name = "dbx model-gateway", dependencies = DEFAULT_DEPENDENCIES) {
38
+ const version = PACKAGE_VERSION;
39
+ const program = addArgs(new Command()
40
+ .name(name)
41
+ .description("Run or manage the AppKit Databricks model gateway")
42
+ .version(version, "-v, --version"), ModelGatewayCliOptionsSchema).action(async () => {
43
+ const options = modelGatewayOptions(program);
44
+ if (options.runtimeInfo) {
45
+ process.stdout.write(`${JSON.stringify({ implementation: "typescript-appkit", version })}\n`);
46
+ return;
47
+ }
48
+ const { runtimeInfo: _, ...serverOptions } = options;
49
+ await dependencies.start(serverOptions);
50
+ });
51
+ const serviceCommand = buildServiceCommand(() => {
52
+ return modelGatewayServiceDefinition(modelGatewayOptions(program));
53
+ }, dependencies.service);
54
+ program.addCommand(serviceCommand);
55
+ return program;
56
+ }
57
+ function modelGatewayOptions(command) {
58
+ return parseArgs(command, ModelGatewayCliOptionsSchema);
59
+ }
60
+ function urlHost(host) {
61
+ return host.includes(":") ? `[${host}]` : host;
62
+ }
63
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL21vZGVsLWdhdGV3YXkvY2xpLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7O0dBSUc7QUFFSCxPQUFPLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxhQUFhLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN4RSxPQUFPLEVBQUUsbUJBQW1CLEVBQWtDLE1BQU0sNEJBQTRCLENBQUM7QUFDakcsT0FBTyxFQUFFLGFBQWEsRUFBNkIsTUFBTSxtQ0FBbUMsQ0FBQztBQUM3RixPQUFPLEVBQ0wsNEJBQTRCLEVBQzVCLDZCQUE2QixHQUc5QixNQUFNLHlDQUF5QyxDQUFDO0FBQ2pELE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFFcEMsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ2hELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQVNqRCxNQUFNLG9CQUFvQixHQUFnQztJQUN4RCxLQUFLLEVBQUUsaUJBQWlCO0NBQ3pCLENBQUM7QUFFRiw0REFBNEQ7QUFDNUQsTUFBTSxVQUFVLDZCQUE2QixDQUMzQyxVQUErQixFQUFFO0lBRWpDLE1BQU0sRUFDSixXQUFXLEVBQUUsQ0FBQyxFQUNkLFdBQVcsRUFBRSxZQUFZLEVBQ3pCLEdBQUcsUUFBUSxFQUNaLEdBQUcsNkJBQTZCLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDM0MsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDM0MsT0FBTyxhQUFhLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUU7UUFDcEMsRUFBRSxFQUFFLDZCQUE2QjtRQUNqQyxJQUFJLEVBQUUsbUJBQW1CO1FBQ3pCLE9BQU8sRUFBRTtZQUNQLE9BQU8sRUFBRSxtQkFBbUI7WUFDNUIsU0FBUyxFQUFFLGFBQWEsQ0FBQyxRQUFRLENBQUM7U0FDbkM7UUFDRCxJQUFJLEVBQUU7WUFDSjtnQkFDRSxJQUFJLEVBQUUsS0FBSztnQkFDWCxLQUFLLEVBQUUsUUFBUTtnQkFDZixHQUFHLEVBQUUsVUFBVSxJQUFJLElBQUksUUFBUSxDQUFDLE1BQU0sQ0FBQyxJQUFJLFlBQVk7YUFDeEQ7U0FDRjtLQUNGLENBQUMsQ0FBQztBQUNMLENBQUM7QUFFRCxxRkFBcUY7QUFDckYsTUFBTSxVQUFVLFlBQVksQ0FDMUIsSUFBSSxHQUFHLG1CQUFtQixFQUMxQixlQUE0QyxvQkFBb0I7SUFFaEUsTUFBTSxPQUFPLEdBQUcsZUFBZSxDQUFDO0lBQ2hDLE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FDckIsSUFBSSxPQUFPLEVBQUU7U0FDVixJQUFJLENBQUMsSUFBSSxDQUFDO1NBQ1YsV0FBVyxDQUFDLG1EQUFtRCxDQUFDO1NBQ2hFLE9BQU8sQ0FBQyxPQUFPLEVBQUUsZUFBZSxDQUFDLEVBQ3BDLDRCQUE0QixDQUM3QixDQUFDLE1BQU0sQ0FBQyxLQUFLLElBQUksRUFBRTtRQUNsQixNQUFNLE9BQU8sR0FBRyxtQkFBbUIsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM3QyxJQUFJLE9BQU8sQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUN4QixPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxjQUFjLEVBQUUsbUJBQW1CLEVBQUUsT0FBTyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDOUYsT0FBTztRQUNULENBQUM7UUFDRCxNQUFNLEVBQUUsV0FBVyxFQUFFLENBQUMsRUFBRSxHQUFHLGFBQWEsRUFBRSxHQUFHLE9BQU8sQ0FBQztRQUNyRCxNQUFNLFlBQVksQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLENBQUM7SUFDMUMsQ0FBQyxDQUFDLENBQUM7SUFDSCxNQUFNLGNBQWMsR0FBRyxtQkFBbUIsQ0FBQyxHQUFHLEVBQUU7UUFDOUMsT0FBTyw2QkFBNkIsQ0FBQyxtQkFBbUIsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQ3JFLENBQUMsRUFBRSxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDekIsT0FBTyxDQUFDLFVBQVUsQ0FBQyxjQUFjLENBQUMsQ0FBQztJQUNuQyxPQUFPLE9BQU8sQ0FBQztBQUNqQixDQUFDO0FBRUQsU0FBUyxtQkFBbUIsQ0FBQyxPQUFnQjtJQUMzQyxPQUFPLFNBQVMsQ0FBQyxPQUFPLEVBQUUsNEJBQTRCLENBQUMsQ0FBQztBQUMxRCxDQUFDO0FBRUQsU0FBUyxPQUFPLENBQUMsSUFBWTtJQUMzQixPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksSUFBSSxHQUFHLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztBQUNqRCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBGb3JlZ3JvdW5kIGBkYnggbW9kZWwtZ2F0ZXdheWAgY29tbWFuZC5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgYWRkQXJncywgcGFyc2VBcmdzLCBzZXJpYWxpemVBcmdzIH0gZnJvbSBcIkBkYngtdG9vbHMvY2xpLWFyZ3NcIjtcbmltcG9ydCB7IGJ1aWxkU2VydmljZUNvbW1hbmQsIHR5cGUgQ2xpU2VydmljZUNsaURlcGVuZGVuY2llcyB9IGZyb20gXCJAZGJ4LXRvb2xzL2NsaS1zZXJ2aWNlL2NsaVwiO1xuaW1wb3J0IHsgZGVmaW5lU2VydmljZSwgdHlwZSBDbGlTZXJ2aWNlRGVmaW5pdGlvbiB9IGZyb20gXCJAZGJ4LXRvb2xzL2NsaS1zZXJ2aWNlL2RlZmluaXRpb25cIjtcbmltcG9ydCB7XG4gIE1vZGVsR2F0ZXdheUNsaU9wdGlvbnNTY2hlbWEsXG4gIHJlc29sdmVNb2RlbEdhdGV3YXlDbGlPcHRpb25zLFxuICB0eXBlIE1vZGVsR2F0ZXdheUNsaU9wdGlvbnMsXG4gIHR5cGUgTW9kZWxHYXRld2F5T3B0aW9ucyxcbn0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLW1vZGVsLWdhdGV3YXkvb3B0aW9uc1wiO1xuaW1wb3J0IHsgQ29tbWFuZCB9IGZyb20gXCJjb21tYW5kZXJcIjtcblxuaW1wb3J0IHsgc3RhcnRNb2RlbEdhdGV3YXkgfSBmcm9tIFwiLi9zZXJ2ZXIudHNcIjtcbmltcG9ydCB7IFBBQ0tBR0VfVkVSU0lPTiB9IGZyb20gXCIuLi8uLi9pbmRleC50c1wiO1xuXG4vKiogSW5qZWN0YWJsZSBmb3JlZ3JvdW5kIGdhdGV3YXkgYm91bmRhcnkgZm9yIENMSSB0ZXN0cy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTW9kZWxHYXRld2F5Q2xpRGVwZW5kZW5jaWVzIHtcbiAgc3RhcnQob3B0aW9uczogTW9kZWxHYXRld2F5T3B0aW9ucyk6IFByb21pc2U8dm9pZD47XG4gIC8qKiBPcHRpb25hbCBzZXJ2aWNlIENMSSBib3VuZGFyeSBmb3IgdGVzdHMgYW5kIGVtYmVkZGluZy4gKi9cbiAgcmVhZG9ubHkgc2VydmljZT86IENsaVNlcnZpY2VDbGlEZXBlbmRlbmNpZXM7XG59XG5cbmNvbnN0IERFRkFVTFRfREVQRU5ERU5DSUVTOiBNb2RlbEdhdGV3YXlDbGlEZXBlbmRlbmNpZXMgPSB7XG4gIHN0YXJ0OiBzdGFydE1vZGVsR2F0ZXdheSxcbn07XG5cbi8qKiBCdWlsZCB0aGUgdHJheS1vbmx5IG1vZGVsLWdhdGV3YXkgc2VydmljZSBkZWZpbml0aW9uLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1vZGVsR2F0ZXdheVNlcnZpY2VEZWZpbml0aW9uKFxuICBvcHRpb25zOiBNb2RlbEdhdGV3YXlPcHRpb25zID0ge30sXG4pOiBDbGlTZXJ2aWNlRGVmaW5pdGlvbiB7XG4gIGNvbnN0IHtcbiAgICBydW50aW1lSW5mbzogXyxcbiAgICBiZWFyZXJUb2tlbjogX2JlYXJlclRva2VuLFxuICAgIC4uLnJlc29sdmVkXG4gIH0gPSByZXNvbHZlTW9kZWxHYXRld2F5Q2xpT3B0aW9ucyhvcHRpb25zKTtcbiAgY29uc3QgaG9zdCA9IHVybEhvc3QocmVzb2x2ZWQubGlzdGVuLmhvc3QpO1xuICByZXR1cm4gZGVmaW5lU2VydmljZShpbXBvcnQubWV0YS51cmwsIHtcbiAgICBpZDogXCJkYngtdG9vbHMuY2xpLW1vZGVsLWdhdGV3YXlcIixcbiAgICBuYW1lOiBcImRieCBtb2RlbCBnYXRld2F5XCIsXG4gICAgY29tbWFuZDoge1xuICAgICAgYmluTmFtZTogXCJkYngtbW9kZWwtZ2F0ZXdheVwiLFxuICAgICAgYXJndW1lbnRzOiBzZXJpYWxpemVBcmdzKHJlc29sdmVkKSxcbiAgICB9LFxuICAgIG1lbnU6IFtcbiAgICAgIHtcbiAgICAgICAgdHlwZTogXCJ1cmxcIixcbiAgICAgICAgbGFiZWw6IFwiTW9kZWxzXCIsXG4gICAgICAgIHVybDogYGh0dHA6Ly8ke2hvc3R9OiR7cmVzb2x2ZWQubGlzdGVuLnBvcnR9L3YxL21vZGVsc2AsXG4gICAgICB9LFxuICAgIF0sXG4gIH0pO1xufVxuXG4vKiogQnVpbGQgZm9yZWdyb3VuZCBhbmQgc2VydmljZSBtb2RlbC1nYXRld2F5IGNvbW1hbmRzIHdpdGhvdXQgc3RhcnRpbmcgYSBzZXJ2ZXIuICovXG5leHBvcnQgZnVuY3Rpb24gYnVpbGRQcm9ncmFtKFxuICBuYW1lID0gXCJkYnggbW9kZWwtZ2F0ZXdheVwiLFxuICBkZXBlbmRlbmNpZXM6IE1vZGVsR2F0ZXdheUNsaURlcGVuZGVuY2llcyA9IERFRkFVTFRfREVQRU5ERU5DSUVTLFxuKTogQ29tbWFuZCB7XG4gIGNvbnN0IHZlcnNpb24gPSBQQUNLQUdFX1ZFUlNJT047XG4gIGNvbnN0IHByb2dyYW0gPSBhZGRBcmdzKFxuICAgIG5ldyBDb21tYW5kKClcbiAgICAgIC5uYW1lKG5hbWUpXG4gICAgICAuZGVzY3JpcHRpb24oXCJSdW4gb3IgbWFuYWdlIHRoZSBBcHBLaXQgRGF0YWJyaWNrcyBtb2RlbCBnYXRld2F5XCIpXG4gICAgICAudmVyc2lvbih2ZXJzaW9uLCBcIi12LCAtLXZlcnNpb25cIiksXG4gICAgTW9kZWxHYXRld2F5Q2xpT3B0aW9uc1NjaGVtYSxcbiAgKS5hY3Rpb24oYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IG9wdGlvbnMgPSBtb2RlbEdhdGV3YXlPcHRpb25zKHByb2dyYW0pO1xuICAgIGlmIChvcHRpb25zLnJ1bnRpbWVJbmZvKSB7XG4gICAgICBwcm9jZXNzLnN0ZG91dC53cml0ZShgJHtKU09OLnN0cmluZ2lmeSh7IGltcGxlbWVudGF0aW9uOiBcInR5cGVzY3JpcHQtYXBwa2l0XCIsIHZlcnNpb24gfSl9XFxuYCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IHsgcnVudGltZUluZm86IF8sIC4uLnNlcnZlck9wdGlvbnMgfSA9IG9wdGlvbnM7XG4gICAgYXdhaXQgZGVwZW5kZW5jaWVzLnN0YXJ0KHNlcnZlck9wdGlvbnMpO1xuICB9KTtcbiAgY29uc3Qgc2VydmljZUNvbW1hbmQgPSBidWlsZFNlcnZpY2VDb21tYW5kKCgpID0+IHtcbiAgICByZXR1cm4gbW9kZWxHYXRld2F5U2VydmljZURlZmluaXRpb24obW9kZWxHYXRld2F5T3B0aW9ucyhwcm9ncmFtKSk7XG4gIH0sIGRlcGVuZGVuY2llcy5zZXJ2aWNlKTtcbiAgcHJvZ3JhbS5hZGRDb21tYW5kKHNlcnZpY2VDb21tYW5kKTtcbiAgcmV0dXJuIHByb2dyYW07XG59XG5cbmZ1bmN0aW9uIG1vZGVsR2F0ZXdheU9wdGlvbnMoY29tbWFuZDogQ29tbWFuZCk6IE1vZGVsR2F0ZXdheUNsaU9wdGlvbnMge1xuICByZXR1cm4gcGFyc2VBcmdzKGNvbW1hbmQsIE1vZGVsR2F0ZXdheUNsaU9wdGlvbnNTY2hlbWEpO1xufVxuXG5mdW5jdGlvbiB1cmxIb3N0KGhvc3Q6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBob3N0LmluY2x1ZGVzKFwiOlwiKSA/IGBbJHtob3N0fV1gIDogaG9zdDtcbn1cbiJdfQ==
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Foreground model-gateway server owned by the CLI package.
3
+ *
4
+ * @module
5
+ */
6
+ import { server } from "@databricks/appkit";
7
+ import { type ModelGatewayOptions } from "@dbx-tools/shared-model-gateway/options";
8
+ import type express from "express";
9
+ type AppKitServerOptions = NonNullable<Parameters<typeof server>[0]>;
10
+ /** Resolve AppKit server settings for the loopback model gateway. */
11
+ export declare function modelGatewayServerOptions(options?: ModelGatewayOptions): AppKitServerOptions;
12
+ /** Require one bearer token without retaining or logging request credentials. */
13
+ export declare function gatewayBearerMiddleware(token: string): express.RequestHandler;
14
+ /** Start the foreground model gateway and keep its AppKit server active. */
15
+ export declare function startModelGateway(options?: ModelGatewayOptions): Promise<void>;
16
+ export {};
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Foreground model-gateway server owned by the CLI package.
3
+ *
4
+ * @module
5
+ */
6
+ import { createHash, timingSafeEqual } from "node:crypto";
7
+ import { createApp, server } from "@databricks/appkit";
8
+ import { ModelGateway } from "@dbx-tools/appkit-model-gateway";
9
+ import { sendHealth, sendInference, sendModels } from "@dbx-tools/appkit-model-gateway/routes";
10
+ import { workspaceClient } from "@dbx-tools/databricks";
11
+ import { resolveModelGatewayOptions, } from "@dbx-tools/shared-model-gateway/options";
12
+ /** Resolve AppKit server settings for the loopback model gateway. */
13
+ export function modelGatewayServerOptions(options = {}) {
14
+ return appKitServerOptions(resolveModelGatewayOptions(options));
15
+ }
16
+ function appKitServerOptions(options) {
17
+ return {
18
+ bodyLimit: options.bodyLimit,
19
+ host: options.listen.host,
20
+ port: options.listen.port,
21
+ };
22
+ }
23
+ /** Require one bearer token without retaining or logging request credentials. */
24
+ export function gatewayBearerMiddleware(token) {
25
+ const expected = createHash("sha256").update(token).digest();
26
+ return (request, response, next) => {
27
+ const authorization = request.header("authorization");
28
+ const match = /^Bearer\s+(.+)$/i.exec(authorization ?? "");
29
+ const actual = createHash("sha256")
30
+ .update(match?.[1] ?? "")
31
+ .digest();
32
+ if (match && timingSafeEqual(actual, expected)) {
33
+ next();
34
+ return;
35
+ }
36
+ response
37
+ .status(401)
38
+ .setHeader("www-authenticate", "Bearer")
39
+ .json({
40
+ error: {
41
+ message: "Invalid or missing model-gateway bearer token.",
42
+ type: "authentication_error",
43
+ code: "invalid_bearer_token",
44
+ },
45
+ });
46
+ };
47
+ }
48
+ /** Start the foreground model gateway and keep its AppKit server active. */
49
+ export async function startModelGateway(options = {}) {
50
+ const resolved = resolveModelGatewayOptions(options);
51
+ const gateway = new ModelGateway();
52
+ const client = await workspaceClient.createWorkspaceClient({
53
+ ...(resolved.profile ? { profile: resolved.profile } : {}),
54
+ });
55
+ await createApp({
56
+ client,
57
+ plugins: [server(appKitServerOptions(resolved))],
58
+ onPluginsReady(appkit) {
59
+ appkit.server.extend((application) => {
60
+ if (resolved.bearerToken) {
61
+ application.use(gatewayBearerMiddleware(resolved.bearerToken));
62
+ }
63
+ application.get("/api/healthz", (_request, response) => {
64
+ sendHealth(response);
65
+ });
66
+ application.get("/v1/models", (request, response) => {
67
+ void sendModels(gateway, request, response);
68
+ });
69
+ for (const [path, protocol] of [
70
+ ["/v1/chat/completions", "openai-chat"],
71
+ ["/v1/responses", "openai-responses"],
72
+ ["/v1/messages", "anthropic-messages"],
73
+ ["/v1/embeddings", "openai-embeddings"],
74
+ ]) {
75
+ application.post(path, (request, response) => {
76
+ void sendInference(gateway, protocol, request, response);
77
+ });
78
+ }
79
+ });
80
+ },
81
+ });
82
+ }
83
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL21vZGVsLWdhdGV3YXkvc2VydmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7O0dBSUc7QUFFSCxPQUFPLEVBQUUsVUFBVSxFQUFFLGVBQWUsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUMxRCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUMvRCxPQUFPLEVBQUUsVUFBVSxFQUFFLGFBQWEsRUFBRSxVQUFVLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQztBQUMvRixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDeEQsT0FBTyxFQUNMLDBCQUEwQixHQUczQixNQUFNLHlDQUF5QyxDQUFDO0FBS2pELHFFQUFxRTtBQUNyRSxNQUFNLFVBQVUseUJBQXlCLENBQUMsVUFBK0IsRUFBRTtJQUN6RSxPQUFPLG1CQUFtQixDQUFDLDBCQUEwQixDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUM7QUFDbEUsQ0FBQztBQUVELFNBQVMsbUJBQW1CLENBQUMsT0FBb0M7SUFDL0QsT0FBTztRQUNMLFNBQVMsRUFBRSxPQUFPLENBQUMsU0FBUztRQUM1QixJQUFJLEVBQUUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJO1FBQ3pCLElBQUksRUFBRSxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUk7S0FDMUIsQ0FBQztBQUNKLENBQUM7QUFFRCxpRkFBaUY7QUFDakYsTUFBTSxVQUFVLHVCQUF1QixDQUFDLEtBQWE7SUFDbkQsTUFBTSxRQUFRLEdBQUcsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQztJQUM3RCxPQUFPLENBQUMsT0FBTyxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUs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TCxDQUFDO1lBQ0gsQ0FBQyxDQUFDLENBQUM7UUFDTCxDQUFDO0tBQ0YsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRm9yZWdyb3VuZCBtb2RlbC1nYXRld2F5IHNlcnZlciBvd25lZCBieSB0aGUgQ0xJIHBhY2thZ2UuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IGNyZWF0ZUhhc2gsIHRpbWluZ1NhZmVFcXVhbCB9IGZyb20gXCJub2RlOmNyeXB0b1wiO1xuaW1wb3J0IHsgY3JlYXRlQXBwLCBzZXJ2ZXIgfSBmcm9tIFwiQGRhdGFicmlja3MvYXBwa2l0XCI7XG5pbXBvcnQgeyBNb2RlbEdhdGV3YXkgfSBmcm9tIFwiQGRieC10b29scy9hcHBraXQtbW9kZWwtZ2F0ZXdheVwiO1xuaW1wb3J0IHsgc2VuZEhlYWx0aCwgc2VuZEluZmVyZW5jZSwgc2VuZE1vZGVscyB9IGZyb20gXCJAZGJ4LXRvb2xzL2FwcGtpdC1tb2RlbC1nYXRld2F5L3JvdXRlc1wiO1xuaW1wb3J0IHsgd29ya3NwYWNlQ2xpZW50IH0gZnJvbSBcIkBkYngtdG9vbHMvZGF0YWJyaWNrc1wiO1xuaW1wb3J0IHtcbiAgcmVzb2x2ZU1vZGVsR2F0ZXdheU9wdGlvbnMsXG4gIHR5cGUgTW9kZWxHYXRld2F5T3B0aW9ucyxcbiAgdHlwZSBSZXNvbHZlZE1vZGVsR2F0ZXdheU9wdGlvbnMsXG59IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1tb2RlbC1nYXRld2F5L29wdGlvbnNcIjtcbmltcG9ydCB0eXBlIGV4cHJlc3MgZnJvbSBcImV4cHJlc3NcIjtcblxudHlwZSBBcHBLaXRTZXJ2ZXJPcHRpb25zID0gTm9uTnVsbGFibGU8UGFyYW1ldGVyczx0eXBlb2Ygc2VydmVyPlswXT47XG5cbi8qKiBSZXNvbHZlIEFwcEtpdCBzZXJ2ZXIgc2V0dGluZ3MgZm9yIHRoZSBsb29wYmFjayBtb2RlbCBnYXRld2F5LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1vZGVsR2F0ZXdheVNlcnZlck9wdGlvbnMob3B0aW9uczogTW9kZWxHYXRld2F5T3B0aW9ucyA9IHt9KTogQXBwS2l0U2VydmVyT3B0aW9ucyB7XG4gIHJldHVybiBhcHBLaXRTZXJ2ZXJPcHRpb25zKHJlc29sdmVNb2RlbEdhdGV3YXlPcHRpb25zKG9wdGlvbnMpKTtcbn1cblxuZnVuY3Rpb24gYXBwS2l0U2VydmVyT3B0aW9ucyhvcHRpb25zOiBSZXNvbHZlZE1vZGVsR2F0ZXdheU9wdGlvbnMpOiBBcHBLaXRTZXJ2ZXJPcHRpb25zIHtcbiAgcmV0dXJuIHtcbiAgICBib2R5TGltaXQ6IG9wdGlvbnMuYm9keUxpbWl0LFxuICAgIGhvc3Q6IG9wdGlvbnMubGlzdGVuLmhvc3QsXG4gICAgcG9ydDogb3B0aW9ucy5saXN0ZW4ucG9ydCxcbiAgfTtcbn1cblxuLyoqIFJlcXVpcmUgb25lIGJlYXJlciB0b2tlbiB3aXRob3V0IHJldGFpbmluZyBvciBsb2dnaW5nIHJlcXVlc3QgY3JlZGVudGlhbHMuICovXG5leHBvcnQgZnVuY3Rpb24gZ2F0ZXdheUJlYXJlck1pZGRsZXdhcmUodG9rZW46IHN0cmluZyk6IGV4cHJlc3MuUmVxdWVzdEhhbmRsZXIge1xuICBjb25zdCBleHBlY3RlZCA9IGNyZWF0ZUhhc2goXCJzaGEyNTZcIikudXBkYXRlKHRva2VuKS5kaWdlc3QoKTtcbiAgcmV0dXJuIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xuICAgIGNvbnN0IGF1dGhvcml6YXRpb24gPSByZXF1ZXN0LmhlYWRlcihcImF1dGhvcml6YXRpb25cIik7XG4gICAgY29uc3QgbWF0Y2ggPSAvXkJlYXJlclxccysoLispJC9pLmV4ZWMoYXV0aG9yaXphdGlvbiA/PyBcIlwiKTtcbiAgICBjb25zdCBhY3R1YWwgPSBjcmVhdGVIYXNoKFwic2hhMjU2XCIpXG4gICAgICAudXBkYXRlKG1hdGNoPy5bMV0gPz8gXCJcIilcbiAgICAgIC5kaWdlc3QoKTtcbiAgICBpZiAobWF0Y2ggJiYgdGltaW5nU2FmZUVxdWFsKGFjdHVhbCwgZXhwZWN0ZWQpKSB7XG4gICAgICBuZXh0KCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHJlc3BvbnNlXG4gICAgICAuc3RhdHVzKDQwMSlcbiAgICAgIC5zZXRIZWFkZXIoXCJ3d3ctYXV0aGVudGljYXRlXCIsIFwiQmVhcmVyXCIpXG4gICAgICAuanNvbih7XG4gICAgICAgIGVycm9yOiB7XG4gICAgICAgICAgbWVzc2FnZTogXCJJbnZhbGlkIG9yIG1pc3NpbmcgbW9kZWwtZ2F0ZXdheSBiZWFyZXIgdG9rZW4uXCIsXG4gICAgICAgICAgdHlwZTogXCJhdXRoZW50aWNhdGlvbl9lcnJvclwiLFxuICAgICAgICAgIGNvZGU6IFwiaW52YWxpZF9iZWFyZXJfdG9rZW5cIixcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICB9O1xufVxuXG4vKiogU3RhcnQgdGhlIGZvcmVncm91bmQgbW9kZWwgZ2F0ZXdheSBhbmQga2VlcCBpdHMgQXBwS2l0IHNlcnZlciBhY3RpdmUuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RhcnRNb2RlbEdhdGV3YXkob3B0aW9uczogTW9kZWxHYXRld2F5T3B0aW9ucyA9IHt9KTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHJlc29sdmVkID0gcmVzb2x2ZU1vZGVsR2F0ZXdheU9wdGlvbnMob3B0aW9ucyk7XG4gIGNvbnN0IGdhdGV3YXkgPSBuZXcgTW9kZWxHYXRld2F5KCk7XG4gIGNvbnN0IGNsaWVudCA9IGF3YWl0IHdvcmtzcGFjZUNsaWVudC5jcmVhdGVXb3Jrc3BhY2VDbGllbnQoe1xuICAgIC4uLihyZXNvbHZlZC5wcm9maWxlID8geyBwcm9maWxlOiByZXNvbHZlZC5wcm9maWxlIH0gOiB7fSksXG4gIH0pO1xuICBhd2FpdCBjcmVhdGVBcHAoe1xuICAgIGNsaWVudCxcbiAgICBwbHVnaW5zOiBbc2VydmVyKGFwcEtpdFNlcnZlck9wdGlvbnMocmVzb2x2ZWQpKV0sXG4gICAgb25QbHVnaW5zUmVhZHkoYXBwa2l0KSB7XG4gICAgICBhcHBraXQuc2VydmVyLmV4dGVuZCgoYXBwbGljYXRpb24pID0+IHtcbiAgICAgICAgaWYgKHJlc29sdmVkLmJlYXJlclRva2VuKSB7XG4gICAgICAgICAgYXBwbGljYXRpb24udXNlKGdhdGV3YXlCZWFyZXJNaWRkbGV3YXJlKHJlc29sdmVkLmJlYXJlclRva2VuKSk7XG4gICAgICAgIH1cbiAgICAgICAgYXBwbGljYXRpb24uZ2V0KFwiL2FwaS9oZWFsdGh6XCIsIChfcmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcbiAgICAgICAgICBzZW5kSGVhbHRoKHJlc3BvbnNlKTtcbiAgICAgICAgfSk7XG4gICAgICAgIGFwcGxpY2F0aW9uLmdldChcIi92MS9tb2RlbHNcIiwgKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XG4gICAgICAgICAgdm9pZCBzZW5kTW9kZWxzKGdhdGV3YXksIHJlcXVlc3QsIHJlc3BvbnNlKTtcbiAgICAgICAgfSk7XG4gICAgICAgIGZvciAoY29uc3QgW3BhdGgsIHByb3RvY29sXSBvZiBbXG4gICAgICAgICAgW1wiL3YxL2NoYXQvY29tcGxldGlvbnNcIiwgXCJvcGVuYWktY2hhdFwiXSxcbiAgICAgICAgICBbXCIvdjEvcmVzcG9uc2VzXCIsIFwib3BlbmFpLXJlc3BvbnNlc1wiXSxcbiAgICAgICAgICBbXCIvdjEvbWVzc2FnZXNcIiwgXCJhbnRocm9waWMtbWVzc2FnZXNcIl0sXG4gICAgICAgICAgW1wiL3YxL2VtYmVkZGluZ3NcIiwgXCJvcGVuYWktZW1iZWRkaW5nc1wiXSxcbiAgICAgICAgXSBhcyBjb25zdCkge1xuICAgICAgICAgIGFwcGxpY2F0aW9uLnBvc3QocGF0aCwgKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XG4gICAgICAgICAgICB2b2lkIHNlbmRJbmZlcmVuY2UoZ2F0ZXdheSwgcHJvdG9jb2wsIHJlcXVlc3QsIHJlc3BvbnNlKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSxcbiAgfSk7XG59XG4iXX0=
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The GATE half of the wrapper: a server-less AppKit app whose only job is to
3
+ * expose the `authGate` handlers the proxy calls.
4
+ *
5
+ * The in-process plugin path (`authGate` in the app's own `plugins`) has a real
6
+ * HTTP server to mount routes on. A wrapper does not - the app it fronts is a
7
+ * separate process it must not reach into - so the gate's login routes live on
8
+ * the proxy instead, and this app exists purely to give the plugin the runtime it
9
+ * needs: a `CacheManager` for the one-time-code store and signing key, and the
10
+ * sibling `email` plugin's transport for delivering a code.
11
+ *
12
+ * Lazily imported by `cli.ts`, so `dbx tunnel --insecure` (and `install` /
13
+ * `status`) never load AppKit, the Databricks SDK, or the SMTP stack.
14
+ *
15
+ * @module
16
+ */
17
+ import { type WorkspaceClient } from "@databricks/appkit";
18
+ import { type AuthGateApi, type AuthGateConfig } from "@dbx-tools/tunnel";
19
+ /** Boot the gate app and return the handlers the proxy authenticates against. */
20
+ export declare function startGateApp(config: AuthGateConfig, client?: WorkspaceClient): Promise<AuthGateApi>;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * The GATE half of the wrapper: a server-less AppKit app whose only job is to
3
+ * expose the `authGate` handlers the proxy calls.
4
+ *
5
+ * The in-process plugin path (`authGate` in the app's own `plugins`) has a real
6
+ * HTTP server to mount routes on. A wrapper does not - the app it fronts is a
7
+ * separate process it must not reach into - so the gate's login routes live on
8
+ * the proxy instead, and this app exists purely to give the plugin the runtime it
9
+ * needs: a `CacheManager` for the one-time-code store and signing key, and the
10
+ * sibling `email` plugin's transport for delivering a code.
11
+ *
12
+ * Lazily imported by `cli.ts`, so `dbx tunnel --insecure` (and `install` /
13
+ * `status`) never load AppKit, the Databricks SDK, or the SMTP stack.
14
+ *
15
+ * @module
16
+ */
17
+ import { lakebase } from "@databricks/appkit";
18
+ import { appkit } from "@dbx-tools/appkit";
19
+ import { authStorage } from "@dbx-tools/auth-gate";
20
+ import { email } from "@dbx-tools/email";
21
+ import { postgresConnectionOptions } from "@dbx-tools/postgres";
22
+ import { object } from "@dbx-tools/shared-core";
23
+ import { authGate } from "@dbx-tools/tunnel";
24
+ /** Boot the gate app and return the handlers the proxy authenticates against. */
25
+ export async function startGateApp(config, client) {
26
+ // No `server()` plugin: nothing here listens. `plugins` order matters - `email`
27
+ // registers its transport before `authGate` looks for a sibling to send with.
28
+ const plugins = await appkit.createApp({
29
+ client,
30
+ plugins: [
31
+ ...(authStorage.shouldUseLakebase(config)
32
+ ? [lakebase({ pool: postgresConnectionOptions({}) })]
33
+ : []),
34
+ ...(config.sendCode ? [] : [email()]),
35
+ authGate(config),
36
+ ],
37
+ });
38
+ const api = Reflect.get(plugins, "authGate");
39
+ if (!isAuthGateApi(api))
40
+ throw new Error("the authGate plugin exposed no api");
41
+ return api;
42
+ }
43
+ function isAuthGateApi(value) {
44
+ return (object.isRecord(value) &&
45
+ typeof value.basePath === "string" &&
46
+ typeof value.passkeysEnabled === "boolean" &&
47
+ typeof value.handler === "function" &&
48
+ typeof value.session === "function" &&
49
+ typeof value.status === "function" &&
50
+ typeof value.close === "function");
51
+ }
52
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3R1bm5lbC9hcHAudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBRUgsT0FBTyxFQUFFLFFBQVEsRUFBd0IsTUFBTSxvQkFBb0IsQ0FBQztBQUNwRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDM0MsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ25ELE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUN6QyxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNoRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDaEQsT0FBTyxFQUFFLFFBQVEsRUFBeUMsTUFBTSxtQkFBbUIsQ0FBQztBQUVwRixpRkFBaUY7QUFDakYsTUFBTSxDQUFDLEtBQUssVUFBVSxZQUFZLENBQ2hDLE1BQXNCLEVBQ3RCLE1BQXdCO0lBRXhCLGdGQUFnRjtJQUNoRiw4RUFBOEU7SUFDOUUsTUFBTSxPQUFPLEdBQUcsTUFBTSxNQUFNLENBQUMsU0FBUyxDQUFDO1FBQ3JDLE1BQU07UUFDTixPQUFPLEVBQUU7WUFDUCxHQUFHLENBQUMsV0FBVyxDQUFDLGlCQUFpQixDQUFDLE1BQU0sQ0FBQztnQkFDdkMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLEVBQUUsSUFBSSxFQUFFLHlCQUF5QixDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztnQkFDckQsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUNQLEdBQUcsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQztZQUNyQyxRQUFRLENBQUMsTUFBTSxDQUFDO1NBQ2pCO0tBQ0YsQ0FBQyxDQUFDO0lBQ0gsTUFBTSxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsVUFBVSxDQUFDLENBQUM7SUFDN0MsSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUM7UUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLG9DQUFvQyxDQUFDLENBQUM7SUFDL0UsT0FBTyxHQUFHLENBQUM7QUFDYixDQUFDO0FBRUQsU0FBUyxhQUFhLENBQUMsS0FBYztJQUNuQyxPQUFPLENBQ0wsTUFBTSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUM7UUFDdEIsT0FBTyxLQUFLLENBQUMsUUFBUSxLQUFLLFFBQVE7UUFDbEMsT0FBTyxLQUFLLENBQUMsZUFBZSxLQUFLLFNBQVM7UUFDMUMsT0FBTyxLQUFLLENBQUMsT0FBTyxLQUFLLFVBQVU7UUFDbkMsT0FBTyxLQUFLLENBQUMsT0FBTyxLQUFLLFVBQVU7UUFDbkMsT0FBTyxLQUFLLENBQUMsTUFBTSxLQUFLLFVBQVU7UUFDbEMsT0FBTyxLQUFLLENBQUMsS0FBSyxLQUFLLFVBQVUsQ0FDbEMsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFRoZSBHQVRFIGhhbGYgb2YgdGhlIHdyYXBwZXI6IGEgc2VydmVyLWxlc3MgQXBwS2l0IGFwcCB3aG9zZSBvbmx5IGpvYiBpcyB0b1xuICogZXhwb3NlIHRoZSBgYXV0aEdhdGVgIGhhbmRsZXJzIHRoZSBwcm94eSBjYWxscy5cbiAqXG4gKiBUaGUgaW4tcHJvY2VzcyBwbHVnaW4gcGF0aCAoYGF1dGhHYXRlYCBpbiB0aGUgYXBwJ3Mgb3duIGBwbHVnaW5zYCkgaGFzIGEgcmVhbFxuICogSFRUUCBzZXJ2ZXIgdG8gbW91bnQgcm91dGVzIG9uLiBBIHdyYXBwZXIgZG9lcyBub3QgLSB0aGUgYXBwIGl0IGZyb250cyBpcyBhXG4gKiBzZXBhcmF0ZSBwcm9jZXNzIGl0IG11c3Qgbm90IHJlYWNoIGludG8gLSBzbyB0aGUgZ2F0ZSdzIGxvZ2luIHJvdXRlcyBsaXZlIG9uXG4gKiB0aGUgcHJveHkgaW5zdGVhZCwgYW5kIHRoaXMgYXBwIGV4aXN0cyBwdXJlbHkgdG8gZ2l2ZSB0aGUgcGx1Z2luIHRoZSBydW50aW1lIGl0XG4gKiBuZWVkczogYSBgQ2FjaGVNYW5hZ2VyYCBmb3IgdGhlIG9uZS10aW1lLWNvZGUgc3RvcmUgYW5kIHNpZ25pbmcga2V5LCBhbmQgdGhlXG4gKiBzaWJsaW5nIGBlbWFpbGAgcGx1Z2luJ3MgdHJhbnNwb3J0IGZvciBkZWxpdmVyaW5nIGEgY29kZS5cbiAqXG4gKiBMYXppbHkgaW1wb3J0ZWQgYnkgYGNsaS50c2AsIHNvIGBkYnggdHVubmVsIC0taW5zZWN1cmVgIChhbmQgYGluc3RhbGxgIC9cbiAqIGBzdGF0dXNgKSBuZXZlciBsb2FkIEFwcEtpdCwgdGhlIERhdGFicmlja3MgU0RLLCBvciB0aGUgU01UUCBzdGFjay5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgbGFrZWJhc2UsIHR5cGUgV29ya3NwYWNlQ2xpZW50IH0gZnJvbSBcIkBkYXRhYnJpY2tzL2FwcGtpdFwiO1xuaW1wb3J0IHsgYXBwa2l0IH0gZnJvbSBcIkBkYngtdG9vbHMvYXBwa2l0XCI7XG5pbXBvcnQgeyBhdXRoU3RvcmFnZSB9IGZyb20gXCJAZGJ4LXRvb2xzL2F1dGgtZ2F0ZVwiO1xuaW1wb3J0IHsgZW1haWwgfSBmcm9tIFwiQGRieC10b29scy9lbWFpbFwiO1xuaW1wb3J0IHsgcG9zdGdyZXNDb25uZWN0aW9uT3B0aW9ucyB9IGZyb20gXCJAZGJ4LXRvb2xzL3Bvc3RncmVzXCI7XG5pbXBvcnQgeyBvYmplY3QgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHsgYXV0aEdhdGUsIHR5cGUgQXV0aEdhdGVBcGksIHR5cGUgQXV0aEdhdGVDb25maWcgfSBmcm9tIFwiQGRieC10b29scy90dW5uZWxcIjtcblxuLyoqIEJvb3QgdGhlIGdhdGUgYXBwIGFuZCByZXR1cm4gdGhlIGhhbmRsZXJzIHRoZSBwcm94eSBhdXRoZW50aWNhdGVzIGFnYWluc3QuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RhcnRHYXRlQXBwKFxuICBjb25maWc6IEF1dGhHYXRlQ29uZmlnLFxuICBjbGllbnQ/OiBXb3Jrc3BhY2VDbGllbnQsXG4pOiBQcm9taXNlPEF1dGhHYXRlQXBpPiB7XG4gIC8vIE5vIGBzZXJ2ZXIoKWAgcGx1Z2luOiBub3RoaW5nIGhlcmUgbGlzdGVucy4gYHBsdWdpbnNgIG9yZGVyIG1hdHRlcnMgLSBgZW1haWxgXG4gIC8vIHJlZ2lzdGVycyBpdHMgdHJhbnNwb3J0IGJlZm9yZSBgYXV0aEdhdGVgIGxvb2tzIGZvciBhIHNpYmxpbmcgdG8gc2VuZCB3aXRoLlxuICBjb25zdCBwbHVnaW5zID0gYXdhaXQgYXBwa2l0LmNyZWF0ZUFwcCh7XG4gICAgY2xpZW50LFxuICAgIHBsdWdpbnM6IFtcbiAgICAgIC4uLihhdXRoU3RvcmFnZS5zaG91bGRVc2VMYWtlYmFzZShjb25maWcpXG4gICAgICAgID8gW2xha2ViYXNlKHsgcG9vbDogcG9zdGdyZXNDb25uZWN0aW9uT3B0aW9ucyh7fSkgfSldXG4gICAgICAgIDogW10pLFxuICAgICAgLi4uKGNvbmZpZy5zZW5kQ29kZSA/IFtdIDogW2VtYWlsKCldKSxcbiAgICAgIGF1dGhHYXRlKGNvbmZpZyksXG4gICAgXSxcbiAgfSk7XG4gIGNvbnN0IGFwaSA9IFJlZmxlY3QuZ2V0KHBsdWdpbnMsIFwiYXV0aEdhdGVcIik7XG4gIGlmICghaXNBdXRoR2F0ZUFwaShhcGkpKSB0aHJvdyBuZXcgRXJyb3IoXCJ0aGUgYXV0aEdhdGUgcGx1Z2luIGV4cG9zZWQgbm8gYXBpXCIpO1xuICByZXR1cm4gYXBpO1xufVxuXG5mdW5jdGlvbiBpc0F1dGhHYXRlQXBpKHZhbHVlOiB1bmtub3duKTogdmFsdWUgaXMgQXV0aEdhdGVBcGkge1xuICByZXR1cm4gKFxuICAgIG9iamVjdC5pc1JlY29yZCh2YWx1ZSkgJiZcbiAgICB0eXBlb2YgdmFsdWUuYmFzZVBhdGggPT09IFwic3RyaW5nXCIgJiZcbiAgICB0eXBlb2YgdmFsdWUucGFzc2tleXNFbmFibGVkID09PSBcImJvb2xlYW5cIiAmJlxuICAgIHR5cGVvZiB2YWx1ZS5oYW5kbGVyID09PSBcImZ1bmN0aW9uXCIgJiZcbiAgICB0eXBlb2YgdmFsdWUuc2Vzc2lvbiA9PT0gXCJmdW5jdGlvblwiICYmXG4gICAgdHlwZW9mIHZhbHVlLnN0YXR1cyA9PT0gXCJmdW5jdGlvblwiICYmXG4gICAgdHlwZW9mIHZhbHVlLmNsb3NlID09PSBcImZ1bmN0aW9uXCJcbiAgKTtcbn1cbiJdfQ==
@@ -0,0 +1,27 @@
1
+ /**
2
+ * `dbx tunnel` - front a command with a public portr tunnel and passwordless gate.
3
+ *
4
+ * This is the WRAPPER path, and it exists for one case: a project that does not
5
+ * use `@dbx-tools/appkit`'s `createApp`, and therefore cannot register
6
+ * `tunnelInterceptor()` + the `authGate` plugin in-process. An AppKit app should
7
+ * still take the plugin path - one process, no proxy hop, no duplicated header
8
+ * handling.
9
+ *
10
+ * The wrapper claims the PUBLIC port (`DATABRICKS_APP_PORT`, the port the
11
+ * platform and portr route to), moves the wrapped app to a private one, and
12
+ * reverse-proxies between them so the gate sits in front of traffic it would
13
+ * otherwise have no way to intercept. Everything else is delegated: the gate
14
+ * config comes from `plugin.resolveAuthGateConfig`, the portr lifecycle from
15
+ * `portr.*` - both the same functions the in-process path uses.
16
+ *
17
+ * Ships no bin. `@dbx-tools/cli` mounts `buildProgram()` as `dbx tunnel` lazily,
18
+ * so `dbx dev` pays for none of this, and `--insecure` / `status` / `install`
19
+ * never load AppKit or the SMTP stack either (the gate app is behind a dynamic
20
+ * import).
21
+ *
22
+ * @module
23
+ */
24
+ import { Command, CommanderError } from "commander";
25
+ export { CommanderError };
26
+ /** The `dbx tunnel` program. No side effects until parsed. */
27
+ export declare function buildProgram(name?: string): Command;