@hachej/boring-workspace 0.1.83 → 0.1.85

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/app-front.js CHANGED
@@ -1,6 +1,6 @@
1
- import { B as e, C as t, E as n, F as r, G as i, H as a, I as o, Kt as s, L as c, Lt as l, M as u, N as d, P as f, Q as p, R as m, Rt as h, S as g, Sn as _, T as ee, V as v, an as te, c as ne, cn as re, g as ie, hn as ae, j as oe, kt as se, m as ce, mn as le, n as ue, on as de, r as fe, x as pe, xn as me, z as he } from "./WorkspaceProvider-DH-yiJZ8.js";
1
+ import { B as e, C as t, E as n, F as r, G as i, H as a, I as o, Kt as s, L as c, Lt as l, M as u, N as d, P as f, Q as p, R as m, Rt as h, S as g, Sn as _, T as ee, V as v, an as te, c as ne, cn as re, g as ie, hn as ae, j as oe, kt as se, m as ce, mn as le, n as ue, on as de, r as fe, x as pe, xn as me, z as he } from "./WorkspaceProvider-C8rWNm72.js";
2
2
  import { t as y } from "./utils-BRcxFdrz.js";
3
- import { a as ge, c as _e, f as ve, l as ye, n as be, o as xe, r as Se, s as Ce, t as we, u as Te } from "./WorkspaceLoadingState-D_b8t-6U.js";
3
+ import { a as ge, c as _e, f as ve, l as ye, n as be, o as xe, r as Se, s as Ce, t as we, u as Te } from "./WorkspaceLoadingState-BkAUFt_A.js";
4
4
  import { createElement as Ee, useCallback as b, useEffect as x, useLayoutEffect as De, useMemo as S, useRef as C, useState as w, useSyncExternalStore as Oe } from "react";
5
5
  import { Fragment as T, jsx as E, jsxs as D } from "react/jsx-runtime";
6
6
  import { ChevronRight as ke, Clock3 as Ae, ExternalLink as je, FileText as Me, Maximize2 as Ne, MessageSquare as Pe, MessageSquarePlus as O, Moon as Fe, MoreHorizontal as Ie, PanelLeftClose as Le, PanelLeftOpen as Re, Pin as ze, PinOff as Be, Plug as Ve, Plus as He, RefreshCw as Ue, Search as We, Settings as Ge, Sparkles as Ke, Sun as qe, X as Je } from "lucide-react";
@@ -3585,6 +3585,7 @@ function workspaceBridgeHttpRoutes(app, opts, done) {
3585
3585
  }
3586
3586
  await opts.assertRuntimeWorkspaceScope(request, verifiedRuntimeToken.claims);
3587
3587
  }
3588
+ let authorized;
3588
3589
  try {
3589
3590
  const registry = await resolveRegistry(request, body, opts);
3590
3591
  const definition = registry.getDefinition(body.op);
@@ -3592,13 +3593,22 @@ function workspaceBridgeHttpRoutes(app, opts, done) {
3592
3593
  return sendBridgeError(reply, statusForBridgeError("BRIDGE_OP_NOT_FOUND" /* OpNotFound */), body.requestId, "BRIDGE_OP_NOT_FOUND" /* OpNotFound */, "WorkspaceBridge operation is not registered");
3593
3594
  }
3594
3595
  const authContext = runtimeToken !== void 0 ? resolveRuntimeContext(runtimeToken, opts, definition, verifiedRuntimeToken) : await resolveBrowserContext(request, opts, definition, body);
3596
+ authorized = { registry, definition, authContext };
3597
+ } catch (err) {
3598
+ const bridgeError = isBridgeError(err) ? err : createWorkspaceBridgeError("BRIDGE_HANDLER_FAILED" /* HandlerFailed */, "WorkspaceBridge transport failed");
3599
+ return sendBridgeError(reply, statusForBridgeError(bridgeError.code), body.requestId, bridgeError.code, bridgeError.message);
3600
+ }
3601
+ if (runtimeToken !== void 0 && opts.admitRuntimeOperation) {
3602
+ await opts.admitRuntimeOperation(authorized.authContext.workspaceId);
3603
+ }
3604
+ try {
3595
3605
  const idempotencyStore = opts.getIdempotencyStore ? await opts.getIdempotencyStore(request, body) : opts.idempotencyStore;
3596
- const expectedWorkspaceId = opts.getOwnerWorkspaceId ? await opts.getOwnerWorkspaceId(request, body, authContext) : opts.ownerWorkspaceId;
3606
+ const expectedWorkspaceId = opts.getOwnerWorkspaceId ? await opts.getOwnerWorkspaceId(request, body, authorized.authContext) : opts.ownerWorkspaceId;
3597
3607
  const response = await runWithWorkspaceBridgeIdempotency(idempotencyStore, {
3598
- definition,
3608
+ definition: authorized.definition,
3599
3609
  request: body,
3600
- auth: authContext
3601
- }, async () => await registry.call(body, authContext, { expectedWorkspaceId }));
3610
+ auth: authorized.authContext
3611
+ }, async () => await authorized.registry.call(body, authorized.authContext, { expectedWorkspaceId }));
3602
3612
  return await sendResponse(reply, response);
3603
3613
  } catch (err) {
3604
3614
  const bridgeError = isBridgeError(err) ? err : createWorkspaceBridgeError("BRIDGE_HANDLER_FAILED" /* HandlerFailed */, "WorkspaceBridge transport failed");
@@ -3672,16 +3682,22 @@ async function resolveRegistry(request, body, opts) {
3672
3682
  return registry;
3673
3683
  }
3674
3684
  function resolveRuntimeContext(token, opts, definition, verified) {
3685
+ let authorized;
3675
3686
  if (verified) {
3676
- return authorizeWorkspaceBridgeRuntimeToken(verified, definition.requiredCapabilities).authContext;
3687
+ authorized = authorizeWorkspaceBridgeRuntimeToken(verified, definition.requiredCapabilities);
3688
+ } else {
3689
+ if (!opts.runtimeTokenSecret) {
3690
+ throw createWorkspaceBridgeError("BRIDGE_AUTH_REQUIRED" /* AuthRequired */, "Runtime bridge token auth is not configured");
3691
+ }
3692
+ authorized = verifyWorkspaceBridgeRuntimeToken(token, {
3693
+ secret: opts.runtimeTokenSecret,
3694
+ requiredCapabilities: definition.requiredCapabilities
3695
+ });
3677
3696
  }
3678
- if (!opts.runtimeTokenSecret) {
3679
- throw createWorkspaceBridgeError("BRIDGE_AUTH_REQUIRED" /* AuthRequired */, "Runtime bridge token auth is not configured");
3697
+ if (opts.admitRuntimeOperation && !definition.callerClassesAllowed.includes("runtime")) {
3698
+ throw createWorkspaceBridgeError("BRIDGE_CALLER_NOT_ALLOWED" /* CallerNotAllowed */, "Caller class is not allowed for operation");
3680
3699
  }
3681
- return verifyWorkspaceBridgeRuntimeToken(token, {
3682
- secret: opts.runtimeTokenSecret,
3683
- requiredCapabilities: definition.requiredCapabilities
3684
- }).authContext;
3700
+ return authorized.authContext;
3685
3701
  }
3686
3702
  function resolveRuntimeClaims(token, opts) {
3687
3703
  if (!opts.runtimeTokenSecret) {
package/dist/server.d.ts CHANGED
@@ -296,6 +296,7 @@ interface WorkspaceBridgeHttpRoutesOptions {
296
296
  runtimeRefreshTokenStore?: WorkspaceBridgeRuntimeRefreshTokenStore;
297
297
  getRuntimeRefreshTokenStore?: (request: FastifyRequest, claims: WorkspaceBridgeRuntimeRefreshTokenClaims) => WorkspaceBridgeRuntimeRefreshTokenStore | undefined | Promise<WorkspaceBridgeRuntimeRefreshTokenStore | undefined>;
298
298
  assertRuntimeWorkspaceScope?: (request: FastifyRequest, claims: WorkspaceBridgeRuntimeTokenClaims | WorkspaceBridgeRuntimeRefreshTokenClaims) => void | Promise<void>;
299
+ admitRuntimeOperation?: (workspaceId: string) => void | Promise<void>;
299
300
  refreshTokenRateLimit?: {
300
301
  maxUses?: number;
301
302
  windowMs?: number;
package/dist/server.js CHANGED
@@ -1664,6 +1664,7 @@ function workspaceBridgeHttpRoutes(app, opts, done) {
1664
1664
  }
1665
1665
  await opts.assertRuntimeWorkspaceScope(request, verifiedRuntimeToken.claims);
1666
1666
  }
1667
+ let authorized;
1667
1668
  try {
1668
1669
  const registry = await resolveRegistry(request, body, opts);
1669
1670
  const definition = registry.getDefinition(body.op);
@@ -1671,13 +1672,22 @@ function workspaceBridgeHttpRoutes(app, opts, done) {
1671
1672
  return sendBridgeError(reply, statusForBridgeError("BRIDGE_OP_NOT_FOUND" /* OpNotFound */), body.requestId, "BRIDGE_OP_NOT_FOUND" /* OpNotFound */, "WorkspaceBridge operation is not registered");
1672
1673
  }
1673
1674
  const authContext = runtimeToken !== void 0 ? resolveRuntimeContext(runtimeToken, opts, definition, verifiedRuntimeToken) : await resolveBrowserContext(request, opts, definition, body);
1675
+ authorized = { registry, definition, authContext };
1676
+ } catch (err) {
1677
+ const bridgeError = isBridgeError(err) ? err : createWorkspaceBridgeError("BRIDGE_HANDLER_FAILED" /* HandlerFailed */, "WorkspaceBridge transport failed");
1678
+ return sendBridgeError(reply, statusForBridgeError(bridgeError.code), body.requestId, bridgeError.code, bridgeError.message);
1679
+ }
1680
+ if (runtimeToken !== void 0 && opts.admitRuntimeOperation) {
1681
+ await opts.admitRuntimeOperation(authorized.authContext.workspaceId);
1682
+ }
1683
+ try {
1674
1684
  const idempotencyStore = opts.getIdempotencyStore ? await opts.getIdempotencyStore(request, body) : opts.idempotencyStore;
1675
- const expectedWorkspaceId = opts.getOwnerWorkspaceId ? await opts.getOwnerWorkspaceId(request, body, authContext) : opts.ownerWorkspaceId;
1685
+ const expectedWorkspaceId = opts.getOwnerWorkspaceId ? await opts.getOwnerWorkspaceId(request, body, authorized.authContext) : opts.ownerWorkspaceId;
1676
1686
  const response = await runWithWorkspaceBridgeIdempotency(idempotencyStore, {
1677
- definition,
1687
+ definition: authorized.definition,
1678
1688
  request: body,
1679
- auth: authContext
1680
- }, async () => await registry.call(body, authContext, { expectedWorkspaceId }));
1689
+ auth: authorized.authContext
1690
+ }, async () => await authorized.registry.call(body, authorized.authContext, { expectedWorkspaceId }));
1681
1691
  return await sendResponse(reply, response);
1682
1692
  } catch (err) {
1683
1693
  const bridgeError = isBridgeError(err) ? err : createWorkspaceBridgeError("BRIDGE_HANDLER_FAILED" /* HandlerFailed */, "WorkspaceBridge transport failed");
@@ -1751,16 +1761,22 @@ async function resolveRegistry(request, body, opts) {
1751
1761
  return registry;
1752
1762
  }
1753
1763
  function resolveRuntimeContext(token, opts, definition, verified) {
1764
+ let authorized;
1754
1765
  if (verified) {
1755
- return authorizeWorkspaceBridgeRuntimeToken(verified, definition.requiredCapabilities).authContext;
1766
+ authorized = authorizeWorkspaceBridgeRuntimeToken(verified, definition.requiredCapabilities);
1767
+ } else {
1768
+ if (!opts.runtimeTokenSecret) {
1769
+ throw createWorkspaceBridgeError("BRIDGE_AUTH_REQUIRED" /* AuthRequired */, "Runtime bridge token auth is not configured");
1770
+ }
1771
+ authorized = verifyWorkspaceBridgeRuntimeToken(token, {
1772
+ secret: opts.runtimeTokenSecret,
1773
+ requiredCapabilities: definition.requiredCapabilities
1774
+ });
1756
1775
  }
1757
- if (!opts.runtimeTokenSecret) {
1758
- throw createWorkspaceBridgeError("BRIDGE_AUTH_REQUIRED" /* AuthRequired */, "Runtime bridge token auth is not configured");
1776
+ if (opts.admitRuntimeOperation && !definition.callerClassesAllowed.includes("runtime")) {
1777
+ throw createWorkspaceBridgeError("BRIDGE_CALLER_NOT_ALLOWED" /* CallerNotAllowed */, "Caller class is not allowed for operation");
1759
1778
  }
1760
- return verifyWorkspaceBridgeRuntimeToken(token, {
1761
- secret: opts.runtimeTokenSecret,
1762
- requiredCapabilities: definition.requiredCapabilities
1763
- }).authContext;
1779
+ return authorized.authContext;
1764
1780
  }
1765
1781
  function resolveRuntimeClaims(token, opts) {
1766
1782
  if (!opts.runtimeTokenSecret) {
@@ -3,6 +3,7 @@ import { FileTreeBridge } from '../../../../front/bridge/types';
3
3
  import { FilesystemId } from '../../../../shared/types/filesystem';
4
4
  import { PaneProps } from '../../../../shared/types/panel';
5
5
  import { LeftTabParams } from '../../../../shared/plugins/types';
6
+ import { ForwardRefExoticComponent, RefAttributes } from 'react';
6
7
  export { copyToClipboard } from './clipboard';
7
8
  export declare function preloadFileTreeComponent(): void;
8
9
  declare function clampContextMenuPosition(x: number, y: number, menuRect: Pick<DOMRect, "width" | "height">, viewportWidth: number, viewportHeight: number): {
@@ -30,6 +31,14 @@ export interface FileTreeViewProps {
30
31
  /** Forwarded to the inner <FileTree>. */
31
32
  className?: string;
32
33
  }
34
+ /** Imperative handle for hosts (e.g. `FileTreePane`'s refresh button) that need
35
+ * to force a re-sync of this root's listing on demand, outside the normal
36
+ * mutation/event-driven refresh paths. */
37
+ export interface FileTreeViewHandle {
38
+ /** Re-fetch this root's top-level listing plus every currently-expanded
39
+ * subfolder. Resolves once all of it has settled. */
40
+ refetch: () => Promise<void>;
41
+ }
33
42
  /**
34
43
  * File tree with the full workbench actions: tracks container height,
35
44
  * routes selects through `bridge.openFile`, and provides a right-click
@@ -41,7 +50,7 @@ export interface FileTreeViewProps {
41
50
  * want a "Files" panel; `WorkbenchLeftPane` uses this primitive directly to
42
51
  * share its search input with the Data tab.
43
52
  */
44
- export declare function FileTreeView({ rootDir, searchQuery, bridge, revealFileTreeRequest, filesystem, access, ignoreNames, className, }: FileTreeViewProps): import("react").JSX.Element;
53
+ export declare const FileTreeView: ForwardRefExoticComponent<FileTreeViewProps & RefAttributes<FileTreeViewHandle>>;
45
54
  export { clampContextMenuPosition };
46
55
  export interface FileTreeRootConfig {
47
56
  filesystem: FilesystemId;
@@ -3,6 +3,18 @@ import { FileTreeNode } from './FileTree';
3
3
  export declare function buildTree(entries: FileEntry[], childrenByDir: Map<string, FileEntry[]>): FileTreeNode[];
4
4
  export declare function parentDir(path: string): string;
5
5
  export declare function dirKey(dir: string): string;
6
+ /**
7
+ * Join a directory and a leaf name into a path, the same way every path in
8
+ * this module is shaped: no leading "./", no doubled or trailing slashes.
9
+ * `dir` is normally "." (root) or a bare relative path like "src/lib" — but
10
+ * some hosts configure a filesystem root as "/" (see company_context in
11
+ * `FileTreeRootConfig`), and naively doing `${dir}/${name}` there produced
12
+ * "//name": a path string that doesn't match what the server round-trips
13
+ * back, so the optimistic entry and the server-confirmed entry never
14
+ * deduped by path and the row rendered twice. Stripping trailing slashes
15
+ * from `dir` first keeps every root shape converging on the same string.
16
+ */
17
+ export declare function joinPath(dir: string, name: string): string;
6
18
  export declare function mergeEntries(base: FileEntry[] | undefined, optimistic: FileEntry[] | undefined): FileEntry[] | undefined;
7
19
  export type DraftEditing = {
8
20
  kind: 'create-file';
package/dist/testing.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { r as e, t } from "./rolldown-runtime-Dqa2HsxW.js";
2
- import { Mt as n, jt as r, n as i, p as a } from "./WorkspaceProvider-DH-yiJZ8.js";
2
+ import { Mt as n, jt as r, n as i, p as a } from "./WorkspaceProvider-C8rWNm72.js";
3
3
  import { bootClean as o, openPaneViaBridge as s, openWorkbench as c } from "./testing-e2e.js";
4
4
  import * as l from "react";
5
5
  import { cloneElement as u, createElement as d, isValidElement as f, useLayoutEffect as p, useMemo as m, useSyncExternalStore as h } from "react";
package/dist/workspace.js CHANGED
@@ -1,8 +1,8 @@
1
- import { $ as e, $t as t, A as n, At as r, Bt as i, Ct as a, D as o, Dt as s, E as c, Et as l, Ft as u, Gt as d, Ht as f, It as p, J as m, Jt as h, K as g, Lt as _, Mt as v, Nt as y, O as b, Ot as x, Pt as S, Q as C, Qt as w, Rt as T, S as ee, Sn as te, St as ne, T as re, Tt as E, U as ie, Ut as ae, Vt as oe, W as se, Wt as ce, Xt as le, Y as ue, Yt as de, Z as fe, Zt as pe, _n as me, _t as he, a as ge, an as _e, at as ve, b as ye, bn as be, bt as xe, cn as Se, ct as Ce, d as we, dn as D, dt as O, en as k, et as Te, f as Ee, fn as De, ft as Oe, gn as ke, gt as A, h as Ae, hn as je, ht as Me, i as Ne, in as Pe, it as Fe, jt as Ie, k as Le, l as Re, ln as ze, lt as Be, mn as j, mt as Ve, n as He, nt as Ue, o as We, on as Ge, ot as Ke, p as qe, pn as Je, pt as Ye, q as Xe, qt as Ze, r as Qe, rn as $e, rt as et, s as tt, sn as nt, st as rt, t as it, tn as at, tt as ot, u as st, un as ct, ut as lt, vn as ut, vt as dt, w as ft, wt as pt, x as mt, xt as ht, y as gt, yn as _t, yt as vt, zt as yt } from "./WorkspaceProvider-DH-yiJZ8.js";
2
- import { t as bt } from "./MarkdownEditor-D8NqIunl.js";
1
+ import { $ as e, $t as t, A as n, At as r, Bt as i, Ct as a, D as o, Dt as s, E as c, Et as l, Ft as u, Gt as d, Ht as f, It as p, J as m, Jt as h, K as g, Lt as _, Mt as v, Nt as y, O as b, Ot as x, Pt as S, Q as C, Qt as w, Rt as T, S as ee, Sn as te, St as ne, T as re, Tt as E, U as ie, Ut as ae, Vt as oe, W as se, Wt as ce, Xt as le, Y as ue, Yt as de, Z as fe, Zt as pe, _n as me, _t as he, a as ge, an as _e, at as ve, b as ye, bn as be, bt as xe, cn as Se, ct as Ce, d as we, dn as D, dt as O, en as k, et as Te, f as Ee, fn as De, ft as Oe, gn as ke, gt as A, h as Ae, hn as je, ht as Me, i as Ne, in as Pe, it as Fe, jt as Ie, k as Le, l as Re, ln as ze, lt as Be, mn as j, mt as Ve, n as He, nt as Ue, o as We, on as Ge, ot as Ke, p as qe, pn as Je, pt as Ye, q as Xe, qt as Ze, r as Qe, rn as $e, rt as et, s as tt, sn as nt, st as rt, t as it, tn as at, tt as ot, u as st, un as ct, ut as lt, vn as ut, vt as dt, w as ft, wt as pt, x as mt, xt as ht, y as gt, yn as _t, yt as vt, zt as yt } from "./WorkspaceProvider-C8rWNm72.js";
2
+ import { t as bt } from "./MarkdownEditor-B4MXLBVy.js";
3
3
  import { t as M } from "./utils-BRcxFdrz.js";
4
- import { d as xt, i as St, n as Ct, p as wt, r as Tt, t as Et } from "./WorkspaceLoadingState-D_b8t-6U.js";
5
- import { t as Dt } from "./FileTree-DQQ1NXtr.js";
4
+ import { d as xt, i as St, n as Ct, p as wt, r as Tt, t as Et } from "./WorkspaceLoadingState-BkAUFt_A.js";
5
+ import { t as Dt } from "./FileTree-BIRGkW6O.js";
6
6
  import { Component as Ot, Suspense as kt, useCallback as N, useEffect as P, useMemo as F, useRef as I, useState as L, useSyncExternalStore as R } from "react";
7
7
  import { Fragment as At, jsx as z, jsxs as B } from "react/jsx-runtime";
8
8
  import { CheckIcon as jt, CopyIcon as Mt, MenuIcon as Nt, PanelLeftIcon as V, PinIcon as Pt } from "lucide-react";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hachej/boring-workspace",
3
- "version": "0.1.83",
3
+ "version": "0.1.85",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Workspace UI, plugin, and bridge package for composing chat, files, catalogs, editors, and app-specific panes.",
@@ -139,9 +139,9 @@
139
139
  "tailwind-merge": "^2.0.0",
140
140
  "zod": "^3.23.0",
141
141
  "zustand": "^5.0.14",
142
- "@hachej/boring-agent": "0.1.83",
143
- "@hachej/boring-ui-kit": "0.1.83",
144
- "@hachej/boring-ui-plugin-cli": "0.1.83"
142
+ "@hachej/boring-agent": "0.1.85",
143
+ "@hachej/boring-ui-kit": "0.1.85",
144
+ "@hachej/boring-ui-plugin-cli": "0.1.85"
145
145
  },
146
146
  "devDependencies": {
147
147
  "@tailwindcss/postcss": "^4.3.1",