diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index eef52aa..6dc52c3 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -19,3 +19,4 @@ jobs: bash ./bin/check-release-environment env: NPM_TOKEN: ${{ secrets.BEEPER_DESKTOP_NPM_TOKEN || secrets.NPM_TOKEN }} + diff --git a/.gitignore b/.gitignore index 74cba89..d62bea5 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,6 @@ dist dist-deno /*.tgz .idea/ +.eslintcache dist-bundle *.mcpb diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 18e45d5..0f24e47 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.5" + ".": "0.1.6" } diff --git a/.stats.yml b/.stats.yml index fc8ce6a..c2693cc 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 14 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper%2Fbeeper-desktop-api-8c712fe19f280b0b89ecc8a3ce61e9f6b165cee97ce33f66c66a7a5db339c755.yml -openapi_spec_hash: 1ea71129cc1a1ccc3dc8a99566082311 -config_hash: 061b75b88f80bb43b4121e5e7c1255e2 +configured_endpoints: 15 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper%2Fbeeper-desktop-api-a3fb0de6dd98f8a51d73e3fdf51de6143f2e8e764048246392624a56b4a3a481.yml +openapi_spec_hash: 50e1001c340cb0bd3436b6329240769b +config_hash: 2e31d02f28a11ef29eb747bcf559786a diff --git a/CHANGELOG.md b/CHANGELOG.md index fce55f0..5d424b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,54 @@ # Changelog +## 0.1.6 (2025-10-07) + +Full Changelog: [v0.1.5...v0.1.6](https://github.com/beeper/desktop-api-js/compare/v0.1.5...v0.1.6) + +### Features + +* **api:** manual updates ([e12ab16](https://github.com/beeper/desktop-api-js/commit/e12ab16a4664ef6b770750225dc0e9ea53005b89)) +* **api:** manual updates ([914badc](https://github.com/beeper/desktop-api-js/commit/914badc5d98d1b3ab5b7d1b404c687110ef34913)) +* **api:** manual updates ([e657efe](https://github.com/beeper/desktop-api-js/commit/e657efe6bf48b6c76e09060ac00c8e0403213982)) +* **api:** manual updates ([0de85a3](https://github.com/beeper/desktop-api-js/commit/0de85a39f784415474e73187609e4ef4c5fe2cf1)) +* **api:** manual updates ([d7c35d2](https://github.com/beeper/desktop-api-js/commit/d7c35d27538be9752a6e15a4d17c4b5354b44b3f)) +* **api:** manual updates ([80f8804](https://github.com/beeper/desktop-api-js/commit/80f880478414edcba479e4717c5a1033a2545d3d)) +* **api:** manual updates ([e404d7e](https://github.com/beeper/desktop-api-js/commit/e404d7ebd08830f115f7468598cc275db637d508)) +* **api:** manual updates ([540c168](https://github.com/beeper/desktop-api-js/commit/540c168bfa982178e5ab743c9ef3986784438617)) +* **api:** manual updates ([3501ff9](https://github.com/beeper/desktop-api-js/commit/3501ff900847979fcf7b6e543a99364b74a979a5)) +* **api:** manual updates ([d1a5970](https://github.com/beeper/desktop-api-js/commit/d1a5970f917e9ddfe1060a4129feee7bb1be1414)) +* **api:** remove limit from list routes ([c145154](https://github.com/beeper/desktop-api-js/commit/c1451540df373793b5fd90e780faab8acf38a1dc)) +* **mcp:** add option for including docs tools ([a521cb8](https://github.com/beeper/desktop-api-js/commit/a521cb8f972778c0253b657b712da7681dd78853)) +* **mcp:** enable experimental docs search tool ([c349699](https://github.com/beeper/desktop-api-js/commit/c349699a05745356ce3d12dc693d643a85a52d5d)) + + +### Bug Fixes + +* **mcp:** fix cli argument parsing logic ([98c6489](https://github.com/beeper/desktop-api-js/commit/98c6489b8780dbe7d4ba377fb64364fb862fc7f7)) +* **mcp:** resolve a linting issue in server code ([2c84441](https://github.com/beeper/desktop-api-js/commit/2c8444166c9b4e6f67c9bf4827989aee65d672e8)) + + +### Performance Improvements + +* faster formatting ([a4321bf](https://github.com/beeper/desktop-api-js/commit/a4321bf9c91f3043414724486c130f3b0bd25606)) + + +### Chores + +* configure new SDK language ([f50310b](https://github.com/beeper/desktop-api-js/commit/f50310b4a7cc3e2286430530c8ffc867f77f7ef9)) +* configure new SDK language ([fee94ba](https://github.com/beeper/desktop-api-js/commit/fee94ba4b23ec91abc030ddbb872c08af43e2df8)) +* do not install brew dependencies in ./scripts/bootstrap by default ([cd62f83](https://github.com/beeper/desktop-api-js/commit/cd62f83fc5e6e93501df72cf49c0ee2838e02476)) +* fix changelog with actual entries ([45de3f5](https://github.com/beeper/desktop-api-js/commit/45de3f5a1d86486b9752e32cbd5283d6efe88434)) +* **internal:** codegen related update ([3598172](https://github.com/beeper/desktop-api-js/commit/3598172f0839f111c6000c9f29502d21afabee0c)) +* **internal:** codegen related update ([44137d6](https://github.com/beeper/desktop-api-js/commit/44137d644ffcd7407acc815a68d8df093e17f45d)) +* **internal:** fix incremental formatting in some cases ([697d742](https://github.com/beeper/desktop-api-js/commit/697d742608fead14c628f5d809b6a4beedff4656)) +* **internal:** ignore .eslintcache ([22d7f29](https://github.com/beeper/desktop-api-js/commit/22d7f29cd477bf4d22c68b51cd4b99bcf710efbd)) +* **internal:** remove .eslintcache ([f2a0dfb](https://github.com/beeper/desktop-api-js/commit/f2a0dfbd7930292f715ab530a6dedbf53e6ae8e3)) +* **internal:** remove deprecated `compilerOptions.baseUrl` from tsconfig.json ([ffaa6d6](https://github.com/beeper/desktop-api-js/commit/ffaa6d646236e88ecf997dc9a0b77733029a885b)) +* **internal:** use npm pack for build uploads ([31e0341](https://github.com/beeper/desktop-api-js/commit/31e0341efbad7c4b9abc13d145c477eb3676cc0b)) +* **jsdoc:** fix [@link](https://github.com/link) annotations to refer only to parts of the package‘s public interface ([8cf89a9](https://github.com/beeper/desktop-api-js/commit/8cf89a9e31969a45d24179342955b2a4e931ae6f)) +* **mcp:** allow pointing `docs_search` tool at other URLs ([6044c34](https://github.com/beeper/desktop-api-js/commit/6044c3467dd578e2fba46fa10f83ad3240222c3f)) +* update lockfile ([a9a736f](https://github.com/beeper/desktop-api-js/commit/a9a736fba58dde3c39bc2f5501be1ae30f380367)) + ## 0.1.5 (2025-09-19) Full Changelog: [v0.1.4...v0.1.5](https://github.com/beeper/desktop-api-js/compare/v0.1.4...v0.1.5) diff --git a/api.md b/api.md index 54b94fd..4c59aba 100644 --- a/api.md +++ b/api.md @@ -1,3 +1,17 @@ +# BeeperDesktop + +Types: + +- DownloadAssetResponse +- OpenResponse +- SearchResponse + +Methods: + +- client.downloadAsset({ ...params }) -> DownloadAssetResponse +- client.open({ ...params }) -> OpenResponse +- client.search({ ...params }) -> SearchResponse + # Shared Types: @@ -18,21 +32,7 @@ Types: Methods: -- client.accounts.list() -> AccountListResponse - -# App - -Types: - -- AppDownloadAssetResponse -- AppOpenResponse -- AppSearchResponse - -Methods: - -- client.app.downloadAsset({ ...params }) -> AppDownloadAssetResponse -- client.app.open({ ...params }) -> AppOpenResponse -- client.app.search({ ...params }) -> AppSearchResponse +- client.accounts.list() -> AccountListResponse # Contacts @@ -42,7 +42,7 @@ Types: Methods: -- client.contacts.search({ ...params }) -> ContactSearchResponse +- client.contacts.search({ ...params }) -> ContactSearchResponse # Chats @@ -50,20 +50,22 @@ Types: - Chat - ChatCreateResponse +- ChatListResponse Methods: -- client.chats.create({ ...params }) -> ChatCreateResponse -- client.chats.retrieve({ ...params }) -> Chat -- client.chats.archive({ ...params }) -> BaseResponse -- client.chats.search({ ...params }) -> ChatsCursor +- client.chats.create({ ...params }) -> ChatCreateResponse +- client.chats.retrieve(chatID, { ...params }) -> Chat +- client.chats.list({ ...params }) -> ChatListResponsesCursorList +- client.chats.archive(chatID, { ...params }) -> BaseResponse +- client.chats.search({ ...params }) -> ChatsCursorSearch ## Reminders Methods: -- client.chats.reminders.create({ ...params }) -> BaseResponse -- client.chats.reminders.delete({ ...params }) -> BaseResponse +- client.chats.reminders.create(chatID, { ...params }) -> BaseResponse +- client.chats.reminders.delete(chatID) -> BaseResponse # Messages @@ -73,16 +75,6 @@ Types: Methods: -- client.messages.search({ ...params }) -> MessagesCursor -- client.messages.send({ ...params }) -> MessageSendResponse - -# Token - -Types: - -- RevokeRequest -- UserInfo - -Methods: - -- client.token.info() -> UserInfo +- client.messages.list({ ...params }) -> MessagesCursorList +- client.messages.search({ ...params }) -> MessagesCursorSearch +- client.messages.send({ ...params }) -> MessageSendResponse diff --git a/package.json b/package.json index bf401d4..f94972f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@beeper/desktop-api", - "version": "0.1.5", + "version": "0.1.6", "description": "The official TypeScript library for the Beeper Desktop API", "author": "Beeper Desktop ", "types": "dist/index.d.ts", diff --git a/packages/mcp-server/README.md b/packages/mcp-server/README.md index 2ab4e18..2616e14 100644 --- a/packages/mcp-server/README.md +++ b/packages/mcp-server/README.md @@ -180,7 +180,7 @@ http://localhost:3000?client=cursor&capability=tool-name-length%3D40 import { server, endpoints, init } from "@beeper/desktop-mcp/server"; // import a specific tool -import getAccounts from "@beeper/desktop-mcp/tools/accounts/get-accounts"; +import openInApp from "@beeper/desktop-mcp/tools/top-level/open-in-app"; // initialize the server and all endpoints init({ server, endpoints }); @@ -205,22 +205,22 @@ const myCustomEndpoint = { }; // initialize the server with your custom endpoints -init({ server: myServer, endpoints: [getAccounts, myCustomEndpoint] }); +init({ server: myServer, endpoints: [openInApp, myCustomEndpoint] }); ``` ## Available Tools The following tools are available in this MCP server. -### Resource `accounts`: - -- `get_accounts` (`read`) tags: [accounts]: List connected accounts on this device. Use to pick account context. - -### Resource `app`: +### Resource `$client`: - `open_in_app` (`write`) tags: [app]: Open Beeper Desktop and optionally navigate to a specific chat, message, or pre-fill draft text and attachment. - `search` (`read`) tags: [app]: Search for chats, participant name matches in groups, and the first page of messages in one call. Use this when the user asks for a specific chat, group, or person. +### Resource `accounts`: + +- `get_accounts` (`read`) tags: [accounts]: List connected accounts on this device. + ### Resource `chats`: - `get_chat` (`read`) tags: [chats]: Get chat details: metadata, participants (limited), last activity. diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index b9510db..04c01af 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -1,6 +1,6 @@ { "name": "@beeper/desktop-mcp", - "version": "0.1.5", + "version": "0.1.6", "description": "The official MCP Server for the Beeper Desktop API", "author": "Beeper Desktop ", "types": "dist/index.d.ts", diff --git a/packages/mcp-server/src/docs-search-tool.ts b/packages/mcp-server/src/docs-search-tool.ts new file mode 100644 index 0000000..eb89849 --- /dev/null +++ b/packages/mcp-server/src/docs-search-tool.ts @@ -0,0 +1,48 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Metadata, asTextContentResult } from './tools/types'; + +import { Tool } from '@modelcontextprotocol/sdk/types.js'; + +export const metadata: Metadata = { + resource: 'all', + operation: 'read', + tags: [], + httpMethod: 'get', +}; + +export const tool: Tool = { + name: 'search_docs', + description: + 'Search for documentation for how to use the client to interact with the API.\nThe tool will return an array of Markdown-formatted documentation pages.', + inputSchema: { + type: 'object', + properties: { + query: { + type: 'string', + description: 'The query to search for.', + }, + language: { + type: 'string', + description: 'The language for the SDK to search for.', + enum: ['http', 'python', 'go', 'typescript', 'terraform', 'ruby', 'java', 'kotlin'], + }, + }, + required: ['query', 'language'], + }, + annotations: { + readOnlyHint: true, + }, +}; + +const docsSearchURL = + process.env['DOCS_SEARCH_URL'] || 'https://api.stainless.com/api/projects/beeper-desktop-api/docs/search'; + +export const handler = async (_: unknown, args: Record | undefined) => { + const body = args as any; + const query = new URLSearchParams(body).toString(); + const result = await fetch(`${docsSearchURL}?${query}`); + return asTextContentResult(await result.json()); +}; + +export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/options.ts b/packages/mcp-server/src/options.ts index ecc9f10..4fe3b98 100644 --- a/packages/mcp-server/src/options.ts +++ b/packages/mcp-server/src/options.ts @@ -17,6 +17,7 @@ export type McpOptions = { includeDynamicTools?: boolean | undefined; includeAllTools?: boolean | undefined; includeCodeTools?: boolean | undefined; + includeDocsTools?: boolean | undefined; filters?: Filter[] | undefined; capabilities?: Partial | undefined; }; @@ -55,13 +56,13 @@ export function parseCLIOptions(): CLIOptions { .option('tools', { type: 'string', array: true, - choices: ['dynamic', 'all', 'code'], + choices: ['dynamic', 'all', 'code', 'docs'], description: 'Use dynamic tools or all tools', }) .option('no-tools', { type: 'string', array: true, - choices: ['dynamic', 'all', 'code'], + choices: ['dynamic', 'all', 'code', 'docs'], description: 'Do not use any dynamic or all tools', }) .option('tool', { @@ -245,13 +246,15 @@ export function parseCLIOptions(): CLIOptions { } } - const shouldIncludeToolType = (toolType: 'dynamic' | 'all' | 'code') => - explicitTools ? argv.tools?.includes(toolType) && !argv.noTools?.includes(toolType) : undefined; + const shouldIncludeToolType = (toolType: 'dynamic' | 'all' | 'code' | 'docs') => + argv.noTools?.includes(toolType) ? false + : argv.tools?.includes(toolType) ? true + : undefined; - const explicitTools = Boolean(argv.tools || argv.noTools); const includeDynamicTools = shouldIncludeToolType('dynamic'); const includeAllTools = shouldIncludeToolType('all'); const includeCodeTools = shouldIncludeToolType('code'); + const includeDocsTools = shouldIncludeToolType('docs'); const transport = argv.transport as 'stdio' | 'http'; @@ -261,6 +264,7 @@ export function parseCLIOptions(): CLIOptions { includeDynamicTools, includeAllTools, includeCodeTools, + includeDocsTools, filters, capabilities: clientCapabilities, list: argv.list || false, @@ -280,8 +284,8 @@ const coerceArray = (zodType: T) => ); const QueryOptions = z.object({ - tools: coerceArray(z.enum(['dynamic', 'all'])).describe('Use dynamic tools or all tools'), - no_tools: coerceArray(z.enum(['dynamic', 'all'])).describe('Do not use dynamic tools or all tools'), + tools: coerceArray(z.enum(['dynamic', 'all', 'docs'])).describe('Use dynamic tools or all tools'), + no_tools: coerceArray(z.enum(['dynamic', 'all', 'docs'])).describe('Do not use dynamic tools or all tools'), tool: coerceArray(z.string()).describe('Include tools matching the specified names'), resource: coerceArray(z.string()).describe('Include tools matching the specified resources'), operation: coerceArray(z.enum(['read', 'write'])).describe( @@ -376,11 +380,17 @@ export function parseQueryOptions(defaultOptions: McpOptions, query: unknown): M : queryOptions.tools?.includes('all') ? true : defaultOptions.includeAllTools; + let docsTools: boolean | undefined = + queryOptions.no_tools && queryOptions.no_tools?.includes('docs') ? false + : queryOptions.tools?.includes('docs') ? true + : defaultOptions.includeDocsTools; + return { client: queryOptions.client ?? defaultOptions.client, includeDynamicTools: dynamicTools, includeAllTools: allTools, includeCodeTools: undefined, + includeDocsTools: docsTools, filters, capabilities: clientCapabilities, }; diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index 3f193eb..314817c 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -21,6 +21,7 @@ import { } from './compat'; import { dynamicTools } from './dynamic-tools'; import { codeTool } from './code-tool'; +import docsSearchTool from './docs-search-tool'; import { McpOptions } from './options'; export { McpOptions } from './options'; @@ -33,7 +34,7 @@ export const newMcpServer = () => new McpServer( { name: 'beeper_desktop_api_api', - version: '0.1.5', + version: '0.1.6', }, { capabilities: { tools: {}, logging: {} }, @@ -151,7 +152,7 @@ export function initMcpServer(params: { export async function selectTools(endpoints: Endpoint[], options?: McpOptions): Promise { const filteredEndpoints = query(options?.filters ?? [], endpoints); - let includedTools = filteredEndpoints; + let includedTools = filteredEndpoints.slice(); if (includedTools.length > 0) { if (options?.includeDynamicTools) { @@ -159,16 +160,18 @@ export async function selectTools(endpoints: Endpoint[], options?: McpOptions): } } else { if (options?.includeAllTools) { - includedTools = endpoints; + includedTools = endpoints.slice(); } else if (options?.includeDynamicTools) { includedTools = dynamicTools(endpoints); } else if (options?.includeCodeTools) { includedTools = [await codeTool()]; } else { - includedTools = endpoints; + includedTools = endpoints.slice(); } } - + if (options?.includeDocsTools ?? true) { + includedTools.push(docsSearchTool); + } const capabilities = { ...defaultClientCapabilities, ...options?.capabilities }; return applyCompatibilityTransformations(includedTools, capabilities); } diff --git a/packages/mcp-server/src/tools/accounts/get-accounts.ts b/packages/mcp-server/src/tools/accounts/get-accounts.ts index c0aa224..85fe44c 100644 --- a/packages/mcp-server/src/tools/accounts/get-accounts.ts +++ b/packages/mcp-server/src/tools/accounts/get-accounts.ts @@ -10,13 +10,13 @@ export const metadata: Metadata = { operation: 'read', tags: ['accounts'], httpMethod: 'get', - httpPath: '/v0/get-accounts', - operationId: 'get_accounts', + httpPath: '/v1/accounts', + operationId: 'getAccounts', }; export const tool: Tool = { name: 'get_accounts', - description: 'List connected accounts on this device. Use to pick account context.', + description: 'List connected accounts on this device.', inputSchema: { type: 'object', properties: {}, diff --git a/packages/mcp-server/src/tools/chats/archive-chat.ts b/packages/mcp-server/src/tools/chats/archive-chat.ts index e0ecebd..c5eb924 100644 --- a/packages/mcp-server/src/tools/chats/archive-chat.ts +++ b/packages/mcp-server/src/tools/chats/archive-chat.ts @@ -10,8 +10,8 @@ export const metadata: Metadata = { operation: 'write', tags: ['chats'], httpMethod: 'post', - httpPath: '/v0/archive-chat', - operationId: 'archive_chat', + httpPath: '/v1/chats/{chatID}/archive', + operationId: 'archiveChat', }; export const tool: Tool = { @@ -36,8 +36,8 @@ export const tool: Tool = { }; export const handler = async (client: BeeperDesktop, args: Record | undefined) => { - const body = args as any; - return asTextContentResult(await client.chats.archive(body)); + const { chatID, ...body } = args as any; + return asTextContentResult(await client.chats.archive(chatID, body)); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/chats/get-chat.ts b/packages/mcp-server/src/tools/chats/get-chat.ts index c31d6f4..9ab3537 100644 --- a/packages/mcp-server/src/tools/chats/get-chat.ts +++ b/packages/mcp-server/src/tools/chats/get-chat.ts @@ -10,8 +10,8 @@ export const metadata: Metadata = { operation: 'read', tags: ['chats'], httpMethod: 'get', - httpPath: '/v0/get-chat', - operationId: 'get_chat', + httpPath: '/v1/chats/{chatID}', + operationId: 'getChat', }; export const tool: Tool = { @@ -39,8 +39,8 @@ export const tool: Tool = { }; export const handler = async (client: BeeperDesktop, args: Record | undefined) => { - const body = args as any; - return asTextContentResult(await client.chats.retrieve(body)); + const { chatID, ...body } = args as any; + return asTextContentResult(await client.chats.retrieve(chatID, body)); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/chats/reminders/clear-chat-reminder.ts b/packages/mcp-server/src/tools/chats/reminders/clear-chat-reminder.ts index 6177be5..c7bd13d 100644 --- a/packages/mcp-server/src/tools/chats/reminders/clear-chat-reminder.ts +++ b/packages/mcp-server/src/tools/chats/reminders/clear-chat-reminder.ts @@ -9,9 +9,9 @@ export const metadata: Metadata = { resource: 'chats.reminders', operation: 'write', tags: ['chats'], - httpMethod: 'post', - httpPath: '/v0/clear-chat-reminder', - operationId: 'clear_chat_reminder', + httpMethod: 'delete', + httpPath: '/v1/chats/{chatID}/reminders', + operationId: 'clearChatReminder', }; export const tool: Tool = { @@ -28,12 +28,14 @@ export const tool: Tool = { }, required: ['chatID'], }, - annotations: {}, + annotations: { + idempotentHint: true, + }, }; export const handler = async (client: BeeperDesktop, args: Record | undefined) => { - const body = args as any; - return asTextContentResult(await client.chats.reminders.delete(body)); + const { chatID, ...body } = args as any; + return asTextContentResult(await client.chats.reminders.delete(chatID)); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/chats/reminders/set-chat-reminder.ts b/packages/mcp-server/src/tools/chats/reminders/set-chat-reminder.ts index 521d7fd..b311372 100644 --- a/packages/mcp-server/src/tools/chats/reminders/set-chat-reminder.ts +++ b/packages/mcp-server/src/tools/chats/reminders/set-chat-reminder.ts @@ -10,8 +10,8 @@ export const metadata: Metadata = { operation: 'write', tags: ['chats'], httpMethod: 'post', - httpPath: '/v0/set-chat-reminder', - operationId: 'set_chat_reminder', + httpPath: '/v1/chats/{chatID}/reminders', + operationId: 'setChatReminder', }; export const tool: Tool = { @@ -46,8 +46,8 @@ export const tool: Tool = { }; export const handler = async (client: BeeperDesktop, args: Record | undefined) => { - const body = args as any; - return asTextContentResult(await client.chats.reminders.create(body)); + const { chatID, ...body } = args as any; + return asTextContentResult(await client.chats.reminders.create(chatID, body)); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/chats/search-chats.ts b/packages/mcp-server/src/tools/chats/search-chats.ts index bc746d9..bfe61d7 100644 --- a/packages/mcp-server/src/tools/chats/search-chats.ts +++ b/packages/mcp-server/src/tools/chats/search-chats.ts @@ -10,8 +10,8 @@ export const metadata: Metadata = { operation: 'read', tags: ['chats'], httpMethod: 'get', - httpPath: '/v0/search-chats', - operationId: 'search_chats', + httpPath: '/v1/chats/search', + operationId: 'searchChats', }; export const tool: Tool = { @@ -26,7 +26,7 @@ export const tool: Tool = { description: 'Provide an array of account IDs to filter chats from specific messaging accounts only', items: { type: 'string', - description: 'Beeper account ID this resource belongs to.', + description: 'Account ID this resource belongs to.', }, }, cursor: { diff --git a/packages/mcp-server/src/tools/index.ts b/packages/mcp-server/src/tools/index.ts index e3ad0a9..4f1144e 100644 --- a/packages/mcp-server/src/tools/index.ts +++ b/packages/mcp-server/src/tools/index.ts @@ -4,9 +4,9 @@ import { Metadata, Endpoint, HandlerFunction } from './types'; export { Metadata, Endpoint, HandlerFunction }; +import open_in_app from './top-level/open-in-app'; +import search from './top-level/search'; import get_accounts from './accounts/get-accounts'; -import open_in_app from './app/open-in-app'; -import search from './app/search'; import get_chat from './chats/get-chat'; import archive_chat from './chats/archive-chat'; import search_chats from './chats/search-chats'; @@ -21,9 +21,9 @@ function addEndpoint(endpoint: Endpoint) { endpoints.push(endpoint); } -addEndpoint(get_accounts); addEndpoint(open_in_app); addEndpoint(search); +addEndpoint(get_accounts); addEndpoint(get_chat); addEndpoint(archive_chat); addEndpoint(search_chats); diff --git a/packages/mcp-server/src/tools/messages/search-messages.ts b/packages/mcp-server/src/tools/messages/search-messages.ts index f9ca9c7..93d735c 100644 --- a/packages/mcp-server/src/tools/messages/search-messages.ts +++ b/packages/mcp-server/src/tools/messages/search-messages.ts @@ -10,8 +10,8 @@ export const metadata: Metadata = { operation: 'read', tags: ['messages'], httpMethod: 'get', - httpPath: '/v0/search-messages', - operationId: 'search_messages', + httpPath: '/v1/messages/search', + operationId: 'searchMessages', }; export const tool: Tool = { @@ -23,15 +23,15 @@ export const tool: Tool = { properties: { accountIDs: { type: 'array', - description: 'Limit search to specific Beeper account IDs (bridge instances).', + description: 'Limit search to specific account IDs.', items: { type: 'string', - description: 'Beeper account ID this resource belongs to.', + description: 'Account ID this resource belongs to.', }, }, chatIDs: { type: 'array', - description: 'Limit search to specific Beeper chat IDs.', + description: 'Limit search to specific chat IDs.', items: { type: 'string', }, diff --git a/packages/mcp-server/src/tools/messages/send-message.ts b/packages/mcp-server/src/tools/messages/send-message.ts index 93a7e8a..60668a7 100644 --- a/packages/mcp-server/src/tools/messages/send-message.ts +++ b/packages/mcp-server/src/tools/messages/send-message.ts @@ -10,8 +10,8 @@ export const metadata: Metadata = { operation: 'write', tags: ['messages'], httpMethod: 'post', - httpPath: '/v0/send-message', - operationId: 'send_message', + httpPath: '/v1/messages', + operationId: 'sendMessage', }; export const tool: Tool = { @@ -23,7 +23,7 @@ export const tool: Tool = { properties: { chatID: { type: 'string', - description: 'Unique identifier of the chat (a.k.a. room or thread).', + description: 'Unique identifier of the chat.', }, replyToMessageID: { type: 'string', diff --git a/packages/mcp-server/src/tools/app/open-in-app.ts b/packages/mcp-server/src/tools/top-level/open-in-app.ts similarity index 91% rename from packages/mcp-server/src/tools/app/open-in-app.ts rename to packages/mcp-server/src/tools/top-level/open-in-app.ts index bf8fbb1..d7cac93 100644 --- a/packages/mcp-server/src/tools/app/open-in-app.ts +++ b/packages/mcp-server/src/tools/top-level/open-in-app.ts @@ -6,12 +6,12 @@ import { Tool } from '@modelcontextprotocol/sdk/types.js'; import BeeperDesktop from '@beeper/desktop-api'; export const metadata: Metadata = { - resource: 'app', + resource: '$client', operation: 'write', tags: ['app'], httpMethod: 'post', - httpPath: '/v0/open-app', - operationId: 'open_app', + httpPath: '/v1/open', + operationId: 'openApp', }; export const tool: Tool = { @@ -46,7 +46,7 @@ export const tool: Tool = { export const handler = async (client: BeeperDesktop, args: Record | undefined) => { const body = args as any; - return asTextContentResult(await client.app.open(body)); + return asTextContentResult(await client.open(body)); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/app/search.ts b/packages/mcp-server/src/tools/top-level/search.ts similarity index 91% rename from packages/mcp-server/src/tools/app/search.ts rename to packages/mcp-server/src/tools/top-level/search.ts index a911592..ce1bdfb 100644 --- a/packages/mcp-server/src/tools/app/search.ts +++ b/packages/mcp-server/src/tools/top-level/search.ts @@ -6,11 +6,11 @@ import { Tool } from '@modelcontextprotocol/sdk/types.js'; import BeeperDesktop from '@beeper/desktop-api'; export const metadata: Metadata = { - resource: 'app', + resource: '$client', operation: 'read', tags: ['app'], httpMethod: 'get', - httpPath: '/v0/search', + httpPath: '/v1/search', operationId: 'search', }; @@ -35,7 +35,7 @@ export const tool: Tool = { export const handler = async (client: BeeperDesktop, args: Record | undefined) => { const body = args as any; - return asTextContentResult(await client.app.search(body)); + return asTextContentResult(await client.search(body)); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/tsconfig.build.json b/packages/mcp-server/tsconfig.build.json index e790c29..c1fe977 100644 --- a/packages/mcp-server/tsconfig.build.json +++ b/packages/mcp-server/tsconfig.build.json @@ -5,8 +5,8 @@ "compilerOptions": { "rootDir": "./dist/src", "paths": { - "@beeper/desktop-mcp/*": ["dist/src/*"], - "@beeper/desktop-mcp": ["dist/src/index.ts"] + "@beeper/desktop-mcp/*": ["./dist/src/*"], + "@beeper/desktop-mcp": ["./dist/src/index.ts"] }, "noEmit": false, "declaration": true, diff --git a/packages/mcp-server/tsconfig.json b/packages/mcp-server/tsconfig.json index ad28452..c70b6cc 100644 --- a/packages/mcp-server/tsconfig.json +++ b/packages/mcp-server/tsconfig.json @@ -7,10 +7,9 @@ "module": "commonjs", "moduleResolution": "node", "esModuleInterop": true, - "baseUrl": "./", "paths": { - "@beeper/desktop-mcp/*": ["src/*"], - "@beeper/desktop-mcp": ["src/index.ts"] + "@beeper/desktop-mcp/*": ["./src/*"], + "@beeper/desktop-mcp": ["./src/index.ts"] }, "noEmit": true, diff --git a/packages/mcp-server/yarn.lock b/packages/mcp-server/yarn.lock index ad81983..966d057 100644 --- a/packages/mcp-server/yarn.lock +++ b/packages/mcp-server/yarn.lock @@ -10,20 +10,6 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" -"@anthropic-ai/dxt@^0.2.6": - version "0.2.6" - resolved "https://registry.yarnpkg.com/@anthropic-ai/dxt/-/dxt-0.2.6.tgz#636197c3d083c9136ac3b5a11d2ba82477fdc2c6" - integrity sha512-5VSqKRpkytTYh5UJz9jOaI8zLXNCe4Gc+ArKGFV6IeWnEPP0Qnd0k+V3pO8cYzp92Puf/+Cgo0xc4haE0azTXg== - dependencies: - "@inquirer/prompts" "^6.0.1" - commander "^13.1.0" - fflate "^0.8.2" - galactus "^1.0.0" - ignore "^7.0.5" - node-forge "^1.3.1" - pretty-bytes "^5.6.0" - zod "^3.25.67" - "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" @@ -350,144 +336,6 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== -"@inquirer/checkbox@^3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@inquirer/checkbox/-/checkbox-3.0.1.tgz#0a57f704265f78c36e17f07e421b98efb4b9867b" - integrity sha512-0hm2nrToWUdD6/UHnel/UKGdk1//ke5zGUpHIvk5ZWmaKezlGxZkOJXNSWsdxO/rEqTkbB3lNC2J6nBElV2aAQ== - dependencies: - "@inquirer/core" "^9.2.1" - "@inquirer/figures" "^1.0.6" - "@inquirer/type" "^2.0.0" - ansi-escapes "^4.3.2" - yoctocolors-cjs "^2.1.2" - -"@inquirer/confirm@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-4.0.1.tgz#9106d6bffa0b2fdd0e4f60319b6f04f2e06e6e25" - integrity sha512-46yL28o2NJ9doViqOy0VDcoTzng7rAb6yPQKU7VDLqkmbCaH4JqK4yk4XqlzNWy9PVC5pG1ZUXPBQv+VqnYs2w== - dependencies: - "@inquirer/core" "^9.2.1" - "@inquirer/type" "^2.0.0" - -"@inquirer/core@^9.2.1": - version "9.2.1" - resolved "https://registry.yarnpkg.com/@inquirer/core/-/core-9.2.1.tgz#677c49dee399c9063f31e0c93f0f37bddc67add1" - integrity sha512-F2VBt7W/mwqEU4bL0RnHNZmC/OxzNx9cOYxHqnXX3MP6ruYvZUZAW9imgN9+h/uBT/oP8Gh888J2OZSbjSeWcg== - dependencies: - "@inquirer/figures" "^1.0.6" - "@inquirer/type" "^2.0.0" - "@types/mute-stream" "^0.0.4" - "@types/node" "^22.5.5" - "@types/wrap-ansi" "^3.0.0" - ansi-escapes "^4.3.2" - cli-width "^4.1.0" - mute-stream "^1.0.0" - signal-exit "^4.1.0" - strip-ansi "^6.0.1" - wrap-ansi "^6.2.0" - yoctocolors-cjs "^2.1.2" - -"@inquirer/editor@^3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@inquirer/editor/-/editor-3.0.1.tgz#d109f21e050af6b960725388cb1c04214ed7c7bc" - integrity sha512-VA96GPFaSOVudjKFraokEEmUQg/Lub6OXvbIEZU1SDCmBzRkHGhxoFAVaF30nyiB4m5cEbDgiI2QRacXZ2hw9Q== - dependencies: - "@inquirer/core" "^9.2.1" - "@inquirer/type" "^2.0.0" - external-editor "^3.1.0" - -"@inquirer/expand@^3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@inquirer/expand/-/expand-3.0.1.tgz#aed9183cac4d12811be47a4a895ea8e82a17e22c" - integrity sha512-ToG8d6RIbnVpbdPdiN7BCxZGiHOTomOX94C2FaT5KOHupV40tKEDozp12res6cMIfRKrXLJyexAZhWVHgbALSQ== - dependencies: - "@inquirer/core" "^9.2.1" - "@inquirer/type" "^2.0.0" - yoctocolors-cjs "^2.1.2" - -"@inquirer/figures@^1.0.6": - version "1.0.13" - resolved "https://registry.yarnpkg.com/@inquirer/figures/-/figures-1.0.13.tgz#ad0afd62baab1c23175115a9b62f511b6a751e45" - integrity sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw== - -"@inquirer/input@^3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@inquirer/input/-/input-3.0.1.tgz#de63d49e516487388508d42049deb70f2cb5f28e" - integrity sha512-BDuPBmpvi8eMCxqC5iacloWqv+5tQSJlUafYWUe31ow1BVXjW2a5qe3dh4X/Z25Wp22RwvcaLCc2siHobEOfzg== - dependencies: - "@inquirer/core" "^9.2.1" - "@inquirer/type" "^2.0.0" - -"@inquirer/number@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@inquirer/number/-/number-2.0.1.tgz#b9863080d02ab7dc2e56e16433d83abea0f2a980" - integrity sha512-QpR8jPhRjSmlr/mD2cw3IR8HRO7lSVOnqUvQa8scv1Lsr3xoAMMworcYW3J13z3ppjBFBD2ef1Ci6AE5Qn8goQ== - dependencies: - "@inquirer/core" "^9.2.1" - "@inquirer/type" "^2.0.0" - -"@inquirer/password@^3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@inquirer/password/-/password-3.0.1.tgz#2a9a9143591088336bbd573bcb05d5bf080dbf87" - integrity sha512-haoeEPUisD1NeE2IanLOiFr4wcTXGWrBOyAyPZi1FfLJuXOzNmxCJPgUrGYKVh+Y8hfGJenIfz5Wb/DkE9KkMQ== - dependencies: - "@inquirer/core" "^9.2.1" - "@inquirer/type" "^2.0.0" - ansi-escapes "^4.3.2" - -"@inquirer/prompts@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@inquirer/prompts/-/prompts-6.0.1.tgz#43f5c0ed35c5ebfe52f1d43d46da2d363d950071" - integrity sha512-yl43JD/86CIj3Mz5mvvLJqAOfIup7ncxfJ0Btnl0/v5TouVUyeEdcpknfgc+yMevS/48oH9WAkkw93m7otLb/A== - dependencies: - "@inquirer/checkbox" "^3.0.1" - "@inquirer/confirm" "^4.0.1" - "@inquirer/editor" "^3.0.1" - "@inquirer/expand" "^3.0.1" - "@inquirer/input" "^3.0.1" - "@inquirer/number" "^2.0.1" - "@inquirer/password" "^3.0.1" - "@inquirer/rawlist" "^3.0.1" - "@inquirer/search" "^2.0.1" - "@inquirer/select" "^3.0.1" - -"@inquirer/rawlist@^3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@inquirer/rawlist/-/rawlist-3.0.1.tgz#729def358419cc929045f264131878ed379e0af3" - integrity sha512-VgRtFIwZInUzTiPLSfDXK5jLrnpkuSOh1ctfaoygKAdPqjcjKYmGh6sCY1pb0aGnCGsmhUxoqLDUAU0ud+lGXQ== - dependencies: - "@inquirer/core" "^9.2.1" - "@inquirer/type" "^2.0.0" - yoctocolors-cjs "^2.1.2" - -"@inquirer/search@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@inquirer/search/-/search-2.0.1.tgz#69b774a0a826de2e27b48981d01bc5ad81e73721" - integrity sha512-r5hBKZk3g5MkIzLVoSgE4evypGqtOannnB3PKTG9NRZxyFRKcfzrdxXXPcoJQsxJPzvdSU2Rn7pB7lw0GCmGAg== - dependencies: - "@inquirer/core" "^9.2.1" - "@inquirer/figures" "^1.0.6" - "@inquirer/type" "^2.0.0" - yoctocolors-cjs "^2.1.2" - -"@inquirer/select@^3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@inquirer/select/-/select-3.0.1.tgz#1df9ed27fb85a5f526d559ac5ce7cc4e9dc4e7ec" - integrity sha512-lUDGUxPhdWMkN/fHy1Lk7pF3nK1fh/gqeyWXmctefhxLYxlDsc7vsPBEpxrfVGDsVdyYJsiJoD4bJ1b623cV1Q== - dependencies: - "@inquirer/core" "^9.2.1" - "@inquirer/figures" "^1.0.6" - "@inquirer/type" "^2.0.0" - ansi-escapes "^4.3.2" - yoctocolors-cjs "^2.1.2" - -"@inquirer/type@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-2.0.0.tgz#08fa513dca2cb6264fe1b0a2fabade051444e3f6" - integrity sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag== - dependencies: - mute-stream "^1.0.0" - "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -947,13 +795,6 @@ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== -"@types/mute-stream@^0.0.4": - version "0.0.4" - resolved "https://registry.yarnpkg.com/@types/mute-stream/-/mute-stream-0.0.4.tgz#77208e56a08767af6c5e1237be8888e2f255c478" - integrity sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow== - dependencies: - "@types/node" "*" - "@types/node@*": version "22.15.17" resolved "https://registry.yarnpkg.com/@types/node/-/node-22.15.17.tgz#355ccec95f705b664e4332bb64a7f07db30b7055" @@ -961,13 +802,6 @@ dependencies: undici-types "~6.21.0" -"@types/node@^22.5.5": - version "22.18.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.18.0.tgz#9e4709be4f104e3568f7dd1c71e2949bf147a47b" - integrity sha512-m5ObIqwsUp6BZzyiy4RdZpzWGub9bqLJMvZDD0QMXhxjqMHMENlj+SqF5QxoUwaQNFe+8kz8XM8ZQhqkQPTgMQ== - dependencies: - undici-types "~6.21.0" - "@types/qs@*", "@types/qs@^6.14.0": version "6.14.0" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.14.0.tgz#d8b60cecf62f2db0fb68e5e006077b9178b85de5" @@ -1000,11 +834,6 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== -"@types/wrap-ansi@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz#18b97a972f94f60a679fd5c796d96421b9abb9fd" - integrity sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g== - "@types/yargs-parser@*": version "21.0.3" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" @@ -1151,7 +980,7 @@ ajv@^6.12.4, ajv@^6.12.6: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ansi-escapes@^4.2.1, ansi-escapes@^4.3.2: +ansi-escapes@^4.2.1: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== @@ -1393,11 +1222,6 @@ char-regex@^1.0.2: resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - ci-info@^3.2.0: version "3.9.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" @@ -1413,11 +1237,6 @@ clean-stack@^2.0.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== -cli-width@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.1.0.tgz#42daac41d3c254ef38ad8ac037672130173691c5" - integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ== - cliui@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" @@ -1454,11 +1273,6 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -commander@^13.1.0: - version "13.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-13.1.0.tgz#776167db68c78f38dcce1f9b8d7b8b9a488abf46" - integrity sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw== - concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -1871,15 +1685,6 @@ express@^5.0.1, express@^5.1.0: type-is "^2.0.1" vary "^1.1.2" -external-editor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -1925,11 +1730,6 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" -fflate@^0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.8.2.tgz#fc8631f5347812ad6028bbe4a2308b2792aa1dea" - integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A== - file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -1993,14 +1793,6 @@ flatted@^3.2.9: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358" integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== -flora-colossus@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/flora-colossus/-/flora-colossus-2.0.0.tgz#af1e85db0a8256ef05f3fb531c1235236c97220a" - integrity sha512-dz4HxH6pOvbUzZpZ/yXhafjbR2I8cenK5xL0KtBFb7U2ADsR+OwXifnxZjij/pZWF775uSCMzWVd+jDik2H2IA== - dependencies: - debug "^4.3.4" - fs-extra "^10.1.0" - forwarded@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" @@ -2011,15 +1803,6 @@ fresh@^2.0.0: resolved "https://registry.yarnpkg.com/fresh/-/fresh-2.0.0.tgz#8dd7df6a1b3a1b3a5cf186c05a5dd267622635a4" integrity sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A== -fs-extra@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" - integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -2035,15 +1818,6 @@ function-bind@^1.1.2: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== -galactus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/galactus/-/galactus-1.0.0.tgz#c2615182afa0c6d0859b92e56ae36d052827db7e" - integrity sha512-R1fam6D4CyKQGNlvJne4dkNF+PvUUl7TAJInvTGa9fti9qAv95quQz29GXapA4d8Ec266mJJxFVh82M4GIIGDQ== - dependencies: - debug "^4.3.4" - flora-colossus "^2.0.0" - fs-extra "^10.1.0" - gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -2136,7 +1910,7 @@ gopd@^1.2.0: resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== -graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.9: +graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -2191,23 +1965,11 @@ iconv-lite@0.6.3, iconv-lite@^0.6.3: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -iconv-lite@^0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - ignore@^5.2.0, ignore@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== -ignore@^7.0.5: - version "7.0.5" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.5.tgz#4cb5f6cd7d4c7ab0365738c7aea888baa6d7efd9" - integrity sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg== - import-fresh@^3.2.1: version "3.3.1" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" @@ -2786,15 +2548,6 @@ json5@^2.2.2, json5@^2.2.3: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== -jsonfile@^6.0.1: - version "6.2.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.2.0.tgz#7c265bd1b65de6977478300087c99f1c84383f62" - integrity sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - keyv@^4.5.3: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" @@ -2968,11 +2721,6 @@ ms@^2.1.3: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -mute-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e" - integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA== - natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -2983,11 +2731,6 @@ negotiator@^1.0.0: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a" integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg== -node-forge@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" - integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== - node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -3053,11 +2796,6 @@ optionator@^0.9.3: type-check "^0.4.0" word-wrap "^1.2.5" -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== - p-all@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/p-all/-/p-all-3.0.0.tgz#077c023c37e75e760193badab2bad3ccd5782bfb" @@ -3201,11 +2939,6 @@ prettier@^3.0.0: resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.5.3.tgz#4fc2ce0d657e7a02e602549f053b239cb7dfe1b5" integrity sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw== -pretty-bytes@^5.6.0: - version "5.6.0" - resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" - integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg== - pretty-format@^29.0.0, pretty-format@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" @@ -3353,7 +3086,7 @@ safe-buffer@5.2.1, safe-buffer@~5.2.0: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": +"safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -3457,11 +3190,6 @@ signal-exit@^3.0.3, signal-exit@^3.0.7: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== -signal-exit@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" - integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== - sisteransi@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" @@ -3606,13 +3334,6 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - tmpl@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" @@ -3753,11 +3474,6 @@ undici-types@~6.21.0: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== -universalify@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" - integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== - unpipe@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -3821,15 +3537,6 @@ word-wrap@^1.2.5: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -wrap-ansi@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" - integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" @@ -3890,11 +3597,6 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -yoctocolors-cjs@^2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz#7e4964ea8ec422b7a40ac917d3a344cfd2304baa" - integrity sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw== - zod-to-json-schema@^3.24.1, zod-to-json-schema@^3.24.5: version "3.24.5" resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz#d1095440b147fb7c2093812a53c54df8d5df50a3" @@ -3910,7 +3612,7 @@ zod@^3.23.8: resolved "https://registry.yarnpkg.com/zod/-/zod-3.24.4.tgz#e2e2cca5faaa012d76e527d0d36622e0a90c315f" integrity sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg== -zod@^3.25.20, zod@^3.25.67: +zod@^3.25.20: version "3.25.76" resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.76.tgz#26841c3f6fd22a6a2760e7ccb719179768471e34" integrity sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ== diff --git a/scripts/bootstrap b/scripts/bootstrap index 062a034..a8b69ff 100755 --- a/scripts/bootstrap +++ b/scripts/bootstrap @@ -4,10 +4,18 @@ set -e cd "$(dirname "$0")/.." -if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ]; then +if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ] && [ -t 0 ]; then brew bundle check >/dev/null 2>&1 || { - echo "==> Installing Homebrew dependencies…" - brew bundle + echo -n "==> Install Homebrew dependencies? (y/N): " + read -r response + case "$response" in + [yY][eE][sS]|[yY]) + brew bundle + ;; + *) + ;; + esac + echo } fi diff --git a/scripts/fast-format b/scripts/fast-format new file mode 100755 index 0000000..53721ac --- /dev/null +++ b/scripts/fast-format @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +set -euo pipefail + +echo "Script started with $# arguments" +echo "Arguments: $*" +echo "Script location: $(dirname "$0")" + +cd "$(dirname "$0")/.." +echo "Changed to directory: $(pwd)" + +if [ $# -eq 0 ]; then + echo "Usage: $0 [additional-formatter-args...]" + echo "The file should contain one file path per line" + exit 1 +fi + +FILE_LIST="$1" + +echo "Looking for file: $FILE_LIST" + +if [ ! -f "$FILE_LIST" ]; then + echo "Error: File '$FILE_LIST' not found" + exit 1 +fi + +echo "==> Running eslint --fix" +ESLINT_FILES="$(grep '\.ts$' "$FILE_LIST" || true)" +if ! [ -z "$ESLINT_FILES" ]; then + echo "$ESLINT_FILES" | xargs ./node_modules/.bin/eslint --cache --fix +fi + +echo "==> Running prettier --write" +# format things eslint didn't +PRETTIER_FILES="$(grep '\.\(js\|json\)$' "$FILE_LIST" || true)" +if ! [ -z "$PRETTIER_FILES" ]; then + echo "$PRETTIER_FILES" | xargs ./node_modules/.bin/prettier \ + --write --cache --cache-strategy metadata --no-error-on-unmatched-pattern \ + '!**/dist' '!**/*.ts' '!**/*.mts' '!**/*.cts' '!**/*.js' '!**/*.mjs' '!**/*.cjs' +fi diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh index 35e2b8f..826f861 100755 --- a/scripts/utils/upload-artifact.sh +++ b/scripts/utils/upload-artifact.sh @@ -12,9 +12,11 @@ if [[ "$SIGNED_URL" == "null" ]]; then exit 1 fi -UPLOAD_RESPONSE=$(tar "${BASE_PATH:+-C$BASE_PATH}" -cz "${ARTIFACT_PATH:-dist}" | curl -v -X PUT \ +TARBALL=$(cd dist && npm pack --silent) + +UPLOAD_RESPONSE=$(curl -v -X PUT \ -H "Content-Type: application/gzip" \ - --data-binary @- "$SIGNED_URL" 2>&1) + --data-binary "@dist/$TARBALL" "$SIGNED_URL" 2>&1) if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then echo -e "\033[32mUploaded build to Stainless storage.\033[0m" diff --git a/src/client.ts b/src/client.ts index d9bc8cf..cb8bdcf 100644 --- a/src/client.ts +++ b/src/client.ts @@ -15,32 +15,46 @@ import * as qs from './internal/qs'; import { VERSION } from './version'; import * as Errors from './core/error'; import * as Pagination from './core/pagination'; -import { AbstractPage, type CursorParams, CursorResponse } from './core/pagination'; +import { + AbstractPage, + type CursorListParams, + CursorListResponse, + type CursorSearchParams, + CursorSearchResponse, +} from './core/pagination'; import * as Uploads from './core/uploads'; import * as API from './resources/index'; +import * as TopLevelAPI from './resources/top-level'; +import { + DownloadAssetParams, + DownloadAssetResponse, + OpenParams, + OpenResponse, + SearchParams, + SearchResponse, +} from './resources/top-level'; import { APIPromise } from './core/api-promise'; import { Account, AccountListResponse, Accounts } from './resources/accounts'; -import { - App, - AppDownloadAssetParams, - AppDownloadAssetResponse, - AppOpenParams, - AppOpenResponse, - AppSearchParams, - AppSearchResponse, -} from './resources/app'; import { ContactSearchParams, ContactSearchResponse, Contacts } from './resources/contacts'; -import { MessageSearchParams, MessageSendParams, MessageSendResponse, Messages } from './resources/messages'; -import { RevokeRequest, Token, UserInfo } from './resources/token'; +import { + MessageListParams, + MessageSearchParams, + MessageSendParams, + MessageSendResponse, + Messages, +} from './resources/messages'; import { Chat, ChatArchiveParams, ChatCreateParams, ChatCreateResponse, + ChatListParams, + ChatListResponse, + ChatListResponsesCursorList, ChatRetrieveParams, ChatSearchParams, Chats, - ChatsCursor, + ChatsCursorSearch, } from './resources/chats/chats'; import { type Fetch } from './internal/builtin-types'; import { isRunningInBrowser } from './internal/detect-platform'; @@ -237,6 +251,54 @@ export class BeeperDesktop { return this.baseURL !== 'http://localhost:23373'; } + /** + * Download a Matrix asset using its mxc:// or localmxc:// URL and return the local + * file URL. + * + * @example + * ```ts + * const response = await client.downloadAsset({ + * url: 'mxc://example.org/Q4x9CqGz1pB3Oa6XgJ', + * }); + * ``` + */ + downloadAsset( + body: TopLevelAPI.DownloadAssetParams, + options?: RequestOptions, + ): APIPromise { + return this.post('/v1/download-asset', { body, ...options }); + } + + /** + * Open Beeper Desktop and optionally navigate to a specific chat, message, or + * pre-fill draft text and attachment. + * + * @example + * ```ts + * const response = await client.open(); + * ``` + */ + open( + body: TopLevelAPI.OpenParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { + return this.post('/v1/open', { body, ...options }); + } + + /** + * Returns matching chats, participant name matches in groups, and the first page + * of messages in one call. Paginate messages via search-messages. Paginate chats + * via search-chats. Uses the same sorting as the chat search in the app. + * + * @example + * ```ts + * const response = await client.search({ query: 'x' }); + * ``` + */ + search(query: TopLevelAPI.SearchParams, options?: RequestOptions): APIPromise { + return this.get('/v1/search', { query, ...options }); + } + protected defaultQuery(): Record | undefined { return this._options.defaultQuery; } @@ -246,17 +308,9 @@ export class BeeperDesktop { } protected async authHeaders(opts: FinalRequestOptions): Promise { - return buildHeaders([await this.bearerAuth(opts), await this.oauth2Auth(opts)]); - } - - protected async bearerAuth(opts: FinalRequestOptions): Promise { return buildHeaders([{ Authorization: `Bearer ${this.accessToken}` }]); } - protected async oauth2Auth(opts: FinalRequestOptions): Promise { - return undefined; - } - protected stringifyQuery(query: Record): string { return qs.stringify(query, { arrayFormat: 'repeat' }); } @@ -765,13 +819,9 @@ export class BeeperDesktop { static toFile = Uploads.toFile; /** - * Accounts operations + * Manage connected chat accounts */ accounts: API.Accounts = new API.Accounts(this); - /** - * App operations - */ - app: API.App = new API.App(this); /** * Contacts operations */ @@ -784,37 +834,33 @@ export class BeeperDesktop { * Messages operations */ messages: API.Messages = new API.Messages(this); - /** - * Operations related to the current access token - */ - token: API.Token = new API.Token(this); } BeeperDesktop.Accounts = Accounts; -BeeperDesktop.App = App; BeeperDesktop.Contacts = Contacts; BeeperDesktop.Chats = Chats; BeeperDesktop.Messages = Messages; -BeeperDesktop.Token = Token; export declare namespace BeeperDesktop { export type RequestOptions = Opts.RequestOptions; - export import Cursor = Pagination.Cursor; - export { type CursorParams as CursorParams, type CursorResponse as CursorResponse }; + export import CursorSearch = Pagination.CursorSearch; + export { type CursorSearchParams as CursorSearchParams, type CursorSearchResponse as CursorSearchResponse }; - export { Accounts as Accounts, type Account as Account, type AccountListResponse as AccountListResponse }; + export import CursorList = Pagination.CursorList; + export { type CursorListParams as CursorListParams, type CursorListResponse as CursorListResponse }; export { - App as App, - type AppDownloadAssetResponse as AppDownloadAssetResponse, - type AppOpenResponse as AppOpenResponse, - type AppSearchResponse as AppSearchResponse, - type AppDownloadAssetParams as AppDownloadAssetParams, - type AppOpenParams as AppOpenParams, - type AppSearchParams as AppSearchParams, + type DownloadAssetResponse as DownloadAssetResponse, + type OpenResponse as OpenResponse, + type SearchResponse as SearchResponse, + type DownloadAssetParams as DownloadAssetParams, + type OpenParams as OpenParams, + type SearchParams as SearchParams, }; + export { Accounts as Accounts, type Account as Account, type AccountListResponse as AccountListResponse }; + export { Contacts as Contacts, type ContactSearchResponse as ContactSearchResponse, @@ -825,9 +871,12 @@ export declare namespace BeeperDesktop { Chats as Chats, type Chat as Chat, type ChatCreateResponse as ChatCreateResponse, - type ChatsCursor as ChatsCursor, + type ChatListResponse as ChatListResponse, + type ChatListResponsesCursorList as ChatListResponsesCursorList, + type ChatsCursorSearch as ChatsCursorSearch, type ChatCreateParams as ChatCreateParams, type ChatRetrieveParams as ChatRetrieveParams, + type ChatListParams as ChatListParams, type ChatArchiveParams as ChatArchiveParams, type ChatSearchParams as ChatSearchParams, }; @@ -835,12 +884,11 @@ export declare namespace BeeperDesktop { export { Messages as Messages, type MessageSendResponse as MessageSendResponse, + type MessageListParams as MessageListParams, type MessageSearchParams as MessageSearchParams, type MessageSendParams as MessageSendParams, }; - export { Token as Token, type RevokeRequest as RevokeRequest, type UserInfo as UserInfo }; - export type Attachment = API.Attachment; export type BaseResponse = API.BaseResponse; export type Error = API.Error; diff --git a/src/core/pagination.ts b/src/core/pagination.ts index 00238cf..11e94e9 100644 --- a/src/core/pagination.ts +++ b/src/core/pagination.ts @@ -107,7 +107,7 @@ export class PagePromise< } } -export interface CursorResponse { +export interface CursorSearchResponse { items: Array; hasMore: boolean; @@ -117,7 +117,7 @@ export interface CursorResponse { newestCursor: string | null; } -export interface CursorParams { +export interface CursorSearchParams { cursor?: string | null; direction?: string | null; @@ -125,7 +125,7 @@ export interface CursorParams { limit?: number | null; } -export class Cursor extends AbstractPage implements CursorResponse { +export class CursorSearch extends AbstractPage implements CursorSearchResponse { items: Array; hasMore: boolean; @@ -137,7 +137,74 @@ export class Cursor extends AbstractPage implements CursorResponse, + body: CursorSearchResponse, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.items = body.items || []; + this.hasMore = body.hasMore || false; + this.oldestCursor = body.oldestCursor || null; + this.newestCursor = body.newestCursor || null; + } + + getPaginatedItems(): Item[] { + return this.items ?? []; + } + + override hasNextPage(): boolean { + if (this.hasMore === false) { + return false; + } + + return super.hasNextPage(); + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.oldestCursor; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + cursor, + }, + }; + } +} + +export interface CursorListResponse { + items: Array; + + hasMore: boolean; + + oldestCursor: string | null; + + newestCursor: string | null; +} + +export interface CursorListParams { + cursor?: string | null; + + direction?: string | null; +} + +export class CursorList extends AbstractPage implements CursorListResponse { + items: Array; + + hasMore: boolean; + + oldestCursor: string | null; + + newestCursor: string | null; + + constructor( + client: BeeperDesktop, + response: Response, + body: CursorListResponse, options: FinalRequestOptions, ) { super(client, response, body, options); diff --git a/src/internal/to-file.ts b/src/internal/to-file.ts index 245e849..30eada3 100644 --- a/src/internal/to-file.ts +++ b/src/internal/to-file.ts @@ -73,7 +73,7 @@ export type ToFileInput = /** * Helper for creating a {@link File} to pass to an SDK upload method from a variety of different data formats - * @param value the raw content of the file. Can be an {@link Uploadable}, {@link BlobLikePart}, or {@link AsyncIterable} of {@link BlobLikePart}s + * @param value the raw content of the file. Can be an {@link Uploadable}, BlobLikePart, or AsyncIterable of BlobLikeParts * @param {string=} name the name of the file. If omitted, toFile will try to determine a file name from bits if possible * @param {Object=} options additional properties * @param {string=} options.type the MIME type of the content diff --git a/src/resources/accounts.ts b/src/resources/accounts.ts index 8dcdaf0..9d1df07 100644 --- a/src/resources/accounts.ts +++ b/src/resources/accounts.ts @@ -6,11 +6,12 @@ import { APIPromise } from '../core/api-promise'; import { RequestOptions } from '../internal/request-options'; /** - * Accounts operations + * Manage connected chat accounts */ export class Accounts extends APIResource { /** - * List connected Beeper accounts available on this device + * Lists chat accounts across networks (WhatsApp, Telegram, Twitter/X, etc.) + * actively connected to this Beeper Desktop instance * * @example * ```ts @@ -18,7 +19,7 @@ export class Accounts extends APIResource { * ``` */ list(options?: RequestOptions): APIPromise { - return this._client.get('/v0/get-accounts', options); + return this._client.get('/v1/accounts', options); } } @@ -32,14 +33,12 @@ export interface Account { accountID: string; /** - * Display-only human-readable network name (e.g., 'WhatsApp', 'Messenger'). You - * MUST use 'accountID' to perform actions. + * Display-only human-readable network name (e.g., 'WhatsApp', 'Messenger'). */ network: string; /** - * A person on or reachable through Beeper. Values are best-effort and can vary by - * network. + * User the account belongs to. */ user: Shared.User; } diff --git a/src/resources/app.ts b/src/resources/app.ts deleted file mode 100644 index a7991cf..0000000 --- a/src/resources/app.ts +++ /dev/null @@ -1,178 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { APIResource } from '../core/resource'; -import * as Shared from './shared'; -import * as ChatsAPI from './chats/chats'; -import { APIPromise } from '../core/api-promise'; -import { RequestOptions } from '../internal/request-options'; - -/** - * App operations - */ -export class App extends APIResource { - /** - * Download a Matrix asset using its mxc:// or localmxc:// URL and return the local - * file URL. - * - * @example - * ```ts - * const response = await client.app.downloadAsset({ - * url: 'x', - * }); - * ``` - */ - downloadAsset( - body: AppDownloadAssetParams, - options?: RequestOptions, - ): APIPromise { - return this._client.post('/v0/download-asset', { body, ...options }); - } - - /** - * Open Beeper Desktop and optionally navigate to a specific chat, message, or - * pre-fill draft text and attachment. - * - * @example - * ```ts - * const response = await client.app.open(); - * ``` - */ - open(body: AppOpenParams | null | undefined = {}, options?: RequestOptions): APIPromise { - return this._client.post('/v0/open-app', { body, ...options }); - } - - /** - * Returns matching chats, participant name matches in groups, and the first page - * of messages in one call. Paginate messages via search-messages. Paginate chats - * via search-chats. Uses the same sorting as the chat search in the app. - * - * @example - * ```ts - * const response = await client.app.search({ query: 'x' }); - * ``` - */ - search(query: AppSearchParams, options?: RequestOptions): APIPromise { - return this._client.get('/v0/search', { query, ...options }); - } -} - -export interface AppDownloadAssetResponse { - /** - * Error message if the download failed. - */ - error?: string; - - /** - * Local file URL to the downloaded asset. - */ - srcURL?: string; -} - -/** - * Response indicating successful app opening. - */ -export interface AppOpenResponse { - /** - * Whether the app was successfully opened/focused. - */ - success: boolean; -} - -export interface AppSearchResponse { - results: AppSearchResponse.Results; -} - -export namespace AppSearchResponse { - export interface Results { - /** - * Top chat results. - */ - chats: Array; - - /** - * Top group results by participant matches. - */ - in_groups: Array; - - messages: Results.Messages; - } - - export namespace Results { - export interface Messages { - /** - * Map of chatID -> chat details for chats referenced in items. - */ - chats: { [key: string]: ChatsAPI.Chat }; - - /** - * True if additional results can be fetched using the provided cursors. - */ - hasMore: boolean; - - /** - * Messages matching the query and filters. - */ - items: Array; - - /** - * Cursor for fetching newer results (use with direction='after'). Opaque string; - * do not inspect. - */ - newestCursor: string | null; - - /** - * Cursor for fetching older results (use with direction='before'). Opaque string; - * do not inspect. - */ - oldestCursor: string | null; - } - } -} - -export interface AppDownloadAssetParams { - /** - * Matrix content URL (mxc:// or localmxc://) for the asset to download. - */ - url: string; -} - -export interface AppOpenParams { - /** - * Optional Beeper chat ID (or local chat ID) to focus after opening the app. If - * omitted, only opens/focuses the app. - */ - chatID?: string; - - /** - * Optional draft attachment path to populate in the message input field. - */ - draftAttachmentPath?: string; - - /** - * Optional draft text to populate in the message input field. - */ - draftText?: string; - - /** - * Optional message ID. Jumps to that message in the chat when opening. - */ - messageID?: string; -} - -export interface AppSearchParams { - /** - * User-typed search text. Literal word matching (NOT semantic). - */ - query: string; -} - -export declare namespace App { - export { - type AppDownloadAssetResponse as AppDownloadAssetResponse, - type AppOpenResponse as AppOpenResponse, - type AppSearchResponse as AppSearchResponse, - type AppDownloadAssetParams as AppDownloadAssetParams, - type AppOpenParams as AppOpenParams, - type AppSearchParams as AppSearchParams, - }; -} diff --git a/src/resources/chats/chats.ts b/src/resources/chats/chats.ts index 0154f56..271d168 100644 --- a/src/resources/chats/chats.ts +++ b/src/resources/chats/chats.ts @@ -3,10 +3,17 @@ import { APIResource } from '../../core/resource'; import * as Shared from '../shared'; import * as RemindersAPI from './reminders'; -import { ReminderCreateParams, ReminderDeleteParams, Reminders } from './reminders'; +import { ReminderCreateParams, Reminders } from './reminders'; import { APIPromise } from '../../core/api-promise'; -import { Cursor, type CursorParams, PagePromise } from '../../core/pagination'; +import { + CursorList, + type CursorListParams, + CursorSearch, + type CursorSearchParams, + PagePromise, +} from '../../core/pagination'; import { RequestOptions } from '../../internal/request-options'; +import { path } from '../../internal/utils/path'; /** * Chats operations @@ -29,7 +36,7 @@ export class Chats extends APIResource { * ``` */ create(body: ChatCreateParams, options?: RequestOptions): APIPromise { - return this._client.post('/v0/create-chat', { body, ...options }); + return this._client.post('/v1/chats', { body, ...options }); } /** @@ -37,13 +44,36 @@ export class Chats extends APIResource { * * @example * ```ts - * const chat = await client.chats.retrieve({ - * chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', - * }); + * const chat = await client.chats.retrieve( + * '!NCdzlIaMjZUmvmvyHU:beeper.com', + * ); * ``` */ - retrieve(query: ChatRetrieveParams, options?: RequestOptions): APIPromise { - return this._client.get('/v0/get-chat', { query, ...options }); + retrieve( + chatID: string, + query: ChatRetrieveParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.get(path`/v1/chats/${chatID}`, { query, ...options }); + } + + /** + * List all chats sorted by last activity (most recent first). Combines all + * accounts into a single paginated list. + * + * @example + * ```ts + * // Automatically fetches more pages as needed. + * for await (const chatListResponse of client.chats.list()) { + * // ... + * } + * ``` + */ + list( + query: ChatListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList('/v1/chats', CursorList, { query, ...options }); } /** @@ -52,13 +82,17 @@ export class Chats extends APIResource { * * @example * ```ts - * const baseResponse = await client.chats.archive({ - * chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', - * }); + * const baseResponse = await client.chats.archive( + * '!NCdzlIaMjZUmvmvyHU:beeper.com', + * ); * ``` */ - archive(body: ChatArchiveParams, options?: RequestOptions): APIPromise { - return this._client.post('/v0/archive-chat', { body, ...options }); + archive( + chatID: string, + body: ChatArchiveParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.post(path`/v1/chats/${chatID}/archive`, { body, ...options }); } /** @@ -76,12 +110,14 @@ export class Chats extends APIResource { search( query: ChatSearchParams | null | undefined = {}, options?: RequestOptions, - ): PagePromise { - return this._client.getAPIList('/v0/search-chats', Cursor, { query, ...options }); + ): PagePromise { + return this._client.getAPIList('/v1/chats/search', CursorSearch, { query, ...options }); } } -export type ChatsCursor = Cursor; +export type ChatListResponsesCursorList = CursorList; + +export type ChatsCursorSearch = CursorSearch; export interface Chat { /** @@ -95,8 +131,7 @@ export interface Chat { accountID: string; /** - * Display-only human-readable network name (e.g., 'WhatsApp', 'Messenger'). You - * MUST use 'accountID' to perform actions. + * Display-only human-readable network name (e.g., 'WhatsApp', 'Messenger'). */ network: string; @@ -181,6 +216,13 @@ export interface ChatCreateResponse extends Shared.BaseResponse { chatID?: string; } +export interface ChatListResponse extends Chat { + /** + * Last message preview for this chat, if available. + */ + preview?: Shared.Message; +} + export interface ChatCreateParams { /** * Account to create the chat on. @@ -210,12 +252,6 @@ export interface ChatCreateParams { } export interface ChatRetrieveParams { - /** - * Unique identifier of the chat to retrieve. Not available for iMessage chats. - * Participants are limited by 'maxParticipantCount'. - */ - chatID: string; - /** * Maximum number of participants to return. Use -1 for all; otherwise 0–500. * Defaults to 20. @@ -223,20 +259,21 @@ export interface ChatRetrieveParams { maxParticipantCount?: number | null; } -export interface ChatArchiveParams { +export interface ChatListParams extends CursorListParams { /** - * The identifier of the chat to archive or unarchive (accepts both chatID and - * local chat ID) + * Limit to specific account IDs. If omitted, fetches from all accounts. */ - chatID: string; + accountIDs?: Array; +} +export interface ChatArchiveParams { /** * True to archive, false to unarchive */ archived?: boolean; } -export interface ChatSearchParams extends CursorParams { +export interface ChatSearchParams extends CursorSearchParams { /** * Provide an array of account IDs to filter chats from specific messaging accounts * only @@ -297,16 +334,15 @@ export declare namespace Chats { export { type Chat as Chat, type ChatCreateResponse as ChatCreateResponse, - type ChatsCursor as ChatsCursor, + type ChatListResponse as ChatListResponse, + type ChatListResponsesCursorList as ChatListResponsesCursorList, + type ChatsCursorSearch as ChatsCursorSearch, type ChatCreateParams as ChatCreateParams, type ChatRetrieveParams as ChatRetrieveParams, + type ChatListParams as ChatListParams, type ChatArchiveParams as ChatArchiveParams, type ChatSearchParams as ChatSearchParams, }; - export { - Reminders as Reminders, - type ReminderCreateParams as ReminderCreateParams, - type ReminderDeleteParams as ReminderDeleteParams, - }; + export { Reminders as Reminders, type ReminderCreateParams as ReminderCreateParams }; } diff --git a/src/resources/chats/index.ts b/src/resources/chats/index.ts index ab2b155..25bb4a5 100644 --- a/src/resources/chats/index.ts +++ b/src/resources/chats/index.ts @@ -4,10 +4,13 @@ export { Chats, type Chat, type ChatCreateResponse, + type ChatListResponse, type ChatCreateParams, type ChatRetrieveParams, + type ChatListParams, type ChatArchiveParams, type ChatSearchParams, - type ChatsCursor, + type ChatListResponsesCursorList, + type ChatsCursorSearch, } from './chats'; -export { Reminders, type ReminderCreateParams, type ReminderDeleteParams } from './reminders'; +export { Reminders, type ReminderCreateParams } from './reminders'; diff --git a/src/resources/chats/reminders.ts b/src/resources/chats/reminders.ts index 8be2e77..8da0a14 100644 --- a/src/resources/chats/reminders.ts +++ b/src/resources/chats/reminders.ts @@ -4,6 +4,7 @@ import { APIResource } from '../../core/resource'; import * as Shared from '../shared'; import { APIPromise } from '../../core/api-promise'; import { RequestOptions } from '../../internal/request-options'; +import { path } from '../../internal/utils/path'; /** * Reminders operations @@ -14,14 +15,18 @@ export class Reminders extends APIResource { * * @example * ```ts - * const baseResponse = await client.chats.reminders.create({ - * chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', - * reminder: { remindAtMs: 0 }, - * }); + * const baseResponse = await client.chats.reminders.create( + * '!NCdzlIaMjZUmvmvyHU:beeper.com', + * { reminder: { remindAtMs: 0 } }, + * ); * ``` */ - create(body: ReminderCreateParams, options?: RequestOptions): APIPromise { - return this._client.post('/v0/set-chat-reminder', { body, ...options }); + create( + chatID: string, + body: ReminderCreateParams, + options?: RequestOptions, + ): APIPromise { + return this._client.post(path`/v1/chats/${chatID}/reminders`, { body, ...options }); } /** @@ -29,23 +34,17 @@ export class Reminders extends APIResource { * * @example * ```ts - * const baseResponse = await client.chats.reminders.delete({ - * chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', - * }); + * const baseResponse = await client.chats.reminders.delete( + * '!NCdzlIaMjZUmvmvyHU:beeper.com', + * ); * ``` */ - delete(body: ReminderDeleteParams, options?: RequestOptions): APIPromise { - return this._client.post('/v0/clear-chat-reminder', { body, ...options }); + delete(chatID: string, options?: RequestOptions): APIPromise { + return this._client.delete(path`/v1/chats/${chatID}/reminders`, options); } } export interface ReminderCreateParams { - /** - * The identifier of the chat to set reminder for (accepts both chatID and local - * chat ID) - */ - chatID: string; - /** * Reminder configuration */ @@ -69,17 +68,6 @@ export namespace ReminderCreateParams { } } -export interface ReminderDeleteParams { - /** - * The identifier of the chat to clear reminder from (accepts both chatID and local - * chat ID) - */ - chatID: string; -} - export declare namespace Reminders { - export { - type ReminderCreateParams as ReminderCreateParams, - type ReminderDeleteParams as ReminderDeleteParams, - }; + export { type ReminderCreateParams as ReminderCreateParams }; } diff --git a/src/resources/contacts.ts b/src/resources/contacts.ts index b7b0f4b..3d0b682 100644 --- a/src/resources/contacts.ts +++ b/src/resources/contacts.ts @@ -10,11 +10,11 @@ import { RequestOptions } from '../internal/request-options'; */ export class Contacts extends APIResource { /** - * Search users across on a specific account using the network's search API. Only - * use for creating new chats. + * Search contacts across on a specific account using the network's search API. + * Only use for creating new chats. */ search(query: ContactSearchParams, options?: RequestOptions): APIPromise { - return this._client.get('/v0/search-users', { query, ...options }); + return this._client.get('/v1/contacts/search', { query, ...options }); } } @@ -24,7 +24,7 @@ export interface ContactSearchResponse { export interface ContactSearchParams { /** - * Beeper account ID this resource belongs to. + * Account ID this resource belongs to. */ accountID: string; diff --git a/src/resources/index.ts b/src/resources/index.ts index 4d7984c..74575e3 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -2,30 +2,32 @@ export * from './shared'; export { Accounts, type Account, type AccountListResponse } from './accounts'; -export { - App, - type AppDownloadAssetResponse, - type AppOpenResponse, - type AppSearchResponse, - type AppDownloadAssetParams, - type AppOpenParams, - type AppSearchParams, -} from './app'; export { Chats, type Chat, type ChatCreateResponse, + type ChatListResponse, type ChatCreateParams, type ChatRetrieveParams, + type ChatListParams, type ChatArchiveParams, type ChatSearchParams, - type ChatsCursor, + type ChatListResponsesCursorList, + type ChatsCursorSearch, } from './chats/chats'; export { Contacts, type ContactSearchResponse, type ContactSearchParams } from './contacts'; export { Messages, type MessageSendResponse, + type MessageListParams, type MessageSearchParams, type MessageSendParams, } from './messages'; -export { Token, type RevokeRequest, type UserInfo } from './token'; +export { + type DownloadAssetResponse, + type OpenResponse, + type SearchResponse, + type DownloadAssetParams, + type OpenParams, + type SearchParams, +} from './top-level'; diff --git a/src/resources/messages.ts b/src/resources/messages.ts index 32dff27..da415dc 100644 --- a/src/resources/messages.ts +++ b/src/resources/messages.ts @@ -2,15 +2,38 @@ import { APIResource } from '../core/resource'; import * as Shared from './shared'; -import { MessagesCursor } from './shared'; +import { MessagesCursorList, MessagesCursorSearch } from './shared'; import { APIPromise } from '../core/api-promise'; -import { Cursor, type CursorParams, PagePromise } from '../core/pagination'; +import { + CursorList, + type CursorListParams, + CursorSearch, + type CursorSearchParams, + PagePromise, +} from '../core/pagination'; import { RequestOptions } from '../internal/request-options'; /** * Messages operations */ export class Messages extends APIResource { + /** + * List all messages in a chat with cursor-based pagination. Sorted by timestamp. + * + * @example + * ```ts + * // Automatically fetches more pages as needed. + * for await (const message of client.messages.list({ + * chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', + * })) { + * // ... + * } + * ``` + */ + list(query: MessageListParams, options?: RequestOptions): PagePromise { + return this._client.getAPIList('/v1/messages', CursorList, { query, ...options }); + } + /** * Search messages across chats using Beeper's message index * @@ -25,8 +48,11 @@ export class Messages extends APIResource { search( query: MessageSearchParams | null | undefined = {}, options?: RequestOptions, - ): PagePromise { - return this._client.getAPIList('/v0/search-messages', Cursor, { query, ...options }); + ): PagePromise { + return this._client.getAPIList('/v1/messages/search', CursorSearch, { + query, + ...options, + }); } /** @@ -41,13 +67,13 @@ export class Messages extends APIResource { * ``` */ send(body: MessageSendParams, options?: RequestOptions): APIPromise { - return this._client.post('/v0/send-message', { body, ...options }); + return this._client.post('/v1/messages', { body, ...options }); } } export interface MessageSendResponse extends Shared.BaseResponse { /** - * Unique identifier of the chat (a.k.a. room or thread). + * Unique identifier of the chat. */ chatID: string; @@ -57,14 +83,21 @@ export interface MessageSendResponse extends Shared.BaseResponse { pendingMessageID: string; } -export interface MessageSearchParams extends CursorParams { +export interface MessageListParams extends CursorListParams { + /** + * Chat ID to list messages from + */ + chatID: string; +} + +export interface MessageSearchParams extends CursorSearchParams { /** - * Limit search to specific Beeper account IDs (bridge instances). + * Limit search to specific account IDs. */ accountIDs?: Array; /** - * Limit search to specific Beeper chat IDs. + * Limit search to specific chat IDs. */ chatIDs?: Array; @@ -120,7 +153,7 @@ export interface MessageSearchParams extends CursorParams { export interface MessageSendParams { /** - * Unique identifier of the chat (a.k.a. room or thread). + * Unique identifier of the chat. */ chatID: string; @@ -138,9 +171,10 @@ export interface MessageSendParams { export declare namespace Messages { export { type MessageSendResponse as MessageSendResponse, + type MessageListParams as MessageListParams, type MessageSearchParams as MessageSearchParams, type MessageSendParams as MessageSendParams, }; } -export { type MessagesCursor }; +export { type MessagesCursorList, type MessagesCursorSearch }; diff --git a/src/resources/shared.ts b/src/resources/shared.ts index 2ef2269..716ddb7 100644 --- a/src/resources/shared.ts +++ b/src/resources/shared.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { Cursor } from '../core/pagination'; +import { CursorList, CursorSearch } from '../core/pagination'; export interface Attachment { /** @@ -80,19 +80,36 @@ export interface BaseResponse { export interface Error { /** - * Error message + * Error details */ - error: string; + error: Error.Error; +} +export namespace Error { /** - * Error code + * Error details */ - code?: string; + export interface Error { + /** + * Machine-readable error code + */ + code: string; - /** - * Additional error details - */ - details?: { [key: string]: string }; + /** + * Error message + */ + message: string; + + /** + * Error type (e.g., invalid_request_error, authentication_error, not_found_error) + */ + type: string; + + /** + * Parameter that caused the error + */ + param?: string; + } } export interface Message { @@ -194,8 +211,7 @@ export interface Reaction { } /** - * A person on or reachable through Beeper. Values are best-effort and can vary by - * network. + * User the account belongs to. */ export interface User { /** @@ -242,4 +258,6 @@ export interface User { username?: string; } -export type MessagesCursor = Cursor; +export type MessagesCursorList = CursorList; + +export type MessagesCursorSearch = CursorSearch; diff --git a/src/resources/token.ts b/src/resources/token.ts deleted file mode 100644 index 4a6608d..0000000 --- a/src/resources/token.ts +++ /dev/null @@ -1,70 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { APIResource } from '../core/resource'; -import { APIPromise } from '../core/api-promise'; -import { RequestOptions } from '../internal/request-options'; - -/** - * Operations related to the current access token - */ -export class Token extends APIResource { - /** - * Returns information about the authenticated user/token - */ - info(options?: RequestOptions): APIPromise { - return this._client.get('/oauth/userinfo', options); - } -} - -export interface RevokeRequest { - /** - * The token to revoke - */ - token: string; - - /** - * Hint about the type of token being revoked - */ - token_type_hint?: 'access_token'; -} - -export interface UserInfo { - /** - * Issued at timestamp (Unix epoch seconds) - */ - iat: number; - - /** - * Granted scopes - */ - scope: string; - - /** - * Subject identifier (token ID) - */ - sub: string; - - /** - * Token type - */ - token_use: 'access'; - - /** - * Audience (client ID) - */ - aud?: string; - - /** - * Client identifier - */ - client_id?: string; - - /** - * Expiration timestamp (Unix epoch seconds) - */ - exp?: number; -} - -export declare namespace Token { - export { type RevokeRequest as RevokeRequest, type UserInfo as UserInfo }; -} diff --git a/src/resources/top-level.ts b/src/resources/top-level.ts new file mode 100644 index 0000000..7a9eafe --- /dev/null +++ b/src/resources/top-level.ts @@ -0,0 +1,125 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import * as Shared from './shared'; +import * as ChatsAPI from './chats/chats'; + +export interface DownloadAssetResponse { + /** + * Error message if the download failed. + */ + error?: string; + + /** + * Local file URL to the downloaded asset. + */ + srcURL?: string; +} + +/** + * Response indicating successful app opening. + */ +export interface OpenResponse { + /** + * Whether the app was successfully opened/focused. + */ + success: boolean; +} + +export interface SearchResponse { + results: SearchResponse.Results; +} + +export namespace SearchResponse { + export interface Results { + /** + * Top chat results. + */ + chats: Array; + + /** + * Top group results by participant matches. + */ + in_groups: Array; + + messages: Results.Messages; + } + + export namespace Results { + export interface Messages { + /** + * Map of chatID -> chat details for chats referenced in items. + */ + chats: { [key: string]: ChatsAPI.Chat }; + + /** + * True if additional results can be fetched using the provided cursors. + */ + hasMore: boolean; + + /** + * Messages matching the query and filters. + */ + items: Array; + + /** + * Cursor for fetching newer results (use with direction='after'). Opaque string; + * do not inspect. + */ + newestCursor: string | null; + + /** + * Cursor for fetching older results (use with direction='before'). Opaque string; + * do not inspect. + */ + oldestCursor: string | null; + } + } +} + +export interface DownloadAssetParams { + /** + * Matrix content URL (mxc:// or localmxc://) for the asset to download. + */ + url: string; +} + +export interface OpenParams { + /** + * Optional Beeper chat ID (or local chat ID) to focus after opening the app. If + * omitted, only opens/focuses the app. + */ + chatID?: string; + + /** + * Optional draft attachment path to populate in the message input field. + */ + draftAttachmentPath?: string; + + /** + * Optional draft text to populate in the message input field. + */ + draftText?: string; + + /** + * Optional message ID. Jumps to that message in the chat when opening. + */ + messageID?: string; +} + +export interface SearchParams { + /** + * User-typed search text. Literal word matching (NOT semantic). + */ + query: string; +} + +export declare namespace TopLevel { + export { + type DownloadAssetResponse as DownloadAssetResponse, + type OpenResponse as OpenResponse, + type SearchResponse as SearchResponse, + type DownloadAssetParams as DownloadAssetParams, + type OpenParams as OpenParams, + type SearchParams as SearchParams, + }; +} diff --git a/src/version.ts b/src/version.ts index 44ea521..8243372 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '0.1.5'; // x-release-please-version +export const VERSION = '0.1.6'; // x-release-please-version diff --git a/tests/api-resources/chats/chats.test.ts b/tests/api-resources/chats/chats.test.ts index 162c241..c411418 100644 --- a/tests/api-resources/chats/chats.test.ts +++ b/tests/api-resources/chats/chats.test.ts @@ -33,8 +33,8 @@ describe('resource chats', () => { }); }); - test('retrieve: only required params', async () => { - const responsePromise = client.chats.retrieve({ chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com' }); + test('retrieve', async () => { + const responsePromise = client.chats.retrieve('!NCdzlIaMjZUmvmvyHU:beeper.com'); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -44,15 +44,48 @@ describe('resource chats', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('retrieve: required and optional params', async () => { - const response = await client.chats.retrieve({ - chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', - maxParticipantCount: 50, - }); + test('retrieve: request options and params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.chats.retrieve( + '!NCdzlIaMjZUmvmvyHU:beeper.com', + { maxParticipantCount: 50 }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(BeeperDesktop.NotFoundError); + }); + + test('list', async () => { + const responsePromise = client.chats.list(); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + test('list: request options and params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.chats.list( + { + accountIDs: [ + 'whatsapp', + 'local-whatsapp_ba_EvYDBBsZbRQAy3UOSWqG0LuTVkc', + 'local-instagram_ba_eRfQMmnSNy_p7Ih7HL7RduRpKFU', + ], + cursor: '1725489123456', + direction: 'before', + }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(BeeperDesktop.NotFoundError); }); - test('archive: only required params', async () => { - const responsePromise = client.chats.archive({ chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com' }); + test('archive', async () => { + const responsePromise = client.chats.archive('!NCdzlIaMjZUmvmvyHU:beeper.com'); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -62,8 +95,15 @@ describe('resource chats', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('archive: required and optional params', async () => { - const response = await client.chats.archive({ chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', archived: true }); + test('archive: request options and params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.chats.archive( + '!NCdzlIaMjZUmvmvyHU:beeper.com', + { archived: true }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(BeeperDesktop.NotFoundError); }); test('search', async () => { diff --git a/tests/api-resources/chats/reminders.test.ts b/tests/api-resources/chats/reminders.test.ts index 8bf6fbd..82114dc 100644 --- a/tests/api-resources/chats/reminders.test.ts +++ b/tests/api-resources/chats/reminders.test.ts @@ -9,8 +9,7 @@ const client = new BeeperDesktop({ describe('resource reminders', () => { test('create: only required params', async () => { - const responsePromise = client.chats.reminders.create({ - chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', + const responsePromise = client.chats.reminders.create('!NCdzlIaMjZUmvmvyHU:beeper.com', { reminder: { remindAtMs: 0 }, }); const rawResponse = await responsePromise.asResponse(); @@ -23,14 +22,13 @@ describe('resource reminders', () => { }); test('create: required and optional params', async () => { - const response = await client.chats.reminders.create({ - chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', + const response = await client.chats.reminders.create('!NCdzlIaMjZUmvmvyHU:beeper.com', { reminder: { remindAtMs: 0, dismissOnIncomingMessage: true }, }); }); - test('delete: only required params', async () => { - const responsePromise = client.chats.reminders.delete({ chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com' }); + test('delete', async () => { + const responsePromise = client.chats.reminders.delete('!NCdzlIaMjZUmvmvyHU:beeper.com'); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -39,8 +37,4 @@ describe('resource reminders', () => { expect(dataAndResponse.data).toBe(response); expect(dataAndResponse.response).toBe(rawResponse); }); - - test('delete: required and optional params', async () => { - const response = await client.chats.reminders.delete({ chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com' }); - }); }); diff --git a/tests/api-resources/messages.test.ts b/tests/api-resources/messages.test.ts index 21fafff..616bd17 100644 --- a/tests/api-resources/messages.test.ts +++ b/tests/api-resources/messages.test.ts @@ -8,6 +8,25 @@ const client = new BeeperDesktop({ }); describe('resource messages', () => { + test('list: only required params', async () => { + const responsePromise = client.messages.list({ chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com' }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + test('list: required and optional params', async () => { + const response = await client.messages.list({ + chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', + cursor: '821744079', + direction: 'before', + }); + }); + test('search', async () => { const responsePromise = client.messages.search(); const rawResponse = await responsePromise.asResponse(); @@ -25,6 +44,7 @@ describe('resource messages', () => { client.messages.search( { accountIDs: [ + 'whatsapp', 'local-whatsapp_ba_EvYDBBsZbRQAy3UOSWqG0LuTVkc', 'local-instagram_ba_eRfQMmnSNy_p7Ih7HL7RduRpKFU', ], diff --git a/tests/api-resources/token.test.ts b/tests/api-resources/token.test.ts deleted file mode 100644 index 55e8716..0000000 --- a/tests/api-resources/token.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import BeeperDesktop from '@beeper/desktop-api'; - -const client = new BeeperDesktop({ - accessToken: 'My Access Token', - baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', -}); - -describe('resource token', () => { - test('info', async () => { - const responsePromise = client.token.info(); - const rawResponse = await responsePromise.asResponse(); - expect(rawResponse).toBeInstanceOf(Response); - const response = await responsePromise; - expect(response).not.toBeInstanceOf(Response); - const dataAndResponse = await responsePromise.withResponse(); - expect(dataAndResponse.data).toBe(response); - expect(dataAndResponse.response).toBe(rawResponse); - }); -}); diff --git a/tests/api-resources/app.test.ts b/tests/api-resources/top-level.test.ts similarity index 84% rename from tests/api-resources/app.test.ts rename to tests/api-resources/top-level.test.ts index 0e0a118..9ad90a9 100644 --- a/tests/api-resources/app.test.ts +++ b/tests/api-resources/top-level.test.ts @@ -7,9 +7,9 @@ const client = new BeeperDesktop({ baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', }); -describe('resource app', () => { +describe('top level methods', () => { test('downloadAsset: only required params', async () => { - const responsePromise = client.app.downloadAsset({ url: 'x' }); + const responsePromise = client.downloadAsset({ url: 'mxc://example.org/Q4x9CqGz1pB3Oa6XgJ' }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -20,11 +20,11 @@ describe('resource app', () => { }); test('downloadAsset: required and optional params', async () => { - const response = await client.app.downloadAsset({ url: 'x' }); + const response = await client.downloadAsset({ url: 'mxc://example.org/Q4x9CqGz1pB3Oa6XgJ' }); }); test('open', async () => { - const responsePromise = client.app.open(); + const responsePromise = client.open(); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -37,7 +37,7 @@ describe('resource app', () => { test('open: request options and params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error await expect( - client.app.open( + client.open( { chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', draftAttachmentPath: 'draftAttachmentPath', @@ -50,7 +50,7 @@ describe('resource app', () => { }); test('search: only required params', async () => { - const responsePromise = client.app.search({ query: 'x' }); + const responsePromise = client.search({ query: 'x' }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -61,6 +61,6 @@ describe('resource app', () => { }); test('search: required and optional params', async () => { - const response = await client.app.search({ query: 'x' }); + const response = await client.search({ query: 'x' }); }); }); diff --git a/tsconfig.build.json b/tsconfig.build.json index 4dd4578..1954cb1 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -5,8 +5,8 @@ "compilerOptions": { "rootDir": "./dist/src", "paths": { - "@beeper/desktop-api/*": ["dist/src/*"], - "@beeper/desktop-api": ["dist/src/index.ts"] + "@beeper/desktop-api/*": ["./dist/src/*"], + "@beeper/desktop-api": ["./dist/src/index.ts"] }, "noEmit": false, "declaration": true, diff --git a/tsconfig.json b/tsconfig.json index be8a0cd..a69f508 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,10 +7,9 @@ "module": "commonjs", "moduleResolution": "node", "esModuleInterop": true, - "baseUrl": "./", "paths": { - "@beeper/desktop-api/*": ["src/*"], - "@beeper/desktop-api": ["src/index.ts"] + "@beeper/desktop-api/*": ["./src/*"], + "@beeper/desktop-api": ["./src/index.ts"] }, "noEmit": true,