@squadbase/vite-server 0.1.3-dev.9 → 0.1.4-dev.0

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 +14539 -29447
  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 +522 -118
  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 +4574 -3863
  58. package/dist/main.js +4572 -3862
  59. package/dist/vite-plugin.js +4572 -3862
  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
@@ -42,98 +42,14 @@ var ParameterDefinition = class {
42
42
  }
43
43
  };
44
44
 
45
- // ../connectors/src/connectors/linkedin-ads/parameters.ts
46
- var parameters = {
47
- accessToken: new ParameterDefinition({
48
- slug: "access-token",
49
- name: "Access Token",
50
- description: "A LinkedIn Marketing API access token. Obtainable from the LinkedIn Developer Portal token generator or via OAuth 2.0 authorization code flow.",
51
- envVarBaseKey: "LINKEDIN_ADS_ACCESS_TOKEN",
52
- type: "text",
53
- secret: true,
54
- required: true
55
- }),
56
- adAccountId: new ParameterDefinition({
57
- slug: "ad-account-id",
58
- name: "Ad Account ID",
59
- description: "The LinkedIn ad account ID (numeric). Found in Campaign Manager under Account Assets. The URN format urn:li:sponsoredAccount:{id} is constructed automatically.",
60
- envVarBaseKey: "LINKEDIN_ADS_AD_ACCOUNT_ID",
61
- type: "text",
62
- secret: false,
63
- required: false
64
- })
65
- };
66
-
67
45
  // ../connectors/src/connectors/linkedin-ads/sdk/index.ts
68
46
  var BASE_URL = "https://api.linkedin.com/rest/";
69
- var LINKEDIN_VERSION = "202603";
70
- function createClient(params, fetchFn = fetch) {
71
- const accessToken = params[parameters.accessToken.slug];
72
- const defaultAdAccountId = params[parameters.adAccountId.slug] ?? "";
73
- if (!accessToken) {
74
- throw new Error(
75
- `linkedin-ads: missing required parameter: ${parameters.accessToken.slug}`
76
- );
77
- }
78
- function getHeaders(extra) {
79
- return {
80
- Authorization: `Bearer ${accessToken}`,
81
- "LinkedIn-Version": LINKEDIN_VERSION,
82
- "X-Restli-Protocol-Version": "2.0.0",
83
- "Content-Type": "application/json",
84
- ...extra
85
- };
86
- }
47
+ function createClient(_params, fetchFn = fetch) {
87
48
  function request(path2, init) {
88
- const resolvedPath = defaultAdAccountId ? path2.replace(/\{adAccountId\}/g, defaultAdAccountId) : path2;
89
- const url = `${BASE_URL}${resolvedPath}`;
90
- const headers = new Headers(init?.headers);
91
- for (const [k, v] of Object.entries(getHeaders())) {
92
- if (!headers.has(k)) {
93
- headers.set(k, v);
94
- }
95
- }
96
- return fetchFn(url, { ...init, headers });
97
- }
98
- async function getAnalytics(queryParams) {
99
- const searchParams = new URLSearchParams({ q: "analytics", ...queryParams });
100
- const url = `${BASE_URL}adAnalytics?${searchParams.toString()}`;
101
- const response = await fetchFn(url, {
102
- method: "GET",
103
- headers: getHeaders()
104
- });
105
- if (!response.ok) {
106
- const body = await response.text();
107
- throw new Error(
108
- `linkedin-ads: getAnalytics failed (${response.status}): ${body}`
109
- );
110
- }
111
- const data = await response.json();
112
- return data.elements ?? [];
113
- }
114
- async function listAdAccounts() {
115
- const url = `${BASE_URL}adAccounts?q=search&search=(status:(values:List(ACTIVE)))&pageSize=100`;
116
- const response = await fetchFn(url, {
117
- method: "GET",
118
- headers: getHeaders()
119
- });
120
- if (!response.ok) {
121
- const body = await response.text();
122
- throw new Error(
123
- `linkedin-ads: listAdAccounts failed (${response.status}): ${body}`
124
- );
125
- }
126
- const data = await response.json();
127
- return (data.elements ?? []).map((a) => ({
128
- adAccountId: String(a.id ?? ""),
129
- name: a.name ?? String(a.id ?? "")
130
- }));
49
+ const url = `${BASE_URL}${path2}`;
50
+ return fetchFn(url, init);
131
51
  }
132
- return {
133
- request,
134
- getAnalytics,
135
- listAdAccounts
136
- };
52
+ return { request };
137
53
  }
138
54
 
139
55
  // ../connectors/src/connector-onboarding.ts
@@ -218,21 +134,58 @@ var ConnectorPlugin = class _ConnectorPlugin {
218
134
  * Filters connections by connectorKey internally.
219
135
  * Returns tools keyed as `${connectorKey}_${toolName}`.
220
136
  */
221
- createTools(connections, config) {
137
+ createTools(connections, config, opts) {
222
138
  const myConnections = connections.filter(
223
139
  (c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
224
140
  );
225
141
  const result = {};
226
142
  for (const t of Object.values(this.tools)) {
227
- result[`${this.connectorKey}_${t.name}`] = t.createTool(
228
- myConnections,
229
- config
230
- );
143
+ const tool = t.createTool(myConnections, config);
144
+ const originalToModelOutput = tool.toModelOutput;
145
+ result[`${this.connectorKey}_${t.name}`] = {
146
+ ...tool,
147
+ toModelOutput: async (options) => {
148
+ if (!originalToModelOutput) {
149
+ return opts.truncateOutput(options.output);
150
+ }
151
+ const modelOutput = await originalToModelOutput(options);
152
+ if (modelOutput.type === "text" || modelOutput.type === "json") {
153
+ return opts.truncateOutput(modelOutput.value);
154
+ }
155
+ return modelOutput;
156
+ }
157
+ };
231
158
  }
232
159
  return result;
233
160
  }
234
161
  static deriveKey(slug, authType) {
235
- return authType ? `${slug}-${authType}` : slug;
162
+ if (authType) return `${slug}-${authType}`;
163
+ const LEGACY_NULL_AUTH_TYPE_MAP = {
164
+ // user-password
165
+ "postgresql": "user-password",
166
+ "mysql": "user-password",
167
+ "clickhouse": "user-password",
168
+ "kintone": "user-password",
169
+ "squadbase-db": "user-password",
170
+ // service-account
171
+ "snowflake": "service-account",
172
+ "bigquery": "service-account",
173
+ "google-analytics": "service-account",
174
+ "google-calendar": "service-account",
175
+ "aws-athena": "service-account",
176
+ "redshift": "service-account",
177
+ // api-key
178
+ "databricks": "api-key",
179
+ "dbt": "api-key",
180
+ "airtable": "api-key",
181
+ "openai": "api-key",
182
+ "gemini": "api-key",
183
+ "anthropic": "api-key",
184
+ "wix-store": "api-key"
185
+ };
186
+ const fallbackAuthType = LEGACY_NULL_AUTH_TYPE_MAP[slug];
187
+ if (fallbackAuthType) return `${slug}-${fallbackAuthType}`;
188
+ return slug;
236
189
  }
237
190
  };
238
191
 
@@ -248,13 +201,45 @@ var AUTH_TYPES = {
248
201
 
249
202
  // ../connectors/src/connectors/linkedin-ads/tools/list-ad-accounts.ts
250
203
  import { z } from "zod";
204
+ var BASE_URL2 = "https://api.linkedin.com/rest/";
205
+ var LINKEDIN_VERSION = "202603";
251
206
  var REQUEST_TIMEOUT_MS = 6e4;
252
- var LINKEDIN_VERSION2 = "202603";
207
+ var cachedToken = null;
208
+ async function getProxyToken(config) {
209
+ if (cachedToken && cachedToken.expiresAt > Date.now() + 6e4) {
210
+ return cachedToken.token;
211
+ }
212
+ const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
213
+ const res = await fetch(url, {
214
+ method: "POST",
215
+ headers: {
216
+ "Content-Type": "application/json",
217
+ "x-api-key": config.appApiKey,
218
+ "project-id": config.projectId
219
+ },
220
+ body: JSON.stringify({
221
+ sandboxId: config.sandboxId,
222
+ issuedBy: "coding-agent"
223
+ })
224
+ });
225
+ if (!res.ok) {
226
+ const errorText = await res.text().catch(() => res.statusText);
227
+ throw new Error(
228
+ `Failed to get proxy token: HTTP ${res.status} ${errorText}`
229
+ );
230
+ }
231
+ const data = await res.json();
232
+ cachedToken = {
233
+ token: data.token,
234
+ expiresAt: new Date(data.expiresAt).getTime()
235
+ };
236
+ return data.token;
237
+ }
253
238
  var inputSchema = z.object({
254
239
  toolUseIntent: z.string().optional().describe(
255
240
  "Brief description of what you intend to accomplish with this tool call"
256
241
  ),
257
- connectionId: z.string().describe("ID of the LinkedIn Ads connection to use")
242
+ connectionId: z.string().describe("ID of the LinkedIn Ads OAuth connection to use")
258
243
  });
259
244
  var outputSchema = z.discriminatedUnion("success", [
260
245
  z.object({
@@ -273,10 +258,10 @@ var outputSchema = z.discriminatedUnion("success", [
273
258
  ]);
274
259
  var listAdAccountsTool = new ConnectorTool({
275
260
  name: "listAdAccounts",
276
- description: "List LinkedIn ad accounts accessible with the current access token.",
261
+ description: "List LinkedIn ad accounts accessible with the current OAuth credentials.",
277
262
  inputSchema,
278
263
  outputSchema,
279
- async execute({ connectionId }, connections) {
264
+ async execute({ connectionId }, connections, config) {
280
265
  const connection2 = connections.find((c) => c.id === connectionId);
281
266
  if (!connection2) {
282
267
  return {
@@ -288,18 +273,25 @@ var listAdAccountsTool = new ConnectorTool({
288
273
  `[connector-request] linkedin-ads/${connection2.name}: listAdAccounts`
289
274
  );
290
275
  try {
291
- const accessToken = parameters.accessToken.getValue(connection2);
292
- const url = "https://api.linkedin.com/rest/adAccounts?q=search&search=(status:(values:List(ACTIVE)))&pageSize=100";
276
+ const token = await getProxyToken(config.oauthProxy);
277
+ const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
293
278
  const controller = new AbortController();
294
279
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
295
280
  try {
296
- const response = await fetch(url, {
297
- method: "GET",
281
+ const response = await fetch(proxyUrl, {
282
+ method: "POST",
298
283
  headers: {
299
- Authorization: `Bearer ${accessToken}`,
300
- "LinkedIn-Version": LINKEDIN_VERSION2,
301
- "X-Restli-Protocol-Version": "2.0.0"
284
+ "Content-Type": "application/json",
285
+ Authorization: `Bearer ${token}`
302
286
  },
287
+ body: JSON.stringify({
288
+ url: `${BASE_URL2}adAccounts?q=search&search=(status:(values:List(ACTIVE)))&pageSize=100`,
289
+ method: "GET",
290
+ headers: {
291
+ "LinkedIn-Version": LINKEDIN_VERSION,
292
+ "X-Restli-Protocol-Version": "2.0.0"
293
+ }
294
+ }),
303
295
  signal: controller.signal
304
296
  });
305
297
  const data = await response.json();
@@ -326,10 +318,10 @@ var listAdAccountsTool = new ConnectorTool({
326
318
  var listAdAccountsToolName = `linkedin-ads_${listAdAccountsTool.name}`;
327
319
  var linkedinAdsOnboarding = new ConnectorOnboarding({
328
320
  connectionSetupInstructions: {
329
- ja: `\u4EE5\u4E0B\u306E\u624B\u9806\u3067LinkedIn\u5E83\u544A\u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3092\u884C\u3063\u3066\u304F\u3060\u3055\u3044\u3002
321
+ ja: `\u4EE5\u4E0B\u306E\u624B\u9806\u3067LinkedIn\u5E83\u544A (OAuth) \u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3092\u884C\u3063\u3066\u304F\u3060\u3055\u3044\u3002
330
322
 
331
- 1. \`${listAdAccountsToolName}\` \u3092\u547C\u3073\u51FA\u3057\u3066\u3001\u30A2\u30AF\u30BB\u30B9\u30C8\u30FC\u30AF\u30F3\u3067\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u5E83\u544A\u30A2\u30AB\u30A6\u30F3\u30C8\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B
332
- 2. \u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u305F\u5834\u5408\u306F\u30E6\u30FC\u30B6\u30FC\u306B\u30A2\u30AF\u30BB\u30B9\u30C8\u30FC\u30AF\u30F3\u306E\u78BA\u8A8D\u3092\u4F9D\u983C\u3059\u308B
323
+ 1. \`${listAdAccountsToolName}\` \u3092\u547C\u3073\u51FA\u3057\u3066\u3001OAuth\u3067\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u5E83\u544A\u30A2\u30AB\u30A6\u30F3\u30C8\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B
324
+ 2. \u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u305F\u5834\u5408\u306F\u30E6\u30FC\u30B6\u30FC\u306BOAuth\u63A5\u7D9A\u306E\u78BA\u8A8D\u3092\u4F9D\u983C\u3059\u308B
333
325
  3. \`updateConnectionParameters\` \u3092\u547C\u3073\u51FA\u3059:
334
326
  - \`parameterSlug\`: \`"ad-account-id"\`
335
327
  - \`options\`: \u5E83\u544A\u30A2\u30AB\u30A6\u30F3\u30C8\u4E00\u89A7\u3002\u5404 option \u306E \`label\` \u306F \`\u30A2\u30AB\u30A6\u30F3\u30C8\u540D (id: \u30A2\u30AB\u30A6\u30F3\u30C8ID)\` \u306E\u5F62\u5F0F\u3001\`value\` \u306F\u30A2\u30AB\u30A6\u30F3\u30C8ID
@@ -342,10 +334,10 @@ var linkedinAdsOnboarding = new ConnectorOnboarding({
342
334
  #### \u5236\u7D04
343
335
  - **\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u4E2D\u306B\u30EC\u30DD\u30FC\u30C8\u30C7\u30FC\u30BF\u3092\u53D6\u5F97\u3057\u306A\u3044\u3053\u3068**\u3002\u5B9F\u884C\u3057\u3066\u3088\u3044\u306E\u306F\u4E0A\u8A18\u624B\u9806\u3067\u6307\u5B9A\u3055\u308C\u305F\u30E1\u30BF\u30C7\u30FC\u30BF\u53D6\u5F97\u306E\u307F
344
336
  - \u30C4\u30FC\u30EB\u9593\u306F1\u6587\u3060\u3051\u66F8\u3044\u3066\u5373\u6B21\u306E\u30C4\u30FC\u30EB\u547C\u3073\u51FA\u3057\u3002\u4E0D\u8981\u306A\u8AAC\u660E\u306F\u7701\u7565\u3057\u3001\u52B9\u7387\u7684\u306B\u9032\u3081\u308B`,
345
- en: `Follow these steps to set up the LinkedIn Ads connection.
337
+ en: `Follow these steps to set up the LinkedIn Ads (OAuth) connection.
346
338
 
347
- 1. Call \`${listAdAccountsToolName}\` to get the list of ad accounts accessible with the access token
348
- 2. If an error occurs, ask the user to verify their access token
339
+ 1. Call \`${listAdAccountsToolName}\` to get the list of ad accounts accessible with the OAuth credentials
340
+ 2. If an error occurs, ask the user to verify their OAuth connection
349
341
  3. Call \`updateConnectionParameters\`:
350
342
  - \`parameterSlug\`: \`"ad-account-id"\`
351
343
  - \`options\`: The ad account list. Each option's \`label\` should be \`Account Name (id: accountId)\`, \`value\` should be the account ID
@@ -369,19 +361,63 @@ var linkedinAdsOnboarding = new ConnectorOnboarding({
369
361
  }
370
362
  });
371
363
 
364
+ // ../connectors/src/connectors/linkedin-ads/parameters.ts
365
+ var parameters = {
366
+ adAccountId: new ParameterDefinition({
367
+ slug: "ad-account-id",
368
+ name: "Ad Account ID",
369
+ description: "The LinkedIn ad account ID (numeric). Found in Campaign Manager under Account Assets. The URN format urn:li:sponsoredAccount:{id} is constructed automatically.",
370
+ envVarBaseKey: "LINKEDIN_ADS_AD_ACCOUNT_ID",
371
+ type: "text",
372
+ secret: false,
373
+ required: false
374
+ })
375
+ };
376
+
372
377
  // ../connectors/src/connectors/linkedin-ads/tools/request.ts
373
378
  import { z as z2 } from "zod";
374
- var BASE_URL2 = "https://api.linkedin.com/rest/";
375
- var LINKEDIN_VERSION3 = "202603";
379
+ var BASE_URL3 = "https://api.linkedin.com/rest/";
380
+ var LINKEDIN_VERSION2 = "202603";
376
381
  var REQUEST_TIMEOUT_MS2 = 6e4;
382
+ var cachedToken2 = null;
383
+ async function getProxyToken2(config) {
384
+ if (cachedToken2 && cachedToken2.expiresAt > Date.now() + 6e4) {
385
+ return cachedToken2.token;
386
+ }
387
+ const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
388
+ const res = await fetch(url, {
389
+ method: "POST",
390
+ headers: {
391
+ "Content-Type": "application/json",
392
+ "x-api-key": config.appApiKey,
393
+ "project-id": config.projectId
394
+ },
395
+ body: JSON.stringify({
396
+ sandboxId: config.sandboxId,
397
+ issuedBy: "coding-agent"
398
+ })
399
+ });
400
+ if (!res.ok) {
401
+ const errorText = await res.text().catch(() => res.statusText);
402
+ throw new Error(
403
+ `Failed to get proxy token: HTTP ${res.status} ${errorText}`
404
+ );
405
+ }
406
+ const data = await res.json();
407
+ cachedToken2 = {
408
+ token: data.token,
409
+ expiresAt: new Date(data.expiresAt).getTime()
410
+ };
411
+ return data.token;
412
+ }
377
413
  var inputSchema2 = z2.object({
378
414
  toolUseIntent: z2.string().optional().describe(
379
415
  "Brief description of what you intend to accomplish with this tool call"
380
416
  ),
381
- connectionId: z2.string().describe("ID of the LinkedIn Ads connection to use"),
417
+ connectionId: z2.string().describe("ID of the LinkedIn Ads OAuth connection to use"),
382
418
  method: z2.enum(["GET", "POST", "DELETE"]).describe("HTTP method"),
383
419
  path: z2.string().describe(
384
- "API path appended to https://api.linkedin.com/rest/ (e.g., 'adAccounts/{adAccountId}/adCampaigns'). {adAccountId} is automatically replaced with the configured ad account ID."
420
+ "API path appended to https://api.linkedin.com/rest/ (e.g., 'adAccounts/{adAccountId}/adCampaigns'). {adAccountId} is automatically replaced with the connection's ad account ID."
385
421
  ),
386
422
  queryParams: z2.record(z2.string(), z2.string()).optional().describe("Query parameters to append to the URL"),
387
423
  body: z2.record(z2.string(), z2.unknown()).optional().describe("Request body (JSON). For partial updates, use the patch format: { patch: { $set: { ... } } }")
@@ -400,12 +436,12 @@ var outputSchema2 = z2.discriminatedUnion("success", [
400
436
  var requestTool = new ConnectorTool({
401
437
  name: "request",
402
438
  description: `Send authenticated requests to the LinkedIn Marketing API (REST).
403
- Authentication is handled via the configured access token.
439
+ Authentication is handled automatically via OAuth proxy.
404
440
  {adAccountId} in the path is automatically replaced with the connection's ad account ID.
405
- Required headers (Authorization, LinkedIn-Version, X-Restli-Protocol-Version) are set automatically.`,
441
+ Required headers (LinkedIn-Version, X-Restli-Protocol-Version) are set automatically.`,
406
442
  inputSchema: inputSchema2,
407
443
  outputSchema: outputSchema2,
408
- async execute({ connectionId, method, path: path2, queryParams, body }, connections) {
444
+ async execute({ connectionId, method, path: path2, queryParams, body }, connections, config) {
409
445
  const connection2 = connections.find((c) => c.id === connectionId);
410
446
  if (!connection2) {
411
447
  return {
@@ -417,31 +453,38 @@ Required headers (Authorization, LinkedIn-Version, X-Restli-Protocol-Version) ar
417
453
  `[connector-request] linkedin-ads/${connection2.name}: ${method} ${path2}`
418
454
  );
419
455
  try {
420
- const accessToken = parameters.accessToken.getValue(connection2);
421
456
  const adAccountId = parameters.adAccountId.tryGetValue(connection2) ?? "";
422
457
  const resolvedPath = adAccountId ? path2.replace(/\{adAccountId\}/g, adAccountId) : path2;
423
- let url = `${BASE_URL2}${resolvedPath}`;
458
+ let url = `${BASE_URL3}${resolvedPath}`;
424
459
  if (queryParams && Object.keys(queryParams).length > 0) {
425
460
  const params = new URLSearchParams(queryParams);
426
461
  const separator = url.includes("?") ? "&" : "?";
427
462
  url = `${url}${separator}${params.toString()}`;
428
463
  }
464
+ const token = await getProxyToken2(config.oauthProxy);
465
+ const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
429
466
  const controller = new AbortController();
430
467
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS2);
431
468
  try {
432
- const headers = {
433
- Authorization: `Bearer ${accessToken}`,
434
- "LinkedIn-Version": LINKEDIN_VERSION3,
435
- "X-Restli-Protocol-Version": "2.0.0",
436
- "Content-Type": "application/json"
469
+ const additionalHeaders = {
470
+ "LinkedIn-Version": LINKEDIN_VERSION2,
471
+ "X-Restli-Protocol-Version": "2.0.0"
437
472
  };
438
473
  if (body && "patch" in body) {
439
- headers["X-RestLi-Method"] = "PARTIAL_UPDATE";
474
+ additionalHeaders["X-RestLi-Method"] = "PARTIAL_UPDATE";
440
475
  }
441
- const response = await fetch(url, {
442
- method,
443
- headers,
444
- ...(method === "POST" || method === "DELETE") && body ? { body: JSON.stringify(body) } : {},
476
+ const response = await fetch(proxyUrl, {
477
+ method: "POST",
478
+ headers: {
479
+ "Content-Type": "application/json",
480
+ Authorization: `Bearer ${token}`
481
+ },
482
+ body: JSON.stringify({
483
+ url,
484
+ method,
485
+ headers: additionalHeaders,
486
+ ...(method === "POST" || method === "DELETE") && body ? { body: JSON.stringify(body) } : {}
487
+ }),
445
488
  signal: controller.signal
446
489
  });
447
490
  if (response.status === 204) {
@@ -471,17 +514,25 @@ var tools = {
471
514
  };
472
515
  var linkedinAdsConnector = new ConnectorPlugin({
473
516
  slug: "linkedin-ads",
474
- authType: AUTH_TYPES.API_KEY,
517
+ authType: AUTH_TYPES.OAUTH,
475
518
  name: "LinkedIn Ads",
476
- description: "Connect to LinkedIn Ads (Marketing API) for advertising campaign data and reporting using an access token.",
519
+ description: "Connect to LinkedIn Ads (Marketing API) for advertising campaign data and reporting using OAuth.",
477
520
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/3x7xd9pVJkRFY7ADIg4ycq/b94720e34cb081e9ae45dfde799a59cd/LinkedIn_icon.svg.png",
478
521
  parameters,
479
522
  releaseFlag: { dev1: true, dev2: false, prod: false },
480
523
  onboarding: linkedinAdsOnboarding,
524
+ proxyPolicy: {
525
+ allowlist: [
526
+ {
527
+ host: "api.linkedin.com",
528
+ methods: ["GET", "POST", "DELETE"]
529
+ }
530
+ ]
531
+ },
481
532
  systemPrompt: {
482
533
  en: `### Tools
483
534
 
484
- - \`linkedin-ads_request\`: Send authenticated requests to the LinkedIn Marketing API (REST). The {adAccountId} placeholder in paths is automatically replaced. Authentication is configured via the access token parameter. Required headers (Authorization, LinkedIn-Version, X-Restli-Protocol-Version) are set automatically.
535
+ - \`linkedin-ads_request\`: Send authenticated requests to the LinkedIn Marketing API (REST). The {adAccountId} placeholder in paths is automatically replaced. Authentication is handled automatically via OAuth proxy. Required headers (LinkedIn-Version, X-Restli-Protocol-Version) are set automatically.
485
536
  - \`linkedin-ads_listAdAccounts\`: List accessible LinkedIn ad accounts. Use this during setup to discover available accounts.
486
537
 
487
538
  ### LinkedIn Marketing API Reference
@@ -568,25 +619,13 @@ import { connection } from "@squadbase/vite-server/connectors/linkedin-ads";
568
619
 
569
620
  const linkedin = connection("<connectionId>");
570
621
 
571
- // Get analytics for an ad account
572
- const analytics = await linkedin.getAnalytics({
573
- pivot: "CAMPAIGN",
574
- timeGranularity: "MONTHLY",
575
- "dateRange": "(start:(year:2025,month:1,day:1))",
576
- accounts: "List(urn%3Ali%3AsponsoredAccount%3A{adAccountId})",
577
- fields: "impressions,clicks,costInLocalCurrency,dateRange,pivotValues",
578
- });
579
-
580
- // List ad accounts
581
- const accounts = await linkedin.listAdAccounts();
582
-
583
622
  // Get campaigns
584
623
  const res = await linkedin.request("adAccounts/{adAccountId}/adCampaigns?q=search&search=(status:(values:List(ACTIVE)))");
585
624
  const data = await res.json();
586
625
  \`\`\``,
587
626
  ja: `### \u30C4\u30FC\u30EB
588
627
 
589
- - \`linkedin-ads_request\`: LinkedIn Marketing API\uFF08REST\uFF09\u3078\u8A8D\u8A3C\u6E08\u307F\u30EA\u30AF\u30A8\u30B9\u30C8\u3092\u9001\u4FE1\u3057\u307E\u3059\u3002\u30D1\u30B9\u5185\u306E{adAccountId}\u30D7\u30EC\u30FC\u30B9\u30DB\u30EB\u30C0\u30FC\u306F\u81EA\u52D5\u7684\u306B\u7F6E\u63DB\u3055\u308C\u307E\u3059\u3002\u8A8D\u8A3C\u306F\u30A2\u30AF\u30BB\u30B9\u30C8\u30FC\u30AF\u30F3\u30D1\u30E9\u30E1\u30FC\u30BF\u3067\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002\u5FC5\u9808\u30D8\u30C3\u30C0\u30FC\uFF08Authorization\u3001LinkedIn-Version\u3001X-Restli-Protocol-Version\uFF09\u306F\u81EA\u52D5\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002
628
+ - \`linkedin-ads_request\`: LinkedIn Marketing API\uFF08REST\uFF09\u3078\u8A8D\u8A3C\u6E08\u307F\u30EA\u30AF\u30A8\u30B9\u30C8\u3092\u9001\u4FE1\u3057\u307E\u3059\u3002\u30D1\u30B9\u5185\u306E{adAccountId}\u30D7\u30EC\u30FC\u30B9\u30DB\u30EB\u30C0\u30FC\u306F\u81EA\u52D5\u7684\u306B\u7F6E\u63DB\u3055\u308C\u307E\u3059\u3002\u8A8D\u8A3C\u306FOAuth\u30D7\u30ED\u30AD\u30B7\u7D4C\u7531\u3067\u81EA\u52D5\u7684\u306B\u51E6\u7406\u3055\u308C\u307E\u3059\u3002\u5FC5\u9808\u30D8\u30C3\u30C0\u30FC\uFF08LinkedIn-Version\u3001X-Restli-Protocol-Version\uFF09\u306F\u81EA\u52D5\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002
590
629
  - \`linkedin-ads_listAdAccounts\`: \u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306ALinkedIn\u5E83\u544A\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u4E00\u89A7\u3092\u53D6\u5F97\u3057\u307E\u3059\u3002\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u6642\u306B\u5229\u7528\u53EF\u80FD\u306A\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u78BA\u8A8D\u3059\u308B\u305F\u3081\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002
591
630
 
592
631
  ### LinkedIn Marketing API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
@@ -673,38 +712,19 @@ import { connection } from "@squadbase/vite-server/connectors/linkedin-ads";
673
712
 
674
713
  const linkedin = connection("<connectionId>");
675
714
 
676
- // \u5E83\u544A\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u30A2\u30CA\u30EA\u30C6\u30A3\u30AF\u30B9\u3092\u53D6\u5F97
677
- const analytics = await linkedin.getAnalytics({
678
- pivot: "CAMPAIGN",
679
- timeGranularity: "MONTHLY",
680
- "dateRange": "(start:(year:2025,month:1,day:1))",
681
- accounts: "List(urn%3Ali%3AsponsoredAccount%3A{adAccountId})",
682
- fields: "impressions,clicks,costInLocalCurrency,dateRange,pivotValues",
683
- });
684
-
685
- // \u5E83\u544A\u30A2\u30AB\u30A6\u30F3\u30C8\u4E00\u89A7\u3092\u53D6\u5F97
686
- const accounts = await linkedin.listAdAccounts();
687
-
688
715
  // \u30AD\u30E3\u30F3\u30DA\u30FC\u30F3\u3092\u53D6\u5F97
689
716
  const res = await linkedin.request("adAccounts/{adAccountId}/adCampaigns?q=search&search=(status:(values:List(ACTIVE)))");
690
717
  const data = await res.json();
691
718
  \`\`\``
692
719
  },
693
720
  tools,
694
- async checkConnection(params) {
695
- const accessToken = params[parameters.accessToken.slug];
696
- if (!accessToken) {
697
- return {
698
- success: false,
699
- error: "Access token is required"
700
- };
701
- }
721
+ async checkConnection(_params, config) {
722
+ const { proxyFetch } = config;
702
723
  try {
703
724
  const url = "https://api.linkedin.com/rest/adAccounts?q=search&search=(status:(values:List(ACTIVE)))&pageSize=1";
704
- const res = await fetch(url, {
725
+ const res = await proxyFetch(url, {
705
726
  method: "GET",
706
727
  headers: {
707
- Authorization: `Bearer ${accessToken}`,
708
728
  "LinkedIn-Version": "202603",
709
729
  "X-Restli-Protocol-Version": "2.0.0"
710
730
  }
@@ -140,21 +140,58 @@ var ConnectorPlugin = class _ConnectorPlugin {
140
140
  * Filters connections by connectorKey internally.
141
141
  * Returns tools keyed as `${connectorKey}_${toolName}`.
142
142
  */
143
- createTools(connections, config) {
143
+ createTools(connections, config, opts) {
144
144
  const myConnections = connections.filter(
145
145
  (c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
146
146
  );
147
147
  const result = {};
148
148
  for (const t of Object.values(this.tools)) {
149
- result[`${this.connectorKey}_${t.name}`] = t.createTool(
150
- myConnections,
151
- config
152
- );
149
+ const tool = t.createTool(myConnections, config);
150
+ const originalToModelOutput = tool.toModelOutput;
151
+ result[`${this.connectorKey}_${t.name}`] = {
152
+ ...tool,
153
+ toModelOutput: async (options) => {
154
+ if (!originalToModelOutput) {
155
+ return opts.truncateOutput(options.output);
156
+ }
157
+ const modelOutput = await originalToModelOutput(options);
158
+ if (modelOutput.type === "text" || modelOutput.type === "json") {
159
+ return opts.truncateOutput(modelOutput.value);
160
+ }
161
+ return modelOutput;
162
+ }
163
+ };
153
164
  }
154
165
  return result;
155
166
  }
156
167
  static deriveKey(slug, authType) {
157
- return authType ? `${slug}-${authType}` : slug;
168
+ if (authType) return `${slug}-${authType}`;
169
+ const LEGACY_NULL_AUTH_TYPE_MAP = {
170
+ // user-password
171
+ "postgresql": "user-password",
172
+ "mysql": "user-password",
173
+ "clickhouse": "user-password",
174
+ "kintone": "user-password",
175
+ "squadbase-db": "user-password",
176
+ // service-account
177
+ "snowflake": "service-account",
178
+ "bigquery": "service-account",
179
+ "google-analytics": "service-account",
180
+ "google-calendar": "service-account",
181
+ "aws-athena": "service-account",
182
+ "redshift": "service-account",
183
+ // api-key
184
+ "databricks": "api-key",
185
+ "dbt": "api-key",
186
+ "airtable": "api-key",
187
+ "openai": "api-key",
188
+ "gemini": "api-key",
189
+ "anthropic": "api-key",
190
+ "wix-store": "api-key"
191
+ };
192
+ const fallbackAuthType = LEGACY_NULL_AUTH_TYPE_MAP[slug];
193
+ if (fallbackAuthType) return `${slug}-${fallbackAuthType}`;
194
+ return slug;
158
195
  }
159
196
  };
160
197
 
@@ -244,21 +244,58 @@ var ConnectorPlugin = class _ConnectorPlugin {
244
244
  * Filters connections by connectorKey internally.
245
245
  * Returns tools keyed as `${connectorKey}_${toolName}`.
246
246
  */
247
- createTools(connections, config) {
247
+ createTools(connections, config, opts) {
248
248
  const myConnections = connections.filter(
249
249
  (c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
250
250
  );
251
251
  const result = {};
252
252
  for (const t of Object.values(this.tools)) {
253
- result[`${this.connectorKey}_${t.name}`] = t.createTool(
254
- myConnections,
255
- config
256
- );
253
+ const tool = t.createTool(myConnections, config);
254
+ const originalToModelOutput = tool.toModelOutput;
255
+ result[`${this.connectorKey}_${t.name}`] = {
256
+ ...tool,
257
+ toModelOutput: async (options) => {
258
+ if (!originalToModelOutput) {
259
+ return opts.truncateOutput(options.output);
260
+ }
261
+ const modelOutput = await originalToModelOutput(options);
262
+ if (modelOutput.type === "text" || modelOutput.type === "json") {
263
+ return opts.truncateOutput(modelOutput.value);
264
+ }
265
+ return modelOutput;
266
+ }
267
+ };
257
268
  }
258
269
  return result;
259
270
  }
260
271
  static deriveKey(slug, authType) {
261
- return authType ? `${slug}-${authType}` : slug;
272
+ if (authType) return `${slug}-${authType}`;
273
+ const LEGACY_NULL_AUTH_TYPE_MAP = {
274
+ // user-password
275
+ "postgresql": "user-password",
276
+ "mysql": "user-password",
277
+ "clickhouse": "user-password",
278
+ "kintone": "user-password",
279
+ "squadbase-db": "user-password",
280
+ // service-account
281
+ "snowflake": "service-account",
282
+ "bigquery": "service-account",
283
+ "google-analytics": "service-account",
284
+ "google-calendar": "service-account",
285
+ "aws-athena": "service-account",
286
+ "redshift": "service-account",
287
+ // api-key
288
+ "databricks": "api-key",
289
+ "dbt": "api-key",
290
+ "airtable": "api-key",
291
+ "openai": "api-key",
292
+ "gemini": "api-key",
293
+ "anthropic": "api-key",
294
+ "wix-store": "api-key"
295
+ };
296
+ const fallbackAuthType = LEGACY_NULL_AUTH_TYPE_MAP[slug];
297
+ if (fallbackAuthType) return `${slug}-${fallbackAuthType}`;
298
+ return slug;
262
299
  }
263
300
  };
264
301
 
@@ -0,0 +1,5 @@
1
+ import * as _squadbase_connectors_sdk from '@squadbase/connectors/sdk';
2
+
3
+ declare const connection: (connectionId: string) => _squadbase_connectors_sdk.MixpanelConnectorSdk;
4
+
5
+ export { connection };