You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
refactor(connectors): split client metadata from server runtime + cover 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.
Copy file name to clipboardExpand all lines: .agents/skills/add-connector/SKILL.md
+65-16Lines changed: 65 additions & 16 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -12,8 +12,8 @@ You are an expert at adding knowledge base connectors to Sim. A connector syncs
12
12
When the user asks you to create a connector:
13
13
1. Use Context7 or WebFetch to read the service's API documentation
14
14
2. Determine the auth mode: **OAuth** (if Sim already has an OAuth provider for the service) or **API key** (if the service uses API key / Bearer token auth)
15
-
3. Create the connector directory and config
16
-
4. Register it in the connector registry
15
+
3. Create the connector directory: a client-safe `meta.ts` (declarative metadata) plus the runtime module that spreads it
16
+
4. Register it in BOTH the server registry and the client-safe meta registry
17
17
18
18
## Hard Rule: No Guessed Response Or Document Schemas
19
19
@@ -32,13 +32,19 @@ If the source schema is unknown, do one of these instead:
32
32
33
33
## Directory Structure
34
34
35
+
Each connector is split into a client-safe metadata file and a server-only runtime file. This mirrors the `XBlockMeta` / `BLOCK_META_REGISTRY` split in `apps/sim/blocks` — client components (the knowledge UI) only need the metadata (icon, name, auth, config fields), so the runtime functions (which pull server-only helpers like `input-validation.server` → `undici` → `node:net`) must stay out of the client bundle.
36
+
35
37
Create files in `apps/sim/connectors/{service}/`:
36
38
```
37
39
connectors/{service}/
38
-
├── index.ts # Barrel export
39
-
└── {service}.ts # ConnectorConfig definition
40
+
├── index.ts # Barrel export (re-exports the runtime connector)
└── {service}.ts # ConnectorConfig — spreads the meta + adds runtime functions
40
43
```
41
44
45
+
-`meta.ts` exports `{service}ConnectorMeta: ConnectorMeta`. It imports ONLY the icon from `@/components/icons`, `import type { ConnectorMeta } from '@/connectors/types'`, and any pure-data constants. It must NEVER import server/runtime code.
46
+
-`{service}.ts` exports `{service}Connector: ConnectorConfig`. It imports the meta via `import { {service}ConnectorMeta } from '@/connectors/{service}/meta'`, spreads it as the first property, and holds the runtime functions (which may import server-only helpers like `@/lib/knowledge/documents/utils`).
47
+
42
48
## Authentication
43
49
44
50
Connectors use a discriminated union for auth config (`ConnectorAuthConfig` in `connectors/types.ts`):
@@ -55,19 +61,17 @@ For services with existing OAuth providers in `apps/sim/lib/oauth/types.ts`. The
55
61
### API key mode
56
62
For services that use API key / Bearer token auth. The modal shows a password input with the configured `label` and `placeholder`. The API key is encrypted at rest using AES-256-GCM and stored in a dedicated `encryptedApiKey` column on the connector record. The sync engine decrypts it automatically — connectors receive the raw access token in `listDocuments`, `getDocument`, and `validateConfig`.
57
63
58
-
## ConnectorConfig Structure
64
+
## Connector Structure (meta.ts + runtime)
65
+
66
+
The declarative metadata lives in `meta.ts` (`ConnectorMeta`). The runtime functions live in `{service}.ts` (`ConnectorConfig`), which spreads the meta as its first property.
@@ -499,7 +531,9 @@ If the service already has an icon in `apps/sim/components/icons.tsx` (from a to
499
531
500
532
## Registering
501
533
502
-
Add one line to `apps/sim/connectors/registry.ts`:
534
+
Register in BOTH registries, keeping the same alphabetical-by-id ordering in each.
535
+
536
+
1.**Server registry** — `apps/sim/connectors/registry.server.ts` (server-only full registry; holds full connectors with runtime functions, imported by the sync engine and knowledge API routes):
2.**Client-safe meta registry** — `apps/sim/connectors/registry.ts` (imports each connector's `meta.ts` only, so client components can use it without pulling server-only code; the metadata counterpart to `BLOCK_META_REGISTRY`):
`registry.ts` exports `CONNECTOR_META_REGISTRY: ConnectorMetaRegistry` plus the helpers `getConnectorMeta(id)` and `getAllConnectorMeta()`, importing each `@/connectors/{service}/meta` directly — never the runtime module. `registry.server.ts` exports `CONNECTOR_REGISTRY: ConnectorRegistry`.
559
+
513
560
## Reference Implementations
514
561
515
562
-**OAuth + contentDeferred**: `apps/sim/connectors/google-drive/google-drive.ts` — file download with metadata-based hash, `orderBy` for deterministic pagination
@@ -262,10 +264,18 @@ Connectors where the list API already returns content inline (e.g., Slack messag
262
264
-[ ] Logs sync progress at `info` level
263
265
-[ ] Logs errors at `warn` or `error` level with context
264
266
267
+
### Meta / Runtime Split
268
+
-[ ]`connectors/{service}/meta.ts` exports `{service}ConnectorMeta: ConnectorMeta` (id, name, description, version, icon, auth, configFields, and any `tagDefinitions` / `supportsIncrementalSync`)
269
+
-[ ]`meta.ts` imports ONLY the icon from `@/components/icons`, `ConnectorMeta` (type-only), and pure-data constants — NO server/runtime imports (`@/lib/knowledge/...`, `input-validation.server`, `fetchWithRetry`, etc.); any such import in `meta.ts` is **critical** (breaks the client bundle)
270
+
-[ ]`connectors/{service}/{service}.ts` spreads `...{service}ConnectorMeta` as the first property and adds the runtime functions (`listDocuments`, `getDocument`, `validateConfig`, `mapTags?`)
271
+
-[ ] Metadata fields (id, name, auth, configFields, etc.) live ONLY in `meta.ts`, not duplicated in `{service}.ts`
272
+
265
273
### Registry
266
274
-[ ] Connector is exported from `connectors/{service}/index.ts`
267
-
-[ ] Connector is registered in `connectors/registry.ts`
268
-
-[ ] Registry key matches the connector's `id` field
275
+
-[ ] Full connector is registered in `connectors/registry.server.ts` (server-only registry, `CONNECTOR_REGISTRY`)
276
+
-[ ] Meta is registered in `connectors/registry.ts` (client-safe registry, `CONNECTOR_META_REGISTRY`), importing `@/connectors/{service}/meta`
277
+
-[ ] Both registries use the same key and it matches the connector's `id` field
278
+
-[ ] Both registries keep the same alphabetical-by-id ordering
269
279
270
280
## Step 11: Report and Fix
271
281
@@ -284,6 +294,8 @@ Group findings by severity:
284
294
- Query/filter injection: user-controlled values interpolated into OData `$filter`, SOQL, or query strings without escaping
285
295
- Per-document content download in `listDocuments` without `contentDeferred: true` — causes sync timeouts for large document sets
286
296
-`contentHash` mismatch between `listDocuments` stub and `getDocument` return — causes unnecessary re-processing every sync
297
+
- Server/runtime import in `meta.ts` (e.g. `@/lib/knowledge/...`, `input-validation.server`, `fetchWithRetry`) — pulls server-only code into the client bundle and breaks the build
298
+
- Connector missing from `connectors/registry.ts` (the client-safe meta registry) — or its entry there imports the runtime module instead of `meta.ts` — the knowledge UI can't render it
287
299
288
300
**Warning** (incorrect behavior, data quality issues, or convention violations):
-[ ] Validated meta/runtime split: `meta.ts` holds metadata with no server/runtime imports, `{service}.ts` spreads the meta + adds runtime functions
358
+
-[ ] Validated registry: exported from index.ts, full connector in `registry.server.ts`, meta in `registry.ts`, matching keys and alphabetical-by-id ordering in both
0 commit comments