@squadbase/vite-server 0.1.5-dev.0 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +411 -236
- package/dist/connectors/airtable-oauth.js +0 -8
- package/dist/connectors/gmail-oauth.js +0 -8
- package/dist/connectors/gmail.js +0 -8
- package/dist/connectors/google-ads.js +0 -8
- package/dist/connectors/google-analytics-oauth.js +0 -8
- package/dist/connectors/google-calendar-oauth.js +0 -8
- package/dist/connectors/google-calendar.js +0 -10
- package/dist/connectors/hubspot-oauth.js +0 -6
- package/dist/connectors/influxdb.d.ts +5 -0
- package/dist/connectors/influxdb.js +767 -0
- package/dist/connectors/intercom-oauth.js +0 -6
- package/dist/connectors/linear.d.ts +5 -0
- package/dist/connectors/linear.js +688 -0
- package/dist/connectors/linkedin-ads.js +0 -8
- package/dist/connectors/meta-ads-oauth.d.ts +5 -0
- package/dist/connectors/meta-ads-oauth.js +795 -0
- package/dist/connectors/meta-ads.d.ts +5 -0
- package/dist/connectors/meta-ads.js +780 -0
- package/dist/connectors/notion-oauth.js +0 -6
- package/dist/connectors/shopify-oauth.js +0 -6
- package/dist/connectors/stripe-api-key.js +0 -4
- package/dist/connectors/stripe-oauth.js +0 -6
- package/dist/connectors/tiktok-ads.d.ts +5 -0
- package/dist/connectors/tiktok-ads.js +840 -0
- package/dist/connectors/zendesk-oauth.js +0 -6
- package/dist/index.js +411 -236
- package/dist/main.js +411 -236
- package/dist/vite-plugin.js +411 -236
- package/package.json +21 -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
|
+
};
|