@squadbase/vite-server 0.1.17-dev.24af54e → 0.1.17-dev.423ee34
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 +4873 -1073
- package/dist/connectors/airtable-oauth.js +78 -11
- package/dist/connectors/airtable.js +74 -11
- package/dist/connectors/amplitude.js +38 -11
- package/dist/connectors/anthropic.js +4 -2
- package/dist/connectors/asana.js +67 -13
- package/dist/connectors/attio.js +60 -16
- package/dist/connectors/aws-billing.js +38 -11
- package/dist/connectors/azure-sql.js +64 -13
- package/dist/connectors/backlog-api-key.js +70 -18
- package/dist/connectors/clickup.js +80 -13
- package/dist/connectors/cosmosdb.js +42 -15
- package/dist/connectors/customerio.js +39 -12
- package/dist/connectors/dbt.js +716 -28
- package/dist/connectors/freshdesk.js +112 -11
- package/dist/connectors/freshsales.js +38 -11
- package/dist/connectors/freshservice.js +38 -11
- package/dist/connectors/gamma.js +47 -20
- package/dist/connectors/gemini.js +4 -2
- package/dist/connectors/github.js +42 -15
- package/dist/connectors/gmail-oauth.js +38 -13
- package/dist/connectors/gmail.js +34 -7
- package/dist/connectors/google-ads.js +38 -11
- package/dist/connectors/google-analytics-oauth.js +182 -28
- package/dist/connectors/google-analytics.js +653 -104
- package/dist/connectors/google-audit-log.js +34 -7
- package/dist/connectors/google-calendar-oauth.js +91 -18
- package/dist/connectors/google-calendar.js +91 -14
- package/dist/connectors/google-docs.js +38 -13
- package/dist/connectors/google-drive.js +60 -13
- package/dist/connectors/google-search-console-oauth.js +156 -20
- package/dist/connectors/google-sheets.js +36 -9
- package/dist/connectors/google-slides.js +38 -13
- package/dist/connectors/grafana.js +75 -13
- package/dist/connectors/hubspot-oauth.js +69 -12
- package/dist/connectors/hubspot.js +55 -12
- package/dist/connectors/influxdb.js +38 -11
- package/dist/connectors/intercom-oauth.js +100 -15
- package/dist/connectors/intercom.js +42 -15
- package/dist/connectors/jdbc.js +36 -9
- package/dist/connectors/jira-api-key.js +98 -14
- package/dist/connectors/kintone-api-token.js +96 -21
- package/dist/connectors/kintone.js +84 -14
- package/dist/connectors/linear.js +84 -15
- package/dist/connectors/linkedin-ads.js +71 -17
- package/dist/connectors/mailchimp-oauth.js +36 -9
- package/dist/connectors/mailchimp.js +36 -9
- package/dist/connectors/meta-ads-oauth.js +63 -17
- package/dist/connectors/meta-ads.js +65 -17
- package/dist/connectors/mixpanel.js +38 -11
- package/dist/connectors/monday.js +39 -12
- package/dist/connectors/mongodb.js +38 -11
- package/dist/connectors/notion-oauth.js +88 -14
- package/dist/connectors/notion.js +90 -14
- package/dist/connectors/openai.js +4 -2
- package/dist/connectors/oracle.js +78 -20
- package/dist/connectors/outlook-oauth.js +48 -23
- package/dist/connectors/powerbi-oauth.js +321 -49
- package/dist/connectors/salesforce.js +72 -12
- package/dist/connectors/semrush.js +374 -52
- package/dist/connectors/sentry.js +66 -13
- package/dist/connectors/shopify-oauth.js +71 -13
- package/dist/connectors/shopify.js +38 -11
- package/dist/connectors/sqlserver.js +64 -13
- package/dist/connectors/stripe-api-key.js +96 -18
- package/dist/connectors/stripe-oauth.js +98 -22
- package/dist/connectors/supabase.js +55 -11
- package/dist/connectors/tableau.js +262 -92
- package/dist/connectors/tiktok-ads.js +67 -19
- package/dist/connectors/wix-store.js +38 -11
- package/dist/connectors/zendesk-oauth.js +83 -15
- package/dist/connectors/zendesk.js +42 -15
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4902 -1077
- package/dist/main.js +4891 -1071
- package/dist/vite-plugin.js +4871 -1071
- package/package.json +1 -1
|
@@ -16,6 +16,7 @@ var init_parameter_definition = __esm({
|
|
|
16
16
|
type;
|
|
17
17
|
secret;
|
|
18
18
|
required;
|
|
19
|
+
isDeprecated;
|
|
19
20
|
constructor(config) {
|
|
20
21
|
this.slug = config.slug;
|
|
21
22
|
this.name = config.name;
|
|
@@ -24,6 +25,7 @@ var init_parameter_definition = __esm({
|
|
|
24
25
|
this.type = config.type;
|
|
25
26
|
this.secret = config.secret;
|
|
26
27
|
this.required = config.required;
|
|
28
|
+
this.isDeprecated = config.isDeprecated ?? false;
|
|
27
29
|
}
|
|
28
30
|
/**
|
|
29
31
|
* Get the parameter value from a ConnectorConnectionObject.
|
|
@@ -169,7 +171,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
169
171
|
/**
|
|
170
172
|
* Create tools for connections that belong to this connector.
|
|
171
173
|
* Filters connections by connectorKey internally.
|
|
172
|
-
* Returns tools keyed as
|
|
174
|
+
* Returns tools keyed as `connector_${connectorKey}_${toolName}`.
|
|
173
175
|
*/
|
|
174
176
|
createTools(connections, config, opts) {
|
|
175
177
|
const myConnections = connections.filter(
|
|
@@ -179,7 +181,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
179
181
|
for (const t of Object.values(this.tools)) {
|
|
180
182
|
const tool = t.createTool(myConnections, config);
|
|
181
183
|
const originalToModelOutput = tool.toModelOutput;
|
|
182
|
-
result[
|
|
184
|
+
result[`connector_${this.connectorKey}_${t.name}`] = {
|
|
183
185
|
...tool,
|
|
184
186
|
toModelOutput: async (options) => {
|
|
185
187
|
if (!originalToModelOutput) {
|
|
@@ -235,19 +237,34 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
235
237
|
};
|
|
236
238
|
let state = flow.initialState();
|
|
237
239
|
let answerIdx = 0;
|
|
240
|
+
const pendingParameterUpdates = [];
|
|
238
241
|
for (const step of flow.steps) {
|
|
239
242
|
const ans = ctx.answers[answerIdx];
|
|
240
243
|
if (ans && ans.questionSlug === step.slug) {
|
|
241
244
|
state = step.applyAnswer(state, ans.answer);
|
|
245
|
+
if (step.toParameterUpdates) {
|
|
246
|
+
pendingParameterUpdates.push(...step.toParameterUpdates(state));
|
|
247
|
+
}
|
|
242
248
|
answerIdx += 1;
|
|
243
249
|
continue;
|
|
244
250
|
}
|
|
251
|
+
const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
|
|
245
252
|
if (step.type === "text") {
|
|
253
|
+
if (step.fetchOptions) {
|
|
254
|
+
const options2 = await step.fetchOptions(state, runtime);
|
|
255
|
+
if (options2.length === 0) {
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
246
259
|
return {
|
|
247
260
|
type: "nextQuestion",
|
|
248
261
|
questionSlug: step.slug,
|
|
249
262
|
question: step.question[ctx.language],
|
|
250
|
-
questionType: "text"
|
|
263
|
+
questionType: "text",
|
|
264
|
+
allowFreeText: resolvedAllowFreeText,
|
|
265
|
+
...pendingParameterUpdates.length > 0 && {
|
|
266
|
+
parameterUpdates: pendingParameterUpdates
|
|
267
|
+
}
|
|
251
268
|
};
|
|
252
269
|
}
|
|
253
270
|
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
@@ -259,11 +276,21 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
259
276
|
questionSlug: step.slug,
|
|
260
277
|
question: step.question[ctx.language],
|
|
261
278
|
questionType: step.type,
|
|
262
|
-
options
|
|
279
|
+
options,
|
|
280
|
+
allowFreeText: resolvedAllowFreeText,
|
|
281
|
+
...pendingParameterUpdates.length > 0 && {
|
|
282
|
+
parameterUpdates: pendingParameterUpdates
|
|
283
|
+
}
|
|
263
284
|
};
|
|
264
285
|
}
|
|
265
286
|
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
266
|
-
return {
|
|
287
|
+
return {
|
|
288
|
+
type: "fulfilled",
|
|
289
|
+
dataInvestigationResult,
|
|
290
|
+
...pendingParameterUpdates.length > 0 && {
|
|
291
|
+
parameterUpdates: pendingParameterUpdates
|
|
292
|
+
}
|
|
293
|
+
};
|
|
267
294
|
}
|
|
268
295
|
async function resolveSetupSelection(params) {
|
|
269
296
|
const { selected, allSentinel, fetchAll, limit } = params;
|
|
@@ -441,12 +468,12 @@ var tiktokAdsOnboarding = new ConnectorOnboarding({
|
|
|
441
468
|
- Write only 1 sentence between tool calls, then immediately call the next tool. Skip unnecessary explanations and proceed efficiently`
|
|
442
469
|
},
|
|
443
470
|
dataOverviewInstructions: {
|
|
444
|
-
en: `1. Call
|
|
445
|
-
2. Call
|
|
446
|
-
3. Call
|
|
447
|
-
ja: `1.
|
|
448
|
-
2.
|
|
449
|
-
3.
|
|
471
|
+
en: `1. Call connector_tiktok-ads_request with GET campaign/get/ to explore campaign data
|
|
472
|
+
2. Call connector_tiktok-ads_request with GET adgroup/get/ to explore ad group data
|
|
473
|
+
3. Call connector_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`,
|
|
474
|
+
ja: `1. connector_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
|
|
475
|
+
2. connector_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
|
|
476
|
+
3. connector_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`
|
|
450
477
|
}
|
|
451
478
|
});
|
|
452
479
|
|
|
@@ -486,6 +513,19 @@ async function listAdvertisers(proxyFetch) {
|
|
|
486
513
|
}
|
|
487
514
|
return data.data?.list ?? [];
|
|
488
515
|
}
|
|
516
|
+
async function fetchCampaignCount(proxyFetch, advertiserId) {
|
|
517
|
+
try {
|
|
518
|
+
const url = `${BASE_URL3}/campaign/get/?advertiser_id=${encodeURIComponent(advertiserId)}&page_size=1`;
|
|
519
|
+
const res = await proxyFetch(url, { method: "GET" });
|
|
520
|
+
if (!res.ok) return null;
|
|
521
|
+
const data = await res.json();
|
|
522
|
+
if (data.code !== void 0 && data.code !== 0) return null;
|
|
523
|
+
const total = data.data?.page_info?.total_number;
|
|
524
|
+
return typeof total === "number" ? total : null;
|
|
525
|
+
} catch {
|
|
526
|
+
return null;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
489
529
|
async function fetchAdvertiserInfo(proxyFetch, advertiserId) {
|
|
490
530
|
const advertiserIdsParam = encodeURIComponent(
|
|
491
531
|
JSON.stringify([advertiserId])
|
|
@@ -550,16 +590,24 @@ var tiktokAdsSetupFlow = {
|
|
|
550
590
|
sections.push("_No advertisers selected._", "");
|
|
551
591
|
return sections.join("\n");
|
|
552
592
|
}
|
|
553
|
-
sections.push(
|
|
554
|
-
|
|
593
|
+
sections.push(
|
|
594
|
+
"| Advertiser ID | Name | Currency | Status | Time Zone | Campaigns |"
|
|
595
|
+
);
|
|
596
|
+
sections.push(
|
|
597
|
+
"|---------------|------|----------|--------|-----------|-----------|"
|
|
598
|
+
);
|
|
555
599
|
for (const id of targetIds) {
|
|
556
|
-
const info = await
|
|
600
|
+
const [info, campaignCount] = await Promise.all([
|
|
601
|
+
fetchAdvertiserInfo(rt.config.proxyFetch, id),
|
|
602
|
+
fetchCampaignCount(rt.config.proxyFetch, id)
|
|
603
|
+
]);
|
|
557
604
|
const name = (info.name ?? "-").replace(/\|/g, "\\|");
|
|
558
605
|
const currency = info.currency ?? "-";
|
|
559
606
|
const status = info.status ?? "-";
|
|
560
607
|
const timeZone = info.display_timezone ?? "-";
|
|
608
|
+
const campaigns = campaignCount == null ? "-" : String(campaignCount);
|
|
561
609
|
sections.push(
|
|
562
|
-
`| ${id} | ${name} | ${currency} | ${status} | ${timeZone} |`
|
|
610
|
+
`| ${id} | ${name} | ${currency} | ${status} | ${timeZone} | ${campaigns} |`
|
|
563
611
|
);
|
|
564
612
|
}
|
|
565
613
|
sections.push("");
|
|
@@ -732,8 +780,8 @@ var tiktokAdsConnector = new ConnectorPlugin({
|
|
|
732
780
|
systemPrompt: {
|
|
733
781
|
en: `### Tools
|
|
734
782
|
|
|
735
|
-
- \`
|
|
736
|
-
- \`
|
|
783
|
+
- \`connector_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.
|
|
784
|
+
- \`connector_tiktok-ads_listAdvertisers\`: List accessible TikTok Ads advertiser accounts. Use this during setup to discover available accounts.
|
|
737
785
|
|
|
738
786
|
### TikTok Marketing API Reference
|
|
739
787
|
|
|
@@ -798,8 +846,8 @@ const data = await res.json();
|
|
|
798
846
|
\`\`\``,
|
|
799
847
|
ja: `### \u30C4\u30FC\u30EB
|
|
800
848
|
|
|
801
|
-
- \`
|
|
802
|
-
- \`
|
|
849
|
+
- \`connector_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
|
|
850
|
+
- \`connector_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
|
|
803
851
|
|
|
804
852
|
### TikTok Marketing API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
|
|
805
853
|
|
|
@@ -16,6 +16,7 @@ var init_parameter_definition = __esm({
|
|
|
16
16
|
type;
|
|
17
17
|
secret;
|
|
18
18
|
required;
|
|
19
|
+
isDeprecated;
|
|
19
20
|
constructor(config) {
|
|
20
21
|
this.slug = config.slug;
|
|
21
22
|
this.name = config.name;
|
|
@@ -24,6 +25,7 @@ var init_parameter_definition = __esm({
|
|
|
24
25
|
this.type = config.type;
|
|
25
26
|
this.secret = config.secret;
|
|
26
27
|
this.required = config.required;
|
|
28
|
+
this.isDeprecated = config.isDeprecated ?? false;
|
|
27
29
|
}
|
|
28
30
|
/**
|
|
29
31
|
* Get the parameter value from a ConnectorConnectionObject.
|
|
@@ -317,7 +319,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
317
319
|
/**
|
|
318
320
|
* Create tools for connections that belong to this connector.
|
|
319
321
|
* Filters connections by connectorKey internally.
|
|
320
|
-
* Returns tools keyed as
|
|
322
|
+
* Returns tools keyed as `connector_${connectorKey}_${toolName}`.
|
|
321
323
|
*/
|
|
322
324
|
createTools(connections, config, opts) {
|
|
323
325
|
const myConnections = connections.filter(
|
|
@@ -327,7 +329,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
327
329
|
for (const t of Object.values(this.tools)) {
|
|
328
330
|
const tool = t.createTool(myConnections, config);
|
|
329
331
|
const originalToModelOutput = tool.toModelOutput;
|
|
330
|
-
result[
|
|
332
|
+
result[`connector_${this.connectorKey}_${t.name}`] = {
|
|
331
333
|
...tool,
|
|
332
334
|
toModelOutput: async (options) => {
|
|
333
335
|
if (!originalToModelOutput) {
|
|
@@ -383,19 +385,34 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
383
385
|
};
|
|
384
386
|
let state = flow.initialState();
|
|
385
387
|
let answerIdx = 0;
|
|
388
|
+
const pendingParameterUpdates = [];
|
|
386
389
|
for (const step of flow.steps) {
|
|
387
390
|
const ans = ctx.answers[answerIdx];
|
|
388
391
|
if (ans && ans.questionSlug === step.slug) {
|
|
389
392
|
state = step.applyAnswer(state, ans.answer);
|
|
393
|
+
if (step.toParameterUpdates) {
|
|
394
|
+
pendingParameterUpdates.push(...step.toParameterUpdates(state));
|
|
395
|
+
}
|
|
390
396
|
answerIdx += 1;
|
|
391
397
|
continue;
|
|
392
398
|
}
|
|
399
|
+
const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
|
|
393
400
|
if (step.type === "text") {
|
|
401
|
+
if (step.fetchOptions) {
|
|
402
|
+
const options2 = await step.fetchOptions(state, runtime);
|
|
403
|
+
if (options2.length === 0) {
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
394
407
|
return {
|
|
395
408
|
type: "nextQuestion",
|
|
396
409
|
questionSlug: step.slug,
|
|
397
410
|
question: step.question[ctx.language],
|
|
398
|
-
questionType: "text"
|
|
411
|
+
questionType: "text",
|
|
412
|
+
allowFreeText: resolvedAllowFreeText,
|
|
413
|
+
...pendingParameterUpdates.length > 0 && {
|
|
414
|
+
parameterUpdates: pendingParameterUpdates
|
|
415
|
+
}
|
|
399
416
|
};
|
|
400
417
|
}
|
|
401
418
|
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
@@ -407,11 +424,21 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
407
424
|
questionSlug: step.slug,
|
|
408
425
|
question: step.question[ctx.language],
|
|
409
426
|
questionType: step.type,
|
|
410
|
-
options
|
|
427
|
+
options,
|
|
428
|
+
allowFreeText: resolvedAllowFreeText,
|
|
429
|
+
...pendingParameterUpdates.length > 0 && {
|
|
430
|
+
parameterUpdates: pendingParameterUpdates
|
|
431
|
+
}
|
|
411
432
|
};
|
|
412
433
|
}
|
|
413
434
|
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
414
|
-
return {
|
|
435
|
+
return {
|
|
436
|
+
type: "fulfilled",
|
|
437
|
+
dataInvestigationResult,
|
|
438
|
+
...pendingParameterUpdates.length > 0 && {
|
|
439
|
+
parameterUpdates: pendingParameterUpdates
|
|
440
|
+
}
|
|
441
|
+
};
|
|
415
442
|
}
|
|
416
443
|
|
|
417
444
|
// ../connectors/src/auth-types.ts
|
|
@@ -427,11 +454,11 @@ var AUTH_TYPES = {
|
|
|
427
454
|
// ../connectors/src/connectors/wix-store/setup.ts
|
|
428
455
|
var wixStoreOnboarding = new ConnectorOnboarding({
|
|
429
456
|
dataOverviewInstructions: {
|
|
430
|
-
en: `1. Call
|
|
431
|
-
2. Call
|
|
457
|
+
en: `1. Call connector_wix-store_request with POST stores/v1/products/query with { "query": { "paging": { "limit": 5 } } } to explore products
|
|
458
|
+
2. Call connector_wix-store_request with POST ecom/v1/orders/search with { "search": { "cursorPaging": { "limit": 5 } } } to explore orders
|
|
432
459
|
3. Explore other endpoints (collections, inventory) as needed`,
|
|
433
|
-
ja: `1.
|
|
434
|
-
2.
|
|
460
|
+
ja: `1. connector_wix-store_request \u3067 POST stores/v1/products/query \u3092 { "query": { "paging": { "limit": 5 } } } \u3067\u547C\u3073\u51FA\u3057\u3001\u5546\u54C1\u30C7\u30FC\u30BF\u3092\u78BA\u8A8D
|
|
461
|
+
2. connector_wix-store_request \u3067 POST ecom/v1/orders/search \u3092 { "search": { "cursorPaging": { "limit": 5 } } } \u3067\u547C\u3073\u51FA\u3057\u3001\u6CE8\u6587\u30C7\u30FC\u30BF\u3092\u78BA\u8A8D
|
|
435
462
|
3. \u5FC5\u8981\u306B\u5FDC\u3058\u3066\u4ED6\u306E\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\uFF08\u30B3\u30EC\u30AF\u30B7\u30E7\u30F3\u3001\u5728\u5EAB\uFF09\u3092\u63A2\u7D22`
|
|
436
463
|
}
|
|
437
464
|
});
|
|
@@ -632,7 +659,7 @@ var wixStoreConnector = new ConnectorPlugin({
|
|
|
632
659
|
systemPrompt: {
|
|
633
660
|
en: `### Tools
|
|
634
661
|
|
|
635
|
-
- \`
|
|
662
|
+
- \`connector_wix-store_request\`: The only way to call the Wix Store REST API. Use it to query products, orders, collections, and inventory. Authentication (API Key, Site ID) is configured automatically. Note that Wix uses POST even for query endpoints, and filters are written in WQL (Wix Query Language). See the Wix Store API Reference below for endpoints and request bodies.
|
|
636
663
|
|
|
637
664
|
### Business Logic
|
|
638
665
|
|
|
@@ -706,7 +733,7 @@ export default async function handler(c: Context) {
|
|
|
706
733
|
- Body: \`{ "query": { "paging": { "limit": 50 } } }\``,
|
|
707
734
|
ja: `### \u30C4\u30FC\u30EB
|
|
708
735
|
|
|
709
|
-
- \`
|
|
736
|
+
- \`connector_wix-store_request\`: Wix Store REST API\u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\u3002\u5546\u54C1\u3001\u6CE8\u6587\u3001\u30B3\u30EC\u30AF\u30B7\u30E7\u30F3\u3001\u5728\u5EAB\u306E\u30AF\u30A8\u30EA\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\u8A8D\u8A3C\uFF08API Key\u3001Site ID\uFF09\u306F\u81EA\u52D5\u7684\u306B\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002Wix\u306F\u30AF\u30A8\u30EA\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3067\u3082 POST \u3092\u4F7F\u7528\u3057\u3001\u30D5\u30A3\u30EB\u30BF\u306F WQL (Wix Query Language) \u3067\u8A18\u8FF0\u3059\u308B\u3053\u3068\u306B\u6CE8\u610F\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u5229\u7528\u53EF\u80FD\u306A\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3068\u30EA\u30AF\u30A8\u30B9\u30C8\u30DC\u30C7\u30A3\u306F\u4E0B\u90E8\u306E\u300CWix Store API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9\u300D\u3092\u53C2\u7167\u3057\u3066\u304F\u3060\u3055\u3044\u3002
|
|
710
737
|
|
|
711
738
|
### Business Logic
|
|
712
739
|
|
|
@@ -112,7 +112,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
112
112
|
/**
|
|
113
113
|
* Create tools for connections that belong to this connector.
|
|
114
114
|
* Filters connections by connectorKey internally.
|
|
115
|
-
* Returns tools keyed as
|
|
115
|
+
* Returns tools keyed as `connector_${connectorKey}_${toolName}`.
|
|
116
116
|
*/
|
|
117
117
|
createTools(connections, config, opts) {
|
|
118
118
|
const myConnections = connections.filter(
|
|
@@ -122,7 +122,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
122
122
|
for (const t of Object.values(this.tools)) {
|
|
123
123
|
const tool = t.createTool(myConnections, config);
|
|
124
124
|
const originalToModelOutput = tool.toModelOutput;
|
|
125
|
-
result[
|
|
125
|
+
result[`connector_${this.connectorKey}_${t.name}`] = {
|
|
126
126
|
...tool,
|
|
127
127
|
toModelOutput: async (options) => {
|
|
128
128
|
if (!originalToModelOutput) {
|
|
@@ -178,19 +178,34 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
178
178
|
};
|
|
179
179
|
let state = flow.initialState();
|
|
180
180
|
let answerIdx = 0;
|
|
181
|
+
const pendingParameterUpdates = [];
|
|
181
182
|
for (const step of flow.steps) {
|
|
182
183
|
const ans = ctx.answers[answerIdx];
|
|
183
184
|
if (ans && ans.questionSlug === step.slug) {
|
|
184
185
|
state = step.applyAnswer(state, ans.answer);
|
|
186
|
+
if (step.toParameterUpdates) {
|
|
187
|
+
pendingParameterUpdates.push(...step.toParameterUpdates(state));
|
|
188
|
+
}
|
|
185
189
|
answerIdx += 1;
|
|
186
190
|
continue;
|
|
187
191
|
}
|
|
192
|
+
const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
|
|
188
193
|
if (step.type === "text") {
|
|
194
|
+
if (step.fetchOptions) {
|
|
195
|
+
const options2 = await step.fetchOptions(state, runtime);
|
|
196
|
+
if (options2.length === 0) {
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
189
200
|
return {
|
|
190
201
|
type: "nextQuestion",
|
|
191
202
|
questionSlug: step.slug,
|
|
192
203
|
question: step.question[ctx.language],
|
|
193
|
-
questionType: "text"
|
|
204
|
+
questionType: "text",
|
|
205
|
+
allowFreeText: resolvedAllowFreeText,
|
|
206
|
+
...pendingParameterUpdates.length > 0 && {
|
|
207
|
+
parameterUpdates: pendingParameterUpdates
|
|
208
|
+
}
|
|
194
209
|
};
|
|
195
210
|
}
|
|
196
211
|
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
@@ -202,11 +217,21 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
202
217
|
questionSlug: step.slug,
|
|
203
218
|
question: step.question[ctx.language],
|
|
204
219
|
questionType: step.type,
|
|
205
|
-
options
|
|
220
|
+
options,
|
|
221
|
+
allowFreeText: resolvedAllowFreeText,
|
|
222
|
+
...pendingParameterUpdates.length > 0 && {
|
|
223
|
+
parameterUpdates: pendingParameterUpdates
|
|
224
|
+
}
|
|
206
225
|
};
|
|
207
226
|
}
|
|
208
227
|
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
209
|
-
return {
|
|
228
|
+
return {
|
|
229
|
+
type: "fulfilled",
|
|
230
|
+
dataInvestigationResult,
|
|
231
|
+
...pendingParameterUpdates.length > 0 && {
|
|
232
|
+
parameterUpdates: pendingParameterUpdates
|
|
233
|
+
}
|
|
234
|
+
};
|
|
210
235
|
}
|
|
211
236
|
async function resolveSetupSelection(params) {
|
|
212
237
|
const { selected, allSentinel, fetchAll, limit } = params;
|
|
@@ -367,14 +392,14 @@ var zendeskOauthOnboarding = new ConnectorOnboarding({
|
|
|
367
392
|
- \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`
|
|
368
393
|
},
|
|
369
394
|
dataOverviewInstructions: {
|
|
370
|
-
en: `1. Call
|
|
371
|
-
2. Call
|
|
372
|
-
3. Call
|
|
373
|
-
4. Call
|
|
374
|
-
ja: `1.
|
|
375
|
-
2.
|
|
376
|
-
3.
|
|
377
|
-
4.
|
|
395
|
+
en: `1. Call connector_zendesk-oauth_request with GET /api/v2/ticket_fields.json to list available ticket fields
|
|
396
|
+
2. Call connector_zendesk-oauth_request with GET /api/v2/tickets.json?page[size]=5 to explore ticket structure
|
|
397
|
+
3. Call connector_zendesk-oauth_request with GET /api/v2/users.json?page[size]=5 to explore user structure
|
|
398
|
+
4. Call connector_zendesk-oauth_request with GET /api/v2/organizations.json?page[size]=5 to explore organization structure`,
|
|
399
|
+
ja: `1. connector_zendesk-oauth_request \u3067 GET /api/v2/ticket_fields.json \u3092\u547C\u3073\u51FA\u3057\u3001\u5229\u7528\u53EF\u80FD\u306A\u30C1\u30B1\u30C3\u30C8\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u78BA\u8A8D
|
|
400
|
+
2. connector_zendesk-oauth_request \u3067 GET /api/v2/tickets.json?page[size]=5 \u3092\u547C\u3073\u51FA\u3057\u3001\u30C1\u30B1\u30C3\u30C8\u306E\u69CB\u9020\u3092\u78BA\u8A8D
|
|
401
|
+
3. connector_zendesk-oauth_request \u3067 GET /api/v2/users.json?page[size]=5 \u3092\u547C\u3073\u51FA\u3057\u3001\u30E6\u30FC\u30B6\u30FC\u306E\u69CB\u9020\u3092\u78BA\u8A8D
|
|
402
|
+
4. connector_zendesk-oauth_request \u3067 GET /api/v2/organizations.json?page[size]=5 \u3092\u547C\u3073\u51FA\u3057\u3001\u7D44\u7E54\u306E\u69CB\u9020\u3092\u78BA\u8A8D`
|
|
378
403
|
}
|
|
379
404
|
});
|
|
380
405
|
|
|
@@ -492,6 +517,49 @@ var zendeskOauthSetupFlow = {
|
|
|
492
517
|
);
|
|
493
518
|
}
|
|
494
519
|
sections.push("");
|
|
520
|
+
if (targetEntities.includes("tickets")) {
|
|
521
|
+
try {
|
|
522
|
+
const statusRes = await apiFetch(
|
|
523
|
+
rt.config.proxyFetch,
|
|
524
|
+
"/api/v2/tickets.json?page[size]=100&sort=-created_at"
|
|
525
|
+
);
|
|
526
|
+
if (statusRes.ok) {
|
|
527
|
+
const statusData = await statusRes.json();
|
|
528
|
+
const tickets = statusData.tickets ?? [];
|
|
529
|
+
if (tickets.length > 0) {
|
|
530
|
+
const statusCounts = {};
|
|
531
|
+
for (const t of tickets) {
|
|
532
|
+
const s = t.status ?? "unknown";
|
|
533
|
+
statusCounts[s] = (statusCounts[s] ?? 0) + 1;
|
|
534
|
+
}
|
|
535
|
+
sections.push("### Ticket status breakdown (from recent tickets)", "");
|
|
536
|
+
sections.push("| Status | Count |");
|
|
537
|
+
sections.push("|--------|-------|");
|
|
538
|
+
for (const [status, cnt] of Object.entries(statusCounts).sort(
|
|
539
|
+
(a, b) => b[1] - a[1]
|
|
540
|
+
)) {
|
|
541
|
+
sections.push(`| ${status} | ${cnt} |`);
|
|
542
|
+
}
|
|
543
|
+
sections.push("");
|
|
544
|
+
sections.push("### Recent tickets (sample)", "");
|
|
545
|
+
sections.push("| ID | Subject | Status | Priority | Created |");
|
|
546
|
+
sections.push("|----|---------|--------|----------|---------|");
|
|
547
|
+
for (const t of tickets.slice(0, 5)) {
|
|
548
|
+
const id = t.id != null ? String(t.id) : "-";
|
|
549
|
+
const subject = (t.subject ?? "-").replace(/\|/g, "\\|").slice(0, 60);
|
|
550
|
+
const status = t.status ?? "-";
|
|
551
|
+
const priority = t.priority ?? "-";
|
|
552
|
+
const created = t.created_at ? t.created_at.slice(0, 10) : "-";
|
|
553
|
+
sections.push(
|
|
554
|
+
`| ${id} | ${subject} | ${status} | ${priority} | ${created} |`
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
sections.push("");
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
} catch {
|
|
561
|
+
}
|
|
562
|
+
}
|
|
495
563
|
return sections.join("\n");
|
|
496
564
|
}
|
|
497
565
|
};
|
|
@@ -523,7 +591,7 @@ var zendeskOauthConnector = new ConnectorPlugin({
|
|
|
523
591
|
systemPrompt: {
|
|
524
592
|
en: `### Tools
|
|
525
593
|
|
|
526
|
-
- \`
|
|
594
|
+
- \`connector_zendesk-oauth_request\`: The only way to call the Zendesk Support API. Use it to query tickets, users, organizations, groups, and perform searches. Authentication is configured automatically via OAuth. Zendesk uses cursor-based pagination with \`page[size]\` and \`page[after]\` parameters. All endpoint paths end with \`.json\`.
|
|
527
595
|
|
|
528
596
|
### Zendesk API Reference
|
|
529
597
|
|
|
@@ -581,7 +649,7 @@ const data = await res.json();
|
|
|
581
649
|
\`\`\``,
|
|
582
650
|
ja: `### \u30C4\u30FC\u30EB
|
|
583
651
|
|
|
584
|
-
- \`
|
|
652
|
+
- \`connector_zendesk-oauth_request\`: Zendesk Support API\u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\u3002\u30C1\u30B1\u30C3\u30C8\u3001\u30E6\u30FC\u30B6\u30FC\u3001\u7D44\u7E54\u3001\u30B0\u30EB\u30FC\u30D7\u306E\u30AF\u30A8\u30EA\u3084\u691C\u7D22\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002OAuth\u7D4C\u7531\u3067\u8A8D\u8A3C\u306F\u81EA\u52D5\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002Zendesk\u306F \`page[size]\` \u3068 \`page[after]\` \u30D1\u30E9\u30E1\u30FC\u30BF\u306B\u3088\u308B\u30AB\u30FC\u30BD\u30EB\u30D9\u30FC\u30B9\u306E\u30DA\u30FC\u30B8\u30CD\u30FC\u30B7\u30E7\u30F3\u3092\u4F7F\u7528\u3057\u307E\u3059\u3002\u5168\u3066\u306E\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u30D1\u30B9\u306F \`.json\` \u3067\u7D42\u308F\u308A\u307E\u3059\u3002
|
|
585
653
|
|
|
586
654
|
### Zendesk API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
|
|
587
655
|
|
|
@@ -16,6 +16,7 @@ var init_parameter_definition = __esm({
|
|
|
16
16
|
type;
|
|
17
17
|
secret;
|
|
18
18
|
required;
|
|
19
|
+
isDeprecated;
|
|
19
20
|
constructor(config) {
|
|
20
21
|
this.slug = config.slug;
|
|
21
22
|
this.name = config.name;
|
|
@@ -24,6 +25,7 @@ var init_parameter_definition = __esm({
|
|
|
24
25
|
this.type = config.type;
|
|
25
26
|
this.secret = config.secret;
|
|
26
27
|
this.required = config.required;
|
|
28
|
+
this.isDeprecated = config.isDeprecated ?? false;
|
|
27
29
|
}
|
|
28
30
|
/**
|
|
29
31
|
* Get the parameter value from a ConnectorConnectionObject.
|
|
@@ -299,7 +301,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
299
301
|
/**
|
|
300
302
|
* Create tools for connections that belong to this connector.
|
|
301
303
|
* Filters connections by connectorKey internally.
|
|
302
|
-
* Returns tools keyed as
|
|
304
|
+
* Returns tools keyed as `connector_${connectorKey}_${toolName}`.
|
|
303
305
|
*/
|
|
304
306
|
createTools(connections, config, opts) {
|
|
305
307
|
const myConnections = connections.filter(
|
|
@@ -309,7 +311,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
309
311
|
for (const t of Object.values(this.tools)) {
|
|
310
312
|
const tool = t.createTool(myConnections, config);
|
|
311
313
|
const originalToModelOutput = tool.toModelOutput;
|
|
312
|
-
result[
|
|
314
|
+
result[`connector_${this.connectorKey}_${t.name}`] = {
|
|
313
315
|
...tool,
|
|
314
316
|
toModelOutput: async (options) => {
|
|
315
317
|
if (!originalToModelOutput) {
|
|
@@ -365,19 +367,34 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
365
367
|
};
|
|
366
368
|
let state = flow.initialState();
|
|
367
369
|
let answerIdx = 0;
|
|
370
|
+
const pendingParameterUpdates = [];
|
|
368
371
|
for (const step of flow.steps) {
|
|
369
372
|
const ans = ctx.answers[answerIdx];
|
|
370
373
|
if (ans && ans.questionSlug === step.slug) {
|
|
371
374
|
state = step.applyAnswer(state, ans.answer);
|
|
375
|
+
if (step.toParameterUpdates) {
|
|
376
|
+
pendingParameterUpdates.push(...step.toParameterUpdates(state));
|
|
377
|
+
}
|
|
372
378
|
answerIdx += 1;
|
|
373
379
|
continue;
|
|
374
380
|
}
|
|
381
|
+
const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
|
|
375
382
|
if (step.type === "text") {
|
|
383
|
+
if (step.fetchOptions) {
|
|
384
|
+
const options2 = await step.fetchOptions(state, runtime);
|
|
385
|
+
if (options2.length === 0) {
|
|
386
|
+
continue;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
376
389
|
return {
|
|
377
390
|
type: "nextQuestion",
|
|
378
391
|
questionSlug: step.slug,
|
|
379
392
|
question: step.question[ctx.language],
|
|
380
|
-
questionType: "text"
|
|
393
|
+
questionType: "text",
|
|
394
|
+
allowFreeText: resolvedAllowFreeText,
|
|
395
|
+
...pendingParameterUpdates.length > 0 && {
|
|
396
|
+
parameterUpdates: pendingParameterUpdates
|
|
397
|
+
}
|
|
381
398
|
};
|
|
382
399
|
}
|
|
383
400
|
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
@@ -389,11 +406,21 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
389
406
|
questionSlug: step.slug,
|
|
390
407
|
question: step.question[ctx.language],
|
|
391
408
|
questionType: step.type,
|
|
392
|
-
options
|
|
409
|
+
options,
|
|
410
|
+
allowFreeText: resolvedAllowFreeText,
|
|
411
|
+
...pendingParameterUpdates.length > 0 && {
|
|
412
|
+
parameterUpdates: pendingParameterUpdates
|
|
413
|
+
}
|
|
393
414
|
};
|
|
394
415
|
}
|
|
395
416
|
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
396
|
-
return {
|
|
417
|
+
return {
|
|
418
|
+
type: "fulfilled",
|
|
419
|
+
dataInvestigationResult,
|
|
420
|
+
...pendingParameterUpdates.length > 0 && {
|
|
421
|
+
parameterUpdates: pendingParameterUpdates
|
|
422
|
+
}
|
|
423
|
+
};
|
|
397
424
|
}
|
|
398
425
|
async function resolveSetupSelection(params) {
|
|
399
426
|
const { selected, allSentinel, fetchAll, limit } = params;
|
|
@@ -414,14 +441,14 @@ var AUTH_TYPES = {
|
|
|
414
441
|
// ../connectors/src/connectors/zendesk/setup.ts
|
|
415
442
|
var zendeskOnboarding = new ConnectorOnboarding({
|
|
416
443
|
dataOverviewInstructions: {
|
|
417
|
-
en: `1. Call
|
|
418
|
-
2. Call
|
|
419
|
-
3. Call
|
|
420
|
-
4. Call
|
|
421
|
-
ja: `1.
|
|
422
|
-
2.
|
|
423
|
-
3.
|
|
424
|
-
4.
|
|
444
|
+
en: `1. Call connector_zendesk_request with GET /api/v2/ticket_fields.json to list available ticket fields
|
|
445
|
+
2. Call connector_zendesk_request with GET /api/v2/tickets.json?page[size]=5 to explore ticket structure
|
|
446
|
+
3. Call connector_zendesk_request with GET /api/v2/users.json?page[size]=5 to explore user structure
|
|
447
|
+
4. Call connector_zendesk_request with GET /api/v2/organizations.json?page[size]=5 to explore organization structure`,
|
|
448
|
+
ja: `1. connector_zendesk_request \u3067 GET /api/v2/ticket_fields.json \u3092\u547C\u3073\u51FA\u3057\u3001\u5229\u7528\u53EF\u80FD\u306A\u30C1\u30B1\u30C3\u30C8\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u78BA\u8A8D
|
|
449
|
+
2. connector_zendesk_request \u3067 GET /api/v2/tickets.json?page[size]=5 \u3092\u547C\u3073\u51FA\u3057\u3001\u30C1\u30B1\u30C3\u30C8\u306E\u69CB\u9020\u3092\u78BA\u8A8D
|
|
450
|
+
3. connector_zendesk_request \u3067 GET /api/v2/users.json?page[size]=5 \u3092\u547C\u3073\u51FA\u3057\u3001\u30E6\u30FC\u30B6\u30FC\u306E\u69CB\u9020\u3092\u78BA\u8A8D
|
|
451
|
+
4. connector_zendesk_request \u3067 GET /api/v2/organizations.json?page[size]=5 \u3092\u547C\u3073\u51FA\u3057\u3001\u7D44\u7E54\u306E\u69CB\u9020\u3092\u78BA\u8A8D`
|
|
425
452
|
}
|
|
426
453
|
});
|
|
427
454
|
|
|
@@ -666,7 +693,7 @@ var zendeskConnector = new ConnectorPlugin({
|
|
|
666
693
|
systemPrompt: {
|
|
667
694
|
en: `### Tools
|
|
668
695
|
|
|
669
|
-
- \`
|
|
696
|
+
- \`connector_zendesk_request\`: The only way to call the Zendesk Support API. Use it to query tickets, users, organizations, groups, and perform searches. Authentication (Basic auth with email/token) is configured automatically. Zendesk uses cursor-based pagination with \`page[size]\` and \`page[after]\` parameters. All endpoint paths end with \`.json\`.
|
|
670
697
|
|
|
671
698
|
### Business Logic
|
|
672
699
|
|
|
@@ -752,7 +779,7 @@ export default async function handler(c: Context) {
|
|
|
752
779
|
- \`type:organization {name}\` \u2014 Organizations matching a name`,
|
|
753
780
|
ja: `### \u30C4\u30FC\u30EB
|
|
754
781
|
|
|
755
|
-
- \`
|
|
782
|
+
- \`connector_zendesk_request\`: Zendesk Support API\u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\u3002\u30C1\u30B1\u30C3\u30C8\u3001\u30E6\u30FC\u30B6\u30FC\u3001\u7D44\u7E54\u3001\u30B0\u30EB\u30FC\u30D7\u306E\u30AF\u30A8\u30EA\u3084\u691C\u7D22\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\u8A8D\u8A3C\uFF08\u30E1\u30FC\u30EB/\u30C8\u30FC\u30AF\u30F3\u306B\u3088\u308BBasic\u8A8D\u8A3C\uFF09\u306F\u81EA\u52D5\u7684\u306B\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002Zendesk\u306F \`page[size]\` \u3068 \`page[after]\` \u30D1\u30E9\u30E1\u30FC\u30BF\u306B\u3088\u308B\u30AB\u30FC\u30BD\u30EB\u30D9\u30FC\u30B9\u306E\u30DA\u30FC\u30B8\u30CD\u30FC\u30B7\u30E7\u30F3\u3092\u4F7F\u7528\u3057\u307E\u3059\u3002\u5168\u3066\u306E\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u30D1\u30B9\u306F \`.json\` \u3067\u7D42\u308F\u308A\u307E\u3059\u3002
|
|
756
783
|
|
|
757
784
|
### Business Logic
|
|
758
785
|
|