@squadbase/vite-server 0.1.9-dev.f236b23 → 0.1.10-dev.cec85c2

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.
@@ -52,15 +52,6 @@ var parameters = {
52
52
  type: "text",
53
53
  secret: false,
54
54
  required: false
55
- }),
56
- developerToken: new ParameterDefinition({
57
- slug: "developer-token",
58
- name: "Google Ads Developer Token",
59
- description: "The developer token for accessing the Google Ads API. Required for all API requests.",
60
- envVarBaseKey: "GOOGLE_ADS_DEVELOPER_TOKEN",
61
- type: "text",
62
- secret: true,
63
- required: true
64
55
  })
65
56
  };
66
57
 
@@ -69,12 +60,6 @@ var BASE_URL = "https://googleads.googleapis.com/v18/";
69
60
  function createClient(params, fetchFn = fetch) {
70
61
  const rawCustomerId = params[parameters.customerId.slug];
71
62
  const defaultCustomerId = rawCustomerId?.replace(/-/g, "") ?? "";
72
- const developerToken = params[parameters.developerToken.slug];
73
- if (!developerToken) {
74
- throw new Error(
75
- `google-ads: missing required parameter: ${parameters.developerToken.slug}`
76
- );
77
- }
78
63
  function resolveCustomerId(override) {
79
64
  const id = override?.replace(/-/g, "") ?? defaultCustomerId;
80
65
  if (!id) {
@@ -88,7 +73,6 @@ function createClient(params, fetchFn = fetch) {
88
73
  const resolvedPath = defaultCustomerId ? path2.replace(/\{customerId\}/g, defaultCustomerId) : path2;
89
74
  const url = `${BASE_URL}${resolvedPath}`;
90
75
  const headers = new Headers(init?.headers);
91
- headers.set("developer-token", developerToken);
92
76
  if (defaultCustomerId) {
93
77
  headers.set("login-customer-id", defaultCustomerId);
94
78
  }
@@ -99,7 +83,6 @@ function createClient(params, fetchFn = fetch) {
99
83
  const url = `${BASE_URL}customers/${cid}/googleAds:searchStream`;
100
84
  const headers = new Headers();
101
85
  headers.set("Content-Type", "application/json");
102
- headers.set("developer-token", developerToken);
103
86
  headers.set("login-customer-id", cid);
104
87
  const response = await fetchFn(url, {
105
88
  method: "POST",
@@ -117,9 +100,7 @@ function createClient(params, fetchFn = fetch) {
117
100
  }
118
101
  async function listAccessibleCustomers() {
119
102
  const url = `${BASE_URL}customers:listAccessibleCustomers`;
120
- const headers = new Headers();
121
- headers.set("developer-token", developerToken);
122
- const response = await fetchFn(url, { method: "GET", headers });
103
+ const response = await fetchFn(url, { method: "GET" });
123
104
  if (!response.ok) {
124
105
  const body = await response.text();
125
106
  throw new Error(
@@ -360,7 +341,6 @@ var listCustomersTool = new ConnectorTool({
360
341
  `[connector-request] google-ads/${connection2.name}: listCustomers`
361
342
  );
362
343
  try {
363
- const developerToken = parameters.developerToken.getValue(connection2);
364
344
  const token = await getProxyToken(config.oauthProxy);
365
345
  const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
366
346
  const controller = new AbortController();
@@ -374,10 +354,7 @@ var listCustomersTool = new ConnectorTool({
374
354
  },
375
355
  body: JSON.stringify({
376
356
  url: `${BASE_URL2}customers:listAccessibleCustomers`,
377
- method: "GET",
378
- headers: {
379
- "developer-token": developerToken
380
- }
357
+ method: "GET"
381
358
  }),
382
359
  signal: controller.signal
383
360
  });
@@ -403,7 +380,6 @@ var listCustomersTool = new ConnectorTool({
403
380
  method: "POST",
404
381
  headers: {
405
382
  "Content-Type": "application/json",
406
- "developer-token": developerToken,
407
383
  "login-customer-id": cid
408
384
  },
409
385
  body: JSON.stringify({
@@ -449,30 +425,24 @@ var googleAdsOnboarding = new ConnectorOnboarding({
449
425
  connectionSetupInstructions: {
450
426
  ja: `\u4EE5\u4E0B\u306E\u624B\u9806\u3067Google Ads (OAuth) \u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3092\u884C\u3063\u3066\u304F\u3060\u3055\u3044\u3002
451
427
 
452
- 1. \u30E6\u30FC\u30B6\u30FC\u306B\u300CGoogle Ads API \u306E Developer Token \u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\uFF08Google Ads \u7BA1\u7406\u753B\u9762 > \u30C4\u30FC\u30EB\u3068\u8A2D\u5B9A > API \u30BB\u30F3\u30BF\u30FC\u3067\u53D6\u5F97\u3067\u304D\u307E\u3059\uFF09\u300D\u3068\u4F1D\u3048\u308B
428
+ 1. \`${listCustomersToolName}\` \u3092\u547C\u3073\u51FA\u3057\u3066\u3001OAuth\u3067\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306AGoogle Ads\u30AB\u30B9\u30BF\u30DE\u30FC\u30A2\u30AB\u30A6\u30F3\u30C8\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B
453
429
  2. \`updateConnectionParameters\` \u3092\u547C\u3073\u51FA\u3059:
454
- - \`parameterSlug\`: \`"developer-token"\`
455
- - \`value\`: \u30E6\u30FC\u30B6\u30FC\u304C\u63D0\u4F9B\u3057\u305F Developer Token
456
- 3. \`${listCustomersToolName}\` \u3092\u547C\u3073\u51FA\u3057\u3066\u3001OAuth\u3067\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306AGoogle Ads\u30AB\u30B9\u30BF\u30DE\u30FC\u30A2\u30AB\u30A6\u30F3\u30C8\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B
457
- 4. \`updateConnectionParameters\` \u3092\u547C\u3073\u51FA\u3059:
458
430
  - \`parameterSlug\`: \`"customer-id"\`
459
431
  - \`options\`: \u30AB\u30B9\u30BF\u30DE\u30FC\u4E00\u89A7\u3002\u5404 option \u306E \`label\` \u306F \`\u30A2\u30AB\u30A6\u30F3\u30C8\u540D (id: \u30AB\u30B9\u30BF\u30DE\u30FCID)\` \u306E\u5F62\u5F0F\u3001\`value\` \u306F\u30AB\u30B9\u30BF\u30DE\u30FCID
460
- 5. \u30E6\u30FC\u30B6\u30FC\u304C\u9078\u629E\u3057\u305F\u30AB\u30B9\u30BF\u30DE\u30FC\u306E \`label\` \u304C\u30E1\u30C3\u30BB\u30FC\u30B8\u3068\u3057\u3066\u5C4A\u304F\u306E\u3067\u3001\u6B21\u306E\u30B9\u30C6\u30C3\u30D7\u306B\u9032\u3080
432
+ - \u30AB\u30B9\u30BF\u30DE\u30FC\u304C **0\u4EF6** \u306E\u5834\u5408\u306F\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3092\u4E2D\u65AD\u3057\u3001\u30E6\u30FC\u30B6\u30FC\u306B\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u30A2\u30AB\u30A6\u30F3\u30C8\u304C\u306A\u3044\u65E8\u3092\u4F1D\u3048\u308B
433
+ 3. \u30E6\u30FC\u30B6\u30FC\u304C\u9078\u629E\u3057\u305F\u30AB\u30B9\u30BF\u30DE\u30FC\u306E \`label\` \u304C\u30E1\u30C3\u30BB\u30FC\u30B8\u3068\u3057\u3066\u5C4A\u304F\u306E\u3067\u3001\u6B21\u306E\u30B9\u30C6\u30C3\u30D7\u306B\u9032\u3080
461
434
 
462
435
  #### \u5236\u7D04
463
436
  - **\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u4E2D\u306B\u30EC\u30DD\u30FC\u30C8\u30C7\u30FC\u30BF\u3092\u53D6\u5F97\u3057\u306A\u3044\u3053\u3068**\u3002\u5B9F\u884C\u3057\u3066\u3088\u3044\u306E\u306F\u4E0A\u8A18\u624B\u9806\u3067\u6307\u5B9A\u3055\u308C\u305F\u30E1\u30BF\u30C7\u30FC\u30BF\u53D6\u5F97\u306E\u307F
464
437
  - \u30C4\u30FC\u30EB\u9593\u306F1\u6587\u3060\u3051\u66F8\u3044\u3066\u5373\u6B21\u306E\u30C4\u30FC\u30EB\u547C\u3073\u51FA\u3057\u3002\u4E0D\u8981\u306A\u8AAC\u660E\u306F\u7701\u7565\u3057\u3001\u52B9\u7387\u7684\u306B\u9032\u3081\u308B`,
465
438
  en: `Follow these steps to set up the Google Ads (OAuth) connection.
466
439
 
467
- 1. Ask the user to provide their Google Ads API Developer Token (available in Google Ads UI > Tools & Settings > API Center)
440
+ 1. Call \`${listCustomersToolName}\` to get the list of Google Ads customer accounts accessible with the OAuth credentials
468
441
  2. Call \`updateConnectionParameters\`:
469
- - \`parameterSlug\`: \`"developer-token"\`
470
- - \`value\`: The Developer Token provided by the user
471
- 3. Call \`${listCustomersToolName}\` to get the list of Google Ads customer accounts accessible with the OAuth credentials
472
- 4. Call \`updateConnectionParameters\`:
473
442
  - \`parameterSlug\`: \`"customer-id"\`
474
443
  - \`options\`: The customer list. Each option's \`label\` should be \`Account Name (id: customerId)\`, \`value\` should be the customer ID
475
- 5. The \`label\` of the user's selected customer will arrive as a message. Proceed to the next step
444
+ - If **0 customers** are returned, abort setup and inform the user that no accessible accounts are available
445
+ 3. The \`label\` of the user's selected customer will arrive as a message. Proceed to the next step
476
446
 
477
447
  #### Constraints
478
448
  - **Do NOT fetch report data during setup**. Only the metadata requests specified in the steps above are allowed
@@ -571,7 +541,6 @@ Authentication is handled automatically via OAuth proxy.
571
541
  const controller = new AbortController();
572
542
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS2);
573
543
  try {
574
- const developerToken = parameters.developerToken.getValue(connection2);
575
544
  const response = await fetch(proxyUrl, {
576
545
  method: "POST",
577
546
  headers: {
@@ -583,7 +552,6 @@ Authentication is handled automatically via OAuth proxy.
583
552
  method,
584
553
  headers: {
585
554
  "Content-Type": "application/json",
586
- "developer-token": developerToken,
587
555
  ...customerId ? { "login-customer-id": customerId } : {}
588
556
  },
589
557
  ...method === "POST" && body ? { body: JSON.stringify(body) } : {}
@@ -764,20 +732,12 @@ const customerIds = await ads.listAccessibleCustomers();
764
732
  if (!customerId) {
765
733
  return { success: true };
766
734
  }
767
- const developerToken = params[parameters.developerToken.slug];
768
- if (!developerToken) {
769
- return {
770
- success: false,
771
- error: "Developer token is required"
772
- };
773
- }
774
735
  const url = `https://googleads.googleapis.com/v18/customers/${customerId}/googleAds:searchStream`;
775
736
  try {
776
737
  const res = await proxyFetch(url, {
777
738
  method: "POST",
778
739
  headers: {
779
740
  "Content-Type": "application/json",
780
- "developer-token": developerToken,
781
741
  "login-customer-id": customerId
782
742
  },
783
743
  body: JSON.stringify({
@@ -20254,6 +20254,150 @@ var ParameterDefinition = class {
20254
20254
  }
20255
20255
  };
20256
20256
 
20257
+ // ../connectors/src/lib/ssh-tunnel.ts
20258
+ var sshTunnelParameters = {
20259
+ sshHost: new ParameterDefinition({
20260
+ slug: "ssh-host",
20261
+ name: "SSH Tunnel Host",
20262
+ description: "Optional. Hostname of the SSH bastion to tunnel through. Leave empty to connect directly.",
20263
+ envVarBaseKey: "SSH_TUNNEL_HOST",
20264
+ type: "text",
20265
+ secret: false,
20266
+ required: false
20267
+ }),
20268
+ sshPort: new ParameterDefinition({
20269
+ slug: "ssh-port",
20270
+ name: "SSH Tunnel Port",
20271
+ description: "Optional. SSH port of the bastion host (default: 22).",
20272
+ envVarBaseKey: "SSH_TUNNEL_PORT",
20273
+ type: "text",
20274
+ secret: false,
20275
+ required: false
20276
+ }),
20277
+ sshUsername: new ParameterDefinition({
20278
+ slug: "ssh-username",
20279
+ name: "SSH Tunnel Username",
20280
+ description: "Optional. Username for SSH authentication. Required when SSH Tunnel Host is set.",
20281
+ envVarBaseKey: "SSH_TUNNEL_USERNAME",
20282
+ type: "text",
20283
+ secret: false,
20284
+ required: false
20285
+ }),
20286
+ sshPrivateKeyBase64: new ParameterDefinition({
20287
+ slug: "ssh-private-key-base64",
20288
+ name: "SSH Private Key",
20289
+ description: "Optional. Private key (PEM, base64-encoded) used for SSH authentication. Required when SSH Tunnel Host is set.",
20290
+ envVarBaseKey: "SSH_TUNNEL_PRIVATE_KEY_BASE64",
20291
+ type: "base64EncodedText",
20292
+ secret: true,
20293
+ required: false
20294
+ }),
20295
+ sshPassphrase: new ParameterDefinition({
20296
+ slug: "ssh-passphrase",
20297
+ name: "SSH Private Key Passphrase",
20298
+ description: "Optional. Passphrase for the SSH private key, if it is encrypted.",
20299
+ envVarBaseKey: "SSH_TUNNEL_PASSPHRASE",
20300
+ type: "text",
20301
+ secret: true,
20302
+ required: false
20303
+ })
20304
+ };
20305
+ var NOOP_TUNNEL = (connectionUrl) => ({
20306
+ connectionUrl,
20307
+ close: async () => {
20308
+ }
20309
+ });
20310
+ var NOOP_TUNNEL_HOSTPORT = (host, port) => ({
20311
+ host,
20312
+ port,
20313
+ close: async () => {
20314
+ }
20315
+ });
20316
+ function connectionParamsToRecord(connection2) {
20317
+ const out = {};
20318
+ for (const p of connection2.parameters) {
20319
+ if (p.value != null) out[p.parameterSlug] = p.value;
20320
+ }
20321
+ return out;
20322
+ }
20323
+ async function maybeOpenSshTunnelHostPort(params, dbHost, dbPort) {
20324
+ const sshHost = params[sshTunnelParameters.sshHost.slug];
20325
+ if (!sshHost) return NOOP_TUNNEL_HOSTPORT(dbHost, dbPort);
20326
+ const sshUsername = params[sshTunnelParameters.sshUsername.slug];
20327
+ const sshPrivateKeyBase64 = params[sshTunnelParameters.sshPrivateKeyBase64.slug];
20328
+ if (!sshUsername || !sshPrivateKeyBase64) {
20329
+ throw new Error(
20330
+ "SSH tunnel requires `ssh-username` and `ssh-private-key-base64` when `ssh-host` is set."
20331
+ );
20332
+ }
20333
+ const sshPort = Number(params[sshTunnelParameters.sshPort.slug] || "22") || 22;
20334
+ const sshPassphrase = params[sshTunnelParameters.sshPassphrase.slug];
20335
+ const [{ Client }, net] = await Promise.all([
20336
+ Promise.resolve().then(() => __toESM(require_lib3(), 1)),
20337
+ import("net")
20338
+ ]);
20339
+ const sshClient = new Client();
20340
+ await new Promise((resolve, reject) => {
20341
+ sshClient.once("ready", () => resolve());
20342
+ sshClient.once("error", reject);
20343
+ sshClient.connect({
20344
+ host: sshHost,
20345
+ port: sshPort,
20346
+ username: sshUsername,
20347
+ privateKey: Buffer.from(sshPrivateKeyBase64, "base64"),
20348
+ passphrase: sshPassphrase || void 0,
20349
+ readyTimeout: 1e4
20350
+ });
20351
+ });
20352
+ const server = net.createServer((socket) => {
20353
+ sshClient.forwardOut(
20354
+ socket.remoteAddress ?? "127.0.0.1",
20355
+ socket.remotePort ?? 0,
20356
+ dbHost,
20357
+ dbPort,
20358
+ (err, stream) => {
20359
+ if (err) {
20360
+ socket.destroy(err);
20361
+ return;
20362
+ }
20363
+ socket.pipe(stream).pipe(socket);
20364
+ }
20365
+ );
20366
+ });
20367
+ await new Promise((resolve, reject) => {
20368
+ server.once("error", reject);
20369
+ server.listen(0, "127.0.0.1", () => resolve());
20370
+ });
20371
+ const address = server.address();
20372
+ if (!address || typeof address === "string") {
20373
+ server.close();
20374
+ sshClient.end();
20375
+ throw new Error("Failed to allocate local port for SSH tunnel.");
20376
+ }
20377
+ return {
20378
+ host: "127.0.0.1",
20379
+ port: address.port,
20380
+ close: async () => {
20381
+ await new Promise((resolve) => server.close(() => resolve()));
20382
+ sshClient.end();
20383
+ }
20384
+ };
20385
+ }
20386
+ async function maybeOpenSshTunnel(params, connectionUrl, defaultDbPort) {
20387
+ const sshHost = params[sshTunnelParameters.sshHost.slug];
20388
+ if (!sshHost) return NOOP_TUNNEL(connectionUrl);
20389
+ const url = new URL(connectionUrl);
20390
+ const dbHost = url.hostname;
20391
+ const dbPort = url.port ? Number(url.port) : defaultDbPort;
20392
+ const tunnel = await maybeOpenSshTunnelHostPort(params, dbHost, dbPort);
20393
+ url.hostname = tunnel.host;
20394
+ url.port = String(tunnel.port);
20395
+ return {
20396
+ connectionUrl: url.toString(),
20397
+ close: tunnel.close
20398
+ };
20399
+ }
20400
+
20257
20401
  // ../connectors/src/connectors/sqlserver/utils.ts
20258
20402
  var SQLSERVER_PREFIX_RE = /^(?:jdbc:)?sqlserver:\/\//i;
20259
20403
  var TRUE_VALUES = /* @__PURE__ */ new Set(["true", "1", "yes"]);
@@ -20332,17 +20476,27 @@ async function importMssql() {
20332
20476
  }
20333
20477
  async function runMssqlQuery(parsed, sql, options = {}) {
20334
20478
  const sqlMod = await importMssql();
20335
- const config = toMssqlConfig(parsed, {
20336
- encrypt: options.forceEncrypt
20337
- });
20338
- const pool = new sqlMod.ConnectionPool(config);
20339
- await pool.connect();
20479
+ const tunnel = options.tunnelParams ? await maybeOpenSshTunnelHostPort(
20480
+ options.tunnelParams,
20481
+ parsed.server,
20482
+ parsed.port
20483
+ ) : null;
20340
20484
  try {
20341
- const result = await pool.request().query(sql);
20342
- const recordset = result.recordset ?? [];
20343
- return { rows: recordset };
20485
+ const tunneled = tunnel ? { ...parsed, server: tunnel.host, port: tunnel.port } : parsed;
20486
+ const config = toMssqlConfig(tunneled, {
20487
+ encrypt: options.forceEncrypt
20488
+ });
20489
+ const pool = new sqlMod.ConnectionPool(config);
20490
+ await pool.connect();
20491
+ try {
20492
+ const result = await pool.request().query(sql);
20493
+ const recordset = result.recordset ?? [];
20494
+ return { rows: recordset };
20495
+ } finally {
20496
+ await pool.close();
20497
+ }
20344
20498
  } finally {
20345
- await pool.close();
20499
+ await tunnel?.close();
20346
20500
  }
20347
20501
  }
20348
20502
  async function checkMssqlConnection(url, credentials, options = {}) {
@@ -20430,35 +20584,69 @@ function parseOracleJdbcUrl(jdbcUrl, options = {}) {
20430
20584
  function redactOracleUrl(jdbcUrl) {
20431
20585
  return jdbcUrl.replace(/(:\/\/)([^@/]+)@/, "$1***@").replace(/(thin:)([^@]+)@/i, "$1***@");
20432
20586
  }
20587
+ function parseOracleConnectStringHostPort(connectString) {
20588
+ const m = /^([^:/]+):(\d+)(.*)$/.exec(connectString);
20589
+ if (!m) return null;
20590
+ return { host: m[1], port: Number(m[2]), trailing: m[3] };
20591
+ }
20592
+ function rewriteOracleConnectStringHostPort(connectString, host, port) {
20593
+ const parts = parseOracleConnectStringHostPort(connectString);
20594
+ if (!parts) return connectString;
20595
+ return `${host}:${port}${parts.trailing}`;
20596
+ }
20433
20597
 
20434
20598
  // ../connectors/src/lib/oracle-runner.ts
20435
20599
  async function importOracleDb() {
20436
20600
  const mod = await import("oracledb");
20437
20601
  return mod.default ?? mod;
20438
20602
  }
20439
- async function runOracleQuery(parsed, sql) {
20603
+ async function runOracleQuery(parsed, sql, options = {}) {
20440
20604
  const oracledb = await importOracleDb();
20441
- const connection2 = await oracledb.getConnection({
20442
- user: parsed.user,
20443
- password: parsed.password,
20444
- connectString: parsed.connectString
20445
- });
20605
+ let tunnel = null;
20606
+ if (options.tunnelParams) {
20607
+ const hostPort = parseOracleConnectStringHostPort(parsed.connectString);
20608
+ if (hostPort) {
20609
+ tunnel = await maybeOpenSshTunnelHostPort(
20610
+ options.tunnelParams,
20611
+ hostPort.host,
20612
+ hostPort.port
20613
+ );
20614
+ }
20615
+ }
20446
20616
  try {
20447
- const result = await connection2.execute(sql, [], {
20448
- outFormat: oracledb.OUT_FORMAT_OBJECT,
20449
- // Bound by the connector's own row cap, but keep the driver from
20450
- // streaming arbitrarily large result sets.
20451
- maxRows: 5e3
20617
+ const connectString = tunnel ? rewriteOracleConnectStringHostPort(
20618
+ parsed.connectString,
20619
+ tunnel.host,
20620
+ tunnel.port
20621
+ ) : parsed.connectString;
20622
+ const connection2 = await oracledb.getConnection({
20623
+ user: parsed.user,
20624
+ password: parsed.password,
20625
+ connectString
20452
20626
  });
20453
- return { rows: result.rows ?? [] };
20454
- } finally {
20455
20627
  try {
20456
- await connection2.close();
20457
- } catch {
20628
+ const result = await connection2.execute(
20629
+ sql,
20630
+ [],
20631
+ {
20632
+ outFormat: oracledb.OUT_FORMAT_OBJECT,
20633
+ // Bound by the connector's own row cap, but keep the driver from
20634
+ // streaming arbitrarily large result sets.
20635
+ maxRows: 5e3
20636
+ }
20637
+ );
20638
+ return { rows: result.rows ?? [] };
20639
+ } finally {
20640
+ try {
20641
+ await connection2.close();
20642
+ } catch {
20643
+ }
20458
20644
  }
20645
+ } finally {
20646
+ await tunnel?.close();
20459
20647
  }
20460
20648
  }
20461
- async function checkOracleConnection(url, credentials) {
20649
+ async function checkOracleConnection(url, credentials, options = {}) {
20462
20650
  let parsed;
20463
20651
  try {
20464
20652
  parsed = parseOracleJdbcUrl(url, credentials);
@@ -20469,7 +20657,7 @@ async function checkOracleConnection(url, credentials) {
20469
20657
  };
20470
20658
  }
20471
20659
  try {
20472
- await runOracleQuery(parsed, "SELECT 1 FROM DUAL");
20660
+ await runOracleQuery(parsed, "SELECT 1 FROM DUAL", options);
20473
20661
  return { success: true };
20474
20662
  } catch (err) {
20475
20663
  let msg = err instanceof Error ? err.message : String(err);
@@ -20478,134 +20666,6 @@ async function checkOracleConnection(url, credentials) {
20478
20666
  }
20479
20667
  }
20480
20668
 
20481
- // ../connectors/src/lib/ssh-tunnel.ts
20482
- var sshTunnelParameters = {
20483
- sshHost: new ParameterDefinition({
20484
- slug: "ssh-host",
20485
- name: "SSH Tunnel Host",
20486
- description: "Optional. Hostname of the SSH bastion to tunnel through. Leave empty to connect directly.",
20487
- envVarBaseKey: "SSH_TUNNEL_HOST",
20488
- type: "text",
20489
- secret: false,
20490
- required: false
20491
- }),
20492
- sshPort: new ParameterDefinition({
20493
- slug: "ssh-port",
20494
- name: "SSH Tunnel Port",
20495
- description: "Optional. SSH port of the bastion host (default: 22).",
20496
- envVarBaseKey: "SSH_TUNNEL_PORT",
20497
- type: "text",
20498
- secret: false,
20499
- required: false
20500
- }),
20501
- sshUsername: new ParameterDefinition({
20502
- slug: "ssh-username",
20503
- name: "SSH Tunnel Username",
20504
- description: "Optional. Username for SSH authentication. Required when SSH Tunnel Host is set.",
20505
- envVarBaseKey: "SSH_TUNNEL_USERNAME",
20506
- type: "text",
20507
- secret: false,
20508
- required: false
20509
- }),
20510
- sshPrivateKeyBase64: new ParameterDefinition({
20511
- slug: "ssh-private-key-base64",
20512
- name: "SSH Private Key",
20513
- description: "Optional. Private key (PEM, base64-encoded) used for SSH authentication. Required when SSH Tunnel Host is set.",
20514
- envVarBaseKey: "SSH_TUNNEL_PRIVATE_KEY_BASE64",
20515
- type: "base64EncodedText",
20516
- secret: true,
20517
- required: false
20518
- }),
20519
- sshPassphrase: new ParameterDefinition({
20520
- slug: "ssh-passphrase",
20521
- name: "SSH Private Key Passphrase",
20522
- description: "Optional. Passphrase for the SSH private key, if it is encrypted.",
20523
- envVarBaseKey: "SSH_TUNNEL_PASSPHRASE",
20524
- type: "text",
20525
- secret: true,
20526
- required: false
20527
- })
20528
- };
20529
- var NOOP_TUNNEL = (connectionUrl) => ({
20530
- connectionUrl,
20531
- close: async () => {
20532
- }
20533
- });
20534
- function connectionParamsToRecord(connection2) {
20535
- const out = {};
20536
- for (const p of connection2.parameters) {
20537
- if (p.value != null) out[p.parameterSlug] = p.value;
20538
- }
20539
- return out;
20540
- }
20541
- async function maybeOpenSshTunnel(params, connectionUrl, defaultDbPort) {
20542
- const sshHost = params[sshTunnelParameters.sshHost.slug];
20543
- if (!sshHost) return NOOP_TUNNEL(connectionUrl);
20544
- const sshUsername = params[sshTunnelParameters.sshUsername.slug];
20545
- const sshPrivateKeyBase64 = params[sshTunnelParameters.sshPrivateKeyBase64.slug];
20546
- if (!sshUsername || !sshPrivateKeyBase64) {
20547
- throw new Error(
20548
- "SSH tunnel requires `ssh-username` and `ssh-private-key-base64` when `ssh-host` is set."
20549
- );
20550
- }
20551
- const sshPort = Number(params[sshTunnelParameters.sshPort.slug] || "22") || 22;
20552
- const sshPassphrase = params[sshTunnelParameters.sshPassphrase.slug];
20553
- const url = new URL(connectionUrl);
20554
- const dbHost = url.hostname;
20555
- const dbPort = url.port ? Number(url.port) : defaultDbPort;
20556
- const [{ Client }, net] = await Promise.all([
20557
- Promise.resolve().then(() => __toESM(require_lib3(), 1)),
20558
- import("net")
20559
- ]);
20560
- const sshClient = new Client();
20561
- await new Promise((resolve, reject) => {
20562
- sshClient.once("ready", () => resolve());
20563
- sshClient.once("error", reject);
20564
- sshClient.connect({
20565
- host: sshHost,
20566
- port: sshPort,
20567
- username: sshUsername,
20568
- privateKey: Buffer.from(sshPrivateKeyBase64, "base64"),
20569
- passphrase: sshPassphrase || void 0,
20570
- readyTimeout: 1e4
20571
- });
20572
- });
20573
- const server = net.createServer((socket) => {
20574
- sshClient.forwardOut(
20575
- socket.remoteAddress ?? "127.0.0.1",
20576
- socket.remotePort ?? 0,
20577
- dbHost,
20578
- dbPort,
20579
- (err, stream) => {
20580
- if (err) {
20581
- socket.destroy(err);
20582
- return;
20583
- }
20584
- socket.pipe(stream).pipe(socket);
20585
- }
20586
- );
20587
- });
20588
- await new Promise((resolve, reject) => {
20589
- server.once("error", reject);
20590
- server.listen(0, "127.0.0.1", () => resolve());
20591
- });
20592
- const address = server.address();
20593
- if (!address || typeof address === "string") {
20594
- server.close();
20595
- sshClient.end();
20596
- throw new Error("Failed to allocate local port for SSH tunnel.");
20597
- }
20598
- url.hostname = "127.0.0.1";
20599
- url.port = String(address.port);
20600
- return {
20601
- connectionUrl: url.toString(),
20602
- close: async () => {
20603
- await new Promise((resolve) => server.close(() => resolve()));
20604
- sshClient.end();
20605
- }
20606
- };
20607
- }
20608
-
20609
20669
  // ../connectors/src/connectors/jdbc/parameters.ts
20610
20670
  var parameters = {
20611
20671
  jdbcUrl: new ParameterDefinition({
@@ -20749,7 +20809,9 @@ function createClient(params) {
20749
20809
  username,
20750
20810
  password
20751
20811
  });
20752
- const result = await runMssqlQuery(mssqlParsed, sql);
20812
+ const result = await runMssqlQuery(mssqlParsed, sql, {
20813
+ tunnelParams: params
20814
+ });
20753
20815
  return result.rows;
20754
20816
  }
20755
20817
  if (parsed.driver === "oracle") {
@@ -20763,7 +20825,9 @@ function createClient(params) {
20763
20825
  password
20764
20826
  });
20765
20827
  const cleanSql = sql.replace(/;\s*$/, "");
20766
- const result = await runOracleQuery(oracleParsed, cleanSql);
20828
+ const result = await runOracleQuery(oracleParsed, cleanSql, {
20829
+ tunnelParams: params
20830
+ });
20767
20831
  return result.rows;
20768
20832
  }
20769
20833
  const tunnel = await maybeOpenSshTunnel(
@@ -21042,12 +21106,13 @@ Always bound results: LIMIT for PG/MySQL/Redshift, TOP for SQL Server, FETCH FIR
21042
21106
  };
21043
21107
  }
21044
21108
  try {
21109
+ const tunnelParams = connectionParamsToRecord(connection2);
21045
21110
  if (parsed.driver === "sqlserver") {
21046
21111
  const mssqlParsed = parseSqlServerJdbcUrl(parsed.originalUrl, {
21047
21112
  username,
21048
21113
  password
21049
21114
  });
21050
- const result = await runMssqlQuery(mssqlParsed, sql);
21115
+ const result = await runMssqlQuery(mssqlParsed, sql, { tunnelParams });
21051
21116
  const rows = result.rows;
21052
21117
  return {
21053
21118
  success: true,
@@ -21062,7 +21127,9 @@ Always bound results: LIMIT for PG/MySQL/Redshift, TOP for SQL Server, FETCH FIR
21062
21127
  password
21063
21128
  });
21064
21129
  const cleanSql = sql.replace(/;\s*$/, "");
21065
- const result = await runOracleQuery(oracleParsed, cleanSql);
21130
+ const result = await runOracleQuery(oracleParsed, cleanSql, {
21131
+ tunnelParams
21132
+ });
21066
21133
  const rows = result.rows;
21067
21134
  return {
21068
21135
  success: true,
@@ -21074,7 +21141,7 @@ Always bound results: LIMIT for PG/MySQL/Redshift, TOP for SQL Server, FETCH FIR
21074
21141
  let tunnel;
21075
21142
  try {
21076
21143
  tunnel = await maybeOpenSshTunnel(
21077
- connectionParamsToRecord(connection2),
21144
+ tunnelParams,
21078
21145
  parsed.nativeUrl,
21079
21146
  parsed.defaultPort
21080
21147
  );
@@ -21248,10 +21315,18 @@ JDBC URL \u306E\u30D7\u30EC\u30D5\u30A3\u30C3\u30AF\u30B9\u306B\u3088\u308A\u65B
21248
21315
  };
21249
21316
  }
21250
21317
  if (parsed.driver === "sqlserver") {
21251
- return checkMssqlConnection(parsed.originalUrl, { username, password });
21318
+ return checkMssqlConnection(
21319
+ parsed.originalUrl,
21320
+ { username, password },
21321
+ { tunnelParams: params }
21322
+ );
21252
21323
  }
21253
21324
  if (parsed.driver === "oracle") {
21254
- return checkOracleConnection(parsed.originalUrl, { username, password });
21325
+ return checkOracleConnection(
21326
+ parsed.originalUrl,
21327
+ { username, password },
21328
+ { tunnelParams: params }
21329
+ );
21255
21330
  }
21256
21331
  const tunnel = await maybeOpenSshTunnel(
21257
21332
  params,
@@ -21308,10 +21383,12 @@ JDBC URL \u306E\u30D7\u30EC\u30D5\u30A3\u30C3\u30AF\u30B9\u306B\u3088\u308A\u65B
21308
21383
  });
21309
21384
  const sample = unwrapSampleLimit(sql);
21310
21385
  if (sample) {
21311
- const result = await runMssqlQuery(mssqlParsed, sample.inner);
21386
+ const result = await runMssqlQuery(mssqlParsed, sample.inner, {
21387
+ tunnelParams: params
21388
+ });
21312
21389
  return { rows: result.rows.slice(0, sample.limit) };
21313
21390
  }
21314
- return runMssqlQuery(mssqlParsed, sql);
21391
+ return runMssqlQuery(mssqlParsed, sql, { tunnelParams: params });
21315
21392
  }
21316
21393
  if (parsed.driver === "oracle") {
21317
21394
  const oracleParsed = parseOracleJdbcUrl(parsed.originalUrl, {
@@ -21321,11 +21398,13 @@ JDBC URL \u306E\u30D7\u30EC\u30D5\u30A3\u30C3\u30AF\u30B9\u306B\u3088\u308A\u65B
21321
21398
  const sample = unwrapSampleLimit(sql);
21322
21399
  if (sample) {
21323
21400
  const inner = sample.inner.replace(/;\s*$/, "");
21324
- const result = await runOracleQuery(oracleParsed, inner);
21401
+ const result = await runOracleQuery(oracleParsed, inner, {
21402
+ tunnelParams: params
21403
+ });
21325
21404
  return { rows: result.rows.slice(0, sample.limit) };
21326
21405
  }
21327
21406
  const cleanSql = sql.replace(/;\s*$/, "");
21328
- return runOracleQuery(oracleParsed, cleanSql);
21407
+ return runOracleQuery(oracleParsed, cleanSql, { tunnelParams: params });
21329
21408
  }
21330
21409
  const tunnel = await maybeOpenSshTunnel(
21331
21410
  params,