@jini-ai/ui 0.4.4 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +20 -0
- package/dist/core/theme/default.d.ts +4 -0
- package/dist/core/theme/default.js +11 -0
- package/dist/core/theme/stylesheet.d.ts +8 -0
- package/dist/core/theme/stylesheet.js +14 -0
- package/dist/core/theme/types.d.ts +39 -0
- package/dist/core/theme/types.js +2 -0
- package/dist/core/theme/validation.d.ts +15 -0
- package/dist/core/theme/validation.js +55 -0
- package/dist/features/admin-widgets/components/Select/Select.d.ts +11 -3
- package/dist/features/admin-widgets/components/Select/Select.hooks.d.ts +8 -13
- package/dist/features/admin-widgets/components/Select/Select.hooks.js +37 -215
- package/dist/features/admin-widgets/components/Select/Select.js +4 -3
- package/dist/features/appearance/constants.js +1 -1
- package/dist/features/connectors/rules.d.ts +1 -6
- package/dist/features/connectors/types.d.ts +1 -6
- package/dist/features/connectors/types.js +1 -6
- package/dist/features/execution/http-adapter.d.ts +111 -0
- package/dist/features/execution/http-adapter.js +160 -0
- package/dist/features/execution/index.d.ts +4 -0
- package/dist/features/execution/index.js +2 -0
- package/dist/features/execution/react/hooks/use-execution-credential.hooks.d.ts +232 -0
- package/dist/features/execution/react/hooks/use-execution-credential.hooks.js +217 -0
- package/dist/features/html-editor/canvas-style.d.ts +1 -1
- package/dist/features/html-editor/canvas-style.js +2 -2
- package/dist/features/i18n/dictionaries/settings-dialog.ar.js +2 -0
- package/dist/features/i18n/dictionaries/settings-dialog.bn.js +2 -0
- package/dist/features/i18n/dictionaries/settings-dialog.de.js +2 -0
- package/dist/features/i18n/dictionaries/settings-dialog.en.js +2 -0
- package/dist/features/i18n/dictionaries/settings-dialog.es.js +2 -0
- package/dist/features/i18n/dictionaries/settings-dialog.fa.js +2 -0
- package/dist/features/i18n/dictionaries/settings-dialog.fr.js +2 -0
- package/dist/features/i18n/dictionaries/settings-dialog.hi.js +2 -0
- package/dist/features/i18n/dictionaries/settings-dialog.hu.js +2 -0
- package/dist/features/i18n/dictionaries/settings-dialog.id.js +2 -0
- package/dist/features/i18n/dictionaries/settings-dialog.it.js +2 -0
- package/dist/features/i18n/dictionaries/settings-dialog.ja.js +2 -0
- package/dist/features/i18n/dictionaries/settings-dialog.ko.js +2 -0
- package/dist/features/i18n/dictionaries/settings-dialog.pl.js +2 -0
- package/dist/features/i18n/dictionaries/settings-dialog.pt-BR.js +2 -0
- package/dist/features/i18n/dictionaries/settings-dialog.ru.js +2 -0
- package/dist/features/i18n/dictionaries/settings-dialog.th.js +2 -0
- package/dist/features/i18n/dictionaries/settings-dialog.tr.js +2 -0
- package/dist/features/i18n/dictionaries/settings-dialog.uk.js +2 -0
- package/dist/features/i18n/dictionaries/settings-dialog.ur.js +2 -0
- package/dist/features/i18n/dictionaries/settings-dialog.zh-CN.js +2 -0
- package/dist/features/i18n/dictionaries/settings-dialog.zh-TW.js +2 -0
- package/dist/features/i18n/dictionary-translator.d.ts +5 -2
- package/dist/features/i18n/dictionary-translator.js +1 -1
- package/dist/features/i18n/index.d.ts +1 -1
- package/dist/features/i18n/index.js +1 -1
- package/dist/features/i18n/template-i18n.d.ts +11 -0
- package/dist/features/i18n/template-i18n.js +12 -0
- package/dist/features/interactive-ui/providers/recharts/chart-tokens.d.ts +1 -1
- package/dist/features/interactive-ui/providers/recharts/chart-tokens.js +1 -1
- package/dist/features/lexical-rich-text-editor/deserialize.d.ts +0 -5
- package/dist/features/lexical-rich-text-editor/deserialize.js +0 -5
- package/dist/features/lexical-rich-text-editor/mention-node.d.ts +5 -17
- package/dist/features/lexical-rich-text-editor/mention-node.js +5 -17
- package/dist/features/lexical-rich-text-editor/mention-parser.d.ts +2 -4
- package/dist/features/lexical-rich-text-editor/serialize.d.ts +0 -4
- package/dist/features/lexical-rich-text-editor/serialize.js +0 -4
- package/dist/features/lexical-rich-text-editor/types.d.ts +3 -13
- package/dist/features/lexical-rich-text-editor/types.js +3 -13
- package/dist/features/mcp-ui/early-message-buffer.d.ts +1 -2
- package/dist/features/mcp-ui/early-message-buffer.js +1 -2
- package/dist/features/mcp-ui/escape.d.ts +4 -0
- package/dist/features/mcp-ui/escape.js +2 -9
- package/dist/features/mcp-ui/index.d.ts +1 -0
- package/dist/features/mcp-ui/index.js +1 -0
- package/dist/features/mcp-ui/protocol.d.ts +2 -5
- package/dist/features/mcp-ui/protocol.js +2 -5
- package/dist/features/mcp-ui/resource.d.ts +47 -7
- package/dist/features/mcp-ui/resource.js +5 -8
- package/dist/features/mcp-ui/secret-card.d.ts +115 -0
- package/dist/features/mcp-ui/secret-card.js +137 -0
- package/dist/features/mcp-ui/surfaces/confirmation.js +5 -0
- package/dist/features/mcp-ui/surfaces/fields.d.ts +5 -2
- package/dist/features/mcp-ui/surfaces/fields.js +3 -1
- package/dist/features/mcp-ui/surfaces/form.d.ts +4 -1
- package/dist/features/mcp-ui/surfaces/form.js +65 -3
- package/dist/features/mcp-ui/surfaces/outcome.d.ts +2 -0
- package/dist/features/mcp-ui/surfaces/text-input.d.ts +14 -6
- package/dist/features/mcp-ui/surfaces/text-input.js +16 -2
- package/dist/features/mcp-ui/surfaces/tokens.js +1 -1
- package/dist/features/memory/react/components/MemoryConnectedPanel.d.ts +1 -1
- package/dist/features/memory/react/components/MemoryConnectedPanel.js +0 -1
- package/dist/features/panel-kit/helpers/format-timestamp.d.ts +5 -3
- package/dist/features/panel-kit/helpers/format-timestamp.js +13 -4
- package/dist/features/panel-kit/helpers/permissions.js +2 -0
- package/dist/features/panel-kit/helpers/resolve-active-tab-id.js +2 -0
- package/dist/features/panel-kit/helpers/standing-draft-local-backup.d.ts +51 -0
- package/dist/features/panel-kit/helpers/standing-draft-local-backup.js +77 -0
- package/dist/features/panel-kit/helpers/standing-draft-recovery-message.d.ts +8 -0
- package/dist/features/panel-kit/helpers/standing-draft-recovery-message.js +10 -0
- package/dist/features/panel-kit/hooks/use-async-action.hooks.d.ts +1 -0
- package/dist/features/panel-kit/hooks/use-dirty-guard.hooks.d.ts +1 -0
- package/dist/features/panel-kit/hooks/use-dirty-guard.hooks.js +1 -0
- package/dist/features/panel-kit/hooks/use-serial-writes.hooks.d.ts +8 -0
- package/dist/features/panel-kit/hooks/use-serial-writes.hooks.js +3 -0
- package/dist/features/panel-kit/hooks/use-settings-slice.hooks.d.ts +211 -0
- package/dist/features/panel-kit/hooks/use-settings-slice.hooks.js +382 -0
- package/dist/features/panel-kit/hooks/use-standing-draft-autosave.hooks.d.ts +179 -0
- package/dist/features/panel-kit/hooks/use-standing-draft-autosave.hooks.js +300 -0
- package/dist/features/panel-kit/index.d.ts +7 -1
- package/dist/features/panel-kit/index.js +5 -1
- package/dist/features/resource-dashboard/types.d.ts +8 -41
- package/dist/features/resource-dashboard/types.js +3 -26
- package/dist/features/tab-strip/constants.d.ts +3 -4
- package/dist/features/tab-strip/constants.js +3 -4
- package/dist/features/tab-strip/dependencies.d.ts +1 -6
- package/dist/features/tab-strip/dependencies.js +1 -6
- package/dist/features/tab-strip/react/components/TabBar.d.ts +33 -1
- package/dist/features/tab-strip/react/components/TabBar.hooks.d.ts +57 -5
- package/dist/features/tab-strip/react/components/TabBar.hooks.js +63 -5
- package/dist/features/tab-strip/react/components/TabBar.js +12 -1
- package/dist/features/tab-strip/rules.d.ts +4 -17
- package/dist/features/tab-strip/rules.js +4 -17
- package/dist/features/tab-strip/types.d.ts +2 -13
- package/dist/icon-name.d.ts +1 -1
- package/dist/icon-name.js +1 -0
- package/dist/index.d.ts +42 -417
- package/dist/index.js +42 -430
- package/dist/react/components/CustomSelect.d.ts +6 -2
- package/dist/react/components/CustomSelect.js +20 -91
- package/dist/react/components/Icon.d.ts +6 -0
- package/dist/react/components/Icon.js +12 -0
- package/dist/react/components/select-popover.d.ts +106 -0
- package/dist/react/components/select-popover.js +210 -0
- package/dist/renderers/sandbox-scripts.d.ts +29 -0
- package/dist/renderers/sandbox-scripts.js +127 -0
- package/dist/renderers/sandboxed-document.js +3 -86
- package/dist/renderers/srcdoc/build.d.ts +10 -17
- package/dist/renderers/srcdoc/build.js +31 -234
- package/dist/styles/variables.css +2 -2
- package/dist/theme/apply.d.ts +1 -1
- package/dist/theme/apply.js +2 -2
- package/dist/theme/color-scheme.d.ts +1 -1
- package/dist/theme/default.d.ts +1 -3
- package/dist/theme/default.js +2 -10
- package/dist/theme/index.d.ts +3 -3
- package/dist/theme/index.js +2 -2
- package/dist/theme/stylesheet.d.ts +1 -7
- package/dist/theme/stylesheet.js +2 -13
- package/dist/theme/types.d.ts +1 -38
- package/dist/theme/types.js +2 -1
- package/dist/theme/validation.d.ts +1 -14
- package/dist/theme/validation.js +2 -54
- package/dist/utils/endpoint-policy.d.ts +21 -39
- package/dist/utils/endpoint-policy.js +19 -107
- package/dist/utils/file-system-errors.d.ts +1 -2
- package/dist/utils/file-system-errors.js +1 -2
- package/dist/utils/ime-composing.d.ts +0 -3
- package/dist/utils/ime-composing.js +0 -3
- package/dist/utils/platform.d.ts +1 -4
- package/dist/utils/platform.js +1 -4
- package/dist/utils/smooth-scroll-to-top.d.ts +1 -3
- package/dist/utils/smooth-scroll-to-top.js +3 -13
- package/dist/utils/timezone.js +1 -5
- package/dist/utils/uuid.d.ts +0 -3
- package/dist/utils/uuid.js +0 -3
- package/dist/utils/visual-stability.d.ts +1 -3
- package/dist/utils/visual-stability.js +1 -3
- package/package.json +74 -15
|
@@ -1,21 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* Origin: `apps/web/src/components/composer/MentionNode.ts`. The origin
|
|
9
|
-
* imported OD's `connectorBrandColor`/`resolveBrandTheme` directly to color
|
|
10
|
-
* a `connector`-kind pill's `--m-hue` CSS custom property, and installed a
|
|
11
|
-
* document-wide `MutationObserver` to re-stamp every mounted pill on a live
|
|
12
|
-
* theme flip. Both are dropped from this node entirely — no per-instance
|
|
13
|
-
* color logic and no global observer belong on a generic Lexical node class.
|
|
14
|
-
* A host that wants per-kind/per-entity coloring supplies a
|
|
15
|
-
* `resolveMentionColor` callback to `RichTextInput`, applied by
|
|
16
|
-
* `react/hooks/useMentionColorStamping.ts` via Lexical's own
|
|
17
|
-
* `registerMutationListener` (scoped to that one editor instance, not the
|
|
18
|
-
* whole document) — see that file for the replacement mechanism.
|
|
2
|
+
* Atomic @mention extends TextNode so getTextContent preserves the wire token. Token mode deletes
|
|
3
|
+
* one entity but still permits character-level caret movement; rules.ts normalizes arrow navigation.
|
|
4
|
+
* Generic nodes own no brand resolution or document-wide observer. Host colors enter through
|
|
5
|
+
* RichTextInput.resolveMentionColor and an editor-scoped Lexical mutation listener; see
|
|
6
|
+
* react/hooks/useMentionColorStamping.ts.
|
|
19
7
|
*/
|
|
20
8
|
import { TextNode, } from 'lexical';
|
|
21
9
|
export class MentionNode extends TextNode {
|
|
@@ -5,10 +5,8 @@
|
|
|
5
5
|
* mention nodes, and available to hosts that need the same rule to fold
|
|
6
6
|
* plain-text-typed `@token`s into a "currently referenced" entity list.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* surface was `InlineMentionKind`'s fixed union, replaced by `MentionEntity`'s
|
|
11
|
-
* free-form `kind: string` (see `types.ts`).
|
|
8
|
+
* Trie lookup prefers the longest token subject to left/right boundaries. MentionEntity.kind
|
|
9
|
+
* is host-defined rather than a fixed product vocabulary.
|
|
12
10
|
*/
|
|
13
11
|
import type { MentionEntity, MentionPart } from './types.js';
|
|
14
12
|
export declare function buildMentionToken(label: string): string;
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Origin: `apps/web/src/components/composer/serialize.ts`. Ported verbatim —
|
|
3
|
-
* no OD-specific surface (it only ever touched the generic `MentionNode`).
|
|
4
|
-
*/
|
|
5
1
|
import { type EditorState } from 'lexical';
|
|
6
2
|
import type { SerializedRichText } from './types.js';
|
|
7
3
|
export declare function serializeRichText(state: EditorState): SerializedRichText;
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Origin: `apps/web/src/components/composer/serialize.ts`. Ported verbatim —
|
|
3
|
-
* no OD-specific surface (it only ever touched the generic `MentionNode`).
|
|
4
|
-
*/
|
|
5
1
|
import { $getRoot, $isElementNode, $isLineBreakNode, $isParagraphNode, $isTextNode, } from 'lexical';
|
|
6
2
|
import { $isMentionNode } from './mention-node.js';
|
|
7
3
|
// Walk the tree by hand rather than calling `root.getTextContent()`, which
|
|
@@ -1,16 +1,6 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* the origin used Lexical's `PlainTextPlugin`, not `RichTextPlugin`).
|
|
5
|
-
*
|
|
6
|
-
* Origin: `apps/web/src/components/composer/*` (OD's chat composer). The
|
|
7
|
-
* only OD-specific piece was the `@mention` pill's brand color, resolved
|
|
8
|
-
* via a direct import of OD's connector-brand-theme logic — replaced here
|
|
9
|
-
* by a host-injected `resolveMentionColor` callback (see
|
|
10
|
-
* `react/hooks/useMentionColorStamping.ts`). Everything else (trigger
|
|
11
|
-
* detection, atomic-node keyboard navigation, caret-floating-layer
|
|
12
|
-
* positioning, serialize/deserialize) is genuinely generic and ported as-is.
|
|
13
|
-
*/
|
|
1
|
+
/** PlainTextPlugin-backed editing with atomic mentions, rather than block/mark rich text.
|
|
2
|
+
* Mention colors are host-injected through resolveMentionColor; generic trigger/navigation/caret
|
|
3
|
+
* and wire serialization rules stay independent of a product's connector branding. */
|
|
14
4
|
/** A single mention-able entity: any host-owned capability/entity with a
|
|
15
5
|
* stable id, a display label, and a free-form category ("kind"). Unlike
|
|
16
6
|
* the origin's fixed `plugin | skill | mcp | file | workspace | connector`
|
|
@@ -1,15 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* the origin used Lexical's `PlainTextPlugin`, not `RichTextPlugin`).
|
|
5
|
-
*
|
|
6
|
-
* Origin: `apps/web/src/components/composer/*` (OD's chat composer). The
|
|
7
|
-
* only OD-specific piece was the `@mention` pill's brand color, resolved
|
|
8
|
-
* via a direct import of OD's connector-brand-theme logic — replaced here
|
|
9
|
-
* by a host-injected `resolveMentionColor` callback (see
|
|
10
|
-
* `react/hooks/useMentionColorStamping.ts`). Everything else (trigger
|
|
11
|
-
* detection, atomic-node keyboard navigation, caret-floating-layer
|
|
12
|
-
* positioning, serialize/deserialize) is genuinely generic and ported as-is.
|
|
13
|
-
*/
|
|
1
|
+
/** PlainTextPlugin-backed editing with atomic mentions, rather than block/mark rich text.
|
|
2
|
+
* Mention colors are host-injected through resolveMentionColor; generic trigger/navigation/caret
|
|
3
|
+
* and wire serialization rules stay independent of a product's connector branding. */
|
|
14
4
|
export {};
|
|
15
5
|
//# sourceMappingURL=types.js.map
|
|
@@ -16,8 +16,7 @@
|
|
|
16
16
|
* DOM types and no React, so it is testable in a plain Node environment. The module-scope
|
|
17
17
|
* `window.addEventListener` that feeds it belongs to the React half; see
|
|
18
18
|
* `../../react/mcp-ui/host-message-source.ts`.
|
|
19
|
-
|
|
20
|
-
* Ported from `examples/reference-web/src/mcpui-lab-message-buffer.ts` unchanged in behavior.
|
|
19
|
+
|
|
21
20
|
*/
|
|
22
21
|
/**
|
|
23
22
|
* A raw `MessageEvent`, narrowed to the fields this module needs. `source` stays `unknown` (rather
|
|
@@ -16,8 +16,7 @@
|
|
|
16
16
|
* DOM types and no React, so it is testable in a plain Node environment. The module-scope
|
|
17
17
|
* `window.addEventListener` that feeds it belongs to the React half; see
|
|
18
18
|
* `../../react/mcp-ui/host-message-source.ts`.
|
|
19
|
-
|
|
20
|
-
* Ported from `examples/reference-web/src/mcpui-lab-message-buffer.ts` unchanged in behavior.
|
|
19
|
+
|
|
21
20
|
*/
|
|
22
21
|
/**
|
|
23
22
|
* Bound so a hostile or confused page flooding `postMessage` at a tab that never subscribes cannot
|
|
@@ -47,5 +47,9 @@ export declare function escapeJsValue(value: unknown): string;
|
|
|
47
47
|
* `string`-typed signature makes a caller that accidentally passes an object a compile error rather
|
|
48
48
|
* than a silently-inlined `[object Object]`-free-but-surprising literal.
|
|
49
49
|
*/
|
|
50
|
+
export declare function escapeJsString(required: {
|
|
51
|
+
value: string;
|
|
52
|
+
}, optional?: {}): string;
|
|
53
|
+
/** Existing string call retained for published surface builders. */
|
|
50
54
|
export declare function escapeJsString(value: string): string;
|
|
51
55
|
//# sourceMappingURL=escape.d.ts.map
|
|
@@ -55,14 +55,7 @@ export function escapeJsValue(value) {
|
|
|
55
55
|
.replace(/\u2028/g, '\\u2028')
|
|
56
56
|
.replace(/\u2029/g, '\\u2029');
|
|
57
57
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
*
|
|
61
|
-
* Kept as its own export because the overwhelmingly common call is "inline this one string", and a
|
|
62
|
-
* `string`-typed signature makes a caller that accidentally passes an object a compile error rather
|
|
63
|
-
* than a silently-inlined `[object Object]`-free-but-surprising literal.
|
|
64
|
-
*/
|
|
65
|
-
export function escapeJsString(value) {
|
|
66
|
-
return escapeJsValue(value);
|
|
58
|
+
export function escapeJsString(required, _optional = {}) {
|
|
59
|
+
return escapeJsValue(typeof required === "string" ? required : required.value);
|
|
67
60
|
}
|
|
68
61
|
//# sourceMappingURL=escape.js.map
|
|
@@ -23,6 +23,7 @@ export * from './early-message-buffer.js';
|
|
|
23
23
|
export * from './escape.js';
|
|
24
24
|
export * from './protocol.js';
|
|
25
25
|
export * from './resource.js';
|
|
26
|
+
export * from './secret-card.js';
|
|
26
27
|
export * from './sandbox-proxy.js';
|
|
27
28
|
export * from './surfaces/index.js';
|
|
28
29
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -23,6 +23,7 @@ export * from './early-message-buffer.js';
|
|
|
23
23
|
export * from './escape.js';
|
|
24
24
|
export * from './protocol.js';
|
|
25
25
|
export * from './resource.js';
|
|
26
|
+
export * from './secret-card.js';
|
|
26
27
|
export * from './sandbox-proxy.js';
|
|
27
28
|
export * from './surfaces/index.js';
|
|
28
29
|
//# sourceMappingURL=index.js.map
|
|
@@ -4,11 +4,8 @@
|
|
|
4
4
|
* The MCP Apps wire vocabulary, re-exported from `@jini-ai/agentic`'s `mcp-ui-apps.ts` rather than
|
|
5
5
|
* restated here.
|
|
6
6
|
*
|
|
7
|
-
* `mcp-ui-apps.ts`
|
|
8
|
-
*
|
|
9
|
-
* it already carries the two things a second copy would immediately lose: the audit history for
|
|
10
|
-
* which lifecycle messages travel in which direction, and `isJsonRpcMessage`'s hardening against
|
|
11
|
-
* malformed `postMessage` input found by live adversarial testing. Duplicating any of it would
|
|
7
|
+
* `mcp-ui-apps.ts` owns message direction and isJsonRpcMessage's malformed-postMessage guards.
|
|
8
|
+
* Duplicating those rules would
|
|
12
9
|
* create a second surface to keep in sync with a moving spec, so this module owns nothing of the
|
|
13
10
|
* envelope — it only re-exports it, plus adds the one constant that genuinely belongs to *this*
|
|
14
11
|
* package: {@link MCP_UI_VIEW_SANDBOX}.
|
|
@@ -4,11 +4,8 @@
|
|
|
4
4
|
* The MCP Apps wire vocabulary, re-exported from `@jini-ai/agentic`'s `mcp-ui-apps.ts` rather than
|
|
5
5
|
* restated here.
|
|
6
6
|
*
|
|
7
|
-
* `mcp-ui-apps.ts`
|
|
8
|
-
*
|
|
9
|
-
* it already carries the two things a second copy would immediately lose: the audit history for
|
|
10
|
-
* which lifecycle messages travel in which direction, and `isJsonRpcMessage`'s hardening against
|
|
11
|
-
* malformed `postMessage` input found by live adversarial testing. Duplicating any of it would
|
|
7
|
+
* `mcp-ui-apps.ts` owns message direction and isJsonRpcMessage's malformed-postMessage guards.
|
|
8
|
+
* Duplicating those rules would
|
|
12
9
|
* create a second surface to keep in sync with a moving spec, so this module owns nothing of the
|
|
13
10
|
* envelope — it only re-exports it, plus adds the one constant that genuinely belongs to *this*
|
|
14
11
|
* package: {@link MCP_UI_VIEW_SANDBOX}.
|
|
@@ -12,11 +12,8 @@
|
|
|
12
12
|
* ``ui://${string}`` URI scheme and the wider MIME union reproduced in
|
|
13
13
|
* {@link UIResourceMimeType}.
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
* JSON-RPC
|
|
17
|
-
* because its tsconfig's
|
|
18
|
-
* `moduleResolution: "Node"` cannot read a modern package's `exports` map, and this package has no
|
|
19
|
-
* such constraint — the envelope comes from `protocol.ts`'s re-exports instead. See
|
|
15
|
+
* The envelope comes from protocol.ts's re-exports, so this resource layer has no parallel
|
|
16
|
+
* JSON-RPC or UIActionResult definition. See
|
|
20
17
|
* `surfaces/bridge.ts` for why the legacy `{type:'tool', payload}` action shape is not emitted.
|
|
21
18
|
*/
|
|
22
19
|
/** The `ui://` URI scheme MCP Apps fixes for UI resources. */
|
|
@@ -153,7 +150,7 @@ export declare function createUIResource(spec: {
|
|
|
153
150
|
actionPlan?: McpUiActionPlan;
|
|
154
151
|
expiresAtMs?: number;
|
|
155
152
|
meta?: Readonly<Record<string, unknown>>;
|
|
156
|
-
}): UIResource;
|
|
153
|
+
}, _optional?: {}): UIResource;
|
|
157
154
|
/**
|
|
158
155
|
* Assembles the two-part tool result: what the MODEL is told, and what the HUMAN is shown.
|
|
159
156
|
*
|
|
@@ -167,7 +164,7 @@ export declare function buildUIToolResult(spec: {
|
|
|
167
164
|
modelText: string;
|
|
168
165
|
ui: UIResource;
|
|
169
166
|
meta?: Readonly<Record<string, unknown>>;
|
|
170
|
-
}): UIToolResult;
|
|
167
|
+
}, _optional?: {}): UIToolResult;
|
|
171
168
|
/**
|
|
172
169
|
* Narrows an arbitrary value to a {@link UIResource}.
|
|
173
170
|
*
|
|
@@ -209,4 +206,47 @@ export declare function readActionPlan(resource: UIResource): McpUiActionPlan |
|
|
|
209
206
|
* @complexity O(1).
|
|
210
207
|
*/
|
|
211
208
|
export declare function readExpiresAt(resource: UIResource): number | undefined;
|
|
209
|
+
/** Legacy host action vocabulary retained for consumers that negotiate pre-Apps messages. */
|
|
210
|
+
export type UIActionType = "tool" | "prompt" | "link" | "intent" | "notify";
|
|
211
|
+
/**
|
|
212
|
+
* mcp-ui's `UIActionResult` union — the `postMessage` payload an iframe sends to the host.
|
|
213
|
+
*
|
|
214
|
+
* `messageId` is what makes the round trip observable: mcp-ui's client answers a message carrying
|
|
215
|
+
* one with `ui-message-received` and then `ui-message-response` (same `messageId`). A host's
|
|
216
|
+
* confirmation dialog sets one so the rendered UI can show "deleted" or an error instead of
|
|
217
|
+
* silently appearing to do nothing.
|
|
218
|
+
*/
|
|
219
|
+
export type UIActionResult = {
|
|
220
|
+
messageId?: string;
|
|
221
|
+
type: "tool";
|
|
222
|
+
payload: {
|
|
223
|
+
toolName: string;
|
|
224
|
+
params: Record<string, unknown>;
|
|
225
|
+
};
|
|
226
|
+
} | {
|
|
227
|
+
messageId?: string;
|
|
228
|
+
type: "prompt";
|
|
229
|
+
payload: {
|
|
230
|
+
prompt: string;
|
|
231
|
+
};
|
|
232
|
+
} | {
|
|
233
|
+
messageId?: string;
|
|
234
|
+
type: "link";
|
|
235
|
+
payload: {
|
|
236
|
+
url: string;
|
|
237
|
+
};
|
|
238
|
+
} | {
|
|
239
|
+
messageId?: string;
|
|
240
|
+
type: "intent";
|
|
241
|
+
payload: {
|
|
242
|
+
intent: string;
|
|
243
|
+
params: Record<string, unknown>;
|
|
244
|
+
};
|
|
245
|
+
} | {
|
|
246
|
+
messageId?: string;
|
|
247
|
+
type: "notify";
|
|
248
|
+
payload: {
|
|
249
|
+
message: string;
|
|
250
|
+
};
|
|
251
|
+
};
|
|
212
252
|
//# sourceMappingURL=resource.d.ts.map
|
|
@@ -12,11 +12,8 @@
|
|
|
12
12
|
* ``ui://${string}`` URI scheme and the wider MIME union reproduced in
|
|
13
13
|
* {@link UIResourceMimeType}.
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
* JSON-RPC
|
|
17
|
-
* because its tsconfig's
|
|
18
|
-
* `moduleResolution: "Node"` cannot read a modern package's `exports` map, and this package has no
|
|
19
|
-
* such constraint — the envelope comes from `protocol.ts`'s re-exports instead. See
|
|
15
|
+
* The envelope comes from protocol.ts's re-exports, so this resource layer has no parallel
|
|
16
|
+
* JSON-RPC or UIActionResult definition. See
|
|
20
17
|
* `surfaces/bridge.ts` for why the legacy `{type:'tool', payload}` action shape is not emitted.
|
|
21
18
|
*/
|
|
22
19
|
/**
|
|
@@ -94,7 +91,7 @@ export const MCP_UI_EXPIRES_AT_META_KEY = `${JINI_MCP_UI_METADATA_PREFIX}expires
|
|
|
94
91
|
* @returns The `EmbeddedResource` to place in a tool result's `content` array.
|
|
95
92
|
* @complexity O(1).
|
|
96
93
|
*/
|
|
97
|
-
export function createUIResource(spec) {
|
|
94
|
+
export function createUIResource(spec, _optional = {}) {
|
|
98
95
|
const meta = {
|
|
99
96
|
...(spec.preferredFrameSize === undefined
|
|
100
97
|
? {}
|
|
@@ -109,7 +106,7 @@ export function createUIResource(spec) {
|
|
|
109
106
|
uri: spec.uri,
|
|
110
107
|
mimeType: MCP_UI_MIME_TYPE,
|
|
111
108
|
text: spec.htmlString,
|
|
112
|
-
...(Object.keys(meta).length === 0 ? {} : { _meta: meta }),
|
|
109
|
+
...(Object.keys(meta).length === 0 && spec.meta === undefined ? {} : { _meta: meta }),
|
|
113
110
|
},
|
|
114
111
|
};
|
|
115
112
|
}
|
|
@@ -122,7 +119,7 @@ export function createUIResource(spec) {
|
|
|
122
119
|
* @param spec.meta - Optional result-level `_meta`.
|
|
123
120
|
* @complexity O(1).
|
|
124
121
|
*/
|
|
125
|
-
export function buildUIToolResult(spec) {
|
|
122
|
+
export function buildUIToolResult(spec, _optional = {}) {
|
|
126
123
|
return {
|
|
127
124
|
content: [{ type: 'text', text: spec.modelText }, spec.ui],
|
|
128
125
|
...(spec.meta === undefined ? {} : { _meta: spec.meta }),
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One human-only secret-card lifecycle. Keystrokes go directly to the held exchange and save
|
|
3
|
+
* port, never through model input, chat text, or logs. Saved values must stay in the host's
|
|
4
|
+
* sealed store; save returns only a safe summary for result/outcome projections.
|
|
5
|
+
*
|
|
6
|
+
* Fail closed without an emitter: returning a form or accepting a second model call would
|
|
7
|
+
* strand the held call or route a secret through model context. Cancel posts a dismissal so
|
|
8
|
+
* the call wakes immediately instead of waiting for its TTL. askThenReport keeps the exchange
|
|
9
|
+
* open until the real save finishes; reusing the form URI replaces premature "Done." with its
|
|
10
|
+
* actual outcome. The host supplies the daemon's existing helper, never a second store.
|
|
11
|
+
*/
|
|
12
|
+
import { type SurfaceAskThenReport, type SurfaceExchangeStore, type ToolExecutionContext, type ToolExecutionOptions } from '@jini-ai/core';
|
|
13
|
+
import { type FormSurfaceSpec } from './surfaces/form.js';
|
|
14
|
+
import { type SurfaceOutcomeSpec } from './surfaces/outcome.js';
|
|
15
|
+
import type { StringField, SurfaceField } from './surfaces/fields.js';
|
|
16
|
+
/** Secret fields cannot carry a value, even through a previously declared variable.
|
|
17
|
+
* `allowBlank` permits an empty string for stored-value preservation or public-client auth. */
|
|
18
|
+
export type SecretCardField = (SurfaceField & {
|
|
19
|
+
readonly secret?: false;
|
|
20
|
+
}) | (Omit<StringField, 'value' | 'secret'> & {
|
|
21
|
+
readonly secret: true;
|
|
22
|
+
readonly value?: never;
|
|
23
|
+
readonly allowBlank?: boolean;
|
|
24
|
+
});
|
|
25
|
+
/** The host controls copy, field construction and display; routing/dismissal belong to the engine. */
|
|
26
|
+
export type SecretCardForm = Omit<FormSurfaceSpec, 'fields' | 'toolName' | 'baseParams' | 'cancel'> & {
|
|
27
|
+
readonly fields: readonly SecretCardField[];
|
|
28
|
+
readonly cancelLabel?: string;
|
|
29
|
+
};
|
|
30
|
+
export type SecretCardRun<Saved> = {
|
|
31
|
+
readonly status: 'saved';
|
|
32
|
+
readonly saved: Saved;
|
|
33
|
+
} | {
|
|
34
|
+
readonly status: 'cancelled';
|
|
35
|
+
} | {
|
|
36
|
+
readonly status: 'expired';
|
|
37
|
+
} | {
|
|
38
|
+
readonly status: 'abandoned';
|
|
39
|
+
} | {
|
|
40
|
+
readonly status: 'blank';
|
|
41
|
+
} | {
|
|
42
|
+
readonly status: 'failed';
|
|
43
|
+
readonly safeMessage: string;
|
|
44
|
+
};
|
|
45
|
+
/** A domain spec, with authorization and target resolution in prepare and persistence in save.
|
|
46
|
+
* Projections must contain safe metadata only. Neither projection receives the submitted values. */
|
|
47
|
+
export interface SecretCardSpec<Prep, Saved, Result> {
|
|
48
|
+
readonly toolId: string;
|
|
49
|
+
/** Validate public model input, authorize and resolve the target before opening a card.
|
|
50
|
+
* Reject secret-bearing input; never read stored plaintext for form construction. */
|
|
51
|
+
prepare(required: {
|
|
52
|
+
ctx: ToolExecutionContext;
|
|
53
|
+
}): Promise<Prep>;
|
|
54
|
+
form(required: {
|
|
55
|
+
prep: Prep;
|
|
56
|
+
}): SecretCardForm;
|
|
57
|
+
/** Only declared field names are forwarded. Domain validation remains authoritative.
|
|
58
|
+
* Values keep their native field types and exact bytes; stored secrets are never needed here. */
|
|
59
|
+
save(required: {
|
|
60
|
+
values: Readonly<Record<string, unknown>>;
|
|
61
|
+
prep: Prep;
|
|
62
|
+
signal: AbortSignal;
|
|
63
|
+
}): Promise<Saved>;
|
|
64
|
+
/** Return undefined for cancellation/expiry when the form already reports that state locally. */
|
|
65
|
+
outcome(required: {
|
|
66
|
+
prep: Prep;
|
|
67
|
+
run: SecretCardRun<Saved>;
|
|
68
|
+
}): SurfaceOutcomeSpec | undefined;
|
|
69
|
+
result(required: {
|
|
70
|
+
prep: Prep;
|
|
71
|
+
run: SecretCardRun<Saved>;
|
|
72
|
+
}): Result;
|
|
73
|
+
}
|
|
74
|
+
export interface SecretCardText {
|
|
75
|
+
readonly noEmitter?: string;
|
|
76
|
+
readonly saveFailure?: string;
|
|
77
|
+
readonly cancelLabel?: string;
|
|
78
|
+
}
|
|
79
|
+
export interface SecretCardOptions {
|
|
80
|
+
/** Allowlist known error kinds to fixed text. Never return raw error.message. */
|
|
81
|
+
readonly safeError?: (error: unknown) => string | undefined;
|
|
82
|
+
readonly text?: SecretCardText;
|
|
83
|
+
readonly frameSize?: readonly [string, string];
|
|
84
|
+
readonly uriHost?: string;
|
|
85
|
+
/** Fixed metadata only: errors and submitted values are deliberately absent. */
|
|
86
|
+
readonly logFailure?: (metadata: {
|
|
87
|
+
toolId: string;
|
|
88
|
+
exchangeId: string;
|
|
89
|
+
saved: false;
|
|
90
|
+
}) => void;
|
|
91
|
+
}
|
|
92
|
+
export interface SecretCardDeps {
|
|
93
|
+
readonly surfaceExchanges: Pick<SurfaceExchangeStore, 'open'>;
|
|
94
|
+
readonly askThenReport: SurfaceAskThenReport;
|
|
95
|
+
}
|
|
96
|
+
export type SecretCardHandler<Result> = (required: ToolExecutionContext, optional?: ToolExecutionOptions) => Promise<Result>;
|
|
97
|
+
export interface SecretCardTool<Prep, Result> {
|
|
98
|
+
readonly toolId: string;
|
|
99
|
+
secretFieldNames(prep: Prep): string[];
|
|
100
|
+
handler(deps: SecretCardDeps): SecretCardHandler<Result>;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Define a secret card once; inject the exchange store and daemon askThenReport at composition.
|
|
104
|
+
* @param required - Domain fields, permission/target checks, save port and safe projections.
|
|
105
|
+
* @param options - Optional copy, error allowlist, fixed-metadata logger and resource framing.
|
|
106
|
+
* @returns Tool identity, dynamic secret-field metadata and a typed registry-compatible handler.
|
|
107
|
+
* @throws ToolInputError if the emitter is missing or fields violate the secret/routing contract.
|
|
108
|
+
* Prepare/transport failures propagate; save failures become a fixed safe outcome.
|
|
109
|
+
* @complexity O(n + h + b) locally in fields, rendered HTML and submitted secret bytes, plus host I/O.
|
|
110
|
+
* @example
|
|
111
|
+
* const tool = defineSecretCardTool(spec);
|
|
112
|
+
* registry.register({ descriptor, policy, handler: tool.handler({ surfaceExchanges, askThenReport }) });
|
|
113
|
+
*/
|
|
114
|
+
export declare function defineSecretCardTool<Prep, Saved, Result>(required: SecretCardSpec<Prep, Saved, Result>, options?: SecretCardOptions): SecretCardTool<Prep, Result>;
|
|
115
|
+
//# sourceMappingURL=secret-card.d.ts.map
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One human-only secret-card lifecycle. Keystrokes go directly to the held exchange and save
|
|
3
|
+
* port, never through model input, chat text, or logs. Saved values must stay in the host's
|
|
4
|
+
* sealed store; save returns only a safe summary for result/outcome projections.
|
|
5
|
+
*
|
|
6
|
+
* Fail closed without an emitter: returning a form or accepting a second model call would
|
|
7
|
+
* strand the held call or route a secret through model context. Cancel posts a dismissal so
|
|
8
|
+
* the call wakes immediately instead of waiting for its TTL. askThenReport keeps the exchange
|
|
9
|
+
* open until the real save finishes; reusing the form URI replaces premature "Done." with its
|
|
10
|
+
* actual outcome. The host supplies the daemon's existing helper, never a second store.
|
|
11
|
+
*/
|
|
12
|
+
import { ToolInputError, redactSecrets, SURFACE_DISMISSED_PARAM, SURFACE_EXCHANGE_ID_PARAM, SURFACE_TYPED_ANSWER_PARAM, } from '@jini-ai/core';
|
|
13
|
+
import { buildFormSurface } from './surfaces/form.js';
|
|
14
|
+
import { buildOutcomeSurface } from './surfaces/outcome.js';
|
|
15
|
+
/** Reject ambiguous or protocol-reserved names and runtime attempts to prefill secrets.
|
|
16
|
+
* @complexity O(n) time/space in the field count. Throws fixed ToolInputError text only. */
|
|
17
|
+
function checkedFields(form) {
|
|
18
|
+
const names = new Set([SURFACE_EXCHANGE_ID_PARAM, SURFACE_DISMISSED_PARAM, SURFACE_TYPED_ANSWER_PARAM]);
|
|
19
|
+
for (const field of form.fields) {
|
|
20
|
+
if (!field.name || names.has(field.name))
|
|
21
|
+
throw new ToolInputError({ message: 'Secret card field names must be unique and cannot use exchange parameters.' });
|
|
22
|
+
names.add(field.name);
|
|
23
|
+
if (field.secret === true && field.value !== undefined)
|
|
24
|
+
throw new ToolInputError({ message: 'Secret fields cannot have a pre-filled value. Omit value.' });
|
|
25
|
+
}
|
|
26
|
+
// Snapshot policies before waiting: host mutation must not change which submitted fields are secret.
|
|
27
|
+
return form.fields.map(field => ({ ...field }));
|
|
28
|
+
}
|
|
29
|
+
/** Classify before persistence; an abort wins over an already-buffered answer.
|
|
30
|
+
* Trimming tests blankness only: rewriting a provider secret can corrupt intentional newlines.
|
|
31
|
+
* @complexity O(n + b) before save in fields and submitted secret bytes; failure text delegates
|
|
32
|
+
* to core's exact-secret redaction scan. Host persistence cost is external. */
|
|
33
|
+
async function saveAnswer(required) {
|
|
34
|
+
const { answer, fields, prep, ctx, spec, options, exchangeId } = required;
|
|
35
|
+
if (ctx.signal.aborted)
|
|
36
|
+
return { status: 'abandoned' };
|
|
37
|
+
if (answer.status !== 'received')
|
|
38
|
+
return { status: answer.status };
|
|
39
|
+
if (answer.params[SURFACE_DISMISSED_PARAM] === true)
|
|
40
|
+
return { status: 'cancelled' };
|
|
41
|
+
const values = Object.fromEntries(fields.map(field => [field.name, answer.params[field.name]]));
|
|
42
|
+
const secrets = [];
|
|
43
|
+
for (const field of fields) {
|
|
44
|
+
if (field.secret !== true)
|
|
45
|
+
continue;
|
|
46
|
+
const value = values[field.name];
|
|
47
|
+
if (value !== undefined && typeof value !== 'string')
|
|
48
|
+
return { status: 'blank' };
|
|
49
|
+
const secret = typeof value === 'string' ? value : '';
|
|
50
|
+
if (secret.trim() === '' && (secret !== '' || field.allowBlank !== true))
|
|
51
|
+
return { status: 'blank' };
|
|
52
|
+
values[field.name] = secret;
|
|
53
|
+
secrets.push(secret);
|
|
54
|
+
}
|
|
55
|
+
if (ctx.signal.aborted)
|
|
56
|
+
return { status: 'abandoned' };
|
|
57
|
+
try {
|
|
58
|
+
return { status: 'saved', saved: await spec.save({ values, prep, signal: ctx.signal }) };
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
if (ctx.signal.aborted)
|
|
62
|
+
return { status: 'abandoned' };
|
|
63
|
+
let safeMessage = options.text?.saveFailure ?? 'Saving failed. Nothing was saved.';
|
|
64
|
+
try {
|
|
65
|
+
safeMessage = options.safeError?.(error) ?? safeMessage;
|
|
66
|
+
}
|
|
67
|
+
catch { /* An error mapper must not disclose a second exception containing the submitted value. */ }
|
|
68
|
+
// Even an accidentally permissive allowlist must not echo the submitted secret.
|
|
69
|
+
safeMessage = redactSecrets({ input: safeMessage }, { exactSecrets: secrets });
|
|
70
|
+
try {
|
|
71
|
+
options.logFailure?.({ toolId: spec.toolId, exchangeId, saved: false });
|
|
72
|
+
}
|
|
73
|
+
catch { /* Logging must not replace the safe model result with an opaque logger exception. */ }
|
|
74
|
+
return { status: 'failed', safeMessage };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Define a secret card once; inject the exchange store and daemon askThenReport at composition.
|
|
79
|
+
* @param required - Domain fields, permission/target checks, save port and safe projections.
|
|
80
|
+
* @param options - Optional copy, error allowlist, fixed-metadata logger and resource framing.
|
|
81
|
+
* @returns Tool identity, dynamic secret-field metadata and a typed registry-compatible handler.
|
|
82
|
+
* @throws ToolInputError if the emitter is missing or fields violate the secret/routing contract.
|
|
83
|
+
* Prepare/transport failures propagate; save failures become a fixed safe outcome.
|
|
84
|
+
* @complexity O(n + h + b) locally in fields, rendered HTML and submitted secret bytes, plus host I/O.
|
|
85
|
+
* @example
|
|
86
|
+
* const tool = defineSecretCardTool(spec);
|
|
87
|
+
* registry.register({ descriptor, policy, handler: tool.handler({ surfaceExchanges, askThenReport }) });
|
|
88
|
+
*/
|
|
89
|
+
export function defineSecretCardTool(required, options = {}) {
|
|
90
|
+
const spec = required;
|
|
91
|
+
return {
|
|
92
|
+
toolId: spec.toolId,
|
|
93
|
+
secretFieldNames: prep => checkedFields(spec.form({ prep })).filter(field => field.secret === true).map(field => field.name),
|
|
94
|
+
handler: deps => async (ctx, optional = {}) => {
|
|
95
|
+
if (!optional.emitSurface)
|
|
96
|
+
throw new ToolInputError({ message: options.text?.noEmitter ?? `${spec.toolId}: this execution context has no interactive form channel (no emitSurface), so this form cannot be shown here. Nothing was changed.` });
|
|
97
|
+
const prep = await spec.prepare({ ctx });
|
|
98
|
+
if (ctx.signal.aborted)
|
|
99
|
+
return spec.result({ prep, run: { status: 'abandoned' } });
|
|
100
|
+
const form = spec.form({ prep });
|
|
101
|
+
const fields = checkedFields(form);
|
|
102
|
+
if (ctx.signal.aborted)
|
|
103
|
+
return spec.result({ prep, run: { status: 'abandoned' } });
|
|
104
|
+
const exchange = deps.surfaceExchanges.open({ binding: { toolId: spec.toolId, principalId: ctx.principal.id, channel: 'mcp-ui' }, emit: optional.emitSurface });
|
|
105
|
+
const closeOnAbort = () => exchange.close({});
|
|
106
|
+
ctx.signal.addEventListener('abort', closeOnAbort, { once: true });
|
|
107
|
+
try {
|
|
108
|
+
// Close the open/register race as well as the prepare/abort race.
|
|
109
|
+
if (ctx.signal.aborted)
|
|
110
|
+
return spec.result({ prep, run: { status: 'abandoned' } });
|
|
111
|
+
const uri = `ui://${options.uriHost ?? 'jini'}/secret-card/${encodeURIComponent(spec.toolId)}/${encodeURIComponent(exchange.id)}`;
|
|
112
|
+
const framing = options.frameSize === undefined ? {} : { preferredFrameSize: options.frameSize };
|
|
113
|
+
const resource = buildFormSurface({ ...form, fields, uri, ...framing, toolName: spec.toolId,
|
|
114
|
+
baseParams: { [SURFACE_EXCHANGE_ID_PARAM]: exchange.id },
|
|
115
|
+
cancel: { label: form.cancelLabel ?? options.text?.cancelLabel ?? 'Cancel', toolName: spec.toolId,
|
|
116
|
+
params: { [SURFACE_EXCHANGE_ID_PARAM]: exchange.id, [SURFACE_DISMISSED_PARAM]: true } },
|
|
117
|
+
});
|
|
118
|
+
return await deps.askThenReport({ exchange, confirmationEmission: { channel: 'mcp-ui', payload: { resource } },
|
|
119
|
+
handle: async (answer) => {
|
|
120
|
+
const run = await saveAnswer({ answer, fields, prep, ctx, spec, options, exchangeId: exchange.id });
|
|
121
|
+
const result = spec.result({ prep, run });
|
|
122
|
+
const outcome = spec.outcome({ prep, run });
|
|
123
|
+
if (outcome === undefined)
|
|
124
|
+
return { result };
|
|
125
|
+
return { result, outcome: { channel: 'mcp-ui', payload: { resource: buildOutcomeSurface({ ...outcome, uri, ...framing }) } } };
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
ctx.signal.removeEventListener('abort', closeOnAbort);
|
|
131
|
+
// Also covers rendering/projection failures before or inside askThenReport; close is idempotent.
|
|
132
|
+
exchange.close({});
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=secret-card.js.map
|
|
@@ -209,6 +209,11 @@ ${SURFACE_SCRIPT_PRELUDE}
|
|
|
209
209
|
}
|
|
210
210
|
onVisibilityChange();
|
|
211
211
|
document.addEventListener("visibilitychange", onVisibilityChange);
|
|
212
|
+
// Published Jini started the dwell during document.write. If the iframe is hidden then, no
|
|
213
|
+
// timer is armed; becoming visible by sandbox initialization need not send visibilitychange
|
|
214
|
+
// to that new document. Re-check at the bridge ready boundary, preserving the original
|
|
215
|
+
// visibility, dwell, trusted-click and single-call gates. whenReady is already in every bridge.
|
|
216
|
+
api.whenReady(onVisibilityChange);
|
|
212
217
|
|
|
213
218
|
for (var i = 0; i < actionButtons.length; i++) {
|
|
214
219
|
actionButtons[i].addEventListener("click", onClick);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type SelectOption } from './select.js';
|
|
2
|
+
import { type SecretInputText } from './text-input.js';
|
|
2
3
|
interface SurfaceFieldBase {
|
|
3
4
|
/** HTML `name`, DOM `id` suffix, and the params key the value is posted under. */
|
|
4
5
|
readonly name: string;
|
|
@@ -14,7 +15,8 @@ export interface StringField extends SurfaceFieldBase {
|
|
|
14
15
|
readonly placeholder?: string;
|
|
15
16
|
readonly multiline?: boolean;
|
|
16
17
|
readonly rows?: number;
|
|
17
|
-
/** Renders as a masked
|
|
18
|
+
/** Renders as a masked input or multiline textarea; pre-filled values are forbidden.
|
|
19
|
+
* See {@link TextInputProps.secret}. */
|
|
18
20
|
readonly secret?: boolean;
|
|
19
21
|
}
|
|
20
22
|
export interface NumberField extends SurfaceFieldBase {
|
|
@@ -60,10 +62,11 @@ export type SurfaceField = StringField | NumberField | BooleanField | EnumField
|
|
|
60
62
|
* Renders the control fragment for one field, dispatching on its kind.
|
|
61
63
|
*
|
|
62
64
|
* @param field - See {@link SurfaceField}.
|
|
65
|
+
* @param text - Optional host translations for secret reveal controls.
|
|
63
66
|
* @returns An HTML fragment.
|
|
64
67
|
* @complexity O(n) in the rendered length.
|
|
65
68
|
*/
|
|
66
|
-
export declare function renderFieldControl(field: SurfaceField): string;
|
|
69
|
+
export declare function renderFieldControl(field: SurfaceField, text?: Partial<SecretInputText>): string;
|
|
67
70
|
/** What the surface's inline script needs to read a field's value back and coerce it — the runtime half of {@link SurfaceField}, with the presentation stripped out. */
|
|
68
71
|
export interface FieldReadSpec {
|
|
69
72
|
readonly name: string;
|
|
@@ -32,14 +32,16 @@ function base(field) {
|
|
|
32
32
|
* Renders the control fragment for one field, dispatching on its kind.
|
|
33
33
|
*
|
|
34
34
|
* @param field - See {@link SurfaceField}.
|
|
35
|
+
* @param text - Optional host translations for secret reveal controls.
|
|
35
36
|
* @returns An HTML fragment.
|
|
36
37
|
* @complexity O(n) in the rendered length.
|
|
37
38
|
*/
|
|
38
|
-
export function renderFieldControl(field) {
|
|
39
|
+
export function renderFieldControl(field, text) {
|
|
39
40
|
switch (field.kind) {
|
|
40
41
|
case 'string':
|
|
41
42
|
return renderTextInput({
|
|
42
43
|
...base(field),
|
|
44
|
+
...text,
|
|
43
45
|
...(field.value === undefined ? {} : { value: field.value }),
|
|
44
46
|
...(field.placeholder === undefined ? {} : { placeholder: field.placeholder }),
|
|
45
47
|
...(field.multiline === undefined ? {} : { multiline: field.multiline }),
|