@squadbase/vite-server 0.1.9-dev.b193824 → 0.1.9-dev.e22f810

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 (43) hide show
  1. package/dist/cli/index.js +4989 -433
  2. package/dist/connectors/asana.js +15 -2
  3. package/dist/connectors/aws-billing.js +1 -1
  4. package/dist/connectors/azure-sql.d.ts +5 -0
  5. package/dist/connectors/azure-sql.js +682 -0
  6. package/dist/connectors/clickup.d.ts +5 -0
  7. package/dist/connectors/clickup.js +850 -0
  8. package/dist/connectors/freshdesk.d.ts +5 -0
  9. package/dist/connectors/freshdesk.js +842 -0
  10. package/dist/connectors/freshsales.d.ts +5 -0
  11. package/dist/connectors/freshsales.js +867 -0
  12. package/dist/connectors/freshservice.d.ts +5 -0
  13. package/dist/connectors/freshservice.js +813 -0
  14. package/dist/connectors/github.d.ts +5 -0
  15. package/dist/connectors/github.js +963 -0
  16. package/dist/connectors/gmail-oauth.js +15 -2
  17. package/dist/connectors/gmail.js +23 -14
  18. package/dist/connectors/google-audit-log.js +25 -14
  19. package/dist/connectors/google-calendar-oauth.js +18 -2
  20. package/dist/connectors/google-calendar.js +40 -26
  21. package/dist/connectors/google-docs.js +18 -2
  22. package/dist/connectors/google-drive.js +15 -2
  23. package/dist/connectors/google-search-console-oauth.d.ts +5 -0
  24. package/dist/connectors/google-search-console-oauth.js +954 -0
  25. package/dist/connectors/google-sheets.js +18 -2
  26. package/dist/connectors/google-slides.js +18 -2
  27. package/dist/connectors/jdbc.d.ts +5 -0
  28. package/dist/connectors/jdbc.js +21521 -0
  29. package/dist/connectors/monday.d.ts +5 -0
  30. package/dist/connectors/monday.js +853 -0
  31. package/dist/connectors/oracle.d.ts +5 -0
  32. package/dist/connectors/oracle.js +689 -0
  33. package/dist/connectors/semrush.d.ts +5 -0
  34. package/dist/connectors/semrush.js +825 -0
  35. package/dist/connectors/sqlserver.d.ts +5 -0
  36. package/dist/connectors/sqlserver.js +679 -0
  37. package/dist/connectors/supabase.d.ts +5 -0
  38. package/dist/connectors/supabase.js +582 -0
  39. package/dist/connectors/tiktok-ads.js +15 -2
  40. package/dist/index.js +5066 -510
  41. package/dist/main.js +4975 -419
  42. package/dist/vite-plugin.js +4975 -419
  43. package/package.json +56 -2
@@ -0,0 +1,867 @@
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/freshsales/parameters.ts
46
+ var parameters = {
47
+ bundleAlias: new ParameterDefinition({
48
+ slug: "bundle-alias",
49
+ name: "Freshsales Bundle Alias",
50
+ description: "Your Freshsales / Freshworks CRM bundle alias (the subdomain on `myfreshworks.com` \u2014 e.g. `acme` for `https://acme.myfreshworks.com`). Provide just the subdomain without `https://`.",
51
+ envVarBaseKey: "FRESHSALES_BUNDLE_ALIAS",
52
+ type: "text",
53
+ secret: false,
54
+ required: true
55
+ }),
56
+ apiKey: new ParameterDefinition({
57
+ slug: "api-key",
58
+ name: "Freshsales API Key",
59
+ description: "API key for Freshsales / Freshworks CRM. Find it in CRM \u2192 Personal Settings \u2192 API Settings. The key is sent in the `Authorization: Token token=<key>` header.",
60
+ envVarBaseKey: "FRESHSALES_API_KEY",
61
+ type: "text",
62
+ secret: true,
63
+ required: true
64
+ })
65
+ };
66
+
67
+ // ../connectors/src/connectors/freshsales/sdk/index.ts
68
+ function buildBaseUrl(bundleAlias) {
69
+ const trimmed = bundleAlias.trim().replace(/^https?:\/\//, "").replace(/\/+$/, "");
70
+ const subdomain = trimmed.split(".")[0];
71
+ return `https://${subdomain}.myfreshworks.com/crm/sales/api`;
72
+ }
73
+ function createClient(params) {
74
+ const apiKey = params[parameters.apiKey.slug];
75
+ const bundle = params[parameters.bundleAlias.slug];
76
+ if (!apiKey) {
77
+ throw new Error(
78
+ `freshsales: missing required parameter: ${parameters.apiKey.slug}`
79
+ );
80
+ }
81
+ if (!bundle) {
82
+ throw new Error(
83
+ `freshsales: missing required parameter: ${parameters.bundleAlias.slug}`
84
+ );
85
+ }
86
+ const baseUrl = buildBaseUrl(bundle);
87
+ const auth = `Token token=${apiKey}`;
88
+ function authHeaders(extra) {
89
+ const headers = new Headers(extra);
90
+ headers.set("Authorization", auth);
91
+ headers.set("Content-Type", "application/json");
92
+ headers.set("Accept", "application/json");
93
+ return headers;
94
+ }
95
+ async function assertOk(res, label) {
96
+ if (!res.ok) {
97
+ const body = await res.text().catch(() => "(unreadable body)");
98
+ throw new Error(
99
+ `freshsales ${label}: ${res.status} ${res.statusText} \u2014 ${body}`
100
+ );
101
+ }
102
+ }
103
+ function buildQuery(base) {
104
+ const search = new URLSearchParams();
105
+ for (const [key, value] of Object.entries(base)) {
106
+ if (value !== void 0) search.set(key, String(value));
107
+ }
108
+ const qs = search.toString();
109
+ return qs ? `?${qs}` : "";
110
+ }
111
+ return {
112
+ request(path2, init) {
113
+ const headers = new Headers(init?.headers);
114
+ headers.set("Authorization", auth);
115
+ if (!headers.has("Content-Type")) {
116
+ headers.set("Content-Type", "application/json");
117
+ }
118
+ if (!headers.has("Accept")) {
119
+ headers.set("Accept", "application/json");
120
+ }
121
+ return fetch(`${baseUrl}${path2}`, { ...init, headers });
122
+ },
123
+ async listContactViews() {
124
+ const res = await fetch(`${baseUrl}/contacts/filters`, {
125
+ method: "GET",
126
+ headers: authHeaders()
127
+ });
128
+ await assertOk(res, "listContactViews");
129
+ return await res.json();
130
+ },
131
+ async listContactsInView(viewId, options) {
132
+ const qs = buildQuery({
133
+ page: options?.page,
134
+ per_page: options?.per_page,
135
+ sort: options?.sort,
136
+ sort_type: options?.sort_type,
137
+ include: options?.include
138
+ });
139
+ const res = await fetch(
140
+ `${baseUrl}/contacts/view/${encodeURIComponent(String(viewId))}${qs}`,
141
+ { method: "GET", headers: authHeaders() }
142
+ );
143
+ await assertOk(res, "listContactsInView");
144
+ return await res.json();
145
+ },
146
+ async getContact(contactId, options) {
147
+ const qs = buildQuery({ include: options?.include });
148
+ const res = await fetch(
149
+ `${baseUrl}/contacts/${encodeURIComponent(String(contactId))}${qs}`,
150
+ { method: "GET", headers: authHeaders() }
151
+ );
152
+ await assertOk(res, "getContact");
153
+ return await res.json();
154
+ },
155
+ async createContact(contactData) {
156
+ const res = await fetch(`${baseUrl}/contacts`, {
157
+ method: "POST",
158
+ headers: authHeaders(),
159
+ body: JSON.stringify({ contact: contactData })
160
+ });
161
+ await assertOk(res, "createContact");
162
+ return await res.json();
163
+ },
164
+ async updateContact(contactId, contactData) {
165
+ const res = await fetch(
166
+ `${baseUrl}/contacts/${encodeURIComponent(String(contactId))}`,
167
+ {
168
+ method: "PUT",
169
+ headers: authHeaders(),
170
+ body: JSON.stringify({ contact: contactData })
171
+ }
172
+ );
173
+ await assertOk(res, "updateContact");
174
+ return await res.json();
175
+ },
176
+ async listAccountViews() {
177
+ const res = await fetch(`${baseUrl}/sales_accounts/filters`, {
178
+ method: "GET",
179
+ headers: authHeaders()
180
+ });
181
+ await assertOk(res, "listAccountViews");
182
+ return await res.json();
183
+ },
184
+ async listAccountsInView(viewId, options) {
185
+ const qs = buildQuery({
186
+ page: options?.page,
187
+ per_page: options?.per_page,
188
+ include: options?.include
189
+ });
190
+ const res = await fetch(
191
+ `${baseUrl}/sales_accounts/view/${encodeURIComponent(String(viewId))}${qs}`,
192
+ { method: "GET", headers: authHeaders() }
193
+ );
194
+ await assertOk(res, "listAccountsInView");
195
+ return await res.json();
196
+ },
197
+ async listDealViews() {
198
+ const res = await fetch(`${baseUrl}/deals/filters`, {
199
+ method: "GET",
200
+ headers: authHeaders()
201
+ });
202
+ await assertOk(res, "listDealViews");
203
+ return await res.json();
204
+ },
205
+ async listDealsInView(viewId, options) {
206
+ const qs = buildQuery({
207
+ page: options?.page,
208
+ per_page: options?.per_page,
209
+ include: options?.include
210
+ });
211
+ const res = await fetch(
212
+ `${baseUrl}/deals/view/${encodeURIComponent(String(viewId))}${qs}`,
213
+ { method: "GET", headers: authHeaders() }
214
+ );
215
+ await assertOk(res, "listDealsInView");
216
+ return await res.json();
217
+ },
218
+ async getDeal(dealId, options) {
219
+ const qs = buildQuery({ include: options?.include });
220
+ const res = await fetch(
221
+ `${baseUrl}/deals/${encodeURIComponent(String(dealId))}${qs}`,
222
+ { method: "GET", headers: authHeaders() }
223
+ );
224
+ await assertOk(res, "getDeal");
225
+ return await res.json();
226
+ },
227
+ async lookup(query) {
228
+ const qs = buildQuery({
229
+ q: query.q,
230
+ f: query.f,
231
+ entities: query.entities
232
+ });
233
+ const res = await fetch(`${baseUrl}/lookup${qs}`, {
234
+ method: "GET",
235
+ headers: authHeaders()
236
+ });
237
+ await assertOk(res, "lookup");
238
+ return await res.json();
239
+ }
240
+ };
241
+ }
242
+
243
+ // ../connectors/src/connector-onboarding.ts
244
+ var ConnectorOnboarding = class {
245
+ /** Phase 1: Connection setup instructions (optional — some connectors don't need this) */
246
+ connectionSetupInstructions;
247
+ /** Phase 2: Data overview instructions */
248
+ dataOverviewInstructions;
249
+ constructor(config) {
250
+ this.connectionSetupInstructions = config.connectionSetupInstructions;
251
+ this.dataOverviewInstructions = config.dataOverviewInstructions;
252
+ }
253
+ getConnectionSetupPrompt(language) {
254
+ return this.connectionSetupInstructions?.[language] ?? null;
255
+ }
256
+ getDataOverviewInstructions(language) {
257
+ return this.dataOverviewInstructions[language];
258
+ }
259
+ };
260
+
261
+ // ../connectors/src/connector-tool.ts
262
+ var ConnectorTool = class {
263
+ name;
264
+ description;
265
+ inputSchema;
266
+ outputSchema;
267
+ _execute;
268
+ constructor(config) {
269
+ this.name = config.name;
270
+ this.description = config.description;
271
+ this.inputSchema = config.inputSchema;
272
+ this.outputSchema = config.outputSchema;
273
+ this._execute = config.execute;
274
+ }
275
+ createTool(connections, config) {
276
+ return {
277
+ description: this.description,
278
+ inputSchema: this.inputSchema,
279
+ outputSchema: this.outputSchema,
280
+ execute: (input) => this._execute(input, connections, config)
281
+ };
282
+ }
283
+ };
284
+
285
+ // ../connectors/src/connector-plugin.ts
286
+ var ConnectorPlugin = class _ConnectorPlugin {
287
+ slug;
288
+ authType;
289
+ name;
290
+ description;
291
+ iconUrl;
292
+ parameters;
293
+ releaseFlag;
294
+ proxyPolicy;
295
+ experimentalAttributes;
296
+ categories;
297
+ onboarding;
298
+ systemPrompt;
299
+ tools;
300
+ query;
301
+ checkConnection;
302
+ constructor(config) {
303
+ this.slug = config.slug;
304
+ this.authType = config.authType;
305
+ this.name = config.name;
306
+ this.description = config.description;
307
+ this.iconUrl = config.iconUrl;
308
+ this.parameters = config.parameters;
309
+ this.releaseFlag = config.releaseFlag;
310
+ this.proxyPolicy = config.proxyPolicy;
311
+ this.experimentalAttributes = config.experimentalAttributes;
312
+ this.categories = config.categories ?? [];
313
+ this.onboarding = config.onboarding;
314
+ this.systemPrompt = config.systemPrompt;
315
+ this.tools = config.tools;
316
+ this.query = config.query;
317
+ this.checkConnection = config.checkConnection;
318
+ }
319
+ get connectorKey() {
320
+ return _ConnectorPlugin.deriveKey(this.slug, this.authType);
321
+ }
322
+ /**
323
+ * Create tools for connections that belong to this connector.
324
+ * Filters connections by connectorKey internally.
325
+ * Returns tools keyed as `${connectorKey}_${toolName}`.
326
+ */
327
+ createTools(connections, config, opts) {
328
+ const myConnections = connections.filter(
329
+ (c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
330
+ );
331
+ const result = {};
332
+ for (const t of Object.values(this.tools)) {
333
+ const tool = t.createTool(myConnections, config);
334
+ const originalToModelOutput = tool.toModelOutput;
335
+ result[`${this.connectorKey}_${t.name}`] = {
336
+ ...tool,
337
+ toModelOutput: async (options) => {
338
+ if (!originalToModelOutput) {
339
+ return opts.truncateOutput(options.output);
340
+ }
341
+ const modelOutput = await originalToModelOutput(options);
342
+ if (modelOutput.type === "text" || modelOutput.type === "json") {
343
+ return opts.truncateOutput(modelOutput.value);
344
+ }
345
+ return modelOutput;
346
+ }
347
+ };
348
+ }
349
+ return result;
350
+ }
351
+ static deriveKey(slug, authType) {
352
+ if (authType) return `${slug}-${authType}`;
353
+ const LEGACY_NULL_AUTH_TYPE_MAP = {
354
+ // user-password
355
+ "postgresql": "user-password",
356
+ "mysql": "user-password",
357
+ "clickhouse": "user-password",
358
+ "kintone": "user-password",
359
+ "squadbase-db": "user-password",
360
+ // service-account
361
+ "snowflake": "service-account",
362
+ "bigquery": "service-account",
363
+ "google-analytics": "service-account",
364
+ "google-calendar": "service-account",
365
+ "aws-athena": "service-account",
366
+ "redshift": "service-account",
367
+ // api-key
368
+ "databricks": "api-key",
369
+ "dbt": "api-key",
370
+ "airtable": "api-key",
371
+ "openai": "api-key",
372
+ "gemini": "api-key",
373
+ "anthropic": "api-key",
374
+ "wix-store": "api-key"
375
+ };
376
+ const fallbackAuthType = LEGACY_NULL_AUTH_TYPE_MAP[slug];
377
+ if (fallbackAuthType) return `${slug}-${fallbackAuthType}`;
378
+ return slug;
379
+ }
380
+ };
381
+
382
+ // ../connectors/src/auth-types.ts
383
+ var AUTH_TYPES = {
384
+ OAUTH: "oauth",
385
+ API_KEY: "api-key",
386
+ JWT: "jwt",
387
+ SERVICE_ACCOUNT: "service-account",
388
+ PAT: "pat",
389
+ USER_PASSWORD: "user-password"
390
+ };
391
+
392
+ // ../connectors/src/lib/normalize-path.ts
393
+ function normalizeRequestPath(path2, basePathSegment) {
394
+ let p = path2.trim();
395
+ if (!p.startsWith("/")) p = "/" + p;
396
+ if (p === basePathSegment || p.startsWith(basePathSegment + "/")) {
397
+ p = p.slice(basePathSegment.length) || "/";
398
+ }
399
+ return p;
400
+ }
401
+
402
+ // ../connectors/src/connectors/freshsales/setup.ts
403
+ var freshsalesOnboarding = new ConnectorOnboarding({
404
+ dataOverviewInstructions: {
405
+ en: `1. Call freshsales_request with GET /selector/owners to confirm credentials and discover sales team members.
406
+ 2. Call freshsales_request with GET /contacts/filters to list available contact views (filters), then GET /contacts/view/{view_id} to fetch contacts in a view (paginated with \`page\` and \`per_page\`, default 25, max 100).
407
+ 3. Repeat the same pattern for accounts (GET /sales_accounts/filters \u2192 /sales_accounts/view/{view_id}) and deals (GET /deals/filters \u2192 /deals/view/{view_id}).
408
+ 4. To inspect deal pipeline metadata, call GET /selector/deal_pipelines and GET /selector/deal_stages.
409
+ 5. Use GET /lookup to find specific records by attribute (e.g., look up a contact by email).`,
410
+ ja: `1. freshsales_request \u3067 GET /selector/owners \u3092\u547C\u3073\u51FA\u3057\u3001\u8A8D\u8A3C\u60C5\u5831\u306E\u78BA\u8A8D\u3068\u55B6\u696D\u30E1\u30F3\u30D0\u30FC\u306E\u4E00\u89A7\u3092\u53D6\u5F97\u3057\u307E\u3059\u3002
411
+ 2. freshsales_request \u3067 GET /contacts/filters \u3092\u547C\u3073\u51FA\u3057\u3066\u30D3\u30E5\u30FC\uFF08filters\uFF09\u4E00\u89A7\u3092\u53D6\u5F97\u3057\u3001GET /contacts/view/{view_id} \u3067\u5404\u30D3\u30E5\u30FC\u306E\u9023\u7D61\u5148\u3092\u53D6\u5F97\u3057\u307E\u3059\uFF08\`page\` \u3068 \`per_page\` \u3067\u30DA\u30FC\u30B8\u30F3\u30B0\u3001\u30C7\u30D5\u30A9\u30EB\u30C825\u3001\u6700\u5927100\uFF09\u3002
412
+ 3. \u540C\u3058\u30D1\u30BF\u30FC\u30F3\u3092\u53D6\u5F15\u5148\uFF08GET /sales_accounts/filters \u2192 /sales_accounts/view/{view_id}\uFF09\u3001\u5546\u8AC7\uFF08GET /deals/filters \u2192 /deals/view/{view_id}\uFF09\u306B\u3082\u9069\u7528\u3057\u307E\u3059\u3002
413
+ 4. \u5546\u8AC7\u30D1\u30A4\u30D7\u30E9\u30A4\u30F3\u306E\u30E1\u30BF\u60C5\u5831\u306F GET /selector/deal_pipelines \u304A\u3088\u3073 GET /selector/deal_stages \u3067\u53D6\u5F97\u3057\u307E\u3059\u3002
414
+ 5. \u7279\u5B9A\u30EC\u30B3\u30FC\u30C9\u3092\u5C5E\u6027\u3067\u691C\u7D22\u3059\u308B\u306B\u306F GET /lookup \u3092\u4F7F\u7528\u3057\u307E\u3059\uFF08\u4F8B: \u30E1\u30FC\u30EB\u3067\u9023\u7D61\u5148\u3092\u691C\u7D22\uFF09\u3002`
415
+ }
416
+ });
417
+
418
+ // ../connectors/src/connectors/freshsales/tools/request.ts
419
+ import { z } from "zod";
420
+ var BASE_PATH_SEGMENT = "/crm/sales/api";
421
+ var REQUEST_TIMEOUT_MS = 6e4;
422
+ function buildBaseUrl2(bundleAlias) {
423
+ const trimmed = bundleAlias.trim().replace(/^https?:\/\//, "").replace(/\/+$/, "");
424
+ const subdomain = trimmed.split(".")[0];
425
+ return `https://${subdomain}.myfreshworks.com${BASE_PATH_SEGMENT}`;
426
+ }
427
+ var inputSchema = z.object({
428
+ toolUseIntent: z.string().optional().describe(
429
+ "Brief description of what you intend to accomplish with this tool call"
430
+ ),
431
+ connectionId: z.string().describe("ID of the Freshsales connection to use"),
432
+ method: z.enum(["GET", "POST", "PUT", "DELETE"]).describe(
433
+ "HTTP method. GET for reading resources (including /lookup), POST for creating, PUT for updating, DELETE for removing."
434
+ ),
435
+ path: z.string().describe(
436
+ "API path (e.g., '/contacts', '/contacts/filters', '/contacts/view/{view_id}', '/deals/{id}', '/lookup'). Append query parameters such as '?page=1&per_page=100'."
437
+ ),
438
+ body: z.record(z.string(), z.unknown()).optional().describe(
439
+ 'Request body (JSON). For creating a contact: { "contact": { "first_name": "...", "last_name": "...", "email": "..." } }. For lookup: { "q": "john@example.com", "f": "email", "entities": "contact" }.'
440
+ )
441
+ });
442
+ var outputSchema = z.discriminatedUnion("success", [
443
+ z.object({
444
+ success: z.literal(true),
445
+ status: z.number(),
446
+ data: z.union([
447
+ z.record(z.string(), z.unknown()),
448
+ z.array(z.unknown())
449
+ ])
450
+ }),
451
+ z.object({
452
+ success: z.literal(false),
453
+ error: z.string()
454
+ })
455
+ ]);
456
+ var requestTool = new ConnectorTool({
457
+ name: "request",
458
+ description: `Send authenticated requests to the Freshsales / Freshworks CRM REST API.
459
+ Authentication uses the \`Authorization: Token token=<API_KEY>\` header (handled automatically \u2014 note this is NOT HTTP Basic Auth like Freshdesk/Freshservice).
460
+ Provide the API path relative to the base URL (https://<bundle>.myfreshworks.com/crm/sales/api).
461
+
462
+ Common endpoints:
463
+ - GET /contacts/filters \u2014 List contact views (saved filters)
464
+ - GET /contacts/view/{view_id} \u2014 List contacts in a view (paginated)
465
+ - GET /contacts/{id} \u2014 Get a contact (use ?include=owner,creator,deals for related data)
466
+ - POST /contacts \u2014 Create a contact (body: { "contact": { ... } })
467
+ - PUT /contacts/{id} \u2014 Update a contact
468
+ - GET /sales_accounts/filters \u2014 List account views
469
+ - GET /sales_accounts/view/{view_id} \u2014 Accounts in a view
470
+ - GET /deals/filters \u2014 Deal views
471
+ - GET /deals/view/{view_id} \u2014 Deals in a view
472
+ - GET /deals/{id} \u2014 Get a deal
473
+ - POST /deals \u2014 Create a deal
474
+ - GET /leads/filters \u2014 Lead views (legacy / Sales Cloud only)
475
+ - GET /sales_activities \u2014 List sales activities
476
+ - GET /lookup?q=...&f=email&entities=contact \u2014 Look up a record by attribute
477
+ - GET /selector/owners \u2014 Available owners (sales reps)
478
+ - GET /selector/deal_pipelines \u2014 Deal pipelines
479
+ - GET /selector/deal_stages \u2014 Deal stages
480
+ - GET /selector/deal_types \u2014 Deal types
481
+ - GET /selector/lifecycle_stages \u2014 Lifecycle stages
482
+
483
+ Pagination: 1-indexed \`page\` + \`per_page\` (default 25, max 100). View endpoints return \`{ contacts/sales_accounts/deals: [...], meta: { total_pages, total } }\`.
484
+
485
+ Includes: most GET endpoints accept \`?include=\` with a comma-separated list (\`owner\`, \`creator\`, \`deals\`, \`contacts\`, etc.) to inline related records.`,
486
+ inputSchema,
487
+ outputSchema,
488
+ async execute({ connectionId, method, path: path2, body }, connections) {
489
+ const connection2 = connections.find((c) => c.id === connectionId);
490
+ if (!connection2) {
491
+ return {
492
+ success: false,
493
+ error: `Connection ${connectionId} not found`
494
+ };
495
+ }
496
+ console.log(
497
+ `[connector-request] freshsales/${connection2.name}: ${method} ${path2}`
498
+ );
499
+ try {
500
+ const apiKey = parameters.apiKey.getValue(connection2);
501
+ const bundle = parameters.bundleAlias.getValue(connection2);
502
+ const baseUrl = buildBaseUrl2(bundle);
503
+ const normalizedPath = normalizeRequestPath(path2, BASE_PATH_SEGMENT);
504
+ const url = `${baseUrl}${normalizedPath}`;
505
+ const controller = new AbortController();
506
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
507
+ try {
508
+ const response = await fetch(url, {
509
+ method,
510
+ headers: {
511
+ Authorization: `Token token=${apiKey}`,
512
+ "Content-Type": "application/json",
513
+ Accept: "application/json"
514
+ },
515
+ body: body ? JSON.stringify(body) : void 0,
516
+ signal: controller.signal
517
+ });
518
+ const text = await response.text();
519
+ const data = text ? JSON.parse(text) : {};
520
+ if (!response.ok) {
521
+ const errObj = !Array.isArray(data) ? data : {};
522
+ const errorsField = errObj.errors;
523
+ const message = typeof errObj.message === "string" && errObj.message || (errorsField && typeof errorsField.message === "string" ? errorsField.message : null);
524
+ const errorMessage = message ? String(message) : `HTTP ${response.status} ${response.statusText}`;
525
+ return { success: false, error: errorMessage };
526
+ }
527
+ return { success: true, status: response.status, data };
528
+ } finally {
529
+ clearTimeout(timeout);
530
+ }
531
+ } catch (err) {
532
+ const msg = err instanceof Error ? err.message : String(err);
533
+ return { success: false, error: msg };
534
+ }
535
+ }
536
+ });
537
+
538
+ // ../connectors/src/connectors/freshsales/index.ts
539
+ var tools = { request: requestTool };
540
+ var freshsalesConnector = new ConnectorPlugin({
541
+ slug: "freshsales",
542
+ authType: AUTH_TYPES.API_KEY,
543
+ name: "Freshsales",
544
+ description: "Connect to Freshsales / Freshworks CRM for contact, account, and deal data via API key.",
545
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/4UDOrFPM6wOFekbMVljjgl/4acc6060c3a1ff703980e6f4e76a3cd4/629b6c6f7c5cd817694c321f.png",
546
+ parameters,
547
+ releaseFlag: { dev1: true, dev2: true, prod: true },
548
+ categories: ["crm"],
549
+ onboarding: freshsalesOnboarding,
550
+ systemPrompt: {
551
+ en: `### Tools
552
+
553
+ - \`freshsales_request\`: The only way to call the Freshsales / Freshworks CRM REST API. Use it to list and update contacts, accounts, deals, leads, sales activities, and selector metadata. Authentication (\`Authorization: Token token=<API_KEY>\` header \u2014 note: NOT HTTP Basic Auth) and the base URL (https://<bundle>.myfreshworks.com/crm/sales/api) are configured automatically.
554
+
555
+ ### Business Logic
556
+
557
+ The business logic type for this connector is "typescript". Use the connector SDK in your handler. Do NOT read credentials from environment variables.
558
+
559
+ SDK methods (client created via \`connection(connectionId)\`):
560
+ - \`client.request(path, init?)\` \u2014 low-level authenticated fetch
561
+ - \`client.listContactViews()\` / \`client.listContactsInView(viewId, options?)\` \u2014 list contacts via a saved view
562
+ - \`client.getContact(contactId, options?)\` \u2014 get a single contact
563
+ - \`client.createContact(contactData)\` / \`client.updateContact(contactId, contactData)\` \u2014 write contacts
564
+ - \`client.listAccountViews()\` / \`client.listAccountsInView(viewId, options?)\` \u2014 sales accounts
565
+ - \`client.listDealViews()\` / \`client.listDealsInView(viewId, options?)\` / \`client.getDeal(dealId, options?)\` \u2014 deals
566
+ - \`client.lookup({ q, f, entities })\` \u2014 find a record by attribute (e.g. lookup contact by email)
567
+
568
+ \`\`\`ts
569
+ import type { Context } from "hono";
570
+ import { connection } from "@squadbase/vite-server/connectors/freshsales";
571
+
572
+ const fs = connection("<connectionId>");
573
+
574
+ export default async function handler(c: Context) {
575
+ const views = await fs.listDealViews();
576
+ const firstViewId = (views.filters[0] as { id: number }).id;
577
+ const { deals, meta } = await fs.listDealsInView(firstViewId, {
578
+ per_page: 100,
579
+ include: "owner,deal_stage,sales_account",
580
+ });
581
+ return c.json({ deals, totalPages: meta.total_pages });
582
+ }
583
+ \`\`\`
584
+
585
+ ### Freshsales / Freshworks CRM REST API Reference
586
+
587
+ - Base URL: \`https://<bundle>.myfreshworks.com/crm/sales/api\`
588
+ - Authentication: \`Authorization: Token token=<API_KEY>\` header (note: this is NOT HTTP Basic Auth like Freshdesk/Freshservice).
589
+ - Pagination: 1-indexed \`page\` + \`per_page\` (default 25, max 100). View list responses include \`meta: { total_pages, total }\`.
590
+ - Includes: most list/get endpoints accept \`?include=\` with a comma-separated list of related resources to inline.
591
+
592
+ #### Resource Endpoints
593
+
594
+ **Contacts**
595
+ - GET \`/contacts/filters\` \u2014 List saved views (a.k.a. filters)
596
+ - GET \`/contacts/view/{view_id}\` \u2014 Contacts in a view (paginated)
597
+ - GET \`/contacts/{id}\` \u2014 Get a contact (use \`?include=owner,creator,deals,sales_accounts\`)
598
+ - POST \`/contacts\` \u2014 Create a contact (body: \`{ "contact": { ... } }\`)
599
+ - PUT \`/contacts/{id}\` \u2014 Update a contact
600
+
601
+ **Sales accounts (companies)**
602
+ - GET \`/sales_accounts/filters\` \u2014 List saved views
603
+ - GET \`/sales_accounts/view/{view_id}\` \u2014 Accounts in a view
604
+ - GET \`/sales_accounts/{id}\` \u2014 Get an account
605
+ - POST \`/sales_accounts\` / PUT \`/sales_accounts/{id}\` \u2014 Write
606
+
607
+ **Deals**
608
+ - GET \`/deals/filters\` \u2014 List saved views
609
+ - GET \`/deals/view/{view_id}\` \u2014 Deals in a view
610
+ - GET \`/deals/{id}\` \u2014 Get a deal (use \`?include=owner,deal_stage,sales_account,contacts\`)
611
+ - POST \`/deals\` / PUT \`/deals/{id}\` \u2014 Write
612
+
613
+ **Leads (Sales Cloud only)**
614
+ - GET \`/leads/filters\` \u2014 Saved views
615
+ - GET \`/leads/view/{view_id}\` \u2014 Leads in a view
616
+ - GET \`/leads/{id}\` \u2014 Get a lead
617
+
618
+ **Sales activities & tasks**
619
+ - GET \`/sales_activities\` \u2014 List sales activities
620
+ - GET \`/tasks\` \u2014 List tasks
621
+ - GET \`/appointments\` \u2014 List appointments
622
+ - POST \`/notes\` \u2014 Create a note (body references a target contact/account/deal)
623
+
624
+ **Search & lookup**
625
+ - GET \`/lookup\` \u2014 Lookup a record by attribute. Query params: \`q\` (value), \`f\` (field \u2014 typically \`email\`/\`mobile_number\`), \`entities\` (\`contact\`/\`sales_account\`/\`deal\`/\`lead\`).
626
+
627
+ **Selector metadata**
628
+ - GET \`/selector/owners\` \u2014 Sales reps available as owners
629
+ - GET \`/selector/deal_pipelines\` \u2014 Pipelines
630
+ - GET \`/selector/deal_stages\` \u2014 Stages
631
+ - GET \`/selector/deal_types\` \u2014 Deal types
632
+ - GET \`/selector/lifecycle_stages\` \u2014 Lifecycle stages
633
+ - GET \`/selector/territories\` / \`/selector/business_types\` / \`/selector/industry_types\` / \`/selector/contact_statuses\` / \`/selector/sales_activity_types\``,
634
+ ja: `### \u30C4\u30FC\u30EB
635
+
636
+ - \`freshsales_request\`: Freshsales / Freshworks CRM REST API \u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\u3002\u9023\u7D61\u5148\u3001\u53D6\u5F15\u5148\u3001\u5546\u8AC7\u3001\u30EA\u30FC\u30C9\u3001\u55B6\u696D\u6D3B\u52D5\u3001\u5404\u7A2E\u30BB\u30EC\u30AF\u30BF\u30FC\u30E1\u30BF\u60C5\u5831\u306E\u53D6\u5F97\u30FB\u66F4\u65B0\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\u8A8D\u8A3C\uFF08\`Authorization: Token token=<API_KEY>\` \u30D8\u30C3\u30C0\u30FC \u2014 Freshdesk/Freshservice \u3068\u7570\u306A\u308A HTTP Basic Auth \u3067\u306F\u3042\u308A\u307E\u305B\u3093\uFF09\u3068\u30D9\u30FC\u30B9URL\uFF08https://<bundle>.myfreshworks.com/crm/sales/api\uFF09\u306F\u81EA\u52D5\u3067\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002
637
+
638
+ ### Business Logic
639
+
640
+ \u3053\u306E\u30B3\u30CD\u30AF\u30BF\u306E\u30D3\u30B8\u30CD\u30B9\u30ED\u30B8\u30C3\u30AF\u30BF\u30A4\u30D7\u306F "typescript" \u3067\u3059\u3002\u30CF\u30F3\u30C9\u30E9\u5185\u3067\u306F\u30B3\u30CD\u30AF\u30BFSDK\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u74B0\u5883\u5909\u6570\u304B\u3089\u8A8D\u8A3C\u60C5\u5831\u3092\u8AAD\u307F\u53D6\u3089\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
641
+
642
+ SDK\u30E1\u30BD\u30C3\u30C9 (\`connection(connectionId)\` \u3067\u4F5C\u6210\u3057\u305F\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8):
643
+ - \`client.request(path, init?)\` \u2014 \u4F4E\u30EC\u30D9\u30EB\u306E\u8A8D\u8A3C\u4ED8\u304Dfetch
644
+ - \`client.listContactViews()\` / \`client.listContactsInView(viewId, options?)\` \u2014 \u4FDD\u5B58\u30D3\u30E5\u30FC\u7D4C\u7531\u3067\u9023\u7D61\u5148\u4E00\u89A7\u3092\u53D6\u5F97
645
+ - \`client.getContact(contactId, options?)\` \u2014 \u5358\u4E00\u9023\u7D61\u5148\u306E\u53D6\u5F97
646
+ - \`client.createContact(contactData)\` / \`client.updateContact(contactId, contactData)\` \u2014 \u9023\u7D61\u5148\u306E\u4F5C\u6210\u30FB\u66F4\u65B0
647
+ - \`client.listAccountViews()\` / \`client.listAccountsInView(viewId, options?)\` \u2014 \u53D6\u5F15\u5148\uFF08sales_accounts\uFF09
648
+ - \`client.listDealViews()\` / \`client.listDealsInView(viewId, options?)\` / \`client.getDeal(dealId, options?)\` \u2014 \u5546\u8AC7
649
+ - \`client.lookup({ q, f, entities })\` \u2014 \u5C5E\u6027\u3067\u30EC\u30B3\u30FC\u30C9\u691C\u7D22\uFF08\u4F8B: \u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3067\u9023\u7D61\u5148\u3092\u691C\u7D22\uFF09
650
+
651
+ \`\`\`ts
652
+ import type { Context } from "hono";
653
+ import { connection } from "@squadbase/vite-server/connectors/freshsales";
654
+
655
+ const fs = connection("<connectionId>");
656
+
657
+ export default async function handler(c: Context) {
658
+ const views = await fs.listDealViews();
659
+ const firstViewId = (views.filters[0] as { id: number }).id;
660
+ const { deals, meta } = await fs.listDealsInView(firstViewId, {
661
+ per_page: 100,
662
+ include: "owner,deal_stage,sales_account",
663
+ });
664
+ return c.json({ deals, totalPages: meta.total_pages });
665
+ }
666
+ \`\`\`
667
+
668
+ ### Freshsales / Freshworks CRM REST API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
669
+
670
+ - \u30D9\u30FC\u30B9URL: \`https://<bundle>.myfreshworks.com/crm/sales/api\`
671
+ - \u8A8D\u8A3C: \`Authorization: Token token=<API_KEY>\` \u30D8\u30C3\u30C0\u30FC\uFF08Freshdesk/Freshservice \u3068\u7570\u306A\u308A HTTP Basic Auth \u3067\u306F\u3042\u308A\u307E\u305B\u3093\uFF09\u3002
672
+ - \u30DA\u30FC\u30B8\u30CD\u30FC\u30B7\u30E7\u30F3: 1\u59CB\u307E\u308A\u306E \`page\` \u3068 \`per_page\`\uFF08\u30C7\u30D5\u30A9\u30EB\u30C825\u3001\u6700\u5927100\uFF09\u3002\u30D3\u30E5\u30FC\u4E00\u89A7\u7CFB\u306E\u30EC\u30B9\u30DD\u30F3\u30B9\u306B\u306F \`meta: { total_pages, total }\` \u304C\u542B\u307E\u308C\u307E\u3059\u3002
673
+ - \u30A4\u30F3\u30AF\u30EB\u30FC\u30C9: \u307B\u3068\u3093\u3069\u306E\u4E00\u89A7/\u53D6\u5F97\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3067 \`?include=\` \u306B\u30AB\u30F3\u30DE\u533A\u5207\u308A\u3067\u95A2\u9023\u30EA\u30BD\u30FC\u30B9\u3092\u6307\u5B9A\u3057\u3066\u30A4\u30F3\u30E9\u30A4\u30F3\u5C55\u958B\u3067\u304D\u307E\u3059\u3002
674
+
675
+ #### \u30EA\u30BD\u30FC\u30B9\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8
676
+
677
+ **\u9023\u7D61\u5148\uFF08Contacts\uFF09**
678
+ - GET \`/contacts/filters\` \u2014 \u4FDD\u5B58\u30D3\u30E5\u30FC\u4E00\u89A7\uFF08filters\uFF09
679
+ - GET \`/contacts/view/{view_id}\` \u2014 \u30D3\u30E5\u30FC\u5185\u306E\u9023\u7D61\u5148\u4E00\u89A7\uFF08\u30DA\u30FC\u30B8\u30F3\u30B0\uFF09
680
+ - GET \`/contacts/{id}\` \u2014 \u9023\u7D61\u5148\u306E\u53D6\u5F97\uFF08\`?include=owner,creator,deals,sales_accounts\` \u3067\u95A2\u9023\u5C55\u958B\uFF09
681
+ - POST \`/contacts\` \u2014 \u9023\u7D61\u5148\u306E\u4F5C\u6210\uFF08body: \`{ "contact": { ... } }\`\uFF09
682
+ - PUT \`/contacts/{id}\` \u2014 \u9023\u7D61\u5148\u306E\u66F4\u65B0
683
+
684
+ **\u53D6\u5F15\u5148\uFF08Sales accounts / \u4F1A\u793E\uFF09**
685
+ - GET \`/sales_accounts/filters\` \u2014 \u4FDD\u5B58\u30D3\u30E5\u30FC\u4E00\u89A7
686
+ - GET \`/sales_accounts/view/{view_id}\` \u2014 \u30D3\u30E5\u30FC\u5185\u306E\u53D6\u5F15\u5148
687
+ - GET \`/sales_accounts/{id}\` \u2014 \u53D6\u5F15\u5148\u306E\u53D6\u5F97
688
+ - POST \`/sales_accounts\` / PUT \`/sales_accounts/{id}\` \u2014 \u4F5C\u6210\u30FB\u66F4\u65B0
689
+
690
+ **\u5546\u8AC7\uFF08Deals\uFF09**
691
+ - GET \`/deals/filters\` \u2014 \u4FDD\u5B58\u30D3\u30E5\u30FC\u4E00\u89A7
692
+ - GET \`/deals/view/{view_id}\` \u2014 \u30D3\u30E5\u30FC\u5185\u306E\u5546\u8AC7
693
+ - GET \`/deals/{id}\` \u2014 \u5546\u8AC7\u306E\u53D6\u5F97\uFF08\`?include=owner,deal_stage,sales_account,contacts\` \u3067\u95A2\u9023\u5C55\u958B\uFF09
694
+ - POST \`/deals\` / PUT \`/deals/{id}\` \u2014 \u4F5C\u6210\u30FB\u66F4\u65B0
695
+
696
+ **\u30EA\u30FC\u30C9\uFF08Leads \u2014 Sales Cloud \u306E\u307F\uFF09**
697
+ - GET \`/leads/filters\` \u2014 \u4FDD\u5B58\u30D3\u30E5\u30FC\u4E00\u89A7
698
+ - GET \`/leads/view/{view_id}\` \u2014 \u30D3\u30E5\u30FC\u5185\u306E\u30EA\u30FC\u30C9
699
+ - GET \`/leads/{id}\` \u2014 \u30EA\u30FC\u30C9\u306E\u53D6\u5F97
700
+
701
+ **\u55B6\u696D\u6D3B\u52D5 & \u30BF\u30B9\u30AF**
702
+ - GET \`/sales_activities\` \u2014 \u55B6\u696D\u6D3B\u52D5\u306E\u4E00\u89A7
703
+ - GET \`/tasks\` \u2014 \u30BF\u30B9\u30AF\u4E00\u89A7
704
+ - GET \`/appointments\` \u2014 \u30A2\u30DD\u30A4\u30F3\u30C8\u30E1\u30F3\u30C8\u4E00\u89A7
705
+ - POST \`/notes\` \u2014 \u30CE\u30FC\u30C8\u306E\u4F5C\u6210\uFF08body \u3067\u9023\u7D61\u5148/\u53D6\u5F15\u5148/\u5546\u8AC7\u3092\u53C2\u7167\uFF09
706
+
707
+ **\u691C\u7D22 & \u30EB\u30C3\u30AF\u30A2\u30C3\u30D7**
708
+ - GET \`/lookup\` \u2014 \u5C5E\u6027\u306B\u3088\u308B\u30EC\u30B3\u30FC\u30C9\u691C\u7D22\u3002\u30AF\u30A8\u30EA: \`q\`\uFF08\u5024\uFF09\u3001\`f\`\uFF08\u30D5\u30A3\u30FC\u30EB\u30C9 \u2014 \u901A\u5E38 \`email\`/\`mobile_number\`\uFF09\u3001\`entities\`\uFF08\`contact\`/\`sales_account\`/\`deal\`/\`lead\`\uFF09\u3002
709
+
710
+ **\u30BB\u30EC\u30AF\u30BF\u30FC\u30E1\u30BF\u60C5\u5831**
711
+ - GET \`/selector/owners\` \u2014 \u30AA\u30FC\u30CA\u30FC\uFF08\u55B6\u696D\u62C5\u5F53\uFF09\u4E00\u89A7
712
+ - GET \`/selector/deal_pipelines\` \u2014 \u30D1\u30A4\u30D7\u30E9\u30A4\u30F3
713
+ - GET \`/selector/deal_stages\` \u2014 \u30B9\u30C6\u30FC\u30B8
714
+ - GET \`/selector/deal_types\` \u2014 \u5546\u8AC7\u30BF\u30A4\u30D7
715
+ - GET \`/selector/lifecycle_stages\` \u2014 \u30E9\u30A4\u30D5\u30B5\u30A4\u30AF\u30EB\u30B9\u30C6\u30FC\u30B8
716
+ - GET \`/selector/territories\` / \`/selector/business_types\` / \`/selector/industry_types\` / \`/selector/contact_statuses\` / \`/selector/sales_activity_types\``
717
+ },
718
+ tools
719
+ });
720
+
721
+ // src/connectors/create-connector-sdk.ts
722
+ import { readFileSync } from "fs";
723
+ import path from "path";
724
+
725
+ // src/connector-client/env.ts
726
+ function resolveEnvVar(entry, key, connectionId) {
727
+ const envVarName = entry.envVars[key];
728
+ if (!envVarName) {
729
+ throw new Error(`Connection "${connectionId}" is missing envVars mapping for key "${key}"`);
730
+ }
731
+ const value = process.env[envVarName];
732
+ if (!value) {
733
+ throw new Error(`Environment variable "${envVarName}" (for connection "${connectionId}", key "${key}") is not set`);
734
+ }
735
+ return value;
736
+ }
737
+ function resolveEnvVarOptional(entry, key) {
738
+ const envVarName = entry.envVars[key];
739
+ if (!envVarName) return void 0;
740
+ return process.env[envVarName] || void 0;
741
+ }
742
+
743
+ // src/connector-client/proxy-fetch.ts
744
+ import { getContext } from "hono/context-storage";
745
+ import { getCookie } from "hono/cookie";
746
+ var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
747
+ function normalizeHeaders(input) {
748
+ const out = {};
749
+ if (!input) return out;
750
+ new Headers(input).forEach((value, key) => {
751
+ out[key] = value;
752
+ });
753
+ return out;
754
+ }
755
+ function createSandboxProxyFetch(connectionId) {
756
+ return async (input, init) => {
757
+ const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
758
+ const sandboxId = process.env.INTERNAL_SQUADBASE_SANDBOX_ID;
759
+ if (!token || !sandboxId) {
760
+ throw new Error(
761
+ "Connection proxy is not configured. Please check your deployment settings."
762
+ );
763
+ }
764
+ const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
765
+ const originalMethod = init?.method ?? "GET";
766
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
767
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
768
+ const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
769
+ return fetch(proxyUrl, {
770
+ method: "POST",
771
+ headers: {
772
+ "Content-Type": "application/json",
773
+ Authorization: `Bearer ${token}`
774
+ },
775
+ body: JSON.stringify({
776
+ url: originalUrl,
777
+ method: originalMethod,
778
+ headers: normalizeHeaders(init?.headers),
779
+ body: originalBody
780
+ })
781
+ });
782
+ };
783
+ }
784
+ function createDeployedAppProxyFetch(connectionId) {
785
+ const projectId = process.env["SQUADBASE_PROJECT_ID"];
786
+ if (!projectId) {
787
+ throw new Error(
788
+ "Connection proxy is not configured. Please check your deployment settings."
789
+ );
790
+ }
791
+ const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
792
+ const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
793
+ return async (input, init) => {
794
+ const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
795
+ const originalMethod = init?.method ?? "GET";
796
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
797
+ const c = getContext();
798
+ const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
799
+ if (!appSession) {
800
+ throw new Error(
801
+ "No authentication method available for connection proxy."
802
+ );
803
+ }
804
+ return fetch(proxyUrl, {
805
+ method: "POST",
806
+ headers: {
807
+ "Content-Type": "application/json",
808
+ Authorization: `Bearer ${appSession}`
809
+ },
810
+ body: JSON.stringify({
811
+ url: originalUrl,
812
+ method: originalMethod,
813
+ headers: normalizeHeaders(init?.headers),
814
+ body: originalBody
815
+ })
816
+ });
817
+ };
818
+ }
819
+ function createProxyFetch(connectionId) {
820
+ if (process.env.INTERNAL_SQUADBASE_SANDBOX_ID) {
821
+ return createSandboxProxyFetch(connectionId);
822
+ }
823
+ return createDeployedAppProxyFetch(connectionId);
824
+ }
825
+
826
+ // src/connectors/create-connector-sdk.ts
827
+ function loadConnectionsSync() {
828
+ const filePath = process.env.CONNECTIONS_PATH ?? path.join(process.cwd(), ".squadbase/connections.json");
829
+ try {
830
+ const raw = readFileSync(filePath, "utf-8");
831
+ return JSON.parse(raw);
832
+ } catch {
833
+ return {};
834
+ }
835
+ }
836
+ function createConnectorSdk(plugin, createClient2) {
837
+ return (connectionId) => {
838
+ const connections = loadConnectionsSync();
839
+ const entry = connections[connectionId];
840
+ if (!entry) {
841
+ throw new Error(
842
+ `Connection "${connectionId}" not found in .squadbase/connections.json`
843
+ );
844
+ }
845
+ if (entry.connector.slug !== plugin.slug) {
846
+ throw new Error(
847
+ `Connection "${connectionId}" is not a ${plugin.slug} connection (got "${entry.connector.slug}")`
848
+ );
849
+ }
850
+ const params = {};
851
+ for (const param of Object.values(plugin.parameters)) {
852
+ if (param.required) {
853
+ params[param.slug] = resolveEnvVar(entry, param.slug, connectionId);
854
+ } else {
855
+ const val = resolveEnvVarOptional(entry, param.slug);
856
+ if (val !== void 0) params[param.slug] = val;
857
+ }
858
+ }
859
+ return createClient2(params, createProxyFetch(connectionId));
860
+ };
861
+ }
862
+
863
+ // src/connectors/entries/freshsales.ts
864
+ var connection = createConnectorSdk(freshsalesConnector, createClient);
865
+ export {
866
+ connection
867
+ };