@squadbase/vite-server 0.1.3-dev.9 → 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.
- package/dist/cli/index.js +14229 -29321
- package/dist/connectors/airtable-oauth.js +43 -6
- package/dist/connectors/airtable.js +43 -6
- package/dist/connectors/amplitude.js +43 -6
- package/dist/connectors/anthropic.js +43 -6
- package/dist/connectors/asana.js +43 -6
- package/dist/connectors/attio.js +43 -6
- package/dist/connectors/{google-ads-oauth.d.ts → backlog-api-key.d.ts} +1 -1
- package/dist/connectors/backlog-api-key.js +629 -0
- package/dist/connectors/customerio.js +43 -6
- package/dist/connectors/dbt.js +43 -6
- package/dist/connectors/{google-sheets-oauth.d.ts → gamma.d.ts} +1 -1
- package/dist/connectors/gamma.js +866 -0
- package/dist/connectors/gemini.js +43 -6
- package/dist/connectors/gmail-oauth.js +65 -8
- package/dist/connectors/gmail.js +104 -44
- package/dist/connectors/google-ads.d.ts +1 -1
- package/dist/connectors/google-ads.js +410 -332
- package/dist/connectors/google-analytics-oauth.js +61 -8
- package/dist/connectors/google-analytics.js +107 -292
- package/dist/connectors/google-calendar-oauth.js +61 -8
- package/dist/connectors/google-calendar.js +111 -58
- package/dist/connectors/{linkedin-ads-oauth.d.ts → google-docs.d.ts} +1 -1
- package/dist/connectors/google-docs.js +631 -0
- package/dist/connectors/google-drive.d.ts +5 -0
- package/dist/connectors/google-drive.js +875 -0
- package/dist/connectors/google-sheets.d.ts +1 -1
- package/dist/connectors/google-sheets.js +267 -285
- package/dist/connectors/google-slides.d.ts +5 -0
- package/dist/connectors/google-slides.js +663 -0
- package/dist/connectors/grafana.js +43 -6
- package/dist/connectors/hubspot-oauth.js +43 -6
- package/dist/connectors/hubspot.js +43 -6
- package/dist/connectors/intercom-oauth.js +43 -6
- package/dist/connectors/intercom.js +43 -6
- package/dist/connectors/jira-api-key.js +43 -6
- package/dist/connectors/kintone-api-token.js +256 -82
- package/dist/connectors/kintone.js +43 -6
- package/dist/connectors/linkedin-ads.js +188 -168
- package/dist/connectors/mailchimp-oauth.js +43 -6
- package/dist/connectors/mailchimp.js +43 -6
- package/dist/connectors/mixpanel.d.ts +5 -0
- package/dist/connectors/mixpanel.js +779 -0
- package/dist/connectors/notion-oauth.js +43 -6
- package/dist/connectors/notion.js +43 -6
- package/dist/connectors/openai.js +43 -6
- package/dist/connectors/sentry.d.ts +5 -0
- package/dist/connectors/sentry.js +761 -0
- package/dist/connectors/shopify-oauth.js +43 -6
- package/dist/connectors/shopify.js +43 -6
- package/dist/connectors/stripe-api-key.js +46 -7
- package/dist/connectors/stripe-oauth.js +43 -6
- package/dist/connectors/wix-store.js +43 -6
- package/dist/connectors/zendesk-oauth.js +43 -6
- package/dist/connectors/zendesk.js +43 -6
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4476 -3949
- package/dist/main.js +4474 -3948
- package/dist/vite-plugin.js +4474 -3948
- package/package.json +30 -12
- package/dist/connectors/google-ads-oauth.js +0 -890
- package/dist/connectors/google-sheets-oauth.js +0 -718
- 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
|
+
};
|