🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@nimblebrain/synapse

Package Overview
Dependencies
Maintainers
2
Versions
31
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@nimblebrain/synapse - npm Package Compare versions

Comparing version
0.12.0
to
0.12.1
+55
-29
dist/ui/index.cjs

@@ -310,17 +310,19 @@ 'use strict';

var RULES3 = `
.nb-drawer-scrim {
position: fixed; inset: 0; z-index: 1000;
display: flex; background: rgba(0, 0, 0, 0.32);
animation: nb-drawer-fade 200ms ease;
}
.nb-drawer-scrim--right { justify-content: flex-end; }
.nb-drawer-scrim--left { justify-content: flex-start; }
.nb-drawer-scrim--bottom { align-items: flex-end; }
.nb-drawer {
margin: 0; padding: 0; border: none; max-width: 92%;
height: 100%; max-height: 100%; display: flex; flex-direction: column;
outline: none;
}
.nb-drawer--right { margin-left: auto; }
.nb-drawer--left { margin-right: auto; }
.nb-drawer--bottom {
margin-top: auto; width: 100%; max-width: 100%;
height: auto; max-height: 92%;
}
.nb-drawer--right[open] { animation: nb-drawer-in-right 240ms cubic-bezier(0.2, 0, 0, 1); }
.nb-drawer--left[open] { animation: nb-drawer-in-left 240ms cubic-bezier(0.2, 0, 0, 1); }
.nb-drawer--bottom[open] { animation: nb-drawer-in-bottom 240ms cubic-bezier(0.2, 0, 0, 1); }
.nb-drawer::backdrop { background: rgba(0, 0, 0, 0.32); }
.nb-drawer[open]::backdrop { animation: nb-drawer-fade 200ms ease; }
.nb-drawer--bottom { width: 100%; max-width: 100%; height: auto; max-height: 92%; }
.nb-drawer--right { animation: nb-drawer-in-right 240ms cubic-bezier(0.2, 0, 0, 1); }
.nb-drawer--left { animation: nb-drawer-in-left 240ms cubic-bezier(0.2, 0, 0, 1); }
.nb-drawer--bottom { animation: nb-drawer-in-bottom 240ms cubic-bezier(0.2, 0, 0, 1); }
@keyframes nb-drawer-in-right { from { transform: translateX(100%); } }

@@ -347,11 +349,30 @@ @keyframes nb-drawer-in-left { from { transform: translateX(-100%); } }

chunkRX6XCLFF_cjs.ensureStyle(STYLE_ID3, RULES3);
const dialogRef = react.useRef(null);
const panelRef = react.useRef(null);
const labelId = react.useId();
const [hasTitle, setHasTitle] = react.useState(false);
react.useEffect(() => {
const dialog = dialogRef.current;
if (!dialog || typeof dialog.showModal !== "function") return;
if (open && !dialog.open) dialog.showModal();
else if (!open && dialog.open) dialog.close();
if (!open) return;
const onKey = (e) => {
if (e.key === "Escape") {
e.preventDefault();
(onEscape ?? onClose)();
}
};
window.addEventListener("keydown", onKey);
return () => window.removeEventListener("keydown", onKey);
}, [open, onEscape, onClose]);
react.useEffect(() => {
if (!open) return;
const previouslyFocused = document.activeElement;
panelRef.current?.focus();
const { body } = document;
const prevOverflow = body.style.overflow;
body.style.overflow = "hidden";
return () => {
body.style.overflow = prevOverflow;
previouslyFocused?.focus?.();
};
}, [open]);
const ctxValue = react.useMemo(() => ({ labelId, setHasTitle }), [labelId]);
if (!open) return null;
const isBottom = side === "bottom";

@@ -363,22 +384,27 @@ const panelStyle = {

boxShadow: tokens.shadowLg,
outline: "none",
...side === "right" ? { borderLeft: `${tokens.borderWidth} solid ${tokens.border}` } : side === "left" ? { borderRight: `${tokens.borderWidth} solid ${tokens.border}` } : { borderTop: `${tokens.borderWidth} solid ${tokens.border}` },
...style
};
const ctxValue = react.useMemo(() => ({ labelId, setHasTitle }), [labelId]);
return /* @__PURE__ */ jsxRuntime.jsx(DrawerContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsxRuntime.jsx(
"dialog",
"div",
{
ref: dialogRef,
className: `nb-drawer nb-drawer--${side}`,
style: panelStyle,
"aria-labelledby": hasTitle ? labelId : void 0,
onCancel: (e) => {
e.preventDefault();
(onEscape ?? onClose)();
},
className: `nb-drawer-scrim nb-drawer-scrim--${side}`,
onClick: (e) => {
if (e.target === dialogRef.current) onClose();
if (e.target === e.currentTarget) onClose();
},
...rest,
children
children: /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
ref: panelRef,
role: "dialog",
"aria-modal": "true",
"aria-labelledby": hasTitle ? labelId : void 0,
tabIndex: -1,
className: `nb-drawer nb-drawer--${side}`,
style: panelStyle,
...rest,
children
}
)
}

@@ -385,0 +411,0 @@ ) });

import * as react_jsx_runtime from 'react/jsx-runtime';
import { HTMLAttributes, ReactNode, ButtonHTMLAttributes, DialogHTMLAttributes, InputHTMLAttributes, RefObject, CSSProperties, ElementType } from 'react';
import { HTMLAttributes, ReactNode, ButtonHTMLAttributes, InputHTMLAttributes, RefObject, CSSProperties, ElementType } from 'react';

@@ -47,5 +47,5 @@ interface AvatarProps extends Omit<HTMLAttributes<HTMLSpanElement>, "children"> {

type Side$1 = "left" | "right" | "bottom";
interface DrawerProps extends Omit<DialogHTMLAttributes<HTMLDialogElement>, "title" | "onCancel" | "onClick"> {
interface DrawerProps extends Omit<HTMLAttributes<HTMLDivElement>, "onClick"> {
open: boolean;
/** Called by the backdrop and the Header close button. */
/** Called by the scrim and the Header close button. */
onClose: () => void;

@@ -60,3 +60,3 @@ /** Called on Escape. Defaults to `onClose` — override to do something else

}
declare function DrawerRoot({ open, onClose, onEscape, side, width, style, children, ...rest }: DrawerProps): react_jsx_runtime.JSX.Element;
declare function DrawerRoot({ open, onClose, onEscape, side, width, style, children, ...rest }: DrawerProps): react_jsx_runtime.JSX.Element | null;
interface HeaderProps extends Omit<HTMLAttributes<HTMLElement>, "title"> {

@@ -63,0 +63,0 @@ /**

import * as react_jsx_runtime from 'react/jsx-runtime';
import { HTMLAttributes, ReactNode, ButtonHTMLAttributes, DialogHTMLAttributes, InputHTMLAttributes, RefObject, CSSProperties, ElementType } from 'react';
import { HTMLAttributes, ReactNode, ButtonHTMLAttributes, InputHTMLAttributes, RefObject, CSSProperties, ElementType } from 'react';

@@ -47,5 +47,5 @@ interface AvatarProps extends Omit<HTMLAttributes<HTMLSpanElement>, "children"> {

type Side$1 = "left" | "right" | "bottom";
interface DrawerProps extends Omit<DialogHTMLAttributes<HTMLDialogElement>, "title" | "onCancel" | "onClick"> {
interface DrawerProps extends Omit<HTMLAttributes<HTMLDivElement>, "onClick"> {
open: boolean;
/** Called by the backdrop and the Header close button. */
/** Called by the scrim and the Header close button. */
onClose: () => void;

@@ -60,3 +60,3 @@ /** Called on Escape. Defaults to `onClose` — override to do something else

}
declare function DrawerRoot({ open, onClose, onEscape, side, width, style, children, ...rest }: DrawerProps): react_jsx_runtime.JSX.Element;
declare function DrawerRoot({ open, onClose, onEscape, side, width, style, children, ...rest }: DrawerProps): react_jsx_runtime.JSX.Element | null;
interface HeaderProps extends Omit<HTMLAttributes<HTMLElement>, "title"> {

@@ -63,0 +63,0 @@ /**

@@ -308,17 +308,19 @@ import { ensureStyle, injectBaseReset } from '../chunk-3HQGHPNC.js';

var RULES3 = `
.nb-drawer-scrim {
position: fixed; inset: 0; z-index: 1000;
display: flex; background: rgba(0, 0, 0, 0.32);
animation: nb-drawer-fade 200ms ease;
}
.nb-drawer-scrim--right { justify-content: flex-end; }
.nb-drawer-scrim--left { justify-content: flex-start; }
.nb-drawer-scrim--bottom { align-items: flex-end; }
.nb-drawer {
margin: 0; padding: 0; border: none; max-width: 92%;
height: 100%; max-height: 100%; display: flex; flex-direction: column;
outline: none;
}
.nb-drawer--right { margin-left: auto; }
.nb-drawer--left { margin-right: auto; }
.nb-drawer--bottom {
margin-top: auto; width: 100%; max-width: 100%;
height: auto; max-height: 92%;
}
.nb-drawer--right[open] { animation: nb-drawer-in-right 240ms cubic-bezier(0.2, 0, 0, 1); }
.nb-drawer--left[open] { animation: nb-drawer-in-left 240ms cubic-bezier(0.2, 0, 0, 1); }
.nb-drawer--bottom[open] { animation: nb-drawer-in-bottom 240ms cubic-bezier(0.2, 0, 0, 1); }
.nb-drawer::backdrop { background: rgba(0, 0, 0, 0.32); }
.nb-drawer[open]::backdrop { animation: nb-drawer-fade 200ms ease; }
.nb-drawer--bottom { width: 100%; max-width: 100%; height: auto; max-height: 92%; }
.nb-drawer--right { animation: nb-drawer-in-right 240ms cubic-bezier(0.2, 0, 0, 1); }
.nb-drawer--left { animation: nb-drawer-in-left 240ms cubic-bezier(0.2, 0, 0, 1); }
.nb-drawer--bottom { animation: nb-drawer-in-bottom 240ms cubic-bezier(0.2, 0, 0, 1); }
@keyframes nb-drawer-in-right { from { transform: translateX(100%); } }

@@ -345,11 +347,30 @@ @keyframes nb-drawer-in-left { from { transform: translateX(-100%); } }

ensureStyle(STYLE_ID3, RULES3);
const dialogRef = useRef(null);
const panelRef = useRef(null);
const labelId = useId();
const [hasTitle, setHasTitle] = useState(false);
useEffect(() => {
const dialog = dialogRef.current;
if (!dialog || typeof dialog.showModal !== "function") return;
if (open && !dialog.open) dialog.showModal();
else if (!open && dialog.open) dialog.close();
if (!open) return;
const onKey = (e) => {
if (e.key === "Escape") {
e.preventDefault();
(onEscape ?? onClose)();
}
};
window.addEventListener("keydown", onKey);
return () => window.removeEventListener("keydown", onKey);
}, [open, onEscape, onClose]);
useEffect(() => {
if (!open) return;
const previouslyFocused = document.activeElement;
panelRef.current?.focus();
const { body } = document;
const prevOverflow = body.style.overflow;
body.style.overflow = "hidden";
return () => {
body.style.overflow = prevOverflow;
previouslyFocused?.focus?.();
};
}, [open]);
const ctxValue = useMemo(() => ({ labelId, setHasTitle }), [labelId]);
if (!open) return null;
const isBottom = side === "bottom";

@@ -361,22 +382,27 @@ const panelStyle = {

boxShadow: tokens.shadowLg,
outline: "none",
...side === "right" ? { borderLeft: `${tokens.borderWidth} solid ${tokens.border}` } : side === "left" ? { borderRight: `${tokens.borderWidth} solid ${tokens.border}` } : { borderTop: `${tokens.borderWidth} solid ${tokens.border}` },
...style
};
const ctxValue = useMemo(() => ({ labelId, setHasTitle }), [labelId]);
return /* @__PURE__ */ jsx(DrawerContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsx(
"dialog",
"div",
{
ref: dialogRef,
className: `nb-drawer nb-drawer--${side}`,
style: panelStyle,
"aria-labelledby": hasTitle ? labelId : void 0,
onCancel: (e) => {
e.preventDefault();
(onEscape ?? onClose)();
},
className: `nb-drawer-scrim nb-drawer-scrim--${side}`,
onClick: (e) => {
if (e.target === dialogRef.current) onClose();
if (e.target === e.currentTarget) onClose();
},
...rest,
children
children: /* @__PURE__ */ jsx(
"div",
{
ref: panelRef,
role: "dialog",
"aria-modal": "true",
"aria-labelledby": hasTitle ? labelId : void 0,
tabIndex: -1,
className: `nb-drawer nb-drawer--${side}`,
style: panelStyle,
...rest,
children
}
)
}

@@ -383,0 +409,0 @@ ) });

{
"name": "@nimblebrain/synapse",
"version": "0.12.0",
"version": "0.12.1",
"description": "Agent-aware app SDK for the MCP ext-apps protocol",

@@ -5,0 +5,0 @@ "type": "module",

@@ -40,2 +40,6 @@ # @nimblebrain/synapse

**Building a Python MCP server?** The server half — one self-contained `ui://`
component rendered across ChatGPT, Claude, and NimbleBrain — ships as the
[`nimblebrain-synapse`](python/README.md) PyPI package (`pip install nimblebrain-synapse`).
## Package Exports

@@ -117,3 +121,3 @@

```tsx
import { AppProvider, useToolResult, useCallTool, useResize } from "@nimblebrain/synapse/react";
import { AppProvider, useToolResult, useResize } from "@nimblebrain/synapse/react";

@@ -130,3 +134,2 @@ function App() {

const result = useToolResult();
const { call, data, isPending } = useCallTool("list_items");
const resize = useResize();

@@ -342,3 +345,3 @@

| `callTool(name, args?)` | Call an MCP tool and get typed result |
| `callToolAsTask(name, args?, opts?)` | Call a long-running tool task-augmented; returns a `TaskHandle` immediately. See [Long-running tools](#long-running-tools-tasks) below. |
| `callToolAsTask(name, args?, opts?)` | Call a long-running tool task-augmented; returns a `Promise<TaskHandle>`. See [Long-running tools](#long-running-tools-tasks) below. |
| `onDataChanged(cb)` | Subscribe to data change events |

@@ -366,3 +369,3 @@ | `onAction(cb)` | Subscribe to agent actions (typed, declarative) |

```tsx
import { AppProvider, useApp, useToolResult, useToolInput, useResize, useCallTool } from "@nimblebrain/synapse/react";
import { AppProvider, useApp, useToolResult, useToolInput, useResize } from "@nimblebrain/synapse/react";
```

@@ -377,4 +380,5 @@

| `useResize()` | `(w?, h?) => void` | Resize helper — auto-measures body if no args |
| `useCallTool(name)` | `{ call, data, isPending, error }` | Call a tool with loading/error state |
To call a tool on this path, use the `App` instance: `useApp()`, then `app.callTool(name, args)`. The `useCallTool` hook (with built-in loading state) belongs to the `SynapseProvider` set below.
### `SynapseProvider`-based (Legacy)

@@ -381,0 +385,0 @@

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display