@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,840 @@
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/tiktok-ads/sdk/index.ts
46
+ var BASE_URL = "https://business-api.tiktok.com/open_api/v1.3/";
47
+ function createClient(_params, fetchFn = fetch) {
48
+ function request(path2, init) {
49
+ const url = `${BASE_URL}${path2}`;
50
+ return fetchFn(url, init);
51
+ }
52
+ return { request };
53
+ }
54
+
55
+ // ../connectors/src/connector-onboarding.ts
56
+ var ConnectorOnboarding = class {
57
+ /** Phase 1: Connection setup instructions (optional — some connectors don't need this) */
58
+ connectionSetupInstructions;
59
+ /** Phase 2: Data overview instructions */
60
+ dataOverviewInstructions;
61
+ constructor(config) {
62
+ this.connectionSetupInstructions = config.connectionSetupInstructions;
63
+ this.dataOverviewInstructions = config.dataOverviewInstructions;
64
+ }
65
+ getConnectionSetupPrompt(language) {
66
+ return this.connectionSetupInstructions?.[language] ?? null;
67
+ }
68
+ getDataOverviewInstructions(language) {
69
+ return this.dataOverviewInstructions[language];
70
+ }
71
+ };
72
+
73
+ // ../connectors/src/connector-tool.ts
74
+ var ConnectorTool = class {
75
+ name;
76
+ description;
77
+ inputSchema;
78
+ outputSchema;
79
+ _execute;
80
+ constructor(config) {
81
+ this.name = config.name;
82
+ this.description = config.description;
83
+ this.inputSchema = config.inputSchema;
84
+ this.outputSchema = config.outputSchema;
85
+ this._execute = config.execute;
86
+ }
87
+ createTool(connections, config) {
88
+ return {
89
+ description: this.description,
90
+ inputSchema: this.inputSchema,
91
+ outputSchema: this.outputSchema,
92
+ execute: (input) => this._execute(input, connections, config)
93
+ };
94
+ }
95
+ };
96
+
97
+ // ../connectors/src/connector-plugin.ts
98
+ var ConnectorPlugin = class _ConnectorPlugin {
99
+ slug;
100
+ authType;
101
+ name;
102
+ description;
103
+ iconUrl;
104
+ parameters;
105
+ releaseFlag;
106
+ proxyPolicy;
107
+ experimentalAttributes;
108
+ onboarding;
109
+ systemPrompt;
110
+ tools;
111
+ query;
112
+ checkConnection;
113
+ constructor(config) {
114
+ this.slug = config.slug;
115
+ this.authType = config.authType;
116
+ this.name = config.name;
117
+ this.description = config.description;
118
+ this.iconUrl = config.iconUrl;
119
+ this.parameters = config.parameters;
120
+ this.releaseFlag = config.releaseFlag;
121
+ this.proxyPolicy = config.proxyPolicy;
122
+ this.experimentalAttributes = config.experimentalAttributes;
123
+ this.onboarding = config.onboarding;
124
+ this.systemPrompt = config.systemPrompt;
125
+ this.tools = config.tools;
126
+ this.query = config.query;
127
+ this.checkConnection = config.checkConnection;
128
+ }
129
+ get connectorKey() {
130
+ return _ConnectorPlugin.deriveKey(this.slug, this.authType);
131
+ }
132
+ /**
133
+ * Create tools for connections that belong to this connector.
134
+ * Filters connections by connectorKey internally.
135
+ * Returns tools keyed as `${connectorKey}_${toolName}`.
136
+ */
137
+ createTools(connections, config, opts) {
138
+ const myConnections = connections.filter(
139
+ (c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
140
+ );
141
+ const result = {};
142
+ for (const t of Object.values(this.tools)) {
143
+ const tool = t.createTool(myConnections, config);
144
+ const originalToModelOutput = tool.toModelOutput;
145
+ result[`${this.connectorKey}_${t.name}`] = {
146
+ ...tool,
147
+ toModelOutput: async (options) => {
148
+ if (!originalToModelOutput) {
149
+ return opts.truncateOutput(options.output);
150
+ }
151
+ const modelOutput = await originalToModelOutput(options);
152
+ if (modelOutput.type === "text" || modelOutput.type === "json") {
153
+ return opts.truncateOutput(modelOutput.value);
154
+ }
155
+ return modelOutput;
156
+ }
157
+ };
158
+ }
159
+ return result;
160
+ }
161
+ static deriveKey(slug, authType) {
162
+ if (authType) return `${slug}-${authType}`;
163
+ const LEGACY_NULL_AUTH_TYPE_MAP = {
164
+ // user-password
165
+ "postgresql": "user-password",
166
+ "mysql": "user-password",
167
+ "clickhouse": "user-password",
168
+ "kintone": "user-password",
169
+ "squadbase-db": "user-password",
170
+ // service-account
171
+ "snowflake": "service-account",
172
+ "bigquery": "service-account",
173
+ "google-analytics": "service-account",
174
+ "google-calendar": "service-account",
175
+ "aws-athena": "service-account",
176
+ "redshift": "service-account",
177
+ // api-key
178
+ "databricks": "api-key",
179
+ "dbt": "api-key",
180
+ "airtable": "api-key",
181
+ "openai": "api-key",
182
+ "gemini": "api-key",
183
+ "anthropic": "api-key",
184
+ "wix-store": "api-key"
185
+ };
186
+ const fallbackAuthType = LEGACY_NULL_AUTH_TYPE_MAP[slug];
187
+ if (fallbackAuthType) return `${slug}-${fallbackAuthType}`;
188
+ return slug;
189
+ }
190
+ };
191
+
192
+ // ../connectors/src/auth-types.ts
193
+ var AUTH_TYPES = {
194
+ OAUTH: "oauth",
195
+ API_KEY: "api-key",
196
+ JWT: "jwt",
197
+ SERVICE_ACCOUNT: "service-account",
198
+ PAT: "pat",
199
+ USER_PASSWORD: "user-password"
200
+ };
201
+
202
+ // ../connectors/src/connectors/tiktok-ads/tools/list-advertisers.ts
203
+ import { z } from "zod";
204
+ var BASE_URL2 = "https://business-api.tiktok.com/open_api/v1.3/";
205
+ var REQUEST_TIMEOUT_MS = 6e4;
206
+ var cachedToken = null;
207
+ async function getProxyToken(config) {
208
+ if (cachedToken && cachedToken.expiresAt > Date.now() + 6e4) {
209
+ return cachedToken.token;
210
+ }
211
+ const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
212
+ const res = await fetch(url, {
213
+ method: "POST",
214
+ headers: {
215
+ "Content-Type": "application/json",
216
+ "x-api-key": config.appApiKey,
217
+ "project-id": config.projectId
218
+ },
219
+ body: JSON.stringify({
220
+ sandboxId: config.sandboxId,
221
+ issuedBy: "coding-agent"
222
+ })
223
+ });
224
+ if (!res.ok) {
225
+ const errorText = await res.text().catch(() => res.statusText);
226
+ throw new Error(
227
+ `Failed to get proxy token: HTTP ${res.status} ${errorText}`
228
+ );
229
+ }
230
+ const data = await res.json();
231
+ cachedToken = {
232
+ token: data.token,
233
+ expiresAt: new Date(data.expiresAt).getTime()
234
+ };
235
+ return data.token;
236
+ }
237
+ var inputSchema = z.object({
238
+ toolUseIntent: z.string().optional().describe(
239
+ "Brief description of what you intend to accomplish with this tool call"
240
+ ),
241
+ connectionId: z.string().describe("ID of the TikTok Ads OAuth connection to use")
242
+ });
243
+ var outputSchema = z.discriminatedUnion("success", [
244
+ z.object({
245
+ success: z.literal(true),
246
+ advertisers: z.array(
247
+ z.object({
248
+ advertiserId: z.string(),
249
+ name: z.string()
250
+ })
251
+ )
252
+ }),
253
+ z.object({
254
+ success: z.literal(false),
255
+ error: z.string()
256
+ })
257
+ ]);
258
+ var listAdvertisersTool = new ConnectorTool({
259
+ name: "listAdvertisers",
260
+ description: "List TikTok Ads advertiser accounts accessible with the current OAuth credentials.",
261
+ inputSchema,
262
+ outputSchema,
263
+ async execute({ connectionId }, connections, config) {
264
+ const connection2 = connections.find((c) => c.id === connectionId);
265
+ if (!connection2) {
266
+ return {
267
+ success: false,
268
+ error: `Connection ${connectionId} not found`
269
+ };
270
+ }
271
+ console.log(
272
+ `[connector-request] tiktok-ads/${connection2.name}: listAdvertisers`
273
+ );
274
+ try {
275
+ const token = await getProxyToken(config.oauthProxy);
276
+ const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
277
+ const controller = new AbortController();
278
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
279
+ try {
280
+ const advertiserListResponse = await fetch(proxyUrl, {
281
+ method: "POST",
282
+ headers: {
283
+ "Content-Type": "application/json",
284
+ Authorization: `Bearer ${token}`
285
+ },
286
+ body: JSON.stringify({
287
+ url: `${BASE_URL2}oauth2/advertiser/get/`,
288
+ method: "GET"
289
+ }),
290
+ signal: controller.signal
291
+ });
292
+ const advertiserListData = await advertiserListResponse.json();
293
+ if (!advertiserListResponse.ok) {
294
+ return {
295
+ success: false,
296
+ error: advertiserListData?.message ?? `HTTP ${advertiserListResponse.status}`
297
+ };
298
+ }
299
+ if (advertiserListData.code !== void 0 && advertiserListData.code !== 0) {
300
+ return {
301
+ success: false,
302
+ error: advertiserListData.message ?? `API error code: ${advertiserListData.code}`
303
+ };
304
+ }
305
+ const advertisers = (advertiserListData.data?.list ?? []).map(
306
+ (adv) => ({
307
+ advertiserId: String(adv.advertiser_id ?? ""),
308
+ name: adv.advertiser_name ?? String(adv.advertiser_id ?? "")
309
+ })
310
+ );
311
+ return { success: true, advertisers };
312
+ } finally {
313
+ clearTimeout(timeout);
314
+ }
315
+ } catch (err) {
316
+ const msg = err instanceof Error ? err.message : String(err);
317
+ return { success: false, error: msg };
318
+ }
319
+ }
320
+ });
321
+
322
+ // ../connectors/src/connectors/tiktok-ads/setup.ts
323
+ var listAdvertisersToolName = `tiktok-ads_${listAdvertisersTool.name}`;
324
+ var tiktokAdsOnboarding = new ConnectorOnboarding({
325
+ connectionSetupInstructions: {
326
+ ja: `\u4EE5\u4E0B\u306E\u624B\u9806\u3067TikTok\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
327
+
328
+ 1. \`${listAdvertisersToolName}\` \u3092\u547C\u3073\u51FA\u3057\u3066\u3001OAuth\u3067\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u5E83\u544A\u4E3B\u30A2\u30AB\u30A6\u30F3\u30C8\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B
329
+ 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
330
+ 3. \`updateConnectionParameters\` \u3092\u547C\u3073\u51FA\u3059:
331
+ - \`parameterSlug\`: \`"advertiser-id"\`
332
+ - \`options\`: \u5E83\u544A\u4E3B\u4E00\u89A7\u3002\u5404 option \u306E \`label\` \u306F \`\u5E83\u544A\u4E3B\u540D (id: \u5E83\u544A\u4E3BID)\` \u306E\u5F62\u5F0F\u3001\`value\` \u306F\u5E83\u544A\u4E3BID
333
+ 4. \u30E6\u30FC\u30B6\u30FC\u304C\u9078\u629E\u3057\u305F\u5E83\u544A\u4E3B\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
334
+
335
+ #### \u5236\u7D04
336
+ - **\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
337
+ - \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`,
338
+ en: `Follow these steps to set up the TikTok Ads (OAuth) connection.
339
+
340
+ 1. Call \`${listAdvertisersToolName}\` to get the list of advertiser accounts accessible with the OAuth credentials
341
+ 2. If an error occurs, ask the user to verify their OAuth connection
342
+ 3. Call \`updateConnectionParameters\`:
343
+ - \`parameterSlug\`: \`"advertiser-id"\`
344
+ - \`options\`: The advertiser list. Each option's \`label\` should be \`Advertiser Name (id: advertiserId)\`, \`value\` should be the advertiser ID
345
+ 4. The \`label\` of the user's selected advertiser will arrive as a message. Proceed to the next step
346
+
347
+ #### Constraints
348
+ - **Do NOT fetch report data during setup**. Only the metadata requests specified in the steps above are allowed
349
+ - Write only 1 sentence between tool calls, then immediately call the next tool. Skip unnecessary explanations and proceed efficiently`
350
+ },
351
+ dataOverviewInstructions: {
352
+ en: `1. Call tiktok-ads_request with GET campaign/get/ to explore campaign data
353
+ 2. Call tiktok-ads_request with GET adgroup/get/ to explore ad group data
354
+ 3. Call tiktok-ads_request with GET report/integrated/get/ with metrics=["spend","impressions","clicks","ctr","cpm","cpc"]&dimensions=["campaign_id"]&data_level=AUCTION_CAMPAIGN&start_date=YYYY-MM-DD&end_date=YYYY-MM-DD to check recent performance`,
355
+ ja: `1. tiktok-ads_request \u3067 GET campaign/get/ \u3092\u547C\u3073\u51FA\u3057\u3066\u30AD\u30E3\u30F3\u30DA\u30FC\u30F3\u30C7\u30FC\u30BF\u3092\u63A2\u7D22
356
+ 2. tiktok-ads_request \u3067 GET adgroup/get/ \u3092\u547C\u3073\u51FA\u3057\u3066\u5E83\u544A\u30B0\u30EB\u30FC\u30D7\u30C7\u30FC\u30BF\u3092\u63A2\u7D22
357
+ 3. tiktok-ads_request \u3067 GET report/integrated/get/ \u306B metrics=["spend","impressions","clicks","ctr","cpm","cpc"]&dimensions=["campaign_id"]&data_level=AUCTION_CAMPAIGN&start_date=YYYY-MM-DD&end_date=YYYY-MM-DD \u3092\u6307\u5B9A\u3057\u3066\u76F4\u8FD1\u306E\u30D1\u30D5\u30A9\u30FC\u30DE\u30F3\u30B9\u3092\u78BA\u8A8D`
358
+ }
359
+ });
360
+
361
+ // ../connectors/src/connectors/tiktok-ads/parameters.ts
362
+ var parameters = {
363
+ advertiserId: new ParameterDefinition({
364
+ slug: "advertiser-id",
365
+ name: "Advertiser ID",
366
+ description: "The TikTok Ads advertiser ID. Found in the TikTok Ads Manager dashboard.",
367
+ envVarBaseKey: "TIKTOK_ADS_ADVERTISER_ID",
368
+ type: "text",
369
+ secret: false,
370
+ required: false
371
+ })
372
+ };
373
+
374
+ // ../connectors/src/connectors/tiktok-ads/tools/request.ts
375
+ import { z as z2 } from "zod";
376
+ var BASE_URL3 = "https://business-api.tiktok.com/open_api/v1.3/";
377
+ var REQUEST_TIMEOUT_MS2 = 6e4;
378
+ var cachedToken2 = null;
379
+ async function getProxyToken2(config) {
380
+ if (cachedToken2 && cachedToken2.expiresAt > Date.now() + 6e4) {
381
+ return cachedToken2.token;
382
+ }
383
+ const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
384
+ const res = await fetch(url, {
385
+ method: "POST",
386
+ headers: {
387
+ "Content-Type": "application/json",
388
+ "x-api-key": config.appApiKey,
389
+ "project-id": config.projectId
390
+ },
391
+ body: JSON.stringify({
392
+ sandboxId: config.sandboxId,
393
+ issuedBy: "coding-agent"
394
+ })
395
+ });
396
+ if (!res.ok) {
397
+ const errorText = await res.text().catch(() => res.statusText);
398
+ throw new Error(
399
+ `Failed to get proxy token: HTTP ${res.status} ${errorText}`
400
+ );
401
+ }
402
+ const data = await res.json();
403
+ cachedToken2 = {
404
+ token: data.token,
405
+ expiresAt: new Date(data.expiresAt).getTime()
406
+ };
407
+ return data.token;
408
+ }
409
+ var inputSchema2 = z2.object({
410
+ toolUseIntent: z2.string().optional().describe(
411
+ "Brief description of what you intend to accomplish with this tool call"
412
+ ),
413
+ connectionId: z2.string().describe("ID of the TikTok Ads OAuth connection to use"),
414
+ method: z2.enum(["GET", "POST"]).describe("HTTP method"),
415
+ path: z2.string().describe(
416
+ "API path appended to https://business-api.tiktok.com/open_api/v1.3/ (e.g., 'campaign/get/'). The advertiser_id is automatically injected."
417
+ ),
418
+ queryParams: z2.record(z2.string(), z2.string()).optional().describe("Query parameters to append to the URL"),
419
+ body: z2.record(z2.string(), z2.unknown()).optional().describe("POST request body (JSON)")
420
+ });
421
+ var outputSchema2 = z2.discriminatedUnion("success", [
422
+ z2.object({
423
+ success: z2.literal(true),
424
+ status: z2.number(),
425
+ data: z2.unknown()
426
+ }),
427
+ z2.object({
428
+ success: z2.literal(false),
429
+ error: z2.string()
430
+ })
431
+ ]);
432
+ var requestTool = new ConnectorTool({
433
+ name: "request",
434
+ description: `Send authenticated requests to the TikTok Marketing API v1.3.
435
+ Authentication is handled automatically via OAuth proxy.
436
+ The advertiser_id is automatically injected if configured.`,
437
+ inputSchema: inputSchema2,
438
+ outputSchema: outputSchema2,
439
+ async execute({ connectionId, method, path: path2, queryParams, body }, connections, config) {
440
+ const connection2 = connections.find((c) => c.id === connectionId);
441
+ if (!connection2) {
442
+ return {
443
+ success: false,
444
+ error: `Connection ${connectionId} not found`
445
+ };
446
+ }
447
+ console.log(
448
+ `[connector-request] tiktok-ads/${connection2.name}: ${method} ${path2}`
449
+ );
450
+ try {
451
+ const advertiserId = parameters.advertiserId.tryGetValue(connection2) ?? "";
452
+ let url = `${BASE_URL3}${path2}`;
453
+ if (method === "GET") {
454
+ const params = new URLSearchParams(queryParams ?? {});
455
+ if (advertiserId && !params.has("advertiser_id")) {
456
+ params.set("advertiser_id", advertiserId);
457
+ }
458
+ if (params.toString()) {
459
+ const separator = url.includes("?") ? "&" : "?";
460
+ url = `${url}${separator}${params.toString()}`;
461
+ }
462
+ }
463
+ const requestBody = method === "POST" ? {
464
+ ...advertiserId ? { advertiser_id: advertiserId } : {},
465
+ ...body
466
+ } : void 0;
467
+ const token = await getProxyToken2(config.oauthProxy);
468
+ const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
469
+ const controller = new AbortController();
470
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS2);
471
+ try {
472
+ const response = await fetch(proxyUrl, {
473
+ method: "POST",
474
+ headers: {
475
+ "Content-Type": "application/json",
476
+ Authorization: `Bearer ${token}`
477
+ },
478
+ body: JSON.stringify({
479
+ url,
480
+ method,
481
+ ...requestBody ? { body: JSON.stringify(requestBody) } : {}
482
+ }),
483
+ signal: controller.signal
484
+ });
485
+ const data = await response.json();
486
+ if (!response.ok) {
487
+ const dataObj2 = data;
488
+ const errorMessage = typeof dataObj2?.message === "string" ? dataObj2.message : `HTTP ${response.status} ${response.statusText}`;
489
+ return { success: false, error: errorMessage };
490
+ }
491
+ const dataObj = data;
492
+ if (dataObj.code !== void 0 && dataObj.code !== 0) {
493
+ return {
494
+ success: false,
495
+ error: dataObj.message ?? `API error code: ${dataObj.code}`
496
+ };
497
+ }
498
+ return { success: true, status: response.status, data };
499
+ } finally {
500
+ clearTimeout(timeout);
501
+ }
502
+ } catch (err) {
503
+ const msg = err instanceof Error ? err.message : String(err);
504
+ return { success: false, error: msg };
505
+ }
506
+ }
507
+ });
508
+
509
+ // ../connectors/src/connectors/tiktok-ads/index.ts
510
+ var tools = {
511
+ request: requestTool,
512
+ listAdvertisers: listAdvertisersTool
513
+ };
514
+ var tiktokAdsConnector = new ConnectorPlugin({
515
+ slug: "tiktok-ads",
516
+ authType: AUTH_TYPES.OAUTH,
517
+ name: "TikTok Ads",
518
+ description: "Connect to TikTok Ads for advertising campaign data and reporting using OAuth.",
519
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/01jHuwvmhe4ts0wj23Hxpm/afac9fa50ac5b353927900a122e898ab/tiktok.webp",
520
+ parameters,
521
+ releaseFlag: { dev1: true, dev2: false, prod: false },
522
+ onboarding: tiktokAdsOnboarding,
523
+ proxyPolicy: {
524
+ allowlist: [
525
+ {
526
+ host: "business-api.tiktok.com",
527
+ methods: ["GET", "POST"]
528
+ }
529
+ ]
530
+ },
531
+ systemPrompt: {
532
+ en: `### Tools
533
+
534
+ - \`tiktok-ads_request\`: Send authenticated requests to the TikTok Marketing API v1.3. Authentication is handled automatically via OAuth proxy. The advertiser_id is automatically injected if configured.
535
+ - \`tiktok-ads_listAdvertisers\`: List accessible TikTok Ads advertiser accounts. Use this during setup to discover available accounts.
536
+
537
+ ### TikTok Marketing API Reference
538
+
539
+ #### Get Advertiser Info
540
+ - GET advertiser/info/?advertiser_id={advertiserId}
541
+
542
+ #### List Campaigns
543
+ - GET campaign/get/?advertiser_id={advertiserId}&page=1&page_size=100
544
+
545
+ #### List Ad Groups
546
+ - GET adgroup/get/?advertiser_id={advertiserId}&page=1&page_size=100
547
+
548
+ #### List Ads
549
+ - GET ad/get/?advertiser_id={advertiserId}&page=1&page_size=100
550
+
551
+ #### Get Integrated Report
552
+ - GET report/integrated/get/?advertiser_id={advertiserId}&report_type=BASIC&data_level=AUCTION_CAMPAIGN&dimensions=["campaign_id","stat_time_day"]&metrics=["spend","impressions","clicks","ctr","cpm","cpc","conversions","conversion_rate","cost_per_conversion"]&start_date=2025-01-01&end_date=2025-01-31
553
+
554
+ ### Report Data Levels
555
+ - \`AUCTION_CAMPAIGN\`: Campaign-level metrics
556
+ - \`AUCTION_ADGROUP\`: Ad group-level metrics
557
+ - \`AUCTION_AD\`: Ad-level metrics
558
+ - \`AUCTION_ADVERTISER\`: Advertiser-level metrics
559
+
560
+ ### Common Dimensions
561
+ campaign_id, adgroup_id, ad_id, stat_time_day, stat_time_hour, country_code, age, gender
562
+
563
+ ### Common Metrics
564
+ spend, impressions, clicks, reach, frequency, ctr, cpc, cpm,
565
+ conversions, conversion_rate, cost_per_conversion,
566
+ total_complete_payment, total_add_to_cart,
567
+ video_play_actions, video_watched_2s, video_watched_6s, average_video_play_per_user
568
+
569
+ ### Date Range Limits
570
+ - With stat_time_day or stat_time_hour dimensions: max 30 days
571
+ - Without time dimensions: max 90 days
572
+
573
+ ### Pagination
574
+ - Use \`page\` and \`page_size\` (max 1000) parameters
575
+ - Response includes \`page_info.total_number\` and \`page_info.total_page\`
576
+
577
+ ### Tips
578
+ - TikTok API responses have a top-level \`code\` (0 = success) and \`message\` field
579
+ - Arrays in query parameters must be JSON-encoded (e.g., metrics=["spend","clicks"])
580
+ - advertiser_id is required for almost all endpoints
581
+ - Filtering supports IN, NOT_IN operators with JSON array values
582
+
583
+ ### Business Logic
584
+
585
+ 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.
586
+
587
+ #### Example
588
+
589
+ \`\`\`ts
590
+ import { connection } from "@squadbase/vite-server/connectors/tiktok-ads";
591
+
592
+ const tiktok = connection("<connectionId>");
593
+
594
+ // Get campaigns
595
+ const res = await tiktok.request("campaign/get/?advertiser_id={advertiserId}");
596
+ const data = await res.json();
597
+ \`\`\``,
598
+ ja: `### \u30C4\u30FC\u30EB
599
+
600
+ - \`tiktok-ads_request\`: TikTok Marketing API v1.3\u3078\u8A8D\u8A3C\u6E08\u307F\u30EA\u30AF\u30A8\u30B9\u30C8\u3092\u9001\u4FE1\u3057\u307E\u3059\u3002\u8A8D\u8A3C\u306FOAuth\u30D7\u30ED\u30AD\u30B7\u7D4C\u7531\u3067\u81EA\u52D5\u7684\u306B\u51E6\u7406\u3055\u308C\u307E\u3059\u3002advertiser_id\u304C\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u308B\u5834\u5408\u306F\u81EA\u52D5\u7684\u306B\u6CE8\u5165\u3055\u308C\u307E\u3059\u3002
601
+ - \`tiktok-ads_listAdvertisers\`: \u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306ATikTok Ads\u5E83\u544A\u4E3B\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
602
+
603
+ ### TikTok Marketing API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
604
+
605
+ #### \u5E83\u544A\u4E3B\u60C5\u5831\u306E\u53D6\u5F97
606
+ - GET advertiser/info/?advertiser_id={advertiserId}
607
+
608
+ #### \u30AD\u30E3\u30F3\u30DA\u30FC\u30F3\u4E00\u89A7
609
+ - GET campaign/get/?advertiser_id={advertiserId}&page=1&page_size=100
610
+
611
+ #### \u5E83\u544A\u30B0\u30EB\u30FC\u30D7\u4E00\u89A7
612
+ - GET adgroup/get/?advertiser_id={advertiserId}&page=1&page_size=100
613
+
614
+ #### \u5E83\u544A\u4E00\u89A7
615
+ - GET ad/get/?advertiser_id={advertiserId}&page=1&page_size=100
616
+
617
+ #### \u7D71\u5408\u30EC\u30DD\u30FC\u30C8\u306E\u53D6\u5F97
618
+ - GET report/integrated/get/?advertiser_id={advertiserId}&report_type=BASIC&data_level=AUCTION_CAMPAIGN&dimensions=["campaign_id","stat_time_day"]&metrics=["spend","impressions","clicks","ctr","cpm","cpc","conversions","conversion_rate","cost_per_conversion"]&start_date=2025-01-01&end_date=2025-01-31
619
+
620
+ ### \u30EC\u30DD\u30FC\u30C8\u306E\u30C7\u30FC\u30BF\u30EC\u30D9\u30EB
621
+ - \`AUCTION_CAMPAIGN\`: \u30AD\u30E3\u30F3\u30DA\u30FC\u30F3\u30EC\u30D9\u30EB\u306E\u30E1\u30C8\u30EA\u30AF\u30B9
622
+ - \`AUCTION_ADGROUP\`: \u5E83\u544A\u30B0\u30EB\u30FC\u30D7\u30EC\u30D9\u30EB\u306E\u30E1\u30C8\u30EA\u30AF\u30B9
623
+ - \`AUCTION_AD\`: \u5E83\u544A\u30EC\u30D9\u30EB\u306E\u30E1\u30C8\u30EA\u30AF\u30B9
624
+ - \`AUCTION_ADVERTISER\`: \u5E83\u544A\u4E3B\u30EC\u30D9\u30EB\u306E\u30E1\u30C8\u30EA\u30AF\u30B9
625
+
626
+ ### \u4E3B\u8981\u306A\u30C7\u30A3\u30E1\u30F3\u30B7\u30E7\u30F3
627
+ campaign_id, adgroup_id, ad_id, stat_time_day, stat_time_hour, country_code, age, gender
628
+
629
+ ### \u4E3B\u8981\u306A\u30E1\u30C8\u30EA\u30AF\u30B9
630
+ spend, impressions, clicks, reach, frequency, ctr, cpc, cpm,
631
+ conversions, conversion_rate, cost_per_conversion,
632
+ total_complete_payment, total_add_to_cart,
633
+ video_play_actions, video_watched_2s, video_watched_6s, average_video_play_per_user
634
+
635
+ ### \u65E5\u4ED8\u7BC4\u56F2\u306E\u5236\u9650
636
+ - stat_time_day\u307E\u305F\u306Fstat_time_hour\u30C7\u30A3\u30E1\u30F3\u30B7\u30E7\u30F3\u4F7F\u7528\u6642: \u6700\u592730\u65E5\u9593
637
+ - \u6642\u9593\u30C7\u30A3\u30E1\u30F3\u30B7\u30E7\u30F3\u306A\u3057: \u6700\u592790\u65E5\u9593
638
+
639
+ ### \u30DA\u30FC\u30B8\u30CD\u30FC\u30B7\u30E7\u30F3
640
+ - \`page\` \u3068 \`page_size\`\uFF08\u6700\u59271000\uFF09\u30D1\u30E9\u30E1\u30FC\u30BF\u3092\u4F7F\u7528
641
+ - \u30EC\u30B9\u30DD\u30F3\u30B9\u306B \`page_info.total_number\` \u3068 \`page_info.total_page\` \u304C\u542B\u307E\u308C\u308B
642
+
643
+ ### \u30D2\u30F3\u30C8
644
+ - TikTok API\u306E\u30EC\u30B9\u30DD\u30F3\u30B9\u306B\u306F\u30C8\u30C3\u30D7\u30EC\u30D9\u30EB\u306E \`code\`\uFF080 = \u6210\u529F\uFF09\u3068 \`message\` \u30D5\u30A3\u30FC\u30EB\u30C9\u304C\u3042\u308B
645
+ - \u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF\u306E\u914D\u5217\u306FJSON\u5F62\u5F0F\u3067\u30A8\u30F3\u30B3\u30FC\u30C9\u3059\u308B\u5FC5\u8981\u304C\u3042\u308B\uFF08\u4F8B\uFF1Ametrics=["spend","clicks"]\uFF09
646
+ - \u307B\u307C\u5168\u3066\u306E\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3067 advertiser_id \u304C\u5FC5\u8981
647
+ - \u30D5\u30A3\u30EB\u30BF\u30EA\u30F3\u30B0\u306FIN\u3001NOT_IN\u6F14\u7B97\u5B50\u3092JSON\u914D\u5217\u5024\u3067\u30B5\u30DD\u30FC\u30C8
648
+
649
+ ### Business Logic
650
+
651
+ \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
652
+
653
+ #### Example
654
+
655
+ \`\`\`ts
656
+ import { connection } from "@squadbase/vite-server/connectors/tiktok-ads";
657
+
658
+ const tiktok = connection("<connectionId>");
659
+
660
+ // \u30AD\u30E3\u30F3\u30DA\u30FC\u30F3\u3092\u53D6\u5F97
661
+ const res = await tiktok.request("campaign/get/?advertiser_id={advertiserId}");
662
+ const data = await res.json();
663
+ \`\`\``
664
+ },
665
+ tools,
666
+ async checkConnection(_params, config) {
667
+ const { proxyFetch } = config;
668
+ try {
669
+ const url = `https://business-api.tiktok.com/open_api/v1.3/user/info/`;
670
+ const res = await proxyFetch(url, { method: "GET" });
671
+ if (!res.ok) {
672
+ return {
673
+ success: false,
674
+ error: `TikTok API failed: HTTP ${res.status}`
675
+ };
676
+ }
677
+ const data = await res.json();
678
+ if (data.code !== void 0 && data.code !== 0) {
679
+ return {
680
+ success: false,
681
+ error: data.message ?? `API error code: ${data.code}`
682
+ };
683
+ }
684
+ return { success: true };
685
+ } catch (error) {
686
+ return {
687
+ success: false,
688
+ error: error instanceof Error ? error.message : String(error)
689
+ };
690
+ }
691
+ }
692
+ });
693
+
694
+ // src/connectors/create-connector-sdk.ts
695
+ import { readFileSync } from "fs";
696
+ import path from "path";
697
+
698
+ // src/connector-client/env.ts
699
+ function resolveEnvVar(entry, key, connectionId) {
700
+ const envVarName = entry.envVars[key];
701
+ if (!envVarName) {
702
+ throw new Error(`Connection "${connectionId}" is missing envVars mapping for key "${key}"`);
703
+ }
704
+ const value = process.env[envVarName];
705
+ if (!value) {
706
+ throw new Error(`Environment variable "${envVarName}" (for connection "${connectionId}", key "${key}") is not set`);
707
+ }
708
+ return value;
709
+ }
710
+ function resolveEnvVarOptional(entry, key) {
711
+ const envVarName = entry.envVars[key];
712
+ if (!envVarName) return void 0;
713
+ return process.env[envVarName] || void 0;
714
+ }
715
+
716
+ // src/connector-client/proxy-fetch.ts
717
+ import { getContext } from "hono/context-storage";
718
+ import { getCookie } from "hono/cookie";
719
+ var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
720
+ function normalizeHeaders(input) {
721
+ const out = {};
722
+ if (!input) return out;
723
+ new Headers(input).forEach((value, key) => {
724
+ out[key] = value;
725
+ });
726
+ return out;
727
+ }
728
+ function createSandboxProxyFetch(connectionId) {
729
+ return async (input, init) => {
730
+ const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
731
+ const sandboxId = process.env.INTERNAL_SQUADBASE_SANDBOX_ID;
732
+ if (!token || !sandboxId) {
733
+ throw new Error(
734
+ "Connection proxy is not configured. Please check your deployment settings."
735
+ );
736
+ }
737
+ const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
738
+ const originalMethod = init?.method ?? "GET";
739
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
740
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
741
+ const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
742
+ return fetch(proxyUrl, {
743
+ method: "POST",
744
+ headers: {
745
+ "Content-Type": "application/json",
746
+ Authorization: `Bearer ${token}`
747
+ },
748
+ body: JSON.stringify({
749
+ url: originalUrl,
750
+ method: originalMethod,
751
+ headers: normalizeHeaders(init?.headers),
752
+ body: originalBody
753
+ })
754
+ });
755
+ };
756
+ }
757
+ function createDeployedAppProxyFetch(connectionId) {
758
+ const projectId = process.env["SQUADBASE_PROJECT_ID"];
759
+ if (!projectId) {
760
+ throw new Error(
761
+ "Connection proxy is not configured. Please check your deployment settings."
762
+ );
763
+ }
764
+ const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
765
+ const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
766
+ return async (input, init) => {
767
+ const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
768
+ const originalMethod = init?.method ?? "GET";
769
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
770
+ const c = getContext();
771
+ const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
772
+ if (!appSession) {
773
+ throw new Error(
774
+ "No authentication method available for connection proxy."
775
+ );
776
+ }
777
+ return fetch(proxyUrl, {
778
+ method: "POST",
779
+ headers: {
780
+ "Content-Type": "application/json",
781
+ Authorization: `Bearer ${appSession}`
782
+ },
783
+ body: JSON.stringify({
784
+ url: originalUrl,
785
+ method: originalMethod,
786
+ headers: normalizeHeaders(init?.headers),
787
+ body: originalBody
788
+ })
789
+ });
790
+ };
791
+ }
792
+ function createProxyFetch(connectionId) {
793
+ if (process.env.INTERNAL_SQUADBASE_SANDBOX_ID) {
794
+ return createSandboxProxyFetch(connectionId);
795
+ }
796
+ return createDeployedAppProxyFetch(connectionId);
797
+ }
798
+
799
+ // src/connectors/create-connector-sdk.ts
800
+ function loadConnectionsSync() {
801
+ const filePath = process.env.CONNECTIONS_PATH ?? path.join(process.cwd(), ".squadbase/connections.json");
802
+ try {
803
+ const raw = readFileSync(filePath, "utf-8");
804
+ return JSON.parse(raw);
805
+ } catch {
806
+ return {};
807
+ }
808
+ }
809
+ function createConnectorSdk(plugin, createClient2) {
810
+ return (connectionId) => {
811
+ const connections = loadConnectionsSync();
812
+ const entry = connections[connectionId];
813
+ if (!entry) {
814
+ throw new Error(
815
+ `Connection "${connectionId}" not found in .squadbase/connections.json`
816
+ );
817
+ }
818
+ if (entry.connector.slug !== plugin.slug) {
819
+ throw new Error(
820
+ `Connection "${connectionId}" is not a ${plugin.slug} connection (got "${entry.connector.slug}")`
821
+ );
822
+ }
823
+ const params = {};
824
+ for (const param of Object.values(plugin.parameters)) {
825
+ if (param.required) {
826
+ params[param.slug] = resolveEnvVar(entry, param.slug, connectionId);
827
+ } else {
828
+ const val = resolveEnvVarOptional(entry, param.slug);
829
+ if (val !== void 0) params[param.slug] = val;
830
+ }
831
+ }
832
+ return createClient2(params, createProxyFetch(connectionId));
833
+ };
834
+ }
835
+
836
+ // src/connectors/entries/tiktok-ads.ts
837
+ var connection = createConnectorSdk(tiktokAdsConnector, createClient);
838
+ export {
839
+ connection
840
+ };