diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 92d8991..3ce698f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,10 +21,10 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/beeper-desktop-api-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '22' @@ -43,10 +43,10 @@ jobs: contents: read id-token: write steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '22' @@ -61,7 +61,7 @@ jobs: github.repository == 'stainless-sdks/beeper-desktop-api-typescript' && !startsWith(github.ref, 'refs/heads/stl/') id: github-oidc - uses: actions/github-script@v8 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 with: script: core.setOutput('github_token', await core.getIDToken()); @@ -91,10 +91,10 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/beeper-desktop-api-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '22' diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml index 3b8e2b0..76edfd1 100644 --- a/.github/workflows/publish-npm.yml +++ b/.github/workflows/publish-npm.yml @@ -20,10 +20,10 @@ jobs: contents: write steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Node - uses: actions/setup-node@v3 + uses: actions/setup-node@3235b876344d2a9aa001b8d1453c930bba69e610 # v3.9.1 with: node-version: '20' diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index 0e12ec5..2d74c68 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -12,7 +12,7 @@ jobs: if: github.repository == 'beeper/desktop-api-js' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Check release environment run: | diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 32dbe0e..affd1ab 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "5.0.0" + ".": "5.1.0" } diff --git a/.stats.yml b/.stats.yml index 2dd3fee..3e06ccc 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 30 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper/beeper-desktop-api-c08c14bb754b4cb0e02b21fabb680469368286be339dec0aaa8c69d04a1f021a.yml -openapi_spec_hash: a10246aaf7cdc33b682fc245bd5f893b -config_hash: 72f9d43b9b51a5da912e9f3730e53ae2 +configured_endpoints: 56 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper/beeper-desktop-api-baac187842e51587134950c59c4d746bfcb59239f01919ed83b92c24c47d98f4.yml +openapi_spec_hash: 9de80d05f7562b7ecd07c466f0fdf58b +config_hash: a8a4a8b869ccd5976fd4107e67d2ecae diff --git a/CHANGELOG.md b/CHANGELOG.md index 4932b1a..e47c195 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,28 @@ # Changelog +## 5.1.0 (2026-05-19) + +Full Changelog: [v5.0.0...v5.1.0](https://github.com/beeper/desktop-api-js/compare/v5.0.0...v5.1.0) + +### Features + +* **api:** add login flow, verifications, recovery key methods to app ([b9c1714](https://github.com/beeper/desktop-api-js/commit/b9c1714410139c2139b597338cd002d785653e85)) +* **api:** api update ([0a91186](https://github.com/beeper/desktop-api-js/commit/0a91186fa1a0811dc9eeb9d43c8093aaeb115e95)) +* **api:** remove cli ([40669cb](https://github.com/beeper/desktop-api-js/commit/40669cb5d53274627d81fc4554d4c5d29647e373)) + + +### Bug Fixes + +* **mcp:** require auth for standalone HTTP server ([eb86fa5](https://github.com/beeper/desktop-api-js/commit/eb86fa551df33109e963e2faf304b0380ac504f2)) +* **typescript:** upgrade tsc-multi so that it works with Node 26 ([550009b](https://github.com/beeper/desktop-api-js/commit/550009b71f922f605d4ca0e0059bbed6627e5fbe)) + + +### Chores + +* **internal:** regenerate SDK with no functional changes ([8b59f3a](https://github.com/beeper/desktop-api-js/commit/8b59f3a10dc81df3e61d1d467f221edf4fc2d032)) +* redact api-key headers in debug logs ([f34de70](https://github.com/beeper/desktop-api-js/commit/f34de708e01ce81a9cb6a9dcd180c44e76b4f2fd)) +* **tests:** remove redundant File import ([91bb886](https://github.com/beeper/desktop-api-js/commit/91bb8861dbbe6cbf63c3c8f6a3a03c76d579c084)) + ## 5.0.0 (2026-05-07) Full Changelog: [v4.8.0...v5.0.0](https://github.com/beeper/desktop-api-js/compare/v4.8.0...v5.0.0) diff --git a/README.md b/README.md index 86d6f1f..7c59c7f 100644 --- a/README.md +++ b/README.md @@ -220,7 +220,7 @@ const client = createClient({ }); // ... then make API calls as usual. -const accounts = await client.accounts.list(); +const account = await client.accounts.retrieve('accountID'); const chat = await client.chats.create({ accountID: 'accountID', participantIDs: ['string'], @@ -246,7 +246,7 @@ const client: PartialBeeperDesktop<{ accounts: BaseAccounts }> = createClient({ // Function parameter type async function main(client: PartialBeeperDesktop<{ accounts: BaseAccounts }>) { - const accounts = await client.accounts.list(); + const account = await client.accounts.retrieve('accountID'); } // Works with any client that has the accounts resource diff --git a/api.md b/api.md index bde6c07..5c996b9 100644 --- a/api.md +++ b/api.md @@ -14,6 +14,8 @@ Methods: Types: +- APIError +- AppStateSnapshot - Attachment - Error - Message @@ -25,10 +27,13 @@ Types: Types: - Account +- AccountBridge +- AccountRetrieveResponse - AccountListResponse Methods: +- client.accounts.retrieve(accountID) -> AccountRetrieveResponse - client.accounts.list() -> AccountListResponse ## Contacts @@ -42,6 +47,59 @@ Methods: - client.accounts.contacts.list(accountID, { ...params }) -> UsersCursorSearch - client.accounts.contacts.search(accountID, { ...params }) -> ContactSearchResponse +# Bridges + +Types: + +- Bridge +- CookieField +- DisappearingTimerCapability +- GroupFieldCapability +- GroupTypeCapabilities +- LoginFlow +- LoginInputField +- LoginSession +- ProvisioningCapabilities +- ResolveIdentifierCapabilities +- BridgeRetrieveResponse +- BridgeListResponse + +Methods: + +- client.bridges.retrieve(bridgeID) -> BridgeRetrieveResponse +- client.bridges.list() -> BridgeListResponse +- client.bridges.retrieveCapabilities(bridgeID) -> ProvisioningCapabilities + +## LoginFlows + +Types: + +- LoginFlowListResponse + +Methods: + +- client.bridges.loginFlows.list(bridgeID) -> LoginFlowListResponse + +## Connections + +## LoginSessions + +Types: + +- LoginSessionCancelResponse + +Methods: + +- client.bridges.loginSessions.create(bridgeID, { ...params }) -> LoginSession +- client.bridges.loginSessions.retrieve(loginSessionID, { ...params }) -> LoginSession +- client.bridges.loginSessions.cancel(loginSessionID, { ...params }) -> LoginSessionCancelResponse + +### Steps + +Methods: + +- client.bridges.loginSessions.steps.submit(stepID, { ...params }) -> LoginSession + # Chats Types: @@ -125,3 +183,95 @@ Types: Methods: - client.info.retrieve() -> InfoRetrieveResponse + +# App + +Types: + +- Verification +- AppSessionResponse + +Methods: + +- client.app.session() -> AppSessionResponse + +## Login + +Types: + +- LoginRegisterResponse +- LoginResponseResponse +- LoginStartResponse + +Methods: + +- client.app.login.email({ ...params }) -> void +- client.app.login.register({ ...params }) -> LoginRegisterResponse +- client.app.login.response({ ...params }) -> LoginResponseResponse +- client.app.login.start() -> LoginStartResponse + +### Verification + +#### RecoveryKey + +Types: + +- RecoveryKeyVerifyResponse + +Methods: + +- client.app.login.verification.recoveryKey.verify({ ...params }) -> RecoveryKeyVerifyResponse + +##### Reset + +Types: + +- ResetCreateResponse +- ResetConfirmResponse + +Methods: + +- client.app.login.verification.recoveryKey.reset.create({ ...params }) -> ResetCreateResponse +- client.app.login.verification.recoveryKey.reset.confirm({ ...params }) -> ResetConfirmResponse + +## Verifications + +Types: + +- VerificationCreateResponse +- VerificationRetrieveResponse +- VerificationListResponse +- VerificationAcceptResponse +- VerificationCancelResponse + +Methods: + +- client.app.verifications.create({ ...params }) -> VerificationCreateResponse +- client.app.verifications.retrieve(verificationID) -> VerificationRetrieveResponse +- client.app.verifications.list() -> VerificationListResponse +- client.app.verifications.accept(verificationID) -> VerificationAcceptResponse +- client.app.verifications.cancel(verificationID, { ...params }) -> VerificationCancelResponse + +### Qr + +Types: + +- QrConfirmScannedResponse +- QrScanResponse + +Methods: + +- client.app.verifications.qr.confirmScanned(verificationID) -> QrConfirmScannedResponse +- client.app.verifications.qr.scan({ ...params }) -> QrScanResponse + +### SAS + +Types: + +- SASConfirmResponse +- SASStartResponse + +Methods: + +- client.app.verifications.sas.confirm(verificationID) -> SASConfirmResponse +- client.app.verifications.sas.start(verificationID) -> SASStartResponse diff --git a/package.json b/package.json index 0943a76..e510903 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@beeper/desktop-api", - "version": "5.0.0", + "version": "5.1.0", "description": "The official TypeScript library for the Beeper Desktop API", "author": "Beeper Desktop ", "types": "dist/index.d.ts", @@ -43,7 +43,7 @@ "publint": "^0.2.12", "ts-jest": "^29.1.0", "ts-node": "^10.5.0", - "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz", + "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz", "tsconfig-paths": "^4.0.0", "tslib": "^2.8.1", "typescript": "5.8.3", diff --git a/packages/mcp-server/manifest.json b/packages/mcp-server/manifest.json index d59e134..4c124d1 100644 --- a/packages/mcp-server/manifest.json +++ b/packages/mcp-server/manifest.json @@ -1,7 +1,7 @@ { "dxt_version": "0.2", "name": "@beeper/desktop-mcp", - "version": "5.0.0", + "version": "5.1.0", "description": "The official MCP Server for the Beeper Desktop API", "author": { "name": "Beeper Desktop", @@ -29,7 +29,7 @@ "user_config": { "BEEPER_ACCESS_TOKEN": { "title": "access_token", - "description": "Bearer access token obtained via OAuth2 PKCE flow or created in-app. Required for all API operations.", + "description": "Bearer access token obtained via OAuth2 PKCE flow or created in-app. Required for authenticated API operations.", "required": true, "type": "string" } diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index 67c9e04..014babb 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -1,6 +1,6 @@ { "name": "@beeper/desktop-mcp", - "version": "5.0.0", + "version": "5.1.0", "description": "The official MCP Server for the Beeper Desktop API", "author": "Beeper Desktop ", "types": "dist/index.d.ts", @@ -74,7 +74,7 @@ "ts-jest": "^29.1.0", "ts-morph": "^19.0.0", "ts-node": "^10.5.0", - "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz", + "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz", "tsconfig-paths": "^4.0.0" }, "imports": { diff --git a/packages/mcp-server/src/auth.ts b/packages/mcp-server/src/auth.ts index 150450b..56671e9 100644 --- a/packages/mcp-server/src/auth.ts +++ b/packages/mcp-server/src/auth.ts @@ -7,7 +7,6 @@ import { McpOptions } from './options'; export const parseClientAuthHeaders = (req: IncomingMessage, required?: boolean): Partial => { if (req.headers.authorization) { const scheme = req.headers.authorization.split(' ')[0]!; - const value = req.headers.authorization.slice(scheme.length + 1); switch (scheme) { case 'Bearer': return { accessToken: req.headers.authorization.slice('Bearer '.length) }; @@ -16,14 +15,15 @@ export const parseClientAuthHeaders = (req: IncomingMessage, required?: boolean) 'Unsupported authorization scheme. Expected the "Authorization" header to be a supported scheme (Bearer).', ); } - } else if (required) { - throw new Error('Missing required Authorization header; see WWW-Authenticate header for details.'); } const accessToken = Array.isArray(req.headers['x-beeper-access-token']) ? req.headers['x-beeper-access-token'][0] : req.headers['x-beeper-access-token']; + if (!accessToken && required) { + throw new Error('Missing required Authorization header; see WWW-Authenticate header for details.'); + } return { accessToken }; }; diff --git a/packages/mcp-server/src/code-tool-worker.ts b/packages/mcp-server/src/code-tool-worker.ts index b7ad928..931835f 100644 --- a/packages/mcp-server/src/code-tool-worker.ts +++ b/packages/mcp-server/src/code-tool-worker.ts @@ -111,8 +111,17 @@ const fuse = new Fuse( 'client.focus', 'client.search', 'client.accounts.list', + 'client.accounts.retrieve', 'client.accounts.contacts.list', 'client.accounts.contacts.search', + 'client.bridges.list', + 'client.bridges.retrieve', + 'client.bridges.retrieveCapabilities', + 'client.bridges.loginFlows.list', + 'client.bridges.loginSessions.cancel', + 'client.bridges.loginSessions.create', + 'client.bridges.loginSessions.retrieve', + 'client.bridges.loginSessions.steps.submit', 'client.chats.archive', 'client.chats.create', 'client.chats.list', @@ -138,6 +147,23 @@ const fuse = new Fuse( 'client.assets.upload', 'client.assets.uploadBase64', 'client.info.retrieve', + 'client.app.session', + 'client.app.login.email', + 'client.app.login.register', + 'client.app.login.response', + 'client.app.login.start', + 'client.app.login.verification.recoveryKey.verify', + 'client.app.login.verification.recoveryKey.reset.confirm', + 'client.app.login.verification.recoveryKey.reset.create', + 'client.app.verifications.accept', + 'client.app.verifications.cancel', + 'client.app.verifications.create', + 'client.app.verifications.list', + 'client.app.verifications.retrieve', + 'client.app.verifications.qr.confirmScanned', + 'client.app.verifications.qr.scan', + 'client.app.verifications.sas.confirm', + 'client.app.verifications.sas.start', ], { threshold: 1, shouldSort: true }, ); diff --git a/packages/mcp-server/src/http.ts b/packages/mcp-server/src/http.ts index 6a55c8d..3c85a28 100644 --- a/packages/mcp-server/src/http.ts +++ b/packages/mcp-server/src/http.ts @@ -3,7 +3,6 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp'; import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; import { ClientOptions } from '@beeper/desktop-api'; -import cors from 'cors'; import express from 'express'; import pino from 'pino'; import pinoHttp from 'pino-http'; @@ -12,11 +11,6 @@ import { getLogger } from './logger'; import { McpOptions } from './options'; import { initMcpServer, newMcpServer } from './server'; -const oauthResourceIdentifier = (req: express.Request): string => { - const protocol = req.headers['x-forwarded-proto'] ?? req.protocol; - return `${protocol}://${req.get('host')}/`; -}; - const newServer = async ({ clientOptions, mcpOptions, @@ -32,28 +26,7 @@ const newServer = async ({ const customInstructionsPath = mcpOptions.customInstructionsPath; const server = await newMcpServer({ stainlessApiKey, customInstructionsPath }); - // parseClientAuthHeaders throws if the Authorization header uses an unsupported - // scheme, or (when the second arg is true) if the header is missing entirely. - // On error, we return 401 with WWW-Authenticate pointing to the OAuth metadata - // endpoint so clients know how to authenticate (RFC 9728). - let authOptions: Partial; - try { - authOptions = parseClientAuthHeaders(req, false); - } catch (error) { - const resourceIdentifier = oauthResourceIdentifier(req); - res.set( - 'WWW-Authenticate', - `Bearer resource_metadata="${resourceIdentifier}.well-known/oauth-protected-resource"`, - ); - res.status(401).json({ - jsonrpc: '2.0', - error: { - code: -32000, - message: `Unauthorized: ${error instanceof Error ? error.message : error}`, - }, - }); - return null; - } + const authOptions = parseClientAuthHeaders(req, true); let upstreamClientEnvs: Record | undefined; const clientEnvsHeader = req.headers['x-stainless-mcp-client-envs']; @@ -152,16 +125,6 @@ const del = async (req: express.Request, res: express.Response) => { }); }; -const oauthMetadata = (req: express.Request, res: express.Response) => { - const resourceIdentifier = oauthResourceIdentifier(req); - res.json({ - resource: resourceIdentifier, - authorization_servers: ['http://localhost:23373'], - bearer_methods_supported: ['header'], - scopes_supported: 'read write', - }); -}; - const redactHeaders = (headers: Record) => { const hiddenHeaders = /auth|cookie|key|token|x-stainless-mcp-client-envs/i; const filtered = { ...headers }; @@ -231,8 +194,6 @@ export const streamableHTTPApp = ({ }), ); - app.get('/.well-known/oauth-protected-resource', cors(), oauthMetadata); - app.get('/health', async (req: express.Request, res: express.Response) => { res.status(200).send('OK'); }); diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index e2d6160..ed60808 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -56,7 +56,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ httpMethod: 'post', summary: 'Focus Beeper Desktop app', description: - 'Focus Beeper Desktop and optionally navigate to a specific chat, message, or pre-fill plain text and an image path.', + 'Focus Beeper Desktop and optionally open a specific chat, jump to a message, or pre-fill text and an image.', stainlessPath: '(resource) $client > (method) focus', qualified: 'client.focus', params: [ @@ -67,7 +67,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ ], response: '{ success: boolean; }', markdown: - "## focus\n\n`client.focus(chatID?: string, draftAttachmentPath?: string, draftText?: string, messageID?: string): { success: boolean; }`\n\n**post** `/v1/focus`\n\nFocus Beeper Desktop and optionally navigate to a specific chat, message, or pre-fill plain text and an image path.\n\n### Parameters\n\n- `chatID?: string`\n Optional Beeper chat ID (or local chat ID) to focus after opening the app. If omitted, only opens/focuses the app.\n\n- `draftAttachmentPath?: string`\n Optional image path to populate in the message input field.\n\n- `draftText?: string`\n Optional plain text to populate in the message input field.\n\n- `messageID?: string`\n Optional message ID. Jumps to that message in the chat when opening.\n\n### Returns\n\n- `{ success: boolean; }`\n Response indicating successful app focus action.\n\n - `success: boolean`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.focus();\n\nconsole.log(response);\n```", + "## focus\n\n`client.focus(chatID?: string, draftAttachmentPath?: string, draftText?: string, messageID?: string): { success: boolean; }`\n\n**post** `/v1/focus`\n\nFocus Beeper Desktop and optionally open a specific chat, jump to a message, or pre-fill text and an image.\n\n### Parameters\n\n- `chatID?: string`\n Optional Beeper chat ID (or local chat ID) to focus after opening the app. If omitted, only opens/focuses the app.\n\n- `draftAttachmentPath?: string`\n Optional local image path to populate in the message input field.\n\n- `draftText?: string`\n Optional plain text to populate in the message input field.\n\n- `messageID?: string`\n Optional message ID. Jumps to that message in the chat when opening.\n\n### Returns\n\n- `{ success: boolean; }`\n Response indicating successful app focus action.\n\n - `success: boolean`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.focus();\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.focus', @@ -86,7 +86,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ }, cli: { method: '$client focus', - example: "beeper-desktop-cli focus \\\n --access-token 'My Access Token'", + example: "beeper-desktop focus \\\n --access-token 'My Access Token'", }, php: { method: 'focus', @@ -105,14 +105,14 @@ const EMBEDDED_METHODS: MethodEntry[] = [ httpMethod: 'get', summary: 'Search', description: - '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.', + 'Return matching chats, participant matches in group chats, and the first page of message results in one call. Use the dedicated chat and message search endpoints for pagination.', stainlessPath: '(resource) $client > (method) search', qualified: 'client.search', params: ['query: string;'], response: '{ results: { chats: object[]; in_groups: object[]; messages: { chats: object; hasMore: boolean; items: message[]; newestCursor: string; oldestCursor: string; }; }; }', markdown: - "## search\n\n`client.search(query: string): { results: object; }`\n\n**get** `/v1/search`\n\nReturns 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.\n\n### Parameters\n\n- `query: string`\n User-typed search text. Literal word matching (non-semantic).\n\n### Returns\n\n- `{ results: { chats: object[]; in_groups: object[]; messages: { chats: object; hasMore: boolean; items: message[]; newestCursor: string; oldestCursor: string; }; }; }`\n\n - `results: { chats: { id: string; accountID: string; network: string; participants: { hasMore: boolean; items: user[]; total: number; }; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: object; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: object; participantActions?: object; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: object; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }; description?: string; draft?: { text: string; attachments?: object; }; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }; snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }; unreadMentionsCount?: number; }[]; in_groups: { id: string; accountID: string; network: string; participants: { hasMore: boolean; items: user[]; total: number; }; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: object; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: object; participantActions?: object; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: object; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }; description?: string; draft?: { text: string; attachments?: object; }; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }; snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }; unreadMentionsCount?: number; }[]; messages: { chats: object; hasMore: boolean; items: { id: string; accountID: string; chatID: string; senderID: string; sortKey: string; timestamp: string; attachments?: attachment[]; editedTimestamp?: string; isDeleted?: boolean; isHidden?: boolean; isSender?: boolean; isUnread?: boolean; linkedMessageID?: string; links?: object[]; mentions?: string[]; reactions?: reaction[]; seen?: boolean | string | object; senderName?: string; sendStatus?: object; text?: string; type?: string; }[]; newestCursor: string; oldestCursor: string; }; }`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.search({ query: 'x' });\n\nconsole.log(response);\n```", + "## search\n\n`client.search(query: string): { results: object; }`\n\n**get** `/v1/search`\n\nReturn matching chats, participant matches in group chats, and the first page of message results in one call. Use the dedicated chat and message search endpoints for pagination.\n\n### Parameters\n\n- `query: string`\n User-typed search text. Uses literal word matching.\n\n### Returns\n\n- `{ results: { chats: object[]; in_groups: object[]; messages: { chats: object; hasMore: boolean; items: message[]; newestCursor: string; oldestCursor: string; }; }; }`\n\n - `results: { chats: { id: string; accountID: string; network: string; participants: { hasMore: boolean; items: user[]; total: number; }; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: object; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: object; participantActions?: object; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: object; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }; description?: string; draft?: { text: string; attachments?: object; }; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }; snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }; unreadMentionsCount?: number; }[]; in_groups: { id: string; accountID: string; network: string; participants: { hasMore: boolean; items: user[]; total: number; }; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: object; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: object; participantActions?: object; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: object; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }; description?: string; draft?: { text: string; attachments?: object; }; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }; snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }; unreadMentionsCount?: number; }[]; messages: { chats: object; hasMore: boolean; items: { id: string; accountID: string; chatID: string; senderID: string; sortKey: string; timestamp: string; attachments?: attachment[]; editedTimestamp?: string; isDeleted?: boolean; isHidden?: boolean; isSender?: boolean; isUnread?: boolean; linkedMessageID?: string; links?: object[]; mentions?: string[]; reactions?: reaction[]; seen?: boolean | string | object; senderName?: string; sendStatus?: object; text?: string; type?: string; }[]; newestCursor: string; oldestCursor: string; }; }`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.search({ query: 'x' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.search', @@ -131,7 +131,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ }, cli: { method: '$client search', - example: "beeper-desktop-cli search \\\n --access-token 'My Access Token' \\\n --query x", + example: "beeper-desktop search \\\n --access-token 'My Access Token' \\\n --query x", }, php: { method: 'search', @@ -148,15 +148,15 @@ const EMBEDDED_METHODS: MethodEntry[] = [ name: 'list', endpoint: '/v1/accounts', httpMethod: 'get', - summary: 'List Chat Accounts', + summary: 'List chat accounts', description: - 'List Chat Accounts connected to this Beeper Desktop instance, including bridge metadata and network identity.', + 'List chat accounts connected to this Beeper Client API server, including bridge, network, user identity, and connection status.', stainlessPath: '(resource) accounts > (method) list', qualified: 'client.accounts.list', response: - "{ accountID: string; bridge: { id: string; provider: 'cloud' | 'self-hosted' | 'local' | 'platform-sdk'; type: string; }; user: object; network?: string; }[]", + '{ accountID: string; bridge: object; status: string; user: object; capabilities?: object; loginID?: string; network?: string; statusText?: string; }[]', markdown: - "## list\n\n`client.accounts.list(): object[]`\n\n**get** `/v1/accounts`\n\nList Chat Accounts connected to this Beeper Desktop instance, including bridge metadata and network identity.\n\n### Returns\n\n- `{ accountID: string; bridge: { id: string; provider: 'cloud' | 'self-hosted' | 'local' | 'platform-sdk'; type: string; }; user: object; network?: string; }[]`\n Accounts configured on this device. Includes accountID, bridge metadata, optional network name, and user identity.\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst accounts = await client.accounts.list();\n\nconsole.log(accounts);\n```", + "## list\n\n`client.accounts.list(): object[]`\n\n**get** `/v1/accounts`\n\nList chat accounts connected to this Beeper Client API server, including bridge, network, user identity, and connection status.\n\n### Returns\n\n- `{ accountID: string; bridge: object; status: string; user: object; capabilities?: object; loginID?: string; network?: string; statusText?: string; }[]`\n Chat accounts configured on this device. Includes accountID, bridge metadata, optional network name, and user identity.\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst accounts = await client.accounts.list();\n\nconsole.log(accounts);\n```", perLanguage: { typescript: { method: 'client.accounts.list', @@ -175,7 +175,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ }, cli: { method: 'accounts list', - example: "beeper-desktop-cli accounts list \\\n --access-token 'My Access Token'", + example: "beeper-desktop accounts list \\\n --access-token 'My Access Token'", }, php: { method: 'accounts->list', @@ -188,6 +188,51 @@ const EMBEDDED_METHODS: MethodEntry[] = [ }, }, }, + { + name: 'retrieve', + endpoint: '/v1/accounts/{accountID}', + httpMethod: 'get', + summary: 'Get chat account', + description: 'Get one chat account connected to this Beeper Client API server.', + stainlessPath: '(resource) accounts > (method) retrieve', + qualified: 'client.accounts.retrieve', + params: ['accountID: string;'], + response: + "{ accountID: string; bridge: { id: string; provider: 'cloud' | 'self-hosted' | 'local' | 'platform-sdk'; type: string; }; status: string; user: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }; capabilities?: object; loginID?: string; network?: string; statusText?: string; }", + markdown: + "## retrieve\n\n`client.accounts.retrieve(accountID: string): { accountID: string; bridge: account_bridge; status: string; user: user; capabilities?: object; loginID?: string; network?: string; statusText?: string; }`\n\n**get** `/v1/accounts/{accountID}`\n\nGet one chat account connected to this Beeper Client API server.\n\n### Parameters\n\n- `accountID: string`\n Account ID this resource belongs to.\n\n### Returns\n\n- `{ accountID: string; bridge: { id: string; provider: 'cloud' | 'self-hosted' | 'local' | 'platform-sdk'; type: string; }; status: string; user: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }; capabilities?: object; loginID?: string; network?: string; statusText?: string; }`\n A chat account added to Beeper.\n\n - `accountID: string`\n - `bridge: { id: string; provider: 'cloud' | 'self-hosted' | 'local' | 'platform-sdk'; type: string; }`\n - `status: string`\n - `user: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }`\n - `capabilities?: object`\n - `loginID?: string`\n - `network?: string`\n - `statusText?: string`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst account = await client.accounts.retrieve('accountID');\n\nconsole.log(account);\n```", + perLanguage: { + typescript: { + method: 'client.accounts.retrieve', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop({\n accessToken: process.env['BEEPER_ACCESS_TOKEN'], // This is the default and can be omitted\n});\n\nconst account = await client.accounts.retrieve('accountID');\n\nconsole.log(account.bridge);", + }, + python: { + method: 'accounts.retrieve', + example: + 'import os\nfrom beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop(\n access_token=os.environ.get("BEEPER_ACCESS_TOKEN"), # This is the default and can be omitted\n)\naccount = client.accounts.retrieve(\n "accountID",\n)\nprint(account.bridge)', + }, + go: { + method: 'client.Accounts.Get', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\taccount, err := client.Accounts.Get(context.TODO(), "accountID")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", account.Bridge)\n}\n', + }, + cli: { + method: 'accounts retrieve', + example: + "beeper-desktop accounts retrieve \\\n --access-token 'My Access Token' \\\n --account-id accountID", + }, + php: { + method: 'accounts->retrieve', + example: + "accounts->retrieve('accountID');\n\nvar_dump($account);", + }, + http: { + example: + 'curl http://localhost:23373/v1/accounts/$ACCOUNT_ID \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN"', + }, + }, + }, { name: 'search', endpoint: '/v1/accounts/{accountID}/contacts', @@ -201,7 +246,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: '{ items: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }[]; }', markdown: - "## search\n\n`client.accounts.contacts.search(accountID: string, query: string): { items: user[]; }`\n\n**get** `/v1/accounts/{accountID}/contacts`\n\nSearch contacts on a specific account using merged account contacts, network search, and exact identifier lookup.\n\n### Parameters\n\n- `accountID: string`\n Account ID this resource belongs to.\n\n- `query: string`\n Text to search users by. Network-specific behavior.\n\n### Returns\n\n- `{ items: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }[]; }`\n\n - `items: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }[]`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.accounts.contacts.search('accountID', { query: 'x' });\n\nconsole.log(response);\n```", + "## search\n\n`client.accounts.contacts.search(accountID: string, query: string): { items: user[]; }`\n\n**get** `/v1/accounts/{accountID}/contacts`\n\nSearch contacts on a specific account using merged account contacts, network search, and exact identifier lookup.\n\n### Parameters\n\n- `accountID: string`\n Account ID this resource belongs to.\n\n- `query: string`\n Text to search contacts by. Matching behavior depends on the network.\n\n### Returns\n\n- `{ items: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }[]; }`\n\n - `items: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }[]`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.accounts.contacts.search('accountID', { query: 'x' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.accounts.contacts.search', @@ -221,7 +266,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ cli: { method: 'contacts search', example: - "beeper-desktop-cli accounts:contacts search \\\n --access-token 'My Access Token' \\\n --account-id accountID \\\n --query x", + "beeper-desktop accounts:contacts search \\\n --access-token 'My Access Token' \\\n --account-id accountID \\\n --query x", }, php: { method: 'accounts->contacts->search', @@ -252,7 +297,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: '{ id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }', markdown: - "## list\n\n`client.accounts.contacts.list(accountID: string, cursor?: string, direction?: 'after' | 'before', limit?: number, query?: string): { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }`\n\n**get** `/v1/accounts/{accountID}/contacts/list`\n\nList merged contacts for a specific account with cursor-based pagination.\n\n### Parameters\n\n- `accountID: string`\n Account ID this resource belongs to.\n\n- `cursor?: string`\n Opaque pagination cursor; do not inspect. Use together with 'direction'.\n\n- `direction?: 'after' | 'before'`\n Pagination direction used with 'cursor': 'before' fetches older results, 'after' fetches newer results. Defaults to 'before' when only 'cursor' is provided.\n\n- `limit?: number`\n Maximum contacts to return per page.\n\n- `query?: string`\n Optional search query for blended contact lookup.\n\n### Returns\n\n- `{ id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }`\n User the account belongs to.\n\n - `id: string`\n - `cannotMessage?: boolean`\n - `email?: string`\n - `fullName?: string`\n - `imgURL?: string`\n - `isSelf?: boolean`\n - `phoneNumber?: string`\n - `username?: string`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\n// Automatically fetches more pages as needed.\nfor await (const user of client.accounts.contacts.list('accountID')) {\n console.log(user);\n}\n```", + "## list\n\n`client.accounts.contacts.list(accountID: string, cursor?: string, direction?: 'after' | 'before', limit?: number, query?: string): { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }`\n\n**get** `/v1/accounts/{accountID}/contacts/list`\n\nList merged contacts for a specific account with cursor-based pagination.\n\n### Parameters\n\n- `accountID: string`\n Account ID this resource belongs to.\n\n- `cursor?: string`\n Opaque pagination cursor; do not inspect. Use together with 'direction'.\n\n- `direction?: 'after' | 'before'`\n Pagination direction used with 'cursor': 'before' fetches older results, 'after' fetches newer results. Defaults to 'before' when only 'cursor' is provided.\n\n- `limit?: number`\n Maximum contacts to return per page.\n\n- `query?: string`\n Optional search query for contact lookup.\n\n### Returns\n\n- `{ id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }`\n User the account belongs to.\n\n - `id: string`\n - `cannotMessage?: boolean`\n - `email?: string`\n - `fullName?: string`\n - `imgURL?: string`\n - `isSelf?: boolean`\n - `phoneNumber?: string`\n - `username?: string`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\n// Automatically fetches more pages as needed.\nfor await (const user of client.accounts.contacts.list('accountID')) {\n console.log(user);\n}\n```", perLanguage: { typescript: { method: 'client.accounts.contacts.list', @@ -272,7 +317,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ cli: { method: 'contacts list', example: - "beeper-desktop-cli accounts:contacts list \\\n --access-token 'My Access Token' \\\n --account-id accountID", + "beeper-desktop accounts:contacts list \\\n --access-token 'My Access Token' \\\n --account-id accountID", }, php: { method: 'accounts->contacts->list', @@ -285,19 +330,387 @@ const EMBEDDED_METHODS: MethodEntry[] = [ }, }, }, + { + name: 'list', + endpoint: '/v1/bridges', + httpMethod: 'get', + summary: 'List available bridges', + description: + 'List available bridges. A bridge is a chat-network connector that can connect or reconnect chat accounts. Connected accounts use the same Account schema as GET /v1/accounts.', + stainlessPath: '(resource) bridges > (method) list', + qualified: 'client.bridges.list', + response: + "{ items: { id: string; accounts: account[]; activeAccountCount: number; displayName: string; provider: 'cloud' | 'self-hosted' | 'local' | 'platform-sdk'; status: 'available' | 'connected' | 'limit_reached' | 'temporarily_unavailable' | 'disabled'; supportsMultipleAccounts: boolean; type: string; network?: string; statusText?: string; }[]; }", + markdown: + "## list\n\n`client.bridges.list(): { items: bridge[]; }`\n\n**get** `/v1/bridges`\n\nList available bridges. A bridge is a chat-network connector that can connect or reconnect chat accounts. Connected accounts use the same Account schema as GET /v1/accounts.\n\n### Returns\n\n- `{ items: { id: string; accounts: account[]; activeAccountCount: number; displayName: string; provider: 'cloud' | 'self-hosted' | 'local' | 'platform-sdk'; status: 'available' | 'connected' | 'limit_reached' | 'temporarily_unavailable' | 'disabled'; supportsMultipleAccounts: boolean; type: string; network?: string; statusText?: string; }[]; }`\n Available bridges and their connected accounts.\n\n - `items: { id: string; accounts: { accountID: string; bridge: account_bridge; status: string; user: user; capabilities?: object; loginID?: string; network?: string; statusText?: string; }[]; activeAccountCount: number; displayName: string; provider: 'cloud' | 'self-hosted' | 'local' | 'platform-sdk'; status: 'available' | 'connected' | 'limit_reached' | 'temporarily_unavailable' | 'disabled'; supportsMultipleAccounts: boolean; type: string; network?: string; statusText?: string; }[]`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst bridges = await client.bridges.list();\n\nconsole.log(bridges);\n```", + perLanguage: { + typescript: { + method: 'client.bridges.list', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop({\n accessToken: process.env['BEEPER_ACCESS_TOKEN'], // This is the default and can be omitted\n});\n\nconst bridges = await client.bridges.list();\n\nconsole.log(bridges.items);", + }, + python: { + method: 'bridges.list', + example: + 'import os\nfrom beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop(\n access_token=os.environ.get("BEEPER_ACCESS_TOKEN"), # This is the default and can be omitted\n)\nbridges = client.bridges.list()\nprint(bridges.items)', + }, + go: { + method: 'client.Bridges.List', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\tbridges, err := client.Bridges.List(context.TODO())\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", bridges.Items)\n}\n', + }, + cli: { + method: 'bridges list', + example: "beeper-desktop bridges list \\\n --access-token 'My Access Token'", + }, + php: { + method: 'bridges->list', + example: + "bridges->list();\n\nvar_dump($bridges);", + }, + http: { + example: + 'curl http://localhost:23373/v1/bridges \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN"', + }, + }, + }, + { + name: 'retrieve', + endpoint: '/v1/bridges/{bridgeID}', + httpMethod: 'get', + summary: 'Get bridge', + description: 'Get one bridge, including the chat accounts connected through it.', + stainlessPath: '(resource) bridges > (method) retrieve', + qualified: 'client.bridges.retrieve', + params: ['bridgeID: string;'], + response: + "{ id: string; accounts: { accountID: string; bridge: account_bridge; status: string; user: user; capabilities?: object; loginID?: string; network?: string; statusText?: string; }[]; activeAccountCount: number; displayName: string; provider: 'cloud' | 'self-hosted' | 'local' | 'platform-sdk'; status: 'available' | 'connected' | 'limit_reached' | 'temporarily_unavailable' | 'disabled'; supportsMultipleAccounts: boolean; type: string; network?: string; statusText?: string; }", + markdown: + "## retrieve\n\n`client.bridges.retrieve(bridgeID: string): { id: string; accounts: account[]; activeAccountCount: number; displayName: string; provider: 'cloud' | 'self-hosted' | 'local' | 'platform-sdk'; status: 'available' | 'connected' | 'limit_reached' | 'temporarily_unavailable' | 'disabled'; supportsMultipleAccounts: boolean; type: string; network?: string; statusText?: string; }`\n\n**get** `/v1/bridges/{bridgeID}`\n\nGet one bridge, including the chat accounts connected through it.\n\n### Parameters\n\n- `bridgeID: string`\n Bridge ID.\n\n### Returns\n\n- `{ id: string; accounts: { accountID: string; bridge: account_bridge; status: string; user: user; capabilities?: object; loginID?: string; network?: string; statusText?: string; }[]; activeAccountCount: number; displayName: string; provider: 'cloud' | 'self-hosted' | 'local' | 'platform-sdk'; status: 'available' | 'connected' | 'limit_reached' | 'temporarily_unavailable' | 'disabled'; supportsMultipleAccounts: boolean; type: string; network?: string; statusText?: string; }`\n Available bridge that can connect or reconnect chat accounts.\n\n - `id: string`\n - `accounts: { accountID: string; bridge: { id: string; provider: 'cloud' | 'self-hosted' | 'local' | 'platform-sdk'; type: string; }; status: string; user: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }; capabilities?: object; loginID?: string; network?: string; statusText?: string; }[]`\n - `activeAccountCount: number`\n - `displayName: string`\n - `provider: 'cloud' | 'self-hosted' | 'local' | 'platform-sdk'`\n - `status: 'available' | 'connected' | 'limit_reached' | 'temporarily_unavailable' | 'disabled'`\n - `supportsMultipleAccounts: boolean`\n - `type: string`\n - `network?: string`\n - `statusText?: string`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst bridge = await client.bridges.retrieve('local-whatsapp');\n\nconsole.log(bridge);\n```", + perLanguage: { + typescript: { + method: 'client.bridges.retrieve', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop({\n accessToken: process.env['BEEPER_ACCESS_TOKEN'], // This is the default and can be omitted\n});\n\nconst bridge = await client.bridges.retrieve('local-whatsapp');\n\nconsole.log(bridge.id);", + }, + python: { + method: 'bridges.retrieve', + example: + 'import os\nfrom beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop(\n access_token=os.environ.get("BEEPER_ACCESS_TOKEN"), # This is the default and can be omitted\n)\nbridge = client.bridges.retrieve(\n "local-whatsapp",\n)\nprint(bridge.id)', + }, + go: { + method: 'client.Bridges.Get', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\tbridge, err := client.Bridges.Get(context.TODO(), "local-whatsapp")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", bridge.ID)\n}\n', + }, + cli: { + method: 'bridges retrieve', + example: + "beeper-desktop bridges retrieve \\\n --access-token 'My Access Token' \\\n --bridge-id local-whatsapp", + }, + php: { + method: 'bridges->retrieve', + example: + "bridges->retrieve('local-whatsapp');\n\nvar_dump($bridge);", + }, + http: { + example: + 'curl http://localhost:23373/v1/bridges/$BRIDGE_ID \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN"', + }, + }, + }, + { + name: 'retrieve_capabilities', + endpoint: '/v1/bridges/{bridgeID}/capabilities', + httpMethod: 'get', + summary: 'Get bridge capabilities', + description: + 'Get advanced network capabilities for a bridge. This endpoint is intended for clients that build custom connect or chat-creation flows.', + stainlessPath: '(resource) bridges > (method) retrieve_capabilities', + qualified: 'client.bridges.retrieveCapabilities', + params: ['bridgeID: string;'], + response: + '{ group_creation: object; resolve_identifier: { any_phone: boolean; contact_list: boolean; create_dm: boolean; lookup_email: boolean; lookup_phone: boolean; lookup_username: boolean; search: boolean; }; image_pack_import?: boolean; }', + markdown: + "## retrieve_capabilities\n\n`client.bridges.retrieveCapabilities(bridgeID: string): { group_creation: object; resolve_identifier: resolve_identifier_capabilities; image_pack_import?: boolean; }`\n\n**get** `/v1/bridges/{bridgeID}/capabilities`\n\nGet advanced network capabilities for a bridge. This endpoint is intended for clients that build custom connect or chat-creation flows.\n\n### Parameters\n\n- `bridgeID: string`\n Bridge ID.\n\n### Returns\n\n- `{ group_creation: object; resolve_identifier: { any_phone: boolean; contact_list: boolean; create_dm: boolean; lookup_email: boolean; lookup_phone: boolean; lookup_username: boolean; search: boolean; }; image_pack_import?: boolean; }`\n Advanced network capabilities for account lookup and group creation.\n\n - `group_creation: object`\n - `resolve_identifier: { any_phone: boolean; contact_list: boolean; create_dm: boolean; lookup_email: boolean; lookup_phone: boolean; lookup_username: boolean; search: boolean; }`\n - `image_pack_import?: boolean`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst provisioningCapabilities = await client.bridges.retrieveCapabilities('local-whatsapp');\n\nconsole.log(provisioningCapabilities);\n```", + perLanguage: { + typescript: { + method: 'client.bridges.retrieveCapabilities', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop({\n accessToken: process.env['BEEPER_ACCESS_TOKEN'], // This is the default and can be omitted\n});\n\nconst provisioningCapabilities = await client.bridges.retrieveCapabilities('local-whatsapp');\n\nconsole.log(provisioningCapabilities.resolve_identifier);", + }, + python: { + method: 'bridges.retrieve_capabilities', + example: + 'import os\nfrom beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop(\n access_token=os.environ.get("BEEPER_ACCESS_TOKEN"), # This is the default and can be omitted\n)\nprovisioning_capabilities = client.bridges.retrieve_capabilities(\n "local-whatsapp",\n)\nprint(provisioning_capabilities.resolve_identifier)', + }, + go: { + method: 'client.Bridges.GetCapabilities', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\tprovisioningCapabilities, err := client.Bridges.GetCapabilities(context.TODO(), "local-whatsapp")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", provisioningCapabilities.ResolveIdentifier)\n}\n', + }, + cli: { + method: 'bridges retrieve_capabilities', + example: + "beeper-desktop bridges retrieve-capabilities \\\n --access-token 'My Access Token' \\\n --bridge-id local-whatsapp", + }, + php: { + method: 'bridges->retrieveCapabilities', + example: + "bridges->retrieveCapabilities(\n 'local-whatsapp'\n);\n\nvar_dump($provisioningCapabilities);", + }, + http: { + example: + 'curl http://localhost:23373/v1/bridges/$BRIDGE_ID/capabilities \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN"', + }, + }, + }, + { + name: 'list', + endpoint: '/v1/bridges/{bridgeID}/login-flows', + httpMethod: 'get', + summary: 'List login flows', + description: + 'List connect and reconnect flow options for a bridge. Use a flowID when creating a bridge login session.', + stainlessPath: '(resource) bridges.login_flows > (method) list', + qualified: 'client.bridges.loginFlows.list', + params: ['bridgeID: string;'], + response: '{ items: { id: string; description?: string; name?: string; }[]; }', + markdown: + "## list\n\n`client.bridges.loginFlows.list(bridgeID: string): { items: login_flow[]; }`\n\n**get** `/v1/bridges/{bridgeID}/login-flows`\n\nList connect and reconnect flow options for a bridge. Use a flowID when creating a bridge login session.\n\n### Parameters\n\n- `bridgeID: string`\n Bridge ID.\n\n### Returns\n\n- `{ items: { id: string; description?: string; name?: string; }[]; }`\n\n - `items: { id: string; description?: string; name?: string; }[]`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst loginFlows = await client.bridges.loginFlows.list('local-whatsapp');\n\nconsole.log(loginFlows);\n```", + perLanguage: { + typescript: { + method: 'client.bridges.loginFlows.list', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop({\n accessToken: process.env['BEEPER_ACCESS_TOKEN'], // This is the default and can be omitted\n});\n\nconst loginFlows = await client.bridges.loginFlows.list('local-whatsapp');\n\nconsole.log(loginFlows.items);", + }, + python: { + method: 'bridges.login_flows.list', + example: + 'import os\nfrom beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop(\n access_token=os.environ.get("BEEPER_ACCESS_TOKEN"), # This is the default and can be omitted\n)\nlogin_flows = client.bridges.login_flows.list(\n "local-whatsapp",\n)\nprint(login_flows.items)', + }, + go: { + method: 'client.Bridges.LoginFlows.List', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\tloginFlows, err := client.Bridges.LoginFlows.List(context.TODO(), "local-whatsapp")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", loginFlows.Items)\n}\n', + }, + cli: { + method: 'login_flows list', + example: + "beeper-desktop bridges:login-flows list \\\n --access-token 'My Access Token' \\\n --bridge-id local-whatsapp", + }, + php: { + method: 'bridges->loginFlows->list', + example: + "bridges->loginFlows->list('local-whatsapp');\n\nvar_dump($loginFlows);", + }, + http: { + example: + 'curl http://localhost:23373/v1/bridges/$BRIDGE_ID/login-flows \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN"', + }, + }, + }, + { + name: 'create', + endpoint: '/v1/bridges/{bridgeID}/login-sessions', + httpMethod: 'post', + summary: 'Create bridge login session', + description: + 'Start a temporary bridge login session to connect a new chat account or reconnect an existing bridge login. Omit loginID and accountID to connect a new account.', + stainlessPath: '(resource) bridges.login_sessions > (method) create', + qualified: 'client.bridges.loginSessions.create', + params: ['bridgeID: string;', 'accountID?: string;', 'flowID?: string;', 'loginID?: string;'], + response: + "{ bridgeID: string; loginSessionID: string; status: string; account?: object; accountID?: string; currentStep?: { fields: login_input_field[]; stepID: string; type: 'user_input'; attachments?: object[]; instructions?: string; } | { fields: cookie_field[]; stepID: string; type: 'cookies'; url: string; expectedFinalURLRegex?: string; extractJS?: string; instructions?: string; userAgent?: string; } | { display: object | object | object; stepID: string; type: 'display_and_wait'; instructions?: string; } | { type: 'complete'; account?: account; instructions?: string; login?: object; stepID?: string; }; error?: object; login?: { bridgeID: string; loginID: string; removeScopes: 'current-device' | 'all-devices'[]; status: 'connected' | 'connecting' | 'needs_login' | 'logged_out' | 'unknown'; accountIDs?: string[]; statusText?: string; user?: user; }; loginID?: string; }", + markdown: + "## create\n\n`client.bridges.loginSessions.create(bridgeID: string, accountID?: string, flowID?: string, loginID?: string): { bridgeID: string; loginSessionID: string; status: string; account?: account; accountID?: string; currentStep?: object | object | object | object; error?: api_error; login?: object; loginID?: string; }`\n\n**post** `/v1/bridges/{bridgeID}/login-sessions`\n\nStart a temporary bridge login session to connect a new chat account or reconnect an existing bridge login. Omit loginID and accountID to connect a new account.\n\n### Parameters\n\n- `bridgeID: string`\n Bridge ID.\n\n- `accountID?: string`\n Existing chat account ID to reconnect. Omit to connect a new account.\n\n- `flowID?: string`\n Optional flow ID returned by the list login flows endpoint. If omitted, Beeper chooses the default flow.\n\n- `loginID?: string`\n Existing bridge login ID to reconnect. Omit to connect a new account.\n\n### Returns\n\n- `{ bridgeID: string; loginSessionID: string; status: string; account?: { accountID: string; bridge: account_bridge; status: string; user: user; capabilities?: object; loginID?: string; network?: string; statusText?: string; }; accountID?: string; currentStep?: { fields: object[]; stepID: string; type: 'user_input'; attachments?: object[]; instructions?: string; } | { fields: object[]; stepID: string; type: 'cookies'; url: string; expectedFinalURLRegex?: string; extractJS?: string; instructions?: string; userAgent?: string; } | { display: { data: string; type: 'qr'; } | { imageURL: string; type: 'emoji'; } | { type: 'nothing'; }; stepID: string; type: 'display_and_wait'; instructions?: string; } | { type: 'complete'; account?: object; instructions?: string; login?: { bridgeID: string; loginID: string; removeScopes: 'current-device' | 'all-devices'[]; status: 'connected' | 'connecting' | 'needs_login' | 'logged_out' | 'unknown'; accountIDs?: string[]; statusText?: string; user?: user; }; stepID?: string; }; error?: { code: string; message: string; details?: object; }; login?: { bridgeID: string; loginID: string; removeScopes: 'current-device' | 'all-devices'[]; status: 'connected' | 'connecting' | 'needs_login' | 'logged_out' | 'unknown'; accountIDs?: string[]; statusText?: string; user?: object; }; loginID?: string; }`\n\n - `bridgeID: string`\n - `loginSessionID: string`\n - `status: string`\n - `account?: { accountID: string; bridge: { id: string; provider: 'cloud' | 'self-hosted' | 'local' | 'platform-sdk'; type: string; }; status: string; user: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }; capabilities?: object; loginID?: string; network?: string; statusText?: string; }`\n - `accountID?: string`\n - `currentStep?: { fields: { id: string; initialValue?: string; label?: string; optional?: boolean; placeholder?: string; type?: string; }[]; stepID: string; type: 'user_input'; attachments?: object[]; instructions?: string; } | { fields: { id: string; name?: string; type?: 'cookie' | 'header' | 'local_storage'; }[]; stepID: string; type: 'cookies'; url: string; expectedFinalURLRegex?: string; extractJS?: string; instructions?: string; userAgent?: string; } | { display: { data: string; type: 'qr'; } | { imageURL: string; type: 'emoji'; } | { type: 'nothing'; }; stepID: string; type: 'display_and_wait'; instructions?: string; } | { type: 'complete'; account?: { accountID: string; bridge: object; status: string; user: object; capabilities?: object; loginID?: string; network?: string; statusText?: string; }; instructions?: string; login?: { bridgeID: string; loginID: string; removeScopes: 'current-device' | 'all-devices'[]; status: 'connected' | 'connecting' | 'needs_login' | 'logged_out' | 'unknown'; accountIDs?: string[]; statusText?: string; user?: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }; }; stepID?: string; }`\n - `error?: { code: string; message: string; details?: object; }`\n - `login?: { bridgeID: string; loginID: string; removeScopes: 'current-device' | 'all-devices'[]; status: 'connected' | 'connecting' | 'needs_login' | 'logged_out' | 'unknown'; accountIDs?: string[]; statusText?: string; user?: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }; }`\n - `loginID?: string`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst loginSession = await client.bridges.loginSessions.create('local-whatsapp');\n\nconsole.log(loginSession);\n```", + perLanguage: { + typescript: { + method: 'client.bridges.loginSessions.create', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop({\n accessToken: process.env['BEEPER_ACCESS_TOKEN'], // This is the default and can be omitted\n});\n\nconst loginSession = await client.bridges.loginSessions.create('local-whatsapp');\n\nconsole.log(loginSession.bridgeID);", + }, + python: { + method: 'bridges.login_sessions.create', + example: + 'import os\nfrom beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop(\n access_token=os.environ.get("BEEPER_ACCESS_TOKEN"), # This is the default and can be omitted\n)\nlogin_session = client.bridges.login_sessions.create(\n bridge_id="local-whatsapp",\n)\nprint(login_session.bridge_id)', + }, + go: { + method: 'client.Bridges.LoginSessions.New', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\tloginSession, err := client.Bridges.LoginSessions.New(\n\t\tcontext.TODO(),\n\t\t"local-whatsapp",\n\t\tbeeperdesktopapi.BridgeLoginSessionNewParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", loginSession.BridgeID)\n}\n', + }, + cli: { + method: 'login_sessions create', + example: + "beeper-desktop bridges:login-sessions create \\\n --access-token 'My Access Token' \\\n --bridge-id local-whatsapp", + }, + php: { + method: 'bridges->loginSessions->create', + example: + "bridges->loginSessions->create(\n 'local-whatsapp', accountID: 'x', flowID: 'x', loginID: 'x'\n);\n\nvar_dump($loginSession);", + }, + http: { + example: + 'curl http://localhost:23373/v1/bridges/$BRIDGE_ID/login-sessions \\\n -X POST \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN"', + }, + }, + }, + { + name: 'retrieve', + endpoint: '/v1/bridges/{bridgeID}/login-sessions/{loginSessionID}', + httpMethod: 'get', + summary: 'Get bridge login session', + description: 'Get the current state of a temporary bridge login session.', + stainlessPath: '(resource) bridges.login_sessions > (method) retrieve', + qualified: 'client.bridges.loginSessions.retrieve', + params: ['bridgeID: string;', 'loginSessionID: string;'], + response: + "{ bridgeID: string; loginSessionID: string; status: string; account?: object; accountID?: string; currentStep?: { fields: login_input_field[]; stepID: string; type: 'user_input'; attachments?: object[]; instructions?: string; } | { fields: cookie_field[]; stepID: string; type: 'cookies'; url: string; expectedFinalURLRegex?: string; extractJS?: string; instructions?: string; userAgent?: string; } | { display: object | object | object; stepID: string; type: 'display_and_wait'; instructions?: string; } | { type: 'complete'; account?: account; instructions?: string; login?: object; stepID?: string; }; error?: object; login?: { bridgeID: string; loginID: string; removeScopes: 'current-device' | 'all-devices'[]; status: 'connected' | 'connecting' | 'needs_login' | 'logged_out' | 'unknown'; accountIDs?: string[]; statusText?: string; user?: user; }; loginID?: string; }", + markdown: + "## retrieve\n\n`client.bridges.loginSessions.retrieve(bridgeID: string, loginSessionID: string): { bridgeID: string; loginSessionID: string; status: string; account?: account; accountID?: string; currentStep?: object | object | object | object; error?: api_error; login?: object; loginID?: string; }`\n\n**get** `/v1/bridges/{bridgeID}/login-sessions/{loginSessionID}`\n\nGet the current state of a temporary bridge login session.\n\n### Parameters\n\n- `bridgeID: string`\n Bridge ID.\n\n- `loginSessionID: string`\n Temporary bridge login session ID.\n\n### Returns\n\n- `{ bridgeID: string; loginSessionID: string; status: string; account?: { accountID: string; bridge: account_bridge; status: string; user: user; capabilities?: object; loginID?: string; network?: string; statusText?: string; }; accountID?: string; currentStep?: { fields: object[]; stepID: string; type: 'user_input'; attachments?: object[]; instructions?: string; } | { fields: object[]; stepID: string; type: 'cookies'; url: string; expectedFinalURLRegex?: string; extractJS?: string; instructions?: string; userAgent?: string; } | { display: { data: string; type: 'qr'; } | { imageURL: string; type: 'emoji'; } | { type: 'nothing'; }; stepID: string; type: 'display_and_wait'; instructions?: string; } | { type: 'complete'; account?: object; instructions?: string; login?: { bridgeID: string; loginID: string; removeScopes: 'current-device' | 'all-devices'[]; status: 'connected' | 'connecting' | 'needs_login' | 'logged_out' | 'unknown'; accountIDs?: string[]; statusText?: string; user?: user; }; stepID?: string; }; error?: { code: string; message: string; details?: object; }; login?: { bridgeID: string; loginID: string; removeScopes: 'current-device' | 'all-devices'[]; status: 'connected' | 'connecting' | 'needs_login' | 'logged_out' | 'unknown'; accountIDs?: string[]; statusText?: string; user?: object; }; loginID?: string; }`\n\n - `bridgeID: string`\n - `loginSessionID: string`\n - `status: string`\n - `account?: { accountID: string; bridge: { id: string; provider: 'cloud' | 'self-hosted' | 'local' | 'platform-sdk'; type: string; }; status: string; user: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }; capabilities?: object; loginID?: string; network?: string; statusText?: string; }`\n - `accountID?: string`\n - `currentStep?: { fields: { id: string; initialValue?: string; label?: string; optional?: boolean; placeholder?: string; type?: string; }[]; stepID: string; type: 'user_input'; attachments?: object[]; instructions?: string; } | { fields: { id: string; name?: string; type?: 'cookie' | 'header' | 'local_storage'; }[]; stepID: string; type: 'cookies'; url: string; expectedFinalURLRegex?: string; extractJS?: string; instructions?: string; userAgent?: string; } | { display: { data: string; type: 'qr'; } | { imageURL: string; type: 'emoji'; } | { type: 'nothing'; }; stepID: string; type: 'display_and_wait'; instructions?: string; } | { type: 'complete'; account?: { accountID: string; bridge: object; status: string; user: object; capabilities?: object; loginID?: string; network?: string; statusText?: string; }; instructions?: string; login?: { bridgeID: string; loginID: string; removeScopes: 'current-device' | 'all-devices'[]; status: 'connected' | 'connecting' | 'needs_login' | 'logged_out' | 'unknown'; accountIDs?: string[]; statusText?: string; user?: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }; }; stepID?: string; }`\n - `error?: { code: string; message: string; details?: object; }`\n - `login?: { bridgeID: string; loginID: string; removeScopes: 'current-device' | 'all-devices'[]; status: 'connected' | 'connecting' | 'needs_login' | 'logged_out' | 'unknown'; accountIDs?: string[]; statusText?: string; user?: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }; }`\n - `loginID?: string`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst loginSession = await client.bridges.loginSessions.retrieve('123', { bridgeID: 'local-whatsapp' });\n\nconsole.log(loginSession);\n```", + perLanguage: { + typescript: { + method: 'client.bridges.loginSessions.retrieve', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop({\n accessToken: process.env['BEEPER_ACCESS_TOKEN'], // This is the default and can be omitted\n});\n\nconst loginSession = await client.bridges.loginSessions.retrieve('123', {\n bridgeID: 'local-whatsapp',\n});\n\nconsole.log(loginSession.bridgeID);", + }, + python: { + method: 'bridges.login_sessions.retrieve', + example: + 'import os\nfrom beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop(\n access_token=os.environ.get("BEEPER_ACCESS_TOKEN"), # This is the default and can be omitted\n)\nlogin_session = client.bridges.login_sessions.retrieve(\n login_session_id="123",\n bridge_id="local-whatsapp",\n)\nprint(login_session.bridge_id)', + }, + go: { + method: 'client.Bridges.LoginSessions.Get', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\tloginSession, err := client.Bridges.LoginSessions.Get(\n\t\tcontext.TODO(),\n\t\t"123",\n\t\tbeeperdesktopapi.BridgeLoginSessionGetParams{\n\t\t\tBridgeID: "local-whatsapp",\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", loginSession.BridgeID)\n}\n', + }, + cli: { + method: 'login_sessions retrieve', + example: + "beeper-desktop bridges:login-sessions retrieve \\\n --access-token 'My Access Token' \\\n --bridge-id local-whatsapp \\\n --login-session-id 123", + }, + php: { + method: 'bridges->loginSessions->retrieve', + example: + "bridges->loginSessions->retrieve(\n '123', bridgeID: 'local-whatsapp'\n);\n\nvar_dump($loginSession);", + }, + http: { + example: + 'curl http://localhost:23373/v1/bridges/$BRIDGE_ID/login-sessions/$LOGIN_SESSION_ID \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN"', + }, + }, + }, + { + name: 'cancel', + endpoint: '/v1/bridges/{bridgeID}/login-sessions/{loginSessionID}', + httpMethod: 'delete', + summary: 'Cancel bridge login session', + description: 'Cancel a temporary bridge login session.', + stainlessPath: '(resource) bridges.login_sessions > (method) cancel', + qualified: 'client.bridges.loginSessions.cancel', + params: ['bridgeID: string;', 'loginSessionID: string;'], + response: "{ bridgeID: string; loginSessionID: string; status: 'cancelled'; }", + markdown: + "## cancel\n\n`client.bridges.loginSessions.cancel(bridgeID: string, loginSessionID: string): { bridgeID: string; loginSessionID: string; status: 'cancelled'; }`\n\n**delete** `/v1/bridges/{bridgeID}/login-sessions/{loginSessionID}`\n\nCancel a temporary bridge login session.\n\n### Parameters\n\n- `bridgeID: string`\n Bridge ID.\n\n- `loginSessionID: string`\n Temporary bridge login session ID.\n\n### Returns\n\n- `{ bridgeID: string; loginSessionID: string; status: 'cancelled'; }`\n\n - `bridgeID: string`\n - `loginSessionID: string`\n - `status: 'cancelled'`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.bridges.loginSessions.cancel('123', { bridgeID: 'local-whatsapp' });\n\nconsole.log(response);\n```", + perLanguage: { + typescript: { + method: 'client.bridges.loginSessions.cancel', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop({\n accessToken: process.env['BEEPER_ACCESS_TOKEN'], // This is the default and can be omitted\n});\n\nconst response = await client.bridges.loginSessions.cancel('123', { bridgeID: 'local-whatsapp' });\n\nconsole.log(response.bridgeID);", + }, + python: { + method: 'bridges.login_sessions.cancel', + example: + 'import os\nfrom beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop(\n access_token=os.environ.get("BEEPER_ACCESS_TOKEN"), # This is the default and can be omitted\n)\nresponse = client.bridges.login_sessions.cancel(\n login_session_id="123",\n bridge_id="local-whatsapp",\n)\nprint(response.bridge_id)', + }, + go: { + method: 'client.Bridges.LoginSessions.Cancel', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\tresponse, err := client.Bridges.LoginSessions.Cancel(\n\t\tcontext.TODO(),\n\t\t"123",\n\t\tbeeperdesktopapi.BridgeLoginSessionCancelParams{\n\t\t\tBridgeID: "local-whatsapp",\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.BridgeID)\n}\n', + }, + cli: { + method: 'login_sessions cancel', + example: + "beeper-desktop bridges:login-sessions cancel \\\n --access-token 'My Access Token' \\\n --bridge-id local-whatsapp \\\n --login-session-id 123", + }, + php: { + method: 'bridges->loginSessions->cancel', + example: + "bridges->loginSessions->cancel(\n '123', bridgeID: 'local-whatsapp'\n);\n\nvar_dump($response);", + }, + http: { + example: + 'curl http://localhost:23373/v1/bridges/$BRIDGE_ID/login-sessions/$LOGIN_SESSION_ID \\\n -X DELETE \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN"', + }, + }, + }, + { + name: 'submit', + endpoint: '/v1/bridges/{bridgeID}/login-sessions/{loginSessionID}/steps/{stepID}', + httpMethod: 'post', + summary: 'Submit login step', + description: 'Submit input for the current step of a bridge login session.', + stainlessPath: '(resource) bridges.login_sessions.steps > (method) submit', + qualified: 'client.bridges.loginSessions.steps.submit', + params: [ + 'bridgeID: string;', + 'loginSessionID: string;', + 'stepID: string;', + "type: 'user_input' | 'cookies' | 'display_and_wait';", + 'fields?: object;', + 'lastURL?: string;', + "source?: 'api' | 'webview' | 'browser_extension';", + ], + response: + "{ bridgeID: string; loginSessionID: string; status: string; account?: object; accountID?: string; currentStep?: { fields: login_input_field[]; stepID: string; type: 'user_input'; attachments?: object[]; instructions?: string; } | { fields: cookie_field[]; stepID: string; type: 'cookies'; url: string; expectedFinalURLRegex?: string; extractJS?: string; instructions?: string; userAgent?: string; } | { display: object | object | object; stepID: string; type: 'display_and_wait'; instructions?: string; } | { type: 'complete'; account?: account; instructions?: string; login?: object; stepID?: string; }; error?: object; login?: { bridgeID: string; loginID: string; removeScopes: 'current-device' | 'all-devices'[]; status: 'connected' | 'connecting' | 'needs_login' | 'logged_out' | 'unknown'; accountIDs?: string[]; statusText?: string; user?: user; }; loginID?: string; }", + markdown: + "## submit\n\n`client.bridges.loginSessions.steps.submit(bridgeID: string, loginSessionID: string, stepID: string, type: 'user_input' | 'cookies' | 'display_and_wait', fields?: object, lastURL?: string, source?: 'api' | 'webview' | 'browser_extension'): { bridgeID: string; loginSessionID: string; status: string; account?: account; accountID?: string; currentStep?: object | object | object | object; error?: api_error; login?: object; loginID?: string; }`\n\n**post** `/v1/bridges/{bridgeID}/login-sessions/{loginSessionID}/steps/{stepID}`\n\nSubmit input for the current step of a bridge login session.\n\n### Parameters\n\n- `bridgeID: string`\n Bridge ID.\n\n- `loginSessionID: string`\n Temporary bridge login session ID.\n\n- `stepID: string`\n Current bridge login session step ID.\n\n- `type: 'user_input' | 'cookies' | 'display_and_wait'`\n\n- `fields?: object`\n Field values keyed by the field IDs from the current step.\n\n- `lastURL?: string`\n Last browser URL reached during a cookies step, if available.\n\n- `source?: 'api' | 'webview' | 'browser_extension'`\n How the step was completed. Omit unless the client needs to distinguish an embedded webview or browser extension.\n\n### Returns\n\n- `{ bridgeID: string; loginSessionID: string; status: string; account?: { accountID: string; bridge: account_bridge; status: string; user: user; capabilities?: object; loginID?: string; network?: string; statusText?: string; }; accountID?: string; currentStep?: { fields: object[]; stepID: string; type: 'user_input'; attachments?: object[]; instructions?: string; } | { fields: object[]; stepID: string; type: 'cookies'; url: string; expectedFinalURLRegex?: string; extractJS?: string; instructions?: string; userAgent?: string; } | { display: { data: string; type: 'qr'; } | { imageURL: string; type: 'emoji'; } | { type: 'nothing'; }; stepID: string; type: 'display_and_wait'; instructions?: string; } | { type: 'complete'; account?: object; instructions?: string; login?: { bridgeID: string; loginID: string; removeScopes: 'current-device' | 'all-devices'[]; status: 'connected' | 'connecting' | 'needs_login' | 'logged_out' | 'unknown'; accountIDs?: string[]; statusText?: string; user?: user; }; stepID?: string; }; error?: { code: string; message: string; details?: object; }; login?: { bridgeID: string; loginID: string; removeScopes: 'current-device' | 'all-devices'[]; status: 'connected' | 'connecting' | 'needs_login' | 'logged_out' | 'unknown'; accountIDs?: string[]; statusText?: string; user?: object; }; loginID?: string; }`\n\n - `bridgeID: string`\n - `loginSessionID: string`\n - `status: string`\n - `account?: { accountID: string; bridge: { id: string; provider: 'cloud' | 'self-hosted' | 'local' | 'platform-sdk'; type: string; }; status: string; user: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }; capabilities?: object; loginID?: string; network?: string; statusText?: string; }`\n - `accountID?: string`\n - `currentStep?: { fields: { id: string; initialValue?: string; label?: string; optional?: boolean; placeholder?: string; type?: string; }[]; stepID: string; type: 'user_input'; attachments?: object[]; instructions?: string; } | { fields: { id: string; name?: string; type?: 'cookie' | 'header' | 'local_storage'; }[]; stepID: string; type: 'cookies'; url: string; expectedFinalURLRegex?: string; extractJS?: string; instructions?: string; userAgent?: string; } | { display: { data: string; type: 'qr'; } | { imageURL: string; type: 'emoji'; } | { type: 'nothing'; }; stepID: string; type: 'display_and_wait'; instructions?: string; } | { type: 'complete'; account?: { accountID: string; bridge: object; status: string; user: object; capabilities?: object; loginID?: string; network?: string; statusText?: string; }; instructions?: string; login?: { bridgeID: string; loginID: string; removeScopes: 'current-device' | 'all-devices'[]; status: 'connected' | 'connecting' | 'needs_login' | 'logged_out' | 'unknown'; accountIDs?: string[]; statusText?: string; user?: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }; }; stepID?: string; }`\n - `error?: { code: string; message: string; details?: object; }`\n - `login?: { bridgeID: string; loginID: string; removeScopes: 'current-device' | 'all-devices'[]; status: 'connected' | 'connecting' | 'needs_login' | 'logged_out' | 'unknown'; accountIDs?: string[]; statusText?: string; user?: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }; }`\n - `loginID?: string`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst loginSession = await client.bridges.loginSessions.steps.submit('x', {\n bridgeID: 'local-whatsapp',\n loginSessionID: '123',\n type: 'user_input',\n});\n\nconsole.log(loginSession);\n```", + perLanguage: { + typescript: { + method: 'client.bridges.loginSessions.steps.submit', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop({\n accessToken: process.env['BEEPER_ACCESS_TOKEN'], // This is the default and can be omitted\n});\n\nconst loginSession = await client.bridges.loginSessions.steps.submit('x', {\n bridgeID: 'local-whatsapp',\n loginSessionID: '123',\n type: 'user_input',\n});\n\nconsole.log(loginSession.bridgeID);", + }, + python: { + method: 'bridges.login_sessions.steps.submit', + example: + 'import os\nfrom beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop(\n access_token=os.environ.get("BEEPER_ACCESS_TOKEN"), # This is the default and can be omitted\n)\nlogin_session = client.bridges.login_sessions.steps.submit(\n step_id="x",\n bridge_id="local-whatsapp",\n login_session_id="123",\n type="user_input",\n)\nprint(login_session.bridge_id)', + }, + go: { + method: 'client.Bridges.LoginSessions.Steps.Submit', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\tloginSession, err := client.Bridges.LoginSessions.Steps.Submit(\n\t\tcontext.TODO(),\n\t\t"x",\n\t\tbeeperdesktopapi.BridgeLoginSessionStepSubmitParams{\n\t\t\tBridgeID: "local-whatsapp",\n\t\t\tLoginSessionID: "123",\n\t\t\tType: beeperdesktopapi.BridgeLoginSessionStepSubmitParamsTypeUserInput,\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", loginSession.BridgeID)\n}\n', + }, + cli: { + method: 'steps submit', + example: + "beeper-desktop bridges:login-sessions:steps submit \\\n --access-token 'My Access Token' \\\n --bridge-id local-whatsapp \\\n --login-session-id 123 \\\n --step-id x \\\n --type user_input", + }, + php: { + method: 'bridges->loginSessions->steps->submit', + example: + "bridges->loginSessions->steps->submit(\n 'x',\n bridgeID: 'local-whatsapp',\n loginSessionID: '123',\n type: 'user_input',\n fields: ['foo' => 'string'],\n lastURL: 'lastURL',\n source: 'api',\n);\n\nvar_dump($loginSession);", + }, + http: { + example: + 'curl http://localhost:23373/v1/bridges/$BRIDGE_ID/login-sessions/$LOGIN_SESSION_ID/steps/$STEP_ID \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN" \\\n -d \'{\n "type": "user_input"\n }\'', + }, + }, + }, { name: 'retrieve', endpoint: '/v1/chats/{chatID}', httpMethod: 'get', summary: 'Retrieve chat details', - description: 'Retrieve chat details including metadata, participants, and latest message', + description: 'Retrieve chat details, including metadata, participants, and the latest message.', stainlessPath: '(resource) chats > (method) retrieve', qualified: 'client.chats.retrieve', params: ['chatID: string;', 'maxParticipantCount?: number;'], response: "{ id: string; accountID: string; network: string; participants: object; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: object; description?: string; draft?: object; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: object; snooze?: object; unreadMentionsCount?: number; }", markdown: - "## retrieve\n\n`client.chats.retrieve(chatID: string, maxParticipantCount?: number): { id: string; accountID: string; network: string; participants: object; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: object; description?: string; draft?: object; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: object; snooze?: object; unreadMentionsCount?: number; }`\n\n**get** `/v1/chats/{chatID}`\n\nRetrieve chat details including metadata, participants, and latest message\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.\n\n- `maxParticipantCount?: number`\n Maximum number of participants to return. Use -1 for all; otherwise 0-500. Defaults to 100. List and search endpoints return up to 20 participants per chat.\n\n### Returns\n\n- `{ id: string; accountID: string; network: string; participants: { hasMore: boolean; items: object[]; total: number; }; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: object; description?: object; disappearingTimer?: object; title?: object; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }; description?: string; draft?: { text: string; attachments?: object; }; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }; snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }; unreadMentionsCount?: number; }`\n\n - `id: string`\n - `accountID: string`\n - `network: string`\n - `participants: { hasMore: boolean; items: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }[]; total: number; }`\n - `title: string`\n - `type: 'single' | 'group'`\n - `unreadCount: number`\n - `capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: { level: -2 | -1 | 0 | 1 | 2; }; description?: { level: -2 | -1 | 0 | 1 | 2; }; disappearingTimer?: { level: -2 | -1 | 0 | 1 | 2; }; title?: { level: -2 | -1 | 0 | 1 | 2; }; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }`\n - `description?: string`\n - `draft?: { text: string; attachments?: object; }`\n - `imgURL?: string`\n - `isArchived?: boolean`\n - `isLowPriority?: boolean`\n - `isMarkedUnread?: boolean`\n - `isMuted?: boolean`\n - `isPinned?: boolean`\n - `isReadOnly?: boolean`\n - `lastActivity?: string`\n - `lastReadMessageSortKey?: string`\n - `localChatID?: string`\n - `messageExpirySeconds?: number`\n - `reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }`\n - `snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }`\n - `unreadMentionsCount?: number`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst chat = await client.chats.retrieve('!NCdzlIaMjZUmvmvyHU:beeper.com');\n\nconsole.log(chat);\n```", + "## retrieve\n\n`client.chats.retrieve(chatID: string, maxParticipantCount?: number): { id: string; accountID: string; network: string; participants: object; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: object; description?: string; draft?: object; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: object; snooze?: object; unreadMentionsCount?: number; }`\n\n**get** `/v1/chats/{chatID}`\n\nRetrieve chat details, including metadata, participants, and the latest message.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this installation when available.\n\n- `maxParticipantCount?: number`\n Maximum number of participants to return. Use -1 for all; otherwise 0-500. Defaults to 100. List and search endpoints return up to 20 participants per chat.\n\n### Returns\n\n- `{ id: string; accountID: string; network: string; participants: { hasMore: boolean; items: object[]; total: number; }; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: object; description?: object; disappearingTimer?: object; title?: object; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }; description?: string; draft?: { text: string; attachments?: object; }; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }; snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }; unreadMentionsCount?: number; }`\n\n - `id: string`\n - `accountID: string`\n - `network: string`\n - `participants: { hasMore: boolean; items: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }[]; total: number; }`\n - `title: string`\n - `type: 'single' | 'group'`\n - `unreadCount: number`\n - `capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: { level: -2 | -1 | 0 | 1 | 2; }; description?: { level: -2 | -1 | 0 | 1 | 2; }; disappearingTimer?: { level: -2 | -1 | 0 | 1 | 2; }; title?: { level: -2 | -1 | 0 | 1 | 2; }; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }`\n - `description?: string`\n - `draft?: { text: string; attachments?: object; }`\n - `imgURL?: string`\n - `isArchived?: boolean`\n - `isLowPriority?: boolean`\n - `isMarkedUnread?: boolean`\n - `isMuted?: boolean`\n - `isPinned?: boolean`\n - `isReadOnly?: boolean`\n - `lastActivity?: string`\n - `lastReadMessageSortKey?: string`\n - `localChatID?: string`\n - `messageExpirySeconds?: number`\n - `reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }`\n - `snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }`\n - `unreadMentionsCount?: number`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst chat = await client.chats.retrieve('!NCdzlIaMjZUmvmvyHU:beeper.com');\n\nconsole.log(chat);\n```", perLanguage: { typescript: { method: 'client.chats.retrieve', @@ -317,7 +730,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ cli: { method: 'chats retrieve', example: - "beeper-desktop-cli chats retrieve \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com'", + "beeper-desktop chats retrieve \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com'", }, php: { method: 'chats->retrieve', @@ -368,7 +781,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ cli: { method: 'chats create', example: - "beeper-desktop-cli chats create \\\n --access-token 'My Access Token' \\\n --account-id accountID \\\n --participant-id string \\\n --type single", + "beeper-desktop chats create \\\n --access-token 'My Access Token' \\\n --account-id accountID \\\n --participant-id string \\\n --type single", }, php: { method: 'chats->create', @@ -387,7 +800,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ httpMethod: 'post', summary: 'Start a direct chat', description: - 'Resolve a user/contact and open a direct chat. Reuses and returns an existing direct chat when one is found. Available in Beeper Desktop v4.2.808+.', + 'Resolve a user/contact and open a direct chat. Reuses and returns an existing direct chat when one is found. Available in Beeper v4.2.808+.', stainlessPath: '(resource) chats > (method) start', qualified: 'client.chats.start', params: [ @@ -399,7 +812,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: "{ id: string; accountID: string; network: string; participants: object; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: object; description?: string; draft?: object; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: object; snooze?: object; unreadMentionsCount?: number; }", markdown: - "## start\n\n`client.chats.start(accountID: string, user: { id?: string; email?: string; fullName?: string; phoneNumber?: string; username?: string; }, allowInvite?: boolean, messageText?: string): object`\n\n**post** `/v1/chats/start`\n\nResolve a user/contact and open a direct chat. Reuses and returns an existing direct chat when one is found. Available in Beeper Desktop v4.2.808+.\n\n### Parameters\n\n- `accountID: string`\n Account to create or start the chat on.\n\n- `user: { id?: string; email?: string; fullName?: string; phoneNumber?: string; username?: string; }`\n Merged user-like contact payload used to resolve the best identifier.\n - `id?: string`\n Known user ID when available.\n - `email?: string`\n Email candidate.\n - `fullName?: string`\n Display name hint used for ranking only.\n - `phoneNumber?: string`\n Phone number candidate (E.164 preferred).\n - `username?: string`\n Username/handle candidate.\n\n- `allowInvite?: boolean`\n Whether invite-based DM creation is allowed when required by the platform.\n\n- `messageText?: string`\n Optional first message content if the platform requires it to create the chat.\n\n### Returns\n\n- `{ id: string; accountID: string; network: string; participants: { hasMore: boolean; items: user[]; total: number; }; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: object; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: object; participantActions?: object; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: object; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }; description?: string; draft?: { text: string; attachments?: object; }; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }; snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }; unreadMentionsCount?: number; }`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.chats.start({\n accountID: 'accountID',\n user: {},\n});\n\nconsole.log(response);\n```", + "## start\n\n`client.chats.start(accountID: string, user: { id?: string; email?: string; fullName?: string; phoneNumber?: string; username?: string; }, allowInvite?: boolean, messageText?: string): object`\n\n**post** `/v1/chats/start`\n\nResolve a user/contact and open a direct chat. Reuses and returns an existing direct chat when one is found. Available in Beeper v4.2.808+.\n\n### Parameters\n\n- `accountID: string`\n Account to create or start the chat on.\n\n- `user: { id?: string; email?: string; fullName?: string; phoneNumber?: string; username?: string; }`\n Contact-like user payload used to resolve the best identifier.\n - `id?: string`\n Known user ID when available.\n - `email?: string`\n Email candidate.\n - `fullName?: string`\n Display name hint used for ranking only.\n - `phoneNumber?: string`\n Phone number candidate (E.164 preferred).\n - `username?: string`\n Username/handle candidate.\n\n- `allowInvite?: boolean`\n Whether invite-based DM creation is allowed when required by the platform.\n\n- `messageText?: string`\n Optional first message content if the platform requires it to create the chat.\n\n### Returns\n\n- `{ id: string; accountID: string; network: string; participants: { hasMore: boolean; items: user[]; total: number; }; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: object; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: object; participantActions?: object; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: object; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }; description?: string; draft?: { text: string; attachments?: object; }; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }; snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }; unreadMentionsCount?: number; }`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.chats.start({\n accountID: 'accountID',\n user: {},\n});\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.chats.start', @@ -419,7 +832,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ cli: { method: 'chats start', example: - "beeper-desktop-cli chats start \\\n --access-token 'My Access Token' \\\n --account-id accountID \\\n --user '{}'", + "beeper-desktop chats start \\\n --access-token 'My Access Token' \\\n --account-id accountID \\\n --user '{}'", }, php: { method: 'chats->start', @@ -464,7 +877,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ }, cli: { method: 'chats list', - example: "beeper-desktop-cli chats list \\\n --access-token 'My Access Token'", + example: "beeper-desktop chats list \\\n --access-token 'My Access Token'", }, php: { method: 'chats->list', @@ -502,7 +915,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: "{ id: string; accountID: string; network: string; participants: object; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: object; description?: string; draft?: object; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: object; snooze?: object; unreadMentionsCount?: number; }", markdown: - "## search\n\n`client.chats.search(accountIDs?: string[], cursor?: string, direction?: 'after' | 'before', inbox?: 'primary' | 'low-priority' | 'archive', includeMuted?: boolean, lastActivityAfter?: string, lastActivityBefore?: string, limit?: number, query?: string, scope?: 'titles' | 'participants', type?: 'single' | 'group' | 'any', unreadOnly?: boolean): { id: string; accountID: string; network: string; participants: object; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: object; description?: string; draft?: object; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: object; snooze?: object; unreadMentionsCount?: number; }`\n\n**get** `/v1/chats/search`\n\nSearch chats by title, network, or participant names.\n\n### Parameters\n\n- `accountIDs?: string[]`\n Provide an array of account IDs to filter chats from specific messaging accounts only\n\n- `cursor?: string`\n Opaque pagination cursor; do not inspect. Use together with 'direction'.\n\n- `direction?: 'after' | 'before'`\n Pagination direction used with 'cursor': 'before' fetches older results, 'after' fetches newer results. Defaults to 'before' when only 'cursor' is provided.\n\n- `inbox?: 'primary' | 'low-priority' | 'archive'`\n Filter by inbox type: \"primary\" (non-archived, non-low-priority), \"low-priority\", or \"archive\". If not specified, shows all chats.\n\n- `includeMuted?: boolean`\n Include chats marked as Muted by the user, which are usually less important. Default: true. Set to false if the user wants a more refined search.\n\n- `lastActivityAfter?: string`\n Provide an ISO datetime string to only retrieve chats with last activity after this time\n\n- `lastActivityBefore?: string`\n Provide an ISO datetime string to only retrieve chats with last activity before this time\n\n- `limit?: number`\n Set the maximum number of chats to retrieve. Valid range: 1-200, default is 50\n\n- `query?: string`\n Literal token search (non-semantic). Use single words users type (e.g., \"dinner\"). When multiple words provided, ALL must match. Case-insensitive.\n\n- `scope?: 'titles' | 'participants'`\n Search scope: 'titles' matches title + network; 'participants' matches participant names.\n\n- `type?: 'single' | 'group' | 'any'`\n Specify the type of chats to retrieve: use \"single\" for direct messages, \"group\" for group chats, or \"any\" to get all types\n\n- `unreadOnly?: boolean`\n Set to true to only retrieve chats that have unread messages\n\n### Returns\n\n- `{ id: string; accountID: string; network: string; participants: { hasMore: boolean; items: object[]; total: number; }; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: object; description?: object; disappearingTimer?: object; title?: object; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }; description?: string; draft?: { text: string; attachments?: object; }; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }; snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }; unreadMentionsCount?: number; }`\n\n - `id: string`\n - `accountID: string`\n - `network: string`\n - `participants: { hasMore: boolean; items: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }[]; total: number; }`\n - `title: string`\n - `type: 'single' | 'group'`\n - `unreadCount: number`\n - `capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: { level: -2 | -1 | 0 | 1 | 2; }; description?: { level: -2 | -1 | 0 | 1 | 2; }; disappearingTimer?: { level: -2 | -1 | 0 | 1 | 2; }; title?: { level: -2 | -1 | 0 | 1 | 2; }; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }`\n - `description?: string`\n - `draft?: { text: string; attachments?: object; }`\n - `imgURL?: string`\n - `isArchived?: boolean`\n - `isLowPriority?: boolean`\n - `isMarkedUnread?: boolean`\n - `isMuted?: boolean`\n - `isPinned?: boolean`\n - `isReadOnly?: boolean`\n - `lastActivity?: string`\n - `lastReadMessageSortKey?: string`\n - `localChatID?: string`\n - `messageExpirySeconds?: number`\n - `reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }`\n - `snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }`\n - `unreadMentionsCount?: number`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\n// Automatically fetches more pages as needed.\nfor await (const chat of client.chats.search()) {\n console.log(chat);\n}\n```", + "## search\n\n`client.chats.search(accountIDs?: string[], cursor?: string, direction?: 'after' | 'before', inbox?: 'primary' | 'low-priority' | 'archive', includeMuted?: boolean, lastActivityAfter?: string, lastActivityBefore?: string, limit?: number, query?: string, scope?: 'titles' | 'participants', type?: 'single' | 'group' | 'any', unreadOnly?: boolean): { id: string; accountID: string; network: string; participants: object; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: object; description?: string; draft?: object; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: object; snooze?: object; unreadMentionsCount?: number; }`\n\n**get** `/v1/chats/search`\n\nSearch chats by title, network, or participant names.\n\n### Parameters\n\n- `accountIDs?: string[]`\n Limit results to specific chat accounts.\n\n- `cursor?: string`\n Opaque pagination cursor; do not inspect. Use together with 'direction'.\n\n- `direction?: 'after' | 'before'`\n Pagination direction used with 'cursor': 'before' fetches older results, 'after' fetches newer results. Defaults to 'before' when only 'cursor' is provided.\n\n- `inbox?: 'primary' | 'low-priority' | 'archive'`\n Filter by inbox type: \"primary\" (non-archived, non-low-priority), \"low-priority\", or \"archive\". If not specified, shows all chats.\n\n- `includeMuted?: boolean`\n Include chats marked as Muted by the user, which are usually less important. Default: true. Set to false if the user wants a more refined search.\n\n- `lastActivityAfter?: string`\n Only include chats with last activity after this ISO 8601 datetime.\n\n- `lastActivityBefore?: string`\n Only include chats with last activity before this ISO 8601 datetime.\n\n- `limit?: number`\n Set the maximum number of chats to retrieve. Valid range: 1-200, default is 50\n\n- `query?: string`\n Literal chat search. Use words the user typed, such as \"dinner\". When multiple words are provided, all must match. Case-insensitive.\n\n- `scope?: 'titles' | 'participants'`\n Search scope: 'titles' matches title + network; 'participants' matches participant names.\n\n- `type?: 'single' | 'group' | 'any'`\n Specify the type of chats to retrieve: use \"single\" for direct messages, \"group\" for group chats, or \"any\" to get all types\n\n- `unreadOnly?: boolean`\n Set to true to only retrieve chats that have unread messages\n\n### Returns\n\n- `{ id: string; accountID: string; network: string; participants: { hasMore: boolean; items: object[]; total: number; }; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: object; description?: object; disappearingTimer?: object; title?: object; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }; description?: string; draft?: { text: string; attachments?: object; }; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }; snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }; unreadMentionsCount?: number; }`\n\n - `id: string`\n - `accountID: string`\n - `network: string`\n - `participants: { hasMore: boolean; items: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }[]; total: number; }`\n - `title: string`\n - `type: 'single' | 'group'`\n - `unreadCount: number`\n - `capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: { level: -2 | -1 | 0 | 1 | 2; }; description?: { level: -2 | -1 | 0 | 1 | 2; }; disappearingTimer?: { level: -2 | -1 | 0 | 1 | 2; }; title?: { level: -2 | -1 | 0 | 1 | 2; }; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }`\n - `description?: string`\n - `draft?: { text: string; attachments?: object; }`\n - `imgURL?: string`\n - `isArchived?: boolean`\n - `isLowPriority?: boolean`\n - `isMarkedUnread?: boolean`\n - `isMuted?: boolean`\n - `isPinned?: boolean`\n - `isReadOnly?: boolean`\n - `lastActivity?: string`\n - `lastReadMessageSortKey?: string`\n - `localChatID?: string`\n - `messageExpirySeconds?: number`\n - `reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }`\n - `snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }`\n - `unreadMentionsCount?: number`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\n// Automatically fetches more pages as needed.\nfor await (const chat of client.chats.search()) {\n console.log(chat);\n}\n```", perLanguage: { typescript: { method: 'client.chats.search', @@ -521,7 +934,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ }, cli: { method: 'chats search', - example: "beeper-desktop-cli chats search \\\n --access-token 'My Access Token'", + example: "beeper-desktop chats search \\\n --access-token 'My Access Token'", }, php: { method: 'chats->search', @@ -540,12 +953,12 @@ const EMBEDDED_METHODS: MethodEntry[] = [ httpMethod: 'post', summary: 'Archive or unarchive a chat', description: - 'Archive or unarchive a chat. Set archived=true to move to archive, archived=false to move back to inbox', + 'Archive or unarchive a chat. Set archived=true to move it to Archive, or archived=false to move it back to the inbox.', stainlessPath: '(resource) chats > (method) archive', qualified: 'client.chats.archive', params: ['chatID: string;', 'archived?: boolean;'], markdown: - "## archive\n\n`client.chats.archive(chatID: string, archived?: boolean): void`\n\n**post** `/v1/chats/{chatID}/archive`\n\nArchive or unarchive a chat. Set archived=true to move to archive, archived=false to move back to inbox\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.\n\n- `archived?: boolean`\n True to archive, false to unarchive\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nawait client.chats.archive('!NCdzlIaMjZUmvmvyHU:beeper.com')\n```", + "## archive\n\n`client.chats.archive(chatID: string, archived?: boolean): void`\n\n**post** `/v1/chats/{chatID}/archive`\n\nArchive or unarchive a chat. Set archived=true to move it to Archive, or archived=false to move it back to the inbox.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this installation when available.\n\n- `archived?: boolean`\n True to archive, false to unarchive\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nawait client.chats.archive('!NCdzlIaMjZUmvmvyHU:beeper.com')\n```", perLanguage: { typescript: { method: 'client.chats.archive', @@ -565,7 +978,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ cli: { method: 'chats archive', example: - "beeper-desktop-cli chats archive \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com'", + "beeper-desktop chats archive \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com'", }, php: { method: 'chats->archive', @@ -584,7 +997,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ httpMethod: 'patch', summary: 'Update chat', description: - 'Update supported chat fields. Non-empty draft objects are accepted only when the current draft is empty. Send draft=null to clear the draft before setting new draft text or attachments.', + 'Update supported chat fields. Non-empty drafts are accepted only when the current draft is empty. Send draft=null to clear the draft before setting new draft text or attachments.', stainlessPath: '(resource) chats > (method) update', qualified: 'client.chats.update', params: [ @@ -602,7 +1015,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: "{ id: string; accountID: string; network: string; participants: object; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: object; description?: string; draft?: object; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: object; snooze?: object; unreadMentionsCount?: number; }", markdown: - "## update\n\n`client.chats.update(chatID: string, description?: string, draft?: { text: string; attachments?: object; }, imgURL?: string, isArchived?: boolean, isLowPriority?: boolean, isMuted?: boolean, isPinned?: boolean, messageExpirySeconds?: number, title?: string): { id: string; accountID: string; network: string; participants: object; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: object; description?: string; draft?: object; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: object; snooze?: object; unreadMentionsCount?: number; }`\n\n**patch** `/v1/chats/{chatID}`\n\nUpdate supported chat fields. Non-empty draft objects are accepted only when the current draft is empty. Send draft=null to clear the draft before setting new draft text or attachments.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.\n\n- `description?: string`\n Group chat description/topic. Support depends on the chat account and chat permissions.\n\n- `draft?: { text: string; attachments?: object; }`\n Draft object to set or clear. Non-empty drafts are only accepted when the current draft is empty. Send draft=null to clear text and attachments together before setting a new draft.\n - `text: string`\n Draft text. Plain text and Markdown are converted to Matrix HTML with the same rules used by send and edit.\n - `attachments?: object`\n Draft attachments keyed by attachment ID. Each attachment must reference an uploadID returned by the upload file endpoint.\n\n- `imgURL?: string`\n Local filesystem path to a group chat avatar image. Support depends on the chat account and chat permissions.\n\n- `isArchived?: boolean`\n Archive or unarchive the chat.\n\n- `isLowPriority?: boolean`\n Mark or unmark the chat as low priority when supported by the account.\n\n- `isMuted?: boolean`\n Mute or unmute the chat.\n\n- `isPinned?: boolean`\n Pin or unpin the chat when supported by the account.\n\n- `messageExpirySeconds?: number`\n Disappearing-message timer in seconds, or null to clear when supported.\n\n- `title?: string`\n Custom chat title. Support depends on the chat account and chat permissions.\n\n### Returns\n\n- `{ id: string; accountID: string; network: string; participants: { hasMore: boolean; items: object[]; total: number; }; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: object; description?: object; disappearingTimer?: object; title?: object; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }; description?: string; draft?: { text: string; attachments?: object; }; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }; snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }; unreadMentionsCount?: number; }`\n\n - `id: string`\n - `accountID: string`\n - `network: string`\n - `participants: { hasMore: boolean; items: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }[]; total: number; }`\n - `title: string`\n - `type: 'single' | 'group'`\n - `unreadCount: number`\n - `capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: { level: -2 | -1 | 0 | 1 | 2; }; description?: { level: -2 | -1 | 0 | 1 | 2; }; disappearingTimer?: { level: -2 | -1 | 0 | 1 | 2; }; title?: { level: -2 | -1 | 0 | 1 | 2; }; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }`\n - `description?: string`\n - `draft?: { text: string; attachments?: object; }`\n - `imgURL?: string`\n - `isArchived?: boolean`\n - `isLowPriority?: boolean`\n - `isMarkedUnread?: boolean`\n - `isMuted?: boolean`\n - `isPinned?: boolean`\n - `isReadOnly?: boolean`\n - `lastActivity?: string`\n - `lastReadMessageSortKey?: string`\n - `localChatID?: string`\n - `messageExpirySeconds?: number`\n - `reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }`\n - `snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }`\n - `unreadMentionsCount?: number`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst chat = await client.chats.update('!NCdzlIaMjZUmvmvyHU:beeper.com');\n\nconsole.log(chat);\n```", + "## update\n\n`client.chats.update(chatID: string, description?: string, draft?: { text: string; attachments?: object; }, imgURL?: string, isArchived?: boolean, isLowPriority?: boolean, isMuted?: boolean, isPinned?: boolean, messageExpirySeconds?: number, title?: string): { id: string; accountID: string; network: string; participants: object; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: object; description?: string; draft?: object; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: object; snooze?: object; unreadMentionsCount?: number; }`\n\n**patch** `/v1/chats/{chatID}`\n\nUpdate supported chat fields. Non-empty drafts are accepted only when the current draft is empty. Send draft=null to clear the draft before setting new draft text or attachments.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this installation when available.\n\n- `description?: string`\n Group chat description/topic. Support depends on the chat account and chat permissions.\n\n- `draft?: { text: string; attachments?: object; }`\n Draft object to set or clear. Non-empty drafts are only accepted when the current draft is empty. Send draft=null to clear text and attachments together before setting a new draft.\n - `text: string`\n Draft text. Plain text and Markdown are converted to Beeper rich text with the same rules used by send and edit.\n - `attachments?: object`\n Draft attachments keyed by attachment ID. Each attachment must reference an uploadID returned by the upload file endpoint.\n\n- `imgURL?: string`\n Local filesystem path to a group chat avatar image. Support depends on the chat account and chat permissions.\n\n- `isArchived?: boolean`\n Archive or unarchive the chat.\n\n- `isLowPriority?: boolean`\n Mark or unmark the chat as low priority when supported by the account.\n\n- `isMuted?: boolean`\n Mute or unmute the chat.\n\n- `isPinned?: boolean`\n Pin or unpin the chat when supported by the account.\n\n- `messageExpirySeconds?: number`\n Disappearing-message timer in seconds, or null to clear when supported.\n\n- `title?: string`\n Custom chat title. Support depends on the chat account and chat permissions.\n\n### Returns\n\n- `{ id: string; accountID: string; network: string; participants: { hasMore: boolean; items: object[]; total: number; }; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: object; description?: object; disappearingTimer?: object; title?: object; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }; description?: string; draft?: { text: string; attachments?: object; }; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }; snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }; unreadMentionsCount?: number; }`\n\n - `id: string`\n - `accountID: string`\n - `network: string`\n - `participants: { hasMore: boolean; items: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }[]; total: number; }`\n - `title: string`\n - `type: 'single' | 'group'`\n - `unreadCount: number`\n - `capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: { level: -2 | -1 | 0 | 1 | 2; }; description?: { level: -2 | -1 | 0 | 1 | 2; }; disappearingTimer?: { level: -2 | -1 | 0 | 1 | 2; }; title?: { level: -2 | -1 | 0 | 1 | 2; }; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }`\n - `description?: string`\n - `draft?: { text: string; attachments?: object; }`\n - `imgURL?: string`\n - `isArchived?: boolean`\n - `isLowPriority?: boolean`\n - `isMarkedUnread?: boolean`\n - `isMuted?: boolean`\n - `isPinned?: boolean`\n - `isReadOnly?: boolean`\n - `lastActivity?: string`\n - `lastReadMessageSortKey?: string`\n - `localChatID?: string`\n - `messageExpirySeconds?: number`\n - `reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }`\n - `snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }`\n - `unreadMentionsCount?: number`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst chat = await client.chats.update('!NCdzlIaMjZUmvmvyHU:beeper.com');\n\nconsole.log(chat);\n```", perLanguage: { typescript: { method: 'client.chats.update', @@ -622,7 +1035,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ cli: { method: 'chats update', example: - "beeper-desktop-cli chats update \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com'", + "beeper-desktop chats update \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com'", }, php: { method: 'chats->update', @@ -647,7 +1060,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: "{ id: string; accountID: string; network: string; participants: object; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: object; description?: string; draft?: object; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: object; snooze?: object; unreadMentionsCount?: number; }", markdown: - "## mark_read\n\n`client.chats.markRead(chatID: string, messageID?: string): { id: string; accountID: string; network: string; participants: object; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: object; description?: string; draft?: object; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: object; snooze?: object; unreadMentionsCount?: number; }`\n\n**post** `/v1/chats/{chatID}/read`\n\nMark a chat as read, optionally through a specific message ID.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.\n\n- `messageID?: string`\n Optional message ID to mark read through.\n\n### Returns\n\n- `{ id: string; accountID: string; network: string; participants: { hasMore: boolean; items: object[]; total: number; }; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: object; description?: object; disappearingTimer?: object; title?: object; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }; description?: string; draft?: { text: string; attachments?: object; }; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }; snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }; unreadMentionsCount?: number; }`\n\n - `id: string`\n - `accountID: string`\n - `network: string`\n - `participants: { hasMore: boolean; items: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }[]; total: number; }`\n - `title: string`\n - `type: 'single' | 'group'`\n - `unreadCount: number`\n - `capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: { level: -2 | -1 | 0 | 1 | 2; }; description?: { level: -2 | -1 | 0 | 1 | 2; }; disappearingTimer?: { level: -2 | -1 | 0 | 1 | 2; }; title?: { level: -2 | -1 | 0 | 1 | 2; }; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }`\n - `description?: string`\n - `draft?: { text: string; attachments?: object; }`\n - `imgURL?: string`\n - `isArchived?: boolean`\n - `isLowPriority?: boolean`\n - `isMarkedUnread?: boolean`\n - `isMuted?: boolean`\n - `isPinned?: boolean`\n - `isReadOnly?: boolean`\n - `lastActivity?: string`\n - `lastReadMessageSortKey?: string`\n - `localChatID?: string`\n - `messageExpirySeconds?: number`\n - `reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }`\n - `snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }`\n - `unreadMentionsCount?: number`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst chat = await client.chats.markRead('!NCdzlIaMjZUmvmvyHU:beeper.com');\n\nconsole.log(chat);\n```", + "## mark_read\n\n`client.chats.markRead(chatID: string, messageID?: string): { id: string; accountID: string; network: string; participants: object; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: object; description?: string; draft?: object; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: object; snooze?: object; unreadMentionsCount?: number; }`\n\n**post** `/v1/chats/{chatID}/read`\n\nMark a chat as read, optionally through a specific message ID.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this installation when available.\n\n- `messageID?: string`\n Optional message ID to mark read through.\n\n### Returns\n\n- `{ id: string; accountID: string; network: string; participants: { hasMore: boolean; items: object[]; total: number; }; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: object; description?: object; disappearingTimer?: object; title?: object; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }; description?: string; draft?: { text: string; attachments?: object; }; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }; snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }; unreadMentionsCount?: number; }`\n\n - `id: string`\n - `accountID: string`\n - `network: string`\n - `participants: { hasMore: boolean; items: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }[]; total: number; }`\n - `title: string`\n - `type: 'single' | 'group'`\n - `unreadCount: number`\n - `capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: { level: -2 | -1 | 0 | 1 | 2; }; description?: { level: -2 | -1 | 0 | 1 | 2; }; disappearingTimer?: { level: -2 | -1 | 0 | 1 | 2; }; title?: { level: -2 | -1 | 0 | 1 | 2; }; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }`\n - `description?: string`\n - `draft?: { text: string; attachments?: object; }`\n - `imgURL?: string`\n - `isArchived?: boolean`\n - `isLowPriority?: boolean`\n - `isMarkedUnread?: boolean`\n - `isMuted?: boolean`\n - `isPinned?: boolean`\n - `isReadOnly?: boolean`\n - `lastActivity?: string`\n - `lastReadMessageSortKey?: string`\n - `localChatID?: string`\n - `messageExpirySeconds?: number`\n - `reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }`\n - `snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }`\n - `unreadMentionsCount?: number`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst chat = await client.chats.markRead('!NCdzlIaMjZUmvmvyHU:beeper.com');\n\nconsole.log(chat);\n```", perLanguage: { typescript: { method: 'client.chats.markRead', @@ -667,7 +1080,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ cli: { method: 'chats mark_read', example: - "beeper-desktop-cli chats mark-read \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com'", + "beeper-desktop chats mark-read \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com'", }, php: { method: 'chats->markRead', @@ -692,7 +1105,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: "{ id: string; accountID: string; network: string; participants: object; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: object; description?: string; draft?: object; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: object; snooze?: object; unreadMentionsCount?: number; }", markdown: - "## mark_unread\n\n`client.chats.markUnread(chatID: string, messageID?: string): { id: string; accountID: string; network: string; participants: object; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: object; description?: string; draft?: object; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: object; snooze?: object; unreadMentionsCount?: number; }`\n\n**post** `/v1/chats/{chatID}/unread`\n\nMark a chat as unread, optionally from a specific message ID.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.\n\n- `messageID?: string`\n Optional message ID to mark unread from.\n\n### Returns\n\n- `{ id: string; accountID: string; network: string; participants: { hasMore: boolean; items: object[]; total: number; }; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: object; description?: object; disappearingTimer?: object; title?: object; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }; description?: string; draft?: { text: string; attachments?: object; }; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }; snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }; unreadMentionsCount?: number; }`\n\n - `id: string`\n - `accountID: string`\n - `network: string`\n - `participants: { hasMore: boolean; items: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }[]; total: number; }`\n - `title: string`\n - `type: 'single' | 'group'`\n - `unreadCount: number`\n - `capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: { level: -2 | -1 | 0 | 1 | 2; }; description?: { level: -2 | -1 | 0 | 1 | 2; }; disappearingTimer?: { level: -2 | -1 | 0 | 1 | 2; }; title?: { level: -2 | -1 | 0 | 1 | 2; }; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }`\n - `description?: string`\n - `draft?: { text: string; attachments?: object; }`\n - `imgURL?: string`\n - `isArchived?: boolean`\n - `isLowPriority?: boolean`\n - `isMarkedUnread?: boolean`\n - `isMuted?: boolean`\n - `isPinned?: boolean`\n - `isReadOnly?: boolean`\n - `lastActivity?: string`\n - `lastReadMessageSortKey?: string`\n - `localChatID?: string`\n - `messageExpirySeconds?: number`\n - `reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }`\n - `snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }`\n - `unreadMentionsCount?: number`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst chat = await client.chats.markUnread('!NCdzlIaMjZUmvmvyHU:beeper.com');\n\nconsole.log(chat);\n```", + "## mark_unread\n\n`client.chats.markUnread(chatID: string, messageID?: string): { id: string; accountID: string; network: string; participants: object; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: object; description?: string; draft?: object; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: object; snooze?: object; unreadMentionsCount?: number; }`\n\n**post** `/v1/chats/{chatID}/unread`\n\nMark a chat as unread, optionally from a specific message ID.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this installation when available.\n\n- `messageID?: string`\n Optional message ID to mark unread from.\n\n### Returns\n\n- `{ id: string; accountID: string; network: string; participants: { hasMore: boolean; items: object[]; total: number; }; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: object; description?: object; disappearingTimer?: object; title?: object; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }; description?: string; draft?: { text: string; attachments?: object; }; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }; snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }; unreadMentionsCount?: number; }`\n\n - `id: string`\n - `accountID: string`\n - `network: string`\n - `participants: { hasMore: boolean; items: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }[]; total: number; }`\n - `title: string`\n - `type: 'single' | 'group'`\n - `unreadCount: number`\n - `capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: { level: -2 | -1 | 0 | 1 | 2; }; description?: { level: -2 | -1 | 0 | 1 | 2; }; disappearingTimer?: { level: -2 | -1 | 0 | 1 | 2; }; title?: { level: -2 | -1 | 0 | 1 | 2; }; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }`\n - `description?: string`\n - `draft?: { text: string; attachments?: object; }`\n - `imgURL?: string`\n - `isArchived?: boolean`\n - `isLowPriority?: boolean`\n - `isMarkedUnread?: boolean`\n - `isMuted?: boolean`\n - `isPinned?: boolean`\n - `isReadOnly?: boolean`\n - `lastActivity?: string`\n - `lastReadMessageSortKey?: string`\n - `localChatID?: string`\n - `messageExpirySeconds?: number`\n - `reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }`\n - `snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }`\n - `unreadMentionsCount?: number`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst chat = await client.chats.markUnread('!NCdzlIaMjZUmvmvyHU:beeper.com');\n\nconsole.log(chat);\n```", perLanguage: { typescript: { method: 'client.chats.markUnread', @@ -712,7 +1125,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ cli: { method: 'chats mark_unread', example: - "beeper-desktop-cli chats mark-unread \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com'", + "beeper-desktop chats mark-unread \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com'", }, php: { method: 'chats->markUnread', @@ -731,14 +1144,14 @@ const EMBEDDED_METHODS: MethodEntry[] = [ httpMethod: 'post', summary: 'Notify anyway', description: - 'Force a delivery notification when supported by the underlying network. Currently intended for iMessage on macOS; unsupported networks return an error.', + 'Send a notification despite the recipient focus state when the network supports it. Currently intended for iMessage on macOS; unsupported networks return an error.', stainlessPath: '(resource) chats > (method) notify_anyway', qualified: 'client.chats.notifyAnyway', params: ['chatID: string;'], response: "{ id: string; accountID: string; network: string; participants: object; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: object; description?: string; draft?: object; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: object; snooze?: object; unreadMentionsCount?: number; }", markdown: - "## notify_anyway\n\n`client.chats.notifyAnyway(chatID: string): { id: string; accountID: string; network: string; participants: object; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: object; description?: string; draft?: object; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: object; snooze?: object; unreadMentionsCount?: number; }`\n\n**post** `/v1/chats/{chatID}/notify-anyway`\n\nForce a delivery notification when supported by the underlying network. Currently intended for iMessage on macOS; unsupported networks return an error.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.\n\n### Returns\n\n- `{ id: string; accountID: string; network: string; participants: { hasMore: boolean; items: object[]; total: number; }; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: object; description?: object; disappearingTimer?: object; title?: object; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }; description?: string; draft?: { text: string; attachments?: object; }; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }; snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }; unreadMentionsCount?: number; }`\n\n - `id: string`\n - `accountID: string`\n - `network: string`\n - `participants: { hasMore: boolean; items: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }[]; total: number; }`\n - `title: string`\n - `type: 'single' | 'group'`\n - `unreadCount: number`\n - `capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: { level: -2 | -1 | 0 | 1 | 2; }; description?: { level: -2 | -1 | 0 | 1 | 2; }; disappearingTimer?: { level: -2 | -1 | 0 | 1 | 2; }; title?: { level: -2 | -1 | 0 | 1 | 2; }; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }`\n - `description?: string`\n - `draft?: { text: string; attachments?: object; }`\n - `imgURL?: string`\n - `isArchived?: boolean`\n - `isLowPriority?: boolean`\n - `isMarkedUnread?: boolean`\n - `isMuted?: boolean`\n - `isPinned?: boolean`\n - `isReadOnly?: boolean`\n - `lastActivity?: string`\n - `lastReadMessageSortKey?: string`\n - `localChatID?: string`\n - `messageExpirySeconds?: number`\n - `reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }`\n - `snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }`\n - `unreadMentionsCount?: number`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst chat = await client.chats.notifyAnyway('!NCdzlIaMjZUmvmvyHU:beeper.com');\n\nconsole.log(chat);\n```", + "## notify_anyway\n\n`client.chats.notifyAnyway(chatID: string): { id: string; accountID: string; network: string; participants: object; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: object; description?: string; draft?: object; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: object; snooze?: object; unreadMentionsCount?: number; }`\n\n**post** `/v1/chats/{chatID}/notify-anyway`\n\nSend a notification despite the recipient focus state when the network supports it. Currently intended for iMessage on macOS; unsupported networks return an error.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this installation when available.\n\n### Returns\n\n- `{ id: string; accountID: string; network: string; participants: { hasMore: boolean; items: object[]; total: number; }; title: string; type: 'single' | 'group'; unreadCount: number; capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: object; description?: object; disappearingTimer?: object; title?: object; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }; description?: string; draft?: { text: string; attachments?: object; }; imgURL?: string; isArchived?: boolean; isLowPriority?: boolean; isMarkedUnread?: boolean; isMuted?: boolean; isPinned?: boolean; isReadOnly?: boolean; lastActivity?: string; lastReadMessageSortKey?: string; localChatID?: string; messageExpirySeconds?: number; reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }; snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }; unreadMentionsCount?: number; }`\n\n - `id: string`\n - `accountID: string`\n - `network: string`\n - `participants: { hasMore: boolean; items: { id: string; cannotMessage?: boolean; email?: string; fullName?: string; imgURL?: string; isSelf?: boolean; phoneNumber?: string; username?: string; }[]; total: number; }`\n - `title: string`\n - `type: 'single' | 'group'`\n - `unreadCount: number`\n - `capabilities?: { allowedReactions?: string[]; archive?: boolean; attachments?: object; customEmojiReactions?: boolean; delete?: -2 | -1 | 0 | 1 | 2; deleteChat?: boolean; deleteChatForEveryone?: boolean; deleteForMe?: boolean; deleteMaxAge?: number; disappearingTimer?: { omitEmptyTimer?: boolean; timers?: number[]; types?: 'afterRead' | 'afterSend'[]; }; edit?: -2 | -1 | 0 | 1 | 2; editMaxAge?: number; editMaxCount?: number; formatting?: object; locationMessage?: -2 | -1 | 0 | 1 | 2; markAsUnread?: boolean; maxTextLength?: number; messageRequest?: { acceptWithButton?: -2 | -1 | 0 | 1 | 2; acceptWithMessage?: -2 | -1 | 0 | 1 | 2; }; participantActions?: { ban?: -2 | -1 | 0 | 1 | 2; invite?: -2 | -1 | 0 | 1 | 2; kick?: -2 | -1 | 0 | 1 | 2; leave?: -2 | -1 | 0 | 1 | 2; revokeInvite?: -2 | -1 | 0 | 1 | 2; }; poll?: -2 | -1 | 0 | 1 | 2; reaction?: -2 | -1 | 0 | 1 | 2; reactionCount?: number; readReceipts?: boolean; reply?: -2 | -1 | 0 | 1 | 2; state?: { avatar?: { level: -2 | -1 | 0 | 1 | 2; }; description?: { level: -2 | -1 | 0 | 1 | 2; }; disappearingTimer?: { level: -2 | -1 | 0 | 1 | 2; }; title?: { level: -2 | -1 | 0 | 1 | 2; }; }; thread?: -2 | -1 | 0 | 1 | 2; typingNotifications?: boolean; }`\n - `description?: string`\n - `draft?: { text: string; attachments?: object; }`\n - `imgURL?: string`\n - `isArchived?: boolean`\n - `isLowPriority?: boolean`\n - `isMarkedUnread?: boolean`\n - `isMuted?: boolean`\n - `isPinned?: boolean`\n - `isReadOnly?: boolean`\n - `lastActivity?: string`\n - `lastReadMessageSortKey?: string`\n - `localChatID?: string`\n - `messageExpirySeconds?: number`\n - `reminder?: { dismissOnIncomingMessage?: boolean; remindAt?: string; }`\n - `snooze?: { snoozeUntil?: string; userSnoozedAt?: string; }`\n - `unreadMentionsCount?: number`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst chat = await client.chats.notifyAnyway('!NCdzlIaMjZUmvmvyHU:beeper.com');\n\nconsole.log(chat);\n```", perLanguage: { typescript: { method: 'client.chats.notifyAnyway', @@ -758,7 +1171,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ cli: { method: 'chats notify_anyway', example: - "beeper-desktop-cli chats notify-anyway \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com'", + "beeper-desktop chats notify-anyway \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com'", }, php: { method: 'chats->notifyAnyway', @@ -776,12 +1189,12 @@ const EMBEDDED_METHODS: MethodEntry[] = [ endpoint: '/v1/chats/{chatID}/reminders', httpMethod: 'post', summary: 'Create a chat reminder', - description: 'Set a reminder for a chat at a specific time', + description: 'Set a reminder for a chat at a specific time.', stainlessPath: '(resource) chats.reminders > (method) create', qualified: 'client.chats.reminders.create', params: ['chatID: string;', 'reminder: { remindAt: string; dismissOnIncomingMessage?: boolean; };'], markdown: - "## create\n\n`client.chats.reminders.create(chatID: string, reminder: { remindAt: string; dismissOnIncomingMessage?: boolean; }): void`\n\n**post** `/v1/chats/{chatID}/reminders`\n\nSet a reminder for a chat at a specific time\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.\n\n- `reminder: { remindAt: string; dismissOnIncomingMessage?: boolean; }`\n Reminder configuration\n - `remindAt: string`\n Timestamp when the reminder should trigger.\n - `dismissOnIncomingMessage?: boolean`\n Cancel reminder if someone messages in the chat\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nawait client.chats.reminders.create('!NCdzlIaMjZUmvmvyHU:beeper.com', { reminder: { remindAt: '2025-08-31T23:30:12.520Z' } })\n```", + "## create\n\n`client.chats.reminders.create(chatID: string, reminder: { remindAt: string; dismissOnIncomingMessage?: boolean; }): void`\n\n**post** `/v1/chats/{chatID}/reminders`\n\nSet a reminder for a chat at a specific time.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this installation when available.\n\n- `reminder: { remindAt: string; dismissOnIncomingMessage?: boolean; }`\n Reminder configuration\n - `remindAt: string`\n Timestamp when the reminder should trigger.\n - `dismissOnIncomingMessage?: boolean`\n Cancel reminder if someone messages in the chat\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nawait client.chats.reminders.create('!NCdzlIaMjZUmvmvyHU:beeper.com', { reminder: { remindAt: '2025-08-31T23:30:12.520Z' } })\n```", perLanguage: { typescript: { method: 'client.chats.reminders.create', @@ -801,7 +1214,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ cli: { method: 'reminders create', example: - "beeper-desktop-cli chats:reminders create \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com' \\\n --reminder \"{remindAt: '2025-08-31T23:30:12.520Z'}\"", + "beeper-desktop chats:reminders create \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com' \\\n --reminder \"{remindAt: '2025-08-31T23:30:12.520Z'}\"", }, php: { method: 'chats->reminders->create', @@ -819,12 +1232,12 @@ const EMBEDDED_METHODS: MethodEntry[] = [ endpoint: '/v1/chats/{chatID}/reminders', httpMethod: 'delete', summary: 'Delete a chat reminder', - description: 'Clear an existing reminder from a chat', + description: 'Clear an existing reminder from a chat.', stainlessPath: '(resource) chats.reminders > (method) delete', qualified: 'client.chats.reminders.delete', params: ['chatID: string;'], markdown: - "## delete\n\n`client.chats.reminders.delete(chatID: string): void`\n\n**delete** `/v1/chats/{chatID}/reminders`\n\nClear an existing reminder from a chat\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nawait client.chats.reminders.delete('!NCdzlIaMjZUmvmvyHU:beeper.com')\n```", + "## delete\n\n`client.chats.reminders.delete(chatID: string): void`\n\n**delete** `/v1/chats/{chatID}/reminders`\n\nClear an existing reminder from a chat.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this installation when available.\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nawait client.chats.reminders.delete('!NCdzlIaMjZUmvmvyHU:beeper.com')\n```", perLanguage: { typescript: { method: 'client.chats.reminders.delete', @@ -844,7 +1257,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ cli: { method: 'reminders delete', example: - "beeper-desktop-cli chats:reminders delete \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com'", + "beeper-desktop chats:reminders delete \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com'", }, php: { method: 'chats->reminders->delete', @@ -869,7 +1282,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: '{ chatID: string; messageID: string; reactionKey: string; success: true; transactionID: string; }', markdown: - "## add\n\n`client.chats.messages.reactions.add(chatID: string, messageID: string, reactionKey: string, transactionID?: string): { chatID: string; messageID: string; reactionKey: string; success: true; transactionID: string; }`\n\n**post** `/v1/chats/{chatID}/messages/{messageID}/reactions`\n\nAdd a reaction to an existing message.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.\n\n- `messageID: string`\n Message ID.\n\n- `reactionKey: string`\n Reaction key to add (emoji, shortcode, or custom emoji key)\n\n- `transactionID?: string`\n Optional transaction ID for deduplication and send tracking\n\n### Returns\n\n- `{ chatID: string; messageID: string; reactionKey: string; success: true; transactionID: string; }`\n\n - `chatID: string`\n - `messageID: string`\n - `reactionKey: string`\n - `success: true`\n - `transactionID: string`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.chats.messages.reactions.add('1343993', { chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', reactionKey: 'x' });\n\nconsole.log(response);\n```", + "## add\n\n`client.chats.messages.reactions.add(chatID: string, messageID: string, reactionKey: string, transactionID?: string): { chatID: string; messageID: string; reactionKey: string; success: true; transactionID: string; }`\n\n**post** `/v1/chats/{chatID}/messages/{messageID}/reactions`\n\nAdd a reaction to an existing message.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this installation when available.\n\n- `messageID: string`\n Message ID.\n\n- `reactionKey: string`\n Reaction key to add (emoji, shortcode, or custom emoji key)\n\n- `transactionID?: string`\n Optional transaction ID for deduplication and send tracking\n\n### Returns\n\n- `{ chatID: string; messageID: string; reactionKey: string; success: true; transactionID: string; }`\n\n - `chatID: string`\n - `messageID: string`\n - `reactionKey: string`\n - `success: true`\n - `transactionID: string`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.chats.messages.reactions.add('1343993', { chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', reactionKey: 'x' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.chats.messages.reactions.add', @@ -889,7 +1302,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ cli: { method: 'reactions add', example: - "beeper-desktop-cli chats:messages:reactions add \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com' \\\n --message-id 1343993 \\\n --reaction-key x", + "beeper-desktop chats:messages:reactions add \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com' \\\n --message-id 1343993 \\\n --reaction-key x", }, php: { method: 'chats->messages->reactions->add', @@ -913,7 +1326,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ params: ['chatID: string;', 'messageID: string;', 'reactionKey: string;'], response: '{ chatID: string; messageID: string; reactionKey: string; success: true; }', markdown: - "## delete\n\n`client.chats.messages.reactions.delete(chatID: string, messageID: string, reactionKey: string): { chatID: string; messageID: string; reactionKey: string; success: true; }`\n\n**delete** `/v1/chats/{chatID}/messages/{messageID}/reactions/{reactionKey}`\n\nRemove the reaction added by the authenticated user from an existing message.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.\n\n- `messageID: string`\n Message ID.\n\n- `reactionKey: string`\n Reaction key to remove (emoji, shortcode, or custom emoji key)\n\n### Returns\n\n- `{ chatID: string; messageID: string; reactionKey: string; success: true; }`\n\n - `chatID: string`\n - `messageID: string`\n - `reactionKey: string`\n - `success: true`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst reaction = await client.chats.messages.reactions.delete('x', { chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', messageID: '1343993' });\n\nconsole.log(reaction);\n```", + "## delete\n\n`client.chats.messages.reactions.delete(chatID: string, messageID: string, reactionKey: string): { chatID: string; messageID: string; reactionKey: string; success: true; }`\n\n**delete** `/v1/chats/{chatID}/messages/{messageID}/reactions/{reactionKey}`\n\nRemove the reaction added by the authenticated user from an existing message.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this installation when available.\n\n- `messageID: string`\n Message ID.\n\n- `reactionKey: string`\n Reaction key to remove (emoji, shortcode, or custom emoji key)\n\n### Returns\n\n- `{ chatID: string; messageID: string; reactionKey: string; success: true; }`\n\n - `chatID: string`\n - `messageID: string`\n - `reactionKey: string`\n - `success: true`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst reaction = await client.chats.messages.reactions.delete('x', { chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', messageID: '1343993' });\n\nconsole.log(reaction);\n```", perLanguage: { typescript: { method: 'client.chats.messages.reactions.delete', @@ -933,7 +1346,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ cli: { method: 'reactions delete', example: - "beeper-desktop-cli chats:messages:reactions delete \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com' \\\n --message-id 1343993 \\\n --reaction-key x", + "beeper-desktop chats:messages:reactions delete \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com' \\\n --message-id 1343993 \\\n --reaction-key x", }, php: { method: 'chats->messages->reactions->delete', @@ -972,7 +1385,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: "{ id: string; accountID: string; chatID: string; senderID: string; sortKey: string; timestamp: string; attachments?: { type: 'unknown' | 'img' | 'video' | 'audio'; id?: string; duration?: number; fileName?: string; fileSize?: number; isGif?: boolean; isSticker?: boolean; isVoiceNote?: boolean; mimeType?: string; posterImg?: string; size?: object; srcURL?: string; transcription?: object; }[]; editedTimestamp?: string; isDeleted?: boolean; isHidden?: boolean; isSender?: boolean; isUnread?: boolean; linkedMessageID?: string; links?: { title: string; url: string; favicon?: string; img?: string; imgSize?: { height?: number; width?: number; }; originalURL?: string; summary?: string; }[]; mentions?: string[]; reactions?: { id: string; participantID: string; reactionKey: string; emoji?: boolean; imgURL?: string; }[]; seen?: boolean | string | object; senderName?: string; sendStatus?: { status: 'SUCCESS' | 'PENDING' | 'FAIL_RETRIABLE' | 'FAIL_PERMANENT'; timestamp: string; deliveredToUsers?: string[]; internalError?: string; message?: string; reason?: string; }; text?: string; type?: string; }", markdown: - "## search\n\n`client.messages.search(accountIDs?: string[], chatIDs?: string[], chatType?: 'group' | 'single', cursor?: string, dateAfter?: string, dateBefore?: string, direction?: 'after' | 'before', excludeLowPriority?: boolean, includeMuted?: boolean, limit?: number, mediaTypes?: 'any' | 'video' | 'image' | 'link' | 'file'[], query?: string, sender?: string): { id: string; accountID: string; chatID: string; senderID: string; sortKey: string; timestamp: string; attachments?: attachment[]; editedTimestamp?: string; isDeleted?: boolean; isHidden?: boolean; isSender?: boolean; isUnread?: boolean; linkedMessageID?: string; links?: object[]; mentions?: string[]; reactions?: reaction[]; seen?: boolean | string | object; senderName?: string; sendStatus?: object; text?: string; type?: string; }`\n\n**get** `/v1/messages/search`\n\nSearch messages across chats.\n\n### Parameters\n\n- `accountIDs?: string[]`\n Limit search to specific account IDs.\n\n- `chatIDs?: string[]`\n Limit search to specific chat IDs.\n\n- `chatType?: 'group' | 'single'`\n Filter by chat type: 'group' for group chats, 'single' for 1:1 chats.\n\n- `cursor?: string`\n Opaque pagination cursor; do not inspect. Use together with 'direction'.\n\n- `dateAfter?: string`\n Only include messages with timestamp strictly after this ISO 8601 datetime (e.g., '2024-07-01T00:00:00Z' or '2024-07-01T00:00:00+02:00').\n\n- `dateBefore?: string`\n Only include messages with timestamp strictly before this ISO 8601 datetime (e.g., '2024-07-31T23:59:59Z' or '2024-07-31T23:59:59+02:00').\n\n- `direction?: 'after' | 'before'`\n Pagination direction used with 'cursor': 'before' fetches older results, 'after' fetches newer results. Defaults to 'before' when only 'cursor' is provided.\n\n- `excludeLowPriority?: boolean`\n Exclude messages marked Low Priority by the user. Default: true. Set to false to include all.\n\n- `includeMuted?: boolean`\n Include messages in chats marked as Muted by the user, which are usually less important. Default: true. Set to false if the user wants a more refined search.\n\n- `limit?: number`\n Maximum number of messages to return.\n\n- `mediaTypes?: 'any' | 'video' | 'image' | 'link' | 'file'[]`\n Filter messages by media types. Use ['any'] for any media type, or specify exact types like ['video', 'image']. Omit for no media filtering.\n\n- `query?: string`\n Literal word search (non-semantic). Finds messages containing these EXACT words in any order. Use single words users actually type, not concepts or phrases. Example: use \"dinner\" not \"dinner plans\", use \"sick\" not \"health issues\". If omitted, returns results filtered only by other parameters.\n\n- `sender?: string`\n Filter by sender: 'me' (messages sent by the authenticated user), 'others' (messages sent by others), or a specific user ID string (user.id).\n\n### Returns\n\n- `{ id: string; accountID: string; chatID: string; senderID: string; sortKey: string; timestamp: string; attachments?: { type: 'unknown' | 'img' | 'video' | 'audio'; id?: string; duration?: number; fileName?: string; fileSize?: number; isGif?: boolean; isSticker?: boolean; isVoiceNote?: boolean; mimeType?: string; posterImg?: string; size?: object; srcURL?: string; transcription?: object; }[]; editedTimestamp?: string; isDeleted?: boolean; isHidden?: boolean; isSender?: boolean; isUnread?: boolean; linkedMessageID?: string; links?: { title: string; url: string; favicon?: string; img?: string; imgSize?: { height?: number; width?: number; }; originalURL?: string; summary?: string; }[]; mentions?: string[]; reactions?: { id: string; participantID: string; reactionKey: string; emoji?: boolean; imgURL?: string; }[]; seen?: boolean | string | object; senderName?: string; sendStatus?: { status: 'SUCCESS' | 'PENDING' | 'FAIL_RETRIABLE' | 'FAIL_PERMANENT'; timestamp: string; deliveredToUsers?: string[]; internalError?: string; message?: string; reason?: string; }; text?: string; type?: string; }`\n\n - `id: string`\n - `accountID: string`\n - `chatID: string`\n - `senderID: string`\n - `sortKey: string`\n - `timestamp: string`\n - `attachments?: { type: 'unknown' | 'img' | 'video' | 'audio'; id?: string; duration?: number; fileName?: string; fileSize?: number; isGif?: boolean; isSticker?: boolean; isVoiceNote?: boolean; mimeType?: string; posterImg?: string; size?: { height?: number; width?: number; }; srcURL?: string; transcription?: { engine: string; transcription: string; language?: string; }; }[]`\n - `editedTimestamp?: string`\n - `isDeleted?: boolean`\n - `isHidden?: boolean`\n - `isSender?: boolean`\n - `isUnread?: boolean`\n - `linkedMessageID?: string`\n - `links?: { title: string; url: string; favicon?: string; img?: string; imgSize?: { height?: number; width?: number; }; originalURL?: string; summary?: string; }[]`\n - `mentions?: string[]`\n - `reactions?: { id: string; participantID: string; reactionKey: string; emoji?: boolean; imgURL?: string; }[]`\n - `seen?: boolean | string | object`\n - `senderName?: string`\n - `sendStatus?: { status: 'SUCCESS' | 'PENDING' | 'FAIL_RETRIABLE' | 'FAIL_PERMANENT'; timestamp: string; deliveredToUsers?: string[]; internalError?: string; message?: string; reason?: string; }`\n - `text?: string`\n - `type?: string`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\n// Automatically fetches more pages as needed.\nfor await (const message of client.messages.search()) {\n console.log(message);\n}\n```", + "## search\n\n`client.messages.search(accountIDs?: string[], chatIDs?: string[], chatType?: 'group' | 'single', cursor?: string, dateAfter?: string, dateBefore?: string, direction?: 'after' | 'before', excludeLowPriority?: boolean, includeMuted?: boolean, limit?: number, mediaTypes?: 'any' | 'video' | 'image' | 'link' | 'file'[], query?: string, sender?: string): { id: string; accountID: string; chatID: string; senderID: string; sortKey: string; timestamp: string; attachments?: attachment[]; editedTimestamp?: string; isDeleted?: boolean; isHidden?: boolean; isSender?: boolean; isUnread?: boolean; linkedMessageID?: string; links?: object[]; mentions?: string[]; reactions?: reaction[]; seen?: boolean | string | object; senderName?: string; sendStatus?: object; text?: string; type?: string; }`\n\n**get** `/v1/messages/search`\n\nSearch messages across chats.\n\n### Parameters\n\n- `accountIDs?: string[]`\n Limit search to specific account IDs.\n\n- `chatIDs?: string[]`\n Limit search to specific chat IDs.\n\n- `chatType?: 'group' | 'single'`\n Filter by chat type: 'group' for group chats, 'single' for 1:1 chats.\n\n- `cursor?: string`\n Opaque pagination cursor; do not inspect. Use together with 'direction'.\n\n- `dateAfter?: string`\n Only include messages with timestamp strictly after this ISO 8601 datetime (e.g., '2024-07-01T00:00:00Z' or '2024-07-01T00:00:00+02:00').\n\n- `dateBefore?: string`\n Only include messages with timestamp strictly before this ISO 8601 datetime (e.g., '2024-07-31T23:59:59Z' or '2024-07-31T23:59:59+02:00').\n\n- `direction?: 'after' | 'before'`\n Pagination direction used with 'cursor': 'before' fetches older results, 'after' fetches newer results. Defaults to 'before' when only 'cursor' is provided.\n\n- `excludeLowPriority?: boolean`\n Exclude messages marked Low Priority by the user. Default: true. Set to false to include all.\n\n- `includeMuted?: boolean`\n Include messages in chats marked as Muted by the user, which are usually less important. Default: true. Set to false if the user wants a more refined search.\n\n- `limit?: number`\n Maximum number of messages to return.\n\n- `mediaTypes?: 'any' | 'video' | 'image' | 'link' | 'file'[]`\n Filter messages by media types. Use ['any'] for any media type, or specify exact types like ['video', 'image']. Omit for no media filtering.\n\n- `query?: string`\n Literal word search. Finds messages containing these words in any order. Use words the user actually typed, not inferred concepts. Example: use \"dinner\" rather than \"dinner plans\". If omitted, returns results filtered only by the other parameters.\n\n- `sender?: string`\n Filter by sender: 'me' (messages sent by the authenticated user), 'others' (messages sent by others), or a specific user ID string (user.id).\n\n### Returns\n\n- `{ id: string; accountID: string; chatID: string; senderID: string; sortKey: string; timestamp: string; attachments?: { type: 'unknown' | 'img' | 'video' | 'audio'; id?: string; duration?: number; fileName?: string; fileSize?: number; isGif?: boolean; isSticker?: boolean; isVoiceNote?: boolean; mimeType?: string; posterImg?: string; size?: object; srcURL?: string; transcription?: object; }[]; editedTimestamp?: string; isDeleted?: boolean; isHidden?: boolean; isSender?: boolean; isUnread?: boolean; linkedMessageID?: string; links?: { title: string; url: string; favicon?: string; img?: string; imgSize?: { height?: number; width?: number; }; originalURL?: string; summary?: string; }[]; mentions?: string[]; reactions?: { id: string; participantID: string; reactionKey: string; emoji?: boolean; imgURL?: string; }[]; seen?: boolean | string | object; senderName?: string; sendStatus?: { status: 'SUCCESS' | 'PENDING' | 'FAIL_RETRIABLE' | 'FAIL_PERMANENT'; timestamp: string; deliveredToUsers?: string[]; internalError?: string; message?: string; reason?: string; }; text?: string; type?: string; }`\n\n - `id: string`\n - `accountID: string`\n - `chatID: string`\n - `senderID: string`\n - `sortKey: string`\n - `timestamp: string`\n - `attachments?: { type: 'unknown' | 'img' | 'video' | 'audio'; id?: string; duration?: number; fileName?: string; fileSize?: number; isGif?: boolean; isSticker?: boolean; isVoiceNote?: boolean; mimeType?: string; posterImg?: string; size?: { height?: number; width?: number; }; srcURL?: string; transcription?: { engine: string; transcription: string; language?: string; }; }[]`\n - `editedTimestamp?: string`\n - `isDeleted?: boolean`\n - `isHidden?: boolean`\n - `isSender?: boolean`\n - `isUnread?: boolean`\n - `linkedMessageID?: string`\n - `links?: { title: string; url: string; favicon?: string; img?: string; imgSize?: { height?: number; width?: number; }; originalURL?: string; summary?: string; }[]`\n - `mentions?: string[]`\n - `reactions?: { id: string; participantID: string; reactionKey: string; emoji?: boolean; imgURL?: string; }[]`\n - `seen?: boolean | string | object`\n - `senderName?: string`\n - `sendStatus?: { status: 'SUCCESS' | 'PENDING' | 'FAIL_RETRIABLE' | 'FAIL_PERMANENT'; timestamp: string; deliveredToUsers?: string[]; internalError?: string; message?: string; reason?: string; }`\n - `text?: string`\n - `type?: string`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\n// Automatically fetches more pages as needed.\nfor await (const message of client.messages.search()) {\n console.log(message);\n}\n```", perLanguage: { typescript: { method: 'client.messages.search', @@ -991,7 +1404,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ }, cli: { method: 'messages search', - example: "beeper-desktop-cli messages search \\\n --access-token 'My Access Token'", + example: "beeper-desktop messages search \\\n --access-token 'My Access Token'", }, php: { method: 'messages->search', @@ -1016,7 +1429,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: "{ id: string; accountID: string; chatID: string; senderID: string; sortKey: string; timestamp: string; attachments?: { type: 'unknown' | 'img' | 'video' | 'audio'; id?: string; duration?: number; fileName?: string; fileSize?: number; isGif?: boolean; isSticker?: boolean; isVoiceNote?: boolean; mimeType?: string; posterImg?: string; size?: object; srcURL?: string; transcription?: object; }[]; editedTimestamp?: string; isDeleted?: boolean; isHidden?: boolean; isSender?: boolean; isUnread?: boolean; linkedMessageID?: string; links?: { title: string; url: string; favicon?: string; img?: string; imgSize?: { height?: number; width?: number; }; originalURL?: string; summary?: string; }[]; mentions?: string[]; reactions?: { id: string; participantID: string; reactionKey: string; emoji?: boolean; imgURL?: string; }[]; seen?: boolean | string | object; senderName?: string; sendStatus?: { status: 'SUCCESS' | 'PENDING' | 'FAIL_RETRIABLE' | 'FAIL_PERMANENT'; timestamp: string; deliveredToUsers?: string[]; internalError?: string; message?: string; reason?: string; }; text?: string; type?: string; }", markdown: - "## list\n\n`client.messages.list(chatID: string, cursor?: string, direction?: 'after' | 'before'): { id: string; accountID: string; chatID: string; senderID: string; sortKey: string; timestamp: string; attachments?: attachment[]; editedTimestamp?: string; isDeleted?: boolean; isHidden?: boolean; isSender?: boolean; isUnread?: boolean; linkedMessageID?: string; links?: object[]; mentions?: string[]; reactions?: reaction[]; seen?: boolean | string | object; senderName?: string; sendStatus?: object; text?: string; type?: string; }`\n\n**get** `/v1/chats/{chatID}/messages`\n\nList all messages in a chat with cursor-based pagination. Sorted by timestamp.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.\n\n- `cursor?: string`\n Opaque pagination cursor; do not inspect. Use together with 'direction'.\n\n- `direction?: 'after' | 'before'`\n Pagination direction used with 'cursor': 'before' fetches older results, 'after' fetches newer results. Defaults to 'before' when only 'cursor' is provided.\n\n### Returns\n\n- `{ id: string; accountID: string; chatID: string; senderID: string; sortKey: string; timestamp: string; attachments?: { type: 'unknown' | 'img' | 'video' | 'audio'; id?: string; duration?: number; fileName?: string; fileSize?: number; isGif?: boolean; isSticker?: boolean; isVoiceNote?: boolean; mimeType?: string; posterImg?: string; size?: object; srcURL?: string; transcription?: object; }[]; editedTimestamp?: string; isDeleted?: boolean; isHidden?: boolean; isSender?: boolean; isUnread?: boolean; linkedMessageID?: string; links?: { title: string; url: string; favicon?: string; img?: string; imgSize?: { height?: number; width?: number; }; originalURL?: string; summary?: string; }[]; mentions?: string[]; reactions?: { id: string; participantID: string; reactionKey: string; emoji?: boolean; imgURL?: string; }[]; seen?: boolean | string | object; senderName?: string; sendStatus?: { status: 'SUCCESS' | 'PENDING' | 'FAIL_RETRIABLE' | 'FAIL_PERMANENT'; timestamp: string; deliveredToUsers?: string[]; internalError?: string; message?: string; reason?: string; }; text?: string; type?: string; }`\n\n - `id: string`\n - `accountID: string`\n - `chatID: string`\n - `senderID: string`\n - `sortKey: string`\n - `timestamp: string`\n - `attachments?: { type: 'unknown' | 'img' | 'video' | 'audio'; id?: string; duration?: number; fileName?: string; fileSize?: number; isGif?: boolean; isSticker?: boolean; isVoiceNote?: boolean; mimeType?: string; posterImg?: string; size?: { height?: number; width?: number; }; srcURL?: string; transcription?: { engine: string; transcription: string; language?: string; }; }[]`\n - `editedTimestamp?: string`\n - `isDeleted?: boolean`\n - `isHidden?: boolean`\n - `isSender?: boolean`\n - `isUnread?: boolean`\n - `linkedMessageID?: string`\n - `links?: { title: string; url: string; favicon?: string; img?: string; imgSize?: { height?: number; width?: number; }; originalURL?: string; summary?: string; }[]`\n - `mentions?: string[]`\n - `reactions?: { id: string; participantID: string; reactionKey: string; emoji?: boolean; imgURL?: string; }[]`\n - `seen?: boolean | string | object`\n - `senderName?: string`\n - `sendStatus?: { status: 'SUCCESS' | 'PENDING' | 'FAIL_RETRIABLE' | 'FAIL_PERMANENT'; timestamp: string; deliveredToUsers?: string[]; internalError?: string; message?: string; reason?: string; }`\n - `text?: string`\n - `type?: string`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\n// Automatically fetches more pages as needed.\nfor await (const message of client.messages.list('!NCdzlIaMjZUmvmvyHU:beeper.com')) {\n console.log(message);\n}\n```", + "## list\n\n`client.messages.list(chatID: string, cursor?: string, direction?: 'after' | 'before'): { id: string; accountID: string; chatID: string; senderID: string; sortKey: string; timestamp: string; attachments?: attachment[]; editedTimestamp?: string; isDeleted?: boolean; isHidden?: boolean; isSender?: boolean; isUnread?: boolean; linkedMessageID?: string; links?: object[]; mentions?: string[]; reactions?: reaction[]; seen?: boolean | string | object; senderName?: string; sendStatus?: object; text?: string; type?: string; }`\n\n**get** `/v1/chats/{chatID}/messages`\n\nList all messages in a chat with cursor-based pagination. Sorted by timestamp.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this installation when available.\n\n- `cursor?: string`\n Opaque pagination cursor; do not inspect. Use together with 'direction'.\n\n- `direction?: 'after' | 'before'`\n Pagination direction used with 'cursor': 'before' fetches older results, 'after' fetches newer results. Defaults to 'before' when only 'cursor' is provided.\n\n### Returns\n\n- `{ id: string; accountID: string; chatID: string; senderID: string; sortKey: string; timestamp: string; attachments?: { type: 'unknown' | 'img' | 'video' | 'audio'; id?: string; duration?: number; fileName?: string; fileSize?: number; isGif?: boolean; isSticker?: boolean; isVoiceNote?: boolean; mimeType?: string; posterImg?: string; size?: object; srcURL?: string; transcription?: object; }[]; editedTimestamp?: string; isDeleted?: boolean; isHidden?: boolean; isSender?: boolean; isUnread?: boolean; linkedMessageID?: string; links?: { title: string; url: string; favicon?: string; img?: string; imgSize?: { height?: number; width?: number; }; originalURL?: string; summary?: string; }[]; mentions?: string[]; reactions?: { id: string; participantID: string; reactionKey: string; emoji?: boolean; imgURL?: string; }[]; seen?: boolean | string | object; senderName?: string; sendStatus?: { status: 'SUCCESS' | 'PENDING' | 'FAIL_RETRIABLE' | 'FAIL_PERMANENT'; timestamp: string; deliveredToUsers?: string[]; internalError?: string; message?: string; reason?: string; }; text?: string; type?: string; }`\n\n - `id: string`\n - `accountID: string`\n - `chatID: string`\n - `senderID: string`\n - `sortKey: string`\n - `timestamp: string`\n - `attachments?: { type: 'unknown' | 'img' | 'video' | 'audio'; id?: string; duration?: number; fileName?: string; fileSize?: number; isGif?: boolean; isSticker?: boolean; isVoiceNote?: boolean; mimeType?: string; posterImg?: string; size?: { height?: number; width?: number; }; srcURL?: string; transcription?: { engine: string; transcription: string; language?: string; }; }[]`\n - `editedTimestamp?: string`\n - `isDeleted?: boolean`\n - `isHidden?: boolean`\n - `isSender?: boolean`\n - `isUnread?: boolean`\n - `linkedMessageID?: string`\n - `links?: { title: string; url: string; favicon?: string; img?: string; imgSize?: { height?: number; width?: number; }; originalURL?: string; summary?: string; }[]`\n - `mentions?: string[]`\n - `reactions?: { id: string; participantID: string; reactionKey: string; emoji?: boolean; imgURL?: string; }[]`\n - `seen?: boolean | string | object`\n - `senderName?: string`\n - `sendStatus?: { status: 'SUCCESS' | 'PENDING' | 'FAIL_RETRIABLE' | 'FAIL_PERMANENT'; timestamp: string; deliveredToUsers?: string[]; internalError?: string; message?: string; reason?: string; }`\n - `text?: string`\n - `type?: string`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\n// Automatically fetches more pages as needed.\nfor await (const message of client.messages.list('!NCdzlIaMjZUmvmvyHU:beeper.com')) {\n console.log(message);\n}\n```", perLanguage: { typescript: { method: 'client.messages.list', @@ -1036,7 +1449,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ cli: { method: 'messages list', example: - "beeper-desktop-cli messages list \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com'", + "beeper-desktop messages list \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com'", }, php: { method: 'messages->list', @@ -1066,7 +1479,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ ], response: '{ chatID: string; pendingMessageID: string; }', markdown: - "## send\n\n`client.messages.send(chatID: string, attachment?: { uploadID: string; duration?: number; fileName?: string; mimeType?: string; size?: { height: number; width: number; }; type?: 'image' | 'video' | 'audio' | 'file' | 'gif' | 'voice-note' | 'sticker'; }, replyToMessageID?: string, text?: string): { chatID: string; pendingMessageID: string; }`\n\n**post** `/v1/chats/{chatID}/messages`\n\nSend a text message to a specific chat. Supports replying to existing messages. Returns a pending message ID.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.\n\n- `attachment?: { uploadID: string; duration?: number; fileName?: string; mimeType?: string; size?: { height: number; width: number; }; type?: 'image' | 'video' | 'audio' | 'file' | 'gif' | 'voice-note' | 'sticker'; }`\n Single attachment to send with the message\n - `uploadID: string`\n Upload ID from uploadAsset endpoint. Required to reference uploaded files.\n - `duration?: number`\n Duration in seconds (optional override of cached value)\n - `fileName?: string`\n Filename (optional override of cached value)\n - `mimeType?: string`\n MIME type (optional override of cached value)\n - `size?: { height: number; width: number; }`\n Dimensions (optional override of cached value)\n - `type?: 'image' | 'video' | 'audio' | 'file' | 'gif' | 'voice-note' | 'sticker'`\n Attachment type hint (image, video, audio, file, gif, voice-note, sticker). If omitted, auto-detected from mimeType\n\n- `replyToMessageID?: string`\n Provide a message ID to send this as a reply to an existing message\n\n- `text?: string`\n Draft text. Plain text and Markdown are converted to Matrix HTML with the same rules used by send and edit.\n\n### Returns\n\n- `{ chatID: string; pendingMessageID: string; }`\n\n - `chatID: string`\n - `pendingMessageID: string`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.messages.send('!NCdzlIaMjZUmvmvyHU:beeper.com');\n\nconsole.log(response);\n```", + "## send\n\n`client.messages.send(chatID: string, attachment?: { uploadID: string; duration?: number; fileName?: string; mimeType?: string; size?: { height: number; width: number; }; type?: 'image' | 'video' | 'audio' | 'file' | 'gif' | 'voice-note' | 'sticker'; }, replyToMessageID?: string, text?: string): { chatID: string; pendingMessageID: string; }`\n\n**post** `/v1/chats/{chatID}/messages`\n\nSend a text message to a specific chat. Supports replying to existing messages. Returns a pending message ID.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this installation when available.\n\n- `attachment?: { uploadID: string; duration?: number; fileName?: string; mimeType?: string; size?: { height: number; width: number; }; type?: 'image' | 'video' | 'audio' | 'file' | 'gif' | 'voice-note' | 'sticker'; }`\n Single attachment to send with the message\n - `uploadID: string`\n Upload ID from uploadAsset endpoint. Required to reference uploaded files.\n - `duration?: number`\n Duration in seconds (optional override of cached value)\n - `fileName?: string`\n Filename (optional override of cached value)\n - `mimeType?: string`\n MIME type (optional override of cached value)\n - `size?: { height: number; width: number; }`\n Dimensions (optional override of cached value)\n - `type?: 'image' | 'video' | 'audio' | 'file' | 'gif' | 'voice-note' | 'sticker'`\n Attachment type hint (image, video, audio, file, gif, voice-note, sticker). If omitted, auto-detected from mimeType\n\n- `replyToMessageID?: string`\n Provide a message ID to send this as a reply to an existing message\n\n- `text?: string`\n Draft text. Plain text and Markdown are converted to Beeper rich text with the same rules used by send and edit.\n\n### Returns\n\n- `{ chatID: string; pendingMessageID: string; }`\n\n - `chatID: string`\n - `pendingMessageID: string`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.messages.send('!NCdzlIaMjZUmvmvyHU:beeper.com');\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.messages.send', @@ -1086,7 +1499,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ cli: { method: 'messages send', example: - "beeper-desktop-cli messages send \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com'", + "beeper-desktop messages send \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com'", }, php: { method: 'messages->send', @@ -1105,14 +1518,14 @@ const EMBEDDED_METHODS: MethodEntry[] = [ httpMethod: 'get', summary: 'Retrieve a message', description: - 'Retrieve a message by final message ID, pendingMessageID, or Matrix event ID. Chat ID may be a Beeper chat ID or local chat ID.', + 'Retrieve a message by final message ID, pendingMessageID, or Matrix event ID. chatID may be a Beeper chat ID or a local chat ID.', stainlessPath: '(resource) messages > (method) retrieve', qualified: 'client.messages.retrieve', params: ['chatID: string;', 'messageID: string;'], response: "{ id: string; accountID: string; chatID: string; senderID: string; sortKey: string; timestamp: string; attachments?: { type: 'unknown' | 'img' | 'video' | 'audio'; id?: string; duration?: number; fileName?: string; fileSize?: number; isGif?: boolean; isSticker?: boolean; isVoiceNote?: boolean; mimeType?: string; posterImg?: string; size?: object; srcURL?: string; transcription?: object; }[]; editedTimestamp?: string; isDeleted?: boolean; isHidden?: boolean; isSender?: boolean; isUnread?: boolean; linkedMessageID?: string; links?: { title: string; url: string; favicon?: string; img?: string; imgSize?: { height?: number; width?: number; }; originalURL?: string; summary?: string; }[]; mentions?: string[]; reactions?: { id: string; participantID: string; reactionKey: string; emoji?: boolean; imgURL?: string; }[]; seen?: boolean | string | object; senderName?: string; sendStatus?: { status: 'SUCCESS' | 'PENDING' | 'FAIL_RETRIABLE' | 'FAIL_PERMANENT'; timestamp: string; deliveredToUsers?: string[]; internalError?: string; message?: string; reason?: string; }; text?: string; type?: string; }", markdown: - "## retrieve\n\n`client.messages.retrieve(chatID: string, messageID: string): { id: string; accountID: string; chatID: string; senderID: string; sortKey: string; timestamp: string; attachments?: attachment[]; editedTimestamp?: string; isDeleted?: boolean; isHidden?: boolean; isSender?: boolean; isUnread?: boolean; linkedMessageID?: string; links?: object[]; mentions?: string[]; reactions?: reaction[]; seen?: boolean | string | object; senderName?: string; sendStatus?: object; text?: string; type?: string; }`\n\n**get** `/v1/chats/{chatID}/messages/{messageID}`\n\nRetrieve a message by final message ID, pendingMessageID, or Matrix event ID. Chat ID may be a Beeper chat ID or local chat ID.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.\n\n- `messageID: string`\n Message ID.\n\n### Returns\n\n- `{ id: string; accountID: string; chatID: string; senderID: string; sortKey: string; timestamp: string; attachments?: { type: 'unknown' | 'img' | 'video' | 'audio'; id?: string; duration?: number; fileName?: string; fileSize?: number; isGif?: boolean; isSticker?: boolean; isVoiceNote?: boolean; mimeType?: string; posterImg?: string; size?: object; srcURL?: string; transcription?: object; }[]; editedTimestamp?: string; isDeleted?: boolean; isHidden?: boolean; isSender?: boolean; isUnread?: boolean; linkedMessageID?: string; links?: { title: string; url: string; favicon?: string; img?: string; imgSize?: { height?: number; width?: number; }; originalURL?: string; summary?: string; }[]; mentions?: string[]; reactions?: { id: string; participantID: string; reactionKey: string; emoji?: boolean; imgURL?: string; }[]; seen?: boolean | string | object; senderName?: string; sendStatus?: { status: 'SUCCESS' | 'PENDING' | 'FAIL_RETRIABLE' | 'FAIL_PERMANENT'; timestamp: string; deliveredToUsers?: string[]; internalError?: string; message?: string; reason?: string; }; text?: string; type?: string; }`\n\n - `id: string`\n - `accountID: string`\n - `chatID: string`\n - `senderID: string`\n - `sortKey: string`\n - `timestamp: string`\n - `attachments?: { type: 'unknown' | 'img' | 'video' | 'audio'; id?: string; duration?: number; fileName?: string; fileSize?: number; isGif?: boolean; isSticker?: boolean; isVoiceNote?: boolean; mimeType?: string; posterImg?: string; size?: { height?: number; width?: number; }; srcURL?: string; transcription?: { engine: string; transcription: string; language?: string; }; }[]`\n - `editedTimestamp?: string`\n - `isDeleted?: boolean`\n - `isHidden?: boolean`\n - `isSender?: boolean`\n - `isUnread?: boolean`\n - `linkedMessageID?: string`\n - `links?: { title: string; url: string; favicon?: string; img?: string; imgSize?: { height?: number; width?: number; }; originalURL?: string; summary?: string; }[]`\n - `mentions?: string[]`\n - `reactions?: { id: string; participantID: string; reactionKey: string; emoji?: boolean; imgURL?: string; }[]`\n - `seen?: boolean | string | object`\n - `senderName?: string`\n - `sendStatus?: { status: 'SUCCESS' | 'PENDING' | 'FAIL_RETRIABLE' | 'FAIL_PERMANENT'; timestamp: string; deliveredToUsers?: string[]; internalError?: string; message?: string; reason?: string; }`\n - `text?: string`\n - `type?: string`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst message = await client.messages.retrieve('1343993', { chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com' });\n\nconsole.log(message);\n```", + "## retrieve\n\n`client.messages.retrieve(chatID: string, messageID: string): { id: string; accountID: string; chatID: string; senderID: string; sortKey: string; timestamp: string; attachments?: attachment[]; editedTimestamp?: string; isDeleted?: boolean; isHidden?: boolean; isSender?: boolean; isUnread?: boolean; linkedMessageID?: string; links?: object[]; mentions?: string[]; reactions?: reaction[]; seen?: boolean | string | object; senderName?: string; sendStatus?: object; text?: string; type?: string; }`\n\n**get** `/v1/chats/{chatID}/messages/{messageID}`\n\nRetrieve a message by final message ID, pendingMessageID, or Matrix event ID. chatID may be a Beeper chat ID or a local chat ID.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this installation when available.\n\n- `messageID: string`\n Message ID.\n\n### Returns\n\n- `{ id: string; accountID: string; chatID: string; senderID: string; sortKey: string; timestamp: string; attachments?: { type: 'unknown' | 'img' | 'video' | 'audio'; id?: string; duration?: number; fileName?: string; fileSize?: number; isGif?: boolean; isSticker?: boolean; isVoiceNote?: boolean; mimeType?: string; posterImg?: string; size?: object; srcURL?: string; transcription?: object; }[]; editedTimestamp?: string; isDeleted?: boolean; isHidden?: boolean; isSender?: boolean; isUnread?: boolean; linkedMessageID?: string; links?: { title: string; url: string; favicon?: string; img?: string; imgSize?: { height?: number; width?: number; }; originalURL?: string; summary?: string; }[]; mentions?: string[]; reactions?: { id: string; participantID: string; reactionKey: string; emoji?: boolean; imgURL?: string; }[]; seen?: boolean | string | object; senderName?: string; sendStatus?: { status: 'SUCCESS' | 'PENDING' | 'FAIL_RETRIABLE' | 'FAIL_PERMANENT'; timestamp: string; deliveredToUsers?: string[]; internalError?: string; message?: string; reason?: string; }; text?: string; type?: string; }`\n\n - `id: string`\n - `accountID: string`\n - `chatID: string`\n - `senderID: string`\n - `sortKey: string`\n - `timestamp: string`\n - `attachments?: { type: 'unknown' | 'img' | 'video' | 'audio'; id?: string; duration?: number; fileName?: string; fileSize?: number; isGif?: boolean; isSticker?: boolean; isVoiceNote?: boolean; mimeType?: string; posterImg?: string; size?: { height?: number; width?: number; }; srcURL?: string; transcription?: { engine: string; transcription: string; language?: string; }; }[]`\n - `editedTimestamp?: string`\n - `isDeleted?: boolean`\n - `isHidden?: boolean`\n - `isSender?: boolean`\n - `isUnread?: boolean`\n - `linkedMessageID?: string`\n - `links?: { title: string; url: string; favicon?: string; img?: string; imgSize?: { height?: number; width?: number; }; originalURL?: string; summary?: string; }[]`\n - `mentions?: string[]`\n - `reactions?: { id: string; participantID: string; reactionKey: string; emoji?: boolean; imgURL?: string; }[]`\n - `seen?: boolean | string | object`\n - `senderName?: string`\n - `sendStatus?: { status: 'SUCCESS' | 'PENDING' | 'FAIL_RETRIABLE' | 'FAIL_PERMANENT'; timestamp: string; deliveredToUsers?: string[]; internalError?: string; message?: string; reason?: string; }`\n - `text?: string`\n - `type?: string`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst message = await client.messages.retrieve('1343993', { chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com' });\n\nconsole.log(message);\n```", perLanguage: { typescript: { method: 'client.messages.retrieve', @@ -1132,7 +1545,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ cli: { method: 'messages retrieve', example: - "beeper-desktop-cli messages retrieve \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com' \\\n --message-id 1343993", + "beeper-desktop messages retrieve \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com' \\\n --message-id 1343993", }, php: { method: 'messages->retrieve', @@ -1157,7 +1570,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: "{ id: string; accountID: string; chatID: string; senderID: string; sortKey: string; timestamp: string; attachments?: object[]; editedTimestamp?: string; isDeleted?: boolean; isHidden?: boolean; isSender?: boolean; isUnread?: boolean; linkedMessageID?: string; links?: { title: string; url: string; favicon?: string; img?: string; imgSize?: object; originalURL?: string; summary?: string; }[]; mentions?: string[]; reactions?: object[]; seen?: boolean | string | object; senderName?: string; sendStatus?: { status: 'SUCCESS' | 'PENDING' | 'FAIL_RETRIABLE' | 'FAIL_PERMANENT'; timestamp: string; deliveredToUsers?: string[]; internalError?: string; message?: string; reason?: string; }; text?: string; type?: string; }", markdown: - "## update\n\n`client.messages.update(chatID: string, messageID: string, text: string): object`\n\n**put** `/v1/chats/{chatID}/messages/{messageID}`\n\nEdit the text content of an existing message. Messages with attachments cannot be edited.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.\n\n- `messageID: string`\n Message ID.\n\n- `text: string`\n New text content for the message\n\n### Returns\n\n- `{ id: string; accountID: string; chatID: string; senderID: string; sortKey: string; timestamp: string; attachments?: object[]; editedTimestamp?: string; isDeleted?: boolean; isHidden?: boolean; isSender?: boolean; isUnread?: boolean; linkedMessageID?: string; links?: { title: string; url: string; favicon?: string; img?: string; imgSize?: object; originalURL?: string; summary?: string; }[]; mentions?: string[]; reactions?: object[]; seen?: boolean | string | object; senderName?: string; sendStatus?: { status: 'SUCCESS' | 'PENDING' | 'FAIL_RETRIABLE' | 'FAIL_PERMANENT'; timestamp: string; deliveredToUsers?: string[]; internalError?: string; message?: string; reason?: string; }; text?: string; type?: string; }`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst message = await client.messages.update('1343993', { chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', text: 'x' });\n\nconsole.log(message);\n```", + "## update\n\n`client.messages.update(chatID: string, messageID: string, text: string): object`\n\n**put** `/v1/chats/{chatID}/messages/{messageID}`\n\nEdit the text content of an existing message. Messages with attachments cannot be edited.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this installation when available.\n\n- `messageID: string`\n Message ID.\n\n- `text: string`\n New text content for the message\n\n### Returns\n\n- `{ id: string; accountID: string; chatID: string; senderID: string; sortKey: string; timestamp: string; attachments?: object[]; editedTimestamp?: string; isDeleted?: boolean; isHidden?: boolean; isSender?: boolean; isUnread?: boolean; linkedMessageID?: string; links?: { title: string; url: string; favicon?: string; img?: string; imgSize?: object; originalURL?: string; summary?: string; }[]; mentions?: string[]; reactions?: object[]; seen?: boolean | string | object; senderName?: string; sendStatus?: { status: 'SUCCESS' | 'PENDING' | 'FAIL_RETRIABLE' | 'FAIL_PERMANENT'; timestamp: string; deliveredToUsers?: string[]; internalError?: string; message?: string; reason?: string; }; text?: string; type?: string; }`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst message = await client.messages.update('1343993', { chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', text: 'x' });\n\nconsole.log(message);\n```", perLanguage: { typescript: { method: 'client.messages.update', @@ -1177,7 +1590,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ cli: { method: 'messages update', example: - "beeper-desktop-cli messages update \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com' \\\n --message-id 1343993 \\\n --text x", + "beeper-desktop messages update \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com' \\\n --message-id 1343993 \\\n --text x", }, php: { method: 'messages->update', @@ -1201,7 +1614,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ qualified: 'client.messages.delete', params: ['chatID: string;', 'messageID: string;', 'forEveryone?: boolean;'], markdown: - "## delete\n\n`client.messages.delete(chatID: string, messageID: string, forEveryone?: boolean): void`\n\n**delete** `/v1/chats/{chatID}/messages/{messageID}`\n\nDelete a message by final message ID. Pending message IDs are not accepted because messages cannot be deleted while sending.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.\n\n- `messageID: string`\n Message ID.\n\n- `forEveryone?: boolean`\n True to request deletion for everyone when the network supports it; false to delete only for the authenticated user when supported.\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nawait client.messages.delete('1343993', { chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com' })\n```", + "## delete\n\n`client.messages.delete(chatID: string, messageID: string, forEveryone?: boolean): void`\n\n**delete** `/v1/chats/{chatID}/messages/{messageID}`\n\nDelete a message by final message ID. Pending message IDs are not accepted because messages cannot be deleted while sending.\n\n### Parameters\n\n- `chatID: string`\n Chat ID. Input routes also accept the local chat ID from this installation when available.\n\n- `messageID: string`\n Message ID.\n\n- `forEveryone?: boolean`\n True to request deletion for everyone when the network supports it; false to delete only for the authenticated user when supported.\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nawait client.messages.delete('1343993', { chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com' })\n```", perLanguage: { typescript: { method: 'client.messages.delete', @@ -1221,7 +1634,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ cli: { method: 'messages delete', example: - "beeper-desktop-cli messages delete \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com' \\\n --message-id 1343993", + "beeper-desktop messages delete \\\n --access-token 'My Access Token' \\\n --chat-id '!NCdzlIaMjZUmvmvyHU:beeper.com' \\\n --message-id 1343993", }, php: { method: 'messages->delete', @@ -1240,13 +1653,13 @@ const EMBEDDED_METHODS: MethodEntry[] = [ httpMethod: 'post', summary: 'Download a file', description: - 'Download a Matrix file using its mxc:// or localmxc:// URL to the device running Beeper Desktop and return the local file URL.', + 'Download a file from an mxc:// or localmxc:// URL to the device running the Beeper Client API and return the local file URL.', stainlessPath: '(resource) assets > (method) download', qualified: 'client.assets.download', params: ['url: string;'], response: '{ error?: string; srcURL?: string; }', markdown: - "## download\n\n`client.assets.download(url: string): { error?: string; srcURL?: string; }`\n\n**post** `/v1/assets/download`\n\nDownload a Matrix file using its mxc:// or localmxc:// URL to the device running Beeper Desktop and return the local file URL.\n\n### Parameters\n\n- `url: string`\n Matrix content URL (mxc:// or localmxc://) for the file to download.\n\n### Returns\n\n- `{ error?: string; srcURL?: string; }`\n\n - `error?: string`\n - `srcURL?: string`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.assets.download({ url: 'mxc://example.org/Q4x9CqGz1pB3Oa6XgJ' });\n\nconsole.log(response);\n```", + "## download\n\n`client.assets.download(url: string): { error?: string; srcURL?: string; }`\n\n**post** `/v1/assets/download`\n\nDownload a file from an mxc:// or localmxc:// URL to the device running the Beeper Client API and return the local file URL.\n\n### Parameters\n\n- `url: string`\n Beeper media URL (mxc:// or localmxc://) for the file to download.\n\n### Returns\n\n- `{ error?: string; srcURL?: string; }`\n\n - `error?: string`\n - `srcURL?: string`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.assets.download({ url: 'mxc://example.org/Q4x9CqGz1pB3Oa6XgJ' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.assets.download', @@ -1266,7 +1679,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ cli: { method: 'assets download', example: - "beeper-desktop-cli assets download \\\n --access-token 'My Access Token' \\\n --url mxc://example.org/Q4x9CqGz1pB3Oa6XgJ", + "beeper-desktop assets download \\\n --access-token 'My Access Token' \\\n --url mxc://example.org/Q4x9CqGz1pB3Oa6XgJ", }, php: { method: 'assets->download', @@ -1285,14 +1698,14 @@ const EMBEDDED_METHODS: MethodEntry[] = [ httpMethod: 'post', summary: 'Upload a file', description: - 'Upload a file to a temporary location using multipart/form-data. Returns an uploadID that can be referenced when sending a message or materializing a draft attachment.', + 'Upload a file to a temporary location using multipart/form-data. Returns an uploadID that can be referenced when sending a message or creating a draft attachment.', stainlessPath: '(resource) assets > (method) upload', qualified: 'client.assets.upload', params: ['file: string;', 'fileName?: string;', 'mimeType?: string;'], response: '{ duration?: number; error?: string; fileName?: string; fileSize?: number; height?: number; mimeType?: string; srcURL?: string; uploadID?: string; width?: number; }', markdown: - "## upload\n\n`client.assets.upload(file: string, fileName?: string, mimeType?: string): { duration?: number; error?: string; fileName?: string; fileSize?: number; height?: number; mimeType?: string; srcURL?: string; uploadID?: string; width?: number; }`\n\n**post** `/v1/assets/upload`\n\nUpload a file to a temporary location using multipart/form-data. Returns an uploadID that can be referenced when sending a message or materializing a draft attachment.\n\n### Parameters\n\n- `file: string`\n The file to upload (max 500 MB).\n\n- `fileName?: string`\n Original filename. Defaults to the uploaded file name if omitted\n\n- `mimeType?: string`\n MIME type. Auto-detected from magic bytes if omitted\n\n### Returns\n\n- `{ duration?: number; error?: string; fileName?: string; fileSize?: number; height?: number; mimeType?: string; srcURL?: string; uploadID?: string; width?: number; }`\n\n - `duration?: number`\n - `error?: string`\n - `fileName?: string`\n - `fileSize?: number`\n - `height?: number`\n - `mimeType?: string`\n - `srcURL?: string`\n - `uploadID?: string`\n - `width?: number`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.assets.upload({ file: fs.createReadStream('path/to/file') });\n\nconsole.log(response);\n```", + "## upload\n\n`client.assets.upload(file: string, fileName?: string, mimeType?: string): { duration?: number; error?: string; fileName?: string; fileSize?: number; height?: number; mimeType?: string; srcURL?: string; uploadID?: string; width?: number; }`\n\n**post** `/v1/assets/upload`\n\nUpload a file to a temporary location using multipart/form-data. Returns an uploadID that can be referenced when sending a message or creating a draft attachment.\n\n### Parameters\n\n- `file: string`\n The file to upload (max 500 MB).\n\n- `fileName?: string`\n Original filename. Defaults to the uploaded file name if omitted\n\n- `mimeType?: string`\n MIME type. Auto-detected from magic bytes if omitted\n\n### Returns\n\n- `{ duration?: number; error?: string; fileName?: string; fileSize?: number; height?: number; mimeType?: string; srcURL?: string; uploadID?: string; width?: number; }`\n\n - `duration?: number`\n - `error?: string`\n - `fileName?: string`\n - `fileSize?: number`\n - `height?: number`\n - `mimeType?: string`\n - `srcURL?: string`\n - `uploadID?: string`\n - `width?: number`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.assets.upload({ file: fs.createReadStream('path/to/file') });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.assets.upload', @@ -1312,7 +1725,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ cli: { method: 'assets upload', example: - "beeper-desktop-cli assets upload \\\n --access-token 'My Access Token' \\\n --file 'Example data'", + "beeper-desktop assets upload \\\n --access-token 'My Access Token' \\\n --file 'Example data'", }, php: { method: 'assets->upload', @@ -1331,14 +1744,14 @@ const EMBEDDED_METHODS: MethodEntry[] = [ httpMethod: 'post', summary: 'Upload a file (base64)', description: - 'Upload a file using a JSON body with base64-encoded content. Returns an uploadID that can be referenced when sending a message or materializing a draft attachment. Alternative to the multipart upload endpoint.', + 'Upload a file using a JSON body with base64-encoded content. Returns an uploadID that can be referenced when sending a message or creating a draft attachment. Alternative to the multipart upload endpoint.', stainlessPath: '(resource) assets > (method) upload_base64', qualified: 'client.assets.uploadBase64', params: ['content: string;', 'fileName?: string;', 'mimeType?: string;'], response: '{ duration?: number; error?: string; fileName?: string; fileSize?: number; height?: number; mimeType?: string; srcURL?: string; uploadID?: string; width?: number; }', markdown: - "## upload_base64\n\n`client.assets.uploadBase64(content: string, fileName?: string, mimeType?: string): { duration?: number; error?: string; fileName?: string; fileSize?: number; height?: number; mimeType?: string; srcURL?: string; uploadID?: string; width?: number; }`\n\n**post** `/v1/assets/upload/base64`\n\nUpload a file using a JSON body with base64-encoded content. Returns an uploadID that can be referenced when sending a message or materializing a draft attachment. Alternative to the multipart upload endpoint.\n\n### Parameters\n\n- `content: string`\n Base64-encoded file content (max ~500MB decoded)\n\n- `fileName?: string`\n Original filename. Generated if omitted\n\n- `mimeType?: string`\n MIME type. Auto-detected from magic bytes if omitted\n\n### Returns\n\n- `{ duration?: number; error?: string; fileName?: string; fileSize?: number; height?: number; mimeType?: string; srcURL?: string; uploadID?: string; width?: number; }`\n\n - `duration?: number`\n - `error?: string`\n - `fileName?: string`\n - `fileSize?: number`\n - `height?: number`\n - `mimeType?: string`\n - `srcURL?: string`\n - `uploadID?: string`\n - `width?: number`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.assets.uploadBase64({ content: 'x' });\n\nconsole.log(response);\n```", + "## upload_base64\n\n`client.assets.uploadBase64(content: string, fileName?: string, mimeType?: string): { duration?: number; error?: string; fileName?: string; fileSize?: number; height?: number; mimeType?: string; srcURL?: string; uploadID?: string; width?: number; }`\n\n**post** `/v1/assets/upload/base64`\n\nUpload a file using a JSON body with base64-encoded content. Returns an uploadID that can be referenced when sending a message or creating a draft attachment. Alternative to the multipart upload endpoint.\n\n### Parameters\n\n- `content: string`\n Base64-encoded file content (max ~500MB decoded)\n\n- `fileName?: string`\n Original filename. Generated if omitted\n\n- `mimeType?: string`\n MIME type. Auto-detected from magic bytes if omitted\n\n### Returns\n\n- `{ duration?: number; error?: string; fileName?: string; fileSize?: number; height?: number; mimeType?: string; srcURL?: string; uploadID?: string; width?: number; }`\n\n - `duration?: number`\n - `error?: string`\n - `fileName?: string`\n - `fileSize?: number`\n - `height?: number`\n - `mimeType?: string`\n - `srcURL?: string`\n - `uploadID?: string`\n - `width?: number`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.assets.uploadBase64({ content: 'x' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.assets.uploadBase64', @@ -1358,7 +1771,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ cli: { method: 'assets upload_base64', example: - "beeper-desktop-cli assets upload-base64 \\\n --access-token 'My Access Token' \\\n --content x", + "beeper-desktop assets upload-base64 \\\n --access-token 'My Access Token' \\\n --content x", }, php: { method: 'assets->uploadBase64', @@ -1402,7 +1815,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ }, cli: { method: 'assets serve', - example: "beeper-desktop-cli assets serve \\\n --access-token 'My Access Token' \\\n --url x", + example: "beeper-desktop assets serve \\\n --access-token 'My Access Token' \\\n --url x", }, php: { method: 'assets->serve', @@ -1421,13 +1834,13 @@ const EMBEDDED_METHODS: MethodEntry[] = [ httpMethod: 'get', summary: 'Retrieve server info', description: - 'Returns app, platform, server, endpoint discovery, OAuth, and WebSocket metadata for this Beeper Desktop instance.', + 'Returns app, platform, server, endpoint discovery, OAuth, and WebSocket metadata for this Beeper Client API server.', stainlessPath: '(resource) info > (method) retrieve', qualified: 'client.info.retrieve', response: '{ app: { bundle_id: string; name: string; version: string; }; endpoints: { mcp: string; oauth: { authorization_endpoint: string; introspection_endpoint: string; registration_endpoint: string; revocation_endpoint: string; token_endpoint: string; userinfo_endpoint: string; }; spec: string; ws_events: string; }; platform: { arch: string; os: string; release?: string; }; server: { base_url: string; hostname: string; mcp_enabled: boolean; port: number; remote_access: boolean; status: string; }; }', markdown: - "## retrieve\n\n`client.info.retrieve(): { app: object; endpoints: object; platform: object; server: object; }`\n\n**get** `/v1/info`\n\nReturns app, platform, server, endpoint discovery, OAuth, and WebSocket metadata for this Beeper Desktop instance.\n\n### Returns\n\n- `{ app: { bundle_id: string; name: string; version: string; }; endpoints: { mcp: string; oauth: { authorization_endpoint: string; introspection_endpoint: string; registration_endpoint: string; revocation_endpoint: string; token_endpoint: string; userinfo_endpoint: string; }; spec: string; ws_events: string; }; platform: { arch: string; os: string; release?: string; }; server: { base_url: string; hostname: string; mcp_enabled: boolean; port: number; remote_access: boolean; status: string; }; }`\n\n - `app: { bundle_id: string; name: string; version: string; }`\n - `endpoints: { mcp: string; oauth: { authorization_endpoint: string; introspection_endpoint: string; registration_endpoint: string; revocation_endpoint: string; token_endpoint: string; userinfo_endpoint: string; }; spec: string; ws_events: string; }`\n - `platform: { arch: string; os: string; release?: string; }`\n - `server: { base_url: string; hostname: string; mcp_enabled: boolean; port: number; remote_access: boolean; status: string; }`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst info = await client.info.retrieve();\n\nconsole.log(info);\n```", + "## retrieve\n\n`client.info.retrieve(): { app: object; endpoints: object; platform: object; server: object; }`\n\n**get** `/v1/info`\n\nReturns app, platform, server, endpoint discovery, OAuth, and WebSocket metadata for this Beeper Client API server.\n\n### Returns\n\n- `{ app: { bundle_id: string; name: string; version: string; }; endpoints: { mcp: string; oauth: { authorization_endpoint: string; introspection_endpoint: string; registration_endpoint: string; revocation_endpoint: string; token_endpoint: string; userinfo_endpoint: string; }; spec: string; ws_events: string; }; platform: { arch: string; os: string; release?: string; }; server: { base_url: string; hostname: string; mcp_enabled: boolean; port: number; remote_access: boolean; status: string; }; }`\n\n - `app: { bundle_id: string; name: string; version: string; }`\n - `endpoints: { mcp: string; oauth: { authorization_endpoint: string; introspection_endpoint: string; registration_endpoint: string; revocation_endpoint: string; token_endpoint: string; userinfo_endpoint: string; }; spec: string; ws_events: string; }`\n - `platform: { arch: string; os: string; release?: string; }`\n - `server: { base_url: string; hostname: string; mcp_enabled: boolean; port: number; remote_access: boolean; status: string; }`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst info = await client.info.retrieve();\n\nconsole.log(info);\n```", perLanguage: { typescript: { method: 'client.info.retrieve', @@ -1446,7 +1859,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ }, cli: { method: 'info retrieve', - example: "beeper-desktop-cli info retrieve \\\n --access-token 'My Access Token'", + example: "beeper-desktop info retrieve \\\n --access-token 'My Access Token'", }, php: { method: 'info->retrieve', @@ -1459,13 +1872,772 @@ const EMBEDDED_METHODS: MethodEntry[] = [ }, }, }, + { + name: 'session', + endpoint: '/v1/app/setup', + httpMethod: 'get', + summary: 'Get Beeper app setup state', + description: + 'Return the current Beeper Desktop or Beeper Server sign-in and encrypted messaging setup state. This endpoint is public before sign-in so apps can discover that sign-in is needed; after sign-in, pass a read token.', + stainlessPath: '(resource) app > (method) session', + qualified: 'client.app.session', + response: + "{ e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: { masterKey: boolean; megolmBackupKey: boolean; recoveryKey: boolean; selfSigningKey: boolean; userSigningKey: boolean; }; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }; }", + markdown: + "## session\n\n`client.app.session(): { e2ee: object; state: string; matrix?: object; verification?: object; }`\n\n**get** `/v1/app/setup`\n\nReturn the current Beeper Desktop or Beeper Server sign-in and encrypted messaging setup state. This endpoint is public before sign-in so apps can discover that sign-in is needed; after sign-in, pass a read token.\n\n### Returns\n\n- `{ e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: { masterKey: boolean; megolmBackupKey: boolean; recoveryKey: boolean; selfSigningKey: boolean; userSigningKey: boolean; }; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }; }`\n\n - `e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: { masterKey: boolean; megolmBackupKey: boolean; recoveryKey: boolean; selfSigningKey: boolean; userSigningKey: boolean; }; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }`\n - `state: string`\n - `matrix?: { deviceID: string; homeserver: string; userID: string; }`\n - `verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.app.session();\n\nconsole.log(response);\n```", + perLanguage: { + typescript: { + method: 'client.app.session', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop({\n accessToken: process.env['BEEPER_ACCESS_TOKEN'], // This is the default and can be omitted\n});\n\nconst response = await client.app.session();\n\nconsole.log(response.e2ee);", + }, + python: { + method: 'app.session', + example: + 'import os\nfrom beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop(\n access_token=os.environ.get("BEEPER_ACCESS_TOKEN"), # This is the default and can be omitted\n)\nresponse = client.app.session()\nprint(response.e2ee)', + }, + go: { + method: 'client.App.Session', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\tresponse, err := client.App.Session(context.TODO())\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.E2EE)\n}\n', + }, + cli: { + method: 'app session', + example: "beeper-desktop app session \\\n --access-token 'My Access Token'", + }, + php: { + method: 'app->session', + example: + "app->session();\n\nvar_dump($response);", + }, + http: { + example: + 'curl http://localhost:23373/v1/app/setup \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN"', + }, + }, + }, + { + name: 'start', + endpoint: '/v1/app/setup/start', + httpMethod: 'post', + summary: 'Start Beeper app setup', + description: + 'Start setting up Beeper Desktop or Beeper Server. The flow supports existing Beeper accounts and new account creation.', + stainlessPath: '(resource) app.login > (method) start', + qualified: 'client.app.login.start', + response: '{ setupRequestID: string; signInMethods: string[]; }', + markdown: + "## start\n\n`client.app.login.start(): { setupRequestID: string; signInMethods: string[]; }`\n\n**post** `/v1/app/setup/start`\n\nStart setting up Beeper Desktop or Beeper Server. The flow supports existing Beeper accounts and new account creation.\n\n### Returns\n\n- `{ setupRequestID: string; signInMethods: string[]; }`\n\n - `setupRequestID: string`\n - `signInMethods: string[]`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.app.login.start();\n\nconsole.log(response);\n```", + perLanguage: { + typescript: { + method: 'client.app.login.start', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.app.login.start();\n\nconsole.log(response.setupRequestID);", + }, + python: { + method: 'app.login.start', + example: + 'from beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop()\nresponse = client.app.login.start()\nprint(response.setup_request_id)', + }, + go: { + method: 'client.App.Login.Start', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\tresponse, err := client.App.Login.Start(context.TODO())\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.SetupRequestID)\n}\n', + }, + cli: { + method: 'login start', + example: "beeper-desktop app:login start \\\n --access-token 'My Access Token'", + }, + php: { + method: 'app->login->start', + example: + "app->login->start();\n\nvar_dump($response);", + }, + http: { + example: + 'curl http://localhost:23373/v1/app/setup/start \\\n -X POST \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN"', + }, + }, + }, + { + name: 'email', + endpoint: '/v1/app/setup/email', + httpMethod: 'post', + summary: 'Send setup sign-in code', + description: 'Send a sign-in code to the user email address for app setup.', + stainlessPath: '(resource) app.login > (method) email', + qualified: 'client.app.login.email', + params: ['email: string;', 'setupRequestID: string;'], + markdown: + "## email\n\n`client.app.login.email(email: string, setupRequestID: string): void`\n\n**post** `/v1/app/setup/email`\n\nSend a sign-in code to the user email address for app setup.\n\n### Parameters\n\n- `email: string`\n Email address to send the sign-in code to.\n\n- `setupRequestID: string`\n Setup request ID returned by the start step.\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nawait client.app.login.email({ email: 'dev@stainless.com', setupRequestID: 'setupRequestID' })\n```", + perLanguage: { + typescript: { + method: 'client.app.login.email', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nawait client.app.login.email({ email: 'dev@stainless.com', setupRequestID: 'setupRequestID' });", + }, + python: { + method: 'app.login.email', + example: + 'from beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop()\nclient.app.login.email(\n email="dev@stainless.com",\n setup_request_id="setupRequestID",\n)', + }, + go: { + method: 'client.App.Login.Email', + example: + 'package main\n\nimport (\n\t"context"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\terr := client.App.Login.Email(context.TODO(), beeperdesktopapi.AppLoginEmailParams{\n\t\tEmail: "dev@stainless.com",\n\t\tSetupRequestID: "setupRequestID",\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n}\n', + }, + cli: { + method: 'login email', + example: + "beeper-desktop app:login email \\\n --access-token 'My Access Token' \\\n --email dev@stainless.com \\\n --setup-request-id setupRequestID", + }, + php: { + method: 'app->login->email', + example: + "app->login->email(\n email: 'dev@stainless.com', setupRequestID: 'setupRequestID'\n);\n\nvar_dump($result);", + }, + http: { + example: + 'curl http://localhost:23373/v1/app/setup/email \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN" \\\n -d \'{\n "email": "dev@stainless.com",\n "setupRequestID": "setupRequestID"\n }\'', + }, + }, + }, + { + name: 'response', + endpoint: '/v1/app/setup/response', + httpMethod: 'post', + summary: 'Complete setup sign-in with code', + description: + 'Finish setup sign-in with the code sent to the user email address. If the user needs a new account, the response includes account creation copy and username suggestions.', + stainlessPath: '(resource) app.login > (method) response', + qualified: 'client.app.login.response', + params: ['response: string;', 'setupRequestID: string;'], + response: + "{ matrix: { accessToken: string; deviceID: string; homeserver: string; userID: string; }; session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: object; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }; } | { copy: { submit: 'Continue'; terms: 'By continuing, you agree to the Terms of Use and acknowledge the Privacy Policy.'; title: 'Choose your username'; usernamePlaceholder: 'Username'; }; leadToken: string; registrationRequired: true; setupRequestID: string; usernameSuggestions?: string[]; }", + markdown: + "## response\n\n`client.app.login.response(response: string, setupRequestID: string): { matrix: object; session: object; } | { copy: object; leadToken: string; registrationRequired: true; setupRequestID: string; usernameSuggestions?: string[]; }`\n\n**post** `/v1/app/setup/response`\n\nFinish setup sign-in with the code sent to the user email address. If the user needs a new account, the response includes account creation copy and username suggestions.\n\n### Parameters\n\n- `response: string`\n Sign-in code from the user email.\n\n- `setupRequestID: string`\n Setup request ID returned by the start step.\n\n### Returns\n\n- `{ matrix: { accessToken: string; deviceID: string; homeserver: string; userID: string; }; session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: object; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }; } | { copy: { submit: 'Continue'; terms: 'By continuing, you agree to the Terms of Use and acknowledge the Privacy Policy.'; title: 'Choose your username'; usernamePlaceholder: 'Username'; }; leadToken: string; registrationRequired: true; setupRequestID: string; usernameSuggestions?: string[]; }`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.app.login.response({ response: 'response', setupRequestID: 'setupRequestID' });\n\nconsole.log(response);\n```", + perLanguage: { + typescript: { + method: 'client.app.login.response', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.app.login.response({\n response: 'response',\n setupRequestID: 'setupRequestID',\n});\n\nconsole.log(response);", + }, + python: { + method: 'app.login.response', + example: + 'from beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop()\nresponse = client.app.login.response(\n response="response",\n setup_request_id="setupRequestID",\n)\nprint(response)', + }, + go: { + method: 'client.App.Login.Response', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\tresponse, err := client.App.Login.Response(context.TODO(), beeperdesktopapi.AppLoginResponseParams{\n\t\tResponse: "response",\n\t\tSetupRequestID: "setupRequestID",\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response)\n}\n', + }, + cli: { + method: 'login response', + example: + "beeper-desktop app:login response \\\n --access-token 'My Access Token' \\\n --response response \\\n --setup-request-id setupRequestID", + }, + php: { + method: 'app->login->response', + example: + "app->login->response(\n response: 'response', setupRequestID: 'setupRequestID'\n);\n\nvar_dump($response);", + }, + http: { + example: + 'curl http://localhost:23373/v1/app/setup/response \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN" \\\n -d \'{\n "response": "response",\n "setupRequestID": "setupRequestID"\n }\'', + }, + }, + }, + { + name: 'register', + endpoint: '/v1/app/setup/register', + httpMethod: 'post', + summary: 'Create account for setup', + description: 'Create a Beeper account after the user chooses a username and accepts the Terms of Use.', + stainlessPath: '(resource) app.login > (method) register', + qualified: 'client.app.login.register', + params: ['acceptTerms: true;', 'leadToken: string;', 'setupRequestID: string;', 'username: string;'], + response: + "{ matrix: { accessToken: string; deviceID: string; homeserver: string; userID: string; }; session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: object; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }; }", + markdown: + "## register\n\n`client.app.login.register(acceptTerms: true, leadToken: string, setupRequestID: string, username: string): { matrix: object; session: object; }`\n\n**post** `/v1/app/setup/register`\n\nCreate a Beeper account after the user chooses a username and accepts the Terms of Use.\n\n### Parameters\n\n- `acceptTerms: true`\n Confirms that the user agreed to our [terms of use](https://www.beeper.com/terms-onboarding) and has read our [privacy policy](https://www.beeper.com/privacy).\n\n- `leadToken: string`\n Registration token returned by Beeper.\n\n- `setupRequestID: string`\n Setup request ID returned by the start step.\n\n- `username: string`\n Username selected by the user.\n\n### Returns\n\n- `{ matrix: { accessToken: string; deviceID: string; homeserver: string; userID: string; }; session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: object; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }; }`\n\n - `matrix: { accessToken: string; deviceID: string; homeserver: string; userID: string; }`\n - `session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: { masterKey: boolean; megolmBackupKey: boolean; recoveryKey: boolean; selfSigningKey: boolean; userSigningKey: boolean; }; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }; }`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.app.login.register({\n acceptTerms: true,\n leadToken: 'leadToken',\n setupRequestID: 'setupRequestID',\n username: 'x',\n});\n\nconsole.log(response);\n```", + perLanguage: { + typescript: { + method: 'client.app.login.register', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.app.login.register({\n acceptTerms: true,\n leadToken: 'leadToken',\n setupRequestID: 'setupRequestID',\n username: 'x',\n});\n\nconsole.log(response.matrix);", + }, + python: { + method: 'app.login.register', + example: + 'from beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop()\nresponse = client.app.login.register(\n accept_terms=True,\n lead_token="leadToken",\n setup_request_id="setupRequestID",\n username="x",\n)\nprint(response.matrix)', + }, + go: { + method: 'client.App.Login.Register', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\tresponse, err := client.App.Login.Register(context.TODO(), beeperdesktopapi.AppLoginRegisterParams{\n\t\tAcceptTerms: true,\n\t\tLeadToken: "leadToken",\n\t\tSetupRequestID: "setupRequestID",\n\t\tUsername: "x",\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Matrix)\n}\n', + }, + cli: { + method: 'login register', + example: + "beeper-desktop app:login register \\\n --access-token 'My Access Token' \\\n --accept-terms true \\\n --lead-token leadToken \\\n --setup-request-id setupRequestID \\\n --username x", + }, + php: { + method: 'app->login->register', + example: + "app->login->register(\n acceptTerms: true,\n leadToken: 'leadToken',\n setupRequestID: 'setupRequestID',\n username: 'x',\n);\n\nvar_dump($response);", + }, + http: { + example: + 'curl http://localhost:23373/v1/app/setup/register \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN" \\\n -d \'{\n "acceptTerms": true,\n "leadToken": "leadToken",\n "setupRequestID": "setupRequestID",\n "username": "x"\n }\'', + }, + }, + }, + { + name: 'verify', + endpoint: '/v1/app/setup/verification/recovery-key', + httpMethod: 'post', + summary: 'Verify with recovery key', + description: 'Unlock encrypted messages with the user recovery key.', + stainlessPath: '(resource) app.login.verification.recovery_key > (method) verify', + qualified: 'client.app.login.verification.recoveryKey.verify', + params: ['recoveryKey: string;'], + response: + "{ session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: object; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }; }", + markdown: + "## verify\n\n`client.app.login.verification.recoveryKey.verify(recoveryKey: string): { session: object; }`\n\n**post** `/v1/app/setup/verification/recovery-key`\n\nUnlock encrypted messages with the user recovery key.\n\n### Parameters\n\n- `recoveryKey: string`\n Recovery key saved by the user.\n\n### Returns\n\n- `{ session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: object; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }; }`\n\n - `session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: { masterKey: boolean; megolmBackupKey: boolean; recoveryKey: boolean; selfSigningKey: boolean; userSigningKey: boolean; }; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }; }`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.app.login.verification.recoveryKey.verify({ recoveryKey: 'x' });\n\nconsole.log(response);\n```", + perLanguage: { + typescript: { + method: 'client.app.login.verification.recoveryKey.verify', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop({\n accessToken: process.env['BEEPER_ACCESS_TOKEN'], // This is the default and can be omitted\n});\n\nconst response = await client.app.login.verification.recoveryKey.verify({ recoveryKey: 'x' });\n\nconsole.log(response.session);", + }, + python: { + method: 'app.login.verification.recovery_key.verify', + example: + 'import os\nfrom beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop(\n access_token=os.environ.get("BEEPER_ACCESS_TOKEN"), # This is the default and can be omitted\n)\nresponse = client.app.login.verification.recovery_key.verify(\n recovery_key="x",\n)\nprint(response.session)', + }, + go: { + method: 'client.App.Login.Verification.RecoveryKey.Verify', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\tresponse, err := client.App.Login.Verification.RecoveryKey.Verify(context.TODO(), beeperdesktopapi.AppLoginVerificationRecoveryKeyVerifyParams{\n\t\tRecoveryKey: "x",\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Session)\n}\n', + }, + cli: { + method: 'recovery_key verify', + example: + "beeper-desktop app:login:verification:recovery-key verify \\\n --access-token 'My Access Token' \\\n --recovery-key x", + }, + php: { + method: 'app->login->verification->recoveryKey->verify', + example: + "app->login->verification->recoveryKey->verify(\n recoveryKey: 'x'\n);\n\nvar_dump($response);", + }, + http: { + example: + 'curl http://localhost:23373/v1/app/setup/verification/recovery-key \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN" \\\n -d \'{\n "recoveryKey": "x"\n }\'', + }, + }, + }, + { + name: 'create', + endpoint: '/v1/app/setup/verification/recovery-key/reset', + httpMethod: 'post', + summary: 'Create new recovery key', + description: 'Create a new recovery key when the user cannot use the existing one.', + stainlessPath: '(resource) app.login.verification.recovery_key.reset > (method) create', + qualified: 'client.app.login.verification.recoveryKey.reset.create', + params: ['existingRecoveryKey?: string;'], + response: + "{ recoveryKey: string; session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: object; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }; }", + markdown: + "## create\n\n`client.app.login.verification.recoveryKey.reset.create(existingRecoveryKey?: string): { recoveryKey: string; session: object; }`\n\n**post** `/v1/app/setup/verification/recovery-key/reset`\n\nCreate a new recovery key when the user cannot use the existing one.\n\n### Parameters\n\n- `existingRecoveryKey?: string`\n Existing recovery key, if the user has it.\n\n### Returns\n\n- `{ recoveryKey: string; session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: object; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }; }`\n\n - `recoveryKey: string`\n - `session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: { masterKey: boolean; megolmBackupKey: boolean; recoveryKey: boolean; selfSigningKey: boolean; userSigningKey: boolean; }; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }; }`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst reset = await client.app.login.verification.recoveryKey.reset.create();\n\nconsole.log(reset);\n```", + perLanguage: { + typescript: { + method: 'client.app.login.verification.recoveryKey.reset.create', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop({\n accessToken: process.env['BEEPER_ACCESS_TOKEN'], // This is the default and can be omitted\n});\n\nconst reset = await client.app.login.verification.recoveryKey.reset.create();\n\nconsole.log(reset.recoveryKey);", + }, + python: { + method: 'app.login.verification.recovery_key.reset.create', + example: + 'import os\nfrom beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop(\n access_token=os.environ.get("BEEPER_ACCESS_TOKEN"), # This is the default and can be omitted\n)\nreset = client.app.login.verification.recovery_key.reset.create()\nprint(reset.recovery_key)', + }, + go: { + method: 'client.App.Login.Verification.RecoveryKey.Reset.New', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\treset, err := client.App.Login.Verification.RecoveryKey.Reset.New(context.TODO(), beeperdesktopapi.AppLoginVerificationRecoveryKeyResetNewParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", reset.RecoveryKey)\n}\n', + }, + cli: { + method: 'reset create', + example: + "beeper-desktop app:login:verification:recovery-key:reset create \\\n --access-token 'My Access Token'", + }, + php: { + method: 'app->login->verification->recoveryKey->reset->create', + example: + "app->login->verification->recoveryKey->reset->create(\n existingRecoveryKey: 'existingRecoveryKey'\n);\n\nvar_dump($reset);", + }, + http: { + example: + 'curl http://localhost:23373/v1/app/setup/verification/recovery-key/reset \\\n -X POST \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN"', + }, + }, + }, + { + name: 'confirm', + endpoint: '/v1/app/setup/verification/recovery-key/reset/confirm', + httpMethod: 'post', + summary: 'Confirm new recovery key', + description: 'Confirm that the new recovery key should be used for this account.', + stainlessPath: '(resource) app.login.verification.recovery_key.reset > (method) confirm', + qualified: 'client.app.login.verification.recoveryKey.reset.confirm', + params: ['recoveryKey: string;'], + response: + "{ session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: object; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }; }", + markdown: + "## confirm\n\n`client.app.login.verification.recoveryKey.reset.confirm(recoveryKey: string): { session: object; }`\n\n**post** `/v1/app/setup/verification/recovery-key/reset/confirm`\n\nConfirm that the new recovery key should be used for this account.\n\n### Parameters\n\n- `recoveryKey: string`\n New recovery key returned by the reset step.\n\n### Returns\n\n- `{ session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: object; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }; }`\n\n - `session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: { masterKey: boolean; megolmBackupKey: boolean; recoveryKey: boolean; selfSigningKey: boolean; userSigningKey: boolean; }; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }; }`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.app.login.verification.recoveryKey.reset.confirm({ recoveryKey: 'x' });\n\nconsole.log(response);\n```", + perLanguage: { + typescript: { + method: 'client.app.login.verification.recoveryKey.reset.confirm', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop({\n accessToken: process.env['BEEPER_ACCESS_TOKEN'], // This is the default and can be omitted\n});\n\nconst response = await client.app.login.verification.recoveryKey.reset.confirm({\n recoveryKey: 'x',\n});\n\nconsole.log(response.session);", + }, + python: { + method: 'app.login.verification.recovery_key.reset.confirm', + example: + 'import os\nfrom beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop(\n access_token=os.environ.get("BEEPER_ACCESS_TOKEN"), # This is the default and can be omitted\n)\nresponse = client.app.login.verification.recovery_key.reset.confirm(\n recovery_key="x",\n)\nprint(response.session)', + }, + go: { + method: 'client.App.Login.Verification.RecoveryKey.Reset.Confirm', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\tresponse, err := client.App.Login.Verification.RecoveryKey.Reset.Confirm(context.TODO(), beeperdesktopapi.AppLoginVerificationRecoveryKeyResetConfirmParams{\n\t\tRecoveryKey: "x",\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Session)\n}\n', + }, + cli: { + method: 'reset confirm', + example: + "beeper-desktop app:login:verification:recovery-key:reset confirm \\\n --access-token 'My Access Token' \\\n --recovery-key x", + }, + php: { + method: 'app->login->verification->recoveryKey->reset->confirm', + example: + "app->login->verification->recoveryKey->reset->confirm(\n recoveryKey: 'x'\n);\n\nvar_dump($response);", + }, + http: { + example: + 'curl http://localhost:23373/v1/app/setup/verification/recovery-key/reset/confirm \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN" \\\n -d \'{\n "recoveryKey": "x"\n }\'', + }, + }, + }, + { + name: 'list', + endpoint: '/v1/app/setup/verifications', + httpMethod: 'get', + summary: 'List active verifications', + description: + 'List pending and active device verifications. Use this to recover state without a WebSocket connection.', + stainlessPath: '(resource) app.verifications > (method) list', + qualified: 'client.app.verifications.list', + response: + "{ items: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }[]; }", + markdown: + "## list\n\n`client.app.verifications.list(): { items: object[]; }`\n\n**get** `/v1/app/setup/verifications`\n\nList pending and active device verifications. Use this to recover state without a WebSocket connection.\n\n### Returns\n\n- `{ items: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }[]; }`\n\n - `items: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }[]`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst verifications = await client.app.verifications.list();\n\nconsole.log(verifications);\n```", + perLanguage: { + typescript: { + method: 'client.app.verifications.list', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop({\n accessToken: process.env['BEEPER_ACCESS_TOKEN'], // This is the default and can be omitted\n});\n\nconst verifications = await client.app.verifications.list();\n\nconsole.log(verifications.items);", + }, + python: { + method: 'app.verifications.list', + example: + 'import os\nfrom beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop(\n access_token=os.environ.get("BEEPER_ACCESS_TOKEN"), # This is the default and can be omitted\n)\nverifications = client.app.verifications.list()\nprint(verifications.items)', + }, + go: { + method: 'client.App.Verifications.List', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\tverifications, err := client.App.Verifications.List(context.TODO())\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", verifications.Items)\n}\n', + }, + cli: { + method: 'verifications list', + example: "beeper-desktop app:verifications list \\\n --access-token 'My Access Token'", + }, + php: { + method: 'app->verifications->list', + example: + "app->verifications->list();\n\nvar_dump($verifications);", + }, + http: { + example: + 'curl http://localhost:23373/v1/app/setup/verifications \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN"', + }, + }, + }, + { + name: 'create', + endpoint: '/v1/app/setup/verifications', + httpMethod: 'post', + summary: 'Start device verification', + description: 'Start verifying this device from another signed-in device.', + stainlessPath: '(resource) app.verifications > (method) create', + qualified: 'client.app.verifications.create', + params: ["purpose?: 'login' | 'device';", 'userID?: string;'], + response: + "{ session: { e2ee: object; state: string; matrix?: object; verification?: object; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }", + markdown: + "## create\n\n`client.app.verifications.create(purpose?: 'login' | 'device', userID?: string): { session: object; verification?: object; }`\n\n**post** `/v1/app/setup/verifications`\n\nStart verifying this device from another signed-in device.\n\n### Parameters\n\n- `purpose?: 'login' | 'device'`\n Why this verification is being started.\n\n- `userID?: string`\n Beeper user ID to verify. Defaults to the signed-in user.\n\n### Returns\n\n- `{ session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: object; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }; }`\n\n - `session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: { masterKey: boolean; megolmBackupKey: boolean; recoveryKey: boolean; selfSigningKey: boolean; userSigningKey: boolean; }; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }; }`\n - `verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst verification = await client.app.verifications.create();\n\nconsole.log(verification);\n```", + perLanguage: { + typescript: { + method: 'client.app.verifications.create', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop({\n accessToken: process.env['BEEPER_ACCESS_TOKEN'], // This is the default and can be omitted\n});\n\nconst verification = await client.app.verifications.create();\n\nconsole.log(verification.session);", + }, + python: { + method: 'app.verifications.create', + example: + 'import os\nfrom beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop(\n access_token=os.environ.get("BEEPER_ACCESS_TOKEN"), # This is the default and can be omitted\n)\nverification = client.app.verifications.create()\nprint(verification.session)', + }, + go: { + method: 'client.App.Verifications.New', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\tverification, err := client.App.Verifications.New(context.TODO(), beeperdesktopapi.AppVerificationNewParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", verification.Session)\n}\n', + }, + cli: { + method: 'verifications create', + example: "beeper-desktop app:verifications create \\\n --access-token 'My Access Token'", + }, + php: { + method: 'app->verifications->create', + example: + "app->verifications->create(\n purpose: 'login', userID: 'userID'\n);\n\nvar_dump($verification);", + }, + http: { + example: + 'curl http://localhost:23373/v1/app/setup/verifications \\\n -X POST \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN"', + }, + }, + }, + { + name: 'retrieve', + endpoint: '/v1/app/setup/verifications/{verificationID}', + httpMethod: 'get', + summary: 'Get verification', + description: 'Get the current state of a device verification transaction.', + stainlessPath: '(resource) app.verifications > (method) retrieve', + qualified: 'client.app.verifications.retrieve', + params: ['verificationID: string;'], + response: + "{ session: { e2ee: object; state: string; matrix?: object; verification?: object; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }", + markdown: + "## retrieve\n\n`client.app.verifications.retrieve(verificationID: string): { session: object; verification?: object; }`\n\n**get** `/v1/app/setup/verifications/{verificationID}`\n\nGet the current state of a device verification transaction.\n\n### Parameters\n\n- `verificationID: string`\n Verification ID.\n\n### Returns\n\n- `{ session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: object; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }; }`\n\n - `session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: { masterKey: boolean; megolmBackupKey: boolean; recoveryKey: boolean; selfSigningKey: boolean; userSigningKey: boolean; }; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }; }`\n - `verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst verification = await client.app.verifications.retrieve('x');\n\nconsole.log(verification);\n```", + perLanguage: { + typescript: { + method: 'client.app.verifications.retrieve', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop({\n accessToken: process.env['BEEPER_ACCESS_TOKEN'], // This is the default and can be omitted\n});\n\nconst verification = await client.app.verifications.retrieve('x');\n\nconsole.log(verification.session);", + }, + python: { + method: 'app.verifications.retrieve', + example: + 'import os\nfrom beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop(\n access_token=os.environ.get("BEEPER_ACCESS_TOKEN"), # This is the default and can be omitted\n)\nverification = client.app.verifications.retrieve(\n "x",\n)\nprint(verification.session)', + }, + go: { + method: 'client.App.Verifications.Get', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\tverification, err := client.App.Verifications.Get(context.TODO(), "x")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", verification.Session)\n}\n', + }, + cli: { + method: 'verifications retrieve', + example: + "beeper-desktop app:verifications retrieve \\\n --access-token 'My Access Token' \\\n --verification-id x", + }, + php: { + method: 'app->verifications->retrieve', + example: + "app->verifications->retrieve('x');\n\nvar_dump($verification);", + }, + http: { + example: + 'curl http://localhost:23373/v1/app/setup/verifications/$VERIFICATION_ID \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN"', + }, + }, + }, + { + name: 'accept', + endpoint: '/v1/app/setup/verifications/{verificationID}/accept', + httpMethod: 'post', + summary: 'Accept device verification', + description: 'Accept an incoming device verification request.', + stainlessPath: '(resource) app.verifications > (method) accept', + qualified: 'client.app.verifications.accept', + params: ['verificationID: string;'], + response: + "{ session: { e2ee: object; state: string; matrix?: object; verification?: object; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }", + markdown: + "## accept\n\n`client.app.verifications.accept(verificationID: string): { session: object; verification?: object; }`\n\n**post** `/v1/app/setup/verifications/{verificationID}/accept`\n\nAccept an incoming device verification request.\n\n### Parameters\n\n- `verificationID: string`\n Verification ID.\n\n### Returns\n\n- `{ session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: object; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }; }`\n\n - `session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: { masterKey: boolean; megolmBackupKey: boolean; recoveryKey: boolean; selfSigningKey: boolean; userSigningKey: boolean; }; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }; }`\n - `verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.app.verifications.accept('x');\n\nconsole.log(response);\n```", + perLanguage: { + typescript: { + method: 'client.app.verifications.accept', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop({\n accessToken: process.env['BEEPER_ACCESS_TOKEN'], // This is the default and can be omitted\n});\n\nconst response = await client.app.verifications.accept('x');\n\nconsole.log(response.session);", + }, + python: { + method: 'app.verifications.accept', + example: + 'import os\nfrom beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop(\n access_token=os.environ.get("BEEPER_ACCESS_TOKEN"), # This is the default and can be omitted\n)\nresponse = client.app.verifications.accept(\n "x",\n)\nprint(response.session)', + }, + go: { + method: 'client.App.Verifications.Accept', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\tresponse, err := client.App.Verifications.Accept(context.TODO(), "x")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Session)\n}\n', + }, + cli: { + method: 'verifications accept', + example: + "beeper-desktop app:verifications accept \\\n --access-token 'My Access Token' \\\n --verification-id x", + }, + php: { + method: 'app->verifications->accept', + example: + "app->verifications->accept('x');\n\nvar_dump($response);", + }, + http: { + example: + 'curl http://localhost:23373/v1/app/setup/verifications/$VERIFICATION_ID/accept \\\n -X POST \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN"', + }, + }, + }, + { + name: 'cancel', + endpoint: '/v1/app/setup/verifications/{verificationID}/cancel', + httpMethod: 'post', + summary: 'Cancel device verification', + description: 'Cancel an active device verification request.', + stainlessPath: '(resource) app.verifications > (method) cancel', + qualified: 'client.app.verifications.cancel', + params: ['verificationID: string;', 'code?: string;', 'reason?: string;'], + response: + "{ session: { e2ee: object; state: string; matrix?: object; verification?: object; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }", + markdown: + "## cancel\n\n`client.app.verifications.cancel(verificationID: string, code?: string, reason?: string): { session: object; verification?: object; }`\n\n**post** `/v1/app/setup/verifications/{verificationID}/cancel`\n\nCancel an active device verification request.\n\n### Parameters\n\n- `verificationID: string`\n Verification ID.\n\n- `code?: string`\n Optional cancellation code.\n\n- `reason?: string`\n Optional user-facing cancellation reason.\n\n### Returns\n\n- `{ session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: object; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }; }`\n\n - `session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: { masterKey: boolean; megolmBackupKey: boolean; recoveryKey: boolean; selfSigningKey: boolean; userSigningKey: boolean; }; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }; }`\n - `verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.app.verifications.cancel('x');\n\nconsole.log(response);\n```", + perLanguage: { + typescript: { + method: 'client.app.verifications.cancel', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop({\n accessToken: process.env['BEEPER_ACCESS_TOKEN'], // This is the default and can be omitted\n});\n\nconst response = await client.app.verifications.cancel('x');\n\nconsole.log(response.session);", + }, + python: { + method: 'app.verifications.cancel', + example: + 'import os\nfrom beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop(\n access_token=os.environ.get("BEEPER_ACCESS_TOKEN"), # This is the default and can be omitted\n)\nresponse = client.app.verifications.cancel(\n verification_id="x",\n)\nprint(response.session)', + }, + go: { + method: 'client.App.Verifications.Cancel', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\tresponse, err := client.App.Verifications.Cancel(\n\t\tcontext.TODO(),\n\t\t"x",\n\t\tbeeperdesktopapi.AppVerificationCancelParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Session)\n}\n', + }, + cli: { + method: 'verifications cancel', + example: + "beeper-desktop app:verifications cancel \\\n --access-token 'My Access Token' \\\n --verification-id x", + }, + php: { + method: 'app->verifications->cancel', + example: + "app->verifications->cancel(\n 'x', code: 'code', reason: 'reason'\n);\n\nvar_dump($response);", + }, + http: { + example: + 'curl http://localhost:23373/v1/app/setup/verifications/$VERIFICATION_ID/cancel \\\n -X POST \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN"', + }, + }, + }, + { + name: 'scan', + endpoint: '/v1/app/setup/verifications/qr/scan', + httpMethod: 'post', + summary: 'Scan verification QR code', + description: 'Submit the QR code scanned from another signed-in device.', + stainlessPath: '(resource) app.verifications.qr > (method) scan', + qualified: 'client.app.verifications.qr.scan', + params: ['data: string;'], + response: + "{ session: { e2ee: object; state: string; matrix?: object; verification?: object; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }", + markdown: + "## scan\n\n`client.app.verifications.qr.scan(data: string): { session: object; verification?: object; }`\n\n**post** `/v1/app/setup/verifications/qr/scan`\n\nSubmit the QR code scanned from another signed-in device.\n\n### Parameters\n\n- `data: string`\n QR code payload scanned from the other device.\n\n### Returns\n\n- `{ session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: object; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }; }`\n\n - `session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: { masterKey: boolean; megolmBackupKey: boolean; recoveryKey: boolean; selfSigningKey: boolean; userSigningKey: boolean; }; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }; }`\n - `verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.app.verifications.qr.scan({ data: 'x' });\n\nconsole.log(response);\n```", + perLanguage: { + typescript: { + method: 'client.app.verifications.qr.scan', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop({\n accessToken: process.env['BEEPER_ACCESS_TOKEN'], // This is the default and can be omitted\n});\n\nconst response = await client.app.verifications.qr.scan({ data: 'x' });\n\nconsole.log(response.session);", + }, + python: { + method: 'app.verifications.qr.scan', + example: + 'import os\nfrom beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop(\n access_token=os.environ.get("BEEPER_ACCESS_TOKEN"), # This is the default and can be omitted\n)\nresponse = client.app.verifications.qr.scan(\n data="x",\n)\nprint(response.session)', + }, + go: { + method: 'client.App.Verifications.Qr.Scan', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\tresponse, err := client.App.Verifications.Qr.Scan(context.TODO(), beeperdesktopapi.AppVerificationQrScanParams{\n\t\tData: "x",\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Session)\n}\n', + }, + cli: { + method: 'qr scan', + example: + "beeper-desktop app:verifications:qr scan \\\n --access-token 'My Access Token' \\\n --data x", + }, + php: { + method: 'app->verifications->qr->scan', + example: + "app->verifications->qr->scan(data: 'x');\n\nvar_dump($response);", + }, + http: { + example: + 'curl http://localhost:23373/v1/app/setup/verifications/qr/scan \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN" \\\n -d \'{\n "data": "x"\n }\'', + }, + }, + }, + { + name: 'confirm_scanned', + endpoint: '/v1/app/setup/verifications/{verificationID}/qr/confirm-scanned', + httpMethod: 'post', + summary: 'Confirm QR code scan', + description: 'Confirm that another device scanned this device QR code.', + stainlessPath: '(resource) app.verifications.qr > (method) confirm_scanned', + qualified: 'client.app.verifications.qr.confirmScanned', + params: ['verificationID: string;'], + response: + "{ session: { e2ee: object; state: string; matrix?: object; verification?: object; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }", + markdown: + "## confirm_scanned\n\n`client.app.verifications.qr.confirmScanned(verificationID: string): { session: object; verification?: object; }`\n\n**post** `/v1/app/setup/verifications/{verificationID}/qr/confirm-scanned`\n\nConfirm that another device scanned this device QR code.\n\n### Parameters\n\n- `verificationID: string`\n Verification ID.\n\n### Returns\n\n- `{ session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: object; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }; }`\n\n - `session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: { masterKey: boolean; megolmBackupKey: boolean; recoveryKey: boolean; selfSigningKey: boolean; userSigningKey: boolean; }; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }; }`\n - `verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.app.verifications.qr.confirmScanned('x');\n\nconsole.log(response);\n```", + perLanguage: { + typescript: { + method: 'client.app.verifications.qr.confirmScanned', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop({\n accessToken: process.env['BEEPER_ACCESS_TOKEN'], // This is the default and can be omitted\n});\n\nconst response = await client.app.verifications.qr.confirmScanned('x');\n\nconsole.log(response.session);", + }, + python: { + method: 'app.verifications.qr.confirm_scanned', + example: + 'import os\nfrom beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop(\n access_token=os.environ.get("BEEPER_ACCESS_TOKEN"), # This is the default and can be omitted\n)\nresponse = client.app.verifications.qr.confirm_scanned(\n "x",\n)\nprint(response.session)', + }, + go: { + method: 'client.App.Verifications.Qr.ConfirmScanned', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\tresponse, err := client.App.Verifications.Qr.ConfirmScanned(context.TODO(), "x")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Session)\n}\n', + }, + cli: { + method: 'qr confirm_scanned', + example: + "beeper-desktop app:verifications:qr confirm-scanned \\\n --access-token 'My Access Token' \\\n --verification-id x", + }, + php: { + method: 'app->verifications->qr->confirmScanned', + example: + "app->verifications->qr->confirmScanned('x');\n\nvar_dump($response);", + }, + http: { + example: + 'curl http://localhost:23373/v1/app/setup/verifications/$VERIFICATION_ID/qr/confirm-scanned \\\n -X POST \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN"', + }, + }, + }, + { + name: 'start', + endpoint: '/v1/app/setup/verifications/{verificationID}/sas/start', + httpMethod: 'post', + summary: 'Start emoji verification', + description: 'Start emoji comparison for device verification.', + stainlessPath: '(resource) app.verifications.sas > (method) start', + qualified: 'client.app.verifications.sas.start', + params: ['verificationID: string;'], + response: + "{ session: { e2ee: object; state: string; matrix?: object; verification?: object; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }", + markdown: + "## start\n\n`client.app.verifications.sas.start(verificationID: string): { session: object; verification?: object; }`\n\n**post** `/v1/app/setup/verifications/{verificationID}/sas/start`\n\nStart emoji comparison for device verification.\n\n### Parameters\n\n- `verificationID: string`\n Verification ID.\n\n### Returns\n\n- `{ session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: object; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }; }`\n\n - `session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: { masterKey: boolean; megolmBackupKey: boolean; recoveryKey: boolean; selfSigningKey: boolean; userSigningKey: boolean; }; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }; }`\n - `verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.app.verifications.sas.start('x');\n\nconsole.log(response);\n```", + perLanguage: { + typescript: { + method: 'client.app.verifications.sas.start', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop({\n accessToken: process.env['BEEPER_ACCESS_TOKEN'], // This is the default and can be omitted\n});\n\nconst response = await client.app.verifications.sas.start('x');\n\nconsole.log(response.session);", + }, + python: { + method: 'app.verifications.sas.start', + example: + 'import os\nfrom beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop(\n access_token=os.environ.get("BEEPER_ACCESS_TOKEN"), # This is the default and can be omitted\n)\nresponse = client.app.verifications.sas.start(\n "x",\n)\nprint(response.session)', + }, + go: { + method: 'client.App.Verifications.SAS.Start', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\tresponse, err := client.App.Verifications.SAS.Start(context.TODO(), "x")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Session)\n}\n', + }, + cli: { + method: 'sas start', + example: + "beeper-desktop app:verifications:sas start \\\n --access-token 'My Access Token' \\\n --verification-id x", + }, + php: { + method: 'app->verifications->sas->start', + example: + "app->verifications->sas->start('x');\n\nvar_dump($response);", + }, + http: { + example: + 'curl http://localhost:23373/v1/app/setup/verifications/$VERIFICATION_ID/sas/start \\\n -X POST \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN"', + }, + }, + }, + { + name: 'confirm', + endpoint: '/v1/app/setup/verifications/{verificationID}/sas/confirm', + httpMethod: 'post', + summary: 'Confirm emoji verification', + description: 'Confirm that the emoji or number sequence matches on both devices.', + stainlessPath: '(resource) app.verifications.sas > (method) confirm', + qualified: 'client.app.verifications.sas.confirm', + params: ['verificationID: string;'], + response: + "{ session: { e2ee: object; state: string; matrix?: object; verification?: object; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }", + markdown: + "## confirm\n\n`client.app.verifications.sas.confirm(verificationID: string): { session: object; verification?: object; }`\n\n**post** `/v1/app/setup/verifications/{verificationID}/sas/confirm`\n\nConfirm that the emoji or number sequence matches on both devices.\n\n### Parameters\n\n- `verificationID: string`\n Verification ID.\n\n### Returns\n\n- `{ session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: object; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: object; otherDevice?: object; otherUserID?: string; qr?: object; sas?: object; }; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }; }`\n\n - `session: { e2ee: { crossSigning: boolean; firstSyncDone: boolean; hasBackedUpRecoveryKey: boolean; initialized: boolean; keyBackup: boolean; secrets: { masterKey: boolean; megolmBackupKey: boolean; recoveryKey: boolean; selfSigningKey: boolean; userSigningKey: boolean; }; secretStorage: boolean; verified: boolean; recoveryKeyGeneratedAt?: number; }; state: string; matrix?: { deviceID: string; homeserver: string; userID: string; }; verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }; }`\n - `verification?: { id: string; availableActions: 'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'[]; direction: 'incoming' | 'outgoing'; methods: 'qr' | 'sas'[]; purpose: 'login' | 'device'; state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; error?: { code: string; reason: string; }; otherDevice?: { id: string; name?: string; }; otherUserID?: string; qr?: { data: string; }; sas?: { emojis: string; decimals?: string; }; }`\n\n### Example\n\n```typescript\nimport BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop();\n\nconst response = await client.app.verifications.sas.confirm('x');\n\nconsole.log(response);\n```", + perLanguage: { + typescript: { + method: 'client.app.verifications.sas.confirm', + example: + "import BeeperDesktop from '@beeper/desktop-api';\n\nconst client = new BeeperDesktop({\n accessToken: process.env['BEEPER_ACCESS_TOKEN'], // This is the default and can be omitted\n});\n\nconst response = await client.app.verifications.sas.confirm('x');\n\nconsole.log(response.session);", + }, + python: { + method: 'app.verifications.sas.confirm', + example: + 'import os\nfrom beeper_desktop_api import BeeperDesktop\n\nclient = BeeperDesktop(\n access_token=os.environ.get("BEEPER_ACCESS_TOKEN"), # This is the default and can be omitted\n)\nresponse = client.app.verifications.sas.confirm(\n "x",\n)\nprint(response.session)', + }, + go: { + method: 'client.App.Verifications.SAS.Confirm', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/beeper/desktop-api-go"\n\t"github.com/beeper/desktop-api-go/option"\n)\n\nfunc main() {\n\tclient := beeperdesktopapi.NewClient(\n\t\toption.WithAccessToken("My Access Token"),\n\t)\n\tresponse, err := client.App.Verifications.SAS.Confirm(context.TODO(), "x")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Session)\n}\n', + }, + cli: { + method: 'sas confirm', + example: + "beeper-desktop app:verifications:sas confirm \\\n --access-token 'My Access Token' \\\n --verification-id x", + }, + php: { + method: 'app->verifications->sas->confirm', + example: + "app->verifications->sas->confirm('x');\n\nvar_dump($response);", + }, + http: { + example: + 'curl http://localhost:23373/v1/app/setup/verifications/$VERIFICATION_ID/sas/confirm \\\n -X POST \\\n -H "Authorization: Bearer $BEEPER_ACCESS_TOKEN"', + }, + }, + }, ]; const EMBEDDED_READMES: { language: string; content: string }[] = [ { language: 'cli', content: - "# Beeper Desktop CLI\n\nThe official CLI for the [Beeper Desktop REST API](https://developers.beeper.com/desktop-api/).\n\n\n\n## Installation\n\n### Installing with Homebrew\n\n~~~sh\nbrew install beeper/tap/beeper-desktop-cli\n~~~\n\n### Installing with Go\n\nTo test or install the CLI locally, you need [Go](https://go.dev/doc/install) version 1.22 or later installed.\n\n~~~sh\ngo install 'github.com/beeper/desktop-api-cli/cmd/beeper-desktop-cli@latest'\n~~~\n\nOnce you have run `go install`, the binary is placed in your Go bin directory:\n\n- **Default location**: `$HOME/go/bin` (or `$GOPATH/bin` if GOPATH is set)\n- **Check your path**: Run `go env GOPATH` to see the base directory\n\nIf commands aren't found after installation, add the Go bin directory to your PATH:\n\n~~~sh\n# Add to your shell profile (.zshrc, .bashrc, etc.)\nexport PATH=\"$PATH:$(go env GOPATH)/bin\"\n~~~\n\n\n\n### Running Locally\n\nAfter cloning the git repository for this project, you can use the\n`scripts/run` script to run the tool locally:\n\n~~~sh\n./scripts/run args...\n~~~\n\n## Usage\n\nThe CLI follows a resource-based command structure:\n\n~~~sh\nbeeper-desktop-cli [resource] [flags...]\n~~~\n\n~~~sh\nbeeper-desktop-cli chats search \\\n --access-token 'My Access Token' \\\n --account-id matrix \\\n --account-id discordgo \\\n --account-id local-whatsapp_ba_EvYDBBsZbRQAy3UOSWqG0LuTVkc \\\n --include-muted \\\n --limit 3 \\\n --type single\n~~~\n\nFor details about specific commands, use the `--help` flag.\n\n### Environment variables\n\n| Environment variable | Description | Required |\n| --------------------- | ----------------------------------------------------------------------------------------------------- | -------- |\n| `BEEPER_ACCESS_TOKEN` | Bearer access token obtained via OAuth2 PKCE flow or created in-app. Required for all API operations. | yes |\n\n### Global flags\n\n- `--access-token` - Bearer access token obtained via OAuth2 PKCE flow or created in-app. Required for all API operations. (can also be set with `BEEPER_ACCESS_TOKEN` env var)\n- `--help` - Show command line usage\n- `--debug` - Enable debug logging (includes HTTP request/response details)\n- `--version`, `-v` - Show the CLI version\n- `--base-url` - Use a custom API backend URL\n- `--format` - Change the output format (`auto`, `explore`, `json`, `jsonl`, `pretty`, `raw`, `yaml`)\n- `--format-error` - Change the output format for errors (`auto`, `explore`, `json`, `jsonl`, `pretty`, `raw`, `yaml`)\n- `--transform` - Transform the data output using [GJSON syntax](https://github.com/tidwall/gjson/blob/master/SYNTAX.md)\n- `--transform-error` - Transform the error output using [GJSON syntax](https://github.com/tidwall/gjson/blob/master/SYNTAX.md)\n\n### Passing files as arguments\n\nTo pass files to your API, you can use the `@myfile.ext` syntax:\n\n~~~bash\nbeeper-desktop-cli --arg @abe.jpg\n~~~\n\nFiles can also be passed inside JSON or YAML blobs:\n\n~~~bash\nbeeper-desktop-cli --arg '{image: \"@abe.jpg\"}'\n# Equivalent:\nbeeper-desktop-cli < --username '\\@abe'\n~~~\n\n#### Explicit encoding\n\nFor JSON endpoints, the CLI tool does filetype sniffing to determine whether the\nfile contents should be sent as a string literal (for plain text files) or as a\nbase64-encoded string literal (for binary files). If you need to explicitly send\nthe file as either plain text or base64-encoded data, you can use\n`@file://myfile.txt` (for string encoding) or `@data://myfile.dat` (for\nbase64-encoding). Note that absolute paths will begin with `@file://` or\n`@data://`, followed by a third `/` (for example, `@file:///tmp/file.txt`).\n\n~~~bash\nbeeper-desktop-cli --arg @data://file.txt\n~~~\n\n## Linking different Go SDK versions\n\nYou can link the CLI against a different version of the Beeper Desktop Go SDK\nfor development purposes using the `./scripts/link` script.\n\nTo link to a specific version from a repository (version can be a branch,\ngit tag, or commit hash):\n\n~~~bash\n./scripts/link github.com/org/repo@version\n~~~\n\nTo link to a local copy of the SDK:\n\n~~~bash\n./scripts/link ../path/to/beeperdesktopapi-go\n~~~\n\nIf you run the link script without any arguments, it will default to `../beeperdesktopapi-go`.\n", + "# CLI for Beeper Desktop\n\nThe official CLI for the [Beeper Desktop REST API](https://developers.beeper.com/desktop-api/).\n\n\n\n## Installation\n\n### Installing with Go\n\nTo test or install the CLI locally, you need [Go](https://go.dev/doc/install) version 1.22 or later installed.\n\n~~~sh\ngo install 'github.com/beeper/desktop-api-cli/cmd/beeper-desktop@latest'\n~~~\n\nOnce you have run `go install`, the binary is placed in your Go bin directory:\n\n- **Default location**: `$HOME/go/bin` (or `$GOPATH/bin` if GOPATH is set)\n- **Check your path**: Run `go env GOPATH` to see the base directory\n\nIf commands aren't found after installation, add the Go bin directory to your PATH:\n\n~~~sh\n# Add to your shell profile (.zshrc, .bashrc, etc.)\nexport PATH=\"$PATH:$(go env GOPATH)/bin\"\n~~~\n\n\n\n### Running Locally\n\nAfter cloning the git repository for this project, you can use the\n`scripts/run` script to run the tool locally:\n\n~~~sh\n./scripts/run args...\n~~~\n\n## Usage\n\nThe CLI follows a resource-based command structure:\n\n~~~sh\nbeeper-desktop [resource] [flags...]\n~~~\n\n~~~sh\nbeeper-desktop chats search \\\n --access-token 'My Access Token' \\\n --account-id matrix \\\n --account-id discordgo \\\n --account-id local-whatsapp_ba_EvYDBBsZbRQAy3UOSWqG0LuTVkc \\\n --include-muted \\\n --limit 3 \\\n --type single\n~~~\n\nFor details about specific commands, use the `--help` flag.\n\n### Environment variables\n\n| Environment variable | Description | Required |\n| --------------------- | --------------------------------------------------------------------------------------------------------------- | -------- |\n| `BEEPER_ACCESS_TOKEN` | Bearer access token obtained via OAuth2 PKCE flow or created in-app. Required for authenticated API operations. | yes |\n\n### Global flags\n\n- `--access-token` - Bearer access token obtained via OAuth2 PKCE flow or created in-app. Required for authenticated API operations. (can also be set with `BEEPER_ACCESS_TOKEN` env var)\n- `--help` - Show command line usage\n- `--debug` - Enable debug logging (includes HTTP request/response details)\n- `--version`, `-v` - Show the CLI version\n- `--base-url` - Use a custom API backend URL\n- `--format` - Change the output format (`auto`, `explore`, `json`, `jsonl`, `pretty`, `raw`, `yaml`)\n- `--format-error` - Change the output format for errors (`auto`, `explore`, `json`, `jsonl`, `pretty`, `raw`, `yaml`)\n- `--transform` - Transform the data output using [GJSON syntax](https://github.com/tidwall/gjson/blob/master/SYNTAX.md)\n- `--transform-error` - Transform the error output using [GJSON syntax](https://github.com/tidwall/gjson/blob/master/SYNTAX.md)\n\n### Passing files as arguments\n\nTo pass files to your API, you can use the `@myfile.ext` syntax:\n\n~~~bash\nbeeper-desktop --arg @abe.jpg\n~~~\n\nFiles can also be passed inside JSON or YAML blobs:\n\n~~~bash\nbeeper-desktop --arg '{image: \"@abe.jpg\"}'\n# Equivalent:\nbeeper-desktop < --username '\\@abe'\n~~~\n\n#### Explicit encoding\n\nFor JSON endpoints, the CLI tool does filetype sniffing to determine whether the\nfile contents should be sent as a string literal (for plain text files) or as a\nbase64-encoded string literal (for binary files). If you need to explicitly send\nthe file as either plain text or base64-encoded data, you can use\n`@file://myfile.txt` (for string encoding) or `@data://myfile.dat` (for\nbase64-encoding). Note that absolute paths will begin with `@file://` or\n`@data://`, followed by a third `/` (for example, `@file:///tmp/file.txt`).\n\n~~~bash\nbeeper-desktop --arg @data://file.txt\n~~~\n\n## Linking different Go SDK versions\n\nYou can link the CLI against a different version of the Beeper Desktop Go SDK\nfor development purposes using the `./scripts/link` script.\n\nTo link to a specific version from a repository (version can be a branch,\ngit tag, or commit hash):\n\n~~~bash\n./scripts/link github.com/org/repo@version\n~~~\n\nTo link to a local copy of the SDK:\n\n~~~bash\n./scripts/link ../path/to/beeperdesktopapi-go\n~~~\n\nIf you run the link script without any arguments, it will default to `../beeperdesktopapi-go`.\n", }, { language: 'go', diff --git a/packages/mcp-server/src/methods.ts b/packages/mcp-server/src/methods.ts index 509a854..6dfb3ad 100644 --- a/packages/mcp-server/src/methods.ts +++ b/packages/mcp-server/src/methods.ts @@ -22,6 +22,12 @@ export const sdkMethods: SdkMethod[] = [ httpMethod: 'get', httpPath: '/v1/search', }, + { + clientCallName: 'client.accounts.retrieve', + fullyQualifiedName: 'accounts.retrieve', + httpMethod: 'get', + httpPath: '/v1/accounts/{accountID}', + }, { clientCallName: 'client.accounts.list', fullyQualifiedName: 'accounts.list', @@ -40,6 +46,54 @@ export const sdkMethods: SdkMethod[] = [ httpMethod: 'get', httpPath: '/v1/accounts/{accountID}/contacts', }, + { + clientCallName: 'client.bridges.retrieve', + fullyQualifiedName: 'bridges.retrieve', + httpMethod: 'get', + httpPath: '/v1/bridges/{bridgeID}', + }, + { + clientCallName: 'client.bridges.list', + fullyQualifiedName: 'bridges.list', + httpMethod: 'get', + httpPath: '/v1/bridges', + }, + { + clientCallName: 'client.bridges.retrieveCapabilities', + fullyQualifiedName: 'bridges.retrieveCapabilities', + httpMethod: 'get', + httpPath: '/v1/bridges/{bridgeID}/capabilities', + }, + { + clientCallName: 'client.bridges.loginFlows.list', + fullyQualifiedName: 'bridges.loginFlows.list', + httpMethod: 'get', + httpPath: '/v1/bridges/{bridgeID}/login-flows', + }, + { + clientCallName: 'client.bridges.loginSessions.create', + fullyQualifiedName: 'bridges.loginSessions.create', + httpMethod: 'post', + httpPath: '/v1/bridges/{bridgeID}/login-sessions', + }, + { + clientCallName: 'client.bridges.loginSessions.retrieve', + fullyQualifiedName: 'bridges.loginSessions.retrieve', + httpMethod: 'get', + httpPath: '/v1/bridges/{bridgeID}/login-sessions/{loginSessionID}', + }, + { + clientCallName: 'client.bridges.loginSessions.cancel', + fullyQualifiedName: 'bridges.loginSessions.cancel', + httpMethod: 'delete', + httpPath: '/v1/bridges/{bridgeID}/login-sessions/{loginSessionID}', + }, + { + clientCallName: 'client.bridges.loginSessions.steps.submit', + fullyQualifiedName: 'bridges.loginSessions.steps.submit', + httpMethod: 'post', + httpPath: '/v1/bridges/{bridgeID}/login-sessions/{loginSessionID}/steps/{stepID}', + }, { clientCallName: 'client.chats.create', fullyQualifiedName: 'chats.create', @@ -190,6 +244,108 @@ export const sdkMethods: SdkMethod[] = [ httpMethod: 'get', httpPath: '/v1/info', }, + { + clientCallName: 'client.app.session', + fullyQualifiedName: 'app.session', + httpMethod: 'get', + httpPath: '/v1/app/setup', + }, + { + clientCallName: 'client.app.login.email', + fullyQualifiedName: 'app.login.email', + httpMethod: 'post', + httpPath: '/v1/app/setup/email', + }, + { + clientCallName: 'client.app.login.register', + fullyQualifiedName: 'app.login.register', + httpMethod: 'post', + httpPath: '/v1/app/setup/register', + }, + { + clientCallName: 'client.app.login.response', + fullyQualifiedName: 'app.login.response', + httpMethod: 'post', + httpPath: '/v1/app/setup/response', + }, + { + clientCallName: 'client.app.login.start', + fullyQualifiedName: 'app.login.start', + httpMethod: 'post', + httpPath: '/v1/app/setup/start', + }, + { + clientCallName: 'client.app.login.verification.recoveryKey.verify', + fullyQualifiedName: 'app.login.verification.recoveryKey.verify', + httpMethod: 'post', + httpPath: '/v1/app/setup/verification/recovery-key', + }, + { + clientCallName: 'client.app.login.verification.recoveryKey.reset.create', + fullyQualifiedName: 'app.login.verification.recoveryKey.reset.create', + httpMethod: 'post', + httpPath: '/v1/app/setup/verification/recovery-key/reset', + }, + { + clientCallName: 'client.app.login.verification.recoveryKey.reset.confirm', + fullyQualifiedName: 'app.login.verification.recoveryKey.reset.confirm', + httpMethod: 'post', + httpPath: '/v1/app/setup/verification/recovery-key/reset/confirm', + }, + { + clientCallName: 'client.app.verifications.create', + fullyQualifiedName: 'app.verifications.create', + httpMethod: 'post', + httpPath: '/v1/app/setup/verifications', + }, + { + clientCallName: 'client.app.verifications.retrieve', + fullyQualifiedName: 'app.verifications.retrieve', + httpMethod: 'get', + httpPath: '/v1/app/setup/verifications/{verificationID}', + }, + { + clientCallName: 'client.app.verifications.list', + fullyQualifiedName: 'app.verifications.list', + httpMethod: 'get', + httpPath: '/v1/app/setup/verifications', + }, + { + clientCallName: 'client.app.verifications.accept', + fullyQualifiedName: 'app.verifications.accept', + httpMethod: 'post', + httpPath: '/v1/app/setup/verifications/{verificationID}/accept', + }, + { + clientCallName: 'client.app.verifications.cancel', + fullyQualifiedName: 'app.verifications.cancel', + httpMethod: 'post', + httpPath: '/v1/app/setup/verifications/{verificationID}/cancel', + }, + { + clientCallName: 'client.app.verifications.qr.confirmScanned', + fullyQualifiedName: 'app.verifications.qr.confirmScanned', + httpMethod: 'post', + httpPath: '/v1/app/setup/verifications/{verificationID}/qr/confirm-scanned', + }, + { + clientCallName: 'client.app.verifications.qr.scan', + fullyQualifiedName: 'app.verifications.qr.scan', + httpMethod: 'post', + httpPath: '/v1/app/setup/verifications/qr/scan', + }, + { + clientCallName: 'client.app.verifications.sas.confirm', + fullyQualifiedName: 'app.verifications.sas.confirm', + httpMethod: 'post', + httpPath: '/v1/app/setup/verifications/{verificationID}/sas/confirm', + }, + { + clientCallName: 'client.app.verifications.sas.start', + fullyQualifiedName: 'app.verifications.sas.start', + httpMethod: 'post', + httpPath: '/v1/app/setup/verifications/{verificationID}/sas/start', + }, ]; function allowedMethodsForCodeTool(options: McpOptions | undefined): SdkMethod[] | undefined { diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index 293ee94..3fdacca 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -28,7 +28,7 @@ export const newMcpServer = async ({ new McpServer( { name: 'beeper_desktop_api_api', - version: '5.0.0', + version: '5.1.0', }, { instructions: await getInstructions({ stainlessApiKey, customInstructionsPath }), diff --git a/packages/mcp-server/tests/auth.test.ts b/packages/mcp-server/tests/auth.test.ts new file mode 100644 index 0000000..c01dde0 --- /dev/null +++ b/packages/mcp-server/tests/auth.test.ts @@ -0,0 +1,24 @@ +import { IncomingMessage } from 'node:http'; +import { parseClientAuthHeaders } from '../src/auth'; + +const reqWithHeaders = (headers: IncomingMessage['headers']) => ({ headers }) as IncomingMessage; + +describe('parseClientAuthHeaders', () => { + it('returns bearer access token from Authorization header', () => { + expect(parseClientAuthHeaders(reqWithHeaders({ authorization: 'Bearer token' }), true)).toEqual({ + accessToken: 'token', + }); + }); + + it('returns x-beeper-access-token when auth is required', () => { + expect(parseClientAuthHeaders(reqWithHeaders({ 'x-beeper-access-token': 'token' }), true)).toEqual({ + accessToken: 'token', + }); + }); + + it('throws when auth is required and no token is present', () => { + expect(() => parseClientAuthHeaders(reqWithHeaders({}), true)).toThrow( + 'Missing required Authorization header', + ); + }); +}); diff --git a/packages/mcp-server/yarn.lock b/packages/mcp-server/yarn.lock index c7e3769..c6b17b0 100644 --- a/packages/mcp-server/yarn.lock +++ b/packages/mcp-server/yarn.lock @@ -3921,9 +3921,9 @@ ts-node@^10.5.0: v8-compile-cache-lib "^3.0.1" yn "3.1.1" -"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz": - version "1.1.9" - resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz#777f6f5d9e26bf0e94e5170990dd3a841d6707cd" +"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz": + version "1.1.11" + resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz#010247051be13b55abdc98f787c017285149f4f2" dependencies: debug "^4.3.7" fast-glob "^3.3.2" diff --git a/src/client.ts b/src/client.ts index 90ff33e..edbc1e3 100644 --- a/src/client.ts +++ b/src/client.ts @@ -49,7 +49,29 @@ import { MessageUpdateResponse, Messages, } from './resources/messages'; -import { Account, AccountListResponse, Accounts } from './resources/accounts/accounts'; +import { + Account, + AccountBridge, + AccountListResponse, + AccountRetrieveResponse, + Accounts, +} from './resources/accounts/accounts'; +import { App, AppSessionResponse, Verification } from './resources/app/app'; +import { + Bridge, + BridgeListResponse, + BridgeRetrieveResponse, + Bridges, + CookieField, + DisappearingTimerCapability, + GroupFieldCapability, + GroupTypeCapabilities, + LoginFlow, + LoginInputField, + LoginSession, + ProvisioningCapabilities, + ResolveIdentifierCapabilities, +} from './resources/bridges/bridges'; import { Chat, ChatArchiveParams, @@ -84,7 +106,7 @@ import { isEmptyObj } from './internal/utils/values'; export interface ClientOptions { /** - * Bearer access token obtained via OAuth2 PKCE flow or created in-app. Required for all API operations. + * Bearer access token obtained via OAuth2 PKCE flow or created in-app. Required for authenticated API operations. */ accessToken?: string | undefined; @@ -263,8 +285,8 @@ export class BaseBeeperDesktop { } /** - * Focus Beeper Desktop and optionally navigate to a specific chat, message, or - * pre-fill plain text and an image path. + * Focus Beeper Desktop and optionally open a specific chat, jump to a message, or + * pre-fill text and an image. * * @example * ```ts @@ -279,9 +301,9 @@ export class BaseBeeperDesktop { } /** - * 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. + * Return matching chats, participant matches in group chats, and the first page of + * message results in one call. Use the dedicated chat and message search endpoints + * for pagination. * * @example * ```ts @@ -849,6 +871,10 @@ export class BeeperDesktop extends BaseBeeperDesktop { * Manage connected chat accounts */ accounts: API.Accounts = new API.Accounts(this); + /** + * Manage bridge-backed account types, connections, and login sessions + */ + bridges: API.Bridges = new API.Bridges(this); /** * Manage chats */ @@ -865,13 +891,19 @@ export class BeeperDesktop extends BaseBeeperDesktop { * Server discovery and capability metadata. Use /v1/info before authentication setup. */ info: API.Info = new API.Info(this); + /** + * Manage Beeper app login and encrypted messaging setup + */ + app: API.App = new API.App(this); } BeeperDesktop.Accounts = Accounts; +BeeperDesktop.Bridges = Bridges; BeeperDesktop.Chats = Chats; BeeperDesktop.Messages = Messages; BeeperDesktop.Assets = Assets; BeeperDesktop.Info = Info; +BeeperDesktop.App = App; export declare namespace BeeperDesktop { export type RequestOptions = Opts.RequestOptions; @@ -892,7 +924,29 @@ export declare namespace BeeperDesktop { type SearchParams as SearchParams, }; - export { Accounts as Accounts, type Account as Account, type AccountListResponse as AccountListResponse }; + export { + Accounts as Accounts, + type Account as Account, + type AccountBridge as AccountBridge, + type AccountRetrieveResponse as AccountRetrieveResponse, + type AccountListResponse as AccountListResponse, + }; + + export { + Bridges as Bridges, + type Bridge as Bridge, + type CookieField as CookieField, + type DisappearingTimerCapability as DisappearingTimerCapability, + type GroupFieldCapability as GroupFieldCapability, + type GroupTypeCapabilities as GroupTypeCapabilities, + type LoginFlow as LoginFlow, + type LoginInputField as LoginInputField, + type LoginSession as LoginSession, + type ProvisioningCapabilities as ProvisioningCapabilities, + type ResolveIdentifierCapabilities as ResolveIdentifierCapabilities, + type BridgeRetrieveResponse as BridgeRetrieveResponse, + type BridgeListResponse as BridgeListResponse, + }; export { Chats as Chats, @@ -939,6 +993,10 @@ export declare namespace BeeperDesktop { export { Info as Info, type InfoRetrieveResponse as InfoRetrieveResponse }; + export { App as App, type Verification as Verification, type AppSessionResponse as AppSessionResponse }; + + export type APIError = API.APIError; + export type AppStateSnapshot = API.AppStateSnapshot; export type Attachment = API.Attachment; export type Error = API.Error; export type Message = API.Message; diff --git a/src/internal/utils/log.ts b/src/internal/utils/log.ts index 41b8cfd..2c61df7 100644 --- a/src/internal/utils/log.ts +++ b/src/internal/utils/log.ts @@ -107,6 +107,8 @@ export const formatRequestDetails = (details: { name, ( name.toLowerCase() === 'authorization' || + name.toLowerCase() === 'api-key' || + name.toLowerCase() === 'x-api-key' || name.toLowerCase() === 'cookie' || name.toLowerCase() === 'set-cookie' ) ? diff --git a/src/resources/accounts/accounts.ts b/src/resources/accounts/accounts.ts index c3c997f..0be35e7 100644 --- a/src/resources/accounts/accounts.ts +++ b/src/resources/accounts/accounts.ts @@ -12,6 +12,7 @@ import { } from './contacts'; import { APIPromise } from '../../core/api-promise'; import { RequestOptions } from '../../internal/request-options'; +import { path } from '../../internal/utils/path'; /** * Manage connected chat accounts @@ -20,8 +21,20 @@ export class BaseAccounts extends APIResource { static override readonly _key: readonly ['accounts'] = Object.freeze(['accounts'] as const); /** - * List Chat Accounts connected to this Beeper Desktop instance, including bridge - * metadata and network identity. + * Get one chat account connected to this Beeper Client API server. + * + * @example + * ```ts + * const account = await client.accounts.retrieve('accountID'); + * ``` + */ + retrieve(accountID: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/v1/accounts/${accountID}`, options); + } + + /** + * List chat accounts connected to this Beeper Client API server, including bridge, + * network, user identity, and connection status. * * @example * ```ts @@ -54,47 +67,133 @@ export interface Account { /** * Bridge metadata for the account. Available in Beeper Desktop v4.2.785+. */ - bridge: Account.Bridge; + bridge: AccountBridge; + + /** + * Current connection status for this account. + */ + status: + | 'connected' + | 'connecting' + | 'backfilling' + | 'connection_required' + | 'reconnect_required' + | 'attention_required' + | 'disconnected' + | 'disabled'; /** * User the account belongs to. */ user: Shared.User; + /** + * Runtime chat/message capabilities for this connected account, when available. + */ + capabilities?: { [key: string]: unknown }; + + /** + * Bridge login ID for this account, when known. One bridge login can contain + * multiple chat accounts. + */ + loginID?: string; + /** * Human-friendly network name for the account. Omitted when the network is * unknown. */ network?: string; + + /** + * Human-friendly account status text. + */ + statusText?: string; } -export namespace Account { +/** + * Bridge metadata for the account. Available in Beeper Desktop v4.2.785+. + */ +export interface AccountBridge { + /** + * Bridge identifier. Beeper Cloud accounts often use the network type (for example + * matrix or discordgo); on-device accounts use a local bridge ID (for example + * local-whatsapp). Available in Beeper Desktop v4.2.785+. + */ + id: string; + + /** + * Where this account runs: on this device or in Beeper Cloud. Available in Beeper + * Desktop v4.2.785+. + */ + provider: 'cloud' | 'self-hosted' | 'local' | 'platform-sdk'; + + /** + * Bridge type, such as matrix, discordgo, slackgo, whatsapp, telegram, or twitter. + * Available in Beeper Desktop v4.2.785+. + */ + type: string; +} + +/** + * A chat account added to Beeper. + */ +export interface AccountRetrieveResponse { + /** + * Chat account added to Beeper. Use this to route account-scoped actions. Examples + * include matrix for Beeper/Matrix, discordgo for a cloud bridge, + * slackgo.TEAM-USER for workspace-scoped cloud bridges, and local-whatsapp*ba*... + * for local bridges. + */ + accountID: string; + /** * Bridge metadata for the account. Available in Beeper Desktop v4.2.785+. */ - export interface Bridge { - /** - * Bridge instance identifier. Matrix and cloud bridges often use the bridge type - * (for example matrix or discordgo); local bridges use a local bridge ID (for - * example local-whatsapp). Available in Beeper Desktop v4.2.785+. - */ - id: string; - - /** - * Bridge provider for the account. Available in Beeper Desktop v4.2.785+. - */ - provider: 'cloud' | 'self-hosted' | 'local' | 'platform-sdk'; - - /** - * Bridge type, such as matrix, discordgo, slackgo, whatsapp, telegram, or twitter. - * Available in Beeper Desktop v4.2.785+. - */ - type: string; - } + bridge: AccountBridge; + + /** + * Current connection status for this account. + */ + status: + | 'connected' + | 'connecting' + | 'backfilling' + | 'connection_required' + | 'reconnect_required' + | 'attention_required' + | 'disconnected' + | 'disabled'; + + /** + * User the account belongs to. + */ + user: Shared.User; + + /** + * Runtime chat/message capabilities for this connected account, when available. + */ + capabilities?: { [key: string]: unknown }; + + /** + * Bridge login ID for this account, when known. One bridge login can contain + * multiple chat accounts. + */ + loginID?: string; + + /** + * Human-friendly network name for the account. Omitted when the network is + * unknown. + */ + network?: string; + + /** + * Human-friendly account status text. + */ + statusText?: string; } /** - * Accounts configured on this device. Includes accountID, bridge metadata, + * Chat accounts configured on this device. Includes accountID, bridge metadata, * optional network name, and user identity. */ export type AccountListResponse = Array; @@ -103,7 +202,12 @@ Accounts.Contacts = Contacts; Accounts.BaseContacts = BaseContacts; export declare namespace Accounts { - export { type Account as Account, type AccountListResponse as AccountListResponse }; + export { + type Account as Account, + type AccountBridge as AccountBridge, + type AccountRetrieveResponse as AccountRetrieveResponse, + type AccountListResponse as AccountListResponse, + }; export { Contacts as Contacts, diff --git a/src/resources/accounts/contacts.ts b/src/resources/accounts/contacts.ts index 42bd754..18ab023 100644 --- a/src/resources/accounts/contacts.ts +++ b/src/resources/accounts/contacts.ts @@ -72,14 +72,14 @@ export interface ContactSearchResponse { export interface ContactListParams extends CursorSearchParams { /** - * Optional search query for blended contact lookup. + * Optional search query for contact lookup. */ query?: string; } export interface ContactSearchParams { /** - * Text to search users by. Network-specific behavior. + * Text to search contacts by. Matching behavior depends on the network. */ query: string; } diff --git a/src/resources/accounts/index.ts b/src/resources/accounts/index.ts index 1249a9b..c63c2c5 100644 --- a/src/resources/accounts/index.ts +++ b/src/resources/accounts/index.ts @@ -1,6 +1,13 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -export { Accounts, BaseAccounts, type Account, type AccountListResponse } from './accounts'; +export { + Accounts, + BaseAccounts, + type Account, + type AccountBridge, + type AccountRetrieveResponse, + type AccountListResponse, +} from './accounts'; export { Contacts, BaseContacts, diff --git a/src/resources/app.ts b/src/resources/app.ts new file mode 100644 index 0000000..eed68d3 --- /dev/null +++ b/src/resources/app.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './app/index'; diff --git a/src/resources/app/app.ts b/src/resources/app/app.ts new file mode 100644 index 0000000..e55e7c0 --- /dev/null +++ b/src/resources/app/app.ts @@ -0,0 +1,451 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../core/resource'; +import * as LoginAPI from './login/login'; +import { + BaseLogin, + Login, + LoginEmailParams, + LoginRegisterParams, + LoginRegisterResponse, + LoginResponseParams, + LoginResponseResponse, + LoginStartResponse, +} from './login/login'; +import * as VerificationsAPI from './verifications/verifications'; +import { + BaseVerifications, + VerificationAcceptResponse, + VerificationCancelParams, + VerificationCancelResponse, + VerificationCreateParams, + VerificationCreateResponse, + VerificationListResponse, + VerificationRetrieveResponse, + Verifications, +} from './verifications/verifications'; +import { APIPromise } from '../../core/api-promise'; +import { RequestOptions } from '../../internal/request-options'; + +/** + * Manage Beeper app login and encrypted messaging setup + */ +export class BaseApp extends APIResource { + static override readonly _key: readonly ['app'] = Object.freeze(['app'] as const); + + /** + * Return the current Beeper Desktop or Beeper Server sign-in and encrypted + * messaging setup state. This endpoint is public before sign-in so apps can + * discover that sign-in is needed; after sign-in, pass a read token. + */ + session(options?: RequestOptions): APIPromise { + return this._client.get('/v1/app/setup', options); + } +} +/** + * Manage Beeper app login and encrypted messaging setup + */ +export class App extends BaseApp { + login: LoginAPI.Login = new LoginAPI.Login(this._client); + verifications: VerificationsAPI.Verifications = new VerificationsAPI.Verifications(this._client); +} + +/** + * Trusted device verification progress. + */ +export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; +} + +export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } +} + +export interface AppSessionResponse { + /** + * Encrypted messaging setup status. + */ + e2ee: AppSessionResponse.E2EE; + + /** + * Current sign-in and encrypted messaging setup state for Beeper Desktop or Beeper + * Server. + */ + state: + | 'needs-login' + | 'initializing' + | 'needs-cross-signing-setup' + | 'needs-verification' + | 'needs-secrets' + | 'needs-first-sync' + | 'ready'; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + matrix?: AppSessionResponse.Matrix; + + /** + * Trusted device verification progress. + */ + verification?: AppSessionResponse.Verification; +} + +export namespace AppSessionResponse { + /** + * Encrypted messaging setup status. + */ + export interface E2EE { + /** + * Whether this account can verify trusted devices. + */ + crossSigning: boolean; + + /** + * Whether the first encrypted message sync is complete. + */ + firstSyncDone: boolean; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + hasBackedUpRecoveryKey: boolean; + + /** + * Whether encrypted messaging setup has started. + */ + initialized: boolean; + + /** + * Whether encrypted message backup is available. + */ + keyBackup: boolean; + + /** + * Encrypted messaging keys available on this device. + */ + secrets: E2EE.Secrets; + + /** + * Whether secure key storage is available. + */ + secretStorage: boolean; + + /** + * Whether this device is trusted for encrypted messages. + */ + verified: boolean; + + /** + * Unix timestamp for when the recovery key was created. + */ + recoveryKeyGeneratedAt?: number; + } + + export namespace E2EE { + /** + * Encrypted messaging keys available on this device. + */ + export interface Secrets { + /** + * Whether the account identity key is available. + */ + masterKey: boolean; + + /** + * Whether the encrypted message backup key is available. + */ + megolmBackupKey: boolean; + + /** + * Whether a recovery key is available. + */ + recoveryKey: boolean; + + /** + * Whether the device trust key is available. + */ + selfSigningKey: boolean; + + /** + * Whether the user trust key is available. + */ + userSigningKey: boolean; + } + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + export interface Matrix { + /** + * Current device ID. + */ + deviceID: string; + + /** + * Beeper homeserver URL for this account. + */ + homeserver: string; + + /** + * Signed-in Beeper user ID. + */ + userID: string; + } + + /** + * Trusted device verification progress. + */ + export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; + } + + export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } +} + +App.Login = Login; +App.BaseLogin = BaseLogin; +App.Verifications = Verifications; +App.BaseVerifications = BaseVerifications; + +export declare namespace App { + export { type Verification as Verification, type AppSessionResponse as AppSessionResponse }; + + export { + Login as Login, + BaseLogin as BaseLogin, + type LoginRegisterResponse as LoginRegisterResponse, + type LoginResponseResponse as LoginResponseResponse, + type LoginStartResponse as LoginStartResponse, + type LoginEmailParams as LoginEmailParams, + type LoginRegisterParams as LoginRegisterParams, + type LoginResponseParams as LoginResponseParams, + }; + + export { + Verifications as Verifications, + BaseVerifications as BaseVerifications, + type VerificationCreateResponse as VerificationCreateResponse, + type VerificationRetrieveResponse as VerificationRetrieveResponse, + type VerificationListResponse as VerificationListResponse, + type VerificationAcceptResponse as VerificationAcceptResponse, + type VerificationCancelResponse as VerificationCancelResponse, + type VerificationCreateParams as VerificationCreateParams, + type VerificationCancelParams as VerificationCancelParams, + }; +} diff --git a/src/resources/app/index.ts b/src/resources/app/index.ts new file mode 100644 index 0000000..d1fd301 --- /dev/null +++ b/src/resources/app/index.ts @@ -0,0 +1,24 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { App, BaseApp, type Verification, type AppSessionResponse } from './app'; +export { + Login, + BaseLogin, + type LoginRegisterResponse, + type LoginResponseResponse, + type LoginStartResponse, + type LoginEmailParams, + type LoginRegisterParams, + type LoginResponseParams, +} from './login/index'; +export { + Verifications, + BaseVerifications, + type VerificationCreateResponse, + type VerificationRetrieveResponse, + type VerificationListResponse, + type VerificationAcceptResponse, + type VerificationCancelResponse, + type VerificationCreateParams, + type VerificationCancelParams, +} from './verifications/index'; diff --git a/src/resources/app/login.ts b/src/resources/app/login.ts new file mode 100644 index 0000000..8809991 --- /dev/null +++ b/src/resources/app/login.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './login/index'; diff --git a/src/resources/app/login/index.ts b/src/resources/app/login/index.ts new file mode 100644 index 0000000..b1a5c5b --- /dev/null +++ b/src/resources/app/login/index.ts @@ -0,0 +1,13 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { + Login, + BaseLogin, + type LoginRegisterResponse, + type LoginResponseResponse, + type LoginStartResponse, + type LoginEmailParams, + type LoginRegisterParams, + type LoginResponseParams, +} from './login'; +export { Verification, BaseVerification } from './verification/index'; diff --git a/src/resources/app/login/login.ts b/src/resources/app/login/login.ts new file mode 100644 index 0000000..359f2be --- /dev/null +++ b/src/resources/app/login/login.ts @@ -0,0 +1,780 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../../core/resource'; +import * as VerificationAPI from './verification/verification'; +import { BaseVerification, Verification as VerificationAPIVerification } from './verification/verification'; +import { APIPromise } from '../../../core/api-promise'; +import { buildHeaders } from '../../../internal/headers'; +import { RequestOptions } from '../../../internal/request-options'; + +/** + * Complete first-party Beeper app login + */ +export class BaseLogin extends APIResource { + static override readonly _key: readonly ['app', 'login'] = Object.freeze(['app', 'login'] as const); + + /** + * Send a sign-in code to the user email address for app setup. + */ + email(body: LoginEmailParams, options?: RequestOptions): APIPromise { + return this._client.post('/v1/app/setup/email', { + body, + ...options, + headers: buildHeaders([{ Accept: '*/*' }, options?.headers]), + __security: {}, + }); + } + + /** + * Create a Beeper account after the user chooses a username and accepts the Terms + * of Use. + */ + register(body: LoginRegisterParams, options?: RequestOptions): APIPromise { + return this._client.post('/v1/app/setup/register', { body, ...options, __security: {} }); + } + + /** + * Finish setup sign-in with the code sent to the user email address. If the user + * needs a new account, the response includes account creation copy and username + * suggestions. + */ + response(body: LoginResponseParams, options?: RequestOptions): APIPromise { + return this._client.post('/v1/app/setup/response', { body, ...options, __security: {} }); + } + + /** + * Start setting up Beeper Desktop or Beeper Server. The flow supports existing + * Beeper accounts and new account creation. + */ + start(options?: RequestOptions): APIPromise { + return this._client.post('/v1/app/setup/start', { ...options, __security: {} }); + } +} +/** + * Complete first-party Beeper app login + */ +export class Login extends BaseLogin { + verification: VerificationAPI.Verification = new VerificationAPI.Verification(this._client); +} + +export interface LoginRegisterResponse { + /** + * Account credentials for first-party app setup. + */ + matrix: LoginRegisterResponse.Matrix; + + /** + * Current app sign-in and encrypted messaging setup state after sign-in. + */ + session: LoginRegisterResponse.Session; +} + +export namespace LoginRegisterResponse { + /** + * Account credentials for first-party app setup. + */ + export interface Matrix { + /** + * Beeper account access token. Returned once for first-party app setup. + */ + accessToken: string; + + /** + * Current device ID. + */ + deviceID: string; + + /** + * Beeper homeserver URL for this account. + */ + homeserver: string; + + /** + * Signed-in Beeper user ID. + */ + userID: string; + } + + /** + * Current app sign-in and encrypted messaging setup state after sign-in. + */ + export interface Session { + /** + * Encrypted messaging setup status. + */ + e2ee: Session.E2EE; + + /** + * Current sign-in and encrypted messaging setup state for Beeper Desktop or Beeper + * Server. + */ + state: + | 'needs-login' + | 'initializing' + | 'needs-cross-signing-setup' + | 'needs-verification' + | 'needs-secrets' + | 'needs-first-sync' + | 'ready'; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + matrix?: Session.Matrix; + + /** + * Trusted device verification progress. + */ + verification?: Session.Verification; + } + + export namespace Session { + /** + * Encrypted messaging setup status. + */ + export interface E2EE { + /** + * Whether this account can verify trusted devices. + */ + crossSigning: boolean; + + /** + * Whether the first encrypted message sync is complete. + */ + firstSyncDone: boolean; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + hasBackedUpRecoveryKey: boolean; + + /** + * Whether encrypted messaging setup has started. + */ + initialized: boolean; + + /** + * Whether encrypted message backup is available. + */ + keyBackup: boolean; + + /** + * Encrypted messaging keys available on this device. + */ + secrets: E2EE.Secrets; + + /** + * Whether secure key storage is available. + */ + secretStorage: boolean; + + /** + * Whether this device is trusted for encrypted messages. + */ + verified: boolean; + + /** + * Unix timestamp for when the recovery key was created. + */ + recoveryKeyGeneratedAt?: number; + } + + export namespace E2EE { + /** + * Encrypted messaging keys available on this device. + */ + export interface Secrets { + /** + * Whether the account identity key is available. + */ + masterKey: boolean; + + /** + * Whether the encrypted message backup key is available. + */ + megolmBackupKey: boolean; + + /** + * Whether a recovery key is available. + */ + recoveryKey: boolean; + + /** + * Whether the device trust key is available. + */ + selfSigningKey: boolean; + + /** + * Whether the user trust key is available. + */ + userSigningKey: boolean; + } + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + export interface Matrix { + /** + * Current device ID. + */ + deviceID: string; + + /** + * Beeper homeserver URL for this account. + */ + homeserver: string; + + /** + * Signed-in Beeper user ID. + */ + userID: string; + } + + /** + * Trusted device verification progress. + */ + export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; + } + + export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } + } +} + +export type LoginResponseResponse = + | LoginResponseResponse.Success + | LoginResponseResponse.RegistrationRequired; + +export namespace LoginResponseResponse { + export interface Success { + /** + * Account credentials for first-party app setup. + */ + matrix: Success.Matrix; + + /** + * Current app sign-in and encrypted messaging setup state after sign-in. + */ + session: Success.Session; + } + + export namespace Success { + /** + * Account credentials for first-party app setup. + */ + export interface Matrix { + /** + * Beeper account access token. Returned once for first-party app setup. + */ + accessToken: string; + + /** + * Current device ID. + */ + deviceID: string; + + /** + * Beeper homeserver URL for this account. + */ + homeserver: string; + + /** + * Signed-in Beeper user ID. + */ + userID: string; + } + + /** + * Current app sign-in and encrypted messaging setup state after sign-in. + */ + export interface Session { + /** + * Encrypted messaging setup status. + */ + e2ee: Session.E2EE; + + /** + * Current sign-in and encrypted messaging setup state for Beeper Desktop or Beeper + * Server. + */ + state: + | 'needs-login' + | 'initializing' + | 'needs-cross-signing-setup' + | 'needs-verification' + | 'needs-secrets' + | 'needs-first-sync' + | 'ready'; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + matrix?: Session.Matrix; + + /** + * Trusted device verification progress. + */ + verification?: Session.Verification; + } + + export namespace Session { + /** + * Encrypted messaging setup status. + */ + export interface E2EE { + /** + * Whether this account can verify trusted devices. + */ + crossSigning: boolean; + + /** + * Whether the first encrypted message sync is complete. + */ + firstSyncDone: boolean; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + hasBackedUpRecoveryKey: boolean; + + /** + * Whether encrypted messaging setup has started. + */ + initialized: boolean; + + /** + * Whether encrypted message backup is available. + */ + keyBackup: boolean; + + /** + * Encrypted messaging keys available on this device. + */ + secrets: E2EE.Secrets; + + /** + * Whether secure key storage is available. + */ + secretStorage: boolean; + + /** + * Whether this device is trusted for encrypted messages. + */ + verified: boolean; + + /** + * Unix timestamp for when the recovery key was created. + */ + recoveryKeyGeneratedAt?: number; + } + + export namespace E2EE { + /** + * Encrypted messaging keys available on this device. + */ + export interface Secrets { + /** + * Whether the account identity key is available. + */ + masterKey: boolean; + + /** + * Whether the encrypted message backup key is available. + */ + megolmBackupKey: boolean; + + /** + * Whether a recovery key is available. + */ + recoveryKey: boolean; + + /** + * Whether the device trust key is available. + */ + selfSigningKey: boolean; + + /** + * Whether the user trust key is available. + */ + userSigningKey: boolean; + } + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + export interface Matrix { + /** + * Current device ID. + */ + deviceID: string; + + /** + * Beeper homeserver URL for this account. + */ + homeserver: string; + + /** + * Signed-in Beeper user ID. + */ + userID: string; + } + + /** + * Trusted device verification progress. + */ + export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; + } + + export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } + } + } + + export interface RegistrationRequired { + /** + * Copy to display during account creation. + */ + copy: RegistrationRequired.Copy; + + /** + * Registration token returned by Beeper. + */ + leadToken: string; + + /** + * Indicates that the user needs to create a Beeper account. + */ + registrationRequired: true; + + /** + * Setup request ID to use when creating the account. + */ + setupRequestID: string; + + /** + * Suggested usernames for the new account. + */ + usernameSuggestions?: Array; + } + + export namespace RegistrationRequired { + /** + * Copy to display during account creation. + */ + export interface Copy { + /** + * Submit button label. + */ + submit: 'Continue'; + + /** + * Terms and privacy notice to show before account creation. + */ + terms: 'By continuing, you agree to the Terms of Use and acknowledge the Privacy Policy.'; + + /** + * Title for the username step. + */ + title: 'Choose your username'; + + /** + * Placeholder for the username field. + */ + usernamePlaceholder: 'Username'; + } + } +} + +export interface LoginStartResponse { + /** + * Setup request ID to use in the next sign-in step. + */ + setupRequestID: string; + + /** + * Available sign-in methods for this setup request. + */ + signInMethods: Array; +} + +export interface LoginEmailParams { + /** + * Email address to send the sign-in code to. + */ + email: string; + + /** + * Setup request ID returned by the start step. + */ + setupRequestID: string; +} + +export interface LoginRegisterParams { + /** + * Confirms that the user agreed to our + * [terms of use](https://www.beeper.com/terms-onboarding) and has read our + * [privacy policy](https://www.beeper.com/privacy). + */ + acceptTerms: true; + + /** + * Registration token returned by Beeper. + */ + leadToken: string; + + /** + * Setup request ID returned by the start step. + */ + setupRequestID: string; + + /** + * Username selected by the user. + */ + username: string; +} + +export interface LoginResponseParams { + /** + * Sign-in code from the user email. + */ + response: string; + + /** + * Setup request ID returned by the start step. + */ + setupRequestID: string; +} + +Login.Verification = VerificationAPIVerification; +Login.BaseVerification = BaseVerification; + +export declare namespace Login { + export { + type LoginRegisterResponse as LoginRegisterResponse, + type LoginResponseResponse as LoginResponseResponse, + type LoginStartResponse as LoginStartResponse, + type LoginEmailParams as LoginEmailParams, + type LoginRegisterParams as LoginRegisterParams, + type LoginResponseParams as LoginResponseParams, + }; + + export { VerificationAPIVerification as Verification, BaseVerification as BaseVerification }; +} diff --git a/src/resources/app/login/verification.ts b/src/resources/app/login/verification.ts new file mode 100644 index 0000000..d46fce2 --- /dev/null +++ b/src/resources/app/login/verification.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './verification/index'; diff --git a/src/resources/app/login/verification/index.ts b/src/resources/app/login/verification/index.ts new file mode 100644 index 0000000..a24d5e5 --- /dev/null +++ b/src/resources/app/login/verification/index.ts @@ -0,0 +1,9 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { + RecoveryKey, + BaseRecoveryKey, + type RecoveryKeyVerifyResponse, + type RecoveryKeyVerifyParams, +} from './recovery-key/index'; +export { Verification, BaseVerification } from './verification'; diff --git a/src/resources/app/login/verification/recovery-key.ts b/src/resources/app/login/verification/recovery-key.ts new file mode 100644 index 0000000..670c484 --- /dev/null +++ b/src/resources/app/login/verification/recovery-key.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './recovery-key/index'; diff --git a/src/resources/app/login/verification/recovery-key/index.ts b/src/resources/app/login/verification/recovery-key/index.ts new file mode 100644 index 0000000..e0dbac2 --- /dev/null +++ b/src/resources/app/login/verification/recovery-key/index.ts @@ -0,0 +1,16 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { + RecoveryKey, + BaseRecoveryKey, + type RecoveryKeyVerifyResponse, + type RecoveryKeyVerifyParams, +} from './recovery-key'; +export { + Reset, + BaseReset, + type ResetCreateResponse, + type ResetConfirmResponse, + type ResetCreateParams, + type ResetConfirmParams, +} from './reset'; diff --git a/src/resources/app/login/verification/recovery-key/recovery-key.ts b/src/resources/app/login/verification/recovery-key/recovery-key.ts new file mode 100644 index 0000000..306da97 --- /dev/null +++ b/src/resources/app/login/verification/recovery-key/recovery-key.ts @@ -0,0 +1,328 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../../../../core/resource'; +import * as ResetAPI from './reset'; +import { + BaseReset, + Reset, + ResetConfirmParams, + ResetConfirmResponse, + ResetCreateParams, + ResetCreateResponse, +} from './reset'; +import { APIPromise } from '../../../../../core/api-promise'; +import { RequestOptions } from '../../../../../internal/request-options'; + +/** + * First-party sign-in and encrypted messaging setup for Beeper Desktop and Beeper Server. + */ +export class BaseRecoveryKey extends APIResource { + static override readonly _key: readonly ['app', 'login', 'verification', 'recoveryKey'] = Object.freeze([ + 'app', + 'login', + 'verification', + 'recoveryKey', + ] as const); + + /** + * Unlock encrypted messages with the user recovery key. + */ + verify(body: RecoveryKeyVerifyParams, options?: RequestOptions): APIPromise { + return this._client.post('/v1/app/setup/verification/recovery-key', { body, ...options }); + } +} +/** + * First-party sign-in and encrypted messaging setup for Beeper Desktop and Beeper Server. + */ +export class RecoveryKey extends BaseRecoveryKey { + reset: ResetAPI.Reset = new ResetAPI.Reset(this._client); +} + +export interface RecoveryKeyVerifyResponse { + /** + * Current app sign-in and encrypted messaging setup state. + */ + session: RecoveryKeyVerifyResponse.Session; +} + +export namespace RecoveryKeyVerifyResponse { + /** + * Current app sign-in and encrypted messaging setup state. + */ + export interface Session { + /** + * Encrypted messaging setup status. + */ + e2ee: Session.E2EE; + + /** + * Current sign-in and encrypted messaging setup state for Beeper Desktop or Beeper + * Server. + */ + state: + | 'needs-login' + | 'initializing' + | 'needs-cross-signing-setup' + | 'needs-verification' + | 'needs-secrets' + | 'needs-first-sync' + | 'ready'; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + matrix?: Session.Matrix; + + /** + * Trusted device verification progress. + */ + verification?: Session.Verification; + } + + export namespace Session { + /** + * Encrypted messaging setup status. + */ + export interface E2EE { + /** + * Whether this account can verify trusted devices. + */ + crossSigning: boolean; + + /** + * Whether the first encrypted message sync is complete. + */ + firstSyncDone: boolean; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + hasBackedUpRecoveryKey: boolean; + + /** + * Whether encrypted messaging setup has started. + */ + initialized: boolean; + + /** + * Whether encrypted message backup is available. + */ + keyBackup: boolean; + + /** + * Encrypted messaging keys available on this device. + */ + secrets: E2EE.Secrets; + + /** + * Whether secure key storage is available. + */ + secretStorage: boolean; + + /** + * Whether this device is trusted for encrypted messages. + */ + verified: boolean; + + /** + * Unix timestamp for when the recovery key was created. + */ + recoveryKeyGeneratedAt?: number; + } + + export namespace E2EE { + /** + * Encrypted messaging keys available on this device. + */ + export interface Secrets { + /** + * Whether the account identity key is available. + */ + masterKey: boolean; + + /** + * Whether the encrypted message backup key is available. + */ + megolmBackupKey: boolean; + + /** + * Whether a recovery key is available. + */ + recoveryKey: boolean; + + /** + * Whether the device trust key is available. + */ + selfSigningKey: boolean; + + /** + * Whether the user trust key is available. + */ + userSigningKey: boolean; + } + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + export interface Matrix { + /** + * Current device ID. + */ + deviceID: string; + + /** + * Beeper homeserver URL for this account. + */ + homeserver: string; + + /** + * Signed-in Beeper user ID. + */ + userID: string; + } + + /** + * Trusted device verification progress. + */ + export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; + } + + export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } + } +} + +export interface RecoveryKeyVerifyParams { + /** + * Recovery key saved by the user. + */ + recoveryKey: string; +} + +RecoveryKey.Reset = Reset; +RecoveryKey.BaseReset = BaseReset; + +export declare namespace RecoveryKey { + export { + type RecoveryKeyVerifyResponse as RecoveryKeyVerifyResponse, + type RecoveryKeyVerifyParams as RecoveryKeyVerifyParams, + }; + + export { + Reset as Reset, + BaseReset as BaseReset, + type ResetCreateResponse as ResetCreateResponse, + type ResetConfirmResponse as ResetConfirmResponse, + type ResetCreateParams as ResetCreateParams, + type ResetConfirmParams as ResetConfirmParams, + }; +} diff --git a/src/resources/app/login/verification/recovery-key/reset.ts b/src/resources/app/login/verification/recovery-key/reset.ts new file mode 100644 index 0000000..7f801b3 --- /dev/null +++ b/src/resources/app/login/verification/recovery-key/reset.ts @@ -0,0 +1,590 @@ +// 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'; + +/** + * First-party sign-in and encrypted messaging setup for Beeper Desktop and Beeper Server. + */ +export class BaseReset extends APIResource { + static override readonly _key: readonly ['app', 'login', 'verification', 'recoveryKey', 'reset'] = + Object.freeze(['app', 'login', 'verification', 'recoveryKey', 'reset'] as const); + + /** + * Create a new recovery key when the user cannot use the existing one. + */ + create( + body: ResetCreateParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.post('/v1/app/setup/verification/recovery-key/reset', { body, ...options }); + } + + /** + * Confirm that the new recovery key should be used for this account. + */ + confirm(body: ResetConfirmParams, options?: RequestOptions): APIPromise { + return this._client.post('/v1/app/setup/verification/recovery-key/reset/confirm', { body, ...options }); + } +} +/** + * First-party sign-in and encrypted messaging setup for Beeper Desktop and Beeper Server. + */ +export class Reset extends BaseReset {} + +export interface ResetCreateResponse { + /** + * New recovery key. Show it once and ask the user to save it. + */ + recoveryKey: string; + + /** + * Current app sign-in and encrypted messaging setup state after creating the new + * recovery key. + */ + session: ResetCreateResponse.Session; +} + +export namespace ResetCreateResponse { + /** + * Current app sign-in and encrypted messaging setup state after creating the new + * recovery key. + */ + export interface Session { + /** + * Encrypted messaging setup status. + */ + e2ee: Session.E2EE; + + /** + * Current sign-in and encrypted messaging setup state for Beeper Desktop or Beeper + * Server. + */ + state: + | 'needs-login' + | 'initializing' + | 'needs-cross-signing-setup' + | 'needs-verification' + | 'needs-secrets' + | 'needs-first-sync' + | 'ready'; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + matrix?: Session.Matrix; + + /** + * Trusted device verification progress. + */ + verification?: Session.Verification; + } + + export namespace Session { + /** + * Encrypted messaging setup status. + */ + export interface E2EE { + /** + * Whether this account can verify trusted devices. + */ + crossSigning: boolean; + + /** + * Whether the first encrypted message sync is complete. + */ + firstSyncDone: boolean; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + hasBackedUpRecoveryKey: boolean; + + /** + * Whether encrypted messaging setup has started. + */ + initialized: boolean; + + /** + * Whether encrypted message backup is available. + */ + keyBackup: boolean; + + /** + * Encrypted messaging keys available on this device. + */ + secrets: E2EE.Secrets; + + /** + * Whether secure key storage is available. + */ + secretStorage: boolean; + + /** + * Whether this device is trusted for encrypted messages. + */ + verified: boolean; + + /** + * Unix timestamp for when the recovery key was created. + */ + recoveryKeyGeneratedAt?: number; + } + + export namespace E2EE { + /** + * Encrypted messaging keys available on this device. + */ + export interface Secrets { + /** + * Whether the account identity key is available. + */ + masterKey: boolean; + + /** + * Whether the encrypted message backup key is available. + */ + megolmBackupKey: boolean; + + /** + * Whether a recovery key is available. + */ + recoveryKey: boolean; + + /** + * Whether the device trust key is available. + */ + selfSigningKey: boolean; + + /** + * Whether the user trust key is available. + */ + userSigningKey: boolean; + } + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + export interface Matrix { + /** + * Current device ID. + */ + deviceID: string; + + /** + * Beeper homeserver URL for this account. + */ + homeserver: string; + + /** + * Signed-in Beeper user ID. + */ + userID: string; + } + + /** + * Trusted device verification progress. + */ + export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; + } + + export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } + } +} + +export interface ResetConfirmResponse { + /** + * Current app sign-in and encrypted messaging setup state. + */ + session: ResetConfirmResponse.Session; +} + +export namespace ResetConfirmResponse { + /** + * Current app sign-in and encrypted messaging setup state. + */ + export interface Session { + /** + * Encrypted messaging setup status. + */ + e2ee: Session.E2EE; + + /** + * Current sign-in and encrypted messaging setup state for Beeper Desktop or Beeper + * Server. + */ + state: + | 'needs-login' + | 'initializing' + | 'needs-cross-signing-setup' + | 'needs-verification' + | 'needs-secrets' + | 'needs-first-sync' + | 'ready'; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + matrix?: Session.Matrix; + + /** + * Trusted device verification progress. + */ + verification?: Session.Verification; + } + + export namespace Session { + /** + * Encrypted messaging setup status. + */ + export interface E2EE { + /** + * Whether this account can verify trusted devices. + */ + crossSigning: boolean; + + /** + * Whether the first encrypted message sync is complete. + */ + firstSyncDone: boolean; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + hasBackedUpRecoveryKey: boolean; + + /** + * Whether encrypted messaging setup has started. + */ + initialized: boolean; + + /** + * Whether encrypted message backup is available. + */ + keyBackup: boolean; + + /** + * Encrypted messaging keys available on this device. + */ + secrets: E2EE.Secrets; + + /** + * Whether secure key storage is available. + */ + secretStorage: boolean; + + /** + * Whether this device is trusted for encrypted messages. + */ + verified: boolean; + + /** + * Unix timestamp for when the recovery key was created. + */ + recoveryKeyGeneratedAt?: number; + } + + export namespace E2EE { + /** + * Encrypted messaging keys available on this device. + */ + export interface Secrets { + /** + * Whether the account identity key is available. + */ + masterKey: boolean; + + /** + * Whether the encrypted message backup key is available. + */ + megolmBackupKey: boolean; + + /** + * Whether a recovery key is available. + */ + recoveryKey: boolean; + + /** + * Whether the device trust key is available. + */ + selfSigningKey: boolean; + + /** + * Whether the user trust key is available. + */ + userSigningKey: boolean; + } + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + export interface Matrix { + /** + * Current device ID. + */ + deviceID: string; + + /** + * Beeper homeserver URL for this account. + */ + homeserver: string; + + /** + * Signed-in Beeper user ID. + */ + userID: string; + } + + /** + * Trusted device verification progress. + */ + export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; + } + + export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } + } +} + +export interface ResetCreateParams { + /** + * Existing recovery key, if the user has it. + */ + existingRecoveryKey?: string; +} + +export interface ResetConfirmParams { + /** + * New recovery key returned by the reset step. + */ + recoveryKey: string; +} + +export declare namespace Reset { + export { + type ResetCreateResponse as ResetCreateResponse, + type ResetConfirmResponse as ResetConfirmResponse, + type ResetCreateParams as ResetCreateParams, + type ResetConfirmParams as ResetConfirmParams, + }; +} diff --git a/src/resources/app/login/verification/verification.ts b/src/resources/app/login/verification/verification.ts new file mode 100644 index 0000000..0583568 --- /dev/null +++ b/src/resources/app/login/verification/verification.ts @@ -0,0 +1,33 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../../../core/resource'; +import * as RecoveryKeyAPI from './recovery-key/recovery-key'; +import { + BaseRecoveryKey, + RecoveryKey, + RecoveryKeyVerifyParams, + RecoveryKeyVerifyResponse, +} from './recovery-key/recovery-key'; + +export class BaseVerification extends APIResource { + static override readonly _key: readonly ['app', 'login', 'verification'] = Object.freeze([ + 'app', + 'login', + 'verification', + ] as const); +} +export class Verification extends BaseVerification { + recoveryKey: RecoveryKeyAPI.RecoveryKey = new RecoveryKeyAPI.RecoveryKey(this._client); +} + +Verification.RecoveryKey = RecoveryKey; +Verification.BaseRecoveryKey = BaseRecoveryKey; + +export declare namespace Verification { + export { + RecoveryKey as RecoveryKey, + BaseRecoveryKey as BaseRecoveryKey, + type RecoveryKeyVerifyResponse as RecoveryKeyVerifyResponse, + type RecoveryKeyVerifyParams as RecoveryKeyVerifyParams, + }; +} diff --git a/src/resources/app/verifications.ts b/src/resources/app/verifications.ts new file mode 100644 index 0000000..6d82890 --- /dev/null +++ b/src/resources/app/verifications.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './verifications/index'; diff --git a/src/resources/app/verifications/index.ts b/src/resources/app/verifications/index.ts new file mode 100644 index 0000000..a8a8aac --- /dev/null +++ b/src/resources/app/verifications/index.ts @@ -0,0 +1,15 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { Qr, BaseQr, type QrConfirmScannedResponse, type QrScanResponse, type QrScanParams } from './qr'; +export { SAS, BaseSAS, type SASConfirmResponse, type SASStartResponse } from './sas'; +export { + Verifications, + BaseVerifications, + type VerificationCreateResponse, + type VerificationRetrieveResponse, + type VerificationListResponse, + type VerificationAcceptResponse, + type VerificationCancelResponse, + type VerificationCreateParams, + type VerificationCancelParams, +} from './verifications'; diff --git a/src/resources/app/verifications/qr.ts b/src/resources/app/verifications/qr.ts new file mode 100644 index 0000000..0950844 --- /dev/null +++ b/src/resources/app/verifications/qr.ts @@ -0,0 +1,820 @@ +// 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'; +import { path } from '../../../internal/utils/path'; + +/** + * First-party sign-in and encrypted messaging setup for Beeper Desktop and Beeper Server. + */ +export class BaseQr extends APIResource { + static override readonly _key: readonly ['app', 'verifications', 'qr'] = Object.freeze([ + 'app', + 'verifications', + 'qr', + ] as const); + + /** + * Confirm that another device scanned this device QR code. + */ + confirmScanned(verificationID: string, options?: RequestOptions): APIPromise { + return this._client.post(path`/v1/app/setup/verifications/${verificationID}/qr/confirm-scanned`, options); + } + + /** + * Submit the QR code scanned from another signed-in device. + */ + scan(body: QrScanParams, options?: RequestOptions): APIPromise { + return this._client.post('/v1/app/setup/verifications/qr/scan', { body, ...options }); + } +} +/** + * First-party sign-in and encrypted messaging setup for Beeper Desktop and Beeper Server. + */ +export class Qr extends BaseQr {} + +export interface QrConfirmScannedResponse { + /** + * Current app sign-in and encrypted messaging setup state. + */ + session: QrConfirmScannedResponse.Session; + + /** + * Trusted device verification progress. + */ + verification?: QrConfirmScannedResponse.Verification; +} + +export namespace QrConfirmScannedResponse { + /** + * Current app sign-in and encrypted messaging setup state. + */ + export interface Session { + /** + * Encrypted messaging setup status. + */ + e2ee: Session.E2EE; + + /** + * Current sign-in and encrypted messaging setup state for Beeper Desktop or Beeper + * Server. + */ + state: + | 'needs-login' + | 'initializing' + | 'needs-cross-signing-setup' + | 'needs-verification' + | 'needs-secrets' + | 'needs-first-sync' + | 'ready'; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + matrix?: Session.Matrix; + + /** + * Trusted device verification progress. + */ + verification?: Session.Verification; + } + + export namespace Session { + /** + * Encrypted messaging setup status. + */ + export interface E2EE { + /** + * Whether this account can verify trusted devices. + */ + crossSigning: boolean; + + /** + * Whether the first encrypted message sync is complete. + */ + firstSyncDone: boolean; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + hasBackedUpRecoveryKey: boolean; + + /** + * Whether encrypted messaging setup has started. + */ + initialized: boolean; + + /** + * Whether encrypted message backup is available. + */ + keyBackup: boolean; + + /** + * Encrypted messaging keys available on this device. + */ + secrets: E2EE.Secrets; + + /** + * Whether secure key storage is available. + */ + secretStorage: boolean; + + /** + * Whether this device is trusted for encrypted messages. + */ + verified: boolean; + + /** + * Unix timestamp for when the recovery key was created. + */ + recoveryKeyGeneratedAt?: number; + } + + export namespace E2EE { + /** + * Encrypted messaging keys available on this device. + */ + export interface Secrets { + /** + * Whether the account identity key is available. + */ + masterKey: boolean; + + /** + * Whether the encrypted message backup key is available. + */ + megolmBackupKey: boolean; + + /** + * Whether a recovery key is available. + */ + recoveryKey: boolean; + + /** + * Whether the device trust key is available. + */ + selfSigningKey: boolean; + + /** + * Whether the user trust key is available. + */ + userSigningKey: boolean; + } + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + export interface Matrix { + /** + * Current device ID. + */ + deviceID: string; + + /** + * Beeper homeserver URL for this account. + */ + homeserver: string; + + /** + * Signed-in Beeper user ID. + */ + userID: string; + } + + /** + * Trusted device verification progress. + */ + export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; + } + + export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } + } + + /** + * Trusted device verification progress. + */ + export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; + } + + export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } +} + +export interface QrScanResponse { + /** + * Current app sign-in and encrypted messaging setup state. + */ + session: QrScanResponse.Session; + + /** + * Trusted device verification progress. + */ + verification?: QrScanResponse.Verification; +} + +export namespace QrScanResponse { + /** + * Current app sign-in and encrypted messaging setup state. + */ + export interface Session { + /** + * Encrypted messaging setup status. + */ + e2ee: Session.E2EE; + + /** + * Current sign-in and encrypted messaging setup state for Beeper Desktop or Beeper + * Server. + */ + state: + | 'needs-login' + | 'initializing' + | 'needs-cross-signing-setup' + | 'needs-verification' + | 'needs-secrets' + | 'needs-first-sync' + | 'ready'; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + matrix?: Session.Matrix; + + /** + * Trusted device verification progress. + */ + verification?: Session.Verification; + } + + export namespace Session { + /** + * Encrypted messaging setup status. + */ + export interface E2EE { + /** + * Whether this account can verify trusted devices. + */ + crossSigning: boolean; + + /** + * Whether the first encrypted message sync is complete. + */ + firstSyncDone: boolean; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + hasBackedUpRecoveryKey: boolean; + + /** + * Whether encrypted messaging setup has started. + */ + initialized: boolean; + + /** + * Whether encrypted message backup is available. + */ + keyBackup: boolean; + + /** + * Encrypted messaging keys available on this device. + */ + secrets: E2EE.Secrets; + + /** + * Whether secure key storage is available. + */ + secretStorage: boolean; + + /** + * Whether this device is trusted for encrypted messages. + */ + verified: boolean; + + /** + * Unix timestamp for when the recovery key was created. + */ + recoveryKeyGeneratedAt?: number; + } + + export namespace E2EE { + /** + * Encrypted messaging keys available on this device. + */ + export interface Secrets { + /** + * Whether the account identity key is available. + */ + masterKey: boolean; + + /** + * Whether the encrypted message backup key is available. + */ + megolmBackupKey: boolean; + + /** + * Whether a recovery key is available. + */ + recoveryKey: boolean; + + /** + * Whether the device trust key is available. + */ + selfSigningKey: boolean; + + /** + * Whether the user trust key is available. + */ + userSigningKey: boolean; + } + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + export interface Matrix { + /** + * Current device ID. + */ + deviceID: string; + + /** + * Beeper homeserver URL for this account. + */ + homeserver: string; + + /** + * Signed-in Beeper user ID. + */ + userID: string; + } + + /** + * Trusted device verification progress. + */ + export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; + } + + export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } + } + + /** + * Trusted device verification progress. + */ + export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; + } + + export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } +} + +export interface QrScanParams { + /** + * QR code payload scanned from the other device. + */ + data: string; +} + +export declare namespace Qr { + export { + type QrConfirmScannedResponse as QrConfirmScannedResponse, + type QrScanResponse as QrScanResponse, + type QrScanParams as QrScanParams, + }; +} diff --git a/src/resources/app/verifications/sas.ts b/src/resources/app/verifications/sas.ts new file mode 100644 index 0000000..9adfdcf --- /dev/null +++ b/src/resources/app/verifications/sas.ts @@ -0,0 +1,809 @@ +// 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'; +import { path } from '../../../internal/utils/path'; + +/** + * First-party sign-in and encrypted messaging setup for Beeper Desktop and Beeper Server. + */ +export class BaseSAS extends APIResource { + static override readonly _key: readonly ['app', 'verifications', 'sas'] = Object.freeze([ + 'app', + 'verifications', + 'sas', + ] as const); + + /** + * Confirm that the emoji or number sequence matches on both devices. + */ + confirm(verificationID: string, options?: RequestOptions): APIPromise { + return this._client.post(path`/v1/app/setup/verifications/${verificationID}/sas/confirm`, options); + } + + /** + * Start emoji comparison for device verification. + */ + start(verificationID: string, options?: RequestOptions): APIPromise { + return this._client.post(path`/v1/app/setup/verifications/${verificationID}/sas/start`, options); + } +} +/** + * First-party sign-in and encrypted messaging setup for Beeper Desktop and Beeper Server. + */ +export class SAS extends BaseSAS {} + +export interface SASConfirmResponse { + /** + * Current app sign-in and encrypted messaging setup state. + */ + session: SASConfirmResponse.Session; + + /** + * Trusted device verification progress. + */ + verification?: SASConfirmResponse.Verification; +} + +export namespace SASConfirmResponse { + /** + * Current app sign-in and encrypted messaging setup state. + */ + export interface Session { + /** + * Encrypted messaging setup status. + */ + e2ee: Session.E2EE; + + /** + * Current sign-in and encrypted messaging setup state for Beeper Desktop or Beeper + * Server. + */ + state: + | 'needs-login' + | 'initializing' + | 'needs-cross-signing-setup' + | 'needs-verification' + | 'needs-secrets' + | 'needs-first-sync' + | 'ready'; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + matrix?: Session.Matrix; + + /** + * Trusted device verification progress. + */ + verification?: Session.Verification; + } + + export namespace Session { + /** + * Encrypted messaging setup status. + */ + export interface E2EE { + /** + * Whether this account can verify trusted devices. + */ + crossSigning: boolean; + + /** + * Whether the first encrypted message sync is complete. + */ + firstSyncDone: boolean; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + hasBackedUpRecoveryKey: boolean; + + /** + * Whether encrypted messaging setup has started. + */ + initialized: boolean; + + /** + * Whether encrypted message backup is available. + */ + keyBackup: boolean; + + /** + * Encrypted messaging keys available on this device. + */ + secrets: E2EE.Secrets; + + /** + * Whether secure key storage is available. + */ + secretStorage: boolean; + + /** + * Whether this device is trusted for encrypted messages. + */ + verified: boolean; + + /** + * Unix timestamp for when the recovery key was created. + */ + recoveryKeyGeneratedAt?: number; + } + + export namespace E2EE { + /** + * Encrypted messaging keys available on this device. + */ + export interface Secrets { + /** + * Whether the account identity key is available. + */ + masterKey: boolean; + + /** + * Whether the encrypted message backup key is available. + */ + megolmBackupKey: boolean; + + /** + * Whether a recovery key is available. + */ + recoveryKey: boolean; + + /** + * Whether the device trust key is available. + */ + selfSigningKey: boolean; + + /** + * Whether the user trust key is available. + */ + userSigningKey: boolean; + } + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + export interface Matrix { + /** + * Current device ID. + */ + deviceID: string; + + /** + * Beeper homeserver URL for this account. + */ + homeserver: string; + + /** + * Signed-in Beeper user ID. + */ + userID: string; + } + + /** + * Trusted device verification progress. + */ + export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; + } + + export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } + } + + /** + * Trusted device verification progress. + */ + export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; + } + + export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } +} + +export interface SASStartResponse { + /** + * Current app sign-in and encrypted messaging setup state. + */ + session: SASStartResponse.Session; + + /** + * Trusted device verification progress. + */ + verification?: SASStartResponse.Verification; +} + +export namespace SASStartResponse { + /** + * Current app sign-in and encrypted messaging setup state. + */ + export interface Session { + /** + * Encrypted messaging setup status. + */ + e2ee: Session.E2EE; + + /** + * Current sign-in and encrypted messaging setup state for Beeper Desktop or Beeper + * Server. + */ + state: + | 'needs-login' + | 'initializing' + | 'needs-cross-signing-setup' + | 'needs-verification' + | 'needs-secrets' + | 'needs-first-sync' + | 'ready'; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + matrix?: Session.Matrix; + + /** + * Trusted device verification progress. + */ + verification?: Session.Verification; + } + + export namespace Session { + /** + * Encrypted messaging setup status. + */ + export interface E2EE { + /** + * Whether this account can verify trusted devices. + */ + crossSigning: boolean; + + /** + * Whether the first encrypted message sync is complete. + */ + firstSyncDone: boolean; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + hasBackedUpRecoveryKey: boolean; + + /** + * Whether encrypted messaging setup has started. + */ + initialized: boolean; + + /** + * Whether encrypted message backup is available. + */ + keyBackup: boolean; + + /** + * Encrypted messaging keys available on this device. + */ + secrets: E2EE.Secrets; + + /** + * Whether secure key storage is available. + */ + secretStorage: boolean; + + /** + * Whether this device is trusted for encrypted messages. + */ + verified: boolean; + + /** + * Unix timestamp for when the recovery key was created. + */ + recoveryKeyGeneratedAt?: number; + } + + export namespace E2EE { + /** + * Encrypted messaging keys available on this device. + */ + export interface Secrets { + /** + * Whether the account identity key is available. + */ + masterKey: boolean; + + /** + * Whether the encrypted message backup key is available. + */ + megolmBackupKey: boolean; + + /** + * Whether a recovery key is available. + */ + recoveryKey: boolean; + + /** + * Whether the device trust key is available. + */ + selfSigningKey: boolean; + + /** + * Whether the user trust key is available. + */ + userSigningKey: boolean; + } + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + export interface Matrix { + /** + * Current device ID. + */ + deviceID: string; + + /** + * Beeper homeserver URL for this account. + */ + homeserver: string; + + /** + * Signed-in Beeper user ID. + */ + userID: string; + } + + /** + * Trusted device verification progress. + */ + export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; + } + + export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } + } + + /** + * Trusted device verification progress. + */ + export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; + } + + export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } +} + +export declare namespace SAS { + export { type SASConfirmResponse as SASConfirmResponse, type SASStartResponse as SASStartResponse }; +} diff --git a/src/resources/app/verifications/verifications.ts b/src/resources/app/verifications/verifications.ts new file mode 100644 index 0000000..6749911 --- /dev/null +++ b/src/resources/app/verifications/verifications.ts @@ -0,0 +1,1792 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../../core/resource'; +import * as QrAPI from './qr'; +import { BaseQr, Qr as QrAPIQr, QrConfirmScannedResponse, QrScanParams, QrScanResponse } from './qr'; +import * as SASAPI from './sas'; +import { BaseSAS, SAS as SasapiSAS, SASConfirmResponse, SASStartResponse } from './sas'; +import { APIPromise } from '../../../core/api-promise'; +import { RequestOptions } from '../../../internal/request-options'; +import { path } from '../../../internal/utils/path'; + +/** + * Manage device verification transactions + */ +export class BaseVerifications extends APIResource { + static override readonly _key: readonly ['app', 'verifications'] = Object.freeze([ + 'app', + 'verifications', + ] as const); + + /** + * Start verifying this device from another signed-in device. + */ + create( + body: VerificationCreateParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.post('/v1/app/setup/verifications', { body, ...options }); + } + + /** + * Get the current state of a device verification transaction. + */ + retrieve(verificationID: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/v1/app/setup/verifications/${verificationID}`, options); + } + + /** + * List pending and active device verifications. Use this to recover state without + * a WebSocket connection. + */ + list(options?: RequestOptions): APIPromise { + return this._client.get('/v1/app/setup/verifications', options); + } + + /** + * Accept an incoming device verification request. + */ + accept(verificationID: string, options?: RequestOptions): APIPromise { + return this._client.post(path`/v1/app/setup/verifications/${verificationID}/accept`, options); + } + + /** + * Cancel an active device verification request. + */ + cancel( + verificationID: string, + body: VerificationCancelParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.post(path`/v1/app/setup/verifications/${verificationID}/cancel`, { + body, + ...options, + }); + } +} +/** + * Manage device verification transactions + */ +export class Verifications extends BaseVerifications { + qr: QrAPI.Qr = new QrAPI.Qr(this._client); + sas: SASAPI.SAS = new SASAPI.SAS(this._client); +} + +export interface VerificationCreateResponse { + /** + * Current app sign-in and encrypted messaging setup state. + */ + session: VerificationCreateResponse.Session; + + /** + * Trusted device verification progress. + */ + verification?: VerificationCreateResponse.Verification; +} + +export namespace VerificationCreateResponse { + /** + * Current app sign-in and encrypted messaging setup state. + */ + export interface Session { + /** + * Encrypted messaging setup status. + */ + e2ee: Session.E2EE; + + /** + * Current sign-in and encrypted messaging setup state for Beeper Desktop or Beeper + * Server. + */ + state: + | 'needs-login' + | 'initializing' + | 'needs-cross-signing-setup' + | 'needs-verification' + | 'needs-secrets' + | 'needs-first-sync' + | 'ready'; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + matrix?: Session.Matrix; + + /** + * Trusted device verification progress. + */ + verification?: Session.Verification; + } + + export namespace Session { + /** + * Encrypted messaging setup status. + */ + export interface E2EE { + /** + * Whether this account can verify trusted devices. + */ + crossSigning: boolean; + + /** + * Whether the first encrypted message sync is complete. + */ + firstSyncDone: boolean; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + hasBackedUpRecoveryKey: boolean; + + /** + * Whether encrypted messaging setup has started. + */ + initialized: boolean; + + /** + * Whether encrypted message backup is available. + */ + keyBackup: boolean; + + /** + * Encrypted messaging keys available on this device. + */ + secrets: E2EE.Secrets; + + /** + * Whether secure key storage is available. + */ + secretStorage: boolean; + + /** + * Whether this device is trusted for encrypted messages. + */ + verified: boolean; + + /** + * Unix timestamp for when the recovery key was created. + */ + recoveryKeyGeneratedAt?: number; + } + + export namespace E2EE { + /** + * Encrypted messaging keys available on this device. + */ + export interface Secrets { + /** + * Whether the account identity key is available. + */ + masterKey: boolean; + + /** + * Whether the encrypted message backup key is available. + */ + megolmBackupKey: boolean; + + /** + * Whether a recovery key is available. + */ + recoveryKey: boolean; + + /** + * Whether the device trust key is available. + */ + selfSigningKey: boolean; + + /** + * Whether the user trust key is available. + */ + userSigningKey: boolean; + } + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + export interface Matrix { + /** + * Current device ID. + */ + deviceID: string; + + /** + * Beeper homeserver URL for this account. + */ + homeserver: string; + + /** + * Signed-in Beeper user ID. + */ + userID: string; + } + + /** + * Trusted device verification progress. + */ + export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; + } + + export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } + } + + /** + * Trusted device verification progress. + */ + export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; + } + + export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } +} + +export interface VerificationRetrieveResponse { + /** + * Current app sign-in and encrypted messaging setup state. + */ + session: VerificationRetrieveResponse.Session; + + /** + * Trusted device verification progress. + */ + verification?: VerificationRetrieveResponse.Verification; +} + +export namespace VerificationRetrieveResponse { + /** + * Current app sign-in and encrypted messaging setup state. + */ + export interface Session { + /** + * Encrypted messaging setup status. + */ + e2ee: Session.E2EE; + + /** + * Current sign-in and encrypted messaging setup state for Beeper Desktop or Beeper + * Server. + */ + state: + | 'needs-login' + | 'initializing' + | 'needs-cross-signing-setup' + | 'needs-verification' + | 'needs-secrets' + | 'needs-first-sync' + | 'ready'; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + matrix?: Session.Matrix; + + /** + * Trusted device verification progress. + */ + verification?: Session.Verification; + } + + export namespace Session { + /** + * Encrypted messaging setup status. + */ + export interface E2EE { + /** + * Whether this account can verify trusted devices. + */ + crossSigning: boolean; + + /** + * Whether the first encrypted message sync is complete. + */ + firstSyncDone: boolean; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + hasBackedUpRecoveryKey: boolean; + + /** + * Whether encrypted messaging setup has started. + */ + initialized: boolean; + + /** + * Whether encrypted message backup is available. + */ + keyBackup: boolean; + + /** + * Encrypted messaging keys available on this device. + */ + secrets: E2EE.Secrets; + + /** + * Whether secure key storage is available. + */ + secretStorage: boolean; + + /** + * Whether this device is trusted for encrypted messages. + */ + verified: boolean; + + /** + * Unix timestamp for when the recovery key was created. + */ + recoveryKeyGeneratedAt?: number; + } + + export namespace E2EE { + /** + * Encrypted messaging keys available on this device. + */ + export interface Secrets { + /** + * Whether the account identity key is available. + */ + masterKey: boolean; + + /** + * Whether the encrypted message backup key is available. + */ + megolmBackupKey: boolean; + + /** + * Whether a recovery key is available. + */ + recoveryKey: boolean; + + /** + * Whether the device trust key is available. + */ + selfSigningKey: boolean; + + /** + * Whether the user trust key is available. + */ + userSigningKey: boolean; + } + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + export interface Matrix { + /** + * Current device ID. + */ + deviceID: string; + + /** + * Beeper homeserver URL for this account. + */ + homeserver: string; + + /** + * Signed-in Beeper user ID. + */ + userID: string; + } + + /** + * Trusted device verification progress. + */ + export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; + } + + export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } + } + + /** + * Trusted device verification progress. + */ + export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; + } + + export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } +} + +export interface VerificationListResponse { + items: Array; +} + +export namespace VerificationListResponse { + /** + * Trusted device verification progress. + */ + export interface Item { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Item.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Item.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Item.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Item.SAS; + } + + export namespace Item { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } +} + +export interface VerificationAcceptResponse { + /** + * Current app sign-in and encrypted messaging setup state. + */ + session: VerificationAcceptResponse.Session; + + /** + * Trusted device verification progress. + */ + verification?: VerificationAcceptResponse.Verification; +} + +export namespace VerificationAcceptResponse { + /** + * Current app sign-in and encrypted messaging setup state. + */ + export interface Session { + /** + * Encrypted messaging setup status. + */ + e2ee: Session.E2EE; + + /** + * Current sign-in and encrypted messaging setup state for Beeper Desktop or Beeper + * Server. + */ + state: + | 'needs-login' + | 'initializing' + | 'needs-cross-signing-setup' + | 'needs-verification' + | 'needs-secrets' + | 'needs-first-sync' + | 'ready'; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + matrix?: Session.Matrix; + + /** + * Trusted device verification progress. + */ + verification?: Session.Verification; + } + + export namespace Session { + /** + * Encrypted messaging setup status. + */ + export interface E2EE { + /** + * Whether this account can verify trusted devices. + */ + crossSigning: boolean; + + /** + * Whether the first encrypted message sync is complete. + */ + firstSyncDone: boolean; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + hasBackedUpRecoveryKey: boolean; + + /** + * Whether encrypted messaging setup has started. + */ + initialized: boolean; + + /** + * Whether encrypted message backup is available. + */ + keyBackup: boolean; + + /** + * Encrypted messaging keys available on this device. + */ + secrets: E2EE.Secrets; + + /** + * Whether secure key storage is available. + */ + secretStorage: boolean; + + /** + * Whether this device is trusted for encrypted messages. + */ + verified: boolean; + + /** + * Unix timestamp for when the recovery key was created. + */ + recoveryKeyGeneratedAt?: number; + } + + export namespace E2EE { + /** + * Encrypted messaging keys available on this device. + */ + export interface Secrets { + /** + * Whether the account identity key is available. + */ + masterKey: boolean; + + /** + * Whether the encrypted message backup key is available. + */ + megolmBackupKey: boolean; + + /** + * Whether a recovery key is available. + */ + recoveryKey: boolean; + + /** + * Whether the device trust key is available. + */ + selfSigningKey: boolean; + + /** + * Whether the user trust key is available. + */ + userSigningKey: boolean; + } + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + export interface Matrix { + /** + * Current device ID. + */ + deviceID: string; + + /** + * Beeper homeserver URL for this account. + */ + homeserver: string; + + /** + * Signed-in Beeper user ID. + */ + userID: string; + } + + /** + * Trusted device verification progress. + */ + export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; + } + + export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } + } + + /** + * Trusted device verification progress. + */ + export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; + } + + export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } +} + +export interface VerificationCancelResponse { + /** + * Current app sign-in and encrypted messaging setup state. + */ + session: VerificationCancelResponse.Session; + + /** + * Trusted device verification progress. + */ + verification?: VerificationCancelResponse.Verification; +} + +export namespace VerificationCancelResponse { + /** + * Current app sign-in and encrypted messaging setup state. + */ + export interface Session { + /** + * Encrypted messaging setup status. + */ + e2ee: Session.E2EE; + + /** + * Current sign-in and encrypted messaging setup state for Beeper Desktop or Beeper + * Server. + */ + state: + | 'needs-login' + | 'initializing' + | 'needs-cross-signing-setup' + | 'needs-verification' + | 'needs-secrets' + | 'needs-first-sync' + | 'ready'; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + matrix?: Session.Matrix; + + /** + * Trusted device verification progress. + */ + verification?: Session.Verification; + } + + export namespace Session { + /** + * Encrypted messaging setup status. + */ + export interface E2EE { + /** + * Whether this account can verify trusted devices. + */ + crossSigning: boolean; + + /** + * Whether the first encrypted message sync is complete. + */ + firstSyncDone: boolean; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + hasBackedUpRecoveryKey: boolean; + + /** + * Whether encrypted messaging setup has started. + */ + initialized: boolean; + + /** + * Whether encrypted message backup is available. + */ + keyBackup: boolean; + + /** + * Encrypted messaging keys available on this device. + */ + secrets: E2EE.Secrets; + + /** + * Whether secure key storage is available. + */ + secretStorage: boolean; + + /** + * Whether this device is trusted for encrypted messages. + */ + verified: boolean; + + /** + * Unix timestamp for when the recovery key was created. + */ + recoveryKeyGeneratedAt?: number; + } + + export namespace E2EE { + /** + * Encrypted messaging keys available on this device. + */ + export interface Secrets { + /** + * Whether the account identity key is available. + */ + masterKey: boolean; + + /** + * Whether the encrypted message backup key is available. + */ + megolmBackupKey: boolean; + + /** + * Whether a recovery key is available. + */ + recoveryKey: boolean; + + /** + * Whether the device trust key is available. + */ + selfSigningKey: boolean; + + /** + * Whether the user trust key is available. + */ + userSigningKey: boolean; + } + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + export interface Matrix { + /** + * Current device ID. + */ + deviceID: string; + + /** + * Beeper homeserver URL for this account. + */ + homeserver: string; + + /** + * Signed-in Beeper user ID. + */ + userID: string; + } + + /** + * Trusted device verification progress. + */ + export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; + } + + export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } + } + + /** + * Trusted device verification progress. + */ + export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; + } + + export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } +} + +export interface VerificationCreateParams { + /** + * Why this verification is being started. + */ + purpose?: 'login' | 'device'; + + /** + * Beeper user ID to verify. Defaults to the signed-in user. + */ + userID?: string; +} + +export interface VerificationCancelParams { + /** + * Optional cancellation code. + */ + code?: string; + + /** + * Optional user-facing cancellation reason. + */ + reason?: string; +} + +Verifications.Qr = QrAPIQr; +Verifications.BaseQr = BaseQr; +Verifications.SAS = SasapiSAS; +Verifications.BaseSAS = BaseSAS; + +export declare namespace Verifications { + export { + type VerificationCreateResponse as VerificationCreateResponse, + type VerificationRetrieveResponse as VerificationRetrieveResponse, + type VerificationListResponse as VerificationListResponse, + type VerificationAcceptResponse as VerificationAcceptResponse, + type VerificationCancelResponse as VerificationCancelResponse, + type VerificationCreateParams as VerificationCreateParams, + type VerificationCancelParams as VerificationCancelParams, + }; + + export { + QrAPIQr as Qr, + BaseQr as BaseQr, + type QrConfirmScannedResponse as QrConfirmScannedResponse, + type QrScanResponse as QrScanResponse, + type QrScanParams as QrScanParams, + }; + + export { + SasapiSAS as SAS, + BaseSAS as BaseSAS, + type SASConfirmResponse as SASConfirmResponse, + type SASStartResponse as SASStartResponse, + }; +} diff --git a/src/resources/assets.ts b/src/resources/assets.ts index 93203cf..95d907a 100644 --- a/src/resources/assets.ts +++ b/src/resources/assets.ts @@ -14,8 +14,8 @@ export class BaseAssets extends APIResource { static override readonly _key: readonly ['assets'] = Object.freeze(['assets'] as const); /** - * Download a Matrix file using its mxc:// or localmxc:// URL to the device running - * Beeper Desktop and return the local file URL. + * Download a file from an mxc:// or localmxc:// URL to the device running the + * Beeper Client API and return the local file URL. * * @example * ```ts @@ -51,7 +51,7 @@ export class BaseAssets extends APIResource { /** * Upload a file to a temporary location using multipart/form-data. Returns an - * uploadID that can be referenced when sending a message or materializing a draft + * uploadID that can be referenced when sending a message or creating a draft * attachment. * * @example @@ -70,8 +70,8 @@ export class BaseAssets extends APIResource { /** * Upload a file using a JSON body with base64-encoded content. Returns an uploadID - * that can be referenced when sending a message or materializing a draft - * attachment. Alternative to the multipart upload endpoint. + * that can be referenced when sending a message or creating a draft attachment. + * Alternative to the multipart upload endpoint. * * @example * ```ts @@ -200,7 +200,7 @@ export interface AssetUploadBase64Response { export interface AssetDownloadParams { /** - * Matrix content URL (mxc:// or localmxc://) for the file to download. + * Beeper media URL (mxc:// or localmxc://) for the file to download. */ url: string; } diff --git a/src/resources/bridges.ts b/src/resources/bridges.ts new file mode 100644 index 0000000..3a874ef --- /dev/null +++ b/src/resources/bridges.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './bridges/index'; diff --git a/src/resources/bridges/bridges.ts b/src/resources/bridges/bridges.ts new file mode 100644 index 0000000..e1d63ac --- /dev/null +++ b/src/resources/bridges/bridges.ts @@ -0,0 +1,625 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../core/resource'; +import * as BridgesAPI from './bridges'; +import * as Shared from '../shared'; +import * as AccountsAPI from '../accounts/accounts'; +import * as ConnectionsAPI from './connections'; +import { BaseConnections, Connections } from './connections'; +import * as LoginFlowsAPI from './login-flows'; +import { BaseLoginFlows, LoginFlowListResponse, LoginFlows } from './login-flows'; +import * as LoginSessionsAPI from './login-sessions/login-sessions'; +import { + BaseLoginSessions, + LoginSessionCancelParams, + LoginSessionCancelResponse, + LoginSessionCreateParams, + LoginSessionRetrieveParams, + LoginSessions, +} from './login-sessions/login-sessions'; +import { APIPromise } from '../../core/api-promise'; +import { RequestOptions } from '../../internal/request-options'; +import { path } from '../../internal/utils/path'; + +/** + * Manage bridge-backed account types, connections, and login sessions + */ +export class BaseBridges extends APIResource { + static override readonly _key: readonly ['bridges'] = Object.freeze(['bridges'] as const); + + /** + * Get one bridge, including the chat accounts connected through it. + */ + retrieve(bridgeID: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/v1/bridges/${bridgeID}`, options); + } + + /** + * List available bridges. A bridge is a chat-network connector that can connect or + * reconnect chat accounts. Connected accounts use the same Account schema as GET + * /v1/accounts. + */ + list(options?: RequestOptions): APIPromise { + return this._client.get('/v1/bridges', options); + } + + /** + * Get advanced network capabilities for a bridge. This endpoint is intended for + * clients that build custom connect or chat-creation flows. + */ + retrieveCapabilities(bridgeID: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/v1/bridges/${bridgeID}/capabilities`, options); + } +} +/** + * Manage bridge-backed account types, connections, and login sessions + */ +export class Bridges extends BaseBridges { + loginFlows: LoginFlowsAPI.LoginFlows = new LoginFlowsAPI.LoginFlows(this._client); + connections: ConnectionsAPI.Connections = new ConnectionsAPI.Connections(this._client); + loginSessions: LoginSessionsAPI.LoginSessions = new LoginSessionsAPI.LoginSessions(this._client); +} + +/** + * Available bridge that can connect or reconnect chat accounts. + */ +export interface Bridge { + /** + * Bridge ID. Use with bridge endpoints. + */ + id: string; + + /** + * Connected accounts for this bridge. Uses the same Account schema as GET + * /v1/accounts. + */ + accounts: Array; + + /** + * Number of active accounts for this network on this device. + */ + activeAccountCount: number; + + /** + * Human-friendly bridge name shown in Beeper. + */ + displayName: string; + + /** + * Where accounts for this bridge run: on this device or in Beeper Cloud. + */ + provider: 'cloud' | 'self-hosted' | 'local' | 'platform-sdk'; + + /** + * Whether this bridge can currently be used to connect new accounts. + */ + status: 'available' | 'connected' | 'limit_reached' | 'temporarily_unavailable' | 'disabled'; + + /** + * Whether this bridge can have multiple active accounts for the same network. + */ + supportsMultipleAccounts: boolean; + + /** + * Underlying bridge type, such as matrix, discordgo, slackgo, whatsapp, telegram, + * or twitter. + */ + type: string; + + /** + * Network grouping used for account counts and limits. + */ + network?: string; + + /** + * Human-friendly status text matching Beeper account management language. + */ + statusText?: string; +} + +export interface CookieField { + /** + * Field ID to send back in the fields object. + */ + id: string; + + /** + * Cookie, header, or local storage key to collect. + */ + name?: string; + + /** + * Browser storage source for this value. + */ + type?: 'cookie' | 'header' | 'local_storage'; +} + +/** + * Disappearing-message timer capability. + */ +export interface DisappearingTimerCapability { + types: Array<'' | 'after_read' | 'after_send'>; + + omit_empty_timer?: true; + + timers?: Array; +} + +/** + * Group creation field capability. + */ +export interface GroupFieldCapability { + allowed: boolean; + + max_length?: number; + + min_length?: number; + + required?: boolean; + + /** + * Disappearing-message timer capability. + */ + settings?: DisappearingTimerCapability; +} + +/** + * Group creation capabilities for one group type. + */ +export interface GroupTypeCapabilities { + type_description: string; + + /** + * Group creation field capability. + */ + avatar?: GroupFieldCapability; + + /** + * Group creation field capability. + */ + disappear?: GroupFieldCapability; + + /** + * Group creation field capability. + */ + name?: GroupFieldCapability; + + /** + * Group creation field capability. + */ + parent?: GroupFieldCapability; + + /** + * Group creation field capability. + */ + participants?: GroupFieldCapability; + + /** + * Group creation field capability. + */ + topic?: GroupFieldCapability; + + /** + * Group creation field capability. + */ + username?: GroupFieldCapability; +} + +/** + * Connect or reconnect flow option for a bridge. + */ +export interface LoginFlow { + /** + * Flow ID to pass when creating a bridge login session. + */ + id: string; + + /** + * Short explanation for when to use this flow, when provided. + */ + description?: string; + + /** + * Display name for the flow, when provided. + */ + name?: string; +} + +export interface LoginInputField { + /** + * Field ID to send back in the fields object. + */ + id: string; + + /** + * Initial field value, when provided by the network. + */ + initialValue?: string; + + /** + * Field label to show to the user. + */ + label?: string; + + /** + * True if the user can leave this field empty. + */ + optional?: boolean; + + /** + * Placeholder text to show when the field is empty. + */ + placeholder?: string; + + /** + * Suggested input type, such as text, password, or email. + */ + type?: string; +} + +export interface LoginSession { + /** + * Bridge ID. + */ + bridgeID: string; + + /** + * Temporary bridge login session ID. + */ + loginSessionID: string; + + status: + | 'waiting_for_input' + | 'waiting_for_cookies' + | 'waiting_for_display' + | 'complete' + | 'cancelled' + | 'failed'; + + /** + * A chat account added to Beeper. + */ + account?: AccountsAPI.Account; + + /** + * Chat account ID for reconnect flows, when known. + */ + accountID?: string; + + /** + * Step the client should show or complete next. Omitted when the session is + * complete, cancelled, or failed. + */ + currentStep?: + | LoginSession.UserInput + | LoginSession.Cookies + | LoginSession.DisplayAndWait + | LoginSession.Complete; + + error?: Shared.APIError; + + /** + * Signed-in identity for a bridge. One bridge login can contain multiple chat + * accounts. + */ + login?: LoginSession.Login; + + /** + * Bridge login ID for reconnect flows, when known. + */ + loginID?: string; +} + +export namespace LoginSession { + export interface UserInput { + fields: Array; + + stepID: string; + + type: 'user_input'; + + attachments?: Array; + + /** + * User-facing instructions for this step. + */ + instructions?: string; + } + + export interface Cookies { + fields: Array; + + stepID: string; + + type: 'cookies'; + + /** + * URL to open for the user. + */ + url: string; + + /** + * Regular expression that identifies the final URL after sign-in. + */ + expectedFinalURLRegex?: string; + + /** + * Optional extraction script for browser-based sign-in helpers. Treat as an opaque + * helper value. + */ + extractJS?: string; + + /** + * User-facing instructions for this browser step. + */ + instructions?: string; + + /** + * Suggested user agent for the browser session. + */ + userAgent?: string; + } + + export interface DisplayAndWait { + display: DisplayAndWait.QrCode | DisplayAndWait.Emoji | DisplayAndWait.Empty; + + stepID: string; + + type: 'display_and_wait'; + + /** + * User-facing instructions for this step. + */ + instructions?: string; + } + + export namespace DisplayAndWait { + export interface QrCode { + data: string; + + type: 'qr'; + } + + export interface Emoji { + imageURL: string; + + type: 'emoji'; + } + + export interface Empty { + type: 'nothing'; + } + } + + export interface Complete { + type: 'complete'; + + /** + * A chat account added to Beeper. + */ + account?: AccountsAPI.Account; + + /** + * Completion instructions, when provided. + */ + instructions?: string; + + /** + * Signed-in identity for a bridge. One bridge login can contain multiple chat + * accounts. + */ + login?: Complete.Login; + + stepID?: string; + } + + export namespace Complete { + /** + * Signed-in identity for a bridge. One bridge login can contain multiple chat + * accounts. + */ + export interface Login { + /** + * Bridge ID. + */ + bridgeID: string; + + /** + * Bridge login ID. + */ + loginID: string; + + removeScopes: Array<'current-device' | 'all-devices'>; + + status: 'connected' | 'connecting' | 'needs_login' | 'logged_out' | 'unknown'; + + /** + * Chat accounts that belong to this bridge login, when known. + */ + accountIDs?: Array; + + /** + * Human-friendly bridge login status text. + */ + statusText?: string; + + /** + * User the account belongs to. + */ + user?: Shared.User; + } + } + + /** + * Signed-in identity for a bridge. One bridge login can contain multiple chat + * accounts. + */ + export interface Login { + /** + * Bridge ID. + */ + bridgeID: string; + + /** + * Bridge login ID. + */ + loginID: string; + + removeScopes: Array<'current-device' | 'all-devices'>; + + status: 'connected' | 'connecting' | 'needs_login' | 'logged_out' | 'unknown'; + + /** + * Chat accounts that belong to this bridge login, when known. + */ + accountIDs?: Array; + + /** + * Human-friendly bridge login status text. + */ + statusText?: string; + + /** + * User the account belongs to. + */ + user?: Shared.User; + } +} + +/** + * Advanced network capabilities for account lookup and group creation. + */ +export interface ProvisioningCapabilities { + group_creation: { [key: string]: GroupTypeCapabilities }; + + /** + * Identifier lookup capabilities for this bridge. + */ + resolve_identifier: ResolveIdentifierCapabilities; + + image_pack_import?: boolean; +} + +/** + * Identifier lookup capabilities for this bridge. + */ +export interface ResolveIdentifierCapabilities { + any_phone: boolean; + + contact_list: boolean; + + create_dm: boolean; + + lookup_email: boolean; + + lookup_phone: boolean; + + lookup_username: boolean; + + search: boolean; +} + +/** + * Available bridge that can connect or reconnect chat accounts. + */ +export interface BridgeRetrieveResponse { + /** + * Bridge ID. Use with bridge endpoints. + */ + id: string; + + /** + * Connected accounts for this bridge. Uses the same Account schema as GET + * /v1/accounts. + */ + accounts: Array; + + /** + * Number of active accounts for this network on this device. + */ + activeAccountCount: number; + + /** + * Human-friendly bridge name shown in Beeper. + */ + displayName: string; + + /** + * Where accounts for this bridge run: on this device or in Beeper Cloud. + */ + provider: 'cloud' | 'self-hosted' | 'local' | 'platform-sdk'; + + /** + * Whether this bridge can currently be used to connect new accounts. + */ + status: 'available' | 'connected' | 'limit_reached' | 'temporarily_unavailable' | 'disabled'; + + /** + * Whether this bridge can have multiple active accounts for the same network. + */ + supportsMultipleAccounts: boolean; + + /** + * Underlying bridge type, such as matrix, discordgo, slackgo, whatsapp, telegram, + * or twitter. + */ + type: string; + + /** + * Network grouping used for account counts and limits. + */ + network?: string; + + /** + * Human-friendly status text matching Beeper account management language. + */ + statusText?: string; +} + +/** + * Available bridges and their connected accounts. + */ +export interface BridgeListResponse { + items: Array; +} + +Bridges.LoginFlows = LoginFlows; +Bridges.BaseLoginFlows = BaseLoginFlows; +Bridges.Connections = Connections; +Bridges.BaseConnections = BaseConnections; +Bridges.LoginSessions = LoginSessions; +Bridges.BaseLoginSessions = BaseLoginSessions; + +export declare namespace Bridges { + export { + type Bridge as Bridge, + type CookieField as CookieField, + type DisappearingTimerCapability as DisappearingTimerCapability, + type GroupFieldCapability as GroupFieldCapability, + type GroupTypeCapabilities as GroupTypeCapabilities, + type LoginFlow as LoginFlow, + type LoginInputField as LoginInputField, + type LoginSession as LoginSession, + type ProvisioningCapabilities as ProvisioningCapabilities, + type ResolveIdentifierCapabilities as ResolveIdentifierCapabilities, + type BridgeRetrieveResponse as BridgeRetrieveResponse, + type BridgeListResponse as BridgeListResponse, + }; + + export { + LoginFlows as LoginFlows, + BaseLoginFlows as BaseLoginFlows, + type LoginFlowListResponse as LoginFlowListResponse, + }; + + export { Connections as Connections, BaseConnections as BaseConnections }; + + export { + LoginSessions as LoginSessions, + BaseLoginSessions as BaseLoginSessions, + type LoginSessionCancelResponse as LoginSessionCancelResponse, + type LoginSessionCreateParams as LoginSessionCreateParams, + type LoginSessionRetrieveParams as LoginSessionRetrieveParams, + type LoginSessionCancelParams as LoginSessionCancelParams, + }; +} diff --git a/src/resources/bridges/connections.ts b/src/resources/bridges/connections.ts new file mode 100644 index 0000000..cee8241 --- /dev/null +++ b/src/resources/bridges/connections.ts @@ -0,0 +1,11 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../core/resource'; + +export class BaseConnections extends APIResource { + static override readonly _key: readonly ['bridges', 'connections'] = Object.freeze([ + 'bridges', + 'connections', + ] as const); +} +export class Connections extends BaseConnections {} diff --git a/src/resources/bridges/index.ts b/src/resources/bridges/index.ts new file mode 100644 index 0000000..1ecd230 --- /dev/null +++ b/src/resources/bridges/index.ts @@ -0,0 +1,28 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { + Bridges, + BaseBridges, + type Bridge, + type CookieField, + type DisappearingTimerCapability, + type GroupFieldCapability, + type GroupTypeCapabilities, + type LoginFlow, + type LoginInputField, + type LoginSession, + type ProvisioningCapabilities, + type ResolveIdentifierCapabilities, + type BridgeRetrieveResponse, + type BridgeListResponse, +} from './bridges'; +export { Connections, BaseConnections } from './connections'; +export { LoginFlows, BaseLoginFlows, type LoginFlowListResponse } from './login-flows'; +export { + LoginSessions, + BaseLoginSessions, + type LoginSessionCancelResponse, + type LoginSessionCreateParams, + type LoginSessionRetrieveParams, + type LoginSessionCancelParams, +} from './login-sessions/index'; diff --git a/src/resources/bridges/login-flows.ts b/src/resources/bridges/login-flows.ts new file mode 100644 index 0000000..aeb4c96 --- /dev/null +++ b/src/resources/bridges/login-flows.ts @@ -0,0 +1,37 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../core/resource'; +import * as BridgesAPI from './bridges'; +import { APIPromise } from '../../core/api-promise'; +import { RequestOptions } from '../../internal/request-options'; +import { path } from '../../internal/utils/path'; + +/** + * Available bridges, bridge logins, login sessions for connect and reconnect flows, and advanced network capabilities. + */ +export class BaseLoginFlows extends APIResource { + static override readonly _key: readonly ['bridges', 'loginFlows'] = Object.freeze([ + 'bridges', + 'loginFlows', + ] as const); + + /** + * List connect and reconnect flow options for a bridge. Use a flowID when creating + * a bridge login session. + */ + list(bridgeID: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/v1/bridges/${bridgeID}/login-flows`, options); + } +} +/** + * Available bridges, bridge logins, login sessions for connect and reconnect flows, and advanced network capabilities. + */ +export class LoginFlows extends BaseLoginFlows {} + +export interface LoginFlowListResponse { + items: Array; +} + +export declare namespace LoginFlows { + export { type LoginFlowListResponse as LoginFlowListResponse }; +} diff --git a/src/resources/bridges/login-sessions.ts b/src/resources/bridges/login-sessions.ts new file mode 100644 index 0000000..91a3fd1 --- /dev/null +++ b/src/resources/bridges/login-sessions.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './login-sessions/index'; diff --git a/src/resources/bridges/login-sessions/index.ts b/src/resources/bridges/login-sessions/index.ts new file mode 100644 index 0000000..bddb004 --- /dev/null +++ b/src/resources/bridges/login-sessions/index.ts @@ -0,0 +1,11 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { + LoginSessions, + BaseLoginSessions, + type LoginSessionCancelResponse, + type LoginSessionCreateParams, + type LoginSessionRetrieveParams, + type LoginSessionCancelParams, +} from './login-sessions'; +export { Steps, BaseSteps, type StepSubmitParams } from './steps'; diff --git a/src/resources/bridges/login-sessions/login-sessions.ts b/src/resources/bridges/login-sessions/login-sessions.ts new file mode 100644 index 0000000..ecd5290 --- /dev/null +++ b/src/resources/bridges/login-sessions/login-sessions.ts @@ -0,0 +1,116 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../../core/resource'; +import * as BridgesAPI from '../bridges'; +import * as StepsAPI from './steps'; +import { BaseSteps, StepSubmitParams, Steps } from './steps'; +import { APIPromise } from '../../../core/api-promise'; +import { RequestOptions } from '../../../internal/request-options'; +import { path } from '../../../internal/utils/path'; + +/** + * Available bridges, bridge logins, login sessions for connect and reconnect flows, and advanced network capabilities. + */ +export class BaseLoginSessions extends APIResource { + static override readonly _key: readonly ['bridges', 'loginSessions'] = Object.freeze([ + 'bridges', + 'loginSessions', + ] as const); + + /** + * Start a temporary bridge login session to connect a new chat account or + * reconnect an existing bridge login. Omit loginID and accountID to connect a new + * account. + */ + create( + bridgeID: string, + body: LoginSessionCreateParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.post(path`/v1/bridges/${bridgeID}/login-sessions`, { body, ...options }); + } + + /** + * Get the current state of a temporary bridge login session. + */ + retrieve( + loginSessionID: string, + params: LoginSessionRetrieveParams, + options?: RequestOptions, + ): APIPromise { + const { bridgeID } = params; + return this._client.get(path`/v1/bridges/${bridgeID}/login-sessions/${loginSessionID}`, options); + } + + /** + * Cancel a temporary bridge login session. + */ + cancel( + loginSessionID: string, + params: LoginSessionCancelParams, + options?: RequestOptions, + ): APIPromise { + const { bridgeID } = params; + return this._client.delete(path`/v1/bridges/${bridgeID}/login-sessions/${loginSessionID}`, options); + } +} +/** + * Available bridges, bridge logins, login sessions for connect and reconnect flows, and advanced network capabilities. + */ +export class LoginSessions extends BaseLoginSessions { + steps: StepsAPI.Steps = new StepsAPI.Steps(this._client); +} + +export interface LoginSessionCancelResponse { + bridgeID: string; + + loginSessionID: string; + + status: 'cancelled'; +} + +export interface LoginSessionCreateParams { + /** + * Existing chat account ID to reconnect. Omit to connect a new account. + */ + accountID?: string; + + /** + * Optional flow ID returned by the list login flows endpoint. If omitted, Beeper + * chooses the default flow. + */ + flowID?: string; + + /** + * Existing bridge login ID to reconnect. Omit to connect a new account. + */ + loginID?: string; +} + +export interface LoginSessionRetrieveParams { + /** + * Bridge ID. + */ + bridgeID: string; +} + +export interface LoginSessionCancelParams { + /** + * Bridge ID. + */ + bridgeID: string; +} + +LoginSessions.Steps = Steps; +LoginSessions.BaseSteps = BaseSteps; + +export declare namespace LoginSessions { + export { + type LoginSessionCancelResponse as LoginSessionCancelResponse, + type LoginSessionCreateParams as LoginSessionCreateParams, + type LoginSessionRetrieveParams as LoginSessionRetrieveParams, + type LoginSessionCancelParams as LoginSessionCancelParams, + }; + + export { Steps as Steps, BaseSteps as BaseSteps, type StepSubmitParams as StepSubmitParams }; +} diff --git a/src/resources/bridges/login-sessions/steps.ts b/src/resources/bridges/login-sessions/steps.ts new file mode 100644 index 0000000..bfffab1 --- /dev/null +++ b/src/resources/bridges/login-sessions/steps.ts @@ -0,0 +1,74 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../../core/resource'; +import * as BridgesAPI from '../bridges'; +import { APIPromise } from '../../../core/api-promise'; +import { RequestOptions } from '../../../internal/request-options'; +import { path } from '../../../internal/utils/path'; + +/** + * Available bridges, bridge logins, login sessions for connect and reconnect flows, and advanced network capabilities. + */ +export class BaseSteps extends APIResource { + static override readonly _key: readonly ['bridges', 'loginSessions', 'steps'] = Object.freeze([ + 'bridges', + 'loginSessions', + 'steps', + ] as const); + + /** + * Submit input for the current step of a bridge login session. + */ + submit( + stepID: string, + params: StepSubmitParams, + options?: RequestOptions, + ): APIPromise { + const { bridgeID, loginSessionID, ...body } = params; + return this._client.post(path`/v1/bridges/${bridgeID}/login-sessions/${loginSessionID}/steps/${stepID}`, { + body, + ...options, + }); + } +} +/** + * Available bridges, bridge logins, login sessions for connect and reconnect flows, and advanced network capabilities. + */ +export class Steps extends BaseSteps {} + +export interface StepSubmitParams { + /** + * Path param: Bridge ID. + */ + bridgeID: string; + + /** + * Path param: Temporary bridge login session ID. + */ + loginSessionID: string; + + /** + * Body param + */ + type: 'user_input' | 'cookies' | 'display_and_wait'; + + /** + * Body param: Field values keyed by the field IDs from the current step. + */ + fields?: { [key: string]: string }; + + /** + * Body param: Last browser URL reached during a cookies step, if available. + */ + lastURL?: string; + + /** + * Body param: How the step was completed. Omit unless the client needs to + * distinguish an embedded webview or browser extension. + */ + source?: 'api' | 'webview' | 'browser_extension'; +} + +export declare namespace Steps { + export { type StepSubmitParams as StepSubmitParams }; +} diff --git a/src/resources/chats/chats.ts b/src/resources/chats/chats.ts index 03f7ade..851cd42 100644 --- a/src/resources/chats/chats.ts +++ b/src/resources/chats/chats.ts @@ -41,7 +41,7 @@ export class BaseChats extends APIResource { } /** - * Retrieve chat details including metadata, participants, and latest message + * Retrieve chat details, including metadata, participants, and the latest message. * * @example * ```ts @@ -59,7 +59,7 @@ export class BaseChats extends APIResource { } /** - * Update supported chat fields. Non-empty draft objects are accepted only when the + * Update supported chat fields. Non-empty drafts are accepted only when the * current draft is empty. Send draft=null to clear the draft before setting new * draft text or attachments. * @@ -98,8 +98,8 @@ export class BaseChats extends APIResource { } /** - * Archive or unarchive a chat. Set archived=true to move to archive, - * archived=false to move back to inbox + * Archive or unarchive a chat. Set archived=true to move it to Archive, or + * archived=false to move it back to the inbox. * * @example * ```ts @@ -157,8 +157,9 @@ export class BaseChats extends APIResource { } /** - * Force a delivery notification when supported by the underlying network. - * Currently intended for iMessage on macOS; unsupported networks return an error. + * Send a notification despite the recipient focus state when the network supports + * it. Currently intended for iMessage on macOS; unsupported networks return an + * error. * * @example * ```ts @@ -195,7 +196,7 @@ export class BaseChats extends APIResource { /** * Resolve a user/contact and open a direct chat. Reuses and returns an existing - * direct chat when one is found. Available in Beeper Desktop v4.2.808+. + * direct chat when one is found. Available in Beeper v4.2.808+. * * @example * ```ts @@ -318,7 +319,7 @@ export interface Chat { lastReadMessageSortKey?: string; /** - * Local chat ID specific to this Beeper Desktop installation. + * Local chat ID specific to this installation. */ localChatID?: string | null; @@ -375,7 +376,7 @@ export namespace Chat { isAdmin?: boolean; /** - * True if this participant represents a network or bridge bot. + * True if this participant represents an automated network account. */ isNetworkBot?: boolean; @@ -735,7 +736,7 @@ export namespace Chat { */ export interface Draft { /** - * Matrix HTML draft body. + * Rich-text draft body as returned by Beeper. */ text: string; @@ -838,13 +839,12 @@ export namespace Chat { export interface ChatCreateResponse extends Chat { /** - * @deprecated DEPRECATED - use id instead. Compatibility alias for older clients. + * @deprecated Use id instead. */ chatID: string; /** - * @deprecated DEPRECATED - legacy start-chat status for older clients. New clients - * should inspect the returned Chat instead. + * @deprecated Inspect the returned Chat instead. */ status?: 'existing' | 'created'; } @@ -861,13 +861,12 @@ export interface ChatListResponse extends Chat { export interface ChatStartResponse extends Chat { /** - * @deprecated DEPRECATED - use id instead. Compatibility alias for older clients. + * @deprecated Use id instead. */ chatID: string; /** - * @deprecated DEPRECATED - legacy start-chat status for older clients. New clients - * should inspect the returned Chat instead. + * @deprecated Inspect the returned Chat instead. */ status?: 'existing' | 'created'; } @@ -968,8 +967,8 @@ export namespace ChatUpdateParams { */ export interface Draft { /** - * Draft text. Plain text and Markdown are converted to Matrix HTML with the same - * rules used by send and edit. + * Draft text. Plain text and Markdown are converted to Beeper rich text with the + * same rules used by send and edit. */ text: string; @@ -1064,8 +1063,7 @@ export interface ChatNotifyAnywayParams {} export interface ChatSearchParams extends CursorSearchParams { /** - * Provide an array of account IDs to filter chats from specific messaging accounts - * only + * Limit results to specific chat accounts. */ accountIDs?: Array; @@ -1082,20 +1080,18 @@ export interface ChatSearchParams extends CursorSearchParams { includeMuted?: boolean | null; /** - * Provide an ISO datetime string to only retrieve chats with last activity after - * this time + * Only include chats with last activity after this ISO 8601 datetime. */ lastActivityAfter?: string; /** - * Provide an ISO datetime string to only retrieve chats with last activity before - * this time + * Only include chats with last activity before this ISO 8601 datetime. */ lastActivityBefore?: string; /** - * Literal token search (non-semantic). Use single words users type (e.g., - * "dinner"). When multiple words provided, ALL must match. Case-insensitive. + * Literal chat search. Use words the user typed, such as "dinner". When multiple + * words are provided, all must match. Case-insensitive. */ query?: string; @@ -1124,7 +1120,7 @@ export interface ChatStartParams { accountID: string; /** - * Merged user-like contact payload used to resolve the best identifier. + * Contact-like user payload used to resolve the best identifier. */ user: ChatStartParams.User; @@ -1141,7 +1137,7 @@ export interface ChatStartParams { export namespace ChatStartParams { /** - * Merged user-like contact payload used to resolve the best identifier. + * Contact-like user payload used to resolve the best identifier. */ export interface User { /** diff --git a/src/resources/chats/messages/reactions.ts b/src/resources/chats/messages/reactions.ts index ae24698..97d4b94 100644 --- a/src/resources/chats/messages/reactions.ts +++ b/src/resources/chats/messages/reactions.ts @@ -69,8 +69,8 @@ export class Reactions extends BaseReactions {} export interface ReactionDeleteResponse { /** - * Chat ID. Input routes also accept the local chat ID from this Beeper Desktop - * installation when available. + * Chat ID. Input routes also accept the local chat ID from this installation when + * available. */ chatID: string; @@ -93,8 +93,8 @@ export interface ReactionDeleteResponse { export interface ReactionAddResponse { /** - * Chat ID. Input routes also accept the local chat ID from this Beeper Desktop - * installation when available. + * Chat ID. Input routes also accept the local chat ID from this installation when + * available. */ chatID: string; @@ -122,8 +122,8 @@ export interface ReactionAddResponse { export interface ReactionDeleteParams { /** - * Chat ID. Input routes also accept the local chat ID from this Beeper Desktop - * installation when available. + * Chat ID. Input routes also accept the local chat ID from this installation when + * available. */ chatID: string; @@ -135,8 +135,8 @@ export interface ReactionDeleteParams { export interface ReactionAddParams { /** - * Path param: Chat ID. Input routes also accept the local chat ID from this Beeper - * Desktop installation when available. + * Path param: Chat ID. Input routes also accept the local chat ID from this + * installation when available. */ chatID: string; diff --git a/src/resources/chats/reminders.ts b/src/resources/chats/reminders.ts index ae959be..904a6ec 100644 --- a/src/resources/chats/reminders.ts +++ b/src/resources/chats/reminders.ts @@ -16,7 +16,7 @@ export class BaseReminders extends APIResource { ] as const); /** - * Set a reminder for a chat at a specific time + * Set a reminder for a chat at a specific time. * * @example * ```ts @@ -35,7 +35,7 @@ export class BaseReminders extends APIResource { } /** - * Clear an existing reminder from a chat + * Clear an existing reminder from a chat. * * @example * ```ts diff --git a/src/resources/index.ts b/src/resources/index.ts index 7e82418..0aadd8d 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -1,7 +1,15 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. export * from './shared'; -export { Accounts, BaseAccounts, type Account, type AccountListResponse } from './accounts/accounts'; +export { + Accounts, + BaseAccounts, + type Account, + type AccountBridge, + type AccountRetrieveResponse, + type AccountListResponse, +} from './accounts/accounts'; +export { App, BaseApp, type Verification, type AppSessionResponse } from './app/app'; export { Assets, BaseAssets, @@ -13,6 +21,22 @@ export { type AssetUploadParams, type AssetUploadBase64Params, } from './assets'; +export { + Bridges, + BaseBridges, + type Bridge, + type CookieField, + type DisappearingTimerCapability, + type GroupFieldCapability, + type GroupTypeCapabilities, + type LoginFlow, + type LoginInputField, + type LoginSession, + type ProvisioningCapabilities, + type ResolveIdentifierCapabilities, + type BridgeRetrieveResponse, + type BridgeListResponse, +} from './bridges/bridges'; export { Chats, BaseChats, diff --git a/src/resources/info.ts b/src/resources/info.ts index f405a62..263e7fe 100644 --- a/src/resources/info.ts +++ b/src/resources/info.ts @@ -12,7 +12,7 @@ export class BaseInfo extends APIResource { /** * Returns app, platform, server, endpoint discovery, OAuth, and WebSocket metadata - * for this Beeper Desktop instance. + * for this Beeper Client API server. */ retrieve(options?: RequestOptions): APIPromise { return this._client.get('/v1/info', { ...options, __security: {} }); @@ -123,7 +123,7 @@ export namespace InfoRetrieveResponse { export interface Server { /** - * Base URL of the Beeper Desktop API server + * Base URL of the Beeper Client API server */ base_url: string; diff --git a/src/resources/messages.ts b/src/resources/messages.ts index 607df98..3e034b4 100644 --- a/src/resources/messages.ts +++ b/src/resources/messages.ts @@ -23,7 +23,7 @@ export class BaseMessages extends APIResource { /** * Retrieve a message by final message ID, pendingMessageID, or Matrix event ID. - * Chat ID may be a Beeper chat ID or local chat ID. + * chatID may be a Beeper chat ID or a local chat ID. * * @example * ```ts @@ -153,21 +153,20 @@ export class Messages extends BaseMessages {} export interface MessageUpdateResponse extends Shared.Message { /** - * @deprecated DEPRECATED - use id instead. Compatibility alias for older clients. + * @deprecated Use id instead. */ messageID: string; /** - * @deprecated DEPRECATED - compatibility field. Successful responses are already - * represented by the 200 status code. + * @deprecated Use the HTTP 200 response status instead. */ success: true; } export interface MessageSendResponse { /** - * Chat ID. Input routes also accept the local chat ID from this Beeper Desktop - * installation when available. + * Chat ID. Input routes also accept the local chat ID from this installation when + * available. */ chatID: string; @@ -181,16 +180,16 @@ export interface MessageSendResponse { export interface MessageRetrieveParams { /** - * Chat ID. Input routes also accept the local chat ID from this Beeper Desktop - * installation when available. + * Chat ID. Input routes also accept the local chat ID from this installation when + * available. */ chatID: string; } export interface MessageUpdateParams { /** - * Path param: Chat ID. Input routes also accept the local chat ID from this Beeper - * Desktop installation when available. + * Path param: Chat ID. Input routes also accept the local chat ID from this + * installation when available. */ chatID: string; @@ -204,8 +203,8 @@ export interface MessageListParams extends CursorNoLimitParams {} export interface MessageDeleteParams { /** - * Path param: Chat ID. Input routes also accept the local chat ID from this Beeper - * Desktop installation when available. + * Path param: Chat ID. Input routes also accept the local chat ID from this + * installation when available. */ chatID: string; @@ -263,10 +262,10 @@ export interface MessageSearchParams extends CursorSearchParams { mediaTypes?: Array<'any' | 'video' | 'image' | 'link' | 'file'>; /** - * Literal word search (non-semantic). Finds messages containing these EXACT words - * in any order. Use single words users actually type, not concepts or phrases. - * Example: use "dinner" not "dinner plans", use "sick" not "health issues". If - * omitted, returns results filtered only by other parameters. + * Literal word search. Finds messages containing these words in any order. Use + * words the user actually typed, not inferred concepts. Example: use "dinner" + * rather than "dinner plans". If omitted, returns results filtered only by the + * other parameters. */ query?: string; @@ -289,8 +288,8 @@ export interface MessageSendParams { replyToMessageID?: string; /** - * Draft text. Plain text and Markdown are converted to Matrix HTML with the same - * rules used by send and edit. + * Draft text. Plain text and Markdown are converted to Beeper rich text with the + * same rules used by send and edit. */ text?: string; } diff --git a/src/resources/shared.ts b/src/resources/shared.ts index 63fda68..e431675 100644 --- a/src/resources/shared.ts +++ b/src/resources/shared.ts @@ -2,6 +2,265 @@ import { CursorNoLimit, CursorSearch } from '../core/pagination'; +export interface APIError { + code: string; + + message: string; + + details?: { [key: string]: unknown }; +} + +export interface AppStateSnapshot { + /** + * Encrypted messaging setup status. + */ + e2ee: AppStateSnapshot.E2EE; + + /** + * Current sign-in and encrypted messaging setup state for Beeper Desktop or Beeper + * Server. + */ + state: + | 'needs-login' + | 'initializing' + | 'needs-cross-signing-setup' + | 'needs-verification' + | 'needs-secrets' + | 'needs-first-sync' + | 'ready'; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + matrix?: AppStateSnapshot.Matrix; + + /** + * Trusted device verification progress. + */ + verification?: AppStateSnapshot.Verification; +} + +export namespace AppStateSnapshot { + /** + * Encrypted messaging setup status. + */ + export interface E2EE { + /** + * Whether this account can verify trusted devices. + */ + crossSigning: boolean; + + /** + * Whether the first encrypted message sync is complete. + */ + firstSyncDone: boolean; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + hasBackedUpRecoveryKey: boolean; + + /** + * Whether encrypted messaging setup has started. + */ + initialized: boolean; + + /** + * Whether encrypted message backup is available. + */ + keyBackup: boolean; + + /** + * Encrypted messaging keys available on this device. + */ + secrets: E2EE.Secrets; + + /** + * Whether secure key storage is available. + */ + secretStorage: boolean; + + /** + * Whether this device is trusted for encrypted messages. + */ + verified: boolean; + + /** + * Unix timestamp for when the recovery key was created. + */ + recoveryKeyGeneratedAt?: number; + } + + export namespace E2EE { + /** + * Encrypted messaging keys available on this device. + */ + export interface Secrets { + /** + * Whether the account identity key is available. + */ + masterKey: boolean; + + /** + * Whether the encrypted message backup key is available. + */ + megolmBackupKey: boolean; + + /** + * Whether a recovery key is available. + */ + recoveryKey: boolean; + + /** + * Whether the device trust key is available. + */ + selfSigningKey: boolean; + + /** + * Whether the user trust key is available. + */ + userSigningKey: boolean; + } + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + export interface Matrix { + /** + * Current device ID. + */ + deviceID: string; + + /** + * Beeper homeserver URL for this account. + */ + homeserver: string; + + /** + * Signed-in Beeper user ID. + */ + userID: string; + } + + /** + * Trusted device verification progress. + */ + export interface Verification { + /** + * Verification ID to pass in verification action paths. + */ + id: string; + + /** + * Verification actions that are valid for the current state. + */ + availableActions: Array<'accept' | 'cancel' | 'qr.confirmScanned' | 'sas.start' | 'sas.confirm'>; + + /** + * Whether this device started or received the verification. + */ + direction: 'incoming' | 'outgoing'; + + /** + * Verification methods supported for this transaction. + */ + methods: Array<'qr' | 'sas'>; + + /** + * Why this verification exists. + */ + purpose: 'login' | 'device'; + + /** + * Current trusted-device verification state. + */ + state: 'requested' | 'ready' | 'sas_ready' | 'qr_scanned' | 'done' | 'cancelled' | 'error'; + + /** + * Verification error details, if verification stopped. + */ + error?: Verification.Error; + + /** + * Other device participating in verification. + */ + otherDevice?: Verification.OtherDevice; + + /** + * Other Beeper user participating in verification. + */ + otherUserID?: string; + + /** + * QR verification data. + */ + qr?: Verification.Qr; + + /** + * Emoji or number comparison data for verification. + */ + sas?: Verification.SAS; + } + + export namespace Verification { + /** + * Verification error details, if verification stopped. + */ + export interface Error { + /** + * Verification error code. + */ + code: string; + + /** + * User-facing verification error message. + */ + reason: string; + } + + /** + * Other device participating in verification. + */ + export interface OtherDevice { + /** + * Other device ID. + */ + id: string; + + /** + * Other device display name, if known. + */ + name?: string; + } + + /** + * QR verification data. + */ + export interface Qr { + /** + * QR code payload to display for verification. + */ + data: string; + } + + /** + * Emoji or number comparison data for verification. + */ + export interface SAS { + /** + * Emoji sequence to compare on both devices. + */ + emojis: string; + + /** + * Number sequence to compare on both devices. + */ + decimals?: string; + } + } +} + export interface Attachment { /** * Attachment type. @@ -9,7 +268,7 @@ export interface Attachment { type: 'unknown' | 'img' | 'video' | 'audio'; /** - * Attachment identifier (typically an mxc:// URL). Use the download file endpoint + * Attachment identifier, typically an mxc:// URL. Use the download file endpoint * to get a local file path. */ id?: string; @@ -51,7 +310,7 @@ export interface Attachment { /** * Preview image URL for video attachments (poster frame). May be temporary or - * local-only to this device; download promptly if durable access is needed. + * available only on this device; download promptly if durable access is needed. */ posterImg?: string; @@ -61,8 +320,8 @@ export interface Attachment { size?: Attachment.Size; /** - * Public URL or local file path to fetch the file. May be temporary or local-only - * to this device; download promptly if durable access is needed. + * Public URL or local file path to fetch the file. May be temporary or available + * only on this device; download promptly if durable access is needed. */ srcURL?: string; @@ -163,14 +422,14 @@ export interface Message { accountID: string; /** - * Chat ID. Input routes also accept the local chat ID from this Beeper Desktop - * installation when available. + * Chat ID. Input routes also accept the local chat ID from this installation when + * available. */ chatID: string; /** - * Matrix-style fully-qualified sender user ID, usually including a bridge prefix - * and homeserver. + * Fully qualified sender user ID. Network-backed IDs usually include the network + * prefix and homeserver. */ senderID: string; @@ -241,7 +500,7 @@ export interface Message { seen?: boolean | string | { [key: string]: boolean | string }; /** - * Resolved sender display name (impersonator/full name/username/participant name). + * Resolved sender display name. */ senderName?: string; @@ -251,7 +510,7 @@ export interface Message { sendStatus?: Message.SendStatus; /** - * Matrix HTML body if present. + * Rich-text message body if present. */ text?: string; @@ -288,14 +547,14 @@ export namespace Message { url: string; /** - * Favicon URL if available. May be temporary or local-only to this device; + * Favicon URL if available. May be temporary or available only on this device; * download promptly if durable access is needed. */ favicon?: string; /** - * Preview image URL if available. May be temporary or local-only to this device; - * download promptly if durable access is needed. + * Preview image URL if available. May be temporary or available only on this + * device; download promptly if durable access is needed. */ img?: string; @@ -346,7 +605,8 @@ export namespace Message { deliveredToUsers?: Array; /** - * Internal bridge error detail. Intended for diagnostics, not end-user display. + * Diagnostic error detail from the messaging network adapter. Do not show directly + * to users. */ internalError?: string; @@ -387,7 +647,7 @@ export interface Reaction { emoji?: boolean; /** - * URL to the reaction's image. May be temporary or local-only to this device; + * URL to the reaction's image. May be temporary or available only on this device; * download promptly if durable access is needed. */ imgURL?: string; @@ -419,9 +679,9 @@ export interface User { fullName?: string; /** - * Avatar image URL if available. This may be a remote URL, Matrix media URL, data - * URL, or local filesystem URL depending on source and endpoint. May be temporary - * or local-only to this device; download promptly if durable access is needed. + * Avatar image URL if available. This may be a remote URL, media URL, data URL, or + * local file URL depending on the source. May be temporary or available only on + * this device; download promptly if durable access is needed. */ imgURL?: string; diff --git a/src/resources/top-level.ts b/src/resources/top-level.ts index 0cd89f4..a95fffa 100644 --- a/src/resources/top-level.ts +++ b/src/resources/top-level.ts @@ -72,7 +72,7 @@ export interface FocusParams { chatID?: string; /** - * Optional image path to populate in the message input field. + * Optional local image path to populate in the message input field. */ draftAttachmentPath?: string; @@ -89,7 +89,7 @@ export interface FocusParams { export interface SearchParams { /** - * User-typed search text. Literal word matching (non-semantic). + * User-typed search text. Uses literal word matching. */ query: string; } diff --git a/src/version.ts b/src/version.ts index e156b0e..0d43855 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '5.0.0'; // x-release-please-version +export const VERSION = '5.1.0'; // x-release-please-version diff --git a/tests/api-resources/accounts/accounts.test.ts b/tests/api-resources/accounts/accounts.test.ts index aa78a86..d8a98ef 100644 --- a/tests/api-resources/accounts/accounts.test.ts +++ b/tests/api-resources/accounts/accounts.test.ts @@ -17,6 +17,17 @@ const partialClient = createClient({ }); const runTests = (client: PartialBeeperDesktop<{ accounts: BaseAccounts }>) => { + test('retrieve', async () => { + const responsePromise = client.accounts.retrieve('accountID'); + 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', async () => { const responsePromise = client.accounts.list(); const rawResponse = await responsePromise.asResponse(); diff --git a/tests/api-resources/app/app.test.ts b/tests/api-resources/app/app.test.ts new file mode 100644 index 0000000..d433c3b --- /dev/null +++ b/tests/api-resources/app/app.test.ts @@ -0,0 +1,32 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { BaseApp } from '@beeper/desktop-api/resources/app/app'; + +import BeeperDesktop from '@beeper/desktop-api'; +import { createClient, type PartialBeeperDesktop } from '@beeper/desktop-api/tree-shakable'; + +const client = new BeeperDesktop({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +const partialClient = createClient({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', + resources: [BaseApp], +}); + +const runTests = (client: PartialBeeperDesktop<{ app: BaseApp }>) => { + test('session', async () => { + const responsePromise = client.app.session(); + 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); + }); +}; +describe('resource app', () => runTests(client)); +describe('resource app (tree shakable, base)', () => runTests(partialClient)); diff --git a/tests/api-resources/app/login/login.test.ts b/tests/api-resources/app/login/login.test.ts new file mode 100644 index 0000000..5dfb7c7 --- /dev/null +++ b/tests/api-resources/app/login/login.test.ts @@ -0,0 +1,107 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { App } from '@beeper/desktop-api/resources/app/app'; +import { BaseLogin } from '@beeper/desktop-api/resources/app/login/login'; + +import BeeperDesktop from '@beeper/desktop-api'; +import { createClient, type PartialBeeperDesktop } from '@beeper/desktop-api/tree-shakable'; + +const client = new BeeperDesktop({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +const partialClient = createClient({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', + resources: [BaseLogin], +}); + +const parentPartialClient = createClient({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', + resources: [App], +}); + +const runTests = (client: PartialBeeperDesktop<{ app: { login: BaseLogin } }>) => { + test('email: only required params', async () => { + const responsePromise = client.app.login.email({ + email: 'dev@stainless.com', + setupRequestID: 'setupRequestID', + }); + 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('email: required and optional params', async () => { + const response = await client.app.login.email({ + email: 'dev@stainless.com', + setupRequestID: 'setupRequestID', + }); + }); + + test('register: only required params', async () => { + const responsePromise = client.app.login.register({ + acceptTerms: true, + leadToken: 'leadToken', + setupRequestID: 'setupRequestID', + username: 'x', + }); + 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('register: required and optional params', async () => { + const response = await client.app.login.register({ + acceptTerms: true, + leadToken: 'leadToken', + setupRequestID: 'setupRequestID', + username: 'x', + }); + }); + + test('response: only required params', async () => { + const responsePromise = client.app.login.response({ + response: 'response', + setupRequestID: 'setupRequestID', + }); + 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('response: required and optional params', async () => { + const response = await client.app.login.response({ + response: 'response', + setupRequestID: 'setupRequestID', + }); + }); + + test('start', async () => { + const responsePromise = client.app.login.start(); + 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); + }); +}; +describe('resource login', () => runTests(client)); +describe('resource login (tree shakable, base)', () => runTests(partialClient)); +describe('resource login (tree shakable, subresource)', () => runTests(parentPartialClient)); diff --git a/tests/api-resources/app/login/verification/recovery-key/recovery-key.test.ts b/tests/api-resources/app/login/verification/recovery-key/recovery-key.test.ts new file mode 100644 index 0000000..e54a055 --- /dev/null +++ b/tests/api-resources/app/login/verification/recovery-key/recovery-key.test.ts @@ -0,0 +1,46 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Verification } from '@beeper/desktop-api/resources/app/login/verification/verification'; +import { BaseRecoveryKey } from '@beeper/desktop-api/resources/app/login/verification/recovery-key/recovery-key'; + +import BeeperDesktop from '@beeper/desktop-api'; +import { createClient, type PartialBeeperDesktop } from '@beeper/desktop-api/tree-shakable'; + +const client = new BeeperDesktop({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +const partialClient = createClient({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', + resources: [BaseRecoveryKey], +}); + +const parentPartialClient = createClient({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', + resources: [Verification], +}); + +const runTests = ( + client: PartialBeeperDesktop<{ app: { login: { verification: { recoveryKey: BaseRecoveryKey } } } }>, +) => { + test('verify: only required params', async () => { + const responsePromise = client.app.login.verification.recoveryKey.verify({ recoveryKey: 'x' }); + 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('verify: required and optional params', async () => { + const response = await client.app.login.verification.recoveryKey.verify({ recoveryKey: 'x' }); + }); +}; +describe('resource recoveryKey', () => runTests(client)); +describe('resource recoveryKey (tree shakable, base)', () => runTests(partialClient)); +describe('resource recoveryKey (tree shakable, subresource)', () => runTests(parentPartialClient)); diff --git a/tests/api-resources/app/login/verification/recovery-key/reset.test.ts b/tests/api-resources/app/login/verification/recovery-key/reset.test.ts new file mode 100644 index 0000000..178d978 --- /dev/null +++ b/tests/api-resources/app/login/verification/recovery-key/reset.test.ts @@ -0,0 +1,67 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { RecoveryKey } from '@beeper/desktop-api/resources/app/login/verification/recovery-key/recovery-key'; +import { BaseReset } from '@beeper/desktop-api/resources/app/login/verification/recovery-key/reset'; + +import BeeperDesktop from '@beeper/desktop-api'; +import { createClient, type PartialBeeperDesktop } from '@beeper/desktop-api/tree-shakable'; + +const client = new BeeperDesktop({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +const partialClient = createClient({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', + resources: [BaseReset], +}); + +const parentPartialClient = createClient({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', + resources: [RecoveryKey], +}); + +const runTests = ( + client: PartialBeeperDesktop<{ app: { login: { verification: { recoveryKey: { reset: BaseReset } } } } }>, +) => { + test('create', async () => { + const responsePromise = client.app.login.verification.recoveryKey.reset.create(); + 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('create: 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.login.verification.recoveryKey.reset.create( + { existingRecoveryKey: 'existingRecoveryKey' }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(BeeperDesktop.NotFoundError); + }); + + test('confirm: only required params', async () => { + const responsePromise = client.app.login.verification.recoveryKey.reset.confirm({ recoveryKey: 'x' }); + 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('confirm: required and optional params', async () => { + const response = await client.app.login.verification.recoveryKey.reset.confirm({ recoveryKey: 'x' }); + }); +}; +describe('resource reset', () => runTests(client)); +describe('resource reset (tree shakable, base)', () => runTests(partialClient)); +describe('resource reset (tree shakable, subresource)', () => runTests(parentPartialClient)); diff --git a/tests/api-resources/app/verifications/qr.test.ts b/tests/api-resources/app/verifications/qr.test.ts new file mode 100644 index 0000000..fc09226 --- /dev/null +++ b/tests/api-resources/app/verifications/qr.test.ts @@ -0,0 +1,55 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { BaseQr } from '@beeper/desktop-api/resources/app/verifications/qr'; +import { Verifications } from '@beeper/desktop-api/resources/app/verifications/verifications'; + +import BeeperDesktop from '@beeper/desktop-api'; +import { createClient, type PartialBeeperDesktop } from '@beeper/desktop-api/tree-shakable'; + +const client = new BeeperDesktop({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +const partialClient = createClient({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', + resources: [BaseQr], +}); + +const parentPartialClient = createClient({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', + resources: [Verifications], +}); + +const runTests = (client: PartialBeeperDesktop<{ app: { verifications: { qr: BaseQr } } }>) => { + test('confirmScanned', async () => { + const responsePromise = client.app.verifications.qr.confirmScanned('x'); + 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('scan: only required params', async () => { + const responsePromise = client.app.verifications.qr.scan({ data: 'x' }); + 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('scan: required and optional params', async () => { + const response = await client.app.verifications.qr.scan({ data: 'x' }); + }); +}; +describe('resource qr', () => runTests(client)); +describe('resource qr (tree shakable, base)', () => runTests(partialClient)); +describe('resource qr (tree shakable, subresource)', () => runTests(parentPartialClient)); diff --git a/tests/api-resources/app/verifications/sas.test.ts b/tests/api-resources/app/verifications/sas.test.ts new file mode 100644 index 0000000..5564a78 --- /dev/null +++ b/tests/api-resources/app/verifications/sas.test.ts @@ -0,0 +1,51 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { BaseSAS } from '@beeper/desktop-api/resources/app/verifications/sas'; +import { Verifications } from '@beeper/desktop-api/resources/app/verifications/verifications'; + +import BeeperDesktop from '@beeper/desktop-api'; +import { createClient, type PartialBeeperDesktop } from '@beeper/desktop-api/tree-shakable'; + +const client = new BeeperDesktop({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +const partialClient = createClient({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', + resources: [BaseSAS], +}); + +const parentPartialClient = createClient({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', + resources: [Verifications], +}); + +const runTests = (client: PartialBeeperDesktop<{ app: { verifications: { sas: BaseSAS } } }>) => { + test('confirm', async () => { + const responsePromise = client.app.verifications.sas.confirm('x'); + 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('start', async () => { + const responsePromise = client.app.verifications.sas.start('x'); + 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); + }); +}; +describe('resource sas', () => runTests(client)); +describe('resource sas (tree shakable, base)', () => runTests(partialClient)); +describe('resource sas (tree shakable, subresource)', () => runTests(parentPartialClient)); diff --git a/tests/api-resources/app/verifications/verifications.test.ts b/tests/api-resources/app/verifications/verifications.test.ts new file mode 100644 index 0000000..076b9da --- /dev/null +++ b/tests/api-resources/app/verifications/verifications.test.ts @@ -0,0 +1,105 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { App } from '@beeper/desktop-api/resources/app/app'; +import { BaseVerifications } from '@beeper/desktop-api/resources/app/verifications/verifications'; + +import BeeperDesktop from '@beeper/desktop-api'; +import { createClient, type PartialBeeperDesktop } from '@beeper/desktop-api/tree-shakable'; + +const client = new BeeperDesktop({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +const partialClient = createClient({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', + resources: [BaseVerifications], +}); + +const parentPartialClient = createClient({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', + resources: [App], +}); + +const runTests = (client: PartialBeeperDesktop<{ app: { verifications: BaseVerifications } }>) => { + test('create', async () => { + const responsePromise = client.app.verifications.create(); + 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('create: 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.verifications.create( + { purpose: 'login', userID: 'userID' }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(BeeperDesktop.NotFoundError); + }); + + test('retrieve', async () => { + const responsePromise = client.app.verifications.retrieve('x'); + 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', async () => { + const responsePromise = client.app.verifications.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('accept', async () => { + const responsePromise = client.app.verifications.accept('x'); + 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('cancel', async () => { + const responsePromise = client.app.verifications.cancel('x'); + 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('cancel: 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.verifications.cancel( + 'x', + { code: 'code', reason: 'reason' }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(BeeperDesktop.NotFoundError); + }); +}; +describe('resource verifications', () => runTests(client)); +describe('resource verifications (tree shakable, base)', () => runTests(partialClient)); +describe('resource verifications (tree shakable, subresource)', () => runTests(parentPartialClient)); diff --git a/tests/api-resources/bridges/bridges.test.ts b/tests/api-resources/bridges/bridges.test.ts new file mode 100644 index 0000000..8fae5c3 --- /dev/null +++ b/tests/api-resources/bridges/bridges.test.ts @@ -0,0 +1,54 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { BaseBridges } from '@beeper/desktop-api/resources/bridges/bridges'; + +import BeeperDesktop from '@beeper/desktop-api'; +import { createClient, type PartialBeeperDesktop } from '@beeper/desktop-api/tree-shakable'; + +const client = new BeeperDesktop({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +const partialClient = createClient({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', + resources: [BaseBridges], +}); + +const runTests = (client: PartialBeeperDesktop<{ bridges: BaseBridges }>) => { + test('retrieve', async () => { + const responsePromise = client.bridges.retrieve('local-whatsapp'); + 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', async () => { + const responsePromise = client.bridges.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('retrieveCapabilities', async () => { + const responsePromise = client.bridges.retrieveCapabilities('local-whatsapp'); + 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); + }); +}; +describe('resource bridges', () => runTests(client)); +describe('resource bridges (tree shakable, base)', () => runTests(partialClient)); diff --git a/tests/api-resources/bridges/login-flows.test.ts b/tests/api-resources/bridges/login-flows.test.ts new file mode 100644 index 0000000..50d9280 --- /dev/null +++ b/tests/api-resources/bridges/login-flows.test.ts @@ -0,0 +1,40 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Bridges } from '@beeper/desktop-api/resources/bridges/bridges'; +import { BaseLoginFlows } from '@beeper/desktop-api/resources/bridges/login-flows'; + +import BeeperDesktop from '@beeper/desktop-api'; +import { createClient, type PartialBeeperDesktop } from '@beeper/desktop-api/tree-shakable'; + +const client = new BeeperDesktop({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +const partialClient = createClient({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', + resources: [BaseLoginFlows], +}); + +const parentPartialClient = createClient({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', + resources: [Bridges], +}); + +const runTests = (client: PartialBeeperDesktop<{ bridges: { loginFlows: BaseLoginFlows } }>) => { + test('list', async () => { + const responsePromise = client.bridges.loginFlows.list('local-whatsapp'); + 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); + }); +}; +describe('resource loginFlows', () => runTests(client)); +describe('resource loginFlows (tree shakable, base)', () => runTests(partialClient)); +describe('resource loginFlows (tree shakable, subresource)', () => runTests(parentPartialClient)); diff --git a/tests/api-resources/bridges/login-sessions/login-sessions.test.ts b/tests/api-resources/bridges/login-sessions/login-sessions.test.ts new file mode 100644 index 0000000..28d5de2 --- /dev/null +++ b/tests/api-resources/bridges/login-sessions/login-sessions.test.ts @@ -0,0 +1,85 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Bridges } from '@beeper/desktop-api/resources/bridges/bridges'; +import { BaseLoginSessions } from '@beeper/desktop-api/resources/bridges/login-sessions/login-sessions'; + +import BeeperDesktop from '@beeper/desktop-api'; +import { createClient, type PartialBeeperDesktop } from '@beeper/desktop-api/tree-shakable'; + +const client = new BeeperDesktop({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +const partialClient = createClient({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', + resources: [BaseLoginSessions], +}); + +const parentPartialClient = createClient({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', + resources: [Bridges], +}); + +const runTests = (client: PartialBeeperDesktop<{ bridges: { loginSessions: BaseLoginSessions } }>) => { + test('create', async () => { + const responsePromise = client.bridges.loginSessions.create('local-whatsapp'); + 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('create: 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.bridges.loginSessions.create( + 'local-whatsapp', + { + accountID: 'x', + flowID: 'x', + loginID: 'x', + }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(BeeperDesktop.NotFoundError); + }); + + test('retrieve: only required params', async () => { + const responsePromise = client.bridges.loginSessions.retrieve('123', { bridgeID: 'local-whatsapp' }); + 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('retrieve: required and optional params', async () => { + const response = await client.bridges.loginSessions.retrieve('123', { bridgeID: 'local-whatsapp' }); + }); + + test('cancel: only required params', async () => { + const responsePromise = client.bridges.loginSessions.cancel('123', { bridgeID: 'local-whatsapp' }); + 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('cancel: required and optional params', async () => { + const response = await client.bridges.loginSessions.cancel('123', { bridgeID: 'local-whatsapp' }); + }); +}; +describe('resource loginSessions', () => runTests(client)); +describe('resource loginSessions (tree shakable, base)', () => runTests(partialClient)); +describe('resource loginSessions (tree shakable, subresource)', () => runTests(parentPartialClient)); diff --git a/tests/api-resources/bridges/login-sessions/steps.test.ts b/tests/api-resources/bridges/login-sessions/steps.test.ts new file mode 100644 index 0000000..8d742ef --- /dev/null +++ b/tests/api-resources/bridges/login-sessions/steps.test.ts @@ -0,0 +1,55 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { LoginSessions } from '@beeper/desktop-api/resources/bridges/login-sessions/login-sessions'; +import { BaseSteps } from '@beeper/desktop-api/resources/bridges/login-sessions/steps'; + +import BeeperDesktop from '@beeper/desktop-api'; +import { createClient, type PartialBeeperDesktop } from '@beeper/desktop-api/tree-shakable'; + +const client = new BeeperDesktop({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +const partialClient = createClient({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', + resources: [BaseSteps], +}); + +const parentPartialClient = createClient({ + accessToken: 'My Access Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', + resources: [LoginSessions], +}); + +const runTests = (client: PartialBeeperDesktop<{ bridges: { loginSessions: { steps: BaseSteps } } }>) => { + test('submit: only required params', async () => { + const responsePromise = client.bridges.loginSessions.steps.submit('x', { + bridgeID: 'local-whatsapp', + loginSessionID: '123', + type: 'user_input', + }); + 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('submit: required and optional params', async () => { + const response = await client.bridges.loginSessions.steps.submit('x', { + bridgeID: 'local-whatsapp', + loginSessionID: '123', + type: 'user_input', + fields: { foo: 'string' }, + lastURL: 'lastURL', + source: 'api', + }); + }); +}; +describe('resource steps', () => runTests(client)); +describe('resource steps (tree shakable, base)', () => runTests(partialClient)); +describe('resource steps (tree shakable, subresource)', () => runTests(parentPartialClient)); diff --git a/tests/uploads.test.ts b/tests/uploads.test.ts index e13ed28..3cbef94 100644 --- a/tests/uploads.test.ts +++ b/tests/uploads.test.ts @@ -1,7 +1,6 @@ import fs from 'fs'; import type { ResponseLike } from '@beeper/desktop-api/internal/to-file'; import { toFile } from '@beeper/desktop-api/core/uploads'; -import { File } from 'node:buffer'; class MyClass { name: string = 'foo'; diff --git a/yarn.lock b/yarn.lock index 18e7cbd..00842e3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3192,9 +3192,9 @@ ts-node@^10.5.0: v8-compile-cache-lib "^3.0.0" yn "3.1.1" -"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz": - version "1.1.9" - resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz#777f6f5d9e26bf0e94e5170990dd3a841d6707cd" +"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz": + version "1.1.11" + resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz#010247051be13b55abdc98f787c017285149f4f2" dependencies: debug "^4.3.7" fast-glob "^3.3.2"