Skip to content

Commit 5612ff7

Browse files
committed
Merge remote-tracking branch 'origin/staging' into wip/platform-org-wiring
# Conflicts: # apps/sim/lib/credentials/token-service-accounts/server.ts # apps/sim/lib/workspaces/public-queries.ts
2 parents c725e3f + 8718b9c commit 5612ff7

590 files changed

Lines changed: 6502 additions & 1463 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.agents/skills/add-block/SKILL.md‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,40 @@ export const {ServiceName}Block: BlockConfig = {
159159

160160
Optional companions: `credentialLabels` (override the picker's section/connect-row copy) and `allowServiceAccounts: true` (trigger-mode only — list service accounts, which triggers otherwise exclude; set only when the trigger's polling path can resolve a service-account token). The connect modal, provider families (Google JSON key, Atlassian token, token-paste, client-credential, Slack bot), and the preview gate are all resolved from `serviceAccountProviderId` — you don't wire them per block.
161161

162+
### Credential-only successor (replacing inline secrets)
163+
164+
A block that takes a secret inline keeps running for existing workflows; the saved-credential
165+
version is a new block type that spreads it. Keep the successor an object literal with the picker
166+
written inline, because the docs generator reads the source text:
167+
168+
```typescript
169+
export const ServiceV2Block: BlockConfig = {
170+
...ServiceBlock,
171+
type: 'service_v2',
172+
authMode: AuthMode.OAuth,
173+
hideFromToolbar: false,
174+
sunset: undefined,
175+
...withSavedCredential(ServiceBlock, {
176+
id: 'credential',
177+
type: 'oauth-input',
178+
serviceId: 'service',
179+
title: 'Service Credential',
180+
}),
181+
}
182+
```
183+
184+
- The legacy block changes only by `hideFromToolbar: true` and `sunset: { status: 'legacy',
185+
replacedBy: 'service_v2' }` (an older `_v2` points at the new `_v3`). Register both types.
186+
- `withSavedCredential` (`blocks/utils.ts`) swaps exactly the fields its policy in
187+
`SAVED_CREDENTIAL_OAUTH` supplies for the picker, places it directly under the operation
188+
dropdown, inherits the replaced fields' `condition` and `required`, and leaves trigger-mode
189+
fields alone. Pass `required` when the replaced fields disagree (an optional host), and `params`
190+
only when the legacy params builder validates the secret: extract that builder so the legacy
191+
block calls it unchanged (`blocks/legacy-builders.test.ts`) and the successor skips the check.
192+
- Add the pair to `serializer/saved-credentials.test.ts` (`optionalIds` for replaced fields the
193+
legacy block never required), and grep for code that hard-codes the legacy type (`getBlock`,
194+
`integration.type ===`, availability lookups), which now resolves to the successor.
195+
162196
### OAuth deployment availability (required for integration blocks)
163197

164198
A visible tools-category block with OAuth is deployment-gated. Its `oauth-input.serviceId` is

‎.agents/skills/add-integration/SKILL.md‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,42 @@ Use explicit permission choices when the supported operations have different acc
6666
region and permission selections on reconnect unless the user changes them. Verify documented
6767
identity endpoints rather than guessing which person a client-credentials token represents.
6868

69+
### Token credentials (API key, personal access token, token + host)
70+
71+
A service authenticated by a pasted key or token takes it through a saved token credential, never an
72+
inline `password` field, so one shared, verified credential serves every block. Wire it by the
73+
service id:
74+
75+
1. `apps/sim/lib/credentials/token-service-accounts/descriptors.ts`: a provider id and descriptor.
76+
Fields are `apiToken`, plus `domain` for a host, instance URL, or region and
77+
`providerWorkspaceId` for an account or org id; every listed field is required. Set `url: true`
78+
on a `domain` that is a URL whose scheme or path matters, so the connect form sends it as typed.
79+
2. `validators/token-checks.ts`: one `tokenCheckValidator` declaration (register it in
80+
`server.ts`). Make one cheap, documented read on the tools' own host with the tools' own auth,
81+
reusing their header and URL builders. `domain` and `workspaceId` normalize to exactly the form
82+
the tools build URLs from and throw for anything that could steer the host or path
83+
(`normalizeHttpBaseUrl`, `allowedDomain`, `refuseUrlCredentials`); the normalized domain is what
84+
the credential stores. Set `egress` when the user chooses the host. Add `forbiddenMeansScoped`,
85+
`rejectsKey`, or `provesKey` only for documented replies (probe a fake key to see how a bad one
86+
answers), and `errorBodyEchoesToken` when an error body echoes the token.
87+
3. `apps/sim/lib/oauth/oauth.ts` and `types.ts`: the service entry (`authType: 'service_account'`,
88+
`serviceAccountProviderId`).
89+
4. `apps/sim/tools/shared/saved-credentials.ts`: `tokenCredentialOAuth('<service>', { <toolParam>:
90+
'accessToken' | 'domain' | 'providerWorkspaceId' })`, listed in `SAVED_CREDENTIAL_OAUTH`, and set
91+
as `oauth` on every tool. Map every param that decides the request host; the executor overwrites
92+
mapped params after authorizing the credential, and `check-block-registry` probes the tools' real
93+
URL builders and fails on a host-steering param left unmapped.
94+
5. A credential-only block (including a successor) uses `authMode: AuthMode.OAuth`, so the
95+
generated catalog maps the service; a token-only block that keeps `AuthMode.ApiKey`, as Coda
96+
does, registers in `tokenCredentialIntegrationTypes` instead (see below). The credential picker
97+
sits directly under the operation dropdown (`add-block` → OAuth/Credentials). An existing block that already takes the secret inline is never edited in
98+
place: add a credential-only successor (`add-block` → Credential-only successor).
99+
100+
Then run `generate-docs`, `generate:block-successors`, `generate:deployment-config`, and
101+
`generate:tool-metadata`, and `check-block-registry.ts origin/staging`. This pattern does not fit
102+
hosted-key tools, model-provider keys, two-secret or username/password logins, or a host chosen
103+
per call.
104+
69105
### Pair saved credentials with block and resource selectors
70106

71107
`oauth-input` is the shared saved-credential picker, including for service accounts that never

‎.agents/skills/add-tools/SKILL.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ export const {serviceName}{Action}Tool: ToolConfig<
8989
provider: '{service}', // Must match the service id in OAUTH_PROVIDERS
9090
// credentialKind: 'service-account', // service-account-only integrations
9191
},
92+
// A token credential (API key, PAT, token + host) instead uses the service's shared policy from
93+
// tools/shared/saved-credentials.ts, built with tokenCredentialOAuth('{service}', { apiKey:
94+
// 'accessToken' }). Its keys are the tool's own token/host/account params, which the executor
95+
// fills after authorizing the credential.
9296

9397
params: {
9498
// Hidden params (system-injected, e.g. the OAuth accessToken)

‎.agents/skills/validate-integration/SKILL.md‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,17 @@ For **each tool** in `tools.access`:
218218
- True/false → `switch` (a Yes/No `dropdown` only when the tool needs a third "unset" state)
219219
- Credentials → `oauth-input` with correct `serviceId`
220220
- Every tool with a `credential`/`oauthCredential` param declares `oauth: { required: true, provider }` matching that `serviceId`, plus `credentialKind: 'service-account'` when only service accounts are supported
221+
- [ ] In a new block or credential-only successor, a pasted key, token, or token + host comes from a
222+
saved token credential (add-integration → Token credentials), not an inline `password` field
223+
(legacy blocks keep theirs); a successor changes its legacy block only by `hideFromToolbar`
224+
and `sunset`, and its picker sits under the operation
225+
- [ ] For a token-credential integration, every tool in `tools.access` declares the service's
226+
`tokenCredentialOAuth` policy, every
227+
param that decides the request host is mapped, and the stored domain is in the form the tools
228+
build URLs from (`check-block-registry.ts origin/staging` passes)
229+
- [ ] The `tokenCheckValidator` request uses the tools' host and auth, its normalizers refuse
230+
anything that could steer the host or path, and a fake key is rejected without a valid
231+
scoped key being refused
221232
- [ ] Dropdown `value: () => 'default'` is set for dropdowns with a sensible default
222233
- [ ] Every `short-input`, `long-input`, `code`, and selector subBlock has a `placeholder` — including
223234
password fields (`Enter your API key`). Formatted values show the shape

‎apps/docs/components/docs/icon-mapping/icon-mapping.ts‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
343343
ahrefs_v2: AhrefsIcon,
344344
airtable: AirtableIcon,
345345
algolia: AlgoliaIcon,
346+
algolia_v2: AlgoliaIcon,
346347
amplitude: AmplitudeIcon,
347348
api: ApiIcon,
348349
api_trigger: ApiIcon,
@@ -361,6 +362,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
361362
attio: AttioIcon,
362363
azure_data_explorer: AzureDataExplorerIcon,
363364
azure_devops: AzureIcon,
365+
azure_devops_v2: AzureIcon,
364366
bitbucket: BitbucketIcon,
365367
box: BoxCompanyIcon,
366368
box_v2: BoxCompanyIcon,
@@ -403,6 +405,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
403405
confluence_v2: ConfluenceIcon,
404406
context_dev: ContextDevIcon,
405407
convex: ConvexIcon,
408+
convex_v2: ConvexIcon,
406409
credential: CredentialIcon,
407410
credential_group: GridOffset,
408411
crowdstrike: CrowdStrikeIcon,
@@ -420,6 +423,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
420423
daytona_v2: DaytonaIcon,
421424
deployments: Rocket,
422425
devin: DevinIcon,
426+
devin_v2: DevinIcon,
423427
discord: DiscordIcon,
424428
discord_v2: DiscordIcon,
425429
docusign: DocuSignIcon,
@@ -435,12 +439,14 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
435439
dynamodb: DynamoDBIcon,
436440
dynamodb_v2: DynamoDBIcon,
437441
dynatrace: DynatraceIcon,
442+
dynatrace_v2: DynatraceIcon,
438443
ec2: EC2Icon,
439444
ec2_v2: EC2Icon,
440445
elasticsearch: ElasticsearchIcon,
441446
elevenlabs: ElevenLabsIcon,
442447
elevenlabs_v2: ElevenLabsIcon,
443448
emailbison: EmailBisonIcon,
449+
emailbison_v2: EmailBisonIcon,
444450
embeddings: EmbeddingsIcon,
445451
enrich: EnrichSoIcon,
446452
enrich_v2: EnrichSoIcon,
@@ -506,6 +512,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
506512
'google-drive': GoogleDriveIcon,
507513
'google-sheets': GoogleSheetsIcon,
508514
grafana: GrafanaIcon,
515+
grafana_v2: GrafanaIcon,
509516
grain: GrainIcon,
510517
grain_v2: GrainIcon,
511518
grain_v3: GrainIcon,
@@ -537,6 +544,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
537544
incidentio: IncidentioIcon,
538545
incidentio_v2: IncidentioIcon,
539546
infisical: InfisicalIcon,
547+
infisical_v2: InfisicalIcon,
540548
input_trigger: FormInput,
541549
instantly: InstantlyIcon,
542550
instantly_v2: InstantlyIcon,
@@ -549,9 +557,11 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
549557
jira: JiraIcon,
550558
jira_service_management: JiraServiceManagementIcon,
551559
jotform: JotformIcon,
560+
jotform_v2: JotformIcon,
552561
jsm: JiraServiceManagementIcon,
553562
jupyter: JupyterIcon,
554563
jupyter_v2: JupyterIcon,
564+
jupyter_v3: JupyterIcon,
555565
kalshi: KalshiIcon,
556566
kalshi_v2: KalshiIcon,
557567
ketch: KetchIcon,
@@ -573,6 +583,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
573583
linq: LinqIcon,
574584
linq_v2: LinqIcon,
575585
logfire: LogfireIcon,
586+
logfire_v2: LogfireIcon,
576587
logrocket: LogRocketIcon,
577588
logs: Library,
578589
logs_v2: Library,
@@ -583,6 +594,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
583594
mailchimp: MailchimpIcon,
584595
mailchimp_v2: MailchimpIcon,
585596
mailgun: MailgunIcon,
597+
mailgun_v2: MailgunIcon,
586598
managed_agent: ClaudeIcon,
587599
manageengine_sdp: ManageEngineIcon,
588600
manual_trigger: Play,
@@ -615,12 +627,14 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
615627
netsuite: NetSuiteIcon,
616628
neverbounce: NeverBounceIcon,
617629
new_relic: NewRelicIcon,
630+
new_relic_v2: NewRelicIcon,
618631
note: NoteIcon,
619632
notion: NotionIcon,
620633
notion_v2: NotionIcon,
621634
obsidian: ObsidianIcon,
622635
oci: OracleIcon,
623636
okta: OktaIcon,
637+
okta_v2: OktaIcon,
624638
onedrive: MicrosoftOneDriveIcon,
625639
onepassword: OnePasswordIcon,
626640
openai: OpenAIIcon,
@@ -641,6 +655,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
641655
pipedrive: PipedriveIcon,
642656
pitchbook: PitchBookIcon,
643657
plane: PlaneIcon,
658+
plane_v2: PlaneIcon,
644659
planetscale: PlanetScaleIcon,
645660
polymarket: PolymarketIcon,
646661
postgresql: PostgresIcon,
@@ -743,6 +758,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
743758
stt: STTIcon,
744759
stt_v2: STTIcon,
745760
supabase: SupabaseIcon,
761+
supabase_v2: SupabaseIcon,
746762
table: Table,
747763
table_v2: Table,
748764
tailscale: TailscaleIcon,
@@ -757,8 +773,10 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
757773
textract_v3: TextractIcon,
758774
thinking: BrainIcon,
759775
thrive: ThriveIcon,
776+
thrive_v2: ThriveIcon,
760777
tiktok: TikTokIcon,
761778
tinybird: TinybirdIcon,
779+
tinybird_v2: TinybirdIcon,
762780
tinyfish: TinyFishIcon,
763781
translate: TranslateIcon,
764782
trello: TrelloIcon,
@@ -767,10 +785,13 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
767785
tts: TTSIcon,
768786
twilio: TwilioIcon,
769787
twilio_sms: TwilioIcon,
788+
twilio_sms_v2: TwilioIcon,
770789
twilio_voice: TwilioIcon,
790+
twilio_voice_v2: TwilioIcon,
771791
typeform: TypeformIcon,
772792
typeform_v2: TypeformIcon,
773793
upstash: UpstashIcon,
794+
upstash_v2: UpstashIcon,
774795
uptimerobot: UptimeRobotIcon,
775796
uptimerobot_v2: UptimeRobotIcon,
776797
vanta: VantaIcon,

‎apps/docs/content/docs/cli/reference.mdx‎

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8849,12 +8849,12 @@ sim workspaces fork-resources [options]
88498849

88508850
API request and response schemas: [listWorkspaceForkResources](/api-reference/workspace-sync/listWorkspaceForkResources).
88518851

8852-
### sim workspaces members
8852+
### sim workspaces members list [#sim-workspaces-members]
88538853

88548854
List workspace members
88558855

88568856
```bash
8857-
sim workspaces members [options]
8857+
sim workspaces members list [options]
88588858
```
88598859

88608860
**Options**
@@ -8869,6 +8869,68 @@ sim workspaces members [options]
88698869

88708870
API request and response schemas: [listWorkspaceMembers](/api-reference/workspaces/listWorkspaceMembers).
88718871

8872+
### sim workspaces members remove
8873+
8874+
Remove workspace member (OAuth login or personal API key required)
8875+
8876+
This removes the member’s workspace access. If it was their last workspace in the organization, their organization membership is removed and their sessions end.
8877+
8878+
```bash
8879+
sim workspaces members remove <userId> [options]
8880+
```
8881+
8882+
**Arguments**
8883+
8884+
<CommandTable>
8885+
8886+
| Argument | Required | Description |
8887+
| --- | --- | --- |
8888+
| `userId` | Yes | User identifier of the workspace member, as returned by List workspace members. |
8889+
8890+
</CommandTable>
8891+
8892+
**Options**
8893+
8894+
<CommandTable>
8895+
8896+
| Option | Required | Description |
8897+
| --- | --- | --- |
8898+
| `-y, --yes` | Yes | Confirm this operation. |
8899+
8900+
</CommandTable>
8901+
8902+
API request and response schemas: [removeWorkspaceMember](/api-reference/workspaces/removeWorkspaceMember).
8903+
8904+
### sim workspaces members update
8905+
8906+
Update workspace member (OAuth login or personal API key required)
8907+
8908+
```bash
8909+
sim workspaces members update <userId> [options]
8910+
```
8911+
8912+
**Arguments**
8913+
8914+
<CommandTable>
8915+
8916+
| Argument | Required | Description |
8917+
| --- | --- | --- |
8918+
| `userId` | Yes | User identifier of the workspace member, as returned by List workspace members. |
8919+
8920+
</CommandTable>
8921+
8922+
**Options**
8923+
8924+
<CommandTable>
8925+
8926+
| Option | Required | Description |
8927+
| --- | --- | --- |
8928+
| `--role <value>` | Yes | New workspace role. Inherited organization Admin access, the workspace owner, and the workspace billing account keep Admin and cannot be changed here. Accepted values: `admin`, `write`, `read`. |
8929+
8930+
</CommandTable>
8931+
8932+
API request and response schemas: [updateWorkspaceMember](/api-reference/workspaces/updateWorkspaceMember).
8933+
88728934
### sim workspaces list
88738935

88748936
List workspaces

0 commit comments

Comments
 (0)