@squadbase/vite-server 0.1.3-dev.8 → 0.1.3

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 (63) hide show
  1. package/dist/cli/index.js +14229 -29321
  2. package/dist/connectors/airtable-oauth.js +43 -6
  3. package/dist/connectors/airtable.js +43 -6
  4. package/dist/connectors/amplitude.js +43 -6
  5. package/dist/connectors/anthropic.js +43 -6
  6. package/dist/connectors/asana.js +43 -6
  7. package/dist/connectors/attio.js +43 -6
  8. package/dist/connectors/{google-ads-oauth.d.ts → backlog-api-key.d.ts} +1 -1
  9. package/dist/connectors/backlog-api-key.js +629 -0
  10. package/dist/connectors/customerio.js +43 -6
  11. package/dist/connectors/dbt.js +43 -6
  12. package/dist/connectors/{google-sheets-oauth.d.ts → gamma.d.ts} +1 -1
  13. package/dist/connectors/gamma.js +866 -0
  14. package/dist/connectors/gemini.js +43 -6
  15. package/dist/connectors/gmail-oauth.js +65 -8
  16. package/dist/connectors/gmail.js +104 -44
  17. package/dist/connectors/google-ads.d.ts +1 -1
  18. package/dist/connectors/google-ads.js +410 -332
  19. package/dist/connectors/google-analytics-oauth.js +61 -8
  20. package/dist/connectors/google-analytics.js +107 -292
  21. package/dist/connectors/google-calendar-oauth.js +61 -8
  22. package/dist/connectors/google-calendar.js +111 -58
  23. package/dist/connectors/{linkedin-ads-oauth.d.ts → google-docs.d.ts} +1 -1
  24. package/dist/connectors/google-docs.js +631 -0
  25. package/dist/connectors/google-drive.d.ts +5 -0
  26. package/dist/connectors/google-drive.js +875 -0
  27. package/dist/connectors/google-sheets.d.ts +1 -1
  28. package/dist/connectors/google-sheets.js +267 -285
  29. package/dist/connectors/google-slides.d.ts +5 -0
  30. package/dist/connectors/google-slides.js +663 -0
  31. package/dist/connectors/grafana.js +43 -6
  32. package/dist/connectors/hubspot-oauth.js +43 -6
  33. package/dist/connectors/hubspot.js +43 -6
  34. package/dist/connectors/intercom-oauth.js +43 -6
  35. package/dist/connectors/intercom.js +43 -6
  36. package/dist/connectors/jira-api-key.js +43 -6
  37. package/dist/connectors/kintone-api-token.js +256 -82
  38. package/dist/connectors/kintone.js +43 -6
  39. package/dist/connectors/linkedin-ads.js +188 -168
  40. package/dist/connectors/mailchimp-oauth.js +43 -6
  41. package/dist/connectors/mailchimp.js +43 -6
  42. package/dist/connectors/mixpanel.d.ts +5 -0
  43. package/dist/connectors/mixpanel.js +779 -0
  44. package/dist/connectors/notion-oauth.js +43 -6
  45. package/dist/connectors/notion.js +43 -6
  46. package/dist/connectors/openai.js +43 -6
  47. package/dist/connectors/sentry.d.ts +5 -0
  48. package/dist/connectors/sentry.js +761 -0
  49. package/dist/connectors/shopify-oauth.js +43 -6
  50. package/dist/connectors/shopify.js +43 -6
  51. package/dist/connectors/stripe-api-key.js +46 -7
  52. package/dist/connectors/stripe-oauth.js +43 -6
  53. package/dist/connectors/wix-store.js +43 -6
  54. package/dist/connectors/zendesk-oauth.js +43 -6
  55. package/dist/connectors/zendesk.js +43 -6
  56. package/dist/index.d.ts +1 -1
  57. package/dist/index.js +4419 -3855
  58. package/dist/main.js +5481 -4918
  59. package/dist/vite-plugin.js +4474 -3948
  60. package/package.json +30 -12
  61. package/dist/connectors/google-ads-oauth.js +0 -890
  62. package/dist/connectors/google-sheets-oauth.js +0 -718
  63. package/dist/connectors/linkedin-ads-oauth.js +0 -848
@@ -0,0 +1,761 @@
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/sentry/parameters.ts
46
+ var parameters = {
47
+ organizationSlug: new ParameterDefinition({
48
+ slug: "organization-slug",
49
+ name: "Sentry Organization Slug",
50
+ description: "The slug of your Sentry organization (e.g., 'my-org'). Found in your Sentry URL: https://sentry.io/organizations/{slug}/",
51
+ envVarBaseKey: "SENTRY_ORGANIZATION_SLUG",
52
+ type: "text",
53
+ secret: false,
54
+ required: true
55
+ }),
56
+ authToken: new ParameterDefinition({
57
+ slug: "auth-token",
58
+ name: "Sentry Auth Token",
59
+ description: "Sentry API authentication token. Generate one at https://sentry.io/settings/account/api/auth-tokens/ with the required scopes (project:read, org:read, event:read, issue:read, issue:write).",
60
+ envVarBaseKey: "SENTRY_AUTH_TOKEN",
61
+ type: "text",
62
+ secret: true,
63
+ required: true
64
+ })
65
+ };
66
+
67
+ // ../connectors/src/connectors/sentry/sdk/index.ts
68
+ var BASE_URL = "https://sentry.io/api/0";
69
+ function createClient(params) {
70
+ const authToken = params[parameters.authToken.slug];
71
+ const organizationSlug = params[parameters.organizationSlug.slug];
72
+ if (!authToken) {
73
+ throw new Error(
74
+ `sentry: missing required parameter: ${parameters.authToken.slug}`
75
+ );
76
+ }
77
+ if (!organizationSlug) {
78
+ throw new Error(
79
+ `sentry: missing required parameter: ${parameters.organizationSlug.slug}`
80
+ );
81
+ }
82
+ function resolvePath(path2) {
83
+ return path2.replace(/\{organizationSlug\}/g, organizationSlug);
84
+ }
85
+ async function authenticatedFetch(url, init) {
86
+ const headers = new Headers(init?.headers);
87
+ headers.set("Authorization", `Bearer ${authToken}`);
88
+ headers.set("Content-Type", "application/json");
89
+ headers.set("Accept", "application/json");
90
+ return fetch(url, { ...init, headers });
91
+ }
92
+ async function request(path2, init) {
93
+ const resolved = resolvePath(path2);
94
+ const url = `${BASE_URL}${resolved.startsWith("/") ? "" : "/"}${resolved}`;
95
+ return authenticatedFetch(url, init);
96
+ }
97
+ async function listProjects() {
98
+ const url = `${BASE_URL}/organizations/${organizationSlug}/projects/`;
99
+ const response = await authenticatedFetch(url);
100
+ if (!response.ok) {
101
+ const body = await response.text();
102
+ throw new Error(
103
+ `sentry: listProjects failed (${response.status}): ${body}`
104
+ );
105
+ }
106
+ return await response.json();
107
+ }
108
+ async function listIssues(options) {
109
+ const searchParams = new URLSearchParams();
110
+ if (options?.project) searchParams.set("project", options.project);
111
+ if (options?.query) searchParams.set("query", options.query);
112
+ if (options?.sort) searchParams.set("sort", options.sort);
113
+ if (options?.cursor) searchParams.set("cursor", options.cursor);
114
+ const qs = searchParams.toString();
115
+ const url = `${BASE_URL}/organizations/${organizationSlug}/issues/${qs ? `?${qs}` : ""}`;
116
+ const response = await authenticatedFetch(url);
117
+ if (!response.ok) {
118
+ const body = await response.text();
119
+ throw new Error(
120
+ `sentry: listIssues failed (${response.status}): ${body}`
121
+ );
122
+ }
123
+ return await response.json();
124
+ }
125
+ async function getIssue(issueId) {
126
+ const url = `${BASE_URL}/organizations/${organizationSlug}/issues/${issueId}/`;
127
+ const response = await authenticatedFetch(url);
128
+ if (!response.ok) {
129
+ const body = await response.text();
130
+ throw new Error(
131
+ `sentry: getIssue failed (${response.status}): ${body}`
132
+ );
133
+ }
134
+ return await response.json();
135
+ }
136
+ async function listIssueEvents(issueId) {
137
+ const url = `${BASE_URL}/organizations/${organizationSlug}/issues/${issueId}/events/`;
138
+ const response = await authenticatedFetch(url);
139
+ if (!response.ok) {
140
+ const body = await response.text();
141
+ throw new Error(
142
+ `sentry: listIssueEvents failed (${response.status}): ${body}`
143
+ );
144
+ }
145
+ return await response.json();
146
+ }
147
+ async function updateIssue(issueId, updates) {
148
+ const url = `${BASE_URL}/organizations/${organizationSlug}/issues/${issueId}/`;
149
+ const response = await authenticatedFetch(url, {
150
+ method: "PUT",
151
+ body: JSON.stringify(updates)
152
+ });
153
+ if (!response.ok) {
154
+ const body = await response.text();
155
+ throw new Error(
156
+ `sentry: updateIssue failed (${response.status}): ${body}`
157
+ );
158
+ }
159
+ return await response.json();
160
+ }
161
+ return {
162
+ request,
163
+ listProjects,
164
+ listIssues,
165
+ getIssue,
166
+ listIssueEvents,
167
+ updateIssue
168
+ };
169
+ }
170
+
171
+ // ../connectors/src/connector-onboarding.ts
172
+ var ConnectorOnboarding = class {
173
+ /** Phase 1: Connection setup instructions (optional — some connectors don't need this) */
174
+ connectionSetupInstructions;
175
+ /** Phase 2: Data overview instructions */
176
+ dataOverviewInstructions;
177
+ constructor(config) {
178
+ this.connectionSetupInstructions = config.connectionSetupInstructions;
179
+ this.dataOverviewInstructions = config.dataOverviewInstructions;
180
+ }
181
+ getConnectionSetupPrompt(language) {
182
+ return this.connectionSetupInstructions?.[language] ?? null;
183
+ }
184
+ getDataOverviewInstructions(language) {
185
+ return this.dataOverviewInstructions[language];
186
+ }
187
+ };
188
+
189
+ // ../connectors/src/connector-tool.ts
190
+ var ConnectorTool = class {
191
+ name;
192
+ description;
193
+ inputSchema;
194
+ outputSchema;
195
+ _execute;
196
+ constructor(config) {
197
+ this.name = config.name;
198
+ this.description = config.description;
199
+ this.inputSchema = config.inputSchema;
200
+ this.outputSchema = config.outputSchema;
201
+ this._execute = config.execute;
202
+ }
203
+ createTool(connections, config) {
204
+ return {
205
+ description: this.description,
206
+ inputSchema: this.inputSchema,
207
+ outputSchema: this.outputSchema,
208
+ execute: (input) => this._execute(input, connections, config)
209
+ };
210
+ }
211
+ };
212
+
213
+ // ../connectors/src/connector-plugin.ts
214
+ var ConnectorPlugin = class _ConnectorPlugin {
215
+ slug;
216
+ authType;
217
+ name;
218
+ description;
219
+ iconUrl;
220
+ parameters;
221
+ releaseFlag;
222
+ proxyPolicy;
223
+ experimentalAttributes;
224
+ onboarding;
225
+ systemPrompt;
226
+ tools;
227
+ query;
228
+ checkConnection;
229
+ constructor(config) {
230
+ this.slug = config.slug;
231
+ this.authType = config.authType;
232
+ this.name = config.name;
233
+ this.description = config.description;
234
+ this.iconUrl = config.iconUrl;
235
+ this.parameters = config.parameters;
236
+ this.releaseFlag = config.releaseFlag;
237
+ this.proxyPolicy = config.proxyPolicy;
238
+ this.experimentalAttributes = config.experimentalAttributes;
239
+ this.onboarding = config.onboarding;
240
+ this.systemPrompt = config.systemPrompt;
241
+ this.tools = config.tools;
242
+ this.query = config.query;
243
+ this.checkConnection = config.checkConnection;
244
+ }
245
+ get connectorKey() {
246
+ return _ConnectorPlugin.deriveKey(this.slug, this.authType);
247
+ }
248
+ /**
249
+ * Create tools for connections that belong to this connector.
250
+ * Filters connections by connectorKey internally.
251
+ * Returns tools keyed as `${connectorKey}_${toolName}`.
252
+ */
253
+ createTools(connections, config, opts) {
254
+ const myConnections = connections.filter(
255
+ (c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
256
+ );
257
+ const result = {};
258
+ for (const t of Object.values(this.tools)) {
259
+ const tool = t.createTool(myConnections, config);
260
+ const originalToModelOutput = tool.toModelOutput;
261
+ result[`${this.connectorKey}_${t.name}`] = {
262
+ ...tool,
263
+ toModelOutput: async (options) => {
264
+ if (!originalToModelOutput) {
265
+ return opts.truncateOutput(options.output);
266
+ }
267
+ const modelOutput = await originalToModelOutput(options);
268
+ if (modelOutput.type === "text" || modelOutput.type === "json") {
269
+ return opts.truncateOutput(modelOutput.value);
270
+ }
271
+ return modelOutput;
272
+ }
273
+ };
274
+ }
275
+ return result;
276
+ }
277
+ static deriveKey(slug, authType) {
278
+ if (authType) return `${slug}-${authType}`;
279
+ const LEGACY_NULL_AUTH_TYPE_MAP = {
280
+ // user-password
281
+ "postgresql": "user-password",
282
+ "mysql": "user-password",
283
+ "clickhouse": "user-password",
284
+ "kintone": "user-password",
285
+ "squadbase-db": "user-password",
286
+ // service-account
287
+ "snowflake": "service-account",
288
+ "bigquery": "service-account",
289
+ "google-analytics": "service-account",
290
+ "google-calendar": "service-account",
291
+ "aws-athena": "service-account",
292
+ "redshift": "service-account",
293
+ // api-key
294
+ "databricks": "api-key",
295
+ "dbt": "api-key",
296
+ "airtable": "api-key",
297
+ "openai": "api-key",
298
+ "gemini": "api-key",
299
+ "anthropic": "api-key",
300
+ "wix-store": "api-key"
301
+ };
302
+ const fallbackAuthType = LEGACY_NULL_AUTH_TYPE_MAP[slug];
303
+ if (fallbackAuthType) return `${slug}-${fallbackAuthType}`;
304
+ return slug;
305
+ }
306
+ };
307
+
308
+ // ../connectors/src/auth-types.ts
309
+ var AUTH_TYPES = {
310
+ OAUTH: "oauth",
311
+ API_KEY: "api-key",
312
+ JWT: "jwt",
313
+ SERVICE_ACCOUNT: "service-account",
314
+ PAT: "pat",
315
+ USER_PASSWORD: "user-password"
316
+ };
317
+
318
+ // ../connectors/src/connectors/sentry/setup.ts
319
+ var sentryOnboarding = new ConnectorOnboarding({
320
+ dataOverviewInstructions: {
321
+ en: `1. Call sentry_request with GET /organizations/{organizationSlug}/projects/ to list all projects
322
+ 2. Call sentry_request with GET /organizations/{organizationSlug}/issues/?sort=date&query=is:unresolved to get recent unresolved issues
323
+ 3. For a specific issue, call sentry_request with GET /organizations/{organizationSlug}/issues/{issueId}/ to get details`,
324
+ ja: `1. sentry_request \u3067 GET /organizations/{organizationSlug}/projects/ \u3092\u547C\u3073\u51FA\u3057\u3001\u5168\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u4E00\u89A7\u8868\u793A
325
+ 2. sentry_request \u3067 GET /organizations/{organizationSlug}/issues/?sort=date&query=is:unresolved \u3092\u547C\u3073\u51FA\u3057\u3001\u6700\u8FD1\u306E\u672A\u89E3\u6C7A\u30A4\u30B7\u30E5\u30FC\u3092\u53D6\u5F97
326
+ 3. \u7279\u5B9A\u306E\u30A4\u30B7\u30E5\u30FC\u306B\u3064\u3044\u3066 sentry_request \u3067 GET /organizations/{organizationSlug}/issues/{issueId}/ \u3092\u547C\u3073\u51FA\u3057\u3001\u8A73\u7D30\u3092\u53D6\u5F97`
327
+ }
328
+ });
329
+
330
+ // ../connectors/src/connectors/sentry/tools/request.ts
331
+ import { z } from "zod";
332
+ var BASE_URL2 = "https://sentry.io/api/0";
333
+ var REQUEST_TIMEOUT_MS = 6e4;
334
+ var inputSchema = z.object({
335
+ toolUseIntent: z.string().optional().describe(
336
+ "Brief description of what you intend to accomplish with this tool call"
337
+ ),
338
+ connectionId: z.string().describe("ID of the Sentry connection to use"),
339
+ method: z.enum(["GET", "POST", "PUT", "DELETE"]).describe("HTTP method"),
340
+ path: z.string().describe(
341
+ "API path appended to https://sentry.io/api/0 (e.g., '/organizations/{organizationSlug}/projects/', '/projects/{organizationSlug}/{project}/issues/'). {organizationSlug} is automatically replaced with the configured organization slug."
342
+ ),
343
+ body: z.record(z.string(), z.unknown()).optional().describe("JSON request body for POST/PUT requests")
344
+ });
345
+ var outputSchema = z.discriminatedUnion("success", [
346
+ z.object({
347
+ success: z.literal(true),
348
+ status: z.number(),
349
+ data: z.unknown()
350
+ }),
351
+ z.object({
352
+ success: z.literal(false),
353
+ error: z.string()
354
+ })
355
+ ]);
356
+ var requestTool = new ConnectorTool({
357
+ name: "request",
358
+ description: `Send authenticated requests to the Sentry API.
359
+ Supports GET, POST, PUT, and DELETE methods.
360
+ Authentication is handled automatically via Bearer token.
361
+ {organizationSlug} in the path is automatically replaced with the configured organization slug.`,
362
+ inputSchema,
363
+ outputSchema,
364
+ async execute({ connectionId, method, path: path2, body }, connections) {
365
+ const connection2 = connections.find((c) => c.id === connectionId);
366
+ if (!connection2) {
367
+ return {
368
+ success: false,
369
+ error: `Connection ${connectionId} not found`
370
+ };
371
+ }
372
+ console.log(
373
+ `[connector-request] sentry/${connection2.name}: ${method} ${path2}`
374
+ );
375
+ try {
376
+ const authToken = parameters.authToken.getValue(connection2);
377
+ const organizationSlug = parameters.organizationSlug.getValue(connection2);
378
+ const resolvedPath = path2.replace(
379
+ /\{organizationSlug\}/g,
380
+ organizationSlug
381
+ );
382
+ const url = `${BASE_URL2}${resolvedPath.startsWith("/") ? "" : "/"}${resolvedPath}`;
383
+ const controller = new AbortController();
384
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
385
+ try {
386
+ const response = await fetch(url, {
387
+ method,
388
+ headers: {
389
+ Authorization: `Bearer ${authToken}`,
390
+ "Content-Type": "application/json",
391
+ Accept: "application/json"
392
+ },
393
+ ...body != null ? { body: JSON.stringify(body) } : {},
394
+ signal: controller.signal
395
+ });
396
+ const data = await response.json();
397
+ if (!response.ok) {
398
+ const errorMessage = typeof data === "object" && data !== null && "detail" in data && typeof data.detail === "string" ? data.detail : `HTTP ${response.status} ${response.statusText}`;
399
+ return { success: false, error: errorMessage };
400
+ }
401
+ return { success: true, status: response.status, data };
402
+ } finally {
403
+ clearTimeout(timeout);
404
+ }
405
+ } catch (err) {
406
+ const msg = err instanceof Error ? err.message : String(err);
407
+ return { success: false, error: msg };
408
+ }
409
+ }
410
+ });
411
+
412
+ // ../connectors/src/connectors/sentry/index.ts
413
+ var tools = { request: requestTool };
414
+ var sentryConnector = new ConnectorPlugin({
415
+ slug: "sentry",
416
+ authType: AUTH_TYPES.API_KEY,
417
+ name: "Sentry",
418
+ description: "Connect to Sentry for error tracking and performance monitoring data.",
419
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/4B8ZEGFGjTeMWNnXQb1dAL/ac10f813f02353f5b0cbe64fb5c06d8f/sentry.svg",
420
+ parameters,
421
+ releaseFlag: { dev1: true, dev2: false, prod: false },
422
+ onboarding: sentryOnboarding,
423
+ systemPrompt: {
424
+ en: `### Tools
425
+
426
+ - \`sentry_request\`: Send authenticated requests to the Sentry API. Supports GET, POST, PUT, and DELETE methods. Authentication is handled automatically via Bearer token. The {organizationSlug} placeholder in paths is automatically replaced with the configured organization slug.
427
+
428
+ ### Sentry API Reference
429
+
430
+ #### Organization & Projects
431
+ - GET \`/organizations/{organizationSlug}/\` \u2014 Get organization details
432
+ - GET \`/organizations/{organizationSlug}/projects/\` \u2014 List all projects
433
+
434
+ #### Issues
435
+ - GET \`/organizations/{organizationSlug}/issues/\` \u2014 List issues (supports query params: \`query\`, \`sort\`, \`project\`, \`cursor\`)
436
+ - GET \`/organizations/{organizationSlug}/issues/{issueId}/\` \u2014 Get issue details
437
+ - PUT \`/organizations/{organizationSlug}/issues/{issueId}/\` \u2014 Update issue (resolve, ignore, assign). Body: \`{ "status": "resolved" }\` or \`{ "assignedTo": "user:id" }\`
438
+ - DELETE \`/organizations/{organizationSlug}/issues/{issueId}/\` \u2014 Delete an issue
439
+
440
+ #### Events
441
+ - GET \`/organizations/{organizationSlug}/issues/{issueId}/events/\` \u2014 List events for an issue
442
+ - GET \`/organizations/{organizationSlug}/issues/{issueId}/events/latest/\` \u2014 Get latest event for an issue
443
+ - GET \`/organizations/{organizationSlug}/events/{eventId}/\` \u2014 Get event details
444
+
445
+ #### Tags & Stats
446
+ - GET \`/organizations/{organizationSlug}/issues/{issueId}/tags/\` \u2014 List tags for an issue
447
+ - GET \`/organizations/{organizationSlug}/issues/{issueId}/tags/{tagKey}/values/\` \u2014 List tag values
448
+
449
+ #### Issue Search Query Syntax
450
+ - \`is:unresolved\` \u2014 Unresolved issues
451
+ - \`is:resolved\` \u2014 Resolved issues
452
+ - \`is:ignored\` \u2014 Ignored issues
453
+ - \`assigned:me\` \u2014 Assigned to current user
454
+ - \`assigned:none\` \u2014 Unassigned issues
455
+ - \`level:error\` \u2014 Filter by level (fatal, error, warning, info, debug)
456
+ - \`project:my-project\` \u2014 Filter by project slug
457
+ - \`browser:Chrome\` \u2014 Filter by browser tag
458
+ - \`os:Windows\` \u2014 Filter by OS tag
459
+ - \`first-seen:>2024-01-01\` \u2014 First seen after date
460
+ - \`last-seen:<24h\` \u2014 Last seen within 24 hours
461
+ - \`times-seen:>100\` \u2014 Seen more than 100 times
462
+ - Combine with spaces: \`is:unresolved level:error project:backend\`
463
+
464
+ #### Sort Options
465
+ - \`date\` \u2014 Last seen (default)
466
+ - \`new\` \u2014 First seen
467
+ - \`freq\` \u2014 Frequency (most frequent first)
468
+ - \`priority\` \u2014 Priority
469
+
470
+ ### Tips
471
+ - Use \`{organizationSlug}\` placeholder in paths \u2014 it is automatically replaced
472
+ - Sentry API responses are paginated; check the \`Link\` header for pagination cursors
473
+ - Issue IDs are numeric; short IDs (e.g., \`PROJECT-123\`) can be used in the \`query\` param: \`query=PROJECT-123\`
474
+ - To resolve an issue: PUT with \`{ "status": "resolved" }\`
475
+ - To ignore an issue: PUT with \`{ "status": "ignored" }\`
476
+
477
+ ### Business Logic
478
+
479
+ The business logic type for this connector is "typescript". Write handler code using the connector SDK shown below. Do NOT access credentials directly from environment variables.
480
+
481
+ #### Example
482
+
483
+ \`\`\`ts
484
+ import { connection } from "@squadbase/vite-server/connectors/sentry";
485
+
486
+ const sentry = connection("<connectionId>");
487
+
488
+ // List all projects
489
+ const projects = await sentry.listProjects();
490
+ console.log(projects.map(p => p.slug));
491
+
492
+ // List unresolved issues sorted by frequency
493
+ const issues = await sentry.listIssues({ query: "is:unresolved", sort: "freq" });
494
+ issues.forEach(issue => console.log(issue.shortId, issue.title, issue.count));
495
+
496
+ // Get issue details
497
+ const issue = await sentry.getIssue("12345");
498
+ console.log(issue.title, issue.status, issue.lastSeen);
499
+
500
+ // List events for an issue
501
+ const events = await sentry.listIssueEvents("12345");
502
+ events.forEach(e => console.log(e.dateCreated, e.message));
503
+
504
+ // Resolve an issue
505
+ await sentry.updateIssue("12345", { status: "resolved" });
506
+ \`\`\``,
507
+ ja: `### \u30C4\u30FC\u30EB
508
+
509
+ - \`sentry_request\`: Sentry API\u3078\u306E\u8A8D\u8A3C\u6E08\u307F\u30EA\u30AF\u30A8\u30B9\u30C8\u3092\u9001\u4FE1\u3057\u307E\u3059\u3002GET, POST, PUT, DELETE\u30E1\u30BD\u30C3\u30C9\u3092\u30B5\u30DD\u30FC\u30C8\u3057\u307E\u3059\u3002Bearer token\u306B\u3088\u308B\u8A8D\u8A3C\u306F\u81EA\u52D5\u3067\u884C\u308F\u308C\u307E\u3059\u3002\u30D1\u30B9\u5185\u306E{organizationSlug}\u30D7\u30EC\u30FC\u30B9\u30DB\u30EB\u30C0\u30FC\u306F\u8A2D\u5B9A\u6E08\u307F\u306E\u7D44\u7E54\u30B9\u30E9\u30C3\u30B0\u3067\u81EA\u52D5\u7684\u306B\u7F6E\u63DB\u3055\u308C\u307E\u3059\u3002
510
+
511
+ ### Sentry API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
512
+
513
+ #### \u7D44\u7E54 & \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8
514
+ - GET \`/organizations/{organizationSlug}/\` \u2014 \u7D44\u7E54\u306E\u8A73\u7D30\u3092\u53D6\u5F97
515
+ - GET \`/organizations/{organizationSlug}/projects/\` \u2014 \u5168\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u4E00\u89A7\u8868\u793A
516
+
517
+ #### \u30A4\u30B7\u30E5\u30FC
518
+ - GET \`/organizations/{organizationSlug}/issues/\` \u2014 \u30A4\u30B7\u30E5\u30FC\u4E00\u89A7\uFF08\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF: \`query\`, \`sort\`, \`project\`, \`cursor\`\uFF09
519
+ - GET \`/organizations/{organizationSlug}/issues/{issueId}/\` \u2014 \u30A4\u30B7\u30E5\u30FC\u306E\u8A73\u7D30\u3092\u53D6\u5F97
520
+ - PUT \`/organizations/{organizationSlug}/issues/{issueId}/\` \u2014 \u30A4\u30B7\u30E5\u30FC\u306E\u66F4\u65B0\uFF08\u89E3\u6C7A\u3001\u7121\u8996\u3001\u62C5\u5F53\u8005\u5272\u308A\u5F53\u3066\uFF09\u3002Body: \`{ "status": "resolved" }\` \u307E\u305F\u306F \`{ "assignedTo": "user:id" }\`
521
+ - DELETE \`/organizations/{organizationSlug}/issues/{issueId}/\` \u2014 \u30A4\u30B7\u30E5\u30FC\u306E\u524A\u9664
522
+
523
+ #### \u30A4\u30D9\u30F3\u30C8
524
+ - GET \`/organizations/{organizationSlug}/issues/{issueId}/events/\` \u2014 \u30A4\u30B7\u30E5\u30FC\u306E\u30A4\u30D9\u30F3\u30C8\u4E00\u89A7
525
+ - GET \`/organizations/{organizationSlug}/issues/{issueId}/events/latest/\` \u2014 \u30A4\u30B7\u30E5\u30FC\u306E\u6700\u65B0\u30A4\u30D9\u30F3\u30C8
526
+ - GET \`/organizations/{organizationSlug}/events/{eventId}/\` \u2014 \u30A4\u30D9\u30F3\u30C8\u306E\u8A73\u7D30
527
+
528
+ #### \u30BF\u30B0 & \u7D71\u8A08
529
+ - GET \`/organizations/{organizationSlug}/issues/{issueId}/tags/\` \u2014 \u30A4\u30B7\u30E5\u30FC\u306E\u30BF\u30B0\u4E00\u89A7
530
+ - GET \`/organizations/{organizationSlug}/issues/{issueId}/tags/{tagKey}/values/\` \u2014 \u30BF\u30B0\u5024\u306E\u4E00\u89A7
531
+
532
+ #### \u30A4\u30B7\u30E5\u30FC\u691C\u7D22\u30AF\u30A8\u30EA\u69CB\u6587
533
+ - \`is:unresolved\` \u2014 \u672A\u89E3\u6C7A\u306E\u30A4\u30B7\u30E5\u30FC
534
+ - \`is:resolved\` \u2014 \u89E3\u6C7A\u6E08\u307F\u306E\u30A4\u30B7\u30E5\u30FC
535
+ - \`is:ignored\` \u2014 \u7121\u8996\u3055\u308C\u305F\u30A4\u30B7\u30E5\u30FC
536
+ - \`assigned:me\` \u2014 \u81EA\u5206\u306B\u5272\u308A\u5F53\u3066\u3089\u308C\u305F\u30A4\u30B7\u30E5\u30FC
537
+ - \`assigned:none\` \u2014 \u672A\u5272\u308A\u5F53\u3066\u306E\u30A4\u30B7\u30E5\u30FC
538
+ - \`level:error\` \u2014 \u30EC\u30D9\u30EB\u3067\u30D5\u30A3\u30EB\u30BF\uFF08fatal, error, warning, info, debug\uFF09
539
+ - \`project:my-project\` \u2014 \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30B9\u30E9\u30C3\u30B0\u3067\u30D5\u30A3\u30EB\u30BF
540
+ - \`first-seen:>2024-01-01\` \u2014 \u6307\u5B9A\u65E5\u4EE5\u964D\u306B\u521D\u3081\u3066\u767A\u751F
541
+ - \`last-seen:<24h\` \u2014 24\u6642\u9593\u4EE5\u5185\u306B\u6700\u5F8C\u306B\u767A\u751F
542
+ - \`times-seen:>100\` \u2014 100\u56DE\u4EE5\u4E0A\u767A\u751F
543
+ - \u30B9\u30DA\u30FC\u30B9\u3067\u7D44\u307F\u5408\u308F\u305B: \`is:unresolved level:error project:backend\`
544
+
545
+ #### \u30BD\u30FC\u30C8\u30AA\u30D7\u30B7\u30E7\u30F3
546
+ - \`date\` \u2014 \u6700\u7D42\u78BA\u8A8D\u65E5\uFF08\u30C7\u30D5\u30A9\u30EB\u30C8\uFF09
547
+ - \`new\` \u2014 \u521D\u56DE\u78BA\u8A8D\u65E5
548
+ - \`freq\` \u2014 \u983B\u5EA6\uFF08\u9AD8\u3044\u9806\uFF09
549
+ - \`priority\` \u2014 \u512A\u5148\u5EA6
550
+
551
+ ### \u30D2\u30F3\u30C8
552
+ - \u30D1\u30B9\u306B \`{organizationSlug}\` \u30D7\u30EC\u30FC\u30B9\u30DB\u30EB\u30C0\u30FC\u3092\u4F7F\u7528 \u2014 \u8A2D\u5B9A\u6E08\u307F\u306E\u7D44\u7E54\u30B9\u30E9\u30C3\u30B0\u3067\u81EA\u52D5\u7684\u306B\u7F6E\u63DB\u3055\u308C\u307E\u3059
553
+ - Sentry API\u306E\u30EC\u30B9\u30DD\u30F3\u30B9\u306F\u30DA\u30FC\u30B8\u30CD\u30FC\u30B7\u30E7\u30F3\u5BFE\u5FDC\u3067\u3059\u3002\`Link\`\u30D8\u30C3\u30C0\u30FC\u3067\u30AB\u30FC\u30BD\u30EB\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044
554
+ - \u30A4\u30B7\u30E5\u30FCID\u306F\u6570\u5024\u3067\u3059\u3002\u30B7\u30E7\u30FC\u30C8ID\uFF08\u4F8B: \`PROJECT-123\`\uFF09\u306F\`query\`\u30D1\u30E9\u30E1\u30FC\u30BF\u3067\u4F7F\u7528\u3067\u304D\u307E\u3059: \`query=PROJECT-123\`
555
+ - \u30A4\u30B7\u30E5\u30FC\u3092\u89E3\u6C7A\u3059\u308B\u306B\u306F: PUT\u3067 \`{ "status": "resolved" }\`
556
+ - \u30A4\u30B7\u30E5\u30FC\u3092\u7121\u8996\u3059\u308B\u306B\u306F: PUT\u3067 \`{ "status": "ignored" }\`
557
+
558
+ ### Business Logic
559
+
560
+ \u3053\u306E\u30B3\u30CD\u30AF\u30BF\u306E\u30D3\u30B8\u30CD\u30B9\u30ED\u30B8\u30C3\u30AF\u30BF\u30A4\u30D7\u306F "typescript" \u3067\u3059\u3002\u4EE5\u4E0B\u306B\u793A\u3059\u30B3\u30CD\u30AF\u30BFSDK\u3092\u4F7F\u7528\u3057\u3066\u30CF\u30F3\u30C9\u30E9\u30B3\u30FC\u30C9\u3092\u8A18\u8FF0\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u74B0\u5883\u5909\u6570\u304B\u3089\u76F4\u63A5\u8A8D\u8A3C\u60C5\u5831\u306B\u30A2\u30AF\u30BB\u30B9\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
561
+
562
+ #### Example
563
+
564
+ \`\`\`ts
565
+ import { connection } from "@squadbase/vite-server/connectors/sentry";
566
+
567
+ const sentry = connection("<connectionId>");
568
+
569
+ // \u5168\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u4E00\u89A7\u8868\u793A
570
+ const projects = await sentry.listProjects();
571
+ console.log(projects.map(p => p.slug));
572
+
573
+ // \u672A\u89E3\u6C7A\u30A4\u30B7\u30E5\u30FC\u3092\u983B\u5EA6\u9806\u3067\u4E00\u89A7\u8868\u793A
574
+ const issues = await sentry.listIssues({ query: "is:unresolved", sort: "freq" });
575
+ issues.forEach(issue => console.log(issue.shortId, issue.title, issue.count));
576
+
577
+ // \u30A4\u30B7\u30E5\u30FC\u306E\u8A73\u7D30\u3092\u53D6\u5F97
578
+ const issue = await sentry.getIssue("12345");
579
+ console.log(issue.title, issue.status, issue.lastSeen);
580
+
581
+ // \u30A4\u30B7\u30E5\u30FC\u306E\u30A4\u30D9\u30F3\u30C8\u4E00\u89A7\u3092\u53D6\u5F97
582
+ const events = await sentry.listIssueEvents("12345");
583
+ events.forEach(e => console.log(e.dateCreated, e.message));
584
+
585
+ // \u30A4\u30B7\u30E5\u30FC\u3092\u89E3\u6C7A\u3059\u308B
586
+ await sentry.updateIssue("12345", { status: "resolved" });
587
+ \`\`\``
588
+ },
589
+ tools,
590
+ async checkConnection(params) {
591
+ const authToken = params[parameters.authToken.slug];
592
+ const organizationSlug = params[parameters.organizationSlug.slug];
593
+ if (!authToken || !organizationSlug) {
594
+ return {
595
+ success: false,
596
+ error: "Missing required parameters: auth-token and organization-slug"
597
+ };
598
+ }
599
+ const url = `https://sentry.io/api/0/organizations/${organizationSlug}/`;
600
+ try {
601
+ const res = await fetch(url, {
602
+ method: "GET",
603
+ headers: {
604
+ Authorization: `Bearer ${authToken}`,
605
+ Accept: "application/json"
606
+ }
607
+ });
608
+ if (!res.ok) {
609
+ const errorText = await res.text().catch(() => res.statusText);
610
+ return {
611
+ success: false,
612
+ error: `Sentry API failed: HTTP ${res.status} ${errorText}`
613
+ };
614
+ }
615
+ return { success: true };
616
+ } catch (error) {
617
+ return {
618
+ success: false,
619
+ error: error instanceof Error ? error.message : String(error)
620
+ };
621
+ }
622
+ }
623
+ });
624
+
625
+ // src/connectors/create-connector-sdk.ts
626
+ import { readFileSync } from "fs";
627
+ import path from "path";
628
+
629
+ // src/connector-client/env.ts
630
+ function resolveEnvVar(entry, key, connectionId) {
631
+ const envVarName = entry.envVars[key];
632
+ if (!envVarName) {
633
+ throw new Error(`Connection "${connectionId}" is missing envVars mapping for key "${key}"`);
634
+ }
635
+ const value = process.env[envVarName];
636
+ if (!value) {
637
+ throw new Error(`Environment variable "${envVarName}" (for connection "${connectionId}", key "${key}") is not set`);
638
+ }
639
+ return value;
640
+ }
641
+ function resolveEnvVarOptional(entry, key) {
642
+ const envVarName = entry.envVars[key];
643
+ if (!envVarName) return void 0;
644
+ return process.env[envVarName] || void 0;
645
+ }
646
+
647
+ // src/connector-client/proxy-fetch.ts
648
+ import { getContext } from "hono/context-storage";
649
+ import { getCookie } from "hono/cookie";
650
+ var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
651
+ function createSandboxProxyFetch(connectionId) {
652
+ return async (input, init) => {
653
+ const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
654
+ const sandboxId = process.env.INTERNAL_SQUADBASE_SANDBOX_ID;
655
+ if (!token || !sandboxId) {
656
+ throw new Error(
657
+ "Connection proxy is not configured. Please check your deployment settings."
658
+ );
659
+ }
660
+ const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
661
+ const originalMethod = init?.method ?? "GET";
662
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
663
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
664
+ const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
665
+ return fetch(proxyUrl, {
666
+ method: "POST",
667
+ headers: {
668
+ "Content-Type": "application/json",
669
+ Authorization: `Bearer ${token}`
670
+ },
671
+ body: JSON.stringify({
672
+ url: originalUrl,
673
+ method: originalMethod,
674
+ body: originalBody
675
+ })
676
+ });
677
+ };
678
+ }
679
+ function createDeployedAppProxyFetch(connectionId) {
680
+ const projectId = process.env["SQUADBASE_PROJECT_ID"];
681
+ if (!projectId) {
682
+ throw new Error(
683
+ "Connection proxy is not configured. Please check your deployment settings."
684
+ );
685
+ }
686
+ const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
687
+ const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
688
+ return async (input, init) => {
689
+ const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
690
+ const originalMethod = init?.method ?? "GET";
691
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
692
+ const c = getContext();
693
+ const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
694
+ if (!appSession) {
695
+ throw new Error(
696
+ "No authentication method available for connection proxy."
697
+ );
698
+ }
699
+ return fetch(proxyUrl, {
700
+ method: "POST",
701
+ headers: {
702
+ "Content-Type": "application/json",
703
+ Authorization: `Bearer ${appSession}`
704
+ },
705
+ body: JSON.stringify({
706
+ url: originalUrl,
707
+ method: originalMethod,
708
+ body: originalBody
709
+ })
710
+ });
711
+ };
712
+ }
713
+ function createProxyFetch(connectionId) {
714
+ if (process.env.INTERNAL_SQUADBASE_SANDBOX_ID) {
715
+ return createSandboxProxyFetch(connectionId);
716
+ }
717
+ return createDeployedAppProxyFetch(connectionId);
718
+ }
719
+
720
+ // src/connectors/create-connector-sdk.ts
721
+ function loadConnectionsSync() {
722
+ const filePath = process.env.CONNECTIONS_PATH ?? path.join(process.cwd(), ".squadbase/connections.json");
723
+ try {
724
+ const raw = readFileSync(filePath, "utf-8");
725
+ return JSON.parse(raw);
726
+ } catch {
727
+ return {};
728
+ }
729
+ }
730
+ function createConnectorSdk(plugin, createClient2) {
731
+ return (connectionId) => {
732
+ const connections = loadConnectionsSync();
733
+ const entry = connections[connectionId];
734
+ if (!entry) {
735
+ throw new Error(
736
+ `Connection "${connectionId}" not found in .squadbase/connections.json`
737
+ );
738
+ }
739
+ if (entry.connector.slug !== plugin.slug) {
740
+ throw new Error(
741
+ `Connection "${connectionId}" is not a ${plugin.slug} connection (got "${entry.connector.slug}")`
742
+ );
743
+ }
744
+ const params = {};
745
+ for (const param of Object.values(plugin.parameters)) {
746
+ if (param.required) {
747
+ params[param.slug] = resolveEnvVar(entry, param.slug, connectionId);
748
+ } else {
749
+ const val = resolveEnvVarOptional(entry, param.slug);
750
+ if (val !== void 0) params[param.slug] = val;
751
+ }
752
+ }
753
+ return createClient2(params, createProxyFetch(connectionId));
754
+ };
755
+ }
756
+
757
+ // src/connectors/entries/sentry.ts
758
+ var connection = createConnectorSdk(sentryConnector, createClient);
759
+ export {
760
+ connection
761
+ };