@tightknitai/tightknit 0.1.0-alpha.7 → 0.1.0-alpha.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,94 +1,57 @@
1
1
  # @tightknitai/tightknit
2
2
 
3
- Command-line interface and MCP server for the [Tightknit API](https://docs.tightknit.ai/api-reference/introduction).
4
-
5
- ## Setup
6
-
7
- ### Prerequisites
8
-
9
- - Node.js 18+ (for native `fetch`)
10
- - A Tightknit API key
11
-
12
- ### Create an API Key
13
-
14
- 1. Go to **Studio > Settings > Integrations > API Keys**
15
- 2. Click **Create API key**
16
- 3. Give it a descriptive name (e.g. "CLI")
17
- 4. Select the permissions for the APIs the key needs access to. Enable all permissions the CLI commands you plan to use require:
18
- - **Calendar Events** — `events list`, `events get`, `events create`, `events delete`, `events update-attendee`
19
- - **Feeds** — `feeds list`, `feeds get`, `feeds posts`
20
- - **Posts** — `posts get`
21
- - **Members** — `members add` (Enterprise), `members check`
22
- - **Messages** — `messages send`
23
- - **Groups** — `groups add-member`
24
- - **Awards** — `awards assign`
25
- - **Search** — `search query` (Beta)
26
- 5. Copy the key (starts with `sk_`) — it is only shown once
27
-
28
- ### Install and Configure
29
-
30
- ```bash
31
- # Via npm
32
- npx -p @tightknitai/tightknit@alpha tightknit config set api-key sk_your_key_here
3
+ > **Alpha** — APIs and commands may change between releases.
33
4
 
34
- # Or from the monorepo root
35
- pnpm install
36
- npx tsx packages/tightknit-cli/bin/tightknit.ts config set api-key sk_your_key_here
37
- ```
38
-
39
- The API key is stored locally at `~/.config/tightknit/config.json`. Alternatively, set the `TIGHTKNIT_API_KEY` environment variable (takes precedence over stored config).
5
+ Command-line interface and MCP server for the [Tightknit API](https://docs.tightknit.ai/api-reference/introduction).
40
6
 
41
- ## Usage
7
+ **Full documentation:** [docs.tightknit.ai/integrations/cli](https://docs.tightknit.ai/integrations/cli)
42
8
 
43
- ### CLI Commands
9
+ ## Quick Start
44
10
 
45
11
  ```bash
46
- # Alias for convenience
47
- alias tightknit="npx tsx packages/tightknit-cli/bin/tightknit.ts"
12
+ # Install globally
13
+ npm install -g @tightknitai/tightknit@alpha
48
14
 
49
- # Calendar Events
50
- tightknit events list
51
- tightknit events list --time-filter upcoming --status published --json
52
- tightknit events get <event-id>
53
- tightknit events create --title "Meetup" --description "Join us" --start-date "2025-06-01T18:00:00Z" --end-date "2025-06-01T20:00:00Z"
54
- tightknit events delete <event-id>
55
- tightknit events update-attendee <event-id> --email user@example.com --personal-join-link "https://zoom.us/..."
15
+ # Or run without installing
16
+ npx @tightknitai/tightknit@alpha --help
56
17
 
57
- # Awards
58
- tightknit awards assign <award-uuid> --recipient-email user@example.com
18
+ # Set your API key
19
+ tightknit config set api-key sk_your_key_here
59
20
 
60
- # Feeds & Posts
21
+ # Try it out
61
22
  tightknit feeds list
62
- tightknit feeds get <feed-id>
63
- tightknit feeds posts <feed-id> --sort newest
64
- tightknit posts get <post-id>
23
+ tightknit events list --time-filter upcoming --json
24
+ ```
65
25
 
66
- # Members
67
- tightknit members add --email user@example.com --full-name "Jane Doe"
68
- tightknit members check user@example.com
26
+ ## Authentication
69
27
 
70
- # Messages
71
- tightknit messages send --channel C0123456 --text "Hello from CLI!"
28
+ The CLI resolves your API key in this order:
72
29
 
73
- # Groups
74
- tightknit groups add-member <group-id> --email user@example.com
30
+ 1. `--api-key <key>` flag (highest precedence)
31
+ 2. `TIGHTKNIT_API_KEY` environment variable
32
+ 3. Stored config (`~/.config/tightknit/config.json`)
75
33
 
76
- # Search (Beta)
77
- tightknit search query "community meetup" --type post
34
+ ## Commands
78
35
 
79
- # Config
80
- tightknit config set api-key <key>
81
- tightknit config get api-key
82
- tightknit config set default-output json
83
- ```
36
+ | Command Group | Commands |
37
+ |---------------|----------|
38
+ | `events` | `list`, `get`, `create`, `delete`, `update-attendee` |
39
+ | `feeds` | `list`, `get`, `posts` |
40
+ | `posts` | `get` |
41
+ | `members` | `add`, `check` |
42
+ | `messages` | `send` |
43
+ | `groups` | `add-member` |
44
+ | `awards` | `assign` |
45
+ | `search` | `query` (Beta) |
46
+ | `config` | `set`, `get` |
47
+ | `completion` | `bash`, `zsh`, `fish` |
48
+ | `mcp` | Start the MCP server |
84
49
 
85
- Every command supports `--json` for structured JSON output and `--help` for usage info.
50
+ Every command supports `--json` for structured output and `--help` for usage details.
86
51
 
87
- ### MCP Server (for Claude Code)
52
+ ## MCP Server
88
53
 
89
- The MCP server exposes all CLI commands as tools over STDIO.
90
-
91
- Add to your Claude Code MCP config (`.claude/settings.json` or `~/.claude.json`):
54
+ The built-in MCP server exposes all CLI commands as tools for AI agents.
92
55
 
93
56
  ```json
94
57
  {
@@ -104,31 +67,6 @@ Add to your Claude Code MCP config (`.claude/settings.json` or `~/.claude.json`)
104
67
  }
105
68
  ```
106
69
 
107
- Or if installed locally in the monorepo:
108
-
109
- ```json
110
- {
111
- "mcpServers": {
112
- "tightknit": {
113
- "command": "npx",
114
- "args": ["tsx", "packages/tightknit-cli/bin/tightknit.ts", "mcp"],
115
- "cwd": "/path/to/colombo",
116
- "env": {
117
- "TIGHTKNIT_API_KEY": "sk_your_key_here"
118
- }
119
- }
120
- }
121
- }
122
- ```
123
-
124
- This gives Claude access to 17 tools: `tightknit_events_list`, `tightknit_events_create`, `tightknit_feeds_list`, `tightknit_messages_send`, etc.
125
-
126
- **Authentication:** The API key can be provided two ways:
127
- - **`TIGHTKNIT_API_KEY` env var** (recommended for MCP) — pass it in the MCP config as shown above
128
- - **`tightknit config set api-key <key>`** — persists to `~/.config/tightknit/config.json`, good for CLI usage
129
-
130
- The env var takes precedence if both are set.
131
-
132
70
  ## Development
133
71
 
134
72
  ```bash
@@ -138,30 +76,16 @@ pnpm --filter @tightknitai/tightknit test
138
76
  # Type check
139
77
  pnpm --filter @tightknitai/tightknit typecheck
140
78
 
141
- # Run CLI in dev mode
142
- npx tsx packages/tightknit-cli/bin/tightknit.ts --help
79
+ # Build
80
+ pnpm --filter @tightknitai/tightknit build
81
+
82
+ # Run in dev mode (uses tsx, no build needed)
83
+ pnpm --filter @tightknitai/tightknit dev
84
+
85
+ # Test MCP server with Inspector
86
+ pnpm --filter @tightknitai/tightknit test:mcp
143
87
  ```
144
88
 
145
- ## API Coverage
146
-
147
- All endpoints from the [Tightknit Admin API](https://api.tightknit.ai/doc) (`/admin/v0/`) are supported:
148
-
149
- | Method | Path | CLI Command |
150
- |--------|------|-------------|
151
- | GET | `/calendar_events` | `events list` |
152
- | POST | `/calendar_events` | `events create` |
153
- | GET | `/calendar_events/:id` | `events get` |
154
- | DELETE | `/calendar_events/:id` | `events delete` |
155
- | PATCH | `/calendar_events/:id/attendees` | `events update-attendee` |
156
- | POST | `/awards/:id/assign` | `awards assign` |
157
- | GET | `/feeds` | `feeds list` |
158
- | GET | `/feeds/:id` | `feeds get` |
159
- | GET | `/feeds/:id/posts` | `feeds posts` |
160
- | GET | `/posts/:id` | `posts get` |
161
- | POST | `/members` | `members add` |
162
- | POST | `/members/check` | `members check` |
163
- | POST | `/messages` | `messages send` |
164
- | POST | `/groups/:id/members` | `groups add-member` |
165
- | GET | `/search` | `search query` |
166
-
167
- Not yet implemented: `POST /files` (file upload — requires multipart form handling).
89
+ ## License
90
+
91
+ Apache-2.0
package/bin/tightknit.js CHANGED
@@ -5,6 +5,7 @@ checkForUpdates();
5
5
 
6
6
  const program = createProgram();
7
7
 
8
- program.parseAsync(process.argv).catch(() => {
8
+ program.parseAsync(process.argv).catch((err) => {
9
+ console.error(err instanceof Error ? err.message : String(err));
9
10
  process.exit(1);
10
11
  });
@@ -24,8 +24,18 @@ function getDefaultOutput() {
24
24
  function setDefaultOutput(format) {
25
25
  config.set("defaultOutput", format);
26
26
  }
27
+ var VALID_ENVIRONMENTS = /* @__PURE__ */ new Set(["production", "staging"]);
27
28
  function getEnvironment() {
28
- return process.env.TIGHTKNIT_ENVIRONMENT || config.get("environment");
29
+ const envVar = process.env.TIGHTKNIT_ENVIRONMENT;
30
+ if (envVar) {
31
+ if (!VALID_ENVIRONMENTS.has(envVar)) {
32
+ throw new Error(
33
+ `Invalid TIGHTKNIT_ENVIRONMENT: "${envVar}". Must be "production" or "staging"`
34
+ );
35
+ }
36
+ return envVar;
37
+ }
38
+ return config.get("environment");
29
39
  }
30
40
  function setEnvironment(env) {
31
41
  config.set("environment", env);
@@ -40,7 +50,9 @@ function getConfigValue(key) {
40
50
  case "environment":
41
51
  return getEnvironment();
42
52
  default:
43
- throw new Error(`Unknown config key: ${key}. Valid keys: ${VALID_CONFIG_KEYS}`);
53
+ throw new Error(
54
+ `Unknown config key: ${key}. Valid keys: ${VALID_CONFIG_KEYS}`
55
+ );
44
56
  }
45
57
  }
46
58
  function setConfigValue(key, value) {
@@ -50,18 +62,24 @@ function setConfigValue(key, value) {
50
62
  break;
51
63
  case "default-output":
52
64
  if (value !== "json" && value !== "table") {
53
- throw new Error(`Invalid output format: ${value}. Must be "json" or "table"`);
65
+ throw new Error(
66
+ `Invalid output format: ${value}. Must be "json" or "table"`
67
+ );
54
68
  }
55
69
  setDefaultOutput(value);
56
70
  break;
57
71
  case "environment":
58
72
  if (value !== "production" && value !== "staging") {
59
- throw new Error(`Invalid environment: ${value}. Must be "production" or "staging"`);
73
+ throw new Error(
74
+ `Invalid environment: ${value}. Must be "production" or "staging"`
75
+ );
60
76
  }
61
77
  setEnvironment(value);
62
78
  break;
63
79
  default:
64
- throw new Error(`Unknown config key: ${key}. Valid keys: ${VALID_CONFIG_KEYS}`);
80
+ throw new Error(
81
+ `Unknown config key: ${key}. Valid keys: ${VALID_CONFIG_KEYS}`
82
+ );
65
83
  }
66
84
  }
67
85
  function getConfigPath() {
@@ -72,6 +90,8 @@ function getConfigPath() {
72
90
  import { readFileSync } from "fs";
73
91
  import { fileURLToPath } from "url";
74
92
  import { dirname, join } from "path";
93
+ var MissingVersionError = class extends Error {
94
+ };
75
95
  function readVersion() {
76
96
  let dir = dirname(fileURLToPath(import.meta.url));
77
97
  for (let i = 0; i < 5; i++) {
@@ -79,13 +99,23 @@ function readVersion() {
79
99
  const pkgPath = join(dir, "package.json");
80
100
  const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
81
101
  if (pkg.name === "@tightknitai/tightknit") {
82
- return pkg.version ?? "0.0.0";
102
+ if (!pkg.version) {
103
+ throw new MissingVersionError(
104
+ `Found @tightknitai/tightknit package.json at ${pkgPath} but "version" field is missing`
105
+ );
106
+ }
107
+ return pkg.version;
108
+ }
109
+ } catch (err) {
110
+ if (err instanceof MissingVersionError) {
111
+ throw err;
83
112
  }
84
- } catch {
85
113
  }
86
114
  dir = dirname(dir);
87
115
  }
88
- return "0.0.0";
116
+ throw new Error(
117
+ "Could not find @tightknitai/tightknit package.json within 5 parent directories"
118
+ );
89
119
  }
90
120
  var VERSION = readVersion();
91
121
 
@@ -96,7 +126,7 @@ var BASE_URLS = {
96
126
  };
97
127
  var API_PREFIX = "/admin/v0";
98
128
  function getBaseUrl() {
99
- return BASE_URLS[getEnvironment()];
129
+ return process.env.TIGHTKNIT_API_URL || BASE_URLS[getEnvironment()];
100
130
  }
101
131
  function buildUrl(path, params) {
102
132
  const url = new URL(`${API_PREFIX}${path}`, getBaseUrl());
@@ -113,7 +143,7 @@ async function parseErrorResponse(response) {
113
143
  let message;
114
144
  try {
115
145
  const body = await response.json();
116
- message = body.message || body.error || response.statusText;
146
+ message = JSON.stringify(body);
117
147
  } catch {
118
148
  message = response.statusText;
119
149
  }
@@ -176,11 +206,15 @@ async function listEvents(params) {
176
206
  );
177
207
  }
178
208
  async function createEvent(input) {
179
- return apiRequest("/calendar_events", {
180
- method: "POST",
181
- body: input,
182
- idempotencyKey: crypto.randomUUID()
183
- });
209
+ const { description, ...rest } = input;
210
+ return apiRequest(
211
+ "/calendar_events",
212
+ {
213
+ method: "POST",
214
+ body: { ...rest, description: { text: description } },
215
+ idempotencyKey: crypto.randomUUID()
216
+ }
217
+ );
184
218
  }
185
219
  async function getEvent(id) {
186
220
  return apiRequest(`/calendar_events/${id}`);
@@ -250,12 +284,16 @@ async function sendMessage(input) {
250
284
  async function search(params) {
251
285
  return apiRequest(
252
286
  "/search",
253
- { params }
287
+ {
288
+ params
289
+ }
254
290
  );
255
291
  }
256
292
 
257
293
  export {
258
294
  setRuntimeApiKey,
295
+ getApiKey,
296
+ getDefaultOutput,
259
297
  getConfigValue,
260
298
  setConfigValue,
261
299
  getConfigPath,
@@ -277,4 +315,4 @@ export {
277
315
  sendMessage,
278
316
  search
279
317
  };
280
- //# sourceMappingURL=chunk-PRA5JZ27.js.map
318
+ //# sourceMappingURL=chunk-WSRTDKVW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/config.ts","../src/core/version.ts","../src/core/client.ts"],"sourcesContent":["import Conf from 'conf';\n\nexport type Environment = 'production' | 'staging';\n\ninterface TightknitConfig {\n apiKey: string;\n defaultOutput: 'json' | 'table';\n environment: Environment;\n}\n\nconst config = new Conf<TightknitConfig>({\n projectName: 'tightknit',\n defaults: {\n apiKey: '',\n defaultOutput: 'table',\n environment: 'production'\n }\n});\n\n/** Runtime API key set via --api-key flag (highest precedence) */\nlet runtimeApiKey: string | undefined;\n\n/** Set a runtime API key (from --api-key flag). Takes highest precedence. */\nexport function setRuntimeApiKey(key: string | undefined): void {\n runtimeApiKey = key;\n}\n\n/** Get the API key — --api-key flag > env var > stored config */\nexport function getApiKey(): string {\n return runtimeApiKey || process.env.TIGHTKNIT_API_KEY || config.get('apiKey');\n}\n\n/** Set the API key */\nexport function setApiKey(key: string): void {\n config.set('apiKey', key);\n}\n\n/** Get the default output format */\nexport function getDefaultOutput(): 'json' | 'table' {\n return config.get('defaultOutput');\n}\n\n/** Set the default output format */\nexport function setDefaultOutput(format: 'json' | 'table'): void {\n config.set('defaultOutput', format);\n}\n\nconst VALID_ENVIRONMENTS = new Set<string>(['production', 'staging']);\n\n/** Get the configured environment */\nexport function getEnvironment(): Environment {\n const envVar = process.env.TIGHTKNIT_ENVIRONMENT;\n if (envVar) {\n if (!VALID_ENVIRONMENTS.has(envVar)) {\n throw new Error(\n `Invalid TIGHTKNIT_ENVIRONMENT: \"${envVar}\". Must be \"production\" or \"staging\"`\n );\n }\n return envVar as Environment;\n }\n return config.get('environment');\n}\n\n/** Set the environment */\nexport function setEnvironment(env: Environment): void {\n config.set('environment', env);\n}\n\nconst VALID_CONFIG_KEYS = 'api-key, default-output, environment';\n\n/** Get a config value by key name */\nexport function getConfigValue(key: string): string {\n switch (key) {\n case 'api-key':\n return getApiKey();\n case 'default-output':\n return getDefaultOutput();\n case 'environment':\n return getEnvironment();\n default:\n throw new Error(\n `Unknown config key: ${key}. Valid keys: ${VALID_CONFIG_KEYS}`\n );\n }\n}\n\n/** Set a config value by key name */\nexport function setConfigValue(key: string, value: string): void {\n switch (key) {\n case 'api-key':\n setApiKey(value);\n break;\n case 'default-output':\n if (value !== 'json' && value !== 'table') {\n throw new Error(\n `Invalid output format: ${value}. Must be \"json\" or \"table\"`\n );\n }\n setDefaultOutput(value);\n break;\n case 'environment':\n if (value !== 'production' && value !== 'staging') {\n throw new Error(\n `Invalid environment: ${value}. Must be \"production\" or \"staging\"`\n );\n }\n setEnvironment(value);\n break;\n default:\n throw new Error(\n `Unknown config key: ${key}. Valid keys: ${VALID_CONFIG_KEYS}`\n );\n }\n}\n\n/** Get the config file path (useful for debugging) */\nexport function getConfigPath(): string {\n return config.path;\n}\n","import { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\n\nclass MissingVersionError extends Error {}\n\n/** Walks up from the current module to find the CLI's package.json version */\nfunction readVersion(): string {\n let dir = dirname(fileURLToPath(import.meta.url));\n for (let i = 0; i < 5; i++) {\n try {\n const pkgPath = join(dir, 'package.json');\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as {\n name?: string;\n version?: string;\n };\n if (pkg.name === '@tightknitai/tightknit') {\n if (!pkg.version) {\n throw new MissingVersionError(\n `Found @tightknitai/tightknit package.json at ${pkgPath} but \"version\" field is missing`\n );\n }\n return pkg.version;\n }\n } catch (err) {\n if (err instanceof MissingVersionError) {\n throw err;\n }\n // Expected when traversing directories without package.json — keep walking\n }\n dir = dirname(dir);\n }\n throw new Error(\n 'Could not find @tightknitai/tightknit package.json within 5 parent directories'\n );\n}\n\nexport const VERSION = readVersion();\n","import { getApiKey, getEnvironment } from './config';\nimport type { ApiError } from './types';\n\nconst BASE_URLS = {\n production: 'https://api.tightknit.ai',\n staging: 'https://staging-api.tightknit.ai'\n} as const;\n\nconst API_PREFIX = '/admin/v0';\n\n/** TIGHTKNIT_API_URL env var takes highest precedence for custom deployments and testing */\nfunction getBaseUrl(): string {\n return process.env.TIGHTKNIT_API_URL || BASE_URLS[getEnvironment()];\n}\n\ninterface RequestOptions {\n method?: 'GET' | 'POST' | 'PATCH' | 'DELETE';\n body?: Record<string, unknown>;\n params?: Record<string, string | number | boolean | undefined>;\n idempotencyKey?: string;\n}\n\n/** Build a URL with query parameters */\nfunction buildUrl(\n path: string,\n params?: Record<string, string | number | boolean | undefined>\n): string {\n const url = new URL(`${API_PREFIX}${path}`, getBaseUrl());\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n return url.toString();\n}\n\n/** Parse an API error response into a structured error */\nasync function parseErrorResponse(response: Response): Promise<ApiError> {\n let message: string;\n try {\n const body = (await response.json()) as Record<string, unknown>;\n message = JSON.stringify(body);\n } catch {\n message = response.statusText;\n }\n\n return {\n error: true,\n code: response.status,\n message: `${message} (${response.status})`\n };\n}\n\n/** Make an authenticated request to the Tightknit API */\nexport async function apiRequest<T>(\n path: string,\n options: RequestOptions = {}\n): Promise<T> {\n const { method = 'GET', body, params, idempotencyKey } = options;\n\n const apiKey = getApiKey();\n if (!apiKey) {\n throw new TightknitApiError(\n 'No API key configured. Run: tightknit config set api-key <YOUR_KEY>',\n 401\n );\n }\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json'\n };\n\n if (idempotencyKey && (method === 'POST' || method === 'PATCH')) {\n headers['Idempotency-Key'] = idempotencyKey;\n }\n\n const url = buildUrl(path, params);\n\n const response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined\n });\n\n if (!response.ok) {\n const apiError = await parseErrorResponse(response);\n throw new TightknitApiError(apiError.message, apiError.code);\n }\n\n if (response.status === 204) {\n return undefined as T;\n }\n\n return (await response.json()) as T;\n}\n\n/** Custom error class for Tightknit API errors */\nexport class TightknitApiError extends Error {\n code: number;\n\n constructor(message: string, code: number) {\n super(message);\n this.name = 'TightknitApiError';\n this.code = code;\n }\n\n toJSON(): ApiError {\n return {\n error: true,\n code: this.code,\n message: this.message\n };\n }\n}\n\n// --- Calendar Events ---\n// Paths use underscores: /calendar_events\n\nexport interface ListEventsParams {\n page?: number;\n per_page?: number;\n time_filter?: 'upcoming' | 'past';\n date_filter?: string;\n status?: 'draft' | 'needs_approval' | 'published';\n published_to_site?: boolean;\n is_unlisted?: boolean;\n feed_id?: string;\n tag_ids?: string;\n}\n\n/**\n * List calendar events with optional filtering and pagination.\n * @param params - Optional filters for time, status, feed, pagination, etc.\n * @returns Paginated list of calendar events.\n */\nexport async function listEvents(params?: ListEventsParams) {\n return apiRequest<{ data: unknown[]; page: number; per_page: number }>(\n '/calendar_events',\n { params: params as Record<string, string | number | boolean | undefined> }\n );\n}\n\nexport interface CreateEventInput {\n title: string;\n description: string;\n start_date: string;\n end_date: string;\n location?: string;\n link?: string;\n status?: 'needs_approval' | 'published';\n slug?: string;\n publish_to_site?: boolean;\n is_unlisted?: boolean;\n allow_public_guest_list?: boolean;\n enable_registration_button?: boolean;\n triggers_webhooks?: boolean;\n external_speakers?: string;\n cover_image_file_id?: string;\n reminders_config?: number[];\n publish_to_slack_channels?: string[];\n}\n\n/**\n * Create a new calendar event.\n * @param input - Event details including title, dates, and optional settings.\n * @returns The created event's ID and success status.\n */\nexport async function createEvent(input: CreateEventInput) {\n const { description, ...rest } = input;\n return apiRequest<{ success: boolean; data: { calendar_event_id: string } }>(\n '/calendar_events',\n {\n method: 'POST',\n body: { ...rest, description: { text: description } },\n idempotencyKey: crypto.randomUUID()\n }\n );\n}\n\n/**\n * Get a single calendar event by ID.\n * @param id - The calendar event ID.\n * @returns The calendar event details.\n */\nexport async function getEvent(id: string) {\n return apiRequest<unknown>(`/calendar_events/${id}`);\n}\n\n/**\n * Delete a calendar event by ID.\n * @param id - The calendar event ID.\n * @returns void on success (204 response).\n */\nexport async function deleteEvent(id: string) {\n return apiRequest<void>(`/calendar_events/${id}`, { method: 'DELETE' });\n}\n\nexport interface UpdateAttendeeInput {\n user: { slack_user_id: string } | { email: string } | { profile_id: string };\n personal_join_link?: string;\n}\n\n/**\n * Update or add an attendee for a calendar event.\n * @param eventId - The calendar event ID.\n * @param input - Attendee user identifier and optional join link.\n * @returns The updated attendee details.\n */\nexport async function updateAttendee(\n eventId: string,\n input: UpdateAttendeeInput\n) {\n return apiRequest<unknown>(`/calendar_events/${eventId}/attendees`, {\n method: 'PATCH',\n body: input as unknown as Record<string, unknown>,\n idempotencyKey: crypto.randomUUID()\n });\n}\n\n// --- Awards ---\n\nexport interface AssignAwardInput {\n recipient:\n | { slack_user_id: string }\n | { email: string }\n | { profile_id: string };\n sender?:\n | { slack_user_id: string }\n | { email: string }\n | { profile_id: string }\n | null;\n send_anonymously?: boolean;\n}\n\n/**\n * Assign an award to a recipient.\n * @param awardId - The award ID to assign.\n * @param input - Recipient identifier and optional sender/anonymity settings.\n * @returns Success status.\n */\nexport async function assignAward(awardId: string, input: AssignAwardInput) {\n return apiRequest<{ success: boolean }>(`/awards/${awardId}/assign`, {\n method: 'POST',\n body: input as unknown as Record<string, unknown>,\n idempotencyKey: crypto.randomUUID()\n });\n}\n\n// --- Feeds ---\n\nexport interface ListFeedsParams {\n page?: number;\n per_page?: number;\n is_unlisted?: boolean;\n is_archived?: boolean;\n}\n\n/**\n * List feeds with optional filtering and pagination.\n * @param params - Optional filters for unlisted/archived status and pagination.\n * @returns Paginated list of feeds.\n */\nexport async function listFeeds(params?: ListFeedsParams) {\n return apiRequest<{ data: unknown[]; page: number; per_page: number }>(\n '/feeds',\n { params: params as Record<string, string | number | boolean | undefined> }\n );\n}\n\n/**\n * Get a single feed by ID.\n * @param feedId - The feed ID.\n * @returns The feed details.\n */\nexport async function getFeed(feedId: string) {\n return apiRequest<unknown>(`/feeds/${feedId}`);\n}\n\nexport interface ListPostsInFeedParams {\n page?: number;\n per_page?: number;\n sort?: 'oldest' | 'newest' | 'most-recent-activity';\n}\n\n/**\n * List posts within a feed with optional sorting and pagination.\n * @param feedId - The feed ID to list posts from.\n * @param params - Optional sort order and pagination.\n * @returns Paginated list of posts.\n */\nexport async function listPostsInFeed(\n feedId: string,\n params?: ListPostsInFeedParams\n) {\n return apiRequest<{ data: unknown[]; page: number; per_page: number }>(\n `/feeds/${feedId}/posts`,\n { params: params as Record<string, string | number | boolean | undefined> }\n );\n}\n\n// --- Posts ---\n\n/**\n * Get a single post by ID.\n * @param postId - The post ID.\n * @returns The post details.\n */\nexport async function getPost(postId: string) {\n return apiRequest<unknown>(`/posts/${postId}`);\n}\n\n// --- Members ---\n\nexport interface AddMemberInput {\n email: string;\n full_name: string;\n avatar_url_original?: string;\n}\n\n/**\n * Add a new member to the community (Enterprise feature).\n * @param input - Member details including email, name, and optional avatar.\n * @returns The created member details.\n */\nexport async function addMember(input: AddMemberInput) {\n return apiRequest<unknown>('/members', {\n method: 'POST',\n body: input as unknown as Record<string, unknown>,\n idempotencyKey: crypto.randomUUID()\n });\n}\n\n/**\n * Check if a user is a member of the community by email.\n * @param email - The email address to check.\n * @returns Membership status and details.\n */\nexport async function checkMembership(email: string) {\n return apiRequest<unknown>('/members/check', {\n method: 'POST',\n body: { email }\n });\n}\n\n// --- Groups ---\n\nexport interface AddUserToGroupInput {\n user: { slack_user_id: string } | { email: string } | { profile_id: string };\n}\n\n/**\n * Add a user to a group.\n * @param groupId - The group ID.\n * @param input - User identifier to add to the group.\n * @returns The updated group membership details.\n */\nexport async function addUserToGroup(\n groupId: string,\n input: AddUserToGroupInput\n) {\n return apiRequest<unknown>(`/groups/${groupId}/members`, {\n method: 'POST',\n body: input as unknown as Record<string, unknown>,\n idempotencyKey: crypto.randomUUID()\n });\n}\n\n// --- Messages ---\n\nexport interface SendMessageInput {\n channel: string;\n text: string;\n thread_ts?: string;\n}\n\n/**\n * Send a message to a Slack channel.\n * @param input - Channel, message text, and optional thread timestamp.\n * @returns The sent message details.\n */\nexport async function sendMessage(input: SendMessageInput) {\n return apiRequest<unknown>('/messages', {\n method: 'POST',\n body: input as unknown as Record<string, unknown>,\n idempotencyKey: crypto.randomUUID()\n });\n}\n\n// --- Search ---\n\nexport interface SearchParams {\n q: string;\n type: 'post' | 'comment' | 'content_resource';\n page?: number;\n per_page?: number;\n}\n\n/**\n * Search across community content (Beta).\n * @param params - Search query, content type, and optional pagination.\n * @returns Paginated search results.\n */\nexport async function search(params: SearchParams) {\n return apiRequest<{ data: unknown[]; page: number; per_page: number }>(\n '/search',\n {\n params: params as unknown as Record<\n string,\n string | number | boolean | undefined\n >\n }\n );\n}\n"],"mappings":"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","names":[]}