@executor-js/plugin-openapi 1.5.14 → 1.5.16
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/AddOpenApiSource-U7AYB224.js +369 -0
- package/dist/AddOpenApiSource-U7AYB224.js.map +1 -0
- package/dist/{OpenApiAccountsPanel-Y2RGBSSL.js → OpenApiAccountsPanel-GHFHHE6P.js} +15 -39
- package/dist/OpenApiAccountsPanel-GHFHHE6P.js.map +1 -0
- package/dist/{UpdateSpecSection-MIZ5GLBM.js → UpdateSpecSection-PLCBUU4I.js} +4 -4
- package/dist/UpdateSpecSection-PLCBUU4I.js.map +1 -0
- package/dist/api/group.d.ts +0 -21
- package/dist/api/index.d.ts +0 -21
- package/dist/{chunk-PNOEE3ET.js → chunk-3FM2SWM4.js} +643 -569
- package/dist/chunk-3FM2SWM4.js.map +1 -0
- package/dist/chunk-CKBX4SXK.js +95 -0
- package/dist/chunk-CKBX4SXK.js.map +1 -0
- package/dist/{chunk-GS5YN6J4.js → chunk-CPPTKUOW.js} +5 -14
- package/dist/chunk-CPPTKUOW.js.map +1 -0
- package/dist/{chunk-RFSMGUBJ.js → chunk-KVPUDOJZ.js} +83 -8
- package/dist/chunk-KVPUDOJZ.js.map +1 -0
- package/dist/{chunk-PAHWRRS3.js → chunk-QQFCICLX.js} +4 -13
- package/dist/chunk-QQFCICLX.js.map +1 -0
- package/dist/client.js +4 -5
- package/dist/client.js.map +1 -1
- package/dist/core.js +25 -15
- package/dist/core.js.map +1 -1
- package/dist/index.js +4 -5
- package/dist/index.js.map +1 -1
- package/dist/react/atoms.d.ts +0 -22
- package/dist/react/client.d.ts +0 -21
- package/dist/react/index.d.ts +2 -0
- package/dist/sdk/backing.d.ts +54 -0
- package/dist/sdk/config.d.ts +0 -2
- package/dist/sdk/derive-auth.d.ts +5 -3
- package/dist/sdk/extract.d.ts +12 -1
- package/dist/sdk/index.d.ts +2 -1
- package/dist/sdk/invoke.d.ts +12 -1
- package/dist/sdk/plugin.d.ts +4 -10
- package/dist/sdk/presets.d.ts +0 -1
- package/dist/sdk/preview.d.ts +79 -0
- package/dist/sdk/types.d.ts +53 -0
- package/dist/testing/index.d.ts +0 -6
- package/package.json +6 -5
- package/dist/AddOpenApiSource-7TI5XUUY.js +0 -765
- package/dist/AddOpenApiSource-7TI5XUUY.js.map +0 -1
- package/dist/OpenApiAccountsPanel-Y2RGBSSL.js.map +0 -1
- package/dist/UpdateSpecSection-MIZ5GLBM.js.map +0 -1
- package/dist/chunk-GS5YN6J4.js.map +0 -1
- package/dist/chunk-I2XDCVVM.js +0 -712
- package/dist/chunk-I2XDCVVM.js.map +0 -1
- package/dist/chunk-MZWZQ24W.js +0 -226
- package/dist/chunk-MZWZQ24W.js.map +0 -1
- package/dist/chunk-PAHWRRS3.js.map +0 -1
- package/dist/chunk-PNOEE3ET.js.map +0 -1
- package/dist/chunk-RFSMGUBJ.js.map +0 -1
- package/dist/react/GoogleProductPicker.d.ts +0 -9
- package/dist/sdk/google-discovery.d.ts +0 -43
- package/dist/sdk/google-discovery.test.d.ts +0 -1
- package/dist/sdk/google-oauth-batches.d.ts +0 -13
- package/dist/sdk/google-oauth-batches.test.d.ts +0 -1
- package/dist/sdk/google-oauth-scopes.d.ts +0 -3
- package/dist/sdk/google-oauth-scopes.test.d.ts +0 -1
- package/dist/sdk/google-presets.d.ts +0 -16
- package/dist/sdk/google-presets.test.d.ts +0 -1
- package/dist/sdk/google-product-picker-scopes.test.d.ts +0 -1
- /package/dist/sdk/{google-bundle.test.d.ts → store.test.d.ts} +0 -0
|
@@ -1,765 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
compactGoogleOAuthScopes,
|
|
3
|
-
detectedAuthenticationTemplates,
|
|
4
|
-
isGoogleDiscoveryUrl
|
|
5
|
-
} from "./chunk-I2XDCVVM.js";
|
|
6
|
-
import {
|
|
7
|
-
openApiPresets
|
|
8
|
-
} from "./chunk-PAHWRRS3.js";
|
|
9
|
-
import {
|
|
10
|
-
authenticationFromEditorValue,
|
|
11
|
-
editorValueFromAuthentication,
|
|
12
|
-
openApiWireAuthInput
|
|
13
|
-
} from "./chunk-RCBR3QMJ.js";
|
|
14
|
-
import {
|
|
15
|
-
GOOGLE_BUNDLE_PRESET_ID,
|
|
16
|
-
googleOAuthConsentScopesForPreset,
|
|
17
|
-
googleOpenApiPresets
|
|
18
|
-
} from "./chunk-MZWZQ24W.js";
|
|
19
|
-
import {
|
|
20
|
-
addOpenApiSpec,
|
|
21
|
-
previewOpenApiSpec
|
|
22
|
-
} from "./chunk-GS5YN6J4.js";
|
|
23
|
-
import {
|
|
24
|
-
resolveServerUrl
|
|
25
|
-
} from "./chunk-RFSMGUBJ.js";
|
|
26
|
-
|
|
27
|
-
// src/react/AddOpenApiSource.tsx
|
|
28
|
-
import { useCallback, useEffect, useMemo as useMemo2, useRef, useState as useState2 } from "react";
|
|
29
|
-
import { useAtomSet } from "@effect/atom-react";
|
|
30
|
-
import * as Effect from "effect/Effect";
|
|
31
|
-
import * as Exit from "effect/Exit";
|
|
32
|
-
import * as Option from "effect/Option";
|
|
33
|
-
import { integrationWriteKeys } from "@executor-js/react/api/reactivity-keys";
|
|
34
|
-
import {
|
|
35
|
-
slugifyNamespace,
|
|
36
|
-
useIntegrationIdentity
|
|
37
|
-
} from "@executor-js/react/plugins/integration-identity";
|
|
38
|
-
import { Button as Button2 } from "@executor-js/react/components/button";
|
|
39
|
-
import {
|
|
40
|
-
AuthMethodListEditor,
|
|
41
|
-
useAuthMethodList
|
|
42
|
-
} from "@executor-js/react/components/auth-method-list-editor";
|
|
43
|
-
import { CardStack as CardStack2, CardStackContent as CardStackContent2 } from "@executor-js/react/components/card-stack";
|
|
44
|
-
import { FieldLabel as FieldLabel2 } from "@executor-js/react/components/field";
|
|
45
|
-
import { FloatActions } from "@executor-js/react/components/float-actions";
|
|
46
|
-
import { Textarea as Textarea2 } from "@executor-js/react/components/textarea";
|
|
47
|
-
import { IOSSpinner, Spinner } from "@executor-js/react/components/spinner";
|
|
48
|
-
import {
|
|
49
|
-
addIntegrationErrorMessage,
|
|
50
|
-
errorMessageFromExit,
|
|
51
|
-
FormErrorAlert,
|
|
52
|
-
SlugCollisionAlert,
|
|
53
|
-
useSlugAlreadyExists
|
|
54
|
-
} from "@executor-js/react/lib/integration-add";
|
|
55
|
-
|
|
56
|
-
// src/react/OpenApiSourceDetailsFields.tsx
|
|
57
|
-
import {
|
|
58
|
-
CardStack,
|
|
59
|
-
CardStackContent,
|
|
60
|
-
CardStackEntry,
|
|
61
|
-
CardStackEntryContent,
|
|
62
|
-
CardStackEntryDescription,
|
|
63
|
-
CardStackEntryField,
|
|
64
|
-
CardStackEntryTitle
|
|
65
|
-
} from "@executor-js/react/components/card-stack";
|
|
66
|
-
import {
|
|
67
|
-
FreeformCombobox
|
|
68
|
-
} from "@executor-js/react/components/combobox";
|
|
69
|
-
import { Input } from "@executor-js/react/components/input";
|
|
70
|
-
import { Textarea } from "@executor-js/react/components/textarea";
|
|
71
|
-
import { IntegrationFavicon } from "@executor-js/react/components/integration-favicon";
|
|
72
|
-
import {
|
|
73
|
-
IntegrationIdentityFieldRows
|
|
74
|
-
} from "@executor-js/react/plugins/integration-identity";
|
|
75
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
76
|
-
var isUrlInput = (value) => URL.canParse(value.trim());
|
|
77
|
-
function OpenApiSourceDetailsFields(props) {
|
|
78
|
-
const specIsUrl = props.specUrl !== void 0 && isUrlInput(props.specUrl);
|
|
79
|
-
return /* @__PURE__ */ jsx(CardStack, { children: /* @__PURE__ */ jsxs(CardStackContent, { className: "border-t-0", children: [
|
|
80
|
-
/* @__PURE__ */ jsxs(CardStackEntry, { children: [
|
|
81
|
-
(props.faviconIcon || props.faviconUrl) && /* @__PURE__ */ jsx(IntegrationFavicon, { icon: props.faviconIcon, url: props.faviconUrl, size: 16 }),
|
|
82
|
-
/* @__PURE__ */ jsxs(CardStackEntryContent, { children: [
|
|
83
|
-
/* @__PURE__ */ jsx(CardStackEntryTitle, { children: props.title }),
|
|
84
|
-
props.subtitle && /* @__PURE__ */ jsx(CardStackEntryDescription, { children: props.subtitle })
|
|
85
|
-
] }),
|
|
86
|
-
props.saveState && props.saveState !== "idle" && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: props.saveState === "saving" ? "Saving\u2026" : "Saved" })
|
|
87
|
-
] }),
|
|
88
|
-
/* @__PURE__ */ jsx(
|
|
89
|
-
IntegrationIdentityFieldRows,
|
|
90
|
-
{
|
|
91
|
-
identity: props.identity,
|
|
92
|
-
namespaceReadOnly: props.namespaceReadOnly
|
|
93
|
-
}
|
|
94
|
-
),
|
|
95
|
-
props.onDescriptionChange && /* @__PURE__ */ jsx(CardStackEntryField, { label: "Description", children: /* @__PURE__ */ jsx(
|
|
96
|
-
Textarea,
|
|
97
|
-
{
|
|
98
|
-
value: props.description ?? "",
|
|
99
|
-
onChange: (e) => props.onDescriptionChange?.(e.target.value),
|
|
100
|
-
placeholder: "What this API is and when to reach for it",
|
|
101
|
-
rows: 2,
|
|
102
|
-
maxRows: 6,
|
|
103
|
-
className: "text-sm"
|
|
104
|
-
}
|
|
105
|
-
) }),
|
|
106
|
-
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2", children: [
|
|
107
|
-
/* @__PURE__ */ jsxs(CardStackEntryField, { label: props.baseUrlLabel ?? "Base URL", children: [
|
|
108
|
-
props.baseUrlOptions && props.baseUrlOptions.length > 0 ? /* @__PURE__ */ jsx(
|
|
109
|
-
FreeformCombobox,
|
|
110
|
-
{
|
|
111
|
-
value: props.baseUrl,
|
|
112
|
-
onValueChange: props.onBaseUrlChange,
|
|
113
|
-
options: props.baseUrlOptions,
|
|
114
|
-
placeholder: props.baseUrlPlaceholder ?? "https://api.example.com",
|
|
115
|
-
className: "w-full",
|
|
116
|
-
inputClassName: "font-mono text-sm"
|
|
117
|
-
}
|
|
118
|
-
) : /* @__PURE__ */ jsx(
|
|
119
|
-
Input,
|
|
120
|
-
{
|
|
121
|
-
value: props.baseUrl,
|
|
122
|
-
onChange: (e) => props.onBaseUrlChange(e.target.value),
|
|
123
|
-
placeholder: props.baseUrlPlaceholder ?? "https://api.example.com",
|
|
124
|
-
className: "font-mono text-sm"
|
|
125
|
-
}
|
|
126
|
-
),
|
|
127
|
-
props.baseUrlMissingMessage && !props.baseUrl && /* @__PURE__ */ jsx("p", { className: "text-[11px] text-amber-600 dark:text-amber-400", children: props.baseUrlMissingMessage }),
|
|
128
|
-
props.baseUrlHint && /* @__PURE__ */ jsx("p", { className: "text-[11px] text-muted-foreground", children: props.baseUrlHint })
|
|
129
|
-
] }),
|
|
130
|
-
specIsUrl && props.onSpecUrlChange && /* @__PURE__ */ jsx(CardStackEntryField, { label: "Spec URL", children: /* @__PURE__ */ jsx(
|
|
131
|
-
Input,
|
|
132
|
-
{
|
|
133
|
-
value: props.specUrl,
|
|
134
|
-
onChange: (e) => props.onSpecUrlChange?.(e.target.value),
|
|
135
|
-
placeholder: "https://api.example.com/openapi.json",
|
|
136
|
-
className: "font-mono text-sm",
|
|
137
|
-
disabled: props.specUrlDisabled
|
|
138
|
-
}
|
|
139
|
-
) })
|
|
140
|
-
] }),
|
|
141
|
-
props.specUrl !== void 0 && !specIsUrl && props.onSpecUrlChange && /* @__PURE__ */ jsx(CardStackEntryField, { label: "Spec", children: /* @__PURE__ */ jsx(
|
|
142
|
-
Textarea,
|
|
143
|
-
{
|
|
144
|
-
value: props.specUrl,
|
|
145
|
-
onChange: (e) => props.onSpecUrlChange?.(e.target.value),
|
|
146
|
-
placeholder: "Pasted OpenAPI JSON/YAML",
|
|
147
|
-
rows: 4,
|
|
148
|
-
maxRows: 12,
|
|
149
|
-
className: "font-mono text-xs",
|
|
150
|
-
disabled: props.specUrlDisabled
|
|
151
|
-
}
|
|
152
|
-
) }),
|
|
153
|
-
props.footer && /* @__PURE__ */ jsx(CardStackEntry, { children: /* @__PURE__ */ jsx(CardStackEntryContent, { children: /* @__PURE__ */ jsx(CardStackEntryTitle, { children: props.footer }) }) })
|
|
154
|
-
] }) });
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// src/react/GoogleProductPicker.tsx
|
|
158
|
-
import { useMemo, useState } from "react";
|
|
159
|
-
import { ChevronDownIcon, PlusIcon, TriangleAlert, XIcon } from "lucide-react";
|
|
160
|
-
import { cn } from "@executor-js/react/lib/utils";
|
|
161
|
-
import { Badge } from "@executor-js/react/components/badge";
|
|
162
|
-
import { Button } from "@executor-js/react/components/button";
|
|
163
|
-
import { Checkbox } from "@executor-js/react/components/checkbox";
|
|
164
|
-
import {
|
|
165
|
-
Collapsible,
|
|
166
|
-
CollapsibleContent,
|
|
167
|
-
CollapsibleTrigger
|
|
168
|
-
} from "@executor-js/react/components/collapsible";
|
|
169
|
-
import { FieldLabel } from "@executor-js/react/components/field";
|
|
170
|
-
import { Input as Input2 } from "@executor-js/react/components/input";
|
|
171
|
-
import { IntegrationFavicon as IntegrationFavicon2 } from "@executor-js/react/components/integration-favicon";
|
|
172
|
-
|
|
173
|
-
// src/sdk/google-oauth-batches.ts
|
|
174
|
-
var GOOGLE_CLOUD_BATCH_IDS = /* @__PURE__ */ new Set(["google-bigquery", "google-cloud-resource-manager"]);
|
|
175
|
-
var googleOAuthConsentBatches = (items) => {
|
|
176
|
-
const standardScopes = [];
|
|
177
|
-
const cloudScopes = [];
|
|
178
|
-
const batches = [];
|
|
179
|
-
for (const item of items) {
|
|
180
|
-
if (item.scopes.length === 0) continue;
|
|
181
|
-
if (item.oauthAudience === "standard-user") {
|
|
182
|
-
standardScopes.push(...item.scopes);
|
|
183
|
-
continue;
|
|
184
|
-
}
|
|
185
|
-
if (GOOGLE_CLOUD_BATCH_IDS.has(item.id)) {
|
|
186
|
-
cloudScopes.push(...item.scopes);
|
|
187
|
-
continue;
|
|
188
|
-
}
|
|
189
|
-
batches.push({
|
|
190
|
-
id: item.id,
|
|
191
|
-
label: item.name,
|
|
192
|
-
apiScopes: item.scopes
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
const compactedStandardScopes = compactGoogleOAuthScopes(standardScopes);
|
|
196
|
-
const compactedCloudScopes = compactGoogleOAuthScopes(cloudScopes);
|
|
197
|
-
return [
|
|
198
|
-
...compactedStandardScopes.length > 0 ? [
|
|
199
|
-
{
|
|
200
|
-
id: "google-core",
|
|
201
|
-
label: "Core Google services",
|
|
202
|
-
apiScopes: compactedStandardScopes
|
|
203
|
-
}
|
|
204
|
-
] : [],
|
|
205
|
-
...batches.map((batch) => ({
|
|
206
|
-
...batch,
|
|
207
|
-
apiScopes: compactGoogleOAuthScopes(batch.apiScopes)
|
|
208
|
-
})),
|
|
209
|
-
...compactedCloudScopes.length > 0 ? [
|
|
210
|
-
{
|
|
211
|
-
id: "google-cloud",
|
|
212
|
-
label: "Google Cloud services",
|
|
213
|
-
apiScopes: compactedCloudScopes
|
|
214
|
-
}
|
|
215
|
-
] : []
|
|
216
|
-
].filter((batch) => batch.apiScopes.length > 0);
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
// src/react/GoogleProductPicker.tsx
|
|
220
|
-
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
221
|
-
var AUDIENCE_ORDER = [
|
|
222
|
-
"standard-user",
|
|
223
|
-
"advanced-user",
|
|
224
|
-
"workspace-admin",
|
|
225
|
-
"unsupported-user"
|
|
226
|
-
];
|
|
227
|
-
var AUDIENCE_LABEL = {
|
|
228
|
-
"standard-user": "Core Google services",
|
|
229
|
-
"advanced-user": "Advanced services",
|
|
230
|
-
"workspace-admin": "Workspace admin",
|
|
231
|
-
"unsupported-user": "Limited user consent"
|
|
232
|
-
};
|
|
233
|
-
var AUDIENCE_DESCRIPTION = {
|
|
234
|
-
"standard-user": "Connect with a normal Google account \u2014 one consent screen.",
|
|
235
|
-
"advanced-user": "Broader scopes that may need an unverified-app warning to be accepted.",
|
|
236
|
-
"workspace-admin": "Requires a Google Workspace admin account; not available on personal Gmail.",
|
|
237
|
-
"unsupported-user": "Google does not grant these scopes through standard user OAuth consent."
|
|
238
|
-
};
|
|
239
|
-
var audienceNeedsWarning = (audience) => audience === "workspace-admin" || audience === "unsupported-user";
|
|
240
|
-
var AudienceWarningChip = ({ audience }) => audience === "workspace-admin" ? /* @__PURE__ */ jsxs2(
|
|
241
|
-
Badge,
|
|
242
|
-
{
|
|
243
|
-
variant: "outline",
|
|
244
|
-
className: "shrink-0 border-amber-500/40 text-amber-700 dark:text-amber-400",
|
|
245
|
-
children: [
|
|
246
|
-
/* @__PURE__ */ jsx2(TriangleAlert, { className: "size-3" }),
|
|
247
|
-
"Admin only"
|
|
248
|
-
]
|
|
249
|
-
}
|
|
250
|
-
) : audience === "unsupported-user" ? /* @__PURE__ */ jsxs2(Badge, { variant: "outline", className: "shrink-0 border-destructive/40 text-destructive", children: [
|
|
251
|
-
/* @__PURE__ */ jsx2(TriangleAlert, { className: "size-3" }),
|
|
252
|
-
"Limited consent"
|
|
253
|
-
] }) : null;
|
|
254
|
-
var ProductRow = ({
|
|
255
|
-
preset,
|
|
256
|
-
checked,
|
|
257
|
-
onToggle
|
|
258
|
-
}) => /* @__PURE__ */ jsxs2(
|
|
259
|
-
FieldLabel,
|
|
260
|
-
{
|
|
261
|
-
className: cn(
|
|
262
|
-
// `w-full` overrides FieldLabel's base `w-fit` (which would size the row to
|
|
263
|
-
// its content and overflow the column); `min-w-0` then lets the cell shrink
|
|
264
|
-
// to its track so the name/summary truncates instead of spilling over.
|
|
265
|
-
"flex w-full min-w-0 cursor-pointer items-center gap-2.5 rounded-md px-2 py-1.5 transition-colors",
|
|
266
|
-
checked ? "bg-primary/5" : "hover:bg-muted/40"
|
|
267
|
-
),
|
|
268
|
-
children: [
|
|
269
|
-
/* @__PURE__ */ jsx2(Checkbox, { checked, onCheckedChange: (next) => onToggle(next === true) }),
|
|
270
|
-
/* @__PURE__ */ jsx2("div", { className: "shrink-0", children: /* @__PURE__ */ jsx2(IntegrationFavicon2, { icon: preset.icon, url: preset.url, size: 16 }) }),
|
|
271
|
-
/* @__PURE__ */ jsxs2("div", { className: "min-w-0 flex-1 truncate text-sm", children: [
|
|
272
|
-
/* @__PURE__ */ jsx2("span", { className: "font-medium text-foreground", children: preset.name }),
|
|
273
|
-
" ",
|
|
274
|
-
/* @__PURE__ */ jsx2("span", { className: "text-[11px] text-muted-foreground", children: preset.summary })
|
|
275
|
-
] }),
|
|
276
|
-
/* @__PURE__ */ jsx2(AudienceWarningChip, { audience: preset.oauthAudience })
|
|
277
|
-
]
|
|
278
|
-
}
|
|
279
|
-
);
|
|
280
|
-
var CustomUrlEscapeHatch = ({
|
|
281
|
-
customUrls,
|
|
282
|
-
onAddCustomUrl,
|
|
283
|
-
onRemoveCustomUrl
|
|
284
|
-
}) => {
|
|
285
|
-
const [draft, setDraft] = useState("");
|
|
286
|
-
const trimmed = draft.trim();
|
|
287
|
-
const isValid = isGoogleDiscoveryUrl(trimmed);
|
|
288
|
-
const isDuplicate = customUrls.includes(trimmed);
|
|
289
|
-
const commit = () => {
|
|
290
|
-
if (!isValid || isDuplicate) return;
|
|
291
|
-
onAddCustomUrl(trimmed);
|
|
292
|
-
setDraft("");
|
|
293
|
-
};
|
|
294
|
-
return /* @__PURE__ */ jsxs2("div", { className: "space-y-2", children: [
|
|
295
|
-
/* @__PURE__ */ jsx2(FieldLabel, { className: "text-[11px] font-medium text-muted-foreground", children: "Add a custom Google Discovery URL" }),
|
|
296
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
|
|
297
|
-
/* @__PURE__ */ jsx2(
|
|
298
|
-
Input2,
|
|
299
|
-
{
|
|
300
|
-
value: draft,
|
|
301
|
-
onChange: (event) => setDraft(event.target.value),
|
|
302
|
-
onKeyDown: (event) => {
|
|
303
|
-
if (event.key === "Enter") {
|
|
304
|
-
event.preventDefault();
|
|
305
|
-
commit();
|
|
306
|
-
}
|
|
307
|
-
},
|
|
308
|
-
placeholder: "https://www.googleapis.com/discovery/v1/apis/<service>/<version>/rest",
|
|
309
|
-
className: "font-mono text-[11px]"
|
|
310
|
-
}
|
|
311
|
-
),
|
|
312
|
-
/* @__PURE__ */ jsxs2(
|
|
313
|
-
Button,
|
|
314
|
-
{
|
|
315
|
-
type: "button",
|
|
316
|
-
variant: "outline",
|
|
317
|
-
size: "sm",
|
|
318
|
-
disabled: !isValid || isDuplicate,
|
|
319
|
-
onClick: commit,
|
|
320
|
-
children: [
|
|
321
|
-
/* @__PURE__ */ jsx2(PlusIcon, { className: "size-3.5" }),
|
|
322
|
-
"Add"
|
|
323
|
-
]
|
|
324
|
-
}
|
|
325
|
-
)
|
|
326
|
-
] }),
|
|
327
|
-
trimmed.length > 0 && !isValid ? /* @__PURE__ */ jsx2("p", { className: "text-[11px] text-destructive", children: "Enter a Google Discovery document URL (a *.googleapis.com discovery/$discovery endpoint)." }) : null,
|
|
328
|
-
customUrls.length > 0 ? /* @__PURE__ */ jsx2("ul", { className: "space-y-1", children: customUrls.map((url) => /* @__PURE__ */ jsxs2(
|
|
329
|
-
"li",
|
|
330
|
-
{
|
|
331
|
-
className: "flex items-center justify-between gap-2 rounded-md border border-border bg-muted/20 px-2.5 py-1.5",
|
|
332
|
-
children: [
|
|
333
|
-
/* @__PURE__ */ jsx2("span", { className: "truncate font-mono text-[11px] text-foreground", children: url }),
|
|
334
|
-
/* @__PURE__ */ jsx2(
|
|
335
|
-
Button,
|
|
336
|
-
{
|
|
337
|
-
type: "button",
|
|
338
|
-
variant: "ghost",
|
|
339
|
-
size: "icon",
|
|
340
|
-
className: "size-6 shrink-0",
|
|
341
|
-
onClick: () => onRemoveCustomUrl(url),
|
|
342
|
-
"aria-label": `Remove ${url}`,
|
|
343
|
-
children: /* @__PURE__ */ jsx2(XIcon, { className: "size-3.5" })
|
|
344
|
-
}
|
|
345
|
-
)
|
|
346
|
-
]
|
|
347
|
-
},
|
|
348
|
-
url
|
|
349
|
-
)) }) : null
|
|
350
|
-
] });
|
|
351
|
-
};
|
|
352
|
-
function GoogleProductPicker({
|
|
353
|
-
selectedPresetIds,
|
|
354
|
-
onToggle,
|
|
355
|
-
customUrls,
|
|
356
|
-
onAddCustomUrl,
|
|
357
|
-
onRemoveCustomUrl
|
|
358
|
-
}) {
|
|
359
|
-
const [scopesOpen, setScopesOpen] = useState(false);
|
|
360
|
-
const groups = useMemo(
|
|
361
|
-
() => AUDIENCE_ORDER.flatMap((audience) => {
|
|
362
|
-
const presets = googleOpenApiPresets.filter(
|
|
363
|
-
(preset) => preset.oauthAudience === audience
|
|
364
|
-
);
|
|
365
|
-
return presets.length > 0 ? [{ audience, presets }] : [];
|
|
366
|
-
}),
|
|
367
|
-
[]
|
|
368
|
-
);
|
|
369
|
-
const consentBatches = useMemo(
|
|
370
|
-
() => googleOAuthConsentBatches(
|
|
371
|
-
googleOpenApiPresets.filter((preset) => selectedPresetIds.has(preset.id)).map((preset) => ({
|
|
372
|
-
id: preset.id,
|
|
373
|
-
name: preset.name,
|
|
374
|
-
oauthAudience: preset.oauthAudience,
|
|
375
|
-
scopes: googleOAuthConsentScopesForPreset(preset.id)
|
|
376
|
-
}))
|
|
377
|
-
),
|
|
378
|
-
[selectedPresetIds]
|
|
379
|
-
);
|
|
380
|
-
const selectedCount = selectedPresetIds.size + customUrls.length;
|
|
381
|
-
return /* @__PURE__ */ jsxs2("section", { className: "space-y-4", children: [
|
|
382
|
-
/* @__PURE__ */ jsxs2("div", { className: "space-y-1", children: [
|
|
383
|
-
/* @__PURE__ */ jsx2(FieldLabel, { children: "Customize your Google connection" }),
|
|
384
|
-
/* @__PURE__ */ jsx2("p", { className: "text-[11px] text-muted-foreground", children: "Pick the Google APIs to bundle into one connection. They share a single OAuth consent and appear as merged tools under one Google integration." })
|
|
385
|
-
] }),
|
|
386
|
-
groups.map(
|
|
387
|
-
({
|
|
388
|
-
audience,
|
|
389
|
-
presets
|
|
390
|
-
}) => /* @__PURE__ */ jsxs2("div", { className: "space-y-2", children: [
|
|
391
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
|
|
392
|
-
/* @__PURE__ */ jsx2("span", { className: "text-[11px] font-semibold tracking-wide text-foreground uppercase", children: AUDIENCE_LABEL[audience] }),
|
|
393
|
-
audienceNeedsWarning(audience) ? /* @__PURE__ */ jsx2(AudienceWarningChip, { audience }) : null,
|
|
394
|
-
/* @__PURE__ */ jsx2(
|
|
395
|
-
Button,
|
|
396
|
-
{
|
|
397
|
-
type: "button",
|
|
398
|
-
variant: "ghost",
|
|
399
|
-
size: "sm",
|
|
400
|
-
className: "ml-auto h-auto px-1.5 py-0.5 text-[11px] font-normal text-muted-foreground hover:bg-transparent hover:text-foreground",
|
|
401
|
-
onClick: () => {
|
|
402
|
-
const allSelected = presets.every(
|
|
403
|
-
(preset) => selectedPresetIds.has(preset.id)
|
|
404
|
-
);
|
|
405
|
-
presets.forEach(
|
|
406
|
-
(preset) => onToggle(preset.id, !allSelected)
|
|
407
|
-
);
|
|
408
|
-
},
|
|
409
|
-
children: presets.every((preset) => selectedPresetIds.has(preset.id)) ? "Clear" : "Select all"
|
|
410
|
-
}
|
|
411
|
-
)
|
|
412
|
-
] }),
|
|
413
|
-
/* @__PURE__ */ jsx2("p", { className: "text-[11px] text-muted-foreground", children: AUDIENCE_DESCRIPTION[audience] }),
|
|
414
|
-
/* @__PURE__ */ jsx2("div", { className: "grid grid-cols-1 gap-x-4 gap-y-0.5 sm:grid-cols-2", children: presets.map((preset) => /* @__PURE__ */ jsx2(
|
|
415
|
-
ProductRow,
|
|
416
|
-
{
|
|
417
|
-
preset,
|
|
418
|
-
checked: selectedPresetIds.has(preset.id),
|
|
419
|
-
onToggle: (checked) => onToggle(preset.id, checked)
|
|
420
|
-
},
|
|
421
|
-
preset.id
|
|
422
|
-
)) })
|
|
423
|
-
] }, audience)
|
|
424
|
-
),
|
|
425
|
-
/* @__PURE__ */ jsx2(
|
|
426
|
-
CustomUrlEscapeHatch,
|
|
427
|
-
{
|
|
428
|
-
customUrls,
|
|
429
|
-
onAddCustomUrl,
|
|
430
|
-
onRemoveCustomUrl
|
|
431
|
-
}
|
|
432
|
-
),
|
|
433
|
-
/* @__PURE__ */ jsxs2("div", { className: "space-y-1.5 rounded-lg border border-border bg-muted/10 px-3 py-2.5", children: [
|
|
434
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
|
|
435
|
-
/* @__PURE__ */ jsx2("span", { className: "text-[11px] font-semibold tracking-wide text-foreground uppercase", children: "Authentication" }),
|
|
436
|
-
/* @__PURE__ */ jsx2(Badge, { variant: "secondary", children: "OAuth" })
|
|
437
|
-
] }),
|
|
438
|
-
/* @__PURE__ */ jsx2("p", { className: "text-[11px] text-muted-foreground", children: "The selected Google APIs share one OAuth consent. Review the scopes below, then connect a Google account from the integration page after adding." })
|
|
439
|
-
] }),
|
|
440
|
-
/* @__PURE__ */ jsxs2(Collapsible, { open: scopesOpen, onOpenChange: setScopesOpen, children: [
|
|
441
|
-
/* @__PURE__ */ jsx2(CollapsibleTrigger, { asChild: true, children: /* @__PURE__ */ jsxs2(Button, { type: "button", variant: "outline", size: "sm", disabled: consentBatches.length === 0, children: [
|
|
442
|
-
/* @__PURE__ */ jsx2(
|
|
443
|
-
ChevronDownIcon,
|
|
444
|
-
{
|
|
445
|
-
className: cn("size-3.5 transition-transform", scopesOpen ? "rotate-180" : "")
|
|
446
|
-
}
|
|
447
|
-
),
|
|
448
|
-
"View scopes",
|
|
449
|
-
selectedCount > 0 ? /* @__PURE__ */ jsx2(Badge, { variant: "secondary", className: "ml-1", children: selectedCount }) : null
|
|
450
|
-
] }) }),
|
|
451
|
-
/* @__PURE__ */ jsx2(CollapsibleContent, { className: "pt-3", children: consentBatches.length === 0 ? /* @__PURE__ */ jsx2("p", { className: "text-[11px] text-muted-foreground", children: "Select at least one Google API to preview the OAuth consent." }) : /* @__PURE__ */ jsx2("div", { className: "space-y-3", children: consentBatches.map((batch) => /* @__PURE__ */ jsxs2("div", { className: "space-y-1.5", children: [
|
|
452
|
-
/* @__PURE__ */ jsx2("span", { className: "text-[11px] font-semibold text-foreground", children: batch.label }),
|
|
453
|
-
/* @__PURE__ */ jsx2("ul", { className: "space-y-1", children: batch.apiScopes.map((scope) => /* @__PURE__ */ jsx2(
|
|
454
|
-
"li",
|
|
455
|
-
{
|
|
456
|
-
className: "rounded-md border border-border bg-muted/20 px-2.5 py-1 font-mono text-[11px] break-all text-muted-foreground",
|
|
457
|
-
children: scope
|
|
458
|
-
},
|
|
459
|
-
scope
|
|
460
|
-
)) })
|
|
461
|
-
] }, batch.id)) }) })
|
|
462
|
-
] })
|
|
463
|
-
] });
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
// src/react/AddOpenApiSource.tsx
|
|
467
|
-
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
468
|
-
var GOOGLE_BUNDLE_FAVICON = "https://fonts.gstatic.com/s/i/productlogos/googleg/v6/192px.svg";
|
|
469
|
-
var googleBundleDefaultPresetIds = new Set(
|
|
470
|
-
googleOpenApiPresets.filter((preset) => preset.featured).map((preset) => preset.id)
|
|
471
|
-
);
|
|
472
|
-
var googleBundleUrls = (selectedPresetIds, customUrls) => {
|
|
473
|
-
const fromPresets = googleOpenApiPresets.flatMap(
|
|
474
|
-
(preset) => preset.url && selectedPresetIds.has(preset.id) ? [preset.url] : []
|
|
475
|
-
);
|
|
476
|
-
return [.../* @__PURE__ */ new Set([...fromPresets, ...customUrls])];
|
|
477
|
-
};
|
|
478
|
-
var isGoogleDiscoveryUrl2 = (url) => {
|
|
479
|
-
const trimmed = url.trim();
|
|
480
|
-
if (!URL.canParse(trimmed)) return false;
|
|
481
|
-
const parsed = new URL(trimmed);
|
|
482
|
-
const host = parsed.hostname.toLowerCase();
|
|
483
|
-
if (!host.endsWith("googleapis.com")) return false;
|
|
484
|
-
return parsed.pathname.includes("/discovery/") || parsed.pathname.includes("$discovery");
|
|
485
|
-
};
|
|
486
|
-
var normalizePresetUrl = (url) => {
|
|
487
|
-
const trimmed = url.trim();
|
|
488
|
-
if (!URL.canParse(trimmed)) return trimmed.replace(/\/$/, "");
|
|
489
|
-
const parsed = new URL(trimmed);
|
|
490
|
-
parsed.hash = "";
|
|
491
|
-
parsed.searchParams.sort();
|
|
492
|
-
return parsed.toString().replace(/\/$/, "");
|
|
493
|
-
};
|
|
494
|
-
var specInputForAdd = (input) => {
|
|
495
|
-
const value = input.trim();
|
|
496
|
-
const parsed = Effect.runSyncExit(
|
|
497
|
-
Effect.try({
|
|
498
|
-
try: () => new URL(value),
|
|
499
|
-
catch: () => null
|
|
500
|
-
})
|
|
501
|
-
);
|
|
502
|
-
return Exit.isSuccess(parsed) ? isGoogleDiscoveryUrl2(value) ? { kind: "googleDiscovery", url: value } : { kind: "url", url: value } : { kind: "blob", value };
|
|
503
|
-
};
|
|
504
|
-
function AddOpenApiSource(props) {
|
|
505
|
-
const isGoogleBundlePreset = props.initialPreset === GOOGLE_BUNDLE_PRESET_ID;
|
|
506
|
-
const [specUrl, setSpecUrl] = useState2(props.initialUrl ?? "");
|
|
507
|
-
const [selectedPresetIds, setSelectedPresetIds] = useState2(
|
|
508
|
-
googleBundleDefaultPresetIds
|
|
509
|
-
);
|
|
510
|
-
const [customDiscoveryUrls, setCustomDiscoveryUrls] = useState2([]);
|
|
511
|
-
const [analyzing, setAnalyzing] = useState2(false);
|
|
512
|
-
const [analyzeError, setAnalyzeError] = useState2(null);
|
|
513
|
-
const [preview, setPreview] = useState2(null);
|
|
514
|
-
const [baseUrl, setBaseUrl] = useState2("");
|
|
515
|
-
const [descriptionDraft, setDescriptionDraft] = useState2(null);
|
|
516
|
-
const identityFallbackName = isGoogleBundlePreset ? "Google" : preview ? Option.getOrElse(preview.title, () => "") : "";
|
|
517
|
-
const identity = useIntegrationIdentity({
|
|
518
|
-
fallbackName: identityFallbackName,
|
|
519
|
-
fallbackNamespace: props.initialNamespace ?? (isGoogleBundlePreset ? "google" : void 0)
|
|
520
|
-
});
|
|
521
|
-
const bundleDiscoveryUrls = useMemo2(
|
|
522
|
-
() => googleBundleUrls(selectedPresetIds, customDiscoveryUrls),
|
|
523
|
-
[selectedPresetIds, customDiscoveryUrls]
|
|
524
|
-
);
|
|
525
|
-
const toggleBundlePreset = useCallback((presetId, checked) => {
|
|
526
|
-
setSelectedPresetIds((current) => {
|
|
527
|
-
const next = new Set(current);
|
|
528
|
-
if (checked) next.add(presetId);
|
|
529
|
-
else next.delete(presetId);
|
|
530
|
-
return next;
|
|
531
|
-
});
|
|
532
|
-
}, []);
|
|
533
|
-
const addCustomDiscoveryUrl = useCallback((url) => {
|
|
534
|
-
setCustomDiscoveryUrls(
|
|
535
|
-
(current) => current.includes(url) ? current : [...current, url]
|
|
536
|
-
);
|
|
537
|
-
}, []);
|
|
538
|
-
const removeCustomDiscoveryUrl = useCallback((url) => {
|
|
539
|
-
setCustomDiscoveryUrls(
|
|
540
|
-
(current) => current.filter((entry) => entry !== url)
|
|
541
|
-
);
|
|
542
|
-
}, []);
|
|
543
|
-
const [adding, setAdding] = useState2(false);
|
|
544
|
-
const [addError, setAddError] = useState2(null);
|
|
545
|
-
const doPreview = useAtomSet(previewOpenApiSpec, { mode: "promiseExit" });
|
|
546
|
-
const doAdd = useAtomSet(addOpenApiSpec, { mode: "promiseExit" });
|
|
547
|
-
const handleAnalyzeRef = useRef(() => {
|
|
548
|
-
});
|
|
549
|
-
useEffect(() => {
|
|
550
|
-
if (isGoogleBundlePreset) return;
|
|
551
|
-
const trimmed = specUrl.trim();
|
|
552
|
-
if (!trimmed) return;
|
|
553
|
-
if (preview) return;
|
|
554
|
-
const handle = setTimeout(() => {
|
|
555
|
-
handleAnalyzeRef.current();
|
|
556
|
-
}, 400);
|
|
557
|
-
return () => clearTimeout(handle);
|
|
558
|
-
}, [specUrl, preview, isGoogleBundlePreset]);
|
|
559
|
-
const previewHasNoServers = preview !== null && preview.servers.length === 0;
|
|
560
|
-
const baseUrlOptions = preview && preview.servers.length > 1 ? preview.servers.map((server) => {
|
|
561
|
-
const url = resolveServerUrl(server.url, Option.getOrUndefined(server.variables), {});
|
|
562
|
-
return { value: url, label: url };
|
|
563
|
-
}) : void 0;
|
|
564
|
-
const firstServer = preview?.servers[0];
|
|
565
|
-
const firstServerUrl = firstServer ? resolveServerUrl(firstServer.url, Option.getOrUndefined(firstServer.variables), {}) : "";
|
|
566
|
-
const previewPresetIcon = openApiPresets.find(
|
|
567
|
-
(preset) => preset.url && normalizePresetUrl(preset.url) === normalizePresetUrl(specUrl)
|
|
568
|
-
)?.icon ?? null;
|
|
569
|
-
const resolvedBaseUrl = baseUrl.trim();
|
|
570
|
-
const resolvedSourceId = slugifyNamespace(identity.namespace) || (preview ? Option.getOrElse(preview.title, () => "openapi") : "openapi");
|
|
571
|
-
const resolvedDisplayName = identity.name.trim() || (preview ? Option.getOrElse(preview.title, () => resolvedSourceId) : resolvedSourceId);
|
|
572
|
-
const resolvedDescription = descriptionDraft ?? (preview ? Option.getOrElse(preview.description, () => "") : "");
|
|
573
|
-
const authenticationTemplate = useMemo2(
|
|
574
|
-
() => detectedAuthenticationTemplates(
|
|
575
|
-
preview?.headerPresets ?? [],
|
|
576
|
-
preview?.oauth2Presets ?? [],
|
|
577
|
-
resolvedBaseUrl
|
|
578
|
-
),
|
|
579
|
-
[preview, resolvedBaseUrl]
|
|
580
|
-
);
|
|
581
|
-
const authMethodSeeds = useMemo2(() => {
|
|
582
|
-
const labels = [
|
|
583
|
-
...(preview?.headerPresets ?? []).map((preset) => preset.label),
|
|
584
|
-
...(preview?.oauth2Presets ?? []).map((preset) => preset.label)
|
|
585
|
-
];
|
|
586
|
-
return authenticationTemplate.map(
|
|
587
|
-
(template, index) => ({
|
|
588
|
-
value: editorValueFromAuthentication(template),
|
|
589
|
-
slug: String(template.slug),
|
|
590
|
-
...labels[index] !== void 0 ? { label: labels[index] } : {}
|
|
591
|
-
})
|
|
592
|
-
);
|
|
593
|
-
}, [preview, authenticationTemplate]);
|
|
594
|
-
const authMethodList = useAuthMethodList(authMethodSeeds);
|
|
595
|
-
const editedAuthenticationTemplate = useMemo2(() => {
|
|
596
|
-
const templates = [];
|
|
597
|
-
authMethodList.rows.forEach((row, index) => {
|
|
598
|
-
const slug = row.seedSlug ?? (row.value.kind === "oauth" ? `oauth-${index}` : `apikey-${index}`);
|
|
599
|
-
const template = authenticationFromEditorValue(row.value, slug);
|
|
600
|
-
if (template !== null) templates.push(template);
|
|
601
|
-
});
|
|
602
|
-
return templates;
|
|
603
|
-
}, [authMethodList.rows]);
|
|
604
|
-
const slugAlreadyExists = useSlugAlreadyExists(resolvedSourceId);
|
|
605
|
-
const hasPreviewOrBundle = isGoogleBundlePreset ? bundleDiscoveryUrls.length > 0 : preview !== null;
|
|
606
|
-
const canAdd = hasPreviewOrBundle && !slugAlreadyExists && (!previewHasNoServers || resolvedBaseUrl.length > 0);
|
|
607
|
-
const handleAnalyze = async () => {
|
|
608
|
-
setAnalyzing(true);
|
|
609
|
-
setAnalyzeError(null);
|
|
610
|
-
setAddError(null);
|
|
611
|
-
const exit = await doPreview({ payload: { spec: specUrl } });
|
|
612
|
-
if (Exit.isFailure(exit)) {
|
|
613
|
-
setAnalyzeError(errorMessageFromExit(exit, "Failed to parse spec"));
|
|
614
|
-
setAnalyzing(false);
|
|
615
|
-
return;
|
|
616
|
-
}
|
|
617
|
-
const result = exit.value;
|
|
618
|
-
setPreview(result);
|
|
619
|
-
setBaseUrl("");
|
|
620
|
-
setAnalyzing(false);
|
|
621
|
-
};
|
|
622
|
-
handleAnalyzeRef.current = handleAnalyze;
|
|
623
|
-
const ensureIntegration = useCallback(async () => {
|
|
624
|
-
const specForAdd = isGoogleBundlePreset ? { kind: "googleDiscoveryBundle", urls: [...bundleDiscoveryUrls] } : specInputForAdd(specUrl);
|
|
625
|
-
const exit = await doAdd({
|
|
626
|
-
payload: {
|
|
627
|
-
spec: specForAdd,
|
|
628
|
-
slug: resolvedSourceId,
|
|
629
|
-
name: resolvedDisplayName,
|
|
630
|
-
...resolvedDescription.trim().length > 0 ? { description: resolvedDescription.trim() } : {},
|
|
631
|
-
baseUrl: resolvedBaseUrl,
|
|
632
|
-
// Always send the edited method list (even empty) when the user has
|
|
633
|
-
// inspected a preview: an explicit [] means "no auth methods", while
|
|
634
|
-
// OMITTING the field tells the server to derive defaults from the
|
|
635
|
-
// spec — which would silently resurrect methods the user deleted.
|
|
636
|
-
// The Google bundle path stays omitted; its auth is converter-derived
|
|
637
|
-
// server-side.
|
|
638
|
-
...!isGoogleBundlePreset ? {
|
|
639
|
-
// Serialize to the wire input dialect (apikey → request-shaped).
|
|
640
|
-
authenticationTemplate: editedAuthenticationTemplate.map(openApiWireAuthInput)
|
|
641
|
-
} : {}
|
|
642
|
-
},
|
|
643
|
-
reactivityKeys: integrationWriteKeys
|
|
644
|
-
});
|
|
645
|
-
if (Exit.isFailure(exit)) {
|
|
646
|
-
setAddError(addIntegrationErrorMessage(exit, resolvedSourceId, "Failed to add integration"));
|
|
647
|
-
return null;
|
|
648
|
-
}
|
|
649
|
-
return exit.value.slug;
|
|
650
|
-
}, [
|
|
651
|
-
isGoogleBundlePreset,
|
|
652
|
-
bundleDiscoveryUrls,
|
|
653
|
-
specUrl,
|
|
654
|
-
doAdd,
|
|
655
|
-
resolvedSourceId,
|
|
656
|
-
resolvedDisplayName,
|
|
657
|
-
resolvedDescription,
|
|
658
|
-
resolvedBaseUrl,
|
|
659
|
-
editedAuthenticationTemplate
|
|
660
|
-
]);
|
|
661
|
-
const handleAdd = async () => {
|
|
662
|
-
setAdding(true);
|
|
663
|
-
setAddError(null);
|
|
664
|
-
const integration = await ensureIntegration();
|
|
665
|
-
if (!integration) {
|
|
666
|
-
setAdding(false);
|
|
667
|
-
return;
|
|
668
|
-
}
|
|
669
|
-
props.onComplete(String(integration));
|
|
670
|
-
};
|
|
671
|
-
return /* @__PURE__ */ jsxs3("div", { className: "flex flex-1 flex-col gap-6", children: [
|
|
672
|
-
/* @__PURE__ */ jsxs3("div", { children: [
|
|
673
|
-
/* @__PURE__ */ jsx3("h1", { className: "text-xl font-semibold text-foreground", children: isGoogleBundlePreset ? "Add Google" : "Add OpenAPI Integration" }),
|
|
674
|
-
isGoogleBundlePreset ? /* @__PURE__ */ jsx3("p", { className: "mt-1 text-[13px] text-muted-foreground", children: "Bundle Google APIs into one integration from their Discovery documents and register their methods as tools under a single shared OAuth consent." }) : null
|
|
675
|
-
] }),
|
|
676
|
-
isGoogleBundlePreset ? /* @__PURE__ */ jsx3(
|
|
677
|
-
GoogleProductPicker,
|
|
678
|
-
{
|
|
679
|
-
selectedPresetIds,
|
|
680
|
-
onToggle: toggleBundlePreset,
|
|
681
|
-
customUrls: customDiscoveryUrls,
|
|
682
|
-
onAddCustomUrl: addCustomDiscoveryUrl,
|
|
683
|
-
onRemoveCustomUrl: removeCustomDiscoveryUrl
|
|
684
|
-
}
|
|
685
|
-
) : !preview ? /* @__PURE__ */ jsx3(CardStack2, { children: /* @__PURE__ */ jsx3(CardStackContent2, { className: "border-t-0", children: /* @__PURE__ */ jsxs3("div", { className: "space-y-2 p-3", children: [
|
|
686
|
-
/* @__PURE__ */ jsx3(FieldLabel2, { children: "OpenAPI Spec" }),
|
|
687
|
-
/* @__PURE__ */ jsxs3("div", { className: "relative", children: [
|
|
688
|
-
/* @__PURE__ */ jsx3(
|
|
689
|
-
Textarea2,
|
|
690
|
-
{
|
|
691
|
-
value: specUrl,
|
|
692
|
-
onChange: (e) => setSpecUrl(e.target.value),
|
|
693
|
-
placeholder: "https://api.example.com/openapi.json",
|
|
694
|
-
rows: 3,
|
|
695
|
-
maxRows: 10,
|
|
696
|
-
className: "font-mono text-sm"
|
|
697
|
-
}
|
|
698
|
-
),
|
|
699
|
-
analyzing && /* @__PURE__ */ jsx3("div", { className: "pointer-events-none absolute right-2 top-2", children: /* @__PURE__ */ jsx3(IOSSpinner, { className: "size-4" }) })
|
|
700
|
-
] }),
|
|
701
|
-
/* @__PURE__ */ jsx3("p", { className: "text-[11px] text-muted-foreground", children: "Paste a URL or raw JSON/YAML content." })
|
|
702
|
-
] }) }) }) : null,
|
|
703
|
-
isGoogleBundlePreset ? /* @__PURE__ */ jsx3(
|
|
704
|
-
OpenApiSourceDetailsFields,
|
|
705
|
-
{
|
|
706
|
-
title: "Google",
|
|
707
|
-
subtitle: `${bundleDiscoveryUrls.length} Google API${bundleDiscoveryUrls.length !== 1 ? "s" : ""} \xB7 one shared OAuth consent`,
|
|
708
|
-
identity,
|
|
709
|
-
description: resolvedDescription,
|
|
710
|
-
onDescriptionChange: setDescriptionDraft,
|
|
711
|
-
baseUrl: resolvedBaseUrl,
|
|
712
|
-
onBaseUrlChange: setBaseUrl,
|
|
713
|
-
baseUrlLabel: "Base URL override (optional)",
|
|
714
|
-
faviconIcon: GOOGLE_BUNDLE_FAVICON,
|
|
715
|
-
faviconUrl: resolvedBaseUrl
|
|
716
|
-
}
|
|
717
|
-
) : preview ? /* @__PURE__ */ jsx3(
|
|
718
|
-
OpenApiSourceDetailsFields,
|
|
719
|
-
{
|
|
720
|
-
title: Option.getOrElse(preview.title, () => "API"),
|
|
721
|
-
subtitle: `${Option.getOrElse(preview.version, () => "")}${Option.isSome(preview.version) ? " \xB7 " : ""}${preview.operationCount} operation${preview.operationCount !== 1 ? "s" : ""}${preview.tags.length > 0 ? ` \xB7 ${preview.tags.length} tag${preview.tags.length !== 1 ? "s" : ""}` : ""}`,
|
|
722
|
-
identity,
|
|
723
|
-
description: resolvedDescription,
|
|
724
|
-
onDescriptionChange: setDescriptionDraft,
|
|
725
|
-
baseUrl: resolvedBaseUrl,
|
|
726
|
-
onBaseUrlChange: setBaseUrl,
|
|
727
|
-
baseUrlOptions,
|
|
728
|
-
baseUrlLabel: previewHasNoServers ? "Base URL" : "Base URL override (optional)",
|
|
729
|
-
baseUrlPlaceholder: firstServerUrl || "https://api.example.com",
|
|
730
|
-
baseUrlHint: previewHasNoServers ? void 0 : "Overrides the spec's servers; leave empty to choose the server (and variables) per tool call.",
|
|
731
|
-
baseUrlMissingMessage: previewHasNoServers ? "This spec declares no servers \u2014 enter a base URL." : void 0,
|
|
732
|
-
specUrl,
|
|
733
|
-
onSpecUrlChange: (value) => {
|
|
734
|
-
setSpecUrl(value);
|
|
735
|
-
setPreview(null);
|
|
736
|
-
setBaseUrl("");
|
|
737
|
-
},
|
|
738
|
-
faviconIcon: previewPresetIcon,
|
|
739
|
-
faviconUrl: resolvedBaseUrl || firstServerUrl
|
|
740
|
-
}
|
|
741
|
-
) : null,
|
|
742
|
-
analyzeError && /* @__PURE__ */ jsx3(FormErrorAlert, { message: analyzeError }),
|
|
743
|
-
preview && !isGoogleBundlePreset && /* @__PURE__ */ jsx3(
|
|
744
|
-
AuthMethodListEditor,
|
|
745
|
-
{
|
|
746
|
-
list: authMethodList,
|
|
747
|
-
emptyHint: "No authentication detected. Add a method, or add the integration without auth and connect an account from the integration page later.",
|
|
748
|
-
footerHint: "Every method here is registered with the integration. Connect an account from the integration page after adding."
|
|
749
|
-
}
|
|
750
|
-
),
|
|
751
|
-
hasPreviewOrBundle && slugAlreadyExists && !adding && /* @__PURE__ */ jsx3(SlugCollisionAlert, { slug: resolvedSourceId }),
|
|
752
|
-
addError && /* @__PURE__ */ jsx3(FormErrorAlert, { message: addError }),
|
|
753
|
-
/* @__PURE__ */ jsxs3(FloatActions, { children: [
|
|
754
|
-
/* @__PURE__ */ jsx3(Button2, { variant: "ghost", onClick: () => props.onCancel(), disabled: adding, children: "Cancel" }),
|
|
755
|
-
(hasPreviewOrBundle || isGoogleBundlePreset) && /* @__PURE__ */ jsxs3(Button2, { onClick: () => void handleAdd(), disabled: !canAdd || adding, children: [
|
|
756
|
-
adding && /* @__PURE__ */ jsx3(Spinner, { className: "size-3.5" }),
|
|
757
|
-
adding ? "Adding\u2026" : isGoogleBundlePreset ? "Connect Google" : "Add integration"
|
|
758
|
-
] })
|
|
759
|
-
] })
|
|
760
|
-
] });
|
|
761
|
-
}
|
|
762
|
-
export {
|
|
763
|
-
AddOpenApiSource as default
|
|
764
|
-
};
|
|
765
|
-
//# sourceMappingURL=AddOpenApiSource-7TI5XUUY.js.map
|