Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/apps-user-connection-request-auth-bulk-update.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@slack/web-api": minor
---

feat: add support for apps.user.connection.requestAuth and apps.user.connection.bulkUpdate
20 changes: 20 additions & 0 deletions packages/web-api/src/methods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ import type {
AppsManifestUpdateArguments,
AppsManifestValidateArguments,
AppsUninstallArguments,
AppsUserConnectionBulkUpdateArguments,
AppsUserConnectionRequestAuthArguments,
AppsUserConnectionUpdateArguments,
AssistantThreadsSetStatusArguments,
AssistantThreadsSetSuggestedPromptsArguments,
Expand Down Expand Up @@ -400,6 +402,8 @@ import type {
AppsManifestUpdateResponse,
AppsManifestValidateResponse,
AppsUninstallResponse,
AppsUserConnectionBulkUpdateResponse,
AppsUserConnectionRequestAuthResponse,
AppsUserConnectionUpdateResponse,
AssistantThreadsSetStatusResponse,
AssistantThreadsSetSuggestedPromptsResponse,
Expand Down Expand Up @@ -1589,6 +1593,22 @@ export abstract class Methods extends EventEmitter<WebClientEvent> {
uninstall: bindApiCall<AppsUninstallArguments, AppsUninstallResponse>(this, 'apps.uninstall'),
user: {
connection: {
/**
* @description Updates the connection status between an app and many users in one call, for backfilling an existing user base.
* @see {@link https://docs.slack.dev/reference/methods/apps.user.connection.bulkUpdate `apps.user.connection.bulkUpdate` API reference}.
*/
bulkUpdate: bindApiCall<AppsUserConnectionBulkUpdateArguments, AppsUserConnectionBulkUpdateResponse>(
this,
'apps.user.connection.bulkUpdate',
),
/**
* @description Opens or updates a standardized authentication modal for the calling app.
* @see {@link https://docs.slack.dev/reference/methods/apps.user.connection.requestAuth `apps.user.connection.requestAuth` API reference}.
*/
requestAuth: bindApiCall<AppsUserConnectionRequestAuthArguments, AppsUserConnectionRequestAuthResponse>(
this,
'apps.user.connection.requestAuth',
),
/**
* @description Updates the connection status between a user and an app.
* @see {@link https://docs.slack.dev/reference/methods/apps.user.connection.update `apps.user.connection.update` API reference}.
Expand Down
73 changes: 73 additions & 0 deletions packages/web-api/src/types/request/apps.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { Overflow, PlainTextElement } from '@slack/types';

import type { OptionalArgument } from '../helpers';

import type { AppID, CursorPaginationEnabled, OAuthCredentials, TokenOverridable } from './common';
Expand Down Expand Up @@ -32,6 +34,77 @@ export interface AppsManifestValidateArguments extends Partial<AppID>, TokenOver
manifest: Manifest;
}

interface UserConnectionConnectedUserIDs {
/**
* @description IDs of users connected to the app.
* One of `connected_user_ids` or `disconnected_user_ids` is required; combined they may not exceed 1000.
*/
connected_user_ids: string[];
disconnected_user_ids?: string[];
}

interface UserConnectionDisconnectedUserIDs {
connected_user_ids?: string[];
/**
* @description IDs of users not connected to the app.
* One of `connected_user_ids` or `disconnected_user_ids` is required; combined they may not exceed 1000.
*/
disconnected_user_ids: string[];
}

// https://docs.slack.dev/reference/methods/apps.user.connection.bulkUpdate
export type AppsUserConnectionBulkUpdateArguments = TokenOverridable &
(UserConnectionConnectedUserIDs | UserConnectionDisconnectedUserIDs);

export interface UserConnectionPrimaryProvider {
/**
* @description Unique identifier for this provider within the app. Included in interaction payloads and used to
* derive the connect button `action_id` (`auth_provider_connect_<value>`).
*/
value: string;
/** @description Human-readable name of the provider. */
name: PlainTextElement;
/**
* @description Whether this provider is currently connected or disconnected. Slack records this state for the user,
* so an omitted value would be indistinguishable from an explicit `false` and silently mark the user disconnected.
*/
is_connected: boolean;
/** @description Brief description of what this connection enables. */
description?: PlainTextElement;
/** @description URL for the provider icon image. Must be HTTPs format. Falls back to the app's avatar when absent. */
icon_url?: string;
/** @description OAuth redirect URL opened when the user clicks **Connect**. Must be HTTPs format. */
auth_url?: string;
/** @description URL opened when the user clicks **Disconnect**. Must be HTTPs format on a registered auth host. */
disconnect_url?: string;
/** @description Display name of the connected account, shown when `is_connected` is `true`. */
connected_identity?: PlainTextElement;
/** @description Additional context about the connection (e.g., org or workspace name). */
connected_context?: PlainTextElement;
/** @description Overflow menu shown when connected (e.g., Disconnect, Re-authenticate). */
accessory?: Overflow;
}

interface UserConnectionTriggerID {
/** @description The `trigger_id` from the `user_connection` interactive callback. Opens a new modal. */
trigger_id: string;
}

interface UserConnectionUserID {
/**
* @description The user whose auth modal to update. Required when `trigger_id` is omitted, and ignored when it is
* present.
*/
user_id: string;
}

// https://docs.slack.dev/reference/methods/apps.user.connection.requestAuth
export type AppsUserConnectionRequestAuthArguments = TokenOverridable &
(UserConnectionTriggerID | UserConnectionUserID) & {
/** @description The connection to render. Its `icon_url` defaults to the app's own avatar when omitted. */
primary_provider: UserConnectionPrimaryProvider;
};

// https://docs.slack.dev/reference/methods/apps.user.connection.update
export interface AppsUserConnectionUpdateArguments extends TokenOverridable {
/** @description The identifier for the user receiving the status update. */
Expand Down
3 changes: 3 additions & 0 deletions packages/web-api/src/types/request/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,10 @@ export type {
AppsManifestUpdateArguments,
AppsManifestValidateArguments,
AppsUninstallArguments,
AppsUserConnectionBulkUpdateArguments,
AppsUserConnectionRequestAuthArguments,
AppsUserConnectionUpdateArguments,
UserConnectionPrimaryProvider,
} from './apps';
export type {
AssistantThreadsSetStatusArguments,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/////////////////////////////////////////////////////////////////////////////////////////
// //
// !!! DO NOT EDIT THIS FILE !!! //
// //
// This file is auto-generated by scripts/generate-web-api-types.sh in the repository. //
// Please refer to the script code to learn how to update the source data. //
// //
/////////////////////////////////////////////////////////////////////////////////////////

import type { WebAPICallResult } from '../../WebClient';
export type AppsUserConnectionBulkUpdateResponse = WebAPICallResult & {
changed_user_ids?: string[];
error?: string;
failures?: Failure[];
needed?: string;
ok?: boolean;
provided?: string;
response_metadata?: ResponseMetadata;
warning?: string;
};

export interface Failure {
error?: string;
user_id?: string;
}

export interface ResponseMetadata {
messages?: string[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/////////////////////////////////////////////////////////////////////////////////////////
// //
// !!! DO NOT EDIT THIS FILE !!! //
// //
// This file is auto-generated by scripts/generate-web-api-types.sh in the repository. //
// Please refer to the script code to learn how to update the source data. //
// //
/////////////////////////////////////////////////////////////////////////////////////////

import type { WebAPICallResult } from '../../WebClient';
export type AppsUserConnectionRequestAuthResponse = WebAPICallResult & {
error?: string;
needed?: string;
ok?: boolean;
provided?: string;
response_metadata?: ResponseMetadata;
warning?: string;
};

export interface ResponseMetadata {
messages?: string[];
warnings?: string[];
}
2 changes: 2 additions & 0 deletions packages/web-api/src/types/response/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ export { AppsPermissionsScopesListResponse } from './AppsPermissionsScopesListRe
export { AppsPermissionsUsersListResponse } from './AppsPermissionsUsersListResponse';
export { AppsPermissionsUsersRequestResponse } from './AppsPermissionsUsersRequestResponse';
export { AppsUninstallResponse } from './AppsUninstallResponse';
export { AppsUserConnectionBulkUpdateResponse } from './AppsUserConnectionBulkUpdateResponse';
export { AppsUserConnectionRequestAuthResponse } from './AppsUserConnectionRequestAuthResponse';
export { AppsUserConnectionUpdateResponse } from './AppsUserConnectionUpdateResponse';
export { AssistantThreadsSetStatusResponse } from './AssistantThreadsSetStatusResponse';
export { AssistantThreadsSetSuggestedPromptsResponse } from './AssistantThreadsSetSuggestedPromptsResponse';
Expand Down
86 changes: 86 additions & 0 deletions packages/web-api/test/types/methods/apps.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,92 @@ expectAssignable<Parameters<typeof web.apps.manifest.validate>>([
},
]);

// apps.user.connection.bulkUpdate
// -- sad path
expectError(web.apps.user.connection.bulkUpdate()); // lacking argument
expectError(web.apps.user.connection.bulkUpdate({})); // missing both connected_user_ids and disconnected_user_ids
// -- happy path
expectAssignable<Parameters<typeof web.apps.user.connection.bulkUpdate>>([
{
connected_user_ids: ['U1234'],
},
]);
expectAssignable<Parameters<typeof web.apps.user.connection.bulkUpdate>>([
{
disconnected_user_ids: ['U5678'],
},
]);
expectAssignable<Parameters<typeof web.apps.user.connection.bulkUpdate>>([
{
connected_user_ids: ['U1234'],
disconnected_user_ids: ['U5678'],
},
]);

// apps.user.connection.requestAuth
// -- sad path
expectError(web.apps.user.connection.requestAuth()); // lacking argument
expectError(web.apps.user.connection.requestAuth({})); // empty argument
expectError(
web.apps.user.connection.requestAuth({
primary_provider: { value: 'github', name: { type: 'plain_text', text: 'GitHub' }, is_connected: false }, // missing trigger_id or user_id
}),
);
expectError(
web.apps.user.connection.requestAuth({
user_id: 'U1234', // missing primary_provider
}),
);
expectError(
web.apps.user.connection.requestAuth({
user_id: 'U1234',
primary_provider: { name: { type: 'plain_text', text: 'GitHub' }, is_connected: false }, // missing value
}),
);
expectError(
web.apps.user.connection.requestAuth({
user_id: 'U1234',
primary_provider: { value: 'github', is_connected: false }, // missing name
}),
);
expectError(
web.apps.user.connection.requestAuth({
user_id: 'U1234',
primary_provider: { value: 'github', name: { type: 'plain_text', text: 'GitHub' } }, // missing is_connected
}),
);
// -- happy path
expectAssignable<Parameters<typeof web.apps.user.connection.requestAuth>>([
{
trigger_id: '1234567890.1234567890.abcdef0123456789',
primary_provider: {
value: 'github',
name: { type: 'plain_text', text: 'GitHub' },
is_connected: true,
description: { type: 'plain_text', text: 'Link pull requests to conversations' },
icon_url: 'https://example.com/icon.png',
auth_url: 'https://example.com/oauth',
disconnect_url: 'https://example.com/disconnect',
connected_identity: { type: 'plain_text', text: 'octocat' },
connected_context: { type: 'plain_text', text: 'Acme Inc.' },
accessory: {
type: 'overflow',
action_id: 'provider-menu',
options: [
{ text: { type: 'plain_text', text: 'Switch accounts' }, value: 'switch' },
{ text: { type: 'plain_text', text: 'Disconnect' }, value: 'disconnect' },
],
},
},
},
]);
expectAssignable<Parameters<typeof web.apps.user.connection.requestAuth>>([
{
user_id: 'U1234',
primary_provider: { value: 'github', name: { type: 'plain_text', text: 'GitHub' }, is_connected: false },
},
]);

// apps.user.connection.update
// -- sad path
expectError(web.apps.user.connection.update()); // lacking argument
Expand Down
Loading