@squadbase/vite-server 0.1.4 → 0.1.5-dev.1

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 (48) hide show
  1. package/dist/cli/index.js +819 -258
  2. package/dist/connectors/airtable-oauth.js +0 -8
  3. package/dist/connectors/amplitude.js +1 -1
  4. package/dist/connectors/asana.js +1 -1
  5. package/dist/connectors/attio.js +1 -1
  6. package/dist/connectors/backlog-api-key.js +1 -1
  7. package/dist/connectors/customerio.js +1 -1
  8. package/dist/connectors/gamma.js +1 -1
  9. package/dist/connectors/gmail-oauth.js +0 -8
  10. package/dist/connectors/gmail.js +1 -9
  11. package/dist/connectors/google-ads.js +0 -8
  12. package/dist/connectors/google-analytics-oauth.js +0 -8
  13. package/dist/connectors/google-calendar-oauth.js +0 -8
  14. package/dist/connectors/google-calendar.js +0 -10
  15. package/dist/connectors/google-docs.js +3 -1
  16. package/dist/connectors/hubspot-oauth.js +0 -6
  17. package/dist/connectors/hubspot.js +1 -1
  18. package/dist/connectors/influxdb.d.ts +5 -0
  19. package/dist/connectors/influxdb.js +767 -0
  20. package/dist/connectors/intercom-oauth.js +0 -6
  21. package/dist/connectors/intercom.js +1 -1
  22. package/dist/connectors/jira-api-key.js +1 -1
  23. package/dist/connectors/kintone-api-token.js +1 -1
  24. package/dist/connectors/linear.d.ts +5 -0
  25. package/dist/connectors/linear.js +688 -0
  26. package/dist/connectors/linkedin-ads.js +0 -8
  27. package/dist/connectors/mailchimp.js +1 -1
  28. package/dist/connectors/meta-ads-oauth.d.ts +5 -0
  29. package/dist/connectors/meta-ads-oauth.js +795 -0
  30. package/dist/connectors/meta-ads.d.ts +5 -0
  31. package/dist/connectors/meta-ads.js +780 -0
  32. package/dist/connectors/mixpanel.js +1 -1
  33. package/dist/connectors/notion-oauth.js +1 -7
  34. package/dist/connectors/notion.js +1 -1
  35. package/dist/connectors/salesforce.d.ts +5 -0
  36. package/dist/connectors/salesforce.js +862 -0
  37. package/dist/connectors/sentry.js +1 -1
  38. package/dist/connectors/shopify-oauth.js +0 -6
  39. package/dist/connectors/stripe-api-key.js +1 -5
  40. package/dist/connectors/stripe-oauth.js +0 -6
  41. package/dist/connectors/tiktok-ads.d.ts +5 -0
  42. package/dist/connectors/tiktok-ads.js +840 -0
  43. package/dist/connectors/zendesk-oauth.js +0 -6
  44. package/dist/connectors/zendesk.js +1 -1
  45. package/dist/index.js +819 -258
  46. package/dist/main.js +819 -258
  47. package/dist/vite-plugin.js +819 -258
  48. package/package.json +25 -1
@@ -0,0 +1,780 @@
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/meta-ads/parameters.ts
46
+ var parameters = {
47
+ accessToken: new ParameterDefinition({
48
+ slug: "access-token",
49
+ name: "Access Token",
50
+ description: "A long-lived access token or system user token for the Meta Marketing API. Obtainable from Meta Business Suite or the Access Token Tool.",
51
+ envVarBaseKey: "META_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 Meta ad account ID (numeric, without the 'act_' prefix). Found in Meta Business Suite under Ad Accounts.",
60
+ envVarBaseKey: "META_ADS_AD_ACCOUNT_ID",
61
+ type: "text",
62
+ secret: false,
63
+ required: false
64
+ })
65
+ };
66
+
67
+ // ../connectors/src/connectors/meta-ads/sdk/index.ts
68
+ var BASE_URL = "https://graph.facebook.com/v21.0/";
69
+ function createClient(params, fetchFn = fetch) {
70
+ const accessToken = params[parameters.accessToken.slug];
71
+ const defaultAdAccountId = params[parameters.adAccountId.slug] ?? "";
72
+ if (!accessToken) {
73
+ throw new Error(
74
+ `meta-ads: missing required parameter: ${parameters.accessToken.slug}`
75
+ );
76
+ }
77
+ function appendToken(url) {
78
+ const separator = url.includes("?") ? "&" : "?";
79
+ return `${url}${separator}access_token=${encodeURIComponent(accessToken)}`;
80
+ }
81
+ function request(path2, init) {
82
+ const resolvedPath = defaultAdAccountId ? path2.replace(/\{adAccountId\}/g, defaultAdAccountId) : path2;
83
+ const url = appendToken(`${BASE_URL}${resolvedPath}`);
84
+ return fetchFn(url, init);
85
+ }
86
+ async function getInsights(objectId, queryParams) {
87
+ const params2 = new URLSearchParams(queryParams ?? {});
88
+ const url = appendToken(
89
+ `${BASE_URL}${objectId}/insights?${params2.toString()}`
90
+ );
91
+ const response = await fetchFn(url, { method: "GET" });
92
+ if (!response.ok) {
93
+ const body = await response.text();
94
+ throw new Error(
95
+ `meta-ads: getInsights failed (${response.status}): ${body}`
96
+ );
97
+ }
98
+ const data = await response.json();
99
+ return data.data ?? [];
100
+ }
101
+ async function listAdAccounts() {
102
+ const url = appendToken(
103
+ `${BASE_URL}me/adaccounts?fields=account_id,name,account_status`
104
+ );
105
+ const response = await fetchFn(url, { method: "GET" });
106
+ if (!response.ok) {
107
+ const body = await response.text();
108
+ throw new Error(
109
+ `meta-ads: listAdAccounts failed (${response.status}): ${body}`
110
+ );
111
+ }
112
+ const data = await response.json();
113
+ return (data.data ?? []).map((a) => ({
114
+ adAccountId: a.account_id ?? "",
115
+ name: a.name ?? a.account_id ?? ""
116
+ }));
117
+ }
118
+ return {
119
+ request,
120
+ getInsights,
121
+ listAdAccounts
122
+ };
123
+ }
124
+
125
+ // ../connectors/src/connector-onboarding.ts
126
+ var ConnectorOnboarding = class {
127
+ /** Phase 1: Connection setup instructions (optional — some connectors don't need this) */
128
+ connectionSetupInstructions;
129
+ /** Phase 2: Data overview instructions */
130
+ dataOverviewInstructions;
131
+ constructor(config) {
132
+ this.connectionSetupInstructions = config.connectionSetupInstructions;
133
+ this.dataOverviewInstructions = config.dataOverviewInstructions;
134
+ }
135
+ getConnectionSetupPrompt(language) {
136
+ return this.connectionSetupInstructions?.[language] ?? null;
137
+ }
138
+ getDataOverviewInstructions(language) {
139
+ return this.dataOverviewInstructions[language];
140
+ }
141
+ };
142
+
143
+ // ../connectors/src/connector-tool.ts
144
+ var ConnectorTool = class {
145
+ name;
146
+ description;
147
+ inputSchema;
148
+ outputSchema;
149
+ _execute;
150
+ constructor(config) {
151
+ this.name = config.name;
152
+ this.description = config.description;
153
+ this.inputSchema = config.inputSchema;
154
+ this.outputSchema = config.outputSchema;
155
+ this._execute = config.execute;
156
+ }
157
+ createTool(connections, config) {
158
+ return {
159
+ description: this.description,
160
+ inputSchema: this.inputSchema,
161
+ outputSchema: this.outputSchema,
162
+ execute: (input) => this._execute(input, connections, config)
163
+ };
164
+ }
165
+ };
166
+
167
+ // ../connectors/src/connector-plugin.ts
168
+ var ConnectorPlugin = class _ConnectorPlugin {
169
+ slug;
170
+ authType;
171
+ name;
172
+ description;
173
+ iconUrl;
174
+ parameters;
175
+ releaseFlag;
176
+ proxyPolicy;
177
+ experimentalAttributes;
178
+ onboarding;
179
+ systemPrompt;
180
+ tools;
181
+ query;
182
+ checkConnection;
183
+ constructor(config) {
184
+ this.slug = config.slug;
185
+ this.authType = config.authType;
186
+ this.name = config.name;
187
+ this.description = config.description;
188
+ this.iconUrl = config.iconUrl;
189
+ this.parameters = config.parameters;
190
+ this.releaseFlag = config.releaseFlag;
191
+ this.proxyPolicy = config.proxyPolicy;
192
+ this.experimentalAttributes = config.experimentalAttributes;
193
+ this.onboarding = config.onboarding;
194
+ this.systemPrompt = config.systemPrompt;
195
+ this.tools = config.tools;
196
+ this.query = config.query;
197
+ this.checkConnection = config.checkConnection;
198
+ }
199
+ get connectorKey() {
200
+ return _ConnectorPlugin.deriveKey(this.slug, this.authType);
201
+ }
202
+ /**
203
+ * Create tools for connections that belong to this connector.
204
+ * Filters connections by connectorKey internally.
205
+ * Returns tools keyed as `${connectorKey}_${toolName}`.
206
+ */
207
+ createTools(connections, config, opts) {
208
+ const myConnections = connections.filter(
209
+ (c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
210
+ );
211
+ const result = {};
212
+ for (const t of Object.values(this.tools)) {
213
+ const tool = t.createTool(myConnections, config);
214
+ const originalToModelOutput = tool.toModelOutput;
215
+ result[`${this.connectorKey}_${t.name}`] = {
216
+ ...tool,
217
+ toModelOutput: async (options) => {
218
+ if (!originalToModelOutput) {
219
+ return opts.truncateOutput(options.output);
220
+ }
221
+ const modelOutput = await originalToModelOutput(options);
222
+ if (modelOutput.type === "text" || modelOutput.type === "json") {
223
+ return opts.truncateOutput(modelOutput.value);
224
+ }
225
+ return modelOutput;
226
+ }
227
+ };
228
+ }
229
+ return result;
230
+ }
231
+ static deriveKey(slug, authType) {
232
+ if (authType) return `${slug}-${authType}`;
233
+ const LEGACY_NULL_AUTH_TYPE_MAP = {
234
+ // user-password
235
+ "postgresql": "user-password",
236
+ "mysql": "user-password",
237
+ "clickhouse": "user-password",
238
+ "kintone": "user-password",
239
+ "squadbase-db": "user-password",
240
+ // service-account
241
+ "snowflake": "service-account",
242
+ "bigquery": "service-account",
243
+ "google-analytics": "service-account",
244
+ "google-calendar": "service-account",
245
+ "aws-athena": "service-account",
246
+ "redshift": "service-account",
247
+ // api-key
248
+ "databricks": "api-key",
249
+ "dbt": "api-key",
250
+ "airtable": "api-key",
251
+ "openai": "api-key",
252
+ "gemini": "api-key",
253
+ "anthropic": "api-key",
254
+ "wix-store": "api-key"
255
+ };
256
+ const fallbackAuthType = LEGACY_NULL_AUTH_TYPE_MAP[slug];
257
+ if (fallbackAuthType) return `${slug}-${fallbackAuthType}`;
258
+ return slug;
259
+ }
260
+ };
261
+
262
+ // ../connectors/src/auth-types.ts
263
+ var AUTH_TYPES = {
264
+ OAUTH: "oauth",
265
+ API_KEY: "api-key",
266
+ JWT: "jwt",
267
+ SERVICE_ACCOUNT: "service-account",
268
+ PAT: "pat",
269
+ USER_PASSWORD: "user-password"
270
+ };
271
+
272
+ // ../connectors/src/connectors/meta-ads/tools/list-ad-accounts.ts
273
+ import { z } from "zod";
274
+ var BASE_URL2 = "https://graph.facebook.com/v21.0/";
275
+ var REQUEST_TIMEOUT_MS = 6e4;
276
+ var inputSchema = z.object({
277
+ toolUseIntent: z.string().optional().describe(
278
+ "Brief description of what you intend to accomplish with this tool call"
279
+ ),
280
+ connectionId: z.string().describe("ID of the Meta Ads connection to use")
281
+ });
282
+ var outputSchema = z.discriminatedUnion("success", [
283
+ z.object({
284
+ success: z.literal(true),
285
+ adAccounts: z.array(
286
+ z.object({
287
+ adAccountId: z.string(),
288
+ name: z.string()
289
+ })
290
+ )
291
+ }),
292
+ z.object({
293
+ success: z.literal(false),
294
+ error: z.string()
295
+ })
296
+ ]);
297
+ var listAdAccountsTool = new ConnectorTool({
298
+ name: "listAdAccounts",
299
+ description: "List Meta ad accounts accessible with the current access token.",
300
+ inputSchema,
301
+ outputSchema,
302
+ async execute({ connectionId }, connections) {
303
+ const connection2 = connections.find((c) => c.id === connectionId);
304
+ if (!connection2) {
305
+ return {
306
+ success: false,
307
+ error: `Connection ${connectionId} not found`
308
+ };
309
+ }
310
+ console.log(
311
+ `[connector-request] meta-ads/${connection2.name}: listAdAccounts`
312
+ );
313
+ try {
314
+ const accessToken = parameters.accessToken.getValue(connection2);
315
+ const url = `${BASE_URL2}me/adaccounts?fields=account_id,name,account_status&access_token=${encodeURIComponent(accessToken)}`;
316
+ const controller = new AbortController();
317
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
318
+ try {
319
+ const response = await fetch(url, {
320
+ method: "GET",
321
+ signal: controller.signal
322
+ });
323
+ const data = await response.json();
324
+ if (!response.ok) {
325
+ const errorMessage = data?.error?.message ?? `HTTP ${response.status} ${response.statusText}`;
326
+ return { success: false, error: errorMessage };
327
+ }
328
+ const adAccounts = (data.data ?? []).map((account) => ({
329
+ adAccountId: account.account_id ?? "",
330
+ name: account.name ?? account.account_id ?? ""
331
+ }));
332
+ return { success: true, adAccounts };
333
+ } finally {
334
+ clearTimeout(timeout);
335
+ }
336
+ } catch (err) {
337
+ const msg = err instanceof Error ? err.message : String(err);
338
+ return { success: false, error: msg };
339
+ }
340
+ }
341
+ });
342
+
343
+ // ../connectors/src/connectors/meta-ads/setup.ts
344
+ var listAdAccountsToolName = `meta-ads_${listAdAccountsTool.name}`;
345
+ var metaAdsOnboarding = new ConnectorOnboarding({
346
+ connectionSetupInstructions: {
347
+ ja: `\u4EE5\u4E0B\u306E\u624B\u9806\u3067Meta\u5E83\u544A\u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3092\u884C\u3063\u3066\u304F\u3060\u3055\u3044\u3002
348
+
349
+ 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
350
+ 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
351
+ 3. \`updateConnectionParameters\` \u3092\u547C\u3073\u51FA\u3059:
352
+ - \`parameterSlug\`: \`"ad-account-id"\`
353
+ - \`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
354
+ 4. \u30E6\u30FC\u30B6\u30FC\u304C\u9078\u629E\u3057\u305F\u30A2\u30AB\u30A6\u30F3\u30C8\u306E \`label\` \u304C\u30E1\u30C3\u30BB\u30FC\u30B8\u3068\u3057\u3066\u5C4A\u304F\u306E\u3067\u3001\u6B21\u306E\u30B9\u30C6\u30C3\u30D7\u306B\u9032\u3080
355
+
356
+ #### \u5236\u7D04
357
+ - **\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
358
+ - \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`,
359
+ en: `Follow these steps to set up the Meta Ads connection.
360
+
361
+ 1. Call \`${listAdAccountsToolName}\` to get the list of ad accounts accessible with the access token
362
+ 2. If an error occurs, ask the user to verify their access token
363
+ 3. Call \`updateConnectionParameters\`:
364
+ - \`parameterSlug\`: \`"ad-account-id"\`
365
+ - \`options\`: The ad account list. Each option's \`label\` should be \`Account Name (id: accountId)\`, \`value\` should be the account ID
366
+ 4. The \`label\` of the user's selected account will arrive as a message. Proceed to the next step
367
+
368
+ #### Constraints
369
+ - **Do NOT fetch report data during setup**. Only the metadata requests specified in the steps above are allowed
370
+ - Write only 1 sentence between tool calls, then immediately call the next tool. Skip unnecessary explanations and proceed efficiently`
371
+ },
372
+ dataOverviewInstructions: {
373
+ en: `1. Call meta-ads_request with GET act_{adAccountId}/campaigns?fields=id,name,status,objective to explore campaign data
374
+ 2. Call meta-ads_request with GET act_{adAccountId}/insights?fields=impressions,clicks,spend,ctr,cpm&date_preset=last_7d to check recent performance
375
+ 3. Explore ad sets and ads as needed to understand the data structure`,
376
+ ja: `1. meta-ads_request \u3067 GET act_{adAccountId}/campaigns?fields=id,name,status,objective \u3092\u547C\u3073\u51FA\u3057\u3066\u30AD\u30E3\u30F3\u30DA\u30FC\u30F3\u30C7\u30FC\u30BF\u3092\u63A2\u7D22
377
+ 2. meta-ads_request \u3067 GET act_{adAccountId}/insights?fields=impressions,clicks,spend,ctr,cpm&date_preset=last_7d \u3092\u547C\u3073\u51FA\u3057\u3066\u76F4\u8FD1\u306E\u30D1\u30D5\u30A9\u30FC\u30DE\u30F3\u30B9\u3092\u78BA\u8A8D
378
+ 3. \u5FC5\u8981\u306B\u5FDC\u3058\u3066\u5E83\u544A\u30BB\u30C3\u30C8\u3084\u5E83\u544A\u30C7\u30FC\u30BF\u3092\u63A2\u7D22\u3057\u3001\u30C7\u30FC\u30BF\u69CB\u9020\u3092\u628A\u63E1`
379
+ }
380
+ });
381
+
382
+ // ../connectors/src/connectors/meta-ads/tools/request.ts
383
+ import { z as z2 } from "zod";
384
+ var BASE_URL3 = "https://graph.facebook.com/v21.0/";
385
+ var REQUEST_TIMEOUT_MS2 = 6e4;
386
+ var inputSchema2 = z2.object({
387
+ toolUseIntent: z2.string().optional().describe(
388
+ "Brief description of what you intend to accomplish with this tool call"
389
+ ),
390
+ connectionId: z2.string().describe("ID of the Meta Ads connection to use"),
391
+ method: z2.enum(["GET", "POST"]).describe("HTTP method"),
392
+ path: z2.string().describe(
393
+ "API path appended to https://graph.facebook.com/v21.0/ (e.g., 'act_{adAccountId}/campaigns'). {adAccountId} is automatically replaced."
394
+ ),
395
+ queryParams: z2.record(z2.string(), z2.string()).optional().describe("Query parameters to append to the URL"),
396
+ body: z2.record(z2.string(), z2.unknown()).optional().describe("POST request body (JSON)")
397
+ });
398
+ var outputSchema2 = z2.discriminatedUnion("success", [
399
+ z2.object({
400
+ success: z2.literal(true),
401
+ status: z2.number(),
402
+ data: z2.unknown()
403
+ }),
404
+ z2.object({
405
+ success: z2.literal(false),
406
+ error: z2.string()
407
+ })
408
+ ]);
409
+ var requestTool = new ConnectorTool({
410
+ name: "request",
411
+ description: `Send authenticated requests to the Meta Marketing API v21.0.
412
+ Authentication is handled via the configured access token.
413
+ {adAccountId} in the path is automatically replaced with the connection's ad account ID (with act_ prefix added).`,
414
+ inputSchema: inputSchema2,
415
+ outputSchema: outputSchema2,
416
+ async execute({ connectionId, method, path: path2, queryParams, body }, connections) {
417
+ const connection2 = connections.find((c) => c.id === connectionId);
418
+ if (!connection2) {
419
+ return {
420
+ success: false,
421
+ error: `Connection ${connectionId} not found`
422
+ };
423
+ }
424
+ console.log(
425
+ `[connector-request] meta-ads/${connection2.name}: ${method} ${path2}`
426
+ );
427
+ try {
428
+ const accessToken = parameters.accessToken.getValue(connection2);
429
+ const adAccountId = parameters.adAccountId.tryGetValue(connection2) ?? "";
430
+ const resolvedPath = adAccountId ? path2.replace(/\{adAccountId\}/g, adAccountId) : path2;
431
+ let url = `${BASE_URL3}${resolvedPath}`;
432
+ const params = new URLSearchParams(queryParams ?? {});
433
+ params.set("access_token", accessToken);
434
+ const separator = url.includes("?") ? "&" : "?";
435
+ url = `${url}${separator}${params.toString()}`;
436
+ const controller = new AbortController();
437
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS2);
438
+ try {
439
+ const response = await fetch(url, {
440
+ method,
441
+ headers: {
442
+ "Content-Type": "application/json"
443
+ },
444
+ ...method === "POST" && body ? { body: JSON.stringify(body) } : {},
445
+ signal: controller.signal
446
+ });
447
+ const data = await response.json();
448
+ if (!response.ok) {
449
+ const dataObj = data;
450
+ const errorObj = dataObj?.error;
451
+ const errorMessage = typeof errorObj?.message === "string" ? errorObj.message : typeof dataObj?.error === "string" ? dataObj.error : `HTTP ${response.status} ${response.statusText}`;
452
+ return { success: false, error: errorMessage };
453
+ }
454
+ return { success: true, status: response.status, data };
455
+ } finally {
456
+ clearTimeout(timeout);
457
+ }
458
+ } catch (err) {
459
+ const msg = err instanceof Error ? err.message : String(err);
460
+ return { success: false, error: msg };
461
+ }
462
+ }
463
+ });
464
+
465
+ // ../connectors/src/connectors/meta-ads/index.ts
466
+ var tools = {
467
+ request: requestTool,
468
+ listAdAccounts: listAdAccountsTool
469
+ };
470
+ var metaAdsConnector = new ConnectorPlugin({
471
+ slug: "meta-ads",
472
+ authType: AUTH_TYPES.API_KEY,
473
+ name: "Meta Ads",
474
+ description: "Connect to Meta (Facebook/Instagram) Ads for advertising campaign data and reporting using an access token.",
475
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/2vyrgcvdf3jETIFXHtbteO/de7f3288e831c9f738e44cf1f961c3bd/meta-icon.webp",
476
+ parameters,
477
+ releaseFlag: { dev1: true, dev2: false, prod: false },
478
+ onboarding: metaAdsOnboarding,
479
+ systemPrompt: {
480
+ en: `### Tools
481
+
482
+ - \`meta-ads_request\`: Send authenticated requests to the Meta Marketing API v21.0. The {adAccountId} placeholder in paths is automatically replaced. Authentication is configured via the access token parameter.
483
+ - \`meta-ads_listAdAccounts\`: List accessible Meta ad accounts. Use this during setup to discover available accounts.
484
+
485
+ ### Meta Marketing API Reference
486
+
487
+ #### List Campaigns
488
+ - GET act_{adAccountId}/campaigns?fields=id,name,status,objective,daily_budget,lifetime_budget
489
+
490
+ #### List Ad Sets
491
+ - GET act_{adAccountId}/adsets?fields=id,name,status,targeting,daily_budget,bid_amount
492
+
493
+ #### List Ads
494
+ - GET act_{adAccountId}/ads?fields=id,name,status,creative
495
+
496
+ #### Get Insights (Performance Data)
497
+ - GET act_{adAccountId}/insights?fields=impressions,clicks,spend,ctr,cpm,cpc,conversions,actions&date_preset=last_30d
498
+ - GET {campaignId}/insights?fields=impressions,clicks,spend&time_range={"since":"2025-01-01","until":"2025-01-31"}
499
+
500
+ ### Common Fields for Insights
501
+ impressions, reach, frequency, clicks, ctr, cpc, cpm, cpp, spend,
502
+ conversions, actions, action_values, cost_per_action_type,
503
+ video_p25_watched_actions, video_p50_watched_actions, video_p75_watched_actions, video_p100_watched_actions
504
+
505
+ ### Date Filters
506
+ - \`date_preset\`: today, yesterday, last_7d, last_14d, last_30d, last_90d, this_month, last_month
507
+ - \`time_range\`: {"since":"2025-01-01","until":"2025-01-31"}
508
+ - \`time_increment\`: 1 (daily), 7 (weekly), monthly, all_days
509
+
510
+ ### Breakdowns
511
+ age, gender, country, region, publisher_platform, platform_position, device_platform, impression_device
512
+
513
+ ### Pagination
514
+ Responses include a \`paging\` object with \`cursors.after\` and \`cursors.before\`. Use \`after\` parameter for next page.
515
+
516
+ ### Tips
517
+ - Ad account IDs require the \`act_\` prefix (e.g., act_123456789)
518
+ - Always specify \`fields\` parameter \u2014 without it, only IDs are returned
519
+ - Use \`level\` parameter in insights to aggregate at account/campaign/adset/ad level
520
+ - Use \`filtering\` parameter for server-side filtering: [{"field":"campaign.name","operator":"CONTAIN","value":"Brand"}]
521
+
522
+ ### Business Logic
523
+
524
+ The business logic type for this connector is "typescript". Write handler code using the connector SDK shown below. Do NOT access credentials directly from environment variables.
525
+
526
+ #### Example
527
+
528
+ \`\`\`ts
529
+ import { connection } from "@squadbase/vite-server/connectors/meta-ads";
530
+
531
+ const meta = connection("<connectionId>");
532
+
533
+ // Get insights for the ad account
534
+ const insights = await meta.getInsights("act_{adAccountId}", {
535
+ fields: "impressions,clicks,spend,ctr",
536
+ date_preset: "last_30d",
537
+ });
538
+
539
+ // List ad accounts
540
+ const accounts = await meta.listAdAccounts();
541
+ \`\`\``,
542
+ ja: `### \u30C4\u30FC\u30EB
543
+
544
+ - \`meta-ads_request\`: Meta Marketing API v21.0\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
545
+ - \`meta-ads_listAdAccounts\`: \u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306AMeta\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
546
+
547
+ ### Meta Marketing API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
548
+
549
+ #### \u30AD\u30E3\u30F3\u30DA\u30FC\u30F3\u4E00\u89A7
550
+ - GET act_{adAccountId}/campaigns?fields=id,name,status,objective,daily_budget,lifetime_budget
551
+
552
+ #### \u5E83\u544A\u30BB\u30C3\u30C8\u4E00\u89A7
553
+ - GET act_{adAccountId}/adsets?fields=id,name,status,targeting,daily_budget,bid_amount
554
+
555
+ #### \u5E83\u544A\u4E00\u89A7
556
+ - GET act_{adAccountId}/ads?fields=id,name,status,creative
557
+
558
+ #### \u30A4\u30F3\u30B5\u30A4\u30C8\uFF08\u30D1\u30D5\u30A9\u30FC\u30DE\u30F3\u30B9\u30C7\u30FC\u30BF\uFF09\u306E\u53D6\u5F97
559
+ - GET act_{adAccountId}/insights?fields=impressions,clicks,spend,ctr,cpm,cpc,conversions,actions&date_preset=last_30d
560
+ - GET {campaignId}/insights?fields=impressions,clicks,spend&time_range={"since":"2025-01-01","until":"2025-01-31"}
561
+
562
+ ### \u30A4\u30F3\u30B5\u30A4\u30C8\u306E\u4E3B\u8981\u30D5\u30A3\u30FC\u30EB\u30C9
563
+ impressions, reach, frequency, clicks, ctr, cpc, cpm, cpp, spend,
564
+ conversions, actions, action_values, cost_per_action_type,
565
+ video_p25_watched_actions, video_p50_watched_actions, video_p75_watched_actions, video_p100_watched_actions
566
+
567
+ ### \u65E5\u4ED8\u30D5\u30A3\u30EB\u30BF
568
+ - \`date_preset\`: today, yesterday, last_7d, last_14d, last_30d, last_90d, this_month, last_month
569
+ - \`time_range\`: {"since":"2025-01-01","until":"2025-01-31"}
570
+ - \`time_increment\`: 1\uFF08\u65E5\u6B21\uFF09, 7\uFF08\u9031\u6B21\uFF09, monthly, all_days
571
+
572
+ ### \u30D6\u30EC\u30A4\u30AF\u30C0\u30A6\u30F3
573
+ age, gender, country, region, publisher_platform, platform_position, device_platform, impression_device
574
+
575
+ ### \u30DA\u30FC\u30B8\u30CD\u30FC\u30B7\u30E7\u30F3
576
+ \u30EC\u30B9\u30DD\u30F3\u30B9\u306B\u306F \`paging\` \u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u304C\u542B\u307E\u308C\u3001\`cursors.after\` \u3068 \`cursors.before\` \u304C\u3042\u308A\u307E\u3059\u3002\u6B21\u30DA\u30FC\u30B8\u306B\u306F \`after\` \u30D1\u30E9\u30E1\u30FC\u30BF\u3092\u4F7F\u7528\u3057\u307E\u3059\u3002
577
+
578
+ ### \u30D2\u30F3\u30C8
579
+ - \u5E83\u544A\u30A2\u30AB\u30A6\u30F3\u30C8ID\u306B\u306F \`act_\` \u30D7\u30EC\u30D5\u30A3\u30C3\u30AF\u30B9\u304C\u5FC5\u8981\u3067\u3059\uFF08\u4F8B\uFF1Aact_123456789\uFF09
580
+ - \`fields\` \u30D1\u30E9\u30E1\u30FC\u30BF\u3092\u5FC5\u305A\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044 \u2014 \u6307\u5B9A\u3057\u306A\u3044\u5834\u5408\u306FID\u306E\u307F\u304C\u8FD4\u3055\u308C\u307E\u3059
581
+ - \u30A4\u30F3\u30B5\u30A4\u30C8\u306E \`level\` \u30D1\u30E9\u30E1\u30FC\u30BF\u3067account/campaign/adset/ad\u30EC\u30D9\u30EB\u306E\u96C6\u8A08\u304C\u53EF\u80FD\u3067\u3059
582
+ - \`filtering\` \u30D1\u30E9\u30E1\u30FC\u30BF\u3067\u30B5\u30FC\u30D0\u30FC\u30B5\u30A4\u30C9\u30D5\u30A3\u30EB\u30BF\u30EA\u30F3\u30B0\u304C\u53EF\u80FD: [{"field":"campaign.name","operator":"CONTAIN","value":"Brand"}]
583
+
584
+ ### Business Logic
585
+
586
+ \u3053\u306E\u30B3\u30CD\u30AF\u30BF\u306E\u30D3\u30B8\u30CD\u30B9\u30ED\u30B8\u30C3\u30AF\u30BF\u30A4\u30D7\u306F "typescript" \u3067\u3059\u3002\u4EE5\u4E0B\u306B\u793A\u3059\u30B3\u30CD\u30AF\u30BFSDK\u3092\u4F7F\u7528\u3057\u3066\u30CF\u30F3\u30C9\u30E9\u30B3\u30FC\u30C9\u3092\u8A18\u8FF0\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u74B0\u5883\u5909\u6570\u304B\u3089\u76F4\u63A5\u8A8D\u8A3C\u60C5\u5831\u306B\u30A2\u30AF\u30BB\u30B9\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
587
+
588
+ #### Example
589
+
590
+ \`\`\`ts
591
+ import { connection } from "@squadbase/vite-server/connectors/meta-ads";
592
+
593
+ const meta = connection("<connectionId>");
594
+
595
+ // \u5E83\u544A\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u30A4\u30F3\u30B5\u30A4\u30C8\u3092\u53D6\u5F97
596
+ const insights = await meta.getInsights("act_{adAccountId}", {
597
+ fields: "impressions,clicks,spend,ctr",
598
+ date_preset: "last_30d",
599
+ });
600
+
601
+ // \u5E83\u544A\u30A2\u30AB\u30A6\u30F3\u30C8\u4E00\u89A7\u3092\u53D6\u5F97
602
+ const accounts = await meta.listAdAccounts();
603
+ \`\`\``
604
+ },
605
+ tools,
606
+ async checkConnection(params) {
607
+ const accessToken = params[parameters.accessToken.slug];
608
+ if (!accessToken) {
609
+ return {
610
+ success: false,
611
+ error: "Access token is required"
612
+ };
613
+ }
614
+ try {
615
+ const url = `https://graph.facebook.com/v21.0/me?fields=id,name&access_token=${encodeURIComponent(accessToken)}`;
616
+ const res = await fetch(url, { method: "GET" });
617
+ if (!res.ok) {
618
+ const data = await res.json().catch(() => ({}));
619
+ return {
620
+ success: false,
621
+ error: data?.error?.message ?? `Meta API failed: HTTP ${res.status}`
622
+ };
623
+ }
624
+ return { success: true };
625
+ } catch (error) {
626
+ return {
627
+ success: false,
628
+ error: error instanceof Error ? error.message : String(error)
629
+ };
630
+ }
631
+ }
632
+ });
633
+
634
+ // src/connectors/create-connector-sdk.ts
635
+ import { readFileSync } from "fs";
636
+ import path from "path";
637
+
638
+ // src/connector-client/env.ts
639
+ function resolveEnvVar(entry, key, connectionId) {
640
+ const envVarName = entry.envVars[key];
641
+ if (!envVarName) {
642
+ throw new Error(`Connection "${connectionId}" is missing envVars mapping for key "${key}"`);
643
+ }
644
+ const value = process.env[envVarName];
645
+ if (!value) {
646
+ throw new Error(`Environment variable "${envVarName}" (for connection "${connectionId}", key "${key}") is not set`);
647
+ }
648
+ return value;
649
+ }
650
+ function resolveEnvVarOptional(entry, key) {
651
+ const envVarName = entry.envVars[key];
652
+ if (!envVarName) return void 0;
653
+ return process.env[envVarName] || void 0;
654
+ }
655
+
656
+ // src/connector-client/proxy-fetch.ts
657
+ import { getContext } from "hono/context-storage";
658
+ import { getCookie } from "hono/cookie";
659
+ var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
660
+ function normalizeHeaders(input) {
661
+ const out = {};
662
+ if (!input) return out;
663
+ new Headers(input).forEach((value, key) => {
664
+ out[key] = value;
665
+ });
666
+ return out;
667
+ }
668
+ function createSandboxProxyFetch(connectionId) {
669
+ return async (input, init) => {
670
+ const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
671
+ const sandboxId = process.env.INTERNAL_SQUADBASE_SANDBOX_ID;
672
+ if (!token || !sandboxId) {
673
+ throw new Error(
674
+ "Connection proxy is not configured. Please check your deployment settings."
675
+ );
676
+ }
677
+ const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
678
+ const originalMethod = init?.method ?? "GET";
679
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
680
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
681
+ const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
682
+ return fetch(proxyUrl, {
683
+ method: "POST",
684
+ headers: {
685
+ "Content-Type": "application/json",
686
+ Authorization: `Bearer ${token}`
687
+ },
688
+ body: JSON.stringify({
689
+ url: originalUrl,
690
+ method: originalMethod,
691
+ headers: normalizeHeaders(init?.headers),
692
+ body: originalBody
693
+ })
694
+ });
695
+ };
696
+ }
697
+ function createDeployedAppProxyFetch(connectionId) {
698
+ const projectId = process.env["SQUADBASE_PROJECT_ID"];
699
+ if (!projectId) {
700
+ throw new Error(
701
+ "Connection proxy is not configured. Please check your deployment settings."
702
+ );
703
+ }
704
+ const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
705
+ const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
706
+ return async (input, init) => {
707
+ const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
708
+ const originalMethod = init?.method ?? "GET";
709
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
710
+ const c = getContext();
711
+ const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
712
+ if (!appSession) {
713
+ throw new Error(
714
+ "No authentication method available for connection proxy."
715
+ );
716
+ }
717
+ return fetch(proxyUrl, {
718
+ method: "POST",
719
+ headers: {
720
+ "Content-Type": "application/json",
721
+ Authorization: `Bearer ${appSession}`
722
+ },
723
+ body: JSON.stringify({
724
+ url: originalUrl,
725
+ method: originalMethod,
726
+ headers: normalizeHeaders(init?.headers),
727
+ body: originalBody
728
+ })
729
+ });
730
+ };
731
+ }
732
+ function createProxyFetch(connectionId) {
733
+ if (process.env.INTERNAL_SQUADBASE_SANDBOX_ID) {
734
+ return createSandboxProxyFetch(connectionId);
735
+ }
736
+ return createDeployedAppProxyFetch(connectionId);
737
+ }
738
+
739
+ // src/connectors/create-connector-sdk.ts
740
+ function loadConnectionsSync() {
741
+ const filePath = process.env.CONNECTIONS_PATH ?? path.join(process.cwd(), ".squadbase/connections.json");
742
+ try {
743
+ const raw = readFileSync(filePath, "utf-8");
744
+ return JSON.parse(raw);
745
+ } catch {
746
+ return {};
747
+ }
748
+ }
749
+ function createConnectorSdk(plugin, createClient2) {
750
+ return (connectionId) => {
751
+ const connections = loadConnectionsSync();
752
+ const entry = connections[connectionId];
753
+ if (!entry) {
754
+ throw new Error(
755
+ `Connection "${connectionId}" not found in .squadbase/connections.json`
756
+ );
757
+ }
758
+ if (entry.connector.slug !== plugin.slug) {
759
+ throw new Error(
760
+ `Connection "${connectionId}" is not a ${plugin.slug} connection (got "${entry.connector.slug}")`
761
+ );
762
+ }
763
+ const params = {};
764
+ for (const param of Object.values(plugin.parameters)) {
765
+ if (param.required) {
766
+ params[param.slug] = resolveEnvVar(entry, param.slug, connectionId);
767
+ } else {
768
+ const val = resolveEnvVarOptional(entry, param.slug);
769
+ if (val !== void 0) params[param.slug] = val;
770
+ }
771
+ }
772
+ return createClient2(params, createProxyFetch(connectionId));
773
+ };
774
+ }
775
+
776
+ // src/connectors/entries/meta-ads.ts
777
+ var connection = createConnectorSdk(metaAdsConnector, createClient);
778
+ export {
779
+ connection
780
+ };