Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
d4233aa
wip
pedrofrxncx Dec 6, 2025
27e0eab
wip
pedrofrxncx Dec 6, 2025
9e23838
wip
pedrofrxncx Dec 8, 2025
3a918ab
wip
pedrofrxncx Dec 10, 2025
0180d53
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 10, 2025
bfcfe7c
wip
pedrofrxncx Dec 11, 2025
46f173c
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 11, 2025
0f4da99
wip
pedrofrxncx Dec 11, 2025
96a55d3
wip
pedrofrxncx Dec 11, 2025
e477f56
wip
pedrofrxncx Dec 11, 2025
79c3e4b
wip
pedrofrxncx Dec 11, 2025
b9fb845
wip
pedrofrxncx Dec 11, 2025
870d0e4
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 11, 2025
2729351
wip
pedrofrxncx Dec 12, 2025
4f5d931
refactor: replace Textarea with MonacoCodeEditor for action input and…
pedrofrxncx Dec 12, 2025
2a8cbd2
wip
pedrofrxncx Dec 12, 2025
f9dd9ad
wip
pedrofrxncx Dec 12, 2025
52533d8
wip
pedrofrxncx Dec 12, 2025
249ba7e
wip
pedrofrxncx Dec 12, 2025
7cb02f8
wip
pedrofrxncx Dec 12, 2025
6fce54d
wip
pedrofrxncx Dec 12, 2025
02624fe
wip
pedrofrxncx Dec 13, 2025
36cdbd5
wip
pedrofrxncx Dec 14, 2025
53d0f43
First event bus version
mcandeia Dec 13, 2025
588a058
Deleted unused files
mcandeia Dec 15, 2025
8ee0b86
Adds event bus docs
mcandeia Dec 15, 2025
3892d64
Fix tests
mcandeia Dec 15, 2025
27023b6
Improve database interface
mcandeia Dec 15, 2025
0c59b1c
Simplify bus
mcandeia Dec 15, 2025
eda1bb5
Remove sys context
mcandeia Dec 15, 2025
47e4e56
Remove notify subscriber fn
mcandeia Dec 15, 2025
4ed00c2
WellKnownMCP id
mcandeia Dec 15, 2025
5a31a94
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 16, 2025
41902f5
wip
pedrofrxncx Dec 16, 2025
652bfec
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 16, 2025
069ca16
WIP
pedrofrxncx Dec 17, 2025
77a6b95
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 17, 2025
01190ec
wip
pedrofrxncx Dec 17, 2025
22fd3e9
fmt
pedrofrxncx Dec 17, 2025
2ef2bab
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 17, 2025
4c1ddfe
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 17, 2025
c4f6dd8
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 18, 2025
1377fb6
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 18, 2025
ddcf05c
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 18, 2025
f4be390
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 19, 2025
c4fe537
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 20, 2025
b2c02fd
wip
pedrofrxncx Dec 23, 2025
00b588a
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 23, 2025
a7072b2
wip
pedrofrxncx Dec 23, 2025
adec41d
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 23, 2025
a476123
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 23, 2025
0ab17d8
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 23, 2025
2b23930
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 23, 2025
3fd1b3d
wip
pedrofrxncx Dec 23, 2025
17eb8d1
wip
pedrofrxncx Dec 23, 2025
1770363
wip
pedrofrxncx Dec 23, 2025
6b5ced9
wip
pedrofrxncx Dec 23, 2025
e787fcc
wip
pedrofrxncx Dec 23, 2025
a41b7d0
wip
pedrofrxncx Dec 23, 2025
81d67bd
wip
pedrofrxncx Dec 23, 2025
e283600
wip
pedrofrxncx Dec 23, 2025
e5b68e7
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 23, 2025
5b7e000
wip
pedrofrxncx Dec 23, 2025
9567754
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 23, 2025
6554938
wip
pedrofrxncx Dec 24, 2025
8fb9a7e
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 24, 2025
8782389
Implement resizable panels for workflow details view and enhance exec…
pedrofrxncx Dec 24, 2025
d54e6a0
wip
pedrofrxncx Dec 25, 2025
a23b5e5
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 25, 2025
5dd233c
wip
pedrofrxncx Dec 26, 2025
c19b301
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 26, 2025
9ffa9fc
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 26, 2025
7f56628
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 26, 2025
bf02ea0
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 26, 2025
5b946b1
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 26, 2025
3ac5c92
Enhance useTool hook to conditionally enable MCP fetching based on co…
pedrofrxncx Dec 26, 2025
2ef8add
Refactor workflow tabs: replace StepTabs with ActionTab and clean up …
pedrofrxncx Dec 26, 2025
d6f9240
Update workflow tabs to limit mentions to previous steps based on cur…
pedrofrxncx Dec 26, 2025
23eeab3
Enhance Tiptap mentions input functionality by updating rendering met…
pedrofrxncx Dec 26, 2025
a955670
wip
pedrofrxncx Dec 27, 2025
a6b6cfc
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 27, 2025
aa3b655
refactor + knip
pedrofrxncx Dec 27, 2025
08d981f
fmt
pedrofrxncx Dec 27, 2025
bc66796
wip
pedrofrxncx Dec 27, 2025
d561fc4
wip
pedrofrxncx Dec 27, 2025
baca210
big wip
pedrofrxncx Dec 27, 2025
adfd8cf
wip
pedrofrxncx Dec 27, 2025
8f2523b
wip
pedrofrxncx Dec 27, 2025
9af61ae
wip
pedrofrxncx Dec 27, 2025
8e46515
wip
pedrofrxncx Dec 28, 2025
2d2636c
wip
pedrofrxncx Dec 29, 2025
fe06355
wip
pedrofrxncx Dec 29, 2025
a631e47
Updating workflow ui/ux (#2103)
rafavalls Dec 29, 2025
a088c89
Merge branch 'main' of https://github.com/decocms/mesh into feat/work…
pedrofrxncx Dec 29, 2025
a36cbac
feat(workflow): add hooks for current step execution result and step …
pedrofrxncx Dec 29, 2025
69dc305
Merge remote-tracking branch 'origin/main' into feat/workflows
tlgimenes Dec 29, 2025
f29a8e8
Merge branch 'feat/workflows' of https://github.com/decocms/mesh into…
pedrofrxncx Dec 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion apps/mesh/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"@decocms/vite-plugin": "workspace:*",
"@hookform/resolvers": "^5.2.2",
"@modelcontextprotocol/sdk": "1.20.2",
"@monaco-editor/react": "^4.7.0",
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/exporter-prometheus": "^0.208.0",
"@opentelemetry/exporter-trace-otlp-proto": "^0.207.0",
Expand All @@ -77,6 +78,11 @@
"@tanstack/react-query": "^5.90.11",
"@tanstack/react-router": "^1.139.7",
"@tanstack/react-router-devtools": "^1.139.7",
"@tiptap/extension-mention": "^3.13.0",
"@tiptap/pm": "^3.13.0",
"@tiptap/react": "^3.13.0",
"@tiptap/starter-kit": "^3.13.0",
"@tiptap/suggestion": "^3.13.0",
"@types/bun": "^1.3.1",
"@types/pg": "^8.15.6",
"@types/react": "^19.2.2",
Expand All @@ -98,6 +104,8 @@
"hono": "^4.10.7",
"idb-keyval": "^6.2.2",
"input-otp": "^1.4.2",
"lucide-react": "^0.468.0",
"prettier": "^3.4.2",
"jose": "^6.0.11",
"nanoid": "^5.1.6",
"pg": "^8.16.3",
Expand All @@ -114,7 +122,8 @@
"vite-tsconfig-paths": "^5.1.4",
"zod": "^3.25.76",
"zod-from-json-schema": "0.0.5",
"zod-to-json-schema": "3.25.0"
"zod-to-json-schema": "3.25.0",
"zustand": "^5.0.9"
},
"module": "src/index.ts",
"keywords": [
Expand Down
3 changes: 3 additions & 0 deletions apps/mesh/src/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,9 @@ const plugins = [
],
},
},
rateLimit: {
enabled: false,
},
}),

// Admin plugin for system-level super-admins
Expand Down
2 changes: 1 addition & 1 deletion apps/mesh/src/storage/event-bus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1002,7 +1002,7 @@ class KyselyEventBusStorage implements EventBusStorage {
organization_id: organizationId,
connection_id: connectionId,
event_type: desiredSub.eventType,
publisher: desiredSub.publisher ?? null,
publisher: connectionId ?? desiredSub.publisher ?? null,
filter: desiredSub.filter ?? null,
enabled: 1,
created_at: now,
Expand Down
88 changes: 74 additions & 14 deletions apps/mesh/src/tools/database/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,76 @@ const QueryResult = z.object({
success: z.boolean().optional(),
});

/**
* Safely escape and quote SQL values
* This is still not as safe as parameterized queries, but better than raw replacement
*/
function escapeSqlValue(value: any): string {
if (value === null || value === undefined) {
return "NULL";
}

if (typeof value === "number") {
return String(value);
}

if (typeof value === "boolean") {
return value ? "TRUE" : "FALSE";
}

if (typeof value === "string") {
// Escape single quotes by doubling them (SQL standard)
// and wrap in quotes
return `'${value.replace(/'/g, "''")}'`;
}

if (value instanceof Date) {
return `'${value.toISOString()}'`;
}

// For arrays, objects, etc - serialize to JSON string
return `'${JSON.stringify(value).replace(/'/g, "''")}'`;
}

/**
* Replace ALL placeholders (?, $1, $2, etc.) with escaped values
*
* IMPORTANT: We find all placeholder positions FIRST, then replace from end to start.
* This prevents ? characters inside interpolated values from being treated as placeholders.
*/
function interpolateParams(sql: string, params: any[]): string {
// First, handle $1, $2, etc. style placeholders (unambiguous)
let result = sql;
for (let i = params.length; i >= 1; i--) {
const placeholder = `$${i}`;
if (result.includes(placeholder)) {
result = result.replaceAll(placeholder, escapeSqlValue(params[i - 1]));
}
}

// For ? placeholders, find all positions FIRST, then replace from end to start
// This prevents ? inside interpolated values from being matched
const questionMarkPositions: number[] = [];
for (let i = 0; i < result.length; i++) {
if (result[i] === "?") {
questionMarkPositions.push(i);
}
}

// Replace from end to start so positions don't shift
for (
let i = Math.min(questionMarkPositions.length, params.length) - 1;
i >= 0;
i--
) {
const pos = questionMarkPositions[i];
const escaped = escapeSqlValue(params[i]);
result = result.slice(0, pos!) + escaped + result.slice(pos! + 1);
}

return result;
}

export type QueryResult = z.infer<typeof QueryResult>;

const DatatabasesRunSqlInputSchema = z.object({
Expand Down Expand Up @@ -136,14 +206,13 @@ export const DATABASES_RUN_SQL = defineTool({
description: "Run a SQL query against the database",

inputSchema: DatatabasesRunSqlInputSchema,
outputSchema: z.lazy(() =>
z.object({
result: z.array(QueryResult),
}),
),
outputSchema: z.object({
result: z.array(QueryResult),
}),
handler: async (input, ctx) => {
requireAuth(ctx);
await ctx.access.check();
const sqlQuery = interpolateParams(input.sql, input.params || []);

if (!ctx.connectionId) {
throw new Error("Connection context required for database access");
Expand All @@ -152,15 +221,6 @@ export const DATABASES_RUN_SQL = defineTool({
const schemaName = getSchemaName(ctx.connectionId);
const roleName = getRoleName(ctx.connectionId);

let sqlQuery = input.sql;
for (let i = 0; i < (input.params?.length ?? 0); i++) {
const param = input.params?.[i];
sqlQuery = sqlQuery.replace(
`?`,
typeof param === "string" ? `'${param}'` : `${param}`,
);
}

const result = await executeWithIsolation(
ctx.db,
schemaName,
Expand Down
103 changes: 55 additions & 48 deletions apps/mesh/src/web/components/details/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,75 +1,82 @@
import { Button } from "@deco/ui/components/button.tsx";
import { ArrowLeft } from "@untitledui/icons";
import { type ReactNode, useEffect, useState } from "react";
import { createContext, type ReactNode, useContext, useState } from "react";
import { createPortal } from "react-dom";

const TABS_PORTAL_ID = "view-details-tabs-portal";
const ACTIONS_PORTAL_ID = "view-details-actions-portal";

interface PortalProps {
children: ReactNode;
interface ViewLayoutContextValue {
tabsEl: HTMLDivElement | null;
actionsEl: HTMLDivElement | null;
}

function usePortal(id: string) {
const [element, setElement] = useState<HTMLElement | null>(null);
const ViewLayoutContext = createContext<ViewLayoutContextValue | null>(null);

// oxlint-disable-next-line ban-use-effect/ban-use-effect
useEffect(() => {
setElement(document.getElementById(id));
}, [id]);

return element;
interface PortalProps {
children: ReactNode;
icon?: string;
title?: string;
}

export function ViewTabs({ children }: PortalProps) {
const target = usePortal(TABS_PORTAL_ID);
if (!target) return null;
return createPortal(children, target);
const ctx = useContext(ViewLayoutContext);
if (!ctx?.tabsEl) return null;
return createPortal(children, ctx.tabsEl);
}

export function ViewActions({ children }: PortalProps) {
const target = usePortal(ACTIONS_PORTAL_ID);
if (!target) return null;
return createPortal(children, target);
const ctx = useContext(ViewLayoutContext);
if (!ctx?.actionsEl) return null;
return createPortal(children, ctx.actionsEl);
}

interface ViewLayoutProps {
children: ReactNode;
onBack: () => void;
title?: string;
}

export function ViewLayout({ children, onBack }: ViewLayoutProps) {
export function ViewLayout({ children, onBack, title }: ViewLayoutProps) {
const [tabsEl, setTabsEl] = useState<HTMLDivElement | null>(null);
const [actionsEl, setActionsEl] = useState<HTMLDivElement | null>(null);

return (
<div className="flex flex-col h-full bg-background">
{/* Header */}
<div className="flex items-center h-12 border-b border-border shrink-0">
{/* Back Button */}
<div className="flex h-full px-2 border-r items-center">
<Button
variant="ghost"
size="icon"
className="items-center size-8 text-muted-foreground"
onClick={onBack}
>
<ArrowLeft />
</Button>
</div>
<ViewLayoutContext value={{ tabsEl, actionsEl }}>
<div className="flex flex-col h-full bg-background">
{/* Header */}
<div className="flex items-center h-12 border-b border-border shrink-0">
{/* Back Button */}
<div className="flex h-full px-2 border-r items-center">
<Button
variant="ghost"
size="icon"
className="items-center size-8 text-muted-foreground"
onClick={onBack}
>
<ArrowLeft />
</Button>
</div>

{title && (
<div className="flex items-center gap-2 px-2">
<p className="text-sm font-medium">{title}</p>
</div>
)}

{/* Tabs and Actions */}
<div className="flex justify-between px-4 items-center gap-4 flex-1">
{/* Tabs Slot */}
<div id={TABS_PORTAL_ID} className="flex items-center gap-2" />
{/* Tabs and Actions */}
<div className="flex justify-between px-4 items-center gap-4 flex-1">
{/* Tabs Slot */}
<div ref={setTabsEl} className="flex items-center gap-2" />

{/* Actions Slot */}
<div
id={ACTIONS_PORTAL_ID}
className="flex items-center gap-2 ml-auto"
/>
{/* Actions Slot */}
<div
ref={setActionsEl}
className="flex items-center gap-2 ml-auto"
/>
</div>
</div>
</div>

{/* Main Content */}
<div className="flex-1 overflow-auto">{children}</div>
</div>
{/* Main Content */}
<div className="flex-1 overflow-auto">{children}</div>
</div>
</ViewLayoutContext>
);
}
Loading
Loading