@executor-js/plugin-mcp 1.4.28 → 1.4.30

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 (46) hide show
  1. package/dist/{AddMcpSource-TLAL463B.js → AddMcpSource-3HUBFR3K.js} +68 -141
  2. package/dist/AddMcpSource-3HUBFR3K.js.map +1 -0
  3. package/dist/{EditMcpSource-FAWEECNU.js → EditMcpSource-UVGSSC2R.js} +106 -83
  4. package/dist/EditMcpSource-UVGSSC2R.js.map +1 -0
  5. package/dist/McpSourceSummary-UWVCAJOU.js +171 -0
  6. package/dist/McpSourceSummary-UWVCAJOU.js.map +1 -0
  7. package/dist/api/group.d.ts +92 -180
  8. package/dist/api/index.d.ts +97 -382
  9. package/dist/{chunk-4ORPFRLI.js → chunk-2A4H3UVR.js} +21 -80
  10. package/dist/chunk-2A4H3UVR.js.map +1 -0
  11. package/dist/{chunk-M6REVU6O.js → chunk-3TGDWTNE.js} +14 -40
  12. package/dist/chunk-3TGDWTNE.js.map +1 -0
  13. package/dist/{chunk-NQT7NAGE.js → chunk-H5PLTEMB.js} +673 -713
  14. package/dist/chunk-H5PLTEMB.js.map +1 -0
  15. package/dist/chunk-PZ5AY32C.js +10 -0
  16. package/dist/chunk-PZ5AY32C.js.map +1 -0
  17. package/dist/{chunk-SKSXXFOA.js → chunk-TW44CBXJ.js} +12 -1
  18. package/dist/chunk-TW44CBXJ.js.map +1 -0
  19. package/dist/client.js +5 -4
  20. package/dist/client.js.map +1 -1
  21. package/dist/core.js +4 -6
  22. package/dist/index.js +4 -2
  23. package/dist/promise.d.ts +1 -1
  24. package/dist/react/atoms.d.ts +198 -236
  25. package/dist/react/client.d.ts +91 -179
  26. package/dist/sdk/binding-store.d.ts +3 -163
  27. package/dist/sdk/index.d.ts +2 -2
  28. package/dist/sdk/plugin.d.ts +172 -225
  29. package/dist/sdk/presets.d.ts +1 -0
  30. package/dist/sdk/testing-fixtures.test.d.ts +1 -0
  31. package/dist/sdk/types.d.ts +58 -83
  32. package/dist/{stdio-connector-AA5S6UUJ.js → stdio-connector-MDW6PW36.js} +3 -1
  33. package/dist/{stdio-connector-AA5S6UUJ.js.map → stdio-connector-MDW6PW36.js.map} +1 -1
  34. package/dist/testing/index.d.ts +1 -1
  35. package/dist/testing/server.d.ts +70 -4
  36. package/dist/testing.js +14085 -30
  37. package/dist/testing.js.map +1 -1
  38. package/package.json +3 -4
  39. package/dist/AddMcpSource-TLAL463B.js.map +0 -1
  40. package/dist/EditMcpSource-FAWEECNU.js.map +0 -1
  41. package/dist/McpSourceSummary-257JNETP.js +0 -85
  42. package/dist/McpSourceSummary-257JNETP.js.map +0 -1
  43. package/dist/chunk-4ORPFRLI.js.map +0 -1
  44. package/dist/chunk-M6REVU6O.js.map +0 -1
  45. package/dist/chunk-NQT7NAGE.js.map +0 -1
  46. package/dist/chunk-SKSXXFOA.js.map +0 -1
@@ -3,113 +3,123 @@ import {
3
3
  } from "./chunk-ZIRGIRGP.js";
4
4
  import {
5
5
  mcpSourceAtom,
6
- mcpSourceBindingsAtom,
7
- setMcpSourceBinding,
8
- updateMcpSource
9
- } from "./chunk-4ORPFRLI.js";
10
- import {
11
- McpSourceBindingInput
12
- } from "./chunk-M6REVU6O.js";
6
+ mcpSourceBindingsAtom
7
+ } from "./chunk-2A4H3UVR.js";
8
+ import "./chunk-3TGDWTNE.js";
9
+ import "./chunk-PZ5AY32C.js";
13
10
 
14
11
  // src/react/EditMcpSource.tsx
15
- import { useState } from "react";
12
+ import { useMemo, useState } from "react";
16
13
  import { useAtomValue, useAtomSet } from "@effect/atom-react";
17
14
  import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
18
15
  import * as Exit from "effect/Exit";
19
- import { connectionsAtom } from "@executor-js/react/api/atoms";
20
- import { useScope, useScopeStack } from "@executor-js/react/api/scope-context";
16
+ import {
17
+ configureSource,
18
+ connectionsAtom,
19
+ setSourceCredentialBinding
20
+ } from "@executor-js/react/api/atoms";
21
+ import { useScope, useUserScope } from "@executor-js/react/api/scope-context";
21
22
  import { connectionWriteKeys, sourceWriteKeys } from "@executor-js/react/api/reactivity-keys";
22
23
  import { slugifyNamespace, useSourceIdentity } from "@executor-js/react/plugins/source-identity";
23
24
  import { useCredentialTargetScope } from "@executor-js/react/plugins/credential-target-scope";
24
25
  import { useSecretPickerSecrets } from "@executor-js/react/plugins/use-secret-picker-secrets";
25
26
  import {
26
- HttpCredentialsEditor,
27
- serializeHttpCredentials,
28
- serializeScopedHttpCredentials
27
+ httpCredentialsFromConfiguredCredentialBindings,
28
+ serializeHttpCredentials
29
29
  } from "@executor-js/react/plugins/http-credentials";
30
30
  import {
31
- effectiveCredentialBindingForScope,
32
- httpCredentialsFromConfiguredCredentialBindings,
33
- initialCredentialTargetScope
34
- } from "@executor-js/react/plugins/credential-bindings";
35
- import { SourceOAuthConnectionControl } from "@executor-js/react/plugins/source-oauth-connection";
31
+ useSourceCredentialBindingScopes,
32
+ useSourceCredentialBindingWriter
33
+ } from "@executor-js/react/plugins/source-credential-bindings";
34
+ import {
35
+ SourceOAuthConnectionControl,
36
+ sourceOAuthConnectionUiState
37
+ } from "@executor-js/react/plugins/source-oauth-connection";
36
38
  import { Button } from "@executor-js/react/components/button";
39
+ import {
40
+ CardStack,
41
+ CardStackContent,
42
+ CardStackEntry,
43
+ CardStackEntryContent,
44
+ CardStackEntryDescription,
45
+ CardStackEntryTitle
46
+ } from "@executor-js/react/components/card-stack";
37
47
  import { Badge } from "@executor-js/react/components/badge";
38
- import { ScopeId } from "@executor-js/sdk/core";
48
+ import { ScopeId } from "@executor-js/sdk/shared";
49
+ import {
50
+ SecretCredentialSlotBindings,
51
+ secretCredentialSlotsFromHttpConfig
52
+ } from "@executor-js/react/plugins/credential-slot-bindings";
39
53
  import { jsx, jsxs } from "react/jsx-runtime";
40
54
  function RemoteEditForm(props) {
41
55
  const displayScope = useScope();
42
- const scopeStack = useScopeStack();
56
+ const userScope = useUserScope();
43
57
  const sourceScope = ScopeId.make(props.initial.scope);
44
- const { credentialTargetScope, credentialScopeOptions } = useCredentialTargetScope({
45
- sourceScope,
46
- initialTargetScope: initialCredentialTargetScope(sourceScope, props.bindings)
47
- });
48
58
  const {
49
59
  credentialTargetScope: oauthCredentialTargetScope,
50
60
  setCredentialTargetScope: setOAuthCredentialTargetScope
51
61
  } = useCredentialTargetScope({
52
62
  sourceScope,
53
- initialTargetScope: initialCredentialTargetScope(sourceScope, props.bindings)
63
+ initialTargetScope: userScope
54
64
  });
55
- const doUpdate = useAtomSet(updateMcpSource, { mode: "promiseExit" });
56
- const setBinding = useAtomSet(setMcpSourceBinding, { mode: "promise" });
65
+ const doConfigure = useAtomSet(configureSource, { mode: "promiseExit" });
66
+ const setConnectionBinding = useAtomSet(setSourceCredentialBinding, { mode: "promise" });
57
67
  const secretList = useSecretPickerSecrets();
58
- const connectionsResult = useAtomValue(connectionsAtom(displayScope));
68
+ const connectionsResult = useAtomValue(connectionsAtom(userScope));
59
69
  const identity = useSourceIdentity({
60
70
  fallbackName: props.initial.name,
61
71
  fallbackNamespace: props.initial.namespace
62
72
  });
63
73
  const [endpoint, setEndpoint] = useState(props.initial.config.endpoint);
64
- const [credentials, setCredentials] = useState(
74
+ const credentials = useMemo(
65
75
  () => httpCredentialsFromConfiguredCredentialBindings({
66
76
  headers: props.initial.config.headers,
67
77
  queryParams: props.initial.config.queryParams,
68
78
  bindings: props.bindings
69
- })
79
+ }),
80
+ [props.bindings, props.initial.config.headers, props.initial.config.queryParams]
70
81
  );
71
82
  const [saving, setSaving] = useState(false);
72
83
  const [error, setError] = useState(null);
73
- const [credentialsDirty, setCredentialsDirty] = useState(false);
84
+ const { busyKey, setSecretBinding, clearBinding } = useSourceCredentialBindingWriter({
85
+ displayScope,
86
+ source: { id: props.sourceId, scope: sourceScope },
87
+ onError: setError
88
+ });
74
89
  const identityDirty = identity.name.trim() !== props.initial.name.trim();
75
90
  const metadataDirty = identityDirty || endpoint.trim() !== props.initial.config.endpoint.trim();
76
- const dirty = metadataDirty || credentialsDirty;
91
+ const dirty = metadataDirty;
77
92
  const oauth2 = props.initial.config.auth.kind === "oauth2" ? props.initial.config.auth : null;
78
93
  const connections = AsyncResult.isSuccess(connectionsResult) ? connectionsResult.value : [];
79
- const scopeRanks = new Map(scopeStack.map((scope, index) => [scope.id, index]));
80
- const connectionBinding = oauth2 ? effectiveCredentialBindingForScope(
81
- props.bindings,
82
- oauth2.connectionSlot,
83
- oauthCredentialTargetScope,
84
- scopeRanks
85
- ) : null;
86
- const boundConnectionId = connectionBinding?.value.kind === "connection" ? connectionBinding.value.connectionId : null;
87
- const isConnected = boundConnectionId !== null && connections.some((connection) => connection.id === boundConnectionId);
94
+ const { credentialScopeOptions, secretBindingScopes, scopeRanks } = useSourceCredentialBindingScopes({ sourceScope });
95
+ const secretSlots = secretCredentialSlotsFromHttpConfig({
96
+ headers: props.initial.config.headers,
97
+ queryParams: props.initial.config.queryParams
98
+ });
99
+ const oauthConnectionState = oauth2 ? sourceOAuthConnectionUiState({
100
+ bindings: props.bindings,
101
+ connectionSlot: oauth2.connectionSlot,
102
+ tokenScope: oauthCredentialTargetScope,
103
+ scopeRanks,
104
+ credentialScopeOptions,
105
+ connections
106
+ }) : null;
88
107
  const oauthRequestCredentials = serializeHttpCredentials(credentials);
89
- const handleCredentialsChange = (next) => {
90
- setCredentials(next);
91
- setCredentialsDirty(true);
92
- };
93
108
  const handleSave = async () => {
94
109
  setSaving(true);
95
110
  setError(null);
96
- const { headers, queryParams } = serializeScopedHttpCredentials(
97
- credentials,
98
- credentialTargetScope
99
- );
100
- const payload = {
101
- sourceScope,
111
+ const config = {
102
112
  name: metadataDirty ? identity.name.trim() || void 0 : void 0,
103
113
  endpoint: metadataDirty ? endpoint.trim() || void 0 : void 0
104
114
  };
105
- if (credentialsDirty) {
106
- payload.headers = headers;
107
- payload.queryParams = queryParams;
108
- payload.credentialTargetScope = credentialTargetScope;
109
- }
110
- const exit = await doUpdate({
111
- params: { scopeId: displayScope, namespace: props.sourceId },
112
- payload,
115
+ const exit = await doConfigure({
116
+ params: { scopeId: displayScope },
117
+ payload: {
118
+ source: { id: props.sourceId, scope: sourceScope },
119
+ scope: sourceScope,
120
+ type: "mcp",
121
+ config
122
+ },
113
123
  reactivityKeys: sourceWriteKeys
114
124
  });
115
125
  if (Exit.isFailure(exit)) {
@@ -117,7 +127,6 @@ function RemoteEditForm(props) {
117
127
  setSaving(false);
118
128
  return;
119
129
  }
120
- setCredentialsDirty(false);
121
130
  setSaving(false);
122
131
  props.onSave();
123
132
  };
@@ -145,19 +154,29 @@ function RemoteEditForm(props) {
145
154
  namespaceReadOnly: true
146
155
  }
147
156
  ),
148
- /* @__PURE__ */ jsx(
149
- HttpCredentialsEditor,
150
- {
151
- credentials,
152
- onChange: handleCredentialsChange,
153
- existingSecrets: secretList,
154
- sourceName: identity.name,
155
- targetScope: credentialTargetScope,
156
- credentialScopeOptions,
157
- bindingScopeOptions: credentialScopeOptions
158
- }
159
- ),
160
- oauth2 && /* @__PURE__ */ jsx(
157
+ secretSlots.length > 0 && /* @__PURE__ */ jsx(CardStack, { children: /* @__PURE__ */ jsxs(CardStackContent, { className: "border-t-0", children: [
158
+ /* @__PURE__ */ jsx(CardStackEntry, { children: /* @__PURE__ */ jsxs(CardStackEntryContent, { children: [
159
+ /* @__PURE__ */ jsx(CardStackEntryTitle, { children: "Request credentials" }),
160
+ /* @__PURE__ */ jsx(CardStackEntryDescription, { children: "Headers and query parameters sent with every MCP request." })
161
+ ] }) }),
162
+ /* @__PURE__ */ jsx(
163
+ SecretCredentialSlotBindings,
164
+ {
165
+ slots: secretSlots,
166
+ bindingScopes: secretBindingScopes,
167
+ bindingRows: props.bindings,
168
+ scopeRanks,
169
+ secrets: secretList,
170
+ sourceId: props.sourceId,
171
+ sourceName: identity.name,
172
+ credentialScopeOptions,
173
+ busyKey,
174
+ onSetSecretBinding: setSecretBinding,
175
+ onClearBinding: clearBinding
176
+ }
177
+ )
178
+ ] }) }),
179
+ oauth2 && oauthConnectionState && /* @__PURE__ */ jsx(
161
180
  SourceOAuthConnectionControl,
162
181
  {
163
182
  popupName: "mcp-oauth",
@@ -168,25 +187,28 @@ function RemoteEditForm(props) {
168
187
  tokenScope: oauthCredentialTargetScope,
169
188
  onTokenScopeChange: setOAuthCredentialTargetScope,
170
189
  credentialScopeOptions,
171
- connectionId: boundConnectionId,
190
+ connectionId: oauthConnectionState.connectionId,
172
191
  sourceLabel: `${identity.name.trim() || props.initial.namespace || "MCP"} OAuth`,
173
192
  headers: oauthRequestCredentials.headers,
174
193
  queryParams: oauthRequestCredentials.queryParams,
175
- isConnected,
194
+ isConnected: oauthConnectionState.isConnected,
195
+ buttonIsConnected: oauthConnectionState.buttonIsConnected,
196
+ statusLabel: oauthConnectionState.statusLabel,
176
197
  onConnected: async (connectionId) => {
177
- await setBinding({
198
+ await setConnectionBinding({
178
199
  params: { scopeId: oauthCredentialTargetScope },
179
- payload: McpSourceBindingInput.make({
180
- sourceId: props.sourceId,
181
- sourceScope,
200
+ payload: {
182
201
  scope: oauthCredentialTargetScope,
183
- slot: oauth2.connectionSlot,
202
+ source: { id: props.sourceId, scope: sourceScope },
203
+ slotKey: oauth2.connectionSlot,
184
204
  value: { kind: "connection", connectionId }
185
- }),
205
+ },
186
206
  reactivityKeys: [...sourceWriteKeys, ...connectionWriteKeys]
187
207
  });
188
208
  },
189
209
  reconnectingLabel: "Reconnecting\u2026",
210
+ reconnectLabel: "Reconnect",
211
+ signInLabel: oauthConnectionState.signInLabel,
190
212
  signingInLabel: "Signing in\u2026"
191
213
  }
192
214
  ),
@@ -223,10 +245,11 @@ function EditMcpSource({
223
245
  onSave
224
246
  }) {
225
247
  const scopeId = useScope();
248
+ const userScope = useUserScope();
226
249
  const sourceResult = useAtomValue(mcpSourceAtom(scopeId, sourceId));
227
250
  const source = AsyncResult.isSuccess(sourceResult) && sourceResult.value ? sourceResult.value : null;
228
251
  const sourceScope = source ? ScopeId.make(source.scope) : scopeId;
229
- const bindingsResult = useAtomValue(mcpSourceBindingsAtom(scopeId, sourceId, sourceScope));
252
+ const bindingsResult = useAtomValue(mcpSourceBindingsAtom(userScope, sourceId, sourceScope));
230
253
  if (!AsyncResult.isSuccess(sourceResult) || !source || !AsyncResult.isSuccess(bindingsResult)) {
231
254
  return /* @__PURE__ */ jsx("div", { className: "space-y-6", children: /* @__PURE__ */ jsxs("div", { children: [
232
255
  /* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold text-foreground", children: "Edit MCP Source" }),
@@ -256,4 +279,4 @@ function EditMcpSource({
256
279
  export {
257
280
  EditMcpSource as default
258
281
  };
259
- //# sourceMappingURL=EditMcpSource-FAWEECNU.js.map
282
+ //# sourceMappingURL=EditMcpSource-UVGSSC2R.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react/EditMcpSource.tsx"],"sourcesContent":["import { useMemo, useState } from \"react\";\nimport { useAtomValue, useAtomSet } from \"@effect/atom-react\";\nimport * as AsyncResult from \"effect/unstable/reactivity/AsyncResult\";\nimport * as Exit from \"effect/Exit\";\nimport { mcpSourceAtom, mcpSourceBindingsAtom } from \"./atoms\";\nimport {\n configureSource,\n connectionsAtom,\n setSourceCredentialBinding,\n} from \"@executor-js/react/api/atoms\";\nimport { useScope, useUserScope } from \"@executor-js/react/api/scope-context\";\nimport { connectionWriteKeys, sourceWriteKeys } from \"@executor-js/react/api/reactivity-keys\";\nimport { slugifyNamespace, useSourceIdentity } from \"@executor-js/react/plugins/source-identity\";\nimport { useCredentialTargetScope } from \"@executor-js/react/plugins/credential-target-scope\";\nimport { useSecretPickerSecrets } from \"@executor-js/react/plugins/use-secret-picker-secrets\";\nimport {\n httpCredentialsFromConfiguredCredentialBindings,\n serializeHttpCredentials,\n type HttpCredentialsState,\n} from \"@executor-js/react/plugins/http-credentials\";\nimport {\n useSourceCredentialBindingScopes,\n useSourceCredentialBindingWriter,\n} from \"@executor-js/react/plugins/source-credential-bindings\";\nimport {\n SourceOAuthConnectionControl,\n sourceOAuthConnectionUiState,\n} from \"@executor-js/react/plugins/source-oauth-connection\";\nimport { Button } from \"@executor-js/react/components/button\";\nimport {\n CardStack,\n CardStackContent,\n CardStackEntry,\n CardStackEntryContent,\n CardStackEntryDescription,\n CardStackEntryTitle,\n} from \"@executor-js/react/components/card-stack\";\nimport { Badge } from \"@executor-js/react/components/badge\";\nimport { type CredentialBindingRef, ScopeId } from \"@executor-js/sdk/shared\";\nimport {\n SecretCredentialSlotBindings,\n secretCredentialSlotsFromHttpConfig,\n} from \"@executor-js/react/plugins/credential-slot-bindings\";\nimport { McpRemoteSourceFields } from \"./McpRemoteSourceFields\";\nimport type { McpStoredSourceSchemaType } from \"../sdk/stored-source\";\n\n// ---------------------------------------------------------------------------\n// Remote edit form\n// ---------------------------------------------------------------------------\n\nfunction RemoteEditForm(props: {\n sourceId: string;\n initial: McpStoredSourceSchemaType & { config: { transport: \"remote\" } };\n bindings: readonly CredentialBindingRef[];\n onSave: () => void;\n}) {\n const displayScope = useScope();\n const userScope = useUserScope();\n const sourceScope = ScopeId.make(props.initial.scope);\n const {\n credentialTargetScope: oauthCredentialTargetScope,\n setCredentialTargetScope: setOAuthCredentialTargetScope,\n } = useCredentialTargetScope({\n sourceScope,\n initialTargetScope: userScope,\n });\n const doConfigure = useAtomSet(configureSource, { mode: \"promiseExit\" });\n const setConnectionBinding = useAtomSet(setSourceCredentialBinding, { mode: \"promise\" });\n const secretList = useSecretPickerSecrets();\n const connectionsResult = useAtomValue(connectionsAtom(userScope));\n\n const identity = useSourceIdentity({\n fallbackName: props.initial.name,\n fallbackNamespace: props.initial.namespace,\n });\n const [endpoint, setEndpoint] = useState(props.initial.config.endpoint);\n const credentials = useMemo<HttpCredentialsState>(\n () =>\n httpCredentialsFromConfiguredCredentialBindings({\n headers: props.initial.config.headers,\n queryParams: props.initial.config.queryParams,\n bindings: props.bindings,\n }),\n [props.bindings, props.initial.config.headers, props.initial.config.queryParams],\n );\n const [saving, setSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const { busyKey, setSecretBinding, clearBinding } = useSourceCredentialBindingWriter({\n displayScope,\n source: { id: props.sourceId, scope: sourceScope },\n onError: setError,\n });\n\n const identityDirty = identity.name.trim() !== props.initial.name.trim();\n const metadataDirty = identityDirty || endpoint.trim() !== props.initial.config.endpoint.trim();\n const dirty = metadataDirty;\n const oauth2 = props.initial.config.auth.kind === \"oauth2\" ? props.initial.config.auth : null;\n const connections = AsyncResult.isSuccess(connectionsResult) ? connectionsResult.value : [];\n const { credentialScopeOptions, secretBindingScopes, scopeRanks } =\n useSourceCredentialBindingScopes({ sourceScope });\n const secretSlots = secretCredentialSlotsFromHttpConfig({\n headers: props.initial.config.headers,\n queryParams: props.initial.config.queryParams,\n });\n const oauthConnectionState = oauth2\n ? sourceOAuthConnectionUiState({\n bindings: props.bindings,\n connectionSlot: oauth2.connectionSlot,\n tokenScope: oauthCredentialTargetScope,\n scopeRanks,\n credentialScopeOptions,\n connections,\n })\n : null;\n const oauthRequestCredentials = serializeHttpCredentials(credentials);\n\n const handleSave = async () => {\n setSaving(true);\n setError(null);\n const config: {\n name?: string;\n endpoint?: string;\n } = {\n name: metadataDirty ? identity.name.trim() || undefined : undefined,\n endpoint: metadataDirty ? endpoint.trim() || undefined : undefined,\n };\n const exit = await doConfigure({\n params: { scopeId: displayScope },\n payload: {\n source: { id: props.sourceId, scope: sourceScope },\n scope: sourceScope,\n type: \"mcp\",\n config,\n },\n reactivityKeys: sourceWriteKeys,\n });\n if (Exit.isFailure(exit)) {\n setError(\"Failed to update source\");\n setSaving(false);\n return;\n }\n setSaving(false);\n props.onSave();\n };\n\n return (\n <div className=\"space-y-6\">\n <div>\n <h1 className=\"text-xl font-semibold text-foreground\">Edit MCP Source</h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n Update the endpoint and headers for this MCP connection.\n </p>\n </div>\n\n <div className=\"flex items-center gap-3 rounded-lg border border-border bg-card px-4 py-3\">\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-semibold text-card-foreground\">{props.sourceId}</p>\n </div>\n <Badge variant=\"secondary\" className=\"text-xs\">\n remote\n </Badge>\n </div>\n\n <McpRemoteSourceFields\n url={endpoint}\n onUrlChange={setEndpoint}\n identity={identity}\n preview={{\n name: props.initial.name,\n serverName: props.initial.name,\n connected: true,\n toolCount: null,\n }}\n namespaceReadOnly\n />\n\n {secretSlots.length > 0 && (\n <CardStack>\n <CardStackContent className=\"border-t-0\">\n <CardStackEntry>\n <CardStackEntryContent>\n <CardStackEntryTitle>Request credentials</CardStackEntryTitle>\n <CardStackEntryDescription>\n Headers and query parameters sent with every MCP request.\n </CardStackEntryDescription>\n </CardStackEntryContent>\n </CardStackEntry>\n <SecretCredentialSlotBindings\n slots={secretSlots}\n bindingScopes={secretBindingScopes}\n bindingRows={props.bindings}\n scopeRanks={scopeRanks}\n secrets={secretList}\n sourceId={props.sourceId}\n sourceName={identity.name}\n credentialScopeOptions={credentialScopeOptions}\n busyKey={busyKey}\n onSetSecretBinding={setSecretBinding}\n onClearBinding={clearBinding}\n />\n </CardStackContent>\n </CardStack>\n )}\n\n {oauth2 && oauthConnectionState && (\n <SourceOAuthConnectionControl\n popupName=\"mcp-oauth\"\n pluginId=\"mcp\"\n namespace={slugifyNamespace(props.initial.namespace) || \"mcp\"}\n fallbackNamespace=\"mcp\"\n endpoint={endpoint.trim()}\n tokenScope={oauthCredentialTargetScope}\n onTokenScopeChange={setOAuthCredentialTargetScope}\n credentialScopeOptions={credentialScopeOptions}\n connectionId={oauthConnectionState.connectionId}\n sourceLabel={`${identity.name.trim() || props.initial.namespace || \"MCP\"} OAuth`}\n headers={oauthRequestCredentials.headers}\n queryParams={oauthRequestCredentials.queryParams}\n isConnected={oauthConnectionState.isConnected}\n buttonIsConnected={oauthConnectionState.buttonIsConnected}\n statusLabel={oauthConnectionState.statusLabel}\n onConnected={async (connectionId) => {\n await setConnectionBinding({\n params: { scopeId: oauthCredentialTargetScope },\n payload: {\n scope: oauthCredentialTargetScope,\n source: { id: props.sourceId, scope: sourceScope },\n slotKey: oauth2.connectionSlot,\n value: { kind: \"connection\", connectionId },\n },\n reactivityKeys: [...sourceWriteKeys, ...connectionWriteKeys],\n });\n }}\n reconnectingLabel=\"Reconnecting…\"\n reconnectLabel=\"Reconnect\"\n signInLabel={oauthConnectionState.signInLabel}\n signingInLabel=\"Signing in…\"\n />\n )}\n\n {error && (\n <div className=\"rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2\">\n <p className=\"text-sm text-destructive\">{error}</p>\n </div>\n )}\n\n <div className=\"flex items-center justify-between border-t border-border pt-4\">\n <Button variant=\"ghost\" onClick={props.onSave}>\n Cancel\n </Button>\n <Button onClick={handleSave} disabled={!dirty || saving}>\n {saving ? \"Saving…\" : \"Save changes\"}\n </Button>\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Stdio read-only view\n// ---------------------------------------------------------------------------\n\nfunction StdioReadOnly(props: {\n sourceId: string;\n initial: McpStoredSourceSchemaType & { config: { transport: \"stdio\" } };\n onSave: () => void;\n}) {\n const { command, args } = props.initial.config;\n return (\n <div className=\"space-y-6\">\n <div>\n <h1 className=\"text-xl font-semibold text-foreground\">Edit MCP Source</h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n Stdio MCP sources cannot be edited in the UI. Remove and recreate the source with the\n updated command.\n </p>\n </div>\n\n <div className=\"flex items-center gap-3 rounded-lg border border-border bg-card px-4 py-3\">\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-semibold text-card-foreground\">{props.sourceId}</p>\n <p className=\"mt-0.5 text-xs text-muted-foreground font-mono\">\n {command} {(args ?? []).join(\" \")}\n </p>\n </div>\n <Badge variant=\"secondary\" className=\"text-xs\">\n stdio\n </Badge>\n </div>\n\n <div className=\"flex items-center justify-end border-t border-border pt-4\">\n <Button onClick={props.onSave}>Done</Button>\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Main component\n// ---------------------------------------------------------------------------\n\nexport default function EditMcpSource({\n sourceId,\n onSave,\n}: {\n readonly sourceId: string;\n readonly onSave: () => void;\n}) {\n const scopeId = useScope();\n const userScope = useUserScope();\n const sourceResult = useAtomValue(mcpSourceAtom(scopeId, sourceId)) as AsyncResult.AsyncResult<\n McpStoredSourceSchemaType | null,\n unknown\n >;\n const source =\n AsyncResult.isSuccess(sourceResult) && sourceResult.value ? sourceResult.value : null;\n const sourceScope = source ? ScopeId.make(source.scope) : scopeId;\n const bindingsResult = useAtomValue(mcpSourceBindingsAtom(userScope, sourceId, sourceScope));\n\n if (!AsyncResult.isSuccess(sourceResult) || !source || !AsyncResult.isSuccess(bindingsResult)) {\n return (\n <div className=\"space-y-6\">\n <div>\n <h1 className=\"text-xl font-semibold text-foreground\">Edit MCP Source</h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">Loading configuration…</p>\n </div>\n </div>\n );\n }\n\n if (source.config.transport === \"stdio\") {\n return (\n <StdioReadOnly\n sourceId={sourceId}\n initial={source as McpStoredSourceSchemaType & { config: { transport: \"stdio\" } }}\n onSave={onSave}\n />\n );\n }\n\n return (\n <RemoteEditForm\n sourceId={sourceId}\n initial={source as McpStoredSourceSchemaType & { config: { transport: \"remote\" } }}\n bindings={bindingsResult.value}\n onSave={onSave}\n />\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,171 @@
1
+ import {
2
+ mcpSourceAtom,
3
+ mcpSourceBindingsAtom
4
+ } from "./chunk-2A4H3UVR.js";
5
+ import "./chunk-3TGDWTNE.js";
6
+ import "./chunk-PZ5AY32C.js";
7
+
8
+ // src/react/McpSourceSummary.tsx
9
+ import { useAtomValue as useAtomValue2 } from "@effect/atom-react";
10
+ import * as AsyncResult2 from "effect/unstable/reactivity/AsyncResult";
11
+ import { connectionsAtom as connectionsAtom2 } from "@executor-js/react/api/atoms";
12
+ import { useScope as useScope2, useScopeStack, useUserScope as useUserScope2 } from "@executor-js/react/api/scope-context";
13
+ import { Button } from "@executor-js/react/components/button";
14
+ import {
15
+ SourceCredentialNotice,
16
+ SourceCredentialStatusBadge,
17
+ missingSourceCredentialLabels
18
+ } from "@executor-js/react/plugins/source-credential-status";
19
+ import { ScopeId as ScopeId2 } from "@executor-js/sdk/shared";
20
+
21
+ // src/react/McpSignInButton.tsx
22
+ import { useAtomSet, useAtomValue } from "@effect/atom-react";
23
+ import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
24
+ import { ScopeId } from "@executor-js/sdk/shared";
25
+ import { useScope, useUserScope } from "@executor-js/react/api/scope-context";
26
+ import { connectionWriteKeys, sourceWriteKeys } from "@executor-js/react/api/reactivity-keys";
27
+ import { connectionsAtom, setSourceCredentialBinding } from "@executor-js/react/api/atoms";
28
+ import { SourceOAuthSignInButton } from "@executor-js/react/plugins/oauth-sign-in";
29
+ import { slugifyNamespace } from "@executor-js/react/plugins/source-identity";
30
+ import { secretBackedValuesFromConfiguredCredentialBindings } from "@executor-js/react/plugins/credential-bindings";
31
+ import { jsx } from "react/jsx-runtime";
32
+ function McpSignInButton(props) {
33
+ const scopeId = useScope();
34
+ const userScopeId = useUserScope();
35
+ const sourceResult = useAtomValue(
36
+ mcpSourceAtom(scopeId, props.sourceId)
37
+ );
38
+ const source = AsyncResult.isSuccess(sourceResult) && sourceResult.value ? sourceResult.value : null;
39
+ const sourceScope = source ? ScopeId.make(source.scope) : scopeId;
40
+ const bindingsResult = useAtomValue(
41
+ mcpSourceBindingsAtom(userScopeId, props.sourceId, sourceScope)
42
+ );
43
+ const connectionsResult = useAtomValue(connectionsAtom(userScopeId));
44
+ const setBinding = useAtomSet(setSourceCredentialBinding, { mode: "promise" });
45
+ const remote = source && source.config.transport === "remote" ? source.config : null;
46
+ const oauth2 = remote && remote.auth.kind === "oauth2" ? remote.auth : null;
47
+ const connections = AsyncResult.isSuccess(connectionsResult) ? connectionsResult.value : null;
48
+ const bindings = AsyncResult.isSuccess(bindingsResult) ? bindingsResult.value : null;
49
+ const connectionBinding = bindings?.find(
50
+ (binding) => binding.slotKey === oauth2?.connectionSlot && binding.value.kind === "connection"
51
+ );
52
+ const connectionId = connectionBinding?.value.kind === "connection" ? connectionBinding.value.connectionId : null;
53
+ const isConnected = oauth2 !== null && connections !== null && connectionId !== null && connections.some((c) => c.id === connectionId);
54
+ if (!remote || !oauth2 || !source) return null;
55
+ const namespaceSlug = slugifyNamespace(source.namespace) || "mcp";
56
+ return /* @__PURE__ */ jsx(
57
+ SourceOAuthSignInButton,
58
+ {
59
+ popupName: "mcp-oauth",
60
+ pluginId: "mcp",
61
+ namespace: namespaceSlug,
62
+ fallbackNamespace: "mcp",
63
+ endpoint: remote.endpoint,
64
+ tokenScope: userScopeId,
65
+ connectionId,
66
+ sourceLabel: `${source.name.trim() || source.namespace || "MCP"} OAuth`,
67
+ headers: secretBackedValuesFromConfiguredCredentialBindings(remote.headers, bindings ?? []),
68
+ queryParams: secretBackedValuesFromConfiguredCredentialBindings(
69
+ remote.queryParams,
70
+ bindings ?? []
71
+ ),
72
+ isConnected,
73
+ detectPopupClosed: false,
74
+ onConnected: async (nextConnectionId) => {
75
+ await setBinding({
76
+ params: { scopeId: userScopeId },
77
+ payload: {
78
+ scope: userScopeId,
79
+ source: { id: props.sourceId, scope: sourceScope },
80
+ slotKey: oauth2.connectionSlot,
81
+ value: { kind: "connection", connectionId: nextConnectionId }
82
+ },
83
+ reactivityKeys: [...sourceWriteKeys, ...connectionWriteKeys]
84
+ });
85
+ },
86
+ reconnectingLabel: "Reconnecting\u2026",
87
+ signingInLabel: "Signing in\u2026"
88
+ }
89
+ );
90
+ }
91
+
92
+ // src/react/McpSourceSummary.tsx
93
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
94
+ var sourceCredentialSlots = (source) => {
95
+ if (source.config.transport !== "remote") return [];
96
+ const slots = [];
97
+ for (const [name, value] of Object.entries(source.config.headers ?? {})) {
98
+ if (typeof value !== "string") slots.push({ kind: "secret", slot: value.slot, label: name });
99
+ }
100
+ for (const [name, value] of Object.entries(source.config.queryParams ?? {})) {
101
+ if (typeof value !== "string") slots.push({ kind: "secret", slot: value.slot, label: name });
102
+ }
103
+ const auth = source.config.auth;
104
+ if (auth.kind === "header") {
105
+ slots.push({
106
+ kind: "secret",
107
+ slot: auth.secretSlot,
108
+ label: auth.headerName
109
+ });
110
+ }
111
+ if (auth.kind === "oauth2") {
112
+ if (auth.clientIdSlot) {
113
+ slots.push({ kind: "secret", slot: auth.clientIdSlot, label: "Client ID" });
114
+ }
115
+ if (auth.clientSecretSlot) {
116
+ slots.push({ kind: "secret", slot: auth.clientSecretSlot, label: "Client Secret" });
117
+ }
118
+ slots.push({
119
+ kind: "connection",
120
+ slot: auth.connectionSlot,
121
+ label: "OAuth sign-in"
122
+ });
123
+ }
124
+ return slots;
125
+ };
126
+ function McpSourceSummary(props) {
127
+ const displayScope = useScope2();
128
+ const userScope = useUserScope2();
129
+ const scopeStack = useScopeStack();
130
+ const sourceResult = useAtomValue2(mcpSourceAtom(displayScope, props.sourceId));
131
+ const source = AsyncResult2.isSuccess(sourceResult) && sourceResult.value ? sourceResult.value : null;
132
+ const sourceScope = source ? ScopeId2.make(source.scope) : displayScope;
133
+ const bindingsResult = useAtomValue2(
134
+ mcpSourceBindingsAtom(userScope, props.sourceId, sourceScope)
135
+ );
136
+ const connectionsResult = useAtomValue2(connectionsAtom2(userScope));
137
+ if (!source) return null;
138
+ const slots = sourceCredentialSlots(source);
139
+ if (slots.length === 0) return null;
140
+ if (!AsyncResult2.isSuccess(bindingsResult) || !AsyncResult2.isSuccess(connectionsResult)) {
141
+ return props.variant === "panel" ? null : /* @__PURE__ */ jsx2(SourceCredentialStatusBadge, { missing: ["credentials"] });
142
+ }
143
+ const scopeRanks = new Map(scopeStack.map((scope, index) => [scope.id, index]));
144
+ const liveConnectionIds = new Set(connectionsResult.value.map((connection) => connection.id));
145
+ const missing = missingSourceCredentialLabels({
146
+ slots,
147
+ bindings: bindingsResult.value,
148
+ targetScope: userScope,
149
+ scopeRanks,
150
+ liveConnectionIds
151
+ });
152
+ if (props.variant === "panel") {
153
+ const needsOAuth = missing.includes("OAuth sign-in");
154
+ const needsConfiguration = missing.some((label) => label !== "OAuth sign-in");
155
+ return /* @__PURE__ */ jsx2(
156
+ SourceCredentialNotice,
157
+ {
158
+ missing,
159
+ action: /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [
160
+ needsOAuth && /* @__PURE__ */ jsx2(McpSignInButton, { sourceId: props.sourceId }),
161
+ needsConfiguration && props.onAction && /* @__PURE__ */ jsx2(Button, { type: "button", size: "sm", variant: "outline", onClick: props.onAction, children: "Configure" })
162
+ ] })
163
+ }
164
+ );
165
+ }
166
+ return /* @__PURE__ */ jsx2(SourceCredentialStatusBadge, { missing });
167
+ }
168
+ export {
169
+ McpSourceSummary as default
170
+ };
171
+ //# sourceMappingURL=McpSourceSummary-UWVCAJOU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react/McpSourceSummary.tsx","../src/react/McpSignInButton.tsx"],"sourcesContent":["import { useAtomValue } from \"@effect/atom-react\";\nimport * as AsyncResult from \"effect/unstable/reactivity/AsyncResult\";\n\nimport { connectionsAtom } from \"@executor-js/react/api/atoms\";\nimport { useScope, useScopeStack, useUserScope } from \"@executor-js/react/api/scope-context\";\nimport { Button } from \"@executor-js/react/components/button\";\nimport {\n SourceCredentialNotice,\n SourceCredentialStatusBadge,\n missingSourceCredentialLabels,\n type SourceCredentialSlot,\n} from \"@executor-js/react/plugins/source-credential-status\";\nimport { ScopeId } from \"@executor-js/sdk/shared\";\n\nimport { mcpSourceAtom, mcpSourceBindingsAtom } from \"./atoms\";\nimport McpSignInButton from \"./McpSignInButton\";\nimport type { McpStoredSourceSchemaType } from \"../sdk/stored-source\";\n\nconst sourceCredentialSlots = (\n source: McpStoredSourceSchemaType,\n): readonly SourceCredentialSlot[] => {\n if (source.config.transport !== \"remote\") return [];\n const slots: SourceCredentialSlot[] = [];\n for (const [name, value] of Object.entries(source.config.headers ?? {})) {\n if (typeof value !== \"string\") slots.push({ kind: \"secret\", slot: value.slot, label: name });\n }\n for (const [name, value] of Object.entries(source.config.queryParams ?? {})) {\n if (typeof value !== \"string\") slots.push({ kind: \"secret\", slot: value.slot, label: name });\n }\n const auth = source.config.auth;\n if (auth.kind === \"header\") {\n slots.push({\n kind: \"secret\",\n slot: auth.secretSlot,\n label: auth.headerName,\n });\n }\n if (auth.kind === \"oauth2\") {\n if (auth.clientIdSlot) {\n slots.push({ kind: \"secret\", slot: auth.clientIdSlot, label: \"Client ID\" });\n }\n if (auth.clientSecretSlot) {\n slots.push({ kind: \"secret\", slot: auth.clientSecretSlot, label: \"Client Secret\" });\n }\n slots.push({\n kind: \"connection\",\n slot: auth.connectionSlot,\n label: \"OAuth sign-in\",\n });\n }\n return slots;\n};\n\nexport default function McpSourceSummary(props: {\n readonly sourceId: string;\n readonly variant?: \"badge\" | \"panel\";\n readonly onAction?: () => void;\n}) {\n const displayScope = useScope();\n const userScope = useUserScope();\n const scopeStack = useScopeStack();\n const sourceResult = useAtomValue(mcpSourceAtom(displayScope, props.sourceId));\n const source =\n AsyncResult.isSuccess(sourceResult) && sourceResult.value ? sourceResult.value : null;\n const sourceScope = source ? ScopeId.make(source.scope) : displayScope;\n const bindingsResult = useAtomValue(\n mcpSourceBindingsAtom(userScope, props.sourceId, sourceScope),\n );\n const connectionsResult = useAtomValue(connectionsAtom(userScope));\n\n if (!source) return null;\n const slots = sourceCredentialSlots(source as McpStoredSourceSchemaType);\n if (slots.length === 0) return null;\n if (!AsyncResult.isSuccess(bindingsResult) || !AsyncResult.isSuccess(connectionsResult)) {\n return props.variant === \"panel\" ? null : (\n <SourceCredentialStatusBadge missing={[\"credentials\"]} />\n );\n }\n\n const scopeRanks = new Map(scopeStack.map((scope, index) => [scope.id, index] as const));\n const liveConnectionIds = new Set(connectionsResult.value.map((connection) => connection.id));\n const missing = missingSourceCredentialLabels({\n slots,\n bindings: bindingsResult.value,\n targetScope: userScope,\n scopeRanks,\n liveConnectionIds,\n });\n\n if (props.variant === \"panel\") {\n const needsOAuth = missing.includes(\"OAuth sign-in\");\n const needsConfiguration = missing.some((label) => label !== \"OAuth sign-in\");\n return (\n <SourceCredentialNotice\n missing={missing}\n action={\n <div className=\"flex shrink-0 items-center gap-2\">\n {needsOAuth && <McpSignInButton sourceId={props.sourceId} />}\n {needsConfiguration && props.onAction && (\n <Button type=\"button\" size=\"sm\" variant=\"outline\" onClick={props.onAction}>\n Configure\n </Button>\n )}\n </div>\n }\n />\n );\n }\n\n return <SourceCredentialStatusBadge missing={missing} />;\n}\n","import { useAtomSet, useAtomValue } from \"@effect/atom-react\";\nimport * as AsyncResult from \"effect/unstable/reactivity/AsyncResult\";\n\nimport { ScopeId } from \"@executor-js/sdk/shared\";\nimport { useScope, useUserScope } from \"@executor-js/react/api/scope-context\";\nimport { connectionWriteKeys, sourceWriteKeys } from \"@executor-js/react/api/reactivity-keys\";\nimport { connectionsAtom, setSourceCredentialBinding } from \"@executor-js/react/api/atoms\";\nimport { SourceOAuthSignInButton } from \"@executor-js/react/plugins/oauth-sign-in\";\nimport { slugifyNamespace } from \"@executor-js/react/plugins/source-identity\";\nimport { secretBackedValuesFromConfiguredCredentialBindings } from \"@executor-js/react/plugins/credential-bindings\";\n\nimport { mcpSourceAtom, mcpSourceBindingsAtom } from \"./atoms\";\nimport type { McpStoredSourceSchemaType } from \"../sdk/stored-source\";\n\n// ---------------------------------------------------------------------------\n// McpSignInButton — top-bar action on the source detail page.\n//\n// Reads the source's stored endpoint + oauth2 slot, re-runs the DCR /\n// authorization-code flow against a stable `mcp-oauth2-${namespace}`\n// connection id, and on success writes the user's credential binding.\n// ---------------------------------------------------------------------------\n\nexport default function McpSignInButton(props: { sourceId: string }) {\n const scopeId = useScope();\n const userScopeId = useUserScope();\n const sourceResult = useAtomValue(\n mcpSourceAtom(scopeId, props.sourceId),\n ) as AsyncResult.AsyncResult<McpStoredSourceSchemaType | null, unknown>;\n const source =\n AsyncResult.isSuccess(sourceResult) && sourceResult.value ? sourceResult.value : null;\n const sourceScope = source ? ScopeId.make(source.scope) : scopeId;\n const bindingsResult = useAtomValue(\n mcpSourceBindingsAtom(userScopeId, props.sourceId, sourceScope),\n );\n const connectionsResult = useAtomValue(connectionsAtom(userScopeId));\n const setBinding = useAtomSet(setSourceCredentialBinding, { mode: \"promise\" });\n\n const remote = source && source.config.transport === \"remote\" ? source.config : null;\n const oauth2 = remote && remote.auth.kind === \"oauth2\" ? remote.auth : null;\n const connections = AsyncResult.isSuccess(connectionsResult)\n ? (connectionsResult.value as readonly { readonly id: string }[])\n : null;\n const bindings = AsyncResult.isSuccess(bindingsResult) ? bindingsResult.value : null;\n const connectionBinding = bindings?.find(\n (binding) => binding.slotKey === oauth2?.connectionSlot && binding.value.kind === \"connection\",\n );\n const connectionId =\n connectionBinding?.value.kind === \"connection\" ? connectionBinding.value.connectionId : null;\n const isConnected =\n oauth2 !== null &&\n connections !== null &&\n connectionId !== null &&\n connections.some((c) => c.id === connectionId);\n\n if (!remote || !oauth2 || !source) return null;\n const namespaceSlug = slugifyNamespace(source.namespace) || \"mcp\";\n\n return (\n <SourceOAuthSignInButton\n popupName=\"mcp-oauth\"\n pluginId=\"mcp\"\n namespace={namespaceSlug}\n fallbackNamespace=\"mcp\"\n endpoint={remote.endpoint}\n tokenScope={userScopeId}\n connectionId={connectionId}\n sourceLabel={`${source.name.trim() || source.namespace || \"MCP\"} OAuth`}\n headers={secretBackedValuesFromConfiguredCredentialBindings(remote.headers, bindings ?? [])}\n queryParams={secretBackedValuesFromConfiguredCredentialBindings(\n remote.queryParams,\n bindings ?? [],\n )}\n isConnected={isConnected}\n detectPopupClosed={false}\n onConnected={async (nextConnectionId) => {\n await setBinding({\n params: { scopeId: userScopeId },\n payload: {\n scope: userScopeId,\n source: { id: props.sourceId, scope: sourceScope },\n slotKey: oauth2.connectionSlot,\n value: { kind: \"connection\", connectionId: nextConnectionId },\n },\n reactivityKeys: [...sourceWriteKeys, ...connectionWriteKeys],\n });\n }}\n reconnectingLabel=\"Reconnecting…\"\n signingInLabel=\"Signing in…\"\n />\n );\n}\n"],"mappings":"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","names":["useAtomValue","AsyncResult","connectionsAtom","useScope","useUserScope","ScopeId","jsx","useScope","useUserScope","useAtomValue","ScopeId","connectionsAtom"]}