@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
|
@@ -190,7 +190,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
190
190
|
/**
|
|
191
191
|
* Create tools for connections that belong to this connector.
|
|
192
192
|
* Filters connections by connectorKey internally.
|
|
193
|
-
* Returns tools keyed as
|
|
193
|
+
* Returns tools keyed as `connector_${connectorKey}_${toolName}`.
|
|
194
194
|
*/
|
|
195
195
|
createTools(connections, config, opts) {
|
|
196
196
|
const myConnections = connections.filter(
|
|
@@ -200,7 +200,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
200
200
|
for (const t of Object.values(this.tools)) {
|
|
201
201
|
const tool = t.createTool(myConnections, config);
|
|
202
202
|
const originalToModelOutput = tool.toModelOutput;
|
|
203
|
-
result[
|
|
203
|
+
result[`connector_${this.connectorKey}_${t.name}`] = {
|
|
204
204
|
...tool,
|
|
205
205
|
toModelOutput: async (options) => {
|
|
206
206
|
if (!originalToModelOutput) {
|
|
@@ -256,19 +256,34 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
256
256
|
};
|
|
257
257
|
let state = flow.initialState();
|
|
258
258
|
let answerIdx = 0;
|
|
259
|
+
const pendingParameterUpdates = [];
|
|
259
260
|
for (const step of flow.steps) {
|
|
260
261
|
const ans = ctx.answers[answerIdx];
|
|
261
262
|
if (ans && ans.questionSlug === step.slug) {
|
|
262
263
|
state = step.applyAnswer(state, ans.answer);
|
|
264
|
+
if (step.toParameterUpdates) {
|
|
265
|
+
pendingParameterUpdates.push(...step.toParameterUpdates(state));
|
|
266
|
+
}
|
|
263
267
|
answerIdx += 1;
|
|
264
268
|
continue;
|
|
265
269
|
}
|
|
270
|
+
const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
|
|
266
271
|
if (step.type === "text") {
|
|
272
|
+
if (step.fetchOptions) {
|
|
273
|
+
const options2 = await step.fetchOptions(state, runtime);
|
|
274
|
+
if (options2.length === 0) {
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
267
278
|
return {
|
|
268
279
|
type: "nextQuestion",
|
|
269
280
|
questionSlug: step.slug,
|
|
270
281
|
question: step.question[ctx.language],
|
|
271
|
-
questionType: "text"
|
|
282
|
+
questionType: "text",
|
|
283
|
+
allowFreeText: resolvedAllowFreeText,
|
|
284
|
+
...pendingParameterUpdates.length > 0 && {
|
|
285
|
+
parameterUpdates: pendingParameterUpdates
|
|
286
|
+
}
|
|
272
287
|
};
|
|
273
288
|
}
|
|
274
289
|
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
@@ -280,11 +295,21 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
280
295
|
questionSlug: step.slug,
|
|
281
296
|
question: step.question[ctx.language],
|
|
282
297
|
questionType: step.type,
|
|
283
|
-
options
|
|
298
|
+
options,
|
|
299
|
+
allowFreeText: resolvedAllowFreeText,
|
|
300
|
+
...pendingParameterUpdates.length > 0 && {
|
|
301
|
+
parameterUpdates: pendingParameterUpdates
|
|
302
|
+
}
|
|
284
303
|
};
|
|
285
304
|
}
|
|
286
305
|
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
287
|
-
return {
|
|
306
|
+
return {
|
|
307
|
+
type: "fulfilled",
|
|
308
|
+
dataInvestigationResult,
|
|
309
|
+
...pendingParameterUpdates.length > 0 && {
|
|
310
|
+
parameterUpdates: pendingParameterUpdates
|
|
311
|
+
}
|
|
312
|
+
};
|
|
288
313
|
}
|
|
289
314
|
async function resolveSetupSelection(params) {
|
|
290
315
|
const { selected, allSentinel, fetchAll, limit } = params;
|
|
@@ -466,14 +491,14 @@ var powerbiOauthOnboarding = new ConnectorOnboarding({
|
|
|
466
491
|
- Write only 1 sentence between tool calls, then immediately call the next tool`
|
|
467
492
|
},
|
|
468
493
|
dataOverviewInstructions: {
|
|
469
|
-
en: `1. Call
|
|
470
|
-
2. For a target workspace, call
|
|
471
|
-
3. Call
|
|
472
|
-
4. For each interesting dataset call
|
|
473
|
-
ja: `1.
|
|
474
|
-
2. \u5BFE\u8C61\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u306B\u5BFE\u3057\u3066
|
|
475
|
-
3.
|
|
476
|
-
4. \u8208\u5473\u306E\u3042\u308B\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u306B\u3064\u3044\u3066
|
|
494
|
+
en: `1. Call connector_powerbi-oauth_request with GET /groups to list accessible workspaces
|
|
495
|
+
2. For a target workspace, call connector_powerbi-oauth_request with GET /groups/{groupId}/datasets to list datasets
|
|
496
|
+
3. Call connector_powerbi-oauth_request with GET /groups/{groupId}/reports to list reports
|
|
497
|
+
4. For each interesting dataset call connector_powerbi-oauth_request with GET /groups/{groupId}/datasets/{datasetId}/tables to inspect tables`,
|
|
498
|
+
ja: `1. connector_powerbi-oauth_request \u3067 GET /groups \u3092\u547C\u3073\u51FA\u3057\u3001\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u4E00\u89A7\u3092\u53D6\u5F97
|
|
499
|
+
2. \u5BFE\u8C61\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u306B\u5BFE\u3057\u3066 connector_powerbi-oauth_request \u3067 GET /groups/{groupId}/datasets \u3092\u547C\u3073\u51FA\u3057\u3001\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u4E00\u89A7\u3092\u53D6\u5F97
|
|
500
|
+
3. connector_powerbi-oauth_request \u3067 GET /groups/{groupId}/reports \u3092\u547C\u3073\u51FA\u3057\u3001\u30EC\u30DD\u30FC\u30C8\u4E00\u89A7\u3092\u53D6\u5F97
|
|
501
|
+
4. \u8208\u5473\u306E\u3042\u308B\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u306B\u3064\u3044\u3066 connector_powerbi-oauth_request \u3067 GET /groups/{groupId}/datasets/{datasetId}/tables \u3092\u547C\u3073\u51FA\u3057\u3001\u30C6\u30FC\u30D6\u30EB\u69CB\u9020\u3092\u78BA\u8A8D`
|
|
477
502
|
}
|
|
478
503
|
});
|
|
479
504
|
|
|
@@ -489,6 +514,10 @@ function apiFetch(proxyFetch, path2, init) {
|
|
|
489
514
|
|
|
490
515
|
// ../connectors/src/connectors/powerbi-oauth/setup-flow.ts
|
|
491
516
|
var ALL_WORKSPACES = "__ALL_WORKSPACES__";
|
|
517
|
+
var MY_WORKSPACE = "__MY_WORKSPACE__";
|
|
518
|
+
var ALL_DATASETS = "__ALL_DATASETS__";
|
|
519
|
+
var ALL_REPORTS = "__ALL_REPORTS__";
|
|
520
|
+
var ALL_DASHBOARDS = "__ALL_DASHBOARDS__";
|
|
492
521
|
var POWERBI_SETUP_MAX_WORKSPACES = 10;
|
|
493
522
|
var RESOURCE_DISPLAY_LIMIT = 25;
|
|
494
523
|
var RESOURCE_DATASETS = "datasets";
|
|
@@ -504,14 +533,12 @@ async function listGroups(proxyFetch) {
|
|
|
504
533
|
return data.value ?? [];
|
|
505
534
|
}
|
|
506
535
|
async function listResource(proxyFetch, groupId, resource) {
|
|
507
|
-
const
|
|
508
|
-
|
|
509
|
-
`/groups/${encodeURIComponent(groupId)}/${resource}`
|
|
510
|
-
);
|
|
536
|
+
const path2 = groupId === MY_WORKSPACE ? `/${resource}` : `/groups/${encodeURIComponent(groupId)}/${resource}`;
|
|
537
|
+
const res = await apiFetch(proxyFetch, path2);
|
|
511
538
|
if (!res.ok) {
|
|
512
539
|
const body = await res.text().catch(() => res.statusText);
|
|
513
540
|
throw new Error(
|
|
514
|
-
`powerbi: list ${resource} for group ${groupId} failed (${res.status}): ${body}`
|
|
541
|
+
`powerbi: list ${resource} for ${groupId === MY_WORKSPACE ? "My workspace" : `group ${groupId}`} failed (${res.status}): ${body}`
|
|
515
542
|
);
|
|
516
543
|
}
|
|
517
544
|
const data = await res.json();
|
|
@@ -520,6 +547,99 @@ async function listResource(proxyFetch, groupId, resource) {
|
|
|
520
547
|
function resourceLabel(r) {
|
|
521
548
|
return r.name ?? r.displayName ?? r.id ?? "(unknown)";
|
|
522
549
|
}
|
|
550
|
+
var INTERNAL_TABLE_PREFIXES = [
|
|
551
|
+
"DateTableTemplate_",
|
|
552
|
+
"LocalDateTable_"
|
|
553
|
+
];
|
|
554
|
+
function isInternalColumn(name) {
|
|
555
|
+
return /^RowNumber-[0-9A-Fa-f-]+$/.test(name);
|
|
556
|
+
}
|
|
557
|
+
async function fetchDatasetSchema(proxyFetch, wsId, datasetId) {
|
|
558
|
+
const pathPrefix = wsId === MY_WORKSPACE ? "" : `/groups/${encodeURIComponent(wsId)}`;
|
|
559
|
+
const daxQuery = 'EVALUATE SELECTCOLUMNS(COLUMNSTATISTICS(), "T", [Table Name], "C", [Column Name])';
|
|
560
|
+
const res = await apiFetch(
|
|
561
|
+
proxyFetch,
|
|
562
|
+
`${pathPrefix}/datasets/${encodeURIComponent(datasetId)}/executeQueries`,
|
|
563
|
+
{
|
|
564
|
+
method: "POST",
|
|
565
|
+
headers: { "Content-Type": "application/json" },
|
|
566
|
+
body: JSON.stringify({
|
|
567
|
+
queries: [{ query: daxQuery }],
|
|
568
|
+
serializerSettings: { includeNulls: true }
|
|
569
|
+
})
|
|
570
|
+
}
|
|
571
|
+
);
|
|
572
|
+
if (!res.ok) return /* @__PURE__ */ new Map();
|
|
573
|
+
const data = await res.json();
|
|
574
|
+
const rows = data.results?.[0]?.tables?.[0]?.rows ?? [];
|
|
575
|
+
const schema = /* @__PURE__ */ new Map();
|
|
576
|
+
for (const row of rows) {
|
|
577
|
+
const table = row["[T]"] ?? "";
|
|
578
|
+
const column = row["[C]"] ?? "";
|
|
579
|
+
if (!table || !column) continue;
|
|
580
|
+
if (INTERNAL_TABLE_PREFIXES.some((p) => table.startsWith(p))) continue;
|
|
581
|
+
if (isInternalColumn(column)) continue;
|
|
582
|
+
if (!schema.has(table)) schema.set(table, []);
|
|
583
|
+
schema.get(table).push(column);
|
|
584
|
+
}
|
|
585
|
+
return schema;
|
|
586
|
+
}
|
|
587
|
+
function workspaceName(wsId, groupById, language) {
|
|
588
|
+
if (wsId === MY_WORKSPACE) {
|
|
589
|
+
return language === "ja" ? "\u30DE\u30A4 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9" : "My workspace";
|
|
590
|
+
}
|
|
591
|
+
return groupById.get(wsId)?.name ?? wsId;
|
|
592
|
+
}
|
|
593
|
+
async function resolveWorkspaceIds(selected, proxyFetch) {
|
|
594
|
+
return resolveSetupSelection({
|
|
595
|
+
selected,
|
|
596
|
+
allSentinel: ALL_WORKSPACES,
|
|
597
|
+
fetchAll: async () => {
|
|
598
|
+
const groups = await listGroups(proxyFetch);
|
|
599
|
+
return [MY_WORKSPACE, ...groups.map((g) => g.id).filter(Boolean)];
|
|
600
|
+
},
|
|
601
|
+
limit: POWERBI_SETUP_MAX_WORKSPACES
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
function compoundKey(wsId, objectId) {
|
|
605
|
+
return `${wsId}:${objectId}`;
|
|
606
|
+
}
|
|
607
|
+
function parseCompoundKey(key) {
|
|
608
|
+
const idx = key.indexOf(":");
|
|
609
|
+
if (idx < 0) return { wsId: "", objectId: key };
|
|
610
|
+
return { wsId: key.slice(0, idx), objectId: key.slice(idx + 1) };
|
|
611
|
+
}
|
|
612
|
+
async function fetchObjectOptions(state, resource, allSentinel, allLabelJa, allLabelEn, rt) {
|
|
613
|
+
if (!state.workspaces?.length || !state.resources?.includes(resource))
|
|
614
|
+
return [];
|
|
615
|
+
const wsIds = await resolveWorkspaceIds(
|
|
616
|
+
state.workspaces,
|
|
617
|
+
rt.config.proxyFetch
|
|
618
|
+
);
|
|
619
|
+
const allGroups = await listGroups(rt.config.proxyFetch);
|
|
620
|
+
const groupById = new Map(allGroups.map((g) => [g.id, g]));
|
|
621
|
+
const multiWorkspace = wsIds.length > 1;
|
|
622
|
+
const options = [];
|
|
623
|
+
for (const wsId of wsIds) {
|
|
624
|
+
const wsLabel = workspaceName(wsId, groupById, rt.language);
|
|
625
|
+
const items = await listResource(rt.config.proxyFetch, wsId, resource);
|
|
626
|
+
for (const item of items) {
|
|
627
|
+
if (!item.id) continue;
|
|
628
|
+
options.push({
|
|
629
|
+
value: compoundKey(wsId, item.id),
|
|
630
|
+
label: multiWorkspace ? `${wsLabel} / ${resourceLabel(item)}` : resourceLabel(item)
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
if (options.length === 0) return [];
|
|
635
|
+
return [
|
|
636
|
+
{
|
|
637
|
+
value: allSentinel,
|
|
638
|
+
label: rt.language === "ja" ? allLabelJa : allLabelEn
|
|
639
|
+
},
|
|
640
|
+
...options
|
|
641
|
+
];
|
|
642
|
+
}
|
|
523
643
|
var powerbiOauthSetupFlow = {
|
|
524
644
|
initialState: () => ({}),
|
|
525
645
|
steps: [
|
|
@@ -538,6 +658,10 @@ var powerbiOauthSetupFlow = {
|
|
|
538
658
|
value: ALL_WORKSPACES,
|
|
539
659
|
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9" : "All workspaces"
|
|
540
660
|
},
|
|
661
|
+
{
|
|
662
|
+
value: MY_WORKSPACE,
|
|
663
|
+
label: rt.language === "ja" ? "\u30DE\u30A4 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9" : "My workspace"
|
|
664
|
+
},
|
|
541
665
|
...options
|
|
542
666
|
];
|
|
543
667
|
},
|
|
@@ -552,16 +676,82 @@ var powerbiOauthSetupFlow = {
|
|
|
552
676
|
},
|
|
553
677
|
async fetchOptions(state, rt) {
|
|
554
678
|
if (!state.workspaces?.length) return [];
|
|
555
|
-
const datasetsLabel = rt.language === "ja" ? "\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8" : "Datasets";
|
|
556
|
-
const reportsLabel = rt.language === "ja" ? "\u30EC\u30DD\u30FC\u30C8" : "Reports";
|
|
557
|
-
const dashboardsLabel = rt.language === "ja" ? "\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9" : "Dashboards";
|
|
558
679
|
return [
|
|
559
|
-
{
|
|
560
|
-
|
|
561
|
-
|
|
680
|
+
{
|
|
681
|
+
value: RESOURCE_DATASETS,
|
|
682
|
+
label: rt.language === "ja" ? "\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8" : "Datasets"
|
|
683
|
+
},
|
|
684
|
+
{
|
|
685
|
+
value: RESOURCE_REPORTS,
|
|
686
|
+
label: rt.language === "ja" ? "\u30EC\u30DD\u30FC\u30C8" : "Reports"
|
|
687
|
+
},
|
|
688
|
+
{
|
|
689
|
+
value: RESOURCE_DASHBOARDS,
|
|
690
|
+
label: rt.language === "ja" ? "\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9" : "Dashboards"
|
|
691
|
+
}
|
|
562
692
|
];
|
|
563
693
|
},
|
|
564
694
|
applyAnswer: (state, answer) => ({ ...state, resources: answer })
|
|
695
|
+
},
|
|
696
|
+
{
|
|
697
|
+
slug: "datasets",
|
|
698
|
+
type: "multiSelect",
|
|
699
|
+
question: {
|
|
700
|
+
ja: "\u4F7F\u7528\u3059\u308B\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
701
|
+
en: "Select the datasets you want to use (multi-select allowed)"
|
|
702
|
+
},
|
|
703
|
+
async fetchOptions(state, rt) {
|
|
704
|
+
return fetchObjectOptions(
|
|
705
|
+
state,
|
|
706
|
+
RESOURCE_DATASETS,
|
|
707
|
+
ALL_DATASETS,
|
|
708
|
+
"\u3059\u3079\u3066\u306E\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8",
|
|
709
|
+
"All datasets",
|
|
710
|
+
rt
|
|
711
|
+
);
|
|
712
|
+
},
|
|
713
|
+
applyAnswer: (state, answer) => ({ ...state, selectedDatasets: answer })
|
|
714
|
+
},
|
|
715
|
+
{
|
|
716
|
+
slug: "reports",
|
|
717
|
+
type: "multiSelect",
|
|
718
|
+
question: {
|
|
719
|
+
ja: "\u4F7F\u7528\u3059\u308B\u30EC\u30DD\u30FC\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
720
|
+
en: "Select the reports you want to use (multi-select allowed)"
|
|
721
|
+
},
|
|
722
|
+
async fetchOptions(state, rt) {
|
|
723
|
+
return fetchObjectOptions(
|
|
724
|
+
state,
|
|
725
|
+
RESOURCE_REPORTS,
|
|
726
|
+
ALL_REPORTS,
|
|
727
|
+
"\u3059\u3079\u3066\u306E\u30EC\u30DD\u30FC\u30C8",
|
|
728
|
+
"All reports",
|
|
729
|
+
rt
|
|
730
|
+
);
|
|
731
|
+
},
|
|
732
|
+
applyAnswer: (state, answer) => ({ ...state, selectedReports: answer })
|
|
733
|
+
},
|
|
734
|
+
{
|
|
735
|
+
slug: "dashboards",
|
|
736
|
+
type: "multiSelect",
|
|
737
|
+
question: {
|
|
738
|
+
ja: "\u4F7F\u7528\u3059\u308B\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
739
|
+
en: "Select the dashboards you want to use (multi-select allowed)"
|
|
740
|
+
},
|
|
741
|
+
async fetchOptions(state, rt) {
|
|
742
|
+
return fetchObjectOptions(
|
|
743
|
+
state,
|
|
744
|
+
RESOURCE_DASHBOARDS,
|
|
745
|
+
ALL_DASHBOARDS,
|
|
746
|
+
"\u3059\u3079\u3066\u306E\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9",
|
|
747
|
+
"All dashboards",
|
|
748
|
+
rt
|
|
749
|
+
);
|
|
750
|
+
},
|
|
751
|
+
applyAnswer: (state, answer) => ({
|
|
752
|
+
...state,
|
|
753
|
+
selectedDashboards: answer
|
|
754
|
+
})
|
|
565
755
|
}
|
|
566
756
|
],
|
|
567
757
|
async finalize(state, rt) {
|
|
@@ -570,37 +760,119 @@ var powerbiOauthSetupFlow = {
|
|
|
570
760
|
}
|
|
571
761
|
const allGroups = await listGroups(rt.config.proxyFetch);
|
|
572
762
|
const groupById = new Map(allGroups.map((g) => [g.id, g]));
|
|
573
|
-
const
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
limit: POWERBI_SETUP_MAX_WORKSPACES
|
|
578
|
-
});
|
|
763
|
+
const wsIds = await resolveWorkspaceIds(
|
|
764
|
+
state.workspaces,
|
|
765
|
+
rt.config.proxyFetch
|
|
766
|
+
);
|
|
579
767
|
const selectedResources = new Set(state.resources);
|
|
768
|
+
async function resolveObjects(selected, allSentinel, resource) {
|
|
769
|
+
const byWorkspace = /* @__PURE__ */ new Map();
|
|
770
|
+
if (!selected || !selectedResources.has(resource)) return byWorkspace;
|
|
771
|
+
if (selected.includes(allSentinel)) {
|
|
772
|
+
for (const wsId of wsIds) {
|
|
773
|
+
const items = await listResource(
|
|
774
|
+
rt.config.proxyFetch,
|
|
775
|
+
wsId,
|
|
776
|
+
resource
|
|
777
|
+
);
|
|
778
|
+
const ids = items.map((i) => i.id).filter((id) => !!id);
|
|
779
|
+
if (ids.length > 0) byWorkspace.set(wsId, new Set(ids));
|
|
780
|
+
}
|
|
781
|
+
} else {
|
|
782
|
+
for (const key of selected) {
|
|
783
|
+
if (key === allSentinel) continue;
|
|
784
|
+
const { wsId, objectId } = parseCompoundKey(key);
|
|
785
|
+
if (!byWorkspace.has(wsId)) byWorkspace.set(wsId, /* @__PURE__ */ new Set());
|
|
786
|
+
byWorkspace.get(wsId).add(objectId);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
return byWorkspace;
|
|
790
|
+
}
|
|
791
|
+
const datasetsByWs = await resolveObjects(
|
|
792
|
+
state.selectedDatasets,
|
|
793
|
+
ALL_DATASETS,
|
|
794
|
+
RESOURCE_DATASETS
|
|
795
|
+
);
|
|
796
|
+
const reportsByWs = await resolveObjects(
|
|
797
|
+
state.selectedReports,
|
|
798
|
+
ALL_REPORTS,
|
|
799
|
+
RESOURCE_REPORTS
|
|
800
|
+
);
|
|
801
|
+
const dashboardsByWs = await resolveObjects(
|
|
802
|
+
state.selectedDashboards,
|
|
803
|
+
ALL_DASHBOARDS,
|
|
804
|
+
RESOURCE_DASHBOARDS
|
|
805
|
+
);
|
|
806
|
+
const allWsIds = /* @__PURE__ */ new Set([
|
|
807
|
+
...datasetsByWs.keys(),
|
|
808
|
+
...reportsByWs.keys(),
|
|
809
|
+
...dashboardsByWs.keys()
|
|
810
|
+
]);
|
|
580
811
|
const sections = ["## Power BI", ""];
|
|
581
|
-
if (
|
|
582
|
-
sections.push("_No
|
|
812
|
+
if (allWsIds.size === 0) {
|
|
813
|
+
sections.push("_No resources selected._", "");
|
|
583
814
|
return sections.join("\n");
|
|
584
815
|
}
|
|
585
|
-
for (const
|
|
586
|
-
|
|
587
|
-
const name =
|
|
588
|
-
sections.push(`### Workspace: ${name}`, ""
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
816
|
+
for (const wsId of wsIds) {
|
|
817
|
+
if (!allWsIds.has(wsId)) continue;
|
|
818
|
+
const name = workspaceName(wsId, groupById, rt.language);
|
|
819
|
+
sections.push(`### Workspace: ${name}`, "");
|
|
820
|
+
if (wsId !== MY_WORKSPACE) {
|
|
821
|
+
sections.push(`- id: \`${wsId}\``);
|
|
822
|
+
}
|
|
823
|
+
const datasetIds = datasetsByWs.get(wsId);
|
|
824
|
+
if (datasetIds?.size) {
|
|
825
|
+
const items = await listResource(
|
|
826
|
+
rt.config.proxyFetch,
|
|
827
|
+
wsId,
|
|
828
|
+
RESOURCE_DATASETS
|
|
829
|
+
);
|
|
830
|
+
const filtered = items.filter(
|
|
831
|
+
(item) => item.id && datasetIds.has(item.id)
|
|
832
|
+
);
|
|
833
|
+
for (const item of filtered.slice(0, RESOURCE_DISPLAY_LIMIT)) {
|
|
834
|
+
sections.push(`#### Dataset: ${resourceLabel(item)}`, "");
|
|
835
|
+
const schema = await fetchDatasetSchema(
|
|
836
|
+
rt.config.proxyFetch,
|
|
837
|
+
wsId,
|
|
838
|
+
item.id
|
|
839
|
+
);
|
|
840
|
+
if (schema.size > 0) {
|
|
841
|
+
for (const [table, columns] of schema) {
|
|
842
|
+
sections.push(`##### Table: ${table}`, "");
|
|
843
|
+
sections.push("| Column |");
|
|
844
|
+
sections.push("|--------|");
|
|
845
|
+
for (const col of columns) {
|
|
846
|
+
sections.push(`| ${col} |`);
|
|
847
|
+
}
|
|
848
|
+
sections.push("");
|
|
849
|
+
}
|
|
850
|
+
} else {
|
|
851
|
+
sections.push("_Schema not available._", "");
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
for (const [resource, selectedByWs, heading] of [
|
|
856
|
+
[RESOURCE_REPORTS, reportsByWs, "Reports"],
|
|
857
|
+
[RESOURCE_DASHBOARDS, dashboardsByWs, "Dashboards"]
|
|
593
858
|
]) {
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
const
|
|
597
|
-
|
|
598
|
-
|
|
859
|
+
const selectedIds = selectedByWs.get(wsId);
|
|
860
|
+
if (!selectedIds?.size) continue;
|
|
861
|
+
const items = await listResource(
|
|
862
|
+
rt.config.proxyFetch,
|
|
863
|
+
wsId,
|
|
864
|
+
resource
|
|
865
|
+
);
|
|
866
|
+
const filtered = items.filter(
|
|
867
|
+
(item) => item.id && selectedIds.has(item.id)
|
|
868
|
+
);
|
|
869
|
+
sections.push(`- ${heading} (${filtered.length}):`);
|
|
870
|
+
for (const item of filtered.slice(0, RESOURCE_DISPLAY_LIMIT)) {
|
|
599
871
|
sections.push(` - ${resourceLabel(item)}`);
|
|
600
872
|
}
|
|
601
|
-
if (
|
|
873
|
+
if (filtered.length > RESOURCE_DISPLAY_LIMIT) {
|
|
602
874
|
sections.push(
|
|
603
|
-
` - \u2026and ${
|
|
875
|
+
` - \u2026and ${filtered.length - RESOURCE_DISPLAY_LIMIT} more`
|
|
604
876
|
);
|
|
605
877
|
}
|
|
606
878
|
}
|
|
@@ -634,7 +906,7 @@ var powerbiOauthConnector = new ConnectorPlugin({
|
|
|
634
906
|
systemPrompt: {
|
|
635
907
|
en: `### Tools
|
|
636
908
|
|
|
637
|
-
- \`
|
|
909
|
+
- \`connector_powerbi-oauth_request\`: The only way to call the Power BI REST API v1.0. Use it to list workspaces (\`/groups\`), datasets, reports, and to run DAX via the \`executeQueries\` endpoint. Authentication is configured automatically via OAuth (Microsoft Entra ID).
|
|
638
910
|
|
|
639
911
|
### Business Logic
|
|
640
912
|
|
|
@@ -690,7 +962,7 @@ export default async function handler(c: Context) {
|
|
|
690
962
|
- Each \`executeQueries\` call accepts one query in the \`queries\` array (per current Power BI API limits)`,
|
|
691
963
|
ja: `### \u30C4\u30FC\u30EB
|
|
692
964
|
|
|
693
|
-
- \`
|
|
965
|
+
- \`connector_powerbi-oauth_request\`: Power BI REST API v1.0 \u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\u3002\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9 (\`/groups\`)\u3001\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u3001\u30EC\u30DD\u30FC\u30C8\u306E\u4E00\u89A7\u53D6\u5F97\u3084\u3001\`executeQueries\` \u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u306B\u3088\u308B DAX \u306E\u5B9F\u884C\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002OAuth (Microsoft Entra ID) \u7D4C\u7531\u3067\u8A8D\u8A3C\u306F\u81EA\u52D5\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002
|
|
694
966
|
|
|
695
967
|
### Business Logic
|
|
696
968
|
|
|
@@ -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.
|
|
@@ -331,7 +333,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
331
333
|
/**
|
|
332
334
|
* Create tools for connections that belong to this connector.
|
|
333
335
|
* Filters connections by connectorKey internally.
|
|
334
|
-
* Returns tools keyed as
|
|
336
|
+
* Returns tools keyed as `connector_${connectorKey}_${toolName}`.
|
|
335
337
|
*/
|
|
336
338
|
createTools(connections, config, opts) {
|
|
337
339
|
const myConnections = connections.filter(
|
|
@@ -341,7 +343,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
341
343
|
for (const t of Object.values(this.tools)) {
|
|
342
344
|
const tool = t.createTool(myConnections, config);
|
|
343
345
|
const originalToModelOutput = tool.toModelOutput;
|
|
344
|
-
result[
|
|
346
|
+
result[`connector_${this.connectorKey}_${t.name}`] = {
|
|
345
347
|
...tool,
|
|
346
348
|
toModelOutput: async (options) => {
|
|
347
349
|
if (!originalToModelOutput) {
|
|
@@ -397,19 +399,34 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
397
399
|
};
|
|
398
400
|
let state = flow.initialState();
|
|
399
401
|
let answerIdx = 0;
|
|
402
|
+
const pendingParameterUpdates = [];
|
|
400
403
|
for (const step of flow.steps) {
|
|
401
404
|
const ans = ctx.answers[answerIdx];
|
|
402
405
|
if (ans && ans.questionSlug === step.slug) {
|
|
403
406
|
state = step.applyAnswer(state, ans.answer);
|
|
407
|
+
if (step.toParameterUpdates) {
|
|
408
|
+
pendingParameterUpdates.push(...step.toParameterUpdates(state));
|
|
409
|
+
}
|
|
404
410
|
answerIdx += 1;
|
|
405
411
|
continue;
|
|
406
412
|
}
|
|
413
|
+
const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
|
|
407
414
|
if (step.type === "text") {
|
|
415
|
+
if (step.fetchOptions) {
|
|
416
|
+
const options2 = await step.fetchOptions(state, runtime);
|
|
417
|
+
if (options2.length === 0) {
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
408
421
|
return {
|
|
409
422
|
type: "nextQuestion",
|
|
410
423
|
questionSlug: step.slug,
|
|
411
424
|
question: step.question[ctx.language],
|
|
412
|
-
questionType: "text"
|
|
425
|
+
questionType: "text",
|
|
426
|
+
allowFreeText: resolvedAllowFreeText,
|
|
427
|
+
...pendingParameterUpdates.length > 0 && {
|
|
428
|
+
parameterUpdates: pendingParameterUpdates
|
|
429
|
+
}
|
|
413
430
|
};
|
|
414
431
|
}
|
|
415
432
|
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
@@ -421,11 +438,21 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
421
438
|
questionSlug: step.slug,
|
|
422
439
|
question: step.question[ctx.language],
|
|
423
440
|
questionType: step.type,
|
|
424
|
-
options
|
|
441
|
+
options,
|
|
442
|
+
allowFreeText: resolvedAllowFreeText,
|
|
443
|
+
...pendingParameterUpdates.length > 0 && {
|
|
444
|
+
parameterUpdates: pendingParameterUpdates
|
|
445
|
+
}
|
|
425
446
|
};
|
|
426
447
|
}
|
|
427
448
|
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
428
|
-
return {
|
|
449
|
+
return {
|
|
450
|
+
type: "fulfilled",
|
|
451
|
+
dataInvestigationResult,
|
|
452
|
+
...pendingParameterUpdates.length > 0 && {
|
|
453
|
+
parameterUpdates: pendingParameterUpdates
|
|
454
|
+
}
|
|
455
|
+
};
|
|
429
456
|
}
|
|
430
457
|
async function resolveSetupSelection(params) {
|
|
431
458
|
const { selected, allSentinel, fetchAll, limit } = params;
|
|
@@ -446,11 +473,11 @@ var AUTH_TYPES = {
|
|
|
446
473
|
// ../connectors/src/connectors/salesforce/setup.ts
|
|
447
474
|
var salesforceOnboarding = new ConnectorOnboarding({
|
|
448
475
|
dataOverviewInstructions: {
|
|
449
|
-
en: `1. Call
|
|
450
|
-
2. Call
|
|
476
|
+
en: `1. Call connector_salesforce_request with GET /services/data/v60.0/sobjects/ to list available sObjects (standard + custom)
|
|
477
|
+
2. Call connector_salesforce_request with GET /services/data/v60.0/sobjects/Account/describe to inspect Account fields; repeat for Contact, Opportunity, Lead as needed
|
|
451
478
|
3. Run a sample SOQL query: GET /services/data/v60.0/query?q=SELECT+Id,Name,Industry+FROM+Account+LIMIT+5 to verify access and explore data`,
|
|
452
|
-
ja: `1.
|
|
453
|
-
2.
|
|
479
|
+
ja: `1. connector_salesforce_request \u3067 GET /services/data/v60.0/sobjects/ \u3092\u547C\u3073\u51FA\u3057\u3001\u5229\u7528\u53EF\u80FD\u306A sObject\uFF08\u6A19\u6E96 + \u30AB\u30B9\u30BF\u30E0\uFF09\u3092\u4E00\u89A7\u53D6\u5F97
|
|
480
|
+
2. connector_salesforce_request \u3067 GET /services/data/v60.0/sobjects/Account/describe \u3092\u547C\u3073\u51FA\u3057 Account \u306E\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u78BA\u8A8D\u3002Contact / Opportunity / Lead \u306A\u3069\u5FC5\u8981\u306A sObject \u306B\u5BFE\u3057\u3066\u540C\u69D8\u306B\u5B9F\u884C
|
|
454
481
|
3. \u30B5\u30F3\u30D7\u30EB SOQL \u3092\u5B9F\u884C: GET /services/data/v60.0/query?q=SELECT+Id,Name,Industry+FROM+Account+LIMIT+5 \u3067\u30A2\u30AF\u30BB\u30B9\u53EF\u5426\u3068\u30C7\u30FC\u30BF\u69CB\u9020\u3092\u78BA\u8A8D`
|
|
455
482
|
}
|
|
456
483
|
});
|
|
@@ -540,6 +567,20 @@ async function describeSObject(params, name) {
|
|
|
540
567
|
const data = await res.json();
|
|
541
568
|
return data.fields ?? [];
|
|
542
569
|
}
|
|
570
|
+
async function fetchSObjectCount(params, objectName) {
|
|
571
|
+
try {
|
|
572
|
+
const query = encodeURIComponent(`SELECT COUNT() FROM ${objectName}`);
|
|
573
|
+
const res = await apiFetch(
|
|
574
|
+
params,
|
|
575
|
+
`/services/data/${SALESFORCE_API_VERSION}/query?q=${query}`
|
|
576
|
+
);
|
|
577
|
+
if (!res.ok) return null;
|
|
578
|
+
const data = await res.json();
|
|
579
|
+
return typeof data.totalSize === "number" ? data.totalSize : null;
|
|
580
|
+
} catch {
|
|
581
|
+
return null;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
543
584
|
var salesforceSetupFlow = {
|
|
544
585
|
initialState: () => ({}),
|
|
545
586
|
steps: [
|
|
@@ -574,8 +615,27 @@ var salesforceSetupFlow = {
|
|
|
574
615
|
limit: SALESFORCE_SETUP_MAX_OBJECTS
|
|
575
616
|
});
|
|
576
617
|
const sections = ["## Salesforce", ""];
|
|
618
|
+
const countByObject = /* @__PURE__ */ new Map();
|
|
619
|
+
for (const objectName of targetObjects) {
|
|
620
|
+
countByObject.set(
|
|
621
|
+
objectName,
|
|
622
|
+
await fetchSObjectCount(rt.params, objectName)
|
|
623
|
+
);
|
|
624
|
+
}
|
|
625
|
+
sections.push("### Record counts", "");
|
|
626
|
+
sections.push("| sObject | Record count |");
|
|
627
|
+
sections.push("|---------|-------------|");
|
|
628
|
+
for (const objectName of targetObjects) {
|
|
629
|
+
const count = countByObject.get(objectName);
|
|
630
|
+
sections.push(
|
|
631
|
+
`| ${objectName} | ${count == null ? "-" : count.toLocaleString()} |`
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
sections.push("");
|
|
577
635
|
for (const objectName of targetObjects) {
|
|
578
|
-
|
|
636
|
+
const count = countByObject.get(objectName);
|
|
637
|
+
const countLabel = count == null ? "" : ` (${count.toLocaleString()} records)`;
|
|
638
|
+
sections.push(`### sObject: ${objectName}${countLabel}`, "");
|
|
579
639
|
const fields = await describeSObject(rt.params, objectName);
|
|
580
640
|
const limited = fields.slice(0, SALESFORCE_SETUP_MAX_FIELDS);
|
|
581
641
|
sections.push("| Field | Type | Label | Custom |");
|
|
@@ -745,7 +805,7 @@ var salesforceConnector = new ConnectorPlugin({
|
|
|
745
805
|
systemPrompt: {
|
|
746
806
|
en: `### Tools
|
|
747
807
|
|
|
748
|
-
- \`
|
|
808
|
+
- \`connector_salesforce_request\`: The only way to call the Salesforce REST API. Use it to run SOQL queries, describe sObjects, and read/create/update/delete standard (Account, Contact, Opportunity, Lead, Case) and custom objects. Authentication (OAuth 2.0 Client Credentials Flow against the External Client App / Connected App) is configured automatically \u2014 an access token is resolved on each request against the configured org instance URL. Prefer SOQL via \`GET /services/data/v60.0/query?q=...\` over paginating \`/sobjects/{Type}\` endpoints for filtered or joined reads.
|
|
749
809
|
|
|
750
810
|
### Business Logic
|
|
751
811
|
|
|
@@ -816,7 +876,7 @@ export default async function handler(c: Context) {
|
|
|
816
876
|
- Parent-to-child subquery: \`SELECT Id, Name, (SELECT Id, Email FROM Contacts) FROM Account\``,
|
|
817
877
|
ja: `### \u30C4\u30FC\u30EB
|
|
818
878
|
|
|
819
|
-
- \`
|
|
879
|
+
- \`connector_salesforce_request\`: Salesforce REST API \u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\u3002SOQL \u30AF\u30A8\u30EA\u306E\u5B9F\u884C\u3001sObject \u306E describe\u3001\u6A19\u6E96\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\uFF08Account, Contact, Opportunity, Lead, Case\uFF09\u3084\u30AB\u30B9\u30BF\u30E0\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u306E\u8AAD\u307F\u66F8\u304D\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\u8A8D\u8A3C\uFF08External Client App / Connected App + OAuth 2.0 Client Credentials Flow\uFF09\u306F\u81EA\u52D5\u3067\u884C\u308F\u308C\u3001\u8A2D\u5B9A\u3055\u308C\u305F\u7D44\u7E54\u306E instance URL \u306B\u5BFE\u3057\u3066\u30EA\u30AF\u30A8\u30B9\u30C8\u3054\u3068\u306B\u30A2\u30AF\u30BB\u30B9\u30C8\u30FC\u30AF\u30F3\u304C\u89E3\u6C7A\u3055\u308C\u307E\u3059\u3002\u30D5\u30A3\u30EB\u30BF\u3084\u7D50\u5408\u306E\u3042\u308B\u8AAD\u307F\u53D6\u308A\u3067\u306F \`/sobjects/{Type}\` \u3092\u30DA\u30FC\u30B8\u30F3\u30B0\u3059\u308B\u306E\u3067\u306F\u306A\u304F\u3001\`GET /services/data/v60.0/query?q=...\` \u306E SOQL \u3092\u512A\u5148\u3057\u3066\u304F\u3060\u3055\u3044\u3002
|
|
820
880
|
|
|
821
881
|
### Business Logic
|
|
822
882
|
|