|
| 1 | +--- |
| 2 | +name: add-selector |
| 3 | +description: Add or update a Sim dynamic selector using the shared manifest, server attachment, and selectors.execute path. Use for provider-backed, internal, or local option lists referenced by block, trigger, or connector selectorKey fields. |
| 4 | +argument-hint: <selector-key> |
| 5 | +--- |
| 6 | + |
| 7 | +# Add Selector |
| 8 | + |
| 9 | +Dynamic selectors expose option metadata while a workflow or connector is being configured. Every |
| 10 | +remote selector executes through the authorized `selectors.execute` application operation; the |
| 11 | +browser never resolves credentials or calls a provider directly. |
| 12 | + |
| 13 | +## Read the shared boundary |
| 14 | + |
| 15 | +Before editing, read: |
| 16 | + |
| 17 | +- `apps/sim/lib/selectors/types.ts` |
| 18 | +- `apps/sim/lib/selectors/manifest.ts` |
| 19 | +- `apps/sim/lib/selectors/context.ts` |
| 20 | +- `apps/sim/lib/selectors/server/types.ts` |
| 21 | +- `apps/sim/lib/selectors/server/registry.ts` |
| 22 | +- `apps/sim/hooks/queries/selectors.ts` |
| 23 | + |
| 24 | +Then read the nearest existing selector attachment and the block, trigger, or connector declaration |
| 25 | +that will consume the key. |
| 26 | + |
| 27 | +## Classify the selector |
| 28 | + |
| 29 | +- `provider-server`: contacts an external provider or uses provider credentials. |
| 30 | +- `internal-server`: reads protected Sim data through an existing authorized application use case. |
| 31 | +- `local`: pure browser-safe data with no protected data, credentials, references, or network I/O. |
| 32 | + |
| 33 | +Add every key to the browser-safe manifest in `lib/selectors/manifest.ts`. `SelectorKey` derives from |
| 34 | +that manifest; do not maintain a second union. Manifest entries contain data only: allowed context, |
| 35 | +readiness, scope kinds, list/search/detail capabilities, and stale time. Do not import provider SDKs, |
| 36 | +credentials, server helpers, or attachment functions into the manifest. |
| 37 | + |
| 38 | +## Build context from active values |
| 39 | + |
| 40 | +Declare `dependsOn` on the consuming sub-block or connector field. The shared context builder sends |
| 41 | +only declared, active dependencies: |
| 42 | + |
| 43 | +- Canonical basic/advanced pairs contribute the active value under their canonical key. |
| 44 | +- Action and trigger modes contribute only fields active on that surface. |
| 45 | +- Exact environment references such as `{{GMAIL_CREDENTIAL_ID}}` remain unresolved in the browser. |
| 46 | +- Runtime block-output references are not selector context. |
| 47 | +- Embedded environment interpolation such as `https://{{HOST}}/path` is unsupported. |
| 48 | + |
| 49 | +Add a new `SelectorContextKey` only when the value is a real, reusable selector dependency. Allow it |
| 50 | +explicitly on each relevant manifest entry. Never send a full block or connector configuration. |
| 51 | + |
| 52 | +## Add the server attachment |
| 53 | + |
| 54 | +Add the service's attachment map under `apps/sim/lib/selectors/server/providers/` and include it in |
| 55 | +the exhaustive server registry. A provider attachment declares: |
| 56 | + |
| 57 | +- Credential policy, including the exact context field and trusted `serviceIds`. |
| 58 | +- Destination policy: `fixed`, `credential-bound`, or `user-controlled`. |
| 59 | +- A list/detail adapter that explicitly projects `id`, `label`, and allowlisted scalar `meta`. |
| 60 | + |
| 61 | +Stored credentials must pass actor-use, workspace, and provider/service binding checks. Do not trust |
| 62 | +a provider, service, operation kind, origin, or module name supplied by the browser. |
| 63 | + |
| 64 | +Choose the destination policy deliberately: |
| 65 | + |
| 66 | +- `fixed`: provider origin is code-defined. |
| 67 | +- `credential-bound`: origin/account/site comes from, or is verified against, the authorized |
| 68 | + credential. |
| 69 | +- `user-controlled`: the user selects the destination. Hidden use-only authentication requires an |
| 70 | + explicit security policy; do not combine it with an arbitrary destination by default. |
| 71 | + |
| 72 | +Reuse or extract a server-only provider listing primitive. If an existing provider route has |
| 73 | +non-selector callers, keep the route as a thin caller of that primitive. If it is selector-only, |
| 74 | +move the logic and remove the obsolete route and contract. Never import a route handler or make an |
| 75 | +internal HTTP request from an attachment. |
| 76 | + |
| 77 | +The attachment must return normalized selector results only. It must not return provider payloads, |
| 78 | +resolved context, credential IDs, tokens, or secrets. Let the shared executor own scope |
| 79 | +authorization, exact-reference resolution, credential authorization, error projection, output |
| 80 | +sanitization, and abort propagation. |
| 81 | + |
| 82 | +## Wire the UI declaration |
| 83 | + |
| 84 | +Point the block, trigger, or connector field at `selectorKey` and declare its `dependsOn` fields. |
| 85 | +Keep connector selector/manual canonical pairs and fork reconfiguration behavior intact. Static |
| 86 | +`options` stay local and need no selector. |
| 87 | + |
| 88 | +Do not add: |
| 89 | + |
| 90 | +- A module under `hooks/selectors/providers` or any client provider fetcher. |
| 91 | +- A provider-specific React Query key. |
| 92 | +- A selector-specific OAuth-token request. |
| 93 | +- A selector-only API route when the provider primitive can be called directly. |
| 94 | + |
| 95 | +All server selectors use the shared POST contract and React Query facade. Query identities must stay |
| 96 | +opaque and must not include context values, references, credential IDs, secrets, or their hashes. |
| 97 | + |
| 98 | +## Focused validation |
| 99 | + |
| 100 | +Follow nearby Vitest and route-test style. Do not add an authorization matrix for every ordinary |
| 101 | +provider attachment; the shared executor tests own shared security behavior. |
| 102 | + |
| 103 | +Add a focused adapter test when behavior is special, such as pagination, nontrivial destination |
| 104 | +binding, provider-specific projection, or a raw-connection policy. For an ordinary fixed-origin OAuth |
| 105 | +list, manifest/registry exhaustiveness plus an existing provider primitive test is usually enough. |
| 106 | + |
| 107 | +Run the smallest relevant set, then: |
| 108 | + |
| 109 | +```bash |
| 110 | +bunx vitest run <focused selector tests> |
| 111 | +bun run --cwd apps/sim type-check |
| 112 | +bun run check:fork-dependent-coverage |
| 113 | +bun run check:client-boundary |
| 114 | +git diff --check |
| 115 | +``` |
| 116 | + |
| 117 | +Confirm there is no browser-side provider call, every server key has one attachment, and every |
| 118 | +returned option is explicitly projected. |
0 commit comments