Skip to content

feat(connector): [YW-263] auth-blind pipeline via SecretResolver bound-resolver#131

Merged
youhaowei merged 3 commits into
mainfrom
charixandra/yw-263-secretvault-data-plane-bound-resolver-remoteapiconnector
Jun 17, 2026
Merged

feat(connector): [YW-263] auth-blind pipeline via SecretResolver bound-resolver#131
youhaowei merged 3 commits into
mainfrom
charixandra/yw-263-secretvault-data-plane-bound-resolver-remoteapiconnector

Conversation

@youhaowei

@youhaowei youhaowei commented Jun 16, 2026

Copy link
Copy Markdown
Owner

Summary

  • Inverts the connector credential contract: RemoteApiConnector.connect() and query() carry no credential arguments; the constructor takes auth: SecretResolver (a capability-attenuated lease pre-bound to one SecretRef)
  • Defines SecretResolver = <T>(use: (plaintext: string) => Promise<T>) => Promise<T> in @dashframe/engine; exported from the engine entry point
  • NotionConnector uses this.auth(use => ...) internally; singleton removed, replaced by makeNotionConnector(auth) factory
  • mintBoundResolver(vault, ref, label) in apps/server/src/functions/app-artifacts.ts is the single mint site: (vault, ref) → boundResolver → connector
  • listNotionDatabases WyStack mutation reads the DataSource row, extracts the SecretRef from config, mints a resolver, and calls connector.connect() — no plaintext in scope at the call site
  • Renderer registers a metadata-only connector with a throwing resolver; connect()/query() route through server mutations, never the renderer IPC
  • queryNotionDatabase is deferred: NotionConnector.query() calls DataFrame.create({storageType:"indexeddb"}) which requires a browser environment; the server-safe query path belongs in a follow-on (see deferred comment in source)
  • FileSourceConnector.parse() removes the dead optional formData arg

Test coverage

  • connector.test.ts: resolver-count oracle for both connect() (existing) and query() (new); DataFrame.create mocked in Node environment
  • vault-control-plane.test.ts: two new mintBoundResolver fail-closed tests — no-vault path and plaintext-not-SecretRef path — exercised through listNotionDatabases

Gate

  • turbo typecheck: 44/44 pass
  • turbo test: connector-notion 73/73, server 191/191, app 473/473, all others pass
  • turbo lint: 18/18 pass

Tracked internally as YW-263.

🤖 Generated with Claude Code

Greptile Summary

This PR inverts the connector credential contract: RemoteApiConnector.connect() and query() no longer accept credential arguments; instead the constructor takes a SecretResolver capability-attenuated to one SecretRef. The renderer-registered connector gets a throwing resolver (metadata-only), while the server mints a bound resolver per DataSource row before constructing the connector. The tRPC stub (Provider.tsx) is deleted, and two new WyStack mutations (listNotionDatabases, queryNotionDatabase) replace the old tRPC routes. ConnectorQueryResult is also reshaped to be IPC-serializable (arrowBuffer + fieldIds + fields instead of a live DataFrame).

  • Core contract change: SecretResolver defined in @dashframe/engine, RemoteApiConnector base class now requires it in its constructor; NotionConnector calls this.auth(use => …) internally
  • Mint site: mintBoundResolver(vault, ref, label) in app-artifacts.ts is the single seam; fail-closed on no-vault and non-SecretRef paths — both exercised in new tests
  • Renderer safety: ConnectorCardWithForm now calls execute(async data => data) (form validation only), passing validated form values up to the stub onConnect handler; deferred flows in DataSourceDisplay are gated behind NOTION_ENABLED=false with explicit comments pointing to the follow-on wiring

Confidence Score: 5/5

Safe to merge — the credential-inversion contract is correctly enforced at every boundary: the renderer connector throws on connect/query, the mint site is fail-closed, and both server mutations resolve credentials exclusively through the vault's withSecret callback.

The auth-blind pipeline is structurally sound: SecretResolver is defined once and imported from the canonical export, mintBoundResolver is fail-closed on both the no-vault and non-SecretRef paths, and ConnectorQueryResult is now IPC-serializable with no live DataFrame. The tRPC stub is cleanly removed. All deferred code paths are gated behind NOTION_ENABLED=false with clear follow-on comments. The test matrix covers happy-path DTO mapping, resolver invocation counts, plaintext absence in responses, and all four fail-closed scenarios.

No files require special attention. DataSourceDisplay.tsx has intentionally dead code with a type annotation shaped for the old tRPC result; this will need updating when the preview path is wired to the new mutation.

Important Files Changed

Filename Overview
packages/engine/src/connector/base.ts Defines SecretResolver type and reworks RemoteApiConnector to require it in its constructor; connect() and query() signatures drop credential arguments. FileSourceConnector.parse() optional formData arg also removed.
apps/server/src/functions/app-artifacts.ts Adds mintBoundResolver factory (fail-closed), notionConnectorFor helper, and two new mutations listNotionDatabases / queryNotionDatabase; imports reorganized to bring in @dashframe/connector-notion and @dashframe/engine.
packages/connector-notion/src/connector.ts Singleton removed; makeNotionConnector(auth) factory added; connect() and query() use this.auth(use => …) with no credential param; query() no longer creates a DataFrame (serializable result only).
packages/app/src/components/data-sources/renderers/ConnectorCardWithForm.tsx Submit handler changed to execute(async data => data) — validates form and returns credentials to parent; connector.connect() is never called from the renderer. onConnect signature updated to accept Record<string, unknown> instead of RemoteDatabase[].
packages/app/src/components/data-sources/DataSourceDisplay.tsx tRPC mutation hooks removed; replaced with pendingQueryResult() / pendingSchema() guards that throw, each gated behind !NOTION_ENABLED short-circuits. Dead code path preserved for future wiring.
packages/app-data/src/notion.ts New module exporting useNotionMutations hook and imperative listNotionDatabases helper; both call server-side mutations via @wystack/client, with as casts on mutation return values.
apps/server/src/functions/notion-routes.test.ts New happy-path test file verifying DTO mapping, vault resolution count, and absence of plaintext in response.
apps/server/src/functions/vault-control-plane.test.ts Adds four new fail-closed tests: no-vault path, non-SecretRef config, wrong DataSource kind for both mutations.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant R as Renderer
    participant F as ConnectorCardWithForm
    participant SM as WyStack Mutation
    participant MBR as mintBoundResolver
    participant V as SecretVault
    participant NC as NotionConnector

    R->>F: user submits form (apiKey)
    F->>F: "execute(async data => data) validates"
    F-->>R: onConnect(connector, credentials) stub

    Note over SM,NC: Server-side path
    R->>SM: "listNotionDatabases({dataSourceId})"
    SM->>MBR: mintBoundResolver(vault, ref, label)
    MBR->>MBR: fail-closed checks
    MBR-->>SM: boundResolver
    SM->>NC: makeNotionConnector(boundResolver)
    SM->>NC: connector.connect()
    NC->>V: "this.auth(use => listDatabases(apiKey))"
    V-->>NC: plaintext (inside callback only)
    NC-->>SM: RemoteDatabase[]
    SM-->>R: "[{id, title}, ...]"
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 R as Renderer
    participant F as ConnectorCardWithForm
    participant SM as WyStack Mutation
    participant MBR as mintBoundResolver
    participant V as SecretVault
    participant NC as NotionConnector

    R->>F: user submits form (apiKey)
    F->>F: "execute(async data => data) validates"
    F-->>R: onConnect(connector, credentials) stub

    Note over SM,NC: Server-side path
    R->>SM: "listNotionDatabases({dataSourceId})"
    SM->>MBR: mintBoundResolver(vault, ref, label)
    MBR->>MBR: fail-closed checks
    MBR-->>SM: boundResolver
    SM->>NC: makeNotionConnector(boundResolver)
    SM->>NC: connector.connect()
    NC->>V: "this.auth(use => listDatabases(apiKey))"
    V-->>NC: plaintext (inside callback only)
    NC-->>SM: RemoteDatabase[]
    SM-->>R: "[{id, title}, ...]"
Loading

Comments Outside Diff (1)

  1. packages/app/src/hooks/useConnectorForm.ts, line 18 (link)

    P2 Stale JSDoc example still shows the old connect(data) signature. Since connect() is now auth-blind and takes no arguments, the example should be updated to avoid misleading future callers.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: packages/app/src/hooks/useConnectorForm.ts
    Line: 18
    
    Comment:
    Stale JSDoc example still shows the old `connect(data)` signature. Since `connect()` is now auth-blind and takes no arguments, the example should be updated to avoid misleading future callers.
    
    
    
    How can I resolve this? If you propose a fix, please make it concise.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

    Fix in Claude Code Fix in Codex Fix in Cursor

Reviews (3): Last reviewed commit: "chore(connector): address review nits — ..." | Re-trigger Greptile

Verification

Local gate (full graph) green before each push: turbo typecheck lint test — 85 tasks, all passing. Key runtime-behavior coverage:

  • Auth-blind query (Node-safe): connector.query() returns a serializable { arrowBuffer, fieldIds, fields } and builds no DataFrame — connector.test.ts asserts the shape, resolveCallCount === 1, and not.toHaveProperty("dataFrame"). Proves it runs without a browser/IndexedDB.
  • Server routes through the vault: notion-routes.test.ts exercises listNotionDatabases/queryNotionDatabase end-to-end through createWyStack + a TestBackend vault — verifies the {id,name}→{id,title} mapping, the serializable query payload, resolver-invoked-once, and that no plaintext appears in the response payload.
  • Fail-closed: vault-control-plane.test.ts covers no-vault, non-SecretRef config, and wrong-kind — all throw before any network call.
  • Capability attenuation: two connectors with separate bound resolvers cannot resolve each other's secret (connector.test.ts).
  • Renderer never resolves credentials: the renderer-registered connector uses a throwing resolver; connect()/query() are not called from the renderer (verified by grep + the throwing-resolver backstop). @ts-expect-error makeNotionConnector() makes the "auth is required" contract executable.

The NOTION_ENABLED renderer preview/property-selection UI is gated off (default false) and is a separate follow-on; the credential-inversion contract is what this ticket verifies.

@linear-code

linear-code Bot commented Jun 16, 2026

Copy link
Copy Markdown

YW-263

@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR shifts Notion connector operations from client-side singleton to a server-side factory pattern. A new SecretResolver type and makeNotionConnector(auth) factory replace the singleton. ConnectorQueryResult changes from a live DataFrame to a serializable Arrow IPC payload. Server-side listNotionDatabases and queryNotionDatabase handlers with fail-closed vault resolution are added, while the renderer UI is adapted to pass credentials instead of resolved databases.

Changes

Notion Server-Side Data-Plane with Vault-Backed SecretResolver

Layer / File(s) Summary
Engine contracts: SecretResolver, ConnectorQueryResult, RemoteApiConnector
packages/engine/src/connector/base.ts, packages/engine/src/connector/types.ts, packages/engine/src/connector/index.ts, packages/engine/src/index.ts
Adds the SecretResolver capability-attenuated type, changes ConnectorQueryResult from dataFrame: DataFrame to arrowBuffer/fieldIds/fields, removes formData from RemoteApiConnector.connect/query, and adds a constructor(auth: SecretResolver) to the abstract base class.
NotionConnector factory and serializable query
packages/connector-notion/src/connector.ts, packages/connector-notion/src/index.ts, packages/connector-notion/package.json
Replaces the notionConnector singleton with makeNotionConnector(auth) factory; connect()/query() resolve the API key via this.auth internally; query() returns a serializable Arrow IPC payload instead of constructing a browser DataFrame.
NotionConnector unit tests: factory, resolver attenuation, serializable result
packages/connector-notion/src/connector.test.ts
Rewrites tests to use makeNotionConnector(resolver) with a SecretVault/TestBackend; adds capability-attenuation, resolver-isolation, and serializable-result assertions; removes singleton-based tests.
Server-side Notion handlers: mintBoundResolver, notionConnectorFor, listNotionDatabases, queryNotionDatabase
apps/server/src/functions/app-artifacts.ts, apps/server/package.json
Adds mintBoundResolver (fail-closed vault/ref validation, single-ref attenuation via vault.withSecret), notionConnectorFor (loads data source row, verifies notion kind, constructs bound connector), and listNotionDatabases/queryNotionDatabase wired into appArtifactFunctions.
Server route tests: happy-path and fail-closed
apps/server/src/functions/notion-routes.test.ts, apps/server/src/functions/vault-control-plane.test.ts
Adds happy-path tests verifying {id,name}→{id,title} mapping, serializable query payload, and single credential resolution; extends vault tests with fail-closed assertions for missing vault, invalid SecretRef, and wrong DataSource kind.
app-data Notion client hooks and types
packages/app-data/src/notion.ts, packages/app-data/src/index.ts
Adds NotionDatabaseRef/NotionQueryResult interfaces, useNotionMutations() React hook, and imperative listNotionDatabases() function; re-exports them from the package index.
Renderer UI: credentials-based onConnect and DataSource migration
packages/app/src/components/data-sources/renderers/ConnectorCardWithForm.tsx, packages/app/src/components/data-sources/AddConnectionPanel.tsx, packages/app/src/components/data-sources/DataPickerContent.tsx, packages/app/src/components/data-sources/DataSourcesWorkbench.tsx, packages/app/src/components/data-sources/DataSourceControls.tsx, packages/app/src/components/data-sources/DataSourceDisplay.tsx, packages/app/src/components/providers/ConnectorSetup.tsx, packages/app/src/hooks/useConnectorForm.ts, packages/app/src/lib/connectors/registry.test.ts, packages/app/src/lib/trpc/Provider.tsx
Changes onConnect callback from databases[] to credentials across all call sites; migrates DataSourceControls to useNotionMutations/NotionDatabaseRef; stubs DataSourceDisplay Notion query paths behind NOTION_ENABLED; registers a non-functional renderer-side Notion connector via makeNotionConnector; removes the inert tRPC Provider stub.

Sequence Diagram(s)

sequenceDiagram
  participant Renderer as Renderer UI
  participant AppData as app-data (useNotionMutations)
  participant Server as Server (appArtifactFunctions)
  participant Vault as SecretVault
  participant NotionAPI as Notion API

  rect rgba(100, 149, 237, 0.5)
    Note over Renderer,NotionAPI: List Databases Flow
    Renderer->>AppData: notionMutations.listDatabases(dataSourceId)
    AppData->>Server: api.listNotionDatabases(dataSourceId)
    Server->>Vault: mintBoundResolver → vault.withSecret(ref)
    Vault-->>Server: bound SecretResolver
    Server->>NotionAPI: connector.connect() resolves API key via auth
    NotionAPI-->>Server: RemoteDatabase[]
    Server-->>AppData: NotionDatabaseRef[] {id, title}
    AppData-->>Renderer: NotionDatabaseRef[]
  end

  rect rgba(144, 238, 144, 0.5)
    Note over Renderer,NotionAPI: Query Database Flow
    Renderer->>AppData: notionMutations.queryDatabase(dataSourceId, databaseId, tableId)
    AppData->>Server: api.queryNotionDatabase(...)
    Server->>Vault: mintBoundResolver → vault.withSecret(ref)
    Vault-->>Server: bound SecretResolver
    Server->>NotionAPI: connector.query(databaseId, tableId) resolves API key via auth
    NotionAPI-->>Server: Arrow IPC data
    Server-->>AppData: NotionQueryResult {arrowBuffer, fieldIds, fields}
    AppData-->>Renderer: NotionQueryResult
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • youhaowei/DashFrame#100: Modifies ConnectorSetup.tsx connector registry bootstrapping, directly related to the Notion connector factory registration pattern introduced here.
  • youhaowei/DashFrame#119: Both PRs modify apps/server/src/functions/app-artifacts.ts for credential handling — the retrieved PR adds hasApiKey redaction flags while this PR adds fail-closed SecretRef-backed Notion data-plane resolution.
  • youhaowei/DashFrame#124: Directly related — adds vault injection and SecretRef-based store/presence control-plane semantics to app-artifacts.ts that this PR's mintBoundResolver depends on.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and specifically describes the main architectural change: inverting the connector credential contract through auth-blind design and SecretResolver bound-resolver pattern.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description is comprehensive and detailed, covering the major architectural changes, technical implementation, test coverage, and verification approach required by the repository's template.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread packages/app/src/components/data-sources/renderers/ConnectorCardWithForm.tsx Outdated
Comment thread apps/server/src/functions/app-artifacts.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a313c3952a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/app/src/components/data-sources/renderers/ConnectorCardWithForm.tsx Outdated
Comment thread apps/server/src/functions/app-artifacts.ts Outdated
youhaowei and others added 2 commits June 16, 2026 17:32
…solver

Inverts the connector credential contract so the pipeline is auth-blind:

- Define SecretResolver type in @dashframe/engine (capability-attenuated
  bound lease: <T>(use: (plaintext: string) => Promise<T>) => Promise<T>)
- RemoteApiConnector constructor takes auth: SecretResolver; connect() and
  query() carry no credential arguments
- FileSourceConnector.parse() removes the unused optional formData arg
- NotionConnector uses this.auth(use => ...) internally; exported via
  makeNotionConnector(auth) factory (singleton removed)
- mintBoundResolver(vault, ref, label) in server/app-artifacts.ts is the
  single mint site: (vault, ref) → boundResolver → connector
- listNotionDatabases WyStack mutation resolves the credential via vault;
  the handler has no plaintext in scope
- Renderer registers a metadata-only connector with a throwing resolver;
  connect()/query() route through server mutations, never the renderer
- queryNotionDatabase deferred: NotionConnector.query() calls
  DataFrame.create({storageType:indexeddb}) which requires a browser
  environment; the server-safe query path belongs in a follow-on
- Tests: resolver-count oracle for both connect() and query(); two
  mintBoundResolver fail-closed tests (no-vault + plaintext-not-ref)
  added to vault-control-plane.test.ts; DataFrame.create mocked in
  connector-notion tests (Node environment)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ugh server

Round 2 — resolves the open review threads and un-defers the query path.

Engine + connector contract:
- ConnectorQueryResult is now serializable: { arrowBuffer, fieldIds, fields }
  instead of a live DataFrame. This is the root unblock — a live DataFrame
  binds query() to a browser (IndexedDB) and can't cross IPC. NotionConnector
  .query() now returns the raw Arrow buffer + ids and builds no DataFrame, so
  it runs cleanly in a Node server handler. The renderer materializes the
  browser DataFrame from the result.

Server (app-artifacts.ts):
- queryNotionDatabase mutation un-deferred — resolves the credential via the
  bound resolver inside connector.query() and returns the serializable result.
- Shared notionConnectorFor(ctx, dataSourceId) seam: row lookup + kind guard +
  bound-resolver mint + connector construction, used by both notion routes.
- listNotionDatabases maps the connector's {id,name} to the renderer DTO
  {id,title} so DataSourceControls renders/adds by title without a mismatch.
- Import the canonical SecretResolver from @dashframe/engine (aliased
  BoundSecretResolver) instead of re-declaring the type; added @dashframe/engine
  as an explicit dep.

Renderer routing (the credential surface):
- ConnectorCardWithForm no longer calls connector.connect()/query(). It
  validates the form and hands the credentials up; the credential resolves
  SERVER-SIDE. onConnect now carries credentials, not a database list.
- DataSourceControls lists databases via useNotionMutations().listDatabases
  (new app-data hook over api.listNotionDatabases) — not the dead trpc stub.
- DataSourceDisplay's schema/property/preview flow (a separate NOTION_ENABLED
  feature) short-circuits before any server call; removed its dead trpc stubs.
- Deleted the orphaned trpc Provider stub.

Tests:
- query() asserts the serializable contract + resolveCallCount.
- queryNotionDatabase fail-closed (no-vault, wrong-kind) tests.
- New notion-routes happy-path tests: name→title mapping + serializable query
  result + resolver invoked once + no plaintext in the payload (mocked client).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@youhaowei youhaowei force-pushed the charixandra/yw-263-secretvault-data-plane-bound-resolver-remoteapiconnector branch from a313c39 to 025b456 Compare June 17, 2026 00:33
@youhaowei

Copy link
Copy Markdown
Owner Author

Round 2 — resolved all review threads + closed the query path

Thanks for the reviews. All four findings are addressed in 025b4569 (rebased onto main after #130):

P1 (Greptile) + P2 (Codex) — renderer calling connect() on the throwing connector (ConnectorCardWithForm.tsx)
The renderer no longer calls connector.connect()/query() at all. handleConnect now validates the form and hands the credentials up; the credential resolves server-side. The Notion database list is fetched through the listNotionDatabases WyStack mutation in DataSourceControls (which is keyed off a created DataSource's id — the correct post-creation seam). The dead trpc.notion.* stubs are gone (the orphaned trpc/Provider.tsx is deleted).

P2 (Codex) — preserve the {id, title} DTO (app-artifacts.ts)
listNotionDatabases now maps the connector's {id, name} to {id, title}, matching what DataSourceControls renders and adds by. A new notion-routes test asserts the mapping end-to-end.

P2 (Greptile) — inlined BoundSecretResolver (app-artifacts.ts)
Now import type { SecretResolver as BoundSecretResolver } from "@dashframe/engine" (added @dashframe/engine as an explicit dep). No more type duplication.

Closed the deferred query path (the heart of the ticket)
ConnectorQueryResult is now serializable ({ arrowBuffer, fieldIds, fields }) instead of a live DataFrame. That was the root reason query() couldn't run server-side — a BrowserDataFrame binds it to IndexedDB. NotionConnector.query() now returns the raw Arrow buffer + ids (no DataFrame.create), so queryNotionDatabase runs cleanly in a Node handler. The renderer materializes the browser DataFrame from the result. Tests cover the serializable contract, resolver-invoked-once, fail-closed (no-vault / wrong-kind), and the happy-path mapping.

Out of scope (follow-up): the frozen apps/web tRPC notion router still takes a plaintext apiKey input — that's the v0.2 web surface, untouched here, and should be removed/frozen separately.

Full local gate (turbo typecheck + lint + test, 85 tasks) green before push.

@coderabbitai coderabbitai 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.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/app/src/components/data-sources/AddConnectionPanel.tsx (1)

34-38: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update the example callback to use credentials, not databases.

The example still shows the old onConnect payload, which now conflicts with the updated prop contract and can mislead future integrations.

Suggested doc fix
- *   onConnect={(connector, databases) => handleConnect(databases)}
+ *   onConnect={(connector, credentials) => handleConnect(credentials)}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/app/src/components/data-sources/AddConnectionPanel.tsx` around lines
34 - 38, The JSDoc example for the AddConnectionPanel component shows an
outdated onConnect callback signature that receives databases as a parameter,
but the actual prop contract now expects credentials instead. Update the example
callback in the comment block to show onConnect receiving (connector,
credentials) instead of (connector, databases) to align with the current
implementation and prevent confusion for future integrations.
packages/app/src/hooks/useConnectorForm.ts (1)

17-21: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix the stale example to reflect connect()’s current signature.

The example still calls notionConnector.connect(data), but the updated contract resolves credentials internally and connect() no longer takes form data.

Suggested doc fix
- *     const databases = await execute((data) => notionConnector.connect(data));
+ *     const databases = await execute(async () => notionConnector.connect());
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/app/src/hooks/useConnectorForm.ts` around lines 17 - 21, The example
code for handleConnect in the useConnectorForm hook shows an outdated call to
notionConnector.connect(data), but the connect() method has been updated to no
longer accept form data as a parameter since it now resolves credentials
internally. Update the function call to remove the data argument being passed to
connect(), so it simply calls notionConnector.connect() without any parameters,
to reflect the current method signature.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/app-data/src/notion.ts`:
- Around line 22-26: The fields property in the NotionQueryResult interface
currently uses unknown[] as its type, which compromises type safety for the
public API contract. Replace the unknown[] type with the appropriate shared
field type definition used elsewhere in the codebase (typically a union or
concrete type representing valid field objects). This will ensure that renderer
and server implementations are checked at compile time for consistency rather
than using the overly permissive unknown type.

In `@packages/app/src/components/data-sources/DataSourcesWorkbench.tsx`:
- Around line 279-288: The handleRemoteConnect function currently only logs and
displays a toast message when a remote connector form is submitted, but does not
actually create a data source or persist the credentials, resulting in a broken
user workflow. Either implement the complete remote-source creation path by
calling the appropriate mutation to create the DataSource (storing credentials
as a vault SecretRef) and handling the response, or alternatively disable/hide
the remote connector submission option in the UI until the full implementation
is ready. Choose one approach based on your team's priorities for completing
this feature.

In `@packages/connector-notion/src/connector.test.ts`:
- Around line 209-219: The test for makeNotionConnector does not actually
validate the claimed TypeScript compile-time contract that the auth parameter is
required. Add a test case within the same it block that attempts to call
makeNotionConnector without any arguments and mark it with `@ts-expect-error`.
This ensures TypeScript prevents the call at compile time and guards against
accidental regression if the auth parameter becomes optional in the type
definition. The existing valid resolver test case can remain to demonstrate the
correct usage.

---

Outside diff comments:
In `@packages/app/src/components/data-sources/AddConnectionPanel.tsx`:
- Around line 34-38: The JSDoc example for the AddConnectionPanel component
shows an outdated onConnect callback signature that receives databases as a
parameter, but the actual prop contract now expects credentials instead. Update
the example callback in the comment block to show onConnect receiving
(connector, credentials) instead of (connector, databases) to align with the
current implementation and prevent confusion for future integrations.

In `@packages/app/src/hooks/useConnectorForm.ts`:
- Around line 17-21: The example code for handleConnect in the useConnectorForm
hook shows an outdated call to notionConnector.connect(data), but the connect()
method has been updated to no longer accept form data as a parameter since it
now resolves credentials internally. Update the function call to remove the data
argument being passed to connect(), so it simply calls notionConnector.connect()
without any parameters, to reflect the current method signature.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5b146b57-acbd-47a4-85be-36463c07d266

📥 Commits

Reviewing files that changed from the base of the PR and between f82c7c1 and 025b456.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (24)
  • apps/server/package.json
  • apps/server/src/functions/app-artifacts.ts
  • apps/server/src/functions/notion-routes.test.ts
  • apps/server/src/functions/vault-control-plane.test.ts
  • packages/app-data/src/index.ts
  • packages/app-data/src/notion.ts
  • packages/app/src/components/data-sources/AddConnectionPanel.tsx
  • packages/app/src/components/data-sources/DataPickerContent.tsx
  • packages/app/src/components/data-sources/DataSourceControls.tsx
  • packages/app/src/components/data-sources/DataSourceDisplay.tsx
  • packages/app/src/components/data-sources/DataSourcesWorkbench.tsx
  • packages/app/src/components/data-sources/renderers/ConnectorCardWithForm.tsx
  • packages/app/src/components/providers/ConnectorSetup.tsx
  • packages/app/src/hooks/useConnectorForm.ts
  • packages/app/src/lib/connectors/registry.test.ts
  • packages/app/src/lib/trpc/Provider.tsx
  • packages/connector-notion/package.json
  • packages/connector-notion/src/connector.test.ts
  • packages/connector-notion/src/connector.ts
  • packages/connector-notion/src/index.ts
  • packages/engine/src/connector/base.ts
  • packages/engine/src/connector/index.ts
  • packages/engine/src/connector/types.ts
  • packages/engine/src/index.ts
💤 Files with no reviewable changes (1)
  • packages/app/src/lib/trpc/Provider.tsx

Comment thread packages/app-data/src/notion.ts
Comment thread packages/app/src/components/data-sources/DataSourcesWorkbench.tsx
Comment thread packages/connector-notion/src/connector.test.ts
…contract test

- NotionQueryResult.fields: unknown[] → Field[] (typed end-to-end contract)
- connector test: @ts-expect-error on makeNotionConnector() makes AC #1's
  "auth is required" compile-time contract executable (fails if auth ever
  goes optional)
- refresh stale JSDoc examples in AddConnectionPanel + useConnectorForm to the
  credentials-based onConnect / no-arg connect() contract

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@youhaowei youhaowei merged commit 422f5d7 into main Jun 17, 2026
19 checks passed
@youhaowei youhaowei deleted the charixandra/yw-263-secretvault-data-plane-bound-resolver-remoteapiconnector branch June 17, 2026 02:06
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