commune-ai 0.3.2 → 0.3.6

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/LICENSE ADDED
@@ -0,0 +1,191 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to the Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by the Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding any notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ Copyright 2024-2026 Commune
180
+
181
+ Licensed under the Apache License, Version 2.0 (the "License");
182
+ you may not use this file except in compliance with the License.
183
+ You may obtain a copy of the License at
184
+
185
+ http://www.apache.org/licenses/LICENSE-2.0
186
+
187
+ Unless required by applicable law or agreed to in writing, software
188
+ distributed under the License is distributed on an "AS IS" BASIS,
189
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
190
+ See the License for the specific language governing permissions and
191
+ limitations under the License.
package/README.md CHANGED
@@ -1,11 +1,29 @@
1
- # commune-ai
1
+ # TypeScript SDK for Email in AI Agents
2
2
 
3
- Email infrastructure for agents — set up an inbox and send your first email in 30 seconds. Programmatic inboxes (~1 line), consistent threads, setup and verify custom domains, send and receive attachments, structured data extraction.
3
+ [![npm](https://img.shields.io/npm/v/commune-ai?color=blue&label=npm)](https://www.npmjs.com/package/commune-ai)
4
+ [![npm downloads](https://img.shields.io/npm/dm/commune-ai?label=downloads%2Fmo)](https://www.npmjs.com/package/commune-ai)
5
+ [![Node.js 18+](https://img.shields.io/badge/node-18%2B-blue)](https://www.npmjs.com/package/commune-ai)
6
+ [![Apache-2.0 License](https://img.shields.io/badge/license-Apache--2.0-blue)](LICENSE)
7
+ [![commune.email](https://img.shields.io/badge/docs-commune.email-blue)](https://commune.email/?ref=commune-ai)
8
+
9
+ Give your TypeScript/Node.js agent a real inbox. Send email, receive webhooks, manage threads — in 4 lines.
4
10
 
5
11
  ```bash
6
12
  npm install commune-ai
7
13
  ```
8
14
 
15
+ ```typescript
16
+ import { CommuneClient } from 'commune-ai';
17
+
18
+ const commune = new CommuneClient({ apiKey: 'comm_...' });
19
+ await commune.messages.send({
20
+ to: 'user@example.com',
21
+ subject: 'From your agent',
22
+ text: 'Task complete.',
23
+ inboxId: process.env.COMMUNE_INBOX_ID! // inbox ID from dashboard (e.g. "inbox_...")
24
+ });
25
+ ```
26
+
9
27
  ## Table of Contents
10
28
 
11
29
  - [Quickstart](#quickstart-endtoend-in-one-file)
@@ -715,6 +733,93 @@ Inbound webhook payloads from Commune are signed with your inbox webhook secret.
715
733
 
716
734
  ---
717
735
 
736
+ ## Why commune-ai instead of alternatives
737
+
738
+ | | Commune | Gmail API | SendGrid | Resend | Raw SMTP/IMAP |
739
+ |---|---|---|---|---|---|
740
+ | Per-agent isolated inbox | ✅ | ❌ shared | ❌ | ❌ | ❌ |
741
+ | Inbound email + webhooks | ✅ | ✅ complex | ❌ | ✅ limited | ❌ |
742
+ | Outbound sending | ✅ | ✅ | ✅ | ✅ | ✅ |
743
+ | Email threading (RFC 5322) | ✅ automatic | ✅ manual | ❌ | ❌ | ❌ |
744
+ | Semantic search across history | ✅ | ❌ | ❌ | ❌ | ❌ |
745
+ | Structured JSON extraction | ✅ per-inbox | ❌ | ❌ | ❌ | ❌ |
746
+ | Prompt injection protection | ✅ built-in | ❌ | ❌ | ❌ | ❌ |
747
+ | Agent-native design | ✅ | ❌ human-first | ❌ | ❌ | ❌ |
748
+ | TypeScript types | ✅ full | partial | partial | ✅ | ❌ |
749
+ | Self-hostable backend | ✅ | ❌ | ❌ | ❌ | ✅ |
750
+
751
+ **Key difference:** Commune is designed for AI agents from the ground up. Each agent gets an isolated inbox, inbound emails fire webhooks immediately, threads track conversation context automatically, and the platform handles security so your agent doesn't have to.
752
+
753
+ ---
754
+
755
+ ## FAQ
756
+
757
+ **How do I give my TypeScript LangChain agent its own email address?**
758
+ Install `commune-ai`, initialize `CommuneClient`, and call `commune.inboxes.create({ localPart: 'support' })`. The returned `inbox.address` is a real, deliverable email. Wrap `send_email` and `read_inbox` as LangChain tools to make them callable from your agent's reasoning loop.
759
+
760
+ **How does my agent receive emails in real time?**
761
+ Set a webhook URL on the inbox — either in the dashboard or via `client.inboxes.create({ webhookEndpoint: 'https://...' })`. When an email arrives, Commune POSTs the payload to your endpoint with an HMAC-SHA256 signature. Use `verifyCommuneWebhook()` to verify before processing.
762
+
763
+ **What happens if my webhook handler is down?**
764
+ Commune retries up to 8 times with exponential backoff (1s, 2s, 4s, 8s, 16s, 32s, 64s, 128s). Your handler will receive the event when it comes back up. A circuit breaker prevents thundering herd on recovery.
765
+
766
+ **How do I reply in the same email thread?**
767
+ Pass `thread_id` to `messages.send()`. The thread_id comes from the webhook payload (`message.thread_id`) or from `threads.list()`. Without thread_id, the reply appears as a new email.
768
+
769
+ **Can I use this with CrewAI or OpenAI Agents SDK in TypeScript?**
770
+ Yes. Wrap the commune-ai methods as tool definitions using your framework's tool interface. See the [cookbook](https://github.com/shanjai-raj/commune-cookbook) for TypeScript examples.
771
+
772
+ **How do I search through an agent's email history?**
773
+ Use `client.searchConversations('natural language query', { organizationId })`. The search uses vector embeddings — it finds semantically similar content, not just keyword matches.
774
+
775
+ **What does structured extraction do?**
776
+ You define a JSON schema on an inbox (e.g., `{ order_id: string, issue_type: string }`). Every inbound email is automatically parsed against the schema before your webhook fires. The extracted data is in `context.payload.extractedData`. No extra LLM call needed.
777
+
778
+ **How do I verify a webhook signature?**
779
+ Use `verifyCommuneWebhook({ rawBody, timestamp, signature, secret })`. The signature is in the `x-commune-signature` header, timestamp in `x-commune-timestamp`. Always verify before processing to prevent spoofed requests.
780
+
781
+ **Can multiple TypeScript agents share one Commune org?**
782
+ Yes. Create one inbox per agent (or per logical workflow). They share the same API key but have isolated inboxes, thread histories, and webhook endpoints.
783
+
784
+ **What is the commune-ai package vs commune-mail?**
785
+ `commune-ai` is the TypeScript/Node.js SDK (npm). `commune-mail` is the Python SDK (PyPI). Both connect to the same Commune backend and have the same capabilities, just different language interfaces.
786
+
787
+ **Does commune-ai work in serverless environments (Vercel, AWS Lambda, Cloudflare Workers)?**
788
+ Yes. The SDK is a standard HTTP client with no persistent connections. It works in any Node.js environment including serverless.
789
+
790
+ **Is there a rate limit?**
791
+ Free tier: 100 emails/hour, 1,000/day. Pro tier: 10,000/hour, 100,000/day. Enterprise: unlimited. Rate limit headers (`X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`) are included in all API responses.
792
+
793
+ ---
794
+
795
+ ## Ecosystem
796
+
797
+ | Package | Description |
798
+ |---------|-------------|
799
+ | [commune](https://github.com/shanjai-raj/commune) | Email infrastructure — self-hostable backend |
800
+ | **[commune-ai](https://github.com/shanjai-raj/commune-ai)** | **TypeScript/Node.js SDK** |
801
+ | [commune-python](https://github.com/shanjai-raj/commune-python) | Python SDK |
802
+ | [commune-mcp](https://github.com/shanjai-raj/commune-mcp) | MCP server for Claude Desktop, Cursor, Windsurf |
803
+ | [commune-cli](https://github.com/shanjai-raj/commune-cli) | Command-line interface |
804
+
805
+ ## Guides
806
+
807
+ Framework integration tutorials:
808
+
809
+ - [LangChain agent with email](https://commune.email/blog/email-for-langchain-agents) — BaseTool pattern, send + receive in under 10 min
810
+ - [CrewAI email agent](https://commune.email/blog/crewai-email-agent) — Researcher → Writer → Sender crew, reply webhook
811
+ - [AutoGen email agent](https://commune.email/blog/autogen-email-agent) — function registration, agent-to-agent handoffs via inbox
812
+ - [OpenAI Agents SDK + email](https://commune.email/blog/openai-agents-sdk-email) — tool definitions for the Agents SDK
813
+
814
+ Comparison pages (if you're evaluating alternatives):
815
+
816
+ - [SendGrid alternative for AI agents](https://commune.email/sendgrid-alternative)
817
+ - [Mailgun alternative for AI agents](https://commune.email/mailgun-alternative)
818
+ - [Gmail alternative for AI agents](https://commune.email/gmail-alternative-for-ai-agents)
819
+ - [Inbound email API](https://commune.email/inbound-email-api)
820
+
821
+ ---
822
+
718
823
  ## License
719
824
 
720
- MIT
825
+ Apache-2.0
package/dist/client.d.ts CHANGED
@@ -1,17 +1,74 @@
1
- import type { AttachmentRecord, AttachmentUrl, AttachmentUploadResponse, CreateDomainPayload, DomainEntry, InboxEntry, MessageListParams, SendMessagePayload, UnifiedMessage, SearchFilter, SearchOptions, SearchResult, IndexConversationPayload, ThreadListParams, ThreadListResponse, SearchThreadsParams, SearchThreadResult, ThreadMetadataEntry, DeliveryMetricsParams, DeliveryEventEntry, DeliveryEventsParams, DeliverySuppressionsParams, SuppressionEntry, PhoneNumber, UpdatePhoneNumberPayload, SmsConversation, SmsConversationListParams, SmsMessage, SendSmsPayload, SendSmsResult, SmsSearchParams, CreditBalance, CreditBundle } from './types.js';
1
+ import type { AttachmentRecord, AttachmentUrl, AttachmentUploadResponse, CreateDomainPayload, DomainEntry, InboxEntry, MessageListParams, SendMessagePayload, UnifiedMessage, SearchFilter, SearchOptions, SearchResult, IndexConversationPayload, ThreadListParams, ThreadListResponse, SearchThreadsParams, SearchThreadResult, ThreadMetadataEntry, DeliveryMetricsParams, DeliveryEventEntry, DeliveryEventsParams, DeliverySuppressionsParams, SuppressionEntry, PhoneNumber, UpdatePhoneNumberPayload, PhoneNumberWebhookPayload, AvailablePhoneNumber, ProvisionPhoneNumberPayload, SmsConversation, SmsConversationListParams, SmsMessage, SmsListParams, SmsSuppression, SendSmsPayload, SendSmsResult, SmsSearchParams, CreditBalance, CreditBundle, CreditCheckoutResult, FeedbackSubmitPayload, FeedbackResult } from './types.js';
2
+ /**
3
+ * x402Client interface — matches the x402 SDK's client shape.
4
+ * Developers create and configure their own x402Client with their preferred
5
+ * signers, networks, and policies, then pass it to CommuneClient.
6
+ *
7
+ * We never touch private keys. The developer controls their own signer.
8
+ */
9
+ export interface X402ClientLike {
10
+ [key: string]: unknown;
11
+ }
12
+ /**
13
+ * Client options — two auth modes:
14
+ *
15
+ * 1. API key (existing Stripe subscription):
16
+ * `new CommuneClient({ apiKey: 'comm_xxx' })`
17
+ *
18
+ * 2. x402 client (pay-per-call with USDC):
19
+ * `new CommuneClient({ wallet: x402Client })`
20
+ * The developer creates and owns the x402Client — we never see their keys.
21
+ *
22
+ * 3. Auto-detect from environment:
23
+ * `new CommuneClient()`
24
+ * Reads COMMUNE_API_KEY env var.
25
+ */
2
26
  export type ClientOptions = {
3
- baseUrl?: string;
4
27
  apiKey: string;
28
+ baseUrl?: string;
5
29
  headers?: Record<string, string>;
6
30
  fetcher?: typeof fetch;
31
+ } | {
32
+ wallet: X402ClientLike;
33
+ baseUrl?: string;
34
+ headers?: Record<string, string>;
35
+ } | {
36
+ baseUrl?: string;
37
+ headers?: Record<string, string>;
7
38
  };
8
39
  export declare class CommuneClient {
9
40
  private baseUrl;
10
41
  private apiKey;
11
42
  private headers?;
12
43
  private fetcher;
44
+ private authMode;
13
45
  private deprecationWarnings;
14
- constructor(options: ClientOptions);
46
+ /**
47
+ * Create a Commune client.
48
+ *
49
+ * @example
50
+ * // API key auth (existing Stripe subscription)
51
+ * const client = new CommuneClient({ apiKey: 'comm_xxx' });
52
+ *
53
+ * // x402 wallet auth (pay-per-call with USDC)
54
+ * // Developer creates and owns the x402Client — we never touch private keys.
55
+ * import { x402Client } from '@x402/fetch';
56
+ * import { registerExactEvmScheme } from '@x402/evm/exact/client';
57
+ * import { privateKeyToAccount } from 'viem/accounts';
58
+ *
59
+ * const x402 = new x402Client();
60
+ * registerExactEvmScheme(x402, { signer: privateKeyToAccount(process.env.WALLET_KEY) });
61
+ * const client = new CommuneClient({ wallet: x402 });
62
+ *
63
+ * // Auto-detect from COMMUNE_API_KEY env var
64
+ * const client = new CommuneClient();
65
+ */
66
+ constructor(options?: ClientOptions);
67
+ /**
68
+ * Wrap fetch with an x402Client for transparent payment handling.
69
+ * The x402Client is created and owned by the developer — we never see their keys.
70
+ */
71
+ private static createX402Fetcher;
15
72
  private warnDeprecated;
16
73
  private request;
17
74
  domains: {
@@ -134,15 +191,64 @@ export declare class CommuneClient {
134
191
  list: () => Promise<PhoneNumber[]>;
135
192
  get: (phoneNumberId: string) => Promise<PhoneNumber>;
136
193
  update: (phoneNumberId: string, payload: UpdatePhoneNumberPayload) => Promise<PhoneNumber>;
194
+ available: (params?: {
195
+ type?: "TollFree" | "Local";
196
+ country?: string;
197
+ area_code?: string;
198
+ limit?: number;
199
+ }) => Promise<AvailablePhoneNumber[]>;
200
+ provision: (payload?: ProvisionPhoneNumberPayload) => Promise<PhoneNumber>;
201
+ release: (phoneNumberId: string) => Promise<{
202
+ id: string;
203
+ status: string;
204
+ message: string;
205
+ }>;
206
+ setAllowList: (phoneNumberId: string, numbers: string[]) => Promise<PhoneNumber>;
207
+ setBlockList: (phoneNumberId: string, numbers: string[]) => Promise<PhoneNumber>;
208
+ setWebhook: (phoneNumberId: string, payload: PhoneNumberWebhookPayload) => Promise<PhoneNumber>;
137
209
  };
138
210
  sms: {
211
+ list: (params?: SmsListParams) => Promise<SmsMessage[]>;
139
212
  send: (payload: SendSmsPayload) => Promise<SendSmsResult>;
140
213
  conversations: (params?: SmsConversationListParams) => Promise<SmsConversation[]>;
141
214
  thread: (remoteNumber: string, phoneNumberId?: string) => Promise<SmsMessage[]>;
142
215
  search: (params: SmsSearchParams) => Promise<SmsMessage[]>;
216
+ suppressions: (phoneNumberId?: string) => Promise<SmsSuppression[]>;
217
+ removeSuppression: (phoneNumber: string) => Promise<{
218
+ removed: boolean;
219
+ phone_number: string;
220
+ }>;
143
221
  };
144
222
  credits: {
145
223
  balance: () => Promise<CreditBalance>;
146
224
  bundles: () => Promise<CreditBundle[]>;
225
+ checkout: (bundle: "starter" | "growth" | "scale", returnUrl?: string) => Promise<CreditCheckoutResult>;
226
+ };
227
+ feedback: {
228
+ /**
229
+ * Submit feedback to the Commune product team.
230
+ *
231
+ * Three types:
232
+ * - `"error"` — something broke or behaved unexpectedly
233
+ * - `"feature"` — request for new functionality
234
+ * - `"signal"` — observation, impression, or positive note
235
+ *
236
+ * The optional `context` object lets you attach structured metadata
237
+ * that makes feedback actionable (e.g. which endpoint failed, what IDs
238
+ * were involved, what you were trying to do).
239
+ *
240
+ * @example
241
+ * await commune.feedback.submit({
242
+ * type: 'error',
243
+ * message: 'Thread list returns 500 when inbox has never received a message',
244
+ * context: { inbox_id: 'inb_123', status_code: 500 },
245
+ * });
246
+ *
247
+ * await commune.feedback.submit({
248
+ * type: 'signal',
249
+ * message: 'Semantic search quality on long threads is excellent',
250
+ * });
251
+ */
252
+ submit: (payload: FeedbackSubmitPayload) => Promise<FeedbackResult>;
147
253
  };
148
254
  }
package/dist/client.js CHANGED
@@ -11,6 +11,26 @@ const buildQuery = (params) => {
11
11
  return serialized ? `?${serialized}` : '';
12
12
  };
13
13
  export class CommuneClient {
14
+ /**
15
+ * Create a Commune client.
16
+ *
17
+ * @example
18
+ * // API key auth (existing Stripe subscription)
19
+ * const client = new CommuneClient({ apiKey: 'comm_xxx' });
20
+ *
21
+ * // x402 wallet auth (pay-per-call with USDC)
22
+ * // Developer creates and owns the x402Client — we never touch private keys.
23
+ * import { x402Client } from '@x402/fetch';
24
+ * import { registerExactEvmScheme } from '@x402/evm/exact/client';
25
+ * import { privateKeyToAccount } from 'viem/accounts';
26
+ *
27
+ * const x402 = new x402Client();
28
+ * registerExactEvmScheme(x402, { signer: privateKeyToAccount(process.env.WALLET_KEY) });
29
+ * const client = new CommuneClient({ wallet: x402 });
30
+ *
31
+ * // Auto-detect from COMMUNE_API_KEY env var
32
+ * const client = new CommuneClient();
33
+ */
14
34
  constructor(options) {
15
35
  this.deprecationWarnings = new Set();
16
36
  this.domains = {
@@ -283,8 +303,42 @@ export class CommuneClient {
283
303
  update: async (phoneNumberId, payload) => {
284
304
  return this.request(`/v1/phone-numbers/${encodeURIComponent(phoneNumberId)}`, { method: 'PATCH', json: payload });
285
305
  },
306
+ available: async (params) => {
307
+ return this.request(`/v1/phone-numbers/available${buildQuery({
308
+ type: params?.type,
309
+ country: params?.country,
310
+ area_code: params?.area_code,
311
+ limit: params?.limit,
312
+ })}`);
313
+ },
314
+ provision: async (payload) => {
315
+ return this.request('/v1/phone-numbers', {
316
+ method: 'POST',
317
+ json: (payload ?? {}),
318
+ });
319
+ },
320
+ release: async (phoneNumberId) => {
321
+ return this.request(`/v1/phone-numbers/${encodeURIComponent(phoneNumberId)}`, { method: 'DELETE' });
322
+ },
323
+ setAllowList: async (phoneNumberId, numbers) => {
324
+ return this.request(`/v1/phone-numbers/${encodeURIComponent(phoneNumberId)}/allow-list`, { method: 'PUT', json: { numbers } });
325
+ },
326
+ setBlockList: async (phoneNumberId, numbers) => {
327
+ return this.request(`/v1/phone-numbers/${encodeURIComponent(phoneNumberId)}/block-list`, { method: 'PUT', json: { numbers } });
328
+ },
329
+ setWebhook: async (phoneNumberId, payload) => {
330
+ return this.request(`/v1/phone-numbers/${encodeURIComponent(phoneNumberId)}`, { method: 'PATCH', json: { webhook: payload } });
331
+ },
286
332
  };
287
333
  this.sms = {
334
+ list: async (params = {}) => {
335
+ return this.request(`/v1/sms${buildQuery({
336
+ phone_number_id: params.phone_number_id,
337
+ limit: params.limit,
338
+ before: params.before,
339
+ after: params.after,
340
+ })}`);
341
+ },
288
342
  send: async (payload) => {
289
343
  return this.request('/v1/sms/send', {
290
344
  method: 'POST',
@@ -310,6 +364,12 @@ export class CommuneClient {
310
364
  limit: params.limit,
311
365
  })}`);
312
366
  },
367
+ suppressions: async (phoneNumberId) => {
368
+ return this.request(`/v1/sms/suppressions${buildQuery({ phone_number_id: phoneNumberId })}`);
369
+ },
370
+ removeSuppression: async (phoneNumber) => {
371
+ return this.request(`/v1/sms/suppressions/${encodeURIComponent(phoneNumber)}`, { method: 'DELETE' });
372
+ },
313
373
  };
314
374
  this.credits = {
315
375
  balance: async () => {
@@ -318,11 +378,92 @@ export class CommuneClient {
318
378
  bundles: async () => {
319
379
  return this.request('/v1/credits/bundles');
320
380
  },
381
+ checkout: async (bundle, returnUrl) => {
382
+ return this.request('/v1/credits/checkout', {
383
+ method: 'POST',
384
+ json: {
385
+ bundle,
386
+ ...(returnUrl ? { success_url: returnUrl, cancel_url: returnUrl } : {}),
387
+ },
388
+ });
389
+ },
321
390
  };
322
- this.baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, '');
323
- this.apiKey = options.apiKey;
324
- this.headers = options.headers;
325
- this.fetcher = options.fetcher || fetch;
391
+ this.feedback = {
392
+ /**
393
+ * Submit feedback to the Commune product team.
394
+ *
395
+ * Three types:
396
+ * - `"error"` — something broke or behaved unexpectedly
397
+ * - `"feature"` — request for new functionality
398
+ * - `"signal"` — observation, impression, or positive note
399
+ *
400
+ * The optional `context` object lets you attach structured metadata
401
+ * that makes feedback actionable (e.g. which endpoint failed, what IDs
402
+ * were involved, what you were trying to do).
403
+ *
404
+ * @example
405
+ * await commune.feedback.submit({
406
+ * type: 'error',
407
+ * message: 'Thread list returns 500 when inbox has never received a message',
408
+ * context: { inbox_id: 'inb_123', status_code: 500 },
409
+ * });
410
+ *
411
+ * await commune.feedback.submit({
412
+ * type: 'signal',
413
+ * message: 'Semantic search quality on long threads is excellent',
414
+ * });
415
+ */
416
+ submit: async (payload) => {
417
+ return this.request('/v1/feedback', {
418
+ method: 'POST',
419
+ json: payload,
420
+ });
421
+ },
422
+ };
423
+ const opts = options || {};
424
+ this.baseUrl = (opts.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, '');
425
+ this.headers = 'headers' in opts ? opts.headers : undefined;
426
+ // Resolve auth mode
427
+ if ('apiKey' in opts && opts.apiKey) {
428
+ this.apiKey = opts.apiKey;
429
+ this.authMode = 'apikey';
430
+ this.fetcher = ('fetcher' in opts ? opts.fetcher : undefined) || fetch;
431
+ }
432
+ else if ('wallet' in opts && opts.wallet) {
433
+ this.apiKey = '';
434
+ this.authMode = 'wallet';
435
+ this.fetcher = CommuneClient.createX402Fetcher(opts.wallet);
436
+ }
437
+ else {
438
+ // Auto-detect from environment (API key only — wallet requires explicit x402Client)
439
+ const envApiKey = typeof process !== 'undefined' ? process.env?.COMMUNE_API_KEY : undefined;
440
+ if (envApiKey) {
441
+ this.apiKey = envApiKey;
442
+ this.authMode = 'apikey';
443
+ this.fetcher = fetch;
444
+ }
445
+ else {
446
+ throw new Error('No auth configured. Pass { apiKey } or { wallet: x402Client }, or set COMMUNE_API_KEY.');
447
+ }
448
+ }
449
+ }
450
+ /**
451
+ * Wrap fetch with an x402Client for transparent payment handling.
452
+ * The x402Client is created and owned by the developer — we never see their keys.
453
+ */
454
+ static createX402Fetcher(wallet) {
455
+ try {
456
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
457
+ const { wrapFetchWithPayment } = require('@x402/fetch');
458
+ return wrapFetchWithPayment(fetch, wallet);
459
+ }
460
+ catch (err) {
461
+ if (err?.code === 'MODULE_NOT_FOUND' || err?.code === 'ERR_MODULE_NOT_FOUND' || err instanceof ReferenceError) {
462
+ throw new Error('x402 wallet mode requires @x402/fetch. Install it:\n' +
463
+ ' npm install @x402/fetch @x402/evm viem');
464
+ }
465
+ throw err;
466
+ }
326
467
  }
327
468
  warnDeprecated(key, message) {
328
469
  if (this.deprecationWarnings.has(key))
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { CommuneClient } from './client.js';
2
- export type { ApiError, ApiResponse, AttachmentRecord, Channel, ConversationListParams, CreateDomainPayload, CreateInboxPayload, Direction, DomainEntry, DomainWebhook, InboxEntry, InboxWebhook, InboundEmailWebhookPayload, MessageListParams, MessageMetadata, Participant, ParticipantRole, SendMessagePayload, SearchThreadResult, SearchThreadsParams, ThreadMetadataEntry, SvixHeaders, SuppressionEntry, Thread, DeliveryEventEntry, DeliveryEventsParams, DeliveryMetricsParams, DeliverySuppressionsParams, ThreadListParams, ThreadListResponse, UnifiedMessage, PhoneNumber, UpdatePhoneNumberPayload, SmsConversation, SmsConversationListParams, SmsMessage, SendSmsPayload, SendSmsResult, SmsSearchParams, CreditBalance, CreditBundle, } from './types.js';
2
+ export type { ClientOptions, X402ClientLike } from './client.js';
3
+ export type { ApiError, ApiResponse, AttachmentRecord, Channel, ConversationListParams, CreateDomainPayload, CreateInboxPayload, Direction, DomainEntry, DomainWebhook, InboxEntry, InboxWebhook, InboundEmailWebhookPayload, MessageListParams, MessageMetadata, Participant, ParticipantRole, SendMessagePayload, SearchThreadResult, SearchThreadsParams, ThreadMetadataEntry, SvixHeaders, SuppressionEntry, Thread, DeliveryEventEntry, DeliveryEventsParams, DeliveryMetricsParams, DeliverySuppressionsParams, ThreadListParams, ThreadListResponse, UnifiedMessage, PhoneNumber, UpdatePhoneNumberPayload, PhoneNumberWebhookPayload, AvailablePhoneNumber, ProvisionPhoneNumberPayload, SmsConversation, SmsConversationListParams, SmsMessage, SmsListParams, SmsSuppression, SendSmsPayload, SendSmsResult, SmsSearchParams, CreditBalance, CreditBundle, CreditCheckoutResult, FeedbackType, FeedbackSubmitPayload, FeedbackResult, } from './types.js';
3
4
  export { verifyResendWebhook, verifyCommuneWebhook, computeCommuneSignature } from './webhooks.js';
4
5
  export type { CommuneWebhookHeaders } from './webhooks.js';
5
6
  export { createWebhookHandler } from './listener.js';
package/dist/types.d.ts CHANGED
@@ -367,6 +367,25 @@ export interface DeliverySuppressionsParams {
367
367
  domainId?: string;
368
368
  limit?: number;
369
369
  }
370
+ export interface AvailablePhoneNumber {
371
+ phoneNumber: string;
372
+ friendlyName: string;
373
+ capabilities: {
374
+ sms: boolean;
375
+ mms: boolean;
376
+ voice: boolean;
377
+ };
378
+ region?: string;
379
+ locality?: string;
380
+ postalCode?: string;
381
+ }
382
+ export interface ProvisionPhoneNumberPayload {
383
+ phone_number?: string;
384
+ type?: 'tollfree' | 'local';
385
+ country?: string;
386
+ friendly_name?: string;
387
+ area_code?: string;
388
+ }
370
389
  export interface PhoneNumber {
371
390
  id: string;
372
391
  number: string;
@@ -386,11 +405,17 @@ export interface PhoneNumber {
386
405
  createdAt: string;
387
406
  updatedAt: string;
388
407
  }
408
+ export interface PhoneNumberWebhookPayload {
409
+ endpoint?: string;
410
+ secret?: string;
411
+ events?: string[];
412
+ }
389
413
  export interface UpdatePhoneNumberPayload {
390
414
  friendlyName?: string;
391
415
  autoReply?: string | null;
392
416
  allowList?: string[];
393
417
  blockList?: string[];
418
+ webhook?: PhoneNumberWebhookPayload;
394
419
  }
395
420
  export interface SmsConversation {
396
421
  thread_id: string;
@@ -443,6 +468,19 @@ export interface SmsSearchParams {
443
468
  phone_number_id?: string;
444
469
  limit?: number;
445
470
  }
471
+ export interface SmsListParams {
472
+ phone_number_id?: string;
473
+ limit?: number;
474
+ before?: string;
475
+ after?: string;
476
+ }
477
+ export interface SmsSuppression {
478
+ phone_number: string;
479
+ orgId: string;
480
+ phone_number_id?: string;
481
+ reason?: string;
482
+ created_at?: string;
483
+ }
446
484
  export interface CreditBalance {
447
485
  included: number;
448
486
  purchased: number;
@@ -453,6 +491,24 @@ export interface CreditBundle {
453
491
  id: string;
454
492
  credits: number;
455
493
  price: number;
456
- pricePerCredit: string;
457
- available: boolean;
494
+ price_per_credit: string;
495
+ available?: boolean;
496
+ }
497
+ export interface CreditCheckoutResult {
498
+ checkout_url: string;
499
+ bundle: string;
500
+ credits: number;
501
+ price: number;
502
+ }
503
+ export type FeedbackType = 'error' | 'feature' | 'signal';
504
+ export interface FeedbackSubmitPayload {
505
+ type: FeedbackType;
506
+ message: string;
507
+ context?: Record<string, unknown>;
508
+ }
509
+ export interface FeedbackResult {
510
+ id: string;
511
+ type: FeedbackType;
512
+ status: 'received';
513
+ created_at: string;
458
514
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "commune-ai",
3
- "version": "0.3.2",
3
+ "version": "0.3.6",
4
4
  "description": "Email infrastructure for agents — set up an inbox and send your first email in 30 seconds. Programmatic inboxes (~1 line), consistent threads, custom domains, attachments, and structured data.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -17,22 +17,38 @@
17
17
  ],
18
18
  "keywords": [
19
19
  "email",
20
- "slack",
21
- "ai",
22
- "agent",
20
+ "ai-agents",
21
+ "agents",
22
+ "llm",
23
+ "langchain",
24
+ "crewai",
25
+ "openai-agents",
26
+ "claude",
27
+ "mcp",
23
28
  "webhook",
24
- "communication",
25
29
  "inbox",
26
- "api"
30
+ "smtp",
31
+ "email-api",
32
+ "email-sdk",
33
+ "typescript",
34
+ "nodejs",
35
+ "async-agents",
36
+ "multi-agent",
37
+ "commune",
38
+ "email-infrastructure",
39
+ "agent-tools",
40
+ "sms",
41
+ "thread",
42
+ "ai"
27
43
  ],
28
- "license": "MIT",
44
+ "license": "Apache-2.0",
29
45
  "repository": {
30
46
  "type": "git",
31
- "url": "https://github.com/commune-ai/commune"
47
+ "url": "https://github.com/shanjai-raj/commune-ai"
32
48
  },
33
- "homepage": "https://github.com/commune-ai/commune#readme",
49
+ "homepage": "https://github.com/shanjai-raj/commune-ai#readme",
34
50
  "bugs": {
35
- "url": "https://github.com/commune-ai/commune/issues"
51
+ "url": "https://github.com/shanjai-raj/commune-ai/issues"
36
52
  },
37
53
  "scripts": {
38
54
  "build": "tsc -p tsconfig.json",