@squadbase/vite-server 0.1.9-dev.a57a0ac → 0.1.9-dev.a70dcaa

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.
@@ -0,0 +1,5 @@
1
+ import * as _squadbase_connectors_sdk from '@squadbase/connectors/sdk';
2
+
3
+ declare const connection: (connectionId: string) => _squadbase_connectors_sdk.CosmosDbConnectorSdk;
4
+
5
+ export { connection };
@@ -0,0 +1,685 @@
1
+ // ../connectors/src/parameter-definition.ts
2
+ var ParameterDefinition = class {
3
+ slug;
4
+ name;
5
+ description;
6
+ envVarBaseKey;
7
+ type;
8
+ secret;
9
+ required;
10
+ constructor(config) {
11
+ this.slug = config.slug;
12
+ this.name = config.name;
13
+ this.description = config.description;
14
+ this.envVarBaseKey = config.envVarBaseKey;
15
+ this.type = config.type;
16
+ this.secret = config.secret;
17
+ this.required = config.required;
18
+ }
19
+ /**
20
+ * Get the parameter value from a ConnectorConnectionObject.
21
+ */
22
+ getValue(connection2) {
23
+ const param = connection2.parameters.find(
24
+ (p) => p.parameterSlug === this.slug
25
+ );
26
+ if (!param || param.value == null) {
27
+ throw new Error(
28
+ `Parameter "${this.slug}" not found or has no value in connection "${connection2.id}"`
29
+ );
30
+ }
31
+ return param.value;
32
+ }
33
+ /**
34
+ * Try to get the parameter value. Returns undefined if not found (for optional params).
35
+ */
36
+ tryGetValue(connection2) {
37
+ const param = connection2.parameters.find(
38
+ (p) => p.parameterSlug === this.slug
39
+ );
40
+ if (!param || param.value == null) return void 0;
41
+ return param.value;
42
+ }
43
+ };
44
+
45
+ // ../connectors/src/connectors/cosmosdb/parameters.ts
46
+ var parameters = {
47
+ endpoint: new ParameterDefinition({
48
+ slug: "endpoint",
49
+ name: "Cosmos DB Endpoint",
50
+ description: "Cosmos DB account endpoint URL (e.g. `https://<account>.documents.azure.com:443/`). Found in the Azure Portal under the account's *Keys* blade.",
51
+ envVarBaseKey: "COSMOSDB_ENDPOINT",
52
+ type: "text",
53
+ secret: false,
54
+ required: true
55
+ }),
56
+ key: new ParameterDefinition({
57
+ slug: "key",
58
+ name: "Account Key",
59
+ description: "Cosmos DB account key (primary or secondary master key). Use a read-only key when only querying data.",
60
+ envVarBaseKey: "COSMOSDB_KEY",
61
+ type: "text",
62
+ secret: true,
63
+ required: true
64
+ }),
65
+ database: new ParameterDefinition({
66
+ slug: "database",
67
+ name: "Database",
68
+ description: "The Cosmos DB database (a.k.a. database account namespace) to connect to.",
69
+ envVarBaseKey: "COSMOSDB_DATABASE",
70
+ type: "text",
71
+ secret: false,
72
+ required: true
73
+ })
74
+ };
75
+
76
+ // ../connectors/src/connectors/cosmosdb/sdk/index.ts
77
+ function createClient(params) {
78
+ const endpoint = params[parameters.endpoint.slug];
79
+ if (!endpoint) {
80
+ throw new Error(
81
+ `cosmosdb: missing required parameter: ${parameters.endpoint.slug}`
82
+ );
83
+ }
84
+ const key = params[parameters.key.slug];
85
+ if (!key) {
86
+ throw new Error(
87
+ `cosmosdb: missing required parameter: ${parameters.key.slug}`
88
+ );
89
+ }
90
+ const database = params[parameters.database.slug];
91
+ if (!database) {
92
+ throw new Error(
93
+ `cosmosdb: missing required parameter: ${parameters.database.slug}`
94
+ );
95
+ }
96
+ async function getDatabase() {
97
+ const { CosmosClient } = await import("@azure/cosmos");
98
+ return new CosmosClient({ endpoint, key }).database(database);
99
+ }
100
+ async function runQuery(container, sql, options) {
101
+ try {
102
+ const db = await getDatabase();
103
+ const cont = db.container(container);
104
+ const queryOptions = {};
105
+ if (options?.maxItemCount != null) {
106
+ queryOptions.maxItemCount = options.maxItemCount;
107
+ }
108
+ if (options?.partitionKey !== void 0) {
109
+ queryOptions.partitionKey = options.partitionKey;
110
+ }
111
+ const iterator = cont.items.query(sql, queryOptions);
112
+ const { resources } = await iterator.fetchNext();
113
+ return resources ?? [];
114
+ } catch (err) {
115
+ const msg = err instanceof Error ? err.message : String(err);
116
+ throw new Error(msg.replaceAll(key, "***"));
117
+ }
118
+ }
119
+ async function listContainers() {
120
+ try {
121
+ const db = await getDatabase();
122
+ const { resources } = await db.containers.readAll().fetchAll();
123
+ return resources.map((c) => ({
124
+ id: c.id,
125
+ partitionKey: extractPartitionKeyPaths(c.partitionKey)
126
+ }));
127
+ } catch (err) {
128
+ const msg = err instanceof Error ? err.message : String(err);
129
+ throw new Error(msg.replaceAll(key, "***"));
130
+ }
131
+ }
132
+ return { query: runQuery, listContainers };
133
+ }
134
+ function extractPartitionKeyPaths(partitionKey) {
135
+ if (!partitionKey || typeof partitionKey !== "object") return void 0;
136
+ const paths = partitionKey.paths;
137
+ if (!Array.isArray(paths)) return void 0;
138
+ return paths.filter((p) => typeof p === "string");
139
+ }
140
+
141
+ // ../connectors/src/connector-onboarding.ts
142
+ var ConnectorOnboarding = class {
143
+ /** Phase 1: Connection setup instructions (optional — some connectors don't need this) */
144
+ connectionSetupInstructions;
145
+ /** Phase 2: Data overview instructions */
146
+ dataOverviewInstructions;
147
+ constructor(config) {
148
+ this.connectionSetupInstructions = config.connectionSetupInstructions;
149
+ this.dataOverviewInstructions = config.dataOverviewInstructions;
150
+ }
151
+ getConnectionSetupPrompt(language) {
152
+ return this.connectionSetupInstructions?.[language] ?? null;
153
+ }
154
+ getDataOverviewInstructions(language) {
155
+ return this.dataOverviewInstructions[language];
156
+ }
157
+ };
158
+
159
+ // ../connectors/src/connector-tool.ts
160
+ var ConnectorTool = class {
161
+ name;
162
+ description;
163
+ inputSchema;
164
+ outputSchema;
165
+ _execute;
166
+ constructor(config) {
167
+ this.name = config.name;
168
+ this.description = config.description;
169
+ this.inputSchema = config.inputSchema;
170
+ this.outputSchema = config.outputSchema;
171
+ this._execute = config.execute;
172
+ }
173
+ createTool(connections, config) {
174
+ return {
175
+ description: this.description,
176
+ inputSchema: this.inputSchema,
177
+ outputSchema: this.outputSchema,
178
+ execute: (input) => this._execute(input, connections, config)
179
+ };
180
+ }
181
+ };
182
+
183
+ // ../connectors/src/connector-plugin.ts
184
+ var ConnectorPlugin = class _ConnectorPlugin {
185
+ slug;
186
+ authType;
187
+ name;
188
+ description;
189
+ iconUrl;
190
+ parameters;
191
+ releaseFlag;
192
+ proxyPolicy;
193
+ experimentalAttributes;
194
+ categories;
195
+ onboarding;
196
+ systemPrompt;
197
+ tools;
198
+ query;
199
+ checkConnection;
200
+ constructor(config) {
201
+ this.slug = config.slug;
202
+ this.authType = config.authType;
203
+ this.name = config.name;
204
+ this.description = config.description;
205
+ this.iconUrl = config.iconUrl;
206
+ this.parameters = config.parameters;
207
+ this.releaseFlag = config.releaseFlag;
208
+ this.proxyPolicy = config.proxyPolicy;
209
+ this.experimentalAttributes = config.experimentalAttributes;
210
+ this.categories = config.categories ?? [];
211
+ this.onboarding = config.onboarding;
212
+ this.systemPrompt = config.systemPrompt;
213
+ this.tools = config.tools;
214
+ this.query = config.query;
215
+ this.checkConnection = config.checkConnection;
216
+ }
217
+ get connectorKey() {
218
+ return _ConnectorPlugin.deriveKey(this.slug, this.authType);
219
+ }
220
+ /**
221
+ * Create tools for connections that belong to this connector.
222
+ * Filters connections by connectorKey internally.
223
+ * Returns tools keyed as `${connectorKey}_${toolName}`.
224
+ */
225
+ createTools(connections, config, opts) {
226
+ const myConnections = connections.filter(
227
+ (c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
228
+ );
229
+ const result = {};
230
+ for (const t of Object.values(this.tools)) {
231
+ const tool = t.createTool(myConnections, config);
232
+ const originalToModelOutput = tool.toModelOutput;
233
+ result[`${this.connectorKey}_${t.name}`] = {
234
+ ...tool,
235
+ toModelOutput: async (options) => {
236
+ if (!originalToModelOutput) {
237
+ return opts.truncateOutput(options.output);
238
+ }
239
+ const modelOutput = await originalToModelOutput(options);
240
+ if (modelOutput.type === "text" || modelOutput.type === "json") {
241
+ return opts.truncateOutput(modelOutput.value);
242
+ }
243
+ return modelOutput;
244
+ }
245
+ };
246
+ }
247
+ return result;
248
+ }
249
+ static deriveKey(slug, authType) {
250
+ if (authType) return `${slug}-${authType}`;
251
+ const LEGACY_NULL_AUTH_TYPE_MAP = {
252
+ // user-password
253
+ "postgresql": "user-password",
254
+ "mysql": "user-password",
255
+ "clickhouse": "user-password",
256
+ "kintone": "user-password",
257
+ "squadbase-db": "user-password",
258
+ // service-account
259
+ "snowflake": "service-account",
260
+ "bigquery": "service-account",
261
+ "google-analytics": "service-account",
262
+ "google-calendar": "service-account",
263
+ "aws-athena": "service-account",
264
+ "redshift": "service-account",
265
+ // api-key
266
+ "databricks": "api-key",
267
+ "dbt": "api-key",
268
+ "airtable": "api-key",
269
+ "openai": "api-key",
270
+ "gemini": "api-key",
271
+ "anthropic": "api-key",
272
+ "wix-store": "api-key"
273
+ };
274
+ const fallbackAuthType = LEGACY_NULL_AUTH_TYPE_MAP[slug];
275
+ if (fallbackAuthType) return `${slug}-${fallbackAuthType}`;
276
+ return slug;
277
+ }
278
+ };
279
+
280
+ // ../connectors/src/auth-types.ts
281
+ var AUTH_TYPES = {
282
+ OAUTH: "oauth",
283
+ API_KEY: "api-key",
284
+ JWT: "jwt",
285
+ SERVICE_ACCOUNT: "service-account",
286
+ PAT: "pat",
287
+ USER_PASSWORD: "user-password"
288
+ };
289
+
290
+ // ../connectors/src/connectors/cosmosdb/setup.ts
291
+ var cosmosdbOnboarding = new ConnectorOnboarding({
292
+ dataOverviewInstructions: {
293
+ en: `1. Use cosmosdb_listContainers to list all containers in the configured database
294
+ 2. For key containers, sample documents with cosmosdb_query: container="users", sql="SELECT TOP 5 * FROM c"
295
+ 3. Examine the document structure to understand the schema (Cosmos DB containers are schema-flexible \u2014 items in the same container may have different fields)
296
+ 4. Use cosmosdb_query with GROUP BY to analyse data distribution if needed: \`SELECT c.status, COUNT(1) AS n FROM c GROUP BY c.status\``,
297
+ ja: `1. cosmosdb_listContainers \u3067\u5BFE\u8C61\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u5185\u306E\u30B3\u30F3\u30C6\u30CA\u4E00\u89A7\u3092\u53D6\u5F97
298
+ 2. \u4E3B\u8981\u30B3\u30F3\u30C6\u30CA\u306B\u3064\u3044\u3066 cosmosdb_query \u3067\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u3092\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0: container="users", sql="SELECT TOP 5 * FROM c"
299
+ 3. \u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u69CB\u9020\u3092\u78BA\u8A8D\u3057\u3066\u30B9\u30AD\u30FC\u30DE\u3092\u628A\u63E1\uFF08Cosmos DB \u306E\u30B3\u30F3\u30C6\u30CA\u306F\u30B9\u30AD\u30FC\u30DE\u304C\u67D4\u8EDF\u306A\u305F\u3081\u3001\u540C\u3058\u30B3\u30F3\u30C6\u30CA\u5185\u3067\u3082\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u306E\u30D5\u30A3\u30FC\u30EB\u30C9\u304C\u7570\u306A\u308B\u5834\u5408\u304C\u3042\u308A\u307E\u3059\uFF09
300
+ 4. \u5FC5\u8981\u306B\u5FDC\u3058\u3066 cosmosdb_query \u306E GROUP BY \u3067\u30C7\u30FC\u30BF\u5206\u5E03\u3092\u78BA\u8A8D: \`SELECT c.status, COUNT(1) AS n FROM c GROUP BY c.status\``
301
+ }
302
+ });
303
+
304
+ // ../connectors/src/connectors/cosmosdb/tools/list-containers.ts
305
+ import { z } from "zod";
306
+ var inputSchema = z.object({
307
+ toolUseIntent: z.string().optional().describe(
308
+ "Brief description of what you intend to accomplish with this tool call"
309
+ ),
310
+ connectionId: z.string().describe("ID of the Cosmos DB connection to use")
311
+ });
312
+ var outputSchema = z.discriminatedUnion("success", [
313
+ z.object({
314
+ success: z.literal(true),
315
+ containers: z.array(
316
+ z.object({
317
+ id: z.string(),
318
+ partitionKey: z.array(z.string()).optional()
319
+ })
320
+ )
321
+ }),
322
+ z.object({
323
+ success: z.literal(false),
324
+ error: z.string()
325
+ })
326
+ ]);
327
+ var listContainersTool = new ConnectorTool({
328
+ name: "listContainers",
329
+ description: `List all containers in the configured Cosmos DB database.
330
+ Use this as the first step to explore the data structure. Returns container ids and their partition key paths.
331
+ After listing containers, use the query tool to sample items and understand each container's schema.`,
332
+ inputSchema,
333
+ outputSchema,
334
+ async execute({ connectionId }, connections) {
335
+ const connection2 = connections.find((c) => c.id === connectionId);
336
+ if (!connection2) {
337
+ return {
338
+ success: false,
339
+ error: `Connection ${connectionId} not found`
340
+ };
341
+ }
342
+ console.log(
343
+ `[connector-query] cosmosdb/${connection2.name}: listContainers`
344
+ );
345
+ let key;
346
+ try {
347
+ const { CosmosClient } = await import("@azure/cosmos");
348
+ const endpoint = parameters.endpoint.getValue(connection2);
349
+ key = parameters.key.getValue(connection2);
350
+ const database = parameters.database.getValue(connection2);
351
+ const client = new CosmosClient({ endpoint, key });
352
+ const db = client.database(database);
353
+ const { resources } = await db.containers.readAll().fetchAll();
354
+ return {
355
+ success: true,
356
+ containers: resources.map((c) => ({
357
+ id: c.id,
358
+ partitionKey: extractPartitionKeyPaths2(c.partitionKey)
359
+ }))
360
+ };
361
+ } catch (err) {
362
+ let msg = err instanceof Error ? err.message : String(err);
363
+ if (key) msg = msg.replaceAll(key, "***");
364
+ return { success: false, error: msg };
365
+ }
366
+ }
367
+ });
368
+ function extractPartitionKeyPaths2(partitionKey) {
369
+ if (!partitionKey || typeof partitionKey !== "object") return void 0;
370
+ const paths = partitionKey.paths;
371
+ if (!Array.isArray(paths)) return void 0;
372
+ return paths.filter((p) => typeof p === "string");
373
+ }
374
+
375
+ // ../connectors/src/connectors/cosmosdb/tools/query.ts
376
+ import { z as z2 } from "zod";
377
+ var MAX_DOCUMENTS = 500;
378
+ var inputSchema2 = z2.object({
379
+ toolUseIntent: z2.string().optional().describe(
380
+ "Brief description of what you intend to accomplish with this tool call"
381
+ ),
382
+ connectionId: z2.string().describe("ID of the Cosmos DB connection to use"),
383
+ container: z2.string().describe("Id of the container (a.k.a. collection) to query"),
384
+ sql: z2.string().describe(
385
+ "Cosmos DB SQL query (Core / NoSQL API). Reference items via the alias `c` (e.g. `SELECT TOP 100 c.id, c.name FROM c WHERE c.status = 'active'`). Use `TOP n` rather than `LIMIT n` \u2014 Cosmos DB does not understand `LIMIT`."
386
+ ),
387
+ partitionKey: z2.string().optional().describe(
388
+ `Optional partition key value to scope the query to a single partition. Pass as a JSON-encoded scalar (e.g. '"abc"' or '123'). Omit for cross-partition queries.`
389
+ )
390
+ });
391
+ var outputSchema2 = z2.discriminatedUnion("success", [
392
+ z2.object({
393
+ success: z2.literal(true),
394
+ documentCount: z2.number(),
395
+ truncated: z2.boolean(),
396
+ requestCharge: z2.number().optional(),
397
+ documents: z2.array(z2.record(z2.string(), z2.unknown()))
398
+ }),
399
+ z2.object({
400
+ success: z2.literal(false),
401
+ error: z2.string()
402
+ })
403
+ ]);
404
+ var queryTool = new ConnectorTool({
405
+ name: "query",
406
+ description: `Execute a Cosmos DB SQL (Core / NoSQL API) query against a container. Returns up to ${MAX_DOCUMENTS} items.
407
+ Use for: schema exploration, data sampling, aggregations, and analytical queries.
408
+ Cosmos DB SQL targets a single container; reference items via the alias \`c\` (e.g. \`SELECT c.id FROM c WHERE c.userId = 'abc'\`).
409
+ Use \`TOP n\` (not \`LIMIT n\`) to bound the result. Cross-partition queries are enabled by default \u2014 pass \`partitionKey\` to restrict to a single partition.`,
410
+ inputSchema: inputSchema2,
411
+ outputSchema: outputSchema2,
412
+ async execute({ connectionId, container, sql, partitionKey }, connections) {
413
+ const connection2 = connections.find((c) => c.id === connectionId);
414
+ if (!connection2) {
415
+ return {
416
+ success: false,
417
+ error: `Connection ${connectionId} not found`
418
+ };
419
+ }
420
+ console.log(
421
+ `[connector-query] cosmosdb/${connection2.name} (${container}): ${sql}`
422
+ );
423
+ let key;
424
+ try {
425
+ const cosmos = await import("@azure/cosmos");
426
+ const { CosmosClient } = cosmos;
427
+ const endpoint = parameters.endpoint.getValue(connection2);
428
+ key = parameters.key.getValue(connection2);
429
+ const database = parameters.database.getValue(connection2);
430
+ const client = new CosmosClient({ endpoint, key });
431
+ const cont = client.database(database).container(container);
432
+ const queryOptions = {
433
+ // Bound by the connector's own row cap, but keep the SDK from
434
+ // streaming arbitrarily large continuations.
435
+ maxItemCount: MAX_DOCUMENTS + 1
436
+ };
437
+ if (partitionKey != null && partitionKey !== "") {
438
+ try {
439
+ queryOptions.partitionKey = JSON.parse(partitionKey);
440
+ } catch {
441
+ return {
442
+ success: false,
443
+ error: `Invalid partitionKey: must be a JSON-encoded scalar (e.g. '"abc"' or '123'). Got: ${partitionKey}`
444
+ };
445
+ }
446
+ }
447
+ const iterator = cont.items.query(sql, queryOptions);
448
+ const { resources, requestCharge } = await iterator.fetchNext();
449
+ const documents = resources ?? [];
450
+ const truncated = documents.length > MAX_DOCUMENTS;
451
+ return {
452
+ success: true,
453
+ documentCount: Math.min(documents.length, MAX_DOCUMENTS),
454
+ truncated,
455
+ requestCharge,
456
+ documents: documents.slice(0, MAX_DOCUMENTS)
457
+ };
458
+ } catch (err) {
459
+ let msg = err instanceof Error ? err.message : String(err);
460
+ if (key) msg = msg.replaceAll(key, "***");
461
+ return { success: false, error: msg };
462
+ }
463
+ }
464
+ });
465
+
466
+ // ../connectors/src/connectors/cosmosdb/index.ts
467
+ var tools = {
468
+ listContainers: listContainersTool,
469
+ query: queryTool
470
+ };
471
+ var cosmosdbConnector = new ConnectorPlugin({
472
+ slug: "cosmosdb",
473
+ authType: AUTH_TYPES.USER_PASSWORD,
474
+ name: "Azure Cosmos DB",
475
+ description: "Connect to Azure Cosmos DB (Core / NoSQL API) for document-oriented data storage and SQL-style querying.",
476
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/5p9B2Db0V2d8mK2jgBWtZu/dad72db8f41b16c50de2bcef03f9d415/cosmosdb-icon.png",
477
+ parameters,
478
+ releaseFlag: { dev1: true, dev2: false, prod: false },
479
+ categories: ["database"],
480
+ onboarding: cosmosdbOnboarding,
481
+ systemPrompt: {
482
+ en: `### Tools
483
+
484
+ - \`cosmosdb_listContainers\`: Lists all containers in the configured database, with their partition key paths. Use this first to explore available data.
485
+ - \`cosmosdb_query\`: Executes a Cosmos DB SQL (Core / NoSQL API) query against a single container and returns items. Use for schema exploration, data sampling, and analytical queries. Pass \`partitionKey\` to scope the query to a single partition (cross-partition queries are enabled by default).
486
+
487
+ ### Business Logic
488
+
489
+ The business logic type for this connector is "typescript".
490
+
491
+ ### Cosmos DB SQL Reference
492
+ - Cosmos DB stores schema-flexible JSON items in **containers** organised under a **database**. Items are partitioned by a per-container partition key path.
493
+ - Queries always target a single container and reference items via the alias \`c\` (e.g. \`SELECT c.id, c.name FROM c WHERE c.status = 'active'\`).
494
+ - Row limiting: use \`TOP n\` (e.g. \`SELECT TOP 100 * FROM c\`). \`LIMIT\` is **not** supported. \`OFFSET m LIMIT n\` is supported on newer accounts but \`TOP\` is the safe default.
495
+ - System fields are prefixed with an underscore (\`c.id\`, \`c._ts\` for the modification timestamp, \`c._etag\`).
496
+ - Aggregates: \`COUNT(1)\`, \`SUM\`, \`AVG\`, \`MIN\`, \`MAX\`, with \`GROUP BY\` (e.g. \`SELECT c.country, COUNT(1) AS n FROM c GROUP BY c.country\`).
497
+ - Joins: only **intra-document** joins via \`JOIN\` over arrays inside the same item; there is no cross-container/cross-document join.
498
+ - Always bound results with \`TOP n\` and prefer scoped queries with a \`partitionKey\` value when possible \u2014 cross-partition queries cost more RUs.`,
499
+ ja: `### \u30C4\u30FC\u30EB
500
+
501
+ - \`cosmosdb_listContainers\`: \u8A2D\u5B9A\u3055\u308C\u305F\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u5185\u306E\u30B3\u30F3\u30C6\u30CA\u4E00\u89A7\uFF08\u30D1\u30FC\u30C6\u30A3\u30B7\u30E7\u30F3\u30AD\u30FC\u306E\u30D1\u30B9\u4ED8\u304D\uFF09\u3092\u53D6\u5F97\u3057\u307E\u3059\u3002\u30C7\u30FC\u30BF\u63A2\u7D22\u306E\u6700\u521D\u306E\u30B9\u30C6\u30C3\u30D7\u3068\u3057\u3066\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002
502
+ - \`cosmosdb_query\`: \u5358\u4E00\u306E\u30B3\u30F3\u30C6\u30CA\u306B\u5BFE\u3057\u3066 Cosmos DB SQL\uFF08Core / NoSQL API\uFF09\u30AF\u30A8\u30EA\u3092\u5B9F\u884C\u3057\u3001\u30A2\u30A4\u30C6\u30E0\u3092\u8FD4\u3057\u307E\u3059\u3002\u30B9\u30AD\u30FC\u30DE\u63A2\u7D22\u3001\u30C7\u30FC\u30BF\u306E\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0\u3001\u5206\u6790\u30AF\u30A8\u30EA\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\`partitionKey\` \u3092\u6E21\u3059\u3068\u5358\u4E00\u30D1\u30FC\u30C6\u30A3\u30B7\u30E7\u30F3\u306B\u30B9\u30B3\u30FC\u30D7\u3067\u304D\u3001\u672A\u6307\u5B9A\u3060\u3068\u30AF\u30ED\u30B9\u30D1\u30FC\u30C6\u30A3\u30B7\u30E7\u30F3\u30AF\u30A8\u30EA\u306B\u306A\u308A\u307E\u3059\u3002
503
+
504
+ ### Business Logic
505
+
506
+ \u3053\u306E\u30B3\u30CD\u30AF\u30BF\u306E\u30D3\u30B8\u30CD\u30B9\u30ED\u30B8\u30C3\u30AF\u30BF\u30A4\u30D7\u306F "typescript" \u3067\u3059\u3002
507
+
508
+ ### Cosmos DB SQL \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
509
+ - Cosmos DB \u306F\u30B9\u30AD\u30FC\u30DE\u67D4\u8EDF\u306A JSON \u30A2\u30A4\u30C6\u30E0\u3092 **\u30B3\u30F3\u30C6\u30CA** \u306B\u683C\u7D0D\u3057\u3001\u30B3\u30F3\u30C6\u30CA\u306F\u30B3\u30F3\u30C6\u30CA\u3054\u3068\u306E\u30D1\u30FC\u30C6\u30A3\u30B7\u30E7\u30F3\u30AD\u30FC\u30D1\u30B9\u3067\u30D1\u30FC\u30C6\u30A3\u30B7\u30E7\u30F3\u5206\u5272\u3055\u308C\u307E\u3059\u3002\u30B3\u30F3\u30C6\u30CA\u306F **\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9** \u306B\u307E\u3068\u3081\u3089\u308C\u307E\u3059\u3002
510
+ - \u30AF\u30A8\u30EA\u306F\u5E38\u306B\u5358\u4E00\u30B3\u30F3\u30C6\u30CA\u3092\u5BFE\u8C61\u3068\u3057\u3001\u30A2\u30A4\u30C6\u30E0\u306F\u5225\u540D \`c\` \u3067\u53C2\u7167\u3057\u307E\u3059\uFF08\u4F8B: \`SELECT c.id, c.name FROM c WHERE c.status = 'active'\`\uFF09\u3002
511
+ - \u884C\u6570\u5236\u9650: \`TOP n\` \u3092\u4F7F\u7528\u3057\u307E\u3059\uFF08\u4F8B: \`SELECT TOP 100 * FROM c\`\uFF09\u3002\`LIMIT\` \u306F **\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093**\u3002\u65B0\u3057\u3044\u30A2\u30AB\u30A6\u30F3\u30C8\u3067\u306F \`OFFSET m LIMIT n\` \u304C\u4F7F\u3048\u307E\u3059\u304C\u3001\u5B89\u5168\u5074\u306E\u65E2\u5B9A\u306F \`TOP\` \u3067\u3059\u3002
512
+ - \u30B7\u30B9\u30C6\u30E0\u30D5\u30A3\u30FC\u30EB\u30C9\u306F\u30A2\u30F3\u30C0\u30FC\u30B9\u30B3\u30A2\u59CB\u307E\u308A\uFF08\`c.id\`\u3001\u5909\u66F4\u6642\u523B\u306E \`c._ts\`\u3001\`c._etag\`\uFF09\u3002
513
+ - \u96C6\u7D04: \`COUNT(1)\`\u3001\`SUM\`\u3001\`AVG\`\u3001\`MIN\`\u3001\`MAX\` \u3092 \`GROUP BY\` \u3068\u7D44\u307F\u5408\u308F\u305B\u307E\u3059\uFF08\u4F8B: \`SELECT c.country, COUNT(1) AS n FROM c GROUP BY c.country\`\uFF09\u3002
514
+ - \u7D50\u5408: \u540C\u4E00\u30A2\u30A4\u30C6\u30E0\u5185\u306E\u914D\u5217\u306B\u5BFE\u3059\u308B **\u30A4\u30F3\u30C8\u30E9\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8** \`JOIN\` \u306E\u307F\u3067\u3001\u30B3\u30F3\u30C6\u30CA\u9593\uFF0F\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u9593\u306E\u7D50\u5408\u306F\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u307E\u305B\u3093\u3002
515
+ - \u7D50\u679C\u4EF6\u6570\u306F\u5FC5\u305A \`TOP n\` \u3067\u5236\u9650\u3057\u3001\u53EF\u80FD\u3067\u3042\u308C\u3070 \`partitionKey\` \u3067\u5358\u4E00\u30D1\u30FC\u30C6\u30A3\u30B7\u30E7\u30F3\u306B\u30B9\u30B3\u30FC\u30D7\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u30AF\u30ED\u30B9\u30D1\u30FC\u30C6\u30A3\u30B7\u30E7\u30F3\u30AF\u30A8\u30EA\u306F RU \u3092\u591A\u304F\u6D88\u8CBB\u3057\u307E\u3059\uFF09\u3002`
516
+ },
517
+ tools,
518
+ async checkConnection(params, _config) {
519
+ try {
520
+ const { CosmosClient } = await import("@azure/cosmos");
521
+ const client = new CosmosClient({
522
+ endpoint: params[parameters.endpoint.slug],
523
+ key: params[parameters.key.slug]
524
+ });
525
+ const database = params[parameters.database.slug];
526
+ await client.database(database).read();
527
+ return { success: true };
528
+ } catch (error) {
529
+ const msg = error instanceof Error ? error.message : String(error);
530
+ const key = params[parameters.key.slug];
531
+ return {
532
+ success: false,
533
+ error: key ? msg.replaceAll(key, "***") : msg
534
+ };
535
+ }
536
+ }
537
+ });
538
+
539
+ // src/connectors/create-connector-sdk.ts
540
+ import { readFileSync } from "fs";
541
+ import path from "path";
542
+
543
+ // src/connector-client/env.ts
544
+ function resolveEnvVar(entry, key, connectionId) {
545
+ const envVarName = entry.envVars[key];
546
+ if (!envVarName) {
547
+ throw new Error(`Connection "${connectionId}" is missing envVars mapping for key "${key}"`);
548
+ }
549
+ const value = process.env[envVarName];
550
+ if (!value) {
551
+ throw new Error(`Environment variable "${envVarName}" (for connection "${connectionId}", key "${key}") is not set`);
552
+ }
553
+ return value;
554
+ }
555
+ function resolveEnvVarOptional(entry, key) {
556
+ const envVarName = entry.envVars[key];
557
+ if (!envVarName) return void 0;
558
+ return process.env[envVarName] || void 0;
559
+ }
560
+
561
+ // src/connector-client/proxy-fetch.ts
562
+ import { getContext } from "hono/context-storage";
563
+ import { getCookie } from "hono/cookie";
564
+ var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
565
+ function normalizeHeaders(input) {
566
+ const out = {};
567
+ if (!input) return out;
568
+ new Headers(input).forEach((value, key) => {
569
+ out[key] = value;
570
+ });
571
+ return out;
572
+ }
573
+ function createSandboxProxyFetch(connectionId) {
574
+ return async (input, init) => {
575
+ const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
576
+ const sandboxId = process.env.INTERNAL_SQUADBASE_SANDBOX_ID;
577
+ if (!token || !sandboxId) {
578
+ throw new Error(
579
+ "Connection proxy is not configured. Please check your deployment settings."
580
+ );
581
+ }
582
+ const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
583
+ const originalMethod = init?.method ?? "GET";
584
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
585
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
586
+ const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
587
+ return fetch(proxyUrl, {
588
+ method: "POST",
589
+ headers: {
590
+ "Content-Type": "application/json",
591
+ Authorization: `Bearer ${token}`
592
+ },
593
+ body: JSON.stringify({
594
+ url: originalUrl,
595
+ method: originalMethod,
596
+ headers: normalizeHeaders(init?.headers),
597
+ body: originalBody
598
+ })
599
+ });
600
+ };
601
+ }
602
+ function createDeployedAppProxyFetch(connectionId) {
603
+ const projectId = process.env["SQUADBASE_PROJECT_ID"];
604
+ if (!projectId) {
605
+ throw new Error(
606
+ "Connection proxy is not configured. Please check your deployment settings."
607
+ );
608
+ }
609
+ const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
610
+ const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
611
+ return async (input, init) => {
612
+ const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
613
+ const originalMethod = init?.method ?? "GET";
614
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
615
+ const c = getContext();
616
+ const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
617
+ if (!appSession) {
618
+ throw new Error(
619
+ "No authentication method available for connection proxy."
620
+ );
621
+ }
622
+ return fetch(proxyUrl, {
623
+ method: "POST",
624
+ headers: {
625
+ "Content-Type": "application/json",
626
+ Authorization: `Bearer ${appSession}`
627
+ },
628
+ body: JSON.stringify({
629
+ url: originalUrl,
630
+ method: originalMethod,
631
+ headers: normalizeHeaders(init?.headers),
632
+ body: originalBody
633
+ })
634
+ });
635
+ };
636
+ }
637
+ function createProxyFetch(connectionId) {
638
+ if (process.env.INTERNAL_SQUADBASE_SANDBOX_ID) {
639
+ return createSandboxProxyFetch(connectionId);
640
+ }
641
+ return createDeployedAppProxyFetch(connectionId);
642
+ }
643
+
644
+ // src/connectors/create-connector-sdk.ts
645
+ function loadConnectionsSync() {
646
+ const filePath = process.env.CONNECTIONS_PATH ?? path.join(process.cwd(), ".squadbase/connections.json");
647
+ try {
648
+ const raw = readFileSync(filePath, "utf-8");
649
+ return JSON.parse(raw);
650
+ } catch {
651
+ return {};
652
+ }
653
+ }
654
+ function createConnectorSdk(plugin, createClient2) {
655
+ return (connectionId) => {
656
+ const connections = loadConnectionsSync();
657
+ const entry = connections[connectionId];
658
+ if (!entry) {
659
+ throw new Error(
660
+ `Connection "${connectionId}" not found in .squadbase/connections.json`
661
+ );
662
+ }
663
+ if (entry.connector.slug !== plugin.slug) {
664
+ throw new Error(
665
+ `Connection "${connectionId}" is not a ${plugin.slug} connection (got "${entry.connector.slug}")`
666
+ );
667
+ }
668
+ const params = {};
669
+ for (const param of Object.values(plugin.parameters)) {
670
+ if (param.required) {
671
+ params[param.slug] = resolveEnvVar(entry, param.slug, connectionId);
672
+ } else {
673
+ const val = resolveEnvVarOptional(entry, param.slug);
674
+ if (val !== void 0) params[param.slug] = val;
675
+ }
676
+ }
677
+ return createClient2(params, createProxyFetch(connectionId));
678
+ };
679
+ }
680
+
681
+ // src/connectors/entries/cosmosdb.ts
682
+ var connection = createConnectorSdk(cosmosdbConnector, createClient);
683
+ export {
684
+ connection
685
+ };