@executor-js/plugin-openapi 1.4.33 → 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.
Files changed (81) hide show
  1. package/dist/AddOpenApiSource-7M52SRUX.js +893 -0
  2. package/dist/AddOpenApiSource-7M52SRUX.js.map +1 -0
  3. package/dist/EditOpenApiSource-WTAMRJUK.js +68 -0
  4. package/dist/EditOpenApiSource-WTAMRJUK.js.map +1 -0
  5. package/dist/OpenApiAccountsPanel-3VJJXNQF.js +112 -0
  6. package/dist/OpenApiAccountsPanel-3VJJXNQF.js.map +1 -0
  7. package/dist/api/group.d.ts +104 -225
  8. package/dist/api/index.d.ts +127 -271
  9. package/dist/{chunk-BB5IAKRG.js → chunk-AQ7JDDRM.js} +12 -2
  10. package/dist/chunk-AQ7JDDRM.js.map +1 -0
  11. package/dist/chunk-BSLE6HCE.js +181 -0
  12. package/dist/chunk-BSLE6HCE.js.map +1 -0
  13. package/dist/chunk-MZWZQ24W.js +226 -0
  14. package/dist/chunk-MZWZQ24W.js.map +1 -0
  15. package/dist/chunk-OSIFYIQP.js +623 -0
  16. package/dist/chunk-OSIFYIQP.js.map +1 -0
  17. package/dist/chunk-QSSRVK6M.js +139 -0
  18. package/dist/chunk-QSSRVK6M.js.map +1 -0
  19. package/dist/chunk-V7VCHYOY.js +1544 -0
  20. package/dist/chunk-V7VCHYOY.js.map +1 -0
  21. package/dist/{chunk-AN4HJFNP.js → chunk-YVRI7KRC.js} +162 -186
  22. package/dist/chunk-YVRI7KRC.js.map +1 -0
  23. package/dist/client.js +9 -8
  24. package/dist/client.js.map +1 -1
  25. package/dist/core.js +28 -11
  26. package/dist/index.js +11 -4
  27. package/dist/react/AddOpenApiSource.d.ts +2 -13
  28. package/dist/react/GoogleProductPicker.d.ts +9 -0
  29. package/dist/react/OpenApiAccountsPanel.d.ts +6 -0
  30. package/dist/react/OpenApiSourceDetailsFields.d.ts +3 -2
  31. package/dist/react/atoms.d.ts +177 -192
  32. package/dist/react/auth-method-config.d.ts +15 -0
  33. package/dist/react/client.d.ts +103 -224
  34. package/dist/react/index.d.ts +2 -2
  35. package/dist/react/source-plugin.d.ts +2 -2
  36. package/dist/sdk/config.d.ts +75 -0
  37. package/dist/sdk/configure.test.d.ts +1 -0
  38. package/dist/sdk/describe-auth-methods.test.d.ts +1 -0
  39. package/dist/sdk/errors.d.ts +4 -6
  40. package/dist/sdk/extract.d.ts +7 -5
  41. package/dist/sdk/google-bundle.test.d.ts +1 -0
  42. package/dist/sdk/google-discovery.d.ts +43 -0
  43. package/dist/sdk/google-discovery.test.d.ts +1 -0
  44. package/dist/sdk/google-oauth-batches.d.ts +13 -0
  45. package/dist/sdk/google-oauth-batches.test.d.ts +1 -0
  46. package/dist/sdk/google-oauth-scopes.d.ts +3 -0
  47. package/dist/sdk/google-oauth-scopes.test.d.ts +1 -0
  48. package/dist/sdk/google-presets.d.ts +16 -0
  49. package/dist/sdk/google-presets.test.d.ts +1 -0
  50. package/dist/sdk/google-product-picker-scopes.test.d.ts +1 -0
  51. package/dist/sdk/index.d.ts +7 -5
  52. package/dist/sdk/invoke.d.ts +6 -9
  53. package/dist/sdk/openapi-utils.d.ts +1 -0
  54. package/dist/sdk/plugin.d.ts +74 -231
  55. package/dist/sdk/presets.d.ts +2 -1
  56. package/dist/sdk/preview.d.ts +20 -15
  57. package/dist/sdk/query-serialization.test.d.ts +1 -0
  58. package/dist/sdk/store.d.ts +14 -41
  59. package/dist/sdk/types.d.ts +23 -51
  60. package/dist/testing/index.d.ts +49 -38
  61. package/dist/testing.js +46 -18
  62. package/dist/testing.js.map +1 -1
  63. package/package.json +6 -4
  64. package/dist/AddOpenApiSource-NSCULGTM.js +0 -19
  65. package/dist/AddOpenApiSource-NSCULGTM.js.map +0 -1
  66. package/dist/EditOpenApiSource-MV7NYTRP.js +0 -774
  67. package/dist/EditOpenApiSource-MV7NYTRP.js.map +0 -1
  68. package/dist/OpenApiSourceSummary-7JBS7PUV.js +0 -122
  69. package/dist/OpenApiSourceSummary-7JBS7PUV.js.map +0 -1
  70. package/dist/chunk-2ZKKZYZH.js +0 -1181
  71. package/dist/chunk-2ZKKZYZH.js.map +0 -1
  72. package/dist/chunk-AN4HJFNP.js.map +0 -1
  73. package/dist/chunk-BB5IAKRG.js.map +0 -1
  74. package/dist/chunk-PRVJDE43.js +0 -2101
  75. package/dist/chunk-PRVJDE43.js.map +0 -1
  76. package/dist/chunk-X5JX3KTA.js +0 -201
  77. package/dist/chunk-X5JX3KTA.js.map +0 -1
  78. package/dist/react/OpenApiSourceSummary.d.ts +0 -5
  79. package/dist/sdk/credential-status.d.ts +0 -23
  80. package/dist/sdk/source-contracts.d.ts +0 -55
  81. /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