@coffer-org/plugin-webchat 2.1.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ChatWidget-B5heKPXv.js → ChatWidget-U4vyG1gt.js} +31 -36
- package/dist/schema.js +23 -30
- package/dist/web.js +1 -1
- package/package.json +4 -4
|
@@ -6040,7 +6040,7 @@ var getDefaultConfig = () => {
|
|
|
6040
6040
|
var twMerge = /*#__PURE__*/ createTailwindMerge(getDefaultConfig);
|
|
6041
6041
|
//#endregion
|
|
6042
6042
|
//#region ../web/lib/utils.ts
|
|
6043
|
-
/**
|
|
6043
|
+
/** Merge classes while resolving Tailwind conflicts (shadcn convention). */
|
|
6044
6044
|
function cn(...inputs) {
|
|
6045
6045
|
return twMerge(clsx(inputs));
|
|
6046
6046
|
}
|
|
@@ -6054,7 +6054,7 @@ var DialogOverlay = React.forwardRef(({ className, ...props }, ref) => /* @__PUR
|
|
|
6054
6054
|
...props
|
|
6055
6055
|
}));
|
|
6056
6056
|
DialogOverlay.displayName = DialogOverlay$1.displayName;
|
|
6057
|
-
/**
|
|
6057
|
+
/** Responsive content: bottom sheet on mobile, centered modal on desktop. */
|
|
6058
6058
|
var DialogContent = React.forwardRef(({ className, children, hideClose, ...props }, ref) => /* @__PURE__ */ jsxs(DialogPortal, { children: [/* @__PURE__ */ jsx(DialogOverlay, {}), /* @__PURE__ */ jsxs(DialogContent$1, {
|
|
6059
6059
|
ref,
|
|
6060
6060
|
className: cn("fixed z-50 flex flex-col border border-border bg-surface text-text shadow-xl", "inset-x-0 bottom-0 max-h-[88dvh] overflow-y-auto rounded-t-2xl", "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom data-[state=closed]:duration-200", "md:inset-x-auto md:bottom-auto md:left-1/2 md:top-1/2 md:max-h-[85dvh] md:w-full md:max-w-xl md:-translate-x-1/2 md:-translate-y-1/2 md:rounded-2xl", "md:data-[state=open]:slide-in-from-bottom-0 md:data-[state=closed]:slide-out-to-bottom-0 md:data-[state=open]:zoom-in-95 md:data-[state=closed]:zoom-out-95", className),
|
|
@@ -6083,14 +6083,13 @@ DialogDescription.displayName = DialogDescription$1.displayName;
|
|
|
6083
6083
|
//#endregion
|
|
6084
6084
|
//#region ../web/hooks/use-media-query.ts
|
|
6085
6085
|
/**
|
|
6086
|
-
*
|
|
6086
|
+
* Media-query state as a reactive value.
|
|
6087
6087
|
*
|
|
6088
|
-
*
|
|
6089
|
-
*
|
|
6090
|
-
* подвійна робота — таблиця і картки одночасно.
|
|
6088
|
+
* Needed where CSS hiding (`hidden list:block`) is insufficient: hidden elements remain in the
|
|
6089
|
+
* DOM and still render. For a list of 700 records, that means doing the work twice — table and cards.
|
|
6091
6090
|
*
|
|
6092
|
-
* `fallback`
|
|
6093
|
-
*
|
|
6091
|
+
* `fallback` is the answer when `matchMedia` is unavailable (jsdom tests): default to a
|
|
6092
|
+
* “wide screen” so tests see the desktop layout.
|
|
6094
6093
|
*/
|
|
6095
6094
|
function useMediaQuery(query, fallback = true) {
|
|
6096
6095
|
return useSyncExternalStore(useCallback((onChange) => {
|
|
@@ -6104,8 +6103,8 @@ function useMediaQuery(query, fallback = true) {
|
|
|
6104
6103
|
}, [query, fallback]), () => fallback);
|
|
6105
6104
|
}
|
|
6106
6105
|
/**
|
|
6107
|
-
*
|
|
6108
|
-
* Tailwind v4
|
|
6106
|
+
* Breakpoint value from `@theme` (globals.css), so JS and CSS do not drift.
|
|
6107
|
+
* Tailwind v4 publishes them as CSS variables on :root. Without CSS (tests), use `fallback`.
|
|
6109
6108
|
*/
|
|
6110
6109
|
function breakpointPx(name, fallback) {
|
|
6111
6110
|
if (typeof window === "undefined" || typeof getComputedStyle !== "function") return fallback;
|
|
@@ -6113,7 +6112,7 @@ function breakpointPx(name, fallback) {
|
|
|
6113
6112
|
const n = Number.parseInt(raw.trim(), 10);
|
|
6114
6113
|
return Number.isFinite(n) && n > 0 ? n : fallback;
|
|
6115
6114
|
}
|
|
6116
|
-
/** `(min-width: …)`
|
|
6115
|
+
/** `(min-width: …)` for a theme breakpoint. */
|
|
6117
6116
|
function useMinWidth(name, fallback) {
|
|
6118
6117
|
return useMediaQuery(`(min-width: ${breakpointPx(name, fallback)}px)`, true);
|
|
6119
6118
|
}
|
|
@@ -6147,14 +6146,13 @@ async function* readSse(body) {
|
|
|
6147
6146
|
}
|
|
6148
6147
|
//#endregion
|
|
6149
6148
|
//#region src/ui/chat-api.ts
|
|
6150
|
-
/**
|
|
6151
|
-
*
|
|
6149
|
+
/** Web-chat transport. Session cookies are sent automatically (same-origin), so there is no
|
|
6150
|
+
* separate authorization here; the gate is on the server. */
|
|
6152
6151
|
var BASE = "/api/plugins/webchat/user";
|
|
6153
6152
|
/**
|
|
6154
|
-
*
|
|
6155
|
-
*
|
|
6156
|
-
*
|
|
6157
|
-
* означали б рівно одне.
|
|
6153
|
+
* Throws on any rejection, including 404 (“plugin was disabled AFTER the widget bundle
|
|
6154
|
+
* loaded”). There is deliberately no separate `null` for this case: the caller keeps
|
|
6155
|
+
* the current thread list either way, so two return codes would mean the same thing.
|
|
6158
6156
|
*/
|
|
6159
6157
|
async function fetchThreads() {
|
|
6160
6158
|
const r = await fetch(`${BASE}/threads`, {
|
|
@@ -6358,8 +6356,8 @@ function useChat() {
|
|
|
6358
6356
|
}
|
|
6359
6357
|
//#endregion
|
|
6360
6358
|
//#region src/ui/use-page-context.ts
|
|
6361
|
-
/**
|
|
6362
|
-
*
|
|
6359
|
+
/** Current-page context for the agent. SPA routes: `/:library/:type[/:id]`;
|
|
6360
|
+
* system branches (settings, browse) are returned by path only. */
|
|
6363
6361
|
function usePageContext() {
|
|
6364
6362
|
const { pathname } = useLocation();
|
|
6365
6363
|
const parts = pathname.split("/").filter(Boolean);
|
|
@@ -29005,9 +29003,8 @@ function remarkGfm(options) {
|
|
|
29005
29003
|
//#endregion
|
|
29006
29004
|
//#region src/ui/internal-link.ts
|
|
29007
29005
|
var SEGMENT = /^[A-Za-z0-9._~%-]+$/;
|
|
29008
|
-
/**
|
|
29009
|
-
*
|
|
29010
|
-
* не дочитуючи got до кінця. */
|
|
29006
|
+
/** Returns captured ':param' values on a match, or null. '*' is legal only as the
|
|
29007
|
+
* last pattern segment, so this branch may return immediately without reading got to the end. */
|
|
29011
29008
|
function matchesPattern(pathname, pattern) {
|
|
29012
29009
|
const got = pathname.split("/").filter(Boolean);
|
|
29013
29010
|
const want = pattern.split("/").filter(Boolean);
|
|
@@ -29053,9 +29050,9 @@ function classifyHref(href, origin, routes, pairs = []) {
|
|
|
29053
29050
|
}
|
|
29054
29051
|
//#endregion
|
|
29055
29052
|
//#region src/ui/chat-nav.tsx
|
|
29056
|
-
/**
|
|
29057
|
-
*
|
|
29058
|
-
*
|
|
29053
|
+
/** What to do with the widget when the user follows a link from a response.
|
|
29054
|
+
* ChatWidget supplies the callback (it owns mode/open), avoiding a prop
|
|
29055
|
+
* threaded through ChatMessages and Bubble. */
|
|
29059
29056
|
var ChatNavContext = createContext(() => {});
|
|
29060
29057
|
function ChatNavProvider({ onNavigate, children }) {
|
|
29061
29058
|
return /* @__PURE__ */ jsx(ChatNavContext.Provider, {
|
|
@@ -29119,18 +29116,17 @@ function ChatMessages({ messages, pending, pendingReasoning }) {
|
|
|
29119
29116
|
}, m.msgId)), pending !== null && /* @__PURE__ */ jsx(Bubble, {
|
|
29120
29117
|
role: "assistant",
|
|
29121
29118
|
text: pending || t("webchat.thinking"),
|
|
29122
|
-
reasoning: pendingReasoning
|
|
29123
|
-
live: true
|
|
29119
|
+
reasoning: pendingReasoning
|
|
29124
29120
|
})]
|
|
29125
29121
|
});
|
|
29126
29122
|
}
|
|
29127
29123
|
/**
|
|
29128
|
-
* memo:
|
|
29129
|
-
*
|
|
29130
|
-
*
|
|
29131
|
-
*
|
|
29124
|
+
* memo: during streaming, the parent re-renders on EVERY delta (several times per
|
|
29125
|
+
* second). Without memo, each tick would re-render (and therefore re-parse markdown)
|
|
29126
|
+
* for every completed message while only one bubble at the bottom is changing.
|
|
29127
|
+
* The props are primitives, so the default shallow comparison is sufficient.
|
|
29132
29128
|
*/
|
|
29133
|
-
var Bubble = memo(function Bubble({ role, text, reasoning
|
|
29129
|
+
var Bubble = memo(function Bubble({ role, text, reasoning }) {
|
|
29134
29130
|
const { t } = useTranslation();
|
|
29135
29131
|
if (role === "user") return /* @__PURE__ */ jsx("div", {
|
|
29136
29132
|
className: "self-end max-w-[85%] rounded-2xl rounded-br-sm bg-accent/15 px-3 py-2 text-sm whitespace-pre-wrap break-words",
|
|
@@ -29139,7 +29135,6 @@ var Bubble = memo(function Bubble({ role, text, reasoning, live }) {
|
|
|
29139
29135
|
return /* @__PURE__ */ jsxs("div", {
|
|
29140
29136
|
className: "self-start max-w-[95%] min-w-0 rounded-2xl rounded-bl-sm bg-elevated px-3 py-2 text-sm break-words",
|
|
29141
29137
|
children: [reasoning ? /* @__PURE__ */ jsxs("details", {
|
|
29142
|
-
open: live,
|
|
29143
29138
|
className: "mb-2 rounded-lg border border-border px-2 py-1",
|
|
29144
29139
|
children: [/* @__PURE__ */ jsx("summary", {
|
|
29145
29140
|
className: "cursor-pointer select-none text-xs text-muted",
|
|
@@ -29217,9 +29212,9 @@ function ChatThreadList({ threads, activeId, onOpen, onNew, className = "w-[220p
|
|
|
29217
29212
|
}
|
|
29218
29213
|
//#endregion
|
|
29219
29214
|
//#region src/ui/ChatWidget.tsx
|
|
29220
|
-
/**
|
|
29221
|
-
*
|
|
29222
|
-
*
|
|
29215
|
+
/** What to do with the widget after following a link from a response. On desktop a 380px
|
|
29216
|
+
* panel does not obstruct the page (a darkened modal does, so it collapses into it);
|
|
29217
|
+
* below the nav breakpoint the panel consumes nearly the whole screen. */
|
|
29223
29218
|
function nextModeAfterNav(wideNav) {
|
|
29224
29219
|
return wideNav ? "panel" : "bubble";
|
|
29225
29220
|
}
|
package/dist/schema.js
CHANGED
|
@@ -4391,11 +4391,11 @@ function resolveUnits(u) {
|
|
|
4391
4391
|
//#endregion
|
|
4392
4392
|
//#region ../sdk/src/currencies.ts
|
|
4393
4393
|
/**
|
|
4394
|
-
*
|
|
4395
|
-
*
|
|
4394
|
+
* Currencies from built-in `Intl` (ISO 4217), with NO hand list or npm dependency.
|
|
4395
|
+
* Codes come from `Intl.supportedValuesOf('currency')`; symbols/names are localized through
|
|
4396
4396
|
* `Intl.NumberFormat`/`Intl.DisplayNames`.
|
|
4397
4397
|
*/
|
|
4398
|
-
/**
|
|
4398
|
+
/** All ISO 4217 codes. Fallback: several major codes for older runtimes. */
|
|
4399
4399
|
var CURRENCY_CODES = (() => {
|
|
4400
4400
|
try {
|
|
4401
4401
|
return Intl.supportedValuesOf("currency");
|
|
@@ -4410,26 +4410,26 @@ var CURRENCY_CODES = (() => {
|
|
|
4410
4410
|
}
|
|
4411
4411
|
})();
|
|
4412
4412
|
var CODE_SET = new Set(CURRENCY_CODES);
|
|
4413
|
-
/**
|
|
4413
|
+
/** Whether an ISO 4217 code is valid. */
|
|
4414
4414
|
var isCurrencyCode = (c) => CODE_SET.has(c);
|
|
4415
4415
|
//#endregion
|
|
4416
4416
|
//#region ../sdk/src/fields/validation.ts
|
|
4417
|
-
/**
|
|
4417
|
+
/** Structured message for zod: JSON {code, params}. Decoded by mutate.ts. */
|
|
4418
4418
|
function vmsg(code, params) {
|
|
4419
4419
|
return JSON.stringify(params ? {
|
|
4420
4420
|
code,
|
|
4421
4421
|
params
|
|
4422
4422
|
} : { code });
|
|
4423
4423
|
}
|
|
4424
|
-
/** v4 error-map:
|
|
4424
|
+
/** v4 error-map: message for a missing value (formerly required_error). */
|
|
4425
4425
|
function reqErr(code = "required") {
|
|
4426
4426
|
return { error: (iss) => iss.input === void 0 ? vmsg(code) : void 0 };
|
|
4427
4427
|
}
|
|
4428
|
-
/** v4 error-map:
|
|
4428
|
+
/** v4 error-map: message for an invalid type (formerly invalid_type_error). */
|
|
4429
4429
|
function typeErr(code = "invalid_type") {
|
|
4430
4430
|
return { error: (iss) => iss.code === "invalid_type" ? vmsg(code) : void 0 };
|
|
4431
4431
|
}
|
|
4432
|
-
/** v4 error-map: required + invalid_type
|
|
4432
|
+
/** v4 error-map: required + invalid_type together (formerly required_error + invalid_type_error). */
|
|
4433
4433
|
function reqTypeErr() {
|
|
4434
4434
|
return { error: (iss) => iss.code === "invalid_type" ? iss.input === void 0 ? vmsg("required") : vmsg("invalid_type") : void 0 };
|
|
4435
4435
|
}
|
|
@@ -4447,10 +4447,10 @@ function jsonValue(raw) {
|
|
|
4447
4447
|
return raw;
|
|
4448
4448
|
}
|
|
4449
4449
|
/**
|
|
4450
|
-
*
|
|
4451
|
-
*
|
|
4452
|
-
* Single
|
|
4453
|
-
*
|
|
4450
|
+
* Factory for fields that store JSON and validate it with a nested zod schema.
|
|
4451
|
+
* Accepts a native object/array (native form state) OR a JSON string (legacy).
|
|
4452
|
+
* Single parse through jsonValue → inner.safeParse → issue `code`; an unparseable
|
|
4453
|
+
* string remains a string → code 'json'.
|
|
4454
4454
|
*/
|
|
4455
4455
|
function jsonRefined(inner, code) {
|
|
4456
4456
|
return unknown().superRefine((raw, ctx) => {
|
|
@@ -4522,16 +4522,16 @@ function normalizeOpts(rawIn) {
|
|
|
4522
4522
|
//#endregion
|
|
4523
4523
|
//#region ../sdk/src/field-presets.ts
|
|
4524
4524
|
/**
|
|
4525
|
-
*
|
|
4525
|
+
* Field presets are thin wrappers around the primitives in fields.ts.
|
|
4526
4526
|
*
|
|
4527
|
-
*
|
|
4528
|
-
*
|
|
4527
|
+
* Each preset = one kind (one widget). Presets do not accept `format`;
|
|
4528
|
+
* they are semantic types themselves. min/max/step go through `config`.
|
|
4529
4529
|
*
|
|
4530
|
-
*
|
|
4531
|
-
*
|
|
4530
|
+
* Presets are added to `f` through `composeF`, which guarantees no preset
|
|
4531
|
+
* overrides a primitive.
|
|
4532
4532
|
*
|
|
4533
|
-
*
|
|
4534
|
-
*
|
|
4533
|
+
* The cyclic import from fields.ts is safe: factories/helpers are hoisted declarations,
|
|
4534
|
+
* and presets call them only inside their function bodies.
|
|
4535
4535
|
*/
|
|
4536
4536
|
function email(raw) {
|
|
4537
4537
|
const o = normalizeOpts(raw);
|
|
@@ -4705,9 +4705,9 @@ function link(raw) {
|
|
|
4705
4705
|
}, o.multiple ?? false));
|
|
4706
4706
|
}
|
|
4707
4707
|
var TEL_RE = /^\+?[\d\s()-]{4,}$/;
|
|
4708
|
-
/** Loose URL:
|
|
4708
|
+
/** Loose URL: any scheme:// OR dotted host (optional port/path). No spaces. */
|
|
4709
4709
|
var LINK_RE = /^([a-z][a-z0-9+.-]*:\/\/\S+|[\w-]+(\.[\w-]+)+(:\d+)?(\/\S*)?)$/i;
|
|
4710
|
-
/** CSS named colors (CSS Color Module L4)
|
|
4710
|
+
/** CSS named colors (CSS Color Module L4) for f.colorname. */
|
|
4711
4711
|
var CSS_COLOR_NAMES = /* @__PURE__ */ new Set([
|
|
4712
4712
|
"aliceblue",
|
|
4713
4713
|
"antiquewhite",
|
|
@@ -4966,7 +4966,7 @@ function reminder(raw) {
|
|
|
4966
4966
|
}
|
|
4967
4967
|
var _real = real;
|
|
4968
4968
|
var _int = int;
|
|
4969
|
-
/**
|
|
4969
|
+
/** Percentage 0..100 — real with rules:{min:0,max:100}. */
|
|
4970
4970
|
function percent(o) {
|
|
4971
4971
|
return _real({
|
|
4972
4972
|
...o,
|
|
@@ -4977,7 +4977,7 @@ function percent(o) {
|
|
|
4977
4977
|
}
|
|
4978
4978
|
});
|
|
4979
4979
|
}
|
|
4980
|
-
/**
|
|
4980
|
+
/** Year — int with rules:{min:1900,max:2100}; bounds can be overridden via rules.min/max. */
|
|
4981
4981
|
function year(o) {
|
|
4982
4982
|
return _int({
|
|
4983
4983
|
...o,
|
|
@@ -6027,13 +6027,6 @@ function wrapKey(opts, meta) {
|
|
|
6027
6027
|
role: opts.role
|
|
6028
6028
|
}
|
|
6029
6029
|
};
|
|
6030
|
-
if (opts.pinned) m = {
|
|
6031
|
-
...m,
|
|
6032
|
-
hints: {
|
|
6033
|
-
...m.hints,
|
|
6034
|
-
pinned: true
|
|
6035
|
-
}
|
|
6036
|
-
};
|
|
6037
6030
|
if (opts.default !== void 0) m = {
|
|
6038
6031
|
...m,
|
|
6039
6032
|
default: opts.default
|
package/dist/web.js
CHANGED
|
@@ -11,7 +11,7 @@ import { definePluginUI } from "@coffer-org/web-sdk";
|
|
|
11
11
|
var ui_default = definePluginUI({ slots: [{
|
|
12
12
|
slot: "overlay",
|
|
13
13
|
id: "webchat",
|
|
14
|
-
load: () => import("./ChatWidget-
|
|
14
|
+
load: () => import("./ChatWidget-U4vyG1gt.js")
|
|
15
15
|
}] });
|
|
16
16
|
//#endregion
|
|
17
17
|
export { ui_default as default };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coffer-org/plugin-webchat",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=24"
|
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
"test:ui": "vitest run --root ."
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@coffer-org/plugin-orchestrator": "^2.1.
|
|
30
|
-
"@coffer-org/sdk": "^2.1.
|
|
31
|
-
"@coffer-org/server": "^2.2.
|
|
29
|
+
"@coffer-org/plugin-orchestrator": "^2.1.1",
|
|
30
|
+
"@coffer-org/sdk": "^2.1.1",
|
|
31
|
+
"@coffer-org/server": "^2.2.2",
|
|
32
32
|
"react-markdown": "^10.1.0",
|
|
33
33
|
"remark-gfm": "^4.0.1"
|
|
34
34
|
},
|