@squadbase/vite-server 0.1.7-dev.3 → 0.1.7-dev.5
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 +161 -190
- package/dist/connectors/google-sheets.js +183 -138
- package/dist/connectors/grafana.js +1 -1
- package/dist/connectors/influxdb.js +1 -1
- package/dist/connectors/salesforce.js +54 -107
- package/dist/index.js +161 -190
- package/dist/main.js +161 -190
- package/dist/vite-plugin.js +161 -190
- package/package.json +1 -1
|
@@ -44,28 +44,19 @@ var ParameterDefinition = class {
|
|
|
44
44
|
|
|
45
45
|
// ../connectors/src/connectors/salesforce/parameters.ts
|
|
46
46
|
var parameters = {
|
|
47
|
-
|
|
48
|
-
slug: "
|
|
49
|
-
name: "
|
|
50
|
-
description: "Your Salesforce
|
|
51
|
-
envVarBaseKey: "
|
|
47
|
+
instanceUrl: new ParameterDefinition({
|
|
48
|
+
slug: "instance-url",
|
|
49
|
+
name: "Instance URL",
|
|
50
|
+
description: "Your Salesforce org's My Domain URL (e.g., https://yourorg.my.salesforce.com). Find it under Setup \u2192 Company Settings \u2192 My Domain \u2192 Current My Domain URL.",
|
|
51
|
+
envVarBaseKey: "SALESFORCE_INSTANCE_URL",
|
|
52
52
|
type: "text",
|
|
53
53
|
secret: false,
|
|
54
54
|
required: true
|
|
55
55
|
}),
|
|
56
|
-
password: new ParameterDefinition({
|
|
57
|
-
slug: "password",
|
|
58
|
-
name: "Password",
|
|
59
|
-
description: "Your Salesforce account password concatenated with your security token (password + securityToken). The security token is emailed to you when you reset it from Settings \u2192 My Personal Information \u2192 Reset My Security Token.",
|
|
60
|
-
envVarBaseKey: "SALESFORCE_PASSWORD",
|
|
61
|
-
type: "text",
|
|
62
|
-
secret: true,
|
|
63
|
-
required: true
|
|
64
|
-
}),
|
|
65
56
|
clientId: new ParameterDefinition({
|
|
66
57
|
slug: "client-id",
|
|
67
58
|
name: "Consumer Key",
|
|
68
|
-
description: "The Consumer Key (client_id) of your
|
|
59
|
+
description: "The Consumer Key (client_id) of your External Client App (or Connected App). The app must enable the OAuth 2.0 Client Credentials Flow and bind a Run-As user with API access.",
|
|
69
60
|
envVarBaseKey: "SALESFORCE_CLIENT_ID",
|
|
70
61
|
type: "text",
|
|
71
62
|
secret: false,
|
|
@@ -74,34 +65,30 @@ var parameters = {
|
|
|
74
65
|
clientSecret: new ParameterDefinition({
|
|
75
66
|
slug: "client-secret",
|
|
76
67
|
name: "Consumer Secret",
|
|
77
|
-
description: "The Consumer Secret (client_secret) of your
|
|
68
|
+
description: "The Consumer Secret (client_secret) of your External Client App (or Connected App).",
|
|
78
69
|
envVarBaseKey: "SALESFORCE_CLIENT_SECRET",
|
|
79
70
|
type: "text",
|
|
80
71
|
secret: true,
|
|
81
72
|
required: true
|
|
82
|
-
}),
|
|
83
|
-
isSandbox: new ParameterDefinition({
|
|
84
|
-
slug: "is-sandbox",
|
|
85
|
-
name: "Use Sandbox",
|
|
86
|
-
description: 'Set to "true" to authenticate against a Salesforce sandbox (test.salesforce.com) instead of production (login.salesforce.com). Defaults to "false".',
|
|
87
|
-
envVarBaseKey: "SALESFORCE_IS_SANDBOX",
|
|
88
|
-
type: "text",
|
|
89
|
-
secret: false,
|
|
90
|
-
required: false
|
|
91
73
|
})
|
|
92
74
|
};
|
|
93
75
|
|
|
94
76
|
// ../connectors/src/connectors/salesforce/sdk/index.ts
|
|
95
77
|
var DEFAULT_API_VERSION = "60.0";
|
|
96
|
-
|
|
78
|
+
function normalizeInstanceUrl(raw) {
|
|
79
|
+
const trimmed = raw.trim().replace(/\/+$/, "");
|
|
80
|
+
if (!/^https?:\/\//i.test(trimmed)) {
|
|
81
|
+
return `https://${trimmed}`;
|
|
82
|
+
}
|
|
83
|
+
return trimmed;
|
|
84
|
+
}
|
|
85
|
+
async function fetchAccessToken(instanceUrl, clientId, clientSecret) {
|
|
97
86
|
const body = new URLSearchParams({
|
|
98
|
-
grant_type: "
|
|
87
|
+
grant_type: "client_credentials",
|
|
99
88
|
client_id: clientId,
|
|
100
|
-
client_secret: clientSecret
|
|
101
|
-
username,
|
|
102
|
-
password
|
|
89
|
+
client_secret: clientSecret
|
|
103
90
|
});
|
|
104
|
-
const res = await fetch(`${
|
|
91
|
+
const res = await fetch(`${instanceUrl}/services/oauth2/token`, {
|
|
105
92
|
method: "POST",
|
|
106
93
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
107
94
|
body: body.toString()
|
|
@@ -113,22 +100,22 @@ async function fetchAccessToken(loginHost, clientId, clientSecret, username, pas
|
|
|
113
100
|
);
|
|
114
101
|
}
|
|
115
102
|
const json = await res.json();
|
|
116
|
-
if (!json.access_token
|
|
103
|
+
if (!json.access_token) {
|
|
117
104
|
throw new Error(
|
|
118
|
-
"salesforce: access_token
|
|
105
|
+
"salesforce: access_token not found in token response"
|
|
119
106
|
);
|
|
120
107
|
}
|
|
121
|
-
return {
|
|
108
|
+
return {
|
|
109
|
+
accessToken: json.access_token,
|
|
110
|
+
instanceUrl: json.instance_url ?? instanceUrl
|
|
111
|
+
};
|
|
122
112
|
}
|
|
123
113
|
function createClient(params) {
|
|
124
|
-
const
|
|
125
|
-
const password = params[parameters.password.slug];
|
|
114
|
+
const instanceUrlParam = params[parameters.instanceUrl.slug];
|
|
126
115
|
const clientId = params[parameters.clientId.slug];
|
|
127
116
|
const clientSecret = params[parameters.clientSecret.slug];
|
|
128
|
-
const isSandbox = (params[parameters.isSandbox.slug] ?? "").toLowerCase() === "true";
|
|
129
117
|
for (const [slug, value] of [
|
|
130
|
-
[parameters.
|
|
131
|
-
[parameters.password.slug, password],
|
|
118
|
+
[parameters.instanceUrl.slug, instanceUrlParam],
|
|
132
119
|
[parameters.clientId.slug, clientId],
|
|
133
120
|
[parameters.clientSecret.slug, clientSecret]
|
|
134
121
|
]) {
|
|
@@ -136,19 +123,13 @@ function createClient(params) {
|
|
|
136
123
|
throw new Error(`salesforce: missing required parameter: ${slug}`);
|
|
137
124
|
}
|
|
138
125
|
}
|
|
139
|
-
const
|
|
126
|
+
const instanceUrl = normalizeInstanceUrl(instanceUrlParam);
|
|
140
127
|
async function getToken() {
|
|
141
|
-
return fetchAccessToken(
|
|
142
|
-
loginHost,
|
|
143
|
-
clientId,
|
|
144
|
-
clientSecret,
|
|
145
|
-
username,
|
|
146
|
-
password
|
|
147
|
-
);
|
|
128
|
+
return fetchAccessToken(instanceUrl, clientId, clientSecret);
|
|
148
129
|
}
|
|
149
130
|
async function authFetch(path2, init) {
|
|
150
|
-
const { accessToken, instanceUrl } = await getToken();
|
|
151
|
-
const url = path2.startsWith("http") ? path2 : `${
|
|
131
|
+
const { accessToken, instanceUrl: resolvedInstanceUrl } = await getToken();
|
|
132
|
+
const url = path2.startsWith("http") ? path2 : `${resolvedInstanceUrl}${path2.startsWith("/") ? "" : "/"}${path2}`;
|
|
152
133
|
const headers = new Headers(init?.headers);
|
|
153
134
|
headers.set("Authorization", `Bearer ${accessToken}`);
|
|
154
135
|
if (!headers.has("Content-Type") && init?.body) {
|
|
@@ -381,42 +362,6 @@ var AUTH_TYPES = {
|
|
|
381
362
|
|
|
382
363
|
// ../connectors/src/connectors/salesforce/setup.ts
|
|
383
364
|
var salesforceOnboarding = new ConnectorOnboarding({
|
|
384
|
-
connectionSetupInstructions: {
|
|
385
|
-
en: `#### Create a Connected App in Salesforce
|
|
386
|
-
1. In Salesforce Setup, go to App Manager \u2192 New Connected App
|
|
387
|
-
2. Under API (Enable OAuth Settings), check "Enable OAuth Settings"
|
|
388
|
-
3. Add OAuth scopes: "Manage user data via APIs (api)" and "Perform requests at any time (refresh_token, offline_access)"
|
|
389
|
-
4. Save and note the Consumer Key (client_id) and Consumer Secret (client_secret)
|
|
390
|
-
|
|
391
|
-
#### Allow Username-Password Flow
|
|
392
|
-
1. Go to Setup \u2192 Identity \u2192 OAuth and OpenID Connect Settings
|
|
393
|
-
2. Enable "Allow OAuth Username-Password Flows"
|
|
394
|
-
|
|
395
|
-
#### Reset your Security Token
|
|
396
|
-
1. Go to Settings \u2192 My Personal Information \u2192 Reset My Security Token
|
|
397
|
-
2. Salesforce emails you a new security token \u2014 append it to your password when entering the Password parameter (password + securityToken)
|
|
398
|
-
|
|
399
|
-
#### Sandbox vs Production
|
|
400
|
-
- Leave Use Sandbox as "false" (or empty) to connect to production (login.salesforce.com)
|
|
401
|
-
- Set Use Sandbox to "true" to connect to a sandbox (test.salesforce.com)`,
|
|
402
|
-
ja: `#### Salesforce \u3067 Connected App \u3092\u4F5C\u6210
|
|
403
|
-
1. Setup \u2192 App Manager \u2192 New Connected App
|
|
404
|
-
2. API (Enable OAuth Settings) \u30BB\u30AF\u30B7\u30E7\u30F3\u3067 "Enable OAuth Settings" \u3092\u6709\u52B9\u5316
|
|
405
|
-
3. OAuth \u30B9\u30B3\u30FC\u30D7\u306B "Manage user data via APIs (api)" \u3068 "Perform requests at any time (refresh_token, offline_access)" \u3092\u8FFD\u52A0
|
|
406
|
-
4. \u4FDD\u5B58\u5F8C\u3001Consumer Key (client_id) \u3068 Consumer Secret (client_secret) \u3092\u63A7\u3048\u308B
|
|
407
|
-
|
|
408
|
-
#### Username-Password Flow \u3092\u8A31\u53EF
|
|
409
|
-
1. Setup \u2192 Identity \u2192 OAuth and OpenID Connect Settings
|
|
410
|
-
2. "Allow OAuth Username-Password Flows" \u3092\u6709\u52B9\u5316
|
|
411
|
-
|
|
412
|
-
#### Security Token \u306E\u767A\u884C
|
|
413
|
-
1. \u500B\u4EBA\u8A2D\u5B9A \u2192 My Personal Information \u2192 Reset My Security Token
|
|
414
|
-
2. Salesforce \u304B\u3089\u9001\u3089\u308C\u308B\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3\u30C8\u30FC\u30AF\u30F3\u3092\u30D1\u30B9\u30EF\u30FC\u30C9\u306B\u9023\u7D50\u3057\u3066\u5165\u529B\uFF08password + securityToken\uFF09
|
|
415
|
-
|
|
416
|
-
#### Sandbox / Production
|
|
417
|
-
- \u672C\u756A (login.salesforce.com) \u306E\u5834\u5408: Use Sandbox \u3092 "false" \u307E\u305F\u306F\u672A\u5165\u529B
|
|
418
|
-
- Sandbox (test.salesforce.com) \u306E\u5834\u5408: Use Sandbox \u3092 "true" \u306B\u8A2D\u5B9A`
|
|
419
|
-
},
|
|
420
365
|
dataOverviewInstructions: {
|
|
421
366
|
en: `1. Call salesforce_request with GET /services/data/v60.0/sobjects/ to list available sObjects (standard + custom)
|
|
422
367
|
2. Call salesforce_request with GET /services/data/v60.0/sobjects/Account/describe to inspect Account fields; repeat for Contact, Opportunity, Lead as needed
|
|
@@ -454,10 +399,17 @@ var outputSchema = z.discriminatedUnion("success", [
|
|
|
454
399
|
error: z.string()
|
|
455
400
|
})
|
|
456
401
|
]);
|
|
402
|
+
function normalizeInstanceUrl2(raw) {
|
|
403
|
+
const trimmed = raw.trim().replace(/\/+$/, "");
|
|
404
|
+
if (!/^https?:\/\//i.test(trimmed)) {
|
|
405
|
+
return `https://${trimmed}`;
|
|
406
|
+
}
|
|
407
|
+
return trimmed;
|
|
408
|
+
}
|
|
457
409
|
var requestTool = new ConnectorTool({
|
|
458
410
|
name: "request",
|
|
459
411
|
description: `Send authenticated requests to the Salesforce REST API.
|
|
460
|
-
Authentication is handled automatically using the OAuth 2.0
|
|
412
|
+
Authentication is handled automatically using the OAuth 2.0 Client Credentials Flow (External Client App or Connected App Consumer Key + Secret). An access token is obtained on each request, so the tool user only provides the API path.
|
|
461
413
|
Use this tool for all Salesforce interactions: describing sObjects, running SOQL queries (GET /services/data/vXX.X/query?q=...), reading/creating/updating standard (Account, Contact, Opportunity, Lead, Case) and custom objects.
|
|
462
414
|
Prefer SOQL via the /query endpoint for filtered, joined, or aggregated reads rather than paginating /sobjects/{Type} endpoints.`,
|
|
463
415
|
inputSchema,
|
|
@@ -474,20 +426,16 @@ Prefer SOQL via the /query endpoint for filtered, joined, or aggregated reads ra
|
|
|
474
426
|
`[connector-request] salesforce/${connection2.name}: ${method} ${path2}`
|
|
475
427
|
);
|
|
476
428
|
try {
|
|
477
|
-
const
|
|
478
|
-
const password = parameters.password.getValue(connection2);
|
|
429
|
+
const instanceUrlParam = parameters.instanceUrl.getValue(connection2);
|
|
479
430
|
const clientId = parameters.clientId.getValue(connection2);
|
|
480
431
|
const clientSecret = parameters.clientSecret.getValue(connection2);
|
|
481
|
-
const
|
|
482
|
-
const loginHost = isSandbox ? "https://test.salesforce.com" : "https://login.salesforce.com";
|
|
432
|
+
const instanceUrl = normalizeInstanceUrl2(instanceUrlParam);
|
|
483
433
|
const tokenBody = new URLSearchParams({
|
|
484
|
-
grant_type: "
|
|
434
|
+
grant_type: "client_credentials",
|
|
485
435
|
client_id: clientId,
|
|
486
|
-
client_secret: clientSecret
|
|
487
|
-
username,
|
|
488
|
-
password
|
|
436
|
+
client_secret: clientSecret
|
|
489
437
|
});
|
|
490
|
-
const tokenRes = await fetch(`${
|
|
438
|
+
const tokenRes = await fetch(`${instanceUrl}/services/oauth2/token`, {
|
|
491
439
|
method: "POST",
|
|
492
440
|
headers: {
|
|
493
441
|
"Content-Type": "application/x-www-form-urlencoded"
|
|
@@ -502,13 +450,14 @@ Prefer SOQL via the /query endpoint for filtered, joined, or aggregated reads ra
|
|
|
502
450
|
};
|
|
503
451
|
}
|
|
504
452
|
const tokenJson = await tokenRes.json();
|
|
505
|
-
if (!tokenJson.access_token
|
|
453
|
+
if (!tokenJson.access_token) {
|
|
506
454
|
return {
|
|
507
455
|
success: false,
|
|
508
|
-
error: "access_token
|
|
456
|
+
error: "access_token not found in token response"
|
|
509
457
|
};
|
|
510
458
|
}
|
|
511
|
-
const
|
|
459
|
+
const resolvedInstanceUrl = tokenJson.instance_url ?? instanceUrl;
|
|
460
|
+
const url = `${resolvedInstanceUrl}${path2.startsWith("/") ? "" : "/"}${path2}`;
|
|
512
461
|
const controller = new AbortController();
|
|
513
462
|
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
514
463
|
try {
|
|
@@ -557,7 +506,7 @@ Prefer SOQL via the /query endpoint for filtered, joined, or aggregated reads ra
|
|
|
557
506
|
var tools = { request: requestTool };
|
|
558
507
|
var salesforceConnector = new ConnectorPlugin({
|
|
559
508
|
slug: "salesforce",
|
|
560
|
-
authType: AUTH_TYPES.
|
|
509
|
+
authType: AUTH_TYPES.API_KEY,
|
|
561
510
|
name: "Salesforce",
|
|
562
511
|
description: "Connect to Salesforce CRM for accounts, contacts, opportunities, leads, cases, and custom objects via SOQL and the REST API.",
|
|
563
512
|
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/6vZlbrUKhxXIiuvWJlb8YB/bbc5e08b88de46c8ed338a74c7d0abb3/salesforce-icon.png",
|
|
@@ -567,7 +516,7 @@ var salesforceConnector = new ConnectorPlugin({
|
|
|
567
516
|
systemPrompt: {
|
|
568
517
|
en: `### Tools
|
|
569
518
|
|
|
570
|
-
- \`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
|
|
519
|
+
- \`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.
|
|
571
520
|
|
|
572
521
|
### Business Logic
|
|
573
522
|
|
|
@@ -613,9 +562,8 @@ export default async function handler(c: Context) {
|
|
|
613
562
|
|
|
614
563
|
### Salesforce REST API Reference
|
|
615
564
|
|
|
616
|
-
-
|
|
617
|
-
-
|
|
618
|
-
- Base path after login: \`{instance_url}/services/data/v60.0\`
|
|
565
|
+
- Token endpoint: \`POST {instance_url}/services/oauth2/token\` (grant_type=client_credentials + client_id/secret)
|
|
566
|
+
- Base path: \`{instance_url}/services/data/v60.0\` where instance_url is the org's My Domain URL
|
|
619
567
|
- Authentication: Bearer token (handled automatically per request)
|
|
620
568
|
- Pagination (SOQL): follow \`nextRecordsUrl\` from the response (absolute path starting with \`/services/data/v60.0/query/...\`)
|
|
621
569
|
|
|
@@ -639,7 +587,7 @@ export default async function handler(c: Context) {
|
|
|
639
587
|
- Parent-to-child subquery: \`SELECT Id, Name, (SELECT Id, Email FROM Contacts) FROM Account\``,
|
|
640
588
|
ja: `### \u30C4\u30FC\u30EB
|
|
641
589
|
|
|
642
|
-
- \`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\
|
|
590
|
+
- \`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
|
|
643
591
|
|
|
644
592
|
### Business Logic
|
|
645
593
|
|
|
@@ -685,9 +633,8 @@ export default async function handler(c: Context) {
|
|
|
685
633
|
|
|
686
634
|
### Salesforce REST API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
|
|
687
635
|
|
|
688
|
-
- \
|
|
689
|
-
- \
|
|
690
|
-
- \u30ED\u30B0\u30A4\u30F3\u5F8C\u306E\u30D9\u30FC\u30B9\u30D1\u30B9: \`{instance_url}/services/data/v60.0\`
|
|
636
|
+
- \u30C8\u30FC\u30AF\u30F3\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8: \`POST {instance_url}/services/oauth2/token\`\uFF08grant_type=client_credentials + client_id/secret\uFF09
|
|
637
|
+
- \u30D9\u30FC\u30B9\u30D1\u30B9: \`{instance_url}/services/data/v60.0\`\uFF08instance_url \u306F\u7D44\u7E54\u306E My Domain URL\uFF09
|
|
691
638
|
- \u8A8D\u8A3C: Bearer \u30C8\u30FC\u30AF\u30F3\uFF08\u30EA\u30AF\u30A8\u30B9\u30C8\u3054\u3068\u306B\u81EA\u52D5\u8A2D\u5B9A\uFF09
|
|
692
639
|
- \u30DA\u30FC\u30B8\u30CD\u30FC\u30B7\u30E7\u30F3\uFF08SOQL\uFF09: \u30EC\u30B9\u30DD\u30F3\u30B9\u306E \`nextRecordsUrl\`\uFF08\`/services/data/v60.0/query/...\` \u304B\u3089\u59CB\u307E\u308B\u7D76\u5BFE\u30D1\u30B9\uFF09\u3092\u8FBF\u308B
|
|
693
640
|
|