@squadbase/vite-server 0.1.3-dev.13 → 0.1.3-dev.14

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.
@@ -462,7 +462,7 @@ var googleDriveOauthConnector = new ConnectorPlugin({
462
462
  authType: AUTH_TYPES.OAUTH,
463
463
  name: "Google Drive",
464
464
  description: "Connect to Google Drive for file management, sharing, and collaboration using OAuth.",
465
- iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/4GJX5yQTogUgar1buWxXbv/4b43a65353319c508111489f834d22c4/google_drive.png",
465
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/7rOUJhO4dDKRYirBqCYzxI/48e9a5b85f0b4c6f9a3d7e2c1b8a5f4d/google-drive.svg",
466
466
  parameters,
467
467
  releaseFlag: { dev1: true, dev2: false, prod: false },
468
468
  onboarding: googleDriveOnboarding,
@@ -510,7 +510,7 @@ var googleDriveConnector = new ConnectorPlugin({
510
510
  authType: AUTH_TYPES.SERVICE_ACCOUNT,
511
511
  name: "Google Drive",
512
512
  description: "Connect to Google Drive for file management, sharing, and collaboration using a service account.",
513
- iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/4GJX5yQTogUgar1buWxXbv/4b43a65353319c508111489f834d22c4/google_drive.png",
513
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/7rOUJhO4dDKRYirBqCYzxI/48e9a5b85f0b4c6f9a3d7e2c1b8a5f4d/google-drive.svg",
514
514
  parameters,
515
515
  releaseFlag: { dev1: true, dev2: false, prod: false },
516
516
  onboarding: googleDriveOnboarding,
@@ -429,7 +429,7 @@ var googleSlidesOauthConnector = new ConnectorPlugin({
429
429
  authType: AUTH_TYPES.OAUTH,
430
430
  name: "Google Slides",
431
431
  description: "Connect to Google Slides for presentation data access and creation using OAuth.",
432
- iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/4oyF4yTRpemMA43X49masx/e1582d25e3b4c9a63ba83df2147c1968/google_slide.png",
432
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/5g0LJMwN28s2OhJbYU9CxC/71f1abfb40c89e5a6b5e3a3ad83b5a73/google-slides.svg",
433
433
  parameters,
434
434
  releaseFlag: { dev1: true, dev2: false, prod: false },
435
435
  onboarding: googleSlidesOnboarding,
@@ -64,6 +64,15 @@ var parameters = {
64
64
  type: "text",
65
65
  secret: false,
66
66
  required: false
67
+ }),
68
+ sharedDriveId: new ParameterDefinition({
69
+ slug: "shared-drive-id",
70
+ name: "Shared Drive ID",
71
+ description: "The ID of the Google Shared Drive where new presentations will be created. Required for service accounts that do not have their own Drive storage. You can find the ID in the Shared Drive URL: https://drive.google.com/drive/folders/{sharedDriveId}",
72
+ envVarBaseKey: "GOOGLE_SLIDES_SHARED_DRIVE_ID",
73
+ type: "text",
74
+ secret: false,
75
+ required: false
67
76
  })
68
77
  };
69
78
 
@@ -81,7 +90,8 @@ function extractPresentationId(urlOrId) {
81
90
  // ../connectors/src/connectors/google-slides/sdk/index.ts
82
91
  var TOKEN_URL = "https://oauth2.googleapis.com/token";
83
92
  var SLIDES_BASE_URL = "https://slides.googleapis.com/v1/presentations";
84
- var SCOPE = "https://www.googleapis.com/auth/presentations";
93
+ var DRIVE_FILES_URL = "https://www.googleapis.com/drive/v3/files";
94
+ var SCOPE = "https://www.googleapis.com/auth/presentations https://www.googleapis.com/auth/drive";
85
95
  function base64url(input) {
86
96
  const buf = typeof input === "string" ? Buffer.from(input) : input;
87
97
  return buf.toString("base64url");
@@ -108,6 +118,7 @@ function createClient(params) {
108
118
  const serviceAccountKeyJsonBase64 = params[parameters.serviceAccountKeyJsonBase64.slug];
109
119
  const presentationUrl = params[parameters.presentationUrl.slug];
110
120
  const defaultPresentationId = presentationUrl ? extractPresentationId(presentationUrl) : void 0;
121
+ const sharedDriveId = params[parameters.sharedDriveId.slug] || void 0;
111
122
  if (!serviceAccountKeyJsonBase64) {
112
123
  throw new Error(
113
124
  `google-slides: missing required parameter: ${parameters.serviceAccountKeyJsonBase64.slug}`
@@ -216,6 +227,36 @@ function createClient(params) {
216
227
  return await response.json();
217
228
  },
218
229
  async createPresentation(title) {
230
+ if (sharedDriveId) {
231
+ const driveResponse = await authenticatedFetch(
232
+ `${DRIVE_FILES_URL}?supportsAllDrives=true`,
233
+ {
234
+ method: "POST",
235
+ body: JSON.stringify({
236
+ name: title,
237
+ mimeType: "application/vnd.google-apps.presentation",
238
+ parents: [sharedDriveId]
239
+ })
240
+ }
241
+ );
242
+ if (!driveResponse.ok) {
243
+ const body = await driveResponse.text();
244
+ throw new Error(
245
+ `google-slides: createPresentation (Drive API) failed (${driveResponse.status}): ${body}`
246
+ );
247
+ }
248
+ const driveFile = await driveResponse.json();
249
+ const slidesResponse = await authenticatedFetch(
250
+ `${SLIDES_BASE_URL}/${driveFile.id}`
251
+ );
252
+ if (!slidesResponse.ok) {
253
+ const body = await slidesResponse.text();
254
+ throw new Error(
255
+ `google-slides: getPresentation after create failed (${slidesResponse.status}): ${body}`
256
+ );
257
+ }
258
+ return await slidesResponse.json();
259
+ }
219
260
  const response = await authenticatedFetch(SLIDES_BASE_URL, {
220
261
  method: "POST",
221
262
  body: JSON.stringify({ title })
@@ -405,7 +446,10 @@ Authentication is handled automatically using a service account.
405
446
  );
406
447
  const auth = new GoogleAuth({
407
448
  credentials,
408
- scopes: ["https://www.googleapis.com/auth/presentations"]
449
+ scopes: [
450
+ "https://www.googleapis.com/auth/presentations",
451
+ "https://www.googleapis.com/auth/drive"
452
+ ]
409
453
  });
410
454
  const token = await auth.getAccessToken();
411
455
  if (!token) {
@@ -458,7 +502,7 @@ var googleSlidesConnector = new ConnectorPlugin({
458
502
  authType: AUTH_TYPES.SERVICE_ACCOUNT,
459
503
  name: "Google Slides",
460
504
  description: "Connect to Google Slides for presentation data access and creation using a service account.",
461
- iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/4oyF4yTRpemMA43X49masx/e1582d25e3b4c9a63ba83df2147c1968/google_slide.png",
505
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/5g0LJMwN28s2OhJbYU9CxC/71f1abfb40c89e5a6b5e3a3ad83b5a73/google-slides.svg",
462
506
  parameters,
463
507
  releaseFlag: { dev1: true, dev2: false, prod: false },
464
508
  onboarding: googleSlidesOnboarding,
@@ -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 });
49
+ const url = `${BASE_URL}${path2}`;
50
+ return fetchFn(url, init);
97
51
  }
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
- }));
131
- }
132
- return {
133
- request,
134
- getAnalytics,
135
- listAdAccounts
136
- };
52
+ return { request };
137
53
  }
138
54
 
139
55
  // ../connectors/src/connector-onboarding.ts
@@ -248,13 +164,45 @@ var AUTH_TYPES = {
248
164
 
249
165
  // ../connectors/src/connectors/linkedin-ads/tools/list-ad-accounts.ts
250
166
  import { z } from "zod";
167
+ var BASE_URL2 = "https://api.linkedin.com/rest/";
168
+ var LINKEDIN_VERSION = "202603";
251
169
  var REQUEST_TIMEOUT_MS = 6e4;
252
- var LINKEDIN_VERSION2 = "202603";
170
+ var cachedToken = null;
171
+ async function getProxyToken(config) {
172
+ if (cachedToken && cachedToken.expiresAt > Date.now() + 6e4) {
173
+ return cachedToken.token;
174
+ }
175
+ const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
176
+ const res = await fetch(url, {
177
+ method: "POST",
178
+ headers: {
179
+ "Content-Type": "application/json",
180
+ "x-api-key": config.appApiKey,
181
+ "project-id": config.projectId
182
+ },
183
+ body: JSON.stringify({
184
+ sandboxId: config.sandboxId,
185
+ issuedBy: "coding-agent"
186
+ })
187
+ });
188
+ if (!res.ok) {
189
+ const errorText = await res.text().catch(() => res.statusText);
190
+ throw new Error(
191
+ `Failed to get proxy token: HTTP ${res.status} ${errorText}`
192
+ );
193
+ }
194
+ const data = await res.json();
195
+ cachedToken = {
196
+ token: data.token,
197
+ expiresAt: new Date(data.expiresAt).getTime()
198
+ };
199
+ return data.token;
200
+ }
253
201
  var inputSchema = z.object({
254
202
  toolUseIntent: z.string().optional().describe(
255
203
  "Brief description of what you intend to accomplish with this tool call"
256
204
  ),
257
- connectionId: z.string().describe("ID of the LinkedIn Ads connection to use")
205
+ connectionId: z.string().describe("ID of the LinkedIn Ads OAuth connection to use")
258
206
  });
259
207
  var outputSchema = z.discriminatedUnion("success", [
260
208
  z.object({
@@ -273,10 +221,10 @@ var outputSchema = z.discriminatedUnion("success", [
273
221
  ]);
274
222
  var listAdAccountsTool = new ConnectorTool({
275
223
  name: "listAdAccounts",
276
- description: "List LinkedIn ad accounts accessible with the current access token.",
224
+ description: "List LinkedIn ad accounts accessible with the current OAuth credentials.",
277
225
  inputSchema,
278
226
  outputSchema,
279
- async execute({ connectionId }, connections) {
227
+ async execute({ connectionId }, connections, config) {
280
228
  const connection2 = connections.find((c) => c.id === connectionId);
281
229
  if (!connection2) {
282
230
  return {
@@ -288,18 +236,25 @@ var listAdAccountsTool = new ConnectorTool({
288
236
  `[connector-request] linkedin-ads/${connection2.name}: listAdAccounts`
289
237
  );
290
238
  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";
239
+ const token = await getProxyToken(config.oauthProxy);
240
+ const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
293
241
  const controller = new AbortController();
294
242
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
295
243
  try {
296
- const response = await fetch(url, {
297
- method: "GET",
244
+ const response = await fetch(proxyUrl, {
245
+ method: "POST",
298
246
  headers: {
299
- Authorization: `Bearer ${accessToken}`,
300
- "LinkedIn-Version": LINKEDIN_VERSION2,
301
- "X-Restli-Protocol-Version": "2.0.0"
247
+ "Content-Type": "application/json",
248
+ Authorization: `Bearer ${token}`
302
249
  },
250
+ body: JSON.stringify({
251
+ url: `${BASE_URL2}adAccounts?q=search&search=(status:(values:List(ACTIVE)))&pageSize=100`,
252
+ method: "GET",
253
+ headers: {
254
+ "LinkedIn-Version": LINKEDIN_VERSION,
255
+ "X-Restli-Protocol-Version": "2.0.0"
256
+ }
257
+ }),
303
258
  signal: controller.signal
304
259
  });
305
260
  const data = await response.json();
@@ -326,10 +281,10 @@ var listAdAccountsTool = new ConnectorTool({
326
281
  var listAdAccountsToolName = `linkedin-ads_${listAdAccountsTool.name}`;
327
282
  var linkedinAdsOnboarding = new ConnectorOnboarding({
328
283
  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
284
+ 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
285
 
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
286
+ 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
287
+ 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
288
  3. \`updateConnectionParameters\` \u3092\u547C\u3073\u51FA\u3059:
334
289
  - \`parameterSlug\`: \`"ad-account-id"\`
335
290
  - \`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 +297,10 @@ var linkedinAdsOnboarding = new ConnectorOnboarding({
342
297
  #### \u5236\u7D04
343
298
  - **\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
299
  - \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.
300
+ en: `Follow these steps to set up the LinkedIn Ads (OAuth) connection.
346
301
 
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
302
+ 1. Call \`${listAdAccountsToolName}\` to get the list of ad accounts accessible with the OAuth credentials
303
+ 2. If an error occurs, ask the user to verify their OAuth connection
349
304
  3. Call \`updateConnectionParameters\`:
350
305
  - \`parameterSlug\`: \`"ad-account-id"\`
351
306
  - \`options\`: The ad account list. Each option's \`label\` should be \`Account Name (id: accountId)\`, \`value\` should be the account ID
@@ -369,19 +324,63 @@ var linkedinAdsOnboarding = new ConnectorOnboarding({
369
324
  }
370
325
  });
371
326
 
327
+ // ../connectors/src/connectors/linkedin-ads/parameters.ts
328
+ var parameters = {
329
+ adAccountId: new ParameterDefinition({
330
+ slug: "ad-account-id",
331
+ name: "Ad Account ID",
332
+ description: "The LinkedIn ad account ID (numeric). Found in Campaign Manager under Account Assets. The URN format urn:li:sponsoredAccount:{id} is constructed automatically.",
333
+ envVarBaseKey: "LINKEDIN_ADS_AD_ACCOUNT_ID",
334
+ type: "text",
335
+ secret: false,
336
+ required: false
337
+ })
338
+ };
339
+
372
340
  // ../connectors/src/connectors/linkedin-ads/tools/request.ts
373
341
  import { z as z2 } from "zod";
374
- var BASE_URL2 = "https://api.linkedin.com/rest/";
375
- var LINKEDIN_VERSION3 = "202603";
342
+ var BASE_URL3 = "https://api.linkedin.com/rest/";
343
+ var LINKEDIN_VERSION2 = "202603";
376
344
  var REQUEST_TIMEOUT_MS2 = 6e4;
345
+ var cachedToken2 = null;
346
+ async function getProxyToken2(config) {
347
+ if (cachedToken2 && cachedToken2.expiresAt > Date.now() + 6e4) {
348
+ return cachedToken2.token;
349
+ }
350
+ const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
351
+ const res = await fetch(url, {
352
+ method: "POST",
353
+ headers: {
354
+ "Content-Type": "application/json",
355
+ "x-api-key": config.appApiKey,
356
+ "project-id": config.projectId
357
+ },
358
+ body: JSON.stringify({
359
+ sandboxId: config.sandboxId,
360
+ issuedBy: "coding-agent"
361
+ })
362
+ });
363
+ if (!res.ok) {
364
+ const errorText = await res.text().catch(() => res.statusText);
365
+ throw new Error(
366
+ `Failed to get proxy token: HTTP ${res.status} ${errorText}`
367
+ );
368
+ }
369
+ const data = await res.json();
370
+ cachedToken2 = {
371
+ token: data.token,
372
+ expiresAt: new Date(data.expiresAt).getTime()
373
+ };
374
+ return data.token;
375
+ }
377
376
  var inputSchema2 = z2.object({
378
377
  toolUseIntent: z2.string().optional().describe(
379
378
  "Brief description of what you intend to accomplish with this tool call"
380
379
  ),
381
- connectionId: z2.string().describe("ID of the LinkedIn Ads connection to use"),
380
+ connectionId: z2.string().describe("ID of the LinkedIn Ads OAuth connection to use"),
382
381
  method: z2.enum(["GET", "POST", "DELETE"]).describe("HTTP method"),
383
382
  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."
383
+ "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
384
  ),
386
385
  queryParams: z2.record(z2.string(), z2.string()).optional().describe("Query parameters to append to the URL"),
387
386
  body: z2.record(z2.string(), z2.unknown()).optional().describe("Request body (JSON). For partial updates, use the patch format: { patch: { $set: { ... } } }")
@@ -400,12 +399,12 @@ var outputSchema2 = z2.discriminatedUnion("success", [
400
399
  var requestTool = new ConnectorTool({
401
400
  name: "request",
402
401
  description: `Send authenticated requests to the LinkedIn Marketing API (REST).
403
- Authentication is handled via the configured access token.
402
+ Authentication is handled automatically via OAuth proxy.
404
403
  {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.`,
404
+ Required headers (LinkedIn-Version, X-Restli-Protocol-Version) are set automatically.`,
406
405
  inputSchema: inputSchema2,
407
406
  outputSchema: outputSchema2,
408
- async execute({ connectionId, method, path: path2, queryParams, body }, connections) {
407
+ async execute({ connectionId, method, path: path2, queryParams, body }, connections, config) {
409
408
  const connection2 = connections.find((c) => c.id === connectionId);
410
409
  if (!connection2) {
411
410
  return {
@@ -417,31 +416,38 @@ Required headers (Authorization, LinkedIn-Version, X-Restli-Protocol-Version) ar
417
416
  `[connector-request] linkedin-ads/${connection2.name}: ${method} ${path2}`
418
417
  );
419
418
  try {
420
- const accessToken = parameters.accessToken.getValue(connection2);
421
419
  const adAccountId = parameters.adAccountId.tryGetValue(connection2) ?? "";
422
420
  const resolvedPath = adAccountId ? path2.replace(/\{adAccountId\}/g, adAccountId) : path2;
423
- let url = `${BASE_URL2}${resolvedPath}`;
421
+ let url = `${BASE_URL3}${resolvedPath}`;
424
422
  if (queryParams && Object.keys(queryParams).length > 0) {
425
423
  const params = new URLSearchParams(queryParams);
426
424
  const separator = url.includes("?") ? "&" : "?";
427
425
  url = `${url}${separator}${params.toString()}`;
428
426
  }
427
+ const token = await getProxyToken2(config.oauthProxy);
428
+ const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
429
429
  const controller = new AbortController();
430
430
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS2);
431
431
  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"
432
+ const additionalHeaders = {
433
+ "LinkedIn-Version": LINKEDIN_VERSION2,
434
+ "X-Restli-Protocol-Version": "2.0.0"
437
435
  };
438
436
  if (body && "patch" in body) {
439
- headers["X-RestLi-Method"] = "PARTIAL_UPDATE";
437
+ additionalHeaders["X-RestLi-Method"] = "PARTIAL_UPDATE";
440
438
  }
441
- const response = await fetch(url, {
442
- method,
443
- headers,
444
- ...(method === "POST" || method === "DELETE") && body ? { body: JSON.stringify(body) } : {},
439
+ const response = await fetch(proxyUrl, {
440
+ method: "POST",
441
+ headers: {
442
+ "Content-Type": "application/json",
443
+ Authorization: `Bearer ${token}`
444
+ },
445
+ body: JSON.stringify({
446
+ url,
447
+ method,
448
+ headers: additionalHeaders,
449
+ ...(method === "POST" || method === "DELETE") && body ? { body: JSON.stringify(body) } : {}
450
+ }),
445
451
  signal: controller.signal
446
452
  });
447
453
  if (response.status === 204) {
@@ -471,17 +477,25 @@ var tools = {
471
477
  };
472
478
  var linkedinAdsConnector = new ConnectorPlugin({
473
479
  slug: "linkedin-ads",
474
- authType: AUTH_TYPES.API_KEY,
480
+ authType: AUTH_TYPES.OAUTH,
475
481
  name: "LinkedIn Ads",
476
- description: "Connect to LinkedIn Ads (Marketing API) for advertising campaign data and reporting using an access token.",
482
+ description: "Connect to LinkedIn Ads (Marketing API) for advertising campaign data and reporting using OAuth.",
477
483
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/3x7xd9pVJkRFY7ADIg4ycq/b94720e34cb081e9ae45dfde799a59cd/LinkedIn_icon.svg.png",
478
484
  parameters,
479
485
  releaseFlag: { dev1: true, dev2: false, prod: false },
480
486
  onboarding: linkedinAdsOnboarding,
487
+ proxyPolicy: {
488
+ allowlist: [
489
+ {
490
+ host: "api.linkedin.com",
491
+ methods: ["GET", "POST", "DELETE"]
492
+ }
493
+ ]
494
+ },
481
495
  systemPrompt: {
482
496
  en: `### Tools
483
497
 
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.
498
+ - \`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
499
  - \`linkedin-ads_listAdAccounts\`: List accessible LinkedIn ad accounts. Use this during setup to discover available accounts.
486
500
 
487
501
  ### LinkedIn Marketing API Reference
@@ -568,25 +582,13 @@ import { connection } from "@squadbase/vite-server/connectors/linkedin-ads";
568
582
 
569
583
  const linkedin = connection("<connectionId>");
570
584
 
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
585
  // Get campaigns
584
586
  const res = await linkedin.request("adAccounts/{adAccountId}/adCampaigns?q=search&search=(status:(values:List(ACTIVE)))");
585
587
  const data = await res.json();
586
588
  \`\`\``,
587
589
  ja: `### \u30C4\u30FC\u30EB
588
590
 
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
591
+ - \`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
592
  - \`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
593
 
592
594
  ### LinkedIn Marketing API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
@@ -673,38 +675,19 @@ import { connection } from "@squadbase/vite-server/connectors/linkedin-ads";
673
675
 
674
676
  const linkedin = connection("<connectionId>");
675
677
 
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
678
  // \u30AD\u30E3\u30F3\u30DA\u30FC\u30F3\u3092\u53D6\u5F97
689
679
  const res = await linkedin.request("adAccounts/{adAccountId}/adCampaigns?q=search&search=(status:(values:List(ACTIVE)))");
690
680
  const data = await res.json();
691
681
  \`\`\``
692
682
  },
693
683
  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
- }
684
+ async checkConnection(_params, config) {
685
+ const { proxyFetch } = config;
702
686
  try {
703
687
  const url = "https://api.linkedin.com/rest/adAccounts?q=search&search=(status:(values:List(ACTIVE)))&pageSize=1";
704
- const res = await fetch(url, {
688
+ const res = await proxyFetch(url, {
705
689
  method: "GET",
706
690
  headers: {
707
- Authorization: `Bearer ${accessToken}`,
708
691
  "LinkedIn-Version": "202603",
709
692
  "X-Restli-Protocol-Version": "2.0.0"
710
693
  }
@@ -1,5 +1,5 @@
1
1
  import * as _squadbase_connectors_sdk from '@squadbase/connectors/sdk';
2
2
 
3
- declare const connection: (connectionId: string) => _squadbase_connectors_sdk.GoogleAdsConnectorSdk;
3
+ declare const connection: (connectionId: string) => _squadbase_connectors_sdk.MixpanelConnectorSdk;
4
4
 
5
5
  export { connection };