@executor-js/plugin-openapi 1.4.32 → 1.5.0
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-7M52SRUX.js +893 -0
- package/dist/AddOpenApiSource-7M52SRUX.js.map +1 -0
- package/dist/EditOpenApiSource-WTAMRJUK.js +68 -0
- package/dist/EditOpenApiSource-WTAMRJUK.js.map +1 -0
- package/dist/OpenApiAccountsPanel-3VJJXNQF.js +112 -0
- package/dist/OpenApiAccountsPanel-3VJJXNQF.js.map +1 -0
- package/dist/api/group.d.ts +104 -225
- package/dist/api/index.d.ts +127 -271
- package/dist/{chunk-BB5IAKRG.js → chunk-AQ7JDDRM.js} +12 -2
- package/dist/chunk-AQ7JDDRM.js.map +1 -0
- package/dist/chunk-BSLE6HCE.js +181 -0
- package/dist/chunk-BSLE6HCE.js.map +1 -0
- package/dist/chunk-MZWZQ24W.js +226 -0
- package/dist/chunk-MZWZQ24W.js.map +1 -0
- package/dist/chunk-OSIFYIQP.js +623 -0
- package/dist/chunk-OSIFYIQP.js.map +1 -0
- package/dist/chunk-QSSRVK6M.js +139 -0
- package/dist/chunk-QSSRVK6M.js.map +1 -0
- package/dist/chunk-V7VCHYOY.js +1544 -0
- package/dist/chunk-V7VCHYOY.js.map +1 -0
- package/dist/{chunk-AN4HJFNP.js → chunk-YVRI7KRC.js} +162 -186
- package/dist/chunk-YVRI7KRC.js.map +1 -0
- package/dist/client.js +9 -8
- package/dist/client.js.map +1 -1
- package/dist/core.js +28 -11
- package/dist/index.js +11 -4
- package/dist/react/AddOpenApiSource.d.ts +2 -13
- package/dist/react/GoogleProductPicker.d.ts +9 -0
- package/dist/react/OpenApiAccountsPanel.d.ts +6 -0
- package/dist/react/OpenApiSourceDetailsFields.d.ts +3 -2
- package/dist/react/atoms.d.ts +177 -192
- package/dist/react/auth-method-config.d.ts +15 -0
- package/dist/react/client.d.ts +103 -224
- package/dist/react/index.d.ts +2 -2
- package/dist/react/source-plugin.d.ts +2 -2
- package/dist/sdk/config.d.ts +75 -0
- package/dist/sdk/configure.test.d.ts +1 -0
- package/dist/sdk/describe-auth-methods.test.d.ts +1 -0
- package/dist/sdk/errors.d.ts +4 -6
- package/dist/sdk/extract.d.ts +7 -5
- package/dist/sdk/google-bundle.test.d.ts +1 -0
- package/dist/sdk/google-discovery.d.ts +43 -0
- package/dist/sdk/google-discovery.test.d.ts +1 -0
- package/dist/sdk/google-oauth-batches.d.ts +13 -0
- package/dist/sdk/google-oauth-batches.test.d.ts +1 -0
- package/dist/sdk/google-oauth-scopes.d.ts +3 -0
- package/dist/sdk/google-oauth-scopes.test.d.ts +1 -0
- package/dist/sdk/google-presets.d.ts +16 -0
- package/dist/sdk/google-presets.test.d.ts +1 -0
- package/dist/sdk/google-product-picker-scopes.test.d.ts +1 -0
- package/dist/sdk/index.d.ts +7 -5
- package/dist/sdk/invoke.d.ts +6 -9
- package/dist/sdk/openapi-utils.d.ts +1 -0
- package/dist/sdk/plugin.d.ts +74 -231
- package/dist/sdk/presets.d.ts +2 -1
- package/dist/sdk/preview.d.ts +20 -15
- package/dist/sdk/query-serialization.test.d.ts +1 -0
- package/dist/sdk/store.d.ts +14 -41
- package/dist/sdk/types.d.ts +23 -51
- package/dist/testing/index.d.ts +49 -38
- package/dist/testing.js +46 -18
- package/dist/testing.js.map +1 -1
- package/package.json +6 -4
- package/dist/AddOpenApiSource-NSCULGTM.js +0 -19
- package/dist/AddOpenApiSource-NSCULGTM.js.map +0 -1
- package/dist/EditOpenApiSource-MV7NYTRP.js +0 -774
- package/dist/EditOpenApiSource-MV7NYTRP.js.map +0 -1
- package/dist/OpenApiSourceSummary-7JBS7PUV.js +0 -122
- package/dist/OpenApiSourceSummary-7JBS7PUV.js.map +0 -1
- package/dist/chunk-2ZKKZYZH.js +0 -1181
- package/dist/chunk-2ZKKZYZH.js.map +0 -1
- package/dist/chunk-AN4HJFNP.js.map +0 -1
- package/dist/chunk-BB5IAKRG.js.map +0 -1
- package/dist/chunk-PS5XP3DG.js +0 -2086
- package/dist/chunk-PS5XP3DG.js.map +0 -1
- package/dist/chunk-X5JX3KTA.js +0 -201
- package/dist/chunk-X5JX3KTA.js.map +0 -1
- package/dist/react/OpenApiSourceSummary.d.ts +0 -5
- package/dist/sdk/credential-status.d.ts +0 -23
- package/dist/sdk/source-contracts.d.ts +0 -55
- /package/dist/{sdk/credential-status.test.d.ts → react/auth-method-config.test.d.ts} +0 -0
|
@@ -1,774 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
OPENAPI_OAUTH_CALLBACK_PATH,
|
|
3
|
-
OPENAPI_OAUTH_POPUP_NAME,
|
|
4
|
-
OpenApiSourceDetailsFields,
|
|
5
|
-
inferOAuthIssuerUrl,
|
|
6
|
-
resolveOAuthUrl
|
|
7
|
-
} from "./chunk-2ZKKZYZH.js";
|
|
8
|
-
import {
|
|
9
|
-
openApiSourceAtom,
|
|
10
|
-
openApiSourceBindingsAtom
|
|
11
|
-
} from "./chunk-X5JX3KTA.js";
|
|
12
|
-
import {
|
|
13
|
-
OAuth2SourceConfig,
|
|
14
|
-
oauth2ClientSecretSlot
|
|
15
|
-
} from "./chunk-AN4HJFNP.js";
|
|
16
|
-
|
|
17
|
-
// src/react/EditOpenApiSource.tsx
|
|
18
|
-
import { useEffect, useMemo, useRef, useState } from "react";
|
|
19
|
-
import { useAtomSet, useAtomValue } from "@effect/atom-react";
|
|
20
|
-
import * as Exit from "effect/Exit";
|
|
21
|
-
import * as Option from "effect/Option";
|
|
22
|
-
import * as Schema from "effect/Schema";
|
|
23
|
-
import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
|
|
24
|
-
import {
|
|
25
|
-
connectionsAtom,
|
|
26
|
-
configureSource,
|
|
27
|
-
setSourceCredentialBinding,
|
|
28
|
-
sourceAtom,
|
|
29
|
-
startOAuth
|
|
30
|
-
} from "@executor-js/react/api/atoms";
|
|
31
|
-
import { useScope, useUserScope } from "@executor-js/react/api/scope-context";
|
|
32
|
-
import { connectionWriteKeys, sourceWriteKeys } from "@executor-js/react/api/reactivity-keys";
|
|
33
|
-
import { Button } from "@executor-js/react/components/button";
|
|
34
|
-
import { CopyButton } from "@executor-js/react/components/copy-button";
|
|
35
|
-
import {
|
|
36
|
-
CardStack,
|
|
37
|
-
CardStackContent,
|
|
38
|
-
CardStackEntry,
|
|
39
|
-
CardStackEntryContent,
|
|
40
|
-
CardStackEntryDescription,
|
|
41
|
-
CardStackEntryTitle,
|
|
42
|
-
CardStackEntryField
|
|
43
|
-
} from "@executor-js/react/components/card-stack";
|
|
44
|
-
import { FieldLabel } from "@executor-js/react/components/field";
|
|
45
|
-
import { HelpTooltip } from "@executor-js/react/components/help-tooltip";
|
|
46
|
-
import { Input } from "@executor-js/react/components/input";
|
|
47
|
-
import { sourceWriteKeys as openApiWriteKeys } from "@executor-js/react/api/reactivity-keys";
|
|
48
|
-
import {
|
|
49
|
-
ConnectionId,
|
|
50
|
-
ScopeId,
|
|
51
|
-
SetSourceCredentialBindingInput
|
|
52
|
-
} from "@executor-js/sdk/shared";
|
|
53
|
-
import { useSecretPickerSecrets } from "@executor-js/react/plugins/use-secret-picker-secrets";
|
|
54
|
-
import {
|
|
55
|
-
oauthCallbackUrl,
|
|
56
|
-
useOAuthPopupFlow
|
|
57
|
-
} from "@executor-js/react/plugins/oauth-sign-in";
|
|
58
|
-
import {
|
|
59
|
-
CredentialControlField,
|
|
60
|
-
CredentialScopeDropdown,
|
|
61
|
-
CredentialUsageRow
|
|
62
|
-
} from "@executor-js/react/plugins/credential-target-scope";
|
|
63
|
-
import {
|
|
64
|
-
effectiveCredentialBindingForScope,
|
|
65
|
-
exactCredentialBindingForScope,
|
|
66
|
-
isConnectionCredentialBindingValue,
|
|
67
|
-
isSecretCredentialBindingValue
|
|
68
|
-
} from "@executor-js/react/plugins/credential-bindings";
|
|
69
|
-
import { SecretCredentialSlotBindings } from "@executor-js/react/plugins/credential-slot-bindings";
|
|
70
|
-
import {
|
|
71
|
-
useSourceCredentialBindingScopes,
|
|
72
|
-
useSourceCredentialBindingWriter
|
|
73
|
-
} from "@executor-js/react/plugins/source-credential-bindings";
|
|
74
|
-
import { CreatableSecretPicker } from "@executor-js/react/plugins/secret-header-auth";
|
|
75
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
76
|
-
var ErrorMessage = Schema.Struct({ message: Schema.String });
|
|
77
|
-
var decodeErrorMessage = Schema.decodeUnknownOption(ErrorMessage);
|
|
78
|
-
var errorMessageFromExit = (exit, fallback) => Option.match(Option.flatMap(Exit.findErrorOption(exit), decodeErrorMessage), {
|
|
79
|
-
onNone: () => fallback,
|
|
80
|
-
onSome: ({ message }) => message
|
|
81
|
-
});
|
|
82
|
-
var slugify = (value) => value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "default";
|
|
83
|
-
var shortHash = (value) => {
|
|
84
|
-
let hash = 2166136261;
|
|
85
|
-
for (let i = 0; i < value.length; i++) {
|
|
86
|
-
hash ^= value.charCodeAt(i);
|
|
87
|
-
hash = Math.imul(hash, 16777619);
|
|
88
|
-
}
|
|
89
|
-
return (hash >>> 0).toString(36).slice(0, 6);
|
|
90
|
-
};
|
|
91
|
-
var openApiOAuthConnectionId = (sourceId, securitySchemeName, targetScope) => ConnectionId.make(
|
|
92
|
-
`openapi-oauth-${slugify(sourceId)}-${slugify(securitySchemeName)}-${shortHash(targetScope)}`
|
|
93
|
-
);
|
|
94
|
-
var effectiveClientSecretSlot = (oauth2) => oauth2.clientSecretSlot ?? oauth2ClientSecretSlot(oauth2.securitySchemeName);
|
|
95
|
-
function EditOpenApiSource(props) {
|
|
96
|
-
const displayScope = useScope();
|
|
97
|
-
const userScope = useUserScope();
|
|
98
|
-
const sourceSummaryResult = useAtomValue(sourceAtom(props.sourceId, displayScope));
|
|
99
|
-
const sourceSummary = AsyncResult.isSuccess(sourceSummaryResult) && sourceSummaryResult.value ? sourceSummaryResult.value : null;
|
|
100
|
-
const sourceScopeId = sourceSummary?.scopeId ?? displayScope;
|
|
101
|
-
const sourceScope = ScopeId.make(sourceScopeId);
|
|
102
|
-
const {
|
|
103
|
-
credentialScopes,
|
|
104
|
-
credentialScopeOptions,
|
|
105
|
-
organizationCredentialScope,
|
|
106
|
-
secretBindingScopes,
|
|
107
|
-
scopeRanks
|
|
108
|
-
} = useSourceCredentialBindingScopes({ sourceScope });
|
|
109
|
-
const sourceResult = useAtomValue(openApiSourceAtom(sourceScope, props.sourceId));
|
|
110
|
-
const bindingsResult = useAtomValue(
|
|
111
|
-
openApiSourceBindingsAtom(displayScope, props.sourceId, sourceScope)
|
|
112
|
-
);
|
|
113
|
-
const connectionsResult = useAtomValue(connectionsAtom(displayScope));
|
|
114
|
-
const secretList = useSecretPickerSecrets();
|
|
115
|
-
const doConfigure = useAtomSet(configureSource, { mode: "promiseExit" });
|
|
116
|
-
const doSetBinding = useAtomSet(setSourceCredentialBinding, {
|
|
117
|
-
mode: "promiseExit"
|
|
118
|
-
});
|
|
119
|
-
const doStartOAuth = useAtomSet(startOAuth, { mode: "promiseExit" });
|
|
120
|
-
const oauth = useOAuthPopupFlow({
|
|
121
|
-
popupName: OPENAPI_OAUTH_POPUP_NAME,
|
|
122
|
-
popupBlockedMessage: "OAuth popup was blocked by the browser",
|
|
123
|
-
startErrorMessage: "Failed to connect OAuth"
|
|
124
|
-
});
|
|
125
|
-
const source = AsyncResult.isSuccess(sourceResult) && sourceResult.value ? sourceResult.value : null;
|
|
126
|
-
const bindingRows = AsyncResult.isSuccess(bindingsResult) ? bindingsResult.value : [];
|
|
127
|
-
const connections = AsyncResult.isSuccess(connectionsResult) ? connectionsResult.value : [];
|
|
128
|
-
const oauth2RedirectUrl = oauthCallbackUrl(OPENAPI_OAUTH_CALLBACK_PATH);
|
|
129
|
-
const [name, setName] = useState(source?.name ?? "");
|
|
130
|
-
const [baseUrl, setBaseUrl] = useState(source?.config.baseUrl ?? "");
|
|
131
|
-
const [sourceSaveState, setSourceSaveState] = useState("idle");
|
|
132
|
-
const [error, setError] = useState(null);
|
|
133
|
-
const [busyKey, setBusyKey] = useState(null);
|
|
134
|
-
const sourceBindingWriter = useSourceCredentialBindingWriter({
|
|
135
|
-
displayScope,
|
|
136
|
-
source: { id: props.sourceId, scope: sourceScope },
|
|
137
|
-
onError: setError,
|
|
138
|
-
errorMessageFromExit
|
|
139
|
-
});
|
|
140
|
-
const [pendingOAuthConnection, setPendingOAuthConnection] = useState(null);
|
|
141
|
-
const [loadedSourceKey, setLoadedSourceKey] = useState(null);
|
|
142
|
-
const [selectedOAuthTokenScope, setSelectedOAuthTokenScope] = useState(
|
|
143
|
-
userScope !== sourceScopeId ? userScope : sourceScopeId
|
|
144
|
-
);
|
|
145
|
-
const [selectedOAuthClientIdScope, setSelectedOAuthClientIdScope] = useState(sourceScopeId);
|
|
146
|
-
const [selectedOAuthClientSecretScope, setSelectedOAuthClientSecretScope] = useState(sourceScopeId);
|
|
147
|
-
const [oauthEndpointsOpen, setOAuthEndpointsOpen] = useState(false);
|
|
148
|
-
const [oauth2AuthorizationUrl, setOAuth2AuthorizationUrl] = useState(
|
|
149
|
-
source?.config.oauth2?.authorizationUrl ?? ""
|
|
150
|
-
);
|
|
151
|
-
const [oauth2TokenUrl, setOAuth2TokenUrl] = useState(source?.config.oauth2?.tokenUrl ?? "");
|
|
152
|
-
const [oauth2EndpointsSaveState, setOAuth2EndpointsSaveState] = useState("idle");
|
|
153
|
-
const editIdentity = useMemo(
|
|
154
|
-
() => ({
|
|
155
|
-
name,
|
|
156
|
-
namespace: props.sourceId,
|
|
157
|
-
setName,
|
|
158
|
-
setNamespace: () => {
|
|
159
|
-
},
|
|
160
|
-
reset: () => {
|
|
161
|
-
}
|
|
162
|
-
}),
|
|
163
|
-
[name, props.sourceId]
|
|
164
|
-
);
|
|
165
|
-
const sourceSaveSeq = useRef(0);
|
|
166
|
-
const oauth2EndpointsSaveSeq = useRef(0);
|
|
167
|
-
useEffect(() => {
|
|
168
|
-
setSelectedOAuthTokenScope(userScope !== sourceScopeId ? userScope : sourceScopeId);
|
|
169
|
-
setSelectedOAuthClientIdScope(sourceScopeId);
|
|
170
|
-
setSelectedOAuthClientSecretScope(sourceScopeId);
|
|
171
|
-
}, [sourceScopeId, userScope]);
|
|
172
|
-
useEffect(() => {
|
|
173
|
-
if (!source) return;
|
|
174
|
-
const sourceKey = `${sourceScopeId}:${source.namespace}`;
|
|
175
|
-
if (loadedSourceKey === sourceKey) return;
|
|
176
|
-
setName(source.name);
|
|
177
|
-
setBaseUrl(source.config.baseUrl ?? "");
|
|
178
|
-
setOAuth2AuthorizationUrl(source.config.oauth2?.authorizationUrl ?? "");
|
|
179
|
-
setOAuth2TokenUrl(source.config.oauth2?.tokenUrl ?? "");
|
|
180
|
-
setOAuth2EndpointsSaveState("idle");
|
|
181
|
-
setOAuthEndpointsOpen(false);
|
|
182
|
-
setSourceSaveState("idle");
|
|
183
|
-
setLoadedSourceKey(sourceKey);
|
|
184
|
-
}, [loadedSourceKey, source, sourceScopeId]);
|
|
185
|
-
useEffect(() => {
|
|
186
|
-
if (!source) return;
|
|
187
|
-
const sourceKey = `${sourceScopeId}:${source.namespace}`;
|
|
188
|
-
if (loadedSourceKey !== sourceKey) return;
|
|
189
|
-
const nextName = name.trim();
|
|
190
|
-
const nextBaseUrl = baseUrl.trim();
|
|
191
|
-
const currentName = source.name;
|
|
192
|
-
const currentBaseUrl = source.config.baseUrl ?? "";
|
|
193
|
-
if ((nextName || currentName) === currentName && nextBaseUrl === currentBaseUrl) {
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
const timeout = window.setTimeout(() => {
|
|
197
|
-
const seq = ++sourceSaveSeq.current;
|
|
198
|
-
setSourceSaveState("saving");
|
|
199
|
-
setError(null);
|
|
200
|
-
void (async () => {
|
|
201
|
-
const exit = await doConfigure({
|
|
202
|
-
params: { scopeId: displayScope },
|
|
203
|
-
payload: {
|
|
204
|
-
source: { id: props.sourceId, scope: sourceScope },
|
|
205
|
-
scope: sourceScope,
|
|
206
|
-
type: "openapi",
|
|
207
|
-
config: {
|
|
208
|
-
scope: sourceScope,
|
|
209
|
-
name: nextName || void 0,
|
|
210
|
-
baseUrl: nextBaseUrl || void 0
|
|
211
|
-
}
|
|
212
|
-
},
|
|
213
|
-
reactivityKeys: openApiWriteKeys
|
|
214
|
-
});
|
|
215
|
-
if (sourceSaveSeq.current !== seq) return;
|
|
216
|
-
if (Exit.isFailure(exit)) {
|
|
217
|
-
setSourceSaveState("idle");
|
|
218
|
-
setError(errorMessageFromExit(exit, "Failed to save source details"));
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
setSourceSaveState("saved");
|
|
222
|
-
window.setTimeout(() => {
|
|
223
|
-
if (sourceSaveSeq.current === seq) setSourceSaveState("idle");
|
|
224
|
-
}, 1600);
|
|
225
|
-
})();
|
|
226
|
-
}, 600);
|
|
227
|
-
return () => window.clearTimeout(timeout);
|
|
228
|
-
}, [
|
|
229
|
-
baseUrl,
|
|
230
|
-
displayScope,
|
|
231
|
-
doConfigure,
|
|
232
|
-
loadedSourceKey,
|
|
233
|
-
name,
|
|
234
|
-
props.sourceId,
|
|
235
|
-
source,
|
|
236
|
-
sourceScope,
|
|
237
|
-
sourceScopeId
|
|
238
|
-
]);
|
|
239
|
-
const secretSlots = useMemo(() => {
|
|
240
|
-
if (!source) return [];
|
|
241
|
-
const slots = [];
|
|
242
|
-
for (const [headerName, value] of Object.entries(source.config.headers ?? {})) {
|
|
243
|
-
if (typeof value === "string") continue;
|
|
244
|
-
slots.push({
|
|
245
|
-
kind: "secret",
|
|
246
|
-
slot: value.slot,
|
|
247
|
-
label: headerName,
|
|
248
|
-
hint: value.prefix ? `Prefix: ${value.prefix}` : void 0
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
if (source.config.oauth2) {
|
|
252
|
-
const clientSecretSlot = effectiveClientSecretSlot(source.config.oauth2);
|
|
253
|
-
slots.push({
|
|
254
|
-
kind: "secret",
|
|
255
|
-
slot: source.config.oauth2.clientIdSlot,
|
|
256
|
-
label: "Client ID"
|
|
257
|
-
});
|
|
258
|
-
slots.push({
|
|
259
|
-
kind: "secret",
|
|
260
|
-
slot: clientSecretSlot,
|
|
261
|
-
label: "Client Secret",
|
|
262
|
-
hint: source.config.oauth2.flow === "authorizationCode" ? "Optional for public PKCE clients" : void 0
|
|
263
|
-
});
|
|
264
|
-
slots.push({
|
|
265
|
-
kind: "oauth2",
|
|
266
|
-
slot: source.config.oauth2.connectionSlot,
|
|
267
|
-
label: source.config.oauth2.flow === "clientCredentials" ? "OAuth Client Credentials" : "OAuth Authorization Code"
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
return slots;
|
|
271
|
-
}, [source]);
|
|
272
|
-
const activeOAuthTokenScope = credentialScopes.find((entry) => entry.scopeId === selectedOAuthTokenScope) ?? credentialScopes[0];
|
|
273
|
-
const activeOAuthTokenScopeId = activeOAuthTokenScope.scopeId;
|
|
274
|
-
const activeOAuthTokenScopeLabel = activeOAuthTokenScope.label;
|
|
275
|
-
if (!source) {
|
|
276
|
-
return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
277
|
-
/* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold text-foreground", children: "Edit OpenAPI Source" }),
|
|
278
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Loading configuration\u2026" })
|
|
279
|
-
] });
|
|
280
|
-
}
|
|
281
|
-
const oauthClientSecretSlot = source.config.oauth2 ? effectiveClientSecretSlot(source.config.oauth2) : null;
|
|
282
|
-
const nonOAuthSecretSlots = secretSlots.filter(
|
|
283
|
-
(slot) => slot.kind === "secret" && (!source.config.oauth2 || slot.slot !== source.config.oauth2.clientIdSlot && slot.slot !== oauthClientSecretSlot)
|
|
284
|
-
);
|
|
285
|
-
const connectOAuth = async (targetScope) => {
|
|
286
|
-
const oauth2 = source.config.oauth2;
|
|
287
|
-
if (!oauth2) return;
|
|
288
|
-
const clientIdBinding = effectiveCredentialBindingForScope(
|
|
289
|
-
bindingRows,
|
|
290
|
-
oauth2.clientIdSlot,
|
|
291
|
-
targetScope,
|
|
292
|
-
scopeRanks
|
|
293
|
-
);
|
|
294
|
-
const clientSecretSlot = effectiveClientSecretSlot(oauth2);
|
|
295
|
-
const clientSecretBinding = effectiveCredentialBindingForScope(
|
|
296
|
-
bindingRows,
|
|
297
|
-
clientSecretSlot,
|
|
298
|
-
targetScope,
|
|
299
|
-
scopeRanks
|
|
300
|
-
);
|
|
301
|
-
if (!clientIdBinding || !isSecretCredentialBindingValue(clientIdBinding.value)) {
|
|
302
|
-
setError("Client ID must be bound before connecting");
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
305
|
-
const clientIdSecretId = clientIdBinding.value.secretId;
|
|
306
|
-
const clientIdSecretScopeId = clientIdBinding.value.secretScopeId ?? clientIdBinding.scopeId;
|
|
307
|
-
if (oauth2.flow === "clientCredentials" && (!clientSecretBinding || !isSecretCredentialBindingValue(clientSecretBinding.value))) {
|
|
308
|
-
setError("Client secret must be bound before connecting");
|
|
309
|
-
return;
|
|
310
|
-
}
|
|
311
|
-
const clientSecretValue = oauth2.flow === "clientCredentials" && clientSecretBinding && isSecretCredentialBindingValue(clientSecretBinding.value) ? clientSecretBinding.value : null;
|
|
312
|
-
const clientSecretSecretScopeId = clientSecretBinding && isSecretCredentialBindingValue(clientSecretBinding.value) ? clientSecretBinding.value.secretScopeId ?? clientSecretBinding.scopeId : null;
|
|
313
|
-
const existingConnection = exactCredentialBindingForScope(
|
|
314
|
-
bindingRows,
|
|
315
|
-
oauth2.connectionSlot,
|
|
316
|
-
targetScope
|
|
317
|
-
);
|
|
318
|
-
const connectionId = existingConnection && isConnectionCredentialBindingValue(existingConnection.value) ? existingConnection.value.connectionId : openApiOAuthConnectionId(props.sourceId, oauth2.securitySchemeName, targetScope);
|
|
319
|
-
setBusyKey(`${targetScope}:${oauth2.connectionSlot}:connect`);
|
|
320
|
-
setPendingOAuthConnection({
|
|
321
|
-
scopeId: targetScope,
|
|
322
|
-
slot: oauth2.connectionSlot,
|
|
323
|
-
connectionId
|
|
324
|
-
});
|
|
325
|
-
setError(null);
|
|
326
|
-
const failConnect = (message) => {
|
|
327
|
-
setError(message);
|
|
328
|
-
setPendingOAuthConnection(null);
|
|
329
|
-
setBusyKey(null);
|
|
330
|
-
};
|
|
331
|
-
const displayName = source.name;
|
|
332
|
-
const tokenUrl = resolveOAuthUrl(oauth2.tokenUrl, source.config.baseUrl ?? "");
|
|
333
|
-
if (oauth2.flow === "clientCredentials") {
|
|
334
|
-
const startOAuthExit2 = await doStartOAuth({
|
|
335
|
-
params: { scopeId: targetScope },
|
|
336
|
-
payload: {
|
|
337
|
-
endpoint: tokenUrl,
|
|
338
|
-
redirectUrl: tokenUrl,
|
|
339
|
-
connectionId,
|
|
340
|
-
tokenScope: targetScope,
|
|
341
|
-
strategy: {
|
|
342
|
-
kind: "client-credentials",
|
|
343
|
-
tokenEndpoint: tokenUrl,
|
|
344
|
-
clientIdSecretId,
|
|
345
|
-
clientIdSecretScopeId: String(clientIdSecretScopeId),
|
|
346
|
-
clientSecretSecretId: clientSecretValue.secretId,
|
|
347
|
-
clientSecretSecretScopeId: clientSecretSecretScopeId ? String(clientSecretSecretScopeId) : null,
|
|
348
|
-
scopes: [...oauth2.scopes]
|
|
349
|
-
},
|
|
350
|
-
pluginId: "openapi",
|
|
351
|
-
identityLabel: `${displayName} OAuth`
|
|
352
|
-
}
|
|
353
|
-
});
|
|
354
|
-
if (Exit.isFailure(startOAuthExit2)) {
|
|
355
|
-
failConnect(errorMessageFromExit(startOAuthExit2, "Failed to connect OAuth"));
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
const response2 = startOAuthExit2.value;
|
|
359
|
-
if (!response2.completedConnection) {
|
|
360
|
-
failConnect("Unexpected OAuth response");
|
|
361
|
-
return;
|
|
362
|
-
}
|
|
363
|
-
const setBindingExit = await doSetBinding({
|
|
364
|
-
params: { scopeId: displayScope },
|
|
365
|
-
payload: SetSourceCredentialBindingInput.make({
|
|
366
|
-
source: { id: props.sourceId, scope: sourceScope },
|
|
367
|
-
scope: targetScope,
|
|
368
|
-
slotKey: oauth2.connectionSlot,
|
|
369
|
-
value: {
|
|
370
|
-
kind: "connection",
|
|
371
|
-
connectionId: ConnectionId.make(response2.completedConnection.connectionId)
|
|
372
|
-
}
|
|
373
|
-
}),
|
|
374
|
-
reactivityKeys: [...sourceWriteKeys, ...connectionWriteKeys]
|
|
375
|
-
});
|
|
376
|
-
if (Exit.isFailure(setBindingExit)) {
|
|
377
|
-
failConnect(errorMessageFromExit(setBindingExit, "Failed to connect OAuth"));
|
|
378
|
-
return;
|
|
379
|
-
}
|
|
380
|
-
setPendingOAuthConnection(null);
|
|
381
|
-
setBusyKey(null);
|
|
382
|
-
return;
|
|
383
|
-
}
|
|
384
|
-
const authorizationUrl = resolveOAuthUrl(
|
|
385
|
-
oauth2.authorizationUrl ?? "",
|
|
386
|
-
source.config.baseUrl ?? ""
|
|
387
|
-
);
|
|
388
|
-
const issuerUrl = oauth2.issuerUrl ?? inferOAuthIssuerUrl(authorizationUrl);
|
|
389
|
-
const startOAuthExit = await doStartOAuth({
|
|
390
|
-
params: { scopeId: targetScope },
|
|
391
|
-
payload: {
|
|
392
|
-
endpoint: authorizationUrl,
|
|
393
|
-
connectionId,
|
|
394
|
-
tokenScope: targetScope,
|
|
395
|
-
redirectUrl: oauth2RedirectUrl,
|
|
396
|
-
strategy: {
|
|
397
|
-
kind: "authorization-code",
|
|
398
|
-
authorizationEndpoint: authorizationUrl,
|
|
399
|
-
tokenEndpoint: tokenUrl,
|
|
400
|
-
issuerUrl,
|
|
401
|
-
clientIdSecretId,
|
|
402
|
-
clientIdSecretScopeId: String(clientIdSecretScopeId),
|
|
403
|
-
clientSecretSecretId: clientSecretBinding && isSecretCredentialBindingValue(clientSecretBinding.value) ? clientSecretBinding.value.secretId : null,
|
|
404
|
-
clientSecretSecretScopeId: clientSecretSecretScopeId ? String(clientSecretSecretScopeId) : null,
|
|
405
|
-
scopes: [...oauth2.scopes]
|
|
406
|
-
},
|
|
407
|
-
pluginId: "openapi",
|
|
408
|
-
identityLabel: `${displayName} OAuth`
|
|
409
|
-
}
|
|
410
|
-
});
|
|
411
|
-
if (Exit.isFailure(startOAuthExit)) {
|
|
412
|
-
failConnect(errorMessageFromExit(startOAuthExit, "Failed to connect OAuth"));
|
|
413
|
-
return;
|
|
414
|
-
}
|
|
415
|
-
const response = startOAuthExit.value;
|
|
416
|
-
if (response.authorizationUrl === null) {
|
|
417
|
-
failConnect("Unexpected OAuth response");
|
|
418
|
-
return;
|
|
419
|
-
}
|
|
420
|
-
await oauth.openAuthorization({
|
|
421
|
-
tokenScope: targetScope,
|
|
422
|
-
run: async () => ({
|
|
423
|
-
sessionId: response.sessionId,
|
|
424
|
-
authorizationUrl: response.authorizationUrl
|
|
425
|
-
}),
|
|
426
|
-
onSuccess: async (result) => {
|
|
427
|
-
const setBindingExit = await doSetBinding({
|
|
428
|
-
params: { scopeId: displayScope },
|
|
429
|
-
payload: SetSourceCredentialBindingInput.make({
|
|
430
|
-
source: { id: props.sourceId, scope: sourceScope },
|
|
431
|
-
scope: targetScope,
|
|
432
|
-
slotKey: oauth2.connectionSlot,
|
|
433
|
-
value: {
|
|
434
|
-
kind: "connection",
|
|
435
|
-
connectionId: ConnectionId.make(result.connectionId)
|
|
436
|
-
}
|
|
437
|
-
}),
|
|
438
|
-
reactivityKeys: [...sourceWriteKeys, ...connectionWriteKeys]
|
|
439
|
-
});
|
|
440
|
-
if (Exit.isFailure(setBindingExit)) {
|
|
441
|
-
failConnect(errorMessageFromExit(setBindingExit, "Failed to connect OAuth"));
|
|
442
|
-
return;
|
|
443
|
-
}
|
|
444
|
-
setPendingOAuthConnection(null);
|
|
445
|
-
setBusyKey(null);
|
|
446
|
-
},
|
|
447
|
-
onError: (message) => {
|
|
448
|
-
setError(message);
|
|
449
|
-
setPendingOAuthConnection(null);
|
|
450
|
-
setBusyKey(null);
|
|
451
|
-
}
|
|
452
|
-
});
|
|
453
|
-
};
|
|
454
|
-
return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
455
|
-
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold text-foreground", children: "OpenAPI Source" }) }),
|
|
456
|
-
/* @__PURE__ */ jsx(
|
|
457
|
-
OpenApiSourceDetailsFields,
|
|
458
|
-
{
|
|
459
|
-
title: "Source Details",
|
|
460
|
-
description: "Name and base URL save automatically.",
|
|
461
|
-
identity: editIdentity,
|
|
462
|
-
baseUrl,
|
|
463
|
-
onBaseUrlChange: setBaseUrl,
|
|
464
|
-
specUrl: source.config.sourceUrl ?? "",
|
|
465
|
-
onSpecUrlChange: () => {
|
|
466
|
-
},
|
|
467
|
-
specUrlDisabled: true,
|
|
468
|
-
namespaceReadOnly: true,
|
|
469
|
-
saveState: sourceSaveState,
|
|
470
|
-
footer: source.config.oauth2 ? `Authentication Template: OAuth2 ${source.config.oauth2.flow}` : Object.keys(source.config.headers ?? {}).length > 0 ? `Authentication Template: ${Object.keys(source.config.headers ?? {}).length} header binding${Object.keys(source.config.headers ?? {}).length === 1 ? "" : "s"}` : "Authentication Template: None"
|
|
471
|
-
}
|
|
472
|
-
),
|
|
473
|
-
/* @__PURE__ */ jsx(CardStack, { children: /* @__PURE__ */ jsxs(CardStackContent, { className: "border-t-0", children: [
|
|
474
|
-
nonOAuthSecretSlots.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
475
|
-
/* @__PURE__ */ jsx(CardStackEntry, { children: /* @__PURE__ */ jsxs(CardStackEntryContent, { children: [
|
|
476
|
-
/* @__PURE__ */ jsx(CardStackEntryTitle, { children: "Request credentials" }),
|
|
477
|
-
/* @__PURE__ */ jsx(CardStackEntryDescription, { children: "Headers and query parameters sent with every API request." })
|
|
478
|
-
] }) }),
|
|
479
|
-
/* @__PURE__ */ jsx(
|
|
480
|
-
SecretCredentialSlotBindings,
|
|
481
|
-
{
|
|
482
|
-
slots: nonOAuthSecretSlots,
|
|
483
|
-
bindingScopes: secretBindingScopes,
|
|
484
|
-
bindingRows,
|
|
485
|
-
scopeRanks,
|
|
486
|
-
secrets: secretList,
|
|
487
|
-
sourceId: props.sourceId,
|
|
488
|
-
sourceName: source.name,
|
|
489
|
-
credentialScopeOptions,
|
|
490
|
-
busyKey: sourceBindingWriter.busyKey,
|
|
491
|
-
onSetSecretBinding: sourceBindingWriter.setSecretBinding,
|
|
492
|
-
onClearBinding: sourceBindingWriter.clearBinding
|
|
493
|
-
}
|
|
494
|
-
)
|
|
495
|
-
] }),
|
|
496
|
-
source.config.oauth2 && (() => {
|
|
497
|
-
const oauth2 = source.config.oauth2;
|
|
498
|
-
const trimmedAuthUrl = oauth2AuthorizationUrl.trim();
|
|
499
|
-
const trimmedTokenUrl = oauth2TokenUrl.trim();
|
|
500
|
-
const savedAuthUrl = oauth2.authorizationUrl ?? "";
|
|
501
|
-
const isAuthCode = oauth2.flow === "authorizationCode";
|
|
502
|
-
const endpointsDirty = isAuthCode && trimmedAuthUrl !== savedAuthUrl || trimmedTokenUrl !== oauth2.tokenUrl;
|
|
503
|
-
const saving = oauth2EndpointsSaveState === "saving";
|
|
504
|
-
const tokenUrlMissing = trimmedTokenUrl.length === 0;
|
|
505
|
-
const authUrlMissing = isAuthCode && trimmedAuthUrl.length === 0;
|
|
506
|
-
const canSave = endpointsDirty && !saving && !tokenUrlMissing && !authUrlMissing;
|
|
507
|
-
const saveOAuth2Endpoints = async () => {
|
|
508
|
-
const seq = ++oauth2EndpointsSaveSeq.current;
|
|
509
|
-
setOAuth2EndpointsSaveState("saving");
|
|
510
|
-
setError(null);
|
|
511
|
-
const exit = await doConfigure({
|
|
512
|
-
params: { scopeId: displayScope },
|
|
513
|
-
payload: {
|
|
514
|
-
source: { id: props.sourceId, scope: sourceScope },
|
|
515
|
-
scope: sourceScope,
|
|
516
|
-
type: "openapi",
|
|
517
|
-
config: {
|
|
518
|
-
scope: sourceScope,
|
|
519
|
-
oauth2Source: OAuth2SourceConfig.make({
|
|
520
|
-
kind: "oauth2",
|
|
521
|
-
securitySchemeName: oauth2.securitySchemeName,
|
|
522
|
-
flow: oauth2.flow,
|
|
523
|
-
tokenUrl: trimmedTokenUrl,
|
|
524
|
-
authorizationUrl: isAuthCode ? trimmedAuthUrl || null : null,
|
|
525
|
-
issuerUrl: oauth2.issuerUrl ?? null,
|
|
526
|
-
clientIdSlot: oauth2.clientIdSlot,
|
|
527
|
-
clientSecretSlot: oauth2.clientSecretSlot,
|
|
528
|
-
connectionSlot: oauth2.connectionSlot,
|
|
529
|
-
scopes: [...oauth2.scopes]
|
|
530
|
-
})
|
|
531
|
-
}
|
|
532
|
-
},
|
|
533
|
-
reactivityKeys: openApiWriteKeys
|
|
534
|
-
});
|
|
535
|
-
if (oauth2EndpointsSaveSeq.current !== seq) return;
|
|
536
|
-
if (Exit.isFailure(exit)) {
|
|
537
|
-
setOAuth2EndpointsSaveState("idle");
|
|
538
|
-
setError(errorMessageFromExit(exit, "Failed to save OAuth endpoints"));
|
|
539
|
-
return;
|
|
540
|
-
}
|
|
541
|
-
setOAuth2EndpointsSaveState("saved");
|
|
542
|
-
window.setTimeout(() => {
|
|
543
|
-
if (oauth2EndpointsSaveSeq.current === seq) {
|
|
544
|
-
setOAuth2EndpointsSaveState("idle");
|
|
545
|
-
}
|
|
546
|
-
}, 1600);
|
|
547
|
-
};
|
|
548
|
-
const exact = exactCredentialBindingForScope(
|
|
549
|
-
bindingRows,
|
|
550
|
-
oauth2.connectionSlot,
|
|
551
|
-
activeOAuthTokenScopeId
|
|
552
|
-
);
|
|
553
|
-
const binding = exact ?? effectiveCredentialBindingForScope(
|
|
554
|
-
bindingRows,
|
|
555
|
-
oauth2.connectionSlot,
|
|
556
|
-
activeOAuthTokenScopeId,
|
|
557
|
-
scopeRanks
|
|
558
|
-
);
|
|
559
|
-
const connectionBinding = binding && isConnectionCredentialBindingValue(binding.value) ? binding.value : null;
|
|
560
|
-
const connection = connectionBinding ? connections.find((entry) => entry.id === connectionBinding.connectionId) : null;
|
|
561
|
-
const bindingScopeId = connectionBinding && binding ? binding.scopeId : null;
|
|
562
|
-
const isConnecting = busyKey === `${activeOAuthTokenScopeId}:${oauth2.connectionSlot}:connect`;
|
|
563
|
-
const isPendingOAuthConnection = pendingOAuthConnection?.scopeId === activeOAuthTokenScopeId && pendingOAuthConnection !== null && pendingOAuthConnection.slot === oauth2.connectionSlot;
|
|
564
|
-
const isConnected = connection !== null && connection !== void 0;
|
|
565
|
-
const statusText = isConnecting || isPendingOAuthConnection ? "Saving OAuth connection..." : connectionBinding && bindingScopeId ? connection ? bindingScopeId === activeOAuthTokenScopeId ? `Connected in ${activeOAuthTokenScopeLabel.toLowerCase()} as ${connection.identityLabel ?? connection.id}` : `Using organization connection ${connection.identityLabel ?? connection.id}` : bindingScopeId === activeOAuthTokenScopeId ? `Saved connection is missing in ${activeOAuthTokenScopeLabel.toLowerCase()}` : "Organization connection is missing" : `No ${activeOAuthTokenScopeLabel.toLowerCase()} connection`;
|
|
566
|
-
const connectDisabled = isConnecting || endpointsDirty || saving;
|
|
567
|
-
const clientSecretSlot = effectiveClientSecretSlot(oauth2);
|
|
568
|
-
const renderAppSecret = (input) => {
|
|
569
|
-
const activeScope = credentialScopes.find((entry) => entry.scopeId === input.scopeId) ?? organizationCredentialScope;
|
|
570
|
-
const exactSecret = exactCredentialBindingForScope(
|
|
571
|
-
bindingRows,
|
|
572
|
-
input.slot,
|
|
573
|
-
activeScope.scopeId
|
|
574
|
-
);
|
|
575
|
-
const effectiveSecret = effectiveCredentialBindingForScope(
|
|
576
|
-
bindingRows,
|
|
577
|
-
input.slot,
|
|
578
|
-
activeScope.scopeId,
|
|
579
|
-
scopeRanks
|
|
580
|
-
);
|
|
581
|
-
const exactSecretId = exactSecret && isSecretCredentialBindingValue(exactSecret.value) ? exactSecret.value.secretId : null;
|
|
582
|
-
const inheritedSecret = !exactSecretId && effectiveSecret && effectiveSecret.scopeId !== activeScope.scopeId && isSecretCredentialBindingValue(effectiveSecret.value) ? effectiveSecret : null;
|
|
583
|
-
const status = exactSecretId ? `${activeScope.label} credential set` : inheritedSecret ? "Using organization credential" : "Not set";
|
|
584
|
-
const inputKey = `${activeScope.scopeId}:${input.slot}`;
|
|
585
|
-
const clearKey = `${activeScope.scopeId}:${input.slot}:clear`;
|
|
586
|
-
return /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
587
|
-
/* @__PURE__ */ jsxs(FieldLabel, { className: "text-[11px]", children: [
|
|
588
|
-
input.label,
|
|
589
|
-
" ",
|
|
590
|
-
input.hint && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
|
|
591
|
-
"\xB7 ",
|
|
592
|
-
input.hint
|
|
593
|
-
] })
|
|
594
|
-
] }),
|
|
595
|
-
/* @__PURE__ */ jsxs("div", { className: "grid gap-2 md:grid-cols-2", children: [
|
|
596
|
-
/* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
597
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
598
|
-
/* @__PURE__ */ jsx(FieldLabel, { className: "text-[11px]", children: "Secret" }),
|
|
599
|
-
/* @__PURE__ */ jsxs(HelpTooltip, { label: `${input.label} secret`, children: [
|
|
600
|
-
"Select or create the OAuth ",
|
|
601
|
-
input.label.toLowerCase(),
|
|
602
|
-
" secret."
|
|
603
|
-
] }),
|
|
604
|
-
/* @__PURE__ */ jsx("span", { className: "ml-auto truncate text-xs text-muted-foreground", children: status })
|
|
605
|
-
] }),
|
|
606
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
607
|
-
/* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx(
|
|
608
|
-
CreatableSecretPicker,
|
|
609
|
-
{
|
|
610
|
-
value: exactSecretId,
|
|
611
|
-
onSelect: (secretId, secretScopeId) => void sourceBindingWriter.setSecretBinding(
|
|
612
|
-
activeScope.scopeId,
|
|
613
|
-
input.slot,
|
|
614
|
-
secretId,
|
|
615
|
-
secretScopeId ?? activeScope.scopeId
|
|
616
|
-
),
|
|
617
|
-
secrets: secretList,
|
|
618
|
-
placeholder: "Select or create a secret",
|
|
619
|
-
targetScope: activeScope.scopeId,
|
|
620
|
-
credentialScopeOptions,
|
|
621
|
-
suggestedId: `source-binding-${slugify(props.sourceId)}-${slugify(
|
|
622
|
-
input.slot
|
|
623
|
-
)}-${slugify(activeScope.scopeId)}`,
|
|
624
|
-
sourceName: source.name,
|
|
625
|
-
secretLabel: input.label
|
|
626
|
-
}
|
|
627
|
-
) }),
|
|
628
|
-
exactSecretId && /* @__PURE__ */ jsx(
|
|
629
|
-
Button,
|
|
630
|
-
{
|
|
631
|
-
variant: "outline",
|
|
632
|
-
size: "sm",
|
|
633
|
-
onClick: () => void sourceBindingWriter.clearBinding(
|
|
634
|
-
activeScope.scopeId,
|
|
635
|
-
input.slot
|
|
636
|
-
),
|
|
637
|
-
disabled: sourceBindingWriter.busyKey === clearKey,
|
|
638
|
-
children: "Clear"
|
|
639
|
-
}
|
|
640
|
-
),
|
|
641
|
-
sourceBindingWriter.busyKey === inputKey && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "Saving\u2026" })
|
|
642
|
-
] })
|
|
643
|
-
] }),
|
|
644
|
-
/* @__PURE__ */ jsx(
|
|
645
|
-
CredentialScopeDropdown,
|
|
646
|
-
{
|
|
647
|
-
value: activeScope.scopeId,
|
|
648
|
-
options: credentialScopeOptions,
|
|
649
|
-
onChange: input.onScopeChange,
|
|
650
|
-
label: "Used by",
|
|
651
|
-
help: `Choose where this OAuth ${input.label.toLowerCase()} credential lives.`
|
|
652
|
-
}
|
|
653
|
-
)
|
|
654
|
-
] })
|
|
655
|
-
] });
|
|
656
|
-
};
|
|
657
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
658
|
-
/* @__PURE__ */ jsx(CardStackEntry, { children: /* @__PURE__ */ jsxs(CardStackEntryContent, { children: [
|
|
659
|
-
/* @__PURE__ */ jsx(CardStackEntryTitle, { children: "OAuth" }),
|
|
660
|
-
/* @__PURE__ */ jsx(CardStackEntryDescription, { children: "Configure app credentials and connect accounts for this source." })
|
|
661
|
-
] }) }),
|
|
662
|
-
/* @__PURE__ */ jsx(CardStackEntryField, { label: "OAuth app credentials", children: /* @__PURE__ */ jsxs("div", { className: "space-y-4 rounded-lg border border-border/60 bg-muted/10 p-3", children: [
|
|
663
|
-
renderAppSecret({
|
|
664
|
-
slot: oauth2.clientIdSlot,
|
|
665
|
-
label: "Client ID",
|
|
666
|
-
scopeId: ScopeId.make(selectedOAuthClientIdScope),
|
|
667
|
-
onScopeChange: setSelectedOAuthClientIdScope
|
|
668
|
-
}),
|
|
669
|
-
renderAppSecret({
|
|
670
|
-
slot: clientSecretSlot,
|
|
671
|
-
label: "Client secret",
|
|
672
|
-
hint: oauth2.flow === "authorizationCode" ? "Optional for public clients with PKCE" : void 0,
|
|
673
|
-
scopeId: ScopeId.make(selectedOAuthClientSecretScope),
|
|
674
|
-
onScopeChange: setSelectedOAuthClientSecretScope
|
|
675
|
-
})
|
|
676
|
-
] }) }),
|
|
677
|
-
/* @__PURE__ */ jsx(CardStackEntryField, { label: "Account connection", children: /* @__PURE__ */ jsx(
|
|
678
|
-
CredentialUsageRow,
|
|
679
|
-
{
|
|
680
|
-
value: activeOAuthTokenScopeId,
|
|
681
|
-
options: credentialScopeOptions,
|
|
682
|
-
onChange: setSelectedOAuthTokenScope,
|
|
683
|
-
label: "Connection saved to",
|
|
684
|
-
help: "Choose where the signed-in OAuth token is saved.",
|
|
685
|
-
children: /* @__PURE__ */ jsxs(
|
|
686
|
-
CredentialControlField,
|
|
687
|
-
{
|
|
688
|
-
label: "OAuth connection",
|
|
689
|
-
help: "Start the provider OAuth flow.",
|
|
690
|
-
children: [
|
|
691
|
-
/* @__PURE__ */ jsxs("div", { className: "flex min-h-9 items-center gap-2 rounded-md border border-border bg-muted/30 px-3 py-2", children: [
|
|
692
|
-
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-xs text-muted-foreground", children: statusText }),
|
|
693
|
-
/* @__PURE__ */ jsx(
|
|
694
|
-
Button,
|
|
695
|
-
{
|
|
696
|
-
size: "sm",
|
|
697
|
-
onClick: () => void connectOAuth(activeOAuthTokenScopeId),
|
|
698
|
-
disabled: connectDisabled,
|
|
699
|
-
children: isConnecting ? "Connecting\u2026" : isConnected ? "Reconnect" : "Connect"
|
|
700
|
-
}
|
|
701
|
-
)
|
|
702
|
-
] }),
|
|
703
|
-
endpointsDirty && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Save endpoint changes before reconnecting." })
|
|
704
|
-
]
|
|
705
|
-
}
|
|
706
|
-
)
|
|
707
|
-
}
|
|
708
|
-
) }),
|
|
709
|
-
/* @__PURE__ */ jsxs(CardStackEntry, { children: [
|
|
710
|
-
/* @__PURE__ */ jsxs(CardStackEntryContent, { children: [
|
|
711
|
-
/* @__PURE__ */ jsx(CardStackEntryTitle, { children: "Advanced endpoints" }),
|
|
712
|
-
/* @__PURE__ */ jsx(CardStackEntryDescription, { children: "Override provider URLs only when the OpenAPI spec is wrong." })
|
|
713
|
-
] }),
|
|
714
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
715
|
-
oauth2EndpointsSaveState !== "idle" && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: saving ? "Saving\u2026" : "Saved" }),
|
|
716
|
-
/* @__PURE__ */ jsx(
|
|
717
|
-
Button,
|
|
718
|
-
{
|
|
719
|
-
variant: "outline",
|
|
720
|
-
size: "sm",
|
|
721
|
-
onClick: () => setOAuthEndpointsOpen((open) => !open),
|
|
722
|
-
children: oauthEndpointsOpen ? "Hide" : endpointsDirty ? "Review" : "Show"
|
|
723
|
-
}
|
|
724
|
-
)
|
|
725
|
-
] })
|
|
726
|
-
] }),
|
|
727
|
-
oauthEndpointsOpen && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
728
|
-
isAuthCode && /* @__PURE__ */ jsx(CardStackEntryField, { label: "Authorization URL", children: /* @__PURE__ */ jsx(
|
|
729
|
-
Input,
|
|
730
|
-
{
|
|
731
|
-
value: oauth2AuthorizationUrl,
|
|
732
|
-
onChange: (e) => setOAuth2AuthorizationUrl(e.target.value),
|
|
733
|
-
className: "font-mono text-sm"
|
|
734
|
-
}
|
|
735
|
-
) }),
|
|
736
|
-
/* @__PURE__ */ jsx(CardStackEntryField, { label: "Token URL", children: /* @__PURE__ */ jsx(
|
|
737
|
-
Input,
|
|
738
|
-
{
|
|
739
|
-
value: oauth2TokenUrl,
|
|
740
|
-
onChange: (e) => setOAuth2TokenUrl(e.target.value),
|
|
741
|
-
className: "font-mono text-sm"
|
|
742
|
-
}
|
|
743
|
-
) }),
|
|
744
|
-
/* @__PURE__ */ jsx(CardStackEntryField, { label: "Redirect URL", children: /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
745
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 rounded-md border border-border bg-background/50 px-2.5 py-1.5 font-mono text-[11px]", children: [
|
|
746
|
-
/* @__PURE__ */ jsx("span", { className: "truncate flex-1 text-foreground", children: oauth2RedirectUrl }),
|
|
747
|
-
/* @__PURE__ */ jsx(CopyButton, { value: oauth2RedirectUrl })
|
|
748
|
-
] }),
|
|
749
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Add this to your OAuth app's allowed redirects." })
|
|
750
|
-
] }) }),
|
|
751
|
-
/* @__PURE__ */ jsxs(CardStackEntry, { children: [
|
|
752
|
-
/* @__PURE__ */ jsx(CardStackEntryContent, { children: /* @__PURE__ */ jsx(CardStackEntryDescription, { children: "Save endpoint changes before reconnecting." }) }),
|
|
753
|
-
/* @__PURE__ */ jsx(
|
|
754
|
-
Button,
|
|
755
|
-
{
|
|
756
|
-
size: "sm",
|
|
757
|
-
onClick: () => void saveOAuth2Endpoints(),
|
|
758
|
-
disabled: !canSave,
|
|
759
|
-
children: "Save endpoints"
|
|
760
|
-
}
|
|
761
|
-
)
|
|
762
|
-
] })
|
|
763
|
-
] })
|
|
764
|
-
] });
|
|
765
|
-
})()
|
|
766
|
-
] }) }),
|
|
767
|
-
error && /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: error }) }),
|
|
768
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-start border-t border-border pt-4", children: /* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: props.onSave, children: "Back" }) })
|
|
769
|
-
] });
|
|
770
|
-
}
|
|
771
|
-
export {
|
|
772
|
-
EditOpenApiSource as default
|
|
773
|
-
};
|
|
774
|
-
//# sourceMappingURL=EditOpenApiSource-MV7NYTRP.js.map
|