@squadbase/vite-server 0.1.9-dev.f236b23 → 0.1.10-dev.5b0c0a8
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/dist/cli/index.js +1526 -89508
- package/dist/connectors/aws-billing.js +18 -4
- package/dist/connectors/azure-sql.js +162 -16
- package/dist/connectors/cosmosdb.d.ts +5 -0
- package/dist/connectors/cosmosdb.js +743 -0
- package/dist/connectors/google-ads.js +196 -120
- package/dist/connectors/jdbc.js +311 -20402
- package/dist/connectors/mongodb.d.ts +5 -0
- package/dist/connectors/mongodb.js +879 -0
- package/dist/connectors/oracle.js +205 -28
- package/dist/connectors/semrush.js +109 -21
- package/dist/connectors/sqlserver.js +158 -15
- package/dist/index.js +1595 -89587
- package/dist/main.js +1580 -89572
- package/dist/vite-plugin.js +1475 -89467
- package/package.json +13 -2
- package/dist/cli/cpufeatures-ORCDQN2Y.node +0 -0
- package/dist/cli/sshcrypto-P3UBA7BP.node +0 -0
- package/dist/cpufeatures-ORCDQN2Y.node +0 -0
- package/dist/sshcrypto-P3UBA7BP.node +0 -0
|
@@ -701,9 +701,16 @@ A Filter is an Expression. Leaves are \`Dimensions\`, \`Tags\`, or \`CostCategor
|
|
|
701
701
|
|
|
702
702
|
### Business Logic
|
|
703
703
|
|
|
704
|
-
The business logic type for this connector is "typescript". The connector exposes resolved AWS credentials via \`connection(connectionId)
|
|
704
|
+
The business logic type for this connector is "typescript". The connector exposes resolved AWS credentials via \`connection(connectionId)\` (already typed as \`{ accessKeyId, secretAccessKey, region }\` \u2014 do NOT add an \`as\` cast). Pass them to \`@aws-sdk/client-cost-explorer\` directly inside the handler. Do NOT read AWS credentials from environment variables.
|
|
705
705
|
|
|
706
|
-
####
|
|
706
|
+
#### Server logic slug naming
|
|
707
|
+
|
|
708
|
+
When creating a server logic for this connector, the \`slug\` (file name) MUST be lowercase kebab-case or snake_case \u2014 only \`[a-z0-9-_]\` is allowed. camelCase and uppercase will fail validation.
|
|
709
|
+
|
|
710
|
+
- OK: \`monthly-cost-trend\`, \`cost_by_service\`, \`top10-services\`
|
|
711
|
+
- NG: \`monthlyCostTrend\`, \`MonthlyCostTrend\`, \`monthly cost trend\`
|
|
712
|
+
|
|
713
|
+
#### Example (slug: \`monthly-cost-trend\`)
|
|
707
714
|
|
|
708
715
|
\`\`\`ts
|
|
709
716
|
import type { Context } from "hono";
|
|
@@ -779,9 +786,16 @@ Filter \u306F Expression \u3067\u3059\u3002\u30EA\u30FC\u30D5\u306F \`Dimensions
|
|
|
779
786
|
|
|
780
787
|
### Business Logic
|
|
781
788
|
|
|
782
|
-
\u3053\u306E\u30B3\u30CD\u30AF\u30BF\u306E\u30D3\u30B8\u30CD\u30B9\u30ED\u30B8\u30C3\u30AF\u30BF\u30A4\u30D7\u306F "typescript" \u3067\u3059\u3002\`connection(connectionId)\` \u3067\u89E3\u6C7A\u6E08\u307F\u306E AWS \u8A8D\u8A3C\u60C5\u5831\u3092\u53D6\u5F97\u3057\u3001\`@aws-sdk/client-cost-explorer\` \u306B\u76F4\u63A5\u6E21\u3057\u3066\u30CF\u30F3\u30C9\u30E9\u5185\u3067\u5229\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u74B0\u5883\u5909\u6570\u304B\u3089 AWS \u8A8D\u8A3C\u60C5\u5831\u3092\u8AAD\u307F\u53D6\u3089\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
|
|
789
|
+
\u3053\u306E\u30B3\u30CD\u30AF\u30BF\u306E\u30D3\u30B8\u30CD\u30B9\u30ED\u30B8\u30C3\u30AF\u30BF\u30A4\u30D7\u306F "typescript" \u3067\u3059\u3002\`connection(connectionId)\` \u3067\u89E3\u6C7A\u6E08\u307F\u306E AWS \u8A8D\u8A3C\u60C5\u5831\uFF08\`{ accessKeyId, secretAccessKey, region }\` \u3068\u3057\u3066\u578B\u4ED8\u3051\u6E08\u307F \u2014 \`as\` \u30AD\u30E3\u30B9\u30C8\u306F\u4E0D\u8981\uFF09\u3092\u53D6\u5F97\u3057\u3001\`@aws-sdk/client-cost-explorer\` \u306B\u76F4\u63A5\u6E21\u3057\u3066\u30CF\u30F3\u30C9\u30E9\u5185\u3067\u5229\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u74B0\u5883\u5909\u6570\u304B\u3089 AWS \u8A8D\u8A3C\u60C5\u5831\u3092\u8AAD\u307F\u53D6\u3089\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
|
|
790
|
+
|
|
791
|
+
#### \u30B5\u30FC\u30D0\u30FC\u30ED\u30B8\u30C3\u30AF\u306E slug \u547D\u540D\u898F\u5247
|
|
792
|
+
|
|
793
|
+
\u3053\u306E\u30B3\u30CD\u30AF\u30BF\u7528\u306E\u30B5\u30FC\u30D0\u30FC\u30ED\u30B8\u30C3\u30AF\u3092\u4F5C\u6210\u3059\u308B\u969B\u3001\`slug\`\uFF08\u30D5\u30A1\u30A4\u30EB\u540D\uFF09\u306F **\u5C0F\u6587\u5B57\u306E kebab-case \u307E\u305F\u306F snake_case** \u306B\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u8A31\u5BB9\u6587\u5B57\u306F \`[a-z0-9-_]\` \u306E\u307F\uFF09\u3002camelCase \u3084\u5927\u6587\u5B57\u3092\u542B\u3080\u3068\u30D0\u30EA\u30C7\u30FC\u30B7\u30E7\u30F3\u30A8\u30E9\u30FC\u306B\u306A\u308A\u307E\u3059\u3002
|
|
794
|
+
|
|
795
|
+
- OK: \`monthly-cost-trend\`\u3001\`cost_by_service\`\u3001\`top10-services\`
|
|
796
|
+
- NG: \`monthlyCostTrend\`\u3001\`MonthlyCostTrend\`\u3001\`monthly cost trend\`
|
|
783
797
|
|
|
784
|
-
#### Example
|
|
798
|
+
#### Example\uFF08slug: \`monthly-cost-trend\`\uFF09
|
|
785
799
|
|
|
786
800
|
\`\`\`ts
|
|
787
801
|
import type { Context } from "hono";
|
|
@@ -42,6 +42,131 @@ var ParameterDefinition = class {
|
|
|
42
42
|
}
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
+
// ../connectors/src/lib/ssh-tunnel.ts
|
|
46
|
+
var sshTunnelParameters = {
|
|
47
|
+
sshHost: new ParameterDefinition({
|
|
48
|
+
slug: "ssh-host",
|
|
49
|
+
name: "SSH Tunnel Host",
|
|
50
|
+
description: "Optional. Hostname of the SSH bastion to tunnel through. Leave empty to connect directly.",
|
|
51
|
+
envVarBaseKey: "SSH_TUNNEL_HOST",
|
|
52
|
+
type: "text",
|
|
53
|
+
secret: false,
|
|
54
|
+
required: false
|
|
55
|
+
}),
|
|
56
|
+
sshPort: new ParameterDefinition({
|
|
57
|
+
slug: "ssh-port",
|
|
58
|
+
name: "SSH Tunnel Port",
|
|
59
|
+
description: "Optional. SSH port of the bastion host (default: 22).",
|
|
60
|
+
envVarBaseKey: "SSH_TUNNEL_PORT",
|
|
61
|
+
type: "text",
|
|
62
|
+
secret: false,
|
|
63
|
+
required: false
|
|
64
|
+
}),
|
|
65
|
+
sshUsername: new ParameterDefinition({
|
|
66
|
+
slug: "ssh-username",
|
|
67
|
+
name: "SSH Tunnel Username",
|
|
68
|
+
description: "Optional. Username for SSH authentication. Required when SSH Tunnel Host is set.",
|
|
69
|
+
envVarBaseKey: "SSH_TUNNEL_USERNAME",
|
|
70
|
+
type: "text",
|
|
71
|
+
secret: false,
|
|
72
|
+
required: false
|
|
73
|
+
}),
|
|
74
|
+
sshPrivateKeyBase64: new ParameterDefinition({
|
|
75
|
+
slug: "ssh-private-key-base64",
|
|
76
|
+
name: "SSH Private Key",
|
|
77
|
+
description: "Optional. Private key (PEM, base64-encoded) used for SSH authentication. Required when SSH Tunnel Host is set.",
|
|
78
|
+
envVarBaseKey: "SSH_TUNNEL_PRIVATE_KEY_BASE64",
|
|
79
|
+
type: "base64EncodedText",
|
|
80
|
+
secret: true,
|
|
81
|
+
required: false
|
|
82
|
+
}),
|
|
83
|
+
sshPassphrase: new ParameterDefinition({
|
|
84
|
+
slug: "ssh-passphrase",
|
|
85
|
+
name: "SSH Private Key Passphrase",
|
|
86
|
+
description: "Optional. Passphrase for the SSH private key, if it is encrypted.",
|
|
87
|
+
envVarBaseKey: "SSH_TUNNEL_PASSPHRASE",
|
|
88
|
+
type: "text",
|
|
89
|
+
secret: true,
|
|
90
|
+
required: false
|
|
91
|
+
})
|
|
92
|
+
};
|
|
93
|
+
var NOOP_TUNNEL_HOSTPORT = (host, port) => ({
|
|
94
|
+
host,
|
|
95
|
+
port,
|
|
96
|
+
close: async () => {
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
function connectionParamsToRecord(connection2) {
|
|
100
|
+
const out = {};
|
|
101
|
+
for (const p of connection2.parameters) {
|
|
102
|
+
if (p.value != null) out[p.parameterSlug] = p.value;
|
|
103
|
+
}
|
|
104
|
+
return out;
|
|
105
|
+
}
|
|
106
|
+
async function maybeOpenSshTunnelHostPort(params, dbHost, dbPort) {
|
|
107
|
+
const sshHost = params[sshTunnelParameters.sshHost.slug];
|
|
108
|
+
if (!sshHost) return NOOP_TUNNEL_HOSTPORT(dbHost, dbPort);
|
|
109
|
+
const sshUsername = params[sshTunnelParameters.sshUsername.slug];
|
|
110
|
+
const sshPrivateKeyBase64 = params[sshTunnelParameters.sshPrivateKeyBase64.slug];
|
|
111
|
+
if (!sshUsername || !sshPrivateKeyBase64) {
|
|
112
|
+
throw new Error(
|
|
113
|
+
"SSH tunnel requires `ssh-username` and `ssh-private-key-base64` when `ssh-host` is set."
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
const sshPort = Number(params[sshTunnelParameters.sshPort.slug] || "22") || 22;
|
|
117
|
+
const sshPassphrase = params[sshTunnelParameters.sshPassphrase.slug];
|
|
118
|
+
const [{ Client }, net] = await Promise.all([
|
|
119
|
+
import("ssh2"),
|
|
120
|
+
import("net")
|
|
121
|
+
]);
|
|
122
|
+
const sshClient = new Client();
|
|
123
|
+
await new Promise((resolve, reject) => {
|
|
124
|
+
sshClient.once("ready", () => resolve());
|
|
125
|
+
sshClient.once("error", reject);
|
|
126
|
+
sshClient.connect({
|
|
127
|
+
host: sshHost,
|
|
128
|
+
port: sshPort,
|
|
129
|
+
username: sshUsername,
|
|
130
|
+
privateKey: Buffer.from(sshPrivateKeyBase64, "base64"),
|
|
131
|
+
passphrase: sshPassphrase || void 0,
|
|
132
|
+
readyTimeout: 1e4
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
const server = net.createServer((socket) => {
|
|
136
|
+
sshClient.forwardOut(
|
|
137
|
+
socket.remoteAddress ?? "127.0.0.1",
|
|
138
|
+
socket.remotePort ?? 0,
|
|
139
|
+
dbHost,
|
|
140
|
+
dbPort,
|
|
141
|
+
(err, stream) => {
|
|
142
|
+
if (err) {
|
|
143
|
+
socket.destroy(err);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
socket.pipe(stream).pipe(socket);
|
|
147
|
+
}
|
|
148
|
+
);
|
|
149
|
+
});
|
|
150
|
+
await new Promise((resolve, reject) => {
|
|
151
|
+
server.once("error", reject);
|
|
152
|
+
server.listen(0, "127.0.0.1", () => resolve());
|
|
153
|
+
});
|
|
154
|
+
const address = server.address();
|
|
155
|
+
if (!address || typeof address === "string") {
|
|
156
|
+
server.close();
|
|
157
|
+
sshClient.end();
|
|
158
|
+
throw new Error("Failed to allocate local port for SSH tunnel.");
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
host: "127.0.0.1",
|
|
162
|
+
port: address.port,
|
|
163
|
+
close: async () => {
|
|
164
|
+
await new Promise((resolve) => server.close(() => resolve()));
|
|
165
|
+
sshClient.end();
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
45
170
|
// ../connectors/src/connectors/sqlserver/utils.ts
|
|
46
171
|
var SQLSERVER_PREFIX_RE = /^(?:jdbc:)?sqlserver:\/\//i;
|
|
47
172
|
var TRUE_VALUES = /* @__PURE__ */ new Set(["true", "1", "yes"]);
|
|
@@ -120,17 +245,27 @@ async function importMssql() {
|
|
|
120
245
|
}
|
|
121
246
|
async function runMssqlQuery(parsed, sql, options = {}) {
|
|
122
247
|
const sqlMod = await importMssql();
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
248
|
+
const tunnel = options.tunnelParams ? await maybeOpenSshTunnelHostPort(
|
|
249
|
+
options.tunnelParams,
|
|
250
|
+
parsed.server,
|
|
251
|
+
parsed.port
|
|
252
|
+
) : null;
|
|
128
253
|
try {
|
|
129
|
-
const
|
|
130
|
-
const
|
|
131
|
-
|
|
254
|
+
const tunneled = tunnel ? { ...parsed, server: tunnel.host, port: tunnel.port } : parsed;
|
|
255
|
+
const config = toMssqlConfig(tunneled, {
|
|
256
|
+
encrypt: options.forceEncrypt
|
|
257
|
+
});
|
|
258
|
+
const pool = new sqlMod.ConnectionPool(config);
|
|
259
|
+
await pool.connect();
|
|
260
|
+
try {
|
|
261
|
+
const result = await pool.request().query(sql);
|
|
262
|
+
const recordset = result.recordset ?? [];
|
|
263
|
+
return { rows: recordset };
|
|
264
|
+
} finally {
|
|
265
|
+
await pool.close();
|
|
266
|
+
}
|
|
132
267
|
} finally {
|
|
133
|
-
await
|
|
268
|
+
await tunnel?.close();
|
|
134
269
|
}
|
|
135
270
|
}
|
|
136
271
|
async function checkMssqlConnection(url, credentials, options = {}) {
|
|
@@ -181,7 +316,8 @@ var parameters = {
|
|
|
181
316
|
type: "text",
|
|
182
317
|
secret: true,
|
|
183
318
|
required: false
|
|
184
|
-
})
|
|
319
|
+
}),
|
|
320
|
+
...sshTunnelParameters
|
|
185
321
|
};
|
|
186
322
|
|
|
187
323
|
// ../connectors/src/connectors/azure-sql/sdk/index.ts
|
|
@@ -197,7 +333,10 @@ function createClient(params) {
|
|
|
197
333
|
const parsed = parseSqlServerJdbcUrl(jdbcUrl, { username, password });
|
|
198
334
|
async function runQuery(sql) {
|
|
199
335
|
try {
|
|
200
|
-
const { rows } = await runMssqlQuery(parsed, sql, {
|
|
336
|
+
const { rows } = await runMssqlQuery(parsed, sql, {
|
|
337
|
+
forceEncrypt: true,
|
|
338
|
+
tunnelParams: params
|
|
339
|
+
});
|
|
201
340
|
return rows;
|
|
202
341
|
} catch (err) {
|
|
203
342
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -442,7 +581,10 @@ Avoid loading large amounts of data; always include \`TOP\` in queries.`,
|
|
|
442
581
|
};
|
|
443
582
|
}
|
|
444
583
|
try {
|
|
445
|
-
const { rows } = await runMssqlQuery(parsed, sql, {
|
|
584
|
+
const { rows } = await runMssqlQuery(parsed, sql, {
|
|
585
|
+
forceEncrypt: true,
|
|
586
|
+
tunnelParams: connectionParamsToRecord(connection2)
|
|
587
|
+
});
|
|
446
588
|
const truncated = rows.length > MAX_ROWS;
|
|
447
589
|
return {
|
|
448
590
|
success: true,
|
|
@@ -467,7 +609,7 @@ var azureSqlConnector = new ConnectorPlugin({
|
|
|
467
609
|
description: "Connect to Azure SQL Database (managed) using a JDBC-style URL. Encryption is enforced automatically.",
|
|
468
610
|
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/5TL0yBbxoLlk6jFZuiHl8w/55040f52d57bf0b77a2215c985c5a772/azure-sql-icon.png",
|
|
469
611
|
parameters,
|
|
470
|
-
releaseFlag: { dev1: true, dev2:
|
|
612
|
+
releaseFlag: { dev1: true, dev2: true, prod: true },
|
|
471
613
|
categories: ["database"],
|
|
472
614
|
onboarding: azureSqlOnboarding,
|
|
473
615
|
systemPrompt: {
|
|
@@ -514,7 +656,7 @@ The business logic type for this connector is "sql".
|
|
|
514
656
|
username: params[parameters.username.slug],
|
|
515
657
|
password: params[parameters.password.slug]
|
|
516
658
|
},
|
|
517
|
-
{ forceEncrypt: true }
|
|
659
|
+
{ forceEncrypt: true, tunnelParams: params }
|
|
518
660
|
);
|
|
519
661
|
},
|
|
520
662
|
async query(params, sql, _namedParams) {
|
|
@@ -525,11 +667,15 @@ The business logic type for this connector is "sql".
|
|
|
525
667
|
const sample = unwrapSampleLimit(sql);
|
|
526
668
|
if (sample) {
|
|
527
669
|
const result = await runMssqlQuery(parsed, sample.inner, {
|
|
528
|
-
forceEncrypt: true
|
|
670
|
+
forceEncrypt: true,
|
|
671
|
+
tunnelParams: params
|
|
529
672
|
});
|
|
530
673
|
return { rows: result.rows.slice(0, sample.limit) };
|
|
531
674
|
}
|
|
532
|
-
return runMssqlQuery(parsed, sql, {
|
|
675
|
+
return runMssqlQuery(parsed, sql, {
|
|
676
|
+
forceEncrypt: true,
|
|
677
|
+
tunnelParams: params
|
|
678
|
+
});
|
|
533
679
|
}
|
|
534
680
|
});
|
|
535
681
|
|