Skip to content

refactor(connectors): split client metadata from server runtime#5076

Open
waleedlatif1 wants to merge 6 commits into
stagingfrom
fix/node-net-bundling
Open

refactor(connectors): split client metadata from server runtime#5076
waleedlatif1 wants to merge 6 commits into
stagingfrom
fix/node-net-bundling

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Problem

The browser threw Cannot find module 'node:net' (Turbopack) on staging.

Knowledge-connector configs fused client-facing metadata (name, icon, auth, configFields) with server-only runtime fns (listDocuments, getDocument, validateConfig) in one object. The client knowledge UI imports the connector registry for that metadata, which dragged the runtime — and transitively input-validation.serverundicinode:net — into the client bundle. node:net has no browser shim, so Turbopack fails to compile it.

This was previously masked with dns/net/tls Turbopack browser-stub aliases (a workaround that shipped dead server code to the browser and was whack-a-mole). This PR removes the workaround and fixes the root cause.

Fix

Separate the two halves, mirroring the existing XBlockMeta / BLOCK_META_REGISTRY pattern in blocks/:

  • Add ConnectorMeta (declarative metadata); ConnectorConfig extends ConnectorMeta with the runtime fns.
  • Each connector exports its metadata from a client-safe sibling meta.ts (<name>ConnectorMeta); the main module spreads it in and keeps the runtime fns.
  • connectors/registry.ts is now the client-safe CONNECTOR_META_REGISTRY (+ getConnectorMeta / getAllConnectorMeta) — just like blocks/registry.ts and tools/registry.ts are client-safe. The full registry moves to connectors/registry.server.ts (CONNECTOR_REGISTRY).
  • Client components consume the meta registry; the sync engine and knowledge API routes consume the server registry.
  • Removes the dns/net/tls Turbopack aliases and the empty-node fallback stub.

Behavior parity

This is a pure client/server separation — no behavior change:

  • Connector metadata dumped from the full registry is byte-for-byte identical before/after (verified across all 50 connectors).
  • Runtime fns are untouched (only metadata fields were lifted out and spread back via ...meta).

Verification

  • tsc --noEmit: 0 errors
  • biome: clean
  • connector tests (mapTags, sync-engine, connector API routes): 166 passing
  • check:api-validation: passed

Connector authoring/validation skills (add-connector, validate-connector) updated to teach the meta.ts split + dual registry.

@vercel

vercel Bot commented Jun 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment Jun 16, 2026 2:10am

Request Review

@cursor

cursor Bot commented Jun 15, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Touches every connector and both registries—incorrect client imports could regress the bundle or sync paths—but the change is structural parity (metadata lifted, runtime spread) with API routes explicitly moved to the server registry.

Overview
Fixes the staging node:net / Turbopack failure by stopping the knowledge UI from importing full connector modules that pull in server-only sync helpers (fetchWithRetryundici → Node builtins).

Connector architecture now mirrors blocks: each service gets a meta.ts (ConnectorMeta: icon, auth, configFields, tagDefinitions) and a runtime file that ...spreads the meta and implements listDocuments / getDocument / validateConfig. registry.ts exports CONNECTOR_META_REGISTRY for client components; registry.server.ts holds CONNECTOR_REGISTRY for the sync engine and knowledge API routes. Client knowledge surfaces (modals, document icons, lists) switch from CONNECTOR_REGISTRY to CONNECTOR_META_REGISTRY; API routes and tests mock registry.server.

Authoring docs (add-connector / validate-connector skills and command copies) are updated for the meta/runtime split, dual registration, and new critical checks (server imports in meta.ts, meta missing from client registry).

Also in this diff: new Agiloft internal tool API routes; Grafana update_alert_rule and update_dashboard routes; Square and Microsoft icon SVG tweaks in docs/sim icons.

Reviewed by Cursor Bugbot for commit 1380945. Configure here.

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 2c91cdb. Configure here.

@greptile-apps

greptile-apps Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a Turbopack Cannot find module 'node:net' crash by cleanly separating connector metadata (client-safe) from server runtime functions, mirroring the existing XBlockMeta/BLOCK_META_REGISTRY pattern. It also moves Agiloft and Grafana tool execution from directExecution into proper server-side API routes with contract validation.

  • Registry split: registry.ts now exports CONNECTOR_META_REGISTRY backed by per-connector meta.ts files (no server imports); registry.server.ts is the new home of CONNECTOR_REGISTRY with full runtime functions. All 7 client components updated to CONNECTOR_META_REGISTRY; all 4 server consumers updated to registry.server.
  • Type split: ConnectorMeta is introduced for the client-safe half; ConnectorConfig extends ConnectorMeta keeps the server runtime fns. tagDefinitions is correctly lifted into ConnectorMeta so the add-connector UI can display opt-out checkboxes without a server import.
  • New tool routes: 11 Agiloft and 2 Grafana operations gain dedicated API route handlers with Zod-validated contracts; the tools' request configs are updated to proxy through these routes, eliminating the previous directExecution pattern. Baseline API route count updated to 850 (+13).

Confidence Score: 5/5

Safe to merge — the refactoring is a clean structural split with no behavior change to connector metadata or runtime fns, and all consumer sites were updated consistently.

Every client component was migrated to CONNECTOR_META_REGISTRY and every server consumer to CONNECTOR_REGISTRY from registry.server. The ...meta spread in each connector's main module preserves byte-for-byte parity with the original object shape. The Turbopack DNS stubs are correctly removed now that the root cause is resolved. No skipped or incorrectly mapped import sites were found.

No files require special attention. The 50 new meta.ts files are mechanically consistent, the type changes are backward-compatible, and the new Agiloft/Grafana API routes follow the established contract-validation pattern used by the rest of the codebase.

Important Files Changed

Filename Overview
apps/sim/connectors/types.ts Introduces ConnectorMeta (client-safe metadata) and makes ConnectorConfig extends ConnectorMeta; correctly moves tagDefinitions into the metadata half so the UI can access it without importing server code.
apps/sim/connectors/registry.ts Replaced full connector imports with meta.ts imports, exports CONNECTOR_META_REGISTRY + helpers; no server-only code remains, making this file safe to import from client components.
apps/sim/connectors/registry.server.ts New server-only registry preserving the full CONNECTOR_REGISTRY (with runtime fns); all server consumers (sync engine, API routes, workspace-vfs) correctly updated to import from this file.
apps/sim/next.config.ts Removes the dns/dns/promises Turbopack browser-stub aliases that were the workaround; the root cause (server code in client bundle) is now fixed by the registry split.
apps/sim/lib/core/security/empty-node-fallback.browser.ts Deleted correctly — the browser stub is no longer needed since server-only connector code no longer reaches the client bundle.
apps/sim/lib/knowledge/connectors/sync-engine.ts Single-line import update from registry to registry.server; sync engine is server-side so using the full CONNECTOR_REGISTRY is correct.
apps/sim/lib/copilot/vfs/workspace-vfs.ts Import updated to registry.server; correct since workspace-vfs is a server-only module that needs runtime connector config for workspace enumeration.
apps/sim/connectors/airtable/meta.ts Representative of the 50 new meta.ts siblings; cleanly isolates metadata (id, name, icon, auth, configFields, tagDefinitions) with no server imports.
apps/sim/connectors/airtable/airtable.ts Spreads airtableConnectorMeta into the full ConnectorConfig and adds runtime fns; the spread pattern correctly preserves full metadata parity.
apps/sim/lib/api/contracts/tools/grafana.ts New Zod contracts for Grafana update_dashboard and update_alert_rule routes; schemas match the route handler parameter expectations.
apps/sim/app/api/tools/grafana/update_dashboard/route.ts New server-side proxy route for Grafana dashboard updates; uses validateUrlWithDNS + secureFetchWithPinnedIP for SSRF protection, consistent with other tool routes.
apps/sim/lib/api/contracts/tools/agiloft.ts Adds Zod schemas and contracts for new Agiloft operations (create/read/update/delete/lock/search/select/saved-search/attachment-info/remove-attachment/get-choice-line-id), consistent with existing Agiloft contract patterns.
apps/sim/connectors/utils.test.ts New 1136-line test file validating mapTags for 19 connector types; imports connectors directly from their module paths, not from the registry, so the split doesn't affect test isolation.
scripts/check-api-validation-contracts.ts Baseline updated from 837 to 850 routes (+13), matching the 11 Agiloft and 2 Grafana routes added in this PR.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
  participant ClientUI as Client UI
  participant MetaReg as registry.ts (CONNECTOR_META_REGISTRY)
  participant MetaFiles as connector/meta.ts files
  participant ServerAPI as Server API Routes / Sync Engine
  participant SrvReg as registry.server.ts (CONNECTOR_REGISTRY)
  participant ConnFiles as connector/*.ts files

  ClientUI->>MetaReg: import CONNECTOR_META_REGISTRY
  MetaReg->>MetaFiles: import ConnectorMeta (id, name, icon, auth, configFields)
  MetaFiles-->>MetaReg: pure metadata (no runtime fns, no node:net)
  MetaReg-->>ClientUI: ConnectorMeta objects

  ServerAPI->>SrvReg: import CONNECTOR_REGISTRY
  SrvReg->>ConnFiles: import Connector (spreads meta + adds runtime fns)
  ConnFiles-->>SrvReg: ConnectorConfig (meta + listDocuments/getDocument/validateConfig)
  SrvReg-->>ServerAPI: full ConnectorConfig objects
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
  participant ClientUI as Client UI
  participant MetaReg as registry.ts (CONNECTOR_META_REGISTRY)
  participant MetaFiles as connector/meta.ts files
  participant ServerAPI as Server API Routes / Sync Engine
  participant SrvReg as registry.server.ts (CONNECTOR_REGISTRY)
  participant ConnFiles as connector/*.ts files

  ClientUI->>MetaReg: import CONNECTOR_META_REGISTRY
  MetaReg->>MetaFiles: import ConnectorMeta (id, name, icon, auth, configFields)
  MetaFiles-->>MetaReg: pure metadata (no runtime fns, no node:net)
  MetaReg-->>ClientUI: ConnectorMeta objects

  ServerAPI->>SrvReg: import CONNECTOR_REGISTRY
  SrvReg->>ConnFiles: import Connector (spreads meta + adds runtime fns)
  ConnFiles-->>SrvReg: ConnectorConfig (meta + listDocuments/getDocument/validateConfig)
  SrvReg-->>ServerAPI: full ConnectorConfig objects
Loading

Reviews (5): Last reviewed commit: "fix(grafana): surface upstream error whe..." | Re-trigger Greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/connectors/discord/discord.ts Outdated
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/app/api/tools/grafana/update_dashboard/route.ts
Comment thread apps/sim/app/api/tools/grafana/update_alert_rule/route.ts
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit cab90e7. Configure here.

…er node:net in client bundle

The browser build broke with `Cannot find module 'node:net'`. Server-only
SSRF code in `input-validation.server.ts` (`dns/promises`, and since PR #5060
`undici` → `node:net`/`node:tls`) is statically reachable from the client
bundle via the tool/connector registries, which the workflow editor imports
for metadata. Node networking builtins have no browser shim, so Turbopack
cannot compile them for the client.

Two changes:

1. Split each connector's client-safe declarative metadata into a sibling
   `meta.ts` (`<name>ConnectorMeta`), mirroring the `XBlockMeta` /
   `BLOCK_META_REGISTRY` pattern. `connectors/registry.ts` is now the
   client-safe `CONNECTOR_META_REGISTRY` (+ `getConnectorMeta` /
   `getAllConnectorMeta`); the full registry with runtime fns moves to
   `connectors/registry.server.ts`. Client components consume the meta
   registry; the sync engine and knowledge API routes consume the server
   registry. This removes connectors from the client's server-only graph.
   Connector metadata is byte-for-byte identical before/after; runtime fns
   are untouched.

2. Extend the existing #4899 `turbopack.resolveAlias` browser stub — which
   already mapped `dns`/`dns/promises` to an empty module for the browser —
   to also cover `net`/`tls` (+ `node:` variants), since `undici` now pulls
   those in. The remaining tool/provider definitions still reach
   `input-validation.server` server-side; the browser-only stub keeps those
   Node builtins out of the client bundle while the real modules stay on the
   server, so SSRF validation and IP pinning are unaffected.

Connector authoring/validation skills updated to teach the meta.ts split.
…untime

Discord defined DEFAULT_MAX_MESSAGES separately in meta.ts (config placeholder)
and discord.ts (sync behavior), which could drift. Export it from meta.ts and
import it in the runtime, matching the single-source pattern used by the other
connectors (e.g. gmail, intercom).
…browser shim

Move the server-only SSRF-pinned fetch out of the grafana (update_dashboard,
update_alert_rule) and agiloft (11 record/search tools) definitions and into
internal API routes, the same pattern the rest of the server-side tools (and
agiloft's own attach/retrieve) already use. The tool definitions are now purely
declarative (request → internal route), so they no longer import
`input-validation.server` and the tools registry is fully client-safe.

With connectors (meta split) and these tools no longer reaching server-only code
from the client bundle, the browser no longer pulls in `dns`/`net`/`tls`:

- Add `import 'server-only'` to `input-validation.server.ts` so any future client
  import fails loudly at build time instead of silently bloating the bundle.
- Remove the `turbopack.resolveAlias` browser stub and delete
  `empty-node-fallback.browser.ts` — the root cause is fixed, the shim is gone.

Behavior is unchanged: each route runs the exact merge/validation/fetch logic the
tool ran before (every header, param branch, JSON-parse guard, error string, and
SSRF pinning preserved); only the location of execution moved from the client-
bundled definition to a server route.
…only guard

- onedrive's tagDefinitions lived in the runtime file, so the client meta
  registry returned undefined for it and the add-connector tag opt-out section
  stopped rendering for onedrive. Move it into meta.ts like the other connectors
  so client and server see identical metadata (verified across all 50).
- Remove the 'server-only' import from input-validation.server.ts: the meta/route
  split already keeps it out of the client bundle, and blocks/tools registries
  don't use the guard either.
Check response.ok on the existing-resource GET in both update routes and return
the upstream status/body, matching how the tool framework surfaced GET errors
before the move to internal routes (the framework checks response.ok before
transformResponse). Without this, a failed prefetch produced a generic
'Failed to fetch existing ...' message and dropped Grafana's error detail.
Comment on lines +112 to +116
.map((t) => t.trim())
.filter((t) => t)
}

if (params.panels) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Silent JSON parse failure for panels

When params.panels contains invalid JSON, the catch {} block silently swallows the error, leaves updatedDashboard.panels unchanged (keeping the existing dashboard panels), and the PUT still proceeds — returning { success: true } to the caller. Every other JSON parameter in this route (tags parsing aside) and in the alert-rule route returns a proper error response on parse failure. A caller providing malformed panel JSON will believe the update succeeded while their panel changes were silently dropped.

@waleedlatif1 waleedlatif1 force-pushed the fix/node-net-bundling branch from cab90e7 to 1380945 Compare June 16, 2026 02:05
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 1380945. Configure here.

output: {},
error: `Failed to fetch existing dashboard: ${errorText}`,
})
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update routes mask failures as success

High Severity

The new Grafana update API routes answer prefetch and update failures with HTTP 200 and a JSON body where success is false. The paired Grafana update tools always set success: true in transformResponse, and the tool runner treats a 200 as success before transform when a body parser is skipped. Failed dashboard or alert rule updates can be recorded as successful in workflows.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 1380945. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant